@bolloon/bolloon-agent 0.3.37 → 0.3.39

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 (222) hide show
  1. package/README.md +135 -135
  2. package/bin/bolloon-cli.cjs +183 -183
  3. package/bin/bolloon.cjs +0 -0
  4. package/bin/bolloon.js +157 -0
  5. package/dist/agents/constraint-layer.js +19 -19
  6. package/dist/agents/judgment-protocol.js +14 -14
  7. package/dist/agents/loop-review.js +58 -0
  8. package/dist/agents/pi-sdk-tools.js +107 -0
  9. package/dist/agents/pi-sdk-types.js +12 -12
  10. package/dist/agents/pi-sdk.js +133 -91
  11. package/dist/agents/workflow-pivot-loop.js +2 -2
  12. package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
  13. package/dist/bollharness-integration/context-router-judgment.js +4 -4
  14. package/dist/bollharness-integration/context-router.js +292 -292
  15. package/dist/bollharness-integration/gate-state-machine.js +13 -13
  16. package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
  17. package/dist/bollharness-integration/skill-adapter.js +21 -21
  18. package/dist/bootstrap/bootstrap.js +14 -1
  19. package/dist/bootstrap/chat-archiver.js +14 -14
  20. package/dist/bootstrap/context-collector.js +5 -1
  21. package/dist/bootstrap/context-os.js +21 -21
  22. package/dist/bootstrap/memory-compressor.js +13 -13
  23. package/dist/cli/ink-app.js +46 -8
  24. package/dist/cli/loading-tui.js +7 -5
  25. package/dist/cli/mention-data.js +2 -1
  26. package/dist/cli-entry.js +37 -37
  27. package/dist/constraint-runtime/setup.js +1 -1
  28. package/dist/constraint-runtime/tools/PolymarketSDK/cancelOrder.d.ts +3 -13
  29. package/dist/constraint-runtime/tools/PolymarketSDK/cancelOrder.js +4 -16
  30. package/dist/constraint-runtime/tools/PolymarketSDK/createOrder.d.ts +3 -24
  31. package/dist/constraint-runtime/tools/PolymarketSDK/createOrder.js +4 -31
  32. package/dist/constraint-runtime/tools/PolymarketSDK/getMarket.d.ts +0 -1
  33. package/dist/constraint-runtime/tools/PolymarketSDK/getMarket.js +3 -14
  34. package/dist/constraint-runtime/tools/PolymarketSDK/getOrders.d.ts +2 -11
  35. package/dist/constraint-runtime/tools/PolymarketSDK/getOrders.js +4 -23
  36. package/dist/constraint-runtime/tools/PolymarketSDK/listMarkets.d.ts +0 -4
  37. package/dist/constraint-runtime/tools/PolymarketSDK/listMarkets.js +2 -22
  38. package/dist/context-compaction/auto-compact.js +7 -7
  39. package/dist/electron/first-run.js +54 -54
  40. package/dist/electron-build/electron/first-run.js +54 -54
  41. package/dist/electron-build/utils/auto-update.js +8 -0
  42. package/dist/electron-build/utils/auto-update.js.map +1 -1
  43. package/dist/electron-preload.js.map +1 -1
  44. package/dist/electron.js.map +1 -1
  45. package/dist/index.js +246 -143
  46. package/dist/llm/config-store.js +18 -2
  47. package/dist/llm/llm-judgment-client.js +102 -102
  48. package/dist/llm/pi-ai.js +77 -59
  49. package/dist/llm/system-prompt/layers/channel/human-async.md +41 -41
  50. package/dist/llm/system-prompt/layers/channel/local.md +14 -14
  51. package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
  52. package/dist/llm/system-prompt/layers/channel/p2p-peer-sync.md +51 -51
  53. package/dist/llm/system-prompt/layers/channel/p2p-proactive.md +43 -43
  54. package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
  55. package/dist/llm/system-prompt/layers/channel/session-handoff.md +61 -61
  56. package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
  57. package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
  58. package/dist/llm/system-prompt/layers/core/external-engagement.md +73 -73
  59. package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
  60. package/dist/llm/system-prompt/layers/core/identity.md +48 -48
  61. package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
  62. package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
  63. package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
  64. package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
  65. package/dist/llm/system-prompt/layers/core/tone.md +31 -31
  66. package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
  67. package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
  68. package/dist/llm/system-prompt/layers/role/architect.md +20 -20
  69. package/dist/llm/system-prompt/layers/role/expert.md +19 -19
  70. package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
  71. package/dist/llm/system-prompt/layers/role/security.md +15 -15
  72. package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
  73. package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
  74. package/dist/llm/system-prompt/layers/tool/goal_handoff.md +77 -77
  75. package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
  76. package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
  77. package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
  78. package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
  79. package/dist/llm/system-prompt/layers/tool/p2p_request.md +61 -61
  80. package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
  81. package/dist/llm/tool-manifest/ask_user_input.js +1 -1
  82. package/dist/llm/tool-manifest/bash.js +3 -3
  83. package/dist/llm/tool-manifest/create_file.js +4 -4
  84. package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
  85. package/dist/llm/tool-manifest/image_search.js +2 -2
  86. package/dist/llm/tool-manifest/index.js +0 -59
  87. package/dist/llm/tool-manifest/mcp.js +2 -2
  88. package/dist/llm/tool-manifest/message_compose.js +3 -3
  89. package/dist/llm/tool-manifest/places.js +2 -2
  90. package/dist/llm/tool-manifest/present_files.js +1 -1
  91. package/dist/llm/tool-manifest/recipe.js +2 -2
  92. package/dist/llm/tool-manifest/str_replace.js +5 -5
  93. package/dist/llm/tool-manifest/view.js +3 -3
  94. package/dist/llm/tool-manifest/weather.js +4 -4
  95. package/dist/llm/tool-manifest/web.js +4 -4
  96. package/dist/migration/external-agent-migrator.js +300 -0
  97. package/dist/pi-ecosystem-colony/index.js +365 -0
  98. package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
  99. package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
  100. package/dist/pi-ecosystem-judgment/distillation.js +14 -14
  101. package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
  102. package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
  103. package/dist/security/context-router-tool.js +15 -15
  104. package/dist/security/tool-gate.js +2 -0
  105. package/dist/social/ant-colony/AdaptiveHeartbeat.js +101 -0
  106. package/dist/social/ant-colony/PheromoneEngine.js +227 -0
  107. package/dist/social/ant-colony/index.js +6 -0
  108. package/dist/social/ant-colony/types.js +24 -0
  109. package/dist/test/ai-judgment-test.js +80 -0
  110. package/dist/test/bollharness-integration.test.js +318 -0
  111. package/dist/test/channel-agent-multi-dialogue.js +205 -0
  112. package/dist/test/channel-heartbeat-agent-test.js +201 -0
  113. package/dist/test/constraint-layer.test.js +164 -0
  114. package/dist/test/diap-identity-test.js +172 -0
  115. package/dist/test/diap-quick-test.js +62 -0
  116. package/dist/test/global-shared-context.test.js +315 -0
  117. package/dist/test/harness-judgment-injection.test.js +246 -0
  118. package/dist/test/harness-workflow-integrator-test.js +228 -0
  119. package/dist/test/human-value-store.test.js +243 -0
  120. package/dist/test/hybrid-integration-test.js +118 -0
  121. package/dist/test/hybrid-messenger-verify.js +55 -0
  122. package/dist/test/iroh-bistream-debug.js +38 -0
  123. package/dist/test/iroh-communication.test.js +66 -0
  124. package/dist/test/iroh-debug-test.js +57 -0
  125. package/dist/test/iroh-diap-test.js +71 -0
  126. package/dist/test/iroh-direct-connect.js +55 -0
  127. package/dist/test/iroh-e2e-fixed.js +89 -0
  128. package/dist/test/iroh-e2e-same-process.js +63 -0
  129. package/dist/test/iroh-e2e.js +66 -0
  130. package/dist/test/iroh-final-e2e.js +72 -0
  131. package/dist/test/iroh-relay-test.js +37 -0
  132. package/dist/test/iroh-simple-test.js +41 -0
  133. package/dist/test/iroh-transport-verify.js +54 -0
  134. package/dist/test/iroh-transport.test.js +37 -0
  135. package/dist/test/iroh-two-nodes.js +70 -0
  136. package/dist/test/iroh-verify.js +44 -0
  137. package/dist/test/judgment-decision.test.js +219 -0
  138. package/dist/test/llm-judgment-integration.test.js +220 -0
  139. package/dist/test/p2p-agent-complex-dialogue.js +385 -0
  140. package/dist/test/p2p-agent-dialogue.js +341 -0
  141. package/dist/test/p2p-agent-full-bidirectional.js +510 -0
  142. package/dist/test/p2p-agent-harness-flow.js +437 -0
  143. package/dist/test/p2p-agent-harness-single.js +143 -0
  144. package/dist/test/p2p-ai-dialogue-test.js +318 -0
  145. package/dist/test/p2p-cid-connect-test.js +195 -0
  146. package/dist/test/p2p-connect-receiver.js +69 -0
  147. package/dist/test/p2p-doc-transfer.js +110 -0
  148. package/dist/test/p2p-identity-page-test.js +77 -0
  149. package/dist/test/p2p-iroh-test.js +171 -0
  150. package/dist/test/p2p-minimal-test.js +241 -0
  151. package/dist/test/p2p-node-1.js +148 -0
  152. package/dist/test/p2p-node-2.js +148 -0
  153. package/dist/test/p2p-server.js +281 -0
  154. package/dist/test/p2p-two-nodes-test.js +438 -0
  155. package/dist/test/pi-sdk.test.js +44 -0
  156. package/dist/test/set-persona.js +40 -0
  157. package/dist/test/simple.test.js +9 -0
  158. package/dist/test/storage-integration.test.js +150 -0
  159. package/dist/test/subagent-manager.test.js +276 -0
  160. package/dist/test/test-gate-flow.test.js +81 -0
  161. package/dist/test/workflow-engine.test.js +87 -0
  162. package/dist/test/workflow-pivot-loop.test.js +246 -0
  163. package/dist/utils/auto-update.js +7 -0
  164. package/dist/web/api-config.html +779 -779
  165. package/dist/web/client-hearth.js +10 -10
  166. package/dist/web/components/wallet-viem.mjs +118 -118
  167. package/dist/web/index.html +424 -424
  168. package/dist/web/manifest.json +20 -20
  169. package/dist/web/server.js +13 -13
  170. package/dist/web/style.css +4914 -4914
  171. package/package.json +193 -193
  172. package/scripts/build-cli.js +215 -215
  173. package/scripts/build-web.ts +130 -130
  174. package/scripts/postinstall.js +152 -152
  175. package/bin/bolloon-daemon.sh +0 -207
  176. package/dist/constraint-runtime/reference_data/archive_surface_snapshot.json +0 -63
  177. package/dist/constraint-runtime/reference_data/commands_snapshot.json +0 -1037
  178. package/dist/constraint-runtime/reference_data/subsystems/assistant.json +0 -8
  179. package/dist/constraint-runtime/reference_data/subsystems/bootstrap.json +0 -8
  180. package/dist/constraint-runtime/reference_data/subsystems/bridge.json +0 -32
  181. package/dist/constraint-runtime/reference_data/subsystems/buddy.json +0 -13
  182. package/dist/constraint-runtime/reference_data/subsystems/cli.json +0 -26
  183. package/dist/constraint-runtime/reference_data/subsystems/components.json +0 -32
  184. package/dist/constraint-runtime/reference_data/subsystems/constants.json +0 -28
  185. package/dist/constraint-runtime/reference_data/subsystems/coordinator.json +0 -8
  186. package/dist/constraint-runtime/reference_data/subsystems/entrypoints.json +0 -15
  187. package/dist/constraint-runtime/reference_data/subsystems/hooks.json +0 -32
  188. package/dist/constraint-runtime/reference_data/subsystems/keybindings.json +0 -21
  189. package/dist/constraint-runtime/reference_data/subsystems/memdir.json +0 -15
  190. package/dist/constraint-runtime/reference_data/subsystems/migrations.json +0 -18
  191. package/dist/constraint-runtime/reference_data/subsystems/moreright.json +0 -8
  192. package/dist/constraint-runtime/reference_data/subsystems/native_ts.json +0 -11
  193. package/dist/constraint-runtime/reference_data/subsystems/outputStyles.json +0 -8
  194. package/dist/constraint-runtime/reference_data/subsystems/plugins.json +0 -9
  195. package/dist/constraint-runtime/reference_data/subsystems/remote.json +0 -11
  196. package/dist/constraint-runtime/reference_data/subsystems/schemas.json +0 -8
  197. package/dist/constraint-runtime/reference_data/subsystems/screens.json +0 -10
  198. package/dist/constraint-runtime/reference_data/subsystems/server.json +0 -10
  199. package/dist/constraint-runtime/reference_data/subsystems/services.json +0 -32
  200. package/dist/constraint-runtime/reference_data/subsystems/skills.json +0 -27
  201. package/dist/constraint-runtime/reference_data/subsystems/state.json +0 -13
  202. package/dist/constraint-runtime/reference_data/subsystems/types.json +0 -18
  203. package/dist/constraint-runtime/reference_data/subsystems/upstreamproxy.json +0 -9
  204. package/dist/constraint-runtime/reference_data/subsystems/utils.json +0 -32
  205. package/dist/constraint-runtime/reference_data/subsystems/vim.json +0 -12
  206. package/dist/constraint-runtime/reference_data/subsystems/voice.json +0 -8
  207. package/dist/constraint-runtime/reference_data/tools_snapshot.json +0 -922
  208. package/dist/constraint-runtime/tools/PolymarketSDK/clobShared.d.ts +0 -50
  209. package/dist/constraint-runtime/tools/PolymarketSDK/clobShared.js +0 -78
  210. package/dist/electron/config.js.map +0 -1
  211. package/dist/electron/dialogs.js.map +0 -1
  212. package/dist/electron/first-run.js.map +0 -1
  213. package/dist/electron/ipc.js.map +0 -1
  214. package/dist/electron/logger.js.map +0 -1
  215. package/dist/electron/main.js.map +0 -1
  216. package/dist/electron/menu.js.map +0 -1
  217. package/dist/electron/paths.js.map +0 -1
  218. package/dist/electron/server.js.map +0 -1
  219. package/dist/electron/tray.js.map +0 -1
  220. package/dist/electron/window.js.map +0 -1
  221. package/dist/utils/auto-update.js.map +0 -1
  222. package/dist/web/client.js.map +0 -7
