@wrongstack/acp 0.273.1 → 0.275.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,520 @@
1
+ import { EventEmitter } from 'node:events';
2
+
3
+ /**
4
+ * ACP message types — transport-agnostic JSON-RPC 2.0 envelope.
5
+ * Reuses MCP types where possible; custom types for agentic UX (diffs, plans).
6
+ */
7
+ interface ACPMessage {
8
+ method: string;
9
+ id?: string | number | undefined;
10
+ params?: unknown | undefined;
11
+ result?: unknown | undefined;
12
+ error?: ACPError | undefined;
13
+ }
14
+ interface ACPError {
15
+ code: number;
16
+ message: string;
17
+ data?: unknown | undefined;
18
+ }
19
+ type ACPRequest = RequiredPick<ACPMessage, 'id' | 'params' | 'method'>;
20
+ type ACPResponse = RequiredPick<ACPMessage, 'id' | 'result' | 'method'>;
21
+ type ACPNotification = Omit<ACPMessage, 'id'> & {
22
+ method: string;
23
+ };
24
+ interface ACPInitializeParams {
25
+ capabilities?: string[] | undefined;
26
+ protocolVersion?: string | undefined;
27
+ sessionId?: string | undefined;
28
+ authToken?: string | undefined;
29
+ sessionPath?: string | undefined;
30
+ workspaceRoots?: string[] | undefined;
31
+ mcpServers?: unknown[] | undefined;
32
+ [key: string]: unknown;
33
+ }
34
+ interface ACPCapabilities {
35
+ capabilities: string[];
36
+ agentName: string;
37
+ agentVersion: string;
38
+ tools?: ACPToolList | undefined;
39
+ protocolVersion: string;
40
+ }
41
+ interface ACPToolList {
42
+ tools: ACPToolDefinition[];
43
+ }
44
+ interface ACPToolDefinition {
45
+ name: string;
46
+ description?: string | undefined;
47
+ inputSchema: ACPInputSchema;
48
+ annotations?: {
49
+ title?: string | undefined;
50
+ description?: string | undefined;
51
+ priority?: 'high' | 'medium' | 'low' | undefined;
52
+ alwaysAccept?: boolean | undefined;
53
+ };
54
+ }
55
+ type ACPInputSchema = {
56
+ type?: string | undefined;
57
+ properties?: Record<string, ACPInputSchema>;
58
+ required?: string[] | undefined;
59
+ items?: ACPInputSchema | undefined;
60
+ enum?: unknown[] | undefined;
61
+ description?: string | undefined;
62
+ default?: unknown | undefined;
63
+ minimum?: number | undefined;
64
+ maximum?: number | undefined;
65
+ [key: string]: unknown;
66
+ };
67
+ type ContentBlock$1 = ACPTextContent | ACPResourceContent | ACPImageContent | ACPProgressContent;
68
+ interface ACPTextContent {
69
+ type: 'text';
70
+ text: string;
71
+ }
72
+ interface ACPResourceContent {
73
+ type: 'resource';
74
+ resource: {
75
+ type: string;
76
+ uri: string;
77
+ data?: string | undefined;
78
+ mimeType?: string | undefined;
79
+ };
80
+ }
81
+ interface ACPImageContent {
82
+ type: 'image';
83
+ data: string;
84
+ mimeType?: string | undefined;
85
+ }
86
+ interface ACPProgressContent {
87
+ type: 'progress';
88
+ id: string;
89
+ label?: string | undefined;
90
+ message?: string | undefined;
91
+ messages?: string[] | undefined;
92
+ }
93
+ interface ACPToolCallRequest {
94
+ method: 'tools/call';
95
+ id: string | number;
96
+ params: {
97
+ name: string;
98
+ arguments: Record<string, unknown>;
99
+ };
100
+ }
101
+ interface ACPToolResult {
102
+ content: ContentBlock$1[];
103
+ isError?: boolean | undefined;
104
+ }
105
+ type ACPToolCallResponse = {
106
+ method: 'tools/call';
107
+ id: string | number;
108
+ result: ACPToolResult;
109
+ };
110
+ interface ACPSessionInfo {
111
+ sessionId: string;
112
+ path: string;
113
+ title?: string | undefined;
114
+ modelId?: string | undefined;
115
+ createdAt: string;
116
+ lastActiveAt: string;
117
+ }
118
+ interface ACPPlanStep {
119
+ id: string;
120
+ description: string;
121
+ status?: 'pending' | 'running' | 'completed' | 'skipped' | undefined;
122
+ }
123
+ interface ACPPlanContent {
124
+ type: 'plan';
125
+ plan: {
126
+ steps: ACPPlanStep[];
127
+ };
128
+ }
129
+ type ACPSessionMode = 'agent' | 'chat' | 'edit' | 'preview';
130
+ interface ACPCancelParams {
131
+ reason?: string | undefined;
132
+ }
133
+ type RequiredPick<T, K extends keyof T> = Pick<T, K> & Partial<Omit<T, K>>;
134
+
135
+ interface AgentServerTransport {
136
+ send(msg: ACPMessage): Promise<void>;
137
+ sendRaw(chunk: string): void;
138
+ read(): Promise<ACPMessage | null>;
139
+ close(): void;
140
+ onMessage(handler: (msg: ACPMessage) => void): () => void;
141
+ }
142
+ /**
143
+ * Minimal client-side transport contract `ACPSession` drives. `ClientTransport`
144
+ * (stdio subprocess) and `WebSocketClientTransport` (remote) both implement it,
145
+ * so the session is agnostic to how bytes reach the agent.
146
+ */
147
+ interface ACPClientTransport {
148
+ start(): Promise<void>;
149
+ send(msg: ACPMessage): Promise<void>;
150
+ onMessage(handler: (msg: ACPMessage) => void): () => void;
151
+ stop(): void;
152
+ }
153
+ declare class StdioTransport implements AgentServerTransport {
154
+ private readonly stdin;
155
+ private readonly stdout;
156
+ private readonly stderr;
157
+ private buffer;
158
+ private readonly handlers;
159
+ private closed;
160
+ private resolveRead;
161
+ private messageQueue;
162
+ constructor();
163
+ sendStartupMarker(): void;
164
+ send(msg: ACPMessage): Promise<void>;
165
+ sendRaw(chunk: string): void;
166
+ read(): Promise<ACPMessage | null>;
167
+ onMessage(handler: (msg: ACPMessage) => void): () => void;
168
+ close(): void;
169
+ private onData;
170
+ private dispatch;
171
+ private handleClose;
172
+ private failAll;
173
+ }
174
+
175
+ interface ClientTransportOptions {
176
+ command: string;
177
+ args?: string[] | undefined;
178
+ env?: Record<string, string>;
179
+ cwd?: string | undefined;
180
+ handshakeTimeoutMs?: number | undefined;
181
+ /**
182
+ * Set to true when the child is an external ACP agent (Claude Code,
183
+ * Gemini CLI, Codex CLI, …) that does NOT emit a `[wstack-acp]\n`
184
+ * marker on startup. The v1 client (`ACPSession`) sets this; the
185
+ * server-side transport (the default) keeps the marker check.
186
+ */
187
+ skipHandshakeMarker?: boolean | undefined;
188
+ }
189
+ interface ACPChildProcess extends EventEmitter {
190
+ stdout: NodeJS.ReadableStream;
191
+ stdin: NodeJS.WritableStream;
192
+ stderr: NodeJS.ReadableStream;
193
+ pid: number | undefined;
194
+ kill(): void;
195
+ }
196
+ declare class ClientTransport implements ACPClientTransport {
197
+ private child;
198
+ private buffer;
199
+ private readonly handlers;
200
+ private closed;
201
+ private resolveRead;
202
+ private messageQueue;
203
+ private readonly opts;
204
+ constructor(options: ClientTransportOptions);
205
+ start(): Promise<void>;
206
+ send(msg: ACPMessage): Promise<void>;
207
+ read(): Promise<ACPMessage | null>;
208
+ onMessage(handler: (msg: ACPMessage) => void): () => void;
209
+ stop(): void;
210
+ private onChildData;
211
+ private onChildError;
212
+ private onChildClose;
213
+ private dispatch;
214
+ }
215
+
216
+ /** Per the spec: opaque, unique id. We type as branded string. */
217
+ type SessionId = string & {
218
+ readonly __acpSessionId: unique symbol;
219
+ };
220
+ type ToolCallId = string & {
221
+ readonly __acpToolCallId: unique symbol;
222
+ };
223
+ type MessageId = string & {
224
+ readonly __acpMessageId: unique symbol;
225
+ };
226
+ type TerminalId = string & {
227
+ readonly __acpTerminalId: unique symbol;
228
+ };
229
+ interface PromptCapabilities {
230
+ image?: boolean | undefined;
231
+ audio?: boolean | undefined;
232
+ embeddedContext?: boolean | undefined;
233
+ }
234
+ interface McpCapabilities {
235
+ http?: boolean | undefined;
236
+ sse?: boolean | undefined;
237
+ }
238
+ interface SessionCapabilities {
239
+ close?: Record<string, unknown> | undefined;
240
+ list?: Record<string, unknown> | undefined;
241
+ delete?: Record<string, unknown> | undefined;
242
+ resume?: Record<string, unknown> | undefined;
243
+ additionalDirectories?: Record<string, unknown> | undefined;
244
+ }
245
+ interface AuthCapabilities {
246
+ logout?: Record<string, unknown> | undefined;
247
+ }
248
+ interface AgentCapabilities {
249
+ loadSession?: boolean | undefined;
250
+ promptCapabilities?: PromptCapabilities | undefined;
251
+ mcpCapabilities?: McpCapabilities | undefined;
252
+ sessionCapabilities?: SessionCapabilities | undefined;
253
+ auth?: AuthCapabilities | undefined;
254
+ }
255
+ interface AuthMethod {
256
+ id: string;
257
+ name: string;
258
+ description?: string | undefined;
259
+ type?: 'agent' | 'oauth' | 'http' | undefined;
260
+ }
261
+ interface StdioMcpServer {
262
+ name: string;
263
+ command: string;
264
+ args?: string[] | undefined;
265
+ env?: {
266
+ name: string;
267
+ value: string;
268
+ }[] | undefined;
269
+ }
270
+ interface HttpMcpServer {
271
+ type: 'http';
272
+ name: string;
273
+ url: string;
274
+ headers?: {
275
+ name: string;
276
+ value: string;
277
+ }[] | undefined;
278
+ }
279
+ interface SseMcpServer {
280
+ type: 'sse';
281
+ name: string;
282
+ url: string;
283
+ headers?: {
284
+ name: string;
285
+ value: string;
286
+ }[] | undefined;
287
+ }
288
+ type McpServer = StdioMcpServer | HttpMcpServer | SseMcpServer;
289
+ /**
290
+ * Annotations attached to a content block. Optional, agent-supplied hint
291
+ * about audience/priority. Spec leaves shape open; we mirror the fields
292
+ * the spec shows in its examples.
293
+ */
294
+ interface ContentAnnotations {
295
+ audience?: ('user' | 'assistant')[] | undefined;
296
+ priority?: number | undefined;
297
+ [key: string]: unknown;
298
+ }
299
+ interface TextContent {
300
+ type: 'text';
301
+ text: string;
302
+ annotations?: ContentAnnotations | undefined;
303
+ }
304
+ interface ImageContent {
305
+ type: 'image';
306
+ mimeType: string;
307
+ /** Base64-encoded image data. */
308
+ data: string;
309
+ uri?: string | undefined;
310
+ annotations?: ContentAnnotations | undefined;
311
+ }
312
+ interface AudioContent {
313
+ type: 'audio';
314
+ mimeType: string;
315
+ /** Base64-encoded audio data. */
316
+ data: string;
317
+ annotations?: ContentAnnotations | undefined;
318
+ }
319
+ interface TextResourceContents {
320
+ uri: string;
321
+ mimeType?: string | undefined;
322
+ text: string;
323
+ }
324
+ interface BlobResourceContents {
325
+ uri: string;
326
+ mimeType?: string | undefined;
327
+ /** Base64-encoded binary. */
328
+ blob: string;
329
+ }
330
+ type EmbeddedResourceContents = TextResourceContents | BlobResourceContents;
331
+ interface EmbeddedResourceContent {
332
+ type: 'resource';
333
+ resource: EmbeddedResourceContents;
334
+ annotations?: ContentAnnotations | undefined;
335
+ }
336
+ interface ResourceLinkContent {
337
+ type: 'resource_link';
338
+ uri: string;
339
+ name: string;
340
+ mimeType?: string | undefined;
341
+ title?: string | undefined;
342
+ description?: string | undefined;
343
+ size?: number | undefined;
344
+ annotations?: ContentAnnotations | undefined;
345
+ }
346
+ type ContentBlock = TextContent | ImageContent | AudioContent | EmbeddedResourceContent | ResourceLinkContent;
347
+ type ToolKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'think' | 'fetch' | 'switch_mode' | 'other';
348
+ type ToolCallStatus = 'pending' | 'in_progress' | 'completed' | 'failed';
349
+ /** A single concrete content payload attached to a tool call. */
350
+ type ToolCallContent = {
351
+ type: 'content';
352
+ content: ContentBlock;
353
+ } | {
354
+ type: 'diff';
355
+ path: string;
356
+ oldText: string | null;
357
+ newText: string;
358
+ } | {
359
+ type: 'terminal';
360
+ terminalId: TerminalId;
361
+ };
362
+ interface ToolCallLocation {
363
+ path: string;
364
+ /** 1-based per the spec's argument requirements. */
365
+ line?: number | undefined;
366
+ }
367
+ type PlanEntryPriority = 'high' | 'medium' | 'low';
368
+ type PlanEntryStatus = 'pending' | 'in_progress' | 'completed';
369
+ interface PlanEntry {
370
+ /** Required by the spec for the array shape, but per-entry id is optional. */
371
+ content: string;
372
+ priority: PlanEntryPriority;
373
+ status: PlanEntryStatus;
374
+ }
375
+ interface AvailableCommandInput {
376
+ hint: string;
377
+ }
378
+ interface AvailableCommand {
379
+ name: string;
380
+ description: string;
381
+ input?: AvailableCommandInput | undefined;
382
+ }
383
+ type SessionModeId = string & {
384
+ readonly __acpModeId: unique symbol;
385
+ };
386
+ /** Reserved spec categories. Underscore-prefixed names are free for custom use. */
387
+ type ConfigOptionCategory = 'mode' | 'model' | 'thought_level' | `_${string}`;
388
+ type ConfigOptionType = 'select' | string;
389
+ interface ConfigOptionValue {
390
+ value: string;
391
+ name: string;
392
+ description?: string | undefined;
393
+ }
394
+ interface ConfigOption {
395
+ id: string;
396
+ name: string;
397
+ description?: string | undefined;
398
+ category?: ConfigOptionCategory | undefined;
399
+ type: ConfigOptionType;
400
+ currentValue: string;
401
+ options: ConfigOptionValue[];
402
+ }
403
+ interface SessionInfo {
404
+ sessionId: SessionId;
405
+ cwd: string;
406
+ title?: string | undefined;
407
+ updatedAt?: string | undefined;
408
+ /** Agent-supplied extension metadata; opaque to clients. */
409
+ _meta?: Record<string, unknown> | undefined;
410
+ }
411
+ interface UsageCost {
412
+ amount: number;
413
+ /** ISO 4217 currency code, e.g. "USD". */
414
+ currency: string;
415
+ }
416
+ type PermissionOptionKind = 'allow_once' | 'allow_always' | 'reject_once' | 'reject_always';
417
+ interface PermissionOption {
418
+ optionId: string;
419
+ name: string;
420
+ kind: PermissionOptionKind;
421
+ }
422
+ type RequestPermissionOutcome = {
423
+ outcome: 'cancelled';
424
+ } | {
425
+ outcome: 'selected';
426
+ optionId: string;
427
+ };
428
+ type StopReason = 'end_turn' | 'max_tokens' | 'max_turn_requests' | 'refusal' | 'cancelled' | string;
429
+ /** Stable v1 variants. The spec currently defines exactly 11. */
430
+ type SessionUpdate = UserMessageChunkUpdate | AgentMessageChunkUpdate | ThoughtChunkUpdate | ToolCallUpdateUpdate | ToolCallUpdateNotification | PlanUpdate | AvailableCommandsUpdate | CurrentModeUpdate | ConfigOptionUpdate | SessionInfoUpdate | UsageUpdateUpdate;
431
+ interface UserMessageChunkUpdate {
432
+ sessionUpdate: 'user_message_chunk';
433
+ messageId?: MessageId | undefined;
434
+ content: ContentBlock;
435
+ }
436
+ interface AgentMessageChunkUpdate {
437
+ sessionUpdate: 'agent_message_chunk';
438
+ messageId?: MessageId | undefined;
439
+ content: ContentBlock;
440
+ }
441
+ interface ThoughtChunkUpdate {
442
+ sessionUpdate: 'thought_chunk';
443
+ messageId?: MessageId | undefined;
444
+ content: ContentBlock;
445
+ }
446
+ /** First notification for a new tool call. */
447
+ interface ToolCallUpdateUpdate {
448
+ sessionUpdate: 'tool_call';
449
+ toolCallId: ToolCallId;
450
+ title: string;
451
+ kind?: ToolKind | undefined;
452
+ status?: ToolCallStatus | undefined;
453
+ content?: ToolCallContent[] | undefined;
454
+ locations?: ToolCallLocation[] | undefined;
455
+ rawInput?: Record<string, unknown> | undefined;
456
+ }
457
+ /** Subsequent updates to a previously-emitted tool call. */
458
+ interface ToolCallUpdateNotification {
459
+ sessionUpdate: 'tool_call_update';
460
+ toolCallId: ToolCallId;
461
+ status?: ToolCallStatus | undefined;
462
+ content?: ToolCallContent[] | undefined;
463
+ title?: string | undefined;
464
+ kind?: ToolKind | undefined;
465
+ locations?: ToolCallLocation[] | undefined;
466
+ rawInput?: Record<string, unknown> | undefined;
467
+ rawOutput?: Record<string, unknown> | undefined;
468
+ }
469
+ interface PlanUpdate {
470
+ sessionUpdate: 'plan';
471
+ entries: PlanEntry[];
472
+ }
473
+ interface AvailableCommandsUpdate {
474
+ sessionUpdate: 'available_commands_update';
475
+ availableCommands: AvailableCommand[];
476
+ }
477
+ interface CurrentModeUpdate {
478
+ sessionUpdate: 'current_mode_update';
479
+ modeId: SessionModeId;
480
+ }
481
+ interface ConfigOptionUpdate {
482
+ sessionUpdate: 'config_option_update';
483
+ configOptions: ConfigOption[];
484
+ }
485
+ interface SessionInfoUpdate {
486
+ sessionUpdate: 'session_info_update';
487
+ title?: string | null | undefined;
488
+ updatedAt?: string | null | undefined;
489
+ _meta?: Record<string, unknown> | undefined;
490
+ }
491
+ interface UsageUpdateUpdate {
492
+ sessionUpdate: 'usage_update';
493
+ used: number;
494
+ size: number;
495
+ cost?: UsageCost | undefined;
496
+ }
497
+ /**
498
+ * Escape hatch for v2-RFD `sessionUpdate` kinds that have been published
499
+ * but are not yet stabilised in the v1 spec. Examples seen in the wild:
500
+ * `next_edit_suggestions`, `elicitation`, `proxy_extension`. We surface
501
+ * the raw payload so forward-compat code can switch on
502
+ * `kind === 'next_edit_suggestions'` etc. without losing the data.
503
+ */
504
+ interface UnstableSessionUpdate {
505
+ sessionUpdate: `_unstable_${string}`;
506
+ [key: string]: unknown;
507
+ }
508
+ /**
509
+ * Last-resort variant: the agent sent a discriminator string we don't
510
+ * recognise at all. The full payload is preserved as a record so consumers
511
+ * can still log/inspect it. Prefer matching the known variants first.
512
+ */
513
+ interface UnknownSessionUpdate {
514
+ sessionUpdate: string;
515
+ [key: string]: unknown;
516
+ }
517
+ /** The full union, including escape hatches. */
518
+ type AnySessionUpdate = SessionUpdate | UnstableSessionUpdate | UnknownSessionUpdate;
519
+
520
+ export { type ACPClientTransport as A, type ACPResponse as B, type ContentBlock as C, type ACPSessionInfo as D, type ACPSessionMode as E, type ACPTextContent as F, type ACPToolCallRequest as G, type ACPToolCallResponse as H, type ACPToolDefinition as I, ClientTransport as J, type ClientTransportOptions as K, type ContentBlock$1 as L, type McpServer as M, type PermissionOption as P, type RequestPermissionOutcome as R, StdioTransport as S, type ToolKind as T, type UsageCost as U, type AgentServerTransport as a, type ACPMessage as b, type ACPToolList as c, type ACPToolResult as d, type StopReason as e, type PlanEntry as f, type ToolCallUpdateNotification as g, type ToolCallStatus as h, type AnySessionUpdate as i, type AgentCapabilities as j, type AuthMethod as k, type SessionId as l, type SessionInfo as m, type ACPCancelParams as n, type ACPCapabilities as o, type ACPChildProcess as p, type ACPError as q, type ACPImageContent as r, type ACPInitializeParams as s, type ACPInputSchema as t, type ACPNotification as u, type ACPPlanContent as v, type ACPPlanStep as w, type ACPProgressContent as x, type ACPRequest as y, type ACPResourceContent as z };
package/dist/agent.d.ts CHANGED
@@ -1,72 +1,45 @@
1
- export { A as AgentServerTransport, S as StdioTransport } from './stdio-transport-CsFr8JzC.js';
2
- export { A as ACPToolsRegistry } from './tools-registry-BCf8evEG.js';
3
- import { R as RunTurn } from './wrongstack-acp-agent-Dv-A0bEm.js';
4
- export { A as ACPProtocolHandler, W as WrongStackACPServer, a as WrongStackACPServerOptions } from './wrongstack-acp-agent-Dv-A0bEm.js';
5
- import { Agent } from '@wrongstack/core';
1
+ import { a as AgentServerTransport, b as ACPMessage } from './acp-v1-BxskPsdo.js';
2
+ export { S as StdioTransport } from './acp-v1-BxskPsdo.js';
3
+ export { A as ACPToolsRegistry } from './tools-registry-D2xdbzN7.js';
4
+ export { A as ACPProtocolHandler, C as ClientCapabilities, R as RunTurn, g as RunTurnApi, a as RunTurnInput, h as RunTurnPermissionRequest, b as RunTurnResult, i as SessionPersistence, e as WrongStackACPServer, f as WrongStackACPServerOptions } from './wrongstack-acp-agent-nzrqmJnc.js';
5
+ export { A as ACPServerAgentTurnOptions, a as ACPSessionStore, P as PersistedSession, S as SessionStoreOptions, m as makeACPServerAgentTurn } from './server-agent-turn-C3U0lhA-.js';
6
6
  import 'node:events';
