2269 Commits

Author SHA1 Message Date
Yichen Jiang
a352425d82 Merge remote-tracking branch 'origin/master' into worktree/persist-web-theme-settings
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-theme/README.i18n.yaml
#	packages/host/apiproxy/README.i18n.yaml
2026-08-07 19:34:05 +08:00
Yichen Jiang
e9f6d82b12 fix(locale): keep settings constants private 2026-08-07 19:30:22 +08:00
imccyu
c631236a08 Merge pull request #1859 from deepseek-harness/fix/hero-preview-badge
feat(web): change preview badge position
2026-08-07 19:29:54 +08:00
Tianyi Cui
886dbfe67f Merge branch 'master' into worktree/add-web-pwa-manifest 2026-08-07 19:25:49 +08:00
Yichen Jiang
209fb4d355 Merge remote-tracking branch 'origin/master' into worktree/default-model-persistence
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/host/apiproxy/README.i18n.yaml
2026-08-07 18:18:40 +08:00
ZiyaZhang
fe505e1e91 feat(web): a prose mention of a produced file opens it
The chatFileMentions service (provided by ui-deliverables beside its
turn-tail entry, reached via ctx.get) resolves inline-code tokens in the
closing message against the turn's produced locations: exact path or
unique basename links, ambiguity and unknowns stay inert. MarkdownText
gains the optional fileMentions seam — settled renders only, never
inside anchors.
2026-08-07 03:02:10 -07:00
Yichen Jiang
2dc1406dfd feat(ui-models): drop the provider-scoped reasoning effort, and red-flag a bad route id
**Reasoning effort leaves the provider cards entirely.** It is a per-MODEL
capability and the models under one provider disagree about which levels
they accept: setting `anthropic` to `max` made six of its eight models
throw UNSUPPORTED_REASONING_EFFORT, and because the catalog build catches
per provider, the whole provider vanished from the picker behind one error
row. A provider-scoped control can only ever be set to a value some of its
models reject.

The composer's model picker already offers each model its own levels, and
a switch there now records provider, model, and effort together as the
next session's default — so the setting has a better home at the right
granularity. The profile field stays in `settings.yaml` for a deployment
that knows its route; only the control is gone, from both cards and both
adapter families. Two `components.spec` cases used the control as the
vehicle for their op assertions and now use `baseURL`, which is what they
were actually testing.

**A rejected Provider ID now reads as a fault.** It shared the neutral
hint paragraph with the field's guidance, so the copy telling the user
what they got wrong looked like advice. Reuses the existing `.error`
style, matching the split the key field already makes.
2026-08-07 17:36:08 +08:00
imccyu
daac50c84c fix(client): name turn-tail selector owner 2026-08-07 17:19:26 +08:00
imccyu
2efce69d79 fix(client): route turn-tail through chain selector 2026-08-07 17:15:27 +08:00
Yif
0a248bcea8 feat(web): make the whole no-workspace composer card the picker trigger
The pick target grows from the read-only textarea to the full capsule:
the card owns the click, its disabled controls let pointer events fall
through, and a dashed l4 stroke with a business-blue hover marks the
affordance (an SVG dash ring — native dashed has a fixed pattern). The
card contains pointerdown so the open picker's outside-close cannot
race the reopen, which flickered the chip's expansion echo.
2026-08-07 17:06:01 +08:00
Yichen Jiang
135064c831 fix(ui-models): stop the shared hint contradicting a filled-in field
The line under the create form names the one blocked gate worth naming,
and its fallback arm reads "no models yet". An unmet Provider ID gate fell
through to that arm, so a card with two models listed right above it was
told it needed one. The key gate was already excluded for this reason; the
route gate was assumed excluded because its field explains itself, and was
not.

Tightening the route rule in the previous commit is what made this easy to
hit — a digit-leading id now fails the gate — but the fallthrough predates
it and fires for an empty or taken id just the same.
2026-08-07 17:02:05 +08:00
imccyu
a6ae15c0f6 Merge remote-tracking branch 'origin/master' into feat/web-workspace-file-links
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/src/client/chat/ToolRow.module.css
#	packages/host/apiproxy/src/native-path-opener.ts
2026-08-07 16:49:20 +08:00
Yichen Jiang
5a90eb41fb fix(ui-models): three faults the running app surfaced
**A hand-declared route must not offer a reasoning effort.** The earlier
commit read the create card's missing control as drift and added one. It
is the other way round: such a model has no reasoning capability — pi-ai's
installed catalog is what supplies one, and it ships nothing under the
route — so `resolveModel` throws UNSUPPORTED_REASONING_EFFORT for every
model on it and the whole provider drops out of the picker. Verified
against the adapter, not inferred. The create card no longer offers it and
the editor withholds it on the directory's `declared` bit, which is the
real bug: that control has always been wrong for these routes.

