@amitdeshmukh/ax-crew 4.1.2 → 6.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 CHANGED
@@ -1,3 +1,46 @@
1
+ # Changelog
2
+
3
+ ## [6.0.0] - 2025-10-22
4
+
5
+ ### Breaking
6
+ - Config is now object-only to be browser-safe. File-path based configs are no longer supported. Load JSON yourself and pass `{ crew: [...] }`.
7
+
8
+ ### Added
9
+ - Runtime API key resolution via `providerKeyName`. Keys are read from `process.env[providerKeyName]` in Node or `globalThis[providerKeyName]` in the browser.
10
+ - Updated examples to use `dotenv/config` to ensure keys are available at runtime.
11
+
12
+ ### Changed
13
+ - Removed reliance on a hardcoded `PROVIDER_API_KEYS` map; providers read secrets using the user-supplied env var name.
14
+ - `providerArgs` are forwarded unchanged to Ax; validation and semantics are handled by Ax provider implementations.
15
+ - Docs updated: object-only config, env resolution behavior, providerArgs guidance.
16
+
17
+ ### Removed
18
+ - Hardcoded provider lists/registries and the old `providers.ts` list file.
19
+ - Temporary removal of router/balancer helpers and related examples to simplify this refactor.
20
+
21
+ ### Migration notes
22
+ - If you previously passed a config file path, read the file yourself and pass the parsed object to `new AxCrew(config)`.
23
+ - Set `providerKeyName` to the exact environment variable name holding the API key. Ensure env is loaded before constructing the crew (e.g., `import 'dotenv/config'`).
24
+
25
+ ## [5.0.0] - 2025-10-16
26
+
27
+ ### Added
28
+ - Provider-specific arguments via `providerArgs` in `AgentConfig` to pass through typed provider params to the underlying Ax factory.
29
+ - Typed forwarding for common providers in `parseAgentConfig`:
30
+ - azure-openai: `resourceName`, `deploymentName`, `version` (falls back to `apiURL` as `resourceName` if provided)
31
+ - anthropic: `projectId`, `region` (on Vertex AI)
32
+ - google-gemini: `projectId`, `region`, `endpointId`
33
+ - openrouter: `referer`, `title`
34
+ - ollama: `url`
35
+ - Example `examples/providerArgs.ts` demonstrating `providerArgs` with Azure OpenAI.
36
+ - JSDoc function hints for cost/usage APIs (`getMetrics`, `resetMetrics`, `resetCosts`, `getCrewMetrics`, `resetCrewMetrics`, and metrics registry helpers).
37
+
38
+ ### Docs
39
+ - README section documenting `providerArgs` usage, supported providers, and Azure configuration examples.
40
+
41
+ ### Notes
42
+ - Existing configs continue to work. For Azure, you can still set `apiURL`; when `resourceName` is omitted, the code uses `apiURL` as the `resourceName` (full endpoint) for convenience.
43
+
1
44
  # Changelog
2
45
  ## [4.1.2] - 2025-10-14
3
46
 
package/README.md CHANGED
@@ -33,34 +33,17 @@ ANTHROPIC_API_KEY=...
33
33
  OPENAI_API_KEY=...
34
34
  AZURE_OPENAI_API_KEY=...
