dsh-subagent-profile 0.3.2 → 0.3.3
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/README.md +38 -29
- package/README.zh.md +38 -29
- package/index.mjs +188 -62
- package/lib/client.js +1240 -47
- package/lib/core/catalog-cache.mjs +45 -7
- package/lib/core/catalog.mjs +6 -6
- package/lib/core/cost-guard.mjs +71 -44
- package/lib/core/decision-trace.mjs +433 -0
- package/lib/core/delegation.mjs +106 -48
- package/lib/core/dispatch-gates.mjs +146 -0
- package/lib/core/dispatch-guard.mjs +150 -0
- package/lib/core/dispatch-schema.mjs +98 -14
- package/lib/core/dispatch-tool.mjs +208 -199
- package/lib/core/escape.mjs +130 -0
- package/lib/core/evolution-ledger.mjs +289 -0
- package/lib/core/evolution-summary.mjs +432 -0
- package/lib/core/http-routes.mjs +155 -40
- package/lib/core/intersection.mjs +6 -9
- package/lib/core/presets-sync.mjs +256 -136
- package/lib/core/profile-provider.mjs +41 -39
- package/lib/core/profiles-store.mjs +103 -76
- package/lib/core/pure.mjs +110 -66
- package/lib/core/shims.mjs +56 -75
- package/lib/core/whitelist.mjs +23 -17
- package/package.json +2 -3
- package/presets/orchestrator/agent.cordis.yml +243 -271
- package/presets/orchestrator/NOTICE +0 -3
package/lib/core/shims.mjs
CHANGED
|
@@ -1,51 +1,42 @@
|
|
|
1
|
-
// lib/core/shims.mjs — facade
|
|
2
|
-
//
|
|
3
|
-
// top-level-scattered import surface. Two failure classes:
|
|
1
|
+
// lib/core/shims.mjs — facade。唯一 import index.mjs 依赖的 @deepseek-ai
|
|
2
|
+
// 符号的模块,收敛此前散落在顶层的 import 面。两类失败:
|
|
4
3
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// wants for the delegation-depth safety gates: no weakened reimplementation is
|
|
11
|
-
// ever substituted, so a child can never be dispatched past MAX_DEPTH.
|
|
4
|
+
// 守卫型(fail-loud,无回退):assertSubagentMaxDepth / resolveChildDepth
|
|
5
|
+
// 是**静态** import 并再导出。宿主 rc 里改名/移除会让本模块——进而
|
|
6
|
+
// index.mjs——在加载时以 ESM 链接错误失败("The requested module ... does
|
|
7
|
+
// not provide an export named '...'")。这正是委派深度安全闸想要的加载时
|
|
8
|
+
// 隔离:绝不替换为弱化实现,子 Agent 永远不可能派发超过 MAX_DEPTH。
|
|
12
9
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// captureDelegatedPolicyOverrides / resolveChildAgentOptions / defineTool
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// local functionally-equivalent (or safe-degraded) implementation is used.
|
|
10
|
+
// 函数映射型(fail-soft + warn):foldConsumedWork / finalAssistantOutput /
|
|
11
|
+
// createUserMessage / appendDelegatedPolicyOverrides /
|
|
12
|
+
// captureDelegatedPolicyOverrides / resolveChildAgentOptions / defineTool
|
|
13
|
+
// 用 try/catch 包裹的动态顶层 await import 加载。导入失败(或命名导出被
|
|
14
|
+
// 改名/移除)时模块仍能加载,发出 console.warn(模块顶层没有 ctx,没有
|
|
15
|
+
// logger),并使用本地功能等价(或安全降级)实现。
|
|
20
16
|
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// also verifies the value is a function before accepting it.
|
|
17
|
+
// 动态 import 的包能加载但命名导出被改名/移除时,解构结果为 `undefined`
|
|
18
|
+
// 且**不抛**,所以 loadSoft 还校验值是函数后才接受。
|
|
24
19
|
|
|
25
20
|
import { randomUUID } from 'node:crypto';
|
|
26
21
|
import { createRequire } from 'node:module';
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
// error BEFORE apply can run, which is the isolation this class exists for.
|
|
22
|
+
// 守卫型:静态、fail-loud、无回退。只保留这两个静态 @deepseek-ai import;
|
|
23
|
+
// 导出缺失会在 apply 能运行之前就以明确错误中止模块加载——这正是本类存在的隔离。
|
|
30
24
|
import { assertSubagentMaxDepth, resolveChildDepth } from '@deepseek-ai/dsh-subagent';
|
|
31
25
|
import { toStopReason } from './pure.mjs';
|
|
32
26
|
|
|
33
|
-
// warn
|
|
34
|
-
//
|
|
27
|
+
// warn:模块顶层没有 ctx / logger,降级用 console.warn。
|
|
28
|
+
// 前缀让来源在共享宿主日志中可辨认。
|
|
35
29
|
function warn(...parts) {
|
|
36
30
|
console.warn('[dsh-subagent-profile]', ...parts);
|
|
37
31
|
}
|
|
38
32
|
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
// override the failure route (e.g. stub it to throw, or return a module object
|
|
44
|
-
// missing the symbol). It is exported as a seam for that purpose.
|
|
33
|
+
// 加载一个函数映射型 `@deepseek-ai` 符号,包或命名导出不可用时返回本地回退。
|
|
34
|
+
// `warnMessage` 携带可操作的用户面向文案。`importer` 是可注入加载器(缺省为
|
|
35
|
+
// 动态 `import`——见 DYNAMIC_IMPORT),测试 / 未来加载器可覆盖失败路径
|
|
36
|
+
// (如 stub 成抛错,或返回缺该符号的模块对象)。为此导出为接缝。
|
|
45
37
|
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
// the dynamic import expression.
|
|
38
|
+
// 注意:`import` 是关键字,不能作值引用(`importer = import` 是 SyntaxError),
|
|
39
|
+
// 故缺省值是动态 import 表达式的薄包装。
|
|
49
40
|
const DYNAMIC_IMPORT = (specifier) => import(specifier);
|
|
50
41
|
async function loadSoft(pkg, symbol, fallback, warnMessage, importer = DYNAMIC_IMPORT) {
|
|
51
42
|
try {
|
|
@@ -60,11 +51,9 @@ async function loadSoft(pkg, symbol, fallback, warnMessage, importer = DYNAMIC_I
|
|
|
60
51
|
}
|
|
61
52
|
}
|
|
62
53
|
|
|
63
|
-
// ---
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
// can exercise the degraded path even though the junction packages resolve
|
|
67
|
-
// successfully here.
|
|
54
|
+
// --- 本地回退(import-free、duck-typed、功能等价)------------------------------
|
|
55
|
+
// 每个都是保留官方助手可观察契约的最小本地实现;经 `__fallbacks` 导出,测试在
|
|
56
|
+
// junction 包解析成功时也能走降级路径。
|
|
68
57
|
|
|
69
58
|
// foldConsumedWork: **近似、非等价**——readResult 只读 `.end`(终止 turn/end 事件)来
|
|
70
59
|
// 推导 stopReason。shipped fold 是精密的 stepped/claimed 状态机;本降级实现取最后一个
|
|
@@ -80,8 +69,8 @@ function foldConsumedWorkFallback(events) {
|
|
|
80
69
|
return { ...(end === undefined ? {} : { end }), droppedUnrun: false };
|
|
81
70
|
}
|
|
82
71
|
|
|
83
|
-
// finalAssistantOutput
|
|
84
|
-
//
|
|
72
|
+
// finalAssistantOutput:相同的 fold 规则——最后一个非空 assistant/message,
|
|
73
|
+
// 否则累加的 text-delta 分片,再否则 undefined。
|
|
85
74
|
function finalAssistantOutputFallback(events) {
|
|
86
75
|
let message;
|
|
87
76
|
const partial = [];
|
|
@@ -99,11 +88,10 @@ function finalAssistantOutputFallback(events) {
|
|
|
99
88
|
return text.length > 0 ? [{ type: 'text', text }] : undefined;
|
|
100
89
|
}
|
|
101
90
|
|
|
102
|
-
// createUserMessage
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
// the shipped deepFreeze immutability; treat it as a plain message object.
|
|
91
|
+
// createUserMessage:构造 followup 驱动需要的 user 角色消息。官方助手用品牌化
|
|
92
|
+
// MessageId + deepFreeze;回退提供相同可观察形状(role/content/id/source)加
|
|
93
|
+
// 新鲜随机 id。注意:返回对象是**可变**的(无 deepFreeze)——消费方不得依赖
|
|
94
|
+
// 官方 deepFreeze 的不可变性;把它当普通消息对象。
|
|
107
95
|
function createUserMessageFallback(input) {
|
|
108
96
|
return {
|
|
109
97
|
...input,
|
|
@@ -112,10 +100,9 @@ function createUserMessageFallback(input) {
|
|
|
112
100
|
};
|
|
113
101
|
}
|
|
114
102
|
|
|
115
|
-
// appendDelegatedPolicyOverrides
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
// faithfully to keep the child's own log reconstructable and the pin visible.
|
|
103
|
+
// appendDelegatedPolicyOverrides:委派策略写进子会话日志供重建。这也是安全
|
|
104
|
+
// 相关的「approval: never」钉,绝不能是 no-op——忠实复现追加,保持子会话自身
|
|
105
|
+
// 日志可重建、钉可见。
|
|
119
106
|
function appendDelegatedPolicyOverridesFallback(childSession, overrides) {
|
|
120
107
|
const o = overrides || {};
|
|
121
108
|
if (o.sandboxMode !== undefined) {
|
|
@@ -126,9 +113,8 @@ function appendDelegatedPolicyOverridesFallback(childSession, overrides) {
|
|
|
126
113
|
}
|
|
127
114
|
}
|
|
128
115
|
|
|
129
|
-
// captureDelegatedPolicyOverrides
|
|
130
|
-
//
|
|
131
|
-
// approval service. Optional chaining keeps a mock parent (tests) working.
|
|
116
|
+
// captureDelegatedPolicyOverrides:父的显式沙箱覆盖(无则 undefined)加父有
|
|
117
|
+
// approval 服务时的审批钉 'never'。可选链让 mock 父(测试)正常工作。
|
|
132
118
|
function captureDelegatedPolicyOverridesFallback(parent) {
|
|
133
119
|
return {
|
|
134
120
|
sandboxMode: parent.ctx?.get?.('sandboxPolicy')?.overrideOf?.(parent.session),
|
|
@@ -136,10 +122,9 @@ function captureDelegatedPolicyOverridesFallback(parent) {
|
|
|
136
122
|
};
|
|
137
123
|
}
|
|
138
124
|
|
|
139
|
-
// resolveChildAgentOptions
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
// break delegation routing.
|
|
125
|
+
// resolveChildAgentOptions:合并父路由(provider/model/maxTokens,存在才带)
|
|
126
|
+
// 与 per-child 覆盖,并盖上子自身的深度。必须保持子配置语义——no-op 会静默
|
|
127
|
+
// 破坏委派路由。
|
|
143
128
|
function resolveChildAgentOptionsFallback(parent, requested, childDepth) {
|
|
144
129
|
const parentProvider = parent.options?.provider;
|
|
145
130
|
const parentModel = parent.options?.model;
|
|
@@ -153,19 +138,16 @@ function resolveChildAgentOptionsFallback(parent, requested, childDepth) {
|
|
|
153
138
|
};
|
|
154
139
|
}
|
|
155
140
|
|
|
156
|
-
// defineTool
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
// of a cryptic module-not-found at import time(加载不崩溃,调用点才报错)。
|
|
141
|
+
// defineTool:没有 dsh-tools 就没有 dispatch 工具。在用途点 fail-loud 并给出
|
|
142
|
+
// 清晰可操作的文案——模块仍然加载,apply 期间调用它才暴露确切的缺失依赖
|
|
143
|
+
// (加载不崩溃,调用点才报错)。
|
|
160
144
|
function defineToolFallback() {
|
|
161
145
|
throw new Error('dsh-tools 缺失:dispatch 工具不可用');
|
|
162
146
|
}
|
|
163
147
|
|
|
164
|
-
// ---
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
// keep the real functions when the junction resolves, and the fallbacks when a
|
|
168
|
-
// host rc renamed/removed a symbol.
|
|
148
|
+
// --- 接线函数映射型符号(模块顶层 await)---------------------------------------
|
|
149
|
+
// 七个加载相互独立,并行(Promise.all)以削减模块加载延迟;每个失败仍降级到
|
|
150
|
+
// 本地回退。junction 解析成功时保留真函数,宿主 rc 改名/移除符号时用回退。
|
|
169
151
|
const [foldConsumedWork, finalAssistantOutput, createUserMessage, appendDelegatedPolicyOverrides, captureDelegatedPolicyOverrides, resolveChildAgentOptions, defineTool] = await Promise.all([
|
|
170
152
|
loadSoft('@deepseek-ai/dsh-agent', 'foldConsumedWork', foldConsumedWorkFallback, 'dsh-agent 的 foldConsumedWork 不可用,结果裁切使用本地降级实现'),
|
|
171
153
|
loadSoft('@deepseek-ai/dsh-subagent', 'finalAssistantOutput', finalAssistantOutputFallback, 'dsh-subagent 的 finalAssistantOutput 不可用,子结果选取使用本地降级实现'),
|
|
@@ -176,9 +158,9 @@ const [foldConsumedWork, finalAssistantOutput, createUserMessage, appendDelegate
|
|
|
176
158
|
loadSoft('@deepseek-ai/dsh-tools', 'defineTool', defineToolFallback, 'dsh-tools 缺失:dispatch 工具不可用'),
|
|
177
159
|
]);
|
|
178
160
|
|
|
179
|
-
// readResult
|
|
180
|
-
//
|
|
181
|
-
//
|
|
161
|
+
// readResult:官方形状。终止 turn 的原因来自 foldConsumedWork;选取的输出来自
|
|
162
|
+
// finalAssistantOutput(最后一个非空 assistant/message,否则拼接的 text-delta
|
|
163
|
+
// 分片,再否则 undefined -> [])。
|
|
182
164
|
function readResult(child, boundary, cancelled) {
|
|
183
165
|
const own = child.session.events.slice(boundary);
|
|
184
166
|
const end = foldConsumedWork(own).end;
|
|
@@ -187,7 +169,7 @@ function readResult(child, boundary, cancelled) {
|
|
|
187
169
|
return { output: finalAssistantOutput(own) ?? [], stopReason };
|
|
188
170
|
}
|
|
189
171
|
|
|
190
|
-
// ---
|
|
172
|
+
// --- 版本探测(纯探测)--------------------------------------------------------
|
|
191
173
|
// 读取 @deepseek-ai 三包(subagent/agent/llm)的 package.json version,与
|
|
192
174
|
// peerDependencies 范围(>=PEER_MIN <PEER_MAX)比对后产出中文 warnings。纯探测:
|
|
193
175
|
// 只读 manifest、不 import 新符号、不触发副作用;每包独立 try/catch,失败记
|
|
@@ -270,9 +252,8 @@ export function detectVersions(reader = readPackageVersion) {
|
|
|
270
252
|
return { versions, warnings };
|
|
271
253
|
}
|
|
272
254
|
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
// fail-soft path without deleting node_modules).
|
|
255
|
+
// 仅供测试访问本地降级实现(包导入在这里可解析,真函数胜出;`__fallbacks`
|
|
256
|
+
// 让测试无需删 node_modules 即可走 fail-soft 路径)。
|
|
276
257
|
export const __fallbacks = {
|
|
277
258
|
foldConsumedWork: foldConsumedWorkFallback,
|
|
278
259
|
finalAssistantOutput: finalAssistantOutputFallback,
|
|
@@ -286,7 +267,7 @@ export const __fallbacks = {
|
|
|
286
267
|
export {
|
|
287
268
|
assertSubagentMaxDepth,
|
|
288
269
|
resolveChildDepth,
|
|
289
|
-
// ----
|
|
270
|
+
// ---- 测试接缝 / 可注入加载器(见 loadSoft 文档)----
|
|
290
271
|
loadSoft,
|
|
291
272
|
foldConsumedWork,
|
|
292
273
|
finalAssistantOutput,
|
|
@@ -296,6 +277,6 @@ export {
|
|
|
296
277
|
resolveChildAgentOptions,
|
|
297
278
|
defineTool,
|
|
298
279
|
readResult,
|
|
299
|
-
// ----
|
|
280
|
+
// ---- 版本探测接缝(见 detectVersions 文档)----
|
|
300
281
|
readPackageVersion,
|
|
301
282
|
};
|
package/lib/core/whitelist.mjs
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// import-free (no @deepseek-ai dependency).
|
|
1
|
+
// lib/core/whitelist.mjs — 目标预设白名单:从运行时名册推导,不硬编码——
|
|
2
|
+
// agentPresets 存在时取 system-trust 预设,否则用官方回退名单。从 index.mjs
|
|
3
|
+
// 逐字移出;import-free(无 @deepseek-ai 依赖)。
|
|
5
4
|
//
|
|
6
|
-
//
|
|
7
|
-
// `agentCtx.get('agentPresets')
|
|
8
|
-
// `resolveWhitelist(parent.ctx.get('agentPresets'))
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// unchanged. FALLBACK_WHITELIST is exported for the tests.
|
|
12
|
-
|
|
13
|
-
// The target-preset whitelist is derived from the runtime roster, not
|
|
14
|
-
// hard-coded: system-trust presets when agentPresets exists, else the
|
|
15
|
-
// shipped fallback names.
|
|
5
|
+
// 注入说明:原 apply 闭包版本自带 `agentCtx` 并自己读
|
|
6
|
+
// `agentCtx.get('agentPresets')`。调用方现在注入服务——
|
|
7
|
+
// `resolveWhitelist(parent.ctx.get('agentPresets'))`——使模块不依赖 apply 闭包
|
|
8
|
+
// 状态。`parent.ctx.get('agentPresets')` 得到完全相同的结果(服务或 undefined),
|
|
9
|
+
// 回退语义不变。FALLBACK_WHITELIST 导出供测试用。
|
|
16
10
|
export const FALLBACK_WHITELIST = ['standard', 'code', 'minimal'];
|
|
17
11
|
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
// 逃生舱叠加(可选):escapeSet 是非 system-trust 预设的显式放行集(Set 或数组,
|
|
13
|
+
// 由调用方在开关打开时传入)。只叠加——base 集原样保留、去重;逃生舱绝不替代或
|
|
14
|
+
// 缩减 base 集,也不升级 base 成员的语义(逃生舱成员仍属「非 system 放行」)。
|
|
15
|
+
// escapeSet 缺省/为空时零叠加(行为与旧单参调用完全一致)。
|
|
16
|
+
function withEscapeSet(base, escapeSet) {
|
|
17
|
+
if (escapeSet === undefined) return base;
|
|
18
|
+
const extras = [...escapeSet].filter((id) => typeof id === 'string' && id !== '');
|
|
19
|
+
if (extras.length === 0) return base;
|
|
20
|
+
return [...new Set([...base, ...extras])];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function resolveWhitelist(agentPresets, escapeSet) {
|
|
24
|
+
if (agentPresets === undefined) return withEscapeSet(FALLBACK_WHITELIST, escapeSet);
|
|
20
25
|
const presets = await agentPresets.list();
|
|
21
|
-
|
|
26
|
+
const base = (presets ?? []).filter((preset) => preset && preset.trust === 'system').map((preset) => preset.id);
|
|
27
|
+
return withEscapeSet(base, escapeSet);
|
|
22
28
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-subagent-profile",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Dispatch one-shot subtasks to derived subagents with per-task overrides (preset/model/provider/reasoningEffort/persona/tool whitelist), a runtime-derived cost guard, a subagent-profiles service, observability metadata, and a web-GUI settings page plus a dispatch tool-call card.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"lib",
|
|
19
19
|
"cordis.patch.yml",
|
|
20
20
|
"presets",
|
|
21
|
-
"docs",
|
|
21
|
+
"docs/screenshots",
|
|
22
22
|
"README.md",
|
|
23
23
|
"README.zh.md"
|
|
24
24
|
],
|
|
@@ -74,7 +74,6 @@
|
|
|
74
74
|
],
|
|
75
75
|
"license": "MIT",
|
|
76
76
|
"scripts": {
|
|
77
|
-
"release": "node scripts/release.mjs",
|
|
78
77
|
"test": "node --test \"test/**/*.test.mjs\"",
|
|
79
78
|
"test:bare": "node --test test/pure.test.mjs test/input-schema.test.mjs test/catalog-integrity.test.mjs",
|
|
80
79
|
"preflight": "node scripts/preflight.mjs",
|