Commit Graph
100 Commits
Author SHA1 Message Date
Yichen Jiang db36fafc3a test(forge): preserve the failure backoff timing assertion 2026-10-26 21:25:20 +08:00
Yichen Jiang e99a597b16 fix(forge): drain list state streams and refresh reopened requests 2026-10-26 21:22:30 +08:00
Yichen Jiang a36d02a596 Merge master into worktree/forge-session-list 2026-10-26 21:17:53 +08:00
Yichen Jiang 9dd1ecc1f4 Merge pull request #5961 from deepseek-harness/worktree/forge-pr-worktree-panel
feat(forge): add the pull request panel and worktree Sessions
2026-10-26 12:40:20 +00:00
Yichen Jiang d1fa5a7a99 Merge pull request #5960 from deepseek-harness/worktree/forge-change-request-bindings
feat(forge): bind code host change requests to Sessions
2026-10-26 20:22:44 +08:00
Yichen Jiang 3cec608656 Merge remote-tracking branch 'origin/worktree/forge-change-request-bindings' into worktree/forge-pr-worktree-panel 2026-10-26 20:09:46 +08:00
Yichen Jiang 71f0ec2905 test(web): record SVG connection termination counters 2026-10-26 20:08:52 +08:00
Yichen Jiang b66c66a71a Merge remote-tracking branch 'origin/worktree/forge-change-request-bindings' into worktree/forge-pr-worktree-panel 2026-10-26 19:47:22 +08:00
Yichen Jiang e729b41395 test(web): remove temporary SVG transport instrumentation 2026-10-26 19:46:34 +08:00
Yichen Jiang 6a88a371be Merge remote-tracking branch 'origin/worktree/forge-change-request-bindings' into worktree/forge-pr-worktree-panel 2026-10-26 19:44:24 +08:00
Yichen Jiang 081249ca29 test(web): preserve the original socket spy implementation 2026-10-26 19:43:48 +08:00
Yichen Jiang 5d8b823f7b Merge remote-tracking branch 'origin/worktree/forge-change-request-bindings' into worktree/forge-pr-worktree-panel 2026-10-26 19:37:59 +08:00
Yichen Jiang ed0fe80f2a test(web): wait for restored terminal output after reload 2026-10-26 19:37:09 +08:00
Yichen Jiang 573544b8b8 Merge remote-tracking branch 'origin/worktree/forge-change-request-bindings' into worktree/forge-pr-worktree-panel 2026-10-26 19:35:43 +08:00
Yichen Jiang 8a5cd2fb63 test(forge): align confined reference and recommendation fixtures 2026-10-26 19:34:55 +08:00
Yichen Jiang 2fa853870f fix(forge-panel): register all shipped locale dictionaries 2026-10-26 19:34:16 +08:00
Yichen Jiang dd4706fffe test(web): diagnose Host termination during SVG delivery 2026-10-26 19:14:57 +08:00
Yichen Jiang a6883f4038 test: calibrate npm layout budget for the expanded release graph 2026-10-26 18:54:40 +08:00
Yichen Jiang f74e15ba08 Merge branch 'worktree/forge-bindings-stack-sync' into worktree/forge-pr-worktree-panel
# Conflicts:
#	docs/module-graph.md
#	docs/module-graph.zh.md
#	packages/experimental/README.i18n.yaml
#	packages/preset/agent-preset/skills/cordis-composition-reference/references/packages.md
2026-10-26 18:39:10 +08:00
Yichen Jiang 667ef04270 Merge remote-tracking branch 'origin/master' into worktree/forge-bindings-stack-sync
# Conflicts:
#	packages/experimental/README.i18n.yaml
2026-10-26 18:35:22 +08:00
Yichen Jiang bbb031654e Merge remote-tracking branch 'origin/worktree/forge-change-request-bindings' into worktree/forge-pr-worktree-panel
# Conflicts:
#	docs/config-catalog.md
#	docs/config-catalog.zh.md
#	docs/event-producer-consumer.md
#	docs/event-producer-consumer.zh.md
#	packages/experimental/forge-github/README.i18n.yaml
#	packages/experimental/forge-github/README.md
#	packages/experimental/forge-github/README.zh.md
#	packages/experimental/forge-github/src/provider.ts
#	packages/experimental/forge-session/README.i18n.yaml
#	packages/experimental/forge-session/README.md
#	packages/experimental/forge-session/README.zh.md
#	packages/experimental/forge-session/src/index.ts
#	packages/experimental/forge/README.i18n.yaml
#	packages/experimental/forge/README.md
#	packages/experimental/forge/README.zh.md
#	packages/experimental/forge/src/index.ts
2026-10-26 18:14:53 +08:00
Yichen Jiang 7fa3deaf82 fix(forge-session): preserve cancelled watches during registry updates 2026-10-26 17:59:54 +08:00
Yichen Jiang 1f54902e3b fix(forge-panel): drain worktree operations before releasing readers 2026-10-26 17:58:53 +08:00
Yichen Jiang 000583c135 fix(forge-panel): retain incomplete worktree recovery across reloads 2026-10-26 17:58:51 +08:00
Yichen Jiang 2384f52719 fix(forge-panel): hide the actual docked or floating tab 2026-10-26 17:57:14 +08:00
Yichen Jiang ccf509205f fix(forge-panel): release cached state with its Session scope 2026-10-26 17:57:12 +08:00
Yichen Jiang fa2dbbd8fd fix(forge-panel): format change counts in the selected locale 2026-10-26 17:57:11 +08:00
Yichen Jiang 04db213ad9 fix(forge-panel): pin merge confirmation to the reviewed head 2026-10-26 17:57:09 +08:00
Yichen Jiang 4969525f33 fix(worktree): remove only the missing target registration 2026-10-26 17:57:07 +08:00
Yichen Jiang b740b95424 fix(worktree): validate recorded restoration targets before mutation 2026-10-26 17:57:06 +08:00
Yichen Jiang e342b7cbf9 fix(forge-panel): label worktrees with their current HEAD 2026-10-26 17:52:33 +08:00
Yichen Jiang 3d29275e63 fix(forge-panel): cancel and join failed Git inspections 2026-10-26 17:52:32 +08:00
Yichen Jiang a5460dbe41 fix(forge): preserve refresh requests during active polling 2026-10-26 17:52:30 +08:00
Yichen Jiang dd0ed998e7 docs(forge): define and verify worktree request type 2026-10-26 17:52:30 +08:00
Yichen Jiang ac1b807e4f docs(worktree): explain generated name migration 2026-10-26 17:52:29 +08:00
Yichen Jiang 47a7694e6b docs(forge-panel): describe current worktree behavior 2026-10-26 17:52:28 +08:00
Yichen Jiang 4bef9db77e fix(forge-github): validate byte budgets separately from timeouts 2026-10-26 17:49:52 +08:00
Yichen Jiang 7457789b98 fix(forge): reject backoff caps below the active interval 2026-10-26 17:49:26 +08:00
Yichen Jiang 1ebb31915b fix(forge-github): preserve HTTP remote ports 2026-10-26 17:49:24 +08:00
Yichen Jiang 8d4c8865dd fix(forge-session): resync watches when providers change 2026-10-26 17:48:19 +08:00
Yichen Jiang ae40382197 fix(forge-github): distinguish HTTP errors from GraphQL results 2026-10-26 17:45:20 +08:00
Yichen Jiang 3f53fe39fb fix(forge-session): cancel discovery when Sessions close 2026-10-26 17:43:59 +08:00
Yichen Jiang fbcfd80e21 fix(forge-github): enforce configured hosts before queries 2026-10-26 17:42:35 +08:00
Yichen Jiang cba0128268 fix(forge): drain provider calls before unregistering 2026-10-26 17:42:09 +08:00
Yichen Jiang 1abf0f55fe docs(forge): clarify discovery limits and provider contracts 2026-10-26 17:39:09 +08:00
Yichen Jiang df4f3fd0c1 fix(forge-session): bind numeric PR references with explicit repositories 2026-10-26 16:10:51 +08:00
Yichen Jiang d78dabef76 Merge pull request #6426 from deepseek-harness/worktree/composer-host-confirmed-echo
feat(web): show a message only after the Host accepts it
2026-10-26 14:44:20 +08:00
Yichen Jiang 28f9c98108 Merge branch 'worktree/forge-bindings-stack-sync' into worktree/forge-pr-worktree-panel 2026-10-26 13:59:36 +08:00
Yichen Jiang 6abae82a41 Merge branch 'worktree/composer-host-confirmed-echo' into worktree/forge-bindings-stack-sync 2026-10-26 13:58:42 +08:00
Yichen Jiang 491a834d99 fix(web): keep mobile focus on the composer after sending 2026-10-26 13:57:39 +08:00
Yichen Jiang 64c81cb3e3 Merge branch 'worktree/forge-bindings-stack-sync' into worktree/forge-pr-worktree-panel 2026-10-26 13:30:55 +08:00
Yichen Jiang 3cee25a3a5 Merge branch 'worktree/composer-host-confirmed-echo' into worktree/forge-bindings-stack-sync 2026-10-26 13:30:15 +08:00
Yichen Jiang b0e41f74ad Merge remote-tracking branch 'origin/master' into worktree/composer-host-confirmed-echo
# Conflicts:
#	packages/api/session-controller/README.i18n.yaml
#	packages/api/session-controller/src/client/sessions/session.ts
#	packages/client/ui-conversation/README.i18n.yaml
2026-10-26 13:29:33 +08:00
Yichen Jiang 04b3164a27 Merge pull request #7211 from deepseek-harness/fix/model-collapse-preferred-width
fix(web): restore the composer model seat icon collapse
2026-10-25 20:26:49 +08:00
Yichen Jiang bc5c2d4142 fix(web): cap the composer model seat at its preferred width
The composer collapses the model seat to its Models icon when the expanded
controls cannot share a row, but the seat's row-relative 45cqw cap made its
measured demand shrink with the row. The measured expanded state therefore
always fit and a narrow composer ellipsized the name instead of showing the
icon. Cap the seat at its 360px content width so the measurement sees the
demand, document the contract, and cover the collapse without the Plan chip.
2026-10-25 15:16:47 +08:00
Yichen Jiang cc4446eecc fix(mcp): keep resource-listing diagnostics off ACP stdout
The MCP SDK answers resources/list and resources/templates/list for a
server without the resources capability with an empty page, but first
writes a console.debug line to stdout. Under the ACP profile that line
lands in the JSON-RPC stream whenever the model lists resources of a
client-supplied, tools-only MCP server. Return the same empty pages
before calling the SDK, and cover it with a unit assertion and an ACP
stdout regression test.
2026-10-24 22:25:48 +08:00
Yichen Jiang 5a1f5a657b fix(forge): follow the corner-shape rule and the README summary budget
- The checks dot in the Session list pairs its full-round radius with
  corner-shape: round, as the ui-theme stylesheet gate requires.
