mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-07 23:02:39 +02:00
Merge upstream/dev into feature/multi-agent
This commit is contained in:
commit
5119915f4f
278 changed files with 34669 additions and 8970 deletions
|
|
@ -215,6 +215,12 @@ class GlobalImageGenConfigRead(BaseModel):
|
|||
Schema for reading global image generation configs from YAML.
|
||||
Global configs have negative IDs. API key is hidden.
|
||||
ID 0 is reserved for Auto mode (LiteLLM Router load balancing).
|
||||
|
||||
The ``billing_tier`` field allows the frontend to show a Premium/Free
|
||||
badge and (more importantly) tells the backend whether to debit the
|
||||
user's premium credit pool when this config is used. ``"free"`` is
|
||||
the default for backward compatibility — admins must explicitly opt
|
||||
a global config into ``"premium"``.
|
||||
"""
|
||||
|
||||
id: int = Field(
|
||||
|
|
@ -231,3 +237,24 @@ class GlobalImageGenConfigRead(BaseModel):
|
|||
litellm_params: dict[str, Any] | None = None
|
||||
is_global: bool = True
|
||||
is_auto_mode: bool = False
|
||||
billing_tier: str = Field(
|
||||
default="free",
|
||||
description="'free' or 'premium'. Premium debits the user's premium credit pool (USD-cost-based).",
|
||||
)
|
||||
is_premium: bool = Field(
|
||||
default=False,
|
||||
description=(
|
||||
"Convenience boolean derived server-side from "
|
||||
"``billing_tier == 'premium'``. The new-chat model selector "
|
||||
"keys its Free/Premium badge off this field for parity with "
|
||||
"chat (`GlobalLLMConfigRead.is_premium`)."
|
||||
),
|
||||
)
|
||||
quota_reserve_micros: int | None = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"Optional override for the reservation amount (in micro-USD) used when "
|
||||
"this image generation is premium. Falls back to "
|
||||
"QUOTA_DEFAULT_IMAGE_RESERVE_MICROS when omitted."
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ class TokenUsageSummary(BaseModel):
|
|||
prompt_tokens: int = 0
|
||||
completion_tokens: int = 0
|
||||
total_tokens: int = 0
|
||||
cost_micros: int = 0
|
||||
model_breakdown: dict | None = None
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
|
@ -199,6 +200,21 @@ class NewChatUserImagePart(BaseModel):
|
|||
return to_data_url(self.media_type, self.data)
|
||||
|
||||
|
||||
class MentionedDocumentInfo(BaseModel):
|
||||
"""Display metadata for a single ``@``-mentioned document.
|
||||
|
||||
The full triple ``{id, title, document_type}`` is forwarded by the
|
||||
frontend mention chip so the server can embed it in the persisted
|
||||
user message ``ContentPart[]`` (single ``mentioned-documents`` part).
|
||||
The history loader then renders the chips on reload without an extra
|
||||
fetch — mirrors the pre-refactor frontend ``persistUserTurn`` shape.
|
||||
"""
|
||||
|
||||
id: int
|
||||
title: str = Field(..., min_length=1, max_length=500)
|
||||
document_type: str = Field(..., min_length=1, max_length=100)
|
||||
|
||||
|
||||
class NewChatRequest(BaseModel):
|
||||
"""Request schema for the deep agent chat endpoint."""
|
||||
|
||||
|
|
@ -212,6 +228,17 @@ class NewChatRequest(BaseModel):
|
|||
mentioned_surfsense_doc_ids: list[int] | None = (
|
||||
None # Optional SurfSense documentation IDs mentioned with @ in the chat
|
||||
)
|
||||
mentioned_documents: list[MentionedDocumentInfo] | None = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"Display metadata (id, title, document_type) for every "
|
||||
"@-mentioned document. Persisted as a ``mentioned-documents`` "
|
||||
"ContentPart on the user message so reload renders chips "
|
||||
"without an extra fetch. Optional and additive — when None "
|
||||
"the user message is persisted without a mentioned-documents "
|
||||
"part."
|
||||
),
|
||||
)
|
||||
disabled_tools: list[str] | None = (
|
||||
None # Optional list of tool names the user has disabled from the UI
|
||||
)
|
||||
|
|
@ -263,6 +290,16 @@ class RegenerateRequest(BaseModel):
|
|||
)
|
||||
mentioned_document_ids: list[int] | None = None
|
||||
mentioned_surfsense_doc_ids: list[int] | None = None
|
||||
mentioned_documents: list[MentionedDocumentInfo] | None = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"Display metadata (id, title, document_type) for every "
|
||||
"@-mentioned document on the edited user turn. Only used "
|
||||
"when ``user_query`` is non-None (edit). Persisted as a "
|
||||
"``mentioned-documents`` ContentPart on the new user "
|
||||
"message. None means no chip metadata."
|
||||
),
|
||||
)
|
||||
disabled_tools: list[str] | None = None
|
||||
filesystem_mode: Literal["cloud", "desktop_local_folder"] = "cloud"
|
||||
client_platform: Literal["web", "desktop"] = "web"
|
||||
|
|
@ -336,6 +373,34 @@ class ResumeRequest(BaseModel):
|
|||
filesystem_mode: Literal["cloud", "desktop_local_folder"] = "cloud"
|
||||
client_platform: Literal["web", "desktop"] = "web"
|
||||
local_filesystem_mounts: list[LocalFilesystemMountPayload] | None = None
|
||||
mentioned_documents: list[MentionedDocumentInfo] | None = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"Display metadata forwarded for symmetry with /new_chat and "
|
||||
"/regenerate. Resume reuses the original interrupted user "
|
||||
"turn so the server does not write a new user message. "
|
||||
"Currently unused but accepted to keep request bodies "
|
||||
"uniform across the three streaming entrypoints."
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class CancelActiveTurnResponse(BaseModel):
|
||||
"""Response for canceling an active turn on a chat thread."""
|
||||
|
||||
status: Literal["cancelling", "idle"]
|
||||
error_code: Literal["TURN_CANCELLING", "NO_ACTIVE_TURN"]
|
||||
retry_after_ms: int | None = None
|
||||
retry_after_at: int | None = None
|
||||
|
||||
|
||||
class TurnStatusResponse(BaseModel):
|
||||
"""Current turn execution status for a thread."""
|
||||
|
||||
status: Literal["idle", "busy", "cancelling"]
|
||||
active_turn_id: str | None = None
|
||||
retry_after_ms: int | None = None
|
||||
retry_after_at: int | None = None
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
|
|
|||
|
|
@ -92,6 +92,20 @@ class NewLLMConfigRead(NewLLMConfigBase):
|
|||
created_at: datetime
|
||||
search_space_id: int
|
||||
user_id: uuid.UUID
|
||||
# Capability flag derived at the API boundary (no DB column). Default
|
||||
# True matches the conservative-allow stance — a BYOK row that the
|
||||
# route forgot to augment is not pre-judged. The streaming-task
|
||||
# safety net is the only place a False actually blocks a request.
|
||||
supports_image_input: bool = Field(
|
||||
default=True,
|
||||
description=(
|
||||
"Whether the BYOK chat config can accept image inputs. Derived "
|
||||
"at the route boundary from LiteLLM's authoritative model map "
|
||||
"(``litellm.supports_vision``) — there is no DB column. "
|
||||
"Default True is the conservative-allow stance for unknown / "
|
||||
"unmapped models."
|
||||
),
|
||||
)
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
|
@ -121,6 +135,15 @@ class NewLLMConfigPublic(BaseModel):
|
|||
created_at: datetime
|
||||
search_space_id: int
|
||||
user_id: uuid.UUID
|
||||
# Capability flag derived at the API boundary (see NewLLMConfigRead).
|
||||
supports_image_input: bool = Field(
|
||||
default=True,
|
||||
description=(
|
||||
"Whether the BYOK chat config can accept image inputs. Derived "
|
||||
"at the route boundary from LiteLLM's authoritative model map. "
|
||||
"Default True is the conservative-allow stance."
|
||||
),
|
||||
)
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
|
@ -172,6 +195,19 @@ class GlobalNewLLMConfigRead(BaseModel):
|
|||
seo_title: str | None = None
|
||||
seo_description: str | None = None
|
||||
quota_reserve_tokens: int | None = None
|
||||
supports_image_input: bool = Field(
|
||||
default=True,
|
||||
description=(
|
||||
"Whether the model accepts image inputs (multimodal vision). "
|
||||
"Derived server-side: OpenRouter dynamic configs use "
|
||||
"``architecture.input_modalities``; YAML / BYOK use LiteLLM's "
|
||||
"authoritative model map (``litellm.supports_vision``). The "
|
||||
"new-chat selector hints with a 'No image' badge when this is "
|
||||
"False and there are pending image attachments. The streaming "
|
||||
"task fails fast only when LiteLLM *explicitly* marks a model "
|
||||
"as text-only — unknown / unmapped models default-allow."
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
|
|
|||
|
|
@ -70,13 +70,17 @@ class CreateTokenCheckoutSessionResponse(BaseModel):
|
|||
|
||||
|
||||
class TokenPurchaseRead(BaseModel):
|
||||
"""Serialized premium token purchase record."""
|
||||
"""Serialized premium credit purchase record.
|
||||
|
||||
``credit_micros_granted`` is in micro-USD (1_000_000 = $1.00). The
|
||||
schema name kept ``Token`` for API back-compat with pinned clients.
|
||||
"""
|
||||
|
||||
id: uuid.UUID
|
||||
stripe_checkout_session_id: str
|
||||
stripe_payment_intent_id: str | None = None
|
||||
quantity: int
|
||||
tokens_granted: int
|
||||
credit_micros_granted: int
|
||||
amount_total: int | None = None
|
||||
currency: str | None = None
|
||||
status: str
|
||||
|
|
@ -87,15 +91,19 @@ class TokenPurchaseRead(BaseModel):
|
|||
|
||||
|
||||
class TokenPurchaseHistoryResponse(BaseModel):
|
||||
"""Response containing the user's premium token purchases."""
|
||||
"""Response containing the user's premium credit purchases."""
|
||||
|
||||
purchases: list[TokenPurchaseRead]
|
||||
|
||||
|
||||
class TokenStripeStatusResponse(BaseModel):
|
||||
"""Response describing token-buying availability and current quota."""
|
||||
"""Response describing premium-credit-buying availability and balance.
|
||||
|
||||
All ``premium_credit_micros_*`` fields are in micro-USD; the FE
|
||||
divides by 1_000_000 to display USD.
|
||||
"""
|
||||
|
||||
token_buying_enabled: bool
|
||||
premium_tokens_used: int = 0
|
||||
premium_tokens_limit: int = 0
|
||||
premium_tokens_remaining: int = 0
|
||||
premium_credit_micros_used: int = 0
|
||||
premium_credit_micros_limit: int = 0
|
||||
premium_credit_micros_remaining: int = 0
|
||||
|
|
|
|||
|
|
@ -62,6 +62,15 @@ class VisionLLMConfigPublic(BaseModel):
|
|||
|
||||
|
||||
class GlobalVisionLLMConfigRead(BaseModel):
|
||||
"""Schema for reading global vision LLM configs from YAML.
|
||||
|
||||
The ``billing_tier`` field allows the frontend to show a Premium/Free
|
||||
badge and (more importantly) tells the backend whether to debit the
|
||||
user's premium credit pool when this config is used. ``"free"`` is
|
||||
the default for backward compatibility — admins must explicitly opt
|
||||
a global config into ``"premium"``.
|
||||
"""
|
||||
|
||||
id: int = Field(...)
|
||||
name: str
|
||||
description: str | None = None
|
||||
|
|
@ -73,3 +82,35 @@ class GlobalVisionLLMConfigRead(BaseModel):
|
|||
litellm_params: dict[str, Any] | None = None
|
||||
is_global: bool = True
|
||||
is_auto_mode: bool = False
|
||||
billing_tier: str = Field(
|
||||
default="free",
|
||||
description="'free' or 'premium'. Premium debits the user's premium credit pool (USD-cost-based).",
|
||||
)
|
||||
is_premium: bool = Field(
|
||||
default=False,
|
||||
description=(
|
||||
"Convenience boolean derived server-side from "
|
||||
"``billing_tier == 'premium'``. The new-chat model selector "
|
||||
"keys its Free/Premium badge off this field for parity with "
|
||||
"chat (`GlobalLLMConfigRead.is_premium`)."
|
||||
),
|
||||
)
|
||||
quota_reserve_tokens: int | None = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"Optional override for the per-call reservation in *tokens* — "
|
||||
"converted to micro-USD via the model's input/output prices at "
|
||||
"reservation time. Falls back to QUOTA_DEFAULT_RESERVE_TOKENS."
|
||||
),
|
||||
)
|
||||
input_cost_per_token: float | None = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"Optional input price in USD/token. Used by pricing_registration to "
|
||||
"register custom Azure / OpenRouter aliases with LiteLLM at startup."
|
||||
),
|
||||
)
|
||||
output_cost_per_token: float | None = Field(
|
||||
default=None,
|
||||
description="Optional output price in USD/token. Pair with input_cost_per_token.",
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue