feat: extend init_data to load and sync user_agent_catalog

- Add UserAgentCatalogSeed and UserAgentCatalogYaml Pydantic models
- Add load_user_agent_catalog function to load from YAML
- Add _upsert_user_agent_catalog helper for upsert logic
- Add initialize_user_agent_catalog function for initialization
- Refactor initialize_data to call initialize_llm_catalog and initialize_user_agent_catalog
- Fix UserAgentCatalog.llm_id type from str to uuid.UUID
This commit is contained in:
qzl
2026-03-02 15:58:13 +08:00
parent fb8f4fdeeb
commit 4afc67b7a8
2 changed files with 105 additions and 3 deletions
+102 -2
View File
@@ -13,6 +13,7 @@ from core.db.session import AsyncSessionLocal
from core.logging import get_logger
from models.llm import Llm
from models.llm_factory import LlmFactory
from models.user_agent_catalog import UserAgentCatalog
logger = get_logger("core.config.initial.init_data")
@@ -33,6 +34,17 @@ class LlmCatalogSeed(BaseModel):
llms: list[LlmSeed]
class UserAgentCatalogSeed(BaseModel):
agent_type: str
llm_model_code: str
status: str
config: dict[str, Any]
class UserAgentCatalogYaml(BaseModel):
agents: list[UserAgentCatalogSeed]
def _default_catalog_path() -> Path:
return (
Path(__file__).resolve().parents[1] / "static" / "database" / "llm_catalog.yaml"
@@ -62,6 +74,32 @@ def load_llm_catalog(catalog_path: Path | None = None) -> dict[str, Any]:
return parsed.model_dump()
def _default_user_agent_catalog_path() -> Path:
return (
Path(__file__).resolve().parents[1]
/ "static"
/ "database"
/ "user_agent_catalog.yaml"
)
def load_user_agent_catalog(catalog_path: Path | None = None) -> dict[str, Any]:
path = catalog_path or _default_user_agent_catalog_path()
with path.open("r", encoding="utf-8") as file:
loaded = yaml.safe_load(file) or {}
if not isinstance(loaded, dict):
raise ValueError(f"Invalid user agent catalog format: {path}")
raw_agents = loaded.get("agents", [])
if not isinstance(raw_agents, list):
raise ValueError(f"Invalid user agent catalog agents section: {path}")
try:
parsed = UserAgentCatalogYaml.model_validate({"agents": list(raw_agents)})
except ValidationError as exc:
raise ValueError(f"Invalid user agent catalog data: {path}") from exc
return parsed.model_dump()
async def _upsert_factory(
session: AsyncSession,
*,
@@ -97,8 +135,63 @@ async def _upsert_llm(
llm.factory_id = factory_id
async def initialize_data() -> bool:
"""Initialize bootstrap data."""
async def _upsert_user_agent_catalog(
session: AsyncSession,
*,
agent_type: str,
llm_id: uuid.UUID,
status: str,
config: dict[str, Any],
) -> None:
result = await session.execute(
select(UserAgentCatalog).where(UserAgentCatalog.agent_type == agent_type)
)
catalog_entry = result.scalar_one_or_none()
if catalog_entry is None:
session.add(
UserAgentCatalog(
agent_type=agent_type,
llm_id=llm_id,
status=status,
config=config,
)
)
else:
catalog_entry.llm_id = llm_id
catalog_entry.status = status
catalog_entry.config = config
async def initialize_user_agent_catalog() -> None:
"""Initialize user agent catalog from YAML."""
catalog = load_user_agent_catalog()
async with AsyncSessionLocal() as session:
async with session.begin():
for agent in catalog["agents"]:
result = await session.execute(
select(Llm).where(Llm.model_code == agent["llm_model_code"])
)
llm = result.scalar_one_or_none()
if llm is None:
raise RuntimeError(
f"LLM model '{agent['llm_model_code']}' not found for agent type '{agent['agent_type']}'"
)
await _upsert_user_agent_catalog(
session,
agent_type=agent["agent_type"],
llm_id=llm.id,
status=agent["status"],
config=agent["config"],
)
logger.info("Initialized user agent catalog")
async def initialize_llm_catalog() -> None:
"""Initialize LLM catalog from YAML."""
catalog = load_llm_catalog()
async with AsyncSessionLocal() as session:
@@ -127,4 +220,11 @@ async def initialize_data() -> bool:
)
logger.info("Initialized LLM factory/model seed data")
async def initialize_data() -> bool:
"""Initialize bootstrap data."""
await initialize_llm_catalog()
await initialize_user_agent_catalog()
return True
+3 -1
View File
@@ -1,5 +1,7 @@
from __future__ import annotations
import uuid
from sqlalchemy import ForeignKey, String
from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy.orm import Mapped, mapped_column
@@ -14,7 +16,7 @@ class UserAgentCatalog(TimestampMixin, Base):
String(20),
primary_key=True,
)
llm_id: Mapped[str] = mapped_column(
llm_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
ForeignKey("llms.id", ondelete="RESTRICT"),
nullable=False,