python-agent-harness 1.5.5.4__tar.gz → 1.5.5.5__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.
- {python_agent_harness-1.5.5.4/python_agent_harness.egg-info → python_agent_harness-1.5.5.5}/PKG-INFO +21 -2
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/README.md +20 -1
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/pyproject.toml +1 -1
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/__init__.py +1 -1
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/agents/reviewer.md +10 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts.py +62 -14
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/session.py +45 -4
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tui/commands.py +3 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5/python_agent_harness.egg-info}/PKG-INFO +21 -2
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_custom_agents.py +223 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/LICENSE +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/__main__.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/agent.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/cli.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/client.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/commands.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/config.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/context_manager.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/diffrender.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/mcp/__init__.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/mcp/client.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/mcp/config.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/mcp/manager.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/models.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/persistence.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/planmode.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/agent.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/build-switch.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/commands/explain.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/compact.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/initialize.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/plan-mode.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/plan.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/review.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/subagent.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/summary.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/task-completion-rules.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/title.md +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/subagent.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/token_estimator.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tool_runner.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/__init__.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/agent_tool.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/base.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/bash.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/bash_win.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/diffapply.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/edit.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/edit_mac.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/edit_win.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/filesystem.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/glob.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/glob_mac.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/glob_win.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/grep.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/grep_mac.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/grep_win.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/insert.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/mcp.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/mkdir.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/planexit.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/question.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/read.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/skill.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/todo.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/write.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tui/__init__.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tui/core.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tui/input.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tui/render.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness.egg-info/SOURCES.txt +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness.egg-info/dependency_links.txt +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness.egg-info/entry_points.txt +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness.egg-info/requires.txt +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness.egg-info/top_level.txt +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/setup.cfg +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_agents_md.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_cli.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_client.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_commands.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_concurrent_subagents.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_config.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_context_rules.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_diffrender.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_filesystem.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_invariants.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_mcp.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_models.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_persistence.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_planmode.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_prompts.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_scenarios.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_session.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_subagent.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_subagent_isolation.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_todos_scope.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_token_estimator.py +0 -0
- {python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_tools_misc.py +0 -0
{python_agent_harness-1.5.5.4/python_agent_harness.egg-info → python_agent_harness-1.5.5.5}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-agent-harness
|
|
3
|
-
Version: 1.5.5.
|
|
3
|
+
Version: 1.5.5.5
|
|
4
4
|
Summary: A lightweight, hackable mini-OpenCode written in Python.
|
|
5
5
|
Author-email: Huming Chen <chenhuming@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -243,13 +243,32 @@ Custom commands from `prompts/commands/*.md` are registered as slash commands as
|
|
|
243
243
|
|
|
244
244
|
Agent prompt files are markdown files (`.md`) placed in the `prompts/agents/` directory. Each file becomes a switchable agent profile available via the `/agent` TUI command.
|
|
245
245
|
|
|
246
|
+
An agent file may carry YAML frontmatter with two optional keys:
|
|
247
|
+
|
|
248
|
+
- `name:` — override the agent name (defaults to the file stem)
|
|
249
|
+
- `exclude_tools:` — a list of tool names the agent must not see. An entry matches a tool by exact name, glob pattern (`mcp__git__*`), or `__`-delimited prefix (`mcp__git` hides `mcp__git__list_repos` but `Write` does NOT hide `TodoWrite`). The built-in `default` agent always sees all tools.
|
|
250
|
+
|
|
251
|
+
```markdown
|
|
252
|
+
---
|
|
253
|
+
name: assistant
|
|
254
|
+
exclude_tools:
|
|
255
|
+
- Bash
|
|
256
|
+
- Edit
|
|
257
|
+
- Write
|
|
258
|
+
- mcp__git__*
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
# Role and Behavior
|
|
262
|
+
You are a personal assistant. You do NOT modify files or run shell commands.
|
|
263
|
+
```
|
|
264
|
+
|
|
246
265
|
#### Commands vs Agents
|
|
247
266
|
|
|
248
267
|
| | Commands (`/review`) | Agents (`/agent reviewer`) |
|
|
249
268
|
|---|---|---|
|
|
250
269
|
| **Scope** | One-shot (prompt resets after run) | Persistent (stays until next `/agent`) |
|
|
251
270
|
| **Kickoff** | Hardcoded kickoff message | User types their own prompt |
|
|
252
|
-
| **Tools** | Can restrict (`allow_planexit=False`) | All tools |
|
|
271
|
+
| **Tools** | Can restrict (`allow_planexit=False`) | All tools, minus the agent's `exclude_tools` |
|
|
253
272
|
| **Ctrl-C** | Restores to default prompt | Stays on the custom agent |
|
|
254
273
|
|
|
255
274
|
## Project layout
|
|
@@ -209,13 +209,32 @@ Custom commands from `prompts/commands/*.md` are registered as slash commands as
|
|
|
209
209
|
|
|
210
210
|
Agent prompt files are markdown files (`.md`) placed in the `prompts/agents/` directory. Each file becomes a switchable agent profile available via the `/agent` TUI command.
|
|
211
211
|
|
|
212
|
+
An agent file may carry YAML frontmatter with two optional keys:
|
|
213
|
+
|
|
214
|
+
- `name:` — override the agent name (defaults to the file stem)
|
|
215
|
+
- `exclude_tools:` — a list of tool names the agent must not see. An entry matches a tool by exact name, glob pattern (`mcp__git__*`), or `__`-delimited prefix (`mcp__git` hides `mcp__git__list_repos` but `Write` does NOT hide `TodoWrite`). The built-in `default` agent always sees all tools.
|
|
216
|
+
|
|
217
|
+
```markdown
|
|
218
|
+
---
|
|
219
|
+
name: assistant
|
|
220
|
+
exclude_tools:
|
|
221
|
+
- Bash
|
|
222
|
+
- Edit
|
|
223
|
+
- Write
|
|
224
|
+
- mcp__git__*
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
# Role and Behavior
|
|
228
|
+
You are a personal assistant. You do NOT modify files or run shell commands.
|
|
229
|
+
```
|
|
230
|
+
|
|
212
231
|
#### Commands vs Agents
|
|
213
232
|
|
|
214
233
|
| | Commands (`/review`) | Agents (`/agent reviewer`) |
|
|
215
234
|
|---|---|---|
|
|
216
235
|
| **Scope** | One-shot (prompt resets after run) | Persistent (stays until next `/agent`) |
|
|
217
236
|
| **Kickoff** | Hardcoded kickoff message | User types their own prompt |
|
|
218
|
-
| **Tools** | Can restrict (`allow_planexit=False`) | All tools |
|
|
237
|
+
| **Tools** | Can restrict (`allow_planexit=False`) | All tools, minus the agent's `exclude_tools` |
|
|
219
238
|
| **Ctrl-C** | Restores to default prompt | Stays on the custom agent |
|
|
220
239
|
|
|
221
240
|
## Project layout
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-agent-harness"
|
|
7
|
-
version = "1.5.5.
|
|
7
|
+
version = "1.5.5.5"
|
|
8
8
|
description = "A lightweight, hackable mini-OpenCode written in Python."
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Huming Chen", email = "chenhuming@gmail.com"}
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts.py
RENAMED
|
@@ -35,7 +35,7 @@ def read_prompt_file(name: str) -> str:
|
|
|
35
35
|
return path.read_text(encoding="utf-8")
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
_FRONTMATTER_RE = re.compile(r"\A---\n.*?\n---\n?", re.DOTALL)
|
|
38
|
+
_FRONTMATTER_RE = re.compile(r"\A---\r?\n.*?\r?\n---\r?\n?", re.DOTALL)
|
|
39
39
|
_SKILLS_PLACEHOLDER_RE = re.compile(r"\{\{\s*SKILLS\s*\}\}")
|
|
40
40
|
_SKILLS_FALLBACK = (
|
|
41
41
|
"Invoke with a skill name and optional args; the tool reports an "
|
|
@@ -509,30 +509,78 @@ def compacted_messages(summary: str, prompts: list[str]) -> list[Message]:
|
|
|
509
509
|
# ``prompts/agents/``. Each file becomes a switchable agent profile
|
|
510
510
|
# available via the ``/agent`` TUI command. The file's stem (e.g.
|
|
511
511
|
# ``reviewer.md`` → ``reviewer``) is the agent name; an optional YAML
|
|
512
|
-
# frontmatter ``name:`` can override it
|
|
513
|
-
#
|
|
514
|
-
#
|
|
512
|
+
# frontmatter ``name:`` can override it, and an optional
|
|
513
|
+
# ``exclude_tools:`` list restricts which tools the agent sees (an
|
|
514
|
+
# entry matches by exact name, glob pattern, or ``__``-delimited
|
|
515
|
+
# prefix, e.g. ``mcp__git`` or ``mcp__git__*``). The built-in
|
|
516
|
+
# ``default`` agent (``prompts/agent.md``) is always available and
|
|
517
|
+
# cannot be overridden by a file in this directory.
|
|
515
518
|
|
|
516
519
|
|
|
517
|
-
def
|
|
518
|
-
"""
|
|
519
|
-
|
|
520
|
+
def _agent_frontmatter(path: Path) -> dict[str, Any]:
|
|
521
|
+
"""Parse the YAML frontmatter of an agent prompt file.
|
|
522
|
+
|
|
523
|
+
Supports ``name:`` (string) and ``exclude_tools:`` (a YAML list —
|
|
524
|
+
either block form with ``- item`` lines or inline ``[a, b]``).
|
|
525
|
+
Unknown keys are ignored; a missing or unreadable frontmatter
|
|
526
|
+
yields an empty dict.
|
|
527
|
+
"""
|
|
520
528
|
try:
|
|
521
529
|
text = path.read_text(encoding="utf-8", errors="replace")
|
|
522
530
|
except OSError:
|
|
523
|
-
return
|
|
531
|
+
return {}
|
|
524
532
|
m = _FRONTMATTER_RE.match(text)
|
|
525
|
-
if m:
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
533
|
+
if not m:
|
|
534
|
+
return {}
|
|
535
|
+
data: dict[str, Any] = {}
|
|
536
|
+
lines = m.group(0).splitlines()
|
|
537
|
+
i = 0
|
|
538
|
+
while i < len(lines):
|
|
539
|
+
line = lines[i]
|
|
540
|
+
if line.startswith("name:"):
|
|
541
|
+
data["name"] = line[len("name:") :].strip()
|
|
542
|
+
elif line.startswith("exclude_tools:"):
|
|
543
|
+
rest = line[len("exclude_tools:") :].strip()
|
|
544
|
+
tools: list[str] = []
|
|
545
|
+
if rest.startswith("[") and rest.endswith("]"):
|
|
546
|
+
tools = [
|
|
547
|
+
item.strip().strip("'\"") for item in rest[1:-1].split(",") if item.strip()
|
|
548
|
+
]
|
|
549
|
+
else:
|
|
550
|
+
j = i + 1
|
|
551
|
+
while j < len(lines) and lines[j].lstrip().startswith("- "):
|
|
552
|
+
tools.append(lines[j].lstrip()[2:].strip().strip("'\""))
|
|
553
|
+
j += 1
|
|
554
|
+
i = j - 1
|
|
555
|
+
data["exclude_tools"] = tools
|
|
556
|
+
i += 1
|
|
557
|
+
return data
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
def _agent_name_from_file(path: Path) -> str:
|
|
561
|
+
"""Derive agent name from a file: frontmatter ``name:`` if present,
|
|
562
|
+
otherwise the file stem (lowercased, non-alphanumerics → ``-``)."""
|
|
563
|
+
name = _agent_frontmatter(path).get("name", "")
|
|
564
|
+
if name:
|
|
565
|
+
return name
|
|
531
566
|
base = path.stem.lower()
|
|
532
567
|
base = re.sub(r"[^a-z0-9]+", "-", base)
|
|
533
568
|
return base.strip("-")
|
|
534
569
|
|
|
535
570
|
|
|
571
|
+
def agent_exclude_tools(path: Path | str) -> tuple[str, ...]:
|
|
572
|
+
"""Tool name substrings/patterns the agent profile excludes.
|
|
573
|
+
|
|
574
|
+
Reads the ``exclude_tools:`` frontmatter list of an agent prompt
|
|
575
|
+
file. An entry matches a tool by exact name, glob pattern
|
|
576
|
+
(``mcp__git__*``), or ``__``-delimited prefix (``mcp__git`` hides
|
|
577
|
+
``mcp__git__list_repos``); matching happens in
|
|
578
|
+
``Session.tool_specs``. Returns an empty tuple when the key is
|
|
579
|
+
absent.
|
|
580
|
+
"""
|
|
581
|
+
return tuple(_agent_frontmatter(Path(path)).get("exclude_tools", ()))
|
|
582
|
+
|
|
583
|
+
|
|
536
584
|
def discover_agents() -> dict[str, str]:
|
|
537
585
|
"""Discover all custom agents in the ``prompts/agents/`` directory.
|
|
538
586
|
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/session.py
RENAMED
|
@@ -9,6 +9,7 @@ provide interactive confirmations.
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import contextlib
|
|
12
|
+
import fnmatch
|
|
12
13
|
import os
|
|
13
14
|
import threading
|
|
14
15
|
import time
|
|
@@ -31,6 +32,21 @@ from .tools.filesystem import cleanup_spooled_files
|
|
|
31
32
|
from .tools.mcp import mcp_tools_from_manager
|
|
32
33
|
|
|
33
34
|
|
|
35
|
+
def _tool_excluded(pattern: str, name: str) -> bool:
|
|
36
|
+
"""True when *pattern* excludes tool *name*.
|
|
37
|
+
|
|
38
|
+
A pattern matches when it is the exact tool name, a glob pattern
|
|
39
|
+
(``mcp__git__*``), or a prefix delimited by ``__`` (``mcp__git``
|
|
40
|
+
hides ``mcp__git__list_repos`` but ``Write`` does NOT hide
|
|
41
|
+
``TodoWrite``).
|
|
42
|
+
"""
|
|
43
|
+
if "*" in pattern:
|
|
44
|
+
return fnmatch.fnmatchcase(name, pattern)
|
|
45
|
+
if pattern == name:
|
|
46
|
+
return True
|
|
47
|
+
return name.startswith(pattern + "__")
|
|
48
|
+
|
|
49
|
+
|
|
34
50
|
def find_skill_dir(project_dir: str, configured: str | None = None) -> str | None:
|
|
35
51
|
"""Locate the skill directory.
|
|
36
52
|
|
|
@@ -201,6 +217,11 @@ class Session:
|
|
|
201
217
|
# Original system prompt assembled at session start — used by
|
|
202
218
|
# /agent default to restore the original agent.md prompt.
|
|
203
219
|
self._default_system_prompt = system_prompt
|
|
220
|
+
# Tool exclusions from the active agent profile's
|
|
221
|
+
# ``exclude_tools`` frontmatter (substrings or glob patterns).
|
|
222
|
+
# The built-in default agent excludes nothing; switch_agent
|
|
223
|
+
# replaces this tuple when a custom agent is activated.
|
|
224
|
+
self._agent_excluded_tools: tuple[str, ...] = ()
|
|
204
225
|
# Monotonic cancel identity: cancel() bumps this counter, so a
|
|
205
226
|
# worker from a cancelled run can tell it was cancelled even
|
|
206
227
|
# after the next run clears the shared event.
|
|
@@ -251,9 +272,26 @@ class Session:
|
|
|
251
272
|
# tools
|
|
252
273
|
# ------------------------------------------------------------------
|
|
253
274
|
def tool_specs(self, exclude: tuple[str, ...] = ()) -> list:
|
|
254
|
-
"""Tool specs exposed to the model
|
|
255
|
-
|
|
256
|
-
|
|
275
|
+
"""Tool specs exposed to the model.
|
|
276
|
+
|
|
277
|
+
``exclude`` drops tools by name (e.g. one-shot/interactive tools
|
|
278
|
+
for sub-agent runs). The active agent profile's own
|
|
279
|
+
``exclude_tools`` frontmatter is applied on top: an entry
|
|
280
|
+
matches a tool by exact name, glob pattern (``mcp__git__*``),
|
|
281
|
+
or ``__``-delimited prefix (``mcp__git`` hides
|
|
282
|
+
``mcp__git__list_repos`` but ``Write`` does NOT hide
|
|
283
|
+
``TodoWrite``).
|
|
284
|
+
"""
|
|
285
|
+
excluded = set(exclude)
|
|
286
|
+
specs = self.registry.specs()
|
|
287
|
+
patterns = self._agent_excluded_tools
|
|
288
|
+
if not patterns:
|
|
289
|
+
return [spec for spec in specs if spec.name not in excluded]
|
|
290
|
+
return [
|
|
291
|
+
spec
|
|
292
|
+
for spec in specs
|
|
293
|
+
if spec.name not in excluded and not any(_tool_excluded(p, spec.name) for p in patterns)
|
|
294
|
+
]
|
|
257
295
|
|
|
258
296
|
def execute_tool(
|
|
259
297
|
self, name: str, args: dict[str, Any], call_id: str | None = None
|
|
@@ -738,6 +776,7 @@ class Session:
|
|
|
738
776
|
self.system_prompt = self._default_system_prompt
|
|
739
777
|
self.store.system_prompt = self._default_system_prompt
|
|
740
778
|
self.store.agent = None
|
|
779
|
+
self._agent_excluded_tools = ()
|
|
741
780
|
return True, "switched to default agent"
|
|
742
781
|
|
|
743
782
|
agents = discover_agents()
|
|
@@ -745,11 +784,12 @@ class Session:
|
|
|
745
784
|
if prompt_file is None:
|
|
746
785
|
available = ", ".join(sorted([RESERVED_AGENT_NAME, *agents.keys()]))
|
|
747
786
|
return False, f"unknown agent: {name} (available: {available})"
|
|
748
|
-
from .prompts import assemble_agent_prompt, load_agent_prompt
|
|
787
|
+
from .prompts import agent_exclude_tools, assemble_agent_prompt, load_agent_prompt
|
|
749
788
|
|
|
750
789
|
agent_prompt = load_agent_prompt(prompt_file, skill_dir=self._skill_dir)
|
|
751
790
|
if agent_prompt is None:
|
|
752
791
|
return False, f"agent {name}: prompt file not found or empty: {prompt_file}"
|
|
792
|
+
new_exclusions = agent_exclude_tools(prompt_file)
|
|
753
793
|
self.system_prompt = assemble_agent_prompt(
|
|
754
794
|
self.project_dir,
|
|
755
795
|
agent_prompt,
|
|
@@ -757,6 +797,7 @@ class Session:
|
|
|
757
797
|
)
|
|
758
798
|
self.store.system_prompt = self.system_prompt
|
|
759
799
|
self.store.agent = name
|
|
800
|
+
self._agent_excluded_tools = new_exclusions
|
|
760
801
|
return True, f"switched to {name}"
|
|
761
802
|
|
|
762
803
|
# ------------------------------------------------------------------
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tui/commands.py
RENAMED
|
@@ -650,6 +650,9 @@ class CommandMixin:
|
|
|
650
650
|
if success:
|
|
651
651
|
self.console.print(f"[green]{msg}[/green]")
|
|
652
652
|
else:
|
|
653
|
+
# Agent no longer exists: reset to default to avoid
|
|
654
|
+
# stale exclusions from the previously active agent
|
|
655
|
+
self.session.switch_agent("default")
|
|
653
656
|
self.console.print(f"[yellow]warning: {msg}[/yellow]")
|
|
654
657
|
except Exception as e:
|
|
655
658
|
self.console.print(f"[yellow]warning: could not restore agent: {e}[/yellow]")
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5/python_agent_harness.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-agent-harness
|
|
3
|
-
Version: 1.5.5.
|
|
3
|
+
Version: 1.5.5.5
|
|
4
4
|
Summary: A lightweight, hackable mini-OpenCode written in Python.
|
|
5
5
|
Author-email: Huming Chen <chenhuming@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -243,13 +243,32 @@ Custom commands from `prompts/commands/*.md` are registered as slash commands as
|
|
|
243
243
|
|
|
244
244
|
Agent prompt files are markdown files (`.md`) placed in the `prompts/agents/` directory. Each file becomes a switchable agent profile available via the `/agent` TUI command.
|
|
245
245
|
|
|
246
|
+
An agent file may carry YAML frontmatter with two optional keys:
|
|
247
|
+
|
|
248
|
+
- `name:` — override the agent name (defaults to the file stem)
|
|
249
|
+
- `exclude_tools:` — a list of tool names the agent must not see. An entry matches a tool by exact name, glob pattern (`mcp__git__*`), or `__`-delimited prefix (`mcp__git` hides `mcp__git__list_repos` but `Write` does NOT hide `TodoWrite`). The built-in `default` agent always sees all tools.
|
|
250
|
+
|
|
251
|
+
```markdown
|
|
252
|
+
---
|
|
253
|
+
name: assistant
|
|
254
|
+
exclude_tools:
|
|
255
|
+
- Bash
|
|
256
|
+
- Edit
|
|
257
|
+
- Write
|
|
258
|
+
- mcp__git__*
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
# Role and Behavior
|
|
262
|
+
You are a personal assistant. You do NOT modify files or run shell commands.
|
|
263
|
+
```
|
|
264
|
+
|
|
246
265
|
#### Commands vs Agents
|
|
247
266
|
|
|
248
267
|
| | Commands (`/review`) | Agents (`/agent reviewer`) |
|
|
249
268
|
|---|---|---|
|
|
250
269
|
| **Scope** | One-shot (prompt resets after run) | Persistent (stays until next `/agent`) |
|
|
251
270
|
| **Kickoff** | Hardcoded kickoff message | User types their own prompt |
|
|
252
|
-
| **Tools** | Can restrict (`allow_planexit=False`) | All tools |
|
|
271
|
+
| **Tools** | Can restrict (`allow_planexit=False`) | All tools, minus the agent's `exclude_tools` |
|
|
253
272
|
| **Ctrl-C** | Restores to default prompt | Stays on the custom agent |
|
|
254
273
|
|
|
255
274
|
## Project layout
|
|
@@ -387,6 +387,229 @@ class TestMcpFailuresAsStartupWarnings(unittest.TestCase):
|
|
|
387
387
|
os.environ[k] = v
|
|
388
388
|
|
|
389
389
|
|
|
390
|
+
class TestAgentExcludeTools(unittest.TestCase):
|
|
391
|
+
"""Agent profile ``exclude_tools`` frontmatter: parsing and effect
|
|
392
|
+
on the tool specs exposed to the model."""
|
|
393
|
+
|
|
394
|
+
def _write_agent(
|
|
395
|
+
self, name: str, frontmatter: str, body: str = "You are a test agent."
|
|
396
|
+
) -> Path:
|
|
397
|
+
p = AGENTS_DIR / f"{name}.md"
|
|
398
|
+
p.write_text(f"---\n{frontmatter}---\n{body}", encoding="utf-8")
|
|
399
|
+
return p
|
|
400
|
+
|
|
401
|
+
def test_parse_exclude_tools(self):
|
|
402
|
+
"""agent_exclude_tools reads the frontmatter list."""
|
|
403
|
+
from python_agent_harness.prompts import agent_exclude_tools
|
|
404
|
+
|
|
405
|
+
p = self._write_agent(
|
|
406
|
+
"test-exclude-parse",
|
|
407
|
+
"name: test-exclude-parse\nexclude_tools:\n - Bash\n - Edit\n - mcp__git__*\n",
|
|
408
|
+
)
|
|
409
|
+
try:
|
|
410
|
+
self.assertEqual(
|
|
411
|
+
agent_exclude_tools(p),
|
|
412
|
+
("Bash", "Edit", "mcp__git__*"),
|
|
413
|
+
)
|
|
414
|
+
finally:
|
|
415
|
+
p.unlink(missing_ok=True)
|
|
416
|
+
|
|
417
|
+
def test_parse_exclude_tools_inline(self):
|
|
418
|
+
"""agent_exclude_tools reads an inline ``[a, b]`` list too."""
|
|
419
|
+
from python_agent_harness.prompts import agent_exclude_tools
|
|
420
|
+
|
|
421
|
+
p = self._write_agent(
|
|
422
|
+
"test-exclude-inline",
|
|
423
|
+
"name: test-exclude-inline\nexclude_tools: [Bash, mcp__git__*]\n",
|
|
424
|
+
)
|
|
425
|
+
try:
|
|
426
|
+
self.assertEqual(
|
|
427
|
+
agent_exclude_tools(p),
|
|
428
|
+
("Bash", "mcp__git__*"),
|
|
429
|
+
)
|
|
430
|
+
finally:
|
|
431
|
+
p.unlink(missing_ok=True)
|
|
432
|
+
|
|
433
|
+
def test_no_exclude_tools_returns_empty(self):
|
|
434
|
+
"""An agent without the key excludes nothing."""
|
|
435
|
+
from python_agent_harness.prompts import agent_exclude_tools
|
|
436
|
+
|
|
437
|
+
p = self._write_agent("test-exclude-none", "name: test-exclude-none\n")
|
|
438
|
+
try:
|
|
439
|
+
self.assertEqual(agent_exclude_tools(p), ())
|
|
440
|
+
finally:
|
|
441
|
+
p.unlink(missing_ok=True)
|
|
442
|
+
|
|
443
|
+
def test_switch_agent_applies_exclusions(self):
|
|
444
|
+
"""switch_agent activates the profile's excluded tools."""
|
|
445
|
+
p = self._write_agent(
|
|
446
|
+
"test-exclude-switch",
|
|
447
|
+
"name: test-exclude-switch\nexclude_tools:\n - Bash\n - Edit\n",
|
|
448
|
+
)
|
|
449
|
+
try:
|
|
450
|
+
session = _make_session()
|
|
451
|
+
ok, msg = session.switch_agent("test-exclude-switch")
|
|
452
|
+
self.assertTrue(ok, msg)
|
|
453
|
+
names = {s.name for s in session.tool_specs()}
|
|
454
|
+
self.assertNotIn("Bash", names)
|
|
455
|
+
self.assertNotIn("Edit", names)
|
|
456
|
+
self.assertIn("Read", names)
|
|
457
|
+
finally:
|
|
458
|
+
p.unlink(missing_ok=True)
|
|
459
|
+
|
|
460
|
+
def test_switch_to_default_clears_exclusions(self):
|
|
461
|
+
"""/agent default restores the full tool set."""
|
|
462
|
+
p = self._write_agent(
|
|
463
|
+
"test-exclude-default",
|
|
464
|
+
"name: test-exclude-default\nexclude_tools:\n - Bash\n",
|
|
465
|
+
)
|
|
466
|
+
try:
|
|
467
|
+
session = _make_session()
|
|
468
|
+
session.switch_agent("test-exclude-default")
|
|
469
|
+
self.assertNotIn("Bash", {s.name for s in session.tool_specs()})
|
|
470
|
+
ok, msg = session.switch_agent("default")
|
|
471
|
+
self.assertTrue(ok, msg)
|
|
472
|
+
self.assertIn("Bash", {s.name for s in session.tool_specs()})
|
|
473
|
+
finally:
|
|
474
|
+
p.unlink(missing_ok=True)
|
|
475
|
+
|
|
476
|
+
def test_glob_pattern_excludes_mcp_tools(self):
|
|
477
|
+
"""mcp__<server>__* patterns hide every tool of one server."""
|
|
478
|
+
from python_agent_harness.tools.base import Tool
|
|
479
|
+
|
|
480
|
+
class FakeMcpTool(Tool):
|
|
481
|
+
name = "mcp__git__list_repos"
|
|
482
|
+
description = "fake"
|
|
483
|
+
|
|
484
|
+
def run(self, args, ctx):
|
|
485
|
+
return ""
|
|
486
|
+
|
|
487
|
+
p = self._write_agent(
|
|
488
|
+
"test-exclude-glob",
|
|
489
|
+
"name: test-exclude-glob\nexclude_tools:\n - mcp__git__*\n",
|
|
490
|
+
)
|
|
491
|
+
try:
|
|
492
|
+
session = _make_session()
|
|
493
|
+
session.registry.register(FakeMcpTool())
|
|
494
|
+
self.assertIn("mcp__git__list_repos", {s.name for s in session.tool_specs()})
|
|
495
|
+
session.switch_agent("test-exclude-glob")
|
|
496
|
+
names = {s.name for s in session.tool_specs()}
|
|
497
|
+
self.assertNotIn("mcp__git__list_repos", names)
|
|
498
|
+
finally:
|
|
499
|
+
p.unlink(missing_ok=True)
|
|
500
|
+
|
|
501
|
+
def test_substring_pattern_excludes_mcp_tools(self):
|
|
502
|
+
"""A ``__``-delimited prefix (mcp__git) hides every tool of one
|
|
503
|
+
server, but does NOT accidentally match unrelated tools."""
|
|
504
|
+
from python_agent_harness.tools.base import Tool
|
|
505
|
+
|
|
506
|
+
class FakeMcpTool(Tool):
|
|
507
|
+
name = "mcp__git__list_repos"
|
|
508
|
+
description = "fake"
|
|
509
|
+
|
|
510
|
+
def run(self, args, ctx):
|
|
511
|
+
return ""
|
|
512
|
+
|
|
513
|
+
p = self._write_agent(
|
|
514
|
+
"test-exclude-substr",
|
|
515
|
+
"name: test-exclude-substr\nexclude_tools:\n - mcp__git\n",
|
|
516
|
+
)
|
|
517
|
+
try:
|
|
518
|
+
session = _make_session()
|
|
519
|
+
session.registry.register(FakeMcpTool())
|
|
520
|
+
self.assertIn("mcp__git__list_repos", {s.name for s in session.tool_specs()})
|
|
521
|
+
session.switch_agent("test-exclude-substr")
|
|
522
|
+
names = {s.name for s in session.tool_specs()}
|
|
523
|
+
self.assertNotIn("mcp__git__list_repos", names)
|
|
524
|
+
finally:
|
|
525
|
+
p.unlink(missing_ok=True)
|
|
526
|
+
|
|
527
|
+
def test_write_does_not_exclude_todowrite(self):
|
|
528
|
+
"""``Write`` must not accidentally hide ``TodoWrite``: matching
|
|
529
|
+
is by exact name or ``__``-delimited prefix, not raw substring."""
|
|
530
|
+
p = self._write_agent(
|
|
531
|
+
"test-exclude-no-false-match",
|
|
532
|
+
"name: test-exclude-no-false-match\nexclude_tools:\n - Write\n",
|
|
533
|
+
)
|
|
534
|
+
try:
|
|
535
|
+
session = _make_session()
|
|
536
|
+
session.switch_agent("test-exclude-no-false-match")
|
|
537
|
+
names = {s.name for s in session.tool_specs()}
|
|
538
|
+
self.assertNotIn("Write", names)
|
|
539
|
+
self.assertIn("TodoWrite", names)
|
|
540
|
+
finally:
|
|
541
|
+
p.unlink(missing_ok=True)
|
|
542
|
+
|
|
543
|
+
def test_explicit_exclude_still_works(self):
|
|
544
|
+
"""The caller's exclude argument composes with the profile's."""
|
|
545
|
+
p = self._write_agent(
|
|
546
|
+
"test-exclude-compose",
|
|
547
|
+
"name: test-exclude-compose\nexclude_tools:\n - Bash\n",
|
|
548
|
+
)
|
|
549
|
+
try:
|
|
550
|
+
session = _make_session()
|
|
551
|
+
session.switch_agent("test-exclude-compose")
|
|
552
|
+
names = {s.name for s in session.tool_specs(exclude=("Edit",))}
|
|
553
|
+
self.assertNotIn("Bash", names)
|
|
554
|
+
self.assertNotIn("Edit", names)
|
|
555
|
+
finally:
|
|
556
|
+
p.unlink(missing_ok=True)
|
|
557
|
+
|
|
558
|
+
def test_failed_switch_leaves_exclusions_untouched(self):
|
|
559
|
+
"""A failed switch (unknown name) must not change the active
|
|
560
|
+
exclusions: the caller's tool set must never silently shift."""
|
|
561
|
+
p = self._write_agent(
|
|
562
|
+
"test-exclude-fail",
|
|
563
|
+
"name: test-exclude-fail\nexclude_tools:\n - Bash\n",
|
|
564
|
+
)
|
|
565
|
+
try:
|
|
566
|
+
session = _make_session()
|
|
567
|
+
session.switch_agent("test-exclude-fail")
|
|
568
|
+
self.assertNotIn("Bash", {s.name for s in session.tool_specs()})
|
|
569
|
+
ok, _ = session.switch_agent("nonexistent")
|
|
570
|
+
self.assertFalse(ok)
|
|
571
|
+
self.assertNotIn("Bash", {s.name for s in session.tool_specs()})
|
|
572
|
+
finally:
|
|
573
|
+
p.unlink(missing_ok=True)
|
|
574
|
+
|
|
575
|
+
def test_quoted_items_stripped(self):
|
|
576
|
+
"""Quoted frontmatter items lose their quotes during parsing."""
|
|
577
|
+
from python_agent_harness.prompts import agent_exclude_tools
|
|
578
|
+
|
|
579
|
+
p = self._write_agent(
|
|
580
|
+
"test-exclude-quoted",
|
|
581
|
+
"name: test-exclude-quoted\nexclude_tools:\n - \"Bash\"\n - 'Edit'\n",
|
|
582
|
+
)
|
|
583
|
+
try:
|
|
584
|
+
self.assertEqual(agent_exclude_tools(p), ("Bash", "Edit"))
|
|
585
|
+
finally:
|
|
586
|
+
p.unlink(missing_ok=True)
|
|
587
|
+
|
|
588
|
+
def test_no_frontmatter_at_all(self):
|
|
589
|
+
"""A file with no frontmatter block excludes nothing."""
|
|
590
|
+
from python_agent_harness.prompts import agent_exclude_tools
|
|
591
|
+
|
|
592
|
+
p = self._write_agent("test-no-frontmatter", "")
|
|
593
|
+
p.write_text("You are a simple agent with no frontmatter.", encoding="utf-8")
|
|
594
|
+
try:
|
|
595
|
+
self.assertEqual(agent_exclude_tools(p), ())
|
|
596
|
+
finally:
|
|
597
|
+
p.unlink(missing_ok=True)
|
|
598
|
+
|
|
599
|
+
def test_crlf_line_endings(self):
|
|
600
|
+
"""CRLF line endings must not break frontmatter parsing."""
|
|
601
|
+
from python_agent_harness.prompts import agent_exclude_tools
|
|
602
|
+
|
|
603
|
+
p = AGENTS_DIR / "test-crlf-agent.md"
|
|
604
|
+
p.write_bytes(
|
|
605
|
+
b"---\r\nname: test-crlf-agent\r\nexclude_tools:\r\n - Bash\r\n - Edit\r\n---\r\nYou are a CRLF agent.\r\n"
|
|
606
|
+
)
|
|
607
|
+
try:
|
|
608
|
+
self.assertEqual(agent_exclude_tools(p), ("Bash", "Edit"))
|
|
609
|
+
finally:
|
|
610
|
+
p.unlink(missing_ok=True)
|
|
611
|
+
|
|
612
|
+
|
|
390
613
|
class TestReviewerAgentContent(unittest.TestCase):
|
|
391
614
|
"""Verify the bundled reviewer.md agent has expected content."""
|
|
392
615
|
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/client.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/commands.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/config.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/diffrender.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/mcp/__init__.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/mcp/client.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/mcp/config.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/mcp/manager.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/models.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/persistence.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/planmode.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/agent.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/plan.md
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/review.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/prompts/title.md
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/subagent.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tool_runner.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/base.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/bash.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/bash_win.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/edit.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/edit_mac.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/edit_win.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/glob.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/glob_mac.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/glob_win.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/grep.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/grep_mac.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/grep_win.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/insert.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/mcp.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/mkdir.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/planexit.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/question.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/read.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/skill.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/todo.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tools/write.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tui/__init__.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tui/core.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tui/input.py
RENAMED
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/python_agent_harness/tui/render.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_concurrent_subagents.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_agent_harness-1.5.5.4 → python_agent_harness-1.5.5.5}/tests/test_subagent_isolation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|