@ax-llm/ax 25.4.1 → 25.4.2

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.
@@ -0,0 +1,354 @@
1
+ # Ax Library (@ax-llm/ax) Quick Reference
2
+
3
+ Ax is a TypeScript library for building LLM-powered applications with type-safe signatures, streaming support, and multi-provider compatibility.
4
+
5
+
6
+ ## Imports & Factories
7
+
8
+ ```typescript
9
+ // Prefer factory functions: ax(), ai(), agent(), flow(); avoid class constructors.
10
+ import { ax, ai, f, s, fn, agent, flow, AxMemory, AxMCPClient } from '@ax-llm/ax';
11
+ import { z } from 'zod'; // optional — any Standard Schema v1 library works
12
+
13
+ // AI provider
14
+ const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_APIKEY });
15
+
16
+ // Generator (from string signature)
17
+ const gen = ax('question:string -> answer:string');
18
+
19
+ // Generator (from fluent signature)
20
+ const fluentGen = ax(
21
+ f()
22
+ .input('question', f.string('User question'))
23
+ .output('answer', f.string('AI response'))
24
+ .build()
25
+ );
26
+
27
+ // Generator (from zod — Standard Schema v1, also works with valibot/arktype)
28
+ const zodGen = ax(
29
+ f()
30
+ .input(z.object({ question: z.string().describe('User question') }))
31
+ .output(z.object({ answer: z.string().describe('AI response') }))
32
+ .build()
33
+ );
34
+
35
+ // Reusable signature
36
+ const sig = s('question:string, context:string[] -> answer:string');
37
+
38
+ // Agent
39
+ const myAgent = agent('userInput:string -> response:string', {
40
+ agentIdentity: {
41
+ name: 'helper',
42
+ description: 'A helpful assistant',
43
+ },
44
+ });
45
+
46
+ // Flow
47
+ const wf = flow<{ input: string }, { output: string }>()
48
+ .node('step1', 'input:string -> output:string')
49
+ .execute('step1', (state) => ({ input: state.input }))
50
+ .returns((state) => ({ output: state.step1Result.output }));
51
+
52
+ // Function tool — native fluent
53
+ const tool = fn('search')
54
+ .description('Search the web')
55
+ .arg('query', f.string('Search query'))
56
+ .returns(f.string('Search results'))
57
+ .handler(({ query }) => searchWeb(query))
58
+ .build();
59
+
60
+ // Function tool — zod schema (Standard Schema v1: also works with valibot, arktype)
61
+ const zodTool = fn('calculateTax')
62
+ .description('Calculate tax for an amount')
63
+ .arg(z.object({
64
+ amount: z.number().positive().describe('Pre-tax amount in USD'),
65
+ region: z.enum(['US', 'EU', 'UK']).describe('Tax region'),
66
+ }))
67
+ .returns(z.object({ tax: z.number(), total: z.number() }))
68
+ .handler(async ({ amount }) => ({ tax: amount * 0.1, total: amount * 1.1 }))
69
+ .build();
70
+ ```
71
+
72
+ ## Running
73
+
74
+ ```typescript
75
+ // Forward (blocking)
76
+ const result = await gen.forward(llm, { question: 'What is 2+2?' });
77
+
78
+ // Streaming
79
+ for await (const chunk of gen.streamingForward(llm, { question: 'Tell a story' })) {
80
+ if (chunk.delta.answer) process.stdout.write(chunk.delta.answer);
81
+ }
82
+ ```
83
+
84
+ ## Forward Options Quick Reference
85
+
86
+ Provider capabilities determine which outputs and options apply. Typesafe/Jev
87
+ and OpenAI Decisions support required boolean/class/rubric score signatures.
88
+ Use `(evidence)` or `.withEvidence()` for probabilities, scores, and native
89
+ confidence through AxGen; provenance distinguishes native and elicited evidence.
90
+ Use native clients for advanced request shapes, and generative providers for
91
+ prose or tools. See
92
+ the [ax-typesafe skill](https://github.com/ax-llm/ax/blob/main/src/ax/skills/ax-typesafe.md)
93
+ before applying the general generation options below to Jev.
94
+
95
+ | Goal | Option | Example |
96
+ |------|--------|---------|
97
+ | Model override | `model` | `{ model: 'gpt-5.4-mini' }` |
98
+ | Temperature | `modelConfig.temperature` | `{ modelConfig: { temperature: 0.8 } }` |
99
+ | Max tokens | `modelConfig.maxTokens` | `{ modelConfig: { maxTokens: 500 } }` |
100
+ | Retry on failure | `maxRetries` | `{ maxRetries: 3 }` |
101
+ | Max agent steps | `maxSteps` | `{ maxSteps: 10 }` |
102
+ | Fail fast | `fastFail` | `{ fastFail: true }` |
103
+ | Thinking budget | `thinkingTokenBudget` | `{ thinkingTokenBudget: 'medium' }` |
104
+ | Show thoughts | `showThoughts` | `{ showThoughts: true }` |
105
+ | Context caching | `contextCache` | `{ contextCache: { cacheBreakpoint: 'after-examples' } }` |
106
+ | Multi-sampling | `sampleCount` | `{ sampleCount: 5 }` |
107
+ | Debug logging | `debug` | `{ debug: true }` |
108
+ | Abort signal | `abortSignal` | `{ abortSignal: controller.signal }` |
109
+ | Memory | `mem` | `{ mem: new AxMemory() }` |
110
+ | Stop function | `stopFunction` | `{ stopFunction: 'finalAnswer' }` |
111
+ | Function mode | `functionCallMode` | `{ functionCallMode: 'auto' }` |
112
+
113
+ Global runtime defaults can be set with `axGlobals` and are read live by future AI, AxGen, and AxFlow calls:
114
+
115
+ ```typescript
116
+ import { axGlobals, axCreateDefaultColorLogger } from '@ax-llm/ax';
117
+ import { metrics, trace } from '@opentelemetry/api';
118
+
119
+ axGlobals.rateLimiter = async (next, info) => next();
120
+ axGlobals.tracer = trace.getTracer('my-app');
121
+ axGlobals.meter = metrics.getMeter('my-app');
122
+ axGlobals.debug = true;
123
+ axGlobals.logger = axCreateDefaultColorLogger();
124
+ ```
125
+
126
+ Runtime hooks resolve as: forward/direct-call hooks, enclosing program defaults, child-program defaults, AI-service hooks, then globals snapshotted at operation start. They are native run-scoped values and never enter AxIR JSON state, cache keys, exported state, traces, or optimizer artifacts. Agent and flow forwards carry them through every internal generator and model call without mutating children or leaking across concurrent runs. Limiter failures propagate; tracer, meter, and usage-observer failures are fail-open. `customLabels` merge by precedence, and `abortSignal` values are combined so either global or local cancellation works.
127
+
128
+ ## Memory and Context
129
+
130
+ ```typescript
131
+ import { AxMemory } from '@ax-llm/ax';
132
+
133
+ const memory = new AxMemory();
134
+
135
+ // Multi-turn conversation
136
+ await gen.forward(llm, { userMessage: 'My name is Alice' }, { mem: memory });
137
+ const r = await gen.forward(llm, { userMessage: 'What is my name?' }, { mem: memory });
138
+ ```
139
+
140
+ ## Few-Shot Examples
141
+
142
+ ```typescript
143
+ const classifier = ax('reviewText:string -> sentiment:class "positive, negative, neutral"');
144
+
145
+ classifier.setExamples([
146
+ { reviewText: 'I love this!', sentiment: 'positive' },
147
+ { reviewText: 'Terrible.', sentiment: 'negative' },
148
+ { reviewText: 'It works.', sentiment: 'neutral' },
149
+ ]);
150
+ ```
151
+
152
+ ## Common Patterns
153
+
154
+ ### Classification
155
+
156
+ ```typescript
157
+ const classifier = ax(
158
+ f()
159
+ .input('text', f.string())
160
+ .output('category', f.class(['spam', 'ham', 'uncertain']))
161
+ .output('confidence', f.number().min(0).max(1))
162
+ .build()
163
+ );
164
+ ```
165
+
166
+ ### Extraction
167
+
168
+ ```typescript
169
+ const extractor = ax(
170
+ f()
171
+ .input('text', f.string())
172
+ .output('entities', f.object({
173
+ people: f.string().array(),
174
+ organizations: f.string().array(),
175
+ locations: f.string().array()
176
+ }))
177
+ .build()
178
+ );
179
+ ```
180
+
181
+ ### Multi-modal (Images)
182
+
183
+ ```typescript
184
+ const analyzer = ax(
185
+ f()
186
+ .input('image', f.image('Image to analyze'))
187
+ .input('question', f.string('Question').optional())
188
+ .output('description', f.string())
189
+ .output('objects', f.string().array())
190
+ .build()
191
+ );
192
+
193
+ const result = await analyzer.forward(llm, {
194
+ image: { mimeType: 'image/jpeg', data: base64Data },
195
+ question: 'What objects are in this image?'
196
+ });
197
+ ```
198
+
199
+ ### Chaining Generators
200
+
201
+ ```typescript
202
+ const researcher = ax('topic:string -> research:string, keyFacts:string[]');
203
+ const writer = ax('research:string, keyFacts:string[] -> article:string');
204
+
205
+ const research = await researcher.forward(llm, { topic: 'AGI' });
206
+ const draft = await writer.forward(llm, { research: research.research, keyFacts: research.keyFacts });
207
+ ```
208
+
209
+ ## Error Handling
210
+
211
+ ```typescript
212
+ import { AxGenerateError, AxAIServiceError, AxAIServiceAbortedError } from '@ax-llm/ax';
213
+
214
+ try {
215
+ const result = await gen.forward(llm, { input: 'test' });
216
+ } catch (error) {
217
+ if (error instanceof AxGenerateError) {
218
+ console.error('Generation failed:', error.details.model, error.details.signature);
219
+ } else if (error instanceof AxAIServiceAbortedError) {
220
+ console.log('Request was aborted');
221
+ } else if (error instanceof AxAIServiceError) {
222
+ console.error('AI service error:', error.message);
223
+ }
224
+ }
225
+ ```
226
+
227
+ ## Debugging
228
+
229
+ ```typescript
230
+ import { axCreateDefaultColorLogger, axGlobals } from '@ax-llm/ax';
231
+
232
+ const result = await gen.forward(llm, { input: 'test' }, {
233
+ debug: true,
234
+ logger: axCreateDefaultColorLogger(),
235
+ // OpenTelemetry
236
+ tracer: openTelemetryTracer,
237
+ meter: openTelemetryMeter,
238
+ });
239
+
240
+ // Or set live app-wide defaults for future calls:
241
+ axGlobals.tracer = openTelemetryTracer;
242
+ axGlobals.meter = openTelemetryMeter;
243
+ ```
244
+
245
+ ## MCP Integration
246
+
247
+ Use the `ax-mcp` skill for the complete native client, transport,
248
+ authentication, catalog, task, subscription, event, and replay workflow.
249
+
250
+ ```typescript
251
+ import { AxMCPClient, agent } from '@ax-llm/ax';
252
+ import { AxMCPStdioTransport } from '@ax-llm/ax-tools';
253
+
254
+ // Stdio transport (local MCP server)
255
+ const transport = new AxMCPStdioTransport({
256
+ command: 'npx',
257
+ args: ['-y', '@modelcontextprotocol/server-memory'],
258
+ });
259
+
260
+ const mcpClient = new AxMCPClient(transport, { namespace: 'memory' });
261
+
262
+ // Native MCP context is initialized once and inherited by all agent stages.
263
+ const myAgent = agent('userMessage:string -> response:string', {
264
+ mcp: mcpClient,
265
+ functionDiscovery: true,
266
+ contextFields: [],
267
+ });
268
+
269
+ const result = await myAgent.forward(llm, { userMessage: 'Remember this.' });
270
+ await mcpClient.close(); // caller-owned clients remain caller-owned
271
+ ```
272
+
273
+ ### HTTP Transport (Remote MCP)
274
+
275
+ ```typescript
276
+ import { AxMCPStreamableHTTPTransport } from '@ax-llm/ax';
277
+
278
+ const transport = new AxMCPStreamableHTTPTransport('https://remote.example/mcp', {
279
+ headers: { 'x-pd-project-id': projectId },
280
+ authorization: `Bearer ${accessToken}`,
281
+ });
282
+ ```
283
+
284
+ ### Native MCP and UCP behavior
285
+
286
+ - Pass `mcp` and `ucp` to AxGen, streaming AxGen, chat, AxAgent, AxFlow, optimization, or evaluation options.
287
+ - Use `mcpContext` to inject attributed prompts/resources before the first model call.
288
+ - Use `mcpInheritance: 'all' | 'none' | string[]` to restrict child programs.
289
+ - Tool calls retain raw MCP content, metadata, errors, tasks, and protocol provenance in memory.
290
+ - AxAgent exposes native modules as `mcp.<namespace>` and `ucp.<namespace>`.
291
+ - `inspectCatalog()` discovers tool/prompt names, concrete resources, and URI
292
+ templates from only an endpoint. Resource event sources default to no
293
+ subscriptions and require an explicit all/URI/selector policy.
294
+ - `toFunction()` remains a compatibility adapter only; native Ax execution never uses it.
295
+ - Live optimization is rejected by default. Use recording/replay or explicitly opt into live MCP evaluation.
296
+
297
+ ```typescript
298
+ const catalog = await mcpClient.inspectCatalog();
299
+ const tools = catalog.tools;
300
+ const prompts = await mcpClient.listPrompts();
301
+ const resource = await mcpClient.readResource('docs://guide');
302
+ const tasks = await mcpClient.listTasks();
303
+ ```
304
+
305
+ ### Function Overrides
306
+
307
+ ```typescript
308
+ const mcpClient = new AxMCPClient(transport, {
309
+ functionOverrides: [
310
+ { name: 'search_documents', updates: { name: 'findDocs', description: 'Search docs' } }
311
+ ]
312
+ });
313
+ ```
314
+
315
+ ## Type Reference
316
+
317
+ All programs use `forward(ai, values, options?)` and
318
+ `streamingForward(ai, values, options?)`. For an AI service type `T`, use the
319
+ exported option types below instead of constructor options:
320
+
321
+ | Program | Forward options | Streaming options |
322
+ | --- | --- | --- |
323
+ | `AxGen` | `AxProgramForwardOptionsWithModels<T>` | `AxProgramStreamingForwardOptionsWithModels<T>` |
324
+ | `AxAgent` | `AxAgentForwardOptions<T>` | `AxAgentStreamingForwardOptions<T>` |
325
+ | `AxFlow` | `AxFlowForwardOptions<T>` | `AxProgramStreamingForwardOptionsWithModels<T>` |
326
+
327
+ `forward()` returns `Promise<OUT>`. `streamingForward()` returns
328
+ `AxGenStreamingOut<OUT>` with `{ version, index, delta }` chunks. Agent input
329
+ values can also include a per-run `memories` array. `AxAgentOptions<IN>` is for
330
+ constructing an agent, not for its forward call.
331
+
332
+ - `AxGen`: `setExamples(...)`, `addAssert(...)`, `addStreamingAssert(...)`,
333
+ `addFieldProcessor(...)`, `addStreamingFieldProcessor(...)`, and `stop()`.
334
+ See `ax-gen` for their callback contracts.
335
+ - `AxAgent`: `getFunction()` exposes a child-agent tool and requires
336
+ `agentIdentity` at construction. See `ax-agent`.
337
+ - `AxFlow`: define nodes with `.node(...)`, execute them with `.execute(...)`,
338
+ and select outputs with `.returns(...)`. See `ax-flow`.
339
+
340
+ ## Event-Driven Programs
341
+
342
+ Use `eventRuntime()` when notifications, webhooks, timers, or remote tasks
343
+ should wake or resume an Ax program. Sources publish into an inbox; explicit
344
+ routes choose `observe`, `invalidate`, `wake`, or `resume`. Event payloads are
345
+ never inserted as user messages automatically. See `ax-event-runtime.md`.
346
+
347
+ ## Examples
348
+
349
+ Fetch these for full working code:
350
+
351
+ - [Standard Schema (zod)](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/standard-schema.ts) — zod with f() and fn()
352
+ - [Chat Log](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/chat-log.ts) — inspect conversation history and multi-step tool calls
353
+ - [Marketing](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/marketing.ts) — product use case
354
+ - [MCP Integration](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/mcp-client-memory.ts) — MCP integration