@@ -48,65 +48,6 @@ export function getToolsByLayer(layerId) {
48
48
  *
49
49
  * 不包含: 完整 parameters schema (那是 PiAI 客户端在调用时读)
50
50
  */
51
- /**
52
- * 把 ToolManifest 转成 OpenAI function calling 格式 (tools 数组)
53
- * 用于 native tool_choice: "auto" 模式, 让 LLM 选择调用.
54
- *
55
- * 注意: 递归处理嵌套参数 (type='object' 的 properties / type='array' 的 items)
56
- */
57
- export function formatForOpenAI(tools) {
58
- const list = tools ?? ALL;
59
- return list.map((t) => {
60
- const properties = {};
61
- const required = [];
62
- for (const p of t.parameters) {
63
- properties[p.name] = convertParameter(p);
64
- if (p.required)
65
- required.push(p.name);
66
- }
67
- return {
68
- type: 'function',
69
- function: {
70
- name: t.id,
71
- description: t.oneLine,
72
- parameters: {
73
- type: 'object',
74
- properties,
75
- required,
76
- },
77
- },
78
- };
79
- });
80
- }
81
- function convertParameter(p) {
82
- const schema = { type: p.type === 'enum' ? 'string' : p.type };
83
- if (p.description)
84
- schema.description = p.description;
85
- if (p.enumValues)
86
- schema.enum = p.enumValues;
87
- if (p.default !== undefined)
88
- schema.default = p.default;
89
- if (p.minimum !== undefined)
90
- schema.minimum = p.minimum;
91
- if (p.maximum !== undefined)
92
- schema.maximum = p.maximum;
93
- if (p.format)
94
- schema.format = p.format;
95
- if (p.type === 'object' && p.properties) {
96
- schema.properties = {};
97
- for (const sub of p.properties) {
98
- schema.properties[sub.name] = convertParameter(sub);
99
- }
100
- }
101
- if (p.type === 'array' && p.items) {
102
- schema.items = convertParameter(p.items);
103
- if (p.minItems !== undefined)
104
- schema.minItems = p.minItems;
105
- if (p.maxItems !== undefined)
106
- schema.maxItems = p.maxItems;
107
- }
108
- return schema;
109
- }
110
51
  export function formatForPrompt(tools) {
111
52
  const list = tools ?? ALL;
112
53
  const lines = [
@@ -15,7 +15,7 @@ export const search_mcp_registry = {
15
15
  parameters: [
16
16
  { name: 'keywords', type: 'array', required: true, description: '搜索关键词', minItems: 1, items: { name: 'kw', type: 'string', required: true, description: '关键词' } }
17
17
  ],
18
- callExample: `[TOOL:search_mcp_registry]
18
+ callExample: `[TOOL:search_mcp_registry]
19
19
  [P:keywords]${'${'}JSON.stringify(["calendar","schedule"])[ENDTOOL]`,
20
20
  layerId: 'tool.mcp_apps',
21
21
  };
@@ -37,7 +37,7 @@ export const suggest_connectors = {
37
37
  parameters: [
38
38
  { name: 'uuids', type: 'array', required: true, description: '从 search_mcp_registry 结果的 directoryUuid 复制', minItems: 1, items: { name: 'u', type: 'string', required: true, description: 'uuid' } }
39
39
  ],
40
- callExample: `[TOOL:suggest_connectors]
40
+ callExample: `[TOOL:suggest_connectors]
41
41
  [P:uuids]${'${'}JSON.stringify(["uuid-from-search-result"])[ENDTOOL]`,
42
42
  layerId: 'tool.mcp_apps',
43
43
  };
@@ -23,9 +23,9 @@ export const message_compose_v1 = {
23
23
  ],
24
24
  } },
25
25
  ],
