@stackfactor/agent-utils 1.2.10 → 1.2.11

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.
@@ -1 +1 @@
1
- {"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":"AA2BA;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACxC,CAAC;;0CAE2C,GAAG,KAAG,IAAI;wBA+jB/C,MAAM,aACD,MAAM,gBACH,MAAM,SACb,GAAG,EAAE,kBACI,GAAG,UACX,GAAG,KACV,GAAG;sBA0BG,GAAG,UACF,MAAM,UACN,GAAG,eACC,QAAQ,GAAG,IAAI,iBACb,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;oCA4XF,MAAM,UACT,GAAG,UACH,GAAG,oBACO,GAAG,eACT,MAAM,eACN,MAAM,wBACG,OAAO,WACpB,GAAG,cACA,MAAM,UACV,GAAG,EAAE,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;sDAktBF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;0CAt/B8B,GAAG,KAAG,MAAM;+CApjB9C,YAAY,GAAG,IAAI,GAAG,SAAS,aAC7B,MAAM,kBACD,MAAM,UACd,GAAG,KACV,IAAI;mCAokBU,MAAM,mBACJ,MAAM,EAAE,KACxB,MAAM;;AA6hCT,wBASE"}
1
+ {"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":"AAgCA;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACxC,CAAC;;0CAE2C,GAAG,KAAG,IAAI;wBA6lB/C,MAAM,aACD,MAAM,gBACH,MAAM,SACb,GAAG,EAAE,kBACI,GAAG,UACX,GAAG,KACV,GAAG;sBA0BG,GAAG,UACF,MAAM,UACN,GAAG,eACC,QAAQ,GAAG,IAAI,iBACb,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;oCA4XF,MAAM,UACT,GAAG,UACH,GAAG,oBACO,GAAG,eACT,MAAM,eACN,MAAM,wBACG,OAAO,WACpB,GAAG,cACA,MAAM,UACV,GAAG,EAAE,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;sDAstBF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;0CA1/B8B,GAAG,KAAG,MAAM;+CA/jB9C,YAAY,GAAG,IAAI,GAAG,SAAS,aAC7B,MAAM,kBACD,MAAM,UACd,GAAG,KACV,IAAI;mCA+kBU,MAAM,mBACJ,MAAM,EAAE,KACxB,MAAM;;AAiiCT,wBASE"}
@@ -56,7 +56,19 @@ const updateUsageTracker = (tracker, modelName, usage, config) => {
56
56
  if (!tracker.tokens || typeof tracker.tokens !== "object")
57
57
  tracker.tokens = {};
58
58
  const inputTokens = usage.input_tokens || 0;
59
- const outputTokens = usage.output_tokens || 0;
59
+ const visibleOutputTokens = usage.output_tokens || 0;
60
+ const totalTokens = usage.total_tokens || 0;
61
+ // Recover reasoning/"thinking" tokens the provider leaves out of
62
+ // `output_tokens`. Gemini reports its thoughts only in `totalTokenCount`, so
63
+ // `total - input - visibleOutput` is the thinking output the caller was still
64
+ // billed for. Providers that already fold reasoning into `output_tokens`
65
+ // (Anthropic, OpenAI) report `total == input + output`, so this adds 0.
66
+ // Reasoning is charged at the output rate, so we treat it as output for both
67
+ // the token counters and the cost.
68
+ const reasoningTokens = totalTokens > 0
69
+ ? Math.max(0, totalTokens - inputTokens - visibleOutputTokens)
70
+ : 0;
71
+ const outputTokens = visibleOutputTokens + reasoningTokens;
60
72
  const inputRate = getModelRate(modelName, config, "input-token");
61
73
  const outputRate = getModelRate(modelName, config, "output-token");
62
74
  const addedCost = (inputTokens / 1_000_000) * inputRate +
@@ -122,7 +134,12 @@ const updateImageUsageTracker = (tracker, modelName, response, config, provider)
122
134
  imageOutputTokens = Number(um.candidatesTokenCount) || 0;
123
135
  }
124
136
  const textInputRate = getModelRate(modelName, config, "input-token");
125
- const imageInputRate = getModelRate(modelName, config, "image-input-token");
137
+ // Reference-image input tokens are billed at the model's input rate. Configs
138
+ // that don't define a dedicated `<model>-image-input-token-costs` (the common
139
+ // case — image models charge all input at one rate and only differ on output)
140
+ // fall back to the text input rate rather than silently billing image input
141
+ // at $0.
142
+ const imageInputRate = getModelRate(modelName, config, "image-input-token") || textInputRate;
126
143
  const imageOutputRate = getModelRate(modelName, config, "image-output-token");
