realtimex-deepagents 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Harrison Chase
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,475 @@
1
+ Metadata-Version: 2.4
2
+ Name: realtimex-deepagents
3
+ Version: 0.1.0
4
+ Summary: General purpose 'deep agent' with sub-agent spawning, todo list capabilities, and mock file system. Built on LangGraph.
5
+ License: MIT
6
+ Requires-Python: <4.0,>=3.11
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: langgraph==0.6.11
10
+ Requires-Dist: langchain-anthropic==0.3.22
11
+ Requires-Dist: langchain==0.3.27
12
+ Dynamic: license-file
13
+
14
+ # 🧠🤖Deep Agents
15
+
16
+ Using an LLM to call tools in a loop is the simplest form of an agent.
17
+ This architecture, however, can yield agents that are “shallow” and fail to plan and act over longer, more complex tasks.
18
+ Applications like “Deep Research”, "Manus", and “Claude Code” have gotten around this limitation by implementing a combination of four things:
19
+ a **planning tool**, **sub agents**, access to a **file system**, and a **detailed prompt**.
20
+
21
+ <img src="deep_agents.png" alt="deep agent" width="600"/>
22
+
23
+ `deepagents` is a Python package that implements these in a general purpose way so that you can easily create a Deep Agent for your application.
24
+
25
+ **Acknowledgements: This project was primarily inspired by Claude Code, and initially was largely an attempt to see what made Claude Code general purpose, and make it even more so.**
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ pip install deepagents
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ (To run the example below, will need to `pip install tavily-python`)
36
+
37
+ ```python
38
+ import os
39
+ from typing import Literal
40
+
41
+ from tavily import TavilyClient
42
+ from deepagents import create_deep_agent
43
+
44
+ tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
45
+
46
+ # Search tool to use to do research
47
+ def internet_search(
48
+ query: str,
49
+ max_results: int = 5,
50
+ topic: Literal["general", "news", "finance"] = "general",
51
+ include_raw_content: bool = False,
52
+ ):
53
+ """Run a web search"""
54
+ return tavily_client.search(
55
+ query,
56
+ max_results=max_results,
57
+ include_raw_content=include_raw_content,
58
+ topic=topic,
59
+ )
60
+
61
+
62
+ # Prompt prefix to steer the agent to be an expert researcher
63
+ research_instructions = """You are an expert researcher. Your job is to conduct thorough research, and then write a polished report.
64
+
65
+ You have access to a few tools.
66
+
67
+ ## `internet_search`
68
+
69
+ 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.
70
+ """
71
+
72
+ # Create the agent
73
+ agent = create_deep_agent(
74
+ [internet_search],
75
+ research_instructions,
76
+ )
77
+
78
+ # Invoke the agent
79
+ result = agent.invoke({"messages": [{"role": "user", "content": "what is langgraph?"}]})
80
+ ```
81
+
82
+ See [examples/research/research_agent.py](examples/research/research_agent.py) for a more complex example.
83
+
84
+ The agent created with `create_deep_agent` is just a LangGraph graph - so you can interact with it (streaming, human-in-the-loop, memory, studio)
85
+ in the same way you would any LangGraph agent.
86
+
87
+ ## Creating a custom deep agent
88
+
89
+ There are three parameters you can pass to `create_deep_agent` to create your own custom deep agent.
90
+
91
+ ### `tools` (Required)
92
+
93
+ The first argument to `create_deep_agent` is `tools`.
94
+ This should be a list of functions or LangChain `@tool` objects.
95
+ The agent (and any subagents) will have access to these tools.
96
+
97
+ ### `instructions` (Required)
98
+
99
+ The second argument to `create_deep_agent` is `instructions`.
100
+ This will serve as part of the prompt of the deep agent.
101
+ Note that there is a [built in system prompt](src/deepagents/prompts.py) as well, so this is not the *entire* prompt the agent will see.
102
+
103
+ ### `subagents` (Optional)
104
+
105
+ A keyword-only argument to `create_deep_agent` is `subagents`.
106
+ This can be used to specify any custom subagents this deep agent will have access to.
107
+ You can read more about why you would want to use subagents [here](#sub-agents)
108
+
109
+ `subagents` should be a list of dictionaries, where each dictionary follow this schema:
110
+
111
+ ```python
112
+ class SubAgent(TypedDict):
113
+ name: str
114
+ description: str
115
+ prompt: str
116
+ tools: NotRequired[list[str]]
117
+ model_settings: NotRequired[dict[str, Any]]
118
+
119
+ class CustomSubAgent(TypedDict):
120
+ name: str
121
+ description: str
122
+ graph: Runnable
123
+ ```
124
+
125
+ **SubAgent fields:**
126
+ - **name**: This is the name of the subagent, and how the main agent will call the subagent
127
+ - **description**: This is the description of the subagent that is shown to the main agent
128
+ - **prompt**: This is the prompt used for the subagent
129
+ - **tools**: This is the list of tools that the subagent has access to. By default will have access to all tools passed in, as well as all built-in tools.
130
+ - **model_settings**: Optional dictionary for per-subagent model configuration (inherits the main model when omitted).
131
+
132
+ **CustomSubAgent fields:**
133
+ - **name**: This is the name of the subagent, and how the main agent will call the subagent
134
+ - **description**: This is the description of the subagent that is shown to the main agent
135
+ - **graph**: A pre-built LangGraph graph/agent that will be used as the subagent
136
+
137
+ #### Using SubAgent
138
+
139
+ ```python
140
+ research_subagent = {
141
+ "name": "research-agent",
142
+ "description": "Used to research more in depth questions",
143
+ "prompt": sub_research_prompt,
144
+ }
145
+ subagents = [research_subagent]
146
+ agent = create_deep_agent(
147
+ tools,
148
+ prompt,
149
+ subagents=subagents
150
+ )
151
+ ```
152
+
153
+ #### Using CustomSubAgent
154
+
155
+ For more complex use cases, you can provide your own pre-built LangGraph graph as a subagent:
156
+
157
+ ```python
158
+ from langgraph.prebuilt import create_react_agent
159
+
160
+ # Create a custom agent graph
161
+ custom_graph = create_react_agent(
162
+ model=your_model,
163
+ tools=specialized_tools,
164
+ prompt="You are a specialized agent for data analysis..."
165
+ )
166
+
167
+ # Use it as a custom subagent
168
+ custom_subagent = {
169
+ "name": "data-analyzer",
170
+ "description": "Specialized agent for complex data analysis tasks",
171
+ "graph": custom_graph
172
+ }
173
+
174
+ subagents = [custom_subagent]
175
+ agent = create_deep_agent(
176
+ tools,
177
+ prompt,
178
+ subagents=subagents
179
+ )
180
+ ```
181
+
182
+ ### `model` (Optional)
183
+
184
+ By default, `deepagents` uses `"claude-sonnet-4-20250514"`. You can customize this by passing any [LangChain model object](https://python.langchain.com/docs/integrations/chat/).
185
+
186
+ ### `builtin_tools` (Optional)
187
+
188
+ By default, a deep agent will have access to a number of [built-in tools](#builtintools--optional-).
189
+ You can change this by specifying the tools (by name) that the agent should have access to with this parameter.
190
+
191
+ Example:
192
+ ```python
193
+ # Only give agent access to todo tool, none of the filesystem tools
194
+ builtin_tools = ["write_todos"]
195
+ agent = create_deep_agent(..., builtin_tools=builtin_tools, ...)
196
+ ```
197
+
198
+ #### Example: Using a Custom Model
199
+
200
+ Here's how to use a custom model (like OpenAI's `gpt-oss` model via Ollama):
201
+
202
+ (Requires `pip install langchain` and then `pip install langchain-ollama` for Ollama models)
203
+
204
+ ```python
205
+ from deepagents import create_deep_agent
206
+
207
+ # ... existing agent definitions ...
208
+
209
+ model = init_chat_model(
210
+ model="ollama:gpt-oss:20b",
211
+ )
212
+ agent = create_deep_agent(
213
+ tools=tools,
214
+ instructions=instructions,
215
+ model=model,
216
+ ...
217
+ )
218
+ ```
219
+
220
+ #### Example: Per-subagent model override (optional)
221
+
222
+ Use a fast, deterministic model for a critique sub-agent, while keeping a different default model for the main agent and others:
223
+
224
+ ```python
225
+ from deepagents import create_deep_agent
226
+
227
+ critique_sub_agent = {
228
+ "name": "critique-agent",
229
+ "description": "Critique the final report",
230
+ "prompt": "You are a tough editor.",
231
+ "model_settings": {
232
+ "model": "anthropic:claude-3-5-haiku-20241022",
233
+ "temperature": 0,
234
+ "max_tokens": 8192
235
+ }
236
+ }
237
+
238
+ agent = create_deep_agent(
239
+ tools=[internet_search],
240
+ instructions="You are an expert researcher...",
241
+ model="claude-sonnet-4-20250514", # default for main agent and other sub-agents
242
+ subagents=[critique_sub_agent],
243
+ )
244
+ ```
245
+
246
+ ## Deep Agent Details
247
+
248
+ The below components are built into `deepagents` and helps make it work for deep tasks off-the-shelf.
249
+
250
+ ### System Prompt
251
+
252
+ `deepagents` comes with a [built-in system prompt](src/deepagents/prompts.py). This is relatively detailed prompt that is heavily based on and inspired by [attempts](https://github.com/kn1026/cc/blob/main/claudecode.md) to [replicate](https://github.com/asgeirtj/system_prompts_leaks/blob/main/Anthropic/claude-code.md)
253
+ Claude Code's system prompt. It was made more general purpose than Claude Code's system prompt.
254
+ This contains detailed instructions for how to use the built-in planning tool, file system tools, and sub agents.
255
+ Note that part of this system prompt [can be customized](#instructions-required)
256
+
257
+ Without this default system prompt - the agent would not be nearly as successful at going as it is.
258
+ The importance of prompting for creating a "deep" agent cannot be understated.
259
+
260
+ ### Planning Tool
261
+
262
+ `deepagents` comes with a built-in planning tool. This planning tool is very simple and is based on ClaudeCode's TodoWrite tool.
263
+ This tool doesn't actually do anything - it is just a way for the agent to come up with a plan, and then have that in the context to help keep it on track.
264
+
265
+ ### File System Tools
266
+
267
+ `deepagents` comes with four built-in file system tools: `ls`, `edit_file`, `read_file`, `write_file`.
268
+ These do not actually use a file system - rather, they mock out a file system using LangGraph's State object.
269
+ This means you can easily run many of these agents on the same machine without worrying that they will edit the same underlying files.
270
+
271
+ Right now the "file system" will only be one level deep (no sub directories).
272
+
273
+ These files can be passed in (and also retrieved) by using the `files` key in the LangGraph State object.
274
+
275
+ ```python
276
+ agent = create_deep_agent(...)
277
+
278
+ result = agent.invoke({
279
+ "messages": ...,
280
+ # Pass in files to the agent using this key
281
+ # "files": {"foo.txt": "foo", ...}
282
+ })
283
+
284
+ # Access any files afterwards like this
285
+ result["files"]
286
+ ```
287
+
288
+ ### Sub Agents
289
+
290
+ `deepagents` comes with the built-in ability to call sub agents (based on Claude Code).
291
+ It has access to a `general-purpose` subagent at all times - this is a subagent with the same instructions as the main agent and all the tools that is has access to.
292
+ You can also specify [custom sub agents](#subagents-optional) with their own instructions and tools.
293
+
294
+ Sub agents are useful for ["context quarantine"](https://www.dbreunig.com/2025/06/26/how-to-fix-your-context.html#context-quarantine) (to help not pollute the overall context of the main agent)
295
+ as well as custom instructions.
296
+
297
+ ### Built In Tools
298
+
299
+ By default, deep agents come with five built-in tools:
300
+
301
+ - `write_todos`: Tool for writing todos
302
+ - `write_file`: Tool for writing to a file in the virtual filesystem
303
+ - `read_file`: Tool for reading from a file in the virtual filesystem
304
+ - `ls`: Tool for listing files in the virtual filesystem
305
+ - `edit_file`: Tool for editing a file in the virtual filesystem
306
+
307
+ These can be disabled via the [`builtin_tools`](#builtintools--optional-) parameter.
308
+
309
+ ### Human-in-the-Loop
310
+
311
+ `deepagents` supports human-in-the-loop approval for tool execution. You can configure specific tools to require human approval before execution using the `interrupt_config` parameter, which maps tool names to `HumanInterruptConfig`.
312
+
313
+ `HumanInterruptConfig` is how you specify what type of human in the loop patterns are supported.
314
+ It is a dictionary with four specific keys:
315
+
316
+ - `allow_ignore`: Whether the user can skip the tool call
317
+ - `allow_respond`: Whether the user can add a text response
318
+ - `allow_edit`: Whether the user can edit the tool arguments
319
+ - `allow_accept`: Whether the user can accept the tool call
320
+
321
+ Currently, `deepagents` does NOT support `allow_ignore`
322
+
323
+ Currently, `deepagents` only support interrupting one tool at a time. If multiple tools are called in parallel, each requiring interrupts, then the agent will error.
324
+
325
+ Instead of specifying a `HumanInterruptConfig` for a tool, you can also just set `True`. This will set `allow_ignore`, `allow_respond`, `allow_edit`, and `allow_accept` to be `True`.
326
+
327
+ In order to use human in the loop, you need to have a checkpointer attached.
328
+ Note: if you are using LangGraph Platform, this is automatically attached.
329
+
330
+ Example usage:
331
+
332
+ ```python
333
+ from deepagents import create_deep_agent
334
+ from langgraph.checkpoint.memory import InMemorySaver
335
+
336
+ # Create agent with file operations requiring approval
337
+ agent = create_deep_agent(
338
+ tools=[your_tools],
339
+ instructions="Your instructions here",
340
+ interrupt_config={
341
+ # You can specify a dictionary for fine grained control over what interrupt options exist
342
+ "tool_1": {
343
+ "allow_ignore": False,
344
+ "allow_respond": True,
345
+ "allow_edit": True,
346
+ "allow_accept":True,
347
+ },
348
+ # You can specify a boolean for shortcut
349
+ # This is a shortcut for the same functionality as above
350
+ "tool_2": True,
351
+ }
352
+ )
353
+
354
+ checkpointer= InMemorySaver()
355
+ agent.checkpointer = checkpointer
356
+ ```
357
+
358
+ #### Approve
359
+
360
+ To "approve" a tool call means the agent will execute the tool call as is.
361
+
362
+ This flow shows how to approve a tool call (assuming the tool requiring approval is called):
363
+
364
+ ```python
365
+ config = {"configurable": {"thread_id": "1"}}
366
+ for s in agent.stream({"messages": [{"role": "user", "content": message}]}, config=config):
367
+ print(s)
368
+ # If this calls a tool with an interrupt, this will then return an interrupt
369
+ for s in agent.stream(Command(resume=[{"type": "accept"}]), config=config):
370
+ print(s)
371
+
372
+ ```
373
+
374
+ #### Edit
375
+
376
+ To "edit" a tool call means the agent will execute the new tool with the new arguments. You can change both the tool to call or the arguments to pass to that tool.
377
+
378
+ The `args` parameter you pass back should be a dictionary with two keys:
379
+
380
+ - `action`: maps to a string which is the name of the tool to call
381
+ - `args`: maps to a dictionary which is the arguments to pass to the tool
382
+
383
+ This flow shows how to edit a tool call (assuming the tool requiring approval is called):
384
+
385
+ ```python
386
+ config = {"configurable": {"thread_id": "1"}}
387
+ for s in agent.stream({"messages": [{"role": "user", "content": message}]}, config=config):
388
+ print(s)
389
+ # If this calls a tool with an interrupt, this will then return an interrupt
390
+ # Replace the `...` with the tool name you want to call, and the arguments
391
+ for s in agent.stream(Command(resume=[{"type": "edit", "args": {"action": "...", "args": {...}}}]), config=config):
392
+ print(s)
393
+
394
+ ```
395
+
396
+ #### Respond
397
+
398
+ To "respond" to a tool call means that tool is NOT called. Rather, a tool message is appended with the content you respond with, and the updated messages list is then sent back to the model.
399
+
400
+ The `args` parameter you pass back should be a string with your response.
401
+
402
+ This flow shows how to respond to a tool call (assuming the tool requiring approval is called):
403
+
404
+ ```python
405
+ config = {"configurable": {"thread_id": "1"}}
406
+ for s in agent.stream({"messages": [{"role": "user", "content": message}]}, config=config):
407
+ print(s)
408
+ # If this calls a tool with an interrupt, this will then return an interrupt
409
+ # Replace the `...` with the response to use all the ToolMessage content
410
+ for s in agent.stream(Command(resume=[{"type": "response", "args": "..."}]), config=config):
411
+ print(s)
412
+
413
+ ```
414
+ ## Async
415
+
416
+ If you are passing async tools to your agent, you will want to `from deepagents import async_create_deep_agent`
417
+ ## MCP
418
+
419
+ The `deepagents` library can be ran with MCP tools. This can be achieved by using the [Langchain MCP Adapter library](https://github.com/langchain-ai/langchain-mcp-adapters).
420
+
421
+ **NOTE:** will want to use `from deepagents import async_create_deep_agent` to use the async version of `deepagents`, since MCP tools are async
422
+
423
+ (To run the example below, will need to `pip install langchain-mcp-adapters`)
424
+
425
+ ```python
426
+ import asyncio
427
+ from langchain_mcp_adapters.client import MultiServerMCPClient
428
+ from deepagents import create_deep_agent
429
+
430
+ async def main():
431
+ # Collect MCP tools
432
+ mcp_client = MultiServerMCPClient(...)
433
+ mcp_tools = await mcp_client.get_tools()
434
+
435
+ # Create agent
436
+ agent = async_create_deep_agent(tools=mcp_tools, ....)
437
+
438
+ # Stream the agent
439
+ async for chunk in agent.astream(
440
+ {"messages": [{"role": "user", "content": "what is langgraph?"}]},
441
+ stream_mode="values"
442
+ ):
443
+ if "messages" in chunk:
444
+ chunk["messages"][-1].pretty_print()
445
+
446
+ asyncio.run(main())
447
+ ```
448
+
449
+ ## Configurable Agent
450
+
451
+ Configurable agents allow you to control the agent via a config passed in.
452
+
453
+ ```python
454
+ from deepagents import create_configurable_agent
455
+
456
+ agent_config = {"instructions": "foo", "subagents": []}
457
+
458
+ build_agent = create_configurable_agent(
459
+ agent_config['instructions'],
460
+ agent_config['subagents'],
461
+ [],
462
+ agent_config={"recursion_limit": 1000}
463
+ )
464
+ ```
465
+ You can now use `build_agent` in your `langgraph.json` and deploy it with `langgraph dev`
466
+
467
+ For async tools, you can use `from deepagents import async_create_configurable_agent`
468
+
469
+
470
+ ## Roadmap
471
+ - [ ] Allow users to customize full system prompt
472
+ - [ ] Code cleanliness (type hinting, docstrings, formating)
473
+ - [ ] Allow for more of a robust virtual filesystem
474
+ - [ ] Create an example of a deep coding agent built on top of this
475
+ - [ ] Benchmark the example of [deep research agent](examples/research/research_agent.py)