Captures every llm_output event regardless of OpenClaw's hook fire order, mirrors openclaw.session.id onto the OTEL-standard session attrs Latitude's resolver looks for, and clears OpenClaw 2026.4.26's potential-exfiltration audit warning.
Fixed
llm_outputenrichment is no longer dropped on theselection.runtimepath. OpenClaw 2026.4.26+ has two hook fire orders:cli-runner.runtime(used by theclaude-codeagent) firesllm_output → agent_end, andselection.runtime(used byopenai-codex/ embedded ACPX agents) firesagent_end → llm_output. The 0.0.6 plugin finalized the run synchronously insideagent_end, deleting the run and shipping the OTLP batch beforeselection.runtime's latellm_outputcould enrich the agent span. Everyllm_output-only attribute —gen_ai.output.messages,gen_ai.response.model,openclaw.resolved.ref,openclaw.harness.id, and the entiregen_ai.usage.*block (input / output / cache_read / cache_creation / total tokens) — was silently lost.onLlmOutput'sif (!run) returnwas a clean no-op, so there was no error, no warning, no signal anything was wrong. The fix defers finalization by one microtask viaqueueMicrotask: both hook handlers in the same dispatch round write to the still-alive run, the deferred finalize runs after both, and the OTLP batch ships fully enriched. Order-agnostic — works identically for either path. Subagents go through the sameonAgentEndcode path so they're fixed automatically.gen_ai.usage.cache_creation_input_tokensis now resolved by Latitude. The resolver'scacheCreateCandidatesonly looked for the dot-separatedgen_ai.usage.cache_creation.input_tokens; we emit the underscore form (matching what Anthropic-style OTel exporters use). Cache-write tokens silently dropped at resolve time. Resolver now picks up both spellings (packages/domain/spans/src/otlp/resolvers/usage/tokens.ts).
Added
session.idandgen_ai.session.idmirrored fromopenclaw.session.idon every span. Both are insessionIdCandidates(domain/spans/src/otlp/resolvers/identity.ts) —session.idis the OpenInference / OTEL standard and the first candidate the resolver tries,gen_ai.session.idis the proposed OTEL GenAI semconv key. With the mirror in place, traces can be grouped by OpenClaw session in the Latitude UI without any openclaw-specific resolver path. Emitted onagent,model_call,tool_call,compaction, andsubagentspans so child spans inherit the same grouping.- Regression tests for both hook fire orders + the no-
llm_outputpath + subagent ordering.plugin.test.tsnow exercises the cli-runner order (llm_outputbeforeagent_end), the selection.runtime order (agent_endbeforellm_output), the no-llm_outputpath (cli-runner skips it whenassistantText.length === 0), and a parent-spawning-subagent flow under the selection.runtime order. The selection-path tests fire both hooks in the same sync round via afireSameRoundhelper that mirrors how the real OpenClaw dispatcher kicks offrunAgentEnd(...).catch()andrunLlmOutput(...).catch()without anawaitbetween them.
Changed (build path)
SCOPE_VERSIONis baked at build time instead of read at runtime. 0.0.6 readpackage.jsonviareadFileSyncto populate the OTLPscope.versionandservice.versionattributes — that pairednode:fswithfetch(in the bundled plugin and tripped OpenClaw 2026.4.26'splugins.code_safetyscanner with a "potential-exfiltration: File read combined with network send" warning. The version is now substituted at bundle time via tsdown'sdefine(__SCOPE_VERSION__→ string literal ofpackage.json'sversion). Single source of truth (package.json) preserved, runtime bundle now has zeronode:fsimports, and the audit warning is gone.
Documentation
- README pins the install spec to an exact version. OpenClaw 2026.4.26's
openclaw security audit --deepwarns about unpinned plugin install specs for supply-chain stability. The README now usesopenclaw plugins install @latitude-data/openclaw-telemetry@0.0.7instead of the bare package name and notes the policy.