@dsh-edge/dsh-edge-agent 0.0.0-stage → 0.1.2

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 (238) hide show
  1. package/CHANGELOG.md +158 -0
  2. package/LICENSE +21 -0
  3. package/README.md +181 -2
  4. package/config/edge.example.json +179 -0
  5. package/config/privacy-policy.json +202 -0
  6. package/cordis.desktop-safe.patch.yml +129 -0
  7. package/cordis.patch.yml +382 -0
  8. package/cordis.yml +374 -0
  9. package/lib/attestation.d.ts +2 -0
  10. package/lib/attestation.d.ts.map +1 -0
  11. package/lib/attestation.js +2 -0
  12. package/lib/audit-log.d.ts +2 -0
  13. package/lib/audit-log.d.ts.map +1 -0
  14. package/lib/audit-log.js +2 -0
  15. package/lib/client.js +87 -0
  16. package/lib/cloud-llm-adapter.d.ts +2 -0
  17. package/lib/cloud-llm-adapter.d.ts.map +1 -0
  18. package/lib/cloud-llm-adapter.js +2 -0
  19. package/lib/dsh-adapter/attestation.d.ts +42 -0
  20. package/lib/dsh-adapter/attestation.d.ts.map +1 -0
  21. package/lib/dsh-adapter/attestation.js +40 -0
  22. package/lib/dsh-adapter/audit-log.d.ts +139 -0
  23. package/lib/dsh-adapter/audit-log.d.ts.map +1 -0
  24. package/lib/dsh-adapter/audit-log.js +376 -0
  25. package/lib/dsh-adapter/cloud-egress.d.ts +181 -0
  26. package/lib/dsh-adapter/cloud-egress.d.ts.map +1 -0
  27. package/lib/dsh-adapter/cloud-egress.js +257 -0
  28. package/lib/dsh-adapter/cloud-llm-adapter.d.ts +416 -0
  29. package/lib/dsh-adapter/cloud-llm-adapter.d.ts.map +1 -0
  30. package/lib/dsh-adapter/cloud-llm-adapter.js +1472 -0
  31. package/lib/dsh-adapter/contract.d.ts +80 -0
  32. package/lib/dsh-adapter/contract.d.ts.map +1 -0
  33. package/lib/dsh-adapter/contract.js +194 -0
  34. package/lib/dsh-adapter/desktop-cookie-janitor.d.ts +214 -0
  35. package/lib/dsh-adapter/desktop-cookie-janitor.d.ts.map +1 -0
  36. package/lib/dsh-adapter/desktop-cookie-janitor.js +409 -0
  37. package/lib/dsh-adapter/dsh-edge-agent.d.ts +48 -0
  38. package/lib/dsh-adapter/dsh-edge-agent.d.ts.map +1 -0
  39. package/lib/dsh-adapter/dsh-edge-agent.js +64 -0
  40. package/lib/dsh-adapter/edge-config.d.ts +484 -0
  41. package/lib/dsh-adapter/edge-config.d.ts.map +1 -0
  42. package/lib/dsh-adapter/edge-config.js +898 -0
  43. package/lib/dsh-adapter/edge-context-view.d.ts +184 -0
  44. package/lib/dsh-adapter/edge-context-view.d.ts.map +1 -0
  45. package/lib/dsh-adapter/edge-context-view.js +483 -0
  46. package/lib/dsh-adapter/effective-model.d.ts +85 -0
  47. package/lib/dsh-adapter/effective-model.d.ts.map +1 -0
  48. package/lib/dsh-adapter/effective-model.js +171 -0
  49. package/lib/dsh-adapter/etscli-shell-guard.d.ts +244 -0
  50. package/lib/dsh-adapter/etscli-shell-guard.d.ts.map +1 -0
  51. package/lib/dsh-adapter/etscli-shell-guard.js +420 -0
  52. package/lib/dsh-adapter/etscli-tools.d.ts +112 -0
  53. package/lib/dsh-adapter/etscli-tools.d.ts.map +1 -0
  54. package/lib/dsh-adapter/etscli-tools.js +393 -0
  55. package/lib/dsh-adapter/file-logger.d.ts +294 -0
  56. package/lib/dsh-adapter/file-logger.d.ts.map +1 -0
  57. package/lib/dsh-adapter/file-logger.js +564 -0
  58. package/lib/dsh-adapter/function-call-external.d.ts +357 -0
  59. package/lib/dsh-adapter/function-call-external.d.ts.map +1 -0
  60. package/lib/dsh-adapter/function-call-external.js +1005 -0
  61. package/lib/dsh-adapter/host-egress-guard.d.ts +161 -0
  62. package/lib/dsh-adapter/host-egress-guard.d.ts.map +1 -0
  63. package/lib/dsh-adapter/host-egress-guard.js +213 -0
  64. package/lib/dsh-adapter/host-llm-trace.d.ts +198 -0
  65. package/lib/dsh-adapter/host-llm-trace.d.ts.map +1 -0
  66. package/lib/dsh-adapter/host-llm-trace.js +344 -0
  67. package/lib/dsh-adapter/http-api-routes.d.ts +61 -0
  68. package/lib/dsh-adapter/http-api-routes.d.ts.map +1 -0
  69. package/lib/dsh-adapter/http-api-routes.js +79 -0
  70. package/lib/dsh-adapter/http-api-sessions.d.ts +105 -0
  71. package/lib/dsh-adapter/http-api-sessions.d.ts.map +1 -0
  72. package/lib/dsh-adapter/http-api-sessions.js +173 -0
  73. package/lib/dsh-adapter/http-api.d.ts +221 -0
  74. package/lib/dsh-adapter/http-api.d.ts.map +1 -0
  75. package/lib/dsh-adapter/http-api.js +1811 -0
  76. package/lib/dsh-adapter/index.d.ts +62 -0
  77. package/lib/dsh-adapter/index.d.ts.map +1 -0
  78. package/lib/dsh-adapter/index.js +97 -0
  79. package/lib/dsh-adapter/input-guard-messages.d.ts +56 -0
  80. package/lib/dsh-adapter/input-guard-messages.d.ts.map +1 -0
  81. package/lib/dsh-adapter/input-guard-messages.js +136 -0
  82. package/lib/dsh-adapter/input-guard.d.ts +508 -0
  83. package/lib/dsh-adapter/input-guard.d.ts.map +1 -0
  84. package/lib/dsh-adapter/input-guard.js +2174 -0
  85. package/lib/dsh-adapter/intent-prompts.d.ts +77 -0
  86. package/lib/dsh-adapter/intent-prompts.d.ts.map +1 -0
  87. package/lib/dsh-adapter/intent-prompts.js +97 -0
  88. package/lib/dsh-adapter/intent-router.d.ts +710 -0
  89. package/lib/dsh-adapter/intent-router.d.ts.map +1 -0
  90. package/lib/dsh-adapter/intent-router.js +2802 -0
  91. package/lib/dsh-adapter/intent-signals.d.ts +208 -0
  92. package/lib/dsh-adapter/intent-signals.d.ts.map +1 -0
  93. package/lib/dsh-adapter/intent-signals.js +391 -0
  94. package/lib/dsh-adapter/invariant-install.d.ts +16 -0
  95. package/lib/dsh-adapter/invariant-install.d.ts.map +1 -0
  96. package/lib/dsh-adapter/invariant-install.js +15 -0
  97. package/lib/dsh-adapter/invariant.d.ts +16 -0
  98. package/lib/dsh-adapter/invariant.d.ts.map +1 -0
  99. package/lib/dsh-adapter/invariant.js +22 -0
  100. package/lib/dsh-adapter/llm-adapters.d.ts +19 -0
  101. package/lib/dsh-adapter/llm-adapters.d.ts.map +1 -0
  102. package/lib/dsh-adapter/llm-adapters.js +16 -0
  103. package/lib/dsh-adapter/llm-internal-caller.d.ts +92 -0
  104. package/lib/dsh-adapter/llm-internal-caller.d.ts.map +1 -0
  105. package/lib/dsh-adapter/llm-internal-caller.js +100 -0
  106. package/lib/dsh-adapter/llm-max-turns.d.ts +55 -0
  107. package/lib/dsh-adapter/llm-max-turns.d.ts.map +1 -0
  108. package/lib/dsh-adapter/llm-max-turns.js +127 -0
  109. package/lib/dsh-adapter/llm-trace-store.d.ts +131 -0
  110. package/lib/dsh-adapter/llm-trace-store.d.ts.map +1 -0
  111. package/lib/dsh-adapter/llm-trace-store.js +205 -0
  112. package/lib/dsh-adapter/llm-trace.d.ts +450 -0
  113. package/lib/dsh-adapter/llm-trace.d.ts.map +1 -0
  114. package/lib/dsh-adapter/llm-trace.js +463 -0
  115. package/lib/dsh-adapter/local-llm-adapter.d.ts +141 -0
  116. package/lib/dsh-adapter/local-llm-adapter.d.ts.map +1 -0
  117. package/lib/dsh-adapter/local-llm-adapter.js +787 -0
  118. package/lib/dsh-adapter/local-storage.d.ts +96 -0
  119. package/lib/dsh-adapter/local-storage.d.ts.map +1 -0
  120. package/lib/dsh-adapter/local-storage.js +198 -0
  121. package/lib/dsh-adapter/model-router.d.ts +79 -0
  122. package/lib/dsh-adapter/model-router.d.ts.map +1 -0
  123. package/lib/dsh-adapter/model-router.js +107 -0
  124. package/lib/dsh-adapter/ohttp-gateway.d.ts +49 -0
  125. package/lib/dsh-adapter/ohttp-gateway.d.ts.map +1 -0
  126. package/lib/dsh-adapter/ohttp-gateway.js +32 -0
  127. package/lib/dsh-adapter/openai-sse.d.ts +85 -0
  128. package/lib/dsh-adapter/openai-sse.d.ts.map +1 -0
  129. package/lib/dsh-adapter/openai-sse.js +462 -0
  130. package/lib/dsh-adapter/pii-utils.d.ts +96 -0
  131. package/lib/dsh-adapter/pii-utils.d.ts.map +1 -0
  132. package/lib/dsh-adapter/pii-utils.js +324 -0
  133. package/lib/dsh-adapter/plugin-host.d.ts +38 -0
  134. package/lib/dsh-adapter/plugin-host.d.ts.map +1 -0
  135. package/lib/dsh-adapter/plugin-host.js +38 -0
  136. package/lib/dsh-adapter/plugin.d.ts +46 -0
  137. package/lib/dsh-adapter/plugin.d.ts.map +1 -0
  138. package/lib/dsh-adapter/plugin.js +100 -0
  139. package/lib/dsh-adapter/privacy-policy.d.ts +237 -0
  140. package/lib/dsh-adapter/privacy-policy.d.ts.map +1 -0
  141. package/lib/dsh-adapter/privacy-policy.js +391 -0
  142. package/lib/dsh-adapter/prompt-guard.d.ts +152 -0
  143. package/lib/dsh-adapter/prompt-guard.d.ts.map +1 -0
  144. package/lib/dsh-adapter/prompt-guard.js +872 -0
  145. package/lib/dsh-adapter/realm-skill-bridge.d.ts +365 -0
  146. package/lib/dsh-adapter/realm-skill-bridge.d.ts.map +1 -0
  147. package/lib/dsh-adapter/realm-skill-bridge.js +1180 -0
  148. package/lib/dsh-adapter/sanitizer-pipeline.d.ts +140 -0
  149. package/lib/dsh-adapter/sanitizer-pipeline.d.ts.map +1 -0
  150. package/lib/dsh-adapter/sanitizer-pipeline.js +431 -0
  151. package/lib/dsh-adapter/secure-bridge.d.ts +47 -0
  152. package/lib/dsh-adapter/secure-bridge.d.ts.map +1 -0
  153. package/lib/dsh-adapter/secure-bridge.js +35 -0
  154. package/lib/dsh-adapter/session-attribution.d.ts +70 -0
  155. package/lib/dsh-adapter/session-attribution.d.ts.map +1 -0
  156. package/lib/dsh-adapter/session-attribution.js +76 -0
  157. package/lib/dsh-adapter/sessions.d.ts +86 -0
  158. package/lib/dsh-adapter/sessions.d.ts.map +1 -0
  159. package/lib/dsh-adapter/sessions.js +179 -0
  160. package/lib/dsh-adapter/tcm.d.ts +55 -0
  161. package/lib/dsh-adapter/tcm.d.ts.map +1 -0
  162. package/lib/dsh-adapter/tcm.js +94 -0
  163. package/lib/dsh-adapter/td-bus.d.ts +87 -0
  164. package/lib/dsh-adapter/td-bus.d.ts.map +1 -0
  165. package/lib/dsh-adapter/td-bus.js +196 -0
  166. package/lib/dsh-adapter/tool-runner.d.ts +185 -0
  167. package/lib/dsh-adapter/tool-runner.d.ts.map +1 -0
  168. package/lib/dsh-adapter/tool-runner.js +271 -0
  169. package/lib/dsh-adapter/tools.d.ts +118 -0
  170. package/lib/dsh-adapter/tools.d.ts.map +1 -0
  171. package/lib/dsh-adapter/tools.js +292 -0
  172. package/lib/dsh-adapter/types.d.ts +23 -0
  173. package/lib/dsh-adapter/types.d.ts.map +1 -0
  174. package/lib/dsh-adapter/types.js +16 -0
  175. package/lib/dsh-adapter/voice-input.d.ts +30 -0
  176. package/lib/dsh-adapter/voice-input.d.ts.map +1 -0
  177. package/lib/dsh-adapter/voice-input.js +34 -0
  178. package/lib/dsh-adapter/web-search-tavily-bocha.d.ts +152 -0
  179. package/lib/dsh-adapter/web-search-tavily-bocha.d.ts.map +1 -0
  180. package/lib/dsh-adapter/web-search-tavily-bocha.js +289 -0
  181. package/lib/http-api.d.ts +2 -0
  182. package/lib/http-api.d.ts.map +1 -0
  183. package/lib/http-api.js +2 -0
  184. package/lib/index.d.ts +48 -0
  185. package/lib/index.d.ts.map +1 -0
  186. package/lib/index.js +49 -0
  187. package/lib/intent-router.d.ts +2 -0
  188. package/lib/intent-router.d.ts.map +1 -0
  189. package/lib/intent-router.js +2 -0
  190. package/lib/llm-adapters.d.ts +2 -0
  191. package/lib/llm-adapters.d.ts.map +1 -0
  192. package/lib/llm-adapters.js +2 -0
  193. package/lib/local-llm-adapter.d.ts +2 -0
  194. package/lib/local-llm-adapter.d.ts.map +1 -0
  195. package/lib/local-llm-adapter.js +2 -0
  196. package/lib/local-storage.d.ts +2 -0
  197. package/lib/local-storage.d.ts.map +1 -0
  198. package/lib/local-storage.js +2 -0
  199. package/lib/model-router.d.ts +2 -0
  200. package/lib/model-router.d.ts.map +1 -0
  201. package/lib/model-router.js +2 -0
  202. package/lib/ohttp-gateway.d.ts +2 -0
  203. package/lib/ohttp-gateway.d.ts.map +1 -0
  204. package/lib/ohttp-gateway.js +2 -0
  205. package/lib/plugin-host.d.ts +2 -0
  206. package/lib/plugin-host.d.ts.map +1 -0
  207. package/lib/plugin-host.js +2 -0
  208. package/lib/privacy-policy.d.ts +2 -0
  209. package/lib/privacy-policy.d.ts.map +1 -0
  210. package/lib/privacy-policy.js +2 -0
  211. package/lib/prompt-guard.d.ts +2 -0
  212. package/lib/prompt-guard.d.ts.map +1 -0
  213. package/lib/prompt-guard.js +2 -0
  214. package/lib/sanitizer-pipeline.d.ts +2 -0
  215. package/lib/sanitizer-pipeline.d.ts.map +1 -0
  216. package/lib/sanitizer-pipeline.js +2 -0
  217. package/lib/secure-bridge.d.ts +2 -0
  218. package/lib/secure-bridge.d.ts.map +1 -0
  219. package/lib/secure-bridge.js +2 -0
  220. package/lib/sessions.d.ts +2 -0
  221. package/lib/sessions.d.ts.map +1 -0
  222. package/lib/sessions.js +2 -0
  223. package/lib/tcm.d.ts +2 -0
  224. package/lib/tcm.d.ts.map +1 -0
  225. package/lib/tcm.js +2 -0
  226. package/lib/td-bus.d.ts +2 -0
  227. package/lib/td-bus.d.ts.map +1 -0
  228. package/lib/td-bus.js +2 -0
  229. package/lib/tools.d.ts +2 -0
  230. package/lib/tools.d.ts.map +1 -0
  231. package/lib/tools.js +2 -0
  232. package/lib/voice-input.d.ts +2 -0
  233. package/lib/voice-input.d.ts.map +1 -0
  234. package/lib/voice-input.js +2 -0
  235. package/package.json +253 -3
  236. package/presets/agent-preset-edge.json +50 -0
  237. package/presets/edge.desktop-safe.patch.yml +503 -0
  238. package/presets/edge.patch.yml +557 -0
