158 lines
4.1 KiB
TypeScript
158 lines
4.1 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { mkdtemp, realpath, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import test from "node:test";
|
|
|
|
import { runHermesCommandForTesting } from "../src/lib/execution/backends/hermes-runner.ts";
|
|
|
|
async function createTempScript(source: string) {
|
|
const dir = await mkdtemp(join(tmpdir(), "hermes-runner-"));
|
|
const scriptPath = join(dir, "hermes-script.mjs");
|
|
await writeFile(scriptPath, source, "utf8");
|
|
return { dir, scriptPath };
|
|
}
|
|
|
|
test("Hermes runner 会按固定 chat -q -Q 形态执行并提取正文", async () => {
|
|
const workspace = await mkdtemp(join(tmpdir(), "hermes-runner-cwd-"));
|
|
const expectedWorkspace = await realpath(workspace);
|
|
const { scriptPath } = await createTempScript(`
|
|
process.stdout.write(JSON.stringify({
|
|
argv: process.argv.slice(2),
|
|
cwd: process.cwd(),
|
|
envSource: process.env.HERMES_SESSION_SOURCE || ""
|
|
}) + "\\n");
|
|
process.stdout.write("Hermes smoke completed\\n\\n");
|
|
process.stdout.write("session_id: hermes-session-123\\n");
|
|
`);
|
|
|
|
const result = await runHermesCommandForTesting({
|
|
config: {
|
|
enabled: true,
|
|
command: process.execPath,
|
|
args: [scriptPath],
|
|
cwd: workspace,
|
|
timeoutMs: 1000,
|
|
defaultModel: "gpt-5.4",
|
|
toolsets: ["web", "terminal"],
|
|
skills: ["boss-dev"],
|
|
sourceTag: "tool",
|
|
},
|
|
payload: {
|
|
executionPrompt: "请输出链路正常",
|
|
model: "gpt-5.5",
|
|
},
|
|
});
|
|
|
|
assert.equal(result.status, "completed");
|
|
if (result.status !== "completed") {
|
|
assert.fail("expected completed");
|
|
}
|
|
|
|
const lines = result.output.split("\n");
|
|
const metadata = JSON.parse(lines[0] ?? "{}") as {
|
|
argv: string[];
|
|
cwd: string;
|
|
envSource: string;
|
|
};
|
|
assert.deepEqual(metadata.argv, [
|
|
"chat",
|
|
"-q",
|
|
"请输出链路正常",
|
|
"-Q",
|
|
"--source",
|
|
"tool",
|
|
"-m",
|
|
"gpt-5.5",
|
|
"-t",
|
|
"web,terminal",
|
|
"-s",
|
|
"boss-dev",
|
|
]);
|
|
assert.equal(metadata.cwd, expectedWorkspace);
|
|
assert.equal(metadata.envSource, "");
|
|
assert.equal(lines.at(-1), "Hermes smoke completed");
|
|
assert.equal(result.sessionId, "hermes-session-123");
|
|
});
|
|
|
|
test("Hermes runner 会把非零退出码映射成 stderr 或退出码错误", async () => {
|
|
const { scriptPath } = await createTempScript(`
|
|
process.stderr.write("hermes crashed");
|
|
process.exit(2);
|
|
`);
|
|
|
|
const result = await runHermesCommandForTesting({
|
|
config: {
|
|
enabled: true,
|
|
command: process.execPath,
|
|
args: [scriptPath],
|
|
timeoutMs: 1000,
|
|
sourceTag: "tool",
|
|
},
|
|
payload: {
|
|
executionPrompt: "anything",
|
|
},
|
|
});
|
|
|
|
assert.equal(result.status, "failed");
|
|
if (result.status !== "failed") {
|
|
assert.fail("expected failed");
|
|
}
|
|
|
|
assert.match(result.error, /hermes crashed/);
|
|
});
|
|
|
|
test("Hermes runner 在输出只有 session_id 时会视为失败", async () => {
|
|
const { scriptPath } = await createTempScript(`
|
|
process.stdout.write("session_id: hermes-session-123\\n");
|
|
`);
|
|
|
|
const result = await runHermesCommandForTesting({
|
|
config: {
|
|
enabled: true,
|
|
command: process.execPath,
|
|
args: [scriptPath],
|
|
timeoutMs: 1000,
|
|
sourceTag: "tool",
|
|
},
|
|
payload: {
|
|
executionPrompt: "anything",
|
|
},
|
|
});
|
|
|
|
assert.equal(result.status, "failed");
|
|
if (result.status !== "failed") {
|
|
assert.fail("expected failed");
|
|
}
|
|
|
|
assert.match(result.error, /EMPTY_HERMES_RESPONSE/);
|
|
});
|
|
|
|
test("Hermes runner 超时后返回 HERMES_TIMEOUT", async () => {
|
|
const { scriptPath } = await createTempScript(`
|
|
setTimeout(() => {
|
|
process.stdout.write("late response\\n");
|
|
}, 500);
|
|
`);
|
|
|
|
const result = await runHermesCommandForTesting({
|
|
config: {
|
|
enabled: true,
|
|
command: process.execPath,
|
|
args: [scriptPath],
|
|
timeoutMs: 50,
|
|
sourceTag: "tool",
|
|
},
|
|
payload: {
|
|
executionPrompt: "slow",
|
|
},
|
|
});
|
|
|
|
assert.equal(result.status, "failed");
|
|
if (result.status !== "failed") {
|
|
assert.fail("expected failed");
|
|
}
|
|
|
|
assert.match(result.error, /HERMES_TIMEOUT/);
|
|
});
|