- The client-ui-forge README summary fits the 100-word budget again
  after the merge combined both branches' descriptions.
2026-10-24 22:12:18 +08:00
Yichen Jiang e4fd8a87ff Merge branch 'worktree/forge-pr-worktree-panel' into worktree/forge-session-list 2026-10-24 22:03:03 +08:00
Yichen Jiang 53d8a336f7 Merge commit 'bf1df01ae99' into worktree/forge-session-list
Brings the Session list branch up to date with the forge panel, whose
held messages now wait at inbox insertion.

- client-ui-forge keeps the Session list's remote-access import and the
  panel's messageOf; the agent-controller import is gone.
- The README and the forge panel Agent Note combine both sides: the
  forgeWorktree projection keeps its client view next to the inbox hold,
  and the Session list paragraphs stay.
- The config catalog is regenerated, and the README, forge subsystem
  page, and Agent Note pairings are recorded again.
2026-10-24 22:02:44 +08:00
Yichen Jiang bec0ac67ba Merge commit '45db0d28ce5' into worktree/forge-pr-worktree-panel 2026-10-24 21:45:54 +08:00
Yichen Jiang 3a52eb1993 Merge commit '861f5200ded' into worktree/forge-pr-worktree-panel
Master replaced the creation and plugin recommendation bundles with one
personalized recommendations bundle.

