feat: overhauled stream timeout and eval session management
- Replaced external watchdog timers with per-request SDK timeouts for first-event budget across OpenAI, Anthropic, and Azure providers. - Keyed Python shared kernels by (sessionId, cwd) to prevent cross-directory state bleed. - Deduplicated concurrent cold-start session acquisition for JS and Python executors. - Moved `isOpenAIResponsesProgressEvent` to shared module and scoped display output routing per run for interleaved async cells.
This commit is contained in:
@@ -681,24 +681,30 @@ describe("AgentSession python cleanup", () => {
|
||||
expect(executeSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("aborts every active Python execution owned by the session during dispose", async () => {
|
||||
it("aborts every active concurrent Python execution owned by the session during dispose", async () => {
|
||||
const { tempDir, cwd } = createTempProject();
|
||||
tempDirs.push(tempDir);
|
||||
const kernel = new FakeKernel();
|
||||
const blockedExecution = Promise.withResolvers<typeof OK_EXECUTION>();
|
||||
const blockedExecutionStarted = Promise.withResolvers<void>();
|
||||
kernel.blockedCode = "print('first')";
|
||||
const bothStarted = Promise.withResolvers<void>();
|
||||
let starts = 0;
|
||||
kernel.blockedCode = "print('blocked')";
|
||||
kernel.blockedExecution = blockedExecution.promise;
|
||||
kernel.blockedExecutionStarted = () => blockedExecutionStarted.resolve();
|
||||
kernel.blockedExecutionStarted = () => {
|
||||
starts += 1;
|
||||
if (starts >= 2) bothStarted.resolve();
|
||||
};
|
||||
|
||||
vi.spyOn(pythonKernel, "checkPythonKernelAvailability").mockResolvedValue({ ok: true });
|
||||
vi.spyOn(pythonKernel.PythonKernel, "start").mockResolvedValue(kernel as unknown as PythonKernelInstance);
|
||||
|
||||
const session = await createSession(tempDir, cwd);
|
||||
|
||||
const firstExecution = session.executePython("print('first')");
|
||||
await blockedExecutionStarted.promise;
|
||||
const secondExecution = session.executePython("print('second')");
|
||||
// Two concurrent blocked executions on the shared kernel session: both must
|
||||
// be tracked when dispose runs so abortEval cancels every signal.
|
||||
const firstExecution = session.executePython("print('blocked')");
|
||||
const secondExecution = session.executePython("print('blocked')");
|
||||
await bothStarted.promise;
|
||||
const sleepSpy = mockPositiveSleepsImmediate();
|
||||
|
||||
await session.dispose();
|
||||
@@ -707,7 +713,7 @@ describe("AgentSession python cleanup", () => {
|
||||
|
||||
expect(firstResult.cancelled).toBe(true);
|
||||
expect(secondResult.cancelled).toBe(true);
|
||||
expect(kernel.executeCalls).toEqual(["print('first')"]);
|
||||
expect(kernel.executeCalls).toEqual(["print('blocked')", "print('blocked')"]);
|
||||
expect(kernel.shutdownCalls).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user