Merge remote-tracking branch 'origin/master' into worktree/web-session-model-selector
# Conflicts: # apps/cli/package.json # apps/web/tests/smoke-real.e2e.ts # apps/web/tests/snapshots/fresh-round-trip/ui.expected.md # apps/web/tests/snapshots/seeded-history/ui.expected.md # docs/config-catalog.md # packages/client/connection/tests/fake-api.ts # packages/client/runtime/src/client/index.ts # packages/client/runtime/src/client/sessions/conversation.ts # packages/client/runtime/src/client/sessions/session.ts # packages/client/runtime/tests/fake-api.ts # packages/client/ui-conversation/src/client/apply.ts # packages/client/ui-conversation/src/client/contract/slots.ts # packages/client/ui-conversation/src/client/index.ts # packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx # packages/client/ui-conversation/src/client/skeleton/InputBar.tsx # packages/client/ui-conversation/tests/chat-stats-bash-sample.spec.tsx # packages/client/ui-conversation/tests/chat-toolview-slot.spec.tsx # packages/client/ui-conversation/tests/chat-view.spec.tsx # packages/client/ui-conversation/tests/gate-branch-tails.spec.tsx # packages/client/ui-conversation/tests/input-bar.spec.tsx # packages/client/ui-conversation/tests/skeleton.spec.tsx # packages/host/apiproxy/README.md # packages/host/apiproxy/src/api-proxy.ts # pnpm-lock.yaml # scripts/verify-package-readme-model-experience.ts # tsconfig.base.json
This commit is contained in:
@@ -14,9 +14,9 @@ The Web Host reuses `installAgentLlmTarget` for every created or resumed agent.
|
||||
|
||||
The session RPC domain exposes `session.history`'s current `modelTarget`, a `session.models` directory, and `session.selectModel`. The directory is built dynamically from the LLM registry and grouped by provider. Provider catalogs load concurrently and fail independently, so successful groups remain usable alongside retryable failure records. Catalog membership stays advisory: the current model is inserted as an unlisted row when its registered provider omits it, and selecting an unlisted model under a registered provider remains valid.
|
||||
|
||||
The browser `Session` object owns the current target, grouped catalog, provider failures, operation error, and `idle`/`loading`/`ready`/`selecting`/`error` state. An existing Host session primes the directory on selector mount so the compact trigger can resolve a catalog name, and each menu open refreshes it. A frontend Session Intent is still connecting and has no Host model route, so it neither renders the selector nor issues a directory RPC until publication clears the intent. Directory and selection calls share an operation generation so older responses cannot replace a newer result; a separate target-change generation lets concurrent history restore the logged model across a mount-time directory refresh without allowing old history to overwrite a user selection. Failures retain the previous current target and usable groups.
|
||||
The browser `Session` object owns the current target, grouped catalog, provider failures, operation error, and `idle`/`loading`/`ready`/`selecting`/`error` state. A Host session primes the directory when its selector mounts so the compact trigger can resolve a catalog name, and each menu open refreshes it. The resident shell has no session model route before Workspace selection connects or reuses a Host session, so its disabled no-session input dispatches no selector. Directory and selection calls share an operation generation so older responses cannot replace a newer result; a separate target-change generation lets concurrent history restore the logged model across a mount-time directory refresh without allowing old history to overwrite a user selection. Failures retain the previous current target and usable groups.
|
||||
|
||||
`@deepseek-ai/dsh-client-ui-conversation` declares the session-scoped single slot `conversation.composer.control` inside the shared input bar's trailing controls, immediately before its primary button and alongside the current attachment, Plan, and Read-only controls. `@deepseek-ai/dsh-client-ui-model-selector` replaces the earlier visual-only native model select by occupying that slot only in a published conversation; the empty new-session hero declares no model control. Its compact trigger and radio rows display the catalog name, falling back to the model id for an unlisted current target, while the upward menu displays provider headings once with keyboard navigation, dismissal, retry states, and current selection marking.
|
||||
`@deepseek-ai/dsh-client-ui-conversation` declares the session-scoped single slot `conversation.input.model` as a child of its composer-bar entry. InputBar renders the seat in its trailing controls immediately before the pending indicator and primary button; the seat receives the bar's `locked` owner prop and the session standard kit. `@deepseek-ai/dsh-client-ui-model-selector` occupies that dedicated seat, including for a Host-owned blank-session hero. Its compact trigger and radio rows display the catalog name, falling back to the model id for an unlisted current target, while the upward menu displays provider headings once with keyboard navigation, dismissal, retry states, and current selection marking.
|
||||
|
||||
The production browser roster is the flat config tree in `apps/cli/cordis.yml`; the selector is one `dshClient` row rather than a package hardcoded in Web boot code. Its package manifest still declares the graph edge on `ui-conversation`, while cordis service availability governs activation.
|
||||
|
||||
@@ -34,8 +34,8 @@ The production browser roster is the flat config tree in `apps/cli/cordis.yml`;
|
||||
|
||||
## Consequences
|
||||
|
||||
An existing Web conversation can switch among dynamically discovered provider groups without displaying duplicated `provider/model` labels, and the current used route survives resume and reconnect. Catalog names remain presentation-only; selection and persistence continue to use provider/model ids. A provider catalog outage degrades only that group. Selection changes can reduce provider-side cache reuse when the route changes, but the selector adds no prompt content and does not disturb the in-flight step. The empty new-session composer and an unpublished Session Intent still use the Host default because they have no published session route; the control appears and loads its directory only after publication.
|
||||
Any Host-backed Web conversation, including a blank session, can switch among dynamically discovered provider groups without displaying duplicated `provider/model` labels, and the current used route survives resume and reconnect. Catalog names remain presentation-only; selection and persistence continue to use provider/model ids. A provider catalog outage degrades only that group. Selection changes can reduce provider-side cache reuse when the route changes, but the selector adds no prompt content and does not disturb the in-flight step. The resident shell uses the Host default and exposes no selector only while it has no current session.
|
||||
|
||||
## Testing
|
||||
|
||||
Host tests pin grouped discovery, duplicate-catalog isolation, partial provider failure, logged restoration, unlisted current targets, unavailable-provider rejection, and next-assembly switching. Client tests pin state transitions, failure preservation, transport errors, stale-response fencing, mount/open overlap, history restoration, and snapshot reference stability. UI tests pin slot lifecycle, Session Intent suppression, catalog-name labels with id fallback, provider grouping, radio semantics, retry/error states, successful and failed selection, outside dismissal, and Arrow/Home/End/Escape navigation. The keyless built-app fixture loads the selector through the production-shaped boot graph, selects OpenAI's GPT-5, sends a turn, and verifies that the next generated response reports the selected route.
|
||||
Host tests pin grouped discovery, duplicate-catalog isolation, partial provider failure, logged restoration, unlisted current targets, unavailable-provider rejection, and next-assembly switching. Client tests pin state transitions, failure preservation, transport errors, stale-response fencing, mount/open overlap, history restoration, and snapshot reference stability. UI tests pin the dedicated model-seat lifecycle and lock propagation, catalog-name labels with id fallback, provider grouping, radio semantics, retry/error states, successful and failed selection, outside dismissal, and Arrow/Home/End/Escape navigation. The keyless built-app fixture loads the selector through the production-shaped boot graph, selects OpenAI's GPT-5, sends a turn, and verifies that the next generated response reports the selected route.
|
||||
|
||||
Reference in New Issue
Block a user