@tangle-network/agent-app 0.10.1 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -17,9 +17,10 @@ import {
17
17
  parseMissionBlocks,
18
18
  parseSessionStreamEnvelope,
19
19
  reduceMissionEvents,
20
+ stepAgentActivity,
20
21
  stepGateProposalId,
21
22
  volumeGateProposalId
22
- } from "./chunk-UIWB2F6N.js";
23
+ } from "./chunk-UDXMR3AD.js";
23
24
  import {
24
25
  addSecurityHeaders,
25
26
  checkRateLimit,
@@ -38,6 +39,22 @@ import {
38
39
  redactForIngestion,
39
40
  revealSpan
40
41
  } from "./chunk-5RMIUJDI.js";
42
+ import {
43
+ buildFlowTrace,
44
+ childSpanContext,
45
+ createMissionTraceContext,
46
+ renderHistogram,
47
+ renderWaterfall,
48
+ summarize,
49
+ timedEventsFromLines,
50
+ traceEnv
51
+ } from "./chunk-5RT6KY4G.js";
52
+ import {
53
+ composeMissionFlowTrace,
54
+ delegationActivityToFlowSpans,
55
+ loopTraceEventsToFlowSpans,
56
+ stepActivityFlowTrace
57
+ } from "./chunk-AFDROJ64.js";
41
58
  import {
42
59
  ApprovalEventSchema,
43
60
  BrandTokensSchema,
@@ -74,12 +91,12 @@ import {
74
91
  createPresetToolHandlers,
75
92
  createPresetWorkspaceKeyManager,
76
93
  createPresetWorkspaceKeyStore
77
- } from "./chunk-EYXTDVDY.js";
94
+ } from "./chunk-SAOAAA3S.js";
78
95
  import {
79
96
  createPlatformBalanceManager,
80
97
  createTcloudKeyProvisioner,
81
98
  createWorkspaceKeyManager
82
- } from "./chunk-YS6A6G57.js";
99
+ } from "./chunk-G3HCU7TA.js";
83
100
  import {
84
101
  createFieldCrypto,
85
102
  decodeHexKey,
@@ -228,14 +245,17 @@ export {
228
245
  buildCatalog,
229
246
  buildConsentUrl,
230
247
  buildDelegationMcpServer,
248
+ buildFlowTrace,
231
249
  buildHttpMcpServer,
232
250
  buildKnowledgeRequirements,
233
251
  buildRedactedDocument,
234
252
  buildUserTextParts,
235
253
  checkRateLimit,
254
+ childSpanContext,
236
255
  clearCookieHeader,
237
256
  coalesceDeltas,
238
257
  coerceHarness,
258
+ composeMissionFlowTrace,
239
259
  createAgentRuntime,
240
260
  createAppToolRuntimeExecutor,
241
261
  createBrokerTokenProvider,
@@ -249,6 +269,7 @@ export {
249
269
  createMemoryTurnEventStore,
250
270
  createMissionEngine,
251
271
  createMissionService,
272
+ createMissionTraceContext,
252
273
  createOpenAICompatStreamTurn,
253
274
  createPlatformBalanceManager,
254
275
  createPresetDrizzleSchema,
@@ -266,6 +287,7 @@ export {
266
287
  decryptBytes,
267
288
  decryptWithKey,
268
289
  defineAgentApp,
290
+ delegationActivityToFlowSpans,
269
291
  delegationMcpForConfig,
270
292
  deriveKey,
271
293
  deriveSignals,
@@ -288,6 +310,7 @@ export {
288
310
  isMissionTerminal,
289
311
  isTangleBillingEnforcementDisabled,
290
312
  isTangleExecutionKeyError,
313
+ loopTraceEventsToFlowSpans,
291
314
  maskSpans,
292
315
  mergeMissionState,
293
316
  mergePersistedPart,
@@ -309,6 +332,8 @@ export {
309
332
  readToolArgs,
310
333
  redactForIngestion,
311
334
  reduceMissionEvents,
335
+ renderHistogram,
336
+ renderWaterfall,
312
337
  replayTurnEvents,
313
338
  requireString,
314
339
  resolveChatTurn,
@@ -325,10 +350,15 @@ export {
325
350
  runAppToolLoop,
326
351
  safeParseAssetSpec,
327
352
  serializeCookie,
353
+ stepActivityFlowTrace,
354
+ stepAgentActivity,
328
355
  stepGateProposalId,
329
356
  streamAppToolLoop,
357
+ summarize,
330
358
  tangleExecutionKeyHttpError,
359
+ timedEventsFromLines,
331
360
  toLoopEvents,
361
+ traceEnv,
332
362
  verifyCapabilityToken,
333
363
  verifyCompletion,
334
364
  volumeGateProposalId,
@@ -1,3 +1,6 @@
1
+ import { S as StepAgentActivity } from '../agent-activity-C8ZG0F0M.js';
2
+ export { W as WithAgentActivity, s as stepAgentActivity } from '../agent-activity-C8ZG0F0M.js';
3
+
1
4
  /**
2
5
  * Durable mission state — the guarded status machine for a multi-step agent run.
3
6
  *
@@ -130,7 +133,11 @@ interface MissionAuditEvent {
130
133
  */
131
134
  interface MissionStorePort {
132
135
  load(id: string): Promise<MissionRecord | null>;
133
- insert(record: MissionRecord): Promise<MissionRecord>;
136
+ /** `extras` are the opaque product-column values from
137
+ * `CreateMissionInput.extras` — write them in the SAME statement as the
138
+ * record (single-write creation) or ignore them if the table has no extra
139
+ * columns. */
140
+ insert(record: MissionRecord, extras?: Record<string, unknown>): Promise<MissionRecord>;
134
141
  update(id: string, guard: MissionUpdateGuard, patch: MissionUpdatePatch): Promise<MissionRecord | null>;
135
142
  appendEvent(event: MissionAuditEvent): Promise<void>;
136
143
  }
@@ -160,6 +167,13 @@ interface CreateMissionInput {
160
167
  * model). Read back via `mission.metadata`; the engine only reads
161
168
  * `stopRequested` from it. */
162
169
  metadata?: Record<string, unknown> | null;
170
+ /**
171
+ * Opaque product-column values handed VERBATIM to `MissionStorePort.insert`
172
+ * (e.g. a `workflowId` FK on the product's mission table), so creation is a
173
+ * single write — no post-insert stamp. The service never reads, validates,
174
+ * or persists them itself; they exist only on the insert call.
175
+ */
176
+ extras?: Record<string, unknown>;
163
177
  }
164
178
  interface SetStepStatusPatch {
165
179
  sublabel?: string;
@@ -204,8 +218,14 @@ interface MissionServiceOptions {
204
218
  store: MissionStorePort;
205
219
  /** Injectable clock (epoch ms). Default `Date.now`. */
206
220
  now?: () => number;
207
- /** Row-id generator when `CreateMissionInput.id` is omitted.
208
- * Default `crypto.randomUUID`. */
221
+ /**
222
+ * Row-id generator when `CreateMissionInput.id` is omitted. Default
223
+ * `crypto.randomUUID()` — a 36-char dashed UUID. Inject your own when your
224
+ * mission table already has an id shape (e.g. 32-hex matching D1 row
225
+ * defaults): the service stamps the generated id verbatim onto the inserted
226
+ * record, so a mismatch with the rest of your schema surfaces only at the
227
+ * product layer. Keep id shape parity here, not in the store.
228
+ */
209
229
  generateId?: () => string;
210
230
  }
211
231
  declare function createMissionService(options: MissionServiceOptions): MissionService;
@@ -243,6 +263,7 @@ declare function createInMemoryMissionStore(): InMemoryMissionStore;
243
263
  * idempotent + order-tolerant, so a re-sent or duplicated event converges.
244
264
  * The sink itself does no dedupe.
245
265
  */
266
+
246
267
  interface MissionEventSink {
247
268
  emit(event: MissionStreamEvent): void;
248
269
  }
@@ -291,7 +312,14 @@ type MissionStreamEvent = {
291
312
  missionId: string;
292
313
  at: number;
293
314
  stepId: string;
294
- sublabel: string;
315
+ sublabel?: string;
316
+ /**
317
+ * Full CURRENT snapshot of the step's delegated runs — never a delta.
318
+ * The reducer replaces the whole lane (latest snapshot wins by `at`), so
319
+ * emitters re-send everything they know each time and at-least-once /
320
+ * out-of-order delivery converges.
321
+ */
322
+ agentActivity?: StepAgentActivity[];
295
323
  } | {
296
324
  type: 'step.completed';
297
325
  missionId: string;
@@ -360,6 +388,11 @@ interface MissionStepState {
360
388
  sublabel?: string;
361
389
  reason?: string;
362
390
  durationMs?: number;
391
+ /** Latest delegated-run snapshot for the step (see `step.updated`). */
392
+ agentActivity?: StepAgentActivity[];
393
+ /** The `at` of the snapshot currently held — an older snapshot arriving
394
+ * late never replaces a newer one. */
395
+ agentActivityAt?: number;
363
396
  }
364
397
  /** Live per-mission view the reducer folds events into. */
365
398
  interface MissionState {
@@ -695,4 +728,4 @@ declare function parseMissionBlocks(fullContent: string, options?: ParseMissionB
695
728
  */
696
729
  declare function buildAgentMissionPlan(steps: ParsedMissionStep[]): MissionStep[];
697
730
 
698
- export { type CompleteMissionInput, type CreateMissionInput, DEFAULT_MISSION_STEP_KINDS, type InMemoryMissionStore, MISSION_CONTROL_CHANNEL_ID, type MissionApprovalsPort, type MissionAuditEvent, MissionConcurrencyError, type MissionCostLedger, type MissionEngine, type MissionEngineOptions, type MissionEventSink, type MissionGateKind, type MissionGateOptions, type MissionGateProposal, type MissionOutcome, type MissionPlanRunOptions, type MissionProposalResolution, type MissionRecord, type MissionService, type MissionServiceOptions, type MissionState, type MissionStatus, type MissionStep, type MissionStepState, type MissionStepStatus, type MissionStorePort, type MissionStreamEvent, type MissionStreamStatus, type MissionStreamStep, type MissionStreamStepStatus, type MissionUpdateGuard, type MissionUpdatePatch, type ParseMissionBlocksOptions, type ParsedMission, type ParsedMissionStep, type PlanOutcome, RetryableStepError, type SandboxDispatch, type SandboxDispatchDoneResult, type SandboxDispatchInProgressResult, type SandboxDispatchInput, type SandboxDispatchResult, type SetStepStatusPatch, type StepGateClassification, type StepOutcome, applyMissionEvent, asMissionStreamEvent, budgetGateProposalId, buildAgentMissionPlan, createInMemoryMissionStore, createMissionEngine, createMissionService, isMissionStopRequested, isMissionTerminal, mergeMissionState, noopEventSink, parseMissionBlocks, parseSessionStreamEnvelope, reduceMissionEvents, stepGateProposalId, volumeGateProposalId };
731
+ export { type CompleteMissionInput, type CreateMissionInput, DEFAULT_MISSION_STEP_KINDS, type InMemoryMissionStore, MISSION_CONTROL_CHANNEL_ID, type MissionApprovalsPort, type MissionAuditEvent, MissionConcurrencyError, type MissionCostLedger, type MissionEngine, type MissionEngineOptions, type MissionEventSink, type MissionGateKind, type MissionGateOptions, type MissionGateProposal, type MissionOutcome, type MissionPlanRunOptions, type MissionProposalResolution, type MissionRecord, type MissionService, type MissionServiceOptions, type MissionState, type MissionStatus, type MissionStep, type MissionStepState, type MissionStepStatus, type MissionStorePort, type MissionStreamEvent, type MissionStreamStatus, type MissionStreamStep, type MissionStreamStepStatus, type MissionUpdateGuard, type MissionUpdatePatch, type ParseMissionBlocksOptions, type ParsedMission, type ParsedMissionStep, type PlanOutcome, RetryableStepError, type SandboxDispatch, type SandboxDispatchDoneResult, type SandboxDispatchInProgressResult, type SandboxDispatchInput, type SandboxDispatchResult, type SetStepStatusPatch, StepAgentActivity, type StepGateClassification, type StepOutcome, applyMissionEvent, asMissionStreamEvent, budgetGateProposalId, buildAgentMissionPlan, createInMemoryMissionStore, createMissionEngine, createMissionService, isMissionStopRequested, isMissionTerminal, mergeMissionState, noopEventSink, parseMissionBlocks, parseSessionStreamEnvelope, reduceMissionEvents, stepGateProposalId, volumeGateProposalId };
@@ -17,9 +17,10 @@ import {
17
17
  parseMissionBlocks,
18
18
  parseSessionStreamEnvelope,
19
19
  reduceMissionEvents,
20
+ stepAgentActivity,
20
21
  stepGateProposalId,
21
22
  volumeGateProposalId
22
- } from "../chunk-UIWB2F6N.js";
23
+ } from "../chunk-UDXMR3AD.js";
23
24
  export {
24
25
  DEFAULT_MISSION_STEP_KINDS,
25
26
  MISSION_CONTROL_CHANNEL_ID,
@@ -39,6 +40,7 @@ export {
39
40
  parseMissionBlocks,
40
41
  parseSessionStreamEnvelope,
41
42
  reduceMissionEvents,
43
+ stepAgentActivity,
42
44
  stepGateProposalId,
43
45
  volumeGateProposalId
44
46
  };
@@ -7,8 +7,8 @@ import {
7
7
  createPresetToolHandlers,
8
8
  createPresetWorkspaceKeyManager,
9
9
  createPresetWorkspaceKeyStore
10
- } from "../chunk-EYXTDVDY.js";
11
- import "../chunk-YS6A6G57.js";
10
+ } from "../chunk-SAOAAA3S.js";
11
+ import "../chunk-G3HCU7TA.js";
12
12
  import "../chunk-TA5Q4I2K.js";
13
13
  export {
14
14
  PRESET_MIGRATION_SQL,
@@ -1,3 +1,138 @@
1
+ import { S as StepAgentActivity } from '../agent-activity-C8ZG0F0M.js';
2
+
3
+ /**
4
+ * Mission trace context — mint + thread the trace ids that join a mission's
5
+ * step attempts and its delegated agent runs into ONE trace tree.
6
+ *
7
+ * ID formats are byte-compatible with agent-runtime's trace propagation
8
+ * (`readTraceContextFromEnv` / OTLP export): 32 lowercase hex chars for a
9
+ * trace id (16 bytes), 16 for a span id (8 bytes). The env pair from
10
+ * {@link traceEnv} is exactly what agent-runtime's MCP subprocess reads at
11
+ * startup (`TRACE_ID` + `PARENT_SPAN_ID`), so a delegation dispatched with it
12
+ * parents its loop→round→iteration spans under the mission's step span.
13
+ *
14
+ * Pure functions, no deps. Ids are DETERMINISTIC when a key is supplied
15
+ * (missionId / step-attempt seed) so a crashed driver re-mints the identical
16
+ * context on re-dispatch and the re-run joins the same trace instead of
17
+ * forking a new one; without a key they are random.
18
+ */
19
+ interface MissionTraceContext {
20
+ /** 32-hex trace id shared by every span in the mission's tree. */
21
+ traceId: string;
22
+ /** 16-hex span id of the mission root — the parent of every step span. */
23
+ rootSpanId: string;
24
+ }
25
+ interface StepSpanContext {
26
+ traceId: string;
27
+ /** 16-hex span id of this step attempt (or any nested unit of work). */
28
+ spanId: string;
29
+ /** The span this one nests under. */
30
+ parentSpanId: string;
31
+ }
32
+ /**
33
+ * Mint a mission's trace context. With `missionId` the ids are a pure
34
+ * function of it; omitted, both ids are random.
35
+ */
36
+ declare function createMissionTraceContext(missionId?: string): MissionTraceContext;
37
+ /**
38
+ * Derive a child span context under `parent` — one per step attempt (seed
39
+ * e.g. `"${stepId}#${attempt}"`), or nested under another step span. With a
40
+ * seed the span id is deterministic for the same parent + seed; omitted, it
41
+ * is random.
42
+ */
43
+ declare function childSpanContext(parent: MissionTraceContext | StepSpanContext, seed?: string): StepSpanContext;
44
+ /**
45
+ * The env pair a delegation subprocess inherits — agent-runtime's
46
+ * `readTraceContextFromEnv` reads exactly these names. `PARENT_SPAN_ID` is
47
+ * the span the dispatched work nests under: the root for a mission context,
48
+ * the step-attempt span for a step context.
49
+ */
50
+ declare function traceEnv(ctx: MissionTraceContext | StepSpanContext): {
51
+ TRACE_ID: string;
52
+ PARENT_SPAN_ID: string;
53
+ };
54
+
55
+ /**
56
+ * Delegation → FlowSpan converters — render what a mission's delegated agent
57
+ * runs actually did as ONE FlowTrace, drawable by the existing
58
+ * `renderWaterfall` (or any viewer that consumes FlowSpans).
59
+ *
60
+ * Two fidelities, one tree:
61
+ * - COARSE: `delegationActivityToFlowSpans` draws one 'tool' span per
62
+ * delegation from the StepAgentActivity snapshot (startedAt/durationMs) —
63
+ * available live, from the step's journaled lane.
64
+ * - FINE: `loopTraceEventsToFlowSpans` reconstructs agent-runtime's
65
+ * loop → round → iteration hierarchy from the LoopTraceEvent journal a
66
+ * delegation persists. FlowSpans carry no parent ids, so nesting rides the
67
+ * span NAME (`loop ▸ round 0 ▸ iter 1 (coder)`), matching how the ASCII
68
+ * waterfall reads.
69
+ *
70
+ * `composeMissionFlowTrace` lays a whole mission out: one 'pipeline' span per
71
+ * step, each step's delegations beneath it. Pure data transforms — the
72
+ * structural `LoopTraceEventLike` keeps this module free of the optional
73
+ * agent-runtime peer.
74
+ */
75
+
76
+ /** Structural mirror of agent-runtime's `LoopTraceEvent` — same fields, no
77
+ * import, so journals parsed from JSON feed straight in. */
78
+ interface LoopTraceEventLike {
79
+ kind: string;
80
+ runId: string;
81
+ /** Epoch ms. */
82
+ timestamp: number;
83
+ payload: object;
84
+ }
85
+ /**
86
+ * One 'tool' FlowSpan per delegation, positioned relative to `turnStartMs`
87
+ * (the epoch-ms origin of the trace — usually the step or mission start).
88
+ * A row whose `startedAt` does not parse cannot be placed on a timeline and
89
+ * is omitted from the WATERFALL (it stays in the lane itself). A run without
90
+ * `durationMs` is still in flight: its span extends to `opts.nowMs` when
91
+ * given, else renders as a point — `approx` flags both.
92
+ */
93
+ declare function delegationActivityToFlowSpans(activity: StepAgentActivity[], turnStartMs: number, opts?: {
94
+ nowMs?: number;
95
+ }): FlowSpan[];
96
+ /**
97
+ * Reconstruct one delegation's loop → round → iteration tree from its
98
+ * journaled LoopTraceEvents, as FlowSpans relative to `loop.started` (or the
99
+ * first event). Mirrors agent-runtime's `buildLoopOtelSpans` topology:
100
+ * rounds open on `loop.plan` and flush on the next plan / `loop.decision` /
101
+ * `loop.ended`; iterations span `loop.iteration.started` → `.ended`.
102
+ */
103
+ declare function loopTraceEventsToFlowSpans(events: LoopTraceEventLike[]): FlowSpan[];
104
+ /**
105
+ * A single step's activity lane as its own FlowTrace — what a per-step
106
+ * drill-in renders. Origin defaults to the earliest delegation start so the
107
+ * waterfall begins at the lane's first run.
108
+ */
109
+ declare function stepActivityFlowTrace(activity: StepAgentActivity[], opts?: {
110
+ startedAt?: number;
111
+ nowMs?: number;
112
+ }): FlowTrace;
113
+ interface MissionFlowStep {
114
+ id: string;
115
+ intent: string;
116
+ status?: string;
117
+ /** Epoch ms the step attempt started. Absent → laid out sequentially after
118
+ * the previous step (missions run steps in order), `approx` flagged. */
119
+ startedAt?: number;
120
+ durationMs?: number;
121
+ }
122
+ /**
123
+ * Compose a mission-wide FlowTrace: one 'pipeline' span per step, the step's
124
+ * delegated runs ('tool' spans, from `activity[stepId]`) beneath it. A step
125
+ * span always covers its delegations' extent. Cost is the sum of delegation
126
+ * `costUsd`; token counts are not knowable from the activity lane and stay 0.
127
+ */
128
+ declare function composeMissionFlowTrace(input: {
129
+ steps: MissionFlowStep[];
130
+ /** Delegated-run snapshots keyed by step id (the step's `agentActivity`). */
131
+ activity?: Record<string, StepAgentActivity[]>;
132
+ /** Epoch-ms origin. Default: the earliest known step/delegation start. */
133
+ startedAt?: number;
134
+ }): FlowTrace;
135
+
1
136
  /**
2
137
  * `@tangle-network/agent-app/trace` — flow observability for agent turns.
3
138
  *
@@ -13,6 +148,7 @@
13
148
  * pump's flush window and the reader's poll cadence (~100–400ms); spans
14
149
  * carry `approx: true` to keep reports honest about that.
15
150
  */
151
+
16
152
  interface TimedEvent {
17
153
  /** ms since turn start (`_t` stamped by pumpBufferedTurn). */
18
154
  t: number;
@@ -68,4 +204,4 @@ declare function renderHistogram(values: number[], opts?: {
68
204
  format?: (v: number) => string;
69
205
  }): string;
70
206
 
71
- export { type DistributionSummary, type FlowSpan, type FlowTrace, type TimedEvent, buildFlowTrace, renderHistogram, renderWaterfall, summarize, timedEventsFromLines };
207
+ export { type DistributionSummary, type FlowSpan, type FlowTrace, type LoopTraceEventLike, type MissionFlowStep, type MissionTraceContext, type StepSpanContext, type TimedEvent, buildFlowTrace, childSpanContext, composeMissionFlowTrace, createMissionTraceContext, delegationActivityToFlowSpans, loopTraceEventsToFlowSpans, renderHistogram, renderWaterfall, stepActivityFlowTrace, summarize, timedEventsFromLines, traceEnv };
@@ -1,145 +1,31 @@
1
- // src/trace/index.ts
2
- function timedEventsFromLines(lines) {
3
- const out = [];
4
- for (const line of lines) {
5
- try {
6
- const parsed = JSON.parse(line);
7
- if (typeof parsed._t === "number") out.push({ t: parsed._t, event: parsed });
8
- } catch {
9
- }
10
- }
11
- return out.sort((a, b) => a.t - b.t);
12
- }
13
- function innerOf(e) {
14
- return (e.kind === "event" ? e.event : e) ?? {};
15
- }
16
- function buildFlowTrace(events, opts) {
17
- const spans = [];
18
- let promptTokens = 0;
19
- let completionTokens = 0;
20
- let toolCalls = 0;
21
- const first = events[0]?.t ?? 0;
22
- if (first > 0) {
23
- spans.push({ kind: "pipeline", name: "dispatch \u2192 first event", startMs: 0, endMs: first });
24
- }
25
- let segStart = null;
26
- let segEnd = 0;
27
- let segKinds = /* @__PURE__ */ new Set();
28
- let lastDeltaT = first;
29
- const openCalls = /* @__PURE__ */ new Map();
30
- const closeSegment = () => {
31
- if (segStart !== null) {
32
- spans.push({
33
- kind: "model",
34
- name: segKinds.has("reasoning") ? "model turn (reasoning + text)" : "model turn",
35
- startMs: segStart,
36
- endMs: segEnd,
37
- approx: true
38
- });
39
- segStart = null;
40
- segKinds = /* @__PURE__ */ new Set();
41
- }
42
- };
43
- for (const { t, event } of events) {
44
- const inner = innerOf(event);
45
- const type = String(event.kind === "tool_result" ? "tool_result" : inner.type ?? "");
46
- if (type === "text" || type === "reasoning") {
47
- if (segStart === null) segStart = t;
48
- segEnd = t;
49
- segKinds.add(type);
50
- lastDeltaT = t;
51
- } else if (type === "tool_call") {
52
- closeSegment();
53
- toolCalls++;
54
- const call = inner.call ?? inner;
55
- const id = String(call.toolCallId ?? `call_${toolCalls}`);
56
- openCalls.set(id, { name: String(call.toolName ?? "tool"), emitT: t, lastDeltaT });
57
- } else if (type === "tool_result") {
58
- const id = String(event.toolCallId ?? inner.toolCallId ?? "");
59
- const open = openCalls.get(id);
60
- if (open) {
61
- spans.push({
62
- kind: "tool",
63
- name: open.name,
64
- // Execution happens between the end of the model turn that emitted
65
- // the call and the result landing in the buffer.
66
- startMs: open.lastDeltaT,
67
- endMs: t,
68
- approx: true,
69
- meta: { ok: (event.outcome ?? inner.outcome)?.ok }
70
- });
71
- openCalls.delete(id);
72
- }
73
- } else if (type === "usage") {
74
- const u = inner.usage ?? {};
75
- promptTokens += u.promptTokens ?? 0;
76
- completionTokens += u.completionTokens ?? 0;
77
- }
78
- }
79
- closeSegment();
80
- const totalMs = events.length ? events[events.length - 1].t : 0;
81
- const trace = { spans, totalMs, promptTokens, completionTokens, toolCalls };
82
- const p = opts?.pricing;
83
- if (p && (p.prompt != null || p.completion != null)) {
84
- trace.costUsd = promptTokens * Number(p.prompt ?? 0) + completionTokens * Number(p.completion ?? 0);
85
- }
86
- return trace;
87
- }
88
- var fmtS = (ms) => `${(ms / 1e3).toFixed(1)}s`;
89
- function renderWaterfall(trace, opts) {
90
- const width = opts?.width ?? 40;
91
- const scale = trace.totalMs > 0 ? width / trace.totalMs : 0;
92
- const lines = [];
93
- const spans = [...trace.spans].sort((a, b) => a.startMs - b.startMs);
94
- for (let i = 0; i < spans.length; i++) {
95
- const s = spans[i];
96
- const offset = Math.round(s.startMs * scale);
97
- const len = Math.max(1, Math.round((s.endMs - s.startMs) * scale));
98
- const bar = " ".repeat(offset) + (s.kind === "tool" ? "\u2593" : s.kind === "pipeline" ? "\u2591" : "\u2588").repeat(len);
99
- const branch = i === spans.length - 1 ? "\u2514\u2500" : "\u251C\u2500";
100
- const dur = `${fmtS(s.endMs - s.startMs)}${s.approx ? "~" : ""}`;
101
- lines.push(`${fmtS(s.startMs).padStart(7)} ${branch} ${bar.padEnd(width + 2)} ${s.name} (${dur})`);
102
- }
103
- const cost = trace.costUsd != null ? ` $${trace.costUsd.toFixed(trace.costUsd < 0.01 ? 6 : 4)}` : "";
104
- lines.push(
105
- `${fmtS(trace.totalMs).padStart(7)} \u2500\u2500 total \xB7 ${trace.promptTokens}p + ${trace.completionTokens}c tok \xB7 ${trace.toolCalls} tool calls${cost}`
106
- );
107
- return lines.join("\n");
108
- }
109
- function summarize(values) {
110
- const sorted = [...values].sort((a, b) => a - b);
111
- const q = (p) => sorted[Math.min(sorted.length - 1, Math.floor(p * sorted.length))] ?? 0;
112
- return { n: sorted.length, min: sorted[0] ?? 0, p50: q(0.5), p90: q(0.9), max: sorted[sorted.length - 1] ?? 0 };
113
- }
114
- function renderHistogram(values, opts) {
115
- if (!values.length) return "(no samples)";
116
- const buckets = opts?.buckets ?? 6;
117
- const width = opts?.width ?? 24;
118
- const fmt = opts?.format ?? ((v) => `${Math.round(v)}${opts?.unit ?? ""}`);
119
- const s = summarize(values);
120
- const lo = s.min;
121
- const hi = s.max === s.min ? s.min + 1 : s.max;
122
- const counts = new Array(buckets).fill(0);
123
- for (const v of values) {
124
- counts[Math.min(buckets - 1, Math.floor((v - lo) / (hi - lo) * buckets))]++;
125
- }
126
- const maxCount = Math.max(...counts);
127
- const lines = [
128
- `n=${s.n} min=${fmt(s.min)} p50=${fmt(s.p50)} p90=${fmt(s.p90)} max=${fmt(s.max)}`
129
- ];
130
- for (let i = 0; i < buckets; i++) {
131
- const a = lo + (hi - lo) * i / buckets;
132
- const b = lo + (hi - lo) * (i + 1) / buckets;
133
- const bar = "\u2588".repeat(Math.max(counts[i] > 0 ? 1 : 0, Math.round(counts[i] / maxCount * width)));
134
- lines.push(`${fmt(a).padStart(8)}-${fmt(b).padEnd(8)} ${bar} ${counts[i]}`);
135
- }
136
- return lines.join("\n");
137
- }
1
+ import {
2
+ buildFlowTrace,
3
+ childSpanContext,
4
+ createMissionTraceContext,
5
+ renderHistogram,
6
+ renderWaterfall,
7
+ summarize,
8
+ timedEventsFromLines,
9
+ traceEnv
10
+ } from "../chunk-5RT6KY4G.js";
11
+ import {
12
+ composeMissionFlowTrace,
13
+ delegationActivityToFlowSpans,
14
+ loopTraceEventsToFlowSpans,
15
+ stepActivityFlowTrace
16
+ } from "../chunk-AFDROJ64.js";
138
17
  export {
139
18
  buildFlowTrace,
19
+ childSpanContext,
20
+ composeMissionFlowTrace,
21
+ createMissionTraceContext,
22
+ delegationActivityToFlowSpans,
23
+ loopTraceEventsToFlowSpans,
140
24
  renderHistogram,
141
25
  renderWaterfall,
26
+ stepActivityFlowTrace,
142
27
  summarize,
143
- timedEventsFromLines
28
+ timedEventsFromLines,
29
+ traceEnv
144
30
  };
145
31
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/trace/index.ts"],"sourcesContent":["/**\n * `@tangle-network/agent-app/trace` — flow observability for agent turns.\n *\n * The turn buffer stamps `_t` (ms since turn start) on every event, so any\n * live stream OR any historical turn replayed from a TurnEventStore can be\n * reconstructed into a span trace: pipeline overhead, model segments (with\n * thinking TTFT), tool executions, token usage, and cost. Renderers turn\n * traces and multi-run samples into ASCII waterfalls and histograms — the\n * default artifact for \"how did this run actually behave\" questions across\n * evals, hill-climbs, and production debugging.\n *\n * Span boundaries derived from a buffered stream are quantized by the\n * pump's flush window and the reader's poll cadence (~100–400ms); spans\n * carry `approx: true` to keep reports honest about that.\n */\n\nexport interface TimedEvent {\n /** ms since turn start (`_t` stamped by pumpBufferedTurn). */\n t: number\n event: Record<string, unknown>\n}\n\nexport interface FlowSpan {\n kind: 'pipeline' | 'model' | 'tool'\n name: string\n startMs: number\n endMs: number\n approx?: boolean\n meta?: Record<string, unknown>\n}\n\nexport interface FlowTrace {\n spans: FlowSpan[]\n totalMs: number\n promptTokens: number\n completionTokens: number\n /** Computed when per-token pricing is supplied. */\n costUsd?: number\n toolCalls: number\n}\n\n/** Parse stored turn-event lines (JSON strings with `_t`) into TimedEvents. */\nexport function timedEventsFromLines(lines: string[]): TimedEvent[] {\n const out: TimedEvent[] = []\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>\n if (typeof parsed._t === 'number') out.push({ t: parsed._t, event: parsed })\n } catch {\n /* skip torn lines */\n }\n }\n return out.sort((a, b) => a.t - b.t)\n}\n\nfunction innerOf(e: Record<string, unknown>): Record<string, unknown> {\n return (e.kind === 'event' ? (e.event as Record<string, unknown>) : e) ?? {}\n}\n\n/**\n * Derive a span trace from timestamped turn events. Model segments are runs\n * of text/reasoning deltas; a tool span opens at the last delta before its\n * tool_call emission and closes at the matching tool_result.\n */\nexport function buildFlowTrace(\n events: TimedEvent[],\n opts?: { pricing?: { prompt?: string | number; completion?: string | number } },\n): FlowTrace {\n const spans: FlowSpan[] = []\n let promptTokens = 0\n let completionTokens = 0\n let toolCalls = 0\n\n const first = events[0]?.t ?? 0\n if (first > 0) {\n spans.push({ kind: 'pipeline', name: 'dispatch → first event', startMs: 0, endMs: first })\n }\n\n let segStart: number | null = null\n let segEnd = 0\n let segKinds = new Set<string>()\n let lastDeltaT = first\n const openCalls = new Map<string, { name: string; emitT: number; lastDeltaT: number }>()\n\n const closeSegment = () => {\n if (segStart !== null) {\n spans.push({\n kind: 'model',\n name: segKinds.has('reasoning') ? 'model turn (reasoning + text)' : 'model turn',\n startMs: segStart,\n endMs: segEnd,\n approx: true,\n })\n segStart = null\n segKinds = new Set()\n }\n }\n\n for (const { t, event } of events) {\n const inner = innerOf(event)\n const type = String(event.kind === 'tool_result' ? 'tool_result' : (inner.type ?? ''))\n\n if (type === 'text' || type === 'reasoning') {\n if (segStart === null) segStart = t\n segEnd = t\n segKinds.add(type)\n lastDeltaT = t\n } else if (type === 'tool_call') {\n closeSegment()\n toolCalls++\n const call = (inner.call ?? inner) as Record<string, unknown>\n const id = String(call.toolCallId ?? `call_${toolCalls}`)\n openCalls.set(id, { name: String(call.toolName ?? 'tool'), emitT: t, lastDeltaT })\n } else if (type === 'tool_result') {\n const id = String(event.toolCallId ?? inner.toolCallId ?? '')\n const open = openCalls.get(id)\n if (open) {\n spans.push({\n kind: 'tool',\n name: open.name,\n // Execution happens between the end of the model turn that emitted\n // the call and the result landing in the buffer.\n startMs: open.lastDeltaT,\n endMs: t,\n approx: true,\n meta: { ok: ((event.outcome ?? inner.outcome) as { ok?: boolean } | undefined)?.ok },\n })\n openCalls.delete(id)\n }\n } else if (type === 'usage') {\n const u = (inner.usage ?? {}) as { promptTokens?: number; completionTokens?: number }\n promptTokens += u.promptTokens ?? 0\n completionTokens += u.completionTokens ?? 0\n }\n }\n closeSegment()\n\n const totalMs = events.length ? events[events.length - 1]!.t : 0\n const trace: FlowTrace = { spans, totalMs, promptTokens, completionTokens, toolCalls }\n const p = opts?.pricing\n if (p && (p.prompt != null || p.completion != null)) {\n trace.costUsd = promptTokens * Number(p.prompt ?? 0) + completionTokens * Number(p.completion ?? 0)\n }\n return trace\n}\n\nconst fmtS = (ms: number) => `${(ms / 1000).toFixed(1)}s`\n\n/** ASCII waterfall cascade — the default artifact for explaining a flow. */\nexport function renderWaterfall(trace: FlowTrace, opts?: { width?: number }): string {\n const width = opts?.width ?? 40\n const scale = trace.totalMs > 0 ? width / trace.totalMs : 0\n const lines: string[] = []\n const spans = [...trace.spans].sort((a, b) => a.startMs - b.startMs)\n for (let i = 0; i < spans.length; i++) {\n const s = spans[i]!\n const offset = Math.round(s.startMs * scale)\n const len = Math.max(1, Math.round((s.endMs - s.startMs) * scale))\n const bar = ' '.repeat(offset) + (s.kind === 'tool' ? '▓' : s.kind === 'pipeline' ? '░' : '█').repeat(len)\n const branch = i === spans.length - 1 ? '└─' : '├─'\n const dur = `${fmtS(s.endMs - s.startMs)}${s.approx ? '~' : ''}`\n lines.push(`${fmtS(s.startMs).padStart(7)} ${branch} ${bar.padEnd(width + 2)} ${s.name} (${dur})`)\n }\n const cost = trace.costUsd != null ? ` $${trace.costUsd.toFixed(trace.costUsd < 0.01 ? 6 : 4)}` : ''\n lines.push(\n `${fmtS(trace.totalMs).padStart(7)} ── total · ${trace.promptTokens}p + ${trace.completionTokens}c tok · ${trace.toolCalls} tool calls${cost}`,\n )\n return lines.join('\\n')\n}\n\nexport interface DistributionSummary {\n n: number\n min: number\n p50: number\n p90: number\n max: number\n}\n\nexport function summarize(values: number[]): DistributionSummary {\n const sorted = [...values].sort((a, b) => a - b)\n const q = (p: number) => sorted[Math.min(sorted.length - 1, Math.floor(p * sorted.length))] ?? 0\n return { n: sorted.length, min: sorted[0] ?? 0, p50: q(0.5), p90: q(0.9), max: sorted[sorted.length - 1] ?? 0 }\n}\n\n/** ASCII histogram for multi-run samples (eval latencies, costs, scores). */\nexport function renderHistogram(\n values: number[],\n opts?: { buckets?: number; width?: number; unit?: string; format?: (v: number) => string },\n): string {\n if (!values.length) return '(no samples)'\n const buckets = opts?.buckets ?? 6\n const width = opts?.width ?? 24\n const fmt = opts?.format ?? ((v: number) => `${Math.round(v)}${opts?.unit ?? ''}`)\n const s = summarize(values)\n const lo = s.min\n const hi = s.max === s.min ? s.min + 1 : s.max\n const counts = new Array<number>(buckets).fill(0)\n for (const v of values) {\n counts[Math.min(buckets - 1, Math.floor(((v - lo) / (hi - lo)) * buckets))]!++\n }\n const maxCount = Math.max(...counts)\n const lines = [\n `n=${s.n} min=${fmt(s.min)} p50=${fmt(s.p50)} p90=${fmt(s.p90)} max=${fmt(s.max)}`,\n ]\n for (let i = 0; i < buckets; i++) {\n const a = lo + ((hi - lo) * i) / buckets\n const b = lo + ((hi - lo) * (i + 1)) / buckets\n const bar = '█'.repeat(Math.max(counts[i]! > 0 ? 1 : 0, Math.round((counts[i]! / maxCount) * width)))\n lines.push(`${fmt(a).padStart(8)}-${fmt(b).padEnd(8)} ${bar} ${counts[i]}`)\n }\n return lines.join('\\n')\n}\n"],"mappings":";AA0CO,SAAS,qBAAqB,OAA+B;AAClE,QAAM,MAAoB,CAAC;AAC3B,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,UAAI,OAAO,OAAO,OAAO,SAAU,KAAI,KAAK,EAAE,GAAG,OAAO,IAAI,OAAO,OAAO,CAAC;AAAA,IAC7E,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO,IAAI,KAAK,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;AACrC;AAEA,SAAS,QAAQ,GAAqD;AACpE,UAAQ,EAAE,SAAS,UAAW,EAAE,QAAoC,MAAM,CAAC;AAC7E;AAOO,SAAS,eACd,QACA,MACW;AACX,QAAM,QAAoB,CAAC;AAC3B,MAAI,eAAe;AACnB,MAAI,mBAAmB;AACvB,MAAI,YAAY;AAEhB,QAAM,QAAQ,OAAO,CAAC,GAAG,KAAK;AAC9B,MAAI,QAAQ,GAAG;AACb,UAAM,KAAK,EAAE,MAAM,YAAY,MAAM,+BAA0B,SAAS,GAAG,OAAO,MAAM,CAAC;AAAA,EAC3F;AAEA,MAAI,WAA0B;AAC9B,MAAI,SAAS;AACb,MAAI,WAAW,oBAAI,IAAY;AAC/B,MAAI,aAAa;AACjB,QAAM,YAAY,oBAAI,IAAiE;AAEvF,QAAM,eAAe,MAAM;AACzB,QAAI,aAAa,MAAM;AACrB,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,MAAM,SAAS,IAAI,WAAW,IAAI,kCAAkC;AAAA,QACpE,SAAS;AAAA,QACT,OAAO;AAAA,QACP,QAAQ;AAAA,MACV,CAAC;AACD,iBAAW;AACX,iBAAW,oBAAI,IAAI;AAAA,IACrB;AAAA,EACF;AAEA,aAAW,EAAE,GAAG,MAAM,KAAK,QAAQ;AACjC,UAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAM,OAAO,OAAO,MAAM,SAAS,gBAAgB,gBAAiB,MAAM,QAAQ,EAAG;AAErF,QAAI,SAAS,UAAU,SAAS,aAAa;AAC3C,UAAI,aAAa,KAAM,YAAW;AAClC,eAAS;AACT,eAAS,IAAI,IAAI;AACjB,mBAAa;AAAA,IACf,WAAW,SAAS,aAAa;AAC/B,mBAAa;AACb;AACA,YAAM,OAAQ,MAAM,QAAQ;AAC5B,YAAM,KAAK,OAAO,KAAK,cAAc,QAAQ,SAAS,EAAE;AACxD,gBAAU,IAAI,IAAI,EAAE,MAAM,OAAO,KAAK,YAAY,MAAM,GAAG,OAAO,GAAG,WAAW,CAAC;AAAA,IACnF,WAAW,SAAS,eAAe;AACjC,YAAM,KAAK,OAAO,MAAM,cAAc,MAAM,cAAc,EAAE;AAC5D,YAAM,OAAO,UAAU,IAAI,EAAE;AAC7B,UAAI,MAAM;AACR,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,MAAM,KAAK;AAAA;AAAA;AAAA,UAGX,SAAS,KAAK;AAAA,UACd,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,MAAM,EAAE,KAAM,MAAM,WAAW,MAAM,UAA2C,GAAG;AAAA,QACrF,CAAC;AACD,kBAAU,OAAO,EAAE;AAAA,MACrB;AAAA,IACF,WAAW,SAAS,SAAS;AAC3B,YAAM,IAAK,MAAM,SAAS,CAAC;AAC3B,sBAAgB,EAAE,gBAAgB;AAClC,0BAAoB,EAAE,oBAAoB;AAAA,IAC5C;AAAA,EACF;AACA,eAAa;AAEb,QAAM,UAAU,OAAO,SAAS,OAAO,OAAO,SAAS,CAAC,EAAG,IAAI;AAC/D,QAAM,QAAmB,EAAE,OAAO,SAAS,cAAc,kBAAkB,UAAU;AACrF,QAAM,IAAI,MAAM;AAChB,MAAI,MAAM,EAAE,UAAU,QAAQ,EAAE,cAAc,OAAO;AACnD,UAAM,UAAU,eAAe,OAAO,EAAE,UAAU,CAAC,IAAI,mBAAmB,OAAO,EAAE,cAAc,CAAC;AAAA,EACpG;AACA,SAAO;AACT;AAEA,IAAM,OAAO,CAAC,OAAe,IAAI,KAAK,KAAM,QAAQ,CAAC,CAAC;AAG/C,SAAS,gBAAgB,OAAkB,MAAmC;AACnF,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,QAAQ,MAAM,UAAU,IAAI,QAAQ,MAAM,UAAU;AAC1D,QAAM,QAAkB,CAAC;AACzB,QAAM,QAAQ,CAAC,GAAG,MAAM,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO;AACnE,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,IAAI,MAAM,CAAC;AACjB,UAAM,SAAS,KAAK,MAAM,EAAE,UAAU,KAAK;AAC3C,UAAM,MAAM,KAAK,IAAI,GAAG,KAAK,OAAO,EAAE,QAAQ,EAAE,WAAW,KAAK,CAAC;AACjE,UAAM,MAAM,IAAI,OAAO,MAAM,KAAK,EAAE,SAAS,SAAS,WAAM,EAAE,SAAS,aAAa,WAAM,UAAK,OAAO,GAAG;AACzG,UAAM,SAAS,MAAM,MAAM,SAAS,IAAI,iBAAO;AAC/C,UAAM,MAAM,GAAG,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE;AAC9D,UAAM,KAAK,GAAG,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,IAAI,MAAM,IAAI,IAAI,OAAO,QAAQ,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,GAAG,GAAG;AAAA,EACnG;AACA,QAAM,OAAO,MAAM,WAAW,OAAO,MAAM,MAAM,QAAQ,QAAQ,MAAM,UAAU,OAAO,IAAI,CAAC,CAAC,KAAK;AACnG,QAAM;AAAA,IACJ,GAAG,KAAK,MAAM,OAAO,EAAE,SAAS,CAAC,CAAC,4BAAe,MAAM,YAAY,OAAO,MAAM,gBAAgB,cAAW,MAAM,SAAS,cAAc,IAAI;AAAA,EAC9I;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAUO,SAAS,UAAU,QAAuC;AAC/D,QAAM,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAC/C,QAAM,IAAI,CAAC,MAAc,OAAO,KAAK,IAAI,OAAO,SAAS,GAAG,KAAK,MAAM,IAAI,OAAO,MAAM,CAAC,CAAC,KAAK;AAC/F,SAAO,EAAE,GAAG,OAAO,QAAQ,KAAK,OAAO,CAAC,KAAK,GAAG,KAAK,EAAE,GAAG,GAAG,KAAK,EAAE,GAAG,GAAG,KAAK,OAAO,OAAO,SAAS,CAAC,KAAK,EAAE;AAChH;AAGO,SAAS,gBACd,QACA,MACQ;AACR,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,UAAU,MAAM,WAAW;AACjC,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,MAAM,MAAM,WAAW,CAAC,MAAc,GAAG,KAAK,MAAM,CAAC,CAAC,GAAG,MAAM,QAAQ,EAAE;AAC/E,QAAM,IAAI,UAAU,MAAM;AAC1B,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE;AAC3C,QAAM,SAAS,IAAI,MAAc,OAAO,EAAE,KAAK,CAAC;AAChD,aAAW,KAAK,QAAQ;AACtB,WAAO,KAAK,IAAI,UAAU,GAAG,KAAK,OAAQ,IAAI,OAAO,KAAK,MAAO,OAAO,CAAC,CAAC;AAAA,EAC5E;AACA,QAAM,WAAW,KAAK,IAAI,GAAG,MAAM;AACnC,QAAM,QAAQ;AAAA,IACZ,KAAK,EAAE,CAAC,SAAS,IAAI,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE,GAAG,CAAC;AAAA,EACtF;AACA,WAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,UAAM,IAAI,MAAO,KAAK,MAAM,IAAK;AACjC,UAAM,IAAI,MAAO,KAAK,OAAO,IAAI,KAAM;AACvC,UAAM,MAAM,SAAI,OAAO,KAAK,IAAI,OAAO,CAAC,IAAK,IAAI,IAAI,GAAG,KAAK,MAAO,OAAO,CAAC,IAAK,WAAY,KAAK,CAAC,CAAC;AACpG,UAAM,KAAK,GAAG,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE;AAAA,EAC5E;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}