@geminixiang/mikan 1.0.0-beta.43 → 1.0.0-beta.44
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/CHANGELOG.md +26 -0
- package/dist/adapters/discord/bot.d.ts.map +1 -1
- package/dist/adapters/discord/bot.js +3 -17
- package/dist/adapters/discord/bot.js.map +1 -1
- package/dist/adapters/discord/components.d.ts +2 -7
- package/dist/adapters/discord/components.d.ts.map +1 -1
- package/dist/adapters/discord/components.js.map +1 -1
- package/dist/adapters/discord/types.d.ts +7 -0
- package/dist/adapters/discord/types.d.ts.map +1 -1
- package/dist/adapters/discord/types.js.map +1 -1
- package/dist/adapters/github/bot.d.ts.map +1 -1
- package/dist/adapters/github/bot.js +10 -2
- package/dist/adapters/github/bot.js.map +1 -1
- package/dist/adapters/github/types.d.ts +5 -0
- package/dist/adapters/github/types.d.ts.map +1 -1
- package/dist/adapters/github/types.js.map +1 -1
- package/dist/adapters/github/webhook.d.ts +2 -5
- package/dist/adapters/github/webhook.d.ts.map +1 -1
- package/dist/adapters/github/webhook.js.map +1 -1
- package/dist/adapters/markdown-tables.d.ts +2 -7
- package/dist/adapters/markdown-tables.d.ts.map +1 -1
- package/dist/adapters/markdown-tables.js.map +1 -1
- package/dist/adapters/slack/assistant.d.ts +2 -30
- package/dist/adapters/slack/assistant.d.ts.map +1 -1
- package/dist/adapters/slack/assistant.js +1 -0
- package/dist/adapters/slack/assistant.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +3 -4
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +19 -64
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/types.d.ts +29 -0
- package/dist/adapters/slack/types.d.ts.map +1 -1
- package/dist/adapters/slack/types.js.map +1 -1
- package/dist/adapters/telegram/bot.d.ts.map +1 -1
- package/dist/adapters/telegram/bot.js +39 -65
- package/dist/adapters/telegram/bot.js.map +1 -1
- package/dist/adapters/types.d.ts +7 -0
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/agent/catalog.d.ts +34 -0
- package/dist/agent/catalog.d.ts.map +1 -0
- package/dist/agent/catalog.js +236 -0
- package/dist/agent/catalog.js.map +1 -0
- package/dist/agent/execution.d.ts +32 -0
- package/dist/agent/execution.d.ts.map +1 -0
- package/dist/agent/execution.js +169 -0
- package/dist/agent/execution.js.map +1 -0
- package/dist/agent/index.d.ts +9 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +8 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/presenter.d.ts +46 -0
- package/dist/agent/presenter.d.ts.map +1 -0
- package/dist/agent/presenter.js +673 -0
- package/dist/agent/presenter.js.map +1 -0
- package/dist/agent/prompt.d.ts +30 -0
- package/dist/agent/prompt.d.ts.map +1 -0
- package/dist/agent/prompt.js +355 -0
- package/dist/agent/prompt.js.map +1 -0
- package/dist/agent/runner.d.ts +10 -0
- package/dist/agent/runner.d.ts.map +1 -0
- package/dist/agent/runner.js +441 -0
- package/dist/agent/runner.js.map +1 -0
- package/dist/agent/types.d.ts +99 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +4 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/cli/boot.d.ts.map +1 -1
- package/dist/cli/boot.js +5 -2
- package/dist/cli/boot.js.map +1 -1
- package/dist/cli/sessions.d.ts +2 -0
- package/dist/cli/sessions.d.ts.map +1 -0
- package/dist/cli/sessions.js +78 -0
- package/dist/cli/sessions.js.map +1 -0
- package/dist/cli/types.d.ts +3 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli/types.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +12 -4
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/manifest.d.ts.map +1 -1
- package/dist/commands/manifest.js +3 -0
- package/dist/commands/manifest.js.map +1 -1
- package/dist/commands/registry.d.ts.map +1 -1
- package/dist/commands/registry.js +25 -10
- package/dist/commands/registry.js.map +1 -1
- package/dist/commands/sandbox.js +1 -1
- package/dist/commands/sandbox.js.map +1 -1
- package/dist/commands/types.d.ts +6 -0
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js.map +1 -1
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +36 -0
- package/dist/config.js.map +1 -1
- package/dist/execution-resolver.js +1 -1
- package/dist/execution-resolver.js.map +1 -1
- package/dist/harness/event-format.d.ts +7 -0
- package/dist/harness/event-format.d.ts.map +1 -1
- package/dist/harness/event-format.js +17 -0
- package/dist/harness/event-format.js.map +1 -1
- package/dist/harness/extensions/loader.d.ts.map +1 -1
- package/dist/harness/extensions/loader.js +12 -2
- package/dist/harness/extensions/loader.js.map +1 -1
- package/dist/harness/extensions/registry.d.ts +14 -1
- package/dist/harness/extensions/registry.d.ts.map +1 -1
- package/dist/harness/extensions/registry.js +49 -3
- package/dist/harness/extensions/registry.js.map +1 -1
- package/dist/harness/index.d.ts +3 -3
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +2 -2
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/runner.d.ts +1 -2
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +27 -40
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session-store.d.ts +50 -51
- package/dist/harness/session-store.d.ts.map +1 -1
- package/dist/harness/session-store.js +439 -271
- package/dist/harness/session-store.js.map +1 -1
- package/dist/harness/subagent-runner.d.ts +1 -1
- package/dist/harness/subagent-runner.d.ts.map +1 -1
- package/dist/harness/subagent-runner.js +9 -5
- package/dist/harness/subagent-runner.js.map +1 -1
- package/dist/harness/subagent-slots.d.ts.map +1 -0
- package/dist/harness/subagent-slots.js.map +1 -0
- package/dist/harness/types.d.ts +29 -16
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/usage.d.ts +9 -4
- package/dist/harness/usage.d.ts.map +1 -1
- package/dist/harness/usage.js +9 -3
- package/dist/harness/usage.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/main.js +5 -0
- package/dist/main.js.map +1 -1
- package/dist/mcp/loader.d.ts +11 -0
- package/dist/mcp/loader.d.ts.map +1 -0
- package/dist/mcp/loader.js +126 -0
- package/dist/mcp/loader.js.map +1 -0
- package/dist/mcp/types.d.ts +38 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +2 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/provisioner.d.ts +1 -0
- package/dist/provisioner.d.ts.map +1 -1
- package/dist/provisioner.js +22 -3
- package/dist/provisioner.js.map +1 -1
- package/dist/runtime/conversation-runtime.d.ts.map +1 -1
- package/dist/runtime/conversation-runtime.js +44 -25
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/session-lifecycle.d.ts +13 -0
- package/dist/runtime/session-lifecycle.d.ts.map +1 -1
- package/dist/runtime/session-lifecycle.js +62 -1
- package/dist/runtime/session-lifecycle.js.map +1 -1
- package/dist/runtime/types.d.ts +1 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/identity.d.ts +12 -5
- package/dist/sandbox/identity.d.ts.map +1 -1
- package/dist/sandbox/identity.js +14 -5
- package/dist/sandbox/identity.js.map +1 -1
- package/dist/sessions/chat-history-sync.d.ts +2 -2
- package/dist/sessions/chat-history-sync.d.ts.map +1 -1
- package/dist/sessions/chat-history-sync.js +48 -50
- package/dist/sessions/chat-history-sync.js.map +1 -1
- package/dist/sessions/migrate-v3.d.ts +18 -0
- package/dist/sessions/migrate-v3.d.ts.map +1 -0
- package/dist/sessions/migrate-v3.js +359 -0
- package/dist/sessions/migrate-v3.js.map +1 -0
- package/dist/sessions/rotation.js +4 -2
- package/dist/sessions/rotation.js.map +1 -1
- package/dist/sessions/store.d.ts +1 -1
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +19 -36
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +1 -2
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/settings-mutation.d.ts.map +1 -1
- package/dist/settings-mutation.js +6 -1
- package/dist/settings-mutation.js.map +1 -1
- package/dist/tools/event.d.ts.map +1 -1
- package/dist/tools/event.js +2 -12
- package/dist/tools/event.js.map +1 -1
- package/dist/tools/index.d.ts +2 -3
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +0 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/sandbox.d.ts +2 -2
- package/dist/tools/sandbox.d.ts.map +1 -1
- package/dist/tools/sandbox.js +1 -1
- package/dist/tools/sandbox.js.map +1 -1
- package/dist/types.d.ts +8 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/web/admin/portal.d.ts.map +1 -1
- package/dist/web/admin/portal.js +323 -27
- package/dist/web/admin/portal.js.map +1 -1
- package/dist/web/session-view/portal.js +6 -6
- package/dist/web/session-view/portal.js.map +1 -1
- package/dist/web/session-view/service.d.ts +2 -2
- package/dist/web/session-view/service.d.ts.map +1 -1
- package/dist/web/session-view/service.js +51 -75
- package/dist/web/session-view/service.js.map +1 -1
- package/package.json +4 -3
- package/dist/agent.d.ts +0 -34
- package/dist/agent.d.ts.map +0 -1
- package/dist/agent.js +0 -1820
- package/dist/agent.js.map +0 -1
- package/dist/tools/subagent-slots.d.ts.map +0 -1
- package/dist/tools/subagent-slots.js.map +0 -1
- /package/dist/{tools → harness}/subagent-slots.d.ts +0 -0
- /package/dist/{tools → harness}/subagent-slots.js +0 -0
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
import {} from "@earendil-works/pi-ai";
|
|
2
|
+
import { mergeSubagentProgress, parseSubagentProgressSnapshot, renderSubagentDashboard, settleSubagentProgress, } from "../subagent-progress.js";
|
|
3
|
+
import * as log from "../log.js";
|
|
4
|
+
import { addLifecycleBreadcrumb, metricAttributes, reportUserFacingError, } from "../observability/sentry.js";
|
|
5
|
+
import * as Sentry from "@sentry/node";
|
|
6
|
+
import { emitAgentEvent } from "../agent-events.js";
|
|
7
|
+
import { appendTriggerAttribution } from "./prompt.js";
|
|
8
|
+
function createEmptyUsageTotals() {
|
|
9
|
+
return {
|
|
10
|
+
input: 0,
|
|
11
|
+
output: 0,
|
|
12
|
+
cacheRead: 0,
|
|
13
|
+
cacheWrite: 0,
|
|
14
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function createRunState() {
|
|
18
|
+
return {
|
|
19
|
+
responder: null,
|
|
20
|
+
logCtx: null,
|
|
21
|
+
queue: null,
|
|
22
|
+
pendingTools: new Map(),
|
|
23
|
+
toolProgress: new Map(),
|
|
24
|
+
subagentProgress: new Map(),
|
|
25
|
+
completedSubagentProgress: [],
|
|
26
|
+
subagentToolCalls: new Set(),
|
|
27
|
+
subagentProgressShown: false,
|
|
28
|
+
suppressResponseDeltas: false,
|
|
29
|
+
lastSubagentProgressAt: 0,
|
|
30
|
+
toolProgressTimer: undefined,
|
|
31
|
+
totalUsage: createEmptyUsageTotals(),
|
|
32
|
+
llmCallCount: 0,
|
|
33
|
+
stopReason: "stop",
|
|
34
|
+
errorMessage: undefined,
|
|
35
|
+
reportedLlmError: false,
|
|
36
|
+
finalResponseHandledByTool: false,
|
|
37
|
+
triggerAttribution: undefined,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function resetRunState(runState, responder, sessionConversation, userName, sessionUuid, triggerAttribution) {
|
|
41
|
+
runState.responder = responder;
|
|
42
|
+
runState.logCtx = {
|
|
43
|
+
conversationId: sessionConversation,
|
|
44
|
+
userName,
|
|
45
|
+
conversationName: undefined,
|
|
46
|
+
sessionId: sessionUuid,
|
|
47
|
+
};
|
|
48
|
+
runState.pendingTools.clear();
|
|
49
|
+
runState.toolProgress.clear();
|
|
50
|
+
runState.subagentProgress.clear();
|
|
51
|
+
runState.completedSubagentProgress = [];
|
|
52
|
+
runState.subagentToolCalls.clear();
|
|
53
|
+
runState.subagentProgressShown = false;
|
|
54
|
+
runState.suppressResponseDeltas = false;
|
|
55
|
+
runState.lastSubagentProgressAt = 0;
|
|
56
|
+
if (runState.toolProgressTimer)
|
|
57
|
+
clearTimeout(runState.toolProgressTimer);
|
|
58
|
+
runState.toolProgressTimer = undefined;
|
|
59
|
+
runState.totalUsage = createEmptyUsageTotals();
|
|
60
|
+
runState.llmCallCount = 0;
|
|
61
|
+
runState.stopReason = "stop";
|
|
62
|
+
runState.errorMessage = undefined;
|
|
63
|
+
runState.reportedLlmError = false;
|
|
64
|
+
runState.finalResponseHandledByTool = false;
|
|
65
|
+
runState.triggerAttribution = triggerAttribution;
|
|
66
|
+
}
|
|
67
|
+
export function createRunQueue(responder, runState) {
|
|
68
|
+
let queueChain = Promise.resolve();
|
|
69
|
+
return {
|
|
70
|
+
queue: {
|
|
71
|
+
enqueue(fn, errorContext) {
|
|
72
|
+
queueChain = queueChain.then(async () => {
|
|
73
|
+
if (runState.finalResponseHandledByTool)
|
|
74
|
+
return;
|
|
75
|
+
try {
|
|
76
|
+
await fn();
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
80
|
+
log.logWarning(`API error (${errorContext})`, errMsg);
|
|
81
|
+
try {
|
|
82
|
+
await responder.respondDiagnostic(`Error: ${errMsg}`, { style: "error" });
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Ignore
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
wait: () => queueChain,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function getFinalAssistantText(session) {
|
|
95
|
+
const lastAssistant = session.messages.findLast((message) => message.role === "assistant");
|
|
96
|
+
return (lastAssistant?.content
|
|
97
|
+
.filter((content) => content.type === "text")
|
|
98
|
+
.map((content) => content.text)
|
|
99
|
+
.join("\n") || "");
|
|
100
|
+
}
|
|
101
|
+
export function isEventTriggerAttribution(triggerAttribution) {
|
|
102
|
+
return triggerAttribution?.startsWith("[event:") === true;
|
|
103
|
+
}
|
|
104
|
+
function extractToolLabel(toolName, args) {
|
|
105
|
+
const label = args?.label;
|
|
106
|
+
if (typeof label !== "string")
|
|
107
|
+
return toolName;
|
|
108
|
+
return label.trim() || toolName;
|
|
109
|
+
}
|
|
110
|
+
/** Non-subagent tool activity lines; subagent calls render as the dashboard. */
|
|
111
|
+
function formatToolProgress(runState) {
|
|
112
|
+
const lines = Array.from(runState.toolProgress.entries()).flatMap(([toolCallId, item]) => {
|
|
113
|
+
if (runState.subagentToolCalls.has(toolCallId))
|
|
114
|
+
return [];
|
|
115
|
+
const marker = item.status === "running" ? "•" : item.status === "error" ? "✗" : "✓";
|
|
116
|
+
return [`${marker} ${item.label}`];
|
|
117
|
+
});
|
|
118
|
+
return lines.join("\n");
|
|
119
|
+
}
|
|
120
|
+
function formatResponseWithToolProgress(text, runState) {
|
|
121
|
+
const progress = formatToolProgress(runState);
|
|
122
|
+
return [progress, text].filter(Boolean).join("\n\n");
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The one dashboard render path. A responder that overrides
|
|
126
|
+
* `replaceSubagentProgress` converts the snapshot for a pipeline that is not
|
|
127
|
+
* response-source Markdown (Telegram HTML); every other platform receives the
|
|
128
|
+
* Markdown dashboard — "dashboard, blank line, answer" — through
|
|
129
|
+
* `replaceResponse`, the same conversion as any response.
|
|
130
|
+
*/
|
|
131
|
+
async function replaceWithSubagentDashboard(responder, snapshot, finalText, options) {
|
|
132
|
+
if (responder.replaceSubagentProgress) {
|
|
133
|
+
await responder.replaceSubagentProgress(snapshot, finalText);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const dashboard = renderSubagentDashboard(snapshot);
|
|
137
|
+
await responder.replaceResponse(finalText ? `${dashboard}\n\n${finalText}` : dashboard, options);
|
|
138
|
+
}
|
|
139
|
+
async function replaceResponseWithToolProgress(responder, runState, subagentProgress = mergeSubagentProgress([...runState.subagentProgress.values()])) {
|
|
140
|
+
if (subagentProgress) {
|
|
141
|
+
await replaceWithSubagentDashboard(responder, subagentProgress);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const progress = formatToolProgress(runState);
|
|
145
|
+
if (progress)
|
|
146
|
+
await responder.replaceResponse(progress);
|
|
147
|
+
}
|
|
148
|
+
const TOOL_PROGRESS_DEBOUNCE_MS = 500;
|
|
149
|
+
const SUBAGENT_PROGRESS_THROTTLE_MS = 2000;
|
|
150
|
+
function subagentProgressDelay(runState) {
|
|
151
|
+
if (!runState.subagentProgressShown)
|
|
152
|
+
return 0;
|
|
153
|
+
return Math.max(0, runState.lastSubagentProgressAt + SUBAGENT_PROGRESS_THROTTLE_MS - Date.now());
|
|
154
|
+
}
|
|
155
|
+
function scheduleToolProgressUpdate(responder, runState) {
|
|
156
|
+
if (runState.toolProgressTimer)
|
|
157
|
+
return;
|
|
158
|
+
const subagentProgress = mergeSubagentProgress([...runState.subagentProgress.values()]);
|
|
159
|
+
const delay = subagentProgress ? subagentProgressDelay(runState) : TOOL_PROGRESS_DEBOUNCE_MS;
|
|
160
|
+
runState.toolProgressTimer = setTimeout(() => {
|
|
161
|
+
runState.toolProgressTimer = undefined;
|
|
162
|
+
const snapshot = mergeSubagentProgress([...runState.subagentProgress.values()]);
|
|
163
|
+
if (snapshot) {
|
|
164
|
+
runState.subagentProgressShown = true;
|
|
165
|
+
runState.lastSubagentProgressAt = Date.now();
|
|
166
|
+
}
|
|
167
|
+
runState.queue?.enqueue(() => replaceResponseWithToolProgress(responder, runState, snapshot), "tool progress update");
|
|
168
|
+
}, delay);
|
|
169
|
+
runState.toolProgressTimer.unref();
|
|
170
|
+
}
|
|
171
|
+
function flushToolProgressUpdate(responder, runState) {
|
|
172
|
+
if (runState.toolProgressTimer)
|
|
173
|
+
clearTimeout(runState.toolProgressTimer);
|
|
174
|
+
runState.toolProgressTimer = undefined;
|
|
175
|
+
const subagentProgress = mergeSubagentProgress([...runState.subagentProgress.values()]);
|
|
176
|
+
if (subagentProgress) {
|
|
177
|
+
runState.subagentProgressShown = true;
|
|
178
|
+
runState.lastSubagentProgressAt = Date.now();
|
|
179
|
+
}
|
|
180
|
+
runState.queue?.enqueue(() => replaceResponseWithToolProgress(responder, runState, subagentProgress), "tool progress update");
|
|
181
|
+
}
|
|
182
|
+
function extractSubagentProgress(partialResult) {
|
|
183
|
+
if (!partialResult || typeof partialResult !== "object")
|
|
184
|
+
return undefined;
|
|
185
|
+
const details = partialResult.details;
|
|
186
|
+
if (!details || typeof details !== "object")
|
|
187
|
+
return undefined;
|
|
188
|
+
return parseSubagentProgressSnapshot(details.progress);
|
|
189
|
+
}
|
|
190
|
+
export async function finalizeRunResponse(responder, session, runState, options) {
|
|
191
|
+
if (runState.stopReason === "error" && runState.errorMessage) {
|
|
192
|
+
if (!runState.reportedLlmError) {
|
|
193
|
+
runState.reportedLlmError = true;
|
|
194
|
+
reportUserFacingError(new Error("LLM run completed with error stop reason"), {
|
|
195
|
+
domain: "llm",
|
|
196
|
+
surface: "assistant_response",
|
|
197
|
+
operation: "llm_turn",
|
|
198
|
+
severity: "error",
|
|
199
|
+
platform: options?.platform,
|
|
200
|
+
provider: options?.model?.provider,
|
|
201
|
+
model: options?.model?.name,
|
|
202
|
+
stopReason: runState.stopReason,
|
|
203
|
+
context: {
|
|
204
|
+
sessionConversation: options?.sessionConversation,
|
|
205
|
+
sessionUuid: options?.sessionUuid,
|
|
206
|
+
hasErrorMessage: true,
|
|
207
|
+
llmCallCount: runState.llmCallCount,
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
await responder.replaceResponse("_Sorry, something went wrong_");
|
|
213
|
+
await responder.respondDiagnostic(`Error: ${runState.errorMessage}`, {
|
|
214
|
+
style: "error",
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
219
|
+
log.logWarning("Failed to post error message", errMsg);
|
|
220
|
+
reportUserFacingError(err, {
|
|
221
|
+
domain: "chat_platform",
|
|
222
|
+
surface: "final_response",
|
|
223
|
+
operation: "finalize_error_response",
|
|
224
|
+
severity: "error",
|
|
225
|
+
platform: options?.platform,
|
|
226
|
+
context: {
|
|
227
|
+
sessionConversation: options?.sessionConversation,
|
|
228
|
+
sessionUuid: options?.sessionUuid,
|
|
229
|
+
stopReason: runState.stopReason,
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const finalText = getFinalAssistantText(session);
|
|
236
|
+
if (runState.finalResponseHandledByTool) {
|
|
237
|
+
log.logInfo("Final response already handled by tool - skipping final replacement");
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (finalText.trim() === "[SILENT]" || finalText.trim().startsWith("[SILENT]")) {
|
|
241
|
+
try {
|
|
242
|
+
await responder.deleteResponse();
|
|
243
|
+
log.logInfo("Silent response - deleted message and thread");
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
247
|
+
log.logWarning("Failed to delete message for silent response", errMsg);
|
|
248
|
+
}
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (!finalText.trim())
|
|
252
|
+
return;
|
|
253
|
+
try {
|
|
254
|
+
const finalResponse = appendTriggerAttribution(finalText, options?.triggerAttribution, options?.triggerSessionLink);
|
|
255
|
+
const finalDashboard = mergeSubagentProgress(runState.completedSubagentProgress);
|
|
256
|
+
if (finalDashboard) {
|
|
257
|
+
await replaceWithSubagentDashboard(responder, finalDashboard, finalResponse, {
|
|
258
|
+
createOverflowLink: options?.createOverflowLink,
|
|
259
|
+
});
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
await responder.replaceResponse(formatResponseWithToolProgress(finalResponse, runState), {
|
|
263
|
+
createOverflowLink: options?.createOverflowLink,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
catch (err) {
|
|
267
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
268
|
+
log.logWarning("Failed to replace message with final text", errMsg);
|
|
269
|
+
reportUserFacingError(err, {
|
|
270
|
+
domain: "chat_platform",
|
|
271
|
+
surface: "final_response",
|
|
272
|
+
operation: "replace_final_response",
|
|
273
|
+
severity: "error",
|
|
274
|
+
platform: options?.platform,
|
|
275
|
+
context: {
|
|
276
|
+
sessionConversation: options?.sessionConversation,
|
|
277
|
+
sessionUuid: options?.sessionUuid,
|
|
278
|
+
finalTextLength: finalText.length,
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
export async function reportUsageSummary(ctx) {
|
|
284
|
+
const { session, runState, responder, platform, model, agentConfig, sessionConversation, sessionUuid, waitForQueue, } = ctx;
|
|
285
|
+
const lastAssistantMessage = session.messages
|
|
286
|
+
.slice()
|
|
287
|
+
.toReversed()
|
|
288
|
+
.find((message) => message.role === "assistant" && message.stopReason !== "aborted");
|
|
289
|
+
const contextTokens = lastAssistantMessage
|
|
290
|
+
? lastAssistantMessage.usage.input +
|
|
291
|
+
lastAssistantMessage.usage.output +
|
|
292
|
+
lastAssistantMessage.usage.cacheRead +
|
|
293
|
+
lastAssistantMessage.usage.cacheWrite
|
|
294
|
+
: 0;
|
|
295
|
+
const contextWindow = model.contextWindow || 200000;
|
|
296
|
+
const { totalUsage } = runState;
|
|
297
|
+
const runMetricAttributes = metricAttributes({
|
|
298
|
+
provider: model.provider,
|
|
299
|
+
model: agentConfig.model,
|
|
300
|
+
channel_id: sessionConversation,
|
|
301
|
+
session_id: sessionUuid,
|
|
302
|
+
stop_reason: runState.stopReason,
|
|
303
|
+
llm_calls: runState.llmCallCount,
|
|
304
|
+
});
|
|
305
|
+
Sentry.metrics.distribution("agent.run.tokens_in", totalUsage.input, {
|
|
306
|
+
attributes: runMetricAttributes,
|
|
307
|
+
});
|
|
308
|
+
Sentry.metrics.distribution("agent.run.tokens_out", totalUsage.output, {
|
|
309
|
+
attributes: runMetricAttributes,
|
|
310
|
+
});
|
|
311
|
+
Sentry.metrics.distribution("agent.run.cache_read", totalUsage.cacheRead, {
|
|
312
|
+
attributes: runMetricAttributes,
|
|
313
|
+
});
|
|
314
|
+
Sentry.metrics.distribution("agent.run.cache_write", totalUsage.cacheWrite, {
|
|
315
|
+
attributes: runMetricAttributes,
|
|
316
|
+
});
|
|
317
|
+
Sentry.metrics.distribution("agent.run.cost", totalUsage.cost.total, {
|
|
318
|
+
attributes: runMetricAttributes,
|
|
319
|
+
});
|
|
320
|
+
Sentry.metrics.gauge("agent.context.utilization", contextTokens / contextWindow, {
|
|
321
|
+
unit: "ratio",
|
|
322
|
+
attributes: runMetricAttributes,
|
|
323
|
+
});
|
|
324
|
+
const summary = log.logUsageSummary(runState.logCtx, runState.totalUsage, contextTokens, contextWindow);
|
|
325
|
+
if (platform.diagnostics?.showUsageSummary === true) {
|
|
326
|
+
runState.queue.enqueue(() => responder.respondDiagnostic(summary, { style: "muted" }), "usage summary");
|
|
327
|
+
await waitForQueue();
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function extractToolResultText(result) {
|
|
331
|
+
if (typeof result === "string") {
|
|
332
|
+
return result;
|
|
333
|
+
}
|
|
334
|
+
if (result &&
|
|
335
|
+
typeof result === "object" &&
|
|
336
|
+
"content" in result &&
|
|
337
|
+
Array.isArray(result.content)) {
|
|
338
|
+
const content = result.content;
|
|
339
|
+
const textParts = [];
|
|
340
|
+
for (const part of content) {
|
|
341
|
+
if (part.type === "text" && part.text) {
|
|
342
|
+
textParts.push(part.text);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (textParts.length > 0) {
|
|
346
|
+
return textParts.join("\n");
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return JSON.stringify(result);
|
|
350
|
+
}
|
|
351
|
+
async function noopResponderMethod() { }
|
|
352
|
+
export function createNoopResponder() {
|
|
353
|
+
return {
|
|
354
|
+
respond: noopResponderMethod,
|
|
355
|
+
replaceResponse: noopResponderMethod,
|
|
356
|
+
respondDiagnostic: noopResponderMethod,
|
|
357
|
+
respondToolResult: noopResponderMethod,
|
|
358
|
+
setTyping: noopResponderMethod,
|
|
359
|
+
setWorking: noopResponderMethod,
|
|
360
|
+
uploadFile: noopResponderMethod,
|
|
361
|
+
deleteResponse: noopResponderMethod,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
export function formatAgentActorName(userName, fallback) {
|
|
365
|
+
return userName ? `DM:${userName}` : fallback;
|
|
366
|
+
}
|
|
367
|
+
export function sendAgentEvent(payload) {
|
|
368
|
+
emitAgentEvent({ source: "mikan", ...payload });
|
|
369
|
+
}
|
|
370
|
+
// ponytail: additive SSE mirror only; keep responder rendering here until another frontend needs the same stream.
|
|
371
|
+
export function attachSessionEventHandlers(params) {
|
|
372
|
+
const { session, runState, model, agentConfig } = params;
|
|
373
|
+
session.subscribe(async (event) => {
|
|
374
|
+
if (!runState.responder || !runState.logCtx || !runState.queue)
|
|
375
|
+
return;
|
|
376
|
+
const { responder, logCtx, queue, pendingTools } = runState;
|
|
377
|
+
const baseAttrs = { channel_id: logCtx.conversationId, session_id: logCtx.sessionId };
|
|
378
|
+
const agentEventSessionId = logCtx.sessionId ?? logCtx.conversationId;
|
|
379
|
+
if (event.type === "tool_execution_start") {
|
|
380
|
+
const args = (event.args ?? {});
|
|
381
|
+
const label = args.label || event.toolName;
|
|
382
|
+
sendAgentEvent({
|
|
383
|
+
sessionId: agentEventSessionId,
|
|
384
|
+
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
385
|
+
event: {
|
|
386
|
+
kind: "toolStart",
|
|
387
|
+
toolId: event.toolCallId,
|
|
388
|
+
toolName: event.toolName,
|
|
389
|
+
input: { label },
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
pendingTools.set(event.toolCallId, {
|
|
393
|
+
toolName: event.toolName,
|
|
394
|
+
args: event.args,
|
|
395
|
+
startTime: Date.now(),
|
|
396
|
+
});
|
|
397
|
+
runState.toolProgress.set(event.toolCallId, {
|
|
398
|
+
label: extractToolLabel(event.toolName, event.args),
|
|
399
|
+
status: "running",
|
|
400
|
+
});
|
|
401
|
+
if (event.toolName === "subagent") {
|
|
402
|
+
runState.subagentToolCalls.add(event.toolCallId);
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
queue.enqueue(() => replaceResponseWithToolProgress(responder, runState), "tool progress update");
|
|
406
|
+
}
|
|
407
|
+
addLifecycleBreadcrumb("agent.tool.started", {
|
|
408
|
+
tool: event.toolName,
|
|
409
|
+
...baseAttrs,
|
|
410
|
+
});
|
|
411
|
+
log.logToolStart(logCtx, event.toolName, label, event.args);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
if (event.type === "tool_execution_update") {
|
|
415
|
+
const subagentProgress = extractSubagentProgress(event.partialResult);
|
|
416
|
+
if (subagentProgress) {
|
|
417
|
+
runState.subagentProgress.set(event.toolCallId, subagentProgress);
|
|
418
|
+
runState.subagentToolCalls.add(event.toolCallId);
|
|
419
|
+
runState.suppressResponseDeltas = true;
|
|
420
|
+
scheduleToolProgressUpdate(responder, runState);
|
|
421
|
+
}
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
if (event.type === "tool_execution_end") {
|
|
425
|
+
const resultStr = extractToolResultText(event.result);
|
|
426
|
+
const pending = pendingTools.get(event.toolCallId);
|
|
427
|
+
sendAgentEvent({
|
|
428
|
+
sessionId: agentEventSessionId,
|
|
429
|
+
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
430
|
+
event: { kind: "toolEnd", toolId: event.toolCallId },
|
|
431
|
+
});
|
|
432
|
+
const progress = runState.toolProgress.get(event.toolCallId);
|
|
433
|
+
if (progress)
|
|
434
|
+
progress.status = event.isError ? "error" : "done";
|
|
435
|
+
const subagentProgress = runState.subagentProgress.get(event.toolCallId);
|
|
436
|
+
if (subagentProgress) {
|
|
437
|
+
runState.subagentProgress.set(event.toolCallId, settleSubagentProgress(subagentProgress, event.isError));
|
|
438
|
+
}
|
|
439
|
+
flushToolProgressUpdate(responder, runState);
|
|
440
|
+
const completedProgress = runState.subagentProgress.get(event.toolCallId);
|
|
441
|
+
if (completedProgress)
|
|
442
|
+
runState.completedSubagentProgress.push(completedProgress);
|
|
443
|
+
runState.subagentProgress.delete(event.toolCallId);
|
|
444
|
+
pendingTools.delete(event.toolCallId);
|
|
445
|
+
const durationMs = pending ? Date.now() - pending.startTime : 0;
|
|
446
|
+
Sentry.metrics.count("agent.tool.calls", 1, {
|
|
447
|
+
attributes: metricAttributes({
|
|
448
|
+
tool: event.toolName,
|
|
449
|
+
error: String(event.isError),
|
|
450
|
+
...baseAttrs,
|
|
451
|
+
}),
|
|
452
|
+
});
|
|
453
|
+
Sentry.metrics.distribution("agent.tool.duration", durationMs, {
|
|
454
|
+
unit: "millisecond",
|
|
455
|
+
attributes: metricAttributes({
|
|
456
|
+
tool: event.toolName,
|
|
457
|
+
...baseAttrs,
|
|
458
|
+
}),
|
|
459
|
+
});
|
|
460
|
+
addLifecycleBreadcrumb("agent.tool.completed", {
|
|
461
|
+
tool: event.toolName,
|
|
462
|
+
error: event.isError,
|
|
463
|
+
duration_ms: durationMs,
|
|
464
|
+
...baseAttrs,
|
|
465
|
+
});
|
|
466
|
+
if (event.isError) {
|
|
467
|
+
log.logToolError(logCtx, event.toolName, durationMs, resultStr);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
log.logToolSuccess(logCtx, event.toolName, durationMs, resultStr);
|
|
471
|
+
if (event.toolName === "slack_blockkit") {
|
|
472
|
+
runState.finalResponseHandledByTool = true;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
if (event.type === "message_start") {
|
|
478
|
+
if (event.message.role === "assistant") {
|
|
479
|
+
runState.llmCallCount += 1;
|
|
480
|
+
sendAgentEvent({
|
|
481
|
+
sessionId: agentEventSessionId,
|
|
482
|
+
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
483
|
+
event: { kind: "sessionStart" },
|
|
484
|
+
});
|
|
485
|
+
addLifecycleBreadcrumb("agent.llm.call.started", {
|
|
486
|
+
call_index: runState.llmCallCount,
|
|
487
|
+
provider: model.provider,
|
|
488
|
+
model: agentConfig.model,
|
|
489
|
+
...baseAttrs,
|
|
490
|
+
});
|
|
491
|
+
log.logResponseStart(logCtx);
|
|
492
|
+
}
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
if (event.type === "message_update") {
|
|
496
|
+
const assistantMessageEvent = event.assistantMessageEvent;
|
|
497
|
+
if (assistantMessageEvent?.type === "text_delta" && assistantMessageEvent.delta) {
|
|
498
|
+
sendAgentEvent({
|
|
499
|
+
sessionId: agentEventSessionId,
|
|
500
|
+
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
501
|
+
event: { kind: "responseDelta", delta: assistantMessageEvent.delta },
|
|
502
|
+
});
|
|
503
|
+
if (responder.appendResponseDelta && !runState.suppressResponseDeltas) {
|
|
504
|
+
queue.enqueue(async () => {
|
|
505
|
+
await responder.appendResponseDelta?.(assistantMessageEvent.delta ?? "");
|
|
506
|
+
}, "response delta");
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (event.type === "message_end") {
|
|
512
|
+
if (event.message.role === "assistant") {
|
|
513
|
+
const assistantMsg = event.message;
|
|
514
|
+
if (assistantMsg.stopReason) {
|
|
515
|
+
runState.stopReason = assistantMsg.stopReason;
|
|
516
|
+
// The settling message is the authority for both fields: a retry
|
|
517
|
+
// that recovered must clear the earlier attempt's error, or the
|
|
518
|
+
// run would report success and a stale errorMessage together.
|
|
519
|
+
runState.errorMessage = assistantMsg.errorMessage;
|
|
520
|
+
}
|
|
521
|
+
if (assistantMsg.usage) {
|
|
522
|
+
runState.totalUsage.input += assistantMsg.usage.input;
|
|
523
|
+
runState.totalUsage.output += assistantMsg.usage.output;
|
|
524
|
+
runState.totalUsage.cacheRead += assistantMsg.usage.cacheRead;
|
|
525
|
+
runState.totalUsage.cacheWrite += assistantMsg.usage.cacheWrite;
|
|
526
|
+
runState.totalUsage.cost.input += assistantMsg.usage.cost.input;
|
|
527
|
+
runState.totalUsage.cost.output += assistantMsg.usage.cost.output;
|
|
528
|
+
runState.totalUsage.cost.cacheRead += assistantMsg.usage.cost.cacheRead;
|
|
529
|
+
runState.totalUsage.cost.cacheWrite += assistantMsg.usage.cost.cacheWrite;
|
|
530
|
+
runState.totalUsage.cost.total += assistantMsg.usage.cost.total;
|
|
531
|
+
const llmAttributes = metricAttributes({
|
|
532
|
+
provider: model.provider,
|
|
533
|
+
model: agentConfig.model,
|
|
534
|
+
...baseAttrs,
|
|
535
|
+
stop_reason: assistantMsg.stopReason,
|
|
536
|
+
error: Boolean(assistantMsg.errorMessage),
|
|
537
|
+
});
|
|
538
|
+
Sentry.metrics.count("agent.llm.calls", 1, { attributes: llmAttributes });
|
|
539
|
+
Sentry.metrics.distribution("agent.llm.tokens_in", assistantMsg.usage.input, {
|
|
540
|
+
attributes: llmAttributes,
|
|
541
|
+
});
|
|
542
|
+
Sentry.metrics.distribution("agent.llm.tokens_out", assistantMsg.usage.output, {
|
|
543
|
+
attributes: llmAttributes,
|
|
544
|
+
});
|
|
545
|
+
if (assistantMsg.usage.cacheRead > 0) {
|
|
546
|
+
Sentry.metrics.distribution("agent.llm.cache_read", assistantMsg.usage.cacheRead, {
|
|
547
|
+
attributes: llmAttributes,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
if (assistantMsg.usage.cacheWrite > 0) {
|
|
551
|
+
Sentry.metrics.distribution("agent.llm.cache_write", assistantMsg.usage.cacheWrite, {
|
|
552
|
+
attributes: llmAttributes,
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
Sentry.metrics.distribution("agent.llm.cost_per_turn", assistantMsg.usage.cost.total, {
|
|
556
|
+
attributes: llmAttributes,
|
|
557
|
+
});
|
|
558
|
+
addLifecycleBreadcrumb("agent.llm.call.completed", {
|
|
559
|
+
call_index: runState.llmCallCount,
|
|
560
|
+
provider: model.provider,
|
|
561
|
+
model: agentConfig.model,
|
|
562
|
+
stop_reason: assistantMsg.stopReason,
|
|
563
|
+
error: Boolean(assistantMsg.errorMessage),
|
|
564
|
+
input_tokens: assistantMsg.usage.input,
|
|
565
|
+
output_tokens: assistantMsg.usage.output,
|
|
566
|
+
cost_total_usd: assistantMsg.usage.cost.total,
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
const thinkingParts = [];
|
|
570
|
+
const textParts = [];
|
|
571
|
+
const hasToolCall = assistantMsg.content.some((part) => ["tool_use", "toolCall", "tool-call"].includes(part.type ?? ""));
|
|
572
|
+
for (const part of assistantMsg.content) {
|
|
573
|
+
if (part.type === "thinking") {
|
|
574
|
+
thinkingParts.push(part.thinking);
|
|
575
|
+
}
|
|
576
|
+
else if (part.type === "text") {
|
|
577
|
+
textParts.push(part.text);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
const text = textParts.join("\n");
|
|
581
|
+
for (const thinking of thinkingParts) {
|
|
582
|
+
log.logThinking(logCtx, thinking);
|
|
583
|
+
queue.enqueue(() => responder.respond(`_${thinking}_`), "thinking main");
|
|
584
|
+
queue.enqueue(() => responder.respondDiagnostic(`_${thinking}_`), "thinking diagnostic");
|
|
585
|
+
}
|
|
586
|
+
if (text.trim() && !hasToolCall) {
|
|
587
|
+
if (runState.finalResponseHandledByTool)
|
|
588
|
+
return;
|
|
589
|
+
const finalText = appendTriggerAttribution(formatResponseWithToolProgress(text, runState), runState.triggerAttribution);
|
|
590
|
+
log.logResponse(logCtx, text);
|
|
591
|
+
sendAgentEvent({
|
|
592
|
+
sessionId: agentEventSessionId,
|
|
593
|
+
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
594
|
+
event: { kind: "responseFinal", text: finalText },
|
|
595
|
+
});
|
|
596
|
+
sendAgentEvent({
|
|
597
|
+
sessionId: agentEventSessionId,
|
|
598
|
+
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
599
|
+
event: { kind: "turnEnd" },
|
|
600
|
+
});
|
|
601
|
+
// A run that produced a subagent dashboard finalizes through it:
|
|
602
|
+
// finalizeRunResponse renders "dashboard, blank line, answer", and a
|
|
603
|
+
// finish here would first overwrite the dashboard with the bare
|
|
604
|
+
// answer on every platform.
|
|
605
|
+
if (runState.completedSubagentProgress.length > 0)
|
|
606
|
+
return;
|
|
607
|
+
if (responder.finishResponse) {
|
|
608
|
+
queue.enqueue(async () => {
|
|
609
|
+
await responder.finishResponse?.(finalText);
|
|
610
|
+
}, "response finish");
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
queue.enqueue(() => responder.respond(finalText), "response main");
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
if (event.type === "compaction_start") {
|
|
620
|
+
const text = "_Compacting context..._";
|
|
621
|
+
log.logInfo(`Auto-compaction started (reason: ${event.reason})`);
|
|
622
|
+
sendAgentEvent({
|
|
623
|
+
sessionId: agentEventSessionId,
|
|
624
|
+
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
625
|
+
event: { kind: "diagnostic", text },
|
|
626
|
+
});
|
|
627
|
+
queue.enqueue(() => responder.respond(text), "compaction start");
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
if (event.type === "compaction_end") {
|
|
631
|
+
if (event.result) {
|
|
632
|
+
log.logInfo(`Auto-compaction complete: ${event.result.tokensBefore} tokens compacted`);
|
|
633
|
+
}
|
|
634
|
+
else if (event.aborted) {
|
|
635
|
+
log.logInfo("Auto-compaction aborted");
|
|
636
|
+
}
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
if (event.type === "auto_retry_start") {
|
|
640
|
+
log.logWarning(`Retrying (${event.attempt}/${event.maxAttempts})`, event.errorMessage);
|
|
641
|
+
sendAgentEvent({
|
|
642
|
+
sessionId: agentEventSessionId,
|
|
643
|
+
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
644
|
+
event: { kind: "sessionStart" },
|
|
645
|
+
});
|
|
646
|
+
const text = `_Retrying (${event.attempt}/${event.maxAttempts})..._`;
|
|
647
|
+
sendAgentEvent({
|
|
648
|
+
sessionId: agentEventSessionId,
|
|
649
|
+
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
650
|
+
event: { kind: "diagnostic", text },
|
|
651
|
+
});
|
|
652
|
+
queue.enqueue(() => responder.respond(text), "retry");
|
|
653
|
+
}
|
|
654
|
+
if (event.type === "budget_exceeded") {
|
|
655
|
+
log.logWarning("Run stopped by budget circuit breaker", `${event.reason} (tokens=${event.tokens}, cost=${event.costUsd.toFixed(2)}, calls=${event.llmCalls}, ${event.durationMs}ms)`);
|
|
656
|
+
const text = `_Stopped: run budget exceeded (${event.reason})_`;
|
|
657
|
+
sendAgentEvent({
|
|
658
|
+
sessionId: agentEventSessionId,
|
|
659
|
+
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
660
|
+
event: { kind: "diagnostic", text },
|
|
661
|
+
});
|
|
662
|
+
queue.enqueue(() => responder.respondDiagnostic(text, { style: "error" }), "budget exceeded");
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Create a new PiAgentWrapper for a channel.
|
|
668
|
+
* Sets up the session and subscribes to events once.
|
|
669
|
+
*
|
|
670
|
+
* Runner caching is handled by the caller (channelStates in main.ts).
|
|
671
|
+
* This is a stateless factory function.
|
|
672
|
+
*/
|
|
673
|
+
//# sourceMappingURL=presenter.js.map
|