aixyz 0.27.1 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/app/adapters/express.ts +1 -1
- package/app/index.ts +22 -4
- package/app/plugin.ts +78 -3
- package/app/plugins/a2a.ts +37 -27
- package/app/plugins/erc-8004.ts +4 -6
- package/app/plugins/index-page/index.ts +6 -7
- package/app/plugins/mcp.ts +8 -9
- package/docs/api-reference/accepts.mdx +116 -0
- package/docs/api-reference/agent.mdx +63 -0
- package/docs/api-reference/agents.mdx +54 -0
- package/docs/api-reference/aixyz-config.mdx +105 -0
- package/docs/api-reference/aixyz-model-fake.mdx +111 -0
- package/docs/api-reference/aixyz-server.mdx +106 -0
- package/docs/api-reference/experimental-stripe-payment-intent-plugin.mdx +90 -0
- package/docs/api-reference/tools.mdx +40 -0
- package/docs/api-reference/unstable-with-index-page.mdx +57 -0
- package/docs/config/aixyz-config.mdx +92 -0
- package/docs/config/environment-variables.mdx +77 -0
- package/docs/getting-started/agent-and-tools.mdx +197 -0
- package/docs/getting-started/deploying.mdx +116 -0
- package/docs/getting-started/installation.mdx +62 -0
- package/docs/getting-started/payments.mdx +108 -0
- package/docs/getting-started/project-structure.mdx +153 -0
- package/docs/getting-started/testing.mdx +122 -0
- package/docs/getting-started/why-bun.mdx +70 -0
- package/docs/index.mdx +62 -0
- package/docs/packages/aixyz.mdx +101 -0
- package/docs/packages/create-aixyz-app.mdx +95 -0
- package/docs/protocols/a2a.mdx +135 -0
- package/docs/protocols/erc-8004.mdx +125 -0
- package/docs/protocols/mcp.mdx +87 -0
- package/docs/protocols/x402.mdx +108 -0
- package/docs/templates/advanced/fake-llm.mdx +126 -0
- package/docs/templates/advanced/sub-agents.mdx +97 -0
- package/docs/templates/advanced/with-custom-facilitator.mdx +74 -0
- package/docs/templates/advanced/with-custom-server.mdx +88 -0
- package/docs/templates/advanced/with-express.mdx +101 -0
- package/docs/templates/advanced/with-tests.mdx +81 -0
- package/docs/templates/basic/boilerplate.mdx +73 -0
- package/docs/templates/basic/chainlink.mdx +72 -0
- package/docs/templates/basic/flights-search.mdx +74 -0
- package/docs/templates/basic/local-llm.mdx +98 -0
- package/docs/templates/overview.mdx +57 -0
- package/examples/boilerplate/README.md +59 -0
- package/examples/boilerplate/aixyz.config.ts +38 -0
- package/examples/boilerplate/app/agent.ts +33 -0
- package/examples/boilerplate/app/icon.svg +6 -0
- package/examples/boilerplate/app/tools/length.ts +45 -0
- package/examples/boilerplate/app/tools/temperature.ts +39 -0
- package/examples/boilerplate/app/tools/weight.ts +33 -0
- package/examples/boilerplate/package.json +18 -0
- package/examples/boilerplate/tsconfig.json +10 -0
- package/examples/boilerplate/vercel.json +5 -0
- package/examples/with-custom-facilitator/README.md +64 -0
- package/examples/with-custom-facilitator/aixyz.config.ts +13 -0
- package/examples/with-custom-facilitator/app/accepts.ts +5 -0
- package/examples/with-custom-facilitator/app/agent.ts +17 -0
- package/examples/with-custom-facilitator/app/tools/temperature.ts +23 -0
- package/examples/with-custom-facilitator/package.json +18 -0
- package/examples/with-custom-facilitator/tsconfig.json +10 -0
- package/examples/with-custom-facilitator/vercel.json +5 -0
- package/examples/with-express/aixyz.config.ts +13 -0
- package/examples/with-express/app/accepts.ts +5 -0
- package/examples/with-express/app/agent.ts +19 -0
- package/examples/with-express/app/server.test.ts +206 -0
- package/examples/with-express/app/server.ts +44 -0
- package/examples/with-express/app/tools/premium-temperature.ts +40 -0
- package/examples/with-express/app/tools/temperature.ts +42 -0
- package/examples/with-express/package.json +25 -0
- package/examples/with-express/tsconfig.json +11 -0
- package/package.json +7 -5
|
@@ -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. Creates a scoped `RegisterContext` that auto-tracks routes in `plugin.registeredRoutes`, calls `plugin.register(ctx)`, and returns `this` for chaining:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
await server.withPlugin(new IndexPagePlugin());
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `initialize()`
|
|
83
|
+
|
|
84
|
+
Initialize payment gateway and plugins. Passes an `InitializeContext` with read access to all routes, registered plugins, and payment gateway. Must be called after all plugins 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([{ exports: 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([{ exports: 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`)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "IndexPagePlugin"
|
|
3
|
+
description: "Add a human-readable text page to your agent server"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Adds a human-readable plain text page to your `AixyzApp` showing agent name, description, version, and skills.
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
import { IndexPagePlugin } from "aixyz/app/plugins/index-page";
|
|
10
|
+
|
|
11
|
+
await server.withPlugin(new IndexPagePlugin());
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Behavior
|
|
15
|
+
|
|
16
|
+
Registers a `GET` handler at the given path that responds with `text/plain` content:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
My Agent
|
|
20
|
+
========
|
|
21
|
+
|
|
22
|
+
Description: A helpful travel agent
|
|
23
|
+
Version: 0.1.0
|
|
24
|
+
|
|
25
|
+
Skills:
|
|
26
|
+
|
|
27
|
+
1. Search Flights
|
|
28
|
+
ID: search-flights
|
|
29
|
+
Description: Search for flights between airports
|
|
30
|
+
Tags: travel, flights
|
|
31
|
+
Examples:
|
|
32
|
+
- Find flights from SFO to LAX
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The output includes:
|
|
36
|
+
|
|
37
|
+
- Agent **name** and a separator line
|
|
38
|
+
- **Description** and **version** from config
|
|
39
|
+
- **Skills** list with IDs, descriptions, tags, and examples (if configured)
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
The auto-generated server registers the `IndexPagePlugin` automatically at `"/"`. In a custom server, register it explicitly:
|
|
44
|
+
|
|
45
|
+
```typescript title="app/server.ts"
|
|
46
|
+
import { AixyzApp } from "aixyz/app";
|
|
47
|
+
import { IndexPagePlugin } from "aixyz/app/plugins/index-page";
|
|
48
|
+
|
|
49
|
+
const server = new AixyzApp();
|
|
50
|
+
|
|
51
|
+
// Mount at root (default)
|
|
52
|
+
await server.withPlugin(new IndexPagePlugin());
|
|
53
|
+
|
|
54
|
+
await server.initialize();
|
|
55
|
+
|
|
56
|
+
export default server;
|
|
57
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "aixyz.config.ts"
|
|
3
|
+
description: "Complete reference for the aixyz configuration file"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Every aixyz project requires an `aixyz.config.ts` at the project root. This file defines your agent's identity, payment settings, and skills. It is validated at build time using Zod schemas.
|
|
7
|
+
|
|
8
|
+
## Full Example
|
|
9
|
+
|
|
10
|
+
```typescript title="aixyz.config.ts"
|
|
11
|
+
import type { AixyzConfig } from "aixyz/config";
|
|
12
|
+
|
|
13
|
+
const config: AixyzConfig = {
|
|
14
|
+
name: "Weather Agent",
|
|
15
|
+
description: "Get current weather for any location worldwide.",
|
|
16
|
+
version: "0.1.0",
|
|
17
|
+
url: "https://my-agent.vercel.app",
|
|
18
|
+
x402: {
|
|
19
|
+
payTo: "0x...",
|
|
20
|
+
network: "eip155:8453",
|
|
21
|
+
},
|
|
22
|
+
skills: [
|
|
23
|
+
{
|
|
24
|
+
id: "get-weather",
|
|
25
|
+
name: "Get Weather",
|
|
26
|
+
description: "Get current weather conditions for any city",
|
|
27
|
+
tags: ["weather"],
|
|
28
|
+
examples: ["What's the weather in Tokyo?"],
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default config;
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Config Fields
|
|
37
|
+
|
|
38
|
+
| Field | Type | Required | Description |
|
|
39
|
+
| -------------- | -------------- | -------- | ---------------------------------------- |
|
|
40
|
+
| `name` | `string` | Yes | Agent display name |
|
|
41
|
+
| `description` | `string` | Yes | What the agent does |
|
|
42
|
+
| `version` | `string` | Yes | Semver version |
|
|
43
|
+
| `url` | `string` | No | Agent base URL (auto-detected on Vercel) |
|
|
44
|
+
| `x402` | `object` | Yes | Payment configuration |
|
|
45
|
+
| `x402.payTo` | `string` | Yes | EVM address to receive payments |
|
|
46
|
+
| `x402.network` | `string` | Yes | CAIP-2 chain ID (e.g., `eip155:8453`) |
|
|
47
|
+
| `skills` | `AgentSkill[]` | Yes | Skills exposed in the A2A agent card |
|
|
48
|
+
|
|
49
|
+
### `AgentSkill`
|
|
50
|
+
|
|
51
|
+
| Field | Type | Required | Description |
|
|
52
|
+
| ------------- | ---------- | -------- | ----------------------- |
|
|
53
|
+
| `id` | `string` | Yes | Unique skill identifier |
|
|
54
|
+
| `name` | `string` | Yes | Skill display name |
|
|
55
|
+
| `description` | `string` | Yes | What the skill does |
|
|
56
|
+
| `tags` | `string[]` | Yes | Categorization tags |
|
|
57
|
+
| `examples` | `string[]` | No | Example prompts |
|
|
58
|
+
| `inputModes` | `string[]` | No | Input MIME types |
|
|
59
|
+
| `outputModes` | `string[]` | No | Output MIME types |
|
|
60
|
+
|
|
61
|
+
## URL Resolution
|
|
62
|
+
|
|
63
|
+
If `url` is omitted, it is auto-detected in the following order:
|
|
64
|
+
|
|
65
|
+
1. `https://${VERCEL_PROJECT_PRODUCTION_URL}/` (when `VERCEL_ENV` is `"production"`)
|
|
66
|
+
2. `https://${VERCEL_URL}/` (Vercel preview/other environments)
|
|
67
|
+
3. `http://localhost:${PORT}/` (fallback, default port 3000)
|
|
68
|
+
|
|
69
|
+
## Payment Networks
|
|
70
|
+
|
|
71
|
+
| Network | CAIP-2 ID |
|
|
72
|
+
| ------------ | -------------- |
|
|
73
|
+
| Base | `eip155:8453` |
|
|
74
|
+
| Base Sepolia | `eip155:84532` |
|
|
75
|
+
| Ethereum | `eip155:1` |
|
|
76
|
+
|
|
77
|
+
Switch networks per environment:
|
|
78
|
+
|
|
79
|
+
```typescript title="aixyz.config.ts"
|
|
80
|
+
x402: {
|
|
81
|
+
payTo: "0x...",
|
|
82
|
+
network: process.env.NODE_ENV === "production" ? "eip155:8453" : "eip155:84532",
|
|
83
|
+
},
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Build-Time vs Runtime
|
|
87
|
+
|
|
88
|
+
At build time, the `AixyzConfigPlugin` resolves the full config and materializes a runtime-safe subset into the bundle. This means:
|
|
89
|
+
|
|
90
|
+
- `import config from "aixyz/config"` works at runtime without the config file
|
|
91
|
+
- Environment variables referenced in the config are baked in at build time
|
|
92
|
+
- The config file itself is not included in the output bundle
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Environment Variables"
|
|
3
|
+
description: "Configure your agent with .env files and environment variables"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## `.env` Files
|
|
7
|
+
|
|
8
|
+
aixyz loads environment variables from `.env` files in the following order (later files take precedence):
|
|
9
|
+
|
|
10
|
+
1. `.env` — Shared defaults
|
|
11
|
+
2. `.env.local` — Local overrides (gitignored)
|
|
12
|
+
3. `.env.$(NODE_ENV)` — e.g., `.env.production`
|
|
13
|
+
4. `.env.$(NODE_ENV).local` — e.g., `.env.production.local`
|
|
14
|
+
|
|
15
|
+
This matches the loading order used by Next.js.
|
|
16
|
+
|
|
17
|
+
<Note>`.env.local` is always gitignored. Use it for API keys and secrets during development.</Note>
|
|
18
|
+
|
|
19
|
+
## Common Variables
|
|
20
|
+
|
|
21
|
+
| Variable | Description |
|
|
22
|
+
| ---------------------- | ------------------------------------------------------ |
|
|
23
|
+
| `OPENAI_API_KEY` | OpenAI API key |
|
|
24
|
+
| `X402_PAY_TO` | Default payment recipient address |
|
|
25
|
+
| `X402_NETWORK` | Default payment network |
|
|
26
|
+
| `X402_FACILITATOR_URL` | Custom x402 facilitator URL |
|
|
27
|
+
| `CDP_API_KEY_ID` | Coinbase CDP key ID (switches to Coinbase facilitator) |
|
|
28
|
+
| `CDP_API_KEY_SECRET` | Coinbase CDP key secret |
|
|
29
|
+
| `STRIPE_SECRET_KEY` | Experimental Stripe adapter |
|
|
30
|
+
| `STRIPE_PRICE_CENTS` | Stripe price in cents (default: 100) |
|
|
31
|
+
|
|
32
|
+
## Using in Config
|
|
33
|
+
|
|
34
|
+
Reference environment variables directly in `aixyz.config.ts`:
|
|
35
|
+
|
|
36
|
+
```typescript title="aixyz.config.ts"
|
|
37
|
+
import type { AixyzConfig } from "aixyz/config";
|
|
38
|
+
|
|
39
|
+
const config: AixyzConfig = {
|
|
40
|
+
name: "My Agent",
|
|
41
|
+
description: "...",
|
|
42
|
+
version: "0.1.0",
|
|
43
|
+
x402: {
|
|
44
|
+
payTo: process.env.X402_PAY_TO!,
|
|
45
|
+
network: process.env.X402_NETWORK!,
|
|
46
|
+
},
|
|
47
|
+
skills: [],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default config;
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Testing Environment
|
|
54
|
+
|
|
55
|
+
For tests, `loadEnv` from `aixyz/test` loads `.env.test.local` (where your `OPENAI_API_KEY` lives for tests). `.env.local` is ignored during testing:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { loadEnv } from "aixyz/test";
|
|
59
|
+
|
|
60
|
+
describe("tests", () => {
|
|
61
|
+
loadEnv();
|
|
62
|
+
// process.env.OPENAI_API_KEY is now available
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Built-in Environment Variables
|
|
67
|
+
|
|
68
|
+
The CLI automatically sets these environment variables based on the command:
|
|
69
|
+
|
|
70
|
+
| Variable | `aixyz dev` | `aixyz build` | Description |
|
|
71
|
+
| ----------- | --------------- | -------------- | ---------------------------------------------------------------------------- |
|
|
72
|
+
| `NODE_ENV` | `"development"` | `"production"` | Standard Node.js environment indicator, for compatibility with node packages |
|
|
73
|
+
| `AIXYZ_ENV` | `"development"` | `"production"` | aixyz-specific environment indicator, mirrors `NODE_ENV` |
|
|
74
|
+
|
|
75
|
+
## Build-Time Resolution
|
|
76
|
+
|
|
77
|
+
Environment variables referenced in `aixyz.config.ts` are resolved and baked into the bundle at build time. The config file itself is not included in the output — only the resolved values.
|