**A blocked composer locked the way out of the block.** Reusing the
no-workspace inert posture disabled the model seat along with everything
else, so the bar asked for a model while preventing the one control that
picks one. A block now rides its own `blocked` owner prop: the textarea,
send, commands, plan seat, and access chip all lock, and the model seat
alone stays live.

**A Provider ID could derive an illegal credential reference.** The card
accepted a digit-leading id, whose derived `123_API_KEY` then failed at
the credential seam with a raw regular expression the user cannot act on.
The id must now start with a letter, and a test pins the relation between
the two rules rather than the regex.
2026-08-07 16:45:50 +08:00
Yichen Jiang
2767d6fb47 Merge remote-tracking branch 'origin/master' into worktree/persist-web-theme-settings
# Conflicts:
#	.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.i18n.yaml
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/host/apiproxy/README.i18n.yaml
2026-08-07 16:45:23 +08:00
Yichen Jiang
84c01cde9f refactor(ui-agent-preset): let the roster read take the store it drives
Threading a status reader and a patch callback made both call sites long
enough to read as the same code again; handing over the store is one line at
each and says the same thing.
2026-08-07 16:44:46 +08:00
Yichen Jiang
0833b29f25 fix(web): persist general preferences in host settings 2026-08-07 16:43:59 +08:00
Yichen Jiang
e265c6038f test: cover the agent-preset wire routes and both restore edges
master moved the RPC surface onto the fetch transport, so the two agentPreset
methods arrived there with nothing driving them. Adds the round trip, plus the
two `recompose` edges that had none: an agent that never composed a preset, so
there is nothing to restore, and a restore that fails because the composition
it reaches for is gone — the roster is a live directory.

Marks the deliberate non-Error rejections in the store specs, which is the
branch they exist to cover.
2026-08-07 16:39:44 +08:00
Yichen Jiang
3d5ebc3210 style(ui-agent-preset): match the repo's type-literal and arrow-parens style 2026-08-07 16:34:50 +08:00
Yichen Jiang
3c81ac1212 Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring 2026-08-07 16:22:09 +08:00
Yichen Jiang
d13cb724ee Merge branch 'stack/agent-profiles-3-wire' into stack/agent-profiles-5-web-ui 2026-08-07 16:22:02 +08:00
Yichen Jiang
41938b9da6 Merge branch 'stack/agent-profiles-1-seam' into stack/agent-profiles-3-wire
# Conflicts:
#	apps/web/tests/shipped-composition.e2e.ts
2026-08-07 16:20:38 +08:00
Yichen Jiang
8e57dd1dac fix(web): render Skill icon at 14px 2026-08-07 16:15:17 +08:00
Yichen Jiang
a4f3aa073f test(ui-agent-preset): cover the paths the extraction left uncovered
The shared picker's id fallback on both trust levels, the chip refusing an
unrelated settings namespace, a refused `settings.describe`, and a blank
draft that names no source. Drops the picker's `title`, which this layer's
one caller never passes.
2026-08-07 16:06:01 +08:00
Yichen Jiang
93ad74cab5 refactor(ui-agent-preset): keep the row's picker shared, the hero chip its own
The chip renders name and description on two lines with its own icon and
alignment, so it is not the same control as the settings row — the shared
picker carries the row, and the chip keeps its shape.
2026-08-07 16:01:43 +08:00
Yichen Jiang
b4213fac6f Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring
# Conflicts:
#	packages/client/ui-agent-preset/src/client/AgentPresetRow.tsx
#	packages/client/ui-agent-preset/src/client/AgentPresetSeat.tsx
2026-08-07 15:59:59 +08:00
Yichen Jiang
e9648bdeee refactor(ui-agent-preset): one preset picker behind both surfaces
The settings row and the composer seat differ in where they sit, what they
call the current value, and when they refuse a pick — not in how the picker
behaves. Extracting it also stops the row from reading like the permission
row it has nothing to do with.
2026-08-07 15:59:23 +08:00
Yichen Jiang
82ae1a8a37 refactor(ui-agent-preset): one home for the roster read every surface starts from
The row and the management section opened `load` the same way — refuse a
concurrent read, mark the store loading, read, fold both refusal shapes into
the store's error. What differs between them starts after that.
2026-08-07 15:52:02 +08:00
Yichen Jiang
0f27a505c4 refactor(ui-agent-preset): one home for turning a roster into options
The chip and the settings row both spread the same three fields, and
`exactOptionalPropertyTypes` makes the absent-vs-undefined dance verbose
enough that the duplication gate flagged it.
2026-08-07 15:46:46 +08:00
Yichen Jiang
53bd0a90a6 Merge pull request #1754 from deepseek-harness/worktree/web-skill-tool-row
feat(web): add dedicated skill tool row
2026-08-07 15:45:24 +08:00
Yichen Jiang
d03d3ab70b Merge remote-tracking branch 'origin/master' into worktree/default-model-persistence
Carries two edits beyond conflict resolution, both forced by what master
brought in:

