Files
next-tjwater-agent/tests/opencode/internalBridgeTools.test.ts
T

267 lines
9.4 KiB
TypeScript

import { afterEach, describe, expect, it } from "bun:test";
let bridgeServer: ReturnType<typeof Bun.serve> | undefined;
afterEach(() => {
bridgeServer?.stop(true);
bridgeServer = undefined;
});
describe("OpenCode internal bridge tools", () => {
it("uses the documented AGENT_INTERNAL_TOKEN from an external process", async () => {
let receivedToken: string | null = null;
let receivedSessionId: string | null = null;
bridgeServer = Bun.serve({
hostname: "127.0.0.1",
port: 0,
fetch(request) {
const url = new URL(request.url);
receivedToken = request.headers.get("x-agent-internal-token");
receivedSessionId = url.searchParams.get("session_id");
return Response.json({ task: { task_id: "task-1" } });
},
});
const child = Bun.spawn([
processExecPath(),
"-e",
[
'import tool from "./.opencode/tools/get_operational_task_context.ts";',
'const result = await tool.execute({}, { sessionID: "runtime-session-1" });',
"process.stdout.write(result);",
].join("\n"),
], {
cwd: process.cwd(),
env: {
...process.env,
AGENT_INTERNAL_TOKEN: "external-shared-token",
TJWATER_AGENT_INTERNAL_BASE_URL: `http://127.0.0.1:${bridgeServer.port}`,
TJWATER_AGENT_INTERNAL_TOKEN: "",
},
stderr: "pipe",
stdout: "pipe",
});
const [exitCode, stdout, stderr] = await Promise.all([
child.exited,
new Response(child.stdout).text(),
new Response(child.stderr).text(),
]);
expect({ exitCode, stderr }).toEqual({ exitCode: 0, stderr: "" });
expect(JSON.parse(stdout)).toEqual({ task: { task_id: "task-1" } });
expect(String(receivedToken)).toBe("external-shared-token");
expect(String(receivedSessionId)).toBe("runtime-session-1");
});
it("fails explicitly before making a bridge request when no shared token exists", async () => {
const child = Bun.spawn([
processExecPath(),
"-e",
[
'import tool from "./.opencode/tools/get_operational_task_context.ts";',
'await tool.execute({}, { sessionID: "runtime-session-1" });',
].join("\n"),
], {
cwd: process.cwd(),
env: {
...process.env,
AGENT_INTERNAL_TOKEN: "",
TJWATER_AGENT_INTERNAL_TOKEN: "",
},
stderr: "pipe",
stdout: "pipe",
});
const [exitCode, stderr] = await Promise.all([
child.exited,
new Response(child.stderr).text(),
]);
expect(exitCode).not.toBe(0);
expect(stderr).toContain("internal Agent tool bridge is not configured");
});
it("publishes execution plans through the authenticated task artifact bridge", async () => {
let receivedBody: Record<string, unknown> | undefined;
bridgeServer = Bun.serve({
hostname: "127.0.0.1",
port: 0,
async fetch(request) {
receivedBody = await request.json() as Record<string, unknown>;
return Response.json({ plan_revision: 1, report_revision: null });
},
});
const child = Bun.spawn([
processExecPath(),
"-e",
[
'import tool from "./.opencode/tools/publish_execution_plan.ts";',
'const result = await tool.execute({ request_id: "60000000-0000-4000-8000-000000000001", schema: "execution-plan@2", title: "调查", reason: "开始", nodes: [{ id: "read", title: "读取", status: "completed", owner: "agent", detail: "完成", evidence: ["evidence-1"], action_refs: [], kind: "activity" }], edges: [] }, { sessionID: "runtime-session-1" });',
"process.stdout.write(result);",
].join("\n"),
], {
cwd: process.cwd(),
env: {
...process.env,
AGENT_INTERNAL_TOKEN: "external-shared-token",
TJWATER_AGENT_INTERNAL_BASE_URL: `http://127.0.0.1:${bridgeServer.port}`,
TJWATER_AGENT_INTERNAL_TOKEN: "",
},
stderr: "pipe",
stdout: "pipe",
});
const [exitCode, stdout, stderr] = await Promise.all([
child.exited,
new Response(child.stdout).text(),
new Response(child.stderr).text(),
]);
expect({ exitCode, stderr }).toEqual({ exitCode: 0, stderr: "" });
expect(JSON.parse(stdout)).toEqual({ plan_revision: 1, report_revision: null });
expect(receivedBody).toMatchObject({
session_id: "runtime-session-1",
request_id: "60000000-0000-4000-8000-000000000001",
execution_plan: { title: "调查", reason: "开始" },
});
});
it("fails the execution plan tool when the task artifact bridge rejects it", async () => {
let requestCount = 0;
bridgeServer = Bun.serve({
hostname: "127.0.0.1",
port: 0,
fetch() {
requestCount += 1;
return Response.json({ message: "A running or completed node has incomplete predecessors" }, { status: 409 });
},
});
const child = Bun.spawn([
processExecPath(),
"-e",
[
'import tool from "./.opencode/tools/publish_execution_plan.ts";',
'await tool.execute({ request_id: "60000000-0000-4000-8000-000000000001", schema: "execution-plan@2", title: "调查", reason: "开始", nodes: [{ id: "read", title: "读取", status: "completed", owner: "agent", detail: "完成", evidence: ["evidence-1"], action_refs: [], kind: "activity" }], edges: [] }, { sessionID: "runtime-session-1" });',
].join("\n"),
], {
cwd: process.cwd(),
env: {
...process.env,
AGENT_INTERNAL_TOKEN: "external-shared-token",
TJWATER_AGENT_INTERNAL_BASE_URL: `http://127.0.0.1:${bridgeServer.port}`,
TJWATER_AGENT_INTERNAL_TOKEN: "",
},
stderr: "pipe",
stdout: "pipe",
});
const [exitCode, stdout, stderr] = await Promise.all([
child.exited,
new Response(child.stdout).text(),
new Response(child.stderr).text(),
]);
expect(exitCode).not.toBe(0);
expect(stdout).toBe("");
expect(stderr).toContain("task plan publish failed (409)");
expect(requestCount).toBe(1);
});
it("rejects an invalid work-order action payload before a bridge request", async () => {
let requestCount = 0;
bridgeServer = Bun.serve({
hostname: "127.0.0.1",
port: 0,
fetch() {
requestCount += 1;
return Response.json({ action_id: "70000000-0000-4000-8000-000000000001" });
},
});
const child = Bun.spawn([
processExecPath(),
"-e",
[
'import tool from "./.opencode/tools/propose_task_action.ts";',
'await tool.execute({ request_id: "60000000-0000-4000-8000-000000000001", kind: "create_work_order", reason: "现场采样", payload: { title: "采样", summary: "错误字段", priority: "high" }, evidence_refs: [] }, { sessionID: "runtime-session-1" });',
].join("\n"),
], {
cwd: process.cwd(),
env: {
...process.env,
AGENT_INTERNAL_TOKEN: "external-shared-token",
TJWATER_AGENT_INTERNAL_BASE_URL: `http://127.0.0.1:${bridgeServer.port}`,
TJWATER_AGENT_INTERNAL_TOKEN: "",
},
stderr: "pipe",
stdout: "pipe",
});
const [exitCode, stdout] = await Promise.all([
child.exited,
new Response(child.stdout).text(),
new Response(child.stderr).text(),
]);
expect(exitCode).not.toBe(0);
expect(stdout).toBe("");
expect(requestCount).toBe(0);
});
it("sends a valid work-order proposal using the exact Server payload fields", async () => {
let receivedBody: Record<string, unknown> | undefined;
bridgeServer = Bun.serve({
hostname: "127.0.0.1",
port: 0,
async fetch(request) {
receivedBody = await request.json() as Record<string, unknown>;
return Response.json({
action_id: "70000000-0000-4000-8000-000000000001",
approval_status: "pending",
execution_status: "not_submitted",
});
},
});
const child = Bun.spawn([
processExecPath(),
"-e",
[
'import tool from "./.opencode/tools/propose_task_action.ts";',
'const result = await tool.execute({ request_id: "60000000-0000-4000-8000-000000000001", kind: "create_work_order", reason: "现场采样", payload: { title: "采样", description: "采集二次供水水样", work_order_type: "water_quality_sampling", priority: "urgent", location: "联调演示小区" }, evidence_refs: ["evidence-1"], node_id: "field_sampling" }, { sessionID: "runtime-session-1" });',
"process.stdout.write(result);",
].join("\n"),
], {
cwd: process.cwd(),
env: {
...process.env,
AGENT_INTERNAL_TOKEN: "external-shared-token",
TJWATER_AGENT_INTERNAL_BASE_URL: `http://127.0.0.1:${bridgeServer.port}`,
TJWATER_AGENT_INTERNAL_TOKEN: "",
},
stderr: "pipe",
stdout: "pipe",
});
const [exitCode, stdout, stderr] = await Promise.all([
child.exited,
new Response(child.stdout).text(),
new Response(child.stderr).text(),
]);
expect({ exitCode, stderr }).toEqual({ exitCode: 0, stderr: "" });
expect(JSON.parse(stdout)).toMatchObject({ approval_status: "pending" });
expect(receivedBody).toMatchObject({
session_id: "runtime-session-1",
action: {
kind: "create_work_order",
payload: {
title: "采样",
description: "采集二次供水水样",
work_order_type: "water_quality_sampling",
priority: "urgent",
},
},
});
});
});
const processExecPath = () => process.execPath;