@tangle-network/agent-runtime 0.32.0 → 0.34.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.
Files changed (35) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-CBQVID7G.js → chunk-5QVVET72.js} +2 -2
  3. package/dist/{chunk-PACEJFUE.js → chunk-7KS6UEHB.js} +277 -10
  4. package/dist/chunk-7KS6UEHB.js.map +1 -0
  5. package/dist/{chunk-UNQM6XQO.js → chunk-HSX6PFZR.js} +2 -2
  6. package/dist/{chunk-URDSRUPQ.js → chunk-PY6NMZYX.js} +2 -2
  7. package/dist/{chunk-IORDTTVB.js → chunk-Q4ZDSLBD.js} +153 -3
  8. package/dist/chunk-Q4ZDSLBD.js.map +1 -0
  9. package/dist/{chunk-XZYF3YJN.js → chunk-SQSCRJ7U.js} +7 -1
  10. package/dist/{chunk-XZYF3YJN.js.map → chunk-SQSCRJ7U.js.map} +1 -1
  11. package/dist/{chunk-XNZYEQMF.js → chunk-VVHX5RKE.js} +4 -4
  12. package/dist/improvement.d.ts +128 -3
  13. package/dist/improvement.js +86 -0
  14. package/dist/improvement.js.map +1 -1
  15. package/dist/index.d.ts +18 -2
  16. package/dist/index.js +7 -3
  17. package/dist/index.js.map +1 -1
  18. package/dist/loops.d.ts +202 -40
  19. package/dist/loops.js +11 -5
  20. package/dist/mcp/bin.js +6 -6
  21. package/dist/mcp/index.d.ts +3 -3
  22. package/dist/mcp/index.js +19 -10
  23. package/dist/mcp/index.js.map +1 -1
  24. package/dist/{otel-export-CsgwKFq8.d.ts → otel-export-xgf4J6bo.d.ts} +23 -1
  25. package/dist/profiles.d.ts +1 -1
  26. package/dist/profiles.js +3 -3
  27. package/dist/{types-Co507h15.d.ts → types-BZw2bqJc.d.ts} +44 -1
  28. package/package.json +24 -12
  29. package/skills/agent-runtime-adoption/SKILL.md +170 -0
  30. package/dist/chunk-IORDTTVB.js.map +0 -1
  31. package/dist/chunk-PACEJFUE.js.map +0 -1
  32. /package/dist/{chunk-CBQVID7G.js.map → chunk-5QVVET72.js.map} +0 -0
  33. /package/dist/{chunk-UNQM6XQO.js.map → chunk-HSX6PFZR.js.map} +0 -0
  34. /package/dist/{chunk-URDSRUPQ.js.map → chunk-PY6NMZYX.js.map} +0 -0
  35. /package/dist/{chunk-XNZYEQMF.js.map → chunk-VVHX5RKE.js.map} +0 -0
package/dist/loops.d.ts CHANGED
@@ -1,12 +1,116 @@
1
+ import { AgentProfile, SandboxEvent } from '@tangle-network/sandbox';
1
2
  export { AgentProfile, CreateSandboxOptions, SandboxEvent, SandboxInstance } from '@tangle-network/sandbox';
2
- import { D as Driver, I as Iteration, A as AgentRunSpec, O as OutputAdapter, V as Validator, E as ExecCtx, L as LoopWinner, a as LoopResult, b as LoopSandboxClient } from './types-Co507h15.js';
3
- export { c as LoopDecisionPayload, d as LoopEndedPayload, e as LoopIterationDispatchPayload, f as LoopIterationEndedPayload, g as LoopIterationStartedPayload, h as LoopSandboxPlacement, i as LoopStartedPayload, j as LoopTokenUsage, k as LoopTraceEmitter, l as LoopTraceEvent, m as ValidationCtx } from './types-Co507h15.js';
4
- import { DefaultVerdict, AgentProfile } from '@tangle-network/agent-eval';
3
+ import { I as Iteration, D as Driver, L as LoopSandboxClient, A as AgentRunSpec, O as OutputAdapter, V as Validator, E as ExecCtx, a as LoopWinner, b as LoopResult } from './types-BZw2bqJc.js';
4
+ export { c as LoopDecisionPayload, d as LoopEndedPayload, e as LoopIterationDispatchPayload, f as LoopIterationEndedPayload, g as LoopIterationStartedPayload, h as LoopPlanDescription, i as LoopPlanPayload, j as LoopSandboxPlacement, k as LoopStartedPayload, l as LoopTokenUsage, m as LoopTraceEmitter, n as LoopTraceEvent, o as ValidationCtx } from './types-BZw2bqJc.js';
5
+ import { DefaultVerdict, AgentProfile as AgentProfile$1 } from '@tangle-network/agent-eval';
5
6
  export { DefaultVerdict } from '@tangle-network/agent-eval';
6
7
  import { Scenario, DispatchFn, ProfileDispatchFn } from '@tangle-network/agent-eval/campaign';
7
8
  import './runtime-run-B8VIiOhI.js';
8
9
  import './types-CsCCryln.js';
9
10
 
