Spaces:
Running
Running
| """ | |
| Data models for stream chat API. | |
| Defines request/response schemas compatible with the Node.js backend. | |
| """ | |
| from typing import Any, Literal, Union | |
| from pydantic import BaseModel, Field | |
| # ================================================================================ | |
| # Request Models | |
| # ================================================================================ | |
| class ToolDefinition(BaseModel): | |
| """Tool definition for function calling.""" | |
| type: str = Field(default="function", description="Type of tool, usually 'function'") | |
| function: "FunctionDefinition" | |
| class FunctionDefinition(BaseModel): | |
| """Function definition for tool calling.""" | |
| name: str | |
| description: str | |
| parameters: dict[str, Any] = Field(default_factory=dict) | |
| class ToolCall(BaseModel): | |
| """Tool call from AI model.""" | |
| id: str | None = None | |
| type: str = Field(default="function") | |
| function: "FunctionCall" | |
| text_index: int | None = Field(default=None, alias="textIndex") | |
| class FunctionCall(BaseModel): | |
| """Function call details.""" | |
| name: str | |
| arguments: str | |
| class UserTool(BaseModel): | |
| """User-defined tool (HTTP or MCP).""" | |
| id: str | |
| name: str | |
| description: str | |
| type: Literal["http", "mcp"] | |
| input_schema: dict[str, Any] = Field(default_factory=dict, alias="inputSchema") | |
| parameters: dict[str, Any] = Field(default_factory=dict) | |
| config: dict[str, Any] = Field(default_factory=dict) | |
| category: str | None = None | |
| class StreamChatRequest(BaseModel): | |
| """Request model for stream chat endpoint.""" | |
| # Provider configuration | |
| provider: Literal[ | |
| "gemini", "openai", "openai_compatibility", "siliconflow", | |
| "glm", "deepseek", "volcengine", "modelscope", "kimi", "nvidia", "minimax" | |
| ] | |
| api_key: str = Field(..., alias="apiKey") | |
| base_url: str | None = Field(default=None, alias="baseUrl") | |
| model: str | None = None | |
| # Message content | |
| messages: list[dict[str, Any]] | |
| # Tool configuration | |
| tools: list[ToolDefinition] | None = None | |
| tool_choice: Any = Field(default=None, alias="toolChoice") | |
| tool_ids: list[str] = Field(default_factory=list, alias="toolIds") | |
| skill_ids: list[str] = Field(default_factory=list, alias="skillIds") | |
| user_tools: list[UserTool] = Field(default_factory=list, alias="userTools") | |
| skip_default_tools: bool = Field(default=False, alias="skipDefaultTools") | |
| # Team configuration (Expert Mode) | |
| expert_mode: bool = Field(default=False, alias="expertMode") | |
| team_mode: Literal["coordinate", "route", "broadcast", "tasks"] | None = Field(default=None, alias="teamMode") | |
| leader_agent_id: str | None = Field(default=None, alias="leaderAgentId") | |
| team_agent_ids: list[str] = Field(default_factory=list, alias="teamAgentIds") | |
| # Response format | |
| # Response format | |
| response_format: dict[str, Any] | None = Field(default=None, alias="responseFormat") | |
| # Thinking mode - supports boolean (enabled/disabled) or dict (specific config) | |
| thinking: dict[str, Any] | bool | None = None | |
| thinking_mode: Literal["smart", "deep", "fast"] | None = Field( | |
| default=None, | |
| alias="thinkingMode", | |
| ) | |
| # Generation parameters | |
| temperature: float | None = None | |
| top_k: int | None = None | |
| top_p: float | None = None | |
| frequency_penalty: float | None = None | |
| presence_penalty: float | None = None | |
| # Context limit | |
| # Turn-based limit (1 turn = user + assistant exchange). | |
| context_turn_limit: int | None = Field(default=None, alias="contextTurns") | |
| # Search configuration | |
| search_provider: Literal["tavily", "serpapi"] | None = Field(default=None, alias="searchProvider") | |
| tavily_api_key: str | None = Field(default=None, alias="tavilyApiKey") | |
| exa_api_key: str | None = Field(default=None, alias="exaApiKey") | |
| exa_search_category: str | None = Field(default=None, alias="exaSearchCategory") | |
| search_backend: str | None = Field(default=None, alias="searchBackend") | |
| serpapi_api_key: str | None = Field(default=None, alias="serpapiApiKey") | |
| concurrency_limit: int | None = Field(default=None, alias="concurrencyLimit") | |
| sequential_research: bool = Field(default=False, alias="sequentialResearch") | |
| # User context | |
| user_id: str | None = Field(default=None, alias="userId") | |
| user_timezone: str | None = Field(default=None, alias="userTimezone") | |
| user_locale: str | None = Field(default=None, alias="userLocale") | |
| enable_long_term_memory: bool = Field(default=False, alias="enableLongTermMemory") | |
| database_provider: str | None = Field(default=None, alias="databaseProvider") | |
| memory_provider: str | None = Field(default=None, alias="memoryProvider") | |
| memory_model: str | None = Field(default=None, alias="memoryModel") | |
| memory_base_url: str | None = Field(default=None, alias="memoryBaseUrl") | |
| memory_api_key: str | None = Field(default=None, alias="memoryApiKey") | |
| # Session Summary Configuration (Separate from Memory) | |
| summary_provider: str | None = Field(default=None, alias="summaryProvider") | |
| summary_model: str | None = Field(default=None, alias="summaryModel") | |
| summary_base_url: str | None = Field(default=None, alias="summaryBaseUrl") | |
| summary_api_key: str | None = Field(default=None, alias="summaryApiKey") | |
| enable_session_summary: bool = Field(default=True, alias="enableSessionSummary") | |
| is_editing: bool = Field(default=False, alias="isEditing", description="Forced summary rebuild flag (for edits/regenerates)") | |
| # Stream flag (default true for streaming) | |
| stream: bool = True | |
| # Internal use only: Structured Output schema (Agno v2) | |
| output_schema: Any | None = Field(default=None, exclude=True) | |
| # Internal use only: Feature flags set by backend routes | |
| enable_skills: bool = Field(default=False, exclude=True) | |
| # Internal use only: Personalized prompt from agent config | |
| personalized_prompt: str | None = Field(default=None, exclude=True) | |
| # Internal use only: Agent identification (set by resolve_agent_config) | |
| agent_id: str | None = Field(default=None, exclude=True) | |
| agent_name: str | None = Field(default=None, exclude=True) | |
| agent_emoji: str | None = Field(default=None, exclude=True) | |
| agent_description: str | None = Field(default=None, exclude=True) | |
| # Context and Session | |
| # Context and Session | |
| conversation_id: str | None = Field(default=None, alias="conversationId", description="Unique identifier for the conversation") | |
| model_config = {"populate_by_name": True} | |
| # ======================================================================== | |
| # HITL (Human-in-the-Loop) Interactive Form Support | |
| # ======================================================================== | |
| # When user submits a form, frontend sends run_id + field_values to resume | |
| run_id: str | None = Field(default=None, alias="runId", description="Agent run ID for HITL resumption") | |
| field_values: dict[str, Any] | None = Field(default=None, alias="fieldValues", description="User-submitted form field values") | |
| # Status of an agent in a team run | |
| AgentStatus = Literal["active", "waiting", "ready", "error", "idle"] | |
| class TextEvent(BaseModel): | |
| """Text content event.""" | |
| model_config = {"populate_by_name": True} | |
| type: Literal["text"] = "text" | |
| content: str | |
| # Agent identification for Team mode (identifies which agent generated this content) | |
| agent_id: str | None = Field(default=None, alias="agentId") | |
| agent_name: str | None = Field(default=None, alias="agentName") | |
| agent_role: str | None = Field(default=None, alias="agentRole") | |
| agent_emoji: str | None = Field(default=None, alias="agentEmoji") | |
| agent_status: AgentStatus | None = Field(default=None, alias="agentStatus") | |
| class ThoughtEvent(BaseModel): | |
| """Thought/reasoning content event.""" | |
| model_config = {"populate_by_name": True} | |
| type: Literal["thought"] = "thought" | |
| content: str | |
| text_index: int | None = Field(default=None, alias="textIndex") | |
| # Agent identification for Team mode (identifies which agent generated this thought) | |
| agent_id: str | None = Field(default=None, alias="agentId") | |
| agent_name: str | None = Field(default=None, alias="agentName") | |
| agent_role: str | None = Field(default=None, alias="agentRole") | |
| agent_emoji: str | None = Field(default=None, alias="agentEmoji") | |
| agent_status: AgentStatus | None = Field(default=None, alias="agentStatus") | |
| class ToolCallEvent(BaseModel): | |
| """Tool call event.""" | |
| model_config = {"populate_by_name": True} | |
| type: Literal["tool_call"] = Field(default="tool_call", alias="type") | |
| id: str | None = None | |
| name: str | |
| arguments: str | |
| text_index: int | None = Field(default=None, alias="textIndex") | |
| # Agent identification for Team mode | |
| agent_id: str | None = Field(default=None, alias="agentId") | |
| agent_name: str | None = Field(default=None, alias="agentName") | |
| agent_role: str | None = Field(default=None, alias="agentRole") | |
| agent_emoji: str | None = Field(default=None, alias="agentEmoji") | |
| agent_status: AgentStatus | None = Field(default=None, alias="agentStatus") | |
| class ToolResultEvent(BaseModel): | |
| """Tool result event.""" | |
| model_config = {"populate_by_name": True} | |
| type: Literal["tool_result"] = Field(default="tool_result", alias="type") | |
| id: str | None = None | |
| name: str | |
| status: Literal["calling", "done", "error"] | |
| output: Any = None | |
| error: str | None = None | |
| duration_ms: int | None = Field(default=None, alias="durationMs") | |
| # Agent identification for Team mode | |
| agent_id: str | None = Field(default=None, alias="agentId") | |
| agent_name: str | None = Field(default=None, alias="agentName") | |
| agent_role: str | None = Field(default=None, alias="agentRole") | |
| agent_emoji: str | None = Field(default=None, alias="agentEmoji") | |
| agent_status: AgentStatus | None = Field(default=None, alias="agentStatus") | |
| class SourceEvent(BaseModel): | |
| """Source/citation event.""" | |
| uri: str | |
| title: str | |
| snippet: str | None = None | |
| class DoneEvent(BaseModel): | |
| """Stream completion event.""" | |
| type: Literal["done"] = "done" | |
| content: str | |
| output: Any | None = None | |
| thought: str | None = None | |
| sources: list[SourceEvent] | None = None | |
| class ErrorEvent(BaseModel): | |
| """Error event.""" | |
| type: Literal["error"] = "error" | |
| error: str | |
| class FormRequestEvent(BaseModel): | |
| """Form request event for HITL interactive forms.""" | |
| type: Literal["form_request"] = "form_request" | |
| run_id: str = Field(..., description="Agent run ID for resumption") | |
| form_id: str | None = Field(default=None, description="Form identifier from tool call") | |
| title: str | None = Field(default=None, description="Form title") | |
| fields: list[dict[str, Any]] = Field(..., description="Form field definitions for frontend rendering") | |
| class AgentStatusEvent(BaseModel): | |
| """Event for signaling agent status transitions in Team mode.""" | |
| model_config = {"populate_by_name": True} | |
| type: Literal["agent_status"] = "agent_status" | |
| agent_id: str = Field(..., alias="agentId") | |
| status: AgentStatus | |
| # Union type for all SSE events | |
| StreamEvent = Union[ | |
| TextEvent, | |
| ThoughtEvent, | |
| ToolCallEvent, | |
| ToolResultEvent, | |
| DoneEvent, | |
| ErrorEvent, | |
| FormRequestEvent, | |
| AgentStatusEvent, | |
| ] | |
| # ================================================================================ | |
| # Update forward references | |
| # ================================================================================ | |
| ToolDefinition.model_rebuild() | |
| ToolCall.model_rebuild() | |