@ax-llm/ax 19.0.15 → 19.0.17

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/skills/ax-llm.md CHANGED
@@ -1,1794 +1,264 @@
1
1
  ---
2
2
  name: ax
3
3
  description: This skill helps with using the @ax-llm/ax TypeScript library for building LLM applications. Use when the user asks about ax(), ai(), f(), s(), agent(), flow(), AxGen, AxAgent, AxFlow, signatures, streaming, or mentions @ax-llm/ax.
4
- version: "19.0.15"
4
+ version: "19.0.17"
5
5
  ---
6
6
 
7
- # Ax Library (@ax-llm/ax) Usage Guide
7
+ # Ax Library (@ax-llm/ax) Quick Reference
8
8
 
9
9
  Ax is a TypeScript library for building LLM-powered applications with type-safe signatures, streaming support, and multi-provider compatibility.
10
10
 
11
- ## Quick Reference
11
+ > **Detailed skills available:** ax-ai (providers), ax-signature (signatures/types), ax-gen (generators), ax-agent (agents), ax-flow (workflows), ax-gepa (Pareto optimization), ax-learn (self-improving agents).
12
12
 
13
- ```typescript
14
- import { ax, ai, f, agent, flow, AxGen, AxAgent, AxFlow } from '@ax-llm/ax';
15
-
16
- // Create AI provider
17
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY });
18
-
19
- // Create typed generator using f() fluent API
20
- const gen = ax(
21
- f()
22
- .input('question', f.string('User question'))
23
- .output('answer', f.string('AI response'))
24
- .build()
25
- );
26
- const result = await gen.forward(llm, { question: 'What is 2+2?' });
27
- // result.answer is typed as string
28
- ```
29
-
30
- ## 1. AI Provider Setup
31
-
32
- ### Quick Setup (All Providers)
33
-
34
- ```typescript
35
- import { ai } from '@ax-llm/ax';
36
-
37
- // OpenAI
38
- const openai = ai({ name: 'openai', apiKey: 'sk-...' });
39
-
40
- // Anthropic Claude
41
- const claude = ai({ name: 'anthropic', apiKey: 'sk-ant-...' });
42
-
43
- // Google Gemini
44
- const gemini = ai({ name: 'google-gemini', apiKey: 'AIza...' });
45
-
46
- // Azure OpenAI
47
- const azure = ai({
48
- name: 'azure-openai',
49
- apiKey: 'your-key',
50
- resourceName: 'your-resource',
51
- deploymentName: 'gpt-4'
52
- });
53
-
54
- // Groq
55
- const groq = ai({ name: 'groq', apiKey: 'gsk_...' });
56
-
57
- // DeepSeek
58
- const deepseek = ai({ name: 'deepseek', apiKey: 'sk-...' });
59
-
60
- // Mistral
61
- const mistral = ai({ name: 'mistral', apiKey: 'your-key' });
62
-
63
- // Cohere
64
- const cohere = ai({ name: 'cohere', apiKey: 'your-key' });
65
-
66
- // Together AI
67
- const together = ai({ name: 'together', apiKey: 'your-key' });
68
-
69
- // OpenRouter
70
- const openrouter = ai({ name: 'openrouter', apiKey: 'your-key' });
71
-
72
- // Ollama (local)
73
- const ollama = ai({ name: 'ollama', url: 'http://localhost:11434' });
74
-
75
- // HuggingFace
76
- const hf = ai({ name: 'huggingface', apiKey: 'hf_...' });
77
-
78
- // Reka
79
- const reka = ai({ name: 'reka', apiKey: 'your-key' });
80
-
81
- // xAI Grok
82
- const grok = ai({ name: 'grok', apiKey: 'your-key' });
83
- ```
84
-
85
- ### Full Provider Example
86
-
87
- ```typescript
88
- import { ai, ax, f } from '@ax-llm/ax';
89
-
90
- // Create provider with options
91
- const llm = ai({
92
- name: 'openai',
93
- apiKey: process.env.OPENAI_API_KEY!,
94
- config: {
95
- model: 'gpt-4o',
96
- temperature: 0.7,
97
- maxTokens: 1000
98
- }
99
- });
100
-
101
- // Use with generator
102
- const gen = ax(
103
- f()
104
- .input('topic', f.string())
105
- .output('essay', f.string('A short essay'))
106
- .build()
107
- );
108
- const result = await gen.forward(llm, { topic: 'Climate change' });
109
- console.log(result.essay);
110
- ```
111
-
112
- ## 2. Signatures & Generators
113
-
114
- Use the `f()` fluent builder to create type-safe signatures with validation, descriptions, and constraints.
115
-
116
- ### Basic Signature
117
-
118
- ```typescript
119
- import { ax, f } from '@ax-llm/ax';
120
-
121
- const gen = ax(
122
- f()
123
- .input('question', f.string('User question'))
124
- .output('answer', f.string('AI response'))
125
- .build()
126
- );
127
- ```
128
-
129
- ### Field Types
130
-
131
- ```typescript
132
- import { f } from '@ax-llm/ax';
133
-
134
- // String types
135
- f.string('description') // Basic string
136
- f.string().min(10).max(1000) // With length constraints
137
- f.string().email() // Email validation
138
- f.string().url() // URL validation
139
- f.string().regex('^[A-Z]', 'Start with capital') // Pattern
140
-
141
- // Numbers
142
- f.number('description')
143
- f.number().min(0).max(100) // With range
144
-
145
- // Boolean
146
- f.boolean('description')
147
-
148
- // Classification/Enum
149
- f.class(['option1', 'option2', 'option3'], 'description')
150
-
151
- // JSON (any structure)
152
- f.json('description')
153
-
154
- // Dates and times
155
- f.date('description')
156
- f.datetime('description')
157
-
158
- // Media (input only)
159
- f.image('description')
160
- f.audio('description')
161
- f.file('description')
162
-
163
- // Code
164
- f.code('python', 'description')
165
-
166
- // URL
167
- f.url('description')
168
-
169
- // Nested objects
170
- f.object({
171
- name: f.string('Person name'),
172
- age: f.number('Age in years'),
173
- email: f.string().email()
174
- }, 'Person details')
175
-
176
- // Arrays
177
- f.string('Item description').array('List of items')
178
- f.object({ id: f.number(), name: f.string() }).array('List of objects')
179
-
180
- // Modifiers
181
- f.string().optional() // Optional field
182
- f.string().internal() // Internal (not shown to LLM)
183
- f.string().cache() // Enable caching
184
- ```
185
-
186
- ### Signature Examples
187
-
188
- ```typescript
189
- import { ax, f } from '@ax-llm/ax';
190
-
191
- // Basic Q&A
192
- const gen1 = ax(
193
- f()
194
- .input('question', f.string())
195
- .output('answer', f.string())
196
- .build()
197
- );
198
-
199
- // With descriptions
200
- const gen2 = ax(
201
- f()
202
- .input('question', f.string('User question'))
203
- .output('answer', f.string('AI response'))
204
- .build()
205
- );
206
-
207
- // Optional fields
208
- const gen3 = ax(
209
- f()
210
- .input('query', f.string())
211
- .input('context', f.string('Background context').optional())
212
- .output('response', f.string())
213
- .build()
214
- );
215
-
216
- // Arrays
217
- const gen4 = ax(
218
- f()
219
- .input('text', f.string())
220
- .output('keywords', f.string().array())
221
- .build()
222
- );
223
-
224
- // Classification (enum)
225
- const gen5 = ax(
226
- f()
227
- .input('review', f.string())
228
- .output('sentiment', f.class(['positive', 'negative', 'neutral']))
229
- .build()
230
- );
231
-
232
- // Multiple outputs
233
- const gen6 = ax(
234
- f()
235
- .input('article', f.string())
236
- .output('title', f.string())
237
- .output('summary', f.string())
238
- .output('tags', f.string().array())
239
- .build()
240
- );
241
-
242
- // Numbers and booleans
243
- const gen7 = ax(
244
- f()
245
- .input('text', f.string())
246
- .output('wordCount', f.number())
247
- .output('isQuestion', f.boolean())
248
- .build()
249
- );
250
-
251
- // JSON output
252
- const gen8 = ax(
253
- f()
254
- .input('data', f.string())
255
- .output('parsed', f.json())
256
- .build()
257
- );
258
-
259
- // Dates
260
- const gen9 = ax(
261
- f()
262
- .input('text', f.string())
263
- .output('extractedDate', f.date())
264
- .build()
265
- );
266
-
267
- // Code blocks
268
- const gen10 = ax(
269
- f()
270
- .input('task', f.string())
271
- .output('code', f.code('python'))
272
- .build()
273
- );
274
-
275
- // Signature description
276
- const gen11 = ax(
277
- f()
278
- .input('text', f.string())
279
- .output('translation', f.string())
280
- .description('Translate text to French')
281
- .build()
282
- );
283
-
284
- // Nested objects
285
- const gen12 = ax(
286
- f()
287
- .input('document', f.string('Document to analyze'))
288
- .input('analysisType', f.class(['sentiment', 'entities', 'summary']))
289
- .output('result', f.object({
290
- score: f.number().min(0).max(1),
291
- label: f.string(),
292
- details: f.string().optional()
293
- }))
294
- .output('entities', f.object({
295
- name: f.string(),
296
- type: f.class(['person', 'org', 'location'])
297
- }).array().optional())
298
- .description('Analyze documents')
299
- .build()
300
- );
301
- ```
302
-
303
- ### Complete Generator Example
304
-
305
- ```typescript
306
- import { ai, ax, f } from '@ax-llm/ax';
307
-
308
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
309
-
310
- // Create generator with options
311
- const summarizer = ax(
312
- f()
313
- .input('article', f.string('Article to summarize'))
314
- .output('summary', f.string('Concise summary'))
315
- .output('keyPoints', f.string('Key point').array())
316
- .build(),
317
- {
318
- description: 'Summarize articles and extract key points',
319
- maxRetries: 3,
320
- maxSteps: 5
321
- }
322
- );
323
-
324
- // Forward (non-streaming)
325
- const result = await summarizer.forward(llm, {
326
- article: 'Long article text here...'
327
- });
328
-
329
- console.log(result.summary); // string
330
- console.log(result.keyPoints); // string[]
331
-
332
- // With model override
333
- const result2 = await summarizer.forward(llm, { article: 'text' }, {
334
- model: 'gpt-4o-mini'
335
- });
336
- ```
337
-
338
- ### String Shorthand
339
-
340
- For simple cases, you can also use string syntax:
341
-
342
- ```typescript
343
- import { ax } from '@ax-llm/ax';
344
-
345
- // String shorthand: 'inputField:type -> outputField:type'
346
- const gen = ax('question:string -> answer:string');
347
-
348
- // Types: string, number, boolean, json, class, date, datetime, image, audio, file, code, url
349
- // Modifiers: field?:type (optional), field:type[] (array), field:class "opt1, opt2" (enum)
350
- ```
351
-
352
- ## 3. Streaming
353
-
354
- ### Basic Streaming
355
-
356
- ```typescript
357
- import { ai, ax, f } from '@ax-llm/ax';
358
-
359
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
360
- const gen = ax(
361
- f()
362
- .input('topic', f.string())
363
- .output('content', f.string())
364
- .build()
365
- );
366
-
367
- // Stream responses
368
- for await (const chunk of gen.streamingForward(llm, { topic: 'AI' })) {
369
- // chunk.delta contains partial values
370
- if (chunk.delta.content) {
371
- process.stdout.write(chunk.delta.content);
372
- }
373
- }
374
- ```
375
-
376
- ### Complete Streaming Example
377
-
378
- ```typescript
379
- import { ai, ax, f } from '@ax-llm/ax';
380
-
381
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
382
-
383
- const writer = ax(
384
- f()
385
- .input('prompt', f.string())
386
- .output('story', f.string())
387
- .output('title', f.string())
388
- .build()
389
- );
390
-
391
- async function streamStory() {
392
- let fullStory = '';
393
- let title = '';
394
-
395
- for await (const chunk of writer.streamingForward(
396
- llm,
397
- { prompt: 'Write a short story about a robot' },
398
- { stream: true }
399
- )) {
400
- // Handle story chunks
401
- if (chunk.delta.story) {
402
- process.stdout.write(chunk.delta.story);
403
- fullStory += chunk.delta.story;
404
- }
405
-
406
- // Handle title (usually comes early)
407
- if (chunk.delta.title) {
408
- title = chunk.delta.title;
409
- }
410
- }
411
-
412
- console.log('\n\nTitle:', title);
413
- return { story: fullStory, title };
414
- }
415
-
416
- await streamStory();
417
- ```
418
-
419
- ### Streaming with Field Processors
420
-
421
- ```typescript
422
- import { ai, ax, f } from '@ax-llm/ax';
423
-
424
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
425
-
426
- const gen = ax(
427
- f()
428
- .input('query', f.string())
429
- .output('response', f.string())
430
- .build()
431
- );
432
-
433
- // Add streaming field processor
434
- gen.addStreamingFieldProcessor('response', (chunk, context) => {
435
- console.log('Chunk received:', chunk);
436
- console.log('Full value so far:', context?.values?.response);
437
- console.log('Done:', context?.done);
438
- });
439
-
440
- await gen.forward(llm, { query: 'Hello' }, { stream: true });
441
- ```
442
-
443
- ## 4. Agents with Tools
444
-
445
- Agents can use functions (tools) to perform actions.
446
-
447
- ### Defining Functions
448
-
449
- ```typescript
450
- import { ai, agent } from '@ax-llm/ax';
451
-
452
- // Function definition
453
- const getCurrentWeather = {
454
- name: 'getCurrentWeather',
455
- description: 'Get the current weather for a location',
456
- parameters: {
457
- type: 'object',
458
- properties: {
459
- location: { type: 'string', description: 'City name' },
460
- unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }
461
- },
462
- required: ['location']
463
- },
464
- func: async ({ location, unit = 'celsius' }) => {
465
- // Implementation
466
- return JSON.stringify({ temp: 22, unit, location });
467
- }
468
- };
469
- ```
470
-
471
- ### Creating Agents
472
-
473
- ```typescript
474
- import { ai, agent, f } from '@ax-llm/ax';
475
-
476
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
477
-
478
- // Create agent with functions
479
- const weatherAgent = agent(
480
- f()
481
- .input('query', f.string())
482
- .output('response', f.string())
483
- .build(),
484
- {
485
- name: 'weatherAssistant',
486
- description: 'An assistant that helps with weather queries',
487
- definition: 'You are a helpful weather assistant. Use the getCurrentWeather function to get weather data and provide friendly responses.',
488
- functions: [getCurrentWeather]
489
- }
490
- );
491
-
492
- const result = await weatherAgent.forward(llm, {
493
- query: 'What is the weather in Tokyo?'
494
- });
495
-
496
- console.log(result.response);
497
- ```
498
-
499
- ### Complete Agent Example
500
-
501
- ```typescript
502
- import { ai, agent, f } from '@ax-llm/ax';
503
-
504
- // Define tools
505
- const searchDatabase = {
506
- name: 'searchDatabase',
507
- description: 'Search the product database',
508
- parameters: {
509
- type: 'object',
510
- properties: {
511
- query: { type: 'string', description: 'Search query' },
512
- limit: { type: 'number', description: 'Max results' }
513
- },
514
- required: ['query']
515
- },
516
- func: async ({ query, limit = 5 }) => {
517
- // Simulate database search
518
- return JSON.stringify([
519
- { id: 1, name: 'Product A', price: 99 },
520
- { id: 2, name: 'Product B', price: 149 }
521
- ].slice(0, limit));
522
- }
523
- };
524
-
525
- const getProductDetails = {
526
- name: 'getProductDetails',
527
- description: 'Get details of a specific product',
528
- parameters: {
529
- type: 'object',
530
- properties: {
531
- productId: { type: 'number', description: 'Product ID' }
532
- },
533
- required: ['productId']
534
- },
535
- func: async ({ productId }) => {
536
- return JSON.stringify({
537
- id: productId,
538
- name: 'Product A',
539
- price: 99,
540
- description: 'A great product',
541
- stock: 50
542
- });
543
- }
544
- };
545
-
546
- // Create agent
547
- const shopAssistant = agent(
548
- f()
549
- .input('userQuery', f.string())
550
- .output('response', f.string())
551
- .output('recommendations', f.string().array())
552
- .build(),
553
- {
554
- name: 'shoppingAssistant',
555
- description: 'An AI assistant that helps users find and learn about products',
556
- definition: `You are a helpful shopping assistant. Use the available tools to:
557
- 1. Search for products when users ask about items
558
- 2. Get product details when they want more information
559
- 3. Provide helpful recommendations based on their needs
560
-
561
- Always be friendly and provide clear, helpful responses.`,
562
- functions: [searchDatabase, getProductDetails]
563
- }
564
- );
565
-
566
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
567
-
568
- const result = await shopAssistant.forward(llm, {
569
- userQuery: 'Can you find me some products and tell me about the first one?'
570
- });
571
-
572
- console.log('Response:', result.response);
573
- console.log('Recommendations:', result.recommendations);
574
- ```
575
-
576
- ### Nested Agents
577
-
578
- ```typescript
579
- import { ai, agent, f } from '@ax-llm/ax';
580
-
581
- // Child agent
582
- const researcher = agent(
583
- f()
584
- .input('topic', f.string())
585
- .output('findings', f.string())
586
- .build(),
587
- {
588
- name: 'researchAgent',
589
- description: 'Researches topics and provides detailed findings'
590
- }
591
- );
592
-
593
- // Parent agent that can use child agent
594
- const writer = agent(
595
- f()
596
- .input('topic', f.string())
597
- .output('article', f.string())
598
- .build(),
599
- {
600
- name: 'writerAgent',
601
- description: 'Writes articles using research from the research agent',
602
- agents: [researcher]
603
- }
604
- );
605
-
606
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
607
-
608
- const result = await writer.forward(llm, {
609
- topic: 'Benefits of meditation'
610
- });
611
- ```
612
-
613
- ## 5. Workflows (AxFlow)
614
-
615
- AxFlow enables building complex, multi-step AI workflows with type safety.
616
-
617
- ### Basic Flow
618
-
619
- ```typescript
620
- import { ai, flow, f } from '@ax-llm/ax';
621
-
622
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
623
-
624
- const summarizerSig = f()
625
- .input('text', f.string())
626
- .output('summary', f.string())
627
- .build();
628
-
629
- const translatorSig = f()
630
- .input('text', f.string())
631
- .output('translation', f.string())
632
- .build();
633
-
634
- const pipeline = flow<{ text: string }, { result: string }>()
635
- .node('summarizer', summarizerSig)
636
- .node('translator', translatorSig)
637
- .execute('summarizer', (state) => ({ text: state.text }))
638
- .execute('translator', (state) => ({ text: state.summarizerResult.summary }))
639
- .map((state) => ({ result: state.translatorResult.translation }));
640
-
641
- const result = await pipeline.forward(llm, { text: 'Long article...' });
642
- console.log(result.result);
643
- ```
644
-
645
- ### Flow with Branching
646
-
647
- ```typescript
648
- import { ai, flow, f } from '@ax-llm/ax';
649
-
650
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
651
-
652
- const technicalSig = f()
653
- .input('query', f.string())
654
- .output('answer', f.string())
655
- .build();
656
-
657
- const creativeSig = f()
658
- .input('query', f.string())
659
- .output('answer', f.string())
660
- .build();
661
-
662
- const workflow = flow<{ query: string; type: string }, { output: string }>()
663
- .node('technical', technicalSig)
664
- .node('creative', creativeSig)
665
- .branch(
666
- (state) => state.type === 'technical',
667
- (branch) => branch.execute('technical', (s) => ({ query: s.query })),
668
- (branch) => branch.execute('creative', (s) => ({ query: s.query }))
669
- )
670
- .map((state) => ({
671
- output: state.technicalResult?.answer || state.creativeResult?.answer || ''
672
- }));
673
-
674
- const result = await workflow.forward(llm, {
675
- query: 'Explain quantum computing',
676
- type: 'technical'
677
- });
678
- ```
679
-
680
- ### Flow with Parallel Execution
681
-
682
- ```typescript
683
- import { ai, flow, f } from '@ax-llm/ax';
684
-
685
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
686
-
687
- const prosSig = f()
688
- .input('topic', f.string())
689
- .output('arguments', f.string())
690
- .build();
691
-
692
- const consSig = f()
693
- .input('topic', f.string())
694
- .output('arguments', f.string())
695
- .build();
696
-
697
- const summarySig = f()
698
- .input('prosArgs', f.string())
699
- .input('consArgs', f.string())
700
- .output('summary', f.string())
701
- .build();
702
-
703
- const parallelFlow = flow<{ topic: string }, { combined: string }>()
704
- .node('pros', prosSig)
705
- .node('cons', consSig)
706
- .node('summary', summarySig)
707
- .parallel([
708
- { branch: (b) => b.execute('pros', (s) => ({ topic: s.topic })) },
709
- { branch: (b) => b.execute('cons', (s) => ({ topic: s.topic })) }
710
- ])
711
- .execute('summary', (state) => ({
712
- prosArgs: state.prosResult.arguments,
713
- consArgs: state.consResult.arguments
714
- }))
715
- .map((state) => ({ combined: state.summaryResult.summary }));
716
-
717
- const result = await parallelFlow.forward(llm, { topic: 'Remote work' });
718
- ```
719
-
720
- ### Complete Flow Example
721
-
722
- ```typescript
723
- import { ai, flow, f } from '@ax-llm/ax';
724
-
725
- // Define nodes with proper signatures
726
- const researchNode = f()
727
- .input('topic', f.string())
728
- .output('research', f.string())
729
- .output('sources', f.string().array())
730
- .build();
731
-
732
- const outlineNode = f()
733
- .input('research', f.string())
734
- .input('sources', f.string().array())
735
- .output('outline', f.string().array())
736
- .build();
737
-
738
- const writeNode = f()
739
- .input('outline', f.string().array())
740
- .input('research', f.string())
741
- .output('draft', f.string())
742
- .build();
743
-
744
- const editNode = f()
745
- .input('draft', f.string())
746
- .output('final', f.string())
747
- .output('wordCount', f.number())
748
- .build();
749
-
750
- // Build the flow
751
- const articlePipeline = flow<
752
- { topic: string },
753
- { article: string; wordCount: number }
754
- >()
755
- .node('research', researchNode)
756
- .node('outline', outlineNode)
757
- .node('write', writeNode)
758
- .node('edit', editNode)
759
- .execute('research', (s) => ({ topic: s.topic }))
760
- .execute('outline', (s) => ({
761
- research: s.researchResult.research,
762
- sources: s.researchResult.sources
763
- }))
764
- .execute('write', (s) => ({
765
- outline: s.outlineResult.outline,
766
- research: s.researchResult.research
767
- }))
768
- .execute('edit', (s) => ({
769
- draft: s.writeResult.draft
770
- }))
771
- .map((s) => ({
772
- article: s.editResult.final,
773
- wordCount: s.editResult.wordCount
774
- }));
775
-
776
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
777
-
778
- const result = await articlePipeline.forward(llm, {
779
- topic: 'The future of renewable energy'
780
- });
781
-
782
- console.log('Article:', result.article);
783
- console.log('Word count:', result.wordCount);
784
- ```
785
-
786
- ## 6. Common Patterns
787
-
788
- ### Classification
789
-
790
- ```typescript
791
- import { ai, ax, f } from '@ax-llm/ax';
792
-
793
- const classifier = ax(
794
- f()
795
- .input('text', f.string())
796
- .output('category', f.class(['spam', 'ham', 'uncertain']))
797
- .output('confidence', f.number().min(0).max(1))
798
- .build()
799
- );
800
-
801
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
802
-
803
- const result = await classifier.forward(llm, {
804
- text: 'Congratulations! You won $1,000,000!'
805
- });
806
-
807
- console.log(result.category); // 'spam'
808
- console.log(result.confidence); // 0.95
809
- ```
810
-
811
- ### Extraction
812
-
813
- ```typescript
814
- import { ai, ax, f } from '@ax-llm/ax';
815
-
816
- const extractor = ax(
817
- f()
818
- .input('text', f.string())
819
- .output('entities', f.object({
820
- people: f.string().array(),
821
- organizations: f.string().array(),
822
- locations: f.string().array()
823
- }))
824
- .build()
825
- );
826
-
827
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
828
-
829
- const result = await extractor.forward(llm, {
830
- text: 'Tim Cook announced that Apple will open a new store in Paris on January 15th.'
831
- });
832
-
833
- console.log(result.entities.people); // ['Tim Cook']
834
- console.log(result.entities.organizations); // ['Apple']
835
- console.log(result.entities.locations); // ['Paris']
836
- ```
837
-
838
- ### Multi-modal (Images)
839
-
840
- ```typescript
841
- import { ai, ax, f } from '@ax-llm/ax';
842
- import { readFileSync } from 'fs';
843
-
844
- const imageAnalyzer = ax(
845
- f()
846
- .input('image', f.image('Image to analyze'))
847
- .input('question', f.string('Question about the image').optional())
848
- .output('description', f.string('Image description'))
849
- .output('objects', f.string().array())
850
- .build()
851
- );
852
-
853
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
854
-
855
- // From file
856
- const imageData = readFileSync('./photo.jpg').toString('base64');
857
- const result = await imageAnalyzer.forward(llm, {
858
- image: { mimeType: 'image/jpeg', data: imageData },
859
- question: 'What objects are in this image?'
860
- });
861
-
862
- // From URL (for providers that support it)
863
- const result2 = await imageAnalyzer.forward(llm, {
864
- image: { mimeType: 'image/jpeg', url: 'https://example.com/image.jpg' }
865
- });
866
- ```
867
-
868
- ### Chaining Generators
869
-
870
- ```typescript
871
- import { ai, ax, f } from '@ax-llm/ax';
872
-
873
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
874
-
875
- // Define generators
876
- const researcher = ax(
877
- f()
878
- .input('topic', f.string())
879
- .output('research', f.string())
880
- .output('keyFacts', f.string().array())
881
- .build()
882
- );
883
-
884
- const writer = ax(
885
- f()
886
- .input('research', f.string())
887
- .input('keyFacts', f.string().array())
888
- .output('article', f.string())
889
- .build()
890
- );
891
-
892
- const editor = ax(
893
- f()
894
- .input('article', f.string())
895
- .output('editedArticle', f.string())
896
- .output('suggestions', f.string().array())
897
- .build()
898
- );
899
-
900
- // Chain them
901
- async function createArticle(topic: string) {
902
- const research = await researcher.forward(llm, { topic });
903
-
904
- const draft = await writer.forward(llm, {
905
- research: research.research,
906
- keyFacts: research.keyFacts
907
- });
908
-
909
- const final = await editor.forward(llm, {
910
- article: draft.article
911
- });
912
-
913
- return final;
914
- }
915
-
916
- const result = await createArticle('Artificial General Intelligence');
917
- console.log(result.editedArticle);
918
- ```
919
-
920
- ### Error Handling
921
-
922
- ```typescript
923
- import { ai, ax, f, AxGenerateError, AxAIServiceError } from '@ax-llm/ax';
924
-
925
- const gen = ax(
926
- f()
927
- .input('input', f.string())
928
- .output('output', f.string())
929
- .build()
930
- );
931
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
932
-
933
- try {
934
- const result = await gen.forward(llm, { input: 'test' });
935
- console.log(result.output);
936
- } catch (error) {
937
- if (error instanceof AxGenerateError) {
938
- console.error('Generation failed:', error.message);
939
- console.error('Details:', error.details);
940
- } else if (error instanceof AxAIServiceError) {
941
- console.error('AI service error:', error.message);
942
- } else {
943
- throw error;
944
- }
945
- }
946
- ```
947
-
948
- ### Examples and Few-Shot Learning
949
-
950
- ```typescript
951
- import { ai, ax, f } from '@ax-llm/ax';
952
-
953
- const classifier = ax(
954
- f()
955
- .input('text', f.string())
956
- .output('sentiment', f.class(['positive', 'negative', 'neutral']))
957
- .build()
958
- );
959
-
960
- // Set examples for few-shot learning
961
- classifier.setExamples([
962
- { text: 'I love this product!', sentiment: 'positive' },
963
- { text: 'This is terrible.', sentiment: 'negative' },
964
- { text: 'It works as expected.', sentiment: 'neutral' }
965
- ]);
966
-
967
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
968
-
969
- const result = await classifier.forward(llm, {
970
- text: 'The quality exceeded my expectations!'
971
- });
972
- ```
973
-
974
- ### Assertions and Validation
975
-
976
- ```typescript
977
- import { ai, ax, f } from '@ax-llm/ax';
978
-
979
- const gen = ax(
980
- f()
981
- .input('number', f.number())
982
- .output('doubled', f.number())
983
- .build()
984
- );
985
-
986
- // Add assertion
987
- gen.addAssert(
988
- (output) => output.doubled === output.number * 2,
989
- 'Output must be double the input'
990
- );
991
-
992
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
993
-
994
- // This will retry if assertion fails
995
- const result = await gen.forward(llm, { number: 5 }, { maxRetries: 3 });
996
- ```
997
-
998
- ### Memory and Context
999
-
1000
- ```typescript
1001
- import { ai, ax, f, AxMemory } from '@ax-llm/ax';
1002
-
1003
- const chatbot = ax(
1004
- f()
1005
- .input('userMessage', f.string())
1006
- .output('response', f.string())
1007
- .build()
1008
- );
1009
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1010
-
1011
- // Create shared memory
1012
- const memory = new AxMemory();
1013
-
1014
- // Conversation with memory
1015
- await chatbot.forward(llm, { userMessage: 'My name is Alice' }, { mem: memory });
1016
- const response = await chatbot.forward(llm, { userMessage: 'What is my name?' }, { mem: memory });
1017
- // response.response will reference "Alice"
1018
- ```
1019
-
1020
- ## 7. Advanced Configuration
1021
-
1022
- ### Model Configuration
1023
-
1024
- ```typescript
1025
- import { ai, ax, f } from '@ax-llm/ax';
1026
-
1027
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1028
- const gen = ax(
1029
- f()
1030
- .input('input', f.string())
1031
- .output('output', f.string())
1032
- .build()
1033
- );
1034
-
1035
- const result = await gen.forward(llm, { input: 'test' }, {
1036
- model: 'gpt-4o',
1037
- modelConfig: {
1038
- temperature: 0.7,
1039
- maxTokens: 2000,
1040
- topP: 0.9
1041
- }
1042
- });
1043
- ```
1044
-
1045
- ### Debugging
1046
-
1047
- ```typescript
1048
- import { ai, ax, f, axCreateDefaultColorLogger } from '@ax-llm/ax';
1049
-
1050
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1051
- const gen = ax(
1052
- f()
1053
- .input('input', f.string())
1054
- .output('output', f.string())
1055
- .build()
1056
- );
1057
-
1058
- // Enable debug logging
1059
- const result = await gen.forward(llm, { input: 'test' }, {
1060
- debug: true,
1061
- logger: axCreateDefaultColorLogger()
1062
- });
1063
- ```
1064
-
1065
- ### Context Caching
1066
-
1067
- ```typescript
1068
- import { ai, ax, f } from '@ax-llm/ax';
1069
-
1070
- const gen = ax(
1071
- f()
1072
- .input('document', f.string())
1073
- .input('question', f.string())
1074
- .output('answer', f.string())
1075
- .build()
1076
- );
1077
- const llm = ai({ name: 'anthropic', apiKey: process.env.ANTHROPIC_API_KEY! });
1078
-
1079
- // Enable context caching for long documents
1080
- const result = await gen.forward(llm, {
1081
- document: longDocument,
1082
- question: 'What is the main topic?'
1083
- }, {
1084
- contextCache: {
1085
- cacheBreakpoint: 'after-examples'
1086
- }
1087
- });
1088
- ```
1089
-
1090
- ## 8. Forward & AI Options
1091
-
1092
- ### Quick Reference Table
1093
-
1094
- | Goal | Option | Example |
1095
- |------|--------|---------|
1096
- | Adjust creativity | `modelConfig.temperature` | `{ modelConfig: { temperature: 0.8 } }` |
1097
- | Limit response length | `modelConfig.maxTokens` | `{ modelConfig: { maxTokens: 500 } }` |
1098
- | Use different model | `model` | `{ model: 'gpt-4o-mini' }` |
1099
- | Enable caching | `contextCache` | `{ contextCache: { cacheBreakpoint: 'after-examples' } }` |
1100
- | Debug output | `debug` | `{ debug: true }` |
1101
- | Retry on failure | `maxRetries` | `{ maxRetries: 3 }` |
1102
- | Multi-sampling | `sampleCount` | `{ sampleCount: 5, resultPicker: bestResultPicker }` |
1103
- | Thinking models | `thinkingTokenBudget` | `{ thinkingTokenBudget: 10000 }` |
1104
- | Abort request | `abortSignal` | `{ abortSignal: controller.signal }` |
1105
- | Custom timeout | `timeout` | `{ timeout: 60000 }` |
1106
-
1107
- ### Execution Control Options
13
+ ## Imports & Factories
1108
14
 
