@openagentmarket/nodejs 1.1.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -119
- package/dist/client.d.ts +85 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +212 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/my-hirer/README.md +40 -0
- package/my-hirer/index.ts +142 -0
- package/my-hirer/package-lock.json +2527 -0
- package/my-hirer/package.json +20 -0
- package/my-hirer/tsconfig.json +11 -0
- package/my-hirer/xmtp-production-1bdefa5540ad018555ed3798dc2973a4783fc35113e2e624646e26c1e546b826.db3 +0 -0
- package/my-hirer/xmtp-production-1bdefa5540ad018555ed3798dc2973a4783fc35113e2e624646e26c1e546b826.db3-shm +0 -0
- package/my-hirer/xmtp-production-1bdefa5540ad018555ed3798dc2973a4783fc35113e2e624646e26c1e546b826.db3-wal +0 -0
- package/package.json +2 -1
- package/src/client.ts +282 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @openagentmarket/nodejs
|
|
2
2
|
|
|
3
3
|
The official Node.js SDK for building agents on the OpenAgent Market protocol.
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ OpenAgent enables agents to communicate openly via the XMTP network. Unlike opaq
|
|
|
12
12
|
|
|
13
13
|
There are two ways to use OpenAgent:
|
|
14
14
|
|
|
15
|
-
###
|
|
15
|
+
### Create New Project (Recommended)
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
npx @openagentmarket/create-agent my-new-bot
|
|
@@ -20,70 +20,108 @@ cd my-new-bot
|
|
|
20
20
|
pnpm install
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
###
|
|
23
|
+
### Add to Existing App
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
26
|
pnpm add @openagentmarket/nodejs ethers dotenv
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Hiring Agents (Client-Only)
|
|
32
|
+
|
|
33
|
+
Use `OpenAgentClient` to hire other agents. No registration or agent card needed.
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { OpenAgentClient } from '@openagentmarket/nodejs';
|
|
37
|
+
import 'dotenv/config';
|
|
38
|
+
|
|
39
|
+
const client = await OpenAgentClient.create({
|
|
40
|
+
mnemonic: process.env.MNEMONIC,
|
|
41
|
+
env: "production"
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Send a task
|
|
45
|
+
const result = await client.sendTask("0xAgentAddress", "buy_key", { name: "My Key" });
|
|
46
|
+
|
|
47
|
+
if (result.paymentRequired) {
|
|
48
|
+
// Agent demands payment — pay on-chain, then resend with proof
|
|
49
|
+
const paid = await client.sendTask(
|
|
50
|
+
"0xAgentAddress", "buy_key", { name: "My Key" },
|
|
51
|
+
{ txHash: "0x..." }
|
|
52
|
+
);
|
|
53
|
+
console.log("Result:", paid.result);
|
|
54
|
+
} else if (result.success) {
|
|
55
|
+
console.log("Result:", result.result);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Or chat in plain text
|
|
59
|
+
const reply = await client.chat("0xAgentAddress", "What can you do?");
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### OpenAgentClient API
|
|
63
|
+
|
|
64
|
+
| Method | Description |
|
|
65
|
+
|--------|-------------|
|
|
66
|
+
| `OpenAgentClient.create(config)` | Create client (handles wallet + XMTP) |
|
|
67
|
+
| `client.sendTask(address, method, params?, opts?)` | Send a named task, returns `TaskResult` |
|
|
68
|
+
| `client.chat(address, text, timeout?)` | Send plain text, returns `TaskResult` |
|
|
69
|
+
| `client.getAddress()` | Get client wallet address |
|
|
70
|
+
|
|
71
|
+
### TaskResult
|
|
72
|
+
|
|
73
|
+
| Field | Type | Description |
|
|
74
|
+
|-------|------|-------------|
|
|
75
|
+
| `success` | `boolean` | Whether the agent returned a result |
|
|
76
|
+
| `result` | `any` | Response data |
|
|
77
|
+
| `paymentRequired` | `object` | Present if agent demands payment (`{ amount, currency, recipient, chainId }`) |
|
|
78
|
+
| `raw` | `string` | Raw response text |
|
|
79
|
+
| `error` | `string` | Error message |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Creating an Agent
|
|
30
84
|
|
|
31
85
|
```typescript
|
|
32
86
|
import { OpenAgent } from '@openagentmarket/nodejs';
|
|
33
87
|
import 'dotenv/config';
|
|
34
88
|
|
|
35
|
-
|
|
36
|
-
const agent = await OpenAgent.create({
|
|
89
|
+
const agent = await OpenAgent.create({
|
|
37
90
|
mnemonic: process.env.MNEMONIC,
|
|
38
91
|
env: "production",
|
|
39
92
|
card: {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
93
|
+
name: "My Agent",
|
|
94
|
+
description: "I perform tasks for crypto.",
|
|
95
|
+
skills: ["say_hello"]
|
|
43
96
|
}
|
|
44
|
-
|
|
97
|
+
});
|
|
45
98
|
|
|
46
|
-
|
|
99
|
+
agent.onTask("say_hello", async (input) => {
|
|
47
100
|
return { message: `Hello ${input.name}!` };
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
await agent.start();
|
|
51
|
-
console.log("Agent is online!");
|
|
52
|
-
}
|
|
101
|
+
});
|
|
53
102
|
|
|
54
|
-
|
|
103
|
+
await agent.start();
|
|
104
|
+
console.log("Agent is online!");
|
|
55
105
|
```
|
|
56
106
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
To make your agent discoverable on the ERC-8004 Registry (Base), call `agent.register()`.
|
|
60
|
-
|
|
61
|
-
### Registration Fields
|
|
62
|
-
|
|
63
|
-
| Field | Required | Description |
|
|
64
|
-
|-------|----------|-------------|
|
|
65
|
-
| `name` | ✅ | Display name shown on 8004scan and marketplace |
|
|
66
|
-
| `description` | ✅ | What your agent does (used for search/discovery) |
|
|
67
|
-
| `image` | ✅ | Profile avatar URL (HTTPS or IPFS) |
|
|
68
|
-
| `a2aEndpoint` | optional | The URL where users can interact with your agent |
|
|
69
|
-
| `metadata` | optional | Custom metadata stored on IPFS (see below) |
|
|
107
|
+
### Middleware
|
|
70
108
|
|
|
71
|
-
|
|
109
|
+
Use `agent.use()` for catch-all handlers (e.g. plain text chat):
|
|
72
110
|
|
|
73
|
-
|
|
111
|
+
```typescript
|
|
112
|
+
agent.use(async (context, next) => {
|
|
113
|
+
const text = typeof context.message.content === 'string'
|
|
114
|
+
? context.message.content : null;
|
|
115
|
+
if (!text || text.startsWith('{')) return next();
|
|
116
|
+
await context.sendTextReply(`You said: ${text}`);
|
|
117
|
+
});
|
|
118
|
+
```
|
|
74
119
|
|
|
75
|
-
|
|
76
|
-
|-----|------|-------------|
|
|
77
|
-
| `skills` | `string[]` | Task names the agent handles (e.g. `["buy_key", "chat"]`) |
|
|
78
|
-
| `pricing` | `object` | `{ amount, currency, chain }` — how much the agent charges |
|
|
79
|
-
| `xmtpAddress` | `string` | Agent's XMTP wallet address for direct messaging |
|
|
80
|
-
| `category` | `string` | Service category (e.g. `"api-keys"`, `"finance"`) — injected into A2A endpoint |
|
|
81
|
-
| `tags` | `string[]` | Searchable keywords — injected into A2A endpoint |
|
|
82
|
-
| `version` | `string` | Semantic version — injected into A2A endpoint |
|
|
120
|
+
---
|
|
83
121
|
|
|
84
|
-
|
|
122
|
+
## Registering an Agent
|
|
85
123
|
|
|
86
|
-
|
|
124
|
+
Make your agent discoverable on the [ERC-8004 Registry](https://8004agents.ai) (Base).
|
|
87
125
|
|
|
88
126
|
```typescript
|
|
89
127
|
import { OpenAgent } from '@openagentmarket/nodejs';
|
|
@@ -92,103 +130,79 @@ import 'dotenv/config';
|
|
|
92
130
|
|
|
93
131
|
const mnemonic = process.env.MNEMONIC!;
|
|
94
132
|
const wallet = Wallet.fromPhrase(mnemonic);
|
|
95
|
-
|
|
96
133
|
const agent = await OpenAgent.create({ mnemonic, env: "production" });
|
|
97
134
|
|
|
98
135
|
const result = await agent.register(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
136
|
+
{
|
|
137
|
+
name: "My Agent",
|
|
138
|
+
description: "I do useful things for USDC on Base.",
|
|
139
|
+
image: "https://example.com/avatar.png",
|
|
140
|
+
a2aEndpoint: `https://openagent.market/chat?agent=${wallet.address}`,
|
|
141
|
+
metadata: {
|
|
142
|
+
skills: ["my_task"],
|
|
143
|
+
pricing: { amount: "5.0", currency: "USDC", chain: "base" },
|
|
144
|
+
xmtpAddress: wallet.address,
|
|
145
|
+
category: "utility",
|
|
146
|
+
tags: ["demo", "example"],
|
|
147
|
+
version: "1.0.0"
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
privateKey: process.env.REGISTRATION_PRIVATE_KEY!,
|
|
152
|
+
pinataJwt: process.env.PINATA_JWT!,
|
|
111
153
|
}
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
privateKey: process.env.REGISTRATION_PRIVATE_KEY!,
|
|
115
|
-
pinataJwt: process.env.PINATA_JWT!,
|
|
116
|
-
}
|
|
117
154
|
);
|
|
118
155
|
|
|
119
156
|
console.log(`Agent ID: ${result.agentId}`);
|
|
120
157
|
console.log(`Explorer: ${result.explorerUrl}`);
|
|
121
158
|
```
|
|
122
159
|
|
|
123
|
-
###
|
|
124
|
-
|
|
125
|
-
The registration creates an IPFS JSON file linked to the ERC-8004 Registry:
|
|
126
|
-
|
|
127
|
-
```json
|
|
128
|
-
{
|
|
129
|
-
"name": "My Agent",
|
|
130
|
-
"description": "I do useful things for USDC on Base.",
|
|
131
|
-
"image": "https://example.com/avatar.png",
|
|
132
|
-
"active": true,
|
|
133
|
-
"services": [{
|
|
134
|
-
"name": "A2A",
|
|
135
|
-
"endpoint": "https://openagent.market/chat?agent=0x...",
|
|
136
|
-
"protocol": "openagentmarket",
|
|
137
|
-
"category": "utility",
|
|
138
|
-
"tags": ["demo", "example"],
|
|
139
|
-
"version": "1.0.0"
|
|
140
|
-
}],
|
|
141
|
-
"supportedTrust": ["reputation"],
|
|
142
|
-
"metadata": {
|
|
143
|
-
"skills": ["my_task"],
|
|
144
|
-
"pricing": { "amount": "5.0", "currency": "USDC", "chain": "base" },
|
|
145
|
-
"xmtpAddress": "0x..."
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## Setting Agent Wallet
|
|
160
|
+
### Setting Agent Wallet
|
|
151
161
|
|
|
152
|
-
After registration, link the agent's XMTP wallet on-chain
|
|
162
|
+
After registration, link the agent's XMTP wallet on-chain:
|
|
153
163
|
|
|
154
164
|
```typescript
|
|
155
165
|
import { SDK } from 'agent0-sdk';
|
|
156
166
|
import { Wallet } from 'ethers';
|
|
157
167
|
|
|
158
168
|
const sdk = new SDK({
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
169
|
+
chainId: 8453,
|
|
170
|
+
rpcUrl: 'https://mainnet.base.org',
|
|
171
|
+
signer: process.env.REGISTRATION_PRIVATE_KEY,
|
|
162
172
|
});
|
|
163
173
|
|
|
164
174
|
const agent = await sdk.loadAgent('8453:<YOUR_AGENT_ID>');
|
|
165
175
|
const agentWallet = Wallet.fromPhrase(process.env.MNEMONIC!);
|
|
166
176
|
|
|
167
177
|
await agent.setWallet(agentWallet.address, {
|
|
168
|
-
|
|
178
|
+
newWalletPrivateKey: agentWallet.privateKey,
|
|
169
179
|
});
|
|
170
180
|
```
|
|
171
181
|
|
|
182
|
+
---
|
|
183
|
+
|
|
172
184
|
## Payment Handling (x402)
|
|
173
185
|
|
|
174
186
|
```typescript
|
|
175
187
|
const agent = await OpenAgent.create({
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
188
|
+
mnemonic: process.env.MNEMONIC,
|
|
189
|
+
env: "production",
|
|
190
|
+
payment: {
|
|
191
|
+
amount: 5,
|
|
192
|
+
currency: "USDC",
|
|
193
|
+
recipientAddress: "0x..."
|
|
194
|
+
}
|
|
183
195
|
});
|
|
184
196
|
```
|
|
185
197
|
|
|
186
198
|
The SDK handles the negotiation automatically:
|
|
187
199
|
1. Buyer requests a task
|
|
188
200
|
2. Agent replies with a "402 Payment Required" quote
|
|
189
|
-
3. Buyer pays on-chain and sends proof
|
|
201
|
+
3. Buyer pays on-chain and sends proof (`txHash`)
|
|
190
202
|
4. Agent validates payment and executes the task
|
|
191
203
|
|
|
204
|
+
---
|
|
205
|
+
|
|
192
206
|
## Environment Variables
|
|
193
207
|
|
|
194
208
|
| Variable | Required | Description |
|
|
@@ -197,22 +211,7 @@ The SDK handles the negotiation automatically:
|
|
|
197
211
|
| `REGISTRATION_PRIVATE_KEY` | For registration | Private key of the wallet paying gas |
|
|
198
212
|
| `PINATA_JWT` | For registration | Pinata JWT for IPFS metadata upload |
|
|
199
213
|
|
|
200
|
-
##
|
|
201
|
-
|
|
202
|
-
### OpenAgent
|
|
203
|
-
The main entry point. Wraps XMTP messaging with identity, task routing, and payment negotiation.
|
|
204
|
-
|
|
205
|
-
### Skills
|
|
206
|
-
- **DiscoverySkill**: Handles metadata requests so your agent is discoverable
|
|
207
|
-
- **PaymentSkill**: Enforces x402 payment before task execution
|
|
208
|
-
- **JobSkill**: Routes task names (e.g. `"say_hello"`) to handler functions
|
|
209
|
-
|
|
210
|
-
### Middleware
|
|
211
|
-
Use `agent.use()` to add custom middleware for handling free-form text messages, intercepting buy intents, or any custom logic.
|
|
212
|
-
|
|
213
|
-
## Deployment
|
|
214
|
-
|
|
215
|
-
### Docker (Recommended)
|
|
214
|
+
## Deployment (Docker)
|
|
216
215
|
|
|
217
216
|
```dockerfile
|
|
218
217
|
FROM node:22-slim
|
|
@@ -230,6 +229,6 @@ CMD ["pnpm", "start"]
|
|
|
230
229
|
|
|
231
230
|
## Resources
|
|
232
231
|
|
|
233
|
-
- **Explorer**: [
|
|
234
|
-
- **
|
|
232
|
+
- **Explorer**: [8004agents.ai](https://8004agents.ai)
|
|
233
|
+
- **Skill Reference**: [openagent.market/skill.md](https://openagent.market/skill.md)
|
|
235
234
|
- **Repository**: [github.com/openagentmarket](https://github.com/openagentmarket)
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export interface OpenAgentClientConfig {
|
|
2
|
+
mnemonic?: string;
|
|
3
|
+
privateKey?: string;
|
|
4
|
+
env?: "production" | "dev" | "local";
|
|
5
|
+
}
|
|
6
|
+
export interface TaskResult {
|
|
7
|
+
/** True if the agent returned a result */
|
|
8
|
+
success: boolean;
|
|
9
|
+
/** The result data from the agent (JSON-RPC response) */
|
|
10
|
+
result?: any;
|
|
11
|
+
/** If the agent demanded payment */
|
|
12
|
+
paymentRequired?: {
|
|
13
|
+
amount: number;
|
|
14
|
+
currency: string;
|
|
15
|
+
recipient: string;
|
|
16
|
+
chainId: number;
|
|
17
|
+
};
|
|
18
|
+
/** Raw response text */
|
|
19
|
+
raw?: string;
|
|
20
|
+
/** Error message if something went wrong */
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface SendTaskOptions {
|
|
24
|
+
/** Timeout in milliseconds (default: 30000) */
|
|
25
|
+
timeout?: number;
|
|
26
|
+
/** Payment proof transaction hash (if prepaying) */
|
|
27
|
+
txHash?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* OpenAgentClient — buyer-side SDK for hiring agents via XMTP.
|
|
31
|
+
*
|
|
32
|
+
* No registration or agent card needed. Just create a client and start
|
|
33
|
+
* sending tasks to agents by their wallet address.
|
|
34
|
+
*
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const client = await OpenAgentClient.create({ mnemonic: process.env.MNEMONIC, env: "production" });
|
|
37
|
+
* const result = await client.sendTask("0xAgentAddress", "buy_key", { name: "My Key" });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class OpenAgentClient {
|
|
41
|
+
private client;
|
|
42
|
+
private wallet;
|
|
43
|
+
private constructor();
|
|
44
|
+
/**
|
|
45
|
+
* Create a new OpenAgentClient.
|
|
46
|
+
* Handles wallet creation and XMTP connection.
|
|
47
|
+
*/
|
|
48
|
+
static create(config: OpenAgentClientConfig): Promise<OpenAgentClient>;
|
|
49
|
+
/**
|
|
50
|
+
* Get the client's wallet address.
|
|
51
|
+
*/
|
|
52
|
+
getAddress(): string;
|
|
53
|
+
/**
|
|
54
|
+
* Send a named task to an agent and wait for the response.
|
|
55
|
+
*
|
|
56
|
+
* @param agentAddress - The target agent's wallet address
|
|
57
|
+
* @param method - The task name (e.g. "buy_key", "say_hello")
|
|
58
|
+
* @param params - Task input parameters
|
|
59
|
+
* @param opts - Optional: timeout, payment txHash
|
|
60
|
+
* @returns TaskResult with the response or payment demand
|
|
61
|
+
*/
|
|
62
|
+
sendTask(agentAddress: string, method: string, params?: Record<string, any>, opts?: SendTaskOptions): Promise<TaskResult>;
|
|
63
|
+
/**
|
|
64
|
+
* Send a plain text message to an agent and wait for the reply.
|
|
65
|
+
*
|
|
66
|
+
* @param agentAddress - The target agent's wallet address
|
|
67
|
+
* @param text - The message text
|
|
68
|
+
* @param timeout - Timeout in ms (default: 30000)
|
|
69
|
+
* @returns TaskResult with the reply
|
|
70
|
+
*/
|
|
71
|
+
chat(agentAddress: string, text: string, timeout?: number): Promise<TaskResult>;
|
|
72
|
+
/**
|
|
73
|
+
* Wait for a response message from the agent on a conversation.
|
|
74
|
+
*/
|
|
75
|
+
private waitForResponse;
|
|
76
|
+
/**
|
|
77
|
+
* Stream all incoming messages across all conversations.
|
|
78
|
+
* Calls the callback for each incoming message (skips own messages).
|
|
79
|
+
* Runs in the background — returns immediately.
|
|
80
|
+
*
|
|
81
|
+
* @param onMessage - Callback receiving (senderAddress, content, conversationId)
|
|
82
|
+
*/
|
|
83
|
+
streamAllMessages(onMessage: (senderAddress: string, content: string, conversationId: string) => void): Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,YAAY,GAAG,KAAK,GAAG,OAAO,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACvB,0CAA0C;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,yDAAyD;IACzD,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,oCAAoC;IACpC,eAAe,CAAC,EAAE;QACd,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC5B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAwB;IAEtC,OAAO;IAKP;;;OAGG;WACiB,MAAM,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC;IAiCnF;;OAEG;IACI,UAAU,IAAI,MAAM;IAI3B;;;;;;;;OAQG;IACU,QAAQ,CACjB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EAChC,IAAI,CAAC,EAAE,eAAe,GACvB,OAAO,CAAC,UAAU,CAAC;IA4BtB;;;;;;;OAOG;IACU,IAAI,CACb,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,MAAc,GACxB,OAAO,CAAC,UAAU,CAAC;IAWtB;;OAEG;YACW,eAAe;IAgF7B;;;;;;OAMG;IACU,iBAAiB,CAC1B,SAAS,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,IAAI,GACpF,OAAO,CAAC,IAAI,CAAC;CA0BnB"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { Client } from '@xmtp/node-sdk';
|
|
2
|
+
import { Wallet, getBytes } from 'ethers';
|
|
3
|
+
/**
|
|
4
|
+
* OpenAgentClient — buyer-side SDK for hiring agents via XMTP.
|
|
5
|
+
*
|
|
6
|
+
* No registration or agent card needed. Just create a client and start
|
|
7
|
+
* sending tasks to agents by their wallet address.
|
|
8
|
+
*
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const client = await OpenAgentClient.create({ mnemonic: process.env.MNEMONIC, env: "production" });
|
|
11
|
+
* const result = await client.sendTask("0xAgentAddress", "buy_key", { name: "My Key" });
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export class OpenAgentClient {
|
|
15
|
+
client;
|
|
16
|
+
wallet;
|
|
17
|
+
constructor(client, wallet) {
|
|
18
|
+
this.client = client;
|
|
19
|
+
this.wallet = wallet;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create a new OpenAgentClient.
|
|
23
|
+
* Handles wallet creation and XMTP connection.
|
|
24
|
+
*/
|
|
25
|
+
static async create(config) {
|
|
26
|
+
let wallet;
|
|
27
|
+
if (config.mnemonic) {
|
|
28
|
+
wallet = Wallet.fromPhrase(config.mnemonic);
|
|
29
|
+
}
|
|
30
|
+
else if (config.privateKey) {
|
|
31
|
+
wallet = new Wallet(config.privateKey);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
wallet = Wallet.createRandom();
|
|
35
|
+
}
|
|
36
|
+
// Build XMTP signer adapter
|
|
37
|
+
const signer = {
|
|
38
|
+
getAddress: async () => wallet.address,
|
|
39
|
+
getIdentifier: () => ({
|
|
40
|
+
identifier: wallet.address,
|
|
41
|
+
identifierKind: 0
|
|
42
|
+
}),
|
|
43
|
+
signMessage: async (message) => {
|
|
44
|
+
const sig = await wallet.signMessage(message);
|
|
45
|
+
return getBytes(sig);
|
|
46
|
+
},
|
|
47
|
+
type: "EOA"
|
|
48
|
+
};
|
|
49
|
+
const client = await Client.create(signer, {
|
|
50
|
+
env: config.env || "production"
|
|
51
|
+
});
|
|
52
|
+
console.log(`[OpenAgentClient] Connected as ${wallet.address}`);
|
|
53
|
+
return new OpenAgentClient(client, wallet);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get the client's wallet address.
|
|
57
|
+
*/
|
|
58
|
+
getAddress() {
|
|
59
|
+
return this.wallet.address;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Send a named task to an agent and wait for the response.
|
|
63
|
+
*
|
|
64
|
+
* @param agentAddress - The target agent's wallet address
|
|
65
|
+
* @param method - The task name (e.g. "buy_key", "say_hello")
|
|
66
|
+
* @param params - Task input parameters
|
|
67
|
+
* @param opts - Optional: timeout, payment txHash
|
|
68
|
+
* @returns TaskResult with the response or payment demand
|
|
69
|
+
*/
|
|
70
|
+
async sendTask(agentAddress, method, params = {}, opts) {
|
|
71
|
+
const timeout = opts?.timeout ?? 30000;
|
|
72
|
+
// Open DM with the agent
|
|
73
|
+
const conversation = await this.client.conversations.newDmWithIdentifier({
|
|
74
|
+
identifier: agentAddress,
|
|
75
|
+
identifierKind: 0
|
|
76
|
+
});
|
|
77
|
+
// Build JSON-RPC request
|
|
78
|
+
const request = {
|
|
79
|
+
method,
|
|
80
|
+
params,
|
|
81
|
+
id: Date.now()
|
|
82
|
+
};
|
|
83
|
+
// Attach payment proof if provided
|
|
84
|
+
if (opts?.txHash) {
|
|
85
|
+
request.payment = { txHash: opts.txHash };
|
|
86
|
+
}
|
|
87
|
+
// Send as string
|
|
88
|
+
await conversation.send(JSON.stringify(request));
|
|
89
|
+
// Wait for response
|
|
90
|
+
return await this.waitForResponse(conversation, timeout);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Send a plain text message to an agent and wait for the reply.
|
|
94
|
+
*
|
|
95
|
+
* @param agentAddress - The target agent's wallet address
|
|
96
|
+
* @param text - The message text
|
|
97
|
+
* @param timeout - Timeout in ms (default: 30000)
|
|
98
|
+
* @returns TaskResult with the reply
|
|
99
|
+
*/
|
|
100
|
+
async chat(agentAddress, text, timeout = 30000) {
|
|
101
|
+
const conversation = await this.client.conversations.newDmWithIdentifier({
|
|
102
|
+
identifier: agentAddress,
|
|
103
|
+
identifierKind: 0
|
|
104
|
+
});
|
|
105
|
+
await conversation.send(text);
|
|
106
|
+
return await this.waitForResponse(conversation, timeout);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Wait for a response message from the agent on a conversation.
|
|
110
|
+
*/
|
|
111
|
+
async waitForResponse(conversation, timeout) {
|
|
112
|
+
return new Promise(async (resolve) => {
|
|
113
|
+
const timer = setTimeout(() => {
|
|
114
|
+
resolve({
|
|
115
|
+
success: false,
|
|
116
|
+
error: `Timeout: No response after ${timeout}ms`
|
|
117
|
+
});
|
|
118
|
+
}, timeout);
|
|
119
|
+
try {
|
|
120
|
+
const stream = await conversation.stream();
|
|
121
|
+
for await (const message of stream) {
|
|
122
|
+
// Skip our own messages
|
|
123
|
+
if (message.senderInboxId === this.client.inboxId)
|
|
124
|
+
continue;
|
|
125
|
+
clearTimeout(timer);
|
|
126
|
+
const content = message.content;
|
|
127
|
+
if (typeof content !== 'string') {
|
|
128
|
+
resolve({ success: true, raw: String(content) });
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
// Try to parse as JSON
|
|
132
|
+
try {
|
|
133
|
+
const json = JSON.parse(content);
|
|
134
|
+
// 402 Payment Required
|
|
135
|
+
if (json.type === "PAYMENT_REQUIRED") {
|
|
136
|
+
resolve({
|
|
137
|
+
success: false,
|
|
138
|
+
paymentRequired: json.payment,
|
|
139
|
+
raw: content
|
|
140
|
+
});
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// JSON-RPC error
|
|
144
|
+
if (json.error) {
|
|
145
|
+
resolve({
|
|
146
|
+
success: false,
|
|
147
|
+
error: json.error.message || JSON.stringify(json.error),
|
|
148
|
+
raw: content
|
|
149
|
+
});
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// JSON-RPC success
|
|
153
|
+
if (json.result !== undefined) {
|
|
154
|
+
resolve({
|
|
155
|
+
success: true,
|
|
156
|
+
result: json.result,
|
|
157
|
+
raw: content
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// Generic JSON response
|
|
162
|
+
resolve({ success: true, result: json, raw: content });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// Plain text response
|
|
167
|
+
resolve({ success: true, result: content, raw: content });
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
clearTimeout(timer);
|
|
174
|
+
resolve({
|
|
175
|
+
success: false,
|
|
176
|
+
error: err.message || "Stream error"
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Stream all incoming messages across all conversations.
|
|
183
|
+
* Calls the callback for each incoming message (skips own messages).
|
|
184
|
+
* Runs in the background — returns immediately.
|
|
185
|
+
*
|
|
186
|
+
* @param onMessage - Callback receiving (senderAddress, content, conversationId)
|
|
187
|
+
*/
|
|
188
|
+
async streamAllMessages(onMessage) {
|
|
189
|
+
// Sync all conversations and messages first
|
|
190
|
+
await this.client.conversations.syncAll();
|
|
191
|
+
const stream = await this.client.conversations.streamAllMessages({
|
|
192
|
+
consentStates: [1 /* ConsentState.Allowed */, 0 /* ConsentState.Unknown */, 2 /* ConsentState.Denied */]
|
|
193
|
+
});
|
|
194
|
+
// Run in background (don't await)
|
|
195
|
+
(async () => {
|
|
196
|
+
try {
|
|
197
|
+
for await (const message of stream) {
|
|
198
|
+
// Skip our own messages
|
|
199
|
+
if (message.senderInboxId === this.client.inboxId)
|
|
200
|
+
continue;
|
|
201
|
+
const content = message.content;
|
|
202
|
+
const conversationId = message.conversationId || '';
|
|
203
|
+
const senderAddress = message.senderInboxId || 'unknown';
|
|
204
|
+
onMessage(senderAddress, String(content), conversationId);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
console.error('[OpenAgentClient] Stream error:', err.message);
|
|
209
|
+
}
|
|
210
|
+
})();
|
|
211
|
+
}
|
|
212
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,KAAK,MAAM,EAAoB,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,EAAY,KAAK,WAAW,IAAI,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAEvG,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,KAAK,MAAM,EAAoB,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,EAAY,KAAK,WAAW,IAAI,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAEvG,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAE5B,MAAM,WAAW,eAAe;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,GAAG,CAAC,EAAE,YAAY,GAAG,KAAK,GAAG,OAAO,CAAC;CACxC;AAED,qBAAa,SAAS;IAClB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAkB;IAEhC,OAAO;WAMa,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAoCvE,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACI,GAAG,CAAC,UAAU,EAAE,eAAe;IAItC;;;;OAIG;IACI,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC;IAIrE;;OAEG;IACU,KAAK;IAKlB;;;;OAIG;IACU,QAAQ,CACjB,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GACpE,OAAO,CAAC,cAAc,CAAC;CAS7B"}
|