Skip to content

[Phase 2.5-F] Wire engine parameter through v2 API routes (#354)#387

Merged
frankbria merged 3 commits intomainfrom
feature/issue-354-react-api-routes
Feb 16, 2026
Merged

[Phase 2.5-F] Wire engine parameter through v2 API routes (#354)#387
frankbria merged 3 commits intomainfrom
feature/issue-354-react-api-routes

Conversation

@frankbria
Copy link
Owner

@frankbria frankbria commented Feb 16, 2026

Summary

  • Add engine parameter ("plan" default, "react" supported) to all three task execution API endpoints
  • Fix pre-existing bug: retry_countmax_retries parameter name mismatch in /execute endpoint
  • Add 9 integration tests covering validation, defaults, and passthrough on all endpoints

Changes

  • POST /api/v2/tasks/execute — accepts engine in request body, passes to conductor.start_batch(), returns in response
  • POST /api/v2/tasks/approve — accepts engine in request body, passes to conductor.start_batch() when start_execution=true
  • POST /api/v2/tasks/{id}/start — accepts engine as query parameter, passes to runtime.execute_agent()
  • Pydantic model validators reject invalid engine values (422 for body fields, 400 for query params)

Acceptance Criteria

  • API endpoint accepts engine parameter
  • codeframe/ui/routers/tasks_v2.py updated with engine field in execution request models
  • tasks_v2.py passes engine to runtime/conductor
  • SSE streaming works with ReAct engine events (already compatible — no changes needed)
  • Integration tests for engine parameter validation and passthrough
  • All existing API tests pass (1854 v2 tests, 0 failures)
  • Linting clean (ruff)

Test Plan

  • 9 new integration tests in tests/integration/test_tasks_v2_engine.py
  • Full v2 test suite passes (1854 tests)
  • Ruff linting clean

Bug Fix

Fixed retry_count=body.retry_countmax_retries=body.retry_count in the /execute endpoint. The old code would have caused a TypeError at runtime since conductor.start_batch() expects max_retries, not retry_count.

Closes #354

Summary by CodeRabbit

  • New Features

    • Users can specify an execution engine ("plan" or "react") when running or approving tasks (default: "plan"); chosen engine is returned in execution responses and used across batch and single-task flows.
  • Bug Fixes

    • Invalid engine values are now rejected with a clear error response.
  • Tests

    • Added integration tests validating engine defaulting, propagation, and validation across task endpoints.

Test User added 2 commits February 15, 2026 20:50
Wire the engine parameter ("plan" or "react") through the v2 API
layer so ReactAgent can be invoked via HTTP, not just CLI.

- Add engine field to StartExecutionRequest and ApproveTasksRequest
- Add engine validation (model_validator + HTTPException for query param)
- Pass engine to conductor.start_batch() and runtime.execute_agent()
- Fix bug: retry_count → max_retries parameter name in /execute endpoint
- Add engine to StartExecutionResponse for confirmation
Test engine parameter validation, default values, and passthrough
on all three execution endpoints: /execute, /approve, and /{id}/start.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 16, 2026

Walkthrough

Added an engine parameter (default "plan") to v2 task execution endpoints, validated via Pydantic model validators, propagated into request/response models, and forwarded to conductor.start_batch and runtime.execute_agent paths; included integration tests covering defaulting, propagation, and validation.

Changes

Cohort / File(s) Summary
Router updates & models
codeframe/ui/routers/tasks_v2.py
Added engine: str = "plan" to ApproveTasksRequest and StartExecutionRequest with model_validator(mode="after") validators restricting to "plan" or "react". Threaded engine through approve_tasks, start_execution, and start_single_task flows, passing it to conductor.start_batch and runtime.execute_agent. StartExecutionResponse now includes engine. Added model_validator import.
Integration tests
tests/integration/test_tasks_v2_engine.py
New end-to-end tests that mock conductor/runtime to assert engine defaulting, explicit "react" forwarding, and invalid-value handling for the three v2 endpoints (/execute, /start, /approve). Includes test helpers/fixtures for minimal app and stubs.

Sequence Diagram(s)

mermaid
sequenceDiagram
autonumber
participant Client as Client
participant Router as API Router
participant Conductor as Conductor
participant Runtime as Runtime
participant BG as Background Task
Client->>Router: POST /api/v2/tasks/execute {engine}
Router-->>Router: validate engine ("plan"|"react")
Router->>Conductor: start_batch(..., engine)
Conductor-->>Router: batch_started (id)
Router-->>Client: 200 StartExecutionResponse {engine, id}

mermaid
sequenceDiagram
autonumber
participant Client as Client
participant Router as API Router
participant BG as Background Task
participant Runtime as Runtime
Client->>Router: POST /api/v2/tasks/{id}/start?engine=...
Router-->>Router: validate engine ("plan"|"react")
Router->>BG: enqueue run_task(task_id, engine)
BG->>Runtime: execute_agent(task, engine)
Runtime-->>BG: execution_result
BG-->>Router: result persisted
Router-->>Client: 202 Accepted / response

(Note: rectangles/colors omitted for simplicity; components represent distinct actors.)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 A tiny hop, an engine sings,

"Plan" and "React" with different springs.
Validators guard each chosen track,
I pass the choice from front to back.
Hooray — the workflow hops intact! 🚀

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective: wiring the engine parameter through v2 API routes as part of Phase 2.5-F implementation.
Linked Issues check ✅ Passed PR successfully implements all core requirements: engine parameter added to endpoints with 'plan' default and 'react' option; pydantic validators enforce valid values; engine passed to runtime/conductor; integration tests cover validation and passthrough.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #354 objectives: engine parameter wiring, model updates, and integration tests. The bug fix (retry_count→max_retries) is a minor supporting fix within scope.
Docstring Coverage ✅ Passed Docstring coverage is 86.96% which is sufficient. The required threshold is 80.00%.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/issue-354-react-api-routes

Comment @coderabbitai help to get the list of available commands and usage tips.

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Feb 16, 2026

Wire the engine parameter through v2 task APIs to select plan or react during batch and single-task execution

Add engine to request/response models and v2 handlers, defaulting to plan and validating against {'plan','react'}; forward engine to conductor.start_batch; include engine in execute responses; accept engine as a query param for single-task start. See tasks_v2.py.

📍Where to Start

Start at the start_execution and approve_tasks_endpoint handlers in tasks_v2.py, then review the StartExecutionRequest, StartExecutionResponse, and ApproveTasksRequest model changes.


Macroscope summarized 2a5f97a.

@claude
Copy link

claude bot commented Feb 16, 2026

Code Review - Phase 2.5-F Engine Parameter Integration

I've reviewed the changes for wiring the engine parameter through the v2 API routes. Overall, this is a well-structured, focused PR that successfully addresses issue #354. Here's my detailed feedback:


✅ Strengths

1. Excellent Test Coverage

  • 9 comprehensive integration tests covering all three endpoints
  • Tests validate defaults, explicit values, invalid inputs, and passthrough behavior
  • Good use of mocks to isolate API layer testing
  • Tests follow existing patterns from the test suite

2. Bug Fix Included

The retry_countmax_retries fix in the /execute endpoint is valuable:

# Before (would cause TypeError)
retry_count=body.retry_count

# After (correct parameter name)
max_retries=body.retry_count

This would have caused runtime failures - good catch!

3. Consistent Validation Pattern

  • Body fields use Pydantic @model_validator (returns 422)
  • Query params use explicit HTTPException (returns 400)
  • Both approaches are appropriate for their contexts

4. Thin Adapter Pattern Maintained

The router correctly delegates to core.* modules without business logic:

conductor.start_batch(..., engine=body.engine)
runtime.execute_agent(..., engine=engine)

5. Response Model Updated

Including engine in StartExecutionResponse provides good API transparency.


🔍 Suggestions & Observations

1. Validator Duplication (Minor)

The @model_validator logic is duplicated across ApproveTasksRequest and StartExecutionRequest. Consider extracting a reusable validator:

# In tasks_v2.py (top-level)
def validate_engine(value: str) -> str:
    """Validate engine parameter."""
    valid = ("plan", "react")
    if value not in valid:
        raise ValueError(f"engine must be one of: {', '.join(valid)}")
    return value

class StartExecutionRequest(BaseModel):
    engine: str = Field("plan", description="...")
    
    @model_validator(mode="after")
    def _validate_engine(self) -> "StartExecutionRequest":
        self.engine = validate_engine(self.engine)
        return self

This is a nice-to-have, not blocking - current approach works fine.

2. Query Param Validation Inconsistency (Minor)

For /api/v2/tasks/{id}/start, the query param validation uses manual HTTPException:

valid_engines = ("plan", "react")
if engine not in valid_engines:
    raise HTTPException(status_code=400, ...)

FastAPI can handle this validation automatically with:

from typing import Literal

engine: Literal["plan", "react"] = Query("plan", description="...")

This would:

  • Return 422 (consistent with body validation)
  • Auto-document allowed values in OpenAPI
  • Reduce boilerplate

Note: If you prefer explicit 400 for query params vs 422 for body, that's a valid design choice. Just worth considering consistency.

3. Test Sleep Timing (Nitpick)

In test_start_single_with_react_engine:

time.sleep(0.5)  # Give background thread a moment

This could be flaky on slow CI systems. Consider using a polling approach or increasing to 1.0 seconds. Not critical if tests pass consistently.

4. Missing Edge Case Test (Enhancement)

Consider adding a test for start_execution=False in the approve endpoint to verify engine is not passed when batch execution isn't started:

def test_approve_without_execution_ignores_engine(self, tmp_path, client):
    """Engine should be ignored when start_execution=False."""
    ws = _make_workspace(tmp_path)
    task = _make_task(ws, status=TaskStatus.BACKLOG)
    
    approval = ApprovalResult(approved_count=1, ...)
    
    with patch("...", return_value=approval):
        resp = client.post(
            "/api/v2/tasks/approve",
            json={"start_execution": False, "engine": "react"},
            params={"workspace_path": str(ws.repo_path)},
        )
    
    assert resp.status_code == 200
    assert "batch_id" not in resp.json()  # No batch started

This verifies the conditional logic in the route handler.

5. Documentation Gap (Enhancement)

The PR description mentions SSE streaming compatibility but there's no explicit test. Consider adding a comment in the test file referencing this, or add a simple test that verifies events work with engine="react".


🔒 Security & Quality

  • No security concerns - validation prevents injection
  • No performance issues - parameter passthrough is trivial
  • Backward compatible - defaults to "plan"
  • Follows CLAUDE.md guidelines - thin adapter pattern, core-first architecture
  • Type safety - Pydantic models enforce contracts

📋 Pre-Merge Checklist

Based on the PR description, all acceptance criteria are met:

  • API endpoints accept engine parameter
  • Router passes engine to runtime/conductor
  • SSE streaming compatible (no changes needed)
  • Integration tests added
  • Bug fix included (retry_count → max_retries)

Recommendation:APPROVE with optional improvements noted above.


🎯 Final Notes

This PR is production-ready. The suggestions above are optional enhancements for code quality and test robustness. The core implementation is solid, well-tested, and follows project conventions.

Great work on finding and fixing the retry_count bug! 🎉

- Use Literal["plan", "react"] for query param instead of manual
  validation — auto-documents in OpenAPI, consistent 422 across all
  endpoints
- Bump background thread sleep from 0.5s to 1.0s for CI stability
- Add edge case test: approve with start_execution=False skips batch
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/integration/test_tasks_v2_engine.py (2)

1-9: Add SSE stream coverage for ReAct engine.
The objectives mention validating /api/v2/tasks/{task_id}/stream with ReAct phase events, but this module doesn't exercise streaming yet. Consider adding a streaming integration test to cover that path.


213-239: Avoid fixed sleep to reduce test flakiness.
Using time.sleep(0.5) can be flaky on slower CI. Prefer waiting on an event set by the mocked execute_agent.

♻️ Suggested refactor
-        import time
+        import threading
@@
-        with (
-            patch("codeframe.ui.routers.tasks_v2.runtime.start_task_run", return_value=run),
-            patch("codeframe.ui.routers.tasks_v2.runtime.execute_agent") as mock_exec,
-        ):
+        called = threading.Event()
+        with (
+            patch("codeframe.ui.routers.tasks_v2.runtime.start_task_run", return_value=run),
+            patch(
+                "codeframe.ui.routers.tasks_v2.runtime.execute_agent",
+                side_effect=lambda *a, **k: called.set(),
+            ) as mock_exec,
+        ):
             resp = client.post(
                 f"/api/v2/tasks/{task.id}/start",
                 params={
                     "workspace_path": str(ws.repo_path),
                     "execute": "true",
                     "engine": "react",
                 },
             )
 
             assert resp.status_code == 200
-            # Give background thread a moment to invoke mock
-            time.sleep(0.5)
+            assert called.wait(1)
             mock_exec.assert_called_once()
             _, kwargs = mock_exec.call_args
             assert kwargs["engine"] == "react"

@claude
Copy link

claude bot commented Feb 16, 2026

Updated Review - Engine Parameter Integration

I've reviewed the latest changes and I'm pleased to see the improvements! Here's my updated feedback:


✅ Changes Since Last Review

1. Query Parameter Validation Improved

The /api/v2/tasks/{id}/start endpoint now uses FastAPI's Literal type for automatic validation:

engine: Literal["plan", "react"] = Query("plan", ...)

This is much better than manual HTTPException validation because:

  • ✅ FastAPI handles validation automatically (returns 422)
  • ✅ OpenAPI docs show exact allowed values
  • ✅ Consistent with body parameter validation approach
  • ✅ Less boilerplate code

Great improvement! 🎉

2. Edge Case Test Added

The new test test_approve_without_execution_skips_engine verifies that conductor.start_batch is not called when start_execution=False. This addresses the edge case I mentioned in my previous review.

3. Test Sleep Increased

In test_start_single_with_react_engine, the sleep was increased from 0.5s to 1.0s:

time.sleep(1.0)  # Give background thread a moment

This should reduce flakiness on slower CI systems.


🔍 Final Review

Code Quality: ✅ Excellent

  • Thin adapter pattern maintained
  • Consistent validation across all endpoints
  • Proper type hints with Pydantic and FastAPI Literal

Test Coverage: ✅ Comprehensive

  • 9 integration tests covering all three endpoints
  • Default values, explicit values, invalid inputs, edge cases
  • Good use of mocks to isolate API layer

Bug Fix: ✅ Valuable

The retry_countmax_retries fix prevents runtime TypeError.

Security: ✅ No concerns

Input validation prevents injection attacks.

Performance: ✅ No concerns

Parameter passthrough has negligible overhead.

Documentation: ✅ Good

  • Clear docstrings on test module
  • OpenAPI will auto-document Literal enum values

🎯 Final Recommendation

✅ APPROVED - This PR is production-ready.

All my previous suggestions have been addressed:

  1. ✅ Literal validation for query params
  2. ✅ Edge case test for approve without execution
  3. ✅ Increased sleep timing for test stability

The only remaining minor suggestion (extracting validator logic to reduce duplication) is a nice-to-have refactoring opportunity for the future - not blocking for this PR.


📋 Verification Checklist

  • All acceptance criteria met
  • Bug fix included
  • Integration tests comprehensive
  • Type safety enforced
  • Backward compatible (defaults to "plan")
  • Follows CLAUDE.md thin adapter pattern
  • Previous review suggestions addressed

Great work on the iterative improvements! 🚀

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
codeframe/ui/routers/tasks_v2.py (1)

54-64: Replace str fields and custom validators with Literal type annotations.

This eliminates duplicate validation logic and lets Pydantic v2 automatically generate proper OpenAPI enums. Since Literal["plan", "react"] is already used elsewhere in this file (line 589–590), apply it consistently to ApproveTasksRequest.engine and StartExecutionRequest.engine, removing both @model_validator methods. If both validators are removed, drop model_validator from the imports.

♻️ Refactor
-class ApproveTasksRequest(BaseModel):
+class ApproveTasksRequest(BaseModel):
     ...
-    engine: str = Field(
+    engine: Literal["plan", "react"] = Field(
         "plan",
         description="Execution engine: 'plan' (default) or 'react' (ReAct loop)",
     )
-
-    `@model_validator`(mode="after")
-    def _validate_engine(self) -> "ApproveTasksRequest":
-        valid = ("plan", "react")
-        if self.engine not in valid:
-            raise ValueError(f"engine must be one of: {', '.join(valid)}")
-        return self

-class StartExecutionRequest(BaseModel):
+class StartExecutionRequest(BaseModel):
     ...
-    engine: str = Field(
+    engine: Literal["plan", "react"] = Field(
         "plan",
         description="Execution engine: 'plan' (default) or 'react' (ReAct loop)",
     )
-
-    `@model_validator`(mode="after")
-    def _validate_engine(self) -> "StartExecutionRequest":
-        valid = ("plan", "react")
-        if self.engine not in valid:
-            raise ValueError(f"engine must be one of: {', '.join(valid)}")
-        return self

Also applies to: 111–121

@frankbria frankbria merged commit 5e72669 into main Feb 16, 2026
13 checks passed
@frankbria frankbria deleted the feature/issue-354-react-api-routes branch February 16, 2026 04:17
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.

[Phase 2.5-F] Verify ReAct engine works via API routes

1 participant