@amitdeshmukh/ax-crew 2.0.7 → 3.1.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 +25 -4
- package/README.md +51 -7
- package/agentConfig.json +65 -0
- package/axllm.js +66 -0
- package/dist/agents/agentConfig.js +88 -32
- package/dist/agents/index.js +21 -11
- package/package.json +3 -3
- package/src/agents/agentConfig.ts +97 -37
- package/src/agents/index.ts +21 -12
- package/test.js +18 -53
- package/test1.js +98 -0
- package/agent_config.example.yaml +0 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
This Changelog format is based on [Keep a Changelog]
|
|
3
|
+
This Changelog format is based on [Keep a Changelog]
|
|
4
|
+
(https://keepachangelog.com/en/1.0.0/), and this project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/
|
|
6
|
+
v2.0.0.html).
|
|
4
7
|
|
|
5
|
-
## [
|
|
8
|
+
## [3.1.0] - 2024-12-10
|
|
6
9
|
|
|
7
10
|
### Added
|
|
8
|
-
-
|
|
9
|
-
-
|
|
11
|
+
- Support for direct JSON object configuration in addition to configuration files
|
|
12
|
+
- New configuration option to pass agent configuration as a JavaScript object
|
|
13
|
+
- Updated documentation in README.md with examples of both configuration methods
|
|
14
|
+
|
|
15
|
+
### Enhanced
|
|
16
|
+
- Configuration flexibility allowing runtime configuration modifications
|
|
17
|
+
- Support for dynamic agent configuration generation
|
|
18
|
+
|
|
19
|
+
## [3.0.0] - 2024-12-10
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Switched from YAML to JSON format for agent configuration files
|
|
23
|
+
- Renamed `provider_key_name` to `providerKeyName` in agent configuration to align with JSON naming conventions
|
|
24
|
+
- Improved error handling for JSON parsing with detailed error message and troubleshooting hints
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
- Better error messages for configuration file parsing issues, including:
|
|
28
|
+
- Exact line and column numbers for JSON syntax errors
|
|
29
|
+
- Context showing surrounding lines of code
|
|
30
|
+
- Common troubleshooting tips for JSON configuration issues
|
|
10
31
|
|
|
11
32
|
## [2.0.7] - 2024-11-23
|
|
12
33
|
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
This repo simplifies development of [AxLLM](https://axllm.dev) AI Agents by using config to instantiate agents. This means you can write a library of functions, and quickly invoke AI agents to use them using a simple configuration file.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
|
-
- **Crew Configuration**: Define a crew of agents in a
|
|
8
|
+
- **Crew Configuration**: Define a crew of agents in a JSON file. (see [agentConfig.json](agentConfig.json) as an example)
|
|
9
9
|
- **State Management**: Share state across agents in a crew, as well as with functions used by those agents.
|
|
10
10
|
- **Task Execution**: Plan and execute tasks using agents in the crew.
|
|
11
11
|
|
|
@@ -28,21 +28,65 @@ Refer to the [.env.example](.env.example) file for the required environment vari
|
|
|
28
28
|
## Usage
|
|
29
29
|
|
|
30
30
|
### Initializing a Crew
|
|
31
|
-
A Crew is a team of agents that work together to achieve a common goal.
|
|
31
|
+
A Crew is a team of agents that work together to achieve a common goal. You can configure your crew in two ways:
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
1. Using a JSON configuration file that defines the agents in the crew, along with their individual configurations.
|
|
34
|
+
2. Directly passing a JSON object with the crew configuration.
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
#### Using a Configuration File
|
|
37
|
+
See [agentConfig.json](agentConfig.json) for an example configuration file.
|
|
36
38
|
|
|
37
39
|
```javascript
|
|
38
40
|
// Import the AxCrew class
|
|
39
41
|
import { AxCrew } from '@amitdeshmukh/ax-crew';
|
|
40
42
|
|
|
41
|
-
// Create a new instance of AxCrew
|
|
42
|
-
const configFilePath = './
|
|
43
|
+
// Create a new instance of AxCrew using a config file
|
|
44
|
+
const configFilePath = './agentConfig.json';
|
|
43
45
|
const crew = new AxCrew(configFilePath);
|
|
44
46
|
```
|
|
45
47
|
|
|
48
|
+
#### Using a Direct Configuration Object
|
|
49
|
+
You can also pass the configuration directly as a JSON object:
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
// Import the AxCrew class
|
|
53
|
+
import { AxCrew } from '@amitdeshmukh/ax-crew';
|
|
54
|
+
|
|
55
|
+
// Create the configuration object
|
|
56
|
+
const config = {
|
|
57
|
+
crew: [
|
|
58
|
+
{
|
|
59
|
+
name: "Planner",
|
|
60
|
+
description: "Creates a plan to complete a task",
|
|
61
|
+
signature: "task:string \"a task to be completed\" -> plan:string \"a plan to execute the task in 5 steps or less\"",
|
|
62
|
+
provider: "google-gemini",
|
|
63
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
64
|
+
ai: {
|
|
65
|
+
model: "gemini-1.5-flash",
|
|
66
|
+
temperature: 0
|
|
67
|
+
},
|
|
68
|
+
options: {
|
|
69
|
+
debug: false
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// ... more agents
|
|
73
|
+
]
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Create a new instance of AxCrew using the config object
|
|
77
|
+
const crew = new AxCrew(config);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Both methods support the same configuration structure and options. Choose the one that best fits your use case:
|
|
81
|
+
- Use a configuration file when you want to:
|
|
82
|
+
- Keep your configuration separate from your code
|
|
83
|
+
- Share configurations across different projects
|
|
84
|
+
- Version control your configurations
|
|
85
|
+
- Use a direct configuration object when you want to:
|
|
86
|
+
- Generate configurations dynamically
|
|
87
|
+
- Modify configurations at runtime
|
|
88
|
+
- Keep everything in one file for simpler projects
|
|
89
|
+
|
|
46
90
|
### Function Registry
|
|
47
91
|
Functions (aka Tools) are the building blocks of agents. They are used to perform specific tasks, such as calling external APIs, databases, or other services.
|
|
48
92
|
|
|
@@ -122,7 +166,7 @@ An example of how to complete a task using the agents is shown below. The `Plann
|
|
|
122
166
|
import { AxCrew, AxCrewFunctions } from '@amitdeshmukh/ax-crew';
|
|
123
167
|
|
|
124
168
|
// Create a new instance of AxCrew
|
|
125
|
-
const crew = new AxCrew('./
|
|
169
|
+
const crew = new AxCrew('./agentConfig.json', AxCrewFunctions);
|
|
126
170
|
crew.addAgentsToCrew(['Planner', 'Calculator', 'Manager']);
|
|
127
171
|
|
|
128
172
|
// Get agent instances
|
package/agentConfig.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"crew": [
|
|
3
|
+
{
|
|
4
|
+
"name": "Planner",
|
|
5
|
+
"description": "Creates a plan to complete a task",
|
|
6
|
+
"signature": "task:string \"a task to be completed\" -> plan:string \"a plan to execute the task in 5 steps or less\"",
|
|
7
|
+
"provider": "google-gemini",
|
|
8
|
+
"providerKeyName": "GEMINI_API_KEY",
|
|
9
|
+
"ai": {
|
|
10
|
+
"model": "gemini-1.5-flash",
|
|
11
|
+
"temperature": 0
|
|
12
|
+
},
|
|
13
|
+
"options": {
|
|
14
|
+
"debug": false
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "Calculator",
|
|
19
|
+
"description": "Solves math problems",
|
|
20
|
+
"signature": "mathProblem:string \"a math problem to be solved using Python code\" -> solution:string \"the solution to the math problem\"",
|
|
21
|
+
"provider": "google-gemini",
|
|
22
|
+
"providerKeyName": "GEMINI_API_KEY",
|
|
23
|
+
"ai": {
|
|
24
|
+
"model": "gemini-1.5-pro",
|
|
25
|
+
"temperature": 0
|
|
26
|
+
},
|
|
27
|
+
"options": {
|
|
28
|
+
"debug": true,
|
|
29
|
+
"codeExecution": true
|
|
30
|
+
},
|
|
31
|
+
"functions": ["CurrentDateTime", "DaysBetweenDates"]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "WebSearch",
|
|
35
|
+
"description": "Searches the web for the latest information using Google search",
|
|
36
|
+
"signature": "webSearchQuery:string \"a query for Google search\" -> webSearchResponse:string \"the result of the search\"",
|
|
37
|
+
"provider": "google-gemini",
|
|
38
|
+
"providerKeyName": "GEMINI_API_KEY",
|
|
39
|
+
"ai": {
|
|
40
|
+
"model": "gemini-1.5-pro",
|
|
41
|
+
"temperature": 0
|
|
42
|
+
},
|
|
43
|
+
"options": {
|
|
44
|
+
"debug": true,
|
|
45
|
+
"googleSearchRetrieval": true
|
|
46
|
+
},
|
|
47
|
+
"functions": ["CurrentDateTime", "DaysBetweenDates"]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "Manager",
|
|
51
|
+
"description": "Answers questions from the user",
|
|
52
|
+
"signature": "question:string \"a question from a user\", plan:string \"a suggested plan to answer the question\" -> answer:string \"the answer\"",
|
|
53
|
+
"provider": "openai",
|
|
54
|
+
"providerKeyName": "OPENAI_API_KEY",
|
|
55
|
+
"ai": {
|
|
56
|
+
"model": "gpt-4o-mini",
|
|
57
|
+
"temperature": 0
|
|
58
|
+
},
|
|
59
|
+
"options": {
|
|
60
|
+
"debug": true
|
|
61
|
+
},
|
|
62
|
+
"functions": ["CurrentDateTime", "DaysBetweenDates"]
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
package/axllm.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { AxAgent, AxAI } from "@ax-llm/ax";
|
|
2
|
+
import dotenv from "dotenv";
|
|
3
|
+
dotenv.config();
|
|
4
|
+
|
|
5
|
+
const googleAI = new AxAI({
|
|
6
|
+
name: "google-gemini",
|
|
7
|
+
apiKey: process.env.GEMINI_API_KEY,
|
|
8
|
+
config: {
|
|
9
|
+
model: "gemini-1.5-pro",
|
|
10
|
+
temperature: 0,
|
|
11
|
+
},
|
|
12
|
+
options: {
|
|
13
|
+
debug: true,
|
|
14
|
+
codeExecution: true,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const openAI = new AxAI({
|
|
19
|
+
name: "openai",
|
|
20
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
21
|
+
config: {
|
|
22
|
+
model: "gpt-4-turbo",
|
|
23
|
+
maxTokens: 1000,
|
|
24
|
+
temperature: 0,
|
|
25
|
+
},
|
|
26
|
+
options: { debug: true },
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const MathAgent = new AxAgent({
|
|
30
|
+
name: "MathAgent",
|
|
31
|
+
description: "Solves math problems",
|
|
32
|
+
signature: `mathProblem:string "a sentence describing a math problem to be solved using Python code" -> solution:string "a precise answer to the math problem"`,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const ManagerAgent = new AxAgent({
|
|
36
|
+
name: "ManagerAgent",
|
|
37
|
+
description: "Completes a user specified task.",
|
|
38
|
+
signature: `question:string "a question to be answered" -> answer:string "the answer to the question"`,
|
|
39
|
+
agents: [MathAgent],
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const userQuery =
|
|
43
|
+
"who is considered as the father of the iphone and what is the 7th root of their year of birth";
|
|
44
|
+
console.log(`\n\nQuestion: ${userQuery}`);
|
|
45
|
+
|
|
46
|
+
const managerAgentResponse = await ManagerAgent.forward(
|
|
47
|
+
openAI,
|
|
48
|
+
{
|
|
49
|
+
question: userQuery,
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
console.log(`\nManagerAgentResponse: ${JSON.stringify(managerAgentResponse, null, 2)}\n`);
|
|
54
|
+
|
|
55
|
+
console.log("❌ This is the wrong answer ☝️");
|
|
56
|
+
|
|
57
|
+
const MathAgentResponse = await MathAgent.forward(
|
|
58
|
+
googleAI,
|
|
59
|
+
{
|
|
60
|
+
mathProblem: userQuery
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
console.log(`\nMathAgentResponse: ${JSON.stringify(MathAgentResponse, null, 2)}\n`);
|
|
65
|
+
console.log(" ✅ Correct answer ☝️");
|
|
66
|
+
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import yaml from 'js-yaml';
|
|
3
2
|
import { AxAIAnthropic, AxAIOpenAI, AxAIAzureOpenAI, AxAICohere, AxAIDeepSeek, AxAIGoogleGemini, AxAIGroq, AxAIHuggingFace, AxAIMistral, AxAIOllama, AxAITogether } from '@ax-llm/ax';
|
|
4
3
|
import { PROVIDER_API_KEYS } from '../config/index.js';
|
|
5
4
|
// Define a mapping from provider names to their respective constructors
|
|
@@ -27,53 +26,108 @@ function isConstructor(func) {
|
|
|
27
26
|
return typeof func === 'function' && 'prototype' in func && 'toFunction' in func.prototype;
|
|
28
27
|
}
|
|
29
28
|
/**
|
|
30
|
-
*
|
|
31
|
-
* @param {string} agentConfigFilePath - The path to the agent_config.yaml file.
|
|
32
|
-
* @returns {Object} The parsed agent configs from the config.yaml file.
|
|
33
|
-
* @throws Will throw an error if reading the file fails.
|
|
29
|
+
* Provides a user-friendly error message for JSON parsing errors
|
|
34
30
|
*/
|
|
35
|
-
const
|
|
31
|
+
const getFormattedJSONError = (error, fileContents) => {
|
|
32
|
+
if (error instanceof SyntaxError) {
|
|
33
|
+
const match = error.message.match(/position (\d+)/);
|
|
34
|
+
const position = match ? parseInt(match[1]) : -1;
|
|
35
|
+
if (position !== -1) {
|
|
36
|
+
const lines = fileContents.split('\n');
|
|
37
|
+
let currentPos = 0;
|
|
38
|
+
let errorLine = 0;
|
|
39
|
+
let errorColumn = 0;
|
|
40
|
+
// Find the line and column of the error
|
|
41
|
+
for (let i = 0; i < lines.length; i++) {
|
|
42
|
+
if (currentPos + lines[i].length >= position) {
|
|
43
|
+
errorLine = i + 1;
|
|
44
|
+
errorColumn = position - currentPos + 1;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
currentPos += lines[i].length + 1; // +1 for the newline character
|
|
48
|
+
}
|
|
49
|
+
const contextLines = lines.slice(Math.max(0, errorLine - 3), errorLine + 2)
|
|
50
|
+
.map((line, idx) => `${errorLine - 2 + idx}: ${line}`).join('\n');
|
|
51
|
+
return `JSON Parse Error in your agent configuration:
|
|
52
|
+
|
|
53
|
+
Error near line ${errorLine}, column ${errorColumn}
|
|
54
|
+
|
|
55
|
+
Context:
|
|
56
|
+
${contextLines}
|
|
57
|
+
|
|
58
|
+
Common issues to check:
|
|
59
|
+
- Missing or extra commas between properties
|
|
60
|
+
- Missing quotes around property names
|
|
61
|
+
- Unmatched brackets or braces
|
|
62
|
+
- Invalid JSON values
|
|
63
|
+
- Trailing commas (not allowed in JSON)
|
|
64
|
+
|
|
65
|
+
Original error: ${error.message}`;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return `Error parsing agent configuration: ${error.message}`;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Reads the AI parameters from either a JSON configuration file or a direct JSON object.
|
|
72
|
+
* @param {AgentConfigInput} input - Either a path to the agent_config.json file or a JSON object with crew configuration.
|
|
73
|
+
* @returns {Object} The parsed agent configs.
|
|
74
|
+
* @throws Will throw an error if reading/parsing fails.
|
|
75
|
+
*/
|
|
76
|
+
const parseAgentConfig = (input) => {
|
|
36
77
|
try {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
78
|
+
if (typeof input === 'string') {
|
|
79
|
+
// Handle file path input
|
|
80
|
+
const fileContents = fs.readFileSync(input, 'utf8');
|
|
81
|
+
const parsedConfigs = JSON.parse(fileContents);
|
|
82
|
+
return parsedConfigs;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Handle direct JSON object input
|
|
86
|
+
return input;
|
|
87
|
+
}
|
|
40
88
|
}
|
|
41
89
|
catch (e) {
|
|
42
|
-
|
|
90
|
+
if (e instanceof Error) {
|
|
91
|
+
if (typeof input === 'string') {
|
|
92
|
+
const formattedError = getFormattedJSONError(e, fs.readFileSync(input, 'utf8'));
|
|
93
|
+
throw new Error(formattedError);
|
|
94
|
+
}
|
|
95
|
+
throw new Error(`Error parsing agent configuration: ${e.message}`);
|
|
96
|
+
}
|
|
43
97
|
throw e;
|
|
44
98
|
}
|
|
45
99
|
};
|
|
46
100
|
/**
|
|
47
|
-
* Initializes the AI agent using the specified agent name and configuration
|
|
101
|
+
* Initializes the AI agent using the specified agent name and configuration.
|
|
48
102
|
* This function parses the agent's configuration, validates the presence of the necessary API key,
|
|
49
103
|
* and creates an instance of the AI agent with the appropriate settings.
|
|
50
104
|
*
|
|
51
105
|
* @param {string} agentName - The identifier for the AI agent to be initialized.
|
|
52
|
-
* @param {
|
|
106
|
+
* @param {AgentConfigInput} agentConfig - Either a file path to the JSON configuration or a JSON object with crew configuration.
|
|
53
107
|
* @param {FunctionRegistryType} functions - The functions available to the agent.
|
|
54
108
|
* @param {Object} state - The state object for the agent.
|
|
55
109
|
* @returns {Object} An object containing the Agents AI instance, its name, description, signature, functions and subAgentList.
|
|
56
110
|
* @throws {Error} Throws an error if the agent configuration is missing, the provider is unsupported,
|
|
57
111
|
* the API key is not found, or the provider key name is not specified in the configuration.
|
|
58
112
|
*/
|
|
59
|
-
const getAgentConfigParams = (agentName,
|
|
113
|
+
const getAgentConfigParams = (agentName, agentConfig, functions, state) => {
|
|
60
114
|
try {
|
|
61
|
-
// Retrieve the parameters for the specified AI agent from
|
|
62
|
-
const
|
|
63
|
-
if (!
|
|
115
|
+
// Retrieve the parameters for the specified AI agent from config
|
|
116
|
+
const agentConfigData = parseAgentConfig(agentConfig).crew.find(agent => agent.name === agentName);
|
|
117
|
+
if (!agentConfigData) {
|
|
64
118
|
throw new Error(`AI agent with name ${agentName} is not configured`);
|
|
65
119
|
}
|
|
66
120
|
// Get the constructor for the AI agent's provider
|
|
67
|
-
const AIConstructor = AIConstructors[
|
|
121
|
+
const AIConstructor = AIConstructors[agentConfigData.provider];
|
|
68
122
|
if (!AIConstructor) {
|
|
69
|
-
throw new Error(`AI provider ${
|
|
123
|
+
throw new Error(`AI provider ${agentConfigData.provider} is not supported. Did you mean '${agentConfigData.provider.toLowerCase()}'?`);
|
|
70
124
|
}
|
|
71
125
|
// If an API Key property is present, get the API key for the AI agent from the environment variables
|
|
72
126
|
let apiKey = '';
|
|
73
|
-
if (
|
|
74
|
-
apiKey = PROVIDER_API_KEYS[
|
|
127
|
+
if (agentConfigData.providerKeyName) {
|
|
128
|
+
apiKey = PROVIDER_API_KEYS[agentConfigData.providerKeyName] || '';
|
|
75
129
|
if (!apiKey) {
|
|
76
|
-
throw new Error(`API key for provider ${
|
|
130
|
+
throw new Error(`API key for provider ${agentConfigData.provider} is not set in environment variables`);
|
|
77
131
|
}
|
|
78
132
|
}
|
|
79
133
|
else {
|
|
@@ -82,19 +136,19 @@ const getAgentConfigParams = (agentName, agentConfigFilePath, functions, state)
|
|
|
82
136
|
// Create an instance of the AI agent
|
|
83
137
|
const ai = new AIConstructor({
|
|
84
138
|
apiKey,
|
|
85
|
-
config:
|
|
139
|
+
config: agentConfigData.ai,
|
|
86
140
|
options: {
|
|
87
|
-
debug:
|
|
141
|
+
debug: agentConfigData.debug || false
|
|
88
142
|
}
|
|
89
143
|
});
|
|
90
144
|
// If an apiURL is provided in the agent config, set it in the AI agent
|
|
91
|
-
if (
|
|
92
|
-
ai.setAPIURL(
|
|
145
|
+
if (agentConfigData.apiURL) {
|
|
146
|
+
ai.setAPIURL(agentConfigData.apiURL);
|
|
93
147
|
}
|
|
94
148
|
// Set all options from the agent configuration
|
|
95
|
-
ai.setOptions({ ...
|
|
149
|
+
ai.setOptions({ ...agentConfigData.options });
|
|
96
150
|
// Prepare functions for the AI agent
|
|
97
|
-
const agentFunctions = (
|
|
151
|
+
const agentFunctions = (agentConfigData.functions || [])
|
|
98
152
|
.map(funcName => {
|
|
99
153
|
const func = functions[funcName];
|
|
100
154
|
if (!func) {
|
|
@@ -113,15 +167,17 @@ const getAgentConfigParams = (agentName, agentConfigFilePath, functions, state)
|
|
|
113
167
|
return {
|
|
114
168
|
ai,
|
|
115
169
|
name: agentName,
|
|
116
|
-
description:
|
|
117
|
-
signature:
|
|
170
|
+
description: agentConfigData.description,
|
|
171
|
+
signature: agentConfigData.signature,
|
|
118
172
|
functions: agentFunctions,
|
|
119
|
-
subAgentNames:
|
|
173
|
+
subAgentNames: agentConfigData.agents || []
|
|
120
174
|
};
|
|
121
175
|
}
|
|
122
176
|
catch (error) {
|
|
123
|
-
|
|
124
|
-
|
|
177
|
+
if (error instanceof Error) {
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
throw new Error(`Error setting up AI agent: ${error}`);
|
|
125
181
|
}
|
|
126
182
|
};
|
|
127
183
|
export { getAgentConfigParams };
|
package/dist/agents/index.js
CHANGED
|
@@ -23,11 +23,11 @@ class StatefulAxAgent extends AxAgent {
|
|
|
23
23
|
class AxCrew {
|
|
24
24
|
/**
|
|
25
25
|
* Creates an instance of AxCrew.
|
|
26
|
-
* @param {
|
|
26
|
+
* @param {AgentConfigInput} agentConfig - Either a path to the agent config file or a JSON object with crew configuration.
|
|
27
27
|
* @param {FunctionRegistryType} [functionsRegistry={}] - The registry of functions to use in the crew.
|
|
28
28
|
* @param {string} [crewId=uuidv4()] - The unique identifier for the crew.
|
|
29
29
|
*/
|
|
30
|
-
constructor(
|
|
30
|
+
constructor(agentConfig, functionsRegistry = {}, crewId = uuidv4()) {
|
|
31
31
|
this.functionsRegistry = {};
|
|
32
32
|
/**
|
|
33
33
|
* Factory function for creating an agent.
|
|
@@ -37,7 +37,7 @@ class AxCrew {
|
|
|
37
37
|
*/
|
|
38
38
|
this.createAgent = (agentName) => {
|
|
39
39
|
try {
|
|
40
|
-
const agentConfigParams = getAgentConfigParams(agentName, this.
|
|
40
|
+
const agentConfigParams = getAgentConfigParams(agentName, this.agentConfig, this.functionsRegistry, this.state);
|
|
41
41
|
// Destructure with type assertion
|
|
42
42
|
const { ai, name, description, signature, functions, subAgentNames } = agentConfigParams;
|
|
43
43
|
// Get subagents for the AI agent
|
|
@@ -58,11 +58,10 @@ class AxCrew {
|
|
|
58
58
|
return agent;
|
|
59
59
|
}
|
|
60
60
|
catch (error) {
|
|
61
|
-
console.error(`Failed to create agent '${agentName}':`, error);
|
|
62
61
|
throw error;
|
|
63
62
|
}
|
|
64
63
|
};
|
|
65
|
-
this.
|
|
64
|
+
this.agentConfig = agentConfig;
|
|
66
65
|
this.functionsRegistry = functionsRegistry;
|
|
67
66
|
this.crewId = crewId;
|
|
68
67
|
this.agents = new Map();
|
|
@@ -73,8 +72,14 @@ class AxCrew {
|
|
|
73
72
|
* @param {string} agentName - The name of the agent to add.
|
|
74
73
|
*/
|
|
75
74
|
addAgent(agentName) {
|
|
76
|
-
|
|
77
|
-
this.agents
|
|
75
|
+
try {
|
|
76
|
+
if (this.agents && !this.agents.has(agentName)) {
|
|
77
|
+
this.agents.set(agentName, this.createAgent(agentName));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error(`Failed to create agent '${agentName}':`);
|
|
82
|
+
throw error;
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
/**
|
|
@@ -85,10 +90,15 @@ class AxCrew {
|
|
|
85
90
|
* @returns {Map<string, StatefulAxAgent> | null} A map of agent names to their corresponding instances.
|
|
86
91
|
*/
|
|
87
92
|
addAgentsToCrew(agentNames) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
try {
|
|
94
|
+
agentNames.forEach((agentName) => {
|
|
95
|
+
this.addAgent(agentName);
|
|
96
|
+
});
|
|
97
|
+
return this.agents;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
92
102
|
}
|
|
93
103
|
/**
|
|
94
104
|
* Cleans up the crew by dereferencing agents and resetting the state.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@amitdeshmukh/ax-crew",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.1.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
|
"engines": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"uuid": "^10.0.0"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
|
-
"@ax-llm/ax": "^10.0.
|
|
21
|
+
"@ax-llm/ax": "^10.0.9"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/js-yaml": "^4.0.9",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
},
|
|
34
34
|
"bugs": {
|
|
35
35
|
"url": "https://github.com/amitdeshmukh/ax-crew/issues"
|
|
36
|
-
},
|
|
36
|
+
},
|
|
37
37
|
"license": "MIT"
|
|
38
38
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import yaml from 'js-yaml';
|
|
3
|
-
|
|
4
2
|
import { AxAIAnthropic, AxAIOpenAI, AxAIAzureOpenAI, AxAICohere, AxAIDeepSeek, AxAIGoogleGemini, AxAIGroq, AxAIHuggingFace, AxAIMistral, AxAIOllama, AxAITogether } from '@ax-llm/ax';
|
|
5
3
|
import type { AxModelConfig, AxFunction, AxSignature } from '@ax-llm/ax';
|
|
6
4
|
|
|
@@ -31,7 +29,7 @@ interface AgentConfig {
|
|
|
31
29
|
description: string;
|
|
32
30
|
signature: AxSignature;
|
|
33
31
|
provider: string;
|
|
34
|
-
|
|
32
|
+
providerKeyName?: string;
|
|
35
33
|
ai: ExtendedAxModelConfig;
|
|
36
34
|
debug?: boolean;
|
|
37
35
|
apiURL?: string;
|
|
@@ -51,31 +49,92 @@ function isConstructor<T>(func: any): func is { new (...args: any[]): T } {
|
|
|
51
49
|
return typeof func === 'function' && 'prototype' in func && 'toFunction' in func.prototype;
|
|
52
50
|
}
|
|
53
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Provides a user-friendly error message for JSON parsing errors
|
|
54
|
+
*/
|
|
55
|
+
const getFormattedJSONError = (error: Error, fileContents: string): string => {
|
|
56
|
+
if (error instanceof SyntaxError) {
|
|
57
|
+
const match = error.message.match(/position (\d+)/);
|
|
58
|
+
const position = match ? parseInt(match[1]) : -1;
|
|
59
|
+
|
|
60
|
+
if (position !== -1) {
|
|
61
|
+
const lines = fileContents.split('\n');
|
|
62
|
+
let currentPos = 0;
|
|
63
|
+
let errorLine = 0;
|
|
64
|
+
let errorColumn = 0;
|
|
65
|
+
|
|
66
|
+
// Find the line and column of the error
|
|
67
|
+
for (let i = 0; i < lines.length; i++) {
|
|
68
|
+
if (currentPos + lines[i].length >= position) {
|
|
69
|
+
errorLine = i + 1;
|
|
70
|
+
errorColumn = position - currentPos + 1;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
currentPos += lines[i].length + 1; // +1 for the newline character
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const contextLines = lines.slice(Math.max(0, errorLine - 3), errorLine + 2)
|
|
77
|
+
.map((line, idx) => `${errorLine - 2 + idx}: ${line}`).join('\n');
|
|
78
|
+
|
|
79
|
+
return `JSON Parse Error in your agent configuration:
|
|
80
|
+
|
|
81
|
+
Error near line ${errorLine}, column ${errorColumn}
|
|
82
|
+
|
|
83
|
+
Context:
|
|
84
|
+
${contextLines}
|
|
85
|
+
|
|
86
|
+
Common issues to check:
|
|
87
|
+
- Missing or extra commas between properties
|
|
88
|
+
- Missing quotes around property names
|
|
89
|
+
- Unmatched brackets or braces
|
|
90
|
+
- Invalid JSON values
|
|
91
|
+
- Trailing commas (not allowed in JSON)
|
|
92
|
+
|
|
93
|
+
Original error: ${error.message}`;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return `Error parsing agent configuration: ${error.message}`;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
type AgentConfigInput = string | { crew: AgentConfig[] };
|
|
54
101
|
|
|
55
102
|
/**
|
|
56
|
-
* Reads the AI parameters from
|
|
57
|
-
* @param {
|
|
58
|
-
* @returns {Object} The parsed agent configs
|
|
59
|
-
* @throws Will throw an error if reading
|
|
103
|
+
* Reads the AI parameters from either a JSON configuration file or a direct JSON object.
|
|
104
|
+
* @param {AgentConfigInput} input - Either a path to the agent_config.json file or a JSON object with crew configuration.
|
|
105
|
+
* @returns {Object} The parsed agent configs.
|
|
106
|
+
* @throws Will throw an error if reading/parsing fails.
|
|
60
107
|
*/
|
|
61
|
-
const parseAgentConfig = (
|
|
108
|
+
const parseAgentConfig = (input: AgentConfigInput): { crew: AgentConfig[] } => {
|
|
62
109
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
110
|
+
if (typeof input === 'string') {
|
|
111
|
+
// Handle file path input
|
|
112
|
+
const fileContents = fs.readFileSync(input, 'utf8');
|
|
113
|
+
const parsedConfigs = JSON.parse(fileContents) as { crew: AgentConfig[] };
|
|
114
|
+
return parsedConfigs;
|
|
115
|
+
} else {
|
|
116
|
+
// Handle direct JSON object input
|
|
117
|
+
return input;
|
|
118
|
+
}
|
|
66
119
|
} catch (e) {
|
|
67
|
-
|
|
120
|
+
if (e instanceof Error) {
|
|
121
|
+
if (typeof input === 'string') {
|
|
122
|
+
const formattedError = getFormattedJSONError(e, fs.readFileSync(input, 'utf8'));
|
|
123
|
+
throw new Error(formattedError);
|
|
124
|
+
}
|
|
125
|
+
throw new Error(`Error parsing agent configuration: ${e.message}`);
|
|
126
|
+
}
|
|
68
127
|
throw e;
|
|
69
128
|
}
|
|
70
129
|
};
|
|
71
130
|
|
|
72
131
|
/**
|
|
73
|
-
* Initializes the AI agent using the specified agent name and configuration
|
|
132
|
+
* Initializes the AI agent using the specified agent name and configuration.
|
|
74
133
|
* This function parses the agent's configuration, validates the presence of the necessary API key,
|
|
75
134
|
* and creates an instance of the AI agent with the appropriate settings.
|
|
76
135
|
*
|
|
77
136
|
* @param {string} agentName - The identifier for the AI agent to be initialized.
|
|
78
|
-
* @param {
|
|
137
|
+
* @param {AgentConfigInput} agentConfig - Either a file path to the JSON configuration or a JSON object with crew configuration.
|
|
79
138
|
* @param {FunctionRegistryType} functions - The functions available to the agent.
|
|
80
139
|
* @param {Object} state - The state object for the agent.
|
|
81
140
|
* @returns {Object} An object containing the Agents AI instance, its name, description, signature, functions and subAgentList.
|
|
@@ -84,30 +143,30 @@ const parseAgentConfig = (agentConfigFilePath: string): {crew: AgentConfig[]} =>
|
|
|
84
143
|
*/
|
|
85
144
|
const getAgentConfigParams = (
|
|
86
145
|
agentName: string,
|
|
87
|
-
|
|
146
|
+
agentConfig: AgentConfigInput,
|
|
88
147
|
functions: FunctionRegistryType,
|
|
89
148
|
state: Record<string, any>
|
|
90
149
|
) => {
|
|
91
|
-
try{
|
|
92
|
-
// Retrieve the parameters for the specified AI agent from
|
|
93
|
-
const
|
|
94
|
-
if (!
|
|
150
|
+
try {
|
|
151
|
+
// Retrieve the parameters for the specified AI agent from config
|
|
152
|
+
const agentConfigData = parseAgentConfig(agentConfig).crew.find(agent => agent.name === agentName);
|
|
153
|
+
if (!agentConfigData) {
|
|
95
154
|
throw new Error(`AI agent with name ${agentName} is not configured`);
|
|
96
155
|
}
|
|
97
156
|
|
|
98
157
|
// Get the constructor for the AI agent's provider
|
|
99
|
-
const AIConstructor = AIConstructors[
|
|
158
|
+
const AIConstructor = AIConstructors[agentConfigData.provider];
|
|
100
159
|
if (!AIConstructor) {
|
|
101
|
-
throw new Error(`AI provider ${
|
|
160
|
+
throw new Error(`AI provider ${agentConfigData.provider} is not supported. Did you mean '${agentConfigData.provider.toLowerCase()}'?`);
|
|
102
161
|
}
|
|
103
162
|
|
|
104
163
|
// If an API Key property is present, get the API key for the AI agent from the environment variables
|
|
105
164
|
let apiKey = '';
|
|
106
|
-
if (
|
|
107
|
-
apiKey = PROVIDER_API_KEYS[
|
|
165
|
+
if (agentConfigData.providerKeyName) {
|
|
166
|
+
apiKey = PROVIDER_API_KEYS[agentConfigData.providerKeyName] || '';
|
|
108
167
|
|
|
109
168
|
if (!apiKey) {
|
|
110
|
-
throw new Error(`API key for provider ${
|
|
169
|
+
throw new Error(`API key for provider ${agentConfigData.provider} is not set in environment variables`);
|
|
111
170
|
}
|
|
112
171
|
} else {
|
|
113
172
|
throw new Error(`Provider key name is missing in the agent configuration`);
|
|
@@ -116,22 +175,21 @@ const getAgentConfigParams = (
|
|
|
116
175
|
// Create an instance of the AI agent
|
|
117
176
|
const ai = new AIConstructor({
|
|
118
177
|
apiKey,
|
|
119
|
-
config:
|
|
178
|
+
config: agentConfigData.ai,
|
|
120
179
|
options: {
|
|
121
|
-
debug:
|
|
180
|
+
debug: agentConfigData.debug || false
|
|
122
181
|
}
|
|
123
182
|
});
|
|
124
|
-
|
|
125
183
|
// If an apiURL is provided in the agent config, set it in the AI agent
|
|
126
|
-
if (
|
|
127
|
-
ai.setAPIURL(
|
|
184
|
+
if (agentConfigData.apiURL) {
|
|
185
|
+
ai.setAPIURL(agentConfigData.apiURL);
|
|
128
186
|
}
|
|
129
187
|
|
|
130
188
|
// Set all options from the agent configuration
|
|
131
|
-
ai.setOptions({ ...
|
|
189
|
+
ai.setOptions({ ...agentConfigData.options });
|
|
132
190
|
|
|
133
191
|
// Prepare functions for the AI agent
|
|
134
|
-
const agentFunctions = (
|
|
192
|
+
const agentFunctions = (agentConfigData.functions || [])
|
|
135
193
|
.map(funcName => {
|
|
136
194
|
const func = functions[funcName];
|
|
137
195
|
if (!func) {
|
|
@@ -153,15 +211,17 @@ const getAgentConfigParams = (
|
|
|
153
211
|
return {
|
|
154
212
|
ai,
|
|
155
213
|
name: agentName,
|
|
156
|
-
description:
|
|
157
|
-
signature:
|
|
214
|
+
description: agentConfigData.description,
|
|
215
|
+
signature: agentConfigData.signature,
|
|
158
216
|
functions: agentFunctions,
|
|
159
|
-
subAgentNames:
|
|
217
|
+
subAgentNames: agentConfigData.agents || []
|
|
160
218
|
};
|
|
161
219
|
} catch (error) {
|
|
162
|
-
|
|
163
|
-
|
|
220
|
+
if (error instanceof Error) {
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
throw new Error(`Error setting up AI agent: ${error}`);
|
|
164
224
|
}
|
|
165
225
|
};
|
|
166
226
|
|
|
167
|
-
export { getAgentConfigParams }
|
|
227
|
+
export { getAgentConfigParams, AgentConfigInput };
|
package/src/agents/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
AxProgramForwardOptions,
|
|
8
8
|
} from "@ax-llm/ax";
|
|
9
9
|
import { getAgentConfigParams } from "./agentConfig.js";
|
|
10
|
+
import type { AgentConfigInput } from "./agentConfig.js";
|
|
10
11
|
import { FunctionRegistryType } from "../functions/index.js";
|
|
11
12
|
import { createState, StateInstance } from "../state/index.js";
|
|
12
13
|
|
|
@@ -62,7 +63,7 @@ class StatefulAxAgent extends AxAgent<any, any> {
|
|
|
62
63
|
* Represents a crew of agents with shared state functionality.
|
|
63
64
|
*/
|
|
64
65
|
class AxCrew {
|
|
65
|
-
private
|
|
66
|
+
private agentConfig: AgentConfigInput;
|
|
66
67
|
functionsRegistry: FunctionRegistryType = {};
|
|
67
68
|
crewId: string;
|
|
68
69
|
agents: Map<string, StatefulAxAgent> | null;
|
|
@@ -70,16 +71,16 @@ class AxCrew {
|
|
|
70
71
|
|
|
71
72
|
/**
|
|
72
73
|
* Creates an instance of AxCrew.
|
|
73
|
-
* @param {
|
|
74
|
+
* @param {AgentConfigInput} agentConfig - Either a path to the agent config file or a JSON object with crew configuration.
|
|
74
75
|
* @param {FunctionRegistryType} [functionsRegistry={}] - The registry of functions to use in the crew.
|
|
75
76
|
* @param {string} [crewId=uuidv4()] - The unique identifier for the crew.
|
|
76
77
|
*/
|
|
77
78
|
constructor(
|
|
78
|
-
|
|
79
|
+
agentConfig: AgentConfigInput,
|
|
79
80
|
functionsRegistry: FunctionRegistryType = {},
|
|
80
81
|
crewId: string = uuidv4()
|
|
81
82
|
) {
|
|
82
|
-
this.
|
|
83
|
+
this.agentConfig = agentConfig;
|
|
83
84
|
this.functionsRegistry = functionsRegistry;
|
|
84
85
|
this.crewId = crewId;
|
|
85
86
|
this.agents = new Map<string, StatefulAxAgent>();
|
|
@@ -96,7 +97,7 @@ class AxCrew {
|
|
|
96
97
|
try {
|
|
97
98
|
const agentConfigParams: AgentConfigParams = getAgentConfigParams(
|
|
98
99
|
agentName,
|
|
99
|
-
this.
|
|
100
|
+
this.agentConfig,
|
|
100
101
|
this.functionsRegistry,
|
|
101
102
|
this.state
|
|
102
103
|
);
|
|
@@ -134,7 +135,6 @@ class AxCrew {
|
|
|
134
135
|
|
|
135
136
|
return agent;
|
|
136
137
|
} catch (error) {
|
|
137
|
-
console.error(`Failed to create agent '${agentName}':`, error);
|
|
138
138
|
throw error;
|
|
139
139
|
}
|
|
140
140
|
};
|
|
@@ -144,8 +144,13 @@ class AxCrew {
|
|
|
144
144
|
* @param {string} agentName - The name of the agent to add.
|
|
145
145
|
*/
|
|
146
146
|
addAgent(agentName: string): void {
|
|
147
|
-
|
|
148
|
-
this.agents
|
|
147
|
+
try {
|
|
148
|
+
if (this.agents && !this.agents.has(agentName)) {
|
|
149
|
+
this.agents.set(agentName, this.createAgent(agentName));
|
|
150
|
+
}
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.error(`Failed to create agent '${agentName}':`);
|
|
153
|
+
throw error;
|
|
149
154
|
}
|
|
150
155
|
}
|
|
151
156
|
|
|
@@ -157,10 +162,14 @@ class AxCrew {
|
|
|
157
162
|
* @returns {Map<string, StatefulAxAgent> | null} A map of agent names to their corresponding instances.
|
|
158
163
|
*/
|
|
159
164
|
addAgentsToCrew(agentNames: string[]): Map<string, StatefulAxAgent> | null {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
165
|
+
try {
|
|
166
|
+
agentNames.forEach((agentName) => {
|
|
167
|
+
this.addAgent(agentName);
|
|
168
|
+
});
|
|
169
|
+
return this.agents;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
164
173
|
}
|
|
165
174
|
|
|
166
175
|
/**
|
package/test.js
CHANGED
|
@@ -1,65 +1,30 @@
|
|
|
1
1
|
import { AxCrew, AxCrewFunctions } from "./dist/index.js";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
crew.addAgentsToCrew(["Planner", "Calculator", "Manager"]);
|
|
3
|
+
const crew = new AxCrew("./agentConfig.json", AxCrewFunctions);
|
|
4
|
+
crew.addAgentsToCrew(["Planner", "Calculator", "WebSearch", "Manager"]);
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const Manager = crew.agents.get("Manager");
|
|
6
|
+
const calculateAndPrintAgentCost = (agent, agentName) => {
|
|
7
|
+
const { models, modelUsage, modelInfo } = agent.axai;
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const usedTokens = agent.aiInstance.modelUsage;
|
|
15
|
-
const modelInfo = agent.aiInstance.modelInfo?.find(
|
|
16
|
-
(model) => model.name === modelUsed);
|
|
17
|
-
|
|
18
|
-
const promptCost =
|
|
19
|
-
(usedTokens.promptTokens / 1000000) * modelInfo?.promptTokenCostPer1M;
|
|
20
|
-
const completionCost =
|
|
21
|
-
(usedTokens.completionTokens / 1000000) *
|
|
22
|
-
modelInfo?.completionTokenCostPer1M;
|
|
23
|
-
const totalCost = promptCost + completionCost;
|
|
9
|
+
const { promptTokens, completionTokens } = modelUsage;
|
|
10
|
+
const modelDetails = modelInfo?.find((m) => m.name === models.model);
|
|
11
|
+
const totalCost = ((promptTokens / 1000000) * modelDetails?.promptTokenCostPer1M) + ((completionTokens / 1000000) * modelDetails?.completionTokenCostPer1M);
|
|
24
12
|
|
|
25
|
-
|
|
26
|
-
totalCost,
|
|
27
|
-
promptTokens: usedTokens.promptTokens,
|
|
28
|
-
completionTokens: usedTokens.completionTokens,
|
|
29
|
-
};
|
|
13
|
+
console.log(`\n${agentName} Usage:\nPrompt Token Cost: $${(promptTokens / 1000000 * modelDetails?.promptTokenCostPer1M).toFixed(6)}\nCompletion Token Cost: $${(completionTokens / 1000000 * modelDetails?.completionTokenCostPer1M).toFixed(6)}\nTotal Cost: $${totalCost.toFixed(6)}\nPrompt Tokens: ${promptTokens}\nCompletion Tokens: ${completionTokens}\nTotal Tokens: ${promptTokens + completionTokens}`);
|
|
30
14
|
};
|
|
31
15
|
|
|
32
|
-
|
|
33
|
-
const userQuery = "whats the square root of the number of days between now and Christmas";
|
|
16
|
+
const userQuery = "what is the cube root of the number of days between now and Christmas";
|
|
34
17
|
console.log(`\n\nQuestion: ${userQuery}`);
|
|
35
18
|
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const planner = calculateAgentCost(Planner);
|
|
42
|
-
console.log('\nPlanner Usage:');
|
|
43
|
-
console.log(`Cost: $${planner.totalCost.toFixed(6)}`);
|
|
44
|
-
console.log(`Prompt Tokens: ${planner.promptTokens}`);
|
|
45
|
-
console.log(`Completion Tokens: ${planner.completionTokens}`);
|
|
46
|
-
console.log(`Total Tokens: ${planner.promptTokens + planner.completionTokens}`);
|
|
47
|
-
|
|
48
|
-
const managerResponse = await Manager.forward({
|
|
49
|
-
question: userQuery,
|
|
50
|
-
plan: planResponse.plan,
|
|
51
|
-
});
|
|
19
|
+
const Planner = crew.agents.get("Planner");
|
|
20
|
+
const plannerResponse = await Planner.forward({ task: userQuery });
|
|
21
|
+
console.log(`\n\nPlanner Response: ${plannerResponse.plan}`);
|
|
52
22
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
console.log(
|
|
56
|
-
console.log(`Prompt Tokens: ${manager.promptTokens}`);
|
|
57
|
-
console.log(`Completion Tokens: ${manager.completionTokens}`);
|
|
58
|
-
console.log(`Total Tokens: ${manager.promptTokens + manager.completionTokens}`);
|
|
23
|
+
const Manager = crew.agents.get("Manager");
|
|
24
|
+
const managerResponse = await Manager.forward({ question: userQuery, plan: plannerResponse.plan });
|
|
25
|
+
console.log(`\n\nManager Response: ${managerResponse.answer}`);
|
|
59
26
|
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
const answer = managerResponse.answer;
|
|
27
|
+
// const calculatorResponse = await crew.agents.get("Calculator").forward({ mathProblem: userQuery });
|
|
28
|
+
// calculateAndPrintAgentCost(crew.agents.get("Calculator"), "Calculator");
|
|
63
29
|
|
|
64
|
-
console.log(`\n\
|
|
65
|
-
console.log(`\n\nAnswer: ${answer}`);
|
|
30
|
+
// console.log(`\n\nAnswer: ${calculatorResponse.solution}`);
|
package/test1.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { AxCrew, AxCrewFunctions } from "./dist/index.js";
|
|
2
|
+
|
|
3
|
+
// Define the configuration object directly
|
|
4
|
+
const config = {
|
|
5
|
+
crew: [
|
|
6
|
+
{
|
|
7
|
+
name: "Planner",
|
|
8
|
+
description: "Creates a plan to complete a task",
|
|
9
|
+
signature: "task:string \"a task to be completed\" -> plan:string \"a plan to execute the task in 5 steps or less\"",
|
|
10
|
+
provider: "google-gemini",
|
|
11
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
12
|
+
ai: {
|
|
13
|
+
model: "gemini-1.5-flash",
|
|
14
|
+
temperature: 0
|
|
15
|
+
},
|
|
16
|
+
options: {
|
|
17
|
+
debug: false
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "Calculator",
|
|
22
|
+
description: "Solves math problems",
|
|
23
|
+
signature: "mathProblem:string \"a math problem to be solved using Python code\" -> solution:string \"the solution to the math problem\"",
|
|
24
|
+
provider: "google-gemini",
|
|
25
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
26
|
+
ai: {
|
|
27
|
+
model: "gemini-1.5-pro",
|
|
28
|
+
temperature: 0
|
|
29
|
+
},
|
|
30
|
+
options: {
|
|
31
|
+
debug: true,
|
|
32
|
+
codeExecution: true
|
|
33
|
+
},
|
|
34
|
+
functions: ["CurrentDateTime", "DaysBetweenDates"]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "WebSearch",
|
|
38
|
+
description: "Searches the web for the latest information using Google search",
|
|
39
|
+
signature: "webSearchQuery:string \"a query for Google search\" -> webSearchResponse:string \"the result of the search\"",
|
|
40
|
+
provider: "google-gemini",
|
|
41
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
42
|
+
ai: {
|
|
43
|
+
model: "gemini-1.5-pro",
|
|
44
|
+
temperature: 0
|
|
45
|
+
},
|
|
46
|
+
options: {
|
|
47
|
+
debug: true,
|
|
48
|
+
googleSearchRetrieval: true
|
|
49
|
+
},
|
|
50
|
+
functions: ["CurrentDateTime", "DaysBetweenDates"]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "Manager",
|
|
54
|
+
description: "Answers questions from the user",
|
|
55
|
+
signature: "question:string \"a question from a user\", plan:string \"a suggested plan to answer the question\" -> answer:string \"the answer\"",
|
|
56
|
+
provider: "openai",
|
|
57
|
+
providerKeyName: "OPENAI_API_KEY",
|
|
58
|
+
ai: {
|
|
59
|
+
model: "gpt-4o-mini",
|
|
60
|
+
temperature: 0
|
|
61
|
+
},
|
|
62
|
+
options: {
|
|
63
|
+
debug: true
|
|
64
|
+
},
|
|
65
|
+
functions: ["CurrentDateTime", "DaysBetweenDates"]
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Create crew instance with the direct configuration
|
|
71
|
+
const crew = new AxCrew(config, AxCrewFunctions);
|
|
72
|
+
crew.addAgentsToCrew(["Planner", "Calculator", "WebSearch", "Manager"]);
|
|
73
|
+
|
|
74
|
+
const calculateAndPrintAgentCost = (agent, agentName) => {
|
|
75
|
+
const { models, modelUsage, modelInfo } = agent.axai;
|
|
76
|
+
|
|
77
|
+
const { promptTokens, completionTokens } = modelUsage;
|
|
78
|
+
const modelDetails = modelInfo?.find((m) => m.name === models.model);
|
|
79
|
+
const totalCost = ((promptTokens / 1000000) * modelDetails?.promptTokenCostPer1M) + ((completionTokens / 1000000) * modelDetails?.completionTokenCostPer1M);
|
|
80
|
+
|
|
81
|
+
console.log(`\n${agentName} Usage:\nPrompt Token Cost: $${(promptTokens / 1000000 * modelDetails?.promptTokenCostPer1M).toFixed(6)}\nCompletion Token Cost: $${(completionTokens / 1000000 * modelDetails?.completionTokenCostPer1M).toFixed(6)}\nTotal Cost: $${totalCost.toFixed(6)}\nPrompt Tokens: ${promptTokens}\nCompletion Tokens: ${completionTokens}\nTotal Tokens: ${promptTokens + completionTokens}`);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const userQuery = "what is the cube root of the number of days between now and Christmas";
|
|
85
|
+
console.log(`\n\nQuestion: ${userQuery}`);
|
|
86
|
+
|
|
87
|
+
const Planner = crew.agents.get("Planner");
|
|
88
|
+
const plannerResponse = await Planner.forward({ task: userQuery });
|
|
89
|
+
console.log(`\n\nPlanner Response: ${plannerResponse.plan}`);
|
|
90
|
+
|
|
91
|
+
const Manager = crew.agents.get("Manager");
|
|
92
|
+
const managerResponse = await Manager.forward({ question: userQuery, plan: plannerResponse.plan });
|
|
93
|
+
console.log(`\n\nManager Response: ${managerResponse.answer}`);
|
|
94
|
+
|
|
95
|
+
// const calculatorResponse = await crew.agents.get("Calculator").forward({ mathProblem: userQuery });
|
|
96
|
+
// calculateAndPrintAgentCost(crew.agents.get("Calculator"), "Calculator");
|
|
97
|
+
|
|
98
|
+
// console.log(`\n\nAnswer: ${calculatorResponse.solution}`);
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# AxLLM Crew config
|
|
2
|
-
crew:
|
|
3
|
-
- name: Planner
|
|
4
|
-
description: Creates a plan to complete a task
|
|
5
|
-
signature: task:string "a task to be completed" -> plan:string "a plan to execute the task in 5 steps or less"
|
|
6
|
-
provider: google-gemini
|
|
7
|
-
provider_key_name: GEMINI_API_KEY
|
|
8
|
-
ai:
|
|
9
|
-
model: gemini-1.5-flash
|
|
10
|
-
temperature: 0
|
|
11
|
-
options:
|
|
12
|
-
debug: false
|
|
13
|
-
|
|
14
|
-
- name: Calculator
|
|
15
|
-
description: Solves math problems
|
|
16
|
-
signature: mathProblem:string "a math problem to be solved using Python code" -> solution:string "the solution to the math problem"
|
|
17
|
-
provider: google-gemini
|
|
18
|
-
provider_key_name: GEMINI_API_KEY
|
|
19
|
-
ai:
|
|
20
|
-
model: gemini-1.5-pro
|
|
21
|
-
temperature: 0
|
|
22
|
-
options:
|
|
23
|
-
debug: true
|
|
24
|
-
codeExecution: true
|
|
25
|
-
|
|
26
|
-
- name: Manager
|
|
27
|
-
description: Answers questions from the user
|
|
28
|
-
signature: question:string "a question from a user", plan:string "a suggested plan to answer the question" -> answer:string "the answer"
|
|
29
|
-
provider: openai
|
|
30
|
-
provider_key_name: OPENAI_API_KEY
|
|
31
|
-
ai:
|
|
32
|
-
model: gpt-4o-mini
|
|
33
|
-
temperature: 0
|
|
34
|
-
options:
|
|
35
|
-
debug: true
|
|
36
|
-
functions:
|
|
37
|
-
- CurrentDateTime
|
|
38
|
-
- DaysBetweenDates
|
|
39
|
-
agents:
|
|
40
|
-
- Calculator
|
|
41
|
-
|