@twinsearth/agent-universe 2.5.6 → 2.5.8

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 CHANGED
@@ -273,7 +273,7 @@ npm config set @twinsearth:registry https://npm.pkg.github.com
273
273
  npm install @twinsearth/agent-universe
274
274
  ```
275
275
 
276
- 已发布版本:1.0.0 / 2.0.0 / 2.2.0 / 2.3.0 / 2.3.1 / 2.3.4 / 2.3.5 / 2.3.6 / 2.4.0 ~ 2.5.6,详见 [Releases](https://github.com/TwinsEarth/agent-universe/releases)。
276
+ 已发布版本:1.0.0 / 2.0.0 / 2.2.0 / 2.3.0 / 2.3.1 / 2.3.4 / 2.3.5 / 2.3.6 / 2.4.0 ~ 2.5.8,详见 [Releases](https://github.com/TwinsEarth/agent-universe/releases)。
277
277
 
278
278
  ## 版本谱系
279
279
 
@@ -307,6 +307,8 @@ npm install @twinsearth/agent-universe
307
307
  | v2.5.4 | **Traversal** | **NAT 穿透:Circuit Relay v2 + AutoNAT + DCUtR + Ping,跨网中继** |
308
308
  | v2.5.5 | **Relay Pool** | **Relay 节点池管理 + 多通道智能切换(默认 3 条,掉线自动补)** |
309
309
  | v2.5.6 | **Regression** | **历史 Bug 回归套件:test/ 14 条 + Rust 网络回归,CI 强制全量回归,修新 bug 先加用例** |
310
+ | v2.5.7 | **Identity** | **跨实现身份一致性:统一 DID 派生口径 + conformance 签名向量逐字节命中上游 + 客户端构建链路根治(file: 依赖)** |
311
+ | v2.5.8 | **Ledger** | **精确整数账本 Money(i64):守恒精确相等无容差 + 发布即托管 __escrow__ 防铸币 + 三端共享金额向量逐值一致** |
310
312
 
311
313
  详见 [RELEASES.md](RELEASES.md) 和 [releases/](releases/) 目录。
312
314
 
package/js/index.js CHANGED
@@ -9,7 +9,7 @@ const { AgentMarket, Bid, Reputation, MIN_STAKE } = require('./lib/market');
9
9
  const { McpHttpClient, McpError, MCP_PROTOCOL_VERSION } = require('./lib/mcp');
10
10
  const aca = require('./lib/aca');
11
11
 
12
- const version = '2.5.6';
12
+ const version = '2.5.8';
13
13
 
14
14
  /**
15
15
  * AgentUniverse 门面:聚合身份、网络、市场能力
package/js/lib/aca.js CHANGED
@@ -129,7 +129,7 @@ function buildManifest(identity, name, capabilities, opts = {}) {
129
129
  const manifest = {
130
130
  did: identity.did,
131
131
  name,
132
- version: opts.version || '2.5.6',
132
+ version: opts.version || '2.5.8',
133
133
  capabilities: [...capabilities],
134
134
  endpoints: opts.endpoints || [],
135
135
  hardware: {
@@ -1,29 +1,51 @@
1
1
  // lib/keychain.js
2
2
  // Ed25519 密钥对 + DID 身份(零依赖,使用 node:crypto)
3
+ //
4
+ // v2.5.7:身份派生口径与 Rust / Python 统一 ——
5
+ // fingerprint = hex(SHA-256(原始 32 字节公钥)[..8])
6
+ // 本项目新铸造身份使用 did:nau: 前缀;parseDid 仍接受上游 did:aip:。
3
7
 
4
8
  const crypto = require('node:crypto');
5
9
 
10
+ // Ed25519 SubjectPublicKeyInfo DER 固定前缀(其后紧跟 32 字节原始公钥)
11
+ const SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex');
12
+
6
13
  /**
7
14
  * 密钥对与去中心化身份
8
15
  */
9
16
  class Keypair {
10
17
  constructor(publicKey, privateKey, did) {
11
- this.publicKey = publicKey; // hex
12
- this.privateKey = privateKey; // hex(node KeyObject 可导出的形式)
13
- this.did = did; // did:au:<hash>
18
+ this.publicKey = publicKey; // SPKI DER hex
19
+ this.privateKey = privateKey; // PKCS8 DER hex
20
+ this.did = did; // did:nau:<fingerprint>
21
+ }
22
+
23
+ /** 从原始 32 字节公钥计算 fingerprint(与 Rust/Python 一致) */
24
+ static fingerprint(rawPubkey) {
25
+ return crypto.createHash('sha256')
26
+ .update(rawPubkey)
27
+ .digest('hex')
28
+ .slice(0, 16); // 前 8 字节 = 16 hex 字符
29
+ }
30
+
31
+ /** 解析 DID,接受上游 did:aip: 与本项目 did:nau:;返回 {method, identifier} */
32
+ static parseDid(s) {
33
+ const m = /^did:(aip|nau):([0-9a-f]+)$/.exec(s);
34
+ if (!m) {
35
+ throw new Error(`不支持的 DID(格式应为 did:<aip|nau>:<id>): ${s}`);
36
+ }
37
+ return { method: m[1], identifier: m[2] };
14
38
  }
15
39
 
16
- /** 生成新的 Ed25519 密钥对与 DID */
40
+ /** 生成新的 Ed25519 密钥对与 DID(新身份使用 did:nau:) */
17
41
  static generate() {
18
42
  const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519');
19
- const pubHex = publicKey.export({ format: 'der', type: 'spki' })
20
- .toString('hex');
21
- // DID 由公钥的 SHA-256 哈希(取前 32 字符)派生
22
- const didHash = crypto.createHash('sha256')
23
- .update(publicKey.export({ format: 'der', type: 'spki' }))
24
- .digest('hex')
25
- .slice(0, 32);
26
- const did = `did:au:${didHash}`;
43
+ const spkiDer = publicKey.export({ format: 'der', type: 'spki' });
44
+ const pubHex = spkiDer.toString('hex');
45
+
46
+ // 去掉 SPKI 固定前缀,得到 32 字节原始公钥
47
+ const rawPub = spkiDer.subarray(SPKI_PREFIX.length);
48
+ const did = `did:nau:${Keypair.fingerprint(rawPub)}`;
27
49
 
28
50
  // 私钥以 PKCS8 DER hex 保存,便于重建 KeyObject
29
51
  const privHex = privateKey.export({ format: 'der', type: 'pkcs8' })
@@ -57,6 +79,12 @@ class Keypair {
57
79
  return this._pubKeyObj;
58
80
  }
59
81
 
82
+ /** 返回 32 字节原始公钥 */
83
+ rawPublicKey() {
84
+ const spkiDer = this._publicKeyObject().export({ format: 'der', type: 'spki' });
85
+ return spkiDer.subarray(SPKI_PREFIX.length);
86
+ }
87
+
60
88
  /** 对消息签名,返回 hex */
61
89
  sign(message) {
62
90
  const data = Buffer.isBuffer(message) ? message : Buffer.from(message);
package/js/lib/market.js CHANGED
@@ -41,8 +41,17 @@ class AgentMarket {
41
41
  this.paidTasks = new Set(); // 已结算任务(防重复支付)
42
42
  }
43
43
 
44
+ /** 金额必须是安全整数(与 Rust Money(i64) 对齐,杜绝浮点导致的跨语言守恒失效) */
45
+ _assertMoney(v, label) {
46
+ if (typeof v !== 'number' || !Number.isInteger(v) || !Number.isSafeInteger(v)) {
47
+ throw new Error(`${label || '金额'}必须是整数`);
48
+ }
49
+ return v;
50
+ }
51
+
44
52
  /** 充值 / 质押金进入账户 */
45
53
  deposit(account, amount) {
54
+ this._assertMoney(amount, '金额');
46
55
  if (amount < 0) throw new Error('金额不能为负');
47
56
  const cur = this.balances.get(account) || 0;
48
57
  this.balances.set(account, cur + amount);
@@ -57,11 +66,17 @@ class AgentMarket {
57
66
  return `__stake__:${agentId}`;
58
67
  }
59
68
 
69
+ /** 任务预算托管账户(发布即锁定,结算时从此支付 / 退款),与 Rust 命名一致 */
70
+ _escrowAccount(taskId) {
71
+ return `__escrow__:${taskId}`;
72
+ }
73
+
60
74
  /** 注册 Agent(需质押 ≥ MIN_STAKE) */
61
75
  registerAgent(card, stake) {
62
76
  if (!card || !card.did) throw new Error('agent_id 不能为空');
63
77
  if (!card.name) throw new Error('name 不能为空');
64
78
  if (this.agents.has(card.did)) throw new Error('Agent 已存在');
79
+ this._assertMoney(stake, '质押');
65
80
  if (stake < MIN_STAKE) {
66
81
  throw new Error(`质押不足,最低 ${MIN_STAKE}`);
67
82
  }
@@ -86,12 +101,15 @@ class AgentMarket {
86
101
  /** 发布任务 */
87
102
  publishTask(taskId, goal, budget, requester) {
88
103
  if (!goal) throw new Error('goal 不能为空');
104
+ this._assertMoney(budget, '预算');
89
105
  if (budget <= 0) throw new Error('预算必须为正');
90
106
  if (this.balance(requester) < budget) {
91
107
  throw new Error('需求方余额不足以覆盖预算');
92
108
  }
93
- // 预算锁定
109
+ // 发布即托管:预算从需求方转入任务托管账户(钱仍在系统内,任意时刻守恒)
94
110
  this.balances.set(requester, this.balance(requester) - budget);
111
+ const escrowAcc = this._escrowAccount(taskId);
112
+ this.balances.set(escrowAcc, this.balance(escrowAcc) + budget);
95
113
 
96
114
  const task = new Task(taskId, goal);
97
115
  task.transition(TaskStatus.OPEN);
@@ -105,6 +123,8 @@ class AgentMarket {
105
123
  /** 提交投标 */
106
124
  submitBid(taskId, agentId, price) {
107
125
  if (!this.agents.has(agentId)) throw new Error('Agent 未注册');
126
+ this._assertMoney(price, '出价');
127
+ if (price <= 0) throw new Error('出价必须为正');
108
128
  const task = this.tasks.get(taskId);
109
129
  if (!task || task.status !== TaskStatus.OPEN) {
110
130
  throw new Error('任务不在开放状态');
@@ -166,12 +186,15 @@ class AgentMarket {
166
186
  const price = task.winnerPrice || task.budget;
167
187
  const pay = Math.min(price, task.budget);
168
188
 
169
- // 从任务锁定预算中支付给执行者(账户间转账,系统总余额不变)
189
+ // 从托管账户支付给执行者、余款退还需求方(账户间转账,总余额不变)
190
+ const escrowAcc = this._escrowAccount(taskId);
170
191
  const assignee = task.assignee;
192
+ this.balances.set(escrowAcc, this.balance(escrowAcc) - pay);
171
193
  this.balances.set(assignee, this.balance(assignee) + pay);
172
194
  // 未用完的预算退还需求方
173
195
  const refund = task.budget - pay;
174
196
  if (refund > 0) {
197
+ this.balances.set(escrowAcc, this.balance(escrowAcc) - refund);
175
198
  this.balances.set(task.requester, this.balance(task.requester) + refund);
176
199
  }
177
200
 
@@ -184,6 +207,8 @@ class AgentMarket {
184
207
  slash(agentId, amount, reason) {
185
208
  const entry = this.agents.get(agentId);
186
209
  if (!entry) throw new Error('Agent 不存在');
210
+ this._assertMoney(amount, '罚没金额');
211
+ if (amount <= 0) throw new Error('罚没金额必须为正');
187
212
  const actual = Math.min(amount, entry.stake);
188
213
  entry.stake -= actual;
189
214
  // 从锁定账户实际扣除(退出系统)
@@ -229,7 +254,7 @@ class AgentMarket {
229
254
  for (const v of this.balances.values()) balanceSum += v;
230
255
  const expected = totalDeposits - this.totalSlashed;
231
256
  return {
232
- conserved: Math.abs(balanceSum - expected) < 1e-9,
257
+ conserved: balanceSum === expected,
233
258
  balanceSum,
234
259
  totalSlashed: this.totalSlashed,
235
260
  expected,
package/js/lib/mcp.js CHANGED
@@ -60,7 +60,7 @@ class McpHttpClient {
60
60
  method: 'initialize',
61
61
  params: {
62
62
  protocolVersion: MCP_PROTOCOL_VERSION,
63
- clientInfo: { name: 'agent-universe-js', version: '2.5.6' },
63
+ clientInfo: { name: 'agent-universe-js', version: '2.5.8' },
64
64
  capabilities: {},
65
65
  },
66
66
  });
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@twinsearth/agent-universe",
3
- "version": "2.5.6",
3
+ "version": "2.5.8",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@twinsearth/agent-universe",
9
- "version": "2.5.6",
9
+ "version": "2.5.8",
10
10
  "license": "MIT",
11
11
  "engines": {
12
12
  "node": ">=18"
package/js/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twinsearth/agent-universe",
3
- "version": "2.5.6",
3
+ "version": "2.5.8",
4
4
  "description": "Agent Universe - 群众化的 AGI 路线,去中心化的智能体共享 & 开源网络。使命:让科技造福全人类!",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
package/js/test/test.js CHANGED
@@ -1,7 +1,9 @@
1
1
  // test/test.js
2
- // Agent Universe JS SDK 测试(8 项)
2
+ // Agent Universe JS SDK 测试(14 项)
3
3
 
4
4
  const assert = require('node:assert');
5
+ const fs = require('node:fs');
6
+ const path = require('node:path');
5
7
  const {
6
8
  version,
7
9
  AgentUniverse,
@@ -41,15 +43,15 @@ function test(name, fn) {
41
43
  console.log('Agent Universe JS SDK 测试\n');
42
44
 
43
45
  // 1. 版本号
44
- test('版本号为 2.5.6', () => {
45
- assert.strictEqual(version, '2.5.6');
46
+ test('版本号为 2.5.8', () => {
47
+ assert.strictEqual(version, '2.5.8');
46
48
  });
47
49
 
48
50
  // 2. 密钥对 + DID + 签名验证
49
51
  test('Keypair 生成 DID 且签名可验证', () => {
50
52
  const kp = Keypair.generate();
51
- assert.ok(kp.did.startsWith('did:au:'), 'DID 前缀');
52
- assert.strictEqual(kp.did.length, 'did:au:'.length + 32);
53
+ assert.ok(kp.did.startsWith('did:nau:'), 'DID 前缀');
54
+ assert.strictEqual(kp.did.length, 'did:nau:'.length + 16);
53
55
  const msg = 'hello agent universe';
54
56
  const sig = kp.sign(msg);
55
57
  assert.ok(kp.verify(msg, sig), '签名验证通过');
@@ -154,6 +156,45 @@ test('罚没后守恒:总余额 = 总充值 − 罚没', () => {
154
156
  assert.strictEqual(check.balanceSum, 140);
155
157
  });
156
158
 
159
+ // 8b. 整数账本:拒绝浮点金额与 0/负出价(与 Rust Money(i64) 对齐)
160
+ test('整数账本:拒绝浮点金额与非正出价', () => {
161
+ const market = new AgentMarket();
162
+ const owner = 'did:au:int';
163
+ assert.throws(() => market.deposit(owner, 10.5), /整数/);
164
+ market.deposit(owner, 200);
165
+ const card = AgentCard.new({ did: owner, name: 'int' });
166
+ market.registerAgent(card, MIN_STAKE);
167
+ market.publishTask('t-int', 'goal', 50, owner);
168
+ assert.throws(() => market.submitBid('t-int', owner, 0), /正/);
169
+ assert.throws(() => market.submitBid('t-int', owner, -5), /正/);
170
+ assert.throws(() => market.submitBid('t-int', owner, 5.5), /整数/);
171
+ });
172
+
173
+ // 8c. 跨语言金额向量:逐账户余额命中 conformance/money-vectors.json(与 Rust 一致)
174
+ test('跨语言金额向量:逐账户余额命中 conformance 向量', () => {
175
+ const vector = JSON.parse(
176
+ fs.readFileSync(path.join(__dirname, '../../conformance/money-vectors.json'), 'utf8')
177
+ );
178
+ const market = new AgentMarket();
179
+ market.deposit('agent-1', 100);
180
+ const card = AgentCard.new({ did: 'agent-1', name: 'worker' }).withSkill('writing');
181
+ market.registerAgent(card, MIN_STAKE);
182
+ market.deposit('requester-1', 50);
183
+ market.publishTask('task-1', 'translate', 50, 'requester-1');
184
+ market.submitBid('task-1', 'agent-1', 10);
185
+ assert.strictEqual(market.matchTask('task-1').agentId, 'agent-1');
186
+ market.completeTask('task-1', true);
187
+ const paid = market.settle('task-1');
188
+ assert.strictEqual(paid.paid, vector.expected_report.total_paid);
189
+ for (const [key, want] of Object.entries(vector.expected_balances)) {
190
+ assert.strictEqual(market.balance(key), want, `账户 ${key} 跨语言不一致`);
191
+ }
192
+ const report = market.conservationCheck(vector.expected_report.total_deposits);
193
+ assert.strictEqual(report.totalSlashed, vector.expected_report.total_slashed);
194
+ assert.strictEqual(report.balanceSum, vector.expected_report.balance_sum);
195
+ assert.strictEqual(report.conserved, vector.expected_report.conserved);
196
+ });
197
+
157
198
  // 9. AipIdentity DID 与签名往返
158
199
  test('AipIdentity 生成 did:aip 且签名可验证', () => {
159
200
  const id = AipIdentity.generate();
package/lib/aca.js ADDED
@@ -0,0 +1,3 @@
1
+ // 根包 /lib 子路径入口(v2.5.7 补):re-export js/lib,
2
+ // 使根发布包暴露 /lib/aca.js 子路径,供浏览器端按需引入(与 js 子包发布结构对齐)。
3
+ module.exports = require('../js/lib/aca.js');
package/lib/dht.js ADDED
@@ -0,0 +1,3 @@
1
+ // 根包 /lib 子路径入口(v2.5.7 补):re-export js/lib,
2
+ // 使根发布包暴露 /lib/dht.js 子路径(与 js 子包发布结构对齐)。
3
+ module.exports = require('../js/lib/dht.js');
@@ -0,0 +1,3 @@
1
+ // 根包 /lib 子路径入口(v2.5.7 补):re-export js/lib,
2
+ // 使根发布包暴露 /lib/keychain.js 子路径(依赖 node:crypto,浏览器端勿直接引)。
3
+ module.exports = require('../js/lib/keychain.js');
package/lib/market.js ADDED
@@ -0,0 +1,4 @@
1
+ // 根包 /lib 子路径入口(v2.5.7 补):re-export js/lib,
2
+ // 使根发布包暴露 /lib/market.js 子路径。market.js 为纯逻辑(仅依赖 models,不引 node:crypto),
3
+ // 浏览器 / WKWebView 端只引此模块即可运行市场演示,避开密钥模块。
4
+ module.exports = require('../js/lib/market.js');
package/lib/mcp.js ADDED
@@ -0,0 +1,3 @@
1
+ // 根包 /lib 子路径入口(v2.5.7 补):re-export js/lib,
2
+ // 使根发布包暴露 /lib/mcp.js 子路径(与 js 子包发布结构对齐)。
3
+ module.exports = require('../js/lib/mcp.js');
package/lib/models.js ADDED
@@ -0,0 +1,3 @@
1
+ // 根包 /lib 子路径入口(v2.5.7 补):re-export js/lib,
2
+ // 使根发布包暴露 /lib/models.js 子路径(与 js 子包发布结构对齐)。
3
+ module.exports = require('../js/lib/models.js');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twinsearth/agent-universe",
3
- "version": "2.5.6",
3
+ "version": "2.5.8",
4
4
  "description": "Agent Universe - 群众化的 AGI 路线,去中心化的智能体共享 & 开源网络。使命:让科技造福全人类!",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -41,6 +41,7 @@
41
41
  "files": [
42
42
  "index.js",
43
43
  "index.d.ts",
44
- "js"
44
+ "js",
45
+ "lib"
45
46
  ]
46
47
  }