feat(coding-agent): export run mode utilities with options interfaces

- Add PrintModeOptions interface, update runPrintMode signature
- Export InteractiveMode, InteractiveModeOptions, runPrintMode, PrintModeOptions, runRpcMode from main package
- Document run modes in docs/sdk.md with usage examples
- Update CHANGELOG
This commit is contained in:
Mario Zechner 2026-01-08 01:53:24 +01:00
parent 5d39074a35
commit e483521075
6 changed files with 94 additions and 16 deletions

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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<void>((resolve) => process.stdout.once("drain", resolve));

View file

@ -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";

View file

@ -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<void> {
export async function runPrintMode(session: AgentSession, options: PrintModeOptions): Promise<void> {
const { mode, messages = [], initialMessage, initialImages } = options;
// Set up extensions for print mode (no UI, no command context)
const extensionRunner = session.extensionRunner;
if (extensionRunner) {