@@ -0,0 +1,557 @@
1
+ # ── 边缘模式 preset(§7.135)──────────────────────────────────────────
2
+ #
3
+ # 宿主 DSH 的「Agent Preset」机制:preset 是一份 cordis insert patch,声明
4
+ # 一行 `@deepseek-ai/dsh-agent-preset`,其 `config.plugins` 是该工作方式
5
+ # 的**完整**插件行列表。宿主内置四种工作方式,都由 bundle 的 patch 文件
6
+ # 声明(@deepseek-ai/dsh-web-app/presets/*.patch.yml):
7
+ #
8
+ # standard —— 标准模式:persona / 工具 / plan-mode / compaction /
9
+ # delegation / subagent …
10
+ # ptc / minimal / cordis —— 另外三种
11
+ #
12
+ # 本文件声明**边缘模式**:标准模式的插件列表 **+ 本项目的功能**(隐私护栏、
13
+ # 意图判定、路由决策、PII 脱敏、两个 LLM adapter、Realm 闸门、威胁总线、
14
+ # Edge 面板)。主人裁决(2026-10-28):
15
+ #
16
+ # 「我需要在 dsh 桌面上成一新的 agent 工作时间,叫做边缘模式,功能是在
17
+ # 标准模式之上增加本项目的功能」
18
+ # 「只有选择 边缘模式 才会出现 edge tab」
19
+ #
20
+ # ## 本项目的插件行在哪(§7.136 修正)
21
+ #
22
+ # 行为面(护栏 / 判定 / 路由 / 脱敏 / Realm / Edge 面板)**在这里**,并且整体
23
+ # 关进一个 `cordis:group` + `isolate` 隔离 realm —— 宿主规则(dsh-agent-preset-
24
+ # registry README):「preset 的服务提供方及其消费方必须共享同一个 cordis:group
25
+ # 隔离 realm」。挂载审计(lib/types/mount.js)会把「挂在 preset 子树里却把服务
26
+ # 存进 root realm」的行判为泄漏 ⇒ 整个 preset 挂载失败 ⇒ 设置页那张卡显示
27
+ # 「加载失败」。这正是 §7.135 那版预设加载失败的原因。
28
+ #
29
+ # **三行必须留在宿主树**(bundle 顶层 insert 段)—— 宿主机制的限制,不是偏好:
30
+ #
31
+ # dsh-edge-agent(裸包名行)—— 宿主的 client-modules 只扫**宿主 Loader 的
32
+ # entries**(dsh-client-modules/lib/index.js:「scans the host Loader's
33
+ # entries」;processOne() 遍历 `this.ctx.loader.entries()`),preset 的插件树
34
+ # 是独立的 EntryTree、不在其中 ⇒ Edge tab 的浏览器半边只有从宿主树里的裸
35
+ # 包名行才能被发现。
36
+ # audit-log / file-logger —— 裸包名行 inject ['auditLog'],且它 apply() 里的
37
+ # installFileLogger 会先占住 `fileLogger` 服务名 ⇒ 两者必须在 root realm,
38
+ # 且 file-logger 行必须比裸包名行更早装载(否则桌面 ops log 的文件名会从
39
+ # `dsh-edge-agent-desktop.log` 退回 `dsh-edge-agent.log`)。
40
+ #
41
+ # ## 「切回标准模式会怎样」(§7.136 实测结论)
42
+ #
43
+ # 宿主的 preset 是**启动即挂载**的(dsh-agent-preset README:「声明会提前加载」):
44
+ # 声明过的 preset 在启动时都建好插件树,选哪个只决定 **Agent 绑到哪个 scope**
45
+ # (可见的工具 / 提示词 / 服务)。所以:
46
+ #
47
+ # * 本项目的插件在任何工作方式下都已挂载 —— 切回标准模式**不会**卸载它们;
48
+ # 让标准模式变「纯宿主」的是**事件作用域**,不是卸载:
49
+ # * 我们的 hook(agent/pre-step / agent/request / system-prompt/assemble /
50
+ # tools/pre-execute / tools/result)**不再带 `{ global: true }`**。宿主的
51
+ # 事件过滤(cordis EventsService.dispatch:
52
+ # `hook.global || !filter || filter.call(thisArg, hook.ctx)`)按 scope 链
53
+ # 判定 —— 监听器自己的 scope 必须是派发 scope 或其祖先;Agent 的 scope 父
54
+ # 链接到所选 preset 的代际 scope(dsh-agent-preset-registry 的
55
+ # `bindScopeParent`),事件沿 scope 链向上流、不向下 ⇒ 标准模式的 Agent
56
+ # 收不到边缘模式 preset 里的 hook ⇒ 标准模式不经过本项目的护栏;
57
+ # * `llm/stream` 保留 `{ global: true }`:该事件不带 scope 载体(去掉也不
58
+ # 生效),且无 pre-step state 时恒直通;
59
+ # * Edge tab 的浏览器半边是全局的(客户端只有一张全局 boot 图,tab 类型是
60
+ # 全局注册表),所以「只有边缘模式才有 edge tab」由**客户端按 roster 的
61
+ # 默认 preset 注册/注销 tab 类型**实现(src/client/index.ts,5s 轮询
62
+ # `agentPresets.list()` 的 `isDefault`)。
63
+ #
64
+ # ## 为什么标准模式的行是抄来的
65
+ #
66
+ # 注册表**不合并**:preset 的 plugins 是完整列表,覆盖式(宿主原文:「用户覆盖
67
+ # 替换完整子插件列表,不自动合并内置列表的未来更新」)。所以边缘模式要
68
+ # 「在标准模式之上增加」,就必须把标准模式的行**整份抄进来**。
69
+ #
70
+ # 代价要说清楚:**宿主升级后标准模式的插件列表若变了,边缘模式不会自动跟随**
71
+ # —— 需要人把宿主的
72
+ # @deepseek-ai/dsh-web-app/presets/standard.patch.yml
73
+ # 重新对齐到本文件。生成器 scripts/_gen-edge-preset.mjs 就是干这件事的。
74
+ #
75
+ # ## 主机 row 的覆盖留在顶层
76
+ #
77
+ # 本 bundle 顶层对宿主行的覆盖(tool-web / web / web-search-deepseek)是
78
+ # **patch 层**语义 —— preset 只能声明插件行,不能覆盖宿主行。所以这些覆盖
79
+ # 在任何工作方式下都生效。这是 preset 机制的边界,如实记录在此。
80
+
81
+ - insert:
82
+ - id: preset-edge
83
+ name: '@deepseek-ai/dsh-agent-preset'
84
+ config:
85
+ id: edge
86
+ name: 边缘模式
87
+ description: 标准模式 + 本项目的端侧隐私能力(意图判定 / 路由决策 / PII 脱敏 / Realm 闸门)
88
+ order: 5
89
+ plugins:
90
+ # §7.175(2026-11-11):这里**故意没有** `agent-default-model` 行;
91
+ # §7.176(2026-11-11)起,本地模型默认值改由**本 preset 内的
92
+ # input-guard** 给出(见下面 edge-stack 组里的 input-guard 行)。
93
+ #
94
+ # 实测(桌面 App 日志 2026-11-11 10:24 / 10:26,两次启动一致):
95
+ # WARN [agent-preset-registry] agent preset edge:
96
+ # agent-default-model (@deepseek-ai/dsh-agent-default-model):
97
+ # service "agentDefaultModel" has been registered at <AgentDefaultModelConfig>
98
+ # ⇒ 加了这一行,**整个边缘模式 preset 挂载失败**(设置页那张卡显示
99
+ # 「加载失败」),Edge 模式用不了。
100
+ #
101
+ # 根因:宿主 dsh-base/cordis.patch.yml L90-94 已经在 **host scope** 声明了
102
+ # 同一个插件(provider: deepseek-official / model: deepseek-flash);该插件
103
+ # 用 `super(ownerContext, "agentDefaultModel")` 注册 cordis service,
104
+ # 而这个 service 名**跨 scope 唯一** ⇒ preset scope 再声明一次 ⇒ 撞名。
105
+ #
106
+ # ⚠️ 本文件此前写的理由(「service 注册在插件所在 scope,scope 查找就近 ⇒
107
+ # preset 内就近拿到这一行、遮蔽 host scope 的全局默认」)是**推断,实测证伪**
108
+ # —— 真正的读取方是 host scope 的那份:
109
+ # `dsh-api-session-controller` 的 `agentOptions()` 读 `this.ctx.agentDefaultModel`,
110
+ # preset scope 里那份即使不撞名也**没有读者**。
111
+ #
112
+ # §7.176:为什么由 input-guard 给默认值,而不是这一行:
113
+ # 1. 宿主 0.2.2-rc.1 起,路由只由**会话级** modelSelection 决定
114
+ # (`agent/request` 里改写会被 prepareRequest() 判非法并抛错);
115
+ # 2. 桌面 GUI 建的 agent,其 agentOptions 来自 host scope 的
116
+ # agentDefaultModel(宿主自带的云端模型)⇒ 边缘模式默认会跑云端;
117
+ # 3. 本地路由 local-llm 在模型目录里隐身(§7.106 Option A:它是管线
118
+ # 内部件,不是用户可选项)⇒ GUI 里**选不到**它,用户没法手动纠正;
119
+ # ⇒ 只能由 preset 侧把会话选择钉成 local-llm。input-guard 用的是宿主
120
+ # 自己的合规入口 `agent.model.select()`(agent-loop 的
121
+ # applyConfiguredRoute() 也是这么写的),**不动**宿主的全局默认 ——
122
+ # `sessionController.selectModel()` 会顺手 `saveSelection()` 改全局,
123
+ # 那样会波及同 profile 的标准模式。
124
+ #
125
+ # 主人裁决(2026-11-11):**npm 包里不会带本地模型配置**(config/edge.json
126
+ # 被 `files` 白名单排除)⇒ local-llm 走 DELEGATE(§7.171)转发宿主
127
+ # provider ⇒ 装上就能用(先用 dsh 自带的云端模型),而 provider 身份仍是
128
+ # local-llm ⇒ §7.175 的 fail-closed 闸门照样放行。
129
+ # 实测记录见 docs/PROGRESS.md §7.175 / §7.176。
130
+ - id: persona
131
+ name: '@deepseek-ai/dsh-persona'
132
+ config:
133
+ prefix: You are a coding agent powered by the {{model}} model.
134
+ - id: agent-instructions
135
+ name: '@deepseek-ai/dsh-agent-instructions'
136
+ config:
137
+ maxBytes: 65536
138
+ - id: time-context
139
+ name: '@deepseek-ai/dsh-time-context'
140
+ - id: tool-bash
141
+ name: '@deepseek-ai/dsh-tool-bash'
142
+ disabled: !!js process.platform === 'win32'
143
+ - id: tool-pwsh
144
+ name: '@deepseek-ai/dsh-tool-pwsh'
145
+ disabled: !!js process.platform !== 'win32'
146
+ - id: tool-fs
147
+ name: '@deepseek-ai/dsh-tool-fs'
148
+ config:
149
+ # §7.174:随宿主 0.2.2-rc.1 的 standard preset 对齐 ——
150
+ # Set false to drop the apply_patch tool beside edit.
151
+ applyPatch: false
152
+ - id: tool-fs-search
153
+ name: '@deepseek-ai/dsh-tool-fs-search'
154
+ config:
155
+ sampleOverCapGlobResults: false
156
+ - id: tool-jobs
157
+ name: '@deepseek-ai/dsh-tool-jobs'
158
+ - id: tool-schedule
159
+ name: '@deepseek-ai/dsh-tool-schedule'
160
+ - id: skill-filesystem
161
+ name: '@deepseek-ai/dsh-skill-filesystem'
162
+ - id: tool-skill
163
+ name: '@deepseek-ai/dsh-tool-skill'
164
+ - id: command-goal
165
+ name: '@deepseek-ai/dsh-command-goal'
166
+ - id: tool-goal
167
+ name: '@deepseek-ai/dsh-tool-goal'
168
+ - id: planning
169
+ name: cordis:group
170
+ group: true
171
+ isolate:
172
+ planMode: true
173
+ config:
174
+ - id: plan-mode
175
+ name: '@deepseek-ai/dsh-plan-mode'
176
+ config:
177
+ section: |
178
+ You are in plan mode. Stay in plan mode until the user approves your plan through exit_plan_mode or 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.
179
+
180
+ 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.
181
+
182
+ 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.
183
+
184
+ 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.
185
+
186
+ 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.
187
+
188
+ 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.
189
+ - id: compaction
190
+ name: cordis:group
191
+ group: true
192
+ isolate:
193
+ compaction: true
194
+ toolResultPruner: true
195
+ config:
196
+ - id: compaction-basic
197
+ name: '@deepseek-ai/dsh-compaction-basic'
198
+ - id: command-compact
199
+ name: '@deepseek-ai/dsh-command-compact'
200
+ - id: tool-result-pruner
201
+ name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
202
+ config:
203
+ thresholdChars: 8192
204
+ headChars: 4096
205
+ tailChars: 1024
206
+ - id: delegation
207
+ name: cordis:group
208
+ group: true
209
+ isolate:
210
+ workflowEngine: true
211
+ config:
212
+ - id: tool-subagent-control
213
+ name: '@deepseek-ai/dsh-tool-subagent-control'
214
+ # §7.174:宿主 0.2.2-rc.1 的 dsh-tool-subagent-control **不再导出**
215
+ # './list-agents' 子路径 ⇒ 保留这行会在 preset 挂载时抛
216
+ # ERR_PACKAGE_PATH_NOT_EXPORTED ⇒ 整个 edge preset 被判 broken
217
+ # ⇒ 设置页「边缘模式」消失。宿主四个内置 preset 都没有这一行。
218
+ - id: tool-subagent
219
+ name: '@deepseek-ai/dsh-tool-subagent'
220
+ config:
221
+ provider: spawn
222
+ toolName: subagent
223
+ # §7.136 曾经**故意不写** modelSelection(旧宿主键名是
224
+ # `modelSelectionSettings`,per-agent 二次安装会重复注册);
225
+ # 上游已改为「挂载时注册一次」,宿主现有 preset 也都写着
226
+ # 这两项 ⇒ §7.174 对齐,边缘模式恢复「子 Agent 选模型」。
227
+ modelSelection: true
228
+ modelDiscovery: true
229
+ - id: tool-subagent-fork
230
+ name: '@deepseek-ai/dsh-tool-subagent'
231
+ config:
232
+ provider: fork
233
+ toolName: subagent_fork
234
+ - id: workflow-ptc
235
+ name: '@deepseek-ai/dsh-workflow-ptc'
236
+ config:
237
+ provider: spawn
238
+ - id: tool-workflow
239
+ name: '@deepseek-ai/dsh-tool-workflow'
240
+ - id: tool-ask-user
241
+ name: '@deepseek-ai/dsh-tool-ask-user'
242
+ - id: tool-todo
243
+ name: '@deepseek-ai/dsh-tool-todo'
244
+ config:
245
+ allowParallelInProgress: true
246
+ - id: tool-web
247
+ name: '@deepseek-ai/dsh-tool-web'
248
+ config:
249
+ fetch: true
250
+ searchTimeoutMs: 60000
251
+ - id: present
252
+ name: '@deepseek-ai/dsh-tool-present'
253
+ - id: tool-plugin-manager
254
+ name: '@deepseek-ai/dsh-plugin-manager/tools'
255
+ disabled: true
256
+ - id: tool-plugin-market
257
+ name: '@deepseek-ai/dsh-plugin-market/tools'
258
+ disabled: true
259
+
260
+ # ── 边缘模式:本项目的功能(§7.135 + §7.136)──────────────────────
261
+ #
262
+ # 宿主规则(dsh-agent-preset-registry README):
263
+ # 「preset 的服务提供方及其消费方必须共享同一个 cordis:group 隔离 realm」
264
+ # 挂载审计(lib/types/mount.js):preset 子树里的服务如果存进 root realm
265
+ # ⇒ 泄漏 ⇒ 整个 preset 挂载失败(设置页那张卡显示「加载失败」)。
266
+ # 所以本组用 cordis:group + isolate 把组内每一行提供的服务关进组内 realm:
267
+ # 组内互相可见,组外(宿主)看不见 ⇒ 不泄漏。
268
+ #
269
+ # isolate 名单由 scripts/_isolate-edge-group.mjs 从源码推导
270
+ # (super(ctx,'<svc>')),门禁 scripts/verify-preset-isolate.ts 复核 ——
271
+ # 改源码后必须重跑本脚本。
272
+ - id: edge-stack
273
+ name: cordis:group
274
+ group: true
275
+ isolate:
276
+ edgeTools: true
277
+ functionCallExternal: true
278
+ httpApi: true
279
+ inputGuard: true
280
+ intentRouter: true
281
+ localStorage: true
282
+ modelRouter: true
283
+ privacyPolicy: true
284
+ promptGuard: true
285
+ realmSkillBridge: true
286
+ sanitizer: true
287
+ tcm: true
288
+ tdBus: true
289
+ config:
290
+ # tcm: prompt-guard injects this; must mount first
291
+ - id: tcm
292
+ name: '@dsh-edge/dsh-edge-agent/tcm'
293
+ # §7.102: teeType / keyStorePath come from config/edge.json (tee.*).
294
+
295
+ # td-bus: http-api injects this; must mount before http-api.
296
+ # Config schema (`td-bus.ts`):
297
+ # - windowSeconds: number (sliding window in seconds; default 60)
298
+ # - thresholds.cloudRequestsPerMinute: number (default 20)
299
+ # - blockLevel: 'elevated' | 'high' | 'critical' (default 'critical')
300
+ # Block triggers at 4× threshold within windowSeconds.
301
+ - id: td-bus
302
+ name: '@dsh-edge/dsh-edge-agent/td-bus'
303
+ inject: [auditLog, privacyPolicy]
304
+ config:
305
+ windowSeconds: 60
306
+ thresholds:
307
+ cloudRequestsPerMinute: 8 # tighter than default 20 — escalate earlier
308
+ failedSanitizationStreak: 3
309
+ permissionDeniedStreak: 5
310
+ blockLevel: critical # block on critical (4× = 32/min)
311
+
312
+ # realm-skill-bridge: realm-aware skill catalog filtering + tool gating.
313
+ # Must mount before http-api (which injects realmSkillBridge).
314
+ # §7.102: configPath / hot-reload knobs come from config/edge.json
315
+ # (privacy.realm*). Row carries no config.
316
+ - id: realm-skill-bridge
317
+ name: '@dsh-edge/dsh-edge-agent/realm-skill-bridge'
318
+ inject: [auditLog, skills, edgeTools, tools]
319
+
320
+ # §7.102: host/port from config/edge.json http.*, session/body caps
321
+ # from resources.*, bearer token from secrets.edgeApiKey — all filled
322
+ # fill-if-unset in http-api.ts apply(). The bare EDGE_API_KEY env stays
323
+ # a per-process override via edge-config's ENV_OVERRIDES. Row carries
324
+ # no config.
325
+ - id: http-api
326
+ name: '@dsh-edge/dsh-edge-agent/http-api'
327
+ inject: [agents, intentRouter, auditLog, tdBus, realmSkillBridge, edgeTools]
328
+
329
+ - id: cloud-llm-adapter
330
+ name: '@dsh-edge/dsh-edge-agent/cloud-llm-adapter'
331
+ inject: [llm, auditLog]
332
+ config:
333
+ providers: [cloud-llm]
334
+ # §7.100: 兜底链改为 `||`(空串视为未配置,根治 .env.sh export "" +
335
+ # §7.102 (2026-10-21): 池配置 + delegate 旋钮迁到 config/edge.json
336
+ # (llm.cloud.*)。patch 不再读 process.env —— 桌面 GUI 起进程时没有
337
+ # 任何 DSH_EDGE_* 变量,读到的全是 undefined。
338
+ # baseUrl 空 = DELEGATE 模式:cloud-llm 路由转发到宿主 profile 已
339
+ # 配置的模型提供商(GUI selection > live 宿主路由),key/凭据归
340
+ # 宿主 adapter。显式配置 llm.cloud.baseUrl 才走自研直连。
341
+ # delegate=false → 禁用委托(LOCAL-only 部署;恢复 §7.35
342
+ # "云不可用→降级 LOCAL" 语义)
343
+ # delegateProvider → 显式指定目标路由 id
344
+ # delegateModel → wire model override(压过 GUI selection.model)
345
+
346
+ - id: local-llm-adapter
347
+ name: '@dsh-edge/dsh-edge-agent/local-llm-adapter'
348
+ inject: [llm, auditLog]
349
+ config:
350
+ providers: [local-llm]
351
+ # §7.102: baseUrl / model / key / stripTools / enableThinking 全部
352
+ # 来自 config/edge.json 的 llm.local.*。§7.171: baseUrl 留空 =
353
+ # DELEGATE(local-llm 路由照样注册,转发给宿主 profile 的提供商,
354
+ # 与 cloud-llm 对称);`llm.local.delegate=false` 才是「不注册本地
355
+ # LLM 路由」(模型列表里不出现 local-llm,意图分类 / prompt-guard
356
+ # 自动降级到关键词 / 正则规则档)。
357
+
358
+ - id: model-router
359
+ name: '@dsh-edge/dsh-edge-agent/model-router'
360
+ inject: [llm]
361
+ config:
362
+ # §7.75: 删 defaultModel(v0.1.x 死字段,model-router.ts:143 构造时
363
+ # 只接 localModels/cloudModels)。routing 由 intent 分类 + classificationProvider
364
+ # 走 modelRouter.resolve() 决定,不靠"默认目标"变量
365
+ localModels: [local-llm]
366
+ cloudModels: [cloud-llm]
367
+
368
+ - id: intent-router
369
+ name: '@dsh-edge/dsh-edge-agent/intent-router'
370
+ inject: [llm, auditLog, privacyPolicy]
371
+ config:
372
+ # 2026-09-02: changed from CLOUD to SANITIZED. Old default failed open
373
+ # (ambiguous requests → CLOUD LLM, raw data egress). New default routes
374
+ # through input-guard sanitizer first; sanitize failure downgrades to
375
+ # LOCAL (fail-closed). See intent-router.ts:60 schema default.
376
+ defaultCategory: SANITIZED
377
+ # §7.102 (2026-10-21): 分类器 + jev 全部参数迁到 config/edge.json
378
+ # (stages.intent.* / jev.*)。patch 不再读 process.env。
379
+
380
+ # NOTE: id renamed from `tools` to avoid colliding with dsh-base.
381
+ - id: edge-tools-registry
382
+ name: '@dsh-edge/dsh-edge-agent/tools'
383
+ inject: [auditLog, tools]
384
+ config:
385
+ defaultRateLimitPerMinute: 60
386
+ enableToolIsolation: true
387
+ presentationMode: native
388
+
389
+ # §7.98:14 个**只读** etscli 子命令注册进 ctx.tools。
390
+ #
391
+ # 注册即安全边界:不在注册表里的工具不会出现在
392
+ # realm-skill-bridge.getToolSchemasForExternal() 的产物里,needle 物理上选不中,
393
+ # ctx.tools.execute() 也没法执行它。写/删类工具(auth logout / fs rm /
394
+ # file delete / chat send / migrate verify …)一律**不注册**,排除依据见
395
+ # src/dsh-adapter/etscli-tools.ts 模块头。
396
+ #
397
+ # 依赖 tools + shell:前者是注册表本体;后者提供子进程执行,白拿超时/中止
398
+ # 判别、输出截断、凭据擦除 env、进程组 kill 升级 —— 不自己 spawn。
399
+ # §7.102: etscliBin / timeoutMs come from config/edge.json (etscli.*).
400
+ - id: etscli-tools
401
+ name: '@dsh-edge/dsh-edge-agent/etscli-tools'
402
+ inject: [tools, shell]
403
+
404
+ # §7.120: 封堵「bash 里直接调 etscli 写子命令」这条逃逸口。
405
+ #
406
+ # 上面那份注册表白名单管的是**工具清单**(模型选不到写子命令),
407
+ # 管不住「模型自己在 shell 里敲 etscli」—— §7.118 那次实测就是
408
+ # `bash: etscli file upload …` 把本地文件传到了 MEOS 设备。
409
+ # 本行挂在 `tools/pre-execute` waterfall 上:shell 里只放行注册表
410
+ # 派生的那 14 个只读子命令,其余一律拒(白名单,不是黑名单)。
411
+ #
412
+ # 独立成行(不与 etscli-tools 合并)⇒ headless HTTP profile 与
413
+ # desktop-safe preset 可以只挂这道闸、不引入那 14 个工具。
414
+ - id: etscli-shell-guard
415
+ name: '@dsh-edge/dsh-edge-agent/etscli-shell-guard'
416
+
417
+ - id: local-storage
418
+ name: '@dsh-edge/dsh-edge-agent/local-storage'
419
+ config:
420
+ # §7.102: root comes from config/edge.json (storage.root), default
421
+ # ~/.dsh-edge-agent/storage (2026-08-29 unified bundle root).
422
+ filename: storage.plain.jsonl
423
+ enablePIIRedaction: true
424
+
425
+
426
+ # ── A1 端侧隐私安全防护 ─────────────────────────────────────────────────
427
+ - id: prompt-guard
428
+ name: '@dsh-edge/dsh-edge-agent/prompt-guard'
429
+ inject: [auditLog, llm]
430
+ config:
431
+ maxInputLength: 10000
432
+ maxRequestsPerMinute: 20
433
+ enablePIIRedaction: true
434
+ enableInjectionDetection: true
435
+ enableRateLimit: true
436
+ # §7.102 (2026-10-21): 模型检测配置迁到 config/edge.json
437
+ # (stages.guard.*)。patch 不再读 process.env。
438
+
439
+ # ── Phase 4: 隐私策略引擎 + 脱敏管线 ──────────────────────────────────
440
+ - id: privacy-policy
441
+ name: '@dsh-edge/dsh-edge-agent/privacy-policy'
442
+ inject: [auditLog]
443
+ # §7.102: row carries no config — policyPath / hot-reload 由
444
+ # config/edge.json (privacy.*) 提供。
445
+ # 2026-09-03 (§7.36): 默认 policy path 改为单 bundle root `~/.dsh-edge-agent/`。
446
+ # §7.33 之前:fallback 到 `~/.dsh-edge-agent-web/`(web profile isolated root)。
447
+ # §7.36:user 决定合并 web + tui → 单 root。DSH CLI 一次只跑一个 profile,
448
+ # 所有 profile 共用同一份 policy 文件——跟 6 个 channel 数据合并一致。
449
+ # §7.102: policyPath 默认 ~/.dsh-edge-agent/privacy-policy.json ——
450
+ # 现由 config/edge.json (privacy.policyPath / policyHotReload /
451
+ # policyWatchMs) 提供,行内不再保留。
452
+ # 2026-09-03 (§7.36): 默认 policy path 单 bundle root(见 PROGRESS)。
453
+
454
+ - id: sanitizer-pipeline
455
+ name: '@dsh-edge/dsh-edge-agent/sanitizer-pipeline'
456
+ inject: [privacyPolicy, auditLog]
457
+ config:
458
+ enableAutoDetection: true
459
+ maxReplacementsPerSession: 1024
460
+ # 明文 PII 映射表的生命周期兜底(2026-08-30)
461
+ # §7.102: sessionTtlMs / maxSessions / sweepIntervalMs 迁到
462
+ # config/edge.json (privacy.*)。patch 不再读 process.env。
463
+
464
+ # ── Phase 5 (§7.82): Tavily → 博查 AI → DeepSeek 三级 web_search 兜底链
465
+ # 注册一个 aggregator search provider(id='tavily-bocha-fallback')到 ctx.web;
466
+ # web.searchProvider = 'tavily-bocha-fallback' 即指向它。任一 tier 抛错
467
+ # (非 2xx / 网络 / JSON 解析) → 下一 tier 接续; 三 tier 都失败 →
468
+ # WEB_PROVIDER_UNAVAILABLE。配置走裸名 env (§7.75: .env + .env.sh source
469
+ # chain;避开 DSH 黑名单 DSH_/XDG_/DYLD_/BASH_FUNC_): TAVILY_API_KEY /
470
+ # BOCHA_API_KEY / DEEPSEEK_API_KEY,都在 repo .env 里跟其他 secret 同地。
471
+ - id: web-search-tavily-bocha
472
+ name: '@dsh-edge/dsh-edge-agent/web-search-tavily-bocha'
473
+ inject: [web]
474
+ config:
475
+ reserved: {}
476
+
477
+
478
+ # ── Phase 6: input-guard 编排器 ────────────────────────────────────
479
+ # 端侧隐私安全管线的编排器。把安全/隐私/脱敏逻辑从 transport 层
480
+ # (http-api) 上移到 Agent Loop 的事件链上 (agent/pre-step + llm/stream),
481
+ # 让所有入口(http-api / Web UI / CLI / SDK)自动统一走同一套管线。
482
+ #
483
+ # 组合调用:
484
+ # promptGuard.checkInput (攻击检测)
485
+ # privacyPolicy.matchRouting (策略 REJECT)
486
+ # intentRouter.classify (LOCAL/CLOUD 路由)
487
+ # sanitizer.sanitize (仅 CLOUD:PII → 占位符)
488
+ # sanitizer.desanitize (输出方向:占位符 → PII)
489
+ #
490
+ # 设计详见:docs/input-guard-design.md
491
+ # ── §7.93.1(2026-09-25 通用化):function-call-external 插件
492
+ # 把 tool-call prefill 抽象成 ExternalToolCaller 接口(healthCheck +
493
+ # extract);当前实现 = NeedleHttpCaller(cactus-needle 3.0.1,API.md v1.1)。
494
+ # 后续替换 = 新增 class implements ExternalToolCaller + 改 apply() 一行。
495
+ # **必须早于 input-guard apply**:本插件是 agent/pre-step waterfall 的最
496
+ # 外层 listener(await next() 串到 input-guard,等 input-guard 的 classify +
497
+ # setSessionRealm 完成后才返回,我们才看得到本 turn 的 realm)。
498
+ # 否则读到 undefined 或上 turn 旧 realm → 触发跳过路径。
499
+ # cordis waterfall 注册顺序 = 执行顺序(shift 第一个 = 最外层)。
500
+ - id: function-call-external
501
+ name: '@dsh-edge/dsh-edge-agent/function-call-external'
502
+ inject: [auditLog, realmSkillBridge, tools]
503
+ # §7.102: row carries no config — 全部旋钮由 config/edge.json
504
+ # (functionCallExternal.*) 提供。默认关(user 终裁)。
505
+ # §7.102 (2026-10-21): 全部旋钮迁到 config/edge.json
506
+ # (functionCallExternal.*)。patch 不再读 process.env。
507
+ # 当前实现 = cactus-needle 3.0.1:GET /health + POST /extract(stateless 无 /reset;
508
+ # P1 中文数字归一化服务端内置;client 不做翻译,管什么语种 caller 自带 cn_grounding)。
509
+ # functionCallExternalEnabled: !!js process.env.DSH_EDGE_FUNCTION_CALL_EXTERNAL_ENABLED === 'true'
510
+ # functionCallExternalUrl: !!js process.env.DSH_EDGE_FUNCTION_CALL_EXTERNAL_URL ?? 'http://127.0.0.1:8081'
511
+ # 实测 /extract 在 caller 当前 LAN 引擎下需 4-7s(dry-run #1 标 376-548ms 是
512
+ # API.md spec 理想值,实际 25-30x degradation);10s 给单请求 1x 余量。
513
+ # 后续引擎恢复 < 1s 时再调低。
514
+ # functionCallExternalTimeoutMs: !!js parseInt(process.env.DSH_EDGE_FUNCTION_CALL_EXTERNAL_TIMEOUT_MS ?? '10000', 10)
515
+ # functionCallExternalConfidenceThreshold: !!js parseFloat(process.env.DSH_EDGE_FUNCTION_CALL_EXTERNAL_CONFIDENCE_THRESHOLD ?? '0.5')
516
+ # §7.92.6:circuit breaker(单 fetch 模式,open-on-first-failure,jev
517
+ # all-batches 失败才开的等价位)。dry-run #1 验证 timeout 几乎全中,
518
+ # breaker 必须计入 timeout。
519
+ # functionCallExternalBreakerTtlMs: !!js parseInt(process.env.DSH_EDGE_FUNCTION_CALL_EXTERNAL_BREAKER_TTL_MS ?? '30000', 10)
520
+ # §7.92.7:boot probe + 周期恢复 probe(GET /health)
521
+ # functionCallExternalBootProbeEnabled: !!js process.env.DSH_EDGE_FUNCTION_CALL_EXTERNAL_BOOT_PROBE_ENABLED !== 'false'
522
+ # functionCallExternalBootProbeTimeoutMs: !!js parseInt(process.env.DSH_EDGE_FUNCTION_CALL_EXTERNAL_BOOT_PROBE_TIMEOUT_MS ?? '2000', 10)
523
+ # functionCallExternalBreakerProbeMs: !!js parseInt(process.env.DSH_EDGE_FUNCTION_CALL_EXTERNAL_BREAKER_PROBE_MS ?? '5000', 10)
524
+ # functionCallExternalProbeTimeoutMs: !!js parseInt(process.env.DSH_EDGE_FUNCTION_CALL_EXTERNAL_PROBE_TIMEOUT_MS ?? '2000', 10)
525
+ - id: input-guard
526
+ name: '@dsh-edge/dsh-edge-agent/input-guard'
527
+ # §7.176 (2026-11-11): 本行是**边缘模式本地模型默认值的给出点**。
528
+ # 宿主 0.2.2-rc.1 起路由只由会话级 modelSelection 决定,而 GUI 建的
529
+ # agent 默认取 host scope 的 agentDefaultModel(宿主自带云端模型),
530
+ # local-llm 又在模型目录里隐身(§7.106 Option A,GUI 选不到)⇒
531
+ # 只能由本 preset 侧把会话选择钉成 local-llm。input-guard 监听
532
+ # `agent/created`,用宿主的合规入口 `agent.model.select()` 写会话级
533
+ # 选择;不动宿主的全局默认(那会波及同 profile 的标准模式)。
534
+ # 详见 docs/PROGRESS.md §7.176。
535
+ # §7.123 (2026-10-27): realmSkillBridge was missing here while
536
+ # input-guard.ts:35-39 declares it MANDATORY ("必须 inject realmSkillBridge,
537
+ # 否则 this.ctx.realmSkillBridge 永远 undefined"). With it absent,
538
+ # setSessionRealm() was silently skipped → the session realm was never
539
+ # registered → the Layer-3 tools/pre-execute gate had no realm to
540
+ # enforce against (fail-open). The row now matches the plugin's own
541
+ # inject declaration.
542
+ inject: [promptGuard, privacyPolicy, intentRouter, sanitizer, auditLog, realmSkillBridge]
543
+ config:
544
+ # §7.102 (2026-10-21): 开关 + 降级 model 迁到 config/edge.json
545
+ # (privacy.* + llm.local.model)。patch 不再读 process.env。
546
+ # enableInputGuard → 全局 hook 开关
547
+ # rejectOnPolicyViolation → 攻击 / privacy-policy REJECT 阻断 step
548
+ # downgradeOnSanitizeFailure → sanitize 失败降级 LOCAL(fail-closed)
549
+ # localModel → 本地池的 model id,跟随 LOCAL 池
550
+ # (§7.176 起还兼作边缘模式会话的默认 model)
551
+ sanitizeLocalTraffic: false
552
+ # §7.179 (2026-11-11): 本 preset 的 id。`agent-preset/selected`
553
+ # 是**全局**事件(宿主 registry 直接 ctx.emit,不带 scope 载体)
554
+ # ⇒ input-guard 必须自己按 presetId 过滤,否则会把标准模式的
555
+ # 会话也钉成 local-llm。必须与上面 `config.id` 一致 ——
556
+ # scripts/verify-preset-isolate.ts 复核这一点。
557
+ presetId: edge