mirror of
https://github.com/ryan4yin/nix-config.git
synced 2026-11-13 12:13:36 +01:00
refactor(agents): link dsh shared policy as a home-layer patch (#388)
dsh rewrites a profile's cordis.patch.yml at runtime, so linking the web profile put GUI state in the checkout and let runtime writes clobber manual edits. Link the stable policy as the $DSH_HOME home layer instead: dsh applies it after every profile and only reads it. The host-plane compaction-basic row is disabled on the web surface and each agent preset owns its own copy, so the top-level override was inert. Drop it; the model contextWindow/maxTokens are the effective knobs. - add home/base/tui/agents/dsh/cordis.patch.yml, linked from default.nix - drop the ~/.dsh/profiles/web link and the tracked web/ profile - keep runtime state and private/local model routes in the profile patch - update the eval test and README
This commit is contained in:
1 parent
205f7c622b
commit
28e0b156ce
10 files changed
+120
-151
No files matched your search
@@ -13,8 +13,8 @@ Nix dependency; this module only wires it into place.
|
||||
- `packages.nix`: agent CLIs (`codex`, `opencode2`, `pi`) from the `llm-agents` flake input, plus
|
||||
`pkgs.mcp-grafana` for the Grafana MCP server.
|
||||
- `env.nix`: telemetry and auto-update opt-outs for the agents.
|
||||
- `dsh/`: the dsh `web` profile that lives in `~/.dsh`. See [dsh/README.md](./dsh/README.md) for the
|
||||
link granularity, the tracked members and which hosts import it.
|
||||
- `dsh/`: the shared dsh home-layer patch linked to `~/.dsh/cordis.patch.yml`. See
|
||||
[dsh/README.md](./dsh/README.md) for why the shared layer is linked and the profile patch is not.
|
||||
|
||||
## Deployed rule targets
|
||||
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
# dsh
|
||||
|
||||
The dsh (DeepSeek Harness) `web` profile, linked into `~/.dsh/profiles/web` from the checked-in
|
||||
files under [`web/`](./web).
|
||||
Shared dsh (DeepSeek Harness) policy, linked into `~/.dsh/cordis.patch.yml`.
|
||||
|
||||
## Why the link targets the directory
|
||||
## Layers
|
||||
|
||||
dsh persists Settings through `cordis.patch.yml` with an atomic write (a random-suffix sibling, then
|
||||
a rename), and that rename replaces a symlinked target instead of writing through to its referent. A
|
||||
file-level link — store or out-of-store — is destroyed by the first Settings save, while a directory
|
||||
link keeps the write inside the checkout. Same reasoning as `home/base/tui/tuios`, one level up.
|
||||
dsh composes a profile from bundle patches, the profile's own `cordis.patch.yml`, then
|
||||
`$DSH_HOME/cordis.patch.yml` (the "home" layer) and `--patch` overlays. The home layer is the only
|
||||
one shared by every profile and surface, so the stable policy lives here.
|
||||
|
||||
| Profile member | Tracked | Role |
|
||||
| --------------------- | ------- | ------------------------------------------ |
|
||||
| `cordis.patch.yml` | yes | the user patch layer the Settings UI edits |
|
||||
| `package.json` | yes | the profile's `dsh.profile.bundles` list |
|
||||
| `pnpm-workspace.yaml` | yes | the profile's pnpm settings |
|
||||
| `cordis.yml` | no | rewritten on every boot |
|
||||
| `node_modules/` | no | written by `dsh plugin --profile web ...` |
|
||||
| Layer | Path | Writer | Tracked |
|
||||
| ------- | ----------------------------------------- | ----------------------------- | ------- |
|
||||
| home | `~/.dsh/cordis.patch.yml` | nix-config; dsh only reads it | yes |
|
||||
| profile | `~/.dsh/profiles/<name>/cordis.patch.yml` | dsh, at runtime | no |
|
||||
|
||||
`web/.gitignore` owns the untracked rows. As with the rules links in the parent module, the
|
||||
trade-off is a config that stays writable in the checkout: a Settings change and a commit are the
|
||||
same edit, and the configuration is shared by every host that deploys the profile.
|
||||
dsh writes the profile patch but only reads the home layer, so linking the home layer is safe while
|
||||
linking the profile patch would put runtime state in the checkout. Declared settings are edited
|
||||
here, not in the Settings UI.
|
||||
|
||||
## Which hosts deploy it
|
||||
|
||||
@@ -31,11 +26,34 @@ host that ships dsh needs one of those two wirings.
|
||||
|
||||
## Default model route
|
||||
|
||||
`web/cordis.patch.yml` pins `agent-default-model` to the API-key route (`deepseek-official`). The
|
||||
`cordis.patch.yml` pins `agent-default-model` to the API-key route (`deepseek-official`). The
|
||||
account route (`deepseek-account`) never falls back to an API key, so a host holding only
|
||||
`DEEPSEEK_API_KEY` fails every freshly created session with `ACCOUNT_SIGN_IN_REQUIRED`. A host that
|
||||
signs in instead can select an account model per session, or override the field in its own
|
||||
`$DSH_HOME/cordis.patch.yml`, which the home layer applies last and which therefore wins.
|
||||
signs in instead can select an account model per session.
|
||||
|
||||
## Compaction
|
||||
|
||||
The web and desktop surfaces give each agent preset its own compaction service, so a top-level
|
||||
`compaction-basic` row here never reaches a session. The effective knobs are the model
|
||||
`contextWindow` and `maxTokens`: the `400000`/`32000` values set here place the first compaction
|
||||
near 300k tokens.
|
||||
|
||||
## Private and local model routes
|
||||
|
||||
Endpoints that must not enter this repository — LAN/self-hosted servers and staging gateways — do
|
||||
not belong in the home layer. Declare them locally as a separate pi-ai instance in the profile
|
||||
patch, which dsh does not deploy from here:
|
||||
|
||||
```yaml
|
||||
# ~/.dsh/profiles/<name>/cordis.patch.yml
|
||||
- insert:
|
||||
- id: llm-pi-ai-private
|
||||
name: "@deepseek-ai/dsh-llm-pi-ai"
|
||||
config:
|
||||
providers: { ... }
|
||||
```
|
||||
|
||||
The private instance coexists with the shared one under its own id.
|
||||
|
||||
## Running it
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Shared dsh policy. Linked to ~/.dsh/cordis.patch.yml and applied as the
|
||||
# $DSH_HOME ("home") layer, after each profile's own patch, so it covers every
|
||||
# profile and surface. dsh only reads it — keep runtime preferences and local
|
||||
# model routes in the profile patch (see README.md).
|
||||
- id: agent-default-model
|
||||
name: "@deepseek-ai/dsh-agent-default-model"
|
||||
config:
|
||||
provider: deepseek-official
|
||||
model: deepseek-flash
|
||||
reasoningEffort: high
|
||||
- id: locale
|
||||
name: "@deepseek-ai/dsh-client-locale"
|
||||
config:
|
||||
preference: zh
|
||||
- id: agent-preset-registry
|
||||
name: "@deepseek-ai/dsh-agent-preset-registry"
|
||||
config:
|
||||
default: standard
|
||||
selectedDefault: ptc
|
||||
- id: llm-deepseek
|
||||
name: "@deepseek-ai/dsh-llm-deepseek-api-key"
|
||||
config:
|
||||
models:
|
||||
- id: deepseek-flash
|
||||
name: DeepSeek-V41-Flash
|
||||
inputModalities:
|
||||
- text
|
||||
- image
|
||||
systemPromptUpdate: in-history
|
||||
toolUpdate: addition-only
|
||||
contextWindow: 400000
|
||||
maxTokens: 32000
|
||||
- id: deepseek-v4-pro
|
||||
name: DeepSeek-V4-Pro
|
||||
description:
|
||||
Stronger agentic coding, knowledge, and difficult reasoning; suited to complex or
|
||||
quality-critical tasks at higher cost.
|
||||
contextWindow: 500000
|
||||
inputModalities:
|
||||
- text
|
||||
- id: llm-deepseek-account
|
||||
name: "@deepseek-ai/dsh-llm-deepseek-account"
|
||||
config:
|
||||
models:
|
||||
- id: deepseek-flash
|
||||
name: DeepSeek-V41-Flash
|
||||
inputModalities:
|
||||
- text
|
||||
- image
|
||||
systemPromptUpdate: in-history
|
||||
toolUpdate: addition-only
|
||||
contextWindow: 400000
|
||||
maxTokens: 32000
|
||||
- id: deepseek-v4-pro
|
||||
name: DeepSeek-V4-Pro
|
||||
description:
|
||||
Stronger agentic coding, knowledge, and difficult reasoning; suited to complex or
|
||||
quality-critical tasks at higher cost.
|
||||
contextWindow: 500000
|
||||
inputModalities:
|
||||
- text
|
||||
- id: agent-loop
|
||||
name: "@deepseek-ai/dsh-agent-loop"
|
||||
config:
|
||||
agents: []
|
||||
maxParallelToolCalls: 8
|
||||
- id: subagent
|
||||
name: "@deepseek-ai/dsh-subagent"
|
||||
config:
|
||||
maxActiveSubagents: 3
|
||||
@@ -3,19 +3,10 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
# dsh persists Settings through the profile's cordis.patch.yml with an atomic
|
||||
# write (a random-suffix sibling, then a rename), and that rename replaces a
|
||||
# symlinked target instead of writing through to its referent. A file-level
|
||||
# link, store or out-of-store, therefore survives only until the first save.
|
||||
# Linking the whole profile directory keeps the write inside the checkout and
|
||||
# leaves the directory symlink intact. Same reasoning as
|
||||
# `home/base/tui/tuios`, one level up; the checkout path is hardcoded like the
|
||||
# repo's other out-of-store links.
|
||||
profileDir = "${config.home.homeDirectory}/nix-config/home/base/tui/agents/dsh/web";
|
||||
# Out-of-store so repo edits apply without a rebuild (see README.md).
|
||||
sharedPatch = "${config.home.homeDirectory}/nix-config/home/base/tui/agents/dsh/cordis.patch.yml";
|
||||
in
|
||||
{
|
||||
# The `web` profile's configuration, owned by hand and by the Settings UI.
|
||||
# Generated members of the profile (cordis.yml, node_modules, lock files) are
|
||||
# gitignored inside that directory rather than tracked.
|
||||
home.file.".dsh/profiles/web".source = config.lib.file.mkOutOfStoreSymlink profileDir;
|
||||
# The shared dsh policy, read as $DSH_HOME/cordis.patch.yml.
|
||||
home.file.".dsh/cordis.patch.yml".source = config.lib.file.mkOutOfStoreSymlink sharedPatch;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
# Regenerated by dsh on every boot (always the empty root entry list).
|
||||
cordis.yml
|
||||
|
||||
# Written by `dsh plugin --profile web ...`.
|
||||
node_modules/
|
||||
pnpm-lock.yaml
|
||||
|
||||
# Transient siblings of the atomic-write and file-lock protocols.
|
||||
*.tmp
|
||||
*.lock
|
||||
@@ -1,77 +0,0 @@
|
||||
# Your patch layer for this dsh profile, applied after every bundle layer:
|
||||
# a top-level YAML array of loader patch entries (id-targeted config
|
||||
# overrides, disables, and insert lists; `!!js` expressions allowed).
|
||||
- id: ui-settings-general
|
||||
name: "@deepseek-ai/dsh-client-ui-settings-general"
|
||||
config:
|
||||
welcomeNoticeVersion: 2026-09-28.1
|
||||
- id: agent-default-model
|
||||
name: "@deepseek-ai/dsh-agent-default-model"
|
||||
config:
|
||||
provider: deepseek-official
|
||||
model: deepseek-flash
|
||||
reasoningEffort: high
|
||||
- id: ui-settings-account
|
||||
name: "@deepseek-ai/dsh-client-ui-settings-account"
|
||||
config:
|
||||
version: 1
|
||||
step: done
|
||||
purpose: development
|
||||
process: standard
|
||||
completion: completed
|
||||
usage: detailed
|
||||
developerTools: true
|
||||
- id: ui-chat
|
||||
name: "@deepseek-ai/dsh-client-ui-chat"
|
||||
config:
|
||||
transcriptView: standard
|
||||
performanceUsage: detailed
|
||||
- id: ui-settings
|
||||
name: "@deepseek-ai/dsh-client-ui-settings"
|
||||
config:
|
||||
enabled: true
|
||||
- id: locale
|
||||
name: "@deepseek-ai/dsh-client-locale"
|
||||
config:
|
||||
preference: zh
|
||||
- id: agent-preset-registry
|
||||
name: "@deepseek-ai/dsh-agent-preset-registry"
|
||||
config:
|
||||
default: standard
|
||||
selectedDefault: ptc
|
||||
- id: llm-deepseek-account
|
||||
name: "@deepseek-ai/dsh-llm-deepseek-account"
|
||||
config:
|
||||
models:
|
||||
- id: deepseek-flash
|
||||
name: DeepSeek-V41-Flash
|
||||
inputModalities:
|
||||
- text
|
||||
- image
|
||||
systemPromptUpdate: in-history
|
||||
toolUpdate: addition-only
|
||||
contextWindow: 1000000
|
||||
- id: deepseek-v4-pro
|
||||
name: DeepSeek-V4-Pro
|
||||
description: Stronger agentic coding, knowledge, and difficult reasoning; suited to complex or quality-critical tasks at higher cost.
|
||||
contextWindow: 500000
|
||||
inputModalities:
|
||||
- text
|
||||
- id: agent-loop
|
||||
name: "@deepseek-ai/dsh-agent-loop"
|
||||
config:
|
||||
agents: []
|
||||
maxParallelToolCalls: 8
|
||||
- id: subagent
|
||||
name: "@deepseek-ai/dsh-subagent"
|
||||
config:
|
||||
maxActiveSubagents: 3
|
||||
- id: compaction-basic
|
||||
name: "@deepseek-ai/dsh-compaction-basic"
|
||||
config:
|
||||
thresholdRatio: 0.35
|
||||
retainRatio: 0.16
|
||||
headroomTokens: 65536
|
||||
compactionRetries: 1
|
||||
maxOverflowRetries: 1
|
||||
auto: true
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"name": "dsh-profile-web",
|
||||
"private": true,
|
||||
"dependencies": {},
|
||||
"dsh": {
|
||||
"profile": {
|
||||
"bundles": [
|
||||
"@deepseek-ai/dsh-base",
|
||||
"@deepseek-ai/dsh-web-app",
|
||||
"@deepseek-ai/dsh-experimental-auto-review"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
packages:
|
||||
- .
|
||||
|
||||
nodeLinker: hoisted
|
||||
autoInstallPeers: false
|
||||
Reference in new issue
Block a user