dsh-plugin-prompt-tool 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +18 -12
  2. package/engine/anchor-match.mjs +117 -0
  3. package/engine/compositions/library/context-gate.yml +2 -2
  4. package/engine/compositions/library/delegation.yml +2 -2
  5. package/engine/compositions/library/str-replace-editor.yml +1 -1
  6. package/engine/compositions/library/tool-bootstrap.yml +2 -2
  7. package/engine/compositions/library/tool-filter.yml +3 -3
  8. package/engine/compositions/source/local/context-gate.yml +2 -2
  9. package/engine/compositions/source/local/tool-bootstrap.yml +3 -3
  10. package/engine/executor.mjs +9 -2
  11. package/engine/interpolate.mjs +66 -0
  12. package/engine/layers.mjs +26 -22
  13. package/engine/schema.mjs +18 -0
  14. package/engine/session-vars.mjs +52 -0
  15. package/engine/shared.mjs +0 -19
  16. package/engine/strategies.mjs +28 -38
  17. package/lib/client.js +471 -162
  18. package/lib/client.js.map +1 -1
  19. package/lib/index.d.mts +35 -9
  20. package/lib/index.mjs +376 -92
  21. package/lib/preset-core.d.mts +2 -2
  22. package/lib/preset-core.mjs +3 -6
  23. package/lib/{prompt-configs-BcP6miu9.d.mts → prompt-configs-B4vH09wx.d.mts} +1 -3
  24. package/lib/{prompt-configs-k7wuZs0C.mjs → prompt-configs-ThS4iXPg.mjs} +85 -33
  25. package/package.json +105 -104
  26. package/preset/anchored/preset.yml +40 -42
  27. package/preset/creative/preset.yml +33 -30
  28. package/preset/creative/skills/cordis-plugin-development/SKILL.md +420 -0
  29. package/preset/creative/skills/editing-cordis-compositions/SKILL.md +165 -0
  30. package/preset/liangshen/preset.yml +24 -18
  31. package/preset/minimal/preset.yml +27 -24
  32. package/preset/ptc/preset.yml +23 -17
  33. package/preset/standard/preset.yml +23 -17
  34. package/templates/20-system-section.yml +5 -0
  35. package/engine/compositions/library/router-first-turn.yml +0 -9
  36. package/engine/compositions/source/local/router-first-turn.yml +0 -5
  37. package/engine/router-first-turn.mjs +0 -85
