blun-king-cli 9.1.564 → 9.1.566

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 (88) hide show
  1. package/LIESMICH.txt +2 -2
  2. package/README.md +1 -1
  3. package/agent-spine-plugin/.claude-plugin/marketplace.json +20 -20
  4. package/agent-spine-plugin/.claude-plugin/plugin.json +14 -14
  5. package/agent-spine-plugin/.codex-plugin/plugin.json +34 -34
  6. package/agent-spine-plugin/.mcp.json +8 -8
  7. package/agent-spine-plugin/CONTRIBUTING.md +52 -0
  8. package/agent-spine-plugin/LICENSE +186 -186
  9. package/agent-spine-plugin/README.md +406 -0
  10. package/agent-spine-plugin/SECURITY.md +47 -0
  11. package/agent-spine-plugin/assets/agentspine-banner.svg +32 -32
  12. package/agent-spine-plugin/bin/agentspine-mcp.js +4 -4
  13. package/agent-spine-plugin/bin/agentspine.js +7 -7
  14. package/agent-spine-plugin/blun.plugin.json +33 -33
  15. package/agent-spine-plugin/hooks/codex.json +47 -47
  16. package/agent-spine-plugin/hooks/hooks.json +106 -106
  17. package/agent-spine-plugin/hooks/version.json +5 -5
  18. package/agent-spine-plugin/package.json +69 -69
  19. package/agent-spine-plugin/scripts/check-hosts.js +199 -199
  20. package/agent-spine-plugin/skill/SKILL.md +76 -76
  21. package/agent-spine-plugin/skills/agent-spine/SKILL.md +85 -85
  22. package/agent-spine-plugin/src/cli.js +1488 -1442
  23. package/agent-spine-plugin/src/hook.js +882 -861
  24. package/agent-spine-plugin/src/index.js +94 -93
  25. package/agent-spine-plugin/src/lib/acceptance.js +333 -333
  26. package/agent-spine-plugin/src/lib/attention.js +755 -755
  27. package/agent-spine-plugin/src/lib/audit.js +351 -342
  28. package/agent-spine-plugin/src/lib/authentication.js +515 -515
  29. package/agent-spine-plugin/src/lib/briefing.js +317 -317
  30. package/agent-spine-plugin/src/lib/catalog.js +167 -167
  31. package/agent-spine-plugin/src/lib/channel-runtime.js +665 -665
  32. package/agent-spine-plugin/src/lib/context.js +154 -154
  33. package/agent-spine-plugin/src/lib/continuity.js +338 -338
  34. package/agent-spine-plugin/src/lib/coordination.js +577 -577
  35. package/agent-spine-plugin/src/lib/documents.js +217 -217
  36. package/agent-spine-plugin/src/lib/feed-transport.js +499 -499
  37. package/agent-spine-plugin/src/lib/filesystem-retry.js +32 -32
  38. package/agent-spine-plugin/src/lib/gateway-runtime.js +1623 -760
  39. package/agent-spine-plugin/src/lib/graph.js +337 -337
  40. package/agent-spine-plugin/src/lib/hook-audit.js +29 -29
  41. package/agent-spine-plugin/src/lib/https-transport.js +392 -392
  42. package/agent-spine-plugin/src/lib/indexed-memory-offline.js +40 -40
  43. package/agent-spine-plugin/src/lib/indexed-memory.js +281 -281
  44. package/agent-spine-plugin/src/lib/learning.js +6923 -6466
  45. package/agent-spine-plugin/src/lib/object-transport.js +206 -206
  46. package/agent-spine-plugin/src/lib/owned-file-lock.js +143 -143
  47. package/agent-spine-plugin/src/lib/paths.js +109 -109
  48. package/agent-spine-plugin/src/lib/peer-transport.js +283 -283
  49. package/agent-spine-plugin/src/lib/persona-runtime.js +581 -581
  50. package/agent-spine-plugin/src/lib/preflight.js +702 -702
  51. package/agent-spine-plugin/src/lib/runtime.js +13 -13
  52. package/agent-spine-plugin/src/lib/selfstarter.js +911 -866
  53. package/agent-spine-plugin/src/lib/sharing.js +969 -969
  54. package/agent-spine-plugin/src/lib/source-roots.js +530 -498
  55. package/agent-spine-plugin/src/lib/sqlite-transport.js +501 -501
  56. package/agent-spine-plugin/src/lib/telegram-adapter.js +119 -119
  57. package/agent-spine-plugin/src/lib/voice-runtime.js +39 -39
  58. package/agent-spine-plugin/src/mcp.js +597 -572
  59. package/agent-spine-plugin/src/version.js +1 -1
  60. package/agent-spine-plugin/src/worker.js +210 -195
  61. package/bin/active-steer-priority-policy.cjs +24 -0
  62. package/bin/launcher-runtime.js +8 -1
  63. package/bin/mnemo-tool-agent-policy.cjs +22 -0
  64. package/bin/native-runtime-cache.cjs +76 -0
  65. package/bin/thinking-activity-status-policy.cjs +132 -0
  66. package/bin/thinking-only-guard.cjs +75 -0
  67. package/bin/tool-call-loop-policy.cjs +53 -0
  68. package/bin/turn-thinking-policy.cjs +25 -1
  69. package/blun.mjs +556 -63
  70. package/package.json +4 -1
  71. package/standard-skills/translate-native/LICENSE +21 -21
  72. package/standard-skills/translate-native/references/evaluation-protocol.md +95 -95
  73. package/standard-skills/translate-native/references/native-orthography.md +79 -79
  74. package/standard-skills/translate-native/references/native-translation-standard.md +94 -94
  75. package/standard-skills/translate-native/references/structured-content.md +72 -72
  76. package/standard-skills/translate-native/references/translationese-review.md +77 -77
  77. package/standard-skills/translate-native/scripts/blun_language_guard.py +697 -697
  78. package/standard-skills/translate-native/scripts/check_diacritics.py +353 -353
  79. package/standard-skills/translate-native/scripts/guard_service_client.py +264 -264
  80. package/standard-skills/translate-native/scripts/language_gateway.py +62 -62
  81. package/standard-skills/translate-native/scripts/language_quality.py +377 -377
  82. package/standard-skills/translate-native/scripts/pre_output_guard.py +64 -64
  83. package/standard-skills/translate-native/scripts/translation_guard.py +916 -916
  84. package/standard-tools/language-guard/blun_language_guard.py +697 -697
  85. package/standard-tools/language-guard/check_diacritics.py +353 -353
  86. package/standard-tools/language-guard/guard_service_client.py +264 -264
  87. package/standard-tools/language-guard/language_quality.py +377 -377
  88. package/standard-tools/language-guard/translation_guard.py +916 -916
package/blun.mjs CHANGED
@@ -17,6 +17,7 @@ import sessionScrollbackArchive from "./bin/session-scrollback-archive.cjs";
17
17
  import sessionReplayWindowPolicy from "./bin/session-replay-window-policy.cjs";
18
18
  import globPatternPolicy from "./bin/glob-pattern-policy.cjs";
19
19
  import userHomePathPolicy from "./bin/user-home-path-policy.cjs";
20
+ import nativeRuntimeCachePolicy from "./bin/native-runtime-cache.cjs";
20
21
  import editableToolApprovalPolicy from "./bin/editable-tool-approval-policy.cjs";
21
22
  import editableToolApprovalRuntime from "./bin/editable-tool-approval-runtime.cjs";
22
23
  import crypto$1, { createHash, randomBytes, randomInt, randomUUID, timingSafeEqual } from "node:crypto";
@@ -59,6 +60,7 @@ const { SessionScrollbackArchive, sessionScrollbackArchiveDirectory } = sessionS
59
60
  const { replayWindowStartIndex, resolveReplayActiveTurnCount } = sessionReplayWindowPolicy;
60
61
  const { globPatternError } = globPatternPolicy;
61
62
  const { unsupportedUserHomePathError } = userHomePathPolicy;
