324 lines
12 KiB
Python
324 lines
12 KiB
Python
"""司命台管理 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="是否管理员。")
|