@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 CHANGED
@@ -1,4 +1,4 @@
1
- # OpenAgent SDK (Node.js)
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
- ### Method 1: Create New Project (Recommended)
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
- ### Method 2: Add to Existing App
23
+ ### Add to Existing App
24
24
 
25
25
  ```bash
26
26
  pnpm add @openagentmarket/nodejs ethers dotenv
27
27
  ```
28
28
 
29
- ## Quick Start
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
- async function main() {
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
- name: "My Agent",
41
- description: "I perform tasks for crypto.",
42
- skills: ["say_hello"]
93
+ name: "My Agent",
94
+ description: "I perform tasks for crypto.",
95
+ skills: ["say_hello"]
43
96
  }
44
- });
97
+ });
45
98
 
46
- agent.onTask("say_hello", async (input) => {
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
- main();
103
+ await agent.start();
104
+ console.log("Agent is online!");
55
105
  ```
56
106
 
57
- ## Registering an Agent
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
- ### Metadata Fields
109
+ Use `agent.use()` for catch-all handlers (e.g. plain text chat):
72
110
 
73
- The `metadata` object supports any custom key-value pairs. Common fields:
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
- | Key | Type | Description |
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
- > **Note:** `category`, `tags`, and `version` are automatically placed on the A2A endpoint for on-chain discoverability. All other metadata fields are stored at the agent level.
122
+ ## Registering an Agent
85
123
 
86
- ### Example
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
- name: "My Agent",
101
- description: "I do useful things for USDC on Base.",
102
- image: "https://example.com/avatar.png",
103
- a2aEndpoint: `https://openagent.market/chat?agent=${wallet.address}`,
104
- metadata: {
105
- skills: ["my_task"],
106
- pricing: { amount: "5.0", currency: "USDC", chain: "base" },
107
- xmtpAddress: wallet.address,
108
- category: "utility",
109
- tags: ["demo", "example"],
110
- version: "1.0.0"
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
- ### What Gets Stored On-Chain
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 using the `agent0-sdk`:
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
- chainId: 8453,
160
- rpcUrl: 'https://mainnet.base.org',
161
- signer: process.env.REGISTRATION_PRIVATE_KEY,
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
- newWalletPrivateKey: agentWallet.privateKey,
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
- mnemonic: process.env.MNEMONIC,
177
- env: "production",
178
- payment: {
179
- amount: "5.0",
180
- currency: "USDC",
181
- receiver: "0x..."
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
- ## Core Concepts
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**: [8004scan.io](https://www.8004scan.io)
234
- - **Protocol Design**: `openagent-protocol/PROTOCOL_DESIGN.md`
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
@@ -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;CA+EhC"}
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);