blun-king-cli 9.1.563 → 9.1.565

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.
Files changed (85) hide show
  1. package/agent-spine-plugin/.claude-plugin/marketplace.json +20 -20
  2. package/agent-spine-plugin/.claude-plugin/plugin.json +14 -14
  3. package/agent-spine-plugin/.codex-plugin/plugin.json +34 -34
  4. package/agent-spine-plugin/.mcp.json +8 -8
  5. package/agent-spine-plugin/CONTRIBUTING.md +52 -0
  6. package/agent-spine-plugin/LICENSE +186 -186
  7. package/agent-spine-plugin/README.md +394 -0
  8. package/agent-spine-plugin/SECURITY.md +47 -0
  9. package/agent-spine-plugin/assets/agentspine-banner.svg +32 -32
  10. package/agent-spine-plugin/bin/agentspine-mcp.js +4 -4
  11. package/agent-spine-plugin/bin/agentspine.js +7 -7
  12. package/agent-spine-plugin/blun.plugin.json +33 -33
  13. package/agent-spine-plugin/hooks/codex.json +47 -47
  14. package/agent-spine-plugin/hooks/hooks.json +106 -106
  15. package/agent-spine-plugin/hooks/version.json +5 -5
  16. package/agent-spine-plugin/package.json +69 -69
  17. package/agent-spine-plugin/scripts/check-hosts.js +199 -199
  18. package/agent-spine-plugin/skill/SKILL.md +76 -76
  19. package/agent-spine-plugin/skills/agent-spine/SKILL.md +85 -85
  20. package/agent-spine-plugin/src/cli.js +1488 -1442
  21. package/agent-spine-plugin/src/hook.js +886 -812
  22. package/agent-spine-plugin/src/index.js +93 -93
  23. package/agent-spine-plugin/src/lib/acceptance.js +333 -333
  24. package/agent-spine-plugin/src/lib/attention.js +755 -755
  25. package/agent-spine-plugin/src/lib/audit.js +351 -342
  26. package/agent-spine-plugin/src/lib/authentication.js +515 -515
  27. package/agent-spine-plugin/src/lib/briefing.js +317 -317
  28. package/agent-spine-plugin/src/lib/catalog.js +167 -167
  29. package/agent-spine-plugin/src/lib/channel-runtime.js +665 -665
  30. package/agent-spine-plugin/src/lib/context.js +154 -154
  31. package/agent-spine-plugin/src/lib/continuity.js +338 -338
  32. package/agent-spine-plugin/src/lib/coordination.js +577 -577
  33. package/agent-spine-plugin/src/lib/documents.js +217 -217
  34. package/agent-spine-plugin/src/lib/feed-transport.js +499 -499
  35. package/agent-spine-plugin/src/lib/filesystem-retry.js +32 -32
  36. package/agent-spine-plugin/src/lib/gateway-runtime.js +1119 -760
  37. package/agent-spine-plugin/src/lib/graph.js +337 -337
  38. package/agent-spine-plugin/src/lib/hook-audit.js +29 -0
  39. package/agent-spine-plugin/src/lib/https-transport.js +392 -392
  40. package/agent-spine-plugin/src/lib/indexed-memory-offline.js +40 -40
  41. package/agent-spine-plugin/src/lib/indexed-memory.js +281 -281
  42. package/agent-spine-plugin/src/lib/learning.js +6923 -6466
  43. package/agent-spine-plugin/src/lib/object-transport.js +206 -206
  44. package/agent-spine-plugin/src/lib/owned-file-lock.js +143 -143
  45. package/agent-spine-plugin/src/lib/paths.js +109 -109
  46. package/agent-spine-plugin/src/lib/peer-transport.js +283 -283
  47. package/agent-spine-plugin/src/lib/persona-runtime.js +581 -581
  48. package/agent-spine-plugin/src/lib/preflight.js +702 -702
  49. package/agent-spine-plugin/src/lib/runtime.js +13 -13
  50. package/agent-spine-plugin/src/lib/selfstarter.js +892 -819
  51. package/agent-spine-plugin/src/lib/sharing.js +969 -969
  52. package/agent-spine-plugin/src/lib/source-roots.js +529 -482
  53. package/agent-spine-plugin/src/lib/sqlite-transport.js +501 -501
  54. package/agent-spine-plugin/src/lib/telegram-adapter.js +119 -119
  55. package/agent-spine-plugin/src/lib/voice-runtime.js +39 -39
  56. package/agent-spine-plugin/src/mcp.js +597 -572
  57. package/agent-spine-plugin/src/version.js +1 -1
  58. package/agent-spine-plugin/src/worker.js +202 -195
  59. package/bin/active-steer-priority-policy.cjs +24 -0
  60. package/bin/launcher-runtime.js +8 -1
  61. package/bin/mnemo-tool-agent-policy.cjs +22 -0
  62. package/bin/thinking-activity-status-policy.cjs +132 -0
  63. package/bin/thinking-only-guard.cjs +75 -0
  64. package/bin/tool-call-loop-policy.cjs +53 -0
  65. package/bin/turn-thinking-policy.cjs +25 -1
  66. package/blun.mjs +554 -64
  67. package/package.json +4 -1
  68. package/standard-skills/translate-native/LICENSE +21 -21
  69. package/standard-skills/translate-native/references/evaluation-protocol.md +95 -95
  70. package/standard-skills/translate-native/references/native-orthography.md +79 -79
  71. package/standard-skills/translate-native/references/native-translation-standard.md +94 -94
  72. package/standard-skills/translate-native/references/structured-content.md +72 -72
  73. package/standard-skills/translate-native/references/translationese-review.md +77 -77
  74. package/standard-skills/translate-native/scripts/blun_language_guard.py +697 -697
  75. package/standard-skills/translate-native/scripts/check_diacritics.py +353 -353
  76. package/standard-skills/translate-native/scripts/guard_service_client.py +264 -264
  77. package/standard-skills/translate-native/scripts/language_gateway.py +62 -62
  78. package/standard-skills/translate-native/scripts/language_quality.py +377 -377
  79. package/standard-skills/translate-native/scripts/pre_output_guard.py +64 -64
  80. package/standard-skills/translate-native/scripts/translation_guard.py +916 -916
  81. package/standard-tools/language-guard/blun_language_guard.py +697 -697
  82. package/standard-tools/language-guard/check_diacritics.py +353 -353
  83. package/standard-tools/language-guard/guard_service_client.py +264 -264
  84. package/standard-tools/language-guard/language_quality.py +377 -377
  85. package/standard-tools/language-guard/translation_guard.py +916 -916