@@ -0,0 +1,165 @@
1
+ ---
2
+ name: editing-cordis-compositions
3
+ description: Use when creating, changing, or validating a Cordis composition for this harness — writing or editing an agent preset, adding or removing a plugin row, deciding whether something belongs to the host composition or to one session, checking whether a preset you authored actually mounts, or diagnosing a row that mounted but contributed nothing.
4
+ ---
5
+
6
+ # Editing Cordis compositions
7
+
8
+ Every capability in this harness is a plugin row in a `cordis.yml`. There is no separate configuration language: changing what an agent can do means changing which rows are composed for it.
9
+
10
+ ## Off-limits
11
+
12
+ **Never edit, delete, or overwrite a preset that ships with the deployment** — the `agent-presets` directory beside the deployment's own config, which supplies `standard`, `code`, `minimal`, and `cordis`. Never escalate the sandbox to reach it, even when a change there looks quicker. An upgrade overwrites that install, and corrupting `cordis` disables preset authoring itself. Reading a shipped composition is the intended way to start; writing to one is not, and neither is editing the host composition to work around a preset limitation.
13
+
14
+ To change what a shipped preset does, copy it and edit the copy. Locally authored presets under the user root are yours to create, edit, and delete.
15
+
16
+ ## Decide the plane first
17
+
18
+ Two planes, and the choice is not about how "agent-related" something feels — it is about whether the thing must be shared.
19
+
20
+ **Host composition.** The registries themselves (`tools`, `systemPrompt`, `agents`, `agent-loop`, `sessions`), anything crossing sessions (persistence, session query, storage, settings, credentials, telemetry), the sandbox and approval stack, the model route, and the subagent registry with its spawn/fork backends. One instance for the process.
21
+
22
+ **Agent preset.** What one session contributes to those registries: its tool plugins, its persona and prompt sections, its compaction policy. One instance per session, mounted under that session's scope and unwound with it.
23
+
24
+ **A service with a consumer outside the agent plane cannot move into a preset.** `subagents` is the worked example: the registry answers cross-session queries for the host api-proxy, so a per-session copy both starves that host row — it waits forever for a service nothing provides — and collides on the second session, since a provider name registers once. The preset contributes the delegation *tools*; the registry and its backends stay host-side.
25
+
26
+ A preset is a directory holding one `agent.cordis.yml`, optionally beside a `preset.yml` carrying display metadata — `name` and `description` (and, for shipped presets, a roster `order`). Write the metadata too: a preset without it shows up in every picker as its bare directory name.
27
+
28
+ Locally authored presets live one directory per preset under `${DSH_HOME:-$HOME/.dsh}/.agent-presets/`, and the shipped set sits beside the deployment's own config. Use those when the user asks where to look. A deployment can configure other roots, so the path you read or edit comes from `list()` or `resolve()` — which is also where `copy()` reports what it just created.
29
+
30
+ ## The roster service
31
+
32
+ `ctx.agentPresets` owns discovery, authoring, and mounting. You reach it by mounting a temporary plugin that injects it and registers a tool for yourself — `cordis_mount` returns only the mount acknowledgement, so a registered tool is how a service answer gets back to you, and it becomes callable on your next step.
33
+
34
+ Read `cordis_inspect what:"api" name:"agentPresets"` for the current signatures before writing the code. What this skill relies on:
35
+
36
+ - `list()` — every preset with its `id`, `trust` (`system` for the shipped set, `user` for authored ones), and the absolute `path` of its composition file. This is how you locate any composition without knowing the install layout; the directory is that path's parent.
37
+ - `read(id)` — one preset's composition text, without a file tool or a path.
38
+ - `copy(from, id, name?)` — the only authoring write (see below).
39
+ - `standingKeyFor(id)` — mount-validate one preset (see below).
40
+
41
+ ```js
42
+ return {
43
+ name: 'preset-tools',
44
+ inject: ['agentPresets', 'tools'],
45
+ apply(ctx) {
46
+ harness.registerTool(ctx, harness.defineTool({
47
+ name: 'preset_check',
48
+ description: 'Mount-validate one preset by id.',
49
+ parameters: { id: { type: 'string', required: true } },
50
+ output: { schema: { type: 'string' }, render(_a, v) { return [{ type: 'text', text: v }] } },
51
+ async execute(args) {
52
+ try {
53
+ await ctx.agentPresets.standingKeyFor(args.id)
54
+ return 'mounted OK'
55
+ } catch (error) {
56
+ return error.message
57
+ }
58
+ },
59
+ }))
60
+ },
61
+ }
62
+ ```
63
+
64
+ Unmount the plugin with `cordis_unmount` when you are done; it is a probe, not a capability to leave behind.
65
+
66
+ ## Authoring a preset
67
+
68
+ 1. **Start from a copy.** `copy(from, id, name)` copies a whole preset directory into the user root — composition, metadata, skill directories, assets. It validates the id against `[a-z0-9][a-z0-9-]*` (it becomes the directory name, so no leading hyphen), refuses an id any root already supplies, rolls a failed copy back, and rewrites the copy's `preset.yml` to keep the source's description while dropping its name and roster `order`. Prefer it over a shell copy: it needs no sandbox escalation, it lands the copy in whichever root this deployment made writable, and the copy is exactly as loadable as its source. `resolve(id)` then names the file it created — that path, not a guessed one, is what the following edits target. `standard` is the full coding agent and the usual source.
69
+ 2. **Expect the file sandbox on every edit after the copy.** The user preset root lies outside the session workspace, so under the default `workspace-write` policy the first write there is denied. Only writes are: reading any composition by absolute path needs no escalation. Retry that exact command once with `sandbox_permissions` escalation and a short justification — the user sees and approves it. Batch your writes (one heredoc per file) rather than escalating many small commands. `copy()` itself runs host-side and needs none of this; the edits do.
70
+ 3. **Write the copy's `description`** in `preset.yml`, and its `name` if you passed none to `copy()`.
71
+ 4. **Edit `agent.cordis.yml`** row by row, keeping the plane rule and the realm rule.
72
+ 5. **Mount-validate the result**, then hand off to the user for a real session — both under *Verifying a change*.
73
+
74
+ A composition written from scratch usually forgets a group realm or a consumer row; a copy starts loadable.
75
+
76
+ ## The rule that catches people
77
+
78
+ **A row that publishes a service may not sit loose in a preset.** Registering a service without an isolate realm puts it in the process-global realm, so the second session mounting that preset collides with the first. The mount rejects it rather than letting the collision surface later.
79
+
80
+ Whether a row publishes a service is not visible from its name, and package READMEs are absent from an installed deployment. Read it off the live runtime instead: `cordis_inspect what:"services"` lists every service with the fiber that owns it, so a service attributed to a fiber other than the row you are adding is one that row consumes rather than provides. For a row not in your current composition, mount-validate and read the rejection — it names the offending service.
81
+
82
+ When a preset genuinely owns a service, wrap the provider **and every consumer that reaches it** in one group carrying an `isolate` realm. The shipped `standard` composition does this for `workflows`, which nothing outside an agent reads — its `delegation` group, with the delegation tools omitted here:
83
+
84
+ ```yaml
85
+ - id: delegation
86
+ name: cordis:group
87
+ group: true
88
+ isolate:
89
+ workflows: true
90
+ config:
91
+ - id: workflow-worker-thread
92
+ name: '@deepseek-ai/dsh-workflow-worker-thread'
93
+ config:
94
+ provider: spawn
95
+ - id: tool-workflow
96
+ name: '@deepseek-ai/dsh-tool-workflow'
97
+ ```
98
+
99
+ `true` means a realm private to each mounting session. A string label instead joins subtrees into one shared realm; `provide()` still throws on the second registration under that symbol, so a label does not pool instances and is not what a preset needs.
100
+
101
+ A consumer left outside the group resolves the host's registry, which the preset did not populate, and then contributes nothing. Mount-validation catches that as a row that never activated.
102
+
103
+ Realms are for services a preset owns, not for every group. A host capability the preset only consumes must stay outside a realm, or the row cannot resolve it: `tool-bash`, `tool-jobs`, and `tool-goal` publish nothing and sit loose in `standard`, which explains in comments which host instance each one resolves and why a realm would break it. Wrapping a consumer row in a realm of its own is the same error as leaving one outside its provider's realm.
104
+
105
+ ## Verifying a change
106
+
107
+ **`standingKeyFor(id)` is the check.** It composes the preset's plugin subtree for real — the same mount a session start performs, minus the agent — and rejects the four ways a composition fails:
108
+
109
+ - a row whose package does not resolve (`Cannot find package …`);
110
+ - a row whose config is invalid (`invalid config: $.<field> missing required value`);
111
+ - a row that never activated (`N row(s) did not activate: <id>: waiting for <service>`);
112
+ - a service published into the root realm, which arrives as one of two messages. A name the host does not supply lands in the root realm and the mount audit rejects it: `row(s) published process-global service(s) [<name>]; a preset service must sit behind an isolate realm or move to the host composition` — this is the shape a preset's own forgotten realm takes. A name the host already supplies collides before the audit: `service "<name>" has been registered at <Owner>`. Both name the offending service.
113
+
114
+ It returns normally when the composition mounts. Run it as the final check on a finished edit rather than after every line: a successful mount installs a standing generation that lives until the process exits, while a failed one disposes its subtree and leaves nothing behind.
115
+
116
+ **Do not treat the roster's `broken` field as validation.** `list()` reports `broken` from a shape check — the file parses in the loader's YAML dialect and holds named rows — which every failure above passes. It catches a damaged file, not an unusable composition.
117
+
118
+ `cordis_inspect` reports THIS session's composition, so it confirms what a row does in the runtime you are already in, never what your new preset will do.
119
+
120
+ After a clean mount-validation, ask the user to start a session on the new preset and confirm the tool list; the preset decides tool schemas and prompt sections, and only a real session shows the agent that composition produces.
121
+
122
+ `cordis_mount` evaluates JavaScript against the live runtime and disappears on restart. It is for probing, not for shipping a capability: a capability belongs in a composition file.
123
+
124
+ ## Native product subagents
125
+
126
+ Codex and Claude Code providers are independent optional Profile Bundles. Install only the products a Profile needs, then restart the Profile so its Host registers those providers:
127
+
128
+ ```sh
129
+ dsh plugin --profile <name> add @deepseek-ai/dsh-subagent-codex
130
+ dsh plugin --profile <name> add @deepseek-ai/dsh-subagent-claude-code
131
+ dsh plugin --profile <name> remove @deepseek-ai/dsh-subagent-codex
132
+ dsh plugin --profile <name> remove @deepseek-ai/dsh-subagent-claude-code
133
+ ```
134
+
135
+ Each Bundle owns its Host availability; the preset separately grants one Agent its ordinary delegation tool. Never move a product provider into the preset and never add a product-specific settings field. Removing one package withdraws only that provider on the next Profile start.
136
+
137
+ Copy these disabled templates from a shipped full preset and remove `disabled` only for the products the user requested:
138
+
139
+ ```yaml
140
+ - id: tool-subagent-codex
141
+ name: '@deepseek-ai/dsh-tool-subagent'
142
+ disabled: true
143
+ config:
144
+ provider: codex
145
+ toolName: subagent_codex
146
+ backgroundMode: one-shot
147
+ maxDepth: provider-managed
148
+
149
+ - id: tool-subagent-claude-code
150
+ name: '@deepseek-ai/dsh-tool-subagent'
151
+ disabled: true
152
+ config:
153
+ provider: claude-code
154
+ toolName: subagent_claude_code
155
+ backgroundMode: one-shot
156
+ maxDepth: provider-managed
157
+ ```
158
+
159
+ For additional named Codex or Claude Code instances, mount a separate host-plane provider row for each instance with a unique `providerName`, then add a separate preset tool row whose `provider` exactly matches that name and whose `toolName` is also unique. Keep the shipped rows for the default `codex` and `claude-code` names; do not reuse one tool row for several providers or derive either name from permission or environment settings.
160
+
161
+ The two rows are independent. Leaving both disabled preserves the copied preset, enabling one exposes only that product tool, and enabling both exposes both. Production `dsh` does not install either optional provider: before enabling a row, install the matching `@deepseek-ai/dsh-subagent-codex` or `@deepseek-ai/dsh-subagent-claude-code` Bundle in the Profile and restart it. Each Bundle registers its dormant default provider and exclusively uses its pinned package-local platform CLI; additional named instances use extra host-plane rows from the same installed package. A preset cannot provide that host dependency. `backgroundMode: one-shot` keeps omitted or `false` calls in the foreground and lets explicit `run_in_background: true` return a generic Job id. Full presets already carry `tool-jobs`, while the base host carries the job registry; retain both so `job_output`, `job_list`, `job_kill`, cancellation, and completion notices stay available. Installing a Bundle or composing a preset row does not start a product, authenticate an account, select a model, probe credentials, or manage native product settings.
162
+
163
+ ## What not to move into a preset
164
+
165
+ `agent-loop` registers the one agent factory and throws on a second. The registries own the per-session layering and cannot themselves be per-session. Session persistence must stay host-side or the session list fragments. The sandbox, approval, and permission rows are a deliberate boundary: a preset is exactly as privileged as the plugins it names, so letting one relax its own confinement would defeat the confinement.
@@ -10,11 +10,10 @@ meta:
10
10
  name: liangshen
