@twinsearth/agent-universe 2.3.5 → 2.5.6
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/LICENSE +21 -0
- package/README.md +410 -0
- package/index.d.ts +5 -107
- package/index.js +5 -50
- package/js/index.d.ts +209 -0
- package/js/index.js +71 -0
- package/js/lib/aca.js +259 -0
- package/js/lib/mcp.js +101 -0
- package/js/package-lock.json +16 -0
- package/js/package.json +43 -0
- package/js/test/test.js +224 -0
- package/package.json +14 -11
- /package/{lib → js/lib}/dht.js +0 -0
- /package/{lib → js/lib}/keychain.js +0 -0
- /package/{lib → js/lib}/market.js +0 -0
- /package/{lib → js/lib}/models.js +0 -0
package/js/index.d.ts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// Type definitions for @twinsearth/agent-universe
|
|
2
|
+
|
|
3
|
+
export const version: string;
|
|
4
|
+
export const MIN_STAKE: number;
|
|
5
|
+
|
|
6
|
+
export class Keypair {
|
|
7
|
+
publicKey: string;
|
|
8
|
+
privateKey: string;
|
|
9
|
+
did: string;
|
|
10
|
+
static generate(): Keypair;
|
|
11
|
+
sign(message: string | Buffer): string;
|
|
12
|
+
verify(message: string | Buffer, signatureHex: string): boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class AgentCard {
|
|
16
|
+
did: string;
|
|
17
|
+
name: string;
|
|
18
|
+
capabilities: string[];
|
|
19
|
+
skills: string[];
|
|
20
|
+
version: string;
|
|
21
|
+
stake: number;
|
|
22
|
+
reputation: number;
|
|
23
|
+
static new(opts: { did: string; name: string }): AgentCard;
|
|
24
|
+
withCapability(cap: string): this;
|
|
25
|
+
withSkill(skill: string): this;
|
|
26
|
+
hasCapability(cap: string): boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const TaskStatus: Record<string, string>;
|
|
30
|
+
|
|
31
|
+
export class Task {
|
|
32
|
+
taskId: string;
|
|
33
|
+
goal: string;
|
|
34
|
+
status: string;
|
|
35
|
+
assignee: string | null;
|
|
36
|
+
history: string[];
|
|
37
|
+
constructor(taskId: string, goal: string);
|
|
38
|
+
assign(did: string): this;
|
|
39
|
+
start(): this;
|
|
40
|
+
complete(): this;
|
|
41
|
+
verify(passed: boolean): this;
|
|
42
|
+
settle(): this;
|
|
43
|
+
readonly isTerminal: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class MemoryDHT {
|
|
47
|
+
put(key: string, value: unknown): void;
|
|
48
|
+
get(key: string): unknown;
|
|
49
|
+
has(key: string): boolean;
|
|
50
|
+
remove(key: string): boolean;
|
|
51
|
+
readonly size: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class ShardedIndex {
|
|
55
|
+
constructor(numShards?: number);
|
|
56
|
+
put(key: string, value: unknown): number;
|
|
57
|
+
get(key: string): unknown;
|
|
58
|
+
has(key: string): boolean;
|
|
59
|
+
remove(key: string): boolean;
|
|
60
|
+
readonly size: number;
|
|
61
|
+
distribution(): number[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function shardOf(key: string, numShards: number): number;
|
|
65
|
+
|
|
66
|
+
export class Bid {
|
|
67
|
+
agentId: string;
|
|
68
|
+
price: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class Reputation {
|
|
72
|
+
quality: number;
|
|
73
|
+
speed: number;
|
|
74
|
+
honesty: number;
|
|
75
|
+
availability: number;
|
|
76
|
+
overall(): number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export class AgentMarket {
|
|
80
|
+
agents: Map<string, unknown>;
|
|
81
|
+
tasks: Map<string, Task>;
|
|
82
|
+
deposit(account: string, amount: number): void;
|
|
83
|
+
balance(account: string): number;
|
|
84
|
+
registerAgent(card: AgentCard, stake: number): boolean;
|
|
85
|
+
publishTask(taskId: string, goal: string, budget: number, requester: string): Task;
|
|
86
|
+
submitBid(taskId: string, agentId: string, price: number): boolean;
|
|
87
|
+
matchTask(taskId: string): Bid;
|
|
88
|
+
completeTask(taskId: string, passed?: boolean): Task;
|
|
89
|
+
settle(taskId: string): { paid: number; reason: string };
|
|
90
|
+
slash(agentId: string, amount: number, reason: string): unknown;
|
|
91
|
+
discoverBySkill(skill: string): AgentCard[];
|
|
92
|
+
leaderboard(limit?: number): unknown[];
|
|
93
|
+
conservationCheck(totalDeposits: number): {
|
|
94
|
+
conserved: boolean;
|
|
95
|
+
balanceSum: number;
|
|
96
|
+
totalSlashed: number;
|
|
97
|
+
expected: number;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export class AgentUniverse {
|
|
102
|
+
identity: Keypair;
|
|
103
|
+
dht: MemoryDHT;
|
|
104
|
+
market: AgentMarket;
|
|
105
|
+
readonly did: string;
|
|
106
|
+
register(card: AgentCard): AgentCard;
|
|
107
|
+
discover(capability: string): AgentCard[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ── MCP ──
|
|
111
|
+
export const MCP_PROTOCOL_VERSION: string;
|
|
112
|
+
|
|
113
|
+
export class McpError extends Error {
|
|
114
|
+
code: number;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export class McpHttpClient {
|
|
118
|
+
initialized: boolean;
|
|
119
|
+
constructor(baseUrl?: string, path?: string, timeout?: number);
|
|
120
|
+
initialize(): Promise<{
|
|
121
|
+
protocolVersion: string;
|
|
122
|
+
serverInfo: { name: string; version: string };
|
|
123
|
+
}>;
|
|
124
|
+
ping(): Promise<boolean>;
|
|
125
|
+
listTools(): Promise<
|
|
126
|
+
Array<{
|
|
127
|
+
name: string;
|
|
128
|
+
description?: string;
|
|
129
|
+
inputSchema: Record<string, unknown>;
|
|
130
|
+
}>
|
|
131
|
+
>;
|
|
132
|
+
callTool(
|
|
133
|
+
name: string,
|
|
134
|
+
args?: Record<string, unknown>
|
|
135
|
+
): Promise<{ content: Array<{ type: string; text: string }>; isError?: boolean }>;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ── ACA ──
|
|
139
|
+
export class AipIdentity {
|
|
140
|
+
did: string;
|
|
141
|
+
readonly publicKey: Buffer;
|
|
142
|
+
static generate(): AipIdentity;
|
|
143
|
+
static fromSeed(seed: Buffer | Uint8Array): AipIdentity;
|
|
144
|
+
signObject(obj: Record<string, unknown>): string;
|
|
145
|
+
signInto(obj: Record<string, unknown>): Record<string, unknown>;
|
|
146
|
+
static verifyObject(obj: Record<string, unknown>, rawPub: Buffer): boolean;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function buildManifest(
|
|
150
|
+
identity: AipIdentity,
|
|
151
|
+
name: string,
|
|
152
|
+
capabilities: string[],
|
|
153
|
+
opts?: Record<string, unknown>
|
|
154
|
+
): Record<string, unknown>;
|
|
155
|
+
|
|
156
|
+
export function buildEnvelope(
|
|
157
|
+
requesterDid: string,
|
|
158
|
+
capability: string,
|
|
159
|
+
outputSpec: string,
|
|
160
|
+
opts?: Record<string, unknown>
|
|
161
|
+
): Record<string, unknown>;
|
|
162
|
+
|
|
163
|
+
export function buildMessage(
|
|
164
|
+
identity: AipIdentity,
|
|
165
|
+
msgType: string,
|
|
166
|
+
toDid: string,
|
|
167
|
+
payload: unknown
|
|
168
|
+
): Record<string, unknown>;
|
|
169
|
+
|
|
170
|
+
export function buildReceipt(
|
|
171
|
+
identity: AipIdentity,
|
|
172
|
+
taskId: string,
|
|
173
|
+
result: Buffer,
|
|
174
|
+
opts?: Record<string, unknown>
|
|
175
|
+
): Record<string, unknown>;
|
|
176
|
+
|
|
177
|
+
export function handshakeMessage(
|
|
178
|
+
identity: AipIdentity,
|
|
179
|
+
manifest: Record<string, unknown>
|
|
180
|
+
): Record<string, unknown>;
|
|
181
|
+
|
|
182
|
+
export function proposalMessage(
|
|
183
|
+
identity: AipIdentity,
|
|
184
|
+
toDid: string,
|
|
185
|
+
envelope: Record<string, unknown>
|
|
186
|
+
): Record<string, unknown>;
|
|
187
|
+
|
|
188
|
+
export function receiptMessage(
|
|
189
|
+
identity: AipIdentity,
|
|
190
|
+
toDid: string,
|
|
191
|
+
receipt: Record<string, unknown>
|
|
192
|
+
): Record<string, unknown>;
|
|
193
|
+
|
|
194
|
+
export function verifyManifest(
|
|
195
|
+
manifest: Record<string, unknown>,
|
|
196
|
+
rawPub: Buffer
|
|
197
|
+
): boolean;
|
|
198
|
+
export function verifyMessage(
|
|
199
|
+
message: Record<string, unknown>,
|
|
200
|
+
rawPub: Buffer
|
|
201
|
+
): boolean;
|
|
202
|
+
export function verifyReceipt(
|
|
203
|
+
receipt: Record<string, unknown>,
|
|
204
|
+
rawPub: Buffer
|
|
205
|
+
): boolean;
|
|
206
|
+
export function verifyReceiptResult(
|
|
207
|
+
receipt: Record<string, unknown>,
|
|
208
|
+
result: Buffer
|
|
209
|
+
): boolean;
|
package/js/index.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// index.js
|
|
2
|
+
// Agent Universe(智能体宇宙)主入口
|
|
3
|
+
// 群众化的 AGI 路线,去中心化的智能体共享 & 开源网络
|
|
4
|
+
|
|
5
|
+
const { Keypair } = require('./lib/keychain');
|
|
6
|
+
const { AgentCard, Task, TaskStatus } = require('./lib/models');
|
|
7
|
+
const { MemoryDHT, ShardedIndex, shardOf } = require('./lib/dht');
|
|
8
|
+
const { AgentMarket, Bid, Reputation, MIN_STAKE } = require('./lib/market');
|
|
9
|
+
const { McpHttpClient, McpError, MCP_PROTOCOL_VERSION } = require('./lib/mcp');
|
|
10
|
+
const aca = require('./lib/aca');
|
|
11
|
+
|
|
12
|
+
const version = '2.5.6';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* AgentUniverse 门面:聚合身份、网络、市场能力
|
|
16
|
+
*/
|
|
17
|
+
class AgentUniverse {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.identity = Keypair.generate();
|
|
20
|
+
this.dht = new MemoryDHT();
|
|
21
|
+
this.market = new AgentMarket();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get did() {
|
|
25
|
+
return this.identity.did;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** 注册一张 AgentCard 到本地网络 */
|
|
29
|
+
register(card) {
|
|
30
|
+
this.dht.put(card.did, card);
|
|
31
|
+
return card;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** 发现某能力的 Agent */
|
|
35
|
+
discover(capability) {
|
|
36
|
+
return this.market.discoverBySkill(capability);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
version,
|
|
42
|
+
AgentUniverse,
|
|
43
|
+
Keypair,
|
|
44
|
+
AgentCard,
|
|
45
|
+
Task,
|
|
46
|
+
TaskStatus,
|
|
47
|
+
MemoryDHT,
|
|
48
|
+
ShardedIndex,
|
|
49
|
+
shardOf,
|
|
50
|
+
AgentMarket,
|
|
51
|
+
Bid,
|
|
52
|
+
Reputation,
|
|
53
|
+
MIN_STAKE,
|
|
54
|
+
// MCP
|
|
55
|
+
McpHttpClient,
|
|
56
|
+
McpError,
|
|
57
|
+
MCP_PROTOCOL_VERSION,
|
|
58
|
+
// ACA(跨语言对齐身份与协议对象)
|
|
59
|
+
AipIdentity: aca.AipIdentity,
|
|
60
|
+
buildManifest: aca.buildManifest,
|
|
61
|
+
buildEnvelope: aca.buildEnvelope,
|
|
62
|
+
buildMessage: aca.buildMessage,
|
|
63
|
+
buildReceipt: aca.buildReceipt,
|
|
64
|
+
handshakeMessage: aca.handshakeMessage,
|
|
65
|
+
proposalMessage: aca.proposalMessage,
|
|
66
|
+
receiptMessage: aca.receiptMessage,
|
|
67
|
+
verifyManifest: aca.verifyManifest,
|
|
68
|
+
verifyMessage: aca.verifyMessage,
|
|
69
|
+
verifyReceipt: aca.verifyReceipt,
|
|
70
|
+
verifyReceiptResult: aca.verifyReceiptResult,
|
|
71
|
+
};
|
package/js/lib/aca.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// lib/aca.js
|
|
2
|
+
// ACA(Agent Communication Architecture):与 Rust gsn-core / Python SDK
|
|
3
|
+
// 对齐的身份、规范签名与协议对象构造。零依赖,使用 node:crypto。
|
|
4
|
+
//
|
|
5
|
+
// 跨语言一致性:canonical 载荷为移除 signature 键后,紧凑、按 key 字典序、
|
|
6
|
+
// 不转义非 ASCII 的 JSON 字节,与 Rust serde_json(BTreeMap)、Python
|
|
7
|
+
// sort_keys 产出逐字节一致,因此三端可互验签名。
|
|
8
|
+
|
|
9
|
+
const crypto = require('node:crypto');
|
|
10
|
+
|
|
11
|
+
// Ed25519 PKCS#8 DER 固定前缀(16 字节),后接 32 字节种子
|
|
12
|
+
const PKCS8_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex');
|
|
13
|
+
|
|
14
|
+
// ── 枚举标签(与 Rust serde 变体名一致) ──
|
|
15
|
+
const MODE_SELF_REPORTED = 'SelfReported';
|
|
16
|
+
const LEVEL_L0 = 'L0Sample';
|
|
17
|
+
const PRIVACY_PUBLIC = 'Public';
|
|
18
|
+
const PRIORITY_NORMAL = 'Normal';
|
|
19
|
+
const STATUS_COMPLETED = 'Completed';
|
|
20
|
+
const MSG_HANDSHAKE = 'Handshake';
|
|
21
|
+
const MSG_TASK_PROPOSAL = 'TaskProposal';
|
|
22
|
+
const MSG_RECEIPT = 'Receipt';
|
|
23
|
+
|
|
24
|
+
function nowSec() {
|
|
25
|
+
return Math.floor(Date.now() / 1000);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** 稳定 JSON 序列化:紧凑、对象键按字典序、非 ASCII 原样输出 */
|
|
29
|
+
function stableStringify(value) {
|
|
30
|
+
if (value === null || typeof value !== 'object') {
|
|
31
|
+
return JSON.stringify(value);
|
|
32
|
+
}
|
|
33
|
+
if (Array.isArray(value)) {
|
|
34
|
+
return '[' + value.map(stableStringify).join(',') + ']';
|
|
35
|
+
}
|
|
36
|
+
const keys = Object.keys(value).sort();
|
|
37
|
+
return (
|
|
38
|
+
'{' +
|
|
39
|
+
keys
|
|
40
|
+
.map((k) => JSON.stringify(k) + ':' + stableStringify(value[k]))
|
|
41
|
+
.join(',') +
|
|
42
|
+
'}'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** 规范待签名载荷:移除 signature 键,返回 Buffer */
|
|
47
|
+
function canonicalPayload(obj) {
|
|
48
|
+
const copy = { ...obj };
|
|
49
|
+
delete copy.signature;
|
|
50
|
+
return Buffer.from(stableStringify(copy), 'utf8');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function rawPublicFromKey(pubKey) {
|
|
54
|
+
return Buffer.from(pubKey.export({ format: 'jwk' }).x, 'base64url');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function pubKeyFromRaw(raw) {
|
|
58
|
+
return crypto.createPublicKey({
|
|
59
|
+
key: { kty: 'OKP', crv: 'Ed25519', x: raw.toString('base64url') },
|
|
60
|
+
format: 'jwk',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 跨语言对齐的节点身份:Ed25519 + did:aip(原始 32 字节公钥指纹)
|
|
66
|
+
*/
|
|
67
|
+
class AipIdentity {
|
|
68
|
+
constructor(privKey, rawPub) {
|
|
69
|
+
this._priv = privKey;
|
|
70
|
+
this._rawPub = rawPub;
|
|
71
|
+
const hash = crypto.createHash('sha256').update(rawPub).digest('hex');
|
|
72
|
+
this.did = 'did:aip:' + hash.slice(0, 16);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static generate() {
|
|
76
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519');
|
|
77
|
+
return new AipIdentity(privateKey, rawPublicFromKey(publicKey));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static fromSeed(seed) {
|
|
81
|
+
const buf = Buffer.isBuffer(seed) ? seed : Buffer.from(seed);
|
|
82
|
+
if (buf.length !== 32) throw new Error('seed 必须为 32 字节');
|
|
83
|
+
const priv = crypto.createPrivateKey({
|
|
84
|
+
key: Buffer.concat([PKCS8_PREFIX, buf]),
|
|
85
|
+
format: 'der',
|
|
86
|
+
type: 'pkcs8',
|
|
87
|
+
});
|
|
88
|
+
const rawPub = rawPublicFromKey(crypto.createPublicKey(priv));
|
|
89
|
+
return new AipIdentity(priv, rawPub);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** 32 字节原始公钥 */
|
|
93
|
+
get publicKey() {
|
|
94
|
+
return this._rawPub;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
signObject(obj) {
|
|
98
|
+
return crypto.sign(null, canonicalPayload(obj), this._priv).toString('hex');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
signInto(obj) {
|
|
102
|
+
obj.signature = this.signObject(obj);
|
|
103
|
+
return obj;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static verifyObject(obj, rawPub) {
|
|
107
|
+
const sigHex = obj && obj.signature;
|
|
108
|
+
if (!sigHex) return false;
|
|
109
|
+
let sig;
|
|
110
|
+
try {
|
|
111
|
+
sig = Buffer.from(sigHex, 'hex');
|
|
112
|
+
} catch (e) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
return crypto.verify(
|
|
117
|
+
null,
|
|
118
|
+
canonicalPayload(obj),
|
|
119
|
+
pubKeyFromRaw(rawPub),
|
|
120
|
+
sig
|
|
121
|
+
);
|
|
122
|
+
} catch (e) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function buildManifest(identity, name, capabilities, opts = {}) {
|
|
129
|
+
const manifest = {
|
|
130
|
+
did: identity.did,
|
|
131
|
+
name,
|
|
132
|
+
version: opts.version || '2.5.6',
|
|
133
|
+
capabilities: [...capabilities],
|
|
134
|
+
endpoints: opts.endpoints || [],
|
|
135
|
+
hardware: {
|
|
136
|
+
cpu_cores: opts.cpuCores || 0,
|
|
137
|
+
memory_mb: opts.memoryMb || 0,
|
|
138
|
+
disk_free_gb: opts.diskFreeGb || 0,
|
|
139
|
+
gpu: null,
|
|
140
|
+
bandwidth_up_mbps: 0,
|
|
141
|
+
bandwidth_down_mbps: 0,
|
|
142
|
+
platform: opts.platform || 'desktop',
|
|
143
|
+
},
|
|
144
|
+
verification_modes: opts.verificationModes || [MODE_SELF_REPORTED],
|
|
145
|
+
stake: opts.stake || 0,
|
|
146
|
+
reputation_ref: null,
|
|
147
|
+
model_hash: null,
|
|
148
|
+
mcp_tool_count: opts.mcpToolCount || 0,
|
|
149
|
+
signature: '',
|
|
150
|
+
timestamp: nowSec(),
|
|
151
|
+
};
|
|
152
|
+
return identity.signInto(manifest);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function buildEnvelope(requesterDid, capability, outputSpec, opts = {}) {
|
|
156
|
+
return {
|
|
157
|
+
task_id: crypto.randomUUID(),
|
|
158
|
+
requester_did: requesterDid,
|
|
159
|
+
capability,
|
|
160
|
+
input_cid: opts.inputCid || '',
|
|
161
|
+
output_spec: outputSpec,
|
|
162
|
+
verification_level: opts.verificationLevel || LEVEL_L0,
|
|
163
|
+
privacy: opts.privacy || PRIVACY_PUBLIC,
|
|
164
|
+
budget: opts.budget || 0,
|
|
165
|
+
timeout_secs: opts.timeoutSecs || 300,
|
|
166
|
+
priority: opts.priority || PRIORITY_NORMAL,
|
|
167
|
+
mcp_tool: opts.mcpTool || null,
|
|
168
|
+
created_at: nowSec(),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function buildMessage(identity, msgType, toDid, payload) {
|
|
173
|
+
const message = {
|
|
174
|
+
message_id: crypto.randomUUID(),
|
|
175
|
+
msg_type: msgType,
|
|
176
|
+
from_did: identity.did,
|
|
177
|
+
to_did: toDid,
|
|
178
|
+
payload,
|
|
179
|
+
timestamp: nowSec(),
|
|
180
|
+
signature: '',
|
|
181
|
+
};
|
|
182
|
+
return identity.signInto(message);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function handshakeMessage(identity, manifest) {
|
|
186
|
+
return buildMessage(identity, MSG_HANDSHAKE, '*', manifest);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function proposalMessage(identity, toDid, envelope) {
|
|
190
|
+
return buildMessage(identity, MSG_TASK_PROPOSAL, toDid, envelope);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function buildReceipt(identity, taskId, result, opts = {}) {
|
|
194
|
+
const hash = crypto.createHash('sha256').update(result).digest();
|
|
195
|
+
const metering = Object.assign(
|
|
196
|
+
{
|
|
197
|
+
compute_ms: 0,
|
|
198
|
+
memory_peak_mb: 0,
|
|
199
|
+
bandwidth_mb: 0,
|
|
200
|
+
storage_bytes: 0,
|
|
201
|
+
energy_joules: 0,
|
|
202
|
+
},
|
|
203
|
+
opts.metering || {}
|
|
204
|
+
);
|
|
205
|
+
const receipt = {
|
|
206
|
+
task_id: taskId,
|
|
207
|
+
executor_did: identity.did,
|
|
208
|
+
result_cid: 'cid:' + hash.toString('hex').slice(0, 16),
|
|
209
|
+
result_hash: [...hash],
|
|
210
|
+
status: opts.status || STATUS_COMPLETED,
|
|
211
|
+
metering,
|
|
212
|
+
tee_quote: opts.teeQuote || null,
|
|
213
|
+
zk_proof: opts.zkProof || null,
|
|
214
|
+
completed_at: nowSec(),
|
|
215
|
+
signature: '',
|
|
216
|
+
};
|
|
217
|
+
return identity.signInto(receipt);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function receiptMessage(identity, toDid, receipt) {
|
|
221
|
+
return buildMessage(identity, MSG_RECEIPT, toDid, receipt);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function verifyManifest(manifest, rawPub) {
|
|
225
|
+
return AipIdentity.verifyObject(manifest, rawPub);
|
|
226
|
+
}
|
|
227
|
+
function verifyMessage(message, rawPub) {
|
|
228
|
+
return AipIdentity.verifyObject(message, rawPub);
|
|
229
|
+
}
|
|
230
|
+
function verifyReceipt(receipt, rawPub) {
|
|
231
|
+
return AipIdentity.verifyObject(receipt, rawPub);
|
|
232
|
+
}
|
|
233
|
+
function verifyReceiptResult(receipt, result) {
|
|
234
|
+
const hash = crypto.createHash('sha256').update(result).digest();
|
|
235
|
+
return deepEqualArray(receipt.result_hash, [...hash]);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function deepEqualArray(a, b) {
|
|
239
|
+
if (!Array.isArray(a) || a.length !== b.length) return false;
|
|
240
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
module.exports = {
|
|
245
|
+
AipIdentity,
|
|
246
|
+
canonicalPayload,
|
|
247
|
+
stableStringify,
|
|
248
|
+
buildManifest,
|
|
249
|
+
buildEnvelope,
|
|
250
|
+
buildMessage,
|
|
251
|
+
buildReceipt,
|
|
252
|
+
handshakeMessage,
|
|
253
|
+
proposalMessage,
|
|
254
|
+
receiptMessage,
|
|
255
|
+
verifyManifest,
|
|
256
|
+
verifyMessage,
|
|
257
|
+
verifyReceipt,
|
|
258
|
+
verifyReceiptResult,
|
|
259
|
+
};
|
package/js/lib/mcp.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// lib/mcp.js
|
|
2
|
+
// MCP(Model Context Protocol)HTTP 客户端。
|
|
3
|
+
// 通过 gsn-daemon 的 POST /api/v1/mcp JSON-RPC 端点调用市场工具,
|
|
4
|
+
// 完整走 initialize → notifications/initialized → ping / tools/list /
|
|
5
|
+
// tools/call。tools/call 由 daemon 端 MarketMcpBridge 真实路由执行。
|
|
6
|
+
// 使用 Node 18+ 内置 fetch,零额外依赖。
|
|
7
|
+
|
|
8
|
+
const MCP_PROTOCOL_VERSION = '2024-11-05';
|
|
9
|
+
|
|
10
|
+
class McpError extends Error {
|
|
11
|
+
constructor(code, message) {
|
|
12
|
+
super(`[JSON-RPC ${code}] ${message}`);
|
|
13
|
+
this.code = code;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class McpHttpClient {
|
|
18
|
+
constructor(
|
|
19
|
+
baseUrl = 'http://127.0.0.1:4002',
|
|
20
|
+
path = '/api/v1/mcp',
|
|
21
|
+
timeout = 10000
|
|
22
|
+
) {
|
|
23
|
+
this.endpoint = baseUrl.replace(/\/$/, '') + path;
|
|
24
|
+
this.timeout = timeout;
|
|
25
|
+
this._id = 0;
|
|
26
|
+
this.initialized = false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async _post(payload, awaitResponse = true) {
|
|
30
|
+
const ctrl = new AbortController();
|
|
31
|
+
const timer = setTimeout(() => ctrl.abort(), this.timeout);
|
|
32
|
+
let res;
|
|
33
|
+
try {
|
|
34
|
+
res = await fetch(this.endpoint, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: {
|
|
37
|
+
'Content-Type': 'application/json',
|
|
38
|
+
Accept: 'application/json',
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify(payload),
|
|
41
|
+
signal: ctrl.signal,
|
|
42
|
+
});
|
|
43
|
+
} finally {
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const text = await res.text();
|
|
48
|
+
if (!awaitResponse || !text) return null;
|
|
49
|
+
const rpc = JSON.parse(text);
|
|
50
|
+
if (rpc.error) {
|
|
51
|
+
throw new McpError(rpc.error.code, rpc.error.message);
|
|
52
|
+
}
|
|
53
|
+
return rpc.result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async initialize() {
|
|
57
|
+
const result = await this._post({
|
|
58
|
+
jsonrpc: '2.0',
|
|
59
|
+
id: ++this._id,
|
|
60
|
+
method: 'initialize',
|
|
61
|
+
params: {
|
|
62
|
+
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
63
|
+
clientInfo: { name: 'agent-universe-js', version: '2.5.6' },
|
|
64
|
+
capabilities: {},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
await this._post(
|
|
68
|
+
{ jsonrpc: '2.0', method: 'notifications/initialized' },
|
|
69
|
+
false
|
|
70
|
+
);
|
|
71
|
+
this.initialized = true;
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async ping() {
|
|
76
|
+
await this._post({ jsonrpc: '2.0', id: ++this._id, method: 'ping' });
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async listTools() {
|
|
81
|
+
if (!this.initialized) await this.initialize();
|
|
82
|
+
const result = await this._post({
|
|
83
|
+
jsonrpc: '2.0',
|
|
84
|
+
id: ++this._id,
|
|
85
|
+
method: 'tools/list',
|
|
86
|
+
});
|
|
87
|
+
return result.tools;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async callTool(name, args = {}) {
|
|
91
|
+
if (!this.initialized) await this.initialize();
|
|
92
|
+
return this._post({
|
|
93
|
+
jsonrpc: '2.0',
|
|
94
|
+
id: ++this._id,
|
|
95
|
+
method: 'tools/call',
|
|
96
|
+
params: { name, arguments: args },
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = { McpHttpClient, McpError, MCP_PROTOCOL_VERSION };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@twinsearth/agent-universe",
|
|
3
|
+
"version": "2.5.6",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "@twinsearth/agent-universe",
|
|
9
|
+
"version": "2.5.6",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=18"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
package/js/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@twinsearth/agent-universe",
|
|
3
|
+
"version": "2.5.6",
|
|
4
|
+
"description": "Agent Universe - 群众化的 AGI 路线,去中心化的智能体共享 & 开源网络。使命:让科技造福全人类!",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "node test/test.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"agi",
|
|
12
|
+
"agent",
|
|
13
|
+
"p2p",
|
|
14
|
+
"decentralized",
|
|
15
|
+
"swarm",
|
|
16
|
+
"dht",
|
|
17
|
+
"mcp",
|
|
18
|
+
"a2a",
|
|
19
|
+
"agent-market"
|
|
20
|
+
],
|
|
21
|
+
"author": "TwinsEarth",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/TwinsEarth/agent-universe.git",
|
|
26
|
+
"directory": "js"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/TwinsEarth/agent-universe#readme",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/TwinsEarth/agent-universe/issues"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"registry": "https://registry.npmjs.org/"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"index.js",
|
|
40
|
+
"index.d.ts",
|
|
41
|
+
"lib"
|
|
42
|
+
]
|
|
43
|
+
}
|