Skip to content

feat: ACP integration — migrate executor layer to Agent Client Protocol#361

Open
zhengxuyu wants to merge 17 commits into
mainfrom
feat/acp-integration
Open

feat: ACP integration — migrate executor layer to Agent Client Protocol#361
zhengxuyu wants to merge 17 commits into
mainfrom
feat/acp-integration

Conversation

@zhengxuyu
Copy link
Copy Markdown
Collaborator

Summary

  • Migrate all OMC executors (LangChain, Claude CLI, Script) to Agent Client Protocol (ACP)
  • EmployeeManager becomes ACP Client, each employee runs as persistent ACP Agent subprocess
  • All tool calls unified through HTTP /api/internal/tool-call (including LangChain, which previously ran in-process)
  • Non-blocking policy engine replaces CEO approval blocking — agents are fully autonomous with YAML-defined guardrails
  • Generic ACP_UPDATE event type bridges ACP streaming updates to frontend via EventBus/WebSocket
  • Session persistence: resume_session for crash recovery, load_session for hot reload
  • Multi-client support: stdio (EmployeeManager) + HTTP (IDE observers like VS Code/Zed)
  • Extended ACP: fork_session, set_session_mode (execute/plan/review), set_session_model, AvailableCommandsUpdate, set_config_option
  • Thin adapter layer (acp/adapter.py) isolates all ACP SDK imports for future v1.0 migration
  • notify_ceo fire-and-forget tool replaces blocking escalation

Stats

  • 42 files changed, +5,436 / -25 lines
  • 15 new source files in src/onemancompany/acp/
  • 56 new test functions (unit + integration + E2E stubs)
  • 4422 tests pass, 0 failures

Test plan

  • 123 adapter re-export tests
  • 7 policy engine tests (default allow, reject rules, missing YAML)
  • 4 events bridge tests
  • 4 agent process tests (initialize, session, prompt, cancel)
  • 7 LangChain backend tests (execute, HTTP proxy, on_log streaming)
  • 4 Claude CLI backend tests
  • 5 Script backend tests
  • 5 connection manager tests (spawn, handshake, heartbeat, prompt)
  • 6 vessel ACP integration tests (register_acp, mode mapping)
  • 5 session persistence tests (save, load, clear, hot reload)
  • 2 multi-client tests (IDE port discovery)
  • 6 extended capability tests (fork, mode, model, config)
  • 13 integration tests (roundtrip, crash recovery, heartbeat, hot reload)
  • 3 E2E test stubs (require running server)
  • Full regression suite green (4422 passed)

🤖 Generated with Claude Code

workspace and others added 17 commits April 29, 2026 10:39
…lient-protocol SDK

- Add `agent-client-protocol>=0.9.0` to pyproject.toml dependencies
- Create `src/onemancompany/acp/` package with adapter.py that re-exports all
  ACP SDK types (protocols, schema, helpers, transport, meta) in one place
- Create `tests/unit/acp/`, `tests/integration/acp/`, `tests/e2e/acp/` test directories
- Add 123-test suite in test_adapter.py covering every exported symbol

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
… interface

Define the AcpBackend protocol (executor_type, setup, teardown, build_task_env)
to standardize subprocess backend implementation. Uses Any types to avoid
circular imports with VesselConfig and TaskContext.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…tion

Implements Task 3: PolicyEngine evaluates tool calls against rules from
company_rules/permissions.yaml in <1ms with no human-in-the-loop.
Supports exact-tool, cost_usd_gt, and arbitrary context-key matching;
first-match-wins with configurable default (allow/reject).
Missing rules file falls back to allow-all with a warning log.
All 6 required TDD tests pass (7 collected, +1 bonus test).

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…payload.kind

Adds EventType.ACP_UPDATE to the enum, implements acp_update_to_event() in
acp/events_bridge.py, and covers all cases with 4 TDD unit tests. Frontend
renderers dispatch on payload.kind; adding new ACP update types requires no
bridge changes.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…ate, and lazy backend dispatch