11
11
  description: 梁神模式:首轮 Minimal 双工具锚定 + promoteGate 门控晋升 + PTC 单 run_code 呈现。
12
12
  order: 4
13
- modules:
14
- - context-gate
15
- - persona
16
- - tool-bootstrap
17
- - official-agent-instructions
13
+ modules:
14
+ - context-gate
15
+ - tool-bootstrap
16
+ - official-agent-instructions
18
17
  - persistent-shell
19
18
  - custom-bash
20
19
  - str-replace-editor
@@ -27,13 +26,11 @@ modules:
27
26
  - planning
28
27
  - compaction
29
28
  - delegation
30
- - tool-ask-user
31
- - tool-todo
32
- - tool-web
33
- moduleConfigs:
34
- persona:
35
- text: You are a helpful software engineer assistant.
36
- tool-bootstrap:
29
+ - tool-ask-user
30
+ - tool-todo
31
+ - tool-web
32
+ moduleConfigs:
33
+ tool-bootstrap:
37
34
  bootstrapTools: [bash, str_replace_editor]
38
35
  includeSubagents: true
39
36
  promoteGate: true
@@ -47,10 +44,11 @@ moduleConfigs:
47
44
  context-gate:
48
45
  messageSources: [user, goal]
49
46
  deferredSources: [agent-instructions, skill-catalog]
