@lucascouts/claude-agent-acp-plus 0.4.0 → 0.5.1
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/dist/acp-agent.d.ts +131 -16
- package/dist/acp-agent.d.ts.map +1 -1
- package/dist/acp-agent.js +657 -164
- package/dist/elicitation.d.ts.map +1 -1
- package/dist/elicitation.js +13 -0
- package/dist/model-deprecation.d.ts +1 -1
- package/dist/model-deprecation.d.ts.map +1 -1
- package/dist/model-deprecation.js +9 -4
- package/dist/rewind-command.d.ts +15 -3
- package/dist/rewind-command.d.ts.map +1 -1
- package/dist/rewind-command.js +37 -6
- package/dist/thinking-option.d.ts +12 -8
- package/dist/thinking-option.d.ts.map +1 -1
- package/dist/thinking-option.js +12 -8
- package/dist/tools.d.ts +1 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +51 -55
- package/package.json +17 -10
- package/dist/ask-user-question-fallback.d.ts +0 -78
- package/dist/ask-user-question-fallback.d.ts.map +0 -1
- package/dist/ask-user-question-fallback.js +0 -104
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../src/elicitation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EACV,wBAAwB,EAKzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,6CAA6C,CAAC;AAErD;;;;;;;;;;;;;GAaG;AAEH,yDAAyD;AACzD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,GAChB,wBAAwB,GAAG,IAAI,CAyBjC;AAgBD;;;GAGG;AACH,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,yBAAyB,GAClC,iBAAiB,CAUnB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,GAAG,IAAI,CAUhG;
|
|
1
|
+
{"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../src/elicitation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EACV,wBAAwB,EAKzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,6CAA6C,CAAC;AAErD;;;;;;;;;;;;;GAaG;AAEH,yDAAyD;AACzD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,GAChB,wBAAwB,GAAG,IAAI,CAyBjC;AAgBD;;;GAGG;AACH,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,yBAAyB,GAClC,iBAAiB,CAUnB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,GAAG,IAAI,CAUhG;AAgCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,eAAe,EAAE,EAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,wBAAwB,CA2D1B;AAED,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAChC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvF;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,yBAAyB,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,SAAS,EAAE,eAAe,EAAE,GAC3B,sBAAsB,CAkCxB;AAgBD;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,4BAA4B,CAAC;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,qBAAqB,GAAG,IAAI,CAW9B;AAYD;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,qBAAqB,EAC7B,SAAS,EAAE,MAAM,GAChB,wBAAwB,CA+B1B;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,yBAAyB,GAAG,MAAM,CAG7F"}
|
package/dist/elicitation.js
CHANGED
|
@@ -89,6 +89,13 @@ function questionCustomFieldKey(index) {
|
|
|
89
89
|
* extensions (`_claude/...`).
|
|
90
90
|
*/
|
|
91
91
|
const OPTION_META_KEY = "_claude/askUserQuestionOption";
|
|
92
|
+
/**
|
|
93
|
+
* Shared `_meta` key for marking a per-question free-text field as the custom
|
|
94
|
+
* answer companion for a select question. This intentionally has no
|
|
95
|
+
* agent-specific namespace so ACP clients can recognize the same marker across
|
|
96
|
+
* Codex, Claude, and other AskUserQuestion bridges.
|
|
97
|
+
*/
|
|
98
|
+
const CUSTOM_ANSWER_META_KEY = "_askUserQuestionCustomAnswer";
|
|
92
99
|
/**
|
|
93
100
|
* Render the AskUserQuestion tool's questions as an ACP form elicitation.
|
|
94
101
|
*
|
|
@@ -137,6 +144,12 @@ export function askUserQuestionsToCreateRequest(questions, sessionId, toolCallId
|
|
|
137
144
|
type: "string",
|
|
138
145
|
title: "Other",
|
|
139
146
|
description: "Type your own answer instead of choosing an option above (optional).",
|
|
147
|
+
_meta: {
|
|
148
|
+
[CUSTOM_ANSWER_META_KEY]: {
|
|
149
|
+
questionId: questionFieldKey(index),
|
|
150
|
+
isCustomAnswer: true,
|
|
151
|
+
},
|
|
152
|
+
},
|
|
140
153
|
};
|
|
141
154
|
});
|
|
142
155
|
const requestedSchema = {
|
|
@@ -8,7 +8,7 @@ import type { ModelInfo } from "@anthropic-ai/claude-agent-sdk";
|
|
|
8
8
|
* `undefined`, or empty `displayName` or `description` is treated as an empty
|
|
9
9
|
* string, so this never throws.
|
|
10
10
|
*
|
|
11
|
-
* See the module doc for WHY this is a heuristic (SDK 0.3.
|
|
11
|
+
* See the module doc for WHY this is a heuristic (SDK 0.3.220 `ModelInfo` has no
|
|
12
12
|
* deprecation field).
|
|
13
13
|
*
|
|
14
14
|
* @param info - A single SDK model row.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-deprecation.d.ts","sourceRoot":"","sources":["../src/model-deprecation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"model-deprecation.d.ts","sourceRoot":"","sources":["../src/model-deprecation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAiChE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAI1D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAEtE"}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model deprecation heuristic.
|
|
3
3
|
*
|
|
4
|
-
* The Claude Agent SDK's `ModelInfo`
|
|
5
|
-
*
|
|
6
|
-
* `supportsAdaptiveThinking`, `supportsFastMode`, and `supportsAutoMode
|
|
4
|
+
* The Claude Agent SDK's `ModelInfo` exposes NO deprecation flag — its only
|
|
5
|
+
* capability fields are `supportsEffort` / `supportedEffortLevels`,
|
|
6
|
+
* `supportsAdaptiveThinking`, `supportsFastMode`, and `supportsAutoMode`
|
|
7
|
+
* (`resolvedModel` is an alias-resolution hint, not a lifecycle signal). There
|
|
7
8
|
* is therefore no authoritative, machine-readable signal telling a host that a
|
|
8
9
|
* model row has been retired.
|
|
9
10
|
*
|
|
11
|
+
* LAST VERIFIED AGAINST SDK 0.3.220 (story 008, R5.5) — the type is byte-for-byte
|
|
12
|
+
* unchanged from 0.3.204/0.3.212, so the heuristic below is still necessary.
|
|
13
|
+
* Re-check this claim on every SDK bump and update the version named here.
|
|
14
|
+
*
|
|
10
15
|
* As a stand-in this module scans the human-facing copy — `displayName` and
|
|
11
16
|
* `description` — for the words "deprecated" or "legacy" (case-insensitive).
|
|
12
17
|
* This is deliberately a HEURISTIC: it can only catch models the SDK happens to
|
|
@@ -31,7 +36,7 @@ const DEPRECATION_MARKER = /deprecated|legacy/i;
|
|
|
31
36
|
* `undefined`, or empty `displayName` or `description` is treated as an empty
|
|
32
37
|
* string, so this never throws.
|
|
33
38
|
*
|
|
34
|
-
* See the module doc for WHY this is a heuristic (SDK 0.3.
|
|
39
|
+
* See the module doc for WHY this is a heuristic (SDK 0.3.220 `ModelInfo` has no
|
|
35
40
|
* deprecation field).
|
|
36
41
|
*
|
|
37
42
|
* @param info - A single SDK model row.
|
package/dist/rewind-command.d.ts
CHANGED
|
@@ -75,11 +75,21 @@ export declare function listCheckpoints(messages: SDKMessage[]): Checkpoint[];
|
|
|
75
75
|
export declare function formatCheckpointList(cps: Checkpoint[]): string;
|
|
76
76
|
/**
|
|
77
77
|
* Confirm a completed rewind, naming the checkpoint that was restored by its
|
|
78
|
-
* index and excerpt (R3.4).
|
|
78
|
+
* index and excerpt (R3.4). When the SDK reports files it refused to touch for
|
|
79
|
+
* link safety, the confirmation is qualified with their count (R1.1) in the
|
|
80
|
+
* grammatical number that count calls for (R1.4), so the sentence cannot claim
|
|
81
|
+
* a clean success the rewind did not have.
|
|
82
|
+
*
|
|
83
|
+
* The unqualified sentence is unchanged character for character: an absent,
|
|
84
|
+
* zero, negative or non-numeric count returns exactly what this function
|
|
85
|
+
* returned before the qualifier existed (R1.2). The SDK exposes a COUNT only,
|
|
86
|
+
* never the refused paths, so the message deliberately names no files.
|
|
79
87
|
*
|
|
80
88
|
* @param cp The checkpoint whose files were restored.
|
|
89
|
+
* @param skippedLinks How many tracked files the SDK left unchanged for link
|
|
90
|
+
* safety (`RewindFilesResult.skippedLinks`); omit or pass 0 when none were.
|
|
81
91
|
*/
|
|
82
|
-
export declare function formatRewindResult(cp: Checkpoint): string;
|
|
92
|
+
export declare function formatRewindResult(cp: Checkpoint, skippedLinks?: number): string;
|
|
83
93
|
/**
|
|
84
94
|
* Build a `/rewind` usage/error message. Always names the `/rewind` command and,
|
|
85
95
|
* when at least one checkpoint exists, the valid index range (R3.5). An optional
|
|
@@ -122,7 +132,9 @@ export interface RewindDeps {
|
|
|
122
132
|
* nothing-to-rewind notice). `restore` fetches + rebuilds the list, validates
|
|
123
133
|
* the requested index, and on a hit calls `query.rewindFiles` with the tracked
|
|
124
134
|
* uuid inside a try/catch — a rejection (or a `canRewind: false` result) is
|
|
125
|
-
* reported via {@link formatRewindError} and never claims success.
|
|
135
|
+
* reported via {@link formatRewindError} and never claims success. A success
|
|
136
|
+
* that refused files for link safety carries that count into the confirmation
|
|
137
|
+
* (R1.1), so a partial rewind is not reported as a whole one. An `invalid`
|
|
126
138
|
* invocation, an out-of-range index, or a failed transcript read each emit an
|
|
127
139
|
* error and leave files untouched (`rewindFiles` is never called); the
|
|
128
140
|
* `invalid` path still reads the transcript so its usage message can name the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rewind-command.d.ts","sourceRoot":"","sources":["../src/rewind-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAMpF,qFAAqF;AACrF,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E,uFAAuF;AACvF,MAAM,MAAM,gBAAgB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3F;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAkBjF;AAkED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CA4BpE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,MAAM,CAY9D;AAED
|
|
1
|
+
{"version":3,"file":"rewind-command.d.ts","sourceRoot":"","sources":["../src/rewind-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAMpF,qFAAqF;AACrF,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E,uFAAuF;AACvF,MAAM,MAAM,gBAAgB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3F;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAkBjF;AAkED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CA4BpE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,MAAM,CAY9D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,UAAU,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAiBhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,MAAM,EAAE;QACN,aAAa,CAAC,YAAY,EAAE;YAC1B,SAAS,EAAE,MAAM,CAAC;YAClB,MAAM,EAAE;gBAAE,aAAa,EAAE,qBAAqB,CAAC;gBAAC,OAAO,EAAE;oBAAE,IAAI,EAAE,MAAM,CAAC;oBAAC,IAAI,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAC;SAC3F,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACnB,CAAC;IACF,oDAAoD;IACpD,KAAK,EAAE;QAAE,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;KAAE,CAAC;IAC1E,sEAAsE;IACtE,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CAC9D;AAqBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,gBAAgB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAkEf"}
|
package/dist/rewind-command.js
CHANGED
|
@@ -170,12 +170,37 @@ export function formatCheckpointList(cps) {
|
|
|
170
170
|
}
|
|
171
171
|
/**
|
|
172
172
|
* Confirm a completed rewind, naming the checkpoint that was restored by its
|
|
173
|
-
* index and excerpt (R3.4).
|
|
173
|
+
* index and excerpt (R3.4). When the SDK reports files it refused to touch for
|
|
174
|
+
* link safety, the confirmation is qualified with their count (R1.1) in the
|
|
175
|
+
* grammatical number that count calls for (R1.4), so the sentence cannot claim
|
|
176
|
+
* a clean success the rewind did not have.
|
|
177
|
+
*
|
|
178
|
+
* The unqualified sentence is unchanged character for character: an absent,
|
|
179
|
+
* zero, negative or non-numeric count returns exactly what this function
|
|
180
|
+
* returned before the qualifier existed (R1.2). The SDK exposes a COUNT only,
|
|
181
|
+
* never the refused paths, so the message deliberately names no files.
|
|
174
182
|
*
|
|
175
183
|
* @param cp The checkpoint whose files were restored.
|
|
184
|
+
* @param skippedLinks How many tracked files the SDK left unchanged for link
|
|
185
|
+
* safety (`RewindFilesResult.skippedLinks`); omit or pass 0 when none were.
|
|
176
186
|
*/
|
|
177
|
-
export function formatRewindResult(cp) {
|
|
178
|
-
|
|
187
|
+
export function formatRewindResult(cp, skippedLinks) {
|
|
188
|
+
const confirmation = `Rewound files to checkpoint ${cp.index}: "${cp.excerpt}".`;
|
|
189
|
+
// Type AND value are checked: the SDK field is optional, so `undefined` is
|
|
190
|
+
// the normal path, and testing `> 0` on a number also rejects NaN, which a
|
|
191
|
+
// `typeof` test alone would admit (`typeof NaN === "number"`).
|
|
192
|
+
//
|
|
193
|
+
// It does NOT reject every malformed number: `Infinity` and `0.5` pass this
|
|
194
|
+
// guard and would render as "Infinity files were" / "0.5 files were". The
|
|
195
|
+
// SDK returns an integer count, so those are UNREACHABLE rather than
|
|
196
|
+
// handled — stated plainly because a comment claiming a guarantee it does
|
|
197
|
+
// not deliver is the exact failure this function was changed to fix.
|
|
198
|
+
if (typeof skippedLinks === "number" && skippedLinks > 0) {
|
|
199
|
+
// Subject + verb agree with the count (R1.4): "1 file was", "2 files were".
|
|
200
|
+
const refusal = skippedLinks === 1 ? "1 file was" : `${skippedLinks} files were`;
|
|
201
|
+
return `${confirmation} ${refusal} left unchanged for link safety.`;
|
|
202
|
+
}
|
|
203
|
+
return confirmation;
|
|
179
204
|
}
|
|
180
205
|
/**
|
|
181
206
|
* Build a `/rewind` usage/error message. Always names the `/rewind` command and,
|
|
@@ -216,7 +241,9 @@ async function emit(deps, text) {
|
|
|
216
241
|
* nothing-to-rewind notice). `restore` fetches + rebuilds the list, validates
|
|
217
242
|
* the requested index, and on a hit calls `query.rewindFiles` with the tracked
|
|
218
243
|
* uuid inside a try/catch — a rejection (or a `canRewind: false` result) is
|
|
219
|
-
* reported via {@link formatRewindError} and never claims success.
|
|
244
|
+
* reported via {@link formatRewindError} and never claims success. A success
|
|
245
|
+
* that refused files for link safety carries that count into the confirmation
|
|
246
|
+
* (R1.1), so a partial rewind is not reported as a whole one. An `invalid`
|
|
220
247
|
* invocation, an out-of-range index, or a failed transcript read each emit an
|
|
221
248
|
* error and leave files untouched (`rewindFiles` is never called); the
|
|
222
249
|
* `invalid` path still reads the transcript so its usage message can name the
|
|
@@ -263,8 +290,12 @@ export async function handleRewindCommand(deps, invocation) {
|
|
|
263
290
|
await emit(deps, formatRewindError(checkpoints.length, `There is no checkpoint ${invocation.index}.`));
|
|
264
291
|
return;
|
|
265
292
|
}
|
|
293
|
+
// Declared out here (same shape as `checkpoints` above) so the confirmation
|
|
294
|
+
// below can read `skippedLinks` off it; the assignment and every early
|
|
295
|
+
// `return` stay inside the try/catch exactly where they were.
|
|
296
|
+
let result;
|
|
266
297
|
try {
|
|
267
|
-
|
|
298
|
+
result = await deps.query.rewindFiles(checkpoint.uuid);
|
|
268
299
|
if (result.canRewind === false) {
|
|
269
300
|
await emit(deps, formatRewindError(checkpoints.length, `Rewind failed: ${result.error ?? "the SDK could not rewind these files"}.`));
|
|
270
301
|
return;
|
|
@@ -274,5 +305,5 @@ export async function handleRewindCommand(deps, invocation) {
|
|
|
274
305
|
await emit(deps, formatRewindError(checkpoints.length, `Rewind failed: ${reasonText(error)}.`));
|
|
275
306
|
return;
|
|
276
307
|
}
|
|
277
|
-
await emit(deps, formatRewindResult(checkpoint));
|
|
308
|
+
await emit(deps, formatRewindResult(checkpoint, result.skippedLinks));
|
|
278
309
|
}
|
|
@@ -5,11 +5,15 @@
|
|
|
5
5
|
* session's thinking intent with the legacy `MAX_THINKING_TOKENS` env
|
|
6
6
|
* resolution into the SDK's `thinking` option.
|
|
7
7
|
*
|
|
8
|
-
* Kept self-contained
|
|
9
|
-
*
|
|
10
|
-
* unit-testable in isolation
|
|
11
|
-
* `
|
|
12
|
-
*
|
|
8
|
+
* Kept self-contained — no import from `acp-agent.ts`; what this module needs
|
|
9
|
+
* from the adapter (a logger, the raw env value) is injected instead, which
|
|
10
|
+
* also leaves the logic unit-testable in isolation. This mirrors the
|
|
11
|
+
* `rewind-command.ts` precedent, likewise isolated from the adapter so it can
|
|
12
|
+
* be unit tested without a live SDK session. The reason is merge cost:
|
|
13
|
+
* `acp-agent.ts` is a ~7,900-line file that changes upstream almost daily, so
|
|
14
|
+
* every coupling to it is paid again at each sync. `acp-agent.ts` wires these
|
|
15
|
+
* helpers into `buildConfigOptions`, `setSessionConfigOption` and query
|
|
16
|
+
* creation.
|
|
13
17
|
*/
|
|
14
18
|
import type { SessionConfigOption } from "@agentclientprotocol/sdk";
|
|
15
19
|
import type { ThinkingConfig } from "@anthropic-ai/claude-agent-sdk";
|
|
@@ -53,9 +57,9 @@ export declare function resolveThinkingSelection(value: unknown): boolean | null
|
|
|
53
57
|
* it); `0` → disabled; a positive integer → a fixed token budget. Anything
|
|
54
58
|
* else is ignored with a logged error, i.e. treated as unset.
|
|
55
59
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
60
|
+
* This is the single source of truth for that translation: `acp-agent.ts`
|
|
61
|
+
* carries no copy of it and reaches it only through `effectiveThinkingConfig`
|
|
62
|
+
* below.
|
|
59
63
|
*
|
|
60
64
|
* @param raw The raw `MAX_THINKING_TOKENS` value (pass
|
|
61
65
|
* `process.env.MAX_THINKING_TOKENS`).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thinking-option.d.ts","sourceRoot":"","sources":["../src/thinking-option.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"thinking-option.d.ts","sourceRoot":"","sources":["../src/thinking-option.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,aAAa,CAAC;AAC7C,oDAAoD;AACpD,eAAO,MAAM,WAAW,OAAO,CAAC;AAChC,qDAAqD;AACrD,eAAO,MAAM,YAAY,QAAQ,CAAC;AAGlC;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAClC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB,CAahF;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAIvE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,MAAM,EAAE,cAAc,GACrB,cAAc,GAAG,SAAS,CAQ5B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,OAAO,GAAG,SAAS,EAC3B,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,MAAM,EAAE,cAAc,GACrB,cAAc,GAAG,SAAS,CAI5B"}
|
package/dist/thinking-option.js
CHANGED
|
@@ -5,11 +5,15 @@
|
|
|
5
5
|
* session's thinking intent with the legacy `MAX_THINKING_TOKENS` env
|
|
6
6
|
* resolution into the SDK's `thinking` option.
|
|
7
7
|
*
|
|
8
|
-
* Kept self-contained
|
|
9
|
-
*
|
|
10
|
-
* unit-testable in isolation
|
|
11
|
-
* `
|
|
12
|
-
*
|
|
8
|
+
* Kept self-contained — no import from `acp-agent.ts`; what this module needs
|
|
9
|
+
* from the adapter (a logger, the raw env value) is injected instead, which
|
|
10
|
+
* also leaves the logic unit-testable in isolation. This mirrors the
|
|
11
|
+
* `rewind-command.ts` precedent, likewise isolated from the adapter so it can
|
|
12
|
+
* be unit tested without a live SDK session. The reason is merge cost:
|
|
13
|
+
* `acp-agent.ts` is a ~7,900-line file that changes upstream almost daily, so
|
|
14
|
+
* every coupling to it is paid again at each sync. `acp-agent.ts` wires these
|
|
15
|
+
* helpers into `buildConfigOptions`, `setSessionConfigOption` and query
|
|
16
|
+
* creation.
|
|
13
17
|
*/
|
|
14
18
|
/** Stable id for the Thinking session config option. */
|
|
15
19
|
export const THINKING_CONFIG_ID = "thinking";
|
|
@@ -62,9 +66,9 @@ export function resolveThinkingSelection(value) {
|
|
|
62
66
|
* it); `0` → disabled; a positive integer → a fixed token budget. Anything
|
|
63
67
|
* else is ignored with a logged error, i.e. treated as unset.
|
|
64
68
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
69
|
+
* This is the single source of truth for that translation: `acp-agent.ts`
|
|
70
|
+
* carries no copy of it and reaches it only through `effectiveThinkingConfig`
|
|
71
|
+
* below.
|
|
68
72
|
*
|
|
69
73
|
* @param raw The raw `MAX_THINKING_TOKENS` value (pass
|
|
70
74
|
* `process.env.MAX_THINKING_TOKENS`).
|
package/dist/tools.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { HookCallback } from "@anthropic-ai/claude-agent-sdk";
|
|
|
3
3
|
import { TaskCreateInput, TaskCreateOutput, TaskUpdateInput } from "@anthropic-ai/claude-agent-sdk/sdk-tools.js";
|
|
4
4
|
import { ToolResultBlockParam, WebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources";
|
|
5
5
|
import { BetaBashCodeExecutionToolResultBlockParam, BetaCodeExecutionToolResultBlockParam, BetaRequestMCPToolResultBlockParam, BetaTextEditorCodeExecutionToolResultBlockParam, BetaToolResultBlockParam, BetaToolSearchToolResultBlockParam, BetaWebFetchToolResultBlockParam, BetaWebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources/beta.mjs";
|
|
6
|
-
import { Logger } from "./acp-agent.js";
|
|
7
6
|
interface ToolInfo {
|
|
8
7
|
title: string;
|
|
9
8
|
kind: ToolKind;
|
|
@@ -82,7 +81,7 @@ export declare function toolUpdateFromDiffToolResponse(toolResponse: unknown): {
|
|
|
82
81
|
export declare const registerHookCallback: (toolUseID: string, { onPostToolUseHook, }: {
|
|
83
82
|
onPostToolUseHook?: (toolUseID: string, toolInput: unknown, toolResponse: unknown) => Promise<void>;
|
|
84
83
|
}) => void;
|
|
85
|
-
export declare const createPostToolUseHook: (
|
|
84
|
+
export declare const createPostToolUseHook: (options?: {
|
|
86
85
|
onEnterPlanMode?: () => Promise<void>;
|
|
87
86
|
}) => HookCallback;
|
|
88
87
|
/**
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACT,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAaL,eAAe,EACf,gBAAgB,EAChB,eAAe,EAKhB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAGL,oBAAoB,EAEpB,6BAA6B,EAE9B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEL,yCAAyC,EAGzC,qCAAqC,EAGrC,kCAAkC,EAGlC,+CAA+C,EAI/C,wBAAwB,EACxB,kCAAkC,EAIlC,gCAAgC,EAEhC,iCAAiC,EAClC,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.js
CHANGED
|
@@ -362,56 +362,39 @@ function structuredResult(toolUseResult) {
|
|
|
362
362
|
* matching rather than mangle the report.
|
|
363
363
|
*/
|
|
364
364
|
function stripAgentTrailer(text) {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
// opener onward is part of the stripped trailer.
|
|
377
|
-
const start = beforeUsage.indexOf("<usage>");
|
|
378
|
-
if (start !== -1) {
|
|
379
|
-
out = beforeUsage.slice(0, start);
|
|
380
|
-
if (out.endsWith("\n"))
|
|
381
|
-
out = out.slice(0, -1);
|
|
382
|
-
}
|
|
365
|
+
return stripAgentIdLine(stripUsageBlock(text));
|
|
366
|
+
}
|
|
367
|
+
const USAGE_OPEN = "<usage>";
|
|
368
|
+
const USAGE_CLOSE = "</usage>";
|
|
369
|
+
/** Remove a trailing `<usage>…</usage>` block, plus trailing whitespace and
|
|
370
|
+
* one preceding newline. Matches from the *last* `<usage>` so a report that
|
|
371
|
+
* merely mentions the marker earlier isn't truncated at the mention. */
|
|
372
|
+
function stripUsageBlock(text) {
|
|
373
|
+
const body = text.trimEnd();
|
|
374
|
+
if (!body.endsWith(USAGE_CLOSE)) {
|
|
375
|
+
return text;
|
|
383
376
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
// the opener can only be the LAST `(` — which pins the whole match without
|
|
388
|
-
// scanning from every position.
|
|
389
|
-
const beforeAgentId = out.trimEnd();
|
|
390
|
-
if (beforeAgentId.endsWith(")")) {
|
|
391
|
-
const open = beforeAgentId.lastIndexOf("(");
|
|
392
|
-
const body = open === -1 ? null : beforeAgentId.slice(open + 1, beforeAgentId.length - 1);
|
|
393
|
-
// A `)` inside the body rules the trailer out (no earlier `(` can help:
|
|
394
|
-
// that stray `)` would still fall inside its body).
|
|
395
|
-
if (body !== null && !body.includes(")")) {
|
|
396
|
-
const head = beforeAgentId.slice(0, open);
|
|
397
|
-
if (head.endsWith(" ")) {
|
|
398
|
-
const beforeSpace = head.slice(0, -1);
|
|
399
|
-
const idStart = beforeSpace.lastIndexOf(" ") + 1;
|
|
400
|
-
const id = beforeSpace.slice(idStart);
|
|
401
|
-
if (AGENT_ID.test(id) && beforeSpace.slice(0, idStart).endsWith("agentId: ")) {
|
|
402
|
-
let start = idStart - "agentId: ".length;
|
|
403
|
-
if (start > 0 && beforeAgentId[start - 1] === "\n")
|
|
404
|
-
start -= 1;
|
|
405
|
-
out = beforeAgentId.slice(0, start);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
377
|
+
const open = body.lastIndexOf(USAGE_OPEN, body.length - USAGE_CLOSE.length - USAGE_OPEN.length);
|
|
378
|
+
if (open === -1) {
|
|
379
|
+
return text;
|
|
409
380
|
}
|
|
410
|
-
return
|
|
381
|
+
return body.slice(0, open > 0 && body[open - 1] === "\n" ? open - 1 : open);
|
|
382
|
+
}
|
|
383
|
+
/** The continuation line, anchored to a whole line so the regex has a single
|
|
384
|
+
* start position and no ambiguous repetition (`[\w-]+` can't consume the
|
|
385
|
+
* following space, `[^)]*` can't consume the closing paren) — it runs in
|
|
386
|
+
* linear time on any input. */
|
|
387
|
+
const AGENT_ID_LINE = /^agentId: [\w-]+ \([^)]*\)$/;
|
|
388
|
+
/** Remove a final `agentId: <id> (…)` line, plus trailing whitespace and the
|
|
389
|
+
* newline that preceded the line. */
|
|
390
|
+
function stripAgentIdLine(text) {
|
|
391
|
+
const body = text.trimEnd();
|
|
392
|
+
const lineStart = body.lastIndexOf("\n") + 1;
|
|
393
|
+
if (!AGENT_ID_LINE.test(body.slice(lineStart))) {
|
|
394
|
+
return text;
|
|
395
|
+
}
|
|
396
|
+
return body.slice(0, Math.max(lineStart - 1, 0));
|
|
411
397
|
}
|
|
412
|
-
/** The `<id>` of an `agentId:` trailer — tested only against an already
|
|
413
|
-
* isolated, space-delimited token, never scanned across the whole report. */
|
|
414
|
-
const AGENT_ID = /^[\w-]+$/;
|
|
415
398
|
/** Apply {@link stripAgentTrailer} across a raw tool_result `content` (plain
|
|
416
399
|
* string or block array), leaving non-text blocks untouched. */
|
|
417
400
|
function stripAgentTrailerFromContent(content) {
|
|
@@ -518,7 +501,17 @@ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOu
|
|
|
518
501
|
}
|
|
519
502
|
case "Bash": {
|
|
520
503
|
const result = toolResult.content;
|
|
521
|
-
|
|
504
|
+
// The terminal was announced under the tool_use's own id (see
|
|
505
|
+
// `toolInfoFromToolUse`), so key the output/exit metas off that: it is the
|
|
506
|
+
// id the client actually created a terminal for. `toolResult.tool_use_id`
|
|
507
|
+
// is the same value whenever present — the caller looks the tool_use up by
|
|
508
|
+
// it — so preferring `toolUse.id` only adds a source for the case where the
|
|
509
|
+
// result block carries no id at all. Anything that isn't a non-empty
|
|
510
|
+
// string is no id at all: `""` matches no terminal, and stringifying a
|
|
511
|
+
// present-but-undefined field would invent the literal `"undefined"`.
|
|
512
|
+
const terminalIdOf = (id) => typeof id === "string" && id.length > 0 ? id : undefined;
|
|
513
|
+
const terminalId = terminalIdOf(toolUse?.id) ??
|
|
514
|
+
terminalIdOf("tool_use_id" in toolResult ? toolResult.tool_use_id : undefined);
|
|
522
515
|
const isError = "is_error" in toolResult && toolResult.is_error;
|
|
523
516
|
// Extract output and exit code from either format:
|
|
524
517
|
// 1. The structured BashOutput (message-level tool_use_result): its
|
|
@@ -593,7 +586,14 @@ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOu
|
|
|
593
586
|
return toAcpContentUpdate(result, isError);
|
|
594
587
|
}
|
|
595
588
|
}
|
|
596
|
-
|
|
589
|
+
// Without a terminal id there is nothing the client can reconcile these
|
|
590
|
+
// metas against, and emitting them anyway strands the output: a client that
|
|
591
|
+
// buffers output/exit for terminals it has not been told about (Zed keeps
|
|
592
|
+
// them in `pending_terminal_output`/`pending_terminal_exit`, drained only on
|
|
593
|
+
// a matching create) would hold them forever behind an id that never
|
|
594
|
+
// arrives, showing an empty terminal. Fall through to the code-block
|
|
595
|
+
// rendering below instead.
|
|
596
|
+
if (supportsTerminalOutput && terminalId !== undefined) {
|
|
597
597
|
return {
|
|
598
598
|
content: [{ type: "terminal", terminalId }],
|
|
599
599
|
_meta: {
|
|
@@ -944,7 +944,7 @@ export const registerHookCallback = (toolUseID, { onPostToolUseHook, }) => {
|
|
|
944
944
|
};
|
|
945
945
|
};
|
|
946
946
|
/* A callback for Claude Code that is called when receiving a PostToolUse hook */
|
|
947
|
-
export const createPostToolUseHook = (
|
|
947
|
+
export const createPostToolUseHook = (options) => async (input, toolUseID) => {
|
|
948
948
|
if (input.hook_event_name === "PostToolUse") {
|
|
949
949
|
// Handle EnterPlanMode tool - notify client of mode change after successful execution
|
|
950
950
|
if (input.tool_name === "EnterPlanMode" && options?.onEnterPlanMode) {
|
|
@@ -954,12 +954,8 @@ export const createPostToolUseHook = (logger = console, options) => async (input
|
|
|
954
954
|
const onPostToolUseHook = toolUseCallbacks[toolUseID]?.onPostToolUseHook;
|
|
955
955
|
if (onPostToolUseHook) {
|
|
956
956
|
await onPostToolUseHook(toolUseID, input.tool_input, input.tool_response);
|
|
957
|
-
delete toolUseCallbacks[toolUseID]; // Cleanup after execution
|
|
958
|
-
}
|
|
959
|
-
else {
|
|
960
|
-
logger.error(`No onPostToolUseHook found for tool use ID: ${toolUseID}`);
|
|
961
|
-
delete toolUseCallbacks[toolUseID];
|
|
962
957
|
}
|
|
958
|
+
delete toolUseCallbacks[toolUseID]; // Cleanup after execution
|
|
963
959
|
}
|
|
964
960
|
}
|
|
965
961
|
return { continue: true };
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.5.1",
|
|
7
7
|
"description": "ACP adapter for the Claude Agent SDK with VS Code-parity UX for Zed and other ACP clients — checkbox multi-select questions, refusal consent dialog, dynamic agent name. Fork of claude-agent-acp.",
|
|
8
8
|
"main": "dist/lib.js",
|
|
9
9
|
"types": "dist/lib.d.ts",
|
|
@@ -64,21 +64,28 @@
|
|
|
64
64
|
"node": ">=24"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@agentclientprotocol/sdk": "1.
|
|
68
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
67
|
+
"@agentclientprotocol/sdk": "1.3.0",
|
|
68
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.220",
|
|
69
69
|
"zod": "^3.25.0 || ^4.0.0"
|
|
70
70
|
},
|
|
71
|
+
"overrides": {
|
|
72
|
+
"@hono/node-server": "~2.0.6",
|
|
73
|
+
"brace-expansion": "^5.0.9",
|
|
74
|
+
"fast-uri": "^3.1.5",
|
|
75
|
+
"hono": "^4.12.34",
|
|
76
|
+
"ip-address": "^10.4.0"
|
|
77
|
+
},
|
|
71
78
|
"devDependencies": {
|
|
72
|
-
"@anthropic-ai/sdk": "0.
|
|
79
|
+
"@anthropic-ai/sdk": "0.115.0",
|
|
73
80
|
"@eslint/js": "10.0.1",
|
|
74
81
|
"@tsconfig/node24": "24.0.4",
|
|
75
|
-
"@types/node": "26.1.
|
|
76
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
77
|
-
"@typescript-eslint/parser": "8.
|
|
78
|
-
"eslint": "10.
|
|
82
|
+
"@types/node": "26.1.2",
|
|
83
|
+
"@typescript-eslint/eslint-plugin": "8.65.0",
|
|
84
|
+
"@typescript-eslint/parser": "8.65.0",
|
|
85
|
+
"eslint": "10.8.0",
|
|
79
86
|
"eslint-config-prettier": "10.1.8",
|
|
80
|
-
"globals": "17.
|
|
81
|
-
"prettier": "3.9.
|
|
87
|
+
"globals": "17.8.0",
|
|
88
|
+
"prettier": "3.9.6",
|
|
82
89
|
"ts-node": "10.9.2",
|
|
83
90
|
"typescript": "6.0.3",
|
|
84
91
|
"vitest": "4.1.10"
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fallback for the built-in AskUserQuestion tool when the connected client does
|
|
3
|
-
* NOT advertise `elicitation.form`. Upstream disables the tool for such clients;
|
|
4
|
-
* this module lets the agent instead route each question through ACP's
|
|
5
|
-
* `session/request_permission` dialog. The path is gated by the
|
|
6
|
-
* `ACP_ASKUSERQUESTION_FALLBACK` env var so it can be turned off to restore
|
|
7
|
-
* byte-for-byte upstream behavior.
|
|
8
|
-
*
|
|
9
|
-
* Alongside the env gate this module provides the pure mapping/orchestration
|
|
10
|
-
* helpers (`questionPermissionOptions`, `handleAskUserQuestionViaPermission`);
|
|
11
|
-
* the ACP client is injected by the adapter that wires them in.
|
|
12
|
-
*/
|
|
13
|
-
import type { PermissionOption } from "@agentclientprotocol/sdk";
|
|
14
|
-
import { type AskUserQuestion } from "./elicitation.js";
|
|
15
|
-
/**
|
|
16
|
-
* Whether the AskUserQuestion permission fallback is enabled for clients lacking
|
|
17
|
-
* `elicitation.form`. Defaults ON: only an explicit `0` or `false` (trimmed,
|
|
18
|
-
* case-insensitive) turns it off; any other value — unset, `1`, `true`, … —
|
|
19
|
-
* leaves it on.
|
|
20
|
-
*
|
|
21
|
-
* @param env Environment map to read `ACP_ASKUSERQUESTION_FALLBACK` from (pass
|
|
22
|
-
* `process.env`).
|
|
23
|
-
*/
|
|
24
|
-
export declare function askUserQuestionFallbackEnabled(env: Record<string, string | undefined>): boolean;
|
|
25
|
-
/**
|
|
26
|
-
* Map one AskUserQuestion question to the options shown in ACP's
|
|
27
|
-
* `session/request_permission` dialog: one `allow_once` option per choice (in
|
|
28
|
-
* order) followed by a trailing `reject_once` "Skip this question" option.
|
|
29
|
-
*
|
|
30
|
-
* Each choice's `optionId` is its bare `label` — the value the tool records as
|
|
31
|
-
* the answer — so the description is never folded into the id; a non-empty
|
|
32
|
-
* `description` is instead appended to the human-readable `name` as
|
|
33
|
-
* `"<label> — <description>"`. The skip option is given a random `optionId`
|
|
34
|
-
* that cannot collide with any label, so the orchestrator can recognize a skip
|
|
35
|
-
* by id alone.
|
|
36
|
-
*
|
|
37
|
-
* @param question The single question whose choices become permission options.
|
|
38
|
-
*/
|
|
39
|
-
export declare function questionPermissionOptions(question: AskUserQuestion): PermissionOption[];
|
|
40
|
-
/**
|
|
41
|
-
* Route an AskUserQuestion tool call through ACP permission requests rather than
|
|
42
|
-
* a form elicitation, for clients that lack `elicitation.form`. Each question is
|
|
43
|
-
* asked sequentially via the injected `requestPermission`; the selected label is
|
|
44
|
-
* accumulated into `answers` (keyed by the question text), a skipped question is
|
|
45
|
-
* omitted, and a multi-select question naturally degrades to a single label
|
|
46
|
-
* since each option is single-select here.
|
|
47
|
-
*
|
|
48
|
-
* Mirrors the upstream form handler's contract: input with no parseable
|
|
49
|
-
* questions denies with the identical message, and an aborted signal or a
|
|
50
|
-
* cancelled request throws `"Tool use aborted"`, discarding every accumulated
|
|
51
|
-
* answer. On success it returns the original `toolInput` augmented with
|
|
52
|
-
* `answers` as `updatedInput`.
|
|
53
|
-
*
|
|
54
|
-
* Pure and injectable — the real ACP client is wired in by the adapter — so the
|
|
55
|
-
* orchestration can be exercised without a transport.
|
|
56
|
-
*
|
|
57
|
-
* @param toolInput Raw AskUserQuestion tool input (expected to carry `questions`).
|
|
58
|
-
* @param requestPermission Injected permission-request function, invoked once per
|
|
59
|
-
* question, resolving to the user's selection or a cancellation.
|
|
60
|
-
* @param signal Abort signal for the tool call; checked on entry and around each
|
|
61
|
-
* request.
|
|
62
|
-
*/
|
|
63
|
-
export declare function handleAskUserQuestionViaPermission(toolInput: Record<string, unknown>, requestPermission: (req: {
|
|
64
|
-
question: AskUserQuestion;
|
|
65
|
-
options: PermissionOption[];
|
|
66
|
-
}) => Promise<{
|
|
67
|
-
outcome: "selected";
|
|
68
|
-
optionId: string;
|
|
69
|
-
} | {
|
|
70
|
-
outcome: "cancelled";
|
|
71
|
-
}>, signal: AbortSignal): Promise<{
|
|
72
|
-
behavior: "allow";
|
|
73
|
-
updatedInput: Record<string, unknown>;
|
|
74
|
-
} | {
|
|
75
|
-
behavior: "deny";
|
|
76
|
-
message: string;
|
|
77
|
-
}>;
|
|
78
|
-
//# sourceMappingURL=ask-user-question-fallback.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ask-user-question-fallback.d.ts","sourceRoot":"","sources":["../src/ask-user-question-fallback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAA2B,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEjF;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAO/F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,eAAe,GAAG,gBAAgB,EAAE,CAYvF;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,kCAAkC,CACtD,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,iBAAiB,EAAE,CAAC,GAAG,EAAE;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B,KAAK,OAAO,CAAC;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC,EACnF,MAAM,EAAE,WAAW,GAClB,OAAO,CACN;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAC5D;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CACxC,CAyBA"}
|