- The CLI manifest keeps master's bundle and the forge bundle.
- The plugin page expectation ranks the forge bundle before the held-back
  personalized recommendations bundle.
- The experimental README pairing is recorded again.
2026-10-24 21:45:41 +08:00
Yichen Jiang 91bd19ea98 Merge remote-tracking branch 'origin/worktree/composer-host-confirmed-echo' into worktree/forge-change-request-bindings 2026-10-24 21:42:23 +08:00
Yichen Jiang ba94a90da3 Merge commit '66a7e6cf07b' into worktree/forge-change-request-bindings
The experimental README pairing is recorded again for the merged
package rows.
2026-10-24 21:42:17 +08:00
Yichen Jiang b10ba84a0f Merge remote-tracking branch 'origin/master' into worktree/composer-host-confirmed-echo 2026-10-24 21:40:27 +08:00
Yichen Jiang 3764b60205 Merge commit '3dd445fe163' into worktree/composer-host-confirmed-echo
The session-controller README pairing is recorded again for the merged
sections.
2026-10-24 21:39:51 +08:00
Yichen Jiang b33271247b Merge pull request #6102 from deepseek-harness/docs/long-table-filter
feat(docs): 为长表增加搜索、清空和固定表头
2026-10-23 16:34:21 +08:00
Yichen Jiang 7fbdf4938a fix(forge): follow master's shipped languages and release version
- The panel and the forge bundle ship Spanish, French, German, Russian,
  and Portuguese titles and descriptions.
