@bolloon/bolloon-agent 0.4.13 → 0.4.14
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/agents/agent-gateway.js +130 -0
- package/dist/agents/gateway-group.js +261 -0
- package/dist/agents/gateway-network.js +278 -0
- package/dist/agents/pi-sdk-tools.js +117 -0
- package/dist/constraint-runtime/tools/PolymarketSDK/econ-integration.d.ts +55 -0
- package/dist/constraint-runtime/tools/PolymarketSDK/econ-integration.js +59 -0
- package/dist/orbitdb/cid-database.js +39 -10
- package/dist/web/client.js +273 -0
- package/dist/web/index.html +17 -0
- package/dist/web/server.js +183 -0
- package/dist/web/style.css +116 -0
- package/package.json +1 -1
package/dist/web/server.js
CHANGED
|
@@ -735,6 +735,16 @@ async function handleV3P2PMessage(parsed, conn, comm) {
|
|
|
735
735
|
}
|
|
736
736
|
// 2026-07-29: 语义分析 — 分析远端聊天内容, 隐式滑动 trustScore
|
|
737
737
|
recordInteraction(senderKey, text).catch(() => { });
|
|
738
|
+
// 2026-08-14: 远端消息带 gateway 链接 → 自动加入 (幂等, fire-and-forget 不阻塞聊天)
|
|
739
|
+
import('../agents/gateway-network.js').then(({ maybeAutoJoinGateway }) => maybeAutoJoinGateway(String(text || '')).then((note) => {
|
|
740
|
+
if (note) {
|
|
741
|
+
console.log(`[agent-gateway] ${note}`);
|
|
742
|
+
try {
|
|
743
|
+
broadcast({ type: 'gateway', content: note, channelId }, channelId);
|
|
744
|
+
}
|
|
745
|
+
catch { /* 广播失败忽略 */ }
|
|
746
|
+
}
|
|
747
|
+
}).catch(() => { })).catch(() => { });
|
|
738
748
|
console.log(`[v3] 收到 ${senderKey.substring(0, 12)}... (${tierLabel(tierState.tier)}) 对 channel ${channelId} 的 chat: "${text.substring(0, 40)}..."`);
|
|
739
749
|
try {
|
|
740
750
|
// 1. 找到 channel
|
|
@@ -2811,6 +2821,141 @@ ${goalDesc}
|
|
|
2811
2821
|
res.status(500).json({ error: e?.message });
|
|
2812
2822
|
}
|
|
2813
2823
|
});
|
|
2824
|
+
// 2026-08-14: Agent Gateway — 网络加入 / 分享链接 / 成员 / 状态 (入口要小: 一条链接)
|
|
2825
|
+
app.post('/api/gateway/join', async (req, res) => {
|
|
2826
|
+
try {
|
|
2827
|
+
const { joinNetwork } = await import('../agents/gateway-network.js');
|
|
2828
|
+
const link = String(req.body?.link || '').trim();
|
|
2829
|
+
if (!link)
|
|
2830
|
+
return res.status(400).json({ error: 'link 必填 (orbitdb:// / ipns:// / https://.../registry)' });
|
|
2831
|
+
const r = await joinNetwork(link);
|
|
2832
|
+
res.json(r);
|
|
2833
|
+
}
|
|
2834
|
+
catch (e) {
|
|
2835
|
+
res.status(500).json({ error: e?.message });
|
|
2836
|
+
}
|
|
2837
|
+
});
|
|
2838
|
+
app.get('/api/gateway/link', async (req, res) => {
|
|
2839
|
+
try {
|
|
2840
|
+
const { shareNetworkLink } = await import('../agents/gateway-network.js');
|
|
2841
|
+
const name = String(req.query?.name || '').trim() || undefined;
|
|
2842
|
+
const r = await shareNetworkLink(name ? { name } : undefined);
|
|
2843
|
+
if (!r.ok)
|
|
2844
|
+
return res.status(400).json({ error: r.error });
|
|
2845
|
+
res.json({ ok: true, link: r.link });
|
|
2846
|
+
}
|
|
2847
|
+
catch (e) {
|
|
2848
|
+
res.status(500).json({ error: e?.message });
|
|
2849
|
+
}
|
|
2850
|
+
});
|
|
2851
|
+
app.get('/api/gateway/networks', async (_req, res) => {
|
|
2852
|
+
try {
|
|
2853
|
+
const { listJoinedNetworks } = await import('../agents/gateway-network.js');
|
|
2854
|
+
res.json({ networks: await listJoinedNetworks() });
|
|
2855
|
+
}
|
|
2856
|
+
catch (e) {
|
|
2857
|
+
res.status(500).json({ error: e?.message });
|
|
2858
|
+
}
|
|
2859
|
+
});
|
|
2860
|
+
app.get('/api/gateway/status', async (_req, res) => {
|
|
2861
|
+
try {
|
|
2862
|
+
const { gatewayStatus } = await import('../agents/agent-gateway.js');
|
|
2863
|
+
const { getAgentRegistry } = await import('../agents/agent-registry.js');
|
|
2864
|
+
const { listJoinedNetworks } = await import('../agents/gateway-network.js');
|
|
2865
|
+
const registry = getAgentRegistry();
|
|
2866
|
+
const services = await registry.list();
|
|
2867
|
+
res.json({
|
|
2868
|
+
ready: registry.ready,
|
|
2869
|
+
count: services.length,
|
|
2870
|
+
services,
|
|
2871
|
+
networks: await listJoinedNetworks(),
|
|
2872
|
+
summary: await gatewayStatus(),
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
catch (e) {
|
|
2876
|
+
res.status(500).json({ error: e?.message });
|
|
2877
|
+
}
|
|
2878
|
+
});
|
|
2879
|
+
// ============ 2026-08-14: P2P 群组 (微信式群聊, OrbitDB events store) ============
|
|
2880
|
+
app.post('/api/gateway/groups', async (req, res) => {
|
|
2881
|
+
try {
|
|
2882
|
+
const { createGroup } = await import('../agents/gateway-group.js');
|
|
2883
|
+
const r = await createGroup(String(req.body?.name || '').trim(), {
|
|
2884
|
+
from: String(req.body?.from || '').trim() || undefined,
|
|
2885
|
+
hello: req.body?.hello ? String(req.body.hello) : undefined,
|
|
2886
|
+
});
|
|
2887
|
+
if (!r.ok)
|
|
2888
|
+
return res.status(400).json({ error: r.error });
|
|
2889
|
+
registerGroupSse(r.group.id, r.group.name);
|
|
2890
|
+
res.json({ ok: true, group: r.group });
|
|
2891
|
+
}
|
|
2892
|
+
catch (e) {
|
|
2893
|
+
res.status(500).json({ error: e?.message });
|
|
2894
|
+
}
|
|
2895
|
+
});
|
|
2896
|
+
app.post('/api/gateway/groups/join', async (req, res) => {
|
|
2897
|
+
try {
|
|
2898
|
+
const { joinGroup } = await import('../agents/gateway-group.js');
|
|
2899
|
+
const link = String(req.body?.link || '').trim();
|
|
2900
|
+
if (!link)
|
|
2901
|
+
return res.status(400).json({ error: 'link 必填 (orbitdb://...?type=group&name=...)' });
|
|
2902
|
+
const r = await joinGroup(link);
|
|
2903
|
+
if (!r.ok)
|
|
2904
|
+
return res.status(400).json({ error: r.error });
|
|
2905
|
+
if (r.group)
|
|
2906
|
+
registerGroupSse(r.group.id, r.group.name);
|
|
2907
|
+
res.json(r);
|
|
2908
|
+
}
|
|
2909
|
+
catch (e) {
|
|
2910
|
+
res.status(500).json({ error: e?.message });
|
|
2911
|
+
}
|
|
2912
|
+
});
|
|
2913
|
+
app.get('/api/gateway/groups', async (_req, res) => {
|
|
2914
|
+
try {
|
|
2915
|
+
const { listGroups, groupInfo } = await import('../agents/gateway-group.js');
|
|
2916
|
+
const groups = await listGroups();
|
|
2917
|
+
const detailed = await Promise.all(groups.map((g) => groupInfo(g.id).catch(() => g)));
|
|
2918
|
+
res.json({ groups: detailed });
|
|
2919
|
+
}
|
|
2920
|
+
catch (e) {
|
|
2921
|
+
res.status(500).json({ error: e?.message });
|
|
2922
|
+
}
|
|
2923
|
+
});
|
|
2924
|
+
app.get('/api/gateway/groups/:id/messages', async (req, res) => {
|
|
2925
|
+
try {
|
|
2926
|
+
const { groupMessages } = await import('../agents/gateway-group.js');
|
|
2927
|
+
const limit = Math.min(Number(req.query?.limit || 50), 200);
|
|
2928
|
+
const msgs = await groupMessages(String(req.params.id), limit);
|
|
2929
|
+
res.json({ messages: msgs });
|
|
2930
|
+
}
|
|
2931
|
+
catch (e) {
|
|
2932
|
+
res.status(500).json({ error: e?.message });
|
|
2933
|
+
}
|
|
2934
|
+
});
|
|
2935
|
+
app.post('/api/gateway/groups/:id/message', async (req, res) => {
|
|
2936
|
+
try {
|
|
2937
|
+
const { groupSend } = await import('../agents/gateway-group.js');
|
|
2938
|
+
const r = await groupSend(String(req.params.id), String(req.body?.text || ''), String(req.body?.from || 'web-user'));
|
|
2939
|
+
if (!r.ok)
|
|
2940
|
+
return res.status(400).json({ error: r.error });
|
|
2941
|
+
res.json({ ok: true });
|
|
2942
|
+
}
|
|
2943
|
+
catch (e) {
|
|
2944
|
+
res.status(500).json({ error: e?.message });
|
|
2945
|
+
}
|
|
2946
|
+
});
|
|
2947
|
+
app.get('/api/gateway/groups/:id/link', async (req, res) => {
|
|
2948
|
+
try {
|
|
2949
|
+
const { groupLink } = await import('../agents/gateway-group.js');
|
|
2950
|
+
const link = await groupLink(String(req.params.id));
|
|
2951
|
+
if (!link)
|
|
2952
|
+
return res.status(404).json({ error: '群组不存在' });
|
|
2953
|
+
res.json({ ok: true, link });
|
|
2954
|
+
}
|
|
2955
|
+
catch (e) {
|
|
2956
|
+
res.status(500).json({ error: e?.message });
|
|
2957
|
+
}
|
|
2958
|
+
});
|
|
2814
2959
|
// 2026-08-13: 人工支付审批 API — YAML 验证门 confirm 的支付请求
|
|
2815
2960
|
app.get('/api/payments/pending', async (_req, res) => {
|
|
2816
2961
|
try {
|
|
@@ -2910,11 +3055,38 @@ ${goalDesc}
|
|
|
2910
3055
|
const { warmAgentRegistry } = await import('../agents/agent-registry.js');
|
|
2911
3056
|
const ok = await warmAgentRegistry();
|
|
2912
3057
|
console.log(`[agent-registry] OrbitDB 服务注册表 ${ok ? '已启用' : '未启用 (回退本地)'}`);
|
|
3058
|
+
// 2026-08-14: 恢复已加入的 Agent 网络 (重启后仍是家庭成员, 失败静默保留记录)
|
|
3059
|
+
const { restoreJoinedNetworks } = await import('../agents/gateway-network.js');
|
|
3060
|
+
restoreJoinedNetworks().then((r) => {
|
|
3061
|
+
if (r.total > 0)
|
|
3062
|
+
console.log(`[agent-gateway] 恢复 ${r.restored}/${r.total} 个已加入网络 (失败 ${r.failed}, 记录保留)`);
|
|
3063
|
+
}).catch(() => { });
|
|
3064
|
+
// 2026-08-14: 恢复已加入的群组 (重开 store + 注册 SSE 广播)
|
|
3065
|
+
const { restoreGroups, listGroups } = await import('../agents/gateway-group.js');
|
|
3066
|
+
restoreGroups().then((r) => {
|
|
3067
|
+
if (r.total > 0)
|
|
3068
|
+
console.log(`[agent-gateway] 恢复 ${r.restored}/${r.total} 个群组 (失败 ${r.failed})`);
|
|
3069
|
+
listGroups().then((gs) => { for (const g of gs)
|
|
3070
|
+
registerGroupSse(g.id, g.name); }).catch(() => { });
|
|
3071
|
+
}).catch(() => { });
|
|
2913
3072
|
}
|
|
2914
3073
|
catch (e) {
|
|
2915
3074
|
console.warn('[agent-registry] 预热失败 (非致命):', e?.message?.slice(0, 120));
|
|
2916
3075
|
}
|
|
2917
3076
|
})();
|
|
3077
|
+
// 2026-08-14: 群组消息 → SSE 广播 (手机端/Web 实时收到群聊)
|
|
3078
|
+
const groupSseRegistered = new Set();
|
|
3079
|
+
function registerGroupSse(groupId, groupName) {
|
|
3080
|
+
if (groupSseRegistered.has(groupId))
|
|
3081
|
+
return;
|
|
3082
|
+
groupSseRegistered.add(groupId);
|
|
3083
|
+
import('../agents/gateway-group.js').then(({ onGroupMessage }) => onGroupMessage(groupId, (msg) => {
|
|
3084
|
+
try {
|
|
3085
|
+
broadcast({ type: 'group-message', groupId, groupName, message: msg }, 'p2p-global');
|
|
3086
|
+
}
|
|
3087
|
+
catch { /* 忽略 */ }
|
|
3088
|
+
})).catch(() => { });
|
|
3089
|
+
}
|
|
2918
3090
|
app.get('/api/health', (_req, res) => {
|
|
2919
3091
|
res.json(healthCheck(getPackageVersion()));
|
|
2920
3092
|
});
|
|
@@ -3655,6 +3827,17 @@ ${goalDesc}
|
|
|
3655
3827
|
catch { /* 预激活失败不阻塞 */ }
|
|
3656
3828
|
// 将真实 DID 作为上下文前缀,让 AI 使用真实的 DID 而不是自己编造的
|
|
3657
3829
|
let contextHint = '';
|
|
3830
|
+
// 2026-08-14: 本地消息带 gateway 链接 → 自动加入, 结果注入 agent 上下文 (5s 上限, 不阻塞 LLM)
|
|
3831
|
+
try {
|
|
3832
|
+
const { maybeAutoJoinGateway } = await import('../agents/gateway-network.js');
|
|
3833
|
+
const gwNote = await Promise.race([
|
|
3834
|
+
maybeAutoJoinGateway(text),
|
|
3835
|
+
new Promise((resolve) => setTimeout(() => resolve(null), 5000)),
|
|
3836
|
+
]);
|
|
3837
|
+
if (gwNote)
|
|
3838
|
+
contextHint += `[系统上下文] ${gwNote}\n`;
|
|
3839
|
+
}
|
|
3840
|
+
catch { /* 自动加入失败不阻塞 */ }
|
|
3658
3841
|
// 2026-08-02: slash 命令提示 (在 /message 开头解析, 这里注入)
|
|
3659
3842
|
if (slashCommandHint)
|
|
3660
3843
|
contextHint += slashCommandHint;
|
package/dist/web/style.css
CHANGED
|
@@ -4944,3 +4944,119 @@ body:has(> .api-config-page) {
|
|
|
4944
4944
|
font-weight: 500;
|
|
4945
4945
|
}
|
|
4946
4946
|
|
|
4947
|
+
|
|
4948
|
+
/* ============ 2026-08-14: Agent 网络 (Gateway) UI ============ */
|
|
4949
|
+
.gateway-item {
|
|
4950
|
+
display: flex;
|
|
4951
|
+
align-items: center;
|
|
4952
|
+
gap: 8px;
|
|
4953
|
+
padding: 6px 10px;
|
|
4954
|
+
cursor: pointer;
|
|
4955
|
+
border-radius: 6px;
|
|
4956
|
+
transition: background 0.15s;
|
|
4957
|
+
}
|
|
4958
|
+
.gateway-item:hover { background: rgba(196, 214, 64, 0.1); }
|
|
4959
|
+
.gateway-item-icon { font-size: 14px; flex-shrink: 0; }
|
|
4960
|
+
.gateway-item-main { display: flex; flex-direction: column; min-width: 0; }
|
|
4961
|
+
.gateway-item-name { font-size: 12.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
4962
|
+
.gateway-item-sub { font-size: 10.5px; opacity: 0.65; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
4963
|
+
.gateway-item-net .gateway-item-icon { opacity: 0.8; }
|
|
4964
|
+
|
|
4965
|
+
/* modal 通用 */
|
|
4966
|
+
.gw-modal-overlay {
|
|
4967
|
+
position: fixed; inset: 0; z-index: 10000;
|
|
4968
|
+
background: rgba(0, 0, 0, 0.55);
|
|
4969
|
+
display: flex; align-items: center; justify-content: center;
|
|
4970
|
+
backdrop-filter: blur(2px);
|
|
4971
|
+
}
|
|
4972
|
+
.gw-modal {
|
|
4973
|
+
position: relative;
|
|
4974
|
+
background: var(--bg, #1a1a18);
|
|
4975
|
+
border: 1px solid rgba(196, 214, 64, 0.35);
|
|
4976
|
+
border-radius: 12px;
|
|
4977
|
+
padding: 18px 20px;
|
|
4978
|
+
max-width: 480px; width: 92%;
|
|
4979
|
+
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
|
|
4980
|
+
color: var(--fg, #d8d8c8);
|
|
4981
|
+
}
|
|
4982
|
+
.gw-modal-close {
|
|
4983
|
+
position: absolute; top: 10px; right: 12px;
|
|
4984
|
+
cursor: pointer; opacity: 0.6; font-size: 15px;
|
|
4985
|
+
padding: 4px 8px; border-radius: 6px;
|
|
4986
|
+
}
|
|
4987
|
+
.gw-modal-close:hover { opacity: 1; background: rgba(255, 255, 255, 0.08); }
|
|
4988
|
+
|
|
4989
|
+
/* 加入/创建 */
|
|
4990
|
+
.gw-join h3 { margin: 0 0 6px; font-size: 15px; color: #c4d640; }
|
|
4991
|
+
.gw-hint { font-size: 11.5px; opacity: 0.7; margin: 0 0 12px; }
|
|
4992
|
+
.gw-join-input {
|
|
4993
|
+
width: 100%; box-sizing: border-box;
|
|
4994
|
+
background: rgba(255, 255, 255, 0.06);
|
|
4995
|
+
border: 1px solid rgba(255, 255, 255, 0.18);
|
|
4996
|
+
border-radius: 8px; color: inherit;
|
|
4997
|
+
padding: 10px 12px; font-size: 12.5px;
|
|
4998
|
+
font-family: 'JetBrains Mono', monospace;
|
|
4999
|
+
}
|
|
5000
|
+
.gw-join-input:focus { outline: none; border-color: #c4d640; }
|
|
5001
|
+
.gw-join-actions { display: flex; gap: 10px; margin-top: 12px; }
|
|
5002
|
+
.gw-join-go, .gw-join-my {
|
|
5003
|
+
padding: 8px 16px; border-radius: 8px; border: none; cursor: pointer;
|
|
5004
|
+
font-size: 12.5px; font-weight: 600;
|
|
5005
|
+
background: #c4d640; color: #1a1a18;
|
|
5006
|
+
}
|
|
5007
|
+
.gw-join-my { background: rgba(196, 214, 64, 0.15); color: #c4d640; border: 1px solid rgba(196, 214, 64, 0.4); }
|
|
5008
|
+
.gw-join-result { margin-top: 12px; font-size: 12px; line-height: 1.5; word-break: break-all; }
|
|
5009
|
+
.gw-join-result code {
|
|
5010
|
+
display: block; background: rgba(255, 255, 255, 0.07);
|
|
5011
|
+
padding: 6px 8px; border-radius: 6px; font-size: 11px;
|
|
5012
|
+
word-break: break-all; margin-top: 4px;
|
|
5013
|
+
}
|
|
5014
|
+
|
|
5015
|
+
/* 群聊 */
|
|
5016
|
+
.gw-chat { display: flex; flex-direction: column; height: 420px; max-height: 70vh; }
|
|
5017
|
+
.gw-chat-header {
|
|
5018
|
+
display: flex; justify-content: space-between; align-items: center;
|
|
5019
|
+
padding-bottom: 10px; border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
|
5020
|
+
font-size: 14px;
|
|
5021
|
+
}
|
|
5022
|
+
.gw-chat-invite {
|
|
5023
|
+
background: rgba(196, 214, 64, 0.15); color: #c4d640;
|
|
5024
|
+
border: 1px solid rgba(196, 214, 64, 0.4);
|
|
5025
|
+
border-radius: 6px; padding: 4px 10px; font-size: 11.5px; cursor: pointer;
|
|
5026
|
+
}
|
|
5027
|
+
.gw-chat-msgs {
|
|
5028
|
+
flex: 1; overflow-y: auto; padding: 12px 4px;
|
|
5029
|
+
display: flex; flex-direction: column; gap: 10px;
|
|
5030
|
+
}
|
|
5031
|
+
.gw-msg {
|
|
5032
|
+
max-width: 85%; align-self: flex-start;
|
|
5033
|
+
background: rgba(255, 255, 255, 0.08);
|
|
5034
|
+
border-radius: 10px 10px 10px 3px;
|
|
5035
|
+
padding: 7px 11px;
|
|
5036
|
+
}
|
|
5037
|
+
.gw-msg-mine {
|
|
5038
|
+
align-self: flex-end;
|
|
5039
|
+
background: rgba(196, 214, 64, 0.18);
|
|
5040
|
+
border-radius: 10px 10px 3px 10px;
|
|
5041
|
+
}
|
|
5042
|
+
.gw-msg-meta { font-size: 10.5px; opacity: 0.65; margin-bottom: 3px; }
|
|
5043
|
+
.gw-msg-text { font-size: 12.5px; line-height: 1.5; word-break: break-word; white-space: pre-wrap; }
|
|
5044
|
+
.gw-msg-empty { text-align: center; opacity: 0.5; font-size: 12px; padding: 30px 0; }
|
|
5045
|
+
.gw-chat-input-row { display: flex; gap: 8px; padding-top: 10px; border-top: 1px solid rgba(255, 255, 255, 0.12); }
|
|
5046
|
+
.gw-chat-input {
|
|
5047
|
+
flex: 1; background: rgba(255, 255, 255, 0.06);
|
|
5048
|
+
border: 1px solid rgba(255, 255, 255, 0.18);
|
|
5049
|
+
border-radius: 8px; color: inherit;
|
|
5050
|
+
padding: 9px 12px; font-size: 12.5px;
|
|
5051
|
+
}
|
|
5052
|
+
.gw-chat-input:focus { outline: none; border-color: #c4d640; }
|
|
5053
|
+
.gw-chat-send {
|
|
5054
|
+
background: #c4d640; color: #1a1a18; border: none;
|
|
5055
|
+
border-radius: 8px; padding: 0 16px; font-size: 12.5px; font-weight: 600; cursor: pointer;
|
|
5056
|
+
}
|
|
5057
|
+
|
|
5058
|
+
/* 手机端窄屏适配 */
|
|
5059
|
+
@media (max-width: 640px) {
|
|
5060
|
+
.gw-modal { max-width: 94%; padding: 14px; }
|
|
5061
|
+
.gw-chat { height: 60vh; }
|
|
5062
|
+
}
|