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:
chihlasm
2026-03-08 15:43:22 -04:00
parent 94b428d168
commit df46046c86
2 changed files with 35 additions and 15 deletions

View File

@@ -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,

View File

@@ -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.