Add agent workflow engine foundation and theme-style page switcher.
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>
This commit is contained in:
128
backend/models/agent.py
Normal file
128
backend/models/agent.py
Normal file
@@ -0,0 +1,128 @@
|
||||
"""
|
||||
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
|
||||
@@ -215,6 +215,10 @@ class ChatHeader(BaseModel):
|
||||
messageCount: int = Field(0, description="消息数量")
|
||||
ragLibraryId: Optional[str] = Field(None, description="关联的 RAG 历史消息库 ID")
|
||||
|
||||
# Agent workflow engine (optional, backward compatible)
|
||||
workflowTemplateId: Optional[str] = Field(None, description="工作流模板 ID")
|
||||
engineRunId: Optional[str] = Field(None, description="最近一次引擎运行 ID")
|
||||
|
||||
|
||||
class ChatMessage(BaseModel):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user