Modos print y rpc
Los modos no interactivos de pi son dos: print (one-shot, salida texto o JSON) y rpc (conexión larga, JSON-RPC over stdin/stdout). El modo print se usa para invocaciones scripteadas pi -p "fix this bug"; el modo rpc para incrustar pi en otra aplicación GUI (extensión VS Code, front web). Ambos comparten AgentSessionRuntime, pero la suscripción a eventos, el formato de salida y la integración de UI de extensiones son completamente distintas.
Responsabilidades
- Modo print:
runPrintModerecibemode: "text" | "json"; el modo text sólo emite el texto final del mensaje assistant, el modo json hace streaming de todos losAgentSessionEvent. Verpackages/coding-agent/src/modes/print-mode.ts:32-66. - Modo rpc:
runRpcModeusaattachJsonlLineReaderpara leer comandos JSON desde stdin y los dispatch a través dehandleCommandcon 29 tipos de comando; eventos y respuestas se escriben a stdout. Verpackages/coding-agent/src/modes/rpc/rpc-mode.ts:48-70ypackages/coding-agent/src/modes/rpc/rpc-mode.ts:371-625. - Gestión de señales: ambos modos registran handler de SIGTERM / SIGHUP, primero
killTrackedDetachedChildreny luegodisposeRuntime, garantizando que los subprocesos bash no queden colgados. Verpackages/coding-agent/src/modes/print-mode.ts:47-63ypackages/coding-agent/src/modes/rpc/rpc-mode.ts:351-365. - Puente UI de extensiones: el modo rpc implementa
createExtensionUIContext, que envía las peticiones dialog / widget de extensiones vía eventoextension_ui_requestal cliente, y el cliente responde conextension_ui_response. Verpackages/coding-agent/src/modes/rpc/rpc-mode.ts:83-130. - Hook de reemplazo de sesión: ambos modos registran un callback rebind con
runtimeHost.setRebindSessionpara, tras un cambio de sesión, volver abindExtensionsy re-suscribirse a eventos. Verpackages/coding-agent/src/modes/print-mode.ts:67-108ypackages/coding-agent/src/modes/rpc/rpc-mode.ts:306-349.
Motivación de diseño
¿Por qué print y rpc no comparten código? Porque el contrato de salida es distinto: el stdout de print es unidireccional (texto o líneas JSON), el stdin/stdout de rpc es bidireccional (comandos entran, eventos + respuestas salen). RPC además mantiene un mapa de Promises pendientes para las peticiones UI de extensiones (esperando respuesta del cliente), mecanismo que print no necesita. Compartir introduciría complejidad innecesaria, así que cada archivo implementa su propio rebindSession y handleEvent.
Los 29 tipos de comando rpc (prompt, steer, follow_up, abort, new_session, get_state, set_model, cycle_model, bash, fork, clone, export_html, etc.) son el mapeo completo de la API pública de AgentSession. El cliente puede invocar por RPC cualquier método expuesto por AgentSession, lo que permite incrustar pi en una GUI escrita en cualquier lenguaje, siempre que hable JSON-RPC.
La ruta mode: "text" de print sólo mira el último mensaje assistant: si va bien, escribe content.text a stdout; si falla (stopReason === "error" || "aborted"), escribe a stderr y devuelve exitCode 1. Simple y directo, ideal para scripts pi -p "..." | jq.
Archivos clave
packages/coding-agent/src/modes/print-mode.ts:14-26—PrintModeOptions:mode,messages,initialMessage,initialImages.packages/coding-agent/src/modes/print-mode.ts:32-70— Firma derunPrintMode, disposeRuntime, registerSignalHandlers, rebindSession.packages/coding-agent/src/modes/print-mode.ts:110-145— Flujo principal: envía initialMessage, itera messages, en modo text saca el último assistant.packages/coding-agent/src/modes/rpc/rpc-mode.ts:1-13— Comentario de cabecera, describe el protocolo rpc (comandos, respuestas, eventos, UI de extensiones).packages/coding-agent/src/modes/rpc/rpc-mode.ts:48-70— Firma derunRpcMode, helpersoutput/success/error.packages/coding-agent/src/modes/rpc/rpc-mode.ts:83-130—createDialogPromise, gestión de Promise + timeout + abort para peticiones UI de extensiones.packages/coding-agent/src/modes/rpc/rpc-mode.ts:306-349—rebindSession: reengancha extensiones,session.subscribepara output de eventos.packages/coding-agent/src/modes/rpc/rpc-mode.ts:371-625— Switch dehandleCommand, 29 ramas.packages/coding-agent/src/modes/rpc/rpc-types.ts— Tipos del protocolo RPC (RpcCommand,RpcResponse,RpcExtensionUIRequest, etc.).
Ruta text de print, sólo saca el text content del último assistant:
// packages/coding-agent/src/modes/print-mode.ts:128-145
if (mode === "text") {
const state = session.state;
const lastMessage = state.messages[state.messages.length - 1];
if (lastMessage?.role === "assistant") {
const assistantMsg = lastMessage as AssistantMessage;
if (assistantMsg.stopReason === "error" || assistantMsg.stopReason === "aborted") {
console.error(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);
exitCode = 1;
} else {
for (const content of assistantMsg.content) {
if (content.type === "text") {
writeRawStdout(`${content.text}\n`);
}
}
}
}
}Comando prompt de rpc, con preflightResult para responder en cuanto prompt acepta:
// packages/coding-agent/src/modes/rpc/rpc-mode.ts:379-401
case "prompt": {
let preflightSucceeded = false;
void session
.prompt(command.message, {
images: command.images,
streamingBehavior: command.streamingBehavior,
source: "rpc",
preflightResult: (didSucceed) => {
if (didSucceed) {
preflightSucceeded = true;
output(success(id, "prompt"));
}
},
})
.catch((e) => {
if (!preflightSucceeded) {
output(error(id, "prompt", e.message));
}
});Flujo de datos
Comparación entrada/salida de ambos modos:
Límites y fallos
- rpc no soporta @file:
main.tsantes del dispatch compruebaparsed.mode === "rpc" && parsed.fileArgs.length > 0y sale con error. Verpackages/coding-agent/src/main.ts:475-478. - rpc no soporta cambio de tema:
setThemedevuelve{ success: false, error: "Theme switching not supported in RPC mode" }. Verpackages/coding-agent/src/modes/rpc/rpc-mode.ts:291-294. - rpc no expande herramientas:
getToolsExpandedsiempre devuelve false, porque el concepto TUI no existe en rpc. Verpackages/coding-agent/src/modes/rpc/rpc-mode.ts:296-303. - Timeout / abort de UI de extensiones:
createDialogPromisesoportaopts.timeoutyopts.signal; al timeout o abort resuelve valor por defecto, no rechaza, para que la lógica de la extensión pueda continuar. Verpackages/coding-agent/src/modes/rpc/rpc-mode.ts:90-130. - Toma de stdout en print:
main.tsllamatakeOverStdout()en modo no interactivo; todoconsole.logse redirige a un buffer interno y al finalflushRawStdoutlo escribe, evitando que escapes TUI contaminen. Verpackages/coding-agent/src/modes/print-mode.ts:155-157. - Señal de shutdown: el flag
shutdownRequestedderpc-modelo dispara elshutdownHandlerde extensiones; el bucle principal lo detecta, limpia y sale. Verpackages/coding-agent/src/modes/rpc/rpc-mode.ts:79-81ypackages/coding-agent/src/modes/rpc/rpc-mode.ts:337-339.
Resumen
print y rpc son los modos no interactivos de pi; comparten AgentSessionRuntime pero con contratos de salida distintos. Print emite texto o flujo de eventos JSON unidireccional; rpc es un protocolo JSON-RPC bidireccional que expone todos los métodos de AgentSession a clientes externos y puentea las peticiones UI de extensiones. La entrada de ensamblaje en entrada y dispatch del CLI; el reemplazo de runtime en sesión switch/fork/import.