-
Notifications
You must be signed in to change notification settings - Fork 0
feat: implement parallel agent execution (#22) #161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e515bf1
32de556
3b040ba
e67dc06
d06f71b
f75ec0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -805,6 +805,8 @@ Task ───┤ ├──▶ Integration ──▶ QA | |||||
| └──▶ Backend Dev ──┘ | ||||||
| ``` | ||||||
|
|
||||||
| > **Current state (M3):** `ParallelExecutor` (in `engine/parallel.py`) implements concurrent agent execution with `asyncio.TaskGroup`, configurable concurrency limits, resource locking for exclusive file access, error isolation, and progress tracking. While M3 primarily targets single-agent execution, parallel coordination is implemented here as prerequisite infrastructure for M4 multi-agent workflows. Models in `engine/parallel_models.py`: `AgentAssignment`, `ParallelExecutionGroup`, `AgentOutcome`, `ParallelExecutionResult`, `ParallelProgress`. | ||||||
|
|
||||||
| #### Kanban Board | ||||||
|
|
||||||
| ```text | ||||||
|
|
@@ -837,7 +839,7 @@ Tasks can be assigned through multiple strategies: | |||||
|
|
||||||
| The agent execution loop defines how an agent processes a task from start to finish. The framework provides multiple configurable loop architectures behind an `ExecutionLoop` protocol, making the system extensible. The default can vary by task complexity, and is configurable per agent or role. | ||||||
|
|
||||||
| > **Current state (M3):** ReAct (Loop 1) and Plan-and-Execute (Loop 2) are implemented. Hybrid loop and auto-selection are M4+. | ||||||
| > **Current state (M3):** ReAct (Loop 1) and Plan-and-Execute (Loop 2) are implemented. `ParallelExecutor` enables concurrent `AgentEngine.run()` calls with `TaskGroup` + Semaphore concurrency limits, resource locking, and error isolation (see §6.3). Hybrid loop and auto-selection are M4+. | ||||||
|
|
||||||
| #### ExecutionLoop Protocol | ||||||
|
|
||||||
|
|
@@ -2374,11 +2376,15 @@ ai-company/ | |||||
| │ │ ├── plan_models.py # Plan step, plan, and plan-execute config models | ||||||
| │ │ ├── plan_parsing.py # Plan response parsing utilities | ||||||
| │ │ ├── plan_execute_loop.py # Plan-and-Execute loop implementation | ||||||
| │ │ ├── plan_parsing.py # Plan extraction from LLM responses (JSON + text fallback) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: DESIGN_SPEC.md
Line: 2379
Comment:
The `plan_parsing.py` entry appears twice in the engine module file tree — once at line 2377 with description "Plan response parsing utilities" and again at line 2379 with "Plan extraction from LLM responses (JSON + text fallback)". The new entry was added but the original wasn't removed.
```suggestion
│ │ ├── plan_parsing.py # Plan extraction from LLM responses (JSON + text fallback)
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||
| │ │ ├── loop_helpers.py # Shared stateless helpers for all loop implementations | ||||||
| │ │ ├── recovery.py # Crash recovery strategies (RecoveryStrategy protocol) | ||||||
| │ │ ├── cost_recording.py # Per-turn cost recording helpers | ||||||
| │ │ ├── run_result.py # AgentRunResult outcome model | ||||||
| │ │ ├── agent_engine.py # Agent execution engine | ||||||
| │ │ ├── parallel.py # Parallel agent executor (TaskGroup + Semaphore) | ||||||
| │ │ ├── parallel_models.py # AgentAssignment, ParallelExecutionGroup, AgentOutcome, ParallelExecutionResult, ParallelProgress | ||||||
| │ │ ├── resource_lock.py # ResourceLock protocol + InMemoryResourceLock | ||||||
| │ │ ├── shutdown.py # Graceful shutdown strategy & manager | ||||||
| │ │ ├── task_engine.py # Task routing & scheduling (M3-M4) | ||||||
| │ │ ├── workflow_engine.py # Workflow orchestration (M4) | ||||||
|
|
@@ -2433,6 +2439,7 @@ ai-company/ | |||||
| │ │ │ ├── correlation.py # CORRELATION_* constants | ||||||
| │ │ │ ├── execution.py # EXECUTION_* constants | ||||||
| │ │ │ ├── git.py # GIT_* constants | ||||||
| │ │ │ ├── parallel.py # PARALLEL_* constants | ||||||
| │ │ │ ├── personality.py # PERSONALITY_* constants | ||||||
| │ │ │ ├── prompt.py # PROMPT_* constants | ||||||
| │ │ │ ├── provider.py # PROVIDER_* constants | ||||||
|
|
@@ -2580,6 +2587,7 @@ These conventions were established during the M0–M2+ review cycle. **Adopted** | |||||
| | **Shared field groups** | Adopted (M2.5) | Extracted common field sets into base models (e.g. `_SpendingTotals`) | Prevents field duplication across spending summary models. `_SpendingTotals` provides shared aggregation fields; `AgentSpending`, `DepartmentSpending`, `PeriodSpending` extend it. | | ||||||
| | **Event constants** | Adopted (per-domain) | Per-domain submodules under `events/` package (e.g. `events.provider`, `events.budget`). Import directly: `from ai_company.observability.events.<domain> import CONSTANT` | Split by domain for discoverability, co-location with domain logic, and reduced merge conflicts as constants grow. `__init__.py` serves as package marker with usage documentation; no re-exports. | | ||||||
| | **Parallel tool execution** | Adopted (M2.5) | `asyncio.TaskGroup` in `ToolInvoker.invoke_all` with optional `max_concurrency` semaphore | Structured concurrency with proper cancellation semantics. Fatal errors collected via guarded wrapper and re-raised after all tasks complete. | | ||||||
| | **Parallel agent execution** | Adopted (M3) | `ParallelExecutor` coordinates concurrent `AgentEngine.run()` calls via `asyncio.TaskGroup` + optional `Semaphore` concurrency limit + `_run_guarded()` error isolation. `ResourceLock` protocol with `InMemoryResourceLock` for exclusive file-path claims. Progress tracking via `ProgressCallback`. Shutdown-aware via `ShutdownManager` task registration. Fail-fast mode cancels sibling tasks on first failure; all errors are surfaced via `ParallelExecutionResult` outcomes. | Follows the `ToolInvoker.invoke_all()` pattern (parallel tool execution above). Composition over inheritance — wraps `AgentEngine`. Structured concurrency with proper cancellation. See §6.3 Parallel Execution. | | ||||||
| | **Tool permission checking** | Adopted (M3) | `ToolPermissionChecker` enforces category-level gating based on `ToolAccessLevel` (sandboxed → restricted → standard → elevated, plus custom). Priority-based resolution: denied list → allowed list → level categories → deny. Case-insensitive name matching. `ToolInvoker` filters definitions for prompt and checks at invocation time. | Defense-in-depth: agents only see permitted tools in the LLM prompt, and invocations are re-checked at execution time. Explicit allow/deny lists provide per-agent overrides. See §11.1.1. | | ||||||
| | **Tool sandboxing** | Adopted (M3, incremental) | File system tools use in-process `PathValidator` for workspace-scoped path validation (symlink resolution + containment check). `BaseFileSystemTool` ABC provides shared `ToolCategory.FILE_SYSTEM` and `PathValidator` integration — all file system tools extend this base. `SandboxBackend` protocol with `SubprocessSandbox` implemented — git tools accept optional `SandboxBackend` injection and delegate subprocess management to it (env filtering, workspace enforcement, timeout + process-group kill). `DockerSandbox` planned for code_runner, terminal, web, and database tools. `K8sSandbox` planned for future container deployments. Config-driven per-category backend selection planned for engine wiring. | File system tools use defence-in-depth path validation; subprocess sandbox provides lightweight isolation for git tools; heavier Docker/K8s isolation reserved for higher-risk tool categories (code execution, network). See §11.1.2. | | ||||||
| | **Crash recovery** | Adopted (M3) | Pluggable `RecoveryStrategy` protocol. M3: `FailAndReassignStrategy` (catch at engine boundary, log snapshot, mark FAILED / eligible for reassignment). M4/M5: `CheckpointStrategy` (persist `AgentContext` per turn, resume from last checkpoint). | Immutable `model_copy` pattern makes checkpoint serialization trivial to add later. Fail-and-reassign is sufficient for short MVP tasks. See §6.6. | | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The engine file tree lists
plan_parsing.pytwice (once as “Plan response parsing utilities” and again as “Plan extraction from LLM responses (JSON + text fallback)”). This looks like an accidental duplicate entry; consider consolidating to a single line with the correct description.