@testchimp/cli 0.1.36 → 0.1.37
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/dist/chimphands/run.js +71 -13
- package/package.json +1 -1
package/dist/chimphands/run.js
CHANGED
|
@@ -47,9 +47,14 @@ function postJsonFireAndForget(backend, apiKey, path, body) {
|
|
|
47
47
|
console.error(`ChimpHands API telemetry failed ${path}: ${detail}`);
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
-
|
|
50
|
+
const TESTCHIMP_PROVIDER_ID = "testchimp";
|
|
51
|
+
function resolveOpencodeModelId(boot) {
|
|
51
52
|
const raw = (boot.llm_model || "gpt-4o-mini").trim();
|
|
52
|
-
|
|
53
|
+
const modelId = raw.includes("/") ? raw.split("/").pop() || "gpt-4o-mini" : raw;
|
|
54
|
+
return modelId;
|
|
55
|
+
}
|
|
56
|
+
function resolveOpencodeModel(boot) {
|
|
57
|
+
return `${TESTCHIMP_PROVIDER_ID}/${resolveOpencodeModelId(boot)}`;
|
|
53
58
|
}
|
|
54
59
|
function extractOpencodeFatalError(raw) {
|
|
55
60
|
const line = raw.trim();
|
|
@@ -69,12 +74,40 @@ function extractOpencodeFatalError(raw) {
|
|
|
69
74
|
if (line.includes("Unexpected server error") && line.includes("UnknownError")) {
|
|
70
75
|
return line;
|
|
71
76
|
}
|
|
77
|
+
const errorLine = line.match(/^Error:\s*(.+)$/i);
|
|
78
|
+
if (errorLine?.[1]?.trim()) {
|
|
79
|
+
return errorLine[1].trim();
|
|
80
|
+
}
|
|
81
|
+
if (/not found/i.test(line) && line.length < 240) {
|
|
82
|
+
return line.trim();
|
|
83
|
+
}
|
|
72
84
|
return null;
|
|
73
85
|
}
|
|
86
|
+
function summarizeOpencodeFailure(stderr, stdout, exitCode) {
|
|
87
|
+
for (const chunk of [stderr, stdout]) {
|
|
88
|
+
for (const line of chunk.split("\n")) {
|
|
89
|
+
const fatal = extractOpencodeFatalError(line);
|
|
90
|
+
if (fatal)
|
|
91
|
+
return fatal;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const merged = `${stderr}\n${stdout}`.trim();
|
|
95
|
+
if (merged) {
|
|
96
|
+
const errorLines = merged
|
|
97
|
+
.split("\n")
|
|
98
|
+
.map((l) => l.trim())
|
|
99
|
+
.filter((l) => /^error:/i.test(l) || /not found/i.test(l));
|
|
100
|
+
if (errorLines.length)
|
|
101
|
+
return errorLines[errorLines.length - 1].replace(/^error:\s*/i, "").trim();
|
|
102
|
+
return merged.slice(0, 1200);
|
|
103
|
+
}
|
|
104
|
+
return exitCode ? `opencode exited with code ${exitCode}` : "opencode failed";
|
|
105
|
+
}
|
|
74
106
|
function writeOpencodeConfig(backend, apiKey, boot) {
|
|
75
107
|
const llmBase = (boot.llm_base_url || `${backend}/v1`).replace(/\/$/, "");
|
|
76
108
|
const llmKey = apiKey || boot.llm_api_key || "";
|
|
77
|
-
const
|
|
109
|
+
const modelId = resolveOpencodeModelId(boot);
|
|
110
|
+
const model = `${TESTCHIMP_PROVIDER_ID}/${modelId}`;
|
|
78
111
|
const mcpEnv = {
|
|
79
112
|
TESTCHIMP_API_KEY: apiKey,
|
|
80
113
|
TESTCHIMP_BACKEND_URL: backend,
|
|
@@ -87,13 +120,19 @@ function writeOpencodeConfig(backend, apiKey, boot) {
|
|
|
87
120
|
$schema: "https://opencode.ai/config.json",
|
|
88
121
|
model,
|
|
89
122
|
autoupdate: false,
|
|
90
|
-
enabled_providers: ["openai"],
|
|
91
123
|
provider: {
|
|
92
|
-
|
|
124
|
+
[TESTCHIMP_PROVIDER_ID]: {
|
|
125
|
+
npm: "@ai-sdk/openai-compatible",
|
|
126
|
+
name: "TestChimp",
|
|
93
127
|
options: {
|
|
94
128
|
apiKey: llmKey,
|
|
95
129
|
baseURL: llmBase,
|
|
96
130
|
},
|
|
131
|
+
models: {
|
|
132
|
+
[modelId]: {
|
|
133
|
+
name: modelId,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
97
136
|
},
|
|
98
137
|
},
|
|
99
138
|
mcp: {
|
|
@@ -173,6 +212,10 @@ function runOpencode(prompt, model, childEnv, postEvent) {
|
|
|
173
212
|
resolve({ code: 1, err: fatalError });
|
|
174
213
|
return;
|
|
175
214
|
}
|
|
215
|
+
if (code != null && code !== 0) {
|
|
216
|
+
resolve({ code, err: summarizeOpencodeFailure(err, buf, code) });
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
176
219
|
resolve({ code: code == null ? 1 : code, err });
|
|
177
220
|
});
|
|
178
221
|
});
|
|
@@ -195,11 +238,7 @@ function runOpencode(prompt, model, childEnv, postEvent) {
|
|
|
195
238
|
const errObj = e;
|
|
196
239
|
const stderr = errObj.stderr?.toString() || "";
|
|
197
240
|
const stdout = errObj.stdout?.toString() || "";
|
|
198
|
-
const fatal =
|
|
199
|
-
extractOpencodeFatalError(stdout) ||
|
|
200
|
-
stderr ||
|
|
201
|
-
errObj.message ||
|
|
202
|
-
"opencode failed";
|
|
241
|
+
const fatal = summarizeOpencodeFailure(stderr, stdout, errObj.status ?? 1);
|
|
203
242
|
return Promise.resolve({ code: errObj.status || 1, err: fatal });
|
|
204
243
|
}
|
|
205
244
|
}
|
|
@@ -347,10 +386,29 @@ export async function runChimphands(opts) {
|
|
|
347
386
|
while (prompt) {
|
|
348
387
|
const result = await runOpencode(ensureTestchimpPrompt(prompt), opencodeModel, childEnv, postEvent);
|
|
349
388
|
if (result.code !== 0) {
|
|
350
|
-
const errMsg = result.err || "opencode failed";
|
|
389
|
+
const errMsg = (result.err || "opencode failed").trim() || "opencode failed";
|
|
351
390
|
console.error(`ChimpHands OpenCode failed: ${errMsg}`);
|
|
352
|
-
|
|
353
|
-
|
|
391
|
+
try {
|
|
392
|
+
await postJson(backend, apiKey, "/api/chimphands/post_agent_event", {
|
|
393
|
+
sessionId,
|
|
394
|
+
role: ROLE_STATUS,
|
|
395
|
+
content: errMsg,
|
|
396
|
+
status: STATUS_FAILED,
|
|
397
|
+
githubRunId: githubRunId || undefined,
|
|
398
|
+
});
|
|
399
|
+
await postJson(backend, apiKey, "/api/chimphands/complete_session", {
|
|
400
|
+
sessionId,
|
|
401
|
+
status: STATUS_FAILED,
|
|
402
|
+
errorMessage: errMsg,
|
|
403
|
+
githubRunId: githubRunId || undefined,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
catch (reportErr) {
|
|
407
|
+
const detail = reportErr instanceof Error ? reportErr.message : String(reportErr);
|
|
408
|
+
console.error(`ChimpHands failed to report OpenCode error to backend: ${detail}`);
|
|
409
|
+
postEvent(ROLE_STATUS, errMsg, STATUS_FAILED);
|
|
410
|
+
complete(STATUS_FAILED, errMsg);
|
|
411
|
+
}
|
|
354
412
|
process.exit(result.code || 1);
|
|
355
413
|
}
|
|
356
414
|
postEvent(ROLE_STATUS, "Waiting for user input", STATUS_WAITING_USER);
|
package/package.json
CHANGED