50
- deferredGraceSteps: 1
51
- instructionHint: true
52
- promptConfigs:
53
- # 晋升后注入 preset.md 内容(custom-fallback 策略:自定义锚定词命中后注入一次)。
47
+ deferredGraceSteps: 1
48
+ instructionHint: true
49
+ params:
50
+ promptConfigs:
51
+ # 晋升后注入 preset.md 内容(custom-fallback 策略:自定义锚定词命中后注入一次)。
54
52
  # phase-1 由 context-gate 的 messageSources 白名单拦截,晋升后随普通注入恢复。
55
53
  - id: prompt-injector
56
54
  name: preset.md 注入
@@ -62,5 +60,13 @@ promptConfigs:
62
60
  role: user
63
61
  position: before-all
64
62
  dedupe: session
65
- promotion: main
66
- sourceKind: plugin
63
+ promotion: main
64
+ sourceKind: plugin
65
+ - id: persona-main
66
+ name: 主会话人设
67
+ layer: system-section
68
+ strategy: static
69
+ order: 0
70
+ params:
71
+ sectionName: deployment:persona
72
+ text: "You are a helpful assistant. Before acting, decide the task type (build or fix) and adopt the matching style: build → hands-on production; fix → inspect-and-plan. Before acting, briefly review what you have already done in this session and continue from where you left off; do not repeat completed steps. Do not run environment checks (echo, whoami, uname, node --version, date) or exhaustive grep/glob scans. Think deeply first, then produce."
@@ -3,27 +3,19 @@ name: 极简模式
3
3
  description: 仅提供持久 bash 与 str_replace_editor 的双工具编码 Agent。
4
4
  version: 1.0.0
5
5
  engineCompat: ">=0.4.2"
6
- modules:
7
- - persona
8
- - official-persistent-shell
9
- - bootstrap-filesystem
10
- - context-gate
11
- - tool-bootstrap
12
- - router-first-turn
13
- - prompt-config-engine
14
- - run-code-env
15
- - custom-bash
16
- - skill-search
17
- moduleConfigs:
18
- persona:
19
- text: You are a helpful software engineer assistant.
20
- complete: true
21
- includeRuntimeContext: false
22
- params:
23
- usePtcMode: true
24
- bootstrapMaxTokens: 0
25
- mainPersona: "You are a helpful assistant. Before acting, decide the task type (build or fix) and adopt the matching style: build → hands-on production; fix → inspect-and-plan. Before acting, briefly review what you have already done in this session and continue from where you left off; do not repeat completed steps. Do not run environment checks (echo, whoami, uname, node --version, date) or exhaustive grep/glob scans. Think deeply first, then produce."
26
- allowKinds: "[skill-invocation, near-anchor, router-guide]"
6
+ modules:
7
+ - official-persistent-shell
8
+ - bootstrap-filesystem
9
+ - context-gate
10
+ - tool-bootstrap
11
+ - prompt-config-engine
12
+ - run-code-env
13
+ - custom-bash
14
+ - skill-search
15
+ params:
16
+ usePtcMode: true
17
+ bootstrapMaxTokens: 0
18
+ allowKinds: "[skill-invocation, near-anchor, router-guide]"
27
19
  # 模型路由与委派 · 主对话与子代理通用(缺省 = 官方默认 / 继承宿主)
28
20
  modelProvider: ""
