feat(web): mount the config plane in dsh web and pin the Models page keyless

apps/cli/cordis.yml gains settings-local, credentials-local, and the bare
dormant llm-pi-ai row (manifest deps added for the resolver contract);
llm-deepseek drops its !!js apiKey inline for per-request credential
resolution. Both adapters tag apiKeyEnv role('credential-ref') so the
form mounts the credential control. The web e2e scaffold isolates a
harness home per run — an in-process boot must never touch the
developer's real ~/.dsh — and the new models-settings scenario pins the
whole loop through the shipped app: dormant directory as add vocabulary,
schema-driven editor apply landing in settings.yaml, the route
registering live (topology frame), and a write-only key landing in the
temp .env with the configured badge converging. A hermetic test-owned
reference name keeps a developer's real provider keys from flipping the
badge. schema-form joins the platform module table (seed + externals)
so client bundles share one instance.
This commit is contained in:
Yichen Jiang
2026-07-30 09:29:40 +08:00
parent 686e40ebf6
commit 0d96676f35
19 changed files with 347 additions and 36 deletions

View File

@@ -78,14 +78,33 @@
config:
agents: []
# The native DeepSeek adapter; reads the key/base-url the boot's layered
# .env loading (cwd then $DSH_HOME) left in the environment.
# User-settings document (`$DSH_HOME/settings.yaml`, hot-reloaded): the web
# settings page writes it through `settings.update`/`settings.replace`, and an
# external edit converges every open surface through `host/settings-changed`.
- id: settings
name: '@deepseek-ai/dsh-settings-local'
# Credential store: the live process environment over `$DSH_HOME/.env`
# (owner-only file, hot-reloaded). The web page's key inputs write it through
# `credentials.set`; adapters resolve references per request.
- id: credentials
name: '@deepseek-ai/dsh-credentials-local'
# The native DeepSeek adapter; the API key resolves per request through the
# credential store above (default reference DEEPSEEK_API_KEY), so no key is
# inlined here and a missing one fails the request, not the boot.
- id: llm-deepseek
name: '@deepseek-ai/dsh-llm-deepseek'
config:
apiKey: !!js process.env.DEEPSEEK_API_KEY
baseURL: !!js process.env.DEEPSEEK_BASE_URL
# The pi-ai multi-provider twin, mounted dormant: zero routes until the
# `llm-pi-ai:` settings section supplies provider profiles — exactly what the
# web Models page writes. Configured routes register live and drop when the
# section empties.
- id: llm-pi-ai
name: '@deepseek-ai/dsh-llm-pi-ai'
# Transient-failure recovery around the loop's model calls (same policy as
# the TUI's agent-spine composition; defaults: 2 retries, 500ms→10s backoff).
- id: llm-retry

View File

@@ -47,6 +47,7 @@
"@deepseek-ai/dsh-command-goal": "workspace:^",
"@deepseek-ai/dsh-commands": "workspace:^",
"@deepseek-ai/dsh-compact-basic": "workspace:^",
"@deepseek-ai/dsh-credentials-local": "workspace:^",
"@deepseek-ai/dsh-frontend": "workspace:^",
"@deepseek-ai/dsh-fs-local": "workspace:^",
"@deepseek-ai/dsh-fs-policy": "workspace:^",
@@ -56,6 +57,7 @@
"@deepseek-ai/dsh-host-webserver": "workspace:^",
"@deepseek-ai/dsh-llm": "workspace:^",
"@deepseek-ai/dsh-llm-deepseek": "workspace:^",
"@deepseek-ai/dsh-llm-pi-ai": "workspace:^",
"@deepseek-ai/dsh-llm-retry": "workspace:^",
"@deepseek-ai/dsh-paths": "workspace:^",
"@deepseek-ai/dsh-plan-mode": "workspace:^",
@@ -65,6 +67,7 @@
"@deepseek-ai/dsh-session-projection-cache": "workspace:^",
"@deepseek-ai/dsh-session-title": "workspace:^",
"@deepseek-ai/dsh-session-title-first-message-llm": "workspace:^",
"@deepseek-ai/dsh-settings-local": "workspace:^",
"@deepseek-ai/dsh-skill": "workspace:^",
"@deepseek-ai/dsh-skill-local": "workspace:^",
"@deepseek-ai/dsh-spill-local": "workspace:^",