mixdog 1.3.3 → 1.3.5

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 (210) hide show
  1. package/LICENSES/oh-my-pi-MIT.txt +23 -0
  2. package/NOTICE.md +15 -0
  3. package/README.md +11 -0
  4. package/package.json +3 -2
  5. package/scripts/embed-google-oauth-client.mjs +49 -0
  6. package/scripts/lib/test-spawn-ledger.mjs +46 -1
  7. package/scripts/test.mjs +5 -0
  8. package/src/defaults/shipped-history.json +8 -0
  9. package/src/defaults/skills/browser-use/SKILL.md +21 -9
  10. package/src/defaults/skills/setup/SKILL.md +7 -2
  11. package/src/defaults/skills/setup/references/actions.md +82 -27
  12. package/src/defaults/skills/setup/references/surfaces.md +67 -34
  13. package/src/defaults/skills/setup-guide/SKILL.md +3 -3
  14. package/src/lib/keychain-cjs.cjs +359 -29
  15. package/src/rules/agent-mode/AGENT_MODE.md +10 -2
  16. package/src/rules/agent-mode/MIXY.md +12 -0
  17. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +193 -0
  18. package/src/runtime/agent/orchestrator/config.mjs +18 -0
  19. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +2 -2
  20. package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
  21. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
  22. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
  23. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
  24. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
  25. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
  26. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
  27. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +68 -23
  28. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +22 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
  30. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  31. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -3
  32. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +52 -8
  33. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
  34. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
  35. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
  36. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
  37. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +19 -2
  38. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  39. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
  40. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
  41. package/src/runtime/agent/orchestrator/providers/cursor.mjs +7 -0
  42. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
  43. package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
  44. package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
  45. package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
  46. package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
  47. package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
  48. package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
  49. package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
  50. package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
  51. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
  52. package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
  53. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
  54. package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
  55. package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
  56. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
  57. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
  58. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
  59. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
  60. package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
  61. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  62. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
  63. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
  64. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +17 -0
  65. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
  66. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  67. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  68. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -1
  69. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +1 -0
  70. package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
  71. package/src/runtime/agent/orchestrator/providers/registry.mjs +17 -3
  72. package/src/runtime/agent/orchestrator/providers/wire-protobuf-codec.mjs +368 -0
  73. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  74. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +1 -1
  75. package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
  76. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  77. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
  78. package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
  79. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
  80. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
  81. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
  82. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
  83. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
  84. package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
  85. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +15 -3
  86. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +5 -0
  87. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +36 -4
  88. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -0
  89. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +15 -3
  90. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
  91. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
  92. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
  93. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +50 -2
  94. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +3 -0
  95. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +11 -2
  96. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +11 -2
  97. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
  98. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +2 -0
  99. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +14 -0
  100. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -1
  101. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +13 -0
  102. package/src/runtime/agent/orchestrator/session/message-ids.mjs +5 -3
  103. package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
  104. package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
  105. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +0 -2
  106. package/src/runtime/agent/orchestrator/session/routine-result.mjs +11 -2
  107. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
  108. package/src/runtime/agent/orchestrator/session/store-agent-worker-header-cache.mjs +85 -0
  109. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +125 -12
  110. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +11 -5
  111. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +4 -0
  112. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
  113. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +7 -1
  114. package/src/runtime/channels/lib/schedule-errors.mjs +51 -0
  115. package/src/runtime/channels/lib/scheduler.mjs +109 -14
  116. package/src/runtime/channels/lib/schedules-db.mjs +49 -0
  117. package/src/runtime/channels/lib/tool-dispatch.mjs +13 -0
  118. package/src/runtime/channels/lib/worker-main.mjs +9 -0
  119. package/src/runtime/office/com/com-adapter.mjs +17 -1
  120. package/src/runtime/office/com/office-com-host.ps1 +51 -1
  121. package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
  122. package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
  123. package/src/runtime/office/pdf/document-preview.mjs +326 -8
  124. package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
  125. package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
  126. package/src/runtime/office/portable/portable-soffice.mjs +45 -5
  127. package/src/runtime/shared/agent-room-host.mjs +1 -1
  128. package/src/runtime/shared/bot-hops.mjs +62 -2
  129. package/src/runtime/shared/config.mjs +49 -22
  130. package/src/runtime/shared/connector-catalog.d.mts +4 -2
  131. package/src/runtime/shared/connector-catalog.mjs +16 -8
  132. package/src/runtime/shared/developer-options.mjs +32 -1
  133. package/src/runtime/shared/google-oauth-client.generated.json +4 -0
  134. package/src/runtime/shared/google-oauth-client.mjs +34 -9
  135. package/src/runtime/shared/llm/anthropic-betas.mjs +7 -0
  136. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
  137. package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
  138. package/src/runtime/shared/llm/usage-rollup.mjs +4 -383
  139. package/src/runtime/shared/llm/well-formed.mjs +66 -0
  140. package/src/runtime/shared/provider-accounts.mjs +224 -58
  141. package/src/runtime/shared/provider-api-key.mjs +19 -8
  142. package/src/runtime/shared/routine-trigger.mjs +42 -0
  143. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  144. package/src/runtime/shared/transcript-metadata.mjs +38 -0
  145. package/src/runtime/shared/user-data-guard.mjs +30 -2
  146. package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
  147. package/src/session-runtime/agent-home-delivery.mjs +57 -13
  148. package/src/session-runtime/agent-room-delivery.mjs +28 -1
  149. package/src/session-runtime/agent-task-sessions.mjs +292 -79
  150. package/src/session-runtime/agent-tool-routing.mjs +49 -4
  151. package/src/session-runtime/boot/begin.mjs +3 -2
  152. package/src/session-runtime/boot/tools.mjs +4 -0
  153. package/src/session-runtime/bot-chain.mjs +32 -0
  154. package/src/session-runtime/bot-status.mjs +7 -4
  155. package/src/session-runtime/channel-config-api.mjs +63 -17
  156. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +45 -0
  157. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
  158. package/src/session-runtime/internal-tool-executor.mjs +4 -0
  159. package/src/session-runtime/mcp-glue/server-catalog.mjs +7 -1
  160. package/src/session-runtime/mixy-heartbeat.mjs +807 -0
  161. package/src/session-runtime/model-route/route-tuning.mjs +10 -6
  162. package/src/session-runtime/owned-automation-run.mjs +33 -12
  163. package/src/session-runtime/provider-auth/login.mjs +7 -0
  164. package/src/session-runtime/provider-models/row-hydration.mjs +13 -2
  165. package/src/session-runtime/routine-home-turn.mjs +33 -6
  166. package/src/session-runtime/schedule-session-run.mjs +7 -3
  167. package/src/session-runtime/services/agent-tool/close-flow.mjs +14 -2
  168. package/src/session-runtime/services/agent-tool/execute.mjs +6 -1
  169. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +11 -2
  170. package/src/session-runtime/services/agent-tool/render.mjs +3 -1
  171. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
  172. package/src/session-runtime/services/agent-tool/tool-def.mjs +1 -1
  173. package/src/session-runtime/services/channel-admin.mjs +66 -18
  174. package/src/session-runtime/services/channel-worker.mjs +1 -1
  175. package/src/session-runtime/services/provider-admin.mjs +128 -25
  176. package/src/session-runtime/services/schedule-access.mjs +14 -0
  177. package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
  178. package/src/session-runtime/session-create/session-options.mjs +7 -4
  179. package/src/session-runtime/settings-system-api.mjs +16 -1
  180. package/src/session-runtime/setup-tool/executor.mjs +49 -14
  181. package/src/session-runtime/setup-tool/extended-actions.mjs +29 -3
  182. package/src/session-runtime/setup-tool/settings-contract.mjs +65 -4
  183. package/src/session-runtime/setup-tool/tool-defs.mjs +30 -3
  184. package/src/session-runtime/task-session-route.mjs +99 -0
  185. package/src/session-runtime/tool-policy/policy-stage.mjs +5 -2
  186. package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
  187. package/src/session-runtime/tool-surface.mjs +4 -0
  188. package/src/session-runtime/usage-stats-api.mjs +1 -1
  189. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
  190. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
  191. package/src/session-runtime/workspace/transitions.mjs +10 -2
  192. package/src/standalone/daemon-session-control.mjs +88 -20
  193. package/src/standalone/daemon.mjs +8 -0
  194. package/src/standalone/session-protocol.mjs +5 -0
  195. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
  196. package/src/standalone/session-service/session-calls/session-turns.mjs +6 -0
  197. package/src/standalone/session-service.mjs +13 -0
  198. package/src/standalone/session-tool-output.mjs +8 -5
  199. package/src/tui/app/model-options.mjs +2 -0
  200. package/src/tui/dist/index.mjs +335 -172
  201. package/src/tui/session/notice-surface.mjs +17 -1
  202. package/src/tui/session/session-api/integrations.mjs +1 -0
  203. package/src/tui/session/session-api/lifecycle.mjs +8 -0
  204. package/src/tui/session/session-api/settings.mjs +14 -2
  205. package/src/tui/session/turn-stream.mjs +17 -1
  206. package/src/tui/session/turn.mjs +22 -2
  207. package/src/vendor/statusline/src/gateway/claude-current.mjs +0 -58
  208. package/src/vendor/statusline/src/gateway/route-meta.mjs +1 -361
  209. package/src/vendor/statusline/src/gateway/session-routes.mjs +0 -55
  210. package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +0 -285
