oh-my-pi Sharpshooter 决策提取解析从用户消息到项目记忆 Delta 的输入信封与证据门控【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi导读本篇技术指南以 oh-my-pi 项目中的sharpshooter-extract-input.md提示词模板为核心剖析 Sharpshooter —— 一个摩擦门控friction-gated的项目决策记忆子系统——如何从编码会话的单条用户消息中异步提取可持久化的项目决策 Delta。读者将掌握提取阶段输入信封envelope的三段式构建逻辑、record_deltas工具与证据evidence硬性校验规则、Delta 队列的落盘与消费机制以及它与 5 分钟合并consolidation流水线之间的完整数据流并可直接在配置中启用该记忆后端。Sharpshooter 在 oh-my-pi 记忆体系中的定位oh-my-pi 的编码 Agent位于 packages/coding-agent面临一个普遍难题会话中用户做出的项目级决策用 X 不用 Y这是有意为之不是 bug会在会话结束后丢失下次会话的 Agent 可能把代码里已反映的决策再次做错。为此项目在 记忆后端选择器 中提供了off / local / hindsight / mnemopi / sharpshooter五种后端其中 Sharpshooter 的定位是Friction-gated project decision files (architecture/product/style), consolidated in the background即以摩擦为门控的项目决策记忆只有踩过坑的决策才值得记住记忆沉淀为architecture.md、product.md、style.md三个 Markdown 决策文件并注入后续编码会话的上下文中。从源码结构看整个子系统分为三个阶段本文聚焦第一阶段提取extract——每条用户消息后异步触发产出决策 Delta写入按会话分组的队列见 extract.ts排队queue——每个 Delta 一个 JSON 文件生产者无锁追加见 queue.ts合并consolidate——按项目每 5 分钟可配执行一次将队列 Delta 按准入法合并进三个记忆文件见 consolidate.ts。提取输入信封关联文档的完整结构本指南的关联文档 sharpshooter-extract-input.md 是提取阶段的用户消息模板Handlebars 模板运行期由prompt.render(extractInputTemplate, { ...envelope })渲染见 extract.ts。其完整内容如下{{#if previousHuman}} previous-user-message purposereferent context only, never evidence {{previousHuman}} /previous-user-message {{/if}} {{#if assistantContext}} assistant-context purposereferent context only, never evidence {{assistantContext}} /assistant-context {{/if}} user-prompt {{prompt}} /user-prompt模板刻意将输入拆成三个区块每个区块的用途各不相同区块变量purpose 标注在提取中的作用user-promptprompt无标注即唯一证据来源触发本次提取的当前用户消息原文是唯一可被引用为evidence的文本previous-user-messagepreviousHumanreferent context only, never evidence上一条用户消息仅用于理解短回复类决策的语义assistant-contextassistantContextreferent context only, never evidence紧邻的助手回复如选项列表仅用于解析opt 2go for it选择了什么这种证据与参照物严格分离的设计是整条证据链防伪的第一道防线参照上下文只辅助理解绝不允许充当证据。对应地提取系统提示词 sharpshooter-extract-system.md 明确要求previous user message and assistant context are referents for interpretation ONLY; they are never evidence, and nothing stated only by the assistant may become a delta。信封在源码中如何构建输入信封由 buildSharpshooterEnvelope 从会话转录快照构建其关键行为包括定位触发消息以当前用户消息为起点向前扫描若消息尚未追加进转录message_start事件先于转录落盘则退化为取转录中最后一条用户消息。反向查找参照物从触发消息向前取最近一条用户消息作为previousHuman、最近一条助手消息作为assistantContext两者都找到即停止。上下文清洗与截断cleanEnvelopeContext会将代码块或~~~整体替换为[code omitted]压缩空白后截断——previousHuman上限 400 字符、assistantContext上限 800 字符。这既防止大段代码撑爆上下文也从源头杜绝从粘贴的日志/代码中提取决策。空消息不触发当前消息为空或不存在时直接返回undefined不启动提取。系统提示词什么才算一个 Delta提取阶段的系统提示词 sharpshooter-extract-system.md 定义了 Delta 的六种类型与 types.ts 的SharpshooterDeltaKind完全一致architecture_decision—— 运行时/组件边界、选定的抽象、协议或存储方向、显式的X 优于 Yproduct_decision—— 行为、UX、默认值、命名/术语、产品范围含什么、不含什么style_decision—— 视觉/审美语言、呈现约定、面向项目文本的措辞/语气规则constraint—— 用户声明的不容协商项隐私、性能包络、兼容性、部署rejected_approach—— 被用户拒绝的尝试过或提议过的方案以及拒绝理由若给出correction—— 用户纠正先前已定论的行为这不是我们约定的X 是有意为之Y 是 bug。同时规定了两类来源SharpshooterDeltaSource用户在消息中直接陈述的用explicit_user短回复opt 2go for itsplit airgapno X plz需要借助助手上下文解析出选择了什么时用contextual_resolution。证据规则硬性要求提示词规定evidence必须是当前用户提示词的精确连续子串逐字节复制。这条规则不是模型自律而是有宿主端强制校验兜底的——见下文准入门控。摩擦标签Friction tags每个 Delta 必须诚实打上三个布尔摩擦标签因为合并阶段按摩擦准入而非按存在准入corrective: true—— 用户在重申或纠正先前已定论的内容regression: true—— 用户报告原本正常的行为破坏、漂移或回退了subtle: true—— 仅凭代码难以一眼看出的非显式不变量跨组件预期、A 与 B 有别的区分、代码无法自描述的意图。三个全为false也是合法结果代表一次干净的首决决策。陈述规则永恒规范式Status bar uses powerline-style segments绝不用用户想要目前我们刚修了不含文件路径、行号、函数/类型名、提交 ID 或 issue 号产品组件词汇composer、status bar、daemon 名允许排除当前任务态正在修的 bug 不是决策但关于先前已定论行为的 bug 报告是correction且regression: true不提取与项目决策无关的个人品味偏好语言、通用编码哲学、提交风格不从不带引号的粘贴材料日志、diff、文档提取只从人类话语中提取rejectedAlternative/rationale仅在用户确实给出时才填严禁臆造。record_deltas 工具与准入门控提取模型被要求恰好调用一次record_deltas工具toolChoice: required空数组是合法且常见的结果——大多数消息不包含持久决策。工具的参数 schema 在 extract.ts 中由 omptype 定义const deltaSchema type({ kind: architecture_decision | product_decision | style_decision | constraint | rejected_approach | correction, statement: string, rejectedAlternative?: string, rationale?: string, source: explicit_user | contextual_resolution, evidence: string, friction: { corrective: boolean, regression: boolean, subtle: boolean, }, });模型吐出的每个候选 Delta 都要经过 admitDelta 的宿主端强制校验而非仅依赖模型自觉任一条件不满足即被丢弃statement必须是非空字符串evidence必须是非空字符串且必须是当前 prompt 的包含子串currentPrompt.includes(raw.evidence)——直接实现证据硬规则防止模型用参照上下文或自编内容充当证据kind必须在六种类别白名单内SHARPSHOOTER_DELTA_KINDSsource必须在两类来源白名单内SHARPSHOOTER_DELTA_SOURCESfriction三个字段必须均为布尔值parseFriction。通过校验后Delta 被落盘为结构化对象v: 1版本号 sessionIdts时间戳进入队列。另外提取模型解析、推理开销被刻意压低maxTokens: 2048、Effort.Low思维级别并默认回退到smol角色模型且整个流程不阻塞主会话fire-and-forgetmaybeStartSharpshooterExtraction只记录 in-flight Promise。队列无锁、幂等、可重投递队列实现见 queue.ts核心设计是每个 Delta 一个 JSON 文件路径为queue/sessionId/ts36-nonce.json文件名即排序键时间戳以 36 进制、零填充 10 位保证字典序等于时间序4 位随机 nonce 化解同一毫秒的并发碰撞生产者无锁没有共享的追加 fd 与消费者的重命名竞争崩溃安全幂等消费合并是先全量重写记忆文件再删除队列文件若应用后、删除前崩溃只会导致同批 Delta 被重投递一次而合并本身最新者胜newest-wins重复应用无副作用脏数据免疫读取时校验v 1且statement为字符串无法解析的撕裂文件跳过不消费listSharpshooterDeltas不会卡死队列会话 ID 净化sanitizeSessionId把路径不友好字符替换为-作为目录名防线消费清理consumeSharpshooterDeltas删除已消费文件并递归清理空会话目录。队列深度的聚合由sharpshooterQueueDepth提供供状态展示与调度器判断是否到期。合并摩擦准入法与三文件记忆库提取只是上游真正决定什么值得记住的是合并阶段其系统提示词 sharpshooter-consolidate-system.md 定义了三条核心法则准入法Admission law——记忆靠摩擦挣得而非靠决策存在只有血统中至少出现以下之一才准入回归Regression已定论的行为在任何时点被破坏或漂移一次即可微妙性Subtlety仅凭代码看不出的规则——隐形不变量、跨组件预期、A 与 B 有别、代码无法自描述的观感意图重复Repetition跨会话两次以上纠正或一次明确反转且被拒方案仍是活诱惑。反例一次性决策、实现后再没做错过不是记忆——代码已反映它单次交流存储细节正是错误记忆的温床。拿不准就略过。具体性测试Concreteness test每条要点必须能改变新 Agent 的行为。提供可配置、兼容引用的交互是删除级状态栏powerline 分段、实心右缘、内收左三角、不加粗、耗时 ≤3 字符是保留级。单归属规则Single-home rule每条决策只住一个文件——architecture.md结构/运行时、product.md行为/UX/范围/命名、style.md视觉/排版/语气。此外还有硬排除项与项目自身文档重复的内容、全局个人品味、进行中的任务态、路径/行号/符号/提交号、更新语义最新者胜、跨会话同主题合并为一条、保留仍有效的旧条目、##分节、每条要点一行、每文件硬性 ≤120 行预算SHARPSHOOTER_MAX_FILE_LINES见 types.ts、无状态陈述。合并实现consolidate.ts还包含多项工程化保障跨进程单写者锁withFileLock(consolidate.lock)重试 1 次拿不到锁即返回locked完整重写而非补丁模型必须恰好一次调用replace_memory_files并给出三个文件的完整新内容toolChoice: required、maxTokens: 8192、Effort.Medium防清库护栏若现有记忆文件非空而模型返回全空内容直接拒绝refusing to wipe memory files密钥脱敏redactSecrets对 sk/pk/token/password 类长串、JWT 形串、AWS/GitHub/npm/Slack/Google API 密钥模式统一替换为[REDACTED]临时文件原子替换先写.name.pid.uuid.tmp再rename覆盖失败时清理残留项目文档去重读取cwd下AGENTS.md/CLAUDE.md截断至 6000 token作为已文档化内容禁止记忆重复调度器scheduler.ts按bankDir共享定时器、引用计数释放每分钟 tick队列非空或距上次合并超过intervalMinutes才执行。配置启用与存储布局要在 oh-my-pi 编码 Agent 中启用 Sharpshooter配置项位于 settings-schema.ts配置键类型/默认值说明memory.backendenum默认off设为sharpshooter即启用该决策记忆后端sharpshooter.modelstring默认空提取/合并使用的模型选择器留空回退smol角色sharpshooter.intervalMinutesnumber默认5合并轮询间隔分钟与调度器DEFAULT_INTERVAL_MINUTES一致sharpshooter.injectionTokenLimitnumber默认15000记忆文件注入会话上下文的 token 上限存储全部位于主目录作用域下的agentDir/memories/sharpshooter/bank/见 paths.ts不写入项目工作树bank由cwd通过projectBankSegment稳定推导同一项目跨会话共享同一记忆库。布局为architecture.md/product.md/style.md—— 三个决策记忆文件按序注入上下文queue/sessionId/ts36-nonce.json—— 每个排队 Delta 一个文件state.json—— 合并记账lastConsolidatedAt、lastResult、lastError供/memory stats与/memory diagnose使用consolidate.lock—— 跨进程单写者锁。小结从 sharpshooter-extract-input.md 这个短小的输入模板出发可以看到 oh-my-pi Sharpshooter 记忆后端的一整套严谨设计三段式输入信封严格隔离证据与参照物宿主端 evidence 子串校验与摩擦标签共同杜绝错误记忆无锁文件队列 幂等消费保证崩溃安全5 分钟合并 准入法 120 行预算把记忆收敛为精炼、可改变新 Agent 行为的项目决策文件。对于希望为编码 Agent 构建会记住项目约定的记忆系统的开发者这套提取 → 排队 → 摩擦门控合并 → 注入上下文的流水线是一个可复用的完整参考实现。【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考