Cada paso desde que enviás tu mensaje hasta que recibís la respuesta — system prompt, agentic loop, context window y el recorrido real de los datos por el modelo. Tres hilos conductores: ① el loop request por request, ② los contratos con Pydantic y ③ 13 escenarios simulados, más labs interactivos, concepto clave, payload real, quiz, sandbox y progreso.
Los términos técnicos en inglés tienen subrayado punteado: pasá el mouse (o tocá) para ver su explicación.
cache_control al final del prefijo estable: se lee a 0,1×, lo nuevo se escribe a 1,25×, mínimo 1.024 tok y expira a los 5 min. Si cambia el prefijo, se invalida desde ahí.thinking: {type:"enabled", budget_tokens:N} y bloque thinking antes del texto. En OpenCode se controla con los variants (#high, etc.).system custom lo reemplaza, pero AGENTS.md y skills se siguen agregando.end_turn, tool_use, max_tokens, stop_sequence.id.auto, any/required, una tool forzada, o none.tool_use.id → tool_result.tool_use_id; en OpenAI: tool_calls[].id → tool_call_id. Nunca se empareja por orden.parameters/input_schema es el schema declarado en el request; arguments/input son los datos de una llamada concreta. OpenAI manda arguments como string JSON; Anthropic, input como objeto.model_json_schema() y valida con model_validate() o model_validate_json().[truncated]). No es lo mismo que compactar.usage.input_tokens; el segundo, stop_reason y el usage.output_tokens definitivo.tool_use en streaming. Solo se puede parsear cuando cierra el bloque (content_block_stop).system, user, assistant o tool. El modelo no tiene "memoria": interpreta roles dentro del payload.previous_response_id) que guarda el hilo del lado del proveedor.jsonrpc, method, params e id. Es el transporte que usa MCP sobre stdio o HTTP.mcp__github__create_issue) para evitar colisiones entre servidores.read es idempotente; un POST o un shell puede no serlo.text, tool_use y tool_result.stop_reason, que es el motivo que devuelve el proveedor.AGENTS.md). El contexto es lo que viaja en este request. "Recordar" implica volver a inyectarlo.messages, qué viaja en el request, qué vuelve en el response, qué contrato de Pydantic valida esa frontera y qué línea de agent.py se está ejecutando. Tocá un nodo del diagrama para saltar a ese momento.messages antes de ejecutar las tools. El tool_result que viene después la referencia por id: sin ella en el historial, la API rechaza el request. [tu entrada]
│
▼
[agregar a messages] role:"user"
│
▼
[llamar al modelo] ◀────────────────────┐ system + tools + TODO messages
│ │
▼ │
[agregar la respuesta] │ role:"assistant" (texto + tool_use)
│ │
▼ │
[¿hay tool_use?] ──no──▶ [imprimir texto, volver al REPL]
│ │
sí │
▼ │
[validar (Pydantic) → permisos │ ValidationError → tool_result is_error
→ ejecutar cada herramienta] │
│ │
▼ │
[agregar tool_results] ─────────────────┘ role:"user" con bloques tool_result
(OpenAI: un role:"tool" por llamada)
| nodo del diagrama | agent.py | 5 etapas | ReAct | micro-pasos (escenario 3) | contrato |
|---|---|---|---|---|---|
| tu entrada | input() | Perceive | — | antes del loop | UserMessage |
| agregar a messages | messages.append(user) | Perceive | — | antes del loop | model_dump() |
| llamar al modelo | client.messages.create | Reason (+ Plan) | Thought | 0–5 | model_json_schema() · Message |
| agregar la respuesta | messages.append(assistant) | Act | Action (registrada) | 6 | ToolUseBlock · id |
| ¿hay tool_use? | resp.stop_reason | Act | — | 11 (decisión) | StopReason |
| validar y ejecutar | model_validate → RUNNERS | Act | Action | 7–8 | ReadArgs |
| agregar tool_results | messages.append(results) | Observe | Observation | 9–10 | ToolResult |
| imprimir, volver al REPL | print · break | — (fin del turno) | respuesta final | post-loop | structured outputs (opcional) |
parameters/input_schema; lo que el modelo devuelve como arguments/input se valida antes de ejecutar. Si falla, vuelve como tool_result con is_error. Las pestañas siguen el orden del loop (declarar → política → propuesta → decisión → resultado → correlación) y cada una te lleva al paso de donde se usa.model_json_schema()→request→modelo→model_validate*()→tool
Un acuerdo explícito sobre la forma y el significado de los datos que se intercambian. En tool use tiene dos piezas: el schema que declarás y los datos que el modelo propone. El contrato también define qué se considera una respuesta válida.
Permite validar antes de ejecutar, devolver errores accionables, documentar tools, evitar acciones con datos incompletos y conectar tools locales o MCP con el mismo acuerdo. Sin contrato, el harness tendría que adivinar qué quiso decir el modelo.
El vocabulario JSON Schema es común, pero cambian los nombres y el soporte: Anthropic usa input_schema e input; OpenAI, parameters y arguments. No todos aplican strict, structured outputs o paralelismo igual, ni con la misma fuerza: algunos usan decoding restringido y otros sólo lo toman como guía. El contrato de tu dominio puede ser el mismo; el adaptador cambia.
Sí. Definí un BaseModel, exportá model_json_schema() y validá con model_validate(). Podés tener contratos propios para tools, argumentos, resultados y salidas estructuradas. El harness decide cuáles acepta, cómo repara y qué permisos exige.
{
"type": "object",
"properties": {
"path": { "type": "string" },
"limit": { "type": "integer", "minimum": 1 }
},
"required": ["path"],
"additionalProperties": false
}