Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions codeframe/ui/routers/tasks_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@

import logging
import threading
from typing import Any, Optional
from typing import Any, Literal, Optional

from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Request
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, model_validator

from codeframe.core.workspace import Workspace
from codeframe.lib.rate_limiter import rate_limit_ai, rate_limit_standard
Expand Down Expand Up @@ -51,6 +51,17 @@ class ApproveTasksRequest(BaseModel):
default=False,
description="Whether to start batch execution after approval",
)
engine: str = 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 ApproveTasksResponse(BaseModel):
Expand Down Expand Up @@ -97,6 +108,17 @@ class StartExecutionRequest(BaseModel):
le=5,
description="Number of retries for failed tasks",
)
engine: str = 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


class StartExecutionResponse(BaseModel):
Expand All @@ -106,6 +128,7 @@ class StartExecutionResponse(BaseModel):
batch_id: str
task_count: int
strategy: str
engine: str
message: str


Expand Down Expand Up @@ -423,6 +446,7 @@ async def approve_tasks_endpoint(
strategy="serial",
max_parallel=4,
on_failure="continue",
engine=body.engine,
)
batch_id = batch.id
message = f"Approved {result.approved_count} task(s) and started execution (batch {batch_id[:8]})."
Expand Down Expand Up @@ -530,15 +554,17 @@ async def start_execution(
task_ids=task_ids,
strategy=body.strategy,
max_parallel=body.max_parallel,
retry_count=body.retry_count,
max_retries=body.retry_count,
on_failure="continue",
engine=body.engine,
)

return StartExecutionResponse(
success=True,
batch_id=batch.id,
task_count=len(task_ids),
strategy=body.strategy,
engine=body.engine,
message=f"Started execution for {len(task_ids)} task(s) (batch {batch.id[:8]}).",
)

Expand All @@ -560,6 +586,7 @@ async def start_single_task(
execute: bool = Query(False, description="Run agent execution (requires ANTHROPIC_API_KEY)"),
dry_run: bool = Query(False, description="Preview changes without making them"),
verbose: bool = Query(False, description="Show detailed progress output"),
engine: Literal["plan", "react"] = Query("plan", description="Execution engine: 'plan' (default) or 'react' (ReAct loop)"),
workspace: Workspace = Depends(get_v2_workspace),
) -> dict[str, Any]:
"""Start a single task run.
Expand Down Expand Up @@ -610,6 +637,7 @@ def _run_agent():
dry_run=dry_run,
verbose=verbose,
event_publisher=publisher,
engine=engine,
)
except Exception as exc:
logger.error(f"Background agent failed for task {task_id}: {exc}", exc_info=True)
Expand Down
Loading
Loading