@geminixiang/mikan 1.0.0-beta.55 → 1.0.0-beta.57
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 +20 -0
- package/dist/harness/presenter.d.ts.map +1 -1
- package/dist/harness/presenter.js +127 -21
- package/dist/harness/presenter.js.map +1 -1
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +6 -1
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/types.d.ts +12 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +2 -1
- package/dist/observability/index.js.map +1 -1
- package/dist/observability/sentry.d.ts.map +1 -1
- package/dist/observability/sentry.js +11 -14
- package/dist/observability/sentry.js.map +1 -1
- package/dist/observability/types.d.ts +1 -0
- package/dist/observability/types.d.ts.map +1 -1
- package/dist/observability/types.js.map +1 -1
- package/dist/runtime/conversation-runtime.js +5 -2
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,26 @@ any release.
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [1.0.0-beta.57]
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Export raw platform conversation, channel, session, thread, message, and user identifiers so Sentry traces can be mapped directly back to their source while continuing to exclude human-readable names and conversation or tool content.
|
|
17
|
+
|
|
18
|
+
### Removed
|
|
19
|
+
|
|
20
|
+
- Remove telemetry identifier hashing and the `TELEMETRY_HASH_KEY` deployment setting.
|
|
21
|
+
|
|
22
|
+
## [1.0.0-beta.56]
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- Add content-free agent diagnostics for actual model IDs, token and cost totals, first-token latency, context utilization, message and attachment counts, payload sizes, tool categories and status, and retry, compaction, and budget summaries.
|
|
27
|
+
|
|
28
|
+
### Security
|
|
29
|
+
|
|
30
|
+
- Replace raw conversation, session, message, thread, and user telemetry identifiers with stable opaque values, support deployment-specific HMACs through `TELEMETRY_HASH_KEY`, and stop sending usernames to Sentry.
|
|
31
|
+
|
|
12
32
|
## [1.0.0-beta.55]
|
|
13
33
|
|
|
14
34
|
### Added
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presenter.d.ts","sourceRoot":"","sources":["../../src/harness/presenter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,GAAG,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAEV,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAOtD,OAAO,KAAK,EAAE,qBAAqB,EAA4B,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"presenter.d.ts","sourceRoot":"","sources":["../../src/harness/presenter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,GAAG,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAEV,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAOtD,OAAO,KAAK,EAAE,qBAAqB,EAA4B,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AA+DhE,wBAAgB,cAAc,IAAI,kBAAkB,CAkCnD;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE;IACP,SAAS,EAAE,qBAAqB,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC,GACA,eAAe,CAsEjB;AAOD,wBAAgB,yBAAyB,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEzF;AAmKD,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,qBAAqB,EAChC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE;IACR,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACA,OAAO,CAAC,IAAI,CAAC,CAiBf;AA4DD,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2F/E;AAubD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,WAAW,EAAE,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAC;CAC7D,GAAG,IAAI,CAiBP"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { contentText } from "@earendil-works/pi-ai";
|
|
2
2
|
import { mergeSubagentProgress, parseSubagentProgressSnapshot, renderSubagentDashboard, settleSubagentProgress, } from "./tools/subagent.js";
|
|
3
|
-
import { addLifecycleEvent, metricAttributes, recordCounter, recordDistribution, recordGauge, reportUserFacingError, startOperationSpan, } from "../observability/index.js";
|
|
3
|
+
import { addLifecycleEvent, metricAttributes, recordCounter, recordDistribution, recordGauge, reportUserFacingError, startOperationSpan, updateActiveSpanAttribution, } from "../observability/index.js";
|
|
4
4
|
import { appendTriggerAttribution } from "./prompt.js";
|
|
5
5
|
import * as log from "../log.js";
|
|
6
6
|
const operationSpans = new WeakMap();
|
|
@@ -22,8 +22,8 @@ function endOutstandingOperationSpans(runState) {
|
|
|
22
22
|
if (!spans)
|
|
23
23
|
return;
|
|
24
24
|
const aborted = operationError("AbortError");
|
|
25
|
-
for (const
|
|
26
|
-
span.end({ error: aborted });
|
|
25
|
+
for (const entry of spans.llm)
|
|
26
|
+
entry.span.end({ error: aborted });
|
|
27
27
|
for (const span of spans.tools.values())
|
|
28
28
|
span.end({ error: aborted });
|
|
29
29
|
operationSpans.delete(runState);
|
|
@@ -53,6 +53,18 @@ export function createRunState() {
|
|
|
53
53
|
toolProgressTimer: undefined,
|
|
54
54
|
totalUsage: createEmptyUsageTotals(),
|
|
55
55
|
llmCallCount: 0,
|
|
56
|
+
toolCallCount: 0,
|
|
57
|
+
toolErrorCount: 0,
|
|
58
|
+
toolInputCharacters: 0,
|
|
59
|
+
toolOutputCharacters: 0,
|
|
60
|
+
assistantMessageCount: 0,
|
|
61
|
+
outputCharacters: 0,
|
|
62
|
+
reasoningTokens: 0,
|
|
63
|
+
retryCount: 0,
|
|
64
|
+
compactionCount: 0,
|
|
65
|
+
budgetExceeded: false,
|
|
66
|
+
firstTokenLatencyMs: undefined,
|
|
67
|
+
responseModel: undefined,
|
|
56
68
|
stopReason: "stop",
|
|
57
69
|
errorMessage: undefined,
|
|
58
70
|
reportedLlmError: false,
|
|
@@ -82,6 +94,18 @@ export function activateRunPresentation(runState, context) {
|
|
|
82
94
|
runState.toolProgressTimer = undefined;
|
|
83
95
|
runState.totalUsage = createEmptyUsageTotals();
|
|
84
96
|
runState.llmCallCount = 0;
|
|
97
|
+
runState.toolCallCount = 0;
|
|
98
|
+
runState.toolErrorCount = 0;
|
|
99
|
+
runState.toolInputCharacters = 0;
|
|
100
|
+
runState.toolOutputCharacters = 0;
|
|
101
|
+
runState.assistantMessageCount = 0;
|
|
102
|
+
runState.outputCharacters = 0;
|
|
103
|
+
runState.reasoningTokens = 0;
|
|
104
|
+
runState.retryCount = 0;
|
|
105
|
+
runState.compactionCount = 0;
|
|
106
|
+
runState.budgetExceeded = false;
|
|
107
|
+
runState.firstTokenLatencyMs = undefined;
|
|
108
|
+
runState.responseModel = undefined;
|
|
85
109
|
runState.stopReason = "stop";
|
|
86
110
|
runState.errorMessage = undefined;
|
|
87
111
|
runState.reportedLlmError = false;
|
|
@@ -320,7 +344,7 @@ async function publishFinalResponse(responder, runState, finalText, options) {
|
|
|
320
344
|
}
|
|
321
345
|
}
|
|
322
346
|
export async function reportUsageSummary(ctx) {
|
|
323
|
-
const { session, runState, responder, platform, model,
|
|
347
|
+
const { session, runState, responder, platform, model, sessionConversation, sessionUuid, waitForQueue, } = ctx;
|
|
324
348
|
const lastAssistantMessage = session.messages.findLast((message) => message.role === "assistant" && message.stopReason !== "aborted");
|
|
325
349
|
const contextTokens = lastAssistantMessage
|
|
326
350
|
? lastAssistantMessage.usage.input +
|
|
@@ -332,7 +356,7 @@ export async function reportUsageSummary(ctx) {
|
|
|
332
356
|
const { totalUsage } = runState;
|
|
333
357
|
const runMetricAttributes = metricAttributes({
|
|
334
358
|
provider: model.provider,
|
|
335
|
-
model:
|
|
359
|
+
model: model.id,
|
|
336
360
|
channel_id: sessionConversation,
|
|
337
361
|
session_id: sessionUuid,
|
|
338
362
|
stop_reason: runState.stopReason,
|
|
@@ -353,10 +377,35 @@ export async function reportUsageSummary(ctx) {
|
|
|
353
377
|
recordDistribution("agent.run.cost", totalUsage.cost.total, {
|
|
354
378
|
attributes: runMetricAttributes,
|
|
355
379
|
});
|
|
356
|
-
|
|
380
|
+
const contextUtilization = contextTokens / contextWindow;
|
|
381
|
+
recordGauge("agent.context.utilization", contextUtilization, {
|
|
357
382
|
unit: "ratio",
|
|
358
383
|
attributes: runMetricAttributes,
|
|
359
384
|
});
|
|
385
|
+
updateActiveSpanAttribution({
|
|
386
|
+
"gen_ai.request.model": model.id,
|
|
387
|
+
"gen_ai.response.model": runState.responseModel ?? model.id,
|
|
388
|
+
"gen_ai.usage.input_tokens": totalUsage.input + totalUsage.cacheRead + totalUsage.cacheWrite,
|
|
389
|
+
"gen_ai.usage.input_tokens.cached": totalUsage.cacheRead,
|
|
390
|
+
"gen_ai.usage.input_tokens.cache_write": totalUsage.cacheWrite,
|
|
391
|
+
"gen_ai.usage.output_tokens": totalUsage.output,
|
|
392
|
+
"gen_ai.usage.output_tokens.reasoning": runState.reasoningTokens,
|
|
393
|
+
"mikan.usage.cost_usd": totalUsage.cost.total,
|
|
394
|
+
"mikan.context.utilization": contextUtilization,
|
|
395
|
+
"mikan.llm.call_count": runState.llmCallCount,
|
|
396
|
+
"mikan.tool.call_count": runState.toolCallCount,
|
|
397
|
+
"mikan.tool.error_count": runState.toolErrorCount,
|
|
398
|
+
"mikan.tool.input.characters": runState.toolInputCharacters,
|
|
399
|
+
"mikan.tool.output.characters": runState.toolOutputCharacters,
|
|
400
|
+
"mikan.output.message_count": runState.assistantMessageCount,
|
|
401
|
+
"mikan.output.characters": runState.outputCharacters,
|
|
402
|
+
"mikan.retry.count": runState.retryCount,
|
|
403
|
+
"mikan.compaction.count": runState.compactionCount,
|
|
404
|
+
"mikan.budget.exceeded": runState.budgetExceeded,
|
|
405
|
+
...(runState.firstTokenLatencyMs === undefined
|
|
406
|
+
? {}
|
|
407
|
+
: { "mikan.response.first_token_ms": runState.firstTokenLatencyMs }),
|
|
408
|
+
});
|
|
360
409
|
const summary = log.logUsageSummary(runState.logCtx, runState.totalUsage, contextTokens, contextWindow);
|
|
361
410
|
if (platform.diagnostics?.showUsageSummary === true) {
|
|
362
411
|
runState.queue.enqueue(() => responder.respondDiagnostic(summary, { style: "muted" }), "usage summary");
|
|
@@ -380,10 +429,35 @@ function extractToolResultText(result) {
|
|
|
380
429
|
return result;
|
|
381
430
|
return toolResultContentText(result) ?? JSON.stringify(result);
|
|
382
431
|
}
|
|
432
|
+
function serializedLength(value) {
|
|
433
|
+
if (typeof value === "string")
|
|
434
|
+
return value.length;
|
|
435
|
+
try {
|
|
436
|
+
return JSON.stringify(value)?.length ?? 0;
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
return 0;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
function toolCategory(name) {
|
|
443
|
+
if (["read", "write", "edit", "bash"].includes(name))
|
|
444
|
+
return "sandbox";
|
|
445
|
+
if (name === "subagent")
|
|
446
|
+
return "agent";
|
|
447
|
+
if (name.startsWith("mcp__"))
|
|
448
|
+
return "mcp";
|
|
449
|
+
if (name.startsWith("github_"))
|
|
450
|
+
return "github";
|
|
451
|
+
if (name === "slack_blockkit")
|
|
452
|
+
return "platform";
|
|
453
|
+
return "function";
|
|
454
|
+
}
|
|
383
455
|
function handleToolStart(event, context) {
|
|
384
456
|
const { runState, responder, logCtx, queue, baseAttrs } = context;
|
|
385
457
|
const args = (event.args ?? {});
|
|
386
458
|
const label = args.label || event.toolName;
|
|
459
|
+
runState.toolCallCount += 1;
|
|
460
|
+
runState.toolInputCharacters += serializedLength(event.args);
|
|
387
461
|
runState.pendingTools.set(event.toolCallId, {
|
|
388
462
|
toolName: event.toolName,
|
|
389
463
|
args: event.args,
|
|
@@ -402,6 +476,9 @@ function handleToolStart(event, context) {
|
|
|
402
476
|
spansFor(runState).tools.set(event.toolCallId, startOperationSpan(`execute_tool ${event.toolName}`, metricAttributes({
|
|
403
477
|
"gen_ai.operation.name": "execute_tool",
|
|
404
478
|
"gen_ai.tool.name": event.toolName,
|
|
479
|
+
"gen_ai.tool.type": "function",
|
|
480
|
+
"mikan.tool.category": toolCategory(event.toolName),
|
|
481
|
+
"mikan.tool.input.characters": serializedLength(event.args),
|
|
405
482
|
"openinference.span.kind": "TOOL",
|
|
406
483
|
...baseAttrs,
|
|
407
484
|
})));
|
|
@@ -437,6 +514,10 @@ function recordToolMetrics(event, durationMs, context) {
|
|
|
437
514
|
function handleToolEnd(event, context) {
|
|
438
515
|
const { runState, responder, logCtx } = context;
|
|
439
516
|
const resultStr = extractToolResultText(event.result);
|
|
517
|
+
const outputCharacters = serializedLength(event.result);
|
|
518
|
+
runState.toolOutputCharacters += outputCharacters;
|
|
519
|
+
if (event.isError)
|
|
520
|
+
runState.toolErrorCount += 1;
|
|
440
521
|
const pending = runState.pendingTools.get(event.toolCallId);
|
|
441
522
|
const progress = runState.toolProgress.get(event.toolCallId);
|
|
442
523
|
if (progress)
|
|
@@ -456,6 +537,9 @@ function handleToolEnd(event, context) {
|
|
|
456
537
|
toolSpan?.end({
|
|
457
538
|
attributes: metricAttributes({
|
|
458
539
|
"gen_ai.tool.name": event.toolName,
|
|
540
|
+
"gen_ai.tool.type": "function",
|
|
541
|
+
"mikan.tool.category": toolCategory(event.toolName),
|
|
542
|
+
"mikan.tool.output.characters": outputCharacters,
|
|
459
543
|
"openinference.span.kind": "TOOL",
|
|
460
544
|
duration_ms: durationMs,
|
|
461
545
|
...context.baseAttrs,
|
|
@@ -476,15 +560,18 @@ function handleMessageStart(event, context) {
|
|
|
476
560
|
if (event.message.role !== "assistant")
|
|
477
561
|
return;
|
|
478
562
|
context.runState.llmCallCount += 1;
|
|
479
|
-
spansFor(context.runState).llm.push(
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
563
|
+
spansFor(context.runState).llm.push({
|
|
564
|
+
span: startOperationSpan(`chat ${context.model.id}`, metricAttributes({
|
|
565
|
+
"gen_ai.operation.name": "chat",
|
|
566
|
+
"gen_ai.provider.name": context.model.provider,
|
|
567
|
+
"gen_ai.request.model": context.model.id,
|
|
568
|
+
"openinference.span.kind": "LLM",
|
|
569
|
+
"llm.provider": context.model.provider,
|
|
570
|
+
"llm.model_name": context.model.id,
|
|
571
|
+
...context.baseAttrs,
|
|
572
|
+
})),
|
|
573
|
+
startedAt: Date.now(),
|
|
574
|
+
});
|
|
488
575
|
addLifecycleEvent("agent.llm.call.started", {
|
|
489
576
|
call_index: context.runState.llmCallCount,
|
|
490
577
|
provider: context.model.provider,
|
|
@@ -497,6 +584,11 @@ function handleMessageUpdate(event, context) {
|
|
|
497
584
|
const update = event.assistantMessageEvent;
|
|
498
585
|
if (update.type !== "text_delta" || !update.delta)
|
|
499
586
|
return;
|
|
587
|
+
const llmEntry = spansFor(context.runState).llm[0];
|
|
588
|
+
if (llmEntry && llmEntry.firstTokenAt === undefined) {
|
|
589
|
+
llmEntry.firstTokenAt = Date.now();
|
|
590
|
+
context.runState.firstTokenLatencyMs ??= llmEntry.firstTokenAt - llmEntry.startedAt;
|
|
591
|
+
}
|
|
500
592
|
if (context.responder.appendResponseDelta && !context.runState.suppressResponseDeltas) {
|
|
501
593
|
context.queue.enqueue(async () => {
|
|
502
594
|
await context.responder.appendResponseDelta?.(update.delta);
|
|
@@ -516,6 +608,8 @@ function recordAssistantUsage(message, context) {
|
|
|
516
608
|
totalUsage.cost.cacheRead += message.usage.cost.cacheRead;
|
|
517
609
|
totalUsage.cost.cacheWrite += message.usage.cost.cacheWrite;
|
|
518
610
|
totalUsage.cost.total += message.usage.cost.total;
|
|
611
|
+
context.runState.reasoningTokens += message.usage.reasoning ?? 0;
|
|
612
|
+
context.runState.responseModel = message.responseModel ?? message.model;
|
|
519
613
|
const attributes = metricAttributes({
|
|
520
614
|
provider: context.model.provider,
|
|
521
615
|
model: context.agentConfig.model,
|
|
@@ -587,27 +681,36 @@ function handleMessageEnd(event, context) {
|
|
|
587
681
|
if (event.message.role !== "assistant")
|
|
588
682
|
return;
|
|
589
683
|
const message = event.message;
|
|
684
|
+
context.runState.assistantMessageCount += 1;
|
|
685
|
+
context.runState.outputCharacters += message.content.reduce((total, part) => total + (part.type === "text" ? part.text.length : 0), 0);
|
|
590
686
|
if (message.stopReason) {
|
|
591
687
|
context.runState.stopReason = message.stopReason;
|
|
592
688
|
// The settling message clears any stale error left by a recovered retry.
|
|
593
689
|
context.runState.errorMessage = message.errorMessage;
|
|
594
690
|
}
|
|
595
691
|
recordAssistantUsage(message, context);
|
|
596
|
-
const
|
|
692
|
+
const llmEntry = spansFor(context.runState).llm.shift();
|
|
597
693
|
const inputTokens = message.usage
|
|
598
694
|
? message.usage.input + message.usage.cacheRead + message.usage.cacheWrite
|
|
599
695
|
: undefined;
|
|
600
|
-
|
|
696
|
+
llmEntry?.span.end({
|
|
601
697
|
attributes: metricAttributes({
|
|
602
698
|
"gen_ai.provider.name": context.model.provider,
|
|
603
|
-
"gen_ai.request.model": context.
|
|
699
|
+
"gen_ai.request.model": context.model.id,
|
|
700
|
+
"gen_ai.response.model": message.responseModel ?? message.model,
|
|
604
701
|
"gen_ai.usage.input_tokens": inputTokens,
|
|
605
702
|
"gen_ai.usage.output_tokens": message.usage?.output,
|
|
606
|
-
"gen_ai.usage.
|
|
607
|
-
"gen_ai.usage.cache_write
|
|
703
|
+
"gen_ai.usage.input_tokens.cached": message.usage?.cacheRead,
|
|
704
|
+
"gen_ai.usage.input_tokens.cache_write": message.usage?.cacheWrite,
|
|
705
|
+
"gen_ai.usage.output_tokens.reasoning": message.usage?.reasoning,
|
|
706
|
+
"mikan.usage.cost_usd": message.usage?.cost.total,
|
|
707
|
+
"mikan.response.first_token_ms": llmEntry?.firstTokenAt === undefined
|
|
708
|
+
? undefined
|
|
709
|
+
: llmEntry.firstTokenAt - llmEntry.startedAt,
|
|
710
|
+
"mikan.output.characters": message.content.reduce((total, part) => total + (part.type === "text" ? part.text.length : 0), 0),
|
|
608
711
|
"openinference.span.kind": "LLM",
|
|
609
712
|
"llm.provider": context.model.provider,
|
|
610
|
-
"llm.model_name": context.
|
|
713
|
+
"llm.model_name": context.model.id,
|
|
611
714
|
"llm.token_count.prompt": inputTokens,
|
|
612
715
|
"llm.token_count.completion": message.usage?.output,
|
|
613
716
|
"llm.token_count.total": inputTokens !== undefined && message.usage ? inputTokens + message.usage.output : undefined,
|
|
@@ -622,6 +725,7 @@ function handleMessageEnd(event, context) {
|
|
|
622
725
|
}
|
|
623
726
|
function handleLifecycleEvent(event, context) {
|
|
624
727
|
if (event.type === "compaction_start") {
|
|
728
|
+
context.runState.compactionCount += 1;
|
|
625
729
|
const text = "_Compacting context..._";
|
|
626
730
|
log.logInfo(`Auto-compaction started (reason: ${event.reason})`);
|
|
627
731
|
context.queue.enqueue(() => context.responder.respond(text), "compaction start");
|
|
@@ -637,11 +741,13 @@ function handleLifecycleEvent(event, context) {
|
|
|
637
741
|
return;
|
|
638
742
|
}
|
|
639
743
|
if (event.type === "auto_retry_start") {
|
|
744
|
+
context.runState.retryCount += 1;
|
|
640
745
|
log.logWarning(`Retrying (${event.attempt}/${event.maxAttempts})`, event.errorMessage);
|
|
641
746
|
const text = `_Retrying (${event.attempt}/${event.maxAttempts})..._`;
|
|
642
747
|
context.queue.enqueue(() => context.responder.respond(text), "retry");
|
|
643
748
|
return;
|
|
644
749
|
}
|
|
750
|
+
context.runState.budgetExceeded = true;
|
|
645
751
|
log.logWarning("Run stopped by budget circuit breaker", `${event.reason} (tokens=${event.tokens}, cost=${event.costUsd.toFixed(2)}, calls=${event.llmCalls}, ${event.durationMs}ms)`);
|
|
646
752
|
const text = `_Stopped: run budget exceeded (${event.reason})_`;
|
|
647
753
|
context.queue.enqueue(() => context.responder.respondDiagnostic(text, { style: "error" }), "budget exceeded");
|