Files
2026-08-21 16:00:13 +08:00

324 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""司命台管理 API schema(api-spec §19)。
九枢健康度聚合 / 朱批待办 / 起居注审计 + 五组治理对象 CRUD。
枚举取值见契约字典 §5.5 / §5.7 / §5.9 / §5.10 / §5.11–§5.14 / §11 / §13。
"""
from datetime import datetime
from typing import Any, Literal
from pydantic import BaseModel, ConfigDict, Field
# —— §19.1 九枢健康度聚合 ——
class PivotHealthSummary(BaseModel):
pivot: str = Field(description="九枢标识(契约字典 §5.9)。")
name: str = Field(description="枢中文名。")
module: str = Field(description="工程模块名。")
health: str = Field(description="健康状态:void / breathing / steady / cracked(§5.10)。")
summary: str = Field(description="人类可读的一句话态势;cracked 须给出原因。")
updated_at: str | None = Field(default=None, description="最近更新时间。")
class PivotHealthReport(BaseModel):
overall: str = Field(description="九枢聚合健康度;存在任一 cracked 则为 cracked。")
alerts: int = Field(description="cracked 枢计数。")
pivots: list[PivotHealthSummary] = Field(
description="九枢全集,缺数据枢 health=void,不得省略。"
)
# —— §19.2 朱批待办 ——
class PendingApproval(BaseModel):
confirmation_id: str = Field(
description="确认 ID,用于 /safety/confirmations/{id}/approve|deny。"
)
character_id: str | None = Field(default=None, description="所属人物 ID。")
tool: str = Field(description="待裁定工具名。")
risk_level: str = Field(description="风险等级(§5.5)。")
permission_policy: str = Field(description="权限策略(§5.6)。")
action_summary: str = Field(description="动作摘要。")
input_summary: str | None = Field(default=None, description="输入摘要,不得含明文密钥。")
possible_impact: str | None = Field(default=None, description="可能影响。")
reason: str | None = Field(default=None, description="裁定原因。")
created_at: str | None = Field(default=None, description="创建时间。")
# —— §19.3 起居注审计 ——
class AuditEntry(BaseModel):
audit_id: str = Field(description="审计事件 ID。")
pivot: str = Field(description="九枢标识。")
actor: str = Field(description="发起者:user / system / tool(§13.2)。")
action: str = Field(description="动作。")
subject: str | None = Field(default=None, description="动作对象。")
decision: str = Field(description="裁定结果:auto / approved / denied / blocked(§13.3)。")
risk_level: str | None = Field(default=None, description="风险等级。")
summary: str = Field(description="人类可读一句话摘要。")
trace_id: str | None = Field(default=None, description="链路追踪 ID。")
created_at: str | None = Field(default=None, description="创建时间。")
# —— §19.4 太一枢 · 目标 ——
class GoalNode(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: str
character_id: str | None = None
title: str
description: str
level: str = Field(description="目标层级(§5.11)。")
type: str = Field(
default="session",
description="目标类型(§5.15):mission/relationship/skill/knowledge/maintenance/exploration",
)
status: str = Field(description="目标状态(§5.12)。")
priority: int
progress: float = Field(default=0.0, ge=0.0, le=1.0, description="完成度 0~1。")
constraints: list[str]
parent_id: str | None = None
success_criteria: list[str]
updated_at: str | None = None
class CreateGoalRequest(BaseModel):
title: str = Field(max_length=300)
description: str = Field(default="", max_length=2000)
level: str = Field(description="目标层级(§5.11)。")
type: str = Field(default="session", description="目标类型(§5.15)。")
priority: int = Field(default=50, ge=0, le=100)
character_id: str | None = Field(default=None, description="归属于哪个人物。")
constraints: list[str] = Field(default_factory=list)
parent_id: str | None = None
success_criteria: list[str] = Field(default_factory=list)
class UpdateGoalRequest(BaseModel):
title: str | None = Field(default=None, max_length=300)
description: str | None = Field(default=None, max_length=2000)
status: str | None = Field(default=None, description="目标状态(§5.12)。")
type: str | None = Field(default=None, description="目标类型(§5.15)。")
priority: int | None = Field(default=None, ge=0, le=100)
progress: float | None = Field(default=None, ge=0.0, le=1.0)
constraints: list[str] | None = None
# —— §19.4 烛照枢 · 感知通道 ——
class PerceptionChannelResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
channel: str
name: str
description: str
enabled: bool
consent_status: str = Field(description="授权状态(§5.7)。")
privacy_level: str = Field(description="隐私等级(§5.4)。")
risk_level: str = Field(description="风险等级(§5.5)。")
last_active_at: str | None = None
class CreatePerceptionChannelRequest(BaseModel):
channel: str = Field(max_length=80, description="通道标识;默认六类,可自定义。")
name: str = Field(max_length=120)
description: str = Field(default="", max_length=2000)
risk_level: str = Field(default="L2")
class UpdatePerceptionChannelRequest(BaseModel):
enabled: bool | None = None
consent_status: str | None = Field(default=None, description="授权状态(§5.7)。")
privacy_level: str | None = Field(default=None, description="隐私等级(§5.4)。")
# —— §19.4 河图枢 · 世界实体 ——
class WorldEntityResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: str
type: str = Field(description="实体类型(§11.1)。")
name: str
attributes: dict[str, str]
state_type: str = Field(description="状态类型(§11.2)。")
confidence: float
sources: list[str]
updated_at: str | None = None
class CreateWorldEntityRequest(BaseModel):
type: str = Field(description="实体类型(§11.1)。")
name: str = Field(max_length=200)
attributes: dict[str, str] = Field(default_factory=dict)
state_type: str = Field(default="inference", description="状态类型(§11.2)。")
confidence: float = Field(default=0.5, ge=0.0, le=1.0)
sources: list[str] = Field(default_factory=list)
class UpdateWorldEntityRequest(BaseModel):
name: str | None = Field(default=None, max_length=200)
state_type: str | None = Field(default=None, description="状态类型(§11.2)。")
confidence: float | None = Field(default=None, ge=0.0, le=1.0)
# —— §19.4 洛书枢 · 计划 ——
class PlanSummaryResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: str
goal_id: str
title: str
status: str = Field(description="计划状态(§5.13)。")
assumptions: list[str]
risks: list[str]
required_tools: list[str]
success_criteria: list[str]
step_count: int
completed_steps: int
updated_at: str | None = None
class CreatePlanRequest(BaseModel):
title: str = Field(max_length=300)
goal_id: str | None = None
assumptions: list[str] = Field(default_factory=list)
risks: list[str] = Field(default_factory=list)
class UpdatePlanRequest(BaseModel):
status: str | None = Field(default=None, description="计划状态(§5.13)。")
assumptions: list[str] | None = None
risks: list[str] | None = None
# —— §19.4 天工阁枢 · 角色在岗 ——
class AgentRosterResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
role: str
name: str
responsibility: str
enabled: bool
presence: str = Field(description="在岗呈现态(派生自最近活跃时间):idle / active。")
last_active_at: str | None = None
class CreateAgentRequest(BaseModel):
role: str = Field(max_length=80, description="角色标识;默认九角色,可自定义。")
name: str = Field(max_length=120)
responsibility: str = Field(default="", max_length=2000)
class UpdateAgentRequest(BaseModel):
enabled: bool | None = None
# —— §19.5 链路追踪 ——
class TraceItem(BaseModel):
kind: Literal["event", "audit", "idempotency"] = Field(
description="记录来源:运行事件 / 安全审计 / 请求幂等。"
)
id: str = Field(description="记录主键。")
created_at: datetime = Field(description="发生时间(前端按此排序展示)。")
source_label: str = Field(description="人类可读来源(如「运行事件 / message.completed」)。")
summary: str = Field(description="一句话摘要。")
detail: dict[str, Any] = Field(
default_factory=dict,
description="原始字段(payload / decision / path 等),供详情展开。",
)
class TraceDetail(BaseModel):
trace_id: str = Field(description="被查询的链路追踪 ID。")
character_ids: list[str] = Field(
default_factory=list, description="该链路涉及的人物去重列表(由 events / audits 聚合)。"
)
run_ids: list[str] = Field(
default_factory=list, description="该链路涉及的 run 去重列表(由 events 聚合)。"
)
session_ids: list[str] = Field(
default_factory=list,
description="该链路涉及的对话(chat session)去重列表(由 runs 聚合)。",
)
items: list[TraceItem] = Field(
default_factory=list, description="按 created_at 升序的时间线条目。"
)
class TraceSummary(BaseModel):
trace_id: str = Field(description="链路追踪 ID。")
last_seen: datetime = Field(description="该链路最近一次活动时间。")
character_ids: list[str] = Field(default_factory=list, description="涉及的人物去重列表。")
session_ids: list[str] = Field(default_factory=list, description="涉及的对话去重列表。")
event_count: int = Field(default=0, description="运行事件数。")
audit_count: int = Field(default=0, description="安全审计数。")
idempotency_count: int = Field(default=0, description="请求幂等数。")
class TraceListResponse(BaseModel):
items: list[TraceSummary] = Field(description="按 last_seen 倒序的链路概览。")
total: int = Field(description="distinct trace 总数(未截断)。")
# —— §8 司命台 · 起居注时间河(辰正 time.* 事件)——
class TimeEventResponse(BaseModel):
"""辰正 time.* 事件(起居注时间河条目)。"""
id: str = Field(description="事件 ID。")
type: str = Field(description="事件类型(time.* 前缀,如 time.reunion / time.sentiment)。")
payload: dict[str, Any] = Field(default_factory=dict, description="事件 payload(已解析)。")
run_id: str | None = Field(default=None, description="所属 run ID(可空)。")
character_id: str | None = Field(default=None, description="所属人物 ID(可空)。")
sensitivity: str = Field(default="low", description="敏感度(§5.4)。")
created_at: str = Field(description="发生时间(ISO 字符串)。")
class TimeEventListResponse(BaseModel):
items: list[TimeEventResponse] = Field(description="按 created_at 倒序的事件列表。")
total: int = Field(description="source='time_sense' 的事件总数(未截断)。")
# —— §19.6 用户管理 ——
class AdminUserResponse(BaseModel):
"""管理员视角的用户信息。"""
model_config = ConfigDict(from_attributes=True)
id: str
username: str
email: str
is_active: bool
is_admin: bool
created_at: datetime
updated_at: datetime | None = None
class AdminCreateUserRequest(BaseModel):
username: str = Field(min_length=1, description="用户名。")
email: str = Field(min_length=1, description="邮箱。")
password: str = Field(min_length=6, description="密码(>=6 字符)。")
is_admin: bool = Field(default=False, description="是否管理员。")
class AdminUpdateUserRequest(BaseModel):
is_active: bool | None = Field(default=None, description="是否启用。")
is_admin: bool | None = Field(default=None, description="是否管理员。")