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.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import express from "express";
|
||||
import { registerTaskAgentBridge } from "../../src/routes/task-agent-bridge.js";
|
||||
import { registerTaskPublicationBridge } from "../../src/routes/task-publication-bridge.js";
|
||||
import { removeRuntimeSessionContext, setRuntimeSessionContext } from "../../src/runtime/sessionContext.js";
|
||||
import { TASK_AGENT, TASK_READER_AGENT } from "../../src/runtime/task-agent-policy.js";
|
||||
|
||||
describe("task reader bridge", () => {
|
||||
it("uses parent identity only for reads, revokes on run end and forbids child publication", async () => {
|
||||
const id = "bridge-task-parent";
|
||||
setRuntimeSessionContext({ sessionId: id, clientSessionId: id, actorKey: "a", projectKey: "p",
|
||||
projectId: "project-1", taskId: "task-1", traceId: "test", purpose: "task_execution" });
|
||||
let active = true;
|
||||
const app = express(); app.use(express.json());
|
||||
const reader = registerTaskAgentBridge(app, { internalToken: "TEST_ONLY", hasActiveRun: () => active,
|
||||
getSession: async (sessionId) => ({ id: sessionId, parentID: sessionId === id ? undefined : id,
|
||||
agent: sessionId === id ? TASK_AGENT : TASK_READER_AGENT, location: { directory: "/workspace" } }),
|
||||
});
|
||||
registerTaskPublicationBridge(app, { internalToken: "TEST_ONLY" });
|
||||
const server = app.listen(0, "127.0.0.1");
|
||||
await new Promise<void>((resolve) => server.once("listening", resolve));
|
||||
const base = `http://127.0.0.1:${(server.address() as { port: number }).port}`;
|
||||
const post = (path: string, token = "TEST_ONLY") => fetch(`${base}/internal/operational-task/${path}`, {
|
||||
method: "POST", headers: { "Content-Type": "application/json", "x-agent-internal-token": token }, body: JSON.stringify({ session_id: "child" }),
|
||||
});
|
||||
try {
|
||||
expect(await (await post("agent-policy")).json()).toEqual({ role: "reader" });
|
||||
expect((await post("agent-policy", "wrong")).status).toBe(403);
|
||||
expect((await reader("child"))?.runtimeSessionId).toBe(id);
|
||||
for (const kind of ["artifacts", "presentation"]) expect((await post(kind)).status).toBe(403);
|
||||
active = false;
|
||||
expect(await reader("child")).toBeNull();
|
||||
expect(await (await post("agent-policy")).json()).toEqual({ role: "denied" });
|
||||
} finally {
|
||||
removeRuntimeSessionContext(id);
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user