@agentclientprotocol/claude-agent-acp 0.81.2 → 0.81.3-preview.2
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.
- package/README.md +8 -5
- package/dist/acp-agent.d.ts +32 -40
- package/dist/acp-agent.d.ts.map +1 -1
- package/dist/acp-agent.js +557 -577
- package/dist/acp-subagents.d.ts +6 -0
- package/dist/acp-subagents.d.ts.map +1 -1
- package/dist/air-extension.d.ts +31 -1
- package/dist/air-extension.d.ts.map +1 -1
- package/dist/air-extension.js +35 -1
- package/dist/async-tasks.d.ts +39 -2
- package/dist/async-tasks.d.ts.map +1 -1
- package/dist/async-tasks.js +147 -44
- package/dist/context-compaction-meta.d.ts +6 -5
- package/dist/context-compaction-meta.d.ts.map +1 -1
- package/dist/context-compaction-meta.js +10 -10
- package/dist/context-compaction.d.ts +3 -0
- package/dist/context-compaction.d.ts.map +1 -1
- package/dist/context-compaction.js +23 -57
- package/dist/diff.d.ts +73 -5
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +435 -64
- package/dist/elicitation.d.ts +1 -1
- package/dist/elicitation.d.ts.map +1 -1
- package/dist/elicitation.js +12 -14
- package/dist/hide-claude-auth.d.ts +2 -6
- package/dist/hide-claude-auth.d.ts.map +1 -1
- package/dist/hide-claude-auth.js +3 -21
- package/dist/native-subagents.d.ts +58 -0
- package/dist/native-subagents.d.ts.map +1 -1
- package/dist/native-subagents.js +186 -34
- package/dist/paths.d.ts +3 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +6 -0
- package/dist/permissions/presentation.d.ts +13 -2
- package/dist/permissions/presentation.d.ts.map +1 -1
- package/dist/permissions/presentation.js +49 -44
- package/dist/resumed-session.d.ts +11 -0
- package/dist/resumed-session.d.ts.map +1 -1
- package/dist/resumed-session.js +106 -4
- package/dist/session-failure-extension.js +1 -1
- package/dist/session-mode.d.ts +2 -0
- package/dist/session-mode.d.ts.map +1 -1
- package/dist/session-mode.js +12 -5
- package/dist/settings.js +2 -2
- package/dist/subagent-history.d.ts +20 -0
- package/dist/subagent-history.d.ts.map +1 -0
- package/dist/subagent-history.js +46 -0
- package/dist/tool-calls/background.d.ts +20 -0
- package/dist/tool-calls/background.d.ts.map +1 -0
- package/dist/tool-calls/background.js +41 -0
- package/dist/tool-calls/changed-meta-filter.d.ts +27 -0
- package/dist/tool-calls/changed-meta-filter.d.ts.map +1 -0
- package/dist/tool-calls/changed-meta-filter.js +102 -0
- package/dist/tool-calls/client-capabilities.d.ts +51 -0
- package/dist/tool-calls/client-capabilities.d.ts.map +1 -0
- package/dist/tool-calls/client-capabilities.js +43 -0
- package/dist/tool-calls/content.d.ts +59 -0
- package/dist/tool-calls/content.d.ts.map +1 -0
- package/dist/tool-calls/content.js +194 -0
- package/dist/tool-calls/facts.d.ts +116 -0
- package/dist/tool-calls/facts.d.ts.map +1 -0
- package/dist/tool-calls/facts.js +1 -0
- package/dist/tool-calls/field-tracker.d.ts +58 -0
- package/dist/tool-calls/field-tracker.d.ts.map +1 -0
- package/dist/tool-calls/field-tracker.js +167 -0
- package/dist/tool-calls/renderer.d.ts +216 -0
- package/dist/tool-calls/renderer.d.ts.map +1 -0
- package/dist/tool-calls/renderer.js +487 -0
- package/dist/tool-calls/reporters/agent.d.ts +7 -0
- package/dist/tool-calls/reporters/agent.d.ts.map +1 -0
- package/dist/tool-calls/reporters/agent.js +190 -0
- package/dist/tool-calls/reporters/bash.d.ts +9 -0
- package/dist/tool-calls/reporters/bash.d.ts.map +1 -0
- package/dist/tool-calls/reporters/bash.js +83 -0
- package/dist/tool-calls/reporters/compaction.d.ts +24 -0
- package/dist/tool-calls/reporters/compaction.d.ts.map +1 -0
- package/dist/tool-calls/reporters/compaction.js +66 -0
- package/dist/tool-calls/reporters/file-edit.d.ts +46 -0
- package/dist/tool-calls/reporters/file-edit.d.ts.map +1 -0
- package/dist/tool-calls/reporters/file-edit.js +180 -0
- package/dist/tool-calls/reporters/index.d.ts +4 -0
- package/dist/tool-calls/reporters/index.d.ts.map +1 -0
- package/dist/tool-calls/reporters/index.js +40 -0
- package/dist/tool-calls/reporters/interaction.d.ts +71 -0
- package/dist/tool-calls/reporters/interaction.d.ts.map +1 -0
- package/dist/tool-calls/reporters/interaction.js +222 -0
- package/dist/tool-calls/reporters/read.d.ts +7 -0
- package/dist/tool-calls/reporters/read.d.ts.map +1 -0
- package/dist/tool-calls/reporters/read.js +64 -0
- package/dist/tool-calls/reporters/search.d.ts +10 -0
- package/dist/tool-calls/reporters/search.d.ts.map +1 -0
- package/dist/tool-calls/reporters/search.js +50 -0
- package/dist/tool-calls/reporters/web.d.ts +11 -0
- package/dist/tool-calls/reporters/web.d.ts.map +1 -0
- package/dist/tool-calls/reporters/web.js +42 -0
- package/dist/tools.d.ts +32 -37
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +48 -970
- package/package.json +4 -1
package/dist/hide-claude-auth.js
CHANGED
|
@@ -158,8 +158,7 @@ export function warnClaudeSubscriptionGuardDegraded(options) {
|
|
|
158
158
|
* mid-session. The refusal mirrors the signed-out path exactly (see
|
|
159
159
|
* `failActiveWithSessionFailure` for `auth_required` in `acp-agent.ts`): every
|
|
160
160
|
* client gets the `authRequired` JSON-RPC rejection that starts its own auth
|
|
161
|
-
* flow
|
|
162
|
-
* failure whose `login` action stays the way back in.
|
|
161
|
+
* flow. The guard sends no separate access message.
|
|
163
162
|
*
|
|
164
163
|
* Fails open when no account can be read at all: session creation already
|
|
165
164
|
* refused every account without a usable credential, and an unavailable probe
|
|
@@ -179,8 +178,8 @@ export async function refuseClaudeSubscriptionTurn(options) {
|
|
|
179
178
|
throw refusal;
|
|
180
179
|
}
|
|
181
180
|
}
|
|
182
|
-
/** Read the account
|
|
183
|
-
*
|
|
181
|
+
/** Read the account and return the error for the refused turn.
|
|
182
|
+
* Never throws: an unreadable account fails open. */
|
|
184
183
|
async function evaluateGuard(options) {
|
|
185
184
|
const account = await readGuardAccount(options);
|
|
186
185
|
if (!account) {
|
|
@@ -195,14 +194,9 @@ async function evaluateGuard(options) {
|
|
|
195
194
|
options.logger.error(`Session ${options.sessionId}: the guard's onAccount hook threw:`, error instanceof Error ? error.message : String(error));
|
|
196
195
|
}
|
|
197
196
|
if (billsClaudeSubscription(account)) {
|
|
198
|
-
await publishRefusal(options.sessionFailures(), {
|
|
199
|
-
details: CLAUDE_SUBSCRIPTION_NOT_SUPPORTED_MESSAGE,
|
|
200
|
-
reason: CLAUDE_SUBSCRIPTION_NOT_SUPPORTED_REASON,
|
|
201
|
-
});
|
|
202
197
|
return claudeSubscriptionNotSupportedError();
|
|
203
198
|
}
|
|
204
199
|
if (!holdsNonSubscriptionCredential(account)) {
|
|
205
|
-
await publishRefusal(options.sessionFailures(), { details: CLAUDE_LOGIN_REQUIRED_MESSAGE });
|
|
206
200
|
return claudeLoginRequiredError();
|
|
207
201
|
}
|
|
208
202
|
return undefined;
|
|
@@ -226,15 +220,3 @@ async function readGuardAccount(options) {
|
|
|
226
220
|
return undefined;
|
|
227
221
|
}
|
|
228
222
|
}
|
|
229
|
-
/** The refusal state does not change between turns: publish once, and skip a
|
|
230
|
-
* republish while the previous failure with this reason is still active. */
|
|
231
|
-
async function publishRefusal(sessionFailures, failure) {
|
|
232
|
-
if (sessionFailures.hasActiveSessionError("auth_required", failure.reason)) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
await sessionFailures.publish("auth_required", {
|
|
236
|
-
sessionScoped: true,
|
|
237
|
-
details: failure.details,
|
|
238
|
-
...(failure.reason ? { reason: failure.reason } : {}),
|
|
239
|
-
});
|
|
240
|
-
}
|
|
@@ -5,6 +5,11 @@ export type NativeSubagent = {
|
|
|
5
5
|
parentToolUseId?: string;
|
|
6
6
|
name: string;
|
|
7
7
|
task: string;
|
|
8
|
+
/**
|
|
9
|
+
* The exact prompt of this generation, sent as `prompt` in
|
|
10
|
+
* `subagent_spawned`. It is absent when the adapter has no prompt.
|
|
11
|
+
*/
|
|
12
|
+
prompt?: string;
|
|
8
13
|
announced?: boolean;
|
|
9
14
|
terminalState?: SubagentState;
|
|
10
15
|
/** Connection-local single-flight state; never serialized on the wire. */
|
|
@@ -44,6 +49,12 @@ export declare class NativeSubagentRuntime {
|
|
|
44
49
|
private readonly identityByToolUse;
|
|
45
50
|
private readonly controlByToolUse;
|
|
46
51
|
private readonly childByParentToolUse;
|
|
52
|
+
/**
|
|
53
|
+
* The child session of each tool call that went to a child session. A later
|
|
54
|
+
* update of that tool call can lose `parentToolUseId`, for example a progress
|
|
55
|
+
* beat after the child finished. It still belongs to the child session.
|
|
56
|
+
*/
|
|
57
|
+
private readonly childByToolCall;
|
|
47
58
|
private readonly taskFinishPromises;
|
|
48
59
|
private readonly generationByTaskId;
|
|
49
60
|
private readonly pending;
|
|
@@ -51,18 +62,65 @@ export declare class NativeSubagentRuntime {
|
|
|
51
62
|
constructor(enabled: boolean, rootSessionId: string, session: NativeSubagentSession, publish: Publish, logger: Logger);
|
|
52
63
|
route(notification: AcpSessionNotification, deliver: Publish, forcedSessionId?: string): Promise<AcpSessionNotification | null>;
|
|
53
64
|
taskStarted(task: TaskStarted, deliver: Publish): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Opens a new generation of a finished child when the SDK resumes the same
|
|
67
|
+
* agent id. The SDK can resume a child without a new `task_started`, so a
|
|
68
|
+
* running `task_updated` patch or a SendMessage `resumedAgentId` is the
|
|
69
|
+
* signal. A child that did not finish is not changed. The `prompt` is the
|
|
70
|
+
* SendMessage text that resumed the child, when the adapter knows it.
|
|
71
|
+
*/
|
|
72
|
+
taskResumed(taskId: string, deliver: Publish, prompt?: string): Promise<void>;
|
|
54
73
|
finishTask(taskId: string, status: unknown, deliver: Publish, toolUseId?: string | null): Promise<void>;
|
|
55
74
|
finishAll(state: SubagentState, deliver: Publish): Promise<void>;
|
|
56
75
|
discardPending(parentToolUseId: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* Routes an update to the child session. An update of a finished child is
|
|
78
|
+
* dropped: it never goes to the root session.
|
|
79
|
+
*/
|
|
80
|
+
private toChild;
|
|
81
|
+
/**
|
|
82
|
+
* The route of the work that a child tool call started, for example an async
|
|
83
|
+
* task. The route sends each update to the child generation that owned the
|
|
84
|
+
* tool call when the work started, and drops the update after that child
|
|
85
|
+
* finished. `undefined` means that the root session owns the tool call.
|
|
86
|
+
* `eagerSessionId` is the session where a permission request created the
|
|
87
|
+
* tool call before the stream routed it.
|
|
88
|
+
*/
|
|
89
|
+
routeOfToolCall(toolCallId: string, eagerSessionId?: string): ((notification: AcpSessionNotification) => AcpSessionNotification | null) | undefined;
|
|
90
|
+
private rememberToolCallOwner;
|
|
91
|
+
/** The child generation with the ACP session `sessionId`, if one exists. */
|
|
92
|
+
private childOfSession;
|
|
57
93
|
clear(): void;
|
|
58
94
|
private takePending;
|
|
59
95
|
private buffer;
|
|
60
96
|
private cleanupControl;
|
|
97
|
+
/** The parent of a resumed generation: the old parent while it is live, else the root. */
|
|
98
|
+
private resumedParentSessionId;
|
|
61
99
|
private isLiveSession;
|
|
100
|
+
/**
|
|
101
|
+
* Registers a new child session for the task and makes it the owner of its
|
|
102
|
+
* parent tool call. With `announce`, it publishes `subagent_spawned` and
|
|
103
|
+
* delivers the updates that waited for the child.
|
|
104
|
+
*/
|
|
105
|
+
private openGeneration;
|
|
62
106
|
private nextChildSessionId;
|
|
63
107
|
}
|
|
64
108
|
export declare function announceNativeSubagent(child: NativeSubagent, publish: Publish): Promise<void>;
|
|
65
109
|
export declare function finishNativeSubagent(session: NativeSubagentSession, taskId: string, state: SubagentState, publish: Publish): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* The agent id that a successful SendMessage result resumed. The SDK puts it
|
|
112
|
+
* in `tool_use_result.resumedAgentId` when a finished agent runs again.
|
|
113
|
+
*/
|
|
114
|
+
export declare function resumedNativeSubagentId(toolUseResult: unknown): string | undefined;
|
|
115
|
+
/**
|
|
116
|
+
* The SendMessage text that resumed the agent `agentId`. The tool uses of
|
|
117
|
+
* `resultToolUseIds` come first: they are the SendMessage calls whose result
|
|
118
|
+
* carried the resume. Otherwise the latest SendMessage call to `agentId` counts.
|
|
119
|
+
*/
|
|
120
|
+
export declare function sendMessageResumePrompt(toolUses: Record<string, {
|
|
121
|
+
name: string;
|
|
122
|
+
input: unknown;
|
|
123
|
+
} | undefined>, agentId: string, resultToolUseIds?: readonly string[]): string | undefined;
|
|
66
124
|
export declare function nativeSubagentState(status: unknown): SubagentState | undefined;
|
|
67
125
|
export declare function isNativeSubagentControlUpdate(update: AcpSessionNotification["update"]): update is Extract<AcpSessionNotification["update"], {
|
|
68
126
|
sessionUpdate: "tool_call" | "tool_call_update";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-subagents.d.ts","sourceRoot":"","sources":["../src/native-subagents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"native-subagents.d.ts","sourceRoot":"","sources":["../src/native-subagents.ts"],"names":[],"mappings":"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"}
|
package/dist/native-subagents.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { AIR_SUBAGENT_KEY, airExtensionMeta } from "./air-extension.js";
|
|
1
2
|
const MAX_PENDING_PARENTS = 64;
|
|
2
3
|
const MAX_PENDING_UPDATES = 256;
|
|
3
4
|
const MAX_PENDING_UPDATES_PER_PARENT = 32;
|
|
5
|
+
/** The number of child tool calls whose owning child session the runtime remembers. */
|
|
6
|
+
const MAX_CHILD_TOOL_CALLS = 2048;
|
|
4
7
|
/**
|
|
5
8
|
* Owns the connection-local native subagent registry and all ACP lifecycle
|
|
6
9
|
* ordering. The main agent only supplies SDK facts and delivers routed output.
|
|
@@ -17,6 +20,12 @@ export class NativeSubagentRuntime {
|
|
|
17
20
|
identityByToolUse = new Map();
|
|
18
21
|
controlByToolUse = new Map();
|
|
19
22
|
childByParentToolUse = new Map();
|
|
23
|
+
/**
|
|
24
|
+
* The child session of each tool call that went to a child session. A later
|
|
25
|
+
* update of that tool call can lose `parentToolUseId`, for example a progress
|
|
26
|
+
* beat after the child finished. It still belongs to the child session.
|
|
27
|
+
*/
|
|
28
|
+
childByToolCall = new Map();
|
|
20
29
|
taskFinishPromises = new Map();
|
|
21
30
|
generationByTaskId = new Map();
|
|
22
31
|
pending = new Map();
|
|
@@ -74,23 +83,29 @@ export class NativeSubagentRuntime {
|
|
|
74
83
|
}
|
|
75
84
|
return forcedSessionId ? { ...notification, sessionId: forcedSessionId } : null;
|
|
76
85
|
}
|
|
86
|
+
const toolCallId = update.sessionUpdate === "tool_call" || update.sessionUpdate === "tool_call_update"
|
|
87
|
+
? update.toolCallId
|
|
88
|
+
: undefined;
|
|
77
89
|
// A permission request may have had to create the tool call before native
|
|
78
90
|
// child ownership was known. Keep every later update in that original ACP
|
|
79
91
|
// session; moving a lifecycle after its initial call creates an orphan in
|
|
80
92
|
// both transcripts.
|
|
81
|
-
if (forcedSessionId)
|
|
93
|
+
if (forcedSessionId) {
|
|
94
|
+
const forcedChild = this.childOfSession(forcedSessionId);
|
|
95
|
+
if (toolCallId && forcedChild)
|
|
96
|
+
this.rememberToolCallOwner(toolCallId, forcedChild);
|
|
82
97
|
return { ...notification, sessionId: forcedSessionId };
|
|
98
|
+
}
|
|
99
|
+
const owner = toolCallId ? this.childByToolCall.get(toolCallId) : undefined;
|
|
100
|
+
if (owner)
|
|
101
|
+
return this.toChild(owner, notification, toolCallId);
|
|
83
102
|
if (this.enabled && claudeMeta?.parentToolUseId) {
|
|
84
103
|
const child = this.childByParentToolUse.get(claudeMeta.parentToolUseId);
|
|
85
104
|
if (!child || !child.announced) {
|
|
86
105
|
this.buffer(claudeMeta.parentToolUseId, notification);
|
|
87
106
|
return null;
|
|
88
107
|
}
|
|
89
|
-
|
|
90
|
-
this.logger.log(`Session ${this.rootSessionId}: ignoring late update for terminal subagent ${child.sessionId}`);
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
return { ...notification, sessionId: child.sessionId };
|
|
108
|
+
return this.toChild(child, notification, toolCallId);
|
|
94
109
|
}
|
|
95
110
|
return notification;
|
|
96
111
|
}
|
|
@@ -108,36 +123,45 @@ export class NativeSubagentRuntime {
|
|
|
108
123
|
if (previous && previous.terminalState === undefined)
|
|
109
124
|
return;
|
|
110
125
|
// A SendMessage resume reuses the finished generation's tool id, whose
|
|
111
|
-
// control state is already cleaned up.
|
|
112
|
-
// is still live; a finished parent can no longer host the new generation.
|
|
113
|
-
const resumedParentSessionId = previous &&
|
|
114
|
-
(this.isLiveSession(previous.parentSessionId)
|
|
115
|
-
? previous.parentSessionId
|
|
116
|
-
: this.rootSessionId);
|
|
126
|
+
// control state is already cleaned up.
|
|
117
127
|
const knownParentSessionId = (task.toolUseId ? this.parentByToolUse.get(task.toolUseId) : undefined) ??
|
|
118
|
-
resumedParentSessionId;
|
|
128
|
+
(previous && this.resumedParentSessionId(previous));
|
|
119
129
|
const identity = task.toolUseId ? this.identityByToolUse.get(task.toolUseId) : undefined;
|
|
120
|
-
|
|
121
|
-
|
|
130
|
+
// A nested child must wait for the spawning Agent/Task frame to establish
|
|
131
|
+
// its immediate parent. Root children without a tool id can be announced.
|
|
132
|
+
await this.openGeneration(task.taskId, previous, {
|
|
122
133
|
parentSessionId: knownParentSessionId ?? this.rootSessionId,
|
|
123
134
|
parentToolUseId: task.toolUseId ?? undefined,
|
|
124
135
|
name: subagentDisplayName(identity?.name, identity?.description ?? task.description, identity?.subagentType ?? task.subagentType, task.taskId),
|
|
125
136
|
task: subagentDescription(identity?.prompt ?? task.prompt, identity?.description ?? task.description),
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
...promptField(promptText(task.prompt) ?? identity?.prompt),
|
|
138
|
+
}, !!knownParentSessionId || !task.toolUseId, deliver);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Opens a new generation of a finished child when the SDK resumes the same
|
|
142
|
+
* agent id. The SDK can resume a child without a new `task_started`, so a
|
|
143
|
+
* running `task_updated` patch or a SendMessage `resumedAgentId` is the
|
|
144
|
+
* signal. A child that did not finish is not changed. The `prompt` is the
|
|
145
|
+
* SendMessage text that resumed the child, when the adapter knows it.
|
|
146
|
+
*/
|
|
147
|
+
async taskResumed(taskId, deliver, prompt) {
|
|
148
|
+
if (!this.enabled)
|
|
149
|
+
return;
|
|
150
|
+
const previous = this.children.get(taskId);
|
|
151
|
+
if (!previous)
|
|
152
|
+
return;
|
|
153
|
+
const finishing = this.taskFinishPromises.get(taskId) ?? previous.terminalPromise;
|
|
154
|
+
if (finishing)
|
|
155
|
+
await finishing.catch(() => { });
|
|
156
|
+
if (this.children.get(taskId) !== previous || previous.terminalState === undefined)
|
|
157
|
+
return;
|
|
158
|
+
await this.openGeneration(taskId, previous, {
|
|
159
|
+
parentSessionId: this.resumedParentSessionId(previous),
|
|
160
|
+
parentToolUseId: previous.parentToolUseId,
|
|
161
|
+
name: previous.name,
|
|
162
|
+
task: previous.task,
|
|
163
|
+
...promptField(promptText(prompt)),
|
|
164
|
+
}, true, deliver);
|
|
141
165
|
}
|
|
142
166
|
async finishTask(taskId, status, deliver, toolUseId) {
|
|
143
167
|
if (!this.enabled)
|
|
@@ -202,8 +226,56 @@ export class NativeSubagentRuntime {
|
|
|
202
226
|
discardPending(parentToolUseId) {
|
|
203
227
|
this.takePending(parentToolUseId);
|
|
204
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Routes an update to the child session. An update of a finished child is
|
|
231
|
+
* dropped: it never goes to the root session.
|
|
232
|
+
*/
|
|
233
|
+
toChild(child, notification, toolCallId) {
|
|
234
|
+
if (child.terminalState !== undefined || child.terminalPromise) {
|
|
235
|
+
this.logger.log(`Session ${this.rootSessionId}: ignoring late update for terminal subagent ${child.sessionId}`);
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
if (toolCallId)
|
|
239
|
+
this.rememberToolCallOwner(toolCallId, child);
|
|
240
|
+
return { ...notification, sessionId: child.sessionId };
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* The route of the work that a child tool call started, for example an async
|
|
244
|
+
* task. The route sends each update to the child generation that owned the
|
|
245
|
+
* tool call when the work started, and drops the update after that child
|
|
246
|
+
* finished. `undefined` means that the root session owns the tool call.
|
|
247
|
+
* `eagerSessionId` is the session where a permission request created the
|
|
248
|
+
* tool call before the stream routed it.
|
|
249
|
+
*/
|
|
250
|
+
routeOfToolCall(toolCallId, eagerSessionId) {
|
|
251
|
+
if (!this.enabled)
|
|
252
|
+
return undefined;
|
|
253
|
+
const owner = this.childByToolCall.get(toolCallId) ??
|
|
254
|
+
(eagerSessionId ? this.childOfSession(eagerSessionId) : undefined);
|
|
255
|
+
return owner && ((notification) => this.toChild(owner, notification, undefined));
|
|
256
|
+
}
|
|
257
|
+
rememberToolCallOwner(toolCallId, child) {
|
|
258
|
+
this.childByToolCall.delete(toolCallId);
|
|
259
|
+
this.childByToolCall.set(toolCallId, child);
|
|
260
|
+
if (this.childByToolCall.size > MAX_CHILD_TOOL_CALLS) {
|
|
261
|
+
const oldest = this.childByToolCall.keys().next().value;
|
|
262
|
+
if (oldest !== undefined)
|
|
263
|
+
this.childByToolCall.delete(oldest);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/** The child generation with the ACP session `sessionId`, if one exists. */
|
|
267
|
+
childOfSession(sessionId) {
|
|
268
|
+
if (sessionId === this.rootSessionId)
|
|
269
|
+
return undefined;
|
|
270
|
+
for (const child of this.children.values()) {
|
|
271
|
+
if (child.sessionId === sessionId)
|
|
272
|
+
return child;
|
|
273
|
+
}
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
205
276
|
clear() {
|
|
206
277
|
this.children.clear();
|
|
278
|
+
this.childByToolCall.clear();
|
|
207
279
|
this.taskByToolUse.clear();
|
|
208
280
|
this.parentByToolUse.clear();
|
|
209
281
|
this.identityByToolUse.clear();
|
|
@@ -241,6 +313,12 @@ export class NativeSubagentRuntime {
|
|
|
241
313
|
this.controlByToolUse.delete(toolUseId);
|
|
242
314
|
this.parentByToolUse.delete(toolUseId);
|
|
243
315
|
}
|
|
316
|
+
/** The parent of a resumed generation: the old parent while it is live, else the root. */
|
|
317
|
+
resumedParentSessionId(previous) {
|
|
318
|
+
return this.isLiveSession(previous.parentSessionId)
|
|
319
|
+
? previous.parentSessionId
|
|
320
|
+
: this.rootSessionId;
|
|
321
|
+
}
|
|
244
322
|
isLiveSession(sessionId) {
|
|
245
323
|
if (sessionId === this.rootSessionId)
|
|
246
324
|
return true;
|
|
@@ -250,6 +328,29 @@ export class NativeSubagentRuntime {
|
|
|
250
328
|
}
|
|
251
329
|
return false;
|
|
252
330
|
}
|
|
331
|
+
/**
|
|
332
|
+
* Registers a new child session for the task and makes it the owner of its
|
|
333
|
+
* parent tool call. With `announce`, it publishes `subagent_spawned` and
|
|
334
|
+
* delivers the updates that waited for the child.
|
|
335
|
+
*/
|
|
336
|
+
async openGeneration(taskId, previous, fields, announce, deliver) {
|
|
337
|
+
const child = {
|
|
338
|
+
sessionId: this.nextChildSessionId(taskId, previous),
|
|
339
|
+
...fields,
|
|
340
|
+
};
|
|
341
|
+
const toolUseId = child.parentToolUseId;
|
|
342
|
+
this.children.set(taskId, child);
|
|
343
|
+
if (toolUseId) {
|
|
344
|
+
this.taskByToolUse.set(toolUseId, taskId);
|
|
345
|
+
this.childByParentToolUse.set(toolUseId, child);
|
|
346
|
+
this.controlByToolUse.delete(toolUseId);
|
|
347
|
+
}
|
|
348
|
+
if (!announce)
|
|
349
|
+
return;
|
|
350
|
+
await announceNativeSubagent(child, this.publish);
|
|
351
|
+
for (const pending of toolUseId ? this.takePending(toolUseId) : [])
|
|
352
|
+
await deliver(pending);
|
|
353
|
+
}
|
|
253
354
|
nextChildSessionId(taskId, previous) {
|
|
254
355
|
if (!previous) {
|
|
255
356
|
this.generationByTaskId.set(taskId, 1);
|
|
@@ -273,6 +374,7 @@ export async function announceNativeSubagent(child, publish) {
|
|
|
273
374
|
subagentSessionId: child.sessionId,
|
|
274
375
|
name: child.name,
|
|
275
376
|
task: child.task,
|
|
377
|
+
...promptField(child.prompt),
|
|
276
378
|
capabilities: {},
|
|
277
379
|
},
|
|
278
380
|
});
|
|
@@ -314,6 +416,41 @@ export async function finishNativeSubagent(session, taskId, state, publish) {
|
|
|
314
416
|
child.terminalPromise = undefined;
|
|
315
417
|
}
|
|
316
418
|
}
|
|
419
|
+
/**
|
|
420
|
+
* The agent id that a successful SendMessage result resumed. The SDK puts it
|
|
421
|
+
* in `tool_use_result.resumedAgentId` when a finished agent runs again.
|
|
422
|
+
*/
|
|
423
|
+
export function resumedNativeSubagentId(toolUseResult) {
|
|
424
|
+
if (typeof toolUseResult !== "object" || toolUseResult === null)
|
|
425
|
+
return undefined;
|
|
426
|
+
const result = toolUseResult;
|
|
427
|
+
return result.success === true ? nonBlankString(result.resumedAgentId) : undefined;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* The SendMessage text that resumed the agent `agentId`. The tool uses of
|
|
431
|
+
* `resultToolUseIds` come first: they are the SendMessage calls whose result
|
|
432
|
+
* carried the resume. Otherwise the latest SendMessage call to `agentId` counts.
|
|
433
|
+
*/
|
|
434
|
+
export function sendMessageResumePrompt(toolUses, agentId, resultToolUseIds = []) {
|
|
435
|
+
for (const toolUseId of resultToolUseIds) {
|
|
436
|
+
const toolUse = toolUses[toolUseId];
|
|
437
|
+
if (toolUse?.name !== "SendMessage")
|
|
438
|
+
continue;
|
|
439
|
+
const text = promptText(toolUse.input?.message);
|
|
440
|
+
if (text)
|
|
441
|
+
return text;
|
|
442
|
+
}
|
|
443
|
+
if (resultToolUseIds.length > 0)
|
|
444
|
+
return undefined;
|
|
445
|
+
for (const toolUse of Object.values(toolUses).reverse()) {
|
|
446
|
+
if (toolUse?.name !== "SendMessage")
|
|
447
|
+
continue;
|
|
448
|
+
const input = toolUse.input;
|
|
449
|
+
if (input?.to === agentId)
|
|
450
|
+
return promptText(input.message);
|
|
451
|
+
}
|
|
452
|
+
return undefined;
|
|
453
|
+
}
|
|
317
454
|
export function nativeSubagentState(status) {
|
|
318
455
|
if (status === "completed")
|
|
319
456
|
return "completed";
|
|
@@ -330,7 +467,8 @@ export function isNativeSubagentControlUpdate(update) {
|
|
|
330
467
|
return false;
|
|
331
468
|
}
|
|
332
469
|
const claudeMeta = update._meta?.claudeCode;
|
|
333
|
-
return
|
|
470
|
+
return (airExtensionMeta(update._meta)?.[AIR_SUBAGENT_KEY] === true ||
|
|
471
|
+
isNativeSubagentControlTool(claudeMeta?.toolName));
|
|
334
472
|
}
|
|
335
473
|
export function isNativeSubagentControlTool(toolName) {
|
|
336
474
|
return toolName === "Agent" || toolName === "Task";
|
|
@@ -387,8 +525,14 @@ function failedControlFallback(initial, terminal, sessionId) {
|
|
|
387
525
|
function ordinaryToolMeta(...values) {
|
|
388
526
|
const merged = Object.assign({}, ...values);
|
|
389
527
|
const claudeCode = Object.assign({}, ...values.map((value) => value?.claudeCode ?? {}));
|
|
390
|
-
|
|
391
|
-
|
|
528
|
+
const result = { ...merged, claudeCode };
|
|
529
|
+
const air = airExtensionMeta(merged);
|
|
530
|
+
if (air && AIR_SUBAGENT_KEY in air) {
|
|
531
|
+
const rest = { ...air };
|
|
532
|
+
delete rest[AIR_SUBAGENT_KEY];
|
|
533
|
+
result.jetbrains = { ...merged.jetbrains, air: rest };
|
|
534
|
+
}
|
|
535
|
+
return result;
|
|
392
536
|
}
|
|
393
537
|
function subagentDisplayName(explicitName, description, type, taskId) {
|
|
394
538
|
for (const value of [explicitName, description, type]) {
|
|
@@ -412,7 +556,7 @@ function subagentIdentity(input) {
|
|
|
412
556
|
const identity = {
|
|
413
557
|
name: nonBlankString(value.name),
|
|
414
558
|
description: nonBlankString(value.description),
|
|
415
|
-
prompt:
|
|
559
|
+
prompt: promptText(value.prompt),
|
|
416
560
|
subagentType: nonBlankString(value.subagent_type),
|
|
417
561
|
};
|
|
418
562
|
return Object.values(identity).some(Boolean) ? identity : undefined;
|
|
@@ -434,6 +578,14 @@ function applySubagentIdentity(child, identity) {
|
|
|
434
578
|
if (identity.prompt || identity.description) {
|
|
435
579
|
child.task = subagentDescription(identity.prompt, identity.description);
|
|
436
580
|
}
|
|
581
|
+
child.prompt ??= identity.prompt;
|
|
582
|
+
}
|
|
583
|
+
/** The prompt text unchanged, or `undefined` when it is not a non-blank string. */
|
|
584
|
+
function promptText(value) {
|
|
585
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
586
|
+
}
|
|
587
|
+
function promptField(prompt) {
|
|
588
|
+
return prompt === undefined ? {} : { prompt };
|
|
437
589
|
}
|
|
438
590
|
function nonBlankString(value) {
|
|
439
591
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAGA,+EAA+E;AAC/E,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
|
package/dist/paths.js
ADDED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type { RequestPermissionRequest } from "@agentclientprotocol/sdk";
|
|
1
|
+
import type { RequestPermissionRequest, ToolCallContent } from "@agentclientprotocol/sdk";
|
|
2
|
+
import { ClientCapabilities } from "../tool-calls/client-capabilities.js";
|
|
2
3
|
export interface ClaudePermissionPresentationInput {
|
|
3
4
|
toolName: string;
|
|
4
5
|
input: Record<string, unknown>;
|
|
5
6
|
toolUseID: string;
|
|
6
7
|
cwd?: string;
|
|
7
|
-
|
|
8
|
+
capabilities?: ClientCapabilities;
|
|
9
|
+
/** The exact patch of the change to approve, for a negotiated `diffPatch` client. */
|
|
10
|
+
previewContent?: ToolCallContent[];
|
|
8
11
|
blockedPath?: string;
|
|
9
12
|
title?: string;
|
|
10
13
|
displayName?: string;
|
|
@@ -12,5 +15,13 @@ export interface ClaudePermissionPresentationInput {
|
|
|
12
15
|
decisionReason?: string;
|
|
13
16
|
defaultToNo?: boolean;
|
|
14
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* The permission request presentation.
|
|
20
|
+
*
|
|
21
|
+
* The request `toolCall` carries `toolCallId`, `title`, and `rawInput`. The
|
|
22
|
+
* adapter emits the `tool_call` before the request, so the client already
|
|
23
|
+
* holds the rest. The request adds only what it shows new: the exact preview
|
|
24
|
+
* patch, and the blocked path when the tool call has no such location.
|
|
25
|
+
*/
|
|
15
26
|
export declare function buildClaudePermissionPresentation(value: ClaudePermissionPresentationInput): Pick<RequestPermissionRequest, "toolCall" | "_meta">;
|
|
16
27
|
//# sourceMappingURL=presentation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../src/permissions/presentation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,
|
|
1
|
+
{"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../src/permissions/presentation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE1F,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAG1E,MAAM,WAAW,iCAAiC;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,qFAAqF;IACrF,cAAc,CAAC,EAAE,eAAe,EAAE,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA0BD;;;;;;;GAOG;AACH,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,iCAAiC,GACvC,IAAI,CAAC,wBAAwB,EAAE,UAAU,GAAG,OAAO,CAAC,CAgEtD"}
|