Repository navigation
Conversation
Generate title can now name a session with a model of its own: a right-click on the button, or a press and hold on a phone, opens a menu of the enabled models with the levels each supports. The choice is one for the whole pi-web instance (pi-web-title-model.json beside pi's own files, GET/PUT /api/title-model), with the session's own model at its cheapest level when nothing is chosen, and a thinking level stored on its own still applies to the session's model. A model row names the session right away; a level row keeps the menu open, so both are set in one visit.
escapeWu
force-pushed
the
feat/title-model-menu
branch
from
October 22, 2026 07:45
80a394d to
ae18371
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Right-clicking Generate title (press and hold on a phone, which has no right-click) opens a menu of the enabled models and, below them, the reasoning levels the chosen model supports. Picking a model names the current session with it right away. Picking a level only stores it, so a model and its level are set in one visit.
With nothing chosen, nothing changes: the session is named with its own model at the cheapest level it supports, as on
main.Related: #671 asked for a dedicated model and thinking level for title generation. #807 bounded the transcript the title is made from; this adds the choice of model and level.
How it works
/api/models?cwd=(modelListandthinkingLevels), read on every open, so a model enabled since the last open is in the list. The row rules are pure and live inlib/title-menu.ts: a level survives clearing the model, a model survives clearing the level, and a chosen model only offers the levels it supports.pi-web-title-model.jsonbeside pi's own files (lib/title-model-preference.ts,GET/PUT /api/title-model), so every browser and device names sessions the same way. No file is the default and needs no write. It follows the pattern ofpi-web-session-state.json. It is not a pi setting, and pi'ssettings.jsonis untouched, so the pi CLI is unaffected.POST /api/sessions/[id]/auto-namereads the choice on every naming and resolves the model on the wrapper'smodelRuntime, with onerefresh({ allowNetwork: false })first for a provider an extension registers atsession_start. A model that no longer resolves logs a warning and names with the session's own model instead of failing the button.resolveTitleThinkingLevel()), so a level picked for one model is never sent to another.SidebarMenu(a bottom sheet on phones). There is no new toolbar control. New strings are inen,zh-CNandzh-TW, anddocs/agents/sessions.mdhas the note.Scope
This adds one instance-wide file for one value. I kept it there rather than per browser because the choice has to be the same on every device that reaches the instance, as the sidebar state is. If you would rather it live somewhere else, or not be stored at all, I am happy to rework it.
Verification
node_modules/.bin/tsc --noEmit— clean.npm run lint— clean.npm test— 2881 tests, 2878 pass, 0 fail, 1 skipped. Two tests inlib/session-membership.integration.test.mjstimed out at 15 s in a run where two suites were going at once. That file passes on its own (2/2, 6 s) and this change does not touch session listing.lib/title-menu.test.mjs),lib/title-model-preference.test.mjs),GET/PUT /api/title-model(app/api/title-model/route.test.mjs),lib/session-title.test.mjs).Not run: a browser pass of the right-click and long-press paths on this branch, and
next build(per AGENTS.md).