@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/.claude/settings.local.json +7 -0
- package/CHANGELOG.md +35 -0
- package/README.md +240 -0
- package/dist/agents/ace.d.ts +134 -0
- package/dist/agents/ace.js +477 -0
- package/dist/agents/agentConfig.d.ts +3 -2
- package/dist/agents/agentConfig.js +6 -2
- package/dist/agents/index.d.ts +86 -2
- package/dist/agents/index.js +364 -6
- package/dist/index.d.ts +3 -3
- package/dist/types.d.ts +52 -1
- package/examples/README.md +46 -8
- package/examples/ace-customer-support.ts +480 -0
- package/examples/ace-flight-finder.ts +329 -0
- package/examples/telemetry-demo.ts +165 -0
- package/package.json +3 -2
- package/plan.md +255 -0
- package/playbooks/customer-support.json +32 -0
- package/playbooks/flight-assistant.json +23 -0
- package/src/agents/ace.ts +594 -0
- package/src/agents/agentConfig.ts +8 -2
- package/src/agents/index.ts +416 -8
- package/src/index.ts +14 -2
- package/src/types.ts +67 -1
- package/tests/telemetry.test.ts +81 -0
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
|
+
}
|