aixyz 0.27.0 → 0.28.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.
Files changed (64) hide show
  1. package/docs/api-reference/accepts.mdx +116 -0
  2. package/docs/api-reference/agent.mdx +63 -0
  3. package/docs/api-reference/agents.mdx +54 -0
  4. package/docs/api-reference/aixyz-config.mdx +105 -0
  5. package/docs/api-reference/aixyz-model-fake.mdx +111 -0
  6. package/docs/api-reference/aixyz-server.mdx +106 -0
  7. package/docs/api-reference/experimental-stripe-payment-intent-plugin.mdx +90 -0
  8. package/docs/api-reference/tools.mdx +40 -0
  9. package/docs/api-reference/unstable-with-index-page.mdx +57 -0
  10. package/docs/config/aixyz-config.mdx +92 -0
  11. package/docs/config/environment-variables.mdx +77 -0
  12. package/docs/getting-started/agent-and-tools.mdx +197 -0
  13. package/docs/getting-started/deploying.mdx +116 -0
  14. package/docs/getting-started/installation.mdx +62 -0
  15. package/docs/getting-started/payments.mdx +108 -0
  16. package/docs/getting-started/project-structure.mdx +153 -0
  17. package/docs/getting-started/testing.mdx +122 -0
  18. package/docs/getting-started/why-bun.mdx +70 -0
  19. package/docs/index.mdx +62 -0
  20. package/docs/packages/aixyz.mdx +101 -0
  21. package/docs/packages/create-aixyz-app.mdx +95 -0
  22. package/docs/protocols/a2a.mdx +131 -0
  23. package/docs/protocols/erc-8004.mdx +126 -0
  24. package/docs/protocols/mcp.mdx +87 -0
  25. package/docs/protocols/x402.mdx +108 -0
  26. package/docs/templates/advanced/fake-llm.mdx +126 -0
  27. package/docs/templates/advanced/sub-agents.mdx +97 -0
  28. package/docs/templates/advanced/with-custom-facilitator.mdx +74 -0
  29. package/docs/templates/advanced/with-custom-server.mdx +88 -0
  30. package/docs/templates/advanced/with-express.mdx +101 -0
  31. package/docs/templates/advanced/with-tests.mdx +81 -0
  32. package/docs/templates/basic/boilerplate.mdx +73 -0
  33. package/docs/templates/basic/chainlink.mdx +72 -0
  34. package/docs/templates/basic/flights-search.mdx +74 -0
  35. package/docs/templates/basic/local-llm.mdx +98 -0
  36. package/docs/templates/overview.mdx +57 -0
  37. package/examples/boilerplate/README.md +59 -0
  38. package/examples/boilerplate/aixyz.config.ts +38 -0
  39. package/examples/boilerplate/app/agent.ts +33 -0
  40. package/examples/boilerplate/app/icon.svg +6 -0
  41. package/examples/boilerplate/app/tools/length.ts +45 -0
  42. package/examples/boilerplate/app/tools/temperature.ts +39 -0
  43. package/examples/boilerplate/app/tools/weight.ts +33 -0
  44. package/examples/boilerplate/package.json +18 -0
  45. package/examples/boilerplate/tsconfig.json +10 -0
  46. package/examples/boilerplate/vercel.json +5 -0
  47. package/examples/with-custom-facilitator/README.md +64 -0
  48. package/examples/with-custom-facilitator/aixyz.config.ts +13 -0
  49. package/examples/with-custom-facilitator/app/accepts.ts +5 -0
  50. package/examples/with-custom-facilitator/app/agent.ts +17 -0
  51. package/examples/with-custom-facilitator/app/tools/temperature.ts +23 -0
  52. package/examples/with-custom-facilitator/package.json +18 -0
  53. package/examples/with-custom-facilitator/tsconfig.json +10 -0
  54. package/examples/with-custom-facilitator/vercel.json +5 -0
  55. package/examples/with-express/aixyz.config.ts +13 -0
  56. package/examples/with-express/app/accepts.ts +5 -0
  57. package/examples/with-express/app/agent.ts +19 -0
  58. package/examples/with-express/app/server.test.ts +206 -0
  59. package/examples/with-express/app/server.ts +44 -0
  60. package/examples/with-express/app/tools/premium-temperature.ts +40 -0
  61. package/examples/with-express/app/tools/temperature.ts +42 -0
  62. package/examples/with-express/package.json +25 -0
  63. package/examples/with-express/tsconfig.json +11 -0
  64. package/package.json +7 -5
