diff --git a/backend/debug.py b/backend/debug.py new file mode 100644 index 0000000..5d5df3d --- /dev/null +++ b/backend/debug.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +""" +Debug script for lead_agent. +Run this file directly in VS Code with breakpoints. + +Usage: + 1. Set breakpoints in agent.py or other files + 2. Press F5 or use "Run and Debug" panel + 3. Input messages in the terminal to interact with the agent +""" + +import asyncio +import os +import sys + +# Ensure we can import from src +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +# Load environment variables +from dotenv import load_dotenv +from langchain_core.messages import HumanMessage + +from src.agents import make_lead_agent + +load_dotenv() + + +async def main(): + # Create agent with default config + config = { + "configurable": { + "thread_id": "debug-thread-001", + "thinking_enabled": True, + # Uncomment to use a specific model + "model_name": "doubao-seed-1.8", + } + } + + agent = make_lead_agent(config) + + print("=" * 50) + print("Lead Agent Debug Mode") + print("Type 'quit' or 'exit' to stop") + print("=" * 50) + + while True: + try: + user_input = input("\nYou: ").strip() + if not user_input: + continue + if user_input.lower() in ("quit", "exit"): + print("Goodbye!") + break + + # Invoke the agent + state = {"messages": [HumanMessage(content=user_input)]} + result = await agent.ainvoke(state, config=config, context={"thread_id": "debug-thread-001"}) + + # Print the response + if result.get("messages"): + last_message = result["messages"][-1] + print(f"\nAgent: {last_message.content}") + + except KeyboardInterrupt: + print("\nInterrupted. Goodbye!") + break + except Exception as e: + print(f"\nError: {e}") + import traceback + + traceback.print_exc() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/backend/langgraph.json b/backend/langgraph.json index a3b5fe9..7c2c842 100644 --- a/backend/langgraph.json +++ b/backend/langgraph.json @@ -3,6 +3,6 @@ "dependencies": ["."], "env": ".env", "graphs": { - "lead_agent": "src.agents:lead_agent" + "lead_agent": "src.agents:make_lead_agent" } } diff --git a/backend/src/agents/__init__.py b/backend/src/agents/__init__.py index cffde06..3bed203 100644 --- a/backend/src/agents/__init__.py +++ b/backend/src/agents/__init__.py @@ -1,4 +1,4 @@ -from .lead_agent import lead_agent +from .lead_agent import make_lead_agent from .thread_state import SandboxState, ThreadState -__all__ = ["lead_agent", "SandboxState", "ThreadState"] +__all__ = ["make_lead_agent", "SandboxState", "ThreadState"] diff --git a/backend/src/agents/lead_agent/__init__.py b/backend/src/agents/lead_agent/__init__.py index 925259a..c93ffa7 100644 --- a/backend/src/agents/lead_agent/__init__.py +++ b/backend/src/agents/lead_agent/__init__.py @@ -1,3 +1,3 @@ -from .agent import lead_agent +from .agent import make_lead_agent -__all__ = ["lead_agent"] +__all__ = ["make_lead_agent"] diff --git a/backend/src/agents/lead_agent/agent.py b/backend/src/agents/lead_agent/agent.py index 0773583..9f137d0 100644 --- a/backend/src/agents/lead_agent/agent.py +++ b/backend/src/agents/lead_agent/agent.py @@ -1,4 +1,5 @@ from langchain.agents import create_agent +from langchain_core.runnables import RunnableConfig from src.agents.lead_agent.prompt import apply_prompt_template from src.agents.middlewares.thread_data_middleware import ThreadDataMiddleware @@ -11,10 +12,15 @@ from src.tools import get_available_tools # ThreadDataMiddleware must be before SandboxMiddleware to ensure thread_id is available middlewares = [ThreadDataMiddleware(), SandboxMiddleware(), TitleMiddleware()] -lead_agent = create_agent( - model=create_chat_model(thinking_enabled=True), - tools=get_available_tools(), - middleware=middlewares, - system_prompt=apply_prompt_template(), - state_schema=ThreadState, -) + +def make_lead_agent(config: RunnableConfig): + thinking_enabled = config.get("configurable", {}).get("thinking_enabled", True) + model_name = config.get("configurable", {}).get("model_name") + print(f"thinking_enabled: {thinking_enabled}, model_name: {model_name}") + return create_agent( + model=create_chat_model(name=model_name, thinking_enabled=thinking_enabled), + tools=get_available_tools(), + middleware=middlewares, + system_prompt=apply_prompt_template(), + state_schema=ThreadState, + ) diff --git a/backend/src/agents/lead_agent/prompt.py b/backend/src/agents/lead_agent/prompt.py index c4ceb96..adfa588 100644 --- a/backend/src/agents/lead_agent/prompt.py +++ b/backend/src/agents/lead_agent/prompt.py @@ -1,4 +1,3 @@ -import os from datetime import datetime SYSTEM_PROMPT = f""" diff --git a/backend/src/agents/middlewares/thread_data_middleware.py b/backend/src/agents/middlewares/thread_data_middleware.py index 727e62f..2367f3f 100644 --- a/backend/src/agents/middlewares/thread_data_middleware.py +++ b/backend/src/agents/middlewares/thread_data_middleware.py @@ -71,8 +71,9 @@ class ThreadDataMiddleware(AgentMiddleware[ThreadDataMiddlewareState]): @override def before_agent(self, state: ThreadDataMiddlewareState, runtime: Runtime) -> dict | None: # Generate new thread ID and create directories - print(runtime.context) - thread_id = runtime.context["thread_id"] + thread_id = runtime.context.get("thread_id") + if thread_id is None: + raise ValueError("Thread ID is required in the context") paths = self._create_thread_directories(thread_id) print(f"Created thread data directories for thread {thread_id}") diff --git a/backend/src/sandbox/tools.py b/backend/src/sandbox/tools.py index a8ec9c5..3ab0c90 100644 --- a/backend/src/sandbox/tools.py +++ b/backend/src/sandbox/tools.py @@ -168,14 +168,16 @@ def read_file_tool( runtime: ToolRuntime[ContextT, ThreadState], description: str, path: str, - view_range: tuple[int, int] | None = None, + start_line: int | None = None, + end_line: int | None = None, ) -> str: - """Read the contents of a text file. + """Read the contents of a text file. Use this to examine source code, configuration files, logs, or any text-based file. Args: - description: Explain why you are viewing this file in short words. ALWAYS PROVIDE THIS PARAMETER FIRST. + description: Explain why you are reading this file in short words. ALWAYS PROVIDE THIS PARAMETER FIRST. path: The **absolute** path to the file to read. - view_range: The range of lines to view. The range is inclusive and starts at 1. For example, (1, 10) will view the first 10 lines of the file. + start_line: Optional starting line number (1-indexed, inclusive). Use with end_line to read a specific range. + end_line: Optional ending line number (1-indexed, inclusive). Use with start_line to read a specific range. """ try: sandbox = sandbox_from_runtime(runtime) @@ -185,9 +187,8 @@ def read_file_tool( content = sandbox.read_file(path) if not content: return "(empty)" - if view_range: - start, end = view_range - content = "\n".join(content.splitlines()[start - 1 : end]) + if start_line is not None and end_line is not None: + content = "\n".join(content.splitlines()[start_line - 1 : end_line]) return content except Exception as e: return f"Error: {e}" diff --git a/deer-flow.code-workspace b/deer-flow.code-workspace index 652a3f1..8622877 100644 --- a/deer-flow.code-workspace +++ b/deer-flow.code-workspace @@ -13,5 +13,34 @@ "workspace": "deer-flow" } ] + }, + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Lead Agent", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/backend/debug.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}/backend", + "env": { + "PYTHONPATH": "${workspaceFolder}/backend" + }, + "justMyCode": false + }, + { + "name": "Debug Lead Agent (justMyCode)", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/backend/debug.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}/backend", + "env": { + "PYTHONPATH": "${workspaceFolder}/backend" + }, + "justMyCode": true + } + ] } }