feat(mcp): resume queued calculation jobs

This commit is contained in:
2026-10-29 18:25:22 +08:00
parent 52681a8451
commit 799b99f310
20 changed files with 348 additions and 42 deletions
+26 -2
View File
@@ -23,7 +23,7 @@ it("advertises simulation budgets and derives the native connection ceiling from
}, additionalProperties: false } };
const { server, client, call, query } = await setup({ productTools: [simulation] });
setRuntimeSessionContext(owner);
expect(server.executionTimeoutMs).toBe(3_665_000);
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 });
@@ -45,7 +45,7 @@ it("discovers calculations natively but denies verified readers before upstream
async function setup(extra: Partial<Parameters<typeof startQueryMcpServer>[0]> = {}) {
const executeLocal = mock(async () => ({ safe: true }));
const query = mock(async () => ({ content: [{ type: "text" as const, text: "evidence" }], structuredContent: { evidence_id: "E1", data: { value: 1 } } }));
const server = startQueryMcpServer({ internalToken: "MCP_TEST_ONLY", productClient: { query }, productTools: [productTool], resolveReader: async () => null, executeLocal, ...extra });
const server = startQueryMcpServer({ internalToken: "MCP_TEST_ONLY", productClient: { query }, productTools: [productTool], resolveNativeCall: async () => "native-call-1", resolveReader: async () => null, executeLocal, ...extra });
servers.push(server);
const client = new Client({ name: "query-test", version: "1" }, { versionNegotiation: { mode: { pin: "2026-07-28" } } });
clients.push(client);
@@ -159,3 +159,27 @@ it("replaces unavailable evidence resources with the authorized paging tool with
data: { evidence_read: { tool: "mcp_tjwater_get_task_evidence", arguments: { evidence_id: "E1", limit: 20, offset: 0 } } } });
expect(upstream.structuredContent.data.resource_uri).toBe(uri);
});
it("keeps the same host request identity across reconnect retries and rejects missing identity", async () => {
setRuntimeSessionContext(owner);
const { call, query } = await setup();
await call("get_task_context");
await call("get_task_context");
const ids = query.mock.calls.map((args) => (args as unknown as unknown[])[4]);
expect(ids[0]).toMatch(/^[a-f0-9]{64}$/);
expect(ids[1]).toBe(ids[0]);
const missing = await setup({ productTools: [{ name: "run_simulation", inputSchema: { type: "object", properties: {} } }], resolveNativeCall: async () => null });
expect((await missing.call("run_simulation")).isError).toBeTrue();
expect(missing.query).not.toHaveBeenCalled();
});
it("distinguishes safe network and timeout failures without upstream text", async () => {
setRuntimeSessionContext(owner);
for (const [cause, message] of [[new DOMException("SECRET", "TimeoutError"), "Query timed out"], [new TypeError("SECRET"), "Query network failure"]] as const) {
const { call } = await setup({ productClient: { query: async () => { throw cause; } } });
const result = await call("get_task_context");
expect(JSON.stringify(result)).toContain(message);
expect(JSON.stringify(result)).not.toContain("SECRET");
}
});