Skip to content
Merged
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
100 changes: 49 additions & 51 deletions apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3051,21 +3051,21 @@ describe("ProviderCommandReactor", () => {
expect(resolvedActivity).toBeUndefined();
});

it("surfaces non-resumable provider user-input callbacks as stale failures", async () => {
const harness = await createHarness();
const now = "2026-01-01T00:00:00.000Z";
harness.respondToUserInput.mockImplementation(() =>
Effect.fail(
new ProviderAdapterRequestError({
provider: ProviderDriverKind.make("claudeAgent"),
method: "item/tool/respondToUserInput",
detail: "Unknown pending Codex user input request: user-input-request-1",
}),
),
);
effectIt.effect("surfaces non-resumable provider user-input callbacks as stale failures", () =>
Effect.gen(function* () {
const harness = yield* Effect.promise(() => createHarness());
const now = "2026-01-01T00:00:00.000Z";
harness.respondToUserInput.mockImplementation(() =>
Effect.fail(
new ProviderAdapterRequestError({
provider: ProviderDriverKind.make("claudeAgent"),
method: "item/tool/respondToUserInput",
detail: "Unknown pending Codex user input request: user-input-request-1",
}),
),
);

await Effect.runPromise(
harness.engine.dispatch({
yield* harness.engine.dispatch({
type: "thread.session.set",
commandId: CommandId.make("cmd-session-set-for-user-input-error"),
threadId: ThreadId.make("thread-1"),
Expand All @@ -3079,11 +3079,9 @@ describe("ProviderCommandReactor", () => {
updatedAt: now,
},
createdAt: now,
}),
);
});

await Effect.runPromise(
harness.engine.dispatch({
yield* harness.engine.dispatch({
type: "thread.activity.append",
commandId: CommandId.make("cmd-user-input-requested"),
threadId: ThreadId.make("thread-1"),
Expand Down Expand Up @@ -3112,11 +3110,9 @@ describe("ProviderCommandReactor", () => {
createdAt: now,
},
createdAt: now,
}),
);
});

await Effect.runPromise(
harness.engine.dispatch({
yield* harness.engine.dispatch({
type: "thread.user-input.respond",
commandId: CommandId.make("cmd-user-input-respond-stale"),
threadId: ThreadId.make("thread-1"),
Expand All @@ -3125,40 +3121,42 @@ describe("ProviderCommandReactor", () => {
sandbox_mode: "workspace-write",
},
createdAt: now,
}),
);
});

await waitFor(async () => {
const readModel = await harness.readModel();
const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1"));
if (!thread) return false;
return thread.activities.some(
(activity) => activity.kind === "provider.user-input.respond.failed",
yield* Effect.promise(() =>
waitFor(async () => {
const readModel = await harness.readModel();
const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1"));
if (!thread) return false;
return thread.activities.some(
(activity) => activity.kind === "provider.user-input.respond.failed",
);
}),
);
});

const readModel = await harness.readModel();
const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1"));
expect(thread).toBeDefined();
const readModel = yield* Effect.promise(() => harness.readModel());
const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1"));
expect(thread).toBeDefined();

const failureActivity = thread?.activities.find(
(activity) => activity.kind === "provider.user-input.respond.failed",
);
expect(failureActivity).toBeDefined();
expect(failureActivity?.payload).toMatchObject({
requestId: "user-input-request-1",
detail: expect.stringContaining("Stale pending user-input request: user-input-request-1"),
});
const failureActivity = thread?.activities.find(
(activity) => activity.kind === "provider.user-input.respond.failed",
);
expect(failureActivity).toBeDefined();
expect(failureActivity?.payload).toMatchObject({
requestId: "user-input-request-1",
detail: expect.stringContaining("Stale pending user-input request: user-input-request-1"),
});

const resolvedActivity = thread?.activities.find(
(activity) =>
activity.kind === "user-input.resolved" &&
typeof activity.payload === "object" &&
activity.payload !== null &&
(activity.payload as Record<string, unknown>).requestId === "user-input-request-1",
);
expect(resolvedActivity).toBeUndefined();
});
const resolvedActivity = thread?.activities.find(
(activity) =>
activity.kind === "user-input.resolved" &&
typeof activity.payload === "object" &&
activity.payload !== null &&
(activity.payload as Record<string, unknown>).requestId === "user-input-request-1",
);
expect(resolvedActivity).toBeUndefined();
}),
);

it("reacts to thread.session.stop by stopping provider session and clearing thread session state", async () => {
const harness = await createHarness();
Expand Down
Loading