- `CustomProviderCard`: master added front-end key validation and a
  component-level `keyValue` (already trimmed) while still writing
  `apiKeyEnv` unconditionally. Kept this branch's blank-key rule and its
  committed-profile retry gate, and adopted master's single `keyValue` so
  the component has one spelling of the key rather than two.
- `docs/user/guide/providers`: master merged #1810, whose default-model
  section still taught overriding the `api-gateway` row in
  `$DSH_HOME/config.yaml` — the behavior this branch replaced. Rewritten
  for the settings section the picker now writes, plus the review fix from
  #1810 replacing the colloquial 挂着 in the opener.
2026-08-07 15:44:57 +08:00
Yichen Jiang
5ec13a23b3 Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring
# Conflicts:
#	packages/host/apiproxy/README.i18n.yaml
2026-08-07 15:41:18 +08:00
Yichen Jiang
df2d2adbb8 Merge branch 'stack/agent-profiles-3-wire' into stack/agent-profiles-5-web-ui
# Conflicts:
#	packages/host/apiproxy/README.i18n.yaml
2026-08-07 15:41:14 +08:00
Yichen Jiang
6093c266c6 Merge branch 'stack/agent-profiles-1-seam' into stack/agent-profiles-3-wire 2026-08-07 15:41:09 +08:00
Turtle
d9a3ae4c3a Merge remote-tracking branch 'origin/master' into task/command-feedback-master 2026-08-07 15:28:07 +08:00
Yichen Jiang
bb43ff4f37 feat(ui): make a session that cannot send refuse to accept one
A default naming a route the Models page has since removed left the
composer saying 选择模型 while the input still accepted a message, which
then failed inside the adapter mid-turn.

`session.prompt` now refuses with `model-unavailable` before opening a
turn. That is the enforcement boundary: the method stays callable no
matter what a client disables. `session.models` reports the same fact as
`routable`, and ui-model pushes a block through the new
`ctx.conversation.blocks` registry so the bar renders the disabled
textarea it already renders without a workspace, carrying the blocker's
own reason. The push direction is forced — ui-model already depends on
ui-conversation, so ui-conversation cannot read it back.

The gate is `routable`, not "matches no advertised group": catalog
membership is advisory, so a route serving a model it stopped advertising
is missing from the groups yet perfectly usable, and `null` before the
first load never blocks so a slow Host cannot lock a working composer.

The scaffold gains a route-only adapter for fixture-less keyless
scenarios. Registering zero providers is a test artifact — every product
composition mounts one — and the goldens that froze the seat's fallback
label now show the model those scenarios actually route to.
2026-08-07 15:26:42 +08:00
Yichen Jiang
a45beb1292 Merge branch 'master' into worktree/web-skill-tool-row 2026-08-07 15:06:42 +08:00
Yichen Jiang
c96b480bc4 test(ui-agent-preset): cover the surface where it is introduced
The package landed here with one store spec; the rest of its tests were written
three layers up, so this layer and the two above it failed the per-file
coverage gate on 191 locations while every test passed.

