@amitdeshmukh/ax-crew 8.7.3 → 9.0.1
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/CHANGELOG.md +40 -0
- package/README.md +9 -9
- package/dist/agents/agentConfig.d.ts +3 -0
- package/dist/agents/agentConfig.js +12 -4
- package/dist/agents/crew.d.ts +59 -0
- package/dist/agents/crew.js +356 -0
- package/dist/agents/deferredTools.d.ts +49 -0
- package/dist/agents/deferredTools.js +237 -0
- package/dist/agents/index.d.ts +4 -266
- package/dist/agents/index.js +3 -1014
- package/dist/agents/lazyAgent.d.ts +33 -0
- package/dist/agents/lazyAgent.js +78 -0
- package/dist/agents/statefulAgent.d.ts +97 -0
- package/dist/agents/statefulAgent.js +478 -0
- package/dist/index.d.ts +2 -2
- package/dist/types.d.ts +18 -1
- package/examples/graphjin-database-agent.ts +85 -64
- package/examples/write-post-and-publish-to-wordpress.ts +1 -1
- package/package.json +1 -1
- package/src/agents/agentConfig.ts +15 -8
- package/src/agents/crew.ts +444 -0
- package/src/agents/deferredTools.ts +275 -0
- package/src/agents/index.ts +4 -1281
- package/src/agents/lazyAgent.ts +95 -0
- package/src/agents/statefulAgent.ts +668 -0
- package/src/index.ts +7 -4
- package/src/skills/axcrew-functions.md +2 -2
- package/src/skills/axcrew-mcp.md +41 -1
- package/src/skills/axcrew-patterns.md +48 -4
- package/src/skills/axcrew-state.md +16 -16
- package/src/skills/axcrew.md +14 -1
- package/src/types.ts +19 -0
- package/.claude/settings.local.json +0 -13
- package/.claude/skills/ax-crew/SKILL.md +0 -466
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
import { AxAgent, AxAI, AxGen } from "@ax-llm/ax";
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
AxSignature,
|
|
5
|
+
AxAgentic,
|
|
6
|
+
AxFunction,
|
|
7
|
+
AxProgramForwardOptions,
|
|
8
|
+
AxProgramStreamingForwardOptions,
|
|
9
|
+
AxGenStreamingOut,
|
|
10
|
+
AxStepHooks,
|
|
11
|
+
} from "@ax-llm/ax";
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
StateInstance,
|
|
15
|
+
FunctionRegistryType,
|
|
16
|
+
UsageCost,
|
|
17
|
+
MCPTransportConfig,
|
|
18
|
+
ACEConfig,
|
|
19
|
+
AgentExecutionMode,
|
|
20
|
+
AxCrewAxAgentOptions,
|
|
21
|
+
} from "../types.js";
|
|
22
|
+
|
|
23
|
+
import type { AxCrew } from "./crew.js";
|
|
24
|
+
import { DeferredToolManager } from "./deferredTools.js";
|
|
25
|
+
import { MetricsRegistry } from "../metrics/index.js";
|
|
26
|
+
|
|
27
|
+
// Define the interface for the agent configuration
|
|
28
|
+
export interface ParsedAgentConfig {
|
|
29
|
+
ai: AxAI;
|
|
30
|
+
name: string;
|
|
31
|
+
executionMode: AgentExecutionMode;
|
|
32
|
+
axAgentOptions?: AxCrewAxAgentOptions;
|
|
33
|
+
description: string;
|
|
34
|
+
definition?: string;
|
|
35
|
+
signature: string | AxSignature;
|
|
36
|
+
functions: (
|
|
37
|
+
| AxFunction
|
|
38
|
+
| (new (state: Record<string, any>) => { toFunction: () => AxFunction })
|
|
39
|
+
| undefined
|
|
40
|
+
)[];
|
|
41
|
+
mcpServers?: Record<string, MCPTransportConfig>;
|
|
42
|
+
subAgentNames: string[];
|
|
43
|
+
examples?: Array<Record<string, any>>;
|
|
44
|
+
tracker?: any;
|
|
45
|
+
/** Agent-level forward options (maxSteps, showThoughts, thinkingTokenBudget, etc.) used as defaults when the caller doesn't supply them. */
|
|
46
|
+
forwardOptions?: Record<string, any>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Extend the AxAgent class from ax-llm
|
|
50
|
+
class StatefulAxAgent extends AxAgent<any, any> {
|
|
51
|
+
crewState: StateInstance;
|
|
52
|
+
axai: any;
|
|
53
|
+
private agentName: string;
|
|
54
|
+
private agentDefinition: string;
|
|
55
|
+
private executionMode: AgentExecutionMode;
|
|
56
|
+
private axGenProgram: AxGen<any, any>;
|
|
57
|
+
private costTracker?: any;
|
|
58
|
+
private debugEnabled: boolean = false;
|
|
59
|
+
private deferredToolManager?: DeferredToolManager;
|
|
60
|
+
private agentForwardOptions?: Record<string, any>;
|
|
61
|
+
private static readonly modernAxAgentRuntime =
|
|
62
|
+
typeof (AxAgent as any)?.prototype?.getFunction === "function" &&
|
|
63
|
+
typeof (AxAgent as any)?.prototype?.setExamples !== "function";
|
|
64
|
+
// ACE-related optional state
|
|
65
|
+
private aceConfig?: ACEConfig;
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
|
+
private aceOptimizer?: any;
|
|
68
|
+
private acePlaybook?: any;
|
|
69
|
+
private aceBaseInstruction?: string; // Original description before playbook injection
|
|
70
|
+
private isAxAIService(obj: any): obj is AxAI {
|
|
71
|
+
return !!obj && typeof obj.getName === 'function' && typeof obj.chat === 'function';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
constructor(
|
|
75
|
+
ai: AxAI,
|
|
76
|
+
options: Readonly<{
|
|
77
|
+
name: string;
|
|
78
|
+
description: string;
|
|
79
|
+
executionMode?: AgentExecutionMode;
|
|
80
|
+
axAgentOptions?: AxCrewAxAgentOptions;
|
|
81
|
+
definition?: string;
|
|
82
|
+
signature: string | AxSignature;
|
|
83
|
+
agents?: AxAgentic<any, any>[] | undefined;
|
|
84
|
+
functions?: (AxFunction | (() => AxFunction))[] | undefined;
|
|
85
|
+
examples?: Array<Record<string, any>> | undefined;
|
|
86
|
+
mcpServers?: Record<string, MCPTransportConfig> | undefined;
|
|
87
|
+
debug?: boolean;
|
|
88
|
+
forwardOptions?: Record<string, any>;
|
|
89
|
+
}>,
|
|
90
|
+
state: StateInstance
|
|
91
|
+
) {
|
|
92
|
+
const { examples, debug } = options;
|
|
93
|
+
const resolvedFunctions = (options.functions ?? []).map((fn) =>
|
|
94
|
+
typeof fn === "function" ? fn() : fn
|
|
95
|
+
) as AxFunction[];
|
|
96
|
+
const resolvedAgents = (options.agents ?? []) as AxAgentic<any, any>[];
|
|
97
|
+
const effectiveDefinition = (options.definition ?? options.description).trim();
|
|
98
|
+
|
|
99
|
+
if (StatefulAxAgent.modernAxAgentRuntime) {
|
|
100
|
+
const configuredAgentOptions = (options.axAgentOptions ?? {}) as Record<string, any>;
|
|
101
|
+
const configuredAgentGraph = (configuredAgentOptions.agents ?? {}) as Record<string, any>;
|
|
102
|
+
const configuredFunctionGraph = (configuredAgentOptions.functions ?? {}) as Record<string, any>;
|
|
103
|
+
const configuredActorOptions = (configuredAgentOptions.actorOptions ?? {}) as Record<string, any>;
|
|
104
|
+
const configuredResponderOptions = (configuredAgentOptions.responderOptions ?? {}) as Record<string, any>;
|
|
105
|
+
|
|
106
|
+
const modernOptions: Record<string, unknown> = {
|
|
107
|
+
...configuredAgentOptions,
|
|
108
|
+
debug: debug ?? configuredAgentOptions.debug ?? false,
|
|
109
|
+
contextFields: Array.isArray(configuredAgentOptions.contextFields)
|
|
110
|
+
? configuredAgentOptions.contextFields
|
|
111
|
+
: [],
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
modernOptions.agents = {
|
|
115
|
+
...configuredAgentGraph,
|
|
116
|
+
local: resolvedAgents,
|
|
117
|
+
};
|
|
118
|
+
modernOptions.functions = {
|
|
119
|
+
...configuredFunctionGraph,
|
|
120
|
+
local: resolvedFunctions,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
if (effectiveDefinition.length > 0) {
|
|
124
|
+
modernOptions.actorOptions = {
|
|
125
|
+
...configuredActorOptions,
|
|
126
|
+
description: configuredActorOptions.description ?? effectiveDefinition,
|
|
127
|
+
};
|
|
128
|
+
modernOptions.responderOptions = {
|
|
129
|
+
...configuredResponderOptions,
|
|
130
|
+
description: configuredResponderOptions.description ?? effectiveDefinition,
|
|
131
|
+
};
|
|
132
|
+
} else {
|
|
133
|
+
modernOptions.actorOptions = configuredActorOptions;
|
|
134
|
+
modernOptions.responderOptions = configuredResponderOptions;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
super(
|
|
138
|
+
{
|
|
139
|
+
ai,
|
|
140
|
+
agentIdentity: {
|
|
141
|
+
name: options.name,
|
|
142
|
+
description: options.description,
|
|
143
|
+
},
|
|
144
|
+
signature: options.signature as any,
|
|
145
|
+
} as any,
|
|
146
|
+
modernOptions as any
|
|
147
|
+
);
|
|
148
|
+
} else {
|
|
149
|
+
super(
|
|
150
|
+
{
|
|
151
|
+
name: options.name,
|
|
152
|
+
description: options.description,
|
|
153
|
+
definition: options.definition,
|
|
154
|
+
signature: options.signature,
|
|
155
|
+
agents: resolvedAgents,
|
|
156
|
+
functions: resolvedFunctions,
|
|
157
|
+
debug: debug ?? false,
|
|
158
|
+
} as any,
|
|
159
|
+
{} as any
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
this.crewState = state;
|
|
164
|
+
this.axai = ai;
|
|
165
|
+
this.agentName = options.name;
|
|
166
|
+
this.agentDefinition = effectiveDefinition;
|
|
167
|
+
this.executionMode = options.executionMode ?? "axgen";
|
|
168
|
+
this.debugEnabled = debug ?? false;
|
|
169
|
+
this.agentForwardOptions = options.forwardOptions;
|
|
170
|
+
// Convert sub-agents to callable functions so AxGen can invoke them as tools
|
|
171
|
+
const subAgentFunctions: AxFunction[] = resolvedAgents
|
|
172
|
+
.map(agent => {
|
|
173
|
+
try { return agent.getFunction() as AxFunction; }
|
|
174
|
+
catch { return undefined; }
|
|
175
|
+
})
|
|
176
|
+
.filter((fn): fn is AxFunction => fn !== undefined);
|
|
177
|
+
|
|
178
|
+
this.axGenProgram = new AxGen(options.signature as any, {
|
|
179
|
+
description: effectiveDefinition,
|
|
180
|
+
functions: [...resolvedFunctions, ...subAgentFunctions],
|
|
181
|
+
} as any);
|
|
182
|
+
|
|
183
|
+
for (const agent of resolvedAgents) {
|
|
184
|
+
try {
|
|
185
|
+
const childName = agent.getFunction().name;
|
|
186
|
+
this.axGenProgram.register(agent as any, childName);
|
|
187
|
+
} catch {
|
|
188
|
+
// Best-effort registration for optimizer/introspection support.
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Apply examples to compatibility layer if provided
|
|
193
|
+
if (examples && examples.length > 0) {
|
|
194
|
+
this.setExamplesCompat(examples);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @deprecated Use setExamplesCompat() to avoid Ax runtime version coupling.
|
|
200
|
+
*/
|
|
201
|
+
setExamples(examples: Readonly<Array<Record<string, any>>>): void {
|
|
202
|
+
this.setExamplesCompat(examples);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
setExamplesCompat(examples: Readonly<Array<Record<string, any>>>): void {
|
|
206
|
+
this.axGenProgram.setExamples(examples as any);
|
|
207
|
+
|
|
208
|
+
const baseSetExamples = (AxAgent.prototype as any).setExamples;
|
|
209
|
+
if (typeof baseSetExamples === "function") {
|
|
210
|
+
baseSetExamples.call(this, examples);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const internalProgram = (this as any).program;
|
|
215
|
+
if (typeof internalProgram?.setExamples === "function") {
|
|
216
|
+
internalProgram.setExamples(examples as any);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @deprecated Use setDescriptionCompat() to avoid Ax runtime version coupling.
|
|
222
|
+
*/
|
|
223
|
+
setDescription(description: string): void {
|
|
224
|
+
this.setDescriptionCompat(description);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
setDescriptionCompat(description: string): void {
|
|
228
|
+
this.agentDefinition = description;
|
|
229
|
+
this.axGenProgram.setDescription(description);
|
|
230
|
+
|
|
231
|
+
const baseSetDescription = (AxAgent.prototype as any).setDescription;
|
|
232
|
+
if (typeof baseSetDescription === "function") {
|
|
233
|
+
baseSetDescription.call(this, description);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const agentRuntime = this as any;
|
|
238
|
+
if (typeof agentRuntime.program?.setDescription === "function") {
|
|
239
|
+
agentRuntime.program.setDescription(description);
|
|
240
|
+
}
|
|
241
|
+
agentRuntime.actorDescription = description;
|
|
242
|
+
agentRuntime.responderDescription = description;
|
|
243
|
+
if (typeof agentRuntime._buildSplitPrograms === "function") {
|
|
244
|
+
agentRuntime._buildSplitPrograms();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
override getUsage() {
|
|
249
|
+
if (this.executionMode === "axgen") {
|
|
250
|
+
return this.axGenProgram.getUsage();
|
|
251
|
+
}
|
|
252
|
+
return super.getUsage();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
override resetUsage() {
|
|
256
|
+
this.axGenProgram.resetUsage();
|
|
257
|
+
super.resetUsage();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private resolveInvocationArgs<TOptions>(
|
|
261
|
+
first: Record<string, any> | AxAI,
|
|
262
|
+
second?: Record<string, any> | Readonly<TOptions>,
|
|
263
|
+
third?: Readonly<TOptions>
|
|
264
|
+
): {
|
|
265
|
+
ai: AxAI;
|
|
266
|
+
values: Record<string, any>;
|
|
267
|
+
options?: Readonly<TOptions>;
|
|
268
|
+
calledWithAI: boolean;
|
|
269
|
+
} {
|
|
270
|
+
const calledWithAI = this.isAxAIService(first);
|
|
271
|
+
const ai = (calledWithAI ? first : this.axai) as AxAI;
|
|
272
|
+
if (!ai) {
|
|
273
|
+
throw new Error(`No AI instance is configured for agent "${this.agentName}"`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const values = (calledWithAI ? second : first) as Record<string, any>;
|
|
277
|
+
const callerOptions = (calledWithAI ? third : second) as Readonly<TOptions> | undefined;
|
|
278
|
+
|
|
279
|
+
// Merge agent-level forward options as defaults under caller-supplied options
|
|
280
|
+
const options = this.agentForwardOptions
|
|
281
|
+
? ({ ...this.agentForwardOptions, ...callerOptions } as Readonly<TOptions>)
|
|
282
|
+
: callerOptions;
|
|
283
|
+
|
|
284
|
+
return { ai, values, options, calledWithAI };
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** Merge deferred tool step hooks into forward options */
|
|
288
|
+
private mergeStepHooks(options?: Readonly<AxProgramForwardOptions<any>>): Readonly<AxProgramForwardOptions<any>> | undefined {
|
|
289
|
+
if (!this.deferredToolManager?.isActive) return options;
|
|
290
|
+
|
|
291
|
+
const deferredHooks = this.deferredToolManager.getStepHooks();
|
|
292
|
+
const existingHooks = (options as any)?.stepHooks as AxStepHooks | undefined;
|
|
293
|
+
|
|
294
|
+
const mergedHooks: AxStepHooks = {
|
|
295
|
+
beforeStep: async (ctx) => {
|
|
296
|
+
await existingHooks?.beforeStep?.(ctx);
|
|
297
|
+
await deferredHooks.beforeStep?.(ctx);
|
|
298
|
+
},
|
|
299
|
+
afterStep: existingHooks?.afterStep,
|
|
300
|
+
afterFunctionExecution: async (ctx) => {
|
|
301
|
+
await existingHooks?.afterFunctionExecution?.(ctx);
|
|
302
|
+
await deferredHooks.afterFunctionExecution?.(ctx);
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
return { ...options, stepHooks: mergedHooks } as any;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private async executeForwardByMode(
|
|
310
|
+
mode: AgentExecutionMode,
|
|
311
|
+
ai: AxAI,
|
|
312
|
+
values: Record<string, any>,
|
|
313
|
+
options?: Readonly<AxProgramForwardOptions<any>>
|
|
314
|
+
): Promise<Record<string, any>> {
|
|
315
|
+
const opts = this.mergeStepHooks(options);
|
|
316
|
+
if (mode === "axgen") {
|
|
317
|
+
return this.axGenProgram.forward(ai, values, opts as any);
|
|
318
|
+
}
|
|
319
|
+
return super.forward(ai, values, opts as any);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private recordUsageMetrics(
|
|
323
|
+
labels: { crewId: string; agent: string },
|
|
324
|
+
mode: AgentExecutionMode
|
|
325
|
+
): void {
|
|
326
|
+
const builtIn =
|
|
327
|
+
mode === "axgen" ? this.axGenProgram.getUsage?.() : super.getUsage?.();
|
|
328
|
+
if (!Array.isArray(builtIn)) return;
|
|
329
|
+
|
|
330
|
+
const totals = builtIn.reduce(
|
|
331
|
+
(acc: any, u: any) => {
|
|
332
|
+
const pt = u.tokens?.promptTokens ?? u.promptTokens ?? 0;
|
|
333
|
+
const ct = u.tokens?.completionTokens ?? u.completionTokens ?? 0;
|
|
334
|
+
acc.promptTokens += typeof pt === "number" ? pt : 0;
|
|
335
|
+
acc.completionTokens += typeof ct === "number" ? ct : 0;
|
|
336
|
+
const model =
|
|
337
|
+
u.model ||
|
|
338
|
+
(this.axai as any)?.getLastUsedChatModel?.() ||
|
|
339
|
+
(this.axai as any)?.defaults?.model;
|
|
340
|
+
if (model) {
|
|
341
|
+
acc.byModel[model] = (acc.byModel[model] || 0) + (pt + ct);
|
|
342
|
+
}
|
|
343
|
+
return acc;
|
|
344
|
+
},
|
|
345
|
+
{ promptTokens: 0, completionTokens: 0, byModel: {} as Record<string, number> }
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
MetricsRegistry.recordTokens(labels, {
|
|
349
|
+
promptTokens: totals.promptTokens,
|
|
350
|
+
completionTokens: totals.completionTokens,
|
|
351
|
+
totalTokens: totals.promptTokens + totals.completionTokens,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const costTracker = (this as any).costTracker;
|
|
355
|
+
try {
|
|
356
|
+
for (const [m, count] of Object.entries(totals.byModel)) {
|
|
357
|
+
costTracker?.trackTokens?.(count, m);
|
|
358
|
+
}
|
|
359
|
+
const totalUSD = Number(costTracker?.getCurrentCost?.() ?? 0);
|
|
360
|
+
if (!Number.isNaN(totalUSD) && totalUSD > 0) {
|
|
361
|
+
MetricsRegistry.recordEstimatedCost(labels, totalUSD);
|
|
362
|
+
}
|
|
363
|
+
} catch {}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private async runForwardInvocation(
|
|
367
|
+
mode: AgentExecutionMode,
|
|
368
|
+
first: Record<string, any> | AxAI,
|
|
369
|
+
second?: Record<string, any> | Readonly<AxProgramForwardOptions<any>>,
|
|
370
|
+
third?: Readonly<AxProgramForwardOptions<any>>
|
|
371
|
+
): Promise<Record<string, any>> {
|
|
372
|
+
const { ai, values, options, calledWithAI } = this.resolveInvocationArgs(
|
|
373
|
+
first,
|
|
374
|
+
second,
|
|
375
|
+
third
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
const start = performance.now();
|
|
379
|
+
const crewId = (this.crewState as any)?.crewId || this.crewState.get?.("crewId") || "default";
|
|
380
|
+
const labels = { crewId, agent: this.agentName };
|
|
381
|
+
const taskId = `task_${crewId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
382
|
+
|
|
383
|
+
// Track execution context in crew for ACE feedback routing
|
|
384
|
+
const crewInstance = (this.crewState as any)?.crew as AxCrew;
|
|
385
|
+
if (crewInstance) {
|
|
386
|
+
if (calledWithAI) {
|
|
387
|
+
const parentTaskId = (this.crewState as any)?.currentTaskId;
|
|
388
|
+
if (parentTaskId) {
|
|
389
|
+
crewInstance.trackAgentExecution(parentTaskId, this.agentName, values);
|
|
390
|
+
}
|
|
391
|
+
} else {
|
|
392
|
+
crewInstance.trackAgentExecution(taskId, this.agentName, values);
|
|
393
|
+
(this.crewState as any).currentTaskId = taskId;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (this.debugEnabled) {
|
|
398
|
+
console.log(`[ACE Debug] forward() called, mode=${mode}, aceConfig=${!!this.aceConfig}`);
|
|
399
|
+
}
|
|
400
|
+
if (this.aceConfig) {
|
|
401
|
+
await this.composeInstructionWithPlaybook();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const result = await this.executeForwardByMode(mode, ai, values, options);
|
|
405
|
+
|
|
406
|
+
const durationMs = performance.now() - start;
|
|
407
|
+
MetricsRegistry.recordRequest(labels, false, durationMs);
|
|
408
|
+
this.recordUsageMetrics(labels, mode);
|
|
409
|
+
|
|
410
|
+
if (crewInstance) {
|
|
411
|
+
if (calledWithAI) {
|
|
412
|
+
const parentTaskId = (this.crewState as any)?.currentTaskId;
|
|
413
|
+
if (parentTaskId) {
|
|
414
|
+
crewInstance.recordAgentResult(parentTaskId, this.agentName, result);
|
|
415
|
+
}
|
|
416
|
+
} else {
|
|
417
|
+
crewInstance.recordAgentResult(taskId, this.agentName, result);
|
|
418
|
+
delete (this.crewState as any).currentTaskId;
|
|
419
|
+
(result as any)._taskId = taskId;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Function overloads for forward method
|
|
427
|
+
async forward(values: Record<string, any>, options?: Readonly<AxProgramForwardOptions<any>>): Promise<Record<string, any>>;
|
|
428
|
+
async forward(ai: AxAI, values: Record<string, any>, options?: Readonly<AxProgramForwardOptions<any>>): Promise<Record<string, any>>;
|
|
429
|
+
|
|
430
|
+
// Implementation
|
|
431
|
+
async forward(
|
|
432
|
+
first: Record<string, any> | AxAI,
|
|
433
|
+
second?: Record<string, any> | Readonly<AxProgramForwardOptions<any>>,
|
|
434
|
+
third?: Readonly<AxProgramForwardOptions<any>>
|
|
435
|
+
): Promise<Record<string, any>> {
|
|
436
|
+
return this.runForwardInvocation(this.executionMode, first, second, third);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
private runStreamingInvocation(
|
|
440
|
+
mode: AgentExecutionMode,
|
|
441
|
+
first: Record<string, any> | AxAI,
|
|
442
|
+
second?: Record<string, any> | Readonly<AxProgramStreamingForwardOptions<any>>,
|
|
443
|
+
third?: Readonly<AxProgramStreamingForwardOptions<any>>
|
|
444
|
+
): AxGenStreamingOut<any> {
|
|
445
|
+
const { ai, values, options } = this.resolveInvocationArgs(
|
|
446
|
+
first,
|
|
447
|
+
second,
|
|
448
|
+
third
|
|
449
|
+
);
|
|
450
|
+
const start = performance.now();
|
|
451
|
+
const crewId = (this.crewState as any)?.crewId || this.crewState.get?.("crewId") || "default";
|
|
452
|
+
const labels = { crewId, agent: this.agentName };
|
|
453
|
+
|
|
454
|
+
const opts = this.mergeStepHooks(options as any);
|
|
455
|
+
const createStream = () =>
|
|
456
|
+
mode === "axgen"
|
|
457
|
+
? this.axGenProgram.streamingForward(ai, values, opts as any)
|
|
458
|
+
: super.streamingForward(ai, values, opts as any);
|
|
459
|
+
|
|
460
|
+
const wrappedGenerator = (async function* (this: StatefulAxAgent) {
|
|
461
|
+
if (this.aceConfig) {
|
|
462
|
+
await this.composeInstructionWithPlaybook();
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const streamingResult = createStream();
|
|
466
|
+
try {
|
|
467
|
+
for await (const chunk of streamingResult) {
|
|
468
|
+
yield chunk;
|
|
469
|
+
}
|
|
470
|
+
} finally {
|
|
471
|
+
const durationMs = performance.now() - start;
|
|
472
|
+
MetricsRegistry.recordRequest(labels, true, durationMs);
|
|
473
|
+
this.recordUsageMetrics(labels, mode);
|
|
474
|
+
}
|
|
475
|
+
}).bind(this)();
|
|
476
|
+
|
|
477
|
+
return wrappedGenerator as AxGenStreamingOut<any>;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Add streaming forward method overloads
|
|
481
|
+
streamingForward(values: Record<string, any>, options?: Readonly<AxProgramStreamingForwardOptions<any>>): AxGenStreamingOut<any>;
|
|
482
|
+
streamingForward(ai: AxAI, values: Record<string, any>, options?: Readonly<AxProgramStreamingForwardOptions<any>>): AxGenStreamingOut<any>;
|
|
483
|
+
|
|
484
|
+
// Implementation
|
|
485
|
+
streamingForward(
|
|
486
|
+
first: Record<string, any> | AxAI,
|
|
487
|
+
second?: Record<string, any> | Readonly<AxProgramStreamingForwardOptions<any>>,
|
|
488
|
+
third?: Readonly<AxProgramStreamingForwardOptions<any>>
|
|
489
|
+
): AxGenStreamingOut<any> {
|
|
490
|
+
return this.runStreamingInvocation(this.executionMode, first, second, third);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Legacy cost API removed: rely on Ax trackers for cost reporting
|
|
494
|
+
getLastUsageCost(): UsageCost | null { return null; }
|
|
495
|
+
|
|
496
|
+
// Get the accumulated costs for all runs of this agent
|
|
497
|
+
getAccumulatedCosts(): UsageCost | null { return null; }
|
|
498
|
+
|
|
499
|
+
// Metrics API for this agent
|
|
500
|
+
getMetrics() {
|
|
501
|
+
const crewId = (this.crewState as any)?.crewId || (this.crewState.get?.('crewId')) || 'default';
|
|
502
|
+
return MetricsRegistry.snapshot({ crewId, agent: this.agentName } as any);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
resetMetrics(): void {
|
|
506
|
+
const crewId = (this.crewState as any)?.crewId || (this.crewState.get?.('crewId')) || 'default';
|
|
507
|
+
MetricsRegistry.reset({ crewId, agent: this.agentName } as any);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// =============
|
|
511
|
+
// ACE API
|
|
512
|
+
// =============
|
|
513
|
+
|
|
514
|
+
async initACE(ace?: ACEConfig): Promise<void> {
|
|
515
|
+
this.aceConfig = ace;
|
|
516
|
+
if (!ace) return;
|
|
517
|
+
try {
|
|
518
|
+
this.aceBaseInstruction =
|
|
519
|
+
this.agentDefinition || this.getSignature().getDescription() || '';
|
|
520
|
+
|
|
521
|
+
const { buildACEOptimizer, loadInitialPlaybook, createEmptyPlaybook } = await import('./ace.js');
|
|
522
|
+
this.aceOptimizer = buildACEOptimizer(this.axai, ace);
|
|
523
|
+
|
|
524
|
+
if (!ace.compileOnStart) {
|
|
525
|
+
(this.aceOptimizer as any).program = this;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const initial = await loadInitialPlaybook(ace.persistence);
|
|
529
|
+
this.applyPlaybook(initial ?? createEmptyPlaybook());
|
|
530
|
+
|
|
531
|
+
if (this.debugEnabled) {
|
|
532
|
+
console.log(`[ACE Debug] Initialized for ${this.agentName}, base instruction: ${this.aceBaseInstruction?.slice(0, 50)}...`);
|
|
533
|
+
}
|
|
534
|
+
} catch (error) {
|
|
535
|
+
console.warn(`Failed to initialize ACE for agent ${this.agentName}:`, error);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async optimizeOffline(params?: { metric?: any; examples?: any[] }): Promise<void> {
|
|
540
|
+
if (!this.aceConfig || !this.aceOptimizer) return;
|
|
541
|
+
try {
|
|
542
|
+
const { runOfflineCompile, resolveMetric } = await import('./ace.js');
|
|
543
|
+
const registry = (this as any).__functionsRegistry as FunctionRegistryType | undefined;
|
|
544
|
+
const metric = params?.metric || resolveMetric(this.aceConfig.metric, registry || {} as any);
|
|
545
|
+
const examples = params?.examples || [];
|
|
546
|
+
|
|
547
|
+
if (!metric || examples.length === 0) {
|
|
548
|
+
console.warn(`ACE offline compile skipped for ${this.agentName}: missing metric or examples`);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const result = await runOfflineCompile({
|
|
553
|
+
program: this,
|
|
554
|
+
optimizer: this.aceOptimizer,
|
|
555
|
+
metric,
|
|
556
|
+
examples,
|
|
557
|
+
persistence: this.aceConfig.persistence
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
if (result?.artifact?.playbook) {
|
|
561
|
+
await this.applyPlaybook(result.artifact.playbook);
|
|
562
|
+
}
|
|
563
|
+
} catch (error) {
|
|
564
|
+
console.warn(`ACE offline compile failed for ${this.agentName}:`, error);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
async applyOnlineUpdate(params: { example: any; prediction: any; feedback?: string }): Promise<void> {
|
|
569
|
+
if (!this.aceConfig) return;
|
|
570
|
+
if (!params.feedback?.trim()) return;
|
|
571
|
+
|
|
572
|
+
try {
|
|
573
|
+
const { persistPlaybook, addFeedbackToPlaybook, createEmptyPlaybook } = await import('./ace.js');
|
|
574
|
+
|
|
575
|
+
let playbook = this.acePlaybook ?? (this.aceOptimizer as any)?.playbook;
|
|
576
|
+
if (!playbook) {
|
|
577
|
+
playbook = createEmptyPlaybook();
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (this.debugEnabled) {
|
|
581
|
+
console.log(`[ACE Debug] Adding feedback to playbook: "${params.feedback}"`);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const teacherAI = (this.aceOptimizer as any)?.teacherAI;
|
|
585
|
+
const aiForAnalysis = teacherAI ?? this.axai;
|
|
586
|
+
|
|
587
|
+
await addFeedbackToPlaybook(playbook, params.feedback, aiForAnalysis, this.debugEnabled);
|
|
588
|
+
|
|
589
|
+
this.applyPlaybook(playbook);
|
|
590
|
+
|
|
591
|
+
if (this.aceOptimizer) {
|
|
592
|
+
(this.aceOptimizer as any).playbook = playbook;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (this.aceConfig.persistence?.autoPersist) {
|
|
596
|
+
await persistPlaybook(playbook, this.aceConfig.persistence);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
if (this.debugEnabled) {
|
|
600
|
+
console.log(`[ACE Debug] Playbook updated, sections: ${Object.keys(playbook.sections || {}).join(', ')}`);
|
|
601
|
+
}
|
|
602
|
+
} catch (error) {
|
|
603
|
+
console.warn(`ACE online update failed for ${this.agentName}:`, error);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
getPlaybook(): any | undefined {
|
|
608
|
+
return this.acePlaybook;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
applyPlaybook(pb: any): void {
|
|
612
|
+
this.acePlaybook = pb;
|
|
613
|
+
try {
|
|
614
|
+
(this.aceOptimizer as any).playbook = pb;
|
|
615
|
+
} catch {
|
|
616
|
+
// Ignore - optimizer may not be initialized yet
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
private async composeInstructionWithPlaybook(): Promise<void> {
|
|
621
|
+
const playbook = this.acePlaybook ?? (this.aceOptimizer as any)?.playbook;
|
|
622
|
+
|
|
623
|
+
if (this.debugEnabled) {
|
|
624
|
+
console.log(`[ACE Debug] composeInstructionWithPlaybook called`);
|
|
625
|
+
console.log(`[ACE Debug] playbook exists: ${!!playbook}, sections: ${playbook ? Object.keys(playbook.sections || {}).length : 0}`);
|
|
626
|
+
console.log(`[ACE Debug] baseInstruction: "${this.aceBaseInstruction?.slice(0, 50)}..."`);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (!playbook) return;
|
|
630
|
+
|
|
631
|
+
try {
|
|
632
|
+
const { renderPlaybook } = await import('./ace.js');
|
|
633
|
+
const rendered = renderPlaybook(playbook);
|
|
634
|
+
|
|
635
|
+
if (this.debugEnabled) {
|
|
636
|
+
console.log(`[ACE Debug] rendered playbook (${rendered.length} chars): ${rendered.slice(0, 100)}...`);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
if (!rendered) return;
|
|
640
|
+
|
|
641
|
+
const baseInstruction = this.aceBaseInstruction || '';
|
|
642
|
+
const combinedInstruction = [baseInstruction.trim(), '', rendered]
|
|
643
|
+
.filter((part) => part.trim().length > 0)
|
|
644
|
+
.join('\n\n');
|
|
645
|
+
|
|
646
|
+
if (this.debugEnabled) {
|
|
647
|
+
console.log(`[ACE Debug] combinedInstruction (${combinedInstruction.length} chars)`);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if (combinedInstruction.length >= 20) {
|
|
651
|
+
const program = (this as any).program;
|
|
652
|
+
if (program?.setDescription) {
|
|
653
|
+
program.setDescription(combinedInstruction);
|
|
654
|
+
}
|
|
655
|
+
this.setDescription(combinedInstruction);
|
|
656
|
+
|
|
657
|
+
if (this.debugEnabled) {
|
|
658
|
+
console.log(`[ACE Debug] setDescription called successfully`);
|
|
659
|
+
console.log(`[ACE Debug] Verifying - signature desc length: ${this.getSignature().getDescription()?.length}`);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
} catch (error) {
|
|
663
|
+
console.warn('[ACE Debug] Failed to compose instruction:', error);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
export { StatefulAxAgent };
|
package/src/index.ts
CHANGED
|
@@ -2,12 +2,13 @@ import { AxCrew } from './agents/index.js';
|
|
|
2
2
|
import { AxCrewFunctions } from './functions/index.js';
|
|
3
3
|
import type { AxCrewConfig, AxCrewOptions, AgentConfig, AgentExecutionMode, AxCrewAxAgentOptions } from './types.js';
|
|
4
4
|
|
|
5
|
-
import type {
|
|
6
|
-
UsageCost,
|
|
7
|
-
AggregatedMetrics,
|
|
5
|
+
import type {
|
|
6
|
+
UsageCost,
|
|
7
|
+
AggregatedMetrics,
|
|
8
8
|
AggregatedCosts,
|
|
9
|
-
StateInstance,
|
|
9
|
+
StateInstance,
|
|
10
10
|
FunctionRegistryType,
|
|
11
|
+
DeferredToolsConfig,
|
|
11
12
|
ACEConfig,
|
|
12
13
|
ACETeacherConfig,
|
|
13
14
|
ACEPersistenceConfig,
|
|
@@ -56,6 +57,8 @@ export {
|
|
|
56
57
|
type AxCrewOptions,
|
|
57
58
|
type StateInstance,
|
|
58
59
|
type UsageCost,
|
|
60
|
+
// Deferred tools
|
|
61
|
+
type DeferredToolsConfig,
|
|
59
62
|
// ACE type exports
|
|
60
63
|
type ACEConfig,
|
|
61
64
|
type ACETeacherConfig,
|