7
+ import '@wrongstack/core';
7
8
 
8
9
  /**
9
- * ACPServerAgentTurn — `RunTurn` adapter for the v1 server side.
10
+ * WsBridgeTransportan `AgentServerTransport` backed by a single
11
+ * bidirectional message channel (one WebSocket connection).
10
12
  *
11
- * Wires the ACP v1 server (`ACPProtocolHandler`) to a core `Agent`.
12
- * Each session gets its own `Agent` instance (per spec: sessions are
13
- * isolated; sharing agents across sessions would defeat isolation).
14
- * The agent is created lazily on the first `session/prompt` and
15
- * torn down when the server is closed or the session is removed.
13
+ * Unlike stdio (a process-wide pipe driven by a read loop) or HTTP (one
14
+ * request/response per POST, notifications buffered), a WebSocket is a live
15
+ * full-duplex channel: the agent can stream `session/update` notifications
16
+ * and make `session/request_permission` callbacks WHILE a turn runs. This
17
+ * transport is the seam that lets `ACPProtocolHandler` drive one such
18
+ * connection.
16
19
  *
17
- * The adapter:
18
- * - converts the ACP `ContentBlock[]` prompt into a single string
19
- * (concatenating text blocks; non-text blocks are recorded as a
20
- * note in the prompt — future work can route images / audio to
21
- * the appropriate provider)
22
- * - calls `agent.run(prompt, {signal})` to drive the core loop
23
- * - captures the agent's text result and emits it as one or more
24
- * `agent_message_chunk` notifications
25
- * - maps the agent's stop semantics to a v1 `StopReason`
26
- *
27
- * Streaming: the core `Agent` API is not currently token-streamed
28
- * through this surface (its `run()` returns a final `RunResult`).
29
- * v1 clients expect text deltas, but most implementations batch
30
- * them — a single chunk per turn is acceptable. A future
31
- * enhancement can use the Agent's `Renderer` interface to capture
32
- * deltas as they're written, then forward them as multiple chunks.
33
- *
34
- * Scope: the adapter is deliberately minimal. It does NOT:
35
- * - model the full conversation history across turns (the v1 spec
36
- * leaves this to the agent; on the next prompt we re-feed the
37
- * latest user message and the agent handles its own history)
38
- * - use the agent's tool registry, permission policy, or
39
- * extensions (this adapter is the lowest-fidelity integration;
40
- * a future PR can wire a richer session-aware agent)
41
- * - stream deltas token-by-token (see "Streaming" above)
42
- *
43
- * Cancellation: the parent `AbortSignal` propagates through
44
- * `agent.run({signal})` and the underlying provider call observes
45
- * it. On abort, the adapter maps the resulting `AbortError` to
46
- * `{stopReason: 'cancelled'}`.
20
+ * It is dependency-free and structural: the caller (the CLI, which already
21
+ * depends on `ws`) constructs it with a `send` sink and feeds inbound
22
+ * messages via `receive(msg)`. One handler + one transport per connection.
47
23
  */
