WP12: Create rpc-mode.ts

This commit is contained in:
Mario Zechner 2025-12-09 00:16:17 +01:00
parent c0996a1078
commit e7c71e7ee3
2 changed files with 86 additions and 2 deletions

View file

@ -1308,8 +1308,8 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
1. `npm run check` passes
2. Manual test: RPC mode still works (if you have a way to test it)
- [ ] Create `src/modes/rpc-mode.ts`
- [ ] Verify with `npm run check`
- [x] Create `src/modes/rpc-mode.ts`
- [x] Verify with `npm run check`
---

View file

@ -0,0 +1,84 @@
/**
* RPC mode: Headless operation with JSON stdin/stdout protocol.
*
* Used for embedding the agent in other applications.
* Receives commands as JSON on stdin, outputs events as JSON on stdout.
*/
import * as readline from "readline";
import type { AgentSession } from "../core/agent-session.js";
/**
* Run in RPC mode.
* Listens for JSON commands on stdin, outputs events on stdout.
*
* Commands:
* - { type: "prompt", message: string, attachments?: Attachment[] }
* - { type: "abort" }
* - { type: "compact", customInstructions?: string }
* - { type: "bash", command: string }
*
* Events are output as JSON lines (same format as session manager).
*/
export async function runRpcMode(session: AgentSession): Promise<never> {
// Output all agent events as JSON
session.subscribe((event) => {
console.log(JSON.stringify(event));
});
// Listen for JSON input
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false,
});
rl.on("line", async (line: string) => {
try {
const input = JSON.parse(line);
switch (input.type) {
case "prompt":
if (input.message) {
await session.prompt(input.message, {
attachments: input.attachments,
expandSlashCommands: false, // RPC mode doesn't expand slash commands
});
}
break;
case "abort":
await session.abort();
break;
case "compact":
try {
const result = await session.compact(input.customInstructions);
console.log(JSON.stringify({ type: "compaction", ...result }));
} catch (error: any) {
console.log(JSON.stringify({ type: "error", error: `Compaction failed: ${error.message}` }));
}
break;
case "bash":
if (input.command) {
try {
const result = await session.executeBash(input.command);
console.log(JSON.stringify({ type: "bash_end", ...result }));
} catch (error: any) {
console.log(JSON.stringify({ type: "error", error: `Bash failed: ${error.message}` }));
}
}
break;
default:
console.log(JSON.stringify({ type: "error", error: `Unknown command: ${input.type}` }));
}
} catch (error: any) {
console.log(JSON.stringify({ type: "error", error: error.message }));
}
});
// Keep process alive forever
return new Promise(() => {});
}