@tangle-network/agent-runtime 0.40.0 → 0.41.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.
- package/dist/{chunk-3WQJRSUJ.js → chunk-4GI7C36B.js} +2 -2
- package/dist/{chunk-VFKBIZTY.js → chunk-FJ4GDNVN.js} +4 -3
- package/dist/chunk-FJ4GDNVN.js.map +1 -0
- package/dist/{chunk-HSX6PFZR.js → chunk-HVYOHJHK.js} +338 -2
- package/dist/chunk-HVYOHJHK.js.map +1 -0
- package/dist/chunk-NRZOXCJK.js +64 -0
- package/dist/chunk-NRZOXCJK.js.map +1 -0
- package/dist/{chunk-6HI3QUJD.js → chunk-WSJJGSD3.js} +51 -5
- package/dist/chunk-WSJJGSD3.js.map +1 -0
- package/dist/{dynamic-BT9Ji3jE.d.ts → dynamic-CazTl_Zp.d.ts} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/dist/{kb-gate-C4tho31v.d.ts → kb-gate-NzOJSnOk.d.ts} +9 -1
- package/dist/{loop-runner-bin-C1MuoT8c.d.ts → loop-runner-bin-DYRzk2cT.d.ts} +3 -3
- package/dist/loop-runner-bin.d.ts +4 -4
- package/dist/loop-runner-bin.js +2 -2
- package/dist/loops.d.ts +4 -4
- package/dist/mcp/bin.js +27 -16
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +3 -3
- package/dist/mcp/index.js +8 -48
- package/dist/mcp/index.js.map +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/{types-CNs7_1R3.d.ts → types-BrJKXXI8.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-6HI3QUJD.js.map +0 -1
- package/dist/chunk-7ZECSZ3C.js +0 -400
- package/dist/chunk-7ZECSZ3C.js.map +0 -1
- package/dist/chunk-HSX6PFZR.js.map +0 -1
- package/dist/chunk-VFKBIZTY.js.map +0 -1
- /package/dist/{chunk-3WQJRSUJ.js.map → chunk-4GI7C36B.js.map} +0 -0
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-FNMGYYSS.js";
|
|
10
10
|
import {
|
|
11
11
|
createDefaultCoderDelegate
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-FJ4GDNVN.js";
|
|
13
13
|
import {
|
|
14
14
|
createDynamicDriver,
|
|
15
15
|
runLoop
|
|
@@ -198,4 +198,4 @@ export {
|
|
|
198
198
|
runLoopRunnerCli,
|
|
199
199
|
parseLoopRunnerArgv
|
|
200
200
|
};
|
|
201
|
-
//# sourceMappingURL=chunk-
|
|
201
|
+
//# sourceMappingURL=chunk-4GI7C36B.js.map
|
|
@@ -78,6 +78,7 @@ function createDefaultCoderDelegate(options) {
|
|
|
78
78
|
const sandboxClient = executor.client;
|
|
79
79
|
const fanoutHarnesses = options.fanoutHarnesses;
|
|
80
80
|
const maxConcurrency = options.maxConcurrency ?? 4;
|
|
81
|
+
const traceEmitter = options.traceEmitter;
|
|
81
82
|
return async (args, ctx) => {
|
|
82
83
|
const task = {
|
|
83
84
|
goal: buildCoderGoal(args),
|
|
@@ -97,7 +98,7 @@ function createDefaultCoderDelegate(options) {
|
|
|
97
98
|
output,
|
|
98
99
|
validator,
|
|
99
100
|
task,
|
|
100
|
-
ctx: { sandboxClient, signal: ctx.signal },
|
|
101
|
+
ctx: { sandboxClient, signal: ctx.signal, ...traceEmitter ? { traceEmitter } : {} },
|
|
101
102
|
maxIterations: 1,
|
|
102
103
|
maxConcurrency
|
|
103
104
|
});
|
|
@@ -122,7 +123,7 @@ function createDefaultCoderDelegate(options) {
|
|
|
122
123
|
output: fanout.output,
|
|
123
124
|
validator: fanout.validator,
|
|
124
125
|
task,
|
|
125
|
-
ctx: { sandboxClient, signal: ctx.signal },
|
|
126
|
+
ctx: { sandboxClient, signal: ctx.signal, ...traceEmitter ? { traceEmitter } : {} },
|
|
126
127
|
maxIterations: variants,
|
|
127
128
|
maxConcurrency: Math.min(maxConcurrency, variants)
|
|
128
129
|
});
|
|
@@ -209,4 +210,4 @@ export {
|
|
|
209
210
|
createFleetWorkspaceExecutor,
|
|
210
211
|
createDefaultCoderDelegate
|
|
211
212
|
};
|
|
212
|
-
//# sourceMappingURL=chunk-
|
|
213
|
+
//# sourceMappingURL=chunk-FJ4GDNVN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/executor.ts","../src/mcp/delegates.ts"],"sourcesContent":["/**\n * @experimental\n *\n * Delegation executors — the layer between MCP delegates and the sandbox\n * substrate. Each executor exposes a {@link LoopSandboxClient} the kernel\n * consumes plus a placement tag so the trace pipeline can correlate workers\n * with their physical placement.\n *\n * Two implementations ship in-box:\n *\n * - {@link createSiblingSandboxExecutor} — every delegation spawns a fresh\n * sandbox sibling to the caller. Default when the MCP server runs as a\n * standalone CLI mounted outside a fleet.\n *\n * - {@link createFleetWorkspaceExecutor} — delegations dispatch onto machines\n * in the caller's existing fleet so worker diffs land directly on the\n * caller's filesystem (the fleet's shared workspace). Selected when the\n * parent sandbox passes `TANGLE_FLEET_ID` into the MCP server's env.\n */\n\nimport type { CreateSandboxOptions, SandboxInstance } from '@tangle-network/sandbox'\nimport type { LoopSandboxClient, LoopSandboxPlacement } from '../loops'\n\n/** @experimental */\nexport interface DelegationExecutor {\n /** Sandbox client the kernel calls. Returned with `describePlacement` set. */\n readonly client: LoopSandboxClient\n /** Best-effort one-liner used in stderr boot logs and diagnostics. */\n describe(): string\n}\n\n/** @experimental */\nexport interface SiblingSandboxExecutorOptions {\n client: LoopSandboxClient\n}\n\n/**\n * Wrap a raw sandbox SDK client so the kernel emits\n * `loop.iteration.dispatch` events with `{ placement: 'sibling', sandboxId }`.\n *\n * The returned client `.create()` delegates to the underlying client; the\n * only added behavior is a `describePlacement` tag the kernel reads.\n *\n * @experimental\n */\nexport function createSiblingSandboxExecutor(\n options: SiblingSandboxExecutorOptions,\n): DelegationExecutor {\n const underlying = options.client\n const client: LoopSandboxClient = {\n create(opts?: CreateSandboxOptions): Promise<SandboxInstance> {\n return underlying.create(opts)\n },\n describePlacement(box: SandboxInstance): LoopSandboxPlacement {\n return { kind: 'sibling', sandboxId: readId(box) }\n },\n }\n return {\n client,\n describe(): string {\n return 'sibling-sandbox (each delegation = fresh sandbox via client.create)'\n },\n }\n}\n\n/**\n * Minimal `SandboxFleet` surface the fleet executor calls. Declared\n * structurally so tests can pass an in-memory stub without instantiating the\n * sandbox SDK.\n *\n * @experimental\n */\nexport interface FleetHandle {\n readonly fleetId: string\n /** Machine ids in dispatch-eligible order. The executor round-robins. */\n readonly ids: ReadonlyArray<string>\n /** Resolve a machine id to its `SandboxInstance` — that machine is mounted\n * on the fleet's shared workspace, so any diff the worker writes lands on\n * every other fleet machine's filesystem too. */\n sandbox(machineId: string): Promise<SandboxInstance>\n}\n\n/** @experimental */\nexport interface FleetWorkspaceExecutorOptions {\n fleet: FleetHandle\n /**\n * Override the machine-selection policy. Default = round-robin across\n * `fleet.ids`, skipping the optional `excludeMachineIds` set (typically the\n * coordinator machine the MCP server is running on).\n */\n selectMachine?: (call: { callIndex: number; ids: ReadonlyArray<string> }) => string\n /**\n * Machine ids to skip during default round-robin. Set to the caller's own\n * machineId so workers don't compete with the orchestrator on the same VM.\n */\n excludeMachineIds?: ReadonlyArray<string>\n}\n\n/**\n * Build an executor that resolves each delegated iteration to an existing\n * machine in `fleet`. The fleet's shared-workspace policy means the worker\n * machine sees the caller's filesystem — diffs land in-place with no\n * cross-sandbox copy step.\n *\n * @experimental\n */\nexport function createFleetWorkspaceExecutor(\n options: FleetWorkspaceExecutorOptions,\n): DelegationExecutor {\n const fleet = options.fleet\n const exclude = new Set(options.excludeMachineIds ?? [])\n let callIndex = 0\n // machineId-by-sandboxId, populated as we resolve machines so\n // `describePlacement` can recover the assignment from the SandboxInstance\n // the kernel hands back.\n const placementBySandboxId = new Map<string, { machineId: string }>()\n\n const client: LoopSandboxClient = {\n async create(): Promise<SandboxInstance> {\n const ids = fleet.ids.filter((id) => !exclude.has(id))\n if (ids.length === 0) {\n throw new Error(\n `agent-runtime: fleet ${fleet.fleetId} has no eligible worker machines (ids=[${fleet.ids.join(',')}], excluded=[${[...exclude].join(',')}])`,\n )\n }\n const selector = options.selectMachine\n const machineId = selector ? selector({ callIndex, ids }) : ids[callIndex % ids.length]\n callIndex += 1\n if (typeof machineId !== 'string' || machineId.length === 0) {\n throw new Error('agent-runtime: fleet executor selectMachine returned an empty machine id')\n }\n const box = await fleet.sandbox(machineId)\n const sandboxId = readId(box)\n if (sandboxId) placementBySandboxId.set(sandboxId, { machineId })\n return box\n },\n describePlacement(box: SandboxInstance): LoopSandboxPlacement {\n const sandboxId = readId(box)\n const recorded = sandboxId ? placementBySandboxId.get(sandboxId) : undefined\n return {\n kind: 'fleet',\n sandboxId,\n fleetId: fleet.fleetId,\n machineId: recorded?.machineId,\n }\n },\n }\n\n return {\n client,\n describe(): string {\n const excluded = exclude.size > 0 ? ` (excluded=[${[...exclude].join(',')}])` : ''\n return `fleet-workspace (fleetId=${fleet.fleetId}, machines=[${fleet.ids.join(',')}]${excluded})`\n },\n }\n}\n\nfunction readId(box: SandboxInstance): string | undefined {\n const raw = (box as unknown as { id?: unknown }).id\n return typeof raw === 'string' && raw.length > 0 ? raw : undefined\n}\n","/**\n * @experimental\n *\n * Delegate factories — the layer between MCP tool handlers and the\n * underlying `runLoop` runners.\n *\n * The MCP server is profile-agnostic: it owns the task queue + feedback\n * store + transport. Each `*Delegate` is the closure that the queue\n * invokes when a task runs. Consumers can override either delegate to\n * inject custom drivers, mocks, fleet-aware dispatchers, etc.\n *\n * The default coder delegate is wired here because we own\n * `coderProfile` / `multiHarnessCoderFanout`. The default researcher\n * delegate is **not** wired in this file — `agent-knowledge` cannot be\n * imported from `agent-runtime` without inducing a cycle. Consumers\n * pass `researcherDelegate` explicitly when constructing the server.\n */\n\nimport type { Iteration, LoopSandboxClient, LoopTraceEmitter } from '../loops'\nimport { runLoop } from '../loops'\nimport { type CoderOutput, coderProfile, multiHarnessCoderFanout } from '../profiles/coder'\nimport { createSiblingSandboxExecutor, type DelegationExecutor } from './executor'\nimport type {\n CoderTask,\n DelegateCodeArgs,\n DelegateResearchArgs,\n DelegationProgress,\n ResearchOutputShape,\n} from './types'\n\n/** @experimental */\nexport interface DelegateRunCtx {\n signal: AbortSignal\n report(progress: DelegationProgress): void\n}\n\n/** @experimental */\nexport type CoderDelegate = (\n args: DelegateCodeArgs,\n ctx: DelegateRunCtx,\n) => Promise<import('../profiles/coder').CoderOutput>\n\n/** @experimental */\nexport type ResearcherDelegate = (\n args: DelegateResearchArgs,\n ctx: DelegateRunCtx,\n) => Promise<ResearchOutputShape>\n\n/** @experimental Structured review verdict over a coder candidate. */\nexport interface CoderReview {\n /** Gate: only approved candidates are eligible to win. */\n approved: boolean\n /** Reviewer's recommendation — surfaced in traces. */\n recommendation: 'ship' | 'approve-with-nits' | 'changes-requested' | 'reject'\n /** Readiness 0..1, used by the `highest-readiness` winner-selection strategy. */\n readiness: number\n notes?: string\n}\n\n/**\n * @experimental\n *\n * Optional adversarial reviewer over a coder candidate that already passed\n * mechanical validation (tests/typecheck/forbidden/diff/no-op/secrets). Folded\n * from the ai-trading-blueprint delegation MCP: a candidate is only eligible to\n * win if the reviewer approves it. The reviewer is the consumer's seam — an LLM\n * judge, a `pnpm review` command, anything returning a `CoderReview`.\n */\nexport type CoderReviewer = (\n output: import('../profiles/coder').CoderOutput,\n task: CoderTask,\n ctx: { signal: AbortSignal },\n) => Promise<CoderReview> | CoderReview\n\n/**\n * @experimental Winner-selection strategy among validated (+ reviewed)\n * candidates. `highest-readiness` requires a `reviewer`. Default `highest-score`\n * (the kernel's behavior — preserves backward compatibility).\n */\nexport type CoderWinnerSelection =\n | 'highest-score'\n | 'smallest-diff'\n | 'highest-readiness'\n | 'first-approved'\n\n/** @experimental */\nexport interface CreateDefaultCoderDelegateOptions {\n /**\n * Execution placement. Pass a {@link DelegationExecutor} (sibling or fleet)\n * to control where worker iterations land. `sandboxClient` is a\n * convenience shorthand that wraps the client in a sibling executor — pass\n * one or the other, not both.\n */\n executor?: DelegationExecutor\n /**\n * Convenience shorthand for sibling placement. Equivalent to\n * `executor: createSiblingSandboxExecutor({ client: sandboxClient })`.\n */\n sandboxClient?: LoopSandboxClient\n /** Default `['claude-code', 'codex', 'opencode/zai-coding-plan/glm-5.1']` when variants > 1. */\n fanoutHarnesses?: string[]\n /** Hard cap on the kernel's per-batch concurrency. Default 4. */\n maxConcurrency?: number\n /**\n * Optional adversarial reviewer. When set, a candidate must pass mechanical\n * validation AND `reviewer.approved` to be eligible to win — empty/secret/\n * test-failing patches are already gone; this catches the \"compiles + passes\n * but wrong/unsafe\" class the deterministic validator can't see.\n */\n reviewer?: CoderReviewer\n /** Winner-selection strategy among eligible candidates. Default `highest-score`. */\n winnerSelection?: CoderWinnerSelection\n /**\n * Loop trace emitter forwarded into every delegated `runLoop`. Wire\n * `createPropagatingTraceEmitter(readTraceContextFromEnv())` here (the bin\n * does) so delegated build-loops export their topology spans to the OTLP /\n * Tangle Intelligence sink when `OTEL_EXPORTER_OTLP_ENDPOINT` is set — and\n * are a cheap no-op when it isn't. Configurable by construction.\n */\n traceEmitter?: LoopTraceEmitter\n}\n\n/**\n * Build a coder delegate that drives `runLoop` against the project's\n * sandbox client + coder profile. When `args.variants > 1` it switches\n * to the multi-harness fanout topology.\n *\n * @experimental\n */\nexport function createDefaultCoderDelegate(\n options: CreateDefaultCoderDelegateOptions,\n): CoderDelegate {\n const executor = resolveExecutor(options)\n const sandboxClient = executor.client\n const fanoutHarnesses = options.fanoutHarnesses\n const maxConcurrency = options.maxConcurrency ?? 4\n const traceEmitter = options.traceEmitter\n return async (args, ctx) => {\n const task: CoderTask = {\n goal: buildCoderGoal(args),\n repoRoot: args.repoRoot,\n testCmd: args.config?.testCmd,\n typecheckCmd: args.config?.typecheckCmd,\n forbiddenPaths: args.config?.forbiddenPaths,\n maxDiffLines: args.config?.maxDiffLines,\n }\n const variants = Math.max(1, Math.trunc(args.variants ?? 1))\n ctx.report({ iteration: 0, phase: 'starting' })\n if (variants <= 1) {\n const { agentRunSpec, output, validator } = coderProfile({ task })\n const result = await runLoop({\n driver: singleShotDriver,\n agentRun: agentRunSpec,\n output,\n validator,\n task,\n ctx: { sandboxClient, signal: ctx.signal, ...(traceEmitter ? { traceEmitter } : {}) },\n maxIterations: 1,\n maxConcurrency,\n })\n const chosen = await pickCoderWinner({\n iterations: result.iterations,\n reviewer: options.reviewer,\n selection: options.winnerSelection ?? 'highest-score',\n task,\n signal: ctx.signal,\n })\n if (!chosen) throw new Error(noWinnerMessage(options.reviewer))\n ctx.report({ iteration: 1, phase: 'completed' })\n return chosen\n }\n const fanout = multiHarnessCoderFanout(\n fanoutHarnesses && fanoutHarnesses.length > 0\n ? { harnesses: fanoutHarnesses.slice(0, variants) }\n : { harnesses: undefined },\n )\n const agentRuns = fanout.agentRuns.slice(0, variants)\n const result = await runLoop({\n driver: fanout.driver,\n agentRuns,\n output: fanout.output,\n validator: fanout.validator,\n task,\n ctx: { sandboxClient, signal: ctx.signal, ...(traceEmitter ? { traceEmitter } : {}) },\n maxIterations: variants,\n maxConcurrency: Math.min(maxConcurrency, variants),\n })\n const chosen = await pickCoderWinner({\n iterations: result.iterations,\n reviewer: options.reviewer,\n selection: options.winnerSelection ?? 'highest-score',\n task,\n signal: ctx.signal,\n })\n if (!chosen) throw new Error(noWinnerMessage(options.reviewer))\n ctx.report({ iteration: agentRuns.length, phase: 'completed' })\n return chosen\n }\n}\n\ninterface PickCoderWinnerArgs {\n iterations: ReadonlyArray<Iteration<CoderTask, CoderOutput>>\n reviewer: CoderReviewer | undefined\n selection: CoderWinnerSelection\n task: CoderTask\n signal: AbortSignal\n}\n\ninterface CoderCandidate {\n index: number\n output: CoderOutput\n score: number\n readiness: number\n}\n\n/**\n * Pick the winning coder candidate from a finished loop's iterations:\n * 1. keep only mechanically-VALID candidates (the validator already gated\n * tests/typecheck/forbidden/diff/no-op/secrets),\n * 2. if a `reviewer` is wired, keep only those it APPROVES,\n * 3. select among survivors by the chosen strategy.\n * Returns `undefined` when nothing survives — the delegate fails loud.\n */\nasync function pickCoderWinner(args: PickCoderWinnerArgs): Promise<CoderOutput | undefined> {\n const valid: CoderCandidate[] = []\n for (const iter of args.iterations) {\n if (iter.output === undefined || iter.error || iter.verdict?.valid !== true) continue\n valid.push({\n index: iter.index,\n output: iter.output,\n score: iter.verdict.score ?? 0,\n readiness: iter.verdict.score ?? 0,\n })\n }\n if (valid.length === 0) return undefined\n\n let eligible = valid\n if (args.reviewer) {\n eligible = []\n for (const c of valid) {\n const review = await args.reviewer(c.output, args.task, { signal: args.signal })\n if (review.approved) eligible.push({ ...c, readiness: review.readiness })\n }\n if (eligible.length === 0) return undefined\n }\n\n return selectCoderCandidate(eligible, args.selection).output\n}\n\n/** Apply the winner-selection strategy; ties broken by earliest iteration. */\nfunction selectCoderCandidate(\n candidates: CoderCandidate[],\n selection: CoderWinnerSelection,\n): CoderCandidate {\n const diffLines = (c: CoderCandidate) =>\n c.output.diffStats.insertions + c.output.diffStats.deletions\n const sorted = [...candidates].sort((a, b) => {\n switch (selection) {\n case 'smallest-diff':\n return diffLines(a) - diffLines(b) || a.index - b.index\n case 'highest-readiness':\n return b.readiness - a.readiness || a.index - b.index\n case 'first-approved':\n return a.index - b.index\n default:\n return b.score - a.score || a.index - b.index\n }\n })\n return sorted[0]!\n}\n\nfunction noWinnerMessage(reviewer: CoderReviewer | undefined): string {\n return reviewer\n ? 'coder delegate: no candidate passed validation + review'\n : 'coder delegate: no candidate passed validation'\n}\n\nfunction buildCoderGoal(args: DelegateCodeArgs): string {\n if (!args.contextHint) return args.goal\n return [args.goal, '', '## Context', args.contextHint].join('\\n')\n}\n\nfunction resolveExecutor(options: CreateDefaultCoderDelegateOptions): DelegationExecutor {\n if (options.executor && options.sandboxClient) {\n throw new Error('createDefaultCoderDelegate: pass exactly one of `executor` or `sandboxClient`')\n }\n if (options.executor) return options.executor\n if (options.sandboxClient) {\n return createSiblingSandboxExecutor({ client: options.sandboxClient })\n }\n throw new Error('createDefaultCoderDelegate: `executor` or `sandboxClient` is required')\n}\n\n/**\n * Single-shot driver — plan one task on iteration 0, stop after one\n * iteration. Used by the coder delegate when `variants <= 1`. Keeps the\n * runLoop kernel-level accounting (timing, cost, trace emission) while\n * skipping fanout/refine topology overhead.\n */\nconst singleShotDriver = {\n name: 'mcp-single-shot',\n async plan<Task>(task: Task, history: ReadonlyArray<unknown>): Promise<Task[]> {\n return history.length === 0 ? [task] : []\n },\n decide(history: ReadonlyArray<unknown>): 'pick-winner' | 'fail' {\n return history.length > 0 ? 'pick-winner' : 'fail'\n },\n}\n"],"mappings":"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","names":["result","chosen"]}
|
|
@@ -838,6 +838,337 @@ function createDelegationStatusHandler(options) {
|
|
|
838
838
|
};
|
|
839
839
|
}
|
|
840
840
|
|
|
841
|
+
// src/otel-export.ts
|
|
842
|
+
var SCOPE = { name: "@tangle-network/agent-runtime", version: "0.33.0" };
|
|
843
|
+
var GEN_AI = {
|
|
844
|
+
operation: "gen_ai.operation.name",
|
|
845
|
+
agentName: "gen_ai.agent.name",
|
|
846
|
+
conversationId: "gen_ai.conversation.id",
|
|
847
|
+
inputTokens: "gen_ai.usage.input_tokens",
|
|
848
|
+
outputTokens: "gen_ai.usage.output_tokens"
|
|
849
|
+
};
|
|
850
|
+
function createOtelExporter(config) {
|
|
851
|
+
const resolvedEndpoint = config?.endpoint ?? (typeof process !== "undefined" ? process.env.OTEL_EXPORTER_OTLP_ENDPOINT : void 0);
|
|
852
|
+
if (!resolvedEndpoint) return void 0;
|
|
853
|
+
const endpoint = resolvedEndpoint;
|
|
854
|
+
const headers = config?.headers ?? parseHeadersFromEnv();
|
|
855
|
+
const batchSize = config?.batchSize ?? 64;
|
|
856
|
+
const flushIntervalMs = config?.flushIntervalMs ?? 5e3;
|
|
857
|
+
const serviceName = config?.serviceName ?? "agent-runtime";
|
|
858
|
+
const resourceAttrs = config?.resourceAttributes ?? {};
|
|
859
|
+
const pending = [];
|
|
860
|
+
let timer;
|
|
861
|
+
let stopped = false;
|
|
862
|
+
const exporter = {
|
|
863
|
+
exportSpan(span) {
|
|
864
|
+
if (stopped) return;
|
|
865
|
+
pending.push(span);
|
|
866
|
+
if (pending.length >= batchSize) {
|
|
867
|
+
void doFlush();
|
|
868
|
+
}
|
|
869
|
+
},
|
|
870
|
+
async flush() {
|
|
871
|
+
await doFlush();
|
|
872
|
+
},
|
|
873
|
+
async shutdown() {
|
|
874
|
+
stopped = true;
|
|
875
|
+
if (timer !== void 0) {
|
|
876
|
+
clearInterval(timer);
|
|
877
|
+
timer = void 0;
|
|
878
|
+
}
|
|
879
|
+
await doFlush();
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
timer = setInterval(() => {
|
|
883
|
+
if (pending.length > 0) void doFlush();
|
|
884
|
+
}, flushIntervalMs);
|
|
885
|
+
if (typeof timer === "object" && "unref" in timer) {
|
|
886
|
+
;
|
|
887
|
+
timer.unref();
|
|
888
|
+
}
|
|
889
|
+
async function doFlush() {
|
|
890
|
+
if (pending.length === 0) return;
|
|
891
|
+
const batch = pending.splice(0);
|
|
892
|
+
const body = {
|
|
893
|
+
resourceSpans: [
|
|
894
|
+
{
|
|
895
|
+
resource: {
|
|
896
|
+
attributes: toAttributes({
|
|
897
|
+
"service.name": serviceName,
|
|
898
|
+
...resourceAttrs
|
|
899
|
+
})
|
|
900
|
+
},
|
|
901
|
+
scopeSpans: [{ scope: SCOPE, spans: batch }]
|
|
902
|
+
}
|
|
903
|
+
]
|
|
904
|
+
};
|
|
905
|
+
const url = `${endpoint.replace(/\/+$/, "")}/v1/traces`;
|
|
906
|
+
try {
|
|
907
|
+
await fetch(url, {
|
|
908
|
+
method: "POST",
|
|
909
|
+
headers: { "content-type": "application/json", ...headers },
|
|
910
|
+
body: JSON.stringify(body)
|
|
911
|
+
});
|
|
912
|
+
} catch {
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
return exporter;
|
|
916
|
+
}
|
|
917
|
+
function loopEventToOtelSpan(event, traceId, parentSpanId) {
|
|
918
|
+
const spanId = generateSpanId();
|
|
919
|
+
const attrs = {
|
|
920
|
+
"loop.event_kind": event.kind,
|
|
921
|
+
"loop.run_id": event.runId
|
|
922
|
+
};
|
|
923
|
+
for (const [k, v] of Object.entries(event.payload)) {
|
|
924
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
925
|
+
attrs[`loop.${k}`] = v;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
const ts = msToNs(event.timestamp);
|
|
929
|
+
return {
|
|
930
|
+
traceId: padTraceId(traceId),
|
|
931
|
+
spanId,
|
|
932
|
+
parentSpanId: parentSpanId ? padSpanId(parentSpanId) : void 0,
|
|
933
|
+
name: event.kind,
|
|
934
|
+
kind: 1,
|
|
935
|
+
startTimeUnixNano: ts,
|
|
936
|
+
endTimeUnixNano: ts,
|
|
937
|
+
attributes: toAttributes(attrs),
|
|
938
|
+
status: { code: 1 }
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
function buildLoopOtelSpans(events, traceId, rootParentSpanId) {
|
|
942
|
+
if (events.length === 0) return [];
|
|
943
|
+
const tid = padTraceId(traceId);
|
|
944
|
+
const out = [];
|
|
945
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
946
|
+
const str = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
|
|
947
|
+
const rec = (v) => v && typeof v === "object" ? v : {};
|
|
948
|
+
const started = events.find((e) => e.kind === "loop.started");
|
|
949
|
+
const ended = events.find((e) => e.kind === "loop.ended");
|
|
950
|
+
const runId = events[0]?.runId ?? "";
|
|
951
|
+
const rootStart = started?.timestamp ?? events[0].timestamp;
|
|
952
|
+
const rootEnd = ended?.timestamp ?? events[events.length - 1].timestamp;
|
|
953
|
+
const rootId = generateSpanId();
|
|
954
|
+
const make = (spanId, parentSpanId, name, startMs, endMs, attrs, statusCode = 1) => ({
|
|
955
|
+
traceId: tid,
|
|
956
|
+
spanId,
|
|
957
|
+
parentSpanId: parentSpanId ? padSpanId(parentSpanId) : void 0,
|
|
958
|
+
name,
|
|
959
|
+
kind: 1,
|
|
960
|
+
startTimeUnixNano: msToNs(startMs),
|
|
961
|
+
endTimeUnixNano: msToNs(endMs),
|
|
962
|
+
attributes: toAttributes(attrs),
|
|
963
|
+
status: { code: statusCode }
|
|
964
|
+
});
|
|
965
|
+
const sp = rec(started?.payload);
|
|
966
|
+
const rootAttrs = {
|
|
967
|
+
[GEN_AI.operation]: "invoke_workflow",
|
|
968
|
+
[GEN_AI.conversationId]: runId,
|
|
969
|
+
"tangle.loop.driver": str(sp.driver) ?? "driver"
|
|
970
|
+
};
|
|
971
|
+
if (Array.isArray(sp.agentRunNames) && sp.agentRunNames.length > 0) {
|
|
972
|
+
rootAttrs["tangle.loop.agents"] = sp.agentRunNames.map(String).join(",");
|
|
973
|
+
}
|
|
974
|
+
if (ended) {
|
|
975
|
+
const ep = rec(ended.payload);
|
|
976
|
+
const win = num(ep.winnerIterationIndex);
|
|
977
|
+
if (win !== void 0) rootAttrs["tangle.loop.winner.iteration_index"] = win;
|
|
978
|
+
const cost = num(ep.totalCostUsd);
|
|
979
|
+
if (cost !== void 0) rootAttrs["tangle.cost.usd"] = cost;
|
|
980
|
+
const dur = num(ep.durationMs);
|
|
981
|
+
if (dur !== void 0) rootAttrs["tangle.loop.duration_ms"] = dur;
|
|
982
|
+
const iters = num(ep.iterations);
|
|
983
|
+
if (iters !== void 0) rootAttrs["tangle.loop.iterations"] = iters;
|
|
984
|
+
}
|
|
985
|
+
out.push(make(rootId, rootParentSpanId, "loop", rootStart, rootEnd, rootAttrs));
|
|
986
|
+
const iterStartTs = /* @__PURE__ */ new Map();
|
|
987
|
+
const placementByIdx = /* @__PURE__ */ new Map();
|
|
988
|
+
let currentRoundId;
|
|
989
|
+
let pendingRound;
|
|
990
|
+
const flushRound = (endMs) => {
|
|
991
|
+
if (!pendingRound) return;
|
|
992
|
+
out.push(
|
|
993
|
+
make(pendingRound.id, rootId, "loop.round", pendingRound.start, endMs, pendingRound.attrs)
|
|
994
|
+
);
|
|
995
|
+
pendingRound = void 0;
|
|
996
|
+
};
|
|
997
|
+
for (const e of events) {
|
|
998
|
+
const p = rec(e.payload);
|
|
999
|
+
switch (e.kind) {
|
|
1000
|
+
case "loop.plan": {
|
|
1001
|
+
flushRound(e.timestamp);
|
|
1002
|
+
const id = generateSpanId();
|
|
1003
|
+
const roundIdx = num(p.roundIndex) ?? 0;
|
|
1004
|
+
const attrs = {
|
|
1005
|
+
[GEN_AI.operation]: "invoke_workflow",
|
|
1006
|
+
"tangle.loop.round.index": roundIdx,
|
|
1007
|
+
"tangle.loop.move.kind": str(p.moveKind) ?? "unknown",
|
|
1008
|
+
"tangle.loop.move.round": roundIdx,
|
|
1009
|
+
"tangle.loop.move.width": num(p.plannedCount) ?? 0
|
|
1010
|
+
};
|
|
1011
|
+
const r = str(p.rationale);
|
|
1012
|
+
if (r) attrs["tangle.loop.move.rationale"] = r;
|
|
1013
|
+
const parent = num(p.parentIndex);
|
|
1014
|
+
if (parent !== void 0) attrs["tangle.loop.move.parent_index"] = parent;
|
|
1015
|
+
if (Array.isArray(p.childIndices) && p.childIndices.length > 0) {
|
|
1016
|
+
attrs["tangle.loop.move.child_indices"] = p.childIndices.map(String).join(",");
|
|
1017
|
+
}
|
|
1018
|
+
pendingRound = { id, start: e.timestamp, attrs };
|
|
1019
|
+
currentRoundId = id;
|
|
1020
|
+
break;
|
|
1021
|
+
}
|
|
1022
|
+
case "loop.iteration.started": {
|
|
1023
|
+
const idx = num(p.iterationIndex);
|
|
1024
|
+
if (idx !== void 0) iterStartTs.set(idx, e.timestamp);
|
|
1025
|
+
break;
|
|
1026
|
+
}
|
|
1027
|
+
case "loop.iteration.dispatch": {
|
|
1028
|
+
const idx = num(p.iterationIndex);
|
|
1029
|
+
if (idx === void 0) break;
|
|
1030
|
+
const place = {};
|
|
1031
|
+
const kind = str(p.placement);
|
|
1032
|
+
if (kind) place["tangle.loop.placement.kind"] = kind;
|
|
1033
|
+
const sid = str(p.sandboxId);
|
|
1034
|
+
if (sid) place["tangle.sandbox.id"] = sid;
|
|
1035
|
+
const fid = str(p.fleetId);
|
|
1036
|
+
if (fid) place["tangle.fleet.id"] = fid;
|
|
1037
|
+
const mid = str(p.machineId);
|
|
1038
|
+
if (mid) place["tangle.machine.id"] = mid;
|
|
1039
|
+
placementByIdx.set(idx, place);
|
|
1040
|
+
break;
|
|
1041
|
+
}
|
|
1042
|
+
case "loop.iteration.ended": {
|
|
1043
|
+
const idx = num(p.iterationIndex) ?? 0;
|
|
1044
|
+
const start = iterStartTs.get(idx) ?? e.timestamp;
|
|
1045
|
+
const err = str(p.error);
|
|
1046
|
+
const attrs = {
|
|
1047
|
+
[GEN_AI.operation]: "invoke_agent",
|
|
1048
|
+
"tangle.loop.iteration.index": idx
|
|
1049
|
+
};
|
|
1050
|
+
const agent = str(p.agentRunName);
|
|
1051
|
+
if (agent) attrs[GEN_AI.agentName] = agent;
|
|
1052
|
+
const tu = rec(p.tokenUsage);
|
|
1053
|
+
const inTok = num(tu.input);
|
|
1054
|
+
if (inTok !== void 0) attrs[GEN_AI.inputTokens] = inTok;
|
|
1055
|
+
const outTok = num(tu.output);
|
|
1056
|
+
if (outTok !== void 0) attrs[GEN_AI.outputTokens] = outTok;
|
|
1057
|
+
const cost = num(p.costUsd);
|
|
1058
|
+
if (cost !== void 0) attrs["tangle.cost.usd"] = cost;
|
|
1059
|
+
const verdict = rec(p.verdict);
|
|
1060
|
+
if (typeof verdict.valid === "boolean") attrs["tangle.loop.verdict.valid"] = verdict.valid;
|
|
1061
|
+
const score = num(verdict.score);
|
|
1062
|
+
if (score !== void 0) attrs["tangle.loop.verdict.score"] = score;
|
|
1063
|
+
if (err) attrs["tangle.loop.error"] = err;
|
|
1064
|
+
const gid = num(p.groupId);
|
|
1065
|
+
if (gid !== void 0) attrs["tangle.loop.iteration.group_id"] = gid;
|
|
1066
|
+
const par = num(p.parentIndex);
|
|
1067
|
+
if (par !== void 0) attrs["tangle.loop.iteration.parent_index"] = par;
|
|
1068
|
+
const dur = num(p.durationMs);
|
|
1069
|
+
if (dur !== void 0) attrs["tangle.loop.iteration.duration_ms"] = dur;
|
|
1070
|
+
const preview = str(p.outputPreview);
|
|
1071
|
+
if (preview) attrs["tangle.loop.iteration.output_preview"] = preview;
|
|
1072
|
+
Object.assign(attrs, placementByIdx.get(idx) ?? {});
|
|
1073
|
+
out.push(
|
|
1074
|
+
make(
|
|
1075
|
+
generateSpanId(),
|
|
1076
|
+
currentRoundId ?? rootId,
|
|
1077
|
+
"loop.iteration",
|
|
1078
|
+
start,
|
|
1079
|
+
e.timestamp,
|
|
1080
|
+
attrs,
|
|
1081
|
+
err ? 2 : 1
|
|
1082
|
+
)
|
|
1083
|
+
);
|
|
1084
|
+
break;
|
|
1085
|
+
}
|
|
1086
|
+
case "loop.decision": {
|
|
1087
|
+
if (pendingRound) {
|
|
1088
|
+
const dec = str(p.decision);
|
|
1089
|
+
if (dec) pendingRound.attrs["tangle.loop.decision"] = dec;
|
|
1090
|
+
flushRound(e.timestamp);
|
|
1091
|
+
}
|
|
1092
|
+
currentRoundId = void 0;
|
|
1093
|
+
break;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
flushRound(rootEnd);
|
|
1098
|
+
return out;
|
|
1099
|
+
}
|
|
1100
|
+
function parseHeadersFromEnv() {
|
|
1101
|
+
if (typeof process === "undefined") return {};
|
|
1102
|
+
const raw = process.env.OTEL_EXPORTER_OTLP_HEADERS;
|
|
1103
|
+
if (!raw) return {};
|
|
1104
|
+
const out = {};
|
|
1105
|
+
for (const pair of raw.split(",")) {
|
|
1106
|
+
const eq = pair.indexOf("=");
|
|
1107
|
+
if (eq < 0) continue;
|
|
1108
|
+
const key = pair.slice(0, eq).trim();
|
|
1109
|
+
const value = pair.slice(eq + 1).trim();
|
|
1110
|
+
if (key) out[key] = value;
|
|
1111
|
+
}
|
|
1112
|
+
return out;
|
|
1113
|
+
}
|
|
1114
|
+
function toAttributes(record) {
|
|
1115
|
+
return Object.entries(record).map(([key, value]) => ({
|
|
1116
|
+
key,
|
|
1117
|
+
value: typeof value === "number" ? Number.isInteger(value) ? { intValue: value.toString() } : { doubleValue: value } : typeof value === "boolean" ? { boolValue: value } : { stringValue: value }
|
|
1118
|
+
}));
|
|
1119
|
+
}
|
|
1120
|
+
function msToNs(ms) {
|
|
1121
|
+
return (BigInt(Math.floor(ms)) * 1000000n).toString();
|
|
1122
|
+
}
|
|
1123
|
+
function padSpanId(id) {
|
|
1124
|
+
const cleaned = id.replace(/-/g, "");
|
|
1125
|
+
return cleaned.slice(0, 16).padEnd(16, "0");
|
|
1126
|
+
}
|
|
1127
|
+
function padTraceId(id) {
|
|
1128
|
+
const cleaned = id.replace(/-/g, "");
|
|
1129
|
+
return cleaned.slice(0, 32).padEnd(32, "0");
|
|
1130
|
+
}
|
|
1131
|
+
function generateSpanId() {
|
|
1132
|
+
const bytes = new Uint8Array(8);
|
|
1133
|
+
if (typeof globalThis.crypto?.getRandomValues === "function") {
|
|
1134
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
1135
|
+
} else {
|
|
1136
|
+
for (let i = 0; i < 8; i++) bytes[i] = Math.floor(Math.random() * 256);
|
|
1137
|
+
}
|
|
1138
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1139
|
+
}
|
|
1140
|
+
var INTELLIGENCE_WIRE_VERSION = "2026-05-26.v1";
|
|
1141
|
+
var DEFAULT_INTELLIGENCE_BASE = "https://intelligence.tangle.tools";
|
|
1142
|
+
async function exportEvalRuns(events, config) {
|
|
1143
|
+
if (events.length === 0) return { ok: true, status: 0, accepted: 0, rejected: [] };
|
|
1144
|
+
const apiKey = config?.apiKey ?? (typeof process !== "undefined" ? process.env.TANGLE_API_KEY : void 0);
|
|
1145
|
+
if (!apiKey)
|
|
1146
|
+
throw new Error("exportEvalRuns: apiKey required (pass config.apiKey or set TANGLE_API_KEY)");
|
|
1147
|
+
const base = config?.base ?? (typeof process !== "undefined" ? process.env.INTELLIGENCE_BASE : void 0) ?? DEFAULT_INTELLIGENCE_BASE;
|
|
1148
|
+
const url = `${base.replace(/\/+$/, "")}/v1/ingest/eval-runs`;
|
|
1149
|
+
const res = await fetch(url, {
|
|
1150
|
+
method: "POST",
|
|
1151
|
+
headers: {
|
|
1152
|
+
"content-type": "application/json",
|
|
1153
|
+
authorization: `Bearer ${apiKey}`,
|
|
1154
|
+
"X-Tangle-Wire-Version": INTELLIGENCE_WIRE_VERSION,
|
|
1155
|
+
...config?.idempotencyKey ? { "Idempotency-Key": config.idempotencyKey } : {}
|
|
1156
|
+
},
|
|
1157
|
+
body: JSON.stringify({ wireVersion: INTELLIGENCE_WIRE_VERSION, events })
|
|
1158
|
+
});
|
|
1159
|
+
let parsed = {};
|
|
1160
|
+
try {
|
|
1161
|
+
parsed = await res.json();
|
|
1162
|
+
} catch {
|
|
1163
|
+
}
|
|
1164
|
+
return {
|
|
1165
|
+
ok: res.ok,
|
|
1166
|
+
status: res.status,
|
|
1167
|
+
accepted: parsed.accepted ?? (res.ok ? events.length : 0),
|
|
1168
|
+
rejected: parsed.rejected ?? []
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
|
|
841
1172
|
export {
|
|
842
1173
|
DelegationTaskQueue,
|
|
843
1174
|
hashIdempotencyInput,
|
|
@@ -867,6 +1198,11 @@ export {
|
|
|
867
1198
|
DELEGATION_STATUS_DESCRIPTION,
|
|
868
1199
|
DELEGATION_STATUS_INPUT_SCHEMA,
|
|
869
1200
|
validateDelegationStatusArgs,
|
|
870
|
-
createDelegationStatusHandler
|
|
1201
|
+
createDelegationStatusHandler,
|
|
1202
|
+
createOtelExporter,
|
|
1203
|
+
loopEventToOtelSpan,
|
|
1204
|
+
buildLoopOtelSpans,
|
|
1205
|
+
INTELLIGENCE_WIRE_VERSION,
|
|
1206
|
+
exportEvalRuns
|
|
871
1207
|
};
|
|
872
|
-
//# sourceMappingURL=chunk-
|
|
1208
|
+
//# sourceMappingURL=chunk-HVYOHJHK.js.map
|