python-agent-harness 1.5.6.3__tar.gz → 1.5.6.4__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.6.3/python_agent_harness.egg-info → python_agent_harness-1.5.6.4}/PKG-INFO +2 -3
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/README.md +1 -2
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/pyproject.toml +1 -1
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/__init__.py +1 -4
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/core/agent.py +14 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/entry/cli.py +0 -13
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/entry/headless.py +3 -4
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/agent.md +1 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/agents/reviewer.md +0 -2
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/session/config.py +0 -38
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/session/session.py +2 -10
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/__init__.py +1 -8
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/base.py +1 -2
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/bash.py +2 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/diffapply.py +1 -1
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/edit.py +4 -1
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/filesystem.py +6 -96
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/grep.py +0 -1
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tui/core.py +1 -1
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tui/render.py +12 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4/python_agent_harness.egg-info}/PKG-INFO +2 -3
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness.egg-info/SOURCES.txt +0 -7
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/tests/test_invariants.py +16 -17
- python_agent_harness-1.5.6.3/python_agent_harness/lsp/__init__.py +0 -14
- python_agent_harness-1.5.6.3/python_agent_harness/lsp/client.py +0 -493
- python_agent_harness-1.5.6.3/python_agent_harness/lsp/config.py +0 -108
- python_agent_harness-1.5.6.3/python_agent_harness/lsp/manager.py +0 -117
- python_agent_harness-1.5.6.3/python_agent_harness/tools/insert.py +0 -87
- python_agent_harness-1.5.6.3/python_agent_harness/tools/lsp.py +0 -287
- python_agent_harness-1.5.6.3/python_agent_harness/tools/mkdir.py +0 -32
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/LICENSE +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/__main__.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/core/__init__.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/core/context_manager.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/core/models.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/core/planmode.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/core/subagent.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/core/token_estimator.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/core/tool_runner.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/entry/__init__.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/entry/controller.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/entry/server.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/entry/view.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/io/__init__.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/io/attachments.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/io/diffrender.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/io/persistence.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/io/text_filter.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/llm/__init__.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/llm/client.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/mcp/__init__.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/mcp/client.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/mcp/config.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/mcp/manager.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/__init__.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/build-switch.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/commands/explain.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/compact.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/core.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/initialize.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/plan-mode.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/plan.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/review.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/subagent.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/summary.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/task-completion-rules.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/title.md +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/session/__init__.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/session/commands.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/agent_tool.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/edit_mac.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/glob.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/glob_mac.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/grep_mac.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/mcp.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/planexit.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/question.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/read.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/skill.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/todo.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/write.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tui/__init__.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tui/commands.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tui/input.py +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness.egg-info/dependency_links.txt +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness.egg-info/entry_points.txt +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness.egg-info/requires.txt +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness.egg-info/top_level.txt +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/setup.cfg +0 -0
- {python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/tests/test_scenarios.py +0 -0
{python_agent_harness-1.5.6.3/python_agent_harness.egg-info → python_agent_harness-1.5.6.4}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-agent-harness
|
|
3
|
-
Version: 1.5.6.
|
|
3
|
+
Version: 1.5.6.4
|
|
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
|
|
@@ -74,7 +74,7 @@ Edit `~/.config/python-agent-harness/config.json` and set your `base_url`, `api_
|
|
|
74
74
|
- **FSM-driven execution** — explicit `WAIT` / `TOOL` / `TRET` / `SUPERVISE` / `DONE` / `ERRS` / `ABRT` states. Completion supervision nudges the model when it stops early; failed tool calls are sanitized. Transient API failures (`429` / `5xx`) retry with exponential backoff. Auth-expired codes (configurable via `AUTH_REFRESH_STATUS_CODES` in `config.py`; defaults to `[401, 502]`) trigger automatic API key re-read from config/env.
|
|
75
75
|
- **Context management** — CJK-aware token estimation, per-model context windows, automatic compaction at 70% usage.
|
|
76
76
|
- **Image & text attachments** — attach with `@path` (e.g. `@screenshot.png`, `@README.md`): images (PNG/JPEG/GIF/WebP, up to 20 MB) become multimodal `image_url` parts; text files are inlined. Web URLs supported for images.
|
|
77
|
-
- **Coding tools** — `Agent`, `TodoWrite`, `Glob`, `Grep`, `Read`, `
|
|
77
|
+
- **Coding tools** — `Agent`, `TodoWrite`, `Glob`, `Grep`, `Read`, `Edit` (incl. unified diffs), `Write`, `Bash`, `Skill`, `Question`, `PlanExit`. Read-only tool rounds (`Read`, `Glob`, `Grep`, `Skill`) dispatch concurrently; async tools (`Bash`, `Agent`) can also run concurrently. Results always delivered in emitted order.
|
|
78
78
|
- **Plan / Build modes** — plan mode is read-only except for the per-session plan file.
|
|
79
79
|
- **Persistent sessions** — auto-saved after every response to `~/.local/share/python-agent-harness/sessions/`, with LLM-generated titles and `/restore --latest` / `/sessions`.
|
|
80
80
|
- **Focused TUI** — Rich-based with pinned status bar, Todos panel, inline diff rendering, and a `prompt_toolkit` editor with history and completion. `Esc+Enter` submits, `Ctrl-D` quits, `Ctrl-C` cancels.
|
|
@@ -191,7 +191,6 @@ All LLM settings live in `~/.config/python-agent-harness/config.json`. Environme
|
|
|
191
191
|
- **`subagent_llm`** — LLM config for `Agent` tool. Unset values inherit from `llm`. Set `profile` to reuse a `models` entry. Precedence: profile > `subagent_llm` > `llm` > env vars.
|
|
192
192
|
- **`default_agent`** — agent name to use at session start (must exist in `prompts/agents/`). `null` = built-in default.
|
|
193
193
|
- **`paths.context_path` / `paths.skill_path`** — locations for context files and skills. Default: project-local `contexts/` and `skills/`.
|
|
194
|
-
- **`lsp.servers`** — per-extension LSP server overrides for the `LSP` tool. Keys are extensions (`.py`, `.cpp`); each has `command` (argv) and optional `language_id`. Layers on top of `DEFAULT_SERVERS` in `lsp/manager.py`.
|
|
195
194
|
- **`mcp.servers`** — MCP server config (requires `[mcp]` extra). Each supports `transport`, `command`, `args`, `env`, `url`, `headers`, `parallel`, `timeout`, `enabled`.
|
|
196
195
|
- **`headless` / `serve`** — optional budget limits: `max_rounds` (LLM rounds) and `timeout` (wall-clock seconds). `--max-rounds` / `--timeout` override per call; `<= 0` or `null` disables. Unset = unlimited.
|
|
197
196
|
- **Precedence** — code defaults < config file < `OPENAI_*` env vars. Sub-agents also support `OPENAI_SUBAGENT_*` (`_BASE_URL`, `_API_KEY`, `_MODEL`).
|
|
@@ -40,7 +40,7 @@ Edit `~/.config/python-agent-harness/config.json` and set your `base_url`, `api_
|
|
|
40
40
|
- **FSM-driven execution** — explicit `WAIT` / `TOOL` / `TRET` / `SUPERVISE` / `DONE` / `ERRS` / `ABRT` states. Completion supervision nudges the model when it stops early; failed tool calls are sanitized. Transient API failures (`429` / `5xx`) retry with exponential backoff. Auth-expired codes (configurable via `AUTH_REFRESH_STATUS_CODES` in `config.py`; defaults to `[401, 502]`) trigger automatic API key re-read from config/env.
|
|
41
41
|
- **Context management** — CJK-aware token estimation, per-model context windows, automatic compaction at 70% usage.
|
|
42
42
|
- **Image & text attachments** — attach with `@path` (e.g. `@screenshot.png`, `@README.md`): images (PNG/JPEG/GIF/WebP, up to 20 MB) become multimodal `image_url` parts; text files are inlined. Web URLs supported for images.
|
|
43
|
-
- **Coding tools** — `Agent`, `TodoWrite`, `Glob`, `Grep`, `Read`, `
|
|
43
|
+
- **Coding tools** — `Agent`, `TodoWrite`, `Glob`, `Grep`, `Read`, `Edit` (incl. unified diffs), `Write`, `Bash`, `Skill`, `Question`, `PlanExit`. Read-only tool rounds (`Read`, `Glob`, `Grep`, `Skill`) dispatch concurrently; async tools (`Bash`, `Agent`) can also run concurrently. Results always delivered in emitted order.
|
|
44
44
|
- **Plan / Build modes** — plan mode is read-only except for the per-session plan file.
|
|
45
45
|
- **Persistent sessions** — auto-saved after every response to `~/.local/share/python-agent-harness/sessions/`, with LLM-generated titles and `/restore --latest` / `/sessions`.
|
|
46
46
|
- **Focused TUI** — Rich-based with pinned status bar, Todos panel, inline diff rendering, and a `prompt_toolkit` editor with history and completion. `Esc+Enter` submits, `Ctrl-D` quits, `Ctrl-C` cancels.
|
|
@@ -157,7 +157,6 @@ All LLM settings live in `~/.config/python-agent-harness/config.json`. Environme
|
|
|
157
157
|
- **`subagent_llm`** — LLM config for `Agent` tool. Unset values inherit from `llm`. Set `profile` to reuse a `models` entry. Precedence: profile > `subagent_llm` > `llm` > env vars.
|
|
158
158
|
- **`default_agent`** — agent name to use at session start (must exist in `prompts/agents/`). `null` = built-in default.
|
|
159
159
|
- **`paths.context_path` / `paths.skill_path`** — locations for context files and skills. Default: project-local `contexts/` and `skills/`.
|
|
160
|
-
- **`lsp.servers`** — per-extension LSP server overrides for the `LSP` tool. Keys are extensions (`.py`, `.cpp`); each has `command` (argv) and optional `language_id`. Layers on top of `DEFAULT_SERVERS` in `lsp/manager.py`.
|
|
161
160
|
- **`mcp.servers`** — MCP server config (requires `[mcp]` extra). Each supports `transport`, `command`, `args`, `env`, `url`, `headers`, `parallel`, `timeout`, `enabled`.
|
|
162
161
|
- **`headless` / `serve`** — optional budget limits: `max_rounds` (LLM rounds) and `timeout` (wall-clock seconds). `--max-rounds` / `--timeout` override per call; `<= 0` or `null` disables. Unset = unlimited.
|
|
163
162
|
- **Precedence** — code defaults < config file < `OPENAI_*` env vars. Sub-agents also support `OPENAI_SUBAGENT_*` (`_BASE_URL`, `_API_KEY`, `_MODEL`).
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-agent-harness"
|
|
7
|
-
version = "1.5.6.
|
|
7
|
+
version = "1.5.6.4"
|
|
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.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/__init__.py
RENAMED
|
@@ -3,20 +3,17 @@
|
|
|
3
3
|
from .core.models import AgentMode, ImagePart, Message, TextPart, ToolCall, ToolSpec
|
|
4
4
|
from .entry.cli import main # noqa: F401 (public lib surface: main entry point)
|
|
5
5
|
from .llm.client import Client, LLMClient
|
|
6
|
-
from .lsp.config import LSPConfig, LSPServerConfig
|
|
7
6
|
from .mcp.config import MCPConfig, MCPServerConfig
|
|
8
7
|
from .mcp.manager import MCPManager
|
|
9
8
|
from .session.session import Session
|
|
10
9
|
|
|
11
|
-
__version__ = "1.5.6.
|
|
10
|
+
__version__ = "1.5.6.4"
|
|
12
11
|
|
|
13
12
|
__all__ = [
|
|
14
13
|
"Client",
|
|
15
14
|
"LLMClient",
|
|
16
15
|
"Session",
|
|
17
16
|
"AgentMode",
|
|
18
|
-
"LSPConfig",
|
|
19
|
-
"LSPServerConfig",
|
|
20
17
|
"MCPConfig",
|
|
21
18
|
"MCPManager",
|
|
22
19
|
"MCPServerConfig",
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/core/agent.py
RENAMED
|
@@ -552,6 +552,20 @@ class AgentLoop:
|
|
|
552
552
|
self._just_compacted = True
|
|
553
553
|
self.info["compacted"] = True
|
|
554
554
|
return
|
|
555
|
+
# Compaction failed (empty summary, no reducible
|
|
556
|
+
# prompts, or an exception -- see ContextManager.
|
|
557
|
+
# compact): the history is unchanged, so without a
|
|
558
|
+
# guard the next WAIT round sees the same
|
|
559
|
+
# above-trigger ratio and compacts again, re-billing
|
|
560
|
+
# the summary request every round for nothing.
|
|
561
|
+
# Remember the current ratio as the floor -- reusing
|
|
562
|
+
# the same mechanism as the "still above trigger
|
|
563
|
+
# after a successful compaction" case above -- so
|
|
564
|
+
# the guard below suppresses re-compaction until the
|
|
565
|
+
# context grows meaningfully past it, at which point
|
|
566
|
+
# a retry is warranted (the conversation really did
|
|
567
|
+
# grow) rather than a no-op loop.
|
|
568
|
+
self._compaction_floor = ratio
|
|
555
569
|
else:
|
|
556
570
|
self._compaction_floor = None
|
|
557
571
|
self._just_compacted = False
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/entry/cli.py
RENAMED
|
@@ -45,11 +45,6 @@ def make_session(
|
|
|
45
45
|
settings = config.load_llm_config(config_path)
|
|
46
46
|
paths = config.load_paths_config(config_path)
|
|
47
47
|
mcp_config = config.load_mcp_config(config_path)
|
|
48
|
-
# Validate lsp.servers eagerly so a malformed override fails fast at
|
|
49
|
-
# session start (with a clear message) instead of poisoning the first
|
|
50
|
-
# LSP tool call mid-session. The LSP manager re-reads it lazily via
|
|
51
|
-
# config_path; this call only surfaces config errors early.
|
|
52
|
-
config.load_lsp_config(config_path)
|
|
53
48
|
model = model or settings["model"]
|
|
54
49
|
# resolve sub-agent overrides against the EFFECTIVE main settings
|
|
55
50
|
# (so a CLI/caller model override is inherited too when the
|
|
@@ -345,14 +340,6 @@ def cmd_config(args: argparse.Namespace) -> int:
|
|
|
345
340
|
print(f" {pattern}: {size}")
|
|
346
341
|
else:
|
|
347
342
|
print("context_windows: (none configured — built-in table in config.py applies)")
|
|
348
|
-
# Show LSP server overrides (per-extension, layered over the built-ins)
|
|
349
|
-
lsp_config = config.load_lsp_config(args.path)
|
|
350
|
-
if lsp_config.servers:
|
|
351
|
-
print("lsp servers:")
|
|
352
|
-
for ext, server in sorted(lsp_config.servers.items()):
|
|
353
|
-
print(f" {ext}: language_id={server.language_id}, command={' '.join(server.command)}")
|
|
354
|
-
else:
|
|
355
|
-
print("lsp servers: (none configured — built-in DEFAULT_SERVERS in lsp/manager.py applies)")
|
|
356
343
|
# Show default agent
|
|
357
344
|
default_agent = config.load_default_agent(args.path)
|
|
358
345
|
print(f"default_agent: {default_agent or '(default: agent.md)'}")
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/entry/headless.py
RENAMED
|
@@ -59,8 +59,8 @@ def _as_error(value: Any) -> dict[str, Any]:
|
|
|
59
59
|
``HeadlessView.errors`` accumulates whatever the notifier passed:
|
|
60
60
|
the agent loop sends a structured ``{"code", "message"}`` for
|
|
61
61
|
classified failures (``budget``/``timeout``), other sites send a
|
|
62
|
-
plain string whose code is then derived from the text, and
|
|
63
|
-
|
|
62
|
+
plain string whose code is then derived from the text, and some
|
|
63
|
+
callers send a ``{"message": ...}`` dict. A nested
|
|
64
64
|
``{"error": {...}}`` shape is unwrapped; a dict carrying only a
|
|
65
65
|
``code`` falls back to that code for its message so the two never
|
|
66
66
|
disagree on emptiness.
|
|
@@ -106,8 +106,7 @@ def error_display_text(value: Any) -> str:
|
|
|
106
106
|
|
|
107
107
|
``notify("error", ...)`` carries either a plain message string or a
|
|
108
108
|
structured ``{"code", "message"}`` payload (the agent loop sends
|
|
109
|
-
the latter where the outcome is known
|
|
110
|
-
``{"message": ...}`` dict too). Views render this rather than the
|
|
109
|
+
the latter where the outcome is known). Views render this rather than the
|
|
111
110
|
raw value, so a structured error does not reach a human as a dict
|
|
112
111
|
repr.
|
|
113
112
|
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/prompts/agent.md
RENAMED
|
@@ -56,6 +56,7 @@ The user will primarily request you perform software engineering tasks. This inc
|
|
|
56
56
|
- Use the available search tools to understand the codebase and the user's query. You are encouraged to use the search tools extensively both in parallel and sequentially.
|
|
57
57
|
- Implement the solution using all tools available to you
|
|
58
58
|
- Verify the solution if possible with tests. NEVER assume specific test framework or test script. Check the README or search codebase to determine the testing approach.
|
|
59
|
+
- Test edge cases to ensure your solution is robust.
|
|
59
60
|
- VERY IMPORTANT:
|
|
60
61
|
- When you have completed a task, you MUST run the lint and typecheck commands (e.g. npm run lint, npm run typecheck, ruff, etc.) with Bash if they were provided to you to ensure your code is correct. If you are unable to find the correct command, ask the user for the command to run and if they supply it, proactively suggest writing it to AGENTS.md so that you will know to run it next time.
|
|
61
62
|
- NEVER commit changes unless the user explicitly asks you to.
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/session/config.py
RENAMED
|
@@ -6,7 +6,6 @@ import json
|
|
|
6
6
|
import os
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from ..lsp.config import LSPConfig
|
|
10
9
|
from ..mcp.config import MCPConfig
|
|
11
10
|
|
|
12
11
|
# ---- context management -------------------------------------------------
|
|
@@ -88,14 +87,11 @@ DEFAULT_TOOLS: list[str] = [
|
|
|
88
87
|
"Glob",
|
|
89
88
|
"Grep",
|
|
90
89
|
"Read",
|
|
91
|
-
"Insert",
|
|
92
90
|
"Edit",
|
|
93
91
|
"Write",
|
|
94
|
-
"Mkdir",
|
|
95
92
|
"Bash",
|
|
96
93
|
"Skill",
|
|
97
94
|
"Question",
|
|
98
|
-
"LSP",
|
|
99
95
|
]
|
|
100
96
|
|
|
101
97
|
# ---- tool output limits --------------------------------------------------------
|
|
@@ -261,15 +257,6 @@ CONFIG_TEMPLATE = """\
|
|
|
261
257
|
"context_path": null,
|
|
262
258
|
"skill_path": null
|
|
263
259
|
}},
|
|
264
|
-
"lsp": {{
|
|
265
|
-
"_comment": "Optional per-extension LSP server overrides. Keys are file extensions (e.g. '.py', '.cpp'); 'command' is the server argv; 'language_id' defaults to the extension without the dot. These override the built-in DEFAULT_SERVERS table. Remove this section to use only the built-ins. The server binary must be on PATH. The '.example' entry below is inert (no such extension) — copy it to a real extension like '.cpp' to activate.",
|
|
266
|
-
"servers": {{
|
|
267
|
-
".example": {{
|
|
268
|
-
"command": ["clangd", "--background-index", "--clang-tidy"],
|
|
269
|
-
"language_id": "cpp"
|
|
270
|
-
}}
|
|
271
|
-
}}
|
|
272
|
-
}},
|
|
273
260
|
"mcp": {{
|
|
274
261
|
"_comment": "Optional MCP servers (requires: pip install -e '.[mcp]'). Each server's tools become agent tools named mcp__<server>__<tool>. Transports: stdio (spawn command+args, pass through env var names), streamable-http / sse (connect to url, optional headers). 'parallel: true' marks read-only servers whose tools may run concurrently; default is serial. 'timeout' bounds connects, discovery and calls (seconds).",
|
|
275
262
|
"servers": {{
|
|
@@ -526,31 +513,6 @@ def load_mcp_config(path: str | os.PathLike | None = None) -> MCPConfig:
|
|
|
526
513
|
return MCPConfig.from_dict(section.get("servers"))
|
|
527
514
|
|
|
528
515
|
|
|
529
|
-
def load_lsp_config(path: str | os.PathLike | None = None) -> LSPConfig:
|
|
530
|
-
"""Load per-extension LSP server overrides from the config file.
|
|
531
|
-
|
|
532
|
-
Reads the optional ``lsp.servers`` object (keyed by file extension,
|
|
533
|
-
e.g. ``".py"``) and returns an ``LSPConfig`` (empty when the file
|
|
534
|
-
has no ``lsp`` section or no servers). These entries layer on top of
|
|
535
|
-
the built-in ``DEFAULT_SERVERS`` table in ``lsp/manager.py``.
|
|
536
|
-
|
|
537
|
-
Malformed entries raise ValueError so config errors surface at
|
|
538
|
-
session start rather than the first LSP call.
|
|
539
|
-
"""
|
|
540
|
-
data = _read_config(path)
|
|
541
|
-
section = data.get("lsp") or {}
|
|
542
|
-
if not isinstance(section, dict):
|
|
543
|
-
raise ValueError(f"config file {_config_path(path)}: lsp must be an object")
|
|
544
|
-
servers = section.get("servers") or {}
|
|
545
|
-
if not isinstance(servers, dict):
|
|
546
|
-
raise ValueError(f"config file {_config_path(path)}: lsp.servers must be an object")
|
|
547
|
-
try:
|
|
548
|
-
return LSPConfig.from_dict(servers)
|
|
549
|
-
except ValueError as e:
|
|
550
|
-
# Re-raise with the config-file path for a clearer message.
|
|
551
|
-
raise ValueError(f"config file {_config_path(path)}: {e}") from e
|
|
552
|
-
|
|
553
|
-
|
|
554
516
|
def load_models_config(path: str | os.PathLike | None = None) -> dict[str, dict]:
|
|
555
517
|
"""Load named LLM profiles from the config file's ``models`` object.
|
|
556
518
|
|
|
@@ -370,7 +370,7 @@ class Session:
|
|
|
370
370
|
# write_file/create_directory), so plan mode stays read-only
|
|
371
371
|
# by refusing every mcp__ tool.
|
|
372
372
|
if self.plan_mode.is_plan and (
|
|
373
|
-
name in ("Write", "Edit", "
|
|
373
|
+
name in ("Write", "Edit", "Bash") or name.startswith("mcp__")
|
|
374
374
|
):
|
|
375
375
|
blocked = self._plan_blocked(name, args)
|
|
376
376
|
if blocked:
|
|
@@ -467,16 +467,8 @@ class Session:
|
|
|
467
467
|
),
|
|
468
468
|
self.project_dir,
|
|
469
469
|
)
|
|
470
|
-
if name
|
|
470
|
+
if name == "Edit":
|
|
471
471
|
return resolve_path(str(args.get("path", "")), self.project_dir)
|
|
472
|
-
if name == "Mkdir":
|
|
473
|
-
# Mirrors Mkdir.run: only the parent is ~-expanded.
|
|
474
|
-
return os.path.realpath(
|
|
475
|
-
os.path.join(
|
|
476
|
-
resolve_path(str(args.get("parent", "")), self.project_dir),
|
|
477
|
-
str(args.get("name", "")),
|
|
478
|
-
)
|
|
479
|
-
)
|
|
480
472
|
return None
|
|
481
473
|
|
|
482
474
|
# ------------------------------------------------------------------
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/__init__.py
RENAMED
|
@@ -9,10 +9,9 @@ from .base import PendingToolResult, Registry, Tool, ToolContext
|
|
|
9
9
|
from .bash import Bash
|
|
10
10
|
from .edit import Edit
|
|
11
11
|
from .edit_mac import EditMac
|
|
12
|
-
from .filesystem import GlobTool, Grep,
|
|
12
|
+
from .filesystem import GlobTool, Grep, Read, Write
|
|
13
13
|
from .glob_mac import GlobMac
|
|
14
14
|
from .grep_mac import GrepMac
|
|
15
|
-
from .lsp import LSP
|
|
16
15
|
from .mcp import MCPTool, mcp_tools_from_manager, normalize_mcp_result
|
|
17
16
|
from .planexit import PlanExit
|
|
18
17
|
from .question import Question
|
|
@@ -32,10 +31,7 @@ __all__ = [
|
|
|
32
31
|
"GlobTool",
|
|
33
32
|
"Grep",
|
|
34
33
|
"GrepMac",
|
|
35
|
-
"Insert",
|
|
36
|
-
"LSP",
|
|
37
34
|
"MCPTool",
|
|
38
|
-
"Mkdir",
|
|
39
35
|
"PlanExit",
|
|
40
36
|
"Question",
|
|
41
37
|
"Read",
|
|
@@ -60,14 +56,11 @@ def default_registry() -> Registry:
|
|
|
60
56
|
for tool in (
|
|
61
57
|
AgentTool(),
|
|
62
58
|
TodoWrite(),
|
|
63
|
-
LSP(),
|
|
64
59
|
glob_tool,
|
|
65
60
|
grep_tool,
|
|
66
61
|
Read(),
|
|
67
|
-
Insert(),
|
|
68
62
|
edit_tool,
|
|
69
63
|
Write(),
|
|
70
|
-
Mkdir(),
|
|
71
64
|
bash_tool,
|
|
72
65
|
Skill(),
|
|
73
66
|
Question(),
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/base.py
RENAMED
|
@@ -165,8 +165,7 @@ class ToolContext:
|
|
|
165
165
|
def config_path(self) -> str | None:
|
|
166
166
|
"""Path to the active config file (None = default resolution).
|
|
167
167
|
|
|
168
|
-
Tools that read the config file
|
|
169
|
-
per-extension server overrides) use this so a session started
|
|
168
|
+
Tools that read the config file use this so a session started
|
|
170
169
|
with ``--config PATH`` reads the same file.
|
|
171
170
|
"""
|
|
172
171
|
if self.session:
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/bash.py
RENAMED
|
@@ -217,6 +217,8 @@ class Bash(Tool):
|
|
|
217
217
|
- Commands that truly require shell execution
|
|
218
218
|
- Running builds, tests, or development servers
|
|
219
219
|
- System administration tasks
|
|
220
|
+
- Creating empty directories: use `mkdir -p <path>` (idempotent; `Write`
|
|
221
|
+
already creates parent directories for any file it writes)
|
|
220
222
|
|
|
221
223
|
**When NOT to use `Bash`:**
|
|
222
224
|
- File operations → use `Read`, `Write`, `Edit`, `Glob`, `Grep` instead
|
|
@@ -227,7 +227,7 @@ def _apply_section(section: _Section, cwd: str, fallback_path: str | None) -> tu
|
|
|
227
227
|
# realpath BEFORE writing (the same resolution diff_targets applies):
|
|
228
228
|
# the write goes through atomic_write_text, whose os.replace would
|
|
229
229
|
# otherwise overwrite a symlink with a regular file and leave the real
|
|
230
|
-
# target untouched. Edit/
|
|
230
|
+
# target untouched. Edit/Write resolve their own paths already.
|
|
231
231
|
target = os.path.realpath(_resolve_target(section.new_path, cwd, fallback_path))
|
|
232
232
|
if not os.path.isfile(target):
|
|
233
233
|
return False, f"target file does not exist: {target}"
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/edit.py
RENAMED
|
@@ -98,7 +98,10 @@ class Edit(Tool):
|
|
|
98
98
|
"fenced code block).\n"
|
|
99
99
|
"- The file paths within the diff (e.g. '--- a/filename' "
|
|
100
100
|
"'+++ b/filename') must be appropriate for the `path`.\n\n"
|
|
101
|
-
|
|
101
|
+
"To insert text at a specific point, use string-replacement mode: "
|
|
102
|
+
"match a unique nearby line as `old_str` and include it plus the new "
|
|
103
|
+
"text in `new_str`. To add content to a brand-new or empty file, use "
|
|
104
|
+
'the "Write" tool instead.'
|
|
102
105
|
)
|
|
103
106
|
parameters = {
|
|
104
107
|
"type": "object",
|
|
@@ -5,7 +5,7 @@ tools — atomic file replacement (``atomic_write_text``), spooling
|
|
|
5
5
|
oversized tool results to temp files (`gptel-agent--truncate-buffer`
|
|
6
6
|
parity), git-root detection, and the ``natnump`` predicate — and
|
|
7
7
|
re-exports the tool classes that live in per-tool modules (`read.py`,
|
|
8
|
-
`glob.py`, `grep.py`, `edit.py`, `write.py
|
|
8
|
+
`glob.py`, `grep.py`, `edit.py`, `write.py`),
|
|
9
9
|
so existing imports such as ``from .tools.filesystem import Read``
|
|
10
10
|
keep working.
|
|
11
11
|
|
|
@@ -19,7 +19,7 @@ NOTE: these filesystem tools are intentionally SYNCHRONOUS. Only Bash
|
|
|
19
19
|
and Agent are `:async t` in gptel-agent; sync tools run one at a time in
|
|
20
20
|
the model-emitted order. Do NOT be tempted to port every tool to async
|
|
21
21
|
for parallelism: tools can depend on one another's side effects within a
|
|
22
|
-
single round (e.g. Write
|
|
22
|
+
single round (e.g. Write then Read/Edit the same path, or Edit then
|
|
23
23
|
Grep the just-changed file). Running them concurrently would introduce
|
|
24
24
|
read-after-write races and non-deterministic results. Keep filesystem
|
|
25
25
|
tools synchronous so ordering — and therefore correctness — is preserved.
|
|
@@ -34,7 +34,6 @@ from __future__ import annotations
|
|
|
34
34
|
|
|
35
35
|
import contextlib
|
|
36
36
|
import os
|
|
37
|
-
import re
|
|
38
37
|
import shutil # noqa: F401 (mock target for tests)
|
|
39
38
|
import stat
|
|
40
39
|
import subprocess # noqa: F401 (mock target for tests)
|
|
@@ -42,7 +41,6 @@ import tempfile
|
|
|
42
41
|
import threading
|
|
43
42
|
import time
|
|
44
43
|
import uuid
|
|
45
|
-
from collections.abc import Callable, Iterator
|
|
46
44
|
from pathlib import Path
|
|
47
45
|
from typing import TypeGuard
|
|
48
46
|
|
|
@@ -138,90 +136,6 @@ def _natnump(n: object) -> TypeGuard[int]:
|
|
|
138
136
|
return isinstance(n, int) and not isinstance(n, bool) and n >= 0
|
|
139
137
|
|
|
140
138
|
|
|
141
|
-
def _glob_to_regex(pattern: str) -> str:
|
|
142
|
-
"""Translate a pathlib-style glob pattern into a :mod:`re` pattern.
|
|
143
|
-
|
|
144
|
-
Follows :mod:`fnmatch` conventions with two deliberate deviations:
|
|
145
|
-
``*`` does not cross path separators (unlike :func:`fnmatch.fnmatch`)
|
|
146
|
-
and ``**`` matches any number of directories (including none). A
|
|
147
|
-
pattern without any glob metacharacters is escaped, so plain names
|
|
148
|
-
match exactly.
|
|
149
|
-
"""
|
|
150
|
-
i, n = 0, len(pattern)
|
|
151
|
-
out: list[str] = []
|
|
152
|
-
while i < n:
|
|
153
|
-
c = pattern[i]
|
|
154
|
-
if c == "*":
|
|
155
|
-
if pattern[i : i + 2] == "**":
|
|
156
|
-
i += 2
|
|
157
|
-
if pattern[i : i + 1] == "/":
|
|
158
|
-
i += 1
|
|
159
|
-
out.append("(?:.*/)?")
|
|
160
|
-
continue
|
|
161
|
-
out.append("[^/]*")
|
|
162
|
-
i += 1
|
|
163
|
-
elif c == "?":
|
|
164
|
-
out.append("[^/]")
|
|
165
|
-
i += 1
|
|
166
|
-
elif c == "[":
|
|
167
|
-
end = _find_glob_class_end(pattern, i)
|
|
168
|
-
if end is None:
|
|
169
|
-
out.append(re.escape(c))
|
|
170
|
-
i += 1
|
|
171
|
-
else:
|
|
172
|
-
# The class body is regex-compatible as-is (\], \\, ranges,
|
|
173
|
-
# and member brackets mean the same thing in both dialects);
|
|
174
|
-
# only the negation sigil differs (! -> ^).
|
|
175
|
-
body = pattern[i + 1 : end]
|
|
176
|
-
if body.startswith("!"):
|
|
177
|
-
body = "^" + body[1:]
|
|
178
|
-
out.append("[" + body + "]")
|
|
179
|
-
i = end + 1
|
|
180
|
-
else:
|
|
181
|
-
out.append(re.escape(c))
|
|
182
|
-
i += 1
|
|
183
|
-
return "".join(out)
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
def _find_glob_class_end(pattern: str, start: int) -> int | None:
|
|
187
|
-
"""Index of the ``]`` closing the char class opened at ``start``.
|
|
188
|
-
|
|
189
|
-
Mirrors glob semantics: a ``]`` immediately after ``[`` (or ``[!``)
|
|
190
|
-
is a literal bracket, and backslash escapes are honoured.
|
|
191
|
-
"""
|
|
192
|
-
i = start + 1
|
|
193
|
-
if i < len(pattern) and pattern[i] == "!":
|
|
194
|
-
i += 1
|
|
195
|
-
if i < len(pattern) and pattern[i] == "]":
|
|
196
|
-
i += 1
|
|
197
|
-
while i < len(pattern):
|
|
198
|
-
if pattern[i] == "\\" and i + 1 < len(pattern):
|
|
199
|
-
i += 2
|
|
200
|
-
elif pattern[i] == "]":
|
|
201
|
-
return i
|
|
202
|
-
else:
|
|
203
|
-
i += 1
|
|
204
|
-
return None
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def _walk_files(root: Path, onerror: Callable[[OSError], object] | None = None) -> Iterator[Path]:
|
|
208
|
-
"""Depth-first file iterator that never raises on traversal errors.
|
|
209
|
-
|
|
210
|
-
Wraps :func:`os.walk` with ``onerror`` so unreadable directories are
|
|
211
|
-
reported instead of silently swallowed, and wraps the whole iteration
|
|
212
|
-
in a try/except so a scan that dies mid-flight still yields the
|
|
213
|
-
entries collected so far (mirroring the 3.13+ ``pathlib`` scan
|
|
214
|
-
behaviour on every supported version).
|
|
215
|
-
"""
|
|
216
|
-
try:
|
|
217
|
-
for dirpath, _dirnames, filenames in os.walk(root, onerror=onerror, followlinks=False):
|
|
218
|
-
for name in filenames:
|
|
219
|
-
yield Path(dirpath) / name
|
|
220
|
-
except OSError as e:
|
|
221
|
-
if onerror is not None:
|
|
222
|
-
onerror(e)
|
|
223
|
-
|
|
224
|
-
|
|
225
139
|
def _git_root(path: str) -> str | None:
|
|
226
140
|
d = Path(path).resolve()
|
|
227
141
|
for parent in [d, *d.parents]:
|
|
@@ -236,11 +150,11 @@ def atomic_write_text(path: str, content: str) -> None:
|
|
|
236
150
|
"""Replace PATH's contents with CONTENT atomically.
|
|
237
151
|
|
|
238
152
|
THE single write path for every tool that rewrites a file (``Edit``,
|
|
239
|
-
``
|
|
153
|
+
``Write``, and the pure-Python diff applier), so the three
|
|
240
154
|
callers cannot drift apart. It lives in this module with the other
|
|
241
|
-
shared helpers, and the
|
|
155
|
+
shared helpers, and the three callers import it LAZILY (inside the
|
|
242
156
|
method that writes) rather than at module level, because this module
|
|
243
|
-
re-imports ``edit``/``write``/``
|
|
157
|
+
re-imports ``edit``/``write``/``diffapply`` at its bottom
|
|
244
158
|
for the compatibility re-exports: a module-level import here would
|
|
245
159
|
close the cycle on a half-initialised module (``tools/__init__``
|
|
246
160
|
loads ``edit`` first, whose import of this module would then ask the
|
|
@@ -286,7 +200,7 @@ def atomic_write_text(path: str, content: str) -> None:
|
|
|
286
200
|
- PATH must already be symlink-resolved. ``os.replace`` onto a
|
|
287
201
|
symlink overwrites the LINK with a regular file, where an in-place
|
|
288
202
|
write would have followed it. Every caller resolves the real path
|
|
289
|
-
first (``Edit``/``
|
|
203
|
+
first (``Edit``/``Write`` via ``os.path.realpath`` on
|
|
290
204
|
entry, ``_apply_section`` on its resolved target).
|
|
291
205
|
- Hard links are broken: the new content lands on a new inode, so
|
|
292
206
|
other links to the old inode keep the old content.
|
|
@@ -332,8 +246,6 @@ from .glob import GlobTool, _git_glob_results # noqa: E402
|
|
|
332
246
|
from .glob_mac import GlobMac # noqa: E402
|
|
333
247
|
from .grep import Grep, _grep_out # noqa: E402
|
|
334
248
|
from .grep_mac import GrepMac # noqa: E402
|
|
335
|
-
from .insert import Insert # noqa: E402
|
|
336
|
-
from .mkdir import Mkdir # noqa: E402
|
|
337
249
|
from .read import Read # noqa: E402
|
|
338
250
|
from .write import Write # noqa: E402
|
|
339
251
|
# isort: on
|
|
@@ -344,8 +256,6 @@ __all__ = [
|
|
|
344
256
|
"GlobTool",
|
|
345
257
|
"Grep",
|
|
346
258
|
"GrepMac",
|
|
347
|
-
"Insert",
|
|
348
|
-
"Mkdir",
|
|
349
259
|
"Read",
|
|
350
260
|
"Write",
|
|
351
261
|
"MAX_OUTPUT",
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tools/grep.py
RENAMED
|
@@ -31,7 +31,6 @@ class Grep(Tool):
|
|
|
31
31
|
**When NOT to use `Grep`:**
|
|
32
32
|
- Searching for files by name → use `Glob`
|
|
33
33
|
- Reading known file contents → use `Read`
|
|
34
|
-
- Navigating a known code symbol (its definition, references, implementations, type info, or call hierarchy) → use `LSP` (semantically correct; `Grep` matches text, not symbols)
|
|
35
34
|
- open-ended search that may require multiple rounds of globbing and grepping → use `Agent`
|
|
36
35
|
|
|
37
36
|
**How to use `Grep`:**
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tui/core.py
RENAMED
|
@@ -202,7 +202,7 @@ class Tui(RenderMixin, InputMixin, CommandMixin):
|
|
|
202
202
|
# old bare "error" so the user sees WHAT failed; the
|
|
203
203
|
# red styling comes from "error" appearing in the text.
|
|
204
204
|
# A structured {"code", "message"} payload (budget /
|
|
205
|
-
# timeout outcomes
|
|
205
|
+
# timeout outcomes) is unwrapped by the
|
|
206
206
|
# shared helper — rendering the dict would both look
|
|
207
207
|
# wrong and lose the detail.
|
|
208
208
|
detail = error_display_text(data) if data else ""
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4}/python_agent_harness/tui/render.py
RENAMED
|
@@ -563,7 +563,19 @@ class RenderMixin:
|
|
|
563
563
|
cells); line 2 gets the full terminal width. Newlines in the
|
|
564
564
|
message are flattened, words break at spaces where possible,
|
|
565
565
|
and anything beyond two lines is truncated with an ellipsis.
|
|
566
|
+
|
|
567
|
+
The status is the one display path that reaches the terminal
|
|
568
|
+
unsanitized: it is set from endpoint/MCP error text
|
|
569
|
+
(``error_display_text``) and ``_on_log`` messages (``agent
|
|
570
|
+
error: {e}``, ``compaction failed: {e}``, ``MCP: [{server}]
|
|
571
|
+
{err}``), any of which can carry a hostile server's escape
|
|
572
|
+
sequences. Strip them here -- the single sink for every status
|
|
573
|
+
source -- mirroring the sibling paths (tool name, history rows)
|
|
574
|
+
that already call ``sanitize_terminal``. Sanitizing BEFORE the
|
|
575
|
+
newline flatten below keeps a stray OSC introducer from hiding
|
|
576
|
+
the rest of the line.
|
|
566
577
|
"""
|
|
578
|
+
msg = sanitize_terminal(msg)
|
|
567
579
|
msg = " ".join(msg.splitlines())
|
|
568
580
|
width = self.console.width or 80
|
|
569
581
|
avail1 = max(1, width - used - 1)
|
{python_agent_harness-1.5.6.3 → python_agent_harness-1.5.6.4/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.6.
|
|
3
|
+
Version: 1.5.6.4
|
|
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
|
|
@@ -74,7 +74,7 @@ Edit `~/.config/python-agent-harness/config.json` and set your `base_url`, `api_
|
|
|
74
74
|
- **FSM-driven execution** — explicit `WAIT` / `TOOL` / `TRET` / `SUPERVISE` / `DONE` / `ERRS` / `ABRT` states. Completion supervision nudges the model when it stops early; failed tool calls are sanitized. Transient API failures (`429` / `5xx`) retry with exponential backoff. Auth-expired codes (configurable via `AUTH_REFRESH_STATUS_CODES` in `config.py`; defaults to `[401, 502]`) trigger automatic API key re-read from config/env.
|
|
75
75
|
- **Context management** — CJK-aware token estimation, per-model context windows, automatic compaction at 70% usage.
|
|
76
76
|
- **Image & text attachments** — attach with `@path` (e.g. `@screenshot.png`, `@README.md`): images (PNG/JPEG/GIF/WebP, up to 20 MB) become multimodal `image_url` parts; text files are inlined. Web URLs supported for images.
|
|
77
|
-
- **Coding tools** — `Agent`, `TodoWrite`, `Glob`, `Grep`, `Read`, `
|
|
77
|
+
- **Coding tools** — `Agent`, `TodoWrite`, `Glob`, `Grep`, `Read`, `Edit` (incl. unified diffs), `Write`, `Bash`, `Skill`, `Question`, `PlanExit`. Read-only tool rounds (`Read`, `Glob`, `Grep`, `Skill`) dispatch concurrently; async tools (`Bash`, `Agent`) can also run concurrently. Results always delivered in emitted order.
|
|
78
78
|
- **Plan / Build modes** — plan mode is read-only except for the per-session plan file.
|
|
79
79
|
- **Persistent sessions** — auto-saved after every response to `~/.local/share/python-agent-harness/sessions/`, with LLM-generated titles and `/restore --latest` / `/sessions`.
|
|
80
80
|
- **Focused TUI** — Rich-based with pinned status bar, Todos panel, inline diff rendering, and a `prompt_toolkit` editor with history and completion. `Esc+Enter` submits, `Ctrl-D` quits, `Ctrl-C` cancels.
|
|
@@ -191,7 +191,6 @@ All LLM settings live in `~/.config/python-agent-harness/config.json`. Environme
|
|
|
191
191
|
- **`subagent_llm`** — LLM config for `Agent` tool. Unset values inherit from `llm`. Set `profile` to reuse a `models` entry. Precedence: profile > `subagent_llm` > `llm` > env vars.
|
|
192
192
|
- **`default_agent`** — agent name to use at session start (must exist in `prompts/agents/`). `null` = built-in default.
|
|
193
193
|
- **`paths.context_path` / `paths.skill_path`** — locations for context files and skills. Default: project-local `contexts/` and `skills/`.
|
|
194
|
-
- **`lsp.servers`** — per-extension LSP server overrides for the `LSP` tool. Keys are extensions (`.py`, `.cpp`); each has `command` (argv) and optional `language_id`. Layers on top of `DEFAULT_SERVERS` in `lsp/manager.py`.
|
|
195
194
|
- **`mcp.servers`** — MCP server config (requires `[mcp]` extra). Each supports `transport`, `command`, `args`, `env`, `url`, `headers`, `parallel`, `timeout`, `enabled`.
|
|
196
195
|
- **`headless` / `serve`** — optional budget limits: `max_rounds` (LLM rounds) and `timeout` (wall-clock seconds). `--max-rounds` / `--timeout` override per call; `<= 0` or `null` disables. Unset = unlimited.
|
|
197
196
|
- **Precedence** — code defaults < config file < `OPENAI_*` env vars. Sub-agents also support `OPENAI_SUBAGENT_*` (`_BASE_URL`, `_API_KEY`, `_MODEL`).
|
|
@@ -30,10 +30,6 @@ python_agent_harness/io/persistence.py
|
|
|
30
30
|
python_agent_harness/io/text_filter.py
|
|
31
31
|
python_agent_harness/llm/__init__.py
|
|
32
32
|
python_agent_harness/llm/client.py
|
|
33
|
-
python_agent_harness/lsp/__init__.py
|
|
34
|
-
python_agent_harness/lsp/client.py
|
|
35
|
-
python_agent_harness/lsp/config.py
|
|
36
|
-
python_agent_harness/lsp/manager.py
|
|
37
33
|
python_agent_harness/mcp/__init__.py
|
|
38
34
|
python_agent_harness/mcp/client.py
|
|
39
35
|
python_agent_harness/mcp/config.py
|
|
@@ -69,10 +65,7 @@ python_agent_harness/tools/glob.py
|
|
|
69
65
|
python_agent_harness/tools/glob_mac.py
|
|
70
66
|
python_agent_harness/tools/grep.py
|
|
71
67
|
python_agent_harness/tools/grep_mac.py
|
|
72
|
-
python_agent_harness/tools/insert.py
|
|
73
|
-
python_agent_harness/tools/lsp.py
|
|
74
68
|
python_agent_harness/tools/mcp.py
|
|
75
|
-
python_agent_harness/tools/mkdir.py
|
|
76
69
|
python_agent_harness/tools/planexit.py
|
|
77
70
|
python_agent_harness/tools/question.py
|
|
78
71
|
python_agent_harness/tools/read.py
|