35
35
  ```
36
- In each agent config, set `providerKeyName` to the env var name.
36
+ In each agent config, set `providerKeyName` to the env var name. AxCrew resolves the key at runtime by reading `process.env[providerKeyName]` in Node or `globalThis[providerKeyName]` in the browser. Ensure your env is loaded (for example, import `dotenv/config` in Node) before creating the crew.
37
37
 
38
- #### Azure OpenAI
39
- - Use provider `azure-openai`.
40
- - Set `providerKeyName` to `AZURE_OPENAI_API_KEY`.
41
- - Set `apiURL` to your Azure endpoint (e.g., `https://your-resource.openai.azure.com`).
42
-
43
- Minimal example agent config:
44
- ```json
45
- {
46
- "name": "Writer",
47
- "description": "Writes concise summaries",
48
- "signature": "topic:string -> summary:string",
49
- "provider": "azure-openai",
50
- "providerKeyName": "AZURE_OPENAI_API_KEY",
51
- "ai": { "model": "gpt-4o-mini", "temperature": 0 },
52
- "apiURL": "https://your-resource.openai.azure.com"
53
- }
54
- ```
38
+ #### Provider-specific arguments (`providerArgs`)
39
+ Some providers require extra top-level configuration beyond `ai.model` (for example, Azure deployment details or Vertex AI project/region). Pass these via `providerArgs`. AxCrew forwards `providerArgs` to Ax unchanged; validation and semantics are handled by Ax. Refer to Ax provider docs for supported fields.
55
40
 
56
41
  ### Quickstart
57
- This package includes TypeScript declarations and provides type safety.
58
42
 
59
43
  ```typescript
60
44
  import { AxCrew, AxCrewFunctions, FunctionRegistryType, StateInstance } from '@amitdeshmukh/ax-crew';
61
45
  import type { AxFunction } from '@ax-llm/ax';
62
46
 
63
- // Type-safe configuration
64
47
  const config = {
65
48
  crew: [{
66
49
  name: "Planner",
@@ -147,25 +130,7 @@ Key TypeScript features:
147
130
  ## Usage
148
131
 
149
132
  ### Initializing a Crew
150
- A Crew is a team of agents that work together to achieve a common goal. You can configure your crew in two ways:
151
-
152
- 1. Using a JSON configuration file that defines the agents in the crew, along with their individual configurations.
153
- 2. Directly passing a JSON object with the crew configuration.
154
-
155
- #### Using a Configuration File
156
- See [agentConfig.json](agentConfig.json) for an example configuration file.
157
-
158
- ```javascript
159
- // Import the AxCrew class
160
- import { AxCrew } from '@amitdeshmukh/ax-crew';
161
-
162
- // Create a new instance of AxCrew using a config file
163
- const configFilePath = './agentConfig.json';
164
- const crew = new AxCrew(configFilePath);
165
- ```
166
-
167
- #### Using a Direct Configuration Object
168
- You can also pass the configuration directly as a JSON object:
133
+ Pass a JSON object to the `AxCrew` constructor:
169
134
 
170
135
  ```javascript
171
136
  // Import the AxCrew class
