@amitdeshmukh/ax-crew 8.0.3 → 8.1.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.
@@ -1,5 +1,5 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
- import { AxAgent, AxAI } from "@ax-llm/ax";
2
+ import { AxAgent, AxAI, AxGen } from "@ax-llm/ax";
3
3
 
4
4
  import type {
5
5
  AxSignature,
@@ -18,6 +18,8 @@ import type {
18
18
  AxCrewOptions,
19
19
  MCPTransportConfig,
20
20
  ACEConfig,
21
+ AgentExecutionMode,
22
+ AxCrewAxAgentOptions,
21
23
  } from "../types.js";
22
24
 
23
25
  import { createState } from "../state/index.js";
@@ -28,6 +30,8 @@ import { MetricsRegistry } from "../metrics/index.js";
28
30
  interface ParsedAgentConfig {
29
31
  ai: AxAI;
30
32
  name: string;
33
+ executionMode: AgentExecutionMode;
34
+ axAgentOptions?: AxCrewAxAgentOptions;
31
35
  description: string;
32
36
  definition?: string;
33
37
  signature: string | AxSignature;
@@ -47,9 +51,14 @@ class StatefulAxAgent extends AxAgent<any, any> {
47
51
  state: StateInstance;
48
52
  axai: any;
49
53
  private agentName: string;
54
+ private agentDefinition: string;
55
+ private executionMode: AgentExecutionMode;
56
+ private axGenProgram: AxGen<any, any>;
50
57
  private costTracker?: any;
51
- private lastRecordedCostUSD: number = 0;
52
58
  private debugEnabled: boolean = false;
59
+ private static readonly modernAxAgentRuntime =
60
+ typeof (AxAgent as any)?.prototype?.getFunction === "function" &&
61
+ typeof (AxAgent as any)?.prototype?.setExamples !== "function";
53
62
  // ACE-related optional state
54
63
  private aceConfig?: ACEConfig;
55
64
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -59,15 +68,14 @@ class StatefulAxAgent extends AxAgent<any, any> {
59
68
  private isAxAIService(obj: any): obj is AxAI {
60
69
  return !!obj && typeof obj.getName === 'function' && typeof obj.chat === 'function';
61
70
  }
62
- private isAxAIInstance(obj: any): obj is AxAI {
63
- return !!obj && typeof obj === 'object' && ('defaults' in obj || 'modelInfo' in obj);
64
- }
65
71
 
66
72
  constructor(
67
73
  ai: AxAI,
68
74
  options: Readonly<{
69
75
  name: string;
70
76
  description: string;
77
+ executionMode?: AgentExecutionMode;
78
+ axAgentOptions?: AxCrewAxAgentOptions;
71
79
  definition?: string;
72
80
  signature: string | AxSignature;
73
81
  agents?: AxAgentic<any, any>[] | undefined;
@@ -78,161 +86,342 @@ class StatefulAxAgent extends AxAgent<any, any> {
78
86
  }>,
79
87
  state: StateInstance
80
88
  ) {
81
- const { examples, debug, ...restOptions } = options;
82
- const formattedOptions = {
83
- ...restOptions,
84
- functions: restOptions.functions?.map((fn) =>
85
- typeof fn === "function" ? fn() : fn
86
- ) as AxFunction[] | undefined,
87
- };
88
- super(formattedOptions);
89
+ const { examples, debug } = options;
90
+ const resolvedFunctions = (options.functions ?? []).map((fn) =>
91
+ typeof fn === "function" ? fn() : fn
92
+ ) as AxFunction[];
93
+ const resolvedAgents = (options.agents ?? []) as AxAgentic<any, any>[];
94
+ const effectiveDefinition = (options.definition ?? options.description).trim();
95
+
96
+ if (StatefulAxAgent.modernAxAgentRuntime) {
97
+ const configuredAgentOptions = (options.axAgentOptions ?? {}) as Record<string, any>;
98
+ const configuredAgentGraph = (configuredAgentOptions.agents ?? {}) as Record<string, any>;
99
+ const configuredFunctionGraph = (configuredAgentOptions.functions ?? {}) as Record<string, any>;
100
+ const configuredActorOptions = (configuredAgentOptions.actorOptions ?? {}) as Record<string, any>;
101
+ const configuredResponderOptions = (configuredAgentOptions.responderOptions ?? {}) as Record<string, any>;
102
+
103
+ const modernOptions: Record<string, unknown> = {
104
+ ...configuredAgentOptions,
105
+ debug: debug ?? configuredAgentOptions.debug ?? false,
106
+ contextFields: Array.isArray(configuredAgentOptions.contextFields)
107
+ ? configuredAgentOptions.contextFields
108
+ : [],
109
+ };
110
+
111
+ modernOptions.agents = {
112
+ ...configuredAgentGraph,
113
+ local: resolvedAgents,
114
+ };
115
+ modernOptions.functions = {
116
+ ...configuredFunctionGraph,
117
+ local: resolvedFunctions,
118
+ };
119
+
120
+ if (effectiveDefinition.length > 0) {
121
+ modernOptions.actorOptions = {
122
+ ...configuredActorOptions,
123
+ description: configuredActorOptions.description ?? effectiveDefinition,
124
+ };
125
+ modernOptions.responderOptions = {
126
+ ...configuredResponderOptions,
127
+ description: configuredResponderOptions.description ?? effectiveDefinition,
128
+ };
129
+ } else {
130
+ modernOptions.actorOptions = configuredActorOptions;
131
+ modernOptions.responderOptions = configuredResponderOptions;
132
+ }
133
+
134
+ super(
135
+ {
136
+ ai,
137
+ agentIdentity: {
138
+ name: options.name,
139
+ description: options.description,
140
+ },
141
+ signature: options.signature as any,
142
+ } as any,
143
+ modernOptions as any
144
+ );
145
+ } else {
146
+ super(
147
+ {
148
+ name: options.name,
149
+ description: options.description,
150
+ definition: options.definition,
151
+ signature: options.signature,
152
+ agents: resolvedAgents,
153
+ functions: resolvedFunctions,
154
+ debug: debug ?? false,
155
+ } as any,
156
+ {} as any
157
+ );
158
+ }
159
+
89
160
  this.state = state;
90
161
  this.axai = ai;
91
162
  this.agentName = options.name;
163
+ this.agentDefinition = effectiveDefinition;
164
+ this.executionMode = options.executionMode ?? "axagent";
92
165
  this.debugEnabled = debug ?? false;
166
+ this.axGenProgram = new AxGen(options.signature as any, {
167
+ description: effectiveDefinition,
168
+ functions: resolvedFunctions,
169
+ } as any);
170
+
171
+ for (const agent of resolvedAgents) {
172
+ try {
173
+ const childName = agent.getFunction().name;
174
+ this.axGenProgram.register(agent as any, childName);
175
+ } catch {
176
+ // Best-effort registration for optimizer/introspection support.
177
+ }
178
+ }
93
179
 
94
- // Set examples if provided
180
+ // Apply examples to compatibility layer if provided
95
181
  if (examples && examples.length > 0) {
96
- super.setExamples(examples);
182
+ this.setExamplesCompat(examples);
97
183
  }
98
184
  }
99
185
 
100
- // Function overloads for forward method
101
- async forward(values: Record<string, any>, options?: Readonly<AxProgramForwardOptions<any>>): Promise<Record<string, any>>;
102
- async forward(ai: AxAI, values: Record<string, any>, options?: Readonly<AxProgramForwardOptions<any>>): Promise<Record<string, any>>;
103
-
104
- // Implementation
105
- async forward(
186
+ /**
187
+ * @deprecated Use setExamplesCompat() to avoid Ax runtime version coupling.
188
+ */
189
+ setExamples(examples: Readonly<Array<Record<string, any>>>): void {
190
+ this.setExamplesCompat(examples);
191
+ }
192
+
193
+ setExamplesCompat(examples: Readonly<Array<Record<string, any>>>): void {
194
+ this.axGenProgram.setExamples(examples as any);
195
+
196
+ const baseSetExamples = (AxAgent.prototype as any).setExamples;
197
+ if (typeof baseSetExamples === "function") {
198
+ baseSetExamples.call(this, examples);
199
+ return;
200
+ }
201
+
202
+ const internalProgram = (this as any).program;
203
+ if (typeof internalProgram?.setExamples === "function") {
204
+ internalProgram.setExamples(examples as any);
205
+ }
206
+ }
207
+
208
+ /**
209
+ * @deprecated Use setDescriptionCompat() to avoid Ax runtime version coupling.
210
+ */
211
+ setDescription(description: string): void {
212
+ this.setDescriptionCompat(description);
213
+ }
214
+
215
+ setDescriptionCompat(description: string): void {
216
+ this.agentDefinition = description;
217
+ this.axGenProgram.setDescription(description);
218
+
219
+ const baseSetDescription = (AxAgent.prototype as any).setDescription;
220
+ if (typeof baseSetDescription === "function") {
221
+ baseSetDescription.call(this, description);
222
+ return;
223
+ }
224
+
225
+ const agentRuntime = this as any;
226
+ if (typeof agentRuntime.program?.setDescription === "function") {
227
+ agentRuntime.program.setDescription(description);
228
+ }
229
+ agentRuntime.actorDescription = description;
230
+ agentRuntime.responderDescription = description;
231
+ if (typeof agentRuntime._buildSplitPrograms === "function") {
232
+ agentRuntime._buildSplitPrograms();
233
+ }
234
+ }
235
+
236
+ override getUsage() {
237
+ if (this.executionMode === "axgen") {
238
+ return this.axGenProgram.getUsage();
239
+ }
240
+ return super.getUsage();
241
+ }
242
+
243
+ override resetUsage() {
244
+ this.axGenProgram.resetUsage();
245
+ super.resetUsage();
246
+ }
247
+
248
+ private resolveInvocationArgs<TOptions>(
249
+ first: Record<string, any> | AxAI,
250
+ second?: Record<string, any> | Readonly<TOptions>,
251
+ third?: Readonly<TOptions>
252
+ ): {
253
+ ai: AxAI;
254
+ values: Record<string, any>;
255
+ options?: Readonly<TOptions>;
256
+ calledWithAI: boolean;
257
+ } {
258
+ const calledWithAI = this.isAxAIService(first);
259
+ const ai = (calledWithAI ? first : this.axai) as AxAI;
260
+ if (!ai) {
261
+ throw new Error(`No AI instance is configured for agent "${this.agentName}"`);
262
+ }
263
+
264
+ const values = (calledWithAI ? second : first) as Record<string, any>;
265
+ const options = (calledWithAI ? third : second) as Readonly<TOptions> | undefined;
266
+
267
+ return { ai, values, options, calledWithAI };
268
+ }
269
+
270
+ private async executeForwardByMode(
271
+ mode: AgentExecutionMode,
272
+ ai: AxAI,
273
+ values: Record<string, any>,
274
+ options?: Readonly<AxProgramForwardOptions<any>>
275
+ ): Promise<Record<string, any>> {
276
+ if (mode === "axgen") {
277
+ return this.axGenProgram.forward(ai, values, options as any);
278
+ }
279
+ return super.forward(ai, values, options as any);
280
+ }
281
+
282
+ private recordUsageMetrics(
283
+ labels: { crewId: string; agent: string },
284
+ mode: AgentExecutionMode
285
+ ): void {
286
+ const builtIn =
287
+ mode === "axgen" ? this.axGenProgram.getUsage?.() : super.getUsage?.();
288
+ if (!Array.isArray(builtIn)) return;
289
+
290
+ const totals = builtIn.reduce(
291
+ (acc: any, u: any) => {
292
+ const pt = u.tokens?.promptTokens ?? u.promptTokens ?? 0;
293
+ const ct = u.tokens?.completionTokens ?? u.completionTokens ?? 0;
294
+ acc.promptTokens += typeof pt === "number" ? pt : 0;
295
+ acc.completionTokens += typeof ct === "number" ? ct : 0;
296
+ const model =
297
+ u.model ||
298
+ (this.axai as any)?.getLastUsedChatModel?.() ||
299
+ (this.axai as any)?.defaults?.model;
300
+ if (model) {
301
+ acc.byModel[model] = (acc.byModel[model] || 0) + (pt + ct);
302
+ }
303
+ return acc;
304
+ },
305
+ { promptTokens: 0, completionTokens: 0, byModel: {} as Record<string, number> }
306
+ );
307
+
308
+ MetricsRegistry.recordTokens(labels, {
309
+ promptTokens: totals.promptTokens,
310
+ completionTokens: totals.completionTokens,
311
+ totalTokens: totals.promptTokens + totals.completionTokens,
312
+ });
313
+
314
+ const costTracker = (this as any).costTracker;
315
+ try {
316
+ for (const [m, count] of Object.entries(totals.byModel)) {
317
+ costTracker?.trackTokens?.(count, m);
318
+ }
319
+ const totalUSD = Number(costTracker?.getCurrentCost?.() ?? 0);
320
+ if (!Number.isNaN(totalUSD) && totalUSD > 0) {
321
+ MetricsRegistry.recordEstimatedCost(labels, totalUSD);
322
+ }
323
+ } catch {}
324
+ }
325
+
326
+ private async runForwardInvocation(
327
+ mode: AgentExecutionMode,
106
328
  first: Record<string, any> | AxAI,
107
329
  second?: Record<string, any> | Readonly<AxProgramForwardOptions<any>>,
108
330
  third?: Readonly<AxProgramForwardOptions<any>>
109
331
  ): Promise<Record<string, any>> {
110
- let result;
332
+ const { ai, values, options, calledWithAI } = this.resolveInvocationArgs(
333
+ first,
334
+ second,
335
+ third
336
+ );
111
337
 
112
338
  const start = performance.now();
113
- const crewId = (this.state as any)?.crewId || (this.state.get?.('crewId')) || 'default';
114
- const labels = { crewId, agent: this.agentName } as any;
115
- const input = this.isAxAIService(first) ? second : first;
339
+ const crewId = (this.state as any)?.crewId || this.state.get?.("crewId") || "default";
340
+ const labels = { crewId, agent: this.agentName };
116
341
  const taskId = `task_${crewId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
117
342
 
118
343
  // Track execution context in crew for ACE feedback routing
119
344
  const crewInstance = (this.state as any)?.crew as AxCrew;
120
345
  if (crewInstance) {
121
- if (this.isAxAIService(first)) {
122
- // For sub-agent calls, track under parent task ID
346
+ if (calledWithAI) {
123
347
  const parentTaskId = (this.state as any)?.currentTaskId;
124
348
  if (parentTaskId) {
125
- crewInstance.trackAgentExecution(parentTaskId, this.agentName, input);
349
+ crewInstance.trackAgentExecution(parentTaskId, this.agentName, values);
126
350
  }
127
351
  } else {
128
- // Root-level call - start new execution tracking
129
- crewInstance.trackAgentExecution(taskId, this.agentName, input);
352
+ crewInstance.trackAgentExecution(taskId, this.agentName, values);
130
353
  (this.state as any).currentTaskId = taskId;
131
354
  }
132
355
  }
133
356
 
134
- // Before forward: compose instruction with current playbook (mirrors AxACE.compile behavior)
135
- // This ensures the agent uses the latest playbook context for this call
136
357
  if (this.debugEnabled) {
137
- console.log(`[ACE Debug] forward() called, aceConfig=${!!this.aceConfig}`);
358
+ console.log(`[ACE Debug] forward() called, mode=${mode}, aceConfig=${!!this.aceConfig}`);
138
359
  }
139
360
  if (this.aceConfig) {
140
361
  await this.composeInstructionWithPlaybook();
141
362
  }
142
363
 
143
- // Execute the forward call
144
- // Note: OpenTelemetry spans are automatically created by AxAI (configured via AxCrewOptions.telemetry)
145
- if (this.isAxAIService(first)) {
146
- // Sub-agent case (called with AI service)
147
- result = await super.forward(this.axai, second as Record<string, any>, third);
148
- } else {
149
- // Direct call case
150
- result = await super.forward(this.axai, first, second as Readonly<AxProgramForwardOptions<any>>);
151
- }
364
+ const result = await this.executeForwardByMode(mode, ai, values, options);
152
365
 
153
- // Track metrics and costs after the call using built-in usage
154
366
  const durationMs = performance.now() - start;
155
367
  MetricsRegistry.recordRequest(labels, false, durationMs);
156
- // Always record tokens from built-in usage array if present
157
- const builtIn = (this as any).getUsage?.();
158
- if (Array.isArray(builtIn)) {
159
- const totals = builtIn.reduce(
160
- (acc: any, u: any) => {
161
- const pt = u.tokens?.promptTokens ?? u.promptTokens ?? 0;
162
- const ct = u.tokens?.completionTokens ?? u.completionTokens ?? 0;
163
- acc.promptTokens += typeof pt === 'number' ? pt : 0;
164
- acc.completionTokens += typeof ct === 'number' ? ct : 0;
165
- // also aggregate per-model to feed Ax tracker
166
- const model = u.model || (this.axai as any)?.getLastUsedChatModel?.() || (this.axai as any)?.defaults?.model;
167
- if (model) {
168
- acc.byModel[model] = (acc.byModel[model] || 0) + (pt + ct);
169
- }
170
- return acc;
171
- },
172
- { promptTokens: 0, completionTokens: 0, byModel: {} as Record<string, number> }
173
- );
174
- MetricsRegistry.recordTokens(labels, {
175
- promptTokens: totals.promptTokens,
176
- completionTokens: totals.completionTokens,
177
- totalTokens: totals.promptTokens + totals.completionTokens,
178
- });
179
- // Feed Ax's cost tracker with token totals per model; Ax owns pricing
180
- const costTracker = (this as any).costTracker;
181
- try {
182
- for (const [m, count] of Object.entries(totals.byModel)) {
183
- costTracker?.trackTokens?.(count, m);
184
- }
185
- const totalUSD = Number(costTracker?.getCurrentCost?.() ?? 0);
186
- if (!Number.isNaN(totalUSD) && totalUSD > 0) {
187
- MetricsRegistry.recordEstimatedCost(labels, totalUSD);
188
- }
189
- } catch {}
190
- }
368
+ this.recordUsageMetrics(labels, mode);
191
369
 
192
- // Record result in crew execution history for ACE feedback routing
193
370
  if (crewInstance) {
194
- if (this.isAxAIService(first)) {
195
- // For sub-agent calls, record under parent task ID
371
+ if (calledWithAI) {
196
372
  const parentTaskId = (this.state as any)?.currentTaskId;
197
373
  if (parentTaskId) {
198
374
  crewInstance.recordAgentResult(parentTaskId, this.agentName, result);
199
375
  }
200
376
  } else {
201
- // Root-level result - include taskId for feedback routing
202
377
  crewInstance.recordAgentResult(taskId, this.agentName, result);
203
- // Clean up current task ID
204
378
  delete (this.state as any).currentTaskId;
205
- // Attach taskId to result for feedback routing convenience
206
- result._taskId = taskId;
379
+ (result as any)._taskId = taskId;
207
380
  }
208
381
  }
209
382
 
210
383
  return result;
211
384
  }
212
385
 
213
- // Add streaming forward method overloads
214
- streamingForward(values: Record<string, any>, options?: Readonly<AxProgramStreamingForwardOptions<any>>): AxGenStreamingOut<any>;
215
- streamingForward(ai: AxAI, values: Record<string, any>, options?: Readonly<AxProgramStreamingForwardOptions<any>>): AxGenStreamingOut<any>;
216
-
386
+ // Function overloads for forward method
387
+ async forward(values: Record<string, any>, options?: Readonly<AxProgramForwardOptions<any>>): Promise<Record<string, any>>;
388
+ async forward(ai: AxAI, values: Record<string, any>, options?: Readonly<AxProgramForwardOptions<any>>): Promise<Record<string, any>>;
389
+
217
390
  // Implementation
218
- streamingForward(
391
+ async forward(
392
+ first: Record<string, any> | AxAI,
393
+ second?: Record<string, any> | Readonly<AxProgramForwardOptions<any>>,
394
+ third?: Readonly<AxProgramForwardOptions<any>>
395
+ ): Promise<Record<string, any>> {
396
+ return this.runForwardInvocation(this.executionMode, first, second, third);
397
+ }
398
+
399
+ private runStreamingInvocation(
400
+ mode: AgentExecutionMode,
219
401
  first: Record<string, any> | AxAI,
220
402
  second?: Record<string, any> | Readonly<AxProgramStreamingForwardOptions<any>>,
221
403
  third?: Readonly<AxProgramStreamingForwardOptions<any>>
222
404
  ): AxGenStreamingOut<any> {
405
+ const { ai, values, options } = this.resolveInvocationArgs(
406
+ first,
407
+ second,
408
+ third
409
+ );
223
410
  const start = performance.now();
224
- const crewId = (this.state as any)?.crewId || (this.state.get?.('crewId')) || 'default';
225
- const labels = { crewId, agent: this.agentName } as any;
226
- let streamingResult: AxGenStreamingOut<any>;
227
-
228
- if (this.isAxAIService(first)) {
229
- streamingResult = super.streamingForward(this.axai, second as Record<string, any>, third);
230
- } else {
231
- streamingResult = super.streamingForward(this.axai, first, second as Readonly<AxProgramStreamingForwardOptions<any>>);
232
- }
411
+ const crewId = (this.state as any)?.crewId || this.state.get?.("crewId") || "default";
412
+ const labels = { crewId, agent: this.agentName };
413
+
414
+ const createStream = () =>
415
+ mode === "axgen"
416
+ ? this.axGenProgram.streamingForward(ai, values, options as any)
417
+ : super.streamingForward(ai, values, options as any);
418
+
419
+ const wrappedGenerator = (async function* (this: StatefulAxAgent) {
420
+ if (this.aceConfig) {
421
+ await this.composeInstructionWithPlaybook();
422
+ }
233
423
 
234
- // Create a new async generator that tracks costs after completion
235
- const wrappedGenerator = (async function*(this: StatefulAxAgent) {
424
+ const streamingResult = createStream();
236
425
  try {
237
426
  for await (const chunk of streamingResult) {
238
427
  yield chunk;
@@ -240,53 +429,26 @@ class StatefulAxAgent extends AxAgent<any, any> {
240
429
  } finally {
241
430
  const durationMs = performance.now() - start;
242
431
  MetricsRegistry.recordRequest(labels, true, durationMs);
243
- // Record tokens from built-in usage array if present
244
- const builtIn = (this as any).getUsage?.();
245
- if (Array.isArray(builtIn)) {
246
- const totals = builtIn.reduce(
247
- (acc: any, u: any) => {
248
- const pt = u.tokens?.promptTokens ?? u.promptTokens ?? 0;
249
- const ct = u.tokens?.completionTokens ?? u.completionTokens ?? 0;
250
- acc.promptTokens += typeof pt === 'number' ? pt : 0;
251
- acc.completionTokens += typeof ct === 'number' ? ct : 0;
252
- const model = u.model || (this.axai as any)?.getLastUsedChatModel?.() || (this.axai as any)?.defaults?.model;
253
- if (model) {
254
- acc.byModel[model] = (acc.byModel[model] || 0) + (pt + ct);
255
- }
256
- return acc;
257
- },
258
- { promptTokens: 0, completionTokens: 0, byModel: {} as Record<string, number> }
259
- );
260
- MetricsRegistry.recordTokens(labels, {
261
- promptTokens: totals.promptTokens,
262
- completionTokens: totals.completionTokens,
263
- totalTokens: totals.promptTokens + totals.completionTokens,
264
- });
265
- const costTracker = (this as any).costTracker;
266
- try {
267
- for (const [m, count] of Object.entries(totals.byModel)) {
268
- costTracker?.trackTokens?.(count, m);
269
- }
270
- const totalUSD = Number(costTracker?.getCurrentCost?.() ?? 0);
271
- if (!Number.isNaN(totalUSD) && totalUSD > 0) {
272
- MetricsRegistry.recordEstimatedCost(labels, totalUSD);
273
- }
274
- } catch {}
275
- }
276
- // Record estimated cost (USD) via attached tracker if available
277
- const costTracker = (this as any).costTracker;
278
- try {
279
- const totalUSD = Number(costTracker?.getCurrentCost?.() ?? 0);
280
- if (!Number.isNaN(totalUSD) && totalUSD > 0) {
281
- MetricsRegistry.recordEstimatedCost(labels, totalUSD);
282
- }
283
- } catch {}
432
+ this.recordUsageMetrics(labels, mode);
284
433
  }
285
434
  }).bind(this)();
286
435
 
287
436
  return wrappedGenerator as AxGenStreamingOut<any>;
288
437
  }
289
438
 
439
+ // Add streaming forward method overloads
440
+ streamingForward(values: Record<string, any>, options?: Readonly<AxProgramStreamingForwardOptions<any>>): AxGenStreamingOut<any>;
441
+ streamingForward(ai: AxAI, values: Record<string, any>, options?: Readonly<AxProgramStreamingForwardOptions<any>>): AxGenStreamingOut<any>;
442
+
443
+ // Implementation
444
+ streamingForward(
445
+ first: Record<string, any> | AxAI,
446
+ second?: Record<string, any> | Readonly<AxProgramStreamingForwardOptions<any>>,
447
+ third?: Readonly<AxProgramStreamingForwardOptions<any>>
448
+ ): AxGenStreamingOut<any> {
449
+ return this.runStreamingInvocation(this.executionMode, first, second, third);
450
+ }
451
+
290
452
  // Legacy cost API removed: rely on Ax trackers for cost reporting
291
453
  getLastUsageCost(): UsageCost | null { return null; }
292
454
 
@@ -328,7 +490,8 @@ class StatefulAxAgent extends AxAgent<any, any> {
328
490
  if (!ace) return;
329
491
  try {
330
492
  // Capture base instruction BEFORE any playbook injection (mirrors AxACE.extractProgramInstruction)
331
- this.aceBaseInstruction = this.getSignature().getDescription() || '';
493
+ this.aceBaseInstruction =
494
+ this.agentDefinition || this.getSignature().getDescription() || '';
332
495
 
333
496
  const { buildACEOptimizer, loadInitialPlaybook, createEmptyPlaybook } = await import('./ace.js');
334
497
  // Build optimizer with agent's AI as student
@@ -615,7 +778,7 @@ class AxCrew {
615
778
  );
616
779
 
617
780
  // Destructure with type assertion
618
- const { ai, name, description, signature, functions, subAgentNames, examples, tracker } = agentConfig;
781
+ const { ai, name, executionMode, axAgentOptions, description, signature, functions, subAgentNames, examples, tracker } = agentConfig;
619
782
 
620
783
  // Get subagents for the AI agent
621
784
  const subAgents = subAgentNames.map((subAgentName: string) => {
@@ -685,6 +848,8 @@ class AxCrew {
685
848
  ai,
686
849
  {
687
850
  name,
851
+ executionMode,
852
+ axAgentOptions,
688
853
  description,
689
854
  definition: (agentConfig as any).definition,
690
855
  signature,
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AxCrew } from './agents/index.js';
2
2
  import { AxCrewFunctions } from './functions/index.js';
3
- import type { AxCrewConfig, AxCrewOptions, AgentConfig } from './types.js';
3
+ import type { AxCrewConfig, AxCrewOptions, AgentConfig, AgentExecutionMode, AxCrewAxAgentOptions } from './types.js';
4
4
 
5
5
  import type {
6
6
  UsageCost,
@@ -50,6 +50,8 @@ export {
50
50
  type AggregatedMetrics,
51
51
  type AggregatedCosts,
52
52
  type AgentConfig,
53
+ type AgentExecutionMode,
54
+ type AxCrewAxAgentOptions,
53
55
  type AxCrewConfig,
54
56
  type AxCrewOptions,
55
57
  type StateInstance,
@@ -60,4 +62,4 @@ export {
60
62
  type ACEPersistenceConfig,
61
63
  type ACEOptionsConfig,
62
64
  type ACEMetricConfig,
63
- };
65
+ };
package/src/types.ts CHANGED
@@ -4,12 +4,21 @@ import type {
4
4
  AxModelConfig,
5
5
  AxMCPStreamableHTTPTransportOptions,
6
6
  AxProgramForwardOptions,
7
- AxAIArgs
7
+ AxAIArgs,
8
+ AxAgentOptions
8
9
  } from '@ax-llm/ax';
9
10
 
10
11
  // Provider ids are derived from Ax's factory arg type so new providers added in Ax
11
12
  // are picked up at compile time without updating AxCrew.
12
13
  export type Provider = AxAIArgs<any>['name'];
14
+ export type AgentExecutionMode = 'axagent' | 'axgen';
15
+ export type AxCrewAxAgentOptions =
16
+ Partial<Omit<AxAgentOptions, 'agents' | 'functions' | 'contextFields'>> & {
17
+ contextFields?: AxAgentOptions['contextFields'];
18
+ agents?: AxAgentOptions['agents'];
19
+ functions?: AxAgentOptions['functions'];
20
+ fields?: AxAgentOptions['fields'];
21
+ };
13
22
 
14
23
  /**
15
24
  * A state instance that is shared between agents.
@@ -208,6 +217,17 @@ interface ACEConfig {
208
217
  interface AgentConfig {
209
218
  name: string;
210
219
  description: string;
220
+ /**
221
+ * Choose the execution engine for this agent.
222
+ * - `axagent` (default): Uses AxAgent capabilities.
223
+ * - `axgen`: Uses AxGen capabilities.
224
+ */
225
+ executionMode?: AgentExecutionMode;
226
+ /**
227
+ * AxAgent runtime options (RLM mode, context fields, recursion, actor/responder options, etc).
228
+ * Only applies when executionMode is `axagent`.
229
+ */
230
+ axAgentOptions?: AxCrewAxAgentOptions;
211
231
  /**
212
232
  * Optional detailed persona/program definition. If provided, becomes the system prompt.
213
233
  * Must be at least 100 characters per Ax semantics.