@bolloon/bolloon-agent 0.4.13 → 0.4.15

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 (221) hide show
  1. package/README.md +127 -127
  2. package/bin/bolloon-cli.cjs +183 -183
  3. package/bin/bolloon-daemon.sh +207 -0
  4. package/bin/bolloon.cjs +0 -0
  5. package/dist/agents/agent-gateway.js +130 -0
  6. package/dist/agents/constraint-layer.js +19 -19
  7. package/dist/agents/gateway-group.js +261 -0
  8. package/dist/agents/gateway-network.js +278 -0
  9. package/dist/agents/judgment-protocol.js +14 -14
  10. package/dist/agents/pi-sdk-tools.js +117 -0
  11. package/dist/agents/pi-sdk-types.js +12 -12
  12. package/dist/agents/pi-sdk.js +101 -101
  13. package/dist/agents/skill-organizer.js +19 -19
  14. package/dist/agents/workflow-pivot-loop.js +2 -2
  15. package/dist/agents/x402/x402Pay.js +4 -0
  16. package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
  17. package/dist/bollharness-integration/context-router-judgment.js +4 -4
  18. package/dist/bollharness-integration/context-router.js +292 -292
  19. package/dist/bollharness-integration/gate-state-machine.js +13 -13
  20. package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
  21. package/dist/bollharness-integration/skill-adapter.js +21 -21
  22. package/dist/bootstrap/chat-archiver.js +14 -14
  23. package/dist/bootstrap/context-os.js +24 -24
  24. package/dist/bootstrap/memory-compressor.js +13 -13
  25. package/dist/cli-entry.js +36 -36
  26. package/dist/constraint-runtime/reference_data/archive_surface_snapshot.json +63 -0
  27. package/dist/constraint-runtime/reference_data/commands_snapshot.json +1037 -0
  28. package/dist/constraint-runtime/reference_data/subsystems/assistant.json +8 -0
  29. package/dist/constraint-runtime/reference_data/subsystems/bootstrap.json +8 -0
  30. package/dist/constraint-runtime/reference_data/subsystems/bridge.json +32 -0
  31. package/dist/constraint-runtime/reference_data/subsystems/buddy.json +13 -0
  32. package/dist/constraint-runtime/reference_data/subsystems/cli.json +26 -0
  33. package/dist/constraint-runtime/reference_data/subsystems/components.json +32 -0
  34. package/dist/constraint-runtime/reference_data/subsystems/constants.json +28 -0
  35. package/dist/constraint-runtime/reference_data/subsystems/coordinator.json +8 -0
  36. package/dist/constraint-runtime/reference_data/subsystems/entrypoints.json +15 -0
  37. package/dist/constraint-runtime/reference_data/subsystems/hooks.json +32 -0
  38. package/dist/constraint-runtime/reference_data/subsystems/keybindings.json +21 -0
  39. package/dist/constraint-runtime/reference_data/subsystems/memdir.json +15 -0
  40. package/dist/constraint-runtime/reference_data/subsystems/migrations.json +18 -0
  41. package/dist/constraint-runtime/reference_data/subsystems/moreright.json +8 -0
  42. package/dist/constraint-runtime/reference_data/subsystems/native_ts.json +11 -0
  43. package/dist/constraint-runtime/reference_data/subsystems/outputStyles.json +8 -0
  44. package/dist/constraint-runtime/reference_data/subsystems/plugins.json +9 -0
  45. package/dist/constraint-runtime/reference_data/subsystems/remote.json +11 -0
  46. package/dist/constraint-runtime/reference_data/subsystems/schemas.json +8 -0
  47. package/dist/constraint-runtime/reference_data/subsystems/screens.json +10 -0
  48. package/dist/constraint-runtime/reference_data/subsystems/server.json +10 -0
  49. package/dist/constraint-runtime/reference_data/subsystems/services.json +32 -0
  50. package/dist/constraint-runtime/reference_data/subsystems/skills.json +27 -0
  51. package/dist/constraint-runtime/reference_data/subsystems/state.json +13 -0
  52. package/dist/constraint-runtime/reference_data/subsystems/types.json +18 -0
  53. package/dist/constraint-runtime/reference_data/subsystems/upstreamproxy.json +9 -0
  54. package/dist/constraint-runtime/reference_data/subsystems/utils.json +32 -0
  55. package/dist/constraint-runtime/reference_data/subsystems/vim.json +12 -0
  56. package/dist/constraint-runtime/reference_data/subsystems/voice.json +8 -0
  57. package/dist/constraint-runtime/reference_data/tools_snapshot.json +922 -0
  58. package/dist/constraint-runtime/tools/PolymarketSDK/econ-integration.d.ts +55 -0
  59. package/dist/constraint-runtime/tools/PolymarketSDK/econ-integration.js +59 -0
  60. package/dist/context-compaction/auto-compact.js +7 -7
  61. package/dist/electron/config.js.map +1 -0
  62. package/dist/electron/dialogs.js.map +1 -0
  63. package/dist/electron/first-run.js +54 -54
  64. package/dist/electron/first-run.js.map +1 -0
  65. package/dist/electron/ipc.js.map +1 -0
  66. package/dist/electron/logger.js.map +1 -0
  67. package/dist/electron/main.js.map +1 -0
  68. package/dist/electron/menu.js.map +1 -0
  69. package/dist/electron/paths.js.map +1 -0
  70. package/dist/electron/server.js.map +1 -0
  71. package/dist/electron/tray.js.map +1 -0
  72. package/dist/electron/window.js.map +1 -0
  73. package/dist/electron-build/electron/first-run.js +54 -54
  74. package/dist/electron-preload.js.map +1 -1
  75. package/dist/electron.js.map +1 -1
  76. package/dist/index.js +112 -112
  77. package/dist/llm/llm-judgment-client.js +102 -102
  78. package/dist/llm/pi-ai.js +48 -48
  79. package/dist/llm/system-prompt/layers/channel/human-async.md +41 -41
  80. package/dist/llm/system-prompt/layers/channel/local.md +14 -14
  81. package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
  82. package/dist/llm/system-prompt/layers/channel/p2p-peer-sync.md +51 -51
  83. package/dist/llm/system-prompt/layers/channel/p2p-proactive.md +43 -43
  84. package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
  85. package/dist/llm/system-prompt/layers/channel/session-handoff.md +61 -61
  86. package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
  87. package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
  88. package/dist/llm/system-prompt/layers/core/external-engagement.md +73 -73
  89. package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
  90. package/dist/llm/system-prompt/layers/core/identity.md +48 -48
  91. package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
  92. package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
  93. package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
  94. package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
  95. package/dist/llm/system-prompt/layers/core/tone.md +31 -31
  96. package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
  97. package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
  98. package/dist/llm/system-prompt/layers/role/architect.md +20 -20
  99. package/dist/llm/system-prompt/layers/role/expert.md +19 -19
  100. package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
  101. package/dist/llm/system-prompt/layers/role/security.md +15 -15
  102. package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
  103. package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
  104. package/dist/llm/system-prompt/layers/tool/goal_handoff.md +77 -77
  105. package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
  106. package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
  107. package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
  108. package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
  109. package/dist/llm/system-prompt/layers/tool/p2p_request.md +61 -61
  110. package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
  111. package/dist/llm/tool-manifest/ask_user_input.js +1 -1
  112. package/dist/llm/tool-manifest/bash.js +3 -3
  113. package/dist/llm/tool-manifest/create_file.js +4 -4
  114. package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
  115. package/dist/llm/tool-manifest/image_search.js +2 -2
  116. package/dist/llm/tool-manifest/index.js +59 -0
  117. package/dist/llm/tool-manifest/mcp.js +2 -2
  118. package/dist/llm/tool-manifest/message_compose.js +3 -3
  119. package/dist/llm/tool-manifest/places.js +2 -2
  120. package/dist/llm/tool-manifest/present_files.js +1 -1
  121. package/dist/llm/tool-manifest/recipe.js +2 -2
  122. package/dist/llm/tool-manifest/str_replace.js +5 -5
  123. package/dist/llm/tool-manifest/view.js +3 -3
  124. package/dist/llm/tool-manifest/weather.js +4 -4
  125. package/dist/llm/tool-manifest/web.js +4 -4
  126. package/dist/network/p2p.js +78 -4
  127. package/dist/orbitdb/cid-database.js +39 -10
  128. package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
  129. package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
  130. package/dist/pi-ecosystem-judgment/distillation.js +14 -14
  131. package/dist/pi-ecosystem-judgment/index.js +1 -1
  132. package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
  133. package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
  134. package/dist/security/context-router-tool.js +15 -15
  135. package/dist/utils/auto-update.js.map +1 -0
  136. package/dist/web/a2ui-client.js +1594 -223
  137. package/dist/web/api-config.html +779 -779
  138. package/dist/web/client-hearth.js +10 -10
  139. package/dist/web/client.js +273 -0
  140. package/dist/web/client.js.map +7 -0
  141. package/dist/web/components/wallet-viem.mjs +118 -118
  142. package/dist/web/index.html +502 -485
  143. package/dist/web/manifest.json +20 -20
  144. package/dist/web/mobile-agent.js +397 -0
  145. package/dist/web/mobile-core.js +86235 -0
  146. package/dist/web/mobile-data.js +346 -0
  147. package/dist/web/mobile-http-api.js +71 -0
  148. package/dist/web/mobile-p2p.js +250 -0
  149. package/dist/web/mobile-payments.js +80 -0
  150. package/dist/web/mobile-wallet.js +226 -0
  151. package/dist/web/mobile.css +483 -6
  152. package/dist/web/mobile.html +99 -50
  153. package/dist/web/mobile.js +1040 -187
  154. package/dist/web/server.js +196 -13
  155. package/dist/web/style.css +5062 -4946
  156. package/package.json +201 -198
  157. package/scripts/build-cli.js +215 -215
  158. package/scripts/build-web.ts +162 -149
  159. package/scripts/postinstall.js +152 -152
  160. package/bin/bolloon.js +0 -157
  161. package/dist/agents/python-exec.js +0 -115
  162. package/dist/pi-ecosystem-colony/index.js +0 -365
  163. package/dist/social/ant-colony/AdaptiveHeartbeat.js +0 -101
  164. package/dist/social/ant-colony/PheromoneEngine.js +0 -227
  165. package/dist/social/ant-colony/index.js +0 -6
  166. package/dist/social/ant-colony/types.js +0 -24
  167. package/dist/storage/trajectory.js +0 -101
  168. package/dist/test/ai-judgment-test.js +0 -80
  169. package/dist/test/bollharness-integration.test.js +0 -318
  170. package/dist/test/channel-agent-multi-dialogue.js +0 -205
  171. package/dist/test/channel-heartbeat-agent-test.js +0 -201
  172. package/dist/test/constraint-layer.test.js +0 -164
  173. package/dist/test/diap-identity-test.js +0 -172
  174. package/dist/test/diap-quick-test.js +0 -62
  175. package/dist/test/global-shared-context.test.js +0 -315
  176. package/dist/test/harness-judgment-injection.test.js +0 -246
  177. package/dist/test/harness-workflow-integrator-test.js +0 -228
  178. package/dist/test/human-value-store.test.js +0 -243
  179. package/dist/test/hybrid-integration-test.js +0 -118
  180. package/dist/test/hybrid-messenger-verify.js +0 -55
  181. package/dist/test/iroh-bistream-debug.js +0 -38
  182. package/dist/test/iroh-communication.test.js +0 -66
  183. package/dist/test/iroh-debug-test.js +0 -57
  184. package/dist/test/iroh-diap-test.js +0 -71
  185. package/dist/test/iroh-direct-connect.js +0 -55
  186. package/dist/test/iroh-e2e-fixed.js +0 -89
  187. package/dist/test/iroh-e2e-same-process.js +0 -63
  188. package/dist/test/iroh-e2e.js +0 -66
  189. package/dist/test/iroh-final-e2e.js +0 -72
  190. package/dist/test/iroh-relay-test.js +0 -37
  191. package/dist/test/iroh-simple-test.js +0 -41
  192. package/dist/test/iroh-transport-verify.js +0 -54
  193. package/dist/test/iroh-transport.test.js +0 -37
  194. package/dist/test/iroh-two-nodes.js +0 -70
  195. package/dist/test/iroh-verify.js +0 -44
  196. package/dist/test/judgment-decision.test.js +0 -219
  197. package/dist/test/llm-judgment-integration.test.js +0 -220
  198. package/dist/test/p2p-agent-complex-dialogue.js +0 -385
  199. package/dist/test/p2p-agent-dialogue.js +0 -341
  200. package/dist/test/p2p-agent-full-bidirectional.js +0 -510
  201. package/dist/test/p2p-agent-harness-flow.js +0 -437
  202. package/dist/test/p2p-agent-harness-single.js +0 -143
  203. package/dist/test/p2p-ai-dialogue-test.js +0 -318
  204. package/dist/test/p2p-cid-connect-test.js +0 -195
  205. package/dist/test/p2p-connect-receiver.js +0 -69
  206. package/dist/test/p2p-doc-transfer.js +0 -110
  207. package/dist/test/p2p-identity-page-test.js +0 -77
  208. package/dist/test/p2p-iroh-test.js +0 -171
  209. package/dist/test/p2p-minimal-test.js +0 -241
  210. package/dist/test/p2p-node-1.js +0 -148
  211. package/dist/test/p2p-node-2.js +0 -148
  212. package/dist/test/p2p-server.js +0 -281
  213. package/dist/test/p2p-two-nodes-test.js +0 -438
  214. package/dist/test/pi-sdk.test.js +0 -44
  215. package/dist/test/set-persona.js +0 -40
  216. package/dist/test/simple.test.js +0 -9
  217. package/dist/test/storage-integration.test.js +0 -150
  218. package/dist/test/subagent-manager.test.js +0 -276
  219. package/dist/test/test-gate-flow.test.js +0 -81
  220. package/dist/test/workflow-engine.test.js +0 -87
  221. package/dist/test/workflow-pivot-loop.test.js +0 -246
