@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
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
3
|
import type { AxCrewConfig, AxCrewOptions, AgentConfig, AgentExecutionMode, AxCrewAxAgentOptions } from './types.js';
|
|
4
|
-
import type { UsageCost, AggregatedMetrics, AggregatedCosts, StateInstance, FunctionRegistryType, ACEConfig, ACETeacherConfig, ACEPersistenceConfig, ACEOptionsConfig, ACEMetricConfig } from './types.js';
|
|
4
|
+
import type { UsageCost, AggregatedMetrics, AggregatedCosts, StateInstance, FunctionRegistryType, DeferredToolsConfig, 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 AgentExecutionMode, type AxCrewAxAgentOptions, type AxCrewConfig, type AxCrewOptions, type StateInstance, type UsageCost, type ACEConfig, type ACETeacherConfig, type ACEPersistenceConfig, type ACEOptionsConfig, type ACEMetricConfig, };
|
|
32
|
+
_AxCrewFunctions as AxCrewFunctions, FunctionRegistryType, type AggregatedMetrics, type AggregatedCosts, type AgentConfig, type AgentExecutionMode, type AxCrewAxAgentOptions, type AxCrewConfig, type AxCrewOptions, type StateInstance, type UsageCost, type DeferredToolsConfig, type ACEConfig, type ACETeacherConfig, type ACEPersistenceConfig, type ACEOptionsConfig, type ACEMetricConfig, };
|
package/dist/types.d.ts
CHANGED
|
@@ -173,6 +173,21 @@ interface ACEConfig {
|
|
|
173
173
|
metric?: ACEMetricConfig;
|
|
174
174
|
compileOnStart?: boolean;
|
|
175
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Configuration for deferred tool loading.
|
|
178
|
+
* When an agent has many tools, only core tools are visible by default.
|
|
179
|
+
* A search_tools meta-function lets the LLM discover and activate deferred tools on demand.
|
|
180
|
+
*/
|
|
181
|
+
interface DeferredToolsConfig {
|
|
182
|
+
/** Enable deferred tool loading. Default: auto (true when tool count > threshold) */
|
|
183
|
+
enabled?: boolean;
|
|
184
|
+
/** Tool count threshold to activate deferred mode. Default: 20 */
|
|
185
|
+
threshold?: number;
|
|
186
|
+
/** Max tools returned per search. Default: 10 */
|
|
187
|
+
maxSearchResults?: number;
|
|
188
|
+
/** Tool names to always keep active (bypasses deferral) */
|
|
189
|
+
coreTools?: string[];
|
|
190
|
+
}
|
|
176
191
|
/**
|
|
177
192
|
* The configuration for an agent.
|
|
178
193
|
*
|
|
@@ -234,6 +249,8 @@ interface AgentConfig {
|
|
|
234
249
|
mcpServers?: Record<string, MCPTransportConfig>;
|
|
235
250
|
/** Optional AxACE configuration to enable optimization for this agent */
|
|
236
251
|
ace?: ACEConfig;
|
|
252
|
+
/** Deferred tool loading — reduces token usage when an agent has many tools */
|
|
253
|
+
deferredTools?: DeferredToolsConfig;
|
|
237
254
|
}
|
|
238
255
|
/**
|
|
239
256
|
* The configuration object for an AxCrew instance.
|
|
@@ -290,4 +307,4 @@ interface AxCrewOptions {
|
|
|
290
307
|
meter?: any;
|
|
291
308
|
};
|
|
292
309
|
}
|
|
293
|
-
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 };
|
|
310
|
+
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 DeferredToolsConfig, type ACEConfig, type ACEMetricConfig, type ACEOptionsConfig, type ACEPersistenceConfig, type ACETeacherConfig };
|
|
@@ -5,27 +5,17 @@ import dotenv from "dotenv";
|
|
|
5
5
|
dotenv.config();
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* GraphJin MCP Server Example
|
|
8
|
+
* GraphJin MCP Server Example — with deferred tool loading
|
|
9
9
|
*
|
|
10
|
-
* This example demonstrates
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* This example demonstrates deferred tool loading: when an agent has many
|
|
11
|
+
* MCP tools, only core tools + a search_tools meta-function are visible
|
|
12
|
+
* to the LLM. The LLM discovers and activates deferred tools on demand.
|
|
13
13
|
*
|
|
14
14
|
* Setup:
|
|
15
15
|
* 1. Install GraphJin: npm install -g graphjin
|
|
16
16
|
* 2. Start GraphJin demo server: graphjin serve --demo --path /path/to/graphjin/examples/webshop
|
|
17
17
|
* 3. GraphJin will start on http://localhost:8080
|
|
18
18
|
* 4. The MCP proxy connects to it via stdio
|
|
19
|
-
*
|
|
20
|
-
* Alternative setup (direct mode):
|
|
21
|
-
* If you have a GraphJin config, you can use direct mode without a running server:
|
|
22
|
-
* - Use command: "graphjin" with args: ["mcp", "--demo", "--path", "/path/to/config"]
|
|
23
|
-
*
|
|
24
|
-
* Note: There is currently a schema validation issue between GraphJin and Ax.
|
|
25
|
-
* GraphJin's array parameters don't include "items" definitions in their JSON Schema,
|
|
26
|
-
* which Ax requires per JSON Schema spec. A fix is needed in either:
|
|
27
|
-
* - GraphJin's mcp-go integration (recommended)
|
|
28
|
-
* - Or Ax's schema validation (less recommended)
|
|
29
19
|
*/
|
|
30
20
|
|
|
31
21
|
// Define the crew configuration
|
|
@@ -33,50 +23,68 @@ const config = {
|
|
|
33
23
|
crew: [
|
|
34
24
|
{
|
|
35
25
|
name: "DatabaseAgent",
|
|
36
|
-
description: "An agent with direct database access via GraphJin. Can
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
26
|
+
description: "An agent with direct database access via GraphJin. Can explore database schema, query tables, list save and run workflows in the builtin JS sandbox etc.",
|
|
27
|
+
definition: `You answer questions by querying databases via a GraphJin server.
|
|
28
|
+
You have resource docs available (query syntax, mutation syntax, workflow guides, JS runtime API). Read them to learn the GraphJin DSL — it differs from standard GraphQL.
|
|
29
|
+
Use search_tools to discover additional action tools not shown by default.
|
|
30
|
+
|
|
31
|
+
STRATEGY:
|
|
32
|
+
1. Check first — call list_workflows and list_saved_queries. If a match exists, execute it and skip to step 5.
|
|
33
|
+
|
|
34
|
+
2. Learn the environment:
|
|
35
|
+
a. Read resource docs (get_query_syntax, get_js_runtime_api) to understand the DSL and runtime API.
|
|
36
|
+
b. Call list_tables + describe_table for schema details. Use explore_relationships or find_path if joins are needed.
|
|
37
|
+
|
|
38
|
+
3. Build and validate:
|
|
39
|
+
a. Author a JavaScript workflow using gj.tools.* for server-side computation. Design it with input variables — never hardcode values.
|
|
40
|
+
b. IMPORTANT: The database enforces a low default row limit (e.g. 20) on ALL queries including aggregations. Your workflow MUST paginate using cursor-based pagination (first: 20, after: cursor) to fetch complete results. Use first: 20 (not higher — the server silently caps it). Loop until the cursor stops changing or returns null.
|
|
41
|
+
c. Call execute_graphql first to validate query shape and results before embedding in a workflow.
|
|
42
|
+
|
|
43
|
+
4. Save and run — call save_workflow with a descriptive snake_case name and tags, then execute_workflow.
|
|
44
|
+
|
|
45
|
+
5. If a query fails, do not retry the same query. Call fix_query_error or explain_query to diagnose, then fix and re-save.
|
|
46
|
+
|
|
47
|
+
6. Synthesize the answer from results.`,
|
|
48
|
+
signature: 'question:string "a natural language question about the database" -> answer:string "the answer to the question"',
|
|
49
|
+
provider: "anthropic",
|
|
50
|
+
providerKeyName: "ANTHROPIC_API_KEY",
|
|
40
51
|
ai: {
|
|
41
|
-
model: "
|
|
52
|
+
model: "claude-sonnet-4-6",
|
|
42
53
|
temperature: 0,
|
|
43
54
|
stream: false
|
|
44
55
|
},
|
|
45
56
|
options: {
|
|
46
57
|
debug: true
|
|
47
58
|
},
|
|
48
|
-
// MCP Server Configuration for GraphJin
|
|
49
|
-
// This assumes you have graphjin running on http://localhost:8080
|
|
50
|
-
// Start it with: graphjin serve --demo --path /path/to/graphjin/examples/webshop
|
|
51
59
|
mcpServers: {
|
|
52
60
|
"graphjin": {
|
|
53
61
|
"command": "graphjin",
|
|
54
|
-
// Proxy mode: connects to a running GraphJin HTTP server
|
|
55
62
|
"args": ["mcp", "--server", "http://localhost:8080"]
|
|
56
|
-
|
|
57
|
-
// Direct mode (alternative - uncomment to use):
|
|
58
|
-
// Runs GraphJin MCP server directly with demo database
|
|
59
|
-
// "args": ["mcp", "--demo", "--path", "/path/to/your/graphjin/config"]
|
|
60
63
|
}
|
|
61
64
|
},
|
|
65
|
+
deferredTools: {
|
|
66
|
+
enabled: true,
|
|
67
|
+
threshold: 5,
|
|
68
|
+
},
|
|
62
69
|
},
|
|
63
70
|
{
|
|
64
71
|
name: "ManagerAgent",
|
|
65
72
|
description: "Orchestrates database queries and analysis tasks",
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
definition: `You are an orchestrator that routes questions to specialized agents.
|
|
74
|
+
Delegate each question to the most relevant agent in a SINGLE call — do not break questions into sub-queries.
|
|
75
|
+
The sub-agent will handle all the steps internally. Your job is to route and synthesize, not to decompose.
|
|
76
|
+
If multiple agents are needed, call them and combine their answers.`,
|
|
69
77
|
signature: 'question:string "a question to be answered" -> answer:string "the answer to the question"',
|
|
70
|
-
provider: "
|
|
71
|
-
providerKeyName: "
|
|
78
|
+
provider: "anthropic",
|
|
79
|
+
providerKeyName: "ANTHROPIC_API_KEY",
|
|
72
80
|
ai: {
|
|
73
|
-
model: "
|
|
81
|
+
model: "claude-sonnet-4-6",
|
|
74
82
|
maxTokens: 2000,
|
|
75
83
|
temperature: 0,
|
|
76
84
|
stream: false
|
|
77
85
|
},
|
|
78
86
|
options: {
|
|
79
|
-
debug:
|
|
87
|
+
debug: false,
|
|
80
88
|
},
|
|
81
89
|
agents: ["DatabaseAgent"]
|
|
82
90
|
}
|
|
@@ -86,50 +94,53 @@ Keep your responses clear and well-formatted.`,
|
|
|
86
94
|
// Create a new instance of AxCrew with the config
|
|
87
95
|
const crew = new AxCrew(config as AxCrewConfig);
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
const queries = [
|
|
91
|
-
"What tables are available in the database?",
|
|
92
|
-
"Show me the schema for the products table",
|
|
93
|
-
"How many products are in the database?",
|
|
94
|
-
"List the top 5 most expensive products",
|
|
95
|
-
"What customers have placed orders in the last 30 days?"
|
|
96
|
-
];
|
|
97
|
+
const userQuery = "which products had the most refund requests and why?";
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
const userQuery: string = queries[0]; // "What tables are available in the database?"
|
|
100
|
-
|
|
101
|
-
console.log(`\n\nQuestion: ${userQuery}`);
|
|
99
|
+
console.log(`\nQuestion: ${userQuery}`);
|
|
102
100
|
|
|
103
101
|
const main = async (): Promise<void> => {
|
|
102
|
+
const timers: Record<string, number> = {};
|
|
103
|
+
|
|
104
104
|
try {
|
|
105
|
-
//
|
|
105
|
+
// --- Setup phase ---
|
|
106
|
+
const t0 = performance.now();
|
|
106
107
|
await crew.addAllAgents();
|
|
108
|
+
timers["setup"] = performance.now() - t0;
|
|
107
109
|
|
|
108
110
|
const managerAgent = crew.agents?.get("ManagerAgent");
|
|
109
|
-
const databaseAgent = crew.agents?.get("DatabaseAgent");
|
|
110
111
|
|
|
111
112
|
if (!managerAgent) {
|
|
112
113
|
throw new Error("Failed to initialize ManagerAgent");
|
|
113
114
|
}
|
|
114
115
|
|
|
116
|
+
// --- Query phase ---
|
|
117
|
+
console.log("\n--- Starting query ---\n");
|
|
118
|
+
const t1 = performance.now();
|
|
119
|
+
|
|
115
120
|
const managerResponse = await managerAgent.forward({
|
|
116
121
|
question: userQuery,
|
|
117
122
|
});
|
|
118
123
|
|
|
124
|
+
timers["query"] = performance.now() - t1;
|
|
125
|
+
timers["total"] = performance.now() - t0;
|
|
126
|
+
|
|
127
|
+
// --- Results ---
|
|
119
128
|
console.log(`\nAnswer: ${JSON.stringify(managerResponse?.answer, null, 2)}`);
|
|
120
129
|
|
|
121
|
-
//
|
|
122
|
-
console.log("\
|
|
123
|
-
console.log(
|
|
124
|
-
console.log(
|
|
125
|
-
console.log(
|
|
130
|
+
// --- Timing & Metrics ---
|
|
131
|
+
console.log("\n--- Performance ---");
|
|
132
|
+
console.log(` Setup: ${(timers["setup"]! / 1000).toFixed(2)}s`);
|
|
133
|
+
console.log(` Query: ${(timers["query"]! / 1000).toFixed(2)}s`);
|
|
134
|
+
console.log(` Total: ${(timers["total"]! / 1000).toFixed(2)}s`);
|
|
135
|
+
|
|
136
|
+
console.log("\n--- Metrics ---");
|
|
137
|
+
console.log(JSON.stringify((crew as any)?.getCrewMetrics?.(), null, 2));
|
|
126
138
|
} catch (error) {
|
|
127
|
-
console.error("\
|
|
139
|
+
console.error("\nError:", error);
|
|
128
140
|
console.error("\nTroubleshooting:");
|
|
129
141
|
console.error("1. Make sure GraphJin is running: graphjin serve --demo --path /path/to/graphjin/examples/webshop");
|
|
130
142
|
console.error("2. Check that GraphJin is accessible at http://localhost:8080");
|
|
131
143
|
console.error("3. Verify graphjin is installed: which graphjin");
|
|
132
|
-
console.error("4. Note: There's a known schema validation issue - see comments in the code");
|
|
133
144
|
throw error;
|
|
134
145
|
} finally {
|
|
135
146
|
crew.destroy();
|
|
@@ -138,10 +149,10 @@ const main = async (): Promise<void> => {
|
|
|
138
149
|
|
|
139
150
|
main()
|
|
140
151
|
.then(() => {
|
|
141
|
-
console.log("\
|
|
152
|
+
console.log("\nDone");
|
|
142
153
|
process.exit(0);
|
|
143
154
|
})
|
|
144
155
|
.catch((error) => {
|
|
145
|
-
console.error("\
|
|
156
|
+
console.error("\nFatal error:", error);
|
|
146
157
|
process.exit(1);
|
|
147
158
|
});
|
|
@@ -93,7 +93,7 @@ const main = async () => {
|
|
|
93
93
|
// Refer to https://github.com/WP-API/Basic-Auth?tab=readme-ov-file
|
|
94
94
|
|
|
95
95
|
// Set environment variables
|
|
96
|
-
crew.
|
|
96
|
+
crew.crewState.set("env", {
|
|
97
97
|
WORDPRESS_URL: "http://my-wordpress-site.com",
|
|
98
98
|
WORDPRESS_USERNAME: "my-username",
|
|
99
99
|
WORDPRESS_PASSWORD: "my-password"
|
package/package.json
CHANGED
|
@@ -54,7 +54,7 @@ const initializeMCPServers = async (agentConfigData: AgentConfig): Promise<AxFun
|
|
|
54
54
|
|
|
55
55
|
let initializedClients: AxMCPClient[] = [];
|
|
56
56
|
const functions: AxFunction[] = [];
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
try {
|
|
59
59
|
for (const [mcpServerName, mcpServerConfig] of Object.entries(mcpServers)) {
|
|
60
60
|
let transport;
|
|
@@ -68,7 +68,7 @@ const initializeMCPServers = async (agentConfigData: AgentConfig): Promise<AxFun
|
|
|
68
68
|
transport = new AxMCPHTTPSSETransport(mcpServerConfig.sseUrl);
|
|
69
69
|
} else if (isStreambleHTTPTransport(mcpServerConfig)) {
|
|
70
70
|
transport = new AxMCPStreambleHTTPTransport(mcpServerConfig.mcpEndpoint, mcpServerConfig.options);
|
|
71
|
-
} else {
|
|
71
|
+
} else {
|
|
72
72
|
throw new Error(`Unsupported transport type: ${JSON.stringify(mcpServerConfig)}`);
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -77,20 +77,21 @@ const initializeMCPServers = async (agentConfigData: AgentConfig): Promise<AxFun
|
|
|
77
77
|
initializedClients.push(mcpClient);
|
|
78
78
|
// Normalize MCP tool schemas: some MCP servers omit `parameters` for
|
|
79
79
|
// zero-arg tools, but providers like Gemini require a valid schema.
|
|
80
|
-
|
|
80
|
+
const allFns = mcpClient.toFunction().map(fn => ({
|
|
81
81
|
...fn,
|
|
82
82
|
parameters: fn.parameters ?? { type: 'object' as const, properties: {} },
|
|
83
83
|
}));
|
|
84
84
|
|
|
85
|
-
// Filter to allowlisted tools if specified
|
|
85
|
+
// Filter to allowlisted tools if specified, but always include resource_* functions
|
|
86
86
|
if (mcpServerConfig.tools && mcpServerConfig.tools.length > 0) {
|
|
87
87
|
const allowed = new Set(mcpServerConfig.tools);
|
|
88
|
-
|
|
88
|
+
const filtered = allFns.filter(fn => allowed.has(fn.name) || fn.name.startsWith('resource_'));
|
|
89
|
+
functions.push(...filtered);
|
|
90
|
+
} else {
|
|
91
|
+
functions.push(...allFns);
|
|
89
92
|
}
|
|
90
|
-
|
|
91
|
-
functions.push(...mcpFns);
|
|
92
93
|
}
|
|
93
|
-
|
|
94
|
+
|
|
94
95
|
return functions;
|
|
95
96
|
} catch (error) {
|
|
96
97
|
initializedClients = [];
|
|
@@ -217,6 +218,9 @@ const parseAgentConfig = async (
|
|
|
217
218
|
const executionMode: AgentExecutionMode =
|
|
218
219
|
agentConfigData.executionMode === 'axagent' ? 'axagent' : 'axgen';
|
|
219
220
|
|
|
221
|
+
// Track MCP function names for deferred tool loading
|
|
222
|
+
const mcpFunctionNames = new Set(mcpFunctions.map(fn => fn.name));
|
|
223
|
+
|
|
220
224
|
// Return AI instance and Agent parameters
|
|
221
225
|
return {
|
|
222
226
|
ai: aiInstance,
|
|
@@ -227,9 +231,11 @@ const parseAgentConfig = async (
|
|
|
227
231
|
definition: (agentConfigData as any).definition ?? (agentConfigData as any).prompt,
|
|
228
232
|
signature: agentConfigData.signature,
|
|
229
233
|
functions: agentFunctions,
|
|
234
|
+
mcpFunctionNames,
|
|
230
235
|
subAgentNames: agentConfigData.agents || [],
|
|
231
236
|
examples: agentConfigData.examples || [],
|
|
232
237
|
tracker: costTracker,
|
|
238
|
+
deferredTools: (agentConfigData as any).deferredTools,
|
|
233
239
|
debug: (agentConfigData as any).options?.debug ?? (agentConfigData as any).debug ?? false,
|
|
234
240
|
};
|
|
235
241
|
} catch (error) {
|