- Their versions follow the root release version 0.2.1-rc.3.
2026-10-23 14:51:41 +08:00
Yichen Jiang 6e9ff4c322 Merge remote-tracking branch 'origin/worktree/forge-change-request-bindings' into worktree/forge-pr-worktree-panel
The parent branch now carries master through #6426 again.

- Master moved the optional, experimental, and plugin page bundle lists
  into @deepseek-ai/dsh-official-bundles; the forge bundle joins the
  optional and experimental lists there.
- The CLI manifest, release families, and plugin page expectations keep
  both sides; the forge bundle ranks before the held-back recommendation
  bundles.
- The lockfile, the event matrix, and the experimental persistence
  catalog are regenerated, and the capability-seams and experimental
  README pairings are recorded again.
2026-10-23 14:51:28 +08:00
Yichen Jiang 3159402734 fix(forge): follow master's shipped languages and release version
- The forge, forge-github, and forge-session packages ship Spanish,
  French, German, Russian, and Portuguese titles and descriptions.
- Their versions follow the root release version 0.2.1-rc.3.
2026-10-23 14:40:35 +08:00
Yichen Jiang 69e7682b6f Merge remote-tracking branch 'origin/worktree/composer-host-confirmed-echo' into worktree/forge-change-request-bindings
The parent branch now carries master through #6426.

- The root manifest keeps the forge packages and master's action cards.
- The event matrix and the experimental persistence catalog are
  regenerated, and the capability-seams and experimental README pairings
  are recorded again.
2026-10-23 14:40:17 +08:00
Yichen Jiang 948d572032 fix(web): follow master's locales and composer cases
- The Spanish, French, German, Russian, and Portuguese dictionaries name
  the sending composer.
- The device classification case expects the acceptance callback that a
  prompt submission carries.
2026-10-23 14:31:45 +08:00
Yichen Jiang 89538fb115 Merge remote-tracking branch 'origin/master' into worktree/composer-host-confirmed-echo
- The composer's primary button keeps master's rule that hides a denied
  action and draws the sending state inside it; a sending prompt stays
  interruptible through master's stopAction.
- The ui-conversation README pairing is recorded again for the merged
  sections.