@@ -0,0 +1,116 @@
1
+ ---
2
+ title: "aixyz/accepts"
3
+ description: "Payment configuration types and facilitator client for x402 gating"
4
+ ---
5
+
6
+ Types and utilities for configuring x402 payment gating on agent and tool endpoints.
7
+
8
+ ```typescript
9
+ import type { Accepts, AcceptsX402, AcceptsFree } from "aixyz/accepts";
10
+ import { HTTPFacilitatorClient, facilitator } from "aixyz/accepts";
11
+ ```
12
+
13
+ ## Types
14
+
15
+ ### `Accepts`
16
+
17
+ Union type for payment configuration:
18
+
19
+ ```typescript
20
+ type Accepts = AcceptsX402 | AcceptsFree;
21
+ ```
22
+
23
+ ### `AcceptsX402`
24
+
25
+ Requires x402 exact payment:
26
+
27
+ ```typescript
28
+ type AcceptsX402 = {
29
+ scheme: "exact";
30
+ price: string; // USD string, e.g. "$0.005"
31
+ network?: string; // CAIP-2 chain ID, overrides config
32
+ payTo?: string; // EVM address, overrides config
33
+ };
34
+ ```
35
+
36
+ | Field | Type | Required | Description |
37
+ | --------- | -------- | -------- | ------------------------------------------------------------- |
38
+ | `scheme` | `string` | Yes | Must be `"exact"` |
39
+ | `price` | `string` | Yes | USD price string (e.g. `"$0.005"`) |
40
+ | `network` | `string` | No | CAIP-2 chain ID, overrides `x402.network` from config |
41
+ | `payTo` | `string` | No | EVM address to receive payment, overrides `x402.payTo` config |
42
+
43
+ ### `AcceptsFree`
44
+
45
+ No payment required:
46
+
47
+ ```typescript
48
+ type AcceptsFree = {
49
+ scheme: "free";
50
+ };
51
+ ```
52
+
53
+ ## Exports
54
+
55
+ ### `HTTPFacilitatorClient`
56
+
57
+ Client for communicating with an x402 facilitator service. Re-exported from `@x402/core/server`.
58
+
59
+ ```typescript
60
+ import { HTTPFacilitatorClient } from "aixyz/accepts";
61
+
62
+ const client = new HTTPFacilitatorClient({
63
+ url: "https://x402.use-agently.com/facilitator",
64
+ });
65
+ ```
66
+
67
+ ### `facilitator`
68
+
69
+ The default facilitator client used by `AixyzApp`. Points to the Agently-hosted x402 facilitator.
70
+
71
+ ```typescript
72
+ import { facilitator } from "aixyz/accepts";
73
+ ```
74
+
75
+ ### `AcceptsScheme`
76
+
77
+ Zod schema for validating `Accepts` objects at runtime:
78
+
79
+ ```typescript
80
+ import { AcceptsScheme } from "aixyz/accepts";
81
+
82
+ AcceptsScheme.parse({ scheme: "exact", price: "$0.005" });
83
+ ```
84
+
85
+ ## Usage
86
+
87
+ Agents and tools declare an `accepts` export to control x402 payment gating. Endpoints without `accepts` are **not registered**.
88
+
89
+ ```typescript title="app/agent.ts"
90
+ import type { Accepts } from "aixyz/accepts";
91
+
92
+ export const accepts: Accepts = {
93
+ scheme: "exact",
94
+ price: "$0.005",
95
+ };
96
+ ```
97
+
98
+ ```typescript title="app/tools/lookup.ts"
99
+ import type { Accepts } from "aixyz/accepts";
100
+
101
+ export const accepts: Accepts = {
102
+ scheme: "free",
103
+ };
104
+ ```
105
+
106
+ ### Custom facilitator
107
+
108
+ Create `app/accepts.ts` to override the default facilitator:
109
+
110
+ ```typescript title="app/accepts.ts"
111
+ import { HTTPFacilitatorClient } from "aixyz/accepts";
112
+
113
+ export const facilitator = new HTTPFacilitatorClient({
114
+ url: process.env.X402_FACILITATOR_URL ?? "https://x402.use-agently.com/facilitator",
115
+ });
116
+ ```
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: "agent.ts"
3
+ description: "Define your agent with Vercel AI SDK"
4
+ ---
5
+
6
+ The agent definition file. Must export a default `ToolLoopAgent` and optionally `accepts` for payment gating and `capabilities` for A2A agent card configuration.
7
+
8
+ ```typescript title="app/agent.ts"
9
+ import { openai } from "@ai-sdk/openai";
10
+ import { stepCountIs, ToolLoopAgent } from "ai";
11
+ import type { Accepts } from "aixyz/accepts";
12
+ import type { Capabilities } from "aixyz/app/plugins/a2a";
13
+ import weather from "./tools/weather";
14
+
15
+ export const accepts: Accepts = {
16
+ scheme: "exact",
17
+ price: "$0.005",
18
+ };
19
+
20
+ export const capabilities: Capabilities = {
21
+ streaming: false,
22
+ pushNotifications: false,
23
+ };
24
+
25
+ export default new ToolLoopAgent({
26
+ model: openai("gpt-4o-mini"),
27
+ instructions: "You are a helpful weather assistant.",
28
+ tools: { weather },
29
+ stopWhen: stepCountIs(10),
30
+ });
31
+ ```
32
+
33
+ ## Exports
34
+
35
+ | Export | Type | Required | Description |
36
+ | -------------- | --------------- | -------- | ------------------------------------------------------------------- |
37
+ | `default` | `ToolLoopAgent` | Yes | The agent instance |
38
+ | `accepts` | `Accepts` | No | Payment config — gates the A2A `/agent` route |
39
+ | `capabilities` | `Capabilities` | No | A2A capabilities — controls streaming and push notification support |
40
+
41
+ When `accepts` is exported, the `/agent` endpoint requires x402 payment. Without it, the agent is not registered on the A2A endpoint.
42
+
43
+ ## Capabilities
44
+
45
+ The optional `capabilities` export controls the A2A agent card's `capabilities` field and the executor's behavior:
46
+
47
+ ```typescript
48
+ import type { Capabilities } from "aixyz/app/plugins/a2a";
49
+
50
+ export const capabilities: Capabilities = {
51
+ streaming: false, // default: true
52
+ pushNotifications: false, // default: false
53
+ stateTransitionHistory: false, // default: undefined
54
+ };
55
+ ```
56
+
57
+ | Field | Type | Default | Description |
58
+ | ------------------------ | --------- | ----------- | ---------------------------------------------------- |
59
+ | `streaming` | `boolean` | `true` | Whether the agent streams responses via `textStream` |
60
+ | `pushNotifications` | `boolean` | `false` | Whether the agent supports push notifications |
61
+ | `stateTransitionHistory` | `boolean` | `undefined` | Whether the agent exposes state transition history |
62
+
63
+ When `streaming` is set to `false`, the executor uses `agent.generate()` instead of `agent.stream()`, returning the full response as a single artifact rather than streaming chunks. This is useful for agents backed by models or APIs that don't support streaming.
@@ -0,0 +1,54 @@
1
+ ---
2
+ title: "agents/[name].ts"
3
+ description: "Auto-discovered sub-agent definitions for multiple A2A endpoints"
4
+ ---
5
+
6
+ Each `.ts` file in `app/agents/` is auto-discovered and registered as a sub-agent on its own A2A endpoint.
7
+
8
+ ```typescript title="app/agents/research.ts"
9
+ import { openai } from "@ai-sdk/openai";
10
+ import { stepCountIs, ToolLoopAgent } from "ai";
11
+ import type { Accepts } from "aixyz/accepts";
12
+
13
+ export const accepts: Accepts = {
14
+ scheme: "exact",
15
+ price: "$0.005",
16
+ };
17
+
18
+ export default new ToolLoopAgent({
19
+ model: openai("gpt-4o-mini"),
20
+ instructions: "You are a research assistant specialized in finding and summarizing information.",
21
+ stopWhen: stepCountIs(10),
22
+ });
23
+ ```
24
+
25
+ Given the file `app/agents/research.ts`, the sub-agent is exposed at `/research/agent` with its agent card at `/research/.well-known/agent-card.json`.
26
+
27
+ ## Exports
28
+
29
+ | Export | Type | Required | Description |
30
+ | --------- | --------------- | -------- | ----------------------------------------------------------- |
31
+ | `default` | `ToolLoopAgent` | Yes | The agent instance |
32
+ | `accepts` | `Accepts` | No | Payment config — gates the sub-agent A2A endpoint with x402 |
33
+
34
+ When `accepts` is exported, the sub-agent endpoint requires x402 payment. Without it, the sub-agent is not registered.
35
+
36
+ ## Conventions
37
+
38
+ - **Auto-discovered** — All `.ts` files in `app/agents/` are registered automatically
39
+ - **Ignored files** — Files starting with `_` (e.g., `_helpers.ts`) are skipped
40
+ - **Routing** — The filename (without `.ts`) becomes the URL prefix (e.g., `research.ts` → `/research/agent`)
41
+
42
+ ## Multiple Sub-Agents
43
+
44
+ You can mix `app/agent.ts` (main agent) with `app/agents/` (sub-agents) in the same project:
45
+
46
+ ```
47
+ app/
48
+ agent.ts # → /agent
49
+ agents/
50
+ research.ts # → /research/agent
51
+ implement.ts # → /implement/agent
52
+ ```
53
+
54
+ This exposes three independent A2A endpoints from a single deployment.
@@ -0,0 +1,105 @@
1
+ ---
2
+ title: "aixyz/config"
3
+ description: "Agent configuration types and runtime config access"
4
+ ---
5
+
6
+ Provides the `AixyzConfig` type and functions to access your agent's configuration at runtime.
7
+
8
+ ```typescript
9
+ import type { AixyzConfig, AixyzConfigRuntime } from "aixyz/config";
10
+ import { getAixyzConfig, getAixyzConfigRuntime } from "aixyz/config";
11
+ ```
12
+
13
+ ## Types
14
+
15
+ ### `AixyzConfig`
16
+
17
+ The full configuration object parsed from `aixyz.config.ts`:
18
+
19
+ ```typescript
20
+ type AixyzConfig = {
21
+ name: string;
22
+ description: string;
23
+ version: string;
24
+ url?: string;
25
+ x402: {
26
+ payTo: string;
27
+ network: string; // CAIP-2 chain ID
28
+ };
29
+ build?: {
30
+ output?: "standalone" | "vercel";
31
+ includes?: string | string[];
32
+ excludes?: string | string[];
33
+ };
34
+ skills?: Skill[];
35
+ };
36
+ ```
37
+
38
+ ### `AixyzConfigRuntime`
39
+
40
+ The subset of config safe to access at runtime (excludes `x402` and `build`):
41
+
42
+ ```typescript
43
+ type AixyzConfigRuntime = {
44
+ name: string;
45
+ description: string;
46
+ version: string;
47
+ url: string;
48
+ skills: Skill[];
49
+ };
50
+ ```
51
+
52
+ ## Functions
53
+
54
+ ### `getAixyzConfig()`
55
+
56
+ Returns the full parsed config. Intended for build-time and CLI use.
57
+
58
+ ```typescript
59
+ const config = getAixyzConfig();
60
+ console.log(config.x402.payTo);
61
+ ```
62
+
63
+ ### `getAixyzConfigRuntime()`
64
+
65
+ Returns the runtime-safe subset of the config. Use this in your server code.
66
+
67
+ ```typescript
68
+ const config = getAixyzConfigRuntime();
69
+ console.log(config.name, config.version);
70
+ ```
71
+
72
+ ## Under the hood: materialization
73
+
74
+ When you run `aixyz build` or `aixyz dev`, the config is **materialized** into the bundle at build time. This means `getAixyzConfig()` and `getAixyzConfigRuntime()` don't read from the filesystem at runtime — they return a pre-computed JSON object that was inlined during the build.
75
+
76
+ The `AixyzConfigPlugin` in the CLI:
77
+
78
+ 1. Reads and validates your `aixyz.config.ts` at build time
79
+ 2. Resolves environment variables (e.g. `VERCEL_URL` for the `url` field)
80
+ 3. Replaces the `aixyz/config` module in the bundle with a static JSON literal:
81
+
82
+ ```typescript
83
+ // What your code imports:
84
+ import { getAixyzConfig } from "aixyz/config";
85
+
86
+ // What ends up in the bundle:
87
+ const config = { name: "my-agent", description: "..." /* ... */ };
88
+ export function getAixyzConfig() {
89
+ return config;
90
+ }
91
+ export function getAixyzConfigRuntime() {
92
+ return config;
93
+ }
94
+ ```
95
+
96
+ This means:
97
+
98
+ - **No filesystem access** at runtime — the config is baked into the bundle
99
+ - **Environment variables are resolved at build time** — changing `VERCEL_URL` after build has no effect on the config
100
+ - The bundle is fully self-contained and portable
101
+
102
+ <Info>
103
+ You don't need to call these functions directly in most cases. The auto-generated server, `A2APlugin`, and `MCPPlugin`
104
+ all read from the materialized config automatically.
105
+ </Info>
@@ -0,0 +1,111 @@
1
+ ---
2
+ title: "aixyz/model/fake"
3
+ description: "Deterministic fake language model for testing and development"
4
+ ---
5
+
6
+ A drop-in `LanguageModelV3` implementation that maps user messages through a transform function — no API key, no network calls, fully deterministic.
7
+
8
+ ```typescript
9
+ import { fake, type Prompt } from "aixyz/model";
10
+ ```
11
+
12
+ ## `fake(transform)`
13
+
14
+ Creates a fake language model conforming to the Vercel AI SDK `LanguageModelV3` specification. The returned model can be passed directly to `ToolLoopAgent` or any AI SDK function that accepts a `LanguageModel`.
15
+
16
+ ```typescript
17
+ function fake(transform: (lastMessage: string, prompt: Prompt) => string): LanguageModelV3;
18
+ ```
19
+
20
+ ### Parameters
21
+
22
+ | Parameter | Type | Description |
23
+ | ----------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
24
+ | `transform` | `(lastMessage: string, prompt: Prompt) => string` | Function that receives the last user message text and the full prompt, and returns the model output string |
25
+
26
+ The `transform` function receives two arguments:
27
+
28
+ - **`lastMessage`** — the text content of the most recent user message (empty string if none)
29
+ - **`prompt`** — the full `LanguageModelV3Prompt` conversation history, useful for tracking turn count or prior context
30
+
31
+ ### Return value
32
+
33
+ A `LanguageModelV3` object with:
34
+
35
+ - `specificationVersion: "v3"`
36
+ - `provider: "aixyz/fake"`
37
+ - `modelId: "aixyz/fake"`
38
+ - `doGenerate()` and `doStream()` that call your transform and report zero token usage
39
+
40
+ ### Examples
41
+
42
+ Simple echo:
43
+
44
+ ```typescript
45
+ import { fake } from "aixyz/model";
46
+
47
+ const model = fake((input) => `You said: ${input}`);
48
+ ```
49
+
50
+ Using full prompt context:
51
+
52
+ ```typescript
53
+ import { fake } from "aixyz/model";
54
+
55
+ const model = fake((input, prompt) => {
56
+ const turn = prompt.filter((m) => m.role === "user").length;
57
+ return `Turn ${turn}: ${input}`;
58
+ });
59
+ ```
60
+
61
+ Wiring into an agent:
62
+
63
+ ```typescript title="app/agent.ts"
64
+ import { fake } from "aixyz/model";
65
+ import { ToolLoopAgent } from "ai";
66
+
67
+ export const model = fake((input) => `Echo: ${input}`);
68
+
69
+ export default new ToolLoopAgent({
70
+ model,
71
+ instructions: "You echo back whatever the user says.",
72
+ });
73
+ ```
74
+
75
+ ## `Prompt`
76
+
77
+ Type alias for `LanguageModelV3Prompt` from `@ai-sdk/provider`. This is an array of messages where each message has a `role` and `content`:
78
+
79
+ ```typescript
80
+ import type { Prompt } from "aixyz/model";
81
+ ```
82
+
83
+ Use this type when you need to reference the prompt shape in your transform function or tests:
84
+
85
+ ```typescript
86
+ import { fake, type Prompt } from "aixyz/model";
87
+
88
+ const model = fake((_input: string, prompt: Prompt) => {
89
+ return `${prompt.length} messages in history`;
90
+ });
91
+ ```
92
+
93
+ ## Testing with `fake()`
94
+
95
+ The fake model makes every test deterministic and CI-safe. Export the model from your agent file so tests can call `doGenerate()` directly:
96
+
97
+ ```typescript title="app/agent.test.ts"
98
+ import { describe, expect, test } from "bun:test";
99
+ import { model } from "./agent";
100
+ import type { Prompt } from "aixyz/model";
101
+
102
+ describe("agent (fake model)", () => {
103
+ test("echoes the user message", async () => {
104
+ const prompt: Prompt = [{ role: "user", content: [{ type: "text", text: "hello" }] }];
105
+ const result = await model.doGenerate({ prompt });
106
+ expect(result.content).toEqual([{ type: "text", text: "Echo: hello" }]);
107
+ });
108
+ });
109
+ ```
110
+
111
+ See the [Testing guide](/getting-started/testing#fully-offline-tests-with-fake) and the [Fake Model Agent template](/templates/advanced/fake-llm) for complete examples.
@@ -0,0 +1,106 @@
1
+ ---
2
+ title: "aixyz/app"
3
+ description: "The core application class built on web-standard Request/Response"
4
+ ---
5
+
6
+ `AixyzApp` is a framework-agnostic server that manages route registration, middleware chaining, and optional x402 payment gating via a `PaymentGateway`. It uses web-standard `Request`/`Response` — no Express dependency.
7
+
8
+ ```typescript
9
+ import { AixyzApp } from "aixyz/app";
10
+ ```
11
+
12
+ ## Constructor
13
+
14
+ ```typescript
15
+ new AixyzApp(options?: AixyzAppOptions)
16
+ ```
17
+
18
+ | Parameter | Type | Default | Description |
19
+ | ---------------------- | ------------------------------------------ | ------- | ------------------------------- |
20
+ | `options.facilitators` | `FacilitatorClient \| FacilitatorClient[]` | — | Payment verification service(s) |
21
+
22
+ When `facilitators` is provided, a `PaymentGateway` is created and x402 payment verification is enabled for routes that declare a `payment` option.
23
+
24
+ After constructing, register plugins with `await server.withPlugin(...)`, then call `await server.initialize()` to finalize payment routes.
25
+
26
+ ## Properties
27
+
28
+ | Property | Type | Description |
29
+ | --------- | ----------------------------- | ---------------------------------------------------- |
30
+ | `routes` | `Map<string, RouteEntry>` | Registered routes, keyed by `"METHOD /path"` |
31
+ | `payment` | `PaymentGateway \| undefined` | Payment gateway (present when facilitators provided) |
32
+
33
+ ## Methods
34
+
35
+ ### `route(method, path, handler, options?)`
36
+
37
+ Register a route with an optional x402 payment requirement:
38
+
39
+ ```typescript
40
+ server.route("POST", "/agent", handler, {
41
+ payment: { scheme: "exact", price: "$0.005" },
42
+ });
43
+ ```
44
+
45
+ | Parameter | Type | Description |
46
+ | ----------------- | -------------- | ----------------------------------------------------- |
47
+ | `method` | `HttpMethod` | HTTP method (GET, POST, etc.) |
48
+ | `path` | `string` | Route path |
49
+ | `handler` | `RouteHandler` | `(request: Request) => Response \| Promise<Response>` |
50
+ | `options.payment` | `AcceptsX402` | Optional payment configuration |
51
+
52
+ ### `fetch(request)`
53
+
54
+ Dispatch a web-standard `Request` through payment verification, middleware chain, and route handler:
55
+
56
+ ```typescript
57
+ const response = await server.fetch(new Request("http://localhost/agent", { method: "POST" }));
58
+ ```
59
+
60
+ ### `use(middleware)`
61
+
62
+ Append a middleware to the chain. Middlewares run in registration order before the route handler:
63
+
64
+ ```typescript
65
+ server.use(async (request, next) => {
66
+ const response = await next();
67
+ return new Response(await response.text(), {
68
+ status: response.status,
69
+ headers: { ...Object.fromEntries(response.headers), "x-custom": "value" },
70
+ });
71
+ });
72
+ ```
73
+
74
+ ### `withPlugin(plugin)`
75
+
76
+ Register a plugin. Calls `plugin.register(this)` and returns `this` for chaining:
77
+
78
+ ```typescript
79
+ await server.withPlugin(new IndexPagePlugin());
80
+ ```
81
+
82
+ ### `initialize()`
83
+
84
+ Initialize payment gateway. Must be called after all routes are registered:
85
+
86
+ ```typescript
87
+ await server.initialize();
88
+ ```
89
+
90
+ ## Example
91
+
92
+ ```typescript title="app/server.ts"
93
+ import { AixyzApp } from "aixyz/app";
94
+ import { IndexPagePlugin } from "aixyz/app/plugins/index-page";
95
+ import { A2APlugin } from "aixyz/app/plugins/a2a";
96
+ import * as agent from "./agent";
97
+
98
+ const server = new AixyzApp();
99
+
100
+ await server.withPlugin(new IndexPagePlugin());
101
+ await server.withPlugin(new A2APlugin(agent));
102
+
103
+ await server.initialize();
104
+
105
+ export default server;
106
+ ```
@@ -0,0 +1,90 @@
1
+ ---
2
+ title: "experimental_StripePaymentIntentPlugin"
3
+ description: "Add Stripe PaymentIntent-based payments to your agent server"
4
+ ---
5
+
6
+ Adds Stripe PaymentIntent creation and validation to an `AixyzApp`, providing an alternative payment method alongside [x402](/protocols/x402).
7
+
8
+ ```typescript
9
+ import { experimental_StripePaymentIntentPlugin } from "@aixyz/stripe";
10
+ ```
11
+
12
+ <Warning>This API is experimental and may change significantly in future releases.</Warning>
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ bun add @aixyz/stripe
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```typescript
23
+ await server.withPlugin(new experimental_StripePaymentIntentPlugin());
24
+ ```
25
+
26
+ ## Environment Variables
27
+
28
+ | Variable | Required | Default | Description |
29
+ | -------------------- | -------- | ------- | ------------------------------ |
30
+ | `STRIPE_SECRET_KEY` | Yes | — | Stripe secret key |
31
+ | `STRIPE_PRICE_CENTS` | No | `100` | Price per request in USD cents |
32
+
33
+ If `STRIPE_SECRET_KEY` is not set, the function is a no-op — no endpoints or middleware are registered.
34
+
35
+ ## Registered Endpoints
36
+
37
+ ### `POST /stripe/create-payment-intent`
38
+
39
+ Creates a new Stripe PaymentIntent for the configured price.
40
+
41
+ **Response:**
42
+
43
+ ```json
44
+ {
45
+ "clientSecret": "pi_xxx_secret_xxx",
46
+ "paymentIntentId": "pi_xxx"
47
+ }
48
+ ```
49
+
50
+ ## Payment Middleware
51
+
52
+ After registering the `experimental_StripePaymentIntentPlugin`, the server checks incoming requests for the `x-stripe-payment-intent-id` header:
53
+
54
+ 1. If the header is present, it validates the PaymentIntent:
55
+ - Status must be `succeeded`
56
+ - Amount must meet the configured `STRIPE_PRICE_CENTS`
57
+ - Payment must not have been already consumed
58
+ 2. Valid payments are marked as consumed (one-time use) and the request proceeds
59
+ 3. Invalid payments return `402 Payment Required`
60
+ 4. If no header is present, the request falls through to x402 middleware
61
+
62
+ ## Usage
63
+
64
+ Use in a [custom server](/api-reference/agent) (`app/server.ts`):
65
+
66
+ ```typescript title="app/server.ts"
67
+ import { AixyzApp } from "aixyz/app";
68
+ import { IndexPagePlugin } from "aixyz/app/plugins/index-page";
69
+ import { A2APlugin } from "aixyz/app/plugins/a2a";
70
+ import { experimental_StripePaymentIntentPlugin } from "@aixyz/stripe";
71
+ import * as agent from "./agent";
72
+
73
+ const server = new AixyzApp();
74
+
75
+ await server.withPlugin(new IndexPagePlugin());
76
+
77
+ // Register Stripe before other plugins so the Stripe middleware runs first
78
+ await server.withPlugin(new experimental_StripePaymentIntentPlugin());
79
+
80
+ await server.withPlugin(new A2APlugin(agent));
81
+
82
+ await server.initialize();
83
+
84
+ export default server;
85
+ ```
86
+
87
+ <Note>
88
+ Register the `experimental_StripePaymentIntentPlugin` **before** A2A or MCP plugins so the Stripe middleware runs
89
+ first. If a valid Stripe payment is found, x402 verification is skipped.
90
+ </Note>
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: "tools/[name].ts"
3
+ description: "Auto-discovered tool definitions for A2A and MCP"
4
+ ---
5
+
6
+ Each `.ts` file in `app/tools/` is auto-discovered and registered as a tool on both A2A and MCP endpoints.
7
+
8
+ ```typescript title="app/tools/weather.ts"
9
+ import { tool } from "ai";
10
+ import { z } from "zod";
11
+ import type { Accepts } from "aixyz/accepts";
12
+
13
+ export const accepts: Accepts = {
14
+ scheme: "exact",
15
+ price: "$0.0001",
16
+ };
17
+
18
+ export default tool({
19
+ description: "Get current weather conditions for a city.",
20
+ inputSchema: z.object({
21
+ location: z.string().describe("City name"),
22
+ }),
23
+ execute: async ({ location }) => {
24
+ // your implementation
25
+ },
26
+ });
27
+ ```
28
+
29
+ ## Exports
30
+
31
+ | Export | Type | Required | Description |
32
+ | --------- | --------- | -------- | --------------------------------------------- |
33
+ | `default` | `tool()` | Yes | The tool instance |
34
+ | `accepts` | `Accepts` | No | Payment config — gates the tool on MCP `/mcp` |
35
+
36
+ ## Conventions
37
+
38
+ - **Auto-discovered** — All `.ts` files in `app/tools/` are registered automatically
39
+ - **Ignored files** — Files starting with `_` (e.g., `_helpers.ts`) are skipped
40
+ - **Naming** — The tool is registered with the filename as its name (e.g., `weather.ts` → `weather`)