fix(plugins): a running agent's composer validates and refreshes against the agent's own catalog

setAgentModel and setAgentThinkingOption checked the provider's global catalog,
while the picker reads the catalog of the agent's directory, so a model only
the project lists was rejected. The validation input now carries the directory.

The composer read the catalog once with no observer, so reconnect repair, which
refetches only active queries, never refreshed it and a failed load never
retried. While anything watches, the composer now observes the catalog query.

The shared composer map kept every agent's composer for the session. It is now
dropped when nothing watches it and no composer is mounted.
This commit is contained in:
Mohamed Boudra
2026-11-04 08:10:29 +01:00
parent dad466d696
commit e59183f2de
8 changed files with 230 additions and 37 deletions
+8 -4
View File
@@ -677,15 +677,19 @@ implementations provide it:
settings are the session store's agent, and `model` and `thinking` resolve through the provider
catalog with `resolveAgentModelSelection`, the picker's own function, so a read equals what the
picker shows. The model loads the catalog itself and resolves with no models until it lands, as the picker does,
so a read never differs from what the picker shows. The mounted
so a read never differs from what the picker shows. While anything watches the model it holds a
`QueryObserver` on the agent's catalog: that is what lets reconnect repair, which refetches only
active queries, refresh a catalog nobody has a picker open for, and retry one that failed. The
model is shared while a watcher or a mounted composer holds it and dropped when the last one
lets go. The mounted
`AgentControls` plugs its input in with `attachInput` so `insertText` lands at the cursor.
Without a live input the model writes the stored prompt with `replaceDraftText`, which also asks
a mounted input to show it. A workspace the user left stays mounted, display none, with no
input ref: `ComposerInput.isLive()` is how the model tells. Closing a root agent's tab archives
it, so a running agent with no mounted composer at all only exists as a subagent whose tab was
closed. The daemon is the authority for `setModel` and `setThinking`, and validates a thinking
option against the model the agent runs: the runtime model when the catalog lists it, else the
configured one.
closed. The daemon is the authority for `setModel` and `setThinking`. It validates against the
catalog of the agent's directory, the one the picker reads, and checks a thinking option against
the model the agent runs: the runtime model when the catalog lists it, else the configured one.
- A draft or New workspace screen's `composerModelFromHalves`, an adapter over the two contexts
in `composer/session.tsx`: `Composer` provides `ComposerInput` (prompt, attachments),
`DraftAgentControls` provides `ComposerAgent` (settings), and the adapter enforces the lock.