diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index c4f322b2..7cffc893 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -24,6 +24,12 @@ - `createExtensionRuntime()` function to create runtime with throwing stubs - `Extension` type exported (cleaner name for loaded extension data) - Interactive mode now warns when extensions override built-in tools (read, bash, edit, write, grep, find, ls) +- `InteractiveMode` constructor simplified to `(session, options?)` with `InteractiveModeOptions` interface +- `InteractiveMode.run()` method for complete initialization and interactive loop +- `InteractiveModeOptions` exported for SDK users building custom interactive modes +- `runPrintMode()` now takes `(session, options)` with `PrintModeOptions` interface +- `PrintModeOptions` exported for SDK users +- Run mode utilities exported from main package: `InteractiveMode`, `InteractiveModeOptions`, `runPrintMode`, `PrintModeOptions`, `runRpcMode` ### Changed diff --git a/packages/coding-agent/docs/sdk.md b/packages/coding-agent/docs/sdk.md index b2a29193..2a691b7f 100644 --- a/packages/coding-agent/docs/sdk.md +++ b/packages/coding-agent/docs/sdk.md @@ -886,9 +886,65 @@ session.subscribe((event) => { await session.prompt("Get status and list files."); ``` +## Run Modes + +The SDK exports run mode utilities for building custom interfaces on top of `createAgentSession()`: + +### InteractiveMode + +Full TUI interactive mode with editor, chat history, and all built-in commands: + +```typescript +import { createAgentSession, InteractiveMode } from "@mariozechner/pi-coding-agent"; + +const { session } = await createAgentSession({ /* ... */ }); + +const mode = new InteractiveMode(session, { + // All optional + migratedProviders: [], // Show migration warnings + modelFallbackMessage: undefined, // Show model restore warning + initialMessage: "Hello", // Send on startup + initialImages: [], // Images with initial message + initialMessages: [], // Additional startup prompts +}); + +await mode.run(); // Blocks until exit +``` + +### runPrintMode + +Single-shot mode: send prompts, output result, exit: + +```typescript +import { createAgentSession, runPrintMode } from "@mariozechner/pi-coding-agent"; + +const { session } = await createAgentSession({ /* ... */ }); + +await runPrintMode(session, { + mode: "text", // "text" for final response, "json" for all events + initialMessage: "Hello", // First message (can include @file content) + initialImages: [], // Images with initial message + messages: ["Follow up"], // Additional prompts +}); +``` + +### runRpcMode + +JSON-RPC mode for subprocess integration: + +```typescript +import { createAgentSession, runRpcMode } from "@mariozechner/pi-coding-agent"; + +const { session } = await createAgentSession({ /* ... */ }); + +await runRpcMode(session); // Reads JSON commands from stdin, writes to stdout +``` + +See [RPC documentation](rpc.md) for the JSON protocol. + ## RPC Mode Alternative -For subprocess-based integration, use RPC mode instead of the SDK: +For subprocess-based integration without building with the SDK, use the CLI directly: ```bash pi --mode rpc --no-session diff --git a/packages/coding-agent/src/index.ts b/packages/coding-agent/src/index.ts index 2aa9f924..8923565e 100644 --- a/packages/coding-agent/src/index.ts +++ b/packages/coding-agent/src/index.ts @@ -202,6 +202,14 @@ export { } from "./core/tools/index.js"; // Main entry point export { main } from "./main.js"; +// Run modes for programmatic SDK usage +export { + InteractiveMode, + type InteractiveModeOptions, + type PrintModeOptions, + runPrintMode, + runRpcMode, +} from "./modes/index.js"; // UI components for extensions export { ArminComponent, diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index f4b1bbbb..49b94b24 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -380,7 +380,12 @@ export async function main(args: string[]) { }); await mode.run(); } else { - await runPrintMode(session, mode, parsed.messages, initialMessage, initialImages); + await runPrintMode(session, { + mode, + messages: parsed.messages, + initialMessage, + initialImages, + }); stopThemeWatcher(); if (process.stdout.writableLength > 0) { await new Promise((resolve) => process.stdout.once("drain", resolve)); diff --git a/packages/coding-agent/src/modes/index.ts b/packages/coding-agent/src/modes/index.ts index 5cd17075..205e9f54 100644 --- a/packages/coding-agent/src/modes/index.ts +++ b/packages/coding-agent/src/modes/index.ts @@ -3,7 +3,7 @@ */ export { InteractiveMode, type InteractiveModeOptions } from "./interactive/interactive-mode.js"; -export { runPrintMode } from "./print-mode.js"; +export { type PrintModeOptions, runPrintMode } from "./print-mode.js"; export { type ModelInfo, RpcClient, type RpcClientOptions, type RpcEventListener } from "./rpc/rpc-client.js"; export { runRpcMode } from "./rpc/rpc-mode.js"; export type { RpcCommand, RpcResponse, RpcSessionState } from "./rpc/rpc-types.js"; diff --git a/packages/coding-agent/src/modes/print-mode.ts b/packages/coding-agent/src/modes/print-mode.ts index 87d9db09..d49f4753 100644 --- a/packages/coding-agent/src/modes/print-mode.ts +++ b/packages/coding-agent/src/modes/print-mode.ts @@ -9,23 +9,26 @@ import type { AssistantMessage, ImageContent } from "@mariozechner/pi-ai"; import type { AgentSession } from "../core/agent-session.js"; +/** + * Options for print mode. + */ +export interface PrintModeOptions { + /** Output mode: "text" for final response only, "json" for all events */ + mode: "text" | "json"; + /** Array of additional prompts to send after initialMessage */ + messages?: string[]; + /** First message to send (may contain @file content) */ + initialMessage?: string; + /** Images to attach to the initial message */ + initialImages?: ImageContent[]; +} + /** * Run in print (single-shot) mode. * Sends prompts to the agent and outputs the result. - * - * @param session The agent session - * @param mode Output mode: "text" for final response only, "json" for all events - * @param messages Array of prompts to send - * @param initialMessage Optional first message (may contain @file content) - * @param initialImages Optional images for the initial message */ -export async function runPrintMode( - session: AgentSession, - mode: "text" | "json", - messages: string[], - initialMessage?: string, - initialImages?: ImageContent[], -): Promise { +export async function runPrintMode(session: AgentSession, options: PrintModeOptions): Promise { + const { mode, messages = [], initialMessage, initialImages } = options; // Set up extensions for print mode (no UI, no command context) const extensionRunner = session.extensionRunner; if (extensionRunner) {