deepagents 0.0.12rc1__py3-none-any.whl → 0.0.12rc2__py3-none-any.whl

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.
tests/test_filesystem.py DELETED
@@ -1,196 +0,0 @@
1
- from deepagents.graph import create_deep_agent
2
- from deepagents.middleware import FilesystemMiddleware
3
- from deepagents.prompts import WRITE_FILE_TOOL_DESCRIPTION, WRITE_FILE_TOOL_DESCRIPTION_LONGTERM_SUPPLEMENT
4
- from langchain.agents import create_agent
5
- import pytest
6
- from langchain_core.messages import HumanMessage
7
- from langchain_anthropic import ChatAnthropic
8
- from langgraph.store.memory import InMemoryStore
9
- from langgraph.checkpoint.memory import MemorySaver
10
- import uuid
11
-
12
- class TestFilesystem:
13
- def test_create_deepagent_without_store_and_with_longterm_memory_should_fail(self):
14
- with pytest.raises(ValueError):
15
- deepagent = create_deep_agent(tools=[], use_longterm_memory=True)
16
- deepagent.invoke({"messages": [HumanMessage(content="List all of the files in your filesystem?")]})
17
-
18
- def test_filesystem_system_prompt_override(self):
19
- agent = create_agent(
20
- model=ChatAnthropic(model="claude-3-5-sonnet-20240620"),
21
- middleware=[
22
- FilesystemMiddleware(
23
- use_longterm_memory=False,
24
- system_prompt="In every single response, you must say the word 'pokemon'! You love it!"
25
- )
26
- ]
27
- )
28
- response = agent.invoke({"messages": [HumanMessage(content="What do you like?")]})
29
- assert "pokemon" in response["messages"][1].text.lower()
30
-
31
- def test_filesystem_system_prompt_override_with_longterm_memory(self):
32
- agent = create_agent(
33
- model=ChatAnthropic(model="claude-3-5-sonnet-20240620"),
34
- middleware=[
35
- FilesystemMiddleware(
36
- use_longterm_memory=True,
37
- system_prompt="In every single response, you must say the word 'pokemon'! You love it!"
38
- )
39
- ],
40
- store=InMemoryStore()
41
- )
42
- response = agent.invoke({"messages": [HumanMessage(content="What do you like?")]})
43
- assert "pokemon" in response["messages"][1].text.lower()
44
-
45
- def test_filesystem_tool_prompt_override(self):
46
- agent = create_agent(
47
- model=ChatAnthropic(model="claude-3-5-sonnet-20240620"),
48
- middleware=[
49
- FilesystemMiddleware(
50
- use_longterm_memory=False,
51
- custom_tool_descriptions={
52
- "ls": "Charmander",
53
- "read_file": "Bulbasaur",
54
- "edit_file": "Squirtle"
55
- }
56
- )
57
- ],
58
- )
59
- tools = agent.nodes["tools"].bound._tools_by_name
60
- assert "ls" in tools
61
- assert tools["ls"].description == "Charmander"
62
- assert "read_file" in tools
63
- assert tools["read_file"].description == "Bulbasaur"
64
- assert "write_file" in tools
65
- assert tools["write_file"].description == WRITE_FILE_TOOL_DESCRIPTION
66
- assert "edit_file" in tools
67
- assert tools["edit_file"].description == "Squirtle"
68
-
69
- def test_filesystem_tool_prompt_override_with_longterm_memory(self):
70
- agent = create_agent(
71
- model=ChatAnthropic(model="claude-3-5-sonnet-20240620"),
72
- middleware=[
73
- FilesystemMiddleware(
74
- use_longterm_memory=True,
75
- custom_tool_descriptions={
76
- "ls": "Charmander",
77
- "read_file": "Bulbasaur",
78
- "edit_file": "Squirtle"
79
- }
80
- )
81
- ],
82
- store=InMemoryStore()
83
- )
84
- tools = agent.nodes["tools"].bound._tools_by_name
85
- assert "ls" in tools
86
- assert tools["ls"].description == "Charmander"
87
- assert "read_file" in tools
88
- assert tools["read_file"].description == "Bulbasaur"
89
- assert "write_file" in tools
90
- assert tools["write_file"].description == WRITE_FILE_TOOL_DESCRIPTION + WRITE_FILE_TOOL_DESCRIPTION_LONGTERM_SUPPLEMENT
91
- assert "edit_file" in tools
92
- assert tools["edit_file"].description == "Squirtle"
93
-
94
-
95
- def test_longterm_memory_tools(self):
96
- checkpointer = MemorySaver()
97
- store = InMemoryStore()
98
- agent = create_agent(
99
- model=ChatAnthropic(model="claude-3-5-sonnet-20240620"),
100
- middleware=[
101
- FilesystemMiddleware(
102
- use_longterm_memory=True,
103
- )
104
- ],
105
- checkpointer=checkpointer,
106
- store=store
107
- )
108
- assert_longterm_mem_tools(agent, store)
109
-
110
-
111
- def test_longterm_memory_tools_deepagent(self):
112
- checkpointer = MemorySaver()
113
- store = InMemoryStore()
114
- agent = create_deep_agent(
115
- use_longterm_memory=True,
116
- checkpointer=checkpointer,
117
- store=store
118
- )
119
- assert_longterm_mem_tools(agent, store)
120
-
121
-
122
- def test_shortterm_memory_tools_deepagent(self):
123
- checkpointer = MemorySaver()
124
- store = InMemoryStore()
125
- agent = create_deep_agent(
126
- use_longterm_memory=False,
127
- checkpointer=checkpointer,
128
- store=store
129
- )
130
- assert_shortterm_mem_tools(agent)
131
-
132
-
133
- def assert_longterm_mem_tools(agent, store):
134
- config = {"configurable": {"thread_id": uuid.uuid4()}}
135
- agent.invoke({"messages": [HumanMessage(content="Write a haiku about Charmander to longterm memory in charmander.txt, use the word 'fiery'")]}, config=config)
136
-
137
- namespaces = store.list_namespaces()
138
- assert len(namespaces) == 1
139
- assert namespaces[0] == "filesystem"
140
- file_item = store.get(("filesystem"), "charmander.txt")
141
- assert file_item is not None
142
- assert file_item.key == "charmander.txt"
143
-
144
- config2 = {"configurable": {"thread_id": uuid.uuid4()}}
145
- response = agent.invoke({"messages": [HumanMessage(content="Read the haiku about Charmander from longterm memory at charmander.txt")]}, config=config2)
146
-
147
- messages = response["messages"]
148
- read_file_message = next(message for message in messages if message.type == "tool" and message.name == "read_file")
149
- assert "fiery" in read_file_message.content or "Fiery" in read_file_message.content
150
-
151
- config3 = {"configurable": {"thread_id": uuid.uuid4()}}
152
- response = agent.invoke({"messages": [HumanMessage(content="List all of the files in longterm memory")]}, config=config3)
153
- messages = response["messages"]
154
- ls_message = next(message for message in messages if message.type == "tool" and message.name == "ls")
155
- assert "memories/charmander.txt" in ls_message.content
156
-
157
- config4 = {"configurable": {"thread_id": uuid.uuid4()}}
158
- response = agent.invoke({"messages": [HumanMessage(content="Edit the haiku about Charmander in longterm memory to use the word 'ember'")]}, config=config4)
159
- file_item = store.get(("filesystem"), "charmander.txt")
160
- assert file_item is not None
161
- assert file_item.key == "charmander.txt"
162
- assert "ember" in file_item.value or "Ember" in file_item.value
163
-
164
- config5 = {"configurable": {"thread_id": uuid.uuid4()}}
165
- response = agent.invoke({"messages": [HumanMessage(content="Read the haiku about Charmander from longterm memory at charmander.txt")]}, config=config5)
166
- messages = response["messages"]
167
- read_file_message = next(message for message in messages if message.type == "tool" and message.name == "read_file")
168
- assert "ember" in read_file_message.content or "Ember" in read_file_message.content
169
-
170
-
171
- def assert_shortterm_mem_tools(agent):
172
- config = {"configurable": {"thread_id": uuid.uuid4()}}
173
- response = agent.invoke({"messages": [HumanMessage(content="Write a haiku about Charmander to charmander.txt, use the word 'fiery'")]}, config=config)
174
- files = response["files"]
175
- assert "charmander.txt" in files
176
-
177
- response = agent.invoke({"messages": [HumanMessage(content="Read the haiku about Charmander from charmander.txt")]}, config=config)
178
- messages = response["messages"]
179
- read_file_message = next(message for message in reversed(messages) if message.type == "tool" and message.name == "read_file")
180
- assert "fiery" in read_file_message.content or "Fiery" in read_file_message.content
181
-
182
- response = agent.invoke({"messages": [HumanMessage(content="List all of the files in memory")]}, config=config)
183
- messages = response["messages"]
184
- ls_message = next(message for message in messages if message.type == "tool" and message.name == "ls")
185
- assert "charmander.txt" in ls_message.content
186
-
187
- response = agent.invoke({"messages": [HumanMessage(content="Edit the haiku about Charmander to use the word 'ember'")]}, config=config)
188
- files = response["files"]
189
- assert "charmander.txt" in files
190
- assert "ember" in files["charmander.txt"] or "Ember" in files["charmander.txt"]
191
-
192
- response = agent.invoke({"messages": [HumanMessage(content="Read the haiku about Charmander at charmander.txt")]}, config=config)
193
- messages = response["messages"]
194
- read_file_message = next(message for message in reversed(messages) if message.type == "tool" and message.name == "read_file")
195
- assert "ember" in read_file_message.content or "Ember" in read_file_message.content
196
-
tests/test_hitl.py DELETED
@@ -1,51 +0,0 @@
1
- from deepagents.graph import create_deep_agent
2
- from tests.utils import assert_all_deepagent_qualities, get_weather, sample_tool, get_soccer_scores
3
- from langgraph.checkpoint.memory import MemorySaver
4
- from langgraph.types import Command
5
- import uuid
6
-
7
- SAMPLE_TOOL_CONFIG = {
8
- "sample_tool": True,
9
- "get_weather": False,
10
- "get_soccer_scores": {
11
- "allow_accept": True,
12
- "allow_reject": True,
13
- "allow_respond": False,
14
- "description": "Ohohohooooo"
15
- },
16
- }
17
-
18
- class TestHITL:
19
- def test_hitl_agent(self):
20
- checkpointer = MemorySaver()
21
- agent = create_deep_agent(tools=[sample_tool, get_weather, get_soccer_scores], tool_configs=SAMPLE_TOOL_CONFIG, checkpointer=checkpointer)
22
- config = {
23
- "configurable": {
24
- "thread_id": uuid.uuid4()
25
- }
26
- }
27
- assert_all_deepagent_qualities(agent)
28
- result = agent.invoke({"messages": [{"role": "user", "content": "Call the sample tool, get the weather in New York and get scores for the latest soccer games in parallel"}]}, config=config)
29
- agent_messages = [msg for msg in result.get("messages", []) if msg.type == "ai"]
30
- tool_calls = [tool_call for msg in agent_messages for tool_call in msg.tool_calls]
31
- assert any([tool_call["name"] == "sample_tool" for tool_call in tool_calls])
32
- assert any([tool_call["name"] == "get_weather" for tool_call in tool_calls])
33
- assert any([tool_call["name"] == "get_soccer_scores" for tool_call in tool_calls])
34
-
35
- assert result["__interrupt__"] is not None
36
- interrupts = result["__interrupt__"][0].value
37
- assert len(interrupts) == 2
38
- assert any([interrupt["action_request"]["action"] == "sample_tool" for interrupt in interrupts])
39
- assert any([interrupt["action_request"]["action"] == "get_soccer_scores" for interrupt in interrupts])
40
-
41
- result2 = agent.invoke(
42
- Command(
43
- resume=[{"type": "accept"}, {"type": "accept"}]
44
- ),
45
- config=config
46
- )
47
- tool_results = [msg for msg in result2.get("messages", []) if msg.type == "tool"]
48
- assert any([tool_result.name == "sample_tool" for tool_result in tool_results])
49
- assert any([tool_result.name == "get_weather" for tool_result in tool_results])
50
- assert any([tool_result.name == "get_soccer_scores" for tool_result in tool_results])
51
- assert "__interrupt__" not in result2
tests/test_middleware.py DELETED
@@ -1,57 +0,0 @@
1
- from langchain.agents import create_agent
2
- from deepagents.middleware import (
3
- PlanningMiddleware,
4
- FilesystemMiddleware,
5
- SubAgentMiddleware,
6
- )
7
-
8
- SAMPLE_MODEL = "claude-3-5-sonnet-20240620"
9
-
10
- class TestAddMiddleware:
11
- def test_planning_middleware(self):
12
- middleware = [PlanningMiddleware()]
13
- agent = create_agent(model=SAMPLE_MODEL, middleware=middleware, tools=[])
14
- assert "todos" in agent.stream_channels
15
- assert "write_todos" in agent.nodes["tools"].bound._tools_by_name.keys()
16
-
17
- def test_filesystem_middleware(self):
18
- middleware = [FilesystemMiddleware()]
19
- agent = create_agent(model=SAMPLE_MODEL, middleware=middleware, tools=[])
20
- assert "files" in agent.stream_channels
21
- agent_tools = agent.nodes["tools"].bound._tools_by_name.keys()
22
- assert "ls" in agent_tools
23
- assert "read_file" in agent_tools
24
- assert "write_file" in agent_tools
25
- assert "edit_file" in agent_tools
26
-
27
- def test_subagent_middleware(self):
28
- middleware = [
29
- SubAgentMiddleware(
30
- default_subagent_tools=[],
31
- subagents=[],
32
- model=SAMPLE_MODEL
33
- )
34
- ]
35
- agent = create_agent(model=SAMPLE_MODEL, middleware=middleware, tools=[])
36
- assert "task" in agent.nodes["tools"].bound._tools_by_name.keys()
37
-
38
- def test_multiple_middleware(self):
39
- middleware = [
40
- PlanningMiddleware(),
41
- FilesystemMiddleware(),
42
- SubAgentMiddleware(
43
- default_subagent_tools=[],
44
- subagents=[],
45
- model=SAMPLE_MODEL
46
- )
47
- ]
48
- agent = create_agent(model=SAMPLE_MODEL, middleware=middleware, tools=[])
49
- assert "todos" in agent.stream_channels
50
- assert "files" in agent.stream_channels
51
- agent_tools = agent.nodes["tools"].bound._tools_by_name.keys()
52
- assert "write_todos" in agent_tools
53
- assert "ls" in agent_tools
54
- assert "read_file" in agent_tools
55
- assert "write_file" in agent_tools
56
- assert "edit_file" in agent_tools
57
- assert "task" in agent_tools
tests/utils.py DELETED
@@ -1,81 +0,0 @@
1
- from langchain_core.tools import tool, InjectedToolCallId
2
- from langchain.agents.middleware import AgentMiddleware
3
- from typing import Annotated
4
- from langchain.tools.tool_node import InjectedState
5
- from langchain.agents.middleware import AgentMiddleware, AgentState
6
- from langgraph.types import Command
7
- from langchain_core.messages import ToolMessage
8
-
9
- def assert_all_deepagent_qualities(agent):
10
- assert "todos" in agent.stream_channels
11
- assert "files" in agent.stream_channels
12
- assert "write_todos" in agent.nodes["tools"].bound._tools_by_name.keys()
13
- assert "ls" in agent.nodes["tools"].bound._tools_by_name.keys()
14
- assert "read_file" in agent.nodes["tools"].bound._tools_by_name.keys()
15
- assert "write_file" in agent.nodes["tools"].bound._tools_by_name.keys()
16
- assert "edit_file" in agent.nodes["tools"].bound._tools_by_name.keys()
17
- assert "task" in agent.nodes["tools"].bound._tools_by_name.keys()
18
-
19
- ###########################
20
- # Mock tools and middleware
21
- ###########################
22
-
23
- SAMPLE_MODEL = "claude-3-5-sonnet-20240620"
24
-
25
- @tool(description="Use this tool to get the weather")
26
- def get_weather(location: str):
27
- return f"The weather in {location} is sunny."
28
-
29
- @tool(description="Use this tool to get the latest soccer scores")
30
- def get_soccer_scores(team: str):
31
- return f"The latest soccer scores for {team} are 2-1."
32
-
33
- @tool(description="Sample tool")
34
- def sample_tool(sample_input: str):
35
- return sample_input
36
-
37
- @tool(description="Sample tool with injected state")
38
- def sample_tool_with_injected_state(sample_input: str, state: Annotated[dict, InjectedState]):
39
- return sample_input + state["sample_input"]
40
-
41
- TOY_BASKETBALL_RESEARCH = "Lebron James is the best basketball player of all time with over 40k points and 21 seasons in the NBA."
42
-
43
- @tool(description="Use this tool to conduct research into basketball and save it to state")
44
- def research_basketball(
45
- topic: str,
46
- state: Annotated[dict, InjectedState],
47
- tool_call_id: Annotated[str, InjectedToolCallId]
48
- ):
49
- current_research = state.get("research", "")
50
- research = f"{current_research}\n\nResearching on {topic}... Done! {TOY_BASKETBALL_RESEARCH}"
51
- return Command(
52
- update={
53
- "research": research,
54
- "messages": [
55
- ToolMessage(research, tool_call_id=tool_call_id)
56
- ]
57
- }
58
- )
59
-
60
- class ResearchState(AgentState):
61
- research: str
62
-
63
- class ResearchMiddlewareWithTools(AgentMiddleware):
64
- state_schema = ResearchState
65
- tools = [research_basketball]
66
-
67
- class ResearchMiddleware(AgentMiddleware):
68
- state_schema = ResearchState
69
-
70
- class SampleMiddlewareWithTools(AgentMiddleware):
71
- tools = [sample_tool]
72
-
73
- class SampleState(AgentState):
74
- sample_input: str
75
-
76
- class SampleMiddlewareWithToolsAndState(AgentMiddleware):
77
- state_schema = SampleState
78
- tools = [sample_tool]
79
-
80
- class WeatherToolMiddleware(AgentMiddleware):
81
- tools = [get_weather]