Skip to content

fix(wukong): rework event-log conversion for correct GenAI traces - #170

Open
Snssn wants to merge 3 commits into
alibaba:mainfrom
Snssn:fix/wukong-trace-quality
Open

fix(wukong): rework event-log conversion for correct GenAI traces#170
Snssn wants to merge 3 commits into
alibaba:mainfrom
Snssn:fix/wukong-trace-quality

Conversation

@Snssn

@Snssn Snssn commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Wukong sessions produced malformed GenAI traces. This reworks the AGUI → event-log conversion in WukongInput to fix four issues, all verified end-to-end against real wukong-cli data:

  • Truncated answer / zero tokens — tighten the completeness gate: a message is only emitted when it has settled (isComplete + RUN_FINISHED/RUN_ERROR + USAGE + a closing TEXT_MESSAGE_END). A still-streaming message is deferred to the next poll instead of being emitted truncated, and the cursor is not advanced past it.
  • Missing other event — each turn now begins with an other user-prompt event, so the stream no longer starts with tool.call.
  • Wrong step order — steps are segmented by LLM decision (an assistant utterance plus the tools it triggers), USAGE is attributed per step, and all records are sorted by time_unix_nano (other → llm.request → llm.response → tool.call → tool.result → …).
  • Token parsing — read real prompt/completion/total/cached tokens from USAGE.

Additional cleanups:

  • Merge REASONING + text into a single llm.response (multi-part).
  • Use a unique per-utterance response id (not the shared runId) so the converter does not collapse distinct steps.
  • Drop redundant agent.* extension fields (source/message_id/conversation_id/ttft/e2e_ttft/run_duration) that duplicated standard fields.

Test plan

  • npx vitest run tests/unit/inputs/wukong-input.test.ts — 37/37 pass
  • New real-session fixture (tests/fixtures/wukong/leetcode-session.json) + end-to-end assertions (other-first, full answer, real tokens, STEP == LLM, chronological order)
  • Verified on live wukong-cli data: field-coverage.mjs --agents wukong = 100% for all event types; validate-trace.mjs = 0 errors

Wukong sessions produced malformed traces. Rework the AGUI -> event-log
conversion in WukongInput to fix four issues verified against real data:

- Truncated answer / zero tokens: tighten the completeness gate (require
  isComplete + RUN_FINISHED/RUN_ERROR + USAGE + a closing TEXT_MESSAGE_END)
  so a still-streaming message is deferred instead of emitted truncated,
  and never advance the cursor past it.
- Missing `other` event: emit an `other` user-prompt event at each turn
  start so the turn no longer begins with tool.call.
- Wrong step order: segment steps by LLM decision (an assistant utterance
  plus the tools it triggers), attribute USAGE per step, and sort all
  records by time_unix_nano.
- Token parsing: read real prompt/completion/total/cached tokens from USAGE.

Also merge REASONING + text into a single llm.response (multi-part), use a
unique per-utterance response id (not the shared runId) so the converter
does not collapse distinct steps, and drop redundant agent.* extension
fields (source/message_id/conversation_id/ttft/e2e_ttft/run_duration).

Add a real-session test fixture and end-to-end assertions.
Comment thread src/inputs/wukong/wukong-input.ts Outdated
Comment thread src/inputs/wukong/wukong-input.ts Outdated
Comment thread src/inputs/wukong/wukong-input.ts Outdated
Comment thread src/inputs/wukong/wukong-input.ts
Comment thread src/inputs/wukong/wukong-input.ts Outdated
Comment thread tests/unit/inputs/wukong-input.test.ts
@linrunqi08

Copy link
Copy Markdown
Collaborator

🔍 Code Review Summary

PR #170 fix(wukong): rework event-log conversion for correct GenAI traces · head 8474be05

Severity Count
Critical 0
High 3
Medium 3
Low 2 (+ 若干既有问题)

Lifecycle Verdict

Check Result
资源释放 PASS
死锁/卡死风险 PASS(graceful stop 因 abort 时序失效可阻塞 ~10s,既有)
状态恢复正确性 FAIL

状态恢复 FAIL 证据:

  • H2:已 RUN_FINISHEDisComplete=1 但缺 USAGE 的消息会让 isMessageComplete 永久返回 false,findLastCompleteIndex 在此处 break 且游标不前进 → 该 session 从此条起所有后续 turn 永久静默不发射。
  • 既有项:transformAssistantMessage 对某条消息抛异常被 try/catch 吞掉后,newSeenCount 仍按 processable.length 越过被丢消息,永久跳过。

