@agentwonderland/mcp 0.1.32 → 0.1.33
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/dist/tools/run.js +39 -12
- package/dist/tools/solve.js +31 -12
- package/package.json +1 -1
- package/src/tools/run.ts +42 -17
- package/src/tools/solve.ts +34 -17
- package/test-x402-flow.mjs +58 -0
package/dist/tools/run.js
CHANGED
|
@@ -10,25 +10,52 @@ import { storeFeedbackToken } from "./_token-cache.js";
|
|
|
10
10
|
import { getOrCreatePendingCardSetup, formatCardSetupBlocks } from "../core/card-setup.js";
|
|
11
11
|
import { formatPaymentLabel, formatRunConfirmationCommand, resolveConfirmationMethod, } from "./_payment-confirmation.js";
|
|
12
12
|
const POLL_INTERVAL_MS = 3000;
|
|
13
|
-
const POLL_MAX_MS =
|
|
13
|
+
const POLL_MAX_MS = 300000;
|
|
14
|
+
// Collects every wallet address the consumer has configured so the poll below
|
|
15
|
+
// works regardless of which chain the job's `callerAddress` was stored on.
|
|
16
|
+
// `run_agent` runs can land as the MPP payer address, the MPP caller address,
|
|
17
|
+
// or (for credit-pack runs) the consumer principal — any of these may differ
|
|
18
|
+
// from `getWalletAddress(paymentMethod)`, which only returns one chain.
|
|
19
|
+
async function collectWalletAddresses(paymentMethod) {
|
|
20
|
+
const addresses = new Set();
|
|
21
|
+
const primary = await getWalletAddress(paymentMethod);
|
|
22
|
+
if (primary)
|
|
23
|
+
addresses.add(primary);
|
|
24
|
+
for (const chain of ["tempo", "base", "solana"]) {
|
|
25
|
+
const addr = await getWalletAddress(chain);
|
|
26
|
+
if (addr)
|
|
27
|
+
addresses.add(addr);
|
|
28
|
+
}
|
|
29
|
+
return [...addresses];
|
|
30
|
+
}
|
|
14
31
|
async function pollJobUntilDone(jobId, paymentMethod) {
|
|
15
32
|
const deadline = Date.now() + POLL_MAX_MS;
|
|
16
|
-
const
|
|
17
|
-
const
|
|
33
|
+
const walletAddresses = await collectWalletAddresses(paymentMethod);
|
|
34
|
+
const walletParams = walletAddresses.length > 0
|
|
35
|
+
? walletAddresses.map((a) => `?wallet=${encodeURIComponent(a)}`)
|
|
36
|
+
: [""];
|
|
18
37
|
while (Date.now() < deadline) {
|
|
19
38
|
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
for (const walletParam of walletParams) {
|
|
40
|
+
try {
|
|
41
|
+
const job = await apiGet(`/jobs/${jobId}${walletParam}`);
|
|
42
|
+
if (job.status === "completed") {
|
|
43
|
+
return { status: "completed", output: job.output };
|
|
44
|
+
}
|
|
45
|
+
if (job.status === "failed") {
|
|
46
|
+
return { status: "failed", output: job.output, error_code: job.error_code };
|
|
47
|
+
}
|
|
48
|
+
// status === "processing" — break out to next poll interval.
|
|
49
|
+
break;
|
|
24
50
|
}
|
|
25
|
-
|
|
26
|
-
|
|
51
|
+
catch (err) {
|
|
52
|
+
const status = err?.status;
|
|
53
|
+
// 404 means wrong wallet for this job — try the next address.
|
|
54
|
+
// Any other error: give up for this interval and retry after the sleep.
|
|
55
|
+
if (status !== 404)
|
|
56
|
+
break;
|
|
27
57
|
}
|
|
28
58
|
}
|
|
29
|
-
catch {
|
|
30
|
-
// Ignore poll errors until timeout.
|
|
31
|
-
}
|
|
32
59
|
}
|
|
33
60
|
return { status: "failed", error_code: "POLL_TIMEOUT" };
|
|
34
61
|
}
|
package/dist/tools/solve.js
CHANGED
|
@@ -10,25 +10,44 @@ import { storeFeedbackToken } from "./_token-cache.js";
|
|
|
10
10
|
import { formatPaymentLabel, formatSolveConfirmationCommand, makeSolvePendingKey, resolveConfirmationMethod, } from "./_payment-confirmation.js";
|
|
11
11
|
import { getActiveCreditPack, getCreditPackInventory, getCreditPackProgram } from "../core/passes.js";
|
|
12
12
|
const POLL_INTERVAL_MS = 3000;
|
|
13
|
-
const POLL_MAX_MS =
|
|
13
|
+
const POLL_MAX_MS = 300000;
|
|
14
|
+
async function collectWalletAddresses(paymentMethod) {
|
|
15
|
+
const addresses = new Set();
|
|
16
|
+
const primary = await getWalletAddress(paymentMethod);
|
|
17
|
+
if (primary)
|
|
18
|
+
addresses.add(primary);
|
|
19
|
+
for (const chain of ["tempo", "base", "solana"]) {
|
|
20
|
+
const addr = await getWalletAddress(chain);
|
|
21
|
+
if (addr)
|
|
22
|
+
addresses.add(addr);
|
|
23
|
+
}
|
|
24
|
+
return [...addresses];
|
|
25
|
+
}
|
|
14
26
|
async function pollSolveJob(jobId, paymentMethod) {
|
|
15
27
|
const deadline = Date.now() + POLL_MAX_MS;
|
|
16
|
-
const
|
|
17
|
-
const
|
|
28
|
+
const walletAddresses = await collectWalletAddresses(paymentMethod);
|
|
29
|
+
const walletParams = walletAddresses.length > 0
|
|
30
|
+
? walletAddresses.map((a) => `?wallet=${encodeURIComponent(a)}`)
|
|
31
|
+
: [""];
|
|
18
32
|
while (Date.now() < deadline) {
|
|
19
33
|
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
34
|
+
for (const walletParam of walletParams) {
|
|
35
|
+
try {
|
|
36
|
+
const job = await apiGet(`/jobs/${jobId}${walletParam}`);
|
|
37
|
+
if (job.status === "completed") {
|
|
38
|
+
return { status: "completed", output: job.output };
|
|
39
|
+
}
|
|
40
|
+
if (job.status === "failed") {
|
|
41
|
+
return { status: "failed", output: job.output, error_code: job.error_code };
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
24
44
|
}
|
|
25
|
-
|
|
26
|
-
|
|
45
|
+
catch (err) {
|
|
46
|
+
const status = err?.status;
|
|
47
|
+
if (status !== 404)
|
|
48
|
+
break;
|
|
27
49
|
}
|
|
28
50
|
}
|
|
29
|
-
catch {
|
|
30
|
-
// Ignore poll errors and keep trying.
|
|
31
|
-
}
|
|
32
51
|
}
|
|
33
52
|
return { status: "failed", error_code: "POLL_TIMEOUT" };
|
|
34
53
|
}
|
package/package.json
CHANGED
package/src/tools/run.ts
CHANGED
|
@@ -29,33 +29,58 @@ import {
|
|
|
29
29
|
import type { AgentRecord } from "../core/types.js";
|
|
30
30
|
|
|
31
31
|
const POLL_INTERVAL_MS = 3000;
|
|
32
|
-
const POLL_MAX_MS =
|
|
32
|
+
const POLL_MAX_MS = 300000;
|
|
33
|
+
|
|
34
|
+
// Collects every wallet address the consumer has configured so the poll below
|
|
35
|
+
// works regardless of which chain the job's `callerAddress` was stored on.
|
|
36
|
+
// `run_agent` runs can land as the MPP payer address, the MPP caller address,
|
|
37
|
+
// or (for credit-pack runs) the consumer principal — any of these may differ
|
|
38
|
+
// from `getWalletAddress(paymentMethod)`, which only returns one chain.
|
|
39
|
+
async function collectWalletAddresses(paymentMethod?: string): Promise<string[]> {
|
|
40
|
+
const addresses = new Set<string>();
|
|
41
|
+
const primary = await getWalletAddress(paymentMethod);
|
|
42
|
+
if (primary) addresses.add(primary);
|
|
43
|
+
for (const chain of ["tempo", "base", "solana"]) {
|
|
44
|
+
const addr = await getWalletAddress(chain);
|
|
45
|
+
if (addr) addresses.add(addr);
|
|
46
|
+
}
|
|
47
|
+
return [...addresses];
|
|
48
|
+
}
|
|
33
49
|
|
|
34
50
|
async function pollJobUntilDone(
|
|
35
51
|
jobId: string,
|
|
36
52
|
paymentMethod?: string,
|
|
37
53
|
): Promise<{ status: string; output?: unknown; error_code?: string }> {
|
|
38
54
|
const deadline = Date.now() + POLL_MAX_MS;
|
|
39
|
-
const
|
|
40
|
-
const
|
|
55
|
+
const walletAddresses = await collectWalletAddresses(paymentMethod);
|
|
56
|
+
const walletParams = walletAddresses.length > 0
|
|
57
|
+
? walletAddresses.map((a) => `?wallet=${encodeURIComponent(a)}`)
|
|
58
|
+
: [""];
|
|
41
59
|
|
|
42
60
|
while (Date.now() < deadline) {
|
|
43
61
|
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
for (const walletParam of walletParams) {
|
|
63
|
+
try {
|
|
64
|
+
const job = await apiGet<{
|
|
65
|
+
status: string;
|
|
66
|
+
output?: unknown;
|
|
67
|
+
error_code?: string;
|
|
68
|
+
}>(`/jobs/${jobId}${walletParam}`);
|
|
69
|
+
|
|
70
|
+
if (job.status === "completed") {
|
|
71
|
+
return { status: "completed", output: job.output };
|
|
72
|
+
}
|
|
73
|
+
if (job.status === "failed") {
|
|
74
|
+
return { status: "failed", output: job.output, error_code: job.error_code };
|
|
75
|
+
}
|
|
76
|
+
// status === "processing" — break out to next poll interval.
|
|
77
|
+
break;
|
|
78
|
+
} catch (err) {
|
|
79
|
+
const status = (err as { status?: number })?.status;
|
|
80
|
+
// 404 means wrong wallet for this job — try the next address.
|
|
81
|
+
// Any other error: give up for this interval and retry after the sleep.
|
|
82
|
+
if (status !== 404) break;
|
|
56
83
|
}
|
|
57
|
-
} catch {
|
|
58
|
-
// Ignore poll errors until timeout.
|
|
59
84
|
}
|
|
60
85
|
}
|
|
61
86
|
|
package/src/tools/solve.ts
CHANGED
|
@@ -27,33 +27,50 @@ import {
|
|
|
27
27
|
import { getActiveCreditPack, getCreditPackInventory, getCreditPackProgram } from "../core/passes.js";
|
|
28
28
|
|
|
29
29
|
const POLL_INTERVAL_MS = 3000;
|
|
30
|
-
const POLL_MAX_MS =
|
|
30
|
+
const POLL_MAX_MS = 300000;
|
|
31
|
+
|
|
32
|
+
async function collectWalletAddresses(paymentMethod?: string): Promise<string[]> {
|
|
33
|
+
const addresses = new Set<string>();
|
|
34
|
+
const primary = await getWalletAddress(paymentMethod);
|
|
35
|
+
if (primary) addresses.add(primary);
|
|
36
|
+
for (const chain of ["tempo", "base", "solana"]) {
|
|
37
|
+
const addr = await getWalletAddress(chain);
|
|
38
|
+
if (addr) addresses.add(addr);
|
|
39
|
+
}
|
|
40
|
+
return [...addresses];
|
|
41
|
+
}
|
|
31
42
|
|
|
32
43
|
async function pollSolveJob(
|
|
33
44
|
jobId: string,
|
|
34
45
|
paymentMethod?: string,
|
|
35
46
|
): Promise<{ status: string; output?: unknown; error_code?: string }> {
|
|
36
47
|
const deadline = Date.now() + POLL_MAX_MS;
|
|
37
|
-
const
|
|
38
|
-
const
|
|
48
|
+
const walletAddresses = await collectWalletAddresses(paymentMethod);
|
|
49
|
+
const walletParams = walletAddresses.length > 0
|
|
50
|
+
? walletAddresses.map((a) => `?wallet=${encodeURIComponent(a)}`)
|
|
51
|
+
: [""];
|
|
39
52
|
|
|
40
53
|
while (Date.now() < deadline) {
|
|
41
54
|
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
for (const walletParam of walletParams) {
|
|
56
|
+
try {
|
|
57
|
+
const job = await apiGet<{
|
|
58
|
+
status: string;
|
|
59
|
+
output?: unknown;
|
|
60
|
+
error_code?: string;
|
|
61
|
+
}>(`/jobs/${jobId}${walletParam}`);
|
|
62
|
+
|
|
63
|
+
if (job.status === "completed") {
|
|
64
|
+
return { status: "completed", output: job.output };
|
|
65
|
+
}
|
|
66
|
+
if (job.status === "failed") {
|
|
67
|
+
return { status: "failed", output: job.output, error_code: job.error_code };
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
} catch (err) {
|
|
71
|
+
const status = (err as { status?: number })?.status;
|
|
72
|
+
if (status !== 404) break;
|
|
54
73
|
}
|
|
55
|
-
} catch {
|
|
56
|
-
// Ignore poll errors and keep trying.
|
|
57
74
|
}
|
|
58
75
|
}
|
|
59
76
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// End-to-end x402 client test against prod Agent Wonderland on Base mainnet.
|
|
2
|
+
//
|
|
3
|
+
// 1. POST /x402/agents/:id/run (no PAYMENT header) → 402 with Stripe-issued payTo
|
|
4
|
+
// 2. Sign the payment authorization on Base mainnet with user's OWS-managed wallet
|
|
5
|
+
// 3. Retry with PAYMENT header → agent runs, USDC transferred to Stripe
|
|
6
|
+
//
|
|
7
|
+
// Then we inspect the resulting payment_attempt + transfer rows to confirm the
|
|
8
|
+
// Connect transfer is funded via source_transaction (same path MPP uses).
|
|
9
|
+
|
|
10
|
+
import { owsAccountFromWalletId } from "./src/core/ows-adapter.ts";
|
|
11
|
+
import { x402Client } from "@x402/core/client";
|
|
12
|
+
import { registerExactEvmScheme } from "@x402/evm/exact/client";
|
|
13
|
+
import { encodePaymentSignatureHeader } from "@x402/core/http";
|
|
14
|
+
|
|
15
|
+
const API = "https://api.agentwonderland.com";
|
|
16
|
+
const AGENT_SLUG = "diagram-renderer-qyf0";
|
|
17
|
+
const INPUT = { code: "graph TD; A-->B;", format: "png" };
|
|
18
|
+
const OWS_WALLET_ID = "9558b02c-93bf-480f-8708-5fe135bf53d9"; // from ~/.agentwonderland/config.json
|
|
19
|
+
|
|
20
|
+
// 1. Get the account
|
|
21
|
+
const account = await owsAccountFromWalletId(OWS_WALLET_ID);
|
|
22
|
+
console.log(`signer: ${account.address}`);
|
|
23
|
+
|
|
24
|
+
// 2. Fetch the 402 challenge
|
|
25
|
+
const first = await fetch(`${API}/x402/agents/${AGENT_SLUG}/run`, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: { "Content-Type": "application/json" },
|
|
28
|
+
body: JSON.stringify({ input: INPUT }),
|
|
29
|
+
});
|
|
30
|
+
console.log(`first response: ${first.status}`);
|
|
31
|
+
const paymentRequired = await first.json();
|
|
32
|
+
console.log("accepts[0].payTo:", paymentRequired.accepts?.[0]?.payTo);
|
|
33
|
+
console.log("payment_attempt_id:", paymentRequired.payment_attempt_id);
|
|
34
|
+
|
|
35
|
+
// 3. Build + sign the payment
|
|
36
|
+
const client = new x402Client();
|
|
37
|
+
registerExactEvmScheme(client, {
|
|
38
|
+
signer: account,
|
|
39
|
+
networks: ["eip155:8453"],
|
|
40
|
+
});
|
|
41
|
+
const paymentPayload = await client.createPaymentPayload(paymentRequired);
|
|
42
|
+
console.log("FULL payment payload:", JSON.stringify(paymentPayload, null, 2));
|
|
43
|
+
|
|
44
|
+
const paymentHeader = encodePaymentSignatureHeader(paymentPayload);
|
|
45
|
+
console.log("PAYMENT header length:", paymentHeader.length);
|
|
46
|
+
|
|
47
|
+
// 4. Retry with PAYMENT header
|
|
48
|
+
const second = await fetch(`${API}/x402/agents/${AGENT_SLUG}/run`, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers: {
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
PAYMENT: paymentHeader,
|
|
53
|
+
},
|
|
54
|
+
body: JSON.stringify({ input: INPUT }),
|
|
55
|
+
});
|
|
56
|
+
console.log(`second response: ${second.status}`);
|
|
57
|
+
const body = await second.text();
|
|
58
|
+
console.log("body preview:", body.slice(0, 400));
|