@msm-core/mini 0.5.1 → 0.5.2

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 CHANGED
@@ -5,6 +5,31 @@ Follows [Semantic Versioning](https://semver.org/).
5
5
 
6
6
  ---
7
7
 
8
+ ## [0.5.2] — 2026-07-01
9
+
10
+ ### Fixed
11
+
12
+ - **The Gemini brain now reports token usage + cost on the tool-call path.** It
13
+ previously returned a bare `{ orchestration }` there (only the text path carried
14
+ usage/cost), so the loop's `costCapPerTask` accrued $0 on exactly the iterations
15
+ that dominate an agentic run — the cost cap never fired on the primary provider.
16
+ Both paths now compute usage + cost once, via the shared pricing table
17
+ (`computeCostUsd`) instead of hardcoded Flash rates, so non-Flash models bill
18
+ correctly. Locked with `tests/gemini-usage.test.ts`.
19
+
20
+ ### Added
21
+
22
+ - Pricing table entry for `gemini-2.5-pro` (Pro agents previously had no cost tracking).
23
+
24
+ ## [0.5.1] — 2026-06-30
25
+
26
+ ### Added
27
+
28
+ - **Array tool-parameters.** `ToolParameter.items` is now forwarded to every
29
+ provider (Gemini included), so an array-typed tool parameter (e.g. a list of
30
+ template variables) is described to the model instead of being dropped — which
31
+ had caused arrays to 400 on Gemini.
32
+
8
33
  ## [0.5.0] — 2026-06-30
9
34
 
10
35
  Brain-parity + guard-integrity release from the 2026-06 SDK audit (H1, H2, H10, M1).
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { withRetry } from "./retry.js";
6
6
  import { foldToolResults } from "./tool-context.js";
7
+ import { computeCostUsd } from "./pricing.js";
7
8
  export function createGeminiBrain(opts) {
8
9
  const model = opts.model ?? "gemini-2.5-flash";
9
10
  return {
@@ -62,6 +63,20 @@ export function createGeminiBrain(opts) {
62
63
  const result = await withRetry(() => geminiModel.generateContent(request, input.signal ? { signal: input.signal } : {}), input.signal ? { signal: input.signal } : {});
63
64
  const response = result.response;
64
65
  const parts = response?.candidates?.[0]?.content?.parts ?? [];
66
+ // Token usage + cost — computed ONCE and returned on BOTH the tool-call and text
67
+ // paths. Most iterations of an agentic run are tool calls, so omitting usage/cost
68
+ // there (as before) left the loop's cost cap seeing $0 and never firing. Price via
69
+ // the shared table (not hardcoded Flash rates) so gemini-2.5-pro bills correctly.
70
+ const usageMeta = response?.usageMetadata;
71
+ const inputTokens = usageMeta?.promptTokenCount;
72
+ const outputTokens = usageMeta?.candidatesTokenCount;
73
+ const usage = inputTokens !== undefined || outputTokens !== undefined
74
+ ? {
75
+ ...(inputTokens !== undefined ? { inputTokens } : {}),
76
+ ...(outputTokens !== undefined ? { outputTokens } : {}),
77
+ }
78
+ : undefined;
79
+ const costUsd = computeCostUsd(model, inputTokens, outputTokens);
65
80
  // Check for function call
66
81
  const fnCallPart = parts.find((p) => "functionCall" in p && p.functionCall);
67
82
  if (fnCallPart &&
@@ -74,31 +89,16 @@ export function createGeminiBrain(opts) {
74
89
  tool_name: fc.name,
75
90
  tool_params: fc.args,
76
91
  };
77
- return { orchestration };
92
+ return { orchestration, costUsd, ...(usage ? { usage } : {}) };
78
93
  }
79
94
  // Text response
80
95
  const textPart = parts.find((p) => "text" in p && typeof p.text === "string");
81
96
  const text = textPart && "text" in textPart ? textPart.text : "";
82
- // Token usage
83
- const usage = response?.usageMetadata;
84
- const inputTokens = usage?.promptTokenCount;
85
- const outputTokens = usage?.candidatesTokenCount;
86
97
  return {
87
98
  generation: { response_text: text },
88
99
  orchestration: { action: "respond", confidence: 0.95 },
89
- // Gemini 2.5 Flash pricing: $0.075/1M input, $0.30/1M output
90
- costUsd: usage
91
- ? (usage.promptTokenCount ?? 0) * 0.000_000_075 +
92
- (usage.candidatesTokenCount ?? 0) * 0.0000003
93
- : 0,
94
- ...(inputTokens !== undefined || outputTokens !== undefined
95
- ? {
96
- usage: {
97
- ...(inputTokens !== undefined ? { inputTokens } : {}),
98
- ...(outputTokens !== undefined ? { outputTokens } : {}),
99
- },
100
- }
101
- : {}),
100
+ costUsd,
101
+ ...(usage ? { usage } : {}),
102
102
  };
103
103
  },
104
104
  };
@@ -24,6 +24,7 @@ export const PRICE_PER_MILLION = {
24
24
  "gpt-4o": { input: 2.5, output: 10 },
25
25
  // Google Gemini (public pricing)
26
26
  "gemini-2.5-flash": { input: 0.075, output: 0.3 },
27
+ "gemini-2.5-pro": { input: 1.25, output: 10 },
27
28
  };
28
29
  /**
29
30
  * Cost in USD for one call. Returns 0 when the model is unknown or usage is
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@msm-core/mini",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Portable AI agent execution loop — brain-agnostic, zero embedded databases",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",