refactor: reorganize into monorepo with separate subprojects
Build and Push API / release (push) Successful in 3s
Build and Push API / build (push) Successful in 2m27s

Structure webber into three independent subprojects:
- webber-api/: FastAPI backend server with all agent code
- webber-cli/: Standalone CLI client (renamed from cli/ to webber_cli/)
- webber-sandbox/: Test project for functional testing

Key changes:
- Each subproject has its own .venv (Python 3.12+)
- Added sandbox.sh for managing test project templates
- Created sandbox-templates/ with calculator-cli and empty starter
- Updated CI/CD for prefixed tags (api/v*, cli/v*)
- Added comprehensive AGENTS.md with operational instructions
- Added gitignore filtering to glob and grep tools
- Created pyproject.toml for each subproject

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-10 10:37:47 +01:00
co-authored by Claude Opus 4.5
parent f4e8552298
commit 3b58fa4f8b
121 changed files with 2034 additions and 284 deletions
+84
View File
@@ -0,0 +1,84 @@
"""
REST API routes for agents.
"""
from fastapi import APIRouter, HTTPException
from src.domains.agents.base import get_agent, list_agents
# Import agents to ensure they're registered
import src.domains.agents.explore # noqa: F401
from src.domains.agents.schemas import (
AgentRunRequest,
AgentRunResponse,
AgentInfo,
AgentListResponse,
)
from src.shared.logging import logged, get_logger
logger = get_logger(__name__)
router = APIRouter(prefix="/agents", tags=["Agents"])
@router.get("/", response_model=AgentListResponse)
async def list_available_agents() -> AgentListResponse:
"""List all available agents."""
agents = list_agents()
return AgentListResponse(
agents=[AgentInfo(**a) for a in agents]
)
@router.post("/run", response_model=AgentRunResponse)
@logged()
async def run_agent(request: AgentRunRequest) -> AgentRunResponse:
"""
Run an agent with the given prompt.
The agent will use tools to explore the codebase and answer questions.
"""
# Get the requested agent
agent = get_agent(request.agent_type)
if not agent:
raise HTTPException(
status_code=400,
detail=f"Unknown agent type: {request.agent_type}"
)
try:
# Run the agent
response = await agent.run(
request.prompt,
working_dir=request.working_dir,
)
return AgentRunResponse(
response=response,
agent_type=request.agent_type,
success=True,
)
except Exception as e:
logger.exception(f"Agent execution failed: {e}")
return AgentRunResponse(
response="",
agent_type=request.agent_type,
success=False,
error=str(e),
)
@router.get("/{agent_type}", response_model=AgentInfo)
async def get_agent_info(agent_type: str) -> AgentInfo:
"""Get information about a specific agent."""
agent = get_agent(agent_type)
if not agent:
raise HTTPException(
status_code=404,
detail=f"Agent not found: {agent_type}"
)
return AgentInfo(
name=agent.name,
description=agent.description,
)