Fix: store agent on app object, access via current_app

Global module variable was unreliable across import boundaries. Storing
the compiled agent on app.main_agent and reading it via current_app is
the idiomatic Quart pattern and guaranteed to reflect the initialized value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-16 22:55:39 -04:00
parent 6621a99149
commit 810d32dcc3
5 changed files with 10 additions and 18 deletions
+1 -1
View File
@@ -103,7 +103,7 @@ async def lifespan():
async with aiosqlite.connect(checkpoint_path) as conn:
checkpointer = AsyncSqliteSaver(conn)
await checkpointer.setup()
build_agent(checkpointer)
app.main_agent = build_agent(checkpointer)
logging.info(f"Agent checkpointer ready at {checkpoint_path}")
watcher_task = None
+3 -4
View File
@@ -6,7 +6,7 @@ import re
import time
import uuid
from quart import Blueprint, jsonify, make_response, request
from quart import Blueprint, current_app, jsonify, make_response, request
from quart_jwt_extended import (
get_jwt_identity,
jwt_refresh_token_required,
@@ -21,7 +21,6 @@ from utils.s3_client import generate_presigned_url as s3_presigned_url
from utils.s3_client import get_image as s3_get_image
from utils.s3_client import upload_image as s3_upload_image
from . import agents as _agents
from .logic import (
add_message_to_conversation,
persist_agent_tool_messages,
@@ -152,7 +151,7 @@ async def query():
}
}
response = await _agents.main_agent.ainvoke(payload, config=agent_config)
response = await current_app.main_agent.ainvoke(payload, config=agent_config)
message = extract_agent_text(response.get("messages", [])[-1].content)
await persist_agent_tool_messages(
conversation, user, response.get("messages", [])
@@ -301,7 +300,7 @@ async def stream_query():
)
try:
aiter = _agents.main_agent.astream_events(
aiter = current_app.main_agent.astream_events(
payload, version="v2", config=agent_config
).__aiter__()
while True:
+2 -9
View File
@@ -1230,18 +1230,11 @@ if google_gmail_enabled:
tools.extend([gmail_search_emails, gmail_get_email])
# main_agent is compiled lazily by build_agent() once the checkpointer is
# ready (the async SQLite connection must be created inside the event loop).
main_agent = None
def build_agent(checkpointer=None):
"""Compile the LangGraph agent, optionally with a checkpointer."""
global main_agent
main_agent = create_react_agent(
"""Compile and return the LangGraph agent."""
return create_react_agent(
model=model_with_fallback,
tools=tools,
prompt=SIMBA_SYSTEM_PROMPT,
checkpointer=checkpointer,
)
return main_agent
+2 -2
View File
@@ -16,7 +16,7 @@ from blueprints.conversation.logic import (
persist_agent_tool_messages,
)
from blueprints.conversation.models import Conversation, ConversationMessage
import blueprints.conversation.agents as _conv_agents
from quart import current_app
from utils.strip_markdown import extract_agent_text, strip_markdown
imessage_blueprint = Blueprint("imessage_api", __name__, url_prefix="/api/imessage")
@@ -351,7 +351,7 @@ async def _process_and_reply(
}
}
logger.info(f"Invoking LangChain agent for conversation {conversation.id}")
response = await _conv_agents.main_agent.ainvoke(
response = await current_app.main_agent.ainvoke(
{"messages": [{"role": "user", "content": user_content}]},
config=agent_config,
)
+2 -2
View File
@@ -13,7 +13,7 @@ from blueprints.conversation.logic import (
add_message_to_conversation,
persist_agent_tool_messages,
)
import blueprints.conversation.agents as _conv_agents
from quart import current_app
from utils.strip_markdown import extract_agent_text
whatsapp_blueprint = Blueprint("whatsapp_api", __name__, url_prefix="/api/whatsapp")
@@ -185,7 +185,7 @@ async def webhook():
}
}
logger.info(f"Invoking LangChain agent for conversation {conversation.id}")
response = await _conv_agents.main_agent.ainvoke(
response = await current_app.main_agent.ainvoke(
{"messages": [{"role": "user", "content": body}]},
config=agent_config,
)