ai-lib-python 0.5.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.
- ai_lib_python/__init__.py +43 -0
- ai_lib_python/batch/__init__.py +15 -0
- ai_lib_python/batch/collector.py +244 -0
- ai_lib_python/batch/executor.py +224 -0
- ai_lib_python/cache/__init__.py +26 -0
- ai_lib_python/cache/backends.py +380 -0
- ai_lib_python/cache/key.py +237 -0
- ai_lib_python/cache/manager.py +332 -0
- ai_lib_python/client/__init__.py +37 -0
- ai_lib_python/client/builder.py +528 -0
- ai_lib_python/client/cancel.py +368 -0
- ai_lib_python/client/core.py +433 -0
- ai_lib_python/client/response.py +134 -0
- ai_lib_python/embeddings/__init__.py +36 -0
- ai_lib_python/embeddings/client.py +339 -0
- ai_lib_python/embeddings/types.py +234 -0
- ai_lib_python/embeddings/vectors.py +246 -0
- ai_lib_python/errors/__init__.py +41 -0
- ai_lib_python/errors/base.py +316 -0
- ai_lib_python/errors/classification.py +210 -0
- ai_lib_python/guardrails/__init__.py +35 -0
- ai_lib_python/guardrails/base.py +336 -0
- ai_lib_python/guardrails/filters.py +583 -0
- ai_lib_python/guardrails/validators.py +475 -0
- ai_lib_python/pipeline/__init__.py +55 -0
- ai_lib_python/pipeline/accumulate.py +248 -0
- ai_lib_python/pipeline/base.py +240 -0
- ai_lib_python/pipeline/decode.py +281 -0
- ai_lib_python/pipeline/event_map.py +506 -0
- ai_lib_python/pipeline/fan_out.py +284 -0
- ai_lib_python/pipeline/select.py +297 -0
- ai_lib_python/plugins/__init__.py +32 -0
- ai_lib_python/plugins/base.py +294 -0
- ai_lib_python/plugins/hooks.py +296 -0
- ai_lib_python/plugins/middleware.py +285 -0
- ai_lib_python/plugins/registry.py +294 -0
- ai_lib_python/protocol/__init__.py +71 -0
- ai_lib_python/protocol/loader.py +317 -0
- ai_lib_python/protocol/manifest.py +385 -0
- ai_lib_python/protocol/validator.py +460 -0
- ai_lib_python/py.typed +1 -0
- ai_lib_python/resilience/__init__.py +102 -0
- ai_lib_python/resilience/backpressure.py +225 -0
- ai_lib_python/resilience/circuit_breaker.py +318 -0
- ai_lib_python/resilience/executor.py +343 -0
- ai_lib_python/resilience/fallback.py +341 -0
- ai_lib_python/resilience/preflight.py +413 -0
- ai_lib_python/resilience/rate_limiter.py +291 -0
- ai_lib_python/resilience/retry.py +299 -0
- ai_lib_python/resilience/signals.py +283 -0
- ai_lib_python/routing/__init__.py +118 -0
- ai_lib_python/routing/manager.py +593 -0
- ai_lib_python/routing/strategy.py +345 -0
- ai_lib_python/routing/types.py +397 -0
- ai_lib_python/structured/__init__.py +33 -0
- ai_lib_python/structured/json_mode.py +281 -0
- ai_lib_python/structured/schema.py +316 -0
- ai_lib_python/structured/validator.py +334 -0
- ai_lib_python/telemetry/__init__.py +127 -0
- ai_lib_python/telemetry/exporters/__init__.py +9 -0
- ai_lib_python/telemetry/exporters/prometheus.py +111 -0
- ai_lib_python/telemetry/feedback.py +446 -0
- ai_lib_python/telemetry/health.py +409 -0
- ai_lib_python/telemetry/logger.py +389 -0
- ai_lib_python/telemetry/metrics.py +496 -0
- ai_lib_python/telemetry/tracer.py +473 -0
- ai_lib_python/tokens/__init__.py +25 -0
- ai_lib_python/tokens/counter.py +282 -0
- ai_lib_python/tokens/estimator.py +286 -0
- ai_lib_python/transport/__init__.py +34 -0
- ai_lib_python/transport/auth.py +141 -0
- ai_lib_python/transport/http.py +364 -0
- ai_lib_python/transport/pool.py +425 -0
- ai_lib_python/types/__init__.py +41 -0
- ai_lib_python/types/events.py +343 -0
- ai_lib_python/types/message.py +332 -0
- ai_lib_python/types/tool.py +191 -0
- ai_lib_python/utils/__init__.py +21 -0
- ai_lib_python/utils/tool_call_assembler.py +317 -0
- ai_lib_python-0.5.0.dist-info/METADATA +837 -0
- ai_lib_python-0.5.0.dist-info/RECORD +84 -0
- ai_lib_python-0.5.0.dist-info/WHEEL +4 -0
- ai_lib_python-0.5.0.dist-info/licenses/LICENSE-APACHE +201 -0
- ai_lib_python-0.5.0.dist-info/licenses/LICENSE-MIT +21 -0
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model manager for routing and load balancing.
|
|
3
|
+
|
|
4
|
+
Provides model management, selection, and load balancing capabilities.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from ai_lib_python.routing.strategy import (
|
|
13
|
+
EndpointSelector,
|
|
14
|
+
LoadBalancingStrategy,
|
|
15
|
+
ModelSelectionStrategy,
|
|
16
|
+
ModelSelector,
|
|
17
|
+
create_endpoint_selector,
|
|
18
|
+
create_model_selector,
|
|
19
|
+
)
|
|
20
|
+
from ai_lib_python.routing.types import (
|
|
21
|
+
HealthCheckConfig,
|
|
22
|
+
ModelCapabilities,
|
|
23
|
+
ModelEndpoint,
|
|
24
|
+
ModelInfo,
|
|
25
|
+
PerformanceMetrics,
|
|
26
|
+
PricingInfo,
|
|
27
|
+
QualityTier,
|
|
28
|
+
SpeedTier,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ModelManager:
|
|
33
|
+
"""Manager for model registration and selection.
|
|
34
|
+
|
|
35
|
+
Provides methods for registering models, selecting models based on
|
|
36
|
+
various strategies, and filtering by capabilities.
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
>>> manager = ModelManager(provider="openai")
|
|
40
|
+
>>> manager.add_model(ModelInfo(
|
|
41
|
+
... name="gpt-4o",
|
|
42
|
+
... capabilities=ModelCapabilities(multimodal=True),
|
|
43
|
+
... pricing=PricingInfo(2.5, 10.0),
|
|
44
|
+
... ))
|
|
45
|
+
>>> model = manager.select_model()
|
|
46
|
+
>>> recommended = manager.recommend_for("multimodal")
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
provider: str = "",
|
|
52
|
+
strategy: ModelSelectionStrategy = ModelSelectionStrategy.ROUND_ROBIN,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""Initialize model manager.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
provider: Provider identifier
|
|
58
|
+
strategy: Model selection strategy
|
|
59
|
+
"""
|
|
60
|
+
self.provider = provider
|
|
61
|
+
self._models: dict[str, ModelInfo] = {}
|
|
62
|
+
self._strategy = strategy
|
|
63
|
+
self._selector: ModelSelector = create_model_selector(strategy)
|
|
64
|
+
|
|
65
|
+
def add_model(self, model: ModelInfo) -> ModelManager:
|
|
66
|
+
"""Add a model to the manager.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
model: Model information
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Self for chaining
|
|
73
|
+
"""
|
|
74
|
+
if not model.provider and self.provider:
|
|
75
|
+
model.provider = self.provider
|
|
76
|
+
self._models[model.name] = model
|
|
77
|
+
return self
|
|
78
|
+
|
|
79
|
+
def remove_model(self, model_name: str) -> ModelInfo | None:
|
|
80
|
+
"""Remove a model from the manager.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
model_name: Model name
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Removed model or None
|
|
87
|
+
"""
|
|
88
|
+
return self._models.pop(model_name, None)
|
|
89
|
+
|
|
90
|
+
def get_model(self, model_name: str) -> ModelInfo | None:
|
|
91
|
+
"""Get a model by name.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
model_name: Model name
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Model info or None
|
|
98
|
+
"""
|
|
99
|
+
return self._models.get(model_name)
|
|
100
|
+
|
|
101
|
+
def list_models(self) -> list[ModelInfo]:
|
|
102
|
+
"""List all registered models.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
List of model info
|
|
106
|
+
"""
|
|
107
|
+
return list(self._models.values())
|
|
108
|
+
|
|
109
|
+
def with_strategy(self, strategy: ModelSelectionStrategy) -> ModelManager:
|
|
110
|
+
"""Set the selection strategy.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
strategy: Selection strategy
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Self for chaining
|
|
117
|
+
"""
|
|
118
|
+
self._strategy = strategy
|
|
119
|
+
self._selector = create_model_selector(strategy)
|
|
120
|
+
return self
|
|
121
|
+
|
|
122
|
+
def select_model(self) -> ModelInfo | None:
|
|
123
|
+
"""Select a model using the current strategy.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Selected model or None
|
|
127
|
+
"""
|
|
128
|
+
models = list(self._models.values())
|
|
129
|
+
return self._selector.select(models)
|
|
130
|
+
|
|
131
|
+
def recommend_for(self, use_case: str) -> ModelInfo | None:
|
|
132
|
+
"""Recommend a model for a specific use case.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
use_case: Use case or capability name
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Recommended model or None
|
|
139
|
+
"""
|
|
140
|
+
supported = [m for m in self._models.values() if m.supports(use_case)]
|
|
141
|
+
if not supported:
|
|
142
|
+
return None
|
|
143
|
+
return self._selector.select(supported)
|
|
144
|
+
|
|
145
|
+
def filter_by_capability(self, capability: str) -> list[ModelInfo]:
|
|
146
|
+
"""Filter models by capability.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
capability: Capability name
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
List of models with the capability
|
|
153
|
+
"""
|
|
154
|
+
return [m for m in self._models.values() if m.supports(capability)]
|
|
155
|
+
|
|
156
|
+
def filter_by_cost(self, max_cost_per_1k: float) -> list[ModelInfo]:
|
|
157
|
+
"""Filter models by maximum cost.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
max_cost_per_1k: Maximum cost per 1000 tokens
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
List of affordable models
|
|
164
|
+
"""
|
|
165
|
+
return [
|
|
166
|
+
m
|
|
167
|
+
for m in self._models.values()
|
|
168
|
+
if m.pricing and (m.pricing.input_cost_per_1k <= max_cost_per_1k)
|
|
169
|
+
]
|
|
170
|
+
|
|
171
|
+
def filter_by_context_window(self, min_tokens: int) -> list[ModelInfo]:
|
|
172
|
+
"""Filter models by minimum context window.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
min_tokens: Minimum context window size
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
List of models meeting the requirement
|
|
179
|
+
"""
|
|
180
|
+
return [
|
|
181
|
+
m
|
|
182
|
+
for m in self._models.values()
|
|
183
|
+
if m.capabilities.context_window
|
|
184
|
+
and m.capabilities.context_window >= min_tokens
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
def load_from_config(self, config_path: str | Path) -> ModelManager:
|
|
188
|
+
"""Load models from a JSON configuration file.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
config_path: Path to configuration file
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Self for chaining
|
|
195
|
+
|
|
196
|
+
Raises:
|
|
197
|
+
FileNotFoundError: If config file doesn't exist
|
|
198
|
+
json.JSONDecodeError: If config is invalid JSON
|
|
199
|
+
"""
|
|
200
|
+
path = Path(config_path)
|
|
201
|
+
content = path.read_text()
|
|
202
|
+
models = json.loads(content)
|
|
203
|
+
|
|
204
|
+
if isinstance(models, list):
|
|
205
|
+
for model_data in models:
|
|
206
|
+
self.add_model(ModelInfo.from_dict(model_data))
|
|
207
|
+
elif isinstance(models, dict) and "models" in models:
|
|
208
|
+
for model_data in models["models"]:
|
|
209
|
+
self.add_model(ModelInfo.from_dict(model_data))
|
|
210
|
+
|
|
211
|
+
return self
|
|
212
|
+
|
|
213
|
+
def save_to_config(self, config_path: str | Path) -> None:
|
|
214
|
+
"""Save models to a JSON configuration file.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
config_path: Path to configuration file
|
|
218
|
+
"""
|
|
219
|
+
path = Path(config_path)
|
|
220
|
+
models = [m.to_dict() for m in self._models.values()]
|
|
221
|
+
content = json.dumps(models, indent=2)
|
|
222
|
+
path.write_text(content)
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def strategy(self) -> ModelSelectionStrategy:
|
|
226
|
+
"""Get current selection strategy."""
|
|
227
|
+
return self._strategy
|
|
228
|
+
|
|
229
|
+
def __len__(self) -> int:
|
|
230
|
+
"""Get number of registered models."""
|
|
231
|
+
return len(self._models)
|
|
232
|
+
|
|
233
|
+
def __contains__(self, model_name: str) -> bool:
|
|
234
|
+
"""Check if model is registered."""
|
|
235
|
+
return model_name in self._models
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class ModelArray:
|
|
239
|
+
"""Model array for load balancing across multiple endpoints.
|
|
240
|
+
|
|
241
|
+
Supports A/B testing and failover scenarios.
|
|
242
|
+
|
|
243
|
+
Example:
|
|
244
|
+
>>> array = ModelArray("gpt-4-cluster")
|
|
245
|
+
>>> array.add_endpoint(ModelEndpoint("primary", "gpt-4o", "https://api1.example.com"))
|
|
246
|
+
>>> array.add_endpoint(ModelEndpoint("secondary", "gpt-4o", "https://api2.example.com"))
|
|
247
|
+
>>> endpoint = array.select_endpoint()
|
|
248
|
+
"""
|
|
249
|
+
|
|
250
|
+
def __init__(
|
|
251
|
+
self,
|
|
252
|
+
name: str,
|
|
253
|
+
strategy: LoadBalancingStrategy = LoadBalancingStrategy.ROUND_ROBIN,
|
|
254
|
+
health_check: HealthCheckConfig | None = None,
|
|
255
|
+
) -> None:
|
|
256
|
+
"""Initialize model array.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
name: Array name/identifier
|
|
260
|
+
strategy: Load balancing strategy
|
|
261
|
+
health_check: Health check configuration
|
|
262
|
+
"""
|
|
263
|
+
self.name = name
|
|
264
|
+
self._endpoints: list[ModelEndpoint] = []
|
|
265
|
+
self._strategy = strategy
|
|
266
|
+
self._selector: EndpointSelector = create_endpoint_selector(strategy)
|
|
267
|
+
self.health_check = health_check or HealthCheckConfig()
|
|
268
|
+
|
|
269
|
+
def add_endpoint(self, endpoint: ModelEndpoint) -> ModelArray:
|
|
270
|
+
"""Add an endpoint to the array.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
endpoint: Endpoint to add
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
Self for chaining
|
|
277
|
+
"""
|
|
278
|
+
self._endpoints.append(endpoint)
|
|
279
|
+
return self
|
|
280
|
+
|
|
281
|
+
def remove_endpoint(self, endpoint_name: str) -> ModelEndpoint | None:
|
|
282
|
+
"""Remove an endpoint by name.
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
endpoint_name: Endpoint name
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
Removed endpoint or None
|
|
289
|
+
"""
|
|
290
|
+
for i, endpoint in enumerate(self._endpoints):
|
|
291
|
+
if endpoint.name == endpoint_name:
|
|
292
|
+
return self._endpoints.pop(i)
|
|
293
|
+
return None
|
|
294
|
+
|
|
295
|
+
def get_endpoint(self, endpoint_name: str) -> ModelEndpoint | None:
|
|
296
|
+
"""Get an endpoint by name.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
endpoint_name: Endpoint name
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Endpoint or None
|
|
303
|
+
"""
|
|
304
|
+
for endpoint in self._endpoints:
|
|
305
|
+
if endpoint.name == endpoint_name:
|
|
306
|
+
return endpoint
|
|
307
|
+
return None
|
|
308
|
+
|
|
309
|
+
def with_strategy(self, strategy: LoadBalancingStrategy) -> ModelArray:
|
|
310
|
+
"""Set the load balancing strategy.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
strategy: Load balancing strategy
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
Self for chaining
|
|
317
|
+
"""
|
|
318
|
+
self._strategy = strategy
|
|
319
|
+
self._selector = create_endpoint_selector(strategy)
|
|
320
|
+
return self
|
|
321
|
+
|
|
322
|
+
def select_endpoint(self) -> ModelEndpoint | None:
|
|
323
|
+
"""Select an endpoint using the current strategy.
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
Selected endpoint or None
|
|
327
|
+
"""
|
|
328
|
+
return self._selector.select(self._endpoints)
|
|
329
|
+
|
|
330
|
+
def mark_healthy(self, endpoint_name: str) -> bool:
|
|
331
|
+
"""Mark an endpoint as healthy.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
endpoint_name: Endpoint name
|
|
335
|
+
|
|
336
|
+
Returns:
|
|
337
|
+
True if endpoint was found
|
|
338
|
+
"""
|
|
339
|
+
endpoint = self.get_endpoint(endpoint_name)
|
|
340
|
+
if endpoint:
|
|
341
|
+
endpoint.healthy = True
|
|
342
|
+
return True
|
|
343
|
+
return False
|
|
344
|
+
|
|
345
|
+
def mark_unhealthy(self, endpoint_name: str) -> bool:
|
|
346
|
+
"""Mark an endpoint as unhealthy.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
endpoint_name: Endpoint name
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
True if endpoint was found
|
|
353
|
+
"""
|
|
354
|
+
endpoint = self.get_endpoint(endpoint_name)
|
|
355
|
+
if endpoint:
|
|
356
|
+
endpoint.healthy = False
|
|
357
|
+
return True
|
|
358
|
+
return False
|
|
359
|
+
|
|
360
|
+
def is_healthy(self) -> bool:
|
|
361
|
+
"""Check if any endpoint is healthy.
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
True if at least one endpoint is healthy
|
|
365
|
+
"""
|
|
366
|
+
return any(e.healthy for e in self._endpoints)
|
|
367
|
+
|
|
368
|
+
def healthy_endpoints(self) -> list[ModelEndpoint]:
|
|
369
|
+
"""Get all healthy endpoints.
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
List of healthy endpoints
|
|
373
|
+
"""
|
|
374
|
+
return [e for e in self._endpoints if e.healthy]
|
|
375
|
+
|
|
376
|
+
@property
|
|
377
|
+
def endpoints(self) -> list[ModelEndpoint]:
|
|
378
|
+
"""Get all endpoints."""
|
|
379
|
+
return list(self._endpoints)
|
|
380
|
+
|
|
381
|
+
@property
|
|
382
|
+
def strategy(self) -> LoadBalancingStrategy:
|
|
383
|
+
"""Get current strategy."""
|
|
384
|
+
return self._strategy
|
|
385
|
+
|
|
386
|
+
def __len__(self) -> int:
|
|
387
|
+
"""Get number of endpoints."""
|
|
388
|
+
return len(self._endpoints)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
# Pre-configured model catalogs
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def create_openai_models() -> ModelManager:
|
|
395
|
+
"""Create a pre-configured OpenAI model manager.
|
|
396
|
+
|
|
397
|
+
Returns:
|
|
398
|
+
ModelManager with OpenAI models
|
|
399
|
+
"""
|
|
400
|
+
manager = ModelManager(provider="openai")
|
|
401
|
+
|
|
402
|
+
# GPT-4o
|
|
403
|
+
manager.add_model(
|
|
404
|
+
ModelInfo(
|
|
405
|
+
name="gpt-4o",
|
|
406
|
+
display_name="GPT-4o",
|
|
407
|
+
description="Most capable GPT-4 model for complex tasks",
|
|
408
|
+
capabilities=ModelCapabilities(
|
|
409
|
+
chat=True,
|
|
410
|
+
code_generation=True,
|
|
411
|
+
multimodal=True,
|
|
412
|
+
function_calling=True,
|
|
413
|
+
context_window=128000,
|
|
414
|
+
),
|
|
415
|
+
pricing=PricingInfo(2.5, 10.0),
|
|
416
|
+
performance=PerformanceMetrics(
|
|
417
|
+
speed=SpeedTier.BALANCED,
|
|
418
|
+
quality=QualityTier.EXCELLENT,
|
|
419
|
+
),
|
|
420
|
+
)
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
# GPT-4o-mini
|
|
424
|
+
manager.add_model(
|
|
425
|
+
ModelInfo(
|
|
426
|
+
name="gpt-4o-mini",
|
|
427
|
+
display_name="GPT-4o Mini",
|
|
428
|
+
description="Smaller, faster GPT-4o variant",
|
|
429
|
+
capabilities=ModelCapabilities(
|
|
430
|
+
chat=True,
|
|
431
|
+
code_generation=True,
|
|
432
|
+
multimodal=True,
|
|
433
|
+
function_calling=True,
|
|
434
|
+
context_window=128000,
|
|
435
|
+
),
|
|
436
|
+
pricing=PricingInfo(0.15, 0.60),
|
|
437
|
+
performance=PerformanceMetrics(
|
|
438
|
+
speed=SpeedTier.FAST,
|
|
439
|
+
quality=QualityTier.GOOD,
|
|
440
|
+
),
|
|
441
|
+
)
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
# GPT-4-turbo
|
|
445
|
+
manager.add_model(
|
|
446
|
+
ModelInfo(
|
|
447
|
+
name="gpt-4-turbo",
|
|
448
|
+
display_name="GPT-4 Turbo",
|
|
449
|
+
description="GPT-4 Turbo with vision capabilities",
|
|
450
|
+
capabilities=ModelCapabilities(
|
|
451
|
+
chat=True,
|
|
452
|
+
code_generation=True,
|
|
453
|
+
multimodal=True,
|
|
454
|
+
function_calling=True,
|
|
455
|
+
context_window=128000,
|
|
456
|
+
),
|
|
457
|
+
pricing=PricingInfo(10.0, 30.0),
|
|
458
|
+
performance=PerformanceMetrics(
|
|
459
|
+
speed=SpeedTier.BALANCED,
|
|
460
|
+
quality=QualityTier.EXCELLENT,
|
|
461
|
+
),
|
|
462
|
+
)
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
# o1-preview
|
|
466
|
+
manager.add_model(
|
|
467
|
+
ModelInfo(
|
|
468
|
+
name="o1-preview",
|
|
469
|
+
display_name="o1 Preview",
|
|
470
|
+
description="Reasoning model for complex problems",
|
|
471
|
+
capabilities=ModelCapabilities(
|
|
472
|
+
chat=True,
|
|
473
|
+
code_generation=True,
|
|
474
|
+
multimodal=False,
|
|
475
|
+
function_calling=False,
|
|
476
|
+
context_window=128000,
|
|
477
|
+
),
|
|
478
|
+
pricing=PricingInfo(15.0, 60.0),
|
|
479
|
+
performance=PerformanceMetrics(
|
|
480
|
+
speed=SpeedTier.SLOW,
|
|
481
|
+
quality=QualityTier.EXCELLENT,
|
|
482
|
+
),
|
|
483
|
+
)
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
return manager
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def create_anthropic_models() -> ModelManager:
|
|
490
|
+
"""Create a pre-configured Anthropic model manager.
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
ModelManager with Anthropic models
|
|
494
|
+
"""
|
|
495
|
+
manager = ModelManager(provider="anthropic")
|
|
496
|
+
|
|
497
|
+
# Claude 3.5 Sonnet
|
|
498
|
+
manager.add_model(
|
|
499
|
+
ModelInfo(
|
|
500
|
+
name="claude-3-5-sonnet-20241022",
|
|
501
|
+
display_name="Claude 3.5 Sonnet",
|
|
502
|
+
description="Most intelligent Claude model",
|
|
503
|
+
capabilities=ModelCapabilities(
|
|
504
|
+
chat=True,
|
|
505
|
+
code_generation=True,
|
|
506
|
+
multimodal=True,
|
|
507
|
+
tool_use=True,
|
|
508
|
+
context_window=200000,
|
|
509
|
+
),
|
|
510
|
+
pricing=PricingInfo(3.0, 15.0),
|
|
511
|
+
performance=PerformanceMetrics(
|
|
512
|
+
speed=SpeedTier.BALANCED,
|
|
513
|
+
quality=QualityTier.EXCELLENT,
|
|
514
|
+
),
|
|
515
|
+
)
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
# Claude 3.5 Haiku
|
|
519
|
+
manager.add_model(
|
|
520
|
+
ModelInfo(
|
|
521
|
+
name="claude-3-5-haiku-20241022",
|
|
522
|
+
display_name="Claude 3.5 Haiku",
|
|
523
|
+
description="Fast and efficient Claude model",
|
|
524
|
+
capabilities=ModelCapabilities(
|
|
525
|
+
chat=True,
|
|
526
|
+
code_generation=True,
|
|
527
|
+
multimodal=True,
|
|
528
|
+
tool_use=True,
|
|
529
|
+
context_window=200000,
|
|
530
|
+
),
|
|
531
|
+
pricing=PricingInfo(0.80, 4.0),
|
|
532
|
+
performance=PerformanceMetrics(
|
|
533
|
+
speed=SpeedTier.FAST,
|
|
534
|
+
quality=QualityTier.GOOD,
|
|
535
|
+
),
|
|
536
|
+
)
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
# Claude 3 Opus
|
|
540
|
+
manager.add_model(
|
|
541
|
+
ModelInfo(
|
|
542
|
+
name="claude-3-opus-20240229",
|
|
543
|
+
display_name="Claude 3 Opus",
|
|
544
|
+
description="Most powerful Claude 3 model",
|
|
545
|
+
capabilities=ModelCapabilities(
|
|
546
|
+
chat=True,
|
|
547
|
+
code_generation=True,
|
|
548
|
+
multimodal=True,
|
|
549
|
+
tool_use=True,
|
|
550
|
+
context_window=200000,
|
|
551
|
+
),
|
|
552
|
+
pricing=PricingInfo(15.0, 75.0),
|
|
553
|
+
performance=PerformanceMetrics(
|
|
554
|
+
speed=SpeedTier.SLOW,
|
|
555
|
+
quality=QualityTier.EXCELLENT,
|
|
556
|
+
),
|
|
557
|
+
)
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
return manager
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
# Global model registry
|
|
564
|
+
_global_managers: dict[str, ModelManager] = {}
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def get_model_manager(provider: str) -> ModelManager:
|
|
568
|
+
"""Get or create a model manager for a provider.
|
|
569
|
+
|
|
570
|
+
Args:
|
|
571
|
+
provider: Provider identifier
|
|
572
|
+
|
|
573
|
+
Returns:
|
|
574
|
+
ModelManager instance
|
|
575
|
+
"""
|
|
576
|
+
if provider not in _global_managers:
|
|
577
|
+
if provider == "openai":
|
|
578
|
+
_global_managers[provider] = create_openai_models()
|
|
579
|
+
elif provider == "anthropic":
|
|
580
|
+
_global_managers[provider] = create_anthropic_models()
|
|
581
|
+
else:
|
|
582
|
+
_global_managers[provider] = ModelManager(provider=provider)
|
|
583
|
+
return _global_managers[provider]
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
def register_model_manager(provider: str, manager: ModelManager) -> None:
|
|
587
|
+
"""Register a custom model manager.
|
|
588
|
+
|
|
589
|
+
Args:
|
|
590
|
+
provider: Provider identifier
|
|
591
|
+
manager: ModelManager instance
|
|
592
|
+
"""
|
|
593
|
+
_global_managers[provider] = manager
|