feat(ui): implement premium beige design system and ux refinements
This commit is contained in:
@@ -4,6 +4,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
|
||||
|
||||
from psycopg.types.json import Json
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from psycopg_pool import AsyncConnectionPool
|
||||
|
||||
@@ -89,7 +91,7 @@ class PostgresAnalyticsRecorder:
|
||||
"duration_ms": duration_ms,
|
||||
"success": success,
|
||||
"error_message": error_message,
|
||||
"metadata": metadata or {},
|
||||
"metadata": Json(metadata or {}),
|
||||
}
|
||||
async with self._pool.connection() as conn:
|
||||
await conn.execute(_INSERT_SQL, params)
|
||||
|
||||
@@ -17,7 +17,7 @@ class Settings(BaseSettings):
|
||||
|
||||
database_url: str
|
||||
|
||||
llm_provider: Literal["anthropic", "openai", "google"] = "anthropic"
|
||||
llm_provider: Literal["anthropic", "openai", "azure_openai", "google"] = "anthropic"
|
||||
llm_model: str = "claude-sonnet-4-6"
|
||||
|
||||
session_ttl_minutes: int = 30
|
||||
@@ -34,6 +34,10 @@ class Settings(BaseSettings):
|
||||
|
||||
anthropic_api_key: str = ""
|
||||
openai_api_key: str = ""
|
||||
azure_openai_api_key: str = ""
|
||||
azure_openai_endpoint: str = ""
|
||||
azure_openai_api_version: str = "2024-12-01-preview"
|
||||
azure_openai_deployment: str = ""
|
||||
google_api_key: str = ""
|
||||
|
||||
@model_validator(mode="after")
|
||||
@@ -41,6 +45,7 @@ class Settings(BaseSettings):
|
||||
key_map = {
|
||||
"anthropic": self.anthropic_api_key,
|
||||
"openai": self.openai_api_key,
|
||||
"azure_openai": self.azure_openai_api_key,
|
||||
"google": self.google_api_key,
|
||||
}
|
||||
key = key_map.get(self.llm_provider, "")
|
||||
@@ -49,4 +54,13 @@ class Settings(BaseSettings):
|
||||
f"API key for provider '{self.llm_provider}' is required. "
|
||||
f"Set the corresponding environment variable."
|
||||
)
|
||||
if self.llm_provider == "azure_openai":
|
||||
if not self.azure_openai_endpoint:
|
||||
raise ValueError(
|
||||
"AZURE_OPENAI_ENDPOINT is required for azure_openai provider."
|
||||
)
|
||||
if not self.azure_openai_deployment:
|
||||
raise ValueError(
|
||||
"AZURE_OPENAI_DEPLOYMENT is required for azure_openai provider."
|
||||
)
|
||||
return self
|
||||
|
||||
@@ -9,7 +9,7 @@ if TYPE_CHECKING:
|
||||
|
||||
_ENSURE_SQL = """
|
||||
INSERT INTO conversations
|
||||
(thread_id, started_at, last_activity)
|
||||
(thread_id, created_at, last_activity)
|
||||
VALUES
|
||||
(%(thread_id)s, NOW(), NOW())
|
||||
ON CONFLICT (thread_id) DO NOTHING
|
||||
|
||||
@@ -31,6 +31,16 @@ def create_llm(settings: Settings) -> BaseChatModel:
|
||||
api_key=settings.openai_api_key,
|
||||
)
|
||||
|
||||
if provider == "azure_openai":
|
||||
from langchain_openai import AzureChatOpenAI
|
||||
|
||||
return AzureChatOpenAI(
|
||||
azure_deployment=settings.azure_openai_deployment,
|
||||
azure_endpoint=settings.azure_openai_endpoint,
|
||||
api_key=settings.azure_openai_api_key,
|
||||
api_version=settings.azure_openai_api_version,
|
||||
)
|
||||
|
||||
if provider == "google":
|
||||
from langchain_google_genai import ChatGoogleGenerativeAI
|
||||
|
||||
@@ -39,4 +49,7 @@ def create_llm(settings: Settings) -> BaseChatModel:
|
||||
google_api_key=settings.google_api_key,
|
||||
)
|
||||
|
||||
raise ValueError(f"Unknown LLM provider: '{provider}'. Use 'anthropic', 'openai', or 'google'.")
|
||||
raise ValueError(
|
||||
f"Unknown LLM provider: '{provider}'. "
|
||||
"Use 'anthropic', 'openai', 'azure_openai', or 'google'."
|
||||
)
|
||||
|
||||
@@ -54,7 +54,10 @@ async def handle_user_message(
|
||||
interrupt_manager: InterruptManager | None = None,
|
||||
) -> None:
|
||||
"""Process a user message through the graph and stream results back."""
|
||||
if session_manager.is_expired(thread_id):
|
||||
# Touch first so new sessions are created before expiry check.
|
||||
# For existing sessions, touch resets the sliding window.
|
||||
existing = session_manager.get_state(thread_id)
|
||||
if existing is not None and session_manager.is_expired(thread_id):
|
||||
msg = "Session expired. Please start a new conversation."
|
||||
await _send_json(ws, {"type": "error", "message": msg})
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user