@tangle-network/sdk-provider-cli-base 0.0.0-stage → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1616 @@
1
+ import { a as partitionImageAttachments, i as PreparedAttachment, n as MAX_TOTAL_INLINE_IMAGE_BYTES, o as preparePromptInputParts, r as PROMPT_SECTION_SEPARATOR, s as prependPromptSection, t as MAX_INLINE_IMAGE_BYTES } from "./prompt-input-BHn_1z69.mjs";
2
+ import { AskUserBridge, DEFAULT_INTERACTION_DECISION_TIMEOUT_MS as PERMISSION_DECISION_TIMEOUT_MS, InteractionBroker, InteractionBroker as InteractionBroker$1, InteractionHttpBridge, PermissionPromptBridge, RequestPermissionBridge, RequestPlanBridge, brokerInteractionTools } from "@tangle-network/agent-core/interactions";
3
+ import { CliExecResult, CliExitResult, CliLauncher, CliProcess, CliSpawnConfig, InvalidAttachmentError, JsonRpcError, RpcBridge, StreamParserConfig } from "@tangle-network/sdk-cli-runner";
4
+ import { AgentExecutionInput, AgentExecutionOutcome, AgentExecutionResult, AgentProfile, AgentProfileSecretProvider, AgentRuntimeAttachments, BackendCapabilities, BackendMessage, CliAuthFile, DurablePlan, GetMessagesOptions, HarnessType, InputPart, InteractionExecutionBinding, InteractionResponse, LocalMcpConfig, McpConfig, McpStatusResponse, PlanProviderState, ProviderConfig, ReasoningEffort, RequestedInteractions, SdkHostServices, SdkPlanHost, SdkProviderAdapter, StreamEvent, TokenUsage, ToolPart } from "@tangle-network/agent-interface";
5
+ import { BindableLaunchControl, HarnessId, HarnessId as HarnessId$1, WorkspacePlanApplication, WorkspacePlanApplication as WorkspacePlanApplication$1, WorkspacePlanReceipt } from "@tangle-network/agent-profile-materialize";
6
+ import { HarnessSessionContract } from "@tangle-network/cli-agent-registry/session-contract";
7
+ import { MessagePart, MessageStore, PersistedMessage, PersistedSession, SessionStore, readProviderMessageIds } from "@tangle-network/sdk-session-persistence";
8
+ import { ProviderLogger } from "@tangle-network/cli-agent-registry";
9
+ import { DEFAULT_INTERACTION_MCP_SERVER_NAME, InteractionMcpServer as InteractionMcpServer$1, InteractionMcpServerConfig as InteractionMcpServerConfig$1, interactionMcpToolName } from "@tangle-network/agent-core/interactions/mcp";
10
+
11
+ //#region src/acp-process-launch.d.ts
12
+ /** How to start the agent process for a session. */
13
+ interface AcpProcessSpec {
14
+ command: string;
15
+ args: string[];
16
+ env?: Record<string, string>;
17
+ /** Status detail shown while the process starts. */
18
+ statusDetail: string;
19
+ }
20
+ /** The spawn request a bridge factory receives. */
21
+ interface AcpBridgeSpawn {
22
+ command: string;
23
+ args: string[];
24
+ cwd: string;
25
+ env?: Record<string, string>;
26
+ rawCapturePath?: string;
27
+ uid?: number;
28
+ gid?: number;
29
+ }
30
+ /** Spawn an ACP agent over NDJSON stdio. The adapter owns abort, so no signal. */
31
+ declare function spawnAcpBridge(request: AcpBridgeSpawn): RpcBridge;
32
+ //#endregion
33
+ //#region src/types.d.ts
34
+ type InteractionToggleKind = keyof RequestedInteractions;
35
+ type InteractionToggleConfig = boolean | RequestedInteractions;
36
+ declare function interactionToggleEnabled(config: InteractionToggleConfig | undefined, kind: InteractionToggleKind): boolean;
37
+ declare function enabledInteractionKinds<TKind extends InteractionToggleKind>(config: InteractionToggleConfig | undefined, supported: readonly TKind[]): TKind[];
38
+ /**
39
+ * Per-turn interaction toggle carried on the execution input. Native harnesses
40
+ * treat plan mode as a per-turn property (toggle build/plan on any message), so
41
+ * the sidecar sends this turn's interactions on the execution input.
42
+ *
43
+ * The shared execution contract owns this field. Adapter initialization still
44
+ * accepts `true` as shorthand, but each turn carries an exact kind map.
45
+ */
46
+ type PerTurnInteractionInput = Pick<AgentExecutionInput, "interactions">;
47
+ /**
48
+ * Host-composed context for THIS turn only (e.g. the sidecar's container
49
+ * runtime snapshot): it must reach the model and nothing else. The caller's
50
+ * `parts`/`message` stay untouched, so recorders and message stores keep a
51
+ * transcript of exactly what the user sent.
52
+ *
53
+ * Optional for the same reason as `PerTurnInteractionInput.interactions`: the
54
+ * published `AgentExecutionInput` does not declare the field, and `systemPrompt`
55
+ * anchors the weak-type check.
56
+ */
57
+ type EphemeralContextInput = {
58
+ ephemeralContext?: string;
59
+ systemPrompt?: unknown;
60
+ };
61
+ /**
62
+ * Read a turn's ephemeral context, rejecting a wrong-typed value loudly.
63
+ *
64
+ * The published `AgentExecutionInput` does not declare the field, so nothing
65
+ * type-checks it at the process boundary. Left unchecked, a caller passing a
66
+ * non-string gets it stringified into the model prompt (`[object Object]`) —
67
+ * a corrupted turn with no error anywhere. `undefined`/`null` mean "no context
68
+ * this turn"; an empty string is likewise nothing to append.
69
+ */
70
+ declare function readEphemeralContext(input: EphemeralContextInput): string | undefined;
71
+ /**
72
+ * Compose the model-facing prompt for a turn: the caller's own text, then this
73
+ * turn's ephemeral context. Call it at the point the prompt is handed to the
74
+ * provider — NEVER on the parts handed to `recordUserMessage` or the message
75
+ * store.
76
+ */
77
+ declare function withEphemeralContext(promptText: string, input: EphemeralContextInput): string;
78
+ /**
79
+ * Resolve whether an interaction kind is active for THIS turn. When the turn
80
+ * carries `interactions` it is authoritative — a complete set that can also
81
+ * turn a kind OFF mid-session; otherwise the adapter falls back to its latched
82
+ * config (the initialize-time wiring, or a direct non-sidecar caller's option).
83
+ */
84
+ declare function turnInteractionEnabled(input: PerTurnInteractionInput, latched: InteractionToggleConfig | undefined, kind: InteractionToggleKind): boolean;
85
+ /**
86
+ * Overlay this turn's interactions onto a latched config, returning a NEW
87
+ * object (no shared mutation — safe when one adapter instance serves concurrent
88
+ * turns from different sessions). When the turn omits `interactions` the config
89
+ * is returned unchanged, preserving behavior for direct non-sidecar callers.
90
+ * Adapters read plan/permission/question posture off the returned config so a
91
+ * mid-session toggle takes effect and can turn a kind off (which the latched
92
+ * config, only ever merged by updateConfig, cannot).
93
+ */
94
+ declare function withTurnInteractions<TConfig extends {
95
+ interactions?: InteractionToggleConfig;
96
+ }>(config: TConfig, input: PerTurnInteractionInput): TConfig;
97
+ /**
98
+ * Logger interface for CLI providers.
99
+ */
100
+ interface CliProviderLogger {
101
+ observePhase?: ProviderLogger["observePhase"];
102
+ debug(message: string, meta?: Record<string, unknown>): void;
103
+ info(message: string, meta?: Record<string, unknown>): void;
104
+ warn(message: string, meta?: Record<string, unknown>): void;
105
+ error(message: string, meta?: Record<string, unknown>): void;
106
+ }
107
+ /**
108
+ * Base configuration shared by all CLI providers.
109
+ */
110
+ interface CliProviderConfig {
111
+ /** Trusted native auth projection resolved by the owning execution host. */
112
+ nativeAuthEnv?: Record<string, string>;
113
+ nativeAuthSecretEnv?: string;
114
+ /** Sidecar-owned credential HOME for this adapter instance. */
115
+ runtimeHome?: string;
116
+ /**
117
+ * Shared, persistent agent HOME. With `runtimeHome`, a harness whose
118
+ * contract can move its native stores off HOME runs with this HOME and keeps
119
+ * those stores in `runtimeHome` (configDirHomeEnv). Absent for an
120
+ * isolated-profile identity, which keeps the private HOME.
121
+ */
122
+ agentHome?: string;
123
+ /** Trusted, adapter-wide native process identity supplied by the executor. */
124
+ subprocessUser?: {
125
+ uid: number;
126
+ gid: number;
127
+ };
128
+ /**
129
+ * The executor keeps this subprocess identity for later backends of the
130
+ * same session, principal and profile authority: the session's secret MCP
131
+ * scope and its warm native server outlive this adapter, so the next turn's
132
+ * backend reuses its running stdio servers and native server. Session end
133
+ * and their idle TTLs still stop them.
134
+ */
135
+ stableIsolatedIdentity?: boolean;
136
+ /** Executor-owned base for public, per-revision native profile controls. */
137
+ publicProfileRevisionRoot?: string;
138
+ /** Executor-owned base for UID-restricted secret profile revisions. */
139
+ secretProfileRevisionRoot?: string;
140
+ /** Root-only 32-byte HMAC key; never copied into a turn result. */
141
+ secretProfileNamingKeyPath?: string;
142
+ /**
143
+ * True when the CLI runs inside a sandbox container or VM, where the OS
144
+ * boundary already confines file access. False or absent means the CLI may
145
+ * run on a developer's host, so harness path guards stay in force.
146
+ */
147
+ sandboxedRuntime?: boolean;
148
+ /** Portable profile applied to this provider execution. */
149
+ profile?: AgentProfile;
150
+ runtimeAttachments?: AgentRuntimeAttachments;
151
+ /**
152
+ * Per-turn credential values resolved by secret references in this
153
+ * execution's runtime MCP attachments. The materialization secret provider
154
+ * checks this map before the host box environment; values are launch
155
+ * state only and never enter the CLI's inherited environment or logs.
156
+ */
157
+ runtimeSecrets?: Record<string, string>;
158
+ /** Path to the CLI executable */
159
+ cliPath?: string;
160
+ /** Default model to use */
161
+ model?: string;
162
+ /** Model provider selected by the caller. */
163
+ provider?: string;
164
+ /** API key (provider-specific env var name) */
165
+ apiKey?: string;
166
+ /** OpenAI-compatible or provider-native base URL. */
167
+ baseUrl?: string;
168
+ /** Optional auth files to materialize under the runtime home directory. */
169
+ authFiles?: Array<{
170
+ path: string;
171
+ content: string;
172
+ mode?: number;
173
+ }>;
174
+ /** Extra flags to pass to the CLI */
175
+ extraFlags?: string[];
176
+ /**
177
+ * Bypass all permission checks for fully autonomous operation.
178
+ * Each CLI has its own flag:
179
+ * - Claude Code: --dangerously-skip-permissions
180
+ * - Codex: --dangerously-bypass-approvals-and-sandbox
181
+ * - Factory Droids: --autonomy-level skip-permissions-unsafe
182
+ * Default: true (for headless/automated use)
183
+ */
184
+ bypassPermissions?: boolean;
185
+ /**
186
+ * Enable structured human interactions by kind. `true` means "all supported
187
+ * kinds for this adapter"; object form is the precise public surface:
188
+ * `{ question: true }`, `{ permission: true }`, `{ plan: true }`.
189
+ *
190
+ * Each adapter maps these requested kinds onto its native transport (MCP,
191
+ * reverse RPC, or extension hook) while all responses flow through the same
192
+ * `/interactions` API.
193
+ */
194
+ interactions?: InteractionToggleConfig;
195
+ }
196
+ /**
197
+ * Options for CLI provider adapter constructors.
198
+ */
199
+ interface CliProviderOptions<TConfig extends CliProviderConfig = CliProviderConfig> {
200
+ /** Provider configuration */
201
+ config?: TConfig;
202
+ /** Logger instance */
203
+ logger?: CliProviderLogger;
204
+ /** Base storage path for session persistence */
205
+ storagePath?: string;
206
+ /** Storage subdirectory name (e.g., ".claude-code", ".codex") */
207
+ storageDir?: string;
208
+ /** Resolve opaque AgentProfile secret references at the private spawn boundary. */
209
+ profileSecretProvider?: AgentProfileSecretProvider;
210
+ /**
211
+ * For a secret profile revision: the keys the runtime itself manages (the
212
+ * box's TANGLE_API_KEY), which a turn may not deliver as runtimeSecrets.
213
+ * Their values reach only the executor's own MCP serving, never the launch.
214
+ * Anything else a secret revision references comes from runtimeSecrets.
215
+ */
216
+ secretProfileRuntimeKeyProvider?: AgentProfileSecretProvider;
217
+ /**
218
+ * Environment every CLI child gets in place of the inherited one for these
219
+ * keys: in a sandbox, the agent user's own HOME, PATH and cache paths, so a
220
+ * child never inherits the supervisor's cache paths it cannot write. The
221
+ * adapter's own environment still wins for any key it sets.
222
+ */
223
+ agentEnvironment?: () => Record<string, string | undefined>;
224
+ /**
225
+ * Start each turn's CLI through the consumer's own executor (a container
226
+ * slot, a jail) instead of a local spawn. It receives the assembled argv,
227
+ * cwd and environment; the adapter still parses, times and stops the turn.
228
+ */
229
+ launcher?: CliLauncher;
230
+ /**
231
+ * Stop what a turn's CLI leaves running in its process group when it exits.
232
+ * Off by default: a sandbox turn may start a process meant to outlive it.
233
+ */
234
+ ownProcessGroup?: boolean;
235
+ }
236
+ /**
237
+ * Per-turn input a CLI adapter reads beyond AgentExecutionInput: text added
238
+ * after the harness's own system prompt (a chat caller's system messages),
239
+ * kept apart from `systemPrompt`, which replaces it.
240
+ */
241
+ type CliExecutionInput = AgentExecutionInput & {
242
+ appendSystemPrompt?: string;
243
+ };
244
+ /**
245
+ * CLI execution arguments.
246
+ */
247
+ interface CliExecArgs {
248
+ /** CLI command */
249
+ command: string;
250
+ /** Command arguments */
251
+ args: string[];
252
+ /** Whether to send message via stdin */
253
+ useStdin: boolean;
254
+ /** Stdin prompt text before provider formatting. Defaults to the prepared user prompt. */
255
+ stdin?: string;
256
+ /**
257
+ * Working directory for the spawned process. Defaults to the execution
258
+ * workspaceRoot when omitted. Set when the CLI must run from a different root
259
+ * than the session workspace — e.g. nanoclaw's chat script derives its data
260
+ * dir (the daemon's Unix socket) from cwd, so it must run from the runtime
261
+ * root, not the sandbox workspace.
262
+ */
263
+ cwd?: string;
264
+ }
265
+ /**
266
+ * Internal state for tracking tool calls during execution.
267
+ */
268
+ interface ToolCallState {
269
+ id: string;
270
+ name: string;
271
+ input: unknown;
272
+ startTime: number;
273
+ status: "pending" | "running" | "completed" | "failed";
274
+ output?: unknown;
275
+ }
276
+ /**
277
+ * Internal state for an execution run.
278
+ */
279
+ interface ExecutionState {
280
+ /** Session ID (from provider or our persistence layer) */
281
+ sessionId?: string;
282
+ /** Message ID for part correlation */
283
+ messageId?: string;
284
+ /**
285
+ * Absolute root the CLI process ran with as its cwd. Used by
286
+ * `trackFilePart` to resolve a relative path it observes into the same
287
+ * absolute path a sibling observation reports absolutely, so the two unify
288
+ * on one dedupe key/url instead of minting divergent parts.
289
+ */
290
+ workspaceRoot?: string;
291
+ /** Text part ID (reused for streaming updates) */
292
+ textPartId?: string;
293
+ /** Active tool calls */
294
+ toolCalls: Map<string, ToolCallState>;
295
+ /** Accumulated text content */
296
+ textBuffer: string;
297
+ /** Accumulated reasoning/thinking blocks */
298
+ reasoningBuffer: string[];
299
+ /**
300
+ * Reasoning parts emitted so far — one entry per distinct reasoning block,
301
+ * carrying the stable part id downstream consumers key on. Maintained by
302
+ * `trackReasoningBlock`.
303
+ */
304
+ reasoningParts?: Array<{
305
+ id: string;
306
+ text: string;
307
+ }>;
308
+ /**
309
+ * File parts announced this reply, deduped by normalized path/data-URI key.
310
+ * Maintained by `trackFilePart`.
311
+ */
312
+ fileParts?: Array<{
313
+ id: string;
314
+ key: string;
315
+ filename?: string;
316
+ mediaType?: string;
317
+ url: string;
318
+ }>;
319
+ /** Structured native failure retained through process exit. */
320
+ failure?: {
321
+ message: string;
322
+ code?: string;
323
+ statusCode?: number;
324
+ };
325
+ /** Latest provider warning emitted before process exit. */
326
+ lastDiagnostic?: string;
327
+ /** Latest terminal status emitted by the provider stream. */
328
+ terminalStatus?: "completed" | "failed";
329
+ /** Observed usage; absent channels were not reported by the provider. */
330
+ tokenUsage?: Partial<TokenUsage>;
331
+ }
332
+ //#endregion
333
+ //#region src/acp-protocol.d.ts
334
+ /** The ACP protocol version this client speaks, and the oldest it accepts. */
335
+ declare const ACP_PROTOCOL_VERSION = 1;
336
+ declare const ACP_MIN_PROTOCOL_VERSION = 1;
337
+ /** Settings every ACP agent process takes. */
338
+ interface AcpBridgeConfig extends CliProviderConfig {
339
+ /** Protocol version requested in `initialize` (default 1). */
340
+ protocolVersion?: number;
341
+ /** Timeout for one `session/prompt` turn (default 10 min). */
342
+ promptTimeoutMs?: number;
343
+ /** Timeout for `initialize` and `session/new|load` (default 2 min). */
344
+ bootstrapTimeoutMs?: number;
345
+ /**
346
+ * How long an idle session keeps its agent process (default 5 min).
347
+ * 0 closes the process after every turn.
348
+ */
349
+ bridgeIdleMs?: number;
350
+ }
351
+ /** ACP content blocks this client reads or sends. */
352
+ type AcpContentBlock = {
353
+ type: "text";
354
+ text: string;
355
+ } | {
356
+ type: "image";
357
+ data?: string;
358
+ mimeType?: string;
359
+ uri?: string;
360
+ } | {
361
+ type: "resource";
362
+ uri: string;
363
+ mimeType?: string;
364
+ } /** Tool-call content: one content block wrapped one level deeper. */ | {
365
+ type: "content";
366
+ content: {
367
+ type: "text";
368
+ text: string;
369
+ };
370
+ };
371
+ interface AcpInitializeParams {
372
+ protocolVersion: number;
373
+ clientCapabilities: {
374
+ fs?: {
375
+ readTextFile?: boolean;
376
+ writeTextFile?: boolean;
377
+ };
378
+ terminal?: boolean;
379
+ };
380
+ }
381
+ interface AcpInitializeResult {
382
+ protocolVersion: number;
383
+ agentCapabilities?: Record<string, unknown>;
384
+ agentInfo?: {
385
+ name?: string;
386
+ title?: string;
387
+ version?: string;
388
+ };
389
+ authMethods?: Array<{
390
+ id: string;
391
+ name?: string;
392
+ description?: string;
393
+ }>;
394
+ }
395
+ interface AcpNewSessionResult {
396
+ sessionId: string;
397
+ }
398
+ interface AcpPromptResult {
399
+ stopReason: "end_turn" | "max_tokens" | "max_turn_requests" | "refusal" | "cancelled" | string;
400
+ }
401
+ /** `session/update` notification params; only the mapped kinds are typed. */
402
+ interface AcpSessionUpdateParams {
403
+ sessionId: string;
404
+ update: {
405
+ sessionUpdate: "agent_message_chunk" | "agent_thought_chunk";
406
+ content: AcpContentBlock | AcpContentBlock[];
407
+ } | {
408
+ sessionUpdate: "tool_call";
409
+ toolCallId: string;
410
+ title?: string;
411
+ kind?: string;
412
+ status?: "pending" | "in_progress" | "completed" | "failed";
413
+ rawInput?: unknown;
414
+ } | {
415
+ sessionUpdate: "tool_call_update";
416
+ toolCallId: string;
417
+ status?: "pending" | "in_progress" | "completed" | "failed";
418
+ content?: AcpContentBlock[];
419
+ rawOutput?: unknown;
420
+ } | {
421
+ sessionUpdate: "plan";
422
+ entries: Array<{
423
+ content: string;
424
+ priority?: string;
425
+ status?: string;
426
+ }>;
427
+ } | {
428
+ sessionUpdate: string;
429
+ [key: string]: unknown;
430
+ };
431
+ }
432
+ /** One turn's inputs, resolved before any session or process work. */
433
+ interface AcpTurn<TConfig extends AcpBridgeConfig> {
434
+ readonly config: TConfig;
435
+ /**
436
+ * The process configuration a cached session was started with. A turn
437
+ * with a different key gets a new process: an ACP agent reads its model
438
+ * and backing agent once, at startup.
439
+ */
440
+ readonly processKey: string;
441
+ }
442
+ /** Text carried by ACP content blocks, including tool-call content. */
443
+ declare function acpContentText(content: AcpContentBlock | AcpContentBlock[] | undefined): string;
444
+ /** Map an ACP stop reason onto a turn status. */
445
+ declare function mapAcpStopReason(reason: string | undefined): {
446
+ status: "completed" | "failed";
447
+ detail?: string;
448
+ };
449
+ //#endregion
450
+ //#region src/turn-process.d.ts
451
+ /** A turn transport may finish while its provider server remains alive. */
452
+ type CliTurnProcess = Pick<CliProcess, "pid" | "write" | "closeInput" | "kill" | "exitPromise" | "beginRawCapture"> & {
453
+ stderr?: NodeJS.ReadableStream;
454
+ };
455
+ type CliTurnSpawn<TConfig, TEvent> = {
456
+ input: AgentExecutionInput;
457
+ sessionId: string;
458
+ providerSessionId?: string;
459
+ config: TConfig;
460
+ execArgs: CliExecArgs;
461
+ workspaceRoot: string;
462
+ env: Record<string, string | undefined>;
463
+ signal: AbortSignal;
464
+ timeoutMs?: number;
465
+ parser: StreamParserConfig<TEvent>;
466
+ /**
467
+ * A process started before the turn it serves (a held spare): its raw
468
+ * capture opens when a turn adopts it (`beginRawCapture`), inside that
469
+ * turn's attempt, not at spawn.
470
+ */
471
+ deferRawCapture?: boolean;
472
+ };
473
+ /** One turn's launch, prepared for a caller that runs the process itself. */
474
+ type PreparedCliLaunch = {
475
+ /** Pass to `execCli` or `launchCliProcess`, adding `signal` and `timeoutMs`. */spawn: CliSpawnConfig; /** Write to the child's stdin and close it; absent when the prompt is in argv. */
476
+ stdin?: string; /** The native session id the argv names, for a harness that pre-mints it. */
477
+ nativeSessionId?: string; /** The profile's workspace files and spawn inputs that were applied. */
478
+ workspacePlan?: WorkspacePlanReceipt;
479
+ };
480
+ //#endregion
481
+ //#region src/adapter-lifecycle.d.ts
482
+ /** Owns configuration, initialization, cancellation, and subprocess identity. */
483
+ declare abstract class CliAdapterLifecycle<TConfig extends CliProviderConfig = CliProviderConfig> {
484
+ abstract readonly provider: string;
485
+ protected abstract readonly defaultCliPath: string;
486
+ /**
487
+ * The message log directory when the caller names none. Unset, it is the
488
+ * registry spec's `messageStorageDir` for `provider`, the one source; only
489
+ * an adapter for a provider the registry does not know sets it.
490
+ */
491
+ protected readonly defaultStorageDir?: string;
492
+ protected readonly inheritProcessEnv: boolean;
493
+ protected config: TConfig;
494
+ private readonly initialConfig;
495
+ protected logger: CliProviderLogger;
496
+ protected sessionStore: SessionStore | null;
497
+ protected messageStore: MessageStore | null;
498
+ protected storagePath: string;
499
+ private _storageDir;
500
+ private readonly agentEnvironment;
501
+ /** The consumer's executor for turn processes; a local spawn when absent. */
502
+ protected readonly launcher: CliLauncher | undefined;
503
+ /** Whether a turn's leftover process-group members are stopped at exit. */
504
+ protected readonly ownProcessGroup: boolean;
505
+ protected initialized: boolean;
506
+ protected readonly activeProcesses: Set<CliTurnProcess>;
507
+ private readonly initialization;
508
+ constructor(options?: CliProviderOptions<TConfig>);
509
+ /**
510
+ * Get the storage directory. Uses provided storageDir or falls back to defaultStorageDir.
511
+ */
512
+ protected get storageDir(): string;
513
+ /** Bind a live interaction to the exact provider execution that originated it. */
514
+ protected interactionExecutionBinding(input: AgentExecutionInput, sessionId: string): InteractionExecutionBinding;
515
+ /**
516
+ * The uid/gid every CLI process this adapter spawns runs as, or undefined
517
+ * when the host process is already unprivileged.
518
+ *
519
+ * This is an adapter-wide invariant, not a per-callsite option, because
520
+ * these CLIs seed their own state on first use — a sqlite database, a log
521
+ * directory, a downloaded-binary cache under the harness HOME. An auxiliary
522
+ * invocation left at root (`mcp add`, `mcp list`, `--version`) creates that
523
+ * tree root-owned, and the streamed run, which does drop privileges, then
524
+ * cannot open its own log and exits before emitting a single event.
525
+ */
526
+ protected subprocessIdentity(): {
527
+ uid: number;
528
+ gid: number;
529
+ } | undefined;
530
+ /** `subprocessIdentity` shaped for `spawn`'s options bag. */
531
+ protected subprocessSpawnOptions(): {
532
+ uid?: number;
533
+ gid?: number;
534
+ };
535
+ /**
536
+ * Run a one-shot CLI command under this adapter's subprocess identity.
537
+ *
538
+ * Every auxiliary invocation an adapter makes goes through here so the
539
+ * identity cannot be forgotten at a call site. Auxiliary output stays out
540
+ * of the streamed turn's raw evidence.
541
+ */
542
+ protected runCli(config: Omit<CliSpawnConfig, "rawCapturePath">): Promise<CliExecResult<unknown>>;
543
+ /**
544
+ * Run a builtin-only Node script under this adapter's subprocess identity
545
+ * and return its stdout. File work inside a directory the CLI user owns goes
546
+ * through here, so a root sidecar never creates, reads or writes there with
547
+ * its own rights: a link the agent plants reaches only what the agent could
548
+ * already reach. The script reads `args` from argv after `--` and `input`
549
+ * from stdin. A failure carries the script's stderr, not the script text.
550
+ */
551
+ protected runNodeAsSubprocess(script: string, args: readonly string[], input?: string): Promise<string>;
552
+ getCapabilities(): BackendCapabilities;
553
+ initialize(config: ProviderConfig & Pick<CliProviderConfig, "runtimeAttachments">): Promise<void>;
554
+ private initializeAtGeneration;
555
+ /**
556
+ * Auth/config files the adapter needs on disk that do NOT arrive through
557
+ * `config.model.authFiles` — e.g. a synthesized `~/.openclaw/openclaw.json`
558
+ * pointing at the managed router. The sidecar materializes these through the
559
+ * hardened `materializeCliAuthFiles` path AFTER `initialize()`, so an adapter
560
+ * can derive them from the resolved config/env. Default: none.
561
+ */
562
+ getManagedAuthFiles(): CliAuthFile[];
563
+ /** Provider-specific initialization runs inside the tracked lifecycle. */
564
+ protected afterInitialize(_config: ProviderConfig): Promise<void>;
565
+ /**
566
+ * The harness session contract this adapter honours (cli-agent-registry
567
+ * NATIVE_SESSION_CONTRACTS), or null for a provider that declares none.
568
+ * Registration refuses a harness spec without one; ACP overrides this per
569
+ * sub-agent.
570
+ */
571
+ protected sessionContract(): HarnessSessionContract | null;
572
+ shutdown(): Promise<void>;
573
+ healthCheck(): Promise<boolean>;
574
+ /** Run this CLI's own one-shot command (version, MCP) in the workspace. */
575
+ protected runAuxiliaryCli(args: string[], timeoutMs: number): Promise<CliExecResult<unknown>>;
576
+ updateConfig(config: Partial<TConfig>): Promise<TConfig>;
577
+ /**
578
+ * Build environment variables for CLI execution.
579
+ */
580
+ protected abstract buildExecEnv(config: TConfig): Record<string, string | undefined>;
581
+ /** Apply private native credentials to every CLI subprocess through one path. */
582
+ protected buildNativeExecutionEnvironment(config: TConfig): Record<string, string | undefined>;
583
+ protected getCliPath(): string;
584
+ protected ensureInitialized(): void;
585
+ protected getSessionStore(): SessionStore;
586
+ protected getMessageStore(): MessageStore;
587
+ /** The agent environment the host supplied (CliProviderOptions.agentEnvironment). */
588
+ protected agentEnvironmentValues(): Record<string, string | undefined>;
589
+ protected applyWritableHomeDefaults(adapterEnv: Record<string, string | undefined>, workspaceRoot: string): Record<string, string | undefined>;
590
+ }
591
+ //#endregion
592
+ //#region src/adapter-profile.d.ts
593
+ /** Owns native profile revisions, launch controls, and prompt composition. */
594
+ declare abstract class CliAdapterProfile<TConfig extends CliProviderConfig = CliProviderConfig> extends CliAdapterLifecycle<TConfig> {
595
+ /** Native profile lowering explicitly owned by this adapter, never inferred from a path. */
596
+ protected readonly profileHarness: HarnessId$1 | undefined;
597
+ /** Trusted implementation capabilities; never read from caller-owned configuration. */
598
+ protected readonly supportsSecretProfileRevisions: boolean;
599
+ private readonly profileSecretProvider;
600
+ private readonly secretProfileRuntimeKeyProvider;
601
+ /**
602
+ * The materialized digest behind each secret revision. It stays here: the
603
+ * executor receipt is all a caller sees of a revision's resolved contents.
604
+ */
605
+ private readonly secretProfileMaterializedDigests;
606
+ /**
607
+ * The value behind each `{env:NAME}` reference in a secret revision's
608
+ * config, by that revision's application. Executor memory only: no launch
609
+ * environment, argv or file ever carries them.
610
+ */
611
+ private readonly secretProfileReferenceValues;
612
+ constructor(options?: CliProviderOptions<TConfig>);
613
+ /** Apply captured diagnostic identity to this spawn, after profile composition. */
614
+ /** The exact child environment a turn uses; shared with prewarm paths. */
615
+ protected buildTurnEnvironment(executionConfig: TConfig, profilePlan: WorkspacePlanApplication$1 | undefined, workspaceRoot: string, correlationHeaders: Readonly<Record<string, string>> | undefined): Record<string, string | undefined>;
616
+ /**
617
+ * A profile's declared executable tools, sealed in its revision, stand in
618
+ * for the app's own tool dirs on this launch's PATH tail. A secret profile's
619
+ * env no longer names the app's dirs (app env is scrubbed), so the sidecar's
620
+ * own SANDBOX_TOOL_BIN_DIRS says which inherited PATH entries they are.
621
+ */
622
+ private bindProfileToolBinDirs;
623
+ protected bindExecutionCorrelation(environment: Record<string, string | undefined>, correlationHeaders: Readonly<Record<string, string>> | undefined): Record<string, string | undefined>;
624
+ /**
625
+ * Provision the inline profile's files and native execution controls with the
626
+ * shared materializer used by cli-bridge. Unsupported portable controls fail
627
+ * before spawn unless the profile is explicitly best-effort
628
+ * (resources.failOnError: false), which materializes the supported subset
629
+ * and warns about the rest.
630
+ */
631
+ /**
632
+ * Launcher controls this adapter OWNS on the spawn it starts — see
633
+ * `BINDABLE_LAUNCH_CONTROLS` in the materializer. Empty by default: a plan
634
+ * whose intent needs a launcher binding then fails closed instead of being
635
+ * silently dropped. An adapter that really applies the plan's launch flags
636
+ * to its own spawn (sdk-provider-opencode selecting the plan's primary
637
+ * agent via `--agent`) overrides this with the controls it honors.
638
+ */
639
+ protected profileMaterializationBinds(): readonly BindableLaunchControl[];
640
+ /** Optional native instruction root. The adapter owns how its runtime locates this directory. */
641
+ protected profileAgentDirectory(_workspaceRoot: string): string | undefined;
642
+ /** Provider transport bound into the private immutable revision and receipt. */
643
+ protected secretProfileProviderConfig(): Record<string, unknown> | undefined;
644
+ /**
645
+ * The values behind a secret revision's `{env:NAME}` config references, for
646
+ * an executor that serves those references itself. Never pass them to the
647
+ * native process.
648
+ */
649
+ protected secretProfileReferences(application: WorkspacePlanApplication$1 | undefined): Readonly<Record<string, string>> | undefined;
650
+ protected materializeProfileResources(inputProfile: AgentProfile | undefined, workspaceRoot: string, ownerId?: string, sessionId?: string, scope?: "turn" | "prewarm"): Promise<WorkspacePlanApplication$1 | undefined>;
651
+ private applyProfileResources;
652
+ /**
653
+ * Publish the profile as an executor-sealed revision for this session's
654
+ * subprocess identity, and record the receipt that binds it to the turn.
655
+ */
656
+ private applySecretProfileRevision;
657
+ /**
658
+ * Prepare the same provider-composed native plan that execute() will check.
659
+ * This may publish an immutable public revision, but never starts a model turn.
660
+ */
661
+ preparePublicProfileRevision(input: AgentExecutionInput): Promise<{
662
+ workspacePlanDigest: string;
663
+ materializedDigest: string;
664
+ launchDigest: string;
665
+ conflicts: Array<{
666
+ relPath: string;
667
+ copyRelPath: string;
668
+ reason: "existing" | "symlink";
669
+ }>;
670
+ }>;
671
+ /** Prepare the private native plan and return only an opaque executor receipt. */
672
+ prepareSecretProfileRevision(input: AgentExecutionInput): Promise<{
673
+ workspacePlanDigest: string;
674
+ executorReceipt: string;
675
+ conflicts: Array<{
676
+ relPath: string;
677
+ copyRelPath: string;
678
+ reason: "existing" | "symlink";
679
+ }>;
680
+ }>;
681
+ /**
682
+ * What the native health check's verdict depends on besides a revision's
683
+ * bytes: the executable that loads them. A provider whose check runs
684
+ * through a configurable binary names it here.
685
+ */
686
+ protected secretProfileVerificationScope(): string;
687
+ /** A secret receipt is issued only after the provider can load this revision. */
688
+ protected verifyPreparedSecretProfileRevision(_input: AgentExecutionInput, _application: WorkspacePlanApplication$1): Promise<void>;
689
+ /** Resolve the canonical profile used for this execution. */
690
+ protected resolveExecutionProfile(requestPrompt: string | undefined): AgentProfile | undefined;
691
+ /** Select the profile materialized for this exact turn. */
692
+ protected resolveExecutionProfileForInput(input: AgentExecutionInput): AgentProfile | undefined;
693
+ /** Compose the provider's user-message channel for this exact turn. */
694
+ protected composePromptText(promptText: string, input: AgentExecutionInput): string;
695
+ protected withProfilePlan(config: TConfig, profilePlan: WorkspacePlanApplication$1 | undefined): TConfig;
696
+ protected resolveProfileSystemPrompt(requestPrompt: string | undefined, profilePlan: WorkspacePlanApplication$1 | undefined): string | undefined;
697
+ /**
698
+ * The plan's additive prompt intent for this spawn. No request-level
699
+ * counterpart exists (`AgentExecutionInput` carries only the replacement),
700
+ * so unlike {@link resolveProfileSystemPrompt} there is nothing to
701
+ * conflict-check against.
702
+ */
703
+ protected resolveProfileAppendSystemPrompt(profilePlan: WorkspacePlanApplication$1 | undefined): string | undefined;
704
+ protected resolveProfileModel(requestModel: string | undefined): string | undefined;
705
+ protected mergeProfilePlanEnvironment(environment: Record<string, string | undefined>, profilePlan: WorkspacePlanApplication$1 | undefined, preserveClearedVariables?: boolean): Record<string, string | undefined>;
706
+ /** Provider-owned allowlist for a generated revision control after env scrub. */
707
+ protected profilePlanMayFillClearedEnvironmentVariable(_name: string, _value: string): boolean;
708
+ protected preparePromptInput(parts: InputPart[], workspaceRoot: string, sessionId: string, options?: {
709
+ /** Override of the per-request inline-image budget — pass 0 on paths
710
+ * that deliver markers only and would discard the base64. */
711
+ inlineImageBudgetBytes?: number;
712
+ /** Override of the adapter's nativeAttachmentKinds() for this call —
713
+ * pass [] on paths that cannot forward any kind natively, so every
714
+ * attachment keeps its canonical text marker. */
715
+ nativeAttachmentKinds?: ReadonlyArray<"image" | "file">;
716
+ }): Promise<{
717
+ promptText: string;
718
+ persistedParts: MessagePart[];
719
+ attachments: PreparedAttachment[];
720
+ }>;
721
+ /**
722
+ * Attachment kinds this adapter forwards natively via buildExecArgs (argv
723
+ * flag / stdin content block) instead of the `[Image: ...]` / `[File: ...]`
724
+ * text marker. The base adapter omits those kinds' markers from the prompt
725
+ * text — an adapter that opts a kind in MUST deliver every attachment of
726
+ * that kind itself, or the model never sees it.
727
+ */
728
+ protected nativeAttachmentKinds(): ReadonlyArray<"image" | "file">;
729
+ }
730
+ //#endregion
731
+ //#region src/adapter-sessions.d.ts
732
+ /** Owns durable transcripts, provider-native session bindings and the turn hooks providers override. */
733
+ declare abstract class CliAdapterSessions<TConfig extends CliProviderConfig = CliProviderConfig> extends CliAdapterProfile<TConfig> {
734
+ createSession(options?: {
735
+ workspaceRoot?: string;
736
+ }): Promise<string>;
737
+ deleteSession(sessionId: string): Promise<boolean>;
738
+ /**
739
+ * Choose the native ID before its argv check, durable binding, and
740
+ * reservation. `input` and `timeoutMs` are the turn's, for a harness that
741
+ * decides here whether a process started earlier can serve it.
742
+ */
743
+ protected mintNativeSessionId(_context: {
744
+ sessionId: string;
745
+ workspaceRoot: string;
746
+ config: TConfig;
747
+ model?: string;
748
+ env: Record<string, string | undefined>;
749
+ signal: AbortSignal;
750
+ buildExecArgs: (nativeSessionId: string) => CliExecArgs;
751
+ input: AgentExecutionInput;
752
+ timeoutMs?: number;
753
+ }): string | Promise<string>;
754
+ /**
755
+ * Make a pre-minted native session durable before the CLI starts, for a
756
+ * harness that would otherwise write nothing until its first model reply
757
+ * (Pi). Called after the argv check and before spawn.
758
+ */
759
+ protected reserveNativeSession(_nativeSessionId: string, _context: {
760
+ workspaceRoot: string;
761
+ }): void | Promise<void>;
762
+ /**
763
+ * Verify that the provider can resume the native session binding. By
764
+ * default a session in a per-session store is resumable only when one of
765
+ * its declared files exists under the runtime HOME; a pre-minted id whose
766
+ * first turn died before the CLI wrote anything is not.
767
+ */
768
+ protected providerSessionIsResumable(runtimeHome: string, providerSessionId: string): boolean | Promise<boolean>;
769
+ /**
770
+ * Resolve the provider-native session id the next turn can resume, or
771
+ * undefined when no usable binding exists. Provider session data lives
772
+ * under the runtime home that minted it. A different home or missing
773
+ * provider storage cannot resume that session. A record without a home
774
+ * stamp predates the field, so treat it as same-home.
775
+ */
776
+ protected resumableProviderSessionId(session: PersistedSession): Promise<string | undefined>;
777
+ /** Bind a checkpoint-proven native session to this provider identity before execution. */
778
+ protected seedNativeSessionForResume(input: AgentExecutionInput, nativeSessionId: string): Promise<void>;
779
+ /**
780
+ * Forks the persisted session and copies its messages up to `messageId`.
781
+ * The forked record carries no provider session id, so its first turn
782
+ * starts a fresh CLI session and receives the copied transcript as
783
+ * execution-only context. Callers that address turns by their own session
784
+ * id (the sidecar) pass that id as `targetSessionId` so later turns find
785
+ * the forked record.
786
+ */
787
+ forkSession(options: {
788
+ sessionId: string;
789
+ messageId?: string;
790
+ workspaceRoot?: string;
791
+ targetSessionId?: string;
792
+ }): Promise<string>;
793
+ getMessages(options: GetMessagesOptions): Promise<BackendMessage[]>;
794
+ protected toBackendMessage(msg: PersistedMessage): BackendMessage;
795
+ protected buildAssistantParts(state: ExecutionState): MessagePart[];
796
+ protected extractToolInvocations(state: ExecutionState): AgentExecutionResult["toolInvocations"];
797
+ /**
798
+ * Names of tools this provider substitutes for a model tool call it could
799
+ * not parse into any real tool.
800
+ *
801
+ * Default: none. A provider that has one must say so, because these calls
802
+ * do not present as failures. OpenCode's `invalid` reports the parse error
803
+ * as its output and completes, so the repeated-failure guard reads a run of
804
+ * them as progress and clears its count on every one.
805
+ */
806
+ protected toolCallRepairToolNames(): ReadonlySet<string>;
807
+ /**
808
+ * Decide whether a non-zero exit should be treated as success.
809
+ *
810
+ * Default: no — any non-zero exit is a failure.
811
+ *
812
+ * Providers override this when their CLI has a known "exits non-zero
813
+ * on a successful run" quirk (e.g. kimi writes its resume trailer to
814
+ * stderr and exits non-zero even when the task completed cleanly).
815
+ *
816
+ * The decision is made AFTER the stream has drained and the exit
817
+ * code is known, so `state` reflects the full set of events the
818
+ * parser emitted (including any terminal `result` / `done` event).
819
+ * A safe heuristic is: "non-zero exit + stderr matches known trailer
820
+ * pattern + at least one assistant part was recorded".
821
+ */
822
+ protected isBenignNonZeroExit(_params: {
823
+ exitCode: number | null;
824
+ stderr: string;
825
+ state: ExecutionState;
826
+ }): boolean;
827
+ /** Observe settled process output before success/failure classification. */
828
+ protected afterCliProcessExit(_params: {
829
+ state: ExecutionState;
830
+ stderr: string;
831
+ exit: CliExitResult;
832
+ workspaceRoot: string;
833
+ env: Record<string, string | undefined>;
834
+ onEvent?: (event: StreamEvent) => void;
835
+ }): Promise<void>;
836
+ protected executionOutcome(_state: ExecutionState, _input: AgentExecutionInput): AgentExecutionOutcome | Promise<AgentExecutionOutcome>;
837
+ /**
838
+ * Format a message for stdin input.
839
+ */
840
+ protected formatStdinMessage(message: string): string;
841
+ }
842
+ //#endregion
843
+ //#region src/adapter-mcp.d.ts
844
+ /** Owns serialized MCP mutations and provider-native MCP status commands. */
845
+ declare abstract class CliAdapterMcp<TConfig extends CliProviderConfig = CliProviderConfig> extends CliAdapterSessions<TConfig> {
846
+ /** Budget for one `mcp list` run, CLI startup and every server's handshake. */
847
+ protected readonly mcpStatusTimeoutMs: number;
848
+ private mcpMutationChain;
849
+ addMcp(name: string, config: McpConfig): Promise<void>;
850
+ private addMcpSerialized;
851
+ getMcpStatus(): Promise<McpStatusResponse>;
852
+ ensureMcps(required: Record<string, McpConfig>): Promise<void>;
853
+ /** Build MCP add command arguments. Override for CLI-specific syntax. */
854
+ protected buildMcpAddArgs(name: string, config: McpConfig): string[];
855
+ /**
856
+ * Build MCP list command arguments. Return null if not supported.
857
+ */
858
+ protected buildMcpListArgs(): string[] | null;
859
+ /** Parse MCP list output. Override for CLI-specific output format. */
860
+ protected parseMcpListOutput(output: string): McpStatusResponse;
861
+ }
862
+ //#endregion
863
+ //#region src/turn-observer.d.ts
864
+ interface TurnObserverOptions {
865
+ provider: string;
866
+ state: ExecutionState;
867
+ sessionId: string;
868
+ getRuntimeHome: () => string | undefined;
869
+ recorder: SdkHostServices["recorder"];
870
+ getSessionStore: () => SessionStore;
871
+ logger: CliProviderLogger;
872
+ repairToolNames: ReadonlySet<string>;
873
+ onEvent: ((event: StreamEvent) => void) | undefined;
874
+ }
875
+ /**
876
+ * Observes one turn's provider stream: keeps the execution state current,
877
+ * persists parts and the provider session id as they arrive, stops a turn
878
+ * that repeats a rejected tool call, and pings while the stream is quiet.
879
+ */
880
+ declare class TurnObserver {
881
+ private readonly options;
882
+ providerSessionPersistence: Promise<void>;
883
+ providerSessionPersistenceError: unknown;
884
+ repeatedToolFailureTripped: boolean;
885
+ nativeSessionObserved: boolean;
886
+ private readonly partUpdates;
887
+ private readonly liveness;
888
+ private readonly repeatedToolFailureGuard;
889
+ private killForRepeatedToolFailure;
890
+ constructor(options: TurnObserverOptions);
891
+ flushPartUpdates(): Promise<void>;
892
+ attachProcess(process: CliTurnProcess): void;
893
+ startLiveness(executionSignal: AbortSignal, startTime: number): NodeJS.Timeout;
894
+ readonly onEvent: (event: StreamEvent) => void;
895
+ private observeToolPart;
896
+ private persistProviderSession;
897
+ }
898
+ //#endregion
899
+ //#region src/execution-state.d.ts
900
+ /**
901
+ * Creates a new execution state.
902
+ */
903
+ declare function createExecutionState(sessionId?: string, messageId?: string, workspaceRoot?: string): ExecutionState;
904
+ //#endregion
905
+ //#region src/profile-config.d.ts
906
+ /**
907
+ * Per-turn credential delivery wins over host-env resolution; the host box
908
+ * environment stays the fallback for references the turn did not deliver.
909
+ * With no turn secrets the host provider is returned unchanged, so the
910
+ * overlay adds no behavior to executions that never asked for it.
911
+ */
912
+ declare function runtimeSecretsOverlay(runtimeSecrets: Record<string, string> | undefined, fallback: AgentProfileSecretProvider): AgentProfileSecretProvider;
913
+ //#endregion
914
+ //#region src/base-adapter.d.ts
915
+ /**
916
+ * Base adapter for CLI-based AI agent providers.
917
+ *
918
+ * Subclasses must implement:
919
+ * - provider: string identifier
920
+ * - defaultCliPath: default CLI executable name
921
+ * - buildExecArgs(): build CLI execution arguments
922
+ * - buildExecEnv(): build environment variables
923
+ * - createEventParser(): create JSONL event parser
924
+ * - mapEventToStreamEvents(): map parsed events to StreamEvents
925
+ *
926
+ * The message log directory is the registry spec's `messageStorageDir` for
927
+ * `provider` (cli-agent-registry `messageStorageDirOf`); only an adapter for
928
+ * a provider the registry does not know sets `defaultStorageDir`.
929
+ *
930
+ * Optional overrides:
931
+ * - buildMcpAddArgs(): MCP add command arguments
932
+ * - buildMcpListArgs(): MCP list command arguments (if supported)
933
+ * - parseMcpListOutput(): parse MCP list output
934
+ */
935
+ declare abstract class CliProviderAdapterBase<TConfig extends CliProviderConfig = CliProviderConfig, TEvent = unknown> extends CliAdapterMcp<TConfig> implements SdkProviderAdapter {
936
+ protected readonly supportsManagedQuote: boolean;
937
+ execute(input: AgentExecutionInput, services: SdkHostServices, onEvent?: (event: StreamEvent) => void): Promise<AgentExecutionResult>;
938
+ private executeInternal;
939
+ /**
940
+ * Record a successful turn: the provider session id, the assistant message,
941
+ * and the result, cached for a same-turnId retry.
942
+ */
943
+ protected completeTurn(params: {
944
+ input: AgentExecutionInput;
945
+ sessionId: string;
946
+ state: ExecutionState; /** The CLI turn's observer, whose coalesced part updates drain first. */
947
+ observer?: TurnObserver;
948
+ recorder: SdkHostServices["recorder"];
949
+ providerMessageIds: ReturnType<typeof readProviderMessageIds>;
950
+ profilePlan?: WorkspacePlanApplication$1;
951
+ startTime: number;
952
+ endTime: number;
953
+ }): Promise<AgentExecutionResult>;
954
+ /** Report and record a failed turn, then throw its error. */
955
+ private failCliTurn;
956
+ /**
957
+ * Open the turn's session (sidecar/provider persistence only; native CLI
958
+ * startup is measured separately). A same-turnId retry of a completed turn
959
+ * gets that turn's cached result instead of running again.
960
+ */
961
+ protected openTurnSession(input: AgentExecutionInput, recorder: SdkHostServices["recorder"], onEvent: ((event: StreamEvent) => void) | undefined): Promise<{
962
+ providerMessageIds: any;
963
+ cached: AgentExecutionResult;
964
+ sessionId: string;
965
+ providerSessionId: string | undefined;
966
+ transcriptReplay: "fork" | "restored" | undefined;
967
+ } | {
968
+ providerMessageIds: any;
969
+ cached: undefined;
970
+ sessionId: string;
971
+ providerSessionId: string | undefined;
972
+ transcriptReplay: "fork" | "restored" | undefined;
973
+ }>;
974
+ /** Provision the profile's cwd-native dimensions for this turn. */
975
+ private materializeTurnProfile;
976
+ /**
977
+ * Prepare the prompt and record the caller's own parts. `promptText`
978
+ * additionally carries the replayed transcript and this turn's ephemeral
979
+ * context, which are execution-only and stay out of both stores.
980
+ */
981
+ protected recordTurnPrompt(input: AgentExecutionInput, session: {
982
+ sessionId: string;
983
+ transcriptReplay: "fork" | "restored" | undefined;
984
+ providerMessageIds: ReturnType<typeof readProviderMessageIds>;
985
+ }, recorder: SdkHostServices["recorder"]): Promise<{
986
+ preparedInput: {
987
+ promptText: string;
988
+ persistedParts: readProviderMessageIds[];
989
+ attachments: PreparedAttachment[];
990
+ };
991
+ promptText: string;
992
+ }>;
993
+ /** Resolve this turn's config, environment and argv, and check them against the session contract. */
994
+ private planLaunch;
995
+ /** Reserve and announce the native session id a pre-minted harness already has. */
996
+ private bindNativeSession;
997
+ /** Spawn the turn's process, feed its input, and wait for it to exit. */
998
+ private runCliTurn;
999
+ /**
1000
+ * Build CLI execution arguments for the exec command.
1001
+ */
1002
+ protected abstract buildExecArgs(params: {
1003
+ message: string;
1004
+ config: TConfig; /** Canonical identity for providers whose native config binds HTTP headers. */
1005
+ correlationHeaders?: Readonly<Record<string, string>>;
1006
+ model?: string;
1007
+ sessionId?: string;
1008
+ /**
1009
+ * Set on a new session of a harness whose contract pre-mints its id: the
1010
+ * adapter MUST start the native session under this id with the contract's
1011
+ * identity args (e.g. `--session-id <id>`). The base checks the argv.
1012
+ */
1013
+ mintedSessionId?: string;
1014
+ workspaceRoot: string;
1015
+ systemPrompt?: string;
1016
+ /**
1017
+ * The plan's ADDITIVE prompt intent: the harness's own prompt stays in
1018
+ * force and this text is added after it. NEVER the same channel as
1019
+ * `systemPrompt` (a replacement) — an adapter must bind it to its
1020
+ * harness's additive control, not substitute one for the other.
1021
+ *
1022
+ * The materializer sets it only for harnesses whose addition control is a
1023
+ * launch argument (claude-code, pi and prime `--append-system-prompt`); an
1024
+ * adapter for such a harness MUST bind it, or the intent the plan asserted
1025
+ * supported is silently dropped. A profile that keeps the harness prompt
1026
+ * (keepsHarnessSystemPrompt) also receives the host prompt here; codex
1027
+ * binds it to `developer_instructions`, and opencode already carries it in
1028
+ * its materialized addition file.
1029
+ */
1030
+ appendSystemPrompt?: string;
1031
+ attachments?: PreparedAttachment[]; /** Preserve the origin of launch flags when a CLI needs one selected agent. */
1032
+ profilePlan?: WorkspacePlanApplication$1;
1033
+ }): CliExecArgs;
1034
+ /** Create the provider event parser for CLI output. */
1035
+ protected abstract createEventParser(state: ExecutionState, onEvent?: (event: StreamEvent) => void): StreamParserConfig<TEvent>;
1036
+ /** How one turn's argv runs: cwd, environment, identity or launcher, stdio. */
1037
+ private turnSpawnConfig;
1038
+ /**
1039
+ * The launch one turn would make, without starting it: the spawn config
1040
+ * (argv, cwd, environment, identity or launcher), the stdin payload, and
1041
+ * the profile files written into the workspace. Session and message
1042
+ * stores are untouched and no held process is reserved, so a caller that
1043
+ * runs the process itself (`execCli`) owns its output and lifecycle.
1044
+ */
1045
+ prepareLaunch(input: CliExecutionInput, options?: {
1046
+ providerSessionId?: string;
1047
+ }): Promise<PreparedCliLaunch>;
1048
+ /** Override only when the provider has a turn transport besides a CLI child. */
1049
+ protected spawnExecutionProcess(request: CliTurnSpawn<TConfig, TEvent>): CliTurnProcess | Promise<CliTurnProcess>;
1050
+ }
1051
+ //#endregion
1052
+ //#region src/acp-session-adapter.d.ts
1053
+ /**
1054
+ * Shared lifecycle of a provider that drives an Agent Client Protocol agent
1055
+ * over a JSON-RPC stdio bridge: one cached process and native ACP session per
1056
+ * Tangle session, `initialize` then `session/new` (or `session/load` for a
1057
+ * provider that resumes), serialized `session/prompt` turns, the cancel
1058
+ * sequence (`session/cancel`, grace, close), `session/update` translation,
1059
+ * idle reaping and eviction on process exit or turn failure.
1060
+ *
1061
+ * A provider supplies only its translation: how a turn resolves its config,
1062
+ * how the process starts, the prompt blocks, and its own failure signals.
1063
+ */
1064
+ declare abstract class AcpProviderAdapterBase<TConfig extends AcpBridgeConfig, TTurn extends AcpTurn<TConfig> = AcpTurn<TConfig>> extends CliProviderAdapterBase<TConfig> {
1065
+ /** True when the agent supports `session/load` for a recorded native session. */
1066
+ protected abstract readonly loadsNativeSessions: boolean;
1067
+ private readonly acpSessions;
1068
+ /** Resolve the turn's effective config. Throws before any session work. */
1069
+ protected abstract resolveTurn(input: AgentExecutionInput): TTurn;
1070
+ /**
1071
+ * How to start the agent process. Runs only when no live process matches.
1072
+ * May be async for a provider that must hand files it wrote to the agent user.
1073
+ */
1074
+ protected abstract processSpec(turn: TTurn, context: {
1075
+ sessionId: string;
1076
+ workspaceRoot: string;
1077
+ }): AcpProcessSpec | Promise<AcpProcessSpec>;
1078
+ /** The error a failed spawn surfaces; `missingBinary` when the command was not found. */
1079
+ protected abstract spawnFailureMessage(failure: {
1080
+ message: string;
1081
+ missingBinary: boolean;
1082
+ }, turn: TTurn): string;
1083
+ /** The `session/prompt` blocks for a turn. */
1084
+ protected abstract promptBlocks(input: AgentExecutionInput, prepared: {
1085
+ promptText: string;
1086
+ persistedParts: MessagePart[];
1087
+ attachments: PreparedAttachment[];
1088
+ }, turn: TTurn): AcpContentBlock[];
1089
+ /** Spawn the bridge. Tests override it to swap the child process. */
1090
+ protected spawnBridge(request: AcpBridgeSpawn): RpcBridge;
1091
+ /** Refuse an agent version beyond the provider's own floor. */
1092
+ protected checkAgentProtocolVersion(_advertised: number, _turn: TTurn): void;
1093
+ /**
1094
+ * Configure a native session the process just opened or loaded, before its
1095
+ * first prompt (e.g. `session/set_model`). A failure fails the acquire.
1096
+ */
1097
+ protected onSessionOpened(_bridge: RpcBridge, _acpSessionId: string, _turn: TTurn, _options: {
1098
+ timeoutMs: number;
1099
+ }): Promise<void>;
1100
+ /** Install reverse-call handlers on a new bridge, before `initialize`. */
1101
+ protected onBridgeSpawned(_bridge: RpcBridge, _sessionId: string, _turn: TTurn): void;
1102
+ /** Start per-turn state; the returned function ends it on every exit. */
1103
+ protected beginTurn(_sessionId: string, _input: AgentExecutionInput, _onEvent: ((event: StreamEvent) => void) | undefined): () => void;
1104
+ /** Inspect a failed tool's output; returned events precede its part update. */
1105
+ protected onToolFailed(_sessionId: string, _failureText: string | undefined): StreamEvent[];
1106
+ /**
1107
+ * A failure the provider recorded for this session during the turn,
1108
+ * cleared on read. It outranks the error the turn surfaced as.
1109
+ */
1110
+ protected takeTurnFailure(_sessionId: string): Error | undefined;
1111
+ /** Release provider state tied to a session's process. */
1112
+ protected onSessionEvicted(_sessionId: string): void;
1113
+ /** Extra fields for the turn-failure log line. */
1114
+ protected turnLogContext(_turn: TTurn): Record<string, unknown>;
1115
+ /**
1116
+ * One turn through the base turn pipeline: session open with transcript
1117
+ * replay and cached-turn replay, then input and result recording around the
1118
+ * bridge's `session/prompt`. The agent owns its profile, so the base's
1119
+ * profile materialization does not run.
1120
+ */
1121
+ execute(input: AgentExecutionInput, services: SdkHostServices, onEvent?: (event: StreamEvent) => void): Promise<AgentExecutionResult>;
1122
+ /** Report a failed turn, retire its process, and throw its error. */
1123
+ private failAcpTurn;
1124
+ private acquireAcpSession;
1125
+ private checkProtocolVersion;
1126
+ /**
1127
+ * Open the native ACP session. A recorded session is loaded when the agent
1128
+ * can; an agent that refuses the load starts a new native session, and the
1129
+ * Tangle transcript stays the record of the earlier turns.
1130
+ */
1131
+ private openNativeSession;
1132
+ /**
1133
+ * One `session/prompt` turn. Abort sends `session/cancel` before closing so
1134
+ * the agent can settle the turn; the bridge's own signal handling would
1135
+ * close first and lose the notify.
1136
+ */
1137
+ private promptAcpSession;
1138
+ private scheduleIdleReap;
1139
+ private cancelIdleReap;
1140
+ /** Close a session's agent process and drop it. Idempotent. */
1141
+ protected evictAcpSession(sessionId: string, reason: string): void;
1142
+ /** Evict every cached session whose process key matches. */
1143
+ protected evictAcpSessionsWhere(matches: (processKey: string) => boolean, reason: string): void;
1144
+ /** Translate one `session/update` notification into stream events. */
1145
+ private mapAcpUpdate;
1146
+ private mapToolStatus;
1147
+ private formatBridgeError;
1148
+ /**
1149
+ * The error a failed process start surfaces. An agent that exits before its
1150
+ * session opens reports why only on stderr, and an agent's JSON-RPC error
1151
+ * carries its cause in `data`; a bare "process-exit" or "Internal error"
1152
+ * hides both from the caller.
1153
+ */
1154
+ private sessionSetupError;
1155
+ healthCheck(): Promise<boolean>;
1156
+ shutdown(): Promise<void>;
1157
+ addMcp(_name: string, _config: McpConfig): Promise<void>;
1158
+ getMcpStatus(): Promise<McpStatusResponse>;
1159
+ protected buildExecArgs(): never;
1160
+ protected buildExecEnv(_config: TConfig): Record<string, string | undefined>;
1161
+ protected createEventParser(): never;
1162
+ protected buildMcpAddArgs(_name: string, _config: McpConfig | LocalMcpConfig): string[];
1163
+ }
1164
+ //#endregion
1165
+ //#region src/errors.d.ts
1166
+ /**
1167
+ * A session's persisted transcript exists but could not be read for replay
1168
+ * into the fresh provider session this turn starts. The turn fails instead
1169
+ * of serving an empty conversation under the same session id. The sidecar's
1170
+ * client-visible whitelist matches on `code`; the wire contract is the
1171
+ * duck-typed field, not class identity.
1172
+ */
1173
+ declare class SessionRehydrationError extends Error {
1174
+ readonly code = "session_rehydration_failed";
1175
+ constructor(message: string, cause: unknown);
1176
+ }
1177
+ /**
1178
+ * Marks a turn failure the adapter raised before it planned the launch:
1179
+ * session preparation or profile materialization refused, so no native
1180
+ * process received this turn and it left no native transcript to copy.
1181
+ * Only the adapter marks, on the error object it caught; error text never
1182
+ * does, so a provider message that reads the same is not marked.
1183
+ */
1184
+ declare function rejectNotLaunched<E>(error: E): never;
1185
+ /** Whether this error is one the adapter raised before launching anything. */
1186
+ declare function wasNeverLaunched(error: Error): boolean;
1187
+ //#endregion
1188
+ //#region src/event-parsers.d.ts
1189
+ /**
1190
+ * Parser for harnesses that print one JSON event per line (claude-code,
1191
+ * codex, amp, factory-droids). Values that fail `accept` are logged and
1192
+ * dropped; unparseable lines become a `PARSE_ERROR` warning. The first event
1193
+ * `isReady` accepts reports the CLI's own start time as `cli_initialize`,
1194
+ * measured from parser creation, which immediately precedes the spawn.
1195
+ */
1196
+ declare function jsonEventParser<TEvent>(logger: CliProviderLogger, onEvent: ((event: StreamEvent) => void) | undefined, spec: {
1197
+ /** Names the harness in the "Received non-<label> event" warning. */label: string;
1198
+ accept(raw: unknown): raw is TEvent;
1199
+ map(event: TEvent): StreamEvent[];
1200
+ isReady?(event: TEvent): boolean;
1201
+ }): StreamParserConfig<TEvent>;
1202
+ /** What a plaintext harness's line mapper records about the response. */
1203
+ interface PlaintextResponse {
1204
+ /** Appends one line of the assistant's reply. */
1205
+ text(line: string): void;
1206
+ /** Records an error line; a turn with errors and no reply fails with the last one. */
1207
+ error(message: string): void;
1208
+ }
1209
+ /**
1210
+ * Parser for harnesses that print their reply as plain stdout lines (hermes,
1211
+ * nanoclaw, forge). Lines classify into provider events; the reply is
1212
+ * emitted as one text part when stdout closes. A turn that printed errors
1213
+ * but no reply ends `failed` with the last error instead of an empty
1214
+ * `completed`.
1215
+ */
1216
+ declare function plaintextResponseParser<TEvent>(state: ExecutionState, onEvent: ((event: StreamEvent) => void) | undefined, spec: {
1217
+ classify(line: string): TEvent | null;
1218
+ map(event: TEvent, response: PlaintextResponse): StreamEvent[]; /** Failure detail when errors were seen but none carried a message. */
1219
+ emptyFailureDetail: string;
1220
+ }): StreamParserConfig<TEvent>;
1221
+ //#endregion
1222
+ //#region src/execution-request-headers.d.ts
1223
+ /** Router column that joins a model request to the turn trace that caused it. */
1224
+ declare const EXECUTION_TRACE_HEADER = "X-Tangle-Trace-ID";
1225
+ declare const MANAGED_QUOTE_VERSION_HEADER = "X-Tangle-Managed-Quote-Version";
1226
+ /**
1227
+ * Capture diagnostic identity without forwarding caller-supplied transport headers.
1228
+ * `traceId` is the turn's trace id; a value no header can carry is omitted,
1229
+ * because a trace is diagnostic and must never refuse the run.
1230
+ */
1231
+ declare function executionCorrelationHeaders(binding: InteractionExecutionBinding | undefined, traceId?: string, quoteVersion?: string): Readonly<Record<string, string>> | undefined;
1232
+ //#endregion
1233
+ //#region src/file-parts.d.ts
1234
+ /** Infers a MIME type from a filename's extension. Unknown/no extension → undefined. */
1235
+ declare function inferMediaType(filename: string): string | undefined;
1236
+ /**
1237
+ * Builds the canonical URL for a file part. A data URI passes through
1238
+ * verbatim; a path is returned unchanged if it already carries a recognized
1239
+ * scheme, else converted to a percent-encoded `file://` URL.
1240
+ *
1241
+ * Callers must pass an already-resolved absolute path — `trackFilePart`
1242
+ * resolves relative paths (or drops the observation when it can't) before
1243
+ * ever reaching here, so a relative path arriving at this layer means a
1244
+ * caller bypassed that resolution. We throw rather than mint a malformed
1245
+ * `file://` URL (e.g. `file://./chart.png`, whose authority is `.`).
1246
+ */
1247
+ declare function buildFileUrl(input: {
1248
+ path?: string;
1249
+ dataUri?: string;
1250
+ }): string;
1251
+ /** Deterministic, stable part id for a file announced within one message. */
1252
+ declare function deterministicFilePartId(messageId: string, key: string): string;
1253
+ /**
1254
+ * Stateless derivation of the canonical file-part fields for one observed
1255
+ * path: resolve-once (normalize, then anchor a relative path to
1256
+ * `workspaceRoot`), and from that single resolved path derive the dedupe
1257
+ * `key`, the deterministic `id`, the `filename`, the inferred `mediaType`,
1258
+ * and the percent-encoded `file://` `url` — so every consumer that surfaces
1259
+ * the same file agrees on all five.
1260
+ *
1261
+ * Returns `null` for a relative path with no `workspaceRoot` to anchor it:
1262
+ * detection is opportunistic and a fabricated location is worse than a
1263
+ * missing part (see `trackFilePart` for the full rationale).
1264
+ *
1265
+ * This is the ONE derivation chain. `trackFilePart` (exec path, with
1266
+ * ExecutionState memoization) and stateless mappers that own no
1267
+ * ExecutionState (codex's app-server item mapper) both call it — never
1268
+ * re-implement the chain, or the two paths drift.
1269
+ */
1270
+ declare function deriveFilePart(input: {
1271
+ path: string;
1272
+ messageId: string;
1273
+ workspaceRoot?: string;
1274
+ }): {
1275
+ id: string;
1276
+ key: string;
1277
+ filename: string;
1278
+ mediaType?: string;
1279
+ url: string;
1280
+ } | null;
1281
+ /**
1282
+ * Tracks a file an adapter observed being created/modified (e.g. from a
1283
+ * write-tool call) and returns the canonical `FilePart` fields to stream,
1284
+ * deduping by resolved-absolute-path or data-URI content so repeated writes
1285
+ * to the same file update one part instead of appending duplicates.
1286
+ *
1287
+ * The path is normalized and resolved to an absolute form ONCE, and that same
1288
+ * resolved value drives both the dedupe key and the `file://` url — so two
1289
+ * observations of the same file that differ only in spelling (`./chart.png`
1290
+ * vs `/workspace/chart.png`, or `/workspace/sub/../chart.png` vs
1291
+ * `/workspace/chart.png`) unify on one part with one stable url, satisfying
1292
+ * the stream invariant that a given part id keeps a stable url.
1293
+ *
1294
+ * A relative path can only be resolved against `state.workspaceRoot` (set by
1295
+ * the adapter from the CLI's cwd). Detection here is opportunistic — a
1296
+ * tool-call observation, not a guarantee of an absolute path — so when no
1297
+ * workspaceRoot is available to anchor a relative path, we drop the
1298
+ * observation (`null`) rather than fabricate an anchor (e.g. resolving
1299
+ * against "/"): a wrong url is worse than a missing part, and a caller that
1300
+ * genuinely lost the file would get a wrong, permanent url once it's on the
1301
+ * stream.
1302
+ *
1303
+ * Detection is opportunistic for other reasons too: a delete, or an
1304
+ * observation carrying neither a path nor a data URI, also yields no part
1305
+ * (`null`) rather than an error — callers are not required to have a file
1306
+ * signal on every tool result.
1307
+ */
1308
+ declare function trackFilePart(state: ExecutionState, args: {
1309
+ path?: string;
1310
+ dataUri?: string;
1311
+ filename?: string;
1312
+ mediaType?: string;
1313
+ changeKind?: "add" | "update" | "delete";
1314
+ }): {
1315
+ id: string;
1316
+ filename?: string;
1317
+ mediaType?: string;
1318
+ url: string;
1319
+ } | null;
1320
+ //#endregion
1321
+ //#region src/interaction-mcp-server.d.ts
1322
+ /**
1323
+ * Compatibility adapter for callers that used the old optional `onStop` field.
1324
+ * Agent Core owns the MCP server, retry-safe transport, and teardown lifecycle.
1325
+ */
1326
+ type InteractionMcpServerConfig = Omit<InteractionMcpServerConfig$1, "onStop"> & {
1327
+ onStop?: InteractionMcpServerConfig$1["onStop"];
1328
+ };
1329
+ declare class InteractionMcpServer extends InteractionMcpServer$1 {
1330
+ constructor(config: InteractionMcpServerConfig);
1331
+ }
1332
+ //#endregion
1333
+ //#region src/interaction-support.d.ts
1334
+ /**
1335
+ * Per-execution lifecycle wrapper for an MCP-capable harness. Permission and
1336
+ * question tools use the live {@link InteractionBroker}; plan tools commit
1337
+ * through {@link TerminalPlanSupport} and end the provider turn.
1338
+ *
1339
+ * Mirrors the claude-code permission-server pattern, but for the GENERIC
1340
+ * `request_permission` / `ask_user` / `request_plan` tools the agent calls
1341
+ * itself — there is no harness-specific reply contract, so any MCP-capable CLI
1342
+ * (factory-droids, …) composes this with ~10 lines: declare the capability
1343
+ * kinds, start/stop around the spawn, inject the server via the CLI's MCP
1344
+ * mechanism, and forward `respondToInteraction` here.
1345
+ *
1346
+ * Unlike claude-code's `--permission-prompt-tool`, these generic tools fire
1347
+ * only when the model chooses to call them. Permission is therefore advisory,
1348
+ * while plan-capable adapters separately prove the terminal turn boundary.
1349
+ */
1350
+ declare class McpInteractionSupport {
1351
+ /** MCP server name; tool names become `mcp__<name>__<tool>`. */
1352
+ private readonly serverName;
1353
+ /**
1354
+ * The {@link InteractionKind} values this harness wires (e.g.
1355
+ * `[InteractionKind.Question, InteractionKind.Plan]`). Passed as the literal
1356
+ * `InteractionKind.*` values so the coverage/live-e2e CI gates that grep
1357
+ * `adapter.ts` see the declaration.
1358
+ */
1359
+ private readonly kinds;
1360
+ /** The shared emit → block → respond → fail-closed round-trip. */
1361
+ readonly broker: InteractionBroker$1;
1362
+ private activeServer?;
1363
+ private terminalPlan?;
1364
+ constructor(/** MCP server name; tool names become `mcp__<name>__<tool>`. */
1365
+
1366
+ serverName: string,
1367
+ /**
1368
+ * The {@link InteractionKind} values this harness wires (e.g.
1369
+ * `[InteractionKind.Question, InteractionKind.Plan]`). Passed as the literal
1370
+ * `InteractionKind.*` values so the coverage/live-e2e CI gates that grep
1371
+ * `adapter.ts` see the declaration.
1372
+ */
1373
+
1374
+ kinds: readonly string[]);
1375
+ /** The interaction kinds to advertise from `getCapabilities().interactions`. */
1376
+ capabilityKinds(): string[];
1377
+ /** The active per-execution server (its `url`/`token`), once started. */
1378
+ get server(): InteractionMcpServer$1 | undefined;
1379
+ /**
1380
+ * Start a per-execution server bound to 127.0.0.1 with an ephemeral bearer
1381
+ * token, registering only the enabled tools. `emit` is the live event sink;
1382
+ * broker-backed tools block on an answer, while plans emit only after their
1383
+ * terminal confirmation. Returns the server for CLI injection.
1384
+ */
1385
+ start(sessionId: string, binding: InteractionExecutionBinding, emit?: (event: StreamEvent) => void, plan?: {
1386
+ planHost: SdkPlanHost;
1387
+ providerState: () => PlanProviderState;
1388
+ onCommitted?: (submitted: DurablePlan) => void | Promise<void>;
1389
+ }): Promise<InteractionMcpServer$1>;
1390
+ confirmSubmittedPlan(): Promise<DurablePlan>;
1391
+ withdrawSubmittedPlan(reason: string): Promise<void>;
1392
+ /** Close the request boundary before inspecting or withdrawing its plan. */
1393
+ drainSubmittedPlan(sessionId: string): Promise<void>;
1394
+ /**
1395
+ * Fail-closed every pending interaction for the session, then stop the server.
1396
+ * `failSession` runs FIRST so any request still blocked in the server resolves
1397
+ * (deny) before close, and the whole thing swallows errors — it runs in adapter
1398
+ * `finally` blocks and must never mask the turn's real error.
1399
+ */
1400
+ stop(sessionId: string): Promise<void>;
1401
+ /**
1402
+ * Route an inbound live `/interactions` response for permission or question.
1403
+ * Plans are durable records and never enter this response channel.
1404
+ */
1405
+ respond(response: InteractionResponse): boolean;
1406
+ }
1407
+ //#endregion
1408
+ //#region src/mcp-commands.d.ts
1409
+ /** A local MCP server's argv: the `command` array, or `command` then `args`. */
1410
+ declare function localMcpArgv(config: McpConfig): string[];
1411
+ /**
1412
+ * A local MCP server's environment, from `environment` (agent-backend-types)
1413
+ * or `env` (agent-interface): reading one drops the other family's variables.
1414
+ */
1415
+ declare function localMcpEnv(config: McpConfig): Record<string, string> | undefined;
1416
+ declare const isLocalMcpConfig: (c: McpConfig) => c is LocalMcpConfig;
1417
+ //#endregion
1418
+ //#region src/metering.d.ts
1419
+ type CliTokenUsage = NonNullable<ExecutionState["tokenUsage"]>;
1420
+ declare function readCliTokenUsage(raw: unknown): CliTokenUsage | undefined;
1421
+ declare function recordCliTokenUsage(state: ExecutionState, ...sources: unknown[]): boolean;
1422
+ /**
1423
+ * Adds one usage report to the running total instead of replacing it.
1424
+ *
1425
+ * For a CLI that reports usage PER TURN (pi) rather than once per run,
1426
+ * `recordCliTokenUsage` would leave the execution billed as its final turn
1427
+ * alone. Use this wherever a single execution can produce more than one usage
1428
+ * report; use `recordCliTokenUsage` when the CLI emits one cumulative total.
1429
+ *
1430
+ * Returns true when a usage report was found in `sources` and folded in.
1431
+ */
1432
+ declare function accumulateCliTokenUsage(state: ExecutionState, ...sources: unknown[]): boolean;
1433
+ declare function parseCliUsageLine(line: string): Record<string, unknown> | undefined;
1434
+ //#endregion
1435
+ //#region src/reasoning-effort.d.ts
1436
+ /** The argv carrying `nativeReasoningControl` for a profile effort, or none. */
1437
+ declare function nativeEffortArgs(harness: HarnessType, effort: ReasoningEffort | undefined): string[];
1438
+ /**
1439
+ * Kimi stays local until #14839: the sandbox ships kimi-cli 1.49.0 as
1440
+ * `kimi-code` (binary `--thinking`/`--no-thinking`) while other paths run
1441
+ * kimi-code 2.x. A model whose name has "thinking" or "reason" always thinks
1442
+ * (kimi-cli `derive_model_capabilities`), so `off` throws there.
1443
+ */
1444
+ declare function kimiThinkingArgs(level: ReasoningEffort | undefined, modelId?: string | null): string[];
1445
+ //#endregion
1446
+ //#region src/reasoning-parts.d.ts
1447
+ /**
1448
+ * Assigns a stable part id and an append-only delta to a reasoning block
1449
+ * emission, absorbing provider replay/growth patterns:
1450
+ *
1451
+ * - text exactly matches an already-tracked block → `null` (duplicate
1452
+ * delivery, e.g. a final assistant message replaying streamed content —
1453
+ * emit nothing). Byte-identical distinct blocks therefore dedupe to one
1454
+ * part; safer than duplicate-part spam.
1455
+ * - text extends the most recent block → same part id, delta = the suffix
1456
+ * (cumulative re-emission of a growing block).
1457
+ * - otherwise → a new block: fresh part id, delta = the full text, so
1458
+ * consumers can be pure appenders (prev text for a fresh id is empty).
1459
+ */
1460
+ declare function trackReasoningBlock(state: ExecutionState, blockText: string): {
1461
+ partId: string;
1462
+ text: string;
1463
+ delta: string;
1464
+ isNewBlock: boolean;
1465
+ } | null;
1466
+ //#endregion
1467
+ //#region src/repeated-tool-failure.d.ts
1468
+ /**
1469
+ * Guard against a turn that keeps sending a tool call the tool keeps
1470
+ * rejecting.
1471
+ *
1472
+ * A CLI hands a rejected call back to the model and asks it to try again. It
1473
+ * puts no bound on how often it does that. A model that cannot form a valid
1474
+ * input therefore bills one round trip per attempt until an unrelated limit
1475
+ * runs out, and the user is told about that limit rather than about the call.
1476
+ * Staging measured 76 such attempts in 24.5 minutes, ending on a spent key
1477
+ * budget.
1478
+ *
1479
+ * The bound has to sit here, not in the CLI. OpenCode drives the turn with
1480
+ * `while (true)` in `session/prompt.ts`. Its per-agent `steps` bound defaults
1481
+ * to `Infinity`, and reaching that bound only appends a message that asks the
1482
+ * model to stop. Every tool stays enabled.
1483
+ *
1484
+ * The guard counts identical rejections in a row and nothing else. Any tool
1485
+ * call that produces a result clears the count. A retry after a transient
1486
+ * error is untouched, because it either succeeds or its error text moves. Only
1487
+ * a model that cannot change its input reaches the limit.
1488
+ */
1489
+ /** What a tripped guard reports to the caller. */
1490
+ interface RepeatedToolFailure {
1491
+ /** The tool the model meant to call. */
1492
+ tool: string;
1493
+ /** Why the call was rejected, in the tool's own words. */
1494
+ detail: string;
1495
+ /** How many times in a row this exact rejection came back. */
1496
+ count: number;
1497
+ }
1498
+ interface RepeatedToolFailureGuardOptions {
1499
+ /** Identical failures in a row that trip the guard. At least 1. */
1500
+ limit: number;
1501
+ /**
1502
+ * Tool names a provider substitutes for a model call it could not parse
1503
+ * into any real tool.
1504
+ *
1505
+ * These do not present as failures. OpenCode rewrites an unparseable call to
1506
+ * a tool named `invalid` that carries the parse error as its OUTPUT and
1507
+ * completes. A guard that reads only `status` scores a run of them as
1508
+ * progress and clears its count on every one.
1509
+ */
1510
+ repairToolNames?: ReadonlySet<string>;
1511
+ }
1512
+ interface RepeatedToolFailureGuard {
1513
+ /**
1514
+ * Feed one tool part. Returns the trip on the call that reaches the limit,
1515
+ * and `undefined` every other time. A tripped guard stays tripped and
1516
+ * reports once, so a caller can kill the turn without racing the events
1517
+ * still in flight behind it.
1518
+ */
1519
+ observe(part: Pick<ToolPart, "id" | "tool" | "state">): RepeatedToolFailure | undefined;
1520
+ }
1521
+ declare function createRepeatedToolFailureGuard(options: RepeatedToolFailureGuardOptions): RepeatedToolFailureGuard;
1522
+ //#endregion
1523
+ //#region src/stream-parts.d.ts
1524
+ /**
1525
+ * The text, reasoning and tool part emissions every stream-json harness
1526
+ * shares. A provider's event mapper decodes its own wire shape, then calls
1527
+ * these so part ids, buffers, tool timing and processing phases stay one
1528
+ * implementation across claude-code, codex, kimi, amp and factory-droids.
1529
+ */
1530
+ /**
1531
+ * Records the CLI's native session id on the turn and announces it: the
1532
+ * generic `session.updated` plus the provider-attributed observation the
1533
+ * turn observer keys evidence on.
1534
+ */
1535
+ declare function sessionObservedEvents(state: ExecutionState, provider: string, sessionId: string): StreamEvent[];
1536
+ /** Correlation fields every emitted part carries. */
1537
+ declare function streamPartBase(state: ExecutionState, partId?: string): {
1538
+ id: string;
1539
+ sessionID: string;
1540
+ messageID: string;
1541
+ };
1542
+ /**
1543
+ * Appends a text delta to the turn's single text part. The first text of a
1544
+ * turn also signals the `generating` phase.
1545
+ */
1546
+ declare function textDeltaEvents(state: ExecutionState, delta: string): StreamEvent[];
1547
+ /** The whole reply as one text part, for harnesses that do not stream. */
1548
+ declare function finalTextEvent(state: ExecutionState, text: string): StreamEvent;
1549
+ /**
1550
+ * Applies a cumulative text frame (the whole assistant text so far). Only the
1551
+ * suffix past the buffer is emitted; a frame that does not extend the buffer
1552
+ * replaces it and is emitted whole.
1553
+ */
1554
+ declare function textSnapshotEvents(state: ExecutionState, text: string): StreamEvent[];
1555
+ /**
1556
+ * Records a thinking block under a stable part id (see trackReasoningBlock).
1557
+ * With `signalPhase`, the turn's first block also signals `thinking`.
1558
+ */
1559
+ declare function reasoningEvents(state: ExecutionState, thinking: string, options: {
1560
+ signalPhase: boolean;
1561
+ }): StreamEvent[];
1562
+ /** Registers a running tool call and emits its running part. */
1563
+ declare function toolStartEvents(state: ExecutionState, call: {
1564
+ id: string;
1565
+ name: string;
1566
+ input: unknown;
1567
+ }): StreamEvent[];
1568
+ /**
1569
+ * Completes a tracked tool call. A successful result emits `afterSuccess`
1570
+ * (file parts the provider detected) and then the `tool-result` phase. A
1571
+ * result for an untracked call is a warning.
1572
+ */
1573
+ declare function toolResultEvents(state: ExecutionState, result: {
1574
+ id: string;
1575
+ content: unknown;
1576
+ isError: boolean;
1577
+ metadata?: Record<string, unknown>;
1578
+ afterSuccess?: (toolCall: ToolCallState) => StreamEvent[];
1579
+ }): StreamEvent[];
1580
+ //#endregion
1581
+ //#region src/terminal-plan-support.d.ts
1582
+ type TerminalPlanSupportOptions = {
1583
+ planHost: SdkPlanHost;
1584
+ providerState: () => PlanProviderState;
1585
+ emit?: (event: StreamEvent) => void;
1586
+ onCommitted?: (plan: DurablePlan) => void | Promise<void>;
1587
+ };
1588
+ /** One-shot durable plan submission for a single provider turn. */
1589
+ declare class TerminalPlanSupport {
1590
+ private readonly options;
1591
+ private committed?;
1592
+ private submittedBody?;
1593
+ private inFlight?;
1594
+ private confirmInFlight?;
1595
+ private confirmed;
1596
+ constructor(options: TerminalPlanSupportOptions);
1597
+ get plan(): DurablePlan | undefined;
1598
+ /** Wait for a submission already accepted by this turn before failure cleanup. */
1599
+ settleSubmission(): Promise<void>;
1600
+ submit(body: string, sourceToolCallId: string): Promise<DurablePlan>;
1601
+ confirm(): Promise<DurablePlan>;
1602
+ withdraw(reason: string): Promise<void>;
1603
+ }
1604
+ //#endregion
1605
+ //#region src/writable-home.d.ts
1606
+ /** HOME and the XDG base directories a CLI resolves under it. */
1607
+ declare function homeXdgEnv(home: string): {
1608
+ HOME: string;
1609
+ XDG_CONFIG_HOME: string;
1610
+ XDG_CACHE_HOME: string;
1611
+ XDG_DATA_HOME: string;
1612
+ XDG_STATE_HOME: string;
1613
+ };
1614
+ //#endregion
1615
+ export { ACP_MIN_PROTOCOL_VERSION, ACP_PROTOCOL_VERSION, type AcpBridgeConfig, type AcpBridgeSpawn, type AcpContentBlock, type AcpInitializeParams, type AcpInitializeResult, type AcpNewSessionResult, type AcpProcessSpec, type AcpPromptResult, AcpProviderAdapterBase, type AcpSessionUpdateParams, type AcpTurn, type AskUserBridge, type CliExecArgs, type CliExecutionInput, CliProviderAdapterBase, type CliProviderConfig, type CliProviderLogger, type CliProviderOptions, type CliTurnProcess, type CliTurnSpawn, DEFAULT_INTERACTION_MCP_SERVER_NAME, EXECUTION_TRACE_HEADER, type EphemeralContextInput, type ExecutionState, type HarnessId, InteractionBroker, InteractionHttpBridge, InteractionMcpServer, type InteractionMcpServerConfig, type InteractionToggleConfig, type InteractionToggleKind, InvalidAttachmentError, MANAGED_QUOTE_VERSION_HEADER, MAX_INLINE_IMAGE_BYTES, MAX_TOTAL_INLINE_IMAGE_BYTES, McpInteractionSupport, PERMISSION_DECISION_TIMEOUT_MS, PROMPT_SECTION_SEPARATOR, type PerTurnInteractionInput, type PermissionPromptBridge, type PlaintextResponse, type PreparedAttachment, type PreparedCliLaunch, type RepeatedToolFailure, type RepeatedToolFailureGuard, type RepeatedToolFailureGuardOptions, type RequestPermissionBridge, type RequestPlanBridge, SessionRehydrationError, TerminalPlanSupport, type TerminalPlanSupportOptions, type ToolCallState, type WorkspacePlanApplication, accumulateCliTokenUsage, acpContentText, brokerInteractionTools, buildFileUrl, createExecutionState, createRepeatedToolFailureGuard, deriveFilePart, deterministicFilePartId, enabledInteractionKinds, executionCorrelationHeaders, finalTextEvent, homeXdgEnv, inferMediaType, interactionMcpToolName, interactionToggleEnabled, isLocalMcpConfig, jsonEventParser, kimiThinkingArgs, localMcpArgv, localMcpEnv, mapAcpStopReason, nativeEffortArgs, parseCliUsageLine, partitionImageAttachments, plaintextResponseParser, preparePromptInputParts, prependPromptSection, readCliTokenUsage, readEphemeralContext, reasoningEvents, recordCliTokenUsage, rejectNotLaunched, runtimeSecretsOverlay, sessionObservedEvents, spawnAcpBridge, streamPartBase, textDeltaEvents, textSnapshotEvents, toolResultEvents, toolStartEvents, trackFilePart, trackReasoningBlock, turnInteractionEnabled, wasNeverLaunched, withEphemeralContext, withTurnInteractions };
1616
+ //# sourceMappingURL=index.d.mts.map