Skip to content

Modos print y rpc

源码版本v0.73.1

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

  1. Modo print: runPrintMode recibe mode: "text" | "json"; el modo text sólo emite el texto final del mensaje assistant, el modo json hace streaming de todos los AgentSessionEvent. Ver packages/coding-agent/src/modes/print-mode.ts:32-66.
  2. Modo rpc: runRpcMode usa attachJsonlLineReader para leer comandos JSON desde stdin y los dispatch a través de handleCommand con 29 tipos de comando; eventos y respuestas se escriben a stdout. Ver packages/coding-agent/src/modes/rpc/rpc-mode.ts:48-70 y packages/coding-agent/src/modes/rpc/rpc-mode.ts:371-625.
  3. Gestión de señales: ambos modos registran handler de SIGTERM / SIGHUP, primero killTrackedDetachedChildren y luego disposeRuntime, garantizando que los subprocesos bash no queden colgados. Ver packages/coding-agent/src/modes/print-mode.ts:47-63 y packages/coding-agent/src/modes/rpc/rpc-mode.ts:351-365.
  4. Puente UI de extensiones: el modo rpc implementa createExtensionUIContext, que envía las peticiones dialog / widget de extensiones vía evento extension_ui_request al cliente, y el cliente responde con extension_ui_response. Ver packages/coding-agent/src/modes/rpc/rpc-mode.ts:83-130.
  5. Hook de reemplazo de sesión: ambos modos registran un callback rebind con runtimeHost.setRebindSession para, tras un cambio de sesión, volver a bindExtensions y re-suscribirse a eventos. Ver packages/coding-agent/src/modes/print-mode.ts:67-108 y packages/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

Ruta text de print, sólo saca el text content del último assistant:

typescript
// 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:

typescript
// 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

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.