总体结论

方向正确:other-first、答案不截断、真实 token、时间序、reasoning+text 合并单条 response、per-utterance response.id 等均与 EVENT_LOG_TO_TRACE_SPEC 一致,并在 leetcode 真实会话上验证。

但重写在删除既有能力/权威信号时引入回归,建议合入前修复 3 个 High

  1. [High] ACTIVITY_SNAPSHOT 抽取丢失wukong-input.ts:920):删除了 FILE_READ/SEARCH/SKILL/ARTIFACT 的专用抽取,落入 defaulttool.call.arguments/tool.call.result 被完全丢弃。本 PR 自带 fixture 的 FILE_READ 活动即触发(读取的 URL/内容全丢),但 e2e 未断言 args/result 故 CI 全绿放行。
  2. [High] isMessageComplete 过度门禁wukong-input.ts:1099):isComplete===1 未被视为权威,仍强制要求 USAGE 等 → 头阻塞/永久丢数据(见 Lifecycle)。相对 base 的回归。
  3. [High] step 分段欠切分wukong-input.ts:501):弃用 STEP_STARTED,仅按发言边界切 step;两次"中间无 text/reasoning"的连续工具轮次会被并入一个 step → 违反 spec §2.3(STEP 数 ≠ 真实 LLM 调用数)。

Medium:activity 结果状态判定回归(失败被标 success、error.message 丢失,:949);多条 USAGE 下 AGENT token 可能双算/少算(:570);测试覆盖盲区(activity args/result、reasoning+text 多 part 均无断言)。

Highlights(正向实践)

  • other-first + messages_delta 增量 + 按 time_unix_nano 排序,忠实落地 spec §5/§7/§8。
  • reasoning+text 合并单条 llm.response、per-utterance 唯一 response.id,规避 §4.2 双 span 与 step 折叠。
  • USAGE 落最终 step 使 AGENT 聚合 == 真实上报(单聚合场景),并有 Σ tokens 守恒的 e2e 断言。
  • 外部数据防御到位:时间戳 sanitize、numOr 拒 NaN/Inf、tool args JSON.parse try/catch 回退。

评审报告详见: code-review/pr-170/final-report.md
Generated by LoongSuite-Pilot Code Review Agent

…mplete, honor STEP_STARTED

Addresses the code-review findings on the wukong rework:

- Restore full ACTIVITY_SNAPSHOT extraction for FILE_READ/SEARCH/SKILL/ARTIFACT
  (plus FILE_WRITE file_path and DIRECTORY_LIST files/total_count fallbacks) via
  compactObject, so their arguments/results are no longer dropped into `default`.
- Restore resolveActivityResultStatus (status string / error_message / cancelled)
  and emit error.message, instead of judging failure by exit_code alone.
- Completeness gate now trusts the API's authoritative `isComplete` flag
  (isComplete===1 -> complete; ===0 -> defer; heuristic only when absent), so a
  settled message can never permanently block the rest of the session.
- Honor STEP_STARTED/STEP_FINISHED as authoritative step boundaries when present;
  otherwise split sequential (non-overlapping) tools into separate steps while
  keeping overlapping/parallel tools together.
- Accumulate per-step USAGE instead of overwriting.
- Skip PERMISSION (HITL) and metadata-only/invisible auxiliary messages so they
  don't fragment the turn or emit empty tool/LLM pairs.

Tests: assert FILE_READ args/result in the e2e case; add unit tests for
FILE_READ/SEARCH/SKILL/ARTIFACT payload extraction, status-from-error_message,
REASONING+text single-response merge, and PERMISSION/aux-message skipping.
@Snssn

Snssn commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator Author

感谢细致的 review 🙏 已在 59999a4 全部修复,逐条回应:

[High] #1 ACTIVITY_SNAPSHOT 抽取回退丢数据 — 已修复。恢复 FILE_READ / SEARCH / SKILL / ARTIFACT 的专用抽取,并补回 FILE_WRITE 的 file_path 回退与 DIRECTORY_LIST 的 files/total_count 回退,compactObject 一并恢复。default 分支不再吞掉这些类型的 args/result。

[Medium] #2 activity 结果状态判定回归 — 已修复。恢复 resolveActivityResultStatus(识别 status 字符串 error/failed/failure、非空 error_messagecancelled)并重新输出 error.message,不再只看 exit_code

