fix(agent): keep background sandbox tasks running
Auto-approve sandbox Shell only for host-bound task execution, stage native results within their owning session, and preserve active lease state on response stream loss. The repeated failures came from interactive approval in unattended runs and transport cleanup invalidating execution state; focused regressions cover both boundaries.
This commit is contained in:
@@ -3,11 +3,14 @@ import { afterEach, describe, expect, it } from "bun:test";
|
||||
import {
|
||||
bindOperationalTaskCredential,
|
||||
humanTaskEvidenceCommandSchema,
|
||||
hasOperationalTaskRun,
|
||||
OperationalTaskClient,
|
||||
proposedTaskActionSchema,
|
||||
releaseOperationalTaskCredential,
|
||||
} from "../../src/product/operational-task-client.js";
|
||||
|
||||
import { runBackgroundTaskExecution } from "../../src/routes/chatSessionRoutes.js";
|
||||
|
||||
const originalFetch = globalThis.fetch;
|
||||
const taskId = "50000000-0000-4000-8000-000000000001";
|
||||
const runId = "55000000-0000-4000-8000-000000000001";
|
||||
@@ -364,3 +367,28 @@ describe("OperationalTaskClient", () => {
|
||||
expect(requestBodies[2]).toMatchObject({ expected_revision: 3 });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it.each([true, false])("retains lease state on background stream loss only while running=%s", async (running) => {
|
||||
const credential = { authorization: "Bearer fixture", projectId: "project-1" };
|
||||
bindOperationalTaskCredential("runtime-1", credential);
|
||||
globalThis.fetch = (async () => Response.json(run)) as unknown as typeof fetch;
|
||||
const client = new OperationalTaskClient("http://server.test");
|
||||
await client.claimTask("runtime-1", taskId, runId, {
|
||||
requestId: executionRequestId, expectedRevision: 1, sourceSessionId: "session-1",
|
||||
});
|
||||
expect(hasOperationalTaskRun("runtime-1")).toBe(true);
|
||||
globalThis.fetch = (async () => new Response(new ReadableStream({
|
||||
start(controller) { controller.error(new Error("fixture stream disconnected")); },
|
||||
}))) as unknown as typeof fetch;
|
||||
await runBackgroundTaskExecution({ sessionId: "runtime-1", credential, model: "fixture/model",
|
||||
isRunning: () => running });
|
||||
expect(hasOperationalTaskRun("runtime-1")).toBe(running);
|
||||
if (running) {
|
||||
globalThis.fetch = (async (_input: Parameters<typeof fetch>[0], init?: RequestInit) => {
|
||||
expect(JSON.parse(String(init?.body)).expected_revision).toBe(2);
|
||||
return Response.json({ ...run, revision: 3 });
|
||||
}) as unknown as typeof fetch;
|
||||
await client.heartbeatTask("runtime-1", taskId, runId, "session-1");
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user