agentic-x402 0.3.7 → 0.3.8
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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/scripts/plugin/tools.ts +50 -43
- package/scripts/plugin/types.ts +14 -5
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/scripts/plugin/tools.ts
CHANGED
|
@@ -4,20 +4,28 @@
|
|
|
4
4
|
import type { PluginTool } from './types.js';
|
|
5
5
|
import type { PaymentWatcher } from './watcher.js';
|
|
6
6
|
|
|
7
|
+
/** Helper to wrap a result as OpenClaw tool response */
|
|
8
|
+
function json(payload: unknown) {
|
|
9
|
+
return {
|
|
10
|
+
content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],
|
|
11
|
+
details: payload,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
8
16
|
return [
|
|
9
17
|
// 1. x402_balance
|
|
10
18
|
{
|
|
11
19
|
name: 'x402_balance',
|
|
12
20
|
description: 'Check wallet USDC and ETH balances on Base',
|
|
13
|
-
|
|
14
|
-
async execute() {
|
|
21
|
+
parameters: { type: 'object', properties: {} },
|
|
22
|
+
async execute(_toolCallId, _params) {
|
|
15
23
|
const { getClient, getWalletAddress, getUsdcBalance, getEthBalance } = await import('../core/client.js');
|
|
16
24
|
const client = getClient();
|
|
17
25
|
const address = getWalletAddress();
|
|
18
26
|
const [usdc, eth] = await Promise.all([getUsdcBalance(), getEthBalance()]);
|
|
19
27
|
|
|
20
|
-
return {
|
|
28
|
+
return json({
|
|
21
29
|
address,
|
|
22
30
|
network: client.config.network,
|
|
23
31
|
chainId: client.config.chainId,
|
|
@@ -25,7 +33,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
25
33
|
usdc: { raw: usdc.raw.toString(), formatted: usdc.formatted },
|
|
26
34
|
eth: { raw: eth.raw.toString(), formatted: eth.formatted },
|
|
27
35
|
},
|
|
28
|
-
};
|
|
36
|
+
});
|
|
29
37
|
},
|
|
30
38
|
},
|
|
31
39
|
|
|
@@ -33,7 +41,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
33
41
|
{
|
|
34
42
|
name: 'x402_pay',
|
|
35
43
|
description: 'Pay for an x402-gated resource. Returns the response body after payment.',
|
|
36
|
-
|
|
44
|
+
parameters: {
|
|
37
45
|
type: 'object',
|
|
38
46
|
properties: {
|
|
39
47
|
url: { type: 'string', description: 'URL of the x402-gated resource' },
|
|
@@ -44,7 +52,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
44
52
|
},
|
|
45
53
|
required: ['url'],
|
|
46
54
|
},
|
|
47
|
-
async execute(params) {
|
|
55
|
+
async execute(_toolCallId, params) {
|
|
48
56
|
const url = params.url as string;
|
|
49
57
|
const method = (params.method as string) || 'GET';
|
|
50
58
|
const body = params.body as string | undefined;
|
|
@@ -65,7 +73,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
65
73
|
const responseBody = contentType?.includes('json')
|
|
66
74
|
? await probe.json()
|
|
67
75
|
: await probe.text();
|
|
68
|
-
return { paid: false, status: probe.status, response: responseBody };
|
|
76
|
+
return json({ paid: false, status: probe.status, response: responseBody });
|
|
69
77
|
}
|
|
70
78
|
|
|
71
79
|
// Parse payment info
|
|
@@ -84,18 +92,18 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
84
92
|
const effectiveMax = maxPaymentUsd ?? client.config.maxPaymentUsd;
|
|
85
93
|
|
|
86
94
|
if (priceNum > effectiveMax) {
|
|
87
|
-
return { paid: false, error: `Price $${priceNum} exceeds max $${effectiveMax}`, paymentInfo };
|
|
95
|
+
return json({ paid: false, error: `Price $${priceNum} exceeds max $${effectiveMax}`, paymentInfo });
|
|
88
96
|
}
|
|
89
97
|
|
|
90
98
|
if (dryRun) {
|
|
91
|
-
return { paid: false, dryRun: true, price: priceNum, paymentInfo };
|
|
99
|
+
return json({ paid: false, dryRun: true, price: priceNum, paymentInfo });
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
// Execute payment
|
|
95
103
|
const response = await client.fetchWithPayment(url, { method, body, headers });
|
|
96
104
|
|
|
97
105
|
if (!response.ok) {
|
|
98
|
-
return { paid: false, error: `${response.status} ${response.statusText}` };
|
|
106
|
+
return json({ paid: false, error: `${response.status} ${response.statusText}` });
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
const contentType = response.headers.get('content-type');
|
|
@@ -112,7 +120,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
112
120
|
} catch { /* */ }
|
|
113
121
|
}
|
|
114
122
|
|
|
115
|
-
return { paid: true, price: priceNum, transactionHash: txHash, response: responseBody };
|
|
123
|
+
return json({ paid: true, price: priceNum, transactionHash: txHash, response: responseBody });
|
|
116
124
|
},
|
|
117
125
|
},
|
|
118
126
|
|
|
@@ -120,7 +128,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
120
128
|
{
|
|
121
129
|
name: 'x402_fetch',
|
|
122
130
|
description: 'Fetch a URL with automatic x402 payment handling. Simpler than x402_pay — just returns the content.',
|
|
123
|
-
|
|
131
|
+
parameters: {
|
|
124
132
|
type: 'object',
|
|
125
133
|
properties: {
|
|
126
134
|
url: { type: 'string', description: 'URL to fetch' },
|
|
@@ -129,7 +137,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
129
137
|
},
|
|
130
138
|
required: ['url'],
|
|
131
139
|
},
|
|
132
|
-
async execute(params) {
|
|
140
|
+
async execute(_toolCallId, params) {
|
|
133
141
|
const url = params.url as string;
|
|
134
142
|
const method = (params.method as string) || 'GET';
|
|
135
143
|
const body = params.body as string | undefined;
|
|
@@ -143,7 +151,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
143
151
|
const response = await client.fetchWithPayment(url, { method, body, headers });
|
|
144
152
|
|
|
145
153
|
if (!response.ok) {
|
|
146
|
-
return { success: false, status: response.status, error: response.statusText };
|
|
154
|
+
return json({ success: false, status: response.status, error: response.statusText });
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
const contentType = response.headers.get('content-type');
|
|
@@ -151,7 +159,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
151
159
|
? await response.json()
|
|
152
160
|
: await response.text();
|
|
153
161
|
|
|
154
|
-
return { success: true, status: response.status, response: responseBody };
|
|
162
|
+
return json({ success: true, status: response.status, response: responseBody });
|
|
155
163
|
},
|
|
156
164
|
},
|
|
157
165
|
|
|
@@ -159,7 +167,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
159
167
|
{
|
|
160
168
|
name: 'x402_create_link',
|
|
161
169
|
description: 'Create a payment link via 21.cash to sell gated content',
|
|
162
|
-
|
|
170
|
+
parameters: {
|
|
163
171
|
type: 'object',
|
|
164
172
|
properties: {
|
|
165
173
|
name: { type: 'string', description: 'Name of the payment link' },
|
|
@@ -171,7 +179,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
171
179
|
},
|
|
172
180
|
required: ['name', 'price'],
|
|
173
181
|
},
|
|
174
|
-
async execute(params) {
|
|
182
|
+
async execute(_toolCallId, params) {
|
|
175
183
|
const name = params.name as string;
|
|
176
184
|
const price = params.price as string;
|
|
177
185
|
const gatedUrl = params.url as string | undefined;
|
|
@@ -180,7 +188,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
180
188
|
const webhookUrl = params.webhookUrl as string | undefined;
|
|
181
189
|
|
|
182
190
|
if (!gatedUrl && !gatedText) {
|
|
183
|
-
return { success: false, error: 'Either url or text is required' };
|
|
191
|
+
return json({ success: false, error: 'Either url or text is required' });
|
|
184
192
|
}
|
|
185
193
|
|
|
186
194
|
const { getClient, getWalletAddress } = await import('../core/client.js');
|
|
@@ -210,10 +218,10 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
210
218
|
|
|
211
219
|
const data = await response.json();
|
|
212
220
|
if (!response.ok || !(data as Record<string, unknown>).success) {
|
|
213
|
-
return { success: false, error: (data as Record<string, unknown>).error ?? 'Unknown error' };
|
|
221
|
+
return json({ success: false, error: (data as Record<string, unknown>).error ?? 'Unknown error' });
|
|
214
222
|
}
|
|
215
223
|
|
|
216
|
-
return data;
|
|
224
|
+
return json(data);
|
|
217
225
|
},
|
|
218
226
|
},
|
|
219
227
|
|
|
@@ -221,14 +229,14 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
221
229
|
{
|
|
222
230
|
name: 'x402_link_info',
|
|
223
231
|
description: 'Get details about a payment link by router address',
|
|
224
|
-
|
|
232
|
+
parameters: {
|
|
225
233
|
type: 'object',
|
|
226
234
|
properties: {
|
|
227
235
|
routerAddress: { type: 'string', description: 'Router contract address or payment URL' },
|
|
228
236
|
},
|
|
229
237
|
required: ['routerAddress'],
|
|
230
238
|
},
|
|
231
|
-
async execute(params) {
|
|
239
|
+
async execute(_toolCallId, params) {
|
|
232
240
|
let routerAddress = params.routerAddress as string;
|
|
233
241
|
|
|
234
242
|
// Extract address from URL if needed
|
|
@@ -239,7 +247,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
239
247
|
}
|
|
240
248
|
|
|
241
249
|
if (!routerAddress.startsWith('0x') || routerAddress.length !== 42) {
|
|
242
|
-
return { success: false, error: 'Invalid router address' };
|
|
250
|
+
return json({ success: false, error: 'Invalid router address' });
|
|
243
251
|
}
|
|
244
252
|
|
|
245
253
|
const { getConfig } = await import('../core/config.js');
|
|
@@ -250,10 +258,10 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
250
258
|
const data = await response.json();
|
|
251
259
|
|
|
252
260
|
if (!response.ok || !(data as Record<string, unknown>).success) {
|
|
253
|
-
return { success: false, error: (data as Record<string, unknown>).error ?? 'Link not found' };
|
|
261
|
+
return json({ success: false, error: (data as Record<string, unknown>).error ?? 'Link not found' });
|
|
254
262
|
}
|
|
255
263
|
|
|
256
|
-
return data;
|
|
264
|
+
return json(data);
|
|
257
265
|
},
|
|
258
266
|
},
|
|
259
267
|
|
|
@@ -261,14 +269,13 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
261
269
|
{
|
|
262
270
|
name: 'x402_routers',
|
|
263
271
|
description: 'List payment routers where your wallet is a beneficiary',
|
|
264
|
-
|
|
272
|
+
parameters: {
|
|
265
273
|
type: 'object',
|
|
266
274
|
properties: {
|
|
267
275
|
withBalances: { type: 'boolean', description: 'Fetch on-chain USDC balance for each router' },
|
|
268
276
|
},
|
|
269
|
-
required: [],
|
|
270
277
|
},
|
|
271
|
-
async execute(params) {
|
|
278
|
+
async execute(_toolCallId, params) {
|
|
272
279
|
const withBalances = params.withBalances as boolean | undefined;
|
|
273
280
|
|
|
274
281
|
const { getWalletAddress } = await import('../core/client.js');
|
|
@@ -282,13 +289,13 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
282
289
|
const data = await response.json() as { success: boolean; links?: Array<Record<string, unknown>>; error?: string };
|
|
283
290
|
|
|
284
291
|
if (!response.ok || !data.success) {
|
|
285
|
-
return { success: false, error: data.error ?? 'Failed to fetch routers' };
|
|
292
|
+
return json({ success: false, error: data.error ?? 'Failed to fetch routers' });
|
|
286
293
|
}
|
|
287
294
|
|
|
288
295
|
const links = data.links ?? [];
|
|
289
296
|
|
|
290
297
|
if (!withBalances) {
|
|
291
|
-
return {
|
|
298
|
+
return json({
|
|
292
299
|
success: true,
|
|
293
300
|
address,
|
|
294
301
|
routers: links.map((l) => ({
|
|
@@ -298,7 +305,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
298
305
|
sharePercent: l.beneficiary_percentage,
|
|
299
306
|
createdAt: l.created_at,
|
|
300
307
|
})),
|
|
301
|
-
};
|
|
308
|
+
});
|
|
302
309
|
}
|
|
303
310
|
|
|
304
311
|
// Fetch balances
|
|
@@ -340,7 +347,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
340
347
|
};
|
|
341
348
|
}));
|
|
342
349
|
|
|
343
|
-
return { success: true, address, routers };
|
|
350
|
+
return json({ success: true, address, routers });
|
|
344
351
|
},
|
|
345
352
|
},
|
|
346
353
|
|
|
@@ -348,7 +355,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
348
355
|
{
|
|
349
356
|
name: 'x402_distribute',
|
|
350
357
|
description: 'Distribute (withdraw) USDC from a PaymentRouter contract',
|
|
351
|
-
|
|
358
|
+
parameters: {
|
|
352
359
|
type: 'object',
|
|
353
360
|
properties: {
|
|
354
361
|
routerAddress: { type: 'string', description: 'PaymentRouter contract address' },
|
|
@@ -356,12 +363,12 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
356
363
|
},
|
|
357
364
|
required: ['routerAddress'],
|
|
358
365
|
},
|
|
359
|
-
async execute(params) {
|
|
366
|
+
async execute(_toolCallId, params) {
|
|
360
367
|
const routerAddress = params.routerAddress as string;
|
|
361
368
|
const specifiedAmount = params.amount as string | undefined;
|
|
362
369
|
|
|
363
370
|
if (!routerAddress.startsWith('0x') || routerAddress.length !== 42) {
|
|
364
|
-
return { success: false, error: 'Invalid router address' };
|
|
371
|
+
return json({ success: false, error: 'Invalid router address' });
|
|
365
372
|
}
|
|
366
373
|
|
|
367
374
|
const { getClient } = await import('../core/client.js');
|
|
@@ -400,17 +407,17 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
400
407
|
});
|
|
401
408
|
|
|
402
409
|
if (routerBalance === 0n) {
|
|
403
|
-
return { success: false, error: 'Router has no USDC balance to distribute' };
|
|
410
|
+
return json({ success: false, error: 'Router has no USDC balance to distribute' });
|
|
404
411
|
}
|
|
405
412
|
|
|
406
413
|
let distributeAmount: bigint;
|
|
407
414
|
if (specifiedAmount) {
|
|
408
415
|
distributeAmount = parseUnits(specifiedAmount, 6);
|
|
409
416
|
if (distributeAmount > routerBalance) {
|
|
410
|
-
return {
|
|
417
|
+
return json({
|
|
411
418
|
success: false,
|
|
412
419
|
error: `Requested ${specifiedAmount} USDC exceeds balance ${formatUnits(routerBalance, 6)} USDC`,
|
|
413
|
-
};
|
|
420
|
+
});
|
|
414
421
|
}
|
|
415
422
|
} else {
|
|
416
423
|
distributeAmount = routerBalance;
|
|
@@ -426,7 +433,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
426
433
|
|
|
427
434
|
const receipt = await client.publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
428
435
|
|
|
429
|
-
return {
|
|
436
|
+
return json({
|
|
430
437
|
success: receipt.status === 'success',
|
|
431
438
|
routerAddress,
|
|
432
439
|
amount: formatUnits(distributeAmount, 6),
|
|
@@ -434,7 +441,7 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
434
441
|
transactionHash: txHash,
|
|
435
442
|
blockNumber: receipt.blockNumber.toString(),
|
|
436
443
|
status: receipt.status,
|
|
437
|
-
};
|
|
444
|
+
});
|
|
438
445
|
},
|
|
439
446
|
},
|
|
440
447
|
|
|
@@ -442,12 +449,12 @@ export function createTools(watcher: PaymentWatcher | null): PluginTool[] {
|
|
|
442
449
|
{
|
|
443
450
|
name: 'x402_watcher_status',
|
|
444
451
|
description: 'Get the status of the background payment watcher (tracked routers, payments detected)',
|
|
445
|
-
|
|
452
|
+
parameters: { type: 'object', properties: {} },
|
|
446
453
|
async execute() {
|
|
447
454
|
if (!watcher) {
|
|
448
|
-
return { running: false, error: 'Watcher is not enabled' };
|
|
455
|
+
return json({ running: false, error: 'Watcher is not enabled' });
|
|
449
456
|
}
|
|
450
|
-
return watcher.getStatus();
|
|
457
|
+
return json(watcher.getStatus());
|
|
451
458
|
},
|
|
452
459
|
},
|
|
453
460
|
];
|
package/scripts/plugin/types.ts
CHANGED
|
@@ -15,24 +15,33 @@ export interface PluginService {
|
|
|
15
15
|
stop(): Promise<void>;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
/** JSON Schema for tool
|
|
19
|
-
export interface
|
|
18
|
+
/** JSON Schema for tool parameters */
|
|
19
|
+
export interface ToolParameters {
|
|
20
20
|
type: 'object';
|
|
21
21
|
properties: Record<string, {
|
|
22
22
|
type: string;
|
|
23
|
-
description
|
|
23
|
+
description?: string;
|
|
24
24
|
enum?: string[];
|
|
25
25
|
default?: unknown;
|
|
26
26
|
}>;
|
|
27
27
|
required?: string[];
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/** Tool result content block */
|
|
31
|
+
export interface ToolResultContent {
|
|
32
|
+
type: 'text';
|
|
33
|
+
text: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
30
36
|
/** An agent tool registered by a plugin */
|
|
31
37
|
export interface PluginTool {
|
|
32
38
|
name: string;
|
|
33
39
|
description: string;
|
|
34
|
-
|
|
35
|
-
execute(params: Record<string, unknown>): Promise<
|
|
40
|
+
parameters: ToolParameters;
|
|
41
|
+
execute(toolCallId: string, params: Record<string, unknown>): Promise<{
|
|
42
|
+
content: ToolResultContent[];
|
|
43
|
+
details?: unknown;
|
|
44
|
+
}>;
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
/** Commander.js-style program for CLI registration */
|