feat(adapters): multi-agent support via ACP preset registry#55
Merged
Conversation
2cb9df9 to
e878edc
Compare
Integrate coding agents through two paths: the pre-existing native
stream-json adapters (claude, kimi) and one new AcpAdapter speaking the
Agent Client Protocol (JSON-RPC over stdio) for everything else.
- presets.py: AgentPreset registry — per-tool launch command, env, and
worktree config dirs as pure data; user presets via .owloop/agents.toml;
${VAR} env expansion and {model} substitution
- acp.py: hand-rolled minimal ACP client (initialize → session/new →
session/prompt), streams session/update into on_line, answers
session/request_permission with allow_once (never bypass/YOLO modes),
maps usage_update → TokenTracker and stopReason → AgentResult
- builtin presets: claude-acp, codex, opencode, qoder, kiro, gemini,
qwen, plus glm/deepseek via their official Anthropic-compatible
endpoints through the Claude ACP adapter
- get_adapter() resolves presets; --agent accepts any preset key; new
'owloop agents' command lists presets with readiness status
- engine copies adapter-declared config dirs into worktrees
- tests: scripted fake ACP agent subprocess covering happy path,
permission round-trip, refusal, hang/timeout, crash, missing binary/env
Closes #50 phases 1-3
tomllib only exists in the stdlib from 3.11; the CI matrix runs 3.10 on ubuntu/macos where user-preset parsing raised RuntimeError. Depend on tomli (the tomllib reference backport) for python_version < 3.11.
cb2d92c to
ffcefbe
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements phases 1–3 of #50: owloop now supports Claude Code, Codex, OpenCode, Qoder, Kimi, GLM, DeepSeek, Kiro (and Gemini/Qwen for free) through a single protocol-level integration.
Rebased onto #52 (Phase 1 trust & safety core): the ACP path composes cleanly with the new engine-owned verification gate — the agent signals DONE over ACP, then the engine runs the acceptance criteria itself and owns commit/push.
What changed
src/owloop/presets.py— agent preset registry (Phase 1)AgentPresetdataclass: launch command, extra env (${VAR}references resolved from the user's environment at spawn time,{model}placeholder), worktree config dirs, experimental flag — per-tool knowledge is pure data, never code.owloop/agents.toml(can also override builtins)src/owloop/acp.py— oneAcpAdapterfor all non-native agents (Phase 2)initialize→session/new→session/prompt, one fresh process + session per iteration (preserves fresh-context-per-iteration)session/updateinto the existingon_linedisplay conventions;usage_update→TokenTracker;stopReasondecides successsession/request_permissionitself, preferringallow_once— agents are never launched in bypass/YOLO modes ("Auto Mode, not YOLO" now enforced by the harness, not just hoped for)Presets (Phase 3)
claude-acp,codex,opencode,qoder,kiro,gemini,qwenglm/deepseek: their officially documented path is an Anthropic-compatible endpoint, so both ride the Claude ACP adapter withANTHROPIC_BASE_URL/ANTHROPIC_AUTH_TOKEN/model env — zero extra code (GLM:api.z.ai/api/anthropic, modelglm-5.2; DeepSeek:api.deepseek.com/anthropic, modeldeepseek-v4-pro— deliberately not the deprecateddeepseek-chat/deepseek-reasoner)owloop agentsoutputWiring
get_adapter()resolves through the registry;claude/kimikeep their native stream-json adapters unchanged (including feat(engine): Phase 1 trust & safety core — enforced verification, terminal states, rollback (#37) #52'smax_turns/max_budget_usdpassthrough)--agentaccepts any preset key (builtin or user-defined); newowloop agentscommand shows readiness (binary found, missing env vars, experimental)OwloopEngine.setup_worktree()copies adapter-declared config dirs (e.g..qoder/) in addition to.claude/Testing
tests/fake_acp_agent.py: scripted fake ACP agent run as a real subprocess — deterministic, no network. Scenarios: full happy turn, permission round-trip (the fake agent only emits DONE if the client selected theallow_onceoption, proving the auto-answer policy), refusal, hang → idle timeout, crash → stderr-tail diagnostics, missing binary, missing env vartests/test_presets.py: registry coverage of all requested agents, env expansion, model placeholder, official endpoint/model assertions for GLM/DeepSeek,agents.tomlload/overrideruffandmypycleanagents.tomlcustom preset +owloop run --agent faketool --no-tui -n 1completes a full iteration — ACP streaming, DONE promise, engine verification gate passes, engine commitsowloop: complete 01-demo.md, terminal statesuccessCloses #50 (phases 1–3; phase 4 — flipping
claude/kimidefaults to ACP — deferred per the issue).