@bolloon/bolloon-agent 0.4.22 → 0.4.24
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/gateway-join.js +271 -0
- package/dist/agents/pi-sdk-tools.js +75 -2
- package/dist/agents/pi-sdk.js +6 -3
- package/dist/ios/index.html +74 -17
- package/dist/ios/mobile-agent.js +49 -4
- package/dist/ios/mobile-chain.js +481 -0
- package/dist/ios/mobile-core.js +373 -13
- package/dist/ios/mobile-helia.js +683 -0
- package/dist/ios/mobile-ipfs.js +680 -0
- package/dist/ios/mobile-orbit.js +268 -0
- package/dist/ios/mobile-p2p.js +130 -1
- package/dist/ios/mobile-social.js +624 -0
- package/dist/ios/mobile-sync.js +193 -0
- package/dist/ios/mobile-trade.js +492 -0
- package/dist/ios/mobile-wallet.js +11 -0
- package/dist/ios/mobile.css +24 -0
- package/dist/ios/mobile.html +74 -17
- package/dist/ios/mobile.js +911 -55
- package/dist/ios/routes-x402-info.js +194 -0
- package/dist/ios/server.js +303 -9
- package/dist/ios/sw.js +26 -2
- package/dist/llm/pi-ai.js +35 -2
- package/dist/network/agent-network.js +78 -6
- package/dist/web/agent-delegate-server.js +58 -12
- package/dist/web/mobile-agent.js +195 -1
- package/dist/web/mobile-core.js +187 -1
- package/dist/web/mobile.css +24 -0
- package/dist/web/mobile.html +23 -14
- package/dist/web/mobile.js +439 -45
- package/dist/web/server.js +114 -9
- package/dist/web/sw.js +26 -2
- package/package.json +1 -1
package/dist/web/server.js
CHANGED
|
@@ -2886,6 +2886,16 @@ ${goalDesc}
|
|
|
2886
2886
|
out.judgments = [];
|
|
2887
2887
|
out.judgmentsError = e?.message;
|
|
2888
2888
|
}
|
|
2889
|
+
// 本机 skills (~/.bolloon/skills/) — 手机端「智能体控制 (MCP / Skills)」页读取
|
|
2890
|
+
try {
|
|
2891
|
+
const { loadSkillsFromPaths, defaultSkillPaths } = await import('../agents/skill-loader.js');
|
|
2892
|
+
const list = await loadSkillsFromPaths(defaultSkillPaths());
|
|
2893
|
+
out.skills = list.map((k) => ({ name: String(k.name || ''), description: String(k.description || '').slice(0, 200) }));
|
|
2894
|
+
}
|
|
2895
|
+
catch (e) {
|
|
2896
|
+
out.skills = [];
|
|
2897
|
+
out.skillsError = e?.message;
|
|
2898
|
+
}
|
|
2889
2899
|
// Agent 服务 Registry (发现层)
|
|
2890
2900
|
try {
|
|
2891
2901
|
const { getAgentRegistry } = await import('../agents/agent-registry.js');
|
|
@@ -3007,6 +3017,68 @@ ${goalDesc}
|
|
|
3007
3017
|
res.status(500).json({ ok: false, error: e?.message });
|
|
3008
3018
|
}
|
|
3009
3019
|
});
|
|
3020
|
+
// 2026-09-15: agent-delegate (manifest 协议 + agent_delegate) **启动即挂载**
|
|
3021
|
+
// 文档 bolloon-gateway-join.md 第 3 节要求 POST /api/agent/register 可用;
|
|
3022
|
+
// 之前只在 iroh 懒初始化 (/api/iroh/info 首次访问) 的收尾挂上 → 没触发时恒 404。
|
|
3023
|
+
//
|
|
3024
|
+
// 2026-09-15 (二修): 同时注入**真执行器** —— 被委派的一方不再是
|
|
3025
|
+
// `resultCid: mock-<ts>` 的假签收: 真的跑本地 agent session 出结果,
|
|
3026
|
+
// 并把结果存进 OrbitDB 得到真实内容寻址 CID; 无活跃 channel / 无 LLM 时如实报错。
|
|
3027
|
+
const delegateExecutor = async (req) => {
|
|
3028
|
+
try {
|
|
3029
|
+
const channels = await loadChannels();
|
|
3030
|
+
const active = (() => {
|
|
3031
|
+
try {
|
|
3032
|
+
const raw = fsSync.existsSync(path.join(process.env.HOME || '/tmp', '.bolloon', 'active-channel.json'))
|
|
3033
|
+
? fsSync.readFileSync(path.join(process.env.HOME || '/tmp', '.bolloon', 'active-channel.json'), 'utf-8') : '';
|
|
3034
|
+
return raw ? JSON.parse(raw) : null;
|
|
3035
|
+
}
|
|
3036
|
+
catch {
|
|
3037
|
+
return null;
|
|
3038
|
+
}
|
|
3039
|
+
})();
|
|
3040
|
+
const ch = channels.find((c) => c.id === active?.channelId) || channels.find((c) => c.id === active?.id) || channels[0];
|
|
3041
|
+
if (!ch)
|
|
3042
|
+
return { ok: false, summary: 'no local channel to execute with', error: 'no-channel' };
|
|
3043
|
+
const agent = await getAgentForChannel(ch.id, ch.publicKey, ch.name, ch.didDocument);
|
|
3044
|
+
const task = [
|
|
3045
|
+
`【被委派任务 · 能力 ${req.capability}】`,
|
|
3046
|
+
req.instruction,
|
|
3047
|
+
req.docPath ? `\n资料路径: ${req.docPath}` : '',
|
|
3048
|
+
req.docContent ? `\n资料内容:\n${req.docContent}` : '',
|
|
3049
|
+
`\n(来自 agent ${req.fromAgentId || 'unknown'}),请直接给出可交付结果。`,
|
|
3050
|
+
].join('');
|
|
3051
|
+
const out = await agent.prompt(task);
|
|
3052
|
+
const text = String(out || '').trim();
|
|
3053
|
+
if (!text || text.startsWith('❌') || text.startsWith('[AI 服务调用失败]')) {
|
|
3054
|
+
return { ok: false, summary: text.slice(0, 800) || '(空结果)', error: 'execution-failed' };
|
|
3055
|
+
}
|
|
3056
|
+
// 真结果 → 内容寻址存储 (CID), 失败不编造 CID, 只回摘要
|
|
3057
|
+
let cid;
|
|
3058
|
+
try {
|
|
3059
|
+
const { getCIDDatabase } = await import('../orbitdb/cid-database.js');
|
|
3060
|
+
const rec = await getCIDDatabase().save({ agentId: req.targetAgentId, type: 'context', content: text, metadata: { capability: req.capability, fromAgentId: req.fromAgentId, kind: 'delegate-result' } });
|
|
3061
|
+
cid = rec?.id;
|
|
3062
|
+
}
|
|
3063
|
+
catch { /* 存不上就不给 CID */ }
|
|
3064
|
+
return { ok: true, summary: text.slice(0, 4000), resultCid: cid };
|
|
3065
|
+
}
|
|
3066
|
+
catch (e) {
|
|
3067
|
+
return { ok: false, summary: `delegate executor failed: ${String(e?.message || e).slice(0, 300)}`, error: 'executor-error' };
|
|
3068
|
+
}
|
|
3069
|
+
};
|
|
3070
|
+
let agentDelegateMounted = false;
|
|
3071
|
+
try {
|
|
3072
|
+
const delegateTransport = createIrohDelegateTransport({ verbose: true });
|
|
3073
|
+
// 注意: createAgentDelegateApp 内部声明的是绝对路径 (/api/agent/...),
|
|
3074
|
+
// 所以挂载时**不能**再带 '/api/agent' 前缀 (否则变成 /api/agent/api/agent/... 恒 404)
|
|
3075
|
+
app.use(createAgentDelegateApp(delegateTransport, { execute: delegateExecutor }));
|
|
3076
|
+
agentDelegateMounted = true;
|
|
3077
|
+
console.log('[agent-delegate] 已挂载到 /api/agent (启动即用: local-manifest / register / pick / delegate, 真执行器已注入)');
|
|
3078
|
+
}
|
|
3079
|
+
catch (e) {
|
|
3080
|
+
console.warn('[agent-delegate] 挂载失败 (非致命):', e?.message);
|
|
3081
|
+
}
|
|
3010
3082
|
// 2026-08-14: Agent Gateway — 网络加入 / 分享链接 / 成员 / 状态 (入口要小: 一条链接)
|
|
3011
3083
|
app.post('/api/gateway/join', async (req, res) => {
|
|
3012
3084
|
try {
|
|
@@ -3043,6 +3115,36 @@ ${goalDesc}
|
|
|
3043
3115
|
res.status(500).json({ error: e?.message });
|
|
3044
3116
|
}
|
|
3045
3117
|
});
|
|
3118
|
+
// 2026-09-15: 文档驱动「加入全球智能体网络」— 人类/手机只给一句 read <doc>, 这里做落地执行.
|
|
3119
|
+
// GET: 查入网态 (joined/url/did/networkLink); POST: 真执行 (可指定 url/name/capabilities/force).
|
|
3120
|
+
app.get('/api/gateway/join-global', async (_req, res) => {
|
|
3121
|
+
try {
|
|
3122
|
+
const { getGatewayJoinState, DEFAULT_GATEWAY_JOIN_DOC } = await import('../agents/gateway-join.js');
|
|
3123
|
+
const state = await getGatewayJoinState();
|
|
3124
|
+
res.json({ ok: true, joined: !!state, docUrl: DEFAULT_GATEWAY_JOIN_DOC, state });
|
|
3125
|
+
}
|
|
3126
|
+
catch (e) {
|
|
3127
|
+
res.status(500).json({ ok: false, error: e?.message });
|
|
3128
|
+
}
|
|
3129
|
+
});
|
|
3130
|
+
app.post('/api/gateway/join-global', async (req, res) => {
|
|
3131
|
+
try {
|
|
3132
|
+
const { joinGlobalGateway } = await import('../agents/gateway-join.js');
|
|
3133
|
+
const identity = await loadOrCreateUserIdentity();
|
|
3134
|
+
const caps = String(req.body?.capabilities || '').split(',').map((s) => s.trim()).filter(Boolean);
|
|
3135
|
+
const r = await joinGlobalGateway({
|
|
3136
|
+
url: String(req.body?.url || '').trim() || undefined,
|
|
3137
|
+
did: identity?.did || undefined,
|
|
3138
|
+
name: String(req.body?.name || '').trim() || identity?.name || undefined,
|
|
3139
|
+
capabilities: caps.length ? caps : undefined,
|
|
3140
|
+
force: req.body?.force === true,
|
|
3141
|
+
});
|
|
3142
|
+
res.status(r.ok ? 200 : 400).json(r);
|
|
3143
|
+
}
|
|
3144
|
+
catch (e) {
|
|
3145
|
+
res.status(500).json({ ok: false, error: e?.message });
|
|
3146
|
+
}
|
|
3147
|
+
});
|
|
3046
3148
|
app.get('/api/gateway/status', async (_req, res) => {
|
|
3047
3149
|
try {
|
|
3048
3150
|
const { gatewayStatus } = await import('../agents/agent-gateway.js');
|
|
@@ -6529,15 +6631,18 @@ ${goalDesc}
|
|
|
6529
6631
|
};
|
|
6530
6632
|
irohInitialized = true;
|
|
6531
6633
|
// 挂载 agent-delegate app (manifest 协议 + agent_delegate)
|
|
6532
|
-
//
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6634
|
+
// 2026-09-15: 已改为启动时提前挂载 (见 createWebServer 的 /api/agent 段), 这里不再重复挂.
|
|
6635
|
+
if (!agentDelegateMounted) {
|
|
6636
|
+
try {
|
|
6637
|
+
const delegateTransport = createIrohDelegateTransport({ verbose: true });
|
|
6638
|
+
const delegateApp = createAgentDelegateApp(delegateTransport, { execute: delegateExecutor });
|
|
6639
|
+
app.use(delegateApp);
|
|
6640
|
+
agentDelegateMounted = true;
|
|
6641
|
+
console.log('[iroh API] agent-delegate app 已挂载到 /api/agent (补挂, 真执行器已注入)');
|
|
6642
|
+
}
|
|
6643
|
+
catch (e) {
|
|
6644
|
+
console.error('[iroh API] 挂载 agent-delegate app 失败:', e);
|
|
6645
|
+
}
|
|
6541
6646
|
}
|
|
6542
6647
|
// 设置消息处理
|
|
6543
6648
|
irohTransport.onMessage('chat', (msg) => {
|
package/dist/web/sw.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
/* Bolloon 手机端 Service Worker — app-shell 缓存, 让 iPhone 可"添加到主屏幕"独立运行
|
|
2
|
-
|
|
1
|
+
/* Bolloon 手机端 Service Worker — app-shell 缓存, 让 iPhone 可"添加到主屏幕"独立运行
|
|
2
|
+
*
|
|
3
|
+
* 2026-09-14 修: 原来是 cache-first + 固定缓存名 (bolloon-mobile-v1) →
|
|
4
|
+
* 一旦装上, 之后每次升级 APK / 重新部署站点, WebView 里跑的仍是**旧的 mobile.js/mobile-core.js**,
|
|
5
|
+
* 表现为「改了 UI 手机上没变化」「升级后还是老界面」。
|
|
6
|
+
* 现在: 代码类资源 (html/js/css/json) 一律 **network-first** (拿不到网才回退缓存),
|
|
7
|
+
* 缓存名带版本号, activate 时清掉所有旧缓存; 图标等静态资源仍 cache-first。
|
|
8
|
+
*/
|
|
9
|
+
const CACHE = 'bolloon-mobile-v1.1';
|
|
3
10
|
const SHELL = [
|
|
4
11
|
'./mobile.html',
|
|
5
12
|
'./mobile.css',
|
|
@@ -25,6 +32,9 @@ self.addEventListener('activate', (e) => {
|
|
|
25
32
|
);
|
|
26
33
|
});
|
|
27
34
|
|
|
35
|
+
// 代码类资源: 必须联网拿最新的 (离线才回退缓存); 图标/manifest 之类可以 cache-first
|
|
36
|
+
const CODE_EXT = /\.(?:html|js|mjs|css|json|webmanifest)$/i;
|
|
37
|
+
|
|
28
38
|
self.addEventListener('fetch', (e) => {
|
|
29
39
|
const req = e.request;
|
|
30
40
|
if (req.method !== 'GET') return;
|
|
@@ -32,6 +42,20 @@ self.addEventListener('fetch', (e) => {
|
|
|
32
42
|
try { url = new URL(req.url); } catch { return; }
|
|
33
43
|
// 跨域 / API / 实时通道不缓存 (registry fetch、WebSocket 等)
|
|
34
44
|
if (url.origin !== location.origin || url.pathname.includes('/api/')) return;
|
|
45
|
+
|
|
46
|
+
if (CODE_EXT.test(url.pathname) || req.mode === 'navigate') {
|
|
47
|
+
e.respondWith(
|
|
48
|
+
fetch(req).then((res) => {
|
|
49
|
+
if (res && res.ok) {
|
|
50
|
+
const copy = res.clone();
|
|
51
|
+
caches.open(CACHE).then((c) => c.put(req, copy)).catch(() => {});
|
|
52
|
+
}
|
|
53
|
+
return res;
|
|
54
|
+
}).catch(() => caches.match(req).then((hit) => hit || caches.match('./mobile.html'))),
|
|
55
|
+
);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
35
59
|
e.respondWith(
|
|
36
60
|
caches.match(req).then((hit) => hit || fetch(req).then((res) => {
|
|
37
61
|
const copy = res.clone();
|