fix: resolve MissingGreenlet crash and add MCP fallback in AI Assistant
Capture user_id/account_id before try block so error handler survives db.rollback() without triggering lazy loads in async context. Add retry-without-MCP fallback when Anthropic MCP server returns rate limit or connection errors. Fixes PYTHON-FASTAPI-3, PYTHON-FASTAPI-4 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -145,11 +145,17 @@ async def post_message(
|
||||
|
||||
plan = await get_user_plan(current_user.account_id, db)
|
||||
|
||||
# Capture scalar fields before the try block — after db.rollback()
|
||||
# the ORM objects are expired and accessing attributes triggers a
|
||||
# lazy load, which crashes in async context (MissingGreenlet).
|
||||
user_id = current_user.id
|
||||
account_id = current_user.account_id
|
||||
|
||||
try:
|
||||
ai_content, suggested_flows, chat = await assistant_chat_service.send_message(
|
||||
chat_id=chat_id,
|
||||
user_id=current_user.id,
|
||||
account_id=current_user.account_id,
|
||||
user_id=user_id,
|
||||
account_id=account_id,
|
||||
message=data.message,
|
||||
db=db,
|
||||
)
|
||||
@@ -159,8 +165,8 @@ async def post_message(
|
||||
logger.exception("Assistant chat message failed: %s", e)
|
||||
await db.rollback()
|
||||
await record_ai_usage(
|
||||
user_id=current_user.id,
|
||||
account_id=current_user.account_id,
|
||||
user_id=user_id,
|
||||
account_id=account_id,
|
||||
conversation_id=None,
|
||||
generation_type="assistant_message",
|
||||
tier=plan,
|
||||
@@ -180,8 +186,8 @@ async def post_message(
|
||||
)
|
||||
|
||||
await record_ai_usage(
|
||||
user_id=current_user.id,
|
||||
account_id=current_user.account_id,
|
||||
user_id=user_id,
|
||||
account_id=account_id,
|
||||
conversation_id=None,
|
||||
generation_type="assistant_message",
|
||||
tier=plan,
|
||||
|
||||
@@ -189,15 +189,29 @@ async def _call_anthropic_cached(
|
||||
}
|
||||
]
|
||||
|
||||
response = await client.beta.messages.create(
|
||||
model=settings.AI_MODEL_ANTHROPIC,
|
||||
max_tokens=max_tokens,
|
||||
system=system_blocks,
|
||||
messages=messages,
|
||||
mcp_servers=mcp_servers,
|
||||
tools=tools,
|
||||
betas=["mcp-client-2025-11-20"],
|
||||
)
|
||||
try:
|
||||
response = await client.beta.messages.create(
|
||||
model=settings.AI_MODEL_ANTHROPIC,
|
||||
max_tokens=max_tokens,
|
||||
system=system_blocks,
|
||||
messages=messages,
|
||||
mcp_servers=mcp_servers,
|
||||
tools=tools,
|
||||
betas=["mcp-client-2025-11-20"],
|
||||
)
|
||||
except anthropic.BadRequestError as e:
|
||||
# MCP server failures (rate limits, connection errors) should not
|
||||
# block the assistant entirely — retry without MCP tools.
|
||||
if "MCP server" in str(e) and mcp_servers is not anthropic.NOT_GIVEN:
|
||||
logger.warning("MCP server error, retrying without MCP: %s", e)
|
||||
response = await client.beta.messages.create(
|
||||
model=settings.AI_MODEL_ANTHROPIC,
|
||||
max_tokens=max_tokens,
|
||||
system=system_blocks,
|
||||
messages=messages,
|
||||
)
|
||||
else:
|
||||
raise
|
||||
|
||||
# Extract text from response — MCP responses can have multiple block
|
||||
# types (text, mcp_tool_use, mcp_tool_result). We join all text blocks.
|
||||
|
||||
Reference in New Issue
Block a user