11
+ /**
12
+ * @experimental
13
+ *
14
+ * Dynamic driver — the agent authors the loop topology at runtime.
15
+ *
16
+ * Where `refine` and `fanout-vote` encode a fixed shape as a pure function of
17
+ * history, this driver delegates the per-round shape to an injected
18
+ * `TopologyPlanner`. Each round the planner inspects the task + iteration
19
+ * history and emits one `TopologyMove`:
20
+ * - `refine` → one task next round (optionally rewritten from the prior attempt)
21
+ * - `fanout` → N tasks next round (the kernel round-robins `agentRuns`, so a
22
+ * 2-harness fanout dispatches branch 0 to harness A and branch 1 to harness B)
23
+ * - `stop` → terminate; the kernel selects the winner across all iterations
24
+ *
25
+ * The planner is the brain; this driver is the structure. It maps moves onto
26
+ * the kernel's `plan`/`decide` contract, enforces the iteration + fanout caps,
27
+ * and fails loud on a malformed move. The planner is injected exactly like
28
+ * `refine`'s `refineTask` and `fanout-vote`'s `selector` — so a test can drive
29
+ * a deterministic policy through the real kernel, and production can wire it to
30
+ * an LLM via `createSandboxPlanner`.
31
+ *
32
+ * Topology is orthogonal to harness: the planner never names a backend. Which
33
+ * harness runs a branch is decided by the `AgentRunSpec` the kernel round-robins
34
+ * to, so one dynamic driver works across claude-code, codex, opencode, pi —
35
+ * including fanning a single round across several at once.
36
+ */
37
+
38
+ /** Terminal once `decide` returns `'done'` (a kernel terminal decision). */
39
+ type DynamicDecision = 'continue' | 'done';
40
+ /**
41
+ * One topology decision for the next round. `fanout` carries explicit tasks
42
+ * rather than a count so the planner can issue heterogeneous branches (a
43
+ * different sub-task per harness); pass N copies of one task for a homogeneous
44
+ * fanout that relies on `agentRuns` diversity instead.
45
+ *
46
+ * @experimental
47
+ */
48
+ type TopologyMove<Task> = {
49
+ kind: 'refine';
50
+ task: Task;
51
+ rationale?: string;
52
+ } | {
53
+ kind: 'fanout';
54
+ tasks: Task[];
55
+ rationale?: string;
56
+ } | {
57
+ kind: 'stop';
58
+ rationale?: string;
59
+ };
60
+ /** @experimental */
61
+ interface PlannerContext<Task, Output> {
62
+ /** The root task the loop was invoked with — stable across rounds. */
63
+ task: Task;
64
+ /** Every iteration so far, in dispatch order, with outputs + verdicts. */
65
+ history: ReadonlyArray<Iteration<Task, Output>>;
66
+ /** `history.length` — iterations already spent. */
67
+ iterationsSpent: number;
68
+ /** Iterations left before the driver's `maxIterations` cap forces a stop. */
69
+ iterationsRemaining: number;
70
+ }
71
+ /**
72
+ * Chooses the next topology move from the task + history. Sync or async; an
73
+ * async planner is where an LLM call goes (see `createSandboxPlanner`).
74
+ *
75
+ * @experimental
76
+ */
77
+ type TopologyPlanner<Task, Output> = (ctx: PlannerContext<Task, Output>) => TopologyMove<Task> | Promise<TopologyMove<Task>>;
78
+ /** @experimental */
79
+ interface CreateDynamicDriverOptions<Task, Output> {
80
+ /** The agent-authored topology policy. Invoked once per round in `plan`. */
81
+ planner: TopologyPlanner<Task, Output>;
82
+ /**
83
+ * Hard safety cap on total iterations. When reached, the driver stops before
84
+ * consulting the planner. Default 8. Set the kernel's `runLoop`
85
+ * `maxIterations >= ` this so the driver's cap governs and the loop closes on
86
+ * a clean `'done'` rather than a truncated `'continue'`.
87
+ */
88
+ maxIterations?: number;
89
+ /** Max branches a single `fanout` move may dispatch. Default 4. */
90
+ maxFanout?: number;
91
+ /** Stable identifier surfaced in trace events. Default `'dynamic'`. */
92
+ name?: string;
93
+ }
94
+ /** @experimental */
95
+ declare function createDynamicDriver<Task, Output>(options: CreateDynamicDriverOptions<Task, Output>): Driver<Task, Output, DynamicDecision>;
96
+ /**
97
+ * Compact, planner-friendly view of iteration history — what an LLM planner
98
+ * needs to choose the next move without the raw event streams. Output is
99
+ * truncated so a long run's prompt stays bounded.
100
+ *
101
+ * @experimental
102
+ */
103
+ declare function summarizeHistory<Task, Output>(history: ReadonlyArray<Iteration<Task, Output>>, opts?: {
104
+ maxOutputChars?: number;
105
+ }): Array<{
106
+ index: number;
107
+ agentRunName: string;
108
+ valid?: boolean;
109
+ score?: number;
110
+ error?: string;
111
+ output?: string;
112
+ }>;
113
+
10
114
  /**
11
115
  * @experimental
12
116
  *
@@ -88,6 +192,64 @@ declare function createRefineDriver<Task, Output>(options?: CreateRefineDriverOp
88
192
  */
