@agentclientprotocol/claude-agent-acp 0.89.2-preview.2 → 0.89.2-preview.21

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 (52) hide show
  1. package/README.md +51 -8
  2. package/dist/acp-agent.d.ts +131 -23
  3. package/dist/acp-agent.d.ts.map +1 -1
  4. package/dist/acp-agent.js +879 -239
  5. package/dist/acp-subagents.d.ts +16 -6
  6. package/dist/acp-subagents.d.ts.map +1 -1
  7. package/dist/acp-subagents.js +8 -2
  8. package/dist/async-tasks.d.ts +4 -1
  9. package/dist/async-tasks.d.ts.map +1 -1
  10. package/dist/auth-status.d.ts +2 -2
  11. package/dist/auth-status.d.ts.map +1 -1
  12. package/dist/auth-status.js +18 -4
  13. package/dist/exit-plan.d.ts +17 -0
  14. package/dist/exit-plan.d.ts.map +1 -1
  15. package/dist/exit-plan.js +34 -0
  16. package/dist/native-subagents.d.ts +190 -11
  17. package/dist/native-subagents.d.ts.map +1 -1
  18. package/dist/native-subagents.js +419 -40
  19. package/dist/settings.d.ts +6 -0
  20. package/dist/settings.d.ts.map +1 -1
  21. package/dist/settings.js +13 -0
  22. package/dist/subagent-history.d.ts +27 -2
  23. package/dist/subagent-history.d.ts.map +1 -1
  24. package/dist/subagent-history.js +38 -10
  25. package/dist/subagent-replay.d.ts +108 -0
  26. package/dist/subagent-replay.d.ts.map +1 -0
  27. package/dist/subagent-replay.js +261 -0
  28. package/dist/tool-calls/background.d.ts +9 -0
  29. package/dist/tool-calls/background.d.ts.map +1 -1
  30. package/dist/tool-calls/background.js +25 -0
  31. package/dist/tool-calls/renderer.d.ts +32 -7
  32. package/dist/tool-calls/renderer.d.ts.map +1 -1
  33. package/dist/tool-calls/renderer.js +54 -21
  34. package/dist/turn-events.d.ts +39 -17
  35. package/dist/turn-events.d.ts.map +1 -1
  36. package/dist/v2/agent.d.ts.map +1 -1
  37. package/dist/v2/agent.js +52 -14
  38. package/dist/v2/initialize.d.ts.map +1 -1
  39. package/dist/v2/initialize.js +10 -1
  40. package/dist/v2/prompt.d.ts +29 -18
  41. package/dist/v2/prompt.d.ts.map +1 -1
  42. package/dist/v2/prompt.js +54 -43
  43. package/dist/v2/session-update.d.ts +11 -0
  44. package/dist/v2/session-update.d.ts.map +1 -1
  45. package/dist/v2/session-update.js +67 -0
  46. package/dist/v2/session.d.ts +3 -12
  47. package/dist/v2/session.d.ts.map +1 -1
  48. package/dist/v2/session.js +5 -18
  49. package/dist/v2/tool-call-meta.d.ts +44 -0
  50. package/dist/v2/tool-call-meta.d.ts.map +1 -0
  51. package/dist/v2/tool-call-meta.js +72 -0
  52. package/package.json +1 -1
package/dist/v2/prompt.js CHANGED
@@ -8,27 +8,15 @@ import { RequestError, } from "@agentclientprotocol/sdk";
8
8
  import * as v2 from "@agentclientprotocol/sdk/experimental/v2";
