- agents 表新增 is_private 列与迁移 20260526_01;列表 filter 拆分为公开
广场用的 _listing_filter(剔除私密)与单条访问用的 _visible_filter(保留可达)
- system_settings 增 PrivateSquareSettings(enabled + password_hash),
对应 GET/PUT /api/system-settings/private-square 由管理员管理
- /api/agents 接口:列表/创建/更新新增 is_private 字段;新增
POST /api/agents/private-square/list(密码校验后返回私密智能体)与
PUT /api/agents/{id}/private(管理员跨用户搬动智能体)
- 前端「智能体」页签新增「私密广场」入口(密码校验 + sessionStorage 缓存 +
锁定按钮),卡片增加紫色私密徽章与盾牌切换按钮(owner 自助 / 管理员跨用户),
「广场」与首页推荐候选均剔除私密智能体
- 新增管理员配置页 /settings/private-square 与侧边栏入口
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
38 lines
2.1 KiB
Python
38 lines
2.1 KiB
Python
"""ORM model for custom agents."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
|
|
from sqlalchemy import BigInteger, Boolean, String
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from deerflow.persistence.base import Base
|
|
from deerflow.persistence.types import BeijingDateTime
|
|
|
|
|
|
class AgentRow(Base):
|
|
__tablename__ = "agents"
|
|
|
|
# Stored as a plain string so the same id can be used as the filesystem
|
|
# directory name under {base_dir}/agents/{id}/.
|
|
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(191), nullable=False, index=True)
|
|
description: Mapped[str] = mapped_column(String(1024), nullable=False, default="")
|
|
user_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
|
published: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, index=True)
|
|
# When True, the agent is moved into the password-gated "private square"
|
|
# (私密广场) and is hidden from the regular public square / built-in list.
|
|
# The flag is independent of ``published``: a private agent is still
|
|
# visible to its owner in the "我的" tab, and visible to anyone in the
|
|
# private-square listing once the password has been verified.
|
|
is_private: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, index=True)
|
|
# NULL = not featured on the homepage selector. Non-NULL = admin-curated
|
|
# featured rank (lower sorts first). Only ``published=True`` agents are
|
|
# eligible; the router enforces that invariant on writes. BIGINT so the
|
|
# frontend can seed initial ranks from ``Date.now()`` (ms-resolution
|
|
# timestamps overflow a 4-byte INT on MySQL).
|
|
featured_order: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True)
|
|
created_at: Mapped[datetime] = mapped_column(BeijingDateTime(), nullable=False, default=lambda: datetime.now(UTC))
|
|
updated_at: Mapped[datetime] = mapped_column(BeijingDateTime(), nullable=False, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))
|