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,332 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cache manager for AI responses.
|
|
3
|
+
|
|
4
|
+
Provides unified cache management with multiple backends.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from ai_lib_python.cache.backends import CacheBackend, MemoryCache, NullCache
|
|
13
|
+
from ai_lib_python.cache.key import CacheKey, CacheKeyGenerator
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class CacheStats:
|
|
18
|
+
"""Cache statistics.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
hits: Number of cache hits
|
|
22
|
+
misses: Number of cache misses
|
|
23
|
+
sets: Number of cache sets
|
|
24
|
+
evictions: Number of evictions
|
|
25
|
+
total_requests: Total requests
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
hits: int = 0
|
|
29
|
+
misses: int = 0
|
|
30
|
+
sets: int = 0
|
|
31
|
+
evictions: int = 0
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def total_requests(self) -> int:
|
|
35
|
+
"""Get total number of requests."""
|
|
36
|
+
return self.hits + self.misses
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def hit_rate(self) -> float:
|
|
40
|
+
"""Get cache hit rate (0.0 to 1.0)."""
|
|
41
|
+
total = self.total_requests
|
|
42
|
+
if total == 0:
|
|
43
|
+
return 0.0
|
|
44
|
+
return self.hits / total
|
|
45
|
+
|
|
46
|
+
def to_dict(self) -> dict[str, Any]:
|
|
47
|
+
"""Convert to dictionary."""
|
|
48
|
+
return {
|
|
49
|
+
"hits": self.hits,
|
|
50
|
+
"misses": self.misses,
|
|
51
|
+
"sets": self.sets,
|
|
52
|
+
"evictions": self.evictions,
|
|
53
|
+
"total_requests": self.total_requests,
|
|
54
|
+
"hit_rate": self.hit_rate,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
def reset(self) -> None:
|
|
58
|
+
"""Reset statistics."""
|
|
59
|
+
self.hits = 0
|
|
60
|
+
self.misses = 0
|
|
61
|
+
self.sets = 0
|
|
62
|
+
self.evictions = 0
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class CacheConfig:
|
|
67
|
+
"""Cache configuration.
|
|
68
|
+
|
|
69
|
+
Attributes:
|
|
70
|
+
enabled: Whether caching is enabled
|
|
71
|
+
default_ttl: Default TTL in seconds
|
|
72
|
+
max_size: Maximum cache size
|
|
73
|
+
cache_streaming: Whether to cache streaming responses
|
|
74
|
+
cache_errors: Whether to cache error responses
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
enabled: bool = True
|
|
78
|
+
default_ttl: float = 3600.0 # 1 hour
|
|
79
|
+
max_size: int = 1000
|
|
80
|
+
cache_streaming: bool = False
|
|
81
|
+
cache_errors: bool = False
|
|
82
|
+
|
|
83
|
+
@classmethod
|
|
84
|
+
def disabled(cls) -> CacheConfig:
|
|
85
|
+
"""Create disabled cache config."""
|
|
86
|
+
return cls(enabled=False)
|
|
87
|
+
|
|
88
|
+
@classmethod
|
|
89
|
+
def short_ttl(cls, ttl: float = 300.0) -> CacheConfig:
|
|
90
|
+
"""Create config with short TTL (5 minutes default)."""
|
|
91
|
+
return cls(default_ttl=ttl)
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def long_ttl(cls, ttl: float = 86400.0) -> CacheConfig:
|
|
95
|
+
"""Create config with long TTL (24 hours default)."""
|
|
96
|
+
return cls(default_ttl=ttl)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class CacheManager:
|
|
100
|
+
"""Manages caching for AI responses.
|
|
101
|
+
|
|
102
|
+
Provides a high-level interface for caching with automatic
|
|
103
|
+
key generation and statistics.
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
>>> manager = CacheManager(CacheConfig(default_ttl=3600))
|
|
107
|
+
>>>
|
|
108
|
+
>>> # Check cache before making request
|
|
109
|
+
>>> cached = await manager.get_response(model, messages)
|
|
110
|
+
>>> if cached:
|
|
111
|
+
... return cached
|
|
112
|
+
>>>
|
|
113
|
+
>>> # Make request and cache result
|
|
114
|
+
>>> response = await client.chat(model, messages)
|
|
115
|
+
>>> await manager.cache_response(model, messages, response)
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
def __init__(
|
|
119
|
+
self,
|
|
120
|
+
config: CacheConfig | None = None,
|
|
121
|
+
backend: CacheBackend | None = None,
|
|
122
|
+
) -> None:
|
|
123
|
+
"""Initialize cache manager.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
config: Cache configuration
|
|
127
|
+
backend: Cache backend (defaults to MemoryCache)
|
|
128
|
+
"""
|
|
129
|
+
self._config = config or CacheConfig()
|
|
130
|
+
self._key_generator = CacheKeyGenerator()
|
|
131
|
+
self._stats = CacheStats()
|
|
132
|
+
|
|
133
|
+
if not self._config.enabled:
|
|
134
|
+
self._backend = NullCache()
|
|
135
|
+
else:
|
|
136
|
+
self._backend = backend or MemoryCache(
|
|
137
|
+
max_size=self._config.max_size,
|
|
138
|
+
default_ttl=self._config.default_ttl,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
async def get_response(
|
|
142
|
+
self,
|
|
143
|
+
model: str,
|
|
144
|
+
messages: list[dict[str, Any]],
|
|
145
|
+
**params: Any,
|
|
146
|
+
) -> dict[str, Any] | None:
|
|
147
|
+
"""Get a cached response.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
model: Model name
|
|
151
|
+
messages: Chat messages
|
|
152
|
+
**params: Additional parameters
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Cached response or None
|
|
156
|
+
"""
|
|
157
|
+
if not self._config.enabled:
|
|
158
|
+
self._stats.misses += 1
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
key = self._key_generator.generate(model, messages, **params)
|
|
162
|
+
value = await self._backend.get(key.key)
|
|
163
|
+
|
|
164
|
+
if value is not None:
|
|
165
|
+
self._stats.hits += 1
|
|
166
|
+
else:
|
|
167
|
+
self._stats.misses += 1
|
|
168
|
+
|
|
169
|
+
return value
|
|
170
|
+
|
|
171
|
+
async def cache_response(
|
|
172
|
+
self,
|
|
173
|
+
model: str,
|
|
174
|
+
messages: list[dict[str, Any]],
|
|
175
|
+
response: dict[str, Any],
|
|
176
|
+
ttl: float | None = None,
|
|
177
|
+
**params: Any,
|
|
178
|
+
) -> CacheKey:
|
|
179
|
+
"""Cache a response.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
model: Model name
|
|
183
|
+
messages: Chat messages
|
|
184
|
+
response: Response to cache
|
|
185
|
+
ttl: TTL override
|
|
186
|
+
**params: Additional parameters
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Cache key used
|
|
190
|
+
"""
|
|
191
|
+
key = self._key_generator.generate(model, messages, **params)
|
|
192
|
+
|
|
193
|
+
if self._config.enabled:
|
|
194
|
+
await self._backend.set(
|
|
195
|
+
key.key,
|
|
196
|
+
response,
|
|
197
|
+
ttl=ttl or self._config.default_ttl,
|
|
198
|
+
)
|
|
199
|
+
self._stats.sets += 1
|
|
200
|
+
|
|
201
|
+
return key
|
|
202
|
+
|
|
203
|
+
async def get_embedding(
|
|
204
|
+
self,
|
|
205
|
+
model: str,
|
|
206
|
+
input_text: str | list[str],
|
|
207
|
+
dimensions: int | None = None,
|
|
208
|
+
) -> list[list[float]] | None:
|
|
209
|
+
"""Get cached embeddings.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
model: Model name
|
|
213
|
+
input_text: Input text(s)
|
|
214
|
+
dimensions: Output dimensions
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Cached embeddings or None
|
|
218
|
+
"""
|
|
219
|
+
if not self._config.enabled:
|
|
220
|
+
self._stats.misses += 1
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
key = self._key_generator.generate_for_embedding(model, input_text, dimensions)
|
|
224
|
+
value = await self._backend.get(key.key)
|
|
225
|
+
|
|
226
|
+
if value is not None:
|
|
227
|
+
self._stats.hits += 1
|
|
228
|
+
else:
|
|
229
|
+
self._stats.misses += 1
|
|
230
|
+
|
|
231
|
+
return value
|
|
232
|
+
|
|
233
|
+
async def cache_embedding(
|
|
234
|
+
self,
|
|
235
|
+
model: str,
|
|
236
|
+
input_text: str | list[str],
|
|
237
|
+
embeddings: list[list[float]],
|
|
238
|
+
dimensions: int | None = None,
|
|
239
|
+
ttl: float | None = None,
|
|
240
|
+
) -> CacheKey:
|
|
241
|
+
"""Cache embeddings.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
model: Model name
|
|
245
|
+
input_text: Input text(s)
|
|
246
|
+
embeddings: Embedding vectors
|
|
247
|
+
dimensions: Output dimensions
|
|
248
|
+
ttl: TTL override
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Cache key used
|
|
252
|
+
"""
|
|
253
|
+
key = self._key_generator.generate_for_embedding(model, input_text, dimensions)
|
|
254
|
+
|
|
255
|
+
if self._config.enabled:
|
|
256
|
+
await self._backend.set(
|
|
257
|
+
key.key,
|
|
258
|
+
embeddings,
|
|
259
|
+
ttl=ttl or self._config.default_ttl,
|
|
260
|
+
)
|
|
261
|
+
self._stats.sets += 1
|
|
262
|
+
|
|
263
|
+
return key
|
|
264
|
+
|
|
265
|
+
async def invalidate(
|
|
266
|
+
self,
|
|
267
|
+
model: str,
|
|
268
|
+
messages: list[dict[str, Any]],
|
|
269
|
+
**params: Any,
|
|
270
|
+
) -> bool:
|
|
271
|
+
"""Invalidate a cached response.
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
model: Model name
|
|
275
|
+
messages: Chat messages
|
|
276
|
+
**params: Additional parameters
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
True if invalidated, False if not found
|
|
280
|
+
"""
|
|
281
|
+
key = self._key_generator.generate(model, messages, **params)
|
|
282
|
+
return await self._backend.delete(key.key)
|
|
283
|
+
|
|
284
|
+
async def clear(self) -> None:
|
|
285
|
+
"""Clear all cached entries."""
|
|
286
|
+
await self._backend.clear()
|
|
287
|
+
self._stats.reset()
|
|
288
|
+
|
|
289
|
+
@property
|
|
290
|
+
def stats(self) -> CacheStats:
|
|
291
|
+
"""Get cache statistics."""
|
|
292
|
+
return self._stats
|
|
293
|
+
|
|
294
|
+
@property
|
|
295
|
+
def config(self) -> CacheConfig:
|
|
296
|
+
"""Get cache configuration."""
|
|
297
|
+
return self._config
|
|
298
|
+
|
|
299
|
+
@property
|
|
300
|
+
def enabled(self) -> bool:
|
|
301
|
+
"""Check if caching is enabled."""
|
|
302
|
+
return self._config.enabled
|
|
303
|
+
|
|
304
|
+
async def close(self) -> None:
|
|
305
|
+
"""Close the cache manager."""
|
|
306
|
+
await self._backend.close()
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
# Global cache manager
|
|
310
|
+
_global_cache: CacheManager | None = None
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def get_cache_manager() -> CacheManager:
|
|
314
|
+
"""Get the global cache manager.
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
Global CacheManager instance
|
|
318
|
+
"""
|
|
319
|
+
global _global_cache
|
|
320
|
+
if _global_cache is None:
|
|
321
|
+
_global_cache = CacheManager()
|
|
322
|
+
return _global_cache
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def set_cache_manager(manager: CacheManager) -> None:
|
|
326
|
+
"""Set the global cache manager.
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
manager: CacheManager instance
|
|
330
|
+
"""
|
|
331
|
+
global _global_cache
|
|
332
|
+
_global_cache = manager
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Client layer - User-facing API.
|
|
3
|
+
|
|
4
|
+
This module provides:
|
|
5
|
+
- AiClient: Main entry point for AI model interaction
|
|
6
|
+
- ChatBuilder: Fluent API for building chat requests
|
|
7
|
+
- Response types and utilities
|
|
8
|
+
- Cancellation: Stream cancellation control
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from ai_lib_python.client.builder import AiClientBuilder, ChatRequestBuilder
|
|
12
|
+
from ai_lib_python.client.cancel import (
|
|
13
|
+
CancellableStream,
|
|
14
|
+
CancelHandle,
|
|
15
|
+
CancelReason,
|
|
16
|
+
CancelState,
|
|
17
|
+
CancelToken,
|
|
18
|
+
create_cancel_pair,
|
|
19
|
+
with_cancellation,
|
|
20
|
+
)
|
|
21
|
+
from ai_lib_python.client.core import AiClient
|
|
22
|
+
from ai_lib_python.client.response import CallStats, ChatResponse
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"AiClient",
|
|
26
|
+
"AiClientBuilder",
|
|
27
|
+
"CallStats",
|
|
28
|
+
"CancellableStream",
|
|
29
|
+
"CancelHandle",
|
|
30
|
+
"CancelReason",
|
|
31
|
+
"CancelState",
|
|
32
|
+
"CancelToken",
|
|
33
|
+
"ChatRequestBuilder",
|
|
34
|
+
"ChatResponse",
|
|
35
|
+
"create_cancel_pair",
|
|
36
|
+
"with_cancellation",
|
|
37
|
+
]
|