@bolloon/bolloon-agent 0.1.39 → 0.1.40
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.
- package/dist/llm/system-prompt/layers/channel/local.md +14 -0
- package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -0
- package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -0
- package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -0
- package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -0
- package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -0
- package/dist/llm/system-prompt/layers/core/identity.md +37 -0
- package/dist/llm/system-prompt/layers/core/knowledge.md +17 -0
- package/dist/llm/system-prompt/layers/core/memory_system.md +12 -0
- package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -0
- package/dist/llm/system-prompt/layers/core/refusal.md +37 -0
- package/dist/llm/system-prompt/layers/core/tone.md +31 -0
- package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -0
- package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -0
- package/dist/llm/system-prompt/layers/role/architect.md +20 -0
- package/dist/llm/system-prompt/layers/role/expert.md +19 -0
- package/dist/llm/system-prompt/layers/role/implementer.md +15 -0
- package/dist/llm/system-prompt/layers/role/security.md +15 -0
- package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -0
- package/dist/llm/system-prompt/layers/tool/bash.md +25 -0
- package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -0
- package/dist/llm/system-prompt/layers/tool/image_search.md +70 -0
- package/dist/llm/system-prompt/layers/tool/manifest.md +89 -0
- package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -0
- package/dist/llm/system-prompt/layers/tool/web_search.md +83 -0
- package/dist/llm/system-prompt/registry.js +5 -1
- package/dist/web/client.js +3770 -2858
- package/dist/web/components/p2p/P2PModal.js +188 -0
- package/dist/web/components/p2p/index.js +264 -226
- package/dist/web/components/p2p/p2p-modal.js +657 -0
- package/dist/web/components/p2p/p2p-tools.js +248 -0
- package/dist/web/server.js +37 -5
- package/dist/web/ui/message-renderer.js +443 -323
- package/dist/web/ui/step-timeline.js +351 -255
- package/package.json +1 -1
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* P2P 工具调用模块
|
|
3
|
+
* 支持文件和本地信息的 P2P 传递
|
|
4
|
+
*/
|
|
5
|
+
// 工具类型枚举
|
|
6
|
+
export var P2PToolType;
|
|
7
|
+
(function (P2PToolType) {
|
|
8
|
+
P2PToolType["FILE_TRANSFER"] = "file_transfer";
|
|
9
|
+
P2PToolType["LOCAL_INFO"] = "local_info";
|
|
10
|
+
P2PToolType["SYSTEM_INFO"] = "system_info";
|
|
11
|
+
P2PToolType["FILE_LIST"] = "file_list";
|
|
12
|
+
})(P2PToolType || (P2PToolType = {}));
|
|
13
|
+
// 文件传输
|
|
14
|
+
export async function transferFile(targetDid, fileInfo, messageId) {
|
|
15
|
+
try {
|
|
16
|
+
const payload = {
|
|
17
|
+
type: 'file',
|
|
18
|
+
tool: P2PToolType.FILE_TRANSFER,
|
|
19
|
+
data: {
|
|
20
|
+
name: fileInfo.name,
|
|
21
|
+
size: fileInfo.size,
|
|
22
|
+
mimeType: fileInfo.mimeType,
|
|
23
|
+
content: fileInfo.content
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const res = await fetch('/api/message-p2p', {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: { 'Content-Type': 'application/json' },
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
targetDid,
|
|
31
|
+
content: JSON.stringify(payload),
|
|
32
|
+
type: 'file'
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
if (res.ok) {
|
|
36
|
+
const data = await res.json();
|
|
37
|
+
return {
|
|
38
|
+
success: true,
|
|
39
|
+
messageId: data.messageId || messageId
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return { success: false, error: '文件传输失败' };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
return { success: false, error: e.message };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// 本地信息查询
|
|
51
|
+
export async function queryLocalInfo(targetDid, query) {
|
|
52
|
+
try {
|
|
53
|
+
const payload = {
|
|
54
|
+
type: 'info_query',
|
|
55
|
+
tool: P2PToolType.LOCAL_INFO,
|
|
56
|
+
query: query
|
|
57
|
+
};
|
|
58
|
+
const res = await fetch('/api/message-p2p', {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: { 'Content-Type': 'application/json' },
|
|
61
|
+
body: JSON.stringify({
|
|
62
|
+
targetDid,
|
|
63
|
+
content: JSON.stringify(payload),
|
|
64
|
+
type: 'ai-dialogue'
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
if (res.ok) {
|
|
68
|
+
const data = await res.json();
|
|
69
|
+
return {
|
|
70
|
+
success: true,
|
|
71
|
+
data: data.response,
|
|
72
|
+
messageId: data.messageId
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return { success: false, error: '信息查询失败' };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
return { success: false, error: e.message };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// 系统信息请求
|
|
84
|
+
export async function getSystemInfo(targetDid) {
|
|
85
|
+
try {
|
|
86
|
+
const payload = {
|
|
87
|
+
type: 'system_info_request',
|
|
88
|
+
tool: P2PToolType.SYSTEM_INFO
|
|
89
|
+
};
|
|
90
|
+
const res = await fetch('/api/message-p2p', {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
headers: { 'Content-Type': 'application/json' },
|
|
93
|
+
body: JSON.stringify({
|
|
94
|
+
targetDid,
|
|
95
|
+
content: JSON.stringify(payload),
|
|
96
|
+
type: 'ai-dialogue'
|
|
97
|
+
})
|
|
98
|
+
});
|
|
99
|
+
if (res.ok) {
|
|
100
|
+
const data = await res.json();
|
|
101
|
+
return {
|
|
102
|
+
success: true,
|
|
103
|
+
data: data.response,
|
|
104
|
+
messageId: data.messageId
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
return { success: false, error: '系统信息获取失败' };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
return { success: false, error: e.message };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// 文件列表请求
|
|
116
|
+
export async function listFiles(targetDid, path = '/') {
|
|
117
|
+
try {
|
|
118
|
+
const payload = {
|
|
119
|
+
type: 'file_list_request',
|
|
120
|
+
tool: P2PToolType.FILE_LIST,
|
|
121
|
+
path: path
|
|
122
|
+
};
|
|
123
|
+
const res = await fetch('/api/message-p2p', {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
headers: { 'Content-Type': 'application/json' },
|
|
126
|
+
body: JSON.stringify({
|
|
127
|
+
targetDid,
|
|
128
|
+
content: JSON.stringify(payload),
|
|
129
|
+
type: 'ai-dialogue'
|
|
130
|
+
})
|
|
131
|
+
});
|
|
132
|
+
if (res.ok) {
|
|
133
|
+
const data = await res.json();
|
|
134
|
+
return {
|
|
135
|
+
success: true,
|
|
136
|
+
data: data.response,
|
|
137
|
+
messageId: data.messageId
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
return { success: false, error: '文件列表获取失败' };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
return { success: false, error: e.message };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// 工具调用入口
|
|
149
|
+
export async function executeP2PTool(request) {
|
|
150
|
+
const { toolName, payload, targetDid } = request;
|
|
151
|
+
if (!targetDid) {
|
|
152
|
+
return { success: false, error: '未指定目标节点' };
|
|
153
|
+
}
|
|
154
|
+
switch (toolName) {
|
|
155
|
+
case P2PToolType.FILE_TRANSFER:
|
|
156
|
+
return transferFile(targetDid, payload.data);
|
|
157
|
+
case P2PToolType.LOCAL_INFO:
|
|
158
|
+
return queryLocalInfo(targetDid, payload.data);
|
|
159
|
+
case P2PToolType.SYSTEM_INFO:
|
|
160
|
+
return getSystemInfo(targetDid);
|
|
161
|
+
case P2PToolType.FILE_LIST:
|
|
162
|
+
return listFiles(targetDid, payload.data?.path || '/');
|
|
163
|
+
default:
|
|
164
|
+
return { success: false, error: `未知工具: ${toolName}` };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// 本地系统信息获取 (用于响应来自远程的请求)
|
|
168
|
+
export function getLocalSystemInfo() {
|
|
169
|
+
const memUsage = process.memoryUsage();
|
|
170
|
+
const cpuCores = require('os').cpus();
|
|
171
|
+
return {
|
|
172
|
+
platform: process.platform,
|
|
173
|
+
arch: process.arch,
|
|
174
|
+
nodeVersion: process.version,
|
|
175
|
+
memory: {
|
|
176
|
+
total: memUsage.heapTotal,
|
|
177
|
+
free: memUsage.heapTotal - memUsage.heapUsed,
|
|
178
|
+
used: memUsage.heapUsed
|
|
179
|
+
},
|
|
180
|
+
cpu: {
|
|
181
|
+
cores: cpuCores.length,
|
|
182
|
+
model: cpuCores[0]?.model || 'Unknown'
|
|
183
|
+
},
|
|
184
|
+
uptime: process.uptime()
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
// 本地文件列表 (用于响应来自远程的请求)
|
|
188
|
+
export function getLocalFileList(dirPath) {
|
|
189
|
+
try {
|
|
190
|
+
// Dynamic import for ESM compatibility
|
|
191
|
+
const pathModule = require('path');
|
|
192
|
+
const fs = require('fs');
|
|
193
|
+
const fullPath = pathModule.resolve(dirPath);
|
|
194
|
+
const files = fs.readdirSync(fullPath);
|
|
195
|
+
const fileList = files.map((name) => {
|
|
196
|
+
const fullFilePath = pathModule.join(fullPath, name);
|
|
197
|
+
let stat;
|
|
198
|
+
try {
|
|
199
|
+
stat = fs.statSync(fullFilePath);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
name: name,
|
|
206
|
+
size: stat.size,
|
|
207
|
+
isDirectory: stat.isDirectory(),
|
|
208
|
+
modified: stat.mtime.toISOString()
|
|
209
|
+
};
|
|
210
|
+
}).filter(Boolean);
|
|
211
|
+
return {
|
|
212
|
+
success: true,
|
|
213
|
+
path: fullPath,
|
|
214
|
+
files: fileList
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
return {
|
|
219
|
+
success: false,
|
|
220
|
+
path: dirPath,
|
|
221
|
+
error: e.message
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// 导出工具名称列表
|
|
226
|
+
export const P2P_TOOLS = [
|
|
227
|
+
{
|
|
228
|
+
name: P2PToolType.FILE_TRANSFER,
|
|
229
|
+
description: '传输文件到远程节点',
|
|
230
|
+
parameters: ['targetDid', 'fileInfo']
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: P2PToolType.LOCAL_INFO,
|
|
234
|
+
description: '查询远程节点本地信息',
|
|
235
|
+
parameters: ['targetDid', 'query']
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: P2PToolType.SYSTEM_INFO,
|
|
239
|
+
description: '获取远程节点系统信息',
|
|
240
|
+
parameters: ['targetDid']
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: P2PToolType.FILE_LIST,
|
|
244
|
+
description: '列出远程节点目录文件',
|
|
245
|
+
parameters: ['targetDid', 'path']
|
|
246
|
+
}
|
|
247
|
+
];
|
|
248
|
+
console.log('[P2P Tools] 工具模块已加载');
|
package/dist/web/server.js
CHANGED
|
@@ -6,6 +6,36 @@ import * as fs from 'fs/promises';
|
|
|
6
6
|
import * as fsSync from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import * as os from 'os';
|
|
9
|
+
// 2026-06-17: 终端静默 — server.ts 高频 spam (LLM 流式每个 token 一次 broadcast,
|
|
10
|
+
// 每次 P2P 收发 [v3]/[v3-meta]/[v3-cross]/[v3-friend] 各一次) 全部走 console.log proxy,
|
|
11
|
+
// 默认 (BOLLOON_VERBOSE != '1') 完全不打;VERBOSE=1 时恢复.
|
|
12
|
+
// 注意: console.error 走原生,所有错误仍然可见.
|
|
13
|
+
const VERBOSE = process.env.BOLLOON_VERBOSE === '1';
|
|
14
|
+
const SUPPRESSED_LOG_PREFIXES = [
|
|
15
|
+
'[broadcast]',
|
|
16
|
+
'[SSE 广播]',
|
|
17
|
+
'[API] /channels',
|
|
18
|
+
'[获取频道]',
|
|
19
|
+
'[v3]',
|
|
20
|
+
'[v3-meta]',
|
|
21
|
+
'[v3-cross]',
|
|
22
|
+
'[v3-friend]',
|
|
23
|
+
'[v3-async]',
|
|
24
|
+
'[saveChannels]',
|
|
25
|
+
];
|
|
26
|
+
const _origConsoleLog = console.log.bind(console);
|
|
27
|
+
console.log = (...args) => {
|
|
28
|
+
if (VERBOSE)
|
|
29
|
+
return _origConsoleLog(...args);
|
|
30
|
+
const first = args[0];
|
|
31
|
+
if (typeof first === 'string') {
|
|
32
|
+
for (const p of SUPPRESSED_LOG_PREFIXES) {
|
|
33
|
+
if (first.startsWith(p))
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return _origConsoleLog(...args);
|
|
38
|
+
};
|
|
9
39
|
import { createHyperswarmCommunicator, createTopic, KeyManager, AgentAuthManager, } from '@diap/sdk';
|
|
10
40
|
import { documentReader } from '../documents/reader.js';
|
|
11
41
|
import { initMinimax, getMinimax } from '../constraints/index.js';
|
|
@@ -1847,12 +1877,14 @@ export async function createWebServer(port = 3000, options = {}) {
|
|
|
1847
1877
|
}
|
|
1848
1878
|
app.get('/channels', async (_req, res) => {
|
|
1849
1879
|
try {
|
|
1850
|
-
console.log
|
|
1880
|
+
// 2026-06-17: 缓存命中 → 0 行;未命中 → 1 行 summary (上面 console.log proxy 已吃掉 [API] /channels 等旧日志)
|
|
1881
|
+
const t0 = Date.now();
|
|
1882
|
+
const now = t0;
|
|
1883
|
+
const hit = !!(channelsCache.data && channelsCache.cachedAt > lastChannelsWriteAt && channelsCache.cachedAt + CHANNELS_CACHE_TTL_MS > now);
|
|
1851
1884
|
const channels = await getChannelsWithDID();
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
});
|
|
1885
|
+
if (!hit) {
|
|
1886
|
+
console.log(`[channels] refresh, n=${channels.length}, t=+${Date.now() - t0}ms`);
|
|
1887
|
+
}
|
|
1856
1888
|
res.json(channels);
|
|
1857
1889
|
}
|
|
1858
1890
|
catch (err) {
|