dspy-agent-tools 0.1.2__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.
- dspy_agent_tools-0.1.2/LICENSE +21 -0
- dspy_agent_tools-0.1.2/PKG-INFO +376 -0
- dspy_agent_tools-0.1.2/README.md +351 -0
- dspy_agent_tools-0.1.2/pyproject.toml +81 -0
- dspy_agent_tools-0.1.2/pyproject.toml.orig +76 -0
- dspy_agent_tools-0.1.2/src/dspy_agent_tools/__init__.py +32 -0
- dspy_agent_tools-0.1.2/src/dspy_agent_tools/bash.py +792 -0
- dspy_agent_tools-0.1.2/src/dspy_agent_tools/files.py +303 -0
- dspy_agent_tools-0.1.2/src/dspy_agent_tools/search.py +81 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Edward Boswell
|
|
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,376 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dspy-agent-tools
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Author: Edward Boswell
|
|
6
|
+
Author-email: Edward Boswell <thememium@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Requires-Dist: beautifulsoup4>=4.15.0
|
|
13
|
+
Requires-Dist: ddgs>=9.16.0
|
|
14
|
+
Requires-Dist: markdownify>=1.2.3
|
|
15
|
+
Requires-Dist: plumbum>=2.0.2
|
|
16
|
+
Requires-Dist: rgapi>=0.2.2
|
|
17
|
+
Requires-Dist: tree-sitter-language-pack>=1.20.0
|
|
18
|
+
Requires-Python: >=3.13
|
|
19
|
+
Project-URL: Homepage, https://github.com/thememium/dspy-agent-tools
|
|
20
|
+
Project-URL: Documentation, https://github.com/thememium/dspy-agent-tools
|
|
21
|
+
Project-URL: Repository, https://github.com/thememium/dspy-agent-tools.git
|
|
22
|
+
Project-URL: Issues, https://github.com/thememium/dspy-agent-tools/issues
|
|
23
|
+
Project-URL: Changelog, https://github.com/thememium/dspy-agent-tools/blob/master/CHANGELOG.md
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
<a name="readme-top"></a>
|
|
27
|
+
|
|
28
|
+
<div align="center">
|
|
29
|
+
<h3 align="center">DSPy Agent Tools</h3>
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
A ready-made toolbox of Python functions for DSPy agents.
|
|
33
|
+
<br />
|
|
34
|
+
<a href="#table-of-contents"><strong>Explore the Documentation »</strong></a>
|
|
35
|
+
<br />
|
|
36
|
+
<a href="https://github.com/thememium/dspy-agent-tools/issues">Report Bug</a>
|
|
37
|
+
·
|
|
38
|
+
<a href="https://github.com/thememium/dspy-agent-tools/issues">Request Feature</a>
|
|
39
|
+
</p>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<!-- TABLE OF CONTENTS -->
|
|
43
|
+
|
|
44
|
+
<a name="table-of-contents"></a>
|
|
45
|
+
|
|
46
|
+
<details>
|
|
47
|
+
<summary>Table of Contents</summary>
|
|
48
|
+
<ol>
|
|
49
|
+
<li><a href="#about">About</a></li>
|
|
50
|
+
<li><a href="#quick-start">Quick Start</a></li>
|
|
51
|
+
<li><a href="#usage">Usage</a></li>
|
|
52
|
+
<li><a href="#tool-reference">Tool Reference</a></li>
|
|
53
|
+
<li><a href="#development">Development</a></li>
|
|
54
|
+
<li><a href="#contributing">Contributing</a></li>
|
|
55
|
+
<li><a href="#license">License</a></li>
|
|
56
|
+
</ol>
|
|
57
|
+
</details>
|
|
58
|
+
|
|
59
|
+
<!-- ABOUT -->
|
|
60
|
+
|
|
61
|
+
## About
|
|
62
|
+
|
|
63
|
+
DSPy Agent Tools is a library of **tool functions** for
|
|
64
|
+
[DSPy](https://dspy.ai) agents. Every tool is a plain, type-hinted Python
|
|
65
|
+
function with a tool-optimized docstring, so you can hand them straight to
|
|
66
|
+
`dspy.ReAct` or `dspy.RLM` — no adapters, no wrappers.
|
|
67
|
+
|
|
68
|
+
Three families of tools:
|
|
69
|
+
|
|
70
|
+
- **Bash** — shell execution, file search (ripgrep/fd-style, no binaries needed), directory listing, and URL fetching
|
|
71
|
+
- **Files** — read, write, and edit files with snapshot-based optimistic concurrency and tree-sitter block addressing
|
|
72
|
+
- **Search** — DuckDuckGo web and news search
|
|
73
|
+
|
|
74
|
+
Tools are just Python functions, exactly as
|
|
75
|
+
[DSPy's docs describe](https://dspy.ai/current/getting-started/react-and-tools/#tools-are-just-python-functions):
|
|
76
|
+
DSPy reads the name, type-hinted parameters, and docstring of each function to
|
|
77
|
+
assemble the instructions it sends to the LM. These docstrings are written for
|
|
78
|
+
that purpose — each one tells the model WHAT the tool does, WHEN to use it
|
|
79
|
+
instead of a sibling tool, and HOW to pass arguments.
|
|
80
|
+
|
|
81
|
+
Requires **Python 3.13+** and **DSPy 3.1+**.
|
|
82
|
+
|
|
83
|
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
84
|
+
|
|
85
|
+
<!-- QUICK START -->
|
|
86
|
+
|
|
87
|
+
## Quick Start
|
|
88
|
+
|
|
89
|
+
### Install
|
|
90
|
+
|
|
91
|
+
Install dspy-agent-tools with uv (recommended):
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
uv add dspy-agent-tools
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Or with pip:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install dspy-agent-tools
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`bash_curl`, `bash_exec`, and `bash_ls` shell out to real `bash`/`curl`/`ls`
|
|
104
|
+
binaries, which must be on your PATH. The search tools
|
|
105
|
+
(`bash_ripgrep`, `bash_find`, `bash_glob`) run through the `rgapi` library —
|
|
106
|
+
ripgrep's and fd's engines as Python modules — so no `rg`/`fd` binary is
|
|
107
|
+
needed.
|
|
108
|
+
|
|
109
|
+
### Basic Usage with dspy.ReAct
|
|
110
|
+
|
|
111
|
+
Import the tools you need and put them in the `tools` list:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
import dspy
|
|
115
|
+
from dspy_agent_tools import web_search, bash_fetch
|
|
116
|
+
|
|
117
|
+
haiku_bot = dspy.ReAct(
|
|
118
|
+
"location -> haiku",
|
|
119
|
+
tools=[web_search, bash_fetch],
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
result = haiku_bot(location="Camp Meeker")
|
|
123
|
+
print(result.haiku)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Basic Usage with dspy.RLM
|
|
127
|
+
|
|
128
|
+
The same functions go into `dspy.RLM`'s `tools` list, where they are injected
|
|
129
|
+
into the REPL namespace and callable from the model's generated code:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
import dspy
|
|
133
|
+
from dspy_agent_tools import bash_exec, read_file, edit_file
|
|
134
|
+
|
|
135
|
+
rlm = dspy.RLM(
|
|
136
|
+
"task -> report",
|
|
137
|
+
tools=[bash_exec, read_file, edit_file],
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
result = rlm(task="Add a docstring to every public function in src/utils.py")
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
144
|
+
|
|
145
|
+
<!-- USAGE -->
|
|
146
|
+
|
|
147
|
+
## Usage
|
|
148
|
+
|
|
149
|
+
### With dspy.ReAct
|
|
150
|
+
|
|
151
|
+
`dspy.ReAct` runs an agentic reasoning loop over your tools. Pick the tools
|
|
152
|
+
the agent should see — a coding agent might get the file and shell tools, a
|
|
153
|
+
research agent the search and fetch tools:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
import dspy
|
|
157
|
+
from dspy_agent_tools import (
|
|
158
|
+
web_search,
|
|
159
|
+
bash_fetch,
|
|
160
|
+
bash_curl,
|
|
161
|
+
web_news,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
researcher = dspy.ReAct(
|
|
165
|
+
"question -> answer, sources",
|
|
166
|
+
tools=[web_search, web_news, bash_fetch, bash_curl],
|
|
167
|
+
max_iters=8,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
result = researcher(question="What changed in DSPy 3.1?")
|
|
171
|
+
print(result.answer)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Each tool is presented to the LM by name, docstring, and parameters. The
|
|
175
|
+
docstrings shipped in this package are already tuned for that presentation —
|
|
176
|
+
they steer the model toward the right tool (e.g. `bash_fetch` for readable
|
|
177
|
+
pages, `bash_curl` for raw API responses).
|
|
178
|
+
|
|
179
|
+
### With dspy.RLM
|
|
180
|
+
|
|
181
|
+
`dspy.RLM` executes model-written Python in a sandboxed REPL and hands the
|
|
182
|
+
model the same functions to call from inside its code:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
import dspy
|
|
186
|
+
from dspy_agent_tools import (
|
|
187
|
+
bash_exec,
|
|
188
|
+
bash_ripgrep,
|
|
189
|
+
bash_find,
|
|
190
|
+
read_file,
|
|
191
|
+
write_file,
|
|
192
|
+
edit_file,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
coder = dspy.RLM(
|
|
196
|
+
"task -> summary",
|
|
197
|
+
tools=[bash_exec, bash_ripgrep, bash_find, read_file, write_file, edit_file],
|
|
198
|
+
max_iters=20,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
result = coder(task="Rename the class SessionManager to Session across the repo")
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
A full coding-agent toolbox, all in one import:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
from dspy_agent_tools import (
|
|
208
|
+
bash_exec,
|
|
209
|
+
bash_curl,
|
|
210
|
+
bash_fetch,
|
|
211
|
+
bash_find,
|
|
212
|
+
bash_find_batch,
|
|
213
|
+
bash_glob,
|
|
214
|
+
bash_glob_batch,
|
|
215
|
+
bash_ls,
|
|
216
|
+
bash_ripgrep,
|
|
217
|
+
bash_ripgrep_batch,
|
|
218
|
+
edit_file,
|
|
219
|
+
read_file,
|
|
220
|
+
write_file,
|
|
221
|
+
web_news,
|
|
222
|
+
web_search,
|
|
223
|
+
)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Batching
|
|
227
|
+
|
|
228
|
+
Search tools come in single and `_batch` variants. A batch takes
|
|
229
|
+
`list[dict]` — one spec per search, each with `pattern`, `path`, and
|
|
230
|
+
`options` — and returns labeled sections. Use it when several independent
|
|
231
|
+
lookups are needed; it saves round trips and shares one timeout across the
|
|
232
|
+
batch:
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
bash_ripgrep_batch([
|
|
236
|
+
{"pattern": r"def main", "path": "src", "options": "-n"},
|
|
237
|
+
{"pattern": "TODO|FIXME", "options": "-n -i"},
|
|
238
|
+
])
|
|
239
|
+
# == def main in src ==
|
|
240
|
+
# src/cli.py:12:def main(args):
|
|
241
|
+
# ...
|
|
242
|
+
# == TODO|FIXME in . ==
|
|
243
|
+
# ...
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
`bash_find_batch` and `bash_glob_batch` work the same way for path lookups.
|
|
247
|
+
|
|
248
|
+
### Safety Notes
|
|
249
|
+
|
|
250
|
+
- `bash_exec` runs arbitrary shell commands with the caller's permissions.
|
|
251
|
+
Sandbox or restrict the agent before giving it that power.
|
|
252
|
+
- File tools are guarded by **snapshots**: `read_file` returns a short hash of
|
|
253
|
+
the file's content, and `edit_file`/`write_file` reject the change if the
|
|
254
|
+
file has changed since it was read, so concurrent edits can't be silently
|
|
255
|
+
overwritten.
|
|
256
|
+
- Non-zero exits, timeouts, and failed transfers are reported inline as
|
|
257
|
+
`"[exit code N]"` / `"[command timed out ...]"` notices rather than raised,
|
|
258
|
+
so an agent can read and recover from failures.
|
|
259
|
+
|
|
260
|
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
261
|
+
|
|
262
|
+
<!-- TOOL REFERENCE -->
|
|
263
|
+
|
|
264
|
+
## Tool Reference
|
|
265
|
+
|
|
266
|
+
### Bash (`dspy_agent_tools.bash`)
|
|
267
|
+
|
|
268
|
+
| Tool | Use it for |
|
|
269
|
+
| --- | --- |
|
|
270
|
+
| **`bash_exec`** | Run an arbitrary shell command (`command`, `cwd`, `timeout`). The fallback tool for anything without a dedicated tool: builds, tests, git, python snippets. |
|
|
271
|
+
| **`bash_ripgrep`** | Search file **contents** with a regex (`pattern`, `path`, `options`). rg-style flags, ripgrep semantics — hidden/gitignored paths skipped by default. |
|
|
272
|
+
| **`bash_ripgrep_batch`** | Many content searches in one call. `list[dict]` specs; labeled sections; one shared timeout. |
|
|
273
|
+
| **`bash_find`** | Find file/directory **names** with a regex (fd engine). `-e py`, `-t f`, `-d 2`, `-E <glob>`. |
|
|
274
|
+
| **`bash_find_batch`** | Many path lookups in one call. |
|
|
275
|
+
| **`bash_glob`** | Match paths against a glob — `"*.py"` at any depth, `"src/*.py"` anchored. |
|
|
276
|
+
| **`bash_glob_batch`** | Many glob lookups in one call. |
|
|
277
|
+
| **`bash_ls`** | List one directory's entries in long format. |
|
|
278
|
+
| **`bash_curl`** | Fetch a URL and return the **raw** response body — API JSON, headers, binaries. |
|
|
279
|
+
| **`bash_fetch`** | Fetch a web page and return **readable markdown** — nav, ads, cookie banners stripped, title kept. Prefer over `bash_curl` when the goal is reading. |
|
|
280
|
+
|
|
281
|
+
### Files (`dspy_agent_tools.files`)
|
|
282
|
+
|
|
283
|
+
| Tool | Use it for |
|
|
284
|
+
| --- | --- |
|
|
285
|
+
| **`read_file`** | Read a file; returns `(numbered_content, snapshot)`. Quote text WITHOUT the `" N | "` prefixes in later calls. |
|
|
286
|
+
| **`write_file`** | Write an entire file; optionally snapshot-guarded. Returns the new snapshot. |
|
|
287
|
+
| **`edit_file`** | Edit under snapshot control. Exactly one addressing mode per call: `block="MyClass.method"` (tree-sitter, any language in tree-sitter-language-pack), `start_line`/`end_line` (inclusive 1-based), or `old_text` (exact, must match once; auto-repairs near-misses down to `min_similarity=0.8` and strips pasted line-number prefixes). |
|
|
288
|
+
|
|
289
|
+
### Search (`dspy_agent_tools.search`)
|
|
290
|
+
|
|
291
|
+
| Tool | Use it for |
|
|
292
|
+
| --- | --- |
|
|
293
|
+
| **`web_search`** | DuckDuckGo web search. Returns `{"query", "results": [{"title", "href", "body"}], "count"}`. `timelimit`: `"d"`, `"w"`, `"m"`, `"y"`, or `None`. |
|
|
294
|
+
| **`web_news`** | DuckDuckGo News search; results add `source` and `date`. Same `timelimit` values. |
|
|
295
|
+
|
|
296
|
+
Shared behaviour across the bash tools:
|
|
297
|
+
|
|
298
|
+
- Output is capped at ~30KB (first 20KB + last 10KB kept) with a truncation notice.
|
|
299
|
+
- Wall time is appended as `(Ns)`.
|
|
300
|
+
- Timeouts kill the whole process group and return partial output.
|
|
301
|
+
- Bad regexes and unknown flags come back as `[Error]` text instead of raising.
|
|
302
|
+
|
|
303
|
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
304
|
+
|
|
305
|
+
<!-- DEVELOPMENT -->
|
|
306
|
+
|
|
307
|
+
## Development
|
|
308
|
+
|
|
309
|
+
### Code Quality
|
|
310
|
+
|
|
311
|
+
This project uses several tools to maintain code quality:
|
|
312
|
+
|
|
313
|
+
- **Ruff:** Linting and formatting
|
|
314
|
+
- **isort:** Import sorting
|
|
315
|
+
- **pytest:** Testing framework
|
|
316
|
+
- **ty:** Type checking
|
|
317
|
+
- **deptry:** Dependency analysis
|
|
318
|
+
|
|
319
|
+
**Available commands:**
|
|
320
|
+
|
|
321
|
+
```sh
|
|
322
|
+
# Run all quality checks
|
|
323
|
+
uv run poe clean-full
|
|
324
|
+
|
|
325
|
+
# Individual checks
|
|
326
|
+
uv run poe lint # Ruff linting
|
|
327
|
+
uv run poe format # Ruff formatting
|
|
328
|
+
uv run poe sort # Import sorting
|
|
329
|
+
uv run poe typecheck # Type checking
|
|
330
|
+
uv run poe deptry # Dependency analysis
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Testing
|
|
334
|
+
|
|
335
|
+
Run tests using pytest:
|
|
336
|
+
|
|
337
|
+
```sh
|
|
338
|
+
# Run all tests
|
|
339
|
+
uv run pytest
|
|
340
|
+
|
|
341
|
+
# Run with coverage
|
|
342
|
+
uv run poe test-cov
|
|
343
|
+
|
|
344
|
+
# Run specific test
|
|
345
|
+
uv run pytest path/to/test.py::test_name
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
349
|
+
|
|
350
|
+
<!-- CONTRIBUTING -->
|
|
351
|
+
|
|
352
|
+
## Contributing
|
|
353
|
+
|
|
354
|
+
Quick workflow:
|
|
355
|
+
|
|
356
|
+
1. Fork and branch: `git checkout -b feature/name`
|
|
357
|
+
2. Make changes
|
|
358
|
+
3. Run checks: `uv run poe clean-full`
|
|
359
|
+
4. Commit and push
|
|
360
|
+
5. Open a Pull Request
|
|
361
|
+
|
|
362
|
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
363
|
+
|
|
364
|
+
<!-- LICENSE -->
|
|
365
|
+
|
|
366
|
+
## License
|
|
367
|
+
|
|
368
|
+
MIT (as declared in `pyproject.toml`).
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
<div align="center">
|
|
373
|
+
<p>
|
|
374
|
+
<sub>Built by <a href="https://github.com/thememium">thememium</a></sub>
|
|
375
|
+
</p>
|
|
376
|
+
</div>
|