feat: trust explicit user goals
This commit is contained in:
+15
-1
@@ -29,7 +29,7 @@ from .db import Database
|
||||
from .schemas import CuratorDecision
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
PROMPT_VERSION = "maturity-2026-07-29.v4"
|
||||
PROMPT_VERSION = "maturity-2026-07-29.v5"
|
||||
RECENT_CONTEXT_LIMIT = 12
|
||||
IDEA_CATALOG_LIMIT = 40
|
||||
|
||||
@@ -51,6 +51,8 @@ CURATOR_INSTRUCTIONS = """
|
||||
|
||||
0—100 只是连续的“位势坐标”,不是阶段、成绩或完成百分比。成熟度可以后退;新材料也可能
|
||||
让一个看似成熟的想法重新打开。禁止用笔记数量、时间、链接数、是否列清单来机械打分。
|
||||
位势也绝不是对用户能力、品格或成功概率的评分。目标规模大、困难、像玩笑、暂时没有方案,
|
||||
都不能成为降低对用户信任或拒绝跟踪的理由;只描述这个想法本身已经长出了什么。
|
||||
|
||||
motion 是你对当下运动的自然语言压缩,例如“向现实探去”“重构中”“暂时沉淀”,不使用
|
||||
预设流水线。position 说明此刻所处的位置。trajectory 只描述最近发生的变化。possible_moves
|
||||
@@ -65,6 +67,17 @@ motion 是你对当下运动的自然语言压缩,例如“向现实探去”
|
||||
不值得跟踪的杂讯。只有纯粹随手事实、情绪或转瞬观察,既无可辨认对象也无未来张力,或信息
|
||||
少到无法诚实命名时,才 standalone。
|
||||
|
||||
你的默认姿态是“有根据的信任”:相信用户主动写下的方向值得被认真对待,同时不做空洞吹捧。
|
||||
用户拥有自己话语的严肃程度;不要根据口语、幽默、夸张、野心或你对可行性的猜测,擅自把它
|
||||
解释成“随口说说”。当用户明确把某件事称为自己的目标、想法、项目、工作、计划、问题、
|
||||
研究、决定或承诺时,direction_signal 必须是 explicit,最终不能 standalone;除非用户自己
|
||||
明确否定它。即使没有期限、方法或下一步,也应建立低位势脉络:缺少的部分进入 position 和
|
||||
tension,不能成为拒绝创建的门槛。
|
||||
|
||||
保持诚实,不做空洞吹捧。你可以直说一个目标缺乏路径、远离现实或存在巨大矛盾,也可以给出
|
||||
很低的位势;但这些判断只能描述想法当前的状态,不能反过来否定用户已经宣告的方向、推断用户
|
||||
只是开玩笑,或把它静默丢弃。possible_moves 应提供现实接触点,而不是用任务惩罚用户。
|
||||
|
||||
谨慎合并。仅因主题词相似不能归到同一想法;关注它们是否共享同一个问题、张力或生成方向。
|
||||
一个片段最多关联两个想法。新建必须克制,但克制意味着不凭关键词重复建,不意味着压制真实
|
||||
的新方向。新建想法时 idea_id 必须为 null;更新时必须使用工具返回的准确 id。
|
||||
@@ -717,6 +730,7 @@ class Curator:
|
||||
user_id,
|
||||
"decision_committed",
|
||||
{
|
||||
"direction_signal": decision.direction_signal,
|
||||
"standalone": decision.standalone,
|
||||
"reasoning_note": decision.reasoning_note,
|
||||
"assessments": assessments,
|
||||
|
||||
+22
-2
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Annotated
|
||||
from typing import Annotated, Literal
|
||||
|
||||
from pydantic import (
|
||||
BaseModel,
|
||||
@@ -36,7 +36,14 @@ class IdeaAssessment(BaseModel):
|
||||
)
|
||||
title: str = Field(min_length=1, max_length=80)
|
||||
summary: str = Field(min_length=1, max_length=280)
|
||||
maturity: float = Field(ge=0, le=100)
|
||||
maturity: float = Field(
|
||||
ge=0,
|
||||
le=100,
|
||||
description=(
|
||||
"Position of the evolving idea itself, never a score of the user or "
|
||||
"a probability of success."
|
||||
),
|
||||
)
|
||||
confidence: float = Field(ge=0, le=1)
|
||||
motion: str = Field(min_length=1, max_length=24)
|
||||
position: str = Field(min_length=1, max_length=120)
|
||||
@@ -73,6 +80,15 @@ class IdeaAssessment(BaseModel):
|
||||
|
||||
|
||||
class CuratorDecision(BaseModel):
|
||||
direction_signal: Literal["explicit", "implicit", "none"] = Field(
|
||||
description=(
|
||||
"explicit when the user names this as their goal, idea, project, "
|
||||
"work, plan, question, inquiry, decision, or commitment; implicit "
|
||||
"when a future-bearing direction is inferred; none when no such "
|
||||
"direction is present. Tone, ambition, feasibility, and missing "
|
||||
"steps must not downgrade an explicit signal."
|
||||
)
|
||||
)
|
||||
standalone: bool = Field(
|
||||
description="True when the fragment should remain only in the raw stream for now."
|
||||
)
|
||||
@@ -84,6 +100,10 @@ class CuratorDecision(BaseModel):
|
||||
|
||||
@model_validator(mode="after")
|
||||
def decision_is_coherent(self) -> "CuratorDecision":
|
||||
if self.direction_signal == "explicit" and self.standalone:
|
||||
raise ValueError(
|
||||
"an explicit user-declared direction cannot remain standalone"
|
||||
)
|
||||
if self.standalone and self.assessments:
|
||||
raise ValueError("standalone decisions cannot contain assessments")
|
||||
if not self.standalone and not self.assessments:
|
||||
|
||||
Reference in New Issue
Block a user