test(live): probe Read tool via gateway
This commit is contained in:
parent
34664601e0
commit
8a5fb796c0
@ -92,6 +92,7 @@
|
|||||||
"test:coverage": "vitest run --coverage",
|
"test:coverage": "vitest run --coverage",
|
||||||
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
||||||
"test:live": "vitest run --config vitest.live.config.ts",
|
"test:live": "vitest run --config vitest.live.config.ts",
|
||||||
|
"test:docker:onboard": "bash scripts/e2e/onboard-docker.sh",
|
||||||
"test:docker:qr": "bash scripts/e2e/qr-import-docker.sh",
|
"test:docker:qr": "bash scripts/e2e/qr-import-docker.sh",
|
||||||
"test:docker:doctor-switch": "bash scripts/e2e/doctor-install-switch-docker.sh",
|
"test:docker:doctor-switch": "bash scripts/e2e/doctor-install-switch-docker.sh",
|
||||||
"protocol:gen": "tsx scripts/protocol-gen.ts",
|
"protocol:gen": "tsx scripts/protocol-gen.ts",
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { resolveClawdbotAgentDir } from "../agents/agent-paths.js";
|
|||||||
import { getApiKeyForModel } from "../agents/model-auth.js";
|
import { getApiKeyForModel } from "../agents/model-auth.js";
|
||||||
import { ensureClawdbotModelsJson } from "../agents/models-config.js";
|
import { ensureClawdbotModelsJson } from "../agents/models-config.js";
|
||||||
import { loadConfig } from "../config/config.js";
|
import { loadConfig } from "../config/config.js";
|
||||||
|
import { resolveUserPath } from "../utils.js";
|
||||||
import { GatewayClient } from "./client.js";
|
import { GatewayClient } from "./client.js";
|
||||||
import { startGatewayServer } from "./server.js";
|
import { startGatewayServer } from "./server.js";
|
||||||
import { getFreePort } from "./test-helpers.js";
|
import { getFreePort } from "./test-helpers.js";
|
||||||
@ -117,6 +118,18 @@ describeLive("gateway live (dev agent, profile keys)", () => {
|
|||||||
const cfg = loadConfig();
|
const cfg = loadConfig();
|
||||||
await ensureClawdbotModelsJson(cfg);
|
await ensureClawdbotModelsJson(cfg);
|
||||||
|
|
||||||
|
const workspaceDir = resolveUserPath(
|
||||||
|
cfg.agents?.defaults?.workspace ?? path.join(os.homedir(), "clawd"),
|
||||||
|
);
|
||||||
|
await fs.mkdir(workspaceDir, { recursive: true });
|
||||||
|
const nonceA = randomUUID();
|
||||||
|
const nonceB = randomUUID();
|
||||||
|
const toolProbePath = path.join(
|
||||||
|
workspaceDir,
|
||||||
|
`.clawdbot-live-tool-probe.${nonceA}.txt`,
|
||||||
|
);
|
||||||
|
await fs.writeFile(toolProbePath, `nonceA=${nonceA}\nnonceB=${nonceB}\n`);
|
||||||
|
|
||||||
const agentDir = resolveClawdbotAgentDir();
|
const agentDir = resolveClawdbotAgentDir();
|
||||||
const authStorage = discoverAuthStorage(agentDir);
|
const authStorage = discoverAuthStorage(agentDir);
|
||||||
const modelRegistry = discoverModels(authStorage, agentDir);
|
const modelRegistry = discoverModels(authStorage, agentDir);
|
||||||
@ -222,6 +235,30 @@ describeLive("gateway live (dev agent, profile keys)", () => {
|
|||||||
throw new Error(`missing required keywords: ${text}`);
|
throw new Error(`missing required keywords: ${text}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Real tool invocation: force the agent to Read a local file and echo a nonce.
|
||||||
|
const runIdTool = randomUUID();
|
||||||
|
const toolProbe = await client.request<AgentFinalPayload>(
|
||||||
|
"agent",
|
||||||
|
{
|
||||||
|
sessionKey,
|
||||||
|
idempotencyKey: `idem-${runIdTool}-tool`,
|
||||||
|
message:
|
||||||
|
`Call the Read tool on "${toolProbePath}". ` +
|
||||||
|
`Then reply with exactly: ${nonceA} ${nonceB}. No extra text.`,
|
||||||
|
deliver: false,
|
||||||
|
},
|
||||||
|
{ expectFinal: true },
|
||||||
|
);
|
||||||
|
if (toolProbe?.status !== "ok") {
|
||||||
|
throw new Error(
|
||||||
|
`tool probe failed: status=${String(toolProbe?.status)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const toolText = extractPayloadText(toolProbe?.result);
|
||||||
|
if (!toolText.includes(nonceA) || !toolText.includes(nonceB)) {
|
||||||
|
throw new Error(`tool probe missing nonce: ${toolText}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Regression: tool-call-only turn followed by a user message (OpenAI responses bug class).
|
// Regression: tool-call-only turn followed by a user message (OpenAI responses bug class).
|
||||||
if (
|
if (
|
||||||
(model.provider === "openai" &&
|
(model.provider === "openai" &&
|
||||||
@ -236,7 +273,7 @@ describeLive("gateway live (dev agent, profile keys)", () => {
|
|||||||
sessionKey,
|
sessionKey,
|
||||||
idempotencyKey: `idem-${runId2}-1`,
|
idempotencyKey: `idem-${runId2}-1`,
|
||||||
message:
|
message:
|
||||||
"Call the read tool on package.json. Do not write any other text.",
|
"Call the Read tool on package.json. Do not write any other text.",
|
||||||
deliver: false,
|
deliver: false,
|
||||||
},
|
},
|
||||||
{ expectFinal: true },
|
{ expectFinal: true },
|
||||||
@ -285,6 +322,7 @@ describeLive("gateway live (dev agent, profile keys)", () => {
|
|||||||
} finally {
|
} finally {
|
||||||
client.stop();
|
client.stop();
|
||||||
await server.close({ reason: "live test complete" });
|
await server.close({ reason: "live test complete" });
|
||||||
|
await fs.rm(toolProbePath, { force: true });
|
||||||
await fs.rm(tempDir, { recursive: true, force: true });
|
await fs.rm(tempDir, { recursive: true, force: true });
|
||||||
|
|
||||||
process.env.CLAWDBOT_CONFIG_PATH = previous.configPath;
|
process.env.CLAWDBOT_CONFIG_PATH = previous.configPath;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user