"""Chat-related web schemas.""" from __future__ import annotations from typing import Any try: from pydantic import BaseModel, Field except ModuleNotFoundError: # pragma: no cover - fallback for skeleton-only environments class BaseModel: """Very small fallback shim used only so imports work without pydantic.""" def __init__(self, **kwargs: Any) -> None: annotations = getattr(self.__class__, "__annotations__", {}) for name in annotations: default = getattr(self.__class__, name, None) if name in kwargs: value = kwargs[name] else: value = default setattr(self, name, value) def model_dump(self, *, exclude_none: bool = False) -> dict[str, Any]: data = dict(self.__dict__) if exclude_none: data = {key: value for key, value in data.items() if value is not None} return data def Field(default: Any = None, **kwargs: Any) -> Any: default_factory = kwargs.get("default_factory") if default_factory is not None: return default_factory() return default class WebProviderTarget(BaseModel): """Web-facing provider target shape. 先保持和 runtime 里的 `ProviderTarget` 接近,但只暴露 Web 当前需要的字段。 后面如果 provider 层扩字段,再由这里显式补齐。 """ provider: str | None = None model: str | None = None api_key: str | None = None api_base: str | None = None extra_headers: dict[str, str] | None = None class WebChatRequest(BaseModel): """最小正式 chat 请求结构。""" message: str = Field(min_length=1) session_id: str | None = None user_id: str | None = None title: str | None = None execution_context: str | None = None model: str | None = None provider_name: str | None = None embedding_model: str | None = None temperature: float | None = None max_tokens: int | None = None thinking_enabled: bool | None = None max_tool_iterations: int | None = None fallback_target: WebProviderTarget | None = None auxiliary_target: WebProviderTarget | None = None embedding_target: WebProviderTarget | None = None reply_to_scheduled_run_id: str | None = None scheduled_reply_intent: str | None = None class WebChatResponse(BaseModel): """最小正式 chat 响应结构。""" session_id: str run_id: str output_text: str finish_reason: str tool_iterations: int provider_name: str | None = None model: str | None = None usage: dict[str, Any] = Field(default_factory=dict) task_id: str | None = None task_status: str | None = None evidence_status: str | None = None acceptance_state: str | None = None validation_result: dict[str, Any] | None = None class WebChatAcceptanceRequest(BaseModel): """User acceptance on the latest assistant result in chat.""" session_id: str run_id: str acceptance_type: str comment: str | None = None class WebChatAcceptanceResponse(BaseModel): """Acceptance recording result.""" session_id: str run_id: str task_id: str task_status: str acceptance_type: str feedback_type: str learning_candidates: list[dict[str, Any]] = Field(default_factory=list) class WebChatFeedbackRequest(BaseModel): """Backward-compatible feedback payload.""" session_id: str run_id: str feedback_type: str comment: str | None = None class WebChatFeedbackResponse(WebChatAcceptanceResponse): """Backward-compatible feedback response.""" class WebProviderConfigRequest(BaseModel): """Provider config update from the status page.""" enabled: bool = True model: str | None = None api_key: str | None = None api_base: str | None = None request_timeout_seconds: float | None = None class WebProviderConfigResponse(BaseModel): """Provider config update result.""" ok: bool provider: str enabled: bool class WebStatusResponse(BaseModel): """Web 宿主层状态响应。""" status: str running: bool mode: str class WebErrorResponse(BaseModel): """统一错误响应结构。""" detail: str