@agentclientprotocol/claude-agent-acp 0.29.0 → 0.29.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/dist/acp-agent.d.ts +6 -0
- package/dist/acp-agent.d.ts.map +1 -1
- package/dist/acp-agent.js +120 -27
- package/package.json +3 -3
package/dist/acp-agent.d.ts
CHANGED
|
@@ -39,6 +39,12 @@ type Session = {
|
|
|
39
39
|
nextPendingOrder: number;
|
|
40
40
|
abortController: AbortController;
|
|
41
41
|
emitRawSDKMessages: boolean | SDKMessageFilter[];
|
|
42
|
+
/** Context window size of the last top-level assistant model, carried across
|
|
43
|
+
* prompts so mid-stream usage_update notifications report a correct `size`
|
|
44
|
+
* before the turn's first result message arrives. Defaults to
|
|
45
|
+
* DEFAULT_CONTEXT_WINDOW, refreshed from each result's modelUsage, and
|
|
46
|
+
* invalidated when the user switches the session's model. */
|
|
47
|
+
contextWindowSize: number;
|
|
42
48
|
};
|
|
43
49
|
type BackgroundTerminal = {
|
|
44
50
|
handle: TerminalHandle;
|
package/dist/acp-agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acp-agent.d.ts","sourceRoot":"","sources":["../src/acp-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,mBAAmB,EACnB,mBAAmB,EAGnB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EAEnB,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EAEpB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,6BAA6B,EAC7B,8BAA8B,EAC9B,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EAEtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,UAAU,EAMV,OAAO,EACP,cAAc,EACd,KAAK,EAEL,0BAA0B,
|
|
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
|
@@ -20,6 +20,13 @@ function sanitizeTitle(text) {
|
|
|
20
20
|
}
|
|
21
21
|
return sanitized.slice(0, MAX_TITLE_LENGTH - 1) + "…";
|
|
22
22
|
}
|
|
23
|
+
const ZERO_USAGE = Object.freeze({
|
|
24
|
+
input_tokens: 0,
|
|
25
|
+
output_tokens: 0,
|
|
26
|
+
cache_read_input_tokens: 0,
|
|
27
|
+
cache_creation_input_tokens: 0,
|
|
28
|
+
});
|
|
29
|
+
const DEFAULT_CONTEXT_WINDOW = 200000;
|
|
23
30
|
/** Compute a stable fingerprint of the session-defining params so we can
|
|
24
31
|
* detect when a loadSession/resumeSession call requires tearing down and
|
|
25
32
|
* recreating the underlying Query process. MCP servers are sorted by name
|
|
@@ -282,8 +289,8 @@ export class ClaudeAcpAgent {
|
|
|
282
289
|
cachedWriteTokens: 0,
|
|
283
290
|
};
|
|
284
291
|
let lastAssistantTotalUsage = null;
|
|
292
|
+
let lastAssistantUsage = null;
|
|
285
293
|
let lastAssistantModel = null;
|
|
286
|
-
let lastContextWindowSize = 200000;
|
|
287
294
|
const userMessage = promptToClaude(params);
|
|
288
295
|
const promptUuid = randomUUID();
|
|
289
296
|
userMessage.uuid = promptUuid;
|
|
@@ -354,12 +361,13 @@ export class ClaudeAcpAgent {
|
|
|
354
361
|
// "944k/1m" right after the user sees "Compacting completed",
|
|
355
362
|
// which is confusing and wrong.
|
|
356
363
|
lastAssistantTotalUsage = 0;
|
|
364
|
+
lastAssistantUsage = null;
|
|
357
365
|
await this.client.sessionUpdate({
|
|
358
366
|
sessionId: message.session_id,
|
|
359
367
|
update: {
|
|
360
368
|
sessionUpdate: "usage_update",
|
|
361
369
|
used: 0,
|
|
362
|
-
size:
|
|
370
|
+
size: session.contextWindowSize,
|
|
363
371
|
},
|
|
364
372
|
});
|
|
365
373
|
await this.client.sessionUpdate({
|
|
@@ -416,8 +424,13 @@ export class ClaudeAcpAgent {
|
|
|
416
424
|
const matchingModelUsage = lastAssistantModel
|
|
417
425
|
? getMatchingModelUsage(message.modelUsage, lastAssistantModel)
|
|
418
426
|
: null;
|
|
419
|
-
|
|
420
|
-
|
|
427
|
+
// Only overwrite when we have an authoritative value — a miss
|
|
428
|
+
// (e.g. a turn with no top-level assistant message) would
|
|
429
|
+
// otherwise discard the window learned on a prior turn and
|
|
430
|
+
// leave the next prompt's mid-stream updates reporting 200k.
|
|
431
|
+
if (matchingModelUsage) {
|
|
432
|
+
session.contextWindowSize = matchingModelUsage.contextWindow;
|
|
433
|
+
}
|
|
421
434
|
// Send usage_update notification
|
|
422
435
|
if (lastAssistantTotalUsage !== null) {
|
|
423
436
|
await this.client.sessionUpdate({
|
|
@@ -425,7 +438,7 @@ export class ClaudeAcpAgent {
|
|
|
425
438
|
update: {
|
|
426
439
|
sessionUpdate: "usage_update",
|
|
427
440
|
used: lastAssistantTotalUsage,
|
|
428
|
-
size: contextWindowSize,
|
|
441
|
+
size: session.contextWindowSize,
|
|
429
442
|
cost: {
|
|
430
443
|
amount: message.total_cost_usd,
|
|
431
444
|
currency: "USD",
|
|
@@ -484,6 +497,53 @@ export class ClaudeAcpAgent {
|
|
|
484
497
|
break;
|
|
485
498
|
}
|
|
486
499
|
case "stream_event": {
|
|
500
|
+
if (message.parent_tool_use_id === null &&
|
|
501
|
+
(message.event.type === "message_start" || message.event.type === "message_delta")) {
|
|
502
|
+
if (message.event.type === "message_start") {
|
|
503
|
+
lastAssistantUsage = snapshotFromUsage(message.event.message.usage);
|
|
504
|
+
const model = message.event.message.model;
|
|
505
|
+
if (model && model !== "<synthetic>") {
|
|
506
|
+
lastAssistantModel = model;
|
|
507
|
+
// Only upgrade from the default — once a `result` has given
|
|
508
|
+
// us an authoritative window, trust it over the heuristic.
|
|
509
|
+
// Model switches invalidate the cached window via
|
|
510
|
+
// `syncSessionConfigState`, which resets us back to the
|
|
511
|
+
// default so this branch runs again for the new model.
|
|
512
|
+
if (session.contextWindowSize === DEFAULT_CONTEXT_WINDOW) {
|
|
513
|
+
const inferred = inferContextWindowFromModel(model);
|
|
514
|
+
if (inferred !== null) {
|
|
515
|
+
session.contextWindowSize = inferred;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
const usage = message.event.usage;
|
|
522
|
+
const prev = lastAssistantUsage ?? ZERO_USAGE;
|
|
523
|
+
// Per Anthropic API, message_delta usage fields are *cumulative*;
|
|
524
|
+
// nullable fields (input_tokens and the cache fields) fall back
|
|
525
|
+
// to the prior snapshot when the server omits them from this
|
|
526
|
+
// delta. Only output_tokens is guaranteed non-null.
|
|
527
|
+
lastAssistantUsage = {
|
|
528
|
+
input_tokens: usage.input_tokens ?? prev.input_tokens,
|
|
529
|
+
output_tokens: usage.output_tokens,
|
|
530
|
+
cache_read_input_tokens: usage.cache_read_input_tokens ?? prev.cache_read_input_tokens,
|
|
531
|
+
cache_creation_input_tokens: usage.cache_creation_input_tokens ?? prev.cache_creation_input_tokens,
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
const nextUsage = totalTokens(lastAssistantUsage);
|
|
535
|
+
if (nextUsage !== lastAssistantTotalUsage) {
|
|
536
|
+
lastAssistantTotalUsage = nextUsage;
|
|
537
|
+
await this.client.sessionUpdate({
|
|
538
|
+
sessionId: params.sessionId,
|
|
539
|
+
update: {
|
|
540
|
+
sessionUpdate: "usage_update",
|
|
541
|
+
used: nextUsage,
|
|
542
|
+
size: session.contextWindowSize,
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
}
|
|
487
547
|
for (const notification of streamEventToAcpNotifications(message, params.sessionId, this.toolUseCache, this.client, this.logger, {
|
|
488
548
|
clientCapabilities: this.clientCapabilities,
|
|
489
549
|
cwd: session.cwd,
|
|
@@ -516,27 +576,16 @@ export class ClaudeAcpAgent {
|
|
|
516
576
|
break;
|
|
517
577
|
}
|
|
518
578
|
}
|
|
519
|
-
//
|
|
520
|
-
//
|
|
521
|
-
//
|
|
522
|
-
//
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
messageWithUsage.usage.output_tokens +
|
|
530
|
-
messageWithUsage.usage.cache_read_input_tokens +
|
|
531
|
-
messageWithUsage.usage.cache_creation_input_tokens;
|
|
532
|
-
}
|
|
533
|
-
// Track the current top-level model for context window size lookup
|
|
534
|
-
// (exclude subagent messages to stay in sync with lastAssistantTotalUsage)
|
|
535
|
-
if (message.type === "assistant" &&
|
|
536
|
-
message.parent_tool_use_id === null &&
|
|
537
|
-
message.message.model &&
|
|
538
|
-
message.message.model !== "<synthetic>") {
|
|
539
|
-
lastAssistantModel = message.message.model;
|
|
579
|
+
// Snapshot the latest top-level assistant usage and model so the
|
|
580
|
+
// next `result` can emit a usage_update tied to the right context
|
|
581
|
+
// window. Subagent messages are excluded to keep the snapshot
|
|
582
|
+
// aligned with what the user's current selection is producing.
|
|
583
|
+
if (message.type === "assistant" && message.parent_tool_use_id === null) {
|
|
584
|
+
lastAssistantUsage = snapshotFromUsage(message.message.usage);
|
|
585
|
+
lastAssistantTotalUsage = totalTokens(lastAssistantUsage);
|
|
586
|
+
if (message.message.model && message.message.model !== "<synthetic>") {
|
|
587
|
+
lastAssistantModel = message.message.model;
|
|
588
|
+
}
|
|
540
589
|
}
|
|
541
590
|
// Slash commands like /compact can generate invalid output... doesn't match
|
|
542
591
|
// their own docs: https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-slash-commands#%2Fcompact-compact-conversation-history
|
|
@@ -944,6 +993,13 @@ export class ClaudeAcpAgent {
|
|
|
944
993
|
session.modes = { ...session.modes, currentModeId: value };
|
|
945
994
|
}
|
|
946
995
|
else if (configId === "model") {
|
|
996
|
+
if (session.models.currentModelId !== value) {
|
|
997
|
+
// The cached context window was learned for the previous model; reset
|
|
998
|
+
// to the new model's heuristic so mid-stream updates between now and
|
|
999
|
+
// the next `result` reflect the user's selection instead of the old
|
|
1000
|
+
// model's window.
|
|
1001
|
+
session.contextWindowSize = inferContextWindowFromModel(value) ?? DEFAULT_CONTEXT_WINDOW;
|
|
1002
|
+
}
|
|
947
1003
|
session.models = { ...session.models, currentModelId: value };
|
|
948
1004
|
}
|
|
949
1005
|
}
|
|
@@ -1150,7 +1206,7 @@ export class ClaudeAcpAgent {
|
|
|
1150
1206
|
{
|
|
1151
1207
|
id: "auto",
|
|
1152
1208
|
name: "Auto",
|
|
1153
|
-
description: "Use a model classifier to approve/deny permission prompts
|
|
1209
|
+
description: "Use a model classifier to approve/deny permission prompts",
|
|
1154
1210
|
},
|
|
1155
1211
|
{
|
|
1156
1212
|
id: "default",
|
|
@@ -1207,6 +1263,7 @@ export class ClaudeAcpAgent {
|
|
|
1207
1263
|
nextPendingOrder: 0,
|
|
1208
1264
|
abortController,
|
|
1209
1265
|
emitRawSDKMessages: sessionMeta?.claudeCode?.emitRawSDKMessages ?? false,
|
|
1266
|
+
contextWindowSize: inferContextWindowFromModel(models.currentModelId) ?? DEFAULT_CONTEXT_WINDOW,
|
|
1210
1267
|
};
|
|
1211
1268
|
return {
|
|
1212
1269
|
sessionId,
|
|
@@ -1235,6 +1292,32 @@ function sessionUsage(session) {
|
|
|
1235
1292
|
session.accumulatedUsage.cachedWriteTokens,
|
|
1236
1293
|
};
|
|
1237
1294
|
}
|
|
1295
|
+
/** Sum all four fields as a proxy for post-turn context occupancy: the current
|
|
1296
|
+
* turn's output becomes next turn's input. Per the Anthropic API, input_tokens
|
|
1297
|
+
* excludes cache tokens — cache_read and cache_creation are reported
|
|
1298
|
+
* separately — so summing all four is not double-counting. */
|
|
1299
|
+
function totalTokens(usage) {
|
|
1300
|
+
return (usage.input_tokens +
|
|
1301
|
+
usage.output_tokens +
|
|
1302
|
+
usage.cache_read_input_tokens +
|
|
1303
|
+
usage.cache_creation_input_tokens);
|
|
1304
|
+
}
|
|
1305
|
+
/** Project a nullable API usage object into our non-null snapshot shape.
|
|
1306
|
+
* Both SDK message_start and assistant message `usage` have `number | null`
|
|
1307
|
+
* cache fields; we coerce absent values to 0 so `totalTokens` never hits
|
|
1308
|
+
* NaN. `input_tokens`/`output_tokens` are typed `number` by the SDK but
|
|
1309
|
+
* synthetic or third-party-backend stream events have been observed emitting
|
|
1310
|
+
* them as null/undefined — coerce those too so a malformed upstream event
|
|
1311
|
+
* can't leak NaN into the wire `used` field. Delta events have different
|
|
1312
|
+
* semantics (cumulative + prev fallback) and are handled inline. */
|
|
1313
|
+
function snapshotFromUsage(usage) {
|
|
1314
|
+
return {
|
|
1315
|
+
input_tokens: usage.input_tokens ?? 0,
|
|
1316
|
+
output_tokens: usage.output_tokens ?? 0,
|
|
1317
|
+
cache_read_input_tokens: usage.cache_read_input_tokens ?? 0,
|
|
1318
|
+
cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1238
1321
|
function createEnvForGateway(gatewayMeta) {
|
|
1239
1322
|
if (!gatewayMeta) {
|
|
1240
1323
|
return {};
|
|
@@ -1771,6 +1854,16 @@ function commonPrefixLength(a, b) {
|
|
|
1771
1854
|
}
|
|
1772
1855
|
return i;
|
|
1773
1856
|
}
|
|
1857
|
+
/** Best-effort first guess of a model's context window from its ID, used only
|
|
1858
|
+
* until a `result` message arrives with the authoritative `modelUsage` value.
|
|
1859
|
+
* Anthropic 1M-context variants encode "1m" as a distinct token in the SDK
|
|
1860
|
+
* model ID (e.g., "claude-opus-4-6-1m"), which `\b1m\b` catches without also
|
|
1861
|
+
* matching things like "10m" or embedded substrings. */
|
|
1862
|
+
function inferContextWindowFromModel(model) {
|
|
1863
|
+
if (/\b1m\b/i.test(model))
|
|
1864
|
+
return 1_000_000;
|
|
1865
|
+
return null;
|
|
1866
|
+
}
|
|
1774
1867
|
function getMatchingModelUsage(modelUsage, currentModel) {
|
|
1775
1868
|
let bestKey = null;
|
|
1776
1869
|
let bestLen = 0;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.29.
|
|
6
|
+
"version": "0.29.2",
|
|
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",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"license": "Apache-2.0",
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@agentclientprotocol/sdk": "0.19.0",
|
|
64
|
-
"@anthropic-ai/claude-agent-sdk": "0.2.
|
|
64
|
+
"@anthropic-ai/claude-agent-sdk": "0.2.112",
|
|
65
65
|
"zod": "^3.25.0 || ^4.0.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"globals": "17.5.0",
|
|
76
76
|
"prettier": "3.8.3",
|
|
77
77
|
"ts-node": "10.9.2",
|
|
78
|
-
"typescript": "6.0.
|
|
78
|
+
"typescript": "6.0.3",
|
|
79
79
|
"vitest": "4.1.4"
|
|
80
80
|
}
|
|
81
81
|
}
|