mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: fix(claude): handle API errors in run_stream() method (#3653)
* fix(claude): handle API errors in run_stream() method - Import AssistantMessage and TextBlock from claude_agent_sdk - Check AssistantMessage.error and raise ServiceException with descriptive message - Check ResultMessage.is_error and raise ServiceException with error details - Add tests for error handling in run_stream() Fixes #3652 * fix: add defensive check for message.content before iterating Address PR review feedback - add null check for message.content to prevent potential AttributeError if content is None. * chore: refresh uv.lock * chore: fix import sorting * chore: refresh uv.lock
This commit is contained in:
committed by
GitHub
Unverified
parent
0daa7700c6
commit
9e51e2f0bc
@@ -23,15 +23,16 @@ from agent_framework import (
|
||||
from agent_framework._types import normalize_tools
|
||||
from agent_framework.exceptions import ServiceException, ServiceInitializationError
|
||||
from claude_agent_sdk import (
|
||||
ClaudeAgentOptions as SDKOptions,
|
||||
)
|
||||
from claude_agent_sdk import (
|
||||
AssistantMessage,
|
||||
ClaudeSDKClient,
|
||||
ResultMessage,
|
||||
SdkMcpTool,
|
||||
create_sdk_mcp_server,
|
||||
)
|
||||
from claude_agent_sdk.types import StreamEvent
|
||||
from claude_agent_sdk import (
|
||||
ClaudeAgentOptions as SDKOptions,
|
||||
)
|
||||
from claude_agent_sdk.types import StreamEvent, TextBlock
|
||||
from pydantic import ValidationError
|
||||
|
||||
from ._settings import ClaudeAgentSettings
|
||||
@@ -639,7 +640,33 @@ class ClaudeAgent(BaseAgent, Generic[TOptions]):
|
||||
contents=[Content.from_text_reasoning(text=thinking, raw_representation=message)],
|
||||
raw_representation=message,
|
||||
)
|
||||
elif isinstance(message, AssistantMessage):
|
||||
# Handle AssistantMessage - check for API errors
|
||||
# Note: In streaming mode, the content was already yielded via StreamEvent,
|
||||
# so we only check for errors here, not re-emit content.
|
||||
if message.error:
|
||||
# Map error types to descriptive messages
|
||||
error_messages = {
|
||||
"authentication_failed": "Authentication failed with Claude API",
|
||||
"billing_error": "Billing error with Claude API",
|
||||
"rate_limit": "Rate limit exceeded for Claude API",
|
||||
"invalid_request": "Invalid request to Claude API",
|
||||
"server_error": "Claude API server error",
|
||||
"unknown": "Unknown error from Claude API",
|
||||
}
|
||||
error_msg = error_messages.get(message.error, f"Claude API error: {message.error}")
|
||||
# Extract any error details from content blocks
|
||||
if message.content:
|
||||
for block in message.content:
|
||||
if isinstance(block, TextBlock):
|
||||
error_msg = f"{error_msg}: {block.text}"
|
||||
break
|
||||
raise ServiceException(error_msg)
|
||||
elif isinstance(message, ResultMessage):
|
||||
# Check for errors in result message
|
||||
if message.is_error:
|
||||
error_msg = message.result or "Unknown error from Claude API"
|
||||
raise ServiceException(f"Claude API error: {error_msg}")
|
||||
session_id = message.session_id
|
||||
|
||||
# Update thread with session ID
|
||||
|
||||
Reference in New Issue
Block a user