Adds the node half's invariant companion, the two components, the registration
apply, and the stores' failure paths. `currentValue` drops a `?? ''` that an
empty roster already returned before reaching — the same shape the later layer
arrived at, so the two converge instead of conflicting.
2026-08-07 14:58:03 +08:00
creatixchu
40ee7f5e27 docs,test: settle review follow-ups for the create-by-name deletion
Rewrite the three sibling Agent Note pairs that still described create-by-name
as current (workspace-ui-product-flow, session-list-browsing-and-manual-order,
same-basename-workspace-adoption) and the one-route note's own alternative and
section title; delete scripts/hero-composer-dom-continuity.mjs, which drove the
name dialog removed by the one-route change; mark WorkspaceRegistry.create's
now test-only title parameter with a deletion TODO; pin the retired { name }
spelling as a schema rejection; align the workspace spec on stageDir and the
fixture spec title on path creates.
2026-08-07 14:48:26 +08:00
Turtle
5e5664e668 Merge remote-tracking branch 'origin/master' into task/command-feedback-master
# Conflicts:
#	.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.i18n.yaml
#	apps/cli/config/base.cordis.yml
#	apps/cli/package.json
#	packages/README.i18n.yaml
#	pnpm-lock.yaml
2026-08-07 14:40:42 +08:00
creatixchu
fbd3a6272b Merge remote-tracking branch 'origin/master' into worktree/drop-create-by-name
# Conflicts:
#	packages/host/apiproxy/README.i18n.yaml
2026-08-07 14:40:25 +08:00
NI0317
c44c6c93c8 feat(web): open workspace picker from composer 2026-08-07 14:38:58 +08:00
Yichen Jiang
23a4c0a51e Merge pull request #1827 from deepseek-harness/worktree/charming-swartz-83bf33
fix(llm,web): validate API key format before it reaches an HTTP header
2026-08-07 14:36:04 +08:00
creatixchu
a7e43d4346 refactor: drop the create-by-name workspace route
The Web picker collapsed onto the directory flow (see the one-route-to-add-a-workspace
Agent Note), leaving workspace.create({ name }) with no product consumer. Delete the
whole feed line: the wire schema's name member and WorkspaceApi spelling, the gateway's
workspaceRoot config/default and the mkdir branch, the client seam that carried the name
(WorkspaceCreateInput, WorkspacesService.create, intentName), the dsh web
--workspace-root flag, and the fixture's name handling. workspace-name-conflict stays as
workspace.rename's duplicate-title error.
2026-08-07 14:26:50 +08:00
_Kerman
4ede2798fe fix(web): address review — placeholder key family, menu-open gate, plan precedence, note wording 2026-08-07 14:20:14 +08:00
Yichen Jiang
d5c5e7f2e9 Merge remote-tracking branch 'origin/master' into worktree/charming-swartz-83bf33
# Conflicts:
#	apps/web/tests/models-settings.e2e.ts
#	docs/config-catalog.md
#	packages/client/ui-models/README.i18n.yaml
#	packages/client/ui-models/README.md
#	packages/client/ui-models/README.zh.md
#	packages/client/ui-models/src/client/ProviderEditor.tsx
#	packages/client/ui-models/tests/provider-form.spec.tsx
#	packages/llm/llm-deepseek/README.i18n.yaml
#	packages/llm/llm-deepseek/README.md
#	packages/llm/llm-deepseek/README.zh.md
#	packages/llm/llm-deepseek/src/index.ts
2026-08-07 14:12:17 +08:00
Yichen Jiang
63724ed5f9 Merge pull request #1856 from deepseek-harness/worktree/fix-wsl-open-config
fix(apiproxy): open config files through Windows on WSL
2026-08-07 14:11:30 +08:00
_Kerman
f79db87d8d Merge remote-tracking branch 'github/feat/web-queue-steer-all' into feat/web-queue-steer-tooltip
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-08-07 14:05:27 +08:00
Yichen Jiang
0823a3484a fix(web): report a wrapped paste as the same API key format failure 2026-08-07 14:03:11 +08:00
Yichen Jiang
72618f29b5 fix(ui-models): stop the create card pinning a reference on a blank key
Master's credential-lifecycle work taught the editor card that a pi-ai
profile names `apiKeyEnv` only when a key is actually stored, so a route
left blank keeps its provider-native auth path. The create card kept
writing the derived reference unconditionally, so a route declared for a
credential chain or ADC was born pointing at a reference nothing sets —
and now rendered a red missing-key dot for it.

Both cards apply one rule. The obsolete assertion moves with the behavior
(the with-key case is covered by the neighbouring test), and the merged
Models e2e golden shows the declared route unmarked rather than flagged.
2026-08-07 13:57:52 +08:00
Yichen Jiang
768e2e866f fix(web): keep skill row pairing client-local 2026-08-07 13:56:42 +08:00