The face layout paragraph still counted six split packages. The
liveshare-protocol split added a seventh, and this names which part of the
package stays on each leaf.
The v2 upgrade guide and the fork-readonly normalization were development-period artifacts that never shipped, so the protocol returns to version 1: the guide triplet is deleted with its references, the withdrawn tier is no longer named anywhere (unknown tiers are rejected generically), and the README plus the version test state version 1. The file-upload capability and its additive field stay.
The share spec gains an optional allowsFileUpload switch, the access-state frame always states it (an absent field reads as off), and the file-upload capability separates the field from the tier and fork switches. The wire version stays 2 because the change is additive; the upgrade guide says so and the recorded add-share frame names the new field.
The access-mode vocabulary changed from open|approval to open|selected without a protocol version change, so a peer could declare version 1 while refusing every value the other side sends. Version 2 states the break; the retired approval name stays refused rather than reinterpreted, and an upgrade guide records the peer upgrade order.
* feat(experimental): ship the two card experiments as one Personalized recommendations bundle
@deepseek-ai/dsh-personalized-recommendations inserts the action card
service, its browser half, Personalized pages and Plugin recommendations
with their card bodies under the existing row ids. As the only layer that
declares those ids, the Plugins page addresses and switches each row,
including the two shared card rows that were read-only while two bundles
inserted them.
The two experiment packages stop being bundles; the new bundle takes their
place in the official lists and the dsh installation, with the personalized
pages icon, localized title and description, and a feature preview of both
cards. The two feature rows describe what they do on the bundle page.
* fix(experimental): drop the model reason line from plugin recommendation cards
The reason follows the language of the user's question while the catalog
description below it follows the interface language, so the two lines could
differ in language and largely repeat each other; the answer already gives
the reason. The card keeps the catalog title and description, both in the
interface language, as its details target.
* test(web): refresh the card fixtures for the Personalized recommendations bundle
Both card replays enable the new bundle, so each Session lists both card
skills, and each skill's catalog lists Personalized recommendations in place
of the two former bundles. The plugin card goldens lose the reason line.
---------
Co-authored-by: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com>
Takes master's move of the official plugin lists into
@deepseek-ai/dsh-official-bundles. The Plugins page files come from master,
and the plugin recommendations bundle follows the personalized pages bundle
in OPTIONAL_BUNDLES, MORE_BUNDLES and EXPERIMENTAL_BUNDLES.
Takes master 020a053a120 through the base, which ships Spanish, French,
German, Russian and Portuguese and requires them in every package. The page
card fixture takes the base's eight-language plugin catalog.
Move @deepseek-ai/dsh-official-bundles from packages/boot to packages/util
and move the plugin manager's protected plugin list and the Web plugin
page's hidden, ordered, and experimental bundle lists into it, so editing
any of these lists no longer touches app-boot or either plugin manager
package.
The two packages keep their directories under packages/experimental and are
registered as experimental name exceptions:
- @deepseek-ai/dsh-plugin-recommendations
- @deepseek-ai/dsh-client-ui-plugin-recommendations
Loader row ids, the Remote service name, locale namespaces and the
enable_official_plugin action are unchanged. Generated catalogs are
regenerated, and both card Web fixtures record the renamed bundle in their
skills' plugin catalogs.
Takes the card packages' new names and master up to e115cc98d65. The plugin
recommendation packages and their bundle rows now name
@deepseek-ai/dsh-action-cards and @deepseek-ai/dsh-client-ui-action-cards;
generated catalogs are regenerated, and both card Web fixtures record the
renamed bundles in their skills' plugin catalogs.
The four packages keep their directories under packages/experimental and
are registered as experimental name exceptions:
- @deepseek-ai/dsh-action-cards
- @deepseek-ai/dsh-client-ui-action-cards
- @deepseek-ai/dsh-creation-recommendations
- @deepseek-ai/dsh-client-ui-creation-recommendations
Loader row ids, plugin record names, message source kinds, the Remote
service name and locale namespaces are unchanged. Generated catalogs are
regenerated, and the page card Web fixture records the renamed bundle in
the skill's plugin catalog.
Takes the action-card fixes: kinds reconcile before every action, only live
roots get cards, the tool refuses while messages are queued, and bodies no
longer receive ready. The plugin card drops ready, its queued-card test goes
with the suppressed phase, and the shared-row limitation follows the base's
new limitations.
- An enable that a plugin reload cuts off records unconfirmed; the card
offers a retry and Not now, and a retry that finds the plugin on records
enabled because this card's change landed.
- A rejected profile change records failed with operation-error and keeps
the retry instead of failing the click; overridden and cancelled are gone
because enabling a bundle only reports applied, restart-required or failed.
- A refused or lost catalog lookup keeps Not now and offers Try again, with
separate copy for each; a settled card keeps its outcome after its plugin
leaves the catalog. Only the clicked button shows Working, the details
label is interpolated, and the reason and description stay its
accessible description.
- The Host entry exports its inject list, so the configuration catalog lists
its services; the skill keeps its rules without the examples.
- With both experiment bundles on, the shared action-card rows cannot be
switched or configured on the Plugins page; the READMEs say so and a
Loader test pins it while the bundles still switch.
- The unused intent fixture is removed and the evaluation set expects a
create_personalized_page card for the counter.
Update the Web permission-policy snapshot, the config catalog line
reference and README text for the new switch notice; pin both switch
directions in the unit test.
Co-authored-by: Tianyi Cui <53024+tianyicui@users.noreply.github.com>
- Kinds can reconcile a card before every user action, including Not now;
the page kind confirms uncertain runs against the installed profile, so an
installed page keeps Undo instead of being dismissed.
- Only a live root's direct skill load activates propose_action; calls from
subagents or from code are refused.
- The tool refuses while queuedMessageLimit messages wait, so the model is
never told a hidden card was shown; the suppressed phase is gone and the
projection moves to state version 2.
- record() refuses actions no kind registered and the derived replaced phase.
- Not now dismisses an unstarted card whose kind is no longer registered.
- The unused ready prop and dead locale keys are removed, and the READMEs
state the card and row rules as implemented.
Plugin recommendations now proposes through the shared propose_action tool
instead of a dsh-action answer block. The Host registers the
enable_official_plugin kind with the action card service: the
official-plugins skill, details holding the plugin name, the Enable verb
with global access, and the enabled, already-enabled and failed phases,
whose data carries the application outcome and the management error code.
The package drops its own projection, Remote act, status notice and
persisted record; it keeps the describe Remote for card text. The bundle
inserts the shared card rows beside its own, as Personalized pages does.
The browser half registers a card body in the shared frame that keeps the
catalog text cache, the reserved loading lines, the single details target
and the Enable and Not now footer. The skill's submission section now asks
for one propose_action call.
Personalized pages registers the create_personalized_page card kind with
its create, keep, undo, cancel and restore handlers and drops its own
projection, Remote and status notice. The skill now ends with a
propose_action call. The Client package contributes only the page card
body. The persistence record moves from the page status source to the
shared action-cards source and decision record.
action-cards owns the propose_action tool, the actionCards projection of
proposals and decisions, the act Remote and the card status notice; card
kinds register an action name, skill, details schema, verbs and handler.
The tool is admitted per Agent only after a registered kind's skill loads.
client-ui-action-cards draws the card frame below the completed answer,
lets kinds register a body per action and adds the propose_action
process row.
Update the capability decision rule, both READMEs, the EventMap JSDoc and generated catalogs. Add the bug-fix Agent Note that records the incident evidence, the decision, rejected alternatives and consequences, and cross-link it from the in-history decision note.
* 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.