@bolloon/bolloon-agent 0.5.2 → 0.5.4

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.
Files changed (80) hide show
  1. package/README.md +4 -4
  2. package/dist/agents/chain/transfer-classify.js +99 -0
  3. package/dist/agents/chain/transfer-index.js +354 -0
  4. package/dist/agents/identity/address-binding.js +613 -0
  5. package/dist/agents/network-pulse.js +706 -27
  6. package/dist/agents/pi-sdk-tools.js +67 -15
  7. package/dist/agents/pi-sdk.js +7 -1
  8. package/dist/agents/session-store.js +144 -3
  9. package/dist/agents/wallet-tools.js +63 -0
  10. package/dist/agents/x402/direct-payment.js +689 -0
  11. package/dist/agents/x402/order-identity.js +408 -0
  12. package/dist/agents/x402/paid-info-store.js +17 -0
  13. package/dist/agents/x402/seller-signing.js +614 -0
  14. package/dist/agents/x402/seller-summary.js +398 -0
  15. package/dist/cli/identity-command.js +327 -2
  16. package/dist/cli/ink-app.js +79 -27
  17. package/dist/cli/input-history.js +119 -0
  18. package/dist/cli/loading-tui.js +66 -6
  19. package/dist/cli/log-gate.js +39 -1
  20. package/dist/cli/protocol-envelope.js +4 -0
  21. package/dist/cli/session-summary.js +129 -0
  22. package/dist/cli/session-tree.js +141 -0
  23. package/dist/cli/status-segments.js +70 -0
  24. package/dist/cli/stores.js +16 -0
  25. package/dist/cli/update-commands.js +41 -25
  26. package/dist/cli/wallet-store.js +159 -0
  27. package/dist/cli/wallet-table.js +46 -0
  28. package/dist/cli/x402-buyer-command.js +463 -0
  29. package/dist/cli/x402-seller-command.js +289 -0
  30. package/dist/cli-entry.js +43 -5
  31. package/dist/electron-build/agents/chain/transfer-classify.js +106 -0
  32. package/dist/electron-build/agents/chain/transfer-classify.js.map +1 -0
  33. package/dist/electron-build/agents/chain/transfer-index.js +400 -0
  34. package/dist/electron-build/agents/chain/transfer-index.js.map +1 -0
  35. package/dist/electron-build/agents/identity/address-binding.js +672 -0
  36. package/dist/electron-build/agents/identity/address-binding.js.map +1 -0
  37. package/dist/electron-build/agents/network-pulse.js +714 -28
  38. package/dist/electron-build/agents/network-pulse.js.map +1 -1
  39. package/dist/electron-build/agents/pi-sdk-tools.js +68 -15
  40. package/dist/electron-build/agents/pi-sdk-tools.js.map +1 -1
  41. package/dist/electron-build/agents/pi-sdk.js +7 -1
  42. package/dist/electron-build/agents/pi-sdk.js.map +1 -1
  43. package/dist/electron-build/agents/session-store.js +144 -3
  44. package/dist/electron-build/agents/session-store.js.map +1 -1
  45. package/dist/electron-build/agents/wallet-tools.js +102 -0
  46. package/dist/electron-build/agents/wallet-tools.js.map +1 -0
  47. package/dist/electron-build/agents/x402/direct-payment.js +744 -0
  48. package/dist/electron-build/agents/x402/direct-payment.js.map +1 -0
  49. package/dist/electron-build/agents/x402/order-identity.js +458 -0
  50. package/dist/electron-build/agents/x402/order-identity.js.map +1 -0
  51. package/dist/electron-build/agents/x402/paid-info-protocol.js.map +1 -1
  52. package/dist/electron-build/agents/x402/paid-info-store.js +18 -0
  53. package/dist/electron-build/agents/x402/paid-info-store.js.map +1 -1
  54. package/dist/electron-build/agents/x402/seller-signing.js +682 -0
  55. package/dist/electron-build/agents/x402/seller-signing.js.map +1 -0
  56. package/dist/electron-build/cli/wallet-store.js +200 -0
  57. package/dist/electron-build/cli/wallet-store.js.map +1 -0
  58. package/dist/electron-build/llm/pi-ai.js +25 -0
  59. package/dist/electron-build/llm/pi-ai.js.map +1 -1
  60. package/dist/electron-build/utils/auto-update.js +2 -2
  61. package/dist/electron-build/utils/auto-update.js.map +1 -1
  62. package/dist/electron-build/utils/runtime-bootstrap.js +1 -1
  63. package/dist/electron-build/utils/runtime-bootstrap.js.map +1 -1
  64. package/dist/electron-build/utils/update-manager.js +3 -3
  65. package/dist/electron-build/utils/update-manager.js.map +1 -1
  66. package/dist/electron-build/utils/version-identity.js +1 -1
  67. package/dist/electron-build/utils/version-identity.js.map +1 -1
  68. package/dist/electron-build/web/routes-x402-info.js +28 -1
  69. package/dist/electron-build/web/routes-x402-info.js.map +1 -1
  70. package/dist/index.js +829 -104
  71. package/dist/llm/pi-ai.js +23 -0
  72. package/dist/utils/auto-update.js +2 -2
  73. package/dist/utils/runtime-bootstrap.js +1 -1
  74. package/dist/utils/update-health.js +2 -2
  75. package/dist/utils/update-manager.js +3 -3
  76. package/dist/utils/version-identity.js +1 -1
  77. package/dist/web/bolloon-web.json +3 -3
  78. package/dist/web/routes-x402-info.js +28 -1
  79. package/dist/web/sw.js +1 -1
  80. package/package.json +2 -1
