Skip to content

Commit b00c879

Browse files
fangxiu-wfclaude
andcommitted
feat(util-genai): add event log → trace converter, passthrough & total_tokens
Introduce the event log → OTel span tree converter for @loongsuite/otel-util-genai (published as 0.1.0-beta.9), turning loongsuite-pilot event logs into ARMS GenAI-compliant traces. - convertEventLogToTrace / convertEventLogToReadableSpans: rebuild ENTRY→AGENT→STEP→LLM/TOOL span trees from flat event logs; honor upstream trace_id / parent_span_id, response.id merge, and 1-level subagent nesting. - ARMS GenAI common attributes (agent.name / user.id / session.id) on every span. - ConvertOptions.passthroughKeys: allowlist to copy custom event fields onto spans (turn-level broadcast + LLM/TOOL per-record override, fill-only so converter-managed attributes are never overwritten). - gen_ai.usage.total_tokens now prefers the upstream-reported value and falls back to input+output only when absent or unusable (incl. total=0 guard). - Rename package to @loongsuite/otel-util-genai; update docs and add EVENT_LOG_TO_TRACE_SPEC.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent d5abd03 commit b00c879

40 files changed

Lines changed: 6077 additions & 25 deletions

opentelemetry-util-genai/CHANGELOG.md

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,104 @@
11
# Changelog
22

