From 99da55ae0d8f38b65c42f4324b053e85ca896c68 Mon Sep 17 00:00:00 2001
From: Philippe d'Argent
Date: Tue, 10 Jun 2025 22:24:50 +0200
Subject: [PATCH] Added a new action provider to call x402 protected api
---
typescript/.changeset/loud-jars-relate.md | 5 +
typescript/agentkit/README.md | 13 +
typescript/agentkit/package.json | 8 +-
.../agentkit/src/action-providers/index.ts | 1 +
.../src/action-providers/x402/README.md | 70 +++
.../src/action-providers/x402/index.ts | 1 +
.../src/action-providers/x402/schemas.ts | 26 +
.../x402/x402ActionProvider.test.ts | 523 ++++++++++++++++++
.../x402/x402ActionProvider.ts | 234 ++++++++
typescript/pnpm-lock.yaml | 346 +++---------
10 files changed, 964 insertions(+), 263 deletions(-)
create mode 100644 typescript/.changeset/loud-jars-relate.md
create mode 100644 typescript/agentkit/src/action-providers/x402/README.md
create mode 100644 typescript/agentkit/src/action-providers/x402/index.ts
create mode 100644 typescript/agentkit/src/action-providers/x402/schemas.ts
create mode 100644 typescript/agentkit/src/action-providers/x402/x402ActionProvider.test.ts
create mode 100644 typescript/agentkit/src/action-providers/x402/x402ActionProvider.ts
diff --git a/typescript/.changeset/loud-jars-relate.md b/typescript/.changeset/loud-jars-relate.md
new file mode 100644
index 000000000..f5259fd6f
--- /dev/null
+++ b/typescript/.changeset/loud-jars-relate.md
@@ -0,0 +1,5 @@
+---
+"@coinbase/agentkit": minor
+---
+
+Added a new action provider to call x402 protected api
diff --git a/typescript/agentkit/README.md b/typescript/agentkit/README.md
index f88c80a7b..76237b746 100644
--- a/typescript/agentkit/README.md
+++ b/typescript/agentkit/README.md
@@ -418,6 +418,19 @@ const agent = createReactAgent({
+X402
+
+
+ paid_request |
+ Makes HTTP requests to x402-protected API endpoints with automatic payment handling. |
+
+
+ fetch_payment_info |
+ Fetches payment information from x402-protected endpoints without making payments. |
+
+
+
+
ZeroDev Wallet
diff --git a/typescript/agentkit/package.json b/typescript/agentkit/package.json
index 3e79e7a34..5977fbb7a 100644
--- a/typescript/agentkit/package.json
+++ b/typescript/agentkit/package.json
@@ -48,18 +48,20 @@
"@privy-io/server-auth": "1.18.4",
"@solana/spl-token": "^0.4.12",
"@solana/web3.js": "^1.98.1",
+ "@zerodev/ecdsa-validator": "^5.4.5",
+ "@zerodev/intent": "^0.0.24",
+ "@zerodev/sdk": "^5.4.28",
+ "axios": "^1.9.0",
"bs58": "^4.0.1",
"canonicalize": "^2.1.0",
"decimal.js": "^10.5.0",
"ethers": "^6.13.5",
- "@zerodev/ecdsa-validator": "^5.4.5",
- "@zerodev/intent": "^0.0.24",
- "@zerodev/sdk": "^5.4.28",
"md5": "^2.3.0",
"opensea-js": "^7.1.18",
"reflect-metadata": "^0.2.2",
"twitter-api-v2": "^1.18.2",
"viem": "^2.22.16",
+ "x402-axios": "^0.3.3",
"zod": "^3.23.8"
},
"devDependencies": {
diff --git a/typescript/agentkit/src/action-providers/index.ts b/typescript/agentkit/src/action-providers/index.ts
index 13856ca53..2ea47ab83 100644
--- a/typescript/agentkit/src/action-providers/index.ts
+++ b/typescript/agentkit/src/action-providers/index.ts
@@ -28,4 +28,5 @@ export * from "./allora";
export * from "./flaunch";
export * from "./onramp";
export * from "./vaultsfyi";
+export * from "./x402";
export * from "./zerodev";
diff --git a/typescript/agentkit/src/action-providers/x402/README.md b/typescript/agentkit/src/action-providers/x402/README.md
new file mode 100644
index 000000000..0d540b73a
--- /dev/null
+++ b/typescript/agentkit/src/action-providers/x402/README.md
@@ -0,0 +1,70 @@
+# X402 Action Provider
+
+This directory contains the **X402ActionProvider** implementation, which provides actions to interact with **x402-protected APIs** that require payment to access.
+
+## Directory Structure
+
+```
+x402/
+├── x402ActionProvider.ts # Main provider with x402 payment functionality
+├── schemas.ts # x402 action schemas
+├── index.ts # Main exports
+└── README.md # This file
+```
+
+## Actions
+
+- `paid_request`: Make HTTP requests to x402-protected API endpoints with automatic payment handling
+- `fetch_payment_info`: Get payment information from x402-protected endpoints without making payments
+
+## Overview
+
+The x402 protocol enables APIs to require micropayments for access. When a client makes a request to a protected endpoint, the server responds with a `402 Payment Required` status code along with payment instructions. This action provider automatically handles the entire payment flow:
+
+1. Makes the initial request to the protected API
+2. If a 402 response is received, automatically processes the payment using the wallet
+3. Retries the request with payment proof
+4. Returns the API response data
+
+## Usage
+
+### `paid_request` Action
+
+The `paid_request` action accepts the following parameters:
+
+- **url**: The full URL of the x402-protected API endpoint
+- **method**: HTTP method (GET, POST, PUT, DELETE, PATCH) - defaults to GET
+- **headers**: Optional additional headers to include in the request
+- **body**: Optional request body for POST/PUT/PATCH requests
+
+### `fetch_payment_info` Action
+
+The `fetch_payment_info` action accepts the following parameters:
+
+- **url**: The full URL of the x402-protected API endpoint
+- **method**: HTTP method (GET, POST, PUT, DELETE, PATCH) - defaults to GET
+- **headers**: Optional additional headers to include in the request
+
+This action is useful for:
+- Checking payment requirements before committing to a paid request
+- Understanding the cost structure of an API
+- Getting details about accepted payment tokens and amounts
+- Debugging x402 payment configurations
+
+## Network Support
+
+The x402 provider currently supports the following networks:
+- `base-mainnet`
+- `base-sepolia`
+
+The provider requires EVM-compatible networks where the wallet can sign payment transactions.
+
+## Dependencies
+
+This action provider requires:
+- `axios` - For making HTTP requests
+- `x402-axios` - For handling x402 payment flows
+
+## Notes
+
+For more information on the **x402 protocol**, visit the [x402 documentation](https://x402.gitbook.io/x402/).
\ No newline at end of file
diff --git a/typescript/agentkit/src/action-providers/x402/index.ts b/typescript/agentkit/src/action-providers/x402/index.ts
new file mode 100644
index 000000000..670411a1e
--- /dev/null
+++ b/typescript/agentkit/src/action-providers/x402/index.ts
@@ -0,0 +1 @@
+export * from "./x402ActionProvider";
diff --git a/typescript/agentkit/src/action-providers/x402/schemas.ts b/typescript/agentkit/src/action-providers/x402/schemas.ts
new file mode 100644
index 000000000..a21d84dc2
--- /dev/null
+++ b/typescript/agentkit/src/action-providers/x402/schemas.ts
@@ -0,0 +1,26 @@
+import { z } from "zod";
+
+export const PaidRequestSchema = z
+ .object({
+ url: z.string().url().describe("The URL of the x402-protected API endpoint"),
+ method: z
+ .enum(["GET", "POST", "PUT", "DELETE", "PATCH"])
+ .default("GET")
+ .describe("The HTTP method to use for the request"),
+ headers: z.record(z.string()).optional().describe("Optional headers to include in the request"),
+ body: z.any().optional().describe("Optional request body for POST/PUT/PATCH requests"),
+ })
+ .strip()
+ .describe("Instructions for making a paid request to an x402-protected API");
+
+export const FetchPaymentInfoSchema = z
+ .object({
+ url: z.string().url().describe("The URL of the x402-protected API endpoint"),
+ method: z
+ .enum(["GET", "POST", "PUT", "DELETE", "PATCH"])
+ .default("GET")
+ .describe("The HTTP method to use for the request"),
+ headers: z.record(z.string()).optional().describe("Optional headers to include in the request"),
+ })
+ .strip()
+ .describe("Instructions for fetching payment information from an x402-protected API endpoint");
diff --git a/typescript/agentkit/src/action-providers/x402/x402ActionProvider.test.ts b/typescript/agentkit/src/action-providers/x402/x402ActionProvider.test.ts
new file mode 100644
index 000000000..ba4c3a4d6
--- /dev/null
+++ b/typescript/agentkit/src/action-providers/x402/x402ActionProvider.test.ts
@@ -0,0 +1,523 @@
+import { X402ActionProvider } from "./x402ActionProvider";
+import { EvmWalletProvider } from "../../wallet-providers";
+import { Network } from "../../network";
+import { AxiosError, AxiosResponse, AxiosRequestConfig, AxiosInstance } from "axios";
+import axios from "axios";
+import * as x402axios from "x402-axios";
+
+// Mock modules
+jest.mock("axios");
+jest.mock("x402-axios");
+
+// Create mock functions
+const mockRequest = jest.fn();
+
+// Create a complete mock axios instance
+const mockAxiosInstance = {
+ request: mockRequest,
+ get: jest.fn(),
+ delete: jest.fn(),
+ head: jest.fn(),
+ options: jest.fn(),
+ post: jest.fn(),
+ put: jest.fn(),
+ patch: jest.fn(),
+ getUri: jest.fn(),
+ defaults: {},
+ interceptors: {
+ request: { use: jest.fn(), eject: jest.fn(), clear: jest.fn() },
+ response: { use: jest.fn(), eject: jest.fn(), clear: jest.fn() },
+ },
+} as unknown as AxiosInstance;
+
+// Create a complete mock axios static
+const mockAxios = {
+ create: jest.fn().mockReturnValue(mockAxiosInstance),
+ request: mockRequest,
+ get: jest.fn(),
+ delete: jest.fn(),
+ head: jest.fn(),
+ options: jest.fn(),
+ post: jest.fn(),
+ put: jest.fn(),
+ patch: jest.fn(),
+ all: jest.fn(),
+ spread: jest.fn(),
+ isAxiosError: jest.fn(),
+ isCancel: jest.fn(),
+ CancelToken: {
+ source: jest.fn(),
+ },
+ VERSION: "1.x",
+} as unknown as jest.Mocked;
+
+const mockWithPaymentInterceptor = jest.fn().mockReturnValue(mockAxiosInstance);
+const mockDecodeXPaymentResponse = jest.fn();
+
+// Override the mocked modules
+(axios as jest.Mocked).create = mockAxios.create;
+(axios as jest.Mocked).request = mockRequest;
+(axios as jest.Mocked).isAxiosError = mockAxios.isAxiosError;
+
+// Mock x402-axios functions
+jest.mocked(x402axios.withPaymentInterceptor).mockImplementation(mockWithPaymentInterceptor);
+jest.mocked(x402axios.decodeXPaymentResponse).mockImplementation(mockDecodeXPaymentResponse);
+
+// Mock wallet provider
+const mockWalletProvider = {
+ toSigner: jest.fn().mockReturnValue("mock-signer"),
+} as unknown as EvmWalletProvider;
+
+// Sample responses based on real examples
+const MOCK_PAYMENT_INFO_RESPONSE = {
+ paymentRequired: true,
+ url: "https://www.x402.org/protected",
+ status: 402,
+ data: {
+ x402Version: 1,
+ error: "X-PAYMENT header is required",
+ accepts: [
+ {
+ scheme: "exact",
+ network: "base-sepolia",
+ maxAmountRequired: "10000",
+ resource: "https://www.x402.org/protected",
+ description: "Access to protected content",
+ mimeType: "application/json",
+ payTo: "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
+ maxTimeoutSeconds: 300,
+ asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
+ extra: {
+ name: "USDC",
+ version: "2",
+ },
+ },
+ ],
+ },
+};
+
+const MOCK_PAYMENT_RESPONSE = {
+ success: true,
+ transaction:
+ "0xcbc385789d3744b52af5106c32809534f64adcbe097e050ec03d6b53fed5d305" as `0x${string}`,
+ network: "base-sepolia" as const,
+ payer: "0xa8c1a5D3C372C65c04f91f87a43F549619A9483f" as `0x${string}`,
+};
+
+const MOCK_PAID_REQUEST_RESPONSE = {
+ success: true,
+ url: "https://www.x402.org/protected",
+ method: "GET",
+ status: 200,
+ data: "...",
+ paymentResponse: MOCK_PAYMENT_RESPONSE,
+};
+
+describe("X402ActionProvider", () => {
+ let provider: X402ActionProvider;
+
+ beforeEach(() => {
+ provider = new X402ActionProvider();
+ jest.clearAllMocks();
+
+ // Setup mocks
+ mockAxios.create.mockReturnValue(mockAxiosInstance);
+ mockWithPaymentInterceptor.mockReturnValue(mockAxiosInstance);
+
+ // Setup axios.isAxiosError mock
+ jest
+ .mocked(axios.isAxiosError)
+ .mockImplementation((error: unknown): boolean =>
+ Boolean(
+ error &&
+ typeof error === "object" &&
+ ("isAxiosError" in error || "response" in error || "request" in error),
+ ),
+ );
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe("supportsNetwork", () => {
+ it("should support base-mainnet", () => {
+ const network: Network = { protocolFamily: "evm", networkId: "base-mainnet" };
+ expect(provider.supportsNetwork(network)).toBe(true);
+ });
+
+ it("should support base-sepolia", () => {
+ const network: Network = { protocolFamily: "evm", networkId: "base-sepolia" };
+ expect(provider.supportsNetwork(network)).toBe(true);
+ });
+
+ it("should not support unsupported EVM networks", () => {
+ const network: Network = { protocolFamily: "evm", networkId: "ethereum" };
+ expect(provider.supportsNetwork(network)).toBe(false);
+ });
+
+ it("should not support non-EVM networks", () => {
+ const network: Network = { protocolFamily: "solana", networkId: "mainnet" };
+ expect(provider.supportsNetwork(network)).toBe(false);
+ });
+ });
+
+ describe("fetchPaymentInfo", () => {
+ it("should successfully fetch payment info for 402 response", async () => {
+ mockRequest.mockResolvedValue({
+ status: 402,
+ statusText: "Payment Required",
+ data: MOCK_PAYMENT_INFO_RESPONSE.data,
+ headers: {},
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse);
+
+ const result = await provider.fetchPaymentInfo(mockWalletProvider, {
+ url: "https://www.x402.org/protected",
+ method: "GET",
+ });
+
+ expect(mockRequest).toHaveBeenCalledWith({
+ url: "https://www.x402.org/protected",
+ method: "GET",
+ headers: undefined,
+ validateStatus: expect.any(Function),
+ });
+
+ const parsedResult = JSON.parse(result);
+ expect(parsedResult.paymentRequired).toBe(true);
+ expect(parsedResult.status).toBe(402);
+ expect(parsedResult.data).toEqual(MOCK_PAYMENT_INFO_RESPONSE.data);
+ });
+
+ it("should handle non-payment-protected endpoints", async () => {
+ mockRequest.mockResolvedValue({
+ status: 200,
+ statusText: "OK",
+ data: { message: "No payment required" },
+ headers: {},
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse);
+
+ const result = await provider.fetchPaymentInfo(mockWalletProvider, {
+ url: "https://api.example.com/free",
+ method: "GET",
+ });
+
+ const parsedResult = JSON.parse(result);
+ expect(parsedResult.paymentRequired).toBe(false);
+ expect(parsedResult.status).toBe(200);
+ expect(parsedResult.data).toEqual({ message: "No payment required" });
+ });
+
+ it("should handle 402 errors with payment details in headers", async () => {
+ mockDecodeXPaymentResponse.mockReturnValue(MOCK_PAYMENT_RESPONSE);
+
+ const error = new Error("Payment required") as AxiosError;
+ error.isAxiosError = true;
+ error.response = {
+ status: 402,
+ statusText: "Payment Required",
+ headers: {
+ "x-payment-response": "encoded-payment-data",
+ },
+ data: MOCK_PAYMENT_INFO_RESPONSE.data,
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse;
+
+ mockRequest.mockRejectedValue(error);
+
+ const result = await provider.fetchPaymentInfo(mockWalletProvider, {
+ url: "https://www.x402.org/protected",
+ method: "GET",
+ });
+
+ expect(mockDecodeXPaymentResponse).toHaveBeenCalledWith("encoded-payment-data");
+
+ const parsedResult = JSON.parse(result);
+ expect(parsedResult.paymentRequired).toBe(true);
+ expect(parsedResult.status).toBe(402);
+ expect(parsedResult.paymentDetails).toEqual(MOCK_PAYMENT_RESPONSE);
+ });
+
+ it("should fallback to JSON.parse when decodeXPaymentResponse fails", async () => {
+ const paymentDetailsJson = '{"amount": "10000"}';
+ mockDecodeXPaymentResponse.mockImplementation(() => {
+ throw new Error("Decode failed");
+ });
+
+ const error = new Error("Payment required") as AxiosError;
+ error.isAxiosError = true;
+ error.response = {
+ status: 402,
+ statusText: "Payment Required",
+ headers: {
+ "x-payment-response": paymentDetailsJson,
+ },
+ data: MOCK_PAYMENT_INFO_RESPONSE.data,
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse;
+
+ mockRequest.mockRejectedValue(error);
+
+ const result = await provider.fetchPaymentInfo(mockWalletProvider, {
+ url: "https://www.x402.org/protected",
+ method: "GET",
+ });
+
+ const parsedResult = JSON.parse(result);
+ expect(parsedResult.paymentDetails).toEqual({ amount: "10000" });
+ });
+
+ it("should handle payment header parsing failures", async () => {
+ mockDecodeXPaymentResponse.mockImplementation(() => {
+ throw new Error("Decode failed");
+ });
+
+ const error = new Error("Payment required") as AxiosError;
+ error.isAxiosError = true;
+ error.response = {
+ status: 402,
+ statusText: "Payment Required",
+ headers: {
+ "x-payment-response": "invalid-json",
+ },
+ data: MOCK_PAYMENT_INFO_RESPONSE.data,
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse;
+
+ mockRequest.mockRejectedValue(error);
+
+ const result = await provider.fetchPaymentInfo(mockWalletProvider, {
+ url: "https://www.x402.org/protected",
+ method: "GET",
+ });
+
+ const parsedResult = JSON.parse(result);
+ expect(parsedResult.paymentDetails.error).toBe("Failed to decode payment response");
+ expect(parsedResult.paymentDetails.rawHeader).toBe("invalid-json");
+ });
+
+ it("should handle non-402 HTTP errors", async () => {
+ const error = new Error("Server error") as AxiosError;
+ error.isAxiosError = true;
+ error.response = {
+ status: 500,
+ statusText: "Internal Server Error",
+ headers: {},
+ data: { error: "Internal server error" },
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse;
+
+ mockRequest.mockRejectedValue(error);
+
+ const result = await provider.fetchPaymentInfo(mockWalletProvider, {
+ url: "https://api.example.com/endpoint",
+ method: "GET",
+ });
+
+ expect(result).toContain("Error fetching payment info");
+ expect(result).toContain("HTTP 500");
+ expect(result).toContain("Internal server error");
+ });
+
+ it("should handle network errors", async () => {
+ const error = new Error("Network error") as AxiosError;
+ error.isAxiosError = true;
+ error.request = {};
+
+ mockRequest.mockRejectedValue(error);
+
+ const result = await provider.fetchPaymentInfo(mockWalletProvider, {
+ url: "https://api.example.com/endpoint",
+ method: "GET",
+ });
+
+ expect(result).toContain("Error fetching payment info");
+ expect(result).toContain("Network error");
+ });
+ });
+
+ describe("paidRequest", () => {
+ it("should successfully make a paid request with payment response", async () => {
+ mockDecodeXPaymentResponse.mockReturnValue(MOCK_PAYMENT_RESPONSE);
+
+ mockRequest.mockResolvedValue({
+ status: 200,
+ statusText: "OK",
+ data: MOCK_PAID_REQUEST_RESPONSE.data,
+ headers: {
+ "x-payment-response": "encoded-payment-response",
+ },
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse);
+
+ const result = await provider.paidRequest(mockWalletProvider, {
+ url: "https://www.x402.org/protected",
+ method: "GET",
+ });
+
+ expect(mockWithPaymentInterceptor).toHaveBeenCalledWith(mockAxiosInstance, "mock-signer");
+
+ expect(mockRequest).toHaveBeenCalledWith({
+ url: "https://www.x402.org/protected",
+ method: "GET",
+ headers: undefined,
+ data: undefined,
+ });
+
+ const parsedResult = JSON.parse(result);
+ expect(parsedResult.success).toBe(true);
+ expect(parsedResult.status).toBe(200);
+ expect(parsedResult.paymentResponse).toEqual(MOCK_PAYMENT_RESPONSE);
+ });
+
+ it("should handle successful request without payment", async () => {
+ mockRequest.mockResolvedValue({
+ status: 200,
+ statusText: "OK",
+ data: { message: "Success" },
+ headers: {},
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse);
+
+ const result = await provider.paidRequest(mockWalletProvider, {
+ url: "https://api.example.com/free",
+ method: "GET",
+ });
+
+ const parsedResult = JSON.parse(result);
+ expect(parsedResult.success).toBe(true);
+ expect(parsedResult.status).toBe(200);
+ expect(parsedResult.paymentResponse).toBe(null);
+ });
+
+ it("should fallback to JSON.parse when decodeXPaymentResponse fails", async () => {
+ const paymentResponseJson = '{"transaction": "0x123"}';
+
+ mockDecodeXPaymentResponse.mockImplementation(() => {
+ throw new Error("Decode failed");
+ });
+
+ mockRequest.mockResolvedValue({
+ status: 200,
+ statusText: "OK",
+ data: "Success",
+ headers: {
+ "x-payment-response": paymentResponseJson,
+ },
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse);
+
+ const result = await provider.paidRequest(mockWalletProvider, {
+ url: "https://www.x402.org/protected",
+ method: "GET",
+ });
+
+ const parsedResult = JSON.parse(result);
+ expect(parsedResult.paymentResponse).toEqual({ transaction: "0x123" });
+ });
+
+ it("should handle payment response parsing failures", async () => {
+ mockDecodeXPaymentResponse.mockImplementation(() => {
+ throw new Error("Decode failed");
+ });
+
+ mockRequest.mockResolvedValue({
+ status: 200,
+ statusText: "OK",
+ data: "Success",
+ headers: {
+ "x-payment-response": "invalid-json",
+ },
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse);
+
+ const result = await provider.paidRequest(mockWalletProvider, {
+ url: "https://www.x402.org/protected",
+ method: "GET",
+ });
+
+ const parsedResult = JSON.parse(result);
+ expect(parsedResult.paymentResponse.error).toBe("Failed to decode payment response");
+ expect(parsedResult.paymentResponse.rawHeader).toBe("invalid-json");
+ });
+
+ it("should handle HTTP errors", async () => {
+ const error = new Error("Bad request") as AxiosError;
+ error.isAxiosError = true;
+ error.response = {
+ status: 400,
+ statusText: "Bad Request",
+ headers: {},
+ data: { error: "Invalid parameters" },
+ config: {} as AxiosRequestConfig,
+ } as AxiosResponse;
+
+ mockRequest.mockRejectedValue(error);
+
+ const result = await provider.paidRequest(mockWalletProvider, {
+ url: "https://api.example.com/endpoint",
+ method: "POST",
+ body: { test: "data" },
+ });
+
+ expect(result).toContain("Error making paid request");
+ expect(result).toContain("HTTP 400");
+ expect(result).toContain("Invalid parameters");
+ });
+
+ it("should handle network errors", async () => {
+ const error = new Error("Connection timeout") as AxiosError;
+ error.isAxiosError = true;
+ error.request = {};
+
+ mockRequest.mockRejectedValue(error);
+
+ const result = await provider.paidRequest(mockWalletProvider, {
+ url: "https://api.example.com/endpoint",
+ method: "GET",
+ });
+
+ expect(result).toContain("Error making paid request");
+ expect(result).toContain("Network error");
+ expect(result).toContain("Connection timeout");
+ });
+
+ it("should handle generic errors", async () => {
+ const error = new Error("Something went wrong");
+
+ mockRequest.mockRejectedValue(error);
+
+ const result = await provider.paidRequest(mockWalletProvider, {
+ url: "https://api.example.com/endpoint",
+ method: "GET",
+ });
+
+ expect(result).toContain("Error making paid request");
+ expect(result).toContain("Something went wrong");
+ });
+
+ it("should pass through all request parameters", async () => {
+ mockRequest.mockResolvedValue({
+ status: 200,
+ data: "Success",
+ headers: {},
+ } as AxiosResponse);
+
+ await provider.paidRequest(mockWalletProvider, {
+ url: "https://api.example.com/endpoint",
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: { key: "value" },
+ });
+
+ expect(mockRequest).toHaveBeenCalledWith({
+ url: "https://api.example.com/endpoint",
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ data: { key: "value" },
+ });
+ });
+ });
+});
diff --git a/typescript/agentkit/src/action-providers/x402/x402ActionProvider.ts b/typescript/agentkit/src/action-providers/x402/x402ActionProvider.ts
new file mode 100644
index 000000000..19d3cf459
--- /dev/null
+++ b/typescript/agentkit/src/action-providers/x402/x402ActionProvider.ts
@@ -0,0 +1,234 @@
+import { z } from "zod";
+import { ActionProvider } from "../actionProvider";
+import { Network } from "../../network";
+import { CreateAction } from "../actionDecorator";
+import { PaidRequestSchema, FetchPaymentInfoSchema } from "./schemas";
+import { EvmWalletProvider } from "../../wallet-providers";
+import axios, { AxiosError } from "axios";
+import { withPaymentInterceptor, decodeXPaymentResponse } from "x402-axios";
+
+const SUPPORTED_NETWORKS = ["base-mainnet", "base-sepolia"];
+
+/**
+ * X402ActionProvider is an action provider for making paid requests to x402-protected APIs.
+ */
+export class X402ActionProvider extends ActionProvider {
+ /**
+ * Constructor for the X402ActionProvider.
+ */
+ constructor() {
+ super("x402", []);
+ }
+
+ /**
+ * Makes a paid request to an x402-protected API endpoint.
+ *
+ * @param walletProvider - The wallet provider to use for payment signing.
+ * @param args - The input arguments for the action.
+ * @returns A message containing the API response data.
+ */
+ @CreateAction({
+ name: "paid_request",
+ description: `
+This tool makes HTTP requests to APIs that are protected by x402 paywalls. It automatically handles the payment flow when a 402 Payment Required response is received.
+
+Inputs:
+- url: The full URL of the x402-protected API endpoint
+- method: The HTTP method (GET, POST, PUT, DELETE, PATCH) - defaults to GET
+- headers: Optional additional headers to include in the request
+- body: Optional request body for POST/PUT/PATCH requests
+
+The tool will:
+1. Make the initial request to the protected endpoint
+2. If a 402 Payment Required response is received, automatically handle the payment using the wallet
+3. Retry the request with payment proof
+4. Return the API response data
+
+Supported on EVM networks where the wallet can sign payment transactions.
+`,
+ schema: PaidRequestSchema,
+ })
+ async paidRequest(
+ walletProvider: EvmWalletProvider,
+ args: z.infer,
+ ): Promise {
+ try {
+ // Get the viem account from the wallet provider for x402-axios
+ const account = walletProvider.toSigner();
+
+ // Create an axios instance with the payment interceptor
+ const api = withPaymentInterceptor(axios.create({}), account);
+
+ // Make the request
+ const response = await api.request({
+ url: args.url,
+ method: args.method,
+ headers: args.headers,
+ data: args.body,
+ });
+
+ // Extract payment information if available
+ const paymentResponseHeader = response.headers["x-payment-response"];
+ let paymentResponse: Record | null = null;
+
+ if (paymentResponseHeader) {
+ try {
+ paymentResponse = decodeXPaymentResponse(paymentResponseHeader);
+ } catch {
+ // Fall back to JSON parsing if decodeXPaymentResponse fails
+ try {
+ paymentResponse = JSON.parse(paymentResponseHeader);
+ } catch {
+ paymentResponse = {
+ error: "Failed to decode payment response",
+ rawHeader: paymentResponseHeader,
+ };
+ }
+ }
+ }
+
+ // Structure the response to clearly separate API response and payment details
+ const result = {
+ success: true,
+ url: args.url,
+ method: args.method,
+ status: response.status,
+ data: response.data,
+ paymentResponse: paymentResponse,
+ };
+
+ return JSON.stringify(result, null, 2);
+ } catch (error) {
+ const axiosError = error as AxiosError<{ error?: string }>;
+ if (axiosError.response) {
+ return `Error making paid request to ${args.url}: HTTP ${axiosError.response.status} - ${axiosError.response.data?.error || axiosError.response.statusText}`;
+ } else if (axiosError.request) {
+ return `Error making paid request to ${args.url}: Network error - ${axiosError.message}`;
+ } else {
+ return `Error making paid request to ${args.url}: ${axiosError.message}`;
+ }
+ }
+ }
+
+ /**
+ * Fetches payment information from an x402-protected API endpoint without making the payment.
+ *
+ * @param walletProvider - The wallet provider (not used for this action but required by interface).
+ * @param args - The input arguments for the action.
+ * @returns A message containing the payment requirements and endpoint information.
+ */
+ @CreateAction({
+ name: "fetch_payment_info",
+ description: `
+This tool fetches payment information from x402-protected API endpoints without actually making any payments. It's useful for checking payment requirements before deciding whether to proceed with a paid request.
+
+Inputs:
+- url: The full URL of the x402-protected API endpoint
+- method: The HTTP method (GET, POST, PUT, DELETE, PATCH) - defaults to GET
+- headers: Optional additional headers to include in the request
+
+The tool will:
+1. Make a request to the protected endpoint
+2. Receive the 402 Payment Required response with payment details
+3. Return information about the payment requirements (amount, token, etc.)
+
+Note: Payment amounts are returned in the smallest unit of the token. For example, for USDC (which has 6 decimal places) maxAmountRequired "10000" corresponds to 0.01 USDC.
+
+This is useful for understanding what payment will be required before using the paid_request action.
+`,
+ schema: FetchPaymentInfoSchema,
+ })
+ async fetchPaymentInfo(
+ walletProvider: EvmWalletProvider,
+ args: z.infer,
+ ): Promise {
+ try {
+ // Make a simple axios request without payment interceptor to get the 402 response
+ const response = await axios.request({
+ url: args.url,
+ method: args.method,
+ headers: args.headers,
+ validateStatus: status => status === 402 || (status >= 200 && status < 300), // Accept 402 responses
+ });
+
+ if (response.status === 402) {
+ return JSON.stringify(
+ {
+ paymentRequired: true,
+ url: args.url,
+ status: response.status,
+ data: response.data,
+ },
+ null,
+ 2,
+ );
+ } else {
+ // Endpoint is not payment-protected or request succeeded without payment
+ return JSON.stringify(
+ {
+ paymentRequired: false,
+ url: args.url,
+ status: response.status,
+ data: response.data,
+ },
+ null,
+ 2,
+ );
+ }
+ } catch (error) {
+ const axiosError = error as AxiosError<{ error?: string }>;
+ if (axiosError.response) {
+ if (axiosError.response.status === 402) {
+ // Handle 402 responses that axios might treat as errors
+ const paymentResponseHeader = axiosError.response.headers["x-payment-response"];
+ let paymentDetails: Record | null = null;
+
+ if (paymentResponseHeader) {
+ try {
+ paymentDetails = decodeXPaymentResponse(paymentResponseHeader);
+ } catch {
+ // Fall back to JSON parsing if decodeXPaymentResponse fails
+ try {
+ paymentDetails = JSON.parse(paymentResponseHeader);
+ } catch {
+ paymentDetails = {
+ error: "Failed to decode payment response",
+ rawHeader: paymentResponseHeader,
+ };
+ }
+ }
+ }
+
+ return JSON.stringify(
+ {
+ paymentRequired: true,
+ url: args.url,
+ status: 402,
+ paymentDetails: paymentDetails,
+ data: axiosError.response.data,
+ },
+ null,
+ 2,
+ );
+ } else {
+ return `Error fetching payment info from ${args.url}: HTTP ${axiosError.response.status} - ${axiosError.response.data?.error || axiosError.response.statusText}`;
+ }
+ } else if (axiosError.request) {
+ return `Error fetching payment info from ${args.url}: Network error - ${axiosError.message}`;
+ } else {
+ return `Error fetching payment info from ${args.url}: ${axiosError.message}`;
+ }
+ }
+ }
+
+ /**
+ * Checks if the X402 action provider supports the given network.
+ *
+ * @param network - The network to check.
+ * @returns True if the X402 action provider supports the network, false otherwise.
+ */
+ supportsNetwork = (network: Network) =>
+ network.protocolFamily === "evm" && SUPPORTED_NETWORKS.includes(network.networkId!);
+}
+
+export const x402ActionProvider = () => new X402ActionProvider();
diff --git a/typescript/pnpm-lock.yaml b/typescript/pnpm-lock.yaml
index 6d28c41c6..50d2ff5e0 100644
--- a/typescript/pnpm-lock.yaml
+++ b/typescript/pnpm-lock.yaml
@@ -98,6 +98,9 @@ importers:
'@zerodev/sdk':
specifier: ^5.4.28
version: 5.4.28(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2))
+ axios:
+ specifier: ^1.9.0
+ version: 1.9.0
bs58:
specifier: ^4.0.1
version: 4.0.1
@@ -125,6 +128,9 @@ importers:
viem:
specifier: ^2.22.16
version: 2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)
+ x402-axios:
+ specifier: ^0.3.3
+ version: 0.3.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
zod:
specifier: ^3.23.8
version: 3.24.2
@@ -152,7 +158,7 @@ importers:
version: 14.1.1
jest:
specifier: ^29.7.0
- version: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
+ version: 29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2))
mock-fs:
specifier: ^5.2.0
version: 5.5.0
@@ -170,7 +176,7 @@ importers:
version: 2.4.2
ts-jest:
specifier: ^29.2.5
- version: 29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)))(typescript@5.8.2)
+ version: 29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)))(typescript@5.8.2)
tsd:
specifier: ^0.31.2
version: 0.31.2
@@ -386,13 +392,13 @@ importers:
version: link:../../framework-extensions/langchain
'@langchain/core':
specifier: ^0.3.19
- version: 0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
+ version: 0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
'@langchain/langgraph':
specifier: ^0.2.21
- version: 0.2.59(@langchain/core@0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(react@18.3.1)(zod-to-json-schema@3.24.5(zod@3.24.2))
+ version: 0.2.59(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(react@18.3.1)(zod-to-json-schema@3.24.5(zod@3.24.2))
'@langchain/openai':
specifier: ^0.3.14
- version: 0.3.17(@langchain/core@0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))
+ version: 0.3.17(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))
'@solana/web3.js':
specifier: ^1.98.0
version: 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)
@@ -2014,8 +2020,8 @@ packages:
peerDependencies:
axios: 0.x || 1.x
- axios@1.8.4:
- resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==}
+ axios@1.9.0:
+ resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==}
babel-jest@29.7.0:
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
@@ -3775,6 +3781,7 @@ packages:
node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
+ deprecated: Use your platform's native DOMException instead
node-fetch-native@1.6.6:
resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==}
@@ -4968,6 +4975,12 @@ packages:
utf-8-validate:
optional: true
+ x402-axios@0.3.3:
+ resolution: {integrity: sha512-WaqYBO6QCLtON6YYHoN1vCxVaWXXTDOltZnwo7VjvWc9gYoQRismONVu2VC6PK5SHad+Ha9wsJJrgL9NBF83Bg==}
+
+ x402@0.3.7:
+ resolution: {integrity: sha512-8g2sXjWX7UbUNg9wJqgSBoYP7QV3/7qYYssdfPiQM5XDDThuVy7+MnH4cCuQ4UGGn2SVz1hpzWpwxMC3nwp+zA==}
+
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
@@ -5422,7 +5435,7 @@ snapshots:
dependencies:
'@solana/web3.js': 1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
abitype: 1.0.6(typescript@5.8.2)(zod@3.24.2)
- axios: 1.8.4
+ axios: 1.9.0
jose: 6.0.10
md5: 2.3.0
viem: 2.24.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)
@@ -5438,9 +5451,9 @@ snapshots:
dependencies:
'@scure/bip32': 1.6.2
abitype: 1.0.8(typescript@5.8.2)(zod@3.24.2)
- axios: 1.8.4
- axios-mock-adapter: 1.22.0(axios@1.8.4)
- axios-retry: 4.5.0(axios@1.8.4)
+ axios: 1.9.0
+ axios-mock-adapter: 1.22.0(axios@1.9.0)
+ axios-retry: 4.5.0(axios@1.9.0)
bip32: 4.0.0
bip39: 3.1.0
decimal.js: 10.5.0
@@ -5902,41 +5915,6 @@ snapshots:
- supports-color
- ts-node
- '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))':
- dependencies:
- '@jest/console': 29.7.0
- '@jest/reporters': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 20.17.27
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- ci-info: 3.9.0
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-resolve-dependencies: 29.7.0
- jest-runner: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- jest-watcher: 29.7.0
- micromatch: 4.0.8
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-ansi: 6.0.1
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
- - ts-node
-
'@jest/environment@29.7.0':
dependencies:
'@jest/fake-timers': 29.7.0
@@ -6079,23 +6057,6 @@ snapshots:
'@jup-ag/api@6.0.40': {}
- '@langchain/core@0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))':
- dependencies:
- '@cfworker/json-schema': 4.1.1
- ansi-styles: 5.2.0
- camelcase: 6.3.0
- decamelize: 1.2.0
- js-tiktoken: 1.0.19
- langsmith: 0.2.15(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
- mustache: 4.2.0
- p-queue: 6.6.2
- p-retry: 4.6.2
- uuid: 10.0.0
- zod: 3.24.2
- zod-to-json-schema: 3.24.5(zod@3.24.2)
- transitivePeerDependencies:
- - openai
-
'@langchain/core@0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))':
dependencies:
'@cfworker/json-schema': 4.1.1
@@ -6113,26 +6074,11 @@ snapshots:
transitivePeerDependencies:
- openai
- '@langchain/langgraph-checkpoint@0.0.16(@langchain/core@0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))':
- dependencies:
- '@langchain/core': 0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
- uuid: 10.0.0
-
'@langchain/langgraph-checkpoint@0.0.16(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))':
dependencies:
'@langchain/core': 0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
uuid: 10.0.0
- '@langchain/langgraph-sdk@0.0.60(@langchain/core@0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(react@18.3.1)':
- dependencies:
- '@types/json-schema': 7.0.15
- p-queue: 6.6.2
- p-retry: 4.6.2
- uuid: 9.0.1
- optionalDependencies:
- '@langchain/core': 0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
- react: 18.3.1
-
'@langchain/langgraph-sdk@0.0.60(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(react@18.3.1)':
dependencies:
'@types/json-schema': 7.0.15
@@ -6143,18 +6089,6 @@ snapshots:
'@langchain/core': 0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
react: 18.3.1
- '@langchain/langgraph@0.2.59(@langchain/core@0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(react@18.3.1)(zod-to-json-schema@3.24.5(zod@3.24.2))':
- dependencies:
- '@langchain/core': 0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
- '@langchain/langgraph-checkpoint': 0.0.16(@langchain/core@0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))
- '@langchain/langgraph-sdk': 0.0.60(@langchain/core@0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(react@18.3.1)
- uuid: 10.0.0
- zod: 3.24.2
- optionalDependencies:
- zod-to-json-schema: 3.24.5(zod@3.24.2)
- transitivePeerDependencies:
- - react
-
'@langchain/langgraph@0.2.59(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(react@18.3.1)(zod-to-json-schema@3.24.5(zod@3.24.2))':
dependencies:
'@langchain/core': 0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
@@ -6167,17 +6101,6 @@ snapshots:
transitivePeerDependencies:
- react
- '@langchain/openai@0.3.17(@langchain/core@0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))':
- dependencies:
- '@langchain/core': 0.3.30(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
- js-tiktoken: 1.0.19
- openai: 4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)
- zod: 3.24.2
- zod-to-json-schema: 3.24.5(zod@3.24.2)
- transitivePeerDependencies:
- - encoding
- - ws
-
'@langchain/openai@0.3.17(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)))(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))':
dependencies:
'@langchain/core': 0.3.30(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2))
@@ -6862,6 +6785,11 @@ snapshots:
typescript: 5.8.2
zod: 3.24.2
+ abitype@1.0.8(typescript@5.8.2)(zod@3.25.56):
+ optionalDependencies:
+ typescript: 5.8.2
+ zod: 3.25.56
+
abort-controller@3.0.0:
dependencies:
event-target-shim: 5.0.1
@@ -7003,18 +6931,18 @@ snapshots:
dependencies:
possible-typed-array-names: 1.1.0
- axios-mock-adapter@1.22.0(axios@1.8.4):
+ axios-mock-adapter@1.22.0(axios@1.9.0):
dependencies:
- axios: 1.8.4
+ axios: 1.9.0
fast-deep-equal: 3.1.3
is-buffer: 2.0.5
- axios-retry@4.5.0(axios@1.8.4):
+ axios-retry@4.5.0(axios@1.9.0):
dependencies:
- axios: 1.8.4
+ axios: 1.9.0
is-retry-allowed: 2.2.0
- axios@1.8.4:
+ axios@1.9.0:
dependencies:
follow-redirects: 1.15.9
form-data: 4.0.2
@@ -7367,21 +7295,6 @@ snapshots:
- supports-color
- ts-node
- create-jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)):
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-config: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
- jest-util: 29.7.0
- prompts: 2.4.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
create-require@1.1.1: {}
cross-spawn@7.0.6:
@@ -8616,25 +8529,6 @@ snapshots:
- supports-color
- ts-node
- jest-cli@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)):
- dependencies:
- '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- chalk: 4.1.2
- create-jest: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
- exit: 0.1.2
- import-local: 3.2.0
- jest-config: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
- jest-util: 29.7.0
- jest-validate: 29.7.0
- yargs: 17.7.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
jest-config@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)):
dependencies:
'@babel/core': 7.26.10
@@ -8666,68 +8560,6 @@ snapshots:
- babel-plugin-macros
- supports-color
- jest-config@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)):
- dependencies:
- '@babel/core': 7.26.10
- '@jest/test-sequencer': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.26.10)
- chalk: 4.1.2
- ci-info: 3.9.0
- deepmerge: 4.3.1
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-circus: 29.7.0
- jest-environment-node: 29.7.0
- jest-get-type: 29.6.3
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-runner: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- micromatch: 4.0.8
- parse-json: 5.2.0
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-json-comments: 3.1.1
- optionalDependencies:
- '@types/node': 20.17.27
- ts-node: 10.9.2(@types/node@22.13.14)(typescript@5.8.2)
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
- jest-config@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)):
- dependencies:
- '@babel/core': 7.26.10
- '@jest/test-sequencer': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.26.10)
- chalk: 4.1.2
- ci-info: 3.9.0
- deepmerge: 4.3.1
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-circus: 29.7.0
- jest-environment-node: 29.7.0
- jest-get-type: 29.6.3
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-runner: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- micromatch: 4.0.8
- parse-json: 5.2.0
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-json-comments: 3.1.1
- optionalDependencies:
- '@types/node': 22.13.14
- ts-node: 10.9.2(@types/node@22.13.14)(typescript@5.8.2)
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
jest-diff@29.7.0:
dependencies:
chalk: 4.1.2
@@ -8955,18 +8787,6 @@ snapshots:
- supports-color
- ts-node
- jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)):
- dependencies:
- '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
- '@jest/types': 29.6.3
- import-local: 3.2.0
- jest-cli: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
jose@4.15.9: {}
jose@5.10.0: {}
@@ -9032,17 +8852,6 @@ snapshots:
kleur@3.0.3: {}
- langsmith@0.2.15(openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)):
- dependencies:
- '@types/uuid': 10.0.0
- commander: 10.0.1
- p-queue: 6.6.2
- p-retry: 4.6.2
- semver: 7.7.1
- uuid: 10.0.0
- optionalDependencies:
- openai: 4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)
-
langsmith@0.2.15(openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)):
dependencies:
'@types/uuid': 10.0.0
@@ -9374,21 +9183,6 @@ snapshots:
dependencies:
mimic-function: 5.0.1
- openai@4.89.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2):
- dependencies:
- '@types/node': 18.19.83
- '@types/node-fetch': 2.6.12
- abort-controller: 3.0.0
- agentkeepalive: 4.6.0
- form-data-encoder: 1.7.2
- formdata-node: 4.4.1
- node-fetch: 2.7.0
- optionalDependencies:
- ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)
- zod: 3.24.2
- transitivePeerDependencies:
- - encoding
-
openai@4.89.1(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2):
dependencies:
'@types/node': 18.19.83
@@ -9471,6 +9265,20 @@ snapshots:
transitivePeerDependencies:
- zod
+ ox@0.6.9(typescript@5.8.2)(zod@3.25.56):
+ dependencies:
+ '@adraffy/ens-normalize': 1.11.0
+ '@noble/curves': 1.8.1
+ '@noble/hashes': 1.7.1
+ '@scure/bip32': 1.6.2
+ '@scure/bip39': 1.5.4
+ abitype: 1.0.8(typescript@5.8.2)(zod@3.25.56)
+ eventemitter3: 5.0.1
+ optionalDependencies:
+ typescript: 5.8.2
+ transitivePeerDependencies:
+ - zod
+
p-filter@2.1.0:
dependencies:
p-map: 2.1.0
@@ -10173,26 +9981,6 @@ snapshots:
'@jest/types': 29.6.3
babel-jest: 29.7.0(@babel/core@7.26.10)
- ts-jest@29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)))(typescript@5.8.2):
- dependencies:
- bs-logger: 0.2.6
- ejs: 3.1.10
- fast-json-stable-stringify: 2.1.0
- jest: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
- jest-util: 29.7.0
- json5: 2.2.3
- lodash.memoize: 4.1.2
- make-error: 1.3.6
- semver: 7.7.1
- type-fest: 4.38.0
- typescript: 5.8.2
- yargs-parser: 21.1.1
- optionalDependencies:
- '@babel/core': 7.26.10
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.26.10)
-
ts-node@10.9.2(@types/node@18.19.83)(typescript@5.8.2):
dependencies:
'@cspotcode/source-map-support': 0.8.1
@@ -10499,6 +10287,23 @@ snapshots:
- utf-8-validate
- zod
+ viem@2.24.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56):
+ dependencies:
+ '@noble/curves': 1.8.1
+ '@noble/hashes': 1.7.1
+ '@scure/bip32': 1.6.2
+ '@scure/bip39': 1.5.4
+ abitype: 1.0.8(typescript@5.8.2)(zod@3.25.56)
+ isows: 1.0.6(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))
+ ox: 0.6.9(typescript@5.8.2)(zod@3.25.56)
+ ws: 8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)
+ optionalDependencies:
+ typescript: 5.8.2
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+ - zod
+
walker@1.0.8:
dependencies:
makeerror: 1.0.12
@@ -10613,6 +10418,27 @@ snapshots:
bufferutil: 4.0.9
utf-8-validate: 5.0.10
+ x402-axios@0.3.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10):
+ dependencies:
+ axios: 1.9.0
+ viem: 2.24.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)
+ x402: 0.3.7(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ zod: 3.25.56
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - typescript
+ - utf-8-validate
+
+ x402@0.3.7(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10):
+ dependencies:
+ viem: 2.24.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)
+ zod: 3.25.56
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+
y18n@5.0.8: {}
yallist@3.1.1: {}