@stackfactor/agent-utils 1.1.0 → 1.1.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/dist/cjs/langChain.d.ts.map +1 -1
- package/dist/cjs/langChain.js +58 -30
- package/dist/esm/langChain.d.ts.map +1 -1
- package/dist/esm/langChain.js +58 -30
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":";0CAiD6C,GAAG,KAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":";0CAiD6C,GAAG,KAAG,IAAI;wBAqgB/C,MAAM,aACD,MAAM,gBACH,MAAM,SACb,GAAG,EAAE,kBACI,GAAG,UACX,GAAG,KACV,GAAG;sBAyBG,GAAG,UACF,MAAM,UACN,GAAG,eACC,QAAQ,GAAG,IAAI,KAC1B,OAAO,CAAC,GAAG,CAAC;oCAqXF,MAAM,UACT,GAAG,UACH,GAAG,oBACO,GAAG,eACT,MAAM,eACN,MAAM,wBACG,OAAO,WACpB,GAAG,cACA,MAAM,UACV,GAAG,EAAE,KACX,OAAO,CAAC,GAAG,CAAC;sDAosBF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,KACX,OAAO,CAAC,GAAG,CAAC;0CAn+B8B,GAAG,KAAG,MAAM;mCAoBxC,MAAM,mBACJ,MAAM,EAAE,KACxB,MAAM;;AAwgCT,wBAQE"}
|
package/dist/cjs/langChain.js
CHANGED
|
@@ -68,40 +68,68 @@ const recordCost = (cost) => {
|
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
70
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
71
|
+
* Reads a per-model rate from the flat cost constants the integration defines
|
|
72
|
+
* in its `config.yaml` (exposed on the config object), e.g.
|
|
73
|
+
* `claude-opus-4-7-input-token-costs`. Returns `null` when the constant is
|
|
74
|
+
* absent or not numeric, in which case cost recording becomes a no-op (the
|
|
75
|
+
* call still succeeds — pricing is the integration's configuration concern).
|
|
75
76
|
*/
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
if (!pricing)
|
|
77
|
+
const getModelRate = (modelName, config, kind) => {
|
|
78
|
+
if (!config || !modelName)
|
|
79
79
|
return null;
|
|
80
|
-
|
|
80
|
+
const rate = Number(config[`${modelName}-${kind}-costs`]);
|
|
81
|
+
return Number.isFinite(rate) ? rate : null;
|
|
81
82
|
};
|
|
82
83
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
84
|
+
* Accumulates the per-model cost breakdown on `global.quota.byModel` so the
|
|
85
|
+
* agent can report input vs output spend per model to the UI. No-ops when the
|
|
86
|
+
* quota global is absent.
|
|
85
87
|
*/
|
|
86
|
-
const
|
|
88
|
+
const recordModelBreakdown = (modelName, inputCost, outputCost, imageCost) => {
|
|
89
|
+
const quota = globalThis.quota;
|
|
90
|
+
if (!quota || !modelName)
|
|
91
|
+
return;
|
|
92
|
+
if (!quota.byModel || typeof quota.byModel !== "object")
|
|
93
|
+
quota.byModel = {};
|
|
94
|
+
const entry = (quota.byModel[modelName] ||= {
|
|
95
|
+
inputCost: 0,
|
|
96
|
+
outputCost: 0,
|
|
97
|
+
imageCost: 0,
|
|
98
|
+
});
|
|
99
|
+
if (Number.isFinite(inputCost) && inputCost > 0)
|
|
100
|
+
entry.inputCost += inputCost;
|
|
101
|
+
if (Number.isFinite(outputCost) && outputCost > 0)
|
|
102
|
+
entry.outputCost += outputCost;
|
|
103
|
+
if (Number.isFinite(imageCost) && imageCost > 0)
|
|
104
|
+
entry.imageCost += imageCost;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Computes and records the USD cost of a text LLM call from the
|
|
108
|
+
* `<model>-input-token-costs` / `<model>-output-token-costs` constants
|
|
109
|
+
* (dollars per million tokens). Updates both the session total
|
|
110
|
+
* (`quota.usedThisSession` / `quota.remaining`) and the per-model breakdown
|
|
111
|
+
* (`quota.byModel`).
|
|
112
|
+
*/
|
|
113
|
+
const recordTextCost = (modelName, usage, config) => {
|
|
87
114
|
if (!usage)
|
|
88
|
-
return
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
115
|
+
return;
|
|
116
|
+
const inputRate = getModelRate(modelName, config, "input-token") || 0;
|
|
117
|
+
const outputRate = getModelRate(modelName, config, "output-token") || 0;
|
|
118
|
+
const inputCost = ((usage.input_tokens || 0) / 1_000_000) * inputRate;
|
|
119
|
+
const outputCost = ((usage.output_tokens || 0) / 1_000_000) * outputRate;
|
|
120
|
+
recordCost(inputCost + outputCost);
|
|
121
|
+
recordModelBreakdown(modelName, inputCost, outputCost, 0);
|
|
95
122
|
};
|
|
96
123
|
/**
|
|
97
|
-
* Computes USD cost
|
|
98
|
-
*
|
|
124
|
+
* Computes and records the USD cost of an image generation call from the
|
|
125
|
+
* `<model>-image-costs` constant (dollars per generated image). Updates both
|
|
126
|
+
* the session total and the per-model breakdown.
|
|
99
127
|
*/
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
128
|
+
const recordImageCost = (modelName, numImages, config) => {
|
|
129
|
+
const rate = getModelRate(modelName, config, "image") || 0;
|
|
130
|
+
const imageCost = (numImages || 0) * rate;
|
|
131
|
+
recordCost(imageCost);
|
|
132
|
+
recordModelBreakdown(modelName, 0, 0, imageCost);
|
|
105
133
|
};
|
|
106
134
|
/**
|
|
107
135
|
* Extracts a normalized token-usage object from a single LangChain `invoke()`
|
|
@@ -569,7 +597,7 @@ const runAgent = async (agent, prompt, config, onProgress = null) => {
|
|
|
569
597
|
throw err;
|
|
570
598
|
}
|
|
571
599
|
}
|
|
572
|
-
|
|
600
|
+
recordTextCost(modelName, sumAgentResponseUsage(response), config);
|
|
573
601
|
const endTime = Date.now();
|
|
574
602
|
const duration = endTime - startTime;
|
|
575
603
|
logger_js_1.default.log(null, logger_js_1.default.levels.info, `Agent "${agent.options?.name}" completed in ${Math.round(duration / 1000)} seconds.`);
|
|
@@ -1044,7 +1072,7 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
|
|
|
1044
1072
|
throw err;
|
|
1045
1073
|
}
|
|
1046
1074
|
}
|
|
1047
|
-
|
|
1075
|
+
recordTextCost(modelName, streamUsage, config);
|
|
1048
1076
|
if (!rawContent) {
|
|
1049
1077
|
throw errorHandling_js_1.default.create(const_js_1.default.HTTP_CODES.INTERNAL_SERVER_ERROR, "LLM returned no content");
|
|
1050
1078
|
}
|
|
@@ -1144,7 +1172,7 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
|
|
|
1144
1172
|
throw err;
|
|
1145
1173
|
}
|
|
1146
1174
|
}
|
|
1147
|
-
|
|
1175
|
+
recordTextCost(modelName, extractUsageFromInvoke(response), config);
|
|
1148
1176
|
const rawContent = response?.content || response;
|
|
1149
1177
|
// If not expecting JSON, return raw content directly
|
|
1150
1178
|
if (!expectsJsonResponse) {
|
|
@@ -1252,7 +1280,7 @@ const generateImageWithOpenAI = async (modelName, config, prompt, options) => {
|
|
|
1252
1280
|
}
|
|
1253
1281
|
assertQuotaAvailable();
|
|
1254
1282
|
const response = await openai.images.generate(requestParams);
|
|
1255
|
-
|
|
1283
|
+
recordImageCost(modelName, response.data?.length || n, config);
|
|
1256
1284
|
// Format response based on number of images
|
|
1257
1285
|
if (n === 1) {
|
|
1258
1286
|
const imageData = response.data[0];
|
|
@@ -1369,7 +1397,7 @@ const generateImageWithGoogle = async (modelName, config, prompt, options) => {
|
|
|
1369
1397
|
if (images.length === 0) {
|
|
1370
1398
|
throw errorHandling_js_1.default.create(const_js_1.default.HTTP_CODES.INTERNAL_SERVER_ERROR, `No images were generated by ${modelName}`);
|
|
1371
1399
|
}
|
|
1372
|
-
|
|
1400
|
+
recordImageCost(modelName, images.length, config);
|
|
1373
1401
|
if (numberOfImages === 1 || images.length === 1) {
|
|
1374
1402
|
return images[0];
|
|
1375
1403
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":";0CAiD6C,GAAG,KAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":";0CAiD6C,GAAG,KAAG,IAAI;wBAqgB/C,MAAM,aACD,MAAM,gBACH,MAAM,SACb,GAAG,EAAE,kBACI,GAAG,UACX,GAAG,KACV,GAAG;sBAyBG,GAAG,UACF,MAAM,UACN,GAAG,eACC,QAAQ,GAAG,IAAI,KAC1B,OAAO,CAAC,GAAG,CAAC;oCAqXF,MAAM,UACT,GAAG,UACH,GAAG,oBACO,GAAG,eACT,MAAM,eACN,MAAM,wBACG,OAAO,WACpB,GAAG,cACA,MAAM,UACV,GAAG,EAAE,KACX,OAAO,CAAC,GAAG,CAAC;sDAosBF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,KACX,OAAO,CAAC,GAAG,CAAC;0CAn+B8B,GAAG,KAAG,MAAM;mCAoBxC,MAAM,mBACJ,MAAM,EAAE,KACxB,MAAM;;AAwgCT,wBAQE"}
|
package/dist/esm/langChain.js
CHANGED
|
@@ -63,40 +63,68 @@ const recordCost = (cost) => {
|
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
66
|
+
* Reads a per-model rate from the flat cost constants the integration defines
|
|
67
|
+
* in its `config.yaml` (exposed on the config object), e.g.
|
|
68
|
+
* `claude-opus-4-7-input-token-costs`. Returns `null` when the constant is
|
|
69
|
+
* absent or not numeric, in which case cost recording becomes a no-op (the
|
|
70
|
+
* call still succeeds — pricing is the integration's configuration concern).
|
|
70
71
|
*/
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
if (!pricing)
|
|
72
|
+
const getModelRate = (modelName, config, kind) => {
|
|
73
|
+
if (!config || !modelName)
|
|
74
74
|
return null;
|
|
75
|
-
|
|
75
|
+
const rate = Number(config[`${modelName}-${kind}-costs`]);
|
|
76
|
+
return Number.isFinite(rate) ? rate : null;
|
|
76
77
|
};
|
|
77
78
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
79
|
+
* Accumulates the per-model cost breakdown on `global.quota.byModel` so the
|
|
80
|
+
* agent can report input vs output spend per model to the UI. No-ops when the
|
|
81
|
+
* quota global is absent.
|
|
80
82
|
*/
|
|
81
|
-
const
|
|
83
|
+
const recordModelBreakdown = (modelName, inputCost, outputCost, imageCost) => {
|
|
84
|
+
const quota = globalThis.quota;
|
|
85
|
+
if (!quota || !modelName)
|
|
86
|
+
return;
|
|
87
|
+
if (!quota.byModel || typeof quota.byModel !== "object")
|
|
88
|
+
quota.byModel = {};
|
|
89
|
+
const entry = (quota.byModel[modelName] ||= {
|
|
90
|
+
inputCost: 0,
|
|
91
|
+
outputCost: 0,
|
|
92
|
+
imageCost: 0,
|
|
93
|
+
});
|
|
94
|
+
if (Number.isFinite(inputCost) && inputCost > 0)
|
|
95
|
+
entry.inputCost += inputCost;
|
|
96
|
+
if (Number.isFinite(outputCost) && outputCost > 0)
|
|
97
|
+
entry.outputCost += outputCost;
|
|
98
|
+
if (Number.isFinite(imageCost) && imageCost > 0)
|
|
99
|
+
entry.imageCost += imageCost;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Computes and records the USD cost of a text LLM call from the
|
|
103
|
+
* `<model>-input-token-costs` / `<model>-output-token-costs` constants
|
|
104
|
+
* (dollars per million tokens). Updates both the session total
|
|
105
|
+
* (`quota.usedThisSession` / `quota.remaining`) and the per-model breakdown
|
|
106
|
+
* (`quota.byModel`).
|
|
107
|
+
*/
|
|
108
|
+
const recordTextCost = (modelName, usage, config) => {
|
|
82
109
|
if (!usage)
|
|
83
|
-
return
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
110
|
+
return;
|
|
111
|
+
const inputRate = getModelRate(modelName, config, "input-token") || 0;
|
|
112
|
+
const outputRate = getModelRate(modelName, config, "output-token") || 0;
|
|
113
|
+
const inputCost = ((usage.input_tokens || 0) / 1_000_000) * inputRate;
|
|
114
|
+
const outputCost = ((usage.output_tokens || 0) / 1_000_000) * outputRate;
|
|
115
|
+
recordCost(inputCost + outputCost);
|
|
116
|
+
recordModelBreakdown(modelName, inputCost, outputCost, 0);
|
|
90
117
|
};
|
|
91
118
|
/**
|
|
92
|
-
* Computes USD cost
|
|
93
|
-
*
|
|
119
|
+
* Computes and records the USD cost of an image generation call from the
|
|
120
|
+
* `<model>-image-costs` constant (dollars per generated image). Updates both
|
|
121
|
+
* the session total and the per-model breakdown.
|
|
94
122
|
*/
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
123
|
+
const recordImageCost = (modelName, numImages, config) => {
|
|
124
|
+
const rate = getModelRate(modelName, config, "image") || 0;
|
|
125
|
+
const imageCost = (numImages || 0) * rate;
|
|
126
|
+
recordCost(imageCost);
|
|
127
|
+
recordModelBreakdown(modelName, 0, 0, imageCost);
|
|
100
128
|
};
|
|
101
129
|
/**
|
|
102
130
|
* Extracts a normalized token-usage object from a single LangChain `invoke()`
|
|
@@ -564,7 +592,7 @@ const runAgent = async (agent, prompt, config, onProgress = null) => {
|
|
|
564
592
|
throw err;
|
|
565
593
|
}
|
|
566
594
|
}
|
|
567
|
-
|
|
595
|
+
recordTextCost(modelName, sumAgentResponseUsage(response), config);
|
|
568
596
|
const endTime = Date.now();
|
|
569
597
|
const duration = endTime - startTime;
|
|
570
598
|
logger.log(null, logger.levels.info, `Agent "${agent.options?.name}" completed in ${Math.round(duration / 1000)} seconds.`);
|
|
@@ -1039,7 +1067,7 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
|
|
|
1039
1067
|
throw err;
|
|
1040
1068
|
}
|
|
1041
1069
|
}
|
|
1042
|
-
|
|
1070
|
+
recordTextCost(modelName, streamUsage, config);
|
|
1043
1071
|
if (!rawContent) {
|
|
1044
1072
|
throw errorHandlingHelper.create(constants.HTTP_CODES.INTERNAL_SERVER_ERROR, "LLM returned no content");
|
|
1045
1073
|
}
|
|
@@ -1139,7 +1167,7 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
|
|
|
1139
1167
|
throw err;
|
|
1140
1168
|
}
|
|
1141
1169
|
}
|
|
1142
|
-
|
|
1170
|
+
recordTextCost(modelName, extractUsageFromInvoke(response), config);
|
|
1143
1171
|
const rawContent = response?.content || response;
|
|
1144
1172
|
// If not expecting JSON, return raw content directly
|
|
1145
1173
|
if (!expectsJsonResponse) {
|
|
@@ -1247,7 +1275,7 @@ const generateImageWithOpenAI = async (modelName, config, prompt, options) => {
|
|
|
1247
1275
|
}
|
|
1248
1276
|
assertQuotaAvailable();
|
|
1249
1277
|
const response = await openai.images.generate(requestParams);
|
|
1250
|
-
|
|
1278
|
+
recordImageCost(modelName, response.data?.length || n, config);
|
|
1251
1279
|
// Format response based on number of images
|
|
1252
1280
|
if (n === 1) {
|
|
1253
1281
|
const imageData = response.data[0];
|
|
@@ -1364,7 +1392,7 @@ const generateImageWithGoogle = async (modelName, config, prompt, options) => {
|
|
|
1364
1392
|
if (images.length === 0) {
|
|
1365
1393
|
throw errorHandlingHelper.create(constants.HTTP_CODES.INTERNAL_SERVER_ERROR, `No images were generated by ${modelName}`);
|
|
1366
1394
|
}
|
|
1367
|
-
|
|
1395
|
+
recordImageCost(modelName, images.length, config);
|
|
1368
1396
|
if (numberOfImages === 1 || images.length === 1) {
|
|
1369
1397
|
return images[0];
|
|
1370
1398
|
}
|