Base Utilities¶
bruno_llm.base
¶
Base utilities and common functionality for LLM providers.
This module provides shared utilities that all provider implementations can use, including token counting, rate limiting, retry logic, cost tracking, caching, streaming, context management, and middleware.
BaseProvider
¶
Bases: LLMInterface, ABC
Base class for LLM provider implementations.
Provides common functionality that all providers can use: - Retry logic with exponential backoff - Rate limiting - Cost tracking - Error handling patterns
Subclasses must implement the LLMInterface methods: - generate() - stream() - get_token_count() - check_connection() - list_models() - get_model_info() - set_system_prompt() - get_system_prompt()
Example
class MyProvider(BaseProvider): ... async def generate(self, messages, kwargs): ... return await self._with_retry( ... self._generate_impl(messages, kwargs) ... )
Source code in bruno_llm/base/base_provider.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | |
__init__(provider_name, max_retries=3, timeout=30.0, **kwargs)
¶
Initialize base provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider_name
|
str
|
Name of the provider (e.g., "ollama", "openai") |
required |
max_retries
|
int
|
Maximum number of retry attempts |
3
|
timeout
|
float
|
Request timeout in seconds |
30.0
|
**kwargs
|
Any
|
Additional provider-specific configuration |
{}
|
Source code in bruno_llm/base/base_provider.py
set_system_prompt(prompt)
¶
Set system prompt for the provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt
|
str
|
System prompt text |
required |
get_system_prompt()
¶
Get current system prompt.
Returns:
| Type | Description |
|---|---|
Optional[str]
|
Current system prompt or None |
get_model_info()
¶
Get provider and configuration information.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Dict with provider information |
Source code in bruno_llm/base/base_provider.py
CacheEntry
dataclass
¶
Cache entry for a response.
Attributes:
| Name | Type | Description |
|---|---|---|
response |
str
|
The cached response |
timestamp |
float
|
When the entry was cached |
hit_count |
int
|
Number of times this entry was accessed |
tokens |
Optional[int]
|
Token count for the response (if available) |
Source code in bruno_llm/base/cache.py
ResponseCache
¶
LRU cache for LLM responses with TTL support.
Caches responses to avoid redundant API calls. Uses message content and parameters as cache keys. Includes TTL (time-to-live) to ensure responses don't become stale.
Features: - LRU eviction when max_size is reached - TTL-based expiration - Hit/miss statistics - Thread-safe operations (async-safe)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_size
|
int
|
Maximum number of entries to cache (default: 1000) |
1000
|
ttl
|
float
|
Time-to-live in seconds (default: 3600 = 1 hour) |
3600
|
Example
cache = ResponseCache(max_size=100, ttl=300)
Check if response is cached¶
response = cache.get(messages, temperature=0.7) if response is None: ... response = await provider.generate(messages) ... cache.set(messages, response, temperature=0.7)
Source code in bruno_llm/base/cache.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | |
__init__(max_size=1000, ttl=3600)
¶
Initialize response cache.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_size
|
int
|
Maximum number of cached entries |
1000
|
ttl
|
float
|
Time-to-live in seconds for cached entries |
3600
|
Source code in bruno_llm/base/cache.py
get(messages, **kwargs)
¶
Get cached response if available and not expired.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
List of conversation messages |
required |
**kwargs
|
Any
|
Additional generation parameters |
{}
|
Returns:
| Type | Description |
|---|---|
Optional[str]
|
Cached response or None if not found/expired |
Source code in bruno_llm/base/cache.py
set(messages, response, tokens=None, **kwargs)
¶
Cache a response.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
List of conversation messages |
required |
response
|
str
|
The response to cache |
required |
tokens
|
Optional[int]
|
Token count for the response (optional) |
None
|
**kwargs
|
Any
|
Additional generation parameters |
{}
|
Source code in bruno_llm/base/cache.py
clear()
¶
invalidate(messages, **kwargs)
¶
Invalidate a specific cache entry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
List of conversation messages |
required |
**kwargs
|
Any
|
Additional generation parameters |
{}
|
Returns:
| Type | Description |
|---|---|
bool
|
True if entry was found and removed, False otherwise |
Source code in bruno_llm/base/cache.py
get_stats()
¶
Get cache statistics.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Dictionary with cache statistics |
Source code in bruno_llm/base/cache.py
get_size_bytes()
¶
Estimate cache size in bytes.
Returns:
| Type | Description |
|---|---|
int
|
Approximate cache size in bytes |
Source code in bruno_llm/base/cache.py
cleanup_expired()
¶
Remove all expired entries.
Returns:
| Type | Description |
|---|---|
int
|
Number of entries removed |
Source code in bruno_llm/base/cache.py
get_top_entries(n=10)
¶
Get top N most frequently accessed entries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int
|
Number of entries to return |
10
|
Returns:
| Type | Description |
|---|---|
list[tuple[str, CacheEntry]]
|
List of (key, entry) tuples sorted by hit count |
Source code in bruno_llm/base/cache.py
ContextLimits
dataclass
¶
Context window limits for a model.
Attributes:
| Name | Type | Description |
|---|---|---|
max_tokens |
int
|
Maximum total tokens (input + output) |
max_input_tokens |
Optional[int]
|
Maximum input tokens |
max_output_tokens |
Optional[int]
|
Maximum output tokens |
warning_threshold |
float
|
Warn when this % of limit is reached (0.0-1.0) |
Source code in bruno_llm/base/context.py
__post_init__()
¶
Validate limits after initialization.
Source code in bruno_llm/base/context.py
ContextWindowManager
¶
Manage context windows and message truncation.
Handles: - Token counting for messages - Context limit checking - Automatic message truncation - Warning when approaching limits
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Model name for context limits |
required |
token_counter
|
Optional[TokenCounter]
|
Token counter instance |
None
|
limits
|
Optional[ContextLimits]
|
Custom context limits (overrides model defaults) |
None
|
strategy
|
TruncationStrategy
|
Truncation strategy to use |
SLIDING_WINDOW
|
Example
manager = ContextWindowManager(model="gpt-4")
Check if messages fit¶
if manager.check_limit(messages): ... response = await provider.generate(messages) ... else: ... # Truncate messages ... truncated = manager.truncate(messages) ... response = await provider.generate(truncated)
Source code in bruno_llm/base/context.py
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | |
__init__(model, token_counter=None, limits=None, strategy=TruncationStrategy.SLIDING_WINDOW)
¶
Initialize context window manager.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Model name |
required |
token_counter
|
Optional[TokenCounter]
|
Token counter instance |
None
|
limits
|
Optional[ContextLimits]
|
Custom context limits |
None
|
strategy
|
TruncationStrategy
|
Truncation strategy |
SLIDING_WINDOW
|
Source code in bruno_llm/base/context.py
count_tokens(messages)
¶
Count tokens in messages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
List of messages |
required |
Returns:
| Type | Description |
|---|---|
int
|
Total token count |
check_limit(messages, max_output_tokens=None)
¶
Check if messages fit within context limit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
List of messages |
required |
max_output_tokens
|
Optional[int]
|
Expected output tokens |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if messages fit, False otherwise |
Source code in bruno_llm/base/context.py
get_available_tokens(messages)
¶
Get number of tokens available for output.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
List of messages |
required |
Returns:
| Type | Description |
|---|---|
int
|
Available tokens for output |
Source code in bruno_llm/base/context.py
truncate(messages, max_output_tokens=None)
¶
Truncate messages to fit within context limit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
List of messages |
required |
max_output_tokens
|
Optional[int]
|
Expected output tokens |
None
|
Returns:
| Type | Description |
|---|---|
list[Message]
|
Truncated message list |
Raises:
| Type | Description |
|---|---|
ContextLengthExceededError
|
If messages can't be truncated enough |
Source code in bruno_llm/base/context.py
set_warning_callback(callback)
¶
Set callback for context limit warnings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
Callable[[int, int], None]
|
Function (current_tokens, max_tokens) -> None |
required |
get_stats(messages)
¶
Get statistics about context usage.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
List of messages |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Dictionary with context statistics |
Source code in bruno_llm/base/context.py
TruncationStrategy
¶
Bases: Enum
Strategy for truncating messages when context limit is exceeded.
Source code in bruno_llm/base/context.py
CostTracker
¶
Track API usage costs across requests.
Maintains history of API calls with token usage and costs. Supports multiple models with different pricing.
Example
tracker = CostTracker( ... provider_name="openai", ... pricing={ ... "gpt-4": {"input": 0.03, "output": 0.06}, ... "gpt-3.5-turbo": {"input": 0.001, "output": 0.002}, ... } ... ) tracker.track_request( ... model="gpt-4", ... input_tokens=100, ... output_tokens=50 ... ) print(tracker.get_total_cost()) 6.0 # $0.06 (in cents)
Source code in bruno_llm/base/cost_tracker.py
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | |
__init__(provider_name, pricing, currency='USD')
¶
Initialize cost tracker.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider_name
|
str
|
Name of the provider |
required |
pricing
|
dict[str, dict[str, float]]
|
Pricing per model (per 1K tokens) Format: {"model_name": {"input": price, "output": price}} |
required |
currency
|
str
|
Currency code (default: "USD") |
'USD'
|
Source code in bruno_llm/base/cost_tracker.py
track_request(model, input_tokens, output_tokens, metadata=None)
¶
Track a single API request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Model name |
required |
input_tokens
|
int
|
Number of input tokens |
required |
output_tokens
|
int
|
Number of output tokens |
required |
metadata
|
Optional[dict[str, str]]
|
Optional metadata about the request |
None
|
Returns:
| Type | Description |
|---|---|
UsageRecord
|
UsageRecord with calculated costs |
Source code in bruno_llm/base/cost_tracker.py
get_total_cost(model=None)
¶
Get total cost across all requests.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
Optional[str]
|
Optional model filter (None = all models) |
None
|
Returns:
| Type | Description |
|---|---|
float
|
Total cost in the configured currency |
Source code in bruno_llm/base/cost_tracker.py
get_total_tokens(model=None)
¶
Get total tokens used.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
Optional[str]
|
Optional model filter (None = all models) |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
Dict with input, output, and total token counts |
Source code in bruno_llm/base/cost_tracker.py
get_request_count(model=None)
¶
Get number of requests made.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
Optional[str]
|
Optional model filter (None = all models) |
None
|
Returns:
| Type | Description |
|---|---|
int
|
Number of requests |
Source code in bruno_llm/base/cost_tracker.py
get_model_breakdown()
¶
Get cost breakdown by model.
Returns:
| Type | Description |
|---|---|
dict[str, dict[str, float]]
|
Dict mapping model names to their usage statistics |
Source code in bruno_llm/base/cost_tracker.py
get_usage_report()
¶
Get comprehensive usage report.
Returns:
| Type | Description |
|---|---|
dict
|
Dict with complete usage statistics |
Source code in bruno_llm/base/cost_tracker.py
clear_history()
¶
export_history()
¶
Export usage history as list of dicts.
Returns:
| Type | Description |
|---|---|
list[dict]
|
List of usage records as dictionaries |
Source code in bruno_llm/base/cost_tracker.py
export_to_csv(filepath)
¶
Export usage history to CSV file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str
|
Path to output CSV file |
required |
Source code in bruno_llm/base/cost_tracker.py
export_to_json(filepath)
¶
Export usage history to JSON file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str
|
Path to output JSON file |
required |
Source code in bruno_llm/base/cost_tracker.py
get_time_range_report(start_time=None, end_time=None)
¶
Get usage report for a specific time range.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_time
|
Optional[float]
|
Start timestamp (inclusive) |
None
|
end_time
|
Optional[float]
|
End timestamp (inclusive) |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
Usage report for the time range |
Source code in bruno_llm/base/cost_tracker.py
check_budget(budget_limit)
¶
Check if spending is within budget.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
budget_limit
|
float
|
Budget limit in currency units |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Budget status information |
Source code in bruno_llm/base/cost_tracker.py
UsageRecord
dataclass
¶
Record of a single API usage event.
Attributes:
| Name | Type | Description |
|---|---|---|
timestamp |
float
|
When the request was made |
model |
str
|
Model name used |
input_tokens |
int
|
Number of input tokens |
output_tokens |
int
|
Number of output tokens |
input_cost |
float
|
Cost for input tokens |
output_cost |
float
|
Cost for output tokens |
total_cost |
float
|
Total cost for this request |
Source code in bruno_llm/base/cost_tracker.py
BaseEmbeddingProvider
¶
Bases: EmbeddingInterface, ABC
Base class for embedding providers using numpy for vector operations.
This base class implements the EmbeddingInterface from bruno-core and provides: - Efficient vector operations using numpy - Input validation and error handling - Similarity calculation using numpy's optimized functions - Batch processing utilities
All embedding providers should inherit from this class and implement the abstract methods for their specific API or model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Model name or identifier |
required |
timeout
|
float
|
Request timeout in seconds |
30.0
|
Examples:
>>> class MyEmbeddingProvider(BaseEmbeddingProvider):
... async def embed_text(self, text: str) -> List[float]:
... # Implementation specific to your provider
... return await self._call_api(text)
...
... def get_dimension(self) -> int:
... return 768 # Your model's dimension
Source code in bruno_llm/base/embedding_interface.py
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | |
embed_text(text)
abstractmethod
async
¶
Generate embedding for a single text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Input text to embed |
required |
Returns:
| Type | Description |
|---|---|
list[float]
|
Embedding vector as list of floats |
Raises:
| Type | Description |
|---|---|
LLMError
|
If embedding generation fails |
Source code in bruno_llm/base/embedding_interface.py
embed_texts(texts)
async
¶
Generate embeddings for multiple texts.
Default implementation calls embed_text for each text. Override for providers with native batch support.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
texts
|
list[str]
|
List of texts to embed |
required |
Returns:
| Type | Description |
|---|---|
list[list[float]]
|
List of embedding vectors |
Raises:
| Type | Description |
|---|---|
LLMError
|
If any embedding generation fails |
Source code in bruno_llm/base/embedding_interface.py
embed_message(message)
async
¶
Generate embedding for a message.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
Message
|
Message object to embed |
required |
Returns:
| Type | Description |
|---|---|
list[float]
|
Embedding vector for the message content |
Source code in bruno_llm/base/embedding_interface.py
get_dimension()
abstractmethod
¶
Get the embedding dimension for this provider.
Returns:
| Type | Description |
|---|---|
int
|
Number of dimensions in embeddings |
get_model_name()
¶
Get the model name used by this provider.
Returns:
| Type | Description |
|---|---|
str
|
Model name string |
calculate_similarity(embedding1, embedding2)
¶
Calculate cosine similarity between two embeddings using numpy.
Uses numpy's optimized dot product and norm calculations for efficiency.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
embedding1
|
list[float]
|
First embedding vector |
required |
embedding2
|
list[float]
|
Second embedding vector |
required |
Returns:
| Type | Description |
|---|---|
float
|
Cosine similarity (-1.0 to 1.0) |
Raises:
| Type | Description |
|---|---|
ValueError
|
If vectors have different dimensions |
Source code in bruno_llm/base/embedding_interface.py
check_connection()
abstractmethod
async
¶
Check if the provider is accessible.
Returns:
| Type | Description |
|---|---|
bool
|
True if provider can be used, False otherwise |
validate_embedding(embedding, expected_dimension=None)
¶
Validate an embedding vector using numpy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
embedding
|
list[float]
|
Embedding to validate |
required |
expected_dimension
|
Optional[int]
|
Expected dimension (uses get_dimension() if None) |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If embedding is invalid |
Source code in bruno_llm/base/embedding_interface.py
batch_cosine_similarity(embeddings1, embeddings2)
¶
Calculate pairwise cosine similarities between two sets of embeddings.
Uses numpy for efficient batch computation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
embeddings1
|
list[list[float]]
|
First set of embeddings |
required |
embeddings2
|
list[list[float]]
|
Second set of embeddings |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Similarity matrix as numpy array (len(embeddings1) x len(embeddings2)) |
Source code in bruno_llm/base/embedding_interface.py
find_most_similar(query_embedding, candidate_embeddings, top_k=None)
¶
Find most similar embeddings to a query using numpy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query_embedding
|
list[float]
|
Query embedding vector |
required |
candidate_embeddings
|
list[list[float]]
|
List of candidate embeddings |
required |
top_k
|
Optional[int]
|
Number of top results (None = all) |
None
|
Returns:
| Type | Description |
|---|---|
list[tuple[int, float]]
|
List of (index, similarity) tuples sorted by similarity (descending) |
Source code in bruno_llm/base/embedding_interface.py
average_embeddings(embeddings)
¶
Calculate average embedding using numpy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
embeddings
|
list[list[float]]
|
List of embedding vectors |
required |
Returns:
| Type | Description |
|---|---|
list[float]
|
Average embedding vector |
Raises:
| Type | Description |
|---|---|
ValueError
|
If embeddings list is empty |
Source code in bruno_llm/base/embedding_interface.py
weighted_average_embeddings(embeddings, weights)
¶
Calculate weighted average embedding using numpy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
embeddings
|
list[list[float]]
|
List of embedding vectors |
required |
weights
|
list[float]
|
List of weights (must sum to 1.0) |
required |
Returns:
| Type | Description |
|---|---|
list[float]
|
Weighted average embedding |
Raises:
| Type | Description |
|---|---|
ValueError
|
If inputs are invalid |
Source code in bruno_llm/base/embedding_interface.py
CachingMiddleware
¶
Bases: Middleware
Cache responses using ResponseCache.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache
|
ResponseCache instance |
required | |
cache_streaming
|
bool
|
Whether to cache streaming responses |
True
|
Example
from bruno_llm.base.cache import ResponseCache cache = ResponseCache(max_size=100, ttl=300) middleware = CachingMiddleware(cache)
Source code in bruno_llm/base/middleware.py
__init__(cache, cache_streaming=True)
¶
Initialize caching middleware.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache
|
ResponseCache instance |
required | |
cache_streaming
|
bool
|
Whether to cache streaming responses |
True
|
Source code in bruno_llm/base/middleware.py
before_request(messages, **kwargs)
async
¶
Check cache before request.
after_response(messages, response, **kwargs)
async
¶
on_stream_chunk(chunk, **kwargs)
async
¶
Collect stream chunks for caching.
Source code in bruno_llm/base/middleware.py
LoggingMiddleware
¶
Bases: Middleware
Log all requests and responses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logger
|
Logger instance (defaults to structlog) |
None
|
|
log_messages
|
bool
|
Whether to log full message content |
False
|
Example
middleware = LoggingMiddleware(log_messages=False) provider = MiddlewareProvider(base_provider, [middleware])
Source code in bruno_llm/base/middleware.py
__init__(logger=None, log_messages=False)
¶
Initialize logging middleware.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logger
|
Logger instance |
None
|
|
log_messages
|
bool
|
Whether to log message content |
False
|
Source code in bruno_llm/base/middleware.py
before_request(messages, **kwargs)
async
¶
Log before request.
Source code in bruno_llm/base/middleware.py
after_response(messages, response, **kwargs)
async
¶
Log after response.
Source code in bruno_llm/base/middleware.py
on_error(error, messages, **kwargs)
async
¶
Log errors.
Source code in bruno_llm/base/middleware.py
Middleware
¶
Bases: ABC
Base class for provider middleware.
Middleware can intercept and modify: - Request messages before sending to provider - Response text after receiving from provider - Streaming chunks as they arrive - Request parameters (temperature, max_tokens, etc.)
Example
class LoggingMiddleware(Middleware): ... async def before_request(self, messages, kwargs): ... print(f"Sending {len(messages)} messages") ... return messages, kwargs ... ... async def after_response(self, messages, response, kwargs): ... print(f"Received {len(response)} chars") ... return response
Source code in bruno_llm/base/middleware.py
before_request(messages, **kwargs)
abstractmethod
async
¶
Process messages and parameters before request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
Input messages |
required |
**kwargs
|
Any
|
Request parameters |
{}
|
Returns:
| Type | Description |
|---|---|
tuple[list[Message], dict[str, Any]]
|
Tuple of (modified_messages, modified_kwargs) |
Source code in bruno_llm/base/middleware.py
after_response(messages, response, **kwargs)
abstractmethod
async
¶
Process response after receiving.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
Original input messages |
required |
response
|
str
|
Provider response |
required |
**kwargs
|
Any
|
Request parameters used |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
Modified response |
Source code in bruno_llm/base/middleware.py
on_stream_chunk(chunk, **kwargs)
async
¶
Process individual stream chunks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
chunk
|
str
|
Stream chunk |
required |
**kwargs
|
Any
|
Request parameters |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
Modified chunk |
on_error(error, messages, **kwargs)
async
¶
Handle errors during request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
error
|
Exception
|
The exception that occurred |
required |
messages
|
list[Message]
|
Messages that were being processed |
required |
**kwargs
|
Any
|
Request parameters |
{}
|
Source code in bruno_llm/base/middleware.py
MiddlewareChain
¶
Chain multiple middleware together.
Executes middleware in order for before_request, and in reverse order for after_response.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
middlewares
|
list[Middleware]
|
List of middleware instances |
required |
Example
chain = MiddlewareChain([ ... LoggingMiddleware(), ... ValidationMiddleware(), ... CachingMiddleware(cache), ... ]) messages, kwargs = await chain.before_request(messages, **kwargs)
Source code in bruno_llm/base/middleware.py
__init__(middlewares)
¶
Initialize middleware chain.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
middlewares
|
list[Middleware]
|
List of middleware to chain |
required |
before_request(messages, **kwargs)
async
¶
Execute all middleware before_request in order.
Source code in bruno_llm/base/middleware.py
after_response(messages, response, **kwargs)
async
¶
Execute all middleware after_response in reverse order.
Source code in bruno_llm/base/middleware.py
on_stream_chunk(chunk, **kwargs)
async
¶
Execute all middleware on_stream_chunk in order.
on_error(error, messages, **kwargs)
async
¶
Execute all middleware on_error.
RetryMiddleware
¶
Bases: Middleware
Add retry logic with exponential backoff.
Note: This is typically handled by BaseProvider's retry logic, but can be used for additional retry layers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_retries
|
int
|
Maximum number of retries |
3
|
base_delay
|
float
|
Base delay in seconds |
1.0
|
Example
middleware = RetryMiddleware(max_retries=3, base_delay=1.0)
Source code in bruno_llm/base/middleware.py
__init__(max_retries=3, base_delay=1.0)
¶
Initialize retry middleware.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_retries
|
int
|
Maximum retry attempts |
3
|
base_delay
|
float
|
Base delay for exponential backoff |
1.0
|
Source code in bruno_llm/base/middleware.py
before_request(messages, **kwargs)
async
¶
after_response(messages, response, **kwargs)
async
¶
on_error(error, messages, **kwargs)
async
¶
Handle retry logic on error.
Source code in bruno_llm/base/middleware.py
ValidationMiddleware
¶
Bases: Middleware
Validate messages and parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_message_length
|
Optional[int]
|
Max length for individual messages |
None
|
allowed_roles
|
Optional[list[str]]
|
Allowed message roles |
None
|
required_params
|
Optional[list[str]]
|
Required parameter names |
None
|
Example
middleware = ValidationMiddleware( ... max_message_length=10000, ... allowed_roles=["user", "assistant", "system"] ... )
Source code in bruno_llm/base/middleware.py
__init__(max_message_length=None, allowed_roles=None, required_params=None)
¶
Initialize validation middleware.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_message_length
|
Optional[int]
|
Maximum message length |
None
|
allowed_roles
|
Optional[list[str]]
|
Allowed message roles |
None
|
required_params
|
Optional[list[str]]
|
Required parameters |
None
|
Source code in bruno_llm/base/middleware.py
before_request(messages, **kwargs)
async
¶
Validate before request.
Source code in bruno_llm/base/middleware.py
RateLimiter
¶
Async rate limiter using token bucket algorithm.
Controls the rate of API calls to prevent exceeding provider limits. Thread-safe and supports multiple concurrent requests.
Example
limiter = RateLimiter(requests_per_minute=60) async with limiter: ... # Make API call ... response = await api_call()
Source code in bruno_llm/base/rate_limiter.py
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | |
__init__(requests_per_minute=60, tokens_per_minute=None)
¶
Initialize rate limiter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
requests_per_minute
|
int
|
Maximum requests allowed per minute |
60
|
tokens_per_minute
|
Optional[int]
|
Maximum tokens allowed per minute (optional) |
None
|
Source code in bruno_llm/base/rate_limiter.py
acquire(api_tokens=0)
async
¶
Acquire permission to make a request.
Blocks until rate limit allows the request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_tokens
|
int
|
Number of API tokens the request will consume |
0
|
Source code in bruno_llm/base/rate_limiter.py
__aenter__()
async
¶
__aexit__(exc_type, exc_val, exc_tb)
async
¶
get_stats()
¶
Get current rate limiter statistics.
Returns:
| Type | Description |
|---|---|
dict
|
Dict with current token levels and limits |
Source code in bruno_llm/base/rate_limiter.py
RetryConfig
¶
Configuration for retry behavior.
Example
config = RetryConfig( ... max_retries=5, ... initial_delay=1.0, ... max_delay=60.0, ... exponential_base=2.0 ... )
Source code in bruno_llm/base/retry.py
__init__(max_retries=3, initial_delay=1.0, max_delay=60.0, exponential_base=2.0, jitter=True, retry_on=None)
¶
Initialize retry configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_retries
|
int
|
Maximum number of retry attempts |
3
|
initial_delay
|
float
|
Initial delay between retries in seconds |
1.0
|
max_delay
|
float
|
Maximum delay between retries in seconds |
60.0
|
exponential_base
|
float
|
Base for exponential backoff |
2.0
|
jitter
|
bool
|
Whether to add random jitter to delays |
True
|
retry_on
|
Optional[tuple[type[Exception], ...]]
|
Tuple of exception types to retry on (None = all) |
None
|
Source code in bruno_llm/base/retry.py
calculate_delay(attempt)
¶
Calculate delay for given retry attempt.
Uses exponential backoff with optional jitter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
attempt
|
int
|
Retry attempt number (0-indexed) |
required |
Returns:
| Type | Description |
|---|---|
float
|
Delay in seconds |
Source code in bruno_llm/base/retry.py
should_retry(exception, attempt)
¶
Determine if retry should be attempted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exception
|
Exception
|
Exception that was raised |
required |
attempt
|
int
|
Current attempt number (0-indexed) |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if should retry, False otherwise |
Source code in bruno_llm/base/retry.py
RetryDecorator
¶
Decorator for adding retry logic to async functions.
Example
@RetryDecorator(max_retries=5) ... async def api_call(): ... return await external_api()
Source code in bruno_llm/base/retry.py
__init__(max_retries=3, initial_delay=1.0, max_delay=60.0, exponential_base=2.0, jitter=True)
¶
Initialize retry decorator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_retries
|
int
|
Maximum number of retry attempts |
3
|
initial_delay
|
float
|
Initial delay between retries |
1.0
|
max_delay
|
float
|
Maximum delay between retries |
60.0
|
exponential_base
|
float
|
Base for exponential backoff |
2.0
|
jitter
|
bool
|
Whether to add jitter |
True
|
Source code in bruno_llm/base/retry.py
__call__(func)
¶
Wrap function with retry logic.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable[..., T]
|
Function to wrap |
required |
Returns:
| Type | Description |
|---|---|
Callable[..., T]
|
Wrapped function |
Source code in bruno_llm/base/retry.py
StreamAggregator
¶
Aggregate streaming chunks with various strategies.
Provides different aggregation strategies for streaming responses: - Word-by-word: Buffer until complete words - Sentence-by-sentence: Buffer until sentence boundaries - Fixed-size: Buffer until fixed character count - Time-based: Buffer for fixed time intervals
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
strategy
|
str
|
Aggregation strategy ('word', 'sentence', 'fixed', 'time') |
'word'
|
size
|
int
|
Size parameter (chars for 'fixed', seconds for 'time') |
10
|
Example
aggregator = StreamAggregator(strategy='word') async for chunk in aggregator.aggregate(stream): ... print(chunk) # Prints complete words
Source code in bruno_llm/base/streaming.py
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | |
__init__(strategy='word', size=10)
¶
Initialize stream aggregator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
strategy
|
str
|
Aggregation strategy |
'word'
|
size
|
int
|
Size parameter for aggregation |
10
|
Source code in bruno_llm/base/streaming.py
aggregate(stream)
async
¶
Aggregate stream chunks according to strategy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stream
|
AsyncIterator[str]
|
Input stream to aggregate |
required |
Yields:
| Type | Description |
|---|---|
AsyncIterator[str]
|
Aggregated chunks |
Source code in bruno_llm/base/streaming.py
StreamBuffer
dataclass
¶
Buffer for managing streaming chunks.
Provides buffering, batching, and aggregation of stream chunks.
Attributes:
| Name | Type | Description |
|---|---|---|
buffer |
deque[str]
|
Internal deque for storing chunks |
max_size |
int
|
Maximum buffer size in characters |
batch_size |
int
|
Number of chunks to batch before yielding |
stats |
StreamStats
|
Stream statistics |
Source code in bruno_llm/base/streaming.py
add(chunk)
¶
Add a chunk to the buffer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
chunk
|
str
|
Text chunk to buffer |
required |
Raises:
| Type | Description |
|---|---|
StreamError
|
If buffer is full |
Source code in bruno_llm/base/streaming.py
get_batch()
¶
Get a batch of chunks.
Returns:
| Type | Description |
|---|---|
Optional[str]
|
Concatenated batch or None if not enough chunks |
Source code in bruno_llm/base/streaming.py
flush()
¶
Flush all remaining chunks.
Returns:
| Type | Description |
|---|---|
str
|
All remaining chunks concatenated |
is_empty()
¶
StreamProcessor
¶
Process streaming responses with callbacks and error handling.
Provides a framework for processing streams with: - Progress callbacks - Error recovery - Automatic retry on connection loss - Statistics tracking
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
on_chunk
|
Optional[Callable[[str], None]]
|
Callback for each chunk (chunk: str) -> None |
None
|
on_error
|
Optional[Callable[[Exception], None]]
|
Callback for errors (error: Exception) -> None |
None
|
on_complete
|
Optional[Callable[[StreamStats], None]]
|
Callback when stream completes (stats: StreamStats) -> None |
None
|
max_retries
|
int
|
Maximum number of retries on error |
3
|
Example
processor = StreamProcessor( ... on_chunk=lambda chunk: print(chunk, end=""), ... on_error=lambda e: print(f"Error: {e}"), ... on_complete=lambda stats: print(f"\nReceived {stats.chunks_received} chunks") ... ) await processor.process(stream)
Source code in bruno_llm/base/streaming.py
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | |
__init__(on_chunk=None, on_error=None, on_complete=None, max_retries=3)
¶
Initialize stream processor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
on_chunk
|
Optional[Callable[[str], None]]
|
Callback for each chunk |
None
|
on_error
|
Optional[Callable[[Exception], None]]
|
Callback for errors |
None
|
on_complete
|
Optional[Callable[[StreamStats], None]]
|
Callback when stream completes |
None
|
max_retries
|
int
|
Maximum number of retries on error |
3
|
Source code in bruno_llm/base/streaming.py
process(stream, retry_on_error=True)
async
¶
Process a stream with callbacks and error handling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stream
|
AsyncIterator[str]
|
Input stream to process |
required |
retry_on_error
|
bool
|
Whether to retry on errors |
True
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of all chunks received |
Raises:
| Type | Description |
|---|---|
StreamError
|
If max retries exceeded |
Source code in bruno_llm/base/streaming.py
StreamStats
dataclass
¶
Statistics for a streaming session.
Attributes:
| Name | Type | Description |
|---|---|---|
chunks_received |
int
|
Number of chunks received |
total_chars |
int
|
Total characters streamed |
total_tokens |
int
|
Estimated token count |
duration |
float
|
Duration of stream in seconds |
errors |
int
|
Number of errors encountered |
Source code in bruno_llm/base/streaming.py
SimpleTokenCounter
¶
Bases: TokenCounter
Simple token counter using word splitting.
This is a fallback implementation that approximates token count by counting words. Not as accurate as provider-specific tokenizers but works universally.
Example
counter = SimpleTokenCounter() tokens = counter.count_tokens("Hello world!") print(tokens) # Approximately 2-3
Source code in bruno_llm/base/token_counter.py
__init__(chars_per_token=4.0)
¶
Initialize simple token counter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
chars_per_token
|
float
|
Average characters per token (default: 4) |
4.0
|
count_tokens(text)
¶
Count tokens using character-based estimation.
Uses the common approximation that 1 token ≈ 4 characters in English text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Text to count tokens for |
required |
Returns:
| Type | Description |
|---|---|
int
|
Estimated token count |
Source code in bruno_llm/base/token_counter.py
TikTokenCounter
¶
Bases: TokenCounter
Token counter using OpenAI's tiktoken library.
Provides accurate token counting for OpenAI models. Falls back to SimpleTokenCounter if tiktoken is not available.
Example
counter = TikTokenCounter(model="gpt-4") tokens = counter.count_tokens("Hello world!") print(tokens)
Source code in bruno_llm/base/token_counter.py
__init__(model='gpt-4')
¶
Initialize tiktoken-based counter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
str
|
Model name for tiktoken encoding |
'gpt-4'
|
Source code in bruno_llm/base/token_counter.py
count_tokens(text)
¶
Count tokens using tiktoken or fallback.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Text to count tokens for |
required |
Returns:
| Type | Description |
|---|---|
int
|
Accurate token count (if tiktoken available) or estimate |
Source code in bruno_llm/base/token_counter.py
TokenCounter
¶
Bases: ABC
Abstract base class for token counting.
Different providers may have different tokenization methods. Subclasses should implement provider-specific counting logic.
Source code in bruno_llm/base/token_counter.py
count_tokens(text)
abstractmethod
¶
Count tokens in text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Text to count tokens for |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of tokens |
count_message_tokens(message)
¶
Count tokens in a message.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
Message
|
Message to count tokens for |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of tokens |
count_messages_tokens(messages)
¶
Count tokens in multiple messages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[Message]
|
List of messages |
required |
Returns:
| Type | Description |
|---|---|
int
|
Total number of tokens |
Source code in bruno_llm/base/token_counter.py
retry_async(func, *args, config=None, **kwargs)
async
¶
Execute async function with retry logic.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable[..., T]
|
Async function to execute |
required |
*args
|
Any
|
Positional arguments for func |
()
|
config
|
Optional[RetryConfig]
|
Retry configuration (uses defaults if None) |
None
|
**kwargs
|
Any
|
Keyword arguments for func |
{}
|
Returns:
| Type | Description |
|---|---|
T
|
Result from func |
Raises:
| Type | Description |
|---|---|
Exception
|
Last exception if all retries fail |
Example
async def api_call(): ... # May fail transiently ... return await external_api() result = await retry_async(api_call, config=RetryConfig(max_retries=5))
Source code in bruno_llm/base/retry.py
stream_with_timeout(stream, timeout=30.0)
async
¶
Wrap a stream with timeout protection.
Raises TimeoutError if no chunk is received within timeout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stream
|
AsyncIterator[str]
|
Input stream to wrap |
required |
timeout
|
float
|
Timeout in seconds for each chunk |
30.0
|
Yields:
| Type | Description |
|---|---|
AsyncIterator[str]
|
Stream chunks |
Raises:
| Type | Description |
|---|---|
TimeoutError
|
If timeout is exceeded |
Example
async for chunk in stream_with_timeout(stream, timeout=10.0): ... print(chunk)
Source code in bruno_llm/base/streaming.py
create_token_counter(provider='simple', model=None)
¶
Factory function to create appropriate token counter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
str
|
Provider name ("simple", "openai", "tiktoken") |
'simple'
|
model
|
Optional[str]
|
Optional model name for provider-specific counting |
None
|
Returns:
| Type | Description |
|---|---|
TokenCounter
|
TokenCounter instance |
Example
counter = create_token_counter("openai", model="gpt-4") tokens = counter.count_tokens("Hello!")