Skip to content

Commit a631559

Browse files
committed
chore: update .gitignore and package.json, refactor AXFLOW documentation to use factory functions
This commit adds *.jsonl to .gitignore and excludes src/data from workspaces in package.json. Additionally, it refactors the AXFLOW documentation to replace constructor patterns with factory function usage for creating flows, enhancing clarity and consistency in examples.
1 parent af101b4 commit a631559

File tree

3 files changed

+192
-30
lines changed

3 files changed

+192
-30
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ site/dist
2424
*.webm
2525
*.txt
2626
__pycache__
27-
27+
*.jsonl
2828
gepa/
29+
src/data

docs/AXFLOW.md

Lines changed: 188 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,36 @@ flexible control flow patterns.
2121
### Basic Flow
2222

2323
```typescript
24-
import { ai, AxFlow } from "@ax-llm/ax";
24+
import { ai, flow } from "@ax-llm/ax";
2525

2626
// Create AI instance
2727
const llm = ai({ name: "openai", apiKey: process.env.OPENAI_APIKEY! });
2828

29-
// Create a simple flow
30-
const flow = new AxFlow<{ userInput: string }, { responseText: string }>()
29+
// Create a simple flow (factory function)
30+
const wf = flow<{ userInput: string }, { responseText: string }>()
3131
.node("testNode", "userInput:string -> responseText:string")
3232
.execute("testNode", (state) => ({ userInput: state.userInput }))
33-
.map((state) => ({ responseText: state.testNodeResult.responseText }));
33+
.returns((state) => ({ responseText: state.testNodeResult.responseText }));
3434

3535
// Execute the flow
36-
const result = await flow.forward(llm, { userInput: "Hello world" });
36+
const result = await wf.forward(llm, { userInput: "Hello world" });
3737
console.log(result.responseText);
3838
```
3939

40-
### Constructor Options
40+
### Factory Options
4141

4242
```typescript
43-
// Basic constructor
44-
const flow = new AxFlow();
43+
// Basic factory
44+
const wf = flow();
4545

4646
// With options
47-
const flow = new AxFlow({ autoParallel: false });
47+
const wf = flow({ autoParallel: false });
4848

4949
// With explicit typing
50-
const flow = new AxFlow<InputType, OutputType>();
50+
const wf = flow<InputType, OutputType>();
5151

5252
// With options and typing
53-
const flow = new AxFlow<InputType, OutputType>({
53+
const wf = flow<InputType, OutputType>({
5454
autoParallel: true,
5555
batchSize: 5,
5656
});
@@ -403,7 +403,7 @@ flow.derive("upperText", "inputText", (text) => text.toUpperCase());
403403
### 1. Sequential Processing
404404

405405
```typescript
406-
const sequentialFlow = new AxFlow<{ input: string }, { finalResult: string }>()
406+
const sequentialFlow = flow<{ input: string }, { finalResult: string }>()
407407
.node("step1", "input:string -> intermediate:string")
408408
.node("step2", "intermediate:string -> output:string")
409409
.execute("step1", (state) => ({ input: state.input }))
@@ -417,7 +417,7 @@ const sequentialFlow = new AxFlow<{ input: string }, { finalResult: string }>()
417417
### 2. Conditional Processing
418418

419419
```typescript
420-
const conditionalFlow = new AxFlow<
420+
const conditionalFlow = flow<
421421
{ query: string; isComplex: boolean },
422422
{ response: string }
423423
>()
@@ -438,7 +438,7 @@ const conditionalFlow = new AxFlow<
438438
### 3. Iterative Processing
439439

440440
```typescript
441-
const iterativeFlow = new AxFlow<
441+
const iterativeFlow = flow<
442442
{ content: string },
443443
{ finalContent: string }
444444
>()
@@ -466,7 +466,7 @@ const iterativeFlow = new AxFlow<
466466
AxFlow automatically detects independent operations and runs them in parallel:
467467

