LeoWalker's picture
MCP source
33516f7 verified
Raw History Blame Contribute Delete
3.41 kB
"""Simple terminal chat loop for the Deep Research agent.
Usage:
uv run python -m src.deep_research_agent.chat_cli
The script:
- Loads .env
- Starts an interactive prompt
- On each turn, sends the accumulated messages to the compiled graph
- Prints intermediate events (clarification, supervisor progress) and the final report if produced
"""
import sys
import asyncio
from typing import List, Any, cast
from dotenv import load_dotenv
from langchain.messages import HumanMessage, AIMessage
from langchain_core.messages import BaseMessage
from src.deep_research_agent.graph import deep_researcher
from src.llm.content import format_message_content
# Simple ANSI colors with auto-disable if not a TTY
SUPPORTS_COLOR = sys.stdout.isatty()
COLOR_RESET = "\033[0m" if SUPPORTS_COLOR else ""
COLOR_INFO = "\033[36m" if SUPPORTS_COLOR else "" # cyan
COLOR_WARN = "\033[33m" if SUPPORTS_COLOR else "" # yellow
COLOR_SUPERVISOR = "\033[35m" if SUPPORTS_COLOR else "" # magenta
COLOR_SUCCESS = "\033[32m" if SUPPORTS_COLOR else "" # green
COLOR_PROMPT = "\033[94m" if SUPPORTS_COLOR else "" # blue
def _format_event(key: str, value: Any) -> str:
if key == "clarify_with_user":
msgs = value.get("messages") or []
if msgs:
return f"{COLOR_INFO}[Clarify]{COLOR_RESET} {format_message_content(msgs[-1].content)}"
if key == "write_research_brief":
brief = format_message_content(value.get("research_brief"))
if brief:
return f"{COLOR_WARN}[Brief]{COLOR_RESET}\n{brief}"
if key == "research_supervisor":
return f"{COLOR_SUPERVISOR}[Supervisor]{COLOR_RESET} ..."
if key == "final_report_generation":
report = format_message_content(value.get("final_report"))
if report:
return f"{COLOR_SUCCESS}[Final Report]{COLOR_RESET}\n{report}"
return ""
async def run_turn(messages: List[BaseMessage]) -> List[BaseMessage]:
"""Run one turn through the graph and return updated messages (if any)."""
async for event in deep_researcher.astream(cast(Any, {"messages": messages})):
for key, value in event.items():
# Print readable updates
out = _format_event(key, value)
if out:
print(out)
print("-" * 60) # visual separation between messages
# Collect message updates if present
if isinstance(value, dict) and "messages" in value:
msgs = value.get("messages") or []
# Keep all messages if provided, else ignore
if msgs:
messages = msgs # type: ignore[assignment]
return messages
async def main():
load_dotenv()
print("Deep Research Chat (type 'exit' to quit)")
print()
messages: List[BaseMessage] = []
# Initial user prompt
user = input(f"{COLOR_PROMPT}You{COLOR_RESET}: ").strip()
if not user or user.lower() == "exit":
return
messages.append(HumanMessage(content=user))
while True:
messages = await run_turn(messages)
# Ask user for next input and append
print() # extra spacing before next prompt
user = input(f"{COLOR_PROMPT}You{COLOR_RESET}: ").strip()
if not user or user.lower() == "exit":
break
messages.append(HumanMessage(content=user))
if __name__ == "__main__":
asyncio.run(main())