29
21
  modelName: ""
@@ -36,6 +28,17 @@ params:
36
28
  subagentTemperature: ""
37
29
  subagentMaxTokens: ""
38
30
  subagentPersona: ""
39
- toolFilterAllow: []
40
- toolFilterDeny: []
41
- maxDepth: ""
31
+ toolFilterAllow: []
32
+ toolFilterDeny: []
33
+ maxDepth: ""
34
+ promptConfigs:
35
+ - id: persona-main
36
+ name: 主会话人设
37
+ layer: system-section
38
+ strategy: static
39
+ order: 0
40
+ params:
41
+ sectionName: deployment:persona
42
+ complete: true
43
+ suppressRuntimeContext: true
44
+ text: "You are a helpful software engineer assistant."
@@ -3,9 +3,8 @@ name: PTC 模式
3
3
  description: 具备标准模式的全部能力,并通过 Code Mode SDK 呈现工具,让模型用一个 TypeScript 程序组合多步操作。
4
4
  version: 1.0.0
5
5
  engineCompat: ">=0.4.2"
6
- modules:
7
- - persona
8
- - official-agent-instructions
6
+ modules:
7
+ - official-agent-instructions
9
8
  - official-tool-bash
10
9
  - tool-pwsh
11
10
  - tool-fs
@@ -21,18 +20,16 @@ modules:
21
20
  - tool-todo
22
21
  - tool-web
23
22
  - official-tool-presentation
24
- - context-gate
25
- - tool-bootstrap
26
- - router-first-turn
27
- - prompt-config-engine
23
+ - context-gate
24
+ - tool-bootstrap
25
+ - prompt-config-engine
28
26
  - run-code-env
29
- - custom-bash
30
- - skill-search
31
- params:
32
- usePtcMode: true
33
- bootstrapMaxTokens: 0
34
- mainPersona: "You are a helpful assistant. Before acting, decide the task type (build or fix) and adopt the matching style: build → hands-on production; fix → inspect-and-plan. Before acting, briefly review what you have already done in this session and continue from where you left off; do not repeat completed steps. Do not run environment checks (echo, whoami, uname, node --version, date) or exhaustive grep/glob scans. Think deeply first, then produce."
35
- allowKinds: "[skill-invocation, near-anchor, router-guide]"
27
+ - custom-bash
28
+ - skill-search
29
+ params:
30
+ usePtcMode: true
31
+ bootstrapMaxTokens: 0
32
+ allowKinds: "[skill-invocation, near-anchor, router-guide]"
36
33
  # 模型路由与委派 · 主对话与子代理通用(缺省 = 官方默认 / 继承宿主)
37
34
  modelProvider: ""
38
35
  modelName: ""
@@ -45,6 +42,15 @@ params:
45
42
  subagentTemperature: ""
46
43
  subagentMaxTokens: ""
47
44
  subagentPersona: ""
48
- toolFilterAllow: []
49
- toolFilterDeny: []
50
- maxDepth: ""
45
+ toolFilterAllow: []
46
+ toolFilterDeny: []
47
+ maxDepth: ""
48
+ promptConfigs:
49
+ - id: persona-main
50
+ name: 主会话人设
51
+ layer: system-section
52
+ strategy: static
53
+ order: 0
54
+ params:
55
+ sectionName: deployment:persona
56
+ text: "You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}."
@@ -3,9 +3,8 @@ name: 标准模式
3
3
  description: 功能完整的编码 Agent,支持文件编辑、Shell、文件与网页检索、Skills、计划、目标、子代理和工作流。
4
4
  version: 1.0.0
5
5
  engineCompat: ">=0.4.2"
6
- modules:
7
- - persona
8
- - official-agent-instructions
6
+ modules:
7
+ - official-agent-instructions
9
8
  - official-tool-bash
10
9
  - tool-pwsh
11
10
  - tool-fs
@@ -20,18 +19,16 @@ modules:
20
19
  - tool-ask-user
21
20
  - tool-todo
22
21
  - tool-web
23
- - context-gate
24
- - tool-bootstrap
25
- - router-first-turn
26
- - prompt-config-engine
22
+ - context-gate
23
+ - tool-bootstrap
24
+ - prompt-config-engine
27
25
  - run-code-env