9
9
  /**
10
10
  * Starts a turn for `params`, and answers when Claude Code takes the prompt
11
- * in. `send` delivers a session update of the prompt's session; it must not
12
- * throw, and must deliver updates in the order it is called, also relative to
13
- * the agent's own updates.
11
+ * in, with the id of the user message it became. `send` delivers a session
12
+ * update of the prompt's session; it must not throw, and must deliver updates
13
+ * in the order it is called, also relative to the agent's own updates.
14
14
  *
15
- * - Taken in: the prompt's `user_message`, then `running`, then the answer.
16
- * - Waiting on a permission request or a question: `requires_action`, and
17
- * `running` once none is open.
18
- * - Ended: `idle` with the stop reason, usage, and `_meta` of the turn.
19
- * - Failed after it was taken in: `idle` with the `error` stop reason and the
20
- * JSON-RPC error that v1 answers the prompt with, so a client can show its
21
- * message and handle its code as for an error response (for example,
22
- * `-32000` starts the client's sign-in).
15
+ * - Taken in: the prompt's `user_message`, then the answer. From then on, the
16
+ * turn is the session's foreground work, which reports its states (see
17
+ * {@link v2Foreground}).
23
18
  * - Ended or failed before it was taken in: the answer is a JSON-RPC error,
24
19
  * `-32800` for a prompt that a cancel ended in the queue.
25
- *
26
- * Deferred decision: a turn whose background subagents still run ends only
27
- * when they finish (`Turn.deferredSettle`), so `idle` waits for them too. The
28
- * hold exists for v1, whose clients stop listening at the prompt response.
29
- * v2 allows background updates while idle, so it could report `idle` at the
30
- * turn's result instead, with a turn event for the hold. To be decided with
31
- * async tasks (step 6 in `docs/acp-v2.md`).
32
20
  */
