mixdog 0.9.87 → 0.9.89

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 (167) hide show
  1. package/package.json +13 -7
  2. package/scripts/tool-failures.mjs +60 -24
  3. package/src/agents/heavy-worker/AGENT.md +3 -4
  4. package/src/agents/worker/AGENT.md +1 -2
  5. package/src/cli.mjs +8 -0
  6. package/src/defaults/cycle3-review-prompt.md +4 -4
  7. package/src/rules/agent/00-core.md +3 -0
  8. package/src/rules/agent/42-cycle3-agent.md +5 -6
  9. package/src/rules/lead/01-general.md +2 -0
  10. package/src/rules/shared/01-tool.md +29 -35
  11. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +3 -51
  12. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +59 -0
  13. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -2
  14. package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +67 -0
  15. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +57 -4
  16. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +2 -3
  17. package/src/runtime/agent/orchestrator/config.mjs +29 -11
  18. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -1
  19. package/src/runtime/agent/orchestrator/internal-agents.mjs +1 -1
  20. package/src/runtime/agent/orchestrator/mcp/client.mjs +0 -24
  21. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +3 -3
  22. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +25 -17
  23. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +321 -22
  24. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +35 -22
  25. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +28 -23
  26. package/src/runtime/agent/orchestrator/providers/gemini.mjs +10 -2
  27. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +0 -1
  28. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +0 -1
  29. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +2 -5
  30. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +27 -0
  31. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +23 -0
  32. package/src/runtime/agent/orchestrator/providers/lib/stream-outcome.mjs +329 -0
  33. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +23 -1
  34. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +107 -20
  35. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +4 -3
  36. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +124 -12
  37. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +19 -2
  38. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +1 -1
  39. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +1 -1
  40. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +110 -75
  41. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +96 -113
  42. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +160 -11
  43. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +18 -1
  44. package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +147 -117
  45. package/src/runtime/agent/orchestrator/session/loop/stop-hooks.mjs +88 -0
  46. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +50 -8
  47. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +25 -0
  48. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +1 -1
  49. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +47 -6
  50. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +485 -24
  51. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +100 -2
  52. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -0
  53. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +80 -14
  54. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +142 -2
  55. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +128 -32
  56. package/src/runtime/agent/orchestrator/session/manager.mjs +5 -1
  57. package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +77 -4
  58. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +70 -39
  59. package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +91 -0
  60. package/src/runtime/agent/orchestrator/session/store/listing.mjs +141 -64
  61. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +253 -0
  62. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +211 -28
  63. package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +313 -0
  64. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +622 -53
  65. package/src/runtime/agent/orchestrator/session/store/serialize.mjs +43 -10
  66. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +53 -8
  67. package/src/runtime/agent/orchestrator/session/store/summary-rebuild-worker.mjs +20 -0
  68. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +113 -9
  69. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +2 -0
  70. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +476 -52
  71. package/src/runtime/agent/orchestrator/session/store.mjs +721 -196
  72. package/src/runtime/agent/orchestrator/session/token-native.mjs +2 -4
  73. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +19 -0
  74. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +4 -6
  75. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  76. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +146 -90
  77. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +6 -0
  78. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +93 -17
  79. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +5 -0
  80. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +7 -7
  81. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +6 -1
  82. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +17 -1
  83. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +85 -5
  84. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +52 -0
  85. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +54 -51
  86. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +14 -15
  87. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +132 -8
  88. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +86 -3
  89. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +6 -1
  90. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +210 -38
  91. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +23 -1
  92. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +87 -19
  93. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
  94. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -8
  95. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +12 -2
  96. package/src/runtime/media/lanes.mjs +2 -2
  97. package/src/runtime/media/renditions.mjs +101 -17
  98. package/src/runtime/media/renditions.test.mjs +54 -0
  99. package/src/runtime/media/store.mjs +111 -43
  100. package/src/runtime/media/store.test.mjs +53 -11
  101. package/src/runtime/memory/index.mjs +26 -50
  102. package/src/runtime/memory/lib/core-memory-candidates.mjs +2 -7
  103. package/src/runtime/memory/lib/core-memory-store.mjs +2 -9
  104. package/src/runtime/memory/lib/cycle-scheduler.mjs +10 -0
  105. package/src/runtime/memory/lib/embedding-provider.mjs +3 -3
  106. package/src/runtime/memory/lib/embedding-worker.mjs +60 -15
  107. package/src/runtime/memory/lib/http-router.mjs +4 -0
  108. package/src/runtime/memory/lib/ko-morph.mjs +49 -6
  109. package/src/runtime/memory/lib/memory-action-handlers.mjs +21 -18
  110. package/src/runtime/memory/lib/memory-cycle2.mjs +3 -3
  111. package/src/runtime/memory/lib/memory-cycle3.mjs +1 -3
  112. package/src/runtime/memory/lib/memory-recall-store.mjs +24 -0
  113. package/src/runtime/memory/lib/query-handlers.mjs +26 -28
  114. package/src/runtime/memory/tool-defs.mjs +3 -3
  115. package/src/runtime/shared/atomic-file.mjs +5 -1
  116. package/src/runtime/shared/child-guardian.mjs +73 -2
  117. package/src/runtime/shared/provider-api-key.mjs +22 -5
  118. package/src/runtime/shared/tool-execution-contract.mjs +53 -0
  119. package/src/session-runtime/config-helpers.mjs +6 -5
  120. package/src/session-runtime/lifecycle-api.mjs +16 -4
  121. package/src/session-runtime/media-api.mjs +31 -16
  122. package/src/session-runtime/prewarm.mjs +2 -24
  123. package/src/session-runtime/runtime-core.mjs +33 -15
  124. package/src/session-runtime/runtime-tunables.mjs +0 -3
  125. package/src/session-runtime/session-lifecycle.mjs +0 -6
  126. package/src/session-runtime/session-title.mjs +228 -0
  127. package/src/session-runtime/session-turn-api.mjs +11 -7
  128. package/src/session-runtime/workflow-agents-api.mjs +16 -0
  129. package/src/session-runtime/workflow.mjs +7 -5
  130. package/src/standalone/agent-tool/job-views.mjs +90 -36
  131. package/src/standalone/agent-tool/spawn-flow.mjs +25 -216
  132. package/src/standalone/agent-tool/worker-index.mjs +8 -0
  133. package/src/standalone/agent-tool/worker-rows.mjs +2 -1
  134. package/src/standalone/agent-tool.mjs +17 -17
  135. package/src/standalone/agent-watchdog-registry.mjs +19 -2
  136. package/src/standalone/channel-daemon.mjs +8 -0
  137. package/src/standalone/explore-tool.mjs +1 -1
  138. package/src/standalone/memory-runtime-proxy.mjs +4 -7
  139. package/src/standalone/projects.mjs +4 -1
  140. package/src/standalone/usage-dashboard.mjs +25 -3
  141. package/src/tui/App.jsx +5 -3
  142. package/src/tui/app/resume-picker.mjs +7 -2
  143. package/src/tui/app/route-pickers.mjs +11 -117
  144. package/src/tui/app/slash-dispatch.mjs +13 -3
  145. package/src/tui/app/transcript-row-estimate.mjs +1 -1
  146. package/src/tui/app/transcript-window.mjs +17 -93
  147. package/src/tui/app/use-transcript-scroll.mjs +32 -2
  148. package/src/tui/app/use-transcript-window.mjs +64 -114
  149. package/src/tui/components/Markdown.jsx +19 -2
  150. package/src/tui/components/Message.jsx +8 -3
  151. package/src/tui/components/ToolExecution.jsx +7 -3
  152. package/src/tui/dist/index.mjs +243 -223
  153. package/src/tui/engine/live-share.mjs +15 -5
  154. package/src/tui/engine/render-timing.mjs +2 -2
  155. package/src/tui/engine/session-api-ext.mjs +74 -4
  156. package/src/tui/engine/session-flow.mjs +3 -1
  157. package/src/tui/engine.mjs +2 -2
  158. package/src/tui/hooks/useSharedTick.mjs +0 -2
  159. package/src/tui/index.jsx +5 -5
  160. package/src/ui/statusline-agents.mjs +44 -11
  161. package/src/vendor/statusline/bin/statusline-route.mjs +26 -3
  162. package/src/workflows/default/WORKFLOW.md +3 -3
  163. package/src/workflows/solo/WORKFLOW.md +5 -3
  164. package/src/runtime/media/index.mjs +0 -18
  165. package/src/runtime/memory/lib/embedding-warmup.mjs +0 -68
  166. package/src/standalone/agent-shard/shard-child.mjs +0 -300
  167. package/src/standalone/agent-shard/shard-pool.mjs +0 -443