@@ -0,0 +1,207 @@
1
+ #!/bin/bash
2
+ # Bolloon Daemon - 守护进程启动脚本
3
+ # 支持自动重启、日志轮转、PID 管理
4
+
5
+ set -e
6
+
7
+ APP_NAME="bolloon"
8
+ APP_DIR="$(cd "$(dirname "$0")/.." && pwd)"
9
+ PID_FILE="$HOME/.bolloon/daemon.pid"
10
+ LOG_FILE="$HOME/.bolloon/daemon.log"
11
+ MAX_RESTARTS=5
12
+ RESTART_DELAY=5
13
+
14
+ # 颜色输出
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[1;33m'
18
+ NC='\033[0m' # No Color
19
+
20
+ log() {
21
+ echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
22
+ }
23
+
24
+ warn() {
25
+ echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] WARN:${NC} $1"
26
+ }
27
+
28
+ error() {
29
+ echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1"
30
+ }
31
+
32
+ # 获取 PID
33
+ get_pid() {
34
+ if [ -f "$PID_FILE" ]; then
35
+ cat "$PID_FILE"
36
+ fi
37
+ }
38
+
39
+ # 检查进程是否运行
40
+ is_running() {
41
+ local pid=$(get_pid)
42
+ if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
43
+ return 0
44
+ fi
45
+ return 1
46
+ }
47
+
48
+ # 启动守护进程
49
+ start() {
50
+ if is_running; then
51
+ log "Bolloon 已在运行 (PID: $(get_pid))"
52
+ return 0
53
+ fi
54
+
55
+ log "启动 Bolloon 守护进程..."
56
+
57
+ # 确保日志目录存在
58
+ mkdir -p "$(dirname "$LOG_FILE")"
59
+
60
+ # 启动进程
61
+ cd "$APP_DIR"
62
+ nohup npx tsx src/index.ts >> "$LOG_FILE" 2>&1 &
63
+ local pid=$!
64
+
65
+ # 保存 PID
66
+ echo "$pid" > "$PID_FILE"
67
+ log "Bolloon 已启动 (PID: $pid)"
68
+ log "日志文件: $LOG_FILE"
69
+ }
70
+
71
+ # 停止守护进程
72
+ stop() {
73
+ local pid=$(get_pid)
74
+
75
+ if [ -z "$pid" ]; then
76
+ warn "Bolloon 未运行"
77
+ return 0
78
+ fi
79
+
80
+ log "停止 Bolloon (PID: $pid)..."
81
+
82
+ # 发送 SIGTERM
83
+ kill -TERM "$pid" 2>/dev/null || true
84
+
85
+ # 等待进程退出
86
+ local count=0
87
+ while kill -0 "$pid" 2>/dev/null && [ $count -lt 10 ]; do
88
+ sleep 1
89
+ count=$((count + 1))
90
+ done
91
+
92
+ # 如果还在运行,强制终止
93
+ if kill -0 "$pid" 2>/dev/null; then
94
+ warn "进程未响应,发送 SIGKILL..."
95
+ kill -KILL "$pid" 2>/dev/null || true
96
+ fi
97
+
98
+ # 清理 PID 文件
99
+ rm -f "$PID_FILE"
100
+ log "Bolloon 已停止"
101
+ }
102
+
103
+ # 重启守护进程
104
+ restart() {
105
+ log "重启 Bolloon..."
106
+ stop
107
+ sleep 2
108
+ start
109
+ }
110
+
111
+ # 查看状态
112
+ status() {
113
+ if is_running; then
114
+ log "Bolloon 运行中 (PID: $(get_pid))"
115
+ # 显示资源使用
116
+ local pid=$(get_pid)
117
+ if [ -n "$pid" ]; then
118
+ ps -p "$pid" -o %cpu,%mem,etime 2>/dev/null | tail -1 || true
119
+ fi
120
+ else
121
+ warn "Bolloon 未运行"
122
+ fi
123
+ }
124
+
125
+ # 查看日志
126
+ logs() {
127
+ if [ -f "$LOG_FILE" ]; then
128
+ tail -100 "$LOG_FILE"
129
+ else
130
+ warn "日志文件不存在: $LOG_FILE"
131
+ fi
132
+ }
133
+
134
+ # 健康检查
135
+ health() {
136
+ local port=${PORT:-54188}
137
+ local response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$port/api/health" 2>/dev/null || echo "000")
138
+
139
+ if [ "$response" = "200" ]; then
140
+ log "健康检查通过"
141
+ curl -s "http://localhost:$port/api/health" 2>/dev/null | head -5
142
+ else
143
+ error "健康检查失败 (HTTP $response)"
144
+ return 1
145
+ fi
146
+ }
147
+
148
+ # 清理日志
149
+ clean_logs() {
150
+ if [ -f "$LOG_FILE" ]; then
151
+ local size=$(du -h "$LOG_FILE" | cut -f1)
152
+ log "当前日志大小: $size"
153
+ > "$LOG_FILE"
154
+ log "日志已清空"
155
+ fi
156
+ }
157
+
158
+ # 显示帮助
159
+ show_help() {
160
+ echo "Bolloon Daemon 守护进程管理脚本"
161
+ echo ""
162
+ echo "用法: $0 [命令]"
163
+ echo ""
164
+ echo "命令:"
165
+ echo " start 启动 Bolloon 守护进程"
166
+ echo " stop 停止 Bolloon 守护进程"
167
+ echo " restart 重启 Bolloon 守护进程"
168
+ echo " status 查看运行状态"
169
+ echo " logs 查看最近日志"
170
+ echo " health 健康检查"
171
+ echo " clean 清空日志"
172
+ echo " help 显示帮助"
173
+ echo ""
174
+ }
175
+
176
+ # 主逻辑
177
+ case "${1:-help}" in
178
+ start)
179
+ start
180
+ ;;
181
+ stop)
182
+ stop
183
+ ;;
184
+ restart)
185
+ restart
186
+ ;;
187
+ status)
188
+ status
189
+ ;;
190
+ logs)
191
+ logs
192
+ ;;
193
+ health)
194
+ health
195
+ ;;
196
+ clean)
197
+ clean_logs
198
+ ;;
199
+ help|--help|-h)
200
+ show_help
201
+ ;;
202
+ *)
203
+ error "未知命令: $1"
204
+ show_help
205
+ exit 1
206
+ ;;
207
+ esac
package/bin/bolloon.cjs CHANGED
File without changes
@@ -0,0 +1,130 @@
1
+ /**
2
+ * agent-gateway.ts — Agent Gateway 协调层 (2026-08-14)
3
+ *
4
+ * Agent Economy 的"经济路由器": 统一入口, 内部编排所有已有层.
5
+ * 定位: 入口层 + 协调层 + 安全边界 (不是新系统, 是把 Registry/DIAP/x402/Policy/Reputation/Treasury 粘起来).
6
+ *
7
+ * 简单用法 (入口要小):
8
+ * gateway.registerAgent({ capability: "research", price: "0.05 USDC" })
9
+ * gateway.callAgent({ task: "analyze paper", budget: 1, capability: "research" })
10
+ * gateway.joinNetwork(link) // 通过链接自动加入共享网络
11
+ *
12
+ * callAgent 自动闭环:
13
+ * Discovery (registry) → Identity (DIAP) → Negotiation (价格/预算匹配)
14
+ * → Policy (预算/白名单) → Payment (x402/审批) → Execution → Reputation
15
+ */
16
+ import { getAgentRegistry, warmAgentRegistry } from './agent-registry.js';
17
+ import { getEconomicPolicy } from './economic-policy.js';
18
+ import { getPaymentGate } from './payment-gate.js';
19
+ import { getApprovalStore } from './payment-approval.js';
20
+ import { recordServiceOutcome } from './agent-reputation.js';
21
+ // ============ 协调层 ============
22
+ /**
23
+ * 注册本 Agent 为服务提供者 (身份 + Registry + 信誉初始化).
24
+ */
25
+ export async function gatewayRegisterAgent(config, identity, deps) {
26
+ // 2026-08-14: 生产路径先 warm OrbitDB — 否则注册只落本地文件, 分享链接指向的 store 是空的.
27
+ // 离线/测试环境 warm 失败不阻塞 (注册仍落本地 fallback).
28
+ let registry = deps?.registry;
29
+ if (!registry) {
30
+ try {
31
+ await warmAgentRegistry();
32
+ }
33
+ catch { /* 离线模式 */ }
34
+ registry = getAgentRegistry();
35
+ }
36
+ const r = await registry.register({
37
+ agentId: identity.did || `did:local:${identity.name}`,
38
+ name: identity.name,
39
+ wallet: config.wallet || identity.wallet,
40
+ service: {
41
+ name: config.capability,
42
+ description: config.description || `${config.capability} 服务`,
43
+ price: {
44
+ amount: config.price,
45
+ currency: (config.currency || 'USDC').toUpperCase(),
46
+ per: config.per || 'query',
47
+ },
48
+ },
49
+ capabilities: [config.capability],
50
+ });
51
+ return { ok: r.ok, error: r.error };
52
+ }
53
+ /**
54
+ * 调用 Agent 服务 (自动闭环).
55
+ * Discovery → Policy → Payment gate → Approval → Execution → Reputation.
56
+ */
57
+ export async function gatewayCallAgent(opts) {
58
+ const { task, budget, capability, url, privateKey } = opts;
59
+ // 1. Discovery: 从 Registry 找 provider
60
+ const registry = getAgentRegistry();
61
+ const providers = capability ? await registry.discover(capability) : await registry.list();
62
+ if (providers.length === 0) {
63
+ return { success: false, error: `未找到能力为 '${capability || 'any'}' 的 Agent (先 joinNetwork 或注册)` };
64
+ }
65
+ const provider = providers[0]; // 简版: 取第一个 (完整版按信誉/价格排序)
66
+ const price = parseFloat(provider.service?.price?.amount || '0');
67
+ // 2. Negotiation: 预算检查
68
+ if (price > budget) {
69
+ return { success: false, error: `价格 ${price} 超预算 ${budget}`, provider: provider.agentId };
70
+ }
71
+ // 3. Payment gate (YAML 验证门): allow/confirm/deny
72
+ const gate = getPaymentGate();
73
+ const verdict = gate.evaluate({ service: provider.service?.name, amount: price, recipient: provider.wallet });
74
+ if (verdict.decision === 'deny') {
75
+ return { success: false, error: `[payment-gate] ${verdict.reason}`, provider: provider.agentId, decision: 'deny' };
76
+ }
77
+ // 4. Policy (预算/白名单)
78
+ const policy = getEconomicPolicy();
79
+ const pol = await policy.check({ payTo: provider.wallet, amount: price, service: provider.service?.name });
80
+ if (!pol.allowed) {
81
+ return { success: false, error: `[policy] ${pol.reason}`, provider: provider.agentId, decision: 'deny' };
82
+ }
83
+ // 5. confirm → 创建人工审批 (不自动执行)
84
+ if (verdict.decision === 'confirm') {
85
+ const store = getApprovalStore();
86
+ const approval = await store.create({
87
+ service: provider.service?.name || capability || 'service',
88
+ amount: price,
89
+ recipient: provider.wallet,
90
+ reason: verdict.reason,
91
+ retryPayload: { task, url, privateKey, serviceName: provider.service?.name, args: { task } },
92
+ });
93
+ return {
94
+ success: false,
95
+ error: `需人工确认: ${verdict.reason} (approval=${approval.id})`,
96
+ provider: provider.agentId,
97
+ decision: 'confirm',
98
+ requiresApproval: true,
99
+ approvalId: approval.id,
100
+ };
101
+ }
102
+ // 6. Execution (x402 支付 + 调用服务)
103
+ try {
104
+ const { serviceCall } = await import('./agent-service-client.js');
105
+ const r = await serviceCall({
106
+ serviceName: provider.service?.name || capability || 'service',
107
+ args: { task },
108
+ privateKey,
109
+ url,
110
+ registry,
111
+ });
112
+ if (!r.success)
113
+ return { success: false, error: r.error, provider: provider.agentId, decision: 'allow' };
114
+ // 7. Reputation: 记录成功
115
+ await recordServiceOutcome(provider.agentId, provider.service?.name || 'service', 'success', registry).catch(() => { });
116
+ return { success: true, provider: provider.agentId, decision: 'allow', output: r.output };
117
+ }
118
+ catch (e) {
119
+ return { success: false, error: `执行失败: ${String(e?.message || e).slice(0, 200)}`, provider: provider.agentId };
120
+ }
121
+ }
122
+ /**
123
+ * 查询网络状态 (注册表 + 信誉概览).
124
+ */
125
+ export async function gatewayStatus() {
126
+ const registry = getAgentRegistry();
127
+ const services = await registry.list();
128
+ const lines = services.slice(0, 20).map((s) => ` [${s.service?.name}] ${s.name} (${s.service?.price?.amount} ${s.service?.price?.currency}/${s.service?.price?.per}) rep=${s.reputation?.score ?? 'n/a'}`);
129
+ return `Agent 网络 (${services.length} 服务):\n${lines.join('\n') || ' (空, 先 joinNetwork 或注册)'}`;
130
+ }
@@ -7,25 +7,25 @@ import { ToolPermissionContext, BudgetTracker } from '@bolloon/constraint-runtim
7
7
  * System prompt for constraint layer
8
8
  * Defines boundaries and autonomous permissions
9
9
  */
10
- export const SYSTEM_PROMPT = `
11
- 你是一个文档处理Agent,在以下规则下运行:
12
-
13
- 【边界规则】
14
- 1. 只处理:txt, md, pdf, docx 格式文档
15
- 2. 不修改原始文件,只输出改进版本
16
- 3. 发送前必须记录操作日志
17
-
18
- 【自主权限】
19
- - ✅ 自主决定:摘要详细程度、chunk分块策略
20
- - ✅ 自主决定:重试次数(最多3次)
21
- - ✅ 自主决定:是否需要补充信息
22
- - ❌ 必须确认:首次向新对等节点发送文档
23
- - ❌ 必须确认:删除操作
24
-
25
- 【敏感操作拦截】
26
- if (操作 === '发送文档' && 对等节点不在已知列表) {
27
- 拦截 → 记录 → 等待确认
28
- }
10
+ export const SYSTEM_PROMPT = `
11
+ 你是一个文档处理Agent,在以下规则下运行:
12
+
13
+ 【边界规则】
14
+ 1. 只处理:txt, md, pdf, docx 格式文档
15
+ 2. 不修改原始文件,只输出改进版本
16
+ 3. 发送前必须记录操作日志
17
+
18
+ 【自主权限】
19
+ - ✅ 自主决定:摘要详细程度、chunk分块策略
20
+ - ✅ 自主决定:重试次数(最多3次)
21
+ - ✅ 自主决定:是否需要补充信息
22
+ - ❌ 必须确认:首次向新对等节点发送文档
23
+ - ❌ 必须确认:删除操作
24
+
25
+ 【敏感操作拦截】
26
+ if (操作 === '发送文档' && 对等节点不在已知列表) {
27
+ 拦截 → 记录 → 等待确认
28
+ }
29
29
  `;
30
30
  /**
31
31
  * Actions that can be executed autonomously without confirmation
@@ -0,0 +1,261 @@
1
+ /**
2
+ * gateway-group.ts — Agent Gateway P2P 群组 (2026-08-14)
3
+ *
4
+ * 群组 = OrbitDB events store (accessController write:'*'), 任何成员可广播消息,
5
+ * 全成员通过 OrbitDB pubsub 复制实时同步. 链接: orbitdb://<addr>?type=group&name=<群名>.
6
+ *
7
+ * 符合用户习惯: 群组 = 微信式群聊 — 加入链接即进群, 发消息全网同步.
8
+ * 持久化: ~/.bolloon/gateway-groups.json (重启后仍是群成员, 自动重开 store).
9
+ */
10
+ import * as os from 'os';
11
+ import * as path from 'path';
12
+ import { getCIDDatabase } from '../orbitdb/cid-database.js';
13
+ // ============ 依赖注入 (测试用, 避免单测起真实 OrbitDB 节点) ============
14
+ let _dbOverride = null;
15
+ /** 测试用: 注入 fake CIDDatabase */
16
+ export function setGroupTestDb(db) { _dbOverride = db; }
17
+ function getDb() { return _dbOverride ?? getCIDDatabase(); }
18
+ /** 测试用: 清空 store 缓存 / 订阅 (避免测试间污染) */
19
+ export function resetGroupState() {
20
+ storeCache.clear();
21
+ onChangeCallbacks.clear();
22
+ }
23
+ // ============ 持久化 ============
24
+ const groupsFile = () => path.join(os.homedir() || '/tmp', '.bolloon', 'gateway-groups.json');
25
+ async function loadGroups() {
26
+ try {
27
+ const { readFile } = await import('fs/promises');
28
+ const parsed = JSON.parse(await readFile(groupsFile(), 'utf-8'));
29
+ return Array.isArray(parsed) ? parsed : [];
30
+ }
31
+ catch {
32
+ return [];
33
+ }
34
+ }
35
+ async function saveGroups(list) {
36
+ try {
37
+ const { mkdir, writeFile } = await import('fs/promises');
38
+ await mkdir(path.dirname(groupsFile()), { recursive: true });
39
+ await writeFile(groupsFile(), JSON.stringify(list, null, 2), 'utf-8');
40
+ }
41
+ catch { /* 持久化失败静默 */ }
42
+ }
43
+ // ============ 链接解析 ============
44
+ /** 解析群组链接: orbitdb://<addr>?type=group&name=<群名> (type 非 group 返回 null) */
45
+ export function parseGroupLink(link) {
46
+ const l = String(link || '').trim();
47
+ if (!l.startsWith('orbitdb://'))
48
+ return null;
49
+ const [base, query] = l.split('?');
50
+ let params = null;
51
+ try {
52
+ params = query ? new URLSearchParams(query) : null;
53
+ }
54
+ catch { /* 忽略 */ }
55
+ if (params && params.get('type') === 'group') {
56
+ let address = base.slice('orbitdb://'.length);
57
+ if (!address.startsWith('/'))
58
+ address = `/${address}`;
59
+ return { address, name: params.get('name') || undefined };
60
+ }
61
+ return null;
62
+ }
63
+ /** 从消息文本检测群组链接 */
64
+ export function detectGroupLink(text) {
65
+ const t = String(text || '');
66
+ const re = /(orbitdb:\/\/\/?orbitdb\/[^\s)'"<>,。;]*\?[^\s)'"<>,。;]*type=group[^\s)'"<>,。;]*)/;
67
+ const m = re.exec(t);
68
+ return m ? m[1].trim() : null;
69
+ }
70
+ // ============ store 缓存 (避免重复 open) ============
71
+ const storeCache = new Map();
72
+ /** 订阅回调注册 (server 层挂 SSE 广播) */
73
+ const onChangeCallbacks = new Map();
74
+ function groupIdOf(address) {
75
+ // /orbitdb/zdpu... → zdpu... (地址后 12 位做短 id)
76
+ const m = /\/orbitdb\/(.{8,})/.exec(address);
77
+ return m ? m[1] : address;
78
+ }
79
+ /** 打开群组 store (缓存) — 可写 (replica=false, write:'*') */
80
+ async function openGroupStore(address) {
81
+ const id = groupIdOf(address);
82
+ if (storeCache.has(id))
83
+ return storeCache.get(id);
84
+ const db = getDb();
85
+ const store = await db.openStoreByAddress(address, 'events', {
86
+ replica: false,
87
+ accessController: { write: ['*'] },
88
+ });
89
+ if (!store)
90
+ return null;
91
+ storeCache.set(id, store);
92
+ // 订阅: 新消息 → 通知回调 (server SSE)
93
+ store.onChange(() => {
94
+ groupMessages(id, 5).then((msgs) => {
95
+ if (msgs.length === 0)
96
+ return;
97
+ const cb = onChangeCallbacks.get(id);
98
+ if (cb)
99
+ for (const fn of cb) {
100
+ try {
101
+ fn(msgs[msgs.length - 1]);
102
+ }
103
+ catch { /* 忽略 */ }
104
+ }
105
+ }).catch(() => { });
106
+ });
107
+ return store;
108
+ }
109
+ /** 注册群组消息回调 (返回退订函数) */
110
+ export function onGroupMessage(groupId, fn) {
111
+ if (!onChangeCallbacks.has(groupId))
112
+ onChangeCallbacks.set(groupId, new Set());
113
+ onChangeCallbacks.get(groupId).add(fn);
114
+ return () => { onChangeCallbacks.get(groupId)?.delete(fn); };
115
+ }
116
+ // ============ 群组操作 ============
117
+ /**
118
+ * 创建群组: 新 events store (write:'*') + 持久化 + 生成邀请链接.
119
+ */
120
+ export async function createGroup(name, opts) {
121
+ const groupName = String(name || '').trim() || `group-${Date.now().toString(36).slice(-4)}`;
122
+ try {
123
+ const db = getDb();
124
+ const store = await db.openStore(`bolloon-gw-group-${groupName}`, 'events', {
125
+ accessController: { write: ['*'] },
126
+ });
127
+ const address = store.address;
128
+ const id = groupIdOf(address);
129
+ const link = `orbitdb://${address}?type=group&name=${encodeURIComponent(groupName)}`;
130
+ const info = {
131
+ id, name: groupName, address, link,
132
+ createdAt: new Date().toISOString(),
133
+ lastSyncAt: new Date().toISOString(),
134
+ };
135
+ storeCache.set(id, store);
136
+ // 欢迎消息 (群主自我介绍)
137
+ const from = opts?.from || 'group-owner';
138
+ await store.add({ from, text: opts?.hello || `📢 群主创建了群「${groupName}」, 分享链接邀请成员加入`, ts: Date.now() });
139
+ const groups = await loadGroups();
140
+ await saveGroups([...groups.filter((g) => g.id !== id), info]);
141
+ return { ok: true, group: info };
142
+ }
143
+ catch (e) {
144
+ return { ok: false, error: `创建群组失败: ${String(e?.message || e).slice(0, 160)}` };
145
+ }
146
+ }
147
+ /**
148
+ * 通过链接加入群组: 打开 store (可写) + 持久化 + 幂等.
149
+ * 失败静默返回错误, 不影响本地.
150
+ */
151
+ export async function joinGroup(link) {
152
+ const parsed = parseGroupLink(link);
153
+ if (!parsed) {
154
+ return { ok: false, error: '不是群组链接 (需要 orbitdb://...?type=group&name=...)' };
155
+ }
156
+ // 幂等: 按地址去重
157
+ const existing = await loadGroups();
158
+ const id = groupIdOf(parsed.address);
159
+ if (existing.some((g) => g.id === id)) {
160
+ return { ok: true, already: true, group: existing.find((g) => g.id === id) };
161
+ }
162
+ const store = await openGroupStore(parsed.address);
163
+ if (!store) {
164
+ return { ok: false, error: '群组 store 不可达 (群主节点需在线), 稍后重试或让群主分享最新链接' };
165
+ }
166
+ const name = parsed.name || id.slice(0, 12);
167
+ const info = {
168
+ id, name, address: parsed.address,
169
+ link: `orbitdb://${parsed.address}?type=group&name=${encodeURIComponent(name)}`,
170
+ createdAt: new Date().toISOString(),
171
+ lastSyncAt: new Date().toISOString(),
172
+ };
173
+ await saveGroups([...existing, info]);
174
+ return { ok: true, group: info };
175
+ }
176
+ /** 列出已加入的群组 */
177
+ export async function listGroups() {
178
+ return loadGroups();
179
+ }
180
+ /** 获取群组 store 的最新消息 (ts 升序, 取最后 N 条) */
181
+ export async function groupMessages(groupId, limit = 50) {
182
+ let store = storeCache.get(groupId) ?? null;
183
+ if (!store) {
184
+ const groups = await loadGroups();
185
+ const g = groups.find((x) => x.id === groupId);
186
+ if (!g)
187
+ return [];
188
+ store = await openGroupStore(g.address);
189
+ if (!store)
190
+ return [];
191
+ }
192
+ const all = await store.all().catch(() => []);
193
+ const msgs = [];
194
+ for (const entry of all) {
195
+ const v = entry.value;
196
+ if (v && typeof v.text === 'string' && typeof v.from === 'string') {
197
+ msgs.push({ from: v.from, text: v.text, ts: typeof v.ts === 'number' ? v.ts : 0 });
198
+ }
199
+ }
200
+ msgs.sort((a, b) => a.ts - b.ts);
201
+ return msgs.slice(-limit);
202
+ }
203
+ /** 群成员: 从消息里提取 from 去重 */
204
+ export async function groupMembers(groupId) {
205
+ const msgs = await groupMessages(groupId, 500);
206
+ return Array.from(new Set(msgs.map((m) => m.from)));
207
+ }
208
+ /** 发送群消息 (广播给所有成员) */
209
+ export async function groupSend(groupId, text, from) {
210
+ const msg = String(text || '').trim();
211
+ if (!msg)
212
+ return { ok: false, error: '消息不能为空' };
213
+ let store = storeCache.get(groupId) ?? null;
214
+ if (!store) {
215
+ const groups = await loadGroups();
216
+ const g = groups.find((x) => x.id === groupId);
217
+ if (!g)
218
+ return { ok: false, error: '群组不存在 (先 joinGroup)' };
219
+ store = await openGroupStore(g.address);
220
+ if (!store)
221
+ return { ok: false, error: '群组 store 不可达' };
222
+ }
223
+ try {
224
+ await store.add({ from: String(from || 'anonymous'), text: msg, ts: Date.now() });
225
+ return { ok: true };
226
+ }
227
+ catch (e) {
228
+ return { ok: false, error: `发送失败: ${String(e?.message || e).slice(0, 160)}` };
229
+ }
230
+ }
231
+ /** 群组邀请链接 */
232
+ export async function groupLink(groupId) {
233
+ const groups = await loadGroups();
234
+ return groups.find((g) => g.id === groupId)?.link ?? null;
235
+ }
236
+ /** 群组信息 (含成员数/消息数) */
237
+ export async function groupInfo(groupId) {
238
+ const groups = await loadGroups();
239
+ const g = groups.find((x) => x.id === groupId);
240
+ if (!g)
241
+ return null;
242
+ const msgs = await groupMessages(groupId, 500);
243
+ const members = await groupMembers(groupId);
244
+ return { ...g, messageCount: msgs.length, memberCount: members.length };
245
+ }
246
+ /** 重启恢复: 重开所有已加入群组的 store (失败静默) */
247
+ export async function restoreGroups() {
248
+ const groups = await loadGroups();
249
+ if (groups.length === 0)
250
+ return { restored: 0, failed: 0, total: 0 };
251
+ let restored = 0;
252
+ let failed = 0;
253
+ for (const g of groups) {
254
+ const store = await openGroupStore(g.address).catch(() => null);
255
+ if (store)
256
+ restored++;
257
+ else
258
+ failed++;
259
+ }
260
+ return { restored, failed, total: groups.length };
261
+ }