feat: upgrade investigation and presentation runtime
Generic Container CI/CD / test-build-publish (push) Successful in 1m6s
Agent CI/CD / build-test-publish-and-deploy (push) Successful in 1m7s

This commit is contained in:
2026-10-30 17:30:19 +08:00
parent 3b52a0ddab
commit 6336157ff4
104 changed files with 6541 additions and 961 deletions
+28 -8
View File
@@ -1,4 +1,4 @@
import { afterEach, expect, it, mock } from "bun:test";
import { afterEach, expect, it, mock, spyOn } from "bun:test";
import { Client, StreamableHTTPClientTransport, type Tool } from "@modelcontextprotocol/client";
import { startQueryMcpServer } from "../../src/mcp/query-server.js";
import { createLocalQueryExecutor } from "../../src/mcp/local-query-tools.js";
@@ -17,17 +17,17 @@ afterEach(async () => {
});
const productTool: Tool = { name: "get_task_context", description: "Bound task", inputSchema: { type: "object", properties: { report_revision: { type: "integer", minimum: 1 } }, additionalProperties: false } };
it("advertises simulation budgets and derives the native connection ceiling from the catalog", async () => {
it("hides HTTP budgets from models and fixes the native connection ceiling", async () => {
const simulation: Tool = { name: "run_simulation", inputSchema: { type: "object", properties: {
timeout_seconds: { type: "integer", minimum: 1, maximum: 3600, default: 120 },
timeout_seconds: { type: "integer", minimum: 1, maximum: 240, default: 120 },
}, additionalProperties: false } };
const { server, client, call, query } = await setup({ productTools: [simulation] });
setRuntimeSessionContext(owner);
expect(server.executionTimeoutMs).toBe(35_000);
expect((await client.listTools()).tools[0].inputSchema.properties?.timeout_seconds).toMatchObject({ maximum: 3600 });
expect((await call("run_simulation", { timeout_seconds: 900 })).isError).not.toBeTrue();
expect((query.mock.calls[0] as unknown as unknown[])[3]).toEqual({ timeout_seconds: 900 });
try { await call("run_simulation", { timeout_seconds: 3601 }); } catch { /* SDK schema rejection */ }
expect(server.executionTimeoutMs).toBe(300_000);
expect((await client.listTools()).tools[0].inputSchema.properties).not.toHaveProperty("timeout_seconds");
expect((await call("run_simulation", {})).isError).not.toBeTrue();
expect((query.mock.calls[0] as unknown as unknown[])[3]).toEqual({});
try { await call("run_simulation", { timeout_seconds: 241 }); } catch { /* SDK schema rejection */ }
expect(query).toHaveBeenCalledTimes(1);
});
it("discovers calculations natively but denies verified readers before upstream dispatch", async () => {
@@ -183,3 +183,23 @@ it("distinguishes safe network and timeout failures without upstream text", asyn
expect(JSON.stringify(result)).not.toContain("SECRET");
}
});
for (const stage of ["reader", "identity", "artifact"] as const) {
it(`bounds a hanging ${stage} operation within the host deadline`, async () => {
const never = () => new Promise<never>(() => {});
const name = stage === "artifact" ? "export_project_model" : "get_task_context";
const { call } = await setup({ productTools: [{ ...productTool, name }],
...(stage === "reader" ? { resolveReader: never } : {}),
...(stage === "identity" ? { resolveNativeCall: never } : {}),
...(stage === "artifact" ? { artifactWorkspace: never } : {}),
});
if (stage !== "reader") setRuntimeSessionContext(owner);
const original = AbortSignal.timeout.bind(AbortSignal);
const timeout = spyOn(AbortSignal, "timeout").mockImplementation((ms) => original(ms === 180_000 ? 20 : ms));
try {
const result = await call(name);
expect(result.isError).toBeTrue();
expect(JSON.stringify(result)).toContain("Query timed out");
} finally { timeout.mockRestore(); }
});
}