@botpress/evals 1.19.0-beta.14 → 1.19.0-beta.16
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/client.d.ts +9 -9
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +74 -20
- package/dist/client.js.map +4 -4
- package/dist/definition.d.ts +2 -3
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js.map +2 -2
- package/dist/graders/index.js +74 -21
- package/dist/graders/index.js.map +2 -2
- package/dist/graders/llm.d.ts +12 -12
- package/dist/graders/llm.d.ts.map +1 -1
- package/dist/graders/llm.js +75 -30
- package/dist/graders/llm.js.map +2 -2
- package/dist/graders/response.js +65 -16
- package/dist/graders/response.js.map +2 -2
- package/dist/index.d.ts +1 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -10
- package/dist/index.js.map +3 -3
- package/dist/loader.js +39 -1
- package/dist/loader.js.map +3 -3
- package/dist/runner.d.ts +1 -5
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +217 -141
- package/dist/runner.js.map +4 -4
- package/dist/{spans/sse-collector.d.ts → sse-collector.d.ts} +4 -6
- package/dist/sse-collector.d.ts.map +1 -0
- package/dist/{spans/sse-collector.js → sse-collector.js} +49 -17
- package/dist/sse-collector.js.map +7 -0
- package/dist/trace.d.ts.map +1 -0
- package/dist/transformer.d.ts +2 -2
- package/dist/transformer.d.ts.map +1 -1
- package/dist/transformer.js +1 -1
- package/dist/transformer.js.map +2 -2
- package/dist/types.d.ts +33 -38
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +2 -2
- package/package.json +6 -66
- package/dist/manifest.d.ts +0 -13
- package/dist/manifest.d.ts.map +0 -1
- package/dist/spans/index.d.ts +0 -5
- package/dist/spans/index.d.ts.map +0 -1
- package/dist/spans/index.js +0 -642
- package/dist/spans/index.js.map +0 -7
- package/dist/spans/local-span-source.d.ts +0 -16
- package/dist/spans/local-span-source.d.ts.map +0 -1
- package/dist/spans/local-span-source.js +0 -478
- package/dist/spans/local-span-source.js.map +0 -7
- package/dist/spans/span-source.d.ts +0 -20
- package/dist/spans/span-source.d.ts.map +0 -1
- package/dist/spans/span-source.js +0 -1
- package/dist/spans/span-source.js.map +0 -7
- package/dist/spans/sse-collector.d.ts.map +0 -1
- package/dist/spans/sse-collector.js.map +0 -7
- package/dist/spans/trace.d.ts.map +0 -1
- package/dist/spans/vortex-span-source.d.ts +0 -34
- package/dist/spans/vortex-span-source.d.ts.map +0 -1
- package/dist/spans/vortex-span-source.js +0 -166
- package/dist/spans/vortex-span-source.js.map +0 -7
- package/dist/stores/eval-definition-loader.d.ts +0 -4
- package/dist/stores/eval-definition-loader.d.ts.map +0 -1
- package/dist/stores/eval-definition-loader.js +0 -104
- package/dist/stores/eval-definition-loader.js.map +0 -7
- package/dist/stores/eval-store.d.ts +0 -61
- package/dist/stores/eval-store.d.ts.map +0 -1
- package/dist/stores/eval-store.js +0 -1
- package/dist/stores/eval-store.js.map +0 -7
- package/dist/stores/index.d.ts +0 -8
- package/dist/stores/index.d.ts.map +0 -1
- package/dist/stores/index.js +0 -1118
- package/dist/stores/index.js.map +0 -7
- package/dist/stores/local-eval-store.d.ts +0 -66
- package/dist/stores/local-eval-store.d.ts.map +0 -1
- package/dist/stores/local-eval-store.js +0 -557
- package/dist/stores/local-eval-store.js.map +0 -7
- package/dist/stores/vortex-eval-store-entry.d.ts +0 -6
- package/dist/stores/vortex-eval-store-entry.d.ts.map +0 -1
- package/dist/stores/vortex-eval-store-entry.js +0 -664
- package/dist/stores/vortex-eval-store-entry.js.map +0 -7
- package/dist/stores/vortex-eval-store.d.ts +0 -78
- package/dist/stores/vortex-eval-store.d.ts.map +0 -1
- package/dist/stores/vortex-eval-store.js +0 -562
- package/dist/stores/vortex-eval-store.js.map +0 -7
- /package/dist/{spans/trace.d.ts → trace.d.ts} +0 -0
- /package/dist/{spans/trace.js → trace.js} +0 -0
- /package/dist/{spans/trace.js.map → trace.js.map} +0 -0
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/errors.ts", "../../src/spans/sse-collector.ts", "../../src/spans/local-span-source.ts"],
|
|
4
|
-
"sourcesContent": ["import { AdkError } from '@botpress/analytics'\n\n/**\n * Stable error codes for the eval engine. Typed as a literal union so a typo'd\n * code is a compile error and PostHog issue-slicing stays consistent.\n * Conventions per docs/ERROR-HANDLING.md.\n */\nexport const EVAL_ERROR_CODES = [\n 'EVAL_LOAD_FAILED',\n 'EVAL_FILE_EMPTY',\n 'EVAL_DUPLICATE_NAME',\n 'EVAL_SEED_NO_CONVERSATION',\n 'EVAL_NO_CONVERSATION_ID',\n 'EVAL_TURN_CONFIG_INVALID',\n 'SSE_CONNECT_FAILED',\n 'SSE_NO_BODY',\n 'CHAT_CLIENT_MISSING',\n 'CHAT_NOT_CONNECTED',\n 'CHAT_INTEGRATION_MISSING',\n 'CHAT_CHANNEL_UNBOUND',\n] as const\n\nexport type EvalErrorCode = (typeof EVAL_ERROR_CODES)[number]\n\n/**\n * Typed error for the eval engine. Named EvalRunnerError (not EvalError) to\n * avoid shadowing the JS built-in `EvalError`.\n */\nexport class EvalRunnerError extends AdkError<EvalErrorCode> {}\n", "/**\n * SSECollector \u2014 connects to the ADK dev server's SSE trace stream,\n * accumulates spans, and provides promise-based wait methods for\n * turn completion and workflow signals.\n *\n * Uses fetch() + async iteration with manual SSE line parsing\n * (Bun does not have native EventSource).\n */\n\nimport type { Span } from './trace'\nimport { EvalRunnerError } from '../errors'\n\ntype SSEFilter = { conversationId: string } | { workflowId: string }\n\ninterface WaitOptions {\n timeout: number\n /**\n * Optional abort signal \u2014 when fired, the wait rejects immediately rather\n * than burning the full timeout. Used by the runner so Stop unblocks\n * pending workflow assertions (otherwise a single negative-result wait\n * can hold the suite hostage for `idleTimeout` per assertion).\n */\n abortSignal?: AbortSignal\n}\n\ninterface WorkflowWaitOptions extends WaitOptions {\n signal: 'entered' | 'completed'\n}\n\n/**\n * Unique key for span deduplication.\n */\nfunction spanKey(span: Span): string {\n return `${span.id.trace}:${span.id.span}`\n}\n\n/**\n * Type-safe accessor for span.data fields.\n */\nfunction spanData(span: Span): Record<string, unknown> {\n return span.data && typeof span.data === 'object' ? (span.data as Record<string, unknown>) : {}\n}\n\n/**\n * Span names that mark a Conversation handler reaching the end of a turn.\n *\n * A turn driven by a user message emits `handler.conversation`; a turn driven\n * by an event (a Conversation's `events:` subscription \u2014 e.g. greeting on a\n * conversation-start signal) emits `handler.event`. Both close exactly once\n * per handler invocation, so either is a valid \"turn complete\" signal.\n */\nconst TURN_HANDLER_SPAN_NAMES = new Set(['handler.conversation', 'handler.event'])\n\nfunction isTurnHandlerSpan(span: Span): boolean {\n return TURN_HANDLER_SPAN_NAMES.has(span.name)\n}\n\nexport class SSECollector {\n private devServerUrl: string\n private headers: Record<string, string>\n\n /** All spans accumulated since connect(), keyed by spanKey for dedup. */\n private spanMap = new Map<string, Span>()\n\n /** Index into spanMap insertion order marking where the current turn started. */\n private turnStartKeys = new Set<string>()\n\n /** Handler span IDs seen before the current turn (for startTurn filtering). */\n private seenHandlerKeys = new Set<string>()\n\n /** Callbacks waiting for span updates. */\n private waiters: Array<(span: Span) => void> = []\n\n /** AbortController for the active SSE connection. */\n private abortController: AbortController | null = null\n\n /** Whether the background loop is running. */\n private connected = false\n\n /** Error from the SSE stream if it died unexpectedly. */\n private streamError: Error | null = null\n\n /** Passive counters used only to explain timeout failures. */\n private updateEventCount = 0\n private keepaliveEventCount = 0\n private lastEvent: { name: string; at: number } | null = null\n\n /** Set while a settle phase is in flight; called by disconnect() to short-circuit. */\n private _cancelSettle: (() => void) | null = null\n\n constructor(devServerUrl: string, headers: Record<string, string> = {}) {\n this.devServerUrl = devServerUrl\n this.headers = headers\n }\n\n /**\n * Open a streaming SSE connection filtered by conversationId or workflowId.\n * Starts a background loop that parses SSE events and accumulates spans.\n */\n async connect(filter: SSEFilter): Promise<void> {\n const attributeName = 'conversationId' in filter ? 'conversationId' : 'workflowId'\n const attributeValue = 'conversationId' in filter ? filter.conversationId : filter.workflowId\n\n const url = `${this.devServerUrl}/api/traces/stream?attributeName=${encodeURIComponent(attributeName)}&attributeValue=${encodeURIComponent(attributeValue)}`\n\n this.abortController = new AbortController()\n\n const response = await fetch(url, {\n headers: { ...this.headers, Accept: 'text/event-stream' },\n signal: this.abortController.signal,\n })\n\n if (!response.ok) {\n throw new EvalRunnerError({\n code: 'SSE_CONNECT_FAILED',\n message: `SSE connection failed: ${response.status} ${response.statusText}`,\n expected: true,\n suggestion: 'Make sure the dev server is running (`adk dev`) and reachable.',\n })\n }\n\n if (!response.body) {\n throw new EvalRunnerError({ code: 'SSE_NO_BODY', message: 'SSE response has no body' })\n }\n\n this.connected = true\n\n // Start background parsing loop\n this._consumeStream(response.body).catch((err) => {\n if (this.connected) {\n this.streamError = err instanceof Error ? err : new Error(String(err))\n }\n })\n\n // Wait for the initial snapshot to arrive before returning.\n // This ensures that connect() resolves only after the snapshot\n // has been processed so callers can immediately check spans.\n await this._waitForSnapshot()\n }\n\n /**\n * Mark the beginning of a new turn.\n * Records which turn-handler span IDs (handler.conversation / handler.event)\n * have been seen so far, so waitForTurnComplete() only resolves on NEW\n * handler completions.\n */\n startTurn(): void {\n // Snapshot the current set of span keys as the turn boundary\n this.turnStartKeys = new Set(this.spanMap.keys())\n\n // Record all turn-handler spans seen so far\n for (const [key, span] of this.spanMap) {\n if (isTurnHandlerSpan(span)) {\n this.seenHandlerKeys.add(key)\n }\n }\n }\n\n private static readonly SETTLE_MS = 100\n\n /**\n * Wait for a turn-handler span (handler.conversation or handler.event) to\n * reach terminal status (ok or error).\n * Only considers spans NOT seen before the last startTurn() call.\n *\n * After the handler closes, waits for a quiet period (no new spans for SETTLE_MS)\n * to ensure all child spans (tool calls, messages, state saves) have arrived.\n * The runtime's HttpSpanExporter fires POSTs without awaiting them, so child\n * spans may arrive slightly after the handler close event.\n */\n async waitForTurnComplete(opts: WaitOptions): Promise<void> {\n // Check if a completed handler already exists (e.g. from snapshot)\n if (this._hasNewCompletedHandler()) {\n return this._settleAfterHandler()\n }\n if (opts.abortSignal?.aborted) {\n throw new Error('waitForTurnComplete aborted')\n }\n\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n this._removeWaiter(waiter)\n opts.abortSignal?.removeEventListener('abort', onAbort)\n const reason = this.streamError\n ? `SSE stream died: ${this.streamError.message}`\n : 'no handler.conversation or handler.event span completed'\n reject(\n new Error(\n `waitForTurnComplete timed out after ${opts.timeout}ms \u2014 ${reason}; diagnostics: ${this._formatTurnDiagnostics()}`\n )\n )\n }, opts.timeout)\n\n const onAbort = () => {\n clearTimeout(timer)\n this._removeWaiter(waiter)\n reject(new Error('waitForTurnComplete aborted'))\n }\n opts.abortSignal?.addEventListener('abort', onAbort, { once: true })\n\n const waiter = (_span: Span) => {\n if (this._hasNewCompletedHandler()) {\n clearTimeout(timer)\n this._removeWaiter(waiter)\n opts.abortSignal?.removeEventListener('abort', onAbort)\n this._settleAfterHandler().then(resolve, reject)\n }\n }\n\n this.waiters.push(waiter)\n })\n }\n\n private static readonly MAX_SETTLE_MS = 2_000\n\n /**\n * After the handler span closes, wait for spans to stop arriving.\n * Resolves when no new spans arrive for SETTLE_MS, or after MAX_SETTLE_MS hard cap.\n *\n * Exposes a cancellation hook via _cancelSettle so disconnect() can short-\n * circuit an in-flight settle phase and avoid leaking timers for up to 2s.\n */\n private _settleAfterHandler(): Promise<void> {\n return new Promise<void>((resolve) => {\n let resolved = false\n const done = () => {\n if (resolved) return\n resolved = true\n clearTimeout(hardCap)\n clearTimeout(settleTimer)\n this._removeWaiter(settleWaiter)\n this._cancelSettle = null\n resolve()\n }\n\n const hardCap = setTimeout(done, SSECollector.MAX_SETTLE_MS)\n\n let settleTimer = setTimeout(done, SSECollector.SETTLE_MS)\n\n const settleWaiter = () => {\n if (resolved) return\n clearTimeout(settleTimer)\n settleTimer = setTimeout(done, SSECollector.SETTLE_MS)\n }\n\n this.waiters.push(settleWaiter)\n this._cancelSettle = done\n })\n }\n\n /**\n * Wait for a handler.workflow span with matching workflow name.\n * - signal 'entered': resolves when the span appears (any status)\n * - signal 'completed': resolves when the span has status !== 'running'\n */\n async waitForWorkflow(name: string, opts: WorkflowWaitOptions): Promise<void> {\n // Check if condition is already met\n if (this._matchesWorkflowCondition(name, opts.signal)) {\n return\n }\n if (opts.abortSignal?.aborted) {\n throw new Error(`waitForWorkflow(\"${name}\", { signal: \"${opts.signal}\" }) aborted`)\n }\n\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n this._removeWaiter(waiter)\n opts.abortSignal?.removeEventListener('abort', onAbort)\n const reason = this.streamError ? `SSE stream died: ${this.streamError.message}` : 'span not found'\n reject(\n new Error(\n `waitForWorkflow(\"${name}\", { signal: \"${opts.signal}\" }) timed out after ${opts.timeout}ms \u2014 ${reason}`\n )\n )\n }, opts.timeout)\n\n const onAbort = () => {\n clearTimeout(timer)\n this._removeWaiter(waiter)\n reject(new Error(`waitForWorkflow(\"${name}\", { signal: \"${opts.signal}\" }) aborted`))\n }\n opts.abortSignal?.addEventListener('abort', onAbort, { once: true })\n\n const waiter = (_span: Span) => {\n if (this._matchesWorkflowCondition(name, opts.signal)) {\n clearTimeout(timer)\n this._removeWaiter(waiter)\n opts.abortSignal?.removeEventListener('abort', onAbort)\n resolve()\n }\n }\n\n this.waiters.push(waiter)\n })\n }\n\n /**\n * Return spans accumulated since the last startTurn() call.\n */\n getTurnSpans(): Span[] {\n const result: Span[] = []\n for (const [key, span] of this.spanMap) {\n if (!this.turnStartKeys.has(key)) {\n result.push(span)\n }\n }\n return result\n }\n\n /**\n * Return all spans accumulated since connect().\n */\n getAllSpans(): Span[] {\n return Array.from(this.spanMap.values())\n }\n\n /**\n * Close the SSE connection and clean up.\n */\n disconnect(): void {\n this.connected = false\n this.abortController?.abort()\n this.abortController = null\n // Short-circuit an in-flight settle phase so its hardCap / settleTimer\n // don't fire after disconnect.\n this._cancelSettle?.()\n this._cancelSettle = null\n // Waiters hold setTimeout references that will reject on their own;\n // clearing the array just prevents further notifications.\n this.waiters = []\n this.snapshotResolvers = []\n }\n\n // \u2500\u2500 Private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /** Whether we have received the initial snapshot. */\n private snapshotReceived = false\n private snapshotResolvers: Array<() => void> = []\n\n private static readonly SNAPSHOT_TIMEOUT_MS = 10_000\n\n /**\n * Returns a promise that resolves once the snapshot event has been processed,\n * or rejects after a timeout to prevent connect() from hanging indefinitely.\n */\n private _waitForSnapshot(): Promise<void> {\n if (this.snapshotReceived) {\n return Promise.resolve()\n }\n return new Promise<void>((resolve, reject) => {\n let settled = false\n const resolver = () => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n resolve()\n }\n const timer = setTimeout(() => {\n if (settled) return\n settled = true\n const idx = this.snapshotResolvers.indexOf(resolver)\n if (idx !== -1) this.snapshotResolvers.splice(idx, 1)\n reject(\n new Error(\n `SSE snapshot not received within ${SSECollector.SNAPSHOT_TIMEOUT_MS}ms \u2014 is the dev server healthy?`\n )\n )\n }, SSECollector.SNAPSHOT_TIMEOUT_MS)\n this.snapshotResolvers.push(resolver)\n })\n }\n\n /**\n * Consume the ReadableStream body, parse SSE lines, and dispatch events.\n */\n private async _consumeStream(body: ReadableStream<Uint8Array>): Promise<void> {\n const decoder = new TextDecoder()\n let buffer = ''\n\n const reader = body.getReader()\n\n try {\n while (this.connected) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n\n // Split on double-newline boundaries to get complete SSE events\n const parts = buffer.split('\\n\\n')\n // The last part may be incomplete \u2014 keep it in the buffer\n buffer = parts.pop() ?? ''\n\n for (const part of parts) {\n this._parseSSEBlock(part)\n }\n }\n } finally {\n reader.releaseLock()\n }\n }\n\n /**\n * Parse a single SSE event block (text between \\n\\n boundaries).\n * Extracts event name and data payload.\n */\n private _parseSSEBlock(block: string): void {\n const lines = block.split('\\n')\n let eventName = ''\n let dataLine = ''\n\n for (const line of lines) {\n if (line.startsWith('event:')) {\n eventName = line.slice('event:'.length).trim()\n } else if (line.startsWith('data:')) {\n const value = line.slice('data:'.length).trim()\n dataLine = dataLine ? `${dataLine}\\n${value}` : value\n }\n // id: and retry: lines are ignored\n }\n\n if (!eventName || !dataLine) {\n // Could be a retry: line or empty block \u2014 skip\n if (!this.snapshotReceived && block.includes('retry:')) {\n // The retry line comes before the snapshot; don't resolve yet\n }\n return\n }\n\n try {\n const payload = JSON.parse(dataLine)\n this._handleEvent(eventName, payload)\n } catch {\n // Malformed JSON \u2014 skip\n }\n }\n\n /**\n * Dispatch a parsed SSE event to the appropriate handler.\n */\n private _handleEvent(eventName: string, payload: unknown): void {\n this._recordEvent(eventName)\n\n if (eventName === 'snapshot') {\n const data = payload as { spans: Span[] }\n const spans = Array.isArray(data.spans) ? data.spans : []\n for (const span of spans) {\n this._upsertSpan(span)\n }\n this.snapshotReceived = true\n for (const resolve of this.snapshotResolvers) {\n resolve()\n }\n this.snapshotResolvers = []\n } else if (eventName === 'update') {\n const data = payload as { span: Span }\n if (data.span) {\n this._upsertSpan(data.span)\n this._notifyWaiters(data.span)\n }\n }\n // keepalive events are intentionally ignored\n }\n\n private _recordEvent(eventName: string): void {\n this.lastEvent = { name: eventName, at: Date.now() }\n\n if (eventName === 'update') {\n this.updateEventCount++\n } else if (eventName === 'keepalive') {\n this.keepaliveEventCount++\n }\n }\n\n private _formatTurnDiagnostics(): string {\n const turnSpans = this.getTurnSpans()\n const spanNames = new Set<string>()\n const handlerStatuses = new Set<string>()\n\n for (const span of turnSpans) {\n spanNames.add(span.name)\n // Tracks both handler.conversation and handler.event so an event-driven\n // turn that times out still surfaces its handler status.\n if (isTurnHandlerSpan(span)) {\n handlerStatuses.add(span.status)\n }\n }\n\n const lastEvent = this.lastEvent ? `${this.lastEvent.name} ${Date.now() - this.lastEvent.at}ms ago` : 'none'\n\n return [\n `snapshotReceived=${this.snapshotReceived}`,\n `totalUpdates=${this.updateEventCount}`,\n `totalKeepalives=${this.keepaliveEventCount}`,\n `lastEvent=${lastEvent}`,\n `totalSpans=${this.spanMap.size}`,\n `turnSpans=${turnSpans.length}`,\n `turnSpanNames=${this._formatSet(spanNames)}`,\n `turnHandlerStatuses=${this._formatSet(handlerStatuses)}`,\n ].join(', ')\n }\n\n private _formatSet(values: Set<string>, limit = 12): string {\n if (values.size === 0) {\n return 'none'\n }\n\n const items = Array.from(values)\n const suffix = items.length > limit ? `|+${items.length - limit} more` : ''\n return `${items.slice(0, limit).join('|')}${suffix}`\n }\n\n /**\n * Insert or replace a span in the map (dedup by trace+span ID).\n */\n private _upsertSpan(span: Span): void {\n this.spanMap.set(spanKey(span), span)\n }\n\n /**\n * Notify all waiters that a new span was received.\n */\n private _notifyWaiters(span: Span): void {\n // Copy the array since waiters may remove themselves during iteration\n const current = [...this.waiters]\n for (const waiter of current) {\n waiter(span)\n }\n }\n\n /**\n * Remove a waiter callback from the list.\n */\n private _removeWaiter(fn: (span: Span) => void): void {\n const idx = this.waiters.indexOf(fn)\n if (idx !== -1) {\n this.waiters.splice(idx, 1)\n }\n }\n\n /**\n * Check if there is a turn-handler span (handler.conversation / handler.event) that:\n * 1. Was NOT seen before startTurn()\n * 2. Has terminal status (ok or error)\n *\n * Marks the matched key as consumed so the same handler span cannot\n * satisfy both the current turn's settle phase AND the next turn's\n * waitForTurnComplete check (which would otherwise resolve instantly\n * against stale data instead of waiting for the new turn's handler).\n */\n private _hasNewCompletedHandler(): boolean {\n for (const [key, span] of this.spanMap) {\n if (\n isTurnHandlerSpan(span) &&\n !this.seenHandlerKeys.has(key) &&\n (span.status === 'ok' || span.status === 'error')\n ) {\n this.seenHandlerKeys.add(key)\n return true\n }\n }\n return false\n }\n\n /**\n * Check if a handler.workflow span matches the given condition.\n */\n private _matchesWorkflowCondition(name: string, signal: 'entered' | 'completed'): boolean {\n for (const span of this.spanMap.values()) {\n if (span.name !== 'handler.workflow') continue\n\n const d = spanData(span)\n const wfName = d['workflow.name'] || d['workflowName']\n if (wfName !== name) continue\n\n if (signal === 'entered') {\n // Any status means the workflow was entered\n return true\n }\n\n if (signal === 'completed') {\n return span.status === 'ok' || span.status === 'error'\n }\n }\n return false\n }\n}\n", "import type { SpanSource, WaitOptions, WorkflowWaitOptions } from './span-source'\nimport type { Span } from './trace'\nimport { SSECollector } from './sse-collector'\n\nexport class LocalSpanSource implements SpanSource {\n private collector: SSECollector\n\n constructor(devServerUrl: string, headers: Record<string, string> = {}) {\n this.collector = new SSECollector(devServerUrl, headers)\n }\n\n async connect(filter: { conversationId: string }): Promise<void> {\n await this.collector.connect(filter)\n }\n\n startTurn(): void {\n this.collector.startTurn()\n }\n\n async waitForTurnComplete(opts: WaitOptions): Promise<void> {\n await this.collector.waitForTurnComplete(opts)\n }\n\n async waitForWorkflow(name: string, opts: WorkflowWaitOptions): Promise<void> {\n await this.collector.waitForWorkflow(name, opts)\n }\n\n getTurnSpans(): Span[] {\n return this.collector.getTurnSpans()\n }\n\n getAllSpans(): Span[] {\n return this.collector.getAllSpans()\n }\n\n disconnect(): void {\n this.collector.disconnect()\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { Span } from './trace';
|
|
2
|
-
export interface WaitOptions {
|
|
3
|
-
timeout: number;
|
|
4
|
-
abortSignal?: AbortSignal;
|
|
5
|
-
}
|
|
6
|
-
export interface WorkflowWaitOptions extends WaitOptions {
|
|
7
|
-
signal: 'entered' | 'completed';
|
|
8
|
-
}
|
|
9
|
-
export interface SpanSource {
|
|
10
|
-
connect(filter: {
|
|
11
|
-
conversationId: string;
|
|
12
|
-
}): Promise<void>;
|
|
13
|
-
startTurn(): void;
|
|
14
|
-
waitForTurnComplete(opts: WaitOptions): Promise<void>;
|
|
15
|
-
waitForWorkflow(name: string, opts: WorkflowWaitOptions): Promise<void>;
|
|
16
|
-
getTurnSpans(): Span[];
|
|
17
|
-
getAllSpans(): Span[];
|
|
18
|
-
disconnect(): void;
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=span-source.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"span-source.d.ts","sourceRoot":"","sources":["../../src/spans/span-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAEnC,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,MAAM,EAAE,SAAS,GAAG,WAAW,CAAA;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,MAAM,EAAE;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D,SAAS,IAAI,IAAI,CAAA;IACjB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACrD,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvE,YAAY,IAAI,IAAI,EAAE,CAAA;IACtB,WAAW,IAAI,IAAI,EAAE,CAAA;IACrB,UAAU,IAAI,IAAI,CAAA;CACnB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=span-source.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sse-collector.d.ts","sourceRoot":"","sources":["../../src/spans/sse-collector.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAGnC,KAAK,SAAS,GAAG;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpE,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAA;IACf;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED,UAAU,mBAAoB,SAAQ,WAAW;IAC/C,MAAM,EAAE,SAAS,GAAG,WAAW,CAAA;CAChC;AA8BD,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,OAAO,CAAwB;IAEvC,yEAAyE;IACzE,OAAO,CAAC,OAAO,CAA0B;IAEzC,iFAAiF;IACjF,OAAO,CAAC,aAAa,CAAoB;IAEzC,+EAA+E;IAC/E,OAAO,CAAC,eAAe,CAAoB;IAE3C,0CAA0C;IAC1C,OAAO,CAAC,OAAO,CAAkC;IAEjD,qDAAqD;IACrD,OAAO,CAAC,eAAe,CAA+B;IAEtD,8CAA8C;IAC9C,OAAO,CAAC,SAAS,CAAQ;IAEzB,yDAAyD;IACzD,OAAO,CAAC,WAAW,CAAqB;IAExC,8DAA8D;IAC9D,OAAO,CAAC,gBAAgB,CAAI;IAC5B,OAAO,CAAC,mBAAmB,CAAI;IAC/B,OAAO,CAAC,SAAS,CAA4C;IAE7D,sFAAsF;IACtF,OAAO,CAAC,aAAa,CAA4B;gBAErC,YAAY,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;IAKtE;;;OAGG;IACG,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAyC/C;;;;;OAKG;IACH,SAAS,IAAI,IAAI;IAYjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAM;IAEvC;;;;;;;;;OASG;IACG,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA2C3D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAQ;IAE7C;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;;;OAIG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAyC7E;;OAEG;IACH,YAAY,IAAI,IAAI,EAAE;IAUtB;;OAEG;IACH,WAAW,IAAI,IAAI,EAAE;IAIrB;;OAEG;IACH,UAAU,IAAI,IAAI;IAgBlB,qDAAqD;IACrD,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,iBAAiB,CAAwB;IAEjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAEpD;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;OAEG;YACW,cAAc;IA2B5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IA+BtB;;OAEG;IACH,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,sBAAsB;IA4B9B,OAAO,CAAC,UAAU;IAUlB;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;OAEG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;;;;;OASG;IACH,OAAO,CAAC,uBAAuB;IAc/B;;OAEG;IACH,OAAO,CAAC,yBAAyB;CAmBlC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/errors.ts", "../../src/spans/sse-collector.ts"],
|
|
4
|
-
"sourcesContent": ["import { AdkError } from '@botpress/analytics'\n\n/**\n * Stable error codes for the eval engine. Typed as a literal union so a typo'd\n * code is a compile error and PostHog issue-slicing stays consistent.\n * Conventions per docs/ERROR-HANDLING.md.\n */\nexport const EVAL_ERROR_CODES = [\n 'EVAL_LOAD_FAILED',\n 'EVAL_FILE_EMPTY',\n 'EVAL_DUPLICATE_NAME',\n 'EVAL_SEED_NO_CONVERSATION',\n 'EVAL_NO_CONVERSATION_ID',\n 'EVAL_TURN_CONFIG_INVALID',\n 'SSE_CONNECT_FAILED',\n 'SSE_NO_BODY',\n 'CHAT_CLIENT_MISSING',\n 'CHAT_NOT_CONNECTED',\n 'CHAT_INTEGRATION_MISSING',\n 'CHAT_CHANNEL_UNBOUND',\n] as const\n\nexport type EvalErrorCode = (typeof EVAL_ERROR_CODES)[number]\n\n/**\n * Typed error for the eval engine. Named EvalRunnerError (not EvalError) to\n * avoid shadowing the JS built-in `EvalError`.\n */\nexport class EvalRunnerError extends AdkError<EvalErrorCode> {}\n", "/**\n * SSECollector \u2014 connects to the ADK dev server's SSE trace stream,\n * accumulates spans, and provides promise-based wait methods for\n * turn completion and workflow signals.\n *\n * Uses fetch() + async iteration with manual SSE line parsing\n * (Bun does not have native EventSource).\n */\n\nimport type { Span } from './trace'\nimport { EvalRunnerError } from '../errors'\n\ntype SSEFilter = { conversationId: string } | { workflowId: string }\n\ninterface WaitOptions {\n timeout: number\n /**\n * Optional abort signal \u2014 when fired, the wait rejects immediately rather\n * than burning the full timeout. Used by the runner so Stop unblocks\n * pending workflow assertions (otherwise a single negative-result wait\n * can hold the suite hostage for `idleTimeout` per assertion).\n */\n abortSignal?: AbortSignal\n}\n\ninterface WorkflowWaitOptions extends WaitOptions {\n signal: 'entered' | 'completed'\n}\n\n/**\n * Unique key for span deduplication.\n */\nfunction spanKey(span: Span): string {\n return `${span.id.trace}:${span.id.span}`\n}\n\n/**\n * Type-safe accessor for span.data fields.\n */\nfunction spanData(span: Span): Record<string, unknown> {\n return span.data && typeof span.data === 'object' ? (span.data as Record<string, unknown>) : {}\n}\n\n/**\n * Span names that mark a Conversation handler reaching the end of a turn.\n *\n * A turn driven by a user message emits `handler.conversation`; a turn driven\n * by an event (a Conversation's `events:` subscription \u2014 e.g. greeting on a\n * conversation-start signal) emits `handler.event`. Both close exactly once\n * per handler invocation, so either is a valid \"turn complete\" signal.\n */\nconst TURN_HANDLER_SPAN_NAMES = new Set(['handler.conversation', 'handler.event'])\n\nfunction isTurnHandlerSpan(span: Span): boolean {\n return TURN_HANDLER_SPAN_NAMES.has(span.name)\n}\n\nexport class SSECollector {\n private devServerUrl: string\n private headers: Record<string, string>\n\n /** All spans accumulated since connect(), keyed by spanKey for dedup. */\n private spanMap = new Map<string, Span>()\n\n /** Index into spanMap insertion order marking where the current turn started. */\n private turnStartKeys = new Set<string>()\n\n /** Handler span IDs seen before the current turn (for startTurn filtering). */\n private seenHandlerKeys = new Set<string>()\n\n /** Callbacks waiting for span updates. */\n private waiters: Array<(span: Span) => void> = []\n\n /** AbortController for the active SSE connection. */\n private abortController: AbortController | null = null\n\n /** Whether the background loop is running. */\n private connected = false\n\n /** Error from the SSE stream if it died unexpectedly. */\n private streamError: Error | null = null\n\n /** Passive counters used only to explain timeout failures. */\n private updateEventCount = 0\n private keepaliveEventCount = 0\n private lastEvent: { name: string; at: number } | null = null\n\n /** Set while a settle phase is in flight; called by disconnect() to short-circuit. */\n private _cancelSettle: (() => void) | null = null\n\n constructor(devServerUrl: string, headers: Record<string, string> = {}) {\n this.devServerUrl = devServerUrl\n this.headers = headers\n }\n\n /**\n * Open a streaming SSE connection filtered by conversationId or workflowId.\n * Starts a background loop that parses SSE events and accumulates spans.\n */\n async connect(filter: SSEFilter): Promise<void> {\n const attributeName = 'conversationId' in filter ? 'conversationId' : 'workflowId'\n const attributeValue = 'conversationId' in filter ? filter.conversationId : filter.workflowId\n\n const url = `${this.devServerUrl}/api/traces/stream?attributeName=${encodeURIComponent(attributeName)}&attributeValue=${encodeURIComponent(attributeValue)}`\n\n this.abortController = new AbortController()\n\n const response = await fetch(url, {\n headers: { ...this.headers, Accept: 'text/event-stream' },\n signal: this.abortController.signal,\n })\n\n if (!response.ok) {\n throw new EvalRunnerError({\n code: 'SSE_CONNECT_FAILED',\n message: `SSE connection failed: ${response.status} ${response.statusText}`,\n expected: true,\n suggestion: 'Make sure the dev server is running (`adk dev`) and reachable.',\n })\n }\n\n if (!response.body) {\n throw new EvalRunnerError({ code: 'SSE_NO_BODY', message: 'SSE response has no body' })\n }\n\n this.connected = true\n\n // Start background parsing loop\n this._consumeStream(response.body).catch((err) => {\n if (this.connected) {\n this.streamError = err instanceof Error ? err : new Error(String(err))\n }\n })\n\n // Wait for the initial snapshot to arrive before returning.\n // This ensures that connect() resolves only after the snapshot\n // has been processed so callers can immediately check spans.\n await this._waitForSnapshot()\n }\n\n /**\n * Mark the beginning of a new turn.\n * Records which turn-handler span IDs (handler.conversation / handler.event)\n * have been seen so far, so waitForTurnComplete() only resolves on NEW\n * handler completions.\n */\n startTurn(): void {\n // Snapshot the current set of span keys as the turn boundary\n this.turnStartKeys = new Set(this.spanMap.keys())\n\n // Record all turn-handler spans seen so far\n for (const [key, span] of this.spanMap) {\n if (isTurnHandlerSpan(span)) {\n this.seenHandlerKeys.add(key)\n }\n }\n }\n\n private static readonly SETTLE_MS = 100\n\n /**\n * Wait for a turn-handler span (handler.conversation or handler.event) to\n * reach terminal status (ok or error).\n * Only considers spans NOT seen before the last startTurn() call.\n *\n * After the handler closes, waits for a quiet period (no new spans for SETTLE_MS)\n * to ensure all child spans (tool calls, messages, state saves) have arrived.\n * The runtime's HttpSpanExporter fires POSTs without awaiting them, so child\n * spans may arrive slightly after the handler close event.\n */\n async waitForTurnComplete(opts: WaitOptions): Promise<void> {\n // Check if a completed handler already exists (e.g. from snapshot)\n if (this._hasNewCompletedHandler()) {\n return this._settleAfterHandler()\n }\n if (opts.abortSignal?.aborted) {\n throw new Error('waitForTurnComplete aborted')\n }\n\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n this._removeWaiter(waiter)\n opts.abortSignal?.removeEventListener('abort', onAbort)\n const reason = this.streamError\n ? `SSE stream died: ${this.streamError.message}`\n : 'no handler.conversation or handler.event span completed'\n reject(\n new Error(\n `waitForTurnComplete timed out after ${opts.timeout}ms \u2014 ${reason}; diagnostics: ${this._formatTurnDiagnostics()}`\n )\n )\n }, opts.timeout)\n\n const onAbort = () => {\n clearTimeout(timer)\n this._removeWaiter(waiter)\n reject(new Error('waitForTurnComplete aborted'))\n }\n opts.abortSignal?.addEventListener('abort', onAbort, { once: true })\n\n const waiter = (_span: Span) => {\n if (this._hasNewCompletedHandler()) {\n clearTimeout(timer)\n this._removeWaiter(waiter)\n opts.abortSignal?.removeEventListener('abort', onAbort)\n this._settleAfterHandler().then(resolve, reject)\n }\n }\n\n this.waiters.push(waiter)\n })\n }\n\n private static readonly MAX_SETTLE_MS = 2_000\n\n /**\n * After the handler span closes, wait for spans to stop arriving.\n * Resolves when no new spans arrive for SETTLE_MS, or after MAX_SETTLE_MS hard cap.\n *\n * Exposes a cancellation hook via _cancelSettle so disconnect() can short-\n * circuit an in-flight settle phase and avoid leaking timers for up to 2s.\n */\n private _settleAfterHandler(): Promise<void> {\n return new Promise<void>((resolve) => {\n let resolved = false\n const done = () => {\n if (resolved) return\n resolved = true\n clearTimeout(hardCap)\n clearTimeout(settleTimer)\n this._removeWaiter(settleWaiter)\n this._cancelSettle = null\n resolve()\n }\n\n const hardCap = setTimeout(done, SSECollector.MAX_SETTLE_MS)\n\n let settleTimer = setTimeout(done, SSECollector.SETTLE_MS)\n\n const settleWaiter = () => {\n if (resolved) return\n clearTimeout(settleTimer)\n settleTimer = setTimeout(done, SSECollector.SETTLE_MS)\n }\n\n this.waiters.push(settleWaiter)\n this._cancelSettle = done\n })\n }\n\n /**\n * Wait for a handler.workflow span with matching workflow name.\n * - signal 'entered': resolves when the span appears (any status)\n * - signal 'completed': resolves when the span has status !== 'running'\n */\n async waitForWorkflow(name: string, opts: WorkflowWaitOptions): Promise<void> {\n // Check if condition is already met\n if (this._matchesWorkflowCondition(name, opts.signal)) {\n return\n }\n if (opts.abortSignal?.aborted) {\n throw new Error(`waitForWorkflow(\"${name}\", { signal: \"${opts.signal}\" }) aborted`)\n }\n\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n this._removeWaiter(waiter)\n opts.abortSignal?.removeEventListener('abort', onAbort)\n const reason = this.streamError ? `SSE stream died: ${this.streamError.message}` : 'span not found'\n reject(\n new Error(\n `waitForWorkflow(\"${name}\", { signal: \"${opts.signal}\" }) timed out after ${opts.timeout}ms \u2014 ${reason}`\n )\n )\n }, opts.timeout)\n\n const onAbort = () => {\n clearTimeout(timer)\n this._removeWaiter(waiter)\n reject(new Error(`waitForWorkflow(\"${name}\", { signal: \"${opts.signal}\" }) aborted`))\n }\n opts.abortSignal?.addEventListener('abort', onAbort, { once: true })\n\n const waiter = (_span: Span) => {\n if (this._matchesWorkflowCondition(name, opts.signal)) {\n clearTimeout(timer)\n this._removeWaiter(waiter)\n opts.abortSignal?.removeEventListener('abort', onAbort)\n resolve()\n }\n }\n\n this.waiters.push(waiter)\n })\n }\n\n /**\n * Return spans accumulated since the last startTurn() call.\n */\n getTurnSpans(): Span[] {\n const result: Span[] = []\n for (const [key, span] of this.spanMap) {\n if (!this.turnStartKeys.has(key)) {\n result.push(span)\n }\n }\n return result\n }\n\n /**\n * Return all spans accumulated since connect().\n */\n getAllSpans(): Span[] {\n return Array.from(this.spanMap.values())\n }\n\n /**\n * Close the SSE connection and clean up.\n */\n disconnect(): void {\n this.connected = false\n this.abortController?.abort()\n this.abortController = null\n // Short-circuit an in-flight settle phase so its hardCap / settleTimer\n // don't fire after disconnect.\n this._cancelSettle?.()\n this._cancelSettle = null\n // Waiters hold setTimeout references that will reject on their own;\n // clearing the array just prevents further notifications.\n this.waiters = []\n this.snapshotResolvers = []\n }\n\n // \u2500\u2500 Private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /** Whether we have received the initial snapshot. */\n private snapshotReceived = false\n private snapshotResolvers: Array<() => void> = []\n\n private static readonly SNAPSHOT_TIMEOUT_MS = 10_000\n\n /**\n * Returns a promise that resolves once the snapshot event has been processed,\n * or rejects after a timeout to prevent connect() from hanging indefinitely.\n */\n private _waitForSnapshot(): Promise<void> {\n if (this.snapshotReceived) {\n return Promise.resolve()\n }\n return new Promise<void>((resolve, reject) => {\n let settled = false\n const resolver = () => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n resolve()\n }\n const timer = setTimeout(() => {\n if (settled) return\n settled = true\n const idx = this.snapshotResolvers.indexOf(resolver)\n if (idx !== -1) this.snapshotResolvers.splice(idx, 1)\n reject(\n new Error(\n `SSE snapshot not received within ${SSECollector.SNAPSHOT_TIMEOUT_MS}ms \u2014 is the dev server healthy?`\n )\n )\n }, SSECollector.SNAPSHOT_TIMEOUT_MS)\n this.snapshotResolvers.push(resolver)\n })\n }\n\n /**\n * Consume the ReadableStream body, parse SSE lines, and dispatch events.\n */\n private async _consumeStream(body: ReadableStream<Uint8Array>): Promise<void> {\n const decoder = new TextDecoder()\n let buffer = ''\n\n const reader = body.getReader()\n\n try {\n while (this.connected) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n\n // Split on double-newline boundaries to get complete SSE events\n const parts = buffer.split('\\n\\n')\n // The last part may be incomplete \u2014 keep it in the buffer\n buffer = parts.pop() ?? ''\n\n for (const part of parts) {\n this._parseSSEBlock(part)\n }\n }\n } finally {\n reader.releaseLock()\n }\n }\n\n /**\n * Parse a single SSE event block (text between \\n\\n boundaries).\n * Extracts event name and data payload.\n */\n private _parseSSEBlock(block: string): void {\n const lines = block.split('\\n')\n let eventName = ''\n let dataLine = ''\n\n for (const line of lines) {\n if (line.startsWith('event:')) {\n eventName = line.slice('event:'.length).trim()\n } else if (line.startsWith('data:')) {\n const value = line.slice('data:'.length).trim()\n dataLine = dataLine ? `${dataLine}\\n${value}` : value\n }\n // id: and retry: lines are ignored\n }\n\n if (!eventName || !dataLine) {\n // Could be a retry: line or empty block \u2014 skip\n if (!this.snapshotReceived && block.includes('retry:')) {\n // The retry line comes before the snapshot; don't resolve yet\n }\n return\n }\n\n try {\n const payload = JSON.parse(dataLine)\n this._handleEvent(eventName, payload)\n } catch {\n // Malformed JSON \u2014 skip\n }\n }\n\n /**\n * Dispatch a parsed SSE event to the appropriate handler.\n */\n private _handleEvent(eventName: string, payload: unknown): void {\n this._recordEvent(eventName)\n\n if (eventName === 'snapshot') {\n const data = payload as { spans: Span[] }\n const spans = Array.isArray(data.spans) ? data.spans : []\n for (const span of spans) {\n this._upsertSpan(span)\n }\n this.snapshotReceived = true\n for (const resolve of this.snapshotResolvers) {\n resolve()\n }\n this.snapshotResolvers = []\n } else if (eventName === 'update') {\n const data = payload as { span: Span }\n if (data.span) {\n this._upsertSpan(data.span)\n this._notifyWaiters(data.span)\n }\n }\n // keepalive events are intentionally ignored\n }\n\n private _recordEvent(eventName: string): void {\n this.lastEvent = { name: eventName, at: Date.now() }\n\n if (eventName === 'update') {\n this.updateEventCount++\n } else if (eventName === 'keepalive') {\n this.keepaliveEventCount++\n }\n }\n\n private _formatTurnDiagnostics(): string {\n const turnSpans = this.getTurnSpans()\n const spanNames = new Set<string>()\n const handlerStatuses = new Set<string>()\n\n for (const span of turnSpans) {\n spanNames.add(span.name)\n // Tracks both handler.conversation and handler.event so an event-driven\n // turn that times out still surfaces its handler status.\n if (isTurnHandlerSpan(span)) {\n handlerStatuses.add(span.status)\n }\n }\n\n const lastEvent = this.lastEvent ? `${this.lastEvent.name} ${Date.now() - this.lastEvent.at}ms ago` : 'none'\n\n return [\n `snapshotReceived=${this.snapshotReceived}`,\n `totalUpdates=${this.updateEventCount}`,\n `totalKeepalives=${this.keepaliveEventCount}`,\n `lastEvent=${lastEvent}`,\n `totalSpans=${this.spanMap.size}`,\n `turnSpans=${turnSpans.length}`,\n `turnSpanNames=${this._formatSet(spanNames)}`,\n `turnHandlerStatuses=${this._formatSet(handlerStatuses)}`,\n ].join(', ')\n }\n\n private _formatSet(values: Set<string>, limit = 12): string {\n if (values.size === 0) {\n return 'none'\n }\n\n const items = Array.from(values)\n const suffix = items.length > limit ? `|+${items.length - limit} more` : ''\n return `${items.slice(0, limit).join('|')}${suffix}`\n }\n\n /**\n * Insert or replace a span in the map (dedup by trace+span ID).\n */\n private _upsertSpan(span: Span): void {\n this.spanMap.set(spanKey(span), span)\n }\n\n /**\n * Notify all waiters that a new span was received.\n */\n private _notifyWaiters(span: Span): void {\n // Copy the array since waiters may remove themselves during iteration\n const current = [...this.waiters]\n for (const waiter of current) {\n waiter(span)\n }\n }\n\n /**\n * Remove a waiter callback from the list.\n */\n private _removeWaiter(fn: (span: Span) => void): void {\n const idx = this.waiters.indexOf(fn)\n if (idx !== -1) {\n this.waiters.splice(idx, 1)\n }\n }\n\n /**\n * Check if there is a turn-handler span (handler.conversation / handler.event) that:\n * 1. Was NOT seen before startTurn()\n * 2. Has terminal status (ok or error)\n *\n * Marks the matched key as consumed so the same handler span cannot\n * satisfy both the current turn's settle phase AND the next turn's\n * waitForTurnComplete check (which would otherwise resolve instantly\n * against stale data instead of waiting for the new turn's handler).\n */\n private _hasNewCompletedHandler(): boolean {\n for (const [key, span] of this.spanMap) {\n if (\n isTurnHandlerSpan(span) &&\n !this.seenHandlerKeys.has(key) &&\n (span.status === 'ok' || span.status === 'error')\n ) {\n this.seenHandlerKeys.add(key)\n return true\n }\n }\n return false\n }\n\n /**\n * Check if a handler.workflow span matches the given condition.\n */\n private _matchesWorkflowCondition(name: string, signal: 'entered' | 'completed'): boolean {\n for (const span of this.spanMap.values()) {\n if (span.name !== 'handler.workflow') continue\n\n const d = spanData(span)\n const wfName = d['workflow.name'] || d['workflowName']\n if (wfName !== name) continue\n\n if (signal === 'entered') {\n // Any status means the workflow was entered\n return true\n }\n\n if (signal === 'completed') {\n return span.status === 'ok' || span.status === 'error'\n }\n }\n return false\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/spans/trace.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,CAAA;AAEnD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,aAAa,GAAG,YAAY,CAAA;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE;QACR,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,CAAA;CACF;AAED,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAA;AAEzD,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,UAAU,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,UAAU,CAAA;IAClB,OAAO,EAAE,WAAW,CAAA;IACpB,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,YAAY,CAAA;CACvB"}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { SpanSource, WaitOptions, WorkflowWaitOptions } from './span-source';
|
|
2
|
-
import type { Span } from './trace';
|
|
3
|
-
interface VortexSpanSourceConfig {
|
|
4
|
-
url: string;
|
|
5
|
-
botId: string;
|
|
6
|
-
workspaceId?: string;
|
|
7
|
-
token?: string;
|
|
8
|
-
pollIntervalMs?: number;
|
|
9
|
-
}
|
|
10
|
-
export declare class VortexSpanSource implements SpanSource {
|
|
11
|
-
private config;
|
|
12
|
-
private conversationId;
|
|
13
|
-
private traceIds;
|
|
14
|
-
private spanMap;
|
|
15
|
-
private turnStartKeys;
|
|
16
|
-
private seenHandlerKeys;
|
|
17
|
-
private consecutiveFailures;
|
|
18
|
-
constructor(config: VortexSpanSourceConfig);
|
|
19
|
-
connect(filter: {
|
|
20
|
-
conversationId: string;
|
|
21
|
-
}): Promise<void>;
|
|
22
|
-
startTurn(): void;
|
|
23
|
-
private static readonly SETTLE_POLLS;
|
|
24
|
-
waitForTurnComplete(opts: WaitOptions): Promise<void>;
|
|
25
|
-
waitForWorkflow(name: string, opts: WorkflowWaitOptions): Promise<void>;
|
|
26
|
-
getTurnSpans(): Span[];
|
|
27
|
-
getAllSpans(): Span[];
|
|
28
|
-
disconnect(): void;
|
|
29
|
-
private _pollOnce;
|
|
30
|
-
private _hasNewCompletedHandler;
|
|
31
|
-
private _matchesWorkflowCondition;
|
|
32
|
-
}
|
|
33
|
-
export {};
|
|
34
|
-
//# sourceMappingURL=vortex-span-source.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"vortex-span-source.d.ts","sourceRoot":"","sources":["../../src/spans/vortex-span-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACjF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAEnC,UAAU,sBAAsB;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AA0DD,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,MAAM,CACyC;IACvD,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,mBAAmB,CAAI;gBAEnB,MAAM,EAAE,sBAAsB;IAUpC,OAAO,CAAC,MAAM,EAAE;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhE,SAAS,IAAI,IAAI;IASjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAI;IAElC,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBrD,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7E,YAAY,IAAI,IAAI,EAAE;IAUtB,WAAW,IAAI,IAAI,EAAE;IAIrB,UAAU,IAAI,IAAI;YAIJ,SAAS;IAoCvB,OAAO,CAAC,uBAAuB;IAc/B,OAAO,CAAC,yBAAyB;CAWlC"}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
// src/spans/vortex-span-source.ts
|
|
2
|
-
function spanKey(span) {
|
|
3
|
-
return `${span.id.trace}:${span.id.span}`;
|
|
4
|
-
}
|
|
5
|
-
function spanData(span) {
|
|
6
|
-
return span.data && typeof span.data === "object" ? span.data : {};
|
|
7
|
-
}
|
|
8
|
-
function normalizeSpan(span) {
|
|
9
|
-
if (span.status !== "running") return span;
|
|
10
|
-
const data = spanData(span);
|
|
11
|
-
const autonomousStatus = data["autonomous.status"];
|
|
12
|
-
if (autonomousStatus === "generation_error" || autonomousStatus === "execution_error" || autonomousStatus === "invalid_code_error" || autonomousStatus === "exit_error" || autonomousStatus === "aborted") {
|
|
13
|
-
return { ...span, status: "error" };
|
|
14
|
-
}
|
|
15
|
-
if (autonomousStatus === "thinking_requested" || autonomousStatus === "callback_requested" || autonomousStatus === "exit_success") {
|
|
16
|
-
return { ...span, status: "ok" };
|
|
17
|
-
}
|
|
18
|
-
const { startedAt, endedAt } = span.timing;
|
|
19
|
-
if (typeof endedAt === "number" && Number.isFinite(endedAt) && endedAt > startedAt) {
|
|
20
|
-
return { ...span, status: "ok" };
|
|
21
|
-
}
|
|
22
|
-
return span;
|
|
23
|
-
}
|
|
24
|
-
function sleep(ms, signal) {
|
|
25
|
-
return new Promise((resolve, reject) => {
|
|
26
|
-
if (signal?.aborted) return reject(new Error("aborted"));
|
|
27
|
-
const onAbort = () => {
|
|
28
|
-
clearTimeout(timer);
|
|
29
|
-
reject(new Error("aborted"));
|
|
30
|
-
};
|
|
31
|
-
const timer = setTimeout(() => {
|
|
32
|
-
signal?.removeEventListener("abort", onAbort);
|
|
33
|
-
resolve();
|
|
34
|
-
}, ms);
|
|
35
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
var VortexSpanSource = class _VortexSpanSource {
|
|
39
|
-
config;
|
|
40
|
-
conversationId = "";
|
|
41
|
-
traceIds = /* @__PURE__ */ new Set();
|
|
42
|
-
spanMap = /* @__PURE__ */ new Map();
|
|
43
|
-
turnStartKeys = /* @__PURE__ */ new Set();
|
|
44
|
-
seenHandlerKeys = /* @__PURE__ */ new Set();
|
|
45
|
-
consecutiveFailures = 0;
|
|
46
|
-
constructor(config) {
|
|
47
|
-
this.config = {
|
|
48
|
-
url: config.url.replace(/\/$/, ""),
|
|
49
|
-
botId: config.botId,
|
|
50
|
-
pollIntervalMs: config.pollIntervalMs ?? 500,
|
|
51
|
-
...config.workspaceId ? { workspaceId: config.workspaceId } : {},
|
|
52
|
-
...config.token ? { token: config.token } : {}
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
async connect(filter) {
|
|
56
|
-
this.conversationId = filter.conversationId;
|
|
57
|
-
await this._pollOnce();
|
|
58
|
-
}
|
|
59
|
-
startTurn() {
|
|
60
|
-
this.turnStartKeys = new Set(this.spanMap.keys());
|
|
61
|
-
for (const [key, span] of this.spanMap) {
|
|
62
|
-
if (span.name === "handler.conversation") {
|
|
63
|
-
this.seenHandlerKeys.add(key);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
static SETTLE_POLLS = 3;
|
|
68
|
-
async waitForTurnComplete(opts) {
|
|
69
|
-
const deadline = Date.now() + opts.timeout;
|
|
70
|
-
while (Date.now() < deadline) {
|
|
71
|
-
if (opts.abortSignal?.aborted) throw new Error("waitForTurnComplete aborted");
|
|
72
|
-
await this._pollOnce();
|
|
73
|
-
if (this._hasNewCompletedHandler()) {
|
|
74
|
-
for (let i = 0; i < _VortexSpanSource.SETTLE_POLLS; i++) {
|
|
75
|
-
await sleep(this.config.pollIntervalMs, opts.abortSignal).catch(() => {
|
|
76
|
-
});
|
|
77
|
-
await this._pollOnce();
|
|
78
|
-
}
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
await sleep(this.config.pollIntervalMs, opts.abortSignal).catch(() => {
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
throw new Error(`waitForTurnComplete timed out after ${opts.timeout}ms`);
|
|
85
|
-
}
|
|
86
|
-
async waitForWorkflow(name, opts) {
|
|
87
|
-
const deadline = Date.now() + opts.timeout;
|
|
88
|
-
while (Date.now() < deadline) {
|
|
89
|
-
if (opts.abortSignal?.aborted) throw new Error(`waitForWorkflow("${name}") aborted`);
|
|
90
|
-
await this._pollOnce();
|
|
91
|
-
if (this._matchesWorkflowCondition(name, opts.signal)) return;
|
|
92
|
-
await sleep(this.config.pollIntervalMs, opts.abortSignal).catch(() => {
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
throw new Error(`waitForWorkflow("${name}", { signal: "${opts.signal}" }) timed out after ${opts.timeout}ms`);
|
|
96
|
-
}
|
|
97
|
-
getTurnSpans() {
|
|
98
|
-
const result = [];
|
|
99
|
-
for (const [key, span] of this.spanMap) {
|
|
100
|
-
if (!this.turnStartKeys.has(key)) {
|
|
101
|
-
result.push(span);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return result;
|
|
105
|
-
}
|
|
106
|
-
getAllSpans() {
|
|
107
|
-
return Array.from(this.spanMap.values());
|
|
108
|
-
}
|
|
109
|
-
disconnect() {
|
|
110
|
-
}
|
|
111
|
-
async _pollOnce() {
|
|
112
|
-
const url = new URL(`${this.config.url}/v1/traces/bot/${this.config.botId}/spans/adk`);
|
|
113
|
-
url.searchParams.set("conversationId", this.conversationId);
|
|
114
|
-
for (const traceId of this.traceIds) {
|
|
115
|
-
url.searchParams.append("traceId", traceId);
|
|
116
|
-
}
|
|
117
|
-
const res = await fetch(url, {
|
|
118
|
-
headers: {
|
|
119
|
-
Accept: "application/json",
|
|
120
|
-
...this.config.token ? { Authorization: `Bearer ${this.config.token}` } : {}
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
if (!res.ok) {
|
|
124
|
-
this.consecutiveFailures++;
|
|
125
|
-
const body = await res.text().catch(() => "");
|
|
126
|
-
const msg = `Vortex poll failed: ${res.status} ${body.slice(0, 200)}`;
|
|
127
|
-
if (this.consecutiveFailures >= 5) {
|
|
128
|
-
throw new Error(`${msg} (${this.consecutiveFailures} consecutive failures)`);
|
|
129
|
-
}
|
|
130
|
-
console.warn(`[VortexSpanSource] ${msg}`);
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
this.consecutiveFailures = 0;
|
|
134
|
-
const payload = await res.json();
|
|
135
|
-
const spans = Array.isArray(payload) ? payload : Array.isArray(payload.spans) ? payload.spans : [];
|
|
136
|
-
for (const rawSpan of spans) {
|
|
137
|
-
const span = normalizeSpan(rawSpan);
|
|
138
|
-
this.spanMap.set(spanKey(span), span);
|
|
139
|
-
this.traceIds.add(span.id.trace);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
_hasNewCompletedHandler() {
|
|
143
|
-
for (const [key, span] of this.spanMap) {
|
|
144
|
-
if (span.name === "handler.conversation" && !this.seenHandlerKeys.has(key) && (span.status === "ok" || span.status === "error")) {
|
|
145
|
-
this.seenHandlerKeys.add(key);
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
_matchesWorkflowCondition(name, signal) {
|
|
152
|
-
for (const span of this.spanMap.values()) {
|
|
153
|
-
if (span.name !== "handler.workflow") continue;
|
|
154
|
-
const d = spanData(span);
|
|
155
|
-
const wfName = d["workflow.name"] || d["workflowName"];
|
|
156
|
-
if (wfName !== name) continue;
|
|
157
|
-
if (signal === "entered") return true;
|
|
158
|
-
if (signal === "completed") return span.status === "ok" || span.status === "error";
|
|
159
|
-
}
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
export {
|
|
164
|
-
VortexSpanSource
|
|
165
|
-
};
|
|
166
|
-
//# sourceMappingURL=vortex-span-source.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/spans/vortex-span-source.ts"],
|
|
4
|
-
"sourcesContent": ["import type { SpanSource, WaitOptions, WorkflowWaitOptions } from './span-source'\nimport type { Span } from './trace'\n\ninterface VortexSpanSourceConfig {\n url: string\n botId: string\n workspaceId?: string\n token?: string\n pollIntervalMs?: number\n}\n\ntype VortexTraceResponse = Span[] | { spans?: Span[] }\n\nfunction spanKey(span: Span): string {\n return `${span.id.trace}:${span.id.span}`\n}\n\nfunction spanData(span: Span): Record<string, unknown> {\n return span.data && typeof span.data === 'object' ? (span.data as Record<string, unknown>) : {}\n}\n\nfunction normalizeSpan(span: Span): Span {\n if (span.status !== 'running') return span\n const data = spanData(span)\n const autonomousStatus = data['autonomous.status']\n\n if (\n autonomousStatus === 'generation_error' ||\n autonomousStatus === 'execution_error' ||\n autonomousStatus === 'invalid_code_error' ||\n autonomousStatus === 'exit_error' ||\n autonomousStatus === 'aborted'\n ) {\n return { ...span, status: 'error' }\n }\n\n if (\n autonomousStatus === 'thinking_requested' ||\n autonomousStatus === 'callback_requested' ||\n autonomousStatus === 'exit_success'\n ) {\n return { ...span, status: 'ok' }\n }\n\n const { startedAt, endedAt } = span.timing\n if (typeof endedAt === 'number' && Number.isFinite(endedAt) && endedAt > startedAt) {\n return { ...span, status: 'ok' }\n }\n\n return span\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) return reject(new Error('aborted'))\n const onAbort = () => {\n clearTimeout(timer)\n reject(new Error('aborted'))\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n signal?.addEventListener('abort', onAbort, { once: true })\n })\n}\n\nexport class VortexSpanSource implements SpanSource {\n private config: Required<Omit<VortexSpanSourceConfig, 'workspaceId' | 'token'>> &\n Pick<VortexSpanSourceConfig, 'workspaceId' | 'token'>\n private conversationId = ''\n private traceIds = new Set<string>()\n private spanMap = new Map<string, Span>()\n private turnStartKeys = new Set<string>()\n private seenHandlerKeys = new Set<string>()\n private consecutiveFailures = 0\n\n constructor(config: VortexSpanSourceConfig) {\n this.config = {\n url: config.url.replace(/\\/$/, ''),\n botId: config.botId,\n pollIntervalMs: config.pollIntervalMs ?? 500,\n ...(config.workspaceId ? { workspaceId: config.workspaceId } : {}),\n ...(config.token ? { token: config.token } : {}),\n }\n }\n\n async connect(filter: { conversationId: string }): Promise<void> {\n this.conversationId = filter.conversationId\n await this._pollOnce()\n }\n\n startTurn(): void {\n this.turnStartKeys = new Set(this.spanMap.keys())\n for (const [key, span] of this.spanMap) {\n if (span.name === 'handler.conversation') {\n this.seenHandlerKeys.add(key)\n }\n }\n }\n\n private static readonly SETTLE_POLLS = 3\n\n async waitForTurnComplete(opts: WaitOptions): Promise<void> {\n const deadline = Date.now() + opts.timeout\n\n while (Date.now() < deadline) {\n if (opts.abortSignal?.aborted) throw new Error('waitForTurnComplete aborted')\n\n await this._pollOnce()\n\n if (this._hasNewCompletedHandler()) {\n for (let i = 0; i < VortexSpanSource.SETTLE_POLLS; i++) {\n await sleep(this.config.pollIntervalMs, opts.abortSignal).catch(() => {})\n await this._pollOnce()\n }\n return\n }\n\n await sleep(this.config.pollIntervalMs, opts.abortSignal).catch(() => {})\n }\n\n throw new Error(`waitForTurnComplete timed out after ${opts.timeout}ms`)\n }\n\n async waitForWorkflow(name: string, opts: WorkflowWaitOptions): Promise<void> {\n const deadline = Date.now() + opts.timeout\n\n while (Date.now() < deadline) {\n if (opts.abortSignal?.aborted) throw new Error(`waitForWorkflow(\"${name}\") aborted`)\n\n await this._pollOnce()\n\n if (this._matchesWorkflowCondition(name, opts.signal)) return\n\n await sleep(this.config.pollIntervalMs, opts.abortSignal).catch(() => {})\n }\n\n throw new Error(`waitForWorkflow(\"${name}\", { signal: \"${opts.signal}\" }) timed out after ${opts.timeout}ms`)\n }\n\n getTurnSpans(): Span[] {\n const result: Span[] = []\n for (const [key, span] of this.spanMap) {\n if (!this.turnStartKeys.has(key)) {\n result.push(span)\n }\n }\n return result\n }\n\n getAllSpans(): Span[] {\n return Array.from(this.spanMap.values())\n }\n\n disconnect(): void {\n // Stateless polling client.\n }\n\n private async _pollOnce(): Promise<void> {\n const url = new URL(`${this.config.url}/v1/traces/bot/${this.config.botId}/spans/adk`)\n url.searchParams.set('conversationId', this.conversationId)\n for (const traceId of this.traceIds) {\n url.searchParams.append('traceId', traceId)\n }\n\n const res = await fetch(url, {\n headers: {\n Accept: 'application/json',\n ...(this.config.token ? { Authorization: `Bearer ${this.config.token}` } : {}),\n },\n })\n\n if (!res.ok) {\n this.consecutiveFailures++\n const body = await res.text().catch(() => '')\n const msg = `Vortex poll failed: ${res.status} ${body.slice(0, 200)}`\n if (this.consecutiveFailures >= 5) {\n throw new Error(`${msg} (${this.consecutiveFailures} consecutive failures)`)\n }\n console.warn(`[VortexSpanSource] ${msg}`)\n return\n }\n\n this.consecutiveFailures = 0\n const payload = (await res.json()) as VortexTraceResponse\n const spans = Array.isArray(payload) ? payload : Array.isArray(payload.spans) ? payload.spans : []\n\n for (const rawSpan of spans) {\n const span = normalizeSpan(rawSpan)\n this.spanMap.set(spanKey(span), span)\n this.traceIds.add(span.id.trace)\n }\n }\n\n private _hasNewCompletedHandler(): boolean {\n for (const [key, span] of this.spanMap) {\n if (\n span.name === 'handler.conversation' &&\n !this.seenHandlerKeys.has(key) &&\n (span.status === 'ok' || span.status === 'error')\n ) {\n this.seenHandlerKeys.add(key)\n return true\n }\n }\n return false\n }\n\n private _matchesWorkflowCondition(name: string, signal: 'entered' | 'completed'): boolean {\n for (const span of this.spanMap.values()) {\n if (span.name !== 'handler.workflow') continue\n const d = spanData(span)\n const wfName = d['workflow.name'] || d['workflowName']\n if (wfName !== name) continue\n if (signal === 'entered') return true\n if (signal === 'completed') return span.status === 'ok' || span.status === 'error'\n }\n return false\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"eval-definition-loader.d.ts","sourceRoot":"","sources":["../../src/stores/eval-definition-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAGnD,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC,CAAA;AAElE,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,oBAAoB,CAE3E"}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
// src/loader.ts
|
|
2
|
-
import { readdirSync, existsSync } from "fs";
|
|
3
|
-
import { resolve } from "path";
|
|
4
|
-
|
|
5
|
-
// src/definition.ts
|
|
6
|
-
var Eval = class {
|
|
7
|
-
name;
|
|
8
|
-
description;
|
|
9
|
-
tags;
|
|
10
|
-
type;
|
|
11
|
-
setup;
|
|
12
|
-
conversation;
|
|
13
|
-
outcome;
|
|
14
|
-
options;
|
|
15
|
-
constructor(def) {
|
|
16
|
-
this.name = def.name;
|
|
17
|
-
this.conversation = def.conversation;
|
|
18
|
-
if (def.description !== void 0) this.description = def.description;
|
|
19
|
-
if (def.tags !== void 0) this.tags = def.tags;
|
|
20
|
-
if (def.type !== void 0) this.type = def.type;
|
|
21
|
-
if (def.setup !== void 0) this.setup = def.setup;
|
|
22
|
-
if (def.outcome !== void 0) this.outcome = def.outcome;
|
|
23
|
-
if (def.options !== void 0) this.options = def.options;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// src/errors.ts
|
|
28
|
-
import { AdkError } from "@botpress/analytics";
|
|
29
|
-
var EvalRunnerError = class extends AdkError {
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// src/loader.ts
|
|
33
|
-
function isEvalDefinition(value) {
|
|
34
|
-
return value !== null && typeof value === "object" && typeof value.name === "string" && value.name !== "" && Array.isArray(value.conversation);
|
|
35
|
-
}
|
|
36
|
-
async function loadEvalFile(filePath) {
|
|
37
|
-
const absPath = resolve(filePath);
|
|
38
|
-
let mod;
|
|
39
|
-
try {
|
|
40
|
-
mod = await import(absPath);
|
|
41
|
-
} catch (err) {
|
|
42
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
43
|
-
throw new EvalRunnerError({
|
|
44
|
-
code: "EVAL_LOAD_FAILED",
|
|
45
|
-
message: `Failed to load eval file ${filePath}: ${msg}
|
|
46
|
-
|
|
47
|
-
Make sure your eval file:
|
|
48
|
-
- Has no syntax or type errors
|
|
49
|
-
- Exports one or more \`new Eval({...})\` instances
|
|
50
|
-
- Has all dependencies installed (\`bun install\`)`,
|
|
51
|
-
expected: true,
|
|
52
|
-
cause: err
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
const results = [];
|
|
56
|
-
for (const [key, value] of Object.entries(mod)) {
|
|
57
|
-
if (key === "__esModule") continue;
|
|
58
|
-
if (value instanceof Eval || isEvalDefinition(value)) {
|
|
59
|
-
results.push(value);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (results.length === 0) {
|
|
63
|
-
throw new EvalRunnerError({
|
|
64
|
-
code: "EVAL_FILE_EMPTY",
|
|
65
|
-
message: `Invalid eval file ${filePath}: no valid evals found. Export one or more \`new Eval({...})\` instances (as default or named exports).`,
|
|
66
|
-
expected: true
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
return results;
|
|
70
|
-
}
|
|
71
|
-
async function loadEvalsFromDir(dirPath) {
|
|
72
|
-
const absDir = resolve(dirPath);
|
|
73
|
-
if (!existsSync(absDir)) {
|
|
74
|
-
return [];
|
|
75
|
-
}
|
|
76
|
-
const files = readdirSync(absDir).filter((f) => f.endsWith(".eval.ts"));
|
|
77
|
-
const evals = [];
|
|
78
|
-
for (const f of files) {
|
|
79
|
-
const defs = await loadEvalFile(`${absDir}/${f}`);
|
|
80
|
-
evals.push(...defs);
|
|
81
|
-
}
|
|
82
|
-
const seen = /* @__PURE__ */ new Set();
|
|
83
|
-
for (const e of evals) {
|
|
84
|
-
if (seen.has(e.name)) {
|
|
85
|
-
throw new EvalRunnerError({
|
|
86
|
-
code: "EVAL_DUPLICATE_NAME",
|
|
87
|
-
message: `Duplicate eval name "${e.name}" found in ${dirPath} \u2014 names must be unique across the evals directory.`,
|
|
88
|
-
expected: true,
|
|
89
|
-
details: { name: e.name }
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
seen.add(e.name);
|
|
93
|
-
}
|
|
94
|
-
return evals;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// src/stores/eval-definition-loader.ts
|
|
98
|
-
function createDiskEvalLoader(evalsDir) {
|
|
99
|
-
return () => loadEvalsFromDir(evalsDir);
|
|
100
|
-
}
|
|
101
|
-
export {
|
|
102
|
-
createDiskEvalLoader
|
|
103
|
-
};
|
|
104
|
-
//# sourceMappingURL=eval-definition-loader.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/loader.ts", "../../src/definition.ts", "../../src/errors.ts", "../../src/stores/eval-definition-loader.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Eval file loader.\n * Loads *.eval.ts files from a directory using dynamic imports.\n * Supports both default and named exports, and multiple evals per file.\n */\n\nimport { readdirSync, existsSync } from 'fs'\nimport { resolve } from 'path'\nimport type { EvalDefinition, EvalFilter } from './types'\nimport { Eval } from './types'\nimport { EvalRunnerError } from './errors'\n\nfunction isEvalDefinition(value: unknown): value is EvalDefinition {\n return (\n value !== null &&\n typeof value === 'object' &&\n typeof (value as Record<string, unknown>).name === 'string' &&\n (value as Record<string, unknown>).name !== '' &&\n Array.isArray((value as Record<string, unknown>).conversation)\n )\n}\n\nexport async function loadEvalFile(filePath: string): Promise<EvalDefinition[]> {\n const absPath = resolve(filePath)\n\n let mod: Record<string, unknown>\n try {\n mod = await import(absPath)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n // Guidance stays in the message until the CLI renders `suggestion`\n // (cli-package remediation) \u2014 report.error/logger.fatal only show message.\n throw new EvalRunnerError({\n code: 'EVAL_LOAD_FAILED',\n message:\n `Failed to load eval file ${filePath}: ${msg}\\n\\n` +\n 'Make sure your eval file:\\n' +\n ' - Has no syntax or type errors\\n' +\n ' - Exports one or more `new Eval({...})` instances\\n' +\n ' - Has all dependencies installed (`bun install`)',\n expected: true,\n cause: err,\n })\n }\n\n const results: EvalDefinition[] = []\n\n for (const [key, value] of Object.entries(mod)) {\n if (key === '__esModule') continue\n if (value instanceof Eval || isEvalDefinition(value)) {\n results.push(value)\n }\n }\n\n if (results.length === 0) {\n throw new EvalRunnerError({\n code: 'EVAL_FILE_EMPTY',\n message: `Invalid eval file ${filePath}: no valid evals found. Export one or more \\`new Eval({...})\\` instances (as default or named exports).`,\n expected: true,\n })\n }\n\n return results\n}\n\nexport async function loadEvalsFromDir(dirPath: string): Promise<EvalDefinition[]> {\n const absDir = resolve(dirPath)\n if (!existsSync(absDir)) {\n return []\n }\n\n const files = readdirSync(absDir).filter((f) => f.endsWith('.eval.ts'))\n const evals: EvalDefinition[] = []\n\n for (const f of files) {\n const defs = await loadEvalFile(`${absDir}/${f}`)\n evals.push(...defs)\n }\n\n const seen = new Set<string>()\n for (const e of evals) {\n if (seen.has(e.name)) {\n throw new EvalRunnerError({\n code: 'EVAL_DUPLICATE_NAME',\n message: `Duplicate eval name \"${e.name}\" found in ${dirPath} \u2014 names must be unique across the evals directory.`,\n expected: true,\n details: { name: e.name },\n })\n }\n seen.add(e.name)\n }\n\n return evals\n}\n\nexport async function loadEvalByName(dirPath: string, name: string): Promise<EvalDefinition | null> {\n const absDir = resolve(dirPath)\n if (!existsSync(absDir)) return null\n\n const files = readdirSync(absDir).filter((f) => f.endsWith('.eval.ts'))\n\n for (const f of files) {\n const defs = await loadEvalFile(`${absDir}/${f}`)\n const found = defs.find((d) => d.name === name)\n if (found) return found\n }\n\n return null\n}\n\nexport function filterEvals(evals: EvalDefinition[], filter?: EvalFilter): EvalDefinition[] {\n if (!filter) return evals\n\n return evals.filter((e) => {\n if (filter.names && filter.names.length > 0) {\n if (!filter.names.includes(e.name)) return false\n }\n if (filter.tags && filter.tags.length > 0) {\n if (!e.tags || !filter.tags.some((t) => e.tags!.includes(t))) return false\n }\n if (filter.type) {\n if (e.type !== filter.type) return false\n }\n return true\n })\n}\n", "export type MatchOperator =\n | string\n | { equals: unknown }\n | { contains: string }\n | { not_contains: string }\n | { matches: string }\n | { in: unknown[] }\n | { exists: boolean }\n | { gte: number }\n | { lte: number }\n\nexport type ResponseAssertion =\n | { contains: string }\n | { not_contains: string }\n | { matches: string }\n | { llm_judge: string }\n// | { similar_to: string } TODO: uncomment this when it gets implemented\n\nexport type ToolAssertion =\n | { called: string; params?: Record<string, MatchOperator> }\n | { not_called: string }\n | { call_order: string[] }\n\nexport interface StateAssertion {\n path: string\n equals?: unknown\n changed?: boolean\n}\n\nexport interface WorkflowAssertion {\n name: string\n entered?: boolean\n completed?: boolean\n}\n\nexport type NumericOperator = { equals: number } | { gte: number } | { lte: number }\n\nexport interface TimingAssertion {\n response_time: NumericOperator\n}\n\nexport interface TurnAssertions {\n response?: ResponseAssertion[]\n tools?: ToolAssertion[]\n state?: StateAssertion[]\n workflow?: WorkflowAssertion[]\n timing?: TimingAssertion[]\n}\n\nexport interface ConversationTurn {\n user?: string\n event?: { payload: Record<string, unknown> }\n expectSilence?: boolean\n assert?: TurnAssertions\n}\n\nexport interface OutcomeAssertions {\n state?: StateAssertion[]\n workflow?: WorkflowAssertion[]\n}\n\nexport interface EvalSetup {\n state?: {\n bot?: Record<string, unknown>\n user?: Record<string, unknown>\n conversation?: Record<string, unknown>\n }\n workflow?: {\n trigger: string\n input?: Record<string, unknown>\n }\n}\n\nexport interface EvalDefinition {\n name: string\n description?: string\n tags?: string[]\n type?: 'capability' | 'regression'\n setup?: EvalSetup\n conversation: ConversationTurn[]\n outcome?: OutcomeAssertions\n options?: {\n idleTimeout?: number\n /** @deprecated No-op: the LLM judge is boolean (zai.check); there is no score threshold. */\n judgePassThreshold?: number\n }\n}\n\nexport class Eval implements EvalDefinition {\n readonly name: string\n readonly description?: string\n readonly tags?: string[]\n readonly type?: 'capability' | 'regression'\n readonly setup?: EvalSetup\n readonly conversation: ConversationTurn[]\n readonly outcome?: OutcomeAssertions\n readonly options?: {\n idleTimeout?: number\n /** @deprecated No-op: the LLM judge is boolean (zai.check); there is no score threshold. */\n judgePassThreshold?: number\n }\n\n constructor(def: EvalDefinition) {\n this.name = def.name\n this.conversation = def.conversation\n if (def.description !== undefined) this.description = def.description\n if (def.tags !== undefined) this.tags = def.tags\n if (def.type !== undefined) this.type = def.type\n if (def.setup !== undefined) this.setup = def.setup\n if (def.outcome !== undefined) this.outcome = def.outcome\n if (def.options !== undefined) this.options = def.options\n }\n}\n", "import { AdkError } from '@botpress/analytics'\n\n/**\n * Stable error codes for the eval engine. Typed as a literal union so a typo'd\n * code is a compile error and PostHog issue-slicing stays consistent.\n * Conventions per docs/ERROR-HANDLING.md.\n */\nexport const EVAL_ERROR_CODES = [\n 'EVAL_LOAD_FAILED',\n 'EVAL_FILE_EMPTY',\n 'EVAL_DUPLICATE_NAME',\n 'EVAL_SEED_NO_CONVERSATION',\n 'EVAL_NO_CONVERSATION_ID',\n 'EVAL_TURN_CONFIG_INVALID',\n 'SSE_CONNECT_FAILED',\n 'SSE_NO_BODY',\n 'CHAT_CLIENT_MISSING',\n 'CHAT_NOT_CONNECTED',\n 'CHAT_INTEGRATION_MISSING',\n 'CHAT_CHANNEL_UNBOUND',\n] as const\n\nexport type EvalErrorCode = (typeof EVAL_ERROR_CODES)[number]\n\n/**\n * Typed error for the eval engine. Named EvalRunnerError (not EvalError) to\n * avoid shadowing the JS built-in `EvalError`.\n */\nexport class EvalRunnerError extends AdkError<EvalErrorCode> {}\n", "import type { EvalDefinition } from '../definition'\nimport { loadEvalsFromDir } from '../loader'\n\nexport type EvalDefinitionLoader = () => Promise<EvalDefinition[]>\n\nexport function createDiskEvalLoader(evalsDir: string): EvalDefinitionLoader {\n return () => loadEvalsFromDir(evalsDir)\n}\n"],
|
|
5
|
-
"mappings": ";AAMA,SAAS,aAAa,kBAAkB;AACxC,SAAS,eAAe;;;ACiFjB,IAAM,OAAN,MAAqC;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAMT,YAAY,KAAqB;AAC/B,SAAK,OAAO,IAAI;AAChB,SAAK,eAAe,IAAI;AACxB,QAAI,IAAI,gBAAgB,OAAW,MAAK,cAAc,IAAI;AAC1D,QAAI,IAAI,SAAS,OAAW,MAAK,OAAO,IAAI;AAC5C,QAAI,IAAI,SAAS,OAAW,MAAK,OAAO,IAAI;AAC5C,QAAI,IAAI,UAAU,OAAW,MAAK,QAAQ,IAAI;AAC9C,QAAI,IAAI,YAAY,OAAW,MAAK,UAAU,IAAI;AAClD,QAAI,IAAI,YAAY,OAAW,MAAK,UAAU,IAAI;AAAA,EACpD;AACF;;;AChHA,SAAS,gBAAgB;AA4BlB,IAAM,kBAAN,cAA8B,SAAwB;AAAC;;;AFhB9D,SAAS,iBAAiB,OAAyC;AACjE,SACE,UAAU,QACV,OAAO,UAAU,YACjB,OAAQ,MAAkC,SAAS,YAClD,MAAkC,SAAS,MAC5C,MAAM,QAAS,MAAkC,YAAY;AAEjE;AAEA,eAAsB,aAAa,UAA6C;AAC9E,QAAM,UAAU,QAAQ,QAAQ;AAEhC,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,OAAO;AAAA,EACrB,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAG3D,UAAM,IAAI,gBAAgB;AAAA,MACxB,MAAM;AAAA,MACN,SACE,4BAA4B,QAAQ,KAAK,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAK9C,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,QAAM,UAA4B,CAAC;AAEnC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,QAAI,QAAQ,aAAc;AAC1B,QAAI,iBAAiB,QAAQ,iBAAiB,KAAK,GAAG;AACpD,cAAQ,KAAK,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,GAAG;AACxB,UAAM,IAAI,gBAAgB;AAAA,MACxB,MAAM;AAAA,MACN,SAAS,qBAAqB,QAAQ;AAAA,MACtC,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,eAAsB,iBAAiB,SAA4C;AACjF,QAAM,SAAS,QAAQ,OAAO;AAC9B,MAAI,CAAC,WAAW,MAAM,GAAG;AACvB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,QAAQ,YAAY,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,UAAU,CAAC;AACtE,QAAM,QAA0B,CAAC;AAEjC,aAAW,KAAK,OAAO;AACrB,UAAM,OAAO,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,EAAE;AAChD,UAAM,KAAK,GAAG,IAAI;AAAA,EACpB;AAEA,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,KAAK,OAAO;AACrB,QAAI,KAAK,IAAI,EAAE,IAAI,GAAG;AACpB,YAAM,IAAI,gBAAgB;AAAA,QACxB,MAAM;AAAA,QACN,SAAS,wBAAwB,EAAE,IAAI,cAAc,OAAO;AAAA,QAC5D,UAAU;AAAA,QACV,SAAS,EAAE,MAAM,EAAE,KAAK;AAAA,MAC1B,CAAC;AAAA,IACH;AACA,SAAK,IAAI,EAAE,IAAI;AAAA,EACjB;AAEA,SAAO;AACT;;;AGxFO,SAAS,qBAAqB,UAAwC;AAC3E,SAAO,MAAM,iBAAiB,QAAQ;AACxC;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|