harness-dispatch 0.4.0
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/LICENSE +21 -0
- package/README.md +582 -0
- package/config.default.yaml +397 -0
- package/data/coding_benchmarks.json +431 -0
- package/dist/auth.d.ts +9 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +73 -0
- package/dist/auth.js.map +1 -0
- package/dist/billing.d.ts +7 -0
- package/dist/billing.d.ts.map +1 -0
- package/dist/billing.js +201 -0
- package/dist/billing.js.map +1 -0
- package/dist/bin.d.ts +6 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +488 -0
- package/dist/bin.js.map +1 -0
- package/dist/breaker-store.d.ts +31 -0
- package/dist/breaker-store.d.ts.map +1 -0
- package/dist/breaker-store.js +103 -0
- package/dist/breaker-store.js.map +1 -0
- package/dist/circuit-breaker.d.ts +47 -0
- package/dist/circuit-breaker.d.ts.map +1 -0
- package/dist/circuit-breaker.js +102 -0
- package/dist/circuit-breaker.js.map +1 -0
- package/dist/config.d.ts +48 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +1248 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard/live.d.ts +49 -0
- package/dist/dashboard/live.d.ts.map +1 -0
- package/dist/dashboard/live.js +149 -0
- package/dist/dashboard/live.js.map +1 -0
- package/dist/dispatch-log.d.ts +46 -0
- package/dist/dispatch-log.d.ts.map +1 -0
- package/dist/dispatch-log.js +89 -0
- package/dist/dispatch-log.js.map +1 -0
- package/dist/dispatchers/base.d.ts +55 -0
- package/dist/dispatchers/base.d.ts.map +1 -0
- package/dist/dispatchers/base.js +80 -0
- package/dist/dispatchers/base.js.map +1 -0
- package/dist/dispatchers/generic-cli.d.ts +30 -0
- package/dist/dispatchers/generic-cli.d.ts.map +1 -0
- package/dist/dispatchers/generic-cli.js +471 -0
- package/dist/dispatchers/generic-cli.js.map +1 -0
- package/dist/dispatchers/openai-compatible.d.ts +57 -0
- package/dist/dispatchers/openai-compatible.d.ts.map +1 -0
- package/dist/dispatchers/openai-compatible.js +662 -0
- package/dist/dispatchers/openai-compatible.js.map +1 -0
- package/dist/dispatchers/shared/kill-tree.d.ts +21 -0
- package/dist/dispatchers/shared/kill-tree.d.ts.map +1 -0
- package/dist/dispatchers/shared/kill-tree.js +35 -0
- package/dist/dispatchers/shared/kill-tree.js.map +1 -0
- package/dist/dispatchers/shared/rate-limit-headers.d.ts +22 -0
- package/dist/dispatchers/shared/rate-limit-headers.d.ts.map +1 -0
- package/dist/dispatchers/shared/rate-limit-headers.js +124 -0
- package/dist/dispatchers/shared/rate-limit-headers.js.map +1 -0
- package/dist/dispatchers/shared/stream-subprocess.d.ts +53 -0
- package/dist/dispatchers/shared/stream-subprocess.d.ts.map +1 -0
- package/dist/dispatchers/shared/stream-subprocess.js +274 -0
- package/dist/dispatchers/shared/stream-subprocess.js.map +1 -0
- package/dist/dispatchers/shared/subprocess.d.ts +25 -0
- package/dist/dispatchers/shared/subprocess.d.ts.map +1 -0
- package/dist/dispatchers/shared/subprocess.js +110 -0
- package/dist/dispatchers/shared/subprocess.js.map +1 -0
- package/dist/dispatchers/shared/which-available.d.ts +2 -0
- package/dist/dispatchers/shared/which-available.d.ts.map +1 -0
- package/dist/dispatchers/shared/which-available.js +8 -0
- package/dist/dispatchers/shared/which-available.js.map +1 -0
- package/dist/dispatchers/shared/windows-cmd.d.ts +38 -0
- package/dist/dispatchers/shared/windows-cmd.d.ts.map +1 -0
- package/dist/dispatchers/shared/windows-cmd.js +91 -0
- package/dist/dispatchers/shared/windows-cmd.js.map +1 -0
- package/dist/http/server.d.ts +15 -0
- package/dist/http/server.d.ts.map +1 -0
- package/dist/http/server.js +495 -0
- package/dist/http/server.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/job-runner.d.ts +19 -0
- package/dist/job-runner.d.ts.map +1 -0
- package/dist/job-runner.js +42 -0
- package/dist/job-runner.js.map +1 -0
- package/dist/jobs.d.ts +116 -0
- package/dist/jobs.d.ts.map +1 -0
- package/dist/jobs.js +542 -0
- package/dist/jobs.js.map +1 -0
- package/dist/leaderboard.d.ts +62 -0
- package/dist/leaderboard.d.ts.map +1 -0
- package/dist/leaderboard.js +287 -0
- package/dist/leaderboard.js.map +1 -0
- package/dist/mcp/config-hot-reload.d.ts +64 -0
- package/dist/mcp/config-hot-reload.d.ts.map +1 -0
- package/dist/mcp/config-hot-reload.js +144 -0
- package/dist/mcp/config-hot-reload.js.map +1 -0
- package/dist/mcp/dispatcher-factory.d.ts +20 -0
- package/dist/mcp/dispatcher-factory.d.ts.map +1 -0
- package/dist/mcp/dispatcher-factory.js +30 -0
- package/dist/mcp/dispatcher-factory.js.map +1 -0
- package/dist/mcp/resources.d.ts +8 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +45 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts +36 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +80 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +171 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +658 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/observability/index.d.ts +52 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +111 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/spans.d.ts +47 -0
- package/dist/observability/spans.d.ts.map +1 -0
- package/dist/observability/spans.js +72 -0
- package/dist/observability/spans.js.map +1 -0
- package/dist/quota.d.ts +91 -0
- package/dist/quota.d.ts.map +1 -0
- package/dist/quota.js +331 -0
- package/dist/quota.js.map +1 -0
- package/dist/route-policy.d.ts +24 -0
- package/dist/route-policy.d.ts.map +1 -0
- package/dist/route-policy.js +92 -0
- package/dist/route-policy.js.map +1 -0
- package/dist/router.d.ts +162 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +878 -0
- package/dist/router.js.map +1 -0
- package/dist/safety.d.ts +7 -0
- package/dist/safety.d.ts.map +1 -0
- package/dist/safety.js +33 -0
- package/dist/safety.js.map +1 -0
- package/dist/status.d.ts +100 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +228 -0
- package/dist/status.js.map +1 -0
- package/dist/types.d.ts +402 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +13 -0
- package/dist/version.js.map +1 -0
- package/dist/working-dir.d.ts +15 -0
- package/dist/working-dir.d.ts.map +1 -0
- package/dist/working-dir.js +22 -0
- package/dist/working-dir.js.map +1 -0
- package/dist/workspaces.d.ts +19 -0
- package/dist/workspaces.d.ts.map +1 -0
- package/dist/workspaces.js +352 -0
- package/dist/workspaces.js.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-cli.d.ts","sourceRoot":"","sources":["../../src/dispatchers/generic-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAIV,eAAe,EACf,SAAS,EAET,aAAa,EACd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAgN9D,qBAAa,oBAAqB,SAAQ,cAAc;;IACtD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgC;IAC7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoC;gBAEzD,GAAG,CAAC,EAAE,aAAa;IAW/B,WAAW,IAAI,OAAO;IAIhB,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC;IAItC,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,YAAiB,GACtB,aAAa,CAAC,eAAe,CAAC;CA0PlC"}
|
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config-driven CLI dispatcher for harness-dispatch.
|
|
3
|
+
*
|
|
4
|
+
* Every part of the invocation comes from `svc.protocol` (CliProtocolConfig,
|
|
5
|
+
* see types.ts) — this dispatcher has no hardcoded knowledge of any specific
|
|
6
|
+
* CLI's flags or output shape. It's the ONE interpreter for every CLI
|
|
7
|
+
* harness, built-in or user-added: prompt input style, working-dir flag,
|
|
8
|
+
* per-file directory flags, model flag, per-safety-profile args, API-key env
|
|
9
|
+
* injection, and (via `eventRules`) the same tool_use/thinking/usage
|
|
10
|
+
* streaming-event semantics Codex's original hand-written dispatcher used —
|
|
11
|
+
* expressed declaratively instead of imperatively, so a new harness (or a
|
|
12
|
+
* redefinition of an existing one) needs zero new TypeScript.
|
|
13
|
+
*/
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import which from "which";
|
|
17
|
+
import { BaseDispatcher } from "./base.js";
|
|
18
|
+
import { streamSubprocess } from "./shared/stream-subprocess.js";
|
|
19
|
+
import { resolveCliCommand } from "./shared/windows-cmd.js";
|
|
20
|
+
import { commandAvailable } from "./shared/which-available.js";
|
|
21
|
+
const DEFAULT_TIMEOUT_MS = 600_000; // 10 minutes
|
|
22
|
+
function detectRateLimit(text) {
|
|
23
|
+
const lowered = text.toLowerCase();
|
|
24
|
+
const flagged = lowered.includes("rate limit") ||
|
|
25
|
+
lowered.includes("quota exceeded") ||
|
|
26
|
+
lowered.includes("resource_exhausted") ||
|
|
27
|
+
lowered.includes("too many requests") ||
|
|
28
|
+
// "usage limit" is OpenAI Codex's real phrasing (confirmed live,
|
|
29
|
+
// 2026-07-24: "You've hit your usage limit... try again at Jul 28th,
|
|
30
|
+
// 2026 10:16 PM.") — none of the phrases above matched it, so a real
|
|
31
|
+
// Codex exhaustion was silently NOT flagged as rate-limited.
|
|
32
|
+
lowered.includes("usage limit") ||
|
|
33
|
+
text.includes("429");
|
|
34
|
+
if (!flagged)
|
|
35
|
+
return { rateLimited: false, retryAfter: null };
|
|
36
|
+
const match = /retry[_\s-]after[:\s]+(\d+(?:\.\d+)?)/i.exec(text);
|
|
37
|
+
const retryAfter = match?.[1] ? Number.parseFloat(match[1]) : null;
|
|
38
|
+
return {
|
|
39
|
+
rateLimited: true,
|
|
40
|
+
retryAfter: retryAfter !== null && Number.isFinite(retryAfter) ? retryAfter : null,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Walk a nested object by dotted path, e.g. "message.content". */
|
|
44
|
+
function getPath(value, path) {
|
|
45
|
+
return path.split(".").reduce((acc, key) => {
|
|
46
|
+
if (acc === null || typeof acc !== "object")
|
|
47
|
+
return undefined;
|
|
48
|
+
return acc[key];
|
|
49
|
+
}, value);
|
|
50
|
+
}
|
|
51
|
+
function extractField(obj, fields) {
|
|
52
|
+
if (obj === null || typeof obj !== "object")
|
|
53
|
+
return undefined;
|
|
54
|
+
for (const field of fields) {
|
|
55
|
+
const v = getPath(obj, field);
|
|
56
|
+
if (typeof v === "string" && v.length > 0)
|
|
57
|
+
return v;
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
function parseJsonBlob(source) {
|
|
62
|
+
const trimmed = source.trim();
|
|
63
|
+
if (!trimmed)
|
|
64
|
+
return undefined;
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(trimmed);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function parseJsonField(stdout, fields) {
|
|
73
|
+
const parsed = parseJsonBlob(stdout);
|
|
74
|
+
return parsed !== undefined ? extractField(parsed, fields) : undefined;
|
|
75
|
+
}
|
|
76
|
+
/** Unique parent directories of absolute file paths, excluding workingDir itself — same rule for every harness. */
|
|
77
|
+
function includedDirectories(files, workingDir) {
|
|
78
|
+
const dirs = new Set();
|
|
79
|
+
for (const file of files) {
|
|
80
|
+
if (!path.isAbsolute(file))
|
|
81
|
+
continue;
|
|
82
|
+
const dir = path.dirname(file);
|
|
83
|
+
if (dir !== workingDir)
|
|
84
|
+
dirs.add(dir);
|
|
85
|
+
}
|
|
86
|
+
return [...dirs];
|
|
87
|
+
}
|
|
88
|
+
function buildFullPrompt(protocol, prompt, files) {
|
|
89
|
+
if (files.length === 0 || !protocol.fileListHeader)
|
|
90
|
+
return prompt;
|
|
91
|
+
const bullet = protocol.fileListBullet ?? " ";
|
|
92
|
+
const fileList = files.map((p) => `${bullet}${p}`).join("\n");
|
|
93
|
+
return `${prompt}\n\n${protocol.fileListHeader}\n${fileList}`;
|
|
94
|
+
}
|
|
95
|
+
/** Expand one `protocol.args` token into zero or more literal argv tokens — see CliProtocolConfig's doc comment for the token reference. */
|
|
96
|
+
function expandToken(token, protocol, prompt, files, workingDir, effectiveModel, safetyProfile, nativeArgs) {
|
|
97
|
+
switch (token) {
|
|
98
|
+
case "{{prompt}}":
|
|
99
|
+
return protocol.stdin ? [] : [prompt];
|
|
100
|
+
case "{{model}}":
|
|
101
|
+
return protocol.model && effectiveModel ? [protocol.model.flag, effectiveModel] : [];
|
|
102
|
+
case "{{safety}}":
|
|
103
|
+
return protocol.safety?.[safetyProfile] ? [...protocol.safety[safetyProfile]] : [];
|
|
104
|
+
case "{{working_dir}}":
|
|
105
|
+
return protocol.workingDir && workingDir
|
|
106
|
+
? [protocol.workingDir.flag, workingDir, ...(protocol.workingDir.extraArgsWhenSet ?? [])]
|
|
107
|
+
: [];
|
|
108
|
+
case "{{file_dirs}}":
|
|
109
|
+
if (!protocol.fileDirs)
|
|
110
|
+
return [];
|
|
111
|
+
return includedDirectories(files, workingDir).flatMap((dir) => [protocol.fileDirs.flag, dir]);
|
|
112
|
+
case "{{native_args}}":
|
|
113
|
+
return nativeArgs;
|
|
114
|
+
default:
|
|
115
|
+
return [token];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function buildArgs(protocol, prefixArgs, prompt, files, workingDir, effectiveModel, nativeArgs, opts) {
|
|
119
|
+
const safetyProfile = opts.safetyProfile ?? "workspace_edit";
|
|
120
|
+
const args = [...prefixArgs];
|
|
121
|
+
for (const token of protocol.args) {
|
|
122
|
+
args.push(...expandToken(token, protocol, prompt, files, workingDir, effectiveModel, safetyProfile, nativeArgs));
|
|
123
|
+
}
|
|
124
|
+
return args;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Event-rule-driven JSONL line handler — the declarative equivalent of
|
|
128
|
+
* Codex's original hand-written `emitLine`. Mutates the shared accumulator
|
|
129
|
+
* state and returns any mid-run DispatcherEvents this line produced.
|
|
130
|
+
*/
|
|
131
|
+
class JsonlAccumulator {
|
|
132
|
+
rules;
|
|
133
|
+
lastText = "";
|
|
134
|
+
inputTokens = 0;
|
|
135
|
+
outputTokens = 0;
|
|
136
|
+
sawUsage = false;
|
|
137
|
+
sawAnyJson = false;
|
|
138
|
+
/** Set by the first matching emit: "error" rule; last one wins if several match across the stream. */
|
|
139
|
+
errorMessage;
|
|
140
|
+
constructor(rules) {
|
|
141
|
+
this.rules = rules;
|
|
142
|
+
}
|
|
143
|
+
process(line) {
|
|
144
|
+
const out = [];
|
|
145
|
+
const trimmed = line.trim();
|
|
146
|
+
if (!trimmed)
|
|
147
|
+
return out;
|
|
148
|
+
let event;
|
|
149
|
+
try {
|
|
150
|
+
event = JSON.parse(trimmed);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
this.sawAnyJson = true;
|
|
156
|
+
for (const rule of this.rules) {
|
|
157
|
+
const matches = Object.entries(rule.when).every(([field, value]) => getPath(event, field) === value);
|
|
158
|
+
if (!matches)
|
|
159
|
+
continue;
|
|
160
|
+
switch (rule.emit) {
|
|
161
|
+
case "text": {
|
|
162
|
+
const t = rule.textField ? getPath(event, rule.textField) : undefined;
|
|
163
|
+
if (typeof t === "string" && t.length > 0)
|
|
164
|
+
this.lastText = t;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
case "tool_use": {
|
|
168
|
+
const name = rule.nameField ? getPath(event, rule.nameField) : undefined;
|
|
169
|
+
if (typeof name === "string") {
|
|
170
|
+
out.push({ type: "tool_use", name, input: rule.inputField ? getPath(event, rule.inputField) : undefined });
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
case "thinking": {
|
|
175
|
+
const chunk = rule.chunkField ? getPath(event, rule.chunkField) : undefined;
|
|
176
|
+
if (typeof chunk === "string" && chunk.length > 0)
|
|
177
|
+
out.push({ type: "thinking", chunk });
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
case "usage": {
|
|
181
|
+
const inTok = firstNumberAt(event, rule.inputTokenFields ?? []);
|
|
182
|
+
const outTok = firstNumberAt(event, rule.outputTokenFields ?? []);
|
|
183
|
+
if (inTok || outTok) {
|
|
184
|
+
this.inputTokens += inTok;
|
|
185
|
+
this.outputTokens += outTok;
|
|
186
|
+
this.sawUsage = true;
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case "error": {
|
|
191
|
+
const message = rule.messageField ? getPath(event, rule.messageField) : undefined;
|
|
192
|
+
if (typeof message === "string" && message.length > 0)
|
|
193
|
+
this.errorMessage = message;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function firstNumberAt(obj, fields) {
|
|
202
|
+
for (const field of fields) {
|
|
203
|
+
const v = getPath(obj, field);
|
|
204
|
+
if (typeof v === "number")
|
|
205
|
+
return v;
|
|
206
|
+
}
|
|
207
|
+
return 0;
|
|
208
|
+
}
|
|
209
|
+
export class GenericCliDispatcher extends BaseDispatcher {
|
|
210
|
+
id;
|
|
211
|
+
command;
|
|
212
|
+
protocol;
|
|
213
|
+
apiKey;
|
|
214
|
+
configuredModel;
|
|
215
|
+
endpointMode;
|
|
216
|
+
endpointProvider;
|
|
217
|
+
constructor(svc) {
|
|
218
|
+
super();
|
|
219
|
+
this.id = svc?.name ?? "generic";
|
|
220
|
+
this.command = svc?.command ?? "";
|
|
221
|
+
this.protocol = svc?.protocol;
|
|
222
|
+
this.apiKey = svc?.apiKey;
|
|
223
|
+
this.configuredModel = svc?.model;
|
|
224
|
+
this.endpointMode = svc?.endpointMode;
|
|
225
|
+
this.endpointProvider = svc?.endpointProvider;
|
|
226
|
+
}
|
|
227
|
+
isAvailable() {
|
|
228
|
+
return Boolean(this.command) && Boolean(this.protocol) && commandAvailable(this.command);
|
|
229
|
+
}
|
|
230
|
+
async checkQuota() {
|
|
231
|
+
return { service: this.id, source: "unknown" };
|
|
232
|
+
}
|
|
233
|
+
stream(prompt, files, workingDir, opts = {}) {
|
|
234
|
+
return this.#runStream(prompt, files, workingDir, opts);
|
|
235
|
+
}
|
|
236
|
+
async *#runStream(prompt, files, workingDir, opts) {
|
|
237
|
+
const protocol = this.protocol;
|
|
238
|
+
if (!this.command || !protocol) {
|
|
239
|
+
yield {
|
|
240
|
+
type: "completion",
|
|
241
|
+
result: {
|
|
242
|
+
output: "",
|
|
243
|
+
service: this.id,
|
|
244
|
+
success: false,
|
|
245
|
+
error: `Route '${this.id}' is missing 'command' and/or 'protocol' — both are ` +
|
|
246
|
+
"required for harness: generic. See README.md#adding-a-harness.",
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const foundPath = await which(this.command, { nothrow: true });
|
|
252
|
+
if (!foundPath) {
|
|
253
|
+
yield {
|
|
254
|
+
type: "completion",
|
|
255
|
+
result: {
|
|
256
|
+
output: "",
|
|
257
|
+
service: this.id,
|
|
258
|
+
success: false,
|
|
259
|
+
error: `'${this.command}' not found on PATH`,
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const effectiveWorkingDir = !workingDir && protocol.workingDir?.fallback === "home" ? os.homedir() : workingDir;
|
|
265
|
+
const fullPrompt = buildFullPrompt(protocol, prompt, files);
|
|
266
|
+
const effectiveModel = opts.modelOverride ?? this.configuredModel;
|
|
267
|
+
const nativeArgs = this.endpointMode === "harness_native_endpoint" && this.endpointProvider
|
|
268
|
+
? (protocol.endpointNativeArgs?.[this.endpointProvider] ?? [])
|
|
269
|
+
: [];
|
|
270
|
+
const resolved = await resolveCliCommand(this.command);
|
|
271
|
+
const args = buildArgs(protocol, resolved.prefixArgs, fullPrompt, files, effectiveWorkingDir, effectiveModel, nativeArgs, opts);
|
|
272
|
+
const extraEnv = {};
|
|
273
|
+
if (protocol.apiKeyEnvVar) {
|
|
274
|
+
if (this.apiKey) {
|
|
275
|
+
extraEnv[protocol.apiKeyEnvVar] = this.apiKey;
|
|
276
|
+
}
|
|
277
|
+
else if (process.env[protocol.apiKeyEnvVar]) {
|
|
278
|
+
extraEnv[protocol.apiKeyEnvVar] = "";
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
282
|
+
const subOpts = { timeoutMs };
|
|
283
|
+
if (effectiveWorkingDir)
|
|
284
|
+
subOpts.cwd = effectiveWorkingDir;
|
|
285
|
+
if (protocol.stdin)
|
|
286
|
+
subOpts.stdin = fullPrompt;
|
|
287
|
+
if (Object.keys(extraEnv).length > 0)
|
|
288
|
+
subOpts.env = extraEnv;
|
|
289
|
+
const stdoutBuf = [];
|
|
290
|
+
const stderrBuf = [];
|
|
291
|
+
let exitCode = -1;
|
|
292
|
+
let durationMs = 0;
|
|
293
|
+
let timedOut = false;
|
|
294
|
+
const eventDriven = protocol.output.mode === "jsonl_stream" && protocol.output.eventRules;
|
|
295
|
+
const acc = eventDriven ? new JsonlAccumulator(protocol.output.eventRules) : undefined;
|
|
296
|
+
let lineBuffer = "";
|
|
297
|
+
for await (const evt of streamSubprocess(resolved.command, args, subOpts)) {
|
|
298
|
+
if ("stream" in evt) {
|
|
299
|
+
if (evt.stream === "stdout") {
|
|
300
|
+
stdoutBuf.push(evt.chunk);
|
|
301
|
+
yield { type: "stdout", chunk: evt.chunk };
|
|
302
|
+
if (acc) {
|
|
303
|
+
lineBuffer += evt.chunk;
|
|
304
|
+
let newlineIdx = lineBuffer.indexOf("\n");
|
|
305
|
+
while (newlineIdx >= 0) {
|
|
306
|
+
const line = lineBuffer.slice(0, newlineIdx);
|
|
307
|
+
lineBuffer = lineBuffer.slice(newlineIdx + 1);
|
|
308
|
+
for (const out of acc.process(line))
|
|
309
|
+
yield out;
|
|
310
|
+
newlineIdx = lineBuffer.indexOf("\n");
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
stderrBuf.push(evt.chunk);
|
|
316
|
+
yield { type: "stderr", chunk: evt.chunk };
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
exitCode = evt.exitCode;
|
|
321
|
+
durationMs = evt.durationMs;
|
|
322
|
+
timedOut = evt.timedOut;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (acc && lineBuffer.length > 0) {
|
|
326
|
+
for (const out of acc.process(lineBuffer))
|
|
327
|
+
yield out;
|
|
328
|
+
}
|
|
329
|
+
const stdout = stdoutBuf.join("");
|
|
330
|
+
const stderr = stderrBuf.join("");
|
|
331
|
+
if (timedOut) {
|
|
332
|
+
yield {
|
|
333
|
+
type: "completion",
|
|
334
|
+
result: {
|
|
335
|
+
output: stdout,
|
|
336
|
+
service: this.id,
|
|
337
|
+
success: false,
|
|
338
|
+
error: `Timed out after ${timeoutMs}ms`,
|
|
339
|
+
durationMs,
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
let parsedOutput;
|
|
345
|
+
let tokensUsed;
|
|
346
|
+
/**
|
|
347
|
+
* A structured, unambiguous error message extracted from a parsed CLI
|
|
348
|
+
* response (event `emit: "error"` rule, or `output.error`'s boolean
|
|
349
|
+
* field) — takes priority over exit code and raw-text heuristics below.
|
|
350
|
+
* Exists because a CLI can report failure while exiting 0 (Claude
|
|
351
|
+
* Code's is_error flag) or bury the real message behind an unrelated
|
|
352
|
+
* exit-1 stderr banner (Codex — confirmed 2026-07-24: its actual error
|
|
353
|
+
* is JSON on stdout; stderr is just "Reading additional input from
|
|
354
|
+
* stdin...", which the old stderr-first fallback picked instead).
|
|
355
|
+
*/
|
|
356
|
+
let structuredError;
|
|
357
|
+
if (eventDriven && acc) {
|
|
358
|
+
// Windows cmd /c can shuffle streams — if nothing parsed from stdout, retry stderr.
|
|
359
|
+
if (!acc.sawAnyJson && stderr) {
|
|
360
|
+
for (const line of stderr.split(/\r?\n/))
|
|
361
|
+
acc.process(line);
|
|
362
|
+
}
|
|
363
|
+
parsedOutput = acc.sawAnyJson ? acc.lastText.trim() || undefined : undefined;
|
|
364
|
+
if (acc.sawUsage)
|
|
365
|
+
tokensUsed = { input: acc.inputTokens, output: acc.outputTokens };
|
|
366
|
+
structuredError = acc.errorMessage;
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
const fields = protocol.output.fields ?? ["result", "output", "text", "response"];
|
|
370
|
+
switch (protocol.output.mode) {
|
|
371
|
+
case "text":
|
|
372
|
+
parsedOutput = stdout.trim() || undefined;
|
|
373
|
+
break;
|
|
374
|
+
case "json_field": {
|
|
375
|
+
const stdoutJson = parseJsonBlob(stdout);
|
|
376
|
+
const stdoutText = stdoutJson !== undefined ? extractField(stdoutJson, fields) : undefined;
|
|
377
|
+
let usageSource = stdoutJson;
|
|
378
|
+
if (stdoutText !== undefined) {
|
|
379
|
+
parsedOutput = stdoutText;
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
const stderrJson = parseJsonBlob(stderr);
|
|
383
|
+
parsedOutput = stderrJson !== undefined ? extractField(stderrJson, fields) : undefined;
|
|
384
|
+
usageSource = stderrJson ?? stdoutJson;
|
|
385
|
+
}
|
|
386
|
+
if (usageSource !== undefined && protocol.output.usage) {
|
|
387
|
+
const inTok = firstNumberAt(usageSource, protocol.output.usage.input);
|
|
388
|
+
const outTok = firstNumberAt(usageSource, protocol.output.usage.output);
|
|
389
|
+
if (inTok || outTok)
|
|
390
|
+
tokensUsed = { input: inTok, output: outTok };
|
|
391
|
+
}
|
|
392
|
+
if (usageSource !== undefined && protocol.output.error) {
|
|
393
|
+
const flagged = getPath(usageSource, protocol.output.error.field) === true;
|
|
394
|
+
if (flagged) {
|
|
395
|
+
const messageFields = protocol.output.error.messageFields ?? fields;
|
|
396
|
+
structuredError =
|
|
397
|
+
extractField(usageSource, messageFields) ??
|
|
398
|
+
`CLI reported an error (${protocol.output.error.field} set) with no extractable message`;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
case "jsonl_stream": {
|
|
404
|
+
const parts = [];
|
|
405
|
+
for (const line of stdout.split("\n")) {
|
|
406
|
+
const trimmed = line.trim();
|
|
407
|
+
if (!trimmed)
|
|
408
|
+
continue;
|
|
409
|
+
try {
|
|
410
|
+
const text = extractField(JSON.parse(trimmed), fields);
|
|
411
|
+
if (text)
|
|
412
|
+
parts.push(text);
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
// Non-JSON line — ignore rather than fail the whole parse.
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
parsedOutput = parts.join("") || undefined;
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const lenient = protocol.successRequiresOutput === false;
|
|
424
|
+
// A structured error overrides exit code entirely — a CLI that reports
|
|
425
|
+
// failure in its own response body (is_error, a turn.failed event) is
|
|
426
|
+
// reporting failure regardless of what the process exit code says.
|
|
427
|
+
if (structuredError === undefined) {
|
|
428
|
+
if (lenient && exitCode === 0) {
|
|
429
|
+
const output = parsedOutput ?? (stdout.trim() || stderr.trim());
|
|
430
|
+
const result = { output, service: this.id, success: true, durationMs };
|
|
431
|
+
if (tokensUsed)
|
|
432
|
+
result.tokensUsed = tokensUsed;
|
|
433
|
+
yield { type: "completion", result };
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
if (!lenient && exitCode === 0 && parsedOutput) {
|
|
437
|
+
const result = { output: parsedOutput, service: this.id, success: true, durationMs };
|
|
438
|
+
if (tokensUsed)
|
|
439
|
+
result.tokensUsed = tokensUsed;
|
|
440
|
+
yield { type: "completion", result };
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
// Text-mode CLIs conventionally put real error text on stderr with
|
|
445
|
+
// stdout empty; JSON-oriented modes (json_field/jsonl_stream) put their
|
|
446
|
+
// real payload — errors included — on stdout, with stderr often just
|
|
447
|
+
// decorative banner noise (see structuredError's doc comment). A
|
|
448
|
+
// structuredError, when present, is authoritative over both.
|
|
449
|
+
const rawErrorFallback = protocol.output.mode === "text"
|
|
450
|
+
? stderr.trim() || stdout.trim()
|
|
451
|
+
: stdout.trim() || stderr.trim();
|
|
452
|
+
const errorDetail = structuredError ?? (rawErrorFallback || `Exit code ${exitCode}`);
|
|
453
|
+
const { rateLimited, retryAfter } = detectRateLimit(errorDetail);
|
|
454
|
+
const result = {
|
|
455
|
+
output: parsedOutput ?? errorDetail,
|
|
456
|
+
service: this.id,
|
|
457
|
+
success: false,
|
|
458
|
+
error: errorDetail,
|
|
459
|
+
durationMs,
|
|
460
|
+
};
|
|
461
|
+
if (rateLimited) {
|
|
462
|
+
result.rateLimited = true;
|
|
463
|
+
if (retryAfter !== null)
|
|
464
|
+
result.retryAfter = retryAfter;
|
|
465
|
+
}
|
|
466
|
+
if (tokensUsed)
|
|
467
|
+
result.tokensUsed = tokensUsed;
|
|
468
|
+
yield { type: "completion", result };
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
//# sourceMappingURL=generic-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-cli.js","sourceRoot":"","sources":["../../src/dispatchers/generic-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP endpoint dispatcher for harness-dispatch — handles both wire protocols
|
|
3
|
+
* a `type: openai_compatible` route can speak, selected by `wire_protocol:`
|
|
4
|
+
* in config (default `openai_chat_completions`):
|
|
5
|
+
*
|
|
6
|
+
* openai_chat_completions POST /chat/completions — Ollama, LM Studio,
|
|
7
|
+
* OpenRouter, OpenAI API, NVIDIA NIM, and any
|
|
8
|
+
* other OpenAI-compatible endpoint.
|
|
9
|
+
* anthropic_messages POST /messages — Anthropic's API directly, or
|
|
10
|
+
* any third-party host that mirrors its Messages
|
|
11
|
+
* API shape (different auth headers, request/
|
|
12
|
+
* response body, and SSE event framing from
|
|
13
|
+
* OpenAI's — see the wire-protocol-specific
|
|
14
|
+
* helpers below).
|
|
15
|
+
*
|
|
16
|
+
* Transport: global `fetch` (Node 24+). No subprocess, no extra deps.
|
|
17
|
+
* Quota: reactive — parses x-ratelimit- and anthropic-ratelimit- headers
|
|
18
|
+
* on every response. Local endpoints (Ollama, LM Studio) have no
|
|
19
|
+
* rate limits.
|
|
20
|
+
*
|
|
21
|
+
* R3: `dispatch()` retains the buffered POST for simplicity + compatibility
|
|
22
|
+
* with tests that mock `fetch`. `stream()` switches to SSE streaming by
|
|
23
|
+
* setting `stream: true` in the request body and parsing wire-protocol-
|
|
24
|
+
* specific SSE frames as they arrive. The `completion` event is built from
|
|
25
|
+
* the summed delta content across all events.
|
|
26
|
+
*/
|
|
27
|
+
import type { DispatchResult, DispatcherEvent, QuotaInfo, ServiceConfig } from "../types.js";
|
|
28
|
+
import { BaseDispatcher, type DispatchOpts } from "./base.js";
|
|
29
|
+
/**
|
|
30
|
+
* Append `path` onto `baseUrl`, inserting `/v1` unless it's already there.
|
|
31
|
+
* Exported so callers other than this dispatcher (e.g. the `usage` tool's
|
|
32
|
+
* listModels, which hits GET {baseUrl}/models on the same endpoint) build
|
|
33
|
+
* URLs the same way — a baseUrl configured without a /v1 suffix must not
|
|
34
|
+
* 404 on one code path while working on the other.
|
|
35
|
+
*/
|
|
36
|
+
export declare function endpointUrl(baseUrl: string, path: string): string;
|
|
37
|
+
export declare class OpenAICompatibleDispatcher extends BaseDispatcher {
|
|
38
|
+
#private;
|
|
39
|
+
readonly id: string;
|
|
40
|
+
private readonly baseUrl;
|
|
41
|
+
private readonly model;
|
|
42
|
+
private readonly apiKey;
|
|
43
|
+
private readonly thinkingLevel?;
|
|
44
|
+
private readonly wireProtocol;
|
|
45
|
+
private readonly maxTokens;
|
|
46
|
+
constructor(svc: ServiceConfig);
|
|
47
|
+
isAvailable(): boolean;
|
|
48
|
+
checkQuota(): Promise<QuotaInfo>;
|
|
49
|
+
/**
|
|
50
|
+
* Buffered one-shot: POST with stream=false, parse a single JSON body.
|
|
51
|
+
* Kept as a fast-path (no incremental parsing overhead) and to preserve
|
|
52
|
+
* existing mocked-fetch tests.
|
|
53
|
+
*/
|
|
54
|
+
dispatch(prompt: string, files: string[], _workingDir: string, opts?: DispatchOpts): Promise<DispatchResult>;
|
|
55
|
+
stream(prompt: string, files: string[], workingDir: string, opts?: DispatchOpts): AsyncIterable<DispatcherEvent>;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=openai-compatible.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compatible.d.ts","sourceRoot":"","sources":["../../src/dispatchers/openai-compatible.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAgB,MAAM,aAAa,CAAC;AAC3G,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAU9D;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjE;AAsED,qBAAa,0BAA2B,SAAQ,cAAc;;IAC5D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,GAAG,EAAE,aAAa;IAY9B,WAAW,IAAI,OAAO;IAIhB,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC;IA0PtC;;;;OAIG;IACY,QAAQ,CACrB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EAAE,EACf,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,cAAc,CAAC;IAqG1B,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,YAAiB,GACtB,aAAa,CAAC,eAAe,CAAC;CAgNlC"}
|