153 lines
5.7 KiB
JavaScript
153 lines
5.7 KiB
JavaScript
const test = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
const { buildSdkTurnPrompt, resolveBackendKey, resolveSdkBackendBinPath } = require("./sdkStreamHandlers.cjs");
|
|
|
|
test("resolveBackendKey maps backend command/value to registry key", () => {
|
|
assert.equal(resolveBackendKey("claude"), "claude");
|
|
assert.equal(resolveBackendKey("codex"), "codex");
|
|
assert.equal(resolveBackendKey("copilot"), "copilot");
|
|
assert.equal(resolveBackendKey("codebuddy"), "codebuddy");
|
|
});
|
|
|
|
test("resolveBackendKey returns null for unknown", () => {
|
|
assert.equal(resolveBackendKey("claude-agent-acp"), null);
|
|
assert.equal(resolveBackendKey(""), null);
|
|
assert.equal(resolveBackendKey(undefined), null);
|
|
});
|
|
|
|
test("buildSdkTurnPrompt replays history only when requested", () => {
|
|
const prompt = buildSdkTurnPrompt({
|
|
prompt: "latest question",
|
|
replayHistory: true,
|
|
historyMessages: [
|
|
{ role: "user", content: "previous question" },
|
|
{ role: "assistant", content: "previous answer" },
|
|
],
|
|
});
|
|
|
|
assert.match(prompt, /Conversation context replay/);
|
|
assert.match(prompt, /USER: previous question/);
|
|
assert.match(prompt, /ASSISTANT: previous answer/);
|
|
assert.match(prompt, /latest question$/);
|
|
|
|
const steadyStatePrompt = buildSdkTurnPrompt({
|
|
prompt: "latest question",
|
|
replayHistory: false,
|
|
historyMessages: [{ role: "user", content: "previous question" }],
|
|
});
|
|
assert.equal(steadyStatePrompt, "latest question");
|
|
});
|
|
|
|
test("buildSdkTurnPrompt stages attachments as local file hints", () => {
|
|
const staged = [];
|
|
const prompt = buildSdkTurnPrompt({
|
|
prompt: "describe it",
|
|
attachments: [
|
|
{ base64Data: Buffer.from("img").toString("base64"), mediaType: "image/png", filename: "screen.png" },
|
|
],
|
|
writeAttachmentToTemp: (attachment) => `/tmp/${attachment.filename}`,
|
|
onStagedAttachment: (attachment) => staged.push(attachment),
|
|
});
|
|
|
|
assert.match(prompt, /Attached files/);
|
|
assert.match(prompt, /read_attachment/);
|
|
assert.match(prompt, /"screen\.png" \(image\/png\)/);
|
|
assert.match(prompt, /\/tmp\/screen\.png/);
|
|
assert.match(prompt, /describe it$/);
|
|
assert.deepEqual(staged, [{
|
|
filename: "screen.png",
|
|
mediaType: "image/png",
|
|
filePath: "/tmp/screen.png",
|
|
base64Data: Buffer.from("img").toString("base64"),
|
|
}]);
|
|
});
|
|
|
|
test("resolveSdkBackendBinPath prefers configured CodeBuddy path", () => {
|
|
const out = resolveSdkBackendBinPath({
|
|
backendKey: "codebuddy",
|
|
shellEnv: { PATH: "/usr/bin" },
|
|
env: { CODEBUDDY_CODE_PATH: "/shim/bin/codebuddy" },
|
|
resolveCliFromPath: () => "/usr/bin/codebuddy",
|
|
normalizeCliPathForPlatform: (value) => value,
|
|
realpath: () => "/opt/codebuddy/bin/codebuddy",
|
|
});
|
|
assert.equal(out, "/opt/codebuddy/bin/codebuddy");
|
|
});
|
|
|
|
test("resolveSdkBackendBinPath falls back to PATH when CodeBuddy path is invalid", () => {
|
|
const out = resolveSdkBackendBinPath({
|
|
backendKey: "codebuddy",
|
|
shellEnv: { PATH: "/usr/bin" },
|
|
env: { CODEBUDDY_CODE_PATH: "/missing/codebuddy" },
|
|
resolveCliFromPath: () => "/usr/bin/codebuddy",
|
|
normalizeCliPathForPlatform: () => null,
|
|
});
|
|
assert.equal(out, "/usr/bin/codebuddy");
|
|
});
|
|
|
|
test("resolveSdkBackendBinPath realpaths CodeBuddy PATH discovery fallback", () => {
|
|
const out = resolveSdkBackendBinPath({
|
|
backendKey: "codebuddy",
|
|
shellEnv: { PATH: "/usr/bin" },
|
|
env: {},
|
|
resolveCliFromPath: () => "/shim/bin/codebuddy",
|
|
normalizeCliPathForPlatform: () => null,
|
|
realpath: () => "/opt/codebuddy/bin/codebuddy",
|
|
});
|
|
assert.equal(out, "/opt/codebuddy/bin/codebuddy");
|
|
});
|
|
|
|
test("resolveSdkBackendBinPath resolves Windows CodeBuddy shim to the package JS entry", () => {
|
|
const out = resolveSdkBackendBinPath({
|
|
backendKey: "codebuddy",
|
|
shellEnv: { Path: "C:\\Users\\me\\AppData\\Roaming\\npm" },
|
|
env: {},
|
|
resolveCliFromPath: () => "C:\\Users\\me\\AppData\\Roaming\\npm\\codebuddy.cmd",
|
|
normalizeCliPathForPlatform: () => null,
|
|
realpath: (p) => p,
|
|
resolveCodebuddyExecutableForSdk: (p) =>
|
|
p.endsWith("codebuddy.cmd")
|
|
? "C:\\Users\\me\\AppData\\Roaming\\npm\\node_modules\\@tencent-ai\\codebuddy-code\\bin\\codebuddy"
|
|
: p,
|
|
});
|
|
assert.equal(
|
|
out,
|
|
"C:\\Users\\me\\AppData\\Roaming\\npm\\node_modules\\@tencent-ai\\codebuddy-code\\bin\\codebuddy",
|
|
);
|
|
});
|
|
|
|
test("resolveSdkBackendBinPath falls back to bundled CLI when Windows CodeBuddy shim is unresolvable", () => {
|
|
const out = resolveSdkBackendBinPath({
|
|
backendKey: "codebuddy",
|
|
shellEnv: { Path: "C:\\Users\\me\\AppData\\Roaming\\npm" },
|
|
env: {},
|
|
resolveCliFromPath: () => "C:\\Users\\me\\AppData\\Roaming\\npm\\codebuddy.cmd",
|
|
normalizeCliPathForPlatform: () => null,
|
|
realpath: (p) => p,
|
|
resolveCodebuddyExecutableForSdk: () => null,
|
|
});
|
|
assert.equal(out, undefined);
|
|
});
|
|
|
|
test("resolveSdkBackendBinPath keeps non-CodeBuddy SDK path normalization", () => {
|
|
const out = resolveSdkBackendBinPath({
|
|
backendKey: "codex",
|
|
shellEnv: { PATH: "C:\\Users\\me\\AppData\\Roaming\\npm" },
|
|
env: {},
|
|
resolveCliFromPath: () => "C:\\Users\\me\\AppData\\Roaming\\npm\\codex.cmd",
|
|
resolveSdkBinPath: () => "C:\\Users\\me\\AppData\\Roaming\\npm\\node_modules\\@openai\\codex\\bin\\codex.js",
|
|
});
|
|
assert.equal(out, "C:\\Users\\me\\AppData\\Roaming\\npm\\node_modules\\@openai\\codex\\bin\\codex.js");
|
|
});
|
|
|
|
test("resolveSdkBackendBinPath does not fall back to Windows shell shims for non-CodeBuddy", () => {
|
|
const out = resolveSdkBackendBinPath({
|
|
backendKey: "codex",
|
|
shellEnv: { PATH: "C:\\Users\\me\\AppData\\Roaming\\npm" },
|
|
env: {},
|
|
resolveCliFromPath: () => "C:\\Users\\me\\AppData\\Roaming\\npm\\codex.cmd",
|
|
resolveSdkBinPath: () => null,
|
|
});
|
|
assert.equal(out, undefined);
|
|
});
|