26
- callExample: `[TOOL:message_compose_v1]
27
- [P:kind]email
28
- [P:summary_title]Follow-up on Q3 review
26
+ callExample: `[TOOL:message_compose_v1]
27
+ [P:kind]email
28
+ [P:summary_title]Follow-up on Q3 review
29
29
  [P:variants]${'${'}JSON.stringify([{"label":"direct","subject":"Quick follow-up","body":"..."}])[ENDTOOL]`,
30
30
  layerId: 'tool.manifest',
31
31
  };
@@ -23,7 +23,7 @@ export const places_search = {
23
23
  { name: 'location_bias_lng', type: 'number', required: false, description: '可选经度' },
24
24
  { name: 'location_bias_radius', type: 'number', required: false, description: '米 (默认 5000)', default: 5000 }
25
25
  ],
26
- callExample: `[TOOL:places_search]
26
+ callExample: `[TOOL:places_search]
27
27
  [P:queries]${'${'}JSON.stringify([{"query":"ramen restaurants Tokyo"}])[ENDTOOL]`,
28
28
  layerId: 'tool.manifest',
29
29
  };
@@ -77,7 +77,7 @@ export const places_map_display_v0 = {
77
77
  { name: 'title', type: 'string', required: false, description: '行程标题' },
78
78
  { name: 'narrative', type: 'string', required: false, description: '行程叙述' },
79
79
  ],