[High] #3 完成门禁覆盖 API 权威标志 — 已修复。isComplete===1 直接判定完成、===0 推迟,仅在该标志缺失时才回退到 RUN 终止启发式,避免单条消息永久阻塞整条 session。

[High] #4 step 分段欠切分 — 已修复。存在 STEP_STARTED/STEP_FINISHED 时按其权威分段;缺失时对"当前 step 已产出工具后、开始时间晚于上一个工具结束"的顺序工具开启新 step(重叠/并行工具仍归并同一 step,符合 §2.3)。

[Medium] #5 多条 USAGE 双算/少算 — 已改为按 step 累加(不再覆盖)。

[Medium] #6 测试盲区 — 已补:e2e 断言 FILE_READ 的 args(path)/result(content);新增 FILE_READ/SEARCH/SKILL/ARTIFACT 载荷抽取、status-from-error_message、REASONING+TEXT 合并单条 llm.response 多 part 的用例。

另外修复了一个连带问题:isComplete 生效后,尾部的 PERMISSION(HITL 审批)活动消息与 invisible 的 session_context_stats 元数据消息会被处理并产生碎片 trace / 空 tool。现已跳过 PERMISSION 活动与无 run/无内容的辅助消息,保证单轮单 trace、顺序正确。

已用真实 wukong 会话复核:field-coverage --agents wukong 全字段 100%,validate-trace 0 error;单测 41/41 通过。

@ralf0131 ralf0131 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: fix(wukong): rework event-log conversion for correct GenAI traces

Summary

Focused 3-file refactor (−62 net lines) that reworks the AGUI → event-log conversion in WukongInput to fix malformed GenAI traces. Four issues addressed, all verified against real wukong-cli data.

Key Changes Analysis

1. Tightened completeness gate

  • A message is only emitted when it has fully settled: isComplete + RUN_FINISHED/RUN_ERROR + USAGE + closing TEXT_MESSAGE_END
  • Still-streaming messages are deferred to next poll — prevents truncated answers and zero-token emission
  • Cursor is not advanced past incomplete messages — correct behavior

2. New StepAcc accumulator interface

  • Properly segments one assistant utterance (reasoning + text) plus triggered tools
  • Per-utterance responseId ensures unique gen_ai.response.id per LLM call (run-level runId is shared and must not be reused)
  • Clear documentation: "one step == one LLM decision (spec §2.3)"

3. Step segmentation

  • Uses explicit STEP_STARTED/STEP_FINISHED boundaries when available (authoritative)
  • Falls back to heuristic segmentation when not present — good defensive design

4. Defensive timestamp sanitization

  • evs map sanitizes AGUI timestamps once upfront with fallback to msg.createdAt
  • Handles external data gracefully

5. Metadata-only message filtering

  • MEANINGFUL_EVENTS set skips messages with only CUSTOM/FIRST_TOKEN events
  • Prevents spurious empty LLM pairs — good edge case handling

6. other event per turn

  • Each turn now begins with an other event for the user prompt
  • Uses earliest user message timestamp for correct temporal ordering

Test Coverage

  • wukong-input.test.ts significantly updated (+238 −177) — tests verify the new conversion logic
  • New fixture leetcode-session.json (+80) — real test data for end-to-end verification
  • CI all green: build-and-test (Node 18/20/22) ✅

Minor Observations

  1. ACTIVITY_TYPE_TO_TOOL_NAME changes: Removed FILE_READ and SEARCH mappings. If these activity types still appear in real AGUI data, they'll fall through to the default case. Worth confirming these are truly unused.

  2. stepMessageId format: Changed from (evt.messageId as string) ?? 'step-${stepIndex}' to just 's${stepIndex}'. This simplifies the ID but loses the AGUI messageId correlation. If downstream consumers relied on this correlation, it could break.

Verdict

Clean, well-documented refactor that fixes real trace correctness issues. Good test coverage with real fixtures. CI green. Approving.


Automated review by github-manager-bot

@linrunqi08 linrunqi08 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Code Review Round 2 — 修复验证

PR #170 · head 59999a48(round-1 head 8474be05)· 增量验证 commit 59999a48

round-1 全部 6 条 inline 评论(3 High + 3 Medium)均已修复,逐条已回复并 resolve。作者另主动修复 PERMISSION/invisible 消息碎片 trace 连带问题,核对不引入回归。

