Files
oh-my-pi/packages/coding-agent/src/session/client-bridge.ts
T
Ogrodev 7f5ea5d9be feat(acp): add ClientBridge interface and AgentSession permission gating
- 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
2026-05-13 06:00:44 +02:00

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>;
}