初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,72 @@
|
||||
"""SQLAlchemy 模型导出。"""
|
||||
|
||||
from app.models.big_cycle import BigCycle
|
||||
from app.models.candidates import MemoryCandidate, ProfileCandidate
|
||||
from app.models.character import Character
|
||||
from app.models.chat import ChatMessage, ChatSession
|
||||
from app.models.drive import CuriosityQuestion, ExploratorySubgoal
|
||||
from app.models.evolution import EvolutionCandidate
|
||||
from app.models.governance import (
|
||||
AgentRosterEntry,
|
||||
GenerationPreferences,
|
||||
Goal,
|
||||
PerceptionChannel,
|
||||
Plan,
|
||||
WorldEntity,
|
||||
)
|
||||
from app.models.idempotency import IdempotencyKey
|
||||
from app.models.imports import CharacterImportJob, ImportItem
|
||||
from app.models.lorebook import Lorebook, LorebookEntry
|
||||
from app.models.mcp_servers import McpServer
|
||||
from app.models.memory import Memory, MemoryLink
|
||||
from app.models.personality import PersonalityProposal, PersonalityVersion
|
||||
from app.models.personality_emotion import CharacterEmotionState
|
||||
from app.models.rbac import Permission, Role, RolePermission, UserRole
|
||||
from app.models.runtime import Event, Run
|
||||
from app.models.safety import AuditEvent, PendingConfirmationRecord
|
||||
from app.models.skills import Skill
|
||||
from app.models.time_anniversary import TimeAnniversary
|
||||
from app.models.user import User
|
||||
from app.models.world import CharacterWorldEntity, WorldRelation
|
||||
|
||||
__all__ = [
|
||||
"AgentRosterEntry",
|
||||
"AuditEvent",
|
||||
"BigCycle",
|
||||
"Character",
|
||||
"CharacterEmotionState",
|
||||
"CharacterImportJob",
|
||||
"CharacterWorldEntity",
|
||||
"ChatMessage",
|
||||
"ChatSession",
|
||||
"CuriosityQuestion",
|
||||
"Event",
|
||||
"EvolutionCandidate",
|
||||
"ExploratorySubgoal",
|
||||
"GenerationPreferences",
|
||||
"Goal",
|
||||
"IdempotencyKey",
|
||||
"ImportItem",
|
||||
"Lorebook",
|
||||
"LorebookEntry",
|
||||
"McpServer",
|
||||
"Memory",
|
||||
"MemoryCandidate",
|
||||
"MemoryLink",
|
||||
"PendingConfirmationRecord",
|
||||
"PerceptionChannel",
|
||||
"Permission",
|
||||
"PersonalityProposal",
|
||||
"PersonalityVersion",
|
||||
"Plan",
|
||||
"ProfileCandidate",
|
||||
"Role",
|
||||
"RolePermission",
|
||||
"Run",
|
||||
"Skill",
|
||||
"TimeAnniversary",
|
||||
"User",
|
||||
"UserRole",
|
||||
"WorldEntity",
|
||||
"WorldRelation",
|
||||
]
|
||||
@@ -0,0 +1,38 @@
|
||||
"""大周天运行记录(architecture §3.2;v1-scope §3.3)。
|
||||
|
||||
大周天是长期演化循环:记忆积累 → 自我评估 → 演化策略 → 候选生成。
|
||||
本表记录每次循环的触发、阶段与终态;演化候选 / 内驱力 / 自动抽取由后续
|
||||
子阶段写入各自表,循环本身只承载编排与留痕。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_cycle_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class BigCycle(Base):
|
||||
"""大周天循环运行记录。"""
|
||||
|
||||
__tablename__ = "big_cycles"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_cycle_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
trigger: Mapped[str] = mapped_column(String(40), nullable=False)
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending", index=True)
|
||||
phase: Mapped[str | None] = mapped_column(String(40))
|
||||
memory_count_at_trigger: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
evaluation_snapshot_json: Mapped[str | None] = mapped_column(Text)
|
||||
summary: Mapped[str | None] = mapped_column(Text)
|
||||
error_code: Mapped[str | None] = mapped_column(String(80))
|
||||
error_message: Mapped[str | None] = mapped_column(Text)
|
||||
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
@@ -0,0 +1,67 @@
|
||||
"""资料导入候选模型(api-spec §8;契约字典 §10.6 candidate.status)。
|
||||
|
||||
导入资料经模型抽取产生档案 / 记忆候选,待用户审核后应用;人格建议复用
|
||||
``personality_proposals``(005)。``evidence_ids`` 指向 ``import_items.id``
|
||||
(EvidenceRef source_type = ``import_item``)。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, Float, ForeignKey, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_memory_candidate_id, new_profile_candidate_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class ProfileCandidate(Base):
|
||||
"""人物档案候选(契约字典 §10.6)。"""
|
||||
|
||||
__tablename__ = "character_profile_candidates"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_profile_candidate_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
import_job_id: Mapped[str | None] = mapped_column(
|
||||
String(80), ForeignKey("character_import_jobs.id"), index=True
|
||||
)
|
||||
field: Mapped[str] = mapped_column(String(60), nullable=False)
|
||||
value: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
evidence_ids_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending", index=True)
|
||||
reason: Mapped[str | None] = mapped_column(Text)
|
||||
reviewed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class MemoryCandidate(Base):
|
||||
"""记忆候选(契约字典 §10.6)。"""
|
||||
|
||||
__tablename__ = "memory_candidates"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_memory_candidate_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
import_job_id: Mapped[str | None] = mapped_column(
|
||||
String(80), ForeignKey("character_import_jobs.id"), index=True
|
||||
)
|
||||
cycle_id: Mapped[str | None] = mapped_column(
|
||||
String(80), ForeignKey("big_cycles.id"), index=True
|
||||
)
|
||||
type: Mapped[str] = mapped_column(String(60), nullable=False)
|
||||
title: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
importance: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
sensitivity: Mapped[str] = mapped_column(String(40), nullable=False, default="low")
|
||||
evidence_ids_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending", index=True)
|
||||
reason: Mapped[str | None] = mapped_column(Text)
|
||||
reviewed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
@@ -0,0 +1,43 @@
|
||||
"""人物模型。"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_character_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Character(Base):
|
||||
__tablename__ = "characters"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_character_id)
|
||||
name: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
display_name: Mapped[str | None] = mapped_column(String(120))
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="active", index=True)
|
||||
language: Mapped[str] = mapped_column(String(20), nullable=False, default="zh-CN")
|
||||
profile_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
model_policy_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
safety_policy_id: Mapped[str | None] = mapped_column(String(80))
|
||||
current_personality_version_id: Mapped[str | None] = mapped_column(String(80))
|
||||
# 道体恒定层(设计理念 §2.1):不可运行时覆盖的人格内核快照,
|
||||
# 由 personality_version 收敛 / 用户确认 / 酒馆卡降生写入,组装运行时契约时做完整性校验。
|
||||
personality_summary: Mapped[str | None] = mapped_column(Text)
|
||||
mission: Mapped[str | None] = mapped_column(Text)
|
||||
safety_guidelines: Mapped[str | None] = mapped_column(Text)
|
||||
current_mood_id: Mapped[str | None] = mapped_column(String(80))
|
||||
privacy_level: Mapped[str] = mapped_column(String(40), nullable=False, default="normal")
|
||||
owner_scope: Mapped[str] = mapped_column(String(80), nullable=False, index=True)
|
||||
is_system_template: Mapped[bool] = mapped_column(
|
||||
Boolean, nullable=False, default=False, index=True
|
||||
)
|
||||
source_template_id: Mapped[str | None] = mapped_column(String(80), index=True)
|
||||
template_key: Mapped[str | None] = mapped_column(String(80), index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
activated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
archived_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
@@ -0,0 +1,52 @@
|
||||
"""聊天会话与消息模型。"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_message_id, new_session_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class ChatSession(Base):
|
||||
__tablename__ = "chat_sessions"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_session_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
title: Mapped[str | None] = mapped_column(String(200))
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="active", index=True)
|
||||
owner_scope: Mapped[str] = mapped_column(String(80), nullable=False, default="", index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class ChatMessage(Base):
|
||||
__tablename__ = "chat_messages"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_message_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
session_id: Mapped[str] = mapped_column(String(80), ForeignKey("chat_sessions.id"), index=True)
|
||||
role: Mapped[str] = mapped_column(String(40), nullable=False)
|
||||
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
modality: Mapped[str] = mapped_column(String(40), nullable=False, default="text")
|
||||
run_id: Mapped[str | None] = mapped_column(String(80), ForeignKey("runs.id"), index=True)
|
||||
metadata_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
sensitivity: Mapped[str] = mapped_column(String(40), nullable=False, default="low")
|
||||
versions_json: Mapped[str] = mapped_column(
|
||||
Text,
|
||||
nullable=False,
|
||||
default="[]",
|
||||
comment="版本历史 JSON 数组:[{content, created_at}],按生成顺序排列,末尾最新",
|
||||
)
|
||||
active_version_idx: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
nullable=False,
|
||||
default=0,
|
||||
comment="当前活跃版本在 versions_json 中的索引(0-based)",
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
@@ -0,0 +1,54 @@
|
||||
"""大周天内驱力模型(database-schema §22;intrinsic-drive §5)。
|
||||
|
||||
好奇问题记录「匮乏感」,探索性次生目标由好奇问题转化而来、可审核(candidate →
|
||||
approved/deferred/rejected)。``cycle_id`` 关联触发本次的大周天循环。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, Float, ForeignKey, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_curiosity_id, new_subgoal_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class CuriosityQuestion(Base):
|
||||
"""好奇问题(缺口记录,无审核状态)。"""
|
||||
|
||||
__tablename__ = "curiosity_questions"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_curiosity_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
cycle_id: Mapped[str] = mapped_column(String(80), ForeignKey("big_cycles.id"), index=True)
|
||||
question: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
source: Mapped[str] = mapped_column(String(60), nullable=False, default="reflection")
|
||||
related_entities_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
expected_value: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
urgency: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
risk_level: Mapped[str] = mapped_column(String(8), nullable=False, default="L4")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
|
||||
|
||||
class ExploratorySubgoal(Base):
|
||||
"""探索性次生目标(可审核,本期不自动执行)。"""
|
||||
|
||||
__tablename__ = "exploratory_subgoals"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_subgoal_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
cycle_id: Mapped[str] = mapped_column(String(80), ForeignKey("big_cycles.id"), index=True)
|
||||
parent_goal_id: Mapped[str | None] = mapped_column(String(80))
|
||||
curiosity_question_id: Mapped[str] = mapped_column(
|
||||
String(80), ForeignKey("curiosity_questions.id"), index=True
|
||||
)
|
||||
title: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
description: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
expected_information_gain: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
interruption_cost: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
risk_level: Mapped[str] = mapped_column(String(8), nullable=False, default="L4")
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="candidate", index=True)
|
||||
reviewed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
reviewed_by: Mapped[str] = mapped_column(String(80), nullable=False, default="system")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
@@ -0,0 +1,50 @@
|
||||
"""大周天演化候选模型(契约字典 §12;self-evolution-design.md §11)。
|
||||
|
||||
演化候选是大周天(及未来镜界 / 反馈)产出的统一轻量演化增量载体;``type`` 区分
|
||||
候选对象,``level``(L0-L4)决定半自动边界(见 [大周天演化候选落地设计]
|
||||
../../docs/domain/core-domains.md §5)。``cycle_id`` 关联触发本次
|
||||
的大周天循环,``resulting_target_id`` 记录派生后的下游资源 ID。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, Float, ForeignKey, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_evolution_candidate_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class EvolutionCandidate(Base):
|
||||
"""演化候选(统一表)。"""
|
||||
|
||||
__tablename__ = "evolution_candidates"
|
||||
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(80), primary_key=True, default=new_evolution_candidate_id
|
||||
)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
cycle_id: Mapped[str] = mapped_column(String(80), ForeignKey("big_cycles.id"), index=True)
|
||||
type: Mapped[str] = mapped_column(String(60), nullable=False)
|
||||
source: Mapped[str] = mapped_column(String(60), nullable=False, default="big_cycle")
|
||||
level: Mapped[str] = mapped_column(String(8), nullable=False, default="L4")
|
||||
scope: Mapped[str] = mapped_column(String(40), nullable=False, default="character_scope")
|
||||
title: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
proposal: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
delta_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
evidence_ids_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
benefit_score: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
risk_score: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
drift_score: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
||||
auto_apply_allowed: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending", index=True)
|
||||
resulting_target_id: Mapped[str | None] = mapped_column(String(80))
|
||||
error_message: Mapped[str | None] = mapped_column(Text)
|
||||
reviewed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
reviewed_by: Mapped[str] = mapped_column(String(80), nullable=False, default="system")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
@@ -0,0 +1,197 @@
|
||||
"""司命台治理对象模型(九枢治理视图,api-spec §19.4)。
|
||||
|
||||
目标(太一)/ 感知通道(烛照)/ 世界实体(河图)/ 计划(洛书)/ 天工阁角色
|
||||
为可增长的开放集合;生成偏好(模型网关 §4.3)为本地单用户单行配置。
|
||||
这些对象当前由司命台治理视图维护,对应枢的自动运行时暂未启用(见
|
||||
docs/operations/capability-matrix.md §8)。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import (
|
||||
Boolean,
|
||||
DateTime,
|
||||
Float,
|
||||
ForeignKey,
|
||||
Integer,
|
||||
String,
|
||||
Text,
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.ids import new_goal_id, new_plan_id, new_world_entity_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Goal(Base):
|
||||
"""太一枢目标节点(契约字典 §5.11 / §5.12)。"""
|
||||
|
||||
__tablename__ = "goals"
|
||||
|
||||
def __init__(self, **kwargs: object) -> None:
|
||||
# Python 端默认值:mapped_column(default=...) 仅在 ORM flush 时生效,
|
||||
# __init__ 覆盖使测试在不侵入 session 时就能验证默认值。
|
||||
kwargs.setdefault("type", "session")
|
||||
kwargs.setdefault("progress", 0.0)
|
||||
super().__init__(**kwargs)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_goal_id)
|
||||
character_id: Mapped[str | None] = mapped_column(
|
||||
String(80), ForeignKey("characters.id"), nullable=True, index=True
|
||||
)
|
||||
title: Mapped[str] = mapped_column(String(300), nullable=False)
|
||||
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
level: Mapped[str] = mapped_column(String(40), nullable=False, default="task", index=True)
|
||||
type: Mapped[str] = mapped_column(String(40), nullable=False, default="session")
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending", index=True)
|
||||
priority: Mapped[int] = mapped_column(Integer, nullable=False, default=50)
|
||||
progress: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
||||
constraints_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
parent_id: Mapped[str | None] = mapped_column(String(80), ForeignKey("goals.id"), nullable=True)
|
||||
success_criteria_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class PerceptionChannel(Base):
|
||||
"""烛照枢感知通道授权(契约字典 §5.7 频道级)。channel 为主键,默认六类可自定义。"""
|
||||
|
||||
__tablename__ = "perception_channels"
|
||||
|
||||
channel: Mapped[str] = mapped_column(String(80), primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
consent_status: Mapped[str] = mapped_column(String(40), nullable=False, default="unknown")
|
||||
privacy_level: Mapped[str] = mapped_column(String(40), nullable=False, default="normal")
|
||||
risk_level: Mapped[str] = mapped_column(String(20), nullable=False, default="L2")
|
||||
last_active_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class WorldEntity(Base):
|
||||
"""河图枢世界实体(契约字典 §11.1 / §11.2)。"""
|
||||
|
||||
__tablename__ = "world_entities"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_world_entity_id)
|
||||
type: Mapped[str] = mapped_column(String(40), nullable=False, default="concept", index=True)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
attributes_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
state_type: Mapped[str] = mapped_column(String(40), nullable=False, default="inference")
|
||||
confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
sources_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class Plan(Base):
|
||||
"""洛书枢计划(契约字典 §5.13)。goal_id 关联太一枢目标,可空。"""
|
||||
|
||||
__tablename__ = "plans"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_plan_id)
|
||||
goal_id: Mapped[str | None] = mapped_column(String(80), ForeignKey("goals.id"), index=True)
|
||||
title: Mapped[str] = mapped_column(String(300), nullable=False)
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="draft", index=True)
|
||||
assumptions_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
risks_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
required_tools_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
success_criteria_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
step_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
completed_steps: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class AgentRosterEntry(Base):
|
||||
"""天工阁枢九角色在岗(契约字典 §5.14)。role 为主键,默认九角色可自定义。"""
|
||||
|
||||
__tablename__ = "agent_roster"
|
||||
|
||||
role: Mapped[str] = mapped_column(String(80), primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
responsibility: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
last_active_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class GenerationPreferences(Base):
|
||||
"""生成参数偏好(模型网关 §4.3)。本地单用户单行,按 owner_scope 固定。"""
|
||||
|
||||
__tablename__ = "generation_preferences"
|
||||
|
||||
owner_scope: Mapped[str] = mapped_column(
|
||||
String(80), primary_key=True, default=settings.default_owner_scope
|
||||
)
|
||||
default_model_hint: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
temperature: Mapped[float] = mapped_column(Float, nullable=False, default=0.7)
|
||||
top_p: Mapped[float] = mapped_column(Float, nullable=False, default=1.0)
|
||||
max_output_tokens: Mapped[int] = mapped_column(Integer, nullable=False, default=4096)
|
||||
streaming: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class ToolPolicy(Base):
|
||||
"""百工枢工具策略治理(api-spec §15 / §16)。
|
||||
|
||||
工具的风险/权限策略持久化层;``name`` 为主键。builtin 工具启动时由种子 upsert
|
||||
(``source=builtin``),自定义工具经 API 注册(``source=custom``)。司命决策器
|
||||
(SafetyGovernor)从本表加载覆盖策略;``/tools`` 与 ``/safety/policies`` 两组 API
|
||||
共享本表——前者返回完整元数据,后者只返回策略子集。
|
||||
"""
|
||||
|
||||
__tablename__ = "tool_policies"
|
||||
|
||||
name: Mapped[str] = mapped_column(String(80), primary_key=True)
|
||||
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
risk_level: Mapped[str] = mapped_column(String(20), nullable=False, default="L2")
|
||||
permission_policy: Mapped[str] = mapped_column(String(20), nullable=False, default="ask")
|
||||
side_effect: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
audit_required: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
source: Mapped[str] = mapped_column(String(20), nullable=False, default="custom")
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class ModelEndpointOverride(Base):
|
||||
"""模型网关 endpoint 运行时覆盖(DB 优先于 .env / yaml,api-spec §4.4)。
|
||||
|
||||
每个 (logical_model_name, endpoint_name) 一行;字段非空才覆盖同名 endpoint 配置,
|
||||
None = 不覆盖、回退 yaml/env。base_url/api_key 经 resolved_* 优先 endpoint 字段生效,
|
||||
故 DB 写入后即「DB 优先 env」。本地单用户边界下 API key 明文存储,GET 脱敏不回值。
|
||||
"""
|
||||
|
||||
__tablename__ = "model_endpoint_overrides"
|
||||
|
||||
logical_model_name: Mapped[str] = mapped_column(String(120), primary_key=True)
|
||||
endpoint_name: Mapped[str] = mapped_column(String(120), primary_key=True)
|
||||
base_url: Mapped[str | None] = mapped_column(String(500))
|
||||
api_key: Mapped[str | None] = mapped_column(String(500))
|
||||
status: Mapped[str | None] = mapped_column(String(40))
|
||||
weight: Mapped[int | None] = mapped_column(Integer)
|
||||
priority: Mapped[int | None] = mapped_column(Integer)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
@@ -0,0 +1,37 @@
|
||||
"""幂等键模型。"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, String, Text, UniqueConstraint
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
def new_idempotency_id() -> str:
|
||||
return new_id("idempotency_")
|
||||
|
||||
|
||||
class IdempotencyKey(Base):
|
||||
__tablename__ = "idempotency_keys"
|
||||
__table_args__ = (UniqueConstraint("scope", "key", name="uq_idempotency_scope_key"),)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_idempotency_id)
|
||||
key: Mapped[str] = mapped_column(String(200), nullable=False, index=True)
|
||||
scope: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
|
||||
method: Mapped[str] = mapped_column(String(20), nullable=False)
|
||||
path: Mapped[str] = mapped_column(String(500), nullable=False)
|
||||
request_hash: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="completed")
|
||||
response_status_code: Mapped[int] = mapped_column(default=200)
|
||||
response_body_json: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
resource_type: Mapped[str | None] = mapped_column(String(80))
|
||||
resource_id: Mapped[str | None] = mapped_column(String(120))
|
||||
trace_id: Mapped[str | None] = mapped_column(String(80), index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), index=True)
|
||||
@@ -0,0 +1,64 @@
|
||||
"""人物资料导入模型(api-spec §8;契约字典 §10)。
|
||||
|
||||
导入流水线把用户授权的聊天记录、人物设定、背景故事、角色卡、语气样例、
|
||||
语音样本等资料解析为可追溯的 ``import_items``,再由后续阶段抽取为
|
||||
档案 / 记忆 / 人格候选。``import_items.id`` 作为候选的 evidence 来源
|
||||
(source_type = ``import_item``)。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_import_item_id, new_import_job_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class CharacterImportJob(Base):
|
||||
"""导入任务(契约字典 §10.3 状态机;api-spec §8)。"""
|
||||
|
||||
__tablename__ = "character_import_jobs"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_import_job_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
material_type: Mapped[str] = mapped_column(String(40), nullable=False, index=True)
|
||||
source_type: Mapped[str] = mapped_column(String(40), nullable=False)
|
||||
title: Mapped[str | None] = mapped_column(String(200))
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending", index=True)
|
||||
format: Mapped[str] = mapped_column(String(40), nullable=False, default="text")
|
||||
media_type: Mapped[str | None] = mapped_column(String(40))
|
||||
mime_type: Mapped[str | None] = mapped_column(String(80))
|
||||
source_description: Mapped[str | None] = mapped_column(Text)
|
||||
speaker_label: Mapped[str | None] = mapped_column(String(120))
|
||||
consent_status: Mapped[str] = mapped_column(String(40), nullable=False, default="unknown")
|
||||
usage_scope: Mapped[str] = mapped_column(String(40), nullable=False, default="reference_only")
|
||||
checksum: Mapped[str | None] = mapped_column(String(120), index=True)
|
||||
item_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
storage_path: Mapped[str | None] = mapped_column(String(500))
|
||||
raw_content: Mapped[str | None] = mapped_column(Text)
|
||||
error_code: Mapped[str | None] = mapped_column(String(80))
|
||||
error_message: Mapped[str | None] = mapped_column(Text)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class ImportItem(Base):
|
||||
"""导入解析条目(契约字典 §10.4 item_type / §10.5 role)。"""
|
||||
|
||||
__tablename__ = "import_items"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_import_item_id)
|
||||
import_job_id: Mapped[str] = mapped_column(
|
||||
String(80), ForeignKey("character_import_jobs.id"), index=True
|
||||
)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
item_type: Mapped[str] = mapped_column(String(40), nullable=False)
|
||||
role: Mapped[str] = mapped_column(String(40), nullable=False, default="other")
|
||||
sequence: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
metadata_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
@@ -0,0 +1,74 @@
|
||||
"""世谱(Lorebook / World Info)模型。
|
||||
|
||||
兼容酒馆 character_book 结构 + 魂镜扩展(scope / bound_entity_id)。
|
||||
纯逻辑(匹配 / 预算 / 分组)在 app.modules.lorebook,本文件仅持久化载体。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_lorebook_entry_id, new_lorebook_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Lorebook(Base):
|
||||
"""一本世谱:条目集合 + 扫描 / 预算参数。
|
||||
|
||||
``character_id`` 为空表示 global 作用域(跨人物共享);非空时按人物隔离。
|
||||
"""
|
||||
|
||||
__tablename__ = "lorebooks"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_lorebook_id)
|
||||
character_id: Mapped[str | None] = mapped_column(
|
||||
String(80), ForeignKey("characters.id"), index=True
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False, default="")
|
||||
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
scan_depth: Mapped[int | None] = mapped_column(Integer)
|
||||
token_budget: Mapped[int | None] = mapped_column(Integer)
|
||||
recursive_scanning: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
scope: Mapped[str] = mapped_column(String(40), nullable=False, default="character", index=True)
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="active", index=True)
|
||||
owner_scope: Mapped[str] = mapped_column(String(80), nullable=False, index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class LorebookEntry(Base):
|
||||
"""单条世谱条目:keys 命中后注入 content。
|
||||
|
||||
``keys`` / ``secondary_keys`` 为字符串数组,落库存 JSON 文本(契约字典 §4)。
|
||||
"""
|
||||
|
||||
__tablename__ = "lorebook_entries"
|
||||
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(80), primary_key=True, default=new_lorebook_entry_id
|
||||
)
|
||||
lorebook_id: Mapped[str] = mapped_column(
|
||||
String(80), ForeignKey("lorebooks.id"), nullable=False, index=True
|
||||
)
|
||||
keys_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
content: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
secondary_keys_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
constant: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
selective: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
case_sensitive: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
use_regex: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
position: Mapped[str] = mapped_column(String(40), nullable=False, default="after_char")
|
||||
insertion_order: Mapped[int] = mapped_column(Integer, nullable=False, default=100)
|
||||
priority: Mapped[int] = mapped_column(Integer, nullable=False, default=10)
|
||||
comment: Mapped[str] = mapped_column(String(500), nullable=False, default="")
|
||||
# 软引用河图世界实体(绑定触发);不加 FK,避免跨枢强耦合
|
||||
bound_entity_id: Mapped[str | None] = mapped_column(String(80), index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
@@ -0,0 +1,43 @@
|
||||
"""百工 MCP server 模型(skills-design §5)。
|
||||
|
||||
注册的 MCP server 元数据 + 拉取缓存的工具清单(tools_json),供启动加载与
|
||||
转 ToolSpec register。
|
||||
|
||||
支持两种传输协议:
|
||||
- streamable-http:通过 endpoint_url POST /message(标准 MCP Streamable HTTP)
|
||||
- stdio:通过子进程 stdin/stdout 通信(本地 MCP 集成)
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_mcp_server_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class McpServer(Base):
|
||||
"""MCP server 注册记录。"""
|
||||
|
||||
__tablename__ = "mcp_servers"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_mcp_server_id)
|
||||
name: Mapped[str] = mapped_column(String(120), nullable=False, unique=True)
|
||||
transport: Mapped[str] = mapped_column(String(40), nullable=False, default="streamable-http")
|
||||
# streamable-http 用
|
||||
endpoint_url: Mapped[str | None] = mapped_column(String(500))
|
||||
auth_token: Mapped[str | None] = mapped_column(String(500))
|
||||
# stdio 用
|
||||
command: Mapped[str | None] = mapped_column(String(500))
|
||||
args_json: Mapped[str | None] = mapped_column(Text) # JSON list
|
||||
env_json: Mapped[str | None] = mapped_column(Text) # JSON dict
|
||||
cwd: Mapped[str | None] = mapped_column(String(500))
|
||||
# 通用
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="enabled", index=True)
|
||||
tools_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
@@ -0,0 +1,46 @@
|
||||
"""记忆模型。"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, Float, ForeignKey, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_memory_id, new_memory_link_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Memory(Base):
|
||||
__tablename__ = "memories"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_memory_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
type: Mapped[str] = mapped_column(String(60), nullable=False)
|
||||
title: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
source: Mapped[str] = mapped_column(String(80), nullable=False, default="user_explicit")
|
||||
confidence: Mapped[float] = mapped_column(Float, nullable=False, default=1.0)
|
||||
importance: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
sensitivity: Mapped[str] = mapped_column(String(40), nullable=False, default="low")
|
||||
evidence_ids_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="active", index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
temporal_context_json: Mapped[str] = mapped_column(
|
||||
Text, nullable=False, default="{}", server_default="{}"
|
||||
)
|
||||
|
||||
|
||||
class MemoryLink(Base):
|
||||
__tablename__ = "memory_links"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_memory_link_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
source_memory_id: Mapped[str] = mapped_column(String(80), ForeignKey("memories.id"), index=True)
|
||||
target_memory_id: Mapped[str] = mapped_column(String(80), ForeignKey("memories.id"), index=True)
|
||||
relation: Mapped[str] = mapped_column(String(80), nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
@@ -0,0 +1,55 @@
|
||||
"""人格版本模型。"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_personality_id, new_personality_proposal_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class PersonalityVersion(Base):
|
||||
__tablename__ = "personality_versions"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_personality_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||||
identity_profile: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
role_destiny: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
personality_seed: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
traits: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
expression_style: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
values: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
relationship_pattern: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
emotion_baseline: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
reason: Mapped[str] = mapped_column(Text, nullable=False, default="system_seed")
|
||||
evidence_ids_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
created_by: Mapped[str] = mapped_column(String(80), nullable=False, default="system")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
rolled_back_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
|
||||
|
||||
class PersonalityProposal(Base):
|
||||
"""灵核枢人格修改建议(契约字典 §10.6 candidate.status;api-spec §11)。
|
||||
|
||||
提议提交后为 ``pending``,经审核批准后派生新人格版本(status=``applied``),
|
||||
驳回则标记 ``rejected``;本地单用户边界下审核者即用户,写操作均记审计。
|
||||
"""
|
||||
|
||||
__tablename__ = "personality_proposals"
|
||||
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(80), primary_key=True, default=new_personality_proposal_id
|
||||
)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
fields_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
reason: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending", index=True)
|
||||
resulting_version_id: Mapped[str | None] = mapped_column(
|
||||
String(80), ForeignKey("personality_versions.id")
|
||||
)
|
||||
reviewed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
reviewed_by: Mapped[str] = mapped_column(String(80), nullable=False, default="system")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
@@ -0,0 +1,32 @@
|
||||
"""灵核情绪状态持久化(设计 §11.4)。"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, Float, ForeignKey, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class CharacterEmotionState(Base):
|
||||
"""角色当前情绪状态(单行 per character,最新状态 + 触发溯源)。
|
||||
|
||||
设计 §11.4:``mood`` / ``intensity`` 由辰正 ``time.*`` 事件驱动动态维护;
|
||||
``baseline_*`` 同步自人格版本 ``emotion_baseline``,作为衰减回归锚点。
|
||||
同步写 ``Character.current_mood_id``(激活既有字段,前端列表无需 join)。
|
||||
"""
|
||||
|
||||
__tablename__ = "character_emotion_states"
|
||||
|
||||
character_id: Mapped[str] = mapped_column(
|
||||
String(80), ForeignKey("characters.id"), primary_key=True
|
||||
)
|
||||
mood: Mapped[str] = mapped_column(String(40), nullable=False, default="neutral")
|
||||
intensity: Mapped[float] = mapped_column(Float, nullable=False, default=0.2)
|
||||
baseline_mood: Mapped[str] = mapped_column(String(40), nullable=False, default="neutral")
|
||||
baseline_intensity: Mapped[float] = mapped_column(Float, nullable=False, default=0.2)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
last_trigger_event_id: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
||||
@@ -0,0 +1,77 @@
|
||||
"""RBAC 角色-权限模型。
|
||||
|
||||
Role ──╮
|
||||
├── RolePermission ── Permission
|
||||
User ──╯
|
||||
└── UserRole ────╯
|
||||
|
||||
前端通过 GET /auth/me 的 permissions 字段获取当前用户权限列表,本地不做角色-权限映射。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, ForeignKey, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_permission_id, new_role_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Role(Base):
|
||||
__tablename__ = "roles"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(40), primary_key=True, default=new_role_id)
|
||||
name: Mapped[str] = mapped_column(String(80), unique=True, nullable=False, index=True)
|
||||
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
is_system: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class Permission(Base):
|
||||
__tablename__ = "permissions"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(40), primary_key=True, default=new_permission_id)
|
||||
resource: Mapped[str] = mapped_column(String(80), nullable=False, index=True)
|
||||
action: Mapped[str] = mapped_column(String(80), nullable=False)
|
||||
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
|
||||
@property
|
||||
def code(self) -> str:
|
||||
return f"{self.resource}:{self.action}"
|
||||
|
||||
|
||||
class UserRole(Base):
|
||||
__tablename__ = "user_roles"
|
||||
|
||||
user_id: Mapped[str] = mapped_column(
|
||||
String(40),
|
||||
ForeignKey("users.id", ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
)
|
||||
role_id: Mapped[str] = mapped_column(
|
||||
String(40),
|
||||
ForeignKey("roles.id", ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
|
||||
|
||||
class RolePermission(Base):
|
||||
__tablename__ = "role_permissions"
|
||||
|
||||
role_id: Mapped[str] = mapped_column(
|
||||
String(40),
|
||||
ForeignKey("roles.id", ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
)
|
||||
permission_id: Mapped[str] = mapped_column(
|
||||
String(40),
|
||||
ForeignKey("permissions.id", ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
@@ -0,0 +1,55 @@
|
||||
"""运行时 Run/Event 模型。"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text, UniqueConstraint
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_event_id, new_run_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Run(Base):
|
||||
__tablename__ = "runs"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_run_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
session_id: Mapped[str | None] = mapped_column(
|
||||
String(80), ForeignKey("chat_sessions.id"), index=True
|
||||
)
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="queued", index=True)
|
||||
goal: Mapped[str | None] = mapped_column(String(300))
|
||||
origin: Mapped[str] = mapped_column(String(40), nullable=False, default="chat")
|
||||
model_hint: Mapped[str | None] = mapped_column(String(120))
|
||||
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
error_code: Mapped[str | None] = mapped_column(String(80))
|
||||
error_message: Mapped[str | None] = mapped_column(Text)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class Event(Base):
|
||||
__tablename__ = "events"
|
||||
__table_args__ = (UniqueConstraint("run_id", "sequence", name="uq_events_run_sequence"),)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_event_id)
|
||||
character_id: Mapped[str | None] = mapped_column(
|
||||
String(80), ForeignKey("characters.id"), index=True, nullable=True
|
||||
)
|
||||
run_id: Mapped[str | None] = mapped_column(
|
||||
String(80), ForeignKey("runs.id"), index=True, nullable=True
|
||||
)
|
||||
type: Mapped[str] = mapped_column(String(80), nullable=False, index=True)
|
||||
source: Mapped[str] = mapped_column(String(40), nullable=False, default="system")
|
||||
payload_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
visibility: Mapped[str] = mapped_column(String(40), nullable=False, default="public")
|
||||
sensitivity: Mapped[str] = mapped_column(String(40), nullable=False, default="low")
|
||||
trace_id: Mapped[str | None] = mapped_column(String(80), index=True)
|
||||
parent_id: Mapped[str | None] = mapped_column(String(80))
|
||||
sequence: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
evidence_ids_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
@@ -0,0 +1,54 @@
|
||||
"""最小审计模型与待确认持久化记录。"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_audit_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class AuditEvent(Base):
|
||||
__tablename__ = "audit_events"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_audit_id)
|
||||
pivot: Mapped[str | None] = mapped_column(String(40), nullable=True, index=True)
|
||||
character_id: Mapped[str | None] = mapped_column(
|
||||
String(80), ForeignKey("characters.id"), index=True
|
||||
)
|
||||
run_id: Mapped[str | None] = mapped_column(String(80), ForeignKey("runs.id"), index=True)
|
||||
action: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
actor: Mapped[str] = mapped_column(String(80), nullable=False, default="system")
|
||||
risk_level: Mapped[str] = mapped_column(String(20), nullable=False, default="L1")
|
||||
decision: Mapped[str] = mapped_column(String(40), nullable=False, default="allow")
|
||||
reason: Mapped[str | None] = mapped_column(Text)
|
||||
input_summary: Mapped[str | None] = mapped_column(Text)
|
||||
output_summary: Mapped[str | None] = mapped_column(Text)
|
||||
trace_id: Mapped[str | None] = mapped_column(String(80), index=True)
|
||||
resource_type: Mapped[str | None] = mapped_column(String(80))
|
||||
resource_id: Mapped[str | None] = mapped_column(String(120))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
|
||||
|
||||
class PendingConfirmationRecord(Base):
|
||||
"""待确认工具调用的持久化记录(多 worker 共享确认状态)。
|
||||
|
||||
对应 ``modules/safety/confirmation.py`` 的 ``PendingConfirmation`` 值对象。
|
||||
``status`` 流转:pending → consumed / timed_out。
|
||||
"""
|
||||
|
||||
__tablename__ = "pending_confirmations"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True)
|
||||
tool: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
input_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
risk_level: Mapped[str] = mapped_column(String(40), nullable=False, default="L2")
|
||||
reason: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
run_id: Mapped[str | None] = mapped_column(String(80), index=True)
|
||||
character_id: Mapped[str | None] = mapped_column(String(80), index=True)
|
||||
trace_id: Mapped[str | None] = mapped_column(String(80))
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending", index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
resolved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
@@ -0,0 +1,33 @@
|
||||
"""百工 Skill 能力包模型(skills-design §4.1;契约字典 §10.5 skill_ 前缀)。
|
||||
|
||||
Skill 是显式注册的能力包:触发时注入 prompt_fragment 到对话 contract,
|
||||
tool_bindings 仅作为 prompt 提示(不改变 ToolRuntime 注册集)。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_skill_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Skill(Base):
|
||||
"""Skill 能力包。"""
|
||||
|
||||
__tablename__ = "skills"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_skill_id)
|
||||
name: Mapped[str] = mapped_column(String(120), nullable=False, unique=True)
|
||||
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
trigger: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
prompt_fragment: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||||
tool_bindings_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
risk_level: Mapped[str] = mapped_column(String(8), nullable=False, default="L1")
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="enabled", index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
"""时态纪念日模型(辰正 §5.3)。"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, ForeignKey, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_anniversary_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class TimeAnniversary(Base):
|
||||
"""纪念日 / 特殊日子(辰正设计 §5.3)。
|
||||
|
||||
枚举值(calendar / kind / subject_type / source)以契约字典
|
||||
``docs/contracts/contract-glossary.md`` §11.4.1–§11.4.4 为单一事实源。
|
||||
"""
|
||||
|
||||
__tablename__ = "time_anniversaries"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_anniversary_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
calendar: Mapped[str] = mapped_column(String(20), nullable=False) # solar / lunar
|
||||
date: Mapped[str] = mapped_column(String(20), nullable=False) # 公历 ISO 或农历日期编码
|
||||
recurs_yearly: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||||
kind: Mapped[str] = mapped_column(
|
||||
String(40), nullable=False
|
||||
) # birthday / anniversary / milestone / custom
|
||||
subject_type: Mapped[str] = mapped_column(
|
||||
String(40), nullable=False
|
||||
) # user / character_self / relationship / custom
|
||||
source: Mapped[str] = mapped_column(
|
||||
String(40), nullable=False, default="manual"
|
||||
) # auto / manual / imported
|
||||
metadata_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
"""用户模型。"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_user_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(40), primary_key=True, default=new_user_id)
|
||||
username: Mapped[str] = mapped_column(String(80), unique=True, nullable=False, index=True)
|
||||
email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False)
|
||||
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||||
is_admin: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
@@ -0,0 +1,58 @@
|
||||
"""河图枢世界模型运行时(api-spec §12;design/world-model-design §3/§4)。
|
||||
|
||||
与治理视图 ``governance.WorldEntity``(全局、人工维护、无 character_id)区分:
|
||||
本模块是**按人物隔离的运行时**世界状态,所有写入绑定 ``character_id``。
|
||||
自动抽取(世界引擎)属 v1 半自动留后项,本表先承载手动 CRUD 与未来抽取结果。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, Float, ForeignKey, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.ids import new_world_entity_id, new_world_relation_id
|
||||
from app.core.time import utc_now
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class CharacterWorldEntity(Base):
|
||||
"""人物视角下的世界实体(契约字典 §11.1 type / §11.2 state_type)。"""
|
||||
|
||||
__tablename__ = "character_world_entities"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_world_entity_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
type: Mapped[str] = mapped_column(String(40), nullable=False, default="concept", index=True)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
attributes_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}")
|
||||
state_type: Mapped[str] = mapped_column(String(40), nullable=False, default="inference")
|
||||
status: Mapped[str] = mapped_column(String(40), nullable=False, default="confirmed", index=True)
|
||||
confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
evidence_ids_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
sources_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
|
||||
|
||||
class WorldRelation(Base):
|
||||
"""实体间关系(design §4;predicate 为自由字符串谓词,非枚举)。"""
|
||||
|
||||
__tablename__ = "world_relations"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_world_relation_id)
|
||||
character_id: Mapped[str] = mapped_column(String(80), ForeignKey("characters.id"), index=True)
|
||||
subject_id: Mapped[str] = mapped_column(
|
||||
String(80), ForeignKey("character_world_entities.id"), index=True
|
||||
)
|
||||
predicate: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
object_id: Mapped[str] = mapped_column(
|
||||
String(80), ForeignKey("character_world_entities.id"), index=True
|
||||
)
|
||||
confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.5)
|
||||
evidence_ids_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utc_now, onupdate=utc_now
|
||||
)
|
||||
Reference in new issue
Block a user