28
- - custom-bash
29
- - skill-search
30
- params:
31
- usePtcMode: true
32
- bootstrapMaxTokens: 0
33
- mainPersona: "You are a helpful assistant. Before acting, decide the task type (build or fix) and adopt the matching style: build → hands-on production; fix → inspect-and-plan. Before acting, briefly review what you have already done in this session and continue from where you left off; do not repeat completed steps. Do not run environment checks (echo, whoami, uname, node --version, date) or exhaustive grep/glob scans. Think deeply first, then produce."
34
- allowKinds: "[skill-invocation, near-anchor, router-guide]"
26
+ - custom-bash
27
+ - skill-search
28
+ params:
29
+ usePtcMode: true
30
+ bootstrapMaxTokens: 0
31
+ allowKinds: "[skill-invocation, near-anchor, router-guide]"
35
32
  # 模型路由与委派 · 主对话与子代理通用(缺省 = 官方默认 / 继承宿主)
36
33
  modelProvider: ""
37
34
  modelName: ""
@@ -44,6 +41,15 @@ params:
44
41
  subagentTemperature: ""
45
42
  subagentMaxTokens: ""
46
43
  subagentPersona: ""
47
- toolFilterAllow: []
48
- toolFilterDeny: []
49
- maxDepth: ""
44
+ toolFilterAllow: []
45
+ toolFilterDeny: []
46
+ maxDepth: ""
47
+ promptConfigs:
48
+ - id: persona-main
49
+ name: 主会话人设
50
+ layer: system-section
51
+ strategy: static
52
+ order: 0
53
+ params:
54
+ sectionName: deployment:persona
55
+ text: "You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}."
@@ -1,5 +1,9 @@
1
1
  # 模板:system-section 静态 system 段(缓存友好,静态内容优先放这里)
2
2
  # order 参考:-100 身份 / 0 persona / 100-199 工具引导。
3
+ # 人设用法:params.sectionName = deployment:persona 时注册为主会话人设段
4
+ # (同名 shadow 全局 persona,模块列表显示「人设」徽标;子代理经 scope 链继承)。
5
+ # - complete: true 独占整个 system prompt(预设内互斥,UI 自动收敛,手写冲突官方 fail loud)
6
+ # - suppressRuntimeContext: true 抑制动态运行时快照(等价官方 includeRuntimeContext:false)
3
7
  id: example-system-section
4
8
  name: 示例:system 静态段
5
9
  layer: system-section
@@ -11,4 +15,5 @@ text: |-
11
15
  variables: {}
12
16
  params:
13
17
  complete: false
18
+ suppressRuntimeContext: false
14
19
  sectionName: ''
