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
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,23 @@ export function useSessionConnection({
const adapter =
task.latest_run.runtime_adapter === "codex" ? "codex" : "claude";
const initialModel = task.latest_run.model ?? undefined;
const cleanup = getSessionService().watchCloudTask(
task.id,
const initialReasoningEffort =
task.latest_run.reasoning_effort ?? undefined;
const cleanup = getSessionService().watchCloudTask({
taskId: task.id,
runId,
getCloudUrlFromRegion(cloudAuthState.cloudRegion),
cloudAuthState.projectId,
() => {
apiHost: getCloudUrlFromRegion(cloudAuthState.cloudRegion),
teamId: cloudAuthState.projectId,
onStatusChange: () => {
queryClient.invalidateQueries({ queryKey: ["tasks"] });
},
task.latest_run?.log_url,
logUrl: task.latest_run?.log_url,
initialMode,
adapter,
initialModel,
task.description ?? undefined,
);
taskDescription: task.description ?? undefined,
initialReasoningEffort,
});
return cleanup;
}, [
cloudAuthState.bootstrapComplete,
Expand All @@ -105,6 +108,7 @@ export function useSessionConnection({
task.latest_run?.id,
task.latest_run?.log_url,
task.latest_run?.model,
task.latest_run?.reasoning_effort,
task.latest_run?.runtime_adapter,
task.latest_run?.state?.initial_permission_mode,
task.description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* Only the tRPC network boundary is faked, that boundary is the thing we simulate dropping.
*/
import type { ContentBlock } from "@agentclientprotocol/sdk";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

const mockTrpcAgent = vi.hoisted(() => ({
start: { mutate: vi.fn() },
Expand Down Expand Up @@ -343,19 +343,22 @@ describe("SessionService cloud queue recovery (real store, e2e)", () => {
});
});

afterEach(() => {
vi.restoreAllMocks();
});

it("recovers a stranded queue after an idle resumed run drops to disconnected", async () => {
const service = getSessionService();

// Subscribe (captures the onUpdate.onData channel) without letting the
// async hydrate clobber the state we control below.
service.watchCloudTask(
TASK_ID,
RUN_ID,
"https://api.anthropic.com",
123,
undefined,
"https://logs.example.com/run",
);
service.watchCloudTask({
taskId: TASK_ID,
runId: RUN_ID,
apiHost: "https://api.anthropic.com",
teamId: 123,
logUrl: "https://logs.example.com/run",
});
const onData = latestOnData();

// Start: agent booting, not yet ready (mirrors a snapshot-resume run
Expand Down Expand Up @@ -442,14 +445,13 @@ describe("SessionService cloud queue recovery (real store, e2e)", () => {

it("drains a queue stranded on an idle disconnected run via the real retry path (no injected status update)", async () => {
const service = getSessionService();
service.watchCloudTask(
TASK_ID,
RUN_ID,
"https://api.anthropic.com",
123,
undefined,
"https://logs.example.com/run",
);
service.watchCloudTask({
taskId: TASK_ID,
runId: RUN_ID,
apiHost: "https://api.anthropic.com",
teamId: 123,
logUrl: "https://logs.example.com/run",
});

// An idle, already-bootstrapped run that completed its turn for THIS run
// (live idle flag set) then dropped to disconnected on an SSE blip. The
Expand Down Expand Up @@ -493,14 +495,13 @@ describe("SessionService cloud queue recovery (real store, e2e)", () => {

it("does not drain while the agent is still booting (boot race protected)", async () => {
const service = getSessionService();
service.watchCloudTask(
TASK_ID,
RUN_ID,
"https://api.anthropic.com",
123,
undefined,
"https://logs.example.com/run",
);
service.watchCloudTask({
taskId: TASK_ID,
runId: RUN_ID,
apiHost: "https://api.anthropic.com",
teamId: 123,
logUrl: "https://logs.example.com/run",
});
const onData = latestOnData();

// Disconnected, queued message, but the agent has NEVER booted for this
Expand Down Expand Up @@ -535,14 +536,13 @@ describe("SessionService cloud queue recovery (real store, e2e)", () => {

it("does not drain on a current-run run_started snapshot until turn_complete (initial/resume turn race)", async () => {
const service = getSessionService();
service.watchCloudTask(
TASK_ID,
RUN_ID,
"https://api.anthropic.com",
123,
undefined,
"https://logs.example.com/run",
);
service.watchCloudTask({
taskId: TASK_ID,
runId: RUN_ID,
apiHost: "https://api.anthropic.com",
teamId: 123,
logUrl: "https://logs.example.com/run",
});
const onData = latestOnData();

// Disconnected, queued message. The agent has NOT completed a turn for
Expand Down Expand Up @@ -637,14 +637,13 @@ describe("SessionService cloud queue recovery (real store, e2e)", () => {

it("does not dispatch a queued follow-up mid-turn after retryCloudTaskWatch clears isPromptPending", async () => {
const service = getSessionService();
service.watchCloudTask(
TASK_ID,
RUN_ID,
"https://api.anthropic.com",
123,
undefined,
"https://logs.example.com/run",
);
service.watchCloudTask({
taskId: TASK_ID,
runId: RUN_ID,
apiHost: "https://api.anthropic.com",
teamId: 123,
logUrl: "https://logs.example.com/run",
});
const onData = latestOnData();

// Agent booted and idle from a prior turn.
Expand Down Expand Up @@ -756,14 +755,13 @@ describe("SessionService cloud queue recovery (real store, e2e)", () => {

it("clears the idle marker when sendCloudPrompt starts a turn even if the session/prompt log never arrives", async () => {
const service = getSessionService();
service.watchCloudTask(
TASK_ID,
RUN_ID,
"https://api.anthropic.com",
123,
undefined,
"https://logs.example.com/run",
);
service.watchCloudTask({
taskId: TASK_ID,
runId: RUN_ID,
apiHost: "https://api.anthropic.com",
teamId: 123,
logUrl: "https://logs.example.com/run",
});

// Agent booted and idle from a prior turn.
sessionStoreSetters.setSession(
Expand Down Expand Up @@ -864,14 +862,13 @@ describe("SessionService cloud queue recovery (real store, e2e)", () => {

it("does not recover from a prior run's turn_complete carried into the resumed session", async () => {
const service = getSessionService();
service.watchCloudTask(
TASK_ID,
RUN_ID,
"https://api.anthropic.com",
123,
undefined,
"https://logs.example.com/run",
);
service.watchCloudTask({
taskId: TASK_ID,
runId: RUN_ID,
apiHost: "https://api.anthropic.com",
teamId: 123,
logUrl: "https://logs.example.com/run",
});
const onData = latestOnData();

// resumeCloudRun copies the PREVIOUS run's history into the new run's
Expand Down
Loading
Loading