Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/cai/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,31 @@ async def process_streamed_response(agent, conversation_input):
agent.model.add_to_message_history(tool_msg)

return result
except OutputGuardrailTripwireTriggered as e:
# Handle guardrail exception specifically - MUST come before broad Exception handler
# Clean up streaming display before showing error
try:
from cai.util import cleanup_all_streaming_resources
cleanup_all_streaming_resources()
except Exception:
pass

# Clean up the async generator
if stream_iterator is not None:
try:
await stream_iterator.aclose()
except Exception:
pass

# Clean up the result object if it has cleanup methods
if result is not None and hasattr(result, '_cleanup_tasks'):
try:
result._cleanup_tasks()
except Exception:
pass

# Re-raise to be caught by outer handler which shows user-friendly message
raise
except (KeyboardInterrupt, asyncio.CancelledError) as e:
# Handle interruption specifically

Expand Down Expand Up @@ -1554,8 +1579,12 @@ async def process_streamed_response(agent, conversation_input):
result._cleanup_tasks()
except Exception:
pass

# Re-raise OutputGuardrailTripwireTriggered to be handled by outer handler
if isinstance(e, OutputGuardrailTripwireTriggered):
raise

# Log error for debugging
# Log error for debugging (non-guardrail exceptions)
logger = logging.getLogger(__name__)
logger.error(f"Error occurred during streaming: {str(e)}", exc_info=True)

Expand Down
4 changes: 4 additions & 0 deletions src/cai/sdk/agents/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,10 @@ async def _run_streamed_impl(

try:
output_guardrail_results = await streamed_result._output_guardrails_task
except OutputGuardrailTripwireTriggered as e:
# Store the guardrail exception immediately so it's checked during streaming
streamed_result._stored_exception = e
output_guardrail_results = []
except Exception:
# Exceptions will be checked in the stream_events loop
output_guardrail_results = []
Expand Down