Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/bundled/codex/runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ afterEach(() => {
for (const runtime of runtimes) runtime.dispose();
runtimes.length = 0;
vi.unstubAllGlobals();
vi.restoreAllMocks();
});

/** External app-server protocol fixture: turns complete only when released by
Expand Down Expand Up @@ -962,6 +963,20 @@ it("publishes unexpected exit and empty-completion failures instead of silently
content: expect.stringContaining("Codex exited"),
});
});
it("sets no deadline of its own on a turn", async () => {
// Any deadline Buzz set would already have passed.
vi.spyOn(AbortSignal, "timeout").mockImplementation(() =>
AbortSignal.abort(
new DOMException("The operation timed out.", "TimeoutError"),
),
);
const f = fixture();
await f.runtime.run(f.delivery("a long job"));
await vi.waitFor(() => expect(f.starts()).toHaveLength(1));
await f.complete();
await vi.waitFor(() => expect(f.publish).toHaveBeenCalledTimes(1));
expect(f.publish.mock.calls[0]?.[0]).toMatchObject({ content: "DONE" });
});
it("ends the server when its agent stops running and suppresses a late final answer", async () => {
const f = fixture();
await f.runtime.run(f.delivery("work"));
Expand Down
7 changes: 2 additions & 5 deletions src/bundled/codex/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,11 +602,8 @@ export class CodexRuntime {
let notReady!: (error: unknown) => void;
const turnAbort = new AbortController();
const server = this.open();
const signal = AbortSignal.any([
entry.abort.signal,
turnAbort.signal,
AbortSignal.timeout(29 * 60_000),
]);
// No deadline of our own: a turn runs until Codex ends it.
const signal = AbortSignal.any([entry.abort.signal, turnAbort.signal]);
Comment on lines +605 to +606

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Sign off the commit before landing

Commit 21968c640956341347d8a370fc444051e3873bd0 has no Signed-off-by trailer in its raw commit message, so the repository's hosted DCO Check will fail even if the code checks pass. Recreate this commit with git commit --signoff before landing.

AGENTS.md reference: AGENTS.md:L194-L198

Useful? React with 👍 / 👎.

const active: Active = {
rpc: server.rpc,
ready: new Promise((resolve, reject) => {
Expand Down
32 changes: 32 additions & 0 deletions src/features/agents/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,38 @@ it("aborts the in-flight run, and drops what is queued, when the agent is remove
expect(run).toHaveBeenCalledTimes(1);
});

// STOPGAP(agent-working-reactions): delete with working-reactions.ts.
it("keeps a mention's reactions however long its handed-off work runs", async () => {
vi.useFakeTimers();
const { service, run, emit, native } = await setup();
await service.create({ type: "example/echo", name: "Echo" });
let finish = () => {};
const turn = new Promise<void>((resolve) => {
finish = resolve;
});
run.mockImplementationOnce(async ({ workingUntil }) => workingUntil(turn));
emit({
events: [
event("m", {
tags: [
["h", channel],
["p", bot],
],
}),
],
channelId: channel,
});
await vi.waitFor(() => expect(run).toHaveBeenCalledTimes(1));
await vi.advanceTimersByTimeAsync(0);
expect(await published(native, 7)).toHaveLength(2);
// Buzz sets no deadline on an agent's work; the harness decides.
await vi.advanceTimersByTimeAsync(2 * 60 * 60_000);
expect(await published(native, 5)).toEqual([]);
finish();
await vi.advanceTimersByTimeAsync(0);
expect(await published(native, 5)).toHaveLength(2);
});

it("drops its events while another copy of the app holds the agent, and runs once it holds it", async () => {
const { service, run, emit, native } = await setup();
await service.create({ type: "example/echo", name: "Echo" });
Expand Down
4 changes: 1 addition & 3 deletions src/features/agents/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1309,7 +1309,7 @@ export class AgentsService extends Service implements Agents {
}

/** Counts a run as working until it and everything it handed to
* `workingUntil` have settled, or the longest run allowed has passed. A
* `workingUntil` have settled, however long that takes. A
* mention run is reacted to, and shown typing here, meanwhile: both are
* STOPGAPs, and `done` is empty without them. */
private working(runner: Runner, { trigger, channelId }: Job) {
Expand Down Expand Up @@ -1342,10 +1342,8 @@ export class AgentsService extends Service implements Agents {
const stop = () => {
if (holds < 0) return;
holds = -1;
clearTimeout(timer);
for (const end of done) end();
};
const timer = setTimeout(stop, TIMEOUT_LIMIT_MS);
const release = () => {
if (holds > 0 && --holds === 0) stop();
};
Expand Down
Loading