|
|
""" |
|
|
Pydantic Schemas for API Request/Response Models. |
|
|
|
|
|
These schemas define the structure of data flowing through the API, |
|
|
providing automatic validation and documentation. |
|
|
""" |
|
|
|
|
|
from typing import Any, Dict, List, Optional, Union |
|
|
from pydantic import BaseModel, Field |
|
|
from datetime import datetime |
|
|
from enum import Enum |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ExecutionStatus(str, Enum): |
|
|
"""Status of a workflow execution.""" |
|
|
PENDING = "pending" |
|
|
RUNNING = "running" |
|
|
COMPLETED = "completed" |
|
|
FAILED = "failed" |
|
|
CANCELLED = "cancelled" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NodeDefinition(BaseModel): |
|
|
"""Definition of a node in the graph.""" |
|
|
name: str = Field(..., description="Unique name for the node") |
|
|
handler: str = Field(..., description="Name of the handler function (must be registered)") |
|
|
description: Optional[str] = Field(None, description="Human-readable description") |
|
|
|
|
|
class Config: |
|
|
json_schema_extra = { |
|
|
"example": { |
|
|
"name": "extract", |
|
|
"handler": "extract_functions", |
|
|
"description": "Extract function definitions from code" |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConditionalRoutes(BaseModel): |
|
|
"""Routes for a conditional edge.""" |
|
|
condition: str = Field(..., description="Name of the condition function") |
|
|
routes: Dict[str, str] = Field( |
|
|
..., |
|
|
description="Mapping of condition results to target nodes" |
|
|
) |
|
|
|
|
|
class Config: |
|
|
json_schema_extra = { |
|
|
"example": { |
|
|
"condition": "quality_check", |
|
|
"routes": { |
|
|
"pass": "__END__", |
|
|
"fail": "improve" |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GraphCreateRequest(BaseModel): |
|
|
"""Request to create a new workflow graph.""" |
|
|
name: str = Field(..., description="Name of the workflow") |
|
|
description: Optional[str] = Field(None, description="Description of what this workflow does") |
|
|
nodes: List[NodeDefinition] = Field(..., description="List of nodes in the graph") |
|
|
edges: Dict[str, str] = Field( |
|
|
default_factory=dict, |
|
|
description="Direct edges: source -> target" |
|
|
) |
|
|
conditional_edges: Dict[str, ConditionalRoutes] = Field( |
|
|
default_factory=dict, |
|
|
description="Conditional edges with routing logic" |
|
|
) |
|
|
entry_point: Optional[str] = Field(None, description="Entry node (defaults to first node)") |
|
|
max_iterations: int = Field(100, description="Maximum loop iterations", ge=1, le=1000) |
|
|
|
|
|
class Config: |
|
|
json_schema_extra = { |
|
|
"example": { |
|
|
"name": "code_review_workflow", |
|
|
"description": "Automated code review with quality checks", |
|
|
"nodes": [ |
|
|
{"name": "extract", "handler": "extract_functions"}, |
|
|
{"name": "complexity", "handler": "calculate_complexity"}, |
|
|
{"name": "issues", "handler": "detect_issues"}, |
|
|
{"name": "improve", "handler": "suggest_improvements"} |
|
|
], |
|
|
"edges": { |
|
|
"extract": "complexity", |
|
|
"complexity": "issues" |
|
|
}, |
|
|
"conditional_edges": { |
|
|
"issues": { |
|
|
"condition": "quality_check", |
|
|
"routes": {"pass": "__END__", "fail": "improve"} |
|
|
}, |
|
|
"improve": { |
|
|
"condition": "always_continue", |
|
|
"routes": {"continue": "issues"} |
|
|
} |
|
|
}, |
|
|
"entry_point": "extract", |
|
|
"max_iterations": 10 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
class GraphCreateResponse(BaseModel): |
|
|
"""Response after creating a graph.""" |
|
|
graph_id: str = Field(..., description="Unique identifier for the created graph") |
|
|
name: str = Field(..., description="Name of the workflow") |
|
|
message: str = Field(default="Graph created successfully") |
|
|
node_count: int = Field(..., description="Number of nodes in the graph") |
|
|
|
|
|
class Config: |
|
|
json_schema_extra = { |
|
|
"example": { |
|
|
"graph_id": "abc123-def456", |
|
|
"name": "code_review_workflow", |
|
|
"message": "Graph created successfully", |
|
|
"node_count": 4 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
class GraphInfoResponse(BaseModel): |
|
|
"""Response with graph information.""" |
|
|
graph_id: str |
|
|
name: str |
|
|
description: Optional[str] |
|
|
node_count: int |
|
|
nodes: List[str] |
|
|
entry_point: Optional[str] |
|
|
max_iterations: int |
|
|
created_at: str |
|
|
mermaid_diagram: Optional[str] = Field(None, description="Mermaid diagram of the graph") |
|
|
|
|
|
|
|
|
class GraphListResponse(BaseModel): |
|
|
"""Response listing all graphs.""" |
|
|
graphs: List[GraphInfoResponse] |
|
|
total: int |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GraphRunRequest(BaseModel): |
|
|
"""Request to run a workflow graph.""" |
|
|
graph_id: str = Field(..., description="ID of the graph to run") |
|
|
initial_state: Dict[str, Any] = Field( |
|
|
..., |
|
|
description="Initial state data for the workflow" |
|
|
) |
|
|
async_execution: bool = Field( |
|
|
False, |
|
|
description="If true, run in background and return immediately" |
|
|
) |
|
|
|
|
|
class Config: |
|
|
json_schema_extra = { |
|
|
"example": { |
|
|
"graph_id": "abc123-def456", |
|
|
"initial_state": { |
|
|
"code": "def hello():\n print('world')", |
|
|
"quality_threshold": 7.0 |
|
|
}, |
|
|
"async_execution": False |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
class ExecutionLogEntry(BaseModel): |
|
|
"""A single entry in the execution log.""" |
|
|
step: int |
|
|
node: str |
|
|
started_at: str |
|
|
completed_at: Optional[str] |
|
|
duration_ms: Optional[float] |
|
|
iteration: int |
|
|
result: str |
|
|
error: Optional[str] |
|
|
route_taken: Optional[str] |
|
|
|
|
|
|
|
|
class GraphRunResponse(BaseModel): |
|
|
"""Response after running a graph.""" |
|
|
run_id: str = Field(..., description="Unique identifier for this run") |
|
|
graph_id: str |
|
|
status: ExecutionStatus |
|
|
final_state: Dict[str, Any] |
|
|
execution_log: List[ExecutionLogEntry] |
|
|
started_at: Optional[str] |
|
|
completed_at: Optional[str] |
|
|
total_duration_ms: Optional[float] |
|
|
iterations: int |
|
|
error: Optional[str] = None |
|
|
|
|
|
class Config: |
|
|
json_schema_extra = { |
|
|
"example": { |
|
|
"run_id": "run-xyz789", |
|
|
"graph_id": "abc123-def456", |
|
|
"status": "completed", |
|
|
"final_state": { |
|
|
"code": "def hello():\n print('world')", |
|
|
"functions": [{"name": "hello"}], |
|
|
"quality_score": 8.5 |
|
|
}, |
|
|
"execution_log": [ |
|
|
{ |
|
|
"step": 1, |
|
|
"node": "extract", |
|
|
"started_at": "2024-01-01T12:00:00", |
|
|
"completed_at": "2024-01-01T12:00:01", |
|
|
"duration_ms": 15.5, |
|
|
"iteration": 0, |
|
|
"result": "success", |
|
|
"error": None, |
|
|
"route_taken": None |
|
|
} |
|
|
], |
|
|
"started_at": "2024-01-01T12:00:00", |
|
|
"completed_at": "2024-01-01T12:00:05", |
|
|
"total_duration_ms": 5000.0, |
|
|
"iterations": 1, |
|
|
"error": None |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
class RunStateResponse(BaseModel): |
|
|
"""Response with current run state.""" |
|
|
run_id: str |
|
|
graph_id: str |
|
|
status: ExecutionStatus |
|
|
current_node: Optional[str] |
|
|
current_state: Dict[str, Any] |
|
|
iteration: int |
|
|
execution_log: List[ExecutionLogEntry] |
|
|
started_at: str |
|
|
completed_at: Optional[str] |
|
|
error: Optional[str] |
|
|
|
|
|
|
|
|
class RunListResponse(BaseModel): |
|
|
"""Response listing runs.""" |
|
|
runs: List[RunStateResponse] |
|
|
total: int |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ToolInfo(BaseModel): |
|
|
"""Information about a registered tool.""" |
|
|
name: str |
|
|
description: str |
|
|
parameters: Dict[str, str] |
|
|
|
|
|
|
|
|
class ToolListResponse(BaseModel): |
|
|
"""Response listing all registered tools.""" |
|
|
tools: List[ToolInfo] |
|
|
total: int |
|
|
|
|
|
|
|
|
class ToolRegisterRequest(BaseModel): |
|
|
"""Request to register a new tool (for dynamic registration).""" |
|
|
name: str = Field(..., description="Unique name for the tool") |
|
|
description: str = Field("", description="Description of what the tool does") |
|
|
code: str = Field(..., description="Python code for the tool function") |
|
|
|
|
|
class Config: |
|
|
json_schema_extra = { |
|
|
"example": { |
|
|
"name": "custom_validator", |
|
|
"description": "Custom validation logic", |
|
|
"code": "def custom_validator(data):\n return {'valid': True}" |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
class ToolRegisterResponse(BaseModel): |
|
|
"""Response after registering a tool.""" |
|
|
name: str |
|
|
message: str |
|
|
warning: Optional[str] = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ErrorResponse(BaseModel): |
|
|
"""Standard error response.""" |
|
|
error: str |
|
|
detail: Optional[str] = None |
|
|
status_code: int |
|
|
|
|
|
|
|
|
class ValidationErrorResponse(BaseModel): |
|
|
"""Validation error response.""" |
|
|
error: str = "Validation Error" |
|
|
detail: List[Dict[str, Any]] |
|
|
status_code: int = 422 |
|
|
|