package/blun.mjs CHANGED
@@ -2705,9 +2705,14 @@ var init_blun = __esmMin((() => {
2705
2705
  if (!choice) continue;
2706
2706
  if (choice.finish_reason !== null && choice.finish_reason !== void 0) this._captureFinishReason(choice.finish_reason);
2707
2707
  const delta = choice.delta ?? {};
2708
+ const hiddenThinkingTokens = typeof delta.blun_denk_tokens === "number" && Number.isFinite(delta.blun_denk_tokens) && delta.blun_denk_tokens >= 0 ? Math.floor(delta.blun_denk_tokens) : void 0;
2709
+ if (hiddenThinkingTokens !== void 0) yield {
2710
+ type: "think_tokens",
2711
+ thinkTokens: hiddenThinkingTokens
2712
+ };
2708
2713
  const reasoning = observeBlunReasoning(delta);
2709
2714
  this._reasoningFieldState = mergeReasoningFieldState(this._reasoningFieldState, reasoning.state);
2710
- if (reasoning.value !== void 0) yield {
2715
+ if (reasoning.value !== void 0 && (hiddenThinkingTokens === void 0 || reasoning.value.trim().length > 0)) yield {
2711
2716
  type: "think",
2712
2717
  think: reasoning.value
2713
2718
  };
@@ -74783,6 +74788,11 @@ function buildKosongCallbacks(params, markStreamOutput) {
74783
74788
  params.onThinkDelta(part.think);
74784
74789
  return;
74785
74790
  }
74791
+ if (part.type === "think_tokens") {
74792
+ if (params.onThinkTokens === void 0) return;
74793
+ params.onThinkTokens(part.thinkTokens);
74794
+ return;
74795
+ }
74786
74796
  if (part.type === "function") {
74787
74797
  const identity = {
74788
74798
  toolCallId: part.id,
@@ -245084,7 +245094,7 @@ var init_tool_call = __esmMin((() => {
245084
245094
  * does not lose model usage that was already spent.
245085
245095
  */
245086
245096
  async function executeLoopStep(deps) {
245087
- const { turnId, signal, buildMessages, buildMessagesStrict, dispatchEvent, llm, tools, hooks, log, currentStep, maxRetryAttempts, recordUsage, onStepStarted, checkpointBeforeToolExecution, checkpointBeforeRetryWait } = deps;
245097
+ const { turnId, signal, buildMessages, buildMessagesStrict, dispatchEvent, llm, tools, hooks, log, currentStep, maxRetryAttempts, recordUsage, onStepStarted, checkpointBeforeToolExecution, checkpointBeforeRetryWait, beginInterruptibleRequest, endInterruptibleRequest } = deps;
245088
245098
  const beforeStep = hooks?.beforeStep === void 0 ? void 0 : await hooks.beforeStep({
245089
245099
  turnId,
245090
245100
  stepNumber: currentStep,
@@ -245132,6 +245142,9 @@ async function executeLoopStep(deps) {
245132
245142
  if (prepareRequestBoundary === void 0) await stepEvents.start();
245133
245143
  else chatParams = await prepareRequestBoundary(chatParams, stepBuildMessages);
245134
245144
  signal.throwIfAborted();
245145
+ const requestSignal = beginInterruptibleRequest?.() ?? signal;
245146
+ const wasInterruptedByActiveSteer = (error) => isActiveSteerInterrupt(error) || isActiveSteerInterrupt(requestSignal.reason);
245147
+ chatParams = { ...chatParams, signal: requestSignal };
245135
245148
  const retryInput = {
245136
245149
  llm: stepLLM,
245137
245150
  dispatchEvent: (event) => stepEvents.dispatchRetrying(event),
@@ -245148,11 +245161,20 @@ async function executeLoopStep(deps) {
245148
245161
  retryInput,
245149
245162
  params: chatParams,
245150
245163
  stepEvents,
245151
- signal,
245164
+ signal: requestSignal,
245152
245165
  log
245153
245166
  });
245154
245167
  } catch (error) {
245155
245168
  await stepEvents.drain();
245169
+ if (wasInterruptedByActiveSteer(error) && !signal.aborted) {
245170
+ await dispatchEvent({
245171
+ type: "turn.interrupted",
245172
+ reason: "steered",
245173
+ attemptedSteps: currentStep,
245174
+ activeStep: currentStep
245175
+ });
245176
+ return { usage: emptyUsage(), stopReason: "steer_restart" };
245177
+ }
245156
245178
  if (stepBuildMessagesStrict === void 0 || !isRecoverableRequestStructureError(error) || prepareRequestBoundary !== void 0 && stepEvents.hasOutput) throw error;
245157
245179
  signal.throwIfAborted();
245158
245180
  log?.warn("provider rejected request structure; resending with strict projection", {
@@ -245172,10 +245194,19 @@ async function executeLoopStep(deps) {
245172
245194
  retryInput,
245173
245195
  params: strictParams,
245174
245196
  stepEvents,
245175
- signal,
245197
+ signal: requestSignal,
245176
245198
  log
245177
245199
  });
245178
245200
  } catch (strictError) {
245201
+ if (wasInterruptedByActiveSteer(strictError) && !signal.aborted) {
245202
+ await dispatchEvent({
245203
+ type: "turn.interrupted",
245204
+ reason: "steered",
245205
+ attemptedSteps: currentStep,
245206
+ activeStep: currentStep
245207
+ });
245208
+ return { usage: emptyUsage(), stopReason: "steer_restart" };
245209
+ }
245179
245210
  log?.error("strict resend still rejected by provider; request remains wire-invalid", {
245180
245211
  turnStep: `${turnId}.${String(currentStep)}`,
245181
245212
  model: stepLLM.modelName,
@@ -245185,6 +245216,8 @@ async function executeLoopStep(deps) {
245185
245216
  throw strictError;
245186
245217
  }
245187
245218
  log?.info("recovered after strict resend", { turnStep: `${turnId}.${String(currentStep)}` });
245219
+ } finally {
245220
+ endInterruptibleRequest?.();
245188
245221
  }
245189
245222
  await stepEvents.start();
245190
245223
  await stepEvents.drain();
@@ -245275,20 +245308,53 @@ function stepEndProviderDiagnostics(response, stopReason) {
245275
245308
  };
245276
245309
  }
245277
245310
  var { createLiveResponseRepetitionGuard } = createRequire(import.meta.url)("./bin/live-response-repetition-guard.cjs");
245311
+ var { createThinkingOnlyGuard, forceAnswerParams } = createRequire(import.meta.url)("./bin/thinking-only-guard.cjs");
245312
+ var { ACTIVE_STEER_PRIORITY_REMINDER, createActiveSteerInterrupt, isActiveSteerInterrupt } = createRequire(import.meta.url)("./bin/active-steer-priority-policy.cjs");
245278
245313
  async function chatWithLiveResponseRepetitionRecovery(deps) {
245279
245314
  const { retryInput, params, stepEvents, signal, log } = deps;
245315
+ let currentParams = params;
245280
245316
  for (let attempt = 1; attempt <= 2; attempt++) {
245281
245317
  try {
245282
- return await chatWithRetry({
245318
+ const response = await chatWithRetry({
245283
245319
  ...retryInput,
245284
245320
  params: {
245285
- ...params,
245321
+ ...currentParams,
245286
245322
  signal: stepEvents.beginLiveResponseAttempt(signal)
245287
245323
  }
245288
245324
  });
245325
+ stepEvents.finishLiveResponseAttempt();
245326
+ return response;
245289
245327
  } catch (error) {
245290
245328
  await stepEvents.drain();
245291
245329
  const repetition = stepEvents.liveRepetitionResult;
245330
+ const thinkingTimeout = stepEvents.thinkingOnlyTimeoutResult;
245331
+ stepEvents.finishLiveResponseAttempt();
245332
+ if (thinkingTimeout !== null && !signal.aborted && attempt < 2) {
245333
+ log?.warn("thinking-only phase exceeded limit; forcing answer", {
245334
+ elapsedMs: thinkingTimeout.elapsedMs,
245335
+ turnStep: `${retryInput.turnId}.${String(retryInput.currentStep)}`
245336
+ });
245337
+ await persistRetrySchedule({
245338
+ dispatchRetrying: (event) => stepEvents.dispatchRetrying(event),
245339
+ flush: retryInput.checkpointBeforeRetryWait,
245340
+ signal,
245341
+ event: {
245342
+ type: "step.retrying",
245343
+ turnId: retryInput.turnId,
245344
+ step: retryInput.currentStep,
245345
+ stepUuid: retryInput.stepUuid,
245346
+ failedAttempt: attempt,
245347
+ nextAttempt: attempt + 1,
245348
+ maxAttempts: 2,
245349
+ delayMs: 0,
245350
+ outputMayHaveStarted: true,
245351
+ errorName: "ThinkingOnlyTimeoutError",
245352
+ errorMessage: "Hidden thinking exceeded the bounded thinking-only phase"
245353
+ }
245354
+ });
245355
+ currentParams = forceAnswerParams(currentParams);
245356
+ continue;
245357
+ }
245292
245358
  if (repetition === null || signal.aborted || attempt >= 2) throw error;
245293
245359
  log?.warn("live response repetition detected; retrying step once", {
245294
245360
  charCount: repetition.charCount,
@@ -245325,6 +245391,9 @@ function createStepEventGate(deps) {
245325
245391
  let liveRepetitionGuard;
245326
245392
  let liveRepetitionController;
245327
245393
  let liveRepetitionResult = null;
245394
+ let thinkingOnlyController;
245395
+ let thinkingOnlyGuard;
245396
+ let thinkingOnlyTimeoutResult = null;
245328
245397
  const start = () => {
245329
245398
  startPromise ??= (async () => {
245330
245399
  await dispatchEvent({
@@ -245365,12 +245434,25 @@ function createStepEventGate(deps) {
245365
245434
  get liveRepetitionResult() {
245366
245435
  return liveRepetitionResult;
245367
245436
  },
245437
+ get thinkingOnlyTimeoutResult() {
245438
+ return thinkingOnlyTimeoutResult;
245439
+ },
245368
245440
  beginLiveResponseAttempt: (signal) => {
245369
245441
  liveRepetitionGuard = createLiveResponseRepetitionGuard();
245370
245442
  liveRepetitionController = new AbortController();
245371
245443
  liveRepetitionResult = null;
245372
- return AbortSignal.any([signal, liveRepetitionController.signal]);
245444
+ thinkingOnlyController = new AbortController();
245445
+ thinkingOnlyTimeoutResult = null;
245446
+ thinkingOnlyGuard = createThinkingOnlyGuard({
245447
+ onTimeout: (result) => {
245448
+ thinkingOnlyTimeoutResult = result;
245449
+ thinkingOnlyController?.abort(/* @__PURE__ */ new Error("Hidden thinking exceeded the bounded thinking-only phase"));
245450
+ }
245451
+ });
245452
+ thinkingOnlyGuard.beginAttempt();
245453
+ return AbortSignal.any([signal, liveRepetitionController.signal, thinkingOnlyController.signal]);
245373
245454
  },
245455
+ finishLiveResponseAttempt: () => thinkingOnlyGuard?.stop(),
245374
245456
  dispatchRetrying: async (event) => {
245375
245457
  const queued = eventQueue.then(async () => {
245376
245458
  await start();
@@ -245383,6 +245465,7 @@ function createStepEventGate(deps) {
245383
245465
  drain: async () => eventQueue,
245384
245466
  callbacks: {
245385
245467
  onTextDelta: (delta) => {
245468
+ if (delta.length > 0) thinkingOnlyGuard?.noteSubstantiveOutput();
245386
245469
  if (inspectLiveRepetition(delta)) return;
245387
245470
  enqueue(() => {
245388
245471
  dispatchEvent({
@@ -245392,6 +245475,7 @@ function createStepEventGate(deps) {
245392
245475
  });
245393
245476
  },
245394
245477
  onThinkDelta: (delta) => {
245478
+ thinkingOnlyGuard?.noteThinking();
245395
245479
  if (inspectLiveRepetition(delta)) return;
245396
245480
  enqueue(() => {
245397
245481
  dispatchEvent({
@@ -245400,7 +245484,17 @@ function createStepEventGate(deps) {
245400
245484
  });
245401
245485
  });
245402
245486
  },
245487
+ onThinkTokens: (cumulativeTokens) => {
245488
+ thinkingOnlyGuard?.noteThinking();
245489
+ enqueue(() => {
245490
+ dispatchEvent({
245491
+ type: "thinking.progress",
245492
+ cumulativeTokens
245493
+ });
245494
+ });
245495
+ },
245403
245496
  onToolCallDelta: (delta) => {
245497
+ thinkingOnlyGuard?.noteSubstantiveOutput();
245404
245498
  enqueue(() => {
245405
245499
  dispatchEvent({
245406
245500
  type: "tool.call.delta",
@@ -245410,14 +245504,17 @@ function createStepEventGate(deps) {
245410
245504
  });
245411
245505
  });
245412
245506
  },
245413
- onTextPart: (part) => enqueue(() => dispatchEvent({
245414
- type: "content.part",
245415
- uuid: randomUUID(),
245416
- turnId,
245417
- step: currentStep,
245418
- stepUuid,
245419
- part
245420
- })),
245507
+ onTextPart: (part) => {
245508
+ thinkingOnlyGuard?.noteSubstantiveOutput();
245509
+ return enqueue(() => dispatchEvent({
245510
+ type: "content.part",
245511
+ uuid: randomUUID(),
245512
+ turnId,
245513
+ step: currentStep,
245514
+ stepUuid,
245515
+ part
245516
+ }));
245517
+ },
245421
245518
  onThinkPart: (part) => enqueue(() => dispatchEvent({
245422
245519
  type: "content.part",
245423
245520
  uuid: randomUUID(),
@@ -245474,6 +245571,10 @@ async function runTurn(input) {
245474
245571
  onStepStarted: setActiveStep.bind(void 0, stepNumber)
245475
245572
  });
245476
245573
  activeStep = void 0;
245574
+ if (stepResult.stopReason === "steer_restart") {
245575
+ steps -= 1;
245576
+ continue;
245577
+ }
245477
245578
  if (stepResult.stopReason === "tool_use") continue;
245478
245579
  const terminalStopReason = stepResult.stopReason;
245479
245580
  stopReason = terminalStopReason;
@@ -246368,7 +246469,7 @@ var init_modelCatalog$2 = __esmMin((() => {
246368
246469
  function isVolatileEventType(type) {
246369
246470
  return volatileEventTypeSet.has(type);
246370
246471
  }
246371
- var MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE, tokenUsageSchema, finishReasonSchema, usageStatusSchema, permissionModeSchema, skillSourceSchema, userPromptOriginSchema, skillActivationOriginSchema, pluginCommandOriginSchema, injectionOriginSchema, shellCommandOriginSchema, compactionSummaryOriginSchema, cronToolScopeSchema, systemTriggerOriginSchema, agentCoreBackgroundTaskStatusSchema, backgroundTaskOriginSchema, cronJobOriginSchema, cronMissedOriginSchema, hookResultOriginSchema, retryOriginSchema, promptOriginSchema, goalStatusSchema, goalActorSchema, goalBudgetReportSchema, goalSnapshotSchema, goalChangeStatsSchema, goalChangeKindSchema, goalChangeSchema, blunErrorCodeSchema, blunErrorPayloadSchema, backgroundTaskInfoBaseSchema, processBackgroundTaskInfoSchema, agentBackgroundTaskInfoSchema, questionBackgroundTaskInfoSchema, backgroundTaskInfoSchema, compactionResultSchema, toolUpdateSchema, turnEndReasonSchema, agentStatusUpdatedEventSchema, sessionMetaUpdatedEventSchema, sessionCreatedEventSchema, workspaceCreatedEventSchema, workspaceUpdatedEventSchema, workspaceDeletedEventSchema, sessionStatusChangedEventSchema, modelCatalogChangedEventSchema, goalUpdatedEventSchema, skillActivatedEventSchema, pluginCommandActivatedEventSchema, errorEventSchema, warningEventSchema, turnStartedEventSchema, turnEndedEventSchema, turnStepStartedEventSchema, turnStepCompletedEventSchema, turnStepRetryingEventSchema, turnStepInterruptedEventSchema, assistantDeltaEventSchema, hookResultEventSchema, thinkingDeltaEventSchema, toolCallDeltaEventSchema, toolCallStartedEventSchema, toolProgressEventSchema, shellOutputEventSchema, shellStartedEventSchema, toolResultEventSchema, subagentSpawnedEventSchema, subagentStartedEventSchema, subagentSuspendedEventSchema, subagentCompletedEventSchema, subagentFailedEventSchema, compactionStartedEventSchema, compactionBlockedEventSchema, compactionCancelledEventSchema, compactionProgressEventSchema, compactionCompletedEventSchema, backgroundTaskStartedEventSchema, backgroundTaskTerminatedEventSchema, cronFiredEventSchema, cronRunCreatedEventSchema, cronRunStartedEventSchema, cronRunTerminalEventSchema, attentionIntentSchema, attentionAuthorizedEventSchema, promptSubmittedEventSchema, toolListUpdatedReasonSchema, toolListUpdatedEventSchema, mcpServerStatusPayloadSchema, mcpServerStatusEventSchema, mediaDroppedEventSchema, agentEventSchema, eventSchema, VOLATILE_EVENT_TYPES, volatileEventTypeSet;
246472
+ var MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE, tokenUsageSchema, finishReasonSchema, usageStatusSchema, permissionModeSchema, skillSourceSchema, userPromptOriginSchema, skillActivationOriginSchema, pluginCommandOriginSchema, injectionOriginSchema, shellCommandOriginSchema, compactionSummaryOriginSchema, cronToolScopeSchema, systemTriggerOriginSchema, agentCoreBackgroundTaskStatusSchema, backgroundTaskOriginSchema, cronJobOriginSchema, cronMissedOriginSchema, hookResultOriginSchema, retryOriginSchema, promptOriginSchema, goalStatusSchema, goalActorSchema, goalBudgetReportSchema, goalSnapshotSchema, goalChangeStatsSchema, goalChangeKindSchema, goalChangeSchema, blunErrorCodeSchema, blunErrorPayloadSchema, backgroundTaskInfoBaseSchema, processBackgroundTaskInfoSchema, agentBackgroundTaskInfoSchema, questionBackgroundTaskInfoSchema, backgroundTaskInfoSchema, compactionResultSchema, toolUpdateSchema, turnEndReasonSchema, agentStatusUpdatedEventSchema, sessionMetaUpdatedEventSchema, sessionCreatedEventSchema, workspaceCreatedEventSchema, workspaceUpdatedEventSchema, workspaceDeletedEventSchema, sessionStatusChangedEventSchema, modelCatalogChangedEventSchema, goalUpdatedEventSchema, skillActivatedEventSchema, pluginCommandActivatedEventSchema, errorEventSchema, warningEventSchema, turnStartedEventSchema, turnEndedEventSchema, turnStepStartedEventSchema, turnStepCompletedEventSchema, turnStepRetryingEventSchema, turnStepInterruptedEventSchema, assistantDeltaEventSchema, hookResultEventSchema, thinkingDeltaEventSchema, thinkingProgressEventSchema, toolCallDeltaEventSchema, toolCallStartedEventSchema, toolProgressEventSchema, shellOutputEventSchema, shellStartedEventSchema, toolResultEventSchema, subagentSpawnedEventSchema, subagentStartedEventSchema, subagentSuspendedEventSchema, subagentCompletedEventSchema, subagentFailedEventSchema, compactionStartedEventSchema, compactionBlockedEventSchema, compactionCancelledEventSchema, compactionProgressEventSchema, compactionCompletedEventSchema, backgroundTaskStartedEventSchema, backgroundTaskTerminatedEventSchema, cronFiredEventSchema, cronRunCreatedEventSchema, cronRunStartedEventSchema, cronRunTerminalEventSchema, attentionIntentSchema, attentionAuthorizedEventSchema, promptSubmittedEventSchema, toolListUpdatedReasonSchema, toolListUpdatedEventSchema, mcpServerStatusPayloadSchema, mcpServerStatusEventSchema, mediaDroppedEventSchema, agentEventSchema, eventSchema, VOLATILE_EVENT_TYPES, volatileEventTypeSet;
246372
246473
  var init_events$1 = __esmMin((() => {
246373
246474
  init_zod$1();
246374
246475
  init_display();
@@ -246905,6 +247006,11 @@ var init_events$1 = __esmMin((() => {
246905
247006
  turnId: number$1(),
246906
247007
  delta: string()
246907
247008
  });
247009
+ thinkingProgressEventSchema = object({
247010
+ type: literal("thinking.progress"),
247011
+ turnId: number$1(),
247012
+ cumulativeTokens: number$1().int().nonnegative()
247013
+ });
246908
247014
  toolCallDeltaEventSchema = object({
246909
247015
  type: literal("tool.call.delta"),
246910
247016
  turnId: number$1(),
@@ -247130,6 +247236,7 @@ var init_events$1 = __esmMin((() => {
247130
247236
  assistantDeltaEventSchema,
247131
247237
  hookResultEventSchema,
247132
247238
  thinkingDeltaEventSchema,
247239
+ thinkingProgressEventSchema,
247133
247240
  toolCallDeltaEventSchema,
247134
247241
  toolCallStartedEventSchema,
247135
247242
  toolProgressEventSchema,
@@ -247165,6 +247272,7 @@ var init_events$1 = __esmMin((() => {
247165
247272
  VOLATILE_EVENT_TYPES = [
247166
247273
  "assistant.delta",
247167
247274
  "thinking.delta",
247275
+ "thinking.progress",
247168
247276
  "tool.call.delta",
247169
247277
  "tool.progress",
247170
247278
  "compaction.progress",
@@ -261915,13 +262023,11 @@ function appendReminder(result, reminderText) {
261915
262023
  output: newOutput
261916
262024
  };
261917
262025
  }
261918
- function forceStopResult(result, reminderText) {
261919
- return {
261920
- ...appendReminder(result, reminderText),
261921
- stopTurn: true
261922
- };
261923
- }
261924
- var REMINDER_TEXT_1, REMINDER_TEXT_3, REPEAT_REMINDER_1_START, REPEAT_REMINDER_2_START, REPEAT_REMINDER_3_START, REPEAT_FORCE_STOP_STREAK, DEDUP_PLACEHOLDER_RESULT, ToolCallDeduplicator;
262026
+ var loopPolicy = createRequire(import.meta.url)("./bin/tool-call-loop-policy.cjs");
262027
+ var FORCE_ANSWER_RESULT_STREAK = loopPolicy.FORCE_ANSWER_RESULT_STREAK;
262028
+ var createToolCallLoopKey = loopPolicy.createToolCallLoopKey;
262029
+ var hashToolResult = loopPolicy.hashToolResult;
262030
+ var REMINDER_TEXT_1, REMINDER_TEXT_3, REPEAT_REMINDER_1_START, REPEAT_REMINDER_2_START, REPEAT_REMINDER_3_START, DEDUP_PLACEHOLDER_RESULT, ToolCallDeduplicator;
261925
262031
  var init_tool_dedup = __esmMin((() => {
261926
262032
  init_canonical_args();
261927
262033
  REMINDER_TEXT_1 = "\n\n<system-reminder>\nYou are repeating the exact same tool call with identical parameters. Please carefully analyze the previous result. If the task is not yet complete, try a different method or parameters instead of repeating the same call.\n</system-reminder>";
@@ -261929,7 +262035,6 @@ var init_tool_dedup = __esmMin((() => {
261929
262035
  REPEAT_REMINDER_1_START = 3;
261930
262036
  REPEAT_REMINDER_2_START = 5;
261931
262037
  REPEAT_REMINDER_3_START = 8;
261932
- REPEAT_FORCE_STOP_STREAK = 12;
261933
262038
  DEDUP_PLACEHOLDER_RESULT = { output: "" };
261934
262039
  ToolCallDeduplicator = class {
261935
262040
  stepDeferreds = /* @__PURE__ */ new Map();
@@ -261945,8 +262050,14 @@ var init_tool_dedup = __esmMin((() => {
261945
262050
  * during finalize.
261946
262051
  */
261947
262052
  callKeyByCallId = /* @__PURE__ */ new Map();
262053
+ /** The tolerant key is used only for cross-step loop detection. */
262054
+ callLoopKeyByCallId = /* @__PURE__ */ new Map();
261948
262055
  consecutiveKey = null;
261949
262056
  consecutiveCount = 0;
262057
+ lastResultLoopKey = null;
262058
+ lastResultHash = null;
262059
+ resultStreakCount = 0;
262060
+ forceAnswerOnly = false;
261950
262061
  telemetry;
261951
262062
  constructor(options) {
261952
262063
  this.telemetry = options?.telemetry;
@@ -261961,6 +262072,7 @@ var init_tool_dedup = __esmMin((() => {
261961
262072
  this.originalCallIndex.clear();
261962
262073
  this.syntheticCallIds.clear();
261963
262074
  this.callKeyByCallId.clear();
262075
+ this.callLoopKeyByCallId.clear();
261964
262076
  }
261965
262077
  endStep() {
261966
262078
  for (const key of this.stepCalls) if (key === this.consecutiveKey) this.consecutiveCount += 1;
@@ -261969,6 +262081,9 @@ var init_tool_dedup = __esmMin((() => {
261969
262081
  this.consecutiveCount = 1;
261970
262082
  }
261971
262083
  }
262084
+ shouldForceAnswerOnly() {
262085
+ return this.forceAnswerOnly;
262086
+ }
261972
262087
  /**
261973
262088
  * Called from `prepareToolExecution`. If this `(toolName, args)` was already
261974
262089
  * seen in the current step, returns a placeholder result so the loop can
@@ -261981,9 +262096,11 @@ var init_tool_dedup = __esmMin((() => {
261981
262096
  */
261982
262097
  checkSameStep(toolCallId, toolName, args) {
261983
262098
  const key = makeKey(toolName, args);
262099
+ const loopKey = createToolCallLoopKey(toolName, args);
261984
262100
  const index = this.stepCalls.length;
261985
- this.stepCalls.push(key);
262101
+ this.stepCalls.push(loopKey);
261986
262102
  this.callKeyByCallId.set(toolCallId, key);
262103
+ this.callLoopKeyByCallId.set(toolCallId, loopKey);
261987
262104
  if (this.stepDeferreds.get(key) !== void 0) {
261988
262105
  this.syntheticCallIds.add(toolCallId);
261989
262106
  return DEDUP_PLACEHOLDER_RESULT;
@@ -262004,6 +262121,8 @@ var init_tool_dedup = __esmMin((() => {
262004
262121
  const key = this.callKeyByCallId.get(toolCallId);
262005
262122
  if (key === void 0) return result;
262006
262123
  this.callKeyByCallId.delete(toolCallId);
262124
+ const loopKey = this.callLoopKeyByCallId.get(toolCallId);
262125
+ this.callLoopKeyByCallId.delete(toolCallId);
262007
262126
  if (this.syntheticCallIds.delete(toolCallId)) {
262008
262127
  const deferred = this.stepDeferreds.get(key);
262009
262128
  if (deferred === void 0) return result;
@@ -262024,9 +262143,15 @@ var init_tool_dedup = __esmMin((() => {
262024
262143
  }
262025
262144
  let finalResult = result;
262026
262145
  let action = "none";
262027
- if (streak >= REPEAT_FORCE_STOP_STREAK) {
262028
- finalResult = forceStopResult(result, REMINDER_TEXT_3);
262029
- action = "stop";
262146
+ const resultHash = hashToolResult(result);
262147
+ const resultRepeatCount = this.lastResultLoopKey === loopKey && this.lastResultHash === resultHash ? this.resultStreakCount + 1 : 1;
262148
+ this.lastResultLoopKey = loopKey;
262149
+ this.lastResultHash = resultHash;
262150
+ this.resultStreakCount = resultRepeatCount;
262151
+ if (resultRepeatCount >= FORCE_ANSWER_RESULT_STREAK) {
262152
+ finalResult = appendReminder(result, REMINDER_TEXT_3);
262153
+ this.forceAnswerOnly = true;
262154
+ action = "force_answer";
262030
262155
  } else if (streak >= REPEAT_REMINDER_3_START) {
262031
262156
  finalResult = appendReminder(result, REMINDER_TEXT_3);
262032
262157
  action = "r3";
@@ -262037,9 +262162,10 @@ var init_tool_dedup = __esmMin((() => {
262037
262162
  finalResult = appendReminder(result, REMINDER_TEXT_1);
262038
262163
  action = "r1";
262039
262164
  }
262040
- if (streak >= 2) this.telemetry?.track("tool_call_repeat", {
262165
+ if (streak >= 2 || resultRepeatCount >= 2) this.telemetry?.track("tool_call_repeat", {
262041
262166
  tool_name: toolName,
262042
262167
  repeat_count: streak,
262168
+ result_repeat_count: resultRepeatCount,
262043
262169
  action
262044
262170
  });
262045
262171
  this.stepDeferreds.get(key)?.resolve(finalResult);
@@ -262911,6 +263037,11 @@ function mapLoopEvent(event, turnId) {
262911
263037
  turnId,
262912
263038
  delta: event.delta
262913
263039
  };
263040
+ case "thinking.progress": return {
263041
+ type: "thinking.progress",
263042
+ turnId,
263043
+ cumulativeTokens: event.cumulativeTokens
263044
+ };
262914
263045
  case "tool.call.delta": return {
262915
263046
  type: "tool.call.delta",
262916
263047
  turnId,
@@ -263066,7 +263197,7 @@ function durablePromptOrigin(origin) {
263066
263197
  void externalReportSources;
263067
263198
  return durableOrigin;
263068
263199
  }
263069
- var BLUN_CORE_TOOL_NAMES, BLUN_LEAN_TOOL_NAMES, BLUN_ATTACHMENT_MARKER_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TELEGRAM_CHANNEL_RE, BLUN_TOOL_BUDGET_RATIO, createDeferredToolLoader, mediaToolNamesForTurnText, rankedSupportToolNamesForGoal, rankedToolNamesForTurnText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens, assessTodoListBounds, assessTodoMaintenanceUpdate, enforceSingleTodoWritePerStep, todoRefreshWorkCallLimit, projectRecurringCronHistory, TelegramDeliveryLedger, createRuntimeCognitiveTurnLifecycle, cognitiveFocusScopesForTurn, buildCognitiveWorkFocus, buildAttentionQueueItem, LLM_NOT_SET_MESSAGE, GOAL_CONTINUATION_ORIGIN, GOAL_COMPLETION_REMINDER_NAME, GOAL_BLOCKED_REMINDER_NAME, GOAL_RATE_LIMIT_PAUSE_REASON, GOAL_PROVIDER_CONNECTION_PAUSE_PREFIX, GOAL_PROVIDER_AUTH_PAUSE_PREFIX, GOAL_PROVIDER_API_PAUSE_PREFIX, GOAL_MODEL_CONFIG_PAUSE_PREFIX, GOAL_RUNTIME_PAUSE_PREFIX, GOAL_PROVIDER_FILTERED_PAUSE_REASON, GOAL_CONTINUATION_PROMPT, TurnFlow;
263200
+ var BLUN_CORE_TOOL_NAMES, BLUN_LEAN_TOOL_NAMES, BLUN_ATTACHMENT_MARKER_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TELEGRAM_CHANNEL_RE, BLUN_TOOL_BUDGET_RATIO, applyMnemoAgentToToolArgs, createDeferredToolLoader, mediaToolNamesForTurnText, rankedSupportToolNamesForGoal, rankedToolNamesForTurnText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens, assessTodoListBounds, assessTodoMaintenanceUpdate, enforceSingleTodoWritePerStep, todoRefreshWorkCallLimit, projectRecurringCronHistory, TelegramDeliveryLedger, createRuntimeCognitiveTurnLifecycle, cognitiveFocusScopesForTurn, buildCognitiveWorkFocus, buildAttentionQueueItem, LLM_NOT_SET_MESSAGE, GOAL_CONTINUATION_ORIGIN, GOAL_COMPLETION_REMINDER_NAME, GOAL_BLOCKED_REMINDER_NAME, GOAL_RATE_LIMIT_PAUSE_REASON, GOAL_PROVIDER_CONNECTION_PAUSE_PREFIX, GOAL_PROVIDER_AUTH_PAUSE_PREFIX, GOAL_PROVIDER_API_PAUSE_PREFIX, GOAL_MODEL_CONFIG_PAUSE_PREFIX, GOAL_RUNTIME_PAUSE_PREFIX, GOAL_PROVIDER_FILTERED_PAUSE_REASON, GOAL_CONTINUATION_PROMPT, TurnFlow;
263070
263201
  var init_turn = __esmMin((() => {
263071
263202
  init_dist$4();
263072
263203
  init_src$4();
@@ -263080,6 +263211,7 @@ var init_turn = __esmMin((() => {
263080
263211
  init_hooks();
263081
263212
  init_canonical_args();
263082
263213
  init_tool_dedup();
263214
+ ({ applyMnemoAgentToToolArgs } = createRequire(import.meta.url)("./bin/mnemo-tool-agent-policy.cjs"));
263083
263215
  init_tool_result_budget();
263084
263216
  init_user_message_offload();
263085
263217
  init_assistant_message_offload();
@@ -263420,6 +263552,7 @@ var init_turn = __esmMin((() => {
263420
263552
  origin: durablePromptOrigin(origin)
263421
263553
  });
263422
263554
  this.bufferSteer(input, origin, this.currentId);
263555
+ active.interruptActiveStep?.();
263423
263556
  return {
263424
263557
  turnId: this.currentId,
263425
263558
  duplicate: false
@@ -263453,7 +263586,8 @@ var init_turn = __esmMin((() => {
263453
263586
  controller,
263454
263587
  promise,
263455
263588
  firstRequest,
263456
- acceptingSteers: false
263589
+ acceptingSteers: false,
263590
+ interruptActiveStep: void 0
263457
263591
  };
263458
263592
  firstRequest.catch(() => void 0);
263459
263593
  promise.then(firstRequest.reject, firstRequest.reject);
@@ -263584,6 +263718,11 @@ var init_turn = __esmMin((() => {
263584
263718
  if (active === null || active === "resuming" || this.currentId !== turnId) return;
263585
263719
  active.acceptingSteers = accepting;
263586
263720
  }
263721
+ setActiveStepInterrupter(turnId, interrupter) {
263722
+ const active = this.activeTurn;
263723
+ if (active === null || active === "resuming" || this.currentId !== turnId) return;
263724
+ active.interruptActiveStep = interrupter;
263725
+ }
263587
263726
  discardUnconsumedActiveSteers(turnId) {
263588
263727
  const before = this.steerBuffer.length;
263589
263728
  this.steerBuffer = this.steerBuffer.filter((steer) => steer.targetTurnId !== turnId);
@@ -263937,7 +264076,7 @@ var init_turn = __esmMin((() => {
263937
264076
  const turnText = blunExtractText(input);
263938
264077
  const turnNeedsTools = blunTurnNeedsTools(input, origin);
263939
264078
  const turnHasAttachment = blunTurnHasAttachment(input);
263940
- const turnThinkingEffort = turnHasAttachment ? void 0 : selectThinkingEffortForTurn(blunExtractText(blunThinkingIntentInput(input)), origin.kind);
264079
+ const turnThinkingEffort = turnHasAttachment ? void 0 : selectThinkingEffortForTurn(blunExtractText(blunThinkingIntentInput(input)), origin.kind, this.agent.config.thinkingEffort);
263941
264080
  const fastConversation = turnThinkingEffort === "off" || turnThinkingEffort === "low";
263942
264081
  const pendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
263943
264082
  const requiredToolNames = mediaToolNamesForTurnText(turnText);
@@ -263947,6 +264086,7 @@ var init_turn = __esmMin((() => {
263947
264086
  let currentStepHadTool = false;
263948
264087
  let currentStepHadFailure = false;
263949
264088
  let currentLoopStep = 0;
264089
+ let activeStepInterruptController;
263950
264090
  while (true) {
263951
264091
  signal.throwIfAborted();
263952
264092
  const model = this.agent.config.model;
@@ -263999,6 +264139,15 @@ var init_turn = __esmMin((() => {
263999
264139
  maxRetryAttempts: loopControl?.maxRetriesPerStep,
264000
264140
  checkpointBeforeToolExecution: () => this.agent.records.flush(),
264001
264141
  checkpointBeforeRetryWait: () => this.agent.records.flush(),
264142
+ beginInterruptibleRequest: () => {
264143
+ activeStepInterruptController = new AbortController();
264144
+ this.setActiveStepInterrupter(turnId, () => activeStepInterruptController?.abort(createActiveSteerInterrupt()));
264145
+ return AbortSignal.any([signal, activeStepInterruptController.signal]);
264146
+ },
264147
+ endInterruptibleRequest: () => {
264148
+ this.setActiveStepInterrupter(turnId, void 0);
264149
+ activeStepInterruptController = void 0;
264150
+ },
264002
264151
  recordStepUsage: async (usage) => {
264003
264152
  try {
264004
264153
  stopForGoalBudget = (await this.agent.goal.recordTokenUsage(grandTotal(usage)))?.budget.overBudget === true;
@@ -264017,6 +264166,10 @@ var init_turn = __esmMin((() => {
264017
264166
  await this.agent.injection.inject();
264018
264167
  stepSignal.throwIfAborted();
264019
264168
  deduper.beginStep();
264169
+ if (deduper.shouldForceAnswerOnly()) {
264170
+ this.agent.log.warn("tool loop stopped; forcing text answer", { stepNumber });
264171
+ return { tools: [] };
264172
+ }
264020
264173
  const workStepThinkingEffort = selectThinkingEffortForWorkStep(stepNumber, previousStepToolOutcome);
264021
264174
  currentStepHadTool = false;
264022
264175
  currentStepHadFailure = false;
@@ -264054,13 +264207,26 @@ var init_turn = __esmMin((() => {
264054
264207
  }
264055
264208
  if (pendingSteers.some((steer) => directMessageAllowsWorkContinuation(blunExtractText(steer.input)))) directSteerContinuationPending = true;
264056
264209
  const steerEfforts = pendingSteers.map((steer) => blunTurnHasAttachment(steer.input) ? void 0 : selectThinkingEffortForBufferedSteer(blunExtractText(blunThinkingIntentInput(steer.input)), steer.origin.kind));
264057
- if (steerEfforts.some((effort) => effort === void 0)) return;
264058
264210
  const steerInput = pendingSteers.flatMap((steer) => [...steer.input]);
264059
- const steerThinkingEffort = "low";
264060
- const steerPendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
264061
264211
  const steerText = blunExtractText(steerInput);
264062
264212
  const steerRequiredToolNames = mediaToolNamesForTurnText(steerText);
264063
264213
  for (const name of rankedToolNamesForTurnText(eligibleTools, steerText)) steerRequiredToolNames.add(name);
264214
+ if (steerEfforts.some((effort) => effort === void 0)) {
264215
+ const prioritizedSelection = blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens, this.loadedToolNames, steerRequiredToolNames);
264216
+ this.agent.context.appendSystemReminder(ACTIVE_STEER_PRIORITY_REMINDER, {
264217
+ kind: "injection",
264218
+ variant: "active_steer_priority"
264219
+ });
264220
+ this.agent.log.info("steer request tools", {
264221
+ requestPurpose: "active_steer_priority",
264222
+ pendingSteerCount: pendingSteers.length,
264223
+ selectedToolCount: prioritizedSelection.tools.length,
264224
+ deferredToolCount: prioritizedSelection.deferredToolCount
264225
+ });
264226
+ return { tools: prioritizedSelection.tools };
264227
+ }
264228
+ const steerThinkingEffort = "low";
264229
+ const steerPendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
264064
264230
  const steerNeedsActionTools = steerRequiredToolNames.size > 0;
264065
264231
  const steerLLM = this.agent.llmForTurn(steerThinkingEffort, blunPendingMediaSystemPrompt(steerNeedsActionTools ? this.agent.effectiveSystemPrompt : this.agent.fastConversationSystemPrompt, steerPendingMediaJobIds));
264066
264232
  const steerTools = [...blunFastConversationTools(eligibleTools, steerInput, steerPendingMediaJobIds, steerRequiredToolNames)];
@@ -264155,8 +264321,10 @@ var init_turn = __esmMin((() => {
264155
264321
  if (goalTodoPolicy !== void 0) return goalTodoPolicy;
264156
264322
  const ideaPolicy = enforceIdeaToolPolicy(this.agent, ctx);
264157
264323
  if (ideaPolicy !== void 0) return ideaPolicy;
264158
- const cached = deduper.checkSameStep(ctx.toolCall.id, ctx.toolCall.name, ctx.args);
264159
- if (cached !== null) return { syntheticResult: cached };
264324
+ const effectiveArgs = applyMnemoAgentToToolArgs(ctx.toolCall.name, ctx.args);
264325
+ const cached = deduper.checkSameStep(ctx.toolCall.id, ctx.toolCall.name, effectiveArgs);
264326
+ if (cached !== null) return { updatedArgs: effectiveArgs, syntheticResult: cached };
264327
+ if (effectiveArgs !== ctx.args) return { updatedArgs: effectiveArgs };
264160
264328
  },
264161
264329
  authorizeToolExecution: async (ctx) => {
264162
264330
  try {
@@ -264263,7 +264431,7 @@ var init_turn = __esmMin((() => {
264263
264431
  emitLiveEvent: (event) => {
264264
264432
  this.noteFirstRequestEvent(event);
264265
264433
  this.trackLoopTelemetry(event, turnId);
264266
- if (event.type === "thinking.delta" && event.delta.trim().length === 0) {
264434
+ if (event.type === "thinking.progress" || event.type === "thinking.delta" && event.delta.trim().length === 0) {
264267
264435
  const requestState = this.stepRequestStateByTurn.get(turnId);
264268
264436
  this.agent.records.logRecord({
264269
264437
  type: "thinking.heartbeat",
@@ -264272,7 +264440,8 @@ var init_turn = __esmMin((() => {
264272
264440
  attempt: requestState?.attempt ?? 1,
264273
264441
  max_attempts: requestState?.maxAttempts,
264274
264442
  completion_budget: requestState?.completionBudget,
264275
- thinking_effort: requestState?.thinkingEffort
264443
+ thinking_effort: requestState?.thinkingEffort,
264444
+ hidden_thinking_tokens: event.type === "thinking.progress" ? event.cumulativeTokens : void 0
264276
264445
  });
264277
264446
  }
264278
264447
  if (event.type === "step.retrying" && event.completionBudgetBefore !== void 0 && event.completionBudgetAfter !== void 0) this.agent.records.logRecord({
@@ -264295,6 +264464,7 @@ var init_turn = __esmMin((() => {
264295
264464
  case "tool.call":
264296
264465
  case "text.delta":
264297
264466
  case "thinking.delta":
264467
+ case "thinking.progress":
264298
264468
  case "tool.call.delta": {
264299
264469
  const active = this.activeTurn;
264300
264470
  if (active === null || active === "resuming") return;
@@ -342898,6 +343068,7 @@ function detectedUiLocale() {
342898
343068
  const SOURCE_LOCALE = "en";
342899
343069
  const PLACEHOLDER_PATTERN = /\{([A-Za-z][A-Za-z0-9_]*)\}/g;
342900
343070
  const catalogs = {};
343071
+ const missingLocalizedUiTextWarnings = /* @__PURE__ */ new Set();
342901
343072
  let currentUiLocale = SOURCE_LOCALE;
342902
343073
  function registerUiCatalogFragment(fragment) {
342903
343074
  for (const [locale, copy] of Object.entries(fragment)) {
@@ -342928,7 +343099,13 @@ function uiTextFor(locale, key, params = {}) {
342928
343099
  const sourceTemplate = catalogs[SOURCE_LOCALE]?.[key];
342929
343100
  if (sourceTemplate === void 0) throw new Error(`Missing English UI source text for key "${key}".`);
342930
343101
  const localizedTemplate = catalogs[locale]?.[key];
342931
- if (locale !== SOURCE_LOCALE && isUiLocaleAvailable(locale) && localizedTemplate === void 0) throw new Error(`Missing UI text for key "${key}" in released locale "${locale}".`);
343102
+ if (locale !== SOURCE_LOCALE && isUiLocaleAvailable(locale) && localizedTemplate === void 0) {
343103
+ const warningKey = `${locale}:${key}`;
343104
+ if (!missingLocalizedUiTextWarnings.has(warningKey)) {
343105
+ missingLocalizedUiTextWarnings.add(warningKey);
343106
+ log?.warn("Missing localized UI text; using English fallback", { locale, key });
343107
+ }
343108
+ }
342932
343109
  const template = localizedTemplate ?? sourceTemplate;
342933
343110
  validateCatalogPlaceholders(key, sourceTemplate, template);
342934
343111
  return interpolate(key, template, params);
@@ -342954,6 +343131,241 @@ function definedCatalogEntries(copy) {
342954
343131
  return Object.entries(copy).filter((entry) => entry[1] !== void 0);
342955
343132
  }
342956
343133
  //#endregion
343134
+ //#region src/tui/i18n/gated-565-catalog-additions.ts
343135
+ registerUiCatalogFragment({
343136
+ "es": {
343137
+ "media.activity.chain": "Cadena de producción",
343138
+ "media.activity.collapse": "ctrl+o: contraer",
343139
+ "media.activity.jobs": "{count} trabajos multimedia activos",
343140
+ "media.activity.showJobs": "ctrl+o: mostrar trabajos",
343141
+ "media.detail.audio": "{seconds}s de audio",
343142
+ "media.detail.duration": "Duración {duration}",
343143
+ "media.detail.open": "Abrir",
343144
+ "media.detail.playSample": "Reproducir muestra",
343145
+ "media.detail.preview": "Vista previa",
343146
+ "media.detail.queue": "Posición {position}",
343147
+ "media.detail.remaining": "quedan aprox. {duration}",
343148
+ "media.detail.resolution": "{width}x{height}",
343149
+ "media.detail.segment": "Segmento {current} de {total}",
343150
+ "media.detail.waveform": "Forma de onda",
343151
+ "media.kind.dubbing": "Doblaje",
343152
+ "media.kind.image": "Imagen",
343153
+ "media.kind.image-analysis": "Análisis de imagen",
343154
+ "media.kind.lipsync": "Sincronización labial",
343155
+ "media.kind.media": "Multimedia",
343156
+ "media.kind.video": "Vídeo",
343157
+ "media.kind.video-analysis": "Análisis de vídeo",
343158
+ "media.kind.voice": "Voz",
343159
+ "media.phase.accepted": "En cola",
343160
+ "media.phase.analyzing": "Analizando",
343161
+ "media.phase.audio-analysis": "Análisis de audio",
343162
+ "media.phase.checking": "Comprobando estado",
343163
+ "media.phase.exporting": "Exportando",
343164
+ "media.phase.face-detection": "Detección de rostros",
343165
+ "media.phase.face-tracking": "Seguimiento de rostros",
343166
+ "media.phase.generating": "Generando",
343167
+ "media.phase.in-progress": "Procesando",
343168
+ "media.phase.lip-sync-running": "Sincronización labial en curso",
343169
+ "media.phase.pending": "En cola",
343170
+ "media.phase.processing": "Procesando",
343171
+ "media.phase.queued": "En cola",
343172
+ "media.phase.rendering": "Renderizando",
343173
+ "media.phase.running": "Procesando",
343174
+ "media.phase.saving": "Guardando",
343175
+ "media.phase.submitting": "Enviando solicitud",
343176
+ "media.phase.uploading": "Enviando solicitud",
343177
+ "media.phase.upscaling": "Aumentando la resolución",
343178
+ "thinking.activity.coordinates": "{name} coordinando",
343179
+ "thinking.activity.plans": "{name} planificando",
343180
+ "thinking.activity.reads": "{name} leyendo",
343181
+ "thinking.activity.runs": "{name} ejecutando",
343182
+ "thinking.activity.writes": "{name} escribiendo",
343183
+ "thinking.attempt": "intento {attempt}/{maxAttempts}",
343184
+ "thinking.budget": "presupuesto {budget}",
343185
+ "thinking.effort": "esfuerzo {effort}",
343186
+ "thinking.emptyRetry": "Respuesta vacía del modelo; {hint} · presupuesto {before} → {after}",
343187
+ "thinking.finished": "listo {time}",
343188
+ "thinking.heartbeat": "señal del pensamiento oculto hace {seconds}s",
343189
+ "thinking.hiddenTokens": "pensando {count}",
343190
+ "thinking.step": "paso {step}",
343191
+ "thinking.worked": "Trabajó {elapsed}"
343192
+ },
343193
+ "fr": {
343194
+ "media.activity.chain": "Chaîne de production",
343195
+ "media.activity.collapse": "ctrl+o : replier",
343196
+ "media.activity.jobs": "{count} tâches média actives",
343197
+ "media.activity.showJobs": "ctrl+o : afficher les tâches",
343198
+ "media.detail.audio": "{seconds} s d'audio",
343199
+ "media.detail.duration": "Durée {duration}",
343200
+ "media.detail.open": "Ouvrir",
343201
+ "media.detail.playSample": "Écouter l'extrait",
343202
+ "media.detail.preview": "Aperçu",
343203
+ "media.detail.queue": "Rang {position}",
343204
+ "media.detail.remaining": "encore environ {duration}",
343205
+ "media.detail.resolution": "{width}x{height}",
343206
+ "media.detail.segment": "Segment {current} sur {total}",
343207
+ "media.detail.waveform": "Forme d'onde",
343208
+ "media.kind.dubbing": "Doublage",
343209
+ "media.kind.image": "Image",
343210
+ "media.kind.image-analysis": "Analyse d'image",
343211
+ "media.kind.lipsync": "Synchronisation labiale",
343212
+ "media.kind.media": "Médias",
343213
+ "media.kind.video": "Vidéo",
343214
+ "media.kind.video-analysis": "Analyse vidéo",
343215
+ "media.kind.voice": "Voix",
343216
+ "media.phase.accepted": "En file d'attente",
343217
+ "media.phase.analyzing": "Analyse en cours",
343218
+ "media.phase.audio-analysis": "Analyse audio",
343219
+ "media.phase.checking": "Vérification de l'état",
343220
+ "media.phase.exporting": "Export en cours",
343221
+ "media.phase.face-detection": "Détection des visages",
343222
+ "media.phase.face-tracking": "Suivi des visages",
343223
+ "media.phase.generating": "Génération en cours",
343224
+ "media.phase.in-progress": "Traitement en cours",
343225
+ "media.phase.lip-sync-running": "Synchronisation labiale en cours",
343226
+ "media.phase.pending": "En file d'attente",
343227
+ "media.phase.processing": "Traitement en cours",
343228
+ "media.phase.queued": "En file d'attente",
343229
+ "media.phase.rendering": "Rendu en cours",
343230
+ "media.phase.running": "Traitement en cours",
343231
+ "media.phase.saving": "Enregistrement en cours",
343232
+ "media.phase.submitting": "Envoi de la requête",
343233
+ "media.phase.uploading": "Envoi de la requête",
343234
+ "media.phase.upscaling": "Agrandissement en cours",
343235
+ "thinking.activity.coordinates": "{name} coordonne",
343236
+ "thinking.activity.plans": "{name} planifie",
343237
+ "thinking.activity.reads": "{name} lit",
343238
+ "thinking.activity.runs": "{name} exécute",
343239
+ "thinking.activity.writes": "{name} écrit",
343240
+ "thinking.attempt": "tentative {attempt}/{maxAttempts}",
343241
+ "thinking.budget": "budget {budget}",
343242
+ "thinking.effort": "niveau d'effort {effort}",
343243
+ "thinking.emptyRetry": "Réponse vide du modèle ; {hint} · budget {before} → {after}",
343244
+ "thinking.finished": "terminé {time}",
343245
+ "thinking.heartbeat": "signe de vie de la réflexion il y a {seconds} s",
343246
+ "thinking.hiddenTokens": "réflexion {count}",
343247
+ "thinking.step": "étape {step}",
343248
+ "thinking.worked": "A travaillé {elapsed}"
343249
+ },
343250
+ "sv": {
343251
+ "media.activity.chain": "Produktionskedja",
343252
+ "media.activity.collapse": "ctrl+o: fäll ihop",
343253
+ "media.activity.jobs": "{count} aktiva mediejobb",
343254
+ "media.activity.showJobs": "ctrl+o: visa jobb",
343255
+ "media.detail.audio": "{seconds}s ljud",
343256
+ "media.detail.duration": "Längd {duration}",
343257
+ "media.detail.open": "Öppna",
343258
+ "media.detail.playSample": "Spela upp exempel",
343259
+ "media.detail.preview": "Förhandsvisning",
343260
+ "media.detail.queue": "Plats {position}",
343261
+ "media.detail.remaining": "cirka {duration} kvar",
343262
+ "media.detail.resolution": "{width}x{height}",
343263
+ "media.detail.segment": "Segment {current} av {total}",
343264
+ "media.detail.waveform": "Vågform",
343265
+ "media.kind.dubbing": "Dubbning",
343266
+ "media.kind.image": "Bild",
343267
+ "media.kind.image-analysis": "Bildanalys",
343268
+ "media.kind.lipsync": "Läppsynk",
343269
+ "media.kind.media": "Media",
343270
+ "media.kind.video": "Video",
343271
+ "media.kind.video-analysis": "Videoanalys",
343272
+ "media.kind.voice": "Röst",
343273
+ "media.phase.accepted": "I kö",
343274
+ "media.phase.analyzing": "Analyserar",
343275
+ "media.phase.audio-analysis": "Ljudanalys",
343276
+ "media.phase.checking": "Kontrollerar status",
343277
+ "media.phase.exporting": "Exporterar",
343278
+ "media.phase.face-detection": "Ansiktsdetektering",
343279
+ "media.phase.face-tracking": "Ansiktsspårning",
343280
+ "media.phase.generating": "Genererar",
343281
+ "media.phase.in-progress": "Bearbetar",
343282
+ "media.phase.lip-sync-running": "Läppsynk pågår",
343283
+ "media.phase.pending": "I kö",
343284
+ "media.phase.processing": "Bearbetar",
343285
+ "media.phase.queued": "I kö",
343286
+ "media.phase.rendering": "Renderar",
343287
+ "media.phase.running": "Bearbetar",
343288
+ "media.phase.saving": "Sparar",
343289
+ "media.phase.submitting": "Skickar begäran",
343290
+ "media.phase.uploading": "Skickar begäran",
343291
+ "media.phase.upscaling": "Skalar upp",
343292
+ "thinking.activity.coordinates": "{name} samordnar",
343293
+ "thinking.activity.plans": "{name} planerar",
343294
+ "thinking.activity.reads": "{name} läser",
343295
+ "thinking.activity.runs": "{name} kör",
343296
+ "thinking.activity.writes": "{name} skriver",
343297
+ "thinking.attempt": "försök {attempt}/{maxAttempts}",
343298
+ "thinking.budget": "budget {budget}",
343299
+ "thinking.effort": "insats {effort}",
343300
+ "thinking.emptyRetry": "Tomt svar från modellen; {hint} · budget {before} → {after}",
343301
+ "thinking.finished": "klar {time}",
343302
+ "thinking.heartbeat": "livstecken från dold tanke för {seconds}s sedan",
343303
+ "thinking.hiddenTokens": "tänker {count}",
343304
+ "thinking.step": "steg {step}",
343305
+ "thinking.worked": "Arbetade {elapsed}"
343306
+ },
343307
+ "cs": {
343308
+ "approval.choice.editArguments": "Upravit argumenty (JSON)",
343309
+ "approval.hint.editArguments": "Zadejte kompletní náhradní objekt JSON · ↵ odeslat.",
343310
+ "approval.transcript.edited": "Argumenty upraveny",
343311
+ "media.activity.chain": "Produkční řetězec",
343312
+ "media.activity.collapse": "ctrl+o: sbalit",
343313
+ "media.activity.jobs": "Aktivní mediální úlohy: {count}",
343314
+ "media.activity.showJobs": "ctrl+o: zobrazit úlohy",
343315
+ "media.detail.audio": "{seconds}s zvuku",
343316
+ "media.detail.duration": "Délka {duration}",
343317
+ "media.detail.open": "Otevřít",
343318
+ "media.detail.playSample": "Přehrát ukázku",
343319
+ "media.detail.preview": "Náhled",
343320
+ "media.detail.queue": "Pozice {position}",
343321
+ "media.detail.remaining": "zbývá přibližně {duration}",
343322
+ "media.detail.resolution": "{width}x{height}",
343323
+ "media.detail.segment": "Segment {current} z {total}",
343324
+ "media.detail.waveform": "Vlnový průběh",
343325
+ "media.kind.dubbing": "Dabing",
343326
+ "media.kind.image": "Obrázek",
343327
+ "media.kind.image-analysis": "Analýza obrázku",
343328
+ "media.kind.lipsync": "Synchronizace rtů",
343329
+ "media.kind.media": "Média",
343330
+ "media.kind.video": "Video",
343331
+ "media.kind.video-analysis": "Analýza videa",
343332
+ "media.kind.voice": "Hlas",
343333
+ "media.phase.accepted": "Ve frontě",
343334
+ "media.phase.analyzing": "Analyzuje se",
343335
+ "media.phase.audio-analysis": "Analýza zvuku",
343336
+ "media.phase.checking": "Kontrola stavu",
343337
+ "media.phase.exporting": "Exportuje se",
343338
+ "media.phase.face-detection": "Detekce obličejů",
343339
+ "media.phase.face-tracking": "Sledování obličejů",
343340
+ "media.phase.generating": "Generuje se",
343341
+ "media.phase.in-progress": "Zpracovává se",
343342
+ "media.phase.lip-sync-running": "Probíhá synchronizace rtů",
343343
+ "media.phase.pending": "Ve frontě",
343344
+ "media.phase.processing": "Zpracovává se",
343345
+ "media.phase.queued": "Ve frontě",
343346
+ "media.phase.rendering": "Renderuje se",
343347
+ "media.phase.running": "Zpracovává se",
343348
+ "media.phase.saving": "Ukládá se",
343349
+ "media.phase.submitting": "Odesílá se požadavek",
343350
+ "media.phase.uploading": "Odesílá se požadavek",
343351
+ "media.phase.upscaling": "Zvyšuje se rozlišení",
343352
+ "thinking.activity.coordinates": "{name} koordinuje",
343353
+ "thinking.activity.plans": "{name} plánuje",
343354
+ "thinking.activity.reads": "{name} čte",
343355
+ "thinking.activity.runs": "{name} spouští",
343356
+ "thinking.activity.writes": "{name} píše",
343357
+ "thinking.attempt": "pokus {attempt}/{maxAttempts}",
343358
+ "thinking.budget": "rozpočet {budget}",
343359
+ "thinking.effort": "úsilí {effort}",
343360
+ "thinking.emptyRetry": "Prázdná odpověď modelu; {hint} · rozpočet {before} → {after}",
343361
+ "thinking.finished": "hotovo {time}",
343362
+ "thinking.heartbeat": "signál skrytého uvažování před {seconds}s",
343363
+ "thinking.hiddenTokens": "uvažuje {count}",
343364
+ "thinking.step": "krok {step}",
343365
+ "thinking.worked": "Pracováno {elapsed}"
343366
+ }
343367
+ });
343368
+ //#endregion
342957
343369
  //#region src/tui/commands/auth.copy.ts
342958
343370
  registerUiCatalogFragment({
342959
343371
  en: {
@@ -493792,12 +494204,18 @@ var PluginCommandComponent = class extends Container {
493792
494204
  registerUiCatalogFragment({
493793
494205
  en: {
493794
494206
  "thinking.label": "{name} thinking",
494207
+ "thinking.activity.reads": "{name} reading",
494208
+ "thinking.activity.writes": "{name} writing",
494209
+ "thinking.activity.runs": "{name} running",
494210
+ "thinking.activity.coordinates": "{name} coordinating",
494211
+ "thinking.activity.plans": "{name} planning",
493795
494212
  "thinking.aborted": "aborted",
493796
494213
  "thinking.step": "step {step}",
493797
494214
  "thinking.effort": "effort {effort}",
493798
494215
  "thinking.attempt": "attempt {attempt}/{maxAttempts}",
493799
494216
  "thinking.budget": "budget {budget}",
493800
494217
  "thinking.heartbeat": "hidden-thought heartbeat {seconds}s ago",
494218
+ "thinking.hiddenTokens": "thinking {count}",
493801
494219
  "thinking.worked": "Worked {elapsed}",
493802
494220
  "thinking.finished": "done {time}",
493803
494221
  "thinking.emptyRetry": "Empty model response; {hint} · budget {before} → {after}",
@@ -493806,12 +494224,18 @@ registerUiCatalogFragment({
493806
494224
  },
493807
494225
  de: {
493808
494226
  "thinking.label": "{name} denkt",
494227
+ "thinking.activity.reads": "{name} liest",
494228
+ "thinking.activity.writes": "{name} schreibt",
494229
+ "thinking.activity.runs": "{name} führt aus",
494230
+ "thinking.activity.coordinates": "{name} koordiniert",
494231
+ "thinking.activity.plans": "{name} plant",
493809
494232
  "thinking.aborted": "abgebrochen",
493810
494233
  "thinking.step": "Schritt {step}",
493811
494234
  "thinking.effort": "Effort {effort}",
493812
494235
  "thinking.attempt": "Versuch {attempt}/{maxAttempts}",
493813
494236
  "thinking.budget": "Budget {budget}",
493814
494237
  "thinking.heartbeat": "Verdecktes Denken läuft · letzter Takt vor {seconds}s",
494238
+ "thinking.hiddenTokens": "denkt {count}",
493815
494239
  "thinking.worked": "Gearbeitet {elapsed}",
493816
494240
  "thinking.finished": "fertig {time}",
493817
494241
  "thinking.emptyRetry": "Leere Modellantwort; {hint} · Budget {before} → {after}",
@@ -493855,6 +494279,7 @@ function formatLiveStartedAt(startedAtMs) {
493855
494279
  const minute = String(startedAt.getMinutes()).padStart(2, "0");
493856
494280
  return `${day}.${month}. · ${hour}:${minute}`;
493857
494281
  }
494282
+ var { ThinkingActivityRotator, inferThinkingActivityGroup } = createRequire(import.meta.url)("./bin/thinking-activity-status-policy.cjs");
493858
494283
  var ThinkingComponent = class {
493859
494284
  text;
493860
494285
  showMarker;
@@ -493868,13 +494293,17 @@ var ThinkingComponent = class {
493868
494293
  thinkElapsedMs = 0;
493869
494294
  thinkAborted = false;
493870
494295
  estimatedOutputTokens = 0;
494296
+ totalTokenCount = 0;
493871
494297
  step;
493872
494298
  thinkingEffort;
493873
494299
  attempt = 1;
493874
494300
  maxAttempts = 1;
493875
494301
  completionBudget;
493876
494302
  lastHeartbeatAtMs;
494303
+ hiddenThinkingTokens = 0;
493877
494304
  activeToolName;
494305
+ activityGroup = "Thinking";
494306
+ activityRotator = new ThinkingActivityRotator();
493878
494307
  finishedAtMs;
493879
494308
  textComponent;
493880
494309
  renderCache;
@@ -493909,21 +494338,24 @@ var ThinkingComponent = class {
493909
494338
  }
493910
494339
  setLiveMetrics(metrics) {
493911
494340
  if (this.mode === "live" && !this.thinkAborted && metrics.startedAtMs !== void 0) this.thinkStartMs = metrics.startedAtMs;
493912
- const before = JSON.stringify([this.estimatedOutputTokens, this.step, this.thinkingEffort, this.attempt, this.maxAttempts, this.completionBudget, this.lastHeartbeatAtMs, this.activeToolName]);
494341
+ const before = JSON.stringify([this.estimatedOutputTokens, this.totalTokenCount, this.hiddenThinkingTokens, this.step, this.thinkingEffort, this.attempt, this.maxAttempts, this.completionBudget, this.lastHeartbeatAtMs, this.activeToolName, this.activityGroup]);
493913
494342
  this.estimatedOutputTokens = metrics.estimatedOutputTokens;
493914
494343
  this.applyLiveMetrics(metrics);
493915
- const after = JSON.stringify([this.estimatedOutputTokens, this.step, this.thinkingEffort, this.attempt, this.maxAttempts, this.completionBudget, this.lastHeartbeatAtMs, this.activeToolName]);
494344
+ const after = JSON.stringify([this.estimatedOutputTokens, this.totalTokenCount, this.hiddenThinkingTokens, this.step, this.thinkingEffort, this.attempt, this.maxAttempts, this.completionBudget, this.lastHeartbeatAtMs, this.activeToolName, this.activityGroup]);
493916
494345
  if (before === after) return;
493917
494346
  this.markRenderDirty();
493918
494347
  }
493919
494348
  applyLiveMetrics(metrics) {
494349
+ this.totalTokenCount = metrics.totalTokenCount ?? 0;
493920
494350
  this.step = metrics.step;
493921
494351
  this.thinkingEffort = metrics.thinkingEffort;
493922
494352
  this.attempt = metrics.attempt ?? 1;
493923
494353
  this.maxAttempts = metrics.maxAttempts ?? 1;
493924
494354
  this.completionBudget = metrics.completionBudget;
493925
494355
  this.lastHeartbeatAtMs = metrics.lastHeartbeatAtMs;
494356
+ this.hiddenThinkingTokens = metrics.hiddenThinkingTokens ?? 0;
493926
494357
  this.activeToolName = metrics.activeToolName;
494358
+ this.activityGroup = metrics.activityGroup ?? "Thinking";
493927
494359
  }
493928
494360
  styled(text) {
493929
494361
  return currentTheme.italicFg("textDim", text);
@@ -493957,26 +494389,29 @@ var ThinkingComponent = class {
493957
494389
  const startedAt = formatLiveStartedAt(this.thinkStartMs ?? Date.now());
493958
494390
  const roundedTokenCount = Math.max(0, Math.round(this.estimatedOutputTokens));
493959
494391
  const tokenCount = formatLiveTokenCount(roundedTokenCount);
493960
- const abortMark = this.thinkAborted ? ` (${uiText("thinking.aborted")})` : "";
493961
- const tokenKey = roundedTokenCount === 1 ? "thinking.tokens.one" : "thinking.tokens.other";
493962
- const thinkingLabel = uiText("thinking.label", { name: this.persona });
493963
- const details = [];
493964
- if (this.step !== void 0) details.push(uiText("thinking.step", { step: this.step }));
493965
- if (this.thinkingEffort !== void 0) details.push(uiText("thinking.effort", { effort: this.thinkingEffort }));
493966
- if (this.attempt > 1 || this.maxAttempts > 1) details.push(uiText("thinking.attempt", { attempt: this.attempt, maxAttempts: this.maxAttempts }));
493967
- if (this.completionBudget !== void 0) details.push(uiText("thinking.budget", { budget: this.completionBudget.toLocaleString(locale) }));
493968
- if (this.lastHeartbeatAtMs !== void 0) details.push(uiText("thinking.heartbeat", { seconds: Math.max(0, Math.floor((Date.now() - this.lastHeartbeatAtMs) / 1e3)) }));
494392
+ const abortMark = this.thinkAborted ? " (aborted)" : "";
494393
+ const thinkingLabel = this.activityRotator.resolve(this.activityGroup, Date.now());
494394
+ const details = [`↓ ~${tokenCount} ${roundedTokenCount === 1 ? "token" : "tokens"}`];
494395
+ if (this.hiddenThinkingTokens > 0) details.push(`thinking ${formatLiveTokenCount(this.hiddenThinkingTokens)}`);
494396
+ if (this.totalTokenCount > 0) details.push(`total ${formatLiveTokenCount(this.totalTokenCount)}`);
494397
+ if (this.thinkingEffort !== void 0) details.push(`thinking with ${this.thinkingEffort} effort`);
494398
+ if (this.step !== void 0) details.push(`step ${this.step}`);
494399
+ if (this.attempt > 1 || this.maxAttempts > 1) details.push(`attempt ${this.attempt}/${this.maxAttempts}`);
494400
+ if (this.completionBudget !== void 0) details.push(`budget ${this.completionBudget.toLocaleString(locale)}`);
494401
+ if (this.lastHeartbeatAtMs !== void 0) details.push(`last hidden-thought tick ${Math.max(0, Math.floor((Date.now() - this.lastHeartbeatAtMs) / 1e3))}s ago`);
493969
494402
  if (this.activeToolName !== void 0) details.push(this.activeToolName);
493970
- const detailText = details.length === 0 ? "" : ` · ${details.join(" · ")}`;
493971
- const fullLabel = `${thinkingLabel}… (${elapsed} · ~${uiText(tokenKey, { count: tokenCount })}${detailText} · ${startedAt})${abortMark}`;
493972
- const compactLabel = `${thinkingLabel}… (${elapsed} · ↓${tokenCount}${this.step === void 0 ? "" : ` · #${this.step}`} · ${startedAt})${abortMark}`;
494403
+ const fullLabel = `${thinkingLabel}… (${elapsed} · ${details.join(" · ")} · ${startedAt})${abortMark}`;
494404
+ const compactHiddenTokens = this.hiddenThinkingTokens > 0 ? ` · thinking ${formatLiveTokenCount(this.hiddenThinkingTokens)}` : "";
494405
+ const compactTotalTokens = this.totalTokenCount > 0 ? ` · total ${formatLiveTokenCount(this.totalTokenCount)}` : "";
494406
+ const compactEffort = this.thinkingEffort === void 0 ? "" : ` · ${this.thinkingEffort} effort`;
494407
+ const compactLabel = `${thinkingLabel}… (${elapsed} · ↓ ${tokenCount} tokens${compactHiddenTokens}${compactTotalTokens}${compactEffort}${this.step === void 0 ? "" : ` · #${this.step}`} · ${startedAt})${abortMark}`;
493973
494408
  const metricsOnly = `(${elapsed} · ${startedAt})${abortMark}`;
493974
494409
  const availableWidth = Math.max(1, width - visibleWidth(spinner));
493975
494410
  const label = visibleWidth(fullLabel) <= availableWidth ? fullLabel : visibleWidth(compactLabel) <= availableWidth ? compactLabel : metricsOnly;
493976
494411
  rendered = ["", spinner + currentTheme.fg("textDim", truncateToWidth(label, availableWidth))];
493977
494412
  } else if (this.thinkElapsedMs > 0) {
493978
494413
  const finishedAt = new Date(this.finishedAtMs ?? Date.now()).toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit" });
493979
- const finalLabel = `${uiText("thinking.worked", { elapsed: formatLiveElapsed(this.formatElapsedSeconds()) })} · ${uiText("thinking.finished", { time: finishedAt })}`;
494414
+ const finalLabel = `Worked for ${formatLiveElapsed(this.formatElapsedSeconds())} · done ${finishedAt}`;
493980
494415
  rendered = ["", currentTheme.fg("textDim", truncateToWidth(finalLabel, Math.max(1, width)))];
493981
494416
  } else rendered = [""];
493982
494417
  if (isRenderCacheEnabled()) this.renderCache = {
@@ -510550,6 +510985,9 @@ var SessionEventHandler = class {
510550
510985
  case "thinking.delta":
510551
510986
  this.handleThinkingDelta(event);
510552
510987
  break;
510988
+ case "thinking.progress":
510989
+ this.handleThinkingProgress(event);
510990
+ break;
510553
510991
  case "tool.call.started":
510554
510992
  this.handleToolCall(event);
510555
510993
  break;
@@ -510717,7 +511155,10 @@ var SessionEventHandler = class {
510717
511155
  this.clearModelRetryHint();
510718
511156
  this.lastStepFinishReason = event.finishReason;
510719
511157
  this.host.streamingUI.flushNow();
510720
- if (event.usage !== void 0) this.currentTurnTokenCount = (this.currentTurnTokenCount ?? 0) + totalTokenUsage(event.usage);
511158
+ if (event.usage !== void 0) {
511159
+ this.currentTurnTokenCount = (this.currentTurnTokenCount ?? 0) + totalTokenUsage(event.usage);
511160
+ this.host.streamingUI.noteTurnTokenUsage(this.currentTurnTokenCount);
511161
+ }
510721
511162
  this.maybeShowDebugTiming(event);
510722
511163
  if (event.providerFinishReason === "filtered") {
510723
511164
  this.host.showNotice(uiText("sessionEvent.filter.title"), uiText("sessionEvent.filter.detail", { reason: event.rawFinishReason ?? "content_filter" }));
@@ -510807,8 +511248,17 @@ var SessionEventHandler = class {
510807
511248
  }
510808
511249
  handleThinkingDelta(event) {
510809
511250
  const { state, streamingUI } = this.host;
510810
- if (event.delta.length === 0 && !streamingUI.hasThinkingDraft()) return;
510811
- if (event.delta.trim().length === 0) streamingUI.noteThinkingHeartbeat();
511251
+ if (event.delta.trim().length === 0) {
511252
+ streamingUI.noteThinkingHeartbeat();
511253
+ this.turnWatchdog.recordProgress();
511254
+ this.clearModelRetryHint();
511255
+ this.host.patchLivePane({ mode: "idle" });
511256
+ if (state.appState.streamingPhase !== "thinking") this.host.setAppState({
511257
+ streamingPhase: "thinking",
511258
+ streamingStartTime: Date.now()
511259
+ });
511260
+ return;
511261
+ }
510812
511262
  if (event.delta.length > 0) this.turnWatchdog.recordProgress();
510813
511263
  if (event.delta.length > 0) this.clearModelRetryHint();
510814
511264
  streamingUI.appendThinkingDelta(event.delta);
@@ -510819,9 +511269,20 @@ var SessionEventHandler = class {
510819
511269
  });
510820
511270
  streamingUI.scheduleFlush();
510821
511271
  }
511272
+ handleThinkingProgress(event) {
511273
+ const { state, streamingUI } = this.host;
511274
+ this.turnWatchdog.recordProgress();
511275
+ this.clearModelRetryHint();
511276
+ streamingUI.noteThinkingProgress(event.cumulativeTokens);
511277
+ this.host.patchLivePane({ mode: "idle" });
511278
+ if (state.appState.streamingPhase !== "thinking") this.host.setAppState({
511279
+ streamingPhase: "thinking",
511280
+ streamingStartTime: Date.now()
511281
+ });
511282
+ }
510822
511283
  handleAssistantDelta(event) {
510823
511284
  const { state, streamingUI } = this.host;
510824
- if (streamingUI.hasThinkingDraft()) streamingUI.flushThinkingToTranscript("idle");
511285
+ if (streamingUI.hasThinkingDraft() || streamingUI.hasActiveThinkingComponent()) streamingUI.flushThinkingToTranscript("idle");
510825
511286
  if (event.delta.trim().length > 0) {
510826
511287
  this.turnWatchdog.recordProgress();
510827
511288
  this.clearModelRetryHint();
@@ -510843,7 +511304,7 @@ var SessionEventHandler = class {
510843
511304
  handleHookResult(event) {
510844
511305
  if (!shouldDisplayHookResult(event)) return;
510845
511306
  this.host.streamingUI.flushNow();
510846
- if (this.host.streamingUI.hasThinkingDraft()) this.host.streamingUI.flushThinkingToTranscript("idle");
511307
+ if (this.host.streamingUI.hasThinkingDraft() || this.host.streamingUI.hasActiveThinkingComponent()) this.host.streamingUI.flushThinkingToTranscript("idle");
510847
511308
  this.host.streamingUI.finalizeAssistantStream();
510848
511309
  if (event.content.trim().length > 0) {
510849
511310
  this.currentTurnHasAssistantText = true;
@@ -513853,6 +514314,8 @@ var StreamingUIController = class {
513853
514314
  _liveTurnStartedAtMs = void 0;
513854
514315
  _liveStepStartedAtMs = void 0;
513855
514316
  _liveThinkingHeartbeatAtMs = void 0;
514317
+ _liveHiddenThinkingTokens = 0;
514318
+ _liveTurnTokenCount = 0;
513856
514319
  _liveStepRequest = {};
513857
514320
  _liveOutputTokens = new LiveOutputTokenCounter();
513858
514321
  _countedToolCallIds = /* @__PURE__ */ new Set();
@@ -513888,6 +514351,7 @@ var StreamingUIController = class {
513888
514351
  this.setStep(event.step);
513889
514352
  this._liveStepStartedAtMs = Date.now();
513890
514353
  this._liveThinkingHeartbeatAtMs = void 0;
514354
+ this._liveHiddenThinkingTokens = 0;
513891
514355
  this._liveOutputTokens.reset();
513892
514356
  this._countedToolCallIds.clear();
513893
514357
  this._liveStepRequest = {
@@ -513900,6 +514364,7 @@ var StreamingUIController = class {
513900
514364
  noteStepRetry(event) {
513901
514365
  this._liveStepStartedAtMs = Date.now();
513902
514366
  this._liveThinkingHeartbeatAtMs = void 0;
514367
+ this._liveHiddenThinkingTokens = 0;
513903
514368
  this._liveStepRequest = {
513904
514369
  ...this._liveStepRequest,
513905
514370
  attempt: event.nextAttempt,
@@ -513909,6 +514374,18 @@ var StreamingUIController = class {
513909
514374
  }
513910
514375
  noteThinkingHeartbeat() {
513911
514376
  this._liveThinkingHeartbeatAtMs = Date.now();
514377
+ this.onThinkingUpdate(this._thinkingDraft, true);
514378
+ }
514379
+ noteThinkingProgress(cumulativeTokens) {
514380
+ if (!Number.isFinite(cumulativeTokens) || cumulativeTokens < 0) return;
514381
+ this._liveThinkingHeartbeatAtMs = Date.now();
514382
+ this._liveHiddenThinkingTokens = Math.max(this._liveHiddenThinkingTokens, Math.floor(cumulativeTokens));
514383
+ this.onThinkingUpdate(this._thinkingDraft, true);
514384
+ }
514385
+ noteTurnTokenUsage(cumulativeTokens) {
514386
+ if (!Number.isFinite(cumulativeTokens) || cumulativeTokens < 0) return;
514387
+ this._liveTurnTokenCount = Math.max(this._liveTurnTokenCount, Math.floor(cumulativeTokens));
514388
+ this.onThinkingUpdate(this._thinkingDraft, true);
513912
514389
  }
513913
514390
  setRemoteTurnActivity(activity) {
513914
514391
  const previous = this._remoteTurnActivity;
@@ -513940,23 +514417,29 @@ var StreamingUIController = class {
513940
514417
  this._liveTurnStartedAtMs = Date.now();
513941
514418
  this._liveStepStartedAtMs = void 0;
513942
514419
  this._liveThinkingHeartbeatAtMs = void 0;
514420
+ this._liveHiddenThinkingTokens = 0;
514421
+ this._liveTurnTokenCount = 0;
513943
514422
  this._liveStepRequest = {};
513944
514423
  this._liveOutputTokens.reset();
513945
514424
  this._countedToolCallIds.clear();
513946
514425
  this.lastFlushAt = void 0;
513947
514426
  }
513948
514427
  getLiveActivityMetrics() {
513949
- const activeToolName = [...this._activeToolCalls.values()].at(-1)?.name ?? [...this._streamingToolCallArguments.values()].at(-1)?.name;
514428
+ const activeTool = [...this._activeToolCalls.values()].at(-1) ?? [...this._streamingToolCallArguments.values()].at(-1);
514429
+ const activeToolName = activeTool?.name;
513950
514430
  return {
513951
514431
  startedAtMs: this._liveStepStartedAtMs ?? this._liveTurnStartedAtMs,
513952
514432
  estimatedOutputTokens: this._liveOutputTokens.estimatedOutputTokens(),
514433
+ totalTokenCount: this._liveTurnTokenCount,
513953
514434
  step: this._currentStep,
513954
514435
  thinkingEffort: this._liveStepRequest.thinkingEffort,
513955
514436
  completionBudget: this._liveStepRequest.completionBudget,
513956
514437
  attempt: this._liveStepRequest.attempt ?? 1,
513957
514438
  maxAttempts: this._liveStepRequest.maxAttempts ?? 1,
513958
514439
  lastHeartbeatAtMs: this._liveThinkingHeartbeatAtMs,
513959
- activeToolName
514440
+ hiddenThinkingTokens: this._liveHiddenThinkingTokens,
514441
+ activeToolName,
514442
+ activityGroup: inferThinkingActivityGroup(activeTool, { retrying: (this._liveStepRequest.attempt ?? 1) > 1 })
513960
514443
  };
513961
514444
  }
513962
514445
  recordLiveOutput(fragment) {
@@ -513999,6 +514482,7 @@ var StreamingUIController = class {
513999
514482
  this._liveTurnStartedAtMs = void 0;
514000
514483
  this._liveStepStartedAtMs = void 0;
514001
514484
  this._liveThinkingHeartbeatAtMs = void 0;
514485
+ this._liveHiddenThinkingTokens = 0;
514002
514486
  this._liveStepRequest = {};
514003
514487
  this._liveOutputTokens.reset();
514004
514488
  this._countedToolCallIds.clear();
@@ -514456,8 +514940,8 @@ var StreamingUIController = class {
514456
514940
  }
514457
514941
  this._streamingBlock = null;
514458
514942
  }
514459
- onThinkingUpdate(fullText) {
514460
- if (fullText.length === 0 && this._activeThinkingComponent === void 0) return;
514943
+ onThinkingUpdate(fullText, forceLiveStatus = false) {
514944
+ if (fullText.length === 0 && this._activeThinkingComponent === void 0 && !forceLiveStatus) return;
514461
514945
  const { state } = this.host;
514462
514946
  if (this._activeThinkingComponent === void 0) {
514463
514947
  this._pendingAgentGroup = null;
@@ -514469,12 +514953,14 @@ var StreamingUIController = class {
514469
514953
  this._activeThinkingComponent.setText(fullText);
514470
514954
  this._activeThinkingComponent.setLiveMetrics(this.getLiveActivityMetrics());
514471
514955
  }
514956
+ this.host.updateActivityPane();
514472
514957
  state.ui.requestRender();
514473
514958
  }
514474
514959
  onThinkingEnd() {
514475
514960
  if (this._activeThinkingComponent === void 0) return;
514476
514961
  this._activeThinkingComponent.finalize();
514477
514962
  this._activeThinkingComponent = void 0;
514963
+ this.host.updateActivityPane();
514478
514964
  this.host.state.ui.requestRender();
514479
514965
  this.host.mergeCurrentTurnSteps();
514480
514966
  }
@@ -519222,6 +519708,7 @@ var BlunTUI = class {
519222
519708
  async start() {
519223
519709
  this.registerSignalHandlers();
519224
519710
  this.startupWorkspaceSelectionPending = !(this.options.startup.sessionFlag !== void 0 || this.options.startup.continueLast);
519711
+ this.startTelegramChannel();
519225
519712
  try {
519226
519713
  const shouldReplayHistory = await this.initMainTui();
519227
519714
  this.startEventLoop();
@@ -522084,6 +522571,7 @@ var BlunTUI = class {
522084
522571
  this.state.ui.requestRender();
522085
522572
  }
522086
522573
  resolveActivityPaneMode() {
522574
+ if (this.streamingUI.hasActiveThinkingComponent()) return "hidden";
522087
522575
  if (this.state.activeDialog === "session-picker") return "hidden";
522088
522576
  if (this.state.livePane.pendingApproval !== null) return "hidden";
522089
522577
  if (this.state.appState.isCompacting) return "hidden";
@@ -522753,6 +523241,7 @@ async function runShell(opts, version) {
522753
523241
  });
522754
523242
  try {
522755
523243
  log.error("uncaughtException, restoring terminal and exiting", { error: String(error) });
523244
+ getRootInternal().flushSync();
522756
523245
  } catch {}
522757
523246
  emergencyExit(1);
522758
523247
  };
@@ -522764,6 +523253,7 @@ async function runShell(opts, version) {
522764
523253
  });
522765
523254
  try {
522766
523255
  log.error("unhandledRejection, restoring terminal and exiting", { reason: String(reason) });
523256
+ getRootInternal().flushSync();
522767
523257
  } catch {}
522768
523258
  emergencyExit(1);
522769
523259
  };