@amitdeshmukh/ax-crew 2.0.3 → 2.0.7

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 ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ This Changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
+
5
+ ## [Unreleased]
6
+
7
+ ### Added
8
+ - Change [agent_config.example.yaml](agent_config.example.yaml) to JSON format
9
+ - Add support for providing examples via `setExamples` method
10
+
11
+ ## [2.0.7] - 2024-11-23
12
+
13
+ ### Added
14
+ - Release of version 2.0.7
15
+ - Support for [AxLLM](https://axllm.dev) versions > 10.0.0
16
+ - Changelog
17
+
18
+ ### Changed
19
+ - Updated README.md
20
+
21
+ ### Fixed
22
+ - Updates to [dateTime.ts](src/dateTime.ts) to enable use in Gemini models
23
+
package/README.md CHANGED
@@ -12,9 +12,15 @@ This repo simplifies development of [AxLLM](https://axllm.dev) AI Agents by usin
12
12
  ## Getting Started
13
13
 
14
14
  ### Installation
15
+ Install this package:
15
16
  ```bash
16
17
  npm install @amitdeshmukh/ax-crew
17
18
  ```
19
+ AxLLM is a peer dependency, so you will need to install it separately.
20
+
21
+ ```bash
22
+ npm install @ax-llm/ax@latest
23
+ ```
18
24
 
19
25
  ### Environment Setup
20
26
  Refer to the [.env.example](.env.example) file for the required environment variables. These will need to be set in the environment where the agents are run.
@@ -139,3 +145,7 @@ const answer = managerResponse.answer;
139
145
  console.log(`\n\nPlan: ${plan}`);
140
146
  console.log(`\n\nAnswer: ${answer}`);
141
147
  ```
148
+
149
+ ## Changelog
150
+
151
+ See [CHANGELOG.md](CHANGELOG.md) for a list of changes and version updates.
@@ -3,13 +3,13 @@ crew:
3
3
  - name: Planner
4
4
  description: Creates a plan to complete a task
5
5
  signature: task:string "a task to be completed" -> plan:string "a plan to execute the task in 5 steps or less"
6
- provider: anthropic
7
- provider_key_name: ANTHROPIC_API_KEY
6
+ provider: google-gemini
7
+ provider_key_name: GEMINI_API_KEY
8
8
  ai:
9
- model: claude-3-5-sonnet-20240620
9
+ model: gemini-1.5-flash
10
10
  temperature: 0
11
11
  options:
12
- debug: true
12
+ debug: false
13
13
 
14
14
  - name: Calculator
15
15
  description: Solves math problems
@@ -26,10 +26,10 @@ crew:
26
26
  - name: Manager
27
27
  description: Answers questions from the user
28
28
  signature: question:string "a question from a user", plan:string "a suggested plan to answer the question" -> answer:string "the answer"
29
- provider: anthropic
30
- provider_key_name: ANTHROPIC_API_KEY
29
+ provider: openai
30
+ provider_key_name: OPENAI_API_KEY
31
31
  ai:
32
- model: claude-3-5-sonnet-20240620
32
+ model: gpt-4o-mini
33
33
  temperature: 0
34
34
  options:
35
35
  debug: true
@@ -1,16 +1,20 @@
1
- import { v4 as uuidv4 } from 'uuid';
2
- import { AxAgent } from '@ax-llm/ax';
3
- import { getAgentConfigParams } from './agentConfig.js';
4
- import { createState } from '../state/createState.js';
1
+ import { v4 as uuidv4 } from "uuid";
2
+ import { AxAgent } from "@ax-llm/ax";
3
+ import { getAgentConfigParams } from "./agentConfig.js";
4
+ import { createState } from "../state/index.js";
5
5
  // Extend the AxAgent class to include shared state functionality
6
6
  class StatefulAxAgent extends AxAgent {
7
7
  constructor(ai, options, state) {
8
8
  const formattedOptions = {
9
9
  ...options,
10
- functions: options.functions?.map(fn => typeof fn === 'function' ? fn() : fn)
10
+ functions: options.functions?.map((fn) => typeof fn === "function" ? fn() : fn),
11
11
  };
12
- super(ai, formattedOptions);
12
+ super(formattedOptions);
13
13
  this.state = state;
14
+ this.axai = ai;
15
+ }
16
+ async forward(input, options) {
17
+ return super.forward(this.axai, input, options);
14
18
  }
15
19
  }
16
20
  /**
@@ -49,7 +53,7 @@ class AxCrew {
49
53
  description,
50
54
  signature,
51
55
  functions: functions.filter((fn) => fn !== undefined),
52
- agents: subAgents.filter((agent) => agent !== undefined)
56
+ agents: subAgents.filter((agent) => agent !== undefined),
53
57
  }, this.state);
54
58
  return agent;
55
59
  }
@@ -81,7 +85,7 @@ class AxCrew {
81
85
  * @returns {Map<string, StatefulAxAgent> | null} A map of agent names to their corresponding instances.
82
86
  */
83
87
  addAgentsToCrew(agentNames) {
84
- agentNames.forEach(agentName => {
88
+ agentNames.forEach((agentName) => {
85
89
  this.addAgent(agentName);
86
90
  });
87
91
  return this.agents;
@@ -3,10 +3,25 @@ export const CurrentDateTime = {
3
3
  description: 'Get the current date and time.',
4
4
  parameters: {
5
5
  type: 'object',
6
- properties: {},
7
- required: []
6
+ properties: {
7
+ format: {
8
+ type: 'string',
9
+ description: 'The format of the date and time to return.',
10
+ enum: ['iso', 'datetime', 'date']
11
+ }
12
+ }
8
13
  },
9
- func: () => new Date().toISOString()
14
+ func: ({ format }) => {
15
+ const now = new Date();
16
+ switch (format) {
17
+ case 'datetime':
18
+ return now.toLocaleString();
19
+ case 'date':
20
+ return now.toLocaleDateString();
21
+ default:
22
+ return now.toISOString();
23
+ }
24
+ }
10
25
  };
11
26
  export const DaysBetweenDates = {
12
27
  name: 'DaysBetweenDates',
@@ -16,11 +31,11 @@ export const DaysBetweenDates = {
16
31
  properties: {
17
32
  startDate: {
18
33
  type: 'string',
19
- description: 'The start date in ISO format.'
34
+ description: 'The start date in ISO format. Must be on or before the end date.'
20
35
  },
21
36
  endDate: {
22
37
  type: 'string',
23
- description: 'The end date in ISO format.'
38
+ description: 'The end date in ISO format. Must be on or after the start date.'
24
39
  }
25
40
  },
26
41
  required: ['startDate', 'endDate']
@@ -1,6 +1,7 @@
1
1
  import { CurrentDateTime, DaysBetweenDates } from './dateTime.js';
2
+ // Built-in functions
2
3
  const AxCrewFunctions = {
3
4
  CurrentDateTime,
4
- DaysBetweenDates,
5
+ DaysBetweenDates
5
6
  };
6
7
  export { AxCrewFunctions };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@amitdeshmukh/ax-crew",
4
- "version": "2.0.3",
4
+ "version": "2.0.7",
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": {
@@ -14,10 +14,11 @@
14
14
  "dependencies": {
15
15
  "dotenv": "^16.4.5",
16
16
  "js-yaml": "^4.1.0",
17
+ "upgrade": "^1.1.0",
17
18
  "uuid": "^10.0.0"
18
19
  },
19
20
  "peerDependencies": {
20
- "@ax-llm/ax": "^9.0.23"
21
+ "@ax-llm/ax": "^10.0.0"
21
22
  },
22
23
  "devDependencies": {
23
24
  "@types/js-yaml": "^4.0.9",
@@ -25,5 +26,13 @@
25
26
  "@types/uuid": "^10.0.0",
26
27
  "typescript": "^5.5.3"
27
28
  },
29
+ "homepage": "https://github.com/amitdeshmukh/ax-crew#readme",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/amitdeshmukh/ax-crew.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/amitdeshmukh/ax-crew/issues"
36
+ },
28
37
  "license": "MIT"
29
38
  }
@@ -1,9 +1,14 @@
1
- import { v4 as uuidv4 } from 'uuid';
2
- import { AxAgent, AxAI } from '@ax-llm/ax';
3
- import type { AxSignature, AxAgentic, AxFunction } from '@ax-llm/ax';
4
- import { getAgentConfigParams } from './agentConfig.js';
5
- import { FunctionRegistryType } from '../functions/index.js';
6
- import { createState, StateInstance } from '../state/createState.js';
1
+ import { v4 as uuidv4 } from "uuid";
2
+ import { AxAgent, AxAI } from "@ax-llm/ax";
3
+ import type {
4
+ AxSignature,
5
+ AxAgentic,
6
+ AxFunction,
7
+ AxProgramForwardOptions,
8
+ } from "@ax-llm/ax";
9
+ import { getAgentConfigParams } from "./agentConfig.js";
10
+ import { FunctionRegistryType } from "../functions/index.js";
11
+ import { createState, StateInstance } from "../state/index.js";
7
12
 
8
13
  // Define the interface for the agent configuration
9
14
  interface AgentConfigParams {
@@ -11,21 +16,45 @@ interface AgentConfigParams {
11
16
  name: string;
12
17
  description: string;
13
18
  signature: AxSignature;
14
- functions: (AxFunction | (new (state: Record<string, any>) => { toFunction: () => AxFunction; }) | undefined)[];
19
+ functions: (
20
+ | AxFunction
21
+ | (new (state: Record<string, any>) => { toFunction: () => AxFunction })
22
+ | undefined
23
+ )[];
15
24
  subAgentNames: string[];
16
25
  }
17
26
 
18
27
  // Extend the AxAgent class to include shared state functionality
19
28
  class StatefulAxAgent extends AxAgent<any, any> {
20
29
  state: StateInstance;
30
+ axai: any;
21
31
 
22
- constructor(ai: AxAI, options: Readonly<{ name: string; description: string; signature: string | AxSignature; agents?: AxAgentic[] | undefined; functions?: (AxFunction | (() => AxFunction))[] | undefined; }>, state: StateInstance) {
32
+ constructor(
33
+ ai: AxAI,
34
+ options: Readonly<{
35
+ name: string;
36
+ description: string;
37
+ signature: string | AxSignature;
38
+ agents?: AxAgentic[] | undefined;
39
+ functions?: (AxFunction | (() => AxFunction))[] | undefined;
40
+ }>,
41
+ state: StateInstance
42
+ ) {
23
43
  const formattedOptions = {
24
44
  ...options,
25
- functions: options.functions?.map(fn => typeof fn === 'function' ? fn() : fn) as AxFunction[] | undefined
45
+ functions: options.functions?.map((fn) =>
46
+ typeof fn === "function" ? fn() : fn
47
+ ) as AxFunction[] | undefined,
26
48
  };
27
- super(ai, formattedOptions);
49
+ super(formattedOptions);
28
50
  this.state = state;
51
+ this.axai = ai;
52
+ }
53
+ async forward(
54
+ input: Record<string, any>,
55
+ options?: Readonly<AxProgramForwardOptions>
56
+ ): Promise<Record<string, any>> {
57
+ return super.forward(this.axai, input, options);
29
58
  }
30
59
  }
31
60
 
@@ -66,39 +95,43 @@ class AxCrew {
66
95
  createAgent = (agentName: string): StatefulAxAgent => {
67
96
  try {
68
97
  const agentConfigParams: AgentConfigParams = getAgentConfigParams(
69
- agentName,
98
+ agentName,
70
99
  this.configFilePath,
71
100
  this.functionsRegistry,
72
101
  this.state
73
102
  );
74
103
 
75
104
  // Destructure with type assertion
76
- const {
77
- ai,
78
- name,
79
- description,
80
- signature,
81
- functions,
82
- subAgentNames
83
- } = agentConfigParams;
105
+ const { ai, name, description, signature, functions, subAgentNames } =
106
+ agentConfigParams;
84
107
 
85
108
  // Get subagents for the AI agent
86
109
  const subAgents = subAgentNames.map((subAgentName: string) => {
87
110
  if (!this.agents?.get(subAgentName)) {
88
- throw new Error(`Sub-agent '${subAgentName}' does not exist in available agents.`);
111
+ throw new Error(
112
+ `Sub-agent '${subAgentName}' does not exist in available agents.`
113
+ );
89
114
  }
90
115
  return this.agents?.get(subAgentName);
91
116
  });
92
117
 
93
118
  // Create an instance of StatefulAxAgent
94
- const agent = new StatefulAxAgent(ai, {
95
- name,
96
- description,
97
- signature,
98
- functions: functions.filter((fn): fn is AxFunction => fn !== undefined),
99
- agents: subAgents.filter((agent): agent is StatefulAxAgent => agent !== undefined)
100
- }, this.state);
101
-
119
+ const agent = new StatefulAxAgent(
120
+ ai,
121
+ {
122
+ name,
123
+ description,
124
+ signature,
125
+ functions: functions.filter(
126
+ (fn): fn is AxFunction => fn !== undefined
127
+ ),
128
+ agents: subAgents.filter(
129
+ (agent): agent is StatefulAxAgent => agent !== undefined
130
+ ),
131
+ },
132
+ this.state
133
+ );
134
+
102
135
  return agent;
103
136
  } catch (error) {
104
137
  console.error(`Failed to create agent '${agentName}':`, error);
@@ -114,7 +147,7 @@ class AxCrew {
114
147
  if (this.agents && !this.agents.has(agentName)) {
115
148
  this.agents.set(agentName, this.createAgent(agentName));
116
149
  }
117
- }
150
+ }
118
151
 
119
152
  /**
120
153
  * Sets up agents in the crew by name.
@@ -124,7 +157,7 @@ class AxCrew {
124
157
  * @returns {Map<string, StatefulAxAgent> | null} A map of agent names to their corresponding instances.
125
158
  */
126
159
  addAgentsToCrew(agentNames: string[]): Map<string, StatefulAxAgent> | null {
127
- agentNames.forEach(agentName => {
160
+ agentNames.forEach((agentName) => {
128
161
  this.addAgent(agentName);
129
162
  });
130
163
  return this.agents;
@@ -136,7 +169,7 @@ class AxCrew {
136
169
  destroy() {
137
170
  this.agents = null;
138
171
  this.state.reset();
139
- }
172
+ }
140
173
  }
141
174
 
142
- export { AxCrew };
175
+ export { AxCrew };
@@ -5,10 +5,25 @@ export const CurrentDateTime: AxFunction = {
5
5
  description: 'Get the current date and time.',
6
6
  parameters: {
7
7
  type: 'object',
8
- properties: {},
9
- required: []
8
+ properties: {
9
+ format: {
10
+ type: 'string',
11
+ description: 'The format of the date and time to return.',
12
+ enum: ['iso', 'datetime', 'date']
13
+ }
14
+ }
10
15
  },
11
- func: () => new Date().toISOString()
16
+ func: ({ format }: { format: string }) => {
17
+ const now = new Date();
18
+ switch (format) {
19
+ case 'datetime':
20
+ return now.toLocaleString();
21
+ case 'date':
22
+ return now.toLocaleDateString();
23
+ default:
24
+ return now.toISOString();
25
+ }
26
+ }
12
27
  }
13
28
 
14
29
  export const DaysBetweenDates: AxFunction = {
@@ -19,11 +34,11 @@ export const DaysBetweenDates: AxFunction = {
19
34
  properties: {
20
35
  startDate: {
21
36
  type: 'string',
22
- description: 'The start date in ISO format.'
37
+ description: 'The start date in ISO format. Must be on or before the end date.'
23
38
  },
24
39
  endDate: {
25
40
  type: 'string',
26
- description: 'The end date in ISO format.'
41
+ description: 'The end date in ISO format. Must be on or after the start date.'
27
42
  }
28
43
  },
29
44
  required: ['startDate', 'endDate']
@@ -1,14 +1,15 @@
1
1
  import { AxFunction } from '@ax-llm/ax';
2
2
  import { CurrentDateTime, DaysBetweenDates } from './dateTime.js';
3
3
 
4
- // FunctionRegistryType
4
+ // FunctionRegistryType to register custom functions
5
5
  type FunctionRegistryType = {
6
6
  [key: string]: AxFunction | { new(state: Record<string, any>): { toFunction: () => AxFunction } };
7
7
  };
8
8
 
9
+ // Built-in functions
9
10
  const AxCrewFunctions = {
10
11
  CurrentDateTime,
11
- DaysBetweenDates,
12
+ DaysBetweenDates
12
13
  };
13
14
 
14
15
  export { AxCrewFunctions, FunctionRegistryType };
package/test.js CHANGED
@@ -1,21 +1,61 @@
1
- import { AxCrew, AxCrewFunctions } from '@amitdeshmukh/ax-crew';
1
+ import { AxCrew, AxCrewFunctions } from "./dist/index.js";
2
2
 
3
3
  // Create a new instance of AxCrew
4
- const crew = new AxCrew('./agent_config.example.yaml', AxCrewFunctions);
5
- crew.addAgentsToCrew(['Planner', 'Manager']);
4
+ const crew = new AxCrew("./agent_config.example.yaml", AxCrewFunctions);
5
+ crew.addAgentsToCrew(["Planner", "Calculator", "Manager"]);
6
6
 
7
7
  // Get agent instances
8
8
  const Planner = crew.agents.get("Planner");
9
9
  const Manager = crew.agents.get("Manager");
10
10
 
11
+ // Calculate costs
12
+ const calculateAgentCost = (agent) => {
13
+ const modelUsed = agent.aiInstance.models.model;
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;
24
+
25
+ return {
26
+ totalCost,
27
+ promptTokens: usedTokens.promptTokens,
28
+ completionTokens: usedTokens.completionTokens,
29
+ };
30
+ };
31
+
11
32
  // User query
12
33
  const userQuery = "whats the square root of the number of days between now and Christmas";
13
-
14
34
  console.log(`\n\nQuestion: ${userQuery}`);
15
35
 
16
36
  // Forward the user query to the agents
17
- const planResponse = await Planner.forward({ task: userQuery });
18
- const managerResponse = await Manager.forward({ question: userQuery, plan: planResponse.plan });
37
+ const planResponse = await Planner.forward({
38
+ task: userQuery
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
+ });
52
+
53
+ const manager = calculateAgentCost(Manager);
54
+ console.log('\nManager Usage:');
55
+ console.log(`Cost: $${manager.totalCost.toFixed(4)}`);
56
+ console.log(`Prompt Tokens: ${manager.promptTokens}`);
57
+ console.log(`Completion Tokens: ${manager.completionTokens}`);
58
+ console.log(`Total Tokens: ${manager.promptTokens + manager.completionTokens}`);
19
59
 
20
60
  // Get and print the plan and answer from the agents
21
61
  const plan = planResponse.plan;
File without changes
File without changes