@posthog/agent 2.1.125 → 2.1.137
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/adapters/claude/conversion/tool-use-to-acp.d.ts +14 -28
- package/dist/adapters/claude/conversion/tool-use-to-acp.js +116 -164
- package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -1
- package/dist/adapters/claude/permissions/permission-options.js +33 -0
- package/dist/adapters/claude/permissions/permission-options.js.map +1 -1
- package/dist/adapters/claude/tools.js +21 -11
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/agent.js +1251 -640
- package/dist/agent.js.map +1 -1
- package/dist/posthog-api.js +2 -2
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +1295 -684
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +1278 -669
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +2 -2
- package/src/adapters/base-acp-agent.ts +6 -3
- package/src/adapters/claude/UPSTREAM.md +63 -0
- package/src/adapters/claude/claude-agent.ts +682 -421
- package/src/adapters/claude/conversion/sdk-to-acp.ts +249 -85
- package/src/adapters/claude/conversion/tool-use-to-acp.ts +174 -149
- package/src/adapters/claude/hooks.ts +53 -1
- package/src/adapters/claude/permissions/permission-handlers.ts +39 -21
- package/src/adapters/claude/session/commands.ts +13 -9
- package/src/adapters/claude/session/mcp-config.ts +2 -5
- package/src/adapters/claude/session/options.ts +58 -6
- package/src/adapters/claude/session/settings.ts +326 -0
- package/src/adapters/claude/tools.ts +1 -0
- package/src/adapters/claude/types.ts +38 -0
- package/src/execution-mode.ts +26 -10
- package/src/server/agent-server.test.ts +41 -1
- package/src/session-log-writer.ts +1 -36
- package/src/utils/common.ts +1 -1
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
AgentSideConnection,
|
|
3
3
|
Role,
|
|
4
4
|
SessionNotification,
|
|
5
|
+
SessionUpdate,
|
|
5
6
|
} from "@agentclientprotocol/sdk";
|
|
6
7
|
import { RequestError } from "@agentclientprotocol/sdk";
|
|
7
8
|
import type {
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
type ClaudePlanEntry,
|
|
26
27
|
planEntries,
|
|
27
28
|
toolInfoFromToolUse,
|
|
29
|
+
toolUpdateFromEditToolResponse,
|
|
28
30
|
toolUpdateFromToolResult,
|
|
29
31
|
} from "./tool-use-to-acp.js";
|
|
30
32
|
|
|
@@ -51,6 +53,8 @@ type ChunkHandlerContext = {
|
|
|
51
53
|
client: AgentSideConnection;
|
|
52
54
|
logger: Logger;
|
|
53
55
|
parentToolCallId?: string;
|
|
56
|
+
registerHooks?: boolean;
|
|
57
|
+
supportsTerminalOutput?: boolean;
|
|
54
58
|
};
|
|
55
59
|
|
|
56
60
|
export interface MessageHandlerContext {
|
|
@@ -60,6 +64,8 @@ export interface MessageHandlerContext {
|
|
|
60
64
|
toolUseCache: ToolUseCache;
|
|
61
65
|
fileContentCache: { [key: string]: string };
|
|
62
66
|
logger: Logger;
|
|
67
|
+
registerHooks?: boolean;
|
|
68
|
+
supportsTerminalOutput?: boolean;
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
function messageUpdateType(role: Role) {
|
|
@@ -81,8 +87,8 @@ function handleTextChunk(
|
|
|
81
87
|
chunk: { text: string },
|
|
82
88
|
role: Role,
|
|
83
89
|
parentToolCallId?: string,
|
|
84
|
-
):
|
|
85
|
-
const update:
|
|
90
|
+
): SessionUpdate {
|
|
91
|
+
const update: SessionUpdate = {
|
|
86
92
|
sessionUpdate: messageUpdateType(role),
|
|
87
93
|
content: text(chunk.text),
|
|
88
94
|
};
|
|
@@ -101,7 +107,7 @@ function handleImageChunk(
|
|
|
101
107
|
source: { type: string; data?: string; media_type?: string; url?: string };
|
|
102
108
|
},
|
|
103
109
|
role: Role,
|
|
104
|
-
):
|
|
110
|
+
): SessionUpdate {
|
|
105
111
|
return {
|
|
106
112
|
sessionUpdate: messageUpdateType(role),
|
|
107
113
|
content: image(
|
|
@@ -115,8 +121,8 @@ function handleImageChunk(
|
|
|
115
121
|
function handleThinkingChunk(
|
|
116
122
|
chunk: { thinking: string },
|
|
117
123
|
parentToolCallId?: string,
|
|
118
|
-
):
|
|
119
|
-
const update:
|
|
124
|
+
): SessionUpdate {
|
|
125
|
+
const update: SessionUpdate = {
|
|
120
126
|
sessionUpdate: "agent_thought_chunk",
|
|
121
127
|
content: text(chunk.thinking),
|
|
122
128
|
};
|
|
@@ -133,7 +139,8 @@ function handleThinkingChunk(
|
|
|
133
139
|
function handleToolUseChunk(
|
|
134
140
|
chunk: ToolUseCache[string],
|
|
135
141
|
ctx: ChunkHandlerContext,
|
|
136
|
-
):
|
|
142
|
+
): SessionUpdate | null {
|
|
143
|
+
const alreadyCached = chunk.id in ctx.toolUseCache;
|
|
137
144
|
ctx.toolUseCache[chunk.id] = chunk;
|
|
138
145
|
|
|
139
146
|
if (chunk.name === "TodoWrite") {
|
|
@@ -147,25 +154,33 @@ function handleToolUseChunk(
|
|
|
147
154
|
return null;
|
|
148
155
|
}
|
|
149
156
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
157
|
+
if (!alreadyCached && ctx.registerHooks !== false) {
|
|
158
|
+
registerHookCallback(chunk.id, {
|
|
159
|
+
onPostToolUseHook: async (toolUseId, _toolInput, toolResponse) => {
|
|
160
|
+
const toolUse = ctx.toolUseCache[toolUseId];
|
|
161
|
+
if (toolUse) {
|
|
162
|
+
const editUpdate =
|
|
163
|
+
toolUse.name === "Edit"
|
|
164
|
+
? toolUpdateFromEditToolResponse(toolResponse)
|
|
165
|
+
: null;
|
|
166
|
+
|
|
167
|
+
await ctx.client.sessionUpdate({
|
|
168
|
+
sessionId: ctx.sessionId,
|
|
169
|
+
update: {
|
|
170
|
+
_meta: toolMeta(toolUse.name, toolResponse, ctx.parentToolCallId),
|
|
171
|
+
toolCallId: toolUseId,
|
|
172
|
+
sessionUpdate: "tool_call_update",
|
|
173
|
+
...(editUpdate ? editUpdate : {}),
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
} else {
|
|
177
|
+
ctx.logger.error(
|
|
178
|
+
`Got a tool response for tool use that wasn't tracked: ${toolUseId}`,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
}
|
|
169
184
|
|
|
170
185
|
let rawInput: Record<string, unknown> | undefined;
|
|
171
186
|
try {
|
|
@@ -174,65 +189,133 @@ function handleToolUseChunk(
|
|
|
174
189
|
// ignore
|
|
175
190
|
}
|
|
176
191
|
|
|
192
|
+
const toolInfo = toolInfoFromToolUse(chunk, {
|
|
193
|
+
supportsTerminalOutput: ctx.supportsTerminalOutput,
|
|
194
|
+
toolUseId: chunk.id,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const meta: Record<string, unknown> = {
|
|
198
|
+
...toolMeta(chunk.name, undefined, ctx.parentToolCallId),
|
|
199
|
+
};
|
|
200
|
+
if (chunk.name === "Bash" && ctx.supportsTerminalOutput && !alreadyCached) {
|
|
201
|
+
meta.terminal_info = { terminal_id: chunk.id };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (alreadyCached) {
|
|
205
|
+
return {
|
|
206
|
+
_meta: meta,
|
|
207
|
+
toolCallId: chunk.id,
|
|
208
|
+
sessionUpdate: "tool_call_update" as const,
|
|
209
|
+
rawInput,
|
|
210
|
+
...toolInfo,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
177
214
|
return {
|
|
178
|
-
_meta:
|
|
215
|
+
_meta: meta,
|
|
179
216
|
toolCallId: chunk.id,
|
|
180
|
-
sessionUpdate: "tool_call",
|
|
217
|
+
sessionUpdate: "tool_call" as const,
|
|
181
218
|
rawInput,
|
|
182
219
|
status: "pending",
|
|
183
|
-
...
|
|
220
|
+
...toolInfo,
|
|
184
221
|
};
|
|
185
222
|
}
|
|
186
223
|
|
|
187
224
|
function handleToolResultChunk(
|
|
188
|
-
chunk: AnthropicContentChunk & {
|
|
225
|
+
chunk: AnthropicContentChunk & {
|
|
226
|
+
tool_use_id: string;
|
|
227
|
+
is_error?: boolean;
|
|
228
|
+
content?: unknown;
|
|
229
|
+
},
|
|
189
230
|
ctx: ChunkHandlerContext,
|
|
190
|
-
):
|
|
231
|
+
): SessionUpdate[] {
|
|
191
232
|
const toolUse = ctx.toolUseCache[chunk.tool_use_id];
|
|
192
233
|
if (!toolUse) {
|
|
193
234
|
ctx.logger.error(
|
|
194
235
|
`Got a tool result for tool use that wasn't tracked: ${chunk.tool_use_id}`,
|
|
195
236
|
);
|
|
196
|
-
return
|
|
237
|
+
return [];
|
|
197
238
|
}
|
|
198
239
|
|
|
199
240
|
if (toolUse.name === "TodoWrite") {
|
|
200
|
-
return
|
|
241
|
+
return [];
|
|
201
242
|
}
|
|
202
243
|
|
|
203
|
-
|
|
204
|
-
|
|
244
|
+
const { _meta: resultMeta, ...toolUpdate } = toolUpdateFromToolResult(
|
|
245
|
+
chunk as Parameters<typeof toolUpdateFromToolResult>[0],
|
|
246
|
+
toolUse,
|
|
247
|
+
{
|
|
248
|
+
supportsTerminalOutput: ctx.supportsTerminalOutput,
|
|
249
|
+
toolUseId: chunk.tool_use_id,
|
|
250
|
+
},
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
const updates: SessionUpdate[] = [];
|
|
254
|
+
|
|
255
|
+
if (resultMeta?.terminal_output) {
|
|
256
|
+
const terminalOutputMeta: Record<string, unknown> = {
|
|
257
|
+
terminal_output: resultMeta.terminal_output,
|
|
258
|
+
};
|
|
259
|
+
if (ctx.parentToolCallId) {
|
|
260
|
+
terminalOutputMeta.claudeCode = {
|
|
261
|
+
parentToolCallId: ctx.parentToolCallId,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
updates.push({
|
|
265
|
+
_meta: terminalOutputMeta,
|
|
266
|
+
toolCallId: chunk.tool_use_id,
|
|
267
|
+
sessionUpdate: "tool_call_update" as const,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const meta: Record<string, unknown> = {
|
|
272
|
+
...toolMeta(toolUse.name, undefined, ctx.parentToolCallId),
|
|
273
|
+
...(resultMeta?.terminal_exit
|
|
274
|
+
? { terminal_exit: resultMeta.terminal_exit }
|
|
275
|
+
: {}),
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
updates.push({
|
|
279
|
+
_meta: meta,
|
|
205
280
|
toolCallId: chunk.tool_use_id,
|
|
206
281
|
sessionUpdate: "tool_call_update",
|
|
207
282
|
status: chunk.is_error ? "failed" : "completed",
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
283
|
+
rawOutput: chunk.content,
|
|
284
|
+
...toolUpdate,
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
return updates;
|
|
213
288
|
}
|
|
214
289
|
|
|
215
290
|
function processContentChunk(
|
|
216
291
|
chunk: AnthropicContentChunk,
|
|
217
292
|
role: Role,
|
|
218
293
|
ctx: ChunkHandlerContext,
|
|
219
|
-
):
|
|
294
|
+
): SessionUpdate[] {
|
|
220
295
|
switch (chunk.type) {
|
|
221
296
|
case "text":
|
|
222
|
-
case "text_delta":
|
|
223
|
-
|
|
297
|
+
case "text_delta": {
|
|
298
|
+
const update = handleTextChunk(chunk, role, ctx.parentToolCallId);
|
|
299
|
+
return update ? [update] : [];
|
|
300
|
+
}
|
|
224
301
|
|
|
225
|
-
case "image":
|
|
226
|
-
|
|
302
|
+
case "image": {
|
|
303
|
+
const update = handleImageChunk(chunk, role);
|
|
304
|
+
return update ? [update] : [];
|
|
305
|
+
}
|
|
227
306
|
|
|
228
307
|
case "thinking":
|
|
229
|
-
case "thinking_delta":
|
|
230
|
-
|
|
308
|
+
case "thinking_delta": {
|
|
309
|
+
const update = handleThinkingChunk(chunk, ctx.parentToolCallId);
|
|
310
|
+
return update ? [update] : [];
|
|
311
|
+
}
|
|
231
312
|
|
|
232
313
|
case "tool_use":
|
|
233
314
|
case "server_tool_use":
|
|
234
|
-
case "mcp_tool_use":
|
|
235
|
-
|
|
315
|
+
case "mcp_tool_use": {
|
|
316
|
+
const update = handleToolUseChunk(chunk as ToolUseCache[string], ctx);
|
|
317
|
+
return update ? [update] : [];
|
|
318
|
+
}
|
|
236
319
|
|
|
237
320
|
case "tool_result":
|
|
238
321
|
case "tool_search_tool_result":
|
|
@@ -246,6 +329,7 @@ function processContentChunk(
|
|
|
246
329
|
chunk as AnthropicContentChunk & {
|
|
247
330
|
tool_use_id: string;
|
|
248
331
|
is_error?: boolean;
|
|
332
|
+
content?: unknown;
|
|
249
333
|
},
|
|
250
334
|
ctx,
|
|
251
335
|
);
|
|
@@ -259,11 +343,11 @@ function processContentChunk(
|
|
|
259
343
|
case "container_upload":
|
|
260
344
|
case "compaction":
|
|
261
345
|
case "compaction_delta":
|
|
262
|
-
return
|
|
346
|
+
return [];
|
|
263
347
|
|
|
264
348
|
default:
|
|
265
|
-
unreachable(chunk, ctx.logger);
|
|
266
|
-
return
|
|
349
|
+
unreachable(chunk as never, ctx.logger);
|
|
350
|
+
return [];
|
|
267
351
|
}
|
|
268
352
|
}
|
|
269
353
|
|
|
@@ -280,9 +364,11 @@ function toAcpNotifications(
|
|
|
280
364
|
client: AgentSideConnection,
|
|
281
365
|
logger: Logger,
|
|
282
366
|
parentToolCallId?: string,
|
|
367
|
+
registerHooks?: boolean,
|
|
368
|
+
supportsTerminalOutput?: boolean,
|
|
283
369
|
): SessionNotification[] {
|
|
284
370
|
if (typeof content === "string") {
|
|
285
|
-
const update:
|
|
371
|
+
const update: SessionUpdate = {
|
|
286
372
|
sessionUpdate: messageUpdateType(role),
|
|
287
373
|
content: text(content),
|
|
288
374
|
};
|
|
@@ -303,12 +389,13 @@ function toAcpNotifications(
|
|
|
303
389
|
client,
|
|
304
390
|
logger,
|
|
305
391
|
parentToolCallId,
|
|
392
|
+
registerHooks,
|
|
393
|
+
supportsTerminalOutput,
|
|
306
394
|
};
|
|
307
395
|
const output: SessionNotification[] = [];
|
|
308
396
|
|
|
309
397
|
for (const chunk of content) {
|
|
310
|
-
const update
|
|
311
|
-
if (update) {
|
|
398
|
+
for (const update of processContentChunk(chunk, role, ctx)) {
|
|
312
399
|
output.push({ sessionId, update });
|
|
313
400
|
}
|
|
314
401
|
}
|
|
@@ -324,6 +411,8 @@ function streamEventToAcpNotifications(
|
|
|
324
411
|
client: AgentSideConnection,
|
|
325
412
|
logger: Logger,
|
|
326
413
|
parentToolCallId?: string,
|
|
414
|
+
registerHooks?: boolean,
|
|
415
|
+
supportsTerminalOutput?: boolean,
|
|
327
416
|
): SessionNotification[] {
|
|
328
417
|
const event = message.event;
|
|
329
418
|
switch (event.type) {
|
|
@@ -337,6 +426,8 @@ function streamEventToAcpNotifications(
|
|
|
337
426
|
client,
|
|
338
427
|
logger,
|
|
339
428
|
parentToolCallId,
|
|
429
|
+
registerHooks,
|
|
430
|
+
supportsTerminalOutput,
|
|
340
431
|
);
|
|
341
432
|
case "content_block_delta":
|
|
342
433
|
return toAcpNotifications(
|
|
@@ -348,6 +439,8 @@ function streamEventToAcpNotifications(
|
|
|
348
439
|
client,
|
|
349
440
|
logger,
|
|
350
441
|
parentToolCallId,
|
|
442
|
+
registerHooks,
|
|
443
|
+
supportsTerminalOutput,
|
|
351
444
|
);
|
|
352
445
|
case "message_start":
|
|
353
446
|
case "message_delta":
|
|
@@ -356,7 +449,7 @@ function streamEventToAcpNotifications(
|
|
|
356
449
|
return [];
|
|
357
450
|
|
|
358
451
|
default:
|
|
359
|
-
unreachable(event, logger);
|
|
452
|
+
unreachable(event as never, logger);
|
|
360
453
|
return [];
|
|
361
454
|
}
|
|
362
455
|
}
|
|
@@ -413,18 +506,24 @@ export async function handleSystemMessage(
|
|
|
413
506
|
}
|
|
414
507
|
}
|
|
415
508
|
|
|
509
|
+
export type ResultMessageHandlerResult = {
|
|
510
|
+
shouldStop: boolean;
|
|
511
|
+
stopReason?: string;
|
|
512
|
+
error?: Error;
|
|
513
|
+
usage?: {
|
|
514
|
+
inputTokens: number;
|
|
515
|
+
outputTokens: number;
|
|
516
|
+
cachedReadTokens: number;
|
|
517
|
+
cachedWriteTokens: number;
|
|
518
|
+
costUsd?: number;
|
|
519
|
+
contextWindowSize?: number;
|
|
520
|
+
};
|
|
521
|
+
};
|
|
522
|
+
|
|
416
523
|
export function handleResultMessage(
|
|
417
524
|
message: SDKResultMessage,
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const { session } = context;
|
|
421
|
-
|
|
422
|
-
if (session.cancelled) {
|
|
423
|
-
return {
|
|
424
|
-
shouldStop: true,
|
|
425
|
-
stopReason: "cancelled",
|
|
426
|
-
};
|
|
427
|
-
}
|
|
525
|
+
): ResultMessageHandlerResult {
|
|
526
|
+
const usage = extractUsageFromResult(message);
|
|
428
527
|
|
|
429
528
|
switch (message.subtype) {
|
|
430
529
|
case "success": {
|
|
@@ -432,15 +531,17 @@ export function handleResultMessage(
|
|
|
432
531
|
return {
|
|
433
532
|
shouldStop: true,
|
|
434
533
|
error: RequestError.authRequired(),
|
|
534
|
+
usage,
|
|
435
535
|
};
|
|
436
536
|
}
|
|
437
537
|
if (message.is_error) {
|
|
438
538
|
return {
|
|
439
539
|
shouldStop: true,
|
|
440
540
|
error: RequestError.internalError(undefined, message.result),
|
|
541
|
+
usage,
|
|
441
542
|
};
|
|
442
543
|
}
|
|
443
|
-
return { shouldStop: true, stopReason: "end_turn" };
|
|
544
|
+
return { shouldStop: true, stopReason: "end_turn", usage };
|
|
444
545
|
}
|
|
445
546
|
case "error_during_execution":
|
|
446
547
|
if (message.is_error) {
|
|
@@ -450,9 +551,10 @@ export function handleResultMessage(
|
|
|
450
551
|
undefined,
|
|
451
552
|
message.errors.join(", ") || message.subtype,
|
|
452
553
|
),
|
|
554
|
+
usage,
|
|
453
555
|
};
|
|
454
556
|
}
|
|
455
|
-
return { shouldStop: true, stopReason: "end_turn" };
|
|
557
|
+
return { shouldStop: true, stopReason: "end_turn", usage };
|
|
456
558
|
case "error_max_budget_usd":
|
|
457
559
|
case "error_max_turns":
|
|
458
560
|
case "error_max_structured_output_retries":
|
|
@@ -463,14 +565,46 @@ export function handleResultMessage(
|
|
|
463
565
|
undefined,
|
|
464
566
|
message.errors.join(", ") || message.subtype,
|
|
465
567
|
),
|
|
568
|
+
usage,
|
|
466
569
|
};
|
|
467
570
|
}
|
|
468
|
-
return { shouldStop: true, stopReason: "max_turn_requests" };
|
|
571
|
+
return { shouldStop: true, stopReason: "max_turn_requests", usage };
|
|
469
572
|
default:
|
|
470
|
-
return { shouldStop: false };
|
|
573
|
+
return { shouldStop: false, usage };
|
|
471
574
|
}
|
|
472
575
|
}
|
|
473
576
|
|
|
577
|
+
function extractUsageFromResult(
|
|
578
|
+
message: SDKResultMessage,
|
|
579
|
+
): ResultMessageHandlerResult["usage"] {
|
|
580
|
+
const msg = message as Record<string, unknown>;
|
|
581
|
+
const msgUsage = msg.usage as Record<string, number> | undefined;
|
|
582
|
+
if (!msgUsage) return undefined;
|
|
583
|
+
|
|
584
|
+
const modelUsage = msg.modelUsage as
|
|
585
|
+
| Record<string, { contextWindow: number }>
|
|
586
|
+
| undefined;
|
|
587
|
+
let contextWindowSize: number | undefined;
|
|
588
|
+
if (modelUsage) {
|
|
589
|
+
const contextWindows = Object.values(modelUsage).map(
|
|
590
|
+
(m) => m.contextWindow,
|
|
591
|
+
);
|
|
592
|
+
if (contextWindows.length > 0) {
|
|
593
|
+
contextWindowSize = Math.min(...contextWindows);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
return {
|
|
598
|
+
inputTokens: msgUsage.input_tokens ?? 0,
|
|
599
|
+
outputTokens: msgUsage.output_tokens ?? 0,
|
|
600
|
+
cachedReadTokens: msgUsage.cache_read_input_tokens ?? 0,
|
|
601
|
+
cachedWriteTokens: msgUsage.cache_creation_input_tokens ?? 0,
|
|
602
|
+
costUsd:
|
|
603
|
+
typeof msg.total_cost_usd === "number" ? msg.total_cost_usd : undefined,
|
|
604
|
+
contextWindowSize,
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
|
|
474
608
|
export async function handleStreamEvent(
|
|
475
609
|
message: SDKPartialAssistantMessage,
|
|
476
610
|
context: MessageHandlerContext,
|
|
@@ -486,6 +620,8 @@ export async function handleStreamEvent(
|
|
|
486
620
|
client,
|
|
487
621
|
logger,
|
|
488
622
|
parentToolCallId,
|
|
623
|
+
context.registerHooks,
|
|
624
|
+
context.supportsTerminalOutput,
|
|
489
625
|
)) {
|
|
490
626
|
await client.sessionUpdate(notification);
|
|
491
627
|
context.session.notificationHistory.push(notification);
|
|
@@ -504,16 +640,6 @@ function hasLocalCommandStderr(content: AnthropicMessageContent): boolean {
|
|
|
504
640
|
);
|
|
505
641
|
}
|
|
506
642
|
|
|
507
|
-
function isSimpleUserMessage(message: AnthropicMessageWithContent): boolean {
|
|
508
|
-
return (
|
|
509
|
-
message.type === "user" &&
|
|
510
|
-
(typeof message.message.content === "string" ||
|
|
511
|
-
(Array.isArray(message.message.content) &&
|
|
512
|
-
message.message.content.length === 1 &&
|
|
513
|
-
message.message.content[0].type === "text"))
|
|
514
|
-
);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
643
|
function isLoginRequiredMessage(message: AnthropicMessageWithContent): boolean {
|
|
518
644
|
return (
|
|
519
645
|
message.type === "assistant" &&
|
|
@@ -525,13 +651,23 @@ function isLoginRequiredMessage(message: AnthropicMessageWithContent): boolean {
|
|
|
525
651
|
);
|
|
526
652
|
}
|
|
527
653
|
|
|
654
|
+
function isPlainTextUserMessage(message: AnthropicMessageWithContent): boolean {
|
|
655
|
+
const content = message.message.content;
|
|
656
|
+
return (
|
|
657
|
+
message.type === "user" &&
|
|
658
|
+
(typeof content === "string" ||
|
|
659
|
+
(Array.isArray(content) &&
|
|
660
|
+
content.length === 1 &&
|
|
661
|
+
content[0].type === "text"))
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
|
|
528
665
|
function shouldSkipUserAssistantMessage(
|
|
529
666
|
message: AnthropicMessageWithContent,
|
|
530
667
|
): boolean {
|
|
531
668
|
return (
|
|
532
669
|
hasLocalCommandStdout(message.message.content) ||
|
|
533
670
|
hasLocalCommandStderr(message.message.content) ||
|
|
534
|
-
isSimpleUserMessage(message) ||
|
|
535
671
|
isLoginRequiredMessage(message)
|
|
536
672
|
);
|
|
537
673
|
}
|
|
@@ -567,11 +703,31 @@ export async function handleUserAssistantMessage(
|
|
|
567
703
|
const { session, sessionId, client, toolUseCache, fileContentCache, logger } =
|
|
568
704
|
context;
|
|
569
705
|
|
|
570
|
-
if (session.cancelled) {
|
|
571
|
-
return {};
|
|
572
|
-
}
|
|
573
|
-
|
|
574
706
|
if (shouldSkipUserAssistantMessage(message)) {
|
|
707
|
+
const content = message.message.content;
|
|
708
|
+
|
|
709
|
+
// Handle /context by sending its reply as a regular agent message
|
|
710
|
+
if (
|
|
711
|
+
typeof content === "string" &&
|
|
712
|
+
hasLocalCommandStdout(content) &&
|
|
713
|
+
content.includes("Context Usage")
|
|
714
|
+
) {
|
|
715
|
+
const stripped = content
|
|
716
|
+
.replace("<local-command-stdout>", "")
|
|
717
|
+
.replace("</local-command-stdout>", "");
|
|
718
|
+
for (const notification of toAcpNotifications(
|
|
719
|
+
stripped,
|
|
720
|
+
"assistant",
|
|
721
|
+
sessionId,
|
|
722
|
+
toolUseCache,
|
|
723
|
+
fileContentCache,
|
|
724
|
+
client,
|
|
725
|
+
logger,
|
|
726
|
+
)) {
|
|
727
|
+
await client.sessionUpdate(notification);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
575
731
|
logSpecialMessages(message, logger);
|
|
576
732
|
|
|
577
733
|
if (isLoginRequiredMessage(message)) {
|
|
@@ -580,8 +736,14 @@ export async function handleUserAssistantMessage(
|
|
|
580
736
|
return {};
|
|
581
737
|
}
|
|
582
738
|
|
|
739
|
+
// Skip plain text user messages (already displayed by the ACP client)
|
|
740
|
+
if (isPlainTextUserMessage(message)) {
|
|
741
|
+
return {};
|
|
742
|
+
}
|
|
743
|
+
|
|
583
744
|
const content = message.message.content;
|
|
584
|
-
const contentToProcess =
|
|
745
|
+
const contentToProcess =
|
|
746
|
+
message.type === "assistant" ? filterMessageContent(content) : content;
|
|
585
747
|
const parentToolCallId =
|
|
586
748
|
"parent_tool_use_id" in message
|
|
587
749
|
? (message.parent_tool_use_id ?? undefined)
|
|
@@ -596,6 +758,8 @@ export async function handleUserAssistantMessage(
|
|
|
596
758
|
client,
|
|
597
759
|
logger,
|
|
598
760
|
parentToolCallId,
|
|
761
|
+
context.registerHooks,
|
|
762
|
+
context.supportsTerminalOutput,
|
|
599
763
|
)) {
|
|
600
764
|
await client.sessionUpdate(notification);
|
|
601
765
|
session.notificationHistory.push(notification);
|