@gaunt-sloth/agent 2.0.0-alpha.38 → 2.0.0-alpha.39

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.
Files changed (38) hide show
  1. package/README.md +6 -5
  2. package/cli-acp.js +5 -4
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +4 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/modules/acp/acpAgentApp.d.ts +16 -52
  7. package/dist/modules/acp/acpAgentApp.js +31 -246
  8. package/dist/modules/acp/acpAgentApp.js.map +1 -1
  9. package/dist/modules/acp/acpAgentAppV1.d.ts +52 -0
  10. package/dist/modules/acp/acpAgentAppV1.js +307 -0
  11. package/dist/modules/acp/acpAgentAppV1.js.map +1 -0
  12. package/dist/modules/acp/acpCommon.d.ts +167 -0
  13. package/dist/modules/acp/acpCommon.js +282 -0
  14. package/dist/modules/acp/acpCommon.js.map +1 -0
  15. package/dist/modules/acp/acpPermissions.d.ts +6 -1
  16. package/dist/modules/acp/acpPermissions.js +5 -1
  17. package/dist/modules/acp/acpPermissions.js.map +1 -1
  18. package/dist/modules/acp/acpPermissionsV1.d.ts +45 -0
  19. package/dist/modules/acp/acpPermissionsV1.js +110 -0
  20. package/dist/modules/acp/acpPermissionsV1.js.map +1 -0
  21. package/dist/modules/acp/acpRouter.d.ts +41 -0
  22. package/dist/modules/acp/acpRouter.js +48 -0
  23. package/dist/modules/acp/acpRouter.js.map +1 -0
  24. package/dist/modules/acp/acpStdio.d.ts +9 -3
  25. package/dist/modules/acp/acpStdio.js +11 -5
  26. package/dist/modules/acp/acpStdio.js.map +1 -1
  27. package/dist/modules/acp/acpToolCalls.d.ts +93 -0
  28. package/dist/modules/acp/acpToolCalls.js +193 -0
  29. package/dist/modules/acp/acpToolCalls.js.map +1 -0
  30. package/dist/modules/acp/acpUpdates.d.ts +7 -60
  31. package/dist/modules/acp/acpUpdates.js +10 -155
  32. package/dist/modules/acp/acpUpdates.js.map +1 -1
  33. package/dist/modules/acp/acpUpdatesV1.d.ts +61 -0
  34. package/dist/modules/acp/acpUpdatesV1.js +162 -0
  35. package/dist/modules/acp/acpUpdatesV1.js.map +1 -0
  36. package/dist/modules/interactiveSessionModule.js +90 -94
  37. package/dist/modules/interactiveSessionModule.js.map +1 -1
  38. package/package.json +2 -2
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * @packageDocumentation
3
- * Translates the agent runtime's typed {@link AgentStreamEvent} stream into ACP v2
4
- * `session/update` payloads.
3
+ * Translates the agent runtime's typed {@link AgentStreamEvent} stream into ACP **v2**
4
+ * `session/update` payloads. (`acpUpdatesV1.ts` is the v1 half; both extend the tool-call tracker
5
+ * in `acpToolCalls.ts`, which is where the parts that are not about the dialect live.)
5
6
  *
6
7
  * Kept as a pure, stateful-but-transport-free mapper rather than inlined in the request handlers
7
8
  * for two reasons. It is the half of the ACP surface with real logic — message identity, tool-call
@@ -20,54 +21,19 @@
20
21
  * call correct rather than flickering back to a bare id.
21
22
  */
22
23
  import { randomUUID } from 'node:crypto';
