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.
Files changed (84) hide show
  1. ai_lib_python/__init__.py +43 -0
  2. ai_lib_python/batch/__init__.py +15 -0
  3. ai_lib_python/batch/collector.py +244 -0
  4. ai_lib_python/batch/executor.py +224 -0
  5. ai_lib_python/cache/__init__.py +26 -0
  6. ai_lib_python/cache/backends.py +380 -0
  7. ai_lib_python/cache/key.py +237 -0
  8. ai_lib_python/cache/manager.py +332 -0
  9. ai_lib_python/client/__init__.py +37 -0
  10. ai_lib_python/client/builder.py +528 -0
  11. ai_lib_python/client/cancel.py +368 -0
  12. ai_lib_python/client/core.py +433 -0
  13. ai_lib_python/client/response.py +134 -0
  14. ai_lib_python/embeddings/__init__.py +36 -0
  15. ai_lib_python/embeddings/client.py +339 -0
  16. ai_lib_python/embeddings/types.py +234 -0
  17. ai_lib_python/embeddings/vectors.py +246 -0
  18. ai_lib_python/errors/__init__.py +41 -0
  19. ai_lib_python/errors/base.py +316 -0
  20. ai_lib_python/errors/classification.py +210 -0
  21. ai_lib_python/guardrails/__init__.py +35 -0
  22. ai_lib_python/guardrails/base.py +336 -0
  23. ai_lib_python/guardrails/filters.py +583 -0
  24. ai_lib_python/guardrails/validators.py +475 -0
  25. ai_lib_python/pipeline/__init__.py +55 -0
  26. ai_lib_python/pipeline/accumulate.py +248 -0
  27. ai_lib_python/pipeline/base.py +240 -0
  28. ai_lib_python/pipeline/decode.py +281 -0
  29. ai_lib_python/pipeline/event_map.py +506 -0
  30. ai_lib_python/pipeline/fan_out.py +284 -0
  31. ai_lib_python/pipeline/select.py +297 -0
  32. ai_lib_python/plugins/__init__.py +32 -0
  33. ai_lib_python/plugins/base.py +294 -0
  34. ai_lib_python/plugins/hooks.py +296 -0
  35. ai_lib_python/plugins/middleware.py +285 -0
  36. ai_lib_python/plugins/registry.py +294 -0
  37. ai_lib_python/protocol/__init__.py +71 -0
  38. ai_lib_python/protocol/loader.py +317 -0
  39. ai_lib_python/protocol/manifest.py +385 -0
  40. ai_lib_python/protocol/validator.py +460 -0
  41. ai_lib_python/py.typed +1 -0
  42. ai_lib_python/resilience/__init__.py +102 -0
  43. ai_lib_python/resilience/backpressure.py +225 -0
  44. ai_lib_python/resilience/circuit_breaker.py +318 -0
  45. ai_lib_python/resilience/executor.py +343 -0
  46. ai_lib_python/resilience/fallback.py +341 -0
  47. ai_lib_python/resilience/preflight.py +413 -0
  48. ai_lib_python/resilience/rate_limiter.py +291 -0
  49. ai_lib_python/resilience/retry.py +299 -0
  50. ai_lib_python/resilience/signals.py +283 -0
  51. ai_lib_python/routing/__init__.py +118 -0
  52. ai_lib_python/routing/manager.py +593 -0
  53. ai_lib_python/routing/strategy.py +345 -0
  54. ai_lib_python/routing/types.py +397 -0
  55. ai_lib_python/structured/__init__.py +33 -0
  56. ai_lib_python/structured/json_mode.py +281 -0
  57. ai_lib_python/structured/schema.py +316 -0
  58. ai_lib_python/structured/validator.py +334 -0
  59. ai_lib_python/telemetry/__init__.py +127 -0
  60. ai_lib_python/telemetry/exporters/__init__.py +9 -0
  61. ai_lib_python/telemetry/exporters/prometheus.py +111 -0
  62. ai_lib_python/telemetry/feedback.py +446 -0
  63. ai_lib_python/telemetry/health.py +409 -0
  64. ai_lib_python/telemetry/logger.py +389 -0
  65. ai_lib_python/telemetry/metrics.py +496 -0
  66. ai_lib_python/telemetry/tracer.py +473 -0
  67. ai_lib_python/tokens/__init__.py +25 -0
  68. ai_lib_python/tokens/counter.py +282 -0
  69. ai_lib_python/tokens/estimator.py +286 -0
  70. ai_lib_python/transport/__init__.py +34 -0
  71. ai_lib_python/transport/auth.py +141 -0
  72. ai_lib_python/transport/http.py +364 -0
  73. ai_lib_python/transport/pool.py +425 -0
  74. ai_lib_python/types/__init__.py +41 -0
  75. ai_lib_python/types/events.py +343 -0
  76. ai_lib_python/types/message.py +332 -0
  77. ai_lib_python/types/tool.py +191 -0
  78. ai_lib_python/utils/__init__.py +21 -0
  79. ai_lib_python/utils/tool_call_assembler.py +317 -0
  80. ai_lib_python-0.5.0.dist-info/METADATA +837 -0
  81. ai_lib_python-0.5.0.dist-info/RECORD +84 -0
  82. ai_lib_python-0.5.0.dist-info/WHEEL +4 -0
  83. ai_lib_python-0.5.0.dist-info/licenses/LICENSE-APACHE +201 -0
  84. 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
+ ]