1109
15
  ```typescript
1110
- import { ai, ax, f } from '@ax-llm/ax';
1111
-
1112
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1113
- const gen = ax(
1114
- f()
1115
- .input('input', f.string())
1116
- .output('output', f.string())
1117
- .build()
1118
- );
1119
-
1120
- const result = await gen.forward(llm, { input: 'test' }, {
1121
- // Retry failed generations (validation failures, API errors)
1122
- maxRetries: 3,
16
+ // Prefer factory functions: ax(), ai(), agent(), flow() not new AxGen(), new AxAI(), etc.
17
+ import { ax, ai, f, s, fn, agent, flow, AxMemory, AxMCPClient, AxLearn } from '@ax-llm/ax';
1123
18
 
1124
- // Maximum agentic steps (for agents with tools)
1125
- maxSteps: 10,
19
+ // AI provider
20
+ const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_APIKEY });
1126
21
 
1127
- // Fail immediately on first error (don't retry)
1128
- fastFail: true
1129
- });
1130
- ```
1131
-
1132
- ### Model Configuration
1133
-
1134
- ```typescript
1135
- import { ai, ax, f } from '@ax-llm/ax';
22
+ // Generator (from string signature)
23
+ const gen = ax('question:string -> answer:string');
1136
24
 
1137
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
25
+ // Generator (from fluent signature)
1138
26
  const gen = ax(
1139
27
  f()
1140
- .input('input', f.string())
1141
- .output('output', f.string())
28
+ .input('question', f.string('User question'))
29
+ .output('answer', f.string('AI response'))
1142
30
  .build()
1143
31
  );
1144
32
 
1145
- const result = await gen.forward(llm, { input: 'test' }, {
1146
- // Override the model for this request
1147
- model: 'gpt-4o-mini',
1148
-
1149
- // Model-specific configuration
1150
- modelConfig: {
1151
- // Sampling temperature (0.0 = deterministic, 2.0 = creative)
1152
- temperature: 0.7,
1153
-
1154
- // Maximum tokens in response
1155
- maxTokens: 2000,
1156
-
1157
- // Nucleus sampling threshold
1158
- topP: 0.9,
1159
-
1160
- // Top-K sampling (not all providers support this)
1161
- topK: 40,
1162
-
1163
- // Frequency penalty (-2.0 to 2.0)
1164
- frequencyPenalty: 0.5,
1165
-
1166
- // Presence penalty (-2.0 to 2.0)
1167
- presencePenalty: 0.5,
1168
-
1169
- // Stop sequences
1170
- stopSequences: ['\n\n', 'END'],
33
+ // Reusable signature
34
+ const sig = s('question:string, context:string[] -> answer:string');
1171
35
 
1172
- // Seed for reproducible outputs (when supported)
1173
- seed: 12345,
1174
-
1175
- // Response format
1176
- responseFormat: 'json_object'
1177
- }
36
+ // Agent
37
+ const myAgent = agent('userInput:string -> response:string', {
38
+ name: 'helper',
39
+ description: 'A helpful assistant',
1178
40
  });
1179
- ```
1180
41
 
