* fix(web): prioritize model ids in narrow rows
Keep the model ID in the compact row and expose its display name when expanded. Preserve wide layouts and input focus while resizing.
Fixes#7511
* test(desktop): wait for supervised network recovery
* fix(web): keep folding rows visible through the viewport
* test(web): measure fold movement within the viewport
* test(snapshot): await cancelled job settlement before retry
* fix(web): stabilize model name focus across responsive layouts
* revert: remove unrelated CI fixes from model layout PR
Revert d1c8ef1de1a, 1050ece1980, 6f2f0906341 and 8f7efbca6b0. Preserve the responsive model layout and its review fixes.
* test(web): align DeepSeek Messages model row snapshot
Merge master and preserve pinned-row visibility. Remove redundant Chat and tool-tree menu forwarding, unify trigger names, and bind file targets at the consuming Slot. Address CI static and coverage gaps without changing upstream scroll assertions.
Derive the picker's checked state from the list at render so a row drafted
during the fetch is not removed. Disable Update list when it would empty a
non-empty list, because an empty list serves the whole catalog. List a
repeated candidate id once and treat rows without an id as unconfigured.
The fetched-model picker now starts with the configured models checked and
Update list adds newly checked candidates and removes unchecked configured
ones. Configured models the provider does not list stay. Select all and
Deselect all change only visible candidates so a hidden configured model is
not removed unseen.
Refs #6290
The reasoning-level editor hardcoded pi-ai's seven levels, so a level a
pi-ai upgrade adds would be missing from the page and a stored key outside
the list would be dropped by the next edit. The levels now come from the
llm-pi-ai namespace schema, the key union of reasoningEfforts, read the
way protocolChoices reads the protocols, and travel explicitly from the
Models section and the provider editor through the model list to each row.
A stored key the schema does not list keeps its row and stays selectable.
The reasoning control now appears wherever that list is non-empty instead
of being inferred from a missing catalog provider.
The reasoning-level editor kept the levels it switched off, its row order,
and typed text in component state, while the model list keys rows by
position, so deleting a row handed that state to the next model: turning
the survivor's switch on wrote the deleted model's levels into it. The
editor now renders only from the model; rows follow the stored order,
switching on always starts from the defaults, and only the focused field
keeps its typed text until the field is left.
The reasoning check moves out of the shared model validator into the two
cards whose rows edit it, so DeepSeek and catalog routes are untouched,
and it now mirrors every pi-ai refusal: a valueless field, a missing value
on a level besides off, and an empty value. A refused value marks its
field, and leaving that field repairs it with the level name.
The Providers guide now points custom model API users to the page before
the YAML, and both package READMEs describe the new behavior.
The help tooltip now says that Off needs no value but keeps and sends a
value already written in the configuration, matching the disabled field
that shows it. Both READMEs add the rule that a custom value carries over
only between two thinking levels, so changing a row to or from Off resets
it. The Models settings e2e header comment is rewrapped.
A model row on a hand-declared pi-ai route now edits its reasoningEfforts
from the Models settings page instead of only through cordis.patch.yml.
A switch turns the field on or off; when on, each row pairs a level
select with the API value sent for it, which defaults to the level name.
Off only turns reasoning off, so its value field is disabled and a value
already stored for it is kept. Saving refuses a list without a level
besides off, and a help tooltip beside the label explains the values.
Catalog routes and the DeepSeek card are unchanged.
Refs #6260
The client tsdown presets found a package's own manifest by name: a glob of
every packages/*/*/package.json, parsed until the name matched. tsdown's
native config loader imports each package config without module cache, so
the module-level cache never hit and all 82 configs repeated the glob
(40-125 ms each) synchronously on tsdown's main thread, where it delayed
every other package build. It was 34.5% of the client pass's main thread.
- clientBundle, staticLinked and clientLibrary take the package directory
(import.meta.dirname at every call site) and read <dir>/package.json
once; the package name, loader id and externals come from that manifest.
- A missing, unreadable or nameless manifest throws an actionable error.
- The glob, the name search and the module-level caches are removed.
tsdown client pass 12.78 s -> 8.73 s (median of 3 interleaved runs each,
-31.7%); all 11,566 lib outputs byte-identical; all 82 configs resolve the
same externals and banners.
Refs #5852
TypeScript builds a synthetic signature for every JSX intrinsic element and
computes a module specifier for @types/react (index and jsx-runtime) per
importing file. computeModuleSpecifiers visits every symlinked location of
that file and scans all 491 tsconfig paths for each; pnpm gave 65 packages
their own node_modules/@types/react link. Client test-aggregate Check
followed 26.9 + 0.494 * N seconds for N locations.
- Remove @types/react and @types/react-dom from all 67 workspace manifests
and declare them once in the root devDependencies; packages keep declaring
the react and react-dom they import (ui-slots gains react).
- verify-package-dependencies rejects either package in any workspace
manifest and requires the root declaration, so a new package cannot add
the link back.
- packages/client/AGENTS.md states the rule.
Client aggregate Check 59.1 s -> 26.5 s; the 76 client-only package
projects 54-57 s -> ~44 s wall. File set (2,613) and diagnostics unchanged.
Refs #5852