@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
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-hirer",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Hire agents on OpenAgent Market",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "tsx index.ts",
|
|
8
|
+
"dev": "tsx watch index.ts"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@openagentmarket/nodejs": "^1.0.0",
|
|
12
|
+
"ethers": "^6.10.0",
|
|
13
|
+
"dotenv": "^16.4.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"tsx": "^4.7.0",
|
|
17
|
+
"typescript": "^5.3.3",
|
|
18
|
+
"@types/node": "^20.11.0"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openagentmarket/nodejs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "OpenAgent Market Node.js SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@xmtp/agent-sdk": "^1.0.0",
|
|
27
|
+
"@xmtp/node-sdk": "^4.6.0",
|
|
27
28
|
"agent0-sdk": "^1.5.3",
|
|
28
29
|
"dotenv": "^16.4.0",
|
|
29
30
|
"ethers": "^6.10.0"
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { Client, ConsentState } from '@xmtp/node-sdk';
|
|
2
|
+
import { type Signer, Wallet, HDNodeWallet, getBytes } from 'ethers';
|
|
3
|
+
|
|
4
|
+
export interface OpenAgentClientConfig {
|
|
5
|
+
mnemonic?: string;
|
|
6
|
+
privateKey?: string;
|
|
7
|
+
env?: "production" | "dev" | "local";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface TaskResult {
|
|
11
|
+
/** True if the agent returned a result */
|
|
12
|
+
success: boolean;
|
|
13
|
+
/** The result data from the agent (JSON-RPC response) */
|
|
14
|
+
result?: any;
|
|
15
|
+
/** If the agent demanded payment */
|
|
16
|
+
paymentRequired?: {
|
|
17
|
+
amount: number;
|
|
18
|
+
currency: string;
|
|
19
|
+
recipient: string;
|
|
20
|
+
chainId: number;
|
|
21
|
+
};
|
|
22
|
+
/** Raw response text */
|
|
23
|
+
raw?: string;
|
|
24
|
+
/** Error message if something went wrong */
|
|
25
|
+
error?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface SendTaskOptions {
|
|
29
|
+
/** Timeout in milliseconds (default: 30000) */
|
|
30
|
+
timeout?: number;
|
|
31
|
+
/** Payment proof transaction hash (if prepaying) */
|
|
32
|
+
txHash?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* OpenAgentClient — buyer-side SDK for hiring agents via XMTP.
|
|
37
|
+
*
|
|
38
|
+
* No registration or agent card needed. Just create a client and start
|
|
39
|
+
* sending tasks to agents by their wallet address.
|
|
40
|
+
*
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const client = await OpenAgentClient.create({ mnemonic: process.env.MNEMONIC, env: "production" });
|
|
43
|
+
* const result = await client.sendTask("0xAgentAddress", "buy_key", { name: "My Key" });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export class OpenAgentClient {
|
|
47
|
+
private client: Client;
|
|
48
|
+
private wallet: Wallet | HDNodeWallet;
|
|
49
|
+
|
|
50
|
+
private constructor(client: Client, wallet: Wallet | HDNodeWallet) {
|
|
51
|
+
this.client = client;
|
|
52
|
+
this.wallet = wallet;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a new OpenAgentClient.
|
|
57
|
+
* Handles wallet creation and XMTP connection.
|
|
58
|
+
*/
|
|
59
|
+
public static async create(config: OpenAgentClientConfig): Promise<OpenAgentClient> {
|
|
60
|
+
let wallet: Wallet | HDNodeWallet;
|
|
61
|
+
|
|
62
|
+
if (config.mnemonic) {
|
|
63
|
+
wallet = Wallet.fromPhrase(config.mnemonic);
|
|
64
|
+
} else if (config.privateKey) {
|
|
65
|
+
wallet = new Wallet(config.privateKey);
|
|
66
|
+
} else {
|
|
67
|
+
wallet = Wallet.createRandom();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Build XMTP signer adapter
|
|
71
|
+
const signer = {
|
|
72
|
+
getAddress: async () => wallet.address,
|
|
73
|
+
getIdentifier: () => ({
|
|
74
|
+
identifier: wallet.address,
|
|
75
|
+
identifierKind: 0
|
|
76
|
+
}),
|
|
77
|
+
signMessage: async (message: string | Uint8Array) => {
|
|
78
|
+
const sig = await wallet.signMessage(message);
|
|
79
|
+
return getBytes(sig);
|
|
80
|
+
},
|
|
81
|
+
type: "EOA"
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const client = await Client.create(signer as any, {
|
|
85
|
+
env: config.env || "production"
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
console.log(`[OpenAgentClient] Connected as ${wallet.address}`);
|
|
89
|
+
return new OpenAgentClient(client, wallet);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get the client's wallet address.
|
|
94
|
+
*/
|
|
95
|
+
public getAddress(): string {
|
|
96
|
+
return this.wallet.address;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Send a named task to an agent and wait for the response.
|
|
101
|
+
*
|
|
102
|
+
* @param agentAddress - The target agent's wallet address
|
|
103
|
+
* @param method - The task name (e.g. "buy_key", "say_hello")
|
|
104
|
+
* @param params - Task input parameters
|
|
105
|
+
* @param opts - Optional: timeout, payment txHash
|
|
106
|
+
* @returns TaskResult with the response or payment demand
|
|
107
|
+
*/
|
|
108
|
+
public async sendTask(
|
|
109
|
+
agentAddress: string,
|
|
110
|
+
method: string,
|
|
111
|
+
params: Record<string, any> = {},
|
|
112
|
+
opts?: SendTaskOptions
|
|
113
|
+
): Promise<TaskResult> {
|
|
114
|
+
const timeout = opts?.timeout ?? 30000;
|
|
115
|
+
|
|
116
|
+
// Open DM with the agent
|
|
117
|
+
const conversation = await this.client.conversations.newDmWithIdentifier({
|
|
118
|
+
identifier: agentAddress,
|
|
119
|
+
identifierKind: 0
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Build JSON-RPC request
|
|
123
|
+
const request: Record<string, any> = {
|
|
124
|
+
method,
|
|
125
|
+
params,
|
|
126
|
+
id: Date.now()
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Attach payment proof if provided
|
|
130
|
+
if (opts?.txHash) {
|
|
131
|
+
request.payment = { txHash: opts.txHash };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Send as string
|
|
135
|
+
await conversation.send(JSON.stringify(request));
|
|
136
|
+
|
|
137
|
+
// Wait for response
|
|
138
|
+
return await this.waitForResponse(conversation, timeout);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Send a plain text message to an agent and wait for the reply.
|
|
143
|
+
*
|
|
144
|
+
* @param agentAddress - The target agent's wallet address
|
|
145
|
+
* @param text - The message text
|
|
146
|
+
* @param timeout - Timeout in ms (default: 30000)
|
|
147
|
+
* @returns TaskResult with the reply
|
|
148
|
+
*/
|
|
149
|
+
public async chat(
|
|
150
|
+
agentAddress: string,
|
|
151
|
+
text: string,
|
|
152
|
+
timeout: number = 30000
|
|
153
|
+
): Promise<TaskResult> {
|
|
154
|
+
const conversation = await this.client.conversations.newDmWithIdentifier({
|
|
155
|
+
identifier: agentAddress,
|
|
156
|
+
identifierKind: 0
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
await conversation.send(text);
|
|
160
|
+
|
|
161
|
+
return await this.waitForResponse(conversation, timeout);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Wait for a response message from the agent on a conversation.
|
|
166
|
+
*/
|
|
167
|
+
private async waitForResponse(
|
|
168
|
+
conversation: any,
|
|
169
|
+
timeout: number
|
|
170
|
+
): Promise<TaskResult> {
|
|
171
|
+
return new Promise<TaskResult>(async (resolve) => {
|
|
172
|
+
const timer = setTimeout(() => {
|
|
173
|
+
resolve({
|
|
174
|
+
success: false,
|
|
175
|
+
error: `Timeout: No response after ${timeout}ms`
|
|
176
|
+
});
|
|
177
|
+
}, timeout);
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
const stream = await conversation.stream();
|
|
181
|
+
|
|
182
|
+
for await (const message of stream) {
|
|
183
|
+
// Skip our own messages
|
|
184
|
+
if ((message as any).senderInboxId === this.client.inboxId) continue;
|
|
185
|
+
|
|
186
|
+
clearTimeout(timer);
|
|
187
|
+
|
|
188
|
+
const content = (message as any).content;
|
|
189
|
+
if (typeof content !== 'string') {
|
|
190
|
+
resolve({ success: true, raw: String(content) });
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Try to parse as JSON
|
|
195
|
+
try {
|
|
196
|
+
const json = JSON.parse(content);
|
|
197
|
+
|
|
198
|
+
// 402 Payment Required
|
|
199
|
+
if (json.type === "PAYMENT_REQUIRED") {
|
|
200
|
+
resolve({
|
|
201
|
+
success: false,
|
|
202
|
+
paymentRequired: json.payment,
|
|
203
|
+
raw: content
|
|
204
|
+
});
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// JSON-RPC error
|
|
209
|
+
if (json.error) {
|
|
210
|
+
resolve({
|
|
211
|
+
success: false,
|
|
212
|
+
error: json.error.message || JSON.stringify(json.error),
|
|
213
|
+
raw: content
|
|
214
|
+
});
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// JSON-RPC success
|
|
219
|
+
if (json.result !== undefined) {
|
|
220
|
+
resolve({
|
|
221
|
+
success: true,
|
|
222
|
+
result: json.result,
|
|
223
|
+
raw: content
|
|
224
|
+
});
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Generic JSON response
|
|
229
|
+
resolve({ success: true, result: json, raw: content });
|
|
230
|
+
return;
|
|
231
|
+
} catch {
|
|
232
|
+
// Plain text response
|
|
233
|
+
resolve({ success: true, result: content, raw: content });
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} catch (err: any) {
|
|
238
|
+
clearTimeout(timer);
|
|
239
|
+
resolve({
|
|
240
|
+
success: false,
|
|
241
|
+
error: err.message || "Stream error"
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Stream all incoming messages across all conversations.
|
|
249
|
+
* Calls the callback for each incoming message (skips own messages).
|
|
250
|
+
* Runs in the background — returns immediately.
|
|
251
|
+
*
|
|
252
|
+
* @param onMessage - Callback receiving (senderAddress, content, conversationId)
|
|
253
|
+
*/
|
|
254
|
+
public async streamAllMessages(
|
|
255
|
+
onMessage: (senderAddress: string, content: string, conversationId: string) => void
|
|
256
|
+
): Promise<void> {
|
|
257
|
+
// Sync all conversations and messages first
|
|
258
|
+
await this.client.conversations.syncAll();
|
|
259
|
+
|
|
260
|
+
const stream = await this.client.conversations.streamAllMessages({
|
|
261
|
+
consentStates: [ConsentState.Allowed, ConsentState.Unknown, ConsentState.Denied]
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Run in background (don't await)
|
|
265
|
+
(async () => {
|
|
266
|
+
try {
|
|
267
|
+
for await (const message of stream) {
|
|
268
|
+
// Skip our own messages
|
|
269
|
+
if ((message as any).senderInboxId === this.client.inboxId) continue;
|
|
270
|
+
|
|
271
|
+
const content = (message as any).content;
|
|
272
|
+
const conversationId = (message as any).conversationId || '';
|
|
273
|
+
const senderAddress = (message as any).senderInboxId || 'unknown';
|
|
274
|
+
|
|
275
|
+
onMessage(senderAddress, String(content), conversationId);
|
|
276
|
+
}
|
|
277
|
+
} catch (err: any) {
|
|
278
|
+
console.error('[OpenAgentClient] Stream error:', err.message);
|
|
279
|
+
}
|
|
280
|
+
})();
|
|
281
|
+
}
|
|
282
|
+
}
|
package/src/index.ts
CHANGED