@@ -1,9 +0,0 @@
1
- # module: router-first-turn
2
- # source: preset/engine/compositions/source/local/router-first-turn.yml (本地附加,非官方模块)
3
-
4
- - id: router-first-turn
5
- name: ./engine/router-first-turn.mjs
6
- config:
7
- mainPersona: "__MAIN_PERSONA__"
8
- hideSectionPrefixes: ["mnemon:"]
9
- includeSubagents: false
@@ -1,5 +0,0 @@
1
- - id: router-first-turn
2
- name: ./engine/router-first-turn.mjs
3
- config:
4
- mainPersona: "__MAIN_PERSONA__"
5
- hideSectionPrefixes: [mnemon:]
@@ -1,85 +0,0 @@
1
- /**
2
- * router-first-turn — prompt-tool 本地附加件(最优组合)。
3
- *
4
- * 依据 dsh-router-standard 的 router-bootstrap 组装逻辑:
5
- * - 只替换 persona 段,保留计划模式段与其他第三方 section;
6
- * - 首轮隐藏 mnemon:* 自动注入段,晋升后恢复(contexts 由 context-gate 清空/恢复);
7
- * - 按主会话模型自动选择 persona:
8
- * Pro → 官方训练原句;
9
- * Flash → dsh-router-standard 的 Flash 弱路由人设(build/fix 分类 +
10
- * 回顾锚 + 收敛锚 + 反跑题锚 + 先深想再产出);
11
- * - 子代理(委托深度 > 0)默认直接放行完整结果,保证 dsh-mnemon 等插件
12
- * 通过工具白名单要求的 mnemon_* 工具首轮可见;includeSubagents=true 时
13
- * 子代理与主会话一样走首轮 persona 替换与段隐藏。
14
- *
15
- * 工具目录裁剪仍由 tool-bootstrap 负责(首轮 = 真实 Minimal 工具对;晋升后
16
- * 恢复完整目录或切换 PTC),本模块不触碰 tools,避免两层过滤器冲突。
17
- */
18
-
19
- import { createEpochPromotion } from './compaction-epoch.mjs'
20
- import { isDelegated, isFlashModel, PROMOTE_EVENTS } from './shared.mjs'
21
-
22
- /** Cordis 插件名,供 loader 诊断使用。 */
23
- export const name = 'router-first-turn'
24
-
25
- /** 无服务依赖,只监听 system-prompt 组装。 */
26
- export const inject = []
27
-
28
- /** 官方 RL 训练原句(保持与 Minimal 预设逐字节一致)。 */
29
- const RL_PERSONA = 'You are a helpful software engineer assistant.'
30
-
31
- /** 是否为 persona 段:旧 persona 段由本模块替换。 */
32
- function isPersonaSection(section) {
33
- if (section === null || typeof section !== 'object') return false
34
- const name = String(section.name ?? '')
35
- return name === 'persona' || /persona/i.test(name)
36
- }
37
-
38
- /** 首轮需要隐藏的 mnemon 自动注入段(晋升后恢复)。 */
39
- function isMnemonSection(section) {
40
- if (section === null || typeof section !== 'object') return false
41
- return String(section.name ?? '').startsWith('mnemon:')
42
- }
43
-
44
- /**
45
- * 引擎级 router-first-turn:所有内容(含主对话自定义模型人设 mainPersona)都由预设配置参数传入,
46
- * 本文件不含任何模板专属文本。
47
- * config: { mainPersona: string, hideSectionPrefixes?: string[], includeSubagents?: boolean }
48
- */
49
- export function apply(ctx, config) {
50
- const mainPersona = typeof config?.mainPersona === 'string' && config.mainPersona.trim().length > 0
51
- ? config.mainPersona
52
- : undefined
53
- if (mainPersona === undefined) {
54
- throw new TypeError(`${name}: config.mainPersona must be a non-empty string`)
55
- }
56
- const hidePrefixes = Array.isArray(config?.hideSectionPrefixes)
57
- ? config.hideSectionPrefixes.filter((item) => typeof item === 'string' && item.length > 0)
58
- : ['mnemon:']
59
- const includeSubagents = config?.includeSubagents === true
60
-
61
- const promotion = createEpochPromotion(PROMOTE_EVENTS.either, { includeSubagents: false })
62
- ctx.on('session/event', (session, event) => promotion.observe(session, event))
63
-
64
- ctx.on('system-prompt/assemble', async (_assembly, context, next) => {
65
- const assembled = await next()
66
- const agent = context.agent
67
- if (agent === undefined) return assembled
68
- const session = agent.session
69
- if (session === undefined) return assembled
70
-
71
- // 子代理默认不裁剪任何 section/context:它与宿主白名单子代理协作;
72
- // includeSubagents=true 时与主会话同一相位逻辑(首轮替换 + 段隐藏)。
73
- if (isDelegated(session) && !includeSubagents) return assembled
74
-
75
- const persona = isFlashModel(agent.options?.model) ? mainPersona : RL_PERSONA
76
-
77
- const sections = assembled.sections ?? []
78
- const promoted = promotion.status(agent).promoted
79
- const kept = sections.filter((section) =>
80
- !isPersonaSection(section)
81
- && (promoted || !hidePrefixes.some((prefix) => String(section?.name ?? '').startsWith(prefix))))
82
- // contexts 由 context-gate 统一清空/恢复,本模块只替换 persona 与隐藏前缀段。
83
- return { ...assembled, sections: [...kept, { name: 'router-persona', text: persona, order: 0 }] }
84
- })
85
- }