summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/pages
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-03-13 11:05:08 -0500
committerGitHub <[email protected]>2026-03-13 11:05:08 -0500
commit4ad8116ce37a0e77e7f3c0e9e4e1002bba05b15e (patch)
treeb7e5ed2b05aabb5ed5134520c4eb485c52eb5333 /packages/app/src/pages
parent5c7088338c07ad632834ebd4a87feb23d255fb8a (diff)
downloadopencode-4ad8116ce37a0e77e7f3c0e9e4e1002bba05b15e.tar.gz
opencode-4ad8116ce37a0e77e7f3c0e9e4e1002bba05b15e.zip
fix(app): model selection persist by session (#17348)
Diffstat (limited to 'packages/app/src/pages')
-rw-r--r--packages/app/src/pages/directory-layout.tsx6
-rw-r--r--packages/app/src/pages/session.tsx4
-rw-r--r--packages/app/src/pages/session/session-model-helpers.test.ts133
-rw-r--r--packages/app/src/pages/session/session-model-helpers.ts42
-rw-r--r--packages/app/src/pages/session/use-session-commands.tsx2
5 files changed, 24 insertions, 163 deletions
diff --git a/packages/app/src/pages/directory-layout.tsx b/packages/app/src/pages/directory-layout.tsx
index fdf321f2d..f993ffcd8 100644
--- a/packages/app/src/pages/directory-layout.tsx
+++ b/packages/app/src/pages/directory-layout.tsx
@@ -80,11 +80,11 @@ export default function Layout(props: ParentProps) {
})
return (
- <Show when={state.resolved}>
+ <Show when={state.resolved} keyed>
{(resolved) => (
- <SDKProvider directory={resolved}>
+ <SDKProvider directory={() => resolved}>
<SyncProvider>
- <DirectoryDataProvider directory={resolved()}>{props.children}</DirectoryDataProvider>
+ <DirectoryDataProvider directory={resolved}>{props.children}</DirectoryDataProvider>
</SyncProvider>
</SDKProvider>
)}
diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx
index 8399a1367..6d2917008 100644
--- a/packages/app/src/pages/session.tsx
+++ b/packages/app/src/pages/session.tsx
@@ -44,7 +44,7 @@ import { createOpenReviewFile, createSessionTabs, createSizing, focusTerminalByI
import { MessageTimeline } from "@/pages/session/message-timeline"
import { type DiffStyle, SessionReviewTab, type SessionReviewTabProps } from "@/pages/session/review-tab"
import { useSessionLayout } from "@/pages/session/session-layout"
-import { resetSessionModel, syncSessionModel } from "@/pages/session/session-model-helpers"
+import { syncSessionModel } from "@/pages/session/session-model-helpers"
import { SessionSidePanel } from "@/pages/session/session-side-panel"
import { TerminalPanel } from "@/pages/session/terminal-panel"
import { useSessionCommands } from "@/pages/session/use-session-commands"
@@ -490,7 +490,7 @@ export default function Page() {
(next, prev) => {
if (!prev) return
if (next.dir === prev.dir && next.id === prev.id) return
- if (!next.id) resetSessionModel(local)
+ if (prev.id && !next.id) local.session.reset()
},
{ defer: true },
),
diff --git a/packages/app/src/pages/session/session-model-helpers.test.ts b/packages/app/src/pages/session/session-model-helpers.test.ts
index 5f554dcd3..319db805d 100644
--- a/packages/app/src/pages/session/session-model-helpers.test.ts
+++ b/packages/app/src/pages/session/session-model-helpers.test.ts
@@ -14,145 +14,38 @@ const message = (input?: Partial<Pick<UserMessage, "agent" | "model" | "variant"
}) as UserMessage
describe("syncSessionModel", () => {
- test("restores the last message model and variant", () => {
+ test("restores the last message through session state", () => {
const calls: unknown[] = []
syncSessionModel(
{
- agent: {
- current() {
- return undefined
- },
- set(value) {
- calls.push(["agent", value])
- },
- },
- model: {
- set(value) {
- calls.push(["model", value])
- },
- current() {
- return { id: "claude-sonnet-4", provider: { id: "anthropic" } }
- },
- variant: {
- set(value) {
- calls.push(["variant", value])
- },
- },
- },
- },
- message({ variant: "high" }),
- )
-
- expect(calls).toEqual([
- ["agent", "build"],
- ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }],
- ["variant", "high"],
- ])
- })
-
- test("skips variant when the model falls back", () => {
- const calls: unknown[] = []
-
- syncSessionModel(
- {
- agent: {
- current() {
- return undefined
- },
- set(value) {
- calls.push(["agent", value])
- },
- },
- model: {
- set(value) {
- calls.push(["model", value])
- },
- current() {
- return { id: "gpt-5", provider: { id: "openai" } }
- },
- variant: {
- set(value) {
- calls.push(["variant", value])
- },
+ session: {
+ restore(value) {
+ calls.push(value)
},
+ reset() {},
},
},
message({ variant: "high" }),
)
- expect(calls).toEqual([
- ["agent", "build"],
- ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }],
- ])
+ expect(calls).toEqual([message({ variant: "high" })])
})
})
describe("resetSessionModel", () => {
- test("restores the current agent defaults", () => {
- const calls: unknown[] = []
+ test("clears draft session state", () => {
+ const calls: string[] = []
resetSessionModel({
- agent: {
- current() {
- return {
- model: { providerID: "anthropic", modelID: "claude-sonnet-4" },
- variant: "high",
- }
- },
- set() {},
- },
- model: {
- set(value) {
- calls.push(["model", value])
- },
- current() {
- return undefined
- },
- variant: {
- set(value) {
- calls.push(["variant", value])
- },
- },
- },
- })
-
- expect(calls).toEqual([
- ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }],
- ["variant", "high"],
- ])
- })
-
- test("clears the variant when the agent has none", () => {
- const calls: unknown[] = []
-
- resetSessionModel({
- agent: {
- current() {
- return {
- model: { providerID: "anthropic", modelID: "claude-sonnet-4" },
- }
- },
- set() {},
- },
- model: {
- set(value) {
- calls.push(["model", value])
- },
- current() {
- return undefined
- },
- variant: {
- set(value) {
- calls.push(["variant", value])
- },
+ session: {
+ reset() {
+ calls.push("reset")
},
+ restore() {},
},
})
- expect(calls).toEqual([
- ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }],
- ["variant", undefined],
- ])
+ expect(calls).toEqual(["reset"])
})
})
diff --git a/packages/app/src/pages/session/session-model-helpers.ts b/packages/app/src/pages/session/session-model-helpers.ts
index 7600f16d5..c9e2e1dbd 100644
--- a/packages/app/src/pages/session/session-model-helpers.ts
+++ b/packages/app/src/pages/session/session-model-helpers.ts
@@ -1,48 +1,16 @@
import type { UserMessage } from "@opencode-ai/sdk/v2"
-import { batch } from "solid-js"
type Local = {
- agent: {
- current():
- | {
- model?: UserMessage["model"]
- variant?: string
- }
- | undefined
- set(name: string | undefined): void
- }
- model: {
- set(model: UserMessage["model"] | undefined): void
- current():
- | {
- id: string
- provider: { id: string }
- }
- | undefined
- variant: {
- set(value: string | undefined): void
- }
+ session: {
+ reset(): void
+ restore(msg: UserMessage): void
}
}
export const resetSessionModel = (local: Local) => {
- const agent = local.agent.current()
- if (!agent) return
- batch(() => {
- local.model.set(agent.model)
- local.model.variant.set(agent.variant)
- })
+ local.session.reset()
}
export const syncSessionModel = (local: Local, msg: UserMessage) => {
- batch(() => {
- local.agent.set(msg.agent)
- local.model.set(msg.model)
- })
-
- const model = local.model.current()
- if (!model) return
- if (model.provider.id !== msg.model.providerID) return
- if (model.id !== msg.model.modelID) return
- local.model.variant.set(msg.variant)
+ local.session.restore(msg)
}
diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx
index f5a4c0576..1a2e777f5 100644
--- a/packages/app/src/pages/session/use-session-commands.tsx
+++ b/packages/app/src/pages/session/use-session-commands.tsx
@@ -351,7 +351,7 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
description: language.t("command.model.choose.description"),
keybind: "mod+'",
slash: "model",
- onSelect: () => dialog.show(() => <DialogSelectModel />),
+ onSelect: () => dialog.show(() => <DialogSelectModel model={local.model} />),
}),
mcpCommand({
id: "mcp.toggle",