Skip to content

Commit 554c08a

Browse files
update to match latest in master
1 parent 7ec7e94 commit 554c08a

File tree

9 files changed

+130
-211
lines changed

9 files changed

+130
-211
lines changed

libs/deepagents-cli/deepagents_cli/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ cli/
1212
├── __main__.py # Entry point for `python -m deepagents.cli`
1313
├── main.py # CLI loop, argument parsing, main orchestration
1414
├── config.py # Configuration, constants, colors, model creation
15-
├── tools.py # Custom tools (http_request, web_search)
15+
├── tools.py # Custom tools (http_request, parallel_search, tavily_search)
1616
├── ui.py # Display logic, TokenTracker, help screens
1717
├── input.py # Input handling, completers, prompt session
1818
├── commands.py # Slash command and bash command handlers

libs/deepagents-cli/deepagents_cli/agent.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ def _format_edit_file_description(tool_call: ToolCall, state: AgentState, runtim
223223
)
224224

225225

226-
def _format_tavily_search_description(tool_call: ToolCall, state: AgentState, runtime: Runtime) -> str:
226+
def _format_tavily_search_description(
227+
tool_call: ToolCall, state: AgentState, runtime: Runtime
228+
) -> str:
227229
"""Format tavily_search tool call for approval prompt."""
228230
args = tool_call["args"]
229231
query = args.get("query", "unknown")
@@ -238,30 +240,17 @@ def _format_tavily_search_description(tool_call: ToolCall, state: AgentState, ru
238240
)
239241

240242

241-
def _format_parallel_search_description(tool_call: ToolCall, state: AgentState, runtime: Runtime) -> str:
243+
def _format_parallel_search_description(
244+
tool_call: ToolCall, state: AgentState, runtime: Runtime
245+
) -> str:
242246
"""Format parallel_search tool call for approval prompt."""
243247
args = tool_call["args"]
244248
queries = args.get("queries", [])
245249
max_results = args.get("max_results", 5)
246250
objective = args.get("objective")
247251

248252
description = f"Queries: {queries}\nMax results: {max_results}\n"
249-
if objective:
250-
description += f"Objective: {objective}\n"
251-
description += "\n⚠️ This will use Parallel API credits"
252-
253-
return description
254-
255-
def _format_parallel_search_description(tool_call: ToolCall, state: AgentState, runtime: Runtime) -> str:
256-
"""Format parallel_search tool call for approval prompt."""
257-
args = tool_call.get("args", {})
258-
queries = args.get("queries", "unknown")
259-
max_results = args.get("max_results", 5)
260-
objective = args.get("objective")
261-
262-
description = f"Queries: {queries}\nMax results: {max_results}\n"
263-
if objective:
264-
description += f"Objective: {objective}\n"
253+
description += f"Objective: {objective}\n"
265254
description += "\n⚠️ This will use Parallel API credits"
266255

267256
return description

libs/deepagents-cli/deepagents_cli/default_agent_prompt.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,11 @@ Examples: `pytest /foo/bar/tests` (good), `cd /foo/bar && pytest tests` (bad)
9595

9696
Always use absolute paths starting with /.
9797

98-
### web_search
99-
Search for documentation, error solutions, and code examples.
98+
### parallel_search
99+
Search for documentation, error solutions, and code examples using Parallel.
100+
101+
### tavily_search
102+
Search for documentation, error solutions, and code examples using Tavily.
100103

101104
### http_request
102105
Make HTTP requests to APIs (GET, POST, etc.).

libs/deepagents-cli/deepagents_cli/execution.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ async def execute_task(
210210
"grep": "🔎",
211211
"shell": "⚡",
212212
"execute": "🔧",
213-
"web_search": "🌐",
213+
"parallel_search": "🌐",
214+
"tavily_search": "🌐",
214215
"http_request": "🌍",
215216
"task": "🤖",
216217
"write_todos": "📋",
@@ -372,7 +373,7 @@ def flush_text_buffer(*, final: bool = False) -> None:
372373
status.start()
373374
spinner_active = True
374375

375-
# For all other tools (web_search, http_request, etc.),
376+
# For all other tools (parallel_search, http_request, etc.),
376377
# results are hidden from user - agent will process and respond
377378
continue
378379

libs/deepagents-cli/deepagents_cli/tools.py

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ def tavily_search(
143143

144144

145145
def parallel_search(
146+
objective: str,
146147
queries: list[str],
147148
max_results: int = 5,
148-
objective: str | None = None,
149149
max_chars_per_excerpt: int = 1000,
150150
) -> SearchResult:
151151
"""Search the web using Parallel for current information and documentation.
@@ -155,11 +155,10 @@ def parallel_search(
155155
helpful response for the user.
156156
157157
Args:
158-
queries: A list of search queries (be specific and detailed)
159-
max_results: Number of results to return (default: 5)
160158
objective: Natural-language description of what the web search is trying to find.
161159
May include guidance about preferred sources or freshness.
162-
At least one of objective or search_queries must be provided.
160+
queries: A list of search queries (be specific and detailed)
161+
max_results: Number of results to return (default: 5)
163162
max_chars_per_excerpt: Maximum characters per excerpt (default: 1000)
164163
165164
Returns:
@@ -200,28 +199,12 @@ def parallel_search(
200199
}
201200

202201

203-
def get_web_search_tool():
204-
"""Get the available web search tool based on configured API keys.
205-
206-
Returns tavily_search if TAVILY_API_KEY is set, otherwise parallel_search
207-
if PARALLEL_API_KEY is set, otherwise None.
208-
209-
This is kept for backward compatibility. New code should use
210-
tavily_search or parallel_search directly.
211-
"""
212-
if tavily_client is not None:
213-
return tavily_search
214-
if parallel_client is not None:
215-
return parallel_search
216-
return None
217-
218-
219202
def web_search(
220203
query: str,
221204
max_results: int = 5,
222205
topic: Literal["general", "news", "finance"] = "general",
223206
include_raw_content: bool = False,
224-
) -> dict[str, Any]:
207+
):
225208
"""Search the web using Tavily for current information and documentation.
226209
227210
This is a backward compatibility wrapper for tavily_search.

libs/deepagents-cli/deepagents_cli/ui.py

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def format_tool_display(tool_name: str, tool_args: dict) -> str:
3636
3737
Examples:
3838
read_file(path="/long/path/file.py") → "read_file(file.py)"
39-
web_search(query="how to code", max_results=5) → 'web_search("how to code")'
39+
parallel_search(objective="how to code", max_results=5) → 'parallel_search("how to code")'
4040
shell(command="pip install foo") → 'shell("pip install foo")'
4141
"""
4242

@@ -79,13 +79,6 @@ def abbreviate_path(path_str: str, max_length: int = 60) -> str:
7979
path = abbreviate_path(str(path_value))
8080
return f"{tool_name}({path})"
8181

82-
elif tool_name == "web_search":
83-
# Web search: show the query string (backward compatibility)
84-
if "query" in tool_args:
85-
query = str(tool_args["query"])
86-
query = truncate_value(query, 100)
87-
return f'{tool_name}("{query}")'
88-
8982
elif tool_name == "tavily_search":
9083
# Tavily search: show the query string
9184
if "query" in tool_args:
@@ -94,19 +87,11 @@ def abbreviate_path(path_str: str, max_length: int = 60) -> str:
9487
return f'{tool_name}("{query}")'
9588

9689
elif tool_name == "parallel_search":
97-
# Parallel search: show the queries list
98-
if "queries" in tool_args:
99-
queries = tool_args["queries"]
100-
if isinstance(queries, list):
101-
# Show first query + count if multiple
102-
if len(queries) == 1:
103-
return f'{tool_name}("{queries[0]}")'
104-
else:
105-
first = truncate_value(str(queries[0]), 80)
106-
return f'{tool_name}("{first}" + {len(queries)-1} more)'
107-
else:
108-
queries_str = truncate_value(str(queries), 100)
109-
return f'{tool_name}({queries_str})'
90+
# Parallel search: show the objective
91+
if "objective" in tool_args:
92+
objective = str(tool_args["objective"])
93+
objective = truncate_value(objective, 100)
94+
return f'{tool_name}("{objective}")'
11095

11196
elif tool_name == "grep":
11297
# Grep: show the search pattern

libs/deepagents-cli/tests/unit_tests/test_agent.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
_format_fetch_url_description,
99
_format_shell_description,
1010
_format_task_description,
11-
_format_web_search_description,
11+
_format_tavily_search_description,
12+
_format_parallel_search_description,
1213
_format_write_file_description,
1314
)
1415

@@ -103,10 +104,10 @@ def test_format_edit_file_description_all_occurrences():
103104
assert "Action: Replace text (all occurrences)" in description
104105

105106

106-
def test_format_web_search_description():
107-
"""Test web_search description formatting."""
107+
def test_format_tavily_search_description():
108+
"""Test tavily_search description formatting."""
108109
tool_call = {
109-
"name": "web_search",
110+
"name": "tavily_search",
110111
"args": {
111112
"query": "python async programming",
112113
"max_results": 10,
@@ -117,17 +118,17 @@ def test_format_web_search_description():
117118
state = Mock()
118119
runtime = Mock()
119120

120-
description = _format_web_search_description(tool_call, state, runtime)
121+
description = _format_tavily_search_description(tool_call, state, runtime)
121122

122123
assert "Query: python async programming" in description
123124
assert "Max results: 10" in description
124125
assert "⚠️ This will use Tavily API credits" in description
125126

126127

127-
def test_format_web_search_description_default_max_results():
128-
"""Test web_search description with default max_results."""
128+
def test_format_tavily_search_description_default_max_results():
129+
"""Test tavily_search description with default max_results."""
129130
tool_call = {
130-
"name": "web_search",
131+
"name": "tavily_search",
131132
"args": {
132133
"query": "langchain tutorial",
133134
},
@@ -137,12 +138,35 @@ def test_format_web_search_description_default_max_results():
137138
state = Mock()
138139
runtime = Mock()
139140

140-
description = _format_web_search_description(tool_call, state, runtime)
141+
description = _format_tavily_search_description(tool_call, state, runtime)
141142

142143
assert "Query: langchain tutorial" in description
143144
assert "Max results: 5" in description
144145

145146

147+
def test_format_parallel_search_description():
148+
"""Test parallel_search description formatting."""
149+
tool_call = {
150+
"name": "parallel_search",
151+
"args": {
152+
"objective": "Learn python async programming",
153+
"queries": ["python async programming"],
154+
"max_results": 10,
155+
},
156+
"id": "call-5",
157+
}
158+
159+
state = Mock()
160+
runtime = Mock()
161+
162+
description = _format_parallel_search_description(tool_call, state, runtime)
163+
164+
assert "Objective: Learn python async programming" in description
165+
assert "Queries: ['python async programming']" in description
166+
assert "Max results: 10" in description
167+
assert "⚠️ This will use Parallel API credits" in description
168+
169+
146170
def test_format_fetch_url_description():
147171
"""Test fetch_url description formatting."""
148172
tool_call = {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import pytest
2+
from parallel.types.beta.web_search_result import WebSearchResult
3+
4+
from deepagents_cli import tools
5+
6+
7+
@pytest.fixture
8+
def mock_parallel_client():
9+
original = tools.parallel_client
10+
yield
11+
tools.parallel_client = original
12+
13+
14+
def test_parallel_search_success(mock_parallel_client):
15+
class MockResult:
16+
results = [WebSearchResult(url="https://python.org", title="Python", excerpts=["Guide"])]
17+
search_id = "123"
18+
19+
class MockBeta:
20+
def search(self, *args, **kwargs):
21+
return MockResult()
22+
23+
class MockClient:
24+
beta = MockBeta()
25+
26+
tools.parallel_client = MockClient()
27+
result = tools.parallel_search("Learn Python", ["python"])
28+
29+
assert result.search_id == "123"
30+
assert len(result.results) == 1
31+
32+
33+
def test_parallel_search_with_objective(mock_parallel_client):
34+
class MockResult:
35+
results = []
36+
search_id = "456"
37+
38+
class MockBeta:
39+
def search(self, objective, search_queries, **kwargs):
40+
assert objective == "Learn Python"
41+
assert search_queries == ["python"]
42+
return MockResult()
43+
44+
class MockClient:
45+
beta = MockBeta()
46+
47+
tools.parallel_client = MockClient()
48+
result = tools.parallel_search("Learn Python", ["python"])
49+
50+
assert result.search_id == "456"
51+
52+
53+
def test_parallel_search_no_client(mock_parallel_client):
54+
tools.parallel_client = None
55+
result = tools.parallel_search("Learn Python", ["python"])
56+
57+
assert "error" in result
58+
59+
60+
def test_parallel_search_error(mock_parallel_client):
61+
class MockBeta:
62+
def search(self, *args, **kwargs):
63+
raise Exception("API error")
64+
65+
class MockClient:
66+
beta = MockBeta()
67+
68+
tools.parallel_client = MockClient()
69+
result = tools.parallel_search("Learn Python", ["python"])
70+
71+
assert "error" in result

0 commit comments

Comments
 (0)