dsh-paoding 0.2.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.
- package/LICENSE +21 -0
- package/README.md +95 -0
- package/README_en.md +95 -0
- package/bin/dsh-paoding.mjs +12 -0
- package/cordis.patch.yml +6 -0
- package/docs/architecture.md +292 -0
- package/docs/architecture_en.md +363 -0
- package/docs/configuration.md +551 -0
- package/docs/configuration_en.md +560 -0
- package/docs/images/1.png +0 -0
- package/docs/images/2.png +0 -0
- package/docs/images/3.png +0 -0
- package/docs/images/4.png +0 -0
- package/docs/images/5.png +0 -0
- package/docs/images/6.png +0 -0
- package/docs/installation.md +364 -0
- package/docs/installation_en.md +367 -0
- package/docs/orchestration.md +254 -0
- package/docs/orchestration_en.md +255 -0
- package/install.sh +31 -0
- package/package.json +29 -0
- package/plugins/paoding-config-ui/api-core.mjs +100 -0
- package/plugins/paoding-config-ui/index.mjs +327 -0
- package/plugins/paoding-config-ui/lib/base.css +615 -0
- package/plugins/paoding-config-ui/lib/client.js +1154 -0
- package/plugins/paoding-config-ui/package.json +23 -0
- package/plugins/paoding-config-ui/runtime-inventory.mjs +212 -0
- package/presets/orchestrator/agent.cordis.yml +323 -0
- package/presets/orchestrator/preset.yml +6 -0
- package/presets/orchestrator/restrict.mjs +191 -0
- package/tools/install.mjs +24 -0
- package/tools/lib/alloc.mjs +138 -0
- package/tools/lib/cli.mjs +522 -0
- package/tools/lib/compose.mjs +647 -0
- package/tools/lib/config.mjs +297 -0
- package/tools/lib/host.mjs +288 -0
- package/tools/lib/skills.mjs +146 -0
- package/tools/lib/spans.mjs +188 -0
- package/tools/lib/state.mjs +328 -0
- package/tools/lib/util.mjs +26 -0
- package/tools/lib/wizard.mjs +516 -0
- package/tools/lib/yaml.mjs +266 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "paoding-config-ui",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.mjs",
|
|
7
|
+
"description": "庖丁 (dsh-paoding) 可视化配置器 — DSH Web 设置页集成插件(settings.section 分区 + /api/paoding 路由)",
|
|
8
|
+
"dsh": {
|
|
9
|
+
"client": {
|
|
10
|
+
"platform": "web",
|
|
11
|
+
"inject": [
|
|
12
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
13
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
14
|
+
"@deepseek-ai/dsh-client-connection"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"exports": {
|
|
19
|
+
".": "./index.mjs",
|
|
20
|
+
"./client": "./lib/client.js",
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 运行时事实采集 —— DSH Web 插件 (plugins/paoding-config-ui)
|
|
3
|
+
*
|
|
4
|
+
* “运行时优先”的通用插件/工具检测基础:在 Web 运行时内直接读取 DSH
|
|
5
|
+
* 宿主自带的实时注册表,识别任何以 bundle/插件形态加载且启用的插件
|
|
6
|
+
* (@hyzyn/dsh-codegraph、dsh-mnemon、magic-memory 等),不再依赖
|
|
7
|
+
* cordis.patch.yml 条目 + 硬编码白名单。已有文件扫描路径保持原样,作为
|
|
8
|
+
* CLI / 无运行时场景的兜底,二者按需叠加。
|
|
9
|
+
*
|
|
10
|
+
* 数据来源(均已查实):
|
|
11
|
+
* - dsh-host-plugin-inventory:ctx.pluginInventory.list() 返回
|
|
12
|
+
* { entries: [{ entryId, moduleName, enabled, fiberPhase }] },
|
|
13
|
+
* entries 为 Loader 中全部非 group 条目(含未启用的,enabled 由
|
|
14
|
+
* loader disabled 推导;fiberPhase:active=正在运行,null=无 fiber,
|
|
15
|
+
* 另有 pending/loading/failed/unloading)。
|
|
16
|
+
* - dsh-tools:名为 'tools' 的 cordis Service(ctx.tools /
|
|
17
|
+
* ctx.get('tools')),公开方法 register/get/restrict/guard/schemas;
|
|
18
|
+
* MCP 工具由 dsh-mcp-client 以 `mcp__<server>__<tool>` 公开名注册,
|
|
19
|
+
* 故 schemas()/entries() 等能枚举出形如 mcp__tavily__tavily_search 的
|
|
20
|
+
* 全名,与 tools/install.mjs 的 inventory 命名约定一致。
|
|
21
|
+
*
|
|
22
|
+
* 约定:本模块只负责“取数”,任何一步失败都不抛出——错误记入 error 字符串
|
|
23
|
+
* (多条用 '; ' 连接、整体截断),返回可用的部分结果;列表带截断上限防爆。
|
|
24
|
+
* 服务端只透传插件条目的原始字段(enabled/fiberPhase 原样保留),仅剔除
|
|
25
|
+
* 显然未启用/未运行(enabled===false 或 fiberPhase 非 'active')的条目,
|
|
26
|
+
* 其余判断留给 UI。
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const MAX_PLUGIN_ENTRIES = 200
|
|
30
|
+
const MAX_TOOL_NAMES = 2000
|
|
31
|
+
const MAX_ERROR_LEN = 500
|
|
32
|
+
|
|
33
|
+
/** 把名字记入结果(字符串校验、去重、截断都在这里做)。 */
|
|
34
|
+
function pushName(name, out, seen) {
|
|
35
|
+
if (typeof name !== 'string' || name === '') return
|
|
36
|
+
if (seen.has(name) || out.length >= MAX_TOOL_NAMES) return
|
|
37
|
+
seen.add(name)
|
|
38
|
+
out.push(name)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 归一化 [key, value] 工具对:优先取 value 对象自带的 name,否则取 key。 */
|
|
42
|
+
function pushPair(key, def, out, seen) {
|
|
43
|
+
if (def && typeof def === 'object' && typeof def.name === 'string') pushName(def.name, out, seen)
|
|
44
|
+
else pushName(key, out, seen)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 把一次枚举调用返回的结果收集成字符串工具名数组。
|
|
49
|
+
* 兼容 Map / 任意迭代器 / 数组三种形态,元素可为字符串、[name, def] 对
|
|
50
|
+
* 或带 name 字段的对象(如 schemas() 返回的 { name, description, ... })。
|
|
51
|
+
*/
|
|
52
|
+
function collectToolNames(value, out, seen) {
|
|
53
|
+
if (value == null) return
|
|
54
|
+
if (typeof value !== 'object' && typeof value !== 'string') return
|
|
55
|
+
if (typeof value[Symbol.iterator] !== 'function') return
|
|
56
|
+
for (const item of value) {
|
|
57
|
+
if (typeof item === 'string') {
|
|
58
|
+
pushName(item, out, seen)
|
|
59
|
+
} else if (Array.isArray(item)) {
|
|
60
|
+
// [name, def] 对(Map.entries() 的产物)
|
|
61
|
+
if (item.length > 0) pushPair(item[0], item[1], out, seen)
|
|
62
|
+
} else if (item && typeof item === 'object') {
|
|
63
|
+
if (typeof item.name === 'string') {
|
|
64
|
+
pushName(item.name, out, seen)
|
|
65
|
+
} else {
|
|
66
|
+
// 兜底:{ [key]: def } 形态的对象,按 key/def.name 处理
|
|
67
|
+
for (const [k, v] of Object.entries(item)) pushPair(k, v, out, seen)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 防御式取服务:cordis 的 ctx[key] 受 inject 护栏约束(未注入直接抛
|
|
75
|
+
* "cannot get property ... without inject"),而 ctx.reflect.get(name)
|
|
76
|
+
* 是官方文档明确的“无需 inject 即可读取”入口(ctx.get 为其 mixin 别名,
|
|
77
|
+
* strict=false 连 provider 未处于 running 态也允许读)。按
|
|
78
|
+
* reflect.get → ctx.get → ctx[key] 三级降级,全部 try/catch,永不抛出。
|
|
79
|
+
*/
|
|
80
|
+
function getService(ctx, key) {
|
|
81
|
+
if (ctx == null) return undefined
|
|
82
|
+
const attempts = [
|
|
83
|
+
() => ctx.reflect?.get?.(key, false),
|
|
84
|
+
() => ctx.get?.(key),
|
|
85
|
+
() => ctx[key],
|
|
86
|
+
]
|
|
87
|
+
for (const fn of attempts) {
|
|
88
|
+
try {
|
|
89
|
+
const v = fn()
|
|
90
|
+
if (v !== undefined && v !== null) return v
|
|
91
|
+
} catch { /* 该路径不可用:尝试下一级 */ }
|
|
92
|
+
}
|
|
93
|
+
return undefined
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** 收集一个对象的可调用方法名(沿原型链,去重,限量)。 */
|
|
97
|
+
function collectMethodNames(svc) {
|
|
98
|
+
const methods = []
|
|
99
|
+
for (let proto = Object.getPrototypeOf(svc); proto && proto !== Object.prototype; proto = Object.getPrototypeOf(proto)) {
|
|
100
|
+
for (const m of Object.getOwnPropertyNames(proto)) {
|
|
101
|
+
if (m !== 'constructor' && typeof svc[m] === 'function' && !methods.includes(m)) methods.push(m)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return methods
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 读取运行时插件清单。返回 { entries, ok }:ok 表示成功拿到 list() 结果
|
|
109
|
+
* (空清单也算成功,区别于服务不可用)。
|
|
110
|
+
*/
|
|
111
|
+
function collectPluginEntries(ctx, errors) {
|
|
112
|
+
const pi = getService(ctx, 'pluginInventory')
|
|
113
|
+
if (pi == null || typeof pi.list !== 'function') return { entries: [], ok: false }
|
|
114
|
+
try {
|
|
115
|
+
const result = pi.list()
|
|
116
|
+
// list() 官方返回 { entries: [...] };兼容直接返回数组的形态
|
|
117
|
+
const raw = Array.isArray(result) ? result : Array.isArray(result?.entries) ? result.entries : null
|
|
118
|
+
if (raw === null) {
|
|
119
|
+
errors.push('pluginInventory.list() returned an unexpected shape')
|
|
120
|
+
return { entries: [], ok: false }
|
|
121
|
+
}
|
|
122
|
+
const entries = []
|
|
123
|
+
for (const e of raw.slice(0, MAX_PLUGIN_ENTRIES)) {
|
|
124
|
+
// 只透传四个已知字段(保持 JSON 安全);剔除未启用 / 未运行(fiberPhase
|
|
125
|
+
// 缺失时按“可接受”处理,兼容字段更老的宿主)的条目,其余留给 UI 判断
|
|
126
|
+
if (e == null || typeof e !== 'object') continue
|
|
127
|
+
if (e.enabled === false) continue
|
|
128
|
+
if (e.fiberPhase != null && e.fiberPhase !== 'active') continue
|
|
129
|
+
entries.push({
|
|
130
|
+
entryId: typeof e.entryId === 'string' ? e.entryId : undefined,
|
|
131
|
+
moduleName: typeof e.moduleName === 'string' ? e.moduleName : undefined,
|
|
132
|
+
enabled: e.enabled,
|
|
133
|
+
fiberPhase: e.fiberPhase ?? null,
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
return { entries, ok: true }
|
|
137
|
+
} catch (err) {
|
|
138
|
+
errors.push(`pluginInventory.list() threw: ${String(err?.message ?? err)}`)
|
|
139
|
+
return { entries: [], ok: false }
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* 读取 tools 服务注册的工具公开名。按下列顺序尝试,任意一步抛错都跳过:
|
|
145
|
+
* 1) t.entries() 若可调用(Map / 迭代器 / 数组 归一化);
|
|
146
|
+
* 2) t.schemas() 若可调用(返回 [{ name, description, ... }],全局视图 =
|
|
147
|
+
* 全部已注册工具,含 mcp__<server>__<tool>);
|
|
148
|
+
* 3) 在方法名里找含 entries/list/schemas/keys 的可调用方法逐个 try 调用
|
|
149
|
+
* (不硬猜 presentAs/visible 这类语义方法);
|
|
150
|
+
* 4) 全部失败返回空数组。返回 { names, ok }。
|
|
151
|
+
*/
|
|
152
|
+
function readRegisteredToolNames(ctx, errors) {
|
|
153
|
+
const out = []
|
|
154
|
+
const seen = new Set()
|
|
155
|
+
const t = getService(ctx, 'tools')
|
|
156
|
+
if (t == null) return { names: [], ok: false }
|
|
157
|
+
const tried = new Set()
|
|
158
|
+
const attempt = (method, source) => {
|
|
159
|
+
if (typeof t[method] !== 'function' || tried.has(method)) return false
|
|
160
|
+
tried.add(method)
|
|
161
|
+
try {
|
|
162
|
+
const result = t[method]()
|
|
163
|
+
// 拿到可迭代结果即视为“服务可用”(即使为空清单);无结果 / 抛错都跳过
|
|
164
|
+
if (result != null && typeof result[Symbol.iterator] === 'function') {
|
|
165
|
+
collectToolNames(result, out, seen)
|
|
166
|
+
return true
|
|
167
|
+
}
|
|
168
|
+
} catch (err) {
|
|
169
|
+
errors.push(`${source} threw: ${String(err?.message ?? err)}`)
|
|
170
|
+
}
|
|
171
|
+
return false
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 1) entries() —— cordis Service 层最直观的枚举口(部分版本存在)
|
|
175
|
+
// 2) schemas() —— dsh-tools 公开 API 里能枚举“全部已注册工具名”的口
|
|
176
|
+
let acquired = attempt('entries', 'tools.entries()')
|
|
177
|
+
if (!acquired) acquired = attempt('schemas', 'tools.schemas()')
|
|
178
|
+
|
|
179
|
+
// 3) 兜底:在方法列表里找名字含 entries/list/schemas/keys 的函数逐个尝试
|
|
180
|
+
if (!acquired) {
|
|
181
|
+
const hint = /entries|list|schemas|keys/
|
|
182
|
+
for (const m of collectMethodNames(t)) {
|
|
183
|
+
if (!hint.test(m)) continue
|
|
184
|
+
if (attempt(m, `tools.${m}()`)) { acquired = true; break }
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return { names: out, ok: acquired }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 采集运行时事实(供 collectState 合并 / UI 展示)。
|
|
192
|
+
* 永不抛出:任何异常都会落到 error 里,返回部分结果。
|
|
193
|
+
*/
|
|
194
|
+
export function collectRuntimeFacts(ctx) {
|
|
195
|
+
const errors = []
|
|
196
|
+
const plugin = collectPluginEntries(ctx, errors)
|
|
197
|
+
const tools = readRegisteredToolNames(ctx, errors)
|
|
198
|
+
|
|
199
|
+
// ok 语义:pluginInventory 与 tools 至少一个服务真正可用即为成功;
|
|
200
|
+
// 两个都拿不到才整体失败(UI 据此提示“已回退文件扫描”)。
|
|
201
|
+
const ok = plugin.ok || tools.ok
|
|
202
|
+
if (!ok) errors.unshift('tools service unavailable (pluginInventory/tools both missing)')
|
|
203
|
+
|
|
204
|
+
let error = errors.join('; ')
|
|
205
|
+
if (error.length > MAX_ERROR_LEN) error = error.slice(0, MAX_ERROR_LEN) + '…'
|
|
206
|
+
return {
|
|
207
|
+
ok,
|
|
208
|
+
...(error !== '' ? { error } : {}),
|
|
209
|
+
pluginEntries: plugin.entries,
|
|
210
|
+
toolNames: tools.names,
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# orchestrator (编排模式) agent composition
|
|
2
|
+
#
|
|
3
|
+
# 基于 builtin `standard` preset 全量组合(基础工具注册在 preset 层,不在 global
|
|
4
|
+
# 层——这是本 preset 此前运行时 tools.restrict() 报 "unknown global tools" 的根因),
|
|
5
|
+
# 叠加编排层:
|
|
6
|
+
# · persona → 编排人设(主 agent 分工指引)
|
|
7
|
+
# · orchestrator-restrict → restrict.mjs 在 system-prompt/assemble 瀑布上把
|
|
8
|
+
# 主 agent 的工具面裁剪为「编排 + 内部搜索」白名单;子 agent(origin:
|
|
9
|
+
# 'subagent')放行,由各自 toolFilter 决定工具面
|
|
10
|
+
# · delegation-* → 3 个角色委派工具(dsh-tool-subagent),子 agent 创建时
|
|
11
|
+
# 以 per-child tools.restrict() 只保留各自 allow 的工具
|
|
12
|
+
#
|
|
13
|
+
# 工具税(每请求估算):主 agent 全量 ~16.2k → 白名单后 ~5.5k(含 3 个委派工具);
|
|
14
|
+
# search_external ~3.0k / design ~3.2k / implement ~3.7k,仅实际委派时发生。
|
|
15
|
+
|
|
16
|
+
# ── identity ────────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
# 编排人设:{{model}}/{{cwd}} 由 agent 的 route/workspace 解析(同 standard)。
|
|
19
|
+
- id: persona
|
|
20
|
+
name: '@deepseek-ai/dsh-persona'
|
|
21
|
+
config:
|
|
22
|
+
text: |-
|
|
23
|
+
You are the orchestrator agent powered by the {{model}} model. Your working directory is {{cwd}}.
|
|
24
|
+
|
|
25
|
+
Decompose the task, delegate to role agents, integrate results.
|
|
26
|
+
- Internal file questions (finding code, references, reading files): solve yourself with glob/grep/read/codegraph — never delegate them.
|
|
27
|
+
- External research: delegate to search_external.
|
|
28
|
+
- UI/design work: delegate to design.
|
|
29
|
+
- Code implementation: delegate to implement.
|
|
30
|
+
Keep your own context lean; integrate only summaries. Use todo_write to plan, and ask_user_question only for user-owned choices.
|
|
31
|
+
|
|
32
|
+
Delegation failure handling (SOP):
|
|
33
|
+
- A delegated run reports failure either as a thrown tool error (foreground)
|
|
34
|
+
or as a failed background job; both carry the child's partial output and
|
|
35
|
+
a stop reason (error / max-tokens / refusal / aborted / completed-but-poor).
|
|
36
|
+
- Diagnose by stop reason, never retry blindly:
|
|
37
|
+
· error (runtime/tool-level) → re-delegate ONCE as a fresh task (not a continuation);
|
|
38
|
+
if the failure cites a missing tool or permission, pick a different role or do it yourself.
|
|
39
|
+
· max-tokens → split the task into smaller steps and re-delegate, or ask the child to
|
|
40
|
+
output incrementally.
|
|
41
|
+
· refusal → do NOT retry the same task: adjust the task's scope or framing, switch roles,
|
|
42
|
+
or handle it yourself (a refusal is a policy decision, not a transient error).
|
|
43
|
+
· aborted → only re-delegate when the cancellation was accidental.
|
|
44
|
+
· completed but poor output → re-delegate with concrete missing points, or send_message
|
|
45
|
+
to ask a continuable child to finish the gaps.
|
|
46
|
+
- If the same task fails twice, stop retrying: report to the user what failed, why,
|
|
47
|
+
and what you already tried. Never loop a failing delegation.
|
|
48
|
+
- When re-delegating (fresh task or continuation), always include your integration
|
|
49
|
+
summary of the previous attempt (what was done, what failed, what to pick up from),
|
|
50
|
+
so the child never re-derives it from a cold context.
|
|
51
|
+
|
|
52
|
+
- id: agent-instructions
|
|
53
|
+
name: '@deepseek-ai/dsh-agent-instructions'
|
|
54
|
+
config:
|
|
55
|
+
maxBytes: 65536
|
|
56
|
+
|
|
57
|
+
# ── 主 agent 工具面白名单 ───────────────────────────────────────────────────
|
|
58
|
+
# 过滤主 agent 的 assembly.tools 为编排 + 内部搜索面;子 agent 放行。
|
|
59
|
+
- id: orchestrator-restrict
|
|
60
|
+
name: ./restrict.mjs
|
|
61
|
+
|
|
62
|
+
# ── shell ───────────────────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
- id: tool-bash
|
|
65
|
+
name: '@deepseek-ai/dsh-tool-bash'
|
|
66
|
+
disabled: !!js process.platform === 'win32'
|
|
67
|
+
|
|
68
|
+
- id: tool-pwsh
|
|
69
|
+
name: '@deepseek-ai/dsh-tool-pwsh'
|
|
70
|
+
disabled: !!js process.platform !== 'win32'
|
|
71
|
+
|
|
72
|
+
# ── filesystem ──────────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
- id: tool-fs
|
|
75
|
+
name: '@deepseek-ai/dsh-tool-fs'
|
|
76
|
+
|
|
77
|
+
- id: tool-fs-search
|
|
78
|
+
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
79
|
+
config:
|
|
80
|
+
sampleOverCapGlobResults: false
|
|
81
|
+
|
|
82
|
+
# ── background jobs ────────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
- id: tool-jobs
|
|
85
|
+
name: '@deepseek-ai/dsh-tool-jobs'
|
|
86
|
+
|
|
87
|
+
# ── skills ──────────────────────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
- id: skill-filesystem
|
|
90
|
+
name: '@deepseek-ai/dsh-skill-filesystem'
|
|
91
|
+
|
|
92
|
+
- id: tool-skill
|
|
93
|
+
name: '@deepseek-ai/dsh-tool-skill'
|
|
94
|
+
|
|
95
|
+
# ── goals ───────────────────────────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
- id: tool-goal
|
|
98
|
+
name: '@deepseek-ai/dsh-tool-goal'
|
|
99
|
+
|
|
100
|
+
# ── plan mode ───────────────────────────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
- id: planning
|
|
103
|
+
name: cordis:group
|
|
104
|
+
group: true
|
|
105
|
+
isolate:
|
|
106
|
+
planMode: true
|
|
107
|
+
config:
|
|
108
|
+
- id: plan-mode
|
|
109
|
+
name: '@deepseek-ai/dsh-plan-mode'
|
|
110
|
+
config:
|
|
111
|
+
section: |
|
|
112
|
+
You are in plan mode. Stay in plan mode until exit_plan_mode succeeds or the user switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
|
|
113
|
+
|
|
114
|
+
Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
|
|
115
|
+
|
|
116
|
+
The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
|
|
117
|
+
|
|
118
|
+
Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
|
|
119
|
+
|
|
120
|
+
Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
|
|
121
|
+
|
|
122
|
+
When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
|
|
123
|
+
|
|
124
|
+
# ── compaction ──────────────────────────────────────────────────────────────
|
|
125
|
+
# 触发线(实测校准,2026-08-20):
|
|
126
|
+
# 默认 thresholdRatio 0.8(窗口 256K → 209,715 tokens 才压缩),长会话
|
|
127
|
+
# 裸涨到 ~137K-142K 稳态且从未触发——这是「每请求 token 是 opencode 近两倍」
|
|
128
|
+
# 的真凶(opencode 同项目 73 会话平均 68K,且全部发生过压缩)。
|
|
129
|
+
# 0.45 → 117,965 tokens 触发,保留 16% 尾部(≈42K)+ 摘要 checkpoint,
|
|
130
|
+
# 稳态平均回落到 ~80K 量级。保留尾部由 retainRatio 控制,不会丢最近上下文。
|
|
131
|
+
# 如需更激进可改 0.35(≈92K 触发,平均 ~67K,逼近 opencode);0.45 是
|
|
132
|
+
# 「省 token 与不频繁摘要的平衡点」(压缩会调用一次 LLM 摘要,复用前缀缓存)。
|
|
133
|
+
|
|
134
|
+
- id: compaction
|
|
135
|
+
name: cordis:group
|
|
136
|
+
group: true
|
|
137
|
+
isolate:
|
|
138
|
+
compaction: true
|
|
139
|
+
toolResultPruner: true
|
|
140
|
+
config:
|
|
141
|
+
- id: compaction-basic
|
|
142
|
+
name: '@deepseek-ai/dsh-compaction-basic'
|
|
143
|
+
config:
|
|
144
|
+
thresholdRatio: 0.45
|
|
145
|
+
|
|
146
|
+
- id: command-compact
|
|
147
|
+
name: '@deepseek-ai/dsh-command-compact'
|
|
148
|
+
|
|
149
|
+
- id: tool-result-pruner
|
|
150
|
+
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
|
151
|
+
config:
|
|
152
|
+
thresholdChars: 8192
|
|
153
|
+
headChars: 4096
|
|
154
|
+
tailChars: 1024
|
|
155
|
+
|
|
156
|
+
# ── delegation and workflows ────────────────────────────────────────────────
|
|
157
|
+
|
|
158
|
+
- id: delegation
|
|
159
|
+
name: cordis:group
|
|
160
|
+
group: true
|
|
161
|
+
isolate:
|
|
162
|
+
workflowEngine: true
|
|
163
|
+
config:
|
|
164
|
+
- id: tool-subagent-control
|
|
165
|
+
name: '@deepseek-ai/dsh-tool-subagent-control'
|
|
166
|
+
|
|
167
|
+
- id: tool-subagent-list-agents
|
|
168
|
+
name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
|
169
|
+
|
|
170
|
+
- id: tool-subagent
|
|
171
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
172
|
+
config:
|
|
173
|
+
provider: spawn
|
|
174
|
+
toolName: subagent
|
|
175
|
+
backgroundMode: continuable
|
|
176
|
+
|
|
177
|
+
- id: tool-subagent-fork
|
|
178
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
179
|
+
config:
|
|
180
|
+
provider: fork
|
|
181
|
+
toolName: subagent_fork
|
|
182
|
+
backgroundMode: continuable
|
|
183
|
+
|
|
184
|
+
- id: workflow-worker-thread
|
|
185
|
+
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
|
186
|
+
config:
|
|
187
|
+
provider: spawn
|
|
188
|
+
|
|
189
|
+
- id: tool-workflow
|
|
190
|
+
name: '@deepseek-ai/dsh-tool-workflow'
|
|
191
|
+
|
|
192
|
+
- id: tool-ralph
|
|
193
|
+
name: '@deepseek-ai/dsh-tool-ralph'
|
|
194
|
+
config:
|
|
195
|
+
subagentProvider: spawn
|
|
196
|
+
maxRounds: 64
|
|
197
|
+
|
|
198
|
+
# ── 角色委派工具 ─────────────────────────────────────────────
|
|
199
|
+
# 每个实例把一个 spawn provider 绑定到一个 toolName;主 agent 调哪个工具,
|
|
200
|
+
# 即选择该子 agent 的工具面。子 agent 创建时 tools.restrict(toolFilter)
|
|
201
|
+
# 校验 allow 名字必须存在于其可见注册面 —— 本组合(standard 全量 + host
|
|
202
|
+
# patch 的 mcp/memory)就是这些名字的来源,缺一行都会报 unknown tools。
|
|
203
|
+
|
|
204
|
+
# search_external:外部调研(冷路径,用一次才付一次 ~3.0k)
|
|
205
|
+
- id: delegation-search-external
|
|
206
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
207
|
+
config:
|
|
208
|
+
provider: spawn
|
|
209
|
+
toolName: search_external
|
|
210
|
+
persona: |-
|
|
211
|
+
You are the external-research agent. Your job is web research only — use web_search and the tavily tools; you never modify files. Search the web, extract key facts, and return a concise structured research summary (findings, sources, open questions).
|
|
212
|
+
On tool failure, do not retry a denied operation: report the failure compactly — what you completed, the exact error, which tool/permission you lack, and your suggested next step — so the orchestrator can re-delegate or adjust.
|
|
213
|
+
toolFilter:
|
|
214
|
+
allow:
|
|
215
|
+
- web_search
|
|
216
|
+
- mcp__tavily__tavily_search
|
|
217
|
+
- mcp__tavily__tavily_crawl
|
|
218
|
+
- mcp__tavily__tavily_extract
|
|
219
|
+
- mcp__tavily__tavily_map
|
|
220
|
+
- mcp__tavily__tavily_research
|
|
221
|
+
- glob
|
|
222
|
+
- grep
|
|
223
|
+
- read
|
|
224
|
+
- ask_user_question
|
|
225
|
+
|
|
226
|
+
# design:设计(读参考 + 设计技能 + 出 spec,不写最终代码)~3.2k
|
|
227
|
+
- id: delegation-design
|
|
228
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
229
|
+
config:
|
|
230
|
+
provider: spawn
|
|
231
|
+
toolName: design
|
|
232
|
+
persona: |-
|
|
233
|
+
You are the design agent. You produce UI/UX designs, wireframes, and frontend specs — and may load design skills (frontend-design, html-ppt) via the skill tool. Read reference material first, then deliver a concrete design spec. You do not implement final code.
|
|
234
|
+
On tool failure, do not retry a denied operation: report the failure compactly — what you completed, the exact error, which tool/permission you lack, and your suggested next step — so the orchestrator can re-delegate or adjust.
|
|
235
|
+
toolFilter:
|
|
236
|
+
allow:
|
|
237
|
+
- read
|
|
238
|
+
- read_image
|
|
239
|
+
- glob
|
|
240
|
+
- grep
|
|
241
|
+
- bash
|
|
242
|
+
- skill
|
|
243
|
+
- write
|
|
244
|
+
- edit
|
|
245
|
+
- ask_user_question
|
|
246
|
+
- todo_write
|
|
247
|
+
- job_output
|
|
248
|
+
- job_list
|
|
249
|
+
- job_kill
|
|
250
|
+
|
|
251
|
+
# implement:实现(读上下文 → 外科手术式修改 → 验证)~3.7k
|
|
252
|
+
- id: delegation-implement
|
|
253
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
254
|
+
config:
|
|
255
|
+
provider: spawn
|
|
256
|
+
toolName: implement
|
|
257
|
+
persona: |-
|
|
258
|
+
You are the implementation agent. You write and edit code: read surrounding context first, make surgical changes, then verify (build/test/grep). Report what you changed and how you verified. You do not redesign architecture.
|
|
259
|
+
On tool failure, do not retry a denied operation: report the failure compactly — what you completed, the exact error, which tool/permission you lack, and your suggested next step — so the orchestrator can re-delegate or adjust.
|
|
260
|
+
toolFilter:
|
|
261
|
+
allow:
|
|
262
|
+
- read
|
|
263
|
+
- write
|
|
264
|
+
- edit
|
|
265
|
+
- glob
|
|
266
|
+
- grep
|
|
267
|
+
- bash
|
|
268
|
+
- skill
|
|
269
|
+
- web_search
|
|
270
|
+
- ask_user_question
|
|
271
|
+
- todo_write
|
|
272
|
+
- job_output
|
|
273
|
+
- job_list
|
|
274
|
+
- job_kill
|
|
275
|
+
- get_goal
|
|
276
|
+
- create_goal
|
|
277
|
+
- update_goal
|
|
278
|
+
|
|
279
|
+
# search_internal_deep:全仓深度探索(冷路径,把大 dump 隔离出主上下文)
|
|
280
|
+
# 主 agent 遇到「超大仓库全量探索」(全仓 grep dump / 大文件通读 / 跨目录
|
|
281
|
+
# 符号追踪)时委派到这里:子 agent 内部消化大输出,只回浓缩摘要。
|
|
282
|
+
# 与 search_external 的区别:search_external 只联网不碰仓库;这个只碰仓库
|
|
283
|
+
# 不联网。工具面 = 内部搜索全量(read 无 limit 限制由它自己权衡),
|
|
284
|
+
# 不含 write/edit —— 它只读不改。
|
|
285
|
+
- id: delegation-search-internal-deep
|
|
286
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
287
|
+
config:
|
|
288
|
+
provider: spawn
|
|
289
|
+
toolName: search_internal_deep
|
|
290
|
+
persona: |-
|
|
291
|
+
You are the internal deep-search agent. Your job is repository exploration only — you never modify files and you never use the network. Handle exactly the tasks the orchestrator can't afford in its own context: whole-repo grep dumps, full-file reads beyond a page, cross-directory symbol/definition tracking. Search thoroughly, then return a CONCISE structured summary: what you searched, key files with line numbers, definitions/symbols found, and the takeaway the orchestrator needs to decide next. Never echo large dumps back — condense aggressively; the orchestrator re-delegates or reads specific ranges itself if it needs details.
|
|
292
|
+
On tool failure, do not retry a denied operation: report the failure compactly — what you completed, the exact error, which tool/permission you lack, and your suggested next step — so the orchestrator can re-delegate or adjust.
|
|
293
|
+
# 2026-09-02: memory_search / mcp__codegraph__codegraph_explore 已从 allow 移除——
|
|
294
|
+
# 两者对应插件(magic-memory / codegraph MCP)停用时不在子 agent 注册面,
|
|
295
|
+
# tools.restrict() 会以 unknown tools 拒绝创建该角色;重开插件时按需加回。
|
|
296
|
+
toolFilter:
|
|
297
|
+
allow:
|
|
298
|
+
- glob
|
|
299
|
+
- grep
|
|
300
|
+
- read
|
|
301
|
+
- read_image
|
|
302
|
+
- bash
|
|
303
|
+
- ask_user_question
|
|
304
|
+
- todo_write
|
|
305
|
+
- job_output
|
|
306
|
+
- job_list
|
|
307
|
+
- job_kill
|
|
308
|
+
|
|
309
|
+
# ── remaining model-facing rows ─────────────────────────────────────────────
|
|
310
|
+
|
|
311
|
+
- id: tool-ask-user
|
|
312
|
+
name: '@deepseek-ai/dsh-tool-ask-user'
|
|
313
|
+
|
|
314
|
+
- id: tool-todo
|
|
315
|
+
name: '@deepseek-ai/dsh-tool-todo'
|
|
316
|
+
config:
|
|
317
|
+
allowParallelInProgress: true
|
|
318
|
+
|
|
319
|
+
- id: tool-web
|
|
320
|
+
name: '@deepseek-ai/dsh-tool-web'
|
|
321
|
+
config:
|
|
322
|
+
fetch: false
|
|
323
|
+
searchTimeoutMs: 60000
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
name: 编排模式 (Orchestrator)
|
|
2
|
+
description: 按角色分工的编排架构——主 agent 只做编排与内部搜索(glob/grep/read/codegraph),
|
|
3
|
+
通过 search_external / design / implement 三个委派工具把联网调研、设计、实现分别交给
|
|
4
|
+
各自只加载必要工具的子 agent;主 agent 不加载任何外部搜索、写文件或技能工具,
|
|
5
|
+
每请求工具税从 ~16.2k tokens 降到 ~5.5k。主 agent 技能目录注入亦归零(实测 ≈1.3k tokens/轮)。
|
|
6
|
+
order: 5
|