0
# Models and Conversations
1
2
Core model management, conversation handling, prompt processing, and response streaming functionality. This module provides both synchronous and asynchronous APIs for interacting with Large Language Models from multiple providers.
3
4
## Capabilities
5
6
### Model Discovery and Management
7
8
The package provides functions to discover, retrieve, and manage models from various providers through a plugin-based registration system.
9
10
```python { .api }
11
def get_model(name: Optional[str] = None) -> Model:
12
"""
13
Get a model by name or alias. Returns the default model if name is None.
14
15
Args:
16
name: Model name or alias. Uses default if None.
17
18
Returns:
19
Model instance
20
21
Raises:
22
UnknownModelError: If model name/alias not found
23
"""
24
25
def get_async_model(name: Optional[str] = None) -> AsyncModel:
26
"""
27
Get an async model by name or alias. Returns default async model if name is None.
28
29
Args:
30
name: Model name or alias. Uses default if None.
31
32
Returns:
33
AsyncModel instance
34
35
Raises:
36
UnknownModelError: If async model name/alias not found
37
"""
38
39
def get_models() -> List[Model]:
40
"""Get all registered synchronous models."""
41
42
def get_async_models() -> List[AsyncModel]:
43
"""Get all registered asynchronous models."""
44
45
def get_models_with_aliases() -> List[ModelWithAliases]:
46
"""Get models with their configured aliases."""
47
48
def get_model_aliases() -> Dict[str, Model]:
49
"""Get mapping of all aliases to their corresponding models."""
50
51
def get_async_model_aliases() -> Dict[str, AsyncModel]:
52
"""Get mapping of all aliases to their corresponding async models."""
53
```
54
55
### Model Hierarchy
56
57
The package defines an abstract model hierarchy supporting both synchronous and asynchronous operations.
58
59
```python { .api }
60
class Model(ABC):
61
"""Abstract base class for synchronous LLM models."""
62
model_id: str
63
64
@abstractmethod
65
def prompt(self, prompt: Prompt, **kwargs) -> Response:
66
"""Execute a prompt and return response."""
67
68
def conversation(self, **kwargs) -> Conversation:
69
"""Create a new conversation with this model."""
70
71
class KeyModel(Model):
72
"""Abstract base for models requiring API keys."""
73
needs_key: str
74
key_env_var: Optional[str] = None
75
76
def __init__(self, key: Optional[str] = None):
77
"""Initialize with optional API key."""
78
79
class AsyncModel(ABC):
80
"""Abstract base class for asynchronous LLM models."""
81
model_id: str
82
83
@abstractmethod
84
async def prompt(self, prompt: Prompt, **kwargs) -> AsyncResponse:
85
"""Execute a prompt asynchronously and return response."""
86
87
def conversation(self, **kwargs) -> AsyncConversation:
88
"""Create a new async conversation with this model."""
89
90
class AsyncKeyModel(AsyncModel):
91
"""Abstract base for async models requiring API keys."""
92
needs_key: str
93
key_env_var: Optional[str] = None
94
95
def __init__(self, key: Optional[str] = None):
96
"""Initialize with optional API key."""
97
98
class ModelWithAliases:
99
"""Container for a model with its aliases."""
100
model: Model
101
async_model: Optional[AsyncModel]
102
aliases: List[str]
103
104
class Options(BaseModel):
105
"""Pydantic model for model configuration options."""
106
model_config = ConfigDict(extra="forbid")
107
```
108
109
### Conversation Management
110
111
Conversations maintain state and history across multiple prompt-response interactions.
112
113
```python { .api }
114
class Conversation:
115
"""Synchronous conversation management with tool chaining support."""
116
117
def __init__(self, model: Optional[Model] = None, conversation_id: Optional[str] = None):
118
"""
119
Initialize conversation.
120
121
Args:
122
model: Model to use for conversation
123
conversation_id: Optional conversation ID for persistence
124
"""
125
126
def prompt(
127
self,
128
prompt: Union[str, Prompt],
129
*,
130
attachments: Optional[List[Attachment]] = None,
131
tools: Optional[List[Tool]] = None,
132
stream: bool = False,
133
**kwargs
134
) -> Response:
135
"""
136
Send a prompt and get response.
137
138
Args:
139
prompt: Text prompt or Prompt object
140
attachments: Optional file/URL attachments
141
tools: Optional tools for function calling
142
stream: Whether to stream response
143
**kwargs: Additional model options
144
145
Returns:
146
Response object with text and metadata
147
"""
148
149
def responses(self) -> List[Response]:
150
"""Get all responses in conversation history."""
151
152
class AsyncConversation:
153
"""Asynchronous conversation management with tool chaining support."""
154
155
def __init__(self, model: Optional[AsyncModel] = None, conversation_id: Optional[str] = None):
156
"""Initialize async conversation."""
157
158
async def prompt(
159
self,
160
prompt: Union[str, Prompt],
161
*,
162
attachments: Optional[List[Attachment]] = None,
163
tools: Optional[List[Tool]] = None,
164
stream: bool = False,
165
**kwargs
166
) -> AsyncResponse:
167
"""Send a prompt asynchronously and get response."""
168
169
async def responses(self) -> List[AsyncResponse]:
170
"""Get all responses in conversation history."""
171
```
172
173
### Prompt System
174
175
The Prompt class provides a rich container for input data including text, attachments, tools, and structured schemas.
176
177
```python { .api }
178
class Prompt:
179
"""Container for prompts with tools, schema, and attachments."""
180
181
def __init__(
182
self,
183
prompt: Optional[str] = None,
184
*,
185
system: Optional[str] = None,
186
attachments: Optional[List[Attachment]] = None,
187
tools: Optional[List[Tool]] = None,
188
tool_choice: Optional[str] = None,
189
schema: Optional[dict] = None,
190
options: Optional[Options] = None
191
):
192
"""
193
Initialize prompt.
194
195
Args:
196
prompt: Main prompt text
197
system: System message
198
attachments: File/URL attachments
199
tools: Available tools for function calling
200
tool_choice: Tool selection strategy
201
schema: JSON schema for structured output
202
options: Model configuration options
203
"""
204
205
def __str__(self) -> str:
206
"""Return prompt text."""
207
208
class Attachment:
209
"""File/URL/binary content attachment to prompts."""
210
211
def __init__(
212
self,
213
type: Optional[str] = None,
214
path: Optional[str] = None,
215
url: Optional[str] = None,
216
content: Optional[bytes] = None
217
):
218
"""
219
Initialize attachment.
220
221
Args:
222
type: MIME type
223
path: File path
224
url: URL to content
225
content: Binary content
226
"""
227
228
def id(self) -> str:
229
"""Generate content hash ID."""
230
231
def resolve_type(self) -> str:
232
"""Determine MIME type from content/path/URL."""
233
234
def content_bytes(self) -> bytes:
235
"""Get content as bytes."""
236
237
def base64_content(self) -> str:
238
"""Get base64-encoded content."""
239
```
240
241
### Response Handling
242
243
Response objects provide access to model output with support for streaming, tool calls, and metadata.
244
245
```python { .api }
246
class Response:
247
"""Synchronous response object with streaming support."""
248
249
def text(self) -> str:
250
"""Get complete response text."""
251
252
def __iter__(self) -> Iterator[str]:
253
"""Stream response text chunks."""
254
255
def tool_calls(self) -> List[ToolCall]:
256
"""Get tool calls made during response."""
257
258
def usage(self) -> Usage:
259
"""Get token usage information."""
260
261
def response_json(self) -> Optional[dict]:
262
"""Get structured JSON response if schema was provided."""
263
264
class AsyncResponse:
265
"""Asynchronous response object for streaming/awaitable results."""
266
267
async def text(self) -> str:
268
"""Get complete response text asynchronously."""
269
270
def __aiter__(self) -> AsyncIterator[str]:
271
"""Stream response text chunks asynchronously."""
272
273
async def tool_calls(self) -> List[ToolCall]:
274
"""Get tool calls made during response."""
275
276
async def usage(self) -> Usage:
277
"""Get token usage information."""
278
279
async def response_json(self) -> Optional[dict]:
280
"""Get structured JSON response if schema was provided."""
281
282
class ChainResponse(Response):
283
"""Synchronous chained tool execution response."""
284
285
def responses(self) -> List[Response]:
286
"""Get all responses in the tool chain."""
287
288
class AsyncChainResponse(AsyncResponse):
289
"""Asynchronous chained tool execution response."""
290
291
async def responses(self) -> List[AsyncResponse]:
292
"""Get all responses in the tool chain."""
293
```
294
295
### Usage Tracking
296
297
The Usage class tracks token consumption and provides detailed usage statistics.
298
299
```python { .api }
300
class Usage:
301
"""Token usage tracking with detailed breakdown."""
302
303
def __init__(
304
self,
305
input: Optional[int] = None,
306
output: Optional[int] = None,
307
details: Optional[Dict[str, Any]] = None
308
):
309
"""
310
Initialize usage tracking.
311
312
Args:
313
input: Input token count
314
output: Output token count
315
details: Additional usage details
316
"""
317
318
input: Optional[int]
319
output: Optional[int]
320
details: Optional[Dict[str, Any]]
321
```
322
323
## Error Handling
324
325
The models module defines several exception classes for error handling:
326
327
```python { .api }
328
class ModelError(Exception):
329
"""Base exception for model-related errors."""
330
331
class NeedsKeyException(ModelError):
332
"""Raised when API key is required but missing."""
333
334
class UnknownModelError(KeyError):
335
"""Raised when model name or alias is not found."""
336
```
337
338
## Usage Examples
339
340
### Basic Model Usage
341
342
```python
343
import llm
344
345
# Get default model and send prompt
346
model = llm.get_model()
347
response = model.prompt("What is machine learning?")
348
print(response.text())
349
350
# Use specific model
351
model = llm.get_model("gpt-4")
352
response = model.prompt("Explain quantum computing in simple terms")
353
print(response.text())
354
```
355
356
### Streaming Responses
357
358
```python
359
import llm
360
361
model = llm.get_model()
362
response = model.prompt("Write a short story", stream=True)
363
364
# Stream response chunks
365
for chunk in response:
366
print(chunk, end="", flush=True)
367
print() # Final newline
368
```
369
370
### Conversation with History
371
372
```python
373
import llm
374
375
model = llm.get_model("claude-3-sonnet")
376
conversation = model.conversation()
377
378
# Multi-turn conversation
379
response1 = conversation.prompt("My name is Alice. What's a good hobby?")
380
print("Assistant:", response1.text())
381
382
response2 = conversation.prompt("Can you suggest books about that hobby?")
383
print("Assistant:", response2.text())
384
385
# Access conversation history
386
for response in conversation.responses():
387
print(f"Usage: {response.usage()}")
388
```
389
390
### Async Operations
391
392
```python
393
import asyncio
394
import llm
395
396
async def async_example():
397
model = llm.get_async_model("gpt-4")
398
conversation = model.conversation()
399
400
response = await conversation.prompt("Hello, how are you?")
401
text = await response.text()
402
print(text)
403
404
# Async streaming
405
response = await conversation.prompt("Tell me a joke", stream=True)
406
async for chunk in response:
407
print(chunk, end="", flush=True)
408
409
asyncio.run(async_example())
410
```
411
412
### Attachments and Media
413
414
```python
415
import llm
416
417
model = llm.get_model("gpt-4-vision")
418
419
# File attachment
420
attachment = llm.Attachment(path="/path/to/image.jpg")
421
response = model.prompt("Describe this image", attachments=[attachment])
422
print(response.text())
423
424
# URL attachment
425
attachment = llm.Attachment(url="https://example.com/document.pdf")
426
response = model.prompt("Summarize this document", attachments=[attachment])
427
print(response.text())
428
429
# Binary content
430
with open("data.png", "rb") as f:
431
content = f.read()
432
attachment = llm.Attachment(content=content, type="image/png")
433
response = model.prompt("What's in this image?", attachments=[attachment])
434
print(response.text())
435
```
436
437
### Structured Output
438
439
```python
440
import llm
441
442
model = llm.get_model("gpt-4")
443
444
# Define JSON schema for structured response
445
schema = {
446
"type": "object",
447
"properties": {
448
"name": {"type": "string"},
449
"age": {"type": "number"},
450
"skills": {
451
"type": "array",
452
"items": {"type": "string"}
453
}
454
},
455
"required": ["name", "age"]
456
}
457
458
response = model.prompt(
459
"Create a profile for a software engineer",
460
schema=schema
461
)
462
463
# Get structured JSON response
464
profile = response.response_json()
465
print(f"Name: {profile['name']}")
466
print(f"Age: {profile['age']}")
467
print(f"Skills: {', '.join(profile['skills'])}")
468
```
469
470
This comprehensive models and conversations system provides the foundation for all LLM interactions in the package, supporting both simple prompting and complex multi-turn conversations with rich media and structured outputs.