48
24
 
49
- interface ACPServerAgentTurnOptions {
25
+ declare class WsBridgeTransport implements AgentServerTransport {
26
+ private readonly sink;
27
+ private readonly handlers;
28
+ private closed;
29
+ /** @param sink Called with each outbound message to write to the socket. */
30
+ constructor(sink: (msg: ACPMessage) => void);
31
+ send(msg: ACPMessage): Promise<void>;
32
+ sendRaw(): void;
33
+ read(): Promise<ACPMessage | null>;
34
+ onMessage(handler: (msg: ACPMessage) => void): () => void;
35
+ close(): void;
50
36
  /**
51
- * Factory that creates a fresh `Agent` for a given session.
52
- * Called once per session on the first `session/prompt` turn.
53
- * The factory must isolate each agent sharing one agent
54
- * across sessions would defeat v1's session-isolation model.
37
+ * Feed one inbound message from the socket. Fires the registered
38
+ * `onMessage` handlers (which route JSON-RPC responses to pending
39
+ * outbound requests inside the handler). Inbound *requests* are processed
40
+ * by the caller via `handler.handleMessage(msg)` call both per message.
55
41
  */
56
- agentFor: (sessionId: string, cwd: string) => Promise<Agent> | Agent;
57
- /**
58
- * Hard wall-clock cap for one turn. The agent's own provider
59
- * timeout is layered under this; this cap is a safety belt.
60
- * Default 5 minutes.
61
- */
62
- timeoutMs?: number | undefined;
42
+ receive(msg: ACPMessage): void;
63
43
  }
64
- /**
65
- * Build a `RunTurn` that owns per-session `Agent` instances and
66
- * delegates each turn to the appropriate agent. The returned
67
- * function is reusable across sessions — the agents are kept in a
68
- * Map keyed by `sessionId`.
69
- */
70
- declare function makeACPServerAgentTurn(opts: ACPServerAgentTurnOptions): RunTurn;
71
44
 
72
- export { type ACPServerAgentTurnOptions, makeACPServerAgentTurn };
45
+ export { AgentServerTransport, WsBridgeTransport };