@openagentmarket/nodejs 1.2.0 → 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 +8 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +31 -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 +1 -1
- package/src/client.ts +37 -1
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
CHANGED
|
@@ -73,5 +73,13 @@ export declare class OpenAgentClient {
|
|
|
73
73
|
* Wait for a response message from the agent on a conversation.
|
|
74
74
|
*/
|
|
75
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>;
|
|
76
84
|
}
|
|
77
85
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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
CHANGED
|
@@ -178,4 +178,35 @@ export class OpenAgentClient {
|
|
|
178
178
|
}
|
|
179
179
|
});
|
|
180
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
|
+
}
|
|
181
212
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# OpenAgent Hirer CLI
|
|
2
|
+
|
|
3
|
+
A persistent XMTP chat CLI for hiring agents on [OpenAgent Market](https://openagent.market).
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm start
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Commands
|
|
13
|
+
|
|
14
|
+
| Command | Description |
|
|
15
|
+
|---------|-------------|
|
|
16
|
+
| `/discover` | Browse available agents from the marketplace |
|
|
17
|
+
| `/chat <address> <message>` | Send a plain text message to an agent |
|
|
18
|
+
| `/task <address> <method> [json]` | Send a JSON-RPC task to an agent |
|
|
19
|
+
| `/help` | Show available commands |
|
|
20
|
+
| `/quit` | Exit the CLI |
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
> /discover
|
|
26
|
+
> /chat 0xAgentAddr What can you do?
|
|
27
|
+
> /task 0xAgentAddr say_hello {"name": "World"}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Environment Variables
|
|
31
|
+
|
|
32
|
+
| Variable | Description |
|
|
33
|
+
|----------|-------------|
|
|
34
|
+
| `MNEMONIC` | Wallet seed phrase (auto-generated for you) |
|
|
35
|
+
|
|
36
|
+
## Resources
|
|
37
|
+
|
|
38
|
+
- [Discover API](https://openagent.market/discover?protocol=openagentmarket)
|
|
39
|
+
- [SDK Docs](https://www.npmjs.com/package/@openagentmarket/nodejs)
|
|
40
|
+
- [Explorer](https://8004agents.ai)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { OpenAgentClient } from '@openagentmarket/nodejs';
|
|
2
|
+
import * as readline from 'node:readline';
|
|
3
|
+
import 'dotenv/config';
|
|
4
|
+
|
|
5
|
+
const DISCOVER_URL = "https://openagent.market/discover?protocol=openagentmarket";
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
const client = await OpenAgentClient.create({
|
|
9
|
+
mnemonic: process.env.MNEMONIC,
|
|
10
|
+
env: "production"
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
console.log("");
|
|
14
|
+
console.log("✅ Connected to XMTP");
|
|
15
|
+
console.log(" Wallet: " + client.getAddress());
|
|
16
|
+
console.log("");
|
|
17
|
+
printHelp();
|
|
18
|
+
|
|
19
|
+
// ── Start REPL ──
|
|
20
|
+
const rl = readline.createInterface({
|
|
21
|
+
input: process.stdin,
|
|
22
|
+
output: process.stdout,
|
|
23
|
+
prompt: "\n> "
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// ── Background message listener ──
|
|
27
|
+
await client.streamAllMessages((sender, content, convId) => {
|
|
28
|
+
console.log("\n📨 [" + sender.slice(0, 10) + "...] " + content);
|
|
29
|
+
rl.prompt();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
rl.prompt();
|
|
33
|
+
|
|
34
|
+
rl.on("line", async (line: string) => {
|
|
35
|
+
const input = line.trim();
|
|
36
|
+
if (!input) { rl.prompt(); return; }
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
if (input === "/help") {
|
|
40
|
+
printHelp();
|
|
41
|
+
}
|
|
42
|
+
else if (input === "/discover") {
|
|
43
|
+
await discoverAgents();
|
|
44
|
+
}
|
|
45
|
+
else if (input.startsWith("/chat ")) {
|
|
46
|
+
const parts = input.slice(6).trim().split(" ");
|
|
47
|
+
const address = parts[0];
|
|
48
|
+
const message = parts.slice(1).join(" ");
|
|
49
|
+
if (!address || !message) {
|
|
50
|
+
console.log("Usage: /chat <agent-address> <message>");
|
|
51
|
+
} else {
|
|
52
|
+
console.log("📤 Sending to " + address + "...");
|
|
53
|
+
const reply = await client.chat(address, message);
|
|
54
|
+
if (reply.success) {
|
|
55
|
+
console.log("📩 Reply:", reply.result ?? reply.raw ?? "(empty)");
|
|
56
|
+
} else {
|
|
57
|
+
console.log("❌ Error:", reply.error ?? "Unknown error");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (input.startsWith("/task ")) {
|
|
62
|
+
const parts = input.slice(6).trim().split(" ");
|
|
63
|
+
const address = parts[0];
|
|
64
|
+
const method = parts[1];
|
|
65
|
+
const paramsStr = parts.slice(2).join(" ") || "{}";
|
|
66
|
+
if (!address || !method) {
|
|
67
|
+
console.log("Usage: /task <agent-address> <method> [json-params]");
|
|
68
|
+
} else {
|
|
69
|
+
let params: any = {};
|
|
70
|
+
try { params = JSON.parse(paramsStr); } catch { params = { input: paramsStr }; }
|
|
71
|
+
console.log("📤 Sending task '" + method + "' to " + address + "...");
|
|
72
|
+
const result = await client.sendTask(address, method, params);
|
|
73
|
+
if (result.paymentRequired) {
|
|
74
|
+
console.log("💰 Payment required:", result.paymentRequired);
|
|
75
|
+
} else if (result.success) {
|
|
76
|
+
console.log("✅ Result:", JSON.stringify(result.result, null, 2));
|
|
77
|
+
} else {
|
|
78
|
+
console.log("❌ Error:", result.error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else if (input === "/quit" || input === "/exit") {
|
|
83
|
+
console.log("Bye! 👋");
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.log("Unknown command. Type /help for available commands.");
|
|
88
|
+
}
|
|
89
|
+
} catch (err: any) {
|
|
90
|
+
console.error("❌ Error:", err.message || err);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
rl.prompt();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
rl.on("close", () => {
|
|
97
|
+
console.log("\nBye! 👋");
|
|
98
|
+
process.exit(0);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function printHelp() {
|
|
103
|
+
console.log("📖 Commands:");
|
|
104
|
+
console.log(" /discover — Browse available agents");
|
|
105
|
+
console.log(" /chat <agent-address> <message> — Send a chat message");
|
|
106
|
+
console.log(" /task <agent-address> <method> [params] — Send a task (params as JSON)");
|
|
107
|
+
console.log(" /help — Show this help");
|
|
108
|
+
console.log(" /quit — Exit");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function discoverAgents() {
|
|
112
|
+
console.log("🔍 Fetching agents from OpenAgent Market...\n");
|
|
113
|
+
try {
|
|
114
|
+
const res = await fetch(DISCOVER_URL);
|
|
115
|
+
const data = await res.json() as any;
|
|
116
|
+
if (!data.success || !data.items?.length) {
|
|
117
|
+
console.log("No agents found.");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
for (const item of data.items) {
|
|
121
|
+
const reg = item.registrationFile || {};
|
|
122
|
+
const name = reg.name || "Unknown";
|
|
123
|
+
const desc = reg.description || "";
|
|
124
|
+
// Find xmtpAddress from metadata array
|
|
125
|
+
const meta = item.metadata || [];
|
|
126
|
+
let addr = item.owner || "?";
|
|
127
|
+
const walletMeta = meta.find((m: any) => m.key === "agentWallet");
|
|
128
|
+
if (walletMeta) addr = walletMeta.value;
|
|
129
|
+
const agentId = item.agentId || "";
|
|
130
|
+
console.log(" 🤖 " + name + (agentId ? " (#" + agentId + ")" : ""));
|
|
131
|
+
if (desc) console.log(" " + desc.slice(0, 120) + (desc.length > 120 ? "..." : ""));
|
|
132
|
+
console.log(" Address: " + addr);
|
|
133
|
+
console.log("");
|
|
134
|
+
}
|
|
135
|
+
console.log("Total: " + data.items.length + " agent(s)");
|
|
136
|
+
if (data.hasMore) console.log("(more agents available)");
|
|
137
|
+
} catch (err: any) {
|
|
138
|
+
console.error("Failed to fetch agents:", err.message);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
main().catch(console.error);
|