@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.
@@ -10,6 +10,13 @@ class StatefulAxAgent extends AxAgent {
10
10
  agentName;
11
11
  costTracker;
12
12
  lastRecordedCostUSD = 0;
13
+ debugEnabled = false;
14
+ // ACE-related optional state
15
+ aceConfig;
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ aceOptimizer;
18
+ acePlaybook;
19
+ aceBaseInstruction; // Original description before playbook injection
13
20
  isAxAIService(obj) {
14
21
  return !!obj && typeof obj.getName === 'function' && typeof obj.chat === 'function';
15
22
  }
@@ -17,7 +24,7 @@ class StatefulAxAgent extends AxAgent {
17
24
  return !!obj && typeof obj === 'object' && ('defaults' in obj || 'modelInfo' in obj);
18
25
  }
19
26
  constructor(ai, options, state) {
20
- const { examples, ...restOptions } = options;
27
+ const { examples, debug, ...restOptions } = options;
21
28
  const formattedOptions = {
22
29
  ...restOptions,
23
30
  functions: restOptions.functions?.map((fn) => typeof fn === "function" ? fn() : fn),
@@ -26,6 +33,7 @@ class StatefulAxAgent extends AxAgent {
26
33
  this.state = state;
27
34
  this.axai = ai;
28
35
  this.agentName = options.name;
36
+ this.debugEnabled = debug ?? false;
29
37
  // Set examples if provided
30
38
  if (examples && examples.length > 0) {
31
39
  super.setExamples(examples);
@@ -37,8 +45,34 @@ class StatefulAxAgent extends AxAgent {
37
45
  const start = performance.now();
38
46
  const crewId = this.state?.crewId || (this.state.get?.('crewId')) || 'default';
39
47
  const labels = { crewId, agent: this.agentName };
40
- // Track costs regardless of whether it's a direct or sub-agent call
41
- // This ensures we capture multiple legitimate calls to the same agent
48
+ const input = this.isAxAIService(first) ? second : first;
49
+ const taskId = `task_${crewId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
50
+ // Track execution context in crew for ACE feedback routing
51
+ const crewInstance = this.state?.crew;
52
+ if (crewInstance) {
53
+ if (this.isAxAIService(first)) {
54
+ // For sub-agent calls, track under parent task ID
55
+ const parentTaskId = this.state?.currentTaskId;
56
+ if (parentTaskId) {
57
+ crewInstance.trackAgentExecution(parentTaskId, this.agentName, input);
58
+ }
59
+ }
60
+ else {
61
+ // Root-level call - start new execution tracking
62
+ crewInstance.trackAgentExecution(taskId, this.agentName, input);
63
+ this.state.currentTaskId = taskId;
64
+ }
65
+ }
66
+ // Before forward: compose instruction with current playbook (mirrors AxACE.compile behavior)
67
+ // This ensures the agent uses the latest playbook context for this call
68
+ if (this.debugEnabled) {
69
+ console.log(`[ACE Debug] forward() called, aceConfig=${!!this.aceConfig}`);
70
+ }
71
+ if (this.aceConfig) {
72
+ await this.composeInstructionWithPlaybook();
73
+ }
74
+ // Execute the forward call
75
+ // Note: OpenTelemetry spans are automatically created by AxAI (configured via AxCrewOptions.telemetry)
42
76
  if (this.isAxAIService(first)) {
43
77
  // Sub-agent case (called with AI service)
44
78
  result = await super.forward(this.axai, second, third);
@@ -83,6 +117,24 @@ class StatefulAxAgent extends AxAgent {
83
117
  }
84
118
  catch { }
85
119
  }
120
+ // Record result in crew execution history for ACE feedback routing
121
+ if (crewInstance) {
122
+ if (this.isAxAIService(first)) {
123
+ // For sub-agent calls, record under parent task ID
124
+ const parentTaskId = this.state?.currentTaskId;
125
+ if (parentTaskId) {
126
+ crewInstance.recordAgentResult(parentTaskId, this.agentName, result);
127
+ }
128
+ }
129
+ else {
130
+ // Root-level result - include taskId for feedback routing
131
+ crewInstance.recordAgentResult(taskId, this.agentName, result);
132
+ // Clean up current task ID
133
+ delete this.state.currentTaskId;
134
+ // Attach taskId to result for feedback routing convenience
135
+ result._taskId = taskId;
136
+ }
137
+ }
86
138
  return result;
87
139
  }
88
140
  // Implementation
@@ -174,6 +226,196 @@ class StatefulAxAgent extends AxAgent {
174
226
  const crewId = this.state?.crewId || (this.state.get?.('crewId')) || 'default';
175
227
  MetricsRegistry.reset({ crewId, agent: this.agentName });
176
228
  }
229
+ // =============
230
+ // ACE API - Agentic Context Engineering for online learning
231
+ // Reference: https://axllm.dev/ace/
232
+ // =============
233
+ /**
234
+ * Initialize ACE (Agentic Context Engineering) for this agent.
235
+ * Builds the optimizer and loads any initial playbook from persistence.
236
+ * Sets up the optimizer for online-only mode if compileOnStart is false.
237
+ */
238
+ async initACE(ace) {
239
+ this.aceConfig = ace;
240
+ if (!ace)
241
+ return;
242
+ try {
243
+ // Capture base instruction BEFORE any playbook injection (mirrors AxACE.extractProgramInstruction)
244
+ this.aceBaseInstruction = this.getSignature().getDescription() || '';
245
+ const { buildACEOptimizer, loadInitialPlaybook, createEmptyPlaybook } = await import('./ace.js');
246
+ // Build optimizer with agent's AI as student
247
+ this.aceOptimizer = buildACEOptimizer(this.axai, ace);
248
+ // For online-only mode (no offline compile), we need to set the program
249
+ // reference so applyOnlineUpdate can work. AxACE requires compile() to
250
+ // set the program, but we can set it directly for online-only use.
251
+ if (!ace.compileOnStart) {
252
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
253
+ this.aceOptimizer.program = this;
254
+ }
255
+ // Load initial playbook or create empty one
256
+ const initial = await loadInitialPlaybook(ace.persistence);
257
+ this.applyPlaybook(initial ?? createEmptyPlaybook());
258
+ if (this.debugEnabled) {
259
+ console.log(`[ACE Debug] Initialized for ${this.agentName}, base instruction: ${this.aceBaseInstruction?.slice(0, 50)}...`);
260
+ }
261
+ }
262
+ catch (error) {
263
+ console.warn(`Failed to initialize ACE for agent ${this.agentName}:`, error);
264
+ }
265
+ }
266
+ /**
267
+ * Run offline ACE compilation with examples and metric.
268
+ * Compiles the playbook based on training examples.
269
+ */
270
+ async optimizeOffline(params) {
271
+ if (!this.aceConfig || !this.aceOptimizer)
272
+ return;
273
+ try {
274
+ const { runOfflineCompile, resolveMetric } = await import('./ace.js');
275
+ const registry = this.__functionsRegistry;
276
+ const metric = params?.metric || resolveMetric(this.aceConfig.metric, registry || {});
277
+ const examples = params?.examples || [];
278
+ if (!metric || examples.length === 0) {
279
+ console.warn(`ACE offline compile skipped for ${this.agentName}: missing metric or examples`);
280
+ return;
281
+ }
282
+ const result = await runOfflineCompile({
283
+ program: this,
284
+ optimizer: this.aceOptimizer,
285
+ metric,
286
+ examples,
287
+ persistence: this.aceConfig.persistence
288
+ });
289
+ // Apply optimized playbook if compilation succeeded
290
+ if (result?.artifact?.playbook) {
291
+ await this.applyPlaybook(result.artifact.playbook);
292
+ }
293
+ }
294
+ catch (error) {
295
+ console.warn(`ACE offline compile failed for ${this.agentName}:`, error);
296
+ }
297
+ }
298
+ /**
299
+ * Apply online ACE update based on user feedback.
300
+ *
301
+ * For preference-based feedback (e.g., "only show flights between 9am-12pm"),
302
+ * we use our own feedback analyzer that preserves specificity.
303
+ *
304
+ * Note: AxACE's built-in curator is designed for error correction (severity mismatches)
305
+ * and tends to over-abstract preference feedback into generic guidelines.
306
+ * We bypass it and directly use our feedback analyzer for better results.
307
+ */
308
+ async applyOnlineUpdate(params) {
309
+ if (!this.aceConfig)
310
+ return;
311
+ if (!params.feedback?.trim())
312
+ return; // Nothing to do without feedback
313
+ try {
314
+ const { persistPlaybook, addFeedbackToPlaybook, createEmptyPlaybook } = await import('./ace.js');
315
+ // Get or create playbook
316
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
317
+ let playbook = this.acePlaybook ?? this.aceOptimizer?.playbook;
318
+ if (!playbook) {
319
+ playbook = createEmptyPlaybook();
320
+ }
321
+ if (this.debugEnabled) {
322
+ console.log(`[ACE Debug] Adding feedback to playbook: "${params.feedback}"`);
323
+ }
324
+ // Use teacher AI (or student AI as fallback) for smart categorization
325
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
326
+ const teacherAI = this.aceOptimizer?.teacherAI;
327
+ const aiForAnalysis = teacherAI ?? this.axai;
328
+ // Directly add feedback to playbook using our analyzer (preserves specificity)
329
+ await addFeedbackToPlaybook(playbook, params.feedback, aiForAnalysis, this.debugEnabled);
330
+ // Store updated playbook (injection happens in next forward() call)
331
+ this.applyPlaybook(playbook);
332
+ // Sync with optimizer if available
333
+ if (this.aceOptimizer) {
334
+ this.aceOptimizer.playbook = playbook;
335
+ }
336
+ // Persist if auto-persist enabled
337
+ if (this.aceConfig.persistence?.autoPersist) {
338
+ await persistPlaybook(playbook, this.aceConfig.persistence);
339
+ }
340
+ if (this.debugEnabled) {
341
+ console.log(`[ACE Debug] Playbook updated, sections: ${Object.keys(playbook.sections || {}).join(', ')}`);
342
+ }
343
+ }
344
+ catch (error) {
345
+ console.warn(`ACE online update failed for ${this.agentName}:`, error);
346
+ }
347
+ }
348
+ /**
349
+ * Get the current ACE playbook for this agent.
350
+ */
351
+ getPlaybook() {
352
+ return this.acePlaybook;
353
+ }
354
+ /**
355
+ * Apply an ACE playbook to this agent.
356
+ * Stores the playbook for use in next forward() call.
357
+ * Note: Playbook is composed into instruction BEFORE each forward(), mirroring AxACE.compile behavior.
358
+ */
359
+ applyPlaybook(pb) {
360
+ this.acePlaybook = pb;
361
+ // Also update optimizer's internal playbook if possible
362
+ try {
363
+ this.aceOptimizer.playbook = pb;
364
+ }
365
+ catch {
366
+ // Ignore - optimizer may not be initialized yet
367
+ }
368
+ }
369
+ /**
370
+ * Compose instruction with current playbook and set on agent.
371
+ * This mirrors what AxACE does internally before each forward() during compile().
372
+ * Should be called BEFORE forward() to ensure playbook is in the prompt.
373
+ */
374
+ async composeInstructionWithPlaybook() {
375
+ const playbook = this.acePlaybook ?? this.aceOptimizer?.playbook;
376
+ if (this.debugEnabled) {
377
+ console.log(`[ACE Debug] composeInstructionWithPlaybook called`);
378
+ console.log(`[ACE Debug] playbook exists: ${!!playbook}, sections: ${playbook ? Object.keys(playbook.sections || {}).length : 0}`);
379
+ console.log(`[ACE Debug] baseInstruction: "${this.aceBaseInstruction?.slice(0, 50)}..."`);
380
+ }
381
+ if (!playbook)
382
+ return;
383
+ try {
384
+ const { renderPlaybook } = await import('./ace.js');
385
+ const rendered = renderPlaybook(playbook);
386
+ if (this.debugEnabled) {
387
+ console.log(`[ACE Debug] rendered playbook (${rendered.length} chars): ${rendered.slice(0, 100)}...`);
388
+ }
389
+ if (!rendered)
390
+ return;
391
+ // Compose: base instruction + playbook (just like AxACE.composeInstruction)
392
+ const baseInstruction = this.aceBaseInstruction || '';
393
+ const combinedInstruction = [baseInstruction.trim(), '', rendered]
394
+ .filter((part) => part.trim().length > 0)
395
+ .join('\n\n');
396
+ if (this.debugEnabled) {
397
+ console.log(`[ACE Debug] combinedInstruction (${combinedInstruction.length} chars)`);
398
+ }
399
+ if (combinedInstruction.length >= 20) {
400
+ // Call setDescription on the internal program (like AxACE does)
401
+ // AxAgent.setDescription() only updates the signature, but we need
402
+ // to update the program's description which is used for the system prompt
403
+ const program = this.program;
404
+ if (program?.setDescription) {
405
+ program.setDescription(combinedInstruction);
406
+ }
407
+ // Also update via AxAgent's setDescription for consistency
408
+ this.setDescription(combinedInstruction);
409
+ if (this.debugEnabled) {
410
+ console.log(`[ACE Debug] setDescription called successfully`);
411
+ console.log(`[ACE Debug] Verifying - signature desc length: ${this.getSignature().getDescription()?.length}`);
412
+ }
413
+ }
414
+ }
415
+ catch (error) {
416
+ console.warn('[ACE Debug] Failed to compose instruction:', error);
417
+ }
418
+ }
177
419
  }
178
420
  /**
179
421
  * AxCrew orchestrates a set of Ax agents that share state,
@@ -196,17 +438,21 @@ class StatefulAxAgent extends AxAgent {
196
438
  */
197
439
  class AxCrew {
198
440
  crewConfig;
441
+ options;
199
442
  functionsRegistry = {};
200
443
  crewId;
201
444
  agents;
202
445
  state;
446
+ // Execution history for ACE feedback routing
447
+ executionHistory = new Map();
203
448
  /**
204
449
  * Creates an instance of AxCrew.
205
450
  * @param {AxCrewConfig} crewConfig - JSON object with crew configuration.
206
451
  * @param {FunctionRegistryType} [functionsRegistry={}] - The registry of functions to use in the crew.
452
+ * @param {AxCrewOptions} [options] - Optional settings for the crew (e.g., telemetry).
207
453
  * @param {string} [crewId=uuidv4()] - The unique identifier for the crew.
208
454
  */
209
- constructor(crewConfig, functionsRegistry = {}, crewId = uuidv4()) {
455
+ constructor(crewConfig, functionsRegistry = {}, options, crewId = uuidv4()) {
210
456
  // Basic validation of crew configuration
211
457
  if (!crewConfig || typeof crewConfig !== 'object' || !('crew' in crewConfig)) {
212
458
  throw new Error('Invalid crew configuration');
@@ -220,6 +466,7 @@ class AxCrew {
220
466
  this.crewConfig = crewConfig;
221
467
  this.functionsRegistry = functionsRegistry;
222
468
  this.crewId = crewId;
469
+ this.options = options;
223
470
  this.agents = new Map();
224
471
  this.state = createState(crewId);
225
472
  // Make crewId discoverable to metrics
@@ -233,7 +480,7 @@ class AxCrew {
233
480
  */
234
481
  createAgent = async (agentName) => {
235
482
  try {
236
- const agentConfig = await parseAgentConfig(agentName, this.crewConfig, this.functionsRegistry, this.state);
483
+ const agentConfig = await parseAgentConfig(agentName, this.crewConfig, this.functionsRegistry, this.state, this.options);
237
484
  // Destructure with type assertion
238
485
  const { ai, name, description, signature, functions, subAgentNames, examples, tracker } = agentConfig;
239
486
  // Get subagents for the AI agent
@@ -267,6 +514,8 @@ class AxCrew {
267
514
  }
268
515
  }
269
516
  // Create an instance of StatefulAxAgent
517
+ // Set crew reference in state for execution tracking (ACE feedback routing)
518
+ const agentState = { ...this.state, crew: this };
270
519
  const agent = new StatefulAxAgent(ai, {
271
520
  name,
272
521
  description,
@@ -275,8 +524,24 @@ class AxCrew {
275
524
  functions: uniqueFunctions,
276
525
  agents: uniqueSubAgents,
277
526
  examples,
278
- }, this.state);
527
+ debug: agentConfig.debug,
528
+ }, agentState);
279
529
  agent.costTracker = tracker;
530
+ agent.__functionsRegistry = this.functionsRegistry;
531
+ // Initialize ACE if configured
532
+ try {
533
+ const crewAgent = parseCrewConfig(this.crewConfig).crew.find(a => a.name === name);
534
+ const ace = crewAgent?.ace;
535
+ if (ace) {
536
+ await agent.initACE?.(ace);
537
+ if (ace.compileOnStart) {
538
+ const { resolveMetric } = await import('./ace.js');
539
+ const metric = resolveMetric(ace.metric, this.functionsRegistry);
540
+ await agent.optimizeOffline?.({ metric, examples });
541
+ }
542
+ }
543
+ }
544
+ catch { }
280
545
  return agent;
281
546
  }
282
547
  catch (error) {
@@ -394,11 +659,104 @@ class AxCrew {
394
659
  throw error;
395
660
  }
396
661
  }
662
+ /**
663
+ * Track agent execution for ACE feedback routing
664
+ */
665
+ trackAgentExecution(taskId, agentName, input) {
666
+ if (!this.executionHistory.has(taskId)) {
667
+ this.executionHistory.set(taskId, {
668
+ taskId,
669
+ rootAgent: agentName,
670
+ involvedAgents: new Set([agentName]),
671
+ taskInput: input,
672
+ agentResults: new Map(),
673
+ startTime: Date.now()
674
+ });
675
+ }
676
+ else {
677
+ // Add to involved agents if not already present
678
+ const context = this.executionHistory.get(taskId);
679
+ context.involvedAgents.add(agentName);
680
+ }
681
+ }
682
+ /**
683
+ * Record agent result for ACE feedback routing
684
+ */
685
+ recordAgentResult(taskId, agentName, result) {
686
+ const context = this.executionHistory.get(taskId);
687
+ if (context) {
688
+ context.agentResults.set(agentName, result);
689
+ context.endTime = Date.now();
690
+ }
691
+ }
692
+ /**
693
+ * Get agent involvement for a task (used for ACE feedback routing)
694
+ */
695
+ getTaskAgentInvolvement(taskId) {
696
+ const context = this.executionHistory.get(taskId);
697
+ if (!context)
698
+ return null;
699
+ return {
700
+ rootAgent: context.rootAgent,
701
+ involvedAgents: Array.from(context.involvedAgents),
702
+ taskInput: context.taskInput,
703
+ agentResults: context.agentResults,
704
+ duration: context.endTime ? context.endTime - context.startTime : undefined
705
+ };
706
+ }
707
+ /**
708
+ * Apply feedback to agents involved in a task for ACE online learning
709
+ */
710
+ async applyTaskFeedback(params) {
711
+ const involvement = this.getTaskAgentInvolvement(params.taskId);
712
+ if (!involvement) {
713
+ console.warn(`No execution history found for task ${params.taskId}`);
714
+ return;
715
+ }
716
+ const { involvedAgents, taskInput, agentResults } = involvement;
717
+ const strategy = params.strategy || 'all';
718
+ // Determine which agents to update based on strategy
719
+ let agentsToUpdate = [];
720
+ if (strategy === 'primary') {
721
+ agentsToUpdate = [involvement.rootAgent];
722
+ }
723
+ else if (strategy === 'all' || strategy === 'weighted') {
724
+ agentsToUpdate = involvedAgents;
725
+ }
726
+ // Apply feedback to each involved agent
727
+ for (const agentName of agentsToUpdate) {
728
+ const agent = this.agents?.get(agentName);
729
+ if (agent && typeof agent.applyOnlineUpdate === 'function') {
730
+ try {
731
+ await agent.applyOnlineUpdate({
732
+ example: taskInput,
733
+ prediction: agentResults.get(agentName),
734
+ feedback: params.feedback
735
+ });
736
+ }
737
+ catch (error) {
738
+ console.warn(`Failed to apply ACE feedback to agent ${agentName}:`, error);
739
+ }
740
+ }
741
+ }
742
+ }
743
+ /**
744
+ * Clean up old execution history (call periodically to prevent memory leaks)
745
+ */
746
+ cleanupOldExecutions(maxAgeMs = 3600000) {
747
+ const cutoffTime = Date.now() - maxAgeMs;
748
+ for (const [taskId, context] of this.executionHistory) {
749
+ if (context.startTime < cutoffTime) {
750
+ this.executionHistory.delete(taskId);
751
+ }
752
+ }
753
+ }
397
754
  /**
398
755
  * Cleans up the crew by dereferencing agents and resetting the state.
399
756
  */
400
757
  destroy() {
401
758
  this.agents = null;
759
+ this.executionHistory.clear();
402
760
  this.state.reset();
403
761
  }
404
762
  /**
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AxCrew } from './agents/index.js';
2
2
  import { AxCrewFunctions } from './functions/index.js';
3
- import type { AxCrewConfig, AgentConfig } from './types.js';
4
- import type { UsageCost, AggregatedMetrics, AggregatedCosts, StateInstance, FunctionRegistryType } from './types.js';
3
+ import type { AxCrewConfig, AxCrewOptions, AgentConfig } from './types.js';
4
+ import type { UsageCost, AggregatedMetrics, AggregatedCosts, StateInstance, FunctionRegistryType, ACEConfig, ACETeacherConfig, ACEPersistenceConfig, ACEOptionsConfig, ACEMetricConfig } from './types.js';
5
5
  /**
6
6
  * Metrics types and helpers for request counts, token usage, and estimated cost.
7
7
  *
@@ -29,4 +29,4 @@ export {
29
29
  /** See class JSDoc on the `AxCrew` implementation. */
30
30
  _AxCrew as AxCrew,
31
31
  /** Built-in function registry; see file docs in `src/functions/index.ts`. */
32
- _AxCrewFunctions as AxCrewFunctions, FunctionRegistryType, type AggregatedMetrics, type AggregatedCosts, type AgentConfig, type AxCrewConfig, type StateInstance, type UsageCost, };
32
+ _AxCrewFunctions as AxCrewFunctions, FunctionRegistryType, type AggregatedMetrics, type AggregatedCosts, type AgentConfig, type AxCrewConfig, type AxCrewOptions, type StateInstance, type UsageCost, type ACEConfig, type ACETeacherConfig, type ACEPersistenceConfig, type ACEOptionsConfig, type ACEMetricConfig, };
package/dist/types.d.ts CHANGED
@@ -127,6 +127,40 @@ interface MCPStreamableHTTPTransportConfig {
127
127
  * @property {MCPStdioTransportConfig | MCPHTTPSSETransportConfig | MCPStreambleHTTPTransportConfig} config - The config for the MCP server. Config can be either stdio, http-sse, or streamable http transport.
128
128
  */
129
129
  type MCPTransportConfig = MCPStdioTransportConfig | MCPHTTPSSETransportConfig | MCPStreamableHTTPTransportConfig;
130
+ interface ACETeacherConfig {
131
+ provider?: Provider;
132
+ providerKeyName?: string;
133
+ apiURL?: string;
134
+ ai?: AxModelConfig & {
135
+ model: string;
136
+ };
137
+ providerArgs?: Record<string, unknown>;
138
+ }
139
+ interface ACEPersistenceConfig {
140
+ playbookPath?: string;
141
+ initialPlaybook?: Record<string, any>;
142
+ autoPersist?: boolean;
143
+ onPersist?: (pb: any) => Promise<void> | void;
144
+ onLoad?: () => Promise<any> | any;
145
+ }
146
+ interface ACEOptionsConfig {
147
+ maxEpochs?: number;
148
+ allowDynamicSections?: boolean;
149
+ tokenBudget?: number;
150
+ reflectorPrompt?: string;
151
+ curatorPrompt?: string;
152
+ }
153
+ interface ACEMetricConfig {
154
+ metricFnName?: string;
155
+ primaryOutputField?: string;
156
+ }
157
+ interface ACEConfig {
158
+ teacher?: ACETeacherConfig;
159
+ persistence?: ACEPersistenceConfig;
160
+ options?: ACEOptionsConfig;
161
+ metric?: ACEMetricConfig;
162
+ compileOnStart?: boolean;
163
+ }
130
164
  /**
131
165
  * The configuration for an agent.
132
166
  *
@@ -175,6 +209,8 @@ interface AgentConfig {
175
209
  agents?: string[];
176
210
  examples?: Array<Record<string, any>>;
177
211
  mcpServers?: Record<string, MCPTransportConfig>;
212
+ /** Optional AxACE configuration to enable optimization for this agent */
213
+ ace?: ACEConfig;
178
214
  }
179
215
  /**
180
216
  * The configuration object for an AxCrew instance.
@@ -216,4 +252,19 @@ interface AgentConfig {
216
252
  interface AxCrewConfig {
217
253
  crew: AgentConfig[];
218
254
  }
219
- export { type AgentConfig, type AxCrewConfig, type AggregatedMetrics, type StateInstance, type FunctionRegistryType, type MCPStdioTransportConfig, type MCPHTTPSSETransportConfig, type MCPStreamableHTTPTransportConfig, type MCPTransportConfig, type ModelUsage, type ModelInfo, type UsageCost, type AggregatedCosts };
255
+ /**
256
+ * Options for the AxCrew instance, specifically allowing optional OpenTelemetry injection.
257
+ *
258
+ * @property {Object} [telemetry] - Telemetry configuration.
259
+ * @property {any} [telemetry.tracer] - OpenTelemetry Tracer instance.
260
+ * @property {any} [telemetry.meter] - OpenTelemetry Meter instance.
261
+ */
262
+ interface AxCrewOptions {
263
+ /** Enable debug logging for ACE and other internal operations */
264
+ debug?: boolean;
265
+ telemetry?: {
266
+ tracer?: any;
267
+ meter?: any;
268
+ };
269
+ }
270
+ export { type AgentConfig, type AxCrewConfig, type AxCrewOptions, type AggregatedMetrics, type StateInstance, type FunctionRegistryType, type MCPStdioTransportConfig, type MCPHTTPSSETransportConfig, type MCPStreamableHTTPTransportConfig, type MCPTransportConfig, type ModelUsage, type ModelInfo, type UsageCost, type AggregatedCosts, type ACEConfig, type ACEMetricConfig, type ACEOptionsConfig, type ACEPersistenceConfig, type ACETeacherConfig };
@@ -122,18 +122,56 @@ Key features:
122
122
  - Integration with external APIs via MCP servers
123
123
  - Cost tracking across agents
124
124
 
125
- ### 5. AxCrew Basic Usage
126
- [`axcrew.ts`](./axcrew.ts)
125
+ ### 5. ACE Flight Assistant (Feedback Learning)
126
+ [`ace-feedback-routing.ts`](./ace-feedback-routing.ts)
127
127
 
128
- A basic example showing core AxCrew features:
129
- - Setting up a crew
130
- - Adding agents
131
- - Using shared state
132
- - Cost tracking
133
- - Error handling
128
+ Demonstrates ACE (Agentic Context Engineering) learning from user feedback:
129
+ - A flight booking assistant using Google Flights MCP server
130
+ - Real-time playbook updates based on user feedback
131
+ - Persistence of learned preferences across sessions
132
+ - Interactive CLI for flight queries
133
+
134
+ **Required Setup:**
135
+ ```bash
136
+ # Clone the Google Flights MCP server
137
+ git clone https://github.com/opspawn/Google-Flights-MCP-Server.git
138
+ cd Google-Flights-MCP-Server
139
+ python -m venv .venv && source .venv/bin/activate
140
+ pip install -r requirements.txt && playwright install
141
+
142
+ # Set environment variable
143
+ export GOOGLE_FLIGHTS_SERVER_PATH=/path/to/server.py
144
+ ```
145
+
146
+ Key features:
147
+ - ACE feedback loop integration
148
+ - Playbook persistence to JSON
149
+ - Learning from natural language feedback
150
+
151
+ ### 6. ACE Customer Support (Edge Case Learning)
152
+ [`ace-customer-support.ts`](./ace-customer-support.ts)
153
+
154
+ Shows how ACE learns to handle edge cases beyond standard policies:
155
+ - A customer support agent with predefined company policies
156
+ - Learning exceptions from supervisor feedback (e.g., "loyal customers get extended returns")
157
+ - Applying learned exceptions to similar future cases
158
+ - Interactive ticket handling demo
134
159
 
135
160
  **Required Dependencies:** None beyond core package
136
161
 
162
+ ```typescript
163
+ // Example feedback that teaches the agent:
164
+ // "For loyal customers (5+ years), extend return window to 60 days"
165
+ // "Medical emergencies justify extended deadlines"
166
+ // "Defective products override 'final sale' policy"
167
+ ```
168
+
169
+ Key features:
170
+ - Edge case learning from feedback
171
+ - Policy exception handling
172
+ - Playbook persistence showing learned rules
173
+ - Sample tickets demonstrating various scenarios
174
+
137
175
  ## Running the Examples
138
176
 
139
177
  1. Clone the repository: