Skip to content
Open
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
7 changes: 7 additions & 0 deletions packages/app/src/context/prompt-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ export type PromptModel = {
providerID: string
modelID: string
variant?: string | null
/**
* Agent the selection was made under. A manual model choice is an override
* scoped to that agent; it must not outlive switching to a different agent.
* Undefined means the value predates this field or was inherited from another
* tab, in which case a configured agent model takes precedence over it.
*/
agent?: string
}

export type FileContextItem = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import { useSDK } from "@/context/sdk"
import { useSync } from "@/context/sync"
import { useProviders } from "@/hooks/use-providers"

export function createPromptModelSelection(input: { agent: () => { model?: ModelKey; variant?: string } | undefined }) {
export function createPromptModelSelection(input: {
agent: () => { name?: string; model?: ModelKey; variant?: string } | undefined
}) {
const sdk = useSDK()
const sync = useSync()
const models = useModels()
Expand Down Expand Up @@ -37,8 +39,21 @@ export function createPromptModelSelection(input: { agent: () => { model?: Model
})[0]
}

const agentName = () => input.agent()?.name

// A manual model pick is an override scoped to the agent it was made under.
// Unscoped values either predate this field or were inherited from another tab
// (see openNewTab in components/titlebar.tsx); those must not shadow an agent
// that has a model configured.
const override = () => {
const value = prompt.model.current()
if (!value) return
if (value.agent === undefined) return input.agent()?.model ? undefined : value
return value.agent === agentName() ? value : undefined
}

const current = () => {
const key = [prompt.model.current(), input.agent()?.model, configured(), recent(), fallback()].find(
const key = [override(), input.agent()?.model, configured(), recent(), fallback()].find(
(item): item is ModelKey => !!item && valid(item),
)
if (!key) return
Expand Down Expand Up @@ -68,7 +83,7 @@ export function createPromptModelSelection(input: { agent: () => { model?: Model
set(item: ModelKey | undefined, options?: { recent?: boolean }) {
startTransition(() =>
batch(() => {
prompt.model.set(item ? { ...item, variant: prompt.model.current()?.variant } : undefined)
prompt.model.set(item ? { ...item, variant: override()?.variant, agent: agentName() } : undefined)
if (!item) return
models.setVisibility(item, true)
if (options?.recent) models.recent.push(item)
Expand All @@ -88,7 +103,7 @@ export function createPromptModelSelection(input: { agent: () => { model?: Model
})
},
selected() {
return prompt.model.current()?.variant
return override()?.variant
},
current() {
const resolved = resolveModelVariant({
Expand All @@ -110,7 +125,12 @@ export function createPromptModelSelection(input: { agent: () => { model?: Model
batch(() => {
const model = current()
if (!model) return
prompt.model.set({ providerID: model.provider.id, modelID: model.id, variant: value ?? null })
prompt.model.set({
providerID: model.provider.id,
modelID: model.id,
variant: value ?? null,
agent: agentName(),
})
models.variant.set({ providerID: model.provider.id, modelID: model.id }, value)
}),
)
Expand Down
Loading