7f5ea5d9be
- Introduces ClientBridge — the abstract boundary between AgentSession and external clients (ACP, TUI), defining terminal handle and permission request contracts - Adds ACP permission gating in AgentSession for destructive tools (bash, edit, write, ast_edit): allow-once, reject-once, allow-always with caching - Wires todo tracking, model cycling/retry-fallback chains, and auto-compaction into the session lifecycle
82 lines
2.6 KiB
TypeScript
82 lines
2.6 KiB
TypeScript
/**
|
|
* ClientBridge — abstraction over capabilities provided by an external client
|
|
* (e.g. ACP editor host) that the agent can route through instead of operating
|
|
* directly on the local filesystem / spawning local subprocesses.
|
|
*
|
|
* When `undefined`, tools fall back to local IO. When populated (currently
|
|
* only by `AcpAgent`), tools route requests through the client so it can
|
|
* surface unsaved buffer state, render terminals in the IDE, or gate
|
|
* destructive operations behind user permission prompts.
|
|
*/
|
|
|
|
export interface ClientBridgeCapabilities {
|
|
/** Client implements `fs/read_text_file`. */
|
|
readTextFile?: boolean;
|
|
/** Client implements `fs/write_text_file`. */
|
|
writeTextFile?: boolean;
|
|
/** Client implements the `terminal/*` family. */
|
|
terminal?: boolean;
|
|
/** Client implements `session/request_permission`. */
|
|
requestPermission?: boolean;
|
|
}
|
|
|
|
export interface ClientBridgePermissionToolCall {
|
|
toolCallId: string;
|
|
toolName: string;
|
|
title: string;
|
|
kind?: string;
|
|
rawInput?: unknown;
|
|
locations?: { path: string; line?: number }[];
|
|
}
|
|
|
|
export type ClientBridgePermissionOptionKind = "allow_once" | "allow_always" | "reject_once" | "reject_always";
|
|
|
|
export interface ClientBridgePermissionOption {
|
|
optionId: string;
|
|
name: string;
|
|
kind: ClientBridgePermissionOptionKind;
|
|
}
|
|
|
|
export type ClientBridgePermissionOutcome =
|
|
| { outcome: "cancelled" }
|
|
| { outcome: "selected"; optionId: string; kind?: ClientBridgePermissionOptionKind };
|
|
|
|
export interface ClientBridgeTerminalExitStatus {
|
|
exitCode?: number | null;
|
|
signal?: string | null;
|
|
}
|
|
|
|
export interface ClientBridgeTerminalOutput {
|
|
output: string;
|
|
truncated: boolean;
|
|
exitStatus?: ClientBridgeTerminalExitStatus | null;
|
|
}
|
|
|
|
export interface ClientBridgeTerminalHandle {
|
|
terminalId: string;
|
|
waitForExit(): Promise<ClientBridgeTerminalExitStatus>;
|
|
currentOutput(): Promise<ClientBridgeTerminalOutput>;
|
|
kill(): Promise<void>;
|
|
release(): Promise<void>;
|
|
}
|
|
|
|
export interface ClientBridgeCreateTerminalParams {
|
|
command: string;
|
|
args?: string[];
|
|
env?: Array<{ name: string; value: string }>;
|
|
cwd?: string;
|
|
outputByteLimit?: number;
|
|
}
|
|
|
|
export interface ClientBridge {
|
|
readonly capabilities: ClientBridgeCapabilities;
|
|
readTextFile?(params: { path: string; line?: number; limit?: number }): Promise<string>;
|
|
writeTextFile?(params: { path: string; content: string }): Promise<void>;
|
|
createTerminal?(params: ClientBridgeCreateTerminalParams): Promise<ClientBridgeTerminalHandle>;
|
|
requestPermission?(
|
|
toolCall: ClientBridgePermissionToolCall,
|
|
options: ClientBridgePermissionOption[],
|
|
signal?: AbortSignal,
|
|
): Promise<ClientBridgePermissionOutcome>;
|
|
}
|