初始化提交

This commit is contained in:
chenxin committed 2026-08-21 16:00:13 +08:00
commit 887c1f449e
963 files changed
+166869

No files matched your search

+1
View File
@@ -0,0 +1 @@
"""大周天内驱力领域纯逻辑(造消息 / 解析好奇问题与次生目标草稿,禁止 IO)。"""
+127
View File
@@ -0,0 +1,127 @@
"""解析模型返回为内驱力草稿(纯函数,无 IO)。
好奇问题可内嵌次生目标([内驱力生成器设计] ../../docs/domain/core-domains.md
§6:好奇问题→转化次生目标)。缺省取**安全悲观默认**:``risk_level=L4``、
``source=reflection``,避免模型漏字段时生成高风险探索。
"""
import json
import re
from dataclasses import dataclass, field
from typing import Any
@dataclass
class SubgoalDraft:
title: str
description: str
expected_information_gain: float = 0.5
interruption_cost: float = 0.5
risk_level: str = "L4"
@dataclass
class CuriosityDraft:
question: str
source: str = "reflection"
related_entities: list[str] = field(default_factory=list)
expected_value: float = 0.5
urgency: float = 0.5
risk_level: str = "L4"
subgoals: list[SubgoalDraft] = field(default_factory=list)
_VALID_SOURCES = {
"world_uncertainty",
"memory_gap",
"perception_change",
"goal_tension",
"reflection",
"time_rhythm",
}
_VALID_LEVELS = {"L0", "L1", "L2", "L3", "L4"}
def parse_curiosities(raw: str) -> list[CuriosityDraft]:
drafts: list[CuriosityDraft] = []
for item in _extract_json_array(raw):
if not isinstance(item, dict):
continue
question = str(item.get("question", "")).strip()
if not question:
continue
drafts.append(
CuriosityDraft(
question=question,
source=_source(item.get("source")),
related_entities=_str_list(item.get("related_entities")),
expected_value=_clamp_float(item.get("expected_value"), 0.5),
urgency=_clamp_float(item.get("urgency"), 0.5),
risk_level=_level(item.get("risk_level")),
subgoals=_parse_subgoals(item.get("subgoals")),
)
)
return drafts
def _parse_subgoals(value: Any) -> list[SubgoalDraft]:
if not isinstance(value, list):
return []
result: list[SubgoalDraft] = []
for item in value:
if not isinstance(item, dict):
continue
title = str(item.get("title", "")).strip()
description = str(item.get("description", "")).strip()
if not title or not description:
continue
result.append(
SubgoalDraft(
title=title,
description=description,
expected_information_gain=_clamp_float(item.get("expected_information_gain"), 0.5),
interruption_cost=_clamp_float(item.get("interruption_cost"), 0.5),
risk_level=_level(item.get("risk_level")),
)
)
return result
def _extract_json_array(raw: str) -> list[Any]:
text = raw.strip()
matched = re.search(r"```(?:json)?\s*(\[.*?\])\s*```", text, re.DOTALL)
if matched:
text = matched.group(1)
else:
start, end = text.find("["), text.rfind("]")
if start != -1 and end > start:
text = text[start : end + 1]
try:
data = json.loads(text)
except json.JSONDecodeError:
return []
return data if isinstance(data, list) else []
def _source(value: Any) -> str:
text = str(value or "").strip()
return text if text in _VALID_SOURCES else "reflection"
def _level(value: Any) -> str:
text = str(value or "").strip().upper()
return text if text in _VALID_LEVELS else "L4"
def _str_list(value: Any) -> list[str]:
if not isinstance(value, list):
return []
return [str(v) for v in value if v is not None]
def _clamp_float(value: Any, default: float) -> float:
try:
num = float(value)
except (TypeError, ValueError):
return default
return max(0.0, min(1.0, num))
+55
View File
@@ -0,0 +1,55 @@
"""大周天内驱力 prompt 构建(纯函数,无 IO)。
复用 ``EvaluationSnapshot``(态势快照),产出 ``(system, user)`` 消息对,喂给
模型网关。模型返回的 JSON 由 ``extract`` 模块解析。
枚举取值以 [内驱力生成器设计](../../docs/domain/core-domains.md) §5 与
[数据库 schema](../../docs/contracts/contract-glossary.md) §22 为准。
"""
from app.modules.big_cycle.prompts import EvaluationSnapshot
DRIVE_SOURCES = (
"world_uncertainty",
"memory_gap",
"perception_change",
"goal_tension",
"reflection",
"time_rhythm",
)
DRIVE_LEVELS = ("L0", "L1", "L2", "L3", "L4")
def build_drive_extraction_messages(
snapshot: EvaluationSnapshot,
) -> tuple[str, str]:
system = (
"你是魂镜的内驱力生成器。基于本轮自我评估的态势快照,识别「匮乏感」——"
"世界模型不确定性、记忆缺口、目标张力等——生成好奇问题与可审核的探索性次生目标。"
"不生成已有确信答案的问题;不为满足好奇而越权(摄像头 / 麦克风 / 敏感读取仍需授权)。"
f"source 取自:{', '.join(DRIVE_SOURCES)}。"
f"risk_level 取自:{', '.join(DRIVE_LEVELS)}"
"(探索风险等级,L4 必须人工确认)。"
'以 JSON 数组返回,每个元素是一个好奇问题:{"question": str, "source": str, '
'"expected_value": 0~1, "urgency": 0~1, "risk_level": str, '
'"related_entities": [实体名], "subgoals": [{"title": str, "description": str, '
'"expected_information_gain": 0~1, "interruption_cost": 0~1, "risk_level": str}]}。'
"subgoals 为该好奇问题转化的可执行探索目标,可空数组。"
"仅在态势确有缺口时生成,宁缺毋滥;无缺口返回 []。"
"只返回 JSON 数组,不要解释或 markdown。"
)
user = (
f"记忆总数:{snapshot.memory_count}\n"
f"世界实体数:{snapshot.world_entity_count}\n"
f"自我评估结论:{snapshot.conclusion or '(无明显态势)'}\n"
f"当前人格摘要:\n{snapshot.personality_summary or '(尚未形成)'}\n"
f"近期记忆摘要:\n{_format_memories(snapshot.recent_memories)}"
)
return system, user
def _format_memories(memories: list[tuple[str, str]]) -> str:
if not memories:
return "(暂无)"
lines = [f"[{idx}] {title}:{content}" for idx, (title, content) in enumerate(memories)]
return "\n".join(lines)