feat: ACP integration — migrate executor layer to Agent Client Protocol#361
Open
zhengxuyu wants to merge 17 commits into
Open
feat: ACP integration — migrate executor layer to Agent Client Protocol#361zhengxuyu wants to merge 17 commits into
zhengxuyu wants to merge 17 commits into
Conversation
…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]>
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.
Summary
/api/internal/tool-call(including LangChain, which previously ran in-process)ACP_UPDATEevent type bridges ACP streaming updates to frontend via EventBus/WebSocketresume_sessionfor crash recovery,load_sessionfor hot reloadacp/adapter.py) isolates all ACP SDK imports for future v1.0 migrationnotify_ceofire-and-forget tool replaces blocking escalationStats
src/onemancompany/acp/Test plan
🤖 Generated with Claude Code