Add a configurable image_generation tool with OpenAI-compatible and Codex hosted providers, propagate generated media metadata through stream events, and let ohmo channels send generated image/file paths automatically.
Support absolute glob patterns without crashing and retry ohmo channel messages without ImageBlocks when a provider rejects image input.\n\nFixes #225\nFixes #226
Add /model list/add/remove/clear so a single provider profile can expose multiple switchable models in the TUI selector. Also add regression coverage for invalid grep regexes in the Python fallback.\n\nFixes #222\nRefs #218
* fix(tools): todo_write updates existing items in-place instead of duplicating
When an agent marks a todo item done by calling todo_write with
checked=True, the tool previously always appended a new [x] line,
leaving the original [ ] line intact. This produced duplicate entries.
The tool now performs an upsert:
- If the item exists as [ ], replace it with [x] in-place.
- If it is already in the target state, return a no-op result.
- Otherwise, append as before.
Adds test_todo_write_upsert to cover the new behaviour.
Co-authored-by: Copilot
* fix(tools): simplify todo_write tool description for LLM clarity
Co-authored-by: Copilot
---------
Co-authored-by: JiangYulin <yulin@JiangYulindeMacBook-Pro.local>
When non-Anthropic models (MiniMax, Moonshot, etc.) call MCP tools, they
sometimes send `null` for parameters they consider optional. The previous
implementation typed all fields as `object | None`, so:
1. Pydantic accepted `null` even for required fields (e.g. `query`)
2. `model_dump()` serialized these as `{"query": null, ...}`
3. The MCP server received null for required parameters → validation error
Fix:
- Map JSON Schema types to proper Python types (string→str, integer→int,
etc.) so Pydantic rejects null for required fields
- Use `exclude_none=True` in model_dump to strip optional null parameters
before passing to the MCP server
This affects ALL MCP tool servers, not just specific ones.
Tested with: MiniMax-M2.7-highspeed + dongtian MCP server (15 tools).
Two tests covering the fix from PR #60:
1. test_agent_tool_uses_subprocess_backend_and_task_is_pollable
- Spawns an agent via AgentTool
- Asserts backend=subprocess in the output (not in_process)
- Asserts the returned task_id has no "in_process_" prefix
- Asserts get_task_manager().get_task(task_id) finds the record,
proving that task tools (TaskGet, TaskOutput, etc.) would succeed
2. test_send_message_swarm_path_uses_subprocess_backend
- Patches SubprocessBackend.send_message as an AsyncMock
- Calls SendMessageTool with a name@team task_id
- Asserts the mock was called (i.e. SubprocessBackend was used,
not InProcessBackend)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Update prompt assertions to match new OpenHarness system prompt
- Update agent definition tests (verification not verifier, tools=['*'])
- Add pytest.mark.skipif for tests needing real API or AutoAgent workspace
- Fix agent tool test for InProcessBackend same-name spawn conflict
- Fix flaky worktree test for CI environments
A lightweight open-source Python implementation of the Agent Harness architecture.
44x lighter than Claude Code (11K vs 512K lines), 98% core tool coverage.
- 43 tools with Pydantic validation and parallel execution
- Skills system compatible with anthropics/skills (17+ tested)
- Plugin system compatible with claude-code/plugins (12+ tested)
- API retry with exponential backoff
- Multi-level permissions with path rules
- React/Ink TUI with "Oh my Harness!" branding
- 114 unit tests + 6 E2E test suites
- MIT License