89
193
  declare function refineWinnerIndex<Task, Output>(iterations: ReadonlyArray<Iteration<Task, Output>>): number | undefined;
90
194
 
195
+ /**
196
+ * @experimental
197
+ *
198
+ * `createSandboxPlanner` — wire the dynamic driver's `TopologyPlanner` to a
199
+ * real agent. Each round it spins a sandbox on `profile`, streams a prompt that
200
+ * carries the history summary, and decodes the agent's chosen `TopologyMove`
201
+ * from a JSON envelope it emits. This is the "agent authors its own loop
202
+ * topology" path: the planner profile can be any harness (claude-code, codex,
203
+ * opencode, pi) — its only job is to read what happened and emit the next move.
204
+ *
205
+ * The planner profile is deliberately distinct from the worker `agentRuns`: a
206
+ * cheap fast model can steer topology while expensive workers do the labor, and
207
+ * the planner never names which harness runs a branch — the kernel's
208
+ * `agentRuns` round-robin decides that.
209
+ *
210
+ * Envelope contract the agent must emit (fenced ```json or a structured
211
+ * `result`/`final` event payload):
212
+ * { "kind": "refine" | "fanout" | "stop",
213
+ * "tasks"?: [ <task>, ... ], // decoded via `decodeTask`
214
+ * "n"?: number, // fanout shorthand: N copies of the root task
215
+ * "rationale"?: string }
216
+ *
217
+ * A missing / unparseable / unknown-kind envelope throws `PlannerError` — the
218
+ * loop never silently runs a topology the agent did not choose.
219
+ */
220
+
221
+ /** Raw, pre-decode envelope an agent emits to choose the next move. */
222
+ interface TopologyMoveEnvelope {
223
+ kind: string;
224
+ tasks?: unknown[];
225
+ n?: number;
226
+ rationale?: string;
227
+ }
228
+ /** @experimental */
229
+ interface CreateSandboxPlannerOptions<Task, Output> {
230
+ /** Sandbox client — the planner calls `.create()` once per round. */
231
+ client: LoopSandboxClient;
232
+ /** The planner agent. Steers topology; does not run the work. */
233
+ profile: AgentProfile;
234
+ /**
235
+ * Decode one raw task from the envelope's `tasks[]` into a domain `Task`.
236
+ * Required because `Task` is opaque to this module — only the caller knows
237
+ * its shape. Throw to reject a malformed task; the error surfaces as a
238
+ * `PlannerError`.
239
+ */
240
+ decodeTask: (raw: unknown, ctx: PlannerContext<Task, Output>) => Task;
241
+ /** Override the default prompt (history summary + envelope contract). */
242
+ buildPrompt?: (ctx: PlannerContext<Task, Output>) => string;
243
+ /** Override envelope extraction from the event stream. */
244
+ parseEnvelope?: (events: SandboxEvent[]) => TopologyMoveEnvelope | undefined;
245
+ /** Sandbox overrides for the planner sandbox (timeouts, env, etc.). */
246
+ sandboxOverrides?: AgentRunSpec<Task>['sandboxOverrides'];
247
+ /** Cancellation for the planner's own LLM call. */
248
+ signal?: AbortSignal;
249
+ }
250
+ /** @experimental */
251
+ declare function createSandboxPlanner<Task, Output>(opts: CreateSandboxPlannerOptions<Task, Output>): TopologyPlanner<Task, Output>;
252
+
91
253
  /**
92
254
  * @experimental
93
255
  *
@@ -154,41 +316,6 @@ interface RunLoopOptions<Task, Output, Decision> {
154
316
  /** @experimental */
155
317
  declare function runLoop<Task, Output, Decision>(options: RunLoopOptions<Task, Output, Decision>): Promise<LoopResult<Task, Output, Decision>>;
156
318
 
157
- /**
158
- * Bridge a finished `runLoop` into an agent-eval campaign / profile-matrix
159
- * dispatch.
160
- *
161
- * `runProfileMatrix` (and `runCampaign`) run the backend-integrity guard over
162
- * the token usage a dispatch reports through `ctx.cost`. A dispatch that wraps
163
- * `runLoop` must forward the loop's cost AND token usage, or the guard reads
164
- * the run as a stub and throws. `reportLoopUsage` is that one line:
165
- *
166
- * const dispatch: ProfileDispatchFn<S, A> = async (profile, scenario, ctx) => {
167
- * const result = await runLoop({ ...optsFor(profile, scenario), ctx: loopCtx })
168
- * reportLoopUsage(ctx, result)
169
- * return result.winner?.output as A
170
- * }
171
- *
172
- * Typed structurally against the campaign `DispatchContext.cost` so this module
173
- * stays free of an agent-eval import — it works with any cost meter exposing
174
- * `observe` + `observeTokens`.
175
- */
176
-
177
- /** The slice of an agent-eval campaign `DispatchContext.cost` this needs. */
178
- interface UsageSink {
179
- observe(amountUsd: number, source: string): void;
180
- observeTokens(usage: {
181
- input: number;
182
- output: number;
183
- }): void;
184
- }
185
- /**
186
- * Forward a `LoopResult`'s aggregated cost + token usage into a campaign cost
187
- * meter so the backend-integrity guard sees real LLM activity. `source`
188
- * defaults to `'loop'`.
189
- */
190
- declare function reportLoopUsage<Task, Output, Decision>(cost: UsageSink, result: Pick<LoopResult<Task, Output, Decision>, 'costUsd' | 'tokenUsage'>, source?: string): void;
191
-
192
319
  /**
193
320
  * `loopDispatch` — turn `runLoop` into an agent-eval campaign dispatch.
194
321
  *
@@ -225,7 +352,7 @@ interface LoopDispatchOptions<Task, Output, Decision, TScenario extends Scenario
225
352
  sandboxClient: LoopSandboxClient;
226
353
  /** Build the per-cell runLoop options from the scenario (+ profile, when
227
354
  * used with `runProfileMatrix`). */
228
- toLoopOptions: (scenario: TScenario, profile: AgentProfile) => LoopOptionsForDispatch<Task, Output, Decision>;
355
+ toLoopOptions: (scenario: TScenario, profile: AgentProfile$1) => LoopOptionsForDispatch<Task, Output, Decision>;
229
356
  /** Map the finished loop to the artifact the judges score. Default:
230
357
  * `result.winner?.output`. A loop with no winner yields `undefined` (judges
231
358
  * skip the cell) — but the loop's token usage is STILL reported, so the
@@ -252,4 +379,39 @@ declare function loopCampaignDispatch<Task, Output, Decision, TScenario extends
252
379
  toLoopOptions: (scenario: TScenario) => LoopOptionsForDispatch<Task, Output, Decision>;
253
380
  }): DispatchFn<TScenario, TArtifact>;
254
381
 
255
- export { AgentRunSpec, type CreateFanoutVoteDriverOptions, type CreateRefineDriverOptions, Driver, ExecCtx, type FanoutVoteDecision, type FanoutVoteScored, Iteration, type LoopDispatchOptions, type LoopOptionsForDispatch, LoopResult, LoopSandboxClient, LoopWinner, OutputAdapter, type RefineDecision, type RunLoopOptions, type UsageSink, Validator, createFanoutVoteDriver, createRefineDriver, loopCampaignDispatch, loopDispatch, refineWinnerIndex, reportLoopUsage, runLoop, scoreFanoutVoteIterations };
382
+ /**
383
+ * Bridge a finished `runLoop` into an agent-eval campaign / profile-matrix
384
+ * dispatch.
385
+ *
386
+ * `runProfileMatrix` (and `runCampaign`) run the backend-integrity guard over
387
+ * the token usage a dispatch reports through `ctx.cost`. A dispatch that wraps
388
+ * `runLoop` must forward the loop's cost AND token usage, or the guard reads
389
+ * the run as a stub and throws. `reportLoopUsage` is that one line:
390
+ *
391
+ * const dispatch: ProfileDispatchFn<S, A> = async (profile, scenario, ctx) => {
392
+ * const result = await runLoop({ ...optsFor(profile, scenario), ctx: loopCtx })
393
+ * reportLoopUsage(ctx, result)
394
+ * return result.winner?.output as A
395
+ * }
396
+ *
397
+ * Typed structurally against the campaign `DispatchContext.cost` so this module
398
+ * stays free of an agent-eval import — it works with any cost meter exposing
399
+ * `observe` + `observeTokens`.
400
+ */
401
+
402
+ /** The slice of an agent-eval campaign `DispatchContext.cost` this needs. */
403
+ interface UsageSink {
404
+ observe(amountUsd: number, source: string): void;
405
+ observeTokens(usage: {
406
+ input: number;
407
+ output: number;
408
+ }): void;
409
+ }
410
+ /**
411
+ * Forward a `LoopResult`'s aggregated cost + token usage into a campaign cost
412
+ * meter so the backend-integrity guard sees real LLM activity. `source`
413
+ * defaults to `'loop'`.
414
+ */
415
+ declare function reportLoopUsage<Task, Output, Decision>(cost: UsageSink, result: Pick<LoopResult<Task, Output, Decision>, 'costUsd' | 'tokenUsage'>, source?: string): void;
416
+
417
+ export { AgentRunSpec, type CreateDynamicDriverOptions, type CreateFanoutVoteDriverOptions, type CreateRefineDriverOptions, type CreateSandboxPlannerOptions, Driver, type DynamicDecision, ExecCtx, type FanoutVoteDecision, type FanoutVoteScored, Iteration, type LoopDispatchOptions, type LoopOptionsForDispatch, LoopResult, LoopSandboxClient, LoopWinner, OutputAdapter, type PlannerContext, type RefineDecision, type RunLoopOptions, type TopologyMove, type TopologyMoveEnvelope, type TopologyPlanner, type UsageSink, Validator, createDynamicDriver, createFanoutVoteDriver, createRefineDriver, createSandboxPlanner, loopCampaignDispatch, loopDispatch, refineWinnerIndex, reportLoopUsage, runLoop, scoreFanoutVoteIterations, summarizeHistory };
package/dist/loops.js CHANGED
@@ -1,25 +1,31 @@
1
1
  import {
2
+ createDynamicDriver,
2
3
  createRefineDriver,
4
+ createSandboxPlanner,
3
5
  loopCampaignDispatch,
4
6
  loopDispatch,
5
7
  refineWinnerIndex,
6
8
  reportLoopUsage,
7
- runLoop
8
- } from "./chunk-PACEJFUE.js";
9
+ runLoop,
10
+ summarizeHistory
11
+ } from "./chunk-7KS6UEHB.js";
9
12
  import {
10
13
  createFanoutVoteDriver,
11
14
  scoreFanoutVoteIterations
12
- } from "./chunk-URDSRUPQ.js";
13
- import "./chunk-XZYF3YJN.js";
15
+ } from "./chunk-PY6NMZYX.js";
16
+ import "./chunk-SQSCRJ7U.js";
14
17
  import "./chunk-DGUM43GV.js";
