linkshell-cli 0.2.67 → 0.2.69
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/cli/src/runtime/acp/acp-client.d.ts +2 -0
- package/dist/cli/src/runtime/acp/acp-client.js +7 -1
- package/dist/cli/src/runtime/acp/acp-client.js.map +1 -1
- package/dist/cli/src/runtime/acp/agent-session.d.ts +14 -0
- package/dist/cli/src/runtime/acp/agent-session.js +391 -8
- package/dist/cli/src/runtime/acp/agent-session.js.map +1 -1
- package/dist/cli/tsconfig.tsbuildinfo +1 -1
- package/dist/shared-protocol/src/index.d.ts +97 -84
- package/dist/shared-protocol/src/index.js +10 -0
- package/dist/shared-protocol/src/index.js.map +1 -1
- package/package.json +2 -2
- package/src/runtime/acp/acp-client.ts +9 -1
- package/src/runtime/acp/agent-session.ts +394 -7
|
@@ -65,6 +65,8 @@ export class AcpClient {
|
|
|
65
65
|
if (this.protocol === "codex-app-server") {
|
|
66
66
|
return this.transport.request("turn/start", {
|
|
67
67
|
threadId: input.sessionId,
|
|
68
|
+
model: input.model,
|
|
69
|
+
effort: input.reasoningEffort,
|
|
68
70
|
input: input.content.map((block) => {
|
|
69
71
|
const raw = block;
|
|
70
72
|
if (raw.type === "image" && raw.data) {
|
|
@@ -77,7 +79,11 @@ export class AcpClient {
|
|
|
77
79
|
return this.transport.request("session/prompt", {
|
|
78
80
|
sessionId: input.sessionId,
|
|
79
81
|
prompt: input.content,
|
|
80
|
-
_meta: {
|
|
82
|
+
_meta: {
|
|
83
|
+
linkshellClientMessageId: input.clientMessageId,
|
|
84
|
+
model: input.model,
|
|
85
|
+
reasoningEffort: input.reasoningEffort,
|
|
86
|
+
},
|
|
81
87
|
}, 60_000);
|
|
82
88
|
}
|
|
83
89
|
cancel(input) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acp-client.js","sourceRoot":"","sources":["../../../../../src/runtime/acp/acp-client.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"acp-client.js","sourceRoot":"","sources":["../../../../../src/runtime/acp/acp-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,9 @@ export declare class AgentSessionProxy {
|
|
|
10
10
|
private currentTurnId;
|
|
11
11
|
private messages;
|
|
12
12
|
private toolCalls;
|
|
13
|
+
private toolOutputBuffers;
|
|
14
|
+
private plan;
|
|
15
|
+
private planDeltaBuffers;
|
|
13
16
|
private pendingPermissions;
|
|
14
17
|
private permissionWaiters;
|
|
15
18
|
private permissionSources;
|
|
@@ -31,9 +34,20 @@ export declare class AgentSessionProxy {
|
|
|
31
34
|
private sendSessionList;
|
|
32
35
|
private handleNotification;
|
|
33
36
|
private handlePermission;
|
|
37
|
+
private handleAgentMessageDelta;
|
|
38
|
+
private handlePlanUpdated;
|
|
39
|
+
private handlePlanDelta;
|
|
40
|
+
private handleItemStarted;
|
|
41
|
+
private handleItemCompleted;
|
|
42
|
+
private handleToolDelta;
|
|
43
|
+
private handleFilePatchUpdated;
|
|
44
|
+
private handleCommandExecDelta;
|
|
45
|
+
private handleCompletedMessageItem;
|
|
46
|
+
private toolCallFromItem;
|
|
34
47
|
private handleUpdate;
|
|
35
48
|
private handleExit;
|
|
36
49
|
private cancelPendingPermissions;
|
|
50
|
+
private upsertMessage;
|
|
37
51
|
private sendCapabilities;
|
|
38
52
|
private sendSnapshot;
|
|
39
53
|
private sendUpdate;
|
|
@@ -23,6 +23,122 @@ function firstString(value, keys) {
|
|
|
23
23
|
}
|
|
24
24
|
return undefined;
|
|
25
25
|
}
|
|
26
|
+
function asRecord(value) {
|
|
27
|
+
return typeof value === "object" && value ? value : undefined;
|
|
28
|
+
}
|
|
29
|
+
function extractItem(value) {
|
|
30
|
+
const raw = asRecord(value);
|
|
31
|
+
if (!raw)
|
|
32
|
+
return undefined;
|
|
33
|
+
return asRecord(raw.item) ?? raw;
|
|
34
|
+
}
|
|
35
|
+
function stringifyDefined(value) {
|
|
36
|
+
if (value === undefined || value === null || value === "")
|
|
37
|
+
return undefined;
|
|
38
|
+
return stringify(value);
|
|
39
|
+
}
|
|
40
|
+
function appendCapped(current, delta, maxLength) {
|
|
41
|
+
const next = `${current ?? ""}${delta}`;
|
|
42
|
+
if (next.length <= maxLength)
|
|
43
|
+
return next;
|
|
44
|
+
return next.slice(next.length - maxLength);
|
|
45
|
+
}
|
|
46
|
+
function decodeBase64(value) {
|
|
47
|
+
if (!value)
|
|
48
|
+
return undefined;
|
|
49
|
+
try {
|
|
50
|
+
return Buffer.from(value, "base64").toString("utf8");
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function normalizeToolStatus(value, completedFallback = false) {
|
|
57
|
+
if (value === "completed" || value === "succeeded" || value === "success" || value === "applied") {
|
|
58
|
+
return "completed";
|
|
59
|
+
}
|
|
60
|
+
if (value === "failed" || value === "error" || value === "declined" || value === "cancelled") {
|
|
61
|
+
return "failed";
|
|
62
|
+
}
|
|
63
|
+
if (value === "pending" || value === "queued")
|
|
64
|
+
return "pending";
|
|
65
|
+
if (value === "running" || value === "inProgress" || value === "executing")
|
|
66
|
+
return "running";
|
|
67
|
+
return completedFallback ? "completed" : "running";
|
|
68
|
+
}
|
|
69
|
+
function normalizePlanStatus(value) {
|
|
70
|
+
if (value === "completed" || value === "done")
|
|
71
|
+
return "completed";
|
|
72
|
+
if (value === "inProgress" || value === "running" || value === "active")
|
|
73
|
+
return "in_progress";
|
|
74
|
+
return "pending";
|
|
75
|
+
}
|
|
76
|
+
function planStepFromItem(item) {
|
|
77
|
+
const text = firstString(item, ["text", "title", "description", "message"]);
|
|
78
|
+
if (!text)
|
|
79
|
+
return undefined;
|
|
80
|
+
return {
|
|
81
|
+
id: firstString(item, ["id", "itemId"]) ?? id("plan"),
|
|
82
|
+
text,
|
|
83
|
+
status: normalizePlanStatus(item.status),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function nameFromToolMethod(method) {
|
|
87
|
+
if (method.includes("commandExecution"))
|
|
88
|
+
return "命令";
|
|
89
|
+
if (method.includes("fileChange"))
|
|
90
|
+
return "文件修改";
|
|
91
|
+
if (method.includes("mcpToolCall"))
|
|
92
|
+
return "MCP 工具";
|
|
93
|
+
return "工具";
|
|
94
|
+
}
|
|
95
|
+
function toolNameFromItem(item) {
|
|
96
|
+
const itemType = firstString(item, ["type"]);
|
|
97
|
+
if (itemType === "commandExecution")
|
|
98
|
+
return "命令";
|
|
99
|
+
if (itemType === "fileChange")
|
|
100
|
+
return "文件修改";
|
|
101
|
+
if (itemType === "mcpToolCall") {
|
|
102
|
+
const server = firstString(item, ["server"]);
|
|
103
|
+
const tool = firstString(item, ["tool", "toolName", "name"]);
|
|
104
|
+
return [server, tool].filter(Boolean).join(" · ") || "MCP 工具";
|
|
105
|
+
}
|
|
106
|
+
if (itemType === "dynamicToolCall") {
|
|
107
|
+
const namespace = firstString(item, ["namespace"]);
|
|
108
|
+
const tool = firstString(item, ["tool", "toolName", "name"]);
|
|
109
|
+
return [namespace, tool].filter(Boolean).join(" · ") || "工具";
|
|
110
|
+
}
|
|
111
|
+
return firstString(item, ["toolName", "tool", "name", "title"]) ?? itemType;
|
|
112
|
+
}
|
|
113
|
+
function toolInputFromItem(item) {
|
|
114
|
+
const itemType = firstString(item, ["type"]);
|
|
115
|
+
if (itemType === "commandExecution") {
|
|
116
|
+
const command = firstString(item, ["command"]);
|
|
117
|
+
const cwd = firstString(item, ["cwd"]);
|
|
118
|
+
if (command && cwd)
|
|
119
|
+
return `${command}\n\ncwd: ${cwd}`;
|
|
120
|
+
return command ?? cwd;
|
|
121
|
+
}
|
|
122
|
+
if (itemType === "fileChange") {
|
|
123
|
+
const changes = Array.isArray(item.changes) ? item.changes : [];
|
|
124
|
+
return summarizeFileChanges(changes);
|
|
125
|
+
}
|
|
126
|
+
return stringifyDefined(item.arguments ?? item.input ?? item.toolInput);
|
|
127
|
+
}
|
|
128
|
+
function summarizeFileChanges(changes) {
|
|
129
|
+
const lines = changes
|
|
130
|
+
.map((change) => {
|
|
131
|
+
const raw = asRecord(change);
|
|
132
|
+
if (!raw)
|
|
133
|
+
return undefined;
|
|
134
|
+
const path = firstString(raw, ["path", "file", "filePath", "absolutePath", "relativePath"]) ??
|
|
135
|
+
firstString(asRecord(raw.update) ?? {}, ["path", "file", "filePath"]);
|
|
136
|
+
const kind = firstString(raw, ["kind", "type", "operation", "action"]);
|
|
137
|
+
return [kind, path].filter(Boolean).join(" ");
|
|
138
|
+
})
|
|
139
|
+
.filter((line) => Boolean(line));
|
|
140
|
+
return lines.length > 0 ? lines.slice(0, 8).join("\n") : undefined;
|
|
141
|
+
}
|
|
26
142
|
export class AgentSessionProxy {
|
|
27
143
|
input;
|
|
28
144
|
client;
|
|
@@ -33,6 +149,9 @@ export class AgentSessionProxy {
|
|
|
33
149
|
currentTurnId;
|
|
34
150
|
messages = [];
|
|
35
151
|
toolCalls = new Map();
|
|
152
|
+
toolOutputBuffers = new Map();
|
|
153
|
+
plan = [];
|
|
154
|
+
planDeltaBuffers = new Map();
|
|
36
155
|
pendingPermissions = new Map();
|
|
37
156
|
permissionWaiters = new Map();
|
|
38
157
|
permissionSources = new Map();
|
|
@@ -199,6 +318,8 @@ export class AgentSessionProxy {
|
|
|
199
318
|
sessionId: payload.agentSessionId ?? this.agentSessionId,
|
|
200
319
|
content: payload.contentBlocks,
|
|
201
320
|
clientMessageId: payload.clientMessageId,
|
|
321
|
+
model: payload.model,
|
|
322
|
+
reasoningEffort: payload.reasoningEffort,
|
|
202
323
|
});
|
|
203
324
|
this.currentTurnId = this.extractTurnId(result) ?? this.currentTurnId;
|
|
204
325
|
if (this.status === "running") {
|
|
@@ -250,7 +371,12 @@ export class AgentSessionProxy {
|
|
|
250
371
|
}
|
|
251
372
|
if (method === "initialized" ||
|
|
252
373
|
method.startsWith("account/") ||
|
|
253
|
-
method.startsWith("mcpServer/startupStatus/")
|
|
374
|
+
method.startsWith("mcpServer/startupStatus/") ||
|
|
375
|
+
method === "thread/status/changed" ||
|
|
376
|
+
method === "thread/tokenUsage/updated" ||
|
|
377
|
+
method === "turn/diff/updated" ||
|
|
378
|
+
method === "serverRequest/resolved" ||
|
|
379
|
+
method === "mcpServer/oauthLogin/completed") {
|
|
254
380
|
return;
|
|
255
381
|
}
|
|
256
382
|
if (method === "thread/started") {
|
|
@@ -275,11 +401,45 @@ export class AgentSessionProxy {
|
|
|
275
401
|
this.handlePermission(params, false, method);
|
|
276
402
|
return;
|
|
277
403
|
}
|
|
278
|
-
|
|
404
|
+
switch (method) {
|
|
405
|
+
case "item/agentMessage/delta":
|
|
406
|
+
this.handleAgentMessageDelta(params);
|
|
407
|
+
return;
|
|
408
|
+
case "turn/plan/updated":
|
|
409
|
+
this.handlePlanUpdated(params);
|
|
410
|
+
return;
|
|
411
|
+
case "item/plan/delta":
|
|
412
|
+
this.handlePlanDelta(params);
|
|
413
|
+
return;
|
|
414
|
+
case "item/started":
|
|
415
|
+
this.handleItemStarted(params);
|
|
416
|
+
return;
|
|
417
|
+
case "item/completed":
|
|
418
|
+
this.handleItemCompleted(params);
|
|
419
|
+
return;
|
|
420
|
+
case "item/commandExecution/outputDelta":
|
|
421
|
+
case "item/fileChange/outputDelta":
|
|
422
|
+
case "item/mcpToolCall/progress":
|
|
423
|
+
this.handleToolDelta(method, params);
|
|
424
|
+
return;
|
|
425
|
+
case "item/fileChange/patchUpdated":
|
|
426
|
+
this.handleFilePatchUpdated(params);
|
|
427
|
+
return;
|
|
428
|
+
case "command/exec/outputDelta":
|
|
429
|
+
this.handleCommandExecDelta(params);
|
|
430
|
+
return;
|
|
431
|
+
case "item/autoApprovalReview/started":
|
|
432
|
+
case "item/autoApprovalReview/completed":
|
|
433
|
+
case "item/commandExecution/terminalInteraction":
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
if (method === "session/update") {
|
|
279
437
|
this.handleUpdate(params);
|
|
280
438
|
return;
|
|
281
439
|
}
|
|
282
|
-
this.
|
|
440
|
+
if (this.input.verbose) {
|
|
441
|
+
process.stderr.write(`[agent] ignored ${method}\n`);
|
|
442
|
+
}
|
|
283
443
|
}
|
|
284
444
|
handlePermission(params, waitForResponse, source) {
|
|
285
445
|
const raw = typeof params === "object" && params ? params : {};
|
|
@@ -316,12 +476,228 @@ export class AgentSessionProxy {
|
|
|
316
476
|
this.permissionWaiters.set(requestId, { resolve, timer });
|
|
317
477
|
});
|
|
318
478
|
}
|
|
479
|
+
handleAgentMessageDelta(params) {
|
|
480
|
+
const raw = asRecord(params);
|
|
481
|
+
if (!raw)
|
|
482
|
+
return;
|
|
483
|
+
const itemId = firstString(raw, ["itemId", "id", "messageId"]) ?? id("msg");
|
|
484
|
+
const delta = firstString(raw, ["delta", "text", "content"]);
|
|
485
|
+
if (!delta)
|
|
486
|
+
return;
|
|
487
|
+
const current = this.messages.find((message) => message.id === itemId);
|
|
488
|
+
const message = {
|
|
489
|
+
id: itemId,
|
|
490
|
+
role: "assistant",
|
|
491
|
+
content: `${current?.content ?? ""}${delta}`,
|
|
492
|
+
createdAt: current?.createdAt ?? Date.now(),
|
|
493
|
+
isStreaming: true,
|
|
494
|
+
};
|
|
495
|
+
this.upsertMessage(message);
|
|
496
|
+
this.status = "running";
|
|
497
|
+
this.sendUpdate({ kind: "message_delta", message, delta, status: "running" });
|
|
498
|
+
}
|
|
499
|
+
handlePlanUpdated(params) {
|
|
500
|
+
const raw = asRecord(params);
|
|
501
|
+
const plan = Array.isArray(raw?.plan) ? raw.plan : [];
|
|
502
|
+
this.plan = plan
|
|
503
|
+
.map((entry, index) => {
|
|
504
|
+
const step = asRecord(entry);
|
|
505
|
+
const text = firstString(step ?? {}, ["text", "title", "description", "message"]);
|
|
506
|
+
if (!text)
|
|
507
|
+
return undefined;
|
|
508
|
+
return {
|
|
509
|
+
id: firstString(step ?? {}, ["id"]) ?? `plan-${index + 1}`,
|
|
510
|
+
text,
|
|
511
|
+
status: normalizePlanStatus(step?.status),
|
|
512
|
+
};
|
|
513
|
+
})
|
|
514
|
+
.filter((step) => Boolean(step));
|
|
515
|
+
if (this.plan.length > 0) {
|
|
516
|
+
this.sendUpdate({ kind: "plan", plan: this.plan, status: "running" });
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
handlePlanDelta(params) {
|
|
520
|
+
const raw = asRecord(params);
|
|
521
|
+
if (!raw)
|
|
522
|
+
return;
|
|
523
|
+
const itemId = firstString(raw, ["itemId", "id"]) ?? id("plan");
|
|
524
|
+
const delta = firstString(raw, ["delta", "text"]);
|
|
525
|
+
if (!delta)
|
|
526
|
+
return;
|
|
527
|
+
const text = `${this.planDeltaBuffers.get(itemId) ?? ""}${delta}`;
|
|
528
|
+
this.planDeltaBuffers.set(itemId, text);
|
|
529
|
+
const existing = this.plan.findIndex((step) => step.id === itemId);
|
|
530
|
+
const step = { id: itemId, text, status: "in_progress" };
|
|
531
|
+
if (existing >= 0)
|
|
532
|
+
this.plan[existing] = step;
|
|
533
|
+
else
|
|
534
|
+
this.plan.push(step);
|
|
535
|
+
this.sendUpdate({ kind: "plan", plan: this.plan, status: "running" });
|
|
536
|
+
}
|
|
537
|
+
handleItemStarted(params) {
|
|
538
|
+
const item = extractItem(params);
|
|
539
|
+
if (!item)
|
|
540
|
+
return;
|
|
541
|
+
const itemType = firstString(item, ["type"]);
|
|
542
|
+
if (itemType === "agentMessage" || itemType === "assistantMessage") {
|
|
543
|
+
this.handleCompletedMessageItem(item, true);
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
if (itemType === "plan") {
|
|
547
|
+
const planStep = planStepFromItem(item);
|
|
548
|
+
if (planStep) {
|
|
549
|
+
const existing = this.plan.findIndex((step) => step.id === planStep.id);
|
|
550
|
+
if (existing >= 0)
|
|
551
|
+
this.plan[existing] = planStep;
|
|
552
|
+
else
|
|
553
|
+
this.plan.push(planStep);
|
|
554
|
+
this.sendUpdate({ kind: "plan", plan: this.plan, status: "running" });
|
|
555
|
+
}
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
const toolCall = this.toolCallFromItem(item, "running");
|
|
559
|
+
if (!toolCall)
|
|
560
|
+
return;
|
|
561
|
+
this.toolCalls.set(toolCall.id, toolCall);
|
|
562
|
+
this.sendUpdate({ kind: "tool_call", toolCall, status: "running" });
|
|
563
|
+
}
|
|
564
|
+
handleItemCompleted(params) {
|
|
565
|
+
const item = extractItem(params);
|
|
566
|
+
if (!item)
|
|
567
|
+
return;
|
|
568
|
+
const itemType = firstString(item, ["type"]);
|
|
569
|
+
if (itemType === "agentMessage" || itemType === "assistantMessage") {
|
|
570
|
+
this.handleCompletedMessageItem(item, false);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (itemType === "plan") {
|
|
574
|
+
const planStep = planStepFromItem(item);
|
|
575
|
+
if (planStep) {
|
|
576
|
+
const existing = this.plan.findIndex((step) => step.id === planStep.id);
|
|
577
|
+
const completed = { ...planStep, status: "completed" };
|
|
578
|
+
if (existing >= 0)
|
|
579
|
+
this.plan[existing] = completed;
|
|
580
|
+
else
|
|
581
|
+
this.plan.push(completed);
|
|
582
|
+
this.sendUpdate({ kind: "plan", plan: this.plan, status: this.status === "running" ? "running" : "idle" });
|
|
583
|
+
}
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
const toolCall = this.toolCallFromItem(item, normalizeToolStatus(item.status, true));
|
|
587
|
+
if (!toolCall)
|
|
588
|
+
return;
|
|
589
|
+
const bufferedOutput = this.toolOutputBuffers.get(toolCall.id);
|
|
590
|
+
if (bufferedOutput && !toolCall.output)
|
|
591
|
+
toolCall.output = bufferedOutput;
|
|
592
|
+
this.toolCalls.set(toolCall.id, toolCall);
|
|
593
|
+
this.sendUpdate({ kind: "tool_result", toolCall, status: this.status === "running" ? "running" : "idle" });
|
|
594
|
+
}
|
|
595
|
+
handleToolDelta(method, params) {
|
|
596
|
+
const raw = asRecord(params);
|
|
597
|
+
if (!raw)
|
|
598
|
+
return;
|
|
599
|
+
const itemId = firstString(raw, ["itemId", "id", "toolCallId"]) ?? id("tool");
|
|
600
|
+
const delta = firstString(raw, ["delta", "message", "text"]);
|
|
601
|
+
if (!delta)
|
|
602
|
+
return;
|
|
603
|
+
const output = appendCapped(this.toolOutputBuffers.get(itemId), delta, 6000);
|
|
604
|
+
this.toolOutputBuffers.set(itemId, output);
|
|
605
|
+
const existing = this.toolCalls.get(itemId);
|
|
606
|
+
const toolCall = {
|
|
607
|
+
id: itemId,
|
|
608
|
+
name: existing?.name ?? nameFromToolMethod(method),
|
|
609
|
+
input: existing?.input,
|
|
610
|
+
output,
|
|
611
|
+
status: "running",
|
|
612
|
+
};
|
|
613
|
+
this.toolCalls.set(itemId, toolCall);
|
|
614
|
+
this.sendUpdate({ kind: "tool_call", toolCall, status: "running" });
|
|
615
|
+
}
|
|
616
|
+
handleFilePatchUpdated(params) {
|
|
617
|
+
const raw = asRecord(params);
|
|
618
|
+
if (!raw)
|
|
619
|
+
return;
|
|
620
|
+
const itemId = firstString(raw, ["itemId", "id"]) ?? id("file");
|
|
621
|
+
const changes = Array.isArray(raw.changes) ? raw.changes : [];
|
|
622
|
+
const output = summarizeFileChanges(changes);
|
|
623
|
+
const existing = this.toolCalls.get(itemId);
|
|
624
|
+
const toolCall = {
|
|
625
|
+
id: itemId,
|
|
626
|
+
name: existing?.name ?? "文件修改",
|
|
627
|
+
input: existing?.input,
|
|
628
|
+
output: output || existing?.output,
|
|
629
|
+
status: existing?.status ?? "running",
|
|
630
|
+
};
|
|
631
|
+
this.toolCalls.set(itemId, toolCall);
|
|
632
|
+
this.sendUpdate({ kind: "tool_call", toolCall, status: "running" });
|
|
633
|
+
}
|
|
634
|
+
handleCommandExecDelta(params) {
|
|
635
|
+
const raw = asRecord(params);
|
|
636
|
+
if (!raw)
|
|
637
|
+
return;
|
|
638
|
+
const processId = firstString(raw, ["processId", "id"]) ?? id("exec");
|
|
639
|
+
const delta = firstString(raw, ["delta", "text"]) ??
|
|
640
|
+
decodeBase64(firstString(raw, ["deltaBase64"]));
|
|
641
|
+
if (!delta)
|
|
642
|
+
return;
|
|
643
|
+
const output = appendCapped(this.toolOutputBuffers.get(processId), delta, 6000);
|
|
644
|
+
this.toolOutputBuffers.set(processId, output);
|
|
645
|
+
const existing = this.toolCalls.get(processId);
|
|
646
|
+
const toolCall = {
|
|
647
|
+
id: processId,
|
|
648
|
+
name: existing?.name ?? "命令输出",
|
|
649
|
+
input: existing?.input,
|
|
650
|
+
output,
|
|
651
|
+
status: "running",
|
|
652
|
+
};
|
|
653
|
+
this.toolCalls.set(processId, toolCall);
|
|
654
|
+
this.sendUpdate({ kind: "tool_call", toolCall, status: "running" });
|
|
655
|
+
}
|
|
656
|
+
handleCompletedMessageItem(item, streaming) {
|
|
657
|
+
const itemId = firstString(item, ["id"]) ?? id("msg");
|
|
658
|
+
const existing = this.messages.find((message) => message.id === itemId);
|
|
659
|
+
const content = firstString(item, ["text", "content", "message"]) ?? existing?.content;
|
|
660
|
+
if (!content)
|
|
661
|
+
return;
|
|
662
|
+
const message = {
|
|
663
|
+
id: itemId,
|
|
664
|
+
role: "assistant",
|
|
665
|
+
content,
|
|
666
|
+
createdAt: existing?.createdAt ?? Date.now(),
|
|
667
|
+
isStreaming: streaming,
|
|
668
|
+
};
|
|
669
|
+
this.upsertMessage(message);
|
|
670
|
+
this.sendUpdate({
|
|
671
|
+
kind: streaming ? "message_delta" : "message",
|
|
672
|
+
message,
|
|
673
|
+
status: this.status === "running" ? "running" : "idle",
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
toolCallFromItem(item, fallbackStatus) {
|
|
677
|
+
const itemId = firstString(item, ["id", "itemId", "toolCallId"]);
|
|
678
|
+
if (!itemId)
|
|
679
|
+
return undefined;
|
|
680
|
+
const itemType = firstString(item, ["type"]);
|
|
681
|
+
const name = toolNameFromItem(item);
|
|
682
|
+
const output = firstString(item, ["aggregatedOutput", "output", "stdout", "stderr"]) ??
|
|
683
|
+
stringifyDefined(item.result ?? item.error ?? item.contentItems);
|
|
684
|
+
const bufferedOutput = this.toolOutputBuffers.get(itemId);
|
|
685
|
+
return {
|
|
686
|
+
id: itemId,
|
|
687
|
+
name: name ?? itemType ?? "tool",
|
|
688
|
+
input: toolInputFromItem(item),
|
|
689
|
+
output: output ?? bufferedOutput,
|
|
690
|
+
status: normalizeToolStatus(item.status, fallbackStatus === "completed"),
|
|
691
|
+
};
|
|
692
|
+
}
|
|
319
693
|
handleUpdate(params) {
|
|
320
694
|
const raw = typeof params === "object" && params ? params : {};
|
|
321
695
|
const nested = typeof raw.params === "object" && raw.params ? raw.params : {};
|
|
322
696
|
const text = firstString(raw, ["delta", "text", "content", "message"]) ??
|
|
323
697
|
firstString(nested, ["delta", "text", "content", "message"]) ??
|
|
324
|
-
|
|
698
|
+
undefined;
|
|
699
|
+
if (!text)
|
|
700
|
+
return;
|
|
325
701
|
const role = raw.role === "user" || raw.role === "system" ? raw.role : "assistant";
|
|
326
702
|
if (firstString(raw, ["toolName", "tool", "name"])) {
|
|
327
703
|
const toolCall = {
|
|
@@ -344,9 +720,7 @@ export class AgentSessionProxy {
|
|
|
344
720
|
createdAt: Date.now(),
|
|
345
721
|
isStreaming: raw.done === false || raw.isStreaming === true,
|
|
346
722
|
};
|
|
347
|
-
this.
|
|
348
|
-
if (this.messages.length > 100)
|
|
349
|
-
this.messages.shift();
|
|
723
|
+
this.upsertMessage(message);
|
|
350
724
|
this.status = raw.done === true ? "idle" : "running";
|
|
351
725
|
this.sendUpdate({
|
|
352
726
|
kind: "message",
|
|
@@ -370,6 +744,15 @@ export class AgentSessionProxy {
|
|
|
370
744
|
}
|
|
371
745
|
this.permissionWaiters.clear();
|
|
372
746
|
}
|
|
747
|
+
upsertMessage(message) {
|
|
748
|
+
const existing = this.messages.findIndex((entry) => entry.id === message.id);
|
|
749
|
+
if (existing >= 0)
|
|
750
|
+
this.messages[existing] = message;
|
|
751
|
+
else
|
|
752
|
+
this.messages.push(message);
|
|
753
|
+
if (this.messages.length > 100)
|
|
754
|
+
this.messages.shift();
|
|
755
|
+
}
|
|
373
756
|
sendCapabilities() {
|
|
374
757
|
const enabled = Boolean(this.client && this.initialized && !this.error);
|
|
375
758
|
this.input.send(createEnvelope({
|
|
@@ -385,7 +768,7 @@ export class AgentSessionProxy {
|
|
|
385
768
|
supportsImages: false,
|
|
386
769
|
supportsAudio: false,
|
|
387
770
|
supportsPermission: enabled,
|
|
388
|
-
supportsPlan:
|
|
771
|
+
supportsPlan: enabled,
|
|
389
772
|
supportsCancel: enabled,
|
|
390
773
|
},
|
|
391
774
|
}));
|