1181
- ### Context Caching (Gemini/Anthropic)
42
+ // Flow
43
+ const wf = flow<{ input: string }, { output: string }>()
44
+ .node('step1', 'input:string -> output:string')
45
+ .execute('step1', (state) => ({ input: state.input }))
46
+ .returns((state) => ({ output: state.step1Result.output }));
47
+
48
+ // Function tool
49
+ const tool = fn('search')
50
+ .description('Search the web')
51
+ .arg('query', f.string('Search query'))
52
+ .returns(f.string('Search results'))
53
+ .handler(({ query }) => searchWeb(query))
54
+ .build();
55
+ ```
1182
56
 
1183
- Context caching saves costs when repeatedly querying with the same large context (documents, system prompts, examples).
57
+ ## Running
1184
58
 
1185
59
  ```typescript
1186
- import { ai, ax, f } from '@ax-llm/ax';
1187
-
1188
- const llm = ai({ name: 'anthropic', apiKey: process.env.ANTHROPIC_API_KEY! });
1189
- const gen = ax(
1190
- f()
1191
- .input('document', f.string())
1192
- .input('question', f.string())
1193
- .output('answer', f.string())
1194
- .build()
1195
- );
1196
-
1197
- const longDocument = '... very long document ...';
1198
-
1199
- // Multiple questions about the same document - caching saves cost
1200
- for (const question of questions) {
1201
- const result = await gen.forward(llm, { document: longDocument, question }, {
1202
- contextCache: {
1203
- // Cache name (required for identifying the cache)
1204
- name: 'doc-analysis-cache',
1205
-
1206
- // Where to split the prompt for caching:
1207
- // - 'system': Cache system prompt only
1208
- // - 'after-functions': Cache system + function definitions
1209
- // - 'after-examples': Cache system + functions + examples
1210
- cacheBreakpoint: 'after-examples',
1211
-
1212
- // Cache time-to-live in seconds (default: provider-specific)
1213
- ttlSeconds: 3600,
1214
-
1215
- // Minimum tokens to trigger caching (avoid caching small prompts)
1216
- minTokens: 1000,
1217
-
1218
- // Refresh cache when within this window of expiry
1219
- refreshWindowSeconds: 300,
60
+ // Forward (blocking)
61
+ const result = await gen.forward(llm, { question: 'What is 2+2?' });
1220
62
 
1221
- // Custom cache registry for external storage (Redis, etc.)
1222
- registry: customCacheRegistry
1223
- }
1224
- });
63
+ // Streaming
64
+ for await (const chunk of gen.streamingForward(llm, { question: 'Tell a story' })) {
65
+ if (chunk.delta.answer) process.stdout.write(chunk.delta.answer);
1225
66
  }
1226
67
  ```
1227
68
 
1228
- ### Thinking Models (o1, o3, Gemini 2.0 Flash Thinking)
69
+ ## Forward Options Quick Reference
70
+
71
+ | Goal | Option | Example |
72
+ |------|--------|---------|
73
+ | Model override | `model` | `{ model: 'gpt-4o-mini' }` |
74
+ | Temperature | `modelConfig.temperature` | `{ modelConfig: { temperature: 0.8 } }` |
75
+ | Max tokens | `modelConfig.maxTokens` | `{ modelConfig: { maxTokens: 500 } }` |
76
+ | Retry on failure | `maxRetries` | `{ maxRetries: 3 }` |
77
+ | Max agent steps | `maxSteps` | `{ maxSteps: 10 }` |
78
+ | Fail fast | `fastFail` | `{ fastFail: true }` |
79
+ | Thinking budget | `thinkingTokenBudget` | `{ thinkingTokenBudget: 'medium' }` |
80
+ | Show thoughts | `showThoughts` | `{ showThoughts: true }` |
81
+ | Context caching | `contextCache` | `{ contextCache: { cacheBreakpoint: 'after-examples' } }` |
82
+ | Multi-sampling | `sampleCount` | `{ sampleCount: 5 }` |
83
+ | Debug logging | `debug` | `{ debug: true }` |
84
+ | Abort signal | `abortSignal` | `{ abortSignal: controller.signal }` |
85
+ | Memory | `mem` | `{ mem: new AxMemory() }` |
86
+ | Stop function | `stopFunction` | `{ stopFunction: 'finalAnswer' }` |
87
+ | Function mode | `functionCallMode` | `{ functionCallMode: 'auto' }` |
1229
88
 
1230
- For reasoning models that support extended thinking:
89
+ ## Memory and Context
1231
90
 
1232
91
  ```typescript
1233
- import { ai, ax, f } from '@ax-llm/ax';
92
+ import { AxMemory } from '@ax-llm/ax';
1234
93
 
1235
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1236
- const gen = ax(
1237
- f()
1238
- .input('problem', f.string())
1239
- .output('solution', f.string())
1240
- .build()
1241
- );
94
+ const memory = new AxMemory();
1242
95
 
1243
- const result = await gen.forward(llm, { problem: 'Complex math problem' }, {
1244
- model: 'o1',
96
+ // Multi-turn conversation
97
+ await gen.forward(llm, { userMessage: 'My name is Alice' }, { mem: memory });
98
+ const r = await gen.forward(llm, { userMessage: 'What is my name?' }, { mem: memory });
99
+ ```
1245
100
 
1246
- // Token budget for thinking/reasoning (model-specific)
1247
- thinkingTokenBudget: 10000,
101
+ ## Few-Shot Examples
1248
102
 
1249
- // Include thinking in output (when supported)
1250
- showThoughts: true,
103
+ ```typescript
104
+ const classifier = ax('reviewText:string -> sentiment:class "positive, negative, neutral"');
1251
105
 
1252
- // Custom field name for thoughts in output
1253
- thoughtFieldName: 'reasoning'
1254
- });
106
+ classifier.setExamples([
107
+ { reviewText: 'I love this!', sentiment: 'positive' },
108
+ { reviewText: 'Terrible.', sentiment: 'negative' },
109
+ { reviewText: 'It works.', sentiment: 'neutral' },
110
+ ]);
1255
111
  ```
1256
112
 
1257
- ### Multi-Sampling for Quality
113
+ ## Common Patterns
1258
114
 
1259
- Generate multiple samples and pick the best one:
115
+ ### Classification
1260
116
 
1261
117
  ```typescript
1262
- import { ai, ax, f } from '@ax-llm/ax';
1263
-
1264
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1265
- const gen = ax(
118
+ const classifier = ax(
1266
119
  f()
1267
- .input('input', f.string())
1268
- .output('output', f.string())
1269
- .output('confidence', f.number())
120
+ .input('text', f.string())
121
+ .output('category', f.class(['spam', 'ham', 'uncertain']))
122
+ .output('confidence', f.number().min(0).max(1))
1270
123
  .build()
1271
124
  );
1272
-
1273
- const result = await gen.forward(llm, { input: 'test' }, {
1274
- // Generate multiple samples
1275
- sampleCount: 5,
1276
-
1277
- // Pick the best result (custom function)
1278
- resultPicker: (results) => {
1279
- // Return the result with highest confidence
1280
- return results.reduce((best, current) =>
1281
- current.confidence > best.confidence ? current : best
1282
- );
1283
- }
1284
- });
1285
125
  ```
1286
126
 
1287
- ### Function Calling Configuration
1288
-
1289
- Control how agents use tools/functions:
127
+ ### Extraction
1290
128
 
1291
129
  ```typescript
1292
- import { ai, agent, f } from '@ax-llm/ax';
1293
-
1294
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1295
-
1296
- const myAgent = agent(
130
+ const extractor = ax(
1297
131
  f()
1298
- .input('query', f.string())
1299
- .output('answer', f.string())
1300
- .build(),
1301
- {
1302
- name: 'toolAgent',
1303
- description: 'An agent that uses tools to answer queries',
1304
- functions: [searchTool, calculatorTool]
1305
- }
132
+ .input('text', f.string())
133
+ .output('entities', f.object({
134
+ people: f.string().array(),
135
+ organizations: f.string().array(),
136
+ locations: f.string().array()
137
+ }))
138
+ .build()
1306
139
  );
1307
-
1308
- const result = await myAgent.forward(llm, { query: 'test' }, {
1309
- // Function calling mode:
1310
- // - 'auto': Model decides when to call functions
1311
- // - 'none': Disable function calling
1312
- // - 'required': Force at least one function call
1313
- functionCallMode: 'auto',
1314
-
1315
- // Force a specific function to be called
1316
- functionCall: 'searchTool',
1317
-
1318
- // Stop after this function is called
1319
- stopFunction: 'finalAnswer',
1320
-
1321
- // Override available functions for this request
1322
- functions: [searchTool],
1323
-
1324
- // Custom caching for function results
1325
- cachingFunction: async (funcName, args) => {
1326
- const cacheKey = `${funcName}:${JSON.stringify(args)}`;
1327
- return await cache.get(cacheKey);
1328
- }
1329
- });
1330
140
  ```
1331
141
 
1332
- ### Debugging & Observability
142
+ ### Multi-modal (Images)
1333
143
 
1334
144
  ```typescript
1335
- import { ai, ax, f, axCreateDefaultColorLogger } from '@ax-llm/ax';
1336
-
1337
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1338
- const gen = ax(
145
+ const analyzer = ax(
1339
146
  f()
1340
- .input('input', f.string())
1341
- .output('output', f.string())
147
+ .input('image', f.image('Image to analyze'))
148
+ .input('question', f.string('Question').optional())
149
+ .output('description', f.string())
150
+ .output('objects', f.string().array())
1342
151
  .build()
1343
152
  );
1344
153
 
1345
- const result = await gen.forward(llm, { input: 'test' }, {
1346
- // Enable debug logging
1347
- debug: true,
1348
-
1349
- // Show verbose output (more details)
1350
- verbose: true,
1351
-
1352
- // Hide system prompt in debug output (security)
1353
- debugHideSystemPrompt: true,
1354
-
1355
- // Custom logger
1356
- logger: axCreateDefaultColorLogger(),
1357
-
1358
- // OpenTelemetry tracer for distributed tracing
1359
- tracer: openTelemetryTracer,
1360
-
1361
- // OpenTelemetry meter for metrics
1362
- meter: openTelemetryMeter,
1363
-
1364
- // Parent trace context
1365
- traceContext: parentSpan,
1366
-
1367
- // Custom labels for traces/metrics
1368
- customLabels: { environment: 'production', version: '1.0' },
1369
-
1370
- // Exclude content from traces (privacy)
1371
- excludeContentFromTrace: true
154
+ const result = await analyzer.forward(llm, {
155
+ image: { mimeType: 'image/jpeg', data: base64Data },
156
+ question: 'What objects are in this image?'
1372
157
  });
1373
158
  ```
1374
159
 
1375
- ### Retry & Error Handling
160
+ ### Chaining Generators
1376
161
 
1377
162
  ```typescript
1378
- import { ai, ax, f } from '@ax-llm/ax';
1379
-
1380
- const llm = ai({
1381
- name: 'openai',
1382
- apiKey: process.env.OPENAI_API_KEY!,
1383
- options: {
1384
- // Retry configuration for API calls
1385
- retry: {
1386
- // Maximum retry attempts
1387
- maxRetries: 3,
1388
-
1389
- // Initial delay between retries (ms)
1390
- initialDelayMs: 1000,
1391
-
1392
- // Maximum delay between retries (ms)
1393
- maxDelayMs: 30000,
163
+ const researcher = ax('topic:string -> research:string, keyFacts:string[]');
164
+ const writer = ax('research:string, keyFacts:string[] -> article:string');
1394
165
 
1395
- // Backoff multiplier
1396
- backoffMultiplier: 2,
1397
-
1398
- // Jitter factor (0-1) to randomize delays
1399
- jitterFactor: 0.1,
1400
-
1401
- // HTTP status codes to retry on
1402
- retryOnStatusCodes: [429, 500, 502, 503, 504]
1403
- },
1404
-
1405
- // Rate limiter for API calls
1406
- rateLimiter: customRateLimiter,
1407
-
1408
- // Request timeout (ms)
1409
- timeout: 60000
1410
- }
1411
- });
166
+ const research = await researcher.forward(llm, { topic: 'AGI' });
167
+ const draft = await writer.forward(llm, { research: research.research, keyFacts: research.keyFacts });
1412
168
  ```
1413
169
 
1414
- ### Request Control
170
+ ## Error Handling
1415
171
 
1416
172
  ```typescript
1417
- import { ai, ax, f } from '@ax-llm/ax';
1418
-
1419
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1420
- const gen = ax(
1421
- f()
1422
- .input('input', f.string())
1423
- .output('output', f.string())
1424
- .build()
1425
- );
1426
-
1427
- // Create abort controller
1428
- const controller = new AbortController();
1429
-
1430
- // Cancel after 5 seconds
1431
- setTimeout(() => controller.abort(), 5000);
173
+ import { AxGenerateError, AxAIServiceError, AxAIServiceAbortedError } from '@ax-llm/ax';
1432
174
 
1433
175
  try {
1434
- const result = await gen.forward(llm, { input: 'test' }, {
1435
- // Abort signal for cancellation
1436
- abortSignal: controller.signal,
1437
-
1438
- // Request timeout (ms)
1439
- timeout: 30000,
1440
-
1441
- // Custom fetch function (for proxies, etc.)
1442
- fetch: customFetch,
1443
-
1444
- // CORS proxy URL (for browser environments)
1445
- corsProxy: 'https://cors-proxy.example.com'
1446
- });
176
+ const result = await gen.forward(llm, { input: 'test' });
1447
177
  } catch (error) {
1448
- if (error.name === 'AbortError') {
1449
- console.log('Request was cancelled');
178
+ if (error instanceof AxGenerateError) {
179
+ console.error('Generation failed:', error.details.model, error.details.signature);
180
+ } else if (error instanceof AxAIServiceAbortedError) {
181
+ console.log('Request was aborted');
182
+ } else if (error instanceof AxAIServiceError) {
183
+ console.error('AI service error:', error.message);
1450
184
  }
1451
185
  }
1452
186
  ```
1453
187
 
1454
- ### Memory Configuration
1455
-
1456
- ```typescript
1457
- import { ai, ax, f, AxMemory } from '@ax-llm/ax';
1458
-
1459
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1460
- const gen = ax(
1461
- f()
1462
- .input('message', f.string())
1463
- .output('response', f.string())
1464
- .build()
1465
- );
1466
-
1467
- const memory = new AxMemory();
1468
-
1469
- const result = await gen.forward(llm, { message: 'Hello' }, {
1470
- // Use shared memory for conversation context
1471
- mem: memory,
1472
-
1473
- // Disable automatic memory cleanup (keep all messages)
1474
- disableMemoryCleanup: true
1475
- });
1476
- ```
1477
-
1478
- ### Validation Options
188
+ ## Debugging
1479
189
 
1480
190
  ```typescript
1481
- import { ai, ax, f } from '@ax-llm/ax';
1482
-
1483
- const llm = ai({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1484
- const gen = ax(
1485
- f()
1486
- .input('input', f.string())
1487
- .output('output', f.string())
1488
- .build()
1489
- );
191
+ import { axCreateDefaultColorLogger } from '@ax-llm/ax';
1490
192
 
1491
193
  const result = await gen.forward(llm, { input: 'test' }, {
1492
- // Strict mode: fail on any validation error
1493
- strictMode: true,
1494
-
1495
- // Custom assertions (run after generation)
1496
- asserts: [
1497
- {
1498
- fn: (output) => output.output.length > 10,
1499
- message: 'Output must be longer than 10 characters'
1500
- }
1501
- ],
1502
-
1503
- // Streaming assertions (run during streaming)
1504
- streamingAsserts: [
1505
- {
1506
- fn: (partial) => !partial.output?.includes('forbidden'),
1507
- message: 'Output must not contain forbidden content'
1508
- }
1509
- ]
194
+ debug: true,
195
+ logger: axCreateDefaultColorLogger(),
196
+ // OpenTelemetry
197
+ tracer: openTelemetryTracer,
198
+ meter: openTelemetryMeter,
1510
199
  });
1511
200
  ```
1512
201
 
1513
- ## 9. MCP Integration
1514
-
1515
- MCP (Model Context Protocol) enables AxAgent to use external tools from MCP-compliant servers. This allows your agents to interact with databases, file systems, APIs, and other services through a standardized protocol.
1516
-
1517
- ### Quick Start
202
+ ## MCP Integration
1518
203
 
1519
204
  ```typescript
1520
- import { AxAgent, AxAI, AxMCPClient } from '@ax-llm/ax';
205
+ import { AxMCPClient } from '@ax-llm/ax';
1521
206
  import { AxMCPStdioTransport } from '@ax-llm/ax-tools';
1522
207
 
1523
- // Create transport for local MCP server
208
+ // Stdio transport (local MCP server)
1524
209
  const transport = new AxMCPStdioTransport({
1525
210
  command: 'npx',
1526
211
  args: ['-y', '@modelcontextprotocol/server-memory'],
1527
212
  });
1528
213
 
1529
- // Initialize MCP client
1530
214
  const mcpClient = new AxMCPClient(transport, { debug: false });
1531
215
  await mcpClient.init();
1532
216
 
1533
- // Create agent with MCP functions
1534
- const agent = new AxAgent({
1535
- name: 'MyAssistant',
1536
- description: 'An assistant with MCP capabilities',
1537
- signature: f()
1538
- .input('userMessage', f.string())
1539
- .output('response', f.string())
1540
- .build(),
1541
- functions: [mcpClient], // Pass client directly
1542
- });
1543
-
1544
- const ai = new AxAI({ name: 'openai', apiKey: process.env.OPENAI_API_KEY! });
1545
- const result = await agent.forward(ai, { userMessage: 'Hello' });
1546
- ```
1547
-
1548
- ### MCP Transports
1549
-
1550
- #### AxMCPStdioTransport (Local Servers)
1551
-
1552
- For MCP servers that run as local processes via stdin/stdout:
1553
-
1554
- ```typescript
1555
- import { AxMCPStdioTransport } from '@ax-llm/ax-tools';
1556
-
1557
- const transport = new AxMCPStdioTransport({
1558
- command: 'npx',
1559
- args: ['-y', '@modelcontextprotocol/server-memory'],
217
+ // Use with agent
218
+ const myAgent = agent('userMessage:string -> response:string', {
219
+ name: 'assistant',
220
+ description: 'An assistant with MCP tools',
221
+ functions: [mcpClient],
1560
222
  });
1561
-
1562
- // Clean up when done
1563
- await transport.terminate();
1564
223
  ```
1565
224
 
1566
- #### AxMCPStreambleHTTPTransport (Remote Servers)
1567
-
1568
- For MCP servers accessible via HTTP (e.g., Pipedream, hosted services):
225
+ ### HTTP Transport (Remote MCP)
1569
226
 
1570
227
  ```typescript
1571
228
  import { AxMCPStreambleHTTPTransport } from '@ax-llm/ax/mcp/transports/httpStreamTransport.js';
1572
229
 
1573
- const transport = new AxMCPStreambleHTTPTransport(
1574
- 'https://remote.mcp.pipedream.net',
1575
- {
1576
- headers: {
1577
- 'x-pd-project-id': projectId,
1578
- 'x-pd-environment': 'development',
1579
- 'x-pd-external-user-id': 'user123',
1580
- 'x-pd-app-slug': 'notion',
1581
- },
1582
- authorization: `Bearer ${accessToken}`,
1583
- }
1584
- );
1585
- ```
1586
-
1587
- ### Using MCP with Agents
1588
-
1589
- Pass the MCP client directly to the agent's `functions` array:
1590
-
1591
- ```typescript
1592
- import { AxAgent, AxAI, AxMCPClient, f } from '@ax-llm/ax';
1593
- import { AxMCPStdioTransport } from '@ax-llm/ax-tools';
1594
-
1595
- const transport = new AxMCPStdioTransport({
1596
- command: 'npx',
1597
- args: ['-y', '@modelcontextprotocol/server-memory'],
1598
- });
1599
-
1600
- const mcpClient = new AxMCPClient(transport);
1601
- await mcpClient.init();
1602
-
1603
- const memoryAgent = new AxAgent<
1604
- { userMessage: string; userId: string },
1605
- { assistantResponse: string }
1606
- >({
1607
- name: 'MemoryAssistant',
1608
- description: 'An assistant that remembers past conversations. Use the database functions to manage, search, and add memories.',
1609
- signature: f()
1610
- .input('userMessage', f.string())
1611
- .input('userId', f.string())
1612
- .output('assistantResponse', f.string())
1613
- .build(),
1614
- functions: [mcpClient],
1615
- });
1616
-
1617
- const ai = new AxAI({
1618
- name: 'openai',
1619
- apiKey: process.env.OPENAI_API_KEY!,
1620
- config: { model: 'gpt-4o-mini' }
1621
- });
1622
-
1623
- // First interaction - stores memory
1624
- const first = await memoryAgent.forward(ai, {
1625
- userMessage: 'My name is Alice and my favorite color is blue.',
1626
- userId: 'user123',
1627
- });
1628
-
1629
- // Later interaction - retrieves memory
1630
- const second = await memoryAgent.forward(ai, {
1631
- userMessage: "What's my favorite color?",
1632
- userId: 'user123',
230
+ const transport = new AxMCPStreambleHTTPTransport('https://remote.mcp.pipedream.net', {
231
+ headers: { 'x-pd-project-id': projectId },
232
+ authorization: `Bearer ${accessToken}`,
1633
233
  });
1634
234
  ```
1635
235
 
1636
236
  ### MCP Capabilities
1637
237
 
1638
- MCP servers can provide three types of capabilities:
1639
-
1640
- | Capability | Function Prefix | Description |
1641
- |------------|-----------------|-------------|
1642
- | **Tools** | *(none)* | Traditional function calls (e.g., `search`, `create`) |
1643
- | **Prompts** | `prompt_` | Prompt templates (e.g., `prompt_summarize`) |
1644
- | **Resources** | `resource_` | File/data access (e.g., `resource_config_json`) |
1645
-
1646
- Check available capabilities:
238
+ | Capability | Prefix | Description |
239
+ |---|---|---|
240
+ | Tools | *(none)* | Function calls |
241
+ | Prompts | `prompt_` | Prompt templates |
242
+ | Resources | `resource_` | File/data access |
1647
243
 
1648
244
  ```typescript
1649
- const mcpClient = new AxMCPClient(transport);
1650
- await mcpClient.init();
1651
-
1652
245
  const caps = mcpClient.getCapabilities();
1653
- console.log('Tools:', caps.tools); // true/false
1654
- console.log('Prompts:', caps.prompts); // true/false
1655
- console.log('Resources:', caps.resources); // true/false
1656
-
1657
- // Or check individually
1658
- if (mcpClient.hasToolsCapability()) {
1659
- console.log('Server supports tools');
1660
- }
246
+ const functions = mcpClient.toFunction();
1661
247
  ```
1662
248
 
1663
249
  ### Function Overrides
1664
250
 
1665
- Customize function names and descriptions while preserving functionality:
1666
-
1667
251
  ```typescript
1668
252
  const mcpClient = new AxMCPClient(transport, {
1669
253
  functionOverrides: [
1670
- {
1671
- name: 'search_documents',
1672
- updates: {
1673
- name: 'findDocs',
1674
- description: 'Search through all available documents'
1675
- }
1676
- },
1677
- {
1678
- name: 'prompt_summarize',
1679
- updates: {
1680
- name: 'getSummaryPrompt',
1681
- description: 'Get a prompt template for summarization'
1682
- }
1683
- }
254
+ { name: 'search_documents', updates: { name: 'findDocs', description: 'Search docs' } }
1684
255
  ]
1685
256
  });
1686
257
  ```
1687
258
 
1688
- ### Getting Functions Directly
1689
-
1690
- If you need the function array instead of passing the client:
1691
-
1692
- ```typescript
1693
- const mcpClient = new AxMCPClient(transport);
1694
- await mcpClient.init();
1695
-
1696
- // Get all functions (tools + prompts + resources)
1697
- const functions = mcpClient.toFunction();
1698
-
1699
- // Use with agent
1700
- const agent = new AxAgent({
1701
- name: 'MyAgent',
1702
- signature: f()
1703
- .input('query', f.string())
1704
- .output('answer', f.string())
1705
- .build(),
1706
- functions: functions, // Or spread: [...functions, otherFunction]
1707
- });
1708
- ```
1709
-
1710
- ### Complete Example: Remote HTTP MCP Server
1711
-
1712
- ```typescript
1713
- import { AxAgent, AxAI, AxMCPClient, f } from '@ax-llm/ax';
1714
- import { AxMCPStreambleHTTPTransport } from '@ax-llm/ax/mcp/transports/httpStreamTransport.js';
1715
- import { createBackendClient } from '@pipedream/sdk/server';
1716
-
1717
- // Initialize Pipedream SDK
1718
- const pd = createBackendClient({
1719
- environment: 'development',
1720
- credentials: {
1721
- clientId: process.env.PIPEDREAM_CLIENT_ID!,
1722
- clientSecret: process.env.PIPEDREAM_CLIENT_SECRET!,
1723
- },
1724
- projectId: process.env.PIPEDREAM_PROJECT_ID!,
1725
- });
1726
-
1727
- // Get access token and app info
1728
- const accessToken = await pd.rawAccessToken();
1729
- const apps = await pd.getApps({ q: 'notion' });
1730
- const appSlug = apps.data[0]?.name_slug;
1731
-
1732
- // Create HTTP transport for Pipedream MCP
1733
- const httpTransport = new AxMCPStreambleHTTPTransport(
1734
- 'https://remote.mcp.pipedream.net',
1735
- {
1736
- headers: {
1737
- 'x-pd-project-id': process.env.PIPEDREAM_PROJECT_ID!,
1738
- 'x-pd-environment': 'development',
1739
- 'x-pd-external-user-id': 'user123',
1740
- 'x-pd-app-slug': appSlug!,
1741
- },
1742
- authorization: `Bearer ${accessToken}`,
1743
- }
1744
- );
1745
-
1746
- // Initialize MCP client
1747
- const mcpClient = new AxMCPClient(httpTransport, { debug: false });
1748
- await mcpClient.init();
1749
-
1750
- // Create Notion agent
1751
- const notionAgent = new AxAgent<
1752
- { userRequest: string },
1753
- { assistantResponse: string }
1754
- >({
1755
- name: 'NotionAssistant',
1756
- description: 'An assistant that can interact with Notion documents. Use the provided functions to read, search, and analyze Notion content.',
1757
- signature: f()
1758
- .input('userRequest', f.string())
1759
- .output('assistantResponse', f.string())
1760
- .build(),
1761
- functions: [mcpClient],
1762
- });
1763
-
1764
- const ai = new AxAI({
1765
- name: 'openai',
1766
- apiKey: process.env.OPENAI_API_KEY!,
1767
- config: { model: 'gpt-4o-mini' }
1768
- });
1769
-
1770
- // Use the agent
1771
- const response = await notionAgent.forward(ai, {
1772
- userRequest: 'Summarize my most recently created Notion doc'
1773
- });
1774
- console.log(response.assistantResponse);
1775
- ```
1776
-
1777
- ### Example Files
1778
-
1779
- Full working examples on GitHub:
1780
-
1781
- - [Local Memory Server (stdio)](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/mcp-client-memory.ts) - Memory-augmented agent using local MCP server
1782
- - [Remote HTTP Server (Pipedream/Notion)](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/mcp-client-pipedream.ts) - Notion integration via Pipedream MCP
1783
-
1784
259
  ## Type Reference
1785
260
 
1786
261
  ```typescript
1787
- // Core types
1788
- type AxGenIn = Record<string, any>;
1789
- type AxGenOut = Record<string, any>;
1790
-
1791
- // Generator
1792
262
  class AxGen<IN, OUT> {
1793
263
  forward(ai: AxAIService, values: IN, options?: AxProgramForwardOptions): Promise<OUT>;
1794
264
  streamingForward(ai: AxAIService, values: IN, options?: AxProgramStreamingForwardOptions): AsyncGenerator<{ delta: Partial<OUT> }>;
@@ -1796,22 +266,27 @@ class AxGen<IN, OUT> {
1796
266
  addAssert(fn: (output: OUT) => boolean, message?: string): void;
1797
267
  addFieldProcessor(field: keyof OUT, fn: (value: any) => any): void;
1798
268
  addStreamingFieldProcessor(field: keyof OUT, fn: (chunk: string, ctx: any) => void): void;
269
+ stop(): void;
1799
270
  }
1800
271
 
1801
- // Agent
1802
272
  class AxAgent<IN, OUT> {
1803
273
  forward(ai: AxAIService, values: IN, options?: AxAgentOptions): Promise<OUT>;
1804
274
  streamingForward(ai: AxAIService, values: IN, options?: AxAgentOptions): AsyncGenerator<{ delta: Partial<OUT> }>;
1805
275
  getFunction(): AxFunction;
1806
276
  }
1807
277
 
1808
- // Flow
1809
- class AxFlow<IN, OUT, TNodes, TState> {
278
+ class AxFlow<IN, OUT> {
1810
279
  node(name: string, signature: string | AxSignature): AxFlow;
1811
- execute(nodeName: string, inputMapper: (state: TState) => any): AxFlow;
1812
- map(transformer: (state: TState) => OUT): AxFlow;
1813
- branch(condition: (state: TState) => boolean, ifTrue: FlowBranch, ifFalse: FlowBranch): AxFlow;
1814
- parallel(branches: ParallelBranch[]): AxFlow;
1815
- forward(ai: AxAIService, input: IN): Promise<OUT>;
280
+ execute(name: string, mapper: (state) => any): AxFlow;
281
+ returns(mapper: (state) => OUT): AxFlow;
282
+ forward(ai: AxAIService, values: IN): Promise<OUT>;
1816
283
  }
1817
284
  ```
285
+
286
+ ## Examples
287
+
288
+ Fetch these for full working code:
289
+
290
+ - [Chat](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/chat.ts) — multi-turn conversation
291
+ - [Marketing](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/marketing.ts) — product use case
292
+ - [MCP Integration](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/mcp-client-memory.ts) — MCP integration