15
18
  export {
19
+ createDynamicDriver,
16
20
  createFanoutVoteDriver,
17
21
  createRefineDriver,
22
+ createSandboxPlanner,
18
23
  loopCampaignDispatch,
19
24
  loopDispatch,
20
25
  refineWinnerIndex,
21
26
  reportLoopUsage,
22
27
  runLoop,
23
- scoreFanoutVoteIterations
28
+ scoreFanoutVoteIterations,
29
+ summarizeHistory
24
30
  };
25
31
  //# sourceMappingURL=loops.js.map
package/dist/mcp/bin.js CHANGED
@@ -3,15 +3,15 @@ import {
3
3
  createDefaultCoderDelegate,
4
4
  createMcpServer,
5
5
  detectExecutor
6
- } from "../chunk-XNZYEQMF.js";
7
- import "../chunk-UNQM6XQO.js";
6
+ } from "../chunk-VVHX5RKE.js";
7
+ import "../chunk-HSX6PFZR.js";
8
8
  import "../chunk-GLR25NG7.js";
9
9
  import {
10
10
  runLoop
11
- } from "../chunk-PACEJFUE.js";
12
- import "../chunk-CBQVID7G.js";
13
- import "../chunk-URDSRUPQ.js";
14
- import "../chunk-XZYF3YJN.js";
11
+ } from "../chunk-7KS6UEHB.js";
12
+ import "../chunk-5QVVET72.js";
13
+ import "../chunk-PY6NMZYX.js";
14
+ import "../chunk-SQSCRJ7U.js";
15
15
  import "../chunk-DGUM43GV.js";
16
16
 
17
17
  // src/mcp/bin.ts
@@ -1,10 +1,10 @@
1
- import { b as LoopSandboxClient, h as LoopSandboxPlacement, k as LoopTraceEmitter } from '../types-Co507h15.js';
1
+ import { L as LoopSandboxClient, j as LoopSandboxPlacement, m as LoopTraceEmitter } from '../types-BZw2bqJc.js';
2
2
  import { SandboxInstance } from '@tangle-network/sandbox';
3
3
  import { CoderOutput } from '../profiles.js';
4
4
  import { L as LocalHarness, r as runLocalHarness } from '../local-harness-KrdFTY5R.js';
5
5
  export { a as LocalHarnessResult, R as RunLocalHarnessOptions } from '../local-harness-KrdFTY5R.js';
6
- import { O as OtelExporter } from '../otel-export-CsgwKFq8.js';
7
- export { m as mcpToolsForRuntimeMcp, a as mcpToolsForRuntimeMcpSubset } from '../otel-export-CsgwKFq8.js';
6
+ import { O as OtelExporter } from '../otel-export-xgf4J6bo.js';
7
+ export { m as mcpToolsForRuntimeMcp, a as mcpToolsForRuntimeMcpSubset } from '../otel-export-xgf4J6bo.js';
8
8
  import '@tangle-network/agent-eval';
9
9
  import '../runtime-run-B8VIiOhI.js';
10
10
  import '../types-CsCCryln.js';
package/dist/mcp/index.js CHANGED
@@ -9,13 +9,13 @@ import {
9
9
  createWorktree,
10
10
  detectExecutor,
11
11
  removeWorktree
12
- } from "../chunk-XNZYEQMF.js";
12
+ } from "../chunk-VVHX5RKE.js";
13
13
  import {
14
+ buildLoopOtelSpans,
14
15
  createOtelExporter,
15
- loopEventToOtelSpan,
16
16
  mcpToolsForRuntimeMcp,
17
17
  mcpToolsForRuntimeMcpSubset
18
- } from "../chunk-IORDTTVB.js";
18
+ } from "../chunk-Q4ZDSLBD.js";
19
19
  import {
20
20
  DELEGATE_CODE_DESCRIPTION,
21
21
  DELEGATE_CODE_INPUT_SCHEMA,
@@ -46,14 +46,14 @@ import {
46
46
  validateDelegateResearchArgs,
47
47
  validateDelegationHistoryArgs,
48
48
  validateDelegationStatusArgs
49
- } from "../chunk-UNQM6XQO.js";
49
+ } from "../chunk-HSX6PFZR.js";
50
50
  import {
51
51
  runLocalHarness
52
52
  } from "../chunk-GLR25NG7.js";
53
- import "../chunk-PACEJFUE.js";
54
- import "../chunk-CBQVID7G.js";
55
- import "../chunk-URDSRUPQ.js";
56
- import "../chunk-XZYF3YJN.js";
53
+ import "../chunk-7KS6UEHB.js";
54
+ import "../chunk-5QVVET72.js";
55
+ import "../chunk-PY6NMZYX.js";
56
+ import "../chunk-SQSCRJ7U.js";
57
57
  import "../chunk-DGUM43GV.js";
58
58
 
59
59
  // src/mcp/trace-propagation.ts
@@ -64,11 +64,20 @@ function readTraceContextFromEnv() {
64
64
  }
65
65
  function createPropagatingTraceEmitter(ctx) {
66
66
  const exporter = createOtelExporter();
67
+ const buffers = /* @__PURE__ */ new Map();
67
68
  const emitter = {
68
69
  emit(event) {
69
70
  if (!exporter) return;
70
- const span = loopEventToOtelSpan(event, ctx.traceId, ctx.parentSpanId);
71
- exporter.exportSpan(span);
71
+ const buf = buffers.get(event.runId);
72
+ if (buf) buf.push(event);
73
+ else buffers.set(event.runId, [event]);
74
+ if (event.kind === "loop.ended") {
75
+ const events = buffers.get(event.runId) ?? [event];
76
+ buffers.delete(event.runId);
77
+ for (const span of buildLoopOtelSpans(events, ctx.traceId, ctx.parentSpanId)) {
78
+ exporter.exportSpan(span);
79
+ }
80
+ }
72
81
  }
73
82
  };
74
83
  return { emitter, exporter, context: ctx };
@@ -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 { 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":[]}
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 { buildLoopOtelSpans, createOtelExporter } 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 // Buffer events per loop run, then emit the full nested span tree on\n // `loop.ended` so the topology hierarchy (loop → round → branch) reaches the\n // OTLP collector — not a flat list of zero-duration point spans. A run that\n // never reaches `loop.ended` (hard abort) drops its buffer; acceptable for\n // the short-lived MCP subprocess.\n const buffers = new Map<string, LoopTraceEvent[]>()\n\n const emitter: LoopTraceEmitter = {\n emit(event: LoopTraceEvent) {\n if (!exporter) return\n const buf = buffers.get(event.runId)\n if (buf) buf.push(event)\n else buffers.set(event.runId, [event])\n if (event.kind === 'loop.ended') {\n const events = buffers.get(event.runId) ?? [event]\n buffers.delete(event.runId)\n for (const span of buildLoopOtelSpans(events, ctx.traceId, ctx.parentSpanId)) {\n exporter.exportSpan(span)\n }\n }\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;AAOpC,QAAM,UAAU,oBAAI,IAA8B;AAElD,QAAM,UAA4B;AAAA,IAChC,KAAK,OAAuB;AAC1B,UAAI,CAAC,SAAU;AACf,YAAM,MAAM,QAAQ,IAAI,MAAM,KAAK;AACnC,UAAI,IAAK,KAAI,KAAK,KAAK;AAAA,UAClB,SAAQ,IAAI,MAAM,OAAO,CAAC,KAAK,CAAC;AACrC,UAAI,MAAM,SAAS,cAAc;AAC/B,cAAM,SAAS,QAAQ,IAAI,MAAM,KAAK,KAAK,CAAC,KAAK;AACjD,gBAAQ,OAAO,MAAM,KAAK;AAC1B,mBAAW,QAAQ,mBAAmB,QAAQ,IAAI,SAAS,IAAI,YAAY,GAAG;AAC5E,mBAAS,WAAW,IAAI;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;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":[]}
@@ -110,6 +110,28 @@ declare function loopEventToOtelSpan(event: {
110
110
  timestamp: number;
111
111
  payload: object;
112
112
  }, traceId: string, parentSpanId?: string): OtelSpan;
113
+ /**
114
+ * Build a nested, real-duration OTLP span tree for ONE loop run from its full
115
+ * ordered `LoopTraceEvent` stream. Unlike `loopEventToOtelSpan` (one flat,
116
+ * zero-duration span per event), this reconstructs the topology hierarchy a
117
+ * GenAI trace viewer renders natively:
118
+ *
119
+ * loop (invoke_workflow)
120
+ * └─ loop.round[k] (invoke_workflow) ← tangle.loop.move.{kind,width,rationale}
121
+ * ├─ loop.iteration[i] (invoke_agent) ← gen_ai.agent.name + usage + verdict + placement
122
+ * └─ …
123
+ *
124
+ * Attributes follow the current GenAI semconv (`gen_ai.*`) where they apply and
125
+ * a namespaced `tangle.loop.*` / `tangle.cost.usd` extension for topology /
126
+ * verdict / placement / cost (not yet standardized). Pure: feed it a buffered
127
+ * per-runId event array (e.g. flushed on `loop.ended`) and export the result.
128
+ */
129
+ declare function buildLoopOtelSpans(events: ReadonlyArray<{
130
+ kind: string;
131
+ runId: string;
132
+ timestamp: number;
133
+ payload: object;
134
+ }>, traceId: string, rootParentSpanId?: string): OtelSpan[];
113
135
  /** Wire version the eval-runs ingest enforces (X-Tangle-Wire-Version + body). */
114
136
  declare const INTELLIGENCE_WIRE_VERSION = "2026-05-26.v1";
115
137
  interface EvalRunGeneration {
@@ -166,4 +188,4 @@ interface EvalRunsExportResult {
166
188
  */
167
189
  declare function exportEvalRuns(events: EvalRunEvent[], config?: EvalRunsExportConfig): Promise<EvalRunsExportResult>;
168
190
 
169
- export { type EvalRunEvent as E, INTELLIGENCE_WIRE_VERSION as I, type OtelExporter as O, mcpToolsForRuntimeMcpSubset as a, type EvalRunGeneration as b, type EvalRunsExportConfig as c, type EvalRunsExportResult as d, type OtelAttribute as e, type OtelExportConfig as f, type OtelSpan as g, createOtelExporter as h, exportEvalRuns as i, loopEventToOtelSpan as l, mcpToolsForRuntimeMcp as m };
191
+ export { type EvalRunEvent as E, INTELLIGENCE_WIRE_VERSION as I, type OtelExporter as O, mcpToolsForRuntimeMcpSubset as a, type EvalRunGeneration as b, type EvalRunsExportConfig as c, type EvalRunsExportResult as d, type OtelAttribute as e, type OtelExportConfig as f, type OtelSpan as g, buildLoopOtelSpans as h, createOtelExporter as i, exportEvalRuns as j, loopEventToOtelSpan as l, mcpToolsForRuntimeMcp as m };
@@ -1,5 +1,5 @@
1
1
  import { AgentProfile } from '@tangle-network/sandbox';
2
- import { O as OutputAdapter, V as Validator, A as AgentRunSpec, D as Driver } from './types-Co507h15.js';
2
+ import { O as OutputAdapter, V as Validator, A as AgentRunSpec, D as Driver } from './types-BZw2bqJc.js';
3
3
  import '@tangle-network/agent-eval';
4
4
  import './runtime-run-B8VIiOhI.js';
5
5
  import './types-CsCCryln.js';
package/dist/profiles.js CHANGED
@@ -2,9 +2,9 @@ import {
2
2
  coderProfile,
3
3
  createCoderValidator,
4
4
  multiHarnessCoderFanout
5
- } from "./chunk-CBQVID7G.js";
6
- import "./chunk-URDSRUPQ.js";
7
- import "./chunk-XZYF3YJN.js";
5
+ } from "./chunk-5QVVET72.js";
6
+ import "./chunk-PY6NMZYX.js";
7
+ import "./chunk-SQSCRJ7U.js";
8
8
  import "./chunk-DGUM43GV.js";
9
9
  export {
10
10
  coderProfile,
@@ -118,6 +118,23 @@ interface Driver<Task, Output, Decision> {
118
118
  * is hit, or when the abort signal fires.
119
119
  */
120
120
  decide(history: ReadonlyArray<Iteration<Task, Output>>): Decision | Promise<Decision>;
121
+ /**
122
+ * Optional: describe the move `plan()` just produced, for trace emission.
123
+ * The kernel calls this immediately after `plan()` and emits the result in
124
+ * the `loop.plan` event so a topology viewer can render the agent's chosen
125
+ * move + rationale (not just the inferred fan-width). Drivers whose topology
126
+ * is a pure function of count (refine/fanout-vote) omit it — the kernel
127
+ * infers `moveKind` from the planned-task count. Agent-authored drivers
128
+ * (`createDynamicDriver`) return their chosen move's kind + rationale.
129
+ */
130
+ describePlan?(): LoopPlanDescription | undefined;
131
+ }
132
+ /** @experimental Driver-supplied description of the just-planned move. */
133
+ interface LoopPlanDescription {
134
+ /** Topology move this round — e.g. `'refine' | 'fanout' | 'verify' | 'stop'`. */
135
+ kind: string;
136
+ /** Why the driver chose this move (the agent's rationale), when available. */
137
+ rationale?: string;
121
138
  }
122
139
  /** @experimental */
123
140
  interface LoopWinner<Task, Output> {
@@ -174,6 +191,11 @@ type LoopTraceEvent = {
174
191
  runId: string;
175
192
  timestamp: number;
176
193
  payload: LoopStartedPayload;
194
+ } | {
195
+ kind: 'loop.plan';
196
+ runId: string;
197
+ timestamp: number;
198
+ payload: LoopPlanPayload;
177
199
  } | {
178
200
  kind: 'loop.iteration.started';
179
201
  runId: string;
@@ -207,6 +229,24 @@ interface LoopStartedPayload {
207
229
  maxIterations: number;
208
230
  maxConcurrency: number;
209
231
  }
232
+ /**
233
+ * Emitted once per `plan()` round, immediately after the driver plans. Carries
234
+ * the topology move so a viewer renders WHAT the agent decided + WHY, not just
235
+ * the inferred fan-width. `moveKind` is the driver's `describePlan().kind` when
236
+ * provided, else inferred from `plannedCount` (0→stop, 1→refine, N→fanout).
237
+ *
238
+ * @experimental
239
+ */
240
+ interface LoopPlanPayload {
241
+ /** 0-based plan round (one per `plan()` call). */
242
+ roundIndex: number;
243
+ /** Tasks the driver issued this round. */
244
+ plannedCount: number;
245
+ /** Topology move — `'refine' | 'fanout' | 'verify' | 'stop'` etc. */
246
+ moveKind: string;
247
+ /** Driver rationale for the move, when available. */
248
+ rationale?: string;
249
+ }
210
250
  /** @experimental */
211
251
  interface LoopIterationStartedPayload {
212
252
  iterationIndex: number;
@@ -241,6 +281,9 @@ interface LoopIterationEndedPayload {
241
281
  error?: string;
242
282
  costUsd: number;
243
283
  durationMs: number;
284
+ /** Summed LLM token usage for this iteration — maps to gen_ai.usage.* on the
285
+ * branch span. Omitted when no `llm_call` events carried token counts. */
286
+ tokenUsage?: LoopTokenUsage;
244
287
  }
245
288
  /** @experimental */
246
289
  interface LoopDecisionPayload {
@@ -281,4 +324,4 @@ interface ExecCtx {
281
324
  parentSpanId?: string;
282
325
  }
283
326
 
284
- export type { AgentRunSpec as A, Driver as D, ExecCtx as E, Iteration as I, LoopWinner as L, OutputAdapter as O, Validator as V, LoopResult as a, LoopSandboxClient as b, LoopDecisionPayload as c, LoopEndedPayload as d, LoopIterationDispatchPayload as e, LoopIterationEndedPayload as f, LoopIterationStartedPayload as g, LoopSandboxPlacement as h, LoopStartedPayload as i, LoopTokenUsage as j, LoopTraceEmitter as k, LoopTraceEvent as l, ValidationCtx as m };
327
+ export type { AgentRunSpec as A, Driver as D, ExecCtx as E, Iteration as I, LoopSandboxClient as L, OutputAdapter as O, Validator as V, LoopWinner as a, LoopResult as b, LoopDecisionPayload as c, LoopEndedPayload as d, LoopIterationDispatchPayload as e, LoopIterationEndedPayload as f, LoopIterationStartedPayload as g, LoopPlanDescription as h, LoopPlanPayload as i, LoopSandboxPlacement as j, LoopStartedPayload as k, LoopTokenUsage as l, LoopTraceEmitter as m, LoopTraceEvent as n, ValidationCtx as o };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-runtime",
3
- "version": "0.32.0",
3
+ "version": "0.34.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": {
@@ -60,11 +60,22 @@
60
60
  },
61
61
  "files": [
62
62
  "dist",
63
- "README.md"
63
+ "README.md",
64
+ "skills"
64
65
  ],
65
66
  "publishConfig": {
66
67
  "access": "public"
67
68
  },
69
+ "scripts": {
70
+ "build": "tsup",
71
+ "dev": "tsup --watch",
72
+ "prepare": "tsup",
73
+ "test": "vitest run",
74
+ "test:watch": "vitest",
75
+ "lint": "biome check src tests examples",
76
+ "lint:fix": "biome check --write src tests examples",
77
+ "typecheck": "tsc --noEmit"
78
+ },
68
79
  "dependencies": {},
69
80
  "devDependencies": {
70
81
  "@biomejs/biome": "^2.4.0",
@@ -75,10 +86,20 @@
75
86
  "typescript": "^5.7.0",
76
87
  "vitest": "^3.0.0"
77
88
  },
89
+ "pnpm": {
90
+ "minimumReleaseAge": 4320,
91
+ "minimumReleaseAgeExclude": [
92
+ "@tangle-network/agent-eval"
93
+ ],
94
+ "onlyBuiltDependencies": [
95
+ "esbuild"
96
+ ]
97
+ },
78
98
  "engines": {
79
99
  "node": ">=20"
80
100
  },
81
101
  "license": "MIT",
102
+ "packageManager": "pnpm@10.28.0",
82
103
  "peerDependencies": {
83
104
  "@tangle-network/agent-eval": ">=0.61.0 <1.0.0",
84
105
  "@tangle-network/agent-knowledge": ">=1.3.0 <2.0.0",
@@ -91,14 +112,5 @@
91
112
  "@tangle-network/sandbox": {
92
113
  "optional": true
93
114
  }
94
- },
95
- "scripts": {
96
- "build": "tsup",
97
- "dev": "tsup --watch",
98
- "test": "vitest run",
99
- "test:watch": "vitest",
100
- "lint": "biome check src tests examples",
101
- "lint:fix": "biome check --write src tests examples",
102
- "typecheck": "tsc --noEmit"
103
115
  }
104
- }
116
+ }