ppxans-harness 2.4.0 → 3.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.
Files changed (186) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +218 -265
  3. package/bin/ppx-channels.js +2 -2
  4. package/bin/ppx-serve.js +5 -5
  5. package/bin/ppx-setup.js +124 -0
  6. package/bin/ppx-web.js +140 -0
  7. package/bin/ppx.js +2 -2
  8. package/config/identity.md +6 -6
  9. package/config/ishiki.md +16 -16
  10. package/config/ppx.json +15 -151
  11. package/config/ppx.json.example +143 -0
  12. package/package.json +17 -10
  13. package/skills/.usage.json +6 -0
  14. package/skills/agent-professional-training/SKILL.md +94 -0
  15. package/skills/brainstorm/SKILL.md +24 -0
  16. package/skills/cupid-lover-comms/SKILL.md +37 -0
  17. package/skills/debug/SKILL.md +26 -0
  18. package/skills/plan/SKILL.md +25 -0
  19. package/skills/ponytail/SKILL.md +25 -0
  20. package/skills/ppx-memory/SKILL.md +91 -0
  21. package/skills/ppx-memory/scripts/cli.js +192 -0
  22. package/skills/ppx-memory/scripts/experience.js +133 -0
  23. package/skills/ppx-memory/scripts/fact-store.js +842 -0
  24. package/skills/ppx-memory/scripts/l0.js +52 -0
  25. package/skills/ppx-memory/scripts/l2.js +146 -0
  26. package/skills/ppx-memory/scripts/l3.js +112 -0
  27. package/skills/ppx-memory/scripts/memory-ticker.js +238 -0
  28. package/skills/ppx-memory/scripts/pii.js +42 -0
  29. package/skills/ppx-memory/scripts/schema.js +80 -0
  30. package/skills/ppx-memory/scripts/session.js +398 -0
  31. package/skills/ppx-memory/scripts/similarity.js +43 -0
  32. package/skills/ppx-memory/scripts/store.js +116 -0
  33. package/skills/ppx-memory/scripts/wal.js +38 -0
  34. package/skills/ppx-selfheal/SKILL.md +24 -0
  35. package/skills/ppx-selfheal/scripts/cli.js +80 -0
  36. package/skills/ppx-selfheal/scripts/healer.js +184 -0
  37. package/skills/ppx-selfheal/scripts/logger.js +17 -0
  38. package/skills/ppx-selfheal/scripts/store.js +116 -0
  39. package/skills/prompt-depth-kit/SKILL.md +28 -0
  40. package/skills/session-naming/SKILL.md +36 -0
  41. package/skills/verify/SKILL.md +25 -0
  42. package/src/agent/index.js +1340 -717
  43. package/src/agent/prompts.js +47 -3
  44. package/src/aml-server.js +197 -151
  45. package/src/ans/eviction.js +123 -143
  46. package/src/ans/guard.js +159 -120
  47. package/src/ans/lifecycle.js +96 -93
  48. package/src/ans/proactive.js +112 -129
  49. package/src/ans/reward.js +95 -111
  50. package/src/ans/values.js +15 -15
  51. package/src/audit/audit-chain.js +43 -7
  52. package/src/audit/verifier.js +157 -120
  53. package/src/bus/circuit-breaker.js +9 -1
  54. package/src/bus/runtime-bus.js +107 -93
  55. package/src/channels/base.js +57 -34
  56. package/src/channels/feishu.js +118 -126
  57. package/src/channels/http.js +1090 -592
  58. package/src/channels/index.js +111 -110
  59. package/src/channels/log.js +29 -29
  60. package/src/channels/wechat-crypto.js +73 -74
  61. package/src/channels/wechat.js +191 -197
  62. package/src/channels/workspace.js +94 -0
  63. package/src/channels-cli.js +126 -124
  64. package/src/cli.js +129 -120
  65. package/src/commands/index.js +142 -0
  66. package/src/config/channels.js +137 -170
  67. package/src/config/index.js +277 -224
  68. package/src/config/placeholder.js +31 -0
  69. package/src/config/providers.js +148 -188
  70. package/src/config/settings.js +156 -182
  71. package/src/core/policy.js +69 -18
  72. package/src/core/trace.js +8 -6
  73. package/src/edit/editblock.js +266 -0
  74. package/src/edit/snapshot.js +67 -0
  75. package/src/evidence/index.js +153 -0
  76. package/src/evolve/playbook.js +9 -10
  77. package/src/hooks/index.js +113 -0
  78. package/src/llm/client.js +188 -446
  79. package/src/llm/dsml.js +74 -74
  80. package/src/llm/embedder.js +41 -35
  81. package/src/llm/fence.js +52 -105
  82. package/src/llm/index.js +4 -4
  83. package/src/llm/local-embedder.js +94 -0
  84. package/src/llm/presets.js +113 -0
  85. package/src/llm/pricing.js +93 -0
  86. package/src/llm/retry.js +73 -73
  87. package/src/llm/router.js +92 -97
  88. package/src/mcp/admin.js +326 -0
  89. package/src/mcp/client.js +487 -375
  90. package/src/mcp/http.js +203 -0
  91. package/src/mcp/index.js +116 -116
  92. package/src/mcp/server.js +392 -0
  93. package/src/mcp/tasks.js +133 -0
  94. package/src/memory/asset-hub.js +6 -11
  95. package/src/memory/canvas.js +2 -5
  96. package/src/memory/compaction.js +28 -28
  97. package/src/memory/experience.js +133 -122
  98. package/src/memory/fact-store.js +914 -698
  99. package/src/memory/failure-episode.js +20 -11
  100. package/src/memory/fork.js +17 -8
  101. package/src/memory/index.js +8 -6
  102. package/src/memory/l0.js +53 -52
  103. package/src/memory/l2.js +145 -130
  104. package/src/memory/l3.js +111 -111
  105. package/src/memory/legion-board.js +71 -0
  106. package/src/memory/memory-ticker.js +239 -240
  107. package/src/memory/session.js +398 -397
  108. package/src/memory/sqlite-store.js +581 -0
  109. package/src/mode/blackboard.js +49 -49
  110. package/src/mode/graph.js +42 -41
  111. package/src/mode/index.js +64 -64
  112. package/src/mode/legion.js +54 -51
  113. package/src/mode/plan-exec.js +50 -50
  114. package/src/mode/router.js +28 -40
  115. package/src/orchestrator/agent-worker.js +69 -69
  116. package/src/orchestrator/dag.js +90 -83
  117. package/src/orchestrator/experts.js +76 -0
  118. package/src/orchestrator/index.js +1 -1
  119. package/src/orchestrator/legion.js +179 -187
  120. package/src/orchestrator/supervisor.js +6 -8
  121. package/src/permissions/index.js +378 -0
  122. package/src/persona/index.js +28 -29
  123. package/src/plugin/builtin.js +313 -212
  124. package/src/plugin/context.js +80 -79
  125. package/src/plugin/index.js +62 -62
  126. package/src/plugin/v3.js +73 -0
  127. package/src/protocol/index.js +148 -0
  128. package/src/repomap/index.js +309 -0
  129. package/src/review/index.js +393 -0
  130. package/src/seam/registry.js +3 -0
  131. package/src/seam/shell.js +55 -55
  132. package/src/security/injection.js +79 -0
  133. package/src/selfheal/evolve.js +67 -67
  134. package/src/selfheal/healer.js +184 -167
  135. package/src/selfheal/run.js +9 -9
  136. package/src/server.js +63 -60
  137. package/src/services/diagnose.js +180 -0
  138. package/src/services/learning-service.js +9 -0
  139. package/src/services/memory-health.js +34 -6
  140. package/src/services/memory-service.js +42 -9
  141. package/src/services/triage.js +138 -0
  142. package/src/session/parts.js +76 -0
  143. package/src/session/projection.js +73 -0
  144. package/src/session/rollout.js +54 -0
  145. package/src/session/turn.js +137 -0
  146. package/src/skills/lint.js +72 -0
  147. package/src/skills/loader.js +231 -150
  148. package/src/skills/search.js +58 -0
  149. package/src/skills/verify.js +95 -100
  150. package/src/tools/advanced.js +388 -352
  151. package/src/tools/builtin.js +384 -297
  152. package/src/tools/catalog.js +283 -159
  153. package/src/tools/command-guard.js +112 -112
  154. package/src/tools/custom.js +47 -47
  155. package/src/tools/delegate.js +383 -297
  156. package/src/tools/document.js +254 -253
  157. package/src/tools/git.js +151 -0
  158. package/src/tools/governance.js +47 -20
  159. package/src/tools/index.js +16 -11
  160. package/src/tools/methods.js +178 -178
  161. package/src/tools/ocr.js +59 -59
  162. package/src/tools/sandbox-worker.js +40 -0
  163. package/src/tools/sandbox.js +92 -0
  164. package/src/tools/seam.js +162 -125
  165. package/src/tools/selfmod.js +196 -176
  166. package/src/tools/v3.js +225 -0
  167. package/src/tools/vad.js +176 -0
  168. package/src/tools/voice.js +238 -0
  169. package/src/utils/async.js +14 -0
  170. package/src/utils/config-file.js +53 -0
  171. package/src/utils/crashguard.js +88 -0
  172. package/src/utils/http.js +53 -0
  173. package/src/utils/id.js +8 -0
  174. package/src/utils/json-state.js +33 -0
  175. package/src/utils/logger.js +17 -17
  176. package/src/utils/ndjson.js +25 -0
  177. package/src/utils/pii.js +42 -42
  178. package/src/utils/rate-limit.js +50 -0
  179. package/src/utils/schema.js +80 -0
  180. package/src/utils/similarity.js +43 -0
  181. package/src/utils/store.js +170 -108
  182. package/src/utils/text.js +15 -15
  183. package/src/utils/trace.js +153 -153
  184. package/src/utils/wal.js +39 -0
  185. package/src/utils/winutf8.js +16 -15
  186. package/src/wiki/index.js +170 -0
@@ -1,212 +1,313 @@
1
- // src/plugin/builtin.js - 皮皮虾内置插件集 (一切皆插件)
2
- // 借鉴 deepseek-harness 的 "everything is a plugin": 每个模块是一个插件, 通过 ctx.provide 注册服务。
3
- // 装配顺序即依赖顺序 (依赖在前), 任何插件都可被用户插件替换或扩展。
4
- import path from "node:path";
5
- import { Healer } from "../selfheal/healer.js";
6
- import { Persona } from "../persona/index.js";
7
- import { FactStore, MemoryTicker, Experience, L0Recorder, SceneStore, PersonaStore } from "../memory/index.js";
8
- import { SessionStore } from "../memory/session.js";
9
- import {
10
- ToolCatalog, registerBuiltinTools, registerAdvancedTools, Scheduler,
11
- registerMethodTools, registerSelfmodTools, registerCustomTools, registerDocumentTools,
12
- registerGovernanceTools,
13
- } from "../tools/index.js";
14
- import { embedderFromConfig } from "../llm/embedder.js";
15
- import { LocalShellProvider } from "../seam/shell.js";
16
- import { registerDelegateTools } from "../tools/delegate.js";
17
- import { Traces } from "../utils/trace.js";
18
- import { AuditLog } from "../audit/audit-chain.js";
19
- import { RuntimeBus } from "../bus/runtime-bus.js";
20
- import { PlaybookStore } from "../evolve/playbook.js";
21
- import { MemoryHealthMonitor } from "../services/memory-health.js";
22
- import { FailureEpisodeStore } from "../memory/failure-episode.js";
23
- import { CanvasStore } from "../memory/canvas.js";
24
- import { AssetHub } from "../memory/asset-hub.js";
25
- import { exportMemorySnapshot, mergeSnapshotBack, hasSnapshot } from "../memory/fork.js";
26
-
27
- // fork 工具 (供 ctx.consume("fork") 取用)
28
- const forkTools = { exportMemorySnapshot, mergeSnapshotBack, hasSnapshot };
29
- export { isUsableProvider, resolveLLM, resolveAllLLMs } from "../llm/router.js";
30
- import { ModeRegistry, registerDefaultModes } from "../mode/index.js";
31
- import { planExecExecutor } from "../mode/plan-exec.js";
32
- import { routerExecutor } from "../mode/router.js";
33
- import { blackboardExecutor } from "../mode/blackboard.js";
34
- import { graphExecutor } from "../mode/graph.js";
35
- import { legionExecutor } from "../mode/legion.js";
36
-
37
- // ---- LLM 路由 (唯一真相源已迁至 src/llm/router.js, 此文件仅 re-export 向后兼容) ----
38
- // router.js 负责: 占位死配置过滤 / 云端真key优先 / 本地零配置兜底 / 健康排序 / PPX_PROVIDER 强制
39
- // 此处保留导出名, agent/热重载/插件继续用 builtin.resolveLLM 等旧引用。
40
-
41
- // ---- 内置插件: 每个 (ctx) => void, 用 ctx.provide 注册服务 ----
42
-
43
-
44
- export const busPlugin = (ctx) => {
45
- // ②循环系: 全局 Runtime 总线。必须最先装配, 其他插件可 ctx.consume("bus") 挂订阅/注册命令。
46
- const bus = new RuntimeBus();
47
- ctx.provide("bus", bus);
48
- // 状态槽: sessionKey 归属 (给观测/审计看当前活跃会话)
49
- bus.set("bootedAt", Date.now());
50
- return bus;
51
- };
52
-
53
- export const healerPlugin = (ctx) => {
54
- const healer = new Healer(ctx.consume("root"));
55
- healer.markDirty();
56
- const health = healer.heal();
57
- ctx.provide("healer", healer);
58
- ctx.provide("health", health);
59
- };
60
-
61
- export const personaPlugin = (ctx) => {
62
- ctx.provide("persona", new Persona(ctx.consume("root")));
63
- };
64
-
65
- export const factsPlugin = (ctx) => {
66
- const config = ctx.consume("config");
67
- ctx.provide("facts", new FactStore(ctx.consume("dataDir"), config.memory || {}));
68
- };
69
-
70
- export const experiencePlugin = (ctx) => {
71
- // 经验库走全局共享目录 (ANS 全局记忆): 跨 agent 共享经验, 写入用文件锁防并发覆盖
72
- ctx.provide("experience", new Experience(ctx.consume("globalDataDir") || ctx.consume("dataDir")));
73
- };
74
-
75
- export const sessionPlugin = (ctx) => {
76
- const config = ctx.consume("config");
77
- const sessions = new SessionStore(ctx.consume("dataDir"));
78
- // 启动时清理过期会话 (config.memory.session_max_age_days, 默认 30; 0/负=不清理)
79
- const maxAge = Number(config.memory?.session_max_age_days ?? 30);
80
- if (maxAge > 0) {
81
- const removed = sessions.pruneOld({ maxAgeDays: maxAge });
82
- if (removed.length) info(`[sessions] 清理过期会话 ${removed.length} 个: ${removed.join(", ")}`);
83
- }
84
- ctx.provide("sessions", sessions);
85
- };
86
-
87
- export const memoryPlugin = (ctx) => {
88
- const facts = ctx.consume("facts");
89
- const sessions = ctx.consume("sessions");
90
- ctx.provide("memory", new MemoryTicker(ctx.consume("dataDir"), facts, null, sessions));
91
- };
92
-
93
- export const llmPlugin = (ctx) => {
94
- const config = ctx.consume("config");
95
- ctx.provide("llm", resolveLLM(config));
96
- ctx.provide("allProviders", resolveAllLLMs(config));
97
- };
98
-
99
- export const memoryLayersPlugin = (ctx) => {
100
- const sessions = ctx.consume("sessions");
101
- const dataDir = ctx.consume("dataDir");
102
- const userName = ctx.consume("userName") || "兄弟";
103
- ctx.provide("l0", new L0Recorder(sessions, dataDir));
104
- ctx.provide("scenes", new SceneStore(dataDir));
105
- ctx.provide("personaStore", new PersonaStore(dataDir, { userName }));
106
- };
107
-
108
- export const tracesPlugin = (ctx) => {
109
- ctx.provide("traces", new Traces(ctx.consume("dataDir")));
110
- };
111
-
112
- export const auditPlugin = (ctx) => {
113
- // 审计哈希链 (吸收自 ppx-v2): append-only + SHA-256 链式防篡改账本。
114
- // 与 core/trace.js 的事件流互补 —— trace 面向"可观测", audit 面向"可追责/防篡改"。
115
- // config.audit.enabled === false 时关闭 (供性能敏感场景), 默认开启。
116
- const config = ctx.consume("config");
117
- if (config?.audit?.enabled === false) {
118
- ctx.provide("audit", null);
119
- return null;
120
- }
121
- const audit = new AuditLog(ctx.consume("dataDir"));
122
- ctx.provide("audit", audit);
123
- return audit;
124
- };
125
-
126
- export const toolsPlugin = (ctx) => {
127
- const root = ctx.consume("root");
128
- const dataDir = ctx.consume("dataDir");
129
- const config = ctx.consume("config");
130
- const facts = ctx.consume("facts");
131
- const memory = ctx.consume("memory");
132
- const tools = new ToolCatalog();
133
- registerBuiltinTools(tools, { rootDir: root, facts, memory });
134
- const scheduler = new Scheduler(dataDir);
135
- ctx.provide("scheduler", scheduler);
136
- registerAdvancedTools(tools, { dataDir, scheduler, onMemoryNote: (note) => facts.add(note, { source: "schedule" }) });
137
- registerMethodTools(tools);
138
- registerSelfmodTools(tools, { skillsDir: path.join(root, "skills") });
139
- // 用户自定义工具 (不改源码扩展能力)
140
- const customDir = path.join(root, (config.tools && config.tools.custom_dir) || "custom-tools");
141
- registerCustomTools(tools, customDir);
142
- // 文档加载器 (RAG: read_document / ingest_document)
143
- registerDocumentTools(tools, { rootDir: root });
144
- // 向量化: 配了 config.embedding 则自动注入 embedder, 检索切 dense+BM25 RRF; 否则纯 BM25 兜底
145
- const embedder = embedderFromConfig(config);
146
- if (embedder) facts.setEmbedder(embedder);
147
- // 多 agent 自主协作: spawn_agent 工具 (agent 自主派生子 agent 分工)
148
- registerDelegateTools(tools, {});
149
- // Shell 能力 seam: 命令执行解耦为可替换 provider (本地/未来沙箱/Docker)
150
- ctx.provide("shell", new LocalShellProvider());
151
- // 审计哈希链接入工具执行收口 (未启用时为 null, catalog 内部零开销跳过)
152
- tools.setAudit(ctx.consume("audit"));
153
- // 记忆治理 + 审计校验 + 运维工具 (吸收自 ppx-v2, 共 10 个)
154
- registerGovernanceTools(tools, {
155
- rootDir: root,
156
- dataDir,
157
- facts,
158
- audit: ctx.consume("audit"),
159
- personaStore: ctx.consume("personaStore"),
160
- healer: ctx.consume("healer"),
161
- experience: ctx.consume("experience"),
162
- });
163
- ctx.provide("tools", tools);
164
- ctx.provide("toolsEnabled", config.tools?.enabled !== false);
165
- };
166
-
167
- export const modePlugin = (ctx) => {
168
- const registry = new ModeRegistry();
169
- registerDefaultModes(registry);
170
- // 更多编排模式 (可插拔): plan-exec / router / blackboard / graph
171
- registry.register("plan-exec", planExecExecutor);
172
- registry.register("router", routerExecutor);
173
- registry.register("blackboard", blackboardExecutor);
174
- registry.register("graph", graphExecutor);
175
- registry.register("legion", legionExecutor);
176
- ctx.provide("modes", registry);
177
- };
178
-
179
- // P2⑧: 内置插件权限位 (函数外赋值, compose 调用前即可读)
180
- // tools/shell 属敏感服务 (SENSITIVE_SERVICES), 需 full-access
181
- toolsPlugin.access = "full-access";
182
-
183
- export const evolvePlugin = (ctx) => {
184
- // P1④⑤⑥: 进化系插件 —— Playbook 引擎 / 记忆健康监控 / 故障记忆
185
- // P2⑥⑦: 符号画布 / 会话 fork 基线
186
- // 提供服务, 消费方按需取用; 未接线时零开销 (不强制)。
187
- const dataDir = ctx.consume("dataDir");
188
- ctx.provide("playbook", new PlaybookStore(dataDir));
189
- ctx.provide("memoryHealth", new MemoryHealthMonitor());
190
- ctx.provide("failures", new FailureEpisodeStore(dataDir));
191
- ctx.provide("canvas", new CanvasStore(dataDir));
192
- ctx.provide("fork", forkTools);
193
- ctx.provide("assets", new AssetHub(dataDir)); // P3⑩: 记忆资产中枢
194
- };
195
-
196
- // 默认内置插件装配顺序 (依赖在前)
197
- export const builtinPlugins = [
198
- busPlugin, // ②循环系: 全局总线必须最先 (依赖在前)
199
- healerPlugin,
200
- personaPlugin,
201
- factsPlugin,
202
- experiencePlugin,
203
- sessionPlugin,
204
- memoryPlugin,
205
- llmPlugin,
206
- memoryLayersPlugin,
207
- tracesPlugin,
208
- auditPlugin, // 审计哈希链 (toolsPlugin 依赖它注入 catalog, 必须在前)
209
- toolsPlugin,
210
- evolvePlugin, // P1: playbook / memoryHealth / failures (tools 之后, 依赖 dataDir)
211
- modePlugin,
212
- ];
1
+ // src/plugin/builtin.js - 皮皮虾内置插件集 (一切皆插件)
2
+ // 借鉴 deepseek-harness 的 "everything is a plugin": 每个模块是一个插件, 通过 ctx.provide 注册服务。
3
+ // 装配顺序即依赖顺序 (依赖在前), 任何插件都可被用户插件替换或扩展。
4
+ import path from "node:path";
5
+ import { info, warn } from "../utils/logger.js";
6
+ import { Healer } from "../selfheal/healer.js";
7
+ import { Persona } from "../persona/index.js";
8
+ import { FactStore, SqliteFactStore, MemoryTicker, Experience, L0Recorder, SceneStore, PersonaStore, LegionBoard } from "../memory/index.js";
9
+ import { SessionStore } from "../memory/session.js";
10
+ import {
11
+ ToolCatalog, registerBuiltinTools, registerAdvancedTools, Scheduler,
12
+ registerMethodTools, registerSelfmodTools, registerCustomTools, registerDocumentTools,
13
+ registerGovernanceTools,
14
+ registerVoiceTools,
15
+ registerSandboxTools,
16
+ registerVadTools,
17
+ } from "../tools/index.js";
18
+ import { embedderFromConfig } from "../llm/embedder.js";
19
+ import { LocalShellProvider } from "../seam/shell.js";
20
+ import { registerDelegateTools } from "../tools/delegate.js";
21
+ import { Traces } from "../utils/trace.js";
22
+ import { AuditLog } from "../audit/audit-chain.js";
23
+ import { RuntimeBus } from "../bus/runtime-bus.js";
24
+ import { PlaybookStore } from "../evolve/playbook.js";
25
+ import { MemoryHealthMonitor } from "../services/memory-health.js";
26
+ import { FailureEpisodeStore } from "../memory/failure-episode.js";
27
+ import { CanvasStore } from "../memory/canvas.js";
28
+ import { AssetHub } from "../memory/asset-hub.js";
29
+ import { exportMemorySnapshot, mergeSnapshotBack, hasSnapshot } from "../memory/fork.js";
30
+ // v3.0 (codex 对齐): 新工具 (repo_map/apply_patch/review_code/goal_board)
31
+ import { registerV3Tools } from "../tools/v3.js";
32
+ // v3.0.1 (GitHub 主流 Agent 对标): git 集成工具 (aider/Claude Code/OpenHands 标配, 带硬护栏)
33
+ import { registerGitTools } from "../tools/git.js";
34
+
35
+ // fork 工具 (供 ctx.consume("fork") 取用)
36
+ const forkTools = { exportMemorySnapshot, mergeSnapshotBack, hasSnapshot };
37
+ // LLM 路由: import 本地绑定 + re-export 向后兼容 (v2.5.0 修复: 仅 export-from 不产生本地绑定,
38
+ // 导致 llmPlugin 里 resolveLLM/resolveAllLLMs 未定义, 插件装配被隔离且 LLM 实际未注入)
39
+ import { isUsableProvider, resolveLLM, resolveAllLLMs } from "../llm/router.js";
40
+ export { isUsableProvider, resolveLLM, resolveAllLLMs };
41
+ import { ModeRegistry, registerDefaultModes } from "../mode/index.js";
42
+ import { planExecExecutor } from "../mode/plan-exec.js";
43
+ import { routerExecutor } from "../mode/router.js";
44
+ import { blackboardExecutor } from "../mode/blackboard.js";
45
+ import { graphExecutor } from "../mode/graph.js";
46
+ import { legionExecutor } from "../mode/legion.js";
47
+
48
+ // ---- LLM 路由 (唯一真相源已迁至 src/llm/router.js, 此文件仅 re-export 向后兼容) ----
49
+ // router.js 负责: 占位死配置过滤 / 云端真key优先 / 本地零配置兜底 / 健康排序 / PPX_PROVIDER 强制
50
+ // 此处保留导出名, agent/热重载/插件继续用 builtin.resolveLLM 等旧引用。
51
+
52
+ // ---- 内置插件: 每个 (ctx) => void, 用 ctx.provide 注册服务 ----
53
+
54
+
55
+ export const busPlugin = (ctx) => {
56
+ // ②循环系: 全局 Runtime 总线。必须最先装配, 其他插件可 ctx.consume("bus") 挂订阅/注册命令。
57
+ const bus = new RuntimeBus();
58
+ ctx.provide("bus", bus);
59
+ // 状态槽: sessionKey 归属 (给观测/审计看当前活跃会话)
60
+ bus.set("bootedAt", Date.now());
61
+ return bus;
62
+ };
63
+
64
+ export const healerPlugin = (ctx) => {
65
+ // v1.0.8 修复 (P1-2): 必须传真实数据目录, 否则自愈体检/崩溃标记会落到 root/data 硬编码路径,
66
+ // 在 PPX_DATA_DIR 自定义时与真实数据目录分叉 (详见 selfheal/healer.js 注释)。
67
+ const healer = new Healer(ctx.consume("root"), ctx.consume("dataDir"));
68
+ healer.markDirty();
69
+ const health = healer.heal();
70
+ ctx.provide("healer", healer);
71
+ ctx.provide("health", health);
72
+ };
73
+
74
+ export const personaPlugin = (ctx) => {
75
+ ctx.provide("persona", new Persona(ctx.consume("root")));
76
+ };
77
+
78
+ export const factsPlugin = (ctx) => {
79
+ const config = ctx.consume("config");
80
+ const dataDir = ctx.consume("dataDir");
81
+ // 记忆后端选择 (2026-10-03): "json" (默认, 向后兼容) | "sqlite" (内嵌库, FTS5+WAL) | "auto" (优先 sqlite)
82
+ // 选 sqlite 的收益: 增量写 (实测 800 条 18.7x 更快, JSON 版每次 add 都全量重写)、
83
+ // 事务级并发安全 (无文件锁忙等)、崩溃可恢复 (WAL)、数据量增大时检索不退化 (JSON 版全量重扫)。
84
+ // 代价: 文件体积更大 (FTS 索引+WAL), 依赖 Node >= 22.5 的 node:sqlite (不可用会自动回落 JSON)。
85
+ const backend = String(config.memory?.backend || "json").toLowerCase();
86
+ let facts = null;
87
+ if (backend === "sqlite" || backend === "auto") {
88
+ try {
89
+ facts = new SqliteFactStore(dataDir, config.memory || {});
90
+ info(`[memory] 记忆后端: SQLite 内嵌库 (FTS5=${facts.ftsReady}, WAL)`);
91
+ } catch (e) {
92
+ warn(`[memory] SQLite 后端不可用, 回落 JSON: ${e.message}`);
93
+ }
94
+ }
95
+ if (!facts) {
96
+ // 2026-10-03 深度优化 (P2 写放大): 主链路默认开启 FactStore WAL 增量落盘 ——
97
+ // 原默认每次变更全量原子重写 facts.json (高频对话下写放大显著, SQLite 注释自认 18.7x 差距)。
98
+ // WAL 模式: 变更走追加日志, 达阈值才 compact 全量写。仅主链路开启 (轻量构造/测试保持旧行为);
99
+ // config.memory.wal 可显式关。agent.shutdown 时 flush 兜底。
100
+ facts = new FactStore(dataDir, { wal: true, walThreshold: 50, ...(config.memory || {}) });
101
+ if (backend === "sqlite") warn("[memory] 显式指定了 sqlite 后端但不可用, 已回落 JSON");
102
+ }
103
+ ctx.provide("facts", facts);
104
+ };
105
+
106
+ export const experiencePlugin = (ctx) => {
107
+ // 经验库走全局共享目录 (ANS 全局记忆): 跨 agent 共享经验, 写入用文件锁防并发覆盖
108
+ ctx.provide("experience", new Experience(ctx.consume("globalDataDir") || ctx.consume("dataDir")));
109
+ };
110
+
111
+ export const legionBoardPlugin = (ctx) => {
112
+ // 军团共享记忆板 (2026-10-02): 走全局共享目录, 主 agent 与 worker 实时互通
113
+ ctx.provide("legionBoard", new LegionBoard(ctx.consume("globalDataDir") || ctx.consume("dataDir")));
114
+ };
115
+
116
+ export const sessionPlugin = (ctx) => {
117
+ const config = ctx.consume("config");
118
+ const sessions = new SessionStore(ctx.consume("dataDir"));
119
+ // 启动时清理过期会话 (config.memory.session_max_age_days, 默认 30; 0/负=不清理)
120
+ const maxAge = Number(config.memory?.session_max_age_days ?? 30);
121
+ if (maxAge > 0) {
122
+ const removed = sessions.pruneOld({ maxAgeDays: maxAge });
123
+ if (removed.length) info(`[sessions] 清理过期会话 ${removed.length} 个: ${removed.join(", ")}`);
124
+ }
125
+ ctx.provide("sessions", sessions);
126
+ };
127
+
128
+ export const memoryPlugin = (ctx) => {
129
+ const facts = ctx.consume("facts");
130
+ const sessions = ctx.consume("sessions");
131
+ ctx.provide("memory", new MemoryTicker(ctx.consume("dataDir"), facts, null, sessions));
132
+ };
133
+
134
+ export const llmPlugin = (ctx) => {
135
+ const config = ctx.consume("config");
136
+ ctx.provide("llm", resolveLLM(config));
137
+ ctx.provide("allProviders", resolveAllLLMs(config));
138
+ };
139
+
140
+ export const memoryLayersPlugin = (ctx) => {
141
+ const sessions = ctx.consume("sessions");
142
+ const dataDir = ctx.consume("dataDir");
143
+ const userName = ctx.consume("userName") || "兄弟";
144
+ ctx.provide("l0", new L0Recorder(sessions, dataDir));
145
+ ctx.provide("scenes", new SceneStore(dataDir));
146
+ ctx.provide("personaStore", new PersonaStore(dataDir, { userName }));
147
+ };
148
+
149
+ export const tracesPlugin = (ctx) => {
150
+ ctx.provide("traces", new Traces(ctx.consume("dataDir")));
151
+ };
152
+
153
+ export const auditPlugin = (ctx) => {
154
+ // 审计哈希链 (吸收自 ppx-v2): append-only + SHA-256 链式防篡改账本。
155
+ // 与 core/trace.js 的事件流互补 —— trace 面向"可观测", audit 面向"可追责/防篡改"。
156
+ // config.audit.enabled === false 时关闭 (供性能敏感场景), 默认开启。
157
+ const config = ctx.consume("config");
158
+ if (config?.audit?.enabled === false) {
159
+ ctx.provide("audit", null);
160
+ return null;
161
+ }
162
+ const audit = new AuditLog(ctx.consume("dataDir"));
163
+ ctx.provide("audit", audit);
164
+ return audit;
165
+ };
166
+
167
+ export const toolsPlugin = (ctx) => {
168
+ const root = ctx.consume("root");
169
+ const dataDir = ctx.consume("dataDir");
170
+ const config = ctx.consume("config");
171
+ const facts = ctx.consume("facts");
172
+ const memory = ctx.consume("memory");
173
+ const tools = new ToolCatalog();
174
+ registerBuiltinTools(tools, { rootDir: root, facts, memory });
175
+ // 2026-09-18: onFire 兜底 —— 重启恢复的持久化任务无 action 闭包, 触发时按 job.name 还原行为
176
+ const scheduler = new Scheduler(dataDir, { onFire: (job) => facts.add(`定时任务触发: ${job?.name || "?"}`, { source: "schedule" }) });
177
+ ctx.provide("scheduler", scheduler);
178
+ registerAdvancedTools(tools, { dataDir, scheduler, onMemoryNote: (note) => facts.add(note, { source: "schedule" }) });
179
+ registerMethodTools(tools);
180
+ registerSelfmodTools(tools, { skillsDir: path.join(root, "skills") });
181
+ // 用户自定义工具 (不改源码扩展能力)
182
+ const customDir = path.join(root, (config.tools && config.tools.custom_dir) || "custom-tools");
183
+ registerCustomTools(tools, customDir);
184
+ // 文档加载器 (RAG: read_document / ingest_document)
185
+ registerDocumentTools(tools, { rootDir: root });
186
+ // 语音能力 (ASR voice_transcribe / TTS voice_speak): 走 OpenAI 兼容端点, 零依赖
187
+ // v3.1: voice.asr 支持 backend:"local" (nodejs-whisper 可选依赖, 离线转写)
188
+ registerVoiceTools(tools, { config, rootDir: root });
189
+ // v3.1 新能力: 内置 JS 沙箱执行器 (CodeAct, 零依赖) + 语音活动检测 (VAD)
190
+ registerSandboxTools(tools, { rootDir: root });
191
+ registerVadTools(tools, { rootDir: root });
192
+ // 向量化: 配了 config.embedding 则自动注入 embedder, 检索切 dense+BM25 RRF; 否则纯 BM25 兜底
193
+ const embedder = embedderFromConfig(config);
194
+ if (embedder) facts.setEmbedder(embedder);
195
+ // 军团共享记忆板 (2026-10-02): 所有 agent (主 + worker) 实时共享知识
196
+ const board = ctx.consume("legionBoard");
197
+ // 多 agent 自主协作: spawn_agent 工具 (agent 自主派生子 agent 分工)
198
+ // 传入军团记忆板: share_board 自动发布子任务结论 + 仲裁前自动读板
199
+ registerDelegateTools(tools, { board });
200
+ if (board) {
201
+ const fromName = () => ctx.consume("agent")?.config?.agent?.name || "main";
202
+ tools.register({
203
+ name: "board_publish",
204
+ description: "向军团共享记忆板发布一条知识/发现/结论, 所有 agent 实时可见。跨 agent 协作时用。",
205
+ parameters: {
206
+ type: "object",
207
+ properties: {
208
+ topic: { type: "string", description: "频道/主题 (如 数据分析/代码审查), 默认 general" },
209
+ content: { type: "string", description: "要共享的内容" },
210
+ tags: { type: "array", items: { type: "string" }, description: "检索标签, 可选" },
211
+ },
212
+ required: ["content"],
213
+ },
214
+ execute: async (args) => {
215
+ try {
216
+ const e = board.publish({ from: fromName(), topic: args.topic, content: args.content, tags: args.tags });
217
+ return JSON.stringify({ ok: true, id: e.id });
218
+ } catch (e) { return JSON.stringify({ error: e.message }); }
219
+ },
220
+ });
221
+ tools.register({
222
+ name: "board_query",
223
+ description: "查询军团共享记忆板: 看其他 agent 发布的知识/发现/结论 (实时, 跨进程)。",
224
+ parameters: {
225
+ type: "object",
226
+ properties: {
227
+ q: { type: "string", description: "关键词 (匹配内容/主题/标签)" },
228
+ topic: { type: "string", description: "按频道过滤, 可选" },
229
+ from: { type: "string", description: "按发布者过滤, 可选" },
230
+ limit: { type: "number", description: "返回条数, 默认 10" },
231
+ },
232
+ },
233
+ execute: async (args) => {
234
+ const rs = board.query(args);
235
+ if (!rs.length) return "(记忆板暂无匹配内容)";
236
+ return rs.map((r) => `- [${r.ts}] ${r.from}@${r.topic}: ${r.content}`).join("\n");
237
+ },
238
+ });
239
+ }
240
+ // Shell 能力 seam: 命令执行解耦为可替换 provider (本地/未来沙箱/Docker)
241
+ ctx.provide("shell", new LocalShellProvider());
242
+ // 审计哈希链接入工具执行收口 (未启用时为 null, catalog 内部零开销跳过)
243
+ tools.setAudit(ctx.consume("audit"));
244
+ // 记忆治理 + 审计校验 + 运维工具 (吸收自 ppx-v2, 共 10 个)
245
+ registerGovernanceTools(tools, {
246
+ rootDir: root,
247
+ dataDir,
248
+ facts,
249
+ audit: ctx.consume("audit"),
250
+ personaStore: ctx.consume("personaStore"),
251
+ healer: ctx.consume("healer"),
252
+ experience: ctx.consume("experience"),
253
+ });
254
+ // v3.0 (codex 对齐): repo_map / apply_patch / review_code / goal_board
255
+ registerV3Tools(tools, { rootDir: root, agent: ctx.consume("agent") });
256
+ // git 集成 (2026-10-01): status/diff/log/commit, 仅 add+commit, 禁 push/reset
257
+ registerGitTools(tools, { rootDir: root });
258
+ ctx.provide("tools", tools);
259
+ ctx.provide("toolsEnabled", config.tools?.enabled !== false);
260
+ };
261
+
262
+ export const modePlugin = (ctx) => {
263
+ const registry = new ModeRegistry();
264
+ registerDefaultModes(registry);
265
+ // 更多编排模式 (可插拔): plan-exec / router / blackboard / graph
266
+ registry.register("plan-exec", planExecExecutor);
267
+ registry.register("router", routerExecutor);
268
+ registry.register("blackboard", blackboardExecutor);
269
+ registry.register("graph", graphExecutor);
270
+ registry.register("legion", legionExecutor);
271
+ ctx.provide("modes", registry);
272
+ };
273
+
274
+ // P2⑧: 内置插件权限位 (函数外赋值, compose 调用前即可读)
275
+ // tools/shell 属敏感服务 (SENSITIVE_SERVICES), 需 full-access
276
+ toolsPlugin.access = "full-access";
277
+
278
+ export const evolvePlugin = (ctx) => {
279
+ // P1④⑤⑥: 进化系插件 —— Playbook 引擎 / 记忆健康监控 / 故障记忆
280
+ // P2⑥⑦: 符号画布 / 会话 fork 基线
281
+ //
282
+ // ⚠ 接线状态 (2026-09-17 核对): 本插件注册的 6 个服务在 src/ 内**当前均无消费方**
283
+ // (grep consume("playbook"|"memoryHealth"|"failures"|"canvas"|"fork"|"assets") = 0 命中)。
284
+ // 即: 构造它们只有极小的初始化开销, 但没有任何链路在读写 —— 属"能力就绪、未接线"。
285
+ // 保留原因: 单测已覆盖, 且是后续进化的现成骨架。
286
+ // 提醒: 读到本插件的服务不等于功能已生效; 接入消费方 (写入 + 注入) 后才算真正启用。
287
+ const dataDir = ctx.consume("dataDir");
288
+ ctx.provide("playbook", new PlaybookStore(dataDir)); // 预留: 语境 bullets 引擎
289
+ ctx.provide("memoryHealth", new MemoryHealthMonitor()); // 预留: 记忆管线健康
290
+ ctx.provide("failures", new FailureEpisodeStore(dataDir)); // 预留: 故障病历
291
+ ctx.provide("canvas", new CanvasStore(dataDir)); // 预留: 符号画布
292
+ ctx.provide("fork", forkTools); // 预留: 会话 fork 基线 (函数集, 供 spawn 流程调用)
293
+ ctx.provide("assets", new AssetHub(dataDir)); // P3⑩: 记忆资产中枢 (预留)
294
+ };
295
+
296
+ // 默认内置插件装配顺序 (依赖在前)
297
+ export const builtinPlugins = [
298
+ busPlugin, // ②循环系: 全局总线必须最先 (依赖在前)
299
+ healerPlugin,
300
+ personaPlugin,
301
+ factsPlugin,
302
+ experiencePlugin,
303
+ legionBoardPlugin, // 军团共享记忆板 (toolsPlugin 依赖, 必须在前)
304
+ sessionPlugin,
305
+ memoryPlugin,
306
+ llmPlugin,
307
+ memoryLayersPlugin,
308
+ tracesPlugin,
309
+ auditPlugin, // 审计哈希链 (toolsPlugin 依赖它注入 catalog, 必须在前)
310
+ toolsPlugin,
311
+ evolvePlugin, // P1: playbook / memoryHealth / failures (tools 之后, 依赖 dataDir)
312
+ modePlugin,
313
+ ];