@amitdeshmukh/ax-crew 8.2.0 → 8.4.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 +11 -0
- package/dist/agents/agentConfig.js +6 -1
- package/dist/agents/index.js +12 -1
- package/dist/types.d.ts +5 -0
- package/examples/run-crew-workflow.ts +76 -0
- package/examples/run-manager.ts +98 -0
- package/package.json +1 -1
- package/src/agents/agentConfig.ts +8 -1
- package/src/agents/index.ts +9 -1
- package/src/types.ts +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [8.4.0] - 2026-03-05
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Optional `tools` allowlist on MCP server configs (stdio, HTTP SSE, streamable HTTP). When specified, only the listed tools are exposed to the agent, keeping system prompts small when connecting to MCP servers with many tools. Tested with GraphJin (40+ tools): filtering to 8 reduced token usage from 43K to 14K per request.
|
|
7
|
+
- `examples/run-crew-workflow.ts` — workflow-aware agent using GraphJin MCP with tool filtering.
|
|
8
|
+
|
|
9
|
+
## [8.3.0] - 2026-03-05
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- Sub-agents were invisible to agents running in `axgen` execution mode. AxGen only supports functions/tools, not native sub-agents. Sub-agents are now converted to callable functions via `getFunction()` and included in the AxGen functions list, making them available as tools during execution.
|
|
13
|
+
|
|
3
14
|
## [8.1.0] - 2026-03-04
|
|
4
15
|
|
|
5
16
|
### Added
|
|
@@ -56,10 +56,15 @@ const initializeMCPServers = async (agentConfigData) => {
|
|
|
56
56
|
initializedClients.push(mcpClient);
|
|
57
57
|
// Normalize MCP tool schemas: some MCP servers omit `parameters` for
|
|
58
58
|
// zero-arg tools, but providers like Gemini require a valid schema.
|
|
59
|
-
|
|
59
|
+
let mcpFns = mcpClient.toFunction().map(fn => ({
|
|
60
60
|
...fn,
|
|
61
61
|
parameters: fn.parameters ?? { type: 'object', properties: {} },
|
|
62
62
|
}));
|
|
63
|
+
// Filter to allowlisted tools if specified
|
|
64
|
+
if (mcpServerConfig.tools && mcpServerConfig.tools.length > 0) {
|
|
65
|
+
const allowed = new Set(mcpServerConfig.tools);
|
|
66
|
+
mcpFns = mcpFns.filter(fn => allowed.has(fn.name));
|
|
67
|
+
}
|
|
63
68
|
functions.push(...mcpFns);
|
|
64
69
|
}
|
|
65
70
|
return functions;
|
package/dist/agents/index.js
CHANGED
|
@@ -90,9 +90,20 @@ class StatefulAxAgent extends AxAgent {
|
|
|
90
90
|
this.agentDefinition = effectiveDefinition;
|
|
91
91
|
this.executionMode = options.executionMode ?? "axgen";
|
|
92
92
|
this.debugEnabled = debug ?? false;
|
|
93
|
+
// Convert sub-agents to callable functions so AxGen can invoke them as tools
|
|
94
|
+
const subAgentFunctions = resolvedAgents
|
|
95
|
+
.map(agent => {
|
|
96
|
+
try {
|
|
97
|
+
return agent.getFunction();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
.filter((fn) => fn !== undefined);
|
|
93
104
|
this.axGenProgram = new AxGen(options.signature, {
|
|
94
105
|
description: effectiveDefinition,
|
|
95
|
-
functions: resolvedFunctions,
|
|
106
|
+
functions: [...resolvedFunctions, ...subAgentFunctions],
|
|
96
107
|
});
|
|
97
108
|
for (const agent of resolvedAgents) {
|
|
98
109
|
try {
|
package/dist/types.d.ts
CHANGED
|
@@ -109,24 +109,29 @@ interface MCPStdioTransportConfig {
|
|
|
109
109
|
command: string;
|
|
110
110
|
args?: string[];
|
|
111
111
|
env?: NodeJS.ProcessEnv;
|
|
112
|
+
tools?: string[];
|
|
112
113
|
}
|
|
113
114
|
/**
|
|
114
115
|
* Config for an HTTP SSE MCP server.
|
|
115
116
|
*
|
|
116
117
|
* @property {string} sseUrl - The SSE URL for the MCP server.
|
|
118
|
+
* @property {string[]} tools - Optional allowlist of tool names to expose to the agent.
|
|
117
119
|
*/
|
|
118
120
|
interface MCPHTTPSSETransportConfig {
|
|
119
121
|
sseUrl: string;
|
|
122
|
+
tools?: string[];
|
|
120
123
|
}
|
|
121
124
|
/**
|
|
122
125
|
* Config for a streamable HTTP MCP server.
|
|
123
126
|
*
|
|
124
127
|
* @property {string} mcpEndpoint - The HTTP endpoint URL for the MCP server.
|
|
125
128
|
* @property {AxMCPStreamableHTTPTransportOptions} options - Optional transport options.
|
|
129
|
+
* @property {string[]} tools - Optional allowlist of tool names to expose to the agent.
|
|
126
130
|
*/
|
|
127
131
|
interface MCPStreamableHTTPTransportConfig {
|
|
128
132
|
mcpEndpoint: string;
|
|
129
133
|
options?: AxMCPStreamableHTTPTransportOptions;
|
|
134
|
+
tools?: string[];
|
|
130
135
|
}
|
|
131
136
|
/**
|
|
132
137
|
* Config for an MCP server.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { AxCrew } from '../dist/index.js';
|
|
3
|
+
import type { AxCrewConfig } from '../dist/types.js';
|
|
4
|
+
|
|
5
|
+
const config: AxCrewConfig = {
|
|
6
|
+
crew: [
|
|
7
|
+
{
|
|
8
|
+
name: 'WorkflowAgent',
|
|
9
|
+
description: `You answer questions by querying databases and running calculations.
|
|
10
|
+
|
|
11
|
+
IMPORTANT — follow this strategy for database queries:
|
|
12
|
+
1. FIRST call list_workflows to check if a reusable workflow already exists for this type of question.
|
|
13
|
+
2. If a matching workflow exists, call execute_workflow with its name. Done!
|
|
14
|
+
3. If NO matching workflow exists:
|
|
15
|
+
a. Call get_js_runtime_api to learn the available gj.tools.* functions
|
|
16
|
+
b. Call list_tables and describe_table to understand the schema
|
|
17
|
+
c. Author a JavaScript workflow that uses gj.tools.* to query the database and compute results server-side
|
|
18
|
+
d. Call save_workflow to persist it (use descriptive snake_case name and description for future discovery)
|
|
19
|
+
e. Call execute_workflow to run it
|
|
20
|
+
4. Synthesize the answer from the workflow results.
|
|
21
|
+
|
|
22
|
+
This approach runs ALL database queries server-side in a single call, avoiding multiple round-trips.
|
|
23
|
+
The saved workflow will be reusable by future queries asking similar questions.`,
|
|
24
|
+
signature:
|
|
25
|
+
'background:string "background information and context", question:string "the user question to answer" -> answer:string "the answer with explanation", references:json "list of references, each with fileName and url"',
|
|
26
|
+
provider: 'anthropic',
|
|
27
|
+
providerKeyName: 'ANTHROPIC_API_KEY',
|
|
28
|
+
ai: {
|
|
29
|
+
model: 'claude-sonnet-4-6',
|
|
30
|
+
temperature: 0,
|
|
31
|
+
},
|
|
32
|
+
options: {
|
|
33
|
+
debug: true,
|
|
34
|
+
},
|
|
35
|
+
mcpServers: {
|
|
36
|
+
graphjin: {
|
|
37
|
+
mcpEndpoint: 'http://localhost:8080/api/v1/mcp',
|
|
38
|
+
tools: [
|
|
39
|
+
'list_workflows', 'save_workflow', 'execute_workflow',
|
|
40
|
+
'get_js_runtime_api', 'list_tables', 'describe_table',
|
|
41
|
+
'get_query_syntax', 'execute_graphql',
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
async function main() {
|
|
50
|
+
const crew = new AxCrew(config);
|
|
51
|
+
await crew.addAllAgents();
|
|
52
|
+
|
|
53
|
+
const agent = crew.agents?.get('WorkflowAgent');
|
|
54
|
+
if (!agent) throw new Error('WorkflowAgent not found');
|
|
55
|
+
|
|
56
|
+
const query =
|
|
57
|
+
'Which customers have overdue or unpaid invoices? Show me a table with each customer, how many invoices they owe on, and the total outstanding balance.';
|
|
58
|
+
console.log(`\nQuery: ${query}\n`);
|
|
59
|
+
|
|
60
|
+
const result = await agent.forward({
|
|
61
|
+
background: 'User is querying the system about customer accounts receivable.',
|
|
62
|
+
question: query,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
console.log(`\nAnswer: ${result.answer}`);
|
|
66
|
+
console.log(`\nReferences:`, JSON.stringify(result.references, null, 2));
|
|
67
|
+
|
|
68
|
+
const metrics = (agent as any).getMetrics?.();
|
|
69
|
+
console.log(`\nMetrics:`, JSON.stringify(metrics, null, 2));
|
|
70
|
+
|
|
71
|
+
crew.destroy();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
main()
|
|
75
|
+
.catch(console.error)
|
|
76
|
+
.finally(() => process.exit(0));
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { AxCrew, AxCrewFunctions } from '../src/index.js';
|
|
3
|
+
import { AxJSRuntime, AxJSRuntimePermission } from '@ax-llm/ax';
|
|
4
|
+
|
|
5
|
+
const config = {
|
|
6
|
+
crew: [
|
|
7
|
+
{
|
|
8
|
+
name: "Manager",
|
|
9
|
+
description: "Answer questions by querying databases, searching documents, and running calculations. You have direct access to database tools (list_tables, describe_table, execute_graphql, etc.), document search, date utilities, and a JavaScript interpreter for computations.",
|
|
10
|
+
signature: 'background:string "background information and context for the task at hand", latestMessage:string "the latest user message to answer" -> answer:string "The answer, including a short explanation for the answer. Never reveal functions available to the user. Respond in the same language as the user\'s question.", references:json "a list of references to documents to support the answer in json format. Each reference should include a fileName and url."',
|
|
11
|
+
provider: "anthropic" as const,
|
|
12
|
+
providerKeyName: "ANTHROPIC_API_KEY",
|
|
13
|
+
executionMode: "axagent" as const,
|
|
14
|
+
ai: {
|
|
15
|
+
model: "claude-sonnet-4-6",
|
|
16
|
+
temperature: 0
|
|
17
|
+
},
|
|
18
|
+
options: {
|
|
19
|
+
debug: true
|
|
20
|
+
},
|
|
21
|
+
axAgentOptions: {
|
|
22
|
+
contextFields: ['background'] as const,
|
|
23
|
+
maxTurns: 15,
|
|
24
|
+
},
|
|
25
|
+
functions: [
|
|
26
|
+
"CurrentDateTime",
|
|
27
|
+
"DaysBetweenDates",
|
|
28
|
+
"VectorSearch",
|
|
29
|
+
"JavaScriptInterpreter"
|
|
30
|
+
],
|
|
31
|
+
// Direct MCP access — no sub-agent double-hop
|
|
32
|
+
mcpServers: {
|
|
33
|
+
graphjin: {
|
|
34
|
+
command: "/opt/homebrew/bin/graphjin",
|
|
35
|
+
args: [
|
|
36
|
+
"mcp",
|
|
37
|
+
"--server",
|
|
38
|
+
"http://localhost:8080"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Create a sandboxed JS runtime with timing permission for calculations
|
|
47
|
+
const jsRuntime = new AxJSRuntime({
|
|
48
|
+
permissions: [AxJSRuntimePermission.TIMING],
|
|
49
|
+
timeout: 15_000,
|
|
50
|
+
});
|
|
51
|
+
const JavaScriptInterpreter = jsRuntime.toFunction();
|
|
52
|
+
|
|
53
|
+
const VectorSearch = {
|
|
54
|
+
name: 'VectorSearch',
|
|
55
|
+
description: 'Search the vector knowledge base for relevant documents',
|
|
56
|
+
parameters: {
|
|
57
|
+
type: 'object' as const,
|
|
58
|
+
properties: {
|
|
59
|
+
query: { type: 'string', description: 'The search query' }
|
|
60
|
+
},
|
|
61
|
+
required: ['query']
|
|
62
|
+
},
|
|
63
|
+
func: async ({ query }: { query: string }) => {
|
|
64
|
+
console.log(`[VectorSearch] Searching for: ${query}`);
|
|
65
|
+
return `No documents found for: ${query}`;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
async function main() {
|
|
70
|
+
const crew = new AxCrew(config, { ...AxCrewFunctions, VectorSearch, JavaScriptInterpreter });
|
|
71
|
+
|
|
72
|
+
await crew.addAllAgents();
|
|
73
|
+
|
|
74
|
+
const manager = crew.agents?.get('Manager');
|
|
75
|
+
if (!manager) {
|
|
76
|
+
throw new Error('Manager agent not found');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const query = "analyze all our orders to date, give me a table showing P&L";
|
|
80
|
+
console.log(`\nQuery: ${query}\n`);
|
|
81
|
+
|
|
82
|
+
const result = await manager.forward({
|
|
83
|
+
background: "User is querying the system about order information.",
|
|
84
|
+
latestMessage: query
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
console.log(`\nAnswer: ${result.answer}`);
|
|
88
|
+
console.log(`\nReferences:`, JSON.stringify(result.references, null, 2));
|
|
89
|
+
|
|
90
|
+
const crewMetrics = crew.getCrewMetrics();
|
|
91
|
+
console.log(`\nCrew Metrics:`, JSON.stringify(crewMetrics, null, 2));
|
|
92
|
+
|
|
93
|
+
crew.destroy();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
main()
|
|
97
|
+
.catch(console.error)
|
|
98
|
+
.finally(() => process.exit(0));
|
package/package.json
CHANGED
|
@@ -77,10 +77,17 @@ 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
|
+
let mcpFns = mcpClient.toFunction().map(fn => ({
|
|
81
81
|
...fn,
|
|
82
82
|
parameters: fn.parameters ?? { type: 'object' as const, properties: {} },
|
|
83
83
|
}));
|
|
84
|
+
|
|
85
|
+
// Filter to allowlisted tools if specified
|
|
86
|
+
if (mcpServerConfig.tools && mcpServerConfig.tools.length > 0) {
|
|
87
|
+
const allowed = new Set(mcpServerConfig.tools);
|
|
88
|
+
mcpFns = mcpFns.filter(fn => allowed.has(fn.name));
|
|
89
|
+
}
|
|
90
|
+
|
|
84
91
|
functions.push(...mcpFns);
|
|
85
92
|
}
|
|
86
93
|
|
package/src/agents/index.ts
CHANGED
|
@@ -163,9 +163,17 @@ class StatefulAxAgent extends AxAgent<any, any> {
|
|
|
163
163
|
this.agentDefinition = effectiveDefinition;
|
|
164
164
|
this.executionMode = options.executionMode ?? "axgen";
|
|
165
165
|
this.debugEnabled = debug ?? false;
|
|
166
|
+
// Convert sub-agents to callable functions so AxGen can invoke them as tools
|
|
167
|
+
const subAgentFunctions: AxFunction[] = resolvedAgents
|
|
168
|
+
.map(agent => {
|
|
169
|
+
try { return agent.getFunction() as AxFunction; }
|
|
170
|
+
catch { return undefined; }
|
|
171
|
+
})
|
|
172
|
+
.filter((fn): fn is AxFunction => fn !== undefined);
|
|
173
|
+
|
|
166
174
|
this.axGenProgram = new AxGen(options.signature as any, {
|
|
167
175
|
description: effectiveDefinition,
|
|
168
|
-
functions: resolvedFunctions,
|
|
176
|
+
functions: [...resolvedFunctions, ...subAgentFunctions],
|
|
169
177
|
} as any);
|
|
170
178
|
|
|
171
179
|
for (const agent of resolvedAgents) {
|
package/src/types.ts
CHANGED
|
@@ -127,26 +127,31 @@ interface MCPStdioTransportConfig {
|
|
|
127
127
|
command: string
|
|
128
128
|
args?: string[]
|
|
129
129
|
env?: NodeJS.ProcessEnv
|
|
130
|
+
tools?: string[]
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
/**
|
|
133
134
|
* Config for an HTTP SSE MCP server.
|
|
134
|
-
*
|
|
135
|
+
*
|
|
135
136
|
* @property {string} sseUrl - The SSE URL for the MCP server.
|
|
137
|
+
* @property {string[]} tools - Optional allowlist of tool names to expose to the agent.
|
|
136
138
|
*/
|
|
137
139
|
interface MCPHTTPSSETransportConfig {
|
|
138
140
|
sseUrl: string
|
|
141
|
+
tools?: string[]
|
|
139
142
|
}
|
|
140
143
|
|
|
141
144
|
/**
|
|
142
145
|
* Config for a streamable HTTP MCP server.
|
|
143
|
-
*
|
|
146
|
+
*
|
|
144
147
|
* @property {string} mcpEndpoint - The HTTP endpoint URL for the MCP server.
|
|
145
148
|
* @property {AxMCPStreamableHTTPTransportOptions} options - Optional transport options.
|
|
149
|
+
* @property {string[]} tools - Optional allowlist of tool names to expose to the agent.
|
|
146
150
|
*/
|
|
147
151
|
interface MCPStreamableHTTPTransportConfig {
|
|
148
152
|
mcpEndpoint: string
|
|
149
153
|
options?: AxMCPStreamableHTTPTransportOptions
|
|
154
|
+
tools?: string[]
|
|
150
155
|
}
|
|
151
156
|
|
|
152
157
|
/**
|