@latitude-data/openclaw-telemetry 0.0.8 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","names":["safeJson"],"sources":["../src/client.ts","../src/config.ts","../src/logger.ts","../src/otlp.ts","../src/messages.ts","../src/span-builder.ts","../src/plugin.ts"],"sourcesContent":["import type { Logger } from \"./logger.ts\"\nimport type { OtlpExportRequest } from \"./types.ts\"\n\nexport async function postTraces({\n baseUrl,\n apiKey,\n project,\n payload,\n logger,\n timeoutMs = 10_000,\n}: {\n baseUrl: string\n apiKey: string\n project: string\n payload: OtlpExportRequest\n logger: Logger\n timeoutMs?: number\n}): Promise<void> {\n const url = `${baseUrl.replace(/\\/+$/, \"\")}/v1/traces`\n const bodyText = JSON.stringify(payload)\n logger.debug(`POST ${url} (project=${project}, ${bodyText.length} bytes)`)\n\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n \"X-Latitude-Project\": project,\n },\n body: bodyText,\n signal: controller.signal,\n })\n if (!res.ok) {\n const text = await res.text().catch(() => \"\")\n logger.warn(`ingest HTTP ${res.status}: ${text.slice(0, 500)}`)\n } else {\n logger.debug(`ingest HTTP ${res.status}`)\n }\n } catch (err) {\n logger.warn(`ingest failed: ${String(err)}`)\n } finally {\n clearTimeout(timer)\n }\n}\n","export interface Config {\n apiKey: string\n baseUrl: string\n project: string\n enabled: boolean\n debug: boolean\n /**\n * When false, the plugin still emits one span per LLM call / tool / run, but\n * scrubs raw conversation content (input/output messages, system prompt,\n * tool args, tool results, the surfaced first-prompt). Token counts, model\n * names, agent ids, and timings are unaffected.\n */\n allowConversationAccess: boolean\n}\n\nconst DEFAULT_BASE_URL = \"https://ingest.latitude.so\"\n\n/**\n * Build a `Config` from OpenClaw's per-plugin config bucket. The plugin SDK\n * passes `api.pluginConfig` (the user's `plugins.entries[id].config` block)\n * to the registration function — that's the only source.\n *\n * Earlier 0.0.x versions also fell back to environment variables when keys\n * were missing from pluginConfig. That fallback is gone deliberately:\n * OpenClaw 2026.4.25's `openclaw plugins install` runs a static-analysis\n * security scan that flags any runtime source combining environment-variable\n * access with a network-send call (we have `fetch(` in postTraces). With\n * the fallback our bundled runtime tripped the scanner. The installer\n * writes credentials to `plugins.entries[id].config` anyway, so the\n * fallback was polish-not-feature — its removal also gives a cleaner\n * privacy story (the runtime can't pick up credentials the operator\n * didn't put in openclaw.json).\n *\n * For dev-time testing with debug logs, set `config.debug = true` in\n * openclaw.json directly.\n */\nexport function loadConfig(pluginConfig: Record<string, unknown> | undefined = undefined): Config {\n const fromOpts = pluginConfig ?? {}\n\n const apiKey = pickString(fromOpts.apiKey) ?? \"\"\n const project = pickString(fromOpts.project) ?? \"\"\n const baseUrl = pickString(fromOpts.baseUrl) ?? DEFAULT_BASE_URL\n\n const debug = pickBool(fromOpts.debug) ?? false\n const allowConversationAccess = pickBool(fromOpts.allowConversationAccess) ?? false\n\n const explicitlyDisabled = pickBool(fromOpts.enabled) === false\n const hasCreds = apiKey !== \"\" && project !== \"\"\n\n return {\n apiKey,\n baseUrl,\n project,\n debug,\n allowConversationAccess,\n enabled: hasCreds && !explicitlyDisabled,\n }\n}\n\nfunction pickString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined\n}\n\nfunction pickBool(value: unknown): boolean | undefined {\n return typeof value === \"boolean\" ? value : undefined\n}\n","const PREFIX = \"[latitude-openclaw]\"\n\nexport interface Logger {\n debug: (msg: string) => void\n warn: (msg: string) => void\n}\n\nexport function createLogger(debugEnabled: boolean): Logger {\n return {\n debug: debugEnabled ? (msg) => process.stderr.write(`${PREFIX} ${msg}\\n`) : () => {},\n warn: (msg) => process.stderr.write(`${PREFIX} ${msg}\\n`),\n }\n}\n","import { arch, hostname, platform, release } from \"node:os\"\nimport type { AttrValue, BuildResult, SpanRecord } from \"./span-builder.ts\"\nimport type { OtlpExportRequest, OtlpKeyValue, OtlpResourceSpans, OtlpSpan } from \"./types.ts\"\n\nconst SCOPE_NAME = \"@latitude-data/openclaw-telemetry\"\n\n/**\n * Build-time-baked package version.\n *\n * `__SCOPE_VERSION__` is replaced at bundle time by tsdown's `define` (see\n * `tsdown.config.ts`) with a string literal of `package.json`'s `version`,\n * so the released bundle ships a constant — no runtime file read.\n *\n * Earlier versions read `package.json` at runtime via `readFileSync` to keep\n * one source of truth for the version. That tripped OpenClaw 2026.4.26's\n * `plugins.code_safety` scanner with a \"potential-exfiltration: File read\n * combined with network send\" warning (we have `fetch(` in `client.ts`).\n * Build-time bake preserves the single source of truth (the build reads\n * `package.json` and inlines the value) while keeping the runtime free of\n * `node:fs`.\n *\n * The `typeof` check is a runtime fallback for environments where the\n * `define` substitution didn't run — chiefly vitest, which executes the\n * source files directly without going through the build. `typeof` of an\n * undeclared identifier returns `\"undefined\"` rather than throwing, which\n * keeps tests working.\n */\ndeclare const __SCOPE_VERSION__: string\nconst SCOPE_VERSION = typeof __SCOPE_VERSION__ === \"string\" ? __SCOPE_VERSION__ : \"0.0.0-dev\"\n\ninterface BuildOptions {\n /**\n * When false, attributes whose key ends in `:gated` are scrubbed from\n * spans before export — that's `gen_ai.input.messages`,\n * `gen_ai.output.messages`, `gen_ai.system_instructions`, `user_prompt`,\n * `gen_ai.tool.call.arguments`, `gen_ai.tool.call.result`,\n * `before_compaction.messages`, `before_agent_start.{prompt,messages}`,\n * `agent_end.messages`, and `openclaw.error.message` (the last because\n * error strings can leak prompt/response content). Timing, token usage,\n * model name, ids, agent name, durations, byte counts, and the\n * `latitude.captured.content` boolean are always emitted.\n */\n allowConversationAccess: boolean\n}\n\n/** Build an OTLP export request for a single completed agent run. */\nexport function buildOtlpRequest(result: BuildResult, options: BuildOptions): OtlpExportRequest {\n const spans = result.spans.map((span) => toOtlpSpan(span, options))\n const rs: OtlpResourceSpans = {\n resource: { attributes: resourceAttrs() },\n scopeSpans: [{ scope: { name: SCOPE_NAME, version: SCOPE_VERSION }, spans }],\n }\n return { resourceSpans: [rs] }\n}\n\n// ─── SpanRecord → OtlpSpan ─────────────────────────────────────────────────\n\nfunction toOtlpSpan(span: SpanRecord, options: BuildOptions): OtlpSpan {\n const startNs = msToNs(span.startMs)\n const endNs = msToNs(span.endMs ?? span.startMs)\n\n const attrs: OtlpKeyValue[] = []\n for (const [rawKey, value] of Object.entries(span.attrs)) {\n if (value === undefined || value === null) continue\n const isGated = rawKey.endsWith(\":gated\")\n if (isGated && !options.allowConversationAccess) continue\n const key = isGated ? rawKey.slice(0, -\":gated\".length) : rawKey\n const kv = encodeAttr(key, value)\n if (kv !== undefined) attrs.push(kv)\n }\n\n // Always emit the gate state so operators can see it in the UI without\n // needing to grep the original config.\n attrs.push(bool(\"latitude.captured.content\", options.allowConversationAccess))\n // Mirror duration into the canonical name as well, when present.\n if (span.endMs !== undefined) {\n attrs.push(int(\"openclaw.duration_ms.computed\", Math.max(0, span.endMs - span.startMs)))\n }\n\n const statusCode = span.outcome === \"error\" ? 2 : 1\n return {\n traceId: span.traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n // OTel SpanKind: 1 = INTERNAL. None of agent/model_call/tool_call/\n // compaction/subagent map cleanly to CLIENT/SERVER/PRODUCER/CONSUMER —\n // OpenClaw is the source-of-truth runtime for all of them.\n kind: 1,\n startTimeUnixNano: startNs,\n endTimeUnixNano: endNs,\n attributes: attrs,\n status: { code: statusCode },\n }\n}\n\nfunction encodeAttr(key: string, value: AttrValue): OtlpKeyValue | undefined {\n if (value === undefined || value === null) return undefined\n if (typeof value === \"string\") return str(key, value)\n if (typeof value === \"boolean\") return bool(key, value)\n if (typeof value === \"number\") {\n return Number.isInteger(value) ? int(key, value) : { key, value: { doubleValue: value } }\n }\n // Arrays + objects → JSON string. The Latitude UI parses the gen_ai.* keys\n // as JSON; anything else lands as opaque string and is queryable as a\n // contains-substring filter.\n return str(key, safeJson(value))\n}\n\n// ─── Resource + helper attribute encoders ──────────────────────────────────\n\nfunction resourceAttrs(): OtlpKeyValue[] {\n return [\n str(\"service.name\", \"openclaw\"),\n str(\"service.version\", SCOPE_VERSION),\n str(\"host.name\", hostname()),\n str(\"host.arch\", arch()),\n str(\"os.type\", platform()),\n str(\"os.version\", release()),\n ]\n}\n\nfunction str(key: string, value: string): OtlpKeyValue {\n return { key, value: { stringValue: value } }\n}\n\nfunction int(key: string, value: number): OtlpKeyValue {\n return { key, value: { intValue: String(Math.trunc(value)) } }\n}\n\nfunction bool(key: string, value: boolean): OtlpKeyValue {\n return { key, value: { boolValue: value } }\n}\n\nfunction msToNs(ms: number): string {\n return (BigInt(Math.trunc(ms)) * 1_000_000n).toString()\n}\n\nfunction safeJson(value: unknown): string {\n try {\n if (typeof value === \"string\") return value\n return JSON.stringify(value)\n } catch {\n return \"\"\n }\n}\n","/**\n * Normalizes provider-specific message shapes (Anthropic, OpenAI, pi-ai) into\n * the parts-based GenAI format Latitude's parser expects:\n *\n * { role: \"system\" | \"user\" | \"assistant\" | \"tool\", parts: MessagePart[] }\n *\n * Downstream consumers cast `gen_ai.input.messages` and `gen_ai.output.messages`\n * to `GenAIMessage[]` and read `message.parts` directly (e.g. for search\n * indexing). Without normalisation those casts produce objects without\n * `parts`, breaking rendering.\n *\n * The shapes we need to handle:\n *\n * - Anthropic: `{role, content: string}` or `{role, content: ContentBlock[]}`\n * with blocks `{type: \"text\", text}`, `{type: \"tool_use\", id, name, input}`,\n * `{type: \"tool_result\", tool_use_id, content}`, `{type: \"image\", source}`,\n * `{type: \"thinking\", thinking}`.\n * - OpenAI: `{role, content: string}` or with `tool_calls` field.\n * - pi-ai (OpenClaw's wrapper) — superset of the above.\n * - Already-normalized parts-shape messages — passed through unchanged.\n *\n * Anything we don't recognize falls through to a JSON-stringified text part\n * so nothing is silently dropped.\n */\n\nexport interface MessagePart {\n type: string\n content?: string\n // Tool call (assistant invokes a tool)\n id?: string\n name?: string\n arguments?: unknown\n // Tool response (tool replies)\n response?: unknown\n // Image / multimodal\n modality?: string\n uri?: string\n [key: string]: unknown\n}\n\nexport type MessageRole = \"system\" | \"user\" | \"assistant\" | \"tool\"\n\nexport interface Message {\n role: MessageRole\n parts: MessagePart[]\n}\n\nconst ALLOWED_ROLES: ReadonlySet<MessageRole> = new Set([\"system\", \"user\", \"assistant\", \"tool\"])\n\n/**\n * Normalize a single message of any of the provider shapes we know about.\n * Returns `undefined` for non-objects so the caller can skip them.\n */\nexport function normalizeMessage(raw: unknown): Message | undefined {\n if (!raw || typeof raw !== \"object\") return undefined\n const obj = raw as Record<string, unknown>\n const role = coerceRole(obj.role)\n\n // Pre-normalized: already has a parts array.\n if (Array.isArray(obj.parts)) {\n const parts: MessagePart[] = []\n for (const p of obj.parts) {\n if (p && typeof p === \"object\") parts.push(p as MessagePart)\n }\n return { role, parts: parts.length > 0 ? parts : [{ type: \"text\", content: safeJson(raw) }] }\n }\n\n const content = obj.content ?? obj.text ?? obj.message\n\n // OpenAI tool message: `{role: \"tool\", tool_call_id, content}` — handle\n // before the generic string-content branch so we emit a tool_call_response\n // part rather than a plain text part.\n if (role === \"tool\" && obj.tool_call_id !== undefined) {\n return {\n role,\n parts: [\n {\n type: \"tool_call_response\",\n id: typeof obj.tool_call_id === \"string\" ? obj.tool_call_id : \"\",\n response: content ?? safeJson(obj),\n },\n ],\n }\n }\n\n if (typeof content === \"string\") {\n const parts: MessagePart[] = [{ type: \"text\", content }]\n // OpenAI assistant messages may have tool_calls alongside string content.\n appendToolCalls(parts, obj.tool_calls)\n return { role, parts }\n }\n\n if (Array.isArray(content)) {\n const parts: MessagePart[] = []\n for (const block of content) {\n const part = normalizeBlock(block)\n if (part) parts.push(part)\n }\n appendToolCalls(parts, obj.tool_calls)\n if (parts.length === 0) parts.push({ type: \"text\", content: safeJson(content) })\n return { role, parts }\n }\n\n // Unknown shape — dump as JSON so nothing is silently dropped.\n return { role, parts: [{ type: \"text\", content: safeJson(raw) }] }\n}\n\n/** Normalize an array of provider messages. */\nexport function normalizeMessages(raw: unknown[]): Message[] {\n const out: Message[] = []\n for (const m of raw) {\n const norm = normalizeMessage(m)\n if (norm) out.push(norm)\n }\n return out\n}\n\n/** Build a single user message from a string prompt. */\nexport function userMessageFromPrompt(prompt: string): Message {\n return { role: \"user\", parts: [{ type: \"text\", content: prompt }] }\n}\n\n/** Build a single assistant message from `assistantTexts` + `lastAssistant` fallback. */\nexport function assistantMessageFromOutput(assistantTexts: string[], lastAssistant: unknown): Message {\n if (lastAssistant !== undefined) {\n const norm = normalizeMessage(lastAssistant)\n if (norm) return { ...norm, role: \"assistant\" }\n }\n const parts: MessagePart[] = []\n for (const text of assistantTexts) {\n if (text.length > 0) parts.push({ type: \"text\", content: text })\n }\n if (parts.length === 0) parts.push({ type: \"text\", content: \"\" })\n return { role: \"assistant\", parts }\n}\n\n/**\n * Wrap a system prompt string into the parts-array shape expected for\n * `gen_ai.system_instructions`. Empty string in → single empty text part out\n * (still a valid array, never `undefined`).\n */\nexport function systemInstructionsParts(prompt: string): MessagePart[] {\n return [{ type: \"text\", content: prompt }]\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nfunction coerceRole(raw: unknown): MessageRole {\n if (typeof raw !== \"string\") return \"user\"\n return ALLOWED_ROLES.has(raw as MessageRole) ? (raw as MessageRole) : \"user\"\n}\n\nfunction normalizeBlock(raw: unknown): MessagePart | undefined {\n if (typeof raw === \"string\") return { type: \"text\", content: raw }\n if (!raw || typeof raw !== \"object\") return undefined\n const obj = raw as Record<string, unknown>\n\n // Already a part.\n if (typeof obj.type === \"string\" && (typeof obj.content === \"string\" || obj.content === undefined)) {\n // If it carries our recognized shape (text / tool_call / tool_call_response /\n // uri), pass through. Otherwise fall through to type-specific normalization.\n if (obj.type === \"text\" && typeof obj.content === \"string\") {\n return { type: \"text\", content: obj.content }\n }\n }\n\n const type = typeof obj.type === \"string\" ? obj.type : \"text\"\n\n if (type === \"text\" && typeof obj.text === \"string\") {\n return { type: \"text\", content: obj.text }\n }\n if (type === \"tool_use\") {\n return {\n type: \"tool_call\",\n id: typeof obj.id === \"string\" ? obj.id : \"\",\n name: typeof obj.name === \"string\" ? obj.name : \"\",\n arguments: obj.input ?? {},\n }\n }\n if (type === \"tool_call\") {\n // Already-normalized tool_call part — pass through.\n return {\n type: \"tool_call\",\n id: typeof obj.id === \"string\" ? obj.id : \"\",\n name: typeof obj.name === \"string\" ? obj.name : \"\",\n arguments: obj.arguments ?? obj.input ?? {},\n }\n }\n if (type === \"tool_result\") {\n return {\n type: \"tool_call_response\",\n id: typeof obj.tool_use_id === \"string\" ? obj.tool_use_id : \"\",\n response: obj.content ?? \"\",\n }\n }\n if (type === \"tool_call_response\") {\n return {\n type: \"tool_call_response\",\n id: typeof obj.id === \"string\" ? obj.id : \"\",\n response: obj.response ?? \"\",\n }\n }\n if (type === \"thinking\" && typeof obj.thinking === \"string\") {\n return { type: \"reasoning\", content: obj.thinking }\n }\n if (type === \"reasoning\" && typeof obj.content === \"string\") {\n return { type: \"reasoning\", content: obj.content }\n }\n if (type === \"image\" && obj.source && typeof obj.source === \"object\") {\n const src = obj.source as { media_type?: string; data?: string; url?: string }\n const uri = src.url ?? (src.data ? `data:${src.media_type ?? \"image/unknown\"};base64,${src.data}` : \"\")\n if (uri) return { type: \"uri\", modality: \"image\", uri }\n }\n\n // Unknown block type — stringify so nothing is silently dropped.\n return { type, content: safeJson(raw) }\n}\n\n/**\n * OpenAI assistant messages put tool calls in a separate `tool_calls` array\n * alongside string content. Append them as parts so the trace shows what the\n * model emitted in that turn.\n */\nfunction appendToolCalls(parts: MessagePart[], raw: unknown): void {\n if (!Array.isArray(raw)) return\n for (const tc of raw) {\n if (!tc || typeof tc !== \"object\") continue\n const t = tc as Record<string, unknown>\n const fn = t.function as { name?: string; arguments?: string | Record<string, unknown> } | undefined\n let parsedArgs: unknown = fn?.arguments\n if (typeof parsedArgs === \"string\") {\n try {\n parsedArgs = JSON.parse(parsedArgs)\n } catch {\n // leave as string\n }\n }\n parts.push({\n type: \"tool_call\",\n id: typeof t.id === \"string\" ? t.id : \"\",\n name: fn?.name ?? \"\",\n arguments: parsedArgs ?? {},\n })\n }\n}\n\nfunction safeJson(value: unknown): string {\n try {\n if (typeof value === \"string\") return value\n return JSON.stringify(value)\n } catch {\n return \"\"\n }\n}\n","import { createHash, randomUUID } from \"node:crypto\"\nimport {\n assistantMessageFromOutput,\n type Message,\n normalizeMessages,\n systemInstructionsParts,\n userMessageFromPrompt,\n} from \"./messages.ts\"\nimport type {\n OpenClawAfterCompactionEvent,\n OpenClawAfterToolCallEvent,\n OpenClawAgentContext,\n OpenClawAgentEndEvent,\n OpenClawBeforeAgentStartEvent,\n OpenClawBeforeCompactionEvent,\n OpenClawBeforeToolCallEvent,\n OpenClawLlmInputEvent,\n OpenClawLlmOutputEvent,\n OpenClawLlmUsage,\n OpenClawModelCallEndedEvent,\n OpenClawModelCallStartedEvent,\n OpenClawSubagentEndedEvent,\n OpenClawSubagentSpawnedEvent,\n} from \"./types.ts\"\n\n/**\n * Builds the per-trace span tree for an OpenClaw agent run from the granular\n * paired hooks. Replaces the older `turn-builder.ts` model that collapsed the\n * whole attempt into a single `llm_request` span — that shape was wrong on\n * two counts: `llm_input` / `llm_output` fire ONCE per attempt (not per\n * generation), and an attempt is a sequence of generations interleaved with\n * tool executions.\n *\n * Span set this builder produces:\n *\n * agent (root)\n * ├─ compaction (0..1, rare)\n * ├─ model_call (1..N, one per provider API call)\n * ├─ tool_call: ... (interleaved between model_calls; siblings of agent)\n * ├─ subagent (0..N; child agent runs nest INSIDE these via\n * │ └─ agent ... cross-runId trace propagation)\n * └─ model_call (final)\n *\n * Tool spans are siblings of `agent`, not children of `model_call`, because\n * tools run BETWEEN generations — not during them. Nesting under model_call\n * would falsely imply concurrency.\n *\n * `llm_input` / `llm_output` are NOT span boundaries here. They're data-only\n * feeds that enrich the parent `agent` span (full message history, output\n * messages, aggregate token usage).\n */\n\n// ─── Span record shapes ─────────────────────────────────────────────────────\n\nexport interface SpanRecord {\n /** Stable id for the span (16 hex chars). */\n spanId: string\n /** Span tree id (32 hex chars). */\n traceId: string\n /** Empty string for root agent spans, parent's spanId otherwise. */\n parentSpanId: string\n /** OpenClaw event noun (`agent` / `model_call` / `tool_call` / `compaction` / `subagent`). */\n name: string\n startMs: number\n endMs: number | undefined\n /** Free-form attribute bag — flattened to OTLP key/value at emit time. */\n attrs: Record<string, AttrValue>\n /** Status — set at close from the event payload's outcome/error. */\n outcome?: \"ok\" | \"error\"\n errorMessage?: string | undefined\n}\n\nexport type AttrValue = string | number | boolean | unknown[] | Record<string, unknown> | undefined\n\n// One entry per simple `prefix.field` attribute the builder records on a span.\ntype AttrInput = Record<string, AttrValue>\n\n// ─── Per-run state ──────────────────────────────────────────────────────────\n\ninterface RunState {\n /** Trace root span (the `agent`). */\n agent: SpanRecord\n /**\n * Working snapshot of conversation history in the parts-based GenAI shape\n * Latitude's parser expects. Provider-specific shapes from `llm_input` get\n * normalized once on entry; tool_call / tool_call_response parts appended\n * during the run are already in the right shape.\n */\n history: Message[]\n /** Open per-call spans, keyed on the OpenClaw `callId` from `model_call_started`. */\n openModelCalls: Map<string, SpanRecord>\n /** Open tool spans, keyed on `toolCallId`. */\n openToolCalls: Map<string, SpanRecord>\n /** Open compaction span (at most one in flight). */\n openCompaction: SpanRecord | undefined\n /** All closed spans for this run, ready to emit on agent_end. */\n closed: SpanRecord[]\n /** Any subagent spans we OPENED inside this run, keyed by child runId so we\n * can close them when the child's `subagent_ended` arrives. */\n childSubagentSpans: Map<string, SpanRecord>\n}\n\n/**\n * When a parent's `subagent_spawned` fires we register a link from the\n * child's runId → the parent's traceId + the subagent span's id. Then when the\n * child's `before_agent_start` fires, we use those values so the child's\n * entire span subtree lands inside the parent's trace. Outlives the parent's\n * RunState because the child's `agent_end` may arrive after the parent's.\n *\n * `createdAt` is used by the `evictStaleSubagentLinks` sweep to drop entries\n * whose child runs never reached `agent_end` (gateway crash mid-spawn,\n * plugin reload, etc.). Without the sweep the map grows unbounded over the\n * lifetime of a long-running OpenClaw process.\n */\ninterface SubagentLink {\n traceId: string\n /** Span id of the parent's `subagent` span — used as parentSpanId for the child's root. */\n subagentSpanId: string\n createdAt: number\n}\n\nconst SUBAGENT_LINK_TTL_MS = 60 * 60 * 1000 // 1 hour\nconst SUBAGENT_LINK_MAX = 1000\n\nexport interface BuildResult {\n /** Run id this batch belongs to. */\n runId: string\n /** All spans ready to be exported (agent + everything beneath it). */\n spans: SpanRecord[]\n}\n\n// ─── Builder ────────────────────────────────────────────────────────────────\n\nexport class SpanBuilder {\n private readonly runs = new Map<string, RunState>()\n private readonly subagentLinks = new Map<string, SubagentLink>()\n\n inflightCount(): number {\n return this.runs.size\n }\n\n /**\n * Open the root `agent` span. If the runId was previously registered as a\n * subagent's child, propagate the parent's traceId and parent the new span\n * under the parent's `subagent` span — so the entire subagent's work nests\n * inside the parent's trace as one waterfall.\n */\n onBeforeAgentStart(evt: OpenClawBeforeAgentStartEvent, ctx: OpenClawAgentContext): void {\n const runId = ctx.runId\n if (!runId) return\n if (this.runs.has(runId)) return // defensive — already open\n\n const link = this.subagentLinks.get(runId)\n const traceId = link?.traceId ?? hashHex(runId, 32)\n const parentSpanId = link?.subagentSpanId ?? \"\"\n\n const agent: SpanRecord = {\n spanId: hashHex(`${traceId}:${runId}:agent`, 16),\n traceId,\n parentSpanId,\n name: \"agent\",\n startMs: Date.now(),\n endMs: undefined,\n attrs: {\n ...flattenCtx(ctx),\n ...latitudeAttrs(ctx),\n ...sessionAttrs(ctx),\n \"openclaw.run.id\": runId,\n // before_agent_start payload — gated content fields go via `gated.*`\n // attribute keys so the OTLP layer can scrub them without a parallel\n // boolean check. Messages get normalized to parts-shape; `prompt` is\n // a plain string (for the user-prompt convenience attribute).\n \"before_agent_start.prompt:gated\": evt.prompt,\n \"before_agent_start.messages:gated\": evt.messages ? normalizeMessages(evt.messages) : undefined,\n },\n }\n\n this.runs.set(runId, {\n agent,\n history: [],\n openModelCalls: new Map(),\n openToolCalls: new Map(),\n openCompaction: undefined,\n closed: [],\n childSubagentSpans: new Map(),\n })\n }\n\n /**\n * Enrich the open `agent` span with content + identity from the LLM input.\n * Also seeds the rolling history snapshot used by per-call `model_call`\n * input attributes.\n *\n * Provider-specific message shapes get normalized into the parts-based\n * GenAI format here — that's the contract Latitude's downstream parser\n * expects on `gen_ai.input.messages` and `gen_ai.system_instructions`.\n */\n onLlmInput(evt: OpenClawLlmInputEvent, ctx: OpenClawAgentContext): void {\n const run = this.runs.get(ctx.runId ?? evt.runId)\n if (!run) return\n\n const normalizedHistory = normalizeMessages(evt.historyMessages)\n const inputMessages: Message[] = [...normalizedHistory]\n if (evt.prompt) inputMessages.push(userMessageFromPrompt(evt.prompt))\n\n Object.assign(run.agent.attrs, {\n \"gen_ai.system_instructions:gated\": evt.systemPrompt ? systemInstructionsParts(evt.systemPrompt) : undefined,\n \"user_prompt:gated\": evt.prompt,\n \"gen_ai.input.messages:gated\": inputMessages,\n \"openclaw.images.count\": evt.imagesCount,\n \"gen_ai.request.model\": evt.model,\n \"gen_ai.system\": evt.provider,\n \"openclaw.provider\": evt.provider,\n })\n // Seed the rolling history with the normalized form. The per-call\n // model_call_started will copy the snapshot at the time it fires;\n // subsequent before_tool_call / after_tool_call events append to the\n // same array (already in parts shape) so the next model_call captures\n // the post-tool state.\n run.history = inputMessages\n }\n\n /**\n * Enrich the agent span with attempt-aggregate output + token usage.\n * (Per-call usage isn't surfaced by OpenClaw today — see PR #2986.)\n */\n onLlmOutput(evt: OpenClawLlmOutputEvent, ctx: OpenClawAgentContext): void {\n const run = this.runs.get(ctx.runId ?? evt.runId)\n if (!run) return\n const assistantMessage = assistantMessageFromOutput(evt.assistantTexts, evt.lastAssistant)\n Object.assign(run.agent.attrs, {\n \"gen_ai.output.messages:gated\": [assistantMessage],\n \"openclaw.resolved.ref\": evt.resolvedRef,\n \"openclaw.harness.id\": evt.harnessId,\n \"gen_ai.response.model\": evt.model,\n ...usageAttrs(evt.usage),\n })\n }\n\n onModelCallStarted(evt: OpenClawModelCallStartedEvent, ctx: OpenClawAgentContext): void {\n const run = this.runs.get(evt.runId)\n if (!run) return\n const span: SpanRecord = {\n spanId: hashHex(`${run.agent.traceId}:model_call:${evt.callId}`, 16),\n traceId: run.agent.traceId,\n parentSpanId: run.agent.spanId,\n name: \"model_call\",\n startMs: Date.now(),\n endMs: undefined,\n attrs: {\n ...latitudeAttrs(ctx),\n ...sessionAttrs(ctx),\n \"openclaw.run.id\": evt.runId,\n \"openclaw.call.id\": evt.callId,\n \"gen_ai.system\": evt.provider,\n \"openclaw.provider\": evt.provider,\n \"gen_ai.request.model\": evt.model,\n \"openclaw.api\": evt.api,\n \"openclaw.transport\": evt.transport,\n // Snapshot the rolling history at the moment this generation starts.\n // The model saw exactly this state. Gated.\n \"gen_ai.input.messages:gated\": [...run.history],\n },\n }\n run.openModelCalls.set(evt.callId, span)\n }\n\n onModelCallEnded(evt: OpenClawModelCallEndedEvent, _ctx: OpenClawAgentContext): void {\n const run = this.runs.get(evt.runId)\n if (!run) return\n const span = run.openModelCalls.get(evt.callId)\n if (!span) return\n span.endMs = Date.now()\n span.outcome = evt.outcome === \"completed\" ? \"ok\" : \"error\"\n span.errorMessage = evt.errorCategory\n Object.assign(span.attrs, {\n \"openclaw.duration_ms\": evt.durationMs,\n \"openclaw.outcome\": evt.outcome,\n \"openclaw.error.category\": evt.errorCategory,\n \"openclaw.failure.kind\": evt.failureKind,\n \"openclaw.request.payload_bytes\": evt.requestPayloadBytes,\n \"openclaw.response.stream_bytes\": evt.responseStreamBytes,\n \"openclaw.ttfb_ms\": evt.timeToFirstByteMs,\n \"openclaw.upstream.request_id_hash\": evt.upstreamRequestIdHash,\n })\n run.openModelCalls.delete(evt.callId)\n run.closed.push(span)\n }\n\n /**\n * Open a `tool_call` span as a sibling of the agent span. Also append a\n * synthetic assistant `tool_call` part to the rolling history so the NEXT\n * model_call's input snapshot reflects what the model emitted.\n *\n * IMPORTANT: this runs as a `runModifyingHook` in OpenClaw — returning\n * anything other than `undefined`/falsy from this handler blocks the tool.\n * The plugin-side handler enforces a void return; this method's signature\n * already returns `void`.\n */\n onBeforeToolCall(evt: OpenClawBeforeToolCallEvent, ctx: OpenClawAgentContext): void {\n if (!evt.runId) return\n const run = this.runs.get(evt.runId)\n if (!run) return\n\n const toolCallId = evt.toolCallId ?? `${evt.toolName}:${randomUUID()}`\n const span: SpanRecord = {\n spanId: hashHex(`${run.agent.traceId}:tool_call:${toolCallId}`, 16),\n traceId: run.agent.traceId,\n parentSpanId: run.agent.spanId,\n name: `tool_call:${evt.toolName}`,\n startMs: Date.now(),\n endMs: undefined,\n attrs: {\n ...latitudeAttrs(ctx),\n ...sessionAttrs(ctx),\n \"openclaw.run.id\": evt.runId,\n \"gen_ai.tool.name\": evt.toolName,\n \"gen_ai.tool.call.id\": toolCallId,\n \"gen_ai.tool.call.arguments:gated\": evt.params,\n },\n }\n run.openToolCalls.set(toolCallId, span)\n\n // Append an assistant tool_call part to the rolling history so the next\n // model_call captures it.\n run.history.push({\n role: \"assistant\",\n parts: [{ type: \"tool_call\", id: toolCallId, name: evt.toolName, arguments: evt.params }],\n })\n }\n\n onAfterToolCall(evt: OpenClawAfterToolCallEvent, _ctx: OpenClawAgentContext): void {\n if (!evt.runId) return\n const run = this.runs.get(evt.runId)\n if (!run) return\n\n // Match priority:\n // 1. Direct id lookup — the happy path.\n // 2. Name-match fallback — if `evt.toolCallId` is missing OR refers to\n // an id we didn't open (e.g. before_tool_call elided it and we\n // synthesised one, then after_tool_call provided the real one).\n //\n // Without the id-mismatch fallback, the open span would never close\n // and would get force-closed as `abandoned` at agent_end.\n let resolvedId: string | undefined =\n evt.toolCallId && run.openToolCalls.has(evt.toolCallId) ? evt.toolCallId : undefined\n if (!resolvedId) resolvedId = this.findOpenToolCallByName(run, evt.toolName)\n if (!resolvedId) return\n const span = run.openToolCalls.get(resolvedId)\n if (!span) return\n const toolCallId: string = resolvedId\n\n span.endMs = Date.now()\n const isError = Boolean(evt.error)\n span.outcome = isError ? \"error\" : \"ok\"\n span.errorMessage = evt.error\n Object.assign(span.attrs, {\n \"gen_ai.tool.call.result:gated\": evt.result,\n \"openclaw.error.message:gated\": evt.error,\n \"openclaw.duration_ms\": evt.durationMs,\n })\n run.openToolCalls.delete(toolCallId)\n run.closed.push(span)\n\n // Append the tool response to the rolling history so the next\n // model_call's input snapshot includes it.\n run.history.push({\n role: \"tool\",\n parts: [{ type: \"tool_call_response\", id: toolCallId, response: evt.result ?? evt.error ?? \"\" }],\n })\n }\n\n onBeforeCompaction(evt: OpenClawBeforeCompactionEvent, ctx: OpenClawAgentContext): void {\n const runId = ctx.runId\n if (!runId) return\n const run = this.runs.get(runId)\n if (!run) return\n const span: SpanRecord = {\n spanId: hashHex(`${run.agent.traceId}:compaction:${run.closed.length}`, 16),\n traceId: run.agent.traceId,\n parentSpanId: run.agent.spanId,\n name: \"compaction\",\n startMs: Date.now(),\n endMs: undefined,\n attrs: {\n ...latitudeAttrs(ctx),\n ...sessionAttrs(ctx),\n \"openclaw.run.id\": runId,\n \"openclaw.compaction.message_count.before\": evt.messageCount,\n \"openclaw.compaction.session_file\": evt.sessionFile,\n \"before_compaction.messages:gated\": evt.messages ? normalizeMessages(evt.messages) : undefined,\n },\n }\n run.openCompaction = span\n }\n\n onAfterCompaction(evt: OpenClawAfterCompactionEvent, ctx: OpenClawAgentContext): void {\n const runId = ctx.runId\n if (!runId) return\n const run = this.runs.get(runId)\n if (!run?.openCompaction) return\n const span = run.openCompaction\n span.endMs = Date.now()\n span.outcome = \"ok\"\n Object.assign(span.attrs, {\n \"openclaw.compaction.message_count.after\": evt.messageCount,\n \"openclaw.compaction.compacted_count\": evt.compactedCount,\n \"openclaw.compaction.token_count\": evt.tokenCount,\n })\n run.openCompaction = undefined\n run.closed.push(span)\n }\n\n /**\n * Open a `subagent` span on the parent run AND register the cross-run link\n * so the child's `before_agent_start` can find us.\n */\n onSubagentSpawned(evt: OpenClawSubagentSpawnedEvent, ctx: OpenClawAgentContext): void {\n const parentRunId = ctx.runId\n if (!parentRunId) return\n const parent = this.runs.get(parentRunId)\n if (!parent) return\n\n const span: SpanRecord = {\n spanId: hashHex(`${parent.agent.traceId}:subagent:${evt.runId}`, 16),\n traceId: parent.agent.traceId,\n parentSpanId: parent.agent.spanId,\n name: \"subagent\",\n startMs: Date.now(),\n endMs: undefined,\n attrs: {\n // The subagent span lives inside the parent's trace — tags +\n // metadata reflect the parent's ctx (which agent/channel/trigger\n // is doing the spawning), not the child's. The child's `agent` span\n // (opened later by the child run's before_agent_start) carries\n // its OWN ctx.\n ...latitudeAttrs(ctx),\n ...sessionAttrs(ctx),\n \"openclaw.parent.run.id\": parentRunId,\n \"openclaw.run.id\": evt.runId,\n \"openclaw.subagent.child_session_key\": evt.childSessionKey,\n \"openclaw.subagent.agent_id\": evt.agentId,\n \"openclaw.subagent.label\": evt.label,\n \"openclaw.subagent.mode\": evt.mode,\n \"openclaw.subagent.thread_requested\": evt.threadRequested,\n \"openclaw.subagent.requester.channel\": evt.requester?.channel,\n \"openclaw.subagent.requester.account_id\": evt.requester?.accountId,\n \"openclaw.subagent.requester.to\": evt.requester?.to,\n \"openclaw.subagent.requester.thread_id\":\n typeof evt.requester?.threadId === \"string\" || typeof evt.requester?.threadId === \"number\"\n ? String(evt.requester.threadId)\n : undefined,\n },\n }\n parent.childSubagentSpans.set(evt.runId, span)\n this.evictStaleSubagentLinks()\n this.subagentLinks.set(evt.runId, {\n traceId: parent.agent.traceId,\n subagentSpanId: span.spanId,\n createdAt: Date.now(),\n })\n }\n\n onSubagentEnded(evt: OpenClawSubagentEndedEvent, ctx: OpenClawAgentContext): void {\n const parentRunId = ctx.runId\n if (!parentRunId) return\n const parent = this.runs.get(parentRunId)\n if (!parent) return\n const childRunId = evt.runId\n if (!childRunId) return\n const span = parent.childSubagentSpans.get(childRunId)\n if (!span) return\n\n span.endMs = Date.now()\n const isError = evt.outcome === \"error\" || Boolean(evt.error)\n span.outcome = isError ? \"error\" : \"ok\"\n span.errorMessage = evt.error\n Object.assign(span.attrs, {\n \"openclaw.subagent.target_session_key\": evt.targetSessionKey,\n \"openclaw.subagent.target_kind\": evt.targetKind,\n \"openclaw.subagent.reason\": evt.reason,\n \"openclaw.subagent.outcome\": evt.outcome,\n \"openclaw.subagent.send_farewell\": evt.sendFarewell,\n \"openclaw.subagent.account_id\": evt.accountId,\n })\n parent.childSubagentSpans.delete(childRunId)\n parent.closed.push(span)\n // Don't delete the subagent link yet — the child's `agent_end` may still\n // be in flight. We clean it up when the child's agent_end fires.\n }\n\n /**\n * Close out the run: finish the agent span, abandon any still-open\n * model_calls / tool_calls / compactions, and return everything ready to\n * emit. Removes the subagent link if this was a child run.\n */\n onAgentEnd(evt: OpenClawAgentEndEvent, ctx: OpenClawAgentContext): BuildResult | undefined {\n const runId = ctx.runId\n if (!runId) return undefined\n const run = this.runs.get(runId)\n if (!run) {\n // Child agent run that closed without ever opening — drop the link\n // entry so the map doesn't grow unbounded.\n this.subagentLinks.delete(runId)\n return undefined\n }\n\n const now = Date.now()\n run.agent.endMs = now\n run.agent.outcome = evt.success ? \"ok\" : \"error\"\n run.agent.errorMessage = evt.error\n Object.assign(run.agent.attrs, {\n \"openclaw.duration_ms\": evt.durationMs,\n \"openclaw.run.success\": evt.success,\n \"openclaw.error.message:gated\": evt.error,\n \"agent_end.messages:gated\": normalizeMessages(evt.messages),\n })\n\n // Anything still open at agent_end didn't get a proper close event.\n // Mark them abandoned and force-close so they show up in the trace\n // rather than vanish silently.\n for (const span of run.openModelCalls.values()) {\n span.endMs = now\n span.outcome = \"error\"\n span.attrs[\"openclaw.outcome\"] = \"abandoned\"\n run.closed.push(span)\n }\n for (const span of run.openToolCalls.values()) {\n span.endMs = now\n span.outcome = \"error\"\n span.attrs[\"openclaw.outcome\"] = \"abandoned\"\n run.closed.push(span)\n }\n if (run.openCompaction) {\n run.openCompaction.endMs = now\n run.openCompaction.outcome = \"error\"\n run.openCompaction.attrs[\"openclaw.outcome\"] = \"abandoned\"\n run.closed.push(run.openCompaction)\n }\n for (const span of run.childSubagentSpans.values()) {\n span.endMs = now\n span.outcome = \"error\"\n span.attrs[\"openclaw.subagent.outcome\"] = \"abandoned\"\n run.closed.push(span)\n }\n\n const spans = [run.agent, ...run.closed]\n this.runs.delete(runId)\n this.subagentLinks.delete(runId)\n return { runId, spans }\n }\n\n /** Drop a run without emitting — used on errors from the emit path. */\n abandon(runId: string): void {\n this.runs.delete(runId)\n this.subagentLinks.delete(runId)\n }\n\n /** Test-only: how many cross-run subagent links we're holding. */\n subagentLinkCount(): number {\n return this.subagentLinks.size\n }\n\n /**\n * Drop any subagent links whose child run never reached `agent_end`. Called\n * before every `subagent_spawned` insert so the map stays bounded even when\n * children crash mid-spawn or the plugin reloads.\n *\n * Two passes: TTL eviction (anything older than `SUBAGENT_LINK_TTL_MS`),\n * then a hard size cap (when we're past `SUBAGENT_LINK_MAX`, drop the\n * oldest until we're under).\n */\n private evictStaleSubagentLinks(): void {\n const now = Date.now()\n for (const [runId, link] of this.subagentLinks) {\n if (now - link.createdAt > SUBAGENT_LINK_TTL_MS) {\n this.subagentLinks.delete(runId)\n }\n }\n if (this.subagentLinks.size <= SUBAGENT_LINK_MAX) return\n const sorted = Array.from(this.subagentLinks.entries()).sort((a, b) => a[1].createdAt - b[1].createdAt)\n const toRemove = this.subagentLinks.size - SUBAGENT_LINK_MAX\n for (let i = 0; i < toRemove; i++) {\n const entry = sorted[i]\n if (entry) this.subagentLinks.delete(entry[0])\n }\n }\n\n private findOpenToolCallByName(run: RunState, toolName: string): string | undefined {\n // Defensive: OpenClaw versions that elide toolCallId on after_tool_call\n // can be matched by name + still-open status. When multiple in-flight\n // tool calls share a name, prefer the MOST RECENTLY opened — Maps\n // preserve insertion order, so iterating in reverse picks the latest.\n // (LIFO matches typical agent runtimes that issue tools sequentially.)\n const target = `tool_call:${toolName}`\n const entries = Array.from(run.openToolCalls.entries())\n for (let i = entries.length - 1; i >= 0; i--) {\n const entry = entries[i]\n if (!entry) continue\n const [id, span] = entry\n if (span.name === target) return id\n }\n return undefined\n }\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nfunction flattenCtx(ctx: OpenClawAgentContext): AttrInput {\n return {\n \"openclaw.run.id\": ctx.runId,\n \"openclaw.session.id\": ctx.sessionId,\n \"openclaw.session.key\": ctx.sessionKey,\n \"openclaw.agent.id\": ctx.agentId,\n \"openclaw.agent.name\": ctx.agentId,\n \"openclaw.workspace.dir\": ctx.workspaceDir,\n \"openclaw.message.provider\": ctx.messageProvider,\n \"openclaw.trigger\": ctx.trigger,\n \"openclaw.channel.id\": ctx.channelId,\n \"openclaw.cron.job.id\": ctx.jobId,\n \"openclaw.model.provider.id\": ctx.modelProviderId,\n \"openclaw.model.id\": ctx.modelId,\n }\n}\n\n/**\n * Mirror OpenClaw's session id onto the OTEL-standard keys Latitude's\n * resolver looks for. `gen_ai.session.id` and `session.id` are both in\n * `sessionIdCandidates` (domain/spans/src/otlp/resolvers/identity.ts), so\n * traces can be grouped by session in the Latitude UI without an\n * openclaw-specific code path. Emitted on every span, not just `agent`,\n * so child spans (model_call / tool_call / etc.) inherit the same grouping.\n */\nfunction sessionAttrs(ctx: OpenClawAgentContext): AttrInput {\n if (!ctx.sessionId) return {}\n return {\n \"session.id\": ctx.sessionId,\n \"gen_ai.session.id\": ctx.sessionId,\n }\n}\n\n/**\n * Build `latitude.tags` and `latitude.metadata` attrs from the hook context.\n * The OTLP encoder JSON-stringifies arrays/objects, which is the encoding\n * Latitude's resolver expects:\n *\n * - `latitude.tags` is a JSON-encoded string array (`fromJsonStringArray`\n * in domain/spans/src/otlp/resolvers/enrichment.ts).\n * - `latitude.metadata` is a JSON-encoded string object (`fromJsonString`).\n *\n * Tags = the agent id, the channel id, and the trigger. When trigger is\n * `cron`, the tag becomes `cron:<jobId>` so dashboards can pivot on the\n * specific cron job. Each tag is conditionally included so absent ctx\n * fields don't produce empty entries.\n *\n * Metadata = every ctx field that's set, namespaced under `openclaw.*` so\n * it can't collide with metadata keys other plugins might emit.\n */\nfunction latitudeAttrs(ctx: OpenClawAgentContext): AttrInput {\n const tags: string[] = []\n if (ctx.agentId) tags.push(ctx.agentId)\n if (ctx.channelId) tags.push(ctx.channelId)\n if (ctx.trigger) {\n tags.push(ctx.trigger === \"cron\" && ctx.jobId ? `cron:${ctx.jobId}` : ctx.trigger)\n }\n\n const metadata: Record<string, string> = {}\n if (ctx.runId) metadata[\"openclaw.run.id\"] = ctx.runId\n if (ctx.sessionId) metadata[\"openclaw.session.id\"] = ctx.sessionId\n if (ctx.sessionKey) metadata[\"openclaw.session.key\"] = ctx.sessionKey\n if (ctx.agentId) metadata[\"openclaw.agent.id\"] = ctx.agentId\n if (ctx.workspaceDir) metadata[\"openclaw.workspace.dir\"] = ctx.workspaceDir\n if (ctx.channelId) metadata[\"openclaw.channel.id\"] = ctx.channelId\n if (ctx.messageProvider) metadata[\"openclaw.message.provider\"] = ctx.messageProvider\n if (ctx.trigger) metadata[\"openclaw.trigger\"] = ctx.trigger\n if (ctx.jobId) metadata[\"openclaw.cron.job.id\"] = ctx.jobId\n if (ctx.modelProviderId) metadata[\"openclaw.model.provider.id\"] = ctx.modelProviderId\n if (ctx.modelId) metadata[\"openclaw.model.id\"] = ctx.modelId\n\n return {\n \"latitude.tags\": tags.length > 0 ? tags : undefined,\n \"latitude.metadata\": Object.keys(metadata).length > 0 ? metadata : undefined,\n }\n}\n\nfunction usageAttrs(usage: OpenClawLlmUsage | undefined): AttrInput {\n if (!usage) return {}\n return {\n \"gen_ai.usage.input_tokens\": usage.input,\n \"gen_ai.usage.output_tokens\": usage.output,\n \"gen_ai.usage.cache_read_input_tokens\": usage.cacheRead,\n \"gen_ai.usage.cache_creation_input_tokens\": usage.cacheWrite,\n \"gen_ai.usage.total_tokens\": usage.total,\n }\n}\n\nfunction hashHex(input: string, length: number): string {\n return createHash(\"sha256\").update(input).digest(\"hex\").slice(0, length)\n}\n","import { postTraces } from \"./client.ts\"\nimport { type Config, loadConfig } from \"./config.ts\"\nimport { createLogger, type Logger } from \"./logger.ts\"\nimport { buildOtlpRequest } from \"./otlp.ts\"\nimport { type BuildResult, SpanBuilder } from \"./span-builder.ts\"\nimport type {\n OpenClawAfterCompactionEvent,\n OpenClawAfterToolCallEvent,\n OpenClawAgentContext,\n OpenClawAgentEndEvent,\n OpenClawBeforeAgentStartEvent,\n OpenClawBeforeCompactionEvent,\n OpenClawBeforeToolCallEvent,\n OpenClawLlmInputEvent,\n OpenClawLlmOutputEvent,\n OpenClawModelCallEndedEvent,\n OpenClawModelCallStartedEvent,\n OpenClawSubagentEndedEvent,\n OpenClawSubagentSpawnedEvent,\n} from \"./types.ts\"\n\n/**\n * Minimal structural type for OpenClaw's plugin API — only the fields we\n * touch. We avoid importing from `openclaw/plugin-sdk` so the package stays\n * usable when OpenClaw isn't installed (the CLI and tests don't need it),\n * and so we're robust to small signature changes across OpenClaw versions.\n *\n * `pluginConfig` is the user's `plugins.entries[id].config` block — that's\n * the canonical place to read credentials and feature flags. The OpenClaw\n * plugin SDK also exposes the same value as `api.pluginConfig` on the\n * builder API; keep both names in sync if the upstream contract evolves.\n */\nexport interface OpenClawPluginApiLike {\n logger?: Logger\n pluginConfig?: Record<string, unknown>\n on: <K extends string>(\n hookName: K,\n handler: (event: unknown, ctx: unknown) => unknown,\n opts?: { priority?: number },\n ) => void\n}\n\nexport interface RegisterOptions {\n /** Override the config, mostly for tests. */\n config?: Config\n /** Override the logger. */\n logger?: Logger\n /**\n * Hook to observe the emitted run right before it's posted. Used by tests;\n * not a stable public API.\n */\n onEmit?: (result: BuildResult) => void\n}\n\n/**\n * Register the Latitude plugin against an OpenClaw plugin API. OpenClaw calls\n * this once at plugin activation; we wire up the granular paired hooks\n * (model_call_started/_ended, before_/after_tool_call, before_/after_compaction,\n * subagent_spawned/_ended, before_agent_start/agent_end) plus the\n * data-only feeds (llm_input/llm_output) that enrich the agent span.\n *\n * Every typed hook on OpenClaw's side fires fire-and-forget for non-modifying\n * hooks; before_tool_call is a `runModifyingHook` where returning anything\n * other than undefined blocks the tool call. Our handler returns nothing —\n * keep it that way.\n */\nexport default function registerLatitudePlugin(api: OpenClawPluginApiLike, opts: RegisterOptions = {}): void {\n // Source of truth: OpenClaw passes the user's `plugins.entries[id].config`\n // as `api.pluginConfig`. Env vars are a fallback so existing deploys with\n // LATITUDE_* exported in the gateway environment keep working.\n const config = opts.config ?? loadConfig(api.pluginConfig)\n const logger = opts.logger ?? createLogger(config.debug)\n\n if (!config.enabled) {\n if (config.apiKey === \"\") logger.debug(\"disabled: apiKey is empty (set plugins.entries[id].config.apiKey)\")\n if (config.project === \"\") logger.debug(\"disabled: project is empty (set plugins.entries[id].config.project)\")\n return\n }\n logger.debug(\n `enabled: project=${config.project} base=${config.baseUrl} allowConversationAccess=${config.allowConversationAccess}`,\n )\n\n const builder = new SpanBuilder()\n\n // Helper: wrap a void-returning hook handler with try/catch + cast.\n const wrap = <E>(\n name: string,\n fn: (evt: E, ctx: OpenClawAgentContext) => void,\n ): ((evt: unknown, ctx: unknown) => void) => {\n return (evt, ctx) => {\n try {\n fn(evt as E, ctx as OpenClawAgentContext)\n } catch (err) {\n logger.warn(`${name} handler failed: ${String(err)}`)\n }\n }\n }\n\n // ─── Span boundaries ────────────────────────────────────────────────────\n\n api.on(\n \"before_agent_start\",\n wrap<OpenClawBeforeAgentStartEvent>(\"before_agent_start\", (evt, ctx) => {\n builder.onBeforeAgentStart(evt, ctx)\n }),\n )\n\n api.on(\n \"model_call_started\",\n wrap<OpenClawModelCallStartedEvent>(\"model_call_started\", (evt, ctx) => {\n builder.onModelCallStarted(evt, ctx)\n }),\n )\n api.on(\n \"model_call_ended\",\n wrap<OpenClawModelCallEndedEvent>(\"model_call_ended\", (evt, ctx) => {\n builder.onModelCallEnded(evt, ctx)\n }),\n )\n\n // before_tool_call is a `runModifyingHook` — returning {block: true} from\n // any plugin handler blocks the tool. We return nothing (void) so OpenClaw\n // dispatches normally. The `wrap` helper preserves that void return.\n api.on(\n \"before_tool_call\",\n wrap<OpenClawBeforeToolCallEvent>(\"before_tool_call\", (evt, ctx) => {\n builder.onBeforeToolCall(evt, ctx)\n }),\n )\n api.on(\n \"after_tool_call\",\n wrap<OpenClawAfterToolCallEvent>(\"after_tool_call\", (evt, ctx) => {\n builder.onAfterToolCall(evt, ctx)\n }),\n )\n\n api.on(\n \"before_compaction\",\n wrap<OpenClawBeforeCompactionEvent>(\"before_compaction\", (evt, ctx) => {\n builder.onBeforeCompaction(evt, ctx)\n }),\n )\n api.on(\n \"after_compaction\",\n wrap<OpenClawAfterCompactionEvent>(\"after_compaction\", (evt, ctx) => {\n builder.onAfterCompaction(evt, ctx)\n }),\n )\n\n api.on(\n \"subagent_spawned\",\n wrap<OpenClawSubagentSpawnedEvent>(\"subagent_spawned\", (evt, ctx) => {\n builder.onSubagentSpawned(evt, ctx)\n }),\n )\n api.on(\n \"subagent_ended\",\n wrap<OpenClawSubagentEndedEvent>(\"subagent_ended\", (evt, ctx) => {\n builder.onSubagentEnded(evt, ctx)\n }),\n )\n\n // ─── Data-only feeds ────────────────────────────────────────────────────\n // These DON'T open or close spans. They enrich the open `agent` span with\n // attempt-aggregate content + token usage, and seed the rolling history\n // snapshot used by per-call `model_call.input.messages`.\n\n api.on(\n \"llm_input\",\n wrap<OpenClawLlmInputEvent>(\"llm_input\", (evt, ctx) => {\n builder.onLlmInput(evt, ctx)\n }),\n )\n api.on(\n \"llm_output\",\n wrap<OpenClawLlmOutputEvent>(\"llm_output\", (evt, ctx) => {\n builder.onLlmOutput(evt, ctx)\n }),\n )\n\n // ─── Trace flush ────────────────────────────────────────────────────────\n //\n // Why we defer the finalize by one microtask tick instead of finalizing\n // synchronously inside the agent_end handler: OpenClaw 2026.4.26+ has TWO\n // hook fire-orders depending on which runtime the agent uses, and the\n // selection.runtime path (used by the codex / embedded ACPX agents) fires\n // events in this order:\n //\n // llm_input → ...model_calls / tool_calls... → agent_end → llm_output\n //\n // The cli-runner.runtime path (used by the claude-code agent) fires the\n // reverse — `llm_output` BEFORE `agent_end` — and only when the assistant\n // emitted a non-empty text part.\n //\n // If we finalize on agent_end synchronously, the run is deleted and the OTLP\n // batch is shipped before `llm_output` (under selection.runtime) gets a\n // chance to enrich the agent span with `gen_ai.output.messages`,\n // `gen_ai.response.model`, `openclaw.resolved.ref`, `openclaw.harness.id`,\n // and the entire `gen_ai.usage.*` block. The `onLlmOutput` handler then\n // bails on `if (!run) return` cleanly (no error, no warning), and every\n // attribute that lives on the `llm_output` event is silently dropped.\n //\n // Deferring with `queueMicrotask` is order-agnostic: in either path, both\n // hook handlers run synchronously in the current microtask round and write\n // to the still-alive run; the queued finalize fires after both have\n // completed and serializes a fully-enriched batch. Subagents go through\n // exactly the same `onAgentEnd` path so they benefit automatically.\n //\n // We don't use `setTimeout(0)` because the +1 macrotask of latency isn't\n // meaningful here, and `queueMicrotask` is more reliable on process exit\n // (microtasks drain before exit; macrotasks may not). If a future OpenClaw\n // ever introduces an `await` between `agent_end` dispatch and `llm_output`\n // dispatch, we'll need to switch to `setTimeout(0)`.\n api.on(\n \"agent_end\",\n wrap<OpenClawAgentEndEvent>(\"agent_end\", (evt, ctx) => {\n queueMicrotask(() => {\n try {\n const result = builder.onAgentEnd(evt, ctx)\n if (!result) {\n logger.debug(\"agent_end fired without a matching run in flight\")\n return\n }\n opts.onEmit?.(result)\n const payload = buildOtlpRequest(result, { allowConversationAccess: config.allowConversationAccess })\n void postTraces({\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\n project: config.project,\n payload,\n logger,\n })\n } catch (err) {\n logger.warn(`agent_end finalize failed: ${String(err)}`)\n }\n })\n }),\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","names":["str","safeJson","MAX_FILE_BYTES"],"sources":["../src/redaction.ts","../src/config.ts","../src/logger.ts","../src/otlp.ts","../src/context.ts","../src/messages.ts","../src/history.ts","../src/memory.ts","../src/tools.ts","../src/usage.ts","../src/span-builder.ts","../src/transport.ts","../src/plugin.ts"],"sourcesContent":["import type { OtlpKeyValue } from \"./types.ts\"\n\nexport interface RedactConfig {\n attributes: string[]\n mask: string\n}\n\nexport function parseRedactConfig(value: unknown): RedactConfig | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined\n const obj = value as Record<string, unknown>\n const attributes = parseAttributes(obj.attributes)\n if (attributes.length === 0) return undefined\n return { attributes, mask: typeof obj.mask === \"string\" ? obj.mask : \"******\" }\n}\n\nexport function redactAttributes(attributes: OtlpKeyValue[], config: RedactConfig | undefined): OtlpKeyValue[] {\n if (!config) return attributes\n const matchers = config.attributes.map(toMatcher).filter((matcher): matcher is (key: string) => boolean => !!matcher)\n if (matchers.length === 0) return attributes\n return attributes.map((attr) =>\n matchers.some((matches) => matches(attr.key)) ? redactedAttr(attr.key, config.mask) : attr,\n )\n}\n\nfunction parseAttributes(value: unknown): string[] {\n if (!Array.isArray(value)) return []\n return value.filter((item): item is string => typeof item === \"string\" && item.trim() !== \"\")\n}\n\nfunction toMatcher(pattern: string): ((key: string) => boolean) | undefined {\n if (pattern.startsWith(\"/\") && pattern.lastIndexOf(\"/\") > 0) {\n const end = pattern.lastIndexOf(\"/\")\n try {\n const regex = new RegExp(pattern.slice(1, end), pattern.slice(end + 1))\n return (key) => {\n regex.lastIndex = 0\n return regex.test(key)\n }\n } catch {\n return undefined\n }\n }\n try {\n const regex = new RegExp(pattern)\n return (key) => {\n regex.lastIndex = 0\n return key === pattern || regex.test(key)\n }\n } catch {\n return (key) => key === pattern\n }\n}\n\nfunction redactedAttr(key: string, mask: string): OtlpKeyValue {\n return { key, value: { stringValue: mask } }\n}\n","import { parseRedactConfig, type RedactConfig } from \"./redaction.ts\"\n\nexport interface Config {\n apiKey: string\n baseUrl: string\n project: string\n enabled: boolean\n debug: boolean\n /**\n * When false, the plugin still emits one span per LLM call / tool / run, but\n * scrubs raw conversation content (input/output messages, system prompt,\n * tool args, tool results, memory bodies). Token counts, model names, agent\n * ids, and timings are unaffected.\n */\n allowConversationAccess: boolean\n redact?: RedactConfig | undefined\n serviceName: string\n tags: string[]\n metadata: Record<string, string>\n memory: boolean\n memoryContent: boolean\n toolDefinitions: boolean\n maxContentChars: number\n}\n\nconst DEFAULT_BASE_URL = \"https://ingest.latitude.so\"\nconst DEFAULT_SERVICE_NAME = \"openclaw\"\nconst DEFAULT_MAX_CONTENT_CHARS = 262_144\n\n/**\n * Build a `Config` from OpenClaw's per-plugin config bucket. The plugin SDK\n * passes `api.pluginConfig` (the user's `plugins.entries[id].config` block)\n * to the registration function; that is the only source. There is no\n * environment fallback: the runtime must not combine env reads with the\n * network send, and the installer always writes credentials here.\n */\nexport function loadConfig(pluginConfig: Record<string, unknown> | undefined = undefined): Config {\n const fromOpts = pluginConfig ?? {}\n\n const apiKey = pickString(fromOpts.apiKey) ?? \"\"\n const project = pickString(fromOpts.project) ?? \"\"\n const baseUrl = pickString(fromOpts.baseUrl) ?? DEFAULT_BASE_URL\n\n const debug = pickBool(fromOpts.debug) ?? false\n const allowConversationAccess = pickBool(fromOpts.allowConversationAccess) ?? false\n\n const explicitlyDisabled = pickBool(fromOpts.enabled) === false\n const hasCreds = apiKey !== \"\" && project !== \"\"\n\n return {\n apiKey,\n baseUrl,\n project,\n debug,\n allowConversationAccess,\n redact: parseRedactConfig(fromOpts.redact),\n enabled: hasCreds && !explicitlyDisabled,\n serviceName: pickString(fromOpts.serviceName) ?? DEFAULT_SERVICE_NAME,\n tags: pickStringList(fromOpts.tags),\n metadata: pickStringMap(fromOpts.metadata),\n memory: pickBool(fromOpts.memory) ?? true,\n memoryContent: pickBool(fromOpts.memoryContent) ?? true,\n toolDefinitions: pickBool(fromOpts.toolDefinitions) ?? true,\n maxContentChars: pickPositiveInt(fromOpts.maxContentChars) ?? DEFAULT_MAX_CONTENT_CHARS,\n }\n}\n\nfunction pickString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined\n}\n\nfunction pickBool(value: unknown): boolean | undefined {\n return typeof value === \"boolean\" ? value : undefined\n}\n\nfunction pickPositiveInt(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isInteger(value) && value > 0 ? value : undefined\n}\n\nfunction pickStringList(value: unknown): string[] {\n if (typeof value === \"string\") {\n return value\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0)\n }\n if (!Array.isArray(value)) return []\n return value.filter((v): v is string => typeof v === \"string\" && v.trim().length > 0).map((v) => v.trim())\n}\n\nfunction pickStringMap(value: unknown): Record<string, string> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return {}\n const out: Record<string, string> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (typeof v === \"string\") out[k] = v\n else if (typeof v === \"number\" || typeof v === \"boolean\") out[k] = String(v)\n }\n return out\n}\n","const PREFIX = \"[latitude-openclaw]\"\n\nexport interface Logger {\n debug: (msg: string) => void\n warn: (msg: string) => void\n}\n\n/** Shape of OpenClaw's `api.logger`; lines written through it land in the gateway log. */\nexport interface HostLogger {\n debug?: (message: string) => void\n info: (message: string) => void\n warn: (message: string) => void\n error: (message: string) => void\n}\n\nexport function createLogger(debugEnabled: boolean, host?: HostLogger): Logger {\n // Host debug output is usually filtered out of the gateway log, so debug lines go through info.\n const debugSink = host ? (msg: string) => host.info(`${PREFIX} ${msg}`) : (msg: string) => writeStderr(msg)\n const warnSink = host ? (msg: string) => host.warn(`${PREFIX} ${msg}`) : (msg: string) => writeStderr(msg)\n return {\n debug: debugEnabled ? debugSink : () => {},\n warn: warnSink,\n }\n}\n\nfunction writeStderr(msg: string): void {\n process.stderr.write(`${PREFIX} ${msg}\\n`)\n}\n","import { arch, hostname, platform, release } from \"node:os\"\nimport { type RedactConfig, redactAttributes } from \"./redaction.ts\"\nimport type { AttrValue, BuildResult, SpanRecord } from \"./span-builder.ts\"\nimport type { OtlpExportRequest, OtlpKeyValue, OtlpResourceSpans, OtlpSpan } from \"./types.ts\"\n\nconst SCOPE_NAME = \"@latitude-data/openclaw-telemetry\"\n\n/**\n * Build-time-baked package version: `__SCOPE_VERSION__` is replaced by tsdown's\n * `define` with `package.json`'s version, so the bundle never reads a file at\n * runtime. The `typeof` guard covers vitest, which runs the source directly.\n */\ndeclare const __SCOPE_VERSION__: string\nexport const SCOPE_VERSION = typeof __SCOPE_VERSION__ === \"string\" ? __SCOPE_VERSION__ : \"0.0.0-dev\"\n\nconst GATED_SUFFIX = \":gated\"\n// Keys Latitude reads as a native OTLP string array rather than a JSON string.\nconst ARRAY_VALUE_KEYS: ReadonlySet<string> = new Set([\"gen_ai.response.finish_reasons\"])\nconst TRUNCATION_MARKER = \"\\n…[truncated by latitude-openclaw]…\\n\"\n\ninterface BuildOptions {\n /**\n * When false, attributes whose key ends in `:gated` are dropped before\n * export: messages, system instructions, tool arguments and results, memory\n * bodies and queries, error messages. Timing, usage, ids and names always ship.\n */\n allowConversationAccess: boolean\n redact?: RedactConfig | undefined\n serviceName?: string\n /** Per-attribute budget in UTF-16 units; larger values are truncated from the middle. */\n maxContentChars?: number\n}\n\nexport function buildOtlpRequest(results: readonly BuildResult[], options: BuildOptions): OtlpExportRequest {\n const spans = results.flatMap((result) => result.spans.map((span) => toOtlpSpan(span, options)))\n const rs: OtlpResourceSpans = {\n resource: { attributes: resourceAttrs(options.serviceName ?? \"openclaw\") },\n scopeSpans: [{ scope: { name: SCOPE_NAME, version: SCOPE_VERSION }, spans }],\n }\n return { resourceSpans: [rs] }\n}\n\nfunction toOtlpSpan(span: SpanRecord, options: BuildOptions): OtlpSpan {\n const attrs: OtlpKeyValue[] = []\n for (const [rawKey, value] of Object.entries(span.attrs)) {\n if (value === undefined || value === null) continue\n const isGated = rawKey.endsWith(GATED_SUFFIX)\n if (isGated && !options.allowConversationAccess) continue\n const key = isGated ? rawKey.slice(0, -GATED_SUFFIX.length) : rawKey\n const kv = encodeAttr(key, value, options.maxContentChars)\n if (kv !== undefined) attrs.push(kv)\n }\n attrs.push(bool(\"latitude.captured.content\", options.allowConversationAccess))\n\n return {\n traceId: span.traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n kind: span.kind,\n startTimeUnixNano: msToNs(span.startMs),\n endTimeUnixNano: msToNs(span.endMs ?? span.startMs),\n attributes: redactAttributes(attrs, options.redact),\n status: { code: span.outcome === \"error\" ? 2 : 1 },\n }\n}\n\nfunction encodeAttr(key: string, value: AttrValue, maxChars: number | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null) return undefined\n if (typeof value === \"string\") return str(key, budget(value, maxChars))\n if (typeof value === \"boolean\") return bool(key, value)\n if (typeof value === \"number\") {\n return Number.isInteger(value) ? int(key, value) : { key, value: { doubleValue: value } }\n }\n if (ARRAY_VALUE_KEYS.has(key) && Array.isArray(value)) {\n return { key, value: { arrayValue: { values: value.map((v) => ({ stringValue: String(v) })) } } }\n }\n // Arrays and objects ship as JSON strings; Latitude parses the gen_ai.* ones.\n return str(key, budgetJson(value, maxChars))\n}\n\nfunction budget(value: string, maxChars: number | undefined): string {\n if (!maxChars || value.length <= maxChars) return value\n const keep = Math.max(0, Math.floor((maxChars - TRUNCATION_MARKER.length) / 2))\n let headEnd = keep\n if (headEnd > 0 && isHighSurrogate(value.charCodeAt(headEnd - 1))) headEnd--\n let tailStart = value.length - keep\n if (tailStart < value.length && isLowSurrogate(value.charCodeAt(tailStart))) tailStart++\n return `${value.slice(0, headEnd)}${TRUNCATION_MARKER}${value.slice(tailStart)}`\n}\n\nfunction isHighSurrogate(code: number): boolean {\n return code >= 0xd800 && code <= 0xdbff\n}\n\nfunction isLowSurrogate(code: number): boolean {\n return code >= 0xdc00 && code <= 0xdfff\n}\n\n/**\n * A structured value must still parse after the budget, since Latitude reads\n * messages, tool definitions and memory records as JSON: long strings inside\n * it are truncated first, then whole items are shed from the middle of an\n * array. Slicing the serialized text is the last resort, for a lone object.\n */\nfunction budgetJson(value: unknown, maxChars: number | undefined): string {\n const json = safeJson(value)\n if (!maxChars || json.length <= maxChars) return json\n const trimmed = budgetStrings(value, Math.max(1, Math.floor(maxChars / 4)))\n const trimmedJson = safeJson(trimmed)\n if (trimmedJson.length <= maxChars) return trimmedJson\n if (Array.isArray(trimmed)) return safeJson(shedItems(trimmed, maxChars))\n return budget(trimmedJson, maxChars)\n}\n\nfunction budgetStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === \"string\") return budget(value, maxChars)\n if (Array.isArray(value)) return value.map((item) => budgetStrings(item, maxChars))\n if (value && typeof value === \"object\") {\n return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, budgetStrings(v, maxChars)]))\n }\n return value\n}\n\nconst OMISSION_RESERVE = 160\n\n/** Keeps the head and tail of an array within the budget; a message list gets a marker for what was dropped. */\nfunction shedItems(items: readonly unknown[], maxChars: number): unknown[] {\n const sizes = items.map((item) => safeJson(item).length + 1)\n const head: unknown[] = []\n const tail: unknown[] = []\n let budgetLeft = maxChars - OMISSION_RESERVE\n let low = 0\n let high = items.length - 1\n while (low <= high) {\n const fromHead = head.length <= tail.length\n const size = (fromHead ? sizes[low] : sizes[high]) as number\n if (budgetLeft - size < 0) break\n budgetLeft -= size\n if (fromHead) head.push(items[low++])\n else tail.unshift(items[high--])\n }\n const omitted = items.length - head.length - tail.length\n if (omitted <= 0) return [...items]\n const marker = isMessageList(items) ? [omissionMessage(omitted)] : []\n return [...head, ...marker, ...tail]\n}\n\nfunction isMessageList(items: readonly unknown[]): boolean {\n const first = items[0]\n return !!first && typeof first === \"object\" && typeof (first as { role?: unknown }).role === \"string\"\n}\n\nfunction omissionMessage(count: number): unknown {\n return {\n role: \"system\",\n parts: [{ type: \"text\", content: `[… ${count} message(s) omitted by latitude-openclaw …]` }],\n }\n}\n\nfunction resourceAttrs(serviceName: string): OtlpKeyValue[] {\n return [\n str(\"service.name\", serviceName),\n str(\"service.version\", SCOPE_VERSION),\n str(\"telemetry.sdk.name\", SCOPE_NAME),\n str(\"host.name\", hostname()),\n str(\"host.arch\", arch()),\n str(\"os.type\", platform()),\n str(\"os.version\", release()),\n ]\n}\n\nfunction str(key: string, value: string): OtlpKeyValue {\n return { key, value: { stringValue: value } }\n}\n\nfunction int(key: string, value: number): OtlpKeyValue {\n return { key, value: { intValue: String(Math.trunc(value)) } }\n}\n\nfunction bool(key: string, value: boolean): OtlpKeyValue {\n return { key, value: { boolValue: value } }\n}\n\nfunction msToNs(ms: number): string {\n return (BigInt(Math.trunc(ms)) * 1_000_000n).toString()\n}\n\nfunction safeJson(value: unknown): string {\n try {\n if (typeof value === \"string\") return value\n return JSON.stringify(value)\n } catch {\n return \"\"\n }\n}\n","import type { OpenClawAgentContext } from \"./types.ts\"\n\nconst TAG_MAX_CHARS = 64\nexport const TAG_MAX_COUNT = 32\nconst METADATA_VALUE_MAX_CHARS = 1024\nconst METADATA_MAX_KEYS = 64\n\nexport interface Sender {\n id: string\n name?: string | undefined\n username?: string | undefined\n}\n\nexport interface CronJob {\n id: string\n name?: string | undefined\n}\n\n/** Everything a run knows about itself that turns into tags and metadata. */\ninterface RunContext {\n ctx: OpenClawAgentContext\n sender?: Sender | undefined\n cron?: CronJob | undefined\n subagentIds: string[]\n pluginVersion: string\n}\n\ninterface Enrichment {\n tags: string[]\n metadata: Record<string, string>\n}\n\n/**\n * Derived tags: `openclaw`, the channel, the agent id, `cron:<job>` (or the\n * bare trigger for other non-user triggers) and `subagent:<agent>` on a run\n * that spawned one. Operator tags are appended. Tags are what `queryAnalytics`\n * can break down on, so they stay low-cardinality; ids go in metadata.\n */\nexport function deriveEnrichment(\n run: RunContext,\n operator: { tags: readonly string[]; metadata: Readonly<Record<string, string>> },\n): Enrichment {\n const { ctx } = run\n const tags: string[] = [\"openclaw\"]\n if (ctx.channel) tags.push(ctx.channel)\n if (ctx.agentId) tags.push(ctx.agentId)\n if (ctx.trigger === \"cron\") tags.push(run.cron ? `cron:${run.cron.id}` : \"cron\")\n else if (ctx.trigger && ctx.trigger !== \"user\") tags.push(ctx.trigger)\n for (const id of run.subagentIds) tags.push(`subagent:${id}`)\n for (const tag of operator.tags) tags.push(tag)\n\n const metadata: Record<string, string> = {}\n for (const [k, v] of Object.entries(operator.metadata)) {\n if (k.startsWith(\"openclaw.\")) continue\n metadata[k] = v\n }\n const derived: Record<string, string | undefined> = {\n \"openclaw.run.id\": ctx.runId,\n \"openclaw.session.id\": ctx.sessionId,\n \"openclaw.session.key\": ctx.sessionKey,\n \"openclaw.agent.id\": ctx.agentId,\n \"openclaw.workspace.dir\": ctx.workspaceDir,\n \"openclaw.channel\": ctx.channel,\n \"openclaw.channel.id\": ctx.channelId,\n \"openclaw.account.id\": ctx.accountId,\n \"openclaw.message.provider\": ctx.messageProvider,\n \"openclaw.trigger\": ctx.trigger,\n \"openclaw.model.provider.id\": ctx.modelProviderId,\n \"openclaw.model.id\": ctx.modelId,\n \"openclaw.cron.job.id\": run.cron?.id,\n \"openclaw.cron.job.name\": run.cron?.name,\n \"openclaw.sender.id\": run.sender?.id,\n \"openclaw.sender.name\": run.sender?.name,\n \"openclaw.sender.username\": run.sender?.username,\n \"openclaw.trace.id\": ctx.trace?.traceId,\n \"openclaw.plugin.version\": run.pluginVersion,\n }\n for (const [k, v] of Object.entries(derived)) {\n if (v !== undefined && v !== \"\") metadata[k] = v\n }\n\n return { tags: capTags(tags), metadata: capMetadata(metadata) }\n}\n\nfunction capTags(tags: string[]): string[] {\n const seen = new Set<string>()\n const out: string[] = []\n for (const tag of tags) {\n const trimmed = tag.trim()\n if (trimmed.length === 0 || trimmed.length > TAG_MAX_CHARS || seen.has(trimmed)) continue\n seen.add(trimmed)\n out.push(trimmed)\n if (out.length >= TAG_MAX_COUNT) break\n }\n return out\n}\n\nfunction capMetadata(metadata: Record<string, string>): Record<string, string> {\n const out: Record<string, string> = {}\n let count = 0\n for (const [k, v] of Object.entries(metadata)) {\n if (v.length > METADATA_VALUE_MAX_CHARS) continue\n out[k] = v\n count++\n if (count >= METADATA_MAX_KEYS) break\n }\n return out\n}\n\nconst CTX_MARKER = \"⟦openclaw:ctx⟧\"\n\n/**\n * OpenClaw prefixes channel prompts with a fenced JSON block after\n * `⟦openclaw:ctx⟧` that carries the sender's id and display name; the only\n * place the name reaches a run when `message_received` did not.\n */\nexport function senderFromPrompt(prompt: string | undefined): Sender | undefined {\n if (!prompt) return undefined\n const marker = prompt.indexOf(CTX_MARKER)\n if (marker < 0) return undefined\n const fenceStart = prompt.indexOf(\"```json\", marker)\n if (fenceStart < 0) return undefined\n const bodyStart = prompt.indexOf(\"\\n\", fenceStart)\n const fenceEnd = prompt.indexOf(\"```\", bodyStart + 1)\n if (bodyStart < 0 || fenceEnd < 0) return undefined\n try {\n const parsed = JSON.parse(prompt.slice(bodyStart + 1, fenceEnd)) as {\n sender?: { id?: unknown; name?: unknown; username?: unknown }\n }\n const sender = parsed.sender\n if (!sender || typeof sender.id !== \"string\" || sender.id.length === 0) return undefined\n return {\n id: sender.id,\n name: typeof sender.name === \"string\" && sender.name.length > 0 ? sender.name : undefined,\n username: typeof sender.username === \"string\" && sender.username.length > 0 ? sender.username : undefined,\n }\n } catch {\n return undefined\n }\n}\n\n/** `agent:<agentId>:cron:<jobId>[:run:<runId>]` is the isolated cron session key shape. */\nexport function cronJobFromSessionKey(sessionKey: string | undefined): string | undefined {\n if (!sessionKey) return undefined\n const match = /^agent:[^:]+:cron:([^:]+)/.exec(sessionKey)\n return match?.[1]\n}\n","/**\n * Normalizes provider-specific message shapes into the parts-based GenAI\n * format Latitude's parser expects:\n *\n * { role: \"system\" | \"user\" | \"assistant\" | \"tool\", parts: MessagePart[] }\n *\n * Dialects handled, dispatched per item on the item's own shape:\n *\n * - OpenClaw / pi-ai transcript: `{role:\"user\", content: string | (text|image)[]}`,\n * `{role:\"assistant\", content: (text|thinking|toolCall)[]}`,\n * `{role:\"toolResult\", toolCallId, toolName, content, isError}`,\n * `{role:\"custom\", ...}` runtime notes.\n * - Anthropic: `{role, content: string | ContentBlock[]}` with `text`,\n * `tool_use`, `tool_result`, `image`, `thinking` blocks.\n * - OpenAI Chat Completions: `{role, content: string, tool_calls?}` and\n * `{role:\"tool\", tool_call_id, content}`.\n * - Already-normalized parts-shape messages, passed through unchanged.\n *\n * Anything unrecognized becomes a JSON-stringified text part so nothing is\n * silently dropped.\n */\n\nexport interface MessagePart {\n type: string\n content?: string\n id?: string | undefined\n name?: string | undefined\n arguments?: unknown\n response?: unknown\n modality?: string\n uri?: string\n [key: string]: unknown\n}\n\nexport type MessageRole = \"system\" | \"user\" | \"assistant\" | \"tool\"\n\nexport interface Message {\n role: MessageRole\n parts: MessagePart[]\n}\n\nconst ALLOWED_ROLES: ReadonlySet<MessageRole> = new Set([\"system\", \"user\", \"assistant\", \"tool\"])\n\nexport function normalizeMessage(raw: unknown): Message | undefined {\n if (!raw || typeof raw !== \"object\") return undefined\n const obj = raw as Record<string, unknown>\n\n if (Array.isArray(obj.parts)) {\n const parts: MessagePart[] = []\n for (const p of obj.parts) {\n if (p && typeof p === \"object\") parts.push(p as MessagePart)\n }\n return { role: coerceRole(obj.role), parts: parts.length > 0 ? parts : [{ type: \"text\", content: safeJson(raw) }] }\n }\n\n if (obj.role === \"toolResult\") return normalizeToolResult(obj)\n if (obj.role === \"custom\") return normalizeCustom(obj)\n\n const content = obj.content ?? obj.text ?? obj.message\n const role = isRuntimeContext(obj, content) ? \"system\" : coerceRole(obj.role)\n\n if (role === \"tool\" && obj.tool_call_id !== undefined) {\n return {\n role,\n parts: [\n {\n type: \"tool_call_response\",\n id: typeof obj.tool_call_id === \"string\" ? obj.tool_call_id : \"\",\n response: content ?? safeJson(obj),\n },\n ],\n }\n }\n\n if (typeof content === \"string\") {\n const parts: MessagePart[] = []\n if (content.length > 0) parts.push({ type: \"text\", content })\n appendToolCalls(parts, obj.tool_calls)\n if (parts.length === 0) parts.push({ type: \"text\", content: \"\" })\n return { role, parts }\n }\n\n if (Array.isArray(content)) {\n const parts: MessagePart[] = []\n for (const block of content) {\n const part = normalizeBlock(block)\n if (part) parts.push(part)\n }\n appendToolCalls(parts, obj.tool_calls)\n if (parts.length === 0) parts.push({ type: \"text\", content: safeJson(content) })\n return { role, parts }\n }\n\n return { role, parts: [{ type: \"text\", content: safeJson(raw) }] }\n}\n\nexport function normalizeMessages(raw: readonly unknown[]): Message[] {\n const out: Message[] = []\n for (const m of raw) {\n const norm = normalizeMessage(m)\n if (norm) out.push(norm)\n }\n return out\n}\n\nexport function userMessageFromPrompt(prompt: string): Message {\n return { role: \"user\", parts: [{ type: \"text\", content: prompt }] }\n}\n\nexport function assistantMessageFromOutput(assistantTexts: readonly string[], lastAssistant: unknown): Message {\n if (lastAssistant !== undefined) {\n const norm = normalizeMessage(lastAssistant)\n if (norm) return { ...norm, role: \"assistant\" }\n }\n const parts: MessagePart[] = []\n for (const text of assistantTexts) {\n if (text.length > 0) parts.push({ type: \"text\", content: text })\n }\n if (parts.length === 0) parts.push({ type: \"text\", content: \"\" })\n return { role: \"assistant\", parts }\n}\n\nexport function systemInstructionsParts(prompt: string): MessagePart[] {\n return [{ type: \"text\", content: prompt }]\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nconst RUNTIME_CONTEXT_PREFIX = \"[openclaw.runtime-context]\"\n\n/**\n * OpenClaw injects its per-turn context as an extra user message right before\n * the prompt. It is instructions rather than the user's words, so it renders\n * as a system message instead of a second user bubble.\n */\nfunction isRuntimeContext(obj: Record<string, unknown>, content: unknown): boolean {\n if (obj.role !== \"user\") return false\n if (obj.runtimeContext) return true\n const text = typeof content === \"string\" ? content : Array.isArray(content) ? blockText(content[0]) : undefined\n return typeof text === \"string\" && text.trimStart().startsWith(RUNTIME_CONTEXT_PREFIX)\n}\n\nfunction coerceRole(raw: unknown): MessageRole {\n if (typeof raw !== \"string\") return \"user\"\n return ALLOWED_ROLES.has(raw as MessageRole) ? (raw as MessageRole) : \"user\"\n}\n\nfunction normalizeToolResult(obj: Record<string, unknown>): Message {\n const content = obj.content\n let response: unknown\n if (typeof content === \"string\") response = content\n else if (Array.isArray(content)) {\n const texts: string[] = []\n let hasNonText = false\n for (const block of content) {\n const text = blockText(block)\n if (text !== undefined) texts.push(text)\n else hasNonText = true\n }\n response = hasNonText ? content.map(normalizeBlock).filter(Boolean) : texts.join(\"\\n\")\n } else response = content ?? \"\"\n return {\n role: \"tool\",\n parts: [\n {\n type: \"tool_call_response\",\n id: typeof obj.toolCallId === \"string\" ? obj.toolCallId : \"\",\n name: typeof obj.toolName === \"string\" ? obj.toolName : undefined,\n response,\n ...(obj.isError === true ? { is_error: true } : {}),\n },\n ],\n }\n}\n\n/** Text of a plain text block, or of the `toolResult` block the Codex harness wraps tool output in. */\nfunction blockText(block: unknown): string | undefined {\n if (!block || typeof block !== \"object\") return undefined\n const b = block as Record<string, unknown>\n if (b.type === \"text\" && typeof b.text === \"string\") return b.text\n if (b.type === \"toolResult\") {\n if (typeof b.text === \"string\") return b.text\n if (typeof b.content === \"string\") return b.content\n }\n return undefined\n}\n\nfunction normalizeCustom(obj: Record<string, unknown>): Message {\n const text = typeof obj.content === \"string\" ? obj.content : safeJson(obj)\n const customType = typeof obj.customType === \"string\" ? obj.customType : \"custom\"\n return { role: \"user\", parts: [{ type: \"text\", content: `[${customType}] ${text}` }] }\n}\n\nfunction normalizeBlock(raw: unknown): MessagePart | undefined {\n if (typeof raw === \"string\") return { type: \"text\", content: raw }\n if (!raw || typeof raw !== \"object\") return undefined\n const obj = raw as Record<string, unknown>\n const type = typeof obj.type === \"string\" ? obj.type : \"text\"\n\n if (type === \"text\") {\n if (typeof obj.content === \"string\") return { type: \"text\", content: obj.content }\n if (typeof obj.text === \"string\") return { type: \"text\", content: obj.text }\n }\n if (type === \"toolResult\") {\n const text = blockText(obj)\n return { type: \"text\", content: text ?? safeJson(raw) }\n }\n if (type === \"toolCall\" || type === \"tool_use\" || type === \"tool_call\") {\n return {\n type: \"tool_call\",\n id: typeof obj.id === \"string\" ? obj.id : \"\",\n name: typeof obj.name === \"string\" ? obj.name : \"\",\n arguments: obj.arguments ?? obj.input ?? {},\n }\n }\n if (type === \"tool_result\") {\n return {\n type: \"tool_call_response\",\n id: typeof obj.tool_use_id === \"string\" ? obj.tool_use_id : \"\",\n response: obj.content ?? \"\",\n }\n }\n if (type === \"tool_call_response\") {\n return {\n type: \"tool_call_response\",\n id: typeof obj.id === \"string\" ? obj.id : \"\",\n response: obj.response ?? \"\",\n }\n }\n if (type === \"thinking\") {\n if (typeof obj.thinking === \"string\" && obj.thinking.length > 0) return { type: \"reasoning\", content: obj.thinking }\n if (obj.redacted === true) return { type: \"reasoning\", content: \"[redacted]\" }\n return undefined\n }\n if (type === \"reasoning\" && typeof obj.content === \"string\") {\n return { type: \"reasoning\", content: obj.content }\n }\n if (type === \"image\") {\n const uri = imageUri(obj)\n if (uri) return { type: \"uri\", modality: \"image\", uri }\n return { type: \"text\", content: \"[image]\" }\n }\n\n return { type, content: safeJson(raw) }\n}\n\nfunction imageUri(obj: Record<string, unknown>): string | undefined {\n if (typeof obj.data === \"string\" && obj.data.length > 0) {\n const mime = typeof obj.mimeType === \"string\" ? obj.mimeType : \"image/unknown\"\n return `data:${mime};base64,${obj.data}`\n }\n if (obj.source && typeof obj.source === \"object\") {\n const src = obj.source as { media_type?: string; data?: string; url?: string }\n if (src.url) return src.url\n if (src.data) return `data:${src.media_type ?? \"image/unknown\"};base64,${src.data}`\n }\n return undefined\n}\n\nfunction appendToolCalls(parts: MessagePart[], raw: unknown): void {\n if (!Array.isArray(raw)) return\n for (const tc of raw) {\n if (!tc || typeof tc !== \"object\") continue\n const t = tc as Record<string, unknown>\n const fn = t.function as { name?: string; arguments?: string | Record<string, unknown> } | undefined\n let parsedArgs: unknown = fn?.arguments\n if (typeof parsedArgs === \"string\") {\n try {\n parsedArgs = JSON.parse(parsedArgs)\n } catch {\n // leave as string\n }\n }\n parts.push({\n type: \"tool_call\",\n id: typeof t.id === \"string\" ? t.id : \"\",\n name: fn?.name ?? \"\",\n arguments: parsedArgs ?? {},\n })\n }\n}\n\nfunction safeJson(value: unknown): string {\n try {\n if (typeof value === \"string\") return value\n return JSON.stringify(value)\n } catch {\n return \"\"\n }\n}\n","import { readFileSync, statSync } from \"node:fs\"\nimport { createRequire } from \"node:module\"\nimport { basename, dirname, join } from \"node:path\"\nimport { type Message, normalizeMessages } from \"./messages.ts\"\n\n/**\n * Conversation history for harnesses that do not hand it to plugins. The\n * embedded runner passes the whole session on `llm_input.historyMessages` and\n * on `agent_end.messages`; the Codex harness owns the thread itself and passes\n * an empty history and a per-turn transcript. The plugin then rebuilds the\n * session from the turns it has seen, and on a cold start from OpenClaw's own\n * transcript store: the per-agent SQLite database (2026.9+) or the older\n * JSONL file under `<stateDir>/agents/<agent>/sessions/`.\n */\n\nconst MAX_MESSAGES = 400\nconst MAX_SESSIONS = 200\nconst SESSION_TTL_MS = 24 * 60 * 60 * 1000\nconst MAX_FILE_BYTES = 8 * 1024 * 1024\nconst CURRENT_PROMPT_WINDOW_MS = 60_000\n\nexport type TranscriptReader = (path: string) => string | undefined\n\nconst defaultTranscriptReader: TranscriptReader = (path) => {\n try {\n if (statSync(path).size > MAX_FILE_BYTES) return undefined\n return readFileSync(path, \"utf8\")\n } catch {\n return undefined\n }\n}\n\ninterface SessionHistory {\n messages: Message[]\n updatedAt: number\n}\n\nexport class SessionHistoryStore {\n private readonly sessions = new Map<string, SessionHistory>()\n private readonly now: () => number\n\n constructor(now: () => number = () => Date.now()) {\n this.now = now\n }\n\n get(sessionId: string): Message[] | undefined {\n const entry = this.sessions.get(sessionId)\n if (!entry) return undefined\n entry.updatedAt = this.now()\n return entry.messages\n }\n\n /** Replace the session's history with a full transcript the harness supplied. */\n replace(sessionId: string, messages: readonly Message[]): void {\n this.set(sessionId, messages.slice(-MAX_MESSAGES))\n }\n\n /** Extend the session's history with one turn's new messages. */\n append(sessionId: string, base: readonly Message[], turn: readonly Message[]): void {\n this.set(sessionId, [...base, ...turn].slice(-MAX_MESSAGES))\n }\n\n forget(sessionId: string): void {\n this.sessions.delete(sessionId)\n }\n\n private set(sessionId: string, messages: Message[]): void {\n this.evict()\n this.sessions.set(sessionId, { messages, updatedAt: this.now() })\n }\n\n private evict(): void {\n const now = this.now()\n for (const [id, entry] of this.sessions) {\n if (now - entry.updatedAt > SESSION_TTL_MS) this.sessions.delete(id)\n }\n if (this.sessions.size < MAX_SESSIONS) return\n const oldest = Array.from(this.sessions.entries()).sort((a, b) => a[1].updatedAt - b[1].updatedAt)\n for (const [id] of oldest.slice(0, this.sessions.size - MAX_SESSIONS + 1)) this.sessions.delete(id)\n }\n}\n\n/** The default workspace is `<stateDir>/workspace`, which is the only structural clue a run carries. */\nexport function stateDirFromWorkspace(workspaceDir: string | undefined): string | undefined {\n if (!workspaceDir) return undefined\n return basename(workspaceDir) === \"workspace\" ? dirname(workspaceDir) : undefined\n}\n\nexport function sessionTranscriptPath(stateDir: string, agentId: string, sessionId: string): string {\n return join(stateDir, \"agents\", agentId, \"sessions\", `${sessionId}.jsonl`)\n}\n\nexport function agentDatabasePath(stateDir: string, agentId: string): string {\n return join(stateDir, \"agents\", agentId, \"agent\", \"openclaw-agent.sqlite\")\n}\n\n/** Rows of `event_json` for a session, active branch first, else every event in order. */\nexport type TranscriptRowsReader = (dbPath: string, sessionId: string) => string[] | undefined\n\ninterface SqliteLike {\n prepare(sql: string): { all(...params: unknown[]): unknown[] }\n close(): void\n}\n\n/**\n * Reads through `node:sqlite` (Node 22.13+), loaded lazily so a host without\n * it degrades to \"no history\" instead of failing to load the plugin. The\n * database is opened read-only; the gateway keeps its own writer open.\n */\nconst defaultTranscriptRowsReader: TranscriptRowsReader = (dbPath, sessionId) => {\n let db: SqliteLike\n try {\n const require = createRequire(import.meta.url)\n const sqlite = require(\"node:sqlite\") as {\n DatabaseSync: new (path: string, opts: { readOnly: boolean }) => SqliteLike\n }\n db = new sqlite.DatabaseSync(dbPath, { readOnly: true })\n } catch {\n return undefined\n }\n try {\n const active = db\n .prepare(\n `SELECT e.event_json AS event_json\n FROM session_transcript_active_events a\n JOIN transcript_events e ON e.session_id = a.session_id AND e.seq = a.event_seq\n WHERE a.session_id = ?\n ORDER BY a.active_position`,\n )\n .all(sessionId)\n const rows =\n active.length > 0\n ? active\n : db.prepare(\"SELECT event_json FROM transcript_events WHERE session_id = ? ORDER BY seq\").all(sessionId)\n return rows\n .map((row) => (row && typeof row === \"object\" ? (row as { event_json?: unknown }).event_json : undefined))\n .filter((v): v is string => typeof v === \"string\")\n } catch {\n return undefined\n } finally {\n try {\n db.close()\n } catch {\n // already closed\n }\n }\n}\n\nexport interface CompactionRecord {\n summary: string\n tokensBefore: number | undefined\n tokensAfter: number | undefined\n}\n\n/**\n * The latest compaction entry of a session. `after_compaction` reports only\n * counts; the summary that replaced the compacted messages lives in the\n * transcript store, written before the hook fires.\n */\nexport function readLatestCompaction(\n dbPath: string,\n sessionId: string,\n readRows: TranscriptRowsReader = defaultTranscriptRowsReader,\n): CompactionRecord | undefined {\n const rows = readRows(dbPath, sessionId)\n return rows ? latestCompactionFromEntries(rows) : undefined\n}\n\nexport function readLatestCompactionFromFile(\n path: string,\n read: TranscriptReader = defaultTranscriptReader,\n): CompactionRecord | undefined {\n const raw = read(path)\n return raw === undefined ? undefined : latestCompactionFromEntries(raw.split(\"\\n\"))\n}\n\nfunction latestCompactionFromEntries(lines: readonly string[]): CompactionRecord | undefined {\n let latest: CompactionRecord | undefined\n for (const line of lines) {\n if (!line.includes('\"compaction\"')) continue\n let entry: TranscriptEntry & { tokensBefore?: unknown; tokensAfter?: unknown }\n try {\n entry = JSON.parse(line)\n } catch {\n continue\n }\n if (!entry || entry.type !== \"compaction\" || typeof entry.summary !== \"string\") continue\n latest = {\n summary: entry.summary,\n tokensBefore: typeof entry.tokensBefore === \"number\" ? entry.tokensBefore : undefined,\n tokensAfter: typeof entry.tokensAfter === \"number\" ? entry.tokensAfter : undefined,\n }\n }\n return latest\n}\n\n/** The session's visible conversation from the agent database, oldest first. */\nexport function readSessionTranscriptFromDatabase(\n dbPath: string,\n sessionId: string,\n readRows: TranscriptRowsReader = defaultTranscriptRowsReader,\n): StoredMessage[] | undefined {\n const rows = readRows(dbPath, sessionId)\n if (!rows) return undefined\n return messagesFromEntries(rows)\n}\n\n/** A stored transcript message with the time it was persisted, when the entry recorded one. */\ninterface StoredMessage {\n message: Message\n timestamp: number | undefined\n}\n\n/**\n * The current prompt is usually persisted before `llm_input` fires, so the\n * stored transcript ends with it. Channels wrap the prompt in an envelope\n * (conversation info, system lines) before the model sees it, so the stored\n * text is matched by containment; a very recent trailing user message with no\n * text match is dropped as well.\n */\nexport function withoutCurrentPrompt(\n stored: StoredMessage[],\n prompt: string | undefined,\n runStartMs: number,\n): Message[] {\n const kept = [...stored]\n for (let i = 0; i < 3 && kept.length > 0; i++) {\n const last = kept[kept.length - 1] as StoredMessage\n if (last.message.role !== \"user\") break\n const text = last.message.parts\n .map((p) => (typeof p.content === \"string\" ? p.content : \"\"))\n .join(\"\\n\")\n .trim()\n const textMatches = text.length > 0 && prompt !== undefined && (prompt === text || prompt.includes(text))\n const recent = last.timestamp !== undefined && Math.abs(runStartMs - last.timestamp) <= CURRENT_PROMPT_WINDOW_MS\n if (!textMatches && !recent) break\n kept.pop()\n }\n return kept.map((m) => m.message)\n}\n\ninterface TranscriptEntry {\n type?: string\n id?: string\n parentId?: string | null\n timestamp?: unknown\n message?: unknown\n summary?: unknown\n}\n\n/**\n * OpenClaw's transcript is a JSONL tree of entries; the visible conversation is\n * the parent chain of the last message entry (compaction and reset entries\n * branch it). Returns the normalized messages, oldest first.\n */\nexport function readSessionTranscript(\n path: string,\n read: TranscriptReader = defaultTranscriptReader,\n): StoredMessage[] | undefined {\n const raw = read(path)\n if (raw === undefined) return undefined\n return messagesFromEntries(raw.split(\"\\n\"))\n}\n\nfunction messagesFromEntries(lines: readonly string[]): StoredMessage[] {\n const byId = new Map<string, TranscriptEntry>()\n let last: TranscriptEntry | undefined\n for (const line of lines) {\n if (line.trim().length === 0) continue\n let entry: TranscriptEntry\n try {\n entry = JSON.parse(line) as TranscriptEntry\n } catch {\n continue\n }\n if (!entry || typeof entry !== \"object\") continue\n if (typeof entry.id === \"string\") byId.set(entry.id, entry)\n if (entry.type === \"message\" && entry.message) last = entry\n }\n if (!last) return []\n const chain: TranscriptEntry[] = []\n const seen = new Set<string>()\n let cursor: TranscriptEntry | undefined = last\n while (cursor && chain.length < MAX_MESSAGES) {\n if (cursor.type === \"message\" && cursor.message) chain.push(cursor)\n // A compaction entry summarizes everything above it; that is where the model's view starts.\n if (cursor.type === \"compaction\") {\n if (typeof cursor.summary === \"string\" && cursor.summary.length > 0) {\n chain.push({ type: \"message\", message: { role: \"user\", content: `[compaction summary] ${cursor.summary}` } })\n }\n break\n }\n const parentId = cursor.parentId\n if (!parentId || seen.has(parentId)) break\n seen.add(parentId)\n cursor = byId.get(parentId)\n }\n chain.reverse()\n const out: StoredMessage[] = []\n for (const entry of chain) {\n const [message] = normalizeMessages([entry.message])\n if (message) out.push({ message, timestamp: entryTimestamp(entry) })\n }\n return out\n}\n\nfunction entryTimestamp(entry: TranscriptEntry): number | undefined {\n const inner = (entry.message as { timestamp?: unknown } | undefined)?.timestamp\n if (typeof inner === \"number\") return inner\n if (typeof entry.timestamp === \"string\") {\n const parsed = Date.parse(entry.timestamp)\n if (!Number.isNaN(parsed)) return parsed\n }\n return undefined\n}\n","import { readFileSync, statSync } from \"node:fs\"\nimport { isAbsolute, relative, resolve, sep } from \"node:path\"\n\n/**\n * OpenClaw's built-in memory is the agent workspace's `MEMORY.md`, `USER.md`\n * and the Markdown files under `memory/` (daily notes), read through the\n * bundled memory-core tools and written with the generic file tools. Reads and\n * writes surface as OTEL GenAI memory operations, one store per agent\n * (`openclaw/<agentId>`) and one record per file, whose body is the whole\n * file so Latitude's ledger can diff and blame per line.\n */\n\nexport type MemoryOperation = \"search_memory\" | \"upsert_memory\" | \"delete_memory\"\n\nexport interface MemoryRecord {\n id?: string | undefined\n content: unknown\n score?: number\n metadata?: Record<string, unknown>\n}\n\nexport interface MemoryEvent {\n operation: MemoryOperation\n storeId: string\n recordId?: string | undefined\n queryText?: string | undefined\n records: MemoryRecord[]\n /** Set when the body had to come from disk and the read failed. */\n bodyUnavailable?: boolean\n}\n\nexport type FileReader = (path: string) => string | undefined\n\nconst MAX_FILE_BYTES = 1024 * 1024\nconst MEMORY_ROOT_FILES = new Set([\"MEMORY.md\", \"memory.md\", \"USER.md\", \"user.md\"])\nconst MEMORY_DIR = \"memory\"\n\nfunction memoryStoreId(agentId: string | undefined): string {\n return `openclaw/${agentId ?? \"main\"}`\n}\n\nconst defaultFileReader: FileReader = (path) => {\n try {\n if (statSync(path).size > MAX_FILE_BYTES) return undefined\n return readFileSync(path, \"utf8\")\n } catch {\n return undefined\n }\n}\n\n/** Workspace-relative record id for a path inside the memory scope, else undefined. */\nexport function memoryRecordId(path: string | undefined, workspaceDir: string | undefined): string | undefined {\n if (!path) return undefined\n const abs = workspaceDir ? resolve(workspaceDir, path) : isAbsolute(path) ? path : undefined\n if (!abs) return undefined\n const rel = workspaceDir ? relative(workspaceDir, abs) : abs\n if (rel.startsWith(\"..\")) return undefined\n const normalized = rel.split(sep).join(\"/\")\n if (MEMORY_ROOT_FILES.has(normalized)) return normalized\n if (normalized.startsWith(`${MEMORY_DIR}/`) && normalized.endsWith(\".md\")) return normalized\n return undefined\n}\n\ninterface ToolCallShape {\n toolName: string\n params: Record<string, unknown>\n result?: unknown\n error?: string | undefined\n workspaceDir?: string | undefined\n agentId?: string | undefined\n}\n\n/** Classify a finished tool call as memory operations; empty when it touched none. */\nexport function memoryEventsFromToolCall(call: ToolCallShape, readFile: FileReader = defaultFileReader): MemoryEvent[] {\n if (call.error) return []\n if (call.toolName === \"apply_patch\") return patchEvents(call, memoryStoreId(call.agentId), readFile)\n const single = singleMemoryEvent(call, readFile)\n return single ? [single] : []\n}\n\nfunction singleMemoryEvent(call: ToolCallShape, readFile: FileReader): MemoryEvent | undefined {\n const storeId = memoryStoreId(call.agentId)\n switch (call.toolName) {\n case \"memory_search\":\n return {\n operation: \"search_memory\",\n storeId,\n queryText: str(call.params.query),\n records: searchRecords(call.result),\n }\n case \"memory_get\": {\n const path = str(call.params.path)\n const text = resultText(call.result)\n return {\n operation: \"search_memory\",\n storeId,\n recordId: path,\n records: text !== undefined ? [{ id: path, content: text }] : [],\n }\n }\n case \"memory_recall\":\n return {\n operation: \"search_memory\",\n storeId,\n queryText: str(call.params.query),\n records: searchRecords(call.result),\n }\n case \"memory_store\": {\n const text = str(call.params.text) ?? str(call.params.content)\n return { operation: \"upsert_memory\", storeId, records: text !== undefined ? [{ content: text }] : [] }\n }\n case \"memory_forget\":\n return {\n operation: \"delete_memory\",\n storeId,\n recordId: str(call.params.id) ?? str(call.params.query),\n records: [],\n }\n case \"write\":\n case \"edit\":\n return fileWriteEvent(call, storeId, readFile)\n default:\n return undefined\n }\n}\n\nfunction fileWriteEvent(call: ToolCallShape, storeId: string, readFile: FileReader): MemoryEvent | undefined {\n const path = str(call.params.path)\n const recordId = memoryRecordId(path, call.workspaceDir)\n if (!recordId || !path) return undefined\n const abs = call.workspaceDir ? resolve(call.workspaceDir, path) : path\n const body = call.toolName === \"write\" ? str(call.params.content) : readFile(abs)\n return writeEvent(storeId, recordId, body)\n}\n\nfunction writeEvent(storeId: string, recordId: string, body: string | undefined): MemoryEvent {\n if (body === undefined) return { operation: \"upsert_memory\", storeId, recordId, records: [], bodyUnavailable: true }\n if (body.trim().length === 0) return { operation: \"delete_memory\", storeId, recordId, records: [] }\n return { operation: \"upsert_memory\", storeId, recordId, records: [{ id: recordId, content: body }] }\n}\n\nconst PATCH_FILE_LINE = /^\\*\\*\\* (Update|Add|Delete) File: (.+)$/gm\n\n/**\n * Codex's `apply_patch` takes one patch text touching any number of files\n * (`*** Update File: <path>`). Each memory-scoped file becomes its own event,\n * with the body read back from disk after the patch landed.\n */\nfunction patchEvents(call: ToolCallShape, storeId: string, readFile: FileReader): MemoryEvent[] {\n const patch = str(call.params.command) ?? str(call.params.input) ?? str(call.params.patch)\n if (!patch) return []\n const events: MemoryEvent[] = []\n for (const match of patch.matchAll(PATCH_FILE_LINE)) {\n const action = match[1]\n const path = match[2]?.trim()\n const recordId = memoryRecordId(path, call.workspaceDir)\n if (!recordId || !path) continue\n if (action === \"Delete\") {\n events.push({ operation: \"delete_memory\", storeId, recordId, records: [] })\n continue\n }\n const abs = call.workspaceDir ? resolve(call.workspaceDir, path) : path\n events.push(writeEvent(storeId, recordId, readFile(abs)))\n }\n return events\n}\n\n/**\n * The frozen snapshot injected at session start: every non-empty built-in\n * store file, read once per session. Returns undefined when nothing exists.\n */\nexport function memorySnapshot(\n workspaceDir: string | undefined,\n agentId: string | undefined,\n readFile: FileReader = defaultFileReader,\n today: Date = new Date(),\n): MemoryEvent | undefined {\n if (!workspaceDir) return undefined\n const day = today.toISOString().slice(0, 10)\n const candidates = [\"MEMORY.md\", \"USER.md\", `${MEMORY_DIR}/${day}.md`]\n const records: MemoryRecord[] = []\n for (const rel of candidates) {\n const body = readFile(resolve(workspaceDir, rel))\n if (body !== undefined && body.trim().length > 0) records.push({ id: rel, content: body })\n }\n if (records.length === 0) return undefined\n return { operation: \"search_memory\", storeId: memoryStoreId(agentId), records }\n}\n\n// ─── Tool result parsing ────────────────────────────────────────────────────\n\nfunction searchRecords(result: unknown): MemoryRecord[] {\n const details = detailsOf(result)\n const list = Array.isArray(details?.results) ? details.results : undefined\n if (list) {\n const out: MemoryRecord[] = []\n for (const item of list) {\n if (!item || typeof item !== \"object\") continue\n const r = item as Record<string, unknown>\n const path = str(r.path)\n const line = typeof r.startLine === \"number\" ? `#${r.startLine}` : \"\"\n out.push({\n ...(path ? { id: `${path}${line}` } : {}),\n content: str(r.snippet) ?? str(r.text) ?? str(r.content) ?? \"\",\n ...(typeof r.score === \"number\" ? { score: r.score } : {}),\n })\n }\n return out\n }\n const text = resultText(result)\n return text !== undefined && text.length > 0 ? [{ content: text }] : []\n}\n\nfunction detailsOf(result: unknown): Record<string, unknown> | undefined {\n if (!result || typeof result !== \"object\") return undefined\n const details = (result as { details?: unknown }).details\n return details && typeof details === \"object\" ? (details as Record<string, unknown>) : undefined\n}\n\nfunction resultText(result: unknown): string | undefined {\n if (typeof result === \"string\") return result\n if (!result || typeof result !== \"object\") return undefined\n const details = detailsOf(result)\n if (details && typeof details.text === \"string\") return details.text\n const content = (result as { content?: unknown }).content\n if (typeof content === \"string\") return content\n if (Array.isArray(content)) {\n const texts = content\n .map((b) =>\n b && typeof b === \"object\" && typeof (b as { text?: unknown }).text === \"string\"\n ? (b as { text: string }).text\n : \"\",\n )\n .filter((t) => t.length > 0)\n if (texts.length > 0) return texts.join(\"\\n\")\n }\n return undefined\n}\n\nfunction str(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined\n}\n","export interface ToolDefinition {\n type: \"function\"\n name: string\n description: string\n parameters?: unknown\n}\n\n/**\n * `llm_input.tools` is the post-policy tool list offered to the model, as\n * pi-ai `Tool` objects (`name`, `description`, `parameters` JSON schema) plus\n * runtime fields such as `execute` that never leave the process.\n */\nexport function toolDefinitionsFrom(raw: readonly unknown[] | undefined): ToolDefinition[] | undefined {\n if (!raw || raw.length === 0) return undefined\n const out: ToolDefinition[] = []\n for (const item of raw) {\n if (!item || typeof item !== \"object\") continue\n const obj = item as Record<string, unknown>\n const fn = obj.function && typeof obj.function === \"object\" ? (obj.function as Record<string, unknown>) : obj\n if (typeof fn.name !== \"string\" || fn.name.length === 0) continue\n const parameters = fn.parameters ?? fn.inputSchema ?? fn.input_schema\n out.push({\n type: \"function\",\n name: fn.name,\n description: typeof fn.description === \"string\" ? fn.description : \"\",\n ...(parameters !== undefined ? { parameters: plainSchema(parameters) } : {}),\n })\n }\n return out.length > 0 ? out : undefined\n}\n\n// TypeBox schemas carry symbol keys and are otherwise plain JSON; a round trip drops the symbols.\nfunction plainSchema(schema: unknown): unknown {\n try {\n return JSON.parse(JSON.stringify(schema))\n } catch {\n return undefined\n }\n}\n","import type { OpenClawLlmUsage } from \"./types.ts\"\n\nexport type AttrValue = string | number | boolean | unknown[] | Record<string, unknown> | undefined\nexport type AttrInput = Record<string, AttrValue>\n\n/** Shape of `usage` on an OpenClaw transcript assistant message (pi-ai `Usage`). */\nexport interface TranscriptUsage {\n input?: number\n output?: number\n cacheRead?: number\n cacheWrite?: number\n totalTokens?: number\n reasoningTokens?: number\n cost?: {\n input?: number\n output?: number\n cacheRead?: number\n cacheWrite?: number\n total?: number\n totalOrigin?: string\n }\n}\n\nexport interface TranscriptAssistant {\n role: \"assistant\"\n content?: unknown[]\n provider?: string\n model?: string\n responseModel?: string\n responseId?: string\n usage?: TranscriptUsage\n stopReason?: string\n errorMessage?: string\n timestamp?: number\n}\n\nexport function isTranscriptAssistant(raw: unknown): raw is TranscriptAssistant {\n return !!raw && typeof raw === \"object\" && (raw as { role?: unknown }).role === \"assistant\"\n}\n\nconst FINISH_REASONS: Record<string, string> = {\n stop: \"stop\",\n length: \"length\",\n toolUse: \"tool_calls\",\n error: \"error\",\n aborted: \"cancelled\",\n}\n\nexport function finishReason(stopReason: string | undefined): string | undefined {\n if (!stopReason) return undefined\n return FINISH_REASONS[stopReason] ?? stopReason\n}\n\n/**\n * `gen_ai.usage.*` from a transcript message. `output_tokens` stays inclusive\n * of reasoning: Latitude's resolver subtracts `reasoning_tokens` itself.\n */\nexport function usageAttrsFromTranscript(usage: TranscriptUsage | undefined): AttrInput {\n if (!usage) return {}\n const input = num(usage.input)\n const output = num(usage.output)\n const cacheRead = num(usage.cacheRead)\n const cacheWrite = num(usage.cacheWrite)\n const total = num(usage.totalTokens) ?? sumDefined(input, output, cacheRead, cacheWrite)\n return {\n \"gen_ai.usage.input_tokens\": input,\n \"gen_ai.usage.output_tokens\": output,\n \"gen_ai.usage.cache_read.input_tokens\": cacheRead,\n \"gen_ai.usage.cache_creation.input_tokens\": cacheWrite,\n \"gen_ai.usage.reasoning_tokens\": num(usage.reasoningTokens),\n \"gen_ai.usage.total_tokens\": total,\n ...costAttrs(usage.cost),\n }\n}\n\n/** Attempt-aggregate usage from `llm_output`, same keys. */\nexport function usageAttrsFromAggregate(usage: OpenClawLlmUsage | undefined): AttrInput {\n if (!usage) return {}\n const input = num(usage.input)\n const output = num(usage.output)\n const cacheRead = num(usage.cacheRead)\n const cacheWrite = num(usage.cacheWrite)\n return {\n \"gen_ai.usage.input_tokens\": input,\n \"gen_ai.usage.output_tokens\": output,\n \"gen_ai.usage.cache_read.input_tokens\": cacheRead,\n \"gen_ai.usage.cache_creation.input_tokens\": cacheWrite,\n \"gen_ai.usage.total_tokens\": num(usage.total) ?? sumDefined(input, output, cacheRead, cacheWrite),\n }\n}\n\n/**\n * OpenClaw prices every call from its own model catalog (or the provider's\n * bill when `totalOrigin` says so). A positive total is reported as the span's\n * cost so a model missing from Latitude's catalog still carries a price.\n */\nfunction costAttrs(cost: TranscriptUsage[\"cost\"]): AttrInput {\n if (!cost) return {}\n const total = num(cost.total)\n if (total === undefined || total <= 0) return {}\n const inputSide = sumDefined(num(cost.input), num(cost.cacheRead), num(cost.cacheWrite))\n return {\n \"gen_ai.usage.cost\": total,\n \"gen_ai.usage.input_cost\": inputSide,\n \"gen_ai.usage.output_cost\": num(cost.output),\n \"openclaw.cost.origin\": cost.totalOrigin === \"provider-billed\" ? \"provider-billed\" : \"catalog\",\n }\n}\n\nfunction num(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined\n}\n\nfunction sumDefined(...values: Array<number | undefined>): number | undefined {\n const defined = values.filter((v): v is number => v !== undefined)\n if (defined.length === 0) return undefined\n return defined.reduce((a, b) => a + b, 0)\n}\n","import { createHash, randomUUID } from \"node:crypto\"\nimport { type CronJob, cronJobFromSessionKey, deriveEnrichment, type Sender, senderFromPrompt } from \"./context.ts\"\nimport {\n agentDatabasePath,\n type CompactionRecord,\n readLatestCompaction,\n readLatestCompactionFromFile,\n readSessionTranscript,\n readSessionTranscriptFromDatabase,\n SessionHistoryStore,\n sessionTranscriptPath,\n stateDirFromWorkspace,\n type TranscriptReader,\n type TranscriptRowsReader,\n withoutCurrentPrompt,\n} from \"./history.ts\"\nimport { type FileReader, type MemoryEvent, memoryEventsFromToolCall, memorySnapshot } from \"./memory.ts\"\nimport {\n type Message,\n normalizeMessage,\n normalizeMessages,\n systemInstructionsParts,\n userMessageFromPrompt,\n} from \"./messages.ts\"\nimport { type ToolDefinition, toolDefinitionsFrom } from \"./tools.ts\"\nimport type {\n OpenClawAfterCompactionEvent,\n OpenClawAfterToolCallEvent,\n OpenClawAgentContext,\n OpenClawAgentEndEvent,\n OpenClawBeforeCompactionEvent,\n OpenClawBeforeToolCallEvent,\n OpenClawCronChangedEvent,\n OpenClawLlmInputEvent,\n OpenClawLlmOutputEvent,\n OpenClawMessageContext,\n OpenClawMessageReceivedEvent,\n OpenClawModelCallEndedEvent,\n OpenClawModelCallStartedEvent,\n OpenClawSessionScopedContext,\n OpenClawSessionStartEvent,\n OpenClawSubagentContext,\n OpenClawSubagentEndedEvent,\n OpenClawSubagentSpawnedEvent,\n OpenClawToolContext,\n} from \"./types.ts\"\nimport {\n type AttrInput,\n type AttrValue,\n finishReason,\n isTranscriptAssistant,\n type TranscriptAssistant,\n type TranscriptUsage,\n usageAttrsFromAggregate,\n usageAttrsFromTranscript,\n} from \"./usage.ts\"\n\nexport type { AttrValue } from \"./usage.ts\"\n\n/**\n * Builds one trace per OpenClaw agent run from the typed plugin hooks:\n *\n * interaction (root, invoke_agent)\n * ├── search_memory (once per session: the snapshot injected at session start)\n * ├── llm_request (chat; one per provider call, per-call usage + cost + messages)\n * ├── tool_call:<name> (execute_tool; sibling of llm_request, tools run between calls)\n * │ └── search_memory / upsert_memory / delete_memory (memory tools and memory file writes)\n * ├── tool_call:sessions_spawn\n * │ └── subagent (spawn → ended; the child run's interaction nests underneath)\n * ├── compaction\n * └── llm_request\n *\n * No hook announces a run before `llm_input`, so the root opens lazily on the\n * first event that carries a run id. `agent_end` carries the whole transcript,\n * which is where per-call usage, cost and output content come from; it fires\n * before `llm_output`, so finalization waits for the latter or a short grace.\n */\n\nexport interface SpanRecord {\n spanId: string\n traceId: string\n parentSpanId: string\n name: string\n /** OTel SpanKind: 1 INTERNAL, 3 CLIENT. */\n kind: number\n startMs: number\n endMs: number | undefined\n attrs: Record<string, AttrValue>\n outcome?: \"ok\" | \"error\"\n errorMessage?: string | undefined\n}\n\nexport interface BuildResult {\n runId: string\n spans: SpanRecord[]\n}\n\ninterface SpanBuilderOptions {\n emit: (result: BuildResult) => void\n pluginVersion: string\n tags?: readonly string[]\n metadata?: Readonly<Record<string, string>>\n memory?: boolean\n memoryContent?: boolean\n toolDefinitions?: boolean\n now?: (() => number) | undefined\n schedule?: ((fn: () => void, ms: number) => () => void) | undefined\n readFile?: FileReader | undefined\n readTranscript?: TranscriptReader | undefined\n readTranscriptRows?: TranscriptRowsReader | undefined\n /** OpenClaw's state dir, when the host exposes it; otherwise derived from the workspace dir. */\n stateDir?: string | undefined\n log?: ((msg: string) => void) | undefined\n}\n\ninterface RunState {\n runId: string\n ctx: OpenClawAgentContext\n traceId: string\n root: SpanRecord\n startedAt: number\n history: Message[]\n inputMessages: Message[]\n /** History rebuilt by the plugin when the harness passed none; prepended to every input. */\n inheritedHistory: Message[]\n historySource: \"harness\" | \"memory\" | \"sqlite\" | \"file\" | \"none\"\n /** Timestamps of streamed assistant/thinking deltas, for time to first token. */\n deltas: number[]\n /** Streamed reasoning text, for harnesses whose transcript omits it. */\n thinking: Array<{ ts: number; text: string }>\n thinkingChars: number\n prompt: string | undefined\n systemPrompt: string | undefined\n toolDefinitions: ToolDefinition[] | undefined\n llmCalls: SpanRecord[]\n openModelCalls: Map<string, SpanRecord>\n openToolCalls: Map<string, SpanRecord>\n openCompaction: SpanRecord | undefined\n closed: SpanRecord[]\n lastSpawnToolSpanId: string | undefined\n subagentIds: string[]\n sender: Sender | undefined\n cron: CronJob | undefined\n link: SubagentLink | undefined\n aggregateUsage: AttrInput\n output:\n | {\n resolvedRef?: string | undefined\n harnessId?: string | undefined\n reasoningEffort?: string | undefined\n lastAssistant?: unknown\n }\n | undefined\n endEvent: OpenClawAgentEndEvent | undefined\n outputSeen: boolean\n finalized: boolean\n cancelGrace: (() => void) | undefined\n}\n\ninterface SubagentLink {\n traceId: string\n parentSpanId: string\n parentRunId: string\n sessionId: string | undefined\n agentName: string | undefined\n createdAt: number\n}\n\ninterface PendingSubagent {\n span: SpanRecord\n parentRunId: string\n createdAt: number\n}\n\nconst GRACE_MS = 1500\nconst RUN_TTL_MS = 2 * 60 * 60 * 1000\nconst LINK_TTL_MS = 60 * 60 * 1000\nconst LINK_MAX = 1000\nconst SESSION_INDEX_MAX = 2000\nconst STANDALONE_COMPACTION_MAX = 100\nconst SPAWN_TOOL_PATTERN = /spawn/i\nconst MAX_DELTAS = 256\nconst MAX_THINKING_CHARS = 64 * 1024\nconst KIND_INTERNAL = 1\nconst KIND_CLIENT = 3\n\nexport class SpanBuilder {\n private readonly runs = new Map<string, RunState>()\n private readonly runsBySession = new Map<string, string[]>()\n private readonly subagentLinks = new Map<string, SubagentLink>()\n private readonly pendingSubagents = new Map<string, PendingSubagent>()\n private readonly sessionIds = new Map<string, string>()\n private readonly modelBySession = new Map<string, { provider: string; model: string }>()\n private readonly workspaceBySession = new Map<string, string>()\n private readonly memorySnapshotSessions = new Set<string>()\n private readonly senders = new Map<string, Map<string, Sender>>()\n private readonly sendersById = new Map<string, Sender>()\n private readonly cronStarted = new Map<string, CronJob>()\n private readonly sessionHistory: SessionHistoryStore\n private readonly standaloneCompactions = new Map<string, SpanRecord>()\n private readonly emit: (result: BuildResult) => void\n private readonly now: () => number\n private readonly schedule: (fn: () => void, ms: number) => () => void\n private readonly readFile: FileReader | undefined\n private readonly readTranscript: TranscriptReader | undefined\n private readonly readTranscriptRows: TranscriptRowsReader | undefined\n private readonly stateDir: string | undefined\n private readonly log: (msg: string) => void\n private readonly pluginVersion: string\n private readonly operatorTags: readonly string[]\n private readonly operatorMetadata: Readonly<Record<string, string>>\n private readonly memoryEnabled: boolean\n private readonly memoryContent: boolean\n private readonly toolDefinitionsEnabled: boolean\n\n constructor(options: SpanBuilderOptions) {\n this.emit = options.emit\n this.now = options.now ?? (() => Date.now())\n this.schedule =\n options.schedule ??\n ((fn, ms) => {\n const timer = setTimeout(fn, ms)\n timer.unref?.()\n return () => clearTimeout(timer)\n })\n this.readFile = options.readFile\n this.readTranscript = options.readTranscript\n this.readTranscriptRows = options.readTranscriptRows\n this.stateDir = options.stateDir\n this.sessionHistory = new SessionHistoryStore(this.now)\n this.log = options.log ?? (() => {})\n this.pluginVersion = options.pluginVersion\n this.operatorTags = options.tags ?? []\n this.operatorMetadata = options.metadata ?? {}\n this.memoryEnabled = options.memory ?? true\n this.memoryContent = options.memoryContent ?? true\n this.toolDefinitionsEnabled = options.toolDefinitions ?? true\n }\n\n inflightCount(): number {\n return this.runs.size\n }\n\n subagentLinkCount(): number {\n return this.subagentLinks.size\n }\n\n // ─── Run lifecycle ────────────────────────────────────────────────────────\n\n onLlmInput(evt: OpenClawLlmInputEvent, ctx: OpenClawAgentContext): void {\n const run = this.ensureRun(evt.runId, ctx)\n if (!run) return\n const harnessHistory = normalizeMessages(evt.historyMessages)\n if (harnessHistory.length > 0) {\n run.inheritedHistory = []\n run.historySource = \"harness\"\n } else {\n this.inheritHistory(run, evt.prompt)\n }\n run.history = [...run.inheritedHistory, ...harnessHistory]\n if (evt.prompt) run.history.push(userMessageFromPrompt(evt.prompt))\n run.inputMessages = [...run.history]\n run.prompt = evt.prompt\n run.systemPrompt = evt.systemPrompt\n if (run.ctx.sessionKey) {\n remember(this.modelBySession, run.ctx.sessionKey, { provider: evt.provider, model: evt.model }, SESSION_INDEX_MAX)\n if (run.ctx.workspaceDir) {\n remember(this.workspaceBySession, run.ctx.sessionKey, run.ctx.workspaceDir, SESSION_INDEX_MAX)\n }\n }\n if (this.toolDefinitionsEnabled) run.toolDefinitions = toolDefinitionsFrom(evt.tools) ?? run.toolDefinitions\n Object.assign(run.root.attrs, {\n \"gen_ai.request.model\": evt.model,\n \"openclaw.provider\": evt.provider,\n \"openclaw.images.count\": evt.imagesCount,\n \"openclaw.tool_count\": evt.tools?.length,\n })\n this.recordMemorySnapshot(run)\n }\n\n onLlmOutput(evt: OpenClawLlmOutputEvent, ctx: OpenClawAgentContext): void {\n const run = this.runs.get(ctx.runId ?? evt.runId)\n if (!run) return\n this.mergeCtx(run, ctx)\n run.outputSeen = true\n run.aggregateUsage = usageAttrsFromAggregate(evt.usage)\n run.output = {\n resolvedRef: evt.resolvedRef,\n harnessId: evt.harnessId,\n reasoningEffort: evt.reasoningEffort,\n lastAssistant: evt.lastAssistant,\n }\n Object.assign(run.root.attrs, {\n \"gen_ai.response.model\": evt.model,\n \"openclaw.resolved.ref\": evt.resolvedRef,\n \"openclaw.harness.id\": evt.harnessId,\n \"openclaw.reasoning.effort\": evt.reasoningEffort,\n })\n if (run.endEvent) this.finalize(run)\n }\n\n onAgentEnd(evt: OpenClawAgentEndEvent, ctx: OpenClawAgentContext): void {\n const runId = ctx.runId ?? evt.runId\n if (!runId) return\n const run = this.runs.get(runId)\n if (!run) {\n this.subagentLinks.delete(runId)\n return\n }\n this.mergeCtx(run, ctx)\n run.endEvent = evt\n if (run.outputSeen) {\n this.finalize(run)\n return\n }\n run.cancelGrace = this.schedule(() => this.finalize(run), GRACE_MS)\n }\n\n // ─── Model calls ──────────────────────────────────────────────────────────\n\n onModelCallStarted(evt: OpenClawModelCallStartedEvent, ctx: OpenClawAgentContext): void {\n const run = this.ensureRun(evt.runId, {\n ...ctx,\n sessionId: ctx.sessionId ?? evt.sessionId,\n sessionKey: ctx.sessionKey ?? evt.sessionKey,\n })\n if (!run) return\n const span: SpanRecord = {\n spanId: hashHex(`${run.runId}:llm_request:${evt.callId}`, 16),\n traceId: run.traceId,\n parentSpanId: run.root.spanId,\n name: \"llm_request\",\n kind: KIND_INTERNAL,\n startMs: this.now(),\n endMs: undefined,\n attrs: {\n \"gen_ai.operation.name\": \"chat\",\n \"gen_ai.provider.name\": evt.provider,\n \"gen_ai.system\": evt.provider,\n \"gen_ai.request.model\": evt.model,\n \"gen_ai.request.stream\": true,\n \"openclaw.call.id\": evt.callId,\n \"openclaw.api\": evt.api,\n \"openclaw.transport\": evt.transport,\n \"openclaw.context.token_budget\": evt.contextTokenBudget,\n \"llm_request.call_index\": run.llmCalls.length + run.openModelCalls.size,\n \"gen_ai.input.messages:gated\": [...run.history],\n \"gen_ai.system_instructions:gated\": run.systemPrompt ? systemInstructionsParts(run.systemPrompt) : undefined,\n \"gen_ai.tool.definitions:gated\": run.toolDefinitions,\n },\n }\n run.openModelCalls.set(evt.callId, span)\n }\n\n onModelCallEnded(evt: OpenClawModelCallEndedEvent, _ctx: OpenClawAgentContext): void {\n const run = this.runs.get(evt.runId)\n if (!run) return\n const span = run.openModelCalls.get(evt.callId)\n if (!span) return\n span.endMs = this.now()\n span.outcome = evt.outcome === \"completed\" ? \"ok\" : \"error\"\n span.errorMessage = evt.errorCategory\n Object.assign(span.attrs, {\n \"openclaw.duration_ms\": evt.durationMs,\n \"openclaw.outcome\": evt.outcome,\n \"openclaw.error.category\": evt.errorCategory,\n \"openclaw.failure.kind\": evt.failureKind,\n \"error.type\": evt.outcome === \"error\" ? (evt.errorCategory ?? evt.failureKind ?? \"error\") : undefined,\n \"openclaw.request.payload_bytes\": evt.requestPayloadBytes,\n \"openclaw.response.stream_bytes\": evt.responseStreamBytes,\n \"openclaw.ttfb_ms\": evt.timeToFirstByteMs,\n \"gen_ai.server.time_to_first_token\":\n evt.timeToFirstByteMs !== undefined && evt.timeToFirstByteMs > 0\n ? Math.round(evt.timeToFirstByteMs * 1_000_000)\n : undefined,\n \"openclaw.upstream.request_id_hash\": evt.upstreamRequestIdHash,\n })\n run.openModelCalls.delete(evt.callId)\n run.llmCalls.push(span)\n }\n\n // ─── Tools ────────────────────────────────────────────────────────────────\n\n onBeforeToolCall(evt: OpenClawBeforeToolCallEvent, ctx: OpenClawToolContext): void {\n const runId = evt.runId ?? ctx.runId\n if (!runId) return\n const run = this.ensureRun(runId, toolCtxToAgentCtx(ctx, runId))\n if (!run) return\n const toolCallId = evt.toolCallId ?? ctx.toolCallId ?? `${evt.toolName}:${randomUUID()}`\n const span: SpanRecord = {\n spanId: hashHex(`${run.runId}:tool_call:${toolCallId}`, 16),\n traceId: run.traceId,\n parentSpanId: run.root.spanId,\n name: `tool_call:${evt.toolName}`,\n kind: KIND_CLIENT,\n startMs: this.now(),\n endMs: undefined,\n attrs: {\n \"gen_ai.operation.name\": \"execute_tool\",\n \"gen_ai.tool.name\": evt.toolName,\n \"gen_ai.tool.call.id\": toolCallId,\n \"gen_ai.tool.call.arguments:gated\": evt.params,\n },\n }\n run.openToolCalls.set(toolCallId, span)\n run.history.push({\n role: \"assistant\",\n parts: [{ type: \"tool_call\", id: toolCallId, name: evt.toolName, arguments: evt.params }],\n })\n if (SPAWN_TOOL_PATTERN.test(evt.toolName)) run.lastSpawnToolSpanId = span.spanId\n }\n\n onAfterToolCall(evt: OpenClawAfterToolCallEvent, ctx: OpenClawToolContext): void {\n const runId = evt.runId ?? ctx.runId\n if (!runId) return\n const run = this.runs.get(runId)\n if (!run) return\n let resolvedId = evt.toolCallId && run.openToolCalls.has(evt.toolCallId) ? evt.toolCallId : undefined\n if (!resolvedId) resolvedId = this.findOpenToolCallByName(run, evt.toolName)\n if (!resolvedId) return\n const span = run.openToolCalls.get(resolvedId)\n if (!span) return\n\n span.endMs = this.now()\n const isError = Boolean(evt.error)\n span.outcome = isError ? \"error\" : \"ok\"\n span.errorMessage = evt.error\n Object.assign(span.attrs, {\n \"gen_ai.tool.call.result:gated\": evt.result,\n \"tool.is_error\": isError,\n \"error.type\": isError ? \"tool_error\" : undefined,\n \"error.message:gated\": evt.error,\n \"openclaw.duration_ms\": evt.durationMs,\n })\n run.openToolCalls.delete(resolvedId)\n run.closed.push(span)\n run.history.push({\n role: \"tool\",\n parts: [\n { type: \"tool_call_response\", id: resolvedId, name: evt.toolName, response: evt.result ?? evt.error ?? \"\" },\n ],\n })\n\n if (this.memoryEnabled) {\n const events = memoryEventsFromToolCall(\n {\n toolName: evt.toolName,\n params: evt.params,\n result: evt.result,\n error: evt.error,\n workspaceDir: run.ctx.workspaceDir,\n agentId: run.ctx.agentId,\n },\n this.readFile,\n )\n for (const memory of events) run.closed.push(this.memorySpan(run, memory, span))\n }\n }\n\n // ─── Compaction (keyed by session, no run id on the hook) ─────────────────\n\n /**\n * A compaction is a model call of its own: the compacted messages go in and\n * a summary comes out, so it is exported as a `chat` span. OpenClaw fires no\n * per-call hooks for the summarizer, so its usage is unreported.\n */\n onBeforeCompaction(evt: OpenClawBeforeCompactionEvent, ctx: OpenClawSessionScopedContext): void {\n const run = this.openRunForSession(ctx.sessionKey)\n const startMs = this.now()\n const traceId = run?.traceId ?? hashHex(`${ctx.sessionKey ?? \"unknown\"}:compaction:${startMs}`, 32)\n const model = ctx.sessionKey ? this.modelBySession.get(ctx.sessionKey) : undefined\n const span: SpanRecord = {\n spanId: hashHex(`${traceId}:compaction:${startMs}`, 16),\n traceId,\n parentSpanId: run?.root.spanId ?? \"\",\n name: \"compaction\",\n kind: KIND_INTERNAL,\n startMs,\n endMs: undefined,\n attrs: {\n \"gen_ai.operation.name\": \"chat\",\n \"gen_ai.provider.name\": model?.provider,\n \"gen_ai.system\": model?.provider,\n \"gen_ai.request.model\": model?.model,\n \"openclaw.usage.state\": \"unreported\",\n \"openclaw.compaction.message_count.before\": evt.messageCount,\n \"openclaw.compaction.compacting_count\": evt.compactingCount,\n \"openclaw.compaction.token_count.before\": evt.tokenCount,\n \"openclaw.compaction.session_file\": evt.sessionFile,\n \"openclaw.session.key\": ctx.sessionKey,\n \"gen_ai.input.messages:gated\": evt.messages ? normalizeMessages(evt.messages) : undefined,\n },\n }\n if (run) {\n run.openCompaction = span\n return\n }\n remember(this.standaloneCompactions, ctx.sessionKey ?? \"\", span, STANDALONE_COMPACTION_MAX)\n }\n\n onAfterCompaction(evt: OpenClawAfterCompactionEvent, ctx: OpenClawSessionScopedContext): void {\n const run = this.openRunForSession(ctx.sessionKey)\n const span = run?.openCompaction ?? this.standaloneCompactions.get(ctx.sessionKey ?? \"\")\n if (!span) return\n const endMs = this.now()\n span.endMs = endMs\n span.outcome = \"ok\"\n const sessionId =\n ctx.sessionId ?? run?.ctx.sessionId ?? (ctx.sessionKey ? this.sessionIds.get(ctx.sessionKey) : undefined)\n const agentId = ctx.agentId ?? run?.ctx.agentId ?? agentIdFromSessionKey(ctx.sessionKey)\n const workspaceDir =\n run?.ctx.workspaceDir ?? (ctx.sessionKey ? this.workspaceBySession.get(ctx.sessionKey) : undefined)\n const record = this.latestCompaction(sessionId, agentId, workspaceDir)\n Object.assign(span.attrs, {\n \"openclaw.compaction.message_count.after\": evt.messageCount,\n \"openclaw.compaction.compacted_count\": evt.compactedCount,\n \"openclaw.compaction.token_count.after\": evt.tokenCount ?? record?.tokensAfter,\n \"openclaw.compaction.token_count.before\":\n span.attrs[\"openclaw.compaction.token_count.before\"] ?? record?.tokensBefore,\n \"openclaw.compaction.previous_session_id\": evt.previousSessionId,\n \"openclaw.compaction.summary_chars\": record?.summary.length,\n \"gen_ai.output.messages:gated\": record\n ? [{ role: \"assistant\", parts: [{ type: \"text\", content: record.summary }] }]\n : undefined,\n })\n if (run?.openCompaction === span) {\n run.openCompaction = undefined\n run.closed.push(span)\n return\n }\n this.standaloneCompactions.delete(ctx.sessionKey ?? \"\")\n\n const runCtx: OpenClawAgentContext = { agentId, sessionKey: ctx.sessionKey, sessionId, workspaceDir }\n const enrichment = deriveEnrichment(\n { ctx: runCtx, subagentIds: [], pluginVersion: this.pluginVersion },\n { tags: this.operatorTags, metadata: this.operatorMetadata },\n )\n const compacted = evt.compactedCount ?? 0\n const root: SpanRecord = {\n spanId: hashHex(`${span.traceId}:compaction-root`, 16),\n traceId: span.traceId,\n parentSpanId: \"\",\n name: \"compaction\",\n kind: KIND_INTERNAL,\n startMs: span.startMs,\n endMs,\n outcome: \"ok\",\n attrs: {\n \"gen_ai.operation.name\": \"invoke_agent\",\n \"interaction.kind\": \"compaction\",\n \"interaction.duration_ms\": endMs - span.startMs,\n \"user_prompt:gated\": `[compaction] ${compacted} messages summarized, ${evt.messageCount} kept`,\n \"gen_ai.output.messages:gated\": span.attrs[\"gen_ai.output.messages:gated\"],\n \"openclaw.outcome\": \"completed\",\n \"openclaw.llm_calls\": 1,\n \"openclaw.tool_calls\": 0,\n },\n }\n span.parentSpanId = root.spanId\n const common: AttrInput = {\n ...sessionAttrs(sessionId),\n \"openclaw.session.id\": sessionId,\n \"openclaw.session.key\": ctx.sessionKey,\n \"openclaw.agent.id\": agentId,\n \"gen_ai.agent.name\": agentId,\n \"openclaw.workspace.dir\": workspaceDir,\n \"latitude.tags\": enrichment.tags,\n \"latitude.metadata\": enrichment.metadata,\n }\n for (const target of [root, span]) {\n for (const [k, v] of Object.entries(common)) {\n if (target.attrs[k] === undefined) target.attrs[k] = v\n }\n }\n this.emit({ runId: `compaction:${span.spanId}`, spans: [root, span] })\n }\n\n private latestCompaction(\n sessionId: string | undefined,\n agentId: string | undefined,\n workspaceDir: string | undefined,\n ): CompactionRecord | undefined {\n const stateDir = this.stateDir ?? stateDirFromWorkspace(workspaceDir)\n if (!sessionId || !agentId || !stateDir) return undefined\n return (\n readLatestCompaction(agentDatabasePath(stateDir, agentId), sessionId, this.readTranscriptRows) ??\n readLatestCompactionFromFile(sessionTranscriptPath(stateDir, agentId, sessionId), this.readTranscript)\n )\n }\n\n // ─── Sessions, senders, cron ──────────────────────────────────────────────\n\n onSessionStart(evt: OpenClawSessionStartEvent, _ctx: OpenClawSessionScopedContext): void {\n if (evt.sessionKey) {\n remember(this.sessionIds, evt.sessionKey, evt.sessionId, SESSION_INDEX_MAX)\n this.memorySnapshotSessions.delete(evt.sessionKey)\n }\n }\n\n onSessionEnd(sessionKey: string | undefined, sessionId?: string): void {\n if (sessionId) this.sessionHistory.forget(sessionId)\n if (!sessionKey) return\n this.memorySnapshotSessions.delete(sessionKey)\n this.senders.delete(sessionKey)\n }\n\n onMessageReceived(evt: OpenClawMessageReceivedEvent, ctx: OpenClawMessageContext): void {\n const sessionKey = evt.sessionKey ?? ctx.sessionKey\n const id = evt.senderId ?? evt.metadata?.senderId ?? ctx.senderId\n if (!sessionKey || !id) return\n let bySender = this.senders.get(sessionKey)\n if (!bySender) {\n bySender = new Map()\n this.senders.set(sessionKey, bySender)\n }\n const sender = { id, name: evt.metadata?.senderName, username: evt.metadata?.senderUsername }\n bySender.set(id, sender)\n if (sender.name || sender.username) this.sendersById.set(id, sender)\n }\n\n /**\n * Streamed agent events: `lifecycle` start gives the run's true start before\n * any hook fires, and the first `assistant` / `thinking` delta after a model\n * call started is its time to first token, which the Codex harness reports\n * nowhere else.\n */\n onAgentEvent(evt: {\n runId?: string\n stream?: string\n ts?: number\n data?: Record<string, unknown>\n sessionKey?: string\n sessionId?: string\n agentId?: string\n }): void {\n if (!evt.runId || !evt.stream) return\n if (evt.stream === \"lifecycle\") {\n if (evt.data?.phase !== \"start\") return\n const startedAt = typeof evt.data.startedAt === \"number\" ? evt.data.startedAt : evt.ts\n const run = this.ensureRun(evt.runId, {\n runId: evt.runId,\n sessionKey: evt.sessionKey,\n sessionId: evt.sessionId,\n agentId: evt.agentId,\n })\n if (run && startedAt !== undefined && startedAt < run.startedAt) {\n run.startedAt = startedAt\n run.root.startMs = startedAt\n }\n return\n }\n if (evt.stream !== \"assistant\" && evt.stream !== \"thinking\") return\n const delta = evt.data?.delta\n if (typeof delta !== \"string\" || delta.length === 0) return\n const run = this.runs.get(evt.runId)\n if (!run) return\n const ts = evt.ts ?? this.now()\n if (run.deltas.length < MAX_DELTAS) run.deltas.push(ts)\n if (evt.stream === \"thinking\" && run.thinkingChars < MAX_THINKING_CHARS) {\n run.thinking.push({ ts, text: delta })\n run.thinkingChars += delta.length\n }\n }\n\n onCronChanged(evt: OpenClawCronChangedEvent): void {\n const agentId = evt.agentId ?? evt.job?.agentId ?? \"main\"\n const job = { id: evt.jobId, name: evt.job?.name }\n if (evt.action === \"started\" || evt.action === \"added\" || evt.action === \"updated\") {\n this.cronStarted.set(`job:${evt.jobId}`, job)\n }\n if (evt.action === \"started\") {\n this.cronStarted.set(agentId, job)\n if (evt.sessionKey) this.cronStarted.set(`session:${evt.sessionKey}`, job)\n return\n }\n if (evt.action === \"finished\") {\n if (this.cronStarted.get(agentId)?.id === evt.jobId) this.cronStarted.delete(agentId)\n if (evt.sessionKey) this.cronStarted.delete(`session:${evt.sessionKey}`)\n }\n if (evt.action === \"removed\") this.cronStarted.delete(`job:${evt.jobId}`)\n }\n\n // ─── Subagents ────────────────────────────────────────────────────────────\n\n onSubagentSpawned(evt: OpenClawSubagentSpawnedEvent, ctx: OpenClawSubagentContext): void {\n const parent = this.openRunForSession(ctx.requesterSessionKey)\n const childRunId = evt.runId ?? ctx.runId\n if (!childRunId) return\n this.evictStale()\n const traceId = parent?.traceId ?? hashHex(childRunId, 32)\n const parentSpanId = parent ? (parent.lastSpawnToolSpanId ?? parent.root.spanId) : \"\"\n const agentName = evt.label ?? evt.agentId\n const span: SpanRecord = {\n spanId: hashHex(`${childRunId}:subagent`, 16),\n traceId,\n parentSpanId,\n name: \"subagent\",\n kind: KIND_INTERNAL,\n startMs: this.now(),\n endMs: undefined,\n attrs: {\n ...(parent ? this.commonAttrs(parent) : {}),\n \"gen_ai.agent.name\": agentName,\n \"subagent.name\": agentName,\n \"subagent.type\": evt.agentId,\n \"subagent.id\": `${evt.agentId}:${childRunId}`,\n \"openclaw.run.id\": childRunId,\n \"openclaw.parent.run.id\": parent?.runId,\n \"openclaw.subagent.child_session_key\": evt.childSessionKey,\n \"openclaw.subagent.agent_id\": evt.agentId,\n \"openclaw.subagent.label\": evt.label,\n \"openclaw.subagent.mode\": evt.mode,\n \"openclaw.subagent.thread_requested\": evt.threadRequested,\n \"openclaw.subagent.resolved_model\": evt.resolvedModel,\n \"openclaw.subagent.resolved_provider\": evt.resolvedProvider,\n \"openclaw.subagent.requester.channel\": evt.requester?.channel,\n \"openclaw.subagent.requester.account_id\": evt.requester?.accountId,\n \"openclaw.subagent.requester.to\": evt.requester?.to,\n \"openclaw.subagent.requester.thread_id\":\n evt.requester?.threadId !== undefined ? String(evt.requester.threadId) : undefined,\n ...sessionAttrs(parent?.ctx.sessionId),\n },\n }\n if (parent) {\n parent.subagentIds.push(evt.agentId)\n parent.lastSpawnToolSpanId = undefined\n }\n this.pendingSubagents.set(childRunId, { span, parentRunId: parent?.runId ?? \"\", createdAt: this.now() })\n this.subagentLinks.set(childRunId, {\n traceId,\n parentSpanId: span.spanId,\n parentRunId: parent?.runId ?? \"\",\n sessionId: parent?.ctx.sessionId,\n agentName,\n createdAt: this.now(),\n })\n const child = this.runs.get(childRunId)\n if (child) this.applyLink(child)\n }\n\n onSubagentEnded(evt: OpenClawSubagentEndedEvent, ctx: OpenClawSubagentContext): void {\n const childRunId = evt.runId ?? ctx.runId\n if (!childRunId) return\n const pending = this.pendingSubagents.get(childRunId)\n if (!pending) return\n const span = pending.span\n span.endMs = evt.endedAt ?? this.now()\n const isError = evt.outcome === \"error\" || evt.outcome === \"timeout\" || Boolean(evt.error)\n span.outcome = isError ? \"error\" : \"ok\"\n span.errorMessage = evt.error\n Object.assign(span.attrs, {\n \"openclaw.subagent.target_session_key\": evt.targetSessionKey,\n \"openclaw.subagent.target_kind\": evt.targetKind,\n \"openclaw.subagent.reason\": evt.reason,\n \"openclaw.subagent.outcome\": evt.outcome,\n \"openclaw.subagent.send_farewell\": evt.sendFarewell,\n \"openclaw.subagent.account_id\": evt.accountId,\n \"error.type\": isError ? (evt.outcome ?? \"error\") : undefined,\n \"error.message:gated\": evt.error,\n })\n this.pendingSubagents.delete(childRunId)\n this.emitSubagentSpan(span, pending.parentRunId)\n }\n\n // ─── Internals ────────────────────────────────────────────────────────────\n\n private ensureRun(runId: string, ctx: OpenClawAgentContext): RunState | undefined {\n const existing = this.runs.get(runId)\n if (existing) {\n this.mergeCtx(existing, ctx)\n return existing\n }\n this.evictStale()\n const startedAt = this.now()\n const link = this.subagentLinks.get(runId)\n const traceId = link?.traceId ?? hashHex(runId, 32)\n const root: SpanRecord = {\n spanId: hashHex(`${runId}:interaction`, 16),\n traceId,\n parentSpanId: link?.parentSpanId ?? \"\",\n name: \"interaction\",\n kind: KIND_INTERNAL,\n startMs: startedAt,\n endMs: undefined,\n attrs: { \"gen_ai.operation.name\": \"invoke_agent\", \"openclaw.run.id\": runId },\n }\n const run: RunState = {\n runId,\n ctx: { ...ctx, runId },\n traceId,\n root,\n startedAt,\n history: [],\n inputMessages: [],\n inheritedHistory: [],\n historySource: \"none\",\n deltas: [],\n thinking: [],\n thinkingChars: 0,\n prompt: undefined,\n systemPrompt: undefined,\n toolDefinitions: undefined,\n llmCalls: [],\n openModelCalls: new Map(),\n openToolCalls: new Map(),\n openCompaction: undefined,\n closed: [],\n lastSpawnToolSpanId: undefined,\n subagentIds: [],\n sender: undefined,\n cron: undefined,\n link,\n aggregateUsage: {},\n output: undefined,\n endEvent: undefined,\n outputSeen: false,\n finalized: false,\n cancelGrace: undefined,\n }\n this.runs.set(runId, run)\n this.indexSession(run)\n this.resolveSender(run)\n this.resolveCron(run)\n return run\n }\n\n private mergeCtx(run: RunState, ctx: OpenClawAgentContext): void {\n let changed = false\n for (const [key, value] of Object.entries(ctx) as Array<[keyof OpenClawAgentContext, unknown]>) {\n if (value === undefined || value === null || value === \"\") continue\n if (run.ctx[key] === undefined) {\n ;(run.ctx as Record<string, unknown>)[key] = value\n changed = true\n }\n }\n if (!changed) return\n this.indexSession(run)\n this.resolveSender(run)\n this.resolveCron(run)\n }\n\n private indexSession(run: RunState): void {\n const key = run.ctx.sessionKey\n if (!key) return\n if (run.ctx.sessionId) remember(this.sessionIds, key, run.ctx.sessionId, SESSION_INDEX_MAX)\n const list = this.runsBySession.get(key) ?? []\n if (!list.includes(run.runId)) {\n list.push(run.runId)\n this.runsBySession.set(key, list)\n }\n }\n\n private resolveSender(run: RunState): void {\n if (run.sender?.name) return\n const id = run.ctx.senderId\n if (!id) return\n const cached =\n (run.ctx.sessionKey ? this.senders.get(run.ctx.sessionKey)?.get(id) : undefined) ?? this.sendersById.get(id)\n if (cached?.name) {\n run.sender = cached\n return\n }\n const fromPrompt = senderFromPrompt(run.prompt)\n run.sender = fromPrompt && fromPrompt.id === id ? fromPrompt : (cached ?? { id })\n if (run.sender.name) this.sendersById.set(id, run.sender)\n }\n\n private resolveCron(run: RunState): void {\n if (run.cron?.name || run.ctx.trigger !== \"cron\") return\n const fromKey = cronJobFromSessionKey(run.ctx.sessionKey)\n const bySession = run.ctx.sessionKey ? this.cronStarted.get(`session:${run.ctx.sessionKey}`) : undefined\n const job = fromKey\n ? (this.cronStarted.get(`job:${fromKey}`) ?? { id: fromKey })\n : (bySession ?? this.cronStarted.get(run.ctx.agentId ?? \"main\"))\n if (!job) return\n run.cron = job.name ? job : { id: job.id, name: cronNameFromPrompt(run.prompt, job.id) }\n }\n\n /**\n * History the harness withheld. The Codex harness passes an empty history\n * and only this turn's transcript, so the session is rebuilt from the turns\n * this process has seen, or from OpenClaw's transcript mirror on a cold start.\n */\n private inheritHistory(run: RunState, prompt: string | undefined): void {\n const sessionId = run.ctx.sessionId\n if (!sessionId) return\n const remembered = this.sessionHistory.get(sessionId)\n if (remembered) {\n run.inheritedHistory = [...remembered]\n run.historySource = \"memory\"\n return\n }\n const stateDir = this.stateDir ?? stateDirFromWorkspace(run.ctx.workspaceDir)\n const agentId = run.ctx.agentId\n if (!stateDir || !agentId) return\n const fromDatabase = readSessionTranscriptFromDatabase(\n agentDatabasePath(stateDir, agentId),\n sessionId,\n this.readTranscriptRows,\n )\n const stored =\n fromDatabase && fromDatabase.length > 0\n ? { messages: fromDatabase, source: \"sqlite\" as const }\n : {\n messages: readSessionTranscript(sessionTranscriptPath(stateDir, agentId, sessionId), this.readTranscript),\n source: \"file\" as const,\n }\n if (!stored.messages) return\n run.inheritedHistory = withoutCurrentPrompt(stored.messages, prompt, run.startedAt)\n run.historySource = stored.source\n }\n\n private openRunForSession(sessionKey: string | undefined): RunState | undefined {\n if (!sessionKey) return undefined\n const ids = this.runsBySession.get(sessionKey)\n if (!ids) return undefined\n for (let i = ids.length - 1; i >= 0; i--) {\n const run = this.runs.get(ids[i] as string)\n if (run && !run.finalized) return run\n }\n return undefined\n }\n\n private recordMemorySnapshot(run: RunState): void {\n if (!this.memoryEnabled) return\n const key = run.ctx.sessionKey ?? run.ctx.sessionId\n if (!key || this.memorySnapshotSessions.has(key)) return\n this.memorySnapshotSessions.add(key)\n const snapshot = memorySnapshot(run.ctx.workspaceDir, run.ctx.agentId, this.readFile)\n if (!snapshot) return\n const span = this.memorySpan(run, snapshot, undefined)\n span.attrs[\"openclaw.memory.source\"] = \"session_snapshot\"\n run.closed.push(span)\n }\n\n private memorySpan(run: RunState, memory: MemoryEvent, parent: SpanRecord | undefined): SpanRecord {\n const at = this.now()\n return {\n spanId: hashHex(\n `${run.runId}:memory:${memory.operation}:${memory.recordId ?? \"\"}:${at}:${run.closed.length}`,\n 16,\n ),\n traceId: run.traceId,\n parentSpanId: parent?.spanId ?? run.root.spanId,\n name: memory.operation,\n kind: KIND_CLIENT,\n startMs: parent?.startMs ?? at,\n endMs: parent?.endMs ?? at,\n outcome: \"ok\",\n attrs: {\n \"gen_ai.operation.name\": memory.operation,\n \"gen_ai.provider.name\": \"openclaw\",\n \"gen_ai.memory.store.id\": memory.storeId,\n \"gen_ai.memory.record.id\": memory.recordId,\n \"gen_ai.memory.record.count\": memory.records.length,\n \"gen_ai.memory.query.text:gated\": this.memoryContent ? memory.queryText : undefined,\n \"gen_ai.memory.records:gated\": this.memoryContent && memory.records.length > 0 ? memory.records : undefined,\n \"openclaw.memory.body_unavailable\": memory.bodyUnavailable ? true : undefined,\n },\n }\n }\n\n private applyLink(run: RunState): void {\n const link = this.subagentLinks.get(run.runId)\n if (!link) return\n run.link = link\n run.traceId = link.traceId\n run.root.parentSpanId = link.parentSpanId\n for (const span of [\n run.root,\n ...run.llmCalls,\n ...run.closed,\n ...run.openModelCalls.values(),\n ...run.openToolCalls.values(),\n ]) {\n span.traceId = link.traceId\n }\n if (run.openCompaction) run.openCompaction.traceId = link.traceId\n }\n\n private finalize(run: RunState): void {\n if (run.finalized) return\n run.finalized = true\n run.cancelGrace?.()\n run.cancelGrace = undefined\n this.applyLink(run)\n\n const evt = run.endEvent\n const now = this.now()\n const endMs = now\n const startMs = evt?.durationMs !== undefined ? Math.min(run.startedAt, endMs - evt.durationMs) : run.startedAt\n run.root.startMs = startMs\n run.root.endMs = endMs\n\n const transcript = evt?.messages ?? []\n this.resolveSender(run)\n this.resolveCron(run)\n const assistants = this.attributeCalls(run, transcript, startMs)\n this.applyTimeToFirstToken(run)\n this.applyStreamedReasoning(run)\n this.rememberHistory(run, transcript, startMs)\n const lastAssistant = assistants[assistants.length - 1]?.message ?? run.output?.lastAssistant\n const outputMessage = lastAssistant !== undefined ? normalizeMessage(lastAssistant) : undefined\n\n const success = evt ? evt.success : false\n run.root.outcome = success ? \"ok\" : \"error\"\n run.root.errorMessage = evt?.error ?? (evt ? undefined : \"abandoned\")\n Object.assign(run.root.attrs, {\n \"user_prompt:gated\": run.prompt,\n \"gen_ai.input.messages:gated\": run.inputMessages.length > 0 ? run.inputMessages : undefined,\n \"gen_ai.output.messages:gated\": outputMessage ? [{ ...outputMessage, role: \"assistant\" }] : undefined,\n \"gen_ai.system_instructions:gated\": run.systemPrompt ? systemInstructionsParts(run.systemPrompt) : undefined,\n \"openclaw.run.success\": success,\n \"openclaw.duration_ms\": evt?.durationMs,\n \"openclaw.outcome\": evt ? (success ? \"completed\" : \"error\") : \"abandoned\",\n \"error.type\": success ? undefined : evt ? \"run_error\" : \"abandoned\",\n \"error.message:gated\": evt?.error,\n \"openclaw.llm_calls\": run.llmCalls.length,\n \"openclaw.tool_calls\": run.closed.filter((s) => s.name.startsWith(\"tool_call:\")).length,\n \"interaction.kind\": interactionKind(run),\n \"interaction.duration_ms\": endMs - startMs,\n \"openclaw.history.source\": run.historySource,\n \"openclaw.history.messages\": run.inheritedHistory.length,\n })\n\n for (const span of run.openModelCalls.values()) abandon(span, now)\n for (const span of run.openToolCalls.values()) abandon(span, now)\n if (run.openCompaction) abandon(run.openCompaction, now)\n const spans = [\n run.root,\n ...run.llmCalls,\n ...run.closed,\n ...run.openModelCalls.values(),\n ...run.openToolCalls.values(),\n ]\n if (run.openCompaction) spans.push(run.openCompaction)\n\n const common = this.commonAttrs(run)\n for (const span of spans) {\n for (const [k, v] of Object.entries(common)) {\n if (span.attrs[k] === undefined) span.attrs[k] = v\n }\n }\n\n this.runs.delete(run.runId)\n this.subagentLinks.delete(run.runId)\n const key = run.ctx.sessionKey\n if (key) {\n const ids = (this.runsBySession.get(key) ?? []).filter((id) => id !== run.runId)\n if (ids.length === 0) this.runsBySession.delete(key)\n else this.runsBySession.set(key, ids)\n }\n this.log(\n `run ${run.runId}: ${spans.length} spans, ${run.llmCalls.length} calls, history=${run.historySource}:${run.inheritedHistory.length}, transcript=${transcript.length}, deltas=${run.deltas.length}, thinking=${run.thinkingChars}`,\n )\n this.emit({ runId: run.runId, spans })\n }\n\n /**\n * Keep the session's conversation for the next turn of a harness that does\n * not pass history. A harness that passes the whole session on `agent_end`\n * replaces the remembered copy outright.\n */\n private rememberHistory(run: RunState, transcript: readonly unknown[], runStartMs: number): void {\n const sessionId = run.ctx.sessionId\n if (!sessionId || transcript.length === 0) return\n if (run.historySource === \"harness\") {\n this.sessionHistory.replace(sessionId, normalizeMessages(transcript))\n return\n }\n const turn = transcript.filter((m) => {\n const ts = (m as { timestamp?: unknown }).timestamp\n return typeof ts !== \"number\" || ts >= runStartMs - 5_000\n })\n this.sessionHistory.append(sessionId, run.inheritedHistory, normalizeMessages(turn))\n }\n\n /** Reasoning streamed during a call's window, when its transcript message carries none. */\n private applyStreamedReasoning(run: RunState): void {\n if (run.thinking.length === 0) return\n for (const call of run.llmCalls) {\n const endMs = call.endMs ?? call.startMs\n const text = run.thinking\n .filter((t) => t.ts > call.startMs - 1_000 && t.ts <= endMs + 1_000)\n .map((t) => t.text)\n .join(\"\")\n .trim()\n if (text.length === 0) continue\n const output = call.attrs[\"gen_ai.output.messages:gated\"] as Message[] | undefined\n const message = output?.[0]\n if (!message || message.parts.some((p) => p.type === \"reasoning\")) continue\n message.parts.unshift({ type: \"reasoning\", content: text })\n call.attrs[\"openclaw.reasoning.source\"] = \"stream\"\n }\n }\n\n /** The first streamed delta inside a call's window, when the harness reported no TTFB. */\n private applyTimeToFirstToken(run: RunState): void {\n if (run.deltas.length === 0) return\n for (const call of run.llmCalls) {\n if (call.attrs[\"gen_ai.server.time_to_first_token\"] !== undefined) continue\n const endMs = call.endMs ?? call.startMs\n const first = run.deltas.find((ts) => ts > call.startMs && ts <= endMs + 1_000)\n if (first === undefined) continue\n call.attrs[\"gen_ai.server.time_to_first_token\"] = (first - call.startMs) * 1_000_000\n call.attrs[\"openclaw.ttft.source\"] = \"stream\"\n }\n }\n\n /**\n * Per-call usage, cost and output come from the transcript's assistant\n * messages, each of which is one provider response. Calls and messages are\n * both chronological, so a message is matched to the call whose window\n * contains its timestamp, falling back to order when the counts line up.\n * A harness that never fires the per-call hooks still leaves its responses\n * in the transcript, so those become `llm_request` spans of their own.\n */\n private attributeCalls(\n run: RunState,\n transcript: readonly unknown[],\n runStartMs: number,\n ): Array<{ message: TranscriptAssistant; index: number }> {\n const assistants: Array<{ message: TranscriptAssistant; index: number }> = []\n transcript.forEach((m, index) => {\n if (!isTranscriptAssistant(m)) return\n const ts = typeof m.timestamp === \"number\" ? m.timestamp : undefined\n if (ts !== undefined && ts < runStartMs - 5_000) return\n assistants.push({ message: m, index })\n })\n\n if (run.llmCalls.length === 0) {\n for (const [i, entry] of assistants.entries()) {\n run.llmCalls.push(this.synthesizeCall(run, entry, i, transcript, runStartMs))\n }\n this.applyAggregateIfUnreported(run)\n return assistants\n }\n\n const unmatched = [...assistants]\n let matchedAny = false\n for (const [callIndex, call] of run.llmCalls.entries()) {\n const remainingCalls = run.llmCalls.length - callIndex\n let picked = unmatched.findIndex(({ message }) => {\n const ts = message.timestamp\n return ts !== undefined && ts >= call.startMs - 2_000 && ts <= (call.endMs ?? call.startMs) + 2_000\n })\n if (picked < 0 && unmatched.length === remainingCalls) picked = 0\n if (picked < 0) continue\n const [entry] = unmatched.splice(picked, 1)\n if (!entry) continue\n matchedAny = true\n this.enrichCall(call, entry.message, this.inputBefore(run, transcript, entry.index))\n }\n if (!matchedAny) {\n const last = run.llmCalls[run.llmCalls.length - 1]\n if (last) Object.assign(last.attrs, run.aggregateUsage, { \"openclaw.usage.scope\": \"attempt\" })\n }\n this.applyAggregateIfUnreported(run)\n return assistants\n }\n\n /** Everything the model saw before a given transcript index, including history the harness withheld. */\n private inputBefore(run: RunState, transcript: readonly unknown[], index: number): unknown[] {\n return [...run.inheritedHistory, ...transcript.slice(0, index)]\n }\n\n /**\n * A harness that reports usage only on the turn's final message leaves a\n * turn ending in a tool call with no usage at all; the attempt aggregate\n * from `llm_output` then goes on the last call.\n */\n private applyAggregateIfUnreported(run: RunState): void {\n const last = run.llmCalls[run.llmCalls.length - 1]\n if (!last || run.aggregateUsage[\"gen_ai.usage.total_tokens\"] === undefined) return\n const reported = run.llmCalls.some((call) => Number(call.attrs[\"gen_ai.usage.total_tokens\"] ?? 0) > 0)\n if (reported) return\n Object.assign(last.attrs, run.aggregateUsage, { \"openclaw.usage.scope\": \"attempt\" })\n }\n\n private synthesizeCall(\n run: RunState,\n entry: { message: TranscriptAssistant; index: number },\n index: number,\n transcript: readonly unknown[],\n runStartMs: number,\n ): SpanRecord {\n // A transcript message is stamped when it completes, so a response spans\n // from the previous message to its own timestamp.\n const endMs = entry.message.timestamp ?? run.startedAt\n const previous = transcript[entry.index - 1] as { timestamp?: unknown } | undefined\n const previousTs = typeof previous?.timestamp === \"number\" ? previous.timestamp : undefined\n const startMs =\n previousTs !== undefined && previousTs <= endMs ? Math.max(previousTs, runStartMs) : Math.min(runStartMs, endMs)\n const span: SpanRecord = {\n spanId: hashHex(`${run.runId}:llm_request:transcript:${index}`, 16),\n traceId: run.traceId,\n parentSpanId: run.root.spanId,\n name: \"llm_request\",\n kind: KIND_INTERNAL,\n startMs,\n endMs,\n outcome: \"ok\",\n attrs: {\n \"gen_ai.operation.name\": \"chat\",\n \"gen_ai.provider.name\": entry.message.provider ?? run.root.attrs[\"openclaw.provider\"],\n \"gen_ai.system\": entry.message.provider ?? run.root.attrs[\"openclaw.provider\"],\n \"gen_ai.request.model\": entry.message.model ?? run.root.attrs[\"gen_ai.request.model\"],\n \"llm_request.call_index\": index,\n \"openclaw.call.source\": \"transcript\",\n \"gen_ai.system_instructions:gated\": run.systemPrompt ? systemInstructionsParts(run.systemPrompt) : undefined,\n \"gen_ai.tool.definitions:gated\": run.toolDefinitions,\n },\n }\n this.enrichCall(span, entry.message, this.inputBefore(run, transcript, entry.index))\n return span\n }\n\n private enrichCall(call: SpanRecord, message: TranscriptAssistant, before: readonly unknown[]): void {\n const output = normalizeMessage(message)\n const usage = message.usage as TranscriptUsage | undefined\n const reason = finishReason(message.stopReason)\n Object.assign(call.attrs, {\n \"gen_ai.input.messages:gated\":\n before.length > 0 ? normalizeMessages(before) : call.attrs[\"gen_ai.input.messages:gated\"],\n \"gen_ai.output.messages:gated\": output ? [{ ...output, role: \"assistant\" }] : undefined,\n \"gen_ai.response.model\": message.responseModel ?? message.model,\n \"gen_ai.response.id\": message.responseId,\n \"gen_ai.response.finish_reasons\": reason ? [reason] : undefined,\n \"openclaw.stop_reason\": message.stopReason,\n ...usageAttrsFromTranscript(usage),\n })\n if (message.stopReason === \"error\" && message.errorMessage) {\n call.outcome = \"error\"\n call.errorMessage = message.errorMessage\n call.attrs[\"error.type\"] = call.attrs[\"error.type\"] ?? \"provider_error\"\n call.attrs[\"error.message:gated\"] = message.errorMessage\n }\n }\n\n private commonAttrs(run: RunState): AttrInput {\n const sessionId = run.link?.sessionId ?? run.ctx.sessionId\n const enrichment = deriveEnrichment(\n {\n ctx: run.ctx,\n sender: run.sender,\n cron: run.cron,\n subagentIds: run.subagentIds,\n pluginVersion: this.pluginVersion,\n },\n { tags: this.operatorTags, metadata: this.operatorMetadata },\n )\n return {\n ...sessionAttrs(sessionId),\n \"openclaw.session.id\": run.ctx.sessionId,\n \"openclaw.session.key\": run.ctx.sessionKey,\n \"openclaw.run.id\": run.runId,\n \"openclaw.agent.id\": run.ctx.agentId,\n \"gen_ai.agent.name\": run.link?.agentName ?? run.ctx.agentId,\n \"openclaw.workspace.dir\": run.ctx.workspaceDir,\n \"openclaw.channel\": run.ctx.channel,\n \"openclaw.channel.id\": run.ctx.channelId,\n \"openclaw.message.provider\": run.ctx.messageProvider,\n \"openclaw.trigger\": run.ctx.trigger,\n \"openclaw.cron.job.id\": run.cron?.id,\n \"openclaw.parent.run.id\": run.link?.parentRunId || undefined,\n \"user.id\": run.sender?.id,\n \"latitude.tags\": enrichment.tags,\n \"latitude.metadata\": enrichment.metadata,\n }\n }\n\n private emitSubagentSpan(span: SpanRecord, parentRunId: string): void {\n const parent = this.runs.get(parentRunId)\n if (parent && !parent.finalized) {\n parent.closed.push(span)\n return\n }\n if (span.attrs[\"latitude.tags\"] === undefined) {\n const enrichment = deriveEnrichment(\n { ctx: {}, subagentIds: [], pluginVersion: this.pluginVersion },\n { tags: this.operatorTags, metadata: this.operatorMetadata },\n )\n span.attrs[\"latitude.tags\"] = enrichment.tags\n span.attrs[\"latitude.metadata\"] = enrichment.metadata\n }\n this.emit({ runId: `subagent:${span.spanId}`, spans: [span] })\n }\n\n private evictStale(): void {\n const now = this.now()\n for (const [runId, link] of this.subagentLinks) {\n if (now - link.createdAt > LINK_TTL_MS) this.subagentLinks.delete(runId)\n }\n if (this.subagentLinks.size > LINK_MAX) {\n const sorted = Array.from(this.subagentLinks.entries()).sort((a, b) => a[1].createdAt - b[1].createdAt)\n for (const [runId] of sorted.slice(0, this.subagentLinks.size - LINK_MAX)) this.subagentLinks.delete(runId)\n }\n for (const [runId, pending] of this.pendingSubagents) {\n if (now - pending.createdAt > LINK_TTL_MS) {\n abandon(pending.span, now)\n pending.span.attrs[\"openclaw.subagent.outcome\"] = \"abandoned\"\n this.pendingSubagents.delete(runId)\n this.emitSubagentSpan(pending.span, pending.parentRunId)\n }\n }\n for (const run of Array.from(this.runs.values())) {\n if (now - run.startedAt > RUN_TTL_MS) {\n this.log(`run ${run.runId} never ended; exporting as abandoned`)\n this.finalize(run)\n }\n }\n }\n\n private findOpenToolCallByName(run: RunState, toolName: string): string | undefined {\n const target = `tool_call:${toolName}`\n const entries = Array.from(run.openToolCalls.entries())\n for (let i = entries.length - 1; i >= 0; i--) {\n const entry = entries[i]\n if (entry && entry[1].name === target) return entry[0]\n }\n return undefined\n }\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nfunction toolCtxToAgentCtx(ctx: OpenClawToolContext, runId: string): OpenClawAgentContext {\n return {\n runId,\n agentId: ctx.agentId,\n sessionKey: ctx.sessionKey,\n sessionId: ctx.sessionId,\n channelId: ctx.channelId,\n channel: ctx.requester?.channel,\n accountId: ctx.requester?.accountId,\n senderId: ctx.requester?.senderId,\n }\n}\n\nfunction interactionKind(run: RunState): string {\n if (run.link) return \"subagent\"\n if (run.runId.startsWith(\"announce:\")) return \"announce\"\n if (run.ctx.trigger === \"cron\") return \"cron\"\n return run.ctx.trigger ?? \"user\"\n}\n\n/** Cron prompts open with `[cron:<jobId> <job name>]`, the only place the name reaches a run. */\nfunction cronNameFromPrompt(prompt: string | undefined, jobId: string): string | undefined {\n if (!prompt) return undefined\n const match = new RegExp(`^\\\\[cron:${jobId.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")} ([^\\\\]]+)\\\\]`).exec(prompt)\n return match?.[1]?.trim() || undefined\n}\n\n/** Session keys are `agent:<agentId>:<rest>`. */\nfunction agentIdFromSessionKey(sessionKey: string | undefined): string | undefined {\n const match = sessionKey ? /^agent:([^:]+):/.exec(sessionKey) : null\n return match?.[1]\n}\n\nfunction sessionAttrs(sessionId: string | undefined): AttrInput {\n if (!sessionId) return {}\n return { \"session.id\": sessionId, \"gen_ai.session.id\": sessionId }\n}\n\nfunction abandon(span: SpanRecord, now: number): void {\n span.endMs = now\n span.outcome = \"error\"\n span.attrs[\"openclaw.outcome\"] = \"abandoned\"\n span.attrs[\"error.type\"] = \"abandoned\"\n}\n\n/** Insertion-ordered cache: re-setting a key moves it to the back, and the oldest keys go once `max` is exceeded. */\nfunction remember<K, V>(map: Map<K, V>, key: K, value: V, max: number): void {\n map.delete(key)\n map.set(key, value)\n for (const oldest of map.keys()) {\n if (map.size <= max) break\n map.delete(oldest)\n }\n}\n\nfunction hashHex(input: string, length: number): string {\n return createHash(\"sha256\").update(input).digest(\"hex\").slice(0, length)\n}\n","import type { Logger } from \"./logger.ts\"\nimport type { OtlpExportRequest } from \"./types.ts\"\n\ninterface TransportOptions {\n baseUrl: string\n apiKey: string\n project: string\n logger: Logger\n timeoutMs?: number\n maxAttempts?: number\n fetchImpl?: typeof fetch\n sleep?: (ms: number) => Promise<void>\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000\nconst DEFAULT_MAX_ATTEMPTS = 3\nconst RETRY_BASE_MS = 500\nconst RETRY_AFTER_MAX_MS = 30_000\n\n/**\n * Ships OTLP requests sequentially with bounded retries. Every span is sent\n * exactly once on success: Latitude's trace and session rollups add per\n * insert, so a duplicate would inflate counts; a `4xx` other than `429` is\n * therefore final, while `429`, `5xx` and network errors retry with backoff.\n */\nexport class Transport {\n private readonly url: string\n private readonly opts: TransportOptions\n private chain: Promise<void> = Promise.resolve()\n private pending = 0\n\n constructor(opts: TransportOptions) {\n this.opts = opts\n this.url = `${withoutTrailingSlashes(opts.baseUrl)}/v1/traces`\n }\n\n enqueue(payload: OtlpExportRequest): void {\n this.pending++\n this.chain = this.chain\n .then(() => this.send(payload))\n .catch((err) => this.opts.logger.warn(`export failed: ${String(err)}`))\n .finally(() => {\n this.pending--\n })\n }\n\n /** Resolves when everything queued so far has been sent or given up on, or the budget elapses. */\n async flush(budgetMs: number): Promise<void> {\n if (this.pending === 0) return\n await Promise.race([this.chain, sleep(budgetMs)])\n }\n\n private async send(payload: OtlpExportRequest): Promise<void> {\n const body = JSON.stringify(payload)\n const spanCount = payload.resourceSpans.reduce(\n (n, rs) => n + rs.scopeSpans.reduce((m, ss) => m + ss.spans.length, 0),\n 0,\n )\n const maxAttempts = this.opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS\n const doFetch = this.opts.fetchImpl ?? fetch\n const wait = this.opts.sleep ?? sleep\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), this.opts.timeoutMs ?? DEFAULT_TIMEOUT_MS)\n try {\n const res = await doFetch(this.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.opts.apiKey}`,\n \"X-Latitude-Project\": this.opts.project,\n },\n body,\n signal: controller.signal,\n })\n if (res.ok) {\n this.opts.logger.debug(`exported ${spanCount} spans (${body.length} bytes) HTTP ${res.status}`)\n return\n }\n const text = await res.text().catch(() => \"\")\n const retryable = res.status === 429 || res.status >= 500\n if (!retryable || attempt === maxAttempts) {\n this.opts.logger.warn(`ingest HTTP ${res.status} (final): ${text.slice(0, 300)}`)\n return\n }\n const retryAfter = Number(res.headers.get(\"retry-after\"))\n const honoured =\n Number.isFinite(retryAfter) && retryAfter > 0 ? Math.min(retryAfter * 1000, RETRY_AFTER_MAX_MS) : 0\n await wait(honoured || backoff(attempt))\n } catch (err) {\n if (attempt === maxAttempts) {\n this.opts.logger.warn(`ingest unreachable after ${attempt} attempts: ${String(err)}`)\n return\n }\n await wait(backoff(attempt))\n } finally {\n clearTimeout(timer)\n }\n }\n }\n}\n\nfunction backoff(attempt: number): number {\n return RETRY_BASE_MS * 2 ** (attempt - 1) + Math.random() * RETRY_BASE_MS\n}\n\nfunction withoutTrailingSlashes(url: string): string {\n let end = url.length\n while (end > 0 && url[end - 1] === \"/\") end--\n return url.slice(0, end)\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms)\n timer.unref?.()\n })\n}\n","import { type Config, loadConfig } from \"./config.ts\"\nimport { createLogger, type HostLogger, type Logger } from \"./logger.ts\"\nimport { buildOtlpRequest, SCOPE_VERSION } from \"./otlp.ts\"\nimport { type BuildResult, SpanBuilder } from \"./span-builder.ts\"\nimport { Transport } from \"./transport.ts\"\nimport type {\n OpenClawAfterCompactionEvent,\n OpenClawAfterToolCallEvent,\n OpenClawAgentContext,\n OpenClawAgentEndEvent,\n OpenClawBeforeCompactionEvent,\n OpenClawBeforeToolCallEvent,\n OpenClawCronChangedEvent,\n OpenClawLlmInputEvent,\n OpenClawLlmOutputEvent,\n OpenClawMessageContext,\n OpenClawMessageReceivedEvent,\n OpenClawModelCallEndedEvent,\n OpenClawModelCallStartedEvent,\n OpenClawSessionEndEvent,\n OpenClawSessionScopedContext,\n OpenClawSessionStartEvent,\n OpenClawSubagentContext,\n OpenClawSubagentEndedEvent,\n OpenClawSubagentSpawnedEvent,\n OpenClawToolContext,\n} from \"./types.ts\"\n\n/**\n * Structural type for the slice of OpenClaw's plugin API this plugin touches.\n * Kept local so the package works without OpenClaw installed (tests, CLI) and\n * tolerates small upstream signature changes.\n */\nexport interface OpenClawPluginApiLike {\n logger?: HostLogger\n pluginConfig?: Record<string, unknown>\n /** The whole OpenClaw config; only the plugin's own `hooks` block is read. */\n config?: { plugins?: { entries?: Record<string, { hooks?: { allowConversationAccess?: boolean } }> } }\n /** Host runtime helpers; the state dir and the agent event stream are used when present. */\n runtime?: {\n state?: { resolveStateDir?: () => string }\n events?: { onAgentEvent?: (listener: (evt: AgentEventLike) => void) => unknown }\n }\n on: <K extends string>(\n hookName: K,\n handler: (event: unknown, ctx: unknown) => unknown,\n opts?: { priority?: number },\n ) => void\n}\n\nexport interface AgentEventLike {\n runId?: string\n stream?: string\n ts?: number\n data?: Record<string, unknown>\n sessionKey?: string\n sessionId?: string\n agentId?: string\n}\n\nexport interface RegisterOptions {\n /** Override the config, mostly for tests. */\n config?: Config\n logger?: Logger\n /** Observe each finished batch right before export. Tests only. */\n onEmit?: (result: BuildResult) => void\n /** Replace the network transport. Tests only. */\n transport?: Pick<Transport, \"enqueue\" | \"flush\">\n now?: () => number\n schedule?: (fn: () => void, ms: number) => () => void\n}\n\nconst STOP_FLUSH_BUDGET_MS = 4_000\nconst PLUGIN_ID = \"@latitude-data/openclaw-telemetry\"\n\nexport default function registerLatitudePlugin(api: OpenClawPluginApiLike, opts: RegisterOptions = {}): void {\n const config = opts.config ?? loadConfig(api.pluginConfig)\n const logger = opts.logger ?? createLogger(config.debug, api.logger)\n\n if (!config.enabled) {\n if (config.apiKey === \"\") logger.warn(\"disabled: apiKey is empty (set plugins.entries[id].config.apiKey)\")\n if (config.project === \"\") logger.warn(\"disabled: project is empty (set plugins.entries[id].config.project)\")\n return\n }\n logger.debug(\n `enabled v${SCOPE_VERSION}: project=${config.project} base=${config.baseUrl} content=${config.allowConversationAccess}`,\n )\n if (api.config?.plugins?.entries && api.config.plugins.entries[PLUGIN_ID]?.hooks?.allowConversationAccess !== true) {\n logger.warn(\n `plugins.entries[\"${PLUGIN_ID}\"].hooks.allowConversationAccess is not true; OpenClaw will not deliver the conversation hooks and no traces will be exported. ` +\n `Run: openclaw config set 'plugins.entries[\"${PLUGIN_ID}\"].hooks.allowConversationAccess' true && openclaw gateway restart`,\n )\n }\n\n const transport =\n opts.transport ?? new Transport({ baseUrl: config.baseUrl, apiKey: config.apiKey, project: config.project, logger })\n\n let stateDir: string | undefined\n try {\n stateDir = api.runtime?.state?.resolveStateDir?.()\n } catch {\n stateDir = undefined\n }\n\n const builder = new SpanBuilder({\n pluginVersion: SCOPE_VERSION,\n stateDir,\n tags: config.tags,\n metadata: config.metadata,\n memory: config.memory,\n memoryContent: config.memoryContent,\n toolDefinitions: config.toolDefinitions,\n now: opts.now,\n schedule: opts.schedule,\n log: (msg) => logger.debug(msg),\n emit: (result) => {\n try {\n opts.onEmit?.(result)\n logger.debug(`run ${result.runId}: ${result.spans.length} spans ready`)\n transport.enqueue(\n buildOtlpRequest([result], {\n allowConversationAccess: config.allowConversationAccess,\n redact: config.redact,\n serviceName: config.serviceName,\n maxContentChars: config.maxContentChars,\n }),\n )\n } catch (err) {\n logger.warn(`export of run ${result.runId} failed: ${String(err)}`)\n }\n },\n })\n\n const wrap = <E, C>(name: string, fn: (evt: E, ctx: C) => void): ((evt: unknown, ctx: unknown) => undefined) => {\n return (evt, ctx) => {\n try {\n fn(evt as E, ctx as C)\n } catch (err) {\n logger.warn(`${name} handler failed: ${String(err)}`)\n }\n // Several of these are modifying hooks; anything but undefined would alter the run.\n return undefined\n }\n }\n\n api.on(\n \"llm_input\",\n wrap<OpenClawLlmInputEvent, OpenClawAgentContext>(\"llm_input\", (e, c) => builder.onLlmInput(e, c)),\n )\n api.on(\n \"llm_output\",\n wrap<OpenClawLlmOutputEvent, OpenClawAgentContext>(\"llm_output\", (e, c) => builder.onLlmOutput(e, c)),\n )\n api.on(\n \"agent_end\",\n wrap<OpenClawAgentEndEvent, OpenClawAgentContext>(\"agent_end\", (e, c) => builder.onAgentEnd(e, c)),\n )\n\n api.on(\n \"model_call_started\",\n wrap<OpenClawModelCallStartedEvent, OpenClawAgentContext>(\"model_call_started\", (e, c) =>\n builder.onModelCallStarted(e, c),\n ),\n )\n api.on(\n \"model_call_ended\",\n wrap<OpenClawModelCallEndedEvent, OpenClawAgentContext>(\"model_call_ended\", (e, c) =>\n builder.onModelCallEnded(e, c),\n ),\n )\n\n api.on(\n \"before_tool_call\",\n wrap<OpenClawBeforeToolCallEvent, OpenClawToolContext>(\"before_tool_call\", (e, c) =>\n builder.onBeforeToolCall(e, c),\n ),\n )\n api.on(\n \"after_tool_call\",\n wrap<OpenClawAfterToolCallEvent, OpenClawToolContext>(\"after_tool_call\", (e, c) => builder.onAfterToolCall(e, c)),\n )\n\n api.on(\n \"before_compaction\",\n wrap<OpenClawBeforeCompactionEvent, OpenClawSessionScopedContext>(\"before_compaction\", (e, c) =>\n builder.onBeforeCompaction(e, c),\n ),\n )\n api.on(\n \"after_compaction\",\n wrap<OpenClawAfterCompactionEvent, OpenClawSessionScopedContext>(\"after_compaction\", (e, c) =>\n builder.onAfterCompaction(e, c),\n ),\n )\n\n api.on(\n \"subagent_spawned\",\n wrap<OpenClawSubagentSpawnedEvent, OpenClawSubagentContext>(\"subagent_spawned\", (e, c) =>\n builder.onSubagentSpawned(e, c),\n ),\n )\n api.on(\n \"subagent_ended\",\n wrap<OpenClawSubagentEndedEvent, OpenClawSubagentContext>(\"subagent_ended\", (e, c) =>\n builder.onSubagentEnded(e, c),\n ),\n )\n\n api.on(\n \"session_start\",\n wrap<OpenClawSessionStartEvent, OpenClawSessionScopedContext>(\"session_start\", (e, c) =>\n builder.onSessionStart(e, c),\n ),\n )\n api.on(\n \"session_end\",\n wrap<OpenClawSessionEndEvent, OpenClawSessionScopedContext>(\"session_end\", (e, c) =>\n builder.onSessionEnd(e.sessionKey ?? c.sessionKey, e.sessionId ?? c.sessionId),\n ),\n )\n api.on(\n \"message_received\",\n wrap<OpenClawMessageReceivedEvent, OpenClawMessageContext>(\"message_received\", (e, c) =>\n builder.onMessageReceived(e, c),\n ),\n )\n api.on(\n \"cron_changed\",\n wrap<OpenClawCronChangedEvent, unknown>(\"cron_changed\", (e) => builder.onCronChanged(e)),\n )\n\n api.on(\"gateway_stop\", (_evt, _ctx) => transport.flush(STOP_FLUSH_BUDGET_MS))\n\n // Streamed deltas are the only time-to-first-token source on the Codex harness.\n try {\n api.runtime?.events?.onAgentEvent?.((evt) => {\n try {\n builder.onAgentEvent(evt)\n } catch (err) {\n logger.warn(`agent event handler failed: ${String(err)}`)\n }\n })\n } catch (err) {\n logger.debug(`agent event stream unavailable: ${String(err)}`)\n }\n}\n"],"mappings":"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"}