@amitdeshmukh/ax-crew 5.0.0 → 7.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.
@@ -0,0 +1,166 @@
1
+
2
+ import { AxCrew } from "../dist/index.js";
3
+ import { AxCrewFunctions } from "../dist/functions/index.js";
4
+ import type { AxCrewConfig } from "../dist/types.js";
5
+ import type { Provider } from "../dist/types.js";
6
+ import "dotenv/config";
7
+
8
+ // Import OpenTelemetry packages
9
+ // Note: In a real project, you would need to install these dependencies:
10
+ // npm install @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/sdk-metrics
11
+ // Optional: npm install @opentelemetry/exporter-jaeger (for Jaeger UI visualization)
12
+ import { metrics, trace } from "@opentelemetry/api";
13
+ import {
14
+ ConsoleSpanExporter,
15
+ SimpleSpanProcessor,
16
+ } from "@opentelemetry/sdk-trace-base";
17
+ import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
18
+ import {
19
+ ConsoleMetricExporter,
20
+ MeterProvider,
21
+ PeriodicExportingMetricReader,
22
+ } from "@opentelemetry/sdk-metrics";
23
+
24
+ // Optional Jaeger import - will be used if available
25
+ let JaegerExporter;
26
+ try {
27
+ JaegerExporter = (await import('@opentelemetry/exporter-jaeger')).JaegerExporter;
28
+ } catch (error) {
29
+ console.log('Jaeger exporter not available. Install with: npm install @opentelemetry/exporter-jaeger');
30
+ console.log('Traces will only be sent to console.');
31
+ }
32
+
33
+ // --- 1. Setup OpenTelemetry (Console + Optional Jaeger) ---
34
+
35
+ // Set up tracing to console and optionally Jaeger
36
+ const spanProcessors = [new SimpleSpanProcessor(new ConsoleSpanExporter())];
37
+
38
+ // Add Jaeger if available
39
+ if (JaegerExporter) {
40
+ try {
41
+ spanProcessors.push(new SimpleSpanProcessor(new JaegerExporter({
42
+ endpoint: 'http://localhost:14268/api/traces',
43
+ })));
44
+ console.log('Jaeger tracing enabled. View traces at: http://localhost:16686');
45
+ } catch (error) {
46
+ console.log('Failed to initialize Jaeger exporter:', error.message);
47
+ console.log('Continuing with console tracing only.');
48
+ }
49
+ }
50
+
51
+ const tracerProvider = new NodeTracerProvider({
52
+ spanProcessors
53
+ });
54
+ tracerProvider.register(); // This registers it as the global tracer provider
55
+
56
+ // Set up basic metrics to print to console
57
+ const meterProvider = new MeterProvider({
58
+ readers: [
59
+ new PeriodicExportingMetricReader({
60
+ exporter: new ConsoleMetricExporter(),
61
+ exportIntervalMillis: 5000, // Export every 5 seconds
62
+ }),
63
+ ],
64
+ });
65
+ metrics.setGlobalMeterProvider(meterProvider);
66
+
67
+ // Get your tracer and meter instances
68
+ const tracer = trace.getTracer("ax-crew-example");
69
+ const meter = metrics.getMeter("ax-crew-example");
70
+
71
+ // --- 2. Define Crew Configuration ---
72
+
73
+ const crewConfig: AxCrewConfig = {
74
+ crew: [
75
+ {
76
+ name: "Researcher",
77
+ description: "Researches a topic using tools and provides a summary.",
78
+ signature: "topic:string -> facts:string[]",
79
+ // Agent 1 uses OpenAI
80
+ provider: "openai" as Provider,
81
+ providerKeyName: "OPENAI_API_KEY",
82
+ ai: {
83
+ model: "gpt-4o-mini",
84
+ temperature: 0.7,
85
+ },
86
+ // Give this agent access to a tool (function)
87
+ functions: ["CurrentDateTime"]
88
+ },
89
+ {
90
+ name: "Writer",
91
+ description: "Writes a blog post based on provided facts.",
92
+ signature: "facts:string[] -> blogPost:string",
93
+ // Agent 2 uses a different provider (e.g., Google Gemini)
94
+ provider: "google-gemini" as Provider,
95
+ providerKeyName: "GEMINI_API_KEY",
96
+ ai: {
97
+ model: "gemini-flash-latest",
98
+ temperature: 0.7,
99
+ },
100
+ // No tools for this agent, just pure generation
101
+ }
102
+ ]
103
+ };
104
+
105
+ // --- 3. Run the Crew ---
106
+
107
+ async function main() {
108
+ console.log("Starting AxCrew with Telemetry...");
109
+
110
+ // Initialize AxCrew with the telemetry options
111
+ const crew = new AxCrew(
112
+ crewConfig,
113
+ AxCrewFunctions,
114
+ undefined, // Use default crewId
115
+ {
116
+ telemetry: {
117
+ tracer,
118
+ meter
119
+ }
120
+ }
121
+ );
122
+
123
+ try {
124
+ // Initialize agents
125
+ await crew.addAgent("Researcher");
126
+ await crew.addAgent("Writer");
127
+
128
+ const researcher = crew.agents!.get("Researcher")!;
129
+ const writer = crew.agents!.get("Writer")!;
130
+
131
+ // Step 1: Research
132
+ console.log("\n--- Step 1: Researching ---");
133
+ // This call will be traced, including the 'CurrentDateTime' tool usage
134
+ const researchResult = await researcher.forward({
135
+ topic: "The future of AI agents in 2025"
136
+ });
137
+ console.log("Research output:", researchResult.facts);
138
+
139
+ // Step 2: Writing
140
+ console.log("\n--- Step 2: Writing ---");
141
+ // This call will be traced under a different provider
142
+ const writerResult = await writer.forward({
143
+ facts: researchResult.facts
144
+ });
145
+ console.log("Blog Post:\n", writerResult.blogPost);
146
+
147
+ console.log("\n--- Done ---");
148
+ console.log("Check your console output above for OpenTelemetry traces and metrics.");
149
+ if (JaegerExporter) {
150
+ console.log("Check Jaeger UI at http://localhost:16686 for enhanced trace visualization.");
151
+ } else {
152
+ console.log("For enhanced visualization, install Jaeger: npm install @opentelemetry/exporter-jaeger");
153
+ console.log("Then run: docker run -d --name jaeger -p 16686:16686 -p 14268:14268 jaegertracing/all-in-one:latest");
154
+ }
155
+
156
+ // Wait a moment for metrics to export before exiting
157
+ await new Promise(resolve => setTimeout(resolve, 6000));
158
+
159
+ } catch (error) {
160
+ console.error("Error running crew:", error);
161
+ } finally {
162
+ crew.destroy();
163
+ }
164
+ }
165
+
166
+ main().catch(console.error);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@amitdeshmukh/ax-crew",
4
- "version": "5.0.0",
4
+ "version": "7.0.0",
5
5
  "description": "Build and launch a crew of AI agents with shared state. Built with axllm.dev",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -11,7 +11,7 @@
