@agentclientprotocol/claude-agent-acp 0.48.0 → 0.50.0

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.
@@ -253,10 +253,15 @@ export declare function describeAlwaysAllow(suggestions: PermissionUpdate[] | un
253
253
  */
254
254
  export interface AcpClient {
255
255
  sessionUpdate(params: SessionNotification): Promise<void>;
256
- requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse>;
256
+ /** `signal`, when aborted, sends `$/cancel_request` for the in-flight
257
+ * permission request so the client can dismiss its prompt (and settle our
258
+ * await) instead of leaving the dialog open after the turn was cancelled. */
259
+ requestPermission(params: RequestPermissionRequest, signal?: AbortSignal): Promise<RequestPermissionResponse>;
257
260
  readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse>;
258
261
  writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse>;
259
- unstable_createElicitation(params: CreateElicitationRequest): Promise<CreateElicitationResponse>;
262
+ /** `signal`, when aborted, sends `$/cancel_request` for the in-flight
263
+ * elicitation so the client can dismiss its prompt and settle our await. */
264
+ unstable_createElicitation(params: CreateElicitationRequest, signal?: AbortSignal): Promise<CreateElicitationResponse>;
260
265
  unstable_completeElicitation(params: CompleteElicitationNotification): Promise<void>;
261
266
  /** Send a custom (extension) notification, e.g. `_claude/sdkMessage`. */
262
267
  extNotification(method: string, params: Record<string, unknown>): Promise<void>;
@@ -325,6 +330,14 @@ export declare class ClaudeAcpAgent {
325
330
  private replaySessionHistory;
326
331
  readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse>;
327
332
  writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse>;
333
+ /** Forward a permission request to the client, wiring the tool call's
334
+ * `signal` through as a `cancellationSignal`. When the turn is cancelled
335
+ * while the client's prompt is still open the signal aborts, the SDK sends
336
+ * `$/cancel_request`, and the client settles the request (a `cancelled`
337
+ * outcome or a `requestCancelled` rejection). Either way we surface the same
338
+ * "Tool use aborted" the callers already expect, so a cancelled dialog no
339
+ * longer leaves the `await` hanging. */
340
+ private requestPermissionFromClient;
328
341
  canUseTool(sessionId: string): CanUseTool;
329
342
  /**
330
343
  * Handle elicitation requests that originate from MCP servers by forwarding
@@ -394,6 +407,19 @@ export declare function streamEventToAcpNotifications(message: SDKPartialAssista
394
407
  taskState?: TaskState;
395
408
  messageId?: string;
396
409
  }): SessionNotification[];
410
+ /** Run a `session/prompt` while honoring `$/cancel_request` for it. ACP clients
411
+ * normally stop a turn with the `session/cancel` notification, but `signal`
412
+ * (the prompt request's abort signal) also fires when the client sends the
413
+ * generic `$/cancel_request` for this prompt — the protocol's complementary
414
+ * cancellation fallback. Route that to the same `agent.cancel` path so a client
415
+ * using only the generic mechanism still stops the turn (and the prompt
416
+ * resolves "cancelled" instead of running to completion).
417
+ *
418
+ * The listener is scoped to this call: once the prompt settles it is removed,
419
+ * so a later teardown-time abort of the (per-request) signal can't cancel a
420
+ * subsequent turn. `signal` also aborts on connection close, in which case
421
+ * cancelling the in-flight turn is the desired behavior anyway. */
422
+ export declare function runPromptWithCancellation(agent: Pick<ClaudeAcpAgent, "prompt" | "cancel" | "logger">, params: PromptRequest, signal: AbortSignal): Promise<PromptResponse>;
397
423
  export declare function runAcp(): {
398
424
  connection: import("@agentclientprotocol/sdk").AgentConnection;
399
425
  agent: ClaudeAcpAgent;
@@ -1 +1 @@
1
- {"version":3,"file":"acp-agent.d.ts","sourceRoot":"","sources":["../src/acp-agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acp-agent.d.ts","sourceRoot":"","sources":["../src/acp-agent.ts"],"names":[],"mappings":"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"}
package/dist/acp-agent.js CHANGED
@@ -253,14 +253,17 @@ export function describeAlwaysAllow(suggestions, toolName) {
253
253
  * construction.
254
254
  */
255
255
  class ClientConnection {
256
+ ctx;
256
257
  constructor(ctx) {
257
258
  this.ctx = ctx;
258
259
  }
259
260
  sessionUpdate(params) {
260
261
  return this.ctx.notify(methods.client.session.update, params);
261
262
  }
262
- requestPermission(params) {
263
- return this.ctx.request(methods.client.session.requestPermission, params);
263
+ requestPermission(params, signal) {
264
+ return this.ctx.request(methods.client.session.requestPermission, params, {
265
+ cancellationSignal: signal,
266
+ });
264
267
  }
265
268
  readTextFile(params) {
266
269
  return this.ctx.request(methods.client.fs.readTextFile, params);
@@ -268,8 +271,10 @@ class ClientConnection {
268
271
  writeTextFile(params) {
269
272
  return this.ctx.request(methods.client.fs.writeTextFile, params);
270
273
  }
271
- unstable_createElicitation(params) {
272
- return this.ctx.request(methods.client.elicitation.create, params);
274
+ unstable_createElicitation(params, signal) {
275
+ return this.ctx.request(methods.client.elicitation.create, params, {
276
+ cancellationSignal: signal,
277
+ });
273
278
  }
274
279
  unstable_completeElicitation(params) {
275
280
  return this.ctx.notify(methods.client.elicitation.complete, params);
@@ -279,11 +284,16 @@ class ClientConnection {
279
284
  }
280
285
  }
281
286
  export class ClaudeAcpAgent {
287
+ sessions;
288
+ client;
289
+ clientCapabilities;
290
+ logger;
291
+ gatewayAuthRequest;
292
+ /** Grace period before a `session/cancel` forces a wedged prompt loop to
293
+ * return "cancelled". See {@link DEFAULT_FORCE_CANCEL_GRACE_MS}. Mutable so
294
+ * tests can shrink it. */
295
+ forceCancelGraceMs = DEFAULT_FORCE_CANCEL_GRACE_MS;
282
296
  constructor(client, logger) {
283
- /** Grace period before a `session/cancel` forces a wedged prompt loop to
284
- * return "cancelled". See {@link DEFAULT_FORCE_CANCEL_GRACE_MS}. Mutable so
285
- * tests can shrink it. */
286
- this.forceCancelGraceMs = DEFAULT_FORCE_CANCEL_GRACE_MS;
287
297
  this.sessions = {};
288
298
  this.client = client;
289
299
  this.logger = logger ?? console;
@@ -577,12 +587,17 @@ export class ClaudeAcpAgent {
577
587
  // (whose delta events don't carry it) can all be tagged with the same,
578
588
  // replay-stable id.
579
589
  let currentStreamMessageId;
580
- // Per-message-id record of which assistant content actually streamed live
581
- // via `stream_event` deltas, split by block type, so the consolidated
582
- // `assistant` message can drop the duplicate blocks that already reached the
583
- // client as chunks while still forwarding any that a non-streaming gateway
584
- const streamedTextIds = new Set();
585
- const streamedThinkingIds = new Set();
590
+ // The text/thinking blocks that have actually streamed live as
591
+ // `stream_event` deltas for the message the next consolidated `assistant`
592
+ // will repeat, in stream order, each accumulated to its full streamed text.
593
+ // The consolidated handler diffs each assembled block against these and
594
+ // forwards only the un-streamed remainder — nothing if it streamed in full
595
+ // (the common case), the whole block if it never streamed (a non-streaming
596
+ // gateway), or just the tail if the stream was cut short mid-block. Matching
597
+ // on content rather than the Anthropic message id makes dedupe robust to
598
+ // gateways that don't carry a stable/matching id across the stream and the
599
+ // consolidated message. Reset after each consolidated message consumes it.
600
+ const streamedBlocks = [];
586
601
  // Stop reason accumulated for the active turn (result subtype, refusal,
587
602
  // max_tokens, …). Reset per turn; read when the turn settles at idle.
588
603
  let stopReason = "end_turn";
@@ -593,12 +608,14 @@ export class ClaudeAcpAgent {
593
608
  lastAssistantError = undefined;
594
609
  lastRefusalExplanation = null;
595
610
  compactionInProgress = false;
596
- // Do NOT reset currentStreamMessageId here. `message_start` sets it per
597
- // message; clearing it on turn activation drops the id for any block that
598
- // streams after a mid-message activation (the replayed user echo with
599
- // --replay-user-messages), so those ids never enter streamedTextIds and the
600
- // consolidated assistant message re-emits already-streamed text as a
601
- // duplicate. #785 stopped resetting streamedTextIds here but left this line.
611
+ // Do NOT reset currentStreamMessageId or streamedBlocks here. Turn
612
+ // activation can fire mid-message (the replayed user echo with
613
+ // --replay-user-messages lands between a message's blocks); clearing the
614
+ // streamed-content record on activation would drop the blocks that
615
+ // streamed before the echo, so the consolidated assistant message would
616
+ // re-emit them as duplicates. streamedBlocks is bounded instead by being
617
+ // cleared when each consolidated message consumes it. #785 stopped
618
+ // resetting the streamed-content tracking here but left this line.
602
619
  stopReason = "end_turn";
603
620
  session.accumulatedUsage = {
604
621
  inputTokens: 0,
@@ -1189,20 +1206,50 @@ export class ClaudeAcpAgent {
1189
1206
  // it) can all be tagged with the same, replay-stable id.
1190
1207
  if (message.event.type === "message_start") {
1191
1208
  currentStreamMessageId = message.event.message.id || undefined;
1209
+ // A new top-level message starts: clear any streamed-content
1210
+ // residue from a prior message that never reached its
1211
+ // consolidated reset — a cancelled turn breaks out before the
1212
+ // reset, and the synthetic-auth/system/local-command paths
1213
+ // `break` early too. Block indices restart at 0 each message, so
1214
+ // leftover entries would otherwise collide with this message's
1215
+ // blocks and re-emit (or truncate) already-streamed text. Gated on
1216
+ // `parent_tool_use_id === null` so a subagent stream can't clear
1217
+ // the top-level record. Fires once, before any of this message's
1218
+ // blocks, so it doesn't disturb the mid-message turn-activation
1219
+ // path the way resetting on turn activation would.
1220
+ if (message.parent_tool_use_id === null) {
1221
+ streamedBlocks.length = 0;
1222
+ }
1192
1223
  }
1193
- // Record that this top-level message id actually streamed text/
1194
- // thinking, so the `assistant` case below knows its assembled blocks
1195
- // are duplicates (filter them) rather than the only copy (forward
1196
- // them). Gated on `parent_tool_use_id === null` so a subagent stream
1197
- // can't attribute its content to the top-level message id.
1198
- if (currentStreamMessageId &&
1199
- message.parent_tool_use_id === null &&
1224
+ // Accumulate the text/thinking actually streamed live, so the
1225
+ // `assistant` case below can diff its assembled blocks against what
1226
+ // already reached the client as chunks and forward only the
1227
+ // remainder. Gated on `parent_tool_use_id === null` so a subagent
1228
+ // stream can't attribute its content to the top-level message.
1229
+ // Contiguous deltas of the same block (same index and type) extend
1230
+ // the current entry; anything else opens a new one.
1231
+ if (message.parent_tool_use_id === null &&
1200
1232
  message.event.type === "content_block_delta") {
1201
- if (message.event.delta.type === "text_delta") {
1202
- streamedTextIds.add(currentStreamMessageId);
1203
- }
1204
- else if (message.event.delta.type === "thinking_delta") {
1205
- streamedThinkingIds.add(currentStreamMessageId);
1233
+ const delta = message.event.delta;
1234
+ const chunk = delta.type === "text_delta"
1235
+ ? { type: "text", text: delta.text }
1236
+ : delta.type === "thinking_delta"
1237
+ ? { type: "thinking", text: delta.thinking }
1238
+ : undefined;
1239
+ // Skip empty deltas (some gateways emit empty thinking chunks —
1240
+ // #793): appending "" is a no-op, but pushing a "" entry would
1241
+ // create a block the consolidated handler's `text.length > 0`
1242
+ // guard can never consume, stalling the diff cursor and
1243
+ // re-emitting the next block as a duplicate.
1244
+ if (chunk && chunk.text.length > 0) {
1245
+ const index = message.event.index;
1246
+ const last = streamedBlocks[streamedBlocks.length - 1];
1247
+ if (last && last.index === index && last.type === chunk.type) {
1248
+ last.text += chunk.text;
1249
+ }
1250
+ else {
1251
+ streamedBlocks.push({ index, type: chunk.type, text: chunk.text });
1252
+ }
1206
1253
  }
1207
1254
  }
1208
1255
  if (message.parent_tool_use_id === null &&
@@ -1376,40 +1423,65 @@ export class ClaudeAcpAgent {
1376
1423
  }
1377
1424
  let content;
1378
1425
  if (message.type === "assistant" && message.parent_tool_use_id === null) {
1379
- // Top-level assistant message: drop text/thinking blocks already
1380
- // streamed live as chunks, and forward (as a fallback) any that were
1381
- // not, so non-streaming gateways still deliver the final answer.
1382
- const id = messageIdForGrouping(message);
1383
- content = message.message.content.filter((item) => {
1384
- // Non-text blocks (tool_use, etc.) always pass through; their own
1385
- // dedupe (`toolUseCache`) collapses the streamed/assembled pair.
1426
+ // Top-level assistant message: each text/thinking block may have
1427
+ // already been streamed live as deltas. Diff each against what
1428
+ // streamed (`streamedBlocks`, in document order) and forward only
1429
+ // the un-streamed remainder — nothing if it streamed in full (the
1430
+ // common case), the whole block if it never streamed (a
1431
+ // non-streaming gateway), or just the tail if the stream was cut
1432
+ // short mid-block. `streamPos` walks the streamed blocks in step
1433
+ // with the assembled text/thinking blocks; tool_use and other
1434
+ // blocks pass through untouched (their own `toolUseCache` collapses
1435
+ // the streamed/assembled pair) without advancing it.
1436
+ const blocks = message.message.content;
1437
+ const kept = [];
1438
+ let streamPos = 0;
1439
+ for (const item of blocks) {
1386
1440
  if (item.type !== "text" && item.type !== "thinking") {
1387
- return true;
1441
+ kept.push(item);
1442
+ continue;
1388
1443
  }
1389
- // Already delivered live as a chunk of this exact type — drop the
1390
- // duplicate. Checked per type so streaming one (e.g. text) doesn't
1391
- // suppress an un-streamed block of the other (e.g. thinking).
1392
- const streamedLive = id !== undefined &&
1393
- (item.type === "text" ? streamedTextIds : streamedThinkingIds).has(id);
1394
- if (streamedLive) {
1395
- return false;
1444
+ const full = item.type === "text" ? item.text : item.thinking;
1445
+ // Empty assembled blocks carry nothing (some gateways emit an
1446
+ // empty `thinking` block before the real text) — drop them.
1447
+ if (full.length === 0) {
1448
+ continue;
1396
1449
  }
1397
- // Empty assembled blocks carry nothing (some gateways emit an empty
1398
- // `thinking` block before the real text) — don't forward stray
1399
- // empty chunks.
1400
- const text = item.type === "text" ? item.text : item.thinking;
1401
- if (text.length === 0) {
1402
- return false;
1450
+ // A streamed block of the same type whose accumulated text is a
1451
+ // prefix of this one was already (at least partly) delivered as
1452
+ // chunks; consume it and forward only what's left. A non-empty
1453
+ // streamed text is required so an empty/aborted streamed block
1454
+ // doesn't swallow the assembled copy.
1455
+ const streamed = streamedBlocks[streamPos];
1456
+ if (streamed &&
1457
+ streamed.type === item.type &&
1458
+ streamed.text.length > 0 &&
1459
+ full.startsWith(streamed.text)) {
1460
+ streamPos++;
1461
+ const remainder = full.slice(streamed.text.length);
1462
+ if (remainder.length === 0) {
1463
+ continue;
1464
+ }
1465
+ // Overwrite in place with just the un-streamed tail (the
1466
+ // assembled message isn't read again after this) so the block
1467
+ // keeps its exact SDK type.
1468
+ if (item.type === "text") {
1469
+ item.text = remainder;
1470
+ }
1471
+ else {
1472
+ item.thinking = remainder;
1473
+ }
1474
+ kept.push(item);
1475
+ continue;
1403
1476
  }
1404
- return true;
1405
- });
1406
- // The consolidated message is the last place this id is needed for
1407
- // dedupe — drop it so the streamed-id sets stay bounded to in-flight
1408
- // streams rather than growing for the session's whole life.
1409
- if (id !== undefined) {
1410
- streamedTextIds.delete(id);
1411
- streamedThinkingIds.delete(id);
1477
+ // Not matched: never streamed (or the stream diverged from the
1478
+ // assembled text) — forward the block in full.
1479
+ kept.push(item);
1412
1480
  }
1481
+ content = kept;
1482
+ // Consumed: reset so the next message's blocks accumulate fresh and
1483
+ // the record stays bounded to the in-flight message.
1484
+ streamedBlocks.length = 0;
1413
1485
  }
1414
1486
  else if (message.type === "assistant") {
1415
1487
  // Subagent assistant message (`parent_tool_use_id !== null`). It is
@@ -1794,6 +1866,24 @@ export class ClaudeAcpAgent {
1794
1866
  const response = await this.client.writeTextFile(params);
1795
1867
  return response;
1796
1868
  }
1869
+ /** Forward a permission request to the client, wiring the tool call's
1870
+ * `signal` through as a `cancellationSignal`. When the turn is cancelled
1871
+ * while the client's prompt is still open the signal aborts, the SDK sends
1872
+ * `$/cancel_request`, and the client settles the request (a `cancelled`
1873
+ * outcome or a `requestCancelled` rejection). Either way we surface the same
1874
+ * "Tool use aborted" the callers already expect, so a cancelled dialog no
1875
+ * longer leaves the `await` hanging. */
1876
+ async requestPermissionFromClient(params, signal) {
1877
+ try {
1878
+ return await this.client.requestPermission(params, signal);
1879
+ }
1880
+ catch (error) {
1881
+ if (signal.aborted) {
1882
+ throw new Error("Tool use aborted", { cause: error });
1883
+ }
1884
+ throw error;
1885
+ }
1886
+ }
1797
1887
  canUseTool(sessionId) {
1798
1888
  return async (toolName, toolInput, { signal, suggestions, toolUseID }) => {
1799
1889
  const alwaysAllowLabel = describeAlwaysAllow(suggestions, toolName);
@@ -1836,7 +1926,7 @@ export class ClaudeAcpAgent {
1836
1926
  // `buildAvailableModes`/`ALLOW_BYPASS`. The `plan` option is a
1837
1927
  // "keep planning" reject path; it's always present in `availableModes`.
1838
1928
  const options = optionsAll.filter((o) => session.modes.availableModes.some((m) => m.id === o.optionId));
1839
- const response = await this.client.requestPermission({
1929
+ const response = await this.requestPermissionFromClient({
1840
1930
  options,
1841
1931
  sessionId,
1842
1932
  toolCall: {
@@ -1844,7 +1934,7 @@ export class ClaudeAcpAgent {
1844
1934
  rawInput: toolInput,
1845
1935
  ...toolInfoFromToolUse({ name: toolName, input: toolInput, id: toolUseID }, supportsTerminalOutput, session?.cwd),
1846
1936
  },
1847
- });
1937
+ }, signal);
1848
1938
  if (signal.aborted || response.outcome?.outcome === "cancelled") {
1849
1939
  throw new Error("Tool use aborted");
1850
1940
  }
@@ -1887,7 +1977,7 @@ export class ClaudeAcpAgent {
1887
1977
  ],
1888
1978
  };
1889
1979
  }
1890
- const response = await this.client.requestPermission({
1980
+ const response = await this.requestPermissionFromClient({
1891
1981
  options: [
1892
1982
  {
1893
1983
  kind: "allow_always",
@@ -1903,7 +1993,7 @@ export class ClaudeAcpAgent {
1903
1993
  rawInput: toolInput,
1904
1994
  ...toolInfoFromToolUse({ name: toolName, input: toolInput, id: toolUseID }, supportsTerminalOutput, session?.cwd),
1905
1995
  },
1906
- });
1996
+ }, signal);
1907
1997
  if (signal.aborted || response.outcome?.outcome === "cancelled") {
1908
1998
  throw new Error("Tool use aborted");
1909
1999
  }
@@ -1953,13 +2043,18 @@ export class ClaudeAcpAgent {
1953
2043
  return { action: "decline" };
1954
2044
  }
1955
2045
  try {
1956
- const response = await this.client.unstable_createElicitation(createRequest);
2046
+ const response = await this.client.unstable_createElicitation(createRequest, signal);
1957
2047
  if (signal.aborted) {
1958
2048
  return { action: "cancel" };
1959
2049
  }
1960
2050
  return createElicitationResponseToElicitResult(response);
1961
2051
  }
1962
2052
  catch (error) {
2053
+ // A cancellation we requested (signal aborted) settles as a cancel, not
2054
+ // a hard decline — the elicitation was abandoned, not refused.
2055
+ if (signal.aborted) {
2056
+ return { action: "cancel" };
2057
+ }
1963
2058
  this.logger.error(`Failed to forward MCP elicitation: ${error}`);
1964
2059
  return { action: "decline" };
1965
2060
  }
@@ -1978,9 +2073,14 @@ export class ClaudeAcpAgent {
1978
2073
  const createRequest = askUserQuestionsToCreateRequest(questions, sessionId, toolUseID);
1979
2074
  let response;
1980
2075
  try {
1981
- response = await this.client.unstable_createElicitation(createRequest);
2076
+ response = await this.client.unstable_createElicitation(createRequest, signal);
1982
2077
  }
1983
2078
  catch (error) {
2079
+ // A cancellation we requested (signal aborted) settles as an aborted tool
2080
+ // use, matching the post-response check below.
2081
+ if (signal.aborted) {
2082
+ throw new Error("Tool use aborted", { cause: error });
2083
+ }
1984
2084
  this.logger.error(`Failed to present AskUserQuestion elicitation: ${error}`);
1985
2085
  return { behavior: "deny", message: "Could not present the question to the user." };
1986
2086
  }
@@ -2025,18 +2125,22 @@ export class ClaudeAcpAgent {
2025
2125
  session.configOptions = session.configOptions.map((o) => o.id === configId && typeof o.currentValue === "string" ? { ...o, currentValue: value } : o);
2026
2126
  }
2027
2127
  else if (configId === "model") {
2128
+ // `ModelInfo.supportsAutoMode` is the canonical SDK signal for clamping
2129
+ // modes below; its `displayName`/`description` also let us infer the
2130
+ // context window for semantic aliases (e.g. `default`) whose ID alone
2131
+ // carries no "1m" token.
2132
+ const newModelInfo = session.modelInfos.find((m) => m.value === value);
2028
2133
  if (session.models.currentModelId !== value) {
2029
2134
  // The cached context window was learned for the previous model; reset
2030
2135
  // to the new model's heuristic so mid-stream updates between now and
2031
2136
  // the next `result` reflect the user's selection instead of the old
2032
2137
  // model's window.
2033
- session.contextWindowSize = inferContextWindowFromModel(value) ?? DEFAULT_CONTEXT_WINDOW;
2138
+ session.contextWindowSize =
2139
+ inferContextWindowFromModel(value, newModelInfo?.displayName, newModelInfo?.description) ?? DEFAULT_CONTEXT_WINDOW;
2034
2140
  }
2035
2141
  session.models = { ...session.models, currentModelId: value };
2036
2142
  // Recompute availableModes for the new model and clamp the current
2037
2143
  // mode if the SDK no longer offers it (today: "auto" on Haiku).
2038
- // `ModelInfo.supportsAutoMode` is the canonical SDK signal.
2039
- const newModelInfo = session.modelInfos.find((m) => m.value === value);
2040
2144
  const newAvailableModes = buildAvailableModes(newModelInfo);
2041
2145
  // Capture BEFORE mutating session.modes so the log message reflects
2042
2146
  // the invalidated mode rather than "default".
@@ -2494,7 +2598,7 @@ export class ClaudeAcpAgent {
2494
2598
  currentAgent,
2495
2599
  abortController,
2496
2600
  emitRawSDKMessages: sessionMeta?.claudeCode?.emitRawSDKMessages ?? false,
2497
- contextWindowSize: inferContextWindowFromModel(models.currentModelId) ?? DEFAULT_CONTEXT_WINDOW,
2601
+ contextWindowSize: inferContextWindowFromModel(models.currentModelId, currentModelInfo?.displayName, currentModelInfo?.description) ?? DEFAULT_CONTEXT_WINDOW,
2498
2602
  taskState,
2499
2603
  toolUseCache: {},
2500
2604
  messageIdToUuid: new Map(),
@@ -3442,6 +3546,34 @@ export function streamEventToAcpNotifications(message, sessionId, toolUseCache,
3442
3546
  return [];
3443
3547
  }
3444
3548
  }
3549
+ /** Run a `session/prompt` while honoring `$/cancel_request` for it. ACP clients
3550
+ * normally stop a turn with the `session/cancel` notification, but `signal`
3551
+ * (the prompt request's abort signal) also fires when the client sends the
3552
+ * generic `$/cancel_request` for this prompt — the protocol's complementary
3553
+ * cancellation fallback. Route that to the same `agent.cancel` path so a client
3554
+ * using only the generic mechanism still stops the turn (and the prompt
3555
+ * resolves "cancelled" instead of running to completion).
3556
+ *
3557
+ * The listener is scoped to this call: once the prompt settles it is removed,
3558
+ * so a later teardown-time abort of the (per-request) signal can't cancel a
3559
+ * subsequent turn. `signal` also aborts on connection close, in which case
3560
+ * cancelling the in-flight turn is the desired behavior anyway. */
3561
+ export async function runPromptWithCancellation(agent, params, signal) {
3562
+ const onAbort = () => {
3563
+ // Fire-and-forget: nothing awaits this listener, so swallow (and log) any
3564
+ // rejection rather than surfacing it as an unhandled rejection.
3565
+ agent.cancel({ sessionId: params.sessionId }).catch((error) => {
3566
+ agent.logger.error(`Failed to cancel prompt via $/cancel_request: ${error}`);
3567
+ });
3568
+ };
3569
+ signal.addEventListener("abort", onAbort, { once: true });
3570
+ try {
3571
+ return await agent.prompt(params);
3572
+ }
3573
+ finally {
3574
+ signal.removeEventListener("abort", onAbort);
3575
+ }
3576
+ }
3445
3577
  export function runAcp() {
3446
3578
  const input = nodeToWebWritable(process.stdout);
3447
3579
  const output = nodeToWebReadable(process.stdin);
@@ -3466,7 +3598,7 @@ export function runAcp() {
3466
3598
  .onRequest(methods.agent.session.setMode, (ctx) => agent.setSessionMode(ctx.params))
3467
3599
  .onRequest(methods.agent.session.setConfigOption, (ctx) => agent.setSessionConfigOption(ctx.params))
3468
3600
  .onRequest(methods.agent.authenticate, (ctx) => agent.authenticate(ctx.params))
3469
- .onRequest(methods.agent.session.prompt, (ctx) => agent.prompt(ctx.params))
3601
+ .onRequest(methods.agent.session.prompt, (ctx) => runPromptWithCancellation(agent, ctx.params, ctx.signal))
3470
3602
  .onNotification(methods.agent.session.cancel, (ctx) => agent.cancel(ctx.params))
3471
3603
  .connect(stream);
3472
3604
  agent = new ClaudeAcpAgent(new ClientConnection(connection.client));
@@ -3479,14 +3611,21 @@ function commonPrefixLength(a, b) {
3479
3611
  }
3480
3612
  return i;
3481
3613
  }
3482
- /** Best-effort first guess of a model's context window from its ID, used only
3483
- * as a fallback when the SDK's authoritative `getContextUsage` is unavailable
3484
- * (and until a `result` message arrives with the `modelUsage` value).
3614
+ /** Best-effort first guess of a model's context window, used only as a
3615
+ * fallback when the SDK's authoritative `getContextUsage` is unavailable (and
3616
+ * until a `result` message arrives with the `modelUsage` value).
3617
+ *
3485
3618
  * Anthropic 1M-context variants encode "1m" as a distinct token in the SDK
3486
3619
  * model ID (e.g., "claude-opus-4-6-1m"), which `\b1m\b` catches without also
3487
- * matching things like "10m" or embedded substrings. */
3488
- function inferContextWindowFromModel(model) {
3489
- if (/\b1m\b/i.test(model))
3620
+ * matching things like "10m" or embedded substrings. Semantic aliases like
3621
+ * `default` carry no such token in the ID, but the SDK's human-facing
3622
+ * `displayName`/`description` do (e.g. "Opus 4.7 (1M context)"), so callers
3623
+ * pass those too — the same `\b1m\b` token appears in "1M context". The SDK's
3624
+ * `ModelInfo` exposes no structured context-window field, so this text scan is
3625
+ * the only pre-`result` signal available. A miss falls back to the default
3626
+ * window and is corrected by `result.modelUsage` within one turn. */
3627
+ function inferContextWindowFromModel(...texts) {
3628
+ if (texts.some((text) => text != null && /\b1m\b/i.test(text)))
3490
3629
  return 1_000_000;
3491
3630
  return null;
3492
3631
  }
package/dist/settings.js CHANGED
@@ -35,13 +35,16 @@ function getManagedSettingsPath() {
35
35
  * `filterEscalatingDefaultMode`, matching the CLI's trust policy.
36
36
  */
37
37
  export class SettingsManager {
38
+ cwd;
39
+ effective = {};
40
+ watchers = [];
41
+ onChange;
42
+ logger;
43
+ initialized = false;
44
+ disposed = false;
45
+ debounceTimer = null;
46
+ initPromise = null;
38
47
  constructor(cwd, options) {
39
- this.effective = {};
40
- this.watchers = [];
41
- this.initialized = false;
42
- this.disposed = false;
43
- this.debounceTimer = null;
44
- this.initPromise = null;
45
48
  this.cwd = cwd;
46
49
  this.onChange = options?.onChange;
47
50
  this.logger = options?.logger ?? console;
package/dist/utils.js CHANGED
@@ -2,11 +2,9 @@
2
2
  import { WritableStream, ReadableStream } from "node:stream/web";
3
3
  // Useful for bridging push-based and async-iterator-based code.
4
4
  export class Pushable {
5
- constructor() {
6
- this.queue = [];
7
- this.resolvers = [];
8
- this.done = false;
9
- }
5
+ queue = [];
6
+ resolvers = [];
7
+ done = false;
10
8
  push(item) {
11
9
  if (this.resolvers.length > 0) {
12
10
  const resolve = this.resolvers.shift();
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.48.0",
6
+ "version": "0.50.0",
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",
@@ -59,20 +59,24 @@
59
59
  },
60
60
  "author": "Zed Industries",
61
61
  "license": "Apache-2.0",
62
+ "engines": {
63
+ "node": ">=22"
64
+ },
62
65
  "dependencies": {
63
- "@agentclientprotocol/sdk": "0.28.1",
64
- "@anthropic-ai/claude-agent-sdk": "0.3.183",
66
+ "@agentclientprotocol/sdk": "0.29.0",
67
+ "@anthropic-ai/claude-agent-sdk": "0.3.186",
65
68
  "zod": "^3.25.0 || ^4.0.0"
66
69
  },
67
70
  "devDependencies": {
68
71
  "@anthropic-ai/sdk": "0.105.0",
69
72
  "@eslint/js": "10.0.1",
73
+ "@tsconfig/node22": "22.0.5",
70
74
  "@types/node": "26.0.0",
71
- "@typescript-eslint/eslint-plugin": "8.61.1",
72
- "@typescript-eslint/parser": "8.61.1",
75
+ "@typescript-eslint/eslint-plugin": "8.62.0",
76
+ "@typescript-eslint/parser": "8.62.0",
73
77
  "eslint": "10.5.0",
74
78
  "eslint-config-prettier": "10.1.8",
75
- "globals": "17.6.0",
79
+ "globals": "17.7.0",
76
80
  "prettier": "3.8.4",
77
81
  "ts-node": "10.9.2",
78
82
  "typescript": "6.0.3",