@@ -35,10 +35,26 @@ export function createNoticeSurface({ getState, set, isDisposed, pushItem, repla
35
35
  // A routine result is a finished sentence, never a raw error to polish;
36
36
  // a group-room row is someone's words, kept verbatim (a pass has none).
37
37
  const value =
38
- options.routine || options.room || options.heldRequest ? String(text ?? '').trim() : polishNoticeText(text);
38
+ options.routine || options.room || options.heldRequest || options.assistant
39
+ ? String(text ?? '').trim()
40
+ : polishNoticeText(text);
39
41
  if (!value && !options.room) return null;
40
42
  const forceTranscript = options.transcript === true;
41
43
  if (!forceTranscript) return pushToast(value, tone, options.ttlMs, options);
44
+ // The agent's own message posted outside a turn (agent-home-delivery.mjs):
45
+ // its reply row, as the stored message restores.
46
+ if (options.assistant) {
47
+ const id = options.messageId || nextId();
48
+ pushItem({
49
+ kind: 'assistant',
50
+ id,
51
+ text: value,
52
+ streaming: false,
53
+ at: Date.now(),
54
+ ...(options.messageId ? { messageId: options.messageId } : {}),
55
+ });
56
+ return id;
57
+ }
42
58
  const userRow = options.room?.kind === 'user';
43
59
  // A room user row keeps its message id (the sender's submission id), as a
44
60
  // turn's own prompt row keeps its submission id.
@@ -138,6 +138,7 @@ export function createSessionIntegrationsApi(bag, { oauthFlows }) {
138
138
  (input) => runtime.saveCustomProvider(input),
139
139
  (result) => `custom provider saved: ${result.id}`
140
140
  ),
141
+ saveCustomProviderKey: (id, secret) => runtime.saveCustomProviderKey(id, secret),
141
142
  updateCustomProviderModel: (id, modelId, patch) => runtime.updateCustomProviderModel(id, modelId, patch),
142
143
  setModelPreferences: (provider, changes) => runtime.setModelPreferences(provider, changes),
143
144
  removeCustomProvider: async (id) => {
@@ -81,6 +81,14 @@ export function createSessionLifecycleApi(bag, { restoreTranscriptItems, oauthFl
81
81
  pushNotice,
82
82
  removeNotice,
83
83
  setProgressHint,
84
+ // A bot's emoji reactions on a user message (message-reactions.mjs): its
85
+ // live row shows them at once; false when the live rows do not hold it.
86
+ setMessageReactions: (messageId, reactions) => {
87
+ const row = bag
88
+ .getState()
89
+ .items.findLast((item) => item?.kind === 'user' && messageId && item.messageId === messageId);
90
+ return row ? bag.patchItem(row.id, { reactions: Array.isArray(reactions) ? reactions : [] }) : false;
91
+ },
84
92
  ...createSessionResetActions(bag),
85
93
  listSessions: (options) => {
86
94
  return runtime.listSessions(options);
@@ -34,8 +34,8 @@ export function createSessionSettingsApi(bag) {
34
34
  // refused: another command's lock does not block a selection.
35
35
  setModel: async (m) => (await bag.setSessionRoute({ model: m })) !== false,
36
36
  setEffort: withCommandLock(
37
- async (value) => {
38
- await runtime.setEffort(value);
37
+ async (value, options) => {
38
+ await runtime.setEffort(value, options);
39
39
  set({ ...routeState() });
40
40
  return runtime.effort || 'auto';
41
41
  },
@@ -112,6 +112,18 @@ export function createSessionSettingsApi(bag) {
112
112
  setAiSessionTitles: withCommandLock(async (enabled) => {
113
113
  return await runtime.setAiSessionTitles?.(enabled);
114
114
  }),
115
+ getHeartbeatSettings: () => {
116
+ return runtime.getHeartbeatSettings?.() || { heartbeat: true };
117
+ },
118
+ setHeartbeatEnabled: withCommandLock(async (enabled) => {
119
+ return await runtime.setHeartbeatEnabled?.(enabled);
120
+ }),
121
+ getReactionSettings: () => {
122
+ return runtime.getReactionSettings?.() || { reactions: true };
123
+ },
124
+ setReactionsEnabled: withCommandLock(async (enabled) => {
125
+ return await runtime.setReactionsEnabled?.(enabled);
126
+ }),
115
127
  getLeadAppearance: () => {
116
128
  return runtime.getLeadAppearance?.() || { avatar: null };
117
129
  },
@@ -40,6 +40,9 @@ export function createTurnStream(deps) {
40
40
  // (`commentary` / `final_answer`), or null; the desktop row carries it.
41
41
  phase: null,
42
42
  thinkingText: '',
43
+ // Length of thinkingText when the current provider send began: a
44
+ // `reasoning` retraction drops only what that send added.
45
+ thinkingSendMark: 0,
43
46
  thinkingStartedAt: 0,
44
47
  thinkingSegmentStartedAt: 0,
45
48
  accumulatedThinkingMs: 0,
@@ -492,9 +495,20 @@ export function appendReasoningDelta(stream, chunk) {
492
495
  scheduleStreamFlush(stream);
493
496
  }
494
497
 
498
+ // A provider send (one model request of the turn) begins: the thinking so far
499
+ // belongs to earlier sends and survives a retraction of this one.
500
+ export function markThinkingSendStart(stream) {
501
+ stream.thinkingSendMark = stream.thinkingText.length;
502
+ }
503
+
495
504
  export function resetStreamedText(stream, { chars, reasoning } = {}) {
496
505
  const count = Math.max(0, Number(chars) || 0);
497
- if (reasoning) endThinkingForText(stream);
506
+ if (reasoning) {
507
+ endThinkingForText(stream);
508
+ // The discarded attempt's thinking must not prefix the next attempt's;
509
+ // earlier sends' thinking stays.
510
+ stream.thinkingText = stream.thinkingText.slice(0, stream.thinkingSendMark);
511
+ }
498
512
  if (!count) return reasoning === true;
499
513
  flushStreamBatch(stream);
500
514
  stream.assistantText = stream.assistantText.slice(0, Math.max(0, stream.assistantText.length - count));
@@ -529,6 +543,8 @@ export function resetStreamedText(stream, { chars, reasoning } = {}) {
529
543
  // tool phase (`spinnerMode`: 'task-wait' or 'tool-use').
530
544
  export function closeThinkingForToolBatch(stream, spinnerMode) {
531
545
  const { getState, set } = stream;
546
+ // The send that produced this batch is complete; its thinking is kept.
547
+ markThinkingSendStart(stream);
532
548
  if (stream.thinkingText && getState().thinking) {
533
549
  const thinkingLastEndedAt = closeThinkingSegment(stream);
534
550
  set({
@@ -23,6 +23,10 @@ import { isRejected429 } from '../../runtime/shared/error-presentation.mjs';
23
23
  import { QUOTA_KINDS, providerErrorKind } from '../../runtime/agent/orchestrator/providers/provider-error-kind.mjs';
24
24
  import { turnFailureRecord } from '../../runtime/agent/orchestrator/session/turn-failure.mjs';
25
25
  import { registerTaskWaitSteeringCheck } from '../../runtime/agent/orchestrator/session/task-wait-control.mjs';
26
+ import {
27
+ isReactionSuccess,
28
+ reactionCallIds,
29
+ } from '../../runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs';
26
30
  import { promptDisplayText, STEERING_SUPPRESSED_DISPLAY } from './queue-helpers.mjs';
27
31
  import { yieldToRenderer } from './render-timing.mjs';
28
32
  import { archiveItemsForCompaction, compactionArchivedRows } from './compaction-view.mjs';
@@ -35,6 +39,7 @@ import {
35
39
  appendTextDelta,
36
40
  appendAssistantText,
37
41
  appendReasoningDelta,
42
+ markThinkingSendStart,
38
43
  noteAssistantPhase,
39
44
  resetStreamedText,
40
45
  applyStageChange,
@@ -152,6 +157,9 @@ function beginTurn({ flags, getState, transcriptRouteMetadata }, options) {
152
157
  askResult: null,
153
158
  finishedNormally: false,
154
159
  transcriptCompacted: false,
160
+ // Ids of this turn's react calls; `reacted` is set once one succeeds.
161
+ reactionCallIds: new Set(),
162
+ reacted: false,
155
163
  };
156
164
  }
157
165
 
@@ -403,10 +411,15 @@ export function toolHandlers(ctx) {
403
411
  if (isCurrentTurn()) settleSegmentBeforeToolCall(ctx);
404
412
  },
405
413
  onToolCall: async (_iter, calls) => {
406
- if (isCurrentTurn()) await openToolCalls(ctx, calls);
414
+ if (!isCurrentTurn()) return;
415
+ for (const id of reactionCallIds(calls)) ctx.turn.reactionCallIds.add(id);
416
+ await openToolCalls(ctx, calls);
407
417
  },
408
418
  onToolResult: (message) => {
409
419
  if (!isCurrentTurn()) return;
420
+ // A reaction that landed on the user's message is this turn's output
421
+ // even with no reply text; a rejected or failed react call is not.
422
+ if (isReactionSuccess(message, ctx.turn.reactionCallIds)) ctx.turn.reacted = true;
410
423
  try {
411
424
  options.onToolResult?.(message);
412
425
  } catch {}
@@ -440,7 +453,9 @@ export function streamHandlers(ctx) {
440
453
  const { isCurrentTurn, stream } = ctx;
441
454
  return {
442
455
  onProviderSendStarted: () => {
443
- if (isCurrentTurn()) markLiveCallRequestStart(stream);
456
+ if (!isCurrentTurn()) return;
457
+ markThinkingSendStart(stream);
458
+ markLiveCallRequestStart(stream);
444
459
  },
445
460
  onStageChange: async (stage, detail = null) => {
446
461
  if (!isCurrentTurn()) return;
@@ -554,6 +569,9 @@ export function turnDoneItem({ turn, stream, cards, getState, nextId }) {
554
569
  outputTokens: finalOutputTokens(stream, getState().spinner?.outputTokens),
555
570
  thinkingElapsedMs: stream.thinkingStartedAt ? stream.accumulatedThinkingMs : 0,
556
571
  toolCount: cards.toolCards.length,
572
+ // Its answer may be a reaction alone: readers of the turn's final answer
573
+ // take it as done with nothing to say (session-final-answer.ts).
574
+ ...(turn.reacted ? { reacted: true } : {}),
557
575
  verb: turn.completionVerb,
558
576
  at: Date.now(),
559
577
  ...(turn.failureDetail ? { detail: turn.failureDetail } : {}),
@@ -577,9 +595,11 @@ function publishTurnClose(ctx, closingItems) {
577
595
  const assistantOutput = (stream.currentAssistantText || stream.assistantText || '').trim();
578
596
  // Suppress only true pending-resume no-ops: no transcript items added and
579
597
  // no model output; cancelled/error turns and any visible turn stay marked.
598
+ // A turn whose only output was a reaction ends with its turndone row too.
580
599
  const isNoOpTurn =
581
600
  turn.finishedNormally &&
582
601
  !turn.cancelled &&
602
+ !turn.reacted &&
583
603
  cards.toolCards.length === 0 &&
584
604
  !resultContent &&
585
605
  !assistantOutput &&
@@ -5,7 +5,6 @@ import { getModelMetadataSync } from '../../../../runtime/shared/llm/model-catal
5
5
  import { providerCachedModelsSync } from '../../../../runtime/shared/llm/provider-catalog-cache.mjs';
6
6
 
7
7
  export const CLAUDE_CURRENT_MODE = 'claude-current';
8
- export const CLAUDE_CURRENT_CHOICE_ID = 'claude-current';
9
8
 
10
9
  const DEFAULT_FAMILY_MODEL = Object.freeze({
11
10
  opus: 'claude-opus-4-8',
@@ -20,7 +19,6 @@ const EFFORT_BUDGET = Object.freeze({
20
19
  xhigh: 32768,
21
20
  max: 32768,
22
21
  });
23
- const SNAPSHOT_REFRESH_MS = 30_000;
24
22
 
25
23
  function cleanString(v) {
26
24
  return typeof v === 'string' && v.trim() ? v.trim() : '';
@@ -33,15 +31,6 @@ export function isMixdogModelSelection(value) {
33
31
  return cleanString(raw).toLowerCase().startsWith('mixdog/');
34
32
  }
35
33
 
36
- export function isClaudeNativeModelSelection(route) {
37
- return !!(
38
- route &&
39
- route.provider === 'anthropic-oauth' &&
40
- cleanString(route.model) &&
41
- !isMixdogModelSelection(route)
42
- );
43
- }
44
-
45
34
  function num(v, fallback = null) {
46
35
  if (v === null || v === undefined || v === '') return fallback;
47
36
  const n = Number(v);
@@ -80,23 +69,6 @@ function readFreshJsonFile(file, maxAgeMs) {
80
69
  }
81
70
  }
82
71
 
83
- function snapshotEquivalent(a, b) {
84
- if (!a || !b) return false;
85
- const keys = [
86
- 'mode',
87
- 'source',
88
- 'provider',
89
- 'model',
90
- 'requestedModel',
91
- 'modelDisplay',
92
- 'effort',
93
- 'fast',
94
- 'thinkingBudgetTokens',
95
- 'contextWindow',
96
- ];
97
- return keys.every(k => (a[k] ?? null) === (b[k] ?? null));
98
- }
99
-
100
72
  // The newest roster model of a family, by the roster's own release stamps.
101
73
  function newestRosterModel(family) {
102
74
  const stamp = (row) => Date.parse(row.releaseDate) || (Number(row.created) > 0 ? Number(row.created) : 0);
@@ -298,33 +270,3 @@ export function readClaudeCodeCurrentRoute({ request = null, maxAgeMs = 10 * 60
298
270
  if (route.fast === null || route.fast === undefined) route.fast = false;
299
271
  return route;
300
272
  }
301
-
302
- export function writeClaudeCodeCurrentSnapshot(ccJsonInput) {
303
- if (!ccJsonInput) return null;
304
- let payload = null;
305
- try { payload = JSON.parse(String(ccJsonInput)); } catch { return null; }
306
- const route = routeFromPayload(payload, 'statusline');
307
- if (!route || (!route.model && !route.requestedModel)) return null;
308
- const file = path.join(pluginDataDir(), 'claude-current-model.json');
309
- try {
310
- fs.mkdirSync(path.dirname(file), { recursive: true });
311
- const st = fs.existsSync(file) ? fs.statSync(file) : null;
312
- const current = st ? readJsonFile(file) : null;
313
- if (
314
- st &&
315
- Date.now() - st.mtimeMs < SNAPSHOT_REFRESH_MS &&
316
- snapshotEquivalent(current, route)
317
- ) {
318
- return route;
319
- }
320
- fs.writeFileSync(file, JSON.stringify(route, null, 2) + '\n');
321
- } catch { /* best-effort statusline cache */ }
322
- return route;
323
- }
324
-
325
- export function formatClaudeCurrentChoiceLabel(route = readClaudeCodeCurrentRoute()) {
326
- const parts = [`Current selection: ${route.modelDisplay || route.model || 'current model'}`];
327
- if (route.effort) parts.push(String(route.effort).toUpperCase());
328
- if (route.fast === true) parts.push('fast');
329
- return parts.join(' · ');
330
- }