80
- callExample: `[TOOL:places_map_display_v0]
80
+ callExample: `[TOOL:places_map_display_v0]
81
81
  [P:locations]${'${'}JSON.stringify([{"name":"Senso-ji","latitude":35.7148,"longitude":139.7967,"place_id":"ChIJ..."}])[ENDTOOL]`,
82
82
  layerId: 'tool.manifest',
83
83
  };
@@ -15,7 +15,7 @@ export const present_files = {
15
15
  parameters: [
16
16
  { name: 'filepaths', type: 'array', required: true, description: '至少 1 个文件路径', minItems: 1, items: { name: 'path', type: 'string', required: true, description: '容器内路径' } },
17
17
  ],
18
- callExample: `[TOOL:present_files]
18
+ callExample: `[TOOL:present_files]
19
19
  [P:filepaths]${'${'}JSON.stringify(["/home/bolloon/report.md"])[ENDTOOL]`,
20
20
  layerId: 'tool.manifest',
21
21
  };
@@ -33,8 +33,8 @@ export const recipe_display_v0 = {
33
33
  } },
34
34
  { name: 'notes', type: 'string', required: false, description: '附加说明' },
35
35
  ],
36
- callExample: `[TOOL:recipe_display_v0]
37
- [P:title]Pasta
36
+ callExample: `[TOOL:recipe_display_v0]
37
+ [P:title]Pasta
38
38
  [P:ingredients]${'${'}JSON.stringify([{"id":"a1","amount":500,"name":"pasta"}])[ENDTOOL]`,
39
39
  layerId: 'tool.manifest',
40
40
  };
@@ -17,11 +17,11 @@ export const str_replace = {
17
17
  { name: 'new_str', type: 'string', required: true, description: '新字符串 (空字符串 = 删除)', default: '' },
18
18
  { name: 'path', type: 'string', required: true, description: '文件路径' },
19
19
  ],
20
- callExample: `[TOOL:str_replace]
21
- [P:description]修复 typo
22
- [P:old_str]recieve
23
- [P:new_str]receive
24
- [P:path]/home/bolloon/main.py
20
+ callExample: `[TOOL:str_replace]
21
+ [P:description]修复 typo
22
+ [P:old_str]recieve
23
+ [P:new_str]receive
24
+ [P:path]/home/bolloon/main.py
25
25
  [ENDTOOL]`,
