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.
@@ -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>