compute-cfo 0.1.0 → 0.2.0

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/pricing.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Model pricing database for OpenAI and Anthropic.
2
+ * Model pricing database for OpenAI, Anthropic, Google Gemini, and Mistral.
3
3
  * Prices are in USD per 1 million tokens. Updated March 2026.
4
4
  */
5
5
  export interface ModelPrice {
package/dist/pricing.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * Model pricing database for OpenAI and Anthropic.
3
+ * Model pricing database for OpenAI, Anthropic, Google Gemini, and Mistral.
4
4
  * Prices are in USD per 1 million tokens. Updated March 2026.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -52,6 +52,23 @@ const MODEL_PRICES = {
52
52
  'claude-3-opus': { inputPerMillion: 15.0, outputPerMillion: 75.0 },
53
53
  'claude-3-sonnet': { inputPerMillion: 3.0, outputPerMillion: 15.0 },
54
54
  'claude-3-haiku': { inputPerMillion: 0.25, outputPerMillion: 1.25 },
55
+ // ── Google Gemini ─────────────────────────────────────────
56
+ 'gemini-2.5-pro': { inputPerMillion: 1.25, outputPerMillion: 10.0 },
57
+ 'gemini-2.5-flash': { inputPerMillion: 0.3, outputPerMillion: 2.5 },
58
+ 'gemini-2.5-flash-lite': { inputPerMillion: 0.1, outputPerMillion: 0.4 },
59
+ 'gemini-2.0-flash': { inputPerMillion: 0.1, outputPerMillion: 0.4 },
60
+ 'gemini-1.5-pro': { inputPerMillion: 1.25, outputPerMillion: 5.0 },
61
+ 'gemini-1.5-flash': { inputPerMillion: 0.075, outputPerMillion: 0.3 },
62
+ 'gemini-1.5-flash-8b': { inputPerMillion: 0.0375, outputPerMillion: 0.15 },
63
+ 'gemini-embedding': { inputPerMillion: 0.15, outputPerMillion: 0 },
64
+ // ── Mistral ───────────────────────────────────────────────
65
+ 'mistral-large-latest': { inputPerMillion: 0.5, outputPerMillion: 1.5 },
66
+ 'mistral-medium-latest': { inputPerMillion: 0.4, outputPerMillion: 2.0 },
67
+ 'mistral-small-latest': { inputPerMillion: 0.03, outputPerMillion: 0.11 },
68
+ 'codestral-latest': { inputPerMillion: 0.3, outputPerMillion: 0.9 },
69
+ 'pixtral-large-latest': { inputPerMillion: 2.0, outputPerMillion: 6.0 },
70
+ 'mistral-nemo': { inputPerMillion: 0.02, outputPerMillion: 0.05 },
71
+ 'pixtral-12b': { inputPerMillion: 0.15, outputPerMillion: 0.15 },
55
72
  };
56
73
  const ALIASES = {
57
74
  'gpt-4o-2024-11-20': 'gpt-4o',
@@ -66,6 +83,19 @@ const ALIASES = {
66
83
  'gpt-3.5-turbo-1106': 'gpt-3.5-turbo',
67
84
  'o3-2025-04-16': 'o3',
68
85
  'o4-mini-2025-04-16': 'o4-mini',
86
+ // Gemini aliases
87
+ 'models/gemini-2.5-pro': 'gemini-2.5-pro',
88
+ 'models/gemini-2.5-flash': 'gemini-2.5-flash',
89
+ 'models/gemini-2.5-flash-lite': 'gemini-2.5-flash-lite',
90
+ 'models/gemini-2.0-flash': 'gemini-2.0-flash',
91
+ 'models/gemini-1.5-pro': 'gemini-1.5-pro',
92
+ 'models/gemini-1.5-flash': 'gemini-1.5-flash',
93
+ 'models/gemini-1.5-flash-8b': 'gemini-1.5-flash-8b',
94
+ // Mistral aliases
95
+ 'mistral-large-2501': 'mistral-large-latest',
96
+ 'mistral-medium-2505': 'mistral-medium-latest',
97
+ 'mistral-small-2503': 'mistral-small-latest',
98
+ 'codestral-2501': 'codestral-latest',
69
99
  };
70
100
  function resolveModel(model) {
71
101
  return ALIASES[model] ?? model;
package/dist/wrapper.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Drop-in wrapper for OpenAI and Anthropic SDK clients.
2
+ * Drop-in wrapper for OpenAI, Anthropic, Google Gemini, and Mistral SDK clients.
3
3
  */
4
4
  import { CostTracker } from './tracker';
5
5
  export interface WrapOptions {
package/dist/wrapper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * Drop-in wrapper for OpenAI and Anthropic SDK clients.
3
+ * Drop-in wrapper for OpenAI, Anthropic, Google Gemini, and Mistral SDK clients.
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.wrap = wrap;
@@ -25,7 +25,13 @@ function wrap(client, options) {
25
25
  if ('messages' in client && typeof client.messages?.create === 'function') {
26
26
  return wrapAnthropic(client, tracker);
27
27
  }
28
- throw new TypeError(`Unsupported client type. Supported: OpenAI, Anthropic`);
28
+ if ('models' in client && typeof client.models?.generateContent === 'function') {
29
+ return wrapGemini(client, tracker);
30
+ }
31
+ if ('chat' in client && typeof client.chat?.complete === 'function') {
32
+ return wrapMistral(client, tracker);
33
+ }
34
+ throw new TypeError(`Unsupported client type. Supported: OpenAI, Anthropic, Google Gemini, Mistral`);
29
35
  }
30
36
  function wrapOpenAI(client, tracker) {
31
37
  const originalCreate = client.chat.completions.create.bind(client.chat.completions);
@@ -78,6 +84,94 @@ function wrapOpenAI(client, tracker) {
78
84
  },
79
85
  });
80
86
  }
87
+ function wrapGemini(client, tracker) {
88
+ const originalGenerateContent = client.models.generateContent.bind(client.models);
89
+ const trackedGenerateContent = async (params) => {
90
+ const { compute_cfo_tags, ...rest } = params ?? {};
91
+ const tags = compute_cfo_tags && typeof compute_cfo_tags === 'object' ? { ...compute_cfo_tags } : {};
92
+ let model = rest.model ?? 'unknown';
93
+ if (typeof model === 'string' && model.startsWith('models/')) {
94
+ model = model.slice('models/'.length);
95
+ }
96
+ const start = performance.now();
97
+ const response = await originalGenerateContent(rest);
98
+ const latencyMs = Math.round((performance.now() - start) * 10) / 10;
99
+ const usage = response?.usageMetadata;
100
+ const inputTokens = usage?.promptTokenCount ?? 0;
101
+ const outputTokens = usage?.candidatesTokenCount ?? 0;
102
+ const costUsd = (0, pricing_1.getCost)(model, inputTokens, outputTokens);
103
+ const event = {
104
+ timestamp: new Date().toISOString(),
105
+ provider: 'google',
106
+ model,
107
+ operation: 'generate_content',
108
+ inputTokens,
109
+ outputTokens,
110
+ costUsd,
111
+ latencyMs,
112
+ tags,
113
+ };
114
+ tracker.record(event);
115
+ return response;
116
+ };
117
+ return new Proxy(client, {
118
+ get(target, prop) {
119
+ if (prop === 'models') {
120
+ return new Proxy(target.models, {
121
+ get(modelsTarget, modelsProp) {
122
+ if (modelsProp === 'generateContent')
123
+ return trackedGenerateContent;
124
+ return modelsTarget[modelsProp];
125
+ },
126
+ });
127
+ }
128
+ return target[prop];
129
+ },
130
+ });
131
+ }
132
+ function wrapMistral(client, tracker) {
133
+ const originalComplete = client.chat.complete.bind(client.chat);
134
+ const trackedComplete = async (params) => {
135
+ const { compute_cfo_tags, ...rest } = params ?? {};
136
+ const tags = compute_cfo_tags && typeof compute_cfo_tags === 'object' ? { ...compute_cfo_tags } : {};
137
+ const model = rest.model ?? 'unknown';
138
+ const start = performance.now();
139
+ const response = await originalComplete(rest);
140
+ const latencyMs = Math.round((performance.now() - start) * 10) / 10;
141
+ const usage = response?.usage;
142
+ const inputTokens = usage?.prompt_tokens ?? 0;
143
+ const outputTokens = usage?.completion_tokens ?? 0;
144
+ const actualModel = response?.model ?? model;
145
+ const costUsd = (0, pricing_1.getCost)(actualModel, inputTokens, outputTokens);
146
+ const event = {
147
+ timestamp: new Date().toISOString(),
148
+ provider: 'mistral',
149
+ model: actualModel,
150
+ operation: 'chat.complete',
151
+ inputTokens,
152
+ outputTokens,
153
+ costUsd,
154
+ latencyMs,
155
+ tags,
156
+ };
157
+ tracker.record(event);
158
+ return response;
159
+ };
160
+ return new Proxy(client, {
161
+ get(target, prop) {
162
+ if (prop === 'chat') {
163
+ return new Proxy(target.chat, {
164
+ get(chatTarget, chatProp) {
165
+ if (chatProp === 'complete')
166
+ return trackedComplete;
167
+ return chatTarget[chatProp];
168
+ },
169
+ });
170
+ }
171
+ return target[prop];
172
+ },
173
+ });
174
+ }
81
175
  function wrapAnthropic(client, tracker) {
82
176
  const originalCreate = client.messages.create.bind(client.messages);
83
177
  const trackedCreate = async (params) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compute-cfo",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Cost tracking, attribution, and budget enforcement for AI inference APIs",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",