@tangle-network/agent-runtime 0.80.1 → 0.81.1

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.
package/dist/agent.js CHANGED
@@ -1,8 +1,8 @@
1
- import "./chunk-3RAXZ6LB.js";
1
+ import "./chunk-D6GIWPKD.js";
2
2
  import {
3
3
  createSandboxForSpec
4
- } from "./chunk-3TAQW75Y.js";
5
- import "./chunk-XRKP3XW3.js";
4
+ } from "./chunk-VHJDS6OR.js";
5
+ import "./chunk-BPS254IE.js";
6
6
  import "./chunk-H7IBHAFT.js";
7
7
  import {
8
8
  mapSandboxEvent
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  buildLoopOtelSpans,
3
3
  createOtelExporter
4
- } from "./chunk-XRKP3XW3.js";
4
+ } from "./chunk-BPS254IE.js";
5
5
 
6
6
  // src/mcp/trace-propagation.ts
7
7
  function readTraceContextFromEnv() {
@@ -49,4 +49,4 @@ export {
49
49
  createPropagatingTraceEmitter,
50
50
  traceContextToEnv
51
51
  };
52
- //# sourceMappingURL=chunk-CR5MQUYO.js.map
52
+ //# sourceMappingURL=chunk-35WXYO26.js.map
@@ -1,5 +1,5 @@
1
1
  // src/otel-export.ts
2
- var SCOPE = { name: "@tangle-network/agent-runtime", version: "0.80.1" };
2
+ var SCOPE = { name: "@tangle-network/agent-runtime", version: "0.81.1" };
3
3
  var GEN_AI = {
4
4
  operation: "gen_ai.operation.name",
5
5
  agentName: "gen_ai.agent.name",
@@ -378,4 +378,4 @@ export {
378
378
  INTELLIGENCE_WIRE_VERSION,
379
379
  exportEvalRuns
380
380
  };
381
- //# sourceMappingURL=chunk-XRKP3XW3.js.map
381
+ //# sourceMappingURL=chunk-BPS254IE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/otel-export.ts"],"sourcesContent":["/**\n * OTEL span exporter — streams LoopTraceEvents to an OTLP/HTTP collector.\n *\n * Reads OTEL_EXPORTER_OTLP_ENDPOINT + OTEL_EXPORTER_OTLP_HEADERS from env\n * when no explicit config is given. Keeps the runtime dep-free from\n * @opentelemetry/sdk-trace-base — minimal OTLP/JSON serializer.\n *\n * The exporter accepts both raw OtelSpan objects and LoopTraceEvents\n * (which get converted to OTLP spans automatically).\n */\n\nexport interface OtelExportConfig {\n /** OTLP endpoint. Reads OTEL_EXPORTER_OTLP_ENDPOINT env by default. */\n endpoint?: string\n /** OTLP headers. Reads OTEL_EXPORTER_OTLP_HEADERS env by default. */\n headers?: Record<string, string>\n /** Batch size before flush. Default 64. */\n batchSize?: number\n /** Flush interval ms. Default 5000. */\n flushIntervalMs?: number\n /** Resource attributes stamped on every export. */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Service name. Default 'agent-runtime'. */\n serviceName?: string\n}\n\nexport interface OtelExporter {\n /** Export a span. */\n exportSpan(span: OtelSpan): void\n /** Force flush pending spans. */\n flush(): Promise<void>\n /** Shutdown cleanly. */\n shutdown(): Promise<void>\n}\n\nexport interface OtelSpan {\n traceId: string\n spanId: string\n parentSpanId?: string\n name: string\n kind?: number\n startTimeUnixNano: string\n endTimeUnixNano: string\n attributes?: OtelAttribute[]\n status?: { code: number; message?: string }\n}\n\nexport interface OtelAttribute {\n key: string\n value: { stringValue?: string; intValue?: string; doubleValue?: number; boolValue?: boolean }\n}\n\ninterface OtlpResourceSpans {\n resource: { attributes: OtelAttribute[] }\n scopeSpans: Array<{ scope: { name: string; version: string }; spans: OtelSpan[] }>\n}\n\ninterface OtlpExport {\n resourceSpans: OtlpResourceSpans[]\n}\n\nconst SCOPE = { name: '@tangle-network/agent-runtime', version: '0.80.1' }\n\n/**\n * Current (non-deprecated) OpenTelemetry GenAI semantic-convention keys.\n * Registry: https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/\n * NB: `gen_ai.system` / `gen_ai.usage.prompt_tokens` / `completion_tokens` are\n * DEPRECATED — do not emit them. We use `provider.name` + `input/output_tokens`.\n */\nconst GEN_AI = {\n operation: 'gen_ai.operation.name',\n agentName: 'gen_ai.agent.name',\n conversationId: 'gen_ai.conversation.id',\n inputTokens: 'gen_ai.usage.input_tokens',\n outputTokens: 'gen_ai.usage.output_tokens',\n} as const\n\n/**\n * Create an OTEL exporter. Returns undefined when no endpoint is configured.\n */\nexport function createOtelExporter(config?: OtelExportConfig): OtelExporter | undefined {\n const resolvedEndpoint =\n config?.endpoint ??\n (typeof process !== 'undefined' ? process.env.OTEL_EXPORTER_OTLP_ENDPOINT : undefined)\n if (!resolvedEndpoint) return undefined\n const endpoint: string = resolvedEndpoint\n\n const headers = config?.headers ?? parseHeadersFromEnv()\n const batchSize = config?.batchSize ?? 64\n const flushIntervalMs = config?.flushIntervalMs ?? 5000\n const serviceName = config?.serviceName ?? 'agent-runtime'\n const resourceAttrs = config?.resourceAttributes ?? {}\n\n const pending: OtelSpan[] = []\n let timer: ReturnType<typeof setInterval> | undefined\n let stopped = false\n\n const exporter: OtelExporter = {\n exportSpan(span: OtelSpan): void {\n if (stopped) return\n pending.push(span)\n if (pending.length >= batchSize) {\n void doFlush()\n }\n },\n\n async flush(): Promise<void> {\n await doFlush()\n },\n\n async shutdown(): Promise<void> {\n stopped = true\n if (timer !== undefined) {\n clearInterval(timer)\n timer = undefined\n }\n await doFlush()\n },\n }\n\n timer = setInterval(() => {\n if (pending.length > 0) void doFlush()\n }, flushIntervalMs)\n if (typeof timer === 'object' && 'unref' in timer) {\n ;(timer as NodeJS.Timeout).unref()\n }\n\n async function doFlush(): Promise<void> {\n if (pending.length === 0) return\n const batch = pending.splice(0)\n const body: OtlpExport = {\n resourceSpans: [\n {\n resource: {\n attributes: toAttributes({\n 'service.name': serviceName,\n ...resourceAttrs,\n }),\n },\n scopeSpans: [{ scope: SCOPE, spans: batch }],\n },\n ],\n }\n const url = `${endpoint.replace(/\\/+$/, '')}/v1/traces`\n try {\n await fetch(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...headers },\n body: JSON.stringify(body),\n })\n } catch {\n // Best-effort — telemetry export must not crash the runtime.\n }\n }\n\n return exporter\n}\n\n/**\n * Convert a LoopTraceEvent into an OtelSpan for export.\n */\nexport function loopEventToOtelSpan(\n event: {\n kind: string\n runId: string\n timestamp: number\n payload: object\n },\n traceId: string,\n parentSpanId?: string,\n): OtelSpan {\n const spanId = generateSpanId()\n const attrs: Record<string, string | number | boolean> = {\n 'loop.event_kind': event.kind,\n 'loop.run_id': event.runId,\n }\n for (const [k, v] of Object.entries(event.payload)) {\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {\n attrs[`loop.${k}`] = v\n }\n }\n const ts = msToNs(event.timestamp)\n return {\n traceId: padTraceId(traceId),\n spanId,\n parentSpanId: parentSpanId ? padSpanId(parentSpanId) : undefined,\n name: event.kind,\n kind: 1,\n startTimeUnixNano: ts,\n endTimeUnixNano: ts,\n attributes: toAttributes(attrs),\n status: { code: 1 },\n }\n}\n\n/**\n * Build a single flat OtelSpan whose attribute keys are emitted VERBATIM — no\n * `loop.` namespace. Use for non-loop spans (e.g. the intelligence per-run\n * span) whose keys ARE the downstream contract (`gen_ai.request.model`,\n * `tangle.sessionId`) and are exact-matched by readers. `loopEventToOtelSpan`\n * namespaces payload keys because loop payload fields are free-form; do not\n * reuse it for spans with contract keys.\n */\nexport function flatOtelSpan(\n name: string,\n attributes: Record<string, string | number | boolean>,\n traceId: string,\n timestampMs: number,\n parentSpanId?: string,\n): OtelSpan {\n const ts = msToNs(timestampMs)\n return {\n traceId: padTraceId(traceId),\n spanId: generateSpanId(),\n parentSpanId: parentSpanId ? padSpanId(parentSpanId) : undefined,\n name,\n kind: 1,\n startTimeUnixNano: ts,\n endTimeUnixNano: ts,\n attributes: toAttributes(attributes),\n status: { code: 1 },\n }\n}\n\n/**\n * Sink-neutral node in a reconstructed loop span tree. The root node's\n * `parentSpanId` is `undefined` — sinks decide how to parent it (the OTEL\n * mapper attaches the inherited delegation span; the delegation journal\n * leaves it as the tree root).\n */\nexport interface LoopSpanNode {\n spanId: string\n parentSpanId?: string\n /** `'loop'` | `'loop.round'` | `'loop.iteration'`. */\n name: string\n /** Topology level: loop root, plan round, or iteration branch. */\n kind: 'loop' | 'round' | 'branch'\n startMs: number\n endMs: number\n attrs: Record<string, string | number | boolean>\n /** True when the iteration carried an error — maps to OTEL status code 2. */\n error: boolean\n}\n\n/**\n * Build a nested, real-duration OTLP span tree for ONE loop run from its full\n * ordered `LoopTraceEvent` stream. Unlike `loopEventToOtelSpan` (one flat,\n * zero-duration span per event), this reconstructs the topology hierarchy a\n * GenAI trace viewer renders natively:\n *\n * loop (invoke_workflow)\n * └─ loop.round[k] (invoke_workflow) ← tangle.loop.move.{kind,width,rationale}\n * ├─ loop.iteration[i] (invoke_agent) ← gen_ai.agent.name + usage + verdict + placement\n * └─ …\n *\n * Attributes follow the current GenAI semconv (`gen_ai.*`) where they apply and\n * a namespaced `tangle.loop.*` / `tangle.cost.usd` extension for topology /\n * verdict / placement / cost (not yet standardized). Pure: feed it a buffered\n * per-runId event array (e.g. flushed on `loop.ended`) and export the result.\n */\nexport function buildLoopOtelSpans(\n events: ReadonlyArray<{ kind: string; runId: string; timestamp: number; payload: object }>,\n traceId: string,\n rootParentSpanId?: string,\n): OtelSpan[] {\n const tid = padTraceId(traceId)\n return buildLoopSpanNodes(events).map((node) => ({\n traceId: tid,\n spanId: node.spanId,\n parentSpanId: node.parentSpanId\n ? padSpanId(node.parentSpanId)\n : rootParentSpanId\n ? padSpanId(rootParentSpanId)\n : undefined,\n name: node.name,\n kind: 1,\n startTimeUnixNano: msToNs(node.startMs),\n endTimeUnixNano: msToNs(node.endMs),\n attributes: toAttributes(node.attrs),\n status: { code: node.error ? 2 : 1 },\n }))\n}\n\n/**\n * Sink-neutral core behind {@link buildLoopOtelSpans}: reconstruct the\n * loop → round → branch span tree from one run's ordered `LoopTraceEvent`\n * stream. Consumed by the OTEL mapper above and by the MCP delegation\n * journal's compact trace tee — one topology reconstruction, two sinks.\n * Tolerates partial streams (a run that never reached `loop.ended` closes\n * at the last observed event's timestamp).\n */\nexport function buildLoopSpanNodes(\n events: ReadonlyArray<{ kind: string; runId: string; timestamp: number; payload: object }>,\n): LoopSpanNode[] {\n if (events.length === 0) return []\n const out: LoopSpanNode[] = []\n const num = (v: unknown): number | undefined =>\n typeof v === 'number' && Number.isFinite(v) ? v : undefined\n const str = (v: unknown): string | undefined =>\n typeof v === 'string' && v.length > 0 ? v : undefined\n const rec = (v: unknown): Record<string, unknown> =>\n v && typeof v === 'object' ? (v as Record<string, unknown>) : {}\n\n const started = events.find((e) => e.kind === 'loop.started')\n const ended = events.find((e) => e.kind === 'loop.ended')\n const runId = events[0]?.runId ?? ''\n const rootStart = started?.timestamp ?? events[0]!.timestamp\n const rootEnd = ended?.timestamp ?? events[events.length - 1]!.timestamp\n const rootId = generateSpanId()\n\n const make = (\n spanId: string,\n parentSpanId: string | undefined,\n name: string,\n kind: LoopSpanNode['kind'],\n startMs: number,\n endMs: number,\n attrs: Record<string, string | number | boolean>,\n error = false,\n ): LoopSpanNode => ({\n spanId,\n parentSpanId,\n name,\n kind,\n startMs,\n endMs,\n attrs,\n error,\n })\n\n // root\n const sp = rec(started?.payload)\n const rootAttrs: Record<string, string | number | boolean> = {\n [GEN_AI.operation]: 'invoke_workflow',\n [GEN_AI.conversationId]: runId,\n // Explicit run identity under the tangle namespace so a consuming system of\n // record (Tangle Intelligence's run spine) maps this span tree to one run\n // deterministically, instead of inferring it from the conversation id.\n 'tangle.run.id': runId,\n 'tangle.loop.driver': str(sp.driver) ?? 'driver',\n }\n if (Array.isArray(sp.agentRunNames) && sp.agentRunNames.length > 0) {\n rootAttrs['tangle.loop.agents'] = sp.agentRunNames.map(String).join(',')\n // Subject grain: the primary agent/profile this run drove. Lets the spine\n // group runs under the thing being worked on rather than one service-wide\n // bucket. `agentRunNames[0]` is the lead agent on a fan-out.\n rootAttrs['tangle.subject.key'] = String(sp.agentRunNames[0])\n }\n if (ended) {\n const ep = rec(ended.payload)\n const win = num(ep.winnerIterationIndex)\n if (win !== undefined) rootAttrs['tangle.loop.winner.iteration_index'] = win\n const cost = num(ep.totalCostUsd)\n if (cost !== undefined) rootAttrs['tangle.cost.usd'] = cost\n const dur = num(ep.durationMs)\n if (dur !== undefined) rootAttrs['tangle.loop.duration_ms'] = dur\n const iters = num(ep.iterations)\n if (iters !== undefined) rootAttrs['tangle.loop.iterations'] = iters\n }\n out.push(make(rootId, undefined, 'loop', 'loop', rootStart, rootEnd, rootAttrs))\n\n // rounds + iterations\n const iterStartTs = new Map<number, number>()\n const placementByIdx = new Map<number, Record<string, string>>()\n let currentRoundId: string | undefined\n let pendingRound:\n | { id: string; start: number; attrs: Record<string, string | number | boolean> }\n | undefined\n const flushRound = (endMs: number) => {\n if (!pendingRound) return\n out.push(\n make(\n pendingRound.id,\n rootId,\n 'loop.round',\n 'round',\n pendingRound.start,\n endMs,\n pendingRound.attrs,\n ),\n )\n pendingRound = undefined\n }\n\n for (const e of events) {\n const p = rec(e.payload)\n switch (e.kind) {\n case 'loop.plan': {\n flushRound(e.timestamp)\n const id = generateSpanId()\n const roundIdx = num(p.roundIndex) ?? 0\n const attrs: Record<string, string | number | boolean> = {\n [GEN_AI.operation]: 'invoke_workflow',\n 'tangle.loop.round.index': roundIdx,\n 'tangle.loop.move.kind': str(p.moveKind) ?? 'unknown',\n 'tangle.loop.move.round': roundIdx,\n 'tangle.loop.move.width': num(p.plannedCount) ?? 0,\n }\n const r = str(p.rationale)\n if (r) attrs['tangle.loop.move.rationale'] = r\n const parent = num(p.parentIndex)\n if (parent !== undefined) attrs['tangle.loop.move.parent_index'] = parent\n if (Array.isArray(p.childIndices) && p.childIndices.length > 0) {\n attrs['tangle.loop.move.child_indices'] = p.childIndices.map(String).join(',')\n }\n pendingRound = { id, start: e.timestamp, attrs }\n currentRoundId = id\n break\n }\n case 'loop.iteration.started': {\n const idx = num(p.iterationIndex)\n if (idx !== undefined) iterStartTs.set(idx, e.timestamp)\n break\n }\n case 'loop.iteration.dispatch': {\n const idx = num(p.iterationIndex)\n if (idx === undefined) break\n const place: Record<string, string> = {}\n const kind = str(p.placement)\n if (kind) place['tangle.loop.placement.kind'] = kind\n const sid = str(p.sandboxId)\n if (sid) place['tangle.sandbox.id'] = sid\n const fid = str(p.fleetId)\n if (fid) place['tangle.fleet.id'] = fid\n const mid = str(p.machineId)\n if (mid) place['tangle.machine.id'] = mid\n placementByIdx.set(idx, place)\n break\n }\n case 'loop.iteration.ended': {\n const idx = num(p.iterationIndex) ?? 0\n const start = iterStartTs.get(idx) ?? e.timestamp\n const err = str(p.error)\n const attrs: Record<string, string | number | boolean> = {\n [GEN_AI.operation]: 'invoke_agent',\n 'tangle.loop.iteration.index': idx,\n }\n const agent = str(p.agentRunName)\n if (agent) attrs[GEN_AI.agentName] = agent\n const tu = rec(p.tokenUsage)\n const inTok = num(tu.input)\n if (inTok !== undefined) attrs[GEN_AI.inputTokens] = inTok\n const outTok = num(tu.output)\n if (outTok !== undefined) attrs[GEN_AI.outputTokens] = outTok\n const cost = num(p.costUsd)\n if (cost !== undefined) attrs['tangle.cost.usd'] = cost\n const verdict = rec(p.verdict)\n if (typeof verdict.valid === 'boolean') attrs['tangle.loop.verdict.valid'] = verdict.valid\n const score = num(verdict.score)\n if (score !== undefined) attrs['tangle.loop.verdict.score'] = score\n if (err) attrs['tangle.loop.error'] = err\n const gid = num(p.groupId)\n if (gid !== undefined) attrs['tangle.loop.iteration.group_id'] = gid\n const par = num(p.parentIndex)\n if (par !== undefined) attrs['tangle.loop.iteration.parent_index'] = par\n const dur = num(p.durationMs)\n if (dur !== undefined) attrs['tangle.loop.iteration.duration_ms'] = dur\n const preview = str(p.outputPreview)\n if (preview) attrs['tangle.loop.iteration.output_preview'] = preview\n Object.assign(attrs, placementByIdx.get(idx) ?? {})\n out.push(\n make(\n generateSpanId(),\n currentRoundId ?? rootId,\n 'loop.iteration',\n 'branch',\n start,\n e.timestamp,\n attrs,\n err !== undefined,\n ),\n )\n break\n }\n case 'loop.decision': {\n if (pendingRound) {\n const dec = str(p.decision)\n if (dec) pendingRound.attrs['tangle.loop.decision'] = dec\n flushRound(e.timestamp)\n }\n currentRoundId = undefined\n break\n }\n }\n }\n flushRound(rootEnd)\n return out\n}\n\nfunction parseHeadersFromEnv(): Record<string, string> {\n if (typeof process === 'undefined') return {}\n const raw = process.env.OTEL_EXPORTER_OTLP_HEADERS\n if (!raw) return {}\n const out: Record<string, string> = {}\n for (const pair of raw.split(',')) {\n const eq = pair.indexOf('=')\n if (eq < 0) continue\n const key = pair.slice(0, eq).trim()\n const value = pair.slice(eq + 1).trim()\n if (key) out[key] = value\n }\n return out\n}\n\nfunction toAttributes(record: Record<string, string | number | boolean>): OtelAttribute[] {\n return Object.entries(record).map(([key, value]) => ({\n key,\n value:\n typeof value === 'number'\n ? Number.isInteger(value)\n ? { intValue: value.toString() }\n : { doubleValue: value }\n : typeof value === 'boolean'\n ? { boolValue: value }\n : { stringValue: value },\n }))\n}\n\nfunction msToNs(ms: number): string {\n return (BigInt(Math.floor(ms)) * 1_000_000n).toString()\n}\n\nfunction padSpanId(id: string): string {\n const cleaned = id.replace(/-/g, '')\n return cleaned.slice(0, 16).padEnd(16, '0')\n}\n\nfunction padTraceId(id: string): string {\n const cleaned = id.replace(/-/g, '')\n return cleaned.slice(0, 32).padEnd(32, '0')\n}\n\nfunction generateSpanId(): string {\n const bytes = new Uint8Array(8)\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes)\n } else {\n for (let i = 0; i < 8; i++) bytes[i] = Math.floor(Math.random() * 256)\n }\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n// ─── Eval-run ingest (self-improvement provenance) ───────────────────────────\n//\n// Tangle Intelligence has a first-class, non-trace record for self-improvement\n// runs: POST /v1/ingest/eval-runs (\"Mode D\"). Each generation carries a\n// `surfaceHash` (the proposed-change identity) + arbitrary `surface` provenance;\n// a later `gate-decided` event re-emits the same `runId` (idempotent upsert) with\n// a real `gateDecision` + `holdoutLift`, so proposal→verdict is one diffable\n// record. This is how a consumer's RSI loop records WHAT it changed, WHY, from\n// which evidence — the audit trail behind agentic self-improvement.\n\n/** Wire version the eval-runs ingest enforces (X-Tangle-Wire-Version + body). */\nexport const INTELLIGENCE_WIRE_VERSION = '2026-05-26.v1'\n\nexport interface EvalRunGeneration {\n /** 0-based ordinal of this generation within the run (required by ingest). */\n index: number\n /** Identity of the proposed surface change (content-addressed hash). */\n surfaceHash: string\n /** Arbitrary provenance for this generation (rationale, evidence, source). */\n surface?: unknown\n /** Per-scenario results; empty until the generation is measured. */\n cells?: unknown[]\n /** Mean composite score (0 when unmeasured — pair with labels.measured). */\n compositeMean: number\n costUsd: number\n durationMs: number\n}\n\nexport interface EvalRunEvent {\n runId: string\n runDir: string\n /** ISO timestamp. */\n timestamp: string\n status:\n | 'started'\n | 'baseline-complete'\n | 'generation-complete'\n | 'gate-decided'\n | 'finished'\n | 'errored'\n labels?: Record<string, string>\n baseline?: EvalRunGeneration\n generations?: EvalRunGeneration[]\n gateDecision?: 'ship' | 'hold' | 'need_more_work' | 'model_ceiling' | 'arch_ceiling'\n holdoutLift?: number\n totalCostUsd: number\n totalDurationMs: number\n errorMessage?: string\n}\n\nexport interface EvalRunsExportConfig {\n /** Bearer key — tenant is resolved server-side from it. Reads TANGLE_API_KEY. */\n apiKey?: string\n /** Intelligence base. Reads INTELLIGENCE_BASE env, else prod. */\n base?: string\n /** Idempotency-Key header (e.g. the runId) — safe retries + upsert. */\n idempotencyKey?: string\n}\n\nexport interface EvalRunsExportResult {\n ok: boolean\n status: number\n accepted: number\n rejected: Array<{ index: number; reason: string }>\n}\n\nconst DEFAULT_INTELLIGENCE_BASE = 'https://intelligence.tangle.tools'\n\n/**\n * Ship self-improvement eval-run events to Tangle Intelligence. Unlike the\n * best-effort span exporter, this RESOLVES with the ingest verdict (accepted /\n * rejected per event) so a consumer's loop can assert its provenance landed.\n * Throws only on a missing key or network failure.\n */\nexport async function exportEvalRuns(\n events: EvalRunEvent[],\n config?: EvalRunsExportConfig,\n): Promise<EvalRunsExportResult> {\n if (events.length === 0) return { ok: true, status: 0, accepted: 0, rejected: [] }\n const apiKey =\n config?.apiKey ?? (typeof process !== 'undefined' ? process.env.TANGLE_API_KEY : undefined)\n if (!apiKey)\n throw new Error('exportEvalRuns: apiKey required (pass config.apiKey or set TANGLE_API_KEY)')\n const base =\n config?.base ??\n (typeof process !== 'undefined' ? process.env.INTELLIGENCE_BASE : undefined) ??\n DEFAULT_INTELLIGENCE_BASE\n const url = `${base.replace(/\\/+$/, '')}/v1/ingest/eval-runs`\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${apiKey}`,\n 'X-Tangle-Wire-Version': INTELLIGENCE_WIRE_VERSION,\n ...(config?.idempotencyKey ? { 'Idempotency-Key': config.idempotencyKey } : {}),\n },\n body: JSON.stringify({ wireVersion: INTELLIGENCE_WIRE_VERSION, events }),\n })\n let parsed: { accepted?: number; rejected?: Array<{ index: number; reason: string }> } = {}\n try {\n parsed = (await res.json()) as typeof parsed\n } catch {\n // non-JSON body (e.g. 5xx HTML) — leave parsed empty\n }\n return {\n ok: res.ok,\n status: res.status,\n accepted: parsed.accepted ?? (res.ok ? events.length : 0),\n rejected: parsed.rejected ?? [],\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/otel-export.ts"],"sourcesContent":["/**\n * OTEL span exporter — streams LoopTraceEvents to an OTLP/HTTP collector.\n *\n * Reads OTEL_EXPORTER_OTLP_ENDPOINT + OTEL_EXPORTER_OTLP_HEADERS from env\n * when no explicit config is given. Keeps the runtime dep-free from\n * @opentelemetry/sdk-trace-base — minimal OTLP/JSON serializer.\n *\n * The exporter accepts both raw OtelSpan objects and LoopTraceEvents\n * (which get converted to OTLP spans automatically).\n */\n\nexport interface OtelExportConfig {\n /** OTLP endpoint. Reads OTEL_EXPORTER_OTLP_ENDPOINT env by default. */\n endpoint?: string\n /** OTLP headers. Reads OTEL_EXPORTER_OTLP_HEADERS env by default. */\n headers?: Record<string, string>\n /** Batch size before flush. Default 64. */\n batchSize?: number\n /** Flush interval ms. Default 5000. */\n flushIntervalMs?: number\n /** Resource attributes stamped on every export. */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Service name. Default 'agent-runtime'. */\n serviceName?: string\n}\n\nexport interface OtelExporter {\n /** Export a span. */\n exportSpan(span: OtelSpan): void\n /** Force flush pending spans. */\n flush(): Promise<void>\n /** Shutdown cleanly. */\n shutdown(): Promise<void>\n}\n\nexport interface OtelSpan {\n traceId: string\n spanId: string\n parentSpanId?: string\n name: string\n kind?: number\n startTimeUnixNano: string\n endTimeUnixNano: string\n attributes?: OtelAttribute[]\n status?: { code: number; message?: string }\n}\n\nexport interface OtelAttribute {\n key: string\n value: { stringValue?: string; intValue?: string; doubleValue?: number; boolValue?: boolean }\n}\n\ninterface OtlpResourceSpans {\n resource: { attributes: OtelAttribute[] }\n scopeSpans: Array<{ scope: { name: string; version: string }; spans: OtelSpan[] }>\n}\n\ninterface OtlpExport {\n resourceSpans: OtlpResourceSpans[]\n}\n\nconst SCOPE = { name: '@tangle-network/agent-runtime', version: '0.81.1' }\n\n/**\n * Current (non-deprecated) OpenTelemetry GenAI semantic-convention keys.\n * Registry: https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/\n * NB: `gen_ai.system` / `gen_ai.usage.prompt_tokens` / `completion_tokens` are\n * DEPRECATED — do not emit them. We use `provider.name` + `input/output_tokens`.\n */\nconst GEN_AI = {\n operation: 'gen_ai.operation.name',\n agentName: 'gen_ai.agent.name',\n conversationId: 'gen_ai.conversation.id',\n inputTokens: 'gen_ai.usage.input_tokens',\n outputTokens: 'gen_ai.usage.output_tokens',\n} as const\n\n/**\n * Create an OTEL exporter. Returns undefined when no endpoint is configured.\n */\nexport function createOtelExporter(config?: OtelExportConfig): OtelExporter | undefined {\n const resolvedEndpoint =\n config?.endpoint ??\n (typeof process !== 'undefined' ? process.env.OTEL_EXPORTER_OTLP_ENDPOINT : undefined)\n if (!resolvedEndpoint) return undefined\n const endpoint: string = resolvedEndpoint\n\n const headers = config?.headers ?? parseHeadersFromEnv()\n const batchSize = config?.batchSize ?? 64\n const flushIntervalMs = config?.flushIntervalMs ?? 5000\n const serviceName = config?.serviceName ?? 'agent-runtime'\n const resourceAttrs = config?.resourceAttributes ?? {}\n\n const pending: OtelSpan[] = []\n let timer: ReturnType<typeof setInterval> | undefined\n let stopped = false\n\n const exporter: OtelExporter = {\n exportSpan(span: OtelSpan): void {\n if (stopped) return\n pending.push(span)\n if (pending.length >= batchSize) {\n void doFlush()\n }\n },\n\n async flush(): Promise<void> {\n await doFlush()\n },\n\n async shutdown(): Promise<void> {\n stopped = true\n if (timer !== undefined) {\n clearInterval(timer)\n timer = undefined\n }\n await doFlush()\n },\n }\n\n timer = setInterval(() => {\n if (pending.length > 0) void doFlush()\n }, flushIntervalMs)\n if (typeof timer === 'object' && 'unref' in timer) {\n ;(timer as NodeJS.Timeout).unref()\n }\n\n async function doFlush(): Promise<void> {\n if (pending.length === 0) return\n const batch = pending.splice(0)\n const body: OtlpExport = {\n resourceSpans: [\n {\n resource: {\n attributes: toAttributes({\n 'service.name': serviceName,\n ...resourceAttrs,\n }),\n },\n scopeSpans: [{ scope: SCOPE, spans: batch }],\n },\n ],\n }\n const url = `${endpoint.replace(/\\/+$/, '')}/v1/traces`\n try {\n await fetch(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...headers },\n body: JSON.stringify(body),\n })\n } catch {\n // Best-effort — telemetry export must not crash the runtime.\n }\n }\n\n return exporter\n}\n\n/**\n * Convert a LoopTraceEvent into an OtelSpan for export.\n */\nexport function loopEventToOtelSpan(\n event: {\n kind: string\n runId: string\n timestamp: number\n payload: object\n },\n traceId: string,\n parentSpanId?: string,\n): OtelSpan {\n const spanId = generateSpanId()\n const attrs: Record<string, string | number | boolean> = {\n 'loop.event_kind': event.kind,\n 'loop.run_id': event.runId,\n }\n for (const [k, v] of Object.entries(event.payload)) {\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {\n attrs[`loop.${k}`] = v\n }\n }\n const ts = msToNs(event.timestamp)\n return {\n traceId: padTraceId(traceId),\n spanId,\n parentSpanId: parentSpanId ? padSpanId(parentSpanId) : undefined,\n name: event.kind,\n kind: 1,\n startTimeUnixNano: ts,\n endTimeUnixNano: ts,\n attributes: toAttributes(attrs),\n status: { code: 1 },\n }\n}\n\n/**\n * Build a single flat OtelSpan whose attribute keys are emitted VERBATIM — no\n * `loop.` namespace. Use for non-loop spans (e.g. the intelligence per-run\n * span) whose keys ARE the downstream contract (`gen_ai.request.model`,\n * `tangle.sessionId`) and are exact-matched by readers. `loopEventToOtelSpan`\n * namespaces payload keys because loop payload fields are free-form; do not\n * reuse it for spans with contract keys.\n */\nexport function flatOtelSpan(\n name: string,\n attributes: Record<string, string | number | boolean>,\n traceId: string,\n timestampMs: number,\n parentSpanId?: string,\n): OtelSpan {\n const ts = msToNs(timestampMs)\n return {\n traceId: padTraceId(traceId),\n spanId: generateSpanId(),\n parentSpanId: parentSpanId ? padSpanId(parentSpanId) : undefined,\n name,\n kind: 1,\n startTimeUnixNano: ts,\n endTimeUnixNano: ts,\n attributes: toAttributes(attributes),\n status: { code: 1 },\n }\n}\n\n/**\n * Sink-neutral node in a reconstructed loop span tree. The root node's\n * `parentSpanId` is `undefined` — sinks decide how to parent it (the OTEL\n * mapper attaches the inherited delegation span; the delegation journal\n * leaves it as the tree root).\n */\nexport interface LoopSpanNode {\n spanId: string\n parentSpanId?: string\n /** `'loop'` | `'loop.round'` | `'loop.iteration'`. */\n name: string\n /** Topology level: loop root, plan round, or iteration branch. */\n kind: 'loop' | 'round' | 'branch'\n startMs: number\n endMs: number\n attrs: Record<string, string | number | boolean>\n /** True when the iteration carried an error — maps to OTEL status code 2. */\n error: boolean\n}\n\n/**\n * Build a nested, real-duration OTLP span tree for ONE loop run from its full\n * ordered `LoopTraceEvent` stream. Unlike `loopEventToOtelSpan` (one flat,\n * zero-duration span per event), this reconstructs the topology hierarchy a\n * GenAI trace viewer renders natively:\n *\n * loop (invoke_workflow)\n * └─ loop.round[k] (invoke_workflow) ← tangle.loop.move.{kind,width,rationale}\n * ├─ loop.iteration[i] (invoke_agent) ← gen_ai.agent.name + usage + verdict + placement\n * └─ …\n *\n * Attributes follow the current GenAI semconv (`gen_ai.*`) where they apply and\n * a namespaced `tangle.loop.*` / `tangle.cost.usd` extension for topology /\n * verdict / placement / cost (not yet standardized). Pure: feed it a buffered\n * per-runId event array (e.g. flushed on `loop.ended`) and export the result.\n */\nexport function buildLoopOtelSpans(\n events: ReadonlyArray<{ kind: string; runId: string; timestamp: number; payload: object }>,\n traceId: string,\n rootParentSpanId?: string,\n): OtelSpan[] {\n const tid = padTraceId(traceId)\n return buildLoopSpanNodes(events).map((node) => ({\n traceId: tid,\n spanId: node.spanId,\n parentSpanId: node.parentSpanId\n ? padSpanId(node.parentSpanId)\n : rootParentSpanId\n ? padSpanId(rootParentSpanId)\n : undefined,\n name: node.name,\n kind: 1,\n startTimeUnixNano: msToNs(node.startMs),\n endTimeUnixNano: msToNs(node.endMs),\n attributes: toAttributes(node.attrs),\n status: { code: node.error ? 2 : 1 },\n }))\n}\n\n/**\n * Sink-neutral core behind {@link buildLoopOtelSpans}: reconstruct the\n * loop → round → branch span tree from one run's ordered `LoopTraceEvent`\n * stream. Consumed by the OTEL mapper above and by the MCP delegation\n * journal's compact trace tee — one topology reconstruction, two sinks.\n * Tolerates partial streams (a run that never reached `loop.ended` closes\n * at the last observed event's timestamp).\n */\nexport function buildLoopSpanNodes(\n events: ReadonlyArray<{ kind: string; runId: string; timestamp: number; payload: object }>,\n): LoopSpanNode[] {\n if (events.length === 0) return []\n const out: LoopSpanNode[] = []\n const num = (v: unknown): number | undefined =>\n typeof v === 'number' && Number.isFinite(v) ? v : undefined\n const str = (v: unknown): string | undefined =>\n typeof v === 'string' && v.length > 0 ? v : undefined\n const rec = (v: unknown): Record<string, unknown> =>\n v && typeof v === 'object' ? (v as Record<string, unknown>) : {}\n\n const started = events.find((e) => e.kind === 'loop.started')\n const ended = events.find((e) => e.kind === 'loop.ended')\n const runId = events[0]?.runId ?? ''\n const rootStart = started?.timestamp ?? events[0]!.timestamp\n const rootEnd = ended?.timestamp ?? events[events.length - 1]!.timestamp\n const rootId = generateSpanId()\n\n const make = (\n spanId: string,\n parentSpanId: string | undefined,\n name: string,\n kind: LoopSpanNode['kind'],\n startMs: number,\n endMs: number,\n attrs: Record<string, string | number | boolean>,\n error = false,\n ): LoopSpanNode => ({\n spanId,\n parentSpanId,\n name,\n kind,\n startMs,\n endMs,\n attrs,\n error,\n })\n\n // root\n const sp = rec(started?.payload)\n const rootAttrs: Record<string, string | number | boolean> = {\n [GEN_AI.operation]: 'invoke_workflow',\n [GEN_AI.conversationId]: runId,\n // Explicit run identity under the tangle namespace so a consuming system of\n // record (Tangle Intelligence's run spine) maps this span tree to one run\n // deterministically, instead of inferring it from the conversation id.\n 'tangle.run.id': runId,\n 'tangle.loop.driver': str(sp.driver) ?? 'driver',\n }\n if (Array.isArray(sp.agentRunNames) && sp.agentRunNames.length > 0) {\n rootAttrs['tangle.loop.agents'] = sp.agentRunNames.map(String).join(',')\n // Subject grain: the primary agent/profile this run drove. Lets the spine\n // group runs under the thing being worked on rather than one service-wide\n // bucket. `agentRunNames[0]` is the lead agent on a fan-out.\n rootAttrs['tangle.subject.key'] = String(sp.agentRunNames[0])\n }\n if (ended) {\n const ep = rec(ended.payload)\n const win = num(ep.winnerIterationIndex)\n if (win !== undefined) rootAttrs['tangle.loop.winner.iteration_index'] = win\n const cost = num(ep.totalCostUsd)\n if (cost !== undefined) rootAttrs['tangle.cost.usd'] = cost\n const dur = num(ep.durationMs)\n if (dur !== undefined) rootAttrs['tangle.loop.duration_ms'] = dur\n const iters = num(ep.iterations)\n if (iters !== undefined) rootAttrs['tangle.loop.iterations'] = iters\n }\n out.push(make(rootId, undefined, 'loop', 'loop', rootStart, rootEnd, rootAttrs))\n\n // rounds + iterations\n const iterStartTs = new Map<number, number>()\n const placementByIdx = new Map<number, Record<string, string>>()\n let currentRoundId: string | undefined\n let pendingRound:\n | { id: string; start: number; attrs: Record<string, string | number | boolean> }\n | undefined\n const flushRound = (endMs: number) => {\n if (!pendingRound) return\n out.push(\n make(\n pendingRound.id,\n rootId,\n 'loop.round',\n 'round',\n pendingRound.start,\n endMs,\n pendingRound.attrs,\n ),\n )\n pendingRound = undefined\n }\n\n for (const e of events) {\n const p = rec(e.payload)\n switch (e.kind) {\n case 'loop.plan': {\n flushRound(e.timestamp)\n const id = generateSpanId()\n const roundIdx = num(p.roundIndex) ?? 0\n const attrs: Record<string, string | number | boolean> = {\n [GEN_AI.operation]: 'invoke_workflow',\n 'tangle.loop.round.index': roundIdx,\n 'tangle.loop.move.kind': str(p.moveKind) ?? 'unknown',\n 'tangle.loop.move.round': roundIdx,\n 'tangle.loop.move.width': num(p.plannedCount) ?? 0,\n }\n const r = str(p.rationale)\n if (r) attrs['tangle.loop.move.rationale'] = r\n const parent = num(p.parentIndex)\n if (parent !== undefined) attrs['tangle.loop.move.parent_index'] = parent\n if (Array.isArray(p.childIndices) && p.childIndices.length > 0) {\n attrs['tangle.loop.move.child_indices'] = p.childIndices.map(String).join(',')\n }\n pendingRound = { id, start: e.timestamp, attrs }\n currentRoundId = id\n break\n }\n case 'loop.iteration.started': {\n const idx = num(p.iterationIndex)\n if (idx !== undefined) iterStartTs.set(idx, e.timestamp)\n break\n }\n case 'loop.iteration.dispatch': {\n const idx = num(p.iterationIndex)\n if (idx === undefined) break\n const place: Record<string, string> = {}\n const kind = str(p.placement)\n if (kind) place['tangle.loop.placement.kind'] = kind\n const sid = str(p.sandboxId)\n if (sid) place['tangle.sandbox.id'] = sid\n const fid = str(p.fleetId)\n if (fid) place['tangle.fleet.id'] = fid\n const mid = str(p.machineId)\n if (mid) place['tangle.machine.id'] = mid\n placementByIdx.set(idx, place)\n break\n }\n case 'loop.iteration.ended': {\n const idx = num(p.iterationIndex) ?? 0\n const start = iterStartTs.get(idx) ?? e.timestamp\n const err = str(p.error)\n const attrs: Record<string, string | number | boolean> = {\n [GEN_AI.operation]: 'invoke_agent',\n 'tangle.loop.iteration.index': idx,\n }\n const agent = str(p.agentRunName)\n if (agent) attrs[GEN_AI.agentName] = agent\n const tu = rec(p.tokenUsage)\n const inTok = num(tu.input)\n if (inTok !== undefined) attrs[GEN_AI.inputTokens] = inTok\n const outTok = num(tu.output)\n if (outTok !== undefined) attrs[GEN_AI.outputTokens] = outTok\n const cost = num(p.costUsd)\n if (cost !== undefined) attrs['tangle.cost.usd'] = cost\n const verdict = rec(p.verdict)\n if (typeof verdict.valid === 'boolean') attrs['tangle.loop.verdict.valid'] = verdict.valid\n const score = num(verdict.score)\n if (score !== undefined) attrs['tangle.loop.verdict.score'] = score\n if (err) attrs['tangle.loop.error'] = err\n const gid = num(p.groupId)\n if (gid !== undefined) attrs['tangle.loop.iteration.group_id'] = gid\n const par = num(p.parentIndex)\n if (par !== undefined) attrs['tangle.loop.iteration.parent_index'] = par\n const dur = num(p.durationMs)\n if (dur !== undefined) attrs['tangle.loop.iteration.duration_ms'] = dur\n const preview = str(p.outputPreview)\n if (preview) attrs['tangle.loop.iteration.output_preview'] = preview\n Object.assign(attrs, placementByIdx.get(idx) ?? {})\n out.push(\n make(\n generateSpanId(),\n currentRoundId ?? rootId,\n 'loop.iteration',\n 'branch',\n start,\n e.timestamp,\n attrs,\n err !== undefined,\n ),\n )\n break\n }\n case 'loop.decision': {\n if (pendingRound) {\n const dec = str(p.decision)\n if (dec) pendingRound.attrs['tangle.loop.decision'] = dec\n flushRound(e.timestamp)\n }\n currentRoundId = undefined\n break\n }\n }\n }\n flushRound(rootEnd)\n return out\n}\n\nfunction parseHeadersFromEnv(): Record<string, string> {\n if (typeof process === 'undefined') return {}\n const raw = process.env.OTEL_EXPORTER_OTLP_HEADERS\n if (!raw) return {}\n const out: Record<string, string> = {}\n for (const pair of raw.split(',')) {\n const eq = pair.indexOf('=')\n if (eq < 0) continue\n const key = pair.slice(0, eq).trim()\n const value = pair.slice(eq + 1).trim()\n if (key) out[key] = value\n }\n return out\n}\n\nfunction toAttributes(record: Record<string, string | number | boolean>): OtelAttribute[] {\n return Object.entries(record).map(([key, value]) => ({\n key,\n value:\n typeof value === 'number'\n ? Number.isInteger(value)\n ? { intValue: value.toString() }\n : { doubleValue: value }\n : typeof value === 'boolean'\n ? { boolValue: value }\n : { stringValue: value },\n }))\n}\n\nfunction msToNs(ms: number): string {\n return (BigInt(Math.floor(ms)) * 1_000_000n).toString()\n}\n\nfunction padSpanId(id: string): string {\n const cleaned = id.replace(/-/g, '')\n return cleaned.slice(0, 16).padEnd(16, '0')\n}\n\nfunction padTraceId(id: string): string {\n const cleaned = id.replace(/-/g, '')\n return cleaned.slice(0, 32).padEnd(32, '0')\n}\n\nfunction generateSpanId(): string {\n const bytes = new Uint8Array(8)\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes)\n } else {\n for (let i = 0; i < 8; i++) bytes[i] = Math.floor(Math.random() * 256)\n }\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n// ─── Eval-run ingest (self-improvement provenance) ───────────────────────────\n//\n// Tangle Intelligence has a first-class, non-trace record for self-improvement\n// runs: POST /v1/ingest/eval-runs (\"Mode D\"). Each generation carries a\n// `surfaceHash` (the proposed-change identity) + arbitrary `surface` provenance;\n// a later `gate-decided` event re-emits the same `runId` (idempotent upsert) with\n// a real `gateDecision` + `holdoutLift`, so proposal→verdict is one diffable\n// record. This is how a consumer's RSI loop records WHAT it changed, WHY, from\n// which evidence — the audit trail behind agentic self-improvement.\n\n/** Wire version the eval-runs ingest enforces (X-Tangle-Wire-Version + body). */\nexport const INTELLIGENCE_WIRE_VERSION = '2026-05-26.v1'\n\nexport interface EvalRunGeneration {\n /** 0-based ordinal of this generation within the run (required by ingest). */\n index: number\n /** Identity of the proposed surface change (content-addressed hash). */\n surfaceHash: string\n /** Arbitrary provenance for this generation (rationale, evidence, source). */\n surface?: unknown\n /** Per-scenario results; empty until the generation is measured. */\n cells?: unknown[]\n /** Mean composite score (0 when unmeasured — pair with labels.measured). */\n compositeMean: number\n costUsd: number\n durationMs: number\n}\n\nexport interface EvalRunEvent {\n runId: string\n runDir: string\n /** ISO timestamp. */\n timestamp: string\n status:\n | 'started'\n | 'baseline-complete'\n | 'generation-complete'\n | 'gate-decided'\n | 'finished'\n | 'errored'\n labels?: Record<string, string>\n baseline?: EvalRunGeneration\n generations?: EvalRunGeneration[]\n gateDecision?: 'ship' | 'hold' | 'need_more_work' | 'model_ceiling' | 'arch_ceiling'\n holdoutLift?: number\n totalCostUsd: number\n totalDurationMs: number\n errorMessage?: string\n}\n\nexport interface EvalRunsExportConfig {\n /** Bearer key — tenant is resolved server-side from it. Reads TANGLE_API_KEY. */\n apiKey?: string\n /** Intelligence base. Reads INTELLIGENCE_BASE env, else prod. */\n base?: string\n /** Idempotency-Key header (e.g. the runId) — safe retries + upsert. */\n idempotencyKey?: string\n}\n\nexport interface EvalRunsExportResult {\n ok: boolean\n status: number\n accepted: number\n rejected: Array<{ index: number; reason: string }>\n}\n\nconst DEFAULT_INTELLIGENCE_BASE = 'https://intelligence.tangle.tools'\n\n/**\n * Ship self-improvement eval-run events to Tangle Intelligence. Unlike the\n * best-effort span exporter, this RESOLVES with the ingest verdict (accepted /\n * rejected per event) so a consumer's loop can assert its provenance landed.\n * Throws only on a missing key or network failure.\n */\nexport async function exportEvalRuns(\n events: EvalRunEvent[],\n config?: EvalRunsExportConfig,\n): Promise<EvalRunsExportResult> {\n if (events.length === 0) return { ok: true, status: 0, accepted: 0, rejected: [] }\n const apiKey =\n config?.apiKey ?? (typeof process !== 'undefined' ? process.env.TANGLE_API_KEY : undefined)\n if (!apiKey)\n throw new Error('exportEvalRuns: apiKey required (pass config.apiKey or set TANGLE_API_KEY)')\n const base =\n config?.base ??\n (typeof process !== 'undefined' ? process.env.INTELLIGENCE_BASE : undefined) ??\n DEFAULT_INTELLIGENCE_BASE\n const url = `${base.replace(/\\/+$/, '')}/v1/ingest/eval-runs`\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${apiKey}`,\n 'X-Tangle-Wire-Version': INTELLIGENCE_WIRE_VERSION,\n ...(config?.idempotencyKey ? { 'Idempotency-Key': config.idempotencyKey } : {}),\n },\n body: JSON.stringify({ wireVersion: INTELLIGENCE_WIRE_VERSION, events }),\n })\n let parsed: { accepted?: number; rejected?: Array<{ index: number; reason: string }> } = {}\n try {\n parsed = (await res.json()) as typeof parsed\n } catch {\n // non-JSON body (e.g. 5xx HTML) — leave parsed empty\n }\n return {\n ok: res.ok,\n status: res.status,\n accepted: parsed.accepted ?? (res.ok ? events.length : 0),\n rejected: parsed.rejected ?? [],\n }\n}\n"],"mappings":"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","names":[]}
@@ -14,7 +14,7 @@ import {
14
14
  settledToIteration,
15
15
  supervise,
16
16
  withDriverExecutor
17
- } from "./chunk-3TAQW75Y.js";
17
+ } from "./chunk-VHJDS6OR.js";
18
18
  import {
19
19
  addTokenUsage,
20
20
  isAbortError,
@@ -555,195 +555,6 @@ ${rows}
555
555
  </body></html>`;
556
556
  }
557
557
 
558
- // src/runtime/cli-bridge-sandbox-client.ts
559
- import { request as httpRequest } from "http";
560
- import { request as httpsRequest } from "https";
561
-
562
- // src/runtime/inline-sandbox-client.ts
563
- function isAsyncIterable(v) {
564
- return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
565
- }
566
- async function settle(exec, task, signal) {
567
- const r = exec.execute(task, signal);
568
- if (isAsyncIterable(r)) {
569
- for await (const _ of r) {
570
- }
571
- return exec.resultArtifact();
572
- }
573
- return r;
574
- }
575
- function inlineSandboxClient(factory) {
576
- let seq = 0;
577
- return {
578
- async create(options) {
579
- const id = `inline-${seq++}`;
580
- const createOptions = options;
581
- return {
582
- id,
583
- async *streamPrompt(message) {
584
- const controller = new AbortController();
585
- const spec = { profile: { name: id }, harness: null };
586
- const exec = factory(spec, { signal: controller.signal, seams: { createOptions } });
587
- try {
588
- const artifact = await settle(exec, message, controller.signal);
589
- const out = artifact.out;
590
- const tokensIn = artifact.spent.tokens.input;
591
- const tokensOut = artifact.spent.tokens.output;
592
- const costUsd = artifact.spent.usd;
593
- if (tokensIn || tokensOut || costUsd) {
594
- yield {
595
- type: "llm_call",
596
- data: { tokensIn, tokensOut, costUsd }
597
- };
598
- }
599
- yield {
600
- type: "result",
601
- data: {
602
- finalText: out?.content ?? "",
603
- tokenUsage: {
604
- inputTokens: tokensIn,
605
- outputTokens: tokensOut
606
- },
607
- costUsd
608
- }
609
- };
610
- } finally {
611
- await exec.teardown("brutalKill").catch(() => {
612
- });
613
- }
614
- },
615
- async delete() {
616
- }
617
- };
618
- }
619
- };
620
- }
621
-
622
- // src/runtime/cli-bridge-sandbox-client.ts
623
- var DEFAULT_BRIDGE_URL = "http://127.0.0.1:3355";
624
- var BRIDGE_TIMEOUT_MS = 9e5;
625
- function bridgeModelId(harness, model) {
626
- return model.startsWith(`${harness}/`) ? model : `${harness}/${model}`;
627
- }
628
- function resolveTarget(cfg, createOptions) {
629
- const backend = createOptions?.backend;
630
- const harness = backend?.type ?? cfg.harness;
631
- const model = backend?.model?.model ?? cfg.model;
632
- if (!harness)
633
- throw new Error(
634
- "cliBridgeSandboxClient: no harness (set cfg.harness or create({ backend: { type } }))"
635
- );
636
- if (!model)
637
- throw new Error(
638
- "cliBridgeSandboxClient: no model (set cfg.model or create({ backend: { model: { model } } }))"
639
- );
640
- return { harness, model };
641
- }
642
- function bridgePost(url, bearer, bridgeModel, prompt, signal) {
643
- const target = new URL(`${url.replace(/\/$/, "")}/v1/chat/completions`);
644
- const body = JSON.stringify({ model: bridgeModel, messages: [{ role: "user", content: prompt }] });
645
- const requestFn = target.protocol === "https:" ? httpsRequest : httpRequest;
646
- return new Promise((resolve, reject) => {
647
- if (signal.aborted) {
648
- reject(new Error(`cli-bridge ${bridgeModel}: aborted before request`));
649
- return;
650
- }
651
- const req = requestFn(
652
- target,
653
- {
654
- method: "POST",
655
- headers: {
656
- "content-type": "application/json",
657
- authorization: `Bearer ${bearer}`,
658
- "content-length": Buffer.byteLength(body)
659
- },
660
- // No header/body idle timeout: a slow bridge is a live bridge; the abort
661
- // signal is the sole deadline.
662
- timeout: 0
663
- },
664
- (res) => {
665
- const chunks = [];
666
- res.on("data", (c) => chunks.push(c));
667
- res.on("end", () => {
668
- const text = Buffer.concat(chunks).toString("utf8");
669
- const status = res.statusCode ?? 0;
670
- if (status < 200 || status >= 300) {
671
- reject(new Error(`cli-bridge ${bridgeModel}: HTTP ${status} ${text.slice(0, 300)}`));
672
- return;
673
- }
674
- let j;
675
- try {
676
- j = JSON.parse(text);
677
- } catch {
678
- reject(new Error(`cli-bridge ${bridgeModel}: non-JSON body ${text.slice(0, 300)}`));
679
- return;
680
- }
681
- if (j.error) {
682
- reject(new Error(`cli-bridge ${bridgeModel}: ${j.error.message}`));
683
- return;
684
- }
685
- resolve({
686
- content: j.choices?.[0]?.message?.content ?? "",
687
- input: j.usage?.prompt_tokens ?? 0,
688
- output: j.usage?.completion_tokens ?? 0
689
- });
690
- });
691
- }
692
- );
693
- const onAbort = () => {
694
- req.destroy(
695
- new Error(
696
- `cli-bridge ${bridgeModel}: aborted (${BRIDGE_TIMEOUT_MS}ms deadline or upstream cancel)`
697
- )
698
- );
699
- };
700
- signal.addEventListener("abort", onAbort, { once: true });
701
- req.on("error", (e) => reject(new Error(`cli-bridge ${bridgeModel}: ${e.message}`)));
702
- req.on("close", () => signal.removeEventListener("abort", onAbort));
703
- req.write(body);
704
- req.end();
705
- });
706
- }
707
- function cliBridgeSandboxClient(cfg) {
708
- if (!cfg.bearer) throw new Error("cliBridgeSandboxClient: bearer is required");
709
- const url = cfg.url ?? DEFAULT_BRIDGE_URL;
710
- let seq = 0;
711
- const factory = (_spec, ctx) => {
712
- const id = `cli-bridge-${seq++}`;
713
- const createOptions = ctx.seams.createOptions;
714
- const { harness, model } = resolveTarget(cfg, createOptions);
715
- const bridgeModel = bridgeModelId(harness, model);
716
- let artifact;
717
- return {
718
- runtime: "cli",
719
- async execute(task, signal) {
720
- const started = Date.now();
721
- const timeout = AbortSignal.timeout(BRIDGE_TIMEOUT_MS);
722
- const composed = AbortSignal.any([signal, timeout]);
723
- const r = await bridgePost(url, cfg.bearer, bridgeModel, String(task), composed);
724
- artifact = {
725
- outRef: `cli-bridge:${id}`,
726
- out: { content: r.content },
727
- spent: {
728
- iterations: 1,
729
- tokens: { input: r.input, output: r.output },
730
- usd: 0,
731
- ms: Date.now() - started
732
- }
733
- };
734
- return artifact;
735
- },
736
- teardown: () => Promise.resolve({ destroyed: true }),
737
- resultArtifact() {
738
- if (!artifact)
739
- throw new Error("cliBridgeSandboxClient: resultArtifact() read before execute()");
740
- return artifact;
741
- }
742
- };
743
- };
744
- return inlineSandboxClient(factory);
745
- }
746
-
747
558
  // src/runtime/completion.ts
748
559
  function completionAuthorizes(v, policy) {
749
560
  if (!v?.done) return false;
@@ -1005,7 +816,7 @@ import { mkdtempSync, rmSync } from "fs";
1005
816
  import { mkdir, readFile, writeFile } from "fs/promises";
1006
817
  import { tmpdir } from "os";
1007
818
  import { dirname, join } from "path";
1008
- function isAsyncIterable2(v) {
819
+ function isAsyncIterable(v) {
1009
820
  return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
1010
821
  }
1011
822
  function inProcessSandboxClient(options) {
@@ -1056,7 +867,7 @@ function inProcessSandboxClient(options) {
1056
867
  const ctx = { round, workdir: boxWorkdir, signal };
1057
868
  round += 1;
1058
869
  const produced = await onPrompt(prompt, ctx);
1059
- if (isAsyncIterable2(produced)) {
870
+ if (isAsyncIterable(produced)) {
1060
871
  for await (const ev of produced) yield ev;
1061
872
  } else {
1062
873
  for (const ev of produced) yield ev;
@@ -1072,6 +883,66 @@ function inProcessSandboxClient(options) {
1072
883
  };
1073
884
  }
1074
885
 
886
+ // src/runtime/inline-sandbox-client.ts
887
+ function isAsyncIterable2(v) {
888
+ return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
889
+ }
890
+ async function settle(exec, task, signal) {
891
+ const r = exec.execute(task, signal);
892
+ if (isAsyncIterable2(r)) {
893
+ for await (const _ of r) {
894
+ }
895
+ return exec.resultArtifact();
896
+ }
897
+ return r;
898
+ }
899
+ function inlineSandboxClient(factory) {
900
+ let seq = 0;
901
+ return {
902
+ async create(options) {
903
+ const id = `inline-${seq++}`;
904
+ const createOptions = options;
905
+ return {
906
+ id,
907
+ async *streamPrompt(message) {
908
+ const controller = new AbortController();
909
+ const spec = { profile: { name: id }, harness: null };
910
+ const exec = factory(spec, { signal: controller.signal, seams: { createOptions } });
911
+ try {
912
+ const artifact = await settle(exec, message, controller.signal);
913
+ const out = artifact.out;
914
+ const tokensIn = artifact.spent.tokens.input;
915
+ const tokensOut = artifact.spent.tokens.output;
916
+ const costUsd = artifact.spent.usd;
917
+ if (tokensIn || tokensOut || costUsd) {
918
+ yield {
919
+ type: "llm_call",
920
+ data: { tokensIn, tokensOut, costUsd }
921
+ };
922
+ }
923
+ yield {
924
+ type: "result",
925
+ data: {
926
+ finalText: out?.content ?? "",
927
+ tokenUsage: {
928
+ inputTokens: tokensIn,
929
+ outputTokens: tokensOut
930
+ },
931
+ costUsd
932
+ }
933
+ };
934
+ } finally {
935
+ await exec.teardown("brutalKill").catch(() => {
936
+ });
937
+ }
938
+ },
939
+ async delete() {
940
+ }
941
+ };
942
+ }
943
+ };
944
+ }
945
+
1075
946
  // src/runtime/report-usage.ts
1076
947
  function reportLoopUsage(cost, result, source = "loop") {
1077
948
  cost.observe(result.costUsd, source);
@@ -4755,8 +4626,6 @@ export {
4755
4626
  renderPairwiseMarkdown,
4756
4627
  renderLeaderboardSvg,
4757
4628
  renderLeaderboardHtml,
4758
- inlineSandboxClient,
4759
- cliBridgeSandboxClient,
4760
4629
  completionAuthorizes,
4761
4630
  stopSentinel,
4762
4631
  sentinelCompletion,
@@ -4766,6 +4635,7 @@ export {
4766
4635
  renderReport,
4767
4636
  harvestCorpus,
4768
4637
  inProcessSandboxClient,
4638
+ inlineSandboxClient,
4769
4639
  reportLoopUsage,
4770
4640
  loopCampaignDispatch,
4771
4641
  loopDispatch,
@@ -4834,4 +4704,4 @@ export {
4834
4704
  computeFindingId,
4835
4705
  makeFinding2 as makeFinding
4836
4706
  };
4837
- //# sourceMappingURL=chunk-3RAXZ6LB.js.map
4707
+ //# sourceMappingURL=chunk-D6GIWPKD.js.map