2026-10-23 14:31:30 +08:00
Yichen Jiang c48f8523f2 feat(llm): follow the official /models listing on the DeepSeek API-key route (#6944)
* refactor(llm-deepseek): share the /models listing machinery

Move the account route's `/models` request and decoding, its
credential-scoped listing cache, and listed-catalog resolution with the
version gate into the shared DeepSeek Messages library, so a second
route can follow the same listing. Names drop the account prefix, the
cache takes each access's endpoint settings with the call, and it gains
`invalidate()` for a forced reload. `isBuiltInCatalog()` recognizes the
catalog an uncustomized `models` setting resolves to.

The account route keeps its behavior; only its imports and the
override diagnostic wording ("model listing") change.

* feat(llm-deepseek-api-key): follow the official /models listing

While `models` equals the built-in catalog and the Messages origin is
https://api.deepseek.com, `deepseek-official` serves the official
`GET /models` listing, authenticated with the API key in `x-api-key`.
Loading, refresh, fallback, merging, and the client-version gate match
the account route: the first access waits up to `modelsTimeoutMs`, a
listing older than `modelsMaxAgeMs` refreshes in the background on the
next access, a failure keeps the last good listing or the built-in
catalog, and listed models this build cannot serve are refused before
network I/O.

A customized `models` list replaces the catalog and requests nothing.
Switching between a customized catalog and the listing discards the
cached listing, so Restore defaults reloads it on the next access.

Suites that boot the route on the official endpoint now answer the
listing themselves instead of reaching the network.

* docs: describe the official route model listing

Document when `deepseek-official` follows the official `/models`
listing, its timing fields, customization precedence, and the forced
reload after Restore defaults in the API-key README, the shared
transport README, and the provider guide. Record the decision in a new
Agent Note, keep the account note's statement of where the shared
listing code lives current, and regenerate the configuration catalog.

* test(llm-deepseek-api-key): pin the once-per-listing hidden-entry diagnostic

* docs: regenerate module and event graphs for the shared listing

* fix(llm-deepseek-api-key): report credential failures on the model request

On the official endpoint, `connect` waited for the listing view, whose
credential lookup rethrew a malformed key or a credential-store failure
before the agent loop recorded the prompt. A failed lookup now resolves
the connection from the current listing view, so `resolveAuth` reports
the failure on the model request and the turn keeps the prompt and the
failed attempt. A caller abort still rejects.

* docs(llm-deepseek-api-key): name which hidden listing entries are logged

* test: keep unit suites off the official model listing

Suites that boot the DeepSeek routes with a dummy or inherited key now
request `GET https://api.deepseek.com/models` on the official endpoint.
A unit-lane setup file rejects that request at once, so such a suite
serves the built-in catalog instead of reaching production or waiting
out the listing deadline on a network that never answers; suites that
exercise the listing answer `fetch` themselves. Other requests pass
through unchanged.

* feat(llm-deepseek): read tool_update from the model listing

Both DeepSeek routes now take a listed model's Messages tool update mode
from `api_capabilities.anthropic_messages.tool_update`, alongside the
system prompt mode. `in-history` and `addition-only` replace the
bundled mode; any other value reads as `leading-only` and removes it.
An absent or `null` mode keeps the bundled one, so a listing that does
not declare the field leaves `deepseek-flash` on `addition-only`.

`system_prompt_update: null` likewise keeps the bundled mode now; it
previously read as `leading-only`, which a serializer writing empty
values as null would have turned into a cache-unfriendly downgrade.

* fix(llm-deepseek): sync the built-in context window with the official listing

The official `/models` listing declares a 1,048,576-token context window
for `deepseek-flash` and `deepseek-v4-pro`; the built-in catalog said
1,000,000, a decimal-versus-binary mismatch. Both built-in entries now
carry the listed value, so offline starts and listing failures size the
context the same way the listing does. The Models page shows the exact
count for these rows, since 1,048,576 has no decimal K/M spelling.

`defaultContextWindow`, the fallback for model ids the catalog does not
describe, stays 1,000,000.

* test(llm-deepseek-api-key): reject the stubbed listing request with an Error

* test(cli): keep the built SDK smoke off the official model listing

The SDK profile's initialize now resolves the deepseek-official catalog,
which requests GET https://api.deepseek.com/models on the official
endpoint. With the smoke's fixture key that request answers 401 and the
route warns on stderr, so the test's empty-stderr assertion failed in the
e2e and snapshots lanes. Point the run at a loopback mock and assert it
received no model call.

* test(llm-deepseek): compose the malformed-key turn without the native executor

release/dsh-0.2.1 predates @deepseek-ai/dsh-tool-executor-native; its tool
runtime executes tools itself. Compose the official-route turn the way
account-routing.spec.ts does on this branch.

* fix(llm-deepseek-api-key): gate nothing when the credential lookup fails

The listing cache switches scope only after it reads a credential, so a
failed lookup left `connect` serving the previous credential's listing.
After a key whose listing refuses a model was replaced by a malformed one,
`admit` refused that model with CLIENT_UPGRADE_REQUIRED before the turn
recorded the prompt, instead of `resolveAuth` reporting the credential
error on the request. Serve the built-in catalog without listing gates
when the lookup fails.

* test(llm-deepseek-api-key): pin the once-per-listing diagnostic across request preparation

The hidden-entry diagnostic test repeated the same discovery assertion to
prove a second pass reports nothing new, which read as a duplicate. Assert
the single warning after the request preparations instead; they resolve
the same listing, so dropping the per-listing deduplication still fails
the test.

* docs(llm-deepseek-api-key): note that a list matching an earlier built-in catalog counts as customized

Customization is judged against the running version's built-in catalog,
so a saved `models` list equal to an earlier version's catalog stops
following the listing once the built-in catalog changes, until Restore
defaults. Record the consequence in the Agent Note and the README's known
limitations.
2026-10-22 20:42:19 +08:00
Yichen Jiang 4b07c32b93 fix(forge): follow master's hover, tooltip, and plugin metadata rules
Master now limits CSS hover styles to hover-capable primary input, opens
tooltips from pointer events, requires a model on every Agent and a model
selection on agent/pre-step, and requires Japanese plugin metadata.

- The panel's hover styles move under @media (hover: hover); expanded,
  pressed, and focus-visible styles stay outside it.
- The hover tests enter with pointer events.
- The test Agent carries an unsupported model, and proposed steps carry a
  model selection.
- The panel and the forge bundle ship Japanese titles and descriptions.
2026-10-22 17:45:15 +08:00
Yichen Jiang cdc72eb229 Merge remote-tracking branch 'origin/worktree/forge-change-request-bindings' into worktree/forge-pr-worktree-panel
The parent branch now carries master through #6426, including the
agent-controller revert.

- Package manifests keep both sides: the ./types and ./locale/*.json
  exports of the forge packages, and the Web app's forge bundle and
  message quotes dependencies.
- The type manifest drops the removed agent-controller entries and keeps
  the forge panel entries.
- The event matrix and the capability-seams pairing are regenerated.
- The forge bundle stays on the main plugin list and now ranks before the
  held-back developer tools; the plugin page expectations follow.
2026-10-22 17:44:45 +08:00
Yichen Jiang eea6d3b7ec feat(forge): hold a sent message until the Session's worktree is ready
The agent-controller admission hook was reverted on master, so the forge
panel now holds the next Turn with Agent maintenance started from the
agent/inbox/inserted notification. The message stays in the inbox until
the hold ends.

- A message sent before the requested worktree exists waits while the
  panel creates it. After a failed or stopped attempt the message keeps
  waiting until the card retries, through the new
  forgePanel.retryWorktree, or withdraws the request so the message goes
  on in the project directory.
- A message sent after the Session's worktree was removed waits on the
  missing card until the worktree is restored or the Session returns to
  the source checkout.
- Restoring a worktree reports its prepare and checkout steps. The card
  shows them in place of its actions, and the tab's restore action shows
  a spinner while it runs.
- The panel state names what a waiting message waits for and the running
  restoration; the agent-controller dependency is removed.
2026-10-22 17:17:55 +08:00
Yichen Jiang c1238b8792 Merge pull request #5263 from deepseek-harness/worktree/web-search-dynamic-tool-e26c2b
feat(web): withhold web_search and web_fetch from requests without credentials
2026-10-22 15:53:05 +08:00
Yichen Jiang fb378dacf2 fix(web): offer DeepSeek web tools whenever a credential exists
The DeepSeek search and Search/Fetch API providers now report readiness
from credential presence alone, on any model route: the account token
first on the deepseek-account route, then a literal apiKey or a
configured apiKeyEnv reference. A conversation on another provider's
model keeps web_search and web_fetch while a DeepSeek key is configured,
as on master, so the route refusal WEB_PROVIDER_ROUTE_DISABLED and its
upgrade guide are removed.

The pi-ai-conversation-updates and deepseek-messages-system-prompt
snapshots replay their master recordings again, the headless keyless
smoke points its search key reference at an unset variable, and the
readiness Agent Note records the rejected route and endpoint rules.
2026-10-22 15:38:16 +08:00
Yichen Jiang 4916ce9bff feat(forge): show worktree and change request state in the Session list
The branch label left the Session header, and finding which Sessions
work in their own worktrees, or which of their change requests need
attention, meant opening each Session's tab.

- A Session row shows a branch glyph while the Session works in the
  worktree the panel created for it, and the state glyph of its most
  urgent change request with a dot for its checks. The row's hover card
  names the worktree branch and its base, then up to three change
  requests with their state and checks.
- The forgeWorktree projection follows the Session's working directory;
  its client view is the created worktree while the Session works in
  it. The forgeChangeRequests projection gains a client view with the
  bindings, so the Session summary carries both without loading a
  Session.
- The forgePanel.changeRequestStates stream serves the states of the
  change requests every listed Session binds from one Host run. It
  polls each until it is merged or closed and stores every change in
  the forge_panel_change_requests storage domain, so a restart shows
  the last known states before the next poll.
- A new Agent Note records the decision; the READMEs, the forge
  subsystem page, and the catalogs follow.
2026-10-22 15:10:29 +08:00
Yichen Jiang a19aabc8ba feat(web): let a key of search's own serve other model routes
A user who gives DeepSeek search a key of its own has chosen what that key
pays for, so the route check now applies only to the shared
DEEPSEEK_API_KEY. A literal apiKey, or an apiKeyEnv other than
DEEPSEEK_API_KEY, opens every model route for Messages search and for the
Search and Fetch APIs; a configured endpoint does not, since the search
still sends the shared key. The Web search settings page saves its key
under the section's apiKeyEnv, DEEPSEEK_API_KEY by default, so a key saved
there keeps serving only the DeepSeek routes.

The route refusal now names the settings that give search a key of its
own, and the READMEs, the readiness Agent Note, and the upgrade guide
describe the exception.
2026-10-22 15:00:39 +08:00
Yichen Jiang a3c0265456 test(snapshots): share web-fetch's tool schemas with web-search-unconfigured
web-search-unconfigured declares exactly the tool catalog that web-fetch
already pins, so it names web-fetch as its toolSchemasSource instead of
committing a second copy.
2026-10-22 14:36:38 +08:00
Yichen Jiang 1922f322aa fix(web): gate the DeepSeek web providers on the model route alone
Review found two faults in the endpoint and configuration checks. The
providers took the official chat route's endpoint from the first active
dsh-llm-deepseek-api-key Loader row, so a composition that isolates several
instances answered for an unrelated one: a correct route lost search, or a
gateway's key reached DeepSeek. And a key saved on the Web search settings
page lands under the default DEEPSEEK_API_KEY reference, so the inference
that search had its own configuration never saw it.

Both DeepSeek web packages now serve only the deepseek-account and
deepseek-official routes, whatever key they are configured with, and no
longer compare the chat endpoint with their own. ready() checks the route
and then credential presence as before; the API-key resolver repeats the
route check and refuses with WEB_PROVIDER_ROUTE_DISABLED. The packages no
longer read Loader rows or depend on dsh-llm-deepseek-api-key, so the
lockfile, the module graph, and the keyless smoke expectations that the
endpoint check had changed return to master's.

An upgrade guide covers conversations on other providers' models, which
lose DeepSeek web search and, with the Search and Fetch APIs selected,
web_fetch.
2026-10-22 13:48:53 +08:00
Yichen Jiang 103dac1b3c feat(web): gate web_fetch and the DeepSeek web APIs on readiness
The Web search switch selects the DeepSeek Search and Fetch APIs together,
and both reuse the DeepSeek chat key by default. Neither provider answered
readiness, so a step without a usable key was offered web_search and
web_fetch whose every call failed, and a conversation on another provider's
model or behind a gateway sent the chat key to DeepSeek.

dsh-web gives WebFetchProvider an optional ready(llmProvider) and adds
ctx.web.fetchReady(), which asks only the provider fetch() selects, as
searchReady() does for search. tool-web registers web_fetch with a step
activation condition on fetchReady(), so a step that cannot fetch leaves the
tool out of declarations, guidance, and PTC bindings and refuses a call to
it as UNKNOWN_TOOL; without web_fetch the search guidance uses its
search-only text. The shipped HTTP fetch provider has no ready() and stays
admitted.

web-deepseek-api applies the API-key rules of Messages search to both APIs:
without a literal apiKey, an apiKeyEnv other than DEEPSEEK_API_KEY, or a
baseURL other than the default, the chat key goes only to the DeepSeek
routes and only to an API base on the official chat route's origin. The
refusal sits in the key's only resolver, and both providers' ready()
answers presence in the order an operation resolves credentials. The
transport repeats these checks so the package still does not depend on
dsh-web-search-deepseek.
2026-10-22 12:10:21 +08:00
Yichen Jiang 80eca619ef refactor(web-search): admit web_search through step activation conditions
Master's step-scoped conditional activation resolves each tool's condition
before a model step assembles, and both the declarations and dispatch read
that admitted set. Prompt assembly no longer carries tool declarations, so
tool-web's system-prompt/assemble listener could not remove web_search any
more, and removing a declaration there never stopped a repeated call from
running.

tool-web now registers web_search with a when condition that asks
ctx.web.searchReady() about the route of the step's model selection, and its
guidance section renders from the step's admitted set. A step that does not
admit the tool leaves it out of declarations, guidance, and PTC program
bindings, and refuses a call to it as UNKNOWN_TOOL without reaching a
provider. Tests that execute web_search directly now run inside a resolved
step, as the executor requires for conditional registrations.

Docs, the readiness Agent Note, and the event producer/consumer table follow
the new mechanism; the tools README gains an explicit conditional-tools
anchor for cross-locale links.
2026-10-22 10:57:09 +08:00
Yichen Jiang 6921551fc4 test(snapshots): refresh this branch's scenarios after merging master
Master declares exit_plan_mode only in plan mode, so this branch's own tool
schema sidecars for web-search-unconfigured and pi-ai-conversation-updates
drop it. The merge took master's pi-ai-conversation-updates session, whose
request headers still listed web_search; the refresh records the moonshotai
route without it again.
2026-10-22 10:56:56 +08:00
Yichen Jiang 19dcdca7b6 test(forge): compose the native tool executor in the session Loader test
Tool registration and scoped executors are now separate plugins, so a
composition without an executor cannot run the bash tool and the Agent
goes idle before its first model request. The forge-session Loader
composition now includes dsh-tool-executor-native, as the other real
composition tests do.
2026-10-22 10:54:25 +08:00
Yichen Jiang dd7e861007 fix(forge): ship plugin locale metadata for the forge packages
The Japanese plugin metadata gate requires every plugin package to carry
locale/en.json and locale/ja.json, and the three forge packages had no
locale directory. Each now has English, Chinese, and Japanese titles and
descriptions, exposed through exports and published through files like
its siblings.
2026-10-22 10:48:28 +08:00
Yichen Jiang 447fb0e1c0 Merge branch 'stack/pr-6426' into stack/pr-5960
# Conflicts:
#	docs/capability-seams.i18n.yaml
#	docs/event-producer-consumer.md
#	docs/event-producer-consumer.zh.md
2026-10-22 10:41:17 +08:00
Yichen Jiang d373778fd8 Merge remote-tracking branch 'origin/master' into worktree/web-search-dynamic-tool-e26c2b
# Conflicts:
#	packages/web/tool-web/tests/tool-web.spec.ts
#	snapshots/session/pi-ai-conversation-updates/session.v4.jsonl
2026-10-22 10:32:41 +08:00
Yichen Jiang 67d5fd7b1e fix(web): add the Japanese label for a sending composer
The Japanese Conversation dictionary must carry every key, and the
locked composer's input.sending label had only Chinese and English
entries.
2026-10-22 10:31:35 +08:00
Yichen Jiang da864e3377 Merge remote-tracking branch 'origin/master' into stack/pr-6426 2026-10-22 10:30:26 +08:00
Yichen Jiang 2bda39dc3a Merge pull request #6024 from deepseek-harness/worktree/conditional-tools
feat(tools): add step-scoped conditional activation
2026-10-22 00:14:48 +08:00
Yichen Jiang 8a6f773867 Merge pull request #6831 from deepseek-harness/worktree/composer-image-preupload
feat(web): upload composer images when they are added
2026-10-22 00:06:37 +08:00
Yichen Jiang 47b6867566 fix(tools): settle cancelled admitted calls through cancellation
A step's tool set no longer empties when the step is cancelled. The shared
pipeline already settles unstarted calls as cancelled; keeping admission lets
those calls keep their finalizers, and a wrapper result completed at
cancellation now reports cancellation instead of UNKNOWN_TOOL.

exit_plan_mode checks for a missing Agent explicitly instead of asserting it.

Document the activation types on the tools subsystem page, the turn/end code
for a failed tool condition, the replacement and no-set consequences in the
upgrade guide, and the admission rule in the parallel tool-call note.
2026-10-21 23:51:22 +08:00
Yichen Jiang d8c99baa28 docs: record batch tool admission and fit the turn-flow summary
The tool executor merge added ToolBatchInput.toolSet; the subsystem page's type-equivalence block now matches it. The architecture turn-flow line names step-admitted tool schemas in one line so the page stays within its word budget.
2026-10-21 23:36:35 +08:00
Yichen Jiang 268d945470 test(web): size the oversized Markdown image past the new image limit
The /api/file route bounds files by maxImageBytes, whose default is now
50 MiB, so the 20 MiB + 1 byte fixture no longer exceeded it and the
route served it with 200 instead of 413.
2026-10-21 23:36:34 +08:00
Yichen Jiang ce24d53eb5 Merge remote-tracking branch 'origin/master' into worktree/dynamic-tool-activation-pr-64796e 2026-10-21 23:32:43 +08:00
Yichen Jiang 207b30d299 Merge remote-tracking branch 'origin/master' into worktree/dynamic-tool-activation-pr-64796e
# Conflicts:
#	docs/config-catalog.md
#	docs/config-catalog.zh.md
#	docs/event-producer-consumer.md
#	docs/event-producer-consumer.zh.md
#	docs/persistence-catalog.i18n.yaml
#	docs/persistence-catalog.md
#	docs/persistence-catalog.zh.md
#	docs/persistence-schema.json
#	packages/core/agent-loop/src/agent.ts
#	packages/core/agent-loop/src/tool-calls.ts
#	packages/core/agent-loop/tests/tool-updates.spec.ts
#	packages/core/system-prompt/README.i18n.yaml
#	packages/core/system-prompt/README.md
#	packages/core/system-prompt/README.zh.md
#	packages/core/tool-executor-ptc/src/ptc.ts
#	packages/core/tool-executor-ptc/tests/ptc.spec.ts
#	packages/core/tools/README.i18n.yaml
#	packages/core/tools/README.md
#	packages/core/tools/README.zh.md
#	packages/core/tools/src/index.ts
#	packages/extensions/tool-cordis/src/api-catalog.ts
#	packages/plan/plan-mode/tests/plan-mode.spec.ts
#	snapshots/session/cordis-inspect-jsdoc/session.v4.jsonl
2026-10-21 23:32:15 +08:00
Yichen Jiang dd568f76de Merge remote-tracking branch 'origin/master' into worktree/composer-image-preupload
# Conflicts:
#	packages/test-support/client-runtime/README.i18n.yaml
2026-10-21 23:17:57 +08:00
Yichen Jiang 076d8a05f1 test(snapshots): declare exit_plan_mode only after plan-mode entry in background-wait-steer
The scenario arrived from master recorded with exit_plan_mode in a Session that never enters plan mode. Its fixture cannot be refreshed until #6710 lands, so the schema is removed by hand to match the replayed request.
2026-10-21 18:03:40 +08:00