Files
next-tjwater-agent/tests/routes/agentMessages.test.ts
T
jiang 6a49d2209e feat(agent): unify MCP tools and adopt Responses delivery
Move project and host queries into native MCP with host-owned OAuth/context,
while retaining memory, skills, actions and publication plugins. Add nearby-model
queries and explicit chat/task/learning model defaults.

Adopt Responses HTTP/SSE and native steer/queue inbox delivery, preserving scoped
session ownership, pending input edits and investigation communication.

Disable local-provider discovery: Server /health allowed native vLLM to probe
/v1/models on port 8000. A native before/after regression prevents recurrence.

Validation: 170 focused Bun tests; service/plugin typechecks; native discovery,
provider-discovery and input-inbox smoke checks; no paid model inference.
2026-10-19 18:46:58 +08:00

62 lines
4.2 KiB
TypeScript

import { describe, expect, it, mock } from "bun:test";
import express from "express";
import { createAgentMessageQuery, registerAgentMessageBridge } from "../../src/routes/agent-message-routes.js";
import { setRuntimeSessionContext, removeRuntimeSessionContext } from "../../src/runtime/sessionContext.js";
import type { SessionMetadataStore, SessionRecord } from "../../src/sessions/metadataStore.js";
import type { AgentMessageCoordinator } from "../../src/chat/agent-message-coordinator.js";
const task = "81000000-0000-4000-8000-000000000001";
const run = "81000000-0000-4000-8000-000000000002";
const request = "81000000-0000-4000-8000-000000000003";
describe("scoped Agent message bridge", () => {
it("derives sender from runtime, validates arguments, and denies child/review/cross-run writes", async () => {
const records = new Map<string, SessionRecord>();
for (const [id, purpose] of [["main", "ordinary_chat"], ["investigator", "task_execution"], ["review", "ordinary_chat"]] as const) {
const record: SessionRecord = { sessionId: id, actorKey: "owner", projectKey: "project", projectId: task,
createdAt: "now", updatedAt: "now", status: "active", purpose, ...(purpose === "task_execution" ? { taskId: task, runId: run } : {}) };
records.set(id, record);
setRuntimeSessionContext({ ...record, clientSessionId: id, traceId: "test", learningMode: id === "review" ? "review" : "interactive" });
}
const send = mock(async (_session: string, input: unknown) => ({ input, target_session_id: null }));
const reply = mock(async () => ({}));
const read = mock(async () => ({ items: [], next_cursor: null }));
const coordinator = {
client: { send, reply, list: read, get: async () => ({ task_id: task, run_id: request, direction: "to_task" }) },
isActive: () => true, notify: () => {}, deliver: async () => {},
} as unknown as AgentMessageCoordinator;
const app = express(); app.use(express.json());
registerAgentMessageBridge(app, { internalToken: "test-only", messages: coordinator,
sessions: { get: async (_context: unknown, id: string) => records.get(id) ?? null } as unknown as SessionMetadataStore });
const server = app.listen(0, "127.0.0.1");
await new Promise<void>((resolve) => server.once("listening", resolve));
const url = `http://127.0.0.1:${(server.address() as { port: number }).port}/internal/agent-messages`;
const call = (operation: string, session: string, input: unknown, token = "test-only") => fetch(`${url}/${operation}`, {
method: "POST", headers: { "Content-Type": "application/json", "x-agent-internal-token": token },
body: JSON.stringify({ session_id: session, input }),
});
const input = { task_id: task, run_id: run, request_id: request, message: "核对压力记录" };
try {
expect((await call("send", "main", input, "wrong")).status).toBe(403);
expect((await call("send", "child", input)).status).toBe(403);
expect((await call("send", "review", input)).status).toBe(403);
expect((await call("send", "investigator", input)).status).toBe(403);
expect((await call("send", "main", { ...input, source_session_id: "someone-else" })).status).toBe(400);
expect((await call("send", "main", input)).status).toBe(200);
expect(send).toHaveBeenCalledTimes(1);
expect(send.mock.calls[0]).toEqual(["main", input]);
expect((await call("reply", "investigator", { message_id: request, request_id: request, message: "回复" })).status).toBe(403);
expect(reply).not.toHaveBeenCalled();
expect((await call("read", "main", {})).status).toBe(404);
const query = createAgentMessageQuery({ sessions: { get: async (_context: unknown, id: string) => records.get(id) ?? null } as unknown as SessionMetadataStore, messages: coordinator });
await query("main", "read", {});
expect(read).toHaveBeenCalledWith("main", "main", undefined, 20);
await expect(query("investigator", "list", {})).rejects.toThrow();
await expect(query("child", "read", {})).rejects.toThrow();
} finally {
for (const id of records.keys()) removeRuntimeSessionContext(id);
await new Promise<void>((resolve) => server.close(() => resolve()));
}
});
});