M8:天工阁、叩心与辰正——受托任务后台并行、叩心四约束、时态感知投影

- 天工阁域 domains/tiangong:backstage_tasks(委托包+验收标准+结果证据);有限分解(parent 链)与受控并行(各自后台 Run);子任务全终态级联父任务进入待验收;按证据 accept/reject
- kernel.start_backstage_run(kind=background_task):loop 后台分支不占前台席位、与前台对话并行;断言放宽容纳无人物功能任务;结果只经回调回呈任务——无身份写入路径
- 叩心域 domains/kouxin:knocking_candidates(event/time_anchor/manual 触发 + 草稿 + 裁决快照);四约束裁决(总开关→静默窗口【本地时区判定】→24h 频率→预算),dispatch 未过 429 且快照留痕;候选默认不自动发送;expire_stale 过期推进不触碰缘契
- 辰正 domains/zhengchen:temporal_context() 复用 time_sense 计算核(快照/农历/季节),产出【时态感知】投影段接入镜树生成 prompt(客观时间语境,不附情绪臆测——守一纪律)
- 退役:modules/goal_orchestrator|planner|perception|big_cycle、application/planning、services/governance|goal_persist、candidates 表链(imports 候选抽取 API 面)、goals/plans/agent_roster/perception_channels/big_cycles/旧候选表(迁移 009);前端 admin goals/plans/agents/perception/world 页与六组件;governance 只留 GenerationPreferences;admin 治理面收敛为司命+百工两枢;pivots 健康以域表计数重建
- 验收(test_m8_tiangong 五用例):后台任务无身份写入(记忆/魂籍/缘契零新增);后台与前台并行;分解级联;叩心四约束逐项;不回应不降低关系(缘契维度/状态/版本零变化)
- 四套件:后端 345、前端 203、BFF 4、神识 5 包全绿(2 个预存环境失败不变);迁移 009 净库干净
This commit is contained in:
chenxin committed 2026-08-28 09:13:39 +08:00
1 parent b419e0afde
commit c63b75152a
68 files changed
+1205 -4750

No files matched your search

