@bolloon/bolloon-agent 0.1.34 → 0.1.36

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 (226) hide show
  1. package/.auto-evolve-calls +1 -0
  2. package/.last-auto-evolve-baseline +1 -0
  3. package/.playwright-mcp/page-2026-06-16T07-51-45-706Z.yml +130 -0
  4. package/.playwright-mcp/page-2026-06-16T07-56-44-116Z.yml +131 -0
  5. package/Bolloon.md +144 -0
  6. package/Dive-into/CITATION.cff +17 -0
  7. package/Dive-into/LICENSE +25 -0
  8. package/Dive-into/README.md +598 -0
  9. package/Dive-into/README_zh.md +599 -0
  10. package/Dive-into/assets/context.png +0 -0
  11. package/Dive-into/assets/extensibility.png +0 -0
  12. package/Dive-into/assets/iteration.png +0 -0
  13. package/Dive-into/assets/layered_architecture.png +0 -0
  14. package/Dive-into/assets/main_structure.png +0 -0
  15. package/Dive-into/assets/permission.png +0 -0
  16. package/Dive-into/assets/session_compact.png +0 -0
  17. package/Dive-into/assets/subagent.png +0 -0
  18. package/Dive-into/paper/Dive_into_Claude_Code.pdf +0 -0
  19. package/README.md +1 -1
  20. package/dist/agents/p2p-chat-tools.js +6 -6
  21. package/dist/agents/permission-mode.js +115 -0
  22. package/dist/agents/pi-sdk.js +687 -25
  23. package/dist/agents/pre-tool-validator.js +194 -0
  24. package/dist/agents/workflow-pivot-loop.js +113 -12
  25. package/dist/bollharness/src/scripts/checks/check_doc_freshness.js +1 -1
  26. package/dist/bollharness/src/scripts/checks/check_doc_links.js +1 -1
  27. package/dist/bollharness/src/scripts/context_router.js +1 -1
  28. package/dist/bollharness/src/scripts/deploy-guard.js +1 -1
  29. package/dist/bollharness/src/scripts/guard_router.js +1 -1
  30. package/dist/bollharness/src/scripts/hooks/_hook_output.js +1 -1
  31. package/dist/bollharness/src/scripts/hooks/risk-tracker.js +1 -1
  32. package/dist/bollharness-integration/context-router.js +2 -2
  33. package/dist/bollharness-integration/guard-checker.js +1 -1
  34. package/dist/bootstrap/bootstrap.js +117 -0
  35. package/dist/bootstrap/context-collector.js +312 -0
  36. package/dist/bootstrap/context-hierarchy.js +218 -0
  37. package/dist/bootstrap/lifecycle-hooks.js +171 -0
  38. package/dist/bootstrap/project-context.js +158 -0
  39. package/dist/context-compaction/auto-compact.js +144 -0
  40. package/dist/context-compaction/budget-gate.js +28 -0
  41. package/dist/context-compaction/budget-reduce.js +35 -0
  42. package/dist/context-compaction/context-collapse.js +66 -0
  43. package/dist/context-compaction/index.js +21 -0
  44. package/dist/context-compaction/microcompact.js +51 -0
  45. package/dist/context-compaction/pipeline.js +123 -0
  46. package/dist/context-compaction/snip.js +45 -0
  47. package/dist/context-compaction/token-estimator.js +35 -0
  48. package/dist/context-compaction/types.js +19 -0
  49. package/dist/heartbeat/HealthMonitor.js +3 -2
  50. package/dist/index.js +49 -2
  51. package/dist/llm/llm-judgment-client.js +32 -30
  52. package/dist/llm/pi-ai.js +125 -28
  53. package/dist/llm/system-prompt/health.js +129 -0
  54. package/dist/llm/system-prompt/registry.js +246 -0
  55. package/dist/llm/system-prompt/strip-hibsml.js +51 -0
  56. package/dist/llm/tool-manifest/ask_user_input.js +35 -0
  57. package/dist/llm/tool-manifest/bash.js +23 -0
  58. package/dist/llm/tool-manifest/create_file.js +24 -0
  59. package/dist/llm/tool-manifest/fetch_sports_data.js +26 -0
  60. package/dist/llm/tool-manifest/image_search.js +24 -0
  61. package/dist/llm/tool-manifest/index.js +69 -0
  62. package/dist/llm/tool-manifest/mcp.js +43 -0
  63. package/dist/llm/tool-manifest/message_compose.js +31 -0
  64. package/dist/llm/tool-manifest/places.js +83 -0
  65. package/dist/llm/tool-manifest/present_files.js +21 -0
  66. package/dist/llm/tool-manifest/recipe.js +40 -0
  67. package/dist/llm/tool-manifest/recommend_apps.js +23 -0
  68. package/dist/llm/tool-manifest/str_replace.js +27 -0
  69. package/dist/llm/tool-manifest/types.js +7 -0
  70. package/dist/llm/tool-manifest/view.js +24 -0
  71. package/dist/llm/tool-manifest/weather.js +27 -0
  72. package/dist/llm/tool-manifest/web.js +51 -0
  73. package/dist/network/p2p-direct.js +23 -0
  74. package/dist/network/source-intent-broadcaster.js +203 -0
  75. package/dist/network/source-intent.js +100 -0
  76. package/dist/pi-ecosystem-judgment/adaptive-scan.js +279 -0
  77. package/dist/pi-ecosystem-judgment/causal-judge.js +449 -0
  78. package/dist/pi-ecosystem-judgment/detect-hook.js +168 -0
  79. package/dist/pi-ecosystem-judgment/distill-prompt.js +226 -0
  80. package/dist/pi-ecosystem-judgment/evolve-judgment.js +170 -0
  81. package/dist/pi-ecosystem-judgment/human-value-pipeline.js +21 -0
  82. package/dist/pi-ecosystem-judgment/human-value-store.js +283 -22
  83. package/dist/pi-ecosystem-judgment/injection-gate.js +208 -0
  84. package/dist/pi-ecosystem-judgment/monitor-gate.js +188 -0
  85. package/dist/pi-ecosystem-judgment/value-injection.js +8 -2
  86. package/dist/security/builtin-guards.js +124 -0
  87. package/dist/security/context-router-tool.js +106 -0
  88. package/dist/security/input-scanner.js +223 -0
  89. package/dist/security/react-harness.js +143 -0
  90. package/dist/security/tool-gate.js +235 -0
  91. package/dist/utils/auto-evolve-policy.js +117 -0
  92. package/dist/utils/clamp.js +7 -0
  93. package/dist/utils/double.js +6 -0
  94. package/dist/web/client.js +3810 -3830
  95. package/dist/web/components/p2p/P2PModal.js +188 -0
  96. package/dist/web/components/p2p/index.js +264 -226
  97. package/dist/web/components/p2p/p2p-modal.js +657 -0
  98. package/dist/web/components/p2p/p2p-tools.js +248 -0
  99. package/dist/web/index.html +60 -49
  100. package/dist/web/server.js +827 -124
  101. package/dist/web/style.css +531 -249
  102. package/dist/web/ui/message-renderer.js +463 -0
  103. package/dist/web/ui/step-timeline.js +375 -0
  104. package/lefthook.yml +33 -0
  105. package/package.json +3 -2
  106. package/scripts/auto-evolve-loop.ts +481 -0
  107. package/scripts/auto-evolve-oneshot.sh +155 -0
  108. package/scripts/auto-evolve-snapshot.sh +136 -0
  109. package/scripts/build-web.ts +35 -1
  110. package/scripts/detect-schema-changes.sh +48 -0
  111. package/scripts/diff-reviewer.ts +159 -0
  112. package/scripts/validate-system-prompt.ts +142 -0
  113. package/scripts/weekly-report.ts +364 -0
  114. package/src/agents/p2p-chat-tools.ts +6 -6
  115. package/src/agents/permission-mode.ts +127 -0
  116. package/src/agents/pi-sdk.ts +741 -30
  117. package/src/agents/pre-tool-validator.ts +213 -0
  118. package/src/agents/workflow-pivot-loop.ts +110 -19
  119. package/src/bollharness/CLAUDE.md +1 -1
  120. package/src/bollharness/README.md +2 -2
  121. package/src/bollharness/README.zh-CN.md +2 -2
  122. package/src/bollharness/reference/boll-reference/scripts/hooks/find-boll-root.sh +2 -2
  123. package/src/bollharness/scripts/context-fragments/truth-source-hierarchy.md +2 -2
  124. package/src/bollharness/scripts/context-fragments/version-sources.md +1 -1
  125. package/src/bollharness/scripts/hooks/find-project-root.sh +4 -4
  126. package/src/bollharness/src/scripts/checks/check_doc_freshness.ts +1 -1
  127. package/src/bollharness/src/scripts/checks/check_doc_links.ts +1 -1
  128. package/src/bollharness/src/scripts/context_router.ts +1 -1
  129. package/src/bollharness/src/scripts/deploy-guard.ts +1 -1
  130. package/src/bollharness/src/scripts/guard_router.ts +1 -1
  131. package/src/bollharness/src/scripts/hooks/_hook_output.ts +1 -1
  132. package/src/bollharness/src/scripts/hooks/risk-tracker.ts +1 -1
  133. package/src/bollharness/templates/scaffold/.gitignore.append +1 -1
  134. package/src/bollharness/templates/scaffold/CLAUDE.md +2 -2
  135. package/src/bollharness-integration/context-router.ts +2 -2
  136. package/src/bollharness-integration/guard-checker.ts +1 -1
  137. package/src/bootstrap/bootstrap.ts +135 -0
  138. package/src/bootstrap/context-collector.ts +371 -0
  139. package/src/bootstrap/context-hierarchy.ts +283 -0
  140. package/src/bootstrap/lifecycle-hooks.ts +289 -0
  141. package/src/bootstrap/project-context.ts +171 -0
  142. package/src/context-compaction/auto-compact.ts +153 -0
  143. package/src/context-compaction/budget-gate.ts +32 -0
  144. package/src/context-compaction/budget-reduce.ts +37 -0
  145. package/src/context-compaction/context-collapse.ts +72 -0
  146. package/src/context-compaction/index.ts +24 -0
  147. package/src/context-compaction/microcompact.ts +54 -0
  148. package/src/context-compaction/pipeline.ts +133 -0
  149. package/src/context-compaction/snip.ts +51 -0
  150. package/src/context-compaction/token-estimator.ts +36 -0
  151. package/src/context-compaction/types.ts +99 -0
  152. package/src/heartbeat/HealthMonitor.ts +3 -2
  153. package/src/index.ts +47 -2
  154. package/src/llm/llm-judgment-client.ts +36 -35
  155. package/src/llm/pi-ai.ts +135 -29
  156. package/src/llm/system-prompt/health.ts +159 -0
  157. package/src/llm/system-prompt/layers/channel/local.md +14 -0
  158. package/src/llm/system-prompt/layers/channel/p2p-agent.md +18 -0
  159. package/src/llm/system-prompt/layers/channel/p2p-visitor.md +19 -0
  160. package/src/llm/system-prompt/layers/core/artifacts_storage.md +89 -0
  161. package/src/llm/system-prompt/layers/core/evenhandedness.md +21 -0
  162. package/src/llm/system-prompt/layers/core/hibs_reminders.md +15 -0
  163. package/src/llm/system-prompt/layers/core/identity.md +37 -0
  164. package/src/llm/system-prompt/layers/core/knowledge.md +17 -0
  165. package/src/llm/system-prompt/layers/core/memory_system.md +12 -0
  166. package/src/llm/system-prompt/layers/core/network_filesystem.md +28 -0
  167. package/src/llm/system-prompt/layers/core/refusal.md +37 -0
  168. package/src/llm/system-prompt/layers/core/tone.md +31 -0
  169. package/src/llm/system-prompt/layers/core/tools.thin.md +13 -0
  170. package/src/llm/system-prompt/layers/core/wellbeing.md +41 -0
  171. package/src/llm/system-prompt/layers/role/architect.md +20 -0
  172. package/src/llm/system-prompt/layers/role/expert.md +19 -0
  173. package/src/llm/system-prompt/layers/role/implementer.md +15 -0
  174. package/src/llm/system-prompt/layers/role/security.md +15 -0
  175. package/src/llm/system-prompt/layers/tool/artifacts.md +72 -0
  176. package/src/llm/system-prompt/layers/tool/bash.md +25 -0
  177. package/src/llm/system-prompt/layers/tool/hibs_api.md +171 -0
  178. package/src/llm/system-prompt/layers/tool/image_search.md +70 -0
  179. package/src/llm/system-prompt/layers/tool/manifest.md +89 -0
  180. package/src/llm/system-prompt/layers/tool/mcp_apps.md +53 -0
  181. package/src/llm/system-prompt/layers/tool/web_search.md +83 -0
  182. package/src/llm/system-prompt/registry.ts +325 -0
  183. package/src/llm/system-prompt/strip-hibsml.ts +52 -0
  184. package/src/llm/tool-manifest/ask_user_input.ts +37 -0
  185. package/src/llm/tool-manifest/bash.ts +25 -0
  186. package/src/llm/tool-manifest/create_file.ts +26 -0
  187. package/src/llm/tool-manifest/fetch_sports_data.ts +28 -0
  188. package/src/llm/tool-manifest/image_search.ts +26 -0
  189. package/src/llm/tool-manifest/index.ts +88 -0
  190. package/src/llm/tool-manifest/mcp.ts +46 -0
  191. package/src/llm/tool-manifest/message_compose.ts +33 -0
  192. package/src/llm/tool-manifest/places.ts +86 -0
  193. package/src/llm/tool-manifest/present_files.ts +23 -0
  194. package/src/llm/tool-manifest/recipe.ts +42 -0
  195. package/src/llm/tool-manifest/recommend_apps.ts +25 -0
  196. package/src/llm/tool-manifest/str_replace.ts +29 -0
  197. package/src/llm/tool-manifest/types.ts +52 -0
  198. package/src/llm/tool-manifest/view.ts +26 -0
  199. package/src/llm/tool-manifest/weather.ts +29 -0
  200. package/src/llm/tool-manifest/web.ts +54 -0
  201. package/src/network/p2p-direct.ts +22 -0
  202. package/src/network/source-intent-broadcaster.ts +242 -0
  203. package/src/network/source-intent.ts +167 -0
  204. package/src/security/builtin-guards.ts +162 -0
  205. package/src/security/context-router-tool.ts +122 -0
  206. package/src/security/input-scanner.ts +287 -0
  207. package/src/security/react-harness.ts +177 -0
  208. package/src/security/tool-gate.ts +294 -0
  209. package/src/utils/auto-evolve-policy.ts +138 -0
  210. package/src/utils/clamp.ts +5 -0
  211. package/src/web/client.js +105 -2187
  212. package/src/web/client.ts +4326 -0
  213. package/src/web/index.html +60 -49
  214. package/src/web/server.ts +894 -148
  215. package/src/web/style.css +531 -249
  216. package/src/web/ui/message-renderer.ts +540 -0
  217. package/src/web/ui/step-timeline.ts +394 -0
  218. package/staging/auto-evolve/clean-001/.review-verdict +9 -0
  219. package/staging/auto-evolve/clean-001/clean-001.patch +14 -0
  220. package/staging/auto-evolve/e2e-001/.patch-id +1 -0
  221. package/staging/auto-evolve/e2e-001/.review-verdict +12 -0
  222. package/staging/auto-evolve/e2e-001/e2e-001.patch +11 -0
  223. package/staging/auto-evolve/test-bad/.review-verdict +12 -0
  224. package/staging/auto-evolve/test-bad/test-bad.patch +11 -0
  225. package/test-results/.last-run.json +6 -0
  226. package/test-results/src-test-web-loop-status-b-5734c-atus-bar-/346/230/276/347/244/272-spinner-/344/270/215/346/230/276/347/244/272/345/276/252/347/216/257/350/256/241/346/225/260/error-context.md +285 -0