23
- /**
24
- * ACP tool KIND for a gth tool name — the hint a client uses to pick an icon and a UI treatment.
25
- *
26
- * Matched by exact name, with `other` as the fallback, because a wrong kind is worse than a
27
- * generic one: a client that shows a delete glyph for a read is actively misleading about what the
28
- * agent is doing. Unknown names (custom tools, MCP tools) therefore land on `other` rather than
29
- * being guessed at from substrings.
30
- */
31
- const TOOL_KINDS = {
32
- create_directory: 'edit',
33
- delete_directory: 'delete',
34
- delete_file: 'delete',
35
- directory_tree: 'read',
36
- edit_file: 'edit',
37
- get_file_info: 'read',
38
- gth_read_binary: 'read',
39
- gth_status_update: 'think',
40
- gth_web_fetch: 'fetch',
41
- list_allowed_directories: 'read',
42
- list_directory: 'read',
43
- list_directory_with_sizes: 'read',
44
- move_file: 'move',
45
- read_file: 'read',
46
- read_multiple_files: 'read',
47
- run_build: 'execute',
48
- run_lint: 'execute',
49
- run_shell_command: 'execute',
50
- run_single_test: 'execute',
51
- run_tests: 'execute',
52
- search_files: 'search',
53
- write_file: 'edit',
54
- };
55
- /** The ACP tool kind for a gth tool name; `other` for anything not built in. */
56
- export function toolKindFor(name) {
57
- return TOOL_KINDS[name] ?? 'other';
58
- }
24
+ import { AcpToolCallTracker, toolKindFor } from '#src/modules/acp/acpToolCalls.js';
59
25
  /** One text content block, the shape both message chunks and tool content wrap. */
60
26
  function textBlock(text) {
61
27
  return { type: 'text', text };
62
28
  }
63
29
  /**
64
- * Turns one agent run's event stream into ACP `session/update` payloads.
30
+ * Turns one agent run's event stream into ACP v2 `session/update` payloads.
65
31
  *
66
32
  * One instance per prompt turn: it holds the message identity of the assistant text run and of the
67
33
  * reasoning run, plus the accumulated argument text per tool call. A fresh instance per turn is
68
34
  * what makes a new turn a new `messageId`, which is how a client tells two messages apart.
69
35
  */
