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.
- 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 +131 -0
- package/docs/protocols/erc-8004.mdx +126 -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,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`)
|