468468
```typescript
469-
const autoParallelFlow = new AxFlow<
469+
const autoParallelFlow = flow<
470470
{ text: string },
471471
{ combinedAnalysis: string }
472472
>()
@@ -498,7 +498,7 @@ AxFlow supports asynchronous transformations in map operations, enabling API
498498
calls, database queries, and other async operations within your flow:
499499

500500
```typescript
501-
const asyncFlow = new AxFlow<
501+
const asyncFlow = flow<
502502
{ userQuery: string },
503503
{ enrichedData: string; apiCallTime: number }
504504
>()
@@ -543,7 +543,7 @@ const asyncFlow = new AxFlow<
543543
You can mix synchronous and asynchronous operations seamlessly:
544544

545545
```typescript
546-
const mixedFlow = new AxFlow<{ rawData: string }, { result: string }>()
546+
const mixedFlow = flow<{ rawData: string }, { result: string }>()
547547
// Sync preprocessing
548548
.map((state) => ({
549549
...state,
@@ -589,7 +589,7 @@ flow
589589
### 6. Self-Healing with Feedback Loops
590590

591591
```typescript
592-
const selfHealingFlow = new AxFlow<{ input: string }, { output: string }>()
592+
const selfHealingFlow = flow<{ input: string }, { output: string }>()
593593
.node("processor", "input:string -> output:string, confidence:number")
594594
.node("validator", "output:string -> isValid:boolean, issues:string[]")
595595
.node("fixer", "output:string, issues:string[] -> fixedOutput:string")
@@ -669,7 +669,7 @@ parallel:
669669

