Skip to content

Commit 6f358b7

Browse files
committed
just fork codes from deepagent repo
1 parent 2fdd634 commit 6f358b7

File tree

8 files changed

+755
-0
lines changed

8 files changed

+755
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from deepagents.graph import create_deep_agent
2+
from deepagents.model import get_default_model
3+
from deepagents.state import DeepAgentState
4+
from deepagents.sub_agent import SubAgent
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from collections.abc import Callable, Sequence
2+
from typing import Any, TypeVar
3+
4+
from deepagents.model import get_default_model
5+
from deepagents.state import DeepAgentState
6+
from deepagents.sub_agent import SubAgent, _create_task_tool
7+
from deepagents.tools import edit_file, ls, read_file, write_file, write_todos
8+
from langchain_core.language_models import LanguageModelLike
9+
from langchain_core.tools import BaseTool
10+
from langgraph.prebuilt import create_react_agent
11+
from langgraph.types import Checkpointer
12+
13+
StateSchema = TypeVar("StateSchema", bound=DeepAgentState)
14+
StateSchemaType = type[StateSchema]
15+
16+
base_prompt = """You have access to a number of standard tools
17+
18+
## `write_todos`
19+
20+
You have access to the `write_todos` tools to help you manage and plan tasks. Use these tools VERY frequently to ensure that you are tracking your tasks and giving the user visibility into your progress.
21+
These tools are also EXTREMELY helpful for planning tasks, and for breaking down larger complex tasks into smaller steps. If you do not use this tool when planning, you may forget to do important tasks - and that is unacceptable.
22+
23+
It is critical that you mark todos as completed as soon as you are done with a task. Do not batch up multiple tasks before marking them as completed.
24+
## `task`
25+
26+
- When doing web search, prefer to use the `task` tool in order to reduce context usage."""
27+
28+
29+
def create_deep_agent(
30+
tools: Sequence[BaseTool | Callable | dict[str, Any]],
31+
instructions: str,
32+
model: str | LanguageModelLike | None = None,
33+
subagents: list[SubAgent] = None,
34+
state_schema: StateSchemaType | None = None,
35+
config_schema: type[Any] | None = None,
36+
checkpointer: Checkpointer | None = None,
37+
):
38+
"""Create a deep agent.
39+
40+
This agent will by default have access to a tool to write todos (write_todos),
41+
and then four file editing tools: write_file, ls, read_file, edit_file.
42+
43+
Args:
44+
tools: The additional tools the agent should have access to.
45+
instructions: The additional instructions the agent should have. Will go in
46+
the system prompt.
47+
model: The model to use.
48+
subagents: The subagents to use. Each subagent should be a dictionary with the
49+
following keys:
50+
- `name`
51+
- `description` (used by the main agent to decide whether to call the sub agent)
52+
- `prompt` (used as the system prompt in the subagent)
53+
- (optional) `tools`
54+
state_schema: The schema of the deep agent. Should subclass from DeepAgentState
55+
config_schema: The schema of the deep agent.
56+
checkpointer: Optional checkpointer for persisting agent state between runs.
57+
"""
58+
prompt = instructions + base_prompt
59+
built_in_tools = [write_todos, write_file, read_file, ls, edit_file]
60+
if model is None:
61+
model = get_default_model()
62+
state_schema = state_schema or DeepAgentState
63+
task_tool = _create_task_tool(list(tools) + built_in_tools, instructions, subagents or [], model, state_schema)
64+
all_tools = built_in_tools + list(tools) + [task_tool]
65+
return create_react_agent(
66+
model,
67+
prompt=prompt,
68+
tools=all_tools,
69+
state_schema=state_schema,
70+
config_schema=config_schema,
71+
checkpointer=checkpointer,
72+
)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from langchain_anthropic import ChatAnthropic
2+
3+
4+
def get_default_model():
5+
return ChatAnthropic(model_name="claude-sonnet-4-20250514", max_tokens=64000)

template_langgraph/agents/demo_agents/deep_agent_core/prompts.py

