Merge pull request #1479 from frizynn/refactor/rpc-mode-dedup

refactor: deduplicate RPC mode shared patterns
This commit is contained in:
TÂCHES 2026-03-19 15:50:03 -06:00 committed by GitHub
commit 0259f0f2e3
3 changed files with 57 additions and 58 deletions

View file

@ -8,6 +8,7 @@
import type { AssistantMessage, ImageContent } from "@gsd/pi-ai";
import type { AgentSession } from "../core/agent-session.js";
import { createDefaultCommandContextActions } from "./shared/command-context-actions.js";
/**
* Options for print mode.
@ -37,36 +38,7 @@ export async function runPrintMode(session: AgentSession, options: PrintModeOpti
}
// Set up extensions for print mode (no UI)
await session.bindExtensions({
commandContextActions: {
waitForIdle: () => session.agent.waitForIdle(),
newSession: async (options) => {
const success = await session.newSession({ parentSession: options?.parentSession });
if (success && options?.setup) {
await options.setup(session.sessionManager);
}
return { cancelled: !success };
},
fork: async (entryId) => {
const result = await session.fork(entryId);
return { cancelled: result.cancelled };
},
navigateTree: async (targetId, options) => {
const result = await session.navigateTree(targetId, {
summarize: options?.summarize,
customInstructions: options?.customInstructions,
replaceInstructions: options?.replaceInstructions,
label: options?.label,
});
return { cancelled: result.cancelled };
},
switchSession: async (sessionPath) => {
const success = await session.switchSession(sessionPath);
return { cancelled: !success };
},
reload: async () => {
await session.reload();
},
},
commandContextActions: createDefaultCommandContextActions(session),
onError: (err) => {
console.error(`Extension error (${err.extensionPath}): ${err.error}`);
},

View file

@ -19,6 +19,7 @@ import type {
ExtensionWidgetOptions,
} from "../../core/extensions/index.js";
import { type Theme, theme } from "../interactive/theme/theme.js";
import { createDefaultCommandContextActions } from "../shared/command-context-actions.js";
import { attachJsonlLineReader, serializeJsonLine } from "./jsonl.js";
import type {
RpcCommand,
@ -285,34 +286,7 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
// Set up extensions with RPC-based UI context
await session.bindExtensions({
uiContext: createExtensionUIContext(),
commandContextActions: {
waitForIdle: () => session.agent.waitForIdle(),
newSession: async (options) => {
// Delegate to AgentSession (handles setup + agent state sync)
const success = await session.newSession(options);
return { cancelled: !success };
},
fork: async (entryId) => {
const result = await session.fork(entryId);
return { cancelled: result.cancelled };
},
navigateTree: async (targetId, options) => {
const result = await session.navigateTree(targetId, {
summarize: options?.summarize,
customInstructions: options?.customInstructions,
replaceInstructions: options?.replaceInstructions,
label: options?.label,
});
return { cancelled: result.cancelled };
},
switchSession: async (sessionPath) => {
const success = await session.switchSession(sessionPath);
return { cancelled: !success };
},
reload: async () => {
await session.reload();
},
},
commandContextActions: createDefaultCommandContextActions(session),
shutdownHandler: () => {
shutdownRequested = true;
},

View file

@ -0,0 +1,53 @@
/**
* Default (headless) implementations of ExtensionCommandContextActions.
*
* These delegate directly to AgentSession without any UI side-effects.
* Interactive mode layers TUI-specific behavior on top of these.
* RPC and print modes use them as-is.
*/
import type { AgentSession } from "../../core/agent-session.js";
import type { ExtensionCommandContextActions } from "../../core/extensions/index.js";
/**
* Create the default set of command context actions that simply delegate
* to the corresponding AgentSession methods.
*
* Callers can spread the result and override individual actions to add
* mode-specific behavior (e.g., interactive mode clears TUI state after
* forking).
*/
export function createDefaultCommandContextActions(session: AgentSession): ExtensionCommandContextActions {
return {
waitForIdle: () => session.agent.waitForIdle(),
newSession: async (options) => {
const success = await session.newSession(options);
return { cancelled: !success };
},
fork: async (entryId) => {
const result = await session.fork(entryId);
return { cancelled: result.cancelled };
},
navigateTree: async (targetId, options) => {
const result = await session.navigateTree(targetId, {
summarize: options?.summarize,
customInstructions: options?.customInstructions,
replaceInstructions: options?.replaceInstructions,
label: options?.label,
});
return { cancelled: result.cancelled };
},
switchSession: async (sessionPath) => {
const success = await session.switchSession(sessionPath);
return { cancelled: !success };
},
reload: async () => {
await session.reload();
},
};
}