11
11
  "scripts": {
12
12
  "build": "rm -rf dist && tsc --outDir dist",
13
13
  "release": "npm run build && npm publish --access public",
14
- "test": "vitest",
14
+ "test": "vitest run",
15
15
  "test:watch": "vitest watch",
16
16
  "test:coverage": "vitest run --coverage",
17
17
  "test:ui": "vitest --ui"
@@ -24,8 +24,9 @@
24
24
  "uuid": "^10.0.0"
25
25
  },
26
26
  "peerDependencies": {
27
- "@ax-llm/ax": "14.0.16",
28
- "@ax-llm/ax-tools": "14.0.16"
27
+ "@ax-llm/ax": "^14.0.36",
28
+ "@ax-llm/ax-tools": "^14.0.36",
29
+ "@opentelemetry/api": "^1.9.0"
29
30
  },
30
31
  "devDependencies": {
31
32
  "@testing-library/jest-dom": "^6.6.3",
@@ -1,20 +1,13 @@
1
- import fs from 'fs';
2
- // Import Ax factory and MCP transports (as exported by current package)
1
+ // Import Ax factory and MCP transports
3
2
  import { ai, AxMCPClient, AxMCPHTTPSSETransport, AxMCPStreambleHTTPTransport, AxDefaultCostTracker } from '@ax-llm/ax'
4
- import type {
5
- AxAIAzureOpenAIArgs,
6
- AxAIAnthropicArgs,
7
- AxAIGoogleGeminiArgs,
8
- AxAIOpenRouterArgs,
9
- AxAIOllamaArgs
10
- } from '@ax-llm/ax';
11
3
  import type { AxFunction } from '@ax-llm/ax';
12
4
  // STDIO transport from tools package
13
5
  import { AxMCPStdioTransport } from '@ax-llm/ax-tools'
14
- import { PROVIDER_API_KEYS } from '../config/index.js';
6
+ // Resolve env by provided key name
15
7
  import type {
16
8
  AgentConfig,
17
- CrewConfigInput,
9
+ AxCrewConfig,
10
+ AxCrewOptions,
18
11
  FunctionRegistryType,
19
12
  MCPTransportConfig,
20
13
  MCPStdioTransportConfig,
@@ -23,26 +16,6 @@ import type {
23
16
  } from '../types.js';
24
17
  import type { Provider } from '../types.js';
25
18
 
26
- // Canonical provider slugs supported by ai() factory
27
- const PROVIDER_CANONICAL = new Set([
28
- 'openai',
29
- 'anthropic',
30
- 'google-gemini',
31
- 'mistral',
32
- 'groq',
33
- 'cohere',
34
- 'together',
35
- 'deepseek',
36
- 'ollama',
37
- 'huggingface',
38
- 'openrouter',
39
- 'azure-openai',
40
- 'reka',
41
- 'x-grok'
42
- ]);
43
-
44
- // Provider type lives in src/types.ts
45
-
46
19
  // Type guard to check if config is stdio transport
47
20
  export function isStdioTransport(config: MCPTransportConfig): config is MCPStdioTransportConfig {
48
21
  return 'command' in config;
@@ -69,53 +42,7 @@ function isConstructor<T>(func: any): func is { new (...args: any[]): T } {
69
42
  return typeof func === 'function' && 'prototype' in func && 'toFunction' in func.prototype;
70
43
  }
71
44
 
72
- /**
73
- * Provides a user-friendly error message for JSON parsing errors
74
- */
75
- const getFormattedJSONError = (error: Error, fileContents: string): string => {
76
- if (error instanceof SyntaxError) {
77
- const match = error.message.match(/position (\d+)/);
78
- const position = match ? parseInt(match[1]) : -1;
79
-
80
- if (position !== -1) {
81
- const lines = fileContents.split('\n');
82
- let currentPos = 0;
83
- let errorLine = 0;
84
- let errorColumn = 0;
85
-
86
- // Find the line and column of the error
87
- for (let i = 0; i < lines.length; i++) {
88
- if (currentPos + lines[i].length >= position) {
89
- errorLine = i + 1;
90
- errorColumn = position - currentPos + 1;
91
- break;
92
- }
93
- currentPos += lines[i].length + 1; // +1 for the newline character
94
- }
95
-
96
- const contextLines = lines.slice(Math.max(0, errorLine - 3), errorLine + 2)
97
- .map((line, idx) => `${errorLine - 2 + idx}: ${line}`).join('\n');
98
-
99
- return `JSON Parse Error in your agent configuration:
100
-
101
- Error near line ${errorLine}, column ${errorColumn}
102
-
103
- Context:
104
- ${contextLines}
105
-
106
- Common issues to check:
107
- - Missing or extra commas between properties
108
- - Missing quotes around property names
109
- - Unmatched brackets or braces
110
- - Invalid JSON values
111
- - Trailing commas (not allowed in JSON)
112
-
113
- Original error: ${error.message}`;
114
- }
115
- }
116
-
117
- return `Error parsing agent configuration: ${error.message}`;
118
- };
45
+ // Removed file/JSON parse helpers to keep browser-safe
119
46
 
120
47
  const initializeMCPServers = async (agentConfigData: AgentConfig): Promise<AxFunction[]> => {
121
48
  const mcpServers = agentConfigData.mcpServers;
@@ -158,32 +85,16 @@ const initializeMCPServers = async (agentConfigData: AgentConfig): Promise<AxFun
158
85
  };
159
86
 
160
87
  /**
161
- * Parses and returns the AxCrew config from either a JSON config file or a direct JSON object.
162
- * @param {CrewConfigInput} input - Either a path to the agent config json file or a JSON object with crew configuration.
88
+ * Returns the AxCrew config from a direct JSON object. Browser-safe.
89
+ * @param {CrewConfig} input - A JSON object with crew configuration.
163
90
  * @returns {Object} The parsed crew config.
164
91
  * @throws Will throw an error if reading/parsing fails.
165
92
  */
166
- const parseCrewConfig = (input: CrewConfigInput): { crew: AgentConfig[] } => {
167
- try {
168
- if (typeof input === 'string') {
169
- // Handle file path input
170
- const fileContents = fs.readFileSync(input, 'utf8');
171
- const parsedConfig = JSON.parse(fileContents) as { crew: AgentConfig[] };
172
- return parsedConfig;
173
- } else {
174
- // Handle direct JSON object input
175
- return input;
176
- }
177
- } catch (e) {
178
- if (e instanceof Error) {
179
- if (typeof input === 'string') {
180
- const formattedError = getFormattedJSONError(e, fs.readFileSync(input, 'utf8'));
181
- throw new Error(formattedError);
182
- }
183
- throw new Error(`Error parsing agent configuration: ${e.message}`);
184
- }
185
- throw e;
93
+ const parseCrewConfig = (input: AxCrewConfig): { crew: AgentConfig[] } => {
94
+ if (!input || typeof input !== 'object' || !Array.isArray((input as any).crew)) {
95
+ throw new Error('Invalid crew configuration: expected an object with a crew array');
186
96
  }
97
+ return input as { crew: AgentConfig[] };
187
98
  };
188
99
 
189
100
  /**
@@ -191,7 +102,7 @@ const parseCrewConfig = (input: CrewConfigInput): { crew: AgentConfig[] } => {
191
102
  * and creates an instance of the Agent with the appropriate settings.
192
103
  *
193
104
  * @param {string} agentName - The identifier for the AI agent to be initialized.
194
- * @param {CrewConfigInput} crewConfig - Either a file path to the JSON configuration or a JSON object with crew configuration.
105
+ * @param {AxCrewConfig} crewConfig - A JSON object with crew configuration.
195
106
  * @param {FunctionRegistryType} functions - The functions available to the agent.
196
107
  * @param {Object} state - The state object for the agent.
197
108
  * @returns {Object} An object containing the Agents AI instance, its name, description, signature, functions and subAgentList.
@@ -200,9 +111,10 @@ const parseCrewConfig = (input: CrewConfigInput): { crew: AgentConfig[] } => {
200
111
  */
201
112
  const parseAgentConfig = async (
202
113
  agentName: string,
203
- crewConfig: CrewConfigInput,
114
+ crewConfig: AxCrewConfig,
204
115
  functions: FunctionRegistryType,
205
- state: Record<string, any>
116
+ state: Record<string, any>,
117
+ options?: AxCrewOptions
206
118
  ) => {
207
119
  try {
208
120
  // Retrieve the parameters for the specified AI agent from config
@@ -211,20 +123,17 @@ const parseAgentConfig = async (
211
123
  throw new Error(`AI agent with name ${agentName} is not configured`);
212
124
  }
213
125
 
214
- // Enforce canonical provider slug
215
- const lower = agentConfigData.provider.toLowerCase();
216
- if (!PROVIDER_CANONICAL.has(lower)) {
217
- throw new Error(`AI provider ${agentConfigData.provider} is not supported. Use one of: ${Array.from(PROVIDER_CANONICAL).join(', ')}`);
218
- }
126
+ // Normalize provider slug to lowercase and validate via Ax factory
127
+ const lower = String(agentConfigData.provider).toLowerCase() as Provider;
219
128
  const provider = lower as Provider;
220
129
 
221
- // If an API Key property is present, get the API key for the AI agent from the environment variables
130
+ // Resolve API key from user-supplied environment variable name
222
131
  let apiKey = '';
223
132
  if (agentConfigData.providerKeyName) {
224
- apiKey = PROVIDER_API_KEYS[agentConfigData.providerKeyName] || '';
225
-
133
+ const keyName = agentConfigData.providerKeyName;
134
+ apiKey = resolveApiKey(keyName) || '';
226
135
  if (!apiKey) {
227
- throw new Error(`API key for provider ${agentConfigData.provider} is not set in environment variables`);
136
+ throw new Error(`API key '${keyName}' for provider ${agentConfigData.provider} is not set in environment`);
228
137
  }
229
138
  } else {
230
139
  throw new Error(`Provider key name is missing in the agent configuration`);
@@ -242,7 +151,10 @@ const parseAgentConfig = async (
242
151
  debug: agentConfigData.debug || false,
243
152
  ...agentConfigData.options,
244
153
  // Attach default cost tracker so usage/costs are recorded by provider layer
245
- trackers: [costTracker]
154
+ trackers: [costTracker],
155
+ // Inject telemetry if provided
156
+ tracer: options?.telemetry?.tracer,
157
+ meter: options?.telemetry?.meter
246
158
  }
247
159
  };
248
160
  if (agentConfigData.apiURL) {
@@ -253,37 +165,19 @@ const parseAgentConfig = async (
253
165
  throw new Error(`Invalid apiURL provided: ${agentConfigData.apiURL}`);
254
166
  }
255
167
  }
256
- // Forward provider-specific arguments with type-safety for Azure OpenAI
168
+ // Forward provider-specific arguments as-is; let Ax validate/ignore as needed
257
169
  const providerArgs = (agentConfigData as any).providerArgs;
258
- if (provider === 'azure-openai') {
259
- type AzureArgs = Pick<AxAIAzureOpenAIArgs<string>, 'resourceName' | 'deploymentName' | 'version'>;
260
- const az: Partial<AzureArgs> = providerArgs ?? {};
261
- // If users supplied apiURL instead of resourceName, accept it (Ax supports full URL as resourceName)
262
- if (!az.resourceName && agentConfigData.apiURL) {
263
- az.resourceName = agentConfigData.apiURL as any;
264
- }
265
- Object.assign(aiArgs, az);
266
- } else if (provider === 'anthropic') {
267
- type AnthropicArgs = Pick<AxAIAnthropicArgs<string>, 'projectId' | 'region'>;
268
- const an: Partial<AnthropicArgs> = providerArgs ?? {};
269
- Object.assign(aiArgs, an);
270
- } else if (provider === 'google-gemini') {
271
- type GeminiArgs = Pick<AxAIGoogleGeminiArgs<string>, 'projectId' | 'region' | 'endpointId'>;
272
- const g: Partial<GeminiArgs> = providerArgs ?? {};
273
- Object.assign(aiArgs, g);
274
- } else if (provider === 'openrouter') {
275
- type OpenRouterArgs = Pick<AxAIOpenRouterArgs<string>, 'referer' | 'title'>;
276
- const o: Partial<OpenRouterArgs> = providerArgs ?? {};
277
- Object.assign(aiArgs, o);
278
- } else if (provider === 'ollama') {
279
- type OllamaArgs = Pick<AxAIOllamaArgs<string>, 'url'>;
280
- const ol: Partial<OllamaArgs> = providerArgs ?? {};
281
- Object.assign(aiArgs, ol);
282
- } else if (providerArgs && typeof providerArgs === 'object') {
283
- // Generic pass-through for other providers if needed in the future
170
+ if (providerArgs && typeof providerArgs === 'object') {
284
171
  Object.assign(aiArgs, providerArgs);
285
172
  }
286
- const aiInstance = ai(aiArgs);
173
+ // Validate provider by attempting instantiation; Ax will throw on unknown providers
174
+ let aiInstance;
175
+ try {
176
+ aiInstance = ai(aiArgs);
177
+ } catch (e) {
178
+ const msg = e instanceof Error ? e.message : String(e);
179
+ throw new Error(`Unsupported provider '${provider}': ${msg}`);
180
+ }
287
181
 
288
182
  // If an mcpServers config is provided in the agent config, convert to functions
289
183
  const mcpFunctions = await initializeMCPServers(agentConfigData);
@@ -328,4 +222,21 @@ const parseAgentConfig = async (
328
222
  export {
329
223
  parseAgentConfig,
330
224
  parseCrewConfig
331
- };
225
+ };
226
+
227
+ function resolveApiKey(varName: string): string | undefined {
228
+ try {
229
+ // Prefer Node env when available
230
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
231
+ // @ts-ignore
232
+ if (typeof process !== 'undefined' && process?.env) {
233
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
234
+ // @ts-ignore
235
+ return process.env[varName];
236
+ }
237
+ // Fallback: allow global exposure in browser builds (e.g., injected at runtime)
238
+ return (globalThis as any)?.[varName];
239
+ } catch {
240
+ return undefined;
241
+ }
242
+ }
@@ -0,0 +1,80 @@
1
+ import { ai } from '@ax-llm/ax';
2
+ import type { AxAI } from '@ax-llm/ax';
3
+ import type { AxCrewConfig } from '../types.js';
4
+
5
+ type BuildProviderArgs = {
6
+ provider: string;
7
+ apiKey: string;
8
+ config: any;
9
+ apiURL?: string;
10
+ providerArgs?: Record<string, unknown>;
11
+ options?: Record<string, unknown>;
12
+ };
13
+
14
+ export function instantiateProvider({
15
+ provider,
16
+ apiKey,
17
+ config,
18
+ apiURL,
19
+ providerArgs,
20
+ options,
21
+ }: BuildProviderArgs): AxAI<any> {
22
+ const args: any = { name: provider as any, apiKey, config, options };
23
+ if (apiURL) args.apiURL = apiURL;
24
+ if (providerArgs && typeof providerArgs === 'object') Object.assign(args, providerArgs);
25
+ return ai(args) as unknown as AxAI<any>;
26
+ }
27
+
28
+ export function buildProvidersFromConfig(cfg: AxCrewConfig): AxAI<any>[] {
29
+ const services: AxAI<any>[] = [];
30
+ for (const agent of cfg.crew) {
31
+ const apiKeyName = agent.providerKeyName;
32
+ if (!apiKeyName) throw new Error(`Provider key name is missing for agent ${agent.name}`);
33
+ const apiKey = resolveApiKey(apiKeyName) || '';
34
+ if (!apiKey) throw new Error(`API key '${apiKeyName}' not set for agent ${agent.name}`);
35
+
36
+ const service = instantiateProvider({
37
+ provider: String(agent.provider).toLowerCase(),
38
+ apiKey,
39
+ config: agent.ai,
40
+ apiURL: agent.apiURL,
41
+ providerArgs: (agent as any).providerArgs,
42
+ options: agent.options,
43
+ });
44
+ services.push(service);
45
+ }
46
+ return services;
47
+ }
48
+
49
+
50
+ // Provider discovery helpers consolidated here (previously in src/providers.ts)
51
+ export function discoverProvidersFromConfig(cfg: AxCrewConfig): string[] {
52
+ const providers = new Set<string>();
53
+ for (const agent of cfg.crew) {
54
+ providers.add(String(agent.provider).toLowerCase());
55
+ }
56
+ return Array.from(providers);
57
+ }
58
+
59
+ export function listSelectableProviders(cfg: AxCrewConfig): string[] {
60
+ return discoverProvidersFromConfig(cfg);
61
+ }
62
+
63
+ function resolveApiKey(varName: string): string | undefined {
64
+ try {
65
+ // Prefer Node env when available
66
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
67
+ // @ts-ignore
68
+ if (typeof process !== 'undefined' && process?.env) {
69
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
70
+ // @ts-ignore
71
+ return process.env[varName];
72
+ }
73
+ // Fallback: allow global exposure in browser builds (e.g., injected at runtime)
74
+ return (globalThis as any)?.[varName];
75
+ } catch {
76
+ return undefined;
77
+ }
78
+ }
79
+
80
+
@@ -14,7 +14,8 @@ import type {
14
14
  StateInstance,
15
15
  FunctionRegistryType,
16
16
  UsageCost,
17
- CrewConfigInput,
17
+ AxCrewConfig,
18
+ AxCrewOptions,
18
19
  MCPTransportConfig,
19
20
  } from "../types.js";
20
21
 
@@ -260,10 +261,27 @@ class StatefulAxAgent extends AxAgent<any, any> {
260
261
  }
261
262
 
262
263
  /**
263
- * Represents a crew of agents with shared state functionality.
264
+ * AxCrew orchestrates a set of Ax agents that share state,
265
+ * tools (functions), optional MCP servers, streaming, and a built-in metrics
266
+ * registry for tokens, requests, and estimated cost.
267
+ *
268
+ * Typical usage:
269
+ * const crew = new AxCrew(config, AxCrewFunctions)
270
+ * await crew.addAllAgents()
271
+ * const planner = crew.agents?.get("Planner")
272
+ * const res = await planner?.forward({ task: "Plan something" })
273
+ *
274
+ * Key behaviors:
275
+ * - Validates and instantiates agents from a config-first model
276
+ * - Shares a mutable state object across all agents in the crew
277
+ * - Supports sub-agents and a function registry per agent
278
+ * - Tracks per-agent and crew-level metrics via MetricsRegistry
279
+ * - Provides helpers to add agents (individually, a subset, or all) and
280
+ * to reset metrics/costs when needed
264
281
  */
265
282
  class AxCrew {
266
- private crewConfig: CrewConfigInput;
283
+ private crewConfig: AxCrewConfig;
284
+ private options?: AxCrewOptions;
267
285
  functionsRegistry: FunctionRegistryType = {};
268
286
  crewId: string;
269
287
  agents: Map<string, StatefulAxAgent> | null;
@@ -271,14 +289,16 @@ class AxCrew {
271
289
 
272
290
  /**
273
291
  * Creates an instance of AxCrew.
274
- * @param {CrewConfigInput} crewConfig - Either a path to the agent config file or a JSON object with crew configuration.
292
+ * @param {AxCrewConfig} crewConfig - JSON object with crew configuration.
275
293
  * @param {FunctionRegistryType} [functionsRegistry={}] - The registry of functions to use in the crew.
294
+ * @param {AxCrewOptions} [options] - Optional settings for the crew (e.g., telemetry).
276
295
  * @param {string} [crewId=uuidv4()] - The unique identifier for the crew.
277
296
  */
278
297
  constructor(
279
- crewConfig: CrewConfigInput,
298
+ crewConfig: AxCrewConfig,
280
299
  functionsRegistry: FunctionRegistryType = {},
281
- crewId: string = uuidv4()
300
+ options?: AxCrewOptions,
301
+ crewId: string = uuidv4(),
282
302
  ) {
283
303
  // Basic validation of crew configuration
284
304
  if (!crewConfig || typeof crewConfig !== 'object' || !('crew' in crewConfig)) {
@@ -286,7 +306,7 @@ class AxCrew {
286
306
  }
287
307
 
288
308
  // Validate each agent in the crew
289
- crewConfig.crew.forEach(agent => {
309
+ crewConfig.crew.forEach((agent: any) => {
290
310
  if (!agent.name || agent.name.trim() === '') {
291
311
  throw new Error('Agent name cannot be empty');
292
312
  }
@@ -295,6 +315,7 @@ class AxCrew {
295
315
  this.crewConfig = crewConfig;
296
316
  this.functionsRegistry = functionsRegistry;
297
317
  this.crewId = crewId;
318
+ this.options = options;
298
319
  this.agents = new Map<string, StatefulAxAgent>();
299
320
  this.state = createState(crewId);
300
321
  // Make crewId discoverable to metrics
@@ -313,7 +334,8 @@ class AxCrew {
313
334
  agentName,
314
335
  this.crewConfig,
315
336
  this.functionsRegistry,
316
- this.state
337
+ this.state,
338
+ this.options
317
339
  );
318
340
 
319
341
  // Destructure with type assertion
@@ -1,6 +1,16 @@
1
1
  import { CurrentDateTime, DaysBetweenDates } from './dateTime.js';
2
2
 
3
- // Built-in functions
3
+ /**
4
+ * Built-in function registry for AxCrew agents.
5
+ *
6
+ * Contains common utility tools/functions that can be referenced by name from
7
+ * agent configs (e.g., "functions": ["CurrentDateTime", "DaysBetweenDates"]).
8
+ * You can pass this object to the AxCrew constructor or merge with your
9
+ * own registry.
10
+ * Example:
11
+ * const crew = new AxCrew(config, AxCrewFunctions); or
12
+ * const crew = new AxCrew(config, { ...AxCrewFunctions, ...myFunctions });
13
+ */
4
14
  const AxCrewFunctions = {
5
15
  CurrentDateTime,
6
16
  DaysBetweenDates