26
26
  layerId: 'tool.manifest',
27
27
  };
@@ -16,9 +16,9 @@ export const view = {
16
16
  { name: 'path', type: 'string', required: true, description: '绝对路径' },
17
17
  { name: 'view_range', type: 'array', required: false, description: '[start, end] 1-indexed, end=-1 表示到末尾', minItems: 2, maxItems: 2, items: { name: 'r', type: 'integer', required: true, description: '行号' } }
18
18
  ],
19
- callExample: `[TOOL:view]
20
- [P:description]读 README
21
- [P:path]/home/bolloon/README.md
19
+ callExample: `[TOOL:view]
20
+ [P:description]读 README
21
+ [P:path]/home/bolloon/README.md
22
22
  [ENDTOOL]`,
23
23
  layerId: 'tool.manifest',
24
24
  };
@@ -18,10 +18,10 @@ export const weather_fetch = {
18
18
  { name: 'latitude', type: 'number', required: true, description: '纬度' },
19
19
  { name: 'longitude', type: 'number', required: true, description: '经度' },
20
20
  ],
21
- callExample: `[TOOL:weather_fetch]
22
- [P:location_name]San Francisco, CA
23
- [P:latitude]37.78
24
- [P:longitude]-122.41
21
+ callExample: `[TOOL:weather_fetch]
22
+ [P:location_name]San Francisco, CA
23
+ [P:latitude]37.78
24
+ [P:longitude]-122.41
25
25
  [ENDTOOL]`,
26
26
  layerId: 'tool.manifest',
27
27
  };
@@ -15,8 +15,8 @@ export const web_search = {
15
15
  parameters: [
16
16
  { name: 'query', type: 'string', required: true, description: '搜索查询 (1-6 词最佳)' },
17
17
  ],
18
- callExample: `[TOOL:web_search]
19
- [P:query]S&P 500 current price
18
+ callExample: `[TOOL:web_search]
19
+ [P:query]S&P 500 current price
20
20
  [ENDTOOL]`,
21
21
  layerId: 'tool.web_search',
22
22
  };
@@ -44,8 +44,8 @@ export const web_fetch = {
44
44
  { name: 'web_fetch_rate_limit_key', type: 'string', required: false, description: '速率限制键' },
45
45
  { name: 'web_fetch_rate_limit_dark_launch', type: 'boolean', required: false, description: '速率限制暗启动模式' },
46
46
  ],
47
- callExample: `[TOOL:web_fetch]
48
- [P:url]https://example.com/article
47
+ callExample: `[TOOL:web_fetch]
48
+ [P:url]https://example.com/article
49
49
  [ENDTOOL]`,
50
50
  layerId: 'tool.manifest',
51
51
  };
