b35c34d58c
The model menu — search, provider grouping, -fast family collapse, keyboard selection, the per-row thinking/effort submenu — was welded to the chat composer's session writes, so any other surface wanting a model picker had to fork it and drift. Splits rendering from meaning. ModelCatalogMenu owns the catalog and the navigation; a ModelMenuController decides what a selection DOES. The composer is now one controller over it, keeping its session scoping, sticky manual pick, preset restore, MoA presets, and rollback-on-failed-write intact. ModelEditSubmenu becomes pure: it reports edits instead of performing them. It previously called setCurrentReasoningEffort and config.set inline, so any non-composer host would have silently retargeted the user's live chat when they picked an effort. Its default effort is passed in rather than read from a store, which is what lets it render outside a session at all. Exported through the SDK so plugins consume the real component instead of a copy. The composer's existing behaviour suite passes unchanged against it.