MSG Chain Agent 注册与发现机制指南 — 构建去中心化 AI Agent 服务网格
链 ID:
msg-chain-1| 共识: DAR | 虚拟机: CosmWasm (WasmVM)
状态: 规划文档 — 主网裁决为 No-Go,所有数据均为主网预演
Gas: 1,000,000,000 attoMSG/gas
Gas 分配: 40% 验证者 / 30% 开发者 / 20% 燃烧 / 10% 基金会金库
地址格式: SHA3-512(前40位) + SHA-256 校验 | 签名: Dilithium-5 (公钥2592字节 / 私钥4864字节 / 签名4595字节)
AI Agent安全边界: 永不自主创建新合约,永不自主调整 Gas 参数,永不自主铸造/销毁代币
目录
1. 概述
1.1 Registry — Agent 生态系统的"电话簿"
在 MSG Chain 的 AI Agent 经济体中,agent_registry_v1 合约充当所有 AI Agent 的中心化去中心化注册表。它类似于一个去中心化的"电话簿":每个 Agent 在此声明自己的身份、能力、服务端点、定价模型和声誉信息。其他 Agent、人类用户或去中心化应用(dApp)通过查询 Registry 发现合适的服务提供者。
Registry 的核心职责:
| 功能 | 描述 | 状态 |
|---|---|---|
| Agent 注册 | Agent 在链上注册自己的基本信息 | 已实现 |
| 能力声明 | Agent 声明自身提供的能力(如 LLM 推理、图像生成等) | 已实现 |
| 端点登记 | Agent 登记自己的服务端点(URL、协议等) | 已实现 |
| 发现查询 | 按能力、价格、声誉等条件搜索 Agent | 已实现 |
| 声誉跟踪 | Agent 链上声誉的累计和衰减 | 部分实现 |
| 事件推送 | Registry 状态变更的链上事件和 WebSocket 推送 | 已实现 |
| 写操作 API | 通过 Agent API 进行注册/更新/注销 | Stub |
1.2 发现模式:Pull vs Push
MSG Chain Registry 支持两种发现模式:
Pull 模式(主动查询)
调用方主动向 Registry 合约发起查询:
调用方 → 查询 Registry 合约 → 返回匹配的 Agent 列表 → 调用方选择并连接
适用于:
- 一次性服务发现
- 批量 Agent 筛选
- 定时刷新 Agent 列表
Push 模式(订阅通知)
调用方通过 WebSocket 订阅 Registry 事件,在 Agent 注册/更新/注销时被动接收通知:
调用方 → 订阅 Registry 事件 → 实时接收 Agent 状态变更 → 自动更新本地缓存
适用于:
- 实时监控 Agent 生态
- 自动负载均衡
- 服务网格动态更新
1.3 合约全景
┌──────────────────┐
│ Agent A (服务) │
│ DID + Registry │
└────────┬─────────┘
│
┌───────────────┼───────────────┐
│ │ │
┌───────▼───────┐ ┌────▼────┐ ┌────────▼──────┐
│ agent_registry │ │ aidid_ │ │ agent_a2a_v1 │
│ _v1 │ │ did_ │ │ (A2A 通信) │
│ (注册/发现) │ │ registry│ │ │
└───────┬───────┘ └────┬────┘ └────────┬──────┘
│ │ │
└───────────────┼───────────────┘
│
┌────────▼────────┐
│ MSG Chain │
│ (共识层 / DAR) │
└─────────────────┘
1.4 与 DNS 的类比
| DNS 概念 | Registry 对应 |
|---|---|
| 域名注册局 | agent_registry_v1 合约 |
| 域名(example.com) | agent_id (did:msg:agent:{name}) |
| A 记录 / CNAME | endpoints (服务端点) |
| MX 记录 | capabilities (能力声明) |
| DNSSEC | DID + Dilithium-5 签名验证 |
| DNS 查询 | discover_agents / get_agent |
1.5 相关合约
| 合约 | Code ID | 与 Registry 的关系 |
|---|---|---|
aidid_did_registry_v1 |
29 | 提供 Agent 去中心化身份,Registry 注册前需先创建 DID |
agent_a2a_v1 |
19 | 通过 Registry 发现后进行 A2A 通信 |
ai_agent_constitution_v1 |
30 | Registry 中的 Agent 需遵守宪法约束 |
genesis_registry_v1 |
2 | 解析各合约的 canonical 地址 |
agent_payment_v1 |
13 | Registry 中的 Agent 通过 AIPAY 结算服务费用 |
1.6 链参数参考
| 参数 | 值 |
|---|---|
| Chain ID | msg-chain-1 |
| Bech32 前缀 | msg |
| 代币符号 | MSG |
| 最小单位 | umsg (1 MSG = 10^18 umsg) |
| 出块时间 | ~5 秒 |
| 共识算法 | Round-Robin + DAR |
| 签名方案 | Dilithium-5 (后量子密码学) |
| Gas 价格 | 1,000,000,000 attoMSG/gas(flat rate,1 MSG = 10^18 attoMSG) |
2. 注册表数据结构
2.1 Agent Record 完整 Schema
agent_registry_v1 合约中存储的 Agent 记录包含以下字段:
interface AgentRecord {
id: string;
name: string;
version: string;
owner: string;
capabilities: Capability[];
endpoints: Endpoint[];
constitution_hash: string;
reputation: Reputation;
status: "active" | "suspended" | "retired";
price_model?: PriceModel;
metadata: Record<string, string>;
registered_at: number;
updated_at: number;
}
2.2 能力声明格式
interface Capability {
id: string;
name: string;
version: string;
description: string;
requires_attestation: boolean;
parameters?: Record<string, string>;
composite_expression?: string;
}
2.3 端点定义
interface Endpoint {
id: string;
url: string;
protocol: "http" | "https" | "grpc" | "ws" | "wss" | "libp2p";
auth_type: "none" | "api_key" | "dilithium5" | "oauth2" | "did_auth";
weight: number;
status: "active" | "degraded" | "offline";
region?: string;
max_concurrency?: number;
metadata?: Record<string, string>;
}
2.4 定价模型
interface PriceModel {
price_type: "fixed" | "per_task" | "per_token" | "per_second" | "subscription" | "free";
price: string;
currency: string;
per_token_price?: string;
free_quota?: { count: number; period: string };
}
2.5 声誉结构
interface Reputation {
score: number;
onchain_score: number;
offchain_score: number;
verified_score: number;
total_transactions: number;
successful_transactions: number;
failed_transactions: number;
last_updated: number;
}
2.6 Rust 合约状态定义
use cosmwasm_std::{Addr, Timestamp};
use cw_storage_plus::{Item, Map};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct AgentInfo {
pub agent_id: String,
pub name: String,
pub owner: Addr,
pub capabilities: Vec<String>,
pub endpoint: String,
pub price_model: Option<PriceModel>,
pub reputation: f64,
pub status: String,
pub registered_height: u64,
pub updated_at: Timestamp,
pub tx_hash: Option<String>,
pub module: String,
pub source: String,
pub boundary: AgentBoundary,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct PriceModel {
pub price_type: String,
pub price: u64,
pub currency: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct AgentBoundary {
pub application_state_owned_by_contract: bool,
pub discovery_index_onchain: bool,
pub endpoint_is_reference_only: bool,
pub node_executes_llm: bool,
pub node_native_state_compatibility_only: bool,
pub natural_language_in_consensus: bool,
pub stores_prompt_or_payload: bool,
pub duplicate_agent_fail_closed: bool,
}
pub const AGENTS: Map<&str, AgentInfo> = Map::new("agents");
pub const CAPABILITY_INDEX: Map<&str, Vec<String>> = Map::new("cap_index");
pub const ADMIN: Item<Addr> = Item::new("admin");
pub const AGENT_COUNT: Item<u64> = Item::new("agent_count");
2.7 Go 节点层状态定义
package quantum
import (
"sync"
"time"
)
type AgentInfo struct {
AgentID string `json:"agent_id"`
Name string `json:"name"`
Owner string `json:"owner"`
Capabilities []string `json:"capabilities"`
PriceModel PriceModel `json:"price_model"`
Endpoint string `json:"endpoint"`
Reputation float64 `json:"reputation"`
CreatedAt time.Time `json:"created_at"`
}
type PriceModel struct {
Type string `json:"type"`
Price uint64 `json:"price"`
Currency string `json:"currency"`
}
type AgentRegistry struct {
agents map[string]*AgentInfo
mu sync.RWMutex
}
func NewAgentRegistry() *AgentRegistry {
return &AgentRegistry{
agents: make(map[string]*AgentInfo),
}
}
func (ar *AgentRegistry) Register(agent *AgentInfo) error {
ar.mu.Lock()
defer ar.mu.Unlock()
agent.CreatedAt = time.Now()
agent.Reputation = 5.0
ar.agents[agent.AgentID] = agent
return nil
}
func (ar *AgentRegistry) Discover(capability string, maxPrice uint64) []*AgentInfo {
ar.mu.RLock()
defer ar.mu.RUnlock()
results := make([]*AgentInfo, 0)
for _, agent := range ar.agents {
if hasCapability(agent.Capabilities, capability) && agent.PriceModel.Price <= maxPrice {
results = append(results, agent)
}
}
return results
}
2.8 边界标记
| 标记 | 含义 |
|---|---|
application_state_owned_by_contract |
应用状态由合约拥有 |
discovery_index_onchain |
发现索引在链上 |
endpoint_is_reference_only |
端点仅作为参考 |
node_executes_llm |
节点本地执行 LLM 推理 |
node_native_state_compatibility_only |
仅兼容节点原生状态 |
natural_language_in_consensus |
自然语言参与共识 |
stores_prompt_or_payload |
存储提示词或负载 |
duplicate_agent_fail_closed |
重复 Agent 默认关闭 |
3. Agent 注册流程
3.1 注册前提条件
3.1.1 创建 MSG Chain 钱包
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
async function createAgentWallet(): Promise<{ mnemonic: string; address: string }> {
const wallet = await DirectSecp256k1HdWallet.generate(24, { prefix: "msg" });
const [account] = await wallet.getAccounts();
console.log("Agent Wallet created:");
console.log(` Address: ${account.address}`);
return { mnemonic: wallet.mnemonic, address: account.address };
}
from cosmoslib import Wallet
def create_agent_wallet() -> tuple[str, str]:
wallet = Wallet.generate(prefix="msg")
address = wallet.address
print(f"Agent Wallet created: {address}")
return wallet.mnemonic, address
3.1.2 给钱包充值
./build/msgd tx bank send \
--from=funder-wallet \
--chain-id=msg-chain-1 \
--gas=auto \
--gas-prices=1000000000000000000attoMSG \
msg1agentaddress... \
1000000000000000000umsg
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { coins } from "@cosmjs/proto-signing";
async function fundAgentWallet(
signingClient: SigningCosmWasmClient,
funderAddress: string,
agentAddress: string,
amount: string = "1000000000000000000"
) {
const result = await signingClient.sendTokens(
funderAddress, agentAddress, coins(amount, "umsg"), "auto"
);
console.log(`Funded: ${result.transactionHash}`);
return result;
}
3.1.3 注册 DID 身份
每个 Agent 必须先在 aidid_did_registry_v1 中注册 DID:
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
const DID_CONTRACT = "msg1...aididRegistryAddress";
async function registerAgentDid(
signingClient: SigningCosmWasmClient,
senderAddress: string,
agentName: string,
publicKeyMultibase: string
) {
const did = `did:msg:agent:${agentName}`;
const vmId = `${did}#keys-1`;
const result = await signingClient.execute(senderAddress, DID_CONTRACT, {
register_did: {
did,
document: {
context: ["https://www.w3.org/ns/did/v1"],
id: did,
verificationMethod: [{
id: vmId,
controller: did,
type_: "Dilithium5VerificationKey2026",
publicKeyMultibase,
}],
authentication: [vmId],
service: [{
id: `${did}#agent-endpoint`,
type_: "AgentService",
serviceEndpoint: "https://agent.example.com/api",
}],
},
verification_method_id: vmId,
signature: "dilithium5-signature",
},
}, "auto");
console.log(`DID registered: ${did}`);
return did;
}
async def register_agent_did(client, sender, agent_name, public_key):
did = f"did:msg:agent:{agent_name}"
vm_id = f"{did}#keys-1"
result = await client.execute(sender, DID_CONTRACT, {
"register_did": {
"did": did,
"document": {
"context": ["https://www.w3.org/ns/did/v1"],
"id": did,
"verificationMethod": [{
"id": vm_id, "controller": did,
"type_": "Dilithium5VerificationKey2026",
"publicKeyMultibase": public_key,
}],
"authentication": [vm_id],
},
"verification_method_id": vm_id,
"signature": "dilithium5-sig",
},
}, "auto")
print(f"DID registered: {did}")
return did
3.1.4 解析 Registry 合约地址
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
const GENESIS_REGISTRY = "msg1...genesisRegistryAddress";
async function resolveRegistryAddress(client: CosmWasmClient): Promise<string> {
try {
const result: any = await client.queryContractSmart(GENESIS_REGISTRY, {
resolve_canonical: { key: "agent_registry_v1" },
});
return result.address;
} catch {
const knownAddress = "msg14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmal";
console.log(`Using known address: ${knownAddress}`);
return knownAddress;
}
}
3.2 注册 Agent
3.2.1 通过合约执行注册
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import { GasPrice } from "@cosmjs/stargate";
const REGISTRY_ADDRESS = "msg1...agentRegistryAddress";
const RPC_ENDPOINT = "http://localhost:26657";
interface RegisterAgentOptions {
agentId: string;
name: string;
owner: string;
capabilities: string[];
endpoint: string;
price: string;
priceType?: string;
naturalLanguage?: string;
nodeExecutesLlm?: boolean;
consensusLlmParse?: boolean;
}
async function registerAgent(mnemonic: string, options: RegisterAgentOptions) {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: "msg" });
const [account] = await wallet.getAccounts();
const signingClient = await SigningCosmWasmClient.connectWithSigner(
RPC_ENDPOINT, wallet,
{ gasPrice: GasPrice.fromString("1000000000000000000attoMSG") }
);
const result = await signingClient.execute(account.address, REGISTRY_ADDRESS, {
register_agent: {
agent_id: options.agentId,
name: options.name,
owner: options.owner,
capabilities: options.capabilities,
endpoint: options.endpoint,
price_model: {
price_type: options.priceType || "per_task",
price: options.price,
currency: "umsg",
},
natural_language: options.naturalLanguage,
node_executes_llm: options.nodeExecutesLlm || false,
consensus_llm_parse: options.consensusLlmParse || false,
},
}, "auto");
console.log(`✅ Agent registered: ${options.agentId}`);
console.log(` TX: ${result.transactionHash}`);
return result;
}
// 使用示例
async function exampleRegister() {
await registerAgent("your mnemonic here", {
agentId: "my-llm-assistant",
name: "LLM Assistant v1",
owner: "msg1qypqxpq9kcrn2c9afea5lq35ef37c5x7jqylz3",
capabilities: ["ai:llm:inference", "ai:embedding:text"],
endpoint: "https://llm-agent.example.com/api/v1",
price: "50000",
naturalLanguage: "AI 助手,提供文本生成和语音识别服务",
});
}
import asyncio
from cosmoslient import SigningCosmWasmClient, Wallet
REGISTRY_ADDRESS = "msg1...agentRegistryAddress"
RPC_ENDPOINT = "http://localhost:26657"
async def register_agent(mnemonic, agent_id, name, owner, capabilities, endpoint, price):
wallet = Wallet.from_mnemonic(mnemonic, prefix="msg")
account = wallet.get_account()
client = await SigningCosmWasmClient.connect_with_signer(RPC_ENDPOINT, wallet)
result = await client.execute(account.address, REGISTRY_ADDRESS, {
"register_agent": {
"agent_id": agent_id,
"name": name,
"owner": owner,
"capabilities": capabilities,
"endpoint": endpoint,
"price_model": {
"price_type": "per_task",
"price": price,
"currency": "umsg",
},
},
}, "auto")
print(f"✅ Agent registered: {agent_id}")
return result
asyncio.run(register_agent(
"mnemonic here",
agent_id="my-llm-assistant",
name="LLM Assistant v1",
owner="msg1qypqxpq9kcrn2c9afea5lq35ef37c5x7jqylz3",
capabilities=["ai:llm:inference", "ai:embedding:text"],
endpoint="https://llm-agent.example.com/api/v1",
price="50000",
))
3.2.2 通过 Agent API 注册
⚠️ Stub 边界:
/agent/v1/registry/register端点当前为 Stub 实现。
const AGENT_API_BASE = "http://localhost:8080";
const API_KEY = "your-api-key";
async function registerAgentViaApi(request: any) {
const response = await fetch(`${AGENT_API_BASE}/agent/v1/registry/register`, {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": API_KEY },
body: JSON.stringify(request),
});
const isStub = response.headers.get("X-MSG-Stub") === "true";
if (isStub) console.warn("⚠️ Registry register is STUB");
return { ...await response.json(), stub: isStub };
}
3.3 更新注册信息
async function updateAgentRegistration(
signingClient: SigningCosmWasmClient,
senderAddress: string,
agentId: string,
updates: {
name?: string;
capabilities?: string[];
endpoint?: string;
price?: string;
status?: "active" | "suspended" | "retired";
}
) {
const updateMsg: any = { update_agent: { agent_id: agentId } };
if (updates.name !== undefined) updateMsg.update_agent.name = updates.name;
if (updates.capabilities !== undefined) updateMsg.update_agent.capabilities = updates.capabilities;
if (updates.endpoint !== undefined) updateMsg.update_agent.endpoint = updates.endpoint;
if (updates.price !== undefined) {
updateMsg.update_agent.price_model = {
price_type: "per_task", price: updates.price, currency: "umsg",
};
}
if (updates.status !== undefined) updateMsg.update_agent.status = updates.status;
const result = await signingClient.execute(senderAddress, REGISTRY_ADDRESS, updateMsg, "auto");
console.log(`✅ Agent ${agentId} updated: ${result.transactionHash}`);
return result;
}
// 添加新能力
async function addCapability(
signingClient: SigningCosmWasmClient,
senderAddress: string,
agentId: string,
newCapability: string
) {
const client = await CosmWasmClient.connect(RPC_ENDPOINT);
const agent: any = await client.queryContractSmart(REGISTRY_ADDRESS, {
get_agent: { agent_id: agentId },
});
const currentCaps = agent.agent.capabilities || [];
if (currentCaps.includes(newCapability)) return;
return updateAgentRegistration(signingClient, senderAddress, agentId, {
capabilities: [...currentCaps, newCapability],
});
}
3.4 版本升级
async function upgradeAgentVersion(
signingClient: SigningCosmWasmClient,
senderAddress: string,
agentId: string,
newVersion: string,
changelog?: string
) {
const result = await signingClient.execute(senderAddress, REGISTRY_ADDRESS, {
update_agent: {
agent_id: agentId,
version: newVersion,
metadata: changelog
? { changelog, updated_at: String(Math.floor(Date.now() / 1000)) }
: undefined,
},
}, "auto");
console.log(`✅ Agent ${agentId} upgraded to v${newVersion}`);
return result;
}
语义化版本约定:
| 版本变更 | 含义 | Registry 行为 |
|---|---|---|
1.0.0 → 1.0.1 |
补丁(bug 修复) | 自动更新,兼容性不变 |
1.0.0 → 1.1.0 |
次要(新增能力) | 能力列表可能变化 |
1.0.0 → 2.0.0 |
主要(不兼容变更) | 端点或协议可能变更 |
3.5 注销 Agent (优雅关闭)
async function deregisterAgent(
signingClient: SigningCosmWasmClient,
senderAddress: string,
agentId: string,
reason?: string
) {
// 1. 先将状态设为 retired
await signingClient.execute(senderAddress, REGISTRY_ADDRESS, {
update_agent: {
agent_id: agentId,
status: "retired",
metadata: reason ? { retire_reason: reason } : undefined,
},
}, "auto");
console.log(`✅ Agent ${agentId} marked as retired`);
// 2. 最终注销
const result = await signingClient.execute(senderAddress, REGISTRY_ADDRESS, {
deregister_agent: { agent_id: agentId },
}, "auto");
console.log(`✅ Agent ${agentId} fully deregistered`);
return result;
}
3.6 完整注册工作流
async function fullRegistrationFlow() {
const mnemonic = "your test mnemonic here";
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: "msg" });
const [account] = await wallet.getAccounts();
const signingClient = await SigningCosmWasmClient.connectWithSigner("http://localhost:26657", wallet);
const readClient = await CosmWasmClient.connect("http://localhost:26657");
const registryAddr = "msg1...agentRegistryAddress";
const didAddr = "msg1...aididRegistryAddress";
const constitutionAddr = "msg1...constitutionAddress";
// 3. 注册 DID
const did = "did:msg:agent:full-flow-test-001";
try {
await readClient.queryContractSmart(didAddr, { resolve_did: { did } });
} catch {
await signingClient.execute(account.address, didAddr, {
register_did: {
did, document: {
context: ["https://www.w3.org/ns/did/v1"],
id: did,
verificationMethod: [{
id: `${did}#keys-1`, controller: did,
type_: "Dilithium5VerificationKey2026",
publicKeyMultibase: "z6Mk...public-key...",
}],
authentication: [`${did}#keys-1`],
},
verification_method_id: `${did}#keys-1`,
signature: "dilithium5-sig",
},
}, "auto");
console.log("✅ DID registered");
}
// 4. 承认宪章
await signingClient.execute(account.address, constitutionAddr, {
acknowledge_constitution: {
agent_id: "full-flow-test-001", aidid: did,
constitution_version: "v1", constitution_hash: "abc123def456",
},
}, "auto");
console.log("✅ Constitution acknowledged");
// 5. 注册到 Agent Registry
const regResult = await signingClient.execute(account.address, registryAddr, {
register_agent: {
agent_id: "full-flow-test-001",
name: "Full Flow Test Agent",
owner: account.address,
capabilities: ["ai:llm:inference", "data:storage:ipfs"],
endpoint: "https://test-agent.example.com/api",
price_model: { price_type: "per_task", price: "10000", currency: "umsg" },
},
}, "auto");
console.log(`✅ Agent registered: ${regResult.transactionHash}`);
// 6. 验证注册
const agent = await readClient.queryContractSmart(registryAddr, {
get_agent: { agent_id: "full-flow-test-001" },
});
console.log("Agent record:", JSON.stringify(agent, null, 2));
console.log("🎉 Full registration workflow completed!");
}
4. Agent 发现与查询
4.1 通过 Agent ID 查询
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
const RPC_URL = "http://localhost:26657";
async function getAgentById(agentId: string): Promise<AgentRecord> {
const client = await CosmWasmClient.connect(RPC_URL);
const result = await client.queryContractSmart(
REGISTRY_ADDRESS, { get_agent: { agent_id: agentId } }
);
return result.agent;
}
// 通过 Agent API
async function getAgentViaApi(agentId: string): Promise<AgentRecord> {
const response = await fetch(
`http://localhost:8080/agent/v1/registry/agent/${agentId}`
);
if (!response.ok) throw new Error(`API error: ${response.status}`);
return response.json();
}
async function exampleQueryById() {
const agent = await getAgentById("my-llm-assistant");
console.log("=== Agent Details ===");
console.log(`ID: ${agent.id}`);
console.log(`Name: ${agent.name}`);
console.log(`Owner: ${agent.owner}`);
console.log(`Status: ${agent.status}`);
console.log(`Version: ${agent.version}`);
console.log(`Endpoint: ${agent.endpoints?.[0]?.url}`);
console.log(`Price: ${agent.price_model?.price} ${agent.price_model?.currency}`);
console.log(`Reputation: ${agent.reputation.score}/100`);
}
async def get_agent_by_id(agent_id: str) -> dict:
client = await CosmWasmClient.connect(RPC_URL)
result = await client.query_contract_smart(REGISTRY_ADDRESS, {"get_agent": {"agent_id": agent_id}})
return result["agent"]
async def get_agent_via_api(agent_id: str) -> dict:
async with httpx.AsyncClient() as http:
response = await http.get(f"http://localhost:8080/agent/v1/registry/agent/{agent_id}")
return response.json()
4.2 按能力搜索
interface SearchCapabilityOptions {
capability: string;
limit?: number;
offset?: number;
maxPrice?: number;
minReputation?: number;
region?: string;
sortBy?: "reputation" | "price" | "registered_at";
sortOrder?: "asc" | "desc";
}
interface SearchResult {
agents: AgentRecord[];
total: number;
limit: number;
offset: number;
}
async function searchByCapability(options: SearchCapabilityOptions): Promise<SearchResult> {
const client = await CosmWasmClient.connect(RPC_URL);
const queryMsg: any = {
discover_agents: { capability: options.capability, limit: options.limit || 20 },
};
if (options.maxPrice !== undefined) {
queryMsg.discover_agents.max_price = options.maxPrice;
}
const result = await client.queryContractSmart(REGISTRY_ADDRESS, queryMsg);
return {
agents: result.agents,
total: result.count,
limit: options.limit || 20,
offset: options.offset || 0,
};
}
// 通过 Agent API
async function searchByCapabilityViaApi(
capability: string, options?: { limit?: number; offset?: number }
): Promise<SearchResult> {
const params = new URLSearchParams({
capability, limit: String(options?.limit || 20), offset: String(options?.offset || 0),
});
const response = await fetch(`http://localhost:8080/agent/v1/registry/search?${params}`);
if (!response.ok) throw new Error(`Search failed: ${response.status}`);
return response.json();
}
async function exampleSearch() {
const result = await searchByCapability({
capability: "ai:llm:inference", limit: 10, maxPrice: 100_000, minReputation: 50,
});
console.log(`Found ${result.total} agents with ai:llm:inference:`);
result.agents.forEach((agent, i) => {
console.log(`${i + 1}. ${agent.name} — Price: ${agent.price_model?.price} — Rep: ${agent.reputation.score}/100`);
});
}
async def search_by_capability(capability: str, limit: int = 20, max_price: int | None = None) -> dict:
client = await CosmWasmClient.connect(RPC_URL)
query = {"discover_agents": {"capability": capability, "limit": limit}}
if max_price is not None:
query["discover_agents"]["max_price"] = max_price
return await client.query_contract_smart(REGISTRY_ADDRESS, query)
async def search_via_api(capability: str, limit: int = 20, offset: int = 0) -> dict:
async with httpx.AsyncClient() as http:
response = await http.get(
"http://localhost:8080/agent/v1/registry/search",
params={"capability": capability, "limit": str(limit), "offset": str(offset)},
)
return response.json()
curl 示例
curl -s "http://localhost:8080/agent/v1/registry/search?capability=ai:llm:inference&limit=5" | jq '.'
curl -s "http://localhost:8080/agent/v1/registry/search?capability=ai:image:generation&max_price=100000" | jq '.'
QUERY=$(echo -n '{"discover_agents":{"capability":"ai:llm:inference","limit":5}}' | base64 -w0)
curl -s "http://localhost:1317/cosmwasm/wasm/v1/contract/msg1...agentRegistryAddress/smart/$QUERY" | jq '.'
4.3 分页查询
async function paginatedSearch(options: {
capability?: string; limit: number; offset: number;
}): Promise<SearchResult & { hasMore: boolean }> {
const client = await CosmWasmClient.connect(RPC_URL);
const queryMsg: any = { discover_agents: { limit: options.limit } };
if (options.capability) queryMsg.discover_agents.capability = options.capability;
const result = await client.queryContractSmart(REGISTRY_ADDRESS, queryMsg);
return {
agents: result.agents, total: result.count,
limit: options.limit, offset: options.offset,
hasMore: options.offset + options.limit < result.count,
};
}
// 分页迭代器
async function* iterateAllAgents(capability?: string, pageSize: number = 20): AsyncGenerator<AgentRecord> {
let offset = 0;
let hasMore = true;
while (hasMore) {
const page = await paginatedSearch({ capability, limit: pageSize, offset });
for (const agent of page.agents) yield agent;
hasMore = page.hasMore ?? (page.agents.length === pageSize);
offset += pageSize;
}
}
async function examplePagination() {
for await (const agent of iterateAllAgents(undefined, 10)) {
if (agent.status === "active") {
console.log(` ${agent.id} — ${agent.name}`);
}
}
}
4.4 按地理区域搜索
async function searchByRegion(region: string, capability?: string): Promise<AgentRecord[]> {
const client = await CosmWasmClient.connect(RPC_URL);
const result = await client.queryContractSmart(REGISTRY_ADDRESS, {
discover_agents: { capability: capability || undefined, limit: 100 },
});
return result.agents.filter((agent: any) => {
const endpoints = agent.endpoints || [];
return endpoints.some((ep: any) => ep.region === region);
});
}
async function exampleRegionSearch() {
const agents = await searchByRegion("us-east-1", "ai:llm:inference");
console.log(`Found ${agents.length} LLM agents in us-east-1:`);
agents.forEach(a => {
const ep = a.endpoints.find(ep => ep.region === "us-east-1");
console.log(` ${a.name} — ${ep?.url}`);
});
}
4.5 按声誉阈值过滤
async function searchByReputationThreshold(minScore: number, capability?: string): Promise<AgentRecord[]> {
const client = await CosmWasmClient.connect(RPC_URL);
const result = await client.queryContractSmart(REGISTRY_ADDRESS, {
discover_agents: { capability: capability || undefined, limit: 100 },
});
return result.agents
.filter((a: any) => (a.reputation?.score || 0) >= minScore)
.sort((a: any, b: any) => (b.reputation?.score || 0) - (a.reputation?.score || 0));
}
async function exampleReputationSearch() {
const topAgents = await searchByReputationThreshold(80, "ai:llm:inference");
console.log("🎯 Top-rated LLM agents (reputation >= 80):");
topAgents.forEach((a, i) => {
console.log(` ${i + 1}. ${a.name} — Score: ${a.reputation.score}/100`);
});
}
4.6 全文搜索 Agent 元数据
async function fulltextAgentSearch(
query: string, fields: string[] = ["name", "metadata.description"], limit: number = 20
): Promise<AgentRecord[]> {
const client = await CosmWasmClient.connect(RPC_URL);
const result = await client.queryContractSmart(REGISTRY_ADDRESS, { list_agents: { limit: 500 } });
const agents = result.agents || [];
const queryLower = query.toLowerCase();
return agents.filter((agent: any) => {
return fields.some(field => {
const value = field.split(".").reduce((o, k) => o?.[k], agent);
return value && String(value).toLowerCase().includes(queryLower);
});
}).slice(0, limit);
}
async function exampleFulltextSearch() {
const results = await fulltextAgentSearch("语音识别");
console.log(`Found ${results.length} agents matching "语音识别":`);
results.forEach(a => console.log(` - ${a.name}`));
}
4.7 列出所有 Agent
async function listAllAgents(limit: number = 50): Promise<{ agents: AgentRecord[]; count: number }> {
const client = await CosmWasmClient.connect(RPC_URL);
const result = await client.queryContractSmart(REGISTRY_ADDRESS, { list_agents: { limit } });
return { agents: result.agents, count: result.count };
}
async function exampleListAll() {
const { agents, count } = await listAllAgents(100);
console.log(`📋 Total agents: ${count}`);
const statusCounts: Record<string, number> = {};
agents.forEach(a => { statusCounts[a.status] = (statusCounts[a.status] || 0) + 1; });
Object.entries(statusCounts).forEach(([s, n]) => {
const bar = "█".repeat(Math.round(n / count * 40));
console.log(` ${s.padEnd(10)} ${String(n).padStart(4)} ${bar}`);
});
}
4.8 查询组合示例
interface AgentFinderConfig {
requiredCapabilities: string[];
maxPrice?: number;
minReputation?: number;
preferredRegion?: string;
requireActive: boolean;
}
async function findBestAgent(config: AgentFinderConfig): Promise<AgentRecord | null> {
const client = await CosmWasmClient.connect(RPC_URL);
const result = await client.queryContractSmart(REGISTRY_ADDRESS, {
discover_agents: {
capability: config.requiredCapabilities[0],
limit: 50, max_price: config.maxPrice,
},
});
let candidates = result.agents || [];
// 过滤: 需要所有能力
candidates = candidates.filter((agent: any) => {
const caps = new Set(agent.capabilities?.map((c: any) => c.id || c) || []);
return config.requiredCapabilities.every(c => caps.has(c));
});
// 过滤: 声誉
if (config.minReputation !== undefined) {
candidates = candidates.filter((a: any) => (a.reputation?.score || 0) >= config.minReputation!);
}
// 过滤: 区域
if (config.preferredRegion) {
const regionAgents = candidates.filter((a: any) =>
(a.endpoints || []).some((ep: any) => ep.region === config.preferredRegion)
);
if (regionAgents.length > 0) candidates = regionAgents;
}
// 过滤: 活跃
if (config.requireActive) {
candidates = candidates.filter((a: any) => a.status === "active");
}
candidates.sort((a: any, b: any) => (b.reputation?.score || 0) - (a.reputation?.score || 0));
return candidates[0] || null;
}
async function exampleFindBestAgent() {
const best = await findBestAgent({
requiredCapabilities: ["ai:llm:inference", "data:storage:ipfs"],
maxPrice: 50_000, minReputation: 70, preferredRegion: "ap-southeast-1", requireActive: true,
});
if (best) console.log(`🏆 Best: ${best.name} (rep: ${best.reputation.score}/100)`);
else console.log("No matching agent found");
}
4.9 原生 CosmWasm 查询
CONTRACT="msg14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmal"
# 查询单个 Agent
QUERY=$(echo -n '{"get_agent":{"agent_id":"my-llm-assistant"}}' | base64 -w0)
curl -s "http://localhost:1317/cosmwasm/wasm/v1/contract/$CONTRACT/smart/$QUERY" | jq '.data'
# 按能力搜索
QUERY=$(echo -n '{"discover_agents":{"capability":"ai:llm:inference","limit":10}}' | base64 -w0)
curl -s "http://localhost:1317/cosmwasm/wasm/v1/contract/$CONTRACT/smart/$QUERY" | jq '.data'
# 通过 msgd CLI
./build/msgd query wasm contract-state smart \
$CONTRACT '{"get_agent":{"agent_id":"my-llm-assistant"}}' \
--node http://localhost:26657 -o json | jq '.data'
4.10 响应结构参考
{
"agent": {
"agent_id": "my-llm-assistant",
"name": "LLM Assistant v1",
"owner": "msg1qypqxpq9kcrn2c9afea5lq35ef37c5x7jqylz3",
"capabilities": ["ai:llm:inference", "ai:embedding:text"],
"endpoint": "https://llm-agent.example.com/api/v1",
"price_model": { "price_type": "per_task", "price": 50000, "currency": "umsg" },
"status": "active",
"registered_height": 12345,
"updated_at": 1704067200,
"module": "agent_registry_v1",
"source": "cosmwasm",
"boundary": {
"application_state_owned_by_contract": true,
"discovery_index_onchain": true,
"endpoint_is_reference_only": false,
"node_executes_llm": false,
"duplicate_agent_fail_closed": true
}
}
}
5. 能力声明系统
5.1 能力分类体系
MSG Chain Agent Registry 使用分层分类法对能力进行分类:
{分类}:{子类}:{操作}
| 前缀 | 分类 | 子类 | 操作 | 完整标识符 |
|---|---|---|---|---|
| ai | AI 能力 | llm | inference | ai:llm:inference |
| ai | AI 能力 | llm | fine_tune | ai:llm:fine_tune |
| ai | AI 能力 | embedding | text | ai:embedding:text |
| ai | AI 能力 | embedding | image | ai:embedding:image |
| ai | AI 能力 | image | generation | ai:image:generation |
| ai | AI 能力 | audio | transcription | ai:audio:transcription |
| ai | AI 能力 | audio | synthesis | ai:audio:synthesis |
| ai | AI 能力 | video | generation | ai:video:generation |
| ai | AI 能力 | code | generation | ai:code:generation |
| ai | AI 能力 | code | review | ai:code:review |
| ai | AI 能力 | analysis | data | ai:analysis:data |
| ai | AI 能力 | analysis | sentiment | ai:analysis:sentiment |
| data | 数据服务 | storage | ipfs | data:storage:ipfs |
| data | 数据服务 | storage | arweave | data:storage:arweave |
| data | 数据服务 | indexing | graphql | data:indexing:graphql |
| data | 数据服务 | streaming | kafka | data:streaming:kafka |
| compute | 计算服务 | execution | wasm | compute:execution:wasm |
| compute | 计算服务 | execution | container | compute:execution:container |
| compute | 计算服务 | gpu | rendering | compute:gpu:rendering |
| compute | 计算服务 | tpu | training | compute:tpu:training |
| finance | 金融服务 | payment | send | finance:payment:send |
| finance | 金融服务 | defi | swap | finance:defi:swap |
| finance | 金融服务 | defi | lend | finance:defi:lend |
| oracle | 预言机 | price_feed | crypto | oracle:price_feed:crypto |
| oracle | 预言机 | randomness | vrf | oracle:randomness:vrf |
| security | 安全服务 | audit | code | security:audit:code |
| security | 安全服务 | verification | zk | security:verification:zk |
| network | 网络服务 | relay | ibc | network:relay:ibc |
| agent | Agent 服务 | scheduling | task | agent:scheduling:task |
| agent | Agent 服务 | coordination | consensus | agent:coordination:consensus |
5.2 能力版本管理
interface VersionedCapability {
id: string;
version: string;
min_version?: string;
}
function isCapabilityCompatible(offered: VersionedCapability, required: VersionedCapability): boolean {
const o = offered.version.split(".").map(Number);
const r = required.version.split(".").map(Number);
if (o[0] !== r[0]) return false;
if (o[1] < r[1]) return false;
if (o[2] < r[2]) return false;
return true;
}
5.3 复合能力声明
const COMPOSITE_CAPABILITIES: Record<string, string> = {
"composite:ai:full_llm_stack": "ai:llm:inference AND ai:embedding:text AND data:storage:ipfs",
"composite:data:pipeline": "data:storage:ipfs AND data:indexing:graphql AND data:streaming:kafka",
"composite:payment:any": "finance:payment:send OR finance:defi:swap",
"composite:media:studio": "(ai:image:generation OR ai:video:generation) AND data:storage:ipfs",
};
5.4 在注册时声明能力
async function registerWithCapabilities(
signingClient: SigningCosmWasmClient, senderAddress: string,
agentId: string, capabilities: string[], compositeCapabilities?: string[]
) {
const allCapabilities = [...capabilities, ...(compositeCapabilities || [])];
return signingClient.execute(senderAddress, REGISTRY_ADDRESS, {
register_agent: {
agent_id: agentId,
name: `Agent ${agentId}`,
owner: senderAddress,
capabilities: allCapabilities,
endpoint: "https://agent.example.com/api",
price_model: { price_type: "per_task", price: "50000", currency: "umsg" },
},
}, "auto");
}
await registerWithCapabilities(
signingClient, senderAddress, "media-agent-001",
["ai:image:generation", "ai:audio:transcription", "data:storage:ipfs"],
["composite:media:studio"]
);
5.5 能力发现与匹配
interface CapabilityMatch {
agent: AgentRecord;
matchedCapabilities: string[];
missingCapabilities: string[];
matchScore: number;
}
async function findBestCapabilityMatch(requiredCapabilities: string[]): Promise<CapabilityMatch[]> {
const client = await CosmWasmClient.connect(RPC_URL);
const result = await client.queryContractSmart(REGISTRY_ADDRESS, {
discover_agents: { capability: requiredCapabilities[0], limit: 100 },
});
const matches: CapabilityMatch[] = [];
for (const agent of result.agents) {
const agentCaps = new Set(agent.capabilities);
const matched: string[] = [];
const missing: string[] = [];
for (const cap of requiredCapabilities) {
if (agentCaps.has(cap)) {
matched.push(cap);
} else {
missing.push(cap);
}
}
if (matched.length > 0) {
matches.push({
agent, matchedCapabilities: matched, missingCapabilities: missing,
matchScore: matched.length / requiredCapabilities.length,
});
}
}
return matches.sort((a, b) => b.matchScore - a.matchScore);
}
async function exampleCapabilityMatching() {
const matches = await findBestCapabilityMatch(["ai:llm:inference", "data:storage:ipfs"]);
matches.slice(0, 5).forEach((m, i) => {
console.log(`${i + 1}. ${m.agent.name} — Match: ${(m.matchScore * 100).toFixed(0)}%`);
});
}
5.6 能力协商 (A2A 前期)
interface NegotiationRequest {
fromAgent: string;
toAgent: string;
requiredCapabilities: Array<{ id: string; version: string; parameters?: Record<string, string> }>;
proposal: { taskDescription: string; maxPrice: string; duration?: number };
}
interface NegotiationResponse {
accepted: boolean;
matchedCapabilities: string[];
offeredPrice?: string;
alternativeCaps?: string[];
reason?: string;
}
async function negotiateCapabilities(request: NegotiationRequest): Promise<NegotiationResponse> {
const client = await CosmWasmClient.connect(RPC_URL);
const agent: any = await client.queryContractSmart(REGISTRY_ADDRESS, {
get_agent: { agent_id: request.toAgent },
});
const agentCaps = new Set(agent.agent.capabilities);
const matched: string[] = [];
const missing: string[] = [];
for (const cap of request.requiredCapabilities) {
if (agentCaps.has(cap.id)) matched.push(cap.id);
else missing.push(cap.id);
}
if (matched.length === 0) {
return { accepted: false, matchedCapabilities: [], reason: `No capabilities match` };
}
const agentPrice = agent.agent.price_model?.price || "0";
if (BigInt(agentPrice) > BigInt(request.proposal.maxPrice)) {
return { accepted: false, matchedCapabilities: matched, offeredPrice: agentPrice, reason: "Price too high" };
}
return { accepted: true, matchedCapabilities: matched, offeredPrice: agentPrice };
}
5.7 Capability Attestation
interface CapabilityAttestation {
capabilityId: string;
agentId: string;
attestor: string;
attestationType: "benchmark" | "certification" | "community_vote" | "self_declared";
proof: string;
expiresAt: number;
signature: string;
}
async function verifyCapabilityAttestation(client: CosmWasmClient, attestation: CapabilityAttestation): Promise<boolean> {
const verifyResult: any = await client.queryContractSmart("msg1...aididRegistryAddress", {
msg_pq_verify_v1: {
algorithm: "Dilithium5", public_key: "",
signature: attestation.signature,
message: JSON.stringify({
capabilityId: attestation.capabilityId, agentId: attestation.agentId,
attestationType: attestation.attestationType, proof: attestation.proof,
}),
},
});
if (!verifyResult.valid) return false;
if (attestation.expiresAt < Math.floor(Date.now() / 1000)) return false;
return true;
}
6. 声誉系统
6.1 声誉来源
| 来源 | 权重 | 数据源 | 防篡改 |
|---|---|---|---|
| On-chain (链上) | 50% | 交易历史、A2A 通信记录、支付结算 | 链上数据不可篡改 |
| Off-chain (链下) | 30% | 用户评价、服务反馈 | 依赖链下存储 (IPFS/Arweave) |
| Verified (已验证) | 20% | 第三方 attestation、benchmark 认证 | 加密签名验证 |
6.2 声誉分计算
interface ReputationInput {
onchain: {
totalTransactions: number; successfulTransactions: number; failedTransactions: number;
totalVolume: number; avgResponseTime: number; uptimePercent: number; ageDays: number;
};
offchain: { totalRatings: number; averageRating: number; reviewCount: number; positivePercent: number };
verified: { attestationCount: number; weightedScore: number; benchmarkPassed: boolean };
}
function calculateReputation(input: ReputationInput): number {
// 1. On-chain 分数 (0-100)
const onchainScore = (() => {
const successRate = input.onchain.totalTransactions > 0
? input.onchain.successfulTransactions / input.onchain.totalTransactions : 0;
const successScore = successRate * 40;
const volumeScore = Math.min(input.onchain.totalVolume / 1_000_000_000, 20);
const uptimeScore = input.onchain.uptimePercent * 0.2;
const ageScore = Math.min(input.onchain.ageDays / 30 * 5, 20);
return Math.min(successScore + volumeScore + uptimeScore + ageScore, 100);
})();
// 2. Off-chain 分数 (0-100)
const offchainScore = input.offchain.totalRatings > 0
? (input.offchain.averageRating / 5) * 100 : 0;
// 3. Verified 分数 (0-100)
const verifiedScore = (() => {
if (input.verified.attestationCount === 0) return 0;
return Math.min(input.verified.weightedScore + (input.verified.benchmarkPassed ? 10 : 0), 100);
})();
// 4. 加权总分
return Math.round((onchainScore * 0.5 + offchainScore * 0.3 + verifiedScore * 0.2) * 10) / 10;
}
6.3 声誉衰减
function calculateDecayedScore(
currentScore: number, lastActivityDays: number, recentTransactions: number
): number {
const halfLifeDays = 90;
const decayFactor = Math.pow(0.5, lastActivityDays / halfLifeDays);
let decayedScore = currentScore * decayFactor;
const activityBonus = Math.min(recentTransactions * 0.1, 20);
decayedScore += activityBonus;
return Math.max(decayedScore, 10);
}
const score = calculateDecayedScore(85, 30, 5);
console.log(`Decayed: ${score.toFixed(1)}`);
6.4 查询 Agent 声誉
async function getAgentReputation(agentId: string): Promise<{
score: number; breakdown: { onchain: number; offchain: number; verified: number };
stats: { totalTx: number; successRate: number };
}> {
const client = await CosmWasmClient.connect(RPC_URL);
const result: any = await client.queryContractSmart(REGISTRY_ADDRESS, {
get_agent: { agent_id: agentId },
});
const rep = result.agent.reputation || {};
return {
score: rep.score || 0,
breakdown: { onchain: rep.onchain_score || 0, offchain: rep.offchain_score || 0, verified: rep.verified_score || 0 },
stats: { totalTx: rep.total_transactions || 0, successRate: rep.total_transactions > 0 ? rep.successful_transactions / rep.total_transactions * 100 : 0 },
};
}
async function exampleReputationQuery() {
const rep = await getAgentReputation("my-llm-assistant");
console.log(`Overall: ${rep.score}/100`);
console.log(`On-chain: ${rep.breakdown.onchain.toFixed(1)}`);
console.log(`Off-chain: ${rep.breakdown.offchain.toFixed(1)}`);
console.log(`Verified: ${rep.breakdown.verified.toFixed(1)}`);
const tier = rep.score >= 80 ? "🌟 Platinum" : rep.score >= 60 ? "💎 Gold" : rep.score >= 40 ? "🥈 Silver" : "🥉 Bronze";
console.log(`Tier: ${tier}`);
}
6.5 声誉可视化 (React 组件)
import React from "react";
export function ReputationBadge({ score, size = "md" }: { score: number; size?: "sm" | "md" | "lg" }) {
const getColor = (s: number) => s >= 80 ? "bg-purple-500" : s >= 60 ? "bg-blue-500" : s >= 40 ? "bg-green-500" : s >= 20 ? "bg-yellow-500" : "bg-gray-400";
const getLabel = (s: number) => s >= 80 ? "Platinum" : s >= 60 ? "Gold" : s >= 40 ? "Silver" : s >= 20 ? "Bronze" : "Newcomer";
const sizes = { sm: "w-8 h-8 text-xs", md: "w-12 h-12 text-sm", lg: "w-16 h-16 text-lg" };
return (
<div className="flex items-center gap-2">
<div className={`${sizes[size]} ${getColor(score)} rounded-full flex items-center justify-center text-white font-bold`}>
{Math.round(score)}
</div>
<div className="font-semibold">{getLabel(score)}</div>
</div>
);
}
6.6 Sybil 抵抗:质押式声誉
async function stakeForReputation(
signingClient: SigningCosmWasmClient, senderAddress: string, agentId: string,
amount: string, lockDays: number = 30
) {
const lockSeconds = lockDays * 86400;
const result = await signingClient.execute(senderAddress, REGISTRY_ADDRESS, {
stake_reputation: { agent_id: agentId, lock_seconds: lockSeconds },
}, "auto", undefined, [{ denom: "umsg", amount }]);
const weight = lockDays >= 180 ? 3.0 : lockDays >= 90 ? 2.5 : lockDays >= 30 ? 2.0 : lockDays >= 7 ? 1.5 : 1.0;
console.log(`✅ Staked ${amount} umsg for reputation (weight: ${weight}x)`);
return result;
}
7. 注册表事件订阅
7.1 事件类型
| 事件名称 | 触发条件 | 数据字段 |
|---|---|---|
AgentRegistered |
新 Agent 注册成功 | agent_id, owner, capabilities |
AgentUpdated |
Agent 信息更新 | agent_id, changed_fields |
AgentSuspended |
Agent 被暂停 | agent_id, reason |
AgentRetired |
Agent 注销/退休 | agent_id, reason |
ReputationChanged |
声誉分变更 | agent_id, old_score, new_score |
CapabilityAdded |
新增能力 | agent_id, capability |
CapabilityRemoved |
移除能力 | agent_id, capability |
7.2 链上事件监听 (CosmJS)
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
interface RegistryEvent { type: string; attributes: Array<{ key: string; value: string }>; }
async function listenToRegistryEvents(rpcUrl: string, registryAddress: string, onEvent: (event: RegistryEvent) => void) {
const client = await CosmWasmClient.connect(rpcUrl);
client.subscribeTx(`wasm._contract_address='${registryAddress}'`, (tx) => {
for (const event of tx.events || []) {
if (event.type.startsWith("wasm-")) {
onEvent({
type: event.type,
attributes: event.attributes.map(a => ({ key: a.key, value: a.value })),
});
}
}
});
console.log(`Listening for events on ${registryAddress}...`);
}
listenToRegistryEvents("http://localhost:26657", "msg1...agentRegistryAddress", (event) => {
if (event.type === "wasm-AgentRegistered") {
const agentId = event.attributes.find(a => a.key === "agent_id")?.value;
console.log(`🆕 New Agent: ${agentId}`);
}
});
7.3 WebSocket 事件订阅
⚠️ Stub 边界:
/agent/v1/registry/eventsWebSocket 端点当前为 Stub 实现。
import WebSocket from "ws";
interface SubscriptionRequest {
type: "subscribe" | "unsubscribe";
filters: { event_types?: string[]; capabilities?: string[]; agent_ids?: string[]; min_reputation?: number };
}
interface RegistryEventMessage {
type: "registry_event"; event_type: string;
data: { agent_id: string; [key: string]: any };
timestamp: number; block_height: number;
}
class RegistryEventSubscriber {
private ws: WebSocket | null = null;
private url: string;
private reconnectAttempts: number = 0;
private maxReconnectAttempts: number = 10;
private reconnectDelay: number = 3000;
private handlers: Map<string, Array<(event: RegistryEventMessage) => void>> = new Map();
private currentFilters: SubscriptionRequest["filters"] = {};
constructor(baseUrl: string = "http://localhost:8080") {
this.url = baseUrl.replace(/^http/, "ws") + "/agent/v1/registry/events";
}
connect(filters: SubscriptionRequest["filters"]) {
this.currentFilters = filters;
try {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
this.reconnectAttempts = 0;
console.log("[WS] Connected");
this.ws!.send(JSON.stringify({ type: "subscribe", filters }));
};
this.ws.onmessage = (event) => {
try { this.dispatch(JSON.parse(event.data.toString())); }
catch (e) { console.error("[WS] Parse error:", e); }
};
this.ws.onclose = () => this.reconnect();
this.ws.onerror = () => this.reconnect();
} catch (e) {
this.reconnect();
}
}
private reconnect() {
this.reconnectAttempts++;
if (this.reconnectAttempts > this.maxReconnectAttempts) return;
const delay = this.reconnectDelay * Math.min(this.reconnectAttempts, 5);
setTimeout(() => this.connect(this.currentFilters), delay);
}
on(eventType: string, handler: (event: RegistryEventMessage) => void) {
if (!this.handlers.has(eventType)) this.handlers.set(eventType, []);
this.handlers.get(eventType)!.push(handler);
}
private dispatch(message: RegistryEventMessage) {
(this.handlers.get(message.event_type) || []).forEach(h => h(message));
(this.handlers.get("*") || []).forEach(h => h(message));
}
disconnect() {
if (this.ws) {
this.ws.send(JSON.stringify({ type: "unsubscribe", filters: {} }));
this.ws.close();
this.ws = null;
}
}
}
// 使用示例
const subscriber = new RegistryEventSubscriber("http://localhost:8080");
subscriber.on("AgentRegistered", (event) => {
console.log(`🆕 New Agent: ${event.data.agent_id}`);
console.log(` Capabilities: ${event.data.capabilities?.join(", ")}`);
});
subscriber.on("ReputationChanged", (event) => {
console.log(`⭐ ${event.data.agent_id}: ${event.data.old_score} → ${event.data.new_score}`);
});
subscriber.on("*", (event) => {
console.log(`[All] ${event.event_type} at block ${event.block_height}`);
});
subscriber.connect({ event_types: ["AgentRegistered", "ReputationChanged"], capabilities: ["ai:llm:inference"] });
7.4 Tendermint WebSocket 原生订阅
import WebSocket from "ws";
async function subscribeTendermintRegistryEvents() {
const ws = new WebSocket("ws://localhost:26657/websocket");
ws.on("open", () => {
ws.send(JSON.stringify({
jsonrpc: "2.0", method: "subscribe", id: 1,
params: { query: "wasm._contract_address='msg1...agentRegistryAddress'" },
}));
});
ws.on("message", (data: string) => {
const msg = JSON.parse(data);
if (msg.result?.data?.value?.TxResult?.result?.events) {
for (const event of msg.result.data.value.TxResult.result.events) {
if (event.type.startsWith("wasm-")) {
const attrs = event.attributes.reduce((a: any, attr: any) => { a[attr.key] = attr.value; return a; }, {});
console.log(`Registry Event: ${event.type}`, attrs);
}
}
}
});
}
7.5 事件驱动的缓存刷新
class RegistryCache {
private cache: Map<string, AgentRecord> = new Map();
private subscriber: RegistryEventSubscriber;
constructor() {
this.subscriber = new RegistryEventSubscriber();
this.subscriber.on("AgentRegistered", (event) => {
this.cache.set(event.data.agent_id, event.data as AgentRecord);
});
this.subscriber.on("AgentUpdated", (event) => {
const cached = this.cache.get(event.data.agent_id);
if (cached) this.cache.set(event.data.agent_id, { ...cached, ...event.data });
});
this.subscriber.on("AgentRetired", (event) => this.cache.delete(event.data.agent_id));
this.subscriber.on("AgentSuspended", (event) => {
const cached = this.cache.get(event.data.agent_id);
if (cached) cached.status = "suspended";
});
}
start() { this.subscriber.connect({ event_types: ["AgentRegistered", "AgentUpdated", "AgentSuspended", "AgentRetired"] }); }
async getAgent(agentId: string): Promise<AgentRecord | undefined> {
if (!this.cache.has(agentId)) {
try {
const client = await CosmWasmClient.connect(RPC_URL);
const result: any = await client.queryContractSmart(REGISTRY_ADDRESS, { get_agent: { agent_id: agentId } });
this.cache.set(agentId, result.agent);
} catch { return undefined; }
}
return this.cache.get(agentId);
}
getCachedAgentsByCapability(capability: string): AgentRecord[] {
return Array.from(this.cache.values()).filter(a => {
const caps = a.capabilities.map(c => typeof c === "string" ? c : c.id);
return caps.includes(capability) && a.status === "active";
});
}
stop() { this.subscriber.disconnect(); }
}
const cache = new RegistryCache();
cache.start();
const agent = await cache.getAgent("my-llm-assistant");
const llmAgents = cache.getCachedAgentsByCapability("ai:llm:inference");
8. 服务网格与 A2A 集成
8.1 完整通信流程
Registry → Discovery → A2A Connection → Payment → Settlement
┌─────────┐ ┌─────────┐
│ Agent A │ │ Agent B │
│ (调用方) │ │ (服务方) │
└────┬────┘ └────┬────┘
│ │
│ 1. 注册到 Registry│
│ ─────────────────►│
│ │
│ 2. 查询能力匹配 │
│ ─────────────────►│
│ │
│ 3. 获取 Agent 信息 │
│◄───────────────────│
│ │
│ 4. DID 身份验证 │
│◄──────────────────►│
│ │
│ 5. 创建 A2A 通道 │
│ ─────────────────►│
│ │
│ 6. 微支付会话创建 │
│ ─────────────────►│
│ │
│ 7. A2A 消息通信 │
│◄──────────────────►│
│ │
│ 8. 关闭会话/结算 │
│ ─────────────────►│
│ │
8.2 服务网格架构
interface ServiceMeshConfig {
registryAddress: string;
a2aAddress: string;
micropaymentAddress: string;
minReputation: number;
maxPrice: string;
failoverEnabled: boolean;
loadBalanceStrategy: "round_robin" | "lowest_price" | "highest_reputation";
}
class AgentServiceMesh {
private config: ServiceMeshConfig;
private readClient!: CosmWasmClient;
private agentPool: Map<string, AgentRecord[]> = new Map();
private roundRobinIndex: Map<string, number> = new Map();
constructor(config: ServiceMeshConfig) { this.config = config; }
async initialize() {
this.readClient = await CosmWasmClient.connect(RPC_URL);
}
async discoverService(capability: string): Promise<AgentRecord[]> {
const result = await this.readClient.queryContractSmart(this.config.registryAddress, {
discover_agents: { capability, limit: 50 },
});
let agents = (result.agents || []).filter(
(a: any) => a.status === "active" && (a.reputation?.score || 0) >= this.config.minReputation
);
if (this.config.maxPrice !== "0") {
agents = agents.filter((a: any) => BigInt(a.price_model?.price || "0") <= BigInt(this.config.maxPrice));
}
this.agentPool.set(capability, agents);
return agents;
}
async getNextAgent(capability: string): Promise<AgentRecord | null> {
let pool = this.agentPool.get(capability);
if (!pool || pool.length === 0) pool = await this.discoverService(capability);
if (pool.length === 0) return null;
switch (this.config.loadBalanceStrategy) {
case "round_robin": {
const idx = (this.roundRobinIndex.get(capability) || 0) % pool.length;
this.roundRobinIndex.set(capability, idx + 1);
return pool[idx];
}
case "lowest_price":
return pool.reduce((min, a) => BigInt(a.price_model?.price || "0") < BigInt(min.price_model?.price || "0") ? a : min);
case "highest_reputation":
return pool.reduce((best, a) => (a.reputation?.score || 0) > (best.reputation?.score || 0) ? a : best);
}
}
async handleFailover(capability: string, failedAgentId: string): Promise<AgentRecord | null> {
if (!this.config.failoverEnabled) return null;
console.log(`[Mesh] Failover: ${failedAgentId} failed`);
const pool = this.agentPool.get(capability) || [];
this.agentPool.set(capability, pool.filter(a => a.id !== failedAgentId && a.agent_id !== failedAgentId));
if (this.agentPool.get(capability)?.length === 0) await this.discoverService(capability);
return this.getNextAgent(capability);
}
}
8.3 服务发现 + A2A 通信
async function discoverAndCommunicate(agentAMnemonic: string, requiredCapability: string) {
const readClient = await CosmWasmClient.connect("http://localhost:26657");
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(agentAMnemonic, { prefix: "msg" });
const [account] = await wallet.getAccounts();
const signingClient = await SigningCosmWasmClient.connectWithSigner("http://localhost:26657", wallet);
const REGISTRY = "msg1...agentRegistryAddress";
const A2A = "msg1...a2aContractAddress";
// 发现服务
const discovery: any = await readClient.queryContractSmart(REGISTRY, {
discover_agents: { capability: requiredCapability, limit: 5 },
});
if (!discovery.agents?.length) { console.log("No agents found"); return; }
const targetAgent = discovery.agents[0];
console.log(`Selected: ${targetAgent.name} (${targetAgent.agent_id})`);
// 创建 A2A 通道
const channelId = `ch-${Date.now()}`;
await signingClient.execute(account.address, A2A, {
create_channel: {
channel_id: channelId,
participants: [account.address, targetAgent.owner],
channel_type: "direct",
},
}, "auto");
console.log(`Channel created: ${channelId}`);
// 发送 A2A 消息
await signingClient.execute(account.address, A2A, {
send_message: {
msg_id: `msg-${Date.now()}`,
sender: account.address,
receiver: targetAgent.owner,
message_type: "request",
payload: Buffer.from(JSON.stringify({ prompt: "Analyze this data..." })).toString("base64"),
priority: 50, ttl: 3600, channel_id: channelId,
},
}, "auto");
console.log("A2A message sent");
}
8.4 负载均衡策略
class AgentLoadBalancer {
private agents: Map<string, AgentRecord[]> = new Map();
private healthStatus: Map<string, boolean> = new Map();
private currentIndex: Map<string, number> = new Map();
async updatePool(capability: string, agents: AgentRecord[]) {
this.agents.set(capability, agents);
agents.forEach(a => {
const key = a.agent_id || a.id;
if (!this.healthStatus.has(key)) this.healthStatus.set(key, true);
});
}
async selectAgent(capability: string): Promise<AgentRecord | null> {
const pool = (this.agents.get(capability) || []).filter(a => this.healthStatus.get(a.agent_id || a.id) !== false);
if (pool.length === 0) return null;
const strategy = "round_robin";
if (strategy === "round_robin") {
const idx = (this.currentIndex.get(capability) || 0) % pool.length;
this.currentIndex.set(capability, idx + 1);
return pool[idx];
}
return pool[0];
}
async healthCheck(agent: AgentRecord): Promise<boolean> {
const endpoint = agent.endpoints?.[0]?.url || agent.endpoint;
if (!endpoint) return false;
try {
const response = await fetch(`${endpoint}/health`, { signal: AbortSignal.timeout(5000) });
const isHealthy = response.ok;
this.healthStatus.set(agent.agent_id || agent.id, isHealthy);
return isHealthy;
} catch {
this.healthStatus.set(agent.agent_id || agent.id, false);
return false;
}
}
}
8.5 服务网格 Dashboard (React)
import React, { useEffect, useState } from "react";
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
export function ServiceMeshDashboard() {
const [stats, setStats] = useState<any>(null);
useEffect(() => {
(async () => {
const client = await CosmWasmClient.connect("http://localhost:26657");
const result: any = await client.queryContractSmart("msg1...agentRegistryAddress", { list_agents: { limit: 500 } });
const agents = result.agents || [];
const active = agents.filter((a: any) => a.status === "active");
const capCounts: Record<string, number> = {};
agents.forEach((a: any) => (a.capabilities || []).forEach((c: string) => { capCounts[c] = (capCounts[c] || 0) + 1; }));
setStats({
totalAgents: agents.length, activeAgents: active.length,
capabilityCounts: capCounts,
avgReputation: active.reduce((s: number, a: any) => s + (a.reputation?.score || 0), 0) / (active.length || 1),
});
})();
}, []);
if (!stats) return <div>Loading...</div>;
return (
<div className="p-6">
<h2 className="text-2xl font-bold mb-6">🧩 Agent Service Mesh</h2>
<div className="grid grid-cols-3 gap-4 mb-6">
<div className="bg-blue-50 p-4 rounded-lg">
<div className="text-sm text-gray-500">Total</div>
<div className="text-3xl font-bold">{stats.totalAgents}</div>
</div>
<div className="bg-green-50 p-4 rounded-lg">
<div className="text-sm text-gray-500">Active</div>
<div className="text-3xl font-bold text-green-600">{stats.activeAgents}</div>
</div>
<div className="bg-purple-50 p-4 rounded-lg">
<div className="text-sm text-gray-500">Avg Reputation</div>
<div className="text-3xl font-bold">{stats.avgReputation.toFixed(1)}</div>
</div>
</div>
<h3 className="font-semibold mb-3">Capability Distribution</h3>
{Object.entries(stats.capabilityCounts).sort(([, a]: any, [, b]: any) => b - a).slice(0, 10).map(([cap, count]: any) => (
<div key={cap} className="flex items-center gap-3 mb-1">
<span className="w-48 text-sm font-mono truncate">{cap}</span>
<div className="flex-1 bg-gray-100 rounded-full h-4">
<div className="bg-blue-500 h-4 rounded-full" style={{ width: `${(count / stats.totalAgents) * 100}%` }} />
</div>
<span className="text-sm w-12 text-right">{count}</span>
</div>
))}
</div>
);
}
9. 安全考虑
9.1 注册验证
9.1.1 DID 控制权证明
interface RegistrationProof {
did: string; agentId: string; timestamp: number;
signature: string; publicKey: string;
}
async function verifyRegistrationProof(client: CosmWasmClient, proof: RegistrationProof): Promise<boolean> {
const didDoc: any = await client.queryContractSmart("msg1...aididRegistryAddress", {
resolve_did: { did: proof.did },
});
if (!didDoc.document?.verificationMethod?.[0]) return false;
const vm = didDoc.document.verificationMethod[0];
const message = `${proof.did}:${proof.agentId}:${proof.timestamp}`;
const verifyResult: any = await client.queryContractSmart("msg1...aididRegistryAddress", {
msg_pq_verify_v1: {
algorithm: "Dilithium5", public_key: vm.publicKeyMultibase,
signature: proof.signature,
message: Buffer.from(message).toString("base64"),
message_encoding: "base64", public_key_encoding: "multibase", signature_encoding: "base64",
},
});
return verifyResult.valid;
}
9.1.2 防止重复注册
pub fn execute_register_agent(
deps: DepsMut, _env: Env, info: MessageInfo,
agent_id: String, name: String, owner: String,
capabilities: Vec<String>, endpoint: String, price_model: Option<PriceModel>,
) -> Result<Response, ContractError> {
if AGENTS.has(deps.storage, &agent_id) {
return Err(ContractError::AgentAlreadyRegistered { agent_id });
}
let owner_addr = deps.api.addr_validate(&owner)?;
if info.sender != owner_addr {
return Err(ContractError::Unauthorized {});
}
let agent = AgentInfo {
agent_id: agent_id.clone(), name, owner: owner_addr,
capabilities: capabilities.clone(), endpoint, price_model,
reputation: 50.0, status: "active".to_string(),
registered_height: _env.block.height, updated_at: _env.block.time,
tx_hash: None, module: "agent_registry_v1".to_string(),
source: "cosmwasm".to_string(), boundary: AgentBoundary::default(),
};
AGENTS.save(deps.storage, &agent_id, &agent)?;
for cap in &capabilities {
CAPABILITY_INDEX.update(deps.storage, cap, |existing| -> Result<_, ContractError> {
let mut list = existing.unwrap_or_default();
if !list.contains(&agent_id) { list.push(agent_id.clone()); }
Ok(list)
})?;
}
AGENT_COUNT.update(deps.storage, |c| -> Result<_, ContractError> { Ok(c + 1) })?;
Ok(Response::new()
.add_attribute("action", "register_agent")
.add_attribute("agent_id", &agent_id)
.add_attribute("owner", &owner)
.add_attribute("capabilities", capabilities.join(",")))
}
9.2 能力声明验证
interface CapabilityVerification {
capabilityId: string; agentId: string;
verifiedBy: string; verificationType: "benchmark" | "audit" | "self_declared" | "community";
proofHash: string; expiresAt: number; signature: string;
}
async function isCapabilityVerified(
client: CosmWasmClient, agentId: string, capabilityId: string
): Promise<{ verified: boolean; verifications: CapabilityVerification[] }> {
try {
const result: any = await client.queryContractSmart(REGISTRY_ADDRESS, {
get_capability_verification: { agent_id: agentId, capability_id: capabilityId },
});
return result;
} catch { return { verified: false, verifications: [] }; }
}
9.3 Sybil 攻击防御
interface SybilDefenseConfig {
minStakeForRegistration: string;
maxAgentsPerOwner: number;
reputationThreshold: number;
}
const DEFAULT_SYBIL_CONFIG: SybilDefenseConfig = {
minStakeForRegistration: "1000000000000000000", // 1 MSG
maxAgentsPerOwner: 10,
reputationThreshold: 30,
};
async function checkSybilResistance(
client: CosmWasmClient, ownerAddress: string, config = DEFAULT_SYBIL_CONFIG
): Promise<{ passed: boolean; reasons: string[] }> {
const reasons: string[] = [];
const result: any = await client.queryContractSmart(REGISTRY_ADDRESS, { list_agents: { limit: 500 } });
const ownerAgents = (result.agents || []).filter((a: any) => a.owner === ownerAddress && a.status !== "retired");
if (ownerAgents.length >= config.maxAgentsPerOwner) {
reasons.push(`Max agents per owner (${config.maxAgentsPerOwner}) reached`);
}
const balance = await client.getBalance(ownerAddress, "umsg");
if (BigInt(balance.amount) < BigInt(config.minStakeForRegistration)) {
reasons.push(`Insufficient stake. Required: ${config.minStakeForRegistration} umsg`);
}
return { passed: reasons.length === 0, reasons };
}
9.4 Rate Limiting
class RegistryQueryRateLimiter {
private counters: Map<string, { count: number; resetAt: number }> = new Map();
private readonly requestsPerWindow = 100;
private readonly windowMs = 1000;
private readonly burstSize = 150;
checkLimit(key: string): boolean {
const now = Date.now();
const entry = this.counters.get(key);
if (!entry || now > entry.resetAt) {
this.counters.set(key, { count: 1, resetAt: now + this.windowMs });
return true;
}
if (entry.count >= this.burstSize) return false;
if (entry.count >= this.requestsPerWindow) return false;
entry.count++;
return true;
}
getRemainingRequests(key: string): number {
const entry = this.counters.get(key);
return entry ? Math.max(0, this.requestsPerWindow - entry.count) : this.requestsPerWindow;
}
}
9.5 Stub 安全边界
class StubAwareClient {
private readonly STUB_HEADER = "X-MSG-Stub";
async registryRegister(request: any): Promise<{ success: boolean; stub: boolean; message: string }> {
const response = await fetch("http://localhost:8080/agent/v1/registry/register", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": process.env.API_KEY || "" },
body: JSON.stringify(request),
});
const isStub = response.headers.get(this.STUB_HEADER) === "true";
if (isStub) {
console.warn("⚠️ STUB — no on-chain action occurred");
return { success: false, stub: true, message: "Stub endpoint — no real registration" };
}
return { success: response.ok, stub: false, message: "Registration complete" };
}
async assertNotStub(context: string) {
if (process.env.NODE_ENV === "production") {
throw new Error(`FATAL: ${context} is a STUB endpoint`);
}
}
}
9.6 安全清单
| 安全领域 | 风险 | 缓解措施 |
|---|---|---|
| 身份伪造 | 攻击者伪造 Agent 身份 | DID + Dilithium-5 签名验证 |
| 能力欺诈 | Agent 声明不具备的能力 | 可选 attestation / benchmark 验证 |
| Sybil 攻击 | 大量虚假 Agent 注册 | 质押门槛 + 每个地址限制 Agent 数 |
| 注册耗尽 | 大量注册导致 Registry 膨胀 | 注册费 + 存储 Gas 费 |
| 查询滥用 | 频繁查询导致节点压力 | Rate Limiting (100 req/s) |
| Stub 滥用 | 在 Stub 端点上构建生产逻辑 | X-MSG-Stub 检测 + NODE_ENV 检查 |
| 端点劫持 | Agent 端点被篡改 | 端点签名 + 定期验证 |
10. 完整示例
10.1 完整场景:图像生成 Agent 服务
以下示例展示两个 Agent 完整交互:Agent A 提供 LLM 推理,Agent B 提供图像生成。
10.1.1 部署 Agent A (LLM 服务)
async function deployLLMAgent() {
const mnemonic = "[未公开凭证]";
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: "msg" });
const [account] = await wallet.getAccounts();
const signingClient = await SigningCosmWasmClient.connectWithSigner("http://localhost:26657", wallet);
const registryAddr = "msg1...agentRegistryAddress";
const didAddr = "msg1...aididRegistryAddress";
const constitutionAddr = "msg1...constitutionAddress";
// Step 1: 注册 DID
const did = "did:msg:agent:openai-llm-v2";
await signingClient.execute(account.address, didAddr, {
register_did: {
did, document: {
context: ["https://www.w3.org/ns/did/v1"], id: did,
verificationMethod: [{
id: `${did}#keys-1`, controller: did,
type_: "Dilithium5VerificationKey2026",
publicKeyMultibase: "z6Mk...public-key...",
}],
authentication: [`${did}#keys-1`],
service: [{ id: `${did}#llm-service`, type_: "LLMInferenceService", serviceEndpoint: "https://llm.example.com/api/v1" }],
},
verification_method_id: `${did}#keys-1`, signature: "dilithium5-signature",
},
}, "auto");
console.log("✅ DID:", did);
// Step 2: 承认宪章
await signingClient.execute(account.address, constitutionAddr, {
acknowledge_constitution: {
agent_id: "openai-llm-v2", aidid: did,
constitution_version: "v1", constitution_hash: "abc123",
},
}, "auto");
console.log("✅ Constitution acknowledged");
// Step 3: 注册到 Agent Registry
await signingClient.execute(account.address, registryAddr, {
register_agent: {
agent_id: "openai-llm-v2", name: "OpenAI LLM v2",
owner: account.address,
capabilities: ["ai:llm:inference", "ai:embedding:text", "ai:code:generation"],
endpoint: "https://llm.example.com/api/v1",
price_model: { price_type: "per_token", price: "10", currency: "umsg" },
natural_language: "I provide LLM inference and text embedding",
node_executes_llm: true, consensus_llm_parse: false,
},
}, "auto");
console.log("✅ Agent A registered");
return { agentId: "openai-llm-v2", did };
}
10.1.2 部署 Agent B (图像生成)
async function deployImageAgent() {
const mnemonic = "[未公开凭证]";
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: "msg" });
const [account] = await wallet.getAccounts();
const signingClient = await SigningCosmWasmClient.connectWithSigner("http://localhost:26657", wallet);
const registryAddr = "msg1...agentRegistryAddress";
const didAddr = "msg1...aididRegistryAddress";
const did = "did:msg:agent:dreambee-img-v1";
await signingClient.execute(account.address, didAddr, {
register_did: {
did, document: {
context: ["https://www.w3.org/ns/did/v1"], id: did,
verificationMethod: [{ id: `${did}#keys-1`, controller: did, type_: "Dilithium5VerificationKey2026", publicKeyMultibase: "z6Mk...pk..." }],
authentication: [`${did}#keys-1`],
service: [{ id: `${did}#img-gen`, type_: "ImageGenerationService", serviceEndpoint: "https://img.example.com/api/v1" }],
},
verification_method_id: `${did}#keys-1`, signature: "sig",
},
}, "auto");
await signingClient.execute(account.address, registryAddr, {
register_agent: {
agent_id: "dreambee-img-v1", name: "DreamBee Image v1",
owner: account.address,
capabilities: ["ai:image:generation", "composite:media:studio"],
endpoint: "https://img.example.com/api/v1",
price_model: { price_type: "per_task", price: "100000", currency: "umsg" },
},
}, "auto");
console.log("✅ Agent B registered");
return { agentId: "dreambee-img-v1", did };
}
10.1.3 Agent B 发现 Agent A 并发送 A2A 请求
async function dreamBeeDiscoversAndCollaborates() {
const readClient = await CosmWasmClient.connect("http://localhost:26657");
const walletB = await DirectSecp256k1HdWallet.fromMnemonic("image ... seed", { prefix: "msg" });
const [agentB] = await walletB.getAccounts();
const signingClientB = await SigningCosmWasmClient.connectWithSigner("http://localhost:26657", walletB);
const REGISTRY = "msg1...agentRegistryAddress";
const A2A = "msg1...a2aContractAddress";
// Step 1: Agent B 发现能做 LLM 推理的 Agent
console.log("[Step 1] Searching for LLM inference agents...");
const discovery: any = await readClient.queryContractSmart(REGISTRY, {
discover_agents: { capability: "ai:llm:inference", limit: 5 },
});
const llmAgent = discovery.agents?.[0];
if (!llmAgent) { console.log("No LLM agents found"); return; }
console.log(`[Step 2] Found: ${llmAgent.name} (${llmAgent.agent_id})`);
console.log(` Endpoint: ${llmAgent.endpoint}`);
console.log(` Price: ${llmAgent.price_model?.price} umsg`);
// Step 2: Agent B 创建 A2A 通道到 Agent A
const channelId = `dream-llm-${Date.now()}`;
await signingClientB.execute(agentB.address, A2A, {
create_channel: {
channel_id: channelId,
participants: [agentB.address, llmAgent.owner],
channel_type: "direct",
},
}, "auto");
console.log(`[Step 3] A2A channel created: ${channelId}`);
// Step 3: Agent B 发送图像生成请求给 Agent A (LLM 先生成文本描述)
const promptPayload = {
task: "generate_image_prompt",
input: "A futuristic city with flying cars and neon lights",
style: "cyberpunk",
};
await signingClientB.execute(agentB.address, A2A, {
send_message: {
msg_id: `dream-msg-${Date.now()}`,
sender: agentB.address,
receiver: llmAgent.owner,
message_type: "request",
payload: Buffer.from(JSON.stringify(promptPayload)).toString("base64"),
priority: 75, ttl: 300, channel_id: channelId,
},
}, "auto");
console.log(`[Step 4] A2A request sent via channel ${channelId}`);
// Step 4: 等待 Agent A 的响应
const listenForResponse = async () => {
const result: any = await readClient.queryContractSmart(A2A, {
get_messages: { receiver: agentB.address, limit: 5 },
});
const responses = (result.messages || []).filter(
(m: any) => m.reply_to?.startsWith("dream-msg-") && m.status === "Delivered"
);
if (responses.length > 0) {
const response = JSON.parse(Buffer.from(responses[0].payload, "base64").toString());
console.log(`[Step 5] LLM response:`, response);
return response;
}
return null;
};
// 轮询等待(简化)
for (let i = 0; i < 10; i++) {
const resp = await listenForResponse();
if (resp) break;
await new Promise(r => setTimeout(r, 5000));
}
console.log("[Done] Complete flow: Registry → Discovery → A2A → Response");
}
10.2 完整工作流测试脚本
async function fullIntegrationTest() {
console.log("🧪 Starting Agent Registry Integration Test");
console.log("=".repeat(60));
// 1. 创建两个钱包
const walletA = await DirectSecp256k1HdWallet.generate(24, { prefix: "msg" });
const walletB = await DirectSecp256k1HdWallet.generate(24, { prefix: "msg" });
const [addrA] = await walletA.getAccounts();
const [addrB] = await walletB.getAccounts();
const client = await CosmWasmClient.connect("http://localhost:26657");
const signingClientA = await SigningCosmWasmClient.connectWithSigner("http://localhost:26657", walletA);
const signingClientB = await SigningCosmWasmClient.connectWithSigner("http://localhost:26657", walletB);
// 2. 注册 Agent A
const didA = "did:msg:agent:test-agent-a";
await signingClientA.execute(addrA.address, "msg1...registry", {
register_agent: {
agent_id: "test-agent-a", name: "Test Agent A",
owner: addrA.address,
capabilities: ["ai:llm:inference", "composite:ai:full_llm_stack"],
endpoint: "https://test-a.example.com/api",
price_model: { price_type: "per_task", price: "50000", currency: "umsg" },
},
}, "auto");
console.log("✅ Agent A registered");
// 3. 注册 Agent B
await signingClientB.execute(addrB.address, "msg1...registry", {
register_agent: {
agent_id: "test-agent-b", name: "Test Agent B",
owner: addrB.address,
capabilities: ["data:storage:ipfs", "ai:image:generation"],
endpoint: "https://test-b.example.com/api",
price_model: { price_type: "per_task", price: "30000", currency: "umsg" },
},
}, "auto");
console.log("✅ Agent B registered");
// 4. 测试发现
const capResult: any = await client.queryContractSmart("msg1...registry", {
discover_agents: { capability: "ai:llm:inference", limit: 10 },
});
console.log(`\n📋 Discovery results for ai:llm:inference: ${capResult.count} agents`);
capResult.agents.forEach((a: any, i: number) => {
console.log(` ${i + 1}. ${a.name} — status: ${a.status}`);
});
// 5. 测试分页
const page1: any = await client.queryContractSmart("msg1...registry", {
list_agents: { limit: 5 },
});
console.log(`\n📄 List agents page: ${page1.count} total, ${page1.agents.length} returned`);
// 6. 查询单个 Agent
const singleA: any = await client.queryContractSmart("msg1...registry", {
get_agent: { agent_id: "test-agent-a" },
});
console.log(`\n🔍 Single agent query:`);
console.log(` Name: ${singleA.agent?.name}`);
console.log(` Caps: ${singleA.agent?.capabilities?.join(", ")}`);
// 7. 更新 Agent A 的能力
await signingClientA.execute(addrA.address, "msg1...registry", {
update_agent: {
agent_id: "test-agent-a",
capabilities: ["ai:llm:inference", "ai:code:review", "composite:ai:full_llm_stack"],
},
}, "auto");
console.log("\n✅ Agent A capabilities updated");
// 8. 验证更新
const updatedA: any = await client.queryContractSmart("msg1...registry", {
get_agent: { agent_id: "test-agent-a" },
});
console.log(` New caps: ${updatedA.agent?.capabilities?.join(", ")}`);
// 9. 注销 Agent B
await signingClientB.execute(addrB.address, "msg1...registry", {
update_agent: { agent_id: "test-agent-b", status: "retired" },
}, "auto");
console.log("\n✅ Agent B retired");
// 10. 验证注销
const retiredB: any = await client.queryContractSmart("msg1...registry", {
get_agent: { agent_id: "test-agent-b" },
});
console.log(` Status: ${retiredB.agent?.status}`);
console.log("\n" + "=".repeat(60));
console.log("🎉 Integration test completed successfully!");
}
11. 边界与限制
11.1 当前实现状态
| 功能 | 状态 | 备注 |
|---|---|---|
| 链上合约注册 (register_agent) | ✅ 已实现 | 通过 CosmWasm execute |
| 链上合约查询 (get_agent) | ✅ 已实现 | 通过 CosmWasm smart query |
| 链上合约发现 (discover_agents) | ✅ 已实现 | 按能力/价格过滤 |
| 链上合约列表 (list_agents) | ✅ 已实现 | 支持分页 |
| Agent API 查询端点 | ✅ 已实现 | GET /agent/v1/registry/agent/{id} |
| Agent API 搜索端点 | ✅ 已实现 | GET /agent/v1/registry/search |
| Agent API 注册端点 | ⚠️ Stub | POST /agent/v1/registry/register |
| Agent API 事件端点 | ⚠️ Stub | /agent/v1/registry/events (WS) |
| 声誉系统 | ⚠️ 部分实现 | 基本分数存储,复杂计算待完善 |
| Capability Attestation | ⚠️ 部分实现 | 基础验证框架 |
| 复合能力表达式 | ✅ 已实现 | AND/OR 组合支持 |
11.2 已知限制
-
写操作 Stub:Registry 写操作 (POST /agent/v1/registry/register) 当前为 Stub 实现,返回模拟数据。生产环境必须通过合约直接执行。
-
WebSocket Stub:Registry 事件 WebSocket 端点为 Stub,真正的实时推送依赖于 Tendermint WebSocket 原生订阅。
-
声誉系统不完整:链上声誉存储了基本结构,但复杂的声誉计算(时间衰减、多源加权)需在链下或未来合约版本中实现。
-
无跨 Registry 发现:当前只有一个 Registry 合约实例。跨链 Agent 发现需通过 IBC 或中介 Registry 实现。
-
能力验证机制:能力声明目前是 self-declared,缺少强制验证。attestation 框架已定义但未强制启用。
-
存储成本:Agent 注册消耗链上存储。每条 Agent 记录约占用 500-2000 字节,需支付相应的 Gas 费。
11.3 Agent API Stub 检测
// 所有 Stub 端点的响应包含 X-MSG-Stub: true 头
async function isStubEndpoint(response: Response): Promise<boolean> {
return response.headers.get("X-MSG-Stub") === "true";
}
// 检测示例
const response = await fetch("http://localhost:8080/agent/v1/registry/register", {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ agent_id: "test" }),
});
if (await isStubEndpoint(response)) {
console.warn("⚠️ Endpoint is STUB - no real on-chain action");
}
11.4 合约地址获取
// 优先通过 genesis_registry_v1 解析
async function resolveContractAddress(client: CosmWasmClient, key: string): Promise<string> {
const genesisRegistry = "msg1...genesisRegistryAddress";
const result: any = await client.queryContractSmart(genesisRegistry, {
resolve_canonical: { key },
});
return result.address;
}
// agent_registry_v1 可能不在 genesis_registry 中注册
// 需要已知地址或链下发现
// 已知 canonical keys:
// genesis_registry -> genesis_registry_v1
// aidid_did_registry_v1 -> aidid_did_registry_v1
// ai_agent_constitution_v1 -> ai_agent_constitution_v1
// agent_payment_v1 -> 需已知地址或链下发现
// agent_registry_v1 -> 需已知地址或链下发现
11.5 下一步路线图
| 功能 | 预期 | 描述 |
|---|---|---|
| Registry 写操作 API | 未来版本 | POST/PUT/DELETE 端点真实化 |
| 声誉系统 v2 | 未来版本 | 完整的衰减、多源加权、质押 |
| WebSocket 实时推送 | 未来版本 | Registry 事件专用 WS 端点 |
| 跨链 Registry | 长期规划 | 通过 IBC 实现跨链 Agent 发现 |
| Capability Benchmark | 长期规划 | 链上 benchmark 验证能力声明 |
本文档基于 MSG Chain 代码库核实的技术事实。
白皮书系统: https://msgchain.org/whitepaper/