127
144
  const addedCost = (textInputTokens / 1_000_000) * textInputRate +
128
145
  (imageInputTokens / 1_000_000) * imageInputRate +
@@ -176,6 +193,7 @@ const extractUsageFromInvoke = (response) => {
176
193
  return {
177
194
  input_tokens: um.input_tokens || 0,
178
195
  output_tokens: um.output_tokens || 0,
196
+ total_tokens: um.total_tokens || 0,
179
197
  };
180
198
  }
181
199
  const rm = response.response_metadata;
@@ -183,12 +201,14 @@ const extractUsageFromInvoke = (response) => {
183
201
  return {
184
202
  input_tokens: rm.usage.input_tokens || rm.usage.prompt_tokens || 0,
185
203
  output_tokens: rm.usage.output_tokens || rm.usage.completion_tokens || 0,
204
+ total_tokens: rm.usage.total_tokens || rm.usage.total_token_count || 0,
186
205
  };
187
206
  }
188
207
  if (rm?.tokenUsage) {
189
208
  return {
190
209
  input_tokens: rm.tokenUsage.promptTokens || 0,
191
210
  output_tokens: rm.tokenUsage.completionTokens || 0,
211
+ total_tokens: rm.tokenUsage.totalTokens || 0,
192
212
  };
193
213
  }
194
214
  return null;
@@ -205,6 +225,7 @@ const accumulateChunkUsage = (acc, chunk) => {
205
225
  if (um) {
206
226
  acc.input_tokens += um.input_tokens || 0;
207
227
  acc.output_tokens += um.output_tokens || 0;
228
+ acc.total_tokens += um.total_tokens || 0;
208
229
  return acc;
209
230
  }
210
231
  const rm = chunk.response_metadata;
@@ -212,6 +233,8 @@ const accumulateChunkUsage = (acc, chunk) => {
212
233
  acc.input_tokens += rm.usage.input_tokens || rm.usage.prompt_tokens || 0;
213
234
  acc.output_tokens +=
214
235
  rm.usage.output_tokens || rm.usage.completion_tokens || 0;
236
+ acc.total_tokens +=
237
+ rm.usage.total_tokens || rm.usage.total_token_count || 0;
215
238
  }
216
239
  return acc;
217
240
  };
