@amitdeshmukh/ax-crew 6.0.0 → 8.0.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/plan.md ADDED
@@ -0,0 +1,255 @@
1
+ # Integrate AxACE into Ax-Crew (per-agent)
2
+
3
+ ### Scope
4
+
5
+ - Add optional AxACE support to `StatefulAxAgent` so each agent can: (a) run offline compile with examples + metric, (b) apply online updates with feedback, and (c) persist playbooks in memory or to file/DB. Reference: [ACE docs](https://axllm.dev/ace/).
6
+ - Add simple execution tracking at crew level for intelligent feedback routing across agent dependency chains.
7
+
8
+ ### Key Design
9
+
10
+ - **Per-agent playbooks**: stored in-memory, optionally persisted via path or callback.
11
+ - **Student/Teacher AIs**: default student = agent's existing `AxAI`; teacher configured per agent (provider + model) or default to student.
12
+ - **Non-breaking**: all ACE fields are optional; no behavior changes unless enabled.
13
+ - **Execution tracking for feedback routing**: Simple in-memory tracking of agent involvement in task execution, enabling feedback distribution across agent dependency chains.
14
+
15
+ ### Architecture Clarification
16
+
17
+ **OpenTelemetry Telemetry** (observability) and **ACE Feedback Routing** (execution tracking) are **separate concerns**:
18
+
19
+ | Feature | Purpose | Where Configured |
20
+ |---------|---------|------------------|
21
+ | **Telemetry** | Observability, tracing, metrics | `AxAI` options via `AxCrewOptions.telemetry` |
22
+ | **Execution Tracking** | Track which agents handled a task for ACE feedback | `AxCrew.executionHistory` in-memory Map |
23
+
24
+ Telemetry is an `AxAI` feature (not `AxAgent`). The Ax framework automatically creates OpenTelemetry spans for all LLM operations when `tracer`/`meter` are passed to `AxAI`.
25
+
26
+ ### Files to Update/Add
27
+
28
+ - Update `src/types.ts`: add `ACEConfig` and optional `ace?: ACEConfig` to `AgentConfig`. ✅ Done
29
+ - **Add `src/agents/ace.ts`**: helper to build optimizer using real `AxACE` from `@ax-llm/ax`, load/save playbooks, run offline/online flows.
30
+ - Update `src/agents/index.ts` (`StatefulAxAgent`): hold `aceConfig`, optional `aceOptimizer`, and methods: `initACE()`, `optimizeOffline(...)`, `applyOnlineUpdate(...)`, `getPlaybook()`, `applyPlaybook(...)`.
31
+ - Update `src/agents/index.ts` (`AxCrew`): add `executionHistory` Map for tracking agent involvement, `applyTaskFeedback()` for routing.
32
+ - Update `src/agents/agentConfig.ts`: parse `ace` block; optionally load initial playbook and pass into agent. ✅ Telemetry already correctly passed to `AxAI`.
33
+ - Add `examples/ace-feedback-routing.ts`: demonstrates execution-based feedback routing across agent dependency chains.
34
+
35
+ ### New Types (in src/types.ts) ✅ Already Implemented
36
+
37
+ ```ts
38
+ export interface ACETeacherConfig {
39
+ provider?: Provider;
40
+ providerKeyName?: string;
41
+ apiURL?: string;
42
+ ai?: AxModelConfig & { model: string };
43
+ providerArgs?: Record<string, unknown>;
44
+ }
45
+
46
+ export interface ACEPersistenceConfig {
47
+ playbookPath?: string;
48
+ initialPlaybook?: Record<string, any>;
49
+ autoPersist?: boolean;
50
+ onPersist?: (pb: any) => Promise<void> | void;
51
+ onLoad?: () => Promise<any> | any;
52
+ }
53
+
54
+ export interface ACEOptionsConfig {
55
+ maxEpochs?: number;
56
+ allowDynamicSections?: boolean;
57
+ tokenBudget?: number;
58
+ reflectorPrompt?: string;
59
+ curatorPrompt?: string;
60
+ }
61
+
62
+ export interface ACEMetricConfig {
63
+ metricFnName?: string;
64
+ primaryOutputField?: string;
65
+ }
66
+
67
+ export interface ACEConfig {
68
+ teacher?: ACETeacherConfig;
69
+ persistence?: ACEPersistenceConfig;
70
+ options?: ACEOptionsConfig;
71
+ metric?: ACEMetricConfig;
72
+ compileOnStart?: boolean;
73
+ }
74
+ ```
75
+
76
+ ### Helper Module (src/agents/ace.ts)
77
+
78
+ ```ts
79
+ import { AxACE, type AxMetricFn } from "@ax-llm/ax";
80
+ import { ai as buildAI } from "@ax-llm/ax";
81
+ import type { ACEConfig, ACEPersistenceConfig, ACEMetricConfig, FunctionRegistryType } from "../types.js";
82
+ import type { StatefulAxAgent } from "./index.js";
83
+
84
+ // Build AxACE optimizer with student (agent's AI) and optional teacher
85
+ export function buildACEOptimizer(
86
+ studentAI: any,
87
+ cfg: ACEConfig
88
+ ): AxACE {
89
+ const teacherAI = buildTeacherAI(cfg.teacher, studentAI);
90
+ return new AxACE(
91
+ { studentAI, teacherAI, verbose: cfg.options?.maxEpochs ? true : false },
92
+ {
93
+ maxEpochs: cfg.options?.maxEpochs,
94
+ allowDynamicSections: cfg.options?.allowDynamicSections,
95
+ initialPlaybook: cfg.persistence?.initialPlaybook
96
+ }
97
+ );
98
+ }
99
+
100
+ // Load playbook from file or callback
101
+ export async function loadInitialPlaybook(cfg?: ACEPersistenceConfig): Promise<any | undefined> { /*...*/ }
102
+
103
+ // Persist playbook to file or callback
104
+ export async function persistPlaybook(pb: any, cfg?: ACEPersistenceConfig): Promise<void> { /*...*/ }
105
+
106
+ // Resolve metric function from registry or create equality metric
107
+ export function resolveMetric(cfg: ACEMetricConfig | undefined, registry: FunctionRegistryType): AxMetricFn | undefined { /*...*/ }
108
+
109
+ // Run offline compile
110
+ export async function runOfflineCompile(args: {
111
+ program: any;
112
+ optimizer: AxACE;
113
+ metric: AxMetricFn;
114
+ examples: any[];
115
+ persistence?: ACEPersistenceConfig;
116
+ }): Promise<any> { /*...*/ }
117
+
118
+ // Run online update
119
+ export async function runOnlineUpdate(args: {
120
+ optimizer: AxACE;
121
+ example: any;
122
+ prediction: any;
123
+ feedback?: string;
124
+ persistence?: ACEPersistenceConfig;
125
+ }): Promise<any> { /*...*/ }
126
+ ```
127
+
128
+ ### Agent Class Changes (minimal API)
129
+
130
+ ```ts
131
+ class StatefulAxAgent extends AxAgent<any, any> {
132
+ private aceConfig?: ACEConfig;
133
+ private aceOptimizer?: AxACE;
134
+ private acePlaybook?: any;
135
+
136
+ async initACE(ace?: ACEConfig): Promise<void> { /* build optimizer, load playbook */ }
137
+ async optimizeOffline(params?: { metric?: AxMetricFn; examples?: any[] }): Promise<void> { /* compile, persist */ }
138
+ async applyOnlineUpdate(params: { example: any; prediction: any; feedback?: string }): Promise<void> { /* update + persist */ }
139
+ getPlaybook(): any | undefined { return this.acePlaybook; }
140
+ applyPlaybook(pb: any): void { /* apply to optimizer */ }
141
+ }
142
+ ```
143
+
144
+ **Note**: No telemetry fields in agent - telemetry is handled by `AxAI`.
145
+
146
+ ### Crew-Level Execution Tracking for Feedback Routing
147
+
148
+ **Problem Solved**: "How does the crew know which agent to pass online feedback to?"
149
+
150
+ **Solution**: Simple in-memory execution history (not OpenTelemetry - that's for observability):
151
+
152
+ ```ts
153
+ class AxCrew {
154
+ // Track agent execution for ACE feedback routing
155
+ private executionHistory: Map<string, {
156
+ taskId: string;
157
+ rootAgent: string;
158
+ involvedAgents: Set<string>;
159
+ taskInput: any;
160
+ results: Map<string, any>;
161
+ startTime: number;
162
+ endTime?: number;
163
+ }> = new Map();
164
+
165
+ // Track agent involvement during execution
166
+ trackAgentExecution(taskId: string, agentName: string, input: any): void { /*...*/ }
167
+ recordAgentResult(taskId: string, agentName: string, result: any): void { /*...*/ }
168
+
169
+ // Get involvement info for feedback routing
170
+ getTaskAgentInvolvement(taskId: string): AgentInvolvement | null { /*...*/ }
171
+
172
+ // Route feedback to involved agents
173
+ async applyTaskFeedback(params: {
174
+ taskId: string;
175
+ feedback: string;
176
+ strategy?: 'all' | 'primary' | 'weighted';
177
+ }): Promise<void> { /*...*/ }
178
+
179
+ // Cleanup old entries
180
+ cleanupOldExecutions(maxAgeMs?: number): void { /*...*/ }
181
+ }
182
+ ```
183
+
184
+ ### Agent Config Parsing
185
+
186
+ In `parseAgentConfig(...)`:
187
+ - Telemetry (`tracer`, `meter`) is passed to `AxAI` options ✅ Already implemented
188
+ - If `agentConfigData.ace` is present, the agent's `initACE()` is called during creation
189
+ - If `compileOnStart` and a usable metric is available, run offline compile with `examples`
190
+
191
+ ### Minimal Usage
192
+
193
+ ```ts
194
+ const config: AxCrewConfig = {
195
+ crew: [
196
+ {
197
+ name: "writer",
198
+ description: "Writes articles",
199
+ signature: "topic:string -> article:string",
200
+ provider: "openai",
201
+ providerKeyName: "OPENAI_API_KEY",
202
+ ai: { model: "gpt-4o-mini" },
203
+ ace: {
204
+ enabled: true,
205
+ teacher: { provider: "openai", providerKeyName: "OPENAI_API_KEY", ai: { model: "gpt-4o" } },
206
+ options: { maxEpochs: 1, allowDynamicSections: true },
207
+ persistence: { playbookPath: "playbooks/writer.json", autoPersist: true },
208
+ metric: { primaryOutputField: "article" },
209
+ compileOnStart: false,
210
+ },
211
+ },
212
+ ],
213
+ };
214
+
215
+ // Initialize crew (telemetry is for observability, separate from ACE)
216
+ const crew = new AxCrew(config, AxCrewFunctions, {
217
+ telemetry: { tracer, meter } // Optional: for OpenTelemetry observability
218
+ });
219
+
220
+ await crew.addAgentsToCrew(["writer"]);
221
+ const writer = crew.agents?.get("writer");
222
+
223
+ // Manual per-agent ACE operations
224
+ await writer?.optimizeOffline();
225
+ const prediction = await writer?.forward({ topic: "Quantum" });
226
+ await writer?.applyOnlineUpdate({
227
+ example: { topic: "Quantum" },
228
+ prediction,
229
+ feedback: "Too verbose."
230
+ });
231
+
232
+ // Crew-level feedback routing (for multi-agent tasks)
233
+ // The forward() call returns a taskId that can be used for feedback
234
+ const result = await writer.forward({ topic: "AI Ethics" });
235
+ await crew.applyTaskFeedback({
236
+ taskId: result._taskId, // Returned by forward()
237
+ feedback: "More balanced perspective needed",
238
+ strategy: "all" // Route to all involved agents
239
+ });
240
+ ```
241
+
242
+ ### Benefits
243
+
244
+ - **Separation of Concerns**: Telemetry (observability) vs Execution Tracking (ACE feedback)
245
+ - **Zero Breaking Changes**: All ACE features are opt-in
246
+ - **Uses Real AxACE**: Imports actual `AxACE` class from `@ax-llm/ax`
247
+ - **Simple Feedback Routing**: In-memory tracking without OpenTelemetry dependency
248
+ - **Flexible**: Supports per-agent and crew-level feedback
249
+
250
+ ### Notes
251
+
252
+ - Persistence is optional; in-memory playbooks work fine. Save to file/DB only if you want reuse after restarts.
253
+ - Metric configuration is required for offline compile; online updates don't need a metric.
254
+ - Defaults are conservative: ACE is only active when `ace` config is present.
255
+ - Telemetry and ACE are independent features - you can use one without the other.
@@ -0,0 +1,32 @@
1
+ {
2
+ "sections": {
3
+ "Guidelines": [
4
+ {
5
+ "id": "guidel-9507499a",
6
+ "section": "Guidelines",
7
+ "content": "For returning customers who have spent $15000 over 8 years, exercise compassion and allow a refund.",
8
+ "helpfulCount": 1,
9
+ "harmfulCount": 0,
10
+ "createdAt": "2026-01-13T13:07:18.958Z",
11
+ "updatedAt": "2026-01-13T13:07:18.958Z"
12
+ },
13
+ {
14
+ "id": "guidel-8b3abea4",
15
+ "section": "Guidelines",
16
+ "content": "Always refund orders that have incurred shipping damage.",
17
+ "helpfulCount": 1,
18
+ "harmfulCount": 0,
19
+ "createdAt": "2026-01-17T10:00:30.736Z",
20
+ "updatedAt": "2026-01-17T10:00:30.736Z"
21
+ }
22
+ ]
23
+ },
24
+ "createdAt": null,
25
+ "updatedAt": "2026-01-17T10:00:30.736Z",
26
+ "stats": {
27
+ "bulletCount": 2,
28
+ "helpfulCount": 2,
29
+ "harmfulCount": 0,
30
+ "tokenEstimate": 39
31
+ }
32
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "version": 1,
3
+ "sections": {
4
+ "Guidelines": [
5
+ {
6
+ "id": "guidel-541925c9",
7
+ "section": "Guidelines",
8
+ "content": "Only show non-stop flights in the search results.",
9
+ "helpfulCount": 1,
10
+ "harmfulCount": 0,
11
+ "createdAt": "2025-12-30T03:44:39.741Z",
12
+ "updatedAt": "2025-12-30T03:44:39.741Z"
13
+ }
14
+ ]
15
+ },
16
+ "stats": {
17
+ "bulletCount": 1,
18
+ "helpfulCount": 1,
19
+ "harmfulCount": 0,
20
+ "tokenEstimate": 13
21
+ },
22
+ "updatedAt": "2025-12-30T03:44:39.743Z"
23
+ }