Lines changed: 277 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import os
2+
from typing import Literal
3+
4+
from deepagents import create_deep_agent
5+
from tavily import TavilyClient
6+
7+
# It's best practice to initialize the client once and reuse it.
8+
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
9+
10+
11+
# Search tool to use to do research
12+
def internet_search(
13+
query: str,
14+
max_results: int = 5,
15+
topic: Literal["general", "news", "finance"] = "general",
16+
include_raw_content: bool = False,
17+
):
18+
"""Run a web search"""
19+
search_docs = tavily_client.search(
20+
query,
21+
max_results=max_results,
22+
include_raw_content=include_raw_content,
23+
topic=topic,
24+
)
25+
return search_docs
26+
27+
28+
sub_research_prompt = """You are a dedicated researcher. Your job is to conduct research based on the users questions.
29+
30+
Conduct thorough research and then reply to the user with a detailed answer to their question
31+
32+
only your FINAL answer will be passed on to the user. They will have NO knowledge of anything except your final message, so your final report should be your final message!"""
33+
34+
research_sub_agent = {
35+
"name": "research-agent",
36+
"description": "Used to research more in depth questions. Only give this researcher one topic at a time. Do not pass multiple sub questions to this researcher. Instead, you should break down a large topic into the necessary components, and then call multiple research agents in parallel, one for each sub question.",
37+
"prompt": sub_research_prompt,
38+
"tools": ["internet_search"],
39+
}
40+
41+
sub_critique_prompt = """You are a dedicated editor. You are being tasked to critique a report.
42+
43+
You can find the report at `final_report.md`.
44+
45+
You can find the question/topic for this report at `question.txt`.
46+
47+
The user may ask for specific areas to critique the report in. Respond to the user with a detailed critique of the report. Things that could be improved.
48+
49+
You can use the search tool to search for information, if that will help you critique the report
50+
51+
Do not write to the `final_report.md` yourself.
52+
53+
Things to check:
54+
- Check that each section is appropriately named
55+
- Check that the report is written as you would find in an essay or a textbook - it should be text heavy, do not let it just be a list of bullet points!
56+
- Check that the report is comprehensive. If any paragraphs or sections are short, or missing important details, point it out.
57+
- Check that the article covers key areas of the industry, ensures overall understanding, and does not omit important parts.
58+
- Check that the article deeply analyzes causes, impacts, and trends, providing valuable insights
59+
- Check that the article closely follows the research topic and directly answers questions
60+
- Check that the article has a clear structure, fluent language, and is easy to understand.
61+
"""
62+
63+
critique_sub_agent = {
64+
"name": "critique-agent",
65+
"description": "Used to critique the final report. Give this agent some infomration about how you want it to critique the report.",
66+
"prompt": sub_critique_prompt,
67+
}
68+
69+
70+
# Prompt prefix to steer the agent to be an expert researcher
71+
research_instructions = """You are an expert researcher. Your job is to conduct thorough research, and then write a polished report.
72+
73+
The first thing you should do is to write the original user question to `question.txt` so you have a record of it.
74+
75+
Use the research-agent to conduct deep research. It will respond to your questions/topics with a detailed answer.
76+
77+
When you think you enough information to write a final report, write it to `final_report.md`
78+
79+
You can call the critique-agent to get a critique of the final report. After that (if needed) you can do more research and edit the `final_report.md`
80+
You can do this however many times you want until are you satisfied with the result.
81+
82+
Only edit the file once at a time (if you call this tool in parallel, there may be conflicts).
83+
84+
Here are instructions for writing the final report:
85+
86+
<report_instructions>
87+
88+
CRITICAL: Make sure the answer is written in the same language as the human messages! If you make a todo plan - you should note in the plan what language the report should be in so you dont forget!
89+
Note: the language the report should be in is the language the QUESTION is in, not the language/country that the question is ABOUT.
90+
91+
Please create a detailed answer to the overall research brief that:
92+
1. Is well-organized with proper headings (# for title, ## for sections, ### for subsections)
93+
2. Includes specific facts and insights from the research
94+
3. References relevant sources using [Title](URL) format
95+
4. Provides a balanced, thorough analysis. Be as comprehensive as possible, and include all information that is relevant to the overall research question. People are using you for deep research and will expect detailed, comprehensive answers.
96+
5. Includes a "Sources" section at the end with all referenced links
97+
98+
You can structure your report in a number of different ways. Here are some examples:
99+
100+
To answer a question that asks you to compare two things, you might structure your report like this:
101+
1/ intro
102+
2/ overview of topic A
103+
3/ overview of topic B
104+
4/ comparison between A and B
105+
5/ conclusion
106+
107+
To answer a question that asks you to return a list of things, you might only need a single section which is the entire list.
108+
1/ list of things or table of things
109+
Or, you could choose to make each item in the list a separate section in the report. When asked for lists, you don't need an introduction or conclusion.
110+
1/ item 1
111+
2/ item 2
112+
3/ item 3
113+
114+
To answer a question that asks you to summarize a topic, give a report, or give an overview, you might structure your report like this:
115+
1/ overview of topic
116+
2/ concept 1
117+
3/ concept 2
118+
4/ concept 3
119+
5/ conclusion
120+
121+
If you think you can answer the question with a single section, you can do that too!
122+
1/ answer
123+
124+
REMEMBER: Section is a VERY fluid and loose concept. You can structure your report however you think is best, including in ways that are not listed above!
125+
Make sure that your sections are cohesive, and make sense for the reader.
126+
127+
For each section of the report, do the following:
128+
- Use simple, clear language
129+
- Use ## for section title (Markdown format) for each section of the report
130+
- Do NOT ever refer to yourself as the writer of the report. This should be a professional report without any self-referential language.
131+
- Do not say what you are doing in the report. Just write the report without any commentary from yourself.
132+
- Each section should be as long as necessary to deeply answer the question with the information you have gathered. It is expected that sections will be fairly long and verbose. You are writing a deep research report, and users will expect a thorough answer.
133+
- Use bullet points to list out information when appropriate, but by default, write in paragraph form.
134+
135+
REMEMBER:
136+
The brief and research may be in English, but you need to translate this information to the right language when writing the final answer.
137+
Make sure the final answer report is in the SAME language as the human messages in the message history.
138+
139+
Format the report in clear markdown with proper structure and include source references where appropriate.
140+
141+
<Citation Rules>
142+
- Assign each unique URL a single citation number in your text
143+
- End with ### Sources that lists each source with corresponding numbers
144+
- IMPORTANT: Number sources sequentially without gaps (1,2,3,4...) in the final list regardless of which sources you choose
145+
- Each source should be a separate line item in a list, so that in markdown it is rendered as a list.
146+
- Example format:
147+
[1] Source Title: URL
148+
[2] Source Title: URL
149+
- Citations are extremely important. Make sure to include these, and pay a lot of attention to getting these right. Users will often use these citations to look into more information.
150+
</Citation Rules>
151+
</report_instructions>
152+
153+
You have access to a few tools.
154+
155+
## `internet_search`
156+
157+
Use this to run an internet search for a given query. You can specify the number of results, the topic, and whether raw content should be included.
158+
"""
159+
160+
# Create the agent
161+
agent = create_deep_agent(
162+
[internet_search],
163+
research_instructions,
164+
subagents=[critique_sub_agent, research_sub_agent],
165+
).with_config({"recursion_limit": 1000})
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from typing import Annotated, Literal, NotRequired
2+
3+
from langgraph.prebuilt.chat_agent_executor import AgentState
4+
from typing_extensions import TypedDict
5+
6+
7+
class Todo(TypedDict):
8+
"""Todo to track."""
9+
10+
content: str
11+
status: Literal["pending", "in_progress", "completed"]
12+
13+
14+
def file_reducer(l, r):
15+
if l is None:
16+
return r
17+
elif r is None:
18+
return l
19+
else:
20+
return {**l, **r}
21+
22+
23+
class DeepAgentState(AgentState):
24+
todos: NotRequired[list[Todo]]
25+
files: Annotated[NotRequired[dict[str, str]], file_reducer]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from typing import Annotated, Any, NotRequired
2+
3+
from deepagents.prompts import TASK_DESCRIPTION_PREFIX, TASK_DESCRIPTION_SUFFIX
4+
from deepagents.state import DeepAgentState
5+
from langchain.chat_models import init_chat_model
6+
from langchain_core.messages import ToolMessage
7+
from langchain_core.tools import BaseTool, InjectedToolCallId, tool
8+
from langgraph.prebuilt import InjectedState, create_react_agent
9+
from langgraph.types import Command
10+
from typing_extensions import TypedDict
11+
12+
13+
class SubAgent(TypedDict):
14+
name: str
15+
description: str
16+
prompt: str
17+
tools: NotRequired[list[str]]
18+
# Optional per-subagent model configuration
19+
model_settings: NotRequired[dict[str, Any]]
20+
21+
22+
def _create_task_tool(tools, instructions, subagents: list[SubAgent], model, state_schema):
23+
agents = {"general-purpose": create_react_agent(model, prompt=instructions, tools=tools)}
24+
tools_by_name = {}
25+
for tool_ in tools:
26+
if not isinstance(tool_, BaseTool):
27+
tool_ = tool(tool_)
28+
tools_by_name[tool_.name] = tool_
29+
for _agent in subagents:
30+
if "tools" in _agent:
31+
_tools = [tools_by_name[t] for t in _agent["tools"]]
32+
else:
33+
_tools = tools
34+
# Resolve per-subagent model if specified, else fallback to main model
35+
if "model_settings" in _agent:
36+
model_config = _agent["model_settings"]
37+
# Always use get_default_model to ensure all settings are applied
38+
sub_model = init_chat_model(**model_config)
39+
else:
40+
sub_model = model
41+
agents[_agent["name"]] = create_react_agent(
42+
sub_model, prompt=_agent["prompt"], tools=_tools, state_schema=state_schema
43+
)
44+
45+
other_agents_string = [f"- {_agent['name']}: {_agent['description']}" for _agent in subagents]
46+
47+
@tool(description=TASK_DESCRIPTION_PREFIX.format(other_agents=other_agents_string) + TASK_DESCRIPTION_SUFFIX)
48+
async def task(
49+
description: str,
50+
subagent_type: str,
51+
state: Annotated[DeepAgentState, InjectedState],
52+
tool_call_id: Annotated[str, InjectedToolCallId],
53+
):
54+
if subagent_type not in agents:
55+
return (
56+
f"Error: invoked agent of type {subagent_type}, the only allowed types are {[f'`{k}`' for k in agents]}"
57+
)
58+
sub_agent = agents[subagent_type]
59+
state["messages"] = [{"role": "user", "content": description}]
60+
result = await sub_agent.ainvoke(state)
61+
return Command(
62+
update={
63+
"files": result.get("files", {}),
64+
"messages": [ToolMessage(result["messages"][-1].content, tool_call_id=tool_call_id)],
65+
}
66+
)
67+
68+
return task

0 commit comments

Comments
 (0)