feat(claude): v0.2.0-beta — transcript tracing, per-turn traces, config file, JSONL logging#40
Open
fangxiu-wf wants to merge 23 commits into
Open
Conversation
- Each conversation turn now produces an independent trace (new traceId), instead of cumulative session-wide traces. All turns share gen_ai.session.id. - STEP spans now map to LLM reasoning cycles (one llm_call + resulting tool calls), not conversation turn boundaries, matching ARMS semantic conventions. - gen_ai.session.id is set on ALL spans (ENTRY, AGENT, STEP, LLM, TOOL), not just ENTRY. - Orphaned pre_tool_use events (where Claude Code drops PostToolUse hooks) now produce TOOL spans with tool.orphaned=true, preventing missing tools in traces. - Events are cleared after successful export in cmdStop(), fixing duplicate trace generation when Stop hook fires per-turn. - Add message-converter module for Anthropic/OpenAI/Responses protocol conversion to ARMS semantic format. - Update README trace hierarchy diagram and export flow description. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The lock file previously contained "link": true pointing to the local monorepo sibling directory, causing fresh clones to symlink instead of downloading from npm. New users got MODULE_NOT_FOUND because the local opentelemetry-util-genai had no dist/cjs/ build output. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Support image content blocks across all three LLM API protocols (Anthropic, OpenAI Chat, OpenAI Responses) by converting them to ARMS semantic convention BlobPart (base64) and UriPart (URL) formats. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ~/.claude/otel-config.json support (priority: config file > env var > default) - Add JSONL log collection with chain hash and daily file rotation - Fix -p mode missing LLM/STEP spans (remove setImmediate race in intercept.js) - Fix OTEL_RESOURCE_ATTRIBUTES not fully parsed into Resource - Update README with config file docs, new modules, and JSONL logging Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…t + update OSS paths
- Add logOnly branch in exportSessionTrace() to skip OTel span building when only JSONL logging is needed
- Add log_filename_format config option ("default" vs "hook") for BaseHookInput compatibility
- Update OSS paths from agenttrack to opentelemetry-instrumentation-claude
- Fix test flakiness caused by local otel-config.json interfering with env-var-based tests
- Document log-only mode in README
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align generateTurnLogRecords() output with the unified AI Agent EventSchema: - Split combined llm_call records into separate llm.request + llm.response events - Split combined tool records into separate tool.call + tool.result events - Rename all gen_ai.* fields to dotted namespace (event.name, session.id, etc.) - Add event.id (UUID), user.id, agent.type, agent.name to every record - Add usage.total_tokens, tool.result.status, tool.result.duration_ms - Add is_error/error.type/error.message on tool.result for failed tools Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update log field references from gen_ai.* to event_t dotted namespace (event.name, session.id, message.role, etc.) and document the split event model (llm.request/llm.response, tool.call/tool.result). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…laude-code" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- setup-alias.sh: add file writability check, handle cat >> failure gracefully - uninstall.sh: add npm uninstall -g otel-claude-hook step for global package cleanup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…xecution Same fix as codex plugin: generate hook-entry.sh wrapper at ~/.cache/opentelemetry.instrumentation.claude/ with built-in Node discovery (nvm, homebrew, volta, fnm fallbacks). Register absolute path in settings.json instead of bare `otel-claude-hook` command. - Add generateHookEntry(), packageBinPath(), hookEntryCacheDir() - Add isOtelHookCommand() to match both old and new formats - Extract removeOtelHooksFromSettings() for shared cleanup logic - Modify installIntoSettings() to clean old entries before adding new - Modify uninstallFromSettings() to use isOtelHookCommand() - Update install.sh to use `node "$PKG_DIR/bin/..."` absolute path - Update uninstall.sh cleanup to match hook-entry.sh format Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ility Cursor's third-party hooks parser requires the `matcher` field on each hook entry. Missing it causes "Failed to parse claude-user Claude hooks configuration" error. Add `"matcher": "*"` to all registered hook events. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
input.messages_delta was recording the full cumulative API context instead of only the new messages added since the last LLM call. Track previous input messages and use slice-based diff to produce correct deltas. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cursor reads ~/.claude/settings.json hooks and executes them, causing duplicate data collection alongside Cursor's own hooks. Detect Cursor by checking for cursor_version in the stdin payload and return early. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…M fix - Add transcript.js: parse Claude Code native transcript JSONL for LLM call data (replaces intercept.js HTTP interception, works with all Claude Code versions) - Inject GenAI SDK env vars (Group A) in bin/otel-claude-hook entry point, removing them from alias (plugin code handles defaults programmatically) - setup-alias.sh: remove Group A vars + NODE_OPTIONS + intercept.js from alias; add --minimal mode (cleanup only, no alias write) for pilot installations - Add upgrade_old_alias() to auto-clean legacy alias blocks containing intercept.js - Fix O(N²) OOM in transcript parsing: store input_messages as delta instead of cumulative copies (35MB transcript: memory from >4GB to ~98MB) - Log generation: incremental hash computation for delta mode events - Add maybeSaveTranscriptPath() + enrichChildStateWithTranscript() for subagent support - Add comprehensive tests for transcript parsing and new functions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allows managed installations (like pilot) to skip shell alias setup during plugin install, preventing redundant alias write + cleanup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e, and config isolation - cli.test: pass entryPath to installIntoSettings so hook dedup works correctly - cli.test: remove agent.name assertion (field was removed in 8f5c00f) - transcript.test: expect delta input_messages with _input_is_delta flag - logger.test: mock otel-config.json to prevent local pilot config from interfering Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Version: 0.1.0 → 0.2.0-beta - CHANGELOG: add 0.2.0-beta section with all PR alibaba#40 changes - README: document transcript-based tracing, simplified alias, --no-alias option, Cursor compatibility, project structure update Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… newline protection - generateHookEntry() now uses $(dirname "$0") relative path first, with install-time absolute path as fallback, and graceful exit 0 when bin is missing (fixes MODULE_NOT_FOUND on remote dev machines) - setup-alias.sh and remote-install.sh: add trailing newline protection before cat >> to prevent uninstall from eating the user's last line Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ring Issue 6: Fix transcript data duplication in interactive sessions by adding byte-offset-based incremental reading to parseClaudeTranscript(). Each Stop hook now reads only new transcript data since the last call. Issue 7: Fix tool.call ordering when PostToolUse hook is dropped (~30% drop rate). alignWithHookEvents now uses prevEnd+0.001 as lower bound for request_start_time, ensuring correct sort order. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Identifies traces from this plugin as originating from Claude Code in ARMS. Always set, not overridable via OTEL_RESOURCE_ATTRIBUTES, so mixed-agent dashboards can reliably filter by agent system. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…, CLAUDE_CONFIG_DIR compat 1. input_tokens now includes cache_read + cache_creation tokens (7 locations) 2. alignWithHookEvents pairs only last N events to prevent historical anchor steal 3. JSONL records now include trace_id/span_id/parent_span_id in all modes 4. Respect CLAUDE_CONFIG_DIR env var for Harbor/CI scenarios (settings + config paths) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
v0.2.0-beta 核心变更
Transcript-based Tracing(新数据源)
新增
transcript.js,解析 Claude Code 原生 session transcript JSONL,替代对intercept.jsHTTP 拦截的依赖:~/.claude/projects/<hash>/<session-id>.jsonl,提取每次 LLM 调用的模型、token 用量、输入输出消息intercept.jsHTTP 拦截O(N²) OOM 修复
transcript.js中input_messages改为 delta 模式存储(_input_is_delta: true),避免每次 LLM call 累积拷贝完整历史:Per-turn 独立 Trace
每轮对话生成独立 trace(新 traceId),同一 session 通过
gen_ai.session.id关联。Span 层级遵循 ENTRY → AGENT → STEP → TOOL/LLM 标准结构。GenAI 语义规范对齐
使用
@loongsuite/opentelemetry-util-genaiSDK 的ExtendedTelemetryHandler重构 span 创建流程,属性名、层级结构、消息格式完全对齐 ARMS GenAI 语义规范。配置文件支持
新增
~/.claude/otel-config.json,优先级:配置文件 > 环境变量 > 默认值。支持 endpoint、headers、service_name、debug、log_enabled 等 9 项配置。JSONL 日志采集
可选的本地日志功能,遵循 AI Agent EventSchema(event_t)规范:
llm.request+llm.response、tool.call+tool.resultAlias 环境变量精简
GenAI SDK 环境变量(Group A)从 alias 移至
bin/otel-claude-hook入口点程序化设置;NODE_OPTIONS+intercept.js从 alias 中移除。Legacy alias 自动升级清理。消息格式转换
新增
message-converter.js,支持 Anthropic、OpenAI Chat、OpenAI Responses 三种协议自动转换为 ARMS JSON Schema 格式。含多模态图片支持(BlobPart/UriPart)。Pilot 集成
--no-aliasinstall 选项:跳过 shell alias 设置,用于 pilot 等托管安装setup-alias.sh --minimal模式:仅清理旧 alias,不写入新 aliasCursor IDE 兼容
matcher字段cursor_version并跳过处理,避免与 Cursor 自身 hooks 冲突Bug 修复
-p非交互模式下 LLM/STEP span 丢失(intercept.jssetImmediate竞态)OTEL_RESOURCE_ATTRIBUTES未完整解析到 Resourceinput.messages_delta误发送累积历史而非增量pre_tool_use事件生成带tool.orphaned=true的 TOOL spancmdStop()导出后清空事件,防止重复 tracepackage-lock.json修复link: true导致新用户MODULE_NOT_FOUNDChanged Files
src/cli.js--no-alias、Cursor 兼容、hook-entry.sh 相对路径、增量 transcript offset 持久化、input_token 全量计算、span_id 增强、CLAUDE_CONFIG_DIR 兼容src/transcript.jssrc/config.jssrc/logger.jssrc/message-converter.jssrc/hooks.jssrc/intercept.jssrc/telemetry.jsbin/otel-claude-hook--no-aliasoption、--settings-path选项scripts/setup-alias.sh--minimal模式、legacy alias 升级、尾部换行保护scripts/remote-install.shpackage.jsontest/*.test.jstest/e2e-verify-fixes.jsREADME.mdCHANGELOG.mdTest plan
npm test— 292 tests 全部通过(9 suites, 0 failures)pack.sh→package.sh→--package-url file://完整验证🤖 Generated with Claude Code