级别 结论
#1 ACTIVITY_SNAPSHOT 抽取回退 High ✅ fixed
#2 结果状态判定回归 Medium ✅ fixed
#3 完成门禁覆盖 isComplete High ✅ fixed
#4 step 分段欠切分 High ✅ fixed
#5 USAGE 双算/少算 Medium ✅ fixed
#6 测试覆盖盲区 Medium ✅ fixed

Lifecycle Verdict

Check round-1 round-2
资源释放 PASS PASS
死锁/卡死风险 PASS PASS
状态恢复正确性 FAIL PASS(H2 根因已修)

Merge Gate(合入门禁)

APPROVE-READY ✅ — 无任何 open 阻断项(Critical/High/Medium 全部 fixed,Lifecycle 三项全 PASS)。仅剩 2 项 Low(otherTs 未钳制、stepMessageId 死字段)不阻断合入。

验证

  • npx vitest run tests/unit/inputs/wukong-input.test.ts41/41 pass(node v22)。

✅ Medium/High 及以上问题已全部解决,本轮评审通过(approved)。


评审报告详见: code-review/pr-170/final-report-round2.md
Generated by LoongSuite-Pilot Code Review Agent

@ralf0131

Copy link
Copy Markdown
Collaborator

⚠️ Merge conflict detected

This PR has conflicts with the main branch and cannot be merged. Please rebase or merge main into your branch and resolve the conflicts:

git fetch origin
git checkout fix/wukong-trace-quality
git rebase origin/main
# resolve conflicts, then:
git push --force-with-lease

This is a one-time reminder. Feel free to @mention me for a re-review after conflicts are resolved.


Automated notification by github-manager-bot

…ality

# Conflicts:
#	tests/unit/inputs/wukong-input.test.ts

@ralf0131 ralf0131 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Reworks the AGUI → event-log conversion in WukongInput to fix four issues with Wukong session GenAI traces: truncated answers/zero tokens, incorrect step segmentation, missing response IDs, and orphan user messages.

Overall: LGTM. The refactoring significantly improves code clarity and correctness.

Highlights

  • StepAcc accumulator pattern — replaces the old mutable flushStepLlm closure pattern with a clean, explicit accumulator per step. Each step now collects reasoning, text, tool calls, and usage independently, making the code much easier to reason about
  • Run-level / step-level separationRUN_STARTED/RUN_FINISHED/RUN_ERROR are now scanned in a dedicated pre-pass, cleanly decoupled from step segmentation logic
  • Completeness gate hardening — the new isComplete field from get_spark_agui_messages provides an explicit signal; fallback to event-based detection for older payloads maintains backward compatibility
  • Metadata-only message filteringMEANINGFUL_EVENTS set prevents spurious empty LLM pairs from invisible session_context_stats messages
  • Per-utterance response IDs — each LLM call in a run now gets a unique gen_ai.response.id, fixing the previous issue where all steps shared the run-level ID
  • User prompt timestampuserPromptTs correctly timestamps the other event before the run starts

Minor Observations (non-blocking)

  1. Tool name mapping cleanupFILE_READ and SEARCH removed from ACTIVITY_TYPE_TO_TOOL_NAME. If any legacy Wukong data still emits these activity types, they will be silently dropped. Consider logging a warning for unmapped types in a follow-up
  2. openStep timestamp — uses the triggering event timestamp, which is correct. If the event timestamp is somehow missing/invalid, the fallback to msg.createdAt in the event sanitization pass handles it

Automated review by github-manager-bot

@ralf0131 ralf0131 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Complete rework of Wukong event-log conversion for correct GenAI trace generation. Replaces the monolithic transformation with a clean step-based accumulator model (StepAcc) that correctly segments multi-step conversations.

Highlights

  • Correct step segmentation: One step = one LLM decision (reasoning + text + tools). New step opens when fresh utterance arrives after tools emitted
  • Completeness gate: isComplete flag + event-based fallback prevents truncated answers and 0-token emissions
  • Defensive timestamp handling: Sanitizes timestamps up front, handles metadata-only messages correctly
  • Per-utterance response IDs: Each LLM call gets a unique responseId (not shared run-level id)
  • Clean separation: Run-level scan (RUN_STARTED/FINISHED/ERROR) separated from step-level accumulation

Comprehensive test coverage with real fixture data.


Automated review by github-manager-bot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants