deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
AI Service Deeplink (aiservice://) import and export for DSH model
configuration. Implements the transport and configuration layers of
the protocol draft v1
against the composition's llm-pi-ai provider routes.
A single aiservice://model, aiservice://provider, or aiservice://bundle
link carries an endpoint, a wire protocol, a credential, model capabilities,
and inference and transport policy. This package turns such a link into DSH
provider routes, and turns the configured routes back into a link.
| Surface | What it does |
|---|---|
| Settings → Models panel | Paste a link, preview what it will configure, import it, or build a share link from the current routes |
aiservice_deeplink Tool |
The same three operations (preview, import, export) for an agent |
POST /aiservice/preview |
Transport + schema validation and a target summary, with no side effects |
POST /aiservice/import |
Validates, discovers models, then writes the routes and credentials |
POST /aiservice/export |
Builds a link from any configured route, including the built-in DeepSeek one |
GET /aiservice/routes |
Every shareable route, from both namespaces |
GET /aiservice/status |
Whether the namespaces exist and are writable |
| File | Role |
|---|---|
lib/protocol.js |
Transport layer (§2), integrity (§9), and schema validation (§3–§6, §8); strict JSON reader, Base64URL codec, merge precedence |
lib/mapping.js |
llm.model / llm.provider / llm.bundle ⇄ llm-pi-ai profiles and the native llm-deepseek route |
lib/index.js |
Host plugin: Tool, HTTP routes, settings and credential writes |
lib/client.js |
Browser plugin: the Settings → Models panel (__ModuleLoader__ bundle, hand-written, no build step) |
test/ |
78 node --test cases, including the protocol repository's own published examples |
~/.dsh/profiles/web/cordis.patch.yml inserts one row pointing at
lib/index.js by absolute path. The package is deliberately
dependency-free: the row is not part of the profile's pnpm project, so it
cannot import @deepseek-ai/*, and every host service is reached through the
declared inject list or through ctx.get at request time.
Two adapters own routes in this composition, and import and export treat them differently.
| Deeplink | DSH llm-pi-ai |
|---|---|
endpoint.base_url |
providers.<route>.baseURL |
endpoint.api_format |
providers.<route>.api (openai_chat_completions → openai-completions, …) |
endpoint.provider / provider.id |
the route key (slugified, deduplicated against unrelated routes) |
endpoint.credential.api_key |
a credential record named <ROUTE>_API_KEY; the profile keeps apiKeyEnv |
transport.mode / timeout_seconds / cache_retention / retry |
transport / timeoutMs / cacheRetention / retryPolicy |
transport.extra_headers |
headers (a name the credential also provides is an error, per §3.2) |
capabilities.* |
models[].contextWindow / maxTokens / input |
capabilities.api_features + compatibility |
compat, where public fields win over the compatibility override (§5) |
inference.reasoning |
models[].reasoningEfforts (false for mode: disabled), plus a route-wide reasoning only when every model can take it |
autodiscover |
one llm.discoverModels call after validation, before persistence (§4.2.1) |
required_features |
provider.autodiscover, transport.websocket, transport.websocket-cached are served; anything else is refused |
Export reads both namespaces, so the built-in DeepSeek route shares like any
other. llm-pi-ai is a registry keyed by route; llm-deepseek owns exactly one
fixed route (deepseek-official) with a flat section, and is projected onto the
same shape — endpoint, credential reference, thinking policy, and the resolved
catalog, which the adapter supplies as schema defaults. The exported
endpoint.provider is deepseek, a catalog identifier a receiver can infer
defaults from, rather than the harness's own route name.
Two limits are worth knowing:
DEEPSEEK_BASE_URL from the trusted launch
environment when no baseURL is configured, and that value is not readable
from a plugin. An explicitly configured endpoint travels; otherwise the link
carries DeepSeek's public endpoint.reasoningEffort default is applied per request and never
appears in the resolved settings, so an unconfigured effort is omitted rather
than guessed. An explicit one travels.providers.<route>.reasoning is a hard default applied to every model on
the route, and a request naming a level a model does not support is refused
with UNSUPPORTED_REASONING_EFFORT. A hand-declared model declares no
reasoning at all, so it supports only off. Hoisting one model's effort onto
the route therefore makes every other model unusable — which is what an
unconditional mapping from inference.reasoning.effort does.
So the effort is handled per model:
mode: disabled → reasoningEfforts: false, the harness's own way of
declaring a non-reasoning model.compatibility.thinking_format or supports_reasoning_effort) →
reasoningEfforts: { off: null, <level>: <level> } on that model, so the
level exists and the session picker offers it.reasoning default is set only when every model on the
route can take the same level. Note this is about what each model supports,
not about the models agreeing: provider defaults make every model resolve to
the same effort, and that is exactly the case that would otherwise force a
level no model was equipped to send.Import always writes llm-pi-ai. The native DeepSeek route is a
single-vendor adapter, not a place to point at an arbitrary endpoint, and route
names are unique across the whole llm registry — so an imported link never
claims a name another adapter owns, even when its endpoint matches.
Everything the mapping cannot carry (transport.user_agent,
inference.temperature, inference.reasoning.history and budget_tokens,
retry.max_retry_after_seconds, a completions-only switch on an Anthropic
route) is reported in the preview's notes rather than dropped silently. On
export the same applies to a thinking level above every level the protocol
names: the harness's max is shared as xhigh and the substitution is
reported beside the link.
import.settings.update('llm-pi-ai', …) call, which validates before persisting, so
a rejected import leaves the previous configuration untouched (§7).credential.type = "prompt" instead (§6.1).overwriteCredentials.The harness owns two disjoint key spaces, and an imported API key belongs to the first:
| Space | Address | Stored as | Used by |
|---|---|---|---|
| reference | <PROVIDER>_API_KEY, a POSIX shell identifier |
.credentials.yaml refs: |
a route's apiKeyEnv, resolved once per request |
| record | <scope>/<id>, lowercase hyphenated |
.credentials.yaml records: |
a plugin's own sign-in flow (e.g. llm-pi-ai/<route>) |
A pi-ai route names a reference, so that is what this plugin writes: the
same <PROVIDER_UPPER_SNAKE>_API_KEY derivation the Models page uses, through
the same credentials.set. References are layered against the environment, and
the inherited process environment outranks the managed file — so a write the
launching shell would shadow is refused by the provider, and this plugin checks
credentials.describe first and reports it instead of failing mid-import.
Because a reference is a shared name rather than a private slot for one link,
the derived name is never written over a value that is already there. A link
naming anthropic would otherwise replace whatever key the user had stored for
that provider.
node --test 'test/*.test.mjs'
test/protocol.test.mjs reproduces the protocol repository's published
model.uri, provider.uri, and bundle.uri byte for byte and checks the
rejections the spec requires. Point AISERVICE_EXAMPLES at another checkout of
that repository to run against a different revision.
The profile mounts the host half by absolute path, and Node caches an ES module
by URL: edits to lib/*.js reach the running process only after dsh web
restarts. The client bundle additionally needs a page refresh.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。