3+
## 0.1.0-beta.9 (2026-07-08)
4+
5+
### Features
6+
7+
- **自定义字段透传**`convertEventLogToTrace` / `convertEventLogToReadableSpans` 新增 `ConvertOptions.passthroughKeys` 白名单,可把 event log 里的自定义字段原样(不改名)写到对应 span。
8+
- 粒度:turn 级字段广播到该 turn 的全部 span(ENTRY/AGENT/STEP/LLM/TOOL);LLM/TOOL 额外读取自身源 record,同名时 per-record 覆盖 turn 级。
9+
- **fill-only 语义**:透传仅在 span 尚未携带该属性时写入,永不覆盖转换器已产出的属性(token 聚合、model、common 属性、TTFT 等)。
10+
- 不传 `passthroughKeys` 时行为完全不变(向后兼容)。
11+
- 新增并导出 helper `applyPassthroughAttributes(attrs, passthrough)`(fill-only 合并),供直接构建 invocation 的插件作者复用。
12+
13+
### Bug Fixes
14+
15+
- **total_tokens 优先采用上游值**:LLM / AGENT span 的 `gen_ai.usage.total_tokens` 现在优先采用 event log 里上游报告的 `gen_ai.usage.total_tokens`,仅当上游未提供时才回退到计算值 `input + output`。此前一律用 `input + output`,忽略上游值,导致 cache 占比高的 provider(如 Anthropic)total 偏小。AGENT 聚合遵循「全部 token response 都报了 total 才用其求和,否则整体回退」,避免上游值与计算值混用。⚠️ 属于行为变更:上游携带 `total_tokens` 的数据,span 上的 total 数值会随之改变。
16+
17+
### Type Changes (additive, backward compatible)
18+
19+
- `LLMInvocation` / `EntryInvocation` / `InvokeAgentInvocation` / `ReactStepInvocation` / `ExecuteToolInvocation` 新增可选字段 `passthroughAttributes?: Record<string, unknown>`
20+
- `LLMInvocation` / `InvokeAgentInvocation` 新增可选字段 `totalTokens?: number | null`(上游报告的 total,未设置时按 `input + output` 计算)。
21+
22+
## 0.1.0-beta.8 (2026-06-24)
23+
24+
### Bug Fixes
25+
26+
- **TTFT 透传**`buildLlmInvocation` 现在从 event log 的 `gen_ai.response.time_to_first_token`(纳秒)读取首包延迟并通过 `invocation.attributes` 写入 LLM span。之前该字段在 event log → OTLP trace 链路中被丢弃(SLS/JSONL/HTTP flusher 不受影响)。
27+
- **parent_span_id 读取范围收窄**`groupByTurn` 现在只从 `event.name="other"` 事件读取 `parent_span_id`(做法 A 的 ENTRY 标记事件)。之前从所有事件读取,与 pilot hook processor 在每条事件上写入 intra-trace 父 span ID 的既有约定冲突,导致多步 turn 必触发 `Inconsistent parent_span_id` false-positive warning,且 ENTRY span parentSpanId 被错误设为某个 STEP span ID。
28+
29+
## 0.1.0-beta.6 (2026-06-16)
30+
31+
### Features
32+
33+
- **支持上游 parentSpanId**`convertEventLogToTrace` 现在从 event log 的 `parent_span_id` 字段读取上游 span ID,作为 ENTRY span 的真实 parent,实现插件 trace 与上游调用方 trace 的 parent-child 真实关联(如上游平台 → claude-code → LLM/TOOL 的完整链路)。不含 `parent_span_id` 的 records 维持原有 synthetic parent 行为(完全向后兼容)。
34+
- 新增 `isValidSpanId` 校验函数并导出。
35+
36+
## 0.1.0-beta.5 (2026-06-09)
37+
38+
### Features
39+
40+
- **Subagent 嵌套**:当 TOOL span 有关联的子 session records(标记 `gen_ai.agent.scope=subagent` + `gen_ai.subagent.parent_tool_call.id`)时,转换器在 TOOL span 下自动创建嵌套的 `AGENT → STEP → LLM/TOOL` 子树。子 records 不参与父级 ENTRY/AGENT 的 token 聚合和 output.messages 构建。TOOL span 时间范围自动扩展以包裹子 agent。初始版本支持 1 层嵌套。不含 subagent 标记的 records 行为完全不变(向后兼容)。
41+
42+
## 0.1.0-beta.4 (2026-06-01)
43+
44+
### Features
45+
46+
- **做法 A 支持**`event.name = "other"` 事件中的 `gen_ai.input.messages_delta` / `gen_ai.input.messages` 现在被提取为 ENTRY/AGENT 的用户输入。所有 `other` 事件不生成任何 span(有 messages 的归 ENTRY,没 messages 的静默丢弃)。做法 B(legacy user-hook llm.request)仍兼容但标记为 deprecated。
47+
48+
### Bug Fixes
49+
50+
- **STEP span startTime 防御性修复**:STEP 的 startTime 现在优先取 step 内 LLM 事件(`llm.request` / `llm.response`)的最早时间,仅在无 LLM 事件时 fallback 到全部 records 的最早时间。修复上游 tool.call 事件 step.id 标错时 STEP span 时间范围被拉歪(如 48s vs 实际 1.6s)的问题。正常数据下行为不变。
51+
52+
### Documentation
53+
54+
- **EVENT_LOG_TO_TRACE_SPEC.md §5 重写**:做法 A(event.name="other")升级为 [MUST] 推荐;做法 B 标为已过期准备废弃。
55+
- **EVENT_LOG_TO_TRACE_SPEC.md 8 处修正**(基于 review):§11 warnings 合格标准排除 user-hook 类;§3.4 AGENT token 双算风险约束;§5.1 真实 LLM 调用必须自带用户消息;§3.2 model fallback 链;§4.2 合并策略细节表;§11 补 peer dep 安装提示;§2.4 round 正则限制说明;§8.2 事件→span 非一一对应措辞。
56+
57+
## 0.1.0-beta.2 (2026-06-01)
58+
59+
### Features
60+
61+
- **response.id 自动合并**:同一 step 内多条 `llm.response` 如果带相同的 `gen_ai.response.id`,转换器会在配对前自动合并为一条(parts 按时间顺序拼接,token 取有值的那条,model/finish_reason 取最后非空值)。解决 qoder / cursor 等上游把 thinking + text 拆成 2 条 event 导致"残影 LLM span"的问题。
62+
- **response-only model fallback**:当 `llm.response` 没有配对的 `llm.request` 时,`gen_ai.request.model` 现在会 fallback 到 `gen_ai.response.model`。之前这种场景 model 字段为 undefined(span name 显示为 `chat unknown`)。
63+
64+
### Documentation
65+
66+
- 更新 `EVENT_LOG_TO_TRACE_SPEC.md` §4.2 / §12,反映 response.id 合并兼容路径。
67+
- 更新 `PLUGIN_FEEDBACK_QODER.md` / `PLUGIN_FEEDBACK_CURSOR.md`,同步修正。
68+
69+
## 0.1.0-beta.1 (2026-05-28)
70+
71+
### Features
72+
73+
- **ARMS GenAI common attributes coverage**`gen_ai.agent.name`, `gen_ai.user.id`, `gen_ai.session.id` are now written on **every span kind** (ENTRY / AGENT / STEP / LLM / TOOL / EMBEDDING / RETRIEVER / RERANKER / MEMORY), per ARMS GenAI semantic conventions update. Previously only some span kinds carried them.
74+
- New helper `applyCommonGenAiAttributes(attrs, invocation)` in `span-utils` for plugin authors who build invocations directly.
75+
- Event log → trace converter automatically resolves these three attributes per turn (with fallback `gen_ai.agent.name → gen_ai.agent.type`) and propagates to all generated spans.
76+
77+
### Type Changes (additive, backward compatible)
78+
79+
- `LLMInvocation` adds `agentName?` / `userId?` / `sessionId?`
80+
- `ExecuteToolInvocation` adds the same three
81+
- `ReactStepInvocation` adds the same three
82+
- `EmbeddingInvocation` / `RetrievalInvocation` / `RerankInvocation` add the same three
83+
- `InvokeAgentInvocation` adds `userId?` / `sessionId?` (already had `agentName`)
84+
- `EntryInvocation` adds `agentName?` (already had `sessionId`/`userId`)
85+
- `MemoryInvocation` adds `agentName?` / `sessionId?` (already had `userId`)
86+
87+
All new fields are optional — plugins ignoring them stay fully backward compatible.
88+
89+
## 0.1.0-beta.0 (2026-05-27)
90+
91+
### Features
92+
93+
- First public beta on npm under `@loongsuite/otel-util-genai`.
94+
- Event log → OTel span tree converter (`convertEventLogToTrace` / `convertEventLogToReadableSpans`).
95+
- user-hook events auto-merge into ENTRY span input.messages.
96+
397
## 0.1.0 (2026-04-14)
498

599
### Features
6100

7-
- Initial release of `@loongsuite/opentelemetry-util-genai`
101+
- Initial release of `@loongsuite/otel-util-genai`
8102
- `TelemetryHandler` for LLM invocation lifecycle management (start/stop/fail + callback pattern)
9103
- `ExtendedTelemetryHandler` with support for all GenAI operation types:
10104
- LLM (chat/completion)

0 commit comments

Comments
 (0)