33
21
  export function v2Prompt(agent, params, send) {
34
22
  return new Promise((resolve, reject) => {
@@ -37,37 +25,18 @@ export function v2Prompt(agent, params, send) {
37
25
  inserted(messageId) {
38
26
  inserted = true;
39
27
  send({ sessionUpdate: "user_message", messageId, content: params.prompt });
40
- send({ sessionUpdate: "state_update", state: "running" });
41
28
  resolve({ messageId });
42
29
  },
43
- awaitingUser() {
44
- send({ sessionUpdate: "state_update", state: "requires_action" });
45
- },
46
- resumed() {
47
- send({ sessionUpdate: "state_update", state: "running" });
48
- },
49
30
  ended(outcome) {
50
- if (inserted) {
51
- send(idle(outcome));
52
- }
53
- else if (outcome.stopReason === "cancelled") {
54
- reject(RequestError.requestCancelled());
55
- }
56
- else {
57
- reject(RequestError.internalError({ stopReason: outcome.stopReason }, "The turn ended before Claude Code took the prompt in"));
58
- }
31
+ if (inserted)
32
+ return;
33
+ reject(outcome.stopReason === "cancelled"
34
+ ? RequestError.requestCancelled()
35
+ : RequestError.internalError({ stopReason: outcome.stopReason }, "The turn ended before Claude Code took the prompt in"));
59
36
  },
60
37
  failed(error) {
61
- if (!inserted) {
38
+ if (!inserted)
62
39
  reject(error);
63
- return;
64
- }
65
- send({
66
- sessionUpdate: "state_update",
67
- state: "idle",
68
- stopReason: "error",
69
- error: jsonRpcError(error),
70
- });
71
40
  },
72
41
  };
73
42
  let request;
@@ -81,6 +50,48 @@ export function v2Prompt(agent, params, send) {
81
50
  agent.startTurn(request, events).catch(reject);
82
51
  });
83
52
  }
53
+ /**
54
+ * Reports the foreground work of a session (see {@link ForegroundEvents}) as
55
+ * its `state_update`s. `send` delivers a session update of that session, as
56
+ * for {@link v2Prompt}.
57
+ *
58
+ * - Started: `running`. For a prompt's turn, right after its `user_message`.
59
+ * - Waiting on a permission request or a question: `requires_action`, and
60
+ * `running` once none is open.
61
+ * - Ended: `idle` with the stop reason, usage, and `_meta` of the work.
62
+ * - Failed: `idle` with the `error` stop reason and the JSON-RPC error that v1
63
+ * answers the prompt with, so a client can show its message and handle its
64
+ * code as for an error response (for example, `-32000` starts the client's
65
+ * sign-in).
66
+ *
67
+ * The work is a prompt's turn or a model cycle that Claude Code started on its
68
+ * own, such as its follow-up after a background subagent finished. A turn's
69
+ * work ends at its result, also when v1 holds the turn's answer for the
70
+ * background subagents it spawned (`Turn.deferredSettle`): v2 allows
71
+ * background updates while idle, so the subagents' output and requests arrive
72
+ * after `idle`, and their follow-up is a cycle of its own.
73
+ */
74
+ export function v2Foreground(send) {
75
+ return {
76
+ running() {
77
+ send({ sessionUpdate: "state_update", state: "running" });
78
+ },
79
+ awaitingUser() {
80
+ send({ sessionUpdate: "state_update", state: "requires_action" });
81
+ },
82
+ ended(outcome) {
83
+ send(idle(outcome));
84
+ },
85
+ failed(error) {
86
+ send({
87
+ sessionUpdate: "state_update",
88
+ state: "idle",
89
+ stopReason: "error",
90
+ error: jsonRpcError(error),
91
+ });
92
+ },
93
+ };
94
+ }
84
95
  /** The JSON-RPC error that v1 answers a failed prompt with. */
85
96
  function jsonRpcError(error) {
86
97
  if (error instanceof RequestError) {
@@ -18,4 +18,15 @@ export declare const SESSION_PLAN_ID = "plan";
18
18
  * an error rather than a silently missing update.
19
19
  */
20
20
  export declare function v2SessionUpdate(update: AcpSessionNotification["update"]): v2.SessionUpdate | undefined;
21
+ /**
22
+ * The child's own `state_update` for a v1 `subagent_update` that reports the
23
+ * child's work state, or `undefined` when it reports none.
24
+ *
25
+ * v1 reports a child's work state only on its parent, as the `state` of the
26
+ * `subagent_update`. v2 reports it on the child's own stream, as for any
27
+ * session, and mirrors it on the parent (the subagents RFD). The child's copy
28
+ * goes right after the parent's: never before the announcement, and both
29
+ * copies of a state before any later state.
30
+ */
31
+ export declare function v2ChildStateUpdate(update: AcpSessionNotification["update"]): v2.UpdateSessionNotification | undefined;
21
32
  //# sourceMappingURL=session-update.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-update.d.ts","sourceRoot":"","sources":["../../src/v2/session-update.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAC/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAIlE;;;;GAIG;AACH,eAAO,MAAM,eAAe,SAAS,CAAC;AAEtC;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GACvC,EAAE,CAAC,aAAa,GAAG,SAAS,CA0C9B"}
1
+ {"version":3,"file":"session-update.d.ts","sourceRoot":"","sources":["../../src/v2/session-update.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAC/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAIlE;;;;GAIG;AACH,eAAO,MAAM,eAAe,SAAS,CAAC;AAEtC;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GACvC,EAAE,CAAC,aAAa,GAAG,SAAS,CAyD9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GACvC,EAAE,CAAC,yBAAyB,GAAG,SAAS,CAM1C"}
@@ -45,6 +45,21 @@ export function v2SessionUpdate(update) {
45
45
  plan: { type: "items", planId: SESSION_PLAN_ID, entries: update.entries },
46
46
  ...(update._meta != null ? { _meta: update._meta } : {}),
47
47
  };
48
+ case "plan_update":
49
+ case "plan_removed":
50
+ // v1's draft plan operations have v2's shape.
51
+ return update;
52
+ case "subagent_update": {
53
+ // The subagents RFD gives it the same shape in v1 and v2. One that
54
+ // reports a state also has a copy on the child's stream (see
55
+ // `v2ChildStateUpdate`).
56
+ const { state, ...association } = update;
57
+ return { ...association, ...(state != null ? { state: v2SubagentState(state) } : {}) };
58
+ }
59
+ case "session_message":
60
+ case "session_message_chunk":
61
+ // The subagents RFD gives these the same shape in v1 and v2.
62
+ return update;
48
63
  case "current_mode_update":
49
64
  // v2 has no modes: the mode is the `mode` config option. Every mode
50
65
  // change also reaches the client as a `config_option_update` or in the
@@ -54,3 +69,55 @@ export function v2SessionUpdate(update) {
54
69
  throw new Error(`The ACP v2 surface does not translate ${update.sessionUpdate} session updates yet`);
55
70
  }
56
71
  }
72
+ /**
73
+ * The child's own `state_update` for a v1 `subagent_update` that reports the
74
+ * child's work state, or `undefined` when it reports none.
75
+ *
76
+ * v1 reports a child's work state only on its parent, as the `state` of the
77
+ * `subagent_update`. v2 reports it on the child's own stream, as for any
78
+ * session, and mirrors it on the parent (the subagents RFD). The child's copy
79
+ * goes right after the parent's: never before the announcement, and both
80
+ * copies of a state before any later state.
81
+ */
82
+ export function v2ChildStateUpdate(update) {
83
+ if (update.sessionUpdate !== "subagent_update" || update.state == null)
84
+ return undefined;
85
+ return {
86
+ sessionId: update.sessionId,
87
+ update: { sessionUpdate: "state_update", ...v2SubagentState(update.state) },
88
+ };
89
+ }
90
+ /** The work states of the subagents RFD, and the stop reasons of its `idle`. */
91
+ const SUBAGENT_STATES = new Set([
92
+ "running",
93
+ "requires_action",
94
+ "unknown",
95
+ "idle",
96
+ ]);
97
+ const IDLE_STOP_REASONS = new Set([
98
+ undefined,
99
+ null,
100
+ "end_turn",
101
+ "max_tokens",
102
+ "max_turn_requests",
103
+ "refusal",
104
+ "cancelled",
105
+ "error",
106
+ ]);
107
+ /**
108
+ * The v2 form of a subagent's v1 work state.
109
+ *
110
+ * The RFD's states have the same shape in v1 and v2. Each version also types
111
+ * an open member for states and stop reasons it does not know, and those two
112
+ * members are typed apart. So the state is checked to be one of the RFD's, and
113
+ * any other throws, as an update kind that this surface does not translate
114
+ * does.
115
+ */
116
+ function v2SubagentState(state) {
117
+ const stopReason = state.stopReason;
118
+ if (!SUBAGENT_STATES.has(state.state) ||
119
+ (state.state === "idle" && !IDLE_STOP_REASONS.has(stopReason))) {
120
+ throw new Error(`The ACP v2 surface does not translate the subagent state ${state.state}${state.state === "idle" ? ` with the stop reason ${String(stopReason)}` : ""}`);
121
+ }
122
+ return state;
123
+ }
@@ -23,19 +23,10 @@ export declare function v1RestoreSessionRequest(params: v2.ResumeSessionRequest)
23
23
  request: LoadSessionRequest;
24
24
  };
25
25
  /**
26
- * The v1 requests that a v2 `session/fork` means.
27
- *
28
- * The agent's v1 fork copies the transcript into a new session and returns
29
- * only its id; a v1 client then resumes or loads it. A v2 fork returns the new
30
- * session with its config options, like `session/new`, so the client can
31
- * prompt it. The v2 surface therefore forks, then resumes the fork without
32
- * replay, with the request's `cwd`, `additionalDirectories`, and
33
- * `mcpServers`. The request's `_meta` goes to the fork alone.
26
+ * The v1 request of a v2 `session/fork`. In both versions the agent's fork
27
+ * returns a session that the client can prompt, with its config options.
34
28
  */
35
- export declare function v1ForkSessionRequests(params: v2.ForkSessionRequest): {
36
- fork: ForkSessionRequest;
37
- resume: (sessionId: string) => ResumeSessionRequest;
38
- };
29
+ export declare function v1ForkSessionRequest(params: v2.ForkSessionRequest): ForkSessionRequest;
39
30
  /** v2 drops `modes`: the session mode is the `mode` config option, which the agent always lists. */
40
31
  export declare function v2NewSessionResponse(response: NewSessionResponse): v2.NewSessionResponse;
41
32
  export declare function v2ResumeSessionResponse(response: ResumeSessionResponse): v2.ResumeSessionResponse;
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/v2/session.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAEvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EAGxB,KAAK,6BAA6B,EACnC,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAE/D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,iBAAiB,GAAG,iBAAiB,CAInF;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,EAAE,CAAC,oBAAoB,GAE7B;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAkBlD;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,EAAE,CAAC,kBAAkB,GAAG;IACpE,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,oBAAoB,CAAC;CACrD,CAUA;AAED,oGAAoG;AACpG,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,EAAE,CAAC,kBAAkB,CAExF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,EAAE,CAAC,qBAAqB,CAKjG;AAED,uEAAuE;AACvE,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,EAAE,CAAC,6BAA6B,GACvC,6BAA6B,CAgB/B;AAED,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAQxF;AAWD,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAKvF"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/v2/session.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAEvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EAGxB,KAAK,6BAA6B,EACnC,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAE/D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,iBAAiB,GAAG,iBAAiB,CAInF;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,EAAE,CAAC,oBAAoB,GAE7B;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAkBlD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,kBAAkB,GAAG,kBAAkB,CAGtF;AAED,oGAAoG;AACpG,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,EAAE,CAAC,kBAAkB,CAExF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,EAAE,CAAC,qBAAqB,CAKjG;AAED,uEAAuE;AACvE,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,EAAE,CAAC,6BAA6B,GACvC,6BAA6B,CAgB/B;AAED,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAQxF;AAWD,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAKvF"}
@@ -36,25 +36,12 @@ export function v1RestoreSessionRequest(params) {
36
36
  };
37
37
  }
