Introduce WorkflowEngine with state machine, tool registry, and builtin chat template; migrate stream chat to engine callbacks. Move page mode switching to TopBar actions cluster as a ThemeToggle-style dropdown (聊天/工作室/爽文/房间). Co-authored-by: Cursor <cursoragent@cursor.com>
129 lines
3.5 KiB
Python
129 lines
3.5 KiB
Python
"""
|
|
Agent workflow engine data models.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
from typing import Any, Awaitable, Callable, Dict, List, Optional
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class WorkflowTemplateKind(str, Enum):
|
|
BUILTIN_CHAT = "builtin.chat"
|
|
|
|
|
|
class RunStatus(str, Enum):
|
|
PENDING = "pending"
|
|
RUNNING = "running"
|
|
COMPLETED = "completed"
|
|
FAILED = "failed"
|
|
|
|
|
|
class RunEventType(str, Enum):
|
|
STATE_ENTER = "state_enter"
|
|
TOOL_START = "tool_start"
|
|
TOOL_END = "tool_end"
|
|
WORLD_BOOK_ACTIVE = "worldbook_active"
|
|
TASKS_CREATED = "tasks_created"
|
|
CHUNK = "chunk"
|
|
ERROR = "error"
|
|
COMPLETE = "complete"
|
|
|
|
|
|
class ToolSpec(BaseModel):
|
|
name: str
|
|
description: str = ""
|
|
parameters: Dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class SkillManifest(BaseModel):
|
|
id: str
|
|
name: str = ""
|
|
description: str = ""
|
|
path: str = ""
|
|
|
|
|
|
class WorkflowTemplate(BaseModel):
|
|
id: str
|
|
kind: WorkflowTemplateKind
|
|
name: str = ""
|
|
description: str = ""
|
|
version: str = "1.0.0"
|
|
state_machine_path: str = "state_machine.json"
|
|
skills: List[SkillManifest] = Field(default_factory=list)
|
|
|
|
|
|
class ChatRunBinding(BaseModel):
|
|
role_name: str
|
|
chat_name: str
|
|
template_id: str = WorkflowTemplateKind.BUILTIN_CHAT.value
|
|
|
|
|
|
class TurnCallbacks(BaseModel):
|
|
"""Optional async callbacks for streaming / WS events."""
|
|
|
|
model_config = {"arbitrary_types_allowed": True}
|
|
|
|
on_worldbook_active: Optional[Callable[[List[Any]], Awaitable[None]]] = None
|
|
on_tasks_created: Optional[Callable[[Dict[str, Any]], Awaitable[None]]] = None
|
|
on_chunk: Optional[Callable[[str], Awaitable[None]]] = None
|
|
|
|
|
|
class TurnContext(BaseModel):
|
|
"""Mutable per-turn execution context passed between tools."""
|
|
|
|
model_config = {"arbitrary_types_allowed": True}
|
|
|
|
request_data: Dict[str, Any] = Field(default_factory=dict)
|
|
template_id: str = WorkflowTemplateKind.BUILTIN_CHAT.value
|
|
run_id: str = ""
|
|
stream: bool = False
|
|
callbacks: Optional[TurnCallbacks] = None
|
|
|
|
current_role: str = ""
|
|
current_chat: str = ""
|
|
user_message: str = ""
|
|
preset_name: Optional[str] = None
|
|
character: Any = None
|
|
active_entries: List[Any] = Field(default_factory=list)
|
|
chat_history: List[Any] = Field(default_factory=list)
|
|
prompt_messages: List[Any] = Field(default_factory=list)
|
|
generated_content: str = ""
|
|
token_usage: Dict[str, Any] = Field(default_factory=dict)
|
|
duration: float = 0.0
|
|
task_ids: Dict[str, Optional[str]] = Field(default_factory=dict)
|
|
error: Optional[str] = None
|
|
|
|
|
|
class WorkflowRun(BaseModel):
|
|
id: str
|
|
template_id: str
|
|
binding: ChatRunBinding
|
|
status: RunStatus = RunStatus.PENDING
|
|
started_at: str = Field(default_factory=lambda: datetime.now().isoformat())
|
|
finished_at: Optional[str] = None
|
|
current_state: Optional[str] = None
|
|
result_content: str = ""
|
|
error: Optional[str] = None
|
|
|
|
|
|
class RunEvent(BaseModel):
|
|
run_id: str
|
|
type: RunEventType
|
|
timestamp: str = Field(default_factory=lambda: datetime.now().isoformat())
|
|
state: Optional[str] = None
|
|
tool: Optional[str] = None
|
|
payload: Dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ChatTurnResult(BaseModel):
|
|
success: bool
|
|
content: str = ""
|
|
error: Optional[str] = None
|
|
active_entries: List[Any] = Field(default_factory=list)
|
|
task_ids: Dict[str, Optional[str]] = Field(default_factory=dict)
|
|
run_id: str = ""
|
|
workflow_template_id: str = WorkflowTemplateKind.BUILTIN_CHAT.value
|