63
+ const { resolveNativeRuntimePath } = nativeRuntimeCachePolicy;
62
64
  const {
63
65
  buildApprovalEditedEvent,
64
66
  canonicalEditedToolInputJson,
@@ -2705,9 +2707,14 @@ var init_blun = __esmMin((() => {
2705
2707
  if (!choice) continue;
2706
2708
  if (choice.finish_reason !== null && choice.finish_reason !== void 0) this._captureFinishReason(choice.finish_reason);
2707
2709
  const delta = choice.delta ?? {};
2710
+ 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;
2711
+ if (hiddenThinkingTokens !== void 0) yield {
2712
+ type: "think_tokens",
2713
+ thinkTokens: hiddenThinkingTokens
2714
+ };
2708
2715
  const reasoning = observeBlunReasoning(delta);
2709
2716
  this._reasoningFieldState = mergeReasoningFieldState(this._reasoningFieldState, reasoning.state);
2710
- if (reasoning.value !== void 0) yield {
2717
+ if (reasoning.value !== void 0 && (hiddenThinkingTokens === void 0 || reasoning.value.trim().length > 0)) yield {
2711
2718
  type: "think",
2712
2719
  think: reasoning.value
2713
2720
  };
@@ -74783,6 +74790,11 @@ function buildKosongCallbacks(params, markStreamOutput) {
74783
74790
  params.onThinkDelta(part.think);
74784
74791
  return;
74785
74792
  }
74793
+ if (part.type === "think_tokens") {
74794
+ if (params.onThinkTokens === void 0) return;
74795
+ params.onThinkTokens(part.thinkTokens);
74796
+ return;
74797
+ }
74786
74798
  if (part.type === "function") {
74787
74799
  const identity = {
74788
74800
  toolCallId: part.id,
@@ -245084,7 +245096,7 @@ var init_tool_call = __esmMin((() => {
245084
245096
  * does not lose model usage that was already spent.
245085
245097
  */
245086
245098
  async function executeLoopStep(deps) {
245087
- const { turnId, signal, buildMessages, buildMessagesStrict, dispatchEvent, llm, tools, hooks, log, currentStep, maxRetryAttempts, recordUsage, onStepStarted, checkpointBeforeToolExecution, checkpointBeforeRetryWait } = deps;
245099
+ const { turnId, signal, buildMessages, buildMessagesStrict, dispatchEvent, llm, tools, hooks, log, currentStep, maxRetryAttempts, recordUsage, onStepStarted, checkpointBeforeToolExecution, checkpointBeforeRetryWait, beginInterruptibleRequest, endInterruptibleRequest } = deps;
245088
245100
  const beforeStep = hooks?.beforeStep === void 0 ? void 0 : await hooks.beforeStep({
245089
245101
  turnId,
245090
245102
  stepNumber: currentStep,
@@ -245132,6 +245144,9 @@ async function executeLoopStep(deps) {
245132
245144
  if (prepareRequestBoundary === void 0) await stepEvents.start();
245133
245145
  else chatParams = await prepareRequestBoundary(chatParams, stepBuildMessages);
245134
245146
  signal.throwIfAborted();
245147
+ const requestSignal = beginInterruptibleRequest?.() ?? signal;
245148
+ const wasInterruptedByActiveSteer = (error) => isActiveSteerInterrupt(error) || isActiveSteerInterrupt(requestSignal.reason);
245149
+ chatParams = { ...chatParams, signal: requestSignal };
245135
245150
  const retryInput = {
245136
245151
  llm: stepLLM,
245137
245152
  dispatchEvent: (event) => stepEvents.dispatchRetrying(event),
@@ -245148,11 +245163,20 @@ async function executeLoopStep(deps) {
245148
245163
  retryInput,
245149
245164
  params: chatParams,
245150
245165
  stepEvents,
245151
- signal,
245166
+ signal: requestSignal,
245152
245167
  log
245153
245168
  });
245154
245169
  } catch (error) {
245155
245170
  await stepEvents.drain();
245171
+ if (wasInterruptedByActiveSteer(error) && !signal.aborted) {
245172
+ await dispatchEvent({
245173
+ type: "turn.interrupted",
245174
+ reason: "steered",
245175
+ attemptedSteps: currentStep,
245176
+ activeStep: currentStep
245177
+ });
245178
+ return { usage: emptyUsage(), stopReason: "steer_restart" };
245179
+ }
245156
245180
  if (stepBuildMessagesStrict === void 0 || !isRecoverableRequestStructureError(error) || prepareRequestBoundary !== void 0 && stepEvents.hasOutput) throw error;
245157
245181
  signal.throwIfAborted();
245158
245182
  log?.warn("provider rejected request structure; resending with strict projection", {
@@ -245172,10 +245196,19 @@ async function executeLoopStep(deps) {
245172
245196
  retryInput,
245173
245197
  params: strictParams,
245174
245198
  stepEvents,
245175
- signal,
245199
+ signal: requestSignal,
245176
245200
  log
245177
245201
  });
245178
245202
  } catch (strictError) {
245203
+ if (wasInterruptedByActiveSteer(strictError) && !signal.aborted) {
245204
+ await dispatchEvent({
245205
+ type: "turn.interrupted",
245206
+ reason: "steered",
245207
+ attemptedSteps: currentStep,
245208
+ activeStep: currentStep
245209
+ });
245210
+ return { usage: emptyUsage(), stopReason: "steer_restart" };
245211
+ }
245179
245212
  log?.error("strict resend still rejected by provider; request remains wire-invalid", {
245180
245213
  turnStep: `${turnId}.${String(currentStep)}`,
245181
245214
  model: stepLLM.modelName,
@@ -245185,6 +245218,8 @@ async function executeLoopStep(deps) {
245185
245218
  throw strictError;
245186
245219
  }
245187
245220
  log?.info("recovered after strict resend", { turnStep: `${turnId}.${String(currentStep)}` });
245221
+ } finally {
245222
+ endInterruptibleRequest?.();
245188
245223
  }
245189
245224
  await stepEvents.start();
245190
245225
  await stepEvents.drain();
@@ -245275,20 +245310,53 @@ function stepEndProviderDiagnostics(response, stopReason) {
245275
245310
  };
245276
245311
  }
245277
245312
  var { createLiveResponseRepetitionGuard } = createRequire(import.meta.url)("./bin/live-response-repetition-guard.cjs");
245313
+ var { createThinkingOnlyGuard, forceAnswerParams } = createRequire(import.meta.url)("./bin/thinking-only-guard.cjs");
245314
+ var { ACTIVE_STEER_PRIORITY_REMINDER, createActiveSteerInterrupt, isActiveSteerInterrupt } = createRequire(import.meta.url)("./bin/active-steer-priority-policy.cjs");
245278
245315
  async function chatWithLiveResponseRepetitionRecovery(deps) {
245279
245316
  const { retryInput, params, stepEvents, signal, log } = deps;
245317
+ let currentParams = params;
245280
245318
  for (let attempt = 1; attempt <= 2; attempt++) {
245281
245319
  try {
245282
- return await chatWithRetry({
245320
+ const response = await chatWithRetry({
245283
245321
  ...retryInput,
245284
245322
  params: {
245285
- ...params,
245323
+ ...currentParams,
245286
245324
  signal: stepEvents.beginLiveResponseAttempt(signal)
245287
245325
  }
245288
245326
  });
245327
+ stepEvents.finishLiveResponseAttempt();
245328
+ return response;
245289
245329
  } catch (error) {
245290
245330
  await stepEvents.drain();
245291
245331
  const repetition = stepEvents.liveRepetitionResult;
245332
+ const thinkingTimeout = stepEvents.thinkingOnlyTimeoutResult;
245333
+ stepEvents.finishLiveResponseAttempt();
245334
+ if (thinkingTimeout !== null && !signal.aborted && attempt < 2) {
245335
+ log?.warn("thinking-only phase exceeded limit; forcing answer", {
245336
+ elapsedMs: thinkingTimeout.elapsedMs,
245337
+ turnStep: `${retryInput.turnId}.${String(retryInput.currentStep)}`
245338
+ });
245339
+ await persistRetrySchedule({
245340
+ dispatchRetrying: (event) => stepEvents.dispatchRetrying(event),
245341
+ flush: retryInput.checkpointBeforeRetryWait,
245342
+ signal,
245343
+ event: {
245344
+ type: "step.retrying",
245345
+ turnId: retryInput.turnId,
245346
+ step: retryInput.currentStep,
245347
+ stepUuid: retryInput.stepUuid,
245348
+ failedAttempt: attempt,
245349
+ nextAttempt: attempt + 1,
245350
+ maxAttempts: 2,
245351
+ delayMs: 0,
245352
+ outputMayHaveStarted: true,
245353
+ errorName: "ThinkingOnlyTimeoutError",
245354
+ errorMessage: "Hidden thinking exceeded the bounded thinking-only phase"
245355
+ }
245356
+ });
245357
+ currentParams = forceAnswerParams(currentParams);
245358
+ continue;
245359
+ }
245292
245360
  if (repetition === null || signal.aborted || attempt >= 2) throw error;
245293
245361
  log?.warn("live response repetition detected; retrying step once", {
245294
245362
  charCount: repetition.charCount,
@@ -245325,6 +245393,9 @@ function createStepEventGate(deps) {
245325
245393
  let liveRepetitionGuard;
245326
245394
  let liveRepetitionController;
245327
245395
  let liveRepetitionResult = null;
245396
+ let thinkingOnlyController;
245397
+ let thinkingOnlyGuard;
245398
+ let thinkingOnlyTimeoutResult = null;
245328
245399
  const start = () => {
245329
245400
  startPromise ??= (async () => {
245330
245401
  await dispatchEvent({
@@ -245365,12 +245436,25 @@ function createStepEventGate(deps) {
245365
245436
  get liveRepetitionResult() {
245366
245437
  return liveRepetitionResult;
245367
245438
  },
245439
+ get thinkingOnlyTimeoutResult() {
245440
+ return thinkingOnlyTimeoutResult;
245441
+ },
245368
245442
  beginLiveResponseAttempt: (signal) => {
245369
245443
  liveRepetitionGuard = createLiveResponseRepetitionGuard();
245370
245444
  liveRepetitionController = new AbortController();
245371
245445
  liveRepetitionResult = null;
245372
- return AbortSignal.any([signal, liveRepetitionController.signal]);
245446
+ thinkingOnlyController = new AbortController();
245447
+ thinkingOnlyTimeoutResult = null;
245448
+ thinkingOnlyGuard = createThinkingOnlyGuard({
245449
+ onTimeout: (result) => {
245450
+ thinkingOnlyTimeoutResult = result;
245451
+ thinkingOnlyController?.abort(/* @__PURE__ */ new Error("Hidden thinking exceeded the bounded thinking-only phase"));
245452
+ }
245453
+ });
245454
+ thinkingOnlyGuard.beginAttempt();
245455
+ return AbortSignal.any([signal, liveRepetitionController.signal, thinkingOnlyController.signal]);
245373
245456
  },
245457
+ finishLiveResponseAttempt: () => thinkingOnlyGuard?.stop(),
245374
245458
  dispatchRetrying: async (event) => {
245375
245459
  const queued = eventQueue.then(async () => {
245376
245460
  await start();
@@ -245383,6 +245467,7 @@ function createStepEventGate(deps) {
245383
245467
  drain: async () => eventQueue,
245384
245468
  callbacks: {
245385
245469
  onTextDelta: (delta) => {
245470
+ if (delta.length > 0) thinkingOnlyGuard?.noteSubstantiveOutput();
245386
245471
  if (inspectLiveRepetition(delta)) return;
245387
245472
  enqueue(() => {
245388
245473
  dispatchEvent({
@@ -245392,6 +245477,7 @@ function createStepEventGate(deps) {
245392
245477
  });
245393
245478
  },
245394
245479
  onThinkDelta: (delta) => {
245480
+ thinkingOnlyGuard?.noteThinking();
245395
245481
  if (inspectLiveRepetition(delta)) return;
245396
245482
  enqueue(() => {
245397
245483
  dispatchEvent({
@@ -245400,7 +245486,17 @@ function createStepEventGate(deps) {
245400
245486
  });
245401
245487
  });
245402
245488
  },
245489
+ onThinkTokens: (cumulativeTokens) => {
245490
+ thinkingOnlyGuard?.noteThinking();
245491
+ enqueue(() => {
245492
+ dispatchEvent({
245493
+ type: "thinking.progress",
245494
+ cumulativeTokens
245495
+ });
245496
+ });
245497
+ },
245403
245498
  onToolCallDelta: (delta) => {
245499
+ thinkingOnlyGuard?.noteSubstantiveOutput();
245404
245500
  enqueue(() => {
245405
245501
  dispatchEvent({
245406
245502
  type: "tool.call.delta",
@@ -245410,14 +245506,17 @@ function createStepEventGate(deps) {
245410
245506
  });
245411
245507
  });
245412
245508
  },
245413
- onTextPart: (part) => enqueue(() => dispatchEvent({
245414
- type: "content.part",
245415
- uuid: randomUUID(),
245416
- turnId,
245417
- step: currentStep,
245418
- stepUuid,
245419
- part
245420
- })),
245509
+ onTextPart: (part) => {
245510
+ thinkingOnlyGuard?.noteSubstantiveOutput();
245511
+ return enqueue(() => dispatchEvent({
245512
+ type: "content.part",
245513
+ uuid: randomUUID(),
245514
+ turnId,
245515
+ step: currentStep,
245516
+ stepUuid,
245517
+ part
245518
+ }));
245519
+ },
245421
245520
  onThinkPart: (part) => enqueue(() => dispatchEvent({
245422
245521
  type: "content.part",
245423
245522
  uuid: randomUUID(),
@@ -245474,6 +245573,10 @@ async function runTurn(input) {
245474
245573
  onStepStarted: setActiveStep.bind(void 0, stepNumber)
245475
245574
  });
245476
245575
  activeStep = void 0;
245576
+ if (stepResult.stopReason === "steer_restart") {
245577
+ steps -= 1;
245578
+ continue;
245579
+ }
245477
245580
  if (stepResult.stopReason === "tool_use") continue;
245478
245581
  const terminalStopReason = stepResult.stopReason;
245479
245582
  stopReason = terminalStopReason;
@@ -246368,7 +246471,7 @@ var init_modelCatalog$2 = __esmMin((() => {
246368
246471
  function isVolatileEventType(type) {
246369
246472
  return volatileEventTypeSet.has(type);
246370
246473
  }
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;
246474
+ 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
246475
  var init_events$1 = __esmMin((() => {
246373
246476
  init_zod$1();
246374
246477
  init_display();
@@ -246905,6 +247008,11 @@ var init_events$1 = __esmMin((() => {
246905
247008
  turnId: number$1(),
246906
247009
  delta: string()
246907
247010
  });
247011
+ thinkingProgressEventSchema = object({
247012
+ type: literal("thinking.progress"),
247013
+ turnId: number$1(),
247014
+ cumulativeTokens: number$1().int().nonnegative()
247015
+ });
246908
247016
  toolCallDeltaEventSchema = object({
246909
247017
  type: literal("tool.call.delta"),
246910
247018
  turnId: number$1(),
@@ -247130,6 +247238,7 @@ var init_events$1 = __esmMin((() => {
247130
247238
  assistantDeltaEventSchema,
247131
247239
  hookResultEventSchema,
247132
247240
  thinkingDeltaEventSchema,
247241
+ thinkingProgressEventSchema,
247133
247242
  toolCallDeltaEventSchema,
247134
247243
  toolCallStartedEventSchema,
247135
247244
  toolProgressEventSchema,
@@ -247165,6 +247274,7 @@ var init_events$1 = __esmMin((() => {
247165
247274
  VOLATILE_EVENT_TYPES = [
247166
247275
  "assistant.delta",
247167
247276
  "thinking.delta",
247277
+ "thinking.progress",
247168
247278
  "tool.call.delta",
247169
247279
  "tool.progress",
247170
247280
  "compaction.progress",
@@ -261915,13 +262025,11 @@ function appendReminder(result, reminderText) {
261915
262025
  output: newOutput
261916
262026
  };
261917
262027
  }
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;
262028
+ var loopPolicy = createRequire(import.meta.url)("./bin/tool-call-loop-policy.cjs");
262029
+ var FORCE_ANSWER_RESULT_STREAK = loopPolicy.FORCE_ANSWER_RESULT_STREAK;
262030
+ var createToolCallLoopKey = loopPolicy.createToolCallLoopKey;
262031
+ var hashToolResult = loopPolicy.hashToolResult;
262032
+ var REMINDER_TEXT_1, REMINDER_TEXT_3, REPEAT_REMINDER_1_START, REPEAT_REMINDER_2_START, REPEAT_REMINDER_3_START, DEDUP_PLACEHOLDER_RESULT, ToolCallDeduplicator;
261925
262033
  var init_tool_dedup = __esmMin((() => {
261926
262034
  init_canonical_args();
261927
262035
  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 +262037,6 @@ var init_tool_dedup = __esmMin((() => {
261929
262037
  REPEAT_REMINDER_1_START = 3;
261930
262038
  REPEAT_REMINDER_2_START = 5;
261931
262039
  REPEAT_REMINDER_3_START = 8;
261932
- REPEAT_FORCE_STOP_STREAK = 12;
261933
262040
  DEDUP_PLACEHOLDER_RESULT = { output: "" };
261934
262041
  ToolCallDeduplicator = class {
261935
262042
  stepDeferreds = /* @__PURE__ */ new Map();
@@ -261945,8 +262052,14 @@ var init_tool_dedup = __esmMin((() => {
261945
262052
  * during finalize.
261946
262053
  */
261947
262054
  callKeyByCallId = /* @__PURE__ */ new Map();
262055
+ /** The tolerant key is used only for cross-step loop detection. */
262056
+ callLoopKeyByCallId = /* @__PURE__ */ new Map();
261948
262057
  consecutiveKey = null;
261949
262058
  consecutiveCount = 0;
262059
+ lastResultLoopKey = null;
262060
+ lastResultHash = null;
262061
+ resultStreakCount = 0;
262062
+ forceAnswerOnly = false;
261950
262063
  telemetry;
261951
262064
  constructor(options) {
261952
262065
  this.telemetry = options?.telemetry;
@@ -261961,6 +262074,7 @@ var init_tool_dedup = __esmMin((() => {
261961
262074
  this.originalCallIndex.clear();
261962
262075
  this.syntheticCallIds.clear();
261963
262076
  this.callKeyByCallId.clear();
262077
+ this.callLoopKeyByCallId.clear();
261964
262078
  }
261965
262079
  endStep() {
261966
262080
  for (const key of this.stepCalls) if (key === this.consecutiveKey) this.consecutiveCount += 1;
@@ -261969,6 +262083,9 @@ var init_tool_dedup = __esmMin((() => {
261969
262083
  this.consecutiveCount = 1;
261970
262084
  }
261971
262085
  }
262086
+ shouldForceAnswerOnly() {
262087
+ return this.forceAnswerOnly;
262088
+ }
261972
262089
  /**
261973
262090
  * Called from `prepareToolExecution`. If this `(toolName, args)` was already
261974
262091
  * seen in the current step, returns a placeholder result so the loop can
@@ -261981,9 +262098,11 @@ var init_tool_dedup = __esmMin((() => {
261981
262098
  */
261982
262099
  checkSameStep(toolCallId, toolName, args) {
261983
262100
  const key = makeKey(toolName, args);
262101
+ const loopKey = createToolCallLoopKey(toolName, args);
261984
262102
  const index = this.stepCalls.length;
261985
- this.stepCalls.push(key);
262103
+ this.stepCalls.push(loopKey);
261986
262104
  this.callKeyByCallId.set(toolCallId, key);
262105
+ this.callLoopKeyByCallId.set(toolCallId, loopKey);
261987
262106
  if (this.stepDeferreds.get(key) !== void 0) {
261988
262107
  this.syntheticCallIds.add(toolCallId);
261989
262108
  return DEDUP_PLACEHOLDER_RESULT;
@@ -262004,6 +262123,8 @@ var init_tool_dedup = __esmMin((() => {
262004
262123
  const key = this.callKeyByCallId.get(toolCallId);
262005
262124
  if (key === void 0) return result;
262006
262125
  this.callKeyByCallId.delete(toolCallId);
262126
+ const loopKey = this.callLoopKeyByCallId.get(toolCallId);
262127
+ this.callLoopKeyByCallId.delete(toolCallId);
262007
262128
  if (this.syntheticCallIds.delete(toolCallId)) {
262008
262129
  const deferred = this.stepDeferreds.get(key);
262009
262130
  if (deferred === void 0) return result;
@@ -262024,9 +262145,15 @@ var init_tool_dedup = __esmMin((() => {
262024
262145
  }
262025
262146
  let finalResult = result;
262026
262147
  let action = "none";
262027
- if (streak >= REPEAT_FORCE_STOP_STREAK) {
262028
- finalResult = forceStopResult(result, REMINDER_TEXT_3);
262029
- action = "stop";
262148
+ const resultHash = hashToolResult(result);
262149
+ const resultRepeatCount = this.lastResultLoopKey === loopKey && this.lastResultHash === resultHash ? this.resultStreakCount + 1 : 1;
262150
+ this.lastResultLoopKey = loopKey;
262151
+ this.lastResultHash = resultHash;
262152
+ this.resultStreakCount = resultRepeatCount;
262153
+ if (resultRepeatCount >= FORCE_ANSWER_RESULT_STREAK) {
262154
+ finalResult = appendReminder(result, REMINDER_TEXT_3);
262155
+ this.forceAnswerOnly = true;
262156
+ action = "force_answer";
262030
262157
  } else if (streak >= REPEAT_REMINDER_3_START) {
262031
262158
  finalResult = appendReminder(result, REMINDER_TEXT_3);
262032
262159
  action = "r3";
@@ -262037,9 +262164,10 @@ var init_tool_dedup = __esmMin((() => {
262037
262164
  finalResult = appendReminder(result, REMINDER_TEXT_1);
262038
262165
  action = "r1";
262039
262166
  }
262040
- if (streak >= 2) this.telemetry?.track("tool_call_repeat", {
262167
+ if (streak >= 2 || resultRepeatCount >= 2) this.telemetry?.track("tool_call_repeat", {
262041
262168
  tool_name: toolName,
262042
262169
  repeat_count: streak,
262170
+ result_repeat_count: resultRepeatCount,
262043
262171
  action
262044
262172
  });
262045
262173
  this.stepDeferreds.get(key)?.resolve(finalResult);
@@ -262911,6 +263039,11 @@ function mapLoopEvent(event, turnId) {
262911
263039
  turnId,
262912
263040
  delta: event.delta
262913
263041
  };
263042
+ case "thinking.progress": return {
263043
+ type: "thinking.progress",
263044
+ turnId,
263045
+ cumulativeTokens: event.cumulativeTokens
263046
+ };
262914
263047
  case "tool.call.delta": return {
262915
263048
  type: "tool.call.delta",
262916
263049
  turnId,
@@ -263066,7 +263199,7 @@ function durablePromptOrigin(origin) {
263066
263199
  void externalReportSources;
263067
263200
  return durableOrigin;
263068
263201
  }
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;
263202
+ 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
263203
  var init_turn = __esmMin((() => {
263071
263204
  init_dist$4();
263072
263205
  init_src$4();
@@ -263080,6 +263213,7 @@ var init_turn = __esmMin((() => {
263080
263213
  init_hooks();
263081
263214
  init_canonical_args();
263082
263215
  init_tool_dedup();
263216
+ ({ applyMnemoAgentToToolArgs } = createRequire(import.meta.url)("./bin/mnemo-tool-agent-policy.cjs"));
263083
263217
  init_tool_result_budget();
263084
263218
  init_user_message_offload();
263085
263219
  init_assistant_message_offload();
@@ -263420,6 +263554,7 @@ var init_turn = __esmMin((() => {
263420
263554
  origin: durablePromptOrigin(origin)
263421
263555
  });
263422
263556
  this.bufferSteer(input, origin, this.currentId);
263557
+ active.interruptActiveStep?.();
263423
263558
  return {
263424
263559
  turnId: this.currentId,
263425
263560
  duplicate: false
@@ -263453,7 +263588,8 @@ var init_turn = __esmMin((() => {
263453
263588
  controller,
263454
263589
  promise,
263455
263590
  firstRequest,
263456
- acceptingSteers: false
263591
+ acceptingSteers: false,
263592
+ interruptActiveStep: void 0
263457
263593
  };
263458
263594
  firstRequest.catch(() => void 0);
263459
263595
  promise.then(firstRequest.reject, firstRequest.reject);
@@ -263584,6 +263720,11 @@ var init_turn = __esmMin((() => {
263584
263720
  if (active === null || active === "resuming" || this.currentId !== turnId) return;
263585
263721
  active.acceptingSteers = accepting;
263586
263722
  }
263723
+ setActiveStepInterrupter(turnId, interrupter) {
263724
+ const active = this.activeTurn;
263725
+ if (active === null || active === "resuming" || this.currentId !== turnId) return;
263726
+ active.interruptActiveStep = interrupter;
263727
+ }
263587
263728
  discardUnconsumedActiveSteers(turnId) {
263588
263729
  const before = this.steerBuffer.length;
263589
263730
  this.steerBuffer = this.steerBuffer.filter((steer) => steer.targetTurnId !== turnId);
@@ -263937,7 +264078,7 @@ var init_turn = __esmMin((() => {
263937
264078
  const turnText = blunExtractText(input);
263938
264079
  const turnNeedsTools = blunTurnNeedsTools(input, origin);
263939
264080
  const turnHasAttachment = blunTurnHasAttachment(input);
263940
- const turnThinkingEffort = turnHasAttachment ? void 0 : selectThinkingEffortForTurn(blunExtractText(blunThinkingIntentInput(input)), origin.kind);
264081
+ const turnThinkingEffort = turnHasAttachment ? void 0 : selectThinkingEffortForTurn(blunExtractText(blunThinkingIntentInput(input)), origin.kind, this.agent.config.thinkingEffort);
263941
264082
  const fastConversation = turnThinkingEffort === "off" || turnThinkingEffort === "low";
263942
264083
  const pendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
263943
264084
  const requiredToolNames = mediaToolNamesForTurnText(turnText);
@@ -263947,6 +264088,7 @@ var init_turn = __esmMin((() => {
263947
264088
  let currentStepHadTool = false;
263948
264089
  let currentStepHadFailure = false;
263949
264090
  let currentLoopStep = 0;
264091
+ let activeStepInterruptController;
263950
264092
  while (true) {
263951
264093
  signal.throwIfAborted();
263952
264094
  const model = this.agent.config.model;
@@ -263999,6 +264141,15 @@ var init_turn = __esmMin((() => {
263999
264141
  maxRetryAttempts: loopControl?.maxRetriesPerStep,
264000
264142
  checkpointBeforeToolExecution: () => this.agent.records.flush(),
264001
264143
  checkpointBeforeRetryWait: () => this.agent.records.flush(),
264144
+ beginInterruptibleRequest: () => {
264145
+ activeStepInterruptController = new AbortController();
264146
+ this.setActiveStepInterrupter(turnId, () => activeStepInterruptController?.abort(createActiveSteerInterrupt()));
264147
+ return AbortSignal.any([signal, activeStepInterruptController.signal]);
264148
+ },
264149
+ endInterruptibleRequest: () => {
264150
+ this.setActiveStepInterrupter(turnId, void 0);
264151
+ activeStepInterruptController = void 0;
264152
+ },
264002
264153
  recordStepUsage: async (usage) => {
264003
264154
  try {
264004
264155
  stopForGoalBudget = (await this.agent.goal.recordTokenUsage(grandTotal(usage)))?.budget.overBudget === true;
@@ -264017,6 +264168,10 @@ var init_turn = __esmMin((() => {
264017
264168
  await this.agent.injection.inject();
264018
264169
  stepSignal.throwIfAborted();
264019
264170
  deduper.beginStep();
264171
+ if (deduper.shouldForceAnswerOnly()) {
264172
+ this.agent.log.warn("tool loop stopped; forcing text answer", { stepNumber });
264173
+ return { tools: [] };
264174
+ }
264020
264175
  const workStepThinkingEffort = selectThinkingEffortForWorkStep(stepNumber, previousStepToolOutcome);
264021
264176
  currentStepHadTool = false;
264022
264177
  currentStepHadFailure = false;
@@ -264054,13 +264209,26 @@ var init_turn = __esmMin((() => {
264054
264209
  }
264055
264210
  if (pendingSteers.some((steer) => directMessageAllowsWorkContinuation(blunExtractText(steer.input)))) directSteerContinuationPending = true;
264056
264211
  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
264212
  const steerInput = pendingSteers.flatMap((steer) => [...steer.input]);
264059
- const steerThinkingEffort = "low";
264060
- const steerPendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
264061
264213
  const steerText = blunExtractText(steerInput);
264062
264214
  const steerRequiredToolNames = mediaToolNamesForTurnText(steerText);
264063
264215
  for (const name of rankedToolNamesForTurnText(eligibleTools, steerText)) steerRequiredToolNames.add(name);
264216
+ if (steerEfforts.some((effort) => effort === void 0)) {
264217
+ const prioritizedSelection = blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens, this.loadedToolNames, steerRequiredToolNames);
264218
+ this.agent.context.appendSystemReminder(ACTIVE_STEER_PRIORITY_REMINDER, {
264219
+ kind: "injection",
264220
+ variant: "active_steer_priority"
264221
+ });
264222
+ this.agent.log.info("steer request tools", {
264223
+ requestPurpose: "active_steer_priority",
264224
+ pendingSteerCount: pendingSteers.length,
264225
+ selectedToolCount: prioritizedSelection.tools.length,
264226
+ deferredToolCount: prioritizedSelection.deferredToolCount
264227
+ });
264228
+ return { tools: prioritizedSelection.tools };
264229
+ }
264230
+ const steerThinkingEffort = "low";
264231
+ const steerPendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
264064
264232
  const steerNeedsActionTools = steerRequiredToolNames.size > 0;
264065
264233
  const steerLLM = this.agent.llmForTurn(steerThinkingEffort, blunPendingMediaSystemPrompt(steerNeedsActionTools ? this.agent.effectiveSystemPrompt : this.agent.fastConversationSystemPrompt, steerPendingMediaJobIds));
264066
264234
  const steerTools = [...blunFastConversationTools(eligibleTools, steerInput, steerPendingMediaJobIds, steerRequiredToolNames)];
@@ -264155,8 +264323,10 @@ var init_turn = __esmMin((() => {
264155
264323
  if (goalTodoPolicy !== void 0) return goalTodoPolicy;
264156
264324
  const ideaPolicy = enforceIdeaToolPolicy(this.agent, ctx);
264157
264325
  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 };
264326
+ const effectiveArgs = applyMnemoAgentToToolArgs(ctx.toolCall.name, ctx.args);
264327
+ const cached = deduper.checkSameStep(ctx.toolCall.id, ctx.toolCall.name, effectiveArgs);
264328
+ if (cached !== null) return { updatedArgs: effectiveArgs, syntheticResult: cached };
264329
+ if (effectiveArgs !== ctx.args) return { updatedArgs: effectiveArgs };
264160
264330
  },
264161
264331
  authorizeToolExecution: async (ctx) => {
264162
264332
  try {
@@ -264263,7 +264433,7 @@ var init_turn = __esmMin((() => {
264263
264433
  emitLiveEvent: (event) => {
264264
264434
  this.noteFirstRequestEvent(event);
264265
264435
  this.trackLoopTelemetry(event, turnId);
264266
- if (event.type === "thinking.delta" && event.delta.trim().length === 0) {
264436
+ if (event.type === "thinking.progress" || event.type === "thinking.delta" && event.delta.trim().length === 0) {
264267
264437
  const requestState = this.stepRequestStateByTurn.get(turnId);
264268
264438
  this.agent.records.logRecord({
264269
264439
  type: "thinking.heartbeat",
@@ -264272,7 +264442,8 @@ var init_turn = __esmMin((() => {
264272
264442
  attempt: requestState?.attempt ?? 1,
264273
264443
  max_attempts: requestState?.maxAttempts,
264274
264444
  completion_budget: requestState?.completionBudget,
264275
- thinking_effort: requestState?.thinkingEffort
264445
+ thinking_effort: requestState?.thinkingEffort,
264446
+ hidden_thinking_tokens: event.type === "thinking.progress" ? event.cumulativeTokens : void 0
264276
264447
  });
264277
264448
  }
264278
264449
  if (event.type === "step.retrying" && event.completionBudgetBefore !== void 0 && event.completionBudgetAfter !== void 0) this.agent.records.logRecord({
@@ -264295,6 +264466,7 @@ var init_turn = __esmMin((() => {
264295
264466
  case "tool.call":
264296
264467
  case "text.delta":
264297
264468
  case "thinking.delta":
264469
+ case "thinking.progress":
264298
264470
  case "tool.call.delta": {
264299
264471
  const active = this.activeTurn;
264300
264472
  if (active === null || active === "resuming") return;
@@ -342961,6 +343133,241 @@ function definedCatalogEntries(copy) {
342961
343133
  return Object.entries(copy).filter((entry) => entry[1] !== void 0);
342962
343134
  }
342963
343135
  //#endregion
343136
+ //#region src/tui/i18n/gated-565-catalog-additions.ts
343137
+ registerUiCatalogFragment({
343138
+ "es": {
343139
+ "media.activity.chain": "Cadena de producción",
343140
+ "media.activity.collapse": "ctrl+o: contraer",
343141
+ "media.activity.jobs": "{count} trabajos multimedia activos",
343142
+ "media.activity.showJobs": "ctrl+o: mostrar trabajos",
343143
+ "media.detail.audio": "{seconds}s de audio",
343144
+ "media.detail.duration": "Duración {duration}",
343145
+ "media.detail.open": "Abrir",
343146
+ "media.detail.playSample": "Reproducir muestra",
343147
+ "media.detail.preview": "Vista previa",
343148
+ "media.detail.queue": "Posición {position}",
343149
+ "media.detail.remaining": "quedan aprox. {duration}",
343150
+ "media.detail.resolution": "{width}x{height}",
343151
+ "media.detail.segment": "Segmento {current} de {total}",
343152
+ "media.detail.waveform": "Forma de onda",
343153
+ "media.kind.dubbing": "Doblaje",
343154
+ "media.kind.image": "Imagen",
343155
+ "media.kind.image-analysis": "Análisis de imagen",
343156
+ "media.kind.lipsync": "Sincronización labial",
343157
+ "media.kind.media": "Multimedia",
343158
+ "media.kind.video": "Vídeo",
343159
+ "media.kind.video-analysis": "Análisis de vídeo",
343160
+ "media.kind.voice": "Voz",
343161
+ "media.phase.accepted": "En cola",
343162
+ "media.phase.analyzing": "Analizando",
343163
+ "media.phase.audio-analysis": "Análisis de audio",
343164
+ "media.phase.checking": "Comprobando estado",
343165
+ "media.phase.exporting": "Exportando",
343166
+ "media.phase.face-detection": "Detección de rostros",
343167
+ "media.phase.face-tracking": "Seguimiento de rostros",
343168
+ "media.phase.generating": "Generando",
343169
+ "media.phase.in-progress": "Procesando",
343170
+ "media.phase.lip-sync-running": "Sincronización labial en curso",
343171
+ "media.phase.pending": "En cola",
343172
+ "media.phase.processing": "Procesando",
343173
+ "media.phase.queued": "En cola",
343174
+ "media.phase.rendering": "Renderizando",
343175
+ "media.phase.running": "Procesando",
343176
+ "media.phase.saving": "Guardando",
343177
+ "media.phase.submitting": "Enviando solicitud",
343178
+ "media.phase.uploading": "Enviando solicitud",
343179
+ "media.phase.upscaling": "Aumentando la resolución",
343180
+ "thinking.activity.coordinates": "{name} coordinando",
343181
+ "thinking.activity.plans": "{name} planificando",
343182
+ "thinking.activity.reads": "{name} leyendo",
343183
+ "thinking.activity.runs": "{name} ejecutando",
343184
+ "thinking.activity.writes": "{name} escribiendo",
343185
+ "thinking.attempt": "intento {attempt}/{maxAttempts}",
343186
+ "thinking.budget": "presupuesto {budget}",
343187
+ "thinking.effort": "esfuerzo {effort}",
343188
+ "thinking.emptyRetry": "Respuesta vacía del modelo; {hint} · presupuesto {before} → {after}",
343189
+ "thinking.finished": "listo {time}",
343190
+ "thinking.heartbeat": "señal del pensamiento oculto hace {seconds}s",
343191
+ "thinking.hiddenTokens": "pensando {count}",
343192
+ "thinking.step": "paso {step}",
343193
+ "thinking.worked": "Trabajó {elapsed}"
343194
+ },
343195
+ "fr": {
343196
+ "media.activity.chain": "Chaîne de production",
343197
+ "media.activity.collapse": "ctrl+o : replier",
343198
+ "media.activity.jobs": "{count} tâches média actives",
343199
+ "media.activity.showJobs": "ctrl+o : afficher les tâches",
343200
+ "media.detail.audio": "{seconds} s d'audio",
343201
+ "media.detail.duration": "Durée {duration}",
343202
+ "media.detail.open": "Ouvrir",
343203
+ "media.detail.playSample": "Écouter l'extrait",
343204
+ "media.detail.preview": "Aperçu",
343205
+ "media.detail.queue": "Rang {position}",
343206
+ "media.detail.remaining": "encore environ {duration}",
343207
+ "media.detail.resolution": "{width}x{height}",
343208
+ "media.detail.segment": "Segment {current} sur {total}",
343209
+ "media.detail.waveform": "Forme d'onde",
343210
+ "media.kind.dubbing": "Doublage",
343211
+ "media.kind.image": "Image",
343212
+ "media.kind.image-analysis": "Analyse d'image",
343213
+ "media.kind.lipsync": "Synchronisation labiale",
343214
+ "media.kind.media": "Médias",
343215
+ "media.kind.video": "Vidéo",
343216
+ "media.kind.video-analysis": "Analyse vidéo",
343217
+ "media.kind.voice": "Voix",
343218
+ "media.phase.accepted": "En file d'attente",
343219
+ "media.phase.analyzing": "Analyse en cours",
343220
+ "media.phase.audio-analysis": "Analyse audio",
343221
+ "media.phase.checking": "Vérification de l'état",
343222
+ "media.phase.exporting": "Export en cours",
343223
+ "media.phase.face-detection": "Détection des visages",
343224
+ "media.phase.face-tracking": "Suivi des visages",
343225
+ "media.phase.generating": "Génération en cours",
343226
+ "media.phase.in-progress": "Traitement en cours",
343227
+ "media.phase.lip-sync-running": "Synchronisation labiale en cours",
343228
+ "media.phase.pending": "En file d'attente",
343229
+ "media.phase.processing": "Traitement en cours",
343230
+ "media.phase.queued": "En file d'attente",
343231
+ "media.phase.rendering": "Rendu en cours",
343232
+ "media.phase.running": "Traitement en cours",
343233
+ "media.phase.saving": "Enregistrement en cours",
343234
+ "media.phase.submitting": "Envoi de la requête",
343235
+ "media.phase.uploading": "Envoi de la requête",
343236
+ "media.phase.upscaling": "Agrandissement en cours",
343237
+ "thinking.activity.coordinates": "{name} coordonne",
343238
+ "thinking.activity.plans": "{name} planifie",
343239
+ "thinking.activity.reads": "{name} lit",
343240
+ "thinking.activity.runs": "{name} exécute",
343241
+ "thinking.activity.writes": "{name} écrit",
343242
+ "thinking.attempt": "tentative {attempt}/{maxAttempts}",
343243
+ "thinking.budget": "budget {budget}",
343244
+ "thinking.effort": "niveau d'effort {effort}",
343245
+ "thinking.emptyRetry": "Réponse vide du modèle ; {hint} · budget {before} → {after}",
343246
+ "thinking.finished": "terminé {time}",
343247
+ "thinking.heartbeat": "signe de vie de la réflexion il y a {seconds} s",
343248
+ "thinking.hiddenTokens": "réflexion {count}",
343249
+ "thinking.step": "étape {step}",
343250
+ "thinking.worked": "A travaillé {elapsed}"
343251
+ },
343252
+ "sv": {
343253
+ "media.activity.chain": "Produktionskedja",
343254
+ "media.activity.collapse": "ctrl+o: fäll ihop",
343255
+ "media.activity.jobs": "{count} aktiva mediejobb",
343256
+ "media.activity.showJobs": "ctrl+o: visa jobb",
343257
+ "media.detail.audio": "{seconds}s ljud",
343258
+ "media.detail.duration": "Längd {duration}",
343259
+ "media.detail.open": "Öppna",
343260
+ "media.detail.playSample": "Spela upp exempel",
343261
+ "media.detail.preview": "Förhandsvisning",
343262
+ "media.detail.queue": "Plats {position}",
343263
+ "media.detail.remaining": "cirka {duration} kvar",
343264
+ "media.detail.resolution": "{width}x{height}",
343265
+ "media.detail.segment": "Segment {current} av {total}",
343266
+ "media.detail.waveform": "Vågform",
343267
+ "media.kind.dubbing": "Dubbning",
343268
+ "media.kind.image": "Bild",
343269
+ "media.kind.image-analysis": "Bildanalys",
343270
+ "media.kind.lipsync": "Läppsynk",
343271
+ "media.kind.media": "Media",
343272
+ "media.kind.video": "Video",
343273
+ "media.kind.video-analysis": "Videoanalys",
343274
+ "media.kind.voice": "Röst",
343275
+ "media.phase.accepted": "I kö",
343276
+ "media.phase.analyzing": "Analyserar",
343277
+ "media.phase.audio-analysis": "Ljudanalys",
343278
+ "media.phase.checking": "Kontrollerar status",
343279
+ "media.phase.exporting": "Exporterar",
343280
+ "media.phase.face-detection": "Ansiktsdetektering",
343281
+ "media.phase.face-tracking": "Ansiktsspårning",
343282
+ "media.phase.generating": "Genererar",
343283
+ "media.phase.in-progress": "Bearbetar",
343284
+ "media.phase.lip-sync-running": "Läppsynk pågår",
343285
+ "media.phase.pending": "I kö",
343286
+ "media.phase.processing": "Bearbetar",
343287
+ "media.phase.queued": "I kö",
343288
+ "media.phase.rendering": "Renderar",
343289
+ "media.phase.running": "Bearbetar",
343290
+ "media.phase.saving": "Sparar",
343291
+ "media.phase.submitting": "Skickar begäran",
343292
+ "media.phase.uploading": "Skickar begäran",
343293
+ "media.phase.upscaling": "Skalar upp",
343294
+ "thinking.activity.coordinates": "{name} samordnar",
343295
+ "thinking.activity.plans": "{name} planerar",
343296
+ "thinking.activity.reads": "{name} läser",
343297
+ "thinking.activity.runs": "{name} kör",
343298
+ "thinking.activity.writes": "{name} skriver",
343299
+ "thinking.attempt": "försök {attempt}/{maxAttempts}",
343300
+ "thinking.budget": "budget {budget}",
343301
+ "thinking.effort": "insats {effort}",
343302
+ "thinking.emptyRetry": "Tomt svar från modellen; {hint} · budget {before} → {after}",
343303
+ "thinking.finished": "klar {time}",
343304
+ "thinking.heartbeat": "livstecken från dold tanke för {seconds}s sedan",
343305
+ "thinking.hiddenTokens": "tänker {count}",
343306
+ "thinking.step": "steg {step}",
343307
+ "thinking.worked": "Arbetade {elapsed}"
343308
+ },
343309
+ "cs": {
343310
+ "approval.choice.editArguments": "Upravit argumenty (JSON)",
343311
+ "approval.hint.editArguments": "Zadejte kompletní náhradní objekt JSON · ↵ odeslat.",
343312
+ "approval.transcript.edited": "Argumenty upraveny",
343313
+ "media.activity.chain": "Produkční řetězec",
343314
+ "media.activity.collapse": "ctrl+o: sbalit",
343315
+ "media.activity.jobs": "Aktivní mediální úlohy: {count}",
343316
+ "media.activity.showJobs": "ctrl+o: zobrazit úlohy",
343317
+ "media.detail.audio": "{seconds}s zvuku",
343318
+ "media.detail.duration": "Délka {duration}",
343319
+ "media.detail.open": "Otevřít",
343320
+ "media.detail.playSample": "Přehrát ukázku",
343321
+ "media.detail.preview": "Náhled",
343322
+ "media.detail.queue": "Pozice {position}",
343323
+ "media.detail.remaining": "zbývá přibližně {duration}",
343324
+ "media.detail.resolution": "{width}x{height}",
343325
+ "media.detail.segment": "Segment {current} z {total}",
343326
+ "media.detail.waveform": "Vlnový průběh",
343327
+ "media.kind.dubbing": "Dabing",
343328
+ "media.kind.image": "Obrázek",
343329
+ "media.kind.image-analysis": "Analýza obrázku",
343330
+ "media.kind.lipsync": "Synchronizace rtů",
343331
+ "media.kind.media": "Média",
343332
+ "media.kind.video": "Video",
343333
+ "media.kind.video-analysis": "Analýza videa",
343334
+ "media.kind.voice": "Hlas",
343335
+ "media.phase.accepted": "Ve frontě",
343336
+ "media.phase.analyzing": "Analyzuje se",
343337
+ "media.phase.audio-analysis": "Analýza zvuku",
343338
+ "media.phase.checking": "Kontrola stavu",
343339
+ "media.phase.exporting": "Exportuje se",
343340
+ "media.phase.face-detection": "Detekce obličejů",
343341
+ "media.phase.face-tracking": "Sledování obličejů",
343342
+ "media.phase.generating": "Generuje se",
343343
+ "media.phase.in-progress": "Zpracovává se",
343344
+ "media.phase.lip-sync-running": "Probíhá synchronizace rtů",
343345
+ "media.phase.pending": "Ve frontě",
343346
+ "media.phase.processing": "Zpracovává se",
343347
+ "media.phase.queued": "Ve frontě",
343348
+ "media.phase.rendering": "Renderuje se",
343349
+ "media.phase.running": "Zpracovává se",
343350
+ "media.phase.saving": "Ukládá se",
343351
+ "media.phase.submitting": "Odesílá se požadavek",
343352
+ "media.phase.uploading": "Odesílá se požadavek",
343353
+ "media.phase.upscaling": "Zvyšuje se rozlišení",
343354
+ "thinking.activity.coordinates": "{name} koordinuje",
343355
+ "thinking.activity.plans": "{name} plánuje",
343356
+ "thinking.activity.reads": "{name} čte",
343357
+ "thinking.activity.runs": "{name} spouští",
343358
+ "thinking.activity.writes": "{name} píše",
343359
+ "thinking.attempt": "pokus {attempt}/{maxAttempts}",
343360
+ "thinking.budget": "rozpočet {budget}",
343361
+ "thinking.effort": "úsilí {effort}",
343362
+ "thinking.emptyRetry": "Prázdná odpověď modelu; {hint} · rozpočet {before} → {after}",
343363
+ "thinking.finished": "hotovo {time}",
343364
+ "thinking.heartbeat": "signál skrytého uvažování před {seconds}s",
343365
+ "thinking.hiddenTokens": "uvažuje {count}",
343366
+ "thinking.step": "krok {step}",
343367
+ "thinking.worked": "Pracováno {elapsed}"
343368
+ }
343369
+ });
343370
+ //#endregion
342964
343371
  //#region src/tui/commands/auth.copy.ts
342965
343372
  registerUiCatalogFragment({
342966
343373
  en: {
@@ -493799,12 +494206,18 @@ var PluginCommandComponent = class extends Container {
493799
494206
  registerUiCatalogFragment({
493800
494207
  en: {
493801
494208
  "thinking.label": "{name} thinking",
494209
+ "thinking.activity.reads": "{name} reading",
494210
+ "thinking.activity.writes": "{name} writing",
494211
+ "thinking.activity.runs": "{name} running",
494212
+ "thinking.activity.coordinates": "{name} coordinating",
494213
+ "thinking.activity.plans": "{name} planning",
493802
494214
  "thinking.aborted": "aborted",
493803
494215
  "thinking.step": "step {step}",
493804
494216
  "thinking.effort": "effort {effort}",
493805
494217
  "thinking.attempt": "attempt {attempt}/{maxAttempts}",
493806
494218
  "thinking.budget": "budget {budget}",
493807
494219
  "thinking.heartbeat": "hidden-thought heartbeat {seconds}s ago",
494220
+ "thinking.hiddenTokens": "thinking {count}",
493808
494221
  "thinking.worked": "Worked {elapsed}",
493809
494222
  "thinking.finished": "done {time}",
493810
494223
  "thinking.emptyRetry": "Empty model response; {hint} · budget {before} → {after}",
@@ -493813,12 +494226,18 @@ registerUiCatalogFragment({
493813
494226
  },
493814
494227
  de: {
493815
494228
  "thinking.label": "{name} denkt",
494229
+ "thinking.activity.reads": "{name} liest",
494230
+ "thinking.activity.writes": "{name} schreibt",
494231
+ "thinking.activity.runs": "{name} führt aus",
494232
+ "thinking.activity.coordinates": "{name} koordiniert",
494233
+ "thinking.activity.plans": "{name} plant",
493816
494234
  "thinking.aborted": "abgebrochen",
493817
494235
  "thinking.step": "Schritt {step}",
493818
494236
  "thinking.effort": "Effort {effort}",
493819
494237
  "thinking.attempt": "Versuch {attempt}/{maxAttempts}",
493820
494238
  "thinking.budget": "Budget {budget}",
493821
494239
  "thinking.heartbeat": "Verdecktes Denken läuft · letzter Takt vor {seconds}s",
494240
+ "thinking.hiddenTokens": "denkt {count}",
493822
494241
  "thinking.worked": "Gearbeitet {elapsed}",
493823
494242
  "thinking.finished": "fertig {time}",
493824
494243
  "thinking.emptyRetry": "Leere Modellantwort; {hint} · Budget {before} → {after}",
@@ -493862,6 +494281,7 @@ function formatLiveStartedAt(startedAtMs) {
493862
494281
  const minute = String(startedAt.getMinutes()).padStart(2, "0");
493863
494282
  return `${day}.${month}. · ${hour}:${minute}`;
493864
494283
  }
494284
+ var { ThinkingActivityRotator, inferThinkingActivityGroup } = createRequire(import.meta.url)("./bin/thinking-activity-status-policy.cjs");
493865
494285
  var ThinkingComponent = class {
493866
494286
  text;
493867
494287
  showMarker;
@@ -493875,13 +494295,17 @@ var ThinkingComponent = class {
493875
494295
  thinkElapsedMs = 0;
493876
494296
  thinkAborted = false;
493877
494297
  estimatedOutputTokens = 0;
494298
+ totalTokenCount = 0;
493878
494299
  step;
493879
494300
  thinkingEffort;
493880
494301
  attempt = 1;
493881
494302
  maxAttempts = 1;
493882
494303
  completionBudget;
493883
494304
  lastHeartbeatAtMs;
494305
+ hiddenThinkingTokens = 0;
493884
494306
  activeToolName;
494307
+ activityGroup = "Thinking";
494308
+ activityRotator = new ThinkingActivityRotator();
493885
494309
  finishedAtMs;
493886
494310
  textComponent;
493887
494311
  renderCache;
@@ -493916,21 +494340,24 @@ var ThinkingComponent = class {
493916
494340
  }
493917
494341
  setLiveMetrics(metrics) {
493918
494342
  if (this.mode === "live" && !this.thinkAborted && metrics.startedAtMs !== void 0) this.thinkStartMs = metrics.startedAtMs;
493919
- const before = JSON.stringify([this.estimatedOutputTokens, this.step, this.thinkingEffort, this.attempt, this.maxAttempts, this.completionBudget, this.lastHeartbeatAtMs, this.activeToolName]);
494343
+ 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]);
493920
494344
  this.estimatedOutputTokens = metrics.estimatedOutputTokens;
493921
494345
  this.applyLiveMetrics(metrics);
493922
- const after = JSON.stringify([this.estimatedOutputTokens, this.step, this.thinkingEffort, this.attempt, this.maxAttempts, this.completionBudget, this.lastHeartbeatAtMs, this.activeToolName]);
494346
+ 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]);
493923
494347
  if (before === after) return;
493924
494348
  this.markRenderDirty();
493925
494349
  }
493926
494350
  applyLiveMetrics(metrics) {
494351
+ this.totalTokenCount = metrics.totalTokenCount ?? 0;
493927
494352
  this.step = metrics.step;
493928
494353
  this.thinkingEffort = metrics.thinkingEffort;
493929
494354
  this.attempt = metrics.attempt ?? 1;
493930
494355
  this.maxAttempts = metrics.maxAttempts ?? 1;
493931
494356
  this.completionBudget = metrics.completionBudget;
493932
494357
  this.lastHeartbeatAtMs = metrics.lastHeartbeatAtMs;
494358
+ this.hiddenThinkingTokens = metrics.hiddenThinkingTokens ?? 0;
493933
494359
  this.activeToolName = metrics.activeToolName;
494360
+ this.activityGroup = metrics.activityGroup ?? "Thinking";
493934
494361
  }
493935
494362
  styled(text) {
493936
494363
  return currentTheme.italicFg("textDim", text);
@@ -493964,26 +494391,29 @@ var ThinkingComponent = class {
493964
494391
  const startedAt = formatLiveStartedAt(this.thinkStartMs ?? Date.now());
493965
494392
  const roundedTokenCount = Math.max(0, Math.round(this.estimatedOutputTokens));
493966
494393
  const tokenCount = formatLiveTokenCount(roundedTokenCount);
493967
- const abortMark = this.thinkAborted ? ` (${uiText("thinking.aborted")})` : "";
493968
- const tokenKey = roundedTokenCount === 1 ? "thinking.tokens.one" : "thinking.tokens.other";
493969
- const thinkingLabel = uiText("thinking.label", { name: this.persona });
493970
- const details = [];
493971
- if (this.step !== void 0) details.push(uiText("thinking.step", { step: this.step }));
493972
- if (this.thinkingEffort !== void 0) details.push(uiText("thinking.effort", { effort: this.thinkingEffort }));
493973
- if (this.attempt > 1 || this.maxAttempts > 1) details.push(uiText("thinking.attempt", { attempt: this.attempt, maxAttempts: this.maxAttempts }));
493974
- if (this.completionBudget !== void 0) details.push(uiText("thinking.budget", { budget: this.completionBudget.toLocaleString(locale) }));
493975
- if (this.lastHeartbeatAtMs !== void 0) details.push(uiText("thinking.heartbeat", { seconds: Math.max(0, Math.floor((Date.now() - this.lastHeartbeatAtMs) / 1e3)) }));
494394
+ const abortMark = this.thinkAborted ? " (aborted)" : "";
494395
+ const thinkingLabel = this.activityRotator.resolve(this.activityGroup, Date.now());
494396
+ const details = [`↓ ~${tokenCount} ${roundedTokenCount === 1 ? "token" : "tokens"}`];
494397
+ if (this.hiddenThinkingTokens > 0) details.push(`thinking ${formatLiveTokenCount(this.hiddenThinkingTokens)}`);
494398
+ if (this.totalTokenCount > 0) details.push(`total ${formatLiveTokenCount(this.totalTokenCount)}`);
494399
+ if (this.thinkingEffort !== void 0) details.push(`thinking with ${this.thinkingEffort} effort`);
494400
+ if (this.step !== void 0) details.push(`step ${this.step}`);
494401
+ if (this.attempt > 1 || this.maxAttempts > 1) details.push(`attempt ${this.attempt}/${this.maxAttempts}`);
494402
+ if (this.completionBudget !== void 0) details.push(`budget ${this.completionBudget.toLocaleString(locale)}`);
494403
+ if (this.lastHeartbeatAtMs !== void 0) details.push(`last hidden-thought tick ${Math.max(0, Math.floor((Date.now() - this.lastHeartbeatAtMs) / 1e3))}s ago`);
493976
494404
  if (this.activeToolName !== void 0) details.push(this.activeToolName);
493977
- const detailText = details.length === 0 ? "" : ` · ${details.join(" · ")}`;
493978
- const fullLabel = `${thinkingLabel}… (${elapsed} · ↓ ~${uiText(tokenKey, { count: tokenCount })}${detailText} · ${startedAt})${abortMark}`;
493979
- const compactLabel = `${thinkingLabel}… (${elapsed} · ↓${tokenCount}${this.step === void 0 ? "" : ` · #${this.step}`} · ${startedAt})${abortMark}`;
494405
+ const fullLabel = `${thinkingLabel}… (${elapsed} · ${details.join(" · ")} · ${startedAt})${abortMark}`;
494406
+ const compactHiddenTokens = this.hiddenThinkingTokens > 0 ? ` · thinking ${formatLiveTokenCount(this.hiddenThinkingTokens)}` : "";
494407
+ const compactTotalTokens = this.totalTokenCount > 0 ? ` · total ${formatLiveTokenCount(this.totalTokenCount)}` : "";
494408
+ const compactEffort = this.thinkingEffort === void 0 ? "" : ` · ${this.thinkingEffort} effort`;
494409
+ const compactLabel = `${thinkingLabel}… (${elapsed} · ↓ ${tokenCount} tokens${compactHiddenTokens}${compactTotalTokens}${compactEffort}${this.step === void 0 ? "" : ` · #${this.step}`} · ${startedAt})${abortMark}`;
493980
494410
  const metricsOnly = `(${elapsed} · ${startedAt})${abortMark}`;
493981
494411
  const availableWidth = Math.max(1, width - visibleWidth(spinner));
493982
494412
  const label = visibleWidth(fullLabel) <= availableWidth ? fullLabel : visibleWidth(compactLabel) <= availableWidth ? compactLabel : metricsOnly;
493983
494413
  rendered = ["", spinner + currentTheme.fg("textDim", truncateToWidth(label, availableWidth))];
493984
494414
  } else if (this.thinkElapsedMs > 0) {
493985
494415
  const finishedAt = new Date(this.finishedAtMs ?? Date.now()).toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit" });
493986
- const finalLabel = `${uiText("thinking.worked", { elapsed: formatLiveElapsed(this.formatElapsedSeconds()) })} · ${uiText("thinking.finished", { time: finishedAt })}`;
494416
+ const finalLabel = `Worked for ${formatLiveElapsed(this.formatElapsedSeconds())} · done ${finishedAt}`;
493987
494417
  rendered = ["", currentTheme.fg("textDim", truncateToWidth(finalLabel, Math.max(1, width)))];
493988
494418
  } else rendered = [""];
493989
494419
  if (isRenderCacheEnabled()) this.renderCache = {
@@ -510557,6 +510987,9 @@ var SessionEventHandler = class {
510557
510987
  case "thinking.delta":
510558
510988
  this.handleThinkingDelta(event);
510559
510989
  break;
510990
+ case "thinking.progress":
510991
+ this.handleThinkingProgress(event);
510992
+ break;
510560
510993
  case "tool.call.started":
510561
510994
  this.handleToolCall(event);
510562
510995
  break;
@@ -510724,7 +511157,10 @@ var SessionEventHandler = class {
510724
511157
  this.clearModelRetryHint();
510725
511158
  this.lastStepFinishReason = event.finishReason;
510726
511159
  this.host.streamingUI.flushNow();
510727
- if (event.usage !== void 0) this.currentTurnTokenCount = (this.currentTurnTokenCount ?? 0) + totalTokenUsage(event.usage);
511160
+ if (event.usage !== void 0) {
511161
+ this.currentTurnTokenCount = (this.currentTurnTokenCount ?? 0) + totalTokenUsage(event.usage);
511162
+ this.host.streamingUI.noteTurnTokenUsage(this.currentTurnTokenCount);
511163
+ }
510728
511164
  this.maybeShowDebugTiming(event);
510729
511165
  if (event.providerFinishReason === "filtered") {
510730
511166
  this.host.showNotice(uiText("sessionEvent.filter.title"), uiText("sessionEvent.filter.detail", { reason: event.rawFinishReason ?? "content_filter" }));
@@ -510814,8 +511250,17 @@ var SessionEventHandler = class {
510814
511250
  }
510815
511251
  handleThinkingDelta(event) {
510816
511252
  const { state, streamingUI } = this.host;
510817
- if (event.delta.length === 0 && !streamingUI.hasThinkingDraft()) return;
510818
- if (event.delta.trim().length === 0) streamingUI.noteThinkingHeartbeat();
511253
+ if (event.delta.trim().length === 0) {
511254
+ streamingUI.noteThinkingHeartbeat();
511255
+ this.turnWatchdog.recordProgress();
511256
+ this.clearModelRetryHint();
511257
+ this.host.patchLivePane({ mode: "idle" });
511258
+ if (state.appState.streamingPhase !== "thinking") this.host.setAppState({
511259
+ streamingPhase: "thinking",
511260
+ streamingStartTime: Date.now()
511261
+ });
511262
+ return;
511263
+ }
510819
511264
  if (event.delta.length > 0) this.turnWatchdog.recordProgress();
510820
511265
  if (event.delta.length > 0) this.clearModelRetryHint();
510821
511266
  streamingUI.appendThinkingDelta(event.delta);
@@ -510826,9 +511271,20 @@ var SessionEventHandler = class {
510826
511271
  });
510827
511272
  streamingUI.scheduleFlush();
510828
511273
  }
511274
+ handleThinkingProgress(event) {
511275
+ const { state, streamingUI } = this.host;
511276
+ this.turnWatchdog.recordProgress();
511277
+ this.clearModelRetryHint();
511278
+ streamingUI.noteThinkingProgress(event.cumulativeTokens);
511279
+ this.host.patchLivePane({ mode: "idle" });
511280
+ if (state.appState.streamingPhase !== "thinking") this.host.setAppState({
511281
+ streamingPhase: "thinking",
511282
+ streamingStartTime: Date.now()
511283
+ });
511284
+ }
510829
511285
  handleAssistantDelta(event) {
510830
511286
  const { state, streamingUI } = this.host;
510831
- if (streamingUI.hasThinkingDraft()) streamingUI.flushThinkingToTranscript("idle");
511287
+ if (streamingUI.hasThinkingDraft() || streamingUI.hasActiveThinkingComponent()) streamingUI.flushThinkingToTranscript("idle");
510832
511288
  if (event.delta.trim().length > 0) {
510833
511289
  this.turnWatchdog.recordProgress();
510834
511290
  this.clearModelRetryHint();
@@ -510850,7 +511306,7 @@ var SessionEventHandler = class {
510850
511306
  handleHookResult(event) {
510851
511307
  if (!shouldDisplayHookResult(event)) return;
510852
511308
  this.host.streamingUI.flushNow();
510853
- if (this.host.streamingUI.hasThinkingDraft()) this.host.streamingUI.flushThinkingToTranscript("idle");
511309
+ if (this.host.streamingUI.hasThinkingDraft() || this.host.streamingUI.hasActiveThinkingComponent()) this.host.streamingUI.flushThinkingToTranscript("idle");
510854
511310
  this.host.streamingUI.finalizeAssistantStream();
510855
511311
  if (event.content.trim().length > 0) {
510856
511312
  this.currentTurnHasAssistantText = true;
@@ -513860,6 +514316,8 @@ var StreamingUIController = class {
513860
514316
  _liveTurnStartedAtMs = void 0;
513861
514317
  _liveStepStartedAtMs = void 0;
513862
514318
  _liveThinkingHeartbeatAtMs = void 0;
514319
+ _liveHiddenThinkingTokens = 0;
514320
+ _liveTurnTokenCount = 0;
513863
514321
  _liveStepRequest = {};
513864
514322
  _liveOutputTokens = new LiveOutputTokenCounter();
513865
514323
  _countedToolCallIds = /* @__PURE__ */ new Set();
@@ -513895,6 +514353,7 @@ var StreamingUIController = class {
513895
514353
  this.setStep(event.step);
513896
514354
  this._liveStepStartedAtMs = Date.now();
513897
514355
  this._liveThinkingHeartbeatAtMs = void 0;
514356
+ this._liveHiddenThinkingTokens = 0;
513898
514357
  this._liveOutputTokens.reset();
513899
514358
  this._countedToolCallIds.clear();
513900
514359
  this._liveStepRequest = {
@@ -513907,6 +514366,7 @@ var StreamingUIController = class {
513907
514366
  noteStepRetry(event) {
513908
514367
  this._liveStepStartedAtMs = Date.now();
513909
514368
  this._liveThinkingHeartbeatAtMs = void 0;
514369
+ this._liveHiddenThinkingTokens = 0;
513910
514370
  this._liveStepRequest = {
513911
514371
  ...this._liveStepRequest,
513912
514372
  attempt: event.nextAttempt,
@@ -513916,6 +514376,18 @@ var StreamingUIController = class {
513916
514376
  }
513917
514377
  noteThinkingHeartbeat() {
513918
514378
  this._liveThinkingHeartbeatAtMs = Date.now();
514379
+ this.onThinkingUpdate(this._thinkingDraft, true);
514380
+ }
514381
+ noteThinkingProgress(cumulativeTokens) {
514382
+ if (!Number.isFinite(cumulativeTokens) || cumulativeTokens < 0) return;
514383
+ this._liveThinkingHeartbeatAtMs = Date.now();
514384
+ this._liveHiddenThinkingTokens = Math.max(this._liveHiddenThinkingTokens, Math.floor(cumulativeTokens));
514385
+ this.onThinkingUpdate(this._thinkingDraft, true);
514386
+ }
514387
+ noteTurnTokenUsage(cumulativeTokens) {
514388
+ if (!Number.isFinite(cumulativeTokens) || cumulativeTokens < 0) return;
514389
+ this._liveTurnTokenCount = Math.max(this._liveTurnTokenCount, Math.floor(cumulativeTokens));
514390
+ this.onThinkingUpdate(this._thinkingDraft, true);
513919
514391
  }
513920
514392
  setRemoteTurnActivity(activity) {
513921
514393
  const previous = this._remoteTurnActivity;
@@ -513947,23 +514419,29 @@ var StreamingUIController = class {
513947
514419
  this._liveTurnStartedAtMs = Date.now();
513948
514420
  this._liveStepStartedAtMs = void 0;
513949
514421
  this._liveThinkingHeartbeatAtMs = void 0;
514422
+ this._liveHiddenThinkingTokens = 0;
514423
+ this._liveTurnTokenCount = 0;
513950
514424
  this._liveStepRequest = {};
513951
514425
  this._liveOutputTokens.reset();
513952
514426
  this._countedToolCallIds.clear();
513953
514427
  this.lastFlushAt = void 0;
513954
514428
  }
513955
514429
  getLiveActivityMetrics() {
513956
- const activeToolName = [...this._activeToolCalls.values()].at(-1)?.name ?? [...this._streamingToolCallArguments.values()].at(-1)?.name;
514430
+ const activeTool = [...this._activeToolCalls.values()].at(-1) ?? [...this._streamingToolCallArguments.values()].at(-1);
514431
+ const activeToolName = activeTool?.name;
513957
514432
  return {
513958
514433
  startedAtMs: this._liveStepStartedAtMs ?? this._liveTurnStartedAtMs,
513959
514434
  estimatedOutputTokens: this._liveOutputTokens.estimatedOutputTokens(),
514435
+ totalTokenCount: this._liveTurnTokenCount,
513960
514436
  step: this._currentStep,
513961
514437
  thinkingEffort: this._liveStepRequest.thinkingEffort,
513962
514438
  completionBudget: this._liveStepRequest.completionBudget,
513963
514439
  attempt: this._liveStepRequest.attempt ?? 1,
513964
514440
  maxAttempts: this._liveStepRequest.maxAttempts ?? 1,
513965
514441
  lastHeartbeatAtMs: this._liveThinkingHeartbeatAtMs,
513966
- activeToolName
514442
+ hiddenThinkingTokens: this._liveHiddenThinkingTokens,
514443
+ activeToolName,
514444
+ activityGroup: inferThinkingActivityGroup(activeTool, { retrying: (this._liveStepRequest.attempt ?? 1) > 1 })
513967
514445
  };
513968
514446
  }
513969
514447
  recordLiveOutput(fragment) {
@@ -514006,6 +514484,7 @@ var StreamingUIController = class {
514006
514484
  this._liveTurnStartedAtMs = void 0;
514007
514485
  this._liveStepStartedAtMs = void 0;
514008
514486
  this._liveThinkingHeartbeatAtMs = void 0;
514487
+ this._liveHiddenThinkingTokens = 0;
514009
514488
  this._liveStepRequest = {};
514010
514489
  this._liveOutputTokens.reset();
514011
514490
  this._countedToolCallIds.clear();
@@ -514463,8 +514942,8 @@ var StreamingUIController = class {
514463
514942
  }
514464
514943
  this._streamingBlock = null;
514465
514944
  }
514466
- onThinkingUpdate(fullText) {
514467
- if (fullText.length === 0 && this._activeThinkingComponent === void 0) return;
514945
+ onThinkingUpdate(fullText, forceLiveStatus = false) {
514946
+ if (fullText.length === 0 && this._activeThinkingComponent === void 0 && !forceLiveStatus) return;
514468
514947
  const { state } = this.host;
514469
514948
  if (this._activeThinkingComponent === void 0) {
514470
514949
  this._pendingAgentGroup = null;
@@ -514476,12 +514955,14 @@ var StreamingUIController = class {
514476
514955
  this._activeThinkingComponent.setText(fullText);
514477
514956
  this._activeThinkingComponent.setLiveMetrics(this.getLiveActivityMetrics());
514478
514957
  }
514958
+ this.host.updateActivityPane();
514479
514959
  state.ui.requestRender();
514480
514960
  }
514481
514961
  onThinkingEnd() {
514482
514962
  if (this._activeThinkingComponent === void 0) return;
514483
514963
  this._activeThinkingComponent.finalize();
514484
514964
  this._activeThinkingComponent = void 0;
514965
+ this.host.updateActivityPane();
514485
514966
  this.host.state.ui.requestRender();
514486
514967
  this.host.mergeCurrentTurnSteps();
514487
514968
  }
@@ -519229,6 +519710,7 @@ var BlunTUI = class {
519229
519710
  async start() {
519230
519711
  this.registerSignalHandlers();
519231
519712
  this.startupWorkspaceSelectionPending = !(this.options.startup.sessionFlag !== void 0 || this.options.startup.continueLast);
519713
+ this.startTelegramChannel();
519232
519714
  try {
519233
519715
  const shouldReplayHistory = await this.initMainTui();
519234
519716
  this.startEventLoop();
@@ -522091,6 +522573,7 @@ var BlunTUI = class {
522091
522573
  this.state.ui.requestRender();
522092
522574
  }
522093
522575
  resolveActivityPaneMode() {
522576
+ if (this.streamingUI.hasActiveThinkingComponent()) return "hidden";
522094
522577
  if (this.state.activeDialog === "session-picker") return "hidden";
522095
522578
  if (this.state.livePane.pendingApproval !== null) return "hidden";
522096
522579
  if (this.state.appState.isCompacting) return "hidden";
@@ -522760,6 +523243,7 @@ async function runShell(opts, version) {
522760
523243
  });
522761
523244
  try {
522762
523245
  log.error("uncaughtException, restoring terminal and exiting", { error: String(error) });
523246
+ getRootInternal().flushSync();
522763
523247
  } catch {}
522764
523248
  emergencyExit(1);
522765
523249
  };
@@ -522771,6 +523255,7 @@ async function runShell(opts, version) {
522771
523255
  });
522772
523256
  try {
522773
523257
  log.error("unhandledRejection, restoring terminal and exiting", { reason: String(reason) });
523258
+ getRootInternal().flushSync();
522774
523259
  } catch {}
522775
523260
  emergencyExit(1);
522776
523261
  };
@@ -523044,6 +523529,7 @@ function installNativeModuleHook() {
523044
523529
  installed = true;
523045
523530
  const moduleBuiltin = nodeRequire("node:module");
523046
523531
  const originalLoad = moduleBuiltin._load;
523532
+ const originalResolveFilename = moduleBuiltin._resolveFilename;
523047
523533
  if (originalLoad === void 0) return;
523048
523534
  moduleBuiltin._load = function loadWithNativeAssets(request, parent, isMain) {
523049
523535
  if (request === "node-pty") {
@@ -523060,6 +523546,13 @@ function installNativeModuleHook() {
523060
523546
  }
523061
523547
  }
523062
523548
  }
523549
+ if (typeof request === "string" && request.toLowerCase().endsWith(".node") && typeof originalResolveFilename === "function") {
523550
+ try {
523551
+ const resolvedRequest = originalResolveFilename.call(moduleBuiltin, request, parent, isMain);
523552
+ const cachedRequest = resolveNativeRuntimePath(resolvedRequest, { packageRoot: __dirname });
523553
+ if (cachedRequest !== resolvedRequest) return originalLoad.call(this, cachedRequest, parent, isMain);
523554
+ } catch {}
523555
+ }
523063
523556
  return originalLoad.call(this, request, parent, isMain);
523064
523557
  };
523065
523558
  }