@@ -1,300 +0,0 @@
1
- // Agent shard child (P1 skeleton — see docs/agent-shard-design.md).
2
- //
3
- // Forked by shard-pool.mjs. Boots the session runtime HEADLESS in this
4
- // process (module singletons initialize from MIXDOG_DATA_DIR config on disk,
5
- // same recipe as the channels worker child) and executes agent WORKER
6
- // sessions on IPC request, so their provider wire encoding and tool
7
- // post-processing CPU never touches the lead's event loop.
8
- //
9
- // IPC protocol (channel-worker style):
10
- // parent→child: { type: 'ping'|'spawn'|'cancel', callId, payload }
11
- // child→parent: { type: 'ready' }
12
- // | { type: 'progress', callId, event, payload }
13
- // | { type: 'result', callId, result|error }
14
- //
15
- // P2 parity in this file: `spawned` progress (lead mirrors tag/row/statusline
16
- // bookkeeping), the SAME idle-progress watchdog the in-process path runs
17
- // (registry lives here because the session state lives here), and the
18
- // watchdog partial-handoff salvage. MCP proxying, cooldown broadcast, and
19
- // tag-reuse routing remain open (design doc).
20
- import process from 'node:process';
21
- import { ensureProcessListenerHeadroom } from '../../runtime/shared/process-listener-headroom.mjs';
22
-
23
- // The session runtime registers several process exit/cleanup hooks; the
24
- // default 10-listener cap emits MaxListenersExceededWarning noise on stderr
25
- // (observed in the first P2 live run).
26
- ensureProcessListenerHeadroom(64);
27
-
28
- function send(msg) {
29
- try { process.send?.(msg); } catch { /* parent gone — exit hook handles */ }
30
- }
31
-
32
- let _bootPromise = null;
33
- function boot() {
34
- _bootPromise ??= (async () => {
35
- const [cfgMod, reg, mgr, sessionBuilder, presetMod, providerInitMod, ownerMod, watchdogMod, watchdogRegistryMod, admissionMod, mcpClientMod, internalToolsMod] = await Promise.all([
36
- import('../../runtime/agent/orchestrator/config.mjs'),
37
- import('../../runtime/agent/orchestrator/providers/registry.mjs'),
38
- import('../../runtime/agent/orchestrator/session/manager.mjs'),
39
- import('../../runtime/agent/orchestrator/agent-runtime/session-builder.mjs'),
40
- import('../agent-tool/spawn-preset.mjs'),
41
- import('../agent-tool/provider-init.mjs'),
42
- import('../../runtime/agent/orchestrator/agent-owner.mjs'),
43
- import('../../runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs'),
44
- import('../agent-watchdog-registry.mjs'),
45
- import('../../runtime/agent/orchestrator/providers/admission-scheduler.mjs'),
46
- import('../../runtime/agent/orchestrator/mcp/client.mjs'),
47
- import('../../runtime/agent/orchestrator/internal-tools.mjs'),
48
- ]);
49
- const { ensureProvider } = providerInitMod.createProviderInit(reg, 120_000);
50
- // Same idle-progress watchdog the in-process spawn path uses — it must
51
- // run HERE because only this process can snapshot/abort its sessions.
52
- const watchdogs = watchdogRegistryMod.createProgressWatchdogRegistry({ mgr });
53
- // 429 fan-out: report locally-recorded cooldowns/resets upward; the
54
- // lead applies them to its own scheduler and rebroadcasts to sibling
55
- // shards so one account's quota window parks every process.
56
- admissionMod.providerAdmissionScheduler.onCooldownEvent?.((event) => {
57
- send({ type: 'rate-limit', payload: event });
58
- });
59
- return { cfgMod, reg, mgr, sessionBuilder, presetMod, ensureProvider, AGENT_OWNER: ownerMod.AGENT_OWNER, watchdogMod, watchdogs, admissionMod, mcpClientMod, internalToolsMod };
60
- })();
61
- return _bootPromise;
62
- }
63
-
64
- // ── Lead-tool proxy (P2 MCP proxy, generalized) ───────────────────────────
65
- // This process has no MCP connections and no internal-tool executor (both
66
- // are lead singletons). The spawn payload carries the lead's tool
67
- // DEFINITIONS; installing them here makes the session tool schema
68
- // byte-identical to an in-process worker, and every call round-trips to the
69
- // lead as a `lead-tool` IPC request.
70
- const LEAD_TOOL_TIMEOUT_MS = 15 * 60 * 1000;
71
- const _leadCalls = new Map();
72
- let _leadCallSeq = 0;
73
-
74
- function _leadToolCall(kind, name, args, callerCtx = null) {
75
- return new Promise((resolve, reject) => {
76
- const callId = `lt${++_leadCallSeq}`;
77
- const timer = setTimeout(() => {
78
- if (_leadCalls.delete(callId)) {
79
- reject(new Error(`lead tool proxy timed out after ${LEAD_TOOL_TIMEOUT_MS}ms (${name})`));
80
- }
81
- }, LEAD_TOOL_TIMEOUT_MS);
82
- timer.unref?.();
83
- _leadCalls.set(callId, { resolve, reject, timer });
84
- try {
85
- send({ type: 'lead-tool', callId, payload: { kind, name, args, callerCtx } });
86
- } catch (error) {
87
- clearTimeout(timer);
88
- _leadCalls.delete(callId);
89
- reject(error);
90
- }
91
- });
92
- }
93
-
94
- function _installLeadToolProxy(rt, leadTools) {
95
- const mcpTools = Array.isArray(leadTools?.mcp) ? leadTools.mcp : [];
96
- const internalTools = Array.isArray(leadTools?.internal) ? leadTools.internal : [];
97
- rt.mcpClientMod.setMcpToolProxy?.({
98
- tools: mcpTools,
99
- call: (name, args) => _leadToolCall('mcp', name, args),
100
- });
101
- if (internalTools.length > 0) {
102
- rt.internalToolsMod.setInternalToolsProvider({
103
- // Forward only the serializable caller context; signal/notifyFn are
104
- // process-local (the tool-level timeout above bounds a hung call).
105
- executor: (name, args, ctx = {}) => _leadToolCall('internal', name, args, {
106
- callerSessionId: ctx.callerSessionId || null,
107
- callerCwd: ctx.callerCwd || null,
108
- clientHostPid: ctx.clientHostPid || null,
109
- routingSessionId: ctx.routingSessionId || null,
110
- shardWorker: true,
111
- }),
112
- tools: internalTools,
113
- });
114
- }
115
- }
116
-
117
- // sessionId → AbortController-ish handle for cancel (P1: close the session).
118
- const _liveSessions = new Set();
119
-
120
- const ops = {
121
- async ping() {
122
- return { pong: true, pid: process.pid };
123
- },
124
- async spawn(payload, ctx = {}) {
125
- const rt = await boot();
126
- const { cfgMod, mgr, sessionBuilder, presetMod, ensureProvider, AGENT_OWNER, watchdogMod, watchdogs } = rt;
127
- const args = payload?.args || {};
128
- const agent = String(args.agent || '').trim();
129
- if (!agent) throw new Error('agent shard spawn: agent is required');
130
- // Refresh the proxy surface BEFORE the session builds its tool list —
131
- // MCP servers reconnect/toggle at runtime on the lead.
132
- _installLeadToolProxy(rt, payload?.leadTools);
133
- const config = cfgMod.loadConfig();
134
- const { presetName, preset } = presetMod.resolveAgentSpawnPreset(config, args);
135
- await ensureProvider(config, preset.provider);
136
- const runtimeSpec = cfgMod.resolveRuntimeSpec(preset, { lane: 'agent', agentId: payload?.tag || agent });
137
- const { session, effectiveCwd } = sessionBuilder.prepareAgentSession({
138
- agent,
139
- presetName,
140
- preset,
141
- runtimeSpec,
142
- owner: AGENT_OWNER,
143
- cwd: payload?.cwd || process.cwd(),
144
- sourceType: 'cli',
145
- sourceName: agent,
146
- parentSessionId: payload?.parentSessionId || null,
147
- ownerSessionId: payload?.ownerSessionId || null,
148
- agentTag: payload?.tag || undefined,
149
- maxLoopIterations: Number(payload?.maxLoopIterations) > 0 ? Number(payload.maxLoopIterations) : undefined,
150
- });
151
- _liveSessions.add(session.id);
152
- if (payload?.tag) _sessionIdByTag.set(String(payload.tag), session.id);
153
- // Session is bound — let the lead mirror its in-process spawn
154
- // bookkeeping (tag map, worker-index row, statusline route,
155
- // SubagentStart) while the loop runs here.
156
- ctx.progress?.('spawned', {
157
- sessionId: session.id,
158
- tag: payload?.tag || null,
159
- agent,
160
- presetName,
161
- provider: preset.provider,
162
- model: preset.model,
163
- effort: preset.effort || null,
164
- fast: preset.fast === true,
165
- cwd: effectiveCwd || payload?.cwd || process.cwd(),
166
- });
167
- const watchdog = watchdogs.start(session.id, watchdogMod.resolveAgentWatchdogPolicy(agent), agent);
168
- const handoffMsgStart = watchdogMod.resolveHandoffMessageStartIndex(mgr.getSession(session.id));
169
- try {
170
- const result = await mgr.askSession(
171
- session.id,
172
- String(payload?.prompt || ''),
173
- args.context || null,
174
- null,
175
- effectiveCwd || payload?.cwd || process.cwd(),
176
- null,
177
- {},
178
- );
179
- return {
180
- sessionId: session.id,
181
- tag: payload?.tag || null,
182
- agent,
183
- presetName,
184
- provider: preset.provider,
185
- model: preset.model,
186
- effort: preset.effort || null,
187
- fast: preset.fast === true,
188
- content: result?.content || '',
189
- terminationReason: result?.terminationReason || null,
190
- };
191
- } catch (error) {
192
- // Watchdog-stall parity with the in-process path: salvage a
193
- // partial handoff from the aborted session instead of surfacing a
194
- // bare failure; the lead completes the task with stallAbort=true.
195
- const partial = watchdogMod.watchdogPartialHandoffFromError(error, mgr.getSession(session.id), handoffMsgStart);
196
- if (partial) {
197
- return {
198
- sessionId: session.id,
199
- tag: payload?.tag || null,
200
- agent,
201
- presetName,
202
- provider: preset.provider,
203
- model: preset.model,
204
- effort: preset.effort || null,
205
- fast: preset.fast === true,
206
- content: partial,
207
- stallAbort: true,
208
- terminationReason: null,
209
- };
210
- }
211
- throw error;
212
- } finally {
213
- watchdog?.stop?.();
214
- _liveSessions.delete(session.id);
215
- if (payload?.tag) _sessionIdByTag.delete(String(payload.tag));
216
- // P1: sessions are one-shot in the shard (tag reuse routes here in
217
- // P2). Close so a long-lived shard cannot accumulate live sessions.
218
- try { mgr.closeSession(session.id, 'agent-shard-complete'); } catch { /* best-effort */ }
219
- }
220
- },
221
- async cancel(payload) {
222
- const rt = await boot();
223
- const id = String(payload?.sessionId || '').trim()
224
- || _sessionIdByTag.get(String(payload?.tag || '').trim())
225
- || '';
226
- if (!id) return { cancelled: false };
227
- try { rt.mgr.closeSession(id, 'agent-shard-cancel'); } catch { /* best-effort */ }
228
- return { cancelled: true };
229
- },
230
- // Tag-reuse routing (P2): a same-tag spawn/send while this shard runs the
231
- // session queues the prompt into the live loop, mirroring the in-process
232
- // busy-session enqueue path.
233
- async enqueue(payload) {
234
- const rt = await boot();
235
- const id = String(payload?.sessionId || '').trim()
236
- || _sessionIdByTag.get(String(payload?.tag || '').trim())
237
- || '';
238
- const session = id ? rt.mgr.getSession(id) : null;
239
- if (!session || session.closed === true || !_liveSessions.has(id)) {
240
- return { queued: false };
241
- }
242
- const prompt = String(payload?.prompt || '');
243
- if (!prompt.trim()) return { queued: false };
244
- const depth = rt.mgr.enqueuePendingMessage(id, prompt);
245
- return { queued: true, sessionId: id, queueDepth: Math.max(1, Number(depth) || 1) };
246
- },
247
- // Cooldown broadcast from the lead (originating from the lead's own 429
248
- // or a sibling shard's report). applyExternalCooldown never re-emits, so
249
- // broadcasts cannot loop.
250
- async cooldown(payload) {
251
- const rt = await boot();
252
- if (payload?.type === 'reset') {
253
- rt.admissionMod.providerAdmissionScheduler.resetCooldowns(payload.provider || null);
254
- return { applied: true };
255
- }
256
- const applied = rt.admissionMod.providerAdmissionScheduler.applyExternalCooldown?.(
257
- payload?.key,
258
- payload?.cooldownUntil,
259
- ) === true;
260
- return { applied };
261
- },
262
- };
263
-
264
- // tag → live shard session id (cancel-by-tag; lead learns sessionId only at completion).
265
- const _sessionIdByTag = new Map();
266
-
267
- process.on('message', (msg) => {
268
- if (!msg || typeof msg !== 'object') return;
269
- const { type, callId, payload } = msg;
270
- if (type === 'lead-tool-result') {
271
- const item = _leadCalls.get(callId);
272
- if (!item) return;
273
- _leadCalls.delete(callId);
274
- clearTimeout(item.timer);
275
- if (msg.error != null) item.reject(new Error(msg.error));
276
- else item.resolve(msg.result);
277
- return;
278
- }
279
- const op = ops[type];
280
- if (typeof op !== 'function') {
281
- if (callId) send({ type: 'result', callId, error: `agent shard: unknown op "${type}"` });
282
- return;
283
- }
284
- const ctx = {
285
- progress: (event, extra) => {
286
- if (callId) send({ type: 'progress', callId, event, payload: extra });
287
- },
288
- };
289
- Promise.resolve()
290
- .then(() => op(payload, ctx))
291
- .then(
292
- (result) => { if (callId) send({ type: 'result', callId, result }); },
293
- (error) => { if (callId) send({ type: 'result', callId, error: error?.message || String(error) }); },
294
- );
295
- });
296
-
297
- // Parent death → no owner: exit rather than run headless forever.
298
- process.on('disconnect', () => process.exit(0));
299
-
300
- send({ type: 'ready', pid: process.pid });