@lmnr-ai/client 0.8.42 → 0.8.43
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.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -9
- package/dist/index.d.mts +14 -9
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -30,7 +30,7 @@ let pino_pretty = require("pino-pretty");
|
|
|
30
30
|
let uuid = require("uuid");
|
|
31
31
|
let _lmnr_ai_types = require("@lmnr-ai/types");
|
|
32
32
|
//#region package.json
|
|
33
|
-
var version = "0.8.
|
|
33
|
+
var version = "0.8.43";
|
|
34
34
|
//#endregion
|
|
35
35
|
//#region src/version.ts
|
|
36
36
|
function getLangVersion() {
|
|
@@ -826,8 +826,8 @@ var SignalsResource = class extends BaseResource {
|
|
|
826
826
|
}
|
|
827
827
|
/**
|
|
828
828
|
* PATCH, not PUT: only the keys present in `options` are sent, so the server
|
|
829
|
-
* leaves everything else as stored. `
|
|
830
|
-
* serialization (it means "clear"), so
|
|
829
|
+
* leaves everything else as stored. An explicit `null` on `sampleRate` must
|
|
830
|
+
* survive serialization (it means "clear"), so nulls are NOT stripped here.
|
|
831
831
|
*/
|
|
832
832
|
async update(signalId, options) {
|
|
833
833
|
const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`, {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["SDK_VERSION","logger","logger","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/resources/cli.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.ts","../src/resources/signals.ts","../src/resources/sql.ts","../src/resources/tags.ts","../src/resources/traces.ts","../src/index.ts"],"sourcesContent":["","// Version detection for runtime environment\nexport function getLangVersion(): string | null {\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return `node-${process.versions.node}`;\n }\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return `browser-${navigator.userAgent}`;\n }\n return null;\n}\n","/**\n * Unified auth for every resource. A discriminated union so a single object\n * drives both the URL prefix and the request headers:\n *\n * - `apiKey` → project API key (SDK / app surfaces). Routes to `/v1/*`,\n * Bearer is the project key, no `x-lmnr-project-id` header.\n * - `userToken` → BetterAuth user access JWT (the CLI user-token surface).\n * Routes to `/v1/cli/*`, Bearer is the JWT, carries the target project in\n * the `x-lmnr-project-id` header.\n */\nexport type LaminarAuth =\n | { type: \"apiKey\"; key: string }\n | { type: \"userToken\"; token: string; projectId: string };\n\nclass BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly auth: LaminarAuth;\n /** The bearer credential, regardless of auth type (project key or user JWT). */\n protected readonly credential: string;\n\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n this.baseHttpUrl = baseHttpUrl;\n this.auth = auth;\n this.credential = auth.type === \"apiKey\" ? auth.key : auth.token;\n }\n\n /** API path prefix: `/v1/cli` for CLI user-token auth, `/v1` otherwise. */\n protected get apiPrefix(): string {\n return this.auth.type === \"userToken\" ? \"/v1/cli\" : \"/v1\";\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.credential}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...(this.auth.type === \"userToken\"\n ? { \"x-lmnr-project-id\": this.auth.projectId }\n : {}),\n };\n }\n\n protected async handleError(response: Response) {\n const errorMsg = await response.text();\n throw new Error(`${response.status} ${errorMsg}`);\n }\n}\n\nexport { BaseResource };\n","import { version as SDK_VERSION } from '../../package.json';\nimport { getLangVersion } from \"../version\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n public async send({\n sessionId,\n traceId,\n events,\n }: {\n sessionId: string;\n traceId: string;\n events: Record<string, any>[];\n }): Promise<void> {\n const payload = {\n sessionId,\n traceId,\n events,\n source: getLangVersion() ?? 'javascript',\n sdkVersion: SDK_VERSION,\n };\n\n const jsonString = JSON.stringify(payload);\n const blob = new Blob([jsonString], { type: 'application/json' });\n const compressedStream = blob.stream().pipeThrough(new CompressionStream('gzip'));\n const compressedResponse = new Response(compressedStream);\n const compressedData = await compressedResponse.arrayBuffer();\n\n const response = await fetch(this.baseHttpUrl + \"/v1/browser-sessions/events\", {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Content-Encoding': 'gzip',\n },\n body: compressedData,\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource, type LaminarAuth } from \"./index\";\n\nexport interface CliProject {\n id: string;\n name: string;\n workspaceId: string;\n workspaceName: string;\n}\n\n/**\n * Locale-aware, case-insensitive comparator for the project listing. Ordering\n * lives here — the single choke point every CLI surface (the `project list`\n * table + its `--json`, and the interactive picker used by `setup` / `plugin\n * add`) reads from — so the order can't drift between surfaces.\n */\nconst projectCollator = new Intl.Collator(undefined, { sensitivity: \"base\" });\n\n/** Sort projects by workspace name, then project name (stable, human-scannable). */\nconst sortProjects = (projects: CliProject[]): CliProject[] =>\n [...projects].sort(\n (a, b) =>\n projectCollator.compare(a.workspaceName ?? \"\", b.workspaceName ?? \"\") ||\n projectCollator.compare(a.name ?? \"\", b.name ?? \"\"),\n );\n\n/**\n * Outcome of resolving which project a project API key belongs to via the\n * user-token CLI endpoint. The states are deliberately distinct so the caller\n * doesn't conflate \"key is bad\" with \"couldn't reach the server\":\n * - `ok` → key verified AND the user is a member; `projectId` is its owner.\n * - `invalid` → 401: key revoked/invalid. Safe to mint a fresh one.\n * - `unverifiable` → 403 (key belongs to a project the user can't access) /\n * network error / other non-2xx / malformed body. The key may be perfectly\n * valid — caller MUST NOT mint (minting would clobber it on a blip).\n */\nexport type ProjectKeyProbe =\n | { status: \"ok\"; projectId: string }\n | { status: \"invalid\" }\n | { status: \"unverifiable\" };\n\n/**\n * User-scoped CLI endpoints that don't target a specific project. Authed by the\n * BetterAuth user JWT (the `credential`); deliberately does NOT send an\n * `x-lmnr-project-id` header (these routes are project discovery, pre-selection).\n *\n * Discovery exception: this resource always hits `/v1/cli/projects` with the\n * bare bearer and overrides `BaseResource.headers()`/`apiPrefix`, so it works\n * even when constructed with a `userToken` auth that has no real project id yet.\n */\nexport class CliResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /** Workspaces + projects the authenticated user can access. */\n public async listProjects(): Promise<CliProject[]> {\n const response = await fetch(`${this.baseHttpUrl}/v1/cli/projects`, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${this.credential}`,\n Accept: \"application/json\",\n },\n });\n if (!response.ok) {\n await this.handleError(response);\n }\n // Coerce a missing/non-array `projects` to [] so callers (.length/.map)\n // don't throw. A malformed body on a 2xx is exceptional — let it surface.\n // Sort here so every consumer inherits one stable, alphabetical order.\n const body = (await response.json()) as { projects?: CliProject[] };\n return Array.isArray(body?.projects) ? sortProjects(body.projects) : [];\n }\n\n /**\n * Resolve which project a project API key belongs to. Authed by the user JWT\n * (the bearer); the project key travels in the body, NOT in `Authorization`.\n * The server verifies the key and that the authenticated user is a member of\n * the resolved project. Returns a tri-state probe so callers can distinguish a\n * revoked key (401 → `invalid`) from a server/access problem (`unverifiable`).\n */\n public async resolveProjectByApiKey(apiKey: string): Promise<ProjectKeyProbe> {\n let response: Response;\n try {\n response = await fetch(`${this.baseHttpUrl}/v1/cli/project`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.credential}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({ apiKey }),\n });\n } catch {\n return { status: \"unverifiable\" };\n }\n if (response.status === 401) return { status: \"invalid\" };\n if (!response.ok) return { status: \"unverifiable\" };\n const body = (await response.json().catch(() => null)) as { projectId?: string } | null;\n return body?.projectId\n ? { status: \"ok\", projectId: body.projectId }\n : { status: \"unverifiable\" };\n }\n}\n","import { type StringUUID } from '@lmnr-ai/types';\nimport { config } from 'dotenv';\nimport * as path from 'path';\nimport pino, { Level } from 'pino';\nimport { PinoPretty } from 'pino-pretty';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport function initializeLogger(options?: { colorize?: boolean; level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level =\n options?.level ??\n (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level) ??\n 'info';\n\n return pino(\n {\n level,\n },\n PinoPretty({\n colorize,\n minimumLevel: level,\n }),\n );\n}\n\nconst logger = initializeLogger();\n\nexport const isStringUUID = (id: string): id is StringUUID =>\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);\n\nexport const NIL_UUID: StringUUID = '00000000-0000-0000-0000-000000000000';\n\nexport const newUUID = (): StringUUID => {\n // crypto.randomUUID is available in most of the modern browsers and node,\n // but is not available in \"insecure\" contexts, e.g. not https, not localhost\n // so we fallback to uuidv4 in those cases, which is less secure, but works\n // just fine.\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n } else {\n return uuidv4() as `${string}-${string}-${string}-${string}-${string}`;\n }\n};\n\nexport const otelSpanIdToUUID = (spanId: string): string => {\n let id = spanId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 16) {\n logger.warn(\n `Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.',\n );\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.padStart(32, '0').replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n );\n};\n\nexport const otelTraceIdToUUID = (traceId: string): StringUUID => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(\n `Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.',\n );\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n ) as StringUUID;\n};\n\nexport const slicePayload = <T>(value: T, length: number) => {\n if (value === null || value === undefined) {\n return value;\n }\n\n const str = JSON.stringify(value);\n if (str.length <= length) {\n return value;\n }\n\n return str.slice(0, length) + '...';\n};\n\nexport const loadEnv = (\n options?: {\n quiet?: boolean;\n paths?: string[];\n },\n): void => {\n const nodeEnv = process.env.NODE_ENV || 'development';\n const envDir = process.cwd();\n\n // Files to load in order (lowest to highest priority)\n // Later files override earlier ones\n const envFiles = [\n '.env',\n '.env.local',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`,\n ];\n\n const logLevel = process.env.LMNR_LOG_LEVEL ?? 'info';\n const verbose = ['debug', 'trace'].includes(logLevel.trim().toLowerCase());\n\n const quiet = options?.quiet ?? !verbose;\n\n config({\n path: options?.paths ?? envFiles.map((envFile) => path.resolve(envDir, envFile)),\n quiet,\n });\n};\n","import {\n type Datapoint,\n type Dataset,\n type GetDatapointsResponse,\n type PushDatapointsResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nconst logger = initializeLogger();\nconst DEFAULT_DATASET_PULL_LIMIT = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\n\nexport class DatasetsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * List all datasets.\n *\n * @returns {Promise<Dataset[]>} Array of datasets\n */\n public async listDatasets(): Promise<Dataset[]> {\n const response = await fetch(this.baseHttpUrl + this.apiPrefix + \"/datasets\", {\n method: \"GET\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Get a dataset by name.\n *\n * @param {string} name - Name of the dataset\n * @returns {Promise<Dataset[]>} Array of datasets with matching name\n */\n public async getDatasetByName(name: string): Promise<Dataset[]> {\n const params = new URLSearchParams({ name });\n const response = await fetch(\n this.baseHttpUrl + `${this.apiPrefix}/datasets?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Push datapoints to a dataset.\n *\n * @param {Object} options - Push options\n * @param {Datapoint<D, T>[]} options.points - Datapoints to push\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.batchSize] - Batch size for pushing (default: 100)\n * @param {boolean} [options.createDataset] - Whether to create the dataset if it doesn't exist\n * @returns {Promise<PushDatapointsResponse | undefined>}\n */\n public async push<D, T>({\n points,\n name,\n id,\n batchSize = DEFAULT_DATASET_PUSH_BATCH_SIZE,\n createDataset = false,\n }: {\n points: Datapoint<D, T>[];\n name?: string;\n id?: StringUUID;\n batchSize?: number;\n createDataset?: boolean;\n }): Promise<PushDatapointsResponse | undefined> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n if (createDataset && !name) {\n throw new Error(\"Name must be provided when creating a new dataset\");\n }\n\n const identifier = name ? { name } : { datasetId: id! };\n const totalBatches = Math.ceil(points.length / batchSize);\n\n let response: PushDatapointsResponse | undefined;\n for (let i = 0; i < points.length; i += batchSize) {\n const batchNum = Math.floor(i / batchSize) + 1;\n logger.debug(`Pushing batch ${batchNum} of ${totalBatches}`);\n\n const batch = points.slice(i, i + batchSize);\n const fetchResponse = await fetch(\n this.baseHttpUrl + this.apiPrefix + \"/datasets/datapoints\",\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n ...identifier,\n datapoints: batch.map((point) => ({\n data: point.data,\n target: point.target ?? {},\n metadata: point.metadata ?? {},\n })),\n createDataset,\n }),\n },\n );\n\n // 201 when creating a new dataset\n if (fetchResponse.status !== 200 && fetchResponse.status !== 201) {\n await this.handleError(fetchResponse);\n }\n\n response = (await fetchResponse.json()) as PushDatapointsResponse;\n }\n\n return response;\n }\n\n /**\n * Pull datapoints from a dataset.\n *\n * @param {Object} options - Pull options\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.limit] - Maximum number of datapoints to return (default: 100)\n * @param {number} [options.offset] - Offset for pagination (default: 0)\n * @returns {Promise<GetDatapointsResponse<D, T>>}\n */\n public async pull<D, T>({\n name,\n id,\n limit = DEFAULT_DATASET_PULL_LIMIT,\n offset = 0,\n }: {\n name?: string;\n id?: StringUUID;\n limit?: number;\n offset?: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n const paramsObj: Record<string, string> = {\n offset: offset.toString(),\n limit: limit.toString(),\n };\n\n if (name) {\n paramsObj.name = name;\n } else {\n paramsObj.datasetId = id!;\n }\n\n const params = new URLSearchParams(paramsObj);\n\n const response = await fetch(\n this.baseHttpUrl + `${this.apiPrefix}/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<GetDatapointsResponse<D, T>>;\n }\n}\n","import {\n type EvaluationDatapoint,\n type GetDatapointsResponse,\n type InitEvaluationResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger, newUUID, slicePayload } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nconst logger = initializeLogger();\nconst INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16_000_000; // 16MB\n\nexport class EvalsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Initialize an evaluation.\n *\n * @param {string} name - Name of the evaluation\n * @param {string} groupName - Group name of the evaluation\n * @param {Record<string, any>} metadata - Optional metadata\n * @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization\n */\n public async init(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + \"/v1/evals\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n groupName: groupName ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n *\n * @param {string} [name] - Optional name of the evaluation\n * @param {string} [groupName] - An identifier to group evaluations\n * @param {Record<string, any>} [metadata] - Optional metadata\n * @returns {Promise<StringUUID>} The evaluation ID\n */\n\n public async create(args?: {\n name?: string, groupName?: string, metadata?: Record<string, any>\n }): Promise<StringUUID> {\n const evaluation = await this.init(args?.name, args?.groupName, args?.metadata);\n return evaluation.id;\n }\n\n /**\n * Update an evaluation's name and/or metadata. The group ID is immutable.\n * Fields left undefined are kept unchanged.\n *\n * @param {Object} options - Update evaluation options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} [options.name] - New name of the evaluation\n * @param {Record<string, any>} [options.metadata] - New metadata for the evaluation\n * @returns {Promise<InitEvaluationResponse>} The updated evaluation\n */\n public async update({\n evalId,\n name,\n metadata,\n }: {\n evalId: string;\n name?: string;\n metadata?: Record<string, any>;\n }): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n * @deprecated use `create` instead.\n */\n public async createEvaluation(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<StringUUID> {\n const evaluation = await this.init(name, groupName, metadata);\n return evaluation.id;\n }\n\n /**\n * Create a datapoint for an evaluation.\n *\n * @param {Object} options - Create datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {D} options.data - The input data for the executor\n * @param {T} [options.target] - The target/expected output for evaluators\n * @param {Record<string, any>} [options.metadata] - Optional metadata\n * @param {number} [options.index] - Optional index of the datapoint\n * @param {string} [options.traceId] - Optional trace ID\n * @returns {Promise<StringUUID>} The datapoint ID\n */\n public async createDatapoint<D, T>({\n evalId,\n data,\n target,\n metadata,\n index,\n traceId,\n }: {\n evalId: string;\n data: D;\n target?: T;\n metadata?: Record<string, any>;\n index?: number;\n traceId?: string;\n }): Promise<StringUUID> {\n const datapointId = newUUID();\n\n const partialDatapoint: EvaluationDatapoint<D, T, any> = {\n id: datapointId,\n data,\n target,\n index: index ?? 0,\n traceId: traceId ?? newUUID(),\n executorSpanId: newUUID(),\n metadata,\n };\n\n await this.saveDatapoints({\n evalId,\n datapoints: [partialDatapoint],\n });\n\n return datapointId;\n }\n\n /**\n * Update a datapoint with evaluation results.\n *\n * @param {Object} options - Update datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} options.datapointId - The datapoint ID\n * @param {Record<string, number>} options.scores - The scores\n * @param {O} [options.executorOutput] - The executor output\n * @returns {Promise<void>}\n */\n public async updateDatapoint<O>({\n evalId,\n datapointId,\n scores,\n executorOutput,\n }: {\n evalId: string;\n datapointId: string;\n scores: Record<string, number>;\n executorOutput?: O;\n }): Promise<void> {\n const response = await fetch(\n this.baseHttpUrl + `/v1/evals/${evalId}/datapoints/${datapointId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n executorOutput,\n scores,\n }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Save evaluation datapoints.\n *\n * @param {Object} options - Save datapoints options\n * @param {string} options.evalId - ID of the evaluation\n * @param {EvaluationDatapoint<D, T, O>[]} options.datapoints - Datapoint to add\n * @param {string} [options.groupName] - Group name of the evaluation\n * @returns {Promise<void>} Response from the datapoint addition\n */\n public async saveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n }): Promise<void> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n target: slicePayload(d.target, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n executorOutput: slicePayload(\n d.executorOutput,\n INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n ),\n })),\n groupName: groupName ?? null,\n }),\n });\n\n if (response.status === 413) {\n return await this.retrySaveDatapoints({\n evalId,\n datapoints,\n groupName,\n });\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Get evaluation datapoints.\n *\n * @deprecated Use `client.datasets.pull()` instead.\n * @param {Object} options - Get datapoints options\n * @param {string} options.datasetName - Name of the dataset\n * @param {number} options.offset - Offset at which to start the query\n * @param {number} options.limit - Maximum number of datapoints to return\n * @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval\n */\n public async getDatapoints<D, T>({\n datasetName,\n offset,\n limit,\n }: {\n datasetName: string;\n offset: number;\n limit: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n logger.warn(\n 'evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.',\n );\n\n const params = new URLSearchParams({\n name: datasetName,\n offset: offset.toString(),\n limit: limit.toString(),\n });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as GetDatapointsResponse<D, T>;\n }\n\n private async retrySaveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n maxRetries = 25,\n initialLength = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n maxRetries?: number;\n initialLength?: number;\n }): Promise<void> {\n let length = initialLength;\n let lastResponse: Response | null = null;\n for (let i = 0; i < maxRetries; i++) {\n logger.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, length),\n target: slicePayload(d.target, length),\n executorOutput: slicePayload(d.executorOutput, length),\n })),\n groupName: groupName ?? null,\n }),\n });\n lastResponse = response;\n length = Math.floor(length / 2);\n if (response.status !== 413) {\n break;\n }\n }\n if (lastResponse && !lastResponse.ok) {\n await this.handleError(lastResponse);\n }\n }\n}\n","import { type StringUUID } from \"@lmnr-ai/types\";\n\nimport { isStringUUID, otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nenum EvaluatorScoreSourceType {\n Evaluator = \"Evaluator\",\n Code = \"Code\",\n}\n\ninterface CreateEvaluatorScoreBase {\n name: string;\n metadata?: Record<string, any>;\n score: number;\n source: EvaluatorScoreSourceType;\n}\n\ninterface CreateEvaluatorScoreRequestWithTraceId extends CreateEvaluatorScoreBase {\n traceId: string;\n}\n\ninterface CreateEvaluatorScoreRequestWithSpanId extends CreateEvaluatorScoreBase {\n spanId: string;\n}\n\ntype ScoreOptions =\n | { name: string; metadata?: Record<string, any>; score: number; traceId: string; }\n | { name: string; metadata?: Record<string, any>; score: number; spanId: string; };\n\n/**\n * Resource for creating evaluator scores\n */\nexport class EvaluatorsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Create a score for a span or trace\n *\n * @param {ScoreOptions} options - Score creation options\n * @param {string} options.name - Name of the score\n * @param {string} [options.traceId] - The trace ID to score (will be attached to top-level span)\n * @param {string} [options.spanId] - The span ID to score\n * @param {Record<string, any>} [options.metadata] - Additional metadata\n * @param {number} options.score - The score value (float)\n * @returns {Promise<void>}\n *\n * @example\n * // Score by trace ID (will attach to root span)\n * await evaluators.score({\n * name: \"quality\",\n * traceId: \"trace-id-here\",\n * score: 0.95,\n * metadata: { model: \"gpt-4\" }\n * });\n *\n * @example\n * // Score by span ID\n * await evaluators.score({\n * name: \"relevance\",\n * spanId: \"span-id-here\",\n * score: 0.87\n * });\n */\n public async score(options: ScoreOptions): Promise<void> {\n const { name, metadata, score } = options;\n\n let payload: CreateEvaluatorScoreRequestWithTraceId | CreateEvaluatorScoreRequestWithSpanId;\n\n if ('traceId' in options && options.traceId) {\n const formattedTraceId = isStringUUID(options.traceId)\n ? options.traceId\n : otelTraceIdToUUID(options.traceId);\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n traceId: formattedTraceId,\n };\n } else if ('spanId' in options && options.spanId) {\n const formattedSpanId = isStringUUID(options.spanId)\n ? options.spanId\n : otelSpanIdToUUID(options.spanId) as StringUUID;\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n spanId: formattedSpanId,\n };\n } else {\n throw new Error(\"Either 'traceId' or 'spanId' must be provided.\");\n }\n\n const response = await fetch(this.baseHttpUrl + \"/v1/evaluators/score\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import {\n type CachedSpan,\n errorMessage,\n type SessionBlock,\n type SessionBlockContent,\n type SessionBlockType,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nconst logger = initializeLogger();\n\n/**\n * Result of a debug-replay cache lookup (debug-replay v2).\n *\n * - `hit` — the server served a cached response for this input hash; replay it\n * and mark the span CACHED.\n * - `miss` — no cache entry; the caller latches process-wide live mode and runs\n * every subsequent call live.\n * - `live` — run THIS call live without latching (server COLD warmup-timeout\n * degrade, or any non-OK / transport error here).\n */\nexport type CacheOutcome =\n | { kind: \"hit\"; cached: CachedSpan }\n | { kind: \"miss\" }\n | { kind: \"live\" };\n\n/**\n * Map the opaque HIT `response` payload onto a {@link CachedSpan} the provider\n * wrappers can replay. The server-side shape of `response` is not yet frozen\n * (app-server plan 01 leaves it as a `serde_json::Value`), so this stays\n * deliberately tolerant: the whole payload is serialized into `output` (the only\n * field the AI SDK wrapper's `parseCachedSpan` actually reads, via\n * `JSON.parse`), and a `finishReason` is surfaced into `attributes` when the\n * payload carries one. `name`/`input` are irrelevant to replay and left empty.\n */\nconst toCachedSpan = (response: unknown): CachedSpan => {\n const output =\n typeof response === \"string\" ? response : JSON.stringify(response ?? null);\n const attributes: Record<string, any> = {};\n if (\n response !== null &&\n typeof response === \"object\" &&\n typeof (response as Record<string, unknown>).finishReason === \"string\"\n ) {\n attributes[\"ai.response.finishReason\"] = (\n response as Record<string, unknown>\n ).finishReason;\n }\n return { name: \"\", input: \"\", output, attributes };\n};\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Idempotently register (upsert) a debug session on the backend, keyed on the\n * SDK-supplied session id. The backend stores the row so the session is\n * visible in the UI; a null/omitted name never clobbers a name set elsewhere.\n *\n * Returns the backend-resolved `projectId` (derived from the API key) so the\n * caller can build the debugger URL; null if the body can't be parsed.\n */\n public async register({\n sessionId,\n name,\n }: {\n sessionId: string;\n name?: string;\n }): Promise<string | null> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as { projectId?: string };\n return body.projectId ?? null;\n } catch (e) {\n logger.warn(\n `Failed to parse rollout register response: ${errorMessage(e)}`,\n );\n return null;\n }\n }\n\n /**\n * Rename an existing debug session. Update-only: the backend returns 404 (and\n * this throws) when the session id is unknown for the project, so a mistyped\n * id surfaces as an error rather than silently creating a session. Creation\n * stays the SDK's job via {@link register}.\n */\n public async setName({\n sessionId,\n name,\n }: {\n sessionId: string;\n name: string;\n }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/name`,\n {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Append a block to a debug session (debugger session blocks).\n *\n * A debug session renders as an ordered list of blocks; this writes one to the\n * backend keyed by session id. The CLI uses it for `text` blocks — standalone\n * agent notes attached post-factum via `lmnr-cli debug session add-note` — so\n * a note is tied to the SESSION, not to a specific trace / evaluation (those\n * blocks are written at ingest from `rollout.session_id` metadata).\n *\n * A 404 (the session is unknown for the project) is logged and swallowed\n * unless `failOnNotFound` is set — CLI callers pass it so an exit 0 means the\n * block actually landed. Any other non-OK status throws.\n *\n * Returns the created block id, or null when the response body can't be parsed.\n */\n public async addBlock({\n sessionId,\n type,\n content,\n failOnNotFound,\n signal,\n }: {\n sessionId: string;\n type: SessionBlockType;\n content: SessionBlockContent;\n failOnNotFound?: boolean;\n // Optional cancellation: aborting tears down the in-flight request so a\n // best-effort caller (e.g. the CLI's command tracking) can bound its own\n // deadline without a leaked socket keeping the process alive.\n signal?: AbortSignal;\n }): Promise<string | null> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/blocks`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ type, content }),\n signal,\n },\n );\n\n if (response.status === 404) {\n const message =\n `Could not add a note: HTTP 404 for session ${sessionId}. Either the ` +\n \"session isn't registered in this project (mint one with `lmnr-cli \" +\n \"debug session new`, or run under LMNR_DEBUG=1), or this Laminar server \" +\n \"doesn't expose the session-blocks write endpoint \" +\n \"(POST /v1/rollouts/{sessionId}/blocks) yet.\";\n if (failOnNotFound) {\n throw new Error(message);\n }\n logger.warn(message);\n return null;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as { id?: string };\n return body.id ?? null;\n } catch (e) {\n logger.warn(`Failed to parse add-block response: ${errorMessage(e)}`);\n return null;\n }\n }\n\n /**\n * List a debug session's blocks in creation order.\n *\n * Returns every `trace` / `evaluation` / `text` block on the session — the\n * same data the debugger UI renders. Used by `lmnr-cli debug session summary`\n * to print a chronological digest of the session. Returns an empty array when\n * the session has no blocks or the body can't be parsed.\n */\n public async listBlocks({\n sessionId,\n }: {\n sessionId: string;\n }): Promise<SessionBlock[]> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/blocks`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as\n | { blocks?: SessionBlock[] }\n | SessionBlock[];\n const blocks = Array.isArray(body) ? body : body.blocks;\n return blocks ?? [];\n } catch (e) {\n logger.warn(`Failed to parse list-blocks response: ${errorMessage(e)}`);\n return [];\n }\n }\n\n /**\n * Look up the debug-replay cache for a single LLM call (debug-replay v2).\n *\n * The server is keyed by `inputHash` (hex blake3 of the canonicalized,\n * system-stripped input messages). It returns one of three outcomes:\n * - `{ outcome: \"hit\", response }` — a cached response to replay.\n * - `{ outcome: \"miss\" }` — no entry; caller latches live mode.\n * - `{ outcome: \"live\" }` — run this call live (COLD degrade).\n *\n * Error posture: a non-OK response or a transport error degrades to\n * `{ kind: \"live\" }` for THIS call only — it never throws and never latches\n * the process-wide live flag (only a real MISS does that). This keeps a flaky\n * cache backend from turning a replay into a crash.\n */\n public async cache({\n sessionId,\n replayTraceId,\n cacheUntil,\n inputHash,\n }: {\n sessionId: string;\n replayTraceId: string;\n cacheUntil: string;\n inputHash: string;\n }): Promise<CacheOutcome> {\n let response: Response;\n try {\n response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/cache`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ replayTraceId, cacheUntil, inputHash }),\n },\n );\n } catch (e) {\n logger.warn(`Debug cache lookup failed, running live: ${errorMessage(e)}`);\n return { kind: \"live\" };\n }\n\n if (!response.ok) {\n logger.warn(\n `Debug cache lookup returned ${response.status}, running live`,\n );\n return { kind: \"live\" };\n }\n\n let body: { outcome?: string; response?: unknown };\n try {\n body = (await response.json()) as { outcome?: string; response?: unknown };\n } catch (e) {\n logger.warn(\n `Failed to parse debug cache response, running live: ${errorMessage(e)}`,\n );\n return { kind: \"live\" };\n }\n\n switch (body.outcome) {\n case \"hit\":\n // A HIT with no replayable payload (missing / JSON `null` response) is\n // useless: serializing it would store the string \"null\", which parses\n // back to `null` and crashes reconstruction. Degrade to live instead.\n if (body.response === null || body.response === undefined) {\n logger.warn(\"Debug cache HIT had no response payload, running live\");\n return { kind: \"live\" };\n }\n return { kind: \"hit\", cached: toCachedSpan(body.response) };\n case \"miss\":\n return { kind: \"miss\" };\n case \"live\":\n return { kind: \"live\" };\n default:\n logger.warn(\n `Unknown debug cache outcome \"${body.outcome}\", running live`,\n );\n return { kind: \"live\" };\n }\n }\n\n public async delete({ sessionId }: { sessionId: string }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`,\n {\n method: \"DELETE\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import {\n type Signal,\n type SignalStructuredOutput,\n type SignalTrigger,\n} from \"@lmnr-ai/types\";\n\nimport { BaseResource, type LaminarAuth } from \".\";\n\nexport interface CreateSignalOptions {\n name: string;\n prompt: string;\n structuredOutput: SignalStructuredOutput;\n sampleRate?: number;\n disabled?: boolean;\n /** Omit to seed the UI's default trigger; `[]` creates an inert signal. */\n triggers?: SignalTrigger[];\n}\n\n/**\n * A partial patch. Every field is optional and an ABSENT field leaves the stored\n * value alone — so updating the prompt can't clear sampling or re-enable a\n * deactivated signal. `sampleRate: null` explicitly clears sampling, and\n * `triggers` replaces the signal's whole trigger set when present.\n */\nexport interface UpdateSignalOptions {\n prompt?: string;\n structuredOutput?: SignalStructuredOutput;\n sampleRate?: number | null;\n disabled?: boolean;\n triggers?: SignalTrigger[];\n}\n\n/** Signals CRUD over the CLI user-token surface (`/v1/cli/signals`). */\nexport class SignalsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Every signal route answers errors as `{ error: \"<message>\" }`, and those\n * messages are written to be shown to the user verbatim (e.g. \"A signal named\n * X already exists in this project\"). The shared `handleError` would surface\n * the raw JSON body, so unwrap the envelope here and fall back to it when the\n * body isn't the expected shape.\n */\n private async raiseSignalError(response: Response): Promise<never> {\n const body = await response.text();\n let message = body;\n try {\n const parsed = JSON.parse(body) as { error?: unknown };\n if (typeof parsed?.error === \"string\" && parsed.error.length > 0) {\n message = parsed.error;\n }\n } catch {\n // Not JSON (a proxy error page, an actix plain-text 413) — use it as-is.\n }\n throw new Error(`${response.status} ${message}`);\n }\n\n public async list(name?: string): Promise<Signal[]> {\n const query = name ? `?${new URLSearchParams({ name }).toString()}` : \"\";\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/signals${query}`, {\n method: \"GET\",\n headers: this.headers(),\n });\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n // Coerce a missing/non-array `signals` to [] so callers can .map/.length it;\n // a malformed body on a 2xx is exceptional, not the normal empty case.\n const body = (await response.json()) as { signals?: Signal[] };\n return Array.isArray(body?.signals) ? body.signals : [];\n }\n\n public async get(signalId: string): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n { method: \"GET\", headers: this.headers() },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n public async create(options: CreateSignalOptions): Promise<Signal> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/signals`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(options),\n });\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n /**\n * PATCH, not PUT: only the keys present in `options` are sent, so the server\n * leaves everything else as stored. `sampleRate: null` must survive\n * serialization (it means \"clear\"), so it is NOT stripped here.\n */\n public async update(signalId: string, options: UpdateSignalOptions): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify(options),\n },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n /** Deletes the signal, its triggers, its alerts, and its ClickHouse events. */\n public async delete(signalId: string): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n { method: \"DELETE\", headers: this.headers() },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n}\n","import type { SqlSchema } from \"@lmnr-ai/types\";\n\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n public async query(\n sql: string,\n parameters: Record<string, any> = {},\n ): Promise<Array<Record<string, any>>> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/sql/query`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n },\n body: JSON.stringify({\n query: sql,\n parameters,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()).data as Array<Record<string, any>>;\n }\n\n /**\n * Fetch the queryable tables, columns, and enums. Server-rendered from\n * app-server's `query_engine::schema`, so it is the same source that backs\n * the MCP `query_laminar_sql` tool description — never a client-side copy.\n */\n public async schema(): Promise<SqlSchema> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/sql/schema`, {\n method: \"GET\",\n headers: {\n ...this.headers(),\n },\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as SqlSchema;\n }\n}\n","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Tag a trace with a list of tags. Note that the trace must be ended before\n * tagging it. You may want to call `await Laminar.flush()` after the trace\n * that you want to tag.\n *\n * @param {string | StringUUID} trace_id - The trace id to tag.\n * @param {string[] | string} tags - The tag or list of tags to add to the trace.\n * @returns {Promise<any>} The response from the server.\n * @example\n * ```javascript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n * let traceId: StringUUID | null = null;\n * // Make sure this is called outside of traced context.\n * await observe(\n * {\n * name: \"my-trace\",\n * },\n * async () => {\n * traceId = await Laminar.getTraceId();\n * await foo();\n * },\n * );\n *\n * // or make sure the trace is ended by this point.\n * await Laminar.flush();\n * if (traceId) {\n * await client.tags.tag(traceId, [\"tag1\", \"tag2\"]);\n * }\n * ```\n */\n public async tag(\n trace_id: string,\n tags: string[] | string,\n ): Promise<any> {\n const traceTags = Array.isArray(tags) ? tags : [tags];\n const formattedTraceId = isStringUUID(trace_id)\n ? trace_id\n : otelTraceIdToUUID(trace_id);\n\n const url = this.baseHttpUrl + \"/v1/tag\";\n const payload = {\n \"traceId\": formattedTraceId,\n \"names\": traceTags,\n };\n const response = await fetch(\n url,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n },\n );\n if (!response.ok) {\n await this.handleError(response);\n }\n return response.json();\n }\n}\n","/** Resource for post-factum operations on existing traces. */\n\nimport { initializeLogger, isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nconst logger = initializeLogger();\n\nexport class TracesResource extends BaseResource {\n /** Resource for post-factum operations on existing traces. */\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Push a metadata patch to an existing trace.\n *\n * The patch is shallow-merged server-side into the trace's existing metadata\n * (`existing || patch`, last-write-wins per top-level key). Useful for\n * attaching post-factum signals — quality scores, human edits, triage labels —\n * to a trace that has already finished. The patch does NOT extend `endTime`\n * or change tokens / cost / top span / tags / span names. `numSpans` is\n * incremented by 1 (paid by the virtual span that carried the patch through\n * the ingestion queue) so the new ClickHouse row beats the prior version on\n * `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.\n *\n * Compared to `Laminar.setTraceMetadata` (which sets metadata on the\n * currently in-flight trace via OpenTelemetry attributes), this method\n * operates on a finished trace by trace id, so it must be called after the\n * trace has been flushed.\n *\n * A 404 response (the trace was not found in the project — typically because\n * it has not been flushed yet) is logged as a warning and the call returns\n * without throwing, since the 404 may be expected when pushing too soon\n * after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.\n * CLI callers that must report the failure). Any other non-OK status throws.\n *\n * @param traceId - The trace id to push metadata to. Accepts a UUID string\n * or a 32-char OTel hex trace id.\n * @param metadata - The metadata patch. Top-level keys are merged into the\n * trace's existing metadata. Must be non-empty (the server rejects empty\n * patches with 400).\n * @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.\n * @example\n * ```typescript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n *\n * let traceId: string | null = null;\n * await observe({ name: \"generate\" }, async () => {\n * traceId = await Laminar.getTraceId();\n * });\n * await Laminar.flush();\n *\n * if (traceId) {\n * await client.traces.pushMetadata(traceId, {\n * score: 0.85,\n * reviewer: \"alice\",\n * needsReview: false,\n * });\n * }\n * ```\n */\n public async pushMetadata(\n traceId: string,\n metadata: Record<string, unknown>,\n options?: { failOnNotFound?: boolean },\n ): Promise<void> {\n if (!metadata || Object.keys(metadata).length === 0) {\n throw new Error(\"metadata must be a non-empty object\");\n }\n\n const formattedTraceId = isStringUUID(traceId)\n ? traceId\n : otelTraceIdToUUID(traceId);\n\n const url = this.baseHttpUrl + this.apiPrefix + \"/traces/metadata\";\n const response = await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n traceId: formattedTraceId,\n metadata,\n }),\n });\n\n if (response.status === 404) {\n const message =\n `Trace ${formattedTraceId} not found. The trace may not have been ` +\n \"flushed yet — call await Laminar.flush() and retry.\";\n if (options?.failOnNotFound) {\n throw new Error(message);\n }\n // Trace not found in this project — likely not flushed yet. Don't throw,\n // but surface a warning so callers debugging an empty patch see it.\n logger.warn(message);\n return;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { CliResource } from \"./resources/cli\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { type LaminarAuth } from \"./resources/index\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\nimport { SignalsResource } from \"./resources/signals\";\nimport { SqlResource } from \"./resources/sql\";\nimport { TagsResource } from \"./resources/tags\";\nimport { TracesResource } from \"./resources/traces\";\nimport { loadEnv } from \"./utils\";\n\nexport class LaminarClient {\n private baseUrl: string;\n private auth: LaminarAuth;\n private _browserEvents: BrowserEventsResource;\n private _cli: CliResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _signals: SignalsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n private _traces: TracesResource;\n\n constructor({\n baseUrl,\n port,\n auth,\n projectApiKey,\n cliUserProjectId,\n }: {\n baseUrl?: string,\n port?: number,\n /**\n * Unified auth. A discriminated union that drives both the URL prefix and\n * the request headers:\n * - `{ type: \"apiKey\", key }` → project key, `/v1/*`.\n * - `{ type: \"userToken\", token, projectId }` → user JWT, `/v1/cli/*` with\n * `x-lmnr-project-id`.\n * When omitted, the legacy `projectApiKey` / `cliUserProjectId` fields (or\n * `LMNR_PROJECT_API_KEY`) are normalized into this union.\n */\n auth?: LaminarAuth,\n /**\n * @deprecated Pass `auth: { type: \"apiKey\", key }` instead. Kept for\n * backward compatibility — normalized into the unified `auth` union.\n */\n projectApiKey?: string,\n /**\n * @deprecated Pass `auth: { type: \"userToken\", token, projectId }` instead.\n * Kept for backward compatibility: when set, the legacy `projectApiKey` is\n * treated as a user JWT and routes to `/v1/cli/*` with this project id.\n */\n cliUserProjectId?: string,\n } = {}) {\n loadEnv();\n this.auth = LaminarClient.normalizeAuth(auth, projectApiKey, cliUserProjectId);\n const httpPort = port ?? (\n baseUrl?.match(/:\\d{1,5}$/g)\n ? parseInt(baseUrl.match(/:\\d{1,5}$/g)![0].slice(1))\n : 443);\n const baseUrlNoPort = (baseUrl ?? process.env.LMNR_BASE_URL)\n ?.replace(/\\/$/, '').replace(/:\\d{1,5}$/g, '');\n this.baseUrl = `${baseUrlNoPort ?? 'https://api.lmnr.ai'}:${httpPort}`;\n this._browserEvents = new BrowserEventsResource(this.baseUrl, this.auth);\n this._cli = new CliResource(this.baseUrl, this.auth);\n this._datasets = new DatasetsResource(this.baseUrl, this.auth);\n this._evals = new EvalsResource(this.baseUrl, this.auth);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.auth);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.auth);\n this._signals = new SignalsResource(this.baseUrl, this.auth);\n this._sql = new SqlResource(this.baseUrl, this.auth);\n this._tags = new TagsResource(this.baseUrl, this.auth);\n this._traces = new TracesResource(this.baseUrl, this.auth);\n }\n\n /**\n * The fully-resolved API origin every resource fetches from, e.g.\n * `http://localhost:8000`. Already normalized: trailing slash removed, any\n * port embedded in `baseUrl` stripped, and the effective port appended.\n *\n * Exposed so callers can name the real address in diagnostics instead of\n * rebuilding it from `baseUrl` + `port` — that reconstruction drifts from\n * this normalization and prints things like `http://host:8000:9000`.\n */\n public get apiBaseUrl(): string {\n return this.baseUrl;\n }\n\n /**\n * Normalize the constructor's auth inputs into a {@link LaminarAuth} union.\n * Precedence: an explicit `auth` wins; otherwise the legacy\n * `projectApiKey` (+ optional `cliUserProjectId`) is mapped — a present\n * `cliUserProjectId` selects the user-token surface, otherwise the project\n * key surface. Falls back to `LMNR_PROJECT_API_KEY` as a project key.\n */\n private static normalizeAuth(\n auth: LaminarAuth | undefined,\n projectApiKey: string | undefined,\n cliUserProjectId: string | undefined,\n ): LaminarAuth {\n if (auth) {\n return auth;\n }\n const key = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\n if (cliUserProjectId) {\n return { type: \"userToken\", token: key, projectId: cliUserProjectId };\n }\n return { type: \"apiKey\", key };\n }\n\n public get browserEvents() {\n return this._browserEvents;\n }\n\n public get cli() {\n return this._cli;\n }\n\n public get datasets() {\n return this._datasets;\n }\n\n public get evals() {\n return this._evals;\n }\n\n public get evaluators() {\n return this._evaluators;\n }\n\n public get signals() {\n return this._signals;\n }\n\n public get rolloutSessions() {\n return this._rolloutSessions;\n }\n\n public get sql() {\n return this._sql;\n }\n\n public get tags() {\n return this._tags;\n }\n\n public get traces() {\n return this._traces;\n }\n}\n\nexport type { CliProject, ProjectKeyProbe } from \"./resources/cli\";\nexport type { LaminarAuth } from \"./resources/index\";\nexport {\n type CacheOutcome,\n RolloutSessionsResource,\n} from \"./resources/rollout-sessions\";\nexport type {\n CreateSignalOptions,\n UpdateSignalOptions,\n} from \"./resources/signals\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["SDK_VERSION","logger","logger","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/resources/cli.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.ts","../src/resources/signals.ts","../src/resources/sql.ts","../src/resources/tags.ts","../src/resources/traces.ts","../src/index.ts"],"sourcesContent":["","// Version detection for runtime environment\nexport function getLangVersion(): string | null {\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return `node-${process.versions.node}`;\n }\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return `browser-${navigator.userAgent}`;\n }\n return null;\n}\n","/**\n * Unified auth for every resource. A discriminated union so a single object\n * drives both the URL prefix and the request headers:\n *\n * - `apiKey` → project API key (SDK / app surfaces). Routes to `/v1/*`,\n * Bearer is the project key, no `x-lmnr-project-id` header.\n * - `userToken` → BetterAuth user access JWT (the CLI user-token surface).\n * Routes to `/v1/cli/*`, Bearer is the JWT, carries the target project in\n * the `x-lmnr-project-id` header.\n */\nexport type LaminarAuth =\n | { type: \"apiKey\"; key: string }\n | { type: \"userToken\"; token: string; projectId: string };\n\nclass BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly auth: LaminarAuth;\n /** The bearer credential, regardless of auth type (project key or user JWT). */\n protected readonly credential: string;\n\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n this.baseHttpUrl = baseHttpUrl;\n this.auth = auth;\n this.credential = auth.type === \"apiKey\" ? auth.key : auth.token;\n }\n\n /** API path prefix: `/v1/cli` for CLI user-token auth, `/v1` otherwise. */\n protected get apiPrefix(): string {\n return this.auth.type === \"userToken\" ? \"/v1/cli\" : \"/v1\";\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.credential}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...(this.auth.type === \"userToken\"\n ? { \"x-lmnr-project-id\": this.auth.projectId }\n : {}),\n };\n }\n\n protected async handleError(response: Response) {\n const errorMsg = await response.text();\n throw new Error(`${response.status} ${errorMsg}`);\n }\n}\n\nexport { BaseResource };\n","import { version as SDK_VERSION } from '../../package.json';\nimport { getLangVersion } from \"../version\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n public async send({\n sessionId,\n traceId,\n events,\n }: {\n sessionId: string;\n traceId: string;\n events: Record<string, any>[];\n }): Promise<void> {\n const payload = {\n sessionId,\n traceId,\n events,\n source: getLangVersion() ?? 'javascript',\n sdkVersion: SDK_VERSION,\n };\n\n const jsonString = JSON.stringify(payload);\n const blob = new Blob([jsonString], { type: 'application/json' });\n const compressedStream = blob.stream().pipeThrough(new CompressionStream('gzip'));\n const compressedResponse = new Response(compressedStream);\n const compressedData = await compressedResponse.arrayBuffer();\n\n const response = await fetch(this.baseHttpUrl + \"/v1/browser-sessions/events\", {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Content-Encoding': 'gzip',\n },\n body: compressedData,\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource, type LaminarAuth } from \"./index\";\n\nexport interface CliProject {\n id: string;\n name: string;\n workspaceId: string;\n workspaceName: string;\n}\n\n/**\n * Locale-aware, case-insensitive comparator for the project listing. Ordering\n * lives here — the single choke point every CLI surface (the `project list`\n * table + its `--json`, and the interactive picker used by `setup` / `plugin\n * add`) reads from — so the order can't drift between surfaces.\n */\nconst projectCollator = new Intl.Collator(undefined, { sensitivity: \"base\" });\n\n/** Sort projects by workspace name, then project name (stable, human-scannable). */\nconst sortProjects = (projects: CliProject[]): CliProject[] =>\n [...projects].sort(\n (a, b) =>\n projectCollator.compare(a.workspaceName ?? \"\", b.workspaceName ?? \"\") ||\n projectCollator.compare(a.name ?? \"\", b.name ?? \"\"),\n );\n\n/**\n * Outcome of resolving which project a project API key belongs to via the\n * user-token CLI endpoint. The states are deliberately distinct so the caller\n * doesn't conflate \"key is bad\" with \"couldn't reach the server\":\n * - `ok` → key verified AND the user is a member; `projectId` is its owner.\n * - `invalid` → 401: key revoked/invalid. Safe to mint a fresh one.\n * - `unverifiable` → 403 (key belongs to a project the user can't access) /\n * network error / other non-2xx / malformed body. The key may be perfectly\n * valid — caller MUST NOT mint (minting would clobber it on a blip).\n */\nexport type ProjectKeyProbe =\n | { status: \"ok\"; projectId: string }\n | { status: \"invalid\" }\n | { status: \"unverifiable\" };\n\n/**\n * User-scoped CLI endpoints that don't target a specific project. Authed by the\n * BetterAuth user JWT (the `credential`); deliberately does NOT send an\n * `x-lmnr-project-id` header (these routes are project discovery, pre-selection).\n *\n * Discovery exception: this resource always hits `/v1/cli/projects` with the\n * bare bearer and overrides `BaseResource.headers()`/`apiPrefix`, so it works\n * even when constructed with a `userToken` auth that has no real project id yet.\n */\nexport class CliResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /** Workspaces + projects the authenticated user can access. */\n public async listProjects(): Promise<CliProject[]> {\n const response = await fetch(`${this.baseHttpUrl}/v1/cli/projects`, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${this.credential}`,\n Accept: \"application/json\",\n },\n });\n if (!response.ok) {\n await this.handleError(response);\n }\n // Coerce a missing/non-array `projects` to [] so callers (.length/.map)\n // don't throw. A malformed body on a 2xx is exceptional — let it surface.\n // Sort here so every consumer inherits one stable, alphabetical order.\n const body = (await response.json()) as { projects?: CliProject[] };\n return Array.isArray(body?.projects) ? sortProjects(body.projects) : [];\n }\n\n /**\n * Resolve which project a project API key belongs to. Authed by the user JWT\n * (the bearer); the project key travels in the body, NOT in `Authorization`.\n * The server verifies the key and that the authenticated user is a member of\n * the resolved project. Returns a tri-state probe so callers can distinguish a\n * revoked key (401 → `invalid`) from a server/access problem (`unverifiable`).\n */\n public async resolveProjectByApiKey(apiKey: string): Promise<ProjectKeyProbe> {\n let response: Response;\n try {\n response = await fetch(`${this.baseHttpUrl}/v1/cli/project`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.credential}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({ apiKey }),\n });\n } catch {\n return { status: \"unverifiable\" };\n }\n if (response.status === 401) return { status: \"invalid\" };\n if (!response.ok) return { status: \"unverifiable\" };\n const body = (await response.json().catch(() => null)) as { projectId?: string } | null;\n return body?.projectId\n ? { status: \"ok\", projectId: body.projectId }\n : { status: \"unverifiable\" };\n }\n}\n","import { type StringUUID } from '@lmnr-ai/types';\nimport { config } from 'dotenv';\nimport * as path from 'path';\nimport pino, { Level } from 'pino';\nimport { PinoPretty } from 'pino-pretty';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport function initializeLogger(options?: { colorize?: boolean; level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level =\n options?.level ??\n (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level) ??\n 'info';\n\n return pino(\n {\n level,\n },\n PinoPretty({\n colorize,\n minimumLevel: level,\n }),\n );\n}\n\nconst logger = initializeLogger();\n\nexport const isStringUUID = (id: string): id is StringUUID =>\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);\n\nexport const NIL_UUID: StringUUID = '00000000-0000-0000-0000-000000000000';\n\nexport const newUUID = (): StringUUID => {\n // crypto.randomUUID is available in most of the modern browsers and node,\n // but is not available in \"insecure\" contexts, e.g. not https, not localhost\n // so we fallback to uuidv4 in those cases, which is less secure, but works\n // just fine.\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n } else {\n return uuidv4() as `${string}-${string}-${string}-${string}-${string}`;\n }\n};\n\nexport const otelSpanIdToUUID = (spanId: string): string => {\n let id = spanId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 16) {\n logger.warn(\n `Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.',\n );\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.padStart(32, '0').replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n );\n};\n\nexport const otelTraceIdToUUID = (traceId: string): StringUUID => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(\n `Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.',\n );\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n ) as StringUUID;\n};\n\nexport const slicePayload = <T>(value: T, length: number) => {\n if (value === null || value === undefined) {\n return value;\n }\n\n const str = JSON.stringify(value);\n if (str.length <= length) {\n return value;\n }\n\n return str.slice(0, length) + '...';\n};\n\nexport const loadEnv = (\n options?: {\n quiet?: boolean;\n paths?: string[];\n },\n): void => {\n const nodeEnv = process.env.NODE_ENV || 'development';\n const envDir = process.cwd();\n\n // Files to load in order (lowest to highest priority)\n // Later files override earlier ones\n const envFiles = [\n '.env',\n '.env.local',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`,\n ];\n\n const logLevel = process.env.LMNR_LOG_LEVEL ?? 'info';\n const verbose = ['debug', 'trace'].includes(logLevel.trim().toLowerCase());\n\n const quiet = options?.quiet ?? !verbose;\n\n config({\n path: options?.paths ?? envFiles.map((envFile) => path.resolve(envDir, envFile)),\n quiet,\n });\n};\n","import {\n type Datapoint,\n type Dataset,\n type GetDatapointsResponse,\n type PushDatapointsResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nconst logger = initializeLogger();\nconst DEFAULT_DATASET_PULL_LIMIT = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\n\nexport class DatasetsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * List all datasets.\n *\n * @returns {Promise<Dataset[]>} Array of datasets\n */\n public async listDatasets(): Promise<Dataset[]> {\n const response = await fetch(this.baseHttpUrl + this.apiPrefix + \"/datasets\", {\n method: \"GET\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Get a dataset by name.\n *\n * @param {string} name - Name of the dataset\n * @returns {Promise<Dataset[]>} Array of datasets with matching name\n */\n public async getDatasetByName(name: string): Promise<Dataset[]> {\n const params = new URLSearchParams({ name });\n const response = await fetch(\n this.baseHttpUrl + `${this.apiPrefix}/datasets?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Push datapoints to a dataset.\n *\n * @param {Object} options - Push options\n * @param {Datapoint<D, T>[]} options.points - Datapoints to push\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.batchSize] - Batch size for pushing (default: 100)\n * @param {boolean} [options.createDataset] - Whether to create the dataset if it doesn't exist\n * @returns {Promise<PushDatapointsResponse | undefined>}\n */\n public async push<D, T>({\n points,\n name,\n id,\n batchSize = DEFAULT_DATASET_PUSH_BATCH_SIZE,\n createDataset = false,\n }: {\n points: Datapoint<D, T>[];\n name?: string;\n id?: StringUUID;\n batchSize?: number;\n createDataset?: boolean;\n }): Promise<PushDatapointsResponse | undefined> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n if (createDataset && !name) {\n throw new Error(\"Name must be provided when creating a new dataset\");\n }\n\n const identifier = name ? { name } : { datasetId: id! };\n const totalBatches = Math.ceil(points.length / batchSize);\n\n let response: PushDatapointsResponse | undefined;\n for (let i = 0; i < points.length; i += batchSize) {\n const batchNum = Math.floor(i / batchSize) + 1;\n logger.debug(`Pushing batch ${batchNum} of ${totalBatches}`);\n\n const batch = points.slice(i, i + batchSize);\n const fetchResponse = await fetch(\n this.baseHttpUrl + this.apiPrefix + \"/datasets/datapoints\",\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n ...identifier,\n datapoints: batch.map((point) => ({\n data: point.data,\n target: point.target ?? {},\n metadata: point.metadata ?? {},\n })),\n createDataset,\n }),\n },\n );\n\n // 201 when creating a new dataset\n if (fetchResponse.status !== 200 && fetchResponse.status !== 201) {\n await this.handleError(fetchResponse);\n }\n\n response = (await fetchResponse.json()) as PushDatapointsResponse;\n }\n\n return response;\n }\n\n /**\n * Pull datapoints from a dataset.\n *\n * @param {Object} options - Pull options\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.limit] - Maximum number of datapoints to return (default: 100)\n * @param {number} [options.offset] - Offset for pagination (default: 0)\n * @returns {Promise<GetDatapointsResponse<D, T>>}\n */\n public async pull<D, T>({\n name,\n id,\n limit = DEFAULT_DATASET_PULL_LIMIT,\n offset = 0,\n }: {\n name?: string;\n id?: StringUUID;\n limit?: number;\n offset?: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n const paramsObj: Record<string, string> = {\n offset: offset.toString(),\n limit: limit.toString(),\n };\n\n if (name) {\n paramsObj.name = name;\n } else {\n paramsObj.datasetId = id!;\n }\n\n const params = new URLSearchParams(paramsObj);\n\n const response = await fetch(\n this.baseHttpUrl + `${this.apiPrefix}/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<GetDatapointsResponse<D, T>>;\n }\n}\n","import {\n type EvaluationDatapoint,\n type GetDatapointsResponse,\n type InitEvaluationResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger, newUUID, slicePayload } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nconst logger = initializeLogger();\nconst INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16_000_000; // 16MB\n\nexport class EvalsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Initialize an evaluation.\n *\n * @param {string} name - Name of the evaluation\n * @param {string} groupName - Group name of the evaluation\n * @param {Record<string, any>} metadata - Optional metadata\n * @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization\n */\n public async init(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + \"/v1/evals\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n groupName: groupName ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n *\n * @param {string} [name] - Optional name of the evaluation\n * @param {string} [groupName] - An identifier to group evaluations\n * @param {Record<string, any>} [metadata] - Optional metadata\n * @returns {Promise<StringUUID>} The evaluation ID\n */\n\n public async create(args?: {\n name?: string, groupName?: string, metadata?: Record<string, any>\n }): Promise<StringUUID> {\n const evaluation = await this.init(args?.name, args?.groupName, args?.metadata);\n return evaluation.id;\n }\n\n /**\n * Update an evaluation's name and/or metadata. The group ID is immutable.\n * Fields left undefined are kept unchanged.\n *\n * @param {Object} options - Update evaluation options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} [options.name] - New name of the evaluation\n * @param {Record<string, any>} [options.metadata] - New metadata for the evaluation\n * @returns {Promise<InitEvaluationResponse>} The updated evaluation\n */\n public async update({\n evalId,\n name,\n metadata,\n }: {\n evalId: string;\n name?: string;\n metadata?: Record<string, any>;\n }): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n * @deprecated use `create` instead.\n */\n public async createEvaluation(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<StringUUID> {\n const evaluation = await this.init(name, groupName, metadata);\n return evaluation.id;\n }\n\n /**\n * Create a datapoint for an evaluation.\n *\n * @param {Object} options - Create datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {D} options.data - The input data for the executor\n * @param {T} [options.target] - The target/expected output for evaluators\n * @param {Record<string, any>} [options.metadata] - Optional metadata\n * @param {number} [options.index] - Optional index of the datapoint\n * @param {string} [options.traceId] - Optional trace ID\n * @returns {Promise<StringUUID>} The datapoint ID\n */\n public async createDatapoint<D, T>({\n evalId,\n data,\n target,\n metadata,\n index,\n traceId,\n }: {\n evalId: string;\n data: D;\n target?: T;\n metadata?: Record<string, any>;\n index?: number;\n traceId?: string;\n }): Promise<StringUUID> {\n const datapointId = newUUID();\n\n const partialDatapoint: EvaluationDatapoint<D, T, any> = {\n id: datapointId,\n data,\n target,\n index: index ?? 0,\n traceId: traceId ?? newUUID(),\n executorSpanId: newUUID(),\n metadata,\n };\n\n await this.saveDatapoints({\n evalId,\n datapoints: [partialDatapoint],\n });\n\n return datapointId;\n }\n\n /**\n * Update a datapoint with evaluation results.\n *\n * @param {Object} options - Update datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} options.datapointId - The datapoint ID\n * @param {Record<string, number>} options.scores - The scores\n * @param {O} [options.executorOutput] - The executor output\n * @returns {Promise<void>}\n */\n public async updateDatapoint<O>({\n evalId,\n datapointId,\n scores,\n executorOutput,\n }: {\n evalId: string;\n datapointId: string;\n scores: Record<string, number>;\n executorOutput?: O;\n }): Promise<void> {\n const response = await fetch(\n this.baseHttpUrl + `/v1/evals/${evalId}/datapoints/${datapointId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n executorOutput,\n scores,\n }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Save evaluation datapoints.\n *\n * @param {Object} options - Save datapoints options\n * @param {string} options.evalId - ID of the evaluation\n * @param {EvaluationDatapoint<D, T, O>[]} options.datapoints - Datapoint to add\n * @param {string} [options.groupName] - Group name of the evaluation\n * @returns {Promise<void>} Response from the datapoint addition\n */\n public async saveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n }): Promise<void> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n target: slicePayload(d.target, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n executorOutput: slicePayload(\n d.executorOutput,\n INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n ),\n })),\n groupName: groupName ?? null,\n }),\n });\n\n if (response.status === 413) {\n return await this.retrySaveDatapoints({\n evalId,\n datapoints,\n groupName,\n });\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Get evaluation datapoints.\n *\n * @deprecated Use `client.datasets.pull()` instead.\n * @param {Object} options - Get datapoints options\n * @param {string} options.datasetName - Name of the dataset\n * @param {number} options.offset - Offset at which to start the query\n * @param {number} options.limit - Maximum number of datapoints to return\n * @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval\n */\n public async getDatapoints<D, T>({\n datasetName,\n offset,\n limit,\n }: {\n datasetName: string;\n offset: number;\n limit: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n logger.warn(\n 'evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.',\n );\n\n const params = new URLSearchParams({\n name: datasetName,\n offset: offset.toString(),\n limit: limit.toString(),\n });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as GetDatapointsResponse<D, T>;\n }\n\n private async retrySaveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n maxRetries = 25,\n initialLength = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n maxRetries?: number;\n initialLength?: number;\n }): Promise<void> {\n let length = initialLength;\n let lastResponse: Response | null = null;\n for (let i = 0; i < maxRetries; i++) {\n logger.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, length),\n target: slicePayload(d.target, length),\n executorOutput: slicePayload(d.executorOutput, length),\n })),\n groupName: groupName ?? null,\n }),\n });\n lastResponse = response;\n length = Math.floor(length / 2);\n if (response.status !== 413) {\n break;\n }\n }\n if (lastResponse && !lastResponse.ok) {\n await this.handleError(lastResponse);\n }\n }\n}\n","import { type StringUUID } from \"@lmnr-ai/types\";\n\nimport { isStringUUID, otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nenum EvaluatorScoreSourceType {\n Evaluator = \"Evaluator\",\n Code = \"Code\",\n}\n\ninterface CreateEvaluatorScoreBase {\n name: string;\n metadata?: Record<string, any>;\n score: number;\n source: EvaluatorScoreSourceType;\n}\n\ninterface CreateEvaluatorScoreRequestWithTraceId extends CreateEvaluatorScoreBase {\n traceId: string;\n}\n\ninterface CreateEvaluatorScoreRequestWithSpanId extends CreateEvaluatorScoreBase {\n spanId: string;\n}\n\ntype ScoreOptions =\n | { name: string; metadata?: Record<string, any>; score: number; traceId: string; }\n | { name: string; metadata?: Record<string, any>; score: number; spanId: string; };\n\n/**\n * Resource for creating evaluator scores\n */\nexport class EvaluatorsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Create a score for a span or trace\n *\n * @param {ScoreOptions} options - Score creation options\n * @param {string} options.name - Name of the score\n * @param {string} [options.traceId] - The trace ID to score (will be attached to top-level span)\n * @param {string} [options.spanId] - The span ID to score\n * @param {Record<string, any>} [options.metadata] - Additional metadata\n * @param {number} options.score - The score value (float)\n * @returns {Promise<void>}\n *\n * @example\n * // Score by trace ID (will attach to root span)\n * await evaluators.score({\n * name: \"quality\",\n * traceId: \"trace-id-here\",\n * score: 0.95,\n * metadata: { model: \"gpt-4\" }\n * });\n *\n * @example\n * // Score by span ID\n * await evaluators.score({\n * name: \"relevance\",\n * spanId: \"span-id-here\",\n * score: 0.87\n * });\n */\n public async score(options: ScoreOptions): Promise<void> {\n const { name, metadata, score } = options;\n\n let payload: CreateEvaluatorScoreRequestWithTraceId | CreateEvaluatorScoreRequestWithSpanId;\n\n if ('traceId' in options && options.traceId) {\n const formattedTraceId = isStringUUID(options.traceId)\n ? options.traceId\n : otelTraceIdToUUID(options.traceId);\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n traceId: formattedTraceId,\n };\n } else if ('spanId' in options && options.spanId) {\n const formattedSpanId = isStringUUID(options.spanId)\n ? options.spanId\n : otelSpanIdToUUID(options.spanId) as StringUUID;\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n spanId: formattedSpanId,\n };\n } else {\n throw new Error(\"Either 'traceId' or 'spanId' must be provided.\");\n }\n\n const response = await fetch(this.baseHttpUrl + \"/v1/evaluators/score\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import {\n type CachedSpan,\n errorMessage,\n type SessionBlock,\n type SessionBlockContent,\n type SessionBlockType,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nconst logger = initializeLogger();\n\n/**\n * Result of a debug-replay cache lookup (debug-replay v2).\n *\n * - `hit` — the server served a cached response for this input hash; replay it\n * and mark the span CACHED.\n * - `miss` — no cache entry; the caller latches process-wide live mode and runs\n * every subsequent call live.\n * - `live` — run THIS call live without latching (server COLD warmup-timeout\n * degrade, or any non-OK / transport error here).\n */\nexport type CacheOutcome =\n | { kind: \"hit\"; cached: CachedSpan }\n | { kind: \"miss\" }\n | { kind: \"live\" };\n\n/**\n * Map the opaque HIT `response` payload onto a {@link CachedSpan} the provider\n * wrappers can replay. The server-side shape of `response` is not yet frozen\n * (app-server plan 01 leaves it as a `serde_json::Value`), so this stays\n * deliberately tolerant: the whole payload is serialized into `output` (the only\n * field the AI SDK wrapper's `parseCachedSpan` actually reads, via\n * `JSON.parse`), and a `finishReason` is surfaced into `attributes` when the\n * payload carries one. `name`/`input` are irrelevant to replay and left empty.\n */\nconst toCachedSpan = (response: unknown): CachedSpan => {\n const output =\n typeof response === \"string\" ? response : JSON.stringify(response ?? null);\n const attributes: Record<string, any> = {};\n if (\n response !== null &&\n typeof response === \"object\" &&\n typeof (response as Record<string, unknown>).finishReason === \"string\"\n ) {\n attributes[\"ai.response.finishReason\"] = (\n response as Record<string, unknown>\n ).finishReason;\n }\n return { name: \"\", input: \"\", output, attributes };\n};\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Idempotently register (upsert) a debug session on the backend, keyed on the\n * SDK-supplied session id. The backend stores the row so the session is\n * visible in the UI; a null/omitted name never clobbers a name set elsewhere.\n *\n * Returns the backend-resolved `projectId` (derived from the API key) so the\n * caller can build the debugger URL; null if the body can't be parsed.\n */\n public async register({\n sessionId,\n name,\n }: {\n sessionId: string;\n name?: string;\n }): Promise<string | null> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as { projectId?: string };\n return body.projectId ?? null;\n } catch (e) {\n logger.warn(\n `Failed to parse rollout register response: ${errorMessage(e)}`,\n );\n return null;\n }\n }\n\n /**\n * Rename an existing debug session. Update-only: the backend returns 404 (and\n * this throws) when the session id is unknown for the project, so a mistyped\n * id surfaces as an error rather than silently creating a session. Creation\n * stays the SDK's job via {@link register}.\n */\n public async setName({\n sessionId,\n name,\n }: {\n sessionId: string;\n name: string;\n }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/name`,\n {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Append a block to a debug session (debugger session blocks).\n *\n * A debug session renders as an ordered list of blocks; this writes one to the\n * backend keyed by session id. The CLI uses it for `text` blocks — standalone\n * agent notes attached post-factum via `lmnr-cli debug session add-note` — so\n * a note is tied to the SESSION, not to a specific trace / evaluation (those\n * blocks are written at ingest from `rollout.session_id` metadata).\n *\n * A 404 (the session is unknown for the project) is logged and swallowed\n * unless `failOnNotFound` is set — CLI callers pass it so an exit 0 means the\n * block actually landed. Any other non-OK status throws.\n *\n * Returns the created block id, or null when the response body can't be parsed.\n */\n public async addBlock({\n sessionId,\n type,\n content,\n failOnNotFound,\n signal,\n }: {\n sessionId: string;\n type: SessionBlockType;\n content: SessionBlockContent;\n failOnNotFound?: boolean;\n // Optional cancellation: aborting tears down the in-flight request so a\n // best-effort caller (e.g. the CLI's command tracking) can bound its own\n // deadline without a leaked socket keeping the process alive.\n signal?: AbortSignal;\n }): Promise<string | null> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/blocks`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ type, content }),\n signal,\n },\n );\n\n if (response.status === 404) {\n const message =\n `Could not add a note: HTTP 404 for session ${sessionId}. Either the ` +\n \"session isn't registered in this project (mint one with `lmnr-cli \" +\n \"debug session new`, or run under LMNR_DEBUG=1), or this Laminar server \" +\n \"doesn't expose the session-blocks write endpoint \" +\n \"(POST /v1/rollouts/{sessionId}/blocks) yet.\";\n if (failOnNotFound) {\n throw new Error(message);\n }\n logger.warn(message);\n return null;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as { id?: string };\n return body.id ?? null;\n } catch (e) {\n logger.warn(`Failed to parse add-block response: ${errorMessage(e)}`);\n return null;\n }\n }\n\n /**\n * List a debug session's blocks in creation order.\n *\n * Returns every `trace` / `evaluation` / `text` block on the session — the\n * same data the debugger UI renders. Used by `lmnr-cli debug session summary`\n * to print a chronological digest of the session. Returns an empty array when\n * the session has no blocks or the body can't be parsed.\n */\n public async listBlocks({\n sessionId,\n }: {\n sessionId: string;\n }): Promise<SessionBlock[]> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/blocks`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as\n | { blocks?: SessionBlock[] }\n | SessionBlock[];\n const blocks = Array.isArray(body) ? body : body.blocks;\n return blocks ?? [];\n } catch (e) {\n logger.warn(`Failed to parse list-blocks response: ${errorMessage(e)}`);\n return [];\n }\n }\n\n /**\n * Look up the debug-replay cache for a single LLM call (debug-replay v2).\n *\n * The server is keyed by `inputHash` (hex blake3 of the canonicalized,\n * system-stripped input messages). It returns one of three outcomes:\n * - `{ outcome: \"hit\", response }` — a cached response to replay.\n * - `{ outcome: \"miss\" }` — no entry; caller latches live mode.\n * - `{ outcome: \"live\" }` — run this call live (COLD degrade).\n *\n * Error posture: a non-OK response or a transport error degrades to\n * `{ kind: \"live\" }` for THIS call only — it never throws and never latches\n * the process-wide live flag (only a real MISS does that). This keeps a flaky\n * cache backend from turning a replay into a crash.\n */\n public async cache({\n sessionId,\n replayTraceId,\n cacheUntil,\n inputHash,\n }: {\n sessionId: string;\n replayTraceId: string;\n cacheUntil: string;\n inputHash: string;\n }): Promise<CacheOutcome> {\n let response: Response;\n try {\n response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/cache`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ replayTraceId, cacheUntil, inputHash }),\n },\n );\n } catch (e) {\n logger.warn(`Debug cache lookup failed, running live: ${errorMessage(e)}`);\n return { kind: \"live\" };\n }\n\n if (!response.ok) {\n logger.warn(\n `Debug cache lookup returned ${response.status}, running live`,\n );\n return { kind: \"live\" };\n }\n\n let body: { outcome?: string; response?: unknown };\n try {\n body = (await response.json()) as { outcome?: string; response?: unknown };\n } catch (e) {\n logger.warn(\n `Failed to parse debug cache response, running live: ${errorMessage(e)}`,\n );\n return { kind: \"live\" };\n }\n\n switch (body.outcome) {\n case \"hit\":\n // A HIT with no replayable payload (missing / JSON `null` response) is\n // useless: serializing it would store the string \"null\", which parses\n // back to `null` and crashes reconstruction. Degrade to live instead.\n if (body.response === null || body.response === undefined) {\n logger.warn(\"Debug cache HIT had no response payload, running live\");\n return { kind: \"live\" };\n }\n return { kind: \"hit\", cached: toCachedSpan(body.response) };\n case \"miss\":\n return { kind: \"miss\" };\n case \"live\":\n return { kind: \"live\" };\n default:\n logger.warn(\n `Unknown debug cache outcome \"${body.outcome}\", running live`,\n );\n return { kind: \"live\" };\n }\n }\n\n public async delete({ sessionId }: { sessionId: string }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`,\n {\n method: \"DELETE\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import {\n type Signal,\n type SignalFilter,\n type SignalMode,\n type SignalStructuredOutput,\n type SignalTrigger,\n} from \"@lmnr-ai/types\";\n\nimport { BaseResource, type LaminarAuth } from \".\";\n\nexport interface CreateSignalOptions {\n name: string;\n prompt: string;\n structuredOutput: SignalStructuredOutput;\n /** Omit for no sampling. */\n sampleRate?: number;\n disabled?: boolean;\n /** Omit for the default (root span finished). */\n trigger?: SignalTrigger;\n /** Omit for the default (>1000 tokens); `[]` runs on every firing trace. */\n filters?: SignalFilter[];\n /** Defaults to `\"realtime\"`. */\n mode?: SignalMode;\n}\n\n/**\n * A partial patch. Every field is optional and an ABSENT field leaves the stored\n * value alone. `sampleRate: null` clears sampling, `filters: []` clears filters.\n */\nexport interface UpdateSignalOptions {\n prompt?: string;\n structuredOutput?: SignalStructuredOutput;\n sampleRate?: number | null;\n disabled?: boolean;\n trigger?: SignalTrigger;\n filters?: SignalFilter[];\n mode?: SignalMode;\n}\n\n/** Signals CRUD over the CLI user-token surface (`/v1/cli/signals`). */\nexport class SignalsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Every signal route answers errors as `{ error: \"<message>\" }`, and those\n * messages are written to be shown to the user verbatim (e.g. \"A signal named\n * X already exists in this project\"). The shared `handleError` would surface\n * the raw JSON body, so unwrap the envelope here and fall back to it when the\n * body isn't the expected shape.\n */\n private async raiseSignalError(response: Response): Promise<never> {\n const body = await response.text();\n let message = body;\n try {\n const parsed = JSON.parse(body) as { error?: unknown };\n if (typeof parsed?.error === \"string\" && parsed.error.length > 0) {\n message = parsed.error;\n }\n } catch {\n // Not JSON (a proxy error page, an actix plain-text 413) — use it as-is.\n }\n throw new Error(`${response.status} ${message}`);\n }\n\n public async list(name?: string): Promise<Signal[]> {\n const query = name ? `?${new URLSearchParams({ name }).toString()}` : \"\";\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/signals${query}`, {\n method: \"GET\",\n headers: this.headers(),\n });\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n // Coerce a missing/non-array `signals` to [] so callers can .map/.length it;\n // a malformed body on a 2xx is exceptional, not the normal empty case.\n const body = (await response.json()) as { signals?: Signal[] };\n return Array.isArray(body?.signals) ? body.signals : [];\n }\n\n public async get(signalId: string): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n { method: \"GET\", headers: this.headers() },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n public async create(options: CreateSignalOptions): Promise<Signal> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/signals`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(options),\n });\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n /**\n * PATCH, not PUT: only the keys present in `options` are sent, so the server\n * leaves everything else as stored. An explicit `null` on `sampleRate` must\n * survive serialization (it means \"clear\"), so nulls are NOT stripped here.\n */\n public async update(signalId: string, options: UpdateSignalOptions): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify(options),\n },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n /** Deletes the signal, its triggers, its alerts, and its ClickHouse events. */\n public async delete(signalId: string): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n { method: \"DELETE\", headers: this.headers() },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n}\n","import type { SqlSchema } from \"@lmnr-ai/types\";\n\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n public async query(\n sql: string,\n parameters: Record<string, any> = {},\n ): Promise<Array<Record<string, any>>> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/sql/query`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n },\n body: JSON.stringify({\n query: sql,\n parameters,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()).data as Array<Record<string, any>>;\n }\n\n /**\n * Fetch the queryable tables, columns, and enums. Server-rendered from\n * app-server's `query_engine::schema`, so it is the same source that backs\n * the MCP `query_laminar_sql` tool description — never a client-side copy.\n */\n public async schema(): Promise<SqlSchema> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/sql/schema`, {\n method: \"GET\",\n headers: {\n ...this.headers(),\n },\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as SqlSchema;\n }\n}\n","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Tag a trace with a list of tags. Note that the trace must be ended before\n * tagging it. You may want to call `await Laminar.flush()` after the trace\n * that you want to tag.\n *\n * @param {string | StringUUID} trace_id - The trace id to tag.\n * @param {string[] | string} tags - The tag or list of tags to add to the trace.\n * @returns {Promise<any>} The response from the server.\n * @example\n * ```javascript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n * let traceId: StringUUID | null = null;\n * // Make sure this is called outside of traced context.\n * await observe(\n * {\n * name: \"my-trace\",\n * },\n * async () => {\n * traceId = await Laminar.getTraceId();\n * await foo();\n * },\n * );\n *\n * // or make sure the trace is ended by this point.\n * await Laminar.flush();\n * if (traceId) {\n * await client.tags.tag(traceId, [\"tag1\", \"tag2\"]);\n * }\n * ```\n */\n public async tag(\n trace_id: string,\n tags: string[] | string,\n ): Promise<any> {\n const traceTags = Array.isArray(tags) ? tags : [tags];\n const formattedTraceId = isStringUUID(trace_id)\n ? trace_id\n : otelTraceIdToUUID(trace_id);\n\n const url = this.baseHttpUrl + \"/v1/tag\";\n const payload = {\n \"traceId\": formattedTraceId,\n \"names\": traceTags,\n };\n const response = await fetch(\n url,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n },\n );\n if (!response.ok) {\n await this.handleError(response);\n }\n return response.json();\n }\n}\n","/** Resource for post-factum operations on existing traces. */\n\nimport { initializeLogger, isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nconst logger = initializeLogger();\n\nexport class TracesResource extends BaseResource {\n /** Resource for post-factum operations on existing traces. */\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Push a metadata patch to an existing trace.\n *\n * The patch is shallow-merged server-side into the trace's existing metadata\n * (`existing || patch`, last-write-wins per top-level key). Useful for\n * attaching post-factum signals — quality scores, human edits, triage labels —\n * to a trace that has already finished. The patch does NOT extend `endTime`\n * or change tokens / cost / top span / tags / span names. `numSpans` is\n * incremented by 1 (paid by the virtual span that carried the patch through\n * the ingestion queue) so the new ClickHouse row beats the prior version on\n * `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.\n *\n * Compared to `Laminar.setTraceMetadata` (which sets metadata on the\n * currently in-flight trace via OpenTelemetry attributes), this method\n * operates on a finished trace by trace id, so it must be called after the\n * trace has been flushed.\n *\n * A 404 response (the trace was not found in the project — typically because\n * it has not been flushed yet) is logged as a warning and the call returns\n * without throwing, since the 404 may be expected when pushing too soon\n * after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.\n * CLI callers that must report the failure). Any other non-OK status throws.\n *\n * @param traceId - The trace id to push metadata to. Accepts a UUID string\n * or a 32-char OTel hex trace id.\n * @param metadata - The metadata patch. Top-level keys are merged into the\n * trace's existing metadata. Must be non-empty (the server rejects empty\n * patches with 400).\n * @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.\n * @example\n * ```typescript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n *\n * let traceId: string | null = null;\n * await observe({ name: \"generate\" }, async () => {\n * traceId = await Laminar.getTraceId();\n * });\n * await Laminar.flush();\n *\n * if (traceId) {\n * await client.traces.pushMetadata(traceId, {\n * score: 0.85,\n * reviewer: \"alice\",\n * needsReview: false,\n * });\n * }\n * ```\n */\n public async pushMetadata(\n traceId: string,\n metadata: Record<string, unknown>,\n options?: { failOnNotFound?: boolean },\n ): Promise<void> {\n if (!metadata || Object.keys(metadata).length === 0) {\n throw new Error(\"metadata must be a non-empty object\");\n }\n\n const formattedTraceId = isStringUUID(traceId)\n ? traceId\n : otelTraceIdToUUID(traceId);\n\n const url = this.baseHttpUrl + this.apiPrefix + \"/traces/metadata\";\n const response = await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n traceId: formattedTraceId,\n metadata,\n }),\n });\n\n if (response.status === 404) {\n const message =\n `Trace ${formattedTraceId} not found. The trace may not have been ` +\n \"flushed yet — call await Laminar.flush() and retry.\";\n if (options?.failOnNotFound) {\n throw new Error(message);\n }\n // Trace not found in this project — likely not flushed yet. Don't throw,\n // but surface a warning so callers debugging an empty patch see it.\n logger.warn(message);\n return;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { CliResource } from \"./resources/cli\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { type LaminarAuth } from \"./resources/index\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\nimport { SignalsResource } from \"./resources/signals\";\nimport { SqlResource } from \"./resources/sql\";\nimport { TagsResource } from \"./resources/tags\";\nimport { TracesResource } from \"./resources/traces\";\nimport { loadEnv } from \"./utils\";\n\nexport class LaminarClient {\n private baseUrl: string;\n private auth: LaminarAuth;\n private _browserEvents: BrowserEventsResource;\n private _cli: CliResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _signals: SignalsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n private _traces: TracesResource;\n\n constructor({\n baseUrl,\n port,\n auth,\n projectApiKey,\n cliUserProjectId,\n }: {\n baseUrl?: string,\n port?: number,\n /**\n * Unified auth. A discriminated union that drives both the URL prefix and\n * the request headers:\n * - `{ type: \"apiKey\", key }` → project key, `/v1/*`.\n * - `{ type: \"userToken\", token, projectId }` → user JWT, `/v1/cli/*` with\n * `x-lmnr-project-id`.\n * When omitted, the legacy `projectApiKey` / `cliUserProjectId` fields (or\n * `LMNR_PROJECT_API_KEY`) are normalized into this union.\n */\n auth?: LaminarAuth,\n /**\n * @deprecated Pass `auth: { type: \"apiKey\", key }` instead. Kept for\n * backward compatibility — normalized into the unified `auth` union.\n */\n projectApiKey?: string,\n /**\n * @deprecated Pass `auth: { type: \"userToken\", token, projectId }` instead.\n * Kept for backward compatibility: when set, the legacy `projectApiKey` is\n * treated as a user JWT and routes to `/v1/cli/*` with this project id.\n */\n cliUserProjectId?: string,\n } = {}) {\n loadEnv();\n this.auth = LaminarClient.normalizeAuth(auth, projectApiKey, cliUserProjectId);\n const httpPort = port ?? (\n baseUrl?.match(/:\\d{1,5}$/g)\n ? parseInt(baseUrl.match(/:\\d{1,5}$/g)![0].slice(1))\n : 443);\n const baseUrlNoPort = (baseUrl ?? process.env.LMNR_BASE_URL)\n ?.replace(/\\/$/, '').replace(/:\\d{1,5}$/g, '');\n this.baseUrl = `${baseUrlNoPort ?? 'https://api.lmnr.ai'}:${httpPort}`;\n this._browserEvents = new BrowserEventsResource(this.baseUrl, this.auth);\n this._cli = new CliResource(this.baseUrl, this.auth);\n this._datasets = new DatasetsResource(this.baseUrl, this.auth);\n this._evals = new EvalsResource(this.baseUrl, this.auth);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.auth);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.auth);\n this._signals = new SignalsResource(this.baseUrl, this.auth);\n this._sql = new SqlResource(this.baseUrl, this.auth);\n this._tags = new TagsResource(this.baseUrl, this.auth);\n this._traces = new TracesResource(this.baseUrl, this.auth);\n }\n\n /**\n * The fully-resolved API origin every resource fetches from, e.g.\n * `http://localhost:8000`. Already normalized: trailing slash removed, any\n * port embedded in `baseUrl` stripped, and the effective port appended.\n *\n * Exposed so callers can name the real address in diagnostics instead of\n * rebuilding it from `baseUrl` + `port` — that reconstruction drifts from\n * this normalization and prints things like `http://host:8000:9000`.\n */\n public get apiBaseUrl(): string {\n return this.baseUrl;\n }\n\n /**\n * Normalize the constructor's auth inputs into a {@link LaminarAuth} union.\n * Precedence: an explicit `auth` wins; otherwise the legacy\n * `projectApiKey` (+ optional `cliUserProjectId`) is mapped — a present\n * `cliUserProjectId` selects the user-token surface, otherwise the project\n * key surface. Falls back to `LMNR_PROJECT_API_KEY` as a project key.\n */\n private static normalizeAuth(\n auth: LaminarAuth | undefined,\n projectApiKey: string | undefined,\n cliUserProjectId: string | undefined,\n ): LaminarAuth {\n if (auth) {\n return auth;\n }\n const key = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\n if (cliUserProjectId) {\n return { type: \"userToken\", token: key, projectId: cliUserProjectId };\n }\n return { type: \"apiKey\", key };\n }\n\n public get browserEvents() {\n return this._browserEvents;\n }\n\n public get cli() {\n return this._cli;\n }\n\n public get datasets() {\n return this._datasets;\n }\n\n public get evals() {\n return this._evals;\n }\n\n public get evaluators() {\n return this._evaluators;\n }\n\n public get signals() {\n return this._signals;\n }\n\n public get rolloutSessions() {\n return this._rolloutSessions;\n }\n\n public get sql() {\n return this._sql;\n }\n\n public get tags() {\n return this._tags;\n }\n\n public get traces() {\n return this._traces;\n }\n}\n\nexport type { CliProject, ProjectKeyProbe } from \"./resources/cli\";\nexport type { LaminarAuth } from \"./resources/index\";\nexport {\n type CacheOutcome,\n RolloutSessionsResource,\n} from \"./resources/rollout-sessions\";\nexport type {\n CreateSignalOptions,\n UpdateSignalOptions,\n} from \"./resources/signals\";\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CachedSpan, Datapoint, Dataset, EvaluationDatapoint, GetDatapointsResponse, InitEvaluationResponse, PushDatapointsResponse, SessionBlock, SessionBlockContent, SessionBlockType, Signal, SignalStructuredOutput, SignalTrigger, SqlSchema, StringUUID } from "@lmnr-ai/types";
|
|
1
|
+
import { CachedSpan, Datapoint, Dataset, EvaluationDatapoint, GetDatapointsResponse, InitEvaluationResponse, PushDatapointsResponse, SessionBlock, SessionBlockContent, SessionBlockType, Signal, SignalFilter, SignalMode, SignalStructuredOutput, SignalTrigger, SqlSchema, StringUUID } from "@lmnr-ai/types";
|
|
2
2
|
|
|
3
3
|
//#region src/resources/index.d.ts
|
|
4
4
|
/**
|
|
@@ -473,23 +473,28 @@ interface CreateSignalOptions {
|
|
|
473
473
|
name: string;
|
|
474
474
|
prompt: string;
|
|
475
475
|
structuredOutput: SignalStructuredOutput;
|
|
476
|
+
/** Omit for no sampling. */
|
|
476
477
|
sampleRate?: number;
|
|
477
478
|
disabled?: boolean;
|
|
478
|
-
/** Omit
|
|
479
|
-
|
|
479
|
+
/** Omit for the default (root span finished). */
|
|
480
|
+
trigger?: SignalTrigger;
|
|
481
|
+
/** Omit for the default (>1000 tokens); `[]` runs on every firing trace. */
|
|
482
|
+
filters?: SignalFilter[];
|
|
483
|
+
/** Defaults to `"realtime"`. */
|
|
484
|
+
mode?: SignalMode;
|
|
480
485
|
}
|
|
481
486
|
/**
|
|
482
487
|
* A partial patch. Every field is optional and an ABSENT field leaves the stored
|
|
483
|
-
* value alone
|
|
484
|
-
* deactivated signal. `sampleRate: null` explicitly clears sampling, and
|
|
485
|
-
* `triggers` replaces the signal's whole trigger set when present.
|
|
488
|
+
* value alone. `sampleRate: null` clears sampling, `filters: []` clears filters.
|
|
486
489
|
*/
|
|
487
490
|
interface UpdateSignalOptions {
|
|
488
491
|
prompt?: string;
|
|
489
492
|
structuredOutput?: SignalStructuredOutput;
|
|
490
493
|
sampleRate?: number | null;
|
|
491
494
|
disabled?: boolean;
|
|
492
|
-
|
|
495
|
+
trigger?: SignalTrigger;
|
|
496
|
+
filters?: SignalFilter[];
|
|
497
|
+
mode?: SignalMode;
|
|
493
498
|
}
|
|
494
499
|
/** Signals CRUD over the CLI user-token surface (`/v1/cli/signals`). */
|
|
495
500
|
declare class SignalsResource extends BaseResource {
|
|
@@ -507,8 +512,8 @@ declare class SignalsResource extends BaseResource {
|
|
|
507
512
|
create(options: CreateSignalOptions): Promise<Signal>;
|
|
508
513
|
/**
|
|
509
514
|
* PATCH, not PUT: only the keys present in `options` are sent, so the server
|
|
510
|
-
* leaves everything else as stored. `
|
|
511
|
-
* serialization (it means "clear"), so
|
|
515
|
+
* leaves everything else as stored. An explicit `null` on `sampleRate` must
|
|
516
|
+
* survive serialization (it means "clear"), so nulls are NOT stripped here.
|
|
512
517
|
*/
|
|
513
518
|
update(signalId: string, options: UpdateSignalOptions): Promise<Signal>;
|
|
514
519
|
/** Deletes the signal, its triggers, its alerts, and its ClickHouse events. */
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CachedSpan, Datapoint, Dataset, EvaluationDatapoint, GetDatapointsResponse, InitEvaluationResponse, PushDatapointsResponse, SessionBlock, SessionBlockContent, SessionBlockType, Signal, SignalStructuredOutput, SignalTrigger, SqlSchema, StringUUID } from "@lmnr-ai/types";
|
|
1
|
+
import { CachedSpan, Datapoint, Dataset, EvaluationDatapoint, GetDatapointsResponse, InitEvaluationResponse, PushDatapointsResponse, SessionBlock, SessionBlockContent, SessionBlockType, Signal, SignalFilter, SignalMode, SignalStructuredOutput, SignalTrigger, SqlSchema, StringUUID } from "@lmnr-ai/types";
|
|
2
2
|
|
|
3
3
|
//#region src/resources/index.d.ts
|
|
4
4
|
/**
|
|
@@ -473,23 +473,28 @@ interface CreateSignalOptions {
|
|
|
473
473
|
name: string;
|
|
474
474
|
prompt: string;
|
|
475
475
|
structuredOutput: SignalStructuredOutput;
|
|
476
|
+
/** Omit for no sampling. */
|
|
476
477
|
sampleRate?: number;
|
|
477
478
|
disabled?: boolean;
|
|
478
|
-
/** Omit
|
|
479
|
-
|
|
479
|
+
/** Omit for the default (root span finished). */
|
|
480
|
+
trigger?: SignalTrigger;
|
|
481
|
+
/** Omit for the default (>1000 tokens); `[]` runs on every firing trace. */
|
|
482
|
+
filters?: SignalFilter[];
|
|
483
|
+
/** Defaults to `"realtime"`. */
|
|
484
|
+
mode?: SignalMode;
|
|
480
485
|
}
|
|
481
486
|
/**
|
|
482
487
|
* A partial patch. Every field is optional and an ABSENT field leaves the stored
|
|
483
|
-
* value alone
|
|
484
|
-
* deactivated signal. `sampleRate: null` explicitly clears sampling, and
|
|
485
|
-
* `triggers` replaces the signal's whole trigger set when present.
|
|
488
|
+
* value alone. `sampleRate: null` clears sampling, `filters: []` clears filters.
|
|
486
489
|
*/
|
|
487
490
|
interface UpdateSignalOptions {
|
|
488
491
|
prompt?: string;
|
|
489
492
|
structuredOutput?: SignalStructuredOutput;
|
|
490
493
|
sampleRate?: number | null;
|
|
491
494
|
disabled?: boolean;
|
|
492
|
-
|
|
495
|
+
trigger?: SignalTrigger;
|
|
496
|
+
filters?: SignalFilter[];
|
|
497
|
+
mode?: SignalMode;
|
|
493
498
|
}
|
|
494
499
|
/** Signals CRUD over the CLI user-token surface (`/v1/cli/signals`). */
|
|
495
500
|
declare class SignalsResource extends BaseResource {
|
|
@@ -507,8 +512,8 @@ declare class SignalsResource extends BaseResource {
|
|
|
507
512
|
create(options: CreateSignalOptions): Promise<Signal>;
|
|
508
513
|
/**
|
|
509
514
|
* PATCH, not PUT: only the keys present in `options` are sent, so the server
|
|
510
|
-
* leaves everything else as stored. `
|
|
511
|
-
* serialization (it means "clear"), so
|
|
515
|
+
* leaves everything else as stored. An explicit `null` on `sampleRate` must
|
|
516
|
+
* survive serialization (it means "clear"), so nulls are NOT stripped here.
|
|
512
517
|
*/
|
|
513
518
|
update(signalId: string, options: UpdateSignalOptions): Promise<Signal>;
|
|
514
519
|
/** Deletes the signal, its triggers, its alerts, and its ClickHouse events. */
|
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { PinoPretty } from "pino-pretty";
|
|
|
5
5
|
import { v4 } from "uuid";
|
|
6
6
|
import { errorMessage } from "@lmnr-ai/types";
|
|
7
7
|
//#region package.json
|
|
8
|
-
var version = "0.8.
|
|
8
|
+
var version = "0.8.43";
|
|
9
9
|
//#endregion
|
|
10
10
|
//#region src/version.ts
|
|
11
11
|
function getLangVersion() {
|
|
@@ -801,8 +801,8 @@ var SignalsResource = class extends BaseResource {
|
|
|
801
801
|
}
|
|
802
802
|
/**
|
|
803
803
|
* PATCH, not PUT: only the keys present in `options` are sent, so the server
|
|
804
|
-
* leaves everything else as stored. `
|
|
805
|
-
* serialization (it means "clear"), so
|
|
804
|
+
* leaves everything else as stored. An explicit `null` on `sampleRate` must
|
|
805
|
+
* survive serialization (it means "clear"), so nulls are NOT stripped here.
|
|
806
806
|
*/
|
|
807
807
|
async update(signalId, options) {
|
|
808
808
|
const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`, {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["SDK_VERSION","logger","uuidv4","logger","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/resources/cli.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.ts","../src/resources/signals.ts","../src/resources/sql.ts","../src/resources/tags.ts","../src/resources/traces.ts","../src/index.ts"],"sourcesContent":["","// Version detection for runtime environment\nexport function getLangVersion(): string | null {\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return `node-${process.versions.node}`;\n }\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return `browser-${navigator.userAgent}`;\n }\n return null;\n}\n","/**\n * Unified auth for every resource. A discriminated union so a single object\n * drives both the URL prefix and the request headers:\n *\n * - `apiKey` → project API key (SDK / app surfaces). Routes to `/v1/*`,\n * Bearer is the project key, no `x-lmnr-project-id` header.\n * - `userToken` → BetterAuth user access JWT (the CLI user-token surface).\n * Routes to `/v1/cli/*`, Bearer is the JWT, carries the target project in\n * the `x-lmnr-project-id` header.\n */\nexport type LaminarAuth =\n | { type: \"apiKey\"; key: string }\n | { type: \"userToken\"; token: string; projectId: string };\n\nclass BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly auth: LaminarAuth;\n /** The bearer credential, regardless of auth type (project key or user JWT). */\n protected readonly credential: string;\n\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n this.baseHttpUrl = baseHttpUrl;\n this.auth = auth;\n this.credential = auth.type === \"apiKey\" ? auth.key : auth.token;\n }\n\n /** API path prefix: `/v1/cli` for CLI user-token auth, `/v1` otherwise. */\n protected get apiPrefix(): string {\n return this.auth.type === \"userToken\" ? \"/v1/cli\" : \"/v1\";\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.credential}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...(this.auth.type === \"userToken\"\n ? { \"x-lmnr-project-id\": this.auth.projectId }\n : {}),\n };\n }\n\n protected async handleError(response: Response) {\n const errorMsg = await response.text();\n throw new Error(`${response.status} ${errorMsg}`);\n }\n}\n\nexport { BaseResource };\n","import { version as SDK_VERSION } from '../../package.json';\nimport { getLangVersion } from \"../version\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n public async send({\n sessionId,\n traceId,\n events,\n }: {\n sessionId: string;\n traceId: string;\n events: Record<string, any>[];\n }): Promise<void> {\n const payload = {\n sessionId,\n traceId,\n events,\n source: getLangVersion() ?? 'javascript',\n sdkVersion: SDK_VERSION,\n };\n\n const jsonString = JSON.stringify(payload);\n const blob = new Blob([jsonString], { type: 'application/json' });\n const compressedStream = blob.stream().pipeThrough(new CompressionStream('gzip'));\n const compressedResponse = new Response(compressedStream);\n const compressedData = await compressedResponse.arrayBuffer();\n\n const response = await fetch(this.baseHttpUrl + \"/v1/browser-sessions/events\", {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Content-Encoding': 'gzip',\n },\n body: compressedData,\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource, type LaminarAuth } from \"./index\";\n\nexport interface CliProject {\n id: string;\n name: string;\n workspaceId: string;\n workspaceName: string;\n}\n\n/**\n * Locale-aware, case-insensitive comparator for the project listing. Ordering\n * lives here — the single choke point every CLI surface (the `project list`\n * table + its `--json`, and the interactive picker used by `setup` / `plugin\n * add`) reads from — so the order can't drift between surfaces.\n */\nconst projectCollator = new Intl.Collator(undefined, { sensitivity: \"base\" });\n\n/** Sort projects by workspace name, then project name (stable, human-scannable). */\nconst sortProjects = (projects: CliProject[]): CliProject[] =>\n [...projects].sort(\n (a, b) =>\n projectCollator.compare(a.workspaceName ?? \"\", b.workspaceName ?? \"\") ||\n projectCollator.compare(a.name ?? \"\", b.name ?? \"\"),\n );\n\n/**\n * Outcome of resolving which project a project API key belongs to via the\n * user-token CLI endpoint. The states are deliberately distinct so the caller\n * doesn't conflate \"key is bad\" with \"couldn't reach the server\":\n * - `ok` → key verified AND the user is a member; `projectId` is its owner.\n * - `invalid` → 401: key revoked/invalid. Safe to mint a fresh one.\n * - `unverifiable` → 403 (key belongs to a project the user can't access) /\n * network error / other non-2xx / malformed body. The key may be perfectly\n * valid — caller MUST NOT mint (minting would clobber it on a blip).\n */\nexport type ProjectKeyProbe =\n | { status: \"ok\"; projectId: string }\n | { status: \"invalid\" }\n | { status: \"unverifiable\" };\n\n/**\n * User-scoped CLI endpoints that don't target a specific project. Authed by the\n * BetterAuth user JWT (the `credential`); deliberately does NOT send an\n * `x-lmnr-project-id` header (these routes are project discovery, pre-selection).\n *\n * Discovery exception: this resource always hits `/v1/cli/projects` with the\n * bare bearer and overrides `BaseResource.headers()`/`apiPrefix`, so it works\n * even when constructed with a `userToken` auth that has no real project id yet.\n */\nexport class CliResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /** Workspaces + projects the authenticated user can access. */\n public async listProjects(): Promise<CliProject[]> {\n const response = await fetch(`${this.baseHttpUrl}/v1/cli/projects`, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${this.credential}`,\n Accept: \"application/json\",\n },\n });\n if (!response.ok) {\n await this.handleError(response);\n }\n // Coerce a missing/non-array `projects` to [] so callers (.length/.map)\n // don't throw. A malformed body on a 2xx is exceptional — let it surface.\n // Sort here so every consumer inherits one stable, alphabetical order.\n const body = (await response.json()) as { projects?: CliProject[] };\n return Array.isArray(body?.projects) ? sortProjects(body.projects) : [];\n }\n\n /**\n * Resolve which project a project API key belongs to. Authed by the user JWT\n * (the bearer); the project key travels in the body, NOT in `Authorization`.\n * The server verifies the key and that the authenticated user is a member of\n * the resolved project. Returns a tri-state probe so callers can distinguish a\n * revoked key (401 → `invalid`) from a server/access problem (`unverifiable`).\n */\n public async resolveProjectByApiKey(apiKey: string): Promise<ProjectKeyProbe> {\n let response: Response;\n try {\n response = await fetch(`${this.baseHttpUrl}/v1/cli/project`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.credential}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({ apiKey }),\n });\n } catch {\n return { status: \"unverifiable\" };\n }\n if (response.status === 401) return { status: \"invalid\" };\n if (!response.ok) return { status: \"unverifiable\" };\n const body = (await response.json().catch(() => null)) as { projectId?: string } | null;\n return body?.projectId\n ? { status: \"ok\", projectId: body.projectId }\n : { status: \"unverifiable\" };\n }\n}\n","import { type StringUUID } from '@lmnr-ai/types';\nimport { config } from 'dotenv';\nimport * as path from 'path';\nimport pino, { Level } from 'pino';\nimport { PinoPretty } from 'pino-pretty';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport function initializeLogger(options?: { colorize?: boolean; level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level =\n options?.level ??\n (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level) ??\n 'info';\n\n return pino(\n {\n level,\n },\n PinoPretty({\n colorize,\n minimumLevel: level,\n }),\n );\n}\n\nconst logger = initializeLogger();\n\nexport const isStringUUID = (id: string): id is StringUUID =>\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);\n\nexport const NIL_UUID: StringUUID = '00000000-0000-0000-0000-000000000000';\n\nexport const newUUID = (): StringUUID => {\n // crypto.randomUUID is available in most of the modern browsers and node,\n // but is not available in \"insecure\" contexts, e.g. not https, not localhost\n // so we fallback to uuidv4 in those cases, which is less secure, but works\n // just fine.\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n } else {\n return uuidv4() as `${string}-${string}-${string}-${string}-${string}`;\n }\n};\n\nexport const otelSpanIdToUUID = (spanId: string): string => {\n let id = spanId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 16) {\n logger.warn(\n `Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.',\n );\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.padStart(32, '0').replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n );\n};\n\nexport const otelTraceIdToUUID = (traceId: string): StringUUID => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(\n `Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.',\n );\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n ) as StringUUID;\n};\n\nexport const slicePayload = <T>(value: T, length: number) => {\n if (value === null || value === undefined) {\n return value;\n }\n\n const str = JSON.stringify(value);\n if (str.length <= length) {\n return value;\n }\n\n return str.slice(0, length) + '...';\n};\n\nexport const loadEnv = (\n options?: {\n quiet?: boolean;\n paths?: string[];\n },\n): void => {\n const nodeEnv = process.env.NODE_ENV || 'development';\n const envDir = process.cwd();\n\n // Files to load in order (lowest to highest priority)\n // Later files override earlier ones\n const envFiles = [\n '.env',\n '.env.local',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`,\n ];\n\n const logLevel = process.env.LMNR_LOG_LEVEL ?? 'info';\n const verbose = ['debug', 'trace'].includes(logLevel.trim().toLowerCase());\n\n const quiet = options?.quiet ?? !verbose;\n\n config({\n path: options?.paths ?? envFiles.map((envFile) => path.resolve(envDir, envFile)),\n quiet,\n });\n};\n","import {\n type Datapoint,\n type Dataset,\n type GetDatapointsResponse,\n type PushDatapointsResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nconst logger = initializeLogger();\nconst DEFAULT_DATASET_PULL_LIMIT = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\n\nexport class DatasetsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * List all datasets.\n *\n * @returns {Promise<Dataset[]>} Array of datasets\n */\n public async listDatasets(): Promise<Dataset[]> {\n const response = await fetch(this.baseHttpUrl + this.apiPrefix + \"/datasets\", {\n method: \"GET\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Get a dataset by name.\n *\n * @param {string} name - Name of the dataset\n * @returns {Promise<Dataset[]>} Array of datasets with matching name\n */\n public async getDatasetByName(name: string): Promise<Dataset[]> {\n const params = new URLSearchParams({ name });\n const response = await fetch(\n this.baseHttpUrl + `${this.apiPrefix}/datasets?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Push datapoints to a dataset.\n *\n * @param {Object} options - Push options\n * @param {Datapoint<D, T>[]} options.points - Datapoints to push\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.batchSize] - Batch size for pushing (default: 100)\n * @param {boolean} [options.createDataset] - Whether to create the dataset if it doesn't exist\n * @returns {Promise<PushDatapointsResponse | undefined>}\n */\n public async push<D, T>({\n points,\n name,\n id,\n batchSize = DEFAULT_DATASET_PUSH_BATCH_SIZE,\n createDataset = false,\n }: {\n points: Datapoint<D, T>[];\n name?: string;\n id?: StringUUID;\n batchSize?: number;\n createDataset?: boolean;\n }): Promise<PushDatapointsResponse | undefined> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n if (createDataset && !name) {\n throw new Error(\"Name must be provided when creating a new dataset\");\n }\n\n const identifier = name ? { name } : { datasetId: id! };\n const totalBatches = Math.ceil(points.length / batchSize);\n\n let response: PushDatapointsResponse | undefined;\n for (let i = 0; i < points.length; i += batchSize) {\n const batchNum = Math.floor(i / batchSize) + 1;\n logger.debug(`Pushing batch ${batchNum} of ${totalBatches}`);\n\n const batch = points.slice(i, i + batchSize);\n const fetchResponse = await fetch(\n this.baseHttpUrl + this.apiPrefix + \"/datasets/datapoints\",\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n ...identifier,\n datapoints: batch.map((point) => ({\n data: point.data,\n target: point.target ?? {},\n metadata: point.metadata ?? {},\n })),\n createDataset,\n }),\n },\n );\n\n // 201 when creating a new dataset\n if (fetchResponse.status !== 200 && fetchResponse.status !== 201) {\n await this.handleError(fetchResponse);\n }\n\n response = (await fetchResponse.json()) as PushDatapointsResponse;\n }\n\n return response;\n }\n\n /**\n * Pull datapoints from a dataset.\n *\n * @param {Object} options - Pull options\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.limit] - Maximum number of datapoints to return (default: 100)\n * @param {number} [options.offset] - Offset for pagination (default: 0)\n * @returns {Promise<GetDatapointsResponse<D, T>>}\n */\n public async pull<D, T>({\n name,\n id,\n limit = DEFAULT_DATASET_PULL_LIMIT,\n offset = 0,\n }: {\n name?: string;\n id?: StringUUID;\n limit?: number;\n offset?: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n const paramsObj: Record<string, string> = {\n offset: offset.toString(),\n limit: limit.toString(),\n };\n\n if (name) {\n paramsObj.name = name;\n } else {\n paramsObj.datasetId = id!;\n }\n\n const params = new URLSearchParams(paramsObj);\n\n const response = await fetch(\n this.baseHttpUrl + `${this.apiPrefix}/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<GetDatapointsResponse<D, T>>;\n }\n}\n","import {\n type EvaluationDatapoint,\n type GetDatapointsResponse,\n type InitEvaluationResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger, newUUID, slicePayload } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nconst logger = initializeLogger();\nconst INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16_000_000; // 16MB\n\nexport class EvalsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Initialize an evaluation.\n *\n * @param {string} name - Name of the evaluation\n * @param {string} groupName - Group name of the evaluation\n * @param {Record<string, any>} metadata - Optional metadata\n * @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization\n */\n public async init(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + \"/v1/evals\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n groupName: groupName ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n *\n * @param {string} [name] - Optional name of the evaluation\n * @param {string} [groupName] - An identifier to group evaluations\n * @param {Record<string, any>} [metadata] - Optional metadata\n * @returns {Promise<StringUUID>} The evaluation ID\n */\n\n public async create(args?: {\n name?: string, groupName?: string, metadata?: Record<string, any>\n }): Promise<StringUUID> {\n const evaluation = await this.init(args?.name, args?.groupName, args?.metadata);\n return evaluation.id;\n }\n\n /**\n * Update an evaluation's name and/or metadata. The group ID is immutable.\n * Fields left undefined are kept unchanged.\n *\n * @param {Object} options - Update evaluation options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} [options.name] - New name of the evaluation\n * @param {Record<string, any>} [options.metadata] - New metadata for the evaluation\n * @returns {Promise<InitEvaluationResponse>} The updated evaluation\n */\n public async update({\n evalId,\n name,\n metadata,\n }: {\n evalId: string;\n name?: string;\n metadata?: Record<string, any>;\n }): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n * @deprecated use `create` instead.\n */\n public async createEvaluation(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<StringUUID> {\n const evaluation = await this.init(name, groupName, metadata);\n return evaluation.id;\n }\n\n /**\n * Create a datapoint for an evaluation.\n *\n * @param {Object} options - Create datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {D} options.data - The input data for the executor\n * @param {T} [options.target] - The target/expected output for evaluators\n * @param {Record<string, any>} [options.metadata] - Optional metadata\n * @param {number} [options.index] - Optional index of the datapoint\n * @param {string} [options.traceId] - Optional trace ID\n * @returns {Promise<StringUUID>} The datapoint ID\n */\n public async createDatapoint<D, T>({\n evalId,\n data,\n target,\n metadata,\n index,\n traceId,\n }: {\n evalId: string;\n data: D;\n target?: T;\n metadata?: Record<string, any>;\n index?: number;\n traceId?: string;\n }): Promise<StringUUID> {\n const datapointId = newUUID();\n\n const partialDatapoint: EvaluationDatapoint<D, T, any> = {\n id: datapointId,\n data,\n target,\n index: index ?? 0,\n traceId: traceId ?? newUUID(),\n executorSpanId: newUUID(),\n metadata,\n };\n\n await this.saveDatapoints({\n evalId,\n datapoints: [partialDatapoint],\n });\n\n return datapointId;\n }\n\n /**\n * Update a datapoint with evaluation results.\n *\n * @param {Object} options - Update datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} options.datapointId - The datapoint ID\n * @param {Record<string, number>} options.scores - The scores\n * @param {O} [options.executorOutput] - The executor output\n * @returns {Promise<void>}\n */\n public async updateDatapoint<O>({\n evalId,\n datapointId,\n scores,\n executorOutput,\n }: {\n evalId: string;\n datapointId: string;\n scores: Record<string, number>;\n executorOutput?: O;\n }): Promise<void> {\n const response = await fetch(\n this.baseHttpUrl + `/v1/evals/${evalId}/datapoints/${datapointId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n executorOutput,\n scores,\n }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Save evaluation datapoints.\n *\n * @param {Object} options - Save datapoints options\n * @param {string} options.evalId - ID of the evaluation\n * @param {EvaluationDatapoint<D, T, O>[]} options.datapoints - Datapoint to add\n * @param {string} [options.groupName] - Group name of the evaluation\n * @returns {Promise<void>} Response from the datapoint addition\n */\n public async saveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n }): Promise<void> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n target: slicePayload(d.target, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n executorOutput: slicePayload(\n d.executorOutput,\n INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n ),\n })),\n groupName: groupName ?? null,\n }),\n });\n\n if (response.status === 413) {\n return await this.retrySaveDatapoints({\n evalId,\n datapoints,\n groupName,\n });\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Get evaluation datapoints.\n *\n * @deprecated Use `client.datasets.pull()` instead.\n * @param {Object} options - Get datapoints options\n * @param {string} options.datasetName - Name of the dataset\n * @param {number} options.offset - Offset at which to start the query\n * @param {number} options.limit - Maximum number of datapoints to return\n * @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval\n */\n public async getDatapoints<D, T>({\n datasetName,\n offset,\n limit,\n }: {\n datasetName: string;\n offset: number;\n limit: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n logger.warn(\n 'evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.',\n );\n\n const params = new URLSearchParams({\n name: datasetName,\n offset: offset.toString(),\n limit: limit.toString(),\n });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as GetDatapointsResponse<D, T>;\n }\n\n private async retrySaveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n maxRetries = 25,\n initialLength = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n maxRetries?: number;\n initialLength?: number;\n }): Promise<void> {\n let length = initialLength;\n let lastResponse: Response | null = null;\n for (let i = 0; i < maxRetries; i++) {\n logger.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, length),\n target: slicePayload(d.target, length),\n executorOutput: slicePayload(d.executorOutput, length),\n })),\n groupName: groupName ?? null,\n }),\n });\n lastResponse = response;\n length = Math.floor(length / 2);\n if (response.status !== 413) {\n break;\n }\n }\n if (lastResponse && !lastResponse.ok) {\n await this.handleError(lastResponse);\n }\n }\n}\n","import { type StringUUID } from \"@lmnr-ai/types\";\n\nimport { isStringUUID, otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nenum EvaluatorScoreSourceType {\n Evaluator = \"Evaluator\",\n Code = \"Code\",\n}\n\ninterface CreateEvaluatorScoreBase {\n name: string;\n metadata?: Record<string, any>;\n score: number;\n source: EvaluatorScoreSourceType;\n}\n\ninterface CreateEvaluatorScoreRequestWithTraceId extends CreateEvaluatorScoreBase {\n traceId: string;\n}\n\ninterface CreateEvaluatorScoreRequestWithSpanId extends CreateEvaluatorScoreBase {\n spanId: string;\n}\n\ntype ScoreOptions =\n | { name: string; metadata?: Record<string, any>; score: number; traceId: string; }\n | { name: string; metadata?: Record<string, any>; score: number; spanId: string; };\n\n/**\n * Resource for creating evaluator scores\n */\nexport class EvaluatorsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Create a score for a span or trace\n *\n * @param {ScoreOptions} options - Score creation options\n * @param {string} options.name - Name of the score\n * @param {string} [options.traceId] - The trace ID to score (will be attached to top-level span)\n * @param {string} [options.spanId] - The span ID to score\n * @param {Record<string, any>} [options.metadata] - Additional metadata\n * @param {number} options.score - The score value (float)\n * @returns {Promise<void>}\n *\n * @example\n * // Score by trace ID (will attach to root span)\n * await evaluators.score({\n * name: \"quality\",\n * traceId: \"trace-id-here\",\n * score: 0.95,\n * metadata: { model: \"gpt-4\" }\n * });\n *\n * @example\n * // Score by span ID\n * await evaluators.score({\n * name: \"relevance\",\n * spanId: \"span-id-here\",\n * score: 0.87\n * });\n */\n public async score(options: ScoreOptions): Promise<void> {\n const { name, metadata, score } = options;\n\n let payload: CreateEvaluatorScoreRequestWithTraceId | CreateEvaluatorScoreRequestWithSpanId;\n\n if ('traceId' in options && options.traceId) {\n const formattedTraceId = isStringUUID(options.traceId)\n ? options.traceId\n : otelTraceIdToUUID(options.traceId);\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n traceId: formattedTraceId,\n };\n } else if ('spanId' in options && options.spanId) {\n const formattedSpanId = isStringUUID(options.spanId)\n ? options.spanId\n : otelSpanIdToUUID(options.spanId) as StringUUID;\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n spanId: formattedSpanId,\n };\n } else {\n throw new Error(\"Either 'traceId' or 'spanId' must be provided.\");\n }\n\n const response = await fetch(this.baseHttpUrl + \"/v1/evaluators/score\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import {\n type CachedSpan,\n errorMessage,\n type SessionBlock,\n type SessionBlockContent,\n type SessionBlockType,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nconst logger = initializeLogger();\n\n/**\n * Result of a debug-replay cache lookup (debug-replay v2).\n *\n * - `hit` — the server served a cached response for this input hash; replay it\n * and mark the span CACHED.\n * - `miss` — no cache entry; the caller latches process-wide live mode and runs\n * every subsequent call live.\n * - `live` — run THIS call live without latching (server COLD warmup-timeout\n * degrade, or any non-OK / transport error here).\n */\nexport type CacheOutcome =\n | { kind: \"hit\"; cached: CachedSpan }\n | { kind: \"miss\" }\n | { kind: \"live\" };\n\n/**\n * Map the opaque HIT `response` payload onto a {@link CachedSpan} the provider\n * wrappers can replay. The server-side shape of `response` is not yet frozen\n * (app-server plan 01 leaves it as a `serde_json::Value`), so this stays\n * deliberately tolerant: the whole payload is serialized into `output` (the only\n * field the AI SDK wrapper's `parseCachedSpan` actually reads, via\n * `JSON.parse`), and a `finishReason` is surfaced into `attributes` when the\n * payload carries one. `name`/`input` are irrelevant to replay and left empty.\n */\nconst toCachedSpan = (response: unknown): CachedSpan => {\n const output =\n typeof response === \"string\" ? response : JSON.stringify(response ?? null);\n const attributes: Record<string, any> = {};\n if (\n response !== null &&\n typeof response === \"object\" &&\n typeof (response as Record<string, unknown>).finishReason === \"string\"\n ) {\n attributes[\"ai.response.finishReason\"] = (\n response as Record<string, unknown>\n ).finishReason;\n }\n return { name: \"\", input: \"\", output, attributes };\n};\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Idempotently register (upsert) a debug session on the backend, keyed on the\n * SDK-supplied session id. The backend stores the row so the session is\n * visible in the UI; a null/omitted name never clobbers a name set elsewhere.\n *\n * Returns the backend-resolved `projectId` (derived from the API key) so the\n * caller can build the debugger URL; null if the body can't be parsed.\n */\n public async register({\n sessionId,\n name,\n }: {\n sessionId: string;\n name?: string;\n }): Promise<string | null> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as { projectId?: string };\n return body.projectId ?? null;\n } catch (e) {\n logger.warn(\n `Failed to parse rollout register response: ${errorMessage(e)}`,\n );\n return null;\n }\n }\n\n /**\n * Rename an existing debug session. Update-only: the backend returns 404 (and\n * this throws) when the session id is unknown for the project, so a mistyped\n * id surfaces as an error rather than silently creating a session. Creation\n * stays the SDK's job via {@link register}.\n */\n public async setName({\n sessionId,\n name,\n }: {\n sessionId: string;\n name: string;\n }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/name`,\n {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Append a block to a debug session (debugger session blocks).\n *\n * A debug session renders as an ordered list of blocks; this writes one to the\n * backend keyed by session id. The CLI uses it for `text` blocks — standalone\n * agent notes attached post-factum via `lmnr-cli debug session add-note` — so\n * a note is tied to the SESSION, not to a specific trace / evaluation (those\n * blocks are written at ingest from `rollout.session_id` metadata).\n *\n * A 404 (the session is unknown for the project) is logged and swallowed\n * unless `failOnNotFound` is set — CLI callers pass it so an exit 0 means the\n * block actually landed. Any other non-OK status throws.\n *\n * Returns the created block id, or null when the response body can't be parsed.\n */\n public async addBlock({\n sessionId,\n type,\n content,\n failOnNotFound,\n signal,\n }: {\n sessionId: string;\n type: SessionBlockType;\n content: SessionBlockContent;\n failOnNotFound?: boolean;\n // Optional cancellation: aborting tears down the in-flight request so a\n // best-effort caller (e.g. the CLI's command tracking) can bound its own\n // deadline without a leaked socket keeping the process alive.\n signal?: AbortSignal;\n }): Promise<string | null> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/blocks`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ type, content }),\n signal,\n },\n );\n\n if (response.status === 404) {\n const message =\n `Could not add a note: HTTP 404 for session ${sessionId}. Either the ` +\n \"session isn't registered in this project (mint one with `lmnr-cli \" +\n \"debug session new`, or run under LMNR_DEBUG=1), or this Laminar server \" +\n \"doesn't expose the session-blocks write endpoint \" +\n \"(POST /v1/rollouts/{sessionId}/blocks) yet.\";\n if (failOnNotFound) {\n throw new Error(message);\n }\n logger.warn(message);\n return null;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as { id?: string };\n return body.id ?? null;\n } catch (e) {\n logger.warn(`Failed to parse add-block response: ${errorMessage(e)}`);\n return null;\n }\n }\n\n /**\n * List a debug session's blocks in creation order.\n *\n * Returns every `trace` / `evaluation` / `text` block on the session — the\n * same data the debugger UI renders. Used by `lmnr-cli debug session summary`\n * to print a chronological digest of the session. Returns an empty array when\n * the session has no blocks or the body can't be parsed.\n */\n public async listBlocks({\n sessionId,\n }: {\n sessionId: string;\n }): Promise<SessionBlock[]> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/blocks`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as\n | { blocks?: SessionBlock[] }\n | SessionBlock[];\n const blocks = Array.isArray(body) ? body : body.blocks;\n return blocks ?? [];\n } catch (e) {\n logger.warn(`Failed to parse list-blocks response: ${errorMessage(e)}`);\n return [];\n }\n }\n\n /**\n * Look up the debug-replay cache for a single LLM call (debug-replay v2).\n *\n * The server is keyed by `inputHash` (hex blake3 of the canonicalized,\n * system-stripped input messages). It returns one of three outcomes:\n * - `{ outcome: \"hit\", response }` — a cached response to replay.\n * - `{ outcome: \"miss\" }` — no entry; caller latches live mode.\n * - `{ outcome: \"live\" }` — run this call live (COLD degrade).\n *\n * Error posture: a non-OK response or a transport error degrades to\n * `{ kind: \"live\" }` for THIS call only — it never throws and never latches\n * the process-wide live flag (only a real MISS does that). This keeps a flaky\n * cache backend from turning a replay into a crash.\n */\n public async cache({\n sessionId,\n replayTraceId,\n cacheUntil,\n inputHash,\n }: {\n sessionId: string;\n replayTraceId: string;\n cacheUntil: string;\n inputHash: string;\n }): Promise<CacheOutcome> {\n let response: Response;\n try {\n response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/cache`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ replayTraceId, cacheUntil, inputHash }),\n },\n );\n } catch (e) {\n logger.warn(`Debug cache lookup failed, running live: ${errorMessage(e)}`);\n return { kind: \"live\" };\n }\n\n if (!response.ok) {\n logger.warn(\n `Debug cache lookup returned ${response.status}, running live`,\n );\n return { kind: \"live\" };\n }\n\n let body: { outcome?: string; response?: unknown };\n try {\n body = (await response.json()) as { outcome?: string; response?: unknown };\n } catch (e) {\n logger.warn(\n `Failed to parse debug cache response, running live: ${errorMessage(e)}`,\n );\n return { kind: \"live\" };\n }\n\n switch (body.outcome) {\n case \"hit\":\n // A HIT with no replayable payload (missing / JSON `null` response) is\n // useless: serializing it would store the string \"null\", which parses\n // back to `null` and crashes reconstruction. Degrade to live instead.\n if (body.response === null || body.response === undefined) {\n logger.warn(\"Debug cache HIT had no response payload, running live\");\n return { kind: \"live\" };\n }\n return { kind: \"hit\", cached: toCachedSpan(body.response) };\n case \"miss\":\n return { kind: \"miss\" };\n case \"live\":\n return { kind: \"live\" };\n default:\n logger.warn(\n `Unknown debug cache outcome \"${body.outcome}\", running live`,\n );\n return { kind: \"live\" };\n }\n }\n\n public async delete({ sessionId }: { sessionId: string }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`,\n {\n method: \"DELETE\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import {\n type Signal,\n type SignalStructuredOutput,\n type SignalTrigger,\n} from \"@lmnr-ai/types\";\n\nimport { BaseResource, type LaminarAuth } from \".\";\n\nexport interface CreateSignalOptions {\n name: string;\n prompt: string;\n structuredOutput: SignalStructuredOutput;\n sampleRate?: number;\n disabled?: boolean;\n /** Omit to seed the UI's default trigger; `[]` creates an inert signal. */\n triggers?: SignalTrigger[];\n}\n\n/**\n * A partial patch. Every field is optional and an ABSENT field leaves the stored\n * value alone — so updating the prompt can't clear sampling or re-enable a\n * deactivated signal. `sampleRate: null` explicitly clears sampling, and\n * `triggers` replaces the signal's whole trigger set when present.\n */\nexport interface UpdateSignalOptions {\n prompt?: string;\n structuredOutput?: SignalStructuredOutput;\n sampleRate?: number | null;\n disabled?: boolean;\n triggers?: SignalTrigger[];\n}\n\n/** Signals CRUD over the CLI user-token surface (`/v1/cli/signals`). */\nexport class SignalsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Every signal route answers errors as `{ error: \"<message>\" }`, and those\n * messages are written to be shown to the user verbatim (e.g. \"A signal named\n * X already exists in this project\"). The shared `handleError` would surface\n * the raw JSON body, so unwrap the envelope here and fall back to it when the\n * body isn't the expected shape.\n */\n private async raiseSignalError(response: Response): Promise<never> {\n const body = await response.text();\n let message = body;\n try {\n const parsed = JSON.parse(body) as { error?: unknown };\n if (typeof parsed?.error === \"string\" && parsed.error.length > 0) {\n message = parsed.error;\n }\n } catch {\n // Not JSON (a proxy error page, an actix plain-text 413) — use it as-is.\n }\n throw new Error(`${response.status} ${message}`);\n }\n\n public async list(name?: string): Promise<Signal[]> {\n const query = name ? `?${new URLSearchParams({ name }).toString()}` : \"\";\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/signals${query}`, {\n method: \"GET\",\n headers: this.headers(),\n });\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n // Coerce a missing/non-array `signals` to [] so callers can .map/.length it;\n // a malformed body on a 2xx is exceptional, not the normal empty case.\n const body = (await response.json()) as { signals?: Signal[] };\n return Array.isArray(body?.signals) ? body.signals : [];\n }\n\n public async get(signalId: string): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n { method: \"GET\", headers: this.headers() },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n public async create(options: CreateSignalOptions): Promise<Signal> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/signals`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(options),\n });\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n /**\n * PATCH, not PUT: only the keys present in `options` are sent, so the server\n * leaves everything else as stored. `sampleRate: null` must survive\n * serialization (it means \"clear\"), so it is NOT stripped here.\n */\n public async update(signalId: string, options: UpdateSignalOptions): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify(options),\n },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n /** Deletes the signal, its triggers, its alerts, and its ClickHouse events. */\n public async delete(signalId: string): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n { method: \"DELETE\", headers: this.headers() },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n}\n","import type { SqlSchema } from \"@lmnr-ai/types\";\n\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n public async query(\n sql: string,\n parameters: Record<string, any> = {},\n ): Promise<Array<Record<string, any>>> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/sql/query`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n },\n body: JSON.stringify({\n query: sql,\n parameters,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()).data as Array<Record<string, any>>;\n }\n\n /**\n * Fetch the queryable tables, columns, and enums. Server-rendered from\n * app-server's `query_engine::schema`, so it is the same source that backs\n * the MCP `query_laminar_sql` tool description — never a client-side copy.\n */\n public async schema(): Promise<SqlSchema> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/sql/schema`, {\n method: \"GET\",\n headers: {\n ...this.headers(),\n },\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as SqlSchema;\n }\n}\n","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Tag a trace with a list of tags. Note that the trace must be ended before\n * tagging it. You may want to call `await Laminar.flush()` after the trace\n * that you want to tag.\n *\n * @param {string | StringUUID} trace_id - The trace id to tag.\n * @param {string[] | string} tags - The tag or list of tags to add to the trace.\n * @returns {Promise<any>} The response from the server.\n * @example\n * ```javascript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n * let traceId: StringUUID | null = null;\n * // Make sure this is called outside of traced context.\n * await observe(\n * {\n * name: \"my-trace\",\n * },\n * async () => {\n * traceId = await Laminar.getTraceId();\n * await foo();\n * },\n * );\n *\n * // or make sure the trace is ended by this point.\n * await Laminar.flush();\n * if (traceId) {\n * await client.tags.tag(traceId, [\"tag1\", \"tag2\"]);\n * }\n * ```\n */\n public async tag(\n trace_id: string,\n tags: string[] | string,\n ): Promise<any> {\n const traceTags = Array.isArray(tags) ? tags : [tags];\n const formattedTraceId = isStringUUID(trace_id)\n ? trace_id\n : otelTraceIdToUUID(trace_id);\n\n const url = this.baseHttpUrl + \"/v1/tag\";\n const payload = {\n \"traceId\": formattedTraceId,\n \"names\": traceTags,\n };\n const response = await fetch(\n url,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n },\n );\n if (!response.ok) {\n await this.handleError(response);\n }\n return response.json();\n }\n}\n","/** Resource for post-factum operations on existing traces. */\n\nimport { initializeLogger, isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nconst logger = initializeLogger();\n\nexport class TracesResource extends BaseResource {\n /** Resource for post-factum operations on existing traces. */\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Push a metadata patch to an existing trace.\n *\n * The patch is shallow-merged server-side into the trace's existing metadata\n * (`existing || patch`, last-write-wins per top-level key). Useful for\n * attaching post-factum signals — quality scores, human edits, triage labels —\n * to a trace that has already finished. The patch does NOT extend `endTime`\n * or change tokens / cost / top span / tags / span names. `numSpans` is\n * incremented by 1 (paid by the virtual span that carried the patch through\n * the ingestion queue) so the new ClickHouse row beats the prior version on\n * `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.\n *\n * Compared to `Laminar.setTraceMetadata` (which sets metadata on the\n * currently in-flight trace via OpenTelemetry attributes), this method\n * operates on a finished trace by trace id, so it must be called after the\n * trace has been flushed.\n *\n * A 404 response (the trace was not found in the project — typically because\n * it has not been flushed yet) is logged as a warning and the call returns\n * without throwing, since the 404 may be expected when pushing too soon\n * after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.\n * CLI callers that must report the failure). Any other non-OK status throws.\n *\n * @param traceId - The trace id to push metadata to. Accepts a UUID string\n * or a 32-char OTel hex trace id.\n * @param metadata - The metadata patch. Top-level keys are merged into the\n * trace's existing metadata. Must be non-empty (the server rejects empty\n * patches with 400).\n * @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.\n * @example\n * ```typescript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n *\n * let traceId: string | null = null;\n * await observe({ name: \"generate\" }, async () => {\n * traceId = await Laminar.getTraceId();\n * });\n * await Laminar.flush();\n *\n * if (traceId) {\n * await client.traces.pushMetadata(traceId, {\n * score: 0.85,\n * reviewer: \"alice\",\n * needsReview: false,\n * });\n * }\n * ```\n */\n public async pushMetadata(\n traceId: string,\n metadata: Record<string, unknown>,\n options?: { failOnNotFound?: boolean },\n ): Promise<void> {\n if (!metadata || Object.keys(metadata).length === 0) {\n throw new Error(\"metadata must be a non-empty object\");\n }\n\n const formattedTraceId = isStringUUID(traceId)\n ? traceId\n : otelTraceIdToUUID(traceId);\n\n const url = this.baseHttpUrl + this.apiPrefix + \"/traces/metadata\";\n const response = await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n traceId: formattedTraceId,\n metadata,\n }),\n });\n\n if (response.status === 404) {\n const message =\n `Trace ${formattedTraceId} not found. The trace may not have been ` +\n \"flushed yet — call await Laminar.flush() and retry.\";\n if (options?.failOnNotFound) {\n throw new Error(message);\n }\n // Trace not found in this project — likely not flushed yet. Don't throw,\n // but surface a warning so callers debugging an empty patch see it.\n logger.warn(message);\n return;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { CliResource } from \"./resources/cli\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { type LaminarAuth } from \"./resources/index\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\nimport { SignalsResource } from \"./resources/signals\";\nimport { SqlResource } from \"./resources/sql\";\nimport { TagsResource } from \"./resources/tags\";\nimport { TracesResource } from \"./resources/traces\";\nimport { loadEnv } from \"./utils\";\n\nexport class LaminarClient {\n private baseUrl: string;\n private auth: LaminarAuth;\n private _browserEvents: BrowserEventsResource;\n private _cli: CliResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _signals: SignalsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n private _traces: TracesResource;\n\n constructor({\n baseUrl,\n port,\n auth,\n projectApiKey,\n cliUserProjectId,\n }: {\n baseUrl?: string,\n port?: number,\n /**\n * Unified auth. A discriminated union that drives both the URL prefix and\n * the request headers:\n * - `{ type: \"apiKey\", key }` → project key, `/v1/*`.\n * - `{ type: \"userToken\", token, projectId }` → user JWT, `/v1/cli/*` with\n * `x-lmnr-project-id`.\n * When omitted, the legacy `projectApiKey` / `cliUserProjectId` fields (or\n * `LMNR_PROJECT_API_KEY`) are normalized into this union.\n */\n auth?: LaminarAuth,\n /**\n * @deprecated Pass `auth: { type: \"apiKey\", key }` instead. Kept for\n * backward compatibility — normalized into the unified `auth` union.\n */\n projectApiKey?: string,\n /**\n * @deprecated Pass `auth: { type: \"userToken\", token, projectId }` instead.\n * Kept for backward compatibility: when set, the legacy `projectApiKey` is\n * treated as a user JWT and routes to `/v1/cli/*` with this project id.\n */\n cliUserProjectId?: string,\n } = {}) {\n loadEnv();\n this.auth = LaminarClient.normalizeAuth(auth, projectApiKey, cliUserProjectId);\n const httpPort = port ?? (\n baseUrl?.match(/:\\d{1,5}$/g)\n ? parseInt(baseUrl.match(/:\\d{1,5}$/g)![0].slice(1))\n : 443);\n const baseUrlNoPort = (baseUrl ?? process.env.LMNR_BASE_URL)\n ?.replace(/\\/$/, '').replace(/:\\d{1,5}$/g, '');\n this.baseUrl = `${baseUrlNoPort ?? 'https://api.lmnr.ai'}:${httpPort}`;\n this._browserEvents = new BrowserEventsResource(this.baseUrl, this.auth);\n this._cli = new CliResource(this.baseUrl, this.auth);\n this._datasets = new DatasetsResource(this.baseUrl, this.auth);\n this._evals = new EvalsResource(this.baseUrl, this.auth);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.auth);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.auth);\n this._signals = new SignalsResource(this.baseUrl, this.auth);\n this._sql = new SqlResource(this.baseUrl, this.auth);\n this._tags = new TagsResource(this.baseUrl, this.auth);\n this._traces = new TracesResource(this.baseUrl, this.auth);\n }\n\n /**\n * The fully-resolved API origin every resource fetches from, e.g.\n * `http://localhost:8000`. Already normalized: trailing slash removed, any\n * port embedded in `baseUrl` stripped, and the effective port appended.\n *\n * Exposed so callers can name the real address in diagnostics instead of\n * rebuilding it from `baseUrl` + `port` — that reconstruction drifts from\n * this normalization and prints things like `http://host:8000:9000`.\n */\n public get apiBaseUrl(): string {\n return this.baseUrl;\n }\n\n /**\n * Normalize the constructor's auth inputs into a {@link LaminarAuth} union.\n * Precedence: an explicit `auth` wins; otherwise the legacy\n * `projectApiKey` (+ optional `cliUserProjectId`) is mapped — a present\n * `cliUserProjectId` selects the user-token surface, otherwise the project\n * key surface. Falls back to `LMNR_PROJECT_API_KEY` as a project key.\n */\n private static normalizeAuth(\n auth: LaminarAuth | undefined,\n projectApiKey: string | undefined,\n cliUserProjectId: string | undefined,\n ): LaminarAuth {\n if (auth) {\n return auth;\n }\n const key = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\n if (cliUserProjectId) {\n return { type: \"userToken\", token: key, projectId: cliUserProjectId };\n }\n return { type: \"apiKey\", key };\n }\n\n public get browserEvents() {\n return this._browserEvents;\n }\n\n public get cli() {\n return this._cli;\n }\n\n public get datasets() {\n return this._datasets;\n }\n\n public get evals() {\n return this._evals;\n }\n\n public get evaluators() {\n return this._evaluators;\n }\n\n public get signals() {\n return this._signals;\n }\n\n public get rolloutSessions() {\n return this._rolloutSessions;\n }\n\n public get sql() {\n return this._sql;\n }\n\n public get tags() {\n return this._tags;\n }\n\n public get traces() {\n return this._traces;\n }\n}\n\nexport type { CliProject, ProjectKeyProbe } from \"./resources/cli\";\nexport type { LaminarAuth } from \"./resources/index\";\nexport {\n type CacheOutcome,\n RolloutSessionsResource,\n} from \"./resources/rollout-sessions\";\nexport type {\n CreateSignalOptions,\n UpdateSignalOptions,\n} from \"./resources/signals\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["SDK_VERSION","logger","uuidv4","logger","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/resources/cli.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.ts","../src/resources/signals.ts","../src/resources/sql.ts","../src/resources/tags.ts","../src/resources/traces.ts","../src/index.ts"],"sourcesContent":["","// Version detection for runtime environment\nexport function getLangVersion(): string | null {\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return `node-${process.versions.node}`;\n }\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return `browser-${navigator.userAgent}`;\n }\n return null;\n}\n","/**\n * Unified auth for every resource. A discriminated union so a single object\n * drives both the URL prefix and the request headers:\n *\n * - `apiKey` → project API key (SDK / app surfaces). Routes to `/v1/*`,\n * Bearer is the project key, no `x-lmnr-project-id` header.\n * - `userToken` → BetterAuth user access JWT (the CLI user-token surface).\n * Routes to `/v1/cli/*`, Bearer is the JWT, carries the target project in\n * the `x-lmnr-project-id` header.\n */\nexport type LaminarAuth =\n | { type: \"apiKey\"; key: string }\n | { type: \"userToken\"; token: string; projectId: string };\n\nclass BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly auth: LaminarAuth;\n /** The bearer credential, regardless of auth type (project key or user JWT). */\n protected readonly credential: string;\n\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n this.baseHttpUrl = baseHttpUrl;\n this.auth = auth;\n this.credential = auth.type === \"apiKey\" ? auth.key : auth.token;\n }\n\n /** API path prefix: `/v1/cli` for CLI user-token auth, `/v1` otherwise. */\n protected get apiPrefix(): string {\n return this.auth.type === \"userToken\" ? \"/v1/cli\" : \"/v1\";\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.credential}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...(this.auth.type === \"userToken\"\n ? { \"x-lmnr-project-id\": this.auth.projectId }\n : {}),\n };\n }\n\n protected async handleError(response: Response) {\n const errorMsg = await response.text();\n throw new Error(`${response.status} ${errorMsg}`);\n }\n}\n\nexport { BaseResource };\n","import { version as SDK_VERSION } from '../../package.json';\nimport { getLangVersion } from \"../version\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n public async send({\n sessionId,\n traceId,\n events,\n }: {\n sessionId: string;\n traceId: string;\n events: Record<string, any>[];\n }): Promise<void> {\n const payload = {\n sessionId,\n traceId,\n events,\n source: getLangVersion() ?? 'javascript',\n sdkVersion: SDK_VERSION,\n };\n\n const jsonString = JSON.stringify(payload);\n const blob = new Blob([jsonString], { type: 'application/json' });\n const compressedStream = blob.stream().pipeThrough(new CompressionStream('gzip'));\n const compressedResponse = new Response(compressedStream);\n const compressedData = await compressedResponse.arrayBuffer();\n\n const response = await fetch(this.baseHttpUrl + \"/v1/browser-sessions/events\", {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Content-Encoding': 'gzip',\n },\n body: compressedData,\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource, type LaminarAuth } from \"./index\";\n\nexport interface CliProject {\n id: string;\n name: string;\n workspaceId: string;\n workspaceName: string;\n}\n\n/**\n * Locale-aware, case-insensitive comparator for the project listing. Ordering\n * lives here — the single choke point every CLI surface (the `project list`\n * table + its `--json`, and the interactive picker used by `setup` / `plugin\n * add`) reads from — so the order can't drift between surfaces.\n */\nconst projectCollator = new Intl.Collator(undefined, { sensitivity: \"base\" });\n\n/** Sort projects by workspace name, then project name (stable, human-scannable). */\nconst sortProjects = (projects: CliProject[]): CliProject[] =>\n [...projects].sort(\n (a, b) =>\n projectCollator.compare(a.workspaceName ?? \"\", b.workspaceName ?? \"\") ||\n projectCollator.compare(a.name ?? \"\", b.name ?? \"\"),\n );\n\n/**\n * Outcome of resolving which project a project API key belongs to via the\n * user-token CLI endpoint. The states are deliberately distinct so the caller\n * doesn't conflate \"key is bad\" with \"couldn't reach the server\":\n * - `ok` → key verified AND the user is a member; `projectId` is its owner.\n * - `invalid` → 401: key revoked/invalid. Safe to mint a fresh one.\n * - `unverifiable` → 403 (key belongs to a project the user can't access) /\n * network error / other non-2xx / malformed body. The key may be perfectly\n * valid — caller MUST NOT mint (minting would clobber it on a blip).\n */\nexport type ProjectKeyProbe =\n | { status: \"ok\"; projectId: string }\n | { status: \"invalid\" }\n | { status: \"unverifiable\" };\n\n/**\n * User-scoped CLI endpoints that don't target a specific project. Authed by the\n * BetterAuth user JWT (the `credential`); deliberately does NOT send an\n * `x-lmnr-project-id` header (these routes are project discovery, pre-selection).\n *\n * Discovery exception: this resource always hits `/v1/cli/projects` with the\n * bare bearer and overrides `BaseResource.headers()`/`apiPrefix`, so it works\n * even when constructed with a `userToken` auth that has no real project id yet.\n */\nexport class CliResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /** Workspaces + projects the authenticated user can access. */\n public async listProjects(): Promise<CliProject[]> {\n const response = await fetch(`${this.baseHttpUrl}/v1/cli/projects`, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${this.credential}`,\n Accept: \"application/json\",\n },\n });\n if (!response.ok) {\n await this.handleError(response);\n }\n // Coerce a missing/non-array `projects` to [] so callers (.length/.map)\n // don't throw. A malformed body on a 2xx is exceptional — let it surface.\n // Sort here so every consumer inherits one stable, alphabetical order.\n const body = (await response.json()) as { projects?: CliProject[] };\n return Array.isArray(body?.projects) ? sortProjects(body.projects) : [];\n }\n\n /**\n * Resolve which project a project API key belongs to. Authed by the user JWT\n * (the bearer); the project key travels in the body, NOT in `Authorization`.\n * The server verifies the key and that the authenticated user is a member of\n * the resolved project. Returns a tri-state probe so callers can distinguish a\n * revoked key (401 → `invalid`) from a server/access problem (`unverifiable`).\n */\n public async resolveProjectByApiKey(apiKey: string): Promise<ProjectKeyProbe> {\n let response: Response;\n try {\n response = await fetch(`${this.baseHttpUrl}/v1/cli/project`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.credential}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({ apiKey }),\n });\n } catch {\n return { status: \"unverifiable\" };\n }\n if (response.status === 401) return { status: \"invalid\" };\n if (!response.ok) return { status: \"unverifiable\" };\n const body = (await response.json().catch(() => null)) as { projectId?: string } | null;\n return body?.projectId\n ? { status: \"ok\", projectId: body.projectId }\n : { status: \"unverifiable\" };\n }\n}\n","import { type StringUUID } from '@lmnr-ai/types';\nimport { config } from 'dotenv';\nimport * as path from 'path';\nimport pino, { Level } from 'pino';\nimport { PinoPretty } from 'pino-pretty';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport function initializeLogger(options?: { colorize?: boolean; level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level =\n options?.level ??\n (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level) ??\n 'info';\n\n return pino(\n {\n level,\n },\n PinoPretty({\n colorize,\n minimumLevel: level,\n }),\n );\n}\n\nconst logger = initializeLogger();\n\nexport const isStringUUID = (id: string): id is StringUUID =>\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);\n\nexport const NIL_UUID: StringUUID = '00000000-0000-0000-0000-000000000000';\n\nexport const newUUID = (): StringUUID => {\n // crypto.randomUUID is available in most of the modern browsers and node,\n // but is not available in \"insecure\" contexts, e.g. not https, not localhost\n // so we fallback to uuidv4 in those cases, which is less secure, but works\n // just fine.\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n } else {\n return uuidv4() as `${string}-${string}-${string}-${string}-${string}`;\n }\n};\n\nexport const otelSpanIdToUUID = (spanId: string): string => {\n let id = spanId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 16) {\n logger.warn(\n `Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.',\n );\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.padStart(32, '0').replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n );\n};\n\nexport const otelTraceIdToUUID = (traceId: string): StringUUID => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(\n `Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.',\n );\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n ) as StringUUID;\n};\n\nexport const slicePayload = <T>(value: T, length: number) => {\n if (value === null || value === undefined) {\n return value;\n }\n\n const str = JSON.stringify(value);\n if (str.length <= length) {\n return value;\n }\n\n return str.slice(0, length) + '...';\n};\n\nexport const loadEnv = (\n options?: {\n quiet?: boolean;\n paths?: string[];\n },\n): void => {\n const nodeEnv = process.env.NODE_ENV || 'development';\n const envDir = process.cwd();\n\n // Files to load in order (lowest to highest priority)\n // Later files override earlier ones\n const envFiles = [\n '.env',\n '.env.local',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`,\n ];\n\n const logLevel = process.env.LMNR_LOG_LEVEL ?? 'info';\n const verbose = ['debug', 'trace'].includes(logLevel.trim().toLowerCase());\n\n const quiet = options?.quiet ?? !verbose;\n\n config({\n path: options?.paths ?? envFiles.map((envFile) => path.resolve(envDir, envFile)),\n quiet,\n });\n};\n","import {\n type Datapoint,\n type Dataset,\n type GetDatapointsResponse,\n type PushDatapointsResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nconst logger = initializeLogger();\nconst DEFAULT_DATASET_PULL_LIMIT = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\n\nexport class DatasetsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * List all datasets.\n *\n * @returns {Promise<Dataset[]>} Array of datasets\n */\n public async listDatasets(): Promise<Dataset[]> {\n const response = await fetch(this.baseHttpUrl + this.apiPrefix + \"/datasets\", {\n method: \"GET\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Get a dataset by name.\n *\n * @param {string} name - Name of the dataset\n * @returns {Promise<Dataset[]>} Array of datasets with matching name\n */\n public async getDatasetByName(name: string): Promise<Dataset[]> {\n const params = new URLSearchParams({ name });\n const response = await fetch(\n this.baseHttpUrl + `${this.apiPrefix}/datasets?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Push datapoints to a dataset.\n *\n * @param {Object} options - Push options\n * @param {Datapoint<D, T>[]} options.points - Datapoints to push\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.batchSize] - Batch size for pushing (default: 100)\n * @param {boolean} [options.createDataset] - Whether to create the dataset if it doesn't exist\n * @returns {Promise<PushDatapointsResponse | undefined>}\n */\n public async push<D, T>({\n points,\n name,\n id,\n batchSize = DEFAULT_DATASET_PUSH_BATCH_SIZE,\n createDataset = false,\n }: {\n points: Datapoint<D, T>[];\n name?: string;\n id?: StringUUID;\n batchSize?: number;\n createDataset?: boolean;\n }): Promise<PushDatapointsResponse | undefined> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n if (createDataset && !name) {\n throw new Error(\"Name must be provided when creating a new dataset\");\n }\n\n const identifier = name ? { name } : { datasetId: id! };\n const totalBatches = Math.ceil(points.length / batchSize);\n\n let response: PushDatapointsResponse | undefined;\n for (let i = 0; i < points.length; i += batchSize) {\n const batchNum = Math.floor(i / batchSize) + 1;\n logger.debug(`Pushing batch ${batchNum} of ${totalBatches}`);\n\n const batch = points.slice(i, i + batchSize);\n const fetchResponse = await fetch(\n this.baseHttpUrl + this.apiPrefix + \"/datasets/datapoints\",\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n ...identifier,\n datapoints: batch.map((point) => ({\n data: point.data,\n target: point.target ?? {},\n metadata: point.metadata ?? {},\n })),\n createDataset,\n }),\n },\n );\n\n // 201 when creating a new dataset\n if (fetchResponse.status !== 200 && fetchResponse.status !== 201) {\n await this.handleError(fetchResponse);\n }\n\n response = (await fetchResponse.json()) as PushDatapointsResponse;\n }\n\n return response;\n }\n\n /**\n * Pull datapoints from a dataset.\n *\n * @param {Object} options - Pull options\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.limit] - Maximum number of datapoints to return (default: 100)\n * @param {number} [options.offset] - Offset for pagination (default: 0)\n * @returns {Promise<GetDatapointsResponse<D, T>>}\n */\n public async pull<D, T>({\n name,\n id,\n limit = DEFAULT_DATASET_PULL_LIMIT,\n offset = 0,\n }: {\n name?: string;\n id?: StringUUID;\n limit?: number;\n offset?: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n const paramsObj: Record<string, string> = {\n offset: offset.toString(),\n limit: limit.toString(),\n };\n\n if (name) {\n paramsObj.name = name;\n } else {\n paramsObj.datasetId = id!;\n }\n\n const params = new URLSearchParams(paramsObj);\n\n const response = await fetch(\n this.baseHttpUrl + `${this.apiPrefix}/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<GetDatapointsResponse<D, T>>;\n }\n}\n","import {\n type EvaluationDatapoint,\n type GetDatapointsResponse,\n type InitEvaluationResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger, newUUID, slicePayload } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nconst logger = initializeLogger();\nconst INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16_000_000; // 16MB\n\nexport class EvalsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Initialize an evaluation.\n *\n * @param {string} name - Name of the evaluation\n * @param {string} groupName - Group name of the evaluation\n * @param {Record<string, any>} metadata - Optional metadata\n * @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization\n */\n public async init(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + \"/v1/evals\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n groupName: groupName ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n *\n * @param {string} [name] - Optional name of the evaluation\n * @param {string} [groupName] - An identifier to group evaluations\n * @param {Record<string, any>} [metadata] - Optional metadata\n * @returns {Promise<StringUUID>} The evaluation ID\n */\n\n public async create(args?: {\n name?: string, groupName?: string, metadata?: Record<string, any>\n }): Promise<StringUUID> {\n const evaluation = await this.init(args?.name, args?.groupName, args?.metadata);\n return evaluation.id;\n }\n\n /**\n * Update an evaluation's name and/or metadata. The group ID is immutable.\n * Fields left undefined are kept unchanged.\n *\n * @param {Object} options - Update evaluation options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} [options.name] - New name of the evaluation\n * @param {Record<string, any>} [options.metadata] - New metadata for the evaluation\n * @returns {Promise<InitEvaluationResponse>} The updated evaluation\n */\n public async update({\n evalId,\n name,\n metadata,\n }: {\n evalId: string;\n name?: string;\n metadata?: Record<string, any>;\n }): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n * @deprecated use `create` instead.\n */\n public async createEvaluation(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<StringUUID> {\n const evaluation = await this.init(name, groupName, metadata);\n return evaluation.id;\n }\n\n /**\n * Create a datapoint for an evaluation.\n *\n * @param {Object} options - Create datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {D} options.data - The input data for the executor\n * @param {T} [options.target] - The target/expected output for evaluators\n * @param {Record<string, any>} [options.metadata] - Optional metadata\n * @param {number} [options.index] - Optional index of the datapoint\n * @param {string} [options.traceId] - Optional trace ID\n * @returns {Promise<StringUUID>} The datapoint ID\n */\n public async createDatapoint<D, T>({\n evalId,\n data,\n target,\n metadata,\n index,\n traceId,\n }: {\n evalId: string;\n data: D;\n target?: T;\n metadata?: Record<string, any>;\n index?: number;\n traceId?: string;\n }): Promise<StringUUID> {\n const datapointId = newUUID();\n\n const partialDatapoint: EvaluationDatapoint<D, T, any> = {\n id: datapointId,\n data,\n target,\n index: index ?? 0,\n traceId: traceId ?? newUUID(),\n executorSpanId: newUUID(),\n metadata,\n };\n\n await this.saveDatapoints({\n evalId,\n datapoints: [partialDatapoint],\n });\n\n return datapointId;\n }\n\n /**\n * Update a datapoint with evaluation results.\n *\n * @param {Object} options - Update datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} options.datapointId - The datapoint ID\n * @param {Record<string, number>} options.scores - The scores\n * @param {O} [options.executorOutput] - The executor output\n * @returns {Promise<void>}\n */\n public async updateDatapoint<O>({\n evalId,\n datapointId,\n scores,\n executorOutput,\n }: {\n evalId: string;\n datapointId: string;\n scores: Record<string, number>;\n executorOutput?: O;\n }): Promise<void> {\n const response = await fetch(\n this.baseHttpUrl + `/v1/evals/${evalId}/datapoints/${datapointId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n executorOutput,\n scores,\n }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Save evaluation datapoints.\n *\n * @param {Object} options - Save datapoints options\n * @param {string} options.evalId - ID of the evaluation\n * @param {EvaluationDatapoint<D, T, O>[]} options.datapoints - Datapoint to add\n * @param {string} [options.groupName] - Group name of the evaluation\n * @returns {Promise<void>} Response from the datapoint addition\n */\n public async saveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n }): Promise<void> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n target: slicePayload(d.target, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n executorOutput: slicePayload(\n d.executorOutput,\n INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n ),\n })),\n groupName: groupName ?? null,\n }),\n });\n\n if (response.status === 413) {\n return await this.retrySaveDatapoints({\n evalId,\n datapoints,\n groupName,\n });\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Get evaluation datapoints.\n *\n * @deprecated Use `client.datasets.pull()` instead.\n * @param {Object} options - Get datapoints options\n * @param {string} options.datasetName - Name of the dataset\n * @param {number} options.offset - Offset at which to start the query\n * @param {number} options.limit - Maximum number of datapoints to return\n * @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval\n */\n public async getDatapoints<D, T>({\n datasetName,\n offset,\n limit,\n }: {\n datasetName: string;\n offset: number;\n limit: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n logger.warn(\n 'evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.',\n );\n\n const params = new URLSearchParams({\n name: datasetName,\n offset: offset.toString(),\n limit: limit.toString(),\n });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as GetDatapointsResponse<D, T>;\n }\n\n private async retrySaveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n maxRetries = 25,\n initialLength = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n maxRetries?: number;\n initialLength?: number;\n }): Promise<void> {\n let length = initialLength;\n let lastResponse: Response | null = null;\n for (let i = 0; i < maxRetries; i++) {\n logger.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, length),\n target: slicePayload(d.target, length),\n executorOutput: slicePayload(d.executorOutput, length),\n })),\n groupName: groupName ?? null,\n }),\n });\n lastResponse = response;\n length = Math.floor(length / 2);\n if (response.status !== 413) {\n break;\n }\n }\n if (lastResponse && !lastResponse.ok) {\n await this.handleError(lastResponse);\n }\n }\n}\n","import { type StringUUID } from \"@lmnr-ai/types\";\n\nimport { isStringUUID, otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \".\";\n\nenum EvaluatorScoreSourceType {\n Evaluator = \"Evaluator\",\n Code = \"Code\",\n}\n\ninterface CreateEvaluatorScoreBase {\n name: string;\n metadata?: Record<string, any>;\n score: number;\n source: EvaluatorScoreSourceType;\n}\n\ninterface CreateEvaluatorScoreRequestWithTraceId extends CreateEvaluatorScoreBase {\n traceId: string;\n}\n\ninterface CreateEvaluatorScoreRequestWithSpanId extends CreateEvaluatorScoreBase {\n spanId: string;\n}\n\ntype ScoreOptions =\n | { name: string; metadata?: Record<string, any>; score: number; traceId: string; }\n | { name: string; metadata?: Record<string, any>; score: number; spanId: string; };\n\n/**\n * Resource for creating evaluator scores\n */\nexport class EvaluatorsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Create a score for a span or trace\n *\n * @param {ScoreOptions} options - Score creation options\n * @param {string} options.name - Name of the score\n * @param {string} [options.traceId] - The trace ID to score (will be attached to top-level span)\n * @param {string} [options.spanId] - The span ID to score\n * @param {Record<string, any>} [options.metadata] - Additional metadata\n * @param {number} options.score - The score value (float)\n * @returns {Promise<void>}\n *\n * @example\n * // Score by trace ID (will attach to root span)\n * await evaluators.score({\n * name: \"quality\",\n * traceId: \"trace-id-here\",\n * score: 0.95,\n * metadata: { model: \"gpt-4\" }\n * });\n *\n * @example\n * // Score by span ID\n * await evaluators.score({\n * name: \"relevance\",\n * spanId: \"span-id-here\",\n * score: 0.87\n * });\n */\n public async score(options: ScoreOptions): Promise<void> {\n const { name, metadata, score } = options;\n\n let payload: CreateEvaluatorScoreRequestWithTraceId | CreateEvaluatorScoreRequestWithSpanId;\n\n if ('traceId' in options && options.traceId) {\n const formattedTraceId = isStringUUID(options.traceId)\n ? options.traceId\n : otelTraceIdToUUID(options.traceId);\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n traceId: formattedTraceId,\n };\n } else if ('spanId' in options && options.spanId) {\n const formattedSpanId = isStringUUID(options.spanId)\n ? options.spanId\n : otelSpanIdToUUID(options.spanId) as StringUUID;\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n spanId: formattedSpanId,\n };\n } else {\n throw new Error(\"Either 'traceId' or 'spanId' must be provided.\");\n }\n\n const response = await fetch(this.baseHttpUrl + \"/v1/evaluators/score\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import {\n type CachedSpan,\n errorMessage,\n type SessionBlock,\n type SessionBlockContent,\n type SessionBlockType,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nconst logger = initializeLogger();\n\n/**\n * Result of a debug-replay cache lookup (debug-replay v2).\n *\n * - `hit` — the server served a cached response for this input hash; replay it\n * and mark the span CACHED.\n * - `miss` — no cache entry; the caller latches process-wide live mode and runs\n * every subsequent call live.\n * - `live` — run THIS call live without latching (server COLD warmup-timeout\n * degrade, or any non-OK / transport error here).\n */\nexport type CacheOutcome =\n | { kind: \"hit\"; cached: CachedSpan }\n | { kind: \"miss\" }\n | { kind: \"live\" };\n\n/**\n * Map the opaque HIT `response` payload onto a {@link CachedSpan} the provider\n * wrappers can replay. The server-side shape of `response` is not yet frozen\n * (app-server plan 01 leaves it as a `serde_json::Value`), so this stays\n * deliberately tolerant: the whole payload is serialized into `output` (the only\n * field the AI SDK wrapper's `parseCachedSpan` actually reads, via\n * `JSON.parse`), and a `finishReason` is surfaced into `attributes` when the\n * payload carries one. `name`/`input` are irrelevant to replay and left empty.\n */\nconst toCachedSpan = (response: unknown): CachedSpan => {\n const output =\n typeof response === \"string\" ? response : JSON.stringify(response ?? null);\n const attributes: Record<string, any> = {};\n if (\n response !== null &&\n typeof response === \"object\" &&\n typeof (response as Record<string, unknown>).finishReason === \"string\"\n ) {\n attributes[\"ai.response.finishReason\"] = (\n response as Record<string, unknown>\n ).finishReason;\n }\n return { name: \"\", input: \"\", output, attributes };\n};\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Idempotently register (upsert) a debug session on the backend, keyed on the\n * SDK-supplied session id. The backend stores the row so the session is\n * visible in the UI; a null/omitted name never clobbers a name set elsewhere.\n *\n * Returns the backend-resolved `projectId` (derived from the API key) so the\n * caller can build the debugger URL; null if the body can't be parsed.\n */\n public async register({\n sessionId,\n name,\n }: {\n sessionId: string;\n name?: string;\n }): Promise<string | null> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as { projectId?: string };\n return body.projectId ?? null;\n } catch (e) {\n logger.warn(\n `Failed to parse rollout register response: ${errorMessage(e)}`,\n );\n return null;\n }\n }\n\n /**\n * Rename an existing debug session. Update-only: the backend returns 404 (and\n * this throws) when the session id is unknown for the project, so a mistyped\n * id surfaces as an error rather than silently creating a session. Creation\n * stays the SDK's job via {@link register}.\n */\n public async setName({\n sessionId,\n name,\n }: {\n sessionId: string;\n name: string;\n }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/name`,\n {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Append a block to a debug session (debugger session blocks).\n *\n * A debug session renders as an ordered list of blocks; this writes one to the\n * backend keyed by session id. The CLI uses it for `text` blocks — standalone\n * agent notes attached post-factum via `lmnr-cli debug session add-note` — so\n * a note is tied to the SESSION, not to a specific trace / evaluation (those\n * blocks are written at ingest from `rollout.session_id` metadata).\n *\n * A 404 (the session is unknown for the project) is logged and swallowed\n * unless `failOnNotFound` is set — CLI callers pass it so an exit 0 means the\n * block actually landed. Any other non-OK status throws.\n *\n * Returns the created block id, or null when the response body can't be parsed.\n */\n public async addBlock({\n sessionId,\n type,\n content,\n failOnNotFound,\n signal,\n }: {\n sessionId: string;\n type: SessionBlockType;\n content: SessionBlockContent;\n failOnNotFound?: boolean;\n // Optional cancellation: aborting tears down the in-flight request so a\n // best-effort caller (e.g. the CLI's command tracking) can bound its own\n // deadline without a leaked socket keeping the process alive.\n signal?: AbortSignal;\n }): Promise<string | null> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/blocks`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ type, content }),\n signal,\n },\n );\n\n if (response.status === 404) {\n const message =\n `Could not add a note: HTTP 404 for session ${sessionId}. Either the ` +\n \"session isn't registered in this project (mint one with `lmnr-cli \" +\n \"debug session new`, or run under LMNR_DEBUG=1), or this Laminar server \" +\n \"doesn't expose the session-blocks write endpoint \" +\n \"(POST /v1/rollouts/{sessionId}/blocks) yet.\";\n if (failOnNotFound) {\n throw new Error(message);\n }\n logger.warn(message);\n return null;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as { id?: string };\n return body.id ?? null;\n } catch (e) {\n logger.warn(`Failed to parse add-block response: ${errorMessage(e)}`);\n return null;\n }\n }\n\n /**\n * List a debug session's blocks in creation order.\n *\n * Returns every `trace` / `evaluation` / `text` block on the session — the\n * same data the debugger UI renders. Used by `lmnr-cli debug session summary`\n * to print a chronological digest of the session. Returns an empty array when\n * the session has no blocks or the body can't be parsed.\n */\n public async listBlocks({\n sessionId,\n }: {\n sessionId: string;\n }): Promise<SessionBlock[]> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/blocks`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as\n | { blocks?: SessionBlock[] }\n | SessionBlock[];\n const blocks = Array.isArray(body) ? body : body.blocks;\n return blocks ?? [];\n } catch (e) {\n logger.warn(`Failed to parse list-blocks response: ${errorMessage(e)}`);\n return [];\n }\n }\n\n /**\n * Look up the debug-replay cache for a single LLM call (debug-replay v2).\n *\n * The server is keyed by `inputHash` (hex blake3 of the canonicalized,\n * system-stripped input messages). It returns one of three outcomes:\n * - `{ outcome: \"hit\", response }` — a cached response to replay.\n * - `{ outcome: \"miss\" }` — no entry; caller latches live mode.\n * - `{ outcome: \"live\" }` — run this call live (COLD degrade).\n *\n * Error posture: a non-OK response or a transport error degrades to\n * `{ kind: \"live\" }` for THIS call only — it never throws and never latches\n * the process-wide live flag (only a real MISS does that). This keeps a flaky\n * cache backend from turning a replay into a crash.\n */\n public async cache({\n sessionId,\n replayTraceId,\n cacheUntil,\n inputHash,\n }: {\n sessionId: string;\n replayTraceId: string;\n cacheUntil: string;\n inputHash: string;\n }): Promise<CacheOutcome> {\n let response: Response;\n try {\n response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}/cache`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ replayTraceId, cacheUntil, inputHash }),\n },\n );\n } catch (e) {\n logger.warn(`Debug cache lookup failed, running live: ${errorMessage(e)}`);\n return { kind: \"live\" };\n }\n\n if (!response.ok) {\n logger.warn(\n `Debug cache lookup returned ${response.status}, running live`,\n );\n return { kind: \"live\" };\n }\n\n let body: { outcome?: string; response?: unknown };\n try {\n body = (await response.json()) as { outcome?: string; response?: unknown };\n } catch (e) {\n logger.warn(\n `Failed to parse debug cache response, running live: ${errorMessage(e)}`,\n );\n return { kind: \"live\" };\n }\n\n switch (body.outcome) {\n case \"hit\":\n // A HIT with no replayable payload (missing / JSON `null` response) is\n // useless: serializing it would store the string \"null\", which parses\n // back to `null` and crashes reconstruction. Degrade to live instead.\n if (body.response === null || body.response === undefined) {\n logger.warn(\"Debug cache HIT had no response payload, running live\");\n return { kind: \"live\" };\n }\n return { kind: \"hit\", cached: toCachedSpan(body.response) };\n case \"miss\":\n return { kind: \"miss\" };\n case \"live\":\n return { kind: \"live\" };\n default:\n logger.warn(\n `Unknown debug cache outcome \"${body.outcome}\", running live`,\n );\n return { kind: \"live\" };\n }\n }\n\n public async delete({ sessionId }: { sessionId: string }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/rollouts/${sessionId}`,\n {\n method: \"DELETE\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import {\n type Signal,\n type SignalFilter,\n type SignalMode,\n type SignalStructuredOutput,\n type SignalTrigger,\n} from \"@lmnr-ai/types\";\n\nimport { BaseResource, type LaminarAuth } from \".\";\n\nexport interface CreateSignalOptions {\n name: string;\n prompt: string;\n structuredOutput: SignalStructuredOutput;\n /** Omit for no sampling. */\n sampleRate?: number;\n disabled?: boolean;\n /** Omit for the default (root span finished). */\n trigger?: SignalTrigger;\n /** Omit for the default (>1000 tokens); `[]` runs on every firing trace. */\n filters?: SignalFilter[];\n /** Defaults to `\"realtime\"`. */\n mode?: SignalMode;\n}\n\n/**\n * A partial patch. Every field is optional and an ABSENT field leaves the stored\n * value alone. `sampleRate: null` clears sampling, `filters: []` clears filters.\n */\nexport interface UpdateSignalOptions {\n prompt?: string;\n structuredOutput?: SignalStructuredOutput;\n sampleRate?: number | null;\n disabled?: boolean;\n trigger?: SignalTrigger;\n filters?: SignalFilter[];\n mode?: SignalMode;\n}\n\n/** Signals CRUD over the CLI user-token surface (`/v1/cli/signals`). */\nexport class SignalsResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Every signal route answers errors as `{ error: \"<message>\" }`, and those\n * messages are written to be shown to the user verbatim (e.g. \"A signal named\n * X already exists in this project\"). The shared `handleError` would surface\n * the raw JSON body, so unwrap the envelope here and fall back to it when the\n * body isn't the expected shape.\n */\n private async raiseSignalError(response: Response): Promise<never> {\n const body = await response.text();\n let message = body;\n try {\n const parsed = JSON.parse(body) as { error?: unknown };\n if (typeof parsed?.error === \"string\" && parsed.error.length > 0) {\n message = parsed.error;\n }\n } catch {\n // Not JSON (a proxy error page, an actix plain-text 413) — use it as-is.\n }\n throw new Error(`${response.status} ${message}`);\n }\n\n public async list(name?: string): Promise<Signal[]> {\n const query = name ? `?${new URLSearchParams({ name }).toString()}` : \"\";\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/signals${query}`, {\n method: \"GET\",\n headers: this.headers(),\n });\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n // Coerce a missing/non-array `signals` to [] so callers can .map/.length it;\n // a malformed body on a 2xx is exceptional, not the normal empty case.\n const body = (await response.json()) as { signals?: Signal[] };\n return Array.isArray(body?.signals) ? body.signals : [];\n }\n\n public async get(signalId: string): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n { method: \"GET\", headers: this.headers() },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n public async create(options: CreateSignalOptions): Promise<Signal> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/signals`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(options),\n });\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n /**\n * PATCH, not PUT: only the keys present in `options` are sent, so the server\n * leaves everything else as stored. An explicit `null` on `sampleRate` must\n * survive serialization (it means \"clear\"), so nulls are NOT stripped here.\n */\n public async update(signalId: string, options: UpdateSignalOptions): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify(options),\n },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n\n /** Deletes the signal, its triggers, its alerts, and its ClickHouse events. */\n public async delete(signalId: string): Promise<Signal> {\n const response = await fetch(\n `${this.baseHttpUrl}${this.apiPrefix}/signals/${signalId}`,\n { method: \"DELETE\", headers: this.headers() },\n );\n if (!response.ok) {\n await this.raiseSignalError(response);\n }\n return response.json() as Promise<Signal>;\n }\n}\n","import type { SqlSchema } from \"@lmnr-ai/types\";\n\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n public async query(\n sql: string,\n parameters: Record<string, any> = {},\n ): Promise<Array<Record<string, any>>> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/sql/query`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n },\n body: JSON.stringify({\n query: sql,\n parameters,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()).data as Array<Record<string, any>>;\n }\n\n /**\n * Fetch the queryable tables, columns, and enums. Server-rendered from\n * app-server's `query_engine::schema`, so it is the same source that backs\n * the MCP `query_laminar_sql` tool description — never a client-side copy.\n */\n public async schema(): Promise<SqlSchema> {\n const response = await fetch(`${this.baseHttpUrl}${this.apiPrefix}/sql/schema`, {\n method: \"GET\",\n headers: {\n ...this.headers(),\n },\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as SqlSchema;\n }\n}\n","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Tag a trace with a list of tags. Note that the trace must be ended before\n * tagging it. You may want to call `await Laminar.flush()` after the trace\n * that you want to tag.\n *\n * @param {string | StringUUID} trace_id - The trace id to tag.\n * @param {string[] | string} tags - The tag or list of tags to add to the trace.\n * @returns {Promise<any>} The response from the server.\n * @example\n * ```javascript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n * let traceId: StringUUID | null = null;\n * // Make sure this is called outside of traced context.\n * await observe(\n * {\n * name: \"my-trace\",\n * },\n * async () => {\n * traceId = await Laminar.getTraceId();\n * await foo();\n * },\n * );\n *\n * // or make sure the trace is ended by this point.\n * await Laminar.flush();\n * if (traceId) {\n * await client.tags.tag(traceId, [\"tag1\", \"tag2\"]);\n * }\n * ```\n */\n public async tag(\n trace_id: string,\n tags: string[] | string,\n ): Promise<any> {\n const traceTags = Array.isArray(tags) ? tags : [tags];\n const formattedTraceId = isStringUUID(trace_id)\n ? trace_id\n : otelTraceIdToUUID(trace_id);\n\n const url = this.baseHttpUrl + \"/v1/tag\";\n const payload = {\n \"traceId\": formattedTraceId,\n \"names\": traceTags,\n };\n const response = await fetch(\n url,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n },\n );\n if (!response.ok) {\n await this.handleError(response);\n }\n return response.json();\n }\n}\n","/** Resource for post-factum operations on existing traces. */\n\nimport { initializeLogger, isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource, type LaminarAuth } from \"./index\";\n\nconst logger = initializeLogger();\n\nexport class TracesResource extends BaseResource {\n /** Resource for post-factum operations on existing traces. */\n constructor(baseHttpUrl: string, auth: LaminarAuth) {\n super(baseHttpUrl, auth);\n }\n\n /**\n * Push a metadata patch to an existing trace.\n *\n * The patch is shallow-merged server-side into the trace's existing metadata\n * (`existing || patch`, last-write-wins per top-level key). Useful for\n * attaching post-factum signals — quality scores, human edits, triage labels —\n * to a trace that has already finished. The patch does NOT extend `endTime`\n * or change tokens / cost / top span / tags / span names. `numSpans` is\n * incremented by 1 (paid by the virtual span that carried the patch through\n * the ingestion queue) so the new ClickHouse row beats the prior version on\n * `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.\n *\n * Compared to `Laminar.setTraceMetadata` (which sets metadata on the\n * currently in-flight trace via OpenTelemetry attributes), this method\n * operates on a finished trace by trace id, so it must be called after the\n * trace has been flushed.\n *\n * A 404 response (the trace was not found in the project — typically because\n * it has not been flushed yet) is logged as a warning and the call returns\n * without throwing, since the 404 may be expected when pushing too soon\n * after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.\n * CLI callers that must report the failure). Any other non-OK status throws.\n *\n * @param traceId - The trace id to push metadata to. Accepts a UUID string\n * or a 32-char OTel hex trace id.\n * @param metadata - The metadata patch. Top-level keys are merged into the\n * trace's existing metadata. Must be non-empty (the server rejects empty\n * patches with 400).\n * @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.\n * @example\n * ```typescript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n *\n * let traceId: string | null = null;\n * await observe({ name: \"generate\" }, async () => {\n * traceId = await Laminar.getTraceId();\n * });\n * await Laminar.flush();\n *\n * if (traceId) {\n * await client.traces.pushMetadata(traceId, {\n * score: 0.85,\n * reviewer: \"alice\",\n * needsReview: false,\n * });\n * }\n * ```\n */\n public async pushMetadata(\n traceId: string,\n metadata: Record<string, unknown>,\n options?: { failOnNotFound?: boolean },\n ): Promise<void> {\n if (!metadata || Object.keys(metadata).length === 0) {\n throw new Error(\"metadata must be a non-empty object\");\n }\n\n const formattedTraceId = isStringUUID(traceId)\n ? traceId\n : otelTraceIdToUUID(traceId);\n\n const url = this.baseHttpUrl + this.apiPrefix + \"/traces/metadata\";\n const response = await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n traceId: formattedTraceId,\n metadata,\n }),\n });\n\n if (response.status === 404) {\n const message =\n `Trace ${formattedTraceId} not found. The trace may not have been ` +\n \"flushed yet — call await Laminar.flush() and retry.\";\n if (options?.failOnNotFound) {\n throw new Error(message);\n }\n // Trace not found in this project — likely not flushed yet. Don't throw,\n // but surface a warning so callers debugging an empty patch see it.\n logger.warn(message);\n return;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { CliResource } from \"./resources/cli\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { type LaminarAuth } from \"./resources/index\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\nimport { SignalsResource } from \"./resources/signals\";\nimport { SqlResource } from \"./resources/sql\";\nimport { TagsResource } from \"./resources/tags\";\nimport { TracesResource } from \"./resources/traces\";\nimport { loadEnv } from \"./utils\";\n\nexport class LaminarClient {\n private baseUrl: string;\n private auth: LaminarAuth;\n private _browserEvents: BrowserEventsResource;\n private _cli: CliResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _signals: SignalsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n private _traces: TracesResource;\n\n constructor({\n baseUrl,\n port,\n auth,\n projectApiKey,\n cliUserProjectId,\n }: {\n baseUrl?: string,\n port?: number,\n /**\n * Unified auth. A discriminated union that drives both the URL prefix and\n * the request headers:\n * - `{ type: \"apiKey\", key }` → project key, `/v1/*`.\n * - `{ type: \"userToken\", token, projectId }` → user JWT, `/v1/cli/*` with\n * `x-lmnr-project-id`.\n * When omitted, the legacy `projectApiKey` / `cliUserProjectId` fields (or\n * `LMNR_PROJECT_API_KEY`) are normalized into this union.\n */\n auth?: LaminarAuth,\n /**\n * @deprecated Pass `auth: { type: \"apiKey\", key }` instead. Kept for\n * backward compatibility — normalized into the unified `auth` union.\n */\n projectApiKey?: string,\n /**\n * @deprecated Pass `auth: { type: \"userToken\", token, projectId }` instead.\n * Kept for backward compatibility: when set, the legacy `projectApiKey` is\n * treated as a user JWT and routes to `/v1/cli/*` with this project id.\n */\n cliUserProjectId?: string,\n } = {}) {\n loadEnv();\n this.auth = LaminarClient.normalizeAuth(auth, projectApiKey, cliUserProjectId);\n const httpPort = port ?? (\n baseUrl?.match(/:\\d{1,5}$/g)\n ? parseInt(baseUrl.match(/:\\d{1,5}$/g)![0].slice(1))\n : 443);\n const baseUrlNoPort = (baseUrl ?? process.env.LMNR_BASE_URL)\n ?.replace(/\\/$/, '').replace(/:\\d{1,5}$/g, '');\n this.baseUrl = `${baseUrlNoPort ?? 'https://api.lmnr.ai'}:${httpPort}`;\n this._browserEvents = new BrowserEventsResource(this.baseUrl, this.auth);\n this._cli = new CliResource(this.baseUrl, this.auth);\n this._datasets = new DatasetsResource(this.baseUrl, this.auth);\n this._evals = new EvalsResource(this.baseUrl, this.auth);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.auth);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.auth);\n this._signals = new SignalsResource(this.baseUrl, this.auth);\n this._sql = new SqlResource(this.baseUrl, this.auth);\n this._tags = new TagsResource(this.baseUrl, this.auth);\n this._traces = new TracesResource(this.baseUrl, this.auth);\n }\n\n /**\n * The fully-resolved API origin every resource fetches from, e.g.\n * `http://localhost:8000`. Already normalized: trailing slash removed, any\n * port embedded in `baseUrl` stripped, and the effective port appended.\n *\n * Exposed so callers can name the real address in diagnostics instead of\n * rebuilding it from `baseUrl` + `port` — that reconstruction drifts from\n * this normalization and prints things like `http://host:8000:9000`.\n */\n public get apiBaseUrl(): string {\n return this.baseUrl;\n }\n\n /**\n * Normalize the constructor's auth inputs into a {@link LaminarAuth} union.\n * Precedence: an explicit `auth` wins; otherwise the legacy\n * `projectApiKey` (+ optional `cliUserProjectId`) is mapped — a present\n * `cliUserProjectId` selects the user-token surface, otherwise the project\n * key surface. Falls back to `LMNR_PROJECT_API_KEY` as a project key.\n */\n private static normalizeAuth(\n auth: LaminarAuth | undefined,\n projectApiKey: string | undefined,\n cliUserProjectId: string | undefined,\n ): LaminarAuth {\n if (auth) {\n return auth;\n }\n const key = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\n if (cliUserProjectId) {\n return { type: \"userToken\", token: key, projectId: cliUserProjectId };\n }\n return { type: \"apiKey\", key };\n }\n\n public get browserEvents() {\n return this._browserEvents;\n }\n\n public get cli() {\n return this._cli;\n }\n\n public get datasets() {\n return this._datasets;\n }\n\n public get evals() {\n return this._evals;\n }\n\n public get evaluators() {\n return this._evaluators;\n }\n\n public get signals() {\n return this._signals;\n }\n\n public get rolloutSessions() {\n return this._rolloutSessions;\n }\n\n public get sql() {\n return this._sql;\n }\n\n public get tags() {\n return this._tags;\n }\n\n public get traces() {\n return this._traces;\n }\n}\n\nexport type { CliProject, ProjectKeyProbe } from \"./resources/cli\";\nexport type { LaminarAuth } from \"./resources/index\";\nexport {\n type CacheOutcome,\n RolloutSessionsResource,\n} from \"./resources/rollout-sessions\";\nexport type {\n CreateSignalOptions,\n UpdateSignalOptions,\n} from \"./resources/signals\";\n"],"mappings":";;;;;;;;;;ACCA,SAAgB,iBAAgC;CAC9C,IAAI,OAAO,YAAY,eAAe,QAAQ,YAAY,QAAQ,SAAS,MACzE,OAAO,QAAQ,QAAQ,SAAS;CAElC,IAAI,OAAO,cAAc,eAAe,UAAU,WAChD,OAAO,WAAW,UAAU;CAE9B,OAAO;AACT;;;ACKA,IAAM,eAAN,MAAmB;CAMjB,YAAY,aAAqB,MAAmB;EAClD,KAAK,cAAc;EACnB,KAAK,OAAO;EACZ,KAAK,aAAa,KAAK,SAAS,WAAW,KAAK,MAAM,KAAK;CAC7D;;CAGA,IAAc,YAAoB;EAChC,OAAO,KAAK,KAAK,SAAS,cAAc,YAAY;CACtD;CAEA,UAAoB;EAClB,OAAO;GACL,eAAe,UAAU,KAAK;GAC9B,gBAAgB;GAChB,QAAQ;GACR,GAAI,KAAK,KAAK,SAAS,cACnB,EAAE,qBAAqB,KAAK,KAAK,UAAU,IAC3C,CAAC;EACP;CACF;CAEA,MAAgB,YAAY,UAAoB;EAC9C,MAAM,WAAW,MAAM,SAAS,KAAK;EACrC,MAAM,IAAI,MAAM,GAAG,SAAS,OAAO,GAAG,UAAU;CAClD;AACF;;;AC1CA,IAAa,wBAAb,cAA2C,aAAa;CACtD,YAAY,aAAqB,MAAmB;EAClD,MAAM,aAAa,IAAI;CACzB;CAEA,MAAa,KAAK,EAChB,WACA,SACA,UAKgB;EAChB,MAAM,UAAU;GACd;GACA;GACA;GACA,QAAQ,eAAe,KAAK;GAC5B,YAAYA;EACd;EAEA,MAAM,aAAa,KAAK,UAAU,OAAO;EAEzC,MAAM,mBAAmB,IADR,KAAK,CAAC,UAAU,GAAG,EAAE,MAAM,mBAAmB,CACnC,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,IAAI,kBAAkB,MAAM,CAAC;EAEhF,MAAM,iBAAiB,MAAM,IADE,SAAS,gBACM,CAAC,CAAC,YAAY;EAE5D,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,+BAA+B;GAC7E,QAAQ;GACR,SAAS;IACP,GAAG,KAAK,QAAQ;IAChB,oBAAoB;GACtB;GACA,MAAM;EACR,CAAC;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;CAEnC;AACF;;;;;;;;;AC9BA,MAAM,kBAAkB,IAAI,KAAK,SAAS,KAAA,GAAW,EAAE,aAAa,OAAO,CAAC;;AAG5E,MAAM,gBAAgB,aACpB,CAAC,GAAG,QAAQ,CAAC,CAAC,MACX,GAAG,MACF,gBAAgB,QAAQ,EAAE,iBAAiB,IAAI,EAAE,iBAAiB,EAAE,KACpE,gBAAgB,QAAQ,EAAE,QAAQ,IAAI,EAAE,QAAQ,EAAE,CACtD;;;;;;;;;;AA0BF,IAAa,cAAb,cAAiC,aAAa;CAC5C,YAAY,aAAqB,MAAmB;EAClD,MAAM,aAAa,IAAI;CACzB;;CAGA,MAAa,eAAsC;EACjD,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,mBAAmB;GAClE,QAAQ;GACR,SAAS;IACP,eAAe,UAAU,KAAK;IAC9B,QAAQ;GACV;EACF,CAAC;EACD,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAKjC,MAAM,OAAQ,MAAM,SAAS,KAAK;EAClC,OAAO,MAAM,QAAQ,MAAM,QAAQ,IAAI,aAAa,KAAK,QAAQ,IAAI,CAAC;CACxE;;;;;;;;CASA,MAAa,uBAAuB,QAA0C;EAC5E,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,kBAAkB;IAC3D,QAAQ;IACR,SAAS;KACP,eAAe,UAAU,KAAK;KAC9B,gBAAgB;KAChB,QAAQ;IACV;IACA,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;GACjC,CAAC;EACH,QAAQ;GACN,OAAO,EAAE,QAAQ,eAAe;EAClC;EACA,IAAI,SAAS,WAAW,KAAK,OAAO,EAAE,QAAQ,UAAU;EACxD,IAAI,CAAC,SAAS,IAAI,OAAO,EAAE,QAAQ,eAAe;EAClD,MAAM,OAAQ,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,IAAI;EACpD,OAAO,MAAM,YACT;GAAE,QAAQ;GAAM,WAAW,KAAK;EAAU,IAC1C,EAAE,QAAQ,eAAe;CAC/B;AACF;;;AC/FA,SAAgB,iBAAiB,SAAiD;CAChF,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,QACJ,SAAS,SACR,QAAQ,IAAI,gBAAgB,YAAY,CAAC,EAAE,KAAK,KACjD;CAEF,OAAO,KACL,EACE,MACF,GACA,WAAW;EACT;EACA,cAAc;CAChB,CAAC,CACH;AACF;AAEA,MAAMC,WAAS,iBAAiB;AAEhC,MAAa,gBAAgB,OAC3B,iEAAiE,KAAK,EAAE;AAI1E,MAAa,gBAA4B;CAKvC,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAChE,OAAO,OAAO,WAAW;MAEzB,OAAOC,GAAO;AAElB;AAEA,MAAa,oBAAoB,WAA2B;CAC1D,IAAI,KAAK,OAAO,YAAY;CAC5B,IAAI,GAAG,WAAW,IAAI,GACpB,KAAK,GAAG,MAAM,CAAC;CAEjB,IAAI,GAAG,WAAW,IAChB,SAAO,KACL,WAAW,OAAO,sEAEpB;CAGF,IAAI,CAAC,cAAc,KAAK,EAAE,GAAG;EAC3B,SAAO,MACL,WAAW,OAAO,8DAEpB;EACA,OAAO,QAAQ;CACjB;CAEA,OAAO,GAAG,SAAS,IAAI,GAAG,CAAC,CAAC,QAC1B,wEACA,gBACF;AACF;AAEA,MAAa,qBAAqB,YAAgC;CAChE,IAAI,KAAK,QAAQ,YAAY;CAC7B,IAAI,GAAG,WAAW,IAAI,GACpB,KAAK,GAAG,MAAM,CAAC;CAEjB,IAAI,GAAG,WAAW,IAChB,SAAO,KACL,YAAY,QAAQ,uEAEtB;CAEF,IAAI,CAAC,cAAc,KAAK,EAAE,GAAG;EAC3B,SAAO,MACL,YAAY,QAAQ,8DAEtB;EACA,OAAO,QAAQ;CACjB;CAEA,OAAO,GAAG,QACR,wEACA,gBACF;AACF;AAEA,MAAa,gBAAmB,OAAU,WAAmB;CAC3D,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;CAGT,MAAM,MAAM,KAAK,UAAU,KAAK;CAChC,IAAI,IAAI,UAAU,QAChB,OAAO;CAGT,OAAO,IAAI,MAAM,GAAG,MAAM,IAAI;AAChC;AAEA,MAAa,WACX,YAIS;CACT,MAAM,UAAU,QAAQ,IAAI,YAAY;CACxC,MAAM,SAAS,QAAQ,IAAI;CAI3B,MAAM,WAAW;EACf;EACA;EACA,QAAQ;EACR,QAAQ,QAAQ;CAClB;CAEA,MAAM,WAAW,QAAQ,IAAI,kBAAkB;CAC/C,MAAM,UAAU,CAAC,SAAS,OAAO,CAAC,CAAC,SAAS,SAAS,KAAK,CAAC,CAAC,YAAY,CAAC;CAEzE,MAAM,QAAQ,SAAS,SAAS,CAAC;CAEjC,OAAO;EACL,MAAM,SAAS,SAAS,SAAS,KAAK,YAAY,KAAK,QAAQ,QAAQ,OAAO,CAAC;EAC/E;CACF,CAAC;AACH;;;AC5HA,MAAMC,WAAS,iBAAiB;AAChC,MAAM,6BAA6B;AACnC,MAAM,kCAAkC;AAExC,IAAa,mBAAb,cAAsC,aAAa;CACjD,YAAY,aAAqB,MAAmB;EAClD,MAAM,aAAa,IAAI;CACzB;;;;;;CAOA,MAAa,eAAmC;EAC9C,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,KAAK,YAAY,aAAa;GAC5E,QAAQ;GACR,SAAS,KAAK,QAAQ;EACxB,CAAC;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,OAAO,SAAS,KAAK;CACvB;;;;;;;CAQA,MAAa,iBAAiB,MAAkC;EAC9D,MAAM,SAAS,IAAI,gBAAgB,EAAE,KAAK,CAAC;EAC3C,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,GAAG,KAAK,UAAU,YAAY,OAAO,SAAS,KACjE;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;EACxB,CACF;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,OAAO,SAAS,KAAK;CACvB;;;;;;;;;;;;CAaA,MAAa,KAAW,EACtB,QACA,MACA,IACA,YAAY,iCACZ,gBAAgB,SAO8B;EAC9C,IAAI,CAAC,QAAQ,CAAC,IACZ,MAAM,IAAI,MAAM,oCAAoC;EAGtD,IAAI,QAAQ,IACV,MAAM,IAAI,MAAM,yCAAyC;EAG3D,IAAI,iBAAiB,CAAC,MACpB,MAAM,IAAI,MAAM,mDAAmD;EAGrE,MAAM,aAAa,OAAO,EAAE,KAAK,IAAI,EAAE,WAAW,GAAI;EACtD,MAAM,eAAe,KAAK,KAAK,OAAO,SAAS,SAAS;EAExD,IAAI;EACJ,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,WAAW;GACjD,MAAM,WAAW,KAAK,MAAM,IAAI,SAAS,IAAI;GAC7C,SAAO,MAAM,iBAAiB,SAAS,MAAM,cAAc;GAE3D,MAAM,QAAQ,OAAO,MAAM,GAAG,IAAI,SAAS;GAC3C,MAAM,gBAAgB,MAAM,MAC1B,KAAK,cAAc,KAAK,YAAY,wBACpC;IACE,QAAQ;IACR,SAAS,KAAK,QAAQ;IACtB,MAAM,KAAK,UAAU;KACnB,GAAG;KACH,YAAY,MAAM,KAAK,WAAW;MAChC,MAAM,MAAM;MACZ,QAAQ,MAAM,UAAU,CAAC;MACzB,UAAU,MAAM,YAAY,CAAC;KAC/B,EAAE;KACF;IACF,CAAC;GACH,CACF;GAGA,IAAI,cAAc,WAAW,OAAO,cAAc,WAAW,KAC3D,MAAM,KAAK,YAAY,aAAa;GAGtC,WAAY,MAAM,cAAc,KAAK;EACvC;EAEA,OAAO;CACT;;;;;;;;;;;CAYA,MAAa,KAAW,EACtB,MACA,IACA,QAAQ,4BACR,SAAS,KAM8B;EACvC,IAAI,CAAC,QAAQ,CAAC,IACZ,MAAM,IAAI,MAAM,oCAAoC;EAGtD,IAAI,QAAQ,IACV,MAAM,IAAI,MAAM,yCAAyC;EAG3D,MAAM,YAAoC;GACxC,QAAQ,OAAO,SAAS;GACxB,OAAO,MAAM,SAAS;EACxB;EAEA,IAAI,MACF,UAAU,OAAO;OAEjB,UAAU,YAAY;EAGxB,MAAM,SAAS,IAAI,gBAAgB,SAAS;EAE5C,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,GAAG,KAAK,UAAU,uBAAuB,OAAO,SAAS,KAC5E;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;EACxB,CACF;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,OAAO,SAAS,KAAK;CACvB;AACF;;;ACpLA,MAAMC,WAAS,iBAAiB;AAChC,MAAM,+CAA+C;AAErD,IAAa,gBAAb,cAAmC,aAAa;CAC9C,YAAY,aAAqB,MAAmB;EAClD,MAAM,aAAa,IAAI;CACzB;;;;;;;;;CAUA,MAAa,KACX,MACA,WACA,UACiC;EACjC,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa;GAC3D,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU;IACnB,MAAM,QAAQ;IACd,WAAW,aAAa;IACxB,UAAU,YAAY;GACxB,CAAC;EACH,CAAC;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,OAAO,SAAS,KAAK;CACvB;;;;;;;;;CAWA,MAAa,OAAO,MAEI;EAEtB,QAAO,MADkB,KAAK,KAAK,MAAM,MAAM,MAAM,WAAW,MAAM,QAAQ,EAAA,CAC5D;CACpB;;;;;;;;;;;CAYA,MAAa,OAAO,EAClB,QACA,MACA,YAKkC;EAClC,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,UAAU;GACrE,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU;IACnB,MAAM,QAAQ;IACd,UAAU,YAAY;GACxB,CAAC;EACH,CAAC;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,OAAO,SAAS,KAAK;CACvB;;;;;CAMA,MAAa,iBACX,MACA,WACA,UACqB;EAErB,QAAO,MADkB,KAAK,KAAK,MAAM,WAAW,QAAQ,EAAA,CAC1C;CACpB;;;;;;;;;;;;;CAcA,MAAa,gBAAsB,EACjC,QACA,MACA,QACA,UACA,OACA,WAQsB;EACtB,MAAM,cAAc,QAAQ;EAE5B,MAAM,mBAAmD;GACvD,IAAI;GACJ;GACA;GACA,OAAO,SAAS;GAChB,SAAS,WAAW,QAAQ;GAC5B,gBAAgB,QAAQ;GACxB;EACF;EAEA,MAAM,KAAK,eAAe;GACxB;GACA,YAAY,CAAC,gBAAgB;EAC/B,CAAC;EAED,OAAO;CACT;;;;;;;;;;;CAYA,MAAa,gBAAmB,EAC9B,QACA,aACA,QACA,kBAMgB;EAChB,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,aAAa,OAAO,cAAc,eACrD;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU;IACnB;IACA;GACF,CAAC;EACH,CACF;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;CAEnC;;;;;;;;;;CAWA,MAAa,eAAwB,EACnC,QACA,YACA,aAKgB;EAChB,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc;GAChF,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU;IACnB,QAAQ,WAAW,KAAK,OACtB;KACE,GAAG;KACH,MAAM,aAAa,EAAE,MAAM,4CAA4C;KACvE,QAAQ,aAAa,EAAE,QAAQ,4CAA4C;KAC3E,gBAAgB,aACd,EAAE,gBACF,4CACF;IACF,EAAE;IACJ,WAAW,aAAa;GAC1B,CAAC;EACH,CAAC;EAED,IAAI,SAAS,WAAW,KACtB,OAAO,MAAM,KAAK,oBAAoB;GACpC;GACA;GACA;EACF,CAAC;EAGH,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;CAEnC;;;;;;;;;;;CAYA,MAAa,cAAoB,EAC/B,aACA,QACA,SAKuC;EACvC,SAAO,KACL,0EACF;EAEA,MAAM,SAAS,IAAI,gBAAgB;GACjC,MAAM;GACN,QAAQ,OAAO,SAAS;GACxB,OAAO,MAAM,SAAS;EACxB,CAAC;EACD,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,2BAA2B,OAAO,SAAS,KAC9D;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;EACxB,CACF;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,OAAQ,MAAM,SAAS,KAAK;CAC9B;CAEA,MAAc,oBAA6B,EACzC,QACA,YACA,WACA,aAAa,IACb,gBAAgB,gDAOA;EAChB,IAAI,SAAS;EACb,IAAI,eAAgC;EACpC,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;GACnC,SAAO,MAAM,+BAA+B,IAAI,EAAE,MAAM,WAAW,YAAY,QAAQ;GACvF,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc;IAChF,QAAQ;IACR,SAAS,KAAK,QAAQ;IACtB,MAAM,KAAK,UAAU;KACnB,QAAQ,WAAW,KAAK,OACtB;MACE,GAAG;MACH,MAAM,aAAa,EAAE,MAAM,MAAM;MACjC,QAAQ,aAAa,EAAE,QAAQ,MAAM;MACrC,gBAAgB,aAAa,EAAE,gBAAgB,MAAM;KACvD,EAAE;KACJ,WAAW,aAAa;IAC1B,CAAC;GACH,CAAC;GACD,eAAe;GACf,SAAS,KAAK,MAAM,SAAS,CAAC;GAC9B,IAAI,SAAS,WAAW,KACtB;EAEJ;EACA,IAAI,gBAAgB,CAAC,aAAa,IAChC,MAAM,KAAK,YAAY,YAAY;CAEvC;AACF;;;;;;AC1SA,IAAa,qBAAb,cAAwC,aAAa;CACnD,YAAY,aAAqB,MAAmB;EAClD,MAAM,aAAa,IAAI;CACzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BA,MAAa,MAAM,SAAsC;EACvD,MAAM,EAAE,MAAM,UAAU,UAAU;EAElC,IAAI;EAEJ,IAAI,aAAa,WAAW,QAAQ,SAKlC,UAAU;GACR;GACA;GACA;GACA,QAAA;GACA,SATuB,aAAa,QAAQ,OAAO,IACjD,QAAQ,UACR,kBAAkB,QAAQ,OAAO;EAQrC;OACK,IAAI,YAAY,WAAW,QAAQ,QAKxC,UAAU;GACR;GACA;GACA;GACA,QAAA;GACA,QATsB,aAAa,QAAQ,MAAM,IAC/C,QAAQ,SACR,iBAAiB,QAAQ,MAAM;EAQnC;OAEA,MAAM,IAAI,MAAM,gDAAgD;EAGlE,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,wBAAwB;GACtE,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU,OAAO;EAC9B,CAAC;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;CAEnC;AACF;;;ACjGA,MAAMC,WAAS,iBAAiB;;;;;;;;;;AA0BhC,MAAM,gBAAgB,aAAkC;CACtD,MAAM,SACJ,OAAO,aAAa,WAAW,WAAW,KAAK,UAAU,YAAY,IAAI;CAC3E,MAAM,aAAkC,CAAC;CACzC,IACE,aAAa,QACb,OAAO,aAAa,YACpB,OAAQ,SAAqC,iBAAiB,UAE9D,WAAW,8BACT,SACA;CAEJ,OAAO;EAAE,MAAM;EAAI,OAAO;EAAI;EAAQ;CAAW;AACnD;AAEA,IAAa,0BAAb,cAA6C,aAAa;CACxD,YAAY,aAAqB,MAAmB;EAClD,MAAM,aAAa,IAAI;CACzB;;;;;;;;;CAUA,MAAa,SAAS,EACpB,WACA,QAIyB;EACzB,MAAM,WAAW,MAAM,MACrB,GAAG,KAAK,cAAc,KAAK,UAAU,YAAY,aACjD;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU,EAAE,KAAK,CAAC;EAC/B,CACF;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,IAAI;GAEF,QAAO,MADa,SAAS,KAAK,EAAA,CACtB,aAAa;EAC3B,SAAS,GAAG;GACV,SAAO,KACL,8CAA8C,aAAa,CAAC,GAC9D;GACA,OAAO;EACT;CACF;;;;;;;CAQA,MAAa,QAAQ,EACnB,WACA,QAIgB;EAChB,MAAM,WAAW,MAAM,MACrB,GAAG,KAAK,cAAc,KAAK,UAAU,YAAY,UAAU,QAC3D;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU,EAAE,KAAK,CAAC;EAC/B,CACF;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;CAEnC;;;;;;;;;;;;;;;;CAiBA,MAAa,SAAS,EACpB,WACA,MACA,SACA,gBACA,UAUyB;EACzB,MAAM,WAAW,MAAM,MACrB,GAAG,KAAK,cAAc,KAAK,UAAU,YAAY,UAAU,UAC3D;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU;IAAE;IAAM;GAAQ,CAAC;GACtC;EACF,CACF;EAEA,IAAI,SAAS,WAAW,KAAK;GAC3B,MAAM,UACJ,8CAA8C,UAAU;GAK1D,IAAI,gBACF,MAAM,IAAI,MAAM,OAAO;GAEzB,SAAO,KAAK,OAAO;GACnB,OAAO;EACT;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,IAAI;GAEF,QAAO,MADa,SAAS,KAAK,EAAA,CACtB,MAAM;EACpB,SAAS,GAAG;GACV,SAAO,KAAK,uCAAuC,aAAa,CAAC,GAAG;GACpE,OAAO;EACT;CACF;;;;;;;;;CAUA,MAAa,WAAW,EACtB,aAG0B;EAC1B,MAAM,WAAW,MAAM,MACrB,GAAG,KAAK,cAAc,KAAK,UAAU,YAAY,UAAU,UAC3D;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;EACxB,CACF;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,IAAI;GACF,MAAM,OAAQ,MAAM,SAAS,KAAK;GAIlC,QADe,MAAM,QAAQ,IAAI,IAAI,OAAO,KAAK,WAChC,CAAC;EACpB,SAAS,GAAG;GACV,SAAO,KAAK,yCAAyC,aAAa,CAAC,GAAG;GACtE,OAAO,CAAC;EACV;CACF;;;;;;;;;;;;;;;CAgBA,MAAa,MAAM,EACjB,WACA,eACA,YACA,aAMwB;EACxB,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,MACf,GAAG,KAAK,cAAc,KAAK,UAAU,YAAY,UAAU,SAC3D;IACE,QAAQ;IACR,SAAS,KAAK,QAAQ;IACtB,MAAM,KAAK,UAAU;KAAE;KAAe;KAAY;IAAU,CAAC;GAC/D,CACF;EACF,SAAS,GAAG;GACV,SAAO,KAAK,4CAA4C,aAAa,CAAC,GAAG;GACzE,OAAO,EAAE,MAAM,OAAO;EACxB;EAEA,IAAI,CAAC,SAAS,IAAI;GAChB,SAAO,KACL,+BAA+B,SAAS,OAAO,eACjD;GACA,OAAO,EAAE,MAAM,OAAO;EACxB;EAEA,IAAI;EACJ,IAAI;GACF,OAAQ,MAAM,SAAS,KAAK;EAC9B,SAAS,GAAG;GACV,SAAO,KACL,uDAAuD,aAAa,CAAC,GACvE;GACA,OAAO,EAAE,MAAM,OAAO;EACxB;EAEA,QAAQ,KAAK,SAAb;GACE,KAAK;IAIH,IAAI,KAAK,aAAa,QAAQ,KAAK,aAAa,KAAA,GAAW;KACzD,SAAO,KAAK,uDAAuD;KACnE,OAAO,EAAE,MAAM,OAAO;IACxB;IACA,OAAO;KAAE,MAAM;KAAO,QAAQ,aAAa,KAAK,QAAQ;IAAE;GAC5D,KAAK,QACH,OAAO,EAAE,MAAM,OAAO;GACxB,KAAK,QACH,OAAO,EAAE,MAAM,OAAO;GACxB;IACE,SAAO,KACL,gCAAgC,KAAK,QAAQ,gBAC/C;IACA,OAAO,EAAE,MAAM,OAAO;EAC1B;CACF;CAEA,MAAa,OAAO,EAAE,aAAmD;EACvE,MAAM,WAAW,MAAM,MACrB,GAAG,KAAK,cAAc,KAAK,UAAU,YAAY,aACjD;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;EACxB,CACF;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;CAEnC;AACF;;;;ACzRA,IAAa,kBAAb,cAAqC,aAAa;CAChD,YAAY,aAAqB,MAAmB;EAClD,MAAM,aAAa,IAAI;CACzB;;;;;;;;CASA,MAAc,iBAAiB,UAAoC;EACjE,MAAM,OAAO,MAAM,SAAS,KAAK;EACjC,IAAI,UAAU;EACd,IAAI;GACF,MAAM,SAAS,KAAK,MAAM,IAAI;GAC9B,IAAI,OAAO,QAAQ,UAAU,YAAY,OAAO,MAAM,SAAS,GAC7D,UAAU,OAAO;EAErB,QAAQ,CAER;EACA,MAAM,IAAI,MAAM,GAAG,SAAS,OAAO,GAAG,SAAS;CACjD;CAEA,MAAa,KAAK,MAAkC;EAClD,MAAM,QAAQ,OAAO,IAAI,IAAI,gBAAgB,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,MAAM;EACtE,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,cAAc,KAAK,UAAU,UAAU,SAAS;GACnF,QAAQ;GACR,SAAS,KAAK,QAAQ;EACxB,CAAC;EACD,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,iBAAiB,QAAQ;EAItC,MAAM,OAAQ,MAAM,SAAS,KAAK;EAClC,OAAO,MAAM,QAAQ,MAAM,OAAO,IAAI,KAAK,UAAU,CAAC;CACxD;CAEA,MAAa,IAAI,UAAmC;EAClD,MAAM,WAAW,MAAM,MACrB,GAAG,KAAK,cAAc,KAAK,UAAU,WAAW,YAChD;GAAE,QAAQ;GAAO,SAAS,KAAK,QAAQ;EAAE,CAC3C;EACA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,iBAAiB,QAAQ;EAEtC,OAAO,SAAS,KAAK;CACvB;CAEA,MAAa,OAAO,SAA+C;EACjE,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,cAAc,KAAK,UAAU,WAAW;GAC3E,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU,OAAO;EAC9B,CAAC;EACD,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,iBAAiB,QAAQ;EAEtC,OAAO,SAAS,KAAK;CACvB;;;;;;CAOA,MAAa,OAAO,UAAkB,SAA+C;EACnF,MAAM,WAAW,MAAM,MACrB,GAAG,KAAK,cAAc,KAAK,UAAU,WAAW,YAChD;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU,OAAO;EAC9B,CACF;EACA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,iBAAiB,QAAQ;EAEtC,OAAO,SAAS,KAAK;CACvB;;CAGA,MAAa,OAAO,UAAmC;EACrD,MAAM,WAAW,MAAM,MACrB,GAAG,KAAK,cAAc,KAAK,UAAU,WAAW,YAChD;GAAE,QAAQ;GAAU,SAAS,KAAK,QAAQ;EAAE,CAC9C;EACA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,iBAAiB,QAAQ;EAEtC,OAAO,SAAS,KAAK;CACvB;AACF;;;ACnIA,IAAa,cAAb,cAAiC,aAAa;CAC5C,YAAY,aAAqB,MAAmB;EAClD,MAAM,aAAa,IAAI;CACzB;CAEA,MAAa,MACX,KACA,aAAkC,CAAC,GACE;EACrC,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,cAAc,KAAK,UAAU,aAAa;GAC7E,QAAQ;GACR,SAAS,EACP,GAAG,KAAK,QAAQ,EAClB;GACA,MAAM,KAAK,UAAU;IACnB,OAAO;IACP;GACF,CAAC;EACH,CAAC;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,QAAQ,MAAM,SAAS,KAAK,EAAA,CAAG;CACjC;;;;;;CAOA,MAAa,SAA6B;EACxC,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,cAAc,KAAK,UAAU,cAAc;GAC9E,QAAQ;GACR,SAAS,EACP,GAAG,KAAK,QAAQ,EAClB;EACF,CAAC;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAGjC,OAAQ,MAAM,SAAS,KAAK;CAC9B;AACF;;;;AC5CA,IAAa,eAAb,cAAkC,aAAa;;CAE7C,YAAY,aAAqB,MAAmB;EAClD,MAAM,aAAa,IAAI;CACzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCA,MAAa,IACX,UACA,MACc;EACd,MAAM,YAAY,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;EACpD,MAAM,mBAAmB,aAAa,QAAQ,IAC1C,WACA,kBAAkB,QAAQ;EAE9B,MAAM,MAAM,KAAK,cAAc;EAC/B,MAAM,UAAU;GACd,WAAW;GACX,SAAS;EACX;EACA,MAAM,WAAW,MAAM,MACrB,KACA;GACE,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU,OAAO;EAC9B,CACF;EACA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;EAEjC,OAAO,SAAS,KAAK;CACvB;AACF;;;;AClEA,MAAM,SAAS,iBAAiB;AAEhC,IAAa,iBAAb,cAAoC,aAAa;;CAE/C,YAAY,aAAqB,MAAmB;EAClD,MAAM,aAAa,IAAI;CACzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDA,MAAa,aACX,SACA,UACA,SACe;EACf,IAAI,CAAC,YAAY,OAAO,KAAK,QAAQ,CAAC,CAAC,WAAW,GAChD,MAAM,IAAI,MAAM,qCAAqC;EAGvD,MAAM,mBAAmB,aAAa,OAAO,IACzC,UACA,kBAAkB,OAAO;EAE7B,MAAM,MAAM,KAAK,cAAc,KAAK,YAAY;EAChD,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,QAAQ;GACR,SAAS,KAAK,QAAQ;GACtB,MAAM,KAAK,UAAU;IACnB,SAAS;IACT;GACF,CAAC;EACH,CAAC;EAED,IAAI,SAAS,WAAW,KAAK;GAC3B,MAAM,UACJ,SAAS,iBAAiB;GAE5B,IAAI,SAAS,gBACX,MAAM,IAAI,MAAM,OAAO;GAIzB,OAAO,KAAK,OAAO;GACnB;EACF;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,QAAQ;CAEnC;AACF;;;AC1FA,IAAa,gBAAb,MAAa,cAAc;CAczB,YAAY,EACV,SACA,MACA,MACA,eACA,qBAyBE,CAAC,GAAG;EACN,QAAQ;EACR,KAAK,OAAO,cAAc,cAAc,MAAM,eAAe,gBAAgB;EAC7E,MAAM,WAAW,SACf,SAAS,MAAM,YAAY,IACvB,SAAS,QAAQ,MAAM,YAAY,CAAC,CAAE,EAAE,CAAC,MAAM,CAAC,CAAC,IACjD;EACN,MAAM,iBAAiB,WAAW,QAAQ,IAAI,cAAA,EAC1C,QAAQ,OAAO,EAAE,CAAC,CAAC,QAAQ,cAAc,EAAE;EAC/C,KAAK,UAAU,GAAG,iBAAiB,sBAAsB,GAAG;EAC5D,KAAK,iBAAiB,IAAI,sBAAsB,KAAK,SAAS,KAAK,IAAI;EACvE,KAAK,OAAO,IAAI,YAAY,KAAK,SAAS,KAAK,IAAI;EACnD,KAAK,YAAY,IAAI,iBAAiB,KAAK,SAAS,KAAK,IAAI;EAC7D,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI;EACvD,KAAK,cAAc,IAAI,mBAAmB,KAAK,SAAS,KAAK,IAAI;EACjE,KAAK,mBAAmB,IAAI,wBAAwB,KAAK,SAAS,KAAK,IAAI;EAC3E,KAAK,WAAW,IAAI,gBAAgB,KAAK,SAAS,KAAK,IAAI;EAC3D,KAAK,OAAO,IAAI,YAAY,KAAK,SAAS,KAAK,IAAI;EACnD,KAAK,QAAQ,IAAI,aAAa,KAAK,SAAS,KAAK,IAAI;EACrD,KAAK,UAAU,IAAI,eAAe,KAAK,SAAS,KAAK,IAAI;CAC3D;;;;;;;;;;CAWA,IAAW,aAAqB;EAC9B,OAAO,KAAK;CACd;;;;;;;;CASA,OAAe,cACb,MACA,eACA,kBACa;EACb,IAAI,MACF,OAAO;EAET,MAAM,MAAM,iBAAiB,QAAQ,IAAI;EACzC,IAAI,kBACF,OAAO;GAAE,MAAM;GAAa,OAAO;GAAK,WAAW;EAAiB;EAEtE,OAAO;GAAE,MAAM;GAAU;EAAI;CAC/B;CAEA,IAAW,gBAAgB;EACzB,OAAO,KAAK;CACd;CAEA,IAAW,MAAM;EACf,OAAO,KAAK;CACd;CAEA,IAAW,WAAW;EACpB,OAAO,KAAK;CACd;CAEA,IAAW,QAAQ;EACjB,OAAO,KAAK;CACd;CAEA,IAAW,aAAa;EACtB,OAAO,KAAK;CACd;CAEA,IAAW,UAAU;EACnB,OAAO,KAAK;CACd;CAEA,IAAW,kBAAkB;EAC3B,OAAO,KAAK;CACd;CAEA,IAAW,MAAM;EACf,OAAO,KAAK;CACd;CAEA,IAAW,OAAO;EAChB,OAAO,KAAK;CACd;CAEA,IAAW,SAAS;EAClB,OAAO,KAAK;CACd;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmnr-ai/client",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.43",
|
|
4
4
|
"description": "HTTP client for Laminar AI API",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"nock": "^14.0.8",
|
|
41
41
|
"tsx": "^4.22.4",
|
|
42
|
-
"@lmnr-ai/types": "0.8.
|
|
42
|
+
"@lmnr-ai/types": "0.8.43"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "tsdown",
|