@oyasmi/pipiclaw 0.5.1 → 0.5.3
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/README.md +308 -209
- package/dist/agent/channel-runner.d.ts +47 -0
- package/dist/agent/channel-runner.js +441 -0
- package/dist/agent/index.d.ts +3 -0
- package/dist/agent/index.js +2 -0
- package/dist/agent/progress-formatter.d.ts +4 -0
- package/dist/agent/progress-formatter.js +52 -0
- package/dist/agent/run-queue.d.ts +7 -0
- package/dist/agent/run-queue.js +26 -0
- package/dist/agent/runner-factory.d.ts +3 -0
- package/dist/agent/runner-factory.js +10 -0
- package/dist/agent/session-events.d.ts +14 -0
- package/dist/agent/session-events.js +215 -0
- package/dist/agent/session-resource-gate.d.ts +10 -0
- package/dist/agent/session-resource-gate.js +44 -0
- package/dist/agent/type-guards.d.ts +22 -0
- package/dist/agent/type-guards.js +106 -0
- package/dist/agent/types.d.ts +160 -0
- package/dist/agent/types.js +22 -0
- package/dist/agent.d.ts +2 -16
- package/dist/agent.js +1 -782
- package/dist/command-extension.d.ts +0 -1
- package/dist/command-extension.js +0 -1
- package/dist/commands.d.ts +0 -1
- package/dist/commands.js +0 -1
- package/dist/config-loader.d.ts +0 -1
- package/dist/config-loader.js +1 -2
- package/dist/context.d.ts +58 -15
- package/dist/context.js +50 -8
- package/dist/index.d.ts +12 -13
- package/dist/index.js +12 -13
- package/dist/log.d.ts +0 -1
- package/dist/log.js +0 -1
- package/dist/main.d.ts +0 -1
- package/dist/main.js +5 -405
- package/dist/memory/bootstrap.d.ts +6 -0
- package/dist/memory/bootstrap.js +46 -0
- package/dist/{memory-candidates.d.ts → memory/candidates.d.ts} +1 -1
- package/dist/{memory-candidates.js → memory/candidates.js} +33 -21
- package/dist/memory/chinese-words.d.ts +1 -0
- package/dist/memory/chinese-words.js +273 -0
- package/dist/{memory-consolidation.d.ts → memory/consolidation.d.ts} +0 -1
- package/dist/{memory-consolidation.js → memory/consolidation.js} +26 -35
- package/dist/{memory-files.d.ts → memory/files.d.ts} +0 -6
- package/dist/{memory-files.js → memory/files.js} +11 -36
- package/dist/{memory-lifecycle.d.ts → memory/lifecycle.d.ts} +23 -6
- package/dist/memory/lifecycle.js +246 -0
- package/dist/{memory-recall.d.ts → memory/recall.d.ts} +2 -2
- package/dist/memory/recall.js +501 -0
- package/dist/{session-memory.d.ts → memory/session.d.ts} +1 -1
- package/dist/{session-memory.js → memory/session.js} +31 -62
- package/dist/model-utils.d.ts +0 -1
- package/dist/model-utils.js +0 -1
- package/dist/paths.d.ts +0 -1
- package/dist/paths.js +0 -1
- package/dist/prompt-builder.d.ts +0 -1
- package/dist/prompt-builder.js +0 -1
- package/dist/runtime/bootstrap.d.ts +47 -0
- package/dist/runtime/bootstrap.js +450 -0
- package/dist/{delivery.d.ts → runtime/delivery.d.ts} +0 -1
- package/dist/{delivery.js → runtime/delivery.js} +1 -2
- package/dist/{dingtalk.d.ts → runtime/dingtalk.d.ts} +10 -1
- package/dist/{dingtalk.js → runtime/dingtalk.js} +87 -28
- package/dist/{events.d.ts → runtime/events.d.ts} +0 -1
- package/dist/{events.js → runtime/events.js} +1 -2
- package/dist/{store.d.ts → runtime/store.d.ts} +5 -1
- package/dist/{store.js → runtime/store.js} +60 -20
- package/dist/sandbox.d.ts +0 -1
- package/dist/sandbox.js +1 -2
- package/dist/{llm-json.d.ts → shared/llm-json.d.ts} +0 -1
- package/dist/{llm-json.js → shared/llm-json.js} +0 -1
- package/dist/shared/markdown-sections.d.ts +6 -0
- package/dist/{markdown-sections.js → shared/markdown-sections.js} +10 -4
- package/dist/{shell-escape.d.ts → shared/shell-escape.d.ts} +0 -1
- package/dist/{shell-escape.js → shared/shell-escape.js} +0 -1
- package/dist/shared/text-utils.d.ts +9 -0
- package/dist/shared/text-utils.js +36 -0
- package/dist/shared/type-guards.d.ts +5 -0
- package/dist/shared/type-guards.js +12 -0
- package/dist/shared/types.d.ts +14 -0
- package/dist/shared/types.js +1 -0
- package/dist/sidecar-worker.d.ts +0 -1
- package/dist/sidecar-worker.js +1 -8
- package/dist/{sub-agents.d.ts → subagents/discovery.d.ts} +0 -1
- package/dist/{sub-agents.js → subagents/discovery.js} +2 -3
- package/dist/{tools/subagent.d.ts → subagents/tool.d.ts} +2 -16
- package/dist/{tools/subagent.js → subagents/tool.js} +16 -38
- package/dist/tools/attach.d.ts +0 -1
- package/dist/tools/attach.js +0 -1
- package/dist/tools/bash.d.ts +0 -1
- package/dist/tools/bash.js +0 -1
- package/dist/tools/edit.d.ts +0 -1
- package/dist/tools/edit.js +1 -2
- package/dist/tools/index.d.ts +1 -2
- package/dist/tools/index.js +1 -2
- package/dist/tools/read.d.ts +0 -1
- package/dist/tools/read.js +1 -2
- package/dist/tools/truncate.d.ts +0 -1
- package/dist/tools/truncate.js +0 -1
- package/dist/tools/write-content.d.ts +0 -1
- package/dist/tools/write-content.js +1 -2
- package/dist/tools/write.d.ts +0 -1
- package/dist/tools/write.js +0 -1
- package/package.json +9 -3
- package/CHANGELOG.md +0 -47
- package/dist/agent.d.ts.map +0 -1
- package/dist/agent.js.map +0 -1
- package/dist/command-extension.d.ts.map +0 -1
- package/dist/command-extension.js.map +0 -1
- package/dist/commands.d.ts.map +0 -1
- package/dist/commands.js.map +0 -1
- package/dist/config-loader.d.ts.map +0 -1
- package/dist/config-loader.js.map +0 -1
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js.map +0 -1
- package/dist/delivery.d.ts.map +0 -1
- package/dist/delivery.js.map +0 -1
- package/dist/dingtalk.d.ts.map +0 -1
- package/dist/dingtalk.js.map +0 -1
- package/dist/events.d.ts.map +0 -1
- package/dist/events.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/llm-json.d.ts.map +0 -1
- package/dist/llm-json.js.map +0 -1
- package/dist/log.d.ts.map +0 -1
- package/dist/log.js.map +0 -1
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/markdown-sections.d.ts +0 -6
- package/dist/markdown-sections.d.ts.map +0 -1
- package/dist/markdown-sections.js.map +0 -1
- package/dist/memory-candidates.d.ts.map +0 -1
- package/dist/memory-candidates.js.map +0 -1
- package/dist/memory-consolidation.d.ts.map +0 -1
- package/dist/memory-consolidation.js.map +0 -1
- package/dist/memory-files.d.ts.map +0 -1
- package/dist/memory-files.js.map +0 -1
- package/dist/memory-lifecycle.d.ts.map +0 -1
- package/dist/memory-lifecycle.js +0 -150
- package/dist/memory-lifecycle.js.map +0 -1
- package/dist/memory-recall.d.ts.map +0 -1
- package/dist/memory-recall.js +0 -218
- package/dist/memory-recall.js.map +0 -1
- package/dist/model-utils.d.ts.map +0 -1
- package/dist/model-utils.js.map +0 -1
- package/dist/paths.d.ts.map +0 -1
- package/dist/paths.js.map +0 -1
- package/dist/prompt-builder.d.ts.map +0 -1
- package/dist/prompt-builder.js.map +0 -1
- package/dist/sandbox.d.ts.map +0 -1
- package/dist/sandbox.js.map +0 -1
- package/dist/session-memory-files.d.ts +0 -2
- package/dist/session-memory-files.d.ts.map +0 -1
- package/dist/session-memory-files.js +0 -2
- package/dist/session-memory-files.js.map +0 -1
- package/dist/session-memory.d.ts.map +0 -1
- package/dist/session-memory.js.map +0 -1
- package/dist/shell-escape.d.ts.map +0 -1
- package/dist/shell-escape.js.map +0 -1
- package/dist/sidecar-worker.d.ts.map +0 -1
- package/dist/sidecar-worker.js.map +0 -1
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js.map +0 -1
- package/dist/sub-agents.d.ts.map +0 -1
- package/dist/sub-agents.js.map +0 -1
- package/dist/tools/attach.d.ts.map +0 -1
- package/dist/tools/attach.js.map +0 -1
- package/dist/tools/bash.d.ts.map +0 -1
- package/dist/tools/bash.js.map +0 -1
- package/dist/tools/edit.d.ts.map +0 -1
- package/dist/tools/edit.js.map +0 -1
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/read.d.ts.map +0 -1
- package/dist/tools/read.js.map +0 -1
- package/dist/tools/subagent.d.ts.map +0 -1
- package/dist/tools/subagent.js.map +0 -1
- package/dist/tools/truncate.d.ts.map +0 -1
- package/dist/tools/truncate.js.map +0 -1
- package/dist/tools/write-content.d.ts.map +0 -1
- package/dist/tools/write-content.js.map +0 -1
- package/dist/tools/write.d.ts.map +0 -1
- package/dist/tools/write.js.map +0 -1
- package/docs/improve-memory/design.md +0 -537
- package/docs/improve-memory/interfaces-and-tests.md +0 -473
- package/docs/improve-memory/spec.md +0 -357
- package/docs/memory-rfc.md +0 -297
- package/docs/proj-review.md +0 -188
- package/docs/subagent/pi-subagent-analyse.txt +0 -190
- package/docs/subagent/pi-subagent-design.txt +0 -266
- package/docs/subagent/pi-subagent-phase1-plan.txt +0 -529
- package/docs/test-supplementation-plan.md +0 -553
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import * as log from "../log.js";
|
|
2
|
+
import { extractLabelFromArgs, truncate } from "../shared/text-utils.js";
|
|
3
|
+
import { isRecord } from "../shared/type-guards.js";
|
|
4
|
+
import { extractToolResultText, formatProgressEntry } from "./progress-formatter.js";
|
|
5
|
+
import { extractCustomCommandResultText, isAssistantEventMessage, isAutoCompactionEndEvent, isAutoCompactionStartEvent, isAutoRetryStartEvent, isMessageEndEvent, isMessageStartEvent, isSubAgentToolDetails, isTextPart, isThinkingPart, isToolExecutionEndEvent, isToolExecutionStartEvent, isToolExecutionUpdateEvent, isTurnEndEvent, } from "./type-guards.js";
|
|
6
|
+
function mergeSubAgentUsage(totalUsage, details) {
|
|
7
|
+
totalUsage.input += details.usage.input;
|
|
8
|
+
totalUsage.output += details.usage.output;
|
|
9
|
+
totalUsage.cacheRead += details.usage.cacheRead;
|
|
10
|
+
totalUsage.cacheWrite += details.usage.cacheWrite;
|
|
11
|
+
totalUsage.total += details.usage.total;
|
|
12
|
+
totalUsage.cost.input += details.usage.cost.input;
|
|
13
|
+
totalUsage.cost.output += details.usage.cost.output;
|
|
14
|
+
totalUsage.cost.cacheRead += details.usage.cost.cacheRead;
|
|
15
|
+
totalUsage.cost.cacheWrite += details.usage.cost.cacheWrite;
|
|
16
|
+
totalUsage.cost.total += details.usage.cost.total;
|
|
17
|
+
}
|
|
18
|
+
function mergeAssistantUsage(runState, usage) {
|
|
19
|
+
runState.totalUsage.input += usage.input;
|
|
20
|
+
runState.totalUsage.output += usage.output;
|
|
21
|
+
runState.totalUsage.cacheRead += usage.cacheRead;
|
|
22
|
+
runState.totalUsage.cacheWrite += usage.cacheWrite;
|
|
23
|
+
runState.totalUsage.total +=
|
|
24
|
+
usage.total ?? usage.totalTokens ?? usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
25
|
+
runState.totalUsage.cost.input += usage.cost.input;
|
|
26
|
+
runState.totalUsage.cost.output += usage.cost.output;
|
|
27
|
+
runState.totalUsage.cost.cacheRead += usage.cost.cacheRead;
|
|
28
|
+
runState.totalUsage.cost.cacheWrite += usage.cost.cacheWrite;
|
|
29
|
+
runState.totalUsage.cost.total += usage.cost.total;
|
|
30
|
+
}
|
|
31
|
+
export async function handleSessionEvent(event, context) {
|
|
32
|
+
const { ctx, logCtx, queue, pendingTools, store, runState, memoryLifecycle } = context;
|
|
33
|
+
if (isToolExecutionStartEvent(event)) {
|
|
34
|
+
const label = extractLabelFromArgs(event.args) || event.toolName;
|
|
35
|
+
pendingTools.set(event.toolCallId, {
|
|
36
|
+
toolName: event.toolName,
|
|
37
|
+
args: event.args,
|
|
38
|
+
startTime: Date.now(),
|
|
39
|
+
});
|
|
40
|
+
memoryLifecycle.noteToolCall();
|
|
41
|
+
log.logToolStart(logCtx, event.toolName, label, isRecord(event.args) ? event.args : {});
|
|
42
|
+
queue.enqueue(() => ctx.respond(formatProgressEntry("tool", label), false), "tool label");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (isToolExecutionUpdateEvent(event)) {
|
|
46
|
+
if (event.toolName !== "subagent") {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const partialText = truncate(extractToolResultText(event.partialResult), 200);
|
|
50
|
+
if (!partialText.trim()) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
queue.enqueue(() => ctx.respond(formatProgressEntry("tool", partialText), false), "tool update");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (isToolExecutionEndEvent(event)) {
|
|
57
|
+
const resultStr = extractToolResultText(event.result);
|
|
58
|
+
const pending = pendingTools.get(event.toolCallId);
|
|
59
|
+
pendingTools.delete(event.toolCallId);
|
|
60
|
+
const durationMs = pending ? Date.now() - pending.startTime : 0;
|
|
61
|
+
const subAgentDetails = event.toolName === "subagent" &&
|
|
62
|
+
isRecord(event.result) &&
|
|
63
|
+
"details" in event.result &&
|
|
64
|
+
isSubAgentToolDetails(event.result.details)
|
|
65
|
+
? event.result.details
|
|
66
|
+
: null;
|
|
67
|
+
if (subAgentDetails) {
|
|
68
|
+
mergeSubAgentUsage(runState.totalUsage, subAgentDetails);
|
|
69
|
+
const label = pending?.args &&
|
|
70
|
+
typeof pending.args === "object" &&
|
|
71
|
+
"label" in pending.args &&
|
|
72
|
+
typeof pending.args.label === "string"
|
|
73
|
+
? (pending.args.label ?? "subagent").trim()
|
|
74
|
+
: "subagent";
|
|
75
|
+
queue.enqueue(() => store?.logSubAgentRun(logCtx.channelId, {
|
|
76
|
+
date: new Date().toISOString(),
|
|
77
|
+
toolCallId: event.toolCallId,
|
|
78
|
+
label,
|
|
79
|
+
agent: subAgentDetails.agent,
|
|
80
|
+
source: subAgentDetails.source,
|
|
81
|
+
model: subAgentDetails.model,
|
|
82
|
+
tools: [...subAgentDetails.tools],
|
|
83
|
+
turns: subAgentDetails.turns,
|
|
84
|
+
toolCalls: subAgentDetails.toolCalls,
|
|
85
|
+
durationMs: subAgentDetails.durationMs,
|
|
86
|
+
failed: subAgentDetails.failed,
|
|
87
|
+
failureReason: subAgentDetails.failureReason,
|
|
88
|
+
output: resultStr.length > 16000 ? resultStr.slice(0, 16000) : resultStr,
|
|
89
|
+
outputTruncated: resultStr.length > 16000,
|
|
90
|
+
usage: {
|
|
91
|
+
...subAgentDetails.usage,
|
|
92
|
+
cost: { ...subAgentDetails.usage.cost },
|
|
93
|
+
},
|
|
94
|
+
}) ?? Promise.resolve(), "sub-agent run log");
|
|
95
|
+
}
|
|
96
|
+
const treatAsError = event.isError || Boolean(subAgentDetails?.failed);
|
|
97
|
+
if (treatAsError) {
|
|
98
|
+
log.logToolError(logCtx, event.toolName, durationMs, resultStr);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
log.logToolSuccess(logCtx, event.toolName, durationMs, resultStr);
|
|
102
|
+
}
|
|
103
|
+
if (treatAsError) {
|
|
104
|
+
queue.enqueue(() => ctx.respond(formatProgressEntry("error", truncate(resultStr, 200)), false), "tool error");
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (isMessageStartEvent(event)) {
|
|
109
|
+
if (isAssistantEventMessage(event.message)) {
|
|
110
|
+
log.logResponseStart(logCtx);
|
|
111
|
+
}
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (isMessageEndEvent(event)) {
|
|
115
|
+
const commandResultText = extractCustomCommandResultText(event.message);
|
|
116
|
+
if (commandResultText) {
|
|
117
|
+
runState.finalOutcome = { kind: "final", text: commandResultText };
|
|
118
|
+
log.logResponse(logCtx, commandResultText);
|
|
119
|
+
queue.enqueue(async () => {
|
|
120
|
+
const delivered = await ctx.respondPlain(commandResultText);
|
|
121
|
+
if (!delivered) {
|
|
122
|
+
await ctx.replaceMessage(commandResultText);
|
|
123
|
+
}
|
|
124
|
+
runState.finalResponseDelivered = true;
|
|
125
|
+
}, "command result");
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (isAssistantEventMessage(event.message)) {
|
|
129
|
+
const assistantMsg = event.message;
|
|
130
|
+
if (assistantMsg.stopReason) {
|
|
131
|
+
runState.stopReason = assistantMsg.stopReason;
|
|
132
|
+
}
|
|
133
|
+
if (assistantMsg.errorMessage) {
|
|
134
|
+
runState.errorMessage = assistantMsg.errorMessage;
|
|
135
|
+
}
|
|
136
|
+
if (assistantMsg.usage) {
|
|
137
|
+
mergeAssistantUsage(runState, assistantMsg.usage);
|
|
138
|
+
}
|
|
139
|
+
const thinkingParts = [];
|
|
140
|
+
const textParts = [];
|
|
141
|
+
let hasToolCalls = false;
|
|
142
|
+
for (const part of assistantMsg.content) {
|
|
143
|
+
if (isThinkingPart(part)) {
|
|
144
|
+
thinkingParts.push(part.thinking);
|
|
145
|
+
}
|
|
146
|
+
else if (isTextPart(part)) {
|
|
147
|
+
textParts.push(part.text);
|
|
148
|
+
}
|
|
149
|
+
else if (part.type === "toolCall") {
|
|
150
|
+
hasToolCalls = true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const text = textParts.join("\n");
|
|
154
|
+
for (const thinking of thinkingParts) {
|
|
155
|
+
log.logThinking(logCtx, thinking);
|
|
156
|
+
queue.enqueue(() => ctx.respond(formatProgressEntry("thinking", thinking), false), "thinking");
|
|
157
|
+
}
|
|
158
|
+
if (hasToolCalls && text.trim()) {
|
|
159
|
+
queue.enqueue(() => ctx.respond(formatProgressEntry("assistant", text), false), "assistant progress");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (isTurnEndEvent(event)) {
|
|
165
|
+
if (isAssistantEventMessage(event.message) && event.toolResults.length === 0) {
|
|
166
|
+
if (event.message.stopReason === "error" || event.message.stopReason === "aborted") {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const finalText = event.message.content
|
|
170
|
+
.filter((part) => isTextPart(part))
|
|
171
|
+
.map((part) => part.text)
|
|
172
|
+
.join("\n");
|
|
173
|
+
const trimmedFinalText = finalText.trim();
|
|
174
|
+
if (!trimmedFinalText) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (trimmedFinalText === "[SILENT]" || trimmedFinalText.startsWith("[SILENT]")) {
|
|
178
|
+
runState.finalOutcome = { kind: "silent" };
|
|
179
|
+
memoryLifecycle.noteCompletedAssistantTurn();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (runState.finalOutcome.kind === "final" && runState.finalOutcome.text.trim() === trimmedFinalText) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
runState.finalOutcome = { kind: "final", text: finalText };
|
|
186
|
+
memoryLifecycle.noteCompletedAssistantTurn();
|
|
187
|
+
log.logResponse(logCtx, finalText);
|
|
188
|
+
queue.enqueue(async () => {
|
|
189
|
+
const delivered = await ctx.respondPlain(finalText);
|
|
190
|
+
if (delivered) {
|
|
191
|
+
runState.finalResponseDelivered = true;
|
|
192
|
+
}
|
|
193
|
+
}, "final response");
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (isAutoCompactionStartEvent(event)) {
|
|
198
|
+
log.logInfo(`Auto-compaction started (reason: ${event.reason})`);
|
|
199
|
+
queue.enqueue(() => ctx.respond(formatProgressEntry("assistant", "Compacting context..."), false), "compaction start");
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (isAutoCompactionEndEvent(event)) {
|
|
203
|
+
if (event.result) {
|
|
204
|
+
log.logInfo(`Auto-compaction complete: ${event.result.tokensBefore} tokens compacted`);
|
|
205
|
+
}
|
|
206
|
+
else if (event.aborted) {
|
|
207
|
+
log.logInfo("Auto-compaction aborted");
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (isAutoRetryStartEvent(event)) {
|
|
212
|
+
log.logWarning(`Retrying (${event.attempt}/${event.maxAttempts})`, event.errorMessage);
|
|
213
|
+
queue.enqueue(() => ctx.respond(formatProgressEntry("assistant", `Retrying (${event.attempt}/${event.maxAttempts})...`), false), "retry");
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class SessionResourceGate {
|
|
2
|
+
private readonly reloadSessionResources;
|
|
3
|
+
private activePromptCount;
|
|
4
|
+
private refreshPending;
|
|
5
|
+
private reloadChain;
|
|
6
|
+
constructor(reloadSessionResources: () => Promise<void>);
|
|
7
|
+
runPrompt<T>(operation: () => Promise<T>): Promise<T>;
|
|
8
|
+
requestRefresh(): Promise<void>;
|
|
9
|
+
private flushPendingRefresh;
|
|
10
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export class SessionResourceGate {
|
|
2
|
+
constructor(reloadSessionResources) {
|
|
3
|
+
this.reloadSessionResources = reloadSessionResources;
|
|
4
|
+
this.activePromptCount = 0;
|
|
5
|
+
this.refreshPending = false;
|
|
6
|
+
this.reloadChain = Promise.resolve();
|
|
7
|
+
}
|
|
8
|
+
async runPrompt(operation) {
|
|
9
|
+
await this.reloadChain;
|
|
10
|
+
this.activePromptCount++;
|
|
11
|
+
try {
|
|
12
|
+
return await operation();
|
|
13
|
+
}
|
|
14
|
+
finally {
|
|
15
|
+
this.activePromptCount--;
|
|
16
|
+
await this.flushPendingRefresh();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async requestRefresh() {
|
|
20
|
+
this.refreshPending = true;
|
|
21
|
+
if (this.activePromptCount > 0) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
await this.flushPendingRefresh();
|
|
25
|
+
}
|
|
26
|
+
async flushPendingRefresh() {
|
|
27
|
+
if (!this.refreshPending || this.activePromptCount > 0) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
this.refreshPending = false;
|
|
31
|
+
const runReload = async () => {
|
|
32
|
+
if (this.activePromptCount > 0) {
|
|
33
|
+
this.refreshPending = true;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
await this.reloadSessionResources();
|
|
37
|
+
};
|
|
38
|
+
this.reloadChain = this.reloadChain.then(runReload, runReload);
|
|
39
|
+
await this.reloadChain;
|
|
40
|
+
if (this.refreshPending && this.activePromptCount === 0) {
|
|
41
|
+
await this.flushPendingRefresh();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SubAgentToolDetails } from "../subagents/tool.js";
|
|
2
|
+
import type { AssistantContentPart, AssistantEventMessage, AssistantUsageMessage, AutoCompactionEndEvent, AutoCompactionStartEvent, AutoRetryStartEvent, MessageEndEvent, MessageStartEvent, ToolExecutionEndEvent, ToolExecutionStartEvent, ToolExecutionUpdateEvent, TurnEndEvent } from "./types.js";
|
|
3
|
+
export declare function isAssistantEventMessage(value: unknown): value is AssistantEventMessage;
|
|
4
|
+
export declare function isAssistantUsageMessage(value: unknown): value is AssistantUsageMessage;
|
|
5
|
+
export declare function getLastAssistantUsage(messages: readonly unknown[]): AssistantUsageMessage | null;
|
|
6
|
+
export declare function isThinkingPart(part: AssistantContentPart): part is Extract<AssistantContentPart, {
|
|
7
|
+
type: "thinking";
|
|
8
|
+
}>;
|
|
9
|
+
export declare function isTextPart(part: AssistantContentPart): part is Extract<AssistantContentPart, {
|
|
10
|
+
type: "text";
|
|
11
|
+
}>;
|
|
12
|
+
export declare function isToolExecutionStartEvent(value: unknown): value is ToolExecutionStartEvent;
|
|
13
|
+
export declare function isToolExecutionUpdateEvent(value: unknown): value is ToolExecutionUpdateEvent;
|
|
14
|
+
export declare function isToolExecutionEndEvent(value: unknown): value is ToolExecutionEndEvent;
|
|
15
|
+
export declare function isMessageStartEvent(value: unknown): value is MessageStartEvent;
|
|
16
|
+
export declare function isMessageEndEvent(value: unknown): value is MessageEndEvent;
|
|
17
|
+
export declare function isTurnEndEvent(value: unknown): value is TurnEndEvent;
|
|
18
|
+
export declare function isAutoCompactionStartEvent(value: unknown): value is AutoCompactionStartEvent;
|
|
19
|
+
export declare function isAutoCompactionEndEvent(value: unknown): value is AutoCompactionEndEvent;
|
|
20
|
+
export declare function isAutoRetryStartEvent(value: unknown): value is AutoRetryStartEvent;
|
|
21
|
+
export declare function isSubAgentToolDetails(value: unknown): value is SubAgentToolDetails;
|
|
22
|
+
export declare function extractCustomCommandResultText(message: unknown): string | null;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { COMMAND_RESULT_CUSTOM_TYPE } from "../command-extension.js";
|
|
2
|
+
import { isRecord } from "../shared/type-guards.js";
|
|
3
|
+
function isMessageWithRole(value) {
|
|
4
|
+
return isRecord(value) && typeof value.role === "string";
|
|
5
|
+
}
|
|
6
|
+
export function isAssistantEventMessage(value) {
|
|
7
|
+
return (isMessageWithRole(value) && value.role === "assistant" && Array.isArray(value.content));
|
|
8
|
+
}
|
|
9
|
+
export function isAssistantUsageMessage(value) {
|
|
10
|
+
if (!isMessageWithRole(value) || value.role !== "assistant" || !("usage" in value) || !isRecord(value.usage)) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
return (typeof value.usage.input === "number" &&
|
|
14
|
+
typeof value.usage.output === "number" &&
|
|
15
|
+
typeof value.usage.cacheRead === "number" &&
|
|
16
|
+
typeof value.usage.cacheWrite === "number" &&
|
|
17
|
+
isRecord(value.usage.cost) &&
|
|
18
|
+
typeof value.usage.cost.input === "number" &&
|
|
19
|
+
typeof value.usage.cost.output === "number" &&
|
|
20
|
+
typeof value.usage.cost.cacheRead === "number" &&
|
|
21
|
+
typeof value.usage.cost.cacheWrite === "number" &&
|
|
22
|
+
typeof value.usage.cost.total === "number");
|
|
23
|
+
}
|
|
24
|
+
export function getLastAssistantUsage(messages) {
|
|
25
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
26
|
+
const message = messages[index];
|
|
27
|
+
if (isAssistantUsageMessage(message) && message.stopReason !== "aborted") {
|
|
28
|
+
return message;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
export function isThinkingPart(part) {
|
|
34
|
+
return part.type === "thinking" && typeof part.thinking === "string";
|
|
35
|
+
}
|
|
36
|
+
export function isTextPart(part) {
|
|
37
|
+
return part.type === "text" && typeof part.text === "string";
|
|
38
|
+
}
|
|
39
|
+
function hasEventType(value, type) {
|
|
40
|
+
return isRecord(value) && value.type === type;
|
|
41
|
+
}
|
|
42
|
+
export function isToolExecutionStartEvent(value) {
|
|
43
|
+
return (hasEventType(value, "tool_execution_start") &&
|
|
44
|
+
typeof value.toolCallId === "string" &&
|
|
45
|
+
typeof value.toolName === "string");
|
|
46
|
+
}
|
|
47
|
+
export function isToolExecutionUpdateEvent(value) {
|
|
48
|
+
return (hasEventType(value, "tool_execution_update") &&
|
|
49
|
+
typeof value.toolCallId === "string" &&
|
|
50
|
+
typeof value.toolName === "string");
|
|
51
|
+
}
|
|
52
|
+
export function isToolExecutionEndEvent(value) {
|
|
53
|
+
return (hasEventType(value, "tool_execution_end") &&
|
|
54
|
+
typeof value.toolCallId === "string" &&
|
|
55
|
+
typeof value.toolName === "string" &&
|
|
56
|
+
typeof value.isError === "boolean");
|
|
57
|
+
}
|
|
58
|
+
export function isMessageStartEvent(value) {
|
|
59
|
+
return hasEventType(value, "message_start") && "message" in value;
|
|
60
|
+
}
|
|
61
|
+
export function isMessageEndEvent(value) {
|
|
62
|
+
return hasEventType(value, "message_end") && "message" in value;
|
|
63
|
+
}
|
|
64
|
+
export function isTurnEndEvent(value) {
|
|
65
|
+
return hasEventType(value, "turn_end") && "message" in value && Array.isArray(value.toolResults);
|
|
66
|
+
}
|
|
67
|
+
export function isAutoCompactionStartEvent(value) {
|
|
68
|
+
return hasEventType(value, "auto_compaction_start") && (value.reason === "threshold" || value.reason === "overflow");
|
|
69
|
+
}
|
|
70
|
+
export function isAutoCompactionEndEvent(value) {
|
|
71
|
+
return hasEventType(value, "auto_compaction_end");
|
|
72
|
+
}
|
|
73
|
+
export function isAutoRetryStartEvent(value) {
|
|
74
|
+
return (hasEventType(value, "auto_retry_start") &&
|
|
75
|
+
typeof value.attempt === "number" &&
|
|
76
|
+
typeof value.maxAttempts === "number" &&
|
|
77
|
+
typeof value.errorMessage === "string");
|
|
78
|
+
}
|
|
79
|
+
export function isSubAgentToolDetails(value) {
|
|
80
|
+
if (!value || typeof value !== "object" || !("kind" in value) || value.kind !== "subagent") {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
if (!("usage" in value)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const usage = value.usage;
|
|
87
|
+
return (!!usage &&
|
|
88
|
+
typeof usage === "object" &&
|
|
89
|
+
"input" in usage &&
|
|
90
|
+
"output" in usage &&
|
|
91
|
+
"cacheRead" in usage &&
|
|
92
|
+
"cacheWrite" in usage &&
|
|
93
|
+
"cost" in usage);
|
|
94
|
+
}
|
|
95
|
+
export function extractCustomCommandResultText(message) {
|
|
96
|
+
if (!message ||
|
|
97
|
+
typeof message !== "object" ||
|
|
98
|
+
!("role" in message) ||
|
|
99
|
+
!("customType" in message) ||
|
|
100
|
+
message.role !== "custom" ||
|
|
101
|
+
message.customType !== COMMAND_RESULT_CUSTOM_TYPE) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const content = message.content;
|
|
105
|
+
return typeof content === "string" && content.trim() ? content : null;
|
|
106
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { BuiltInCommand } from "../commands.js";
|
|
2
|
+
import type { DingTalkContext } from "../runtime/dingtalk.js";
|
|
3
|
+
import type { ChannelStore } from "../runtime/store.js";
|
|
4
|
+
import type { UsageTotals } from "../shared/types.js";
|
|
5
|
+
export interface AgentRunner {
|
|
6
|
+
run(ctx: DingTalkContext, store: ChannelStore): Promise<{
|
|
7
|
+
stopReason: string;
|
|
8
|
+
errorMessage?: string;
|
|
9
|
+
}>;
|
|
10
|
+
handleBuiltinCommand(ctx: DingTalkContext, command: BuiltInCommand): Promise<void>;
|
|
11
|
+
queueSteer(text: string, userName?: string): Promise<void>;
|
|
12
|
+
queueFollowUp(text: string, userName?: string): Promise<void>;
|
|
13
|
+
abort(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export type FinalOutcome = {
|
|
16
|
+
kind: "none";
|
|
17
|
+
} | {
|
|
18
|
+
kind: "silent";
|
|
19
|
+
} | {
|
|
20
|
+
kind: "final";
|
|
21
|
+
text: string;
|
|
22
|
+
};
|
|
23
|
+
export interface PendingTool {
|
|
24
|
+
toolName: string;
|
|
25
|
+
args: unknown;
|
|
26
|
+
startTime: number;
|
|
27
|
+
}
|
|
28
|
+
export interface RunQueue {
|
|
29
|
+
enqueue(fn: () => Promise<void>, errorContext: string): void;
|
|
30
|
+
enqueueMessage(text: string, target: "main" | "thread", errorContext: string, doLog?: boolean): void;
|
|
31
|
+
}
|
|
32
|
+
export interface RunLogContext {
|
|
33
|
+
channelId: string;
|
|
34
|
+
userName?: string;
|
|
35
|
+
channelName?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface RunState {
|
|
38
|
+
ctx: DingTalkContext | null;
|
|
39
|
+
logCtx: RunLogContext | null;
|
|
40
|
+
store: ChannelStore | null;
|
|
41
|
+
queue: RunQueue | null;
|
|
42
|
+
pendingTools: Map<string, PendingTool>;
|
|
43
|
+
totalUsage: UsageTotals;
|
|
44
|
+
stopReason: string;
|
|
45
|
+
errorMessage: string | undefined;
|
|
46
|
+
finalOutcome: FinalOutcome;
|
|
47
|
+
finalResponseDelivered: boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare function createEmptyRunState(): RunState;
|
|
50
|
+
export interface AssistantUsage {
|
|
51
|
+
input: number;
|
|
52
|
+
output: number;
|
|
53
|
+
cacheRead: number;
|
|
54
|
+
cacheWrite: number;
|
|
55
|
+
total?: number;
|
|
56
|
+
totalTokens?: number;
|
|
57
|
+
cost: {
|
|
58
|
+
input: number;
|
|
59
|
+
output: number;
|
|
60
|
+
cacheRead: number;
|
|
61
|
+
cacheWrite: number;
|
|
62
|
+
total: number;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export type AssistantContentPart = {
|
|
66
|
+
type: "thinking";
|
|
67
|
+
thinking: string;
|
|
68
|
+
} | {
|
|
69
|
+
type: "text";
|
|
70
|
+
text: string;
|
|
71
|
+
} | {
|
|
72
|
+
type: "toolCall";
|
|
73
|
+
} | {
|
|
74
|
+
type: string;
|
|
75
|
+
[key: string]: unknown;
|
|
76
|
+
};
|
|
77
|
+
export interface AssistantEventMessage {
|
|
78
|
+
role: "assistant";
|
|
79
|
+
content: AssistantContentPart[];
|
|
80
|
+
stopReason?: string;
|
|
81
|
+
errorMessage?: string;
|
|
82
|
+
usage?: AssistantUsage;
|
|
83
|
+
}
|
|
84
|
+
export interface AssistantUsageMessage {
|
|
85
|
+
role: "assistant";
|
|
86
|
+
stopReason?: string;
|
|
87
|
+
usage: AssistantUsage;
|
|
88
|
+
}
|
|
89
|
+
export type SessionEvent = {
|
|
90
|
+
type: "tool_execution_start";
|
|
91
|
+
toolCallId: string;
|
|
92
|
+
toolName: string;
|
|
93
|
+
args: unknown;
|
|
94
|
+
} | {
|
|
95
|
+
type: "tool_execution_update";
|
|
96
|
+
toolCallId: string;
|
|
97
|
+
toolName: string;
|
|
98
|
+
args: unknown;
|
|
99
|
+
partialResult: unknown;
|
|
100
|
+
} | {
|
|
101
|
+
type: "tool_execution_end";
|
|
102
|
+
toolCallId: string;
|
|
103
|
+
toolName: string;
|
|
104
|
+
result: unknown;
|
|
105
|
+
isError: boolean;
|
|
106
|
+
} | {
|
|
107
|
+
type: "message_start";
|
|
108
|
+
message: unknown;
|
|
109
|
+
} | {
|
|
110
|
+
type: "message_end";
|
|
111
|
+
message: unknown;
|
|
112
|
+
} | {
|
|
113
|
+
type: "turn_end";
|
|
114
|
+
message: unknown;
|
|
115
|
+
toolResults: unknown[];
|
|
116
|
+
} | {
|
|
117
|
+
type: "auto_compaction_start";
|
|
118
|
+
reason: "threshold" | "overflow";
|
|
119
|
+
} | {
|
|
120
|
+
type: "auto_compaction_end";
|
|
121
|
+
result?: {
|
|
122
|
+
tokensBefore: number;
|
|
123
|
+
};
|
|
124
|
+
aborted?: boolean;
|
|
125
|
+
} | {
|
|
126
|
+
type: "auto_retry_start";
|
|
127
|
+
attempt: number;
|
|
128
|
+
maxAttempts: number;
|
|
129
|
+
delayMs?: number;
|
|
130
|
+
errorMessage: string;
|
|
131
|
+
};
|
|
132
|
+
export type ToolExecutionStartEvent = Extract<SessionEvent, {
|
|
133
|
+
type: "tool_execution_start";
|
|
134
|
+
}>;
|
|
135
|
+
export type ToolExecutionUpdateEvent = Extract<SessionEvent, {
|
|
136
|
+
type: "tool_execution_update";
|
|
137
|
+
}>;
|
|
138
|
+
export type ToolExecutionEndEvent = Extract<SessionEvent, {
|
|
139
|
+
type: "tool_execution_end";
|
|
140
|
+
}>;
|
|
141
|
+
export type MessageStartEvent = Extract<SessionEvent, {
|
|
142
|
+
type: "message_start";
|
|
143
|
+
}>;
|
|
144
|
+
export type MessageEndEvent = Extract<SessionEvent, {
|
|
145
|
+
type: "message_end";
|
|
146
|
+
}>;
|
|
147
|
+
export type TurnEndEvent = Extract<SessionEvent, {
|
|
148
|
+
type: "turn_end";
|
|
149
|
+
}>;
|
|
150
|
+
export type AutoCompactionStartEvent = Extract<SessionEvent, {
|
|
151
|
+
type: "auto_compaction_start";
|
|
152
|
+
}>;
|
|
153
|
+
export type AutoCompactionEndEvent = Extract<SessionEvent, {
|
|
154
|
+
type: "auto_compaction_end";
|
|
155
|
+
}>;
|
|
156
|
+
export type AutoRetryStartEvent = Extract<SessionEvent, {
|
|
157
|
+
type: "auto_retry_start";
|
|
158
|
+
}>;
|
|
159
|
+
export type ProgressEntryKind = "tool" | "thinking" | "error" | "assistant";
|
|
160
|
+
export declare const MAX_USER_MESSAGE_CHARS = 12000;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function createEmptyRunState() {
|
|
2
|
+
return {
|
|
3
|
+
ctx: null,
|
|
4
|
+
logCtx: null,
|
|
5
|
+
store: null,
|
|
6
|
+
queue: null,
|
|
7
|
+
pendingTools: new Map(),
|
|
8
|
+
totalUsage: {
|
|
9
|
+
input: 0,
|
|
10
|
+
output: 0,
|
|
11
|
+
cacheRead: 0,
|
|
12
|
+
cacheWrite: 0,
|
|
13
|
+
total: 0,
|
|
14
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
15
|
+
},
|
|
16
|
+
stopReason: "stop",
|
|
17
|
+
errorMessage: undefined,
|
|
18
|
+
finalOutcome: { kind: "none" },
|
|
19
|
+
finalResponseDelivered: false,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export const MAX_USER_MESSAGE_CHARS = 12_000;
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,16 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { type SandboxConfig } from "./sandbox.js";
|
|
4
|
-
import type { ChannelStore } from "./store.js";
|
|
5
|
-
export interface AgentRunner {
|
|
6
|
-
run(ctx: DingTalkContext, store: ChannelStore): Promise<{
|
|
7
|
-
stopReason: string;
|
|
8
|
-
errorMessage?: string;
|
|
9
|
-
}>;
|
|
10
|
-
handleBuiltinCommand(ctx: DingTalkContext, command: BuiltInCommand): Promise<void>;
|
|
11
|
-
queueSteer(text: string, userName?: string): Promise<void>;
|
|
12
|
-
queueFollowUp(text: string, userName?: string): Promise<void>;
|
|
13
|
-
abort(): Promise<void>;
|
|
14
|
-
}
|
|
15
|
-
export declare function getOrCreateRunner(sandboxConfig: SandboxConfig, channelId: string, channelDir: string): AgentRunner;
|
|
16
|
-
//# sourceMappingURL=agent.d.ts.map
|
|
1
|
+
export type { AgentRunner } from "./agent/index.js";
|
|
2
|
+
export { ChannelRunner, getOrCreateRunner } from "./agent/index.js";
|