microharness 0.1.0__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.
- microharness-0.1.0/.env.example +15 -0
- microharness-0.1.0/.gitignore +16 -0
- microharness-0.1.0/AGENTS.md +9 -0
- microharness-0.1.0/LICENSE +21 -0
- microharness-0.1.0/PKG-INFO +491 -0
- microharness-0.1.0/PR_DESCRIPTION.md +75 -0
- microharness-0.1.0/README.md +468 -0
- microharness-0.1.0/SPEC.md +477 -0
- microharness-0.1.0/benchmarks/__init__.py +6 -0
- microharness-0.1.0/benchmarks/harbor.py +215 -0
- microharness-0.1.0/benchmarks/mini_swe.py +543 -0
- microharness-0.1.0/benchmarks/pier_agent.py +69 -0
- microharness-0.1.0/benchmarks/runner.py +396 -0
- microharness-0.1.0/core/__init__.py +3 -0
- microharness-0.1.0/core/auth.py +286 -0
- microharness-0.1.0/core/auth_sigv4.py +354 -0
- microharness-0.1.0/core/commands.py +128 -0
- microharness-0.1.0/core/config.py +324 -0
- microharness-0.1.0/core/discovery.py +305 -0
- microharness-0.1.0/core/environment.py +400 -0
- microharness-0.1.0/core/evaluator.py +98 -0
- microharness-0.1.0/core/harness.py +806 -0
- microharness-0.1.0/core/interactive.py +644 -0
- microharness-0.1.0/core/loop.py +94 -0
- microharness-0.1.0/core/memory.py +257 -0
- microharness-0.1.0/core/model.py +570 -0
- microharness-0.1.0/core/prompts.py +85 -0
- microharness-0.1.0/core/protocols.py +110 -0
- microharness-0.1.0/core/providers.json +94 -0
- microharness-0.1.0/core/providers.py +776 -0
- microharness-0.1.0/core/session.py +491 -0
- microharness-0.1.0/core/skills.py +240 -0
- microharness-0.1.0/core/tools.py +447 -0
- microharness-0.1.0/core/tracer.py +511 -0
- microharness-0.1.0/core/tui.py +1664 -0
- microharness-0.1.0/core/tui_session.py +177 -0
- microharness-0.1.0/core/types.py +155 -0
- microharness-0.1.0/core/usage.py +179 -0
- microharness-0.1.0/main.py +755 -0
- microharness-0.1.0/microharness/__init__.py +8 -0
- microharness-0.1.0/microharness/__main__.py +4 -0
- microharness-0.1.0/pyproject.toml +69 -0
- microharness-0.1.0/tests/__init__.py +1 -0
- microharness-0.1.0/tests/test_auth_aws.py +378 -0
- microharness-0.1.0/tests/test_auth_plugins.py +232 -0
- microharness-0.1.0/tests/test_auth_schemes.py +352 -0
- microharness-0.1.0/tests/test_auth_sigv4.py +228 -0
- microharness-0.1.0/tests/test_benchmarks.py +963 -0
- microharness-0.1.0/tests/test_commands.py +148 -0
- microharness-0.1.0/tests/test_config.py +345 -0
- microharness-0.1.0/tests/test_discovery.py +364 -0
- microharness-0.1.0/tests/test_environment.py +294 -0
- microharness-0.1.0/tests/test_evaluator.py +73 -0
- microharness-0.1.0/tests/test_harbor.py +164 -0
- microharness-0.1.0/tests/test_harness.py +2590 -0
- microharness-0.1.0/tests/test_interactive.py +414 -0
- microharness-0.1.0/tests/test_memory.py +485 -0
- microharness-0.1.0/tests/test_model.py +1475 -0
- microharness-0.1.0/tests/test_model_cache.py +200 -0
- microharness-0.1.0/tests/test_model_context.py +397 -0
- microharness-0.1.0/tests/test_package.py +25 -0
- microharness-0.1.0/tests/test_payload_reasoning.py +52 -0
- microharness-0.1.0/tests/test_prompts.py +106 -0
- microharness-0.1.0/tests/test_protocols.py +112 -0
- microharness-0.1.0/tests/test_providers.py +1216 -0
- microharness-0.1.0/tests/test_session.py +559 -0
- microharness-0.1.0/tests/test_skills.py +231 -0
- microharness-0.1.0/tests/test_tools.py +644 -0
- microharness-0.1.0/tests/test_tracer.py +864 -0
- microharness-0.1.0/tests/test_tui.py +2115 -0
- microharness-0.1.0/tests/test_tui_session.py +288 -0
- microharness-0.1.0/tests/test_usage.py +148 -0
- microharness-0.1.0/uv.lock +108 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copy this file to .env and fill in your values
|
|
2
|
+
# Note: MODEL_ENDPOINT accepts either the base URL or the full /chat/completions URL.
|
|
3
|
+
#
|
|
4
|
+
# For OpenRouter:
|
|
5
|
+
# MODEL_ENDPOINT=https://openrouter.ai/api/v1/chat/completions
|
|
6
|
+
# MODEL_NAME=anthropic/claude-5.5-sonnet
|
|
7
|
+
# MODEL_API_KEY=sk-or-v1-...
|
|
8
|
+
#
|
|
9
|
+
# For Local Ollama:
|
|
10
|
+
# MODEL_ENDPOINT=http://localhost:11434/v1
|
|
11
|
+
# MODEL_NAME=qwen2.5-coder
|
|
12
|
+
#
|
|
13
|
+
# For Local vLLM:
|
|
14
|
+
# MODEL_ENDPOINT=http://localhost:8000/v1
|
|
15
|
+
# MODEL_NAME=mistralai/Mistral-7B-Instruct-v0.3
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Instructions and project conventions for AI agents operating on `microharness`.
|
|
4
|
+
|
|
5
|
+
## Guiding Principles
|
|
6
|
+
- **Zero Runtime Dependencies**: The core harness must only rely on Python's standard library. Do not add runtime dependencies to `pyproject.toml`.
|
|
7
|
+
- **Pluggability**: Components must implement minimal protocols (`Model`, `Tool`, `Evaluator`). Never introduce provider-specific subclasses or hardcoded branching.
|
|
8
|
+
- **Testing Standard**: Every feature must include rigorous unit tests in `tests/`. Never write tautological "pass-through" assertions (`assertIn(result, [A, B, C])`). Always use strict equality and test negative failure cases.
|
|
9
|
+
- **Verification**: Run `uv run pytest` before concluding any changes.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dima Kagan
|
|
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,491 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: microharness
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A minimal, zero-dependency, and pluggable AI agent microframework in Python
|
|
5
|
+
Project-URL: Homepage, https://github.com/Kagandi/microharness
|
|
6
|
+
Project-URL: Repository, https://github.com/Kagandi/microharness
|
|
7
|
+
Project-URL: Issues, https://github.com/Kagandi/microharness/issues
|
|
8
|
+
Author: Dima Kagan
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agent,ai,coding-agent,harness,llm,microframework,swe-bench,zero-dependency
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# microharness
|
|
25
|
+
|
|
26
|
+
A minimalist, zero-dependency, and fully pluggable AI agent microframework in Python.
|
|
27
|
+
|
|
28
|
+
Built with **zero external runtime dependencies** (standard library only) to teach the core architectural boundaries of agentic systems. Compatible with modern packaging tools like [`uv`](https://github.com/astral-sh/uv).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## The Core Mental Model: Harness vs. Loop
|
|
33
|
+
|
|
34
|
+
| Component | Responsibility | Location in `microharness` |
|
|
35
|
+
| :--- | :--- | :--- |
|
|
36
|
+
| **Agent Loop** *(The Engine)* | Pure Thought $\to$ Action $\to$ Observation cycle. Agnostic to benchmarks, sandboxes, and models. | [`core/loop.py`](core/loop.py) (~40 LOC) |
|
|
37
|
+
| **Harness** *(The Chassis)* | The outer environment: workspace directory, sandboxing, budgets, memory compaction, telemetry/tracing, and grading. | [`core/harness.py`](core/harness.py) |
|
|
38
|
+
| **Interactive Router** | One command table (`/model`, `/resume`, `/compact`, `/skill`, ...) shared by the CLI session and the TUI, so the two frontends cannot drift. | [`core/interactive.py`](core/interactive.py) |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Configuration, Steering, Skills, Commands & Tool Plugins
|
|
43
|
+
|
|
44
|
+
`microharness` supports cascading configuration at two distinct scopes:
|
|
45
|
+
1. **Global User Baseline** (`~/.microharness/` or `--global-dir`)
|
|
46
|
+
2. **Project-Local Scope** (`.microharness/` in current workspace root)
|
|
47
|
+
|
|
48
|
+
### 1. Configuration Files (`config.json`)
|
|
49
|
+
Configure your baseline model, endpoint, API key, and limits globally or override them per project:
|
|
50
|
+
* **Global Baseline**: `~/.microharness/config.json`
|
|
51
|
+
* **Project Override**: `.microharness/config.json`
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"default_model": "smart",
|
|
56
|
+
"max_context_tokens": 64000,
|
|
57
|
+
"trigger_ratio": 0.80,
|
|
58
|
+
"max_tool_tokens": 8000,
|
|
59
|
+
"sandbox": false,
|
|
60
|
+
"models": {
|
|
61
|
+
"fast": {
|
|
62
|
+
"model": "gemini-2.5-flash",
|
|
63
|
+
"provider": "google",
|
|
64
|
+
"description": "Fast flash model"
|
|
65
|
+
},
|
|
66
|
+
"smart": {
|
|
67
|
+
"model": "anthropic/claude-5.5-sonnet",
|
|
68
|
+
"provider": "openrouter",
|
|
69
|
+
"description": "Frontier reasoning model"
|
|
70
|
+
},
|
|
71
|
+
"local": {
|
|
72
|
+
"model": "local-model",
|
|
73
|
+
"provider": "lmstudio",
|
|
74
|
+
"endpoint": "http://localhost:1234/v1",
|
|
75
|
+
"description": "Local offline LLM"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Per-model context caps: a `models` entry may declare `max_context_tokens`, and a provider profile in `providers.json` may declare `context_tokens` (entry > profile > global `max_context_tokens`/`max_tokens`/`context_tokens`); switching models applies the cap live.
|
|
82
|
+
|
|
83
|
+
Legacy `max_context_chars`/`max_tool_chars` keys are removed; old char budgets converted as `chars//4` (e.g. 4000 chars behaved as 1000 tokens).
|
|
84
|
+
To preserve prior behavior, set `max_tool_tokens`/`max_context_tokens` explicitly (e.g. `"max_tool_tokens": 1000` replaces a former 4000-char tool limit).
|
|
85
|
+
|
|
86
|
+
#### Precedence Hierarchy:
|
|
87
|
+
1. **CLI Flags** (`--model`, `--endpoint`, `--api-key`, `--sandbox`, `-d`) — *Highest priority*
|
|
88
|
+
2. **Environment Variables / Local `.env`** (`MODEL_ENDPOINT`, `MODEL_NAME`, `MODEL_API_KEY`)
|
|
89
|
+
3. **Project Config** (`.microharness/config.json`) — *Project overrides*
|
|
90
|
+
4. **Global Config** (`~/.microharness/config.json`) — *Machine baseline*
|
|
91
|
+
5. **Hardcoded Fallbacks** (`MockModel`, default prompts) — *Lowest priority*
|
|
92
|
+
|
|
93
|
+
#### Amazon Bedrock
|
|
94
|
+
`bedrock` is a built-in provider that targets Bedrock's official OpenAI-compatible endpoint.
|
|
95
|
+
On a machine with active AWS SSO (`aws sso login`) it works with zero config:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
uv run microharness --model "bedrock/us.openai.gpt-5.6-sol" "Refactor auth.py"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Credentials resolve from the standard chain (environment, `~/.aws/credentials`, SSO
|
|
102
|
+
cache), and requests are SigV4-signed with the standard library; the harness never
|
|
103
|
+
shells out to the AWS CLI. The region resolves from `config.json` `"region"`, then
|
|
104
|
+
`AWS_REGION`, then `AWS_DEFAULT_REGION`, then the `~/.aws/config` profile region
|
|
105
|
+
(profile from `config.json` `"aws_profile"` or `AWS_PROFILE`, default `default`).
|
|
106
|
+
Without credentials or region the spec falls back to `MockModel` with a hint
|
|
107
|
+
(`aws sso login`). A `BEDROCK_API_KEY` bearer token still overrides SSO when set.
|
|
108
|
+
Only models whose Bedrock model card lists Chat Completions are served on this
|
|
109
|
+
endpoint (Claude/Nova IDs return `model_not_found`); the registry default is
|
|
110
|
+
`us.openai.gpt-5.6-sol`.
|
|
111
|
+
|
|
112
|
+
Auth schemes are pluggable: built-ins are `none`, `bearer`, `header`, and `sigv4`
|
|
113
|
+
(see `core/auth.py`), and extra single-file plugins can be installed as
|
|
114
|
+
`~/.microharness/auth/<scheme>.py` (global dir only, never project-local).
|
|
115
|
+
|
|
116
|
+
The shim exposes no prompt-cache or reasoning parameters, so the Bedrock profile runs with `cache_strategy: "openai_breakpoint"` and `reasoning_format: "none"`: with `cache_ttl` on, the first system text part carries an explicit `prompt_cache_breakpoint` (sub-1024-token prefixes are a server-side no-op); a stale user `providers.json` keeps `"none"` and simply skips breakpoints.
|
|
117
|
+
|
|
118
|
+
### 2. Cascading Instructions (`AGENTS.md`)
|
|
119
|
+
You can provide personal agent preferences globally, while projects can specialize or override them:
|
|
120
|
+
* **Global Baseline**: `~/.microharness/AGENTS.md` (e.g., your personal coding habits, formatting preferences).
|
|
121
|
+
* **Project Conventions**: `.microharness/AGENTS.md` or `./AGENTS.md` in the repo root (e.g., repo-specific test commands, architecture rules).
|
|
122
|
+
|
|
123
|
+
The harness loads both in cascading order (Global baseline first, Project local second) into the system prompt.
|
|
124
|
+
|
|
125
|
+
### 3. Progressive Skills Disclosure (`.microharness/skills/` & Shadowing) — Agent-Facing
|
|
126
|
+
Define reusable task workflows for the **agent** in `.microharness/skills/<skill_name>/SKILL.md`:
|
|
127
|
+
* **Global Skills** (`~/.microharness/skills/`): Available across all projects on your machine.
|
|
128
|
+
* **Project Skills** (`.microharness/skills/`): Project-specific tools and workflows (namespaced cleanly without polluting the project root).
|
|
129
|
+
* **Skill Shadowing**: If a project defines a skill with the same name as a global skill, the project version cleanly overrides it.
|
|
130
|
+
* **Progressive Disclosure**: Full skill files are never dumped into the prompt. Instead, the harness injects a 1-line index with scope badges (`[global]` or `[project]`).
|
|
131
|
+
* **Lazy Loading & Security**: The agent reads full instructions on demand via `read_file`. Global skills are authorized for reading, while all file writes remain strictly sandboxed to the project directory.
|
|
132
|
+
|
|
133
|
+
### 4. Custom Slash Commands (`.microharness/commands/*.md`) — User-Facing
|
|
134
|
+
Define reusable prompt templates and macros for the **user** in `.microharness/commands/<name>.md`:
|
|
135
|
+
```markdown
|
|
136
|
+
# Review code changes
|
|
137
|
+
Review the git diff or specified files: $ARGUMENTS.
|
|
138
|
+
Check for:
|
|
139
|
+
1. Correctness and edge-case logic bugs
|
|
140
|
+
2. Unit test coverage
|
|
141
|
+
3. Adherence to conventions in AGENTS.md
|
|
142
|
+
```
|
|
143
|
+
* **Skills vs. Commands**: Skills teach the **agent** how to perform complex workflows; Commands give the **user** prompt shortcuts.
|
|
144
|
+
* **Invocation**: Type `/review src/auth.py` in interactive chat or pass `microharness "/review src/auth.py"`.
|
|
145
|
+
* **Argument Substitution**: `$ARGUMENTS` or `{args}` is substituted with your trailing arguments.
|
|
146
|
+
* **Dynamic Help & Shadowing**: `/help` lists all discovered custom commands with their descriptions and scopes (`[project]` or `[global]`). Project commands shadow global ones.
|
|
147
|
+
|
|
148
|
+
### 5. Custom Tool Plugins (`.microharness/tools/*.py`) — Zero-Commit Extensibility
|
|
149
|
+
Add new capabilities to the agent dynamically without modifying harness core code or making git commits:
|
|
150
|
+
* **Global Tools** (`~/.microharness/tools/*.py`): Available across all projects on your machine (always trusted and loaded automatically).
|
|
151
|
+
* **Project Tools** (`.microharness/tools/*.py`): Scoped to the current repository. Requires explicit opt-in via `--trust-project-tools` (or `"trust_project_tools": true` in `~/.microharness/config.json`) to prevent untrusted code execution from cloned repositories.
|
|
152
|
+
* **Tool Shadowing & Overrides**: A project tool with the same `name` overrides the global version. If a custom plugin shares a name with a built-in tool (e.g. `bash`), it will override it and emit a warning to ensure full visibility.
|
|
153
|
+
|
|
154
|
+
#### Authoring Conventions
|
|
155
|
+
A tool plugin file can follow any of these patterns:
|
|
156
|
+
|
|
157
|
+
##### Option A: Standalone Tool Class (Simplest)
|
|
158
|
+
Any class conforming to the `Tool` protocol (`name`, `description`, `parameters`, `execute`):
|
|
159
|
+
```python
|
|
160
|
+
# ~/.microharness/tools/web_fetch.py or .microharness/tools/calculator.py
|
|
161
|
+
class CalculatorTool:
|
|
162
|
+
name = "calculate"
|
|
163
|
+
description = "Evaluates basic math expressions safely"
|
|
164
|
+
parameters = {
|
|
165
|
+
"type": "object",
|
|
166
|
+
"properties": {
|
|
167
|
+
"expression": {"type": "string", "description": "The math expression (e.g. '24 * 7')"}
|
|
168
|
+
},
|
|
169
|
+
"required": ["expression"],
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
def execute(self, expression: str) -> tuple[int, str]:
|
|
173
|
+
try:
|
|
174
|
+
return 0, str(eval(expression, {"__builtins__": {}}, {}))
|
|
175
|
+
except Exception as exc:
|
|
176
|
+
return 1, f"Error: {exc}"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
##### Option B: Environment-Aware Factory (`get_tools`)
|
|
180
|
+
Use `get_tools(env)` if your tool needs access to the harness execution environment (e.g. `env.workspace_dir`):
|
|
181
|
+
```python
|
|
182
|
+
# .microharness/tools/db_tool.py
|
|
183
|
+
class DatabaseTool:
|
|
184
|
+
name = "query_db"
|
|
185
|
+
description = "Queries a project SQLite database"
|
|
186
|
+
parameters = {
|
|
187
|
+
"type": "object",
|
|
188
|
+
"properties": {"query": {"type": "string"}},
|
|
189
|
+
"required": ["query"],
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
def __init__(self, env=None):
|
|
193
|
+
self.workspace = env.workspace_dir if env else "."
|
|
194
|
+
|
|
195
|
+
def execute(self, query: str) -> tuple[int, str]:
|
|
196
|
+
# Query local database in self.workspace
|
|
197
|
+
return 0, "Query results..."
|
|
198
|
+
|
|
199
|
+
def get_tools(env=None):
|
|
200
|
+
return [DatabaseTool(env)]
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
##### Option C: Module-Level `tools` List
|
|
204
|
+
Export an explicit list of pre-instantiated tool instances:
|
|
205
|
+
```python
|
|
206
|
+
# .microharness/tools/helpers.py
|
|
207
|
+
tools = [ToolOne(), ToolTwo()]
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Working on Existing Projects
|
|
213
|
+
|
|
214
|
+
By default, the agent runs directly in your **current working directory** (like Claude Code or Aider). It sees all your existing files, respects git, and resumes right where you left off:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# Operates directly on the current directory:
|
|
218
|
+
uv run microharness "Inspect the files in this directory and explain the architecture"
|
|
219
|
+
|
|
220
|
+
# Or point to any other project directory with -d:
|
|
221
|
+
uv run microharness -d /path/to/my-project "Fix the bug in auth.py"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
If you ever want an isolated disposable scratchpad (e.g. for testing without touching real files), pass `--sandbox`:
|
|
225
|
+
```bash
|
|
226
|
+
uv run microharness --sandbox "Experiment with writing a new scraper"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Docker Sandboxing (via OrbStack or Docker Desktop)
|
|
230
|
+
For 100% containerized process, operating system, and filesystem isolation (e.g. running untrusted code, heavy test suites, or SWE benchmarks), pass `--docker`:
|
|
231
|
+
```bash
|
|
232
|
+
# Run educational demo inside an isolated Linux Docker container
|
|
233
|
+
uv run microharness --demo calculator --docker
|
|
234
|
+
|
|
235
|
+
# Run the Mini-SWE benchmark suite inside Docker
|
|
236
|
+
uv run microharness --benchmark mini-swe --docker
|
|
237
|
+
|
|
238
|
+
# Specify a custom Docker image (default: python:3.11)
|
|
239
|
+
uv run microharness --docker --docker-image python:3.11 "Run pytest and fix bugs"
|
|
240
|
+
```
|
|
241
|
+
* **Instant Hybrid I/O**: The workspace directory is mounted at `/workspace`. File reading, writing, and editing occur on the host filesystem with zero container latency, while all bash commands execute inside the isolated Docker Linux container via `docker exec`.
|
|
242
|
+
* **Zero Runtime Dependencies**: Operates entirely via Python's standard library `subprocess` without third-party Docker SDKs. Works out of the box with **OrbStack** or standard Docker Desktop.
|
|
243
|
+
* **Automatic Teardown**: Containers are automatically stopped and removed upon task completion with zero orphaned background containers.
|
|
244
|
+
|
|
245
|
+
If you prefer a one-and-done batch run (e.g. for CI), pass `--batch`:
|
|
246
|
+
```bash
|
|
247
|
+
uv run microharness "Run pytest and fix any failures" --batch
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Continuous Interactive Chat & Meta-Commands
|
|
253
|
+
|
|
254
|
+
When you chat with the agent, the harness maintains persistent memory and renders a clean **context budget status line** before every turn:
|
|
255
|
+
|
|
256
|
+
```text
|
|
257
|
+
─── Context: 1.4k / 8k (17.8%) ───
|
|
258
|
+
You:
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Slash Commands (No Model Call)
|
|
262
|
+
You can inspect or control the harness runtime directly:
|
|
263
|
+
|
|
264
|
+
* **`/model [name|number]`**: Inspect available models or switch active model dynamically on the fly (e.g. `/model fast` or `/model 2`). In TUI mode, Tab autocompletes configured model names. A name is matched against the `models` aliases in `config.json`, their underlying model ids, and the provider registry (`openai` or `openai/gpt-4o` both work). An unrecognized name is **rejected with the list of valid models** rather than silently constructing a client for a model that does not exist. The `--model` startup flag applies the same recognition rules but only warns on stderr, so it remains usable for endpoints whose provider is not in the registry.
|
|
265
|
+
* **`/resume [id|number]`**: List previous sessions in `~/.microharness/runs/` (with workspace affinity) or resume conversation history from an earlier session in-place. Discovery reads only the newest sessions first and falls back to a full scan when your repository has no recent session, so an older session for the same repo stays reachable.
|
|
266
|
+
* **`/cache [5m|1h|off]`**: Inspect or switch prompt caching duration on the fly (`5m` standard ephemeral, `1h` extended beta, or `off`).
|
|
267
|
+
* **`/status`**: Displays detailed memory metrics (system, user, assistant, and tool counts + budget percentage) and prompt cache hit rates.
|
|
268
|
+
* **`/compact`**: Manually triggers memory compaction to prune older tool observations and reclaim context space.
|
|
269
|
+
* **`/new`**: Starts a fresh conversation context while keeping all your project files intact.
|
|
270
|
+
* **`/help`**: Lists available commands.
|
|
271
|
+
* **`/exit`**: Finalizes and exports the session trace.
|
|
272
|
+
|
|
273
|
+
### Cancelling a Running Turn
|
|
274
|
+
|
|
275
|
+
The two cancel keys are **not** equivalent, and the status bar says so while a turn runs:
|
|
276
|
+
|
|
277
|
+
* **`Ctrl+C`** aborts the active step immediately, including a request that is already in flight. The incomplete tool turn is dropped and the session stays usable.
|
|
278
|
+
* **`Esc`** is a cooperative cancel. It takes effect at the next step boundary and while the model waits between retries (for example during a throttle backoff). The moment it is seen the UI prints `Cancelling… aborting the pending model request` and abandons the wait.
|
|
279
|
+
|
|
280
|
+
`Esc` cannot abort a request that is currently waiting on the provider, because the HTTP timeout covers time-to-first-byte and shortening it would break slow models. Use `Ctrl+C` for that. See SPEC.md §5.2 for the planned work to unify the two.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Quickstart with `uv`
|
|
285
|
+
|
|
286
|
+
### 1. Install & Sync Environment
|
|
287
|
+
```bash
|
|
288
|
+
uv sync
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### 2. Run the Test Suite
|
|
292
|
+
```bash
|
|
293
|
+
uv run pytest
|
|
294
|
+
```
|
|
295
|
+
*(All 250+ unit and integration tests run in ~7s. Correctness guarantees are enforced by mutation testing — see SPEC.md §4.)*
|
|
296
|
+
|
|
297
|
+
### 3. Interactive and TUI Sessions
|
|
298
|
+
```bash
|
|
299
|
+
# Launch interactive mode (full-screen TUI):
|
|
300
|
+
uv run microharness
|
|
301
|
+
|
|
302
|
+
# Resume previous interactive session:
|
|
303
|
+
uv run microharness --resume
|
|
304
|
+
|
|
305
|
+
# Resume a specific session by ID:
|
|
306
|
+
uv run microharness --resume run-2026-10-03-xxxx
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### 4. Run Mini-SWE for Rapid Sanity Testing
|
|
310
|
+
Run the lightweight 5-task sanity test suite before launching heavy benchmarks:
|
|
311
|
+
```bash
|
|
312
|
+
# Run the entire Mini-SWE sanity benchmark suite:
|
|
313
|
+
uv run microharness --benchmark mini-swe
|
|
314
|
+
|
|
315
|
+
# Filter to a specific challenge (e.g. rate_limiter or query_builder):
|
|
316
|
+
uv run microharness --benchmark mini-swe --task rate_limiter
|
|
317
|
+
|
|
318
|
+
# Built-in demo tasks:
|
|
319
|
+
uv run microharness --demo calculator
|
|
320
|
+
uv run microharness --demo greeting
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Mini-SWE Benchmark Suite (Sanity & Smoke Testing)
|
|
326
|
+
|
|
327
|
+
`microharness` includes **Mini-SWE**, a fast, lightweight, pure-Python benchmark designed primarily for **rapid sanity testing, local iteration, and CI smoke testing**:
|
|
328
|
+
|
|
329
|
+
* **Sanity Testing Focus**: Validates the agent's tool-calling loop, multi-turn file editing, memory compaction, and test assertion grading in seconds—without burning model quota or waiting on multi-hour containerized benchmarks.
|
|
330
|
+
* **Pure Python & Zero Docker**: Operates entirely with Python's standard library. No multi-gigabyte container downloads, instant startup.
|
|
331
|
+
* **Anti-Cheating Evaluator (`PristineTestEvaluator`)**: Evaluators restore pristine test files prior to running verification. An agent cannot bypass tests by deleting or rewriting assertions in the test suite.
|
|
332
|
+
* **5 Realistic Engineering Challenges**:
|
|
333
|
+
1. `rate_limiter`: Token Bucket rate limiter losing fractional refills under rapid polling.
|
|
334
|
+
2. `circular_serializer`: Circular JSON serializer cycle detection & ISO-8601 formatting.
|
|
335
|
+
3. `auth_middleware`: HTTP auth middleware case-insensitive headers & whitespace tolerance.
|
|
336
|
+
4. `lru_ttl_cache`: LRU cache with TTL updating existing keys & refreshing MRU order.
|
|
337
|
+
5. `query_builder`: SQL query builder AST precedence grouping & single-quote escaping.
|
|
338
|
+
* **Automated Scorecard & JSON Telemetry**: Generates a formatted summary table in the terminal and exports comprehensive JSON results to `~/.microharness/runs/benchmark_report.json`.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## DeepSWE-mini Benchmark Suite (Harbor Format & Docker)
|
|
343
|
+
|
|
344
|
+
`microharness` natively supports **DeepSWE-mini** (curated from [Datacurve-AI DeepSWE](https://github.com/datacurve-ai/deep-swe) and [`LocalLLaMA/deepswe-mini`](https://huggingface.co/datasets/LocalLLaMA/deepswe-mini)):
|
|
345
|
+
|
|
346
|
+
* **16 Curated Real-World Repositories**: Across Python, Go, and TypeScript (e.g. `aiomonitor`, `bandit`, `ipython`, `narwhals`, `textual`, `prometheus`, `valibot`, `dasel`).
|
|
347
|
+
* **Harbor Standard Compliance**: Automatically parses `task.toml` metadata (via Python 3.11's standard library `tomllib`), pulls task ECR container images, mounts behavioral verifiers, and grades via `tests/grader.py`.
|
|
348
|
+
* **Zero Dependency Container Sandboxing**: Spawns isolated Docker containers via **OrbStack** or Docker Desktop, syncs repo code at NVMe speed, and automatically captures `model.patch` diffs.
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
# Clone tasks once (only ~3.5MB repository metadata):
|
|
352
|
+
git clone --depth 1 https://github.com/datacurve-ai/deep-swe datasets/deep-swe
|
|
353
|
+
|
|
354
|
+
# Run the entire 16-task DeepSWE-mini benchmark suite in Docker:
|
|
355
|
+
uv run main.py --benchmark deepswe-mini --docker
|
|
356
|
+
|
|
357
|
+
# Run a specific task with custom step & timeout budgets:
|
|
358
|
+
uv run main.py --benchmark deepswe-mini --task aiomonitor --max-steps 500 --timeout 7200 --docker
|
|
359
|
+
|
|
360
|
+
# Run with official Datacurve Pier framework using microharness adapter:
|
|
361
|
+
uvx --from datacurve-pier pier run -p datasets/deep-swe/tasks/aiomonitor-task-snapshots-diff \
|
|
362
|
+
--agent-import-path benchmarks.pier_agent:MicroharnessAgent --env docker
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## True Pluggability (Zero Code Modifications)
|
|
368
|
+
|
|
369
|
+
Because components follow minimal Python `Protocols`, you can plug in any Model, Tool, or Evaluator from the outside without touching a single line of harness code:
|
|
370
|
+
|
|
371
|
+
```python
|
|
372
|
+
from core.harness import Harness
|
|
373
|
+
|
|
374
|
+
# In-place coding agent on your repo with global and project steering:
|
|
375
|
+
harness = Harness(
|
|
376
|
+
model=my_custom_model, # Or HttpChatModel(endpoint, model, key)
|
|
377
|
+
workspace_dir=".", # Works directly on your project
|
|
378
|
+
global_dir="~/.microharness", # Global config, instructions & skills
|
|
379
|
+
tools=[bash_tool, my_tool], # Custom tools (dynamically documented in system prompt)
|
|
380
|
+
)
|
|
381
|
+
harness.run_tui("Help me refactor the database layer")
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## Key Educational Paradigms Demonstrated
|
|
387
|
+
|
|
388
|
+
1. **In-Place Project Operation vs. Sandboxing (`core/environment.py`)**
|
|
389
|
+
- By default, operates directly on existing project files with zero root directory pollution.
|
|
390
|
+
- Optional `--sandbox` creates an isolated scratchpad in `~/.microharness/runs/` (or `--runs-dir`).
|
|
391
|
+
- Prevents path traversal outside project boundaries while permitting read access to authorized global directories (`allowed_read_dirs`).
|
|
392
|
+
- Executes bash with timeouts and combined stdout/stderr.
|
|
393
|
+
|
|
394
|
+
2. **Cascading Configuration & Steering (`core/harness.py`)**
|
|
395
|
+
- Loads global defaults from `~/.microharness/config.json`.
|
|
396
|
+
- Injects global user instructions (`~/.microharness/AGENTS.md`) and project instructions (`./AGENTS.md`) in cascading order.
|
|
397
|
+
- Discovers `skills/` and `commands/` globally and locally; project definitions cleanly shadow global ones.
|
|
398
|
+
- Indexes skills lazily with scope badges to conserve context tokens.
|
|
399
|
+
|
|
400
|
+
3. **Targeted File Editing vs. Full Rewrites (`core/tools.py`)**
|
|
401
|
+
- Built-in `edit_file(path, old_str, new_str)` enforces exact, unique string replacement.
|
|
402
|
+
- Prevents token wastage and LLM hallucination bugs common when rewriting large files with `write_file`.
|
|
403
|
+
|
|
404
|
+
4. **Dynamic Tool Introspection (`core/tools.py`)**
|
|
405
|
+
- `ToolRegistry.to_system_prompt_snippet()` automatically reflects registered tools in the system prompt. Custom tools require zero prompt tweaking.
|
|
406
|
+
|
|
407
|
+
5. **Large Log Handling & Spillover (`core/tools.py`)**
|
|
408
|
+
- Massive command outputs are head + tail truncated.
|
|
409
|
+
- The full, raw output is spilled to `~/.microharness/runs/<run_id>/logs/` so it never pollutes the user's project root.
|
|
410
|
+
|
|
411
|
+
6. **Proactive 80% Context Compaction & Memory Optimization (`core/memory.py`)**
|
|
412
|
+
- Proactively prunes older tool observations at an 80% high-water mark (`trigger_ratio = 0.80`), keeping 20% reserved for output tokens and model reasoning.
|
|
413
|
+
- **Enriched Tombstones with Log Pointers**: Collapsed tool outputs embed the exact spilled log file path (`Full log: <path>. Use read_file to inspect if needed.`), giving the agent a deterministic bridge to inspect full outputs.
|
|
414
|
+
- **Historical Reasoning Pruning**: Automatically prunes transient `<think>...</think>` and `<thinking>...</thinking>` reasoning streams from older assistant turns to reclaim thousands of tokens for reasoning models (DeepSeek-R1, Claude Thinking, o1/o3).
|
|
415
|
+
- **Session Files Modified Ledger**: Injects and maintains an active session ledger (`[Session Files Modified: file1.py, file2.py]`) across compactions at the safe prefix.
|
|
416
|
+
- Preserves system prompt, initial task, and recent working turns.
|
|
417
|
+
|
|
418
|
+
7. **Git Patch Export (`patch.diff`) & Modern CLI Tracing (`core/tracer.py`)**
|
|
419
|
+
- Automatic git diff extraction: generates `patch.diff` for coding tasks in git repositories.
|
|
420
|
+
- **Modern Developer CLI Output**: Eliminates academic ReAct tags (`Thought:` / `Action:` / `Observation:`) in favor of natural assistant speech, `$ <command>` execution, `● Read/Write/Edit <path>`, real-time duration headers, and clean output gutters.
|
|
421
|
+
- Persists machine-readable `trace.json` and human-readable `trace.md` in `~/.microharness/runs/<run_id>/` for every run.
|
|
422
|
+
|
|
423
|
+
8. **Automated Evaluation (`core/evaluator.py`)**
|
|
424
|
+
- Evaluators test whether the agent actually succeeded (e.g. running test commands, asserting file contents, or Docker-based SWE-bench graders).
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Project Structure
|
|
429
|
+
|
|
430
|
+
```
|
|
431
|
+
microharness/
|
|
432
|
+
├── pyproject.toml # Modern PEP 621 packaging for uv & hatchling
|
|
433
|
+
├── uv.lock # Deterministic lockfile generated by uv
|
|
434
|
+
├── SPEC.md # Detailed specification & design rationale
|
|
435
|
+
├── README.md # Quickstart and overview
|
|
436
|
+
├── AGENTS.md # Project conventions for agents
|
|
437
|
+
├── .microharness/ # Clean project-level configuration namespace
|
|
438
|
+
│ ├── skills/ # Progressive disclosure skills
|
|
439
|
+
│ │ └── run-tests/
|
|
440
|
+
│ │ └── SKILL.md
|
|
441
|
+
│ └── commands/ # Custom slash commands (user prompt shortcuts)
|
|
442
|
+
│ └── review.md
|
|
443
|
+
├── .env.example # Environment variable template
|
|
444
|
+
├── main.py # Runnable demonstration & CLI entrypoint
|
|
445
|
+
├── benchmarks/ # SWE benchmark suites & runners
|
|
446
|
+
│ ├── mini_swe.py # 5 real-world pure-Python SWE tasks & PristineTestEvaluator
|
|
447
|
+
│ ├── harbor.py # Harbor / DeepSWE-mini benchmark loader & Docker verifier adapter
|
|
448
|
+
│ ├── pier_agent.py # Datacurve Pier framework agent adapter (MicroharnessAgent)
|
|
449
|
+
│ └── runner.py # Benchmark orchestrator, scorecard table & incremental JSON report export
|
|
450
|
+
├── core/
|
|
451
|
+
│ ├── types.py # Clean dataclasses (Message, ToolCall, Task, Trajectory, RunResult)
|
|
452
|
+
│ ├── prompts.py # System prompt templates & prompt assembly
|
|
453
|
+
│ ├── environment.py # Workspace & bash runner (supports in-place and sandbox)
|
|
454
|
+
│ ├── tools.py # Pluggable tool protocol & built-ins (bash, read_file, write_file)
|
|
455
|
+
│ ├── memory.py # Context manager & 80% high-water mark compaction
|
|
456
|
+
│ ├── protocols.py # Model protocol, capability protocols (cache, deadline, cancel) & cancellation
|
|
457
|
+
│ ├── usage.py # Token normalization, per-model telemetry & run-level totals
|
|
458
|
+
│ ├── providers.py # Provider registry, model-spec resolution & client construction
|
|
459
|
+
│ ├── model.py # Generic HttpChatModel & MockModel clients
|
|
460
|
+
│ ├── config.py # Cascading configuration, JSONC reading & setting resolution
|
|
461
|
+
│ ├── skills.py # Progressive-disclosure skills (discovery, summaries, activation)
|
|
462
|
+
│ ├── commands.py # Custom slash commands & slash-input resolution
|
|
463
|
+
│ ├── discovery.py # Hierarchical resource discovery & @file-tagging
|
|
464
|
+
│ ├── interactive.py # Interactive command router shared by the CLI session & the TUI
|
|
465
|
+
│ ├── session.py # Step driver, session index, resumption & trace reconstruction
|
|
466
|
+
│ ├── loop.py # Native tool-calling loop (~40 lines)
|
|
467
|
+
│ ├── evaluator.py # Automated graders (CommandTestEvaluator, FileContentEvaluator)
|
|
468
|
+
│ ├── tracer.py # Telemetry collector, modern CLI renderer & trace exporter
|
|
469
|
+
│ ├── tui.py # Full-screen curses TUI (markdown rendering, autocomplete)
|
|
470
|
+
│ ├── tui_session.py # TUI turn driver: step rendering & cooperative cancellation
|
|
471
|
+
│ └── harness.py # Harness orchestrator wiring the chassis together
|
|
472
|
+
└── tests/
|
|
473
|
+
├── test_benchmarks.py # Mini-SWE baseline failure, anti-cheating & reference tests
|
|
474
|
+
├── test_harbor.py # Harbor task parsing, Docker image validation & evaluator tests
|
|
475
|
+
├── test_environment.py # Path sandboxing & bash timeout tests
|
|
476
|
+
├── test_tools.py # Tools, truncation & disk spillover tests
|
|
477
|
+
├── test_memory.py # Conversation history, stats & 80% compaction tests
|
|
478
|
+
├── test_model.py # Endpoint normalization, serialization & mock model tests
|
|
479
|
+
├── test_evaluator.py # Grader assertions tests
|
|
480
|
+
├── test_config.py # Config cascade, JSONC parsing & tool-trust boundary tests
|
|
481
|
+
├── test_protocols.py # Capability protocol detection tests
|
|
482
|
+
├── test_usage.py # Token normalization & telemetry accounting tests
|
|
483
|
+
├── test_providers.py # Provider registry, model specs & available-model tests
|
|
484
|
+
├── test_skills.py # Skill discovery, summaries & activation tests
|
|
485
|
+
├── test_commands.py # Slash-command discovery, expansion & resolution tests
|
|
486
|
+
├── test_prompts.py # Prompt assembly & AGENTS.md cascading tests
|
|
487
|
+
├── test_session.py # Step driver retries, deadlines & session resumption tests
|
|
488
|
+
├── test_interactive.py # Command router & rendering tests
|
|
489
|
+
├── test_tui_session.py # TUI turn rendering & cancellation tests
|
|
490
|
+
└── test_harness.py # End-to-end lifecycle, global config, commands & guardrails tests
|
|
491
|
+
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# feat: make TUI default, add local providers, non-blocking execution, and token limits
|
|
2
|
+
|
|
3
|
+
## Summary of Changes
|
|
4
|
+
|
|
5
|
+
This PR modernizes the interactive developer experience, provider registry, and context limits across `microharness`:
|
|
6
|
+
|
|
7
|
+
1. **TUI as Default Interactive Interface**:
|
|
8
|
+
- `Harness.run_interactive()` launches the full-screen Curses TUI by default.
|
|
9
|
+
- Removed legacy `ConsoleUI`; interactive mode is now 100% full-screen TUI.
|
|
10
|
+
- Headless execution is strictly handled via `--batch` (or `Harness.run(task)` in code). If an interactive run is attempted without a TTY, the CLI provides helpful guidance to use `--batch`.
|
|
11
|
+
- Single entrypoint in `main.py` without introducing extra CLI modules into `core/`.
|
|
12
|
+
|
|
13
|
+
2. **Non-Blocking Curses Execution & Thread-Safe Redraw**:
|
|
14
|
+
- Agent turns run asynchronously on a background worker thread (`worker_thread`), with non-blocking key polling (`stdscr.timeout(50)`).
|
|
15
|
+
- Thread-safe drawing synchronization using `_draw_lock` prevents curses race conditions and display corruption.
|
|
16
|
+
- Status spinner and UI remain responsive while model/tool execution takes place.
|
|
17
|
+
|
|
18
|
+
3. **Safe Escape Key Handling**:
|
|
19
|
+
- Pressing <kbd>Esc</kbd> during an active turn signals execution cancellation (`_cancel_requested = True`).
|
|
20
|
+
- Pressing <kbd>Esc</kbd> when idle dismisses menus, clears autocomplete queries, or clears input buffer.
|
|
21
|
+
- **Never exits the session on an empty prompt** when pressing <kbd>Esc</kbd> (exit is via `/exit` or <kbd>Ctrl+C</kbd> / <kbd>Ctrl+D</kbd>).
|
|
22
|
+
|
|
23
|
+
4. **Interactive Reasoning / Thinking Effort Control**:
|
|
24
|
+
- Added interactive `/reasoning` popup menu in TUI with choices: `off`, `low`, `medium`, `high`, `xhigh`, `max`.
|
|
25
|
+
- Dynamic update of active reasoning effort in TUI header and model serialization.
|
|
26
|
+
- Support for `xhigh` and `max` levels across model payloads (OpenAI and OpenRouter specs).
|
|
27
|
+
|
|
28
|
+
5. **First-Class Local Provider Presets & Scoped Endpoints**:
|
|
29
|
+
- Added built-in presets for local inference engines in [`core/providers.json`](file:///Users/dimakagan/Projects/mini-harness/core/providers.json): `lmstudio` (`http://localhost:1234/v1`), `vllm` (`http://localhost:8000/v1`), `llamacpp` (`http://localhost:8080/v1`), `ollama` (`http://localhost:11434/v1`), and generic `local`.
|
|
30
|
+
- Added provider aliases (`lm-studio`, `llama-cpp`, `llama.cpp`).
|
|
31
|
+
- Preserved `LAST_RESORT_MODEL = "cohere/north-mini-code:free"` and configured `anthropic/claude-5.5-sonnet` / `claude-5.5-sonnet` frontier models.
|
|
32
|
+
- Fixed endpoint scoping: models defined under `models: { ... }` in config retain their provider-specific endpoints without being overwritten by top-level defaults.
|
|
33
|
+
|
|
34
|
+
6. **Unified Model Naming (`default_model` / `defaultModel`)**:
|
|
35
|
+
- Supports `default_model` and `defaultModel` keys with precedence over legacy `model` in configuration.
|
|
36
|
+
- Clean documentation and schema examples throughout README.
|
|
37
|
+
|
|
38
|
+
7. **Token-Only Context and Tool Limits**:
|
|
39
|
+
- Fully replaced `max_context_chars` and `max_tool_chars` with `max_context_tokens` (default 64,000 tokens ≈ 256k chars) and `max_tool_tokens` (default 8,000 tokens ≈ 32k chars).
|
|
40
|
+
- `HarnessConfig`, `ResolvedConfig`, `Harness`, `Memory`, and `ToolRegistry` expose only token limits.
|
|
41
|
+
- Legacy character settings from old config files are automatically converted to tokens during resolution.
|
|
42
|
+
- Head (1/3 ≈ 10.6k chars) + Tail (2/3 ≈ 21.3k chars) preservation for tool outputs (at default 8,000 tokens) with disk log spillover.
|
|
43
|
+
|
|
44
|
+
8. **Robust TUI Thread Safety & Cancellation UX**:
|
|
45
|
+
- `TUIState` protects transcript mutations and line slices under `threading.RLock()`.
|
|
46
|
+
- Curses rendering calls are kept strictly on the main thread via `request_redraw()` across both `TuiUI` and `TuiTurnRunner.refresh()`, eliminating background thread curses calls.
|
|
47
|
+
- Submitting Enter while a turn is running gives immediate feedback (`⏳ Turn is running (press Esc or Ctrl+C to cancel)`).
|
|
48
|
+
- `Harness.run_tui(task_id="interactive_session")` standardizes run-directory naming, with `allow_bare_words=True` enabled for interactive shell commands.
|
|
49
|
+
|
|
50
|
+
9. **Configuration Migration & Backward Compatibility**:
|
|
51
|
+
- `get_default_global_dir()` gracefully falls back to `~/.mini-harness` if `~/.microharness` does not exist.
|
|
52
|
+
- Legacy `max_tool_chars` and `max_context_chars` in configuration files are automatically converted to tokens (`chars // 4`).
|
|
53
|
+
- Re-exported `find_recent_sessions`, `load_session_messages`, and `reconstruct_messages_from_steps` in `core.tracer` for backward compatibility.
|
|
54
|
+
|
|
55
|
+
10. **Portable Reasoning Effort**:
|
|
56
|
+
- Maps `xhigh` and `max` to `"high"` on standard OpenAI endpoints to prevent API validation 400 errors, while preserving full values on OpenRouter endpoints.
|
|
57
|
+
|
|
58
|
+
11. **Offline Interactive Guidance**:
|
|
59
|
+
- Interactive TUI launch verifies endpoint and credentials via `Connection.missing_credentials` (handling local vs cloud providers uniformly) and fails fast with setup instructions, while headless batch and benchmark runs continue using `MockModel` when offline.
|
|
60
|
+
|
|
61
|
+
## Verification & Testing
|
|
62
|
+
|
|
63
|
+
- **Zero Runtime Dependencies**: Standard library only (`pyproject.toml` dependencies remain empty).
|
|
64
|
+
- **Correct Repository URLs**: Pointing to `https://github.com/Kagandi/microharness`.
|
|
65
|
+
- **Unit Test Suite**: 557 passing tests (`uv run pytest`):
|
|
66
|
+
- `tests/test_config.py` (token limits, legacy char migration, global dir fallback, cascade priority, reasoning choices)
|
|
67
|
+
- `tests/test_harness.py` (TUI defaults, headless NullUI, session handling)
|
|
68
|
+
- `tests/test_interactive.py` (model switching runner synchronization, reasoning status update)
|
|
69
|
+
- `tests/test_memory.py` (token limits, high-water mark compaction)
|
|
70
|
+
- `tests/test_model.py` (reasoning effort mapping for OpenAI vs OpenRouter)
|
|
71
|
+
- `tests/test_providers.py` (local provider presets, scoped endpoints)
|
|
72
|
+
- `tests/test_tools.py` (token limits and spillover)
|
|
73
|
+
- `tests/test_tui.py` (Esc key safety, reasoning subcommand menus, non-blocking threading)
|
|
74
|
+
- `tests/test_tui_session.py` (turn runner lifecycle, request_redraw dispatching, Esc cancellation)
|
|
75
|
+
- **Lint & Style**: Passed `uv run ruff check` with 0 warnings.
|