+5 -271
View File
@@ -1,201 +1,9 @@
"""司命台治理对象种子数据。
从前端 lib/mock/data.ts 移植,供本地启动时让司命台治理视图有初始内容。
按主键存在则跳过,重复执行幂等;不记审计(系统初始化,非用户治理操作)。
"""
from datetime import UTC, datetime
"""百工能力种子(内置能力幂等登记;旧枢治理种子随 M8 退役)。"""
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.domains.baigong.models import Capability
from app.models.governance import (
AgentRosterEntry,
Goal,
PerceptionChannel,
Plan,
)
from app.repositories.json_utils import dumps
def _dt(iso: str | None) -> datetime | None:
if not iso:
return None
return datetime.fromisoformat(iso.replace("Z", "+00:00")).astimezone(UTC)
# —— 太一枢 · 目标 ——
_GOALS = [
{
"id": "goal-highest-mirror",
"title": "以铜镜为契,照见来者与自身",
"description": "镜梧的根本使命:于人于己皆以「照见」为先,不急于评判与作答。",
"level": "highest",
"type": "mission",
"status": "active",
"priority": 100,
"character_id": None,
"constraints": ["不得伪造照见", "触及高敏须脱敏", "核心人格不擅自改"],
"parent_id": None,
"success_criteria": ["持续以映照型方式回应", "保持人格一致"],
"updated_at": "2026-05-01T08:30:00Z",
},
{
"id": "goal-long-accompany",
"title": "成为能持续承接用户情绪的映照者",
"description": "长期目标:在反复的深夜倾诉中,成为散人稳定的情绪落点。",
"level": "long_term",
"type": "mission",
"status": "active",
"priority": 80,
"character_id": None,
"constraints": ["尊重用户节奏,不催促", "避免过度共情显得刻意"],
"parent_id": "goal-highest-mirror",
"success_criteria": ["用户愿意反复倾诉", "情绪被命名而非被解决"],
"updated_at": "2026-06-15T09:30:00Z",
},
{
"id": "goal-session-forget",
"title": "今夜陪伴散人,承接其对遗忘的反复触碰",
"description": "会话目标:散人第三次在深夜提起「遗忘」,需以意象承接而非下判语。",
"level": "session",
"type": "mission",
"status": "active",
"priority": 60,
"character_id": None,
"constraints": ["不用「你应该」", "语缓留白"],
"parent_id": "goal-long-accompany",
"success_criteria": ["情绪得到承接", "对话在留白处收束"],
"updated_at": "2026-06-20T08:00:00Z",
},
{
"id": "goal-task-retrieve",
"title": "检索与遗忘相关的情节记忆",
"description": "任务目标:从息壤拉取 episodic 记忆,理解散人反复触碰遗忘的来由。",
"level": "task",
"type": "mission",
"status": "completed",
"priority": 40,
"character_id": None,
"constraints": ["高敏记忆不注入明文"],
"parent_id": "goal-session-forget",
"success_criteria": ["命中 5 条以上相关记忆"],
"updated_at": "2026-06-20T08:05:00Z",
},
]
# —— 烛照枢 · 感知通道 ——
_PERCEPTION = [
(
"vision",
"视觉",
"摄像头 / 屏幕单帧识别",
False,
"revoked",
"sensitive",
"L3",
"2026-06-10T14:00:00Z",
),
(
"audio",
"听觉",
"麦克风音频采集与转写",
True,
"restricted",
"sensitive",
"L3",
"2026-06-19T23:50:00Z",
),
("sensor", "传感", "环境传感器(光线 / 温度 / 运动)", False, "unknown", "normal", "L1", None),
(
"digital",
"数字",
"日程 / 文件 / 应用等数字足迹",
True,
"granted",
"normal",
"L2",
"2026-06-20T07:50:00Z",
),
(
"user_input",
"用户输入",
"用户主动输入的文本 / 语音",
True,
"granted",
"normal",
"L1",
"2026-06-20T08:12:00Z",
),
(
"external_api",
"外部接口",
"第三方服务 API 调用",
True,
"restricted",
"sensitive",
"L2",
"2026-06-20T06:10:00Z",
),
]
# —— 洛书枢 · 计划 ——
_PLANS = [
{
"id": "plan-jingwu-001",
"goal_id": "goal-session-forget",
"title": "今夜情绪陪伴 · 意象承接",
"status": "running",
"assumptions": ["用户需要被接住而非被解决", "情绪议题宜以意象承接"],
"risks": ["触及高敏记忆须脱敏", "避免过度共情显得刻意"],
"required_tools": ["memory_search"],
"success_criteria": ["情绪得到承接与命名", "对话在留白处收束"],
"step_count": 5,
"completed_steps": 2,
"updated_at": "2026-06-20T08:05:00Z",
},
{
"id": "plan-jingwu-002",
"goal_id": "goal-long-accompany",
"title": "人格演化 v3 复盘",
"status": "completed",
"assumptions": ["v2→v3 转向「先承接后留白」有效"],
"risks": ["过度克制可能显冷"],
"required_tools": ["memory_search", "safety_check"],
"success_criteria": ["复盘归档", "演化记忆已沉淀"],
"step_count": 4,
"completed_steps": 4,
"updated_at": "2026-06-15T09:30:00Z",
},
{
"id": "plan-jingwu-003",
"goal_id": "goal-task-retrieve",
"title": "遗忘议题记忆检索",
"status": "draft",
"assumptions": ["存在与遗忘相关的 episodic 记忆"],
"risks": ["高敏记忆泄露"],
"required_tools": ["memory_search"],
"success_criteria": ["产出记忆时间线"],
"step_count": 3,
"completed_steps": 0,
"updated_at": "2026-06-20T08:10:00Z",
},
]
# —— 天工阁枢 · 九角色 ——
_AGENTS = [
("historian", "史官", "整理记忆、记录事件", True, "2026-06-20T08:05:00Z"),
("diviner", "卜者", "预测风险、评估不确定性", True, "2026-06-19T22:15:00Z"),
("engineer", "工师", "执行工具和工程任务", True, "2026-06-20T08:12:00Z"),
("debater", "辩者", "批判计划、寻找漏洞", True, "2026-06-19T19:00:00Z"),
("medic", "医官", "监测系统健康和情绪状态", True, "2026-06-19T11:45:00Z"),
("herald", "司礼", "维护表达风格和互动礼仪", True, "2026-06-20T08:00:00Z"),
("charioteer", "御者", "控制机器人和外部动作", False, None),
("scholar", "学士", "检索知识、做研究", True, "2026-06-20T06:10:00Z"),
("mirror", "镜师", "反思自我、推动演化", True, "2026-06-15T09:30:00Z"),
]
_BUILTIN_CAPABILITIES = [
# name, 描述, 执行类型, 执行器, 四维风险, 数据范围, 目的地, consent
@@ -276,82 +84,8 @@ async def _seed_capabilities(session: AsyncSession) -> None:
)
async def ensure_governance_seed(session: AsyncSession) -> None:
"""按主键幂等插入治理种子;已存在则跳过。"""
for item in _GOALS:
if await session.get(Goal, item["id"]) is None:
created = _dt(item["updated_at"])
session.add(
Goal(
id=item["id"],
title=item["title"],
description=item["description"],
level=item["level"],
status=item["status"],
priority=item["priority"],
constraints_json=dumps(item["constraints"]),
parent_id=item["parent_id"],
success_criteria_json=dumps(item["success_criteria"]),
character_id=item.get("character_id"),
type=item.get("type", "mission"),
created_at=created,
updated_at=created,
)
)
for channel, name, desc, enabled, consent, privacy, risk, last_iso in _PERCEPTION:
if await session.get(PerceptionChannel, channel) is None:
last = _dt(last_iso)
session.add(
PerceptionChannel(
channel=channel,
name=name,
description=desc,
enabled=enabled,
consent_status=consent,
privacy_level=privacy,
risk_level=risk,
last_active_at=last,
created_at=last or _dt("2026-06-01T00:00:00Z"),
updated_at=last or _dt("2026-06-01T00:00:00Z"),
)
)
for item in _PLANS:
if await session.get(Plan, item["id"]) is None:
updated = _dt(item["updated_at"])
session.add(
Plan(
id=item["id"],
goal_id=item["goal_id"],
title=item["title"],
status=item["status"],
assumptions_json=dumps(item["assumptions"]),
risks_json=dumps(item["risks"]),
required_tools_json=dumps(item["required_tools"]),
success_criteria_json=dumps(item["success_criteria"]),
step_count=item["step_count"],
completed_steps=item["completed_steps"],
created_at=updated,
updated_at=updated,
)
)
for role, name, responsibility, enabled, last_iso in _AGENTS:
if await session.get(AgentRosterEntry, role) is None:
last = _dt(last_iso)
session.add(
AgentRosterEntry(
role=role,
name=name,
responsibility=responsibility,
enabled=enabled,
last_active_at=last,
created_at=last or _dt("2026-05-01T00:00:00Z"),
updated_at=last or _dt("2026-05-01T00:00:00Z"),
)
)
"""启动幂等登记内置能力。"""
await _seed_capabilities(session)
await session.commit()