@@ -224,13 +247,18 @@ const sumAgentResponseUsage = (response) => {
224
247
  const messages = response?.messages;
225
248
  if (!Array.isArray(messages) || messages.length === 0)
226
249
  return null;
227
- const total = { input_tokens: 0, output_tokens: 0 };
250
+ const total = {
251
+ input_tokens: 0,
252
+ output_tokens: 0,
253
+ total_tokens: 0,
254
+ };
228
255
  let found = false;
229
256
  for (const msg of messages) {
230
257
  const um = msg?.usage_metadata;
231
258
  if (um) {
232
259
  total.input_tokens += um.input_tokens || 0;
233
260
  total.output_tokens += um.output_tokens || 0;
261
+ total.total_tokens += um.total_tokens || 0;
234
262
  found = true;
235
263
  }
236
264
  }
@@ -1054,7 +1082,11 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
1054
1082
  while (true) {
1055
1083
  let rawContent = "";
1056
1084
  let chunkCount = 0;
1057
- let streamUsage = { input_tokens: 0, output_tokens: 0 };
1085
+ let streamUsage = {
1086
+ input_tokens: 0,
1087
+ output_tokens: 0,
1088
+ total_tokens: 0,
1089
+ };
1058
1090
  // Inner loop: wait + retry on 429 around stream setup and consumption.
1059
1091
  // Usage is only recorded on a successful stream — partial streams that
1060
1092
  // error out with a rate limit are not counted. A 429 fired mid-stream
@@ -1063,7 +1095,7 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
1063
1095
  while (true) {
1064
1096
  rawContent = "";
1065
1097
  chunkCount = 0;
1066
- streamUsage = { input_tokens: 0, output_tokens: 0 };
1098
+ streamUsage = { input_tokens: 0, output_tokens: 0, total_tokens: 0 };
1067
1099
  try {
1068
1100
  // Honour caller cancellation: passing the signal tears down the
1069
1101
  // upstream HTTP request so a cancelled call stops billing tokens.
@@ -1 +1 @@
1
- {"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":"AA2BA;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACxC,CAAC;;0CAE2C,GAAG,KAAG,IAAI;wBA+jB/C,MAAM,aACD,MAAM,gBACH,MAAM,SACb,GAAG,EAAE,kBACI,GAAG,UACX,GAAG,KACV,GAAG;sBA0BG,GAAG,UACF,MAAM,UACN,GAAG,eACC,QAAQ,GAAG,IAAI,iBACb,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;oCA4XF,MAAM,UACT,GAAG,UACH,GAAG,oBACO,GAAG,eACT,MAAM,eACN,MAAM,wBACG,OAAO,WACpB,GAAG,cACA,MAAM,UACV,GAAG,EAAE,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;sDAktBF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;0CAt/B8B,GAAG,KAAG,MAAM;+CApjB9C,YAAY,GAAG,IAAI,GAAG,SAAS,aAC7B,MAAM,kBACD,MAAM,UACd,GAAG,KACV,IAAI;mCAokBU,MAAM,mBACJ,MAAM,EAAE,KACxB,MAAM;;AA6hCT,wBASE"}
1
+ {"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":"AAgCA;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACxC,CAAC;;0CAE2C,GAAG,KAAG,IAAI;wBA6lB/C,MAAM,aACD,MAAM,gBACH,MAAM,SACb,GAAG,EAAE,kBACI,GAAG,UACX,GAAG,KACV,GAAG;sBA0BG,GAAG,UACF,MAAM,UACN,GAAG,eACC,QAAQ,GAAG,IAAI,iBACb,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;oCA4XF,MAAM,UACT,GAAG,UACH,GAAG,oBACO,GAAG,eACT,MAAM,eACN,MAAM,wBACG,OAAO,WACpB,GAAG,cACA,MAAM,UACV,GAAG,EAAE,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;sDAstBF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;0CA1/B8B,GAAG,KAAG,MAAM;+CA/jB9C,YAAY,GAAG,IAAI,GAAG,SAAS,aAC7B,MAAM,kBACD,MAAM,UACd,GAAG,KACV,IAAI;mCA+kBU,MAAM,mBACJ,MAAM,EAAE,KACxB,MAAM;;AAiiCT,wBASE"}
@@ -51,7 +51,19 @@ const updateUsageTracker = (tracker, modelName, usage, config) => {
51
51
  if (!tracker.tokens || typeof tracker.tokens !== "object")
52
52
  tracker.tokens = {};
53
53
  const inputTokens = usage.input_tokens || 0;
54
- const outputTokens = usage.output_tokens || 0;
54
+ const visibleOutputTokens = usage.output_tokens || 0;
55
+ const totalTokens = usage.total_tokens || 0;
56
+ // Recover reasoning/"thinking" tokens the provider leaves out of
57
+ // `output_tokens`. Gemini reports its thoughts only in `totalTokenCount`, so
58
+ // `total - input - visibleOutput` is the thinking output the caller was still
59
+ // billed for. Providers that already fold reasoning into `output_tokens`
60
+ // (Anthropic, OpenAI) report `total == input + output`, so this adds 0.
61
+ // Reasoning is charged at the output rate, so we treat it as output for both
62
+ // the token counters and the cost.
63
+ const reasoningTokens = totalTokens > 0
64
+ ? Math.max(0, totalTokens - inputTokens - visibleOutputTokens)
65
+ : 0;
66
+ const outputTokens = visibleOutputTokens + reasoningTokens;
55
67
  const inputRate = getModelRate(modelName, config, "input-token");
56
68
  const outputRate = getModelRate(modelName, config, "output-token");
57
69
  const addedCost = (inputTokens / 1_000_000) * inputRate +
@@ -117,7 +129,12 @@ const updateImageUsageTracker = (tracker, modelName, response, config, provider)
117
129
  imageOutputTokens = Number(um.candidatesTokenCount) || 0;
118
130
  }
119
131
  const textInputRate = getModelRate(modelName, config, "input-token");
120
- const imageInputRate = getModelRate(modelName, config, "image-input-token");
132
+ // Reference-image input tokens are billed at the model's input rate. Configs
133
+ // that don't define a dedicated `<model>-image-input-token-costs` (the common
134
+ // case — image models charge all input at one rate and only differ on output)
135
+ // fall back to the text input rate rather than silently billing image input
136
+ // at $0.
137
+ const imageInputRate = getModelRate(modelName, config, "image-input-token") || textInputRate;
121
138
  const imageOutputRate = getModelRate(modelName, config, "image-output-token");
122
139
  const addedCost = (textInputTokens / 1_000_000) * textInputRate +
123
140
  (imageInputTokens / 1_000_000) * imageInputRate +
@@ -171,6 +188,7 @@ const extractUsageFromInvoke = (response) => {
171
188
  return {
172
189
  input_tokens: um.input_tokens || 0,
173
190
  output_tokens: um.output_tokens || 0,
191
+ total_tokens: um.total_tokens || 0,
174
192
  };
175
193
  }
176
194
  const rm = response.response_metadata;
@@ -178,12 +196,14 @@ const extractUsageFromInvoke = (response) => {
178
196
  return {
179
197
  input_tokens: rm.usage.input_tokens || rm.usage.prompt_tokens || 0,
180
198
  output_tokens: rm.usage.output_tokens || rm.usage.completion_tokens || 0,
199
+ total_tokens: rm.usage.total_tokens || rm.usage.total_token_count || 0,
181
200
  };
182
201
  }
183
202
  if (rm?.tokenUsage) {
184
203
  return {
185
204
  input_tokens: rm.tokenUsage.promptTokens || 0,
186
205
  output_tokens: rm.tokenUsage.completionTokens || 0,
206
+ total_tokens: rm.tokenUsage.totalTokens || 0,
187
207
  };
188
208
  }
189
209
  return null;
@@ -200,6 +220,7 @@ const accumulateChunkUsage = (acc, chunk) => {
200
220
  if (um) {
201
221
  acc.input_tokens += um.input_tokens || 0;
202
222
  acc.output_tokens += um.output_tokens || 0;
223
+ acc.total_tokens += um.total_tokens || 0;
203
224
  return acc;
204
225
  }
205
226
  const rm = chunk.response_metadata;
@@ -207,6 +228,8 @@ const accumulateChunkUsage = (acc, chunk) => {
207
228
  acc.input_tokens += rm.usage.input_tokens || rm.usage.prompt_tokens || 0;
208
229
  acc.output_tokens +=
209
230
  rm.usage.output_tokens || rm.usage.completion_tokens || 0;
231
+ acc.total_tokens +=
232
+ rm.usage.total_tokens || rm.usage.total_token_count || 0;
210
233
  }
211
234
  return acc;
212
235
  };
@@ -219,13 +242,18 @@ const sumAgentResponseUsage = (response) => {
219
242
  const messages = response?.messages;
220
243
  if (!Array.isArray(messages) || messages.length === 0)
221
244
  return null;
222
- const total = { input_tokens: 0, output_tokens: 0 };
245
+ const total = {
246
+ input_tokens: 0,
247
+ output_tokens: 0,
248
+ total_tokens: 0,
249
+ };
223
250
  let found = false;
224
251
  for (const msg of messages) {
225
252
  const um = msg?.usage_metadata;
226
253
  if (um) {
227
254
  total.input_tokens += um.input_tokens || 0;
228
255
  total.output_tokens += um.output_tokens || 0;
256
+ total.total_tokens += um.total_tokens || 0;
229
257
  found = true;
230
258
  }
231
259
  }
@@ -1049,7 +1077,11 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
1049
1077
  while (true) {
1050
1078
  let rawContent = "";
1051
1079
  let chunkCount = 0;
1052
- let streamUsage = { input_tokens: 0, output_tokens: 0 };
1080
+ let streamUsage = {
1081
+ input_tokens: 0,
1082
+ output_tokens: 0,
1083
+ total_tokens: 0,
1084
+ };
1053
1085
  // Inner loop: wait + retry on 429 around stream setup and consumption.
1054
1086
  // Usage is only recorded on a successful stream — partial streams that
1055
1087
  // error out with a rate limit are not counted. A 429 fired mid-stream
@@ -1058,7 +1090,7 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
1058
1090
  while (true) {
1059
1091
  rawContent = "";
1060
1092
  chunkCount = 0;
1061
- streamUsage = { input_tokens: 0, output_tokens: 0 };
1093
+ streamUsage = { input_tokens: 0, output_tokens: 0, total_tokens: 0 };
1062
1094
  try {
1063
1095
  // Honour caller cancellation: passing the signal tears down the
1064
1096
  // upstream HTTP request so a cancelled call stops billing tokens.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.2.10",
6
+ "version": "1.2.11",
7
7
  "description": "",
8
8
  "main": "dist/cjs/index.js",
9
9
  "module": "dist/esm/index.js",