Repository navigation
Releases: Yurzi/dsh-tool-web-enhanced
Releases · Yurzi/dsh-tool-web-enhanced
Release list
v0.1.3
dsh-tool-web-enhanced-profile 0.1.3
- Mounts dsh-web-search-enhanced 0.2.3, dsh-web-fetch-enhanced 0.2.3 and dsh-tool-web-enhanced-ui 0.1.3; the patch itself is unchanged.
dsh-tool-web-enhanced-ui 0.1.3
- Released with the profile; no behaviour change of its own.
dsh-web-search-enhanced 0.2.3
- New: built-in connection
builtin:anysearch(AnySearch web search over REST,POST https://api.anysearch.com/v1/search), listed after Tinyfish and off by default like every remote service. It takes a personal API key only (ANYSEARCH_API_KEY, the same credential name as AnySearch's own plugin): the service has an anonymous tier, but this plugin offers no anonymous access, and custom AnySearch connections use a key too. Two connection options, set on the row settings page for built-in and custom connections:zone(cnorintl) andlanguage(a language tag such aszh-CNoren). Up to 10 results; a source's summary is the service'ssnippet, or itscontentwhen there is none. HTTP 402 gives only the generic HTTP 402 message, the body ignored. Do not install it together with@anysearch/anysearch-dsh: that bundle's profile layer writes both fields of thewebrow asanysearch, so routing leaves this plugin. - Changed: upstream explanations are worded in one place (core
upstreamSuffix); model-facing text for the existing services is unchanged.
dsh-web-fetch-enhanced 0.2.3
- New: built-in connection
builtin:anysearch(AnySearch extract over REST,POST https://api.anysearch.com/v1/extract), listed after Tinyfish, off by default, personal API key only (ANYSEARCH_API_KEY), without options: the request body is only{ url }. Results are text for the requested URL with HTTP 200 (AnySearch reports neither the target status nor a final URL), without the title; a body of 50,000 characters or more is marked truncated, since AnySearch cuts long HTML and plain text there without saying so. Failures are classified by AnySearch'serror_code, in a 2xx answer or an HTTP 400 or 422:invalid_extract_url→WEB_INVALID_URL,extract_target_blocked→WEB_BLOCKED_URL("… refused to read the URL because the service blocks this target; try another URL or fetch connection"),extract_unsupported_content→WEB_UNSUPPORTED_CONTENT_TYPE("… cannot read this content type (for example PDF or other binary files); try another fetch connection"),extract_content_too_large→WEB_FETCH_TOO_LARGE,extract_timeout→WEB_FETCH_TIMEOUT; any other 422 → "could not read the page". An HTTP 400 without a known code, 401, 403, 429 and other statuses keep the generic HTTP wording; 402 gives only the generic message, the body ignored. The settings page's service note says what AnySearch receives, what its privacy policy and terms say it keeps, and what it reads. The plugin-page and package descriptions list AnySearch among the remote reading services. The same caution about@anysearch/anysearch-dshapplies. - Changed: as for search, upstream explanations are worded in one place; model-facing text for the existing services is unchanged.
dsh-tool-web-enhanced-core (private, not published)
./host: anAdapterWiremay classify a non-2xx answer on its REST routes with an optionalparseFailure(response, input)returning aFailureVerdict:status(the generic wording for the HTTP status, with a given explanation or none) oroutcome(a service outcome, mapped and worded like a 2xx one);statusVerdict(generic wording, generic explanation) is the default.mapWiremaps outcome verdicts and passes status verdicts through. The transport knows no service:exchangeJsonreturns the redacted 2xx payload or aFailureResponse(status;json, the first 16 KiB parsed with credential-bearing string values redacted, for classification only; the genericexplanation;explain(value); both explanations are withheld whenever the raw body carries this request's credential), andstatusFailuregives the generic status wording.runAdapterredacts a 2xx outcome afterparseas before and returns a non-2xx outcome as is../host: upstream explanations in outcomes (SearchFailureapi,PageOutcomefailures) areUpstreamDetail, branded on the text value so only the transport builds them (bodyDetailfor 2xx bodies,upstreamDetail,FailureResponse); they keep the whole screened text, andupstreamSuffixtrims and bounds it to 2000 characters when wording it, withholding any detail without atextproperty../host:anysearchSearchandanysearchFetch;SearchInvalidReasonaddscode-numberanddata-results-array,PageFailureaddsblockedandunsupported.
Development
- Tests: the
enhanced-write-racee2e spec collects only responses to requests issued after the reload commits. A request of the old document could get its response while that document was torn down, and its body never settled, so the case timed out. - Tests: the e2e browser harness no longer counts DSH's
Sidebar Session opening failed: … Session reference "…" is releasedconsole message as a page error. DSH's right Sidebar logs it when a conversation is selected before the previously selected one has finished opening, which made GUI specs that switch conversations right after load (setup-commands-ui) fail occasionally; other opening failures are still collected.
v0.1.2
dsh-tool-web-enhanced-profile 0.1.2
- Mounts dsh-web-search-enhanced 0.2.2, dsh-web-fetch-enhanced 0.2.2 and dsh-tool-web-enhanced-ui 0.1.2; the patch itself is unchanged.
dsh-tool-web-enhanced-ui 0.1.2
- Released with the profile; no behaviour change of its own. Its browser face is Web-only: in dsh-TUI the row mounts and does nothing, and the plugins'
/setup-*Host commands below work there without it.
dsh-web-search-enhanced 0.2.2
- Fix: a subagent's conversation (spawn or subagent_fork) no longer shows "Read failed" in the composer menu (#1); its connection can be read and changed there like any conversation's, whether or not the subagent is running. A running subagent uses the new choice from its next model request step, and turning search Off hides
web_searchright away; a subagent that is not running uses it the next time it runs (woken by its parent Agent or by a message in its conversation), and reading or changing the choice does not resume it. Choices made in a subagent's conversation do not write model memory. Top-level conversations and user forks (the Web's forked sessions) are unchanged and still write it. - While a subagent is not running, the model of its next request is unknown: the conversation-model connection says so (reason
no-model), native connections show readiness from the API key only, and a conversation that has neither chosen nor inherited a choice shows the default connection without looking up model memory; that is worked out again, with model memory, when the subagent runs. - The menu text for
no-modelnow reads "The model for this conversation's next request isn't known yet" / "还不知道本会话下一次请求用哪个模型". /setup-searchis now a Host command that the plugin registers while its row runs (the shared UI row is not needed), so it works in the Web GUI and in dsh-TUI. Without arguments it shows the conversation's connection, where the choice comes from and its freshness, whether thewebrow routes search to this plugin, and the enabled connections with their status,current,applies freshnessand who receives the query.off, a connection id andfreshness auto|fresh|realtimechange the choice from the next model request under the composer menu's rules: only enabled connections, a revision check that refuses a choice changed meanwhile, no model memory from a subagent's conversation, and freshness only for a connection that applies it.off,freshnessand the modes are case-insensitive; connection ids are not. The description and output are fixed English text; invalid settings, storage failures and unexpected errors give fixed messages, and the original error is logged to the Host log at warn level, never shown.- Web GUI: the slash-menu row for
/setup-searchnow shows the Host command's name and English description, without the icon and localized title. Choosing it, or pressing Enter without arguments, opens the same chooser as before; a line with arguments (/setup-search off) runs the Host command, its output appears in a command card, and this tab then re-reads that conversation's choice and model memory (other tabs and dsh-TUI's writes show on their next read). A subagent's conversation view has no/setup-*, because DSH lists no commands there; its composer menu still works. - dsh-TUI: arguments complete after
/setup-search:off, the row's enabled connection ids (inserted exactly as written, such ascustom:MyEngine), andfreshnessfollowed byauto,freshorrealtime. Completions mark neither the current choice nor readiness; run the command without arguments for those. dsh-TUI 0.16.1 shows a plugin command's output as a one-line notice of about 200 characters, so only the start of that listing is visible there; the Web GUI's chooser and composer menu show the connections and their status in full.
dsh-web-fetch-enhanced 0.2.2
- The same subagent fix as search (#1): a subagent's conversation can read and change its fetch connection in the composer menu whether or not the subagent is running, turning fetch Off in a running subagent hides
web_fetchright away, a subagent that is not running uses the new choice the next time it runs, and choices made there do not write model memory. While a subagent is not running, native connections show readiness from the API key only, and a conversation that has neither chosen nor inherited a choice shows the default connection without looking up model memory. /setup-fetchis now a Host command, as for search: without arguments it shows the conversation's connection and where the choice comes from, the routing, and the enabled connections with their status,currentand who receives the URL;offor a connection id changes the choice from the next model request under the same rules. The Web GUI's slash-menu row, chooser and command card work as for search, and dsh-TUI completesoffand the row's enabled connection ids.
dsh-tool-web-enhanced-core (private, not published)
./host:sessionOrigin(header)classifies a Session from public header fields astop-level,forkorsubagent(origin: 'subagent'decides first, as in DSH's own subagent ownership rule); selection inheritance, provider-list copying,isNewConversationand the model-memory decision use it, with unchanged results for the first three../host:Sessionsreads and writes aSessionTarget(livewith its Agent vialiveSession(agent), orcoldwith only the Session id and header) instead of an Agent.changedecides model memory itself (only a connection choice, never for asubagentSession, only with a known next-request model) and, once the write is durable, syncs tool masks for whichever Agent is running then.Capability.describeandcredentialReadinesstake the next request's model (SessionModel | undefined) instead of an Agent../host: the connection Remote service'sgetandsetshare one lookup: a running Agent fromctx.agents.get; else, for a subagent Session whose headersessionPersistence.statreturns, the stored record directly without resuming it; elsesessionController.resolveAgent, whose errors pass through. The service is installed in thesessionController+typert+agentsinjection scope../host:registerCommand(host/command.ts) registers a capability's Host command frominstallCapabilityin acommandsinjection scope;writeSelection(host/selection-write.ts) is the one eligibility check and revisioned write that Remotesetand the command share (written,unavailableorconflict; Remote's errors are unchanged);registerTerminal(host/terminal.ts) registers dsh-TUI completion through locally declared structural types in its owntuiCommandTreesinjection scope, so a failure there leaves the row and the command running. New:PluginIdentity.command(./shared), the optionalCapability.commandOptions(search's freshness) andLabeledConnection;enhanced-parts/listing.tsexportsrecipientText,oneLineandLABEL_MAX../client:selectionCommandreturns aCommandDecorationforcommandUi.decorate(no label, description or icon) instead of aCommandContribution;followHostCommandlistens tocommand/executed;ConnectionSelectionStore.invalidateSession(sessionId)re-reads one Session's views.
Development
- New devDependencies
@deepseek-ai/dsh-commands(catalog version; command types and composition tests on the realCommandRuntime) and@deepseek-harness-tui/dsh-tui0.16.1 (the dsh-TUI e2e spec and the completion registry test). Product code imports only types from the first and nothing from the second; neither is in a published package. The e2e suite drives the published dsh-TUI through a real PTY (Python's standardptymodule), so it needspython3.
v0.1.1
dsh-tool-web-enhanced-profile 0.1.1
- Mounts dsh-web-search-enhanced 0.2.1, dsh-web-fetch-enhanced 0.2.1 and dsh-tool-web-enhanced-ui 0.1.1; the patch itself is unchanged.
dsh-tool-web-enhanced-ui 0.1.1
- The composer menu lists only connections that are turned on; the conversation's own choice stays listed (with its warning dot) if it was turned off since.
- When all of a capability's remote services (built-in catalog entries that start off) are off, its panel ends with "More services can be turned on in settings", outside the scrolling list; it opens the plugin settings. Custom connections do not count, and the hint is not shown while the settings are unread or invalid.
- The activation prompt adds "Remote services are off by default; turn them on there when you need them." when the upgrade check finds no problem.
- The menu shows only the conversation's own choice; the Agent's enhanced-tool calls never appear in it.
dsh-web-search-enhanced 0.2.1
- Breaking: remote services are off by default:
builtin:deepseek-search-apiand the six adaptersbuiltin:exa,builtin:firecrawl,builtin:tavily,builtin:tinyfish,builtin:openalexandbuiltin:semanticscholar. A built-in connection without adisabledoverride now takes its catalog default;builtin:deepseek-messages,builtin:session-modeland custom connections stay on. Documents that already saydisabled: falseare unaffected, and the Host never rewrites a document. A conversation choice ordefaultConnectionthat names one of these services fails withWEB_PROVIDER_CONFIGURED_UNAVAILABLEuntil the operator turns the service on in the settings page, which restores it; a model memory that names one falls back to the default connection until then. - Enhanced tools: with the new row setting
enhancedTools: true(the "Enhanced tools" switch, off by default), the plugin registersweb_search_enhanced(queries, then a requiredprovider: a connection id) andlist_web_search_providersto DSH's global tool layer, so every agent preset (minimal included) and the base profile get them. They are registered only while thewebrow is confirmed to route search to this plugin and the settings are valid, and are hidden from an Agent whose conversation has no provider list, turned search Off, or whose choice has not been read. - Each new top-level conversation records its provider list once: the connections enabled at that moment, or an empty list while the tools are not offered, so conversations started earlier never gain the tools mid-way. Child and forked conversations copy their parent's list; resumed conversations read it. Connections turned off later stay usable in that conversation; removed ones fail with "was removed by the user".
- An explicit call runs once per distinct query on the named provider, as the calling Agent, through the same checks and execution layer as
web_search(current settings, credentials, keyless, endpoint trust, deadlines, redaction, upstream explanations, cancellation). It never changes the conversation's choice or model memory, and is refused when the conversation turned search Off. Output isProvider: <id>followed by tool-web's own format; the canonical value addsprovider. - Refusals and argument errors have short fixed wording that names the ready providers ("ready providers: …", "no other provider is ready", or "list_web_search_providers shows the ready providers" when readiness cannot be read); argument errors repeat tool-web's own message after
invalid arguments:. An unknown provider also gets "Providers added or turned on after this conversation started are available only in new conversations." A backend failure keeps its code and message and getsProvider "<id>" failed; list_web_search_providers shows the others.at the end of its first paragraph (after a full stop if the paragraph lacks one), before any untrusted explanation. list_web_search_providerslists the conversation's providers with their name, readiness, use, who receives the query and whether they apply the conversation's freshness; it ends with a note when the conversation's own connection is turned off. Readiness that cannot be read gives a fixedWEB_PROVIDER_ERROR.- Timeouts:
web_search_enhanced100 s, slightly longer than the remote deadline; the list tool has none. - Settings page: an "Enhanced tools" section after the defaults, with its consent ("Turning this on means you agree that when the Agent picks a service, the query is sent to that service."); the services list says "Remote services are off by default." and marks services that are off with "Off"; enabling writes
disabled: falsesparsely over the inherited value. - Fix: switches flipped in quick succession on the settings page are no longer refused; writes on one page now run one at a time, and switch-type writes are computed on the document the previous write left. A change made elsewhere that the page has not received is still refused.
- Connection labels are read as one line (line breaks and control characters become spaces); documents are neither refused nor rewritten.
- Security: an exception thrown while resolving a credential (DSH Credentials or the DeepSeek account service), even a
WebErrorwith a plausible code, no longer reaches the model or the log; it becomes the fixed "search failed; check the connection settings or choose another connection" error, and only real cancellation isWEB_ABORTED. - New peer dependency
@deepseek-ai/dsh-tool-web(already installed with DSH), whose formatters the enhanced tools reuse.
dsh-web-fetch-enhanced 0.2.1
- Breaking: remote services are off by default:
builtin:deepseek-fetch-apiand the four adaptersbuiltin:exa,builtin:firecrawl,builtin:tavilyandbuiltin:tinyfish.builtin:localand custom connections stay on. Documents that already saydisabled: falseare unaffected, and the Host never rewrites a document. A conversation choice ordefaultConnectionthat names one of these services fails withWEB_PROVIDER_CONFIGURED_UNAVAILABLEuntil the operator turns the service on in the settings page; a model memory that names one falls back to the default connection until then. - Enhanced tools, as for search:
enhancedTools: trueregistersweb_fetch_enhanced(url, then a requiredprovider) andlist_web_fetch_providersunder the same conditions, with the same per-conversation provider list, refusals and switch-provider hint (not added to cancellation or to local'sWEB_INVALID_URLandWEB_BLOCKED_URL, so the Agent is not steered around the operator allowlist). The list says who receives the URL and, forbuiltin:local, the operator allowlist worded for "this provider".web_fetch_enhancedtimes out after 130 s. - Settings page: the "Enhanced tools" section ("…the URL is sent to that service."), the remote-services notice and "Off" marks, and the same write fix and one-line labels as search.
- Security: the same credential-resolution fix as search ("fetch failed; check the connection settings or choose another connection").
- New peer dependency
@deepseek-ai/dsh-tool-web.
dsh-tool-web-enhanced-core (private, not published)
./shared: enhanced tool names in the identities (PluginIdentity.tools),isConnectionId, catalogoptInanduse, theenhancedToolssetting,disableddefaulting tooptInfor built-in connections, andsingleLinefor labels../host: the visibility controller (ToolRestriction) now also registers and masks the enhanced tools, with an atomic, rolled-back pair registration; the explicit entry (EnhancedAccessrun/list/ready,ReadyProviders); conversation provider lists (tableprovider_listsin the existing version-1 storage domain, sharing the per-Session queue with selections); the shared enhanced-tool parts (enhanced-parts/);Capability.enhanced. The credential boundary inrunAdapterno longer passes resolverWebErrors through../client:remoteServicesOffSource, the "Enhanced tools" section, and a serialized settings write queue (SettingsChange,readSettings).
v0.1.0
dsh-tool-web-enhanced-profile 0.1.0
- New bundle. Selects
search-enhancedandfetch-enhancedin the sharedwebrow (both fields), disables the nativeweb-search-deepseekrow, and mounts the two plugins and the menu row below.
dsh-tool-web-enhanced-ui 0.1.0
- New package, mounted by the profile as row
tool-web-enhanced-ui. The Host face is empty; the row exists so DSH loads the browser face. It works with either plugin row, both, or neither. - The
webConnectionsbrowser service: plugins register their menu sections and, separately, their route facts into it. - One composer button for both capabilities. It shows each registered section's state in menu order ("Exa · Local HTTP", or Off, Couldn't load, Invalid settings, Connection removed), with a warning dot on a side that needs attention (load failure, invalid settings, a removed or unready connection, or routing to another provider). Its accessible name and tooltip read per side, for example "Search: Exa · Fetch: Local HTTP (needs attention)". When the composer's controls do not fit on one line, the button collapses together with DSH's model selector (it follows the row's
--dsh-composer-model-text-display/--dsh-composer-model-icon-displayinstead of breakpoints of its own): the text hides and the dots move onto the globe icon, so the button never pushes the composer onto two lines. - The menu has two layers: a panel for one capability above, and DSH's segmented tabs at the bottom, nearest the button, to switch between the capabilities (Search, then Fetch). It opens on the first with focus on its tab; ←/→ and Home/End move between the tabs, Escape closes it and returns focus to the button, and a tab carries the same warning dot as its side. All panels share one grid cell, so the menu keeps the tallest panel's height and does not jump when switching; only the list scrolls, and the selected row is scrolled into view. A panel's header shows the current connection and where the choice comes from ("This conversation", "Parent conversation", "Model's last choice", "Default connection"), with a settings button (gear icon) beside it; below are Off, the connections, the capability's own options, a loading state, a "Couldn't load" row that reloads when clicked, and a notice when the
webrow routes the capability elsewhere. When a capability's settings are invalid, its panel says " settings are invalid. Open settings to fix them." and points to that settings button, without a reload. - Route facts come from the running plugins, including
DSH_WEB_SEARCH_PROVIDER/DSH_WEB_FETCH_PROVIDER, even withshowSelector: false. For a plugin row that is not running, the browser has no source for those variables and judges from thewebrow alone. - With a plugin row disabled (search, fetch or both), its tab disappears and the menu and overview say the capability is unavailable; with no sections, the button is hidden.
- Activation prompt for the profile bundle. It runs the same upgrade preflight as the overview: when 0.1.x leftovers may keep web tools away from this bundle, it says so and points to the profile details. It never writes anything itself.
- Bundle overview on the Plugins page: whether each capability is routed to this profile, whether its plugin row is disabled, and an upgrade preflight for leftovers of 0.1.x (user-layer
weboverrides, coexistence-mode provider ids, a re-enabledweb-search-deepseekrow). "Remove leftover settings" appears only next to the leftovers it can fix and removes the user-layerwebfields only after confirmation; nothing is rewritten silently.
dsh-web-search-enhanced 0.2.0
- Breaking: no longer a bundle; install
dsh-tool-web-enhanced-profile. Upgrading this package alone removes its row from the profile. - Breaking: registers the provider
search-enhancedinstead of taking the nativedeepseek-officialseat. - Breaking: the settings format is redesigned and 0.1.x settings are not read. The document is
{ version: 2, defaultConnection, showSelector, defaults: { freshness }, connections }, the same grammar as the fetch row. Retired top-level fields (providerId, top-levelfreshness, and the 0.0.x fieldsmodelMode,protocol,baseURL,model,fallbackModel,apiKey,apiKeyEnv,apiVersion,toolIdentifier,maxTokens,maxUses,chatSearchMode,searchContextSize) are rejected with an error naming the field. The plugin still loads; searches fail withWEB_PROVIDER_CONFIGURED_UNAVAILABLEuntil the settings are fixed. The settings page says "These search settings can't be read…" and offers Reset; a storedapiKeyis hidden from the page and must be removed by hand. - Breaking:
builtin:deepseekandkind: structuredare no longer accepted; usebuiltin:deepseek-search-apiandkind: adapter. The 0.1.x model settings (modelMode,protocol,chatSearchMode, …) are not read; model search is configured anew as the connections below. - Stored conversation choices and model memories from 0.1.x keep working; the storage format is unchanged.
- Session connections: each conversation chooses a connection or Off; the choice is frozen per model request step, forks inherit it, and whether the connection is still enabled, along with its endpoint, key reference and options, is read on every call.
- Model memory is visible and clearable: choosing a connection remembers it for the conversation's model, the composer shows when a choice came from memory, and the settings page lists every memory with a clear button.
- Nine built-in connections: native
deepseek-messages(default, same as native DeepSeek search) anddeepseek-search-api; the model connectionsession-model(below); adapters Exa, Firecrawl, Tavily, Tinyfish, OpenAlex and Semantic Scholar (keyless where the service allows it; Exa and Tinyfish keyless go through their hosted MCP tools). Operators can add custom adapter connections and custom model connections. - Off hides
web_searchfrom that conversation's Agent from the next request step, while thewebrow routes search to this plugin; calls that still arrive get an error. When thewebrow changes, conversations already seen by the plugin are rechecked at once. - Row settings page on the Plugins page, driven by the catalog and shared with fetch: default connection, built-in services (enable, access, credential name, write-only key, options), custom connections, model memory, route notice, Reset. Writes are sparse and validated before they are saved. Each built-in connection can use another DSH Credentials name (empty means the catalog's name). A native
baseURLcan be overridden like on the native row, but only together withtrustedEndpoint: true; on the page an "I trust this address" switch confirms it. Trust belongs to the address it was given for: changing the address asks again, and turning the switch off revokes the trust and returns to the official endpoint in one write. The same applies to custom connections. Switching a service back to keyless also removes, in the same write, options the keyless route does not accept. Yes/no options offer Default, On and Off. Removing a custom connection resetsdefaultConnectiononly when it named that connection. Custom connection rows say which service receives the query. - In the composer menu, ready connections show their access and, for remote services, who receives the query ("No key needed · the query is sent to Exa"); unavailable ones give a short reason ("Needs an API key", "Needs a DeepSeek account or API key"). Freshness uses DSH's segmented control.
/setup-searchcommand to choose or turn off the conversation's connection and set freshness; it works with or without the composer menu (showSelector: falsehides only the menu section).- Model-facing errors are short and actionable, for example " could not complete the search…" for a failed hosted MCP tool. An API key containing a line break or another control character is refused before any request with
WEB_PROVIDER_CREDENTIAL_MISSING, naming only the credential. - Model search: a third backend kind,
model, asks a model with a server-side web search tool to run the search. One non-streaming request through the same bounded transport (redirects refused, 2 MiB, 90 s, no retry); the model's answer is returned ascontentexactly as written (adjacent text blocks joined, a blank line where a tool block sits between them, never trimmed or cut), and the sources it cites go through the same source filter as every other connection. Answers without a search or with a tool error block are returned as they are, for the Agent to judge. Protocols: Anthropic Messages, OpenAI Responses and OpenAI Chat Completions. builtin:session-model("Conversation model"): follows the model of the request that made the call, read again on every call (never frozen in the step plan). DeepSeek's two official routes are handled in one place: the session's endpoint (configuredbaseURL, thenDEEPSEEK_BASE_URL, thenhttps://api.deepseek.com/anthropic) and the session's credential (apiKeyEnv, defaultDEEPSEEK_API_KEY; the account route uses the account sign-in and never falls back to an API key). Other routes are followed when DSH's Models settings declare one of the three protocols (api), with no custom headers and an endpoint not built from an environment variable. When the route cannot be followed, the menu says why (no model yet, unreadable provider settings, no supported protocol, no fixed endpoint, custom headers, no single API key) and calls fail withWEB_PROVIDER_CONFIGURED_UNAVAILABLE; the plugin never switches connection on its own. Enabled by default; it is used only when a conversation chooses it. Overrides accept onlylabel,disabledandoptions.- Custom fixed model connections:
custom:<name>withkind: model,protocol,model, a requiredendpoint,trustedEndpoint: true(always required) and `cr...