Implements the ACP Agent protocol for employee subprocesses: initialize/
new_session/resume/load/fork/prompt/cancel/close_session lifecycle, 30s
heartbeat, session_state.json crash recovery, and lazy import of langchain/
claude_cli/script backends (Tasks 6-7). Also extends adapter.py with
SessionCapabilities, SessionMode, and SessionModeState re-exports.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…streaming

Adds LangChainAcpBackend that wraps EmployeeAgent inside the ACP subprocess.
All tool calls route through HTTP /api/internal/tool-call because the subprocess
cannot access parent-process ContextVars or company_state. The on_log callback
bridges sync LangChain streaming events to async ACP session_update calls by
scheduling Tasks and gathering them after run_streamed completes.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Implements ClaudeCliAcpBackend (delegates to run_claude_session daemon)
and ScriptAcpBackend (spawns launch.sh bash subprocess) with full TDD
test coverage — 9 tests, all passing.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Implements AcpConnectionManager (subprocess spawn, ACP handshake,
watchdog respawn, prompt/collect result cycle) and OMCAcpClient
(session_update classification → EventBus, permission policy, heartbeat,
IDE endpoint, usage_final tracking). Adds 5 unit tests covering spawn
handshake, unregister cleanup, heartbeat tracking, and prompt delegation.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…n path (Task 9)

Add ACP connection management to EmployeeManager in vessel.py:
- _acp_manager attribute with TYPE_CHECKING import to avoid circular deps
- register_acp() method: delegates to AcpConnectionManager, same bookkeeping as register()
- ACP branch in _execute_task(): set_mode + send_prompt + collect_result before legacy fallback
- _get_acp_mode() helper: maps NodeType to ACP session mode (review/execute)
- 6 unit tests covering registration, lazy init, config, and mode mapping

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- routes.py: GET /api/employees/{employee_id}/acp-endpoint returns the
  streamable-http port for IDE direct connection via _acp_manager
- common_tools.py: notify_ceo @tool sends a fire-and-forget CEO_SESSION_MESSAGE
  event without blocking the agent; registered in the base tool registry
- Replace silent `except RuntimeError: pass` with debug log to satisfy
  code quality gate

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
5 unit tests covering _save_session_state, resume_session state
restore, _clear_session_state file removal, graceful handling of
missing state file, and hot_reload_employee call sequence
(close_session → kill → spawn → initialize → load_session).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Tests for recording and retrieving IDE HTTP endpoints by employee.

- test_ide_endpoint_recorded: verify record/get roundtrip
- test_ide_endpoint_none_when_not_set: verify None return for unset endpoint

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…set_mode, set_model, set_config, and agent modes

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Add acp_update case to WebSocket message handler for logging ACP Claude events.
Handles message, thought, tool_call_start, tool_call_progress, plan, usage,
commands, and mode event kinds with appropriate debug logging.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Covers full end-to-end scenarios through AcpConnectionManager:
- test_subprocess_roundtrip: register → send_prompt → simulate usage_final → collect_result returns LaunchResult
- test_tool_call_roundtrip: ext_notification callbacks (heartbeat, usage_final, ide_endpoint) + session_update EventBus publish
- test_crash_recovery: watchdog detects crashed process (returncode≠None) + _respawn_employee restores connection state
- test_heartbeat: watchdog respawns on stale heartbeat; fresh heartbeats prevent respawn; record_heartbeat resets timer
- test_hot_reload: close→kill→spawn→load_session sequence; tolerates close_session errors; preserves executor_type/extra_env

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…tion

- test_full_flow.py: CEO assigns task → dispatch → execute → COMPLETED
- test_agent_coordination.py: Agent A dispatch_child to Agent B → both complete
- test_policy_rejection.py: Agent attempts destructive op → auto-rejected → adapts

All tests use pytest.mark.skip, requiring manual run with running OMC server.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant