@tangle-network/agent-runtime 0.23.0 → 0.25.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/README.md +85 -498
- package/dist/agent.d.ts +5 -206
- package/dist/chunk-GLR25NG7.js +92 -0
- package/dist/chunk-GLR25NG7.js.map +1 -0
- package/dist/{chunk-7HN72MF3.js → chunk-QZEDHTT2.js} +2 -2
- package/dist/chunk-QZEDHTT2.js.map +1 -0
- package/dist/{chunk-IQHYOJU3.js → chunk-ZJACJZF7.js} +289 -1
- package/dist/chunk-ZJACJZF7.js.map +1 -0
- package/dist/improvement-adapter-CaZxFxTd.d.ts +207 -0
- package/dist/improvement.d.ts +120 -0
- package/dist/improvement.js +161 -0
- package/dist/improvement.js.map +1 -0
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/local-harness-KrdFTY5R.d.ts +82 -0
- package/dist/mcp/bin.js +2 -1
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +190 -2
- package/dist/mcp/index.js +21 -13
- package/dist/mcp/index.js.map +1 -1
- package/package.json +17 -23
- package/dist/chunk-7HN72MF3.js.map +0 -1
- package/dist/chunk-IQHYOJU3.js.map +0 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ChildProcess } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @experimental
|
|
5
|
+
*
|
|
6
|
+
* Subprocess wrappers for the local coding-harness CLIs installed in the
|
|
7
|
+
* sandbox image (claude-code, codex, opencode). Used by the in-process
|
|
8
|
+
* delegation executor (`createInProcessExecutor`) so a `delegate_code` call
|
|
9
|
+
* spawns a real harness on a real git worktree instead of provisioning a
|
|
10
|
+
* sibling sandbox.
|
|
11
|
+
*
|
|
12
|
+
* All harness invocations:
|
|
13
|
+
* - run with `cwd` set to the worktree
|
|
14
|
+
* - inherit env from the parent (the MCP server inside the sandbox has
|
|
15
|
+
* the harness's auth already)
|
|
16
|
+
* - capture stdout/stderr
|
|
17
|
+
* - support cancellation via AbortSignal
|
|
18
|
+
* - enforce a wall-clock timeout
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** Local coding harness available inside the sandbox. */
|
|
22
|
+
type LocalHarness = 'claude' | 'codex' | 'opencode';
|
|
23
|
+
/** @experimental */
|
|
24
|
+
interface RunLocalHarnessOptions {
|
|
25
|
+
harness: LocalHarness;
|
|
26
|
+
/** Working directory for the subprocess (typically a worktree path). */
|
|
27
|
+
cwd: string;
|
|
28
|
+
/** Prompt forwarded as the harness CLI's task argument. */
|
|
29
|
+
taskPrompt: string;
|
|
30
|
+
/** Wall-clock kill deadline (ms). Default 5 min. Subprocess SIGTERMed on expiry. */
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
/** Caller cancellation. SIGTERM is sent on abort. */
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
/** Override env (defaults to inheriting from the parent). */
|
|
35
|
+
env?: NodeJS.ProcessEnv;
|
|
36
|
+
/**
|
|
37
|
+
* Test seam — inject a custom spawner so unit tests can mock the
|
|
38
|
+
* subprocess without touching the OS. Defaults to node's `child_process.spawn`.
|
|
39
|
+
*/
|
|
40
|
+
spawn?: (command: string, args: ReadonlyArray<string>, opts: {
|
|
41
|
+
cwd: string;
|
|
42
|
+
env: NodeJS.ProcessEnv;
|
|
43
|
+
stdio: 'pipe';
|
|
44
|
+
}) => ChildProcess;
|
|
45
|
+
}
|
|
46
|
+
/** @experimental */
|
|
47
|
+
interface LocalHarnessResult {
|
|
48
|
+
/** OS exit code. `null` when killed before exit. */
|
|
49
|
+
exitCode: number | null;
|
|
50
|
+
/** Concatenated stdout. */
|
|
51
|
+
stdout: string;
|
|
52
|
+
/** Concatenated stderr. */
|
|
53
|
+
stderr: string;
|
|
54
|
+
/** Set when the process exited via signal (timeout / abort). */
|
|
55
|
+
killedBySignal: NodeJS.Signals | null;
|
|
56
|
+
/** Wall-clock duration ms (spawn → exit). */
|
|
57
|
+
durationMs: number;
|
|
58
|
+
/** Set when timeoutMs elapsed before exit. */
|
|
59
|
+
timedOut: boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Spawn a local coding harness CLI as a subprocess + collect its output.
|
|
63
|
+
*
|
|
64
|
+
* NOT responsible for parsing the harness's output or extracting a diff —
|
|
65
|
+
* the in-process executor's `streamPrompt` orchestrates `git diff` against
|
|
66
|
+
* the worktree after this resolves. This function is intentionally narrow:
|
|
67
|
+
* spawn, wait, capture, return.
|
|
68
|
+
*
|
|
69
|
+
* Fails loud — throws when:
|
|
70
|
+
* - `cwd` doesn't exist (subprocess emits ENOENT; surfaced as Error)
|
|
71
|
+
* - the harness binary is not on PATH (ENOENT)
|
|
72
|
+
*
|
|
73
|
+
* Does NOT throw when:
|
|
74
|
+
* - the subprocess exits non-zero (`result.exitCode` carries the code)
|
|
75
|
+
* - the subprocess is aborted / timed out (`result.killedBySignal` /
|
|
76
|
+
* `result.timedOut` carries the reason)
|
|
77
|
+
*
|
|
78
|
+
* @experimental
|
|
79
|
+
*/
|
|
80
|
+
declare function runLocalHarness(options: RunLocalHarnessOptions): Promise<LocalHarnessResult>;
|
|
81
|
+
|
|
82
|
+
export { type LocalHarness as L, type RunLocalHarnessOptions as R, type LocalHarnessResult as a, runLocalHarness as r };
|
package/dist/mcp/bin.js
CHANGED
package/dist/mcp/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * @experimental\n *\n * `agent-runtime-mcp` — stdio MCP server entry point.\n *\n * Spins up a server with the default coder delegate (wired against the\n * real `@tangle-network/sandbox` client) and, when the optional\n * `@tangle-network/agent-knowledge` peer is installed, a researcher\n * delegate against `multiHarnessResearcherFanout`.\n *\n * Environment variables:\n * TANGLE_API_KEY required — passed to `new Sandbox({ apiKey })`\n * SANDBOX_BASE_URL optional — sandbox-SDK base URL override\n * TANGLE_FLEET_ID optional — when set, delegations dispatch\n * INTO this fleet's shared workspace instead\n * of creating sibling sandboxes. Set by the\n * parent sandbox when launching this MCP\n * server so worker diffs land on the caller's\n * filesystem with no cross-sandbox boundary.\n * TANGLE_FLEET_EXCLUDE_MACHINES optional — comma-separated machine ids to\n * skip during fleet-mode round-robin\n * (typically the coordinator machine this\n * MCP server is running on).\n * MCP_MAX_CONCURRENT_SANDBOXES default 4 — kernel maxConcurrency cap\n * MCP_CODER_FANOUT_HARNESSES comma-separated harness ids to use for variants > 1\n * MCP_DISABLE_CODER set to `1` to omit `delegate_code`\n * MCP_DISABLE_RESEARCHER set to `1` to omit `delegate_research` even when peer is present\n */\n\nimport type { LoopSandboxClient } from '../loops'\nimport { runLoop } from '../loops'\nimport { detectExecutor } from './bin-helpers'\nimport { createDefaultCoderDelegate, type ResearcherDelegate } from './delegates'\nimport type { DelegationExecutor } from './executor'\nimport { createMcpServer } from './server'\nimport type { ResearchOutputShape } from './types'\n\nasync function main(): Promise<void> {\n const fanoutHarnesses = parseHarnesses(process.env.MCP_CODER_FANOUT_HARNESSES)\n const maxConcurrency = parseConcurrency(process.env.MCP_MAX_CONCURRENT_SANDBOXES)\n const wantCoder = !process.env.MCP_DISABLE_CODER\n const wantResearcher = !process.env.MCP_DISABLE_RESEARCHER\n const fleetId = parseFleetId(process.env.TANGLE_FLEET_ID)\n\n // Skip the sandbox client load entirely when no profile delegate needs it —\n // the feedback + status + history tools are queue-bound and require no\n // sandbox. Useful for tooling that mounts the MCP server purely for\n // self-introspection.\n const needsSandbox = wantCoder || wantResearcher\n let sandboxClient: LoopSandboxClient | undefined\n let executor: DelegationExecutor | undefined\n if (needsSandbox) {\n const apiKey = process.env.TANGLE_API_KEY\n if (!apiKey && !process.env.AGENT_RUNTIME_MCP_ALLOW_NO_KEY) {\n process.stderr.write(\n 'agent-runtime-mcp: TANGLE_API_KEY is required. Set AGENT_RUNTIME_MCP_ALLOW_NO_KEY=1 to run without it for diagnostics, or MCP_DISABLE_CODER=1 MCP_DISABLE_RESEARCHER=1 to run the queue-only subset.\\n',\n )\n process.exit(2)\n }\n // Fleet mode against a diagnostic stub is meaningless — the stub can't\n // resolve a real fleet handle. Refuse rather than silently degrading,\n // otherwise a fleet-mounted MCP would behave differently than configured.\n if (fleetId && !apiKey) {\n process.stderr.write(\n 'agent-runtime-mcp: TANGLE_FLEET_ID was set but TANGLE_API_KEY is missing; cannot resolve fleet handle. Provide an api key or unset TANGLE_FLEET_ID.\\n',\n )\n process.exit(2)\n }\n sandboxClient = await loadSandboxClient(apiKey)\n executor = await detectExecutor({ sandboxClient })\n if (fleetId) {\n process.stderr.write(`agent-runtime-mcp: fleet-aware delegation: fleetId=${fleetId}\\n`)\n }\n process.stderr.write(`agent-runtime-mcp: delegation placement → ${executor.describe()}\\n`)\n }\n\n const coderDelegate =\n wantCoder && executor\n ? createDefaultCoderDelegate({\n executor,\n fanoutHarnesses,\n maxConcurrency,\n })\n : undefined\n\n const researcherDelegate =\n wantResearcher && executor\n ? await loadResearcherDelegate(executor.client, maxConcurrency)\n : undefined\n\n const server = createMcpServer({ coderDelegate, researcherDelegate })\n\n process.on('SIGINT', () => {\n server.stop()\n process.exit(0)\n })\n process.on('SIGTERM', () => {\n server.stop()\n process.exit(0)\n })\n\n await server.serve()\n}\n\nasync function loadSandboxClient(apiKey: string | undefined): Promise<LoopSandboxClient> {\n // Diagnostic mode: AGENT_RUNTIME_MCP_ALLOW_NO_KEY=1 enables tools/list + the\n // queue-bound tools (status / history / feedback) without sandbox creds.\n // Coder + researcher delegations require a real client; the stub fails loud\n // at create() so the agent observes the cause instead of silent success.\n if (!apiKey) {\n return {\n async create() {\n throw new Error(\n 'agent-runtime-mcp: TANGLE_API_KEY is unset; coder/researcher delegations are disabled in diagnostic mode. Set TANGLE_API_KEY or use MCP_DISABLE_CODER=1 MCP_DISABLE_RESEARCHER=1 to remove the unsupported tools from the tool list.',\n )\n },\n } satisfies LoopSandboxClient\n }\n // Dynamic import keeps the bin importable in environments that haven't\n // installed `@tangle-network/sandbox` yet (the runtime package lists it\n // as a peer dep, not a hard dep).\n const mod = await import('@tangle-network/sandbox').catch((err) => {\n process.stderr.write(\n `agent-runtime-mcp: failed to load @tangle-network/sandbox (${err.message}); install the peer dependency\\n`,\n )\n process.exit(2)\n })\n const SandboxCtor = (mod as { Sandbox?: new (config: unknown) => LoopSandboxClient }).Sandbox\n if (!SandboxCtor) {\n process.stderr.write(\n 'agent-runtime-mcp: @tangle-network/sandbox does not export Sandbox; cannot construct client\\n',\n )\n process.exit(2)\n }\n const baseUrl = process.env.SANDBOX_BASE_URL\n return new SandboxCtor({\n apiKey,\n ...(baseUrl ? { baseUrl } : {}),\n })\n}\n\ninterface ResearcherProfilePreset {\n agentRunSpec: Parameters<typeof runLoop>[0]['agentRun'] extends infer T ? NonNullable<T> : never\n output: Parameters<typeof runLoop>[0]['output']\n validator: Parameters<typeof runLoop>[0]['validator']\n}\n\ninterface ResearcherFanoutPreset {\n agentRuns: NonNullable<Parameters<typeof runLoop>[0]['agentRuns']>\n output: Parameters<typeof runLoop>[0]['output']\n validator: Parameters<typeof runLoop>[0]['validator']\n driver: Parameters<typeof runLoop>[0]['driver']\n}\n\nasync function loadResearcherDelegate(\n sandboxClient: LoopSandboxClient,\n maxConcurrency: number,\n): Promise<ResearcherDelegate | undefined> {\n // Optional peer — when `@tangle-network/agent-knowledge` isn't installed,\n // we silently omit the researcher tool from the advertisement. The\n // dynamic-import path is resolved at runtime; TypeScript cannot see the\n // peer, so we type the module structurally rather than via its own\n // declaration file.\n const profilesSpecifier = '@tangle-network/agent-knowledge/profiles'\n const mod = await import(profilesSpecifier).catch(() => undefined)\n if (!mod) return undefined\n type SingleFactory = (opts: { task: unknown }) => ResearcherProfilePreset\n type FanoutFactory = (opts: { task: unknown }) => ResearcherFanoutPreset\n const fanoutFactory = (mod as { multiHarnessResearcherFanout?: FanoutFactory })\n .multiHarnessResearcherFanout\n const singleFactory = (mod as { researcherProfile?: SingleFactory }).researcherProfile\n if (!fanoutFactory || !singleFactory) return undefined\n\n return async (args, ctx) => {\n const task = {\n question: args.question,\n knowledgeNamespace: args.namespace,\n scope: args.scope,\n sources: args.sources,\n recencyWindow: args.config?.recencyWindow\n ? {\n since: args.config.recencyWindow.since\n ? new Date(args.config.recencyWindow.since)\n : undefined,\n until: args.config.recencyWindow.until\n ? new Date(args.config.recencyWindow.until)\n : undefined,\n }\n : undefined,\n maxItems: args.config?.maxItems,\n minConfidence: args.config?.minConfidence,\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 preset = singleFactory({ task })\n const result = await runLoop({\n driver: {\n name: 'mcp-researcher-single',\n async plan(t, history) {\n return history.length === 0 ? [t] : []\n },\n decide(history) {\n return history.length > 0 ? 'pick-winner' : 'fail'\n },\n },\n agentRun: preset.agentRunSpec,\n output: preset.output,\n validator: preset.validator,\n task,\n ctx: { sandboxClient, signal: ctx.signal },\n maxIterations: 1,\n maxConcurrency,\n })\n const output = result.winner?.output\n if (!output) throw new Error('researcher delegate produced no winner')\n ctx.report({ iteration: 1, phase: 'completed' })\n return output as ResearchOutputShape\n }\n const fanout = fanoutFactory({ task })\n const result = await runLoop({\n driver: fanout.driver,\n agentRuns: fanout.agentRuns.slice(0, variants),\n output: fanout.output,\n validator: fanout.validator,\n task,\n ctx: { sandboxClient, signal: ctx.signal },\n maxIterations: variants,\n maxConcurrency: Math.min(maxConcurrency, variants),\n })\n const output = result.winner?.output\n if (!output) throw new Error('researcher delegate fanout produced no winner')\n ctx.report({ iteration: result.iterations.length, phase: 'completed' })\n return output as ResearchOutputShape\n }\n}\n\nfunction parseHarnesses(raw: string | undefined): string[] | undefined {\n if (!raw) return undefined\n const list = raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean)\n return list.length > 0 ? list : undefined\n}\n\nfunction parseFleetId(raw: string | undefined): string | undefined {\n if (typeof raw !== 'string') return undefined\n const trimmed = raw.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nfunction parseConcurrency(raw: string | undefined): number {\n if (!raw) return 4\n const n = Number(raw)\n if (!Number.isFinite(n) || n < 1) return 4\n return Math.min(Math.trunc(n), 32)\n}\n\nmain().catch((err) => {\n process.stderr.write(`agent-runtime-mcp: ${err instanceof Error ? err.stack : String(err)}\\n`)\n process.exit(1)\n})\n"],"mappings":"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","names":["result","output"]}
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * @experimental\n *\n * `agent-runtime-mcp` — stdio MCP server entry point.\n *\n * Spins up a server with the default coder delegate (wired against the\n * real `@tangle-network/sandbox` client) and, when the optional\n * `@tangle-network/agent-knowledge` peer is installed, a researcher\n * delegate against `multiHarnessResearcherFanout`.\n *\n * Environment variables:\n * TANGLE_API_KEY required — passed to `new Sandbox({ apiKey })`\n * SANDBOX_BASE_URL optional — sandbox-SDK base URL override\n * TANGLE_FLEET_ID optional — when set, delegations dispatch\n * INTO this fleet's shared workspace instead\n * of creating sibling sandboxes. Set by the\n * parent sandbox when launching this MCP\n * server so worker diffs land on the caller's\n * filesystem with no cross-sandbox boundary.\n * TANGLE_FLEET_EXCLUDE_MACHINES optional — comma-separated machine ids to\n * skip during fleet-mode round-robin\n * (typically the coordinator machine this\n * MCP server is running on).\n * MCP_MAX_CONCURRENT_SANDBOXES default 4 — kernel maxConcurrency cap\n * MCP_CODER_FANOUT_HARNESSES comma-separated harness ids to use for variants > 1\n * MCP_DISABLE_CODER set to `1` to omit `delegate_code`\n * MCP_DISABLE_RESEARCHER set to `1` to omit `delegate_research` even when peer is present\n */\n\nimport type { LoopSandboxClient } from '../loops'\nimport { runLoop } from '../loops'\nimport { detectExecutor } from './bin-helpers'\nimport { createDefaultCoderDelegate, type ResearcherDelegate } from './delegates'\nimport type { DelegationExecutor } from './executor'\nimport { createMcpServer } from './server'\nimport type { ResearchOutputShape } from './types'\n\nasync function main(): Promise<void> {\n const fanoutHarnesses = parseHarnesses(process.env.MCP_CODER_FANOUT_HARNESSES)\n const maxConcurrency = parseConcurrency(process.env.MCP_MAX_CONCURRENT_SANDBOXES)\n const wantCoder = !process.env.MCP_DISABLE_CODER\n const wantResearcher = !process.env.MCP_DISABLE_RESEARCHER\n const fleetId = parseFleetId(process.env.TANGLE_FLEET_ID)\n\n // Skip the sandbox client load entirely when no profile delegate needs it —\n // the feedback + status + history tools are queue-bound and require no\n // sandbox. Useful for tooling that mounts the MCP server purely for\n // self-introspection.\n const needsSandbox = wantCoder || wantResearcher\n let sandboxClient: LoopSandboxClient | undefined\n let executor: DelegationExecutor | undefined\n if (needsSandbox) {\n const apiKey = process.env.TANGLE_API_KEY\n if (!apiKey && !process.env.AGENT_RUNTIME_MCP_ALLOW_NO_KEY) {\n process.stderr.write(\n 'agent-runtime-mcp: TANGLE_API_KEY is required. Set AGENT_RUNTIME_MCP_ALLOW_NO_KEY=1 to run without it for diagnostics, or MCP_DISABLE_CODER=1 MCP_DISABLE_RESEARCHER=1 to run the queue-only subset.\\n',\n )\n process.exit(2)\n }\n // Fleet mode against a diagnostic stub is meaningless — the stub can't\n // resolve a real fleet handle. Refuse rather than silently degrading,\n // otherwise a fleet-mounted MCP would behave differently than configured.\n if (fleetId && !apiKey) {\n process.stderr.write(\n 'agent-runtime-mcp: TANGLE_FLEET_ID was set but TANGLE_API_KEY is missing; cannot resolve fleet handle. Provide an api key or unset TANGLE_FLEET_ID.\\n',\n )\n process.exit(2)\n }\n sandboxClient = await loadSandboxClient(apiKey)\n executor = await detectExecutor({ sandboxClient })\n if (fleetId) {\n process.stderr.write(`agent-runtime-mcp: fleet-aware delegation: fleetId=${fleetId}\\n`)\n }\n process.stderr.write(`agent-runtime-mcp: delegation placement → ${executor.describe()}\\n`)\n }\n\n const coderDelegate =\n wantCoder && executor\n ? createDefaultCoderDelegate({\n executor,\n fanoutHarnesses,\n maxConcurrency,\n })\n : undefined\n\n const researcherDelegate =\n wantResearcher && executor\n ? await loadResearcherDelegate(executor.client, maxConcurrency)\n : undefined\n\n const server = createMcpServer({ coderDelegate, researcherDelegate })\n\n process.on('SIGINT', () => {\n server.stop()\n process.exit(0)\n })\n process.on('SIGTERM', () => {\n server.stop()\n process.exit(0)\n })\n\n await server.serve()\n}\n\nasync function loadSandboxClient(apiKey: string | undefined): Promise<LoopSandboxClient> {\n // Diagnostic mode: AGENT_RUNTIME_MCP_ALLOW_NO_KEY=1 enables tools/list + the\n // queue-bound tools (status / history / feedback) without sandbox creds.\n // Coder + researcher delegations require a real client; the stub fails loud\n // at create() so the agent observes the cause instead of silent success.\n if (!apiKey) {\n return {\n async create() {\n throw new Error(\n 'agent-runtime-mcp: TANGLE_API_KEY is unset; coder/researcher delegations are disabled in diagnostic mode. Set TANGLE_API_KEY or use MCP_DISABLE_CODER=1 MCP_DISABLE_RESEARCHER=1 to remove the unsupported tools from the tool list.',\n )\n },\n } satisfies LoopSandboxClient\n }\n // Dynamic import keeps the bin importable in environments that haven't\n // installed `@tangle-network/sandbox` yet (the runtime package lists it\n // as a peer dep, not a hard dep).\n const mod = await import('@tangle-network/sandbox').catch((err) => {\n process.stderr.write(\n `agent-runtime-mcp: failed to load @tangle-network/sandbox (${err.message}); install the peer dependency\\n`,\n )\n process.exit(2)\n })\n const SandboxCtor = (mod as { Sandbox?: new (config: unknown) => LoopSandboxClient }).Sandbox\n if (!SandboxCtor) {\n process.stderr.write(\n 'agent-runtime-mcp: @tangle-network/sandbox does not export Sandbox; cannot construct client\\n',\n )\n process.exit(2)\n }\n const baseUrl = process.env.SANDBOX_BASE_URL\n return new SandboxCtor({\n apiKey,\n ...(baseUrl ? { baseUrl } : {}),\n })\n}\n\ninterface ResearcherProfilePreset {\n agentRunSpec: Parameters<typeof runLoop>[0]['agentRun'] extends infer T ? NonNullable<T> : never\n output: Parameters<typeof runLoop>[0]['output']\n validator: Parameters<typeof runLoop>[0]['validator']\n}\n\ninterface ResearcherFanoutPreset {\n agentRuns: NonNullable<Parameters<typeof runLoop>[0]['agentRuns']>\n output: Parameters<typeof runLoop>[0]['output']\n validator: Parameters<typeof runLoop>[0]['validator']\n driver: Parameters<typeof runLoop>[0]['driver']\n}\n\nasync function loadResearcherDelegate(\n sandboxClient: LoopSandboxClient,\n maxConcurrency: number,\n): Promise<ResearcherDelegate | undefined> {\n // Optional peer — when `@tangle-network/agent-knowledge` isn't installed,\n // we silently omit the researcher tool from the advertisement. The\n // dynamic-import path is resolved at runtime; TypeScript cannot see the\n // peer, so we type the module structurally rather than via its own\n // declaration file.\n const profilesSpecifier = '@tangle-network/agent-knowledge/profiles'\n const mod = await import(profilesSpecifier).catch(() => undefined)\n if (!mod) return undefined\n type SingleFactory = (opts: { task: unknown }) => ResearcherProfilePreset\n type FanoutFactory = (opts: { task: unknown }) => ResearcherFanoutPreset\n const fanoutFactory = (mod as { multiHarnessResearcherFanout?: FanoutFactory })\n .multiHarnessResearcherFanout\n const singleFactory = (mod as { researcherProfile?: SingleFactory }).researcherProfile\n if (!fanoutFactory || !singleFactory) return undefined\n\n return async (args, ctx) => {\n const task = {\n question: args.question,\n knowledgeNamespace: args.namespace,\n scope: args.scope,\n sources: args.sources,\n recencyWindow: args.config?.recencyWindow\n ? {\n since: args.config.recencyWindow.since\n ? new Date(args.config.recencyWindow.since)\n : undefined,\n until: args.config.recencyWindow.until\n ? new Date(args.config.recencyWindow.until)\n : undefined,\n }\n : undefined,\n maxItems: args.config?.maxItems,\n minConfidence: args.config?.minConfidence,\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 preset = singleFactory({ task })\n const result = await runLoop({\n driver: {\n name: 'mcp-researcher-single',\n async plan(t, history) {\n return history.length === 0 ? [t] : []\n },\n decide(history) {\n return history.length > 0 ? 'pick-winner' : 'fail'\n },\n },\n agentRun: preset.agentRunSpec,\n output: preset.output,\n validator: preset.validator,\n task,\n ctx: { sandboxClient, signal: ctx.signal },\n maxIterations: 1,\n maxConcurrency,\n })\n const output = result.winner?.output\n if (!output) throw new Error('researcher delegate produced no winner')\n ctx.report({ iteration: 1, phase: 'completed' })\n return output as ResearchOutputShape\n }\n const fanout = fanoutFactory({ task })\n const result = await runLoop({\n driver: fanout.driver,\n agentRuns: fanout.agentRuns.slice(0, variants),\n output: fanout.output,\n validator: fanout.validator,\n task,\n ctx: { sandboxClient, signal: ctx.signal },\n maxIterations: variants,\n maxConcurrency: Math.min(maxConcurrency, variants),\n })\n const output = result.winner?.output\n if (!output) throw new Error('researcher delegate fanout produced no winner')\n ctx.report({ iteration: result.iterations.length, phase: 'completed' })\n return output as ResearchOutputShape\n }\n}\n\nfunction parseHarnesses(raw: string | undefined): string[] | undefined {\n if (!raw) return undefined\n const list = raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean)\n return list.length > 0 ? list : undefined\n}\n\nfunction parseFleetId(raw: string | undefined): string | undefined {\n if (typeof raw !== 'string') return undefined\n const trimmed = raw.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nfunction parseConcurrency(raw: string | undefined): number {\n if (!raw) return 4\n const n = Number(raw)\n if (!Number.isFinite(n) || n < 1) return 4\n return Math.min(Math.trunc(n), 32)\n}\n\nmain().catch((err) => {\n process.stderr.write(`agent-runtime-mcp: ${err instanceof Error ? err.stack : String(err)}\\n`)\n process.exit(1)\n})\n"],"mappings":"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","names":["result","output"]}
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { h as LoopSandboxClient, k as LoopTraceEmitter } from '../types-DmkRGTBn.js';
|
|
1
|
+
import { h as LoopSandboxClient, i as LoopSandboxPlacement, k as LoopTraceEmitter } from '../types-DmkRGTBn.js';
|
|
2
2
|
import { SandboxInstance } from '@tangle-network/sandbox';
|
|
3
3
|
import { CoderOutput } from '../profiles.js';
|
|
4
|
+
import { L as LocalHarness, r as runLocalHarness } from '../local-harness-KrdFTY5R.js';
|
|
5
|
+
export { a as LocalHarnessResult, R as RunLocalHarnessOptions } from '../local-harness-KrdFTY5R.js';
|
|
4
6
|
import { b as OtelExporter } from '../otel-export-B33Cy_60.js';
|
|
5
7
|
export { m as mcpToolsForRuntimeMcp, e as mcpToolsForRuntimeMcpSubset } from '../otel-export-B33Cy_60.js';
|
|
6
8
|
import '../runtime-run-D5ItCKl_.js';
|
|
7
9
|
import '../types-BFgFD_sl.js';
|
|
8
10
|
import '@tangle-network/agent-eval';
|
|
11
|
+
import 'node:child_process';
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* @experimental
|
|
@@ -419,6 +422,191 @@ declare class InMemoryFeedbackStore implements FeedbackStore {
|
|
|
419
422
|
*/
|
|
420
423
|
declare function eventToSnapshot(event: FeedbackEvent): DelegationFeedbackSnapshot;
|
|
421
424
|
|
|
425
|
+
/**
|
|
426
|
+
* @experimental
|
|
427
|
+
*
|
|
428
|
+
* Git worktree helpers for the in-process delegation executor. Each
|
|
429
|
+
* delegation runs in its own worktree so multiple parallel harness
|
|
430
|
+
* subprocesses (claude / codex / opencode in a 3-way fanout) don't clobber
|
|
431
|
+
* each other's edits on the shared workspace.
|
|
432
|
+
*
|
|
433
|
+
* Worktrees live under `<repoRoot>/.coder-variants/<runId>/`. After the
|
|
434
|
+
* harness exits + the diff is captured, the worktree is removed.
|
|
435
|
+
*
|
|
436
|
+
* All operations spawn `git` via `child_process.spawn` synchronously
|
|
437
|
+
* (via a `runGit` helper). Stays narrow on purpose: no working-tree
|
|
438
|
+
* staging, no commits, no rebases.
|
|
439
|
+
*/
|
|
440
|
+
/** @experimental */
|
|
441
|
+
interface WorktreeHandle {
|
|
442
|
+
/** Absolute path to the worktree directory. */
|
|
443
|
+
path: string;
|
|
444
|
+
/** SHA the worktree was created at. */
|
|
445
|
+
baseSha: string;
|
|
446
|
+
/** Branch name created for this worktree (typically `delegate/<runId>`). */
|
|
447
|
+
branch: string;
|
|
448
|
+
}
|
|
449
|
+
/** @experimental */
|
|
450
|
+
interface CreateWorktreeOptions {
|
|
451
|
+
/** Absolute path to the main git checkout. */
|
|
452
|
+
repoRoot: string;
|
|
453
|
+
/** Unique id for the worktree path + branch. Use the delegation run id. */
|
|
454
|
+
runId: string;
|
|
455
|
+
/** Parent directory the worktree lives under. Defaults to `.coder-variants`. */
|
|
456
|
+
variantsDir?: string;
|
|
457
|
+
/** Override the base ref (default `HEAD`). */
|
|
458
|
+
baseRef?: string;
|
|
459
|
+
/** Test seam — inject a custom git runner. */
|
|
460
|
+
runGit?: GitRunner;
|
|
461
|
+
}
|
|
462
|
+
/** @experimental */
|
|
463
|
+
interface DiffOptions {
|
|
464
|
+
/** Worktree to diff. */
|
|
465
|
+
worktree: WorktreeHandle;
|
|
466
|
+
/** What to compare against. Default `worktree.baseSha`. */
|
|
467
|
+
baseRef?: string;
|
|
468
|
+
/** Test seam. */
|
|
469
|
+
runGit?: GitRunner;
|
|
470
|
+
}
|
|
471
|
+
/** @experimental */
|
|
472
|
+
interface DiffResult {
|
|
473
|
+
patch: string;
|
|
474
|
+
stats: {
|
|
475
|
+
filesChanged: number;
|
|
476
|
+
insertions: number;
|
|
477
|
+
deletions: number;
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
/** @experimental */
|
|
481
|
+
interface RemoveWorktreeOptions {
|
|
482
|
+
worktree: WorktreeHandle;
|
|
483
|
+
repoRoot: string;
|
|
484
|
+
/** Force removal even if dirty (default true; the loser of a fanout has uncommitted changes). */
|
|
485
|
+
force?: boolean;
|
|
486
|
+
/** Test seam. */
|
|
487
|
+
runGit?: GitRunner;
|
|
488
|
+
}
|
|
489
|
+
/** Pluggable git runner (sync) — replaceable in tests. */
|
|
490
|
+
type GitRunner = (args: ReadonlyArray<string>, opts: {
|
|
491
|
+
cwd: string;
|
|
492
|
+
}) => {
|
|
493
|
+
stdout: string;
|
|
494
|
+
stderr: string;
|
|
495
|
+
exitCode: number;
|
|
496
|
+
};
|
|
497
|
+
/** @experimental */
|
|
498
|
+
declare function createWorktree(options: CreateWorktreeOptions): Promise<WorktreeHandle>;
|
|
499
|
+
/** @experimental */
|
|
500
|
+
declare function captureWorktreeDiff(options: DiffOptions): Promise<DiffResult>;
|
|
501
|
+
/** @experimental */
|
|
502
|
+
declare function removeWorktree(options: RemoveWorktreeOptions): Promise<void>;
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* @experimental
|
|
506
|
+
*
|
|
507
|
+
* In-process delegation executor — when `agent-runtime-mcp` is running
|
|
508
|
+
* inside a sandbox whose image carries the local coding-harness CLIs
|
|
509
|
+
* (claude / codex / opencode), delegations spawn the harness AS A
|
|
510
|
+
* SUBPROCESS against a git worktree on the SAME filesystem instead of
|
|
511
|
+
* provisioning a sibling sandbox.
|
|
512
|
+
*
|
|
513
|
+
* Why: zero provisioning latency, worker diffs land in-place, multi-harness
|
|
514
|
+
* fanout = N parallel subprocesses in N parallel worktrees.
|
|
515
|
+
*
|
|
516
|
+
* Selection:
|
|
517
|
+
* - env `AGENT_RUNTIME_IN_SANDBOX=1` (set by the parent harness at MCP
|
|
518
|
+
* server launch) → in-process executor
|
|
519
|
+
* - env `TANGLE_FLEET_ID=...` → fleet executor (Phase 2.5)
|
|
520
|
+
* - neither → sibling sandbox executor (default)
|
|
521
|
+
*
|
|
522
|
+
* Multi-harness rotation: pass `harnesses: ['claude', 'codex', 'opencode']`
|
|
523
|
+
* to round-robin across calls. A `runLoop` + `FanoutVote(n: 3)` against this
|
|
524
|
+
* executor produces three parallel iterations, each running a different
|
|
525
|
+
* harness on its own worktree.
|
|
526
|
+
*
|
|
527
|
+
* Architecture:
|
|
528
|
+
*
|
|
529
|
+
* client.create() → returns a fake SandboxInstance whose streamPrompt:
|
|
530
|
+
* 1. createWorktree() — git worktree add /workspace/.coder-variants/<id>
|
|
531
|
+
* 2. runLocalHarness() — spawn claude/codex/opencode subprocess
|
|
532
|
+
* 3. captureWorktreeDiff() — git diff HEAD → patch + stats
|
|
533
|
+
* 4. run testCmd + typecheckCmd if specified (the executor doesn't
|
|
534
|
+
* own these — caller wires via task-extractor callback)
|
|
535
|
+
* 5. emit ONE SandboxEvent { type: 'result', data: { result: CoderOutput } }
|
|
536
|
+
* 6. removeWorktree() in finally
|
|
537
|
+
*/
|
|
538
|
+
|
|
539
|
+
/** @experimental */
|
|
540
|
+
interface InProcessExecutorOptions {
|
|
541
|
+
/**
|
|
542
|
+
* Absolute path to the git repo (the workspace inside the sandbox). The
|
|
543
|
+
* executor creates worktrees under `<repoRoot>/.coder-variants/`.
|
|
544
|
+
*/
|
|
545
|
+
repoRoot: string;
|
|
546
|
+
/**
|
|
547
|
+
* Harnesses to round-robin across calls. With one entry every delegation
|
|
548
|
+
* uses that harness; with three you get fanout diversity for free.
|
|
549
|
+
* Default `['claude']`.
|
|
550
|
+
*/
|
|
551
|
+
harnesses?: ReadonlyArray<LocalHarness>;
|
|
552
|
+
/**
|
|
553
|
+
* Optional per-delegation test command. Run with `cwd = worktree.path`
|
|
554
|
+
* after the harness exits. The exit code populates
|
|
555
|
+
* `CoderOutput.testResult.passed`.
|
|
556
|
+
*/
|
|
557
|
+
testCmd?: string;
|
|
558
|
+
/**
|
|
559
|
+
* Optional per-delegation typecheck command. Same shape as `testCmd`.
|
|
560
|
+
*/
|
|
561
|
+
typecheckCmd?: string;
|
|
562
|
+
/** Wall-clock cap per harness subprocess (ms). Default 5min. */
|
|
563
|
+
harnessTimeoutMs?: number;
|
|
564
|
+
/** Wall-clock cap per test/typecheck subprocess (ms). Default 2min. */
|
|
565
|
+
postCheckTimeoutMs?: number;
|
|
566
|
+
/** Test seam — override the git runner used by the worktree helpers. */
|
|
567
|
+
runGit?: GitRunner;
|
|
568
|
+
/**
|
|
569
|
+
* Test seam — override the harness runner. Defaults to spawning the real
|
|
570
|
+
* CLI via `runLocalHarness`. Tests inject a stub that returns a scripted
|
|
571
|
+
* `LocalHarnessResult`.
|
|
572
|
+
*/
|
|
573
|
+
runHarness?: typeof runLocalHarness;
|
|
574
|
+
/**
|
|
575
|
+
* Test seam — override the post-check runner. Defaults to spawning the
|
|
576
|
+
* configured `testCmd` / `typecheckCmd` via `child_process.spawn`.
|
|
577
|
+
*/
|
|
578
|
+
runPostCheck?: (cmd: string, cwd: string, signal?: AbortSignal) => Promise<{
|
|
579
|
+
exitCode: number;
|
|
580
|
+
stdout: string;
|
|
581
|
+
stderr: string;
|
|
582
|
+
}>;
|
|
583
|
+
}
|
|
584
|
+
/** @experimental */
|
|
585
|
+
interface InProcessExecutorDescribePlacement extends LoopSandboxPlacement {
|
|
586
|
+
/**
|
|
587
|
+
* Worktree path in the parent sandbox's filesystem. Set so trace
|
|
588
|
+
* consumers can correlate dispatch events with on-disk artifacts after
|
|
589
|
+
* the worker exits.
|
|
590
|
+
*/
|
|
591
|
+
worktreePath?: string;
|
|
592
|
+
/** Which harness handled this delegation. */
|
|
593
|
+
harness?: LocalHarness;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Build an in-process executor.
|
|
597
|
+
*
|
|
598
|
+
* Returns a {@link DelegationExecutor} whose `client.create()` returns a
|
|
599
|
+
* minimal "virtual" SandboxInstance — the kernel calls `streamPrompt(msg)`
|
|
600
|
+
* on it, which runs the local harness on a worktree and emits one
|
|
601
|
+
* `result` event whose `data.result` is a `CoderOutput`-shaped record.
|
|
602
|
+
*
|
|
603
|
+
* Pairs with `coderProfile`'s event parser (it walks the event list
|
|
604
|
+
* back-to-front for the first `type === 'result'`).
|
|
605
|
+
*
|
|
606
|
+
* @experimental
|
|
607
|
+
*/
|
|
608
|
+
declare function createInProcessExecutor(options: InProcessExecutorOptions): DelegationExecutor;
|
|
609
|
+
|
|
422
610
|
/**
|
|
423
611
|
* @experimental
|
|
424
612
|
*
|
|
@@ -1006,4 +1194,4 @@ declare function createPropagatingTraceEmitter(ctx: TraceContext): {
|
|
|
1006
1194
|
*/
|
|
1007
1195
|
declare function traceContextToEnv(ctx: TraceContext): Record<string, string>;
|
|
1008
1196
|
|
|
1009
|
-
export { type CoderDelegate, type CreateDefaultCoderDelegateOptions, DELEGATE_CODE_DESCRIPTION, DELEGATE_CODE_INPUT_SCHEMA, DELEGATE_CODE_TOOL_NAME, DELEGATE_FEEDBACK_DESCRIPTION, DELEGATE_FEEDBACK_INPUT_SCHEMA, DELEGATE_FEEDBACK_TOOL_NAME, DELEGATE_RESEARCH_DESCRIPTION, DELEGATE_RESEARCH_INPUT_SCHEMA, DELEGATE_RESEARCH_TOOL_NAME, DELEGATION_HISTORY_DESCRIPTION, DELEGATION_HISTORY_INPUT_SCHEMA, DELEGATION_HISTORY_TOOL_NAME, DELEGATION_STATUS_DESCRIPTION, DELEGATION_STATUS_INPUT_SCHEMA, DELEGATION_STATUS_TOOL_NAME, type DelegateCodeArgs, type DelegateCodeConfig, type DelegateCodeResult, type DelegateFeedbackArgs, type DelegateFeedbackResult, type DelegateResearchArgs, type DelegateResearchConfig, type DelegateResearchResult, type DelegateRunCtx, type DelegationError, type DelegationExecutor, type DelegationFeedbackSnapshot, type DelegationHistoryArgs, type DelegationHistoryEntry, type DelegationHistoryResult, type DelegationProfile, type DelegationProgress, type DelegationRecord, type DelegationResultPayload, type DelegationStatus, type DelegationStatusArgs, type DelegationStatusResult, DelegationTaskQueue, type DelegationTaskQueueOptions, type DetectExecutorArgs, type FeedbackEvent, type FeedbackRating, type FeedbackRefersTo, type FeedbackStore, type FleetHandle, type FleetWorkspaceExecutorOptions, InMemoryFeedbackStore, type JsonRpcMessage, type JsonRpcResponse, type McpServer, type McpServerOptions, type McpToolDescriptor, type McpTransport, type ResearchOutputShape, type ResearchSource, type ResearcherDelegate, type SiblingSandboxExecutorOptions, type SubmitInput, type SubmitOutput, type TraceContext, createDefaultCoderDelegate, createDelegateCodeHandler, createDelegateFeedbackHandler, createDelegateResearchHandler, createDelegationHistoryHandler, createDelegationStatusHandler, createFleetWorkspaceExecutor, createInProcessTransport, createMcpServer, createPropagatingTraceEmitter, createSiblingSandboxExecutor, detectExecutor, eventToSnapshot, hashIdempotencyInput, readTraceContextFromEnv, traceContextToEnv, validateDelegateCodeArgs, validateDelegateFeedbackArgs, validateDelegateResearchArgs, validateDelegationHistoryArgs, validateDelegationStatusArgs };
|
|
1197
|
+
export { type CoderDelegate, type CreateDefaultCoderDelegateOptions, type CreateWorktreeOptions, DELEGATE_CODE_DESCRIPTION, DELEGATE_CODE_INPUT_SCHEMA, DELEGATE_CODE_TOOL_NAME, DELEGATE_FEEDBACK_DESCRIPTION, DELEGATE_FEEDBACK_INPUT_SCHEMA, DELEGATE_FEEDBACK_TOOL_NAME, DELEGATE_RESEARCH_DESCRIPTION, DELEGATE_RESEARCH_INPUT_SCHEMA, DELEGATE_RESEARCH_TOOL_NAME, DELEGATION_HISTORY_DESCRIPTION, DELEGATION_HISTORY_INPUT_SCHEMA, DELEGATION_HISTORY_TOOL_NAME, DELEGATION_STATUS_DESCRIPTION, DELEGATION_STATUS_INPUT_SCHEMA, DELEGATION_STATUS_TOOL_NAME, type DelegateCodeArgs, type DelegateCodeConfig, type DelegateCodeResult, type DelegateFeedbackArgs, type DelegateFeedbackResult, type DelegateResearchArgs, type DelegateResearchConfig, type DelegateResearchResult, type DelegateRunCtx, type DelegationError, type DelegationExecutor, type DelegationFeedbackSnapshot, type DelegationHistoryArgs, type DelegationHistoryEntry, type DelegationHistoryResult, type DelegationProfile, type DelegationProgress, type DelegationRecord, type DelegationResultPayload, type DelegationStatus, type DelegationStatusArgs, type DelegationStatusResult, DelegationTaskQueue, type DelegationTaskQueueOptions, type DetectExecutorArgs, type DiffOptions, type DiffResult, type FeedbackEvent, type FeedbackRating, type FeedbackRefersTo, type FeedbackStore, type FleetHandle, type FleetWorkspaceExecutorOptions, type GitRunner, InMemoryFeedbackStore, type InProcessExecutorDescribePlacement, type InProcessExecutorOptions, type JsonRpcMessage, type JsonRpcResponse, LocalHarness, type McpServer, type McpServerOptions, type McpToolDescriptor, type McpTransport, type RemoveWorktreeOptions, type ResearchOutputShape, type ResearchSource, type ResearcherDelegate, type SiblingSandboxExecutorOptions, type SubmitInput, type SubmitOutput, type TraceContext, type WorktreeHandle, captureWorktreeDiff, createDefaultCoderDelegate, createDelegateCodeHandler, createDelegateFeedbackHandler, createDelegateResearchHandler, createDelegationHistoryHandler, createDelegationStatusHandler, createFleetWorkspaceExecutor, createInProcessExecutor, createInProcessTransport, createMcpServer, createPropagatingTraceEmitter, createSiblingSandboxExecutor, createWorktree, detectExecutor, eventToSnapshot, hashIdempotencyInput, readTraceContextFromEnv, removeWorktree, runLocalHarness, traceContextToEnv, validateDelegateCodeArgs, validateDelegateFeedbackArgs, validateDelegateResearchArgs, validateDelegationHistoryArgs, validateDelegationStatusArgs };
|
package/dist/mcp/index.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
loopEventToOtelSpan,
|
|
4
|
-
mcpToolsForRuntimeMcp,
|
|
5
|
-
mcpToolsForRuntimeMcpSubset
|
|
6
|
-
} from "../chunk-7HN72MF3.js";
|
|
7
|
-
import {
|
|
2
|
+
captureWorktreeDiff,
|
|
8
3
|
createDefaultCoderDelegate,
|
|
9
4
|
createFleetWorkspaceExecutor,
|
|
5
|
+
createInProcessExecutor,
|
|
10
6
|
createInProcessTransport,
|
|
11
7
|
createMcpServer,
|
|
12
8
|
createSiblingSandboxExecutor,
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
createWorktree,
|
|
10
|
+
detectExecutor,
|
|
11
|
+
removeWorktree
|
|
12
|
+
} from "../chunk-ZJACJZF7.js";
|
|
13
|
+
import {
|
|
14
|
+
createOtelExporter,
|
|
15
|
+
loopEventToOtelSpan,
|
|
16
|
+
mcpToolsForRuntimeMcp,
|
|
17
|
+
mcpToolsForRuntimeMcpSubset
|
|
18
|
+
} from "../chunk-QZEDHTT2.js";
|
|
15
19
|
import {
|
|
16
20
|
DELEGATE_CODE_DESCRIPTION,
|
|
17
21
|
DELEGATE_CODE_INPUT_SCHEMA,
|
|
@@ -43,6 +47,9 @@ import {
|
|
|
43
47
|
validateDelegationHistoryArgs,
|
|
44
48
|
validateDelegationStatusArgs
|
|
45
49
|
} from "../chunk-UNQM6XQO.js";
|
|
50
|
+
import {
|
|
51
|
+
runLocalHarness
|
|
52
|
+
} from "../chunk-GLR25NG7.js";
|
|
46
53
|
import "../chunk-TZ53F7M7.js";
|
|
47
54
|
import "../chunk-CBQVID7G.js";
|
|
48
55
|
import "../chunk-URDSRUPQ.js";
|
|
@@ -60,11 +67,7 @@ function createPropagatingTraceEmitter(ctx) {
|
|
|
60
67
|
const emitter = {
|
|
61
68
|
emit(event) {
|
|
62
69
|
if (!exporter) return;
|
|
63
|
-
const span = loopEventToOtelSpan(
|
|
64
|
-
event,
|
|
65
|
-
ctx.traceId,
|
|
66
|
-
ctx.parentSpanId
|
|
67
|
-
);
|
|
70
|
+
const span = loopEventToOtelSpan(event, ctx.traceId, ctx.parentSpanId);
|
|
68
71
|
exporter.exportSpan(span);
|
|
69
72
|
}
|
|
70
73
|
};
|
|
@@ -102,6 +105,7 @@ export {
|
|
|
102
105
|
DELEGATION_STATUS_TOOL_NAME,
|
|
103
106
|
DelegationTaskQueue,
|
|
104
107
|
InMemoryFeedbackStore,
|
|
108
|
+
captureWorktreeDiff,
|
|
105
109
|
createDefaultCoderDelegate,
|
|
106
110
|
createDelegateCodeHandler,
|
|
107
111
|
createDelegateFeedbackHandler,
|
|
@@ -109,16 +113,20 @@ export {
|
|
|
109
113
|
createDelegationHistoryHandler,
|
|
110
114
|
createDelegationStatusHandler,
|
|
111
115
|
createFleetWorkspaceExecutor,
|
|
116
|
+
createInProcessExecutor,
|
|
112
117
|
createInProcessTransport,
|
|
113
118
|
createMcpServer,
|
|
114
119
|
createPropagatingTraceEmitter,
|
|
115
120
|
createSiblingSandboxExecutor,
|
|
121
|
+
createWorktree,
|
|
116
122
|
detectExecutor,
|
|
117
123
|
eventToSnapshot,
|
|
118
124
|
hashIdempotencyInput,
|
|
119
125
|
mcpToolsForRuntimeMcp,
|
|
120
126
|
mcpToolsForRuntimeMcpSubset,
|
|
121
127
|
readTraceContextFromEnv,
|
|
128
|
+
removeWorktree,
|
|
129
|
+
runLocalHarness,
|
|
122
130
|
traceContextToEnv,
|
|
123
131
|
validateDelegateCodeArgs,
|
|
124
132
|
validateDelegateFeedbackArgs,
|
package/dist/mcp/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/trace-propagation.ts"],"sourcesContent":["/**\n * @experimental\n *\n * Trace context propagation for MCP subprocess.\n *\n * When the MCP server is launched as a child process by a sandbox harness,\n * the parent passes trace context via environment variables:\n *\n * TRACE_ID=<current-run-trace-id>\n * PARENT_SPAN_ID=<span-that-dispatched-the-delegation>\n *\n * The MCP server reads these at startup and uses them as the root of its\n * internal trace tree. All spans emitted by `runLoop` invocations inside\n * the MCP are children of the parent's delegation span.\n *\n * When these env vars are absent, the MCP generates a fresh trace root —\n * the server operates standalone without trace joining.\n */\n\nimport type { LoopTraceEmitter, LoopTraceEvent } from '../loops/types'\nimport type { OtelExporter } from '../otel-export'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/trace-propagation.ts"],"sourcesContent":["/**\n * @experimental\n *\n * Trace context propagation for MCP subprocess.\n *\n * When the MCP server is launched as a child process by a sandbox harness,\n * the parent passes trace context via environment variables:\n *\n * TRACE_ID=<current-run-trace-id>\n * PARENT_SPAN_ID=<span-that-dispatched-the-delegation>\n *\n * The MCP server reads these at startup and uses them as the root of its\n * internal trace tree. All spans emitted by `runLoop` invocations inside\n * the MCP are children of the parent's delegation span.\n *\n * When these env vars are absent, the MCP generates a fresh trace root —\n * the server operates standalone without trace joining.\n */\n\nimport type { LoopTraceEmitter, LoopTraceEvent } from '../loops/types'\nimport type { OtelExporter } from '../otel-export'\nimport { createOtelExporter, loopEventToOtelSpan } from '../otel-export'\n\nexport interface TraceContext {\n /** Trace id inherited from the parent process, or a fresh one. */\n traceId: string\n /** Parent span id from the delegation that launched this MCP server. */\n parentSpanId?: string\n}\n\n/**\n * Read trace context from the process environment.\n * Returns a context with inherited ids or a freshly generated root.\n */\nexport function readTraceContextFromEnv(): TraceContext {\n const traceId = process.env.TRACE_ID || generateTraceId()\n const parentSpanId = process.env.PARENT_SPAN_ID || undefined\n return { traceId, parentSpanId }\n}\n\n/**\n * Create a LoopTraceEmitter that:\n * 1. Parents all spans under the inherited PARENT_SPAN_ID.\n * 2. Exports spans to OTEL when OTEL_EXPORTER_OTLP_ENDPOINT is set.\n *\n * Returns both the emitter and the optional exporter handle for shutdown.\n */\nexport function createPropagatingTraceEmitter(ctx: TraceContext): {\n emitter: LoopTraceEmitter\n exporter: OtelExporter | undefined\n context: TraceContext\n} {\n const exporter = createOtelExporter()\n\n const emitter: LoopTraceEmitter = {\n emit(event: LoopTraceEvent) {\n if (!exporter) return\n const span = loopEventToOtelSpan(event, ctx.traceId, ctx.parentSpanId)\n exporter.exportSpan(span)\n },\n }\n\n return { emitter, exporter, context: ctx }\n}\n\n/**\n * Build env vars to pass to a child MCP subprocess so it inherits the\n * current trace context.\n */\nexport function traceContextToEnv(ctx: TraceContext): Record<string, string> {\n const env: Record<string, string> = { TRACE_ID: ctx.traceId }\n if (ctx.parentSpanId) env.PARENT_SPAN_ID = ctx.parentSpanId\n return env\n}\n\nfunction generateTraceId(): string {\n const bytes = new Uint8Array(16)\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes)\n } else {\n for (let i = 0; i < 16; 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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCO,SAAS,0BAAwC;AACtD,QAAM,UAAU,QAAQ,IAAI,YAAY,gBAAgB;AACxD,QAAM,eAAe,QAAQ,IAAI,kBAAkB;AACnD,SAAO,EAAE,SAAS,aAAa;AACjC;AASO,SAAS,8BAA8B,KAI5C;AACA,QAAM,WAAW,mBAAmB;AAEpC,QAAM,UAA4B;AAAA,IAChC,KAAK,OAAuB;AAC1B,UAAI,CAAC,SAAU;AACf,YAAM,OAAO,oBAAoB,OAAO,IAAI,SAAS,IAAI,YAAY;AACrE,eAAS,WAAW,IAAI;AAAA,IAC1B;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,UAAU,SAAS,IAAI;AAC3C;AAMO,SAAS,kBAAkB,KAA2C;AAC3E,QAAM,MAA8B,EAAE,UAAU,IAAI,QAAQ;AAC5D,MAAI,IAAI,aAAc,KAAI,iBAAiB,IAAI;AAC/C,SAAO;AACT;AAEA,SAAS,kBAA0B;AACjC,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,MAAI,OAAO,WAAW,QAAQ,oBAAoB,YAAY;AAC5D,eAAW,OAAO,gBAAgB,KAAK;AAAA,EACzC,OAAO;AACL,aAAS,IAAI,GAAG,IAAI,IAAI,IAAK,OAAM,CAAC,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG;AAAA,EACxE;AACA,SAAO,MAAM,KAAK,KAAK,EACpB,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AACZ;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Reusable runtime lifecycle for domain-specific agents.",
|
|
5
5
|
"homepage": "https://github.com/tangle-network/agent-runtime#readme",
|
|
6
6
|
"repository": {
|
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
"import": "./dist/analyst-loop.js",
|
|
30
30
|
"default": "./dist/analyst-loop.js"
|
|
31
31
|
},
|
|
32
|
+
"./improvement": {
|
|
33
|
+
"types": "./dist/improvement.d.ts",
|
|
34
|
+
"import": "./dist/improvement.js",
|
|
35
|
+
"default": "./dist/improvement.js"
|
|
36
|
+
},
|
|
32
37
|
"./agent": {
|
|
33
38
|
"types": "./dist/agent.d.ts",
|
|
34
39
|
"import": "./dist/agent.js",
|
|
@@ -60,18 +65,8 @@
|
|
|
60
65
|
"publishConfig": {
|
|
61
66
|
"access": "public"
|
|
62
67
|
},
|
|
63
|
-
"scripts": {
|
|
64
|
-
"build": "tsup",
|
|
65
|
-
"dev": "tsup --watch",
|
|
66
|
-
"prepare": "tsup",
|
|
67
|
-
"test": "vitest run",
|
|
68
|
-
"test:watch": "vitest",
|
|
69
|
-
"lint": "biome check src tests examples",
|
|
70
|
-
"lint:fix": "biome check --write src tests examples",
|
|
71
|
-
"typecheck": "tsc --noEmit"
|
|
72
|
-
},
|
|
73
68
|
"dependencies": {
|
|
74
|
-
"@tangle-network/agent-eval": "^0.
|
|
69
|
+
"@tangle-network/agent-eval": "^0.40.2"
|
|
75
70
|
},
|
|
76
71
|
"devDependencies": {
|
|
77
72
|
"@biomejs/biome": "^2.4.0",
|
|
@@ -81,20 +76,10 @@
|
|
|
81
76
|
"typescript": "^5.7.0",
|
|
82
77
|
"vitest": "^3.0.0"
|
|
83
78
|
},
|
|
84
|
-
"pnpm": {
|
|
85
|
-
"minimumReleaseAge": 4320,
|
|
86
|
-
"minimumReleaseAgeExclude": [
|
|
87
|
-
"@tangle-network/agent-eval"
|
|
88
|
-
],
|
|
89
|
-
"onlyBuiltDependencies": [
|
|
90
|
-
"esbuild"
|
|
91
|
-
]
|
|
92
|
-
},
|
|
93
79
|
"engines": {
|
|
94
80
|
"node": ">=20"
|
|
95
81
|
},
|
|
96
82
|
"license": "MIT",
|
|
97
|
-
"packageManager": "pnpm@10.28.0",
|
|
98
83
|
"peerDependencies": {
|
|
99
84
|
"@tangle-network/agent-knowledge": ">=1.3.0 <2.0.0",
|
|
100
85
|
"@tangle-network/sandbox": ">=0.1.2 <0.3.0"
|
|
@@ -103,5 +88,14 @@
|
|
|
103
88
|
"@tangle-network/agent-knowledge": {
|
|
104
89
|
"optional": true
|
|
105
90
|
}
|
|
91
|
+
},
|
|
92
|
+
"scripts": {
|
|
93
|
+
"build": "tsup",
|
|
94
|
+
"dev": "tsup --watch",
|
|
95
|
+
"test": "vitest run",
|
|
96
|
+
"test:watch": "vitest",
|
|
97
|
+
"lint": "biome check src tests examples",
|
|
98
|
+
"lint:fix": "biome check --write src tests examples",
|
|
99
|
+
"typecheck": "tsc --noEmit"
|
|
106
100
|
}
|
|
107
|
-
}
|
|
101
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp/openai-tools.ts","../src/otel-export.ts"],"sourcesContent":["/**\n * @experimental\n *\n * OpenAI Chat Completions `tools[]` projection of the 5 agent-runtime MCP\n * delegation tools.\n *\n * Use when configuring `createOpenAICompatibleBackend({ tools: ... })` so the\n * model can call `delegate_code`, `delegate_research`, `delegate_feedback`,\n * `delegation_status`, and `delegation_history` through the OpenAI-compat\n * transport (tcloud, OpenRouter, OpenAI direct, cli-bridge). The runtime\n * surfaces tool calls as `tool_call` stream events — execution is the\n * caller's responsibility (typically the parent sandbox runtime's MCP\n * mount).\n *\n * Sandbox-SDK callers do NOT need this helper: the sandbox runtime mounts\n * MCP servers natively and the in-sandbox harness discovers tools via the\n * runtime, not via an OpenAI tools array.\n *\n * Tool name + description + JSON-schema are pulled from the canonical\n * `DELEGATE_*` constants exported by `./tools/*` so the projection cannot\n * drift from the server's own validators.\n */\n\nimport type { OpenAIChatTool } from '../types'\nimport {\n DELEGATE_CODE_DESCRIPTION,\n DELEGATE_CODE_INPUT_SCHEMA,\n DELEGATE_CODE_TOOL_NAME,\n} from './tools/delegate-code'\nimport {\n DELEGATE_FEEDBACK_DESCRIPTION,\n DELEGATE_FEEDBACK_INPUT_SCHEMA,\n DELEGATE_FEEDBACK_TOOL_NAME,\n} from './tools/delegate-feedback'\nimport {\n DELEGATE_RESEARCH_DESCRIPTION,\n DELEGATE_RESEARCH_INPUT_SCHEMA,\n DELEGATE_RESEARCH_TOOL_NAME,\n} from './tools/delegate-research'\nimport {\n DELEGATION_HISTORY_DESCRIPTION,\n DELEGATION_HISTORY_INPUT_SCHEMA,\n DELEGATION_HISTORY_TOOL_NAME,\n} from './tools/delegation-history'\nimport {\n DELEGATION_STATUS_DESCRIPTION,\n DELEGATION_STATUS_INPUT_SCHEMA,\n DELEGATION_STATUS_TOOL_NAME,\n} from './tools/delegation-status'\n\nfunction buildTool(\n name: string,\n description: string,\n parameters: Readonly<Record<string, unknown>>,\n): OpenAIChatTool {\n // `parameters` arrives as a deeply-readonly `as const` literal. The\n // OpenAI-compat backend JSON-serializes the body so a shallow copy\n // into a plain object is sufficient — and shields callers that mutate\n // the returned descriptor from corrupting the source constant.\n return {\n type: 'function',\n function: { name, description, parameters: { ...parameters } },\n }\n}\n\n/**\n * @experimental\n *\n * Returns the 5 delegation tools projected into OpenAI Chat Completions\n * `tools[]` shape. The order is stable: `delegate_code`,\n * `delegate_research`, `delegate_feedback`, `delegation_status`,\n * `delegation_history`.\n */\nexport function mcpToolsForRuntimeMcp(): OpenAIChatTool[] {\n return [\n buildTool(\n DELEGATE_CODE_TOOL_NAME,\n DELEGATE_CODE_DESCRIPTION,\n DELEGATE_CODE_INPUT_SCHEMA as Readonly<Record<string, unknown>>,\n ),\n buildTool(\n DELEGATE_RESEARCH_TOOL_NAME,\n DELEGATE_RESEARCH_DESCRIPTION,\n DELEGATE_RESEARCH_INPUT_SCHEMA as Readonly<Record<string, unknown>>,\n ),\n buildTool(\n DELEGATE_FEEDBACK_TOOL_NAME,\n DELEGATE_FEEDBACK_DESCRIPTION,\n DELEGATE_FEEDBACK_INPUT_SCHEMA as Readonly<Record<string, unknown>>,\n ),\n buildTool(\n DELEGATION_STATUS_TOOL_NAME,\n DELEGATION_STATUS_DESCRIPTION,\n DELEGATION_STATUS_INPUT_SCHEMA as Readonly<Record<string, unknown>>,\n ),\n buildTool(\n DELEGATION_HISTORY_TOOL_NAME,\n DELEGATION_HISTORY_DESCRIPTION,\n DELEGATION_HISTORY_INPUT_SCHEMA as Readonly<Record<string, unknown>>,\n ),\n ]\n}\n\n/**\n * @experimental\n *\n * Subset filter — return only the projected tools whose `function.name`\n * appears in `names`. Useful for curated mounts (e.g. only the queue-bound\n * delegation tools, omitting `delegate_feedback`). Unknown names are\n * silently ignored; pass an empty array to get an empty result.\n */\nexport function mcpToolsForRuntimeMcpSubset(names: ReadonlyArray<string>): OpenAIChatTool[] {\n const allowed = new Set(names)\n return mcpToolsForRuntimeMcp().filter((tool) => allowed.has(tool.function.name))\n}\n","/**\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.23.0' }\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 ?? (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\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).map(b => b.toString(16).padStart(2, '0')).join('')\n}\n"],"mappings":"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","names":[]}
|