Skip to content

Commit 1ab94c9

Browse files
authored
fix(sessions): preserve model on session retry (#3127)
1 parent 09a3a2b commit 1ab94c9

3 files changed

Lines changed: 110 additions & 1 deletion

File tree

packages/core/src/sessions/sessionService.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,9 @@ export class SessionService {
12991299
session.channel = result.channel;
13001300
session.status = "connected";
13011301
session.adapter = adapter;
1302+
session.model = model;
1303+
session.executionMode = executionMode;
1304+
session.reasoningLevel = reasoningLevel;
13021305

13031306
// An imported CLI session had its history replayed during agent.start;
13041307
// the replay is already in the local run log, so load it for the UI.
@@ -3389,7 +3392,14 @@ export class SessionService {
33893392
this.localRepoPaths.set(taskId, repoPath);
33903393
const session = this.d.store.getSessionByTaskId(taskId);
33913394
if (session?.initialPrompt?.length) {
3392-
const { taskTitle, initialPrompt } = session;
3395+
const {
3396+
taskTitle,
3397+
initialPrompt,
3398+
executionMode,
3399+
adapter,
3400+
model,
3401+
reasoningLevel,
3402+
} = session;
33933403
await this.teardownSession(session.taskRunId);
33943404
const authStatus = await this.getAuthCredentialsStatus();
33953405
if (authStatus.kind === "restoring") {
@@ -3406,6 +3416,10 @@ export class SessionService {
34063416
repoPath,
34073417
authStatus.auth,
34083418
initialPrompt,
3419+
executionMode,
3420+
adapter,
3421+
model,
3422+
reasoningLevel,
34093423
);
34103424
return;
34113425
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import type { AgentSession } from "@posthog/shared";
2+
import { describe, expect, it, vi } from "vitest";
3+
import { SessionService, type SessionServiceDeps } from "./sessionService";
4+
5+
function makeSession(overrides: Partial<AgentSession> = {}): AgentSession {
6+
return {
7+
taskRunId: "run-1",
8+
taskId: "task-1",
9+
taskTitle: "Test task",
10+
channel: "",
11+
events: [],
12+
startedAt: 1,
13+
status: "error",
14+
isPromptPending: false,
15+
isCompacting: false,
16+
promptStartedAt: null,
17+
pendingPermissions: new Map(),
18+
pausedDurationMs: 0,
19+
messageQueue: [],
20+
optimisticItems: [],
21+
initialPrompt: [{ type: "text", text: "Ship the fix" }],
22+
...overrides,
23+
} as AgentSession;
24+
}
25+
26+
function createHarness(session: AgentSession) {
27+
const sessions: Record<string, AgentSession> = {
28+
[session.taskRunId]: session,
29+
};
30+
const deps = {
31+
store: {
32+
getSessionByTaskId: (taskId: string) =>
33+
Object.values(sessions).find((s) => s.taskId === taskId),
34+
},
35+
log: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
36+
trpc: {
37+
agent: {
38+
onSessionIdleKilled: {
39+
subscribe: () => ({ unsubscribe: vi.fn() }),
40+
},
41+
},
42+
},
43+
} as unknown as SessionServiceDeps;
44+
45+
const service = new SessionService(deps);
46+
vi.spyOn(
47+
service as unknown as { teardownSession: () => Promise<void> },
48+
"teardownSession",
49+
).mockResolvedValue(undefined);
50+
vi.spyOn(
51+
service as unknown as {
52+
getAuthCredentialsStatus: () => Promise<unknown>;
53+
},
54+
"getAuthCredentialsStatus",
55+
).mockResolvedValue({ kind: "ready", auth: { client: {} } });
56+
const createNewLocalSession = vi
57+
.spyOn(
58+
service as unknown as {
59+
createNewLocalSession: (...args: unknown[]) => Promise<void>;
60+
},
61+
"createNewLocalSession",
62+
)
63+
.mockResolvedValue(undefined);
64+
65+
return { service, createNewLocalSession };
66+
}
67+
68+
describe("SessionService.clearSessionError retry config", () => {
69+
it("recreates the session with the original run configuration", async () => {
70+
const session = makeSession({
71+
model: "claude-fable-5",
72+
adapter: "claude",
73+
executionMode: "auto",
74+
reasoningLevel: "high",
75+
});
76+
const { service, createNewLocalSession } = createHarness(session);
77+
78+
await service.clearSessionError("task-1", "/repo");
79+
80+
expect(createNewLocalSession).toHaveBeenCalledWith(
81+
"task-1",
82+
"Test task",
83+
"/repo",
84+
{ client: {} },
85+
session.initialPrompt,
86+
"auto", // executionMode
87+
"claude", // adapter
88+
"claude-fable-5", // model
89+
"high", // reasoningLevel
90+
);
91+
});
92+
});

packages/shared/src/sessions.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ export interface AgentSession {
6464
processedLineCount?: number;
6565
framework?: "claude";
6666
adapter?: Adapter;
67+
model?: string;
68+
executionMode?: ExecutionMode;
69+
reasoningLevel?: string;
6770
configOptions?: SessionConfigOption[];
6871
pendingPermissions: Map<string, PermissionRequest>;
6972
pausedDurationMs: number;

0 commit comments

Comments
 (0)