@amitdeshmukh/ax-crew 8.7.3 → 9.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/CHANGELOG.md +34 -0
- package/README.md +9 -9
- package/dist/agents/agentConfig.d.ts +2 -0
- package/dist/agents/agentConfig.js +11 -4
- package/dist/agents/crew.d.ts +59 -0
- package/dist/agents/crew.js +355 -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 +93 -0
- package/dist/agents/statefulAgent.js +473 -0
- package/dist/index.d.ts +2 -2
- package/dist/types.d.ts +18 -1
- package/examples/graphjin-database-agent.ts +68 -57
- package/examples/write-post-and-publish-to-wordpress.ts +1 -1
- package/package.json +1 -1
- package/src/agents/agentConfig.ts +14 -8
- package/src/agents/crew.ts +443 -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 +659 -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,33 @@
|
|
|
1
|
+
import { AxSignature as AxSignatureClass } from "@ax-llm/ax";
|
|
2
|
+
import type { AxFunction } from "@ax-llm/ax";
|
|
3
|
+
import type { AxCrewConfig } from "../types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Lightweight proxy that stands in for a real agent in the crew's agent map.
|
|
6
|
+
* It exposes the same `getFunction()` interface (built from the crew config)
|
|
7
|
+
* but defers the expensive `createAgent()` call — and therefore MCP server
|
|
8
|
+
* startup — until the Manager actually delegates to it.
|
|
9
|
+
*
|
|
10
|
+
* Usage: `crew.addLazyAgent("CreateChart")` instead of `crew.addAgent("CreateChart")`
|
|
11
|
+
*/
|
|
12
|
+
declare class LazyStatefulAxAgent {
|
|
13
|
+
private realAgent;
|
|
14
|
+
private crewRef;
|
|
15
|
+
private agentName;
|
|
16
|
+
private description;
|
|
17
|
+
private signatureStr;
|
|
18
|
+
private func;
|
|
19
|
+
private _id;
|
|
20
|
+
constructor(crewRef: any, agentName: string, crewConfig: AxCrewConfig);
|
|
21
|
+
private resolve;
|
|
22
|
+
getFunction(): AxFunction;
|
|
23
|
+
getSignature(): AxSignatureClass<Record<string, any>, Record<string, any>>;
|
|
24
|
+
getId(): string;
|
|
25
|
+
setId(id: string): void;
|
|
26
|
+
getTraces(): any[];
|
|
27
|
+
setDemos(): void;
|
|
28
|
+
getUsage(): any[];
|
|
29
|
+
resetUsage(): void;
|
|
30
|
+
forward(...args: any[]): Promise<any>;
|
|
31
|
+
streamingForward(...args: any[]): any;
|
|
32
|
+
}
|
|
33
|
+
export { LazyStatefulAxAgent };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { AxSignature as AxSignatureClass } from "@ax-llm/ax";
|
|
2
|
+
import { parseCrewConfig } from "./agentConfig.js";
|
|
3
|
+
/**
|
|
4
|
+
* Lightweight proxy that stands in for a real agent in the crew's agent map.
|
|
5
|
+
* It exposes the same `getFunction()` interface (built from the crew config)
|
|
6
|
+
* but defers the expensive `createAgent()` call — and therefore MCP server
|
|
7
|
+
* startup — until the Manager actually delegates to it.
|
|
8
|
+
*
|
|
9
|
+
* Usage: `crew.addLazyAgent("CreateChart")` instead of `crew.addAgent("CreateChart")`
|
|
10
|
+
*/
|
|
11
|
+
class LazyStatefulAxAgent {
|
|
12
|
+
realAgent = null;
|
|
13
|
+
crewRef; // AxCrew — forward-declared to avoid circular ref
|
|
14
|
+
agentName;
|
|
15
|
+
description;
|
|
16
|
+
signatureStr;
|
|
17
|
+
func;
|
|
18
|
+
_id = "lazy";
|
|
19
|
+
constructor(crewRef, agentName, crewConfig) {
|
|
20
|
+
this.crewRef = crewRef;
|
|
21
|
+
this.agentName = agentName;
|
|
22
|
+
const agentDef = parseCrewConfig(crewConfig).crew.find((a) => a.name === agentName);
|
|
23
|
+
if (!agentDef) {
|
|
24
|
+
throw new Error(`Agent "${agentName}" not found in crew config`);
|
|
25
|
+
}
|
|
26
|
+
this.description = agentDef.description;
|
|
27
|
+
this.signatureStr = agentDef.signature;
|
|
28
|
+
// Build the tool schema from the signature's input fields
|
|
29
|
+
const sig = new AxSignatureClass(this.signatureStr);
|
|
30
|
+
const parameters = sig.toInputJSONSchema();
|
|
31
|
+
this.func = {
|
|
32
|
+
name: agentName.replace(/[^a-zA-Z0-9_]/g, "_").toLowerCase(),
|
|
33
|
+
description: this.description,
|
|
34
|
+
parameters,
|
|
35
|
+
func: async (args) => {
|
|
36
|
+
const agent = await this.resolve();
|
|
37
|
+
return agent.forward(args);
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async resolve() {
|
|
42
|
+
if (!this.realAgent) {
|
|
43
|
+
const agent = await this.crewRef.createAgent(this.agentName);
|
|
44
|
+
agent.setId(this._id);
|
|
45
|
+
this.realAgent = agent;
|
|
46
|
+
}
|
|
47
|
+
return this.realAgent;
|
|
48
|
+
}
|
|
49
|
+
// AxAgentic interface
|
|
50
|
+
getFunction() {
|
|
51
|
+
return this.func;
|
|
52
|
+
}
|
|
53
|
+
getSignature() {
|
|
54
|
+
return new AxSignatureClass(this.signatureStr);
|
|
55
|
+
}
|
|
56
|
+
// AxProgrammable / AxTunable stubs
|
|
57
|
+
getId() { return this._id; }
|
|
58
|
+
setId(id) { this._id = id; }
|
|
59
|
+
getTraces() { return this.realAgent?.getTraces() ?? []; }
|
|
60
|
+
setDemos() { }
|
|
61
|
+
getUsage() { return this.realAgent?.getUsage() ?? []; }
|
|
62
|
+
resetUsage() { this.realAgent?.resetUsage(); }
|
|
63
|
+
// Forward / streaming — resolve on demand
|
|
64
|
+
async forward(...args) {
|
|
65
|
+
const agent = await this.resolve();
|
|
66
|
+
return agent.forward(...args);
|
|
67
|
+
}
|
|
68
|
+
streamingForward(...args) {
|
|
69
|
+
// Must be sync to match the interface, so we wrap in an async generator
|
|
70
|
+
const self = this;
|
|
71
|
+
async function* lazyStream() {
|
|
72
|
+
const agent = await self.resolve();
|
|
73
|
+
yield* agent.streamingForward(...args);
|
|
74
|
+
}
|
|
75
|
+
return lazyStream();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export { LazyStatefulAxAgent };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { AxAgent, AxAI } from "@ax-llm/ax";
|
|
2
|
+
import type { AxSignature, AxAgentic, AxFunction, AxProgramForwardOptions, AxProgramStreamingForwardOptions, AxGenStreamingOut } from "@ax-llm/ax";
|
|
3
|
+
import type { StateInstance, UsageCost, MCPTransportConfig, ACEConfig, AgentExecutionMode, AxCrewAxAgentOptions } from "../types.js";
|
|
4
|
+
export interface ParsedAgentConfig {
|
|
5
|
+
ai: AxAI;
|
|
6
|
+
name: string;
|
|
7
|
+
executionMode: AgentExecutionMode;
|
|
8
|
+
axAgentOptions?: AxCrewAxAgentOptions;
|
|
9
|
+
description: string;
|
|
10
|
+
definition?: string;
|
|
11
|
+
signature: string | AxSignature;
|
|
12
|
+
functions: (AxFunction | (new (state: Record<string, any>) => {
|
|
13
|
+
toFunction: () => AxFunction;
|
|
14
|
+
}) | undefined)[];
|
|
15
|
+
mcpServers?: Record<string, MCPTransportConfig>;
|
|
16
|
+
subAgentNames: string[];
|
|
17
|
+
examples?: Array<Record<string, any>>;
|
|
18
|
+
tracker?: any;
|
|
19
|
+
}
|
|
20
|
+
declare class StatefulAxAgent extends AxAgent<any, any> {
|
|
21
|
+
crewState: StateInstance;
|
|
22
|
+
axai: any;
|
|
23
|
+
private agentName;
|
|
24
|
+
private agentDefinition;
|
|
25
|
+
private executionMode;
|
|
26
|
+
private axGenProgram;
|
|
27
|
+
private costTracker?;
|
|
28
|
+
private debugEnabled;
|
|
29
|
+
private deferredToolManager?;
|
|
30
|
+
private static readonly modernAxAgentRuntime;
|
|
31
|
+
private aceConfig?;
|
|
32
|
+
private aceOptimizer?;
|
|
33
|
+
private acePlaybook?;
|
|
34
|
+
private aceBaseInstruction?;
|
|
35
|
+
private isAxAIService;
|
|
36
|
+
constructor(ai: AxAI, options: Readonly<{
|
|
37
|
+
name: string;
|
|
38
|
+
description: string;
|
|
39
|
+
executionMode?: AgentExecutionMode;
|
|
40
|
+
axAgentOptions?: AxCrewAxAgentOptions;
|
|
41
|
+
definition?: string;
|
|
42
|
+
signature: string | AxSignature;
|
|
43
|
+
agents?: AxAgentic<any, any>[] | undefined;
|
|
44
|
+
functions?: (AxFunction | (() => AxFunction))[] | undefined;
|
|
45
|
+
examples?: Array<Record<string, any>> | undefined;
|
|
46
|
+
mcpServers?: Record<string, MCPTransportConfig> | undefined;
|
|
47
|
+
debug?: boolean;
|
|
48
|
+
}>, state: StateInstance);
|
|
49
|
+
/**
|
|
50
|
+
* @deprecated Use setExamplesCompat() to avoid Ax runtime version coupling.
|
|
51
|
+
*/
|
|
52
|
+
setExamples(examples: Readonly<Array<Record<string, any>>>): void;
|
|
53
|
+
setExamplesCompat(examples: Readonly<Array<Record<string, any>>>): void;
|
|
54
|
+
/**
|
|
55
|
+
* @deprecated Use setDescriptionCompat() to avoid Ax runtime version coupling.
|
|
56
|
+
*/
|
|
57
|
+
setDescription(description: string): void;
|
|
58
|
+
setDescriptionCompat(description: string): void;
|
|
59
|
+
getUsage(): (import("@ax-llm/ax").AxModelUsage & {
|
|
60
|
+
ai: string;
|
|
61
|
+
model: string;
|
|
62
|
+
})[];
|
|
63
|
+
resetUsage(): void;
|
|
64
|
+
private resolveInvocationArgs;
|
|
65
|
+
/** Merge deferred tool step hooks into forward options */
|
|
66
|
+
private mergeStepHooks;
|
|
67
|
+
private executeForwardByMode;
|
|
68
|
+
private recordUsageMetrics;
|
|
69
|
+
private runForwardInvocation;
|
|
70
|
+
forward(values: Record<string, any>, options?: Readonly<AxProgramForwardOptions<any>>): Promise<Record<string, any>>;
|
|
71
|
+
forward(ai: AxAI, values: Record<string, any>, options?: Readonly<AxProgramForwardOptions<any>>): Promise<Record<string, any>>;
|
|
72
|
+
private runStreamingInvocation;
|
|
73
|
+
streamingForward(values: Record<string, any>, options?: Readonly<AxProgramStreamingForwardOptions<any>>): AxGenStreamingOut<any>;
|
|
74
|
+
streamingForward(ai: AxAI, values: Record<string, any>, options?: Readonly<AxProgramStreamingForwardOptions<any>>): AxGenStreamingOut<any>;
|
|
75
|
+
getLastUsageCost(): UsageCost | null;
|
|
76
|
+
getAccumulatedCosts(): UsageCost | null;
|
|
77
|
+
getMetrics(): import("../metrics/types.js").MetricsSnapshot;
|
|
78
|
+
resetMetrics(): void;
|
|
79
|
+
initACE(ace?: ACEConfig): Promise<void>;
|
|
80
|
+
optimizeOffline(params?: {
|
|
81
|
+
metric?: any;
|
|
82
|
+
examples?: any[];
|
|
83
|
+
}): Promise<void>;
|
|
84
|
+
applyOnlineUpdate(params: {
|
|
85
|
+
example: any;
|
|
86
|
+
prediction: any;
|
|
87
|
+
feedback?: string;
|
|
88
|
+
}): Promise<void>;
|
|
89
|
+
getPlaybook(): any | undefined;
|
|
90
|
+
applyPlaybook(pb: any): void;
|
|
91
|
+
private composeInstructionWithPlaybook;
|
|
92
|
+
}
|
|
93
|
+
export { StatefulAxAgent };
|
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
import { AxAgent, AxGen } from "@ax-llm/ax";
|
|
2
|
+
import { MetricsRegistry } from "../metrics/index.js";
|
|
3
|
+
// Extend the AxAgent class from ax-llm
|
|
4
|
+
class StatefulAxAgent extends AxAgent {
|
|
5
|
+
crewState;
|
|
6
|
+
axai;
|
|
7
|
+
agentName;
|
|
8
|
+
agentDefinition;
|
|
9
|
+
executionMode;
|
|
10
|
+
axGenProgram;
|
|
11
|
+
costTracker;
|
|
12
|
+
debugEnabled = false;
|
|
13
|
+
deferredToolManager;
|
|
14
|
+
static modernAxAgentRuntime = typeof AxAgent?.prototype?.getFunction === "function" &&
|
|
15
|
+
typeof AxAgent?.prototype?.setExamples !== "function";
|
|
16
|
+
// ACE-related optional state
|
|
17
|
+
aceConfig;
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
aceOptimizer;
|
|
20
|
+
acePlaybook;
|
|
21
|
+
aceBaseInstruction; // Original description before playbook injection
|
|
22
|
+
isAxAIService(obj) {
|
|
23
|
+
return !!obj && typeof obj.getName === 'function' && typeof obj.chat === 'function';
|
|
24
|
+
}
|
|
25
|
+
constructor(ai, options, state) {
|
|
26
|
+
const { examples, debug } = options;
|
|
27
|
+
const resolvedFunctions = (options.functions ?? []).map((fn) => typeof fn === "function" ? fn() : fn);
|
|
28
|
+
const resolvedAgents = (options.agents ?? []);
|
|
29
|
+
const effectiveDefinition = (options.definition ?? options.description).trim();
|
|
30
|
+
if (StatefulAxAgent.modernAxAgentRuntime) {
|
|
31
|
+
const configuredAgentOptions = (options.axAgentOptions ?? {});
|
|
32
|
+
const configuredAgentGraph = (configuredAgentOptions.agents ?? {});
|
|
33
|
+
const configuredFunctionGraph = (configuredAgentOptions.functions ?? {});
|
|
34
|
+
const configuredActorOptions = (configuredAgentOptions.actorOptions ?? {});
|
|
35
|
+
const configuredResponderOptions = (configuredAgentOptions.responderOptions ?? {});
|
|
36
|
+
const modernOptions = {
|
|
37
|
+
...configuredAgentOptions,
|
|
38
|
+
debug: debug ?? configuredAgentOptions.debug ?? false,
|
|
39
|
+
contextFields: Array.isArray(configuredAgentOptions.contextFields)
|
|
40
|
+
? configuredAgentOptions.contextFields
|
|
41
|
+
: [],
|
|
42
|
+
};
|
|
43
|
+
modernOptions.agents = {
|
|
44
|
+
...configuredAgentGraph,
|
|
45
|
+
local: resolvedAgents,
|
|
46
|
+
};
|
|
47
|
+
modernOptions.functions = {
|
|
48
|
+
...configuredFunctionGraph,
|
|
49
|
+
local: resolvedFunctions,
|
|
50
|
+
};
|
|
51
|
+
if (effectiveDefinition.length > 0) {
|
|
52
|
+
modernOptions.actorOptions = {
|
|
53
|
+
...configuredActorOptions,
|
|
54
|
+
description: configuredActorOptions.description ?? effectiveDefinition,
|
|
55
|
+
};
|
|
56
|
+
modernOptions.responderOptions = {
|
|
57
|
+
...configuredResponderOptions,
|
|
58
|
+
description: configuredResponderOptions.description ?? effectiveDefinition,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
modernOptions.actorOptions = configuredActorOptions;
|
|
63
|
+
modernOptions.responderOptions = configuredResponderOptions;
|
|
64
|
+
}
|
|
65
|
+
super({
|
|
66
|
+
ai,
|
|
67
|
+
agentIdentity: {
|
|
68
|
+
name: options.name,
|
|
69
|
+
description: options.description,
|
|
70
|
+
},
|
|
71
|
+
signature: options.signature,
|
|
72
|
+
}, modernOptions);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
super({
|
|
76
|
+
name: options.name,
|
|
77
|
+
description: options.description,
|
|
78
|
+
definition: options.definition,
|
|
79
|
+
signature: options.signature,
|
|
80
|
+
agents: resolvedAgents,
|
|
81
|
+
functions: resolvedFunctions,
|
|
82
|
+
debug: debug ?? false,
|
|
83
|
+
}, {});
|
|
84
|
+
}
|
|
85
|
+
this.crewState = state;
|
|
86
|
+
this.axai = ai;
|
|
87
|
+
this.agentName = options.name;
|
|
88
|
+
this.agentDefinition = effectiveDefinition;
|
|
89
|
+
this.executionMode = options.executionMode ?? "axgen";
|
|
90
|
+
this.debugEnabled = debug ?? false;
|
|
91
|
+
// Convert sub-agents to callable functions so AxGen can invoke them as tools
|
|
92
|
+
const subAgentFunctions = resolvedAgents
|
|
93
|
+
.map(agent => {
|
|
94
|
+
try {
|
|
95
|
+
return agent.getFunction();
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
.filter((fn) => fn !== undefined);
|
|
102
|
+
this.axGenProgram = new AxGen(options.signature, {
|
|
103
|
+
description: effectiveDefinition,
|
|
104
|
+
functions: [...resolvedFunctions, ...subAgentFunctions],
|
|
105
|
+
contextCache: { cacheBreakpoint: 'after-examples' },
|
|
106
|
+
});
|
|
107
|
+
for (const agent of resolvedAgents) {
|
|
108
|
+
try {
|
|
109
|
+
const childName = agent.getFunction().name;
|
|
110
|
+
this.axGenProgram.register(agent, childName);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// Best-effort registration for optimizer/introspection support.
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Apply examples to compatibility layer if provided
|
|
117
|
+
if (examples && examples.length > 0) {
|
|
118
|
+
this.setExamplesCompat(examples);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* @deprecated Use setExamplesCompat() to avoid Ax runtime version coupling.
|
|
123
|
+
*/
|
|
124
|
+
setExamples(examples) {
|
|
125
|
+
this.setExamplesCompat(examples);
|
|
126
|
+
}
|
|
127
|
+
setExamplesCompat(examples) {
|
|
128
|
+
this.axGenProgram.setExamples(examples);
|
|
129
|
+
const baseSetExamples = AxAgent.prototype.setExamples;
|
|
130
|
+
if (typeof baseSetExamples === "function") {
|
|
131
|
+
baseSetExamples.call(this, examples);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const internalProgram = this.program;
|
|
135
|
+
if (typeof internalProgram?.setExamples === "function") {
|
|
136
|
+
internalProgram.setExamples(examples);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* @deprecated Use setDescriptionCompat() to avoid Ax runtime version coupling.
|
|
141
|
+
*/
|
|
142
|
+
setDescription(description) {
|
|
143
|
+
this.setDescriptionCompat(description);
|
|
144
|
+
}
|
|
145
|
+
setDescriptionCompat(description) {
|
|
146
|
+
this.agentDefinition = description;
|
|
147
|
+
this.axGenProgram.setDescription(description);
|
|
148
|
+
const baseSetDescription = AxAgent.prototype.setDescription;
|
|
149
|
+
if (typeof baseSetDescription === "function") {
|
|
150
|
+
baseSetDescription.call(this, description);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const agentRuntime = this;
|
|
154
|
+
if (typeof agentRuntime.program?.setDescription === "function") {
|
|
155
|
+
agentRuntime.program.setDescription(description);
|
|
156
|
+
}
|
|
157
|
+
agentRuntime.actorDescription = description;
|
|
158
|
+
agentRuntime.responderDescription = description;
|
|
159
|
+
if (typeof agentRuntime._buildSplitPrograms === "function") {
|
|
160
|
+
agentRuntime._buildSplitPrograms();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
getUsage() {
|
|
164
|
+
if (this.executionMode === "axgen") {
|
|
165
|
+
return this.axGenProgram.getUsage();
|
|
166
|
+
}
|
|
167
|
+
return super.getUsage();
|
|
168
|
+
}
|
|
169
|
+
resetUsage() {
|
|
170
|
+
this.axGenProgram.resetUsage();
|
|
171
|
+
super.resetUsage();
|
|
172
|
+
}
|
|
173
|
+
resolveInvocationArgs(first, second, third) {
|
|
174
|
+
const calledWithAI = this.isAxAIService(first);
|
|
175
|
+
const ai = (calledWithAI ? first : this.axai);
|
|
176
|
+
if (!ai) {
|
|
177
|
+
throw new Error(`No AI instance is configured for agent "${this.agentName}"`);
|
|
178
|
+
}
|
|
179
|
+
const values = (calledWithAI ? second : first);
|
|
180
|
+
const options = (calledWithAI ? third : second);
|
|
181
|
+
return { ai, values, options, calledWithAI };
|
|
182
|
+
}
|
|
183
|
+
/** Merge deferred tool step hooks into forward options */
|
|
184
|
+
mergeStepHooks(options) {
|
|
185
|
+
if (!this.deferredToolManager?.isActive)
|
|
186
|
+
return options;
|
|
187
|
+
const deferredHooks = this.deferredToolManager.getStepHooks();
|
|
188
|
+
const existingHooks = options?.stepHooks;
|
|
189
|
+
const mergedHooks = {
|
|
190
|
+
beforeStep: async (ctx) => {
|
|
191
|
+
await existingHooks?.beforeStep?.(ctx);
|
|
192
|
+
await deferredHooks.beforeStep?.(ctx);
|
|
193
|
+
},
|
|
194
|
+
afterStep: existingHooks?.afterStep,
|
|
195
|
+
afterFunctionExecution: async (ctx) => {
|
|
196
|
+
await existingHooks?.afterFunctionExecution?.(ctx);
|
|
197
|
+
await deferredHooks.afterFunctionExecution?.(ctx);
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
return { ...options, stepHooks: mergedHooks };
|
|
201
|
+
}
|
|
202
|
+
async executeForwardByMode(mode, ai, values, options) {
|
|
203
|
+
const opts = this.mergeStepHooks(options);
|
|
204
|
+
if (mode === "axgen") {
|
|
205
|
+
return this.axGenProgram.forward(ai, values, opts);
|
|
206
|
+
}
|
|
207
|
+
return super.forward(ai, values, opts);
|
|
208
|
+
}
|
|
209
|
+
recordUsageMetrics(labels, mode) {
|
|
210
|
+
const builtIn = mode === "axgen" ? this.axGenProgram.getUsage?.() : super.getUsage?.();
|
|
211
|
+
if (!Array.isArray(builtIn))
|
|
212
|
+
return;
|
|
213
|
+
const totals = builtIn.reduce((acc, u) => {
|
|
214
|
+
const pt = u.tokens?.promptTokens ?? u.promptTokens ?? 0;
|
|
215
|
+
const ct = u.tokens?.completionTokens ?? u.completionTokens ?? 0;
|
|
216
|
+
acc.promptTokens += typeof pt === "number" ? pt : 0;
|
|
217
|
+
acc.completionTokens += typeof ct === "number" ? ct : 0;
|
|
218
|
+
const model = u.model ||
|
|
219
|
+
this.axai?.getLastUsedChatModel?.() ||
|
|
220
|
+
this.axai?.defaults?.model;
|
|
221
|
+
if (model) {
|
|
222
|
+
acc.byModel[model] = (acc.byModel[model] || 0) + (pt + ct);
|
|
223
|
+
}
|
|
224
|
+
return acc;
|
|
225
|
+
}, { promptTokens: 0, completionTokens: 0, byModel: {} });
|
|
226
|
+
MetricsRegistry.recordTokens(labels, {
|
|
227
|
+
promptTokens: totals.promptTokens,
|
|
228
|
+
completionTokens: totals.completionTokens,
|
|
229
|
+
totalTokens: totals.promptTokens + totals.completionTokens,
|
|
230
|
+
});
|
|
231
|
+
const costTracker = this.costTracker;
|
|
232
|
+
try {
|
|
233
|
+
for (const [m, count] of Object.entries(totals.byModel)) {
|
|
234
|
+
costTracker?.trackTokens?.(count, m);
|
|
235
|
+
}
|
|
236
|
+
const totalUSD = Number(costTracker?.getCurrentCost?.() ?? 0);
|
|
237
|
+
if (!Number.isNaN(totalUSD) && totalUSD > 0) {
|
|
238
|
+
MetricsRegistry.recordEstimatedCost(labels, totalUSD);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch { }
|
|
242
|
+
}
|
|
243
|
+
async runForwardInvocation(mode, first, second, third) {
|
|
244
|
+
const { ai, values, options, calledWithAI } = this.resolveInvocationArgs(first, second, third);
|
|
245
|
+
const start = performance.now();
|
|
246
|
+
const crewId = this.crewState?.crewId || this.crewState.get?.("crewId") || "default";
|
|
247
|
+
const labels = { crewId, agent: this.agentName };
|
|
248
|
+
const taskId = `task_${crewId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
249
|
+
// Track execution context in crew for ACE feedback routing
|
|
250
|
+
const crewInstance = this.crewState?.crew;
|
|
251
|
+
if (crewInstance) {
|
|
252
|
+
if (calledWithAI) {
|
|
253
|
+
const parentTaskId = this.crewState?.currentTaskId;
|
|
254
|
+
if (parentTaskId) {
|
|
255
|
+
crewInstance.trackAgentExecution(parentTaskId, this.agentName, values);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
crewInstance.trackAgentExecution(taskId, this.agentName, values);
|
|
260
|
+
this.crewState.currentTaskId = taskId;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (this.debugEnabled) {
|
|
264
|
+
console.log(`[ACE Debug] forward() called, mode=${mode}, aceConfig=${!!this.aceConfig}`);
|
|
265
|
+
}
|
|
266
|
+
if (this.aceConfig) {
|
|
267
|
+
await this.composeInstructionWithPlaybook();
|
|
268
|
+
}
|
|
269
|
+
const result = await this.executeForwardByMode(mode, ai, values, options);
|
|
270
|
+
const durationMs = performance.now() - start;
|
|
271
|
+
MetricsRegistry.recordRequest(labels, false, durationMs);
|
|
272
|
+
this.recordUsageMetrics(labels, mode);
|
|
273
|
+
if (crewInstance) {
|
|
274
|
+
if (calledWithAI) {
|
|
275
|
+
const parentTaskId = this.crewState?.currentTaskId;
|
|
276
|
+
if (parentTaskId) {
|
|
277
|
+
crewInstance.recordAgentResult(parentTaskId, this.agentName, result);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
crewInstance.recordAgentResult(taskId, this.agentName, result);
|
|
282
|
+
delete this.crewState.currentTaskId;
|
|
283
|
+
result._taskId = taskId;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
// Implementation
|
|
289
|
+
async forward(first, second, third) {
|
|
290
|
+
return this.runForwardInvocation(this.executionMode, first, second, third);
|
|
291
|
+
}
|
|
292
|
+
runStreamingInvocation(mode, first, second, third) {
|
|
293
|
+
const { ai, values, options } = this.resolveInvocationArgs(first, second, third);
|
|
294
|
+
const start = performance.now();
|
|
295
|
+
const crewId = this.crewState?.crewId || this.crewState.get?.("crewId") || "default";
|
|
296
|
+
const labels = { crewId, agent: this.agentName };
|
|
297
|
+
const opts = this.mergeStepHooks(options);
|
|
298
|
+
const createStream = () => mode === "axgen"
|
|
299
|
+
? this.axGenProgram.streamingForward(ai, values, opts)
|
|
300
|
+
: super.streamingForward(ai, values, opts);
|
|
301
|
+
const wrappedGenerator = (async function* () {
|
|
302
|
+
if (this.aceConfig) {
|
|
303
|
+
await this.composeInstructionWithPlaybook();
|
|
304
|
+
}
|
|
305
|
+
const streamingResult = createStream();
|
|
306
|
+
try {
|
|
307
|
+
for await (const chunk of streamingResult) {
|
|
308
|
+
yield chunk;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
finally {
|
|
312
|
+
const durationMs = performance.now() - start;
|
|
313
|
+
MetricsRegistry.recordRequest(labels, true, durationMs);
|
|
314
|
+
this.recordUsageMetrics(labels, mode);
|
|
315
|
+
}
|
|
316
|
+
}).bind(this)();
|
|
317
|
+
return wrappedGenerator;
|
|
318
|
+
}
|
|
319
|
+
// Implementation
|
|
320
|
+
streamingForward(first, second, third) {
|
|
321
|
+
return this.runStreamingInvocation(this.executionMode, first, second, third);
|
|
322
|
+
}
|
|
323
|
+
// Legacy cost API removed: rely on Ax trackers for cost reporting
|
|
324
|
+
getLastUsageCost() { return null; }
|
|
325
|
+
// Get the accumulated costs for all runs of this agent
|
|
326
|
+
getAccumulatedCosts() { return null; }
|
|
327
|
+
// Metrics API for this agent
|
|
328
|
+
getMetrics() {
|
|
329
|
+
const crewId = this.crewState?.crewId || (this.crewState.get?.('crewId')) || 'default';
|
|
330
|
+
return MetricsRegistry.snapshot({ crewId, agent: this.agentName });
|
|
331
|
+
}
|
|
332
|
+
resetMetrics() {
|
|
333
|
+
const crewId = this.crewState?.crewId || (this.crewState.get?.('crewId')) || 'default';
|
|
334
|
+
MetricsRegistry.reset({ crewId, agent: this.agentName });
|
|
335
|
+
}
|
|
336
|
+
// =============
|
|
337
|
+
// ACE API
|
|
338
|
+
// =============
|
|
339
|
+
async initACE(ace) {
|
|
340
|
+
this.aceConfig = ace;
|
|
341
|
+
if (!ace)
|
|
342
|
+
return;
|
|
343
|
+
try {
|
|
344
|
+
this.aceBaseInstruction =
|
|
345
|
+
this.agentDefinition || this.getSignature().getDescription() || '';
|
|
346
|
+
const { buildACEOptimizer, loadInitialPlaybook, createEmptyPlaybook } = await import('./ace.js');
|
|
347
|
+
this.aceOptimizer = buildACEOptimizer(this.axai, ace);
|
|
348
|
+
if (!ace.compileOnStart) {
|
|
349
|
+
this.aceOptimizer.program = this;
|
|
350
|
+
}
|
|
351
|
+
const initial = await loadInitialPlaybook(ace.persistence);
|
|
352
|
+
this.applyPlaybook(initial ?? createEmptyPlaybook());
|
|
353
|
+
if (this.debugEnabled) {
|
|
354
|
+
console.log(`[ACE Debug] Initialized for ${this.agentName}, base instruction: ${this.aceBaseInstruction?.slice(0, 50)}...`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
console.warn(`Failed to initialize ACE for agent ${this.agentName}:`, error);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
async optimizeOffline(params) {
|
|
362
|
+
if (!this.aceConfig || !this.aceOptimizer)
|
|
363
|
+
return;
|
|
364
|
+
try {
|
|
365
|
+
const { runOfflineCompile, resolveMetric } = await import('./ace.js');
|
|
366
|
+
const registry = this.__functionsRegistry;
|
|
367
|
+
const metric = params?.metric || resolveMetric(this.aceConfig.metric, registry || {});
|
|
368
|
+
const examples = params?.examples || [];
|
|
369
|
+
if (!metric || examples.length === 0) {
|
|
370
|
+
console.warn(`ACE offline compile skipped for ${this.agentName}: missing metric or examples`);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const result = await runOfflineCompile({
|
|
374
|
+
program: this,
|
|
375
|
+
optimizer: this.aceOptimizer,
|
|
376
|
+
metric,
|
|
377
|
+
examples,
|
|
378
|
+
persistence: this.aceConfig.persistence
|
|
379
|
+
});
|
|
380
|
+
if (result?.artifact?.playbook) {
|
|
381
|
+
await this.applyPlaybook(result.artifact.playbook);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
console.warn(`ACE offline compile failed for ${this.agentName}:`, error);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async applyOnlineUpdate(params) {
|
|
389
|
+
if (!this.aceConfig)
|
|
390
|
+
return;
|
|
391
|
+
if (!params.feedback?.trim())
|
|
392
|
+
return;
|
|
393
|
+
try {
|
|
394
|
+
const { persistPlaybook, addFeedbackToPlaybook, createEmptyPlaybook } = await import('./ace.js');
|
|
395
|
+
let playbook = this.acePlaybook ?? this.aceOptimizer?.playbook;
|
|
396
|
+
if (!playbook) {
|
|
397
|
+
playbook = createEmptyPlaybook();
|
|
398
|
+
}
|
|
399
|
+
if (this.debugEnabled) {
|
|
400
|
+
console.log(`[ACE Debug] Adding feedback to playbook: "${params.feedback}"`);
|
|
401
|
+
}
|
|
402
|
+
const teacherAI = this.aceOptimizer?.teacherAI;
|
|
403
|
+
const aiForAnalysis = teacherAI ?? this.axai;
|
|
404
|
+
await addFeedbackToPlaybook(playbook, params.feedback, aiForAnalysis, this.debugEnabled);
|
|
405
|
+
this.applyPlaybook(playbook);
|
|
406
|
+
if (this.aceOptimizer) {
|
|
407
|
+
this.aceOptimizer.playbook = playbook;
|
|
408
|
+
}
|
|
409
|
+
if (this.aceConfig.persistence?.autoPersist) {
|
|
410
|
+
await persistPlaybook(playbook, this.aceConfig.persistence);
|
|
411
|
+
}
|
|
412
|
+
if (this.debugEnabled) {
|
|
413
|
+
console.log(`[ACE Debug] Playbook updated, sections: ${Object.keys(playbook.sections || {}).join(', ')}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
catch (error) {
|
|
417
|
+
console.warn(`ACE online update failed for ${this.agentName}:`, error);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
getPlaybook() {
|
|
421
|
+
return this.acePlaybook;
|
|
422
|
+
}
|
|
423
|
+
applyPlaybook(pb) {
|
|
424
|
+
this.acePlaybook = pb;
|
|
425
|
+
try {
|
|
426
|
+
this.aceOptimizer.playbook = pb;
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
// Ignore - optimizer may not be initialized yet
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async composeInstructionWithPlaybook() {
|
|
433
|
+
const playbook = this.acePlaybook ?? this.aceOptimizer?.playbook;
|
|
434
|
+
if (this.debugEnabled) {
|
|
435
|
+
console.log(`[ACE Debug] composeInstructionWithPlaybook called`);
|
|
436
|
+
console.log(`[ACE Debug] playbook exists: ${!!playbook}, sections: ${playbook ? Object.keys(playbook.sections || {}).length : 0}`);
|
|
437
|
+
console.log(`[ACE Debug] baseInstruction: "${this.aceBaseInstruction?.slice(0, 50)}..."`);
|
|
438
|
+
}
|
|
439
|
+
if (!playbook)
|
|
440
|
+
return;
|
|
441
|
+
try {
|
|
442
|
+
const { renderPlaybook } = await import('./ace.js');
|
|
443
|
+
const rendered = renderPlaybook(playbook);
|
|
444
|
+
if (this.debugEnabled) {
|
|
445
|
+
console.log(`[ACE Debug] rendered playbook (${rendered.length} chars): ${rendered.slice(0, 100)}...`);
|
|
446
|
+
}
|
|
447
|
+
if (!rendered)
|
|
448
|
+
return;
|
|
449
|
+
const baseInstruction = this.aceBaseInstruction || '';
|
|
450
|
+
const combinedInstruction = [baseInstruction.trim(), '', rendered]
|
|
451
|
+
.filter((part) => part.trim().length > 0)
|
|
452
|
+
.join('\n\n');
|
|
453
|
+
if (this.debugEnabled) {
|
|
454
|
+
console.log(`[ACE Debug] combinedInstruction (${combinedInstruction.length} chars)`);
|
|
455
|
+
}
|
|
456
|
+
if (combinedInstruction.length >= 20) {
|
|
457
|
+
const program = this.program;
|
|
458
|
+
if (program?.setDescription) {
|
|
459
|
+
program.setDescription(combinedInstruction);
|
|
460
|
+
}
|
|
461
|
+
this.setDescription(combinedInstruction);
|
|
462
|
+
if (this.debugEnabled) {
|
|
463
|
+
console.log(`[ACE Debug] setDescription called successfully`);
|
|
464
|
+
console.log(`[ACE Debug] Verifying - signature desc length: ${this.getSignature().getDescription()?.length}`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
catch (error) {
|
|
469
|
+
console.warn('[ACE Debug] Failed to compose instruction:', error);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
export { StatefulAxAgent };
|