@bolloon/bolloon-agent 0.1.40 → 0.1.42
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/.comm/README.md +21 -0
- package/.comm/default/2026-06-17T08-23-00-017Z-8a735de8.md +7 -0
- package/CLAUDE.md +3 -0
- package/dist/agents/intent-classifier.js +99 -0
- package/dist/agents/pi-sdk.js +1364 -58
- package/dist/agents/pre-tool-validator.js +2 -1
- package/dist/agents/shell-guard.js +9 -3
- package/dist/agents/shell-tool.js +28 -13
- package/dist/agents/task-state.js +224 -0
- package/dist/agents/workflow-pivot-loop.js +30 -0
- package/dist/bollharness-integration/gate-state-machine.js +13 -0
- package/dist/bollharness-integration/integration.js +71 -0
- package/dist/bollharness-integration/skill-adapter.js +52 -127
- package/dist/bootstrap/context-hierarchy.js +6 -4
- package/dist/cli/interface.js +28 -0
- package/dist/documents/reader.js +14 -0
- package/dist/git-transport/chat-render.js +155 -0
- package/dist/git-transport/chat-repo.js +370 -0
- package/dist/git-transport/chat-types.js +23 -0
- package/dist/git-transport/chat-watch.js +102 -0
- package/dist/index.js +471 -25
- package/dist/llm/pi-ai.js +103 -27
- package/dist/network/local-inbox-bus.js +73 -0
- package/dist/network/p2p-direct.js +3 -4
- package/dist/pi-ecosystem-judgment/adaptive-scan.js +6 -2
- package/dist/pi-ecosystem-judgment/causal-judge.js +3 -3
- package/dist/pi-ecosystem-judgment/index.js +1 -1
- package/dist/security/tool-gate.js +11 -0
- package/dist/web/client.js +2876 -3770
- package/dist/web/components/p2p/index.js +226 -264
- package/dist/web/server.js +83 -15
- package/dist/web/ui/message-renderer.js +326 -442
- package/dist/web/ui/step-timeline.js +255 -351
- package/package.json +2 -2
- package/scripts/lefthook-helper.sh +69 -0
- package/dist/web/components/p2p/P2PModal.js +0 -188
- package/dist/web/components/p2p/p2p-modal.js +0 -657
- package/dist/web/components/p2p/p2p-tools.js +0 -248
package/dist/web/server.js
CHANGED
|
@@ -769,6 +769,50 @@ async function handleV3P2PMessage(parsed, conn, comm) {
|
|
|
769
769
|
}
|
|
770
770
|
return;
|
|
771
771
|
}
|
|
772
|
+
// v3 新增: --collab CLI 派任务过来, 对方 web 收到后跑 LLM 干活, 回结果
|
|
773
|
+
if (op === 'agent.collab.run') {
|
|
774
|
+
const { requestId, task, fromPublicKey, fromRole, timeoutMs } = parsed.payload || {};
|
|
775
|
+
if (!requestId || !task) {
|
|
776
|
+
console.warn(`[v3-collab] agent.collab.run 缺少 requestId/task`);
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
const senderKey = fromPublicKey || peerKey;
|
|
780
|
+
console.log(`[v3-collab] 收到 ${senderKey.substring(0, 12)}... (${fromRole}) 的协作任务: "${task.substring(0, 60)}..."`);
|
|
781
|
+
const startTs = Date.now();
|
|
782
|
+
try {
|
|
783
|
+
// 调 LLM: 走 getAgentForChannel 拿 agent, 用 prompt() 拿 string 结果
|
|
784
|
+
const visitorHint = `[系统上下文] 协作任务来源: 远端 peer (P2P, publicKey=${senderKey.substring(0, 12)}..., role=${fromRole || 'unknown'}). 这是通过 P2P 派过来的协作任务, 回答后会自动回到对方那里. 简洁完成, 不需要反问.\n\n`;
|
|
785
|
+
const fullPrompt = `【本轮协作任务】\n${task}\n【任务结束】\n\n${visitorHint}`;
|
|
786
|
+
// 临时用 channelId = "__collab__" 拿个一次性 agent
|
|
787
|
+
const collabChannelId = `__collab_${senderKey.substring(0, 8)}__`;
|
|
788
|
+
const agent = await getAgentForChannel(collabChannelId, '', `collab-${senderKey.substring(0, 8)}`, undefined);
|
|
789
|
+
const resultText = await agent.prompt(fullPrompt);
|
|
790
|
+
const reply = JSON.stringify({
|
|
791
|
+
v: 3,
|
|
792
|
+
op: 'agent.collab.reply',
|
|
793
|
+
payload: {
|
|
794
|
+
requestId,
|
|
795
|
+
fromPublicKey: v3P2PRef?.getPublicKey() || '',
|
|
796
|
+
result: resultText || '(empty)',
|
|
797
|
+
durationMs: Date.now() - startTs,
|
|
798
|
+
},
|
|
799
|
+
});
|
|
800
|
+
await comm.sendToConnection(conn.id, reply);
|
|
801
|
+
console.log(`[v3-collab] 已回 reply (${Date.now() - startTs}ms, ${(resultText || '').length} chars)`);
|
|
802
|
+
}
|
|
803
|
+
catch (e) {
|
|
804
|
+
console.error(`[v3-collab] 处理失败:`, e.message);
|
|
805
|
+
try {
|
|
806
|
+
const errReply = JSON.stringify({
|
|
807
|
+
v: 3, op: 'agent.collab.reply',
|
|
808
|
+
payload: { requestId, fromPublicKey: v3P2PRef?.getPublicKey() || '', error: e.message, result: '' }
|
|
809
|
+
});
|
|
810
|
+
await comm.sendToConnection(conn.id, errReply);
|
|
811
|
+
}
|
|
812
|
+
catch { }
|
|
813
|
+
}
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
772
816
|
// v3 新增: 收到远端发来的 @-mention 跨渠道消息, 存到本地 target channel
|
|
773
817
|
if (op === 'agent.cross.post') {
|
|
774
818
|
const { targetChannelId, targetChannelName, originChannelId, originChannelName, text, fromPublicKey } = parsed.payload || {};
|
|
@@ -936,7 +980,14 @@ async function getAgentForChannel(channelId, channelDid, channelName, channelDid
|
|
|
936
980
|
const session = await createAgentSession({
|
|
937
981
|
cwd: process.cwd(),
|
|
938
982
|
peerId: `channel-${channelId}:${currentSessionId}`,
|
|
939
|
-
identityDoc
|
|
983
|
+
identityDoc,
|
|
984
|
+
// M2.3 (2026-06-17): 构造时从 session JSON 回灌历史 — 服务重启后 LLM 仍记得前面对话
|
|
985
|
+
// key 跟 server.ts:240 写入路径保持一致: ~/.bolloon/sessions/cache/<key>.json
|
|
986
|
+
loadSessionKey: sessionKey,
|
|
987
|
+
// M3.1 (2026-06-17): 默认启用 WorkflowPivotLoop — web 路径以前死代码, 现在用
|
|
988
|
+
// pivot loop 自带 quality scoring + task complexity analysis + 30 iters cap
|
|
989
|
+
// (老 ReAct 10000 iter cap 容易跑飞)
|
|
990
|
+
usePivotLoop: true,
|
|
940
991
|
}, true); // forceNew: true 强制创建新实例
|
|
941
992
|
channelSessions.set(sessionKey, session);
|
|
942
993
|
if (channelDid) {
|
|
@@ -1334,20 +1385,31 @@ export async function createWebServer(port = 3000, options = {}) {
|
|
|
1334
1385
|
app.get('/', (req, res) => {
|
|
1335
1386
|
res.sendFile(join(webRoot, 'index.html'));
|
|
1336
1387
|
});
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
if (
|
|
1346
|
-
|
|
1347
|
-
res.status(500).type('text/plain').send('api-config.html send error: ' + err.message);
|
|
1388
|
+
// 2026-06-17: /api-config 与 / 改用 fs.readFileSync + res.send 兑底,
|
|
1389
|
+
// 不再依赖 express.sendFile. 原因: npm 全局安装路径下, send library 偶发报
|
|
1390
|
+
// "Not Found" 即使 fs.existsSync+fs.stat 都成功. 现象: 页面 200 但内容是
|
|
1391
|
+
// "api-config.html send error: Not Found" 5xx 错误页. 同步读 + res.type().send
|
|
1392
|
+
// 可靠返回原始 HTML bytes.
|
|
1393
|
+
function serveStaticHtml(relPath, notFoundMsg, label) {
|
|
1394
|
+
return (_req, res) => {
|
|
1395
|
+
const filePath = join(webRoot, relPath);
|
|
1396
|
+
if (!fsSync.existsSync(filePath)) {
|
|
1397
|
+
return res.status(404).type('text/plain').send(notFoundMsg);
|
|
1348
1398
|
}
|
|
1349
|
-
|
|
1350
|
-
|
|
1399
|
+
try {
|
|
1400
|
+
const html = fsSync.readFileSync(filePath);
|
|
1401
|
+
res.type('text/html; charset=utf-8').send(html);
|
|
1402
|
+
}
|
|
1403
|
+
catch (err) {
|
|
1404
|
+
console.error(`[${label}] readFileSync failed:`, err.message);
|
|
1405
|
+
if (!res.headersSent) {
|
|
1406
|
+
res.status(500).type('text/plain').send(`${relPath} read error: ${err.message}`);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
app.get('/', serveStaticHtml('index.html', 'index.html not found; please run `npm run build:web`', 'index'));
|
|
1412
|
+
app.get('/api-config', serveStaticHtml('api-config.html', 'api-config.html not found; please run `npm run build:web`', 'api-config'));
|
|
1351
1413
|
// 全局兜底: 任何 next(err) 走到这里, 给出结构化 4xx/5xx 而不是默认 HTML
|
|
1352
1414
|
app.use((err, req, res, _next) => {
|
|
1353
1415
|
console.error('[server] unhandled error on', req.method, req.path, '-', err?.message || err);
|
|
@@ -1654,13 +1716,19 @@ export async function createWebServer(port = 3000, options = {}) {
|
|
|
1654
1716
|
console.log(`[chat] aborted channel=${channelId}`);
|
|
1655
1717
|
}
|
|
1656
1718
|
else {
|
|
1657
|
-
|
|
1719
|
+
// M1.2 (2026-06-17): 不再 rethrow — 把错误塞到 fullResponse 让 broadcast 出来, 后续 session 仍保存
|
|
1720
|
+
// 旧行为: 抛到外层 catch, 触发 500 + 用户消息丢失 (session 不保存)
|
|
1721
|
+
console.error(`[chat] LLM 调用失败 channel=${channelId}:`, err);
|
|
1722
|
+
fullResponse = `[错误: LLM 调用失败] ${String(err?.message || err).slice(0, 300)}`;
|
|
1723
|
+
broadcast({ type: 'error', content: fullResponse }, channelId);
|
|
1658
1724
|
}
|
|
1659
1725
|
}
|
|
1660
1726
|
// abort 模式: 给 partial 拼后缀
|
|
1661
1727
|
if (runState.abortController?.signal.aborted && fullResponse.trim().length > 0) {
|
|
1662
1728
|
fullResponse = fullResponse + '\n\n_[生成已中断]_';
|
|
1663
1729
|
}
|
|
1730
|
+
// 2026-06-18: 修 lastFinalReply 没设 → /api/loop/inspect 永远返回空
|
|
1731
|
+
runState.lastFinalReply = fullResponse;
|
|
1664
1732
|
// v3 新增: 解析 LLM 回复里的 @-mentions, 转发到目标 channel
|
|
1665
1733
|
await routeMentionsInReply(channelId, fullResponse, localChannels, remoteChannels);
|
|
1666
1734
|
broadcast({ type: 'ai', content: fullResponse }, channelId);
|