feat(coding-agent): added configurable IRC timeout with AbortSignal cancellation

- Added configurable IRC message timeout setting with 120-second default to prevent indefinite hangs.
- Implemented timeout enforcement for IRC send operations using AbortSignal-based cancellation.
- Modified Python tool bridge to route concurrent evaluations using per-run identifiers alongside session IDs.
- Enhanced test coverage for IRC timeout behavior, tool validation, and ephemeral cache key separation.
This commit is contained in:
can1357
2026-05-26 14:46:06 +02:00
parent 0bf1684b97
commit bb4c9cae1e
8 changed files with 213 additions and 32 deletions
@@ -58,10 +58,11 @@ describe("Python tool bridge HTTP server", () => {
});
const session = makeSession(new Map([["read", readTool]]));
const info = await ensurePyToolBridge();
const unregister = registerPyToolBridge("test-session-1", { toolSession: session });
const unregister = registerPyToolBridge("test-session-1", "run-1", { toolSession: session });
try {
const res = await call(info, {
session: "test-session-1",
run: "run-1",
name: "read",
args: { path: "foo.ts", _i: "py prelude" },
});
@@ -78,7 +79,7 @@ describe("Python tool bridge HTTP server", () => {
it("returns ok=false when no session is registered for the given id", async () => {
const info = await ensurePyToolBridge();
const res = await call(info, { session: "missing", name: "read", args: {} });
const res = await call(info, { session: "missing", run: "run-missing", name: "read", args: {} });
expect(res.status).toBe(200);
const body = (await res.json()) as { ok: boolean; error?: string };
expect(body.ok).toBe(false);
@@ -99,9 +100,9 @@ describe("Python tool bridge HTTP server", () => {
}) as unknown as AgentTool,
} as unknown as ToolSession;
const info = await ensurePyToolBridge();
const unregister = registerPyToolBridge("err-session", { toolSession: session });
const unregister = registerPyToolBridge("err-session", "run-err", { toolSession: session });
try {
const res = await call(info, { session: "err-session", name: "boom", args: {} });
const res = await call(info, { session: "err-session", run: "run-err", name: "boom", args: {} });
expect(res.status).toBe(200);
const body = await res.json();
expect(body).toEqual({ ok: false, error: "kapow" });
@@ -112,7 +113,11 @@ describe("Python tool bridge HTTP server", () => {
it("rejects requests with a bad bearer token", async () => {
const info = await ensurePyToolBridge();
const res = await call(info, { session: "anything", name: "read", args: {} }, { token: "wrong" });
const res = await call(
info,
{ session: "anything", run: "run-anything", name: "read", args: {} },
{ token: "wrong" },
);
expect(res.status).toBe(403);
});
@@ -130,13 +135,14 @@ describe("Python tool bridge HTTP server", () => {
const session = makeSession(new Map([["read", readTool]]));
const info = await ensurePyToolBridge();
const statusEvents: Array<{ op: string }> = [];
const unregister = registerPyToolBridge("status-session", {
const unregister = registerPyToolBridge("status-session", "run-status", {
toolSession: session,
emitStatus: event => statusEvents.push(event),
});
try {
const res = await call(info, {
session: "status-session",
run: "run-status",
name: "read",
args: { path: "foo.ts" },
});