Let a dedicated model name sessions - #776
Conversation
Session titles are generated by the session's own model, so naming a conversation costs a request on whatever large model is in use, and it inherits that session's thinking level even though a title needs no reasoning budget. Add a Session title section to General settings that selects any configured model for naming, stored as sessionTitleModel in settings.json next to the existing preferences. The default keeps today's behaviour by inheriting the session model. Thinking is reduced to the cheapest level each model accepts, with "low" for Gemini because it rejects "minimal" and its SDK reports that level when thinking is disabled. The title agent still runs with shadowed tools and sanitized messages, so naming cannot execute tools or mutate the source session.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7a931da4cc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| modelOverride = source.modelRuntime?.getModel( | ||
| options.model.slice(0, slash), | ||
| options.model.slice(slash + 1), | ||
| ); |
There was a problem hiding this comment.
Reject an unavailable dedicated title model
When the stored model is absent from this session's modelRuntime—for example, after adding a model while an existing wrapper is alive, or when a globally selected custom model is unavailable in another project—getModel() returns undefined and buildSessionTitleAgentOptions() silently falls back to the session model. The naming request can therefore use the expensive model the user explicitly replaced; refresh the runtime as the set_model path does and report an error if the configured model still cannot be resolved.
Useful? React with 👍 / 👎.
| const supported = getSupportedThinkingLevels(model); | ||
| if (supported.includes("off")) return "off"; | ||
| if (supported.includes("low")) return "low"; | ||
| if (supported.includes("minimal")) return "minimal"; | ||
| return "off"; |
There was a problem hiding this comment.
Select the actual lowest supported thinking level
For a reasoning model whose supported levels exclude off, this chooses low before the cheaper minimal; if the model exposes only medium or higher through a custom thinkingLevelMap, it returns unsupported off. Those configurations either spend more than advertised or can fail title generation, so choose the first genuinely supported level in canonical cost order and handle an empty supported set explicitly.
Useful? React with 👍 / 👎.
| return () => { cancelled = true; }; | ||
| }, [cwd]); |
There was a problem hiding this comment.
Refresh title-model options after model configuration changes
If General has already mounted, navigating to Models, adding a model, saving it, and returning to General leaves this effect dormant because cwd did not change and mounted settings sections are only hidden rather than unmounted. The newly configured model therefore cannot be selected until the entire settings dialog is closed and reopened; reload the catalogue when General is activated or after model configuration is saved.
Useful? React with 👍 / 👎.
…t level Three points from review: - A configured model that the session's runtime cannot resolve no longer falls back to the session model, which would silently spend the request the dedicated model exists to avoid. The runtime is refreshed first, as set_model does, so a model added while this runtime was already alive is still found; if it is still missing, naming fails with a clear error. - The thinking level is the first entry of getSupportedThinkingLevels(), which is already in ascending cost order, instead of a fixed off/low/ minimal preference. A model that excludes "off" now gets "minimal", and a model that only exposes "medium" and above gets "medium" rather than an unsupported "off". Gemini still skips "minimal". - Settings sections stay mounted once visited, so the model catalogue is reloaded each time General becomes the active section. A model added under Models is selectable without closing the dialog.
|
Addressed all three review points in cefd1e4:
Tests cover the refresh-then-reject path, both level cases, and the reload wiring. |
Problem
Session titles are generated with the session's own model. Naming a conversation therefore spends a request on whatever large model happens to be selected, and
buildSessionTitleAgentOptionscopies that session'sthinkingLevel, so a one-line title can be produced with a full reasoning budget.Change
sessionTitleModelinsettings.json, using the same locked read/write pattern as the existing PowerShell tool preference, and served by/api/session-title/settingsfollowing the shape of/api/tools/settings.generateSessionTitle()accepts aprovider/model-idoverride and resolves it through the session's ownmodelRuntime, so only configured models can be used.lowbecause it rejectsminimaland its SDK reports that level whenever thinking is disabled.Tool shadowing and message sanitization are untouched, so naming still cannot execute tools or mutate the source session.
Tests
lib/session-title-settings.test.mjs— defaults, persistence, removal of the key when inheriting,0600permissions.app/api/session-title/settings/route.test.mjs— GET/PUT round trip and payload validation.lib/session-title.test.mjs— model override and thinking level resolution.npm test(956),tsc --noEmit,eslint, andnext buildpass.settings.json.Notes
The model catalogue is project-scoped, so the dropdown lists models only when a project is open; the stored value is still displayed without one.