-
Notifications
You must be signed in to change notification settings - Fork 1
Agent Presets
Edge's static single-preset composition vs upstream's dynamic per-session YAML presets.
No dedicated upstream documentation page. Package: @deepseek-ai/dsh-agent-presets. See also #43.
The upstream preset system enables per-session agent composition — different sessions can use different tool sets, system prompts, and model selections:
-
dsh-agent-presets — reads
cordis.ymlpreset files, resolves plugin dependencies, and composes a per-session cordis sub-graph. Supports multiple presets with a default,recompose()for hot-swapping, andauthorableuser-created presets. -
cordis-plugin-loader — dynamic package loading at runtime. Reads YAML, resolves
node_modules, callsimport()to load plugin modules on demand. - dsh-host-plugin-inventory — exposes the current plugin graph to the client via Typert Remote, so the settings page can display which plugins are loaded.
- dsh-client-ui-agent-preset — client UI for preset selection dropdown, composition viewer, and preset management (copy, remove, open document).
Edge does not install dsh-agent-presets, cordis-plugin-loader, or dsh-host-plugin-inventory. Instead, all ~30 plugins are installed statically in EdgeSessionStore.initialize() — every session gets the same composition. The apiproxy returns a fixed preset list:
agentPresets: {
list: () => ok({ presets: [{
id: 'dsh-edge',
trust: 'system',
isDefault: true,
name: 'DSH Edge',
description: 'DeepSeek Harness running in a Cloudflare Durable Object.',
}], authorable: false, hasDocument: false }),
select: (req) => req.payload.agentPreset === 'dsh-edge'
? ok({ agentPreset: 'dsh-edge' })
: fail('agent-preset-not-found')
}dsh-client-ui-agent-preset is included in the 33-plugin client bundle. It renders the preset selector dropdown and composition viewer. With only one preset ('dsh-edge'), the selector shows a single option and the composition viewer displays the hardcoded preset description.
- Agent lifecycle (create, dispose, scope isolation) — handled by AgentRegistry
- Per-session model selection — works within the single preset
- Client preset UI rendering — upstream code, just showing one option
| Capability | Upstream | Edge |
|---|---|---|
| Preset count | Multiple from YAML files | One hardcoded |
| Plugin loading | Dynamic import()
|
Static ctx.plugin() at init |
| Per-session composition | Different preset per session | Same composition for all sessions |
| User-created presets | Authorable via copy + edit YAML | Not available |
Hot-swap (recompose()) |
Change preset on blank session | Not available |
| Plugin inventory UI | Full plugin graph in settings | Empty (no host-plugin-inventory) |
| Client bundle | Runtime module scanning + HMR | Build-time static assembly |
Cloudflare Workers have three hard constraints that prevent upstream's dynamic loading:
-
No filesystem —
cordis-plugin-loaderreadscordis.ymlvianode:fs. Workers have no filesystem for config files. -
No dynamic import() — Workers bundle all code at deploy time. Runtime
import()of npm packages is not supported. - Single JS bundle — the Worker is one JavaScript file. All plugin code must be present in that bundle at deploy.
The static composition is not a temporary workaround — it's a deliberate design choice that trades flexibility for Cloudflare compatibility.
| Aspect | Upstream (Dynamic) | Edge (Static) |
|---|---|---|
| Plugin discovery |
cordis-plugin-loader reads cordis.yml at runtime |
assemble-standalone-web.mjs copies published packages at build time |
| Plugin loading |
import() dynamically loads packages |
All plugins bundled into one Worker JS file |
| Presets | Multiple YAML presets; users create/copy/edit | One hardcoded preset 'dsh-edge'; all sessions identical |
| Server plugins | Loaded per-preset from YAML composition | ~31 ctx.plugin() calls in EdgeSessionStore.initialize()
|
| Client plugins | Boot graph built at runtime; HMR in dev | 33 plugins pre-built; expected-boot-graph.json frozen at review time |
| Plugin inventory |
dsh-host-plugin-inventory projects live state to UI |
Not available — settings page plugin list is empty |
| Hot reload | HMR via dsh-client-hmr
|
Full rebuild + redeploy (no HMR) |
| Adding a plugin | Edit cordis.yml → reload |
Edit session-store.ts + package.json → rebuild → redeploy |
session-store.ts (31 ctx.plugin() calls)
→ standalone/scripts/bundle-standalone.mjs
→ worker/direct/index.js (single Worker bundle)
→ gzip budget check: 921,600 bytes max
upstream published client packages
→ standalone/scripts/assemble-standalone-web.mjs
→ dist/plugins/@deepseek-ai/* (33 plugin directories)
→ expected-boot-graph.json (frozen contract)
→ verify-standalone.mjs (CI gate)
9 upstream client packages are explicitly excluded because they depend on features Edge doesn't have:
-
dsh-client-hmr— HMR (no dev server) -
dsh-cordis-client-runner— dynamic loader client half -
dsh-client-ui-cordis— composition inspector -
dsh-client-ui-message-feedback— message rating (server not installed) -
dsh-client-ui-plan— plan mode (server not installed) -
dsh-client-ui-reference— @mentions (server not installed) -
dsh-client-ui-settings-plugin-inventory— plugin list (no inventory service) -
dsh-client-ui-settings-plugins— plugin settings (no preset editing) -
dsh-session-log-export— session export (not wired)
verify-standalone.mjs runs at CI and checks:
- All
@deepseek-ai/dsh-*dependencies pin the exact upstream version - The assembled boot graph matches
expected-boot-graph.json - The excluded client packages list is up to date
- Worker gzip budget stays under 921,600 bytes
Any drift — an upstream upgrade adding a client plugin, a new exclusion, or a bundle size spike — fails CI before reaching production.
| Metric | Upstream | Edge |
|---|---|---|
| Cold start | Plugin discovery + dynamic import + YAML parse | Zero discovery — all code in the bundle, ctx.plugin() calls are synchronous |
| Bundle size | N/A (loaded from disk) | ~774 KB gzip (budget 900 KB) — all server + client code in one deploy |
| Dev iteration | HMR — sub-second reload | Full rebuild ~15s → wrangler dev auto-restart |
| Plugin change | Edit YAML, no restart | Code change → rebuild → redeploy |
| Component | Category | Edge Code |
|---|---|---|
| dsh-agent-presets | Not installed | Hardcoded single preset in edge-api.ts |
| cordis-plugin-loader | Not installed | Static ctx.plugin() calls |
| dsh-host-plugin-inventory | Not installed | Settings page shows no plugin list |
| dsh-client-ui-agent-preset | Reuse | In client bundle, shows single preset |
Evaluate config-driven plugin activation. (#43) All plugin code is already in the bundle. A DO KV config could toggle which plugins are activated per-session without rebuilding — still static code, but dynamic composition. This would enable multiple "presets" as JSON configs rather than YAML files, sidestepping the dynamic loading constraint entirely.
- Home
- Architecture
- Core & Scope
- Session & Persistence
- Model & Context
-
Execution & Tools
- Tools
- Bash
- Subprocess 🚫
- PTY Session 🚫
- Background Jobs 🚫
- Filesystem
- LSP Navigation 🚫
- Code Runtime 🚫
-
Web Access
⚠️ -
Skills
⚠️ - Workflow 🚫
- Subagent 🚫
-
Policy & Interaction
- Goal
- Approval 🚫
- Permission Presets 🚫
-
Sandbox
⚠️ - Plan Mode 🚫
- User Interaction 🚫
- Commands 🚫
- Schedule 🚫
- Message Feedback 🚫
- Platform & Access
- Development
- 首页
- 架构
- 核心与作用域
- 会话与持久化
- 模型与上下文
- 执行与工具
- 策略与交互
- 平台与接入
- 开发