38
38
  /**
39
- * The v1 requests that a v2 `session/fork` means.
40
- *
41
- * The agent's v1 fork copies the transcript into a new session and returns
42
- * only its id; a v1 client then resumes or loads it. A v2 fork returns the new
43
- * session with its config options, like `session/new`, so the client can
44
- * prompt it. The v2 surface therefore forks, then resumes the fork without
45
- * replay, with the request's `cwd`, `additionalDirectories`, and
46
- * `mcpServers`. The request's `_meta` goes to the fork alone.
39
+ * The v1 request of a v2 `session/fork`. In both versions the agent's fork
40
+ * returns a session that the client can prompt, with its config options.
47
41
  */
48
- export function v1ForkSessionRequests(params) {
49
- const { mcpServers, _meta, ...request } = params;
50
- const session = {
51
- ...request,
52
- ...(mcpServers ? { mcpServers: mcpServers.map(v1McpServer) } : {}),
53
- };
54
- return {
55
- fork: { ...session, ...(_meta != null ? { _meta } : {}) },
56
- resume: (sessionId) => ({ ...session, sessionId }),
57
- };
42
+ export function v1ForkSessionRequest(params) {
43
+ const { mcpServers, ...request } = params;
44
+ return { ...request, ...(mcpServers ? { mcpServers: mcpServers.map(v1McpServer) } : {}) };
58
45
  }
59
46
  /** v2 drops `modes`: the session mode is the `mode` config option, which the agent always lists. */
60
47
  export function v2NewSessionResponse(response) {
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The `_meta` of the tool calls of one ACP v2 connection, as the client stores
3
+ * it.
4
+ *
5
+ * The agent gives each v1 tool call report the `_meta` keys of that report.
6
+ * An AIR client merges them by key (see `ToolCallFieldTracker`), and another
7
+ * v1 client reads them per report. A v2 client stores a tool call's `_meta`,
8
+ * and a report that carries `_meta` replaces it. So the earlier keys must
9
+ * travel again, or the `{ toolName }` of a tool's result would replace, for
10
+ * example, the reason of the denial before it.
11
+ *
12
+ * {@link V2ToolCallMeta} therefore keeps the merged `_meta` of each tool call,
13
+ * with the `claudeCode` keys merged one by one and every other key replaced
14
+ * whole, as `ToolCallFieldTracker` models it. A report that changes it carries
15
+ * all of it; a report that changes nothing carries no `_meta`.
16
+ *
17
+ * `claudeCode.toolName` repeats the name of the tool, which v2 has a field
18
+ * for. It becomes the `name` of a tool call that has none yet, and is left out
19
+ * of the stored `_meta`. Subagent routing reads it before this, on the agent's
20
+ * v1 reports.
21
+ */
22
+ import type { ToolCall, ToolCallUpdate } from "@agentclientprotocol/sdk";
23
+ export declare class V2ToolCallMeta {
24
+ /** The stored `_meta` of each tool call, by session and tool call, oldest first. */
25
+ private readonly calls;
26
+ /**
27
+ * `report` with the tool call's whole `_meta` when the report changes it,
28
+ * without `_meta` when it does not, and with `name` when it names the tool
29
+ * call for the first time. `starts` says that the report starts the tool
30
+ * call (a v1 `tool_call`), which forgets what an earlier one stored.
31
+ */
32
+ apply<Report extends ToolCall | ToolCallUpdate>(sessionId: string, report: Report, starts: boolean): Report;
33
+ /**
34
+ * The tool call of a permission request's subject: like {@link apply}, but
35
+ * with the tool call's whole `_meta` even when the subject changes nothing,
36
+ * since a client can show the request from the request alone.
37
+ */
38
+ subject<Report extends ToolCall | ToolCallUpdate>(sessionId: string, toolCall: Report): Report;
39
+ /** Forgets the tool calls of a session, when it closes. */
40
+ forget(sessionId: string): void;
41
+ /** Stores the entry as the most recent one, and forgets the oldest one past the limit. */
42
+ private remember;
43
+ }
44
+ //# sourceMappingURL=tool-call-meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-call-meta.d.ts","sourceRoot":"","sources":["../../src/v2/tool-call-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAOzE,qBAAa,cAAc;IACzB,oFAAoF;IACpF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqD;IAE3E;;;;;OAKG;IACH,KAAK,CAAC,MAAM,SAAS,QAAQ,GAAG,cAAc,EAC5C,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,GACd,MAAM;IA6BT;;;;OAIG;IACH,OAAO,CAAC,MAAM,SAAS,QAAQ,GAAG,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAO9F,2DAA2D;IAC3D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAM/B,0FAA0F;IAC1F,OAAO,CAAC,QAAQ;CAQjB"}
@@ -0,0 +1,72 @@
1
+ /** The number of tool calls whose `_meta` a connection remembers. */
2
+ const TOOL_CALL_LIMIT = 2048;
3
+ export class V2ToolCallMeta {
4
+ /** The stored `_meta` of each tool call, by session and tool call, oldest first. */
5
+ calls = new Map();
6
+ /**
7
+ * `report` with the tool call's whole `_meta` when the report changes it,
8
+ * without `_meta` when it does not, and with `name` when it names the tool
9
+ * call for the first time. `starts` says that the report starts the tool
10
+ * call (a v1 `tool_call`), which forgets what an earlier one stored.
11
+ */
12
+ apply(sessionId, report, starts) {
13
+ const key = `${sessionId} ${report.toolCallId}`;
14
+ const call = (!starts && this.calls.get(key)) || { meta: {}, named: false };
15
+ this.remember(key, call);
16
+ const { _meta, ...fields } = report;
17
+ const result = fields;
18
+ const { toolName, ...claudeCode } = asRecord(_meta?.claudeCode) ?? {};
19
+ if (report.name != null) {
20
+ call.named = true;
21
+ }
22
+ else if (!call.named && typeof toolName === "string") {
23
+ result.name = toolName;
24
+ call.named = true;
25
+ }
26
+ const meta = { ...call.meta };
27
+ for (const [name, value] of Object.entries(_meta ?? {})) {
28
+ if (name !== "claudeCode")
29
+ meta[name] = value;
30
+ }
31
+ if (Object.keys(claudeCode).length > 0) {
32
+ meta.claudeCode = { ...asRecord(call.meta.claudeCode), ...claudeCode };
33
+ }
34
+ if (JSON.stringify(meta) !== JSON.stringify(call.meta)) {
35
+ call.meta = meta;
36
+ result._meta = meta;
37
+ }
38
+ return result;
39
+ }
40
+ /**
41
+ * The tool call of a permission request's subject: like {@link apply}, but
42
+ * with the tool call's whole `_meta` even when the subject changes nothing,
43
+ * since a client can show the request from the request alone.
44
+ */
45
+ subject(sessionId, toolCall) {
46
+ const result = this.apply(sessionId, toolCall, false);
47
+ const stored = this.calls.get(`${sessionId} ${toolCall.toolCallId}`)?.meta ?? {};
48
+ if (result._meta === undefined && Object.keys(stored).length > 0)
49
+ result._meta = stored;
50
+ return result;
51
+ }
52
+ /** Forgets the tool calls of a session, when it closes. */
53
+ forget(sessionId) {
54
+ for (const key of this.calls.keys()) {
55
+ if (key.startsWith(`${sessionId} `))
56
+ this.calls.delete(key);
57
+ }
58
+ }
59
+ /** Stores the entry as the most recent one, and forgets the oldest one past the limit. */
60
+ remember(key, call) {
61
+ this.calls.delete(key);
62
+ this.calls.set(key, call);
63
+ if (this.calls.size > TOOL_CALL_LIMIT) {
64
+ const oldest = this.calls.keys().next().value;
65
+ if (oldest !== undefined)
66
+ this.calls.delete(oldest);
67
+ }
68
+ }
69
+ }
70
+ function asRecord(value) {
71
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
72
+ }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.89.2-preview.2",
6
+ "version": "0.89.2-preview.21",
7
7
  "description": "An ACP-compatible coding agent powered by the Claude Agent SDK (TypeScript)",
8
8
  "main": "dist/lib.js",
9
9
  "types": "dist/lib.d.ts",