@wrongstack/acp 1.0.32 → 1.0.35

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.
@@ -17,16 +17,6 @@ type WireMessage = {
17
17
  };
18
18
  export declare function toWire(msg: WireMessage): ACPMessage;
19
19
  export declare const WRONGSTACK_VERSION: string;
20
- /** What kinds of content the agent accepts in a prompt. */
21
- export interface PromptCapabilities {
22
- image: boolean;
23
- audio: boolean;
24
- embeddedContext: boolean;
25
- }
26
- export interface AgentCapabilities {
27
- loadSession: boolean;
28
- promptCapabilities: PromptCapabilities;
29
- }
30
20
  export interface RunTurnInput {
31
21
  sessionId: string;
32
22
  /** Current session configuration, isolated from other sessions. */
@@ -1,6 +1,5 @@
1
1
  import { type ProtocolHandlerOptions, WRONGSTACK_VERSION } from './protocol-contract.js';
2
- import { errorToJsonRpc } from './protocol-session-ops.js';
3
- export type { AgentCapabilities, ClientCapabilities, McpServer, PromptCapabilities, ProtocolHandlerOptions, RunTurn, RunTurnApi, RunTurnInput, RunTurnPermissionRequest, RunTurnResult, SessionConfigOption, SessionMode, SessionPersistence, SessionState, } from './protocol-contract.js';
2
+ export type { ClientCapabilities, McpServer, ProtocolHandlerOptions, RunTurn, RunTurnApi, RunTurnInput, RunTurnPermissionRequest, RunTurnResult, SessionPersistence, SessionState, } from './protocol-contract.js';
4
3
  export { WRONGSTACK_VERSION };
5
4
  export declare class ACPProtocolHandler {
6
5
  private readonly transport;
@@ -60,8 +59,4 @@ export declare class ACPProtocolHandler {
60
59
  private sendError;
61
60
  private allocId;
62
61
  }
63
- /** Internal deterministic seam used by the per-file coverage suite. */
64
- export declare const protocolHandlerCoverage: {
65
- errorToJsonRpc: typeof errorToJsonRpc;
66
- };
67
62
  //# sourceMappingURL=protocol-handler.d.ts.map
@@ -0,0 +1,117 @@
1
+ /**
2
+ * ACPServerAgentTurn — `RunTurn` adapter for the v1 server side.
3
+ *
4
+ * Wires the ACP v1 server (`ACPProtocolHandler`) to a core `Agent`.
5
+ * Each session gets its own `Agent` instance (per spec: sessions are
6
+ * isolated; sharing agents across sessions would defeat isolation).
7
+ * The agent is created lazily on the first `session/prompt` and
8
+ * torn down when the server is closed or the session is removed.
9
+ *
10
+ * The adapter:
11
+ * - converts the ACP `ContentBlock[]` prompt into a single string
12
+ * (concatenating text blocks; non-text blocks are recorded as a
13
+ * note in the prompt — future work can route images / audio to
14
+ * the appropriate provider)
15
+ * - calls `agent.run(prompt, {signal})` to drive the core loop
16
+ * - captures the agent's text result and emits it as one or more
17
+ * `agent_message_chunk` notifications
18
+ * - maps the agent's stop semantics to a v1 `StopReason`
19
+ *
20
+ * Streaming: the core `Agent` API is not currently token-streamed
21
+ * through this surface (its `run()` returns a final `RunResult`).
22
+ * v1 clients expect text deltas, but most implementations batch
23
+ * them — a single chunk per turn is acceptable. A future
24
+ * enhancement can use the Agent's `Renderer` interface to capture
25
+ * deltas as they're written, then forward them as multiple chunks.
26
+ *
27
+ * Scope: the adapter is deliberately minimal. It does NOT:
28
+ * - model the full conversation history across turns (the v1 spec
29
+ * leaves this to the agent; on the next prompt we re-feed the
30
+ * latest user message and the agent handles its own history)
31
+ * - use the agent's tool registry, permission policy, or
32
+ * extensions (this adapter is the lowest-fidelity integration;
33
+ * a future PR can wire a richer session-aware agent)
34
+ * - stream deltas token-by-token (see "Streaming" above)
35
+ *
36
+ * Cancellation: the parent `AbortSignal` propagates through
37
+ * `agent.run({signal})` and the underlying provider call observes
38
+ * it. On abort, the adapter maps the resulting `AbortError` to
39
+ * `{stopReason: 'cancelled'}`.
40
+ *
41
+ * Background delegations: a background `delegate` result is queued for the
42
+ * session's leader and injected by the core agent loop at its next iteration
43
+ * boundary — on ACP that is the next `session/prompt`, because ACP never
44
+ * starts a turn on its own. So the client is not left guessing, the adapter
45
+ * listens for `leader.delivery_pending` on the session agent's event bus and,
46
+ * while no turn is running, sends one coalesced unprompted `session/update`
47
+ * ("Background delegation <id> finished; send any message to continue.")
48
+ * through `RunTurnApi.sendSessionUpdate`. Nothing is sent after the session is
49
+ * disposed, and a notice failure never reaches the event bus.
50
+ */
51
+ import type { Agent, AgentInput } from '@wrongstack/core/agent';
52
+ import type { ContentBlock, PlanEntry, StopReason, ToolKind, UsageCost } from '../types/acp-v1.js';
53
+ /**
54
+ * Prime a freshly-created agent's conversation state with restored history.
55
+ * Each recorded user/agent chunk becomes a `user`/`assistant` message so the
56
+ * model continues the prior conversation instead of starting blank.
57
+ */
58
+ export declare function seedAgentContext(agent: Agent, history: ReadonlyArray<{
59
+ sessionUpdate: string;
60
+ content: unknown;
61
+ }>): void;
62
+ /** Map a WrongStack tool name to the closest ACP ToolKind for UI grouping. */
63
+ export declare function toolNameToKind(name: string): ToolKind;
64
+ /** A short, human-readable title for a tool call card. */
65
+ export declare function toolTitle(name: string, input: unknown): string;
66
+ export declare function isRecord(v: unknown): v is Record<string, unknown>;
67
+ /**
68
+ * Convert an ACP `ContentBlock[]` prompt into a core `AgentInput`.
69
+ *
70
+ * When the prompt is all text we return a plain string (the common,
71
+ * cheapest path). When it carries images we build a multimodal
72
+ * `ContentBlock[]` the provider can pass to a vision-capable model.
73
+ * Images go through core's shared ingest (allowlist, base64, size and count
74
+ * caps, the bytes decide the media type): the client's label used to reach
75
+ * the provider unchecked. Every other block renders as in the text path, so
76
+ * an embedded resource keeps its `[embedded resource: <uri>]` header.
77
+ */
78
+ export declare function promptToAgentInput(blocks: readonly ContentBlock[]): AgentInput;
79
+ /**
80
+ * Convert an ACP `ContentBlock[]` prompt to a single user-message
81
+ * string. Text blocks are concatenated; image / audio / resource
82
+ * blocks are recorded as a bracketed placeholder (full multimodal
83
+ * support is a future PR — the adapter is v1-text only for now).
84
+ */
85
+ export declare function promptToText(blocks: readonly ContentBlock[]): string;
86
+ /**
87
+ * Extract the agent's final text from a `RunResult`. The shape
88
+ * varies across core versions, so we read the most common fields
89
+ * defensively and concatenate whatever text we find.
90
+ */
91
+ export declare function extractText(result: unknown): string;
92
+ /**
93
+ * Map a `RunResult` (and the parent signal) to a v1 `StopReason`.
94
+ *
95
+ * If the parent signal was aborted, return `'cancelled'`. Otherwise
96
+ * the agent completed normally — we treat any non-error result
97
+ * as `'end_turn'`. The core `RunResult` doesn't currently surface
98
+ * a per-turn stop reason, so v1's `'max_tokens'`, `'max_turn_requests'`,
99
+ * and `'refusal'` discriminators can't be emitted precisely; we
100
+ * log a warning if the result carries an error and return the
101
+ * generic end_turn.
102
+ */
103
+ export declare function pickStopReason(result: unknown, signal: AbortSignal): StopReason;
104
+ /**
105
+ * Extract a plan from the agent's RunResult, if available.
106
+ * The plan is an array of PlanEntry objects.
107
+ */
108
+ export declare function extractPlan(result: unknown): PlanEntry[];
109
+ /**
110
+ * Extract usage/token info from the agent's RunResult, if available.
111
+ */
112
+ export declare function extractUsage(result: unknown): {
113
+ used: number;
114
+ size: number;
115
+ cost?: UsageCost | undefined;
116
+ } | null;
117
+ //# sourceMappingURL=server-agent-turn-content.d.ts.map
@@ -48,9 +48,10 @@
48
48
  * through `RunTurnApi.sendSessionUpdate`. Nothing is sent after the session is
49
49
  * disposed, and a notice failure never reaches the event bus.
50
50
  */
51
- import type { Agent, AgentInput } from '@wrongstack/core/agent';
52
- import type { ContentBlock, McpServer, PlanEntry, StopReason, ToolKind, UsageCost } from '../types/acp-v1.js';
51
+ import type { Agent } from '@wrongstack/core/agent';
52
+ import type { McpServer } from '../types/acp-v1.js';
53
53
  import type { RunTurn, RunTurnApi, RunTurnResult } from './protocol-handler.js';
54
+ import { extractPlan, extractText, extractUsage, isRecord, pickStopReason, promptToAgentInput, promptToText, seedAgentContext, toolNameToKind, toolTitle } from './server-agent-turn-content.js';
54
55
  export interface ACPServerAgentTurnOptions {
55
56
  /**
56
57
  * Factory that creates a fresh `Agent` for a given session.
@@ -105,7 +106,7 @@ interface SessionReplayUpdate {
105
106
  * A `RunTurn` that also exposes the recorded per-session history so the
106
107
  * server can replay it on `session/load`.
107
108
  */
108
- export interface ACPServerAgentTurn {
109
+ interface ACPServerAgentTurn {
109
110
  (input: Parameters<RunTurn>[0], emit: Parameters<RunTurn>[1], api?: Parameters<RunTurn>[2]): Promise<RunTurnResult>;
110
111
  /** Recorded user/agent text turns for a session, in order. */
111
112
  replay(sessionId: string): SessionReplayUpdate[];
@@ -142,32 +143,6 @@ declare function agentOwnsSession(agent: Agent, acpSessionId: string, eventSessi
142
143
  declare function deliveryNoticeText(deliveryIds: readonly string[]): string;
143
144
  declare function trimHistory(entries: SessionReplayUpdate[], retainedBytes: number, maxEntries: number, maxBytes: number): number;
144
145
  declare function replayEntryBytes(entry: SessionReplayUpdate): number;
145
- /**
146
- * Prime a freshly-created agent's conversation state with restored history.
147
- * Each recorded user/agent chunk becomes a `user`/`assistant` message so the
148
- * model continues the prior conversation instead of starting blank.
149
- */
150
- declare function seedAgentContext(agent: Agent, history: ReadonlyArray<{
151
- sessionUpdate: string;
152
- content: unknown;
153
- }>): void;
154
- /** Map a WrongStack tool name to the closest ACP ToolKind for UI grouping. */
155
- declare function toolNameToKind(name: string): ToolKind;
156
- /** A short, human-readable title for a tool call card. */
157
- declare function toolTitle(name: string, input: unknown): string;
158
- declare function isRecord(v: unknown): v is Record<string, unknown>;
159
- /**
160
- * Convert an ACP `ContentBlock[]` prompt into a core `AgentInput`.
161
- *
162
- * When the prompt is all text we return a plain string (the common,
163
- * cheapest path). When it carries images we build a multimodal
164
- * `ContentBlock[]` the provider can pass to a vision-capable model.
165
- * Images go through core's shared ingest (allowlist, base64, size and count
166
- * caps, the bytes decide the media type): the client's label used to reach
167
- * the provider unchecked. Every other block renders as in the text path, so
168
- * an embedded resource keeps its `[embedded resource: <uri>]` header.
169
- */
170
- declare function promptToAgentInput(blocks: readonly ContentBlock[]): AgentInput;
171
146
  /**
172
147
  * Tear down the agents and timers held by a turn factory. The
173
148
  * server's `close()` should call this so child connections don't
@@ -176,44 +151,6 @@ declare function promptToAgentInput(blocks: readonly ContentBlock[]): AgentInput
176
151
  export declare function disposeACPServerAgentTurn(opts: {
177
152
  agents: Map<string, Agent>;
178
153
  }): Promise<void>;
179
- /**
180
- * Convert an ACP `ContentBlock[]` prompt to a single user-message
181
- * string. Text blocks are concatenated; image / audio / resource
182
- * blocks are recorded as a bracketed placeholder (full multimodal
183
- * support is a future PR — the adapter is v1-text only for now).
184
- */
185
- declare function promptToText(blocks: readonly ContentBlock[]): string;
186
- /**
187
- * Extract the agent's final text from a `RunResult`. The shape
188
- * varies across core versions, so we read the most common fields
189
- * defensively and concatenate whatever text we find.
190
- */
191
- declare function extractText(result: unknown): string;
192
- /**
193
- * Map a `RunResult` (and the parent signal) to a v1 `StopReason`.
194
- *
195
- * If the parent signal was aborted, return `'cancelled'`. Otherwise
196
- * the agent completed normally — we treat any non-error result
197
- * as `'end_turn'`. The core `RunResult` doesn't currently surface
198
- * a per-turn stop reason, so v1's `'max_tokens'`, `'max_turn_requests'`,
199
- * and `'refusal'` discriminators can't be emitted precisely; we
200
- * log a warning if the result carries an error and return the
201
- * generic end_turn.
202
- */
203
- declare function pickStopReason(result: unknown, signal: AbortSignal): StopReason;
204
- /**
205
- * Extract a plan from the agent's RunResult, if available.
206
- * The plan is an array of PlanEntry objects.
207
- */
208
- declare function extractPlan(result: unknown): PlanEntry[];
209
- /**
210
- * Extract usage/token info from the agent's RunResult, if available.
211
- */
212
- declare function extractUsage(result: unknown): {
213
- used: number;
214
- size: number;
215
- cost?: UsageCost | undefined;
216
- } | null;
217
154
  /** Internal deterministic seams used by the per-file coverage suite. */
218
155
  export declare const serverAgentTurnCoverage: {
219
156
  finitePositiveLimit: typeof finitePositiveLimit;
package/dist/agent.js CHANGED
@@ -999,8 +999,145 @@ var ACPProtocolHandler = class {
999
999
  }
1000
1000
  };
1001
1001
 
1002
- // src/agent/server-agent-turn.ts
1002
+ // src/agent/server-agent-turn-content.ts
1003
1003
  import { parseIncomingImages } from "@wrongstack/core/utils";
1004
+ function seedAgentContext(agent, history) {
1005
+ const state = agent.ctx?.state;
1006
+ if (!state?.appendMessage) return;
1007
+ for (const u of history) {
1008
+ const text = u.content?.text;
1009
+ if (typeof text !== "string" || text.length === 0) continue;
1010
+ const role = u.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
1011
+ state.appendMessage({ role, content: text });
1012
+ }
1013
+ }
1014
+ function toolNameToKind(name) {
1015
+ const n = name.toLowerCase();
1016
+ if (n.includes("read") || n.includes("cat")) return "read";
1017
+ if (n.includes("write") || n.includes("edit") || n.includes("apply") || n.includes("patch"))
1018
+ return "edit";
1019
+ if (n.includes("delete") || n === "rm" || n.startsWith("rm_") || n.endsWith("_rm"))
1020
+ return "delete";
1021
+ if (n.includes("move") || n.includes("rename") || n.includes("mv")) return "move";
1022
+ if (n.includes("grep") || n.includes("glob") || n.includes("search") || n.includes("find"))
1023
+ return "search";
1024
+ if (n.includes("bash") || n.includes("shell") || n.includes("exec") || n.includes("run") || n.includes("terminal"))
1025
+ return "execute";
1026
+ if (n.includes("fetch") || n.includes("http") || n.includes("web") || n.includes("url"))
1027
+ return "fetch";
1028
+ if (n.includes("think") || n.includes("plan")) return "think";
1029
+ return "other";
1030
+ }
1031
+ function toolTitle(name, input) {
1032
+ if (isRecord(input)) {
1033
+ const path3 = input.path ?? input.file ?? input.filePath ?? input.pattern ?? input.command;
1034
+ if (typeof path3 === "string" && path3.length > 0) {
1035
+ return `${name}: ${path3.length > 80 ? `${path3.slice(0, 77)}\u2026` : path3}`;
1036
+ }
1037
+ }
1038
+ return name;
1039
+ }
1040
+ function isRecord(v) {
1041
+ return typeof v === "object" && v !== null && !Array.isArray(v);
1042
+ }
1043
+ function promptToAgentInput(blocks) {
1044
+ const images = blocks.filter((b) => b.type === "image");
1045
+ if (images.length === 0) {
1046
+ return promptToText(blocks);
1047
+ }
1048
+ let parsed;
1049
+ try {
1050
+ parsed = parseIncomingImages(images.map((b) => ({ data: b.data, mediaType: b.mimeType })));
1051
+ } catch (err) {
1052
+ throw Object.assign(new Error(err.message), { code: -32602 });
1053
+ }
1054
+ const out = [];
1055
+ let next = 0;
1056
+ for (const b of blocks) {
1057
+ if (b.type === "image") out.push(parsed[next++]);
1058
+ else if (b.type === "text") out.push({ type: "text", text: b.text });
1059
+ else {
1060
+ const text = promptToText([b]);
1061
+ if (text) out.push({ type: "text", text });
1062
+ }
1063
+ }
1064
+ return out;
1065
+ }
1066
+ function promptToText(blocks) {
1067
+ const parts = [];
1068
+ for (const b of blocks) {
1069
+ if (b.type === "text") {
1070
+ parts.push(b.text);
1071
+ } else if (b.type === "image") {
1072
+ parts.push(`[image: ${b.mimeType}]`);
1073
+ } else if (b.type === "audio") {
1074
+ parts.push(`[audio: ${b.mimeType}]`);
1075
+ } else if (b.type === "resource") {
1076
+ parts.push(
1077
+ "text" in b.resource && typeof b.resource.text === "string" ? `[embedded resource: ${b.resource.uri}]
1078
+ ${b.resource.text}` : `[embedded resource: ${b.resource.uri}]`
1079
+ );
1080
+ } else if (b.type === "resource_link") {
1081
+ parts.push(`[resource link: ${b.uri}]`);
1082
+ }
1083
+ }
1084
+ return parts.join("\n").trim();
1085
+ }
1086
+ function extractText(result) {
1087
+ if (typeof result !== "object" || result === null) return "";
1088
+ const r = result;
1089
+ if (typeof r.text === "string") return r.text;
1090
+ if (Array.isArray(r.content)) {
1091
+ const parts = [];
1092
+ for (const c of r.content) {
1093
+ if (typeof c === "object" && c !== null) {
1094
+ const cb = c;
1095
+ if (cb.type === "text" && typeof cb.text === "string") parts.push(cb.text);
1096
+ }
1097
+ }
1098
+ return parts.join("");
1099
+ }
1100
+ return "";
1101
+ }
1102
+ function pickStopReason(result, signal) {
1103
+ if (signal.aborted) return "cancelled";
1104
+ if (typeof result !== "object" || result === null) return "end_turn";
1105
+ const r = result;
1106
+ if (r.error) {
1107
+ return "end_turn";
1108
+ }
1109
+ if (typeof r.stopReason === "string" && r.stopReason) {
1110
+ return r.stopReason;
1111
+ }
1112
+ return "end_turn";
1113
+ }
1114
+ function extractPlan(result) {
1115
+ if (typeof result !== "object" || result === null) return [];
1116
+ const r = result;
1117
+ if (Array.isArray(r.plan)) {
1118
+ return r.plan.filter(
1119
+ (e) => typeof e === "object" && e !== null && typeof e.content === "string"
1120
+ );
1121
+ }
1122
+ return [];
1123
+ }
1124
+ function extractUsage(result) {
1125
+ if (typeof result !== "object" || result === null) return null;
1126
+ const r = result;
1127
+ if (typeof r.usage === "object" && r.usage !== null) {
1128
+ const u = r.usage;
1129
+ if (typeof u.used === "number" && Number.isFinite(u.used) && typeof u.size === "number" && Number.isFinite(u.size)) {
1130
+ return {
1131
+ used: u.used,
1132
+ size: u.size,
1133
+ ...typeof u.cost === "object" && u.cost !== null ? { cost: u.cost } : {}
1134
+ };
1135
+ }
1136
+ }
1137
+ return null;
1138
+ }
1139
+
1140
+ // src/agent/server-agent-turn.ts
1004
1141
  function makeACPServerAgentTurn(opts) {
1005
1142
  const agents = /* @__PURE__ */ new Map();
1006
1143
  const timeouts = /* @__PURE__ */ new Map();
@@ -1320,141 +1457,6 @@ function trimHistory(entries, retainedBytes, maxEntries, maxBytes) {
1320
1457
  function replayEntryBytes(entry) {
1321
1458
  return Buffer.byteLength(JSON.stringify(entry), "utf8");
1322
1459
  }
1323
- function seedAgentContext(agent, history) {
1324
- const state = agent.ctx?.state;
1325
- if (!state?.appendMessage) return;
1326
- for (const u of history) {
1327
- const text = u.content?.text;
1328
- if (typeof text !== "string" || text.length === 0) continue;
1329
- const role = u.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
1330
- state.appendMessage({ role, content: text });
1331
- }
1332
- }
1333
- function toolNameToKind(name) {
1334
- const n = name.toLowerCase();
1335
- if (n.includes("read") || n.includes("cat")) return "read";
1336
- if (n.includes("write") || n.includes("edit") || n.includes("apply") || n.includes("patch"))
1337
- return "edit";
1338
- if (n.includes("delete") || n === "rm" || n.startsWith("rm_") || n.endsWith("_rm"))
1339
- return "delete";
1340
- if (n.includes("move") || n.includes("rename") || n.includes("mv")) return "move";
1341
- if (n.includes("grep") || n.includes("glob") || n.includes("search") || n.includes("find"))
1342
- return "search";
1343
- if (n.includes("bash") || n.includes("shell") || n.includes("exec") || n.includes("run") || n.includes("terminal"))
1344
- return "execute";
1345
- if (n.includes("fetch") || n.includes("http") || n.includes("web") || n.includes("url"))
1346
- return "fetch";
1347
- if (n.includes("think") || n.includes("plan")) return "think";
1348
- return "other";
1349
- }
1350
- function toolTitle(name, input) {
1351
- if (isRecord(input)) {
1352
- const path3 = input.path ?? input.file ?? input.filePath ?? input.pattern ?? input.command;
1353
- if (typeof path3 === "string" && path3.length > 0) {
1354
- return `${name}: ${path3.length > 80 ? `${path3.slice(0, 77)}\u2026` : path3}`;
1355
- }
1356
- }
1357
- return name;
1358
- }
1359
- function isRecord(v) {
1360
- return typeof v === "object" && v !== null && !Array.isArray(v);
1361
- }
1362
- function promptToAgentInput(blocks) {
1363
- const images = blocks.filter((b) => b.type === "image");
1364
- if (images.length === 0) {
1365
- return promptToText(blocks);
1366
- }
1367
- let parsed;
1368
- try {
1369
- parsed = parseIncomingImages(images.map((b) => ({ data: b.data, mediaType: b.mimeType })));
1370
- } catch (err) {
1371
- throw Object.assign(new Error(err.message), { code: -32602 });
1372
- }
1373
- const out = [];
1374
- let next = 0;
1375
- for (const b of blocks) {
1376
- if (b.type === "image") out.push(parsed[next++]);
1377
- else if (b.type === "text") out.push({ type: "text", text: b.text });
1378
- else {
1379
- const text = promptToText([b]);
1380
- if (text) out.push({ type: "text", text });
1381
- }
1382
- }
1383
- return out;
1384
- }
1385
- function promptToText(blocks) {
1386
- const parts = [];
1387
- for (const b of blocks) {
1388
- if (b.type === "text") {
1389
- parts.push(b.text);
1390
- } else if (b.type === "image") {
1391
- parts.push(`[image: ${b.mimeType}]`);
1392
- } else if (b.type === "audio") {
1393
- parts.push(`[audio: ${b.mimeType}]`);
1394
- } else if (b.type === "resource") {
1395
- parts.push(
1396
- "text" in b.resource && typeof b.resource.text === "string" ? `[embedded resource: ${b.resource.uri}]
1397
- ${b.resource.text}` : `[embedded resource: ${b.resource.uri}]`
1398
- );
1399
- } else if (b.type === "resource_link") {
1400
- parts.push(`[resource link: ${b.uri}]`);
1401
- }
1402
- }
1403
- return parts.join("\n").trim();
1404
- }
1405
- function extractText(result) {
1406
- if (typeof result !== "object" || result === null) return "";
1407
- const r = result;
1408
- if (typeof r.text === "string") return r.text;
1409
- if (Array.isArray(r.content)) {
1410
- const parts = [];
1411
- for (const c of r.content) {
1412
- if (typeof c === "object" && c !== null) {
1413
- const cb = c;
1414
- if (cb.type === "text" && typeof cb.text === "string") parts.push(cb.text);
1415
- }
1416
- }
1417
- return parts.join("");
1418
- }
1419
- return "";
1420
- }
1421
- function pickStopReason(result, signal) {
1422
- if (signal.aborted) return "cancelled";
1423
- if (typeof result !== "object" || result === null) return "end_turn";
1424
- const r = result;
1425
- if (r.error) {
1426
- return "end_turn";
1427
- }
1428
- if (typeof r.stopReason === "string" && r.stopReason) {
1429
- return r.stopReason;
1430
- }
1431
- return "end_turn";
1432
- }
1433
- function extractPlan(result) {
1434
- if (typeof result !== "object" || result === null) return [];
1435
- const r = result;
1436
- if (Array.isArray(r.plan)) {
1437
- return r.plan.filter(
1438
- (e) => typeof e === "object" && e !== null && typeof e.content === "string"
1439
- );
1440
- }
1441
- return [];
1442
- }
1443
- function extractUsage(result) {
1444
- if (typeof result !== "object" || result === null) return null;
1445
- const r = result;
1446
- if (typeof r.usage === "object" && r.usage !== null) {
1447
- const u = r.usage;
1448
- if (typeof u.used === "number" && Number.isFinite(u.used) && typeof u.size === "number" && Number.isFinite(u.size)) {
1449
- return {
1450
- used: u.used,
1451
- size: u.size,
1452
- ...typeof u.cost === "object" && u.cost !== null ? { cost: u.cost } : {}
1453
- };
1454
- }
1455
- }
1456
- return null;
1457
- }
1458
1460
 
1459
1461
  // src/agent/session-store.ts
1460
1462
  import * as fsp2 from "node:fs/promises";
@@ -0,0 +1,23 @@
1
+ import type { ACPClientTransport } from '../agent/stdio-transport.js';
2
+ import type { AgentCapabilities, ContentBlock, SessionId } from '../types/acp-v1.js';
3
+ import type { State } from './acp-request-state.js';
4
+ import type { ACPProgressHandler, ACPSessionRunResult } from './acp-session-types.js';
5
+ import type { ACPSessionScratch } from './acp-session-updates.js';
6
+ export interface AcpSessionPromptHost {
7
+ closed: boolean;
8
+ state: State;
9
+ promptCallbackAbort: AbortController | null;
10
+ agentCapabilities: AgentCapabilities;
11
+ sessionId: SessionId | null;
12
+ transport: ACPClientTransport;
13
+ createSessionWithAuth(): Promise<SessionId>;
14
+ cancelLateSession(createPromise: Promise<SessionId>): void;
15
+ resetScratch(): void;
16
+ progressHandler: ACPProgressHandler | null;
17
+ allocId(): number;
18
+ sendRequest(id: number, method: string, params: unknown, timeoutMs?: number): Promise<unknown>;
19
+ timeoutMs: number;
20
+ scratch: ACPSessionScratch;
21
+ }
22
+ export declare function prompt(host: AcpSessionPromptHost, blocks: ContentBlock[], signal: AbortSignal, onProgress?: ACPProgressHandler): Promise<ACPSessionRunResult>;
23
+ //# sourceMappingURL=acp-session-prompt.d.ts.map
@@ -140,5 +140,6 @@ export declare class ACPSession {
140
140
  private resetScratch;
141
141
  private acpSessionAuthHost;
142
142
  private acpSessionMessagesHost;
143
+ private acpSessionPromptHost;
143
144
  }
144
145
  //# sourceMappingURL=acp-session.d.ts.map