670670
```typescript
671671
// Disable auto-parallelization globally
672-
const sequentialFlow = new AxFlow({ autoParallel: false });
672+
const sequentialFlow = flow({ autoParallel: false });
673673

674674
// Disable for specific execution
675675
const result = await flow.forward(llm, input, { autoParallel: false });
@@ -695,7 +695,7 @@ flow
695695
### 3. Batch Processing with Derive
696696

697697
```typescript
698-
const batchFlow = new AxFlow<{ items: string[] }, { processedItems: string[] }>(
698+
const batchFlow = flow<{ items: string[] }, { processedItems: string[] }>(
699699
{
700700
autoParallel: true,
701701
batchSize: 3, // Process 3 items at a time
@@ -828,15 +828,175 @@ flow
828828
}));
829829
```
830830

831+
## When to Use Each Feature
832+
833+
### Data shaping vs. AI calls: map() vs execute()
834+
835+
Use `map()` for synchronous/async data transformations without calling AI; use
836+
`execute()` to invoke a previously defined AI node.
837+
838+
```typescript
839+
const wf = flow<{ raw: string }, { answer: string }>()
840+
// Preprocess user input (no AI call)
841+
.map((s) => ({ cleaned: s.raw.trim().toLowerCase() }))
842+
// Call an AI node you defined earlier (requires execute)
843+
.node("qa", "question:string -> answer:string")
844+
.execute("qa", (s) => ({ question: s.cleaned }))
845+
.map((s) => ({ answer: s.qaResult.answer }));
846+
```
847+
848+
### Conditional routing: branch()/when()/merge()
849+
850+
Use when you need different paths for different conditions, then converge.
851+
852+
```typescript
853+
const wf = flow<{ query: string; expertMode: boolean }, { response: string }>()
854+
.node("simple", "query:string -> response:string")
855+
.node("expert", "query:string -> response:string")
856+
.branch((s) => s.expertMode)
857+
.when(true)
858+
.execute("expert", (s) => ({ query: s.query }))
859+
.when(false)
860+
.execute("simple", (s) => ({ query: s.query }))
861+
.merge()
862+
.map((s) => ({
863+
response: s.expertResult?.response ?? s.simpleResult?.response,
864+
}));
865+
```
866+
867+
### Iteration/retries: while()/endWhile()
868+
869+
Use to repeat work until a goal is met or a cap is hit.
870+
871+
```typescript
872+
const wf = flow<{ draft: string }, { final: string }>()
873+
.node("grader", "text:string -> score:number")
874+
.node("improver", "text:string -> improved:string")
875+
.map((s) => ({ current: s.draft, attempts: 0 }))
876+
.while((s) => s.attempts < 3)
877+
.execute("grader", (s) => ({ text: s.current }))
878+
.branch((s) => s.graderResult.score >= 0.8)
879+
.when(true)
880+
.map((s) => ({ attempts: 3 }))
881+
.when(false)
882+
.execute("improver", (s) => ({ text: s.current }))
883+
.map((s) => ({
884+
current: s.improverResult.improved,
885+
attempts: s.attempts + 1,
886+
}))
887+
.merge()
888+
.endWhile()
889+
.map((s) => ({ final: s.current }));
890+
```
891+
892+
### Extend node contracts: nx()
893+
894+
Use `nx()` to augment inputs/outputs (e.g., add internal reasoning or
895+
confidence) without changing original signature text.
896+
897+
```typescript
898+
const wf = flow<{ question: string }, { answer: string; confidence: number }>()
899+
.nx("answerer", "question:string -> answer:string", {
900+
appendOutputs: [{ name: "confidence", type: f.number("0-1") }],
901+
})
902+
.execute("answerer", (s) => ({ question: s.question }))
903+
.map((s) => ({
904+
answer: s.answererResult.answer,
905+
confidence: s.answererResult.confidence,
906+
}));
907+
```
908+
909+
### Batch/array processing: derive()
910+
911+
Use to fan out work over arrays with built-in batching and merging.
912+
913+
```typescript
914+
const wf = flow<{ items: string[] }, { processed: string[] }>({ batchSize: 3 })
915+
.derive("processed", "items", (item) => item.toUpperCase(), { batchSize: 2 });
916+
```
917+
918+
### Free speedups: auto-parallelization
919+
920+
Independent executes run in parallel automatically. Avoid creating unnecessary
921+
dependencies.
922+
923+
```typescript
924+
const wf = flow<{ text: string }, { combined: string }>()
925+
.node("a", "text:string -> x:string")
926+
.node("b", "text:string -> y:string")
927+
.execute("a", (s) => ({ text: s.text }))
928+
.execute("b", (s) => ({ text: s.text }))
929+
.map((s) => ({ combined: `${s.aResult.x}|${s.bResult.y}` }));
930+
```
931+
932+
### Multi-model strategy: dynamic AI context
933+
934+
Override AI per execute to route tasks to the best model.
935+
936+
```typescript
937+
const wf = flow<{ text: string }, { out: string }>()
938+
.node("fast", "text:string -> out:string")
939+
.node("smart", "text:string -> out:string")
940+
.execute("fast", (s) => ({ text: s.text }), { ai: ai({ name: "groq" }) })
941+
.execute("smart", (s) => ({ text: s.text }), {
942+
ai: ai({ name: "anthropic" }),
943+
})
944+
.map((s) => ({ out: s.smartResult?.out ?? s.fastResult.out }));
945+
```
946+
947+
### Final typing and shape: returns()/r()
948+
949+
Use to lock in the exact output type and get full TypeScript inference.
950+
951+
```typescript
952+
const wf = flow<{ input: string }>()
953+
.map((s) => ({ upper: s.input.toUpperCase(), length: s.input.length }))
954+
.returns((s) => ({ upper: s.upper, isLong: s.length > 20 }));
955+
```
956+
957+
### Quality loops: label()/feedback()
958+
959+
Use to jump back to a label when a condition holds, with optional caps.
960+
961+
```typescript
962+
const wf = flow<{ prompt: string }, { result: string }>()
963+
.node("gen", "prompt:string -> result:string, quality:number")
964+
.map((s) => ({ tries: 0 }))
965+
.label("retry")
966+
.execute("gen", (s) => ({ prompt: s.prompt }))
967+
.feedback((s) => s.genResult.quality < 0.9 && s.tries < 2, "retry")
968+
.map((s) => ({ result: s.genResult.result }));
969+
```
970+
971+
### Parallel async transforms: map([...], { parallel: true })
972+
973+
Use to run multiple independent async transforms concurrently.
974+
975+
```typescript
976+
const wf = flow<{ url: string }, { title: string; sentiment: string }>()
977+
.map([
978+
async (s) => ({ html: await fetchHTML(s.url) }),
979+
async (s) => ({ meta: await fetchMetadata(s.url) }),
980+
], { parallel: true })
981+
.node("title", "html:string -> title:string")
982+
.node("sent", "html:string -> sentiment:string")
983+
.execute("title", (s) => ({ html: s.html }))
984+
.execute("sent", (s) => ({ html: s.html }))
985+
.returns((s) => ({
986+
title: s.titleResult.title,
987+
sentiment: s.sentResult.sentiment,
988+
}));
989+
```
990+
831991
## Examples
832992

833993
### Extended Node Patterns with `nx`
834994

835995
```typescript
836-
import { AxFlow, f } from "@ax-llm/ax";
996+
import { f, flow } from "@ax-llm/ax";
837997

