@monoes/monomindcli 2.9.20 → 2.9.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/helpers/control-start.cjs +7 -1
- package/.claude/skills/mastermind-createorg/SKILL.md +26 -3
- package/dist/src/commands/events.d.ts +9 -0
- package/dist/src/commands/events.d.ts.map +1 -0
- package/dist/src/commands/events.js +89 -0
- package/dist/src/commands/events.js.map +1 -0
- package/dist/src/commands/index.d.ts +1 -1
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +2 -1
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/org-observe.d.ts +21 -0
- package/dist/src/commands/org-observe.d.ts.map +1 -1
- package/dist/src/commands/org-observe.js +88 -6
- package/dist/src/commands/org-observe.js.map +1 -1
- package/dist/src/commands/org.d.ts.map +1 -1
- package/dist/src/commands/org.js +20 -0
- package/dist/src/commands/org.js.map +1 -1
- package/dist/src/orgrt/approvals.d.ts +16 -1
- package/dist/src/orgrt/approvals.d.ts.map +1 -1
- package/dist/src/orgrt/approvals.js +44 -2
- package/dist/src/orgrt/approvals.js.map +1 -1
- package/dist/src/orgrt/copilot-runner.d.ts +14 -0
- package/dist/src/orgrt/copilot-runner.d.ts.map +1 -0
- package/dist/src/orgrt/copilot-runner.js +250 -0
- package/dist/src/orgrt/copilot-runner.js.map +1 -0
- package/dist/src/orgrt/crush-runner.d.ts +24 -0
- package/dist/src/orgrt/crush-runner.d.ts.map +1 -0
- package/dist/src/orgrt/crush-runner.js +251 -0
- package/dist/src/orgrt/crush-runner.js.map +1 -0
- package/dist/src/orgrt/daemon.d.ts +40 -1
- package/dist/src/orgrt/daemon.d.ts.map +1 -1
- package/dist/src/orgrt/daemon.js +68 -4
- package/dist/src/orgrt/daemon.js.map +1 -1
- package/dist/src/orgrt/grok-runner.d.ts +18 -0
- package/dist/src/orgrt/grok-runner.d.ts.map +1 -0
- package/dist/src/orgrt/grok-runner.js +323 -0
- package/dist/src/orgrt/grok-runner.js.map +1 -0
- package/dist/src/orgrt/pi-rpc-runner.d.ts +68 -0
- package/dist/src/orgrt/pi-rpc-runner.d.ts.map +1 -0
- package/dist/src/orgrt/pi-rpc-runner.js +400 -0
- package/dist/src/orgrt/pi-rpc-runner.js.map +1 -0
- package/dist/src/orgrt/pi-runner.d.ts +16 -0
- package/dist/src/orgrt/pi-runner.d.ts.map +1 -0
- package/dist/src/orgrt/pi-runner.js +264 -0
- package/dist/src/orgrt/pi-runner.js.map +1 -0
- package/dist/src/orgrt/qwen-runner.d.ts +18 -0
- package/dist/src/orgrt/qwen-runner.d.ts.map +1 -0
- package/dist/src/orgrt/qwen-runner.js +267 -0
- package/dist/src/orgrt/qwen-runner.js.map +1 -0
- package/dist/src/orgrt/session.js +1 -1
- package/dist/src/orgrt/session.js.map +1 -1
- package/dist/src/orgrt/types.d.ts +21 -0
- package/dist/src/orgrt/types.d.ts.map +1 -1
- package/dist/src/orgrt/types.js +9 -2
- package/dist/src/orgrt/types.js.map +1 -1
- package/dist/src/orgrt/usage-proxy.d.ts +32 -0
- package/dist/src/orgrt/usage-proxy.d.ts.map +1 -0
- package/dist/src/orgrt/usage-proxy.js +226 -0
- package/dist/src/orgrt/usage-proxy.js.map +1 -0
- package/dist/src/ui/dashboard.html +63 -0
- package/dist/src/ui/orgs.html +8 -1
- package/dist/src/ui/routes-org.mjs +26 -0
- package/dist/src/utils/resource-governor.d.ts.map +1 -1
- package/dist/src/utils/resource-governor.js +11 -2
- package/dist/src/utils/resource-governor.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
// packages/@monomind/cli/src/orgrt/crush-runner.ts
|
|
2
|
+
/**
|
|
3
|
+
* CrushAgentRunner — AgentRunner impl backed by the Crush CLI
|
|
4
|
+
* (`crush`, https://github.com/charmbracelet/crush).
|
|
5
|
+
*
|
|
6
|
+
* Architectural difference from the other subprocess runners: `crush run
|
|
7
|
+
* "<prompt>"` (per its public CLI docs) is a plain one-shot invocation —
|
|
8
|
+
* text response to stdout, no documented JSON output mode. On the FIRST turn
|
|
9
|
+
* this runner sends the system prompt + tool protocol; subsequent turns add
|
|
10
|
+
* `--continue` (resume the most-recently-used session — confirmed by
|
|
11
|
+
* cross-checking a second, independent public agentic-CLI wrapper's provider
|
|
12
|
+
* table, which lists `--session <id>` / `--continue` as crush's resume
|
|
13
|
+
* mechanism) instead of re-sending the full system prompt, so conversational
|
|
14
|
+
* context is NOT re-derived from scratch every turn the way the original
|
|
15
|
+
* (pre-cross-check) revision of this runner did.
|
|
16
|
+
*
|
|
17
|
+
* RISK, not independently confirmed either way: if crush's "most recently
|
|
18
|
+
* used session" is scoped GLOBALLY rather than per working directory, two
|
|
19
|
+
* different crush-backed roles running concurrently in the same org (each
|
|
20
|
+
* with its OWN cwd via args.cwd) could cross-contaminate — role B's
|
|
21
|
+
* `--continue` might resume role A's conversation instead of its own. crush
|
|
22
|
+
* DOES support an explicit `--session <id>` flag per the same source, which
|
|
23
|
+
* would be the correct fix (capture the session id crush's own output
|
|
24
|
+
* reports, if any, and pass it explicitly instead of relying on "most
|
|
25
|
+
* recent") — not implemented here because crush's plain-text stdout doesn't
|
|
26
|
+
* appear to surface a session id to capture. Validate against a live
|
|
27
|
+
* install before running multiple concurrent crush roles in one org.
|
|
28
|
+
*
|
|
29
|
+
* Usage accounting — crush's plain-text output carries no token counts, so
|
|
30
|
+
* this runner optionally routes crush's LLM traffic through a
|
|
31
|
+
* UsageProxyServer (usage-proxy.ts): crush supports pointing its provider at
|
|
32
|
+
* a custom OpenAI-compatible base URL for BYOK/self-hosted setups, so the
|
|
33
|
+
* runner sets that env var to the local proxy before spawning and reads
|
|
34
|
+
* totals() after the turn. The exact env var crush reads for a runtime
|
|
35
|
+
* base-URL override was not confirmed against a live install (its provider
|
|
36
|
+
* config is normally a JSON file, `~/.config/crush/crush.json`), so the var
|
|
37
|
+
* name is an OVERRIDABLE BEST GUESS (`OPENAI_BASE_URL`, constructor param
|
|
38
|
+
* `baseUrlEnvVar`) — if it doesn't match your crush config, usage simply
|
|
39
|
+
* stays at 0 (fails closed, never breaks the turn itself). A second,
|
|
40
|
+
* independent source's own integration notes state more confidently that
|
|
41
|
+
* crush has NO base-URL env override at all and instead reads a runtime
|
|
42
|
+
* `provider.base_url` from a generated JSON config file pointed to by an
|
|
43
|
+
* env var — if true, this env-var guess does nothing (which the fails-closed
|
|
44
|
+
* design already tolerates) and the real fix is writing that config file
|
|
45
|
+
* before spawn, not renaming the env var. Left as a known follow-up rather
|
|
46
|
+
* than implemented here, since that source's own claim isn't independently
|
|
47
|
+
* confirmed either. Fix the org's provider config or pass the right var
|
|
48
|
+
* name via `baseUrlEnvVar` once confirmed against a live install.
|
|
49
|
+
*
|
|
50
|
+
* Org tools — FENCE PROTOCOL: same approach as the other subprocess runners.
|
|
51
|
+
*/
|
|
52
|
+
import { spawn } from 'node:child_process';
|
|
53
|
+
import { buildToolProtocol, parseToolCalls, executeToolCall, formatToolResults, MAX_TOOL_ROUNDS, TOOL_CALL_RE } from './tool-fence.js';
|
|
54
|
+
import { UsageProxyServer } from './usage-proxy.js';
|
|
55
|
+
const TURN_TIMEOUT_MS = 2 * 60 * 60 * 1000;
|
|
56
|
+
/** Distinct from TURN_TIMEOUT_MS: catches a hung first-run interactive prompt
|
|
57
|
+
* (trust/telemetry gate) fast instead of waiting out the full turn timeout.
|
|
58
|
+
* Fires only if the process has produced ZERO stdout by this point — any
|
|
59
|
+
* output at all disarms it, since a slow model response is not a hang. */
|
|
60
|
+
const STARTUP_GRACE_MS = 45_000;
|
|
61
|
+
/** Strip tool_call fences and normalize whitespace on crush's plain-text
|
|
62
|
+
* stdout. Exported for unit testing (crush-runner.test.ts). */
|
|
63
|
+
export function parseCrushOutput(stdout) {
|
|
64
|
+
const rawText = stdout.trim();
|
|
65
|
+
const text = rawText.replace(TOOL_CALL_RE, '').trim();
|
|
66
|
+
return { text, rawText };
|
|
67
|
+
}
|
|
68
|
+
export class CrushAgentRunner {
|
|
69
|
+
crushBin;
|
|
70
|
+
usageProxyOpts;
|
|
71
|
+
constructor(opts = {}) {
|
|
72
|
+
this.crushBin = opts.crushBin;
|
|
73
|
+
if (opts.usageProxy) {
|
|
74
|
+
this.usageProxyOpts = {
|
|
75
|
+
upstreamBaseUrl: opts.usageProxy.upstreamBaseUrl,
|
|
76
|
+
baseUrlEnvVar: opts.usageProxy.baseUrlEnvVar ?? 'OPENAI_BASE_URL',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async *run(args) {
|
|
81
|
+
const bin = this.crushBin || process.env.CRUSH_CLI_BIN || 'crush';
|
|
82
|
+
let proxy;
|
|
83
|
+
if (this.usageProxyOpts) {
|
|
84
|
+
proxy = new UsageProxyServer({ upstreamBaseUrl: this.usageProxyOpts.upstreamBaseUrl, apiStyle: 'openai' });
|
|
85
|
+
await proxy.start();
|
|
86
|
+
}
|
|
87
|
+
// Set once the first crush invocation completes — subsequent calls pass
|
|
88
|
+
// --continue (resume the most-recently-used session) instead of
|
|
89
|
+
// re-sending the full system prompt from scratch every turn.
|
|
90
|
+
let sessionStarted = false;
|
|
91
|
+
try {
|
|
92
|
+
for await (const p of args.prompt) {
|
|
93
|
+
const text = typeof p === 'string' ? p : (p?.message?.content ?? String(p ?? ''));
|
|
94
|
+
let nextPrompt = sessionStarted ? text : `${args.systemPrompt}${buildToolProtocol(args.tools)}\n\n---\n\n${text}`;
|
|
95
|
+
// Reset ONCE per mailbox prompt, not per tool-call round — totals()
|
|
96
|
+
// is read after the LAST round below, so resetting inside the round
|
|
97
|
+
// loop was discarding every round's usage except the final one.
|
|
98
|
+
proxy?.reset();
|
|
99
|
+
for (let round = 0; round <= MAX_TOOL_ROUNDS; round++) {
|
|
100
|
+
const outcome = await this.runTurn(bin, nextPrompt, args, proxy, sessionStarted);
|
|
101
|
+
sessionStarted = true;
|
|
102
|
+
if (outcome.hangSuspected) {
|
|
103
|
+
throw new Error(`CrushAgentRunner: crush produced no output within ${STARTUP_GRACE_MS / 1000}s and was killed. ` +
|
|
104
|
+
'This usually means it is stuck on a first-run interactive prompt (trust/telemetry gate) ' +
|
|
105
|
+
'that headless mode has no way to answer. Run `crush` once manually in a real terminal in ' +
|
|
106
|
+
`this project to accept any prompts, then retry.${outcome.stderrTail ? `\nstderr: ${outcome.stderrTail.slice(-500)}` : ''}`);
|
|
107
|
+
}
|
|
108
|
+
if (outcome.exitCode !== 0) {
|
|
109
|
+
throw new Error(`CrushAgentRunner: crush run failed (exit ${outcome.exitCode})` +
|
|
110
|
+
(outcome.timedOut ? ` — killed after exceeding the ${TURN_TIMEOUT_MS / 3_600_000}h turn timeout` : '') +
|
|
111
|
+
(outcome.stderrTail ? `\nstderr: ${outcome.stderrTail.slice(-500)}` : ''));
|
|
112
|
+
}
|
|
113
|
+
if (outcome.text)
|
|
114
|
+
yield { type: 'assistant', text: outcome.text };
|
|
115
|
+
const malformed = [];
|
|
116
|
+
const calls = parseToolCalls([outcome.rawText], (raw, err) => malformed.push(`[monomind] ignored malformed tool_call fence (${err}): ${raw.slice(0, 200)}`));
|
|
117
|
+
for (const note of malformed)
|
|
118
|
+
yield { type: 'assistant', text: note };
|
|
119
|
+
if (calls.length === 0) {
|
|
120
|
+
const totals = proxy?.totals();
|
|
121
|
+
yield {
|
|
122
|
+
type: 'result',
|
|
123
|
+
subtype: 'success',
|
|
124
|
+
input_tokens: totals?.inputTokens ?? 0,
|
|
125
|
+
output_tokens: totals?.outputTokens ?? 0,
|
|
126
|
+
};
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
if (round === MAX_TOOL_ROUNDS) {
|
|
130
|
+
yield { type: 'assistant', text: `[monomind] tool-call round cap (${MAX_TOOL_ROUNDS}) reached — dropping ${calls.length} pending tool call(s)` };
|
|
131
|
+
const totals = proxy?.totals();
|
|
132
|
+
yield { type: 'result', subtype: 'success', input_tokens: totals?.inputTokens ?? 0, output_tokens: totals?.outputTokens ?? 0 };
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
// sessionStarted is true by now (set right after the first
|
|
136
|
+
// runTurn call above) — the retry continues the same crush
|
|
137
|
+
// session via --continue instead of re-sending the system prompt.
|
|
138
|
+
const results = [];
|
|
139
|
+
for (const call of calls)
|
|
140
|
+
results.push(await executeToolCall(args.tools, call, args.canUseTool));
|
|
141
|
+
nextPrompt = formatToolResults(calls, results);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
if (err.code === 'ENOENT') {
|
|
147
|
+
throw new Error('CrushAgentRunner requires the Crush CLI (crush) on PATH. ' +
|
|
148
|
+
'Install it per https://github.com/charmbracelet/crush, then configure a provider. ' +
|
|
149
|
+
'Or unset the runtime to use Claude.');
|
|
150
|
+
}
|
|
151
|
+
throw err;
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
await proxy?.stop();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
runTurn(bin, prompt, args, proxy, continueSession) {
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
159
|
+
const cliArgs = ['run', prompt, '--yolo'];
|
|
160
|
+
if (args.model)
|
|
161
|
+
cliArgs.push('--model', args.model);
|
|
162
|
+
if (continueSession)
|
|
163
|
+
cliArgs.push('--continue');
|
|
164
|
+
// CRUSH_DISABLE_PROVIDER_AUTO_UPDATE: confirmed via crush's own docs —
|
|
165
|
+
// suppresses a first-run/periodic provider-list update check that would
|
|
166
|
+
// otherwise add an unpredictable network round-trip to a headless turn.
|
|
167
|
+
const env = {
|
|
168
|
+
...process.env,
|
|
169
|
+
CRUSH_DISABLE_PROVIDER_AUTO_UPDATE: '1',
|
|
170
|
+
...args.env,
|
|
171
|
+
};
|
|
172
|
+
if (proxy && this.usageProxyOpts)
|
|
173
|
+
env[this.usageProxyOpts.baseUrlEnvVar] = proxy.url();
|
|
174
|
+
const child = spawn(bin, cliArgs, { cwd: args.cwd, env, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
175
|
+
let stderrTail = '';
|
|
176
|
+
child.stderr?.on('data', (c) => { stderrTail = (stderrTail + c.toString()).slice(-4000); });
|
|
177
|
+
let sawOutput = false;
|
|
178
|
+
let timedOut = false;
|
|
179
|
+
let hangSuspected = false;
|
|
180
|
+
const KILL_GRACE_MS = 5000;
|
|
181
|
+
let killTimer;
|
|
182
|
+
const timer = setTimeout(() => {
|
|
183
|
+
timedOut = true;
|
|
184
|
+
child.kill('SIGTERM');
|
|
185
|
+
killTimer = setTimeout(() => { try {
|
|
186
|
+
child.kill('SIGKILL');
|
|
187
|
+
}
|
|
188
|
+
catch { /* already gone */ } }, KILL_GRACE_MS);
|
|
189
|
+
killTimer.unref?.();
|
|
190
|
+
}, TURN_TIMEOUT_MS);
|
|
191
|
+
// See STARTUP_GRACE_MS — disarmed by the first stdout chunk below.
|
|
192
|
+
let hangTimer = setTimeout(() => {
|
|
193
|
+
hangSuspected = true;
|
|
194
|
+
child.kill('SIGTERM');
|
|
195
|
+
killTimer = setTimeout(() => { try {
|
|
196
|
+
child.kill('SIGKILL');
|
|
197
|
+
}
|
|
198
|
+
catch { /* already gone */ } }, KILL_GRACE_MS);
|
|
199
|
+
killTimer.unref?.();
|
|
200
|
+
}, STARTUP_GRACE_MS);
|
|
201
|
+
const exitPromise = new Promise((res, rej) => {
|
|
202
|
+
child.on('error', rej);
|
|
203
|
+
child.on('close', (code) => res(code ?? 1));
|
|
204
|
+
});
|
|
205
|
+
exitPromise.catch(() => { });
|
|
206
|
+
const readStdout = (async () => {
|
|
207
|
+
let stdout = '';
|
|
208
|
+
for await (const chunk of child.stdout) {
|
|
209
|
+
if (!sawOutput) {
|
|
210
|
+
sawOutput = true;
|
|
211
|
+
if (hangTimer) {
|
|
212
|
+
clearTimeout(hangTimer);
|
|
213
|
+
hangTimer = undefined;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
stdout += chunk.toString();
|
|
217
|
+
}
|
|
218
|
+
return stdout;
|
|
219
|
+
})();
|
|
220
|
+
// Timer cleanup lives in a top-level .finally() (not nested inside a
|
|
221
|
+
// success-path .then()) so it runs on EITHER path — a stdout stream
|
|
222
|
+
// error would otherwise skip straight to reject() and leave the
|
|
223
|
+
// TURN_TIMEOUT_MS/hangTimer/killTimer timers running past the
|
|
224
|
+
// process's actual lifetime.
|
|
225
|
+
Promise.all([readStdout, exitPromise])
|
|
226
|
+
.then(([stdout, exitCode]) => {
|
|
227
|
+
const parsed = parseCrushOutput(stdout);
|
|
228
|
+
resolve({ text: parsed.text, rawText: parsed.rawText, exitCode, stderrTail, timedOut, hangSuspected });
|
|
229
|
+
}, (err) => {
|
|
230
|
+
// A stdout stream error (the reject path) means the process is
|
|
231
|
+
// still ALIVE and unmanaged — none of the timeout/hang timers
|
|
232
|
+
// would have fired to kill it. Without this, that error would
|
|
233
|
+
// orphan the child. child.kill() on an already-dead process is a
|
|
234
|
+
// documented no-op, so this is safe on every path.
|
|
235
|
+
try {
|
|
236
|
+
child.kill('SIGTERM');
|
|
237
|
+
}
|
|
238
|
+
catch { /* already gone */ }
|
|
239
|
+
reject(err);
|
|
240
|
+
})
|
|
241
|
+
.finally(() => {
|
|
242
|
+
clearTimeout(timer);
|
|
243
|
+
if (hangTimer)
|
|
244
|
+
clearTimeout(hangTimer);
|
|
245
|
+
if (killTimer)
|
|
246
|
+
clearTimeout(killTimer);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=crush-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crush-runner.js","sourceRoot":"","sources":["../../../src/orgrt/crush-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,7 +14,19 @@ import { type RoleFence } from './fence.js';
|
|
|
14
14
|
* undefined for the default path keeps Claude/Antigravity orgs byte-for-byte
|
|
15
15
|
* unchanged. Callers pass `role.runtime ?? def.runtime` as `orgRuntime`
|
|
16
16
|
* (see resolveRoleRunner). */
|
|
17
|
-
export type RuntimeKind = 'claude' | 'kimicode' | 'opencode' | 'vercel' | 'codex' | 'antigravity'
|
|
17
|
+
export type RuntimeKind = 'claude' | 'kimicode' | 'opencode' | 'vercel' | 'codex' | 'antigravity' | 'grok' | 'qwen' | 'crush' | 'copilot' | 'pi'
|
|
18
|
+
/** Opt-in alternate to 'pi': keeps the pi subprocess alive for the whole
|
|
19
|
+
* mailbox session (--mode rpc) instead of spawning fresh per turn — see
|
|
20
|
+
* pi-rpc-runner.ts's header for the protocol source and its one
|
|
21
|
+
* documented-but-unverified heuristic (turn-completion detection via
|
|
22
|
+
* get_state polling). Prefer plain 'pi' unless you specifically want
|
|
23
|
+
* session-lifetime context continuity and have validated this against a
|
|
24
|
+
* live pi install. No 'qwen-rpc' equivalent exists yet — qwen's
|
|
25
|
+
* --input-format stream-json is real but its exact message schema wasn't
|
|
26
|
+
* independently confirmed the way pi's rpc.md was, so implementing it
|
|
27
|
+
* would mean guessing at a wire format rather than building against a
|
|
28
|
+
* literal, sourced example. */
|
|
29
|
+
| 'pi-rpc';
|
|
18
30
|
export type ProviderKind = 'subscription' | 'api-key' | 'base-url' | 'bedrock' | 'vertex' | 'gemini' | 'openai' | 'vercel-api-key' | 'codex' | 'antigravity';
|
|
19
31
|
export declare function resolveRunner(orgRuntime?: RuntimeKind, providerKind?: ProviderKind): AgentRunner | undefined;
|
|
20
32
|
/** Per-session variant: a role's own `runtime` field wins over the org-level
|
|
@@ -26,6 +38,33 @@ export declare function resolveRoleRunner(roleRuntime?: RuntimeKind, orgRuntime?
|
|
|
26
38
|
/** Per-role token budget: a role's own `budget_tokens` wins; otherwise the
|
|
27
39
|
* even split of run_config.budget_tokens across all roles. */
|
|
28
40
|
export declare function roleTokenBudget(role: OrgRole, def: OrgDef): number;
|
|
41
|
+
/** Idle watchdog's per-tick recovery check: given the previous nudge timestamp,
|
|
42
|
+
* the cumulative nudge count, and the timestamp of the most recent real tool
|
|
43
|
+
* call, returns the nudge count that should carry forward now that fresh
|
|
44
|
+
* activity means the org is no longer idle.
|
|
45
|
+
*
|
|
46
|
+
* `nudgedAt !== 0` means we're recovering from an outstanding nudge. Resetting
|
|
47
|
+
* the counter here means it only ever tracks UNRESOLVED idle spells in a row,
|
|
48
|
+
* not a lifetime total — a long-running org that goes idle and recovers any
|
|
49
|
+
* number of times (e.g. periodic checkpoints on a slow background task) is
|
|
50
|
+
* never punished for having had several separate, healthy idle spells over
|
|
51
|
+
* its lifetime. Before this existed, `nudges` only ever incremented, so a run
|
|
52
|
+
* that answered every single nudge with real work still hit the "org idle
|
|
53
|
+
* again after 3 nudges" cap and got force-stopped on its 4th idle spell —
|
|
54
|
+
* observed live killing an in-progress 24h soak test under 90 minutes in.
|
|
55
|
+
*
|
|
56
|
+
* But "recovering" must mean genuine forward progress, not just any bus
|
|
57
|
+
* event — a bare, content-free reply to the nudge (a boss that answers with
|
|
58
|
+
* "✓ Complete" and calls no tools at all) still updates lastActivity, so the
|
|
59
|
+
* org isn't flagged as silent, but it accomplishes nothing: nobody outside
|
|
60
|
+
* the boss's own turn ever sees it, since role coordination only happens via
|
|
61
|
+
* tool calls (org_send, org_task, ...). Requiring `lastToolActivity >=
|
|
62
|
+
* nudgedAt` — a real tool call happened AFTER this nudge was sent — closes
|
|
63
|
+
* that gap: observed live, a boss stuck responding to four consecutive
|
|
64
|
+
* 10-minute nudges with one-line acknowledgments and zero tool calls looped
|
|
65
|
+
* indefinitely making no progress, because every trivial reply reset the cap
|
|
66
|
+
* that was supposed to catch exactly this. */
|
|
67
|
+
export declare function resolvedIdleNudgeCount(nudgedAt: number, nudges: number, lastToolActivity: number): number;
|
|
29
68
|
/** Bounded ring buffer for agent terminal scrollback. */
|
|
30
69
|
export declare class ScrollbackBuffer {
|
|
31
70
|
private maxLines;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/orgrt/daemon.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAKvC,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,YAAY,EAElB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AASxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/orgrt/daemon.ts"],"names":[],"mappings":"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"}
|
package/dist/src/orgrt/daemon.js
CHANGED
|
@@ -21,6 +21,12 @@ import { KimiCodeAgentRunner } from './kimicode-runner.js';
|
|
|
21
21
|
import { VercelAgentRunner } from './vercel-runner.js';
|
|
22
22
|
import { CodexAgentRunner } from './codex-runner.js';
|
|
23
23
|
import { AntigravityAgentRunner } from './antigravity-runner.js';
|
|
24
|
+
import { GrokAgentRunner } from './grok-runner.js';
|
|
25
|
+
import { QwenAgentRunner } from './qwen-runner.js';
|
|
26
|
+
import { CrushAgentRunner } from './crush-runner.js';
|
|
27
|
+
import { CopilotAgentRunner } from './copilot-runner.js';
|
|
28
|
+
import { PiAgentRunner } from './pi-runner.js';
|
|
29
|
+
import { PiRpcAgentRunner } from './pi-rpc-runner.js';
|
|
24
30
|
import { captureCheckpoint, generateChecksum, validateCheckpoint, isCheckpointExpired, restoreMailboxQueue, } from './checkpoint.js';
|
|
25
31
|
import { loadGlobalFenceConfig, mergeFenceConfigs, createFenceForRole, } from './fence.js';
|
|
26
32
|
// ── Extracted module imports ────────────────────────────────────────────
|
|
@@ -87,6 +93,18 @@ export function resolveRunner(orgRuntime, providerKind) {
|
|
|
87
93
|
return new CodexAgentRunner();
|
|
88
94
|
if (selected === 'antigravity')
|
|
89
95
|
return new AntigravityAgentRunner();
|
|
96
|
+
if (selected === 'grok')
|
|
97
|
+
return new GrokAgentRunner();
|
|
98
|
+
if (selected === 'qwen')
|
|
99
|
+
return new QwenAgentRunner();
|
|
100
|
+
if (selected === 'crush')
|
|
101
|
+
return new CrushAgentRunner();
|
|
102
|
+
if (selected === 'copilot')
|
|
103
|
+
return new CopilotAgentRunner();
|
|
104
|
+
if (selected === 'pi')
|
|
105
|
+
return new PiAgentRunner();
|
|
106
|
+
if (selected === 'pi-rpc')
|
|
107
|
+
return new PiRpcAgentRunner();
|
|
90
108
|
return undefined;
|
|
91
109
|
}
|
|
92
110
|
/** Per-session variant: a role's own `runtime` field wins over the org-level
|
|
@@ -105,6 +123,35 @@ export function resolveRoleRunner(roleRuntime, orgRuntime, roleProviderKind, org
|
|
|
105
123
|
export function roleTokenBudget(role, def) {
|
|
106
124
|
return (role.budget_tokens ?? Math.floor((def.run_config.budget_tokens ?? 1_000_000) / def.roles.length));
|
|
107
125
|
}
|
|
126
|
+
/** Idle watchdog's per-tick recovery check: given the previous nudge timestamp,
|
|
127
|
+
* the cumulative nudge count, and the timestamp of the most recent real tool
|
|
128
|
+
* call, returns the nudge count that should carry forward now that fresh
|
|
129
|
+
* activity means the org is no longer idle.
|
|
130
|
+
*
|
|
131
|
+
* `nudgedAt !== 0` means we're recovering from an outstanding nudge. Resetting
|
|
132
|
+
* the counter here means it only ever tracks UNRESOLVED idle spells in a row,
|
|
133
|
+
* not a lifetime total — a long-running org that goes idle and recovers any
|
|
134
|
+
* number of times (e.g. periodic checkpoints on a slow background task) is
|
|
135
|
+
* never punished for having had several separate, healthy idle spells over
|
|
136
|
+
* its lifetime. Before this existed, `nudges` only ever incremented, so a run
|
|
137
|
+
* that answered every single nudge with real work still hit the "org idle
|
|
138
|
+
* again after 3 nudges" cap and got force-stopped on its 4th idle spell —
|
|
139
|
+
* observed live killing an in-progress 24h soak test under 90 minutes in.
|
|
140
|
+
*
|
|
141
|
+
* But "recovering" must mean genuine forward progress, not just any bus
|
|
142
|
+
* event — a bare, content-free reply to the nudge (a boss that answers with
|
|
143
|
+
* "✓ Complete" and calls no tools at all) still updates lastActivity, so the
|
|
144
|
+
* org isn't flagged as silent, but it accomplishes nothing: nobody outside
|
|
145
|
+
* the boss's own turn ever sees it, since role coordination only happens via
|
|
146
|
+
* tool calls (org_send, org_task, ...). Requiring `lastToolActivity >=
|
|
147
|
+
* nudgedAt` — a real tool call happened AFTER this nudge was sent — closes
|
|
148
|
+
* that gap: observed live, a boss stuck responding to four consecutive
|
|
149
|
+
* 10-minute nudges with one-line acknowledgments and zero tool calls looped
|
|
150
|
+
* indefinitely making no progress, because every trivial reply reset the cap
|
|
151
|
+
* that was supposed to catch exactly this. */
|
|
152
|
+
export function resolvedIdleNudgeCount(nudgedAt, nudges, lastToolActivity) {
|
|
153
|
+
return nudgedAt !== 0 && lastToolActivity >= nudgedAt ? 0 : nudges;
|
|
154
|
+
}
|
|
108
155
|
/** Bounded ring buffer for agent terminal scrollback. */
|
|
109
156
|
export class ScrollbackBuffer {
|
|
110
157
|
maxLines;
|
|
@@ -388,6 +435,16 @@ export class OrgDaemon {
|
|
|
388
435
|
const MAX_COLLECTED = 1000;
|
|
389
436
|
const collected = [];
|
|
390
437
|
let lastActivity = Date.now();
|
|
438
|
+
// Separate from lastActivity: only real tool calls (org_send, org_task,
|
|
439
|
+
// Bash, ...) count here, not status pings or chat-only turns. The idle
|
|
440
|
+
// watchdog's nudge-recovery check (resolvedIdleNudgeCount) uses this to
|
|
441
|
+
// tell genuine forward progress apart from a boss that "answers" a nudge
|
|
442
|
+
// with a bare acknowledgment ("✓ Complete") and does nothing — a
|
|
443
|
+
// content-free reply still updates lastActivity (so the org isn't
|
|
444
|
+
// flagged as silent), but must not reset the cumulative nudge cap, or a
|
|
445
|
+
// boss that's genuinely out of ideas can loop forever making zero
|
|
446
|
+
// progress without ever tripping the watchdog.
|
|
447
|
+
let lastToolActivity = 0;
|
|
391
448
|
bus.subscribe((e) => {
|
|
392
449
|
const slim = e.data?.content != null ? { ...e, data: { ...e.data, content: undefined } } : e;
|
|
393
450
|
collected.push(slim);
|
|
@@ -397,6 +454,8 @@ export class OrgDaemon {
|
|
|
397
454
|
// hung boss would never trip the "nudge produced no activity" stop.
|
|
398
455
|
if (e.reason !== 'idle-nudge')
|
|
399
456
|
lastActivity = Date.now();
|
|
457
|
+
if (e.type === 'tool')
|
|
458
|
+
lastToolActivity = Date.now();
|
|
400
459
|
// org_complete IS the end of the run — self-stop instead of sitting
|
|
401
460
|
// "running" forever after a recorded outcome. Deferred (unref'd) so the
|
|
402
461
|
// tool call's receipt reaches the boss and its final turn text still
|
|
@@ -935,7 +994,8 @@ export class OrgDaemon {
|
|
|
935
994
|
running.agents
|
|
936
995
|
.get(boss.id)
|
|
937
996
|
.mailbox.push(`Org "${name}" started (run ${run}).\nGoal: ${taskOverride ?? def.goal}\n` +
|
|
938
|
-
`Coordinate your team via org_send.
|
|
997
|
+
`Coordinate your team via org_send. Only when the FULL goal above is achieved (or clearly can't be) — not merely "this batch of dispatched tasks finished" — record it with org_complete, then end your turn. ` +
|
|
998
|
+
`If a batch finishes but the goal has more scope left, dispatch the next batch instead of ending the run.${prevBrief}`);
|
|
939
999
|
bus.emit({
|
|
940
1000
|
type: 'status',
|
|
941
1001
|
msg: `org started (${def.roles.length} agents)`,
|
|
@@ -947,8 +1007,9 @@ export class OrgDaemon {
|
|
|
947
1007
|
// org_complete) produces no bus events, and every agent just waits. After
|
|
948
1008
|
// idle_minutes of silence, nudge the boss to complete or reassign; if the
|
|
949
1009
|
// nudge itself produces no activity (boss hung/crashed), or the org keeps
|
|
950
|
-
// going idle after MAX_IDLE_NUDGES nudges
|
|
951
|
-
//
|
|
1010
|
+
// going idle after MAX_IDLE_NUDGES nudges in a row without ever recovering
|
|
1011
|
+
// (see resolvedIdleNudgeCount), stop the run instead of letting it freeze
|
|
1012
|
+
// forever. idle_minutes: 0 disables.
|
|
952
1013
|
const idleMs = (def.run_config.idle_minutes ?? 10) * 60_000;
|
|
953
1014
|
if (idleMs > 0) {
|
|
954
1015
|
const MAX_IDLE_NUDGES = 3;
|
|
@@ -967,6 +1028,7 @@ export class OrgDaemon {
|
|
|
967
1028
|
return;
|
|
968
1029
|
const idleFor = Date.now() - lastActivity;
|
|
969
1030
|
if (idleFor < idleMs) {
|
|
1031
|
+
nudges = resolvedIdleNudgeCount(nudgedAt, nudges, lastToolActivity);
|
|
970
1032
|
nudgedAt = 0;
|
|
971
1033
|
return;
|
|
972
1034
|
}
|
|
@@ -989,7 +1051,9 @@ export class OrgDaemon {
|
|
|
989
1051
|
msg: `no org activity for ${Math.round(idleFor / 60_000)}m — nudging boss (${nudges}/${MAX_IDLE_NUDGES})`,
|
|
990
1052
|
});
|
|
991
1053
|
bossRt.mailbox.push(`[watchdog] No activity in org "${name}" for ${Math.round(idleFor / 60_000)} minute(s). ` +
|
|
992
|
-
`
|
|
1054
|
+
`Check org_tasks first, then pick ONE: (1) the org's full stated goal is achieved or clearly cannot be — call org_complete now (this ends the run for good, not just this batch); ` +
|
|
1055
|
+
`(2) someone has stalled or unstarted work — check on your team via org_send and reassign it; ` +
|
|
1056
|
+
`(3) the current task batch is done but the goal has more scope left — do NOT call org_complete for this case, instead dispatch the next batch of work with org_task/createTask so the org keeps making progress.`);
|
|
993
1057
|
}
|
|
994
1058
|
else if (Date.now() - nudgedAt >= idleMs) {
|
|
995
1059
|
idleStop(`nudge produced no activity for another ${Math.round(idleMs / 60_000)}m — boss appears hung, stopping run`);
|