@bolloon/bolloon-agent 0.4.14 → 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.
- package/README.md +127 -127
- package/bin/bolloon-cli.cjs +183 -183
- package/bin/bolloon-daemon.sh +207 -0
- package/bin/bolloon.cjs +0 -0
- package/dist/agents/constraint-layer.js +19 -19
- package/dist/agents/judgment-protocol.js +14 -14
- package/dist/agents/pi-sdk-types.js +12 -12
- package/dist/agents/pi-sdk.js +101 -101
- package/dist/agents/skill-organizer.js +19 -19
- package/dist/agents/workflow-pivot-loop.js +2 -2
- package/dist/agents/x402/x402Pay.js +4 -0
- package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
- package/dist/bollharness-integration/context-router-judgment.js +4 -4
- package/dist/bollharness-integration/context-router.js +292 -292
- package/dist/bollharness-integration/gate-state-machine.js +13 -13
- package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
- package/dist/bollharness-integration/skill-adapter.js +21 -21
- package/dist/bootstrap/chat-archiver.js +14 -14
- package/dist/bootstrap/context-os.js +24 -24
- package/dist/bootstrap/memory-compressor.js +13 -13
- package/dist/cli-entry.js +36 -36
- package/dist/constraint-runtime/reference_data/archive_surface_snapshot.json +63 -0
- package/dist/constraint-runtime/reference_data/commands_snapshot.json +1037 -0
- package/dist/constraint-runtime/reference_data/subsystems/assistant.json +8 -0
- package/dist/constraint-runtime/reference_data/subsystems/bootstrap.json +8 -0
- package/dist/constraint-runtime/reference_data/subsystems/bridge.json +32 -0
- package/dist/constraint-runtime/reference_data/subsystems/buddy.json +13 -0
- package/dist/constraint-runtime/reference_data/subsystems/cli.json +26 -0
- package/dist/constraint-runtime/reference_data/subsystems/components.json +32 -0
- package/dist/constraint-runtime/reference_data/subsystems/constants.json +28 -0
- package/dist/constraint-runtime/reference_data/subsystems/coordinator.json +8 -0
- package/dist/constraint-runtime/reference_data/subsystems/entrypoints.json +15 -0
- package/dist/constraint-runtime/reference_data/subsystems/hooks.json +32 -0
- package/dist/constraint-runtime/reference_data/subsystems/keybindings.json +21 -0
- package/dist/constraint-runtime/reference_data/subsystems/memdir.json +15 -0
- package/dist/constraint-runtime/reference_data/subsystems/migrations.json +18 -0
- package/dist/constraint-runtime/reference_data/subsystems/moreright.json +8 -0
- package/dist/constraint-runtime/reference_data/subsystems/native_ts.json +11 -0
- package/dist/constraint-runtime/reference_data/subsystems/outputStyles.json +8 -0
- package/dist/constraint-runtime/reference_data/subsystems/plugins.json +9 -0
- package/dist/constraint-runtime/reference_data/subsystems/remote.json +11 -0
- package/dist/constraint-runtime/reference_data/subsystems/schemas.json +8 -0
- package/dist/constraint-runtime/reference_data/subsystems/screens.json +10 -0
- package/dist/constraint-runtime/reference_data/subsystems/server.json +10 -0
- package/dist/constraint-runtime/reference_data/subsystems/services.json +32 -0
- package/dist/constraint-runtime/reference_data/subsystems/skills.json +27 -0
- package/dist/constraint-runtime/reference_data/subsystems/state.json +13 -0
- package/dist/constraint-runtime/reference_data/subsystems/types.json +18 -0
- package/dist/constraint-runtime/reference_data/subsystems/upstreamproxy.json +9 -0
- package/dist/constraint-runtime/reference_data/subsystems/utils.json +32 -0
- package/dist/constraint-runtime/reference_data/subsystems/vim.json +12 -0
- package/dist/constraint-runtime/reference_data/subsystems/voice.json +8 -0
- package/dist/constraint-runtime/reference_data/tools_snapshot.json +922 -0
- package/dist/context-compaction/auto-compact.js +7 -7
- package/dist/electron/config.js.map +1 -0
- package/dist/electron/dialogs.js.map +1 -0
- package/dist/electron/first-run.js +54 -54
- package/dist/electron/first-run.js.map +1 -0
- package/dist/electron/ipc.js.map +1 -0
- package/dist/electron/logger.js.map +1 -0
- package/dist/electron/main.js.map +1 -0
- package/dist/electron/menu.js.map +1 -0
- package/dist/electron/paths.js.map +1 -0
- package/dist/electron/server.js.map +1 -0
- package/dist/electron/tray.js.map +1 -0
- package/dist/electron/window.js.map +1 -0
- package/dist/electron-build/electron/first-run.js +54 -54
- package/dist/electron-preload.js.map +1 -1
- package/dist/electron.js.map +1 -1
- package/dist/index.js +112 -112
- package/dist/llm/llm-judgment-client.js +102 -102
- package/dist/llm/pi-ai.js +48 -48
- package/dist/llm/system-prompt/layers/channel/human-async.md +41 -41
- package/dist/llm/system-prompt/layers/channel/local.md +14 -14
- package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
- package/dist/llm/system-prompt/layers/channel/p2p-peer-sync.md +51 -51
- package/dist/llm/system-prompt/layers/channel/p2p-proactive.md +43 -43
- package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
- package/dist/llm/system-prompt/layers/channel/session-handoff.md +61 -61
- package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
- package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
- package/dist/llm/system-prompt/layers/core/external-engagement.md +73 -73
- package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
- package/dist/llm/system-prompt/layers/core/identity.md +48 -48
- package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
- package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
- package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
- package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
- package/dist/llm/system-prompt/layers/core/tone.md +31 -31
- package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
- package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
- package/dist/llm/system-prompt/layers/role/architect.md +20 -20
- package/dist/llm/system-prompt/layers/role/expert.md +19 -19
- package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
- package/dist/llm/system-prompt/layers/role/security.md +15 -15
- package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
- package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
- package/dist/llm/system-prompt/layers/tool/goal_handoff.md +77 -77
- package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
- package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
- package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
- package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
- package/dist/llm/system-prompt/layers/tool/p2p_request.md +61 -61
- package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
- package/dist/llm/tool-manifest/ask_user_input.js +1 -1
- package/dist/llm/tool-manifest/bash.js +3 -3
- package/dist/llm/tool-manifest/create_file.js +4 -4
- package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
- package/dist/llm/tool-manifest/image_search.js +2 -2
- package/dist/llm/tool-manifest/index.js +59 -0
- package/dist/llm/tool-manifest/mcp.js +2 -2
- package/dist/llm/tool-manifest/message_compose.js +3 -3
- package/dist/llm/tool-manifest/places.js +2 -2
- package/dist/llm/tool-manifest/present_files.js +1 -1
- package/dist/llm/tool-manifest/recipe.js +2 -2
- package/dist/llm/tool-manifest/str_replace.js +5 -5
- package/dist/llm/tool-manifest/view.js +3 -3
- package/dist/llm/tool-manifest/weather.js +4 -4
- package/dist/llm/tool-manifest/web.js +4 -4
- package/dist/network/p2p.js +78 -4
- package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
- package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
- package/dist/pi-ecosystem-judgment/distillation.js +14 -14
- package/dist/pi-ecosystem-judgment/index.js +1 -1
- package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
- package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
- package/dist/security/context-router-tool.js +15 -15
- package/dist/utils/auto-update.js.map +1 -0
- package/dist/web/a2ui-client.js +1594 -223
- package/dist/web/api-config.html +779 -779
- package/dist/web/client-hearth.js +10 -10
- package/dist/web/client.js.map +7 -0
- package/dist/web/components/wallet-viem.mjs +118 -118
- package/dist/web/index.html +502 -502
- package/dist/web/manifest.json +20 -20
- package/dist/web/mobile-agent.js +397 -0
- package/dist/web/mobile-core.js +86235 -0
- package/dist/web/mobile-data.js +346 -0
- package/dist/web/mobile-http-api.js +71 -0
- package/dist/web/mobile-p2p.js +250 -0
- package/dist/web/mobile-payments.js +80 -0
- package/dist/web/mobile-wallet.js +226 -0
- package/dist/web/mobile.css +483 -6
- package/dist/web/mobile.html +99 -50
- package/dist/web/mobile.js +1040 -187
- package/dist/web/server.js +13 -13
- package/dist/web/style.css +4946 -4946
- package/package.json +201 -198
- package/scripts/build-cli.js +215 -215
- package/scripts/build-web.ts +162 -149
- package/scripts/postinstall.js +152 -152
- package/bin/bolloon.js +0 -157
- package/dist/agents/python-exec.js +0 -115
- package/dist/pi-ecosystem-colony/index.js +0 -365
- package/dist/social/ant-colony/AdaptiveHeartbeat.js +0 -101
- package/dist/social/ant-colony/PheromoneEngine.js +0 -227
- package/dist/social/ant-colony/index.js +0 -6
- package/dist/social/ant-colony/types.js +0 -24
- package/dist/storage/trajectory.js +0 -101
- package/dist/test/ai-judgment-test.js +0 -80
- package/dist/test/bollharness-integration.test.js +0 -318
- package/dist/test/channel-agent-multi-dialogue.js +0 -205
- package/dist/test/channel-heartbeat-agent-test.js +0 -201
- package/dist/test/constraint-layer.test.js +0 -164
- package/dist/test/diap-identity-test.js +0 -172
- package/dist/test/diap-quick-test.js +0 -62
- package/dist/test/global-shared-context.test.js +0 -315
- package/dist/test/harness-judgment-injection.test.js +0 -246
- package/dist/test/harness-workflow-integrator-test.js +0 -228
- package/dist/test/human-value-store.test.js +0 -243
- package/dist/test/hybrid-integration-test.js +0 -118
- package/dist/test/hybrid-messenger-verify.js +0 -55
- package/dist/test/iroh-bistream-debug.js +0 -38
- package/dist/test/iroh-communication.test.js +0 -66
- package/dist/test/iroh-debug-test.js +0 -57
- package/dist/test/iroh-diap-test.js +0 -71
- package/dist/test/iroh-direct-connect.js +0 -55
- package/dist/test/iroh-e2e-fixed.js +0 -89
- package/dist/test/iroh-e2e-same-process.js +0 -63
- package/dist/test/iroh-e2e.js +0 -66
- package/dist/test/iroh-final-e2e.js +0 -72
- package/dist/test/iroh-relay-test.js +0 -37
- package/dist/test/iroh-simple-test.js +0 -41
- package/dist/test/iroh-transport-verify.js +0 -54
- package/dist/test/iroh-transport.test.js +0 -37
- package/dist/test/iroh-two-nodes.js +0 -70
- package/dist/test/iroh-verify.js +0 -44
- package/dist/test/judgment-decision.test.js +0 -219
- package/dist/test/llm-judgment-integration.test.js +0 -220
- package/dist/test/p2p-agent-complex-dialogue.js +0 -385
- package/dist/test/p2p-agent-dialogue.js +0 -341
- package/dist/test/p2p-agent-full-bidirectional.js +0 -510
- package/dist/test/p2p-agent-harness-flow.js +0 -437
- package/dist/test/p2p-agent-harness-single.js +0 -143
- package/dist/test/p2p-ai-dialogue-test.js +0 -318
- package/dist/test/p2p-cid-connect-test.js +0 -195
- package/dist/test/p2p-connect-receiver.js +0 -69
- package/dist/test/p2p-doc-transfer.js +0 -110
- package/dist/test/p2p-identity-page-test.js +0 -77
- package/dist/test/p2p-iroh-test.js +0 -171
- package/dist/test/p2p-minimal-test.js +0 -241
- package/dist/test/p2p-node-1.js +0 -148
- package/dist/test/p2p-node-2.js +0 -148
- package/dist/test/p2p-server.js +0 -281
- package/dist/test/p2p-two-nodes-test.js +0 -438
- package/dist/test/pi-sdk.test.js +0 -44
- package/dist/test/set-persona.js +0 -40
- package/dist/test/simple.test.js +0 -9
- package/dist/test/storage-integration.test.js +0 -150
- package/dist/test/subagent-manager.test.js +0 -276
- package/dist/test/test-gate-flow.test.js +0 -81
- package/dist/test/workflow-engine.test.js +0 -87
- package/dist/test/workflow-pivot-loop.test.js +0 -246
package/dist/web/manifest.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "Bolloon Agent",
|
|
3
|
-
"short_name": "Bolloon",
|
|
4
|
-
"description": "AI Agent with Claude API integration",
|
|
5
|
-
"start_url": "/",
|
|
6
|
-
"display": "standalone",
|
|
7
|
-
"background_color": "#1a1a2e",
|
|
8
|
-
"theme_color": "#1a1a2e",
|
|
9
|
-
"icons": [
|
|
10
|
-
{
|
|
11
|
-
"src": "/icons/favicon-192x192.png",
|
|
12
|
-
"sizes": "192x192",
|
|
13
|
-
"type": "image/png"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"src": "/icons/favicon-512x512.png",
|
|
17
|
-
"sizes": "512x512",
|
|
18
|
-
"type": "image/png"
|
|
19
|
-
}
|
|
20
|
-
]
|
|
1
|
+
{
|
|
2
|
+
"name": "Bolloon Agent",
|
|
3
|
+
"short_name": "Bolloon",
|
|
4
|
+
"description": "AI Agent with Claude API integration",
|
|
5
|
+
"start_url": "/",
|
|
6
|
+
"display": "standalone",
|
|
7
|
+
"background_color": "#1a1a2e",
|
|
8
|
+
"theme_color": "#1a1a2e",
|
|
9
|
+
"icons": [
|
|
10
|
+
{
|
|
11
|
+
"src": "/icons/favicon-192x192.png",
|
|
12
|
+
"sizes": "192x192",
|
|
13
|
+
"type": "image/png"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"src": "/icons/favicon-512x512.png",
|
|
17
|
+
"sizes": "512x512",
|
|
18
|
+
"type": "image/png"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
21
|
}
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mobile-agent.ts — 手机端 Agent 功能层 (2026-08-15)
|
|
3
|
+
*
|
|
4
|
+
* 独立子系统 #2: 手机是一个"独立 agent 节点", 与数据同步无关.
|
|
5
|
+
* - 自有身份: DID (WebCrypto 生成, 持久化 IndexedDB)
|
|
6
|
+
* - 自有执行: Kotlin AgentRuntime (Capacitor RokidBridge.runAgent), 离线可用内置规则
|
|
7
|
+
* - 协议 (复用桌面 agent.chat.* 语义):
|
|
8
|
+
* agent.chat.send : 主动调用远端 agent (A 节点对 channelId 跑 LLM → 回 agent.chat.reply)
|
|
9
|
+
* agent.chat.reply: 收到远端 agent 的执行结果
|
|
10
|
+
* agent.info : 请求/响应 对端 DID 与能力
|
|
11
|
+
* - 本层只负责"agent 智能", 不碰存储; session 落库由 mobile-core 协调 data 层做.
|
|
12
|
+
*/
|
|
13
|
+
// ============ 身份 (WebCrypto) ============
|
|
14
|
+
const IDENTITY_DB = 'bolloon-mobile';
|
|
15
|
+
let _identity = null;
|
|
16
|
+
async function generateDID() {
|
|
17
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
18
|
+
const digest = await crypto.subtle.digest('SHA-256', bytes);
|
|
19
|
+
return 'did:blln:' + Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, '0')).join('').slice(0, 32);
|
|
20
|
+
}
|
|
21
|
+
function openIdentityDb() {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const req = indexedDB.open(IDENTITY_DB, 1);
|
|
24
|
+
req.onupgradeneeded = () => {
|
|
25
|
+
const db = req.result;
|
|
26
|
+
if (!db.objectStoreNames.contains('kv'))
|
|
27
|
+
db.createObjectStore('kv');
|
|
28
|
+
};
|
|
29
|
+
req.onsuccess = () => resolve(req.result);
|
|
30
|
+
req.onerror = () => reject(req.error);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
let _identityDb = null;
|
|
34
|
+
/** 测试用: 关闭并清空身份库 */
|
|
35
|
+
export async function resetAgentDb() {
|
|
36
|
+
_identity = null;
|
|
37
|
+
if (_identityDb) {
|
|
38
|
+
_identityDb.close();
|
|
39
|
+
_identityDb = null;
|
|
40
|
+
}
|
|
41
|
+
await new Promise((resolve) => {
|
|
42
|
+
try {
|
|
43
|
+
const req = indexedDB.deleteDatabase(IDENTITY_DB);
|
|
44
|
+
req.onsuccess = () => resolve();
|
|
45
|
+
req.onerror = () => resolve();
|
|
46
|
+
req.onblocked = () => resolve();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
resolve();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** 获取本机 DID (首次生成并持久化) */
|
|
54
|
+
export async function ensureIdentity() {
|
|
55
|
+
if (_identity)
|
|
56
|
+
return _identity;
|
|
57
|
+
try {
|
|
58
|
+
const db = _identityDb || (await openIdentityDb());
|
|
59
|
+
_identityDb = db;
|
|
60
|
+
const id = await new Promise((resolve) => {
|
|
61
|
+
const tx = db.transaction('kv', 'readonly');
|
|
62
|
+
const r = tx.objectStore('kv').get('identity');
|
|
63
|
+
r.onsuccess = () => resolve(r.result ?? null);
|
|
64
|
+
r.onerror = () => resolve(null);
|
|
65
|
+
});
|
|
66
|
+
if (id && id.did) {
|
|
67
|
+
_identity = id;
|
|
68
|
+
return id;
|
|
69
|
+
}
|
|
70
|
+
const fresh = { did: await generateDID(), name: 'blln-mobile', createdAt: Date.now() };
|
|
71
|
+
await new Promise((resolve, reject) => {
|
|
72
|
+
const tx = db.transaction('kv', 'readwrite');
|
|
73
|
+
tx.objectStore('kv').put(fresh, 'identity');
|
|
74
|
+
tx.oncomplete = () => resolve();
|
|
75
|
+
tx.onerror = () => reject(tx.error);
|
|
76
|
+
});
|
|
77
|
+
_identity = fresh;
|
|
78
|
+
return fresh;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
const fallback = { did: await generateDID(), name: 'blln-mobile', createdAt: Date.now() };
|
|
82
|
+
_identity = fallback;
|
|
83
|
+
return fallback;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ============ LLM 配置 (桌面同步注入 / 手机默认) ============
|
|
87
|
+
let _llmConfig = null;
|
|
88
|
+
/** 最近一次 runLocalAgent 的执行过程摘要 (每步 onStep 文本), 由 message.send 广播给工作记录 UI */
|
|
89
|
+
let _lastWorklog = [];
|
|
90
|
+
export function getLastWorklog() { return _lastWorklog; }
|
|
91
|
+
/** 注入 LLM 配置 (由 mobile-core 在 data.llm-config.reply 同步后调用) */
|
|
92
|
+
export function setLlmConfig(cfg) {
|
|
93
|
+
_llmConfig = cfg;
|
|
94
|
+
// 立即注入 native bridge (agentConfigure), 让 AgentRuntime 马上可用, 不必等下次 runLocalAgent
|
|
95
|
+
applyLlmConfigToBridge().catch(() => { });
|
|
96
|
+
}
|
|
97
|
+
/** 当前 LLM 配置 (未同步则为 null → 手机默认) */
|
|
98
|
+
export function getLlmConfig() {
|
|
99
|
+
return _llmConfig;
|
|
100
|
+
}
|
|
101
|
+
/** 把配置注入 Capacitor RokidBridge (agentConfigure), 让 Kotlin AgentRuntime 用同步来的 LLM */
|
|
102
|
+
async function applyLlmConfigToBridge() {
|
|
103
|
+
if (!_llmConfig)
|
|
104
|
+
return;
|
|
105
|
+
const win = typeof window !== 'undefined' ? window : null;
|
|
106
|
+
const cap = win?.Capacitor;
|
|
107
|
+
const bridge = cap && cap.Plugins && cap.Plugins.RokidBridge;
|
|
108
|
+
if (!bridge || !cap.isNativePlatform?.())
|
|
109
|
+
return;
|
|
110
|
+
const payload = {};
|
|
111
|
+
if (_llmConfig.baseUrl)
|
|
112
|
+
payload.baseUrl = _llmConfig.baseUrl;
|
|
113
|
+
if (_llmConfig.apiKey)
|
|
114
|
+
payload.apiKey = _llmConfig.apiKey;
|
|
115
|
+
if (_llmConfig.model)
|
|
116
|
+
payload.model = _llmConfig.model;
|
|
117
|
+
try {
|
|
118
|
+
await bridge.agentConfigure?.(payload);
|
|
119
|
+
}
|
|
120
|
+
catch { /* 注入失败不阻塞本地执行 */ }
|
|
121
|
+
}
|
|
122
|
+
// ============ 本地执行 (Kotlin AgentRuntime / 内置规则) ============
|
|
123
|
+
/** 手机端本地 agent 执行 (优先 Kotlin, 离线内置规则) */
|
|
124
|
+
export async function runLocalAgent(goal) {
|
|
125
|
+
const win = typeof window !== 'undefined' ? window : null;
|
|
126
|
+
const cap = win?.Capacitor;
|
|
127
|
+
const bridge = cap && cap.Plugins && cap.Plugins.RokidBridge;
|
|
128
|
+
if (bridge && cap.isNativePlatform?.()) {
|
|
129
|
+
try {
|
|
130
|
+
await applyLlmConfigToBridge();
|
|
131
|
+
const r = await bridge.runAgent({ goal });
|
|
132
|
+
_lastWorklog = (r && Array.isArray(r.worklog)) ? r.worklog.map((x) => String(x)) : [];
|
|
133
|
+
return r?.result || '(无返回)';
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
throw new Error('AgentRuntime: ' + String(e?.message || e).slice(0, 60));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// 内置极简回复 (纯离线可用)
|
|
140
|
+
const t = (goal || '').trim();
|
|
141
|
+
if (t.includes('你好') || t === 'hi' || t === 'hello')
|
|
142
|
+
return '你好! 我是炁球 (Bolloon), 已在手机本地独立运行 (Agent 功能层 + 数据同步层分离)。';
|
|
143
|
+
if (t.includes('身份') || t.includes('did')) {
|
|
144
|
+
const id = await ensureIdentity();
|
|
145
|
+
return `我的本地 DID: ${id.did.slice(0, 12)}... (手机端独立生成)`;
|
|
146
|
+
}
|
|
147
|
+
if (t.includes('余额') || t.includes('钱包') || /balance/i.test(t)) {
|
|
148
|
+
try {
|
|
149
|
+
const id = await ensureIdentity();
|
|
150
|
+
const w = await import('./mobile-wallet.js');
|
|
151
|
+
const info = await w.walletForAgent(id.did);
|
|
152
|
+
if (!info.exists)
|
|
153
|
+
return '本机没有授权给当前智能体的钱包 (我 → 设置 → 钱包 可创建/授权)。';
|
|
154
|
+
const w0 = info.wallets[0];
|
|
155
|
+
let s = `钱包: ${w0.name || w0.id}`;
|
|
156
|
+
s += `\n地址: ${w0.address}${w0.unlocked ? ' (已解锁)' : ' (未解锁)'}`;
|
|
157
|
+
if (w0.unlocked) {
|
|
158
|
+
try {
|
|
159
|
+
s += `\n余额: ${await w.walletBalance(w0.id)}`;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
s += '\n余额: 查询失败';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else
|
|
166
|
+
s += '\n解锁后可见余额。';
|
|
167
|
+
return s;
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
return '钱包查询失败: ' + String(e?.message || e).slice(0, 80);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return `已收到: "${(goal || '').slice(0, 40)}"。这是手机端 Agent 功能层的本地执行 (数据同步与 agent 功能已分离)。`;
|
|
174
|
+
}
|
|
175
|
+
let _send = null;
|
|
176
|
+
let _ownDid = '';
|
|
177
|
+
const replyHandlers = new Set();
|
|
178
|
+
/** 注入传输函数 + 本机 DID (由 mobile-core 在 network.start 时调用) */
|
|
179
|
+
export function setAgentTransport(fn, did) {
|
|
180
|
+
_send = fn;
|
|
181
|
+
_ownDid = did;
|
|
182
|
+
}
|
|
183
|
+
/** 订阅对端 agent.chat.reply 回复 (mobile-core 收到 reply 时分发) */
|
|
184
|
+
export function onAgentReply(fn) {
|
|
185
|
+
replyHandlers.add(fn);
|
|
186
|
+
}
|
|
187
|
+
/** 收到对端 agent.chat.reply 时的内部通知 (mobile-core 调用) */
|
|
188
|
+
export function notifyAgentReply(replyPayload, fromPeer) {
|
|
189
|
+
for (const h of replyHandlers) {
|
|
190
|
+
try {
|
|
191
|
+
h(replyPayload, fromPeer);
|
|
192
|
+
}
|
|
193
|
+
catch { /* 忽略 */ }
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const inboundChatHandlers = new Set();
|
|
197
|
+
export function onInboundChat(fn) {
|
|
198
|
+
inboundChatHandlers.add(fn);
|
|
199
|
+
}
|
|
200
|
+
function notifyInboundChat(text, channelId, fromPeer) {
|
|
201
|
+
for (const h of inboundChatHandlers) {
|
|
202
|
+
try {
|
|
203
|
+
h(text, channelId, fromPeer);
|
|
204
|
+
}
|
|
205
|
+
catch { /* 忽略 */ }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/** 主动调用远端 agent: 发 agent.chat.send, 等待 agent.chat.reply */
|
|
209
|
+
export async function callRemoteAgent(peerId, text, channelId, timeoutMs = 30000) {
|
|
210
|
+
if (!_send)
|
|
211
|
+
return { ok: false, error: 'P2P 未就绪' };
|
|
212
|
+
const did = _ownDid || (await ensureIdentity()).did;
|
|
213
|
+
return new Promise((resolve) => {
|
|
214
|
+
let settled = false;
|
|
215
|
+
const timer = setTimeout(() => {
|
|
216
|
+
if (!settled) {
|
|
217
|
+
settled = true;
|
|
218
|
+
replyHandlers.delete(onReply);
|
|
219
|
+
resolve({ ok: false, error: 'timeout' });
|
|
220
|
+
}
|
|
221
|
+
}, timeoutMs);
|
|
222
|
+
const onReply = (payload, fromPeer) => {
|
|
223
|
+
if (settled)
|
|
224
|
+
return;
|
|
225
|
+
try {
|
|
226
|
+
const m = JSON.parse(payload);
|
|
227
|
+
if (m?.channelId === channelId || !m?.channelId) {
|
|
228
|
+
settled = true;
|
|
229
|
+
clearTimeout(timer);
|
|
230
|
+
replyHandlers.delete(onReply);
|
|
231
|
+
resolve({ ok: true, reply: m?.text || m?.content || payload });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// 非 JSON 回复也接受
|
|
236
|
+
if (!settled) {
|
|
237
|
+
settled = true;
|
|
238
|
+
clearTimeout(timer);
|
|
239
|
+
replyHandlers.delete(onReply);
|
|
240
|
+
resolve({ ok: true, reply: payload });
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
replyHandlers.add(onReply);
|
|
245
|
+
const s = _send;
|
|
246
|
+
if (!s) {
|
|
247
|
+
settled = true;
|
|
248
|
+
replyHandlers.delete(onReply);
|
|
249
|
+
return resolve({ ok: false, error: 'P2P 未就绪' });
|
|
250
|
+
}
|
|
251
|
+
s('agent.chat.send', JSON.stringify({ text, channelId, fromPublicKey: did }), peerId).then((ok) => {
|
|
252
|
+
if (!ok && !settled) {
|
|
253
|
+
settled = true;
|
|
254
|
+
clearTimeout(timer);
|
|
255
|
+
replyHandlers.delete(onReply);
|
|
256
|
+
resolve({ ok: false, error: 'send failed' });
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
/** 处理入站 agent.* 消息 (mobile-core 的 P2P 路由调用) */
|
|
262
|
+
export async function handleIncomingAgentMessage(type, payload, fromPeer) {
|
|
263
|
+
switch (type) {
|
|
264
|
+
case 'agent.chat.send': {
|
|
265
|
+
// 对端调用本机: 手机 on-device 本地执行 → 回 agent.chat.reply
|
|
266
|
+
// 并通知协调层把对端消息写入数据层 (同步会话)
|
|
267
|
+
if (!_send)
|
|
268
|
+
return;
|
|
269
|
+
try {
|
|
270
|
+
const { text, channelId } = JSON.parse(payload);
|
|
271
|
+
notifyInboundChat(text || '', channelId || '', fromPeer);
|
|
272
|
+
const reply = await runLocalAgent(text || '');
|
|
273
|
+
await _send('agent.chat.reply', JSON.stringify({ channelId, text: reply, fromPublicKey: _ownDid }), fromPeer);
|
|
274
|
+
}
|
|
275
|
+
catch { /* 解析/执行失败则不回 */ }
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
case 'agent.chat.reply':
|
|
279
|
+
notifyAgentReply(payload, fromPeer);
|
|
280
|
+
break;
|
|
281
|
+
case 'agent.info':
|
|
282
|
+
// 响应: 返回 DID + 能力
|
|
283
|
+
if (_send) {
|
|
284
|
+
const id = await ensureIdentity();
|
|
285
|
+
await _send('agent.info.reply', JSON.stringify({ did: id.did, name: id.name, capabilities: ['chat', 'local-agent'] }), fromPeer);
|
|
286
|
+
}
|
|
287
|
+
break;
|
|
288
|
+
default:
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/** 手机端执行控制指令 (phone.agent.run) — 手机自治执行, 不经电脑 */
|
|
293
|
+
export async function runPhoneAgent(goal) {
|
|
294
|
+
const win = typeof window !== 'undefined' ? window : null;
|
|
295
|
+
const cap = win?.Capacitor;
|
|
296
|
+
const bridge = cap && cap.Plugins && cap.Plugins.RokidBridge;
|
|
297
|
+
const native = !!(bridge && cap.isNativePlatform?.());
|
|
298
|
+
const id = await ensureIdentity();
|
|
299
|
+
try {
|
|
300
|
+
if (native) {
|
|
301
|
+
await applyLlmConfigToBridge();
|
|
302
|
+
const r = await bridge.runAgent({ goal });
|
|
303
|
+
const result = r?.result || '(无返回)';
|
|
304
|
+
const isDone = /^DONE:/.test(result) || /^CANCELLED/.test(result) || !/^(MAX_STEPS|STOPPED|\[Agent 异常)/.test(result);
|
|
305
|
+
return {
|
|
306
|
+
ok: !/^\[Agent 异常|^STOPPED|^MAX_STEPS/.test(result),
|
|
307
|
+
goal,
|
|
308
|
+
result,
|
|
309
|
+
did: id.did,
|
|
310
|
+
mode: 'native',
|
|
311
|
+
agentId: r?.agentId,
|
|
312
|
+
stepCount: r?.stepCount,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
// 离线 fallback: 内置规则 (不依赖 LLM/无障碍, 手机仍自治可用)
|
|
316
|
+
const reply = await runLocalAgent(goal);
|
|
317
|
+
return { ok: true, goal, result: reply, did: id.did, mode: 'fallback' };
|
|
318
|
+
}
|
|
319
|
+
catch (e) {
|
|
320
|
+
return { ok: false, goal, error: String(e?.message || e).slice(0, 100), did: id.did, mode: native ? 'native' : 'fallback' };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/** 手机端 Agent 状态 (phone.agent.status) */
|
|
324
|
+
export async function phoneStatus() {
|
|
325
|
+
const win = typeof window !== 'undefined' ? window : null;
|
|
326
|
+
const cap = win?.Capacitor;
|
|
327
|
+
const bridge = cap && cap.Plugins && cap.Plugins.RokidBridge;
|
|
328
|
+
const native = !!(bridge && cap.isNativePlatform?.());
|
|
329
|
+
const id = await ensureIdentity();
|
|
330
|
+
let accReady = false;
|
|
331
|
+
let llm;
|
|
332
|
+
if (native && bridge) {
|
|
333
|
+
try {
|
|
334
|
+
const st = await bridge.agentStatus?.();
|
|
335
|
+
accReady = !!st?.accessibilityReady;
|
|
336
|
+
if (st?.baseUrl || st?.model)
|
|
337
|
+
llm = { baseUrl: st.baseUrl, model: st.model };
|
|
338
|
+
}
|
|
339
|
+
catch { /* 忽略 */ }
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
ok: true,
|
|
343
|
+
did: id.did,
|
|
344
|
+
mode: native ? 'native' : 'fallback',
|
|
345
|
+
llm,
|
|
346
|
+
capabilities: ['chat', 'local-agent', 'phone-control'],
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
/** 取消当前手机 Agent 任务 (phone.agent.cancel) */
|
|
350
|
+
export async function cancelPhoneAgent(reason = '远端取消') {
|
|
351
|
+
const win = typeof window !== 'undefined' ? window : null;
|
|
352
|
+
const cap = win?.Capacitor;
|
|
353
|
+
const bridge = cap && cap.Plugins && cap.Plugins.RokidBridge;
|
|
354
|
+
if (bridge && cap.isNativePlatform?.()) {
|
|
355
|
+
try {
|
|
356
|
+
const r = await bridge.cancelAgent?.({ reason });
|
|
357
|
+
return { ok: true, cancelRequested: !!r?.cancelRequested };
|
|
358
|
+
}
|
|
359
|
+
catch (e) {
|
|
360
|
+
return { ok: false };
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return { ok: false };
|
|
364
|
+
}
|
|
365
|
+
/** 处理入站 phone.* 控制消息 (mobile-core 的 P2P 路由调用) */
|
|
366
|
+
export async function handleIncomingPhoneMessage(type, payload, fromPeer) {
|
|
367
|
+
if (!_send)
|
|
368
|
+
return;
|
|
369
|
+
try {
|
|
370
|
+
switch (type) {
|
|
371
|
+
case 'phone.agent.run': {
|
|
372
|
+
// 桌面/其他节点指令 → 手机自治执行 → 回 phone.agent.result
|
|
373
|
+
const req = JSON.parse(payload);
|
|
374
|
+
const goal = (req.goal || '').toString();
|
|
375
|
+
const reqId = req.requestId || '';
|
|
376
|
+
const result = await runPhoneAgent(goal);
|
|
377
|
+
await _send('phone.agent.result', JSON.stringify({ ...result, requestId: reqId, fromPublicKey: _ownDid }), fromPeer);
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
case 'phone.agent.status': {
|
|
381
|
+
const st = await phoneStatus();
|
|
382
|
+
await _send('phone.agent.status.reply', JSON.stringify({ ...st, fromPublicKey: _ownDid }), fromPeer);
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
case 'phone.agent.cancel': {
|
|
386
|
+
const req = JSON.parse(payload);
|
|
387
|
+
const r = await cancelPhoneAgent(req.reason || '远端取消');
|
|
388
|
+
await _send('phone.agent.cancel.reply', JSON.stringify({ ...r, fromPublicKey: _ownDid }), fromPeer);
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
default:
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
catch { /* 控制消息处理失败静默 */ }
|
|
396
|
+
}
|
|
397
|
+
export default { ensureIdentity, runLocalAgent, setAgentTransport, onAgentReply, callRemoteAgent, handleIncomingAgentMessage, notifyAgentReply, onInboundChat, setLlmConfig, getLlmConfig, runPhoneAgent, phoneStatus, cancelPhoneAgent, handleIncomingPhoneMessage };
|