@@ -196,15 +161,7 @@ const config = {
196
161
  const crew = new AxCrew(config);
197
162
  ```
198
163
 
199
- Both methods support the same configuration structure and options. Choose the one that best fits your use case:
200
- - Use a configuration file when you want to:
201
- - Keep your configuration separate from your code
202
- - Share configurations across different projects
203
- - Version control your configurations
204
- - Use a direct configuration object when you want to:
205
- - Generate configurations dynamically
206
- - Modify configurations at runtime
207
- - Keep everything in one file for simpler projects
164
+ AxCrew no longer supports reading from a configuration file to remain browser-compatible.
208
165
 
209
166
  ### Agent Persona: definition and prompt
210
167
 
@@ -408,7 +365,7 @@ An example of how to complete a task using the agents is shown below. The `Plann
408
365
  import { AxCrew, AxCrewFunctions } from '@amitdeshmukh/ax-crew';
409
366
 
410
367
  // Create a new instance of AxCrew
411
- const crew = new AxCrew('./agentConfig.json', AxCrewFunctions);
368
+ const crew = new AxCrew(config, AxCrewFunctions);
412
369
  crew.addAgentsToCrew(['Planner', 'Calculator', 'Manager']);
413
370
 
414
371
  // Get agent instances
@@ -440,7 +397,7 @@ The package supports streaming responses from agents, allowing you to receive an
440
397
  import { AxCrew, AxCrewFunctions } from '@amitdeshmukh/ax-crew';
441
398
 
442
399
  // Create and initialize crew as shown above
443
- const crew = new AxCrew('./agentConfig.json', AxCrewFunctions);
400
+ const crew = new AxCrew(config, AxCrewFunctions);
444
401
  await crew.addAgentsToCrew(['Planner']);
445
402
 
446
403
  const planner = crew.agents.get("Planner");
@@ -657,7 +614,7 @@ MCP functions are automatically available to agents once the servers are configu
657
614
  import { AxCrew } from '@amitdeshmukh/ax-crew';
658
615
 
659
616
  // Create crew with MCP-enabled agents
660
- const crew = new AxCrew('./agentConfig.json');
617
+ const crew = new AxCrew(config);
661
618
  await crew.addAgent('DataAnalyst'); // Agent with MCP servers configured
662
619
 
663
620
  const analyst = crew.agents.get('DataAnalyst');
@@ -1,16 +1,16 @@
1
1
  import { AxDefaultCostTracker } from '@ax-llm/ax';
2
2
  import type { AxFunction } from '@ax-llm/ax';
3
- import type { AgentConfig, CrewConfigInput, FunctionRegistryType, MCPTransportConfig, MCPStdioTransportConfig, MCPHTTPSSETransportConfig, MCPStreamableHTTPTransportConfig } from '../types.js';
3
+ import type { AgentConfig, AxCrewConfig, FunctionRegistryType, MCPTransportConfig, MCPStdioTransportConfig, MCPHTTPSSETransportConfig, MCPStreamableHTTPTransportConfig } from '../types.js';
4
4
  export declare function isStdioTransport(config: MCPTransportConfig): config is MCPStdioTransportConfig;
5
5
  export declare function isHTTPSSETransport(config: MCPTransportConfig): config is MCPHTTPSSETransportConfig;
6
6
  export declare function isStreambleHTTPTransport(config: MCPTransportConfig): config is MCPStreamableHTTPTransportConfig;
7
7
  /**
8
- * Parses and returns the AxCrew config from either a JSON config file or a direct JSON object.
9
- * @param {CrewConfigInput} input - Either a path to the agent config json file or a JSON object with crew configuration.
8
+ * Returns the AxCrew config from a direct JSON object. Browser-safe.
9
+ * @param {CrewConfig} input - A JSON object with crew configuration.
10
10
  * @returns {Object} The parsed crew config.
11
11
  * @throws Will throw an error if reading/parsing fails.
12
12
  */
13
- declare const parseCrewConfig: (input: CrewConfigInput) => {
13
+ declare const parseCrewConfig: (input: AxCrewConfig) => {
14
14
  crew: AgentConfig[];
15
15
  };
16
16
  /**
@@ -18,14 +18,14 @@ declare const parseCrewConfig: (input: CrewConfigInput) => {
18
18
  * and creates an instance of the Agent with the appropriate settings.
19
19
  *
20
20
  * @param {string} agentName - The identifier for the AI agent to be initialized.
21
- * @param {CrewConfigInput} crewConfig - Either a file path to the JSON configuration or a JSON object with crew configuration.
21
+ * @param {AxCrewConfig} crewConfig - A JSON object with crew configuration.
22
22
  * @param {FunctionRegistryType} functions - The functions available to the agent.
23
23
  * @param {Object} state - The state object for the agent.
24
24
  * @returns {Object} An object containing the Agents AI instance, its name, description, signature, functions and subAgentList.
25
25
  * @throws {Error} Throws an error if the agent configuration is missing, the provider is unsupported,
26
26
  * the API key is not found, or the provider key name is not specified in the configuration.
27
27
  */
28
- declare const parseAgentConfig: (agentName: string, crewConfig: CrewConfigInput, functions: FunctionRegistryType, state: Record<string, any>) => Promise<{
28
+ declare const parseAgentConfig: (agentName: string, crewConfig: AxCrewConfig, functions: FunctionRegistryType, state: Record<string, any>) => Promise<{
29
29
  ai: import("@ax-llm/ax").AxAI<string>;
30
30
  name: string;
31
31
  description: string;
@@ -1,27 +1,7 @@
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
3
  // STDIO transport from tools package
5
4
  import { AxMCPStdioTransport } from '@ax-llm/ax-tools';
6
- import { PROVIDER_API_KEYS } from '../config/index.js';
7
- // Canonical provider slugs supported by ai() factory
8
- const PROVIDER_CANONICAL = new Set([
9
- 'openai',
10
- 'anthropic',
11
- 'google-gemini',
12
- 'mistral',
13
- 'groq',
14
- 'cohere',
15
- 'together',
16
- 'deepseek',
17
- 'ollama',
18
- 'huggingface',
19
- 'openrouter',
20
- 'azure-openai',
21
- 'reka',
22
- 'x-grok'
23
- ]);
24
- // Provider type lives in src/types.ts
25
5
  // Type guard to check if config is stdio transport
26
6
  export function isStdioTransport(config) {
27
7
  return 'command' in config;
@@ -44,48 +24,7 @@ export function isStreambleHTTPTransport(config) {
44
24
  function isConstructor(func) {
45
25
  return typeof func === 'function' && 'prototype' in func && 'toFunction' in func.prototype;
46
26
  }
47
- /**
48
- * Provides a user-friendly error message for JSON parsing errors
49
- */
50
- const getFormattedJSONError = (error, fileContents) => {
51
- if (error instanceof SyntaxError) {
52
- const match = error.message.match(/position (\d+)/);
53
- const position = match ? parseInt(match[1]) : -1;
54
- if (position !== -1) {
55
- const lines = fileContents.split('\n');
56
- let currentPos = 0;
57
- let errorLine = 0;
58
- let errorColumn = 0;
59
- // Find the line and column of the error
60
- for (let i = 0; i < lines.length; i++) {
61
- if (currentPos + lines[i].length >= position) {
62
- errorLine = i + 1;
63
- errorColumn = position - currentPos + 1;
64
- break;
65
- }
66
- currentPos += lines[i].length + 1; // +1 for the newline character
67
- }
68
- const contextLines = lines.slice(Math.max(0, errorLine - 3), errorLine + 2)
69
- .map((line, idx) => `${errorLine - 2 + idx}: ${line}`).join('\n');
70
- return `JSON Parse Error in your agent configuration:
71
-
72
- Error near line ${errorLine}, column ${errorColumn}
73
-
74
- Context:
75
- ${contextLines}
76
-
77
- Common issues to check:
78
- - Missing or extra commas between properties
79
- - Missing quotes around property names
80
- - Unmatched brackets or braces
81
- - Invalid JSON values
82
- - Trailing commas (not allowed in JSON)
83
-
84
- Original error: ${error.message}`;
85
- }
86
- }
87
- return `Error parsing agent configuration: ${error.message}`;
88
- };
27
+ // Removed file/JSON parse helpers to keep browser-safe
89
28
  const initializeMCPServers = async (agentConfigData) => {
90
29
  const mcpServers = agentConfigData.mcpServers;
91
30
  if (!mcpServers || Object.keys(mcpServers).length === 0) {
@@ -126,41 +65,23 @@ const initializeMCPServers = async (agentConfigData) => {
126
65
  }
127
66
  };
128
67
  /**
129
- * Parses and returns the AxCrew config from either a JSON config file or a direct JSON object.
130
- * @param {CrewConfigInput} input - Either a path to the agent config json file or a JSON object with crew configuration.
68
+ * Returns the AxCrew config from a direct JSON object. Browser-safe.
69
+ * @param {CrewConfig} input - A JSON object with crew configuration.
131
70
  * @returns {Object} The parsed crew config.
132
71
  * @throws Will throw an error if reading/parsing fails.
133
72
  */
134
73
  const parseCrewConfig = (input) => {
135
- try {
136
- if (typeof input === 'string') {
137
- // Handle file path input
138
- const fileContents = fs.readFileSync(input, 'utf8');
139
- const parsedConfig = JSON.parse(fileContents);
140
- return parsedConfig;
141
- }
142
- else {
143
- // Handle direct JSON object input
144
- return input;
145
- }
146
- }
147
- catch (e) {
148
- if (e instanceof Error) {
149
- if (typeof input === 'string') {
150
- const formattedError = getFormattedJSONError(e, fs.readFileSync(input, 'utf8'));
151
- throw new Error(formattedError);
152
- }
153
- throw new Error(`Error parsing agent configuration: ${e.message}`);
154
- }
155
- throw e;
74
+ if (!input || typeof input !== 'object' || !Array.isArray(input.crew)) {
75
+ throw new Error('Invalid crew configuration: expected an object with a crew array');
156
76
  }
77
+ return input;
157
78
  };
158
79
  /**
159
80
  * Parses the agent's configuration, validates the presence of the necessary API key,
160
81
  * and creates an instance of the Agent with the appropriate settings.
161
82
  *
162
83
  * @param {string} agentName - The identifier for the AI agent to be initialized.
163
- * @param {CrewConfigInput} crewConfig - Either a file path to the JSON configuration or a JSON object with crew configuration.
84
+ * @param {AxCrewConfig} crewConfig - A JSON object with crew configuration.
164
85
  * @param {FunctionRegistryType} functions - The functions available to the agent.
165
86
  * @param {Object} state - The state object for the agent.
166
87
  * @returns {Object} An object containing the Agents AI instance, its name, description, signature, functions and subAgentList.
@@ -174,18 +95,16 @@ const parseAgentConfig = async (agentName, crewConfig, functions, state) => {
174
95
  if (!agentConfigData) {
175
96
  throw new Error(`AI agent with name ${agentName} is not configured`);
176
97
  }
177
- // Enforce canonical provider slug
178
- const lower = agentConfigData.provider.toLowerCase();
179
- if (!PROVIDER_CANONICAL.has(lower)) {
180
- throw new Error(`AI provider ${agentConfigData.provider} is not supported. Use one of: ${Array.from(PROVIDER_CANONICAL).join(', ')}`);
181
- }
98
+ // Normalize provider slug to lowercase and validate via Ax factory
99
+ const lower = String(agentConfigData.provider).toLowerCase();
182
100
  const provider = lower;
183
- // If an API Key property is present, get the API key for the AI agent from the environment variables
101
+ // Resolve API key from user-supplied environment variable name
184
102
  let apiKey = '';
185
103
  if (agentConfigData.providerKeyName) {
186
- apiKey = PROVIDER_API_KEYS[agentConfigData.providerKeyName] || '';
104
+ const keyName = agentConfigData.providerKeyName;
105
+ apiKey = resolveApiKey(keyName) || '';
187
106
  if (!apiKey) {
188
- throw new Error(`API key for provider ${agentConfigData.provider} is not set in environment variables`);
107
+ throw new Error(`API key '${keyName}' for provider ${agentConfigData.provider} is not set in environment`);
189
108
  }
190
109
  }
191
110
  else {
@@ -214,7 +133,20 @@ const parseAgentConfig = async (agentName, crewConfig, functions, state) => {
214
133
  throw new Error(`Invalid apiURL provided: ${agentConfigData.apiURL}`);
215
134
  }
216
135
  }
217
- const aiInstance = ai(aiArgs);
136
+ // Forward provider-specific arguments as-is; let Ax validate/ignore as needed
137
+ const providerArgs = agentConfigData.providerArgs;
138
+ if (providerArgs && typeof providerArgs === 'object') {
139
+ Object.assign(aiArgs, providerArgs);
140
+ }
141
+ // Validate provider by attempting instantiation; Ax will throw on unknown providers
142
+ let aiInstance;
143
+ try {
144
+ aiInstance = ai(aiArgs);
145
+ }
146
+ catch (e) {
147
+ const msg = e instanceof Error ? e.message : String(e);
148
+ throw new Error(`Unsupported provider '${provider}': ${msg}`);
149
+ }
218
150
  // If an mcpServers config is provided in the agent config, convert to functions
219
151
  const mcpFunctions = await initializeMCPServers(agentConfigData);
220
152
  // Prepare functions for the AI agent
@@ -254,3 +186,20 @@ const parseAgentConfig = async (agentName, crewConfig, functions, state) => {
254
186
  }
255
187
  };
256
188
  export { parseAgentConfig, parseCrewConfig };
189
+ function resolveApiKey(varName) {
190
+ try {
191
+ // Prefer Node env when available
192
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
193
+ // @ts-ignore
194
+ if (typeof process !== 'undefined' && process?.env) {
195
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
196
+ // @ts-ignore
197
+ return process.env[varName];
198
+ }
199
+ // Fallback: allow global exposure in browser builds (e.g., injected at runtime)
200
+ return globalThis?.[varName];
201
+ }
202
+ catch {
203
+ return undefined;
204
+ }
205
+ }
@@ -5,8 +5,22 @@ import type { StateInstance, ModelUsage, ModelInfo, UsageCost, AggregatedCosts }
5
5
  */
6
6
  export declare class StateFulAxAgentUsage {
7
7
  static STATE_KEY_PREFIX: string;
8
+ /**
9
+ * Compute usage costs given a model usage record and model pricing info.
10
+ * Returns null if inputs are invalid. Token-based costs are computed with high precision.
11
+ */
8
12
  static calculateCost(modelUsage: ModelUsage, modelInfo: ModelInfo): UsageCost | null;
13
+ /**
14
+ * Persist or aggregate the cost for an agent in the shared crew state.
15
+ * No-op if cost is null.
16
+ */
9
17
  static trackCostInState(agentName: string, cost: UsageCost | null, state: StateInstance): void;
18
+ /**
19
+ * Aggregate and return total costs across all agents from the shared crew state.
20
+ */
10
21
  static getAggregatedCosts(state: StateInstance): AggregatedCosts;
22
+ /**
23
+ * Remove all stored per-agent costs from the shared crew state.
24
+ */
11
25
  static resetCosts(state: StateInstance): void;
12
26
  }
@@ -5,6 +5,10 @@ import { Decimal } from 'decimal.js';
5
5
  */
6
6
  export class StateFulAxAgentUsage {
7
7
  static STATE_KEY_PREFIX = 'agent_usage_';
8
+ /**
9
+ * Compute usage costs given a model usage record and model pricing info.
10
+ * Returns null if inputs are invalid. Token-based costs are computed with high precision.
11
+ */
8
12
  static calculateCost(modelUsage, modelInfo) {
9
13
  // Handle both direct properties and nested tokens structure
10
14
  const promptTokens = modelUsage.tokens?.promptTokens ?? modelUsage.promptTokens;
@@ -44,6 +48,10 @@ export class StateFulAxAgentUsage {
44
48
  return null;
45
49
  }
46
50
  }
51
+ /**
52
+ * Persist or aggregate the cost for an agent in the shared crew state.
53
+ * No-op if cost is null.
54
+ */
47
55
  static trackCostInState(agentName, cost, state) {
48
56
  // If cost is null, skip tracking
49
57
  if (!cost)
@@ -75,6 +83,9 @@ export class StateFulAxAgentUsage {
75
83
  state.set(stateKey, cost);
76
84
  }
77
85
  }
86
+ /**
87
+ * Aggregate and return total costs across all agents from the shared crew state.
88
+ */
78
89
  static getAggregatedCosts(state) {
79
90
  const allState = state.getAll();
80
91
  const agentCosts = {};
@@ -108,6 +119,9 @@ export class StateFulAxAgentUsage {
108
119
  }
109
120
  };
110
121
  }
122
+ /**
123
+ * Remove all stored per-agent costs from the shared crew state.
124
+ */
111
125
  static resetCosts(state) {
112
126
  const allState = state.getAll();
113
127
  Object.keys(allState).forEach(key => {
@@ -0,0 +1,15 @@
1
+ import type { AxAI } from '@ax-llm/ax';
2
+ import type { AxCrewConfig } from '../types.js';
3
+ type BuildProviderArgs = {
4
+ provider: string;
5
+ apiKey: string;
6
+ config: any;
7
+ apiURL?: string;
8
+ providerArgs?: Record<string, unknown>;
9
+ options?: Record<string, unknown>;
10
+ };
11
+ export declare function instantiateProvider({ provider, apiKey, config, apiURL, providerArgs, options, }: BuildProviderArgs): AxAI<any>;
12
+ export declare function buildProvidersFromConfig(cfg: AxCrewConfig): AxAI<any>[];
13
+ export declare function discoverProvidersFromConfig(cfg: AxCrewConfig): string[];
14
+ export declare function listSelectableProviders(cfg: AxCrewConfig): string[];
15
+ export {};
@@ -0,0 +1,58 @@
1
+ import { ai } from '@ax-llm/ax';
2
+ export function instantiateProvider({ provider, apiKey, config, apiURL, providerArgs, options, }) {
3
+ const args = { name: provider, apiKey, config, options };
4
+ if (apiURL)
5
+ args.apiURL = apiURL;
6
+ if (providerArgs && typeof providerArgs === 'object')
7
+ Object.assign(args, providerArgs);
8
+ return ai(args);
9
+ }
10
+ export function buildProvidersFromConfig(cfg) {
11
+ const services = [];
12
+ for (const agent of cfg.crew) {
13
+ const apiKeyName = agent.providerKeyName;
14
+ if (!apiKeyName)
15
+ throw new Error(`Provider key name is missing for agent ${agent.name}`);
16
+ const apiKey = resolveApiKey(apiKeyName) || '';
17
+ if (!apiKey)
18
+ throw new Error(`API key '${apiKeyName}' not set for agent ${agent.name}`);
19
+ const service = instantiateProvider({
20
+ provider: String(agent.provider).toLowerCase(),
21
+ apiKey,
22
+ config: agent.ai,
23
+ apiURL: agent.apiURL,
24
+ providerArgs: agent.providerArgs,
25
+ options: agent.options,
26
+ });
27
+ services.push(service);
28
+ }
29
+ return services;
30
+ }
31
+ // Provider discovery helpers consolidated here (previously in src/providers.ts)
32
+ export function discoverProvidersFromConfig(cfg) {
33
+ const providers = new Set();
34
+ for (const agent of cfg.crew) {
35
+ providers.add(String(agent.provider).toLowerCase());
36
+ }
37
+ return Array.from(providers);
38
+ }
39
+ export function listSelectableProviders(cfg) {
40
+ return discoverProvidersFromConfig(cfg);
41
+ }
42
+ function resolveApiKey(varName) {
43
+ try {
44
+ // Prefer Node env when available
45
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
46
+ // @ts-ignore
47
+ if (typeof process !== 'undefined' && process?.env) {
48
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
49
+ // @ts-ignore
50
+ return process.env[varName];
51
+ }
52
+ // Fallback: allow global exposure in browser builds (e.g., injected at runtime)
53
+ return globalThis?.[varName];
54
+ }
55
+ catch {
56
+ return undefined;
57
+ }
58
+ }
@@ -1,6 +1,6 @@
1
1
  import { AxAgent, AxAI } from "@ax-llm/ax";
2
2
  import type { AxSignature, AxAgentic, AxFunction, AxProgramForwardOptions, AxProgramStreamingForwardOptions, AxGenStreamingOut } from "@ax-llm/ax";
3
- import type { StateInstance, FunctionRegistryType, UsageCost, CrewConfigInput, MCPTransportConfig } from "../types.js";
3
+ import type { StateInstance, FunctionRegistryType, UsageCost, AxCrewConfig, MCPTransportConfig } from "../types.js";
4
4
  declare class StatefulAxAgent extends AxAgent<any, any> {
5
5
  state: StateInstance;
6
6
  axai: any;
@@ -25,11 +25,37 @@ declare class StatefulAxAgent extends AxAgent<any, any> {
25
25
  streamingForward(ai: AxAI, values: Record<string, any>, options?: Readonly<AxProgramStreamingForwardOptions<any>>): AxGenStreamingOut<any>;
26
26
  getLastUsageCost(): UsageCost | null;
27
27
  getAccumulatedCosts(): UsageCost | null;
28
+ /**
29
+ * Get the current metrics snapshot for this agent.
30
+ * Includes request counts, error rates, token usage, estimated USD cost, and function call stats.
31
+ *
32
+ * @returns A metrics snapshot scoped to this agent within its crew.
33
+ */
28
34
  getMetrics(): import("../metrics/types.js").MetricsSnapshot;
35
+ /**
36
+ * Reset all tracked metrics for this agent (does not affect other agents).
37
+ * Call this to start fresh measurement windows for the agent.
38
+ */
29
39
  resetMetrics(): void;
30
40
  }
31
41
  /**
32
- * Represents a crew of agents with shared state functionality.
42
+ * AxCrew orchestrates a set of Ax agents that share state,
43
+ * tools (functions), optional MCP servers, streaming, and a built-in metrics
44
+ * registry for tokens, requests, and estimated cost.
45
+ *
46
+ * Typical usage:
47
+ * const crew = new AxCrew(config, AxCrewFunctions)
48
+ * await crew.addAllAgents()
49
+ * const planner = crew.agents?.get("Planner")
50
+ * const res = await planner?.forward({ task: "Plan something" })
51
+ *
52
+ * Key behaviors:
53
+ * - Validates and instantiates agents from a config-first model
54
+ * - Shares a mutable state object across all agents in the crew
55
+ * - Supports sub-agents and a function registry per agent
56
+ * - Tracks per-agent and crew-level metrics via MetricsRegistry
57
+ * - Provides helpers to add agents (individually, a subset, or all) and
58
+ * to reset metrics/costs when needed
33
59
  */
34
60
  declare class AxCrew {
35
61
  private crewConfig;
@@ -39,11 +65,11 @@ declare class AxCrew {
39
65
  state: StateInstance;
40
66
  /**
41
67
  * Creates an instance of AxCrew.
42
- * @param {CrewConfigInput} crewConfig - Either a path to the agent config file or a JSON object with crew configuration.
68
+ * @param {AxCrewConfig} crewConfig - JSON object with crew configuration.
43
69
  * @param {FunctionRegistryType} [functionsRegistry={}] - The registry of functions to use in the crew.
44
70
  * @param {string} [crewId=uuidv4()] - The unique identifier for the crew.
45
71
  */
46
- constructor(crewConfig: CrewConfigInput, functionsRegistry?: FunctionRegistryType, crewId?: string);
72
+ constructor(crewConfig: AxCrewConfig, functionsRegistry?: FunctionRegistryType, crewId?: string);
47
73
  /**
48
74
  * Factory function for creating an agent.
49
75
  * @param {string} agentName - The name of the agent to create.
@@ -70,10 +96,21 @@ declare class AxCrew {
70
96
  */
71
97
  destroy(): void;
72
98
  /**
73
- * Resets all cost tracking for the crew
99
+ * Resets all cost and usage tracking for the entire crew.
100
+ * Also calls each agent's `resetUsage` (if available) and clears crew-level metrics.
74
101
  */
75
102
  resetCosts(): void;
103
+ /**
104
+ * Get an aggregate metrics snapshot for the entire crew.
105
+ * Sums requests, errors, tokens, and estimated cost across all agents in the crew.
106
+ *
107
+ * @returns Crew-level metrics snapshot.
108
+ */
76
109
  getCrewMetrics(): import("../metrics/types.js").MetricsSnapshot;
110
+ /**
111
+ * Reset all tracked metrics for the entire crew.
112
+ * Use to clear totals before a new measurement period.
113
+ */
77
114
  resetCrewMetrics(): void;
78
115
  }
79
116
  export { AxCrew };