0
# Results and Exceptions
1
2
Run results contain the complete output of agent execution including final output, items, usage statistics, and guardrail results. The SDK provides a comprehensive exception hierarchy for handling errors during agent execution.
3
4
## Capabilities
5
6
### Run Result
7
8
Result of completed agent run with all outputs and metadata.
9
10
```python { .api }
11
class RunResult:
12
"""
13
Result of completed agent run.
14
15
Attributes:
16
- input: str | list[TResponseInputItem] - Original input
17
- new_items: list[RunItem] - Generated items during run
18
- raw_responses: list[ModelResponse] - LLM responses
19
- final_output: Any - Last agent output
20
- input_guardrail_results: list[InputGuardrailResult] - Input guardrail results
21
- output_guardrail_results: list[OutputGuardrailResult] - Output guardrail results
22
- tool_input_guardrail_results: list[ToolInputGuardrailResult] - Tool input results
23
- tool_output_guardrail_results: list[ToolOutputGuardrailResult] - Tool output results
24
- context_wrapper: RunContextWrapper - Run context
25
26
Properties:
27
- last_agent: Agent - Last agent that ran
28
- last_response_id: str | None - Last response ID for continuation
29
"""
30
31
def final_output_as(cls: type[T], raise_if_incorrect_type: bool = True) -> T:
32
"""
33
Cast final output to specific type.
34
35
Parameters:
36
- cls: Type to cast to
37
- raise_if_incorrect_type: Raise error if type mismatch (default: True)
38
39
Returns:
40
- T: Final output cast to type
41
42
Raises:
43
- TypeError: If type mismatch and raise_if_incorrect_type=True
44
"""
45
46
def to_input_list() -> list[TResponseInputItem]:
47
"""
48
Create input list for next run.
49
50
Useful for manual conversation history management.
51
52
Returns:
53
- list[TResponseInputItem]: Items formatted for next input
54
"""
55
56
def release_agents(release_new_items: bool = True) -> None:
57
"""
58
Release agent references for memory management.
59
60
Parameters:
61
- release_new_items: Also release agents from items
62
"""
63
```
64
65
Usage example:
66
67
```python
68
from agents import Agent, Runner
69
from pydantic import BaseModel
70
71
class Answer(BaseModel):
72
answer: str
73
confidence: float
74
75
agent = Agent(
76
name="Assistant",
77
output_type=Answer
78
)
79
80
result = Runner.run_sync(agent, "What is 2+2?")
81
82
# Access final output
83
print(result.final_output)
84
85
# Type-safe access
86
answer = result.final_output_as(Answer)
87
print(f"Answer: {answer.answer}, Confidence: {answer.confidence}")
88
89
# Inspect items
90
for item in result.new_items:
91
print(item)
92
93
# Check usage
94
for response in result.raw_responses:
95
print(f"Tokens: {response.usage.total_tokens}")
96
97
# Continue conversation
98
next_input = result.to_input_list() + ["What about 3+3?"]
99
next_result = Runner.run_sync(agent, next_input)
100
```
101
102
### Run Result Streaming
103
104
Result of streaming agent run with progress tracking.
105
106
```python { .api }
107
class RunResultStreaming:
108
"""
109
Result of streaming agent run.
110
111
Attributes:
112
- current_agent: Agent - Currently running agent
113
- current_turn: int - Current turn number
114
- max_turns: int - Maximum turns
115
- is_complete: bool - Whether run is complete
116
- trace: Trace | None - Associated trace
117
"""
118
119
async def stream_events() -> AsyncIterator[StreamEvent]:
120
"""
121
Stream events from agent execution.
122
123
Yields:
124
- StreamEvent: Events as they occur
125
126
Returns:
127
- AsyncIterator: Event stream
128
"""
129
130
def cancel(mode: Literal["immediate", "after_turn"]) -> None:
131
"""
132
Cancel streaming run.
133
134
Parameters:
135
- mode: Cancellation mode
136
- "immediate": Cancel immediately
137
- "after_turn": Cancel after current turn completes
138
"""
139
```
140
141
Usage example:
142
143
```python
144
import asyncio
145
146
async def streaming_example():
147
result = Runner.run_streamed(agent, "Tell a story")
148
149
print(f"Max turns: {result.max_turns}")
150
151
async for event in result.stream_events():
152
if event.type == "raw_response_event":
153
print(event.data, end='')
154
155
if result.current_turn > 5:
156
result.cancel("immediate")
157
break
158
159
print(f"Completed: {result.is_complete}")
160
print(f"Final output: {result.final_output}")
161
162
asyncio.run(streaming_example())
163
```
164
165
### Usage Tracking
166
167
Token usage information across all LLM calls.
168
169
```python { .api }
170
class Usage:
171
"""
172
Token usage tracking.
173
174
Attributes:
175
- requests: int - Total requests made
176
- input_tokens: int - Total input tokens
177
- input_tokens_details: InputTokensDetails - Detailed input token breakdown
178
- output_tokens: int - Total output tokens
179
- output_tokens_details: OutputTokensDetails - Detailed output token breakdown
180
- total_tokens: int - Total tokens (input + output)
181
- request_usage_entries: list[RequestUsage] - Per-request breakdown
182
"""
183
184
def add(other: Usage) -> None:
185
"""
186
Aggregate another Usage object.
187
188
Parameters:
189
- other: Usage object to add
190
"""
191
192
class RequestUsage:
193
"""
194
Usage for single request.
195
196
Attributes:
197
- input_tokens: int - Input tokens for this request
198
- output_tokens: int - Output tokens for this request
199
- total_tokens: int - Total tokens for this request
200
- input_tokens_details: InputTokensDetails - Input token details
201
- output_tokens_details: OutputTokensDetails - Output token details
202
"""
203
```
204
205
Usage example:
206
207
```python
208
result = Runner.run_sync(agent, "Long task with multiple tool calls")
209
210
usage = result.raw_responses[0].usage
211
print(f"Total tokens: {usage.total_tokens}")
212
print(f"Input tokens: {usage.input_tokens}")
213
print(f"Output tokens: {usage.output_tokens}")
214
print(f"Requests: {usage.requests}")
215
216
# Per-request breakdown
217
for entry in usage.request_usage_entries:
218
print(f"Request: {entry.total_tokens} tokens")
219
220
# Aggregate usage across multiple runs
221
total_usage = Usage()
222
for response in result.raw_responses:
223
total_usage.add(response.usage)
224
```
225
226
## Exception Hierarchy
227
228
### Base Exception
229
230
Base class for all SDK exceptions.
231
232
```python { .api }
233
class AgentsException(Exception):
234
"""
235
Base exception for all SDK exceptions.
236
237
Attributes:
238
- run_data: RunErrorDetails | None - Error details from run
239
"""
240
```
241
242
### Max Turns Exceeded
243
244
Raised when agent reaches maximum turn limit.
245
246
```python { .api }
247
class MaxTurnsExceeded(AgentsException):
248
"""
249
Raised when max turns exceeded.
250
251
Attributes:
252
- message: str - Error message
253
"""
254
```
255
256
Usage example:
257
258
```python
259
from agents import MaxTurnsExceeded
260
261
try:
262
result = Runner.run_sync(
263
agent,
264
"Complex task",
265
max_turns=5
266
)
267
except MaxTurnsExceeded as e:
268
print(f"Agent exceeded max turns: {e.message}")
269
# Access partial results
270
if e.run_data:
271
print(f"Items generated: {len(e.run_data.new_items)}")
272
```
273
274
### Model Behavior Error
275
276
Raised for unexpected model behavior.
277
278
```python { .api }
279
class ModelBehaviorError(AgentsException):
280
"""
281
Raised for unexpected model behavior.
282
283
Attributes:
284
- message: str - Error message
285
"""
286
```
287
288
### User Error
289
290
Raised for user-caused errors (invalid configuration, etc.).
291
292
```python { .api }
293
class UserError(AgentsException):
294
"""
295
Raised for user errors.
296
297
Attributes:
298
- message: str - Error message
299
"""
300
```
301
302
### Guardrail Exceptions
303
304
Exceptions raised when guardrails trigger.
305
306
```python { .api }
307
class InputGuardrailTripwireTriggered(AgentsException):
308
"""
309
Raised when input guardrail trips.
310
311
Attributes:
312
- guardrail_result: InputGuardrailResult - Guardrail result with details
313
"""
314
315
class OutputGuardrailTripwireTriggered(AgentsException):
316
"""
317
Raised when output guardrail trips.
318
319
Attributes:
320
- guardrail_result: OutputGuardrailResult - Guardrail result with details
321
"""
322
323
class ToolInputGuardrailTripwireTriggered(AgentsException):
324
"""
325
Raised when tool input guardrail trips.
326
327
Attributes:
328
- guardrail: ToolInputGuardrail - The guardrail that tripped
329
- output: ToolGuardrailFunctionOutput - Check output with details
330
"""
331
332
class ToolOutputGuardrailTripwireTriggered(AgentsException):
333
"""
334
Raised when tool output guardrail trips.
335
336
Attributes:
337
- guardrail: ToolOutputGuardrail - The guardrail that tripped
338
- output: ToolGuardrailFunctionOutput - Check output with details
339
"""
340
```
341
342
Usage example:
343
344
```python
345
from agents import InputGuardrailTripwireTriggered, OutputGuardrailTripwireTriggered
346
347
try:
348
result = Runner.run_sync(agent, user_input)
349
except InputGuardrailTripwireTriggered as e:
350
print(f"Input blocked by: {e.guardrail_result.guardrail.get_name()}")
351
print(f"Reason: {e.guardrail_result.output.output_info}")
352
except OutputGuardrailTripwireTriggered as e:
353
print(f"Output blocked by: {e.guardrail_result.guardrail.get_name()}")
354
print(f"Reason: {e.guardrail_result.output.output_info}")
355
```
356
357
### Run Error Details
358
359
Error context from failed runs.
360
361
```python { .api }
362
class RunErrorDetails:
363
"""
364
Error data from agent run.
365
366
Attributes:
367
- input: str | list[TResponseInputItem] - Original input
368
- new_items: list[RunItem] - Items generated before error
369
- raw_responses: list[ModelResponse] - Responses before error
370
- last_agent: Agent - Last agent that ran
371
- context_wrapper: RunContextWrapper - Run context
372
- input_guardrail_results: list[InputGuardrailResult] - Input results
373
- output_guardrail_results: list[OutputGuardrailResult] - Output results
374
"""
375
```
376
377
## Error Handling Patterns
378
379
### Basic Error Handling
380
381
```python
382
from agents import AgentsException, MaxTurnsExceeded, ModelBehaviorError
383
384
try:
385
result = Runner.run_sync(agent, user_input)
386
print(result.final_output)
387
except MaxTurnsExceeded as e:
388
print("Agent took too many turns, try simplifying the task")
389
except ModelBehaviorError as e:
390
print(f"Model error: {e.message}")
391
except AgentsException as e:
392
print(f"Agent error: {e}")
393
except Exception as e:
394
print(f"Unexpected error: {e}")
395
```
396
397
### Guardrail Error Handling
398
399
```python
400
from agents import (
401
InputGuardrailTripwireTriggered,
402
OutputGuardrailTripwireTriggered,
403
ToolInputGuardrailTripwireTriggered,
404
ToolOutputGuardrailTripwireTriggered
405
)
406
407
try:
408
result = Runner.run_sync(agent, user_input)
409
except InputGuardrailTripwireTriggered as e:
410
# Handle input rejection
411
return {"error": "Input not allowed", "reason": e.guardrail_result.output.output_info}
412
except OutputGuardrailTripwireTriggered as e:
413
# Handle output rejection
414
return {"error": "Output filtered", "reason": e.guardrail_result.output.output_info}
415
except (ToolInputGuardrailTripwireTriggered, ToolOutputGuardrailTripwireTriggered) as e:
416
# Handle tool guardrail
417
return {"error": "Tool call blocked", "reason": e.output.output_info}
418
```
419
420
### Retry Logic
421
422
```python
423
import asyncio
424
from agents import AgentsException
425
426
async def run_with_retry(agent, input, max_retries=3):
427
"""Run agent with retry logic."""
428
for attempt in range(max_retries):
429
try:
430
return await Runner.run(agent, input)
431
except MaxTurnsExceeded:
432
if attempt == max_retries - 1:
433
raise
434
# Increase max_turns on retry
435
max_turns = (attempt + 2) * 10
436
print(f"Retry {attempt + 1} with max_turns={max_turns}")
437
except ModelBehaviorError as e:
438
if attempt == max_retries - 1:
439
raise
440
# Wait before retry
441
await asyncio.sleep(2 ** attempt)
442
```
443
444
### Partial Results from Errors
445
446
```python
447
try:
448
result = Runner.run_sync(agent, "Complex multi-step task")
449
except MaxTurnsExceeded as e:
450
# Access partial results
451
if e.run_data:
452
print(f"Generated {len(e.run_data.new_items)} items before error")
453
# Use partial results
454
for item in e.run_data.new_items:
455
if isinstance(item, MessageOutputItem):
456
print(f"Partial output: {item}")
457
```
458
459
## Best Practices
460
461
1. **Type Safety**: Use `final_output_as()` for type-safe output access
462
2. **Error Handling**: Always handle AgentsException and its subclasses
463
3. **Usage Tracking**: Monitor token usage for cost control
464
4. **Guardrail Errors**: Provide clear user feedback for guardrail errors
465
5. **Max Turns**: Set appropriate max_turns based on task complexity
466
6. **Retry Logic**: Implement retry for transient errors
467
7. **Partial Results**: Extract useful information from partial results on error
468
8. **Streaming**: Use streaming for long-running tasks with progress feedback
469
9. **Memory Management**: Call `release_agents()` for long-running applications
470
10. **Logging**: Log exceptions with context for debugging
471