Skip to content

Commit 551e05f

Browse files
authored
feat(mothership): let the worker choose models when the model picker is off (#8669)
* feat(mothership): let the worker choose models when the model picker is off With the picker off, chats sent the hidden hosted default selection (GPT-6 Astra), which the worker treats as an explicit pick for both the main agent and subagents. No selection is sent now, so the worker routes every model role itself. A stale client selection is still cleared at admission. Picker-on chats and the Sim Chat block are unchanged. * test(mothership): assert the omitted selection on the serialized worker request * test(mothership): read the serialized request without a JSON round trip
1 parent d59e923 commit 551e05f

4 files changed

Lines changed: 28 additions & 27 deletions

File tree

‎apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/model-selector.tsx‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export function ModelSelector() {
4545
{ effort: effortChoice ?? undefined, modelSelection: selection },
4646
advanced
4747
)
48-
const options = advanced
48+
const options = modelSelection
4949
? mothershipEffortOptions(modelSelection.model)
5050
: MOTHERSHIP_SIMPLE_EFFORT_OPTIONS
5151
const setEffort = (choice: MothershipEffort) => {
@@ -59,13 +59,10 @@ export function ModelSelector() {
5959
}, [chatId])
6060

6161
const effortLabel = options.find((option) => option.value === effort)?.label ?? effort
62-
const modelLabel =
63-
MOTHERSHIP_MODEL_OPTIONS.find((option) => option.value === modelSelection.model)?.label ??
64-
modelSelection.model
6562

6663
return (
6764
<div className='flex items-center gap-[inherit]'>
68-
{advanced && (
65+
{modelSelection && (
6966
<>
7067
{modelSelection.model !== 'claude-opus-5-5' && (
7168
<FastModeToggle
@@ -77,7 +74,10 @@ export function ModelSelector() {
7774
<DropdownMenu modal={false}>
7875
<ModelSettingTrigger
7976
label='Model'
80-
valueLabel={modelLabel}
77+
valueLabel={
78+
MOTHERSHIP_MODEL_OPTIONS.find((option) => option.value === modelSelection.model)
79+
?.label ?? modelSelection.model
80+
}
8181
icon={Sparkles}
8282
showChevron
8383
/>

‎apps/sim/lib/mothership/chat/post.test.ts‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ describe('handleUnifiedChatPost', () => {
816816
['low', 'low'],
817817
['none', 'high'],
818818
])(
819-
'enforces the default model and effort range on submitted %s effort',
819+
'leaves the model to the worker and enforces the effort range on submitted %s effort',
820820
async (effort, expected) => {
821821
flags.models.mockResolvedValue(false)
822822
const response = await handleUnifiedChatPost(
@@ -831,12 +831,9 @@ describe('handleUnifiedChatPost', () => {
831831
})
832832
)
833833
expect(response.status).toBe(200)
834-
expect(buildCopilotRequestPayload).toHaveBeenCalledWith(
835-
expect.objectContaining({
836-
effort: expected,
837-
modelSelection: { model: 'gpt-6-astra', fastMode: false },
838-
})
839-
)
834+
const { requestPayload } = createSSEStream.mock.lastCall?.[0] ?? {}
835+
expect(requestPayload?.effort).toBe(expected)
836+
expect(JSON.stringify(requestPayload)).not.toContain('modelSelection')
840837
}
841838
)
842839

‎apps/sim/lib/mothership/model-options.ts‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,29 @@ export function mothershipEffortOptions(model: ModelSelection['model']) {
3838
: MOTHERSHIP_EFFORT_OPTIONS
3939
}
4040

41-
/** Shared by the visible controls, send path and server admission so hidden preferences cannot leak. */
41+
/**
42+
* Shared by the visible controls, send path and server admission so hidden preferences cannot leak.
43+
* Without the model picker no selection is sent, so the worker routes every model role itself.
44+
*/
4245
export function resolveMothershipModelSettings(
4346
settings: { effort?: MothershipEffort; modelSelection?: ModelSelection },
4447
advanced: boolean
45-
): { effort: MothershipEffort; modelSelection: ModelSelection } {
48+
): { effort: MothershipEffort; modelSelection: ModelSelection | undefined } {
4649
let effort = settings.effort ?? DEFAULT_MOTHERSHIP_EFFORT
4750
if (!advanced) {
4851
if (effort === 'none') effort = DEFAULT_MOTHERSHIP_EFFORT
4952
if (effort === 'max') effort = 'xhigh'
50-
return { effort, modelSelection: { model: 'gpt-6-astra', fastMode: false } }
53+
return { effort, modelSelection: undefined }
5154
}
52-
const stored = settings.modelSelection ?? { model: 'gpt-6-astra', fastMode: false }
55+
const modelSelection = normalizeModelSelection(
56+
settings.modelSelection ?? { model: 'gpt-6-astra', fastMode: false }
57+
)
58+
if (effort === 'none' && modelSelection.model !== 'gpt-6-sol') effort = DEFAULT_MOTHERSHIP_EFFORT
59+
return { effort, modelSelection }
60+
}
61+
62+
/** A stored pick on the current catalog: Opus 5 reads as Opus 5.5, which has no Fast mode. */
63+
export function normalizeModelSelection(stored: ModelSelection): ModelSelection {
5364
const model = stored.model === 'claude-opus-5' ? 'claude-opus-5-5' : stored.model
54-
if (effort === 'none' && model !== 'gpt-6-sol') effort = DEFAULT_MOTHERSHIP_EFFORT
55-
return {
56-
effort,
57-
modelSelection: { model, fastMode: model === 'claude-opus-5-5' ? false : stored.fastMode },
58-
}
65+
return { model, fastMode: model === 'claude-opus-5-5' ? false : stored.fastMode }
5966
}

‎apps/sim/stores/mothership-effort/store.ts‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ import { omit, toRecord } from '@sim/utils/object'
22
import { create } from 'zustand'
33
import { devtools, persist } from 'zustand/middleware'
44
import { type ModelSelection, ModelSelectionSchema } from '@/lib/mothership/generated/protocol'
5-
import {
6-
type MothershipEffort,
7-
resolveMothershipModelSettings,
8-
} from '@/lib/mothership/model-options'
5+
import { type MothershipEffort, normalizeModelSelection } from '@/lib/mothership/model-options'
96

107
/** A chat's effort pick and the token that tells it apart from other picks of the same value. */
118
interface ChatEffortPick {
@@ -52,7 +49,7 @@ let lastChatEffortPick = 0
5249
function withModelSelection(
5350
modelSelection: ModelSelection
5451
): Pick<MothershipEffortState, 'modelSelection'> {
55-
return { modelSelection: resolveMothershipModelSettings({ modelSelection }, true).modelSelection }
52+
return { modelSelection: normalizeModelSelection(modelSelection) }
5653
}
5754

5855
export const useMothershipEffortStore = create<MothershipEffortState>()(

0 commit comments

Comments
 (0)