ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

OmO Native 的 turn_completed 遥测事件:基于 turn_end 的使用量、成本上报与隐私脱敏实现解析

OmO Native 的 turn_completed 遥测事件:基于 turn_end 的使用量、成本上报与隐私脱敏实现解析 OmO Native 的 turn_completed 遥测事件基于 turn_end 的使用量、成本上报与隐私脱敏实现解析【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent导读turn_completed是 OmOoh-my-openagent的 omo-senpi 适配器所内置的匿名产品分析管道 OmO Native 中的核心事件之一用于在每一轮 AI 对话turn结束时上报该轮所消耗的 token 数量、成本、模型与 provider 身份。本文以仓库中task-8的实现证据为主线完整还原该事件的上游数据契约、处理器源码实现、隐私脱敏规则、事件 schema 白名单机制并给出从 RED 测试失败到 GREEN 全绿的落地过程、对抗性用例验证以及一份可复跑的端到端手工 QA 脚本。读完本文你将掌握 OmO Native turn 级遥测的完整数据链路并能够在自己的集成中复现同样的实现与验证方法。turn_completed 在 OmO Native 遥测中的定位OmO Native 是omo-senpi包提供的匿名产品分析管道默认开启、采用 opt-out 模式数据上报到打包配置的 PostHog 项目。senpi-telemetry.md 中将其事件模式schema按事件逐条列出其中turn_completed承载的是每次对话轮次的资源消耗事实token 侧input_tokens、output_tokens、cache_read_tokens、cache_write_tokens、reasoning_tokens、total_tokens成本侧cost_usd身份侧provider、model_id、$session_id、turn_index。在源码中事件的属性白名单定义于 event-schemas.tsturn_completed的全部属性含$session_id共 11 个被冻结为只读 schemaproduct-identity.ts 再把这些 schema 派生为OMO_NATIVE_PROPERTY_ALLOWLISTS即事件名 → 允许携带的属性键集合的结构化白名单供客户端在发送前强制过滤。上游数据契约TurnEndEvent、AgentMessage 与 Usageturn_completed的原始输入是宿主Senpi派发的turn_end事件。证据文档.omo/evidence/20260810-omo-native-telemetry/task-8.md在开发环境中对上游契约逐条核实TurnEndEvent定义于上游 senpi 的packages/coding-agent/src/core/extensions/types.ts本地路径 979-985 行包含turnIndex: number与message: AgentMessage两个核心字段。上游 pi-ai 层的消息联合类型为Message UserMessage | AssistantMessage | ToolResultMessageSenpi 的 agent 层通过AgentMessage暴露它并提供默认为空的声明合并扩展点因此处理器必须显式窄化event.message.role assistant之后才能读取 assistant 专属字段——这与 omo-native-turns.ts 中if (event.message.role ! assistant) return的首行守卫一一对应。Usage结构包含input、output、cacheRead、cacheWrite、可选cacheWrite1h、可选reasoning、totalTokens以及cost.{input,output,cacheRead,cacheWrite,total}。值得特别强调的是上游对reasoning的注释语义reasoning是output的子集output已包含这些 token实现采用reasoning ?? 0语义绝不把 reasoning 加到output或totalTokens上。这条约束直接决定了本文后面要单独说明的不重复计数注意事项。处理器实现createOmoNativeTurnHandler 的完整调用链核心实现位于 omo-native-turns.ts共 90 行刻意保持在 200 行软限制之下。createOmoNativeTurnHandler(options)接收client、可选的diagnostics回调与sessionId返回一个(event: TurnEndEvent) void的处理器其执行流程为角色守卫非assistant消息直接返回一个事件都不会发。容错取数asRecord只把非 null 的普通对象视为记录usage或cost缺失/畸形时得到undefined而不是抛错。字段规整nonNegativeNumber要求值是有限Number.isFinite且非负的 number否则归零并标记valid: falseoptionalNonNegativeNumber对undefined特殊处理——归零但不视为无效因此缺省reasoning不产生诊断。身份脱敏maskModel(provider, model)独立判定 provider 与 model。组装属性把脱敏后的provider/model_id与各 token 字段、cost_usd四位小数四舍五入、turn_index组装为properties并用satisfies RecordTurnCompletedProperty, string | number在编译期约束属性键必须落在OMO_NATIVE_PROPERTY_ALLOWLISTS.turn_completed内。诊断与发送只要任一字段无效就通过diagnostics发出一次telemetry_event_property_rejected诊断随后无条件调用client.captureEvent(turn_completed, properties)。注意第 6 步的容错哲学畸形数据不阻断遥测事件照发坏字段归零同时用诊断信号暴露数据质量问题保证后续排查有迹可循。成本字段cost_usd的取数是cost.total并通过roundToFourDecimalsMath.round((value Number.EPSILON) * 10_000) / 10_000规整例如0.123456 → 0.1235。这解释了手工 QA 输出中的精确数值。隐私脱敏provider 与 model 的独立判定脱敏是 turn 遥测的隐私核心。maskModel的两个半区携带不同的隐私权重因此采用两套不同的规则、两个独立的判定provider是用户自行编写的配置任何不在KNOWN_PROVIDERS内的取值一律输出为custom——自建网关、代理或内部网关的名字可以识别出公司或个人绝不能外泄model_id是公开产品名只要精确命中发布的模型词表model-vocabulary.ts 中的KNOWN_MODELS就原样保留无论它由哪个 provider 路由——因此一个公开模型经由 OpenRouter、LiteLLM 或私有网关到达时模型名依然可读不会坍缩为custom而微调模型、内部代号等任何用户自命名一律输出为custom。KNOWN_MODELS以 provider 为键、公开模型 id 数组为值例如openai: [gpt-5.6-luna-fast, gpt-5.6-sol, gpt-5.6-terra, gpt-6-astra]、anthropic: [claude-fable-5, ...]KNOWN_PROVIDERS则是其键集合。测试用四象限矩阵锁定了独立性omo-native-turns.test.tsprovidermodel输出openai已知已知模型{provider: openai, model_id: 模型}openai已知用户自定义模型{provider: openai, model_id: custom}未知 provider已知模型{provider: custom, model_id: custom}未知 provider用户自定义模型{provider: custom, model_id: custom}这一公开模型经未知网关 →custom/模型名的语义在 senpi-telemetry.md 的 masking 规则表中被正式公开声明model-vocabulary.ts的头部注释也注明改变该边界即意味着同步修改披露文档。白名单强制schema 派生 allowlist 与发送前投影脱敏靠的是结构性强制而非纪律自觉。在 events.ts 的captureEvent中任意事件在发送前都要过三道闸事件名检查事件名不在白名单中直接拒绝并上报telemetry_event_rejected诊断属性键投影只保留allowlist.has(key)通过的键未知键触发telemetry_event_property_dropped诊断并被丢弃禁用键与值检查$ip、以$开头但不在允许集合中的键ALLOWED_DOLLAR_KEYS只放行$os、$os_version、$process_person_profile、$session_id、以及键名以_text/_path/_prompt结尾的字符串值一律被拒绝isForbiddenKey数值必须是有限数字符串截断到 64 字符。随后sharedProperties统一附加platform、product_name、package_version、schema_version并固定$process_person_profile: false关闭人像画像。对turn_completed而言这意味着即使处理器内部组装出多余字段也绝无可能越过白名单进入外发载荷——测试用例专门用Object.keys(...).sort()与OMO_NATIVE_PROPERTY_ALLOWLISTS.turn_completed做精确键集比对omo-native-turns.test.ts。reasoning tokens不重复计数的硬约束turn_completed携带reasoning_tokens但它可选且是output_tokens的子集绝非增量。官方参考文档明确警告计算总量时永远不要把reasoning_tokens加进output_tokens否则会重复计数senpi-telemetry.md 的 Reasoning tokens caveat 一节。实现侧同样遵守optionalNonNegativeNumber(usage?.[reasoning])只把 reasoning 投影为独立属性total取的是usage.totalTokens原值二者从不相加。测试用例锁定了这条语义当usage中完全没有reasoning时输出reasoning_tokens: 0output_tokens与total_tokens保持不变且不产生任何诊断omo-native-turns.test.ts。对下游做成本/用量分析的人而言这是最容易踩的坑reasoning_tokens只能用于拆分视角不能参与求和。落地过程还原RED → GREEN → 必要验证证据文档完整记录了该功能的 TDD 落地过程。RED实现前运行bun test packages/omo-senpi/src/components/telemetry/omo-native-turns.test.ts因目标模块尚不存在而失败error: Cannot find module ./omo-native-turns 0 pass 1 failGREEN实现后同一命令转为全绿7 个用例、22 次断言全部通过覆盖脱敏独立性、每次 turn 恰好一条白名单载荷、reasoning 缺省归零、非 assistant 零事件、缺 usage 归零一条诊断、畸形 usage 坏值归零一条诊断、连续 turn 的turn_index单调跟随宿主。必要验证telemetry 目录全量bun test packages/omo-senpi/src/components/telemetry→ 39 pass、121 断言、6 个文件证据同时给出增量收据——本次任务新增 7 个聚焦测试与 22 条断言证明绿灯不是从陈旧或空测试目标推断出来的类型检查bun run --cwd packages/omo-senpi typecheck底层为tsgo --noEmit -p tsconfig.json退出码 0静态检查git diff --check退出 0实现 90 行、测试 199 行均在 200 行软限制内且未引入任何模型切换字段或状态。对抗性验证把异常输入逐一打穿证据文档记录了 10 项对抗性结果均与源码语义吻合缺usage发出一条turn_completed全部 usage/cost 字段归零恰好一条诊断不抛错cost: nullcost 归零共享该 turn 的唯一一条畸形数据诊断NaN、正无穷、负 token每个无效字段独立归零有效字段保持原值整轮只发一条诊断缺省可选reasoning归零且无诊断无内部状态处理器不维护任何轮次计数器两次宿主索引为 8、9 的事件输出[8, 9]证明turn_index完全来自宿主当前值不存在陈旧状态被复用的可能脱敏独立性openai 用户自定义模型输出{provider:openai, model_id:custom}未知 providermodel 输出custom/custom非 assistant 输入用户消息产生零事件、零诊断载荷形状事件键集与OMO_NATIVE_PROPERTY_ALLOWLISTS.turn_completed精确比对一致。端到端手工 QA录制型 transport 的可复跑脚本证据中最具实操价值的部分是使用录制型recordingtransport 替换默认 PostHog transport在本地完整跑通四输入三捕获的链路。其思路是用transportFactory把capture改为把消息推入内存数组captured从而在不接触网络的前提下断言最终外发载荷。核心片段如下const client createEventTelemetryClient({ distinctId: manual-machine, env: { POSTHOG_API_KEY: manual-key }, product: createOmoNativeProductConfig(), propertyAllowlist: OMO_NATIVE_PROPERTY_ALLOWLISTS, schemaVersion: 1, source: task-8-manual-qa, transportFactory: () ({ capture: (message) captured.push(message), flush: async () undefined, shutdown: async () undefined, }), }) const handle createOmoNativeTurnHandler({ client, sessionId: manual-session })随后依次喂入四个合成turn_end事件openai/gpt-5.6-sol、openai/user-defined-model、sionic-openrouter/private-model、一条 user 消息最终得到三条捕获。摘录第一条与第三条的完整载荷{ distinctId: manual-machine, event: turn_completed, properties: { $session_id: manual-session, provider: openai, model_id: gpt-5.6-sol, input_tokens: 10, output_tokens: 20, cache_read_tokens: 3, cache_write_tokens: 4, reasoning_tokens: 0, total_tokens: 37, cost_usd: 0.1235, turn_index: 1, platform: omo-senpi, product_name: omo-native, package_version: 5.0.0-beta.5, schema_version: 1, $process_person_profile: false } }第三条事件未知 providersionic-openrouter与私有模型private-model的输出为provider: custom、model_id: custom而cost_usd: 0.1235正是0.123456四舍五入到四位小数的结果第四条 user 消息则如预期地零捕获。此外还可在 omo-native-turns.test.ts 中看到同类录制手法在单测里的完整形态createRecorder捕获{name, properties}与诊断数组。清理收据与验收边界手工 QA 是一次性可执行脚本写入/tmp/omo-task8-manual-qa.ts后运行、随后删除证据文档附带了明确的清理收据CLEANUP: removed /tmp/omo-task8-manual-qa.ts且未向证据目录添加任何身份盐、主机名或预览载荷文件。这也呼应了 OmO Native 的本地留存策略不在本地保留已发送载荷的历史或预览文件见 senpi-telemetry.md 的 Local retention 一节事件 schema 与 opt-out 控制面即公开审计面。生产环境中的隐私边界与关闭开关把 turn 遥测接入生产前应完整阅读 senpi-telemetry.md 的以下约束永不收集提示词与回复文本、文件路径、Git 身份、环境变量值、原始主机名、自定义 skill 名、自定义 provider 名一律custom、词表外的模型名一律custom身份模型机器级匿名 id 为sha256(omo-senpi: hostname)的本地哈希$session_id使用按机器随机盐做键控哈希$process_person_profile: false保证 PostHog 不建人像记录opt-out 矩阵DO_NOT_TRACK1、OMO_SENPI_DISABLE_POSTHOG1、OMO_DISABLE_POSTHOG1、omo.json中telemetry.enabled: false、组件级omo-senpi-telemetry-disabled任一命中即整体关闭注意OMO_SENPI_SEND_ANONYMOUS_TELEMETRY/OMO_SEND_ANONYMOUS_TELEMETRY的既有怪癖——值yes反而被视为退出保持变量未设置才是开启。turn_completed处理器通过client.captureEvent与这些身份、过滤机制天然衔接因此上文的录制型 QA 中出现的platform/product_name/package_version/schema_version等附加属性正是由 events.ts 的统一sharedProperties注入的——turn 级实现只负责每轮的事实而身份、版本、白名单与 geoip 策略由 telemetry-core 统一收口。【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表