@amitdeshmukh/ax-crew 8.5.0 → 8.7.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/.claude/settings.local.json +3 -1
- package/.claude/skills/ax-crew/SKILL.md +466 -0
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +7 -7
- package/examples/run-crew-workflow.ts +2 -2
- package/package.json +3 -1
- package/scripts/install-skills.mjs +59 -0
- package/scripts/uninstall-skills.mjs +25 -0
- package/src/skills/ax-crew-ace.md +165 -0
- package/src/skills/ax-crew-agent-config.md +181 -0
- package/src/skills/ax-crew-code-execution.md +166 -0
- package/src/skills/ax-crew-execution-modes.md +287 -0
- package/src/skills/ax-crew-few-shot.md +165 -0
- package/src/skills/ax-crew-functions.md +218 -0
- package/src/skills/ax-crew-mcp.md +221 -0
- package/src/skills/ax-crew-metrics.md +170 -0
- package/src/skills/ax-crew-patterns.md +286 -0
- package/src/skills/ax-crew-providers.md +204 -0
- package/src/skills/ax-crew-signatures.md +169 -0
- package/src/skills/ax-crew-state.md +168 -0
- package/src/skills/ax-crew-streaming.md +143 -0
- package/src/skills/ax-crew-sub-agents.md +203 -0
- package/src/skills/ax-crew-telemetry.md +161 -0
- package/src/skills/ax-crew.md +124 -0
- package/examples/run-manager.ts +0 -98
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ax-crew-mcp
|
|
3
|
+
version: "__VERSION__"
|
|
4
|
+
description: "ax-crew MCP integration: MCP, Model Context Protocol, STDIO, HTTP SSE, Streamable HTTP, mcpServers, tools, tool filtering, multiple servers"
|
|
5
|
+
argument-hint: [topic]
|
|
6
|
+
allowed-tools: Read, Grep, Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# ax-crew MCP (Model Context Protocol)
|
|
10
|
+
|
|
11
|
+
MCP servers expose external tools to agents. Configured per-agent via `mcpServers` in the agent config. Transport type is auto-detected by config shape.
|
|
12
|
+
|
|
13
|
+
## Three Transport Types
|
|
14
|
+
|
|
15
|
+
### STDIO (local process)
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
mcpServers: {
|
|
19
|
+
"context7": {
|
|
20
|
+
command: "npx", // required
|
|
21
|
+
args: ["-y", "@upstash/context7-mcp"], // optional
|
|
22
|
+
env: { API_KEY: "..." }, // optional
|
|
23
|
+
tools: ["resolve-library-id", "query-docs"], // optional allowlist
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Type: `MCPStdioTransportConfig = { command: string; args?: string[]; env?: NodeJS.ProcessEnv; tools?: string[] }`
|
|
29
|
+
|
|
30
|
+
### HTTP SSE (remote, server-sent events)
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
mcpServers: {
|
|
34
|
+
"api-server": {
|
|
35
|
+
sseUrl: "https://api.example.com/mcp/sse", // required
|
|
36
|
+
tools: ["search", "fetch"], // optional allowlist
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Type: `MCPHTTPSSETransportConfig = { sseUrl: string; tools?: string[] }`
|
|
42
|
+
|
|
43
|
+
### Streamable HTTP (bidirectional)
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
mcpServers: {
|
|
47
|
+
"graphjin": {
|
|
48
|
+
mcpEndpoint: "http://localhost:8080/api/v1/mcp", // required
|
|
49
|
+
options: { timeout: 30000 }, // optional AxMCPStreamableHTTPTransportOptions
|
|
50
|
+
tools: ["list_workflows", "execute_workflow"], // optional allowlist
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Type: `MCPStreamableHTTPTransportConfig = { mcpEndpoint: string; options?: AxMCPStreamableHTTPTransportOptions; tools?: string[] }`
|
|
56
|
+
|
|
57
|
+
## tools[] Allowlist
|
|
58
|
+
|
|
59
|
+
When `tools` is specified, only those MCP tool names are exposed to the agent. This reduces token usage and prevents the agent from calling unwanted tools.
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
mcpServers: {
|
|
63
|
+
"big-server": {
|
|
64
|
+
command: "npx",
|
|
65
|
+
args: ["-y", "some-mcp-server"],
|
|
66
|
+
tools: ["only_this_tool", "and_this_one"], // filter from all available
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If `tools` is omitted or empty, all tools from the MCP server are exposed.
|
|
72
|
+
|
|
73
|
+
## Multiple MCP Servers Per Agent
|
|
74
|
+
|
|
75
|
+
An agent can connect to multiple MCP servers simultaneously. All tools are merged:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
{
|
|
79
|
+
name: "MultiToolAgent",
|
|
80
|
+
description: "Agent with multiple MCP servers",
|
|
81
|
+
signature: 'query:string -> answer:string',
|
|
82
|
+
provider: "google-gemini",
|
|
83
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
84
|
+
ai: { model: "gemini-2.5-pro", temperature: 0 },
|
|
85
|
+
mcpServers: {
|
|
86
|
+
"filesystem": {
|
|
87
|
+
command: "npx",
|
|
88
|
+
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
|
|
89
|
+
},
|
|
90
|
+
"database": {
|
|
91
|
+
mcpEndpoint: "http://localhost:8080/api/v1/mcp",
|
|
92
|
+
tools: ["query", "describe_table"],
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Canonical Pattern
|
|
99
|
+
|
|
100
|
+
### STDIO transport (from mcp-agent.ts)
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { AxCrew } from '@amitdeshmukh/ax-crew';
|
|
104
|
+
import type { AxCrewConfig } from '@amitdeshmukh/ax-crew';
|
|
105
|
+
|
|
106
|
+
const config: AxCrewConfig = {
|
|
107
|
+
crew: [
|
|
108
|
+
{
|
|
109
|
+
name: "Context7DocsAgent",
|
|
110
|
+
description: "Agent with access to Context7 Docs APIs",
|
|
111
|
+
signature: 'apiDocQuery:string "a question" -> apiDocAnswer:string "the answer"',
|
|
112
|
+
provider: "google-gemini",
|
|
113
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
114
|
+
ai: { model: "gemini-2.5-pro", temperature: 0 },
|
|
115
|
+
options: { debug: true },
|
|
116
|
+
mcpServers: {
|
|
117
|
+
"context7": {
|
|
118
|
+
command: "npx",
|
|
119
|
+
args: ["-y", "@upstash/context7-mcp", "--api-key", process.env.CONTEXT7_API_KEY!],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: "ManagerAgent",
|
|
125
|
+
description: "Orchestrates sub-agents",
|
|
126
|
+
signature: 'question:string -> answer:string',
|
|
127
|
+
provider: "google-gemini",
|
|
128
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
129
|
+
ai: { model: "gemini-2.5-pro", maxTokens: 1000, temperature: 0 },
|
|
130
|
+
agents: ["Context7DocsAgent"],
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
async function main() {
|
|
136
|
+
const crew = new AxCrew(config);
|
|
137
|
+
try {
|
|
138
|
+
await crew.addAllAgents();
|
|
139
|
+
|
|
140
|
+
const manager = crew.agents?.get("ManagerAgent");
|
|
141
|
+
if (!manager) throw new Error("Agent not found");
|
|
142
|
+
|
|
143
|
+
const result = await manager.forward({
|
|
144
|
+
question: "How do I configure MCP servers in ax-crew?",
|
|
145
|
+
});
|
|
146
|
+
console.log("Answer:", result.answer);
|
|
147
|
+
} finally {
|
|
148
|
+
crew.destroy();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
main().catch(console.error);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Streamable HTTP transport (from graphjin-database-agent.ts)
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { AxCrew } from '@amitdeshmukh/ax-crew';
|
|
159
|
+
import type { AxCrewConfig } from '@amitdeshmukh/ax-crew';
|
|
160
|
+
|
|
161
|
+
const config: AxCrewConfig = {
|
|
162
|
+
crew: [
|
|
163
|
+
{
|
|
164
|
+
name: "DatabaseAgent",
|
|
165
|
+
description: "Agent with direct database access via GraphJin",
|
|
166
|
+
signature: 'dbQuery:string "a database question" -> dbResult:string "the result"',
|
|
167
|
+
provider: "google-gemini",
|
|
168
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
169
|
+
ai: { model: "gemini-2.5-pro", temperature: 0 },
|
|
170
|
+
mcpServers: {
|
|
171
|
+
"graphjin": {
|
|
172
|
+
command: "graphjin",
|
|
173
|
+
args: ["mcp", "--server", "http://localhost:8080"],
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "ManagerAgent",
|
|
179
|
+
description: "Orchestrates database queries",
|
|
180
|
+
signature: 'question:string -> answer:string',
|
|
181
|
+
provider: "google-gemini",
|
|
182
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
183
|
+
ai: { model: "gemini-2.5-pro", maxTokens: 2000, temperature: 0 },
|
|
184
|
+
agents: ["DatabaseAgent"],
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
async function main() {
|
|
190
|
+
const crew = new AxCrew(config);
|
|
191
|
+
try {
|
|
192
|
+
await crew.addAllAgents();
|
|
193
|
+
const manager = crew.agents?.get("ManagerAgent");
|
|
194
|
+
if (!manager) throw new Error("Agent not found");
|
|
195
|
+
|
|
196
|
+
const result = await manager.forward({
|
|
197
|
+
question: "What tables are available in the database?",
|
|
198
|
+
});
|
|
199
|
+
console.log("Answer:", result.answer);
|
|
200
|
+
} finally {
|
|
201
|
+
crew.destroy();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
main().catch(console.error);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Do Not Generate
|
|
209
|
+
|
|
210
|
+
- Do NOT mix transport config keys -- use exactly one of `command`, `sseUrl`, or `mcpEndpoint` per server entry.
|
|
211
|
+
- Do NOT forget `crew.destroy()` -- MCP STDIO processes must be cleaned up.
|
|
212
|
+
- Do NOT put `mcpServers` at the crew level -- it is per-agent only.
|
|
213
|
+
- Do NOT assume MCP tools have `parameters` -- some zero-arg tools omit it; ax-crew normalizes this automatically.
|
|
214
|
+
- Do NOT use `AxMCPStdioTransport` directly -- ax-crew handles transport creation internally from config.
|
|
215
|
+
|
|
216
|
+
## References
|
|
217
|
+
|
|
218
|
+
- [mcp-agent.ts example](https://github.com/amitdeshmukh/ax-crew/blob/main/examples/mcp-agent.ts)
|
|
219
|
+
- [graphjin-database-agent.ts example](https://github.com/amitdeshmukh/ax-crew/blob/main/examples/graphjin-database-agent.ts)
|
|
220
|
+
- [Source: agentConfig.ts (initializeMCPServers)](https://github.com/amitdeshmukh/ax-crew/blob/main/src/agents/agentConfig.ts)
|
|
221
|
+
- [Types: MCPStdioTransportConfig, MCPHTTPSSETransportConfig, MCPStreamableHTTPTransportConfig](https://github.com/amitdeshmukh/ax-crew/blob/main/src/types.ts)
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ax-crew-metrics
|
|
3
|
+
version: "__VERSION__"
|
|
4
|
+
description: "ax-crew metrics and cost tracking: metrics, cost, tracking, getMetrics, getCrewMetrics, MetricsSnapshot, usage, tokens, estimatedCostUSD, resetCosts, resetCrewMetrics"
|
|
5
|
+
argument-hint: [topic]
|
|
6
|
+
allowed-tools: Read, Grep, Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# ax-crew Metrics & Cost Tracking
|
|
10
|
+
|
|
11
|
+
## Per-Agent: agent.getMetrics()
|
|
12
|
+
|
|
13
|
+
Returns a `MetricsSnapshot` scoped to this agent within its crew.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
const agent = crew.agents?.get("MyAgent");
|
|
17
|
+
const metrics = agent.getMetrics();
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Crew-Level: crew.getCrewMetrics()
|
|
21
|
+
|
|
22
|
+
Returns a `MetricsSnapshot` aggregated across all agents in the crew.
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
const crewMetrics = crew.getCrewMetrics();
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## MetricsSnapshot Shape
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
interface MetricsSnapshot {
|
|
32
|
+
provider?: string;
|
|
33
|
+
model?: string;
|
|
34
|
+
requests: {
|
|
35
|
+
totalRequests: number;
|
|
36
|
+
totalErrors: number;
|
|
37
|
+
errorRate: number; // errors / requests
|
|
38
|
+
totalStreamingRequests: number;
|
|
39
|
+
durationMsSum: number;
|
|
40
|
+
durationCount: number;
|
|
41
|
+
};
|
|
42
|
+
tokens: {
|
|
43
|
+
promptTokens: number;
|
|
44
|
+
completionTokens: number;
|
|
45
|
+
totalTokens?: number;
|
|
46
|
+
};
|
|
47
|
+
estimatedCostUSD: number; // rounded to 5 decimal places
|
|
48
|
+
functions: {
|
|
49
|
+
totalFunctionCalls: number;
|
|
50
|
+
totalFunctionLatencyMs: number;
|
|
51
|
+
details?: Array<{ // per-function breakdown
|
|
52
|
+
name: string;
|
|
53
|
+
calls: number;
|
|
54
|
+
totalLatencyMs: number;
|
|
55
|
+
}>;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Reset Methods
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Reset all cost/usage tracking for the entire crew (resets agent usage + metrics)
|
|
64
|
+
crew.resetCosts();
|
|
65
|
+
|
|
66
|
+
// Reset only the metrics registry for the crew
|
|
67
|
+
crew.resetCrewMetrics();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`resetCosts()` calls `resetUsage()` and `resetMetrics()` on each agent, then clears crew-level metrics.
|
|
71
|
+
`resetCrewMetrics()` only clears the MetricsRegistry entries for this crew.
|
|
72
|
+
|
|
73
|
+
## Canonical Pattern
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { AxCrew, AxCrewFunctions } from '@amitdeshmukh/ax-crew';
|
|
77
|
+
import type { AxCrewConfig } from '@amitdeshmukh/ax-crew';
|
|
78
|
+
|
|
79
|
+
const config: AxCrewConfig = {
|
|
80
|
+
crew: [
|
|
81
|
+
{
|
|
82
|
+
name: "researcher",
|
|
83
|
+
description: "A research agent that finds information",
|
|
84
|
+
signature: "query:string -> research:string",
|
|
85
|
+
provider: "google-gemini",
|
|
86
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
87
|
+
ai: { model: "gemini-2.5-flash-lite", maxTokens: 4000, stream: true },
|
|
88
|
+
functions: ["CurrentDateTime"],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "writer",
|
|
92
|
+
description: "A writing agent that creates content",
|
|
93
|
+
signature: "topic:string -> article:string",
|
|
94
|
+
provider: "google-gemini",
|
|
95
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
96
|
+
ai: { model: "gemini-2.5-flash-lite", maxTokens: 4000, stream: true },
|
|
97
|
+
agents: ["researcher"],
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
async function main() {
|
|
103
|
+
const crew = new AxCrew(config, AxCrewFunctions);
|
|
104
|
+
await crew.addAgentsToCrew(["researcher"]);
|
|
105
|
+
await crew.addAgentsToCrew(["writer"]);
|
|
106
|
+
|
|
107
|
+
const writer = crew.agents?.get("writer");
|
|
108
|
+
const researcher = crew.agents?.get("researcher");
|
|
109
|
+
if (!writer || !researcher) throw new Error("Failed to initialize agents");
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const { article } = await writer.forward({
|
|
113
|
+
topic: "Quantum Computing Benefits",
|
|
114
|
+
});
|
|
115
|
+
console.log("Article:", article);
|
|
116
|
+
|
|
117
|
+
// Per-agent metrics
|
|
118
|
+
console.log("Writer Metrics:", JSON.stringify(writer.getMetrics?.(), null, 2));
|
|
119
|
+
console.log("Researcher Metrics:", JSON.stringify(researcher.getMetrics?.(), null, 2));
|
|
120
|
+
|
|
121
|
+
// Crew-wide aggregate
|
|
122
|
+
console.log("Crew Metrics:", JSON.stringify(crew.getCrewMetrics(), null, 2));
|
|
123
|
+
|
|
124
|
+
// Reset for next measurement period
|
|
125
|
+
crew.resetCosts();
|
|
126
|
+
} finally {
|
|
127
|
+
crew.destroy();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
main().catch(console.error);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Accessing Specific Fields
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const m = agent.getMetrics();
|
|
138
|
+
|
|
139
|
+
// Cost
|
|
140
|
+
console.log(`Estimated USD: ${m?.estimatedCostUSD ?? 0}`);
|
|
141
|
+
|
|
142
|
+
// Tokens
|
|
143
|
+
console.log(`Prompt: ${m?.tokens?.promptTokens}, Completion: ${m?.tokens?.completionTokens}, Total: ${m?.tokens?.totalTokens}`);
|
|
144
|
+
|
|
145
|
+
// Request stats
|
|
146
|
+
console.log(`Requests: ${m?.requests?.totalRequests}, Errors: ${m?.requests?.totalErrors}`);
|
|
147
|
+
|
|
148
|
+
// Function calls
|
|
149
|
+
console.log(`Function calls: ${m?.functions?.totalFunctionCalls}`);
|
|
150
|
+
if (m?.functions?.details) {
|
|
151
|
+
for (const fn of m.functions.details) {
|
|
152
|
+
console.log(` ${fn.name}: ${fn.calls} calls, ${fn.totalLatencyMs}ms`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Do Not Generate
|
|
158
|
+
|
|
159
|
+
- Do NOT call `getMetrics()` on the crew object -- use `crew.getCrewMetrics()` for crew-level and `agent.getMetrics()` for per-agent.
|
|
160
|
+
- Do NOT confuse `resetCosts()` with `resetCrewMetrics()` -- `resetCosts()` is broader (resets agent usage too).
|
|
161
|
+
- Do NOT expect `getMetrics()` to return cost data from the legacy `getUsage()` / `getCosts()` API -- those are separate.
|
|
162
|
+
- Do NOT assume `functions.details` is always present -- it is `undefined` when no function calls have been made.
|
|
163
|
+
- Do NOT forget that `estimatedCostUSD` is an estimate based on tracked token counts and model pricing.
|
|
164
|
+
|
|
165
|
+
## References
|
|
166
|
+
|
|
167
|
+
- [basic-researcher-writer.ts example](https://github.com/amitdeshmukh/ax-crew/blob/main/examples/basic-researcher-writer.ts)
|
|
168
|
+
- [rlm-long-task.ts example](https://github.com/amitdeshmukh/ax-crew/blob/main/examples/rlm-long-task.ts)
|
|
169
|
+
- [Source: MetricsSnapshot type](https://github.com/amitdeshmukh/ax-crew/blob/main/src/metrics/types.ts)
|
|
170
|
+
- [Source: MetricsRegistry](https://github.com/amitdeshmukh/ax-crew/blob/main/src/metrics/registry.ts)
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ax-crew-patterns
|
|
3
|
+
version: __VERSION__
|
|
4
|
+
description: "AxCrew multi-agent patterns: pipeline, delegation, fan-out, orchestrator, sequential workflows, and agent coordination."
|
|
5
|
+
tags: [patterns, workflow, pipeline, multi-agent, orchestrator, delegation, sequential, fan-out]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Multi-Agent Patterns
|
|
9
|
+
|
|
10
|
+
## Pipeline Pattern (A -> B -> C)
|
|
11
|
+
|
|
12
|
+
Sequential agent calls where each agent's output feeds the next. Each agent is independent -- the orchestration happens in your code.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { AxCrew } from "ax-crew";
|
|
16
|
+
import type { AxCrewConfig, Provider } from "ax-crew";
|
|
17
|
+
|
|
18
|
+
const config: AxCrewConfig = {
|
|
19
|
+
crew: [
|
|
20
|
+
{
|
|
21
|
+
name: "Planner",
|
|
22
|
+
description: "Generates search queries for a topic",
|
|
23
|
+
signature: 'topic:string, guidance:string -> queries:string[]',
|
|
24
|
+
provider: "anthropic" as Provider,
|
|
25
|
+
providerKeyName: "ANTHROPIC_API_KEY",
|
|
26
|
+
ai: { model: "claude-3-5-sonnet-20240620", temperature: 1 },
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "Searcher",
|
|
30
|
+
description: "Searches the web for a query",
|
|
31
|
+
signature: 'query:string -> searchResult:string',
|
|
32
|
+
provider: "google-gemini" as Provider,
|
|
33
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
34
|
+
ai: { model: "gemini-1.5-pro", temperature: 0.5 },
|
|
35
|
+
options: {
|
|
36
|
+
googleSearchRetrieval: { mode: "MODE_UNSPECIFIED" },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "Writer",
|
|
41
|
+
description: "Writes a blog post from research",
|
|
42
|
+
signature: 'topic:string, guidance:string, searchResults:string[] -> title:string, content:string',
|
|
43
|
+
provider: "anthropic" as Provider,
|
|
44
|
+
providerKeyName: "ANTHROPIC_API_KEY",
|
|
45
|
+
ai: { model: "claude-3-5-sonnet-20240620", temperature: 1 },
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "Publisher",
|
|
49
|
+
description: "Publishes a post to WordPress",
|
|
50
|
+
signature: 'title:string, content:string, status:string -> postResponse:string',
|
|
51
|
+
provider: "anthropic" as Provider,
|
|
52
|
+
providerKeyName: "ANTHROPIC_API_KEY",
|
|
53
|
+
ai: { model: "claude-3-5-sonnet-20240620", temperature: 0 },
|
|
54
|
+
functions: ["WordPressPost"],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
async function main() {
|
|
60
|
+
const crew = new AxCrew(config, customFunctions);
|
|
61
|
+
const agents = await crew.addAgentsToCrew([
|
|
62
|
+
"Planner", "Searcher", "Writer", "Publisher",
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
const planner = agents!.get("Planner")!;
|
|
66
|
+
const searcher = agents!.get("Searcher")!;
|
|
67
|
+
const writer = agents!.get("Writer")!;
|
|
68
|
+
const publisher = agents!.get("Publisher")!;
|
|
69
|
+
|
|
70
|
+
const topic = "How to tell what your dog is thinking";
|
|
71
|
+
const guidance = "Fun, engaging, under 500 words.";
|
|
72
|
+
|
|
73
|
+
// Step 1: Plan
|
|
74
|
+
const { queries } = await planner.forward({ topic, guidance });
|
|
75
|
+
|
|
76
|
+
// Step 2: Research (sequential to avoid rate limits)
|
|
77
|
+
const searchResults: string[] = [];
|
|
78
|
+
for (const query of queries) {
|
|
79
|
+
const { searchResult } = await searcher.forward({ query });
|
|
80
|
+
searchResults.push(searchResult);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Step 3: Write
|
|
84
|
+
const { title, content } = await writer.forward({ topic, guidance, searchResults });
|
|
85
|
+
|
|
86
|
+
// Step 4: Publish
|
|
87
|
+
const { postResponse } = await publisher.forward({ title, content, status: "draft" });
|
|
88
|
+
console.log(postResponse);
|
|
89
|
+
|
|
90
|
+
crew.destroy();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
main().catch(console.error);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Delegation Pattern (Sub-Agents)
|
|
97
|
+
|
|
98
|
+
Use `agents[]` in config to give one agent access to other agents as tools. The parent agent decides when to delegate. Sub-agents must be added to the crew **before** the parent.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
const config: AxCrewConfig = {
|
|
102
|
+
crew: [
|
|
103
|
+
{
|
|
104
|
+
name: "MathAgent",
|
|
105
|
+
description: "Solves math problems using Python code execution",
|
|
106
|
+
signature: 'mathProblem:string -> solution:string',
|
|
107
|
+
provider: "google-gemini" as Provider,
|
|
108
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
109
|
+
ai: { model: "gemini-2.5-flash-lite", temperature: 0 },
|
|
110
|
+
options: { codeExecution: true },
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "ManagerAgent",
|
|
114
|
+
description: "Answers questions, delegating math to MathAgent",
|
|
115
|
+
signature: 'question:string -> answer:string',
|
|
116
|
+
provider: "google-gemini" as Provider,
|
|
117
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
118
|
+
ai: { model: "gemini-2.5-flash-lite", maxTokens: 1000, temperature: 0 },
|
|
119
|
+
agents: ["MathAgent"], // <-- delegation
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
async function main() {
|
|
125
|
+
const crew = new AxCrew(config);
|
|
126
|
+
|
|
127
|
+
// Order matters: sub-agents first, then parent
|
|
128
|
+
await crew.addAgentsToCrew(["MathAgent"]);
|
|
129
|
+
await crew.addAgentsToCrew(["ManagerAgent"]);
|
|
130
|
+
|
|
131
|
+
const manager = crew.agents!.get("ManagerAgent")!;
|
|
132
|
+
const result = await manager.forward({
|
|
133
|
+
question: "What is the 7th root of 1955?",
|
|
134
|
+
});
|
|
135
|
+
console.log(result.answer);
|
|
136
|
+
|
|
137
|
+
crew.destroy();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
main().catch(console.error);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Note: `addAgentsToCrew(["MathAgent", "ManagerAgent"])` also works -- it resolves dependencies automatically.
|
|
144
|
+
|
|
145
|
+
## Fan-Out Pattern (Parallel Agents)
|
|
146
|
+
|
|
147
|
+
Run multiple agents concurrently with `Promise.all`:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
async function main() {
|
|
151
|
+
const crew = new AxCrew(config);
|
|
152
|
+
await crew.addAllAgents();
|
|
153
|
+
|
|
154
|
+
const analyst = crew.agents!.get("Analyst")!;
|
|
155
|
+
const reviewer = crew.agents!.get("Reviewer")!;
|
|
156
|
+
const factChecker = crew.agents!.get("FactChecker")!;
|
|
157
|
+
|
|
158
|
+
const input = { document: "..." };
|
|
159
|
+
|
|
160
|
+
// Fan-out: run all three in parallel
|
|
161
|
+
const [analysis, review, facts] = await Promise.all([
|
|
162
|
+
analyst.forward(input),
|
|
163
|
+
reviewer.forward(input),
|
|
164
|
+
factChecker.forward(input),
|
|
165
|
+
]);
|
|
166
|
+
|
|
167
|
+
// Merge results downstream
|
|
168
|
+
const synthesizer = crew.agents!.get("Synthesizer")!;
|
|
169
|
+
const final = await synthesizer.forward({
|
|
170
|
+
analysis: analysis.result,
|
|
171
|
+
review: review.result,
|
|
172
|
+
facts: facts.result,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
crew.destroy();
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Orchestrator Pattern
|
|
180
|
+
|
|
181
|
+
A manager agent with multiple specialist sub-agents. The manager decides which specialist(s) to invoke based on the query.
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
const config: AxCrewConfig = {
|
|
185
|
+
crew: [
|
|
186
|
+
{
|
|
187
|
+
name: "CodeAgent",
|
|
188
|
+
description: "Writes and reviews code",
|
|
189
|
+
signature: "task:string -> code:string",
|
|
190
|
+
provider: "anthropic" as Provider,
|
|
191
|
+
providerKeyName: "ANTHROPIC_API_KEY",
|
|
192
|
+
ai: { model: "claude-3-5-sonnet-20240620", temperature: 0 },
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: "ResearchAgent",
|
|
196
|
+
description: "Researches technical topics",
|
|
197
|
+
signature: "topic:string -> findings:string",
|
|
198
|
+
provider: "openai" as Provider,
|
|
199
|
+
providerKeyName: "OPENAI_API_KEY",
|
|
200
|
+
ai: { model: "gpt-4o", temperature: 0.5 },
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: "Orchestrator",
|
|
204
|
+
description: "Routes tasks to the right specialist and synthesizes results",
|
|
205
|
+
signature: "request:string -> response:string",
|
|
206
|
+
provider: "anthropic" as Provider,
|
|
207
|
+
providerKeyName: "ANTHROPIC_API_KEY",
|
|
208
|
+
ai: { model: "claude-3-5-sonnet-20240620", temperature: 0.3 },
|
|
209
|
+
agents: ["CodeAgent", "ResearchAgent"], // can delegate to either
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
async function main() {
|
|
215
|
+
const crew = new AxCrew(config);
|
|
216
|
+
await crew.addAgentsToCrew(["CodeAgent", "ResearchAgent", "Orchestrator"]);
|
|
217
|
+
|
|
218
|
+
const orchestrator = crew.agents!.get("Orchestrator")!;
|
|
219
|
+
const result = await orchestrator.forward({
|
|
220
|
+
request: "Research WebSocket best practices and write a TypeScript echo server",
|
|
221
|
+
});
|
|
222
|
+
console.log(result.response);
|
|
223
|
+
|
|
224
|
+
crew.destroy();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
main().catch(console.error);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## definition / prompt for System Prompts
|
|
231
|
+
|
|
232
|
+
Use `definition` (or its alias `prompt`) to provide a detailed system prompt. Must be at least 100 characters. If both are set, `definition` takes precedence.
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
{
|
|
236
|
+
name: "Writer",
|
|
237
|
+
description: "Short description (used as tool description for sub-agent delegation)",
|
|
238
|
+
definition: `You are a senior technical writer specializing in developer documentation.
|
|
239
|
+
Follow the Divio documentation framework: tutorials, how-to guides, reference, explanation.
|
|
240
|
+
Always include code examples. Use active voice. Keep paragraphs under 4 sentences.
|
|
241
|
+
Target audience: intermediate developers familiar with TypeScript.`,
|
|
242
|
+
signature: "topic:string -> documentation:string",
|
|
243
|
+
provider: "anthropic" as Provider,
|
|
244
|
+
providerKeyName: "ANTHROPIC_API_KEY",
|
|
245
|
+
ai: { model: "claude-3-5-sonnet-20240620", temperature: 0.7 },
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Shared State Across Agents
|
|
250
|
+
|
|
251
|
+
All agents in a crew share a mutable `state` object for out-of-band data passing:
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
crew.state.set("env", { WORDPRESS_URL: "http://...", WORDPRESS_USERNAME: "..." });
|
|
255
|
+
crew.state.set("context", { userId: "abc-123" });
|
|
256
|
+
|
|
257
|
+
// Inside a custom function, state is accessible via the constructor:
|
|
258
|
+
class MyTool {
|
|
259
|
+
constructor(private state: Record<string, any>) {}
|
|
260
|
+
toFunction() {
|
|
261
|
+
return {
|
|
262
|
+
name: "myTool",
|
|
263
|
+
description: "...",
|
|
264
|
+
parameters: { ... },
|
|
265
|
+
func: async () => {
|
|
266
|
+
const env = this.state.env; // access shared state
|
|
267
|
+
// ...
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Do Not Generate
|
|
275
|
+
|
|
276
|
+
- Do NOT add a parent agent before its sub-agents -- `addAgentsToCrew` resolves dependencies but `addAgent` does not.
|
|
277
|
+
- Do NOT use `agents: ["SelfName"]` -- an agent cannot be its own sub-agent (circular dependency error).
|
|
278
|
+
- Do NOT assume agents share conversation context -- they share `state` but each `forward()` call is independent. Pass data explicitly via signatures.
|
|
279
|
+
- Do NOT use `definition` shorter than 100 characters -- Ax requires minimum length for program definitions.
|
|
280
|
+
- Do NOT confuse `description` (used as the tool description when this agent is a sub-agent) with `definition` (the system prompt).
|
|
281
|
+
|
|
282
|
+
## References
|
|
283
|
+
|
|
284
|
+
- [write-post-and-publish-to-wordpress.ts](https://github.com/amitdeshmukh/ax-crew/blob/main/examples/write-post-and-publish-to-wordpress.ts) (4-agent pipeline)
|
|
285
|
+
- [solve-math-problem.ts](https://github.com/amitdeshmukh/ax-crew/blob/main/examples/solve-math-problem.ts) (delegation)
|
|
286
|
+
- [search-tweets.ts](https://github.com/amitdeshmukh/ax-crew/blob/main/examples/search-tweets.ts) (streaming)
|