70
- export class AcpUpdateMapper {
36
+ export class AcpUpdateMapper extends AcpToolCallTracker {
71
37
  /**
72
38
  * `messageId` of the assistant text message currently being streamed, or `null` when no text run
73
39
  * is open. Cleared whenever something else interrupts the text (a tool call, a reasoning block),
@@ -77,72 +43,6 @@ export class AcpUpdateMapper {
77
43
  assistantMessageId = null;
78
44
  /** `messageId` of the reasoning message currently being streamed, or `null` outside one. */
79
45
  thoughtMessageId = null;
80
- /**
81
- * Streamed argument text per tool call id, reassembled from `tool_args` deltas. Held rather than
82
- * forwarded per delta because ACP has no argument-delta update: `rawInput` is a whole value, so
83
- * it can only be sent once the deltas stop arriving.
84
- */
85
- toolArgs = new Map();
86
- /**
87
- * Tool calls the model has requested but which have neither produced a result nor been claimed by
88
- * a permission request, in the order they were announced, as `[toolCallId, toolName]`.
89
- *
90
- * Kept so the approval bridge can name the tool call a permission request is ABOUT. The gate's
91
- * `PendingToolInterrupt` carries the tool's name and arguments but no call id — the graph
92
- * suspends inside the middleware wrapping the call, which is downstream of where the id lives —
93
- * while the client has already drawn that call from this stream. This queue reconnects the two.
94
- */
95
- openToolCalls = [];
96
- /**
97
- * Takes the id of the unclaimed tool call that matches `name` and `args`, removing it from the
98
- * queue, or `undefined` when there is none.
99
- *
100
- * **Matched on the ARGUMENTS, because position is not a reliable discriminator here.** The
101
- * arguments are the one value both sides hold: the gate's `PendingToolInterrupt` carries them, and
102
- * this mapper still holds the streamed argument text at claim time (it is only discarded on
103
- * `tool_result`, which exists solely on the resumed run).
104
- *
105
- * **Where the exact match degrades, named rather than implied:** the mapper's side is JSON
106
- * reassembled from the model's streamed argument deltas, and a local model that ignores
107
- * `disable_parallel_tool_use` can merge sibling calls' buffers into invalid JSON (`{}{}`,
108
- * `{"steps":3}{}` — see the AG-UI server's `parseToolArguments` note). {@link parseToolArgs}
109
- * deliberately does not carry that path's recovery, so such a payload stays a raw string, matches
110
- * nothing, and falls back to position — on exactly the model class most likely to emit sloppy
111
- * parallel calls. The fallback is still the best remaining answer and the cost is which row a
112
- * client attaches the prompt to, never which command the human rules on.
113
- *
114
- * **Position was tried and is wrong in both directions**, which is why it is only the fallback.
115
- * The runner drains suspended calls as a BATCH — every pending call decided in turn before
116
- * anything resumes — so a model emitting two parallel calls of one tool has both open and neither
117
- * running. Returning "the most recent" handed BOTH requests the second call's id. But plain
118
- * oldest-first is no better in the case that is *normal* at the rated rungs: this method is
119
- * reached only from the human-approval callback, which sits behind the gate's earlier exits
120
- * (not-gated, deny list, bypass, the hardline floor, the allow list, and the rater's own arms), so
121
- * a batch where one call is settled without a human and its sibling escalates leaves the settled
122
- * call's id unclaimed at the head of the queue — and oldest-first then hands the request the
123
- * wrong one, with every upstream ordering assumption perfectly intact.
124
- *
125
- * **Consuming is right either way**, and the queue order still decides between two calls whose
126
- * arguments are genuinely identical, where either answer is equally true.
127
- *
128
- * Absent rather than guessed when nothing matches — a permission request pointing at the WRONG
129
- * call is worse than one pointing at no call, because a client would then attach the answer to a
130
- * call the user never saw.
131
- */
132
- claimToolCallId(name, args) {
133
- const candidates = this.openToolCalls
134
- .map(([id, toolName], index) => ({ id, toolName, index }))
135
- .filter((candidate) => candidate.toolName === name);
136
- if (candidates.length === 0)
137
- return undefined;
138
- const wanted = args === undefined ? undefined : canonicalJson(args);
139
- const matched = wanted === undefined
140
- ? undefined
141
- : candidates.find((candidate) => canonicalJson(parseToolArgs(this.toolArgs.get(candidate.id))) === wanted);
142
- const chosen = matched ?? candidates[0];
143
- this.openToolCalls.splice(chosen.index, 1);
144
- return chosen.id;
145
- }
146
46
  /**
147
47
  * The `session/update` payloads one runtime event produces — usually one, sometimes none
148
48
  * (`tool_args`, which only accumulates; the reasoning boundaries, which only move state).
@@ -181,8 +81,7 @@ export class AcpUpdateMapper {
181
81
  case 'tool_start': {
182
82
  // A tool call ends the open text run: the text that follows the tool is a separate message.
183
83
  this.assistantMessageId = null;
184
- this.toolArgs.set(event.id, '');
185
- this.openToolCalls.push([event.id, event.name]);
84
+ this.trackToolStart(event.id, event.name);
186
85
  // The CREATING update — the first one a client sees for this id. Everything descriptive is
187
86
  // sent here and never resent, because from here on omission means "unchanged".
188
87
  return [
@@ -197,11 +96,11 @@ export class AcpUpdateMapper {
197
96
  ];
198
97
  }
199
98
  case 'tool_args': {
200
- this.toolArgs.set(event.id, (this.toolArgs.get(event.id) ?? '') + event.delta);
99
+ this.appendToolArgs(event.id, event.delta);
201
100
  return [];
202
101
  }
203
102
  case 'tool_end': {
204
- const rawInput = parseToolArgs(this.toolArgs.get(event.id));
103
+ const rawInput = this.rawInputFor(event.id);
205
104
  // Status only (plus the arguments, once they are complete). No title, no kind, no name —
206
105
  // the client keeps the ones the creating update set.
207
106
  return [
@@ -227,12 +126,7 @@ export class AcpUpdateMapper {
227
126
  ];
228
127
  }
229
128
  case 'tool_result': {
230
- this.toolArgs.delete(event.id);
231
- // A call a permission request already claimed is no longer in the queue; that is expected,
232
- // not a miss.
233
- const open = this.openToolCalls.findIndex(([id]) => id === event.id);
234
- if (open >= 0)
235
- this.openToolCalls.splice(open, 1);
129
+ this.trackToolSettled(event.id);
236
130
  return [
237
131
  {
238
132
  sessionUpdate: 'tool_call_update',
@@ -245,43 +139,4 @@ export class AcpUpdateMapper {
245
139
  }
246
140
  }
247
141
  }
248
- /**
249
- * The reassembled tool arguments as a value for `rawInput`, or `undefined` when there is nothing
250
- * worth sending.
251
- *
252
- * Deliberately fail-soft: a model that emits malformed argument JSON is a real and recurring
253
- * condition (see the AG-UI server's `parseToolArguments` note), and it must not take down the turn
254
- * that reports it. An unparseable payload is passed through as the raw string so the client can
255
- * still show what the model asked for.
256
- */
257
- /**
258
- * A value serialized with object keys in sorted order, so two arguments objects that differ only in
259
- * key order compare equal.
260
- *
261
- * They routinely do: one side is JSON reassembled from a model's streamed argument deltas and the
262
- * other is the object the graph handed the gate. Comparing raw `JSON.stringify` output would make
263
- * the exact match in {@link AcpUpdateMapper.claimToolCallId} fail for a reason that has nothing to
264
- * do with whether the two describe the same call.
265
- */
266
- function canonicalJson(value) {
267
- if (value === null || typeof value !== 'object')
268
- return JSON.stringify(value) ?? 'undefined';
269
- if (Array.isArray(value))
270
- return `[${value.map(canonicalJson).join(',')}]`;
271
- const entries = Object.keys(value)
272
- .sort()
273
- .map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`);
274
- return `{${entries.join(',')}}`;
275
- }
276
- function parseToolArgs(raw) {
277
- const text = (raw ?? '').trim();
278
- if (text.length === 0)
279
- return undefined;
280
- try {
281
- return JSON.parse(text);
282
- }
283
- catch {
284
- return text;
285
- }
286
- }
287
142
  //# sourceMappingURL=acpUpdates.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"acpUpdates.js","sourceRoot":"","sources":["../../../src/modules/acp/acpUpdates.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acpUpdates.js","sourceRoot":"","sources":["../../../src/modules/acp/acpUpdates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Translates the agent runtime's typed {@link AgentStreamEvent} stream into ACP **v1**
4
+ * `session/update` payloads. (`acpUpdates.ts` is the v2 half.)
5
+ *
6
+ * ## Where v1 differs, and why the mapper could not be shared
7
+ *
8
+ * The two dialects report the same events, but not with the same messages, and each difference
9
+ * changes what a conforming client ends up rendering:
10
+ *
11
+ * - **v1 has a distinct `tool_call` update that CREATES a tool call**, where v2 folded creation into
12
+ * the first `tool_call_update`. Sending only `tool_call_update`s on v1 would leave a client
13
+ * patching a call it was never told about.
14
+ * - **v1 has no `tool_call_content_chunk`.** Its `tool_call_update.content` REPLACES the whole
15
+ * collection, so live tool output is streamed by accumulating it here and resending the
16
+ * collection — the opposite of v2, where each chunk appends and only a `tool_call_update` replaces.
17
+ * - **v1 has no `state_update`.** There is nowhere to report `running` / `requires_action` / `idle`,
18
+ * and no notification carries the stop reason: the turn's outcome is the `session/prompt`
19
+ * RESPONSE. See `acpAgentAppV1.ts`.
20
+ * - **A prompt turn does not echo the user's message.** v1 reserves replay for `session/load`; a
21
+ * client already renders what it sent, so echoing it would draw the message twice.
22
+ *
23
+ * What is NOT duplicated is tool-call identity — the kind hint, the argument reassembly, and the
24
+ * pairing that lets a permission request name the call it is about all come from
25
+ * {@link AcpToolCallTracker}.
26
+ */
27
+ import type { SessionUpdate } from '@agentclientprotocol/sdk';
28
+ import type { AgentStreamEvent } from '@gaunt-sloth/core/core/types.js';
29
+ import { AcpToolCallTracker } from '#src/modules/acp/acpToolCalls.js';
30
+ /**
31
+ * Turns one agent run's event stream into ACP v1 `session/update` payloads.
32
+ *
33
+ * One instance per prompt turn: it holds the message identity of the assistant text run and of the
34
+ * reasoning run, the accumulated argument text per tool call, and the output accumulated for each
35
+ * running tool. A fresh instance per turn is what makes a new turn a new `messageId`, which is how
36
+ * a client tells two messages apart.
37
+ */
38
+ export declare class AcpV1UpdateMapper extends AcpToolCallTracker {
39
+ /**
40
+ * `messageId` of the assistant text message currently being streamed, or `null` when no text run
41
+ * is open. Cleared whenever something else interrupts the text (a tool call, a reasoning block),
42
+ * so the text that resumes afterwards is a NEW message rather than an append to the one the
43
+ * client already considers finished.
44
+ */
45
+ private assistantMessageId;
46
+ /** `messageId` of the reasoning message currently being streamed, or `null` outside one. */
47
+ private thoughtMessageId;
48
+ /**
49
+ * Live output accumulated per tool call, because v1 can only REPLACE a tool call's content.
50
+ *
51
+ * With no append-a-chunk update in the dialect, the only way to show a tool's output as it
52
+ * arrives is to resend everything seen so far; keeping the collection here is what makes each
53
+ * replacement a superset of the last rather than a flicker back to the newest line alone.
54
+ */
55
+ private readonly toolOutput;
56
+ /**
57
+ * The `session/update` payloads one runtime event produces — usually one, sometimes none
58
+ * (`tool_args`, which only accumulates; the reasoning boundaries, which only move state).
59
+ */
60
+ map(event: AgentStreamEvent): SessionUpdate[];
61
+ }
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Translates the agent runtime's typed {@link AgentStreamEvent} stream into ACP **v1**
4
+ * `session/update` payloads. (`acpUpdates.ts` is the v2 half.)
5
+ *
6
+ * ## Where v1 differs, and why the mapper could not be shared
7
+ *
8
+ * The two dialects report the same events, but not with the same messages, and each difference
9
+ * changes what a conforming client ends up rendering:
10
+ *
11
+ * - **v1 has a distinct `tool_call` update that CREATES a tool call**, where v2 folded creation into
12
+ * the first `tool_call_update`. Sending only `tool_call_update`s on v1 would leave a client
13
+ * patching a call it was never told about.
14
+ * - **v1 has no `tool_call_content_chunk`.** Its `tool_call_update.content` REPLACES the whole
15
+ * collection, so live tool output is streamed by accumulating it here and resending the
16
+ * collection — the opposite of v2, where each chunk appends and only a `tool_call_update` replaces.
17
+ * - **v1 has no `state_update`.** There is nowhere to report `running` / `requires_action` / `idle`,
18
+ * and no notification carries the stop reason: the turn's outcome is the `session/prompt`
19
+ * RESPONSE. See `acpAgentAppV1.ts`.
20
+ * - **A prompt turn does not echo the user's message.** v1 reserves replay for `session/load`; a
21
+ * client already renders what it sent, so echoing it would draw the message twice.
22
+ *
23
+ * What is NOT duplicated is tool-call identity — the kind hint, the argument reassembly, and the
24
+ * pairing that lets a permission request name the call it is about all come from
25
+ * {@link AcpToolCallTracker}.
26
+ */
27
+ import { randomUUID } from 'node:crypto';
28
+ import { AcpToolCallTracker, toolKindFor } from '#src/modules/acp/acpToolCalls.js';
29
+ /** One text content block, the shape both message chunks and tool content wrap. */
30
+ function textBlock(text) {
31
+ return { type: 'text', text };
32
+ }
33
+ /** One tool-call content entry wrapping a text block. */
34
+ function toolText(text) {
35
+ return { type: 'content', content: textBlock(text) };
36
+ }
37
+ /**
38
+ * Turns one agent run's event stream into ACP v1 `session/update` payloads.
39
+ *
40
+ * One instance per prompt turn: it holds the message identity of the assistant text run and of the
41
+ * reasoning run, the accumulated argument text per tool call, and the output accumulated for each
42
+ * running tool. A fresh instance per turn is what makes a new turn a new `messageId`, which is how
43
+ * a client tells two messages apart.
44
+ */
45
+ export class AcpV1UpdateMapper extends AcpToolCallTracker {
46
+ /**
47
+ * `messageId` of the assistant text message currently being streamed, or `null` when no text run
48
+ * is open. Cleared whenever something else interrupts the text (a tool call, a reasoning block),
49
+ * so the text that resumes afterwards is a NEW message rather than an append to the one the
50
+ * client already considers finished.
51
+ */
52
+ assistantMessageId = null;
53
+ /** `messageId` of the reasoning message currently being streamed, or `null` outside one. */
54
+ thoughtMessageId = null;
55
+ /**
56
+ * Live output accumulated per tool call, because v1 can only REPLACE a tool call's content.
57
+ *
58
+ * With no append-a-chunk update in the dialect, the only way to show a tool's output as it
59
+ * arrives is to resend everything seen so far; keeping the collection here is what makes each
60
+ * replacement a superset of the last rather than a flicker back to the newest line alone.
61
+ */
62
+ toolOutput = new Map();
63
+ /**
64
+ * The `session/update` payloads one runtime event produces — usually one, sometimes none
65
+ * (`tool_args`, which only accumulates; the reasoning boundaries, which only move state).
66
+ */
67
+ map(event) {
68
+ switch (event.type) {
69
+ case 'text': {
70
+ this.assistantMessageId ??= randomUUID();
71
+ return [
72
+ {
73
+ sessionUpdate: 'agent_message_chunk',
74
+ messageId: this.assistantMessageId,
75
+ content: textBlock(event.delta),
76
+ },
77
+ ];
78
+ }
79
+ case 'reasoning_start': {
80
+ this.assistantMessageId = null;
81
+ this.thoughtMessageId = randomUUID();
82
+ return [];
83
+ }
84
+ case 'reasoning_delta': {
85
+ this.thoughtMessageId ??= randomUUID();
86
+ return [
87
+ {
88
+ sessionUpdate: 'agent_thought_chunk',
89
+ messageId: this.thoughtMessageId,
90
+ content: textBlock(event.delta),
91
+ },
92
+ ];
93
+ }
94
+ case 'reasoning_end': {
95
+ this.thoughtMessageId = null;
96
+ return [];
97
+ }
98
+ case 'tool_start': {
99
+ // A tool call ends the open text run: the text that follows the tool is a separate message.
100
+ this.assistantMessageId = null;
101
+ this.trackToolStart(event.id, event.name);
102
+ this.toolOutput.set(event.id, []);
103
+ // v1's CREATE. `title` is required here, and everything descriptive is sent with it; the
104
+ // later `tool_call_update`s carry only what changed.
105
+ return [
106
+ {
107
+ sessionUpdate: 'tool_call',
108
+ toolCallId: event.id,
109
+ name: event.name,
110
+ title: event.name,
111
+ kind: toolKindFor(event.name),
112
+ status: 'pending',
113
+ },
114
+ ];
115
+ }
116
+ case 'tool_args': {
117
+ this.appendToolArgs(event.id, event.delta);
118
+ return [];
119
+ }
120
+ case 'tool_end': {
121
+ const rawInput = this.rawInputFor(event.id);
122
+ // Status only (plus the arguments, once they are complete). No title, no kind, no name —
123
+ // the client keeps the ones the creating update set.
124
+ return [
125
+ {
126
+ sessionUpdate: 'tool_call_update',
127
+ toolCallId: event.id,
128
+ status: 'in_progress',
129
+ ...(rawInput === undefined ? {} : { rawInput }),
130
+ },
131
+ ];
132
+ }
133
+ case 'tool_output': {
134
+ if (event.id === undefined)
135
+ return [];
136
+ const collected = this.toolOutput.get(event.id) ?? [];
137
+ collected.push(toolText(event.chunk));
138
+ this.toolOutput.set(event.id, collected);
139
+ // The whole collection, because v1 replaces rather than appends. Copied so a later push
140
+ // cannot mutate an update already handed to the transport.
141
+ return [
142
+ { sessionUpdate: 'tool_call_update', toolCallId: event.id, content: [...collected] },
143
+ ];
144
+ }
145
+ case 'tool_result': {
146
+ this.trackToolSettled(event.id);
147
+ this.toolOutput.delete(event.id);
148
+ // The result REPLACES whatever live output was showing — it is the authoritative record of
149
+ // what the tool produced, and the same thing v2's final update does.
150
+ return [
151
+ {
152
+ sessionUpdate: 'tool_call_update',
153
+ toolCallId: event.id,
154
+ status: event.isError ? 'failed' : 'completed',
155
+ content: [toolText(event.content)],
156
+ },
157
+ ];
158
+ }
159
+ }
160
+ }
161
+ }
162
+ //# sourceMappingURL=acpUpdatesV1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acpUpdatesV1.js","sourceRoot":"","sources":["../../../src/modules/acp/acpUpdatesV1.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAEnF,mFAAmF;AACnF,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAChC,CAAC;AAED,yDAAyD;AACzD,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;AACvD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAkB,SAAQ,kBAAkB;IACvD;;;;;OAKG;IACK,kBAAkB,GAAkB,IAAI,CAAC;IAEjD,4FAA4F;IACpF,gBAAgB,GAAkB,IAAI,CAAC;IAE/C;;;;;;OAMG;IACc,UAAU,GAAG,IAAI,GAAG,EAA6B,CAAC;IAEnE;;;OAGG;IACH,GAAG,CAAC,KAAuB;QACzB,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,MAAM,EAAE,CAAC;gBACZ,IAAI,CAAC,kBAAkB,KAAK,UAAU,EAAE,CAAC;gBACzC,OAAO;oBACL;wBACE,aAAa,EAAE,qBAAqB;wBACpC,SAAS,EAAE,IAAI,CAAC,kBAAkB;wBAClC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC;qBAChC;iBACF,CAAC;YACJ,CAAC;YACD,KAAK,iBAAiB,EAAE,CAAC;gBACvB,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;gBAC/B,IAAI,CAAC,gBAAgB,GAAG,UAAU,EAAE,CAAC;gBACrC,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,KAAK,iBAAiB,EAAE,CAAC;gBACvB,IAAI,CAAC,gBAAgB,KAAK,UAAU,EAAE,CAAC;gBACvC,OAAO;oBACL;wBACE,aAAa,EAAE,qBAAqB;wBACpC,SAAS,EAAE,IAAI,CAAC,gBAAgB;wBAChC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC;qBAChC;iBACF,CAAC;YACJ,CAAC;YACD,KAAK,eAAe,EAAE,CAAC;gBACrB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAC7B,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,KAAK,YAAY,EAAE,CAAC;gBAClB,4FAA4F;gBAC5F,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;gBAC/B,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC1C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBAClC,yFAAyF;gBACzF,qDAAqD;gBACrD,OAAO;oBACL;wBACE,aAAa,EAAE,WAAW;wBAC1B,UAAU,EAAE,KAAK,CAAC,EAAE;wBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,KAAK,EAAE,KAAK,CAAC,IAAI;wBACjB,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC;wBAC7B,MAAM,EAAE,SAAS;qBAClB;iBACF,CAAC;YACJ,CAAC;YACD,KAAK,WAAW,EAAE,CAAC;gBACjB,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC3C,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,KAAK,UAAU,EAAE,CAAC;gBAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC5C,yFAAyF;gBACzF,qDAAqD;gBACrD,OAAO;oBACL;wBACE,aAAa,EAAE,kBAAkB;wBACjC,UAAU,EAAE,KAAK,CAAC,EAAE;wBACpB,MAAM,EAAE,aAAa;wBACrB,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;qBAChD;iBACF,CAAC;YACJ,CAAC;YACD,KAAK,aAAa,EAAE,CAAC;gBACnB,IAAI,KAAK,CAAC,EAAE,KAAK,SAAS;oBAAE,OAAO,EAAE,CAAC;gBACtC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;gBACtD,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;gBACtC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;gBACzC,wFAAwF;gBACxF,2DAA2D;gBAC3D,OAAO;oBACL,EAAE,aAAa,EAAE,kBAAkB,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE;iBACrF,CAAC;YACJ,CAAC;YACD,KAAK,aAAa,EAAE,CAAC;gBACnB,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAChC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACjC,2FAA2F;gBAC3F,qEAAqE;gBACrE,OAAO;oBACL;wBACE,aAAa,EAAE,kBAAkB;wBACjC,UAAU,EAAE,KAAK,CAAC,EAAE;wBACpB,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW;wBAC9C,OAAO,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;qBACnC;iBACF,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;CACF"}