package/dist/llm/pi-ai.js CHANGED
@@ -920,6 +920,8 @@ export class PiAIModel {
920
920
  const _tAfter = Date.now();
921
921
  const promptBytes = JSON.stringify(messages).length;
922
922
  console.log(`[pi-ai timing] total=${_tAfter - _t0}ms attempt=${attempt + 1} fetch=${_tResp - _tFetch}ms parse=${_tParse - _tResp}ms reply=${content.length}B toolCalls=${toolCalls?.length ?? 0} model=${this.mapModel()} prompt=${promptBytes}B`);
923
+ lastAiTiming = { bytes: content.length, ms: Math.max(1, _tAfter - _t0), at: _tAfter }; // 状态栏 ↑ t/s 的真数
924
+ lastAiUsage = { cached: usage?.cachedTokens || 0, prompt: usage?.promptTokens || 0, at: _tAfter }; // 状态栏 ◎ 缓存命中率
923
925
  retryAgent?.destroy().catch(() => { });
924
926
  return { reply: content, toolCalls: toolCalls && toolCalls.length > 0 ? toolCalls : undefined, reasoningContent, usage };
925
927
  }
@@ -994,6 +996,8 @@ export class PiAIModel {
994
996
  console.log(formatKvServerLine(purpose, usage, { stream: true }));
995
997
  const toolCalls = acc.filter(Boolean);
996
998
  console.log(`[pi-ai timing] total=${Date.now() - t0}ms stream reply=${reply.length}B toolCalls=${toolCalls.length}`);
999
+ lastAiTiming = { bytes: reply.length, ms: Math.max(1, Date.now() - t0), at: Date.now() }; // 状态栏 ↑ t/s 的真数
1000
+ lastAiUsage = { cached: usage?.cachedTokens || 0, prompt: usage?.promptTokens || 0, at: Date.now() }; // 状态栏 ◎ 缓存命中率
997
1001
  return {
998
1002
  reply,
999
1003
  reasoningContent: reasoning || undefined,
@@ -1448,6 +1452,25 @@ export function getModel() {
1448
1452
  export function isModelAvailable() {
1449
1453
  return modelInstance !== null;
1450
1454
  }
1455
+ /**
1456
+ * 最近一次模型调用的**真实吞吐** (2026-09-30, 状态栏 `↑ ≈N t/s` 用)。
1457
+ *
1458
+ * 为什么不用"猜": 这里就是 pi-ai 自己打 timing 日志的地方 —— `total=<ms>` 与 `reply=<bytes>`
1459
+ * 都是**实测**, 状态栏直接读它 = 真数字 (字节折 token 才标 ≈)。
1460
+ * 注意: 只在**成功的模型调用**后更新; 没有记录时状态栏就不显示 ↑ (不编)。
1461
+ */
1462
+ let lastAiTiming = null;
1463
+ /** 读最近一次模型调用的吞吐记录 (null = 本进程还没成功调过) */
1464
+ export function getLastAiTiming() { return lastAiTiming; }
1465
+ /**
1466
+ * 最近一次模型调用的**用量** (2026-09-30, 状态栏 `◎ 缓存命中率` 用)。
1467
+ * cachedTokens / promptTokens 都来自 provider 的 usage 字段 (OpenAI/DeepSeek:
1468
+ * prompt_tokens_details.cached_tokens; llama.cpp: timings.cache_n) —— 见 extractUsage。
1469
+ * 命中率 = cached / prompt。**只报实测**, 没记录就不显示 (不编)。
1470
+ */
1471
+ let lastAiUsage = null;
1472
+ /** 读最近一次模型调用的用量记录 (null = 本进程还没有带 usage 的成功调用) */
1473
+ export function getLastAiUsage() { return lastAiUsage; }
1451
1474
  export function getMinimax() {
1452
1475
  return getModel();
1453
1476
  }
@@ -94,10 +94,10 @@ export async function checkAndUpdate(opts = {}) {
94
94
  case 'update_available': {
95
95
  notify(`⚠ 发现新版本: ${r.currentVersion} → ${r.latestVersion}`, YELLOW);
96
96
  if (!prefs.autoInstall) {
97
- notify(' 当前设置为**只通知不自动安装** (autoInstall=false)。更新: bolloon update plan → bolloon update now', CYAN);
97
+ notify(' 当前设置为**只通知不自动安装** (autoInstall=false)。更新: bolloon update (直接执行; 只看计划用 --dry-run)', CYAN);
98
98
  return {
99
99
  hasUpdate: true, info, updated: false,
100
- message: `发现新版 ${r.latestVersion}(未自动安装;运行 bolloon update now 更新)`,
100
+ message: `发现新版 ${r.latestVersion}(未自动安装;运行 bolloon update 更新)`,
101
101
  };
102
102
  }
103
103
  notify(' 自动安装已开启 (autoInstall=true),执行更新...', CYAN);
@@ -25,7 +25,7 @@ import { execFileSync, spawnSync } from 'child_process';
25
25
  import { resolveBolloonHome, CANONICAL_CONFIG_FILE } from '../setup/setup-store.js';
26
26
  export const RUNTIME_MIN = {
27
27
  node: { min: '18.0.0', why: 'Bolloon CLI 与依赖 (ESM / 全局 fetch / node: 前缀) 的运行时' },
28
- npm: { min: '9.0.0', why: '随 Node 18+ 发布; 全局安装与 `update now` 的安装通道' },
28
+ npm: { min: '9.0.0', why: '随 Node 18+ 发布; 全局安装与 `bolloon update` 的安装通道' },
29
29
  git: { min: '2.20.0', why: '`git -C` / `--porcelain` / worktree —— 源码更新与协作通道' },
30
30
  python: { min: '3.8.0', why: 'scripts/** (wiki 门禁/消融夹具) 与 Python Skill 执行' },
31
31
  };
@@ -345,13 +345,13 @@ export async function runDoctor(opts) {
345
345
  detail: `dev 快照: GitHub master ${st.devRef || 'refs/heads/master'} @ commit ${devSha} (比较语义 ${channelKindOf('dev')}, 非 semver)`
346
346
  + `${st.switchableTo ? ` · 可切回 stable (${st.switchableTo.source}${st.switchableTo.target ? ` @ ${st.switchableTo.target}` : ''})` : ''}`
347
347
  + ` · ${DEV_CHANNEL_WARNING}`,
348
- action: 'bolloon update now --channel stable',
348
+ action: 'bolloon update --channel stable',
349
349
  }
350
350
  : {
351
351
  id: 'update_source', label: '安装来源 (双源)', grade: 'ok',
352
352
  detail: `stable: npm registry 权威 (比较语义 ${channelKindOf('stable')})`
353
353
  + `${st.devSha ? ` · 上次用过 dev 快照 commit ${st.devSha}${st.devCheckedAt ? ` (${st.devCheckedAt})` : ''}, 已切回` : ''}`
354
- + ` · 默认通道 ${prefsChannel} · 切 dev 用: bolloon update now --channel dev`,
354
+ + ` · 默认通道 ${prefsChannel} · 切 dev 用: bolloon update --channel dev`,
355
355
  });
356
356
  }
357
357
  const inFlight = st.lastUpdate && IN_FLIGHT_RUN_STATUSES.includes(st.lastUpdate.status);
@@ -589,12 +589,12 @@ export function renderUpdatePlan(plan) {
589
589
  L.push('提醒 (不阻塞, 但建议先处理):');
590
590
  for (const a of plan.advisories)
591
591
  L.push(` - ${a}`);
592
- L.push(` 建议策略: 等当前 Run 结束后更新 (bolloon update --now --wait)`);
592
+ L.push(` 建议策略: 等当前 Run 结束后更新 (bolloon update wait)`);
593
593
  }
594
594
  L.push('');
595
- L.push(`可选: 立即更新 (bolloon update --now --channel ${plan.channel}) / 等当前 Run 结束 (bolloon update --now --wait --channel ${plan.channel}) / 取消`);
595
+ L.push(`可选: 立即更新 (bolloon update --channel ${plan.channel}) / 等当前 Run 结束 (bolloon update wait --channel ${plan.channel}) / 取消`);
596
596
  if (plan.channelKind === 'git-ref')
597
- L.push(`一键回稳定版: bolloon update now --channel stable`);
597
+ L.push(`一键回稳定版: bolloon update --channel stable`);
598
598
  L.push(`默认: ${plan.defaultStrategy === 'wait' ? '等待当前 Run 结束后更新' : '立即更新'}`);
599
599
  return L.join('\n');
600
600
  }
@@ -101,7 +101,7 @@ export function devShaFromIdentity(v) {
101
101
  */
102
102
  export const DEV_CHANNEL_WARNING = '⚠️ dev 通道 = GitHub master HEAD 的即时快照 (未走发布门): 可能中断正在跑的 Goal/Run, 且不保证可回滚到上一个 dev 版。';
103
103
  /** 一键回 stable 的提示语 (同一份措辞)。 */
104
- export const DEV_BACK_TO_STABLE_HINT = '一键回稳定版: bolloon update now --channel stable';
104
+ export const DEV_BACK_TO_STABLE_HINT = '一键回稳定版: bolloon update --channel stable';
105
105
  /** 手机端同一件事的说法 (原生层规则不同: 手机走 web 层 OTA, 不是 npm 全局安装)。 */
106
106
  export const DEV_BACK_TO_STABLE_HINT_MOBILE = '一键回稳定版: 手机端「更新」页 → 切回 stable';
107
107
  // ── 版本比较 (唯一一份) ─────────────────────────────────────────────────────
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "schema": "bolloon-mobile-web/1",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "channel": "stable",
5
5
  "build": "stable",
6
- "commit": "0f98f0fc9bbcd60f04105402a5163b85c58bc785",
7
- "builtAt": "2026-09-28T08:27:37.768Z",
6
+ "commit": "4ac5fe0393fe1b00b21d7d23dade62e4e7854a52",
7
+ "builtAt": "2026-09-30T10:52:06.970Z",
8
8
  "layer": "web",
9
9
  "note": "web 资源层构建戳 (手机端 OTA 的身份第 ③ 级回退; 装机后以 OTA state.json 为准)"
10
10
  }
@@ -20,6 +20,7 @@ import * as os from 'os';
20
20
  import { listInfo, getStoredInfo, publishInfo, removeInfo, buildPaymentRequired, checkAndSettlePayment, buyInfo, } from '../agents/x402/paid-info-store.js';
21
21
  import { buildSignedEnvelope, verifyEnvelope, summarizeVerify } from '../agents/x402/paid-info-protocol.js';
22
22
  import { makeDidResolver } from '../agents/x402/paid-info-tools.js';
23
+ import { handleDirectPayment, directHealth, directPaymentPath, directPaymentEnabled } from '../agents/x402/direct-payment.js';
23
24
  /** 本机 DIAP 身份 (签发信封用) — 缺失时明确报错, 不静默造一个 */
24
25
  async function loadProviderKeypair() {
25
26
  try {
@@ -122,7 +123,7 @@ export function registerX402InfoRoutes(app) {
122
123
  content: stored.content,
123
124
  keypair: kp,
124
125
  payment: {
125
- mode: pay.mode === 'facilitator' ? 'facilitator' : 'local-dev',
126
+ mode: pay.mode === 'facilitator' ? 'facilitator' : pay.mode === 'direct' ? 'direct' : 'local-dev',
126
127
  receipt: String(pay.receipt || ''),
127
128
  txHash: pay.txHash,
128
129
  network: pay.network || stored.item.price.network,
@@ -139,6 +140,32 @@ export function registerX402InfoRoutes(app) {
139
140
  res.status(500).json({ error: e?.message });
140
141
  }
141
142
  });
143
+ // ---- 去中心化直付 (mode = 'direct'): 买方自己发 USDC, 把 txHash 交回来 ----
144
+ // POST /api/x402/info/:id/payment body: { "txHash": "0x…" }
145
+ // 服务器**只读链**: receipt.status=1 + USDC Transfer → payTo + value >= accepts.amount
146
+ // + 两条不同 RPC 交叉一致 + 确认数够 → 落待办 + 给取件 token (202); 未过 → 402 (accepts 逐字)
147
+ app.post('/api/x402/info/:id/payment', async (req, res) => {
148
+ try {
149
+ const id = String(req.params.id);
150
+ const stored = await getStoredInfo(id);
151
+ if (!stored)
152
+ return res.status(404).json({ error: '信息不存在' });
153
+ const baseUrl = `${req.protocol || 'http'}://${req.headers?.host || `127.0.0.1:${process.env.PORT || 54188}`}`;
154
+ const out = await handleDirectPayment({
155
+ item: stored.item,
156
+ bodyText: typeof req.body === 'string' ? req.body : JSON.stringify(req.body ?? {}),
157
+ resourceUrl: `${baseUrl}${directPaymentPath(stored.item.id)}`,
158
+ });
159
+ return res.status(out.status).set(out.headers).send(out.body);
160
+ }
161
+ catch (e) {
162
+ res.status(500).json({ error: e?.message });
163
+ }
164
+ });
165
+ // ---- 直付模式自述 (health 用: 开关与口径必须能从机器读到) ----
166
+ app.get('/api/x402/direct', async (_req, res) => {
167
+ res.json({ enabled: directPaymentEnabled(), paymentPath: directPaymentPath(':id'), ...directHealth() });
168
+ });
142
169
  // ---- 买方辅助: 代付 + 验真 ----
143
170
  app.post('/api/x402/info/buy', async (req, res) => {
144
171
  try {
package/dist/web/sw.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * 现在: 代码类资源 (html/js/css/json) 一律 **network-first** (拿不到网才回退缓存),
7
7
  * 缓存名带版本号, activate 时清掉所有旧缓存; 图标等静态资源仍 cache-first。
8
8
  */
9
- const CACHE = 'bolloon-mobile-v0.5.2';
9
+ const CACHE = 'bolloon-mobile-v0.5.4';
10
10
  const SHELL = [
11
11
  './mobile.html',
12
12
  './mobile.css',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bolloon/bolloon-agent",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "type": "module",
5
5
  "description": "P2P AI Document Agent - 全局安装后执行 `bolloon` 启动产品",
6
6
  "main": "dist/cli-entry.js",
@@ -108,6 +108,7 @@
108
108
  "qrcode": "^1.5.4",
109
109
  "react": "^19.2.8",
110
110
  "react-dom": "^19.2.8",
111
+ "undici": "^7.30.0",
111
112
  "viem": "^2.56.3"
112
113
  },
113
114
  "devDependencies": {