@@ -0,0 +1,51 @@
1
+ /**
2
+ * strip-hibsml.ts — 把 hibsml 协议标签转成 bolloon 标记
3
+ *
4
+ * hibsml 是 hibs 的协议: {hibsml:cite} {hibsml:invoke} {hibsml:thinking_mode}
5
+ * bolloon 不解析这些, 但传给 LLM 之前要"金脱除":
6
+ * - cite → [CITE:index]
7
+ * - invoke → 简化
8
+ * - thinking_mode → 注释形式保留
9
+ * - 其他标签 → 整段脱除
10
+ *
11
+ * 不脱除 hibsml 标签会让 LLM 看到原文标记 (raw XML) 误以为是工具调用.
12
+ */
13
+ const HIBML_REPLACEMENTS = [
14
+ // {hibsml:cite index="0-1,3-5"}...{/hibsml:cite} → [CITE:0-1,3-5] ... [ENDCITE]
15
+ [
16
+ /\{hibsml:cite\s+index="([^"]+)"\}/g,
17
+ (_m, idx) => `[CITE:${idx}]`,
18
+ ],
19
+ [/\{\/hibsml:cite\}/g, '[ENDCITE]'],
20
+ // {hibsml:invoke name="X"} ... {/hibsml:invoke} → [TOOL:X] ... [ENDTOOL]
21
+ [
22
+ /\{hibsml:invoke\s+name="([^"]+)"\}/g,
23
+ (_m, name) => `[TOOL:${name}]`,
24
+ ],
25
+ [/\{\/hibsml:invoke\}/g, '[ENDTOOL]'],
26
+ // {hibsml:parameter name="X"}val{/hibsml:parameter} → [P:X]val[/P]
27
+ [
28
+ /\{hibsml:parameter\s+name="([^"]+)"\}/g,
29
+ (_m, name) => `[P:${name}]`,
30
+ ],
31
+ [/\{\/hibsml:parameter\}/g, '[/P]'],
32
+ // {hibsml:thinking_mode}auto{/hibsml:thinking_mode} → [THINKING:auto] (保留)
33
+ [
34
+ /\{hibsml:thinking_mode\}(\w+)\{\/hibsml:thinking_mode\}/g,
35
+ (_m, mode) => `[THINKING:${mode}]`,
36
+ ],
37
+ // 脱除 voice_note (hibs 1 明确说永远不用)
38
+ [/<details><summary>.*?<\/summary>.*?<\/details>/gs, ''],
39
+ // 任何其他 hibsml:* 标签
40
+ [/\{hibsml:[a-z_]+\}/g, ''],
41
+ [/\{\/hibsml:[a-z_]+\}/g, ''],
42
+ ];
43
+ export function stripHibsml(text) {
44
+ let out = text;
45
+ for (const [re, rep] of HIBML_REPLACEMENTS) {
46
+ out = out.replace(re, rep);
47
+ }
48
+ // 收尾: 多个空行合并
49
+ out = out.replace(/\n{3,}/g, '\n\n');
50
+ return out.trim();
51
+ }
@@ -0,0 +1,35 @@
1
+ export const ask_user_input_v0 = {
2
+ id: 'ask_user_input_v0',
3
+ name: 'ask_user_input_v0',
4
+ oneLine: '在提供建议前展示可点击的选项以收集用户偏好 (移动端友好).',
5
+ description: '此工具显示交互式按钮, 用户可以点击按钮来回答, 在移动端比键入要容易得多. 用于引出信息 (ELICITATION) — 当你需要了解用户的偏好、约束或目标以提供有用建议时.',
6
+ whenToUse: [
7
+ '需要了解用户的偏好/约束/目标以提供有用建议',
8
+ '示例: 帮我制定锻炼计划 → 询问目标(力量/有氧/减重)、可用时间、设备访问',
9
+ '示例: 帮我为朋友挑礼物 → 询问场合、预算、朋友的兴趣',
10
+ ],
11
+ whenNotToUse: [
12
+ '用户问 A 还是 B (想要分析, 不是按钮)',
13
+ '用户在发泄或处理情绪',
14
+ '用户询问观点',
15
+ '事实问题 (直接回答)',
16
+ '用户需要散文形式反馈',
17
+ ],
18
+ parameters: [
19
+ { name: 'questions', type: 'array', required: true, description: '1-3 个问题', items: {
20
+ name: 'question', type: 'object', required: true, description: '单个问题', properties: [
21
+ { name: 'question', type: 'string', required: true, description: '向用户显示的问题' },
22
+ { name: 'type', type: 'enum', required: false, description: 'single_select | multi-select | rank_priorities', enumValues: ['single_select', 'multi_select', 'rank_priorities'], default: 'single_select' },
23
+ { name: 'options', type: 'array', required: true, description: '2-4 个带短标签的选项', minItems: 2, maxItems: 4, items: {
24
+ name: 'option', type: 'object', required: true, description: '选项', properties: [
25
+ { name: 'label', type: 'string', required: true, description: '短标签' },
26
+ { name: 'description', type: 'string', required: false, description: '选项描述' },
27
+ ],
28
+ } },
29
+ ],
30
+ } },
31
+ ],
32
+ callExample: `[TOOL:ask_user_input_v0]
33
+ [P:questions]${'${'}JSON.stringify([{"question":"你的预算?","options":[{"label":"<500"},{"label":"500-2000"}]}])[ENDTOOL]`,
34
+ layerId: 'tool.manifest',
35
+ };
@@ -0,0 +1,23 @@
1
+ export const bash_tool = {
2
+ id: 'bash_tool',
3
+ name: 'bash_tool',
4
+ oneLine: '在容器中运行 bash 命令.',
5
+ description: '在容器中运行 bash 命令. 必须用 description 参数说明为什么跑.',
6
+ whenToUse: [
7
+ '需要执行 shell 命令 (ls, mkdir, npm, git 等)',
8
+ '需要跑构建/测试/脚本',
9
+ ],
10
+ whenNotToUse: [
11
+ '读取文件 (用 view)',
12
+ '编辑文件 (用 str_replace 或 create_file)',
13
+ ],
14
+ parameters: [
15
+ { name: 'command', type: 'string', required: true, description: '要运行的 bash 命令' },
16
+ { name: 'description', type: 'string', required: true, description: '为什么我要运行此命令' },
17
+ ],
18
+ callExample: `[TOOL:bash_tool]
19
+ [P:command]ls -la /tmp
20
+ [P:description]列出 /tmp 目录内容
21
+ [ENDTOOL]`,
22
+ layerId: 'tool.bash',
23
+ };
@@ -0,0 +1,24 @@
1
+ export const create_file = {
2
+ id: 'create_file',
3
+ name: 'create_file',
4
+ oneLine: '在容器中创建带有内容的新文件.',
5
+ description: '如果路径已存在则失败 — 使用 str_replace 编辑现有文件, 或使用 bash_tool (cat > path << EOF) 覆盖.',
6
+ whenToUse: [
7
+ '创建新文件',
8
+ '需要写完整的文件内容',
9
+ ],
10
+ whenNotToUse: [
11
+ '编辑已有文件 (用 str_replace)',
12
+ ],
13
+ parameters: [
14
+ { name: 'description', type: 'string', required: true, description: '为什么我要创建此文件' },
15
+ { name: 'file_text', type: 'string', required: true, description: '要写入的文件内容' },
16
+ { name: 'path', type: 'string', required: true, description: '要创建的文件路径' },
17
+ ],
18
+ callExample: `[TOOL:create_file]
19
+ [P:description]新建 README
20
+ [P:file_text]# Project\n\nHello world
21
+ [P:path]/home/bolloon/README.md
22
+ [ENDTOOL]`,
23
+ layerId: 'tool.manifest',
24
+ };
@@ -0,0 +1,26 @@
1
+ export const fetch_sports_data = {
2
+ id: 'fetch_sports_data',
3
+ name: 'fetch_sports_data',
4
+ oneLine: '获取当前/即将进行/最近的体育数据 (比分/积分榜/比赛统计).',
5
+ description: '对于最近和即将进行的比赛的数据、比分、统计, 优先使用此工具而非 Web 搜索. 工作流: 1) 获取比分 2) 根据比赛 ID 获取统计 3) 然后才回复用户.',
6
+ whenToUse: [
7
+ '用户对某场比赛的比分感兴趣',
8
+ '广泛查询 (最近的 NBA 结果等)',
9
+ '需要详细比赛统计',
10
+ ],
11
+ whenNotToUse: [
12
+ '历史比赛 (很久以前)',
13
+ '非体育数据',
14
+ ],
15
+ parameters: [
16
+ { name: 'data_type', type: 'enum', required: true, description: 'scores | standings | game_stats', enumValues: ['scores', 'standings', 'game_stats'] },
17
+ { name: 'game_id', type: 'string', required: false, description: 'SportRadar 比赛 ID (data_type=game_stats 时必需)' },
18
+ { name: 'league', type: 'enum', required: true, description: 'nfl/nba/nhl/mlb/wnba/ncaafb/ncaamb/ncaawb/epl/la_liga/serie_a/bundesliga/ligue_1/mls/champions_league/tennis/golf/nascar/cricket/mma', enumValues: ['nfl', 'nba', 'nhl', 'mlb', 'wnba', 'ncaafb', 'ncaamb', 'ncaawb', 'epl', 'la_liga', 'serie_a', 'bundesliga', 'ligue_1', 'mls', 'champions_league', 'tennis', 'golf', 'nascar', 'cricket', 'mma'] },
19
+ { name: 'team', type: 'string', required: false, description: '可选的球队名称' },
20
+ ],
21
+ callExample: `[TOOL:fetch_sports_data]
22
+ [P:data_type]scores
23
+ [P:league]nba
24
+ [ENDTOOL]`,
25
+ layerId: 'tool.manifest',
26
+ };
@@ -0,0 +1,24 @@
1
+ export const image_search = {
2
+ id: 'image_search',
3
+ name: 'image_search',
4
+ oneLine: '在 Web 上查找图像并连同尺寸返回 (3-4 张/次).',
5
+ description: '对于视觉内容可增强用户理解的任何查询, 默认使用图像搜索. 当交付物主要是文本时跳过.',
6
+ whenToUse: [
7
+ '地点、动物、食物、人物、产品、风格、图表、历史照片、练习',
8
+ '关于视觉事物的简单事实 ("埃菲尔铁塔是哪一年造的?" → 展示它)',
9
+ '多项目内容 (指南、列表、比较、时间线、步骤) — 交错图像',
10
+ ],
11
+ whenNotToUse: [
12
+ '文本输出 (撰写邮件、代码、文章)',
13
+ '数字/数据、编码查询、技术支持、分步说明',
14
+ '关于非视觉主题的分析',
15
+ ],
16
+ parameters: [
17
+ { name: 'max_results', type: 'integer', required: false, description: '返回图片数 (默认 3, 最少 3, 最多 5)', minimum: 3, maximum: 5, default: 3 },
18
+ { name: 'query', type: 'string', required: true, description: '搜索查询 (3-6 词具体)' },
19
+ ],
20
+ callExample: `[TOOL:image_search]
21
+ [P:query]Eiffel Tower Paris
22
+ [ENDTOOL]`,
23
+ layerId: 'tool.image_search',
24
+ };
@@ -0,0 +1,69 @@
1
+ import { ask_user_input_v0 } from './ask_user_input.js';
2
+ import { bash_tool } from './bash.js';
3
+ import { create_file } from './create_file.js';
4
+ import { fetch_sports_data } from './fetch_sports_data.js';
5
+ import { image_search } from './image_search.js';
6
+ import { message_compose_v1 } from './message_compose.js';
7
+ import { places_search, places_map_display_v0 } from './places.js';
8
+ import { present_files } from './present_files.js';
9
+ import { recipe_display_v0 } from './recipe.js';
10
+ import { recommend_bolloon_apps } from './recommend_apps.js';
11
+ import { search_mcp_registry, suggest_connectors } from './mcp.js';
12
+ import { str_replace } from './str_replace.js';
13
+ import { view } from './view.js';
14
+ import { web_search, web_fetch } from './web.js';
15
+ import { weather_fetch } from './weather.js';
16
+ const ALL = [
17
+ ask_user_input_v0,
18
+ bash_tool,
19
+ create_file,
20
+ fetch_sports_data,
21
+ image_search,
22
+ message_compose_v1,
23
+ places_search,
24
+ places_map_display_v0,
25
+ present_files,
26
+ recipe_display_v0,
27
+ recommend_bolloon_apps,
28
+ search_mcp_registry,
29
+ suggest_connectors,
30
+ str_replace,
31
+ view,
32
+ web_search,
33
+ web_fetch,
34
+ weather_fetch,
35
+ ];
36
+ export function listTools() {
37
+ return ALL;
38
+ }
39
+ export function getToolManifest(id) {
40
+ return ALL.find((t) => t.id === id);
41
+ }
42
+ export function getToolsByLayer(layerId) {
43
+ return ALL.filter((t) => t.layerId === layerId);
44
+ }
45
+ /**
46
+ * 缩到 1-3KB 装进 system prompt
47
+ * 包含: 名字 + 一句话 + whenToUse(2) + whenNotToUse(1) + 1 行示例
48
+ *
49
+ * 不包含: 完整 parameters schema (那是 PiAI 客户端在调用时读)
50
+ */
51
+ export function formatForPrompt(tools) {
52
+ const list = tools ?? ALL;
53
+ const lines = [
54
+ `## 工具清单 (${list.length} 个, 详细 schema 在 src/llm/tool-manifest/, 调用时由 PiAI 客户端解析)`,
55
+ '',
56
+ ];
57
+ for (const t of list) {
58
+ lines.push(`### ${t.id}`);
59
+ lines.push(`- **用途**: ${t.oneLine}`);
60
+ lines.push(`- **何时用**: ${t.whenToUse[0] ?? ''}`);
61
+ if (t.whenToUse.length > 1) {
62
+ lines.push(` - 也: ${t.whenToUse.slice(1, 3).join(' / ')}`);
63
+ }
64
+ lines.push(`- **何时不用**: ${t.whenNotToUse[0] ?? ''}`);
65
+ lines.push(`- **示例**: ${t.callExample.replace(/\n/g, ' ')}`);
66
+ lines.push('');
67
+ }
68
+ return lines.join('\n');
69
+ }
@@ -0,0 +1,43 @@
1
+ export const search_mcp_registry = {
2
+ id: 'search_mcp_registry',
3
+ name: 'search_mcp_registry',
4
+ oneLine: '在 MCP 注册表中搜索可用连接器.',
5
+ description: '当连接新的 MCP 可能有助于解决用户查询时, 无论他们是否指名了特定产品, 请调用此工具. 如果结果相关, 调用 suggest_connectors 呈现选项. 如果没有任何匹配任务的内容, 不要调用 suggest_connectors.',
6
+ whenToUse: [
7
+ '用户隐含读取个人数据 (邮件、日历、任务、文件、工单)',
8
+ '需要连接外部服务 (Asana/Jira/Slack/Calendar)',
9
+ '用户指名了特定连接器 (即使未连接)',
10
+ ],
11
+ whenNotToUse: [
12
+ '知识问答/购物建议/一般性建议',
13
+ '用户已指名了已连接的特定服务 (直接用)',
14
+ ],
15
+ parameters: [
16
+ { name: 'keywords', type: 'array', required: true, description: '搜索关键词', minItems: 1, items: { name: 'kw', type: 'string', required: true, description: '关键词' } }
17
+ ],
18
+ callExample: `[TOOL:search_mcp_registry]
19
+ [P:keywords]${'${'}JSON.stringify(["calendar","schedule"])[ENDTOOL]`,
20
+ layerId: 'tool.mcp_apps',
21
+ };
22
+ export const suggest_connectors = {
23
+ id: 'suggest_connectors',
24
+ name: 'suggest_connectors',
25
+ oneLine: '向用户展示连接器选项, 让用户选择.',
26
+ description: '每个选项都会渲染一个连接或使用按钮, 以及一个"以上都不是"选项. 调用后用一句简短的引导语结束你的回合.',
27
+ whenToUse: [
28
+ 'search_mcp_registry 找到了相关选项',
29
+ '用户未明确指名连接器',
30
+ '工具调用因身份验证/凭据错误失败 (重认证)',
31
+ ],
32
+ whenNotToUse: [
33
+ 'search_mcp_registry 未返回相关内容',
34
+ '用户已指名了特定的已连接服务 (直接用)',
35
+ '没有 search_mcp_registry 上下文',
36
+ ],
37
+ parameters: [
38
+ { name: 'uuids', type: 'array', required: true, description: '从 search_mcp_registry 结果的 directoryUuid 复制', minItems: 1, items: { name: 'u', type: 'string', required: true, description: 'uuid' } }
39
+ ],
40
+ callExample: `[TOOL:suggest_connectors]
41
+ [P:uuids]${'${'}JSON.stringify(["uuid-from-search-result"])[ENDTOOL]`,
42
+ layerId: 'tool.mcp_apps',
43
+ };
@@ -0,0 +1,31 @@
1
+ export const message_compose_v1 = {
2
+ id: 'message_compose_v1',
3
+ name: 'message_compose_v1',
4
+ oneLine: '起草目标导向的消息 (email/textMessage/other).',
5
+ description: '分析情境类型 (工作分歧、谈判、跟进、传达坏消息、请求某事、设定边界、道歉、拒绝、提供反馈、冷启动接触、回应反馈、澄清误解、委派、庆祝) 并识别竞争目标. 多种方法 (高风险/模糊) 生成 2-3 种策略.',
6
+ whenToUse: [
7
+ '用户要你起草一封邮件/消息',
8
+ '高风险沟通 (谈判、道歉、设定边界)',
9
+ '需要适配渠道 (邮件 vs Slack vs 短信)',
10
+ ],
11
+ whenNotToUse: [
12
+ '用户只是要写笔记/便签',
13
+ '对话中直接回复',
14
+ ],
15
+ parameters: [
16
+ { name: 'kind', type: 'enum', required: true, description: 'email | textMessage | other', enumValues: ['email', 'textMessage', 'other'] },
17
+ { name: 'summary_title', type: 'string', required: true, description: '消息的摘要标题' },
18
+ { name: 'variants', type: 'array', required: true, description: '至少 1 个变体', minItems: 1, items: {
19
+ name: 'variant', type: 'object', required: true, description: '变体', properties: [
20
+ { name: 'label', type: 'string', required: true, description: '变体标签' },
21
+ { name: 'body', type: 'string', required: true, description: '消息内容' },
22
+ { name: 'subject', type: 'string', required: false, description: '邮件主题 (仅 email)' },
23
+ ],
24
+ } },
25
+ ],
26
+ callExample: `[TOOL:message_compose_v1]
27
+ [P:kind]email
28
+ [P:summary_title]Follow-up on Q3 review
29
+ [P:variants]${'${'}JSON.stringify([{"label":"direct","subject":"Quick follow-up","body":"..."}])[ENDTOOL]`,
30
+ layerId: 'tool.manifest',
31
+ };
@@ -0,0 +1,83 @@
1
+ export const places_search = {
2
+ id: 'places_search',
3
+ name: 'places_search',
4
+ oneLine: '使用 Google Places 搜索地点/商户/餐厅/景点 (多查询).',
5
+ description: '单次调用支持多个查询. 多个查询可用于: 高效的行程规划, 拆解广泛或抽象的请求. 包含更广泛的区域以避免同名地点冲突.',
6
+ whenToUse: [
7
+ '用户问某地有什么 (餐厅/景点/酒店)',
8
+ '行程规划 (多地点)',
9
+ '需要 place_id 以便后续在地图展示',
10
+ ],
11
+ whenNotToUse: [
12
+ '需要地点坐标 (问 GPS)',
13
+ '只问天气 (用 weather_fetch)',
14
+ ],
15
+ parameters: [
16
+ { name: 'queries', type: 'array', required: true, description: '1-10 个查询', minItems: 1, maxItems: 10, items: {
17
+ name: 'q', type: 'object', required: true, description: '单查询', properties: [
18
+ { name: 'query', type: 'string', required: true, description: '自然语言搜索' },
19
+ { name: 'max_results', type: 'integer', required: false, description: '1-10, 默认 5', minimum: 1, maximum: 10, default: 5 }
20
+ ],
21
+ } },
22
+ { name: 'location_bias_lat', type: 'number', required: false, description: '可选纬度' },
23
+ { name: 'location_bias_lng', type: 'number', required: false, description: '可选经度' },
24
+ { name: 'location_bias_radius', type: 'number', required: false, description: '米 (默认 5000)', default: 5000 }
25
+ ],
26
+ callExample: `[TOOL:places_search]
27
+ [P:queries]${'${'}JSON.stringify([{"query":"ramen restaurants Tokyo"}])[ENDTOOL]`,
28
+ layerId: 'tool.manifest',
29
+ };
30
+ export const places_map_display_v0 = {
31
+ id: 'places_map_display_v0',
32
+ name: 'places_map_display_v0',
33
+ oneLine: '在地图上展示地点, 附上你的推荐和内行小贴士.',
34
+ description: '工作流: 先用 places_search 获取 place_id, 然后用 place_id 引用调用本工具. 两种模式: 简单标记 (locations) 或行程 (days).',
35
+ whenToUse: [
36
+ '用户需要看地点在地图上',
37
+ '行程规划, 需要可视化',
38
+ ],
39
+ whenNotToUse: [
40
+ '只问地点信息 (用 places_search 文字回答)',
41
+ ],
42
+ parameters: [
43
+ { name: 'locations', type: 'array', required: false, description: '简单标记模式', minItems: 1, maxItems: 50, items: {
44
+ name: 'loc', type: 'object', required: true, description: '地点', properties: [
45
+ { name: 'name', type: 'string', required: true, description: '地点名' },
46
+ { name: 'latitude', type: 'number', required: true, description: '纬度' },
47
+ { name: 'longitude', type: 'number', required: true, description: '经度' },
48
+ { name: 'place_id', type: 'string', required: false, description: '从 places_search 复制' },
49
+ { name: 'notes', type: 'string', required: false, description: '你的小贴士' },
50
+ { name: 'address', type: 'string', required: false, description: '自定义地点的地址 (没有 place_id 时用)' },
51
+ { name: 'arrival_time', type: 'string', required: false, description: '到达时间 (用于行程, e.g. "8:00 AM")' },
52
+ { name: 'duration_minutes', type: 'integer', required: false, description: '停留时长 (分钟)' },
53
+ ],
54
+ } },
55
+ { name: 'days', type: 'array', required: false, description: '行程模式', minItems: 1, maxItems: 30, items: {
56
+ name: 'day', type: 'object', required: true, description: '单日', properties: [
57
+ { name: 'day_number', type: 'integer', required: true, description: '天数 (从 1 开始)', minimum: 1 },
58
+ { name: 'title', type: 'string', required: false, description: '日期标题' },
59
+ { name: 'narrative', type: 'string', required: false, description: '该日叙述' },
60
+ { name: 'locations', type: 'array', required: true, description: '该日地点', minItems: 1, maxItems: 50, items: {
61
+ name: 'loc', type: 'object', required: true, description: '地点', properties: [
62
+ { name: 'name', type: 'string', required: true, description: '地点名' },
63
+ { name: 'latitude', type: 'number', required: true, description: '纬度' },
64
+ { name: 'longitude', type: 'number', required: true, description: '经度' },
65
+ { name: 'place_id', type: 'string', required: false, description: '从 places_search 复制' },
66
+ { name: 'notes', type: 'string', required: false, description: '你的小贴士' },
67
+ { name: 'address', type: 'string', required: false, description: '自定义地点地址' },
68
+ { name: 'arrival_time', type: 'string', required: false, description: '到达时间' },
69
+ { name: 'duration_minutes', type: 'integer', required: false, description: '停留时长 (分钟)' },
70
+ ],
71
+ } },
72
+ ],
73
+ } },
74
+ { name: 'mode', type: 'enum', required: false, description: 'markers | itinerary', enumValues: ['markers', 'itinerary'] },
75
+ { name: 'travel_mode', type: 'enum', required: false, description: 'driving | walking | transit | bicycling', enumValues: ['driving', 'walking', 'transit', 'bicycling'] },
76
+ { name: 'show_route', type: 'boolean', required: false, description: '是否显示路线' },
77
+ { name: 'title', type: 'string', required: false, description: '行程标题' },
78
+ { name: 'narrative', type: 'string', required: false, description: '行程叙述' },
79
+ ],
80
+ callExample: `[TOOL:places_map_display_v0]
81
+ [P:locations]${'${'}JSON.stringify([{"name":"Senso-ji","latitude":35.7148,"longitude":139.7967,"place_id":"ChIJ..."}])[ENDTOOL]`,
82
+ layerId: 'tool.manifest',
83
+ };
@@ -0,0 +1,21 @@
1
+ export const present_files = {
2
+ id: 'present_files',
3
+ name: 'present_files',
4
+ oneLine: '让文件对用户可见, 客户端界面中查看和渲染.',
5
+ description: '接收来自容器文件系统的文件路径数组, 返回客户端可访问文件的输出路径. 输出路径按与输入路径相同的顺序返回. 多个文件可在单次调用中高效呈现. 如果文件不在输出目录中, 会自动复制到该目录.',
6
+ whenToUse: [
7
+ '让用户可以查看、下载或与文件交互',
8
+ '一次展示多个相关文件',
9
+ '创建了应向用户展示的文件之后',
10
+ ],
11
+ whenNotToUse: [
12
+ '只是为了自己的处理而需要读取文件内容',
13
+ '临时或中间文件',
14
+ ],
15
+ parameters: [
16
+ { name: 'filepaths', type: 'array', required: true, description: '至少 1 个文件路径', minItems: 1, items: { name: 'path', type: 'string', required: true, description: '容器内路径' } },
17
+ ],
18
+ callExample: `[TOOL:present_files]
19
+ [P:filepaths]${'${'}JSON.stringify(["/home/bolloon/report.md"])[ENDTOOL]`,
20
+ layerId: 'tool.manifest',
21
+ };
@@ -0,0 +1,40 @@
1
+ export const recipe_display_v0 = {
2
+ id: 'recipe_display_v0',
3
+ name: 'recipe_display_v0',
4
+ oneLine: '显示带可调整份量的交互式食谱.',
5
+ description: '用户要求食谱、烹饪说明或食物准备指南时使用. 该组件允许用户通过调整份量控件按比例缩放所有食材的用量.',
6
+ whenToUse: [
7
+ '用户问食谱',
8
+ '需要比例缩放 (份量调整)',
9
+ ],
10
+ whenNotToUse: [
11
+ '用户只要食材列表 (用文字)',
12
+ '用户问餐厅推荐 (用 places_search)',
13
+ ],
14
+ parameters: [
15
+ { name: 'title', type: 'string', required: true, description: '食谱名称' },
16
+ { name: 'base_servings', type: 'integer', required: false, description: '基础份数 (默认 4)' },
17
+ { name: 'description', type: 'string', required: false, description: '简短描述' },
18
+ { name: 'ingredients', type: 'array', required: true, description: '食材', items: {
19
+ name: 'ing', type: 'object', required: true, description: '食材', properties: [
20
+ { name: 'id', type: 'string', required: true, description: '唯一 ID' },
21
+ { name: 'amount', type: 'number', required: true, description: '数量', minimum: 0 },
22
+ { name: 'unit', type: 'enum', required: false, description: 'g/kg/ml/l/tsp/tbsp/cup/fl_oz/oz/lb/pinch', enumValues: ['g', 'kg', 'ml', 'l', 'tsp', 'tbsp', 'cup', 'fl_oz', 'oz', 'lb', 'pinch'] },
23
+ { name: 'name', type: 'string', required: true, description: '显示名 (整体可数项, 把 counting noun 放在这里)' },
24
+ ],
25
+ } },
26
+ { name: 'steps', type: 'array', required: true, description: '步骤', items: {
27
+ name: 's', type: 'object', required: true, description: '步骤', properties: [
28
+ { name: 'id', type: 'string', required: true, description: '唯一 ID' },
29
+ { name: 'title', type: 'string', required: true, description: '步骤摘要' },
30
+ { name: 'content', type: 'string', required: true, description: '完整指令 (用 {id} 引用食材)' },
31
+ { name: 'timer_seconds', type: 'integer', required: false, description: '等待/烹饪计时秒数', minimum: 0 }
32
+ ],
33
+ } },
34
+ { name: 'notes', type: 'string', required: false, description: '附加说明' },
35
+ ],
36
+ callExample: `[TOOL:recipe_display_v0]
37
+ [P:title]Pasta
38
+ [P:ingredients]${'${'}JSON.stringify([{"id":"a1","amount":500,"name":"pasta"}])[ENDTOOL]`,
39
+ layerId: 'tool.manifest',
40
+ };
@@ -0,0 +1,23 @@
1
+ export const recommend_bolloon_apps = {
2
+ id: 'recommend_bolloon_apps',
3
+ name: 'recommend_bolloon_apps',
4
+ oneLine: '推荐 1-3 个 Bolloon 应用或扩展.',
5
+ description: '当用户正在处理的事情可能更适合用 Bolloon 聊天以外的应用来完成时, 展示此建议. 仅推荐与用户当前用例相关的应用, 并按相关性排序.',
6
+ whenToUse: [
7
+ '编码任务 (Bolloon Code)',
8
+ '知识工作 (Cowork)',
9
+ '处理电子表格 (Excel) 或幻灯片 (PowerPoint)',
10
+ '浏览器自动化 (Chrome)',
11
+ ],
12
+ whenNotToUse: [
13
+ '用户已明确不想离开对话',
14
+ '没有相关应用',
15
+ ],
16
+ parameters: [
17
+ { name: 'app_ids', type: 'array', required: true, description: '应用 ID 数组', items: {
18
+ name: 'id', type: 'string', required: true, description: '应用 ID (如 desktop/ios/android/code_terminal/code_vscode/code_jetbrains/code_slack/excel/powerpoint/chrome)',
19
+ } },
20
+ ],
21
+ callExample: '[TOOL:recommend_bolloon_apps] [P:app_ids] ["code_vscode","excel"] [ENDTOOL]',
22
+ layerId: 'tool.manifest',
23
+ };
@@ -0,0 +1,27 @@
1
+ export const str_replace = {
2
+ id: 'str_replace',
3
+ name: 'str_replace',
4
+ oneLine: '将文件中的唯一字符串替换为另一个.',
5
+ description: 'old_str 必须与原始文件内容完全匹配且只出现一次. 从 view 输出复制时, 不要包含行号前缀(空格 + 行号 + 制表符). 在编辑前立即查看文件; 任何成功的 str_replace 之后, 该文件之前的 view 输出已失效 — 在对同一文件进行进一步编辑之前请重新查看. /mnt/* 路径只读, 需先复制到可写位置.',
6
+ whenToUse: [
7
+ '编辑已有文件的小改动',
8
+ '精确替换单段文本',
9
+ ],
10
+ whenNotToUse: [
11
+ '创建新文件 (用 create_file)',
12
+ '完全重写文件 (用 create_file + 删除)',
13
+ ],
14
+ parameters: [
15
+ { name: 'description', type: 'string', required: true, description: '为什么我要做这个编辑' },
16
+ { name: 'old_str', type: 'string', required: true, description: '要被替换的字符串 (必须唯一)' },
17
+ { name: 'new_str', type: 'string', required: true, description: '新字符串 (空字符串 = 删除)', default: '' },
18
+ { name: 'path', type: 'string', required: true, description: '文件路径' },
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
25
+ [ENDTOOL]`,
26
+ layerId: 'tool.manifest',
27
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * tool-manifest/types.ts — 工具清单的类型
3
+ *
4
+ * 设计原则: schema 在代码侧(结构化数据), description/when-to-use 在代码侧,
5
+ * prompt 里只嵌"调用格式 + 名字 + 一句话描述" — 节省 LLM 注意力.
6
+ */
7
+ export {};
@@ -0,0 +1,24 @@
1
+ export const view = {
2
+ id: 'view',
3
+ name: 'view',
4
+ oneLine: '查看文本、图像和目录列表.',
5
+ description: '支持的路径类型: 目录 (列出文件和目录, 最多 2 层深度, 忽略隐藏项和 node_modules); 图像文件 (.jpg, .jpeg, .png, .gif, .webp) 以可视方式显示; 文本文件显示带行号的内容 (前缀仅用于显示 — 不要在 str_replace 的 old_str 中包含它). 可以指定 view_range 来查看特定行.',
6
+ whenToUse: [
7
+ '读取已有文件的内容',
8
+ '看图像文件',
9
+ '列目录',
10
+ ],
11
+ whenNotToUse: [
12
+ '创建新文件 (用 create_file)',
13
+ ],
14
+ parameters: [
15
+ { name: 'description', type: 'string', required: true, description: '为什么我要查看' },
16
+ { name: 'path', type: 'string', required: true, description: '绝对路径' },
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
+ ],
19
+ callExample: `[TOOL:view]
20
+ [P:description]读 README
21
+ [P:path]/home/bolloon/README.md
22
+ [ENDTOOL]`,
23
+ layerId: 'tool.manifest',
24
+ };
@@ -0,0 +1,27 @@
1
+ export const weather_fetch = {
2
+ id: 'weather_fetch',
3
+ name: 'weather_fetch',
4
+ oneLine: '显示天气信息 (用用户家庭位置确定温度单位).',
5
+ description: '使用用户的家庭位置来确定温度单位: 美国用户使用华氏度, 其他用户使用摄氏度.',
6
+ whenToUse: [
7
+ '用户询问特定地点的天气',
8
+ '用户询问"我该带雨伞/外套吗"',
9
+ '用户在规划户外活动',
10
+ '用户询问"[城市]怎么样"(天气语境)',
11
+ ],
12
+ whenNotToUse: [
13
+ '气候或历史天气问题',
14
+ '闲聊天气但未指定地点',
15
+ ],
16
+ parameters: [
17
+ { name: 'location_name', type: 'string', required: true, description: '人类可读地点名' },
18
+ { name: 'latitude', type: 'number', required: true, description: '纬度' },
19
+ { name: 'longitude', type: 'number', required: true, description: '经度' },
20
+ ],
21
+ callExample: `[TOOL:weather_fetch]
22
+ [P:location_name]San Francisco, CA
23
+ [P:latitude]37.78
24
+ [P:longitude]-122.41
25
+ [ENDTOOL]`,
26
+ layerId: 'tool.manifest',
27
+ };