@amitdeshmukh/ax-crew 3.7.1 → 3.8.1
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 +10 -0
- package/dist/agents/agentUseCosts.d.ts +2 -2
- package/dist/agents/agentUseCosts.js +57 -33
- package/dist/agents/index.js +9 -2
- package/dist/types.d.ts +14 -5
- package/examples/streaming.ts +3 -3
- package/package.json +1 -1
- package/src/agents/agentUseCosts.ts +58 -35
- package/src/agents/index.ts +12 -2
- package/src/types.ts +16 -5
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,16 @@ This Changelog format is based on [Keep a Changelog]
|
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/
|
|
6
6
|
v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.8.1] - 2024-03-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Enhanced type definitions for model usage metrics with nested token structure support
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Improved error handling and robustness in cost calculations
|
|
15
|
+
- Better null handling in usage cost tracking
|
|
16
|
+
- Updated type definitions in `src/types.ts` to support both direct and nested token structures
|
|
17
|
+
|
|
8
18
|
## [3.7.1] - 2025-03-27
|
|
9
19
|
|
|
10
20
|
### Fixed
|
|
@@ -5,8 +5,8 @@ import type { StateInstance, ModelUsage, ModelInfo, UsageCost, AggregatedCosts }
|
|
|
5
5
|
*/
|
|
6
6
|
export declare class StateFulAxAgentUsage {
|
|
7
7
|
static STATE_KEY_PREFIX: string;
|
|
8
|
-
static calculateCost(modelUsage: ModelUsage, modelInfo: ModelInfo): UsageCost;
|
|
9
|
-
static trackCostInState(agentName: string, cost: UsageCost, state: StateInstance): void;
|
|
8
|
+
static calculateCost(modelUsage: ModelUsage, modelInfo: ModelInfo): UsageCost | null;
|
|
9
|
+
static trackCostInState(agentName: string, cost: UsageCost | null, state: StateInstance): void;
|
|
10
10
|
static getAggregatedCosts(state: StateInstance): AggregatedCosts;
|
|
11
11
|
static resetCosts(state: StateInstance): void;
|
|
12
12
|
}
|
|
@@ -5,45 +5,69 @@ import { Decimal } from 'decimal.js';
|
|
|
5
5
|
*/
|
|
6
6
|
export class StateFulAxAgentUsage {
|
|
7
7
|
static calculateCost(modelUsage, modelInfo) {
|
|
8
|
-
|
|
8
|
+
// Handle both direct properties and nested tokens structure
|
|
9
|
+
const promptTokens = modelUsage.tokens?.promptTokens ?? modelUsage.promptTokens;
|
|
10
|
+
const completionTokens = modelUsage.tokens?.completionTokens ?? modelUsage.completionTokens;
|
|
9
11
|
const { promptTokenCostPer1M, completionTokenCostPer1M } = modelInfo;
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
12
|
+
// Return null instead of throwing errors for invalid values
|
|
13
|
+
if (typeof promptTokens !== 'number' || isNaN(promptTokens) ||
|
|
14
|
+
typeof completionTokens !== 'number' || isNaN(completionTokens) ||
|
|
15
|
+
typeof promptTokenCostPer1M !== 'number' || isNaN(promptTokenCostPer1M) ||
|
|
16
|
+
typeof completionTokenCostPer1M !== 'number' || isNaN(completionTokenCostPer1M)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
// Use Decimal for precise calculations
|
|
21
|
+
const promptCost = new Decimal(promptTokens)
|
|
22
|
+
.div(1000000)
|
|
23
|
+
.mul(promptTokenCostPer1M)
|
|
24
|
+
.toDP(10); // Keep 10 decimal places
|
|
25
|
+
const completionCost = new Decimal(completionTokens)
|
|
26
|
+
.div(1000000)
|
|
27
|
+
.mul(completionTokenCostPer1M)
|
|
28
|
+
.toDP(10);
|
|
29
|
+
const totalCost = promptCost.plus(completionCost).toDP(10);
|
|
30
|
+
return {
|
|
31
|
+
promptCost: promptCost.toString(),
|
|
32
|
+
completionCost: completionCost.toString(),
|
|
33
|
+
totalCost: totalCost.toString(),
|
|
34
|
+
tokenMetrics: {
|
|
35
|
+
promptTokens,
|
|
36
|
+
completionTokens,
|
|
37
|
+
totalTokens: promptTokens + completionTokens
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
// If any decimal calculation fails, return null instead of throwing
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
30
45
|
}
|
|
31
46
|
static trackCostInState(agentName, cost, state) {
|
|
47
|
+
// If cost is null, skip tracking
|
|
48
|
+
if (!cost)
|
|
49
|
+
return;
|
|
32
50
|
const stateKey = `${this.STATE_KEY_PREFIX}${agentName}`;
|
|
33
51
|
const existingCost = state.get(stateKey);
|
|
34
52
|
if (existingCost) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
try {
|
|
54
|
+
// Aggregate with existing cost using Decimal
|
|
55
|
+
const aggregatedCost = {
|
|
56
|
+
promptCost: new Decimal(existingCost.promptCost).plus(cost.promptCost).toDP(10).toString(),
|
|
57
|
+
completionCost: new Decimal(existingCost.completionCost).plus(cost.completionCost).toDP(10).toString(),
|
|
58
|
+
totalCost: new Decimal(existingCost.totalCost).plus(cost.totalCost).toDP(10).toString(),
|
|
59
|
+
tokenMetrics: {
|
|
60
|
+
promptTokens: existingCost.tokenMetrics.promptTokens + cost.tokenMetrics.promptTokens,
|
|
61
|
+
completionTokens: existingCost.tokenMetrics.completionTokens + cost.tokenMetrics.completionTokens,
|
|
62
|
+
totalTokens: existingCost.tokenMetrics.totalTokens + cost.tokenMetrics.totalTokens
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
state.set(stateKey, aggregatedCost);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
// If aggregation fails, just use the new cost
|
|
69
|
+
state.set(stateKey, cost);
|
|
70
|
+
}
|
|
47
71
|
}
|
|
48
72
|
else {
|
|
49
73
|
// First time tracking this agent's cost
|
package/dist/agents/index.js
CHANGED
|
@@ -68,8 +68,15 @@ class StatefulAxAgent extends AxAgent {
|
|
|
68
68
|
// Get the usage cost for the most recent run of the agent
|
|
69
69
|
getLastUsageCost() {
|
|
70
70
|
const { modelUsage, modelInfo, defaults } = this.axai;
|
|
71
|
-
|
|
72
|
-
if (!
|
|
71
|
+
// Check if all required properties exist
|
|
72
|
+
if (!modelUsage?.promptTokens || !modelUsage?.completionTokens) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
if (!modelInfo || !defaults?.model) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const currentModelInfo = modelInfo.find((m) => m.name === defaults.model);
|
|
79
|
+
if (!currentModelInfo?.promptTokenCostPer1M || !currentModelInfo?.completionTokenCostPer1M) {
|
|
73
80
|
return null;
|
|
74
81
|
}
|
|
75
82
|
return StateFulAxAgentUsage.calculateCost(modelUsage, currentModelInfo);
|
package/dist/types.d.ts
CHANGED
|
@@ -32,13 +32,22 @@ type FunctionRegistryType = {
|
|
|
32
32
|
};
|
|
33
33
|
/**
|
|
34
34
|
* The usage metrics of the model.
|
|
35
|
-
*
|
|
36
|
-
* completionTokens: number;
|
|
35
|
+
* Supports both direct token properties and nested tokens structure
|
|
37
36
|
*/
|
|
38
|
-
interface
|
|
39
|
-
promptTokens
|
|
40
|
-
completionTokens
|
|
37
|
+
interface ModelUsageBase {
|
|
38
|
+
promptTokens?: number;
|
|
39
|
+
completionTokens?: number;
|
|
40
|
+
}
|
|
41
|
+
interface ModelUsageNested {
|
|
42
|
+
ai?: string;
|
|
43
|
+
model?: string;
|
|
44
|
+
tokens?: {
|
|
45
|
+
totalTokens?: number;
|
|
46
|
+
promptTokens: number;
|
|
47
|
+
completionTokens: number;
|
|
48
|
+
};
|
|
41
49
|
}
|
|
50
|
+
type ModelUsage = ModelUsageBase & ModelUsageNested;
|
|
42
51
|
/**
|
|
43
52
|
* The published cost for using the model.
|
|
44
53
|
* promptTokenCostPer1M: number;
|
package/examples/streaming.ts
CHANGED
|
@@ -11,10 +11,10 @@ const config = {
|
|
|
11
11
|
description: "Completes a user specified task",
|
|
12
12
|
signature:
|
|
13
13
|
'question:string "a question to be answered" -> answer:string "the answer to the question"',
|
|
14
|
-
provider: "
|
|
15
|
-
providerKeyName: "
|
|
14
|
+
provider: "google-gemini",
|
|
15
|
+
providerKeyName: "GEMINI_API_KEY",
|
|
16
16
|
ai: {
|
|
17
|
-
model: "
|
|
17
|
+
model: "gemini-2.0-flash",
|
|
18
18
|
maxTokens: 1000,
|
|
19
19
|
temperature: 0,
|
|
20
20
|
},
|
package/package.json
CHANGED
|
@@ -15,52 +15,75 @@ import type {
|
|
|
15
15
|
export class StateFulAxAgentUsage {
|
|
16
16
|
static STATE_KEY_PREFIX = 'agent_usage_';
|
|
17
17
|
|
|
18
|
-
static calculateCost(modelUsage: ModelUsage, modelInfo: ModelInfo): UsageCost {
|
|
19
|
-
|
|
18
|
+
static calculateCost(modelUsage: ModelUsage, modelInfo: ModelInfo): UsageCost | null {
|
|
19
|
+
// Handle both direct properties and nested tokens structure
|
|
20
|
+
const promptTokens = (modelUsage as any).tokens?.promptTokens ?? modelUsage.promptTokens;
|
|
21
|
+
const completionTokens = (modelUsage as any).tokens?.completionTokens ?? modelUsage.completionTokens;
|
|
20
22
|
const { promptTokenCostPer1M, completionTokenCostPer1M } = modelInfo;
|
|
21
23
|
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
// Return null instead of throwing errors for invalid values
|
|
25
|
+
if (typeof promptTokens !== 'number' || isNaN(promptTokens) ||
|
|
26
|
+
typeof completionTokens !== 'number' || isNaN(completionTokens) ||
|
|
27
|
+
typeof promptTokenCostPer1M !== 'number' || isNaN(promptTokenCostPer1M) ||
|
|
28
|
+
typeof completionTokenCostPer1M !== 'number' || isNaN(completionTokenCostPer1M)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
try {
|
|
33
|
+
// Use Decimal for precise calculations
|
|
34
|
+
const promptCost = new Decimal(promptTokens)
|
|
35
|
+
.div(1000000)
|
|
36
|
+
.mul(promptTokenCostPer1M)
|
|
37
|
+
.toDP(10); // Keep 10 decimal places
|
|
32
38
|
|
|
33
|
-
|
|
39
|
+
const completionCost = new Decimal(completionTokens)
|
|
40
|
+
.div(1000000)
|
|
41
|
+
.mul(completionTokenCostPer1M)
|
|
42
|
+
.toDP(10);
|
|
34
43
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
const totalCost = promptCost.plus(completionCost).toDP(10);
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
promptCost: promptCost.toString(),
|
|
48
|
+
completionCost: completionCost.toString(),
|
|
49
|
+
totalCost: totalCost.toString(),
|
|
50
|
+
tokenMetrics: {
|
|
51
|
+
promptTokens,
|
|
52
|
+
completionTokens,
|
|
53
|
+
totalTokens: promptTokens + completionTokens
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
} catch (error) {
|
|
57
|
+
// If any decimal calculation fails, return null instead of throwing
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
45
60
|
}
|
|
46
61
|
|
|
47
|
-
static trackCostInState(agentName: string, cost: UsageCost, state: StateInstance) {
|
|
62
|
+
static trackCostInState(agentName: string, cost: UsageCost | null, state: StateInstance) {
|
|
63
|
+
// If cost is null, skip tracking
|
|
64
|
+
if (!cost) return;
|
|
65
|
+
|
|
48
66
|
const stateKey = `${this.STATE_KEY_PREFIX}${agentName}`;
|
|
49
67
|
const existingCost = state.get(stateKey) as UsageCost | undefined;
|
|
50
68
|
|
|
51
69
|
if (existingCost) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
try {
|
|
71
|
+
// Aggregate with existing cost using Decimal
|
|
72
|
+
const aggregatedCost: UsageCost = {
|
|
73
|
+
promptCost: new Decimal(existingCost.promptCost).plus(cost.promptCost).toDP(10).toString(),
|
|
74
|
+
completionCost: new Decimal(existingCost.completionCost).plus(cost.completionCost).toDP(10).toString(),
|
|
75
|
+
totalCost: new Decimal(existingCost.totalCost).plus(cost.totalCost).toDP(10).toString(),
|
|
76
|
+
tokenMetrics: {
|
|
77
|
+
promptTokens: existingCost.tokenMetrics.promptTokens + cost.tokenMetrics.promptTokens,
|
|
78
|
+
completionTokens: existingCost.tokenMetrics.completionTokens + cost.tokenMetrics.completionTokens,
|
|
79
|
+
totalTokens: existingCost.tokenMetrics.totalTokens + cost.tokenMetrics.totalTokens
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
state.set(stateKey, aggregatedCost);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
// If aggregation fails, just use the new cost
|
|
85
|
+
state.set(stateKey, cost);
|
|
86
|
+
}
|
|
64
87
|
} else {
|
|
65
88
|
// First time tracking this agent's cost
|
|
66
89
|
state.set(stateKey, cost);
|
package/src/agents/index.ts
CHANGED
|
@@ -144,9 +144,19 @@ class StatefulAxAgent extends AxAgent<any, any> {
|
|
|
144
144
|
// Get the usage cost for the most recent run of the agent
|
|
145
145
|
getLastUsageCost(): UsageCost | null {
|
|
146
146
|
const { modelUsage, modelInfo, defaults } = this.axai;
|
|
147
|
-
const currentModelInfo = modelInfo?.find((m: { name: string }) => m.name === defaults.model);
|
|
148
147
|
|
|
149
|
-
if
|
|
148
|
+
// Check if all required properties exist
|
|
149
|
+
if (!modelUsage?.promptTokens || !modelUsage?.completionTokens) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!modelInfo || !defaults?.model) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const currentModelInfo = modelInfo.find((m: { name: string }) => m.name === defaults.model);
|
|
158
|
+
|
|
159
|
+
if (!currentModelInfo?.promptTokenCostPer1M || !currentModelInfo?.completionTokenCostPer1M) {
|
|
150
160
|
return null;
|
|
151
161
|
}
|
|
152
162
|
|
package/src/types.ts
CHANGED
|
@@ -36,14 +36,25 @@ type FunctionRegistryType = {
|
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* The usage metrics of the model.
|
|
39
|
-
*
|
|
40
|
-
* completionTokens: number;
|
|
39
|
+
* Supports both direct token properties and nested tokens structure
|
|
41
40
|
*/
|
|
42
|
-
interface
|
|
43
|
-
promptTokens
|
|
44
|
-
completionTokens
|
|
41
|
+
interface ModelUsageBase {
|
|
42
|
+
promptTokens?: number;
|
|
43
|
+
completionTokens?: number;
|
|
45
44
|
}
|
|
46
45
|
|
|
46
|
+
interface ModelUsageNested {
|
|
47
|
+
ai?: string;
|
|
48
|
+
model?: string;
|
|
49
|
+
tokens?: {
|
|
50
|
+
totalTokens?: number;
|
|
51
|
+
promptTokens: number;
|
|
52
|
+
completionTokens: number;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
type ModelUsage = ModelUsageBase & ModelUsageNested;
|
|
57
|
+
|
|
47
58
|
/**
|
|
48
59
|
* The published cost for using the model.
|
|
49
60
|
* promptTokenCostPer1M: number;
|