kalibr 1.1.3a0__py3-none-any.whl → 1.4.0__py3-none-any.whl
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.
- kalibr/__init__.py +41 -3
- kalibr/cli/capsule_cmd.py +3 -3
- kalibr/cli/main.py +3 -3
- kalibr/cli/run.py +2 -2
- kalibr/client.py +1 -1
- kalibr/collector.py +227 -48
- kalibr/context.py +42 -0
- kalibr/cost_adapter.py +36 -104
- kalibr/instrumentation/anthropic_instr.py +34 -40
- kalibr/instrumentation/base.py +27 -9
- kalibr/instrumentation/google_instr.py +34 -39
- kalibr/instrumentation/openai_instr.py +34 -28
- kalibr/instrumentation/registry.py +38 -13
- kalibr/intelligence.py +662 -0
- kalibr/middleware/auto_tracer.py +1 -1
- kalibr/pricing.py +245 -0
- kalibr/router.py +545 -0
- kalibr/simple_tracer.py +16 -15
- kalibr/tokens.py +20 -5
- kalibr/trace_capsule.py +19 -12
- kalibr/utils.py +2 -2
- kalibr-1.4.0.dist-info/LICENSE +190 -0
- kalibr-1.4.0.dist-info/METADATA +306 -0
- kalibr-1.4.0.dist-info/RECORD +52 -0
- {kalibr-1.1.3a0.dist-info → kalibr-1.4.0.dist-info}/WHEEL +1 -1
- kalibr_crewai/__init__.py +1 -1
- kalibr_crewai/callbacks.py +122 -14
- kalibr_crewai/instrumentor.py +196 -33
- kalibr_langchain/__init__.py +4 -2
- kalibr_langchain/callback.py +26 -0
- kalibr_langchain/chat_model.py +103 -0
- kalibr_openai_agents/__init__.py +1 -1
- kalibr-1.1.3a0.dist-info/METADATA +0 -236
- kalibr-1.1.3a0.dist-info/RECORD +0 -48
- kalibr-1.1.3a0.dist-info/licenses/LICENSE +0 -21
- {kalibr-1.1.3a0.dist-info → kalibr-1.4.0.dist-info}/entry_points.txt +0 -0
- {kalibr-1.1.3a0.dist-info → kalibr-1.4.0.dist-info}/top_level.txt +0 -0
kalibr/pricing.py
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"""Centralized pricing data for all LLM vendors.
|
|
2
|
+
|
|
3
|
+
This module serves as the single source of truth for model pricing across
|
|
4
|
+
the entire Kalibr SDK. All cost adapters and instrumentation modules should
|
|
5
|
+
use this pricing data to ensure consistency.
|
|
6
|
+
|
|
7
|
+
All prices are in USD per 1 million tokens, matching the format used by
|
|
8
|
+
major LLM providers (OpenAI, Anthropic, etc.) on their pricing pages.
|
|
9
|
+
|
|
10
|
+
Version: 2026-01
|
|
11
|
+
Last Updated: January 2026
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from typing import Dict, Optional, Tuple
|
|
15
|
+
|
|
16
|
+
# Pricing version for tracking updates
|
|
17
|
+
PRICING_VERSION = "2026-01"
|
|
18
|
+
|
|
19
|
+
# All prices in USD per 1M tokens
|
|
20
|
+
MODEL_PRICING: Dict[str, Dict[str, Dict[str, float]]] = {
|
|
21
|
+
"openai": {
|
|
22
|
+
# GPT-5 models (future-proofing)
|
|
23
|
+
"gpt-5": {"input": 5.00, "output": 15.00},
|
|
24
|
+
"gpt-5-turbo": {"input": 2.50, "output": 7.50},
|
|
25
|
+
# GPT-4 models
|
|
26
|
+
"gpt-4": {"input": 30.00, "output": 60.00},
|
|
27
|
+
"gpt-4-turbo": {"input": 10.00, "output": 30.00},
|
|
28
|
+
"gpt-4o": {"input": 2.50, "output": 10.00},
|
|
29
|
+
"gpt-4o-mini": {"input": 0.15, "output": 0.60},
|
|
30
|
+
# GPT-3.5 models
|
|
31
|
+
"gpt-3.5-turbo": {"input": 0.50, "output": 1.50},
|
|
32
|
+
"gpt-3.5-turbo-16k": {"input": 1.00, "output": 2.00},
|
|
33
|
+
},
|
|
34
|
+
"anthropic": {
|
|
35
|
+
# Claude 4 models (future-proofing)
|
|
36
|
+
"claude-4-opus": {"input": 15.00, "output": 75.00},
|
|
37
|
+
"claude-4-sonnet": {"input": 3.00, "output": 15.00},
|
|
38
|
+
# Claude 3.5/3.7 models (Sonnet 4 is actually Claude 3.7)
|
|
39
|
+
"claude-sonnet-4": {"input": 3.00, "output": 15.00},
|
|
40
|
+
"claude-3-7-sonnet": {"input": 3.00, "output": 15.00},
|
|
41
|
+
"claude-3-5-sonnet": {"input": 3.00, "output": 15.00},
|
|
42
|
+
# Claude 3 models
|
|
43
|
+
"claude-3-opus": {"input": 15.00, "output": 75.00},
|
|
44
|
+
"claude-3-sonnet": {"input": 3.00, "output": 15.00},
|
|
45
|
+
"claude-3-haiku": {"input": 0.25, "output": 1.25},
|
|
46
|
+
# Claude 2 models
|
|
47
|
+
"claude-2.1": {"input": 8.00, "output": 24.00},
|
|
48
|
+
"claude-2.0": {"input": 8.00, "output": 24.00},
|
|
49
|
+
"claude-instant-1.2": {"input": 0.80, "output": 2.40},
|
|
50
|
+
},
|
|
51
|
+
"google": {
|
|
52
|
+
# Gemini 2.5 models
|
|
53
|
+
"gemini-2.5-pro": {"input": 1.25, "output": 5.00},
|
|
54
|
+
"gemini-2.5-flash": {"input": 0.075, "output": 0.30},
|
|
55
|
+
# Gemini 2.0 models
|
|
56
|
+
"gemini-2.0-flash": {"input": 0.075, "output": 0.30},
|
|
57
|
+
"gemini-2.0-flash-thinking": {"input": 0.075, "output": 0.30},
|
|
58
|
+
# Gemini 1.5 models
|
|
59
|
+
"gemini-1.5-pro": {"input": 1.25, "output": 5.00},
|
|
60
|
+
"gemini-1.5-flash": {"input": 0.075, "output": 0.30},
|
|
61
|
+
"gemini-1.5-flash-8b": {"input": 0.0375, "output": 0.15},
|
|
62
|
+
# Gemini 1.0 models
|
|
63
|
+
"gemini-1.0-pro": {"input": 0.50, "output": 1.50},
|
|
64
|
+
"gemini-pro": {"input": 0.50, "output": 1.50}, # Alias
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Default fallback pricing per vendor (highest tier pricing for safety)
|
|
69
|
+
DEFAULT_PRICING: Dict[str, Dict[str, float]] = {
|
|
70
|
+
"openai": {"input": 30.00, "output": 60.00}, # GPT-4 pricing
|
|
71
|
+
"anthropic": {"input": 15.00, "output": 75.00}, # Claude 3 Opus pricing
|
|
72
|
+
"google": {"input": 1.25, "output": 5.00}, # Gemini 1.5 Pro pricing
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def normalize_model_name(vendor: str, model_name: str) -> str:
|
|
77
|
+
"""Normalize model name to match pricing table keys.
|
|
78
|
+
|
|
79
|
+
Handles version suffixes, date stamps, and common variations.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
vendor: Vendor name (openai, anthropic, google)
|
|
83
|
+
model_name: Raw model name from API
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Normalized model name that matches pricing table, or original if no match
|
|
87
|
+
|
|
88
|
+
Example:
|
|
89
|
+
>>> normalize_model_name("openai", "gpt-4o-2024-05-13")
|
|
90
|
+
'gpt-4o'
|
|
91
|
+
>>> normalize_model_name("anthropic", "claude-3-5-sonnet-20240620")
|
|
92
|
+
'claude-3-5-sonnet'
|
|
93
|
+
"""
|
|
94
|
+
vendor = vendor.lower()
|
|
95
|
+
model_lower = model_name.lower()
|
|
96
|
+
|
|
97
|
+
# Get vendor pricing table
|
|
98
|
+
vendor_models = MODEL_PRICING.get(vendor, {})
|
|
99
|
+
|
|
100
|
+
# Direct match
|
|
101
|
+
if model_lower in vendor_models:
|
|
102
|
+
return model_lower
|
|
103
|
+
|
|
104
|
+
# OpenAI fuzzy matching
|
|
105
|
+
if vendor == "openai":
|
|
106
|
+
# Remove date suffixes like -20240513
|
|
107
|
+
base_model = model_lower.split("-2")[0] if "-2" in model_lower else model_lower
|
|
108
|
+
|
|
109
|
+
# Try direct match on base
|
|
110
|
+
if base_model in vendor_models:
|
|
111
|
+
return base_model
|
|
112
|
+
|
|
113
|
+
# Fuzzy match in priority order
|
|
114
|
+
if "gpt-4o-mini" in model_lower:
|
|
115
|
+
return "gpt-4o-mini"
|
|
116
|
+
elif "gpt-4o" in model_lower:
|
|
117
|
+
return "gpt-4o"
|
|
118
|
+
elif "gpt-5-turbo" in model_lower:
|
|
119
|
+
return "gpt-5-turbo"
|
|
120
|
+
elif "gpt-5" in model_lower:
|
|
121
|
+
return "gpt-5"
|
|
122
|
+
elif "gpt-4-turbo" in model_lower:
|
|
123
|
+
return "gpt-4-turbo"
|
|
124
|
+
elif "gpt-4" in model_lower:
|
|
125
|
+
return "gpt-4"
|
|
126
|
+
elif "gpt-3.5-turbo-16k" in model_lower:
|
|
127
|
+
return "gpt-3.5-turbo-16k"
|
|
128
|
+
elif "gpt-3.5" in model_lower:
|
|
129
|
+
return "gpt-3.5-turbo"
|
|
130
|
+
|
|
131
|
+
# Anthropic fuzzy matching
|
|
132
|
+
elif vendor == "anthropic":
|
|
133
|
+
# Try fuzzy matching for versioned models
|
|
134
|
+
if "claude-3.5-sonnet" in model_lower or "claude-3-5-sonnet" in model_lower:
|
|
135
|
+
return "claude-3-5-sonnet"
|
|
136
|
+
elif "claude-sonnet-4" in model_lower or "sonnet-4" in model_lower:
|
|
137
|
+
return "claude-sonnet-4"
|
|
138
|
+
elif "claude-3-7-sonnet" in model_lower:
|
|
139
|
+
return "claude-3-7-sonnet"
|
|
140
|
+
elif "claude-4-opus" in model_lower:
|
|
141
|
+
return "claude-4-opus"
|
|
142
|
+
elif "claude-4-sonnet" in model_lower:
|
|
143
|
+
return "claude-4-sonnet"
|
|
144
|
+
elif "claude-3-opus" in model_lower:
|
|
145
|
+
return "claude-3-opus"
|
|
146
|
+
elif "claude-3-sonnet" in model_lower:
|
|
147
|
+
return "claude-3-sonnet"
|
|
148
|
+
elif "claude-3-haiku" in model_lower:
|
|
149
|
+
return "claude-3-haiku"
|
|
150
|
+
elif "claude-2.1" in model_lower:
|
|
151
|
+
return "claude-2.1"
|
|
152
|
+
elif "claude-2.0" in model_lower or "claude-2" in model_lower:
|
|
153
|
+
return "claude-2.0"
|
|
154
|
+
elif "claude-instant" in model_lower:
|
|
155
|
+
return "claude-instant-1.2"
|
|
156
|
+
|
|
157
|
+
# Google fuzzy matching
|
|
158
|
+
elif vendor == "google":
|
|
159
|
+
# Try fuzzy matching for versioned models
|
|
160
|
+
if "gemini-2.5-pro" in model_lower:
|
|
161
|
+
return "gemini-2.5-pro"
|
|
162
|
+
elif "gemini-2.5-flash" in model_lower:
|
|
163
|
+
return "gemini-2.5-flash"
|
|
164
|
+
elif "gemini-2.0-flash-thinking" in model_lower:
|
|
165
|
+
return "gemini-2.0-flash-thinking"
|
|
166
|
+
elif "gemini-2.0-flash" in model_lower:
|
|
167
|
+
return "gemini-2.0-flash"
|
|
168
|
+
elif "gemini-1.5-flash-8b" in model_lower:
|
|
169
|
+
return "gemini-1.5-flash-8b"
|
|
170
|
+
elif "gemini-1.5-flash" in model_lower:
|
|
171
|
+
return "gemini-1.5-flash"
|
|
172
|
+
elif "gemini-1.5-pro" in model_lower:
|
|
173
|
+
return "gemini-1.5-pro"
|
|
174
|
+
elif "gemini-1.0-pro" in model_lower or "gemini-pro" in model_lower:
|
|
175
|
+
return "gemini-pro"
|
|
176
|
+
|
|
177
|
+
# Return original if no match found
|
|
178
|
+
return model_lower
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def get_pricing(
|
|
182
|
+
vendor: str, model_name: str
|
|
183
|
+
) -> Tuple[Dict[str, float], str]:
|
|
184
|
+
"""Get pricing for a specific vendor and model.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
vendor: Vendor name (openai, anthropic, google)
|
|
188
|
+
model_name: Model identifier
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
Tuple of (pricing dict with 'input' and 'output' keys in USD per 1M tokens,
|
|
192
|
+
normalized model name used)
|
|
193
|
+
|
|
194
|
+
Example:
|
|
195
|
+
>>> pricing, normalized = get_pricing("openai", "gpt-4o")
|
|
196
|
+
>>> print(pricing)
|
|
197
|
+
{'input': 2.50, 'output': 10.00}
|
|
198
|
+
>>> print(normalized)
|
|
199
|
+
'gpt-4o'
|
|
200
|
+
"""
|
|
201
|
+
vendor = vendor.lower()
|
|
202
|
+
normalized_model = normalize_model_name(vendor, model_name)
|
|
203
|
+
|
|
204
|
+
# Get vendor pricing table
|
|
205
|
+
vendor_models = MODEL_PRICING.get(vendor, {})
|
|
206
|
+
|
|
207
|
+
# Try to get pricing for normalized model
|
|
208
|
+
pricing = vendor_models.get(normalized_model)
|
|
209
|
+
|
|
210
|
+
# Fall back to default vendor pricing if not found
|
|
211
|
+
if pricing is None:
|
|
212
|
+
pricing = DEFAULT_PRICING.get(vendor, {"input": 20.00, "output": 60.00})
|
|
213
|
+
|
|
214
|
+
return pricing, normalized_model
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def compute_cost(
|
|
218
|
+
vendor: str, model_name: str, input_tokens: int, output_tokens: int
|
|
219
|
+
) -> float:
|
|
220
|
+
"""Compute cost in USD for given vendor, model, and token counts.
|
|
221
|
+
|
|
222
|
+
This is a convenience function that combines pricing lookup and cost calculation.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
vendor: Vendor name (openai, anthropic, google)
|
|
226
|
+
model_name: Model identifier
|
|
227
|
+
input_tokens: Number of input tokens
|
|
228
|
+
output_tokens: Number of output tokens
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
Cost in USD (rounded to 6 decimal places)
|
|
232
|
+
|
|
233
|
+
Example:
|
|
234
|
+
>>> cost = compute_cost("openai", "gpt-4o", 1000, 500)
|
|
235
|
+
>>> print(f"${cost:.6f}")
|
|
236
|
+
$0.007500
|
|
237
|
+
"""
|
|
238
|
+
pricing, _ = get_pricing(vendor, model_name)
|
|
239
|
+
|
|
240
|
+
# Calculate cost (pricing is per 1M tokens)
|
|
241
|
+
input_cost = (input_tokens / 1_000_000) * pricing["input"]
|
|
242
|
+
output_cost = (output_tokens / 1_000_000) * pricing["output"]
|
|
243
|
+
|
|
244
|
+
return round(input_cost + output_cost, 6)
|
|
245
|
+
|