@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,264 @@
|
|
|
1
|
+
// packages/@monomind/cli/src/orgrt/pi-runner.ts
|
|
2
|
+
/**
|
|
3
|
+
* PiAgentRunner — AgentRunner impl backed by the Pi coding agent CLI
|
|
4
|
+
* (`pi`, https://github.com/badlogic/pi-mono, package @mariozechner/pi-coding-agent).
|
|
5
|
+
*
|
|
6
|
+
* Architectural pattern: SAME as the other subprocess runners — spawn the
|
|
7
|
+
* CLI, parse its output, normalize to AgentMessage.
|
|
8
|
+
*
|
|
9
|
+
* Auth: pi's own provider login (per-provider API key or subscription,
|
|
10
|
+
* configured via `pi` itself). No env vars set here.
|
|
11
|
+
*
|
|
12
|
+
* Subprocess protocol — per public docs (pi-mono's rpc.md + README), NOT
|
|
13
|
+
* byte-verified against a running binary. `pi --mode json` shares its event
|
|
14
|
+
* vocabulary with pi's RPC mode:
|
|
15
|
+
* - Invocation: `pi --mode json --approve --session-dir <dir> "<prompt>"`.
|
|
16
|
+
* The prompt is POSITIONAL (matching pi's own interactive-mode CLI shape
|
|
17
|
+
* and the same convention codex uses) — an earlier revision of this
|
|
18
|
+
* runner passed it via a `-p` flag, which a second-source cross-check
|
|
19
|
+
* against another public agentic-CLI wrapper's tool table indicated was
|
|
20
|
+
* wrong; corrected here. `--approve` accepts the cwd as a trusted
|
|
21
|
+
* project so pi doesn't stop to ask (pi has no single "yolo" flag; tool
|
|
22
|
+
* auto-approval for individual actions is a separate, not-yet-wired
|
|
23
|
+
* concern for this runner — org tool calls go through canUseTool
|
|
24
|
+
* regardless, since they use the tool-fence protocol, not pi's native
|
|
25
|
+
* tool surface).
|
|
26
|
+
* (`--session-dir` also gives turn-to-turn continuity: pi persists
|
|
27
|
+
* sessions in that directory and resumes the latest one by default —
|
|
28
|
+
* there is no confirmed explicit `--resume <id>` flag for headless use,
|
|
29
|
+
* so this runner points every turn at the SAME per-run session dir
|
|
30
|
+
* rather than tracking a session id, and disclaims true cross-process
|
|
31
|
+
* resume as best-effort).
|
|
32
|
+
* - Event types seen: `agent_start` (ignored), `message_update` (partial;
|
|
33
|
+
* carries a cumulative `usage` object — kept as running totals but
|
|
34
|
+
* superseded by `message_end`), `message_end` (final `content` array
|
|
35
|
+
* with `{type:'text', text}` / `{type:'toolCall', ...}` items — only
|
|
36
|
+
* `text` items are surfaced to the bus), `tool_execution_*` (ignored;
|
|
37
|
+
* org tool calls use the shared tool-fence protocol, not pi's native
|
|
38
|
+
* tool-call surface).
|
|
39
|
+
* - Usage field names differ from the other CLIs: `usage.input` /
|
|
40
|
+
* `usage.output` (not `input_tokens`/`output_tokens`).
|
|
41
|
+
*
|
|
42
|
+
* Org tools — FENCE PROTOCOL: same approach as the other subprocess runners.
|
|
43
|
+
*/
|
|
44
|
+
import { spawn } from 'node:child_process';
|
|
45
|
+
import { join } from 'node:path';
|
|
46
|
+
import { buildToolProtocol, parseToolCalls, executeToolCall, formatToolResults, MAX_TOOL_ROUNDS, TOOL_CALL_RE } from './tool-fence.js';
|
|
47
|
+
const TURN_TIMEOUT_MS = 2 * 60 * 60 * 1000;
|
|
48
|
+
/** Distinct from TURN_TIMEOUT_MS: catches a hung first-run interactive prompt
|
|
49
|
+
* fast instead of waiting out the full turn timeout. Any output at all
|
|
50
|
+
* disarms it. Per pi's own docs, `-p`/`--mode json`/`--mode rpc` do NOT show
|
|
51
|
+
* a trust prompt (see this file's --approve comment above), so this is a
|
|
52
|
+
* defensive backstop rather than a known risk the way it is for copilot. */
|
|
53
|
+
const STARTUP_GRACE_MS = 45_000;
|
|
54
|
+
/** Pure JSON-event parser — exported for unit testing against fixture lines
|
|
55
|
+
* (pi-runner.test.ts). */
|
|
56
|
+
export function parsePiEvents(lines) {
|
|
57
|
+
const rawTexts = [];
|
|
58
|
+
let inputTokens = 0;
|
|
59
|
+
let outputTokens = 0;
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
const trimmed = line.trim();
|
|
62
|
+
if (!trimmed || !trimmed.startsWith('{'))
|
|
63
|
+
continue;
|
|
64
|
+
let ev;
|
|
65
|
+
try {
|
|
66
|
+
ev = JSON.parse(trimmed);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (ev.type === 'message_end' && ev.message?.content) {
|
|
72
|
+
const text = ev.message.content
|
|
73
|
+
.filter((b) => b.type === 'text' && typeof b.text === 'string')
|
|
74
|
+
.map((b) => b.text)
|
|
75
|
+
.join('\n');
|
|
76
|
+
if (text)
|
|
77
|
+
rawTexts.push(text);
|
|
78
|
+
}
|
|
79
|
+
const usage = ev.message?.usage ?? ev.usage;
|
|
80
|
+
if (usage && (typeof usage.input === 'number' || typeof usage.output === 'number')) {
|
|
81
|
+
inputTokens = usage.input ?? inputTokens;
|
|
82
|
+
outputTokens = usage.output ?? outputTokens;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const texts = rawTexts.map((t) => t.replace(TOOL_CALL_RE, '').trim());
|
|
86
|
+
return { texts, rawTexts, inputTokens, outputTokens };
|
|
87
|
+
}
|
|
88
|
+
export class PiAgentRunner {
|
|
89
|
+
piBin;
|
|
90
|
+
constructor(piBin) {
|
|
91
|
+
this.piBin = piBin;
|
|
92
|
+
}
|
|
93
|
+
async *run(args) {
|
|
94
|
+
const bin = this.piBin || process.env.PI_CLI_BIN || 'pi';
|
|
95
|
+
// Stable per-run session directory — see file header on why this
|
|
96
|
+
// substitutes for an explicit resume-by-id flag.
|
|
97
|
+
const sessionDir = join(args.cwd, '.monomind-pi-session');
|
|
98
|
+
try {
|
|
99
|
+
let first = true;
|
|
100
|
+
for await (const p of args.prompt) {
|
|
101
|
+
const text = typeof p === 'string' ? p : (p?.message?.content ?? String(p ?? ''));
|
|
102
|
+
let nextPrompt = first ? `${args.systemPrompt}${buildToolProtocol(args.tools)}\n\n---\n\n${text}` : text;
|
|
103
|
+
first = false;
|
|
104
|
+
let turnInputTokens = 0;
|
|
105
|
+
let turnOutputTokens = 0;
|
|
106
|
+
for (let round = 0; round <= MAX_TOOL_ROUNDS; round++) {
|
|
107
|
+
const outcome = await this.runTurn(bin, nextPrompt, sessionDir, args);
|
|
108
|
+
if (outcome.hangSuspected) {
|
|
109
|
+
throw new Error(`PiAgentRunner: pi produced no output within ${STARTUP_GRACE_MS / 1000}s and was killed. ` +
|
|
110
|
+
'This usually means it is stuck on a prompt headless mode has no way to answer — pi\'s own ' +
|
|
111
|
+
'docs say --mode json should not show a trust prompt, so this is unexpected. Run `pi` once ' +
|
|
112
|
+
`manually in a real terminal in this project to check, then retry.${outcome.stderrTail ? `\nstderr: ${outcome.stderrTail.slice(-500)}` : ''}`);
|
|
113
|
+
}
|
|
114
|
+
if (outcome.exitCode !== 0) {
|
|
115
|
+
throw new Error(`PiAgentRunner: pi failed (exit ${outcome.exitCode})` +
|
|
116
|
+
(outcome.timedOut ? ` — killed after exceeding the ${TURN_TIMEOUT_MS / 3_600_000}h turn timeout` : '') +
|
|
117
|
+
(outcome.stderrTail ? `\nstderr: ${outcome.stderrTail.slice(-500)}` : ''));
|
|
118
|
+
}
|
|
119
|
+
for (const t of outcome.texts) {
|
|
120
|
+
if (t.trim())
|
|
121
|
+
yield { type: 'assistant', text: t };
|
|
122
|
+
}
|
|
123
|
+
turnInputTokens += outcome.inputTokens;
|
|
124
|
+
turnOutputTokens += outcome.outputTokens;
|
|
125
|
+
const malformed = [];
|
|
126
|
+
const calls = parseToolCalls(outcome.rawTexts, (raw, err) => malformed.push(`[monomind] ignored malformed tool_call fence (${err}): ${raw.slice(0, 200)}`));
|
|
127
|
+
for (const note of malformed)
|
|
128
|
+
yield { type: 'assistant', text: note };
|
|
129
|
+
if (calls.length === 0)
|
|
130
|
+
break;
|
|
131
|
+
if (round === MAX_TOOL_ROUNDS) {
|
|
132
|
+
yield { type: 'assistant', text: `[monomind] tool-call round cap (${MAX_TOOL_ROUNDS}) reached — dropping ${calls.length} pending tool call(s)` };
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
const results = [];
|
|
136
|
+
for (const call of calls)
|
|
137
|
+
results.push(await executeToolCall(args.tools, call, args.canUseTool));
|
|
138
|
+
nextPrompt = formatToolResults(calls, results);
|
|
139
|
+
}
|
|
140
|
+
yield {
|
|
141
|
+
type: 'result',
|
|
142
|
+
subtype: 'success',
|
|
143
|
+
input_tokens: turnInputTokens,
|
|
144
|
+
output_tokens: turnOutputTokens,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
if (err.code === 'ENOENT') {
|
|
150
|
+
throw new Error('PiAgentRunner requires the Pi coding agent CLI (pi) on PATH. ' +
|
|
151
|
+
'Install it: npm install -g @mariozechner/pi-coding-agent, then configure a ' +
|
|
152
|
+
'provider. Or unset the runtime to use Claude.');
|
|
153
|
+
}
|
|
154
|
+
throw err;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
runTurn(bin, prompt, sessionDir, args) {
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
159
|
+
// Prompt is positional (see file header) — always LAST so no later flag
|
|
160
|
+
// is mistaken for part of it.
|
|
161
|
+
const cliArgs = ['--mode', 'json', '--approve', '--session-dir', sessionDir];
|
|
162
|
+
if (args.model)
|
|
163
|
+
cliArgs.push('--model', args.model);
|
|
164
|
+
cliArgs.push(prompt);
|
|
165
|
+
const child = spawn(bin, cliArgs, {
|
|
166
|
+
cwd: args.cwd,
|
|
167
|
+
// PI_TELEMETRY/PI_SKIP_VERSION_CHECK: confirmed via pi's own docs —
|
|
168
|
+
// suppresses install/update telemetry and version-check network calls
|
|
169
|
+
// that otherwise add latency/flakiness to every headless turn.
|
|
170
|
+
env: { ...process.env, PI_TELEMETRY: '0', PI_SKIP_VERSION_CHECK: '1', ...args.env },
|
|
171
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
172
|
+
});
|
|
173
|
+
let stderrTail = '';
|
|
174
|
+
child.stderr?.on('data', (c) => { stderrTail = (stderrTail + c.toString()).slice(-4000); });
|
|
175
|
+
let sawOutput = false;
|
|
176
|
+
let timedOut = false;
|
|
177
|
+
let hangSuspected = false;
|
|
178
|
+
const KILL_GRACE_MS = 5000;
|
|
179
|
+
let killTimer;
|
|
180
|
+
const timer = setTimeout(() => {
|
|
181
|
+
timedOut = true;
|
|
182
|
+
child.kill('SIGTERM');
|
|
183
|
+
killTimer = setTimeout(() => { try {
|
|
184
|
+
child.kill('SIGKILL');
|
|
185
|
+
}
|
|
186
|
+
catch { /* already gone */ } }, KILL_GRACE_MS);
|
|
187
|
+
killTimer.unref?.();
|
|
188
|
+
}, TURN_TIMEOUT_MS);
|
|
189
|
+
// See STARTUP_GRACE_MS — disarmed by the first stdout chunk below.
|
|
190
|
+
let hangTimer = setTimeout(() => {
|
|
191
|
+
hangSuspected = true;
|
|
192
|
+
child.kill('SIGTERM');
|
|
193
|
+
killTimer = setTimeout(() => { try {
|
|
194
|
+
child.kill('SIGKILL');
|
|
195
|
+
}
|
|
196
|
+
catch { /* already gone */ } }, KILL_GRACE_MS);
|
|
197
|
+
killTimer.unref?.();
|
|
198
|
+
}, STARTUP_GRACE_MS);
|
|
199
|
+
const exitPromise = new Promise((res, rej) => {
|
|
200
|
+
child.on('error', rej);
|
|
201
|
+
child.on('close', (code) => res(code ?? 1));
|
|
202
|
+
});
|
|
203
|
+
exitPromise.catch(() => { });
|
|
204
|
+
const readLines = (async () => {
|
|
205
|
+
const lines = [];
|
|
206
|
+
let buf = '';
|
|
207
|
+
for await (const chunk of child.stdout) {
|
|
208
|
+
if (!sawOutput) {
|
|
209
|
+
sawOutput = true;
|
|
210
|
+
if (hangTimer) {
|
|
211
|
+
clearTimeout(hangTimer);
|
|
212
|
+
hangTimer = undefined;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
buf += chunk.toString();
|
|
216
|
+
const parts = buf.split('\n');
|
|
217
|
+
buf = parts.pop() ?? '';
|
|
218
|
+
lines.push(...parts);
|
|
219
|
+
}
|
|
220
|
+
if (buf.trim())
|
|
221
|
+
lines.push(buf);
|
|
222
|
+
return lines;
|
|
223
|
+
})();
|
|
224
|
+
// Timer cleanup lives in a top-level .finally() (not nested inside a
|
|
225
|
+
// success-path .then()) so it runs on EITHER path — a stdout stream
|
|
226
|
+
// error would otherwise skip straight to reject() and leave the
|
|
227
|
+
// TURN_TIMEOUT_MS/hangTimer/killTimer timers running past the
|
|
228
|
+
// process's actual lifetime.
|
|
229
|
+
Promise.all([readLines, exitPromise])
|
|
230
|
+
.then(([lines, exitCode]) => {
|
|
231
|
+
const parsed = parsePiEvents(lines);
|
|
232
|
+
resolve({
|
|
233
|
+
texts: parsed.texts,
|
|
234
|
+
rawTexts: parsed.rawTexts,
|
|
235
|
+
exitCode,
|
|
236
|
+
stderrTail,
|
|
237
|
+
timedOut,
|
|
238
|
+
hangSuspected,
|
|
239
|
+
inputTokens: parsed.inputTokens,
|
|
240
|
+
outputTokens: parsed.outputTokens,
|
|
241
|
+
});
|
|
242
|
+
}, (err) => {
|
|
243
|
+
// A stdout stream error (the reject path) means the process is
|
|
244
|
+
// still ALIVE and unmanaged — none of the timeout/hang timers
|
|
245
|
+
// would have fired to kill it. Without this, that error would
|
|
246
|
+
// orphan the child. child.kill() on an already-dead process is a
|
|
247
|
+
// documented no-op, so this is safe on every path.
|
|
248
|
+
try {
|
|
249
|
+
child.kill('SIGTERM');
|
|
250
|
+
}
|
|
251
|
+
catch { /* already gone */ }
|
|
252
|
+
reject(err);
|
|
253
|
+
})
|
|
254
|
+
.finally(() => {
|
|
255
|
+
clearTimeout(timer);
|
|
256
|
+
if (hangTimer)
|
|
257
|
+
clearTimeout(hangTimer);
|
|
258
|
+
if (killTimer)
|
|
259
|
+
clearTimeout(killTimer);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=pi-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pi-runner.js","sourceRoot":"","sources":["../../../src/orgrt/pi-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentRunner, AgentRunArgs, AgentMessage } from './agent-runner.js';
|
|
2
|
+
/** Pure stream-json parser — exported for unit testing against fixture lines
|
|
3
|
+
* built from Qwen Code's documented event schema (qwen-runner.test.ts). */
|
|
4
|
+
export declare function parseQwenEvents(lines: string[]): {
|
|
5
|
+
texts: string[];
|
|
6
|
+
rawTexts: string[];
|
|
7
|
+
sessionId?: string;
|
|
8
|
+
inputTokens: number;
|
|
9
|
+
outputTokens: number;
|
|
10
|
+
error?: string;
|
|
11
|
+
};
|
|
12
|
+
export declare class QwenAgentRunner implements AgentRunner {
|
|
13
|
+
private qwenBin?;
|
|
14
|
+
constructor(qwenBin?: string | undefined);
|
|
15
|
+
run(args: AgentRunArgs): AsyncIterable<AgentMessage>;
|
|
16
|
+
private runTurn;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=qwen-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qwen-runner.d.ts","sourceRoot":"","sources":["../../../src/orgrt/qwen-runner.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAqCjF;4EAC4E;AAC5E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG;IAChD,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACpH,CAqCA;AAED,qBAAa,eAAgB,YAAW,WAAW;IACrC,OAAO,CAAC,OAAO,CAAC;IAA5B,YAAoB,OAAO,CAAC,EAAE,MAAM,YAAA,EAAI;IAEjC,GAAG,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC,CAsF1D;IAED,OAAO,CAAC,OAAO;CAgGhB"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// packages/@monomind/cli/src/orgrt/qwen-runner.ts
|
|
2
|
+
/**
|
|
3
|
+
* QwenAgentRunner — AgentRunner impl backed by the Qwen Code CLI (`qwen`,
|
|
4
|
+
* https://qwenlm.github.io/qwen-code-docs/).
|
|
5
|
+
*
|
|
6
|
+
* Architectural pattern: SAME as CodexAgentRunner/GrokAgentRunner — spawn the
|
|
7
|
+
* vendor's CLI binary, parse its stream-json output, normalize to
|
|
8
|
+
* AgentMessage. No SDK dependency.
|
|
9
|
+
*
|
|
10
|
+
* Auth: inherited from the CLI's own login flow. No env vars set here.
|
|
11
|
+
*
|
|
12
|
+
* Org tools — FENCE PROTOCOL: same approach as the other subprocess runners
|
|
13
|
+
* (see tool-fence.ts).
|
|
14
|
+
*
|
|
15
|
+
* Subprocess protocol — per Qwen Code's public "Headless Mode" docs, NOT
|
|
16
|
+
* byte-verified against a running binary:
|
|
17
|
+
* - Invocation: `qwen -p "<prompt>" --output-format stream-json --yolo
|
|
18
|
+
* [-m <model>] [--resume <sessionId> | --continue]`
|
|
19
|
+
* - stream-json emits one JSON object per line; documented shape:
|
|
20
|
+
* { type: 'system'|'assistant'|'result', subtype, uuid, session_id,
|
|
21
|
+
* role: 'assistant',
|
|
22
|
+
* message: { content: [{type:'text', text}], usage: { tokens: { input, output, total } } } }
|
|
23
|
+
* - Session continuity: `--resume [sessionId]` resumes a specific session,
|
|
24
|
+
* `--continue` resumes the most recent one; `session_id` is carried on
|
|
25
|
+
* every event.
|
|
26
|
+
* - `--yolo` auto-approves tool actions (org roles gate tool execution
|
|
27
|
+
* themselves via canUseTool/tool-fence, so CLI-level approval prompts
|
|
28
|
+
* would otherwise hang a non-interactive run).
|
|
29
|
+
*/
|
|
30
|
+
import { spawn } from 'node:child_process';
|
|
31
|
+
import { buildToolProtocol, parseToolCalls, executeToolCall, formatToolResults, MAX_TOOL_ROUNDS, TOOL_CALL_RE } from './tool-fence.js';
|
|
32
|
+
const TURN_TIMEOUT_MS = 2 * 60 * 60 * 1000;
|
|
33
|
+
/** Distinct from TURN_TIMEOUT_MS: catches a hung first-run interactive prompt
|
|
34
|
+
* (trust/telemetry gate) fast instead of waiting out the full turn timeout.
|
|
35
|
+
* Fires only if the process has produced ZERO stdout by this point — any
|
|
36
|
+
* output at all disarms it, since a slow model response is not a hang. */
|
|
37
|
+
const STARTUP_GRACE_MS = 45_000;
|
|
38
|
+
/** Pure stream-json parser — exported for unit testing against fixture lines
|
|
39
|
+
* built from Qwen Code's documented event schema (qwen-runner.test.ts). */
|
|
40
|
+
export function parseQwenEvents(lines) {
|
|
41
|
+
const rawTexts = [];
|
|
42
|
+
let sessionId;
|
|
43
|
+
let inputTokens = 0;
|
|
44
|
+
let outputTokens = 0;
|
|
45
|
+
let error;
|
|
46
|
+
for (const line of lines) {
|
|
47
|
+
const trimmed = line.trim();
|
|
48
|
+
if (!trimmed || !trimmed.startsWith('{'))
|
|
49
|
+
continue;
|
|
50
|
+
let ev;
|
|
51
|
+
try {
|
|
52
|
+
ev = JSON.parse(trimmed);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (ev.session_id)
|
|
58
|
+
sessionId = ev.session_id;
|
|
59
|
+
if (ev.type === 'assistant' && ev.message?.content) {
|
|
60
|
+
const text = ev.message.content
|
|
61
|
+
.filter((b) => b.type === 'text' && typeof b.text === 'string')
|
|
62
|
+
.map((b) => b.text)
|
|
63
|
+
.join('\n');
|
|
64
|
+
if (text)
|
|
65
|
+
rawTexts.push(text);
|
|
66
|
+
}
|
|
67
|
+
if (ev.type === 'result') {
|
|
68
|
+
const tokens = ev.message?.usage?.tokens;
|
|
69
|
+
if (tokens) {
|
|
70
|
+
inputTokens = tokens.input ?? 0;
|
|
71
|
+
outputTokens = tokens.output ?? 0;
|
|
72
|
+
}
|
|
73
|
+
if (ev.subtype === 'error') {
|
|
74
|
+
error = typeof ev.error === 'string' ? ev.error : ev.error?.message ?? 'qwen result: error';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const texts = rawTexts.map((t) => t.replace(TOOL_CALL_RE, '').trim());
|
|
79
|
+
return { texts, rawTexts, sessionId, inputTokens, outputTokens, error };
|
|
80
|
+
}
|
|
81
|
+
export class QwenAgentRunner {
|
|
82
|
+
qwenBin;
|
|
83
|
+
constructor(qwenBin) {
|
|
84
|
+
this.qwenBin = qwenBin;
|
|
85
|
+
}
|
|
86
|
+
async *run(args) {
|
|
87
|
+
const bin = this.qwenBin || process.env.QWEN_CLI_BIN || 'qwen';
|
|
88
|
+
let sessionId = args.resume;
|
|
89
|
+
try {
|
|
90
|
+
for await (const p of args.prompt) {
|
|
91
|
+
const text = typeof p === 'string' ? p : (p?.message?.content ?? String(p ?? ''));
|
|
92
|
+
let nextPrompt = text;
|
|
93
|
+
let turnInputTokens = 0;
|
|
94
|
+
let turnOutputTokens = 0;
|
|
95
|
+
for (let round = 0; round <= MAX_TOOL_ROUNDS; round++) {
|
|
96
|
+
// Gated on !sessionId alone, NOT `round === 0 && !sessionId` — if
|
|
97
|
+
// a session id never gets parsed out of qwen's output, every
|
|
98
|
+
// round after the first would otherwise spawn a completely
|
|
99
|
+
// fresh, contextless qwen invocation carrying only the tool-
|
|
100
|
+
// result text. Once a session id IS captured, --resume takes
|
|
101
|
+
// over and this stops re-sending the system prompt.
|
|
102
|
+
const promptWithSystem = !sessionId
|
|
103
|
+
? `${args.systemPrompt}${buildToolProtocol(args.tools)}\n\n---\n\n${nextPrompt}`
|
|
104
|
+
: nextPrompt;
|
|
105
|
+
const outcome = await this.runTurn(bin, promptWithSystem, sessionId, args);
|
|
106
|
+
if (outcome.sessionId)
|
|
107
|
+
sessionId = outcome.sessionId;
|
|
108
|
+
if (outcome.hangSuspected) {
|
|
109
|
+
throw new Error(`QwenAgentRunner: qwen produced no output within ${STARTUP_GRACE_MS / 1000}s and was killed. ` +
|
|
110
|
+
'This usually means it is stuck on a first-run interactive prompt (trust/telemetry gate) ' +
|
|
111
|
+
'that headless mode has no way to answer. Run `qwen` once manually in a real terminal in ' +
|
|
112
|
+
`this project to accept any prompts, then retry.${outcome.stderrTail ? `\nstderr: ${outcome.stderrTail.slice(-500)}` : ''}`);
|
|
113
|
+
}
|
|
114
|
+
if (outcome.exitCode !== 0 || outcome.error) {
|
|
115
|
+
throw new Error(`QwenAgentRunner: qwen failed (exit ${outcome.exitCode})` +
|
|
116
|
+
(outcome.timedOut ? ` — killed after exceeding the ${TURN_TIMEOUT_MS / 3_600_000}h turn timeout` : '') +
|
|
117
|
+
(outcome.error ? `: ${outcome.error}` : '') +
|
|
118
|
+
(outcome.stderrTail ? `\nstderr: ${outcome.stderrTail.slice(-500)}` : ''));
|
|
119
|
+
}
|
|
120
|
+
for (const t of outcome.texts) {
|
|
121
|
+
if (t.trim())
|
|
122
|
+
yield { type: 'assistant', session_id: sessionId, text: t };
|
|
123
|
+
}
|
|
124
|
+
turnInputTokens += outcome.inputTokens;
|
|
125
|
+
turnOutputTokens += outcome.outputTokens;
|
|
126
|
+
const malformed = [];
|
|
127
|
+
const calls = parseToolCalls(outcome.rawTexts, (raw, err) => malformed.push(`[monomind] ignored malformed tool_call fence (${err}): ${raw.slice(0, 200)}`));
|
|
128
|
+
for (const note of malformed)
|
|
129
|
+
yield { type: 'assistant', session_id: sessionId, text: note };
|
|
130
|
+
if (calls.length === 0)
|
|
131
|
+
break;
|
|
132
|
+
if (round === MAX_TOOL_ROUNDS) {
|
|
133
|
+
yield {
|
|
134
|
+
type: 'assistant', session_id: sessionId,
|
|
135
|
+
text: `[monomind] tool-call round cap (${MAX_TOOL_ROUNDS}) reached — dropping ${calls.length} pending tool call(s)`,
|
|
136
|
+
};
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
const results = [];
|
|
140
|
+
for (const call of calls)
|
|
141
|
+
results.push(await executeToolCall(args.tools, call, args.canUseTool));
|
|
142
|
+
nextPrompt = formatToolResults(calls, results);
|
|
143
|
+
}
|
|
144
|
+
yield {
|
|
145
|
+
type: 'result',
|
|
146
|
+
session_id: sessionId,
|
|
147
|
+
subtype: 'success',
|
|
148
|
+
input_tokens: turnInputTokens,
|
|
149
|
+
output_tokens: turnOutputTokens,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
if (err.code === 'ENOENT') {
|
|
155
|
+
throw new Error('QwenAgentRunner requires the Qwen Code CLI (qwen) on PATH. ' +
|
|
156
|
+
'Install it: npm install -g @qwen-code/qwen-code, then run `qwen` once ' +
|
|
157
|
+
'to authenticate. Or unset the runtime to use Claude.');
|
|
158
|
+
}
|
|
159
|
+
throw err;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
runTurn(bin, prompt, sessionId, args) {
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
const cliArgs = ['-p', prompt, '--output-format', 'stream-json', '--yolo'];
|
|
165
|
+
if (args.model)
|
|
166
|
+
cliArgs.push('-m', args.model);
|
|
167
|
+
if (sessionId)
|
|
168
|
+
cliArgs.push('--resume', sessionId);
|
|
169
|
+
const child = spawn(bin, cliArgs, {
|
|
170
|
+
cwd: args.cwd,
|
|
171
|
+
env: { ...process.env, ...args.env },
|
|
172
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
173
|
+
});
|
|
174
|
+
let stderrTail = '';
|
|
175
|
+
child.stderr?.on('data', (c) => { stderrTail = (stderrTail + c.toString()).slice(-4000); });
|
|
176
|
+
let sawOutput = false;
|
|
177
|
+
let timedOut = false;
|
|
178
|
+
let hangSuspected = false;
|
|
179
|
+
const KILL_GRACE_MS = 5000;
|
|
180
|
+
let killTimer;
|
|
181
|
+
const timer = setTimeout(() => {
|
|
182
|
+
timedOut = true;
|
|
183
|
+
child.kill('SIGTERM');
|
|
184
|
+
killTimer = setTimeout(() => { try {
|
|
185
|
+
child.kill('SIGKILL');
|
|
186
|
+
}
|
|
187
|
+
catch { /* already gone */ } }, KILL_GRACE_MS);
|
|
188
|
+
killTimer.unref?.();
|
|
189
|
+
}, TURN_TIMEOUT_MS);
|
|
190
|
+
// See STARTUP_GRACE_MS — disarmed by the first stdout chunk below.
|
|
191
|
+
let hangTimer = setTimeout(() => {
|
|
192
|
+
hangSuspected = true;
|
|
193
|
+
child.kill('SIGTERM');
|
|
194
|
+
killTimer = setTimeout(() => { try {
|
|
195
|
+
child.kill('SIGKILL');
|
|
196
|
+
}
|
|
197
|
+
catch { /* already gone */ } }, KILL_GRACE_MS);
|
|
198
|
+
killTimer.unref?.();
|
|
199
|
+
}, STARTUP_GRACE_MS);
|
|
200
|
+
const exitPromise = new Promise((res, rej) => {
|
|
201
|
+
child.on('error', rej);
|
|
202
|
+
child.on('close', (code) => res(code ?? 1));
|
|
203
|
+
});
|
|
204
|
+
exitPromise.catch(() => { });
|
|
205
|
+
const readLines = (async () => {
|
|
206
|
+
const lines = [];
|
|
207
|
+
let buf = '';
|
|
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
|
+
buf += chunk.toString();
|
|
217
|
+
const parts = buf.split('\n');
|
|
218
|
+
buf = parts.pop() ?? '';
|
|
219
|
+
lines.push(...parts);
|
|
220
|
+
}
|
|
221
|
+
if (buf.trim())
|
|
222
|
+
lines.push(buf);
|
|
223
|
+
return lines;
|
|
224
|
+
})();
|
|
225
|
+
// Timer cleanup lives in a top-level .finally() (not nested inside a
|
|
226
|
+
// success-path .then()) so it runs on EITHER path — a stdout stream
|
|
227
|
+
// error would otherwise skip straight to reject() and leave the
|
|
228
|
+
// TURN_TIMEOUT_MS/hangTimer/killTimer timers running past the
|
|
229
|
+
// process's actual lifetime.
|
|
230
|
+
Promise.all([readLines, exitPromise])
|
|
231
|
+
.then(([lines, exitCode]) => {
|
|
232
|
+
const parsed = parseQwenEvents(lines);
|
|
233
|
+
resolve({
|
|
234
|
+
texts: parsed.texts,
|
|
235
|
+
rawTexts: parsed.rawTexts,
|
|
236
|
+
sessionId: parsed.sessionId ?? sessionId,
|
|
237
|
+
exitCode,
|
|
238
|
+
stderrTail,
|
|
239
|
+
timedOut,
|
|
240
|
+
hangSuspected,
|
|
241
|
+
inputTokens: parsed.inputTokens,
|
|
242
|
+
outputTokens: parsed.outputTokens,
|
|
243
|
+
error: parsed.error,
|
|
244
|
+
});
|
|
245
|
+
}, (err) => {
|
|
246
|
+
// A stdout stream error (the reject path) means the process is
|
|
247
|
+
// still ALIVE and unmanaged — none of the timeout/hang timers
|
|
248
|
+
// would have fired to kill it. Without this, that error would
|
|
249
|
+
// orphan the child. child.kill() on an already-dead process is a
|
|
250
|
+
// documented no-op, so this is safe on every path.
|
|
251
|
+
try {
|
|
252
|
+
child.kill('SIGTERM');
|
|
253
|
+
}
|
|
254
|
+
catch { /* already gone */ }
|
|
255
|
+
reject(err);
|
|
256
|
+
})
|
|
257
|
+
.finally(() => {
|
|
258
|
+
clearTimeout(timer);
|
|
259
|
+
if (hangTimer)
|
|
260
|
+
clearTimeout(hangTimer);
|
|
261
|
+
if (killTimer)
|
|
262
|
+
clearTimeout(killTimer);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=qwen-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qwen-runner.js","sourceRoot":"","sources":["../../../src/orgrt/qwen-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -480,7 +480,7 @@ export function buildOrgTools(opts) {
|
|
|
480
480
|
if (opts.onComplete) {
|
|
481
481
|
tools.push({
|
|
482
482
|
name: 'org_complete',
|
|
483
|
-
description: '
|
|
483
|
+
description: '⚠️ Ends the run — every agent session shuts down after this. Call exactly once, and only against the org\'s actual, full stated goal (see your briefing), never against just the current batch of dispatched tasks. "achieved" means the WHOLE goal is done, not "everyone assigned so far finished their piece" — a multi-phase or open-ended goal is very rarely achieved in a single run. If the current task batch is clearly done but the goal has more scope left: do NOT call this — use org_task/createTask to dispatch the next phase\'s work instead, so the org keeps making progress instead of stopping short. Use outcome "partial" only when you are ending the run with real scope still remaining (e.g. a genuine external stopping point, not merely "out of tasks right now"); "achieved" only when the full goal is met; "failed" only when it clearly cannot be. Before calling, check org_tasks — siblings with in-progress work only get a short drain window to finish before being cut off, so do not call this while others are still mid-build or mid-edit unless the run genuinely cannot continue. The outcome and summary are persisted to the org run history and briefed to the next run.',
|
|
484
484
|
schema: { outcome: z.enum(['achieved', 'partial', 'failed']), summary: z.string() },
|
|
485
485
|
handler: async (args) => {
|
|
486
486
|
opts.onComplete(role.id, args.outcome, args.summary);
|