新增两套 persistence 模块,仿 persistence/agents/ 模板:
1. persistence/skills/
- SkillRow ORM (PK=name, owner_user_id, published, timestamps)
- SkillStore 抽象:list_visible / get_visible / get_any /
get_owned / create / ensure_legacy / update / update_admin /
delete / delete_admin
- SqlAlchemy 实现 SkillRepository
- MemorySkillStore 用于测试
- 可见性 = owner OR published OR builtin
2. persistence/notifications/
- NotificationRow ORM (id, user_id, type, title, body, payload JSON,
read, created_at)
- NotificationStore 抽象:create / list_for_user / unread_count /
mark_read / mark_all_read / delete
- SqlAlchemy 实现 NotificationRepository
- MemoryNotificationStore 用于测试
- sender.notify(user_id, type, ...) 全局接口;harness 不能 import
app.*,所以用 set_notification_store / get_notification_store
注入模式
3. persistence/models/__init__.py 注册 SkillRow + NotificationRow
后续阶段会接入路由、cascade、curator per-user 重构、前端。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
25 lines
1.0 KiB
Python
25 lines
1.0 KiB
Python
"""ORM model for in-app notifications."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
from typing import Any
|
|
|
|
from sqlalchemy import JSON, Boolean, DateTime, String, Text
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from deerflow.persistence.base import Base
|
|
|
|
|
|
class NotificationRow(Base):
|
|
__tablename__ = "notifications"
|
|
|
|
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
|
user_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
|
type: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
title: Mapped[str] = mapped_column(String(256), nullable=False, default="")
|
|
body: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
|
payload: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False, default=dict)
|
|
read: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, index=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC), index=True)
|