@@ -0,0 +1,300 @@
1
+ /**
2
+ * migration/external-agent-migrator.ts — 把本机 OpenClaw / Hermes 的智能体数据
3
+ * 按相同格式整理进 Bolloon 系统路径, 实现"无缝兼容" (性格 / 记忆 / 技能 / 文档).
4
+ *
5
+ * 动机 (2026-08-08, v0.3.39):
6
+ * - 用户在本机用 OpenClaw / Hermes 设计了智能体 (人格文档 + 技能 + 记忆 + 文档).
7
+ * - Bolloon 初始化加载时, 希望把这些"别人的系统"的数据按 Bolloon 的既有格式
8
+ * (persona 6 文件 / SKILL.md / memory sessions / context-os 资产) 迁移进来,
9
+ * 这样 Bolloon 能直接加载同一套性格 / 记忆 / 技能, 无缝兼容.
10
+ * - 隐式处理: 启动时静默跑, 失败不影响主流程; 完成后通告给用户 (见 report).
11
+ *
12
+ * 源 → 目标映射 (OpenClaw workspace 布局):
13
+ * - workspace/SOUL.md → persona/<agent>/soul.md
14
+ * - workspace/IDENTITY.md → persona/<agent>/identity.md
15
+ * - workspace/USER.md → persona/<agent>/user.md
16
+ * - workspace/AGENTS.md → persona/<agent>/agent.md
17
+ * - workspace/TOOLS.md → persona/<agent>/project.md
18
+ * - workspace/MEMORY.md → persona/<agent>/wiki.md
19
+ * - workspace/skills/<name>/SKILL.md → ~/.bolloon/skills/<name>/ (整目录复制)
20
+ * - workspace/memory/*.md → ~/.bolloon/memory/<agent>/sessions/<n>.summary.md
21
+ * - workspace/*.md (其它) → ~/.bolloon/context-os/04-Projects/<agent>-docs/
22
+ *
23
+ * 幂等: 每个源落一份 manifest (~/.bolloon/migration/<source>.json),
24
+ * 记录已迁移的文件 hash; 未变化则跳过, 已存在则覆盖源文档 (文档允许演进),
25
+ * 技能只复制新增/变化的 (不删除目标已存在但源已删的, 保守).
26
+ *
27
+ * 安全: 不读取/复制 API key 类文件 (credentials/identity/*auth*), 不碰 secret.
28
+ *
29
+ * 设计范式: 与 external-engines/discovery.ts 一致 — 纯函数 + 可注入 deps, 便于单测.
30
+ */
31
+ import * as fs from 'fs/promises';
32
+ import * as os from 'os';
33
+ import * as path from 'path';
34
+ import * as crypto from 'crypto';
35
+ import { sanitizeAgentId } from '../bootstrap/persona-loader.js';
36
+ // ============================================================
37
+ // 默认 deps (真实 IO)
38
+ // ============================================================
39
+ function realReadFile(p) {
40
+ return fs.readFile(p, 'utf-8').then((c) => c).catch(() => undefined);
41
+ }
42
+ function realReaddir(dir) {
43
+ return fs.readdir(dir).then((c) => c).catch(() => undefined);
44
+ }
45
+ function realStat(p) {
46
+ return fs.stat(p).then((s) => ({ isDirectory: s.isDirectory(), isFile: s.isFile(), mtimeMs: s.mtimeMs })).catch(() => undefined);
47
+ }
48
+ function realExists(p) {
49
+ return fs.access(p).then(() => true).catch(() => false);
50
+ }
51
+ export function defaultDeps() {
52
+ return {
53
+ home: os.homedir(),
54
+ readFile: realReadFile,
55
+ readdir: realReaddir,
56
+ stat: realStat,
57
+ mkdir: async (p) => { await fs.mkdir(p, { recursive: true }); },
58
+ copyFile: (f, t) => fs.copyFile(f, t),
59
+ writeFile: (p, d) => fs.writeFile(p, d, 'utf-8'),
60
+ exists: realExists,
61
+ };
62
+ }
63
+ // ============================================================
64
+ // 纯函数: 目录布局 + hash
65
+ // ============================================================
66
+ /** 各源的根目录 (相对 home) */
67
+ export function sourceRootPath(source, home) {
68
+ return source === 'openclaw'
69
+ ? path.join(home, '.openclaw')
70
+ : path.join(home, '.hermes');
71
+ }
72
+ /** workspace 路径 (openclaw 用 workspace/, hermes 假设平铺在根) */
73
+ export function workspacePath(source, sourceRoot) {
74
+ return source === 'openclaw'
75
+ ? path.join(sourceRoot, 'workspace')
76
+ : sourceRoot;
77
+ }
78
+ /** 计算文件内容 hash (幂等用) */
79
+ export function sha1(content) {
80
+ return crypto.createHash('sha1').update(content).digest('hex');
81
+ }
82
+ /** bolloon 目标根 (默认 ~/.bolloon, 可注入 override) */
83
+ function bolloonRoot(home) {
84
+ return path.join(home, '.bolloon');
85
+ }
86
+ // ============================================================
87
+ // 单文件迁移 helper
88
+ // ============================================================
89
+ async function copyIfNeeded(deps, from, to, manifest) {
90
+ const content = await deps.readFile(from);
91
+ if (content === undefined)
92
+ return false;
93
+ const hash = sha1(content);
94
+ if (manifest.get(to) === hash)
95
+ return false; // 未变化, 跳过
96
+ await deps.mkdir(path.dirname(to));
97
+ await deps.writeFile(to, content);
98
+ manifest.set(to, hash);
99
+ return true;
100
+ }
101
+ async function copyDirIfNeeded(deps, srcDir, destDir, manifest) {
102
+ const copied = [];
103
+ const entries = await deps.readdir(srcDir);
104
+ if (!entries)
105
+ return copied;
106
+ for (const name of entries) {
107
+ const s = path.join(srcDir, name);
108
+ const st = await deps.stat(s);
109
+ if (!st)
110
+ continue;
111
+ if (st.isDirectory) {
112
+ copied.push(...await copyDirIfNeeded(deps, s, path.join(destDir, name), manifest));
113
+ }
114
+ else if (st.isFile) {
115
+ const to = path.join(destDir, name);
116
+ if (await copyIfNeeded(deps, s, to, manifest))
117
+ copied.push(name);
118
+ }
119
+ }
120
+ return copied;
121
+ }
122
+ // ============================================================
123
+ // 主迁移
124
+ // ============================================================
125
+ /** 探测某个源是否安装 (根目录存在) */
126
+ export async function detectSource(deps, source) {
127
+ const root = sourceRootPath(source, deps.home);
128
+ const st = await deps.stat(root);
129
+ if (st?.isDirectory)
130
+ return root;
131
+ return null;
132
+ }
133
+ /**
134
+ * 迁移单个源的全部数据到 Bolloon.
135
+ * 返回 report; 源不存在 → migrated=false 且不抛错 (静默).
136
+ */
137
+ export async function migrateExternalAgent(source, deps = defaultDeps()) {
138
+ const report = {
139
+ source,
140
+ sourceRoot: sourceRootPath(source, deps.home),
141
+ migratedAt: new Date().toISOString(),
142
+ migrated: false,
143
+ personaAgentId: '',
144
+ persona: [],
145
+ skillsCopied: [],
146
+ memoryCopied: [],
147
+ docsCopied: [],
148
+ entries: [],
149
+ errors: [],
150
+ };
151
+ try {
152
+ const root = await detectSource(deps, source);
153
+ if (!root) {
154
+ report.migrated = false;
155
+ return report; // 未安装, 静默
156
+ }
157
+ const ws = workspacePath(source, root);
158
+ const wsStat = await deps.stat(ws);
159
+ if (!wsStat?.isDirectory) {
160
+ report.migrated = false;
161
+ report.errors.push(`workspace 目录不存在: ${ws}`);
162
+ return report;
163
+ }
164
+ // agentId: 用源名 + 目录名 (openclaw main agent) 兜底
165
+ const rawAgent = source === 'openclaw' ? 'main' : 'hermes-main';
166
+ const agentId = sanitizeAgentId(`ext-${source}-${rawAgent}`);
167
+ report.personaAgentId = agentId;
168
+ const bRoot = bolloonRoot(deps.home);
169
+ const personaDir = path.join(bRoot, 'persona', agentId);
170
+ const skillsRoot = path.join(bRoot, 'skills');
171
+ const memoryRoot = path.join(bRoot, 'memory', agentId, 'sessions');
172
+ const docsRoot = path.join(bRoot, 'context-os', '04-Projects', `${source}-docs`);
173
+ // manifest (幂等)
174
+ const manifestFile = path.join(bRoot, 'migration', `${source}.json`);
175
+ const manifest = new Map();
176
+ const prev = await deps.readFile(manifestFile);
177
+ if (prev) {
178
+ try {
179
+ const obj = JSON.parse(prev);
180
+ if (obj && typeof obj === 'object') {
181
+ for (const [k, v] of Object.entries(obj))
182
+ manifest.set(k, String(v));
183
+ }
184
+ }
185
+ catch { /* 损坏忽略, 从头迁 */ }
186
+ }
187
+ await deps.mkdir(path.join(bRoot, 'migration'));
188
+ // 1. persona 6 文件映射
189
+ const personaMap = [
190
+ ['SOUL.md', 'soul.md'],
191
+ ['IDENTITY.md', 'identity.md'],
192
+ ['USER.md', 'user.md'],
193
+ ['AGENTS.md', 'agent.md'],
194
+ ['TOOLS.md', 'project.md'],
195
+ ['MEMORY.md', 'wiki.md'],
196
+ ];
197
+ for (const [fromName, toName] of personaMap) {
198
+ const from = path.join(ws, fromName);
199
+ const to = path.join(personaDir, toName);
200
+ if (await copyIfNeeded(deps, from, to, manifest)) {
201
+ report.persona.push(toName);
202
+ report.entries.push({ from, to, kind: 'persona' });
203
+ }
204
+ }
205
+ // 2. skills: workspace/skills/*/ → ~/.bolloon/skills/<name>/
206
+ const skillsSrc = path.join(ws, 'skills');
207
+ const skillDirs = await deps.readdir(skillsSrc);
208
+ if (skillDirs) {
209
+ for (const dirName of skillDirs) {
210
+ const srcDir = path.join(skillsSrc, dirName);
211
+ const st = await deps.stat(srcDir);
212
+ if (!st?.isDirectory)
213
+ continue;
214
+ if (dirName.startsWith('.'))
215
+ continue;
216
+ const destDir = path.join(skillsRoot, dirName);
217
+ const copied = await copyDirIfNeeded(deps, srcDir, destDir, manifest);
218
+ if (copied.length > 0) {
219
+ report.skillsCopied.push(dirName);
220
+ report.entries.push({ from: srcDir, to: destDir, kind: 'skill' });
221
+ }
222
+ }
223
+ }
224
+ // 3. memory: workspace/memory/*.md → memory/<agent>/sessions/
225
+ const memSrc = path.join(ws, 'memory');
226
+ const memFiles = await deps.readdir(memSrc);
227
+ if (memFiles) {
228
+ let idx = 0;
229
+ for (const f of memFiles) {
230
+ if (!f.endsWith('.md'))
231
+ continue;
232
+ const from = path.join(memSrc, f);
233
+ const to = path.join(memoryRoot, `${idx + 1}-${f}`);
234
+ if (await copyIfNeeded(deps, from, to, manifest)) {
235
+ report.memoryCopied.push(f);
236
+ report.entries.push({ from, to, kind: 'memory' });
237
+ }
238
+ idx++;
239
+ }
240
+ }
241
+ // 4. docs: workspace 根其他 .md → context-os/04-Projects/<source>-docs/
242
+ const wsFiles = await deps.readdir(ws);
243
+ if (wsFiles) {
244
+ const excluded = new Set(['SOUL.md', 'IDENTITY.md', 'USER.md', 'AGENTS.md', 'TOOLS.md', 'MEMORY.md']);
245
+ for (const f of wsFiles) {
246
+ if (!f.endsWith('.md'))
247
+ continue;
248
+ if (excluded.has(f))
249
+ continue;
250
+ const from = path.join(ws, f);
251
+ const st = await deps.stat(from);
252
+ if (!st?.isFile)
253
+ continue;
254
+ const to = path.join(docsRoot, f);
255
+ if (await copyIfNeeded(deps, from, to, manifest)) {
256
+ report.docsCopied.push(f);
257
+ report.entries.push({ from, to, kind: 'docs' });
258
+ }
259
+ }
260
+ }
261
+ // 写回 manifest
262
+ await deps.writeFile(manifestFile, JSON.stringify(Object.fromEntries(manifest), null, 2));
263
+ report.migrated = true;
264
+ return report;
265
+ }
266
+ catch (err) {
267
+ report.errors.push(err.message?.slice(0, 300) || String(err));
268
+ return report;
269
+ }
270
+ }
271
+ /** 一次性迁移所有已安装源 (openclaw + hermes). 隐式, 静默. */
272
+ export async function migrateAllExternalAgents(deps = defaultDeps()) {
273
+ const sources = ['openclaw', 'hermes'];
274
+ const out = [];
275
+ for (const s of sources) {
276
+ const r = await migrateExternalAgent(s, deps);
277
+ if (r.migrated)
278
+ out.push(r);
279
+ }
280
+ return out;
281
+ }
282
+ /** 把迁移结果格式化成给用户看的中文通告 (纯函数, 可单测) */
283
+ export function formatMigrationNotices(reports) {
284
+ const lines = [];
285
+ for (const r of reports) {
286
+ if (!r.migrated)
287
+ continue;
288
+ const parts = [];
289
+ if (r.persona.length)
290
+ parts.push(`性格 ${r.persona.length} 份`);
291
+ if (r.skillsCopied.length)
292
+ parts.push(`技能 ${r.skillsCopied.length} 个`);
293
+ if (r.memoryCopied.length)
294
+ parts.push(`记忆 ${r.memoryCopied.length} 条`);
295
+ if (r.docsCopied.length)
296
+ parts.push(`文档 ${r.docsCopied.length} 份`);
297
+ lines.push(`[迁移:${r.source}] 外部智能体数据已并入 Bolloon (agentId=${r.personaAgentId}): ${parts.join(', ') || '已就绪'}${r.errors.length ? ` (${r.errors.length} 个错误)` : ''}`);
298
+ }
299
+ return lines;
300
+ }