LeoWalker's picture
MCP source
33516f7 verified
Raw History Blame Contribute Delete
3.39 kB
"""React Agent Graph - Main agent implementation.
Purpose:
Defines a simple ReAct agent using `create_agent` from langchain.agents.
The agent loops: Reason β†’ Act (call tool) β†’ Observe β†’ Repeat until done.
Key Components:
- create_agent: LangChain helper for an agent runtime (built on LangGraph)
- Tools: Imported from shared tools module (Chroma, Neo4j)
- Model: Configurable LLM (default: gemini-flash-latest)
- Checkpointer: SqliteSaver on a gitignored path (survives process restart)
Usage:
from src.react_agent.graph import react_agent
result = await react_agent.ainvoke(
{"messages": [HumanMessage(content="...")]},
config={"configurable": {"thread_id": "my-thread"}}
)
"""
from typing import Any, Optional
from langchain.agents import create_agent
from langchain.messages import HumanMessage
from langchain_core.runnables import RunnableConfig
from src.react_agent.configuration import Configuration
from src.react_agent.tools import tools
from src.react_agent.utils import create_chat_model
from src.react_agent.prompts import system_prompt
from src.react_agent.checkpointer import get_sqlite_checkpointer
_memory = None
_react_agent = None
def _default_memory():
"""Open SQLite on first use so importing the package does not create files."""
global _memory
if _memory is None:
_memory = get_sqlite_checkpointer()
return _memory
def get_react_agent(
config: Optional[RunnableConfig] = None,
checkpointer: Optional[Any] = None,
) -> Any:
"""Create a ReAct agent with the specified configuration.
Args:
config: Optional RunnableConfig with configurable dict (model, max_tokens, etc.)
checkpointer: Optional checkpointer for conversation memory. Defaults to
the production SqliteSaver. Tests may inject MemorySaver. Pass a
thread_id in config to enable memory:
config={"configurable": {"thread_id": "my-thread"}}
Returns:
LangChain agent runnable that accepts {"messages": [...]}
"""
cfg = Configuration.from_runnable_config(config)
# Create the chat model instance
model = create_chat_model(
model_name=cfg.model,
config=config,
max_tokens=cfg.max_tokens,
temperature=cfg.temperature,
timeout=cfg.timeout,
)
# Create agent with model, tools, and checkpointer for conversation memory
# create_agent returns a compiled graph that acts as a runnable
agent: Any = create_agent(
model,
tools=tools,
system_prompt=system_prompt,
checkpointer=checkpointer if checkpointer is not None else _default_memory(),
)
# Respect configured iteration limits; default to Configuration.max_iterations
recursion_limit = None
if isinstance(config, dict):
recursion_limit = config.get("recursion_limit")
if recursion_limit is None:
recursion_limit = cfg.max_iterations
return agent.with_config(recursion_limit=recursion_limit)
def __getattr__(name: str) -> Any:
global _react_agent
if name == "memory":
return _default_memory()
if name == "react_agent":
if _react_agent is None:
_react_agent = get_react_agent()
return _react_agent
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")