Skip to content
Merged
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
181 changes: 181 additions & 0 deletions apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9523,6 +9523,187 @@ describe("CodexAdapterV2 post-settle continuation", () => {
),
);

it.effect.each([
"Codex completes it later",
"its thread is unloaded",
"Codex completes it after the session's Stop deadline",
"Codex completes it after a second Stop fails",
] as const)("keeps a turn open after an unconfirmed Stop until %s", (ending) =>
Effect.gen(function* () {
const nativeThreadId = "unconfirmed-stop-thread";
const nativeTurnId = "unconfirmed-stop-turn";
const usage = {
totalTokens: 15,
inputTokens: 10,
cachedInputTokens: 2,
outputTokens: 5,
reasoningOutputTokens: 1,
};
const pastDeadline = ending === "Codex completes it after the session's Stop deadline";
const harness = yield* makeCodexReplayHarness(
makeCodexReplayTranscript({
scenario: `unconfirmed-stop-${ending.length}`,
entries: [
...codexReplayPreamble({ nativeThreadId, nativeTurnId, prompt: "work" }),
{
type: "expect_outbound",
label: "turn/interrupt",
frame: {
id: 4,
method: "turn/interrupt",
params: { threadId: nativeThreadId, turnId: nativeTurnId },
},
},
{
type: "emit_inbound",
label: "still working",
frame: {
method: "thread/tokenUsage/updated",
params: {
threadId: nativeThreadId,
turnId: nativeTurnId,
tokenUsage: { total: usage, last: usage, modelContextWindow: 200_000 },
},
},
},
{
type: "emit_inbound",
label: "turn/interrupt",
// A slow acknowledgement leaves the adapter's own wait running past the deadline.
...(pastDeadline ? { afterMs: 6_000 } : {}),
frame: { id: 4, result: {} },
},
...(ending === "its thread is unloaded"
? ([
{
type: "expect_outbound",
label: "thread/unsubscribe",
frame: {
id: 5,
method: "thread/unsubscribe",
params: { threadId: nativeThreadId },
},
},
{
type: "emit_inbound",
label: "thread/unsubscribe",
frame: { id: 5, result: { status: "unsubscribed" } },
},
] satisfies Array<CodexReplay.CodexAppServerReplayEntry>)
: ([
...(ending === "Codex completes it after a second Stop fails"
? ([
{
type: "expect_outbound",
label: "turn/interrupt/second",
frame: {
id: 5,
method: "turn/interrupt",
params: { threadId: nativeThreadId, turnId: nativeTurnId },
},
},
{
type: "emit_inbound",
label: "turn/interrupt/second",
frame: { id: 5, error: { code: -32603, message: "internal error" } },
},
] satisfies Array<CodexReplay.CodexAppServerReplayEntry>)
: []),
{
type: "emit_inbound",
label: "turn/completed",
afterMs: 20_000,
frame: {
method: "turn/completed",
params: {
threadId: nativeThreadId,
turn: makeCodexReplayTurn({ id: nativeTurnId, status: "completed" }),
},
},
},
] satisfies Array<CodexReplay.CodexAppServerReplayEntry>)),
],
}),
);
yield* harness.runtime.startTurn(
makeCodexTestTurnInput({
threadId: harness.threadId,
providerThread: harness.providerThread,
now: yield* DateTime.now,
attemptId: RunAttemptId.make("attempt-unconfirmed-stop"),
text: "work",
}),
);
const stopping = yield* harness.runtime
.interruptTurn({
providerThread: harness.providerThread,
providerTurnId: (yield* IdAllocator.IdAllocatorV2).derive.providerTurn({
driver: CodexAdapterV2.CODEX_DRIVER_KIND,
nativeTurnId,
}),
})
.pipe(
// The session manager bounds every Stop the same way.
Effect.timeoutOrElse({
duration: "15 seconds",
orElse: () => Effect.fail({ _tag: "SessionStopDeadline" } as const),
}),
Effect.result,
Effect.forkScoped,
);
// Codex received the interrupt and kept reporting work on the turn.
yield* harness.until(() =>
harness.events.some(
(event) =>
event.type === "provider_turn.updated" &&
event.providerTurn.tokenUsage?.usedTokens === usage.totalTokens,
),
);
yield* TestClock.adjust(pastDeadline ? "15 seconds" : "10 seconds");

const stopped = yield* Fiber.join(stopping);
assert.equal(
stopped._tag === "Failure" ? stopped.failure._tag : "confirmed",
pastDeadline ? "SessionStopDeadline" : "ProviderAdapterInterruptTimeoutError",
);
assert.deepEqual(harness.terminalEvents(), []);

if (ending === "Codex completes it after a second Stop fails") {
const second = yield* harness.runtime
.interruptTurn({
providerThread: harness.providerThread,
providerTurnId: (yield* IdAllocator.IdAllocatorV2).derive.providerTurn({
driver: CodexAdapterV2.CODEX_DRIVER_KIND,
nativeTurnId,
}),
})
.pipe(Effect.result);
assert.equal(second._tag, "Failure");
assert.deepEqual(harness.terminalEvents(), []);
}
if (ending === "its thread is unloaded") {
yield* harness.runtime.unloadThread!({ providerThread: harness.providerThread });
} else {
yield* TestClock.adjust("20 seconds");
}
yield* harness.awaitTerminal(1);
assert.deepEqual(
harness.terminalEvents().map((event) => event.status),
["interrupted"],
);
}).pipe(
Effect.scoped,
Effect.provide(
Layer.mergeAll(
IdAllocator.layer,
McpProviderSessions.layer,
NodeServices.layer,
NodeCrypto.layer,
),
),
),
);

describe("native goals", () => {
const nativeThreadId = "goal-thread";
const objective = "Ship the feature";
Expand Down
Loading
Loading