838998
// Chain-of-thought reasoning pattern
839-
const reasoningFlow = new AxFlow<{ question: string }, { answer: string }>()
999+
const reasoningFlow = flow<{ question: string }, { answer: string }>()
8401000
.nx("reasoner", "question:string -> answer:string", {
8411001
prependOutputs: [
8421002
{
@@ -849,7 +1009,7 @@ const reasoningFlow = new AxFlow<{ question: string }, { answer: string }>()
8491009
.map((state) => ({ answer: state.reasonerResult.answer }));
8501010

8511011
// Confidence scoring pattern
852-
const confidenceFlow = new AxFlow<
1012+
const confidenceFlow = flow<
8531013
{ input: string },
8541014
{ result: string; confidence: number }
8551015
>()
@@ -865,7 +1025,7 @@ const confidenceFlow = new AxFlow<
8651025
}));
8661026

8671027
// Contextual processing pattern
868-
const contextualFlow = new AxFlow<
1028+
const contextualFlow = flow<
8691029
{ query: string; context?: string },
8701030
{ response: string }
8711031
>()
@@ -910,7 +1070,7 @@ console.log(result.keywords); // Fully typed
9101070
### Quality-Driven Content Creation
9111071

9121072
```typescript
913-
const contentCreator = new AxFlow<
1073+
const contentCreator = flow<
9141074
{ topic: string; targetQuality: number },
9151075
{ finalContent: string; iterations: number }
9161076
>()
@@ -955,7 +1115,7 @@ const contentCreator = new AxFlow<
9551115
### Async Data Enrichment Pipeline
9561116

9571117
```typescript
958-
const enrichmentPipeline = new AxFlow<
1118+
const enrichmentPipeline = flow<
9591119
{ userQuery: string },
9601120
{ finalResult: string; metadata: object }
9611121
>()
@@ -1007,7 +1167,7 @@ const enrichmentPipeline = new AxFlow<
10071167
### Real-time Data Processing with Async Maps
10081168

10091169
```typescript
1010-
const realTimeProcessor = new AxFlow<
1170+
const realTimeProcessor = flow<
10111171
{ streamData: string[] },
10121172
{ processedResults: string[]; stats: object }
10131173
>()
@@ -1066,7 +1226,7 @@ const realTimeProcessor = new AxFlow<
10661226
### Multi-Model Research System
10671227

10681228
```typescript
1069-
const researchSystem = new AxFlow<
1229+
const researchSystem = flow<
10701230
{ query: string },
10711231
{ answer: string; sources: string[]; confidence: number }
10721232
>()

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@
6969
"example": "examples"
7070
},
7171
"workspaces": [
72-
"src/*"
72+
"src/*",
73+
"!src/data"
7374
],
7475
"author": "Vikram <https://twitter.com/dosco>",
7576
"private": "true",

0 commit comments

Comments
 (0)