@lmnr-ai/client 0.8.25 → 0.8.26
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 +90 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -0
- package/dist/index.d.mts +56 -0
- package/dist/index.mjs +90 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -29,7 +29,7 @@ pino = __toESM(pino);
|
|
|
29
29
|
let pino_pretty = require("pino-pretty");
|
|
30
30
|
let uuid = require("uuid");
|
|
31
31
|
//#region package.json
|
|
32
|
-
var version = "0.8.
|
|
32
|
+
var version = "0.8.26";
|
|
33
33
|
//#endregion
|
|
34
34
|
//#region src/version.ts
|
|
35
35
|
function getLangVersion() {
|
|
@@ -94,7 +94,7 @@ function initializeLogger(options) {
|
|
|
94
94
|
minimumLevel: level
|
|
95
95
|
}));
|
|
96
96
|
}
|
|
97
|
-
const logger$
|
|
97
|
+
const logger$3 = initializeLogger();
|
|
98
98
|
const isStringUUID = (id) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);
|
|
99
99
|
const newUUID = () => {
|
|
100
100
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
@@ -103,9 +103,9 @@ const newUUID = () => {
|
|
|
103
103
|
const otelSpanIdToUUID = (spanId) => {
|
|
104
104
|
let id = spanId.toLowerCase();
|
|
105
105
|
if (id.startsWith("0x")) id = id.slice(2);
|
|
106
|
-
if (id.length !== 16) logger$
|
|
106
|
+
if (id.length !== 16) logger$3.warn(`Span ID ${spanId} is not 16 hex chars long. This is not a valid OpenTelemetry span ID.`);
|
|
107
107
|
if (!/^[0-9a-f]+$/.test(id)) {
|
|
108
|
-
logger$
|
|
108
|
+
logger$3.error(`Span ID ${spanId} is not a valid hex string. Generating a random UUID instead.`);
|
|
109
109
|
return newUUID();
|
|
110
110
|
}
|
|
111
111
|
return id.padStart(32, "0").replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, "$1-$2-$3-$4-$5");
|
|
@@ -113,9 +113,9 @@ const otelSpanIdToUUID = (spanId) => {
|
|
|
113
113
|
const otelTraceIdToUUID = (traceId) => {
|
|
114
114
|
let id = traceId.toLowerCase();
|
|
115
115
|
if (id.startsWith("0x")) id = id.slice(2);
|
|
116
|
-
if (id.length !== 32) logger$
|
|
116
|
+
if (id.length !== 32) logger$3.warn(`Trace ID ${traceId} is not 32 hex chars long. This is not a valid OpenTelemetry trace ID.`);
|
|
117
117
|
if (!/^[0-9a-f]+$/.test(id)) {
|
|
118
|
-
logger$
|
|
118
|
+
logger$3.error(`Trace ID ${traceId} is not a valid hex string. Generating a random UUID instead.`);
|
|
119
119
|
return newUUID();
|
|
120
120
|
}
|
|
121
121
|
return id.replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, "$1-$2-$3-$4-$5");
|
|
@@ -145,7 +145,7 @@ const loadEnv = (options) => {
|
|
|
145
145
|
};
|
|
146
146
|
//#endregion
|
|
147
147
|
//#region src/resources/datasets.ts
|
|
148
|
-
const logger$
|
|
148
|
+
const logger$2 = initializeLogger();
|
|
149
149
|
const DEFAULT_DATASET_PULL_LIMIT = 100;
|
|
150
150
|
const DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;
|
|
151
151
|
var DatasetsResource = class extends BaseResource {
|
|
@@ -200,7 +200,7 @@ var DatasetsResource = class extends BaseResource {
|
|
|
200
200
|
let response;
|
|
201
201
|
for (let i = 0; i < points.length; i += batchSize) {
|
|
202
202
|
const batchNum = Math.floor(i / batchSize) + 1;
|
|
203
|
-
logger$
|
|
203
|
+
logger$2.debug(`Pushing batch ${batchNum} of ${totalBatches}`);
|
|
204
204
|
const batch = points.slice(i, i + batchSize);
|
|
205
205
|
const fetchResponse = await fetch(this.baseHttpUrl + "/v1/datasets/datapoints", {
|
|
206
206
|
method: "POST",
|
|
@@ -250,7 +250,7 @@ var DatasetsResource = class extends BaseResource {
|
|
|
250
250
|
};
|
|
251
251
|
//#endregion
|
|
252
252
|
//#region src/resources/evals.ts
|
|
253
|
-
const logger = initializeLogger();
|
|
253
|
+
const logger$1 = initializeLogger();
|
|
254
254
|
const INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16e6;
|
|
255
255
|
var EvalsResource = class extends BaseResource {
|
|
256
256
|
constructor(baseHttpUrl, projectApiKey) {
|
|
@@ -386,7 +386,7 @@ var EvalsResource = class extends BaseResource {
|
|
|
386
386
|
* @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval
|
|
387
387
|
*/
|
|
388
388
|
async getDatapoints({ datasetName, offset, limit }) {
|
|
389
|
-
logger.warn("evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.");
|
|
389
|
+
logger$1.warn("evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.");
|
|
390
390
|
const params = new URLSearchParams({
|
|
391
391
|
name: datasetName,
|
|
392
392
|
offset: offset.toString(),
|
|
@@ -403,7 +403,7 @@ var EvalsResource = class extends BaseResource {
|
|
|
403
403
|
let length = initialLength;
|
|
404
404
|
let lastResponse = null;
|
|
405
405
|
for (let i = 0; i < maxRetries; i++) {
|
|
406
|
-
logger.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);
|
|
406
|
+
logger$1.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);
|
|
407
407
|
const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {
|
|
408
408
|
method: "POST",
|
|
409
409
|
headers: this.headers(),
|
|
@@ -624,6 +624,81 @@ var TagsResource = class extends BaseResource {
|
|
|
624
624
|
}
|
|
625
625
|
};
|
|
626
626
|
//#endregion
|
|
627
|
+
//#region src/resources/traces.ts
|
|
628
|
+
/** Resource for post-factum operations on existing traces. */
|
|
629
|
+
const logger = initializeLogger();
|
|
630
|
+
var TracesResource = class extends BaseResource {
|
|
631
|
+
/** Resource for post-factum operations on existing traces. */
|
|
632
|
+
constructor(baseHttpUrl, projectApiKey) {
|
|
633
|
+
super(baseHttpUrl, projectApiKey);
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Push a metadata patch to an existing trace.
|
|
637
|
+
*
|
|
638
|
+
* The patch is shallow-merged server-side into the trace's existing metadata
|
|
639
|
+
* (`existing || patch`, last-write-wins per top-level key). Useful for
|
|
640
|
+
* attaching post-factum signals — quality scores, human edits, triage labels —
|
|
641
|
+
* to a trace that has already finished. The patch does NOT extend `endTime`
|
|
642
|
+
* or change tokens / cost / top span / tags / span names. `numSpans` is
|
|
643
|
+
* incremented by 1 (paid by the virtual span that carried the patch through
|
|
644
|
+
* the ingestion queue) so the new ClickHouse row beats the prior version on
|
|
645
|
+
* `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.
|
|
646
|
+
*
|
|
647
|
+
* Compared to `Laminar.setTraceMetadata` (which sets metadata on the
|
|
648
|
+
* currently in-flight trace via OpenTelemetry attributes), this method
|
|
649
|
+
* operates on a finished trace by trace id, so it must be called after the
|
|
650
|
+
* trace has been flushed.
|
|
651
|
+
*
|
|
652
|
+
* A 404 response (the trace was not found in the project — typically because
|
|
653
|
+
* it has not been flushed yet) is logged as a warning and the call returns
|
|
654
|
+
* without throwing; any other non-OK status throws.
|
|
655
|
+
*
|
|
656
|
+
* @param traceId - The trace id to push metadata to. Accepts a UUID string
|
|
657
|
+
* or a 32-char OTel hex trace id.
|
|
658
|
+
* @param metadata - The metadata patch. Top-level keys are merged into the
|
|
659
|
+
* trace's existing metadata. Must be non-empty (the server rejects empty
|
|
660
|
+
* patches with 400).
|
|
661
|
+
* @example
|
|
662
|
+
* ```typescript
|
|
663
|
+
* import { Laminar, observe, LaminarClient } from "@lmnr-ai/lmnr";
|
|
664
|
+
* Laminar.initialize();
|
|
665
|
+
* const client = new LaminarClient();
|
|
666
|
+
*
|
|
667
|
+
* let traceId: string | null = null;
|
|
668
|
+
* await observe({ name: "generate" }, async () => {
|
|
669
|
+
* traceId = await Laminar.getTraceId();
|
|
670
|
+
* });
|
|
671
|
+
* await Laminar.flush();
|
|
672
|
+
*
|
|
673
|
+
* if (traceId) {
|
|
674
|
+
* await client.traces.pushMetadata(traceId, {
|
|
675
|
+
* score: 0.85,
|
|
676
|
+
* reviewer: "alice",
|
|
677
|
+
* needsReview: false,
|
|
678
|
+
* });
|
|
679
|
+
* }
|
|
680
|
+
* ```
|
|
681
|
+
*/
|
|
682
|
+
async pushMetadata(traceId, metadata) {
|
|
683
|
+
if (!metadata || Object.keys(metadata).length === 0) throw new Error("metadata must be a non-empty object");
|
|
684
|
+
const formattedTraceId = isStringUUID(traceId) ? traceId : otelTraceIdToUUID(traceId);
|
|
685
|
+
const url = this.baseHttpUrl + "/v1/traces/metadata";
|
|
686
|
+
const response = await fetch(url, {
|
|
687
|
+
method: "POST",
|
|
688
|
+
headers: this.headers(),
|
|
689
|
+
body: JSON.stringify({
|
|
690
|
+
traceId: formattedTraceId,
|
|
691
|
+
metadata
|
|
692
|
+
})
|
|
693
|
+
});
|
|
694
|
+
if (response.status === 404) {
|
|
695
|
+
logger.warn(`Trace ${formattedTraceId} not found. The trace may not have been flushed yet — call await Laminar.flush() and retry.`);
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
if (!response.ok) await this.handleError(response);
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
//#endregion
|
|
627
702
|
//#region src/index.ts
|
|
628
703
|
var LaminarClient = class {
|
|
629
704
|
constructor({ baseUrl, projectApiKey, port } = {}) {
|
|
@@ -639,6 +714,7 @@ var LaminarClient = class {
|
|
|
639
714
|
this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.projectApiKey);
|
|
640
715
|
this._sql = new SqlResource(this.baseUrl, this.projectApiKey);
|
|
641
716
|
this._tags = new TagsResource(this.baseUrl, this.projectApiKey);
|
|
717
|
+
this._traces = new TracesResource(this.baseUrl, this.projectApiKey);
|
|
642
718
|
}
|
|
643
719
|
get browserEvents() {
|
|
644
720
|
return this._browserEvents;
|
|
@@ -661,6 +737,9 @@ var LaminarClient = class {
|
|
|
661
737
|
get tags() {
|
|
662
738
|
return this._tags;
|
|
663
739
|
}
|
|
740
|
+
get traces() {
|
|
741
|
+
return this._traces;
|
|
742
|
+
}
|
|
664
743
|
};
|
|
665
744
|
//#endregion
|
|
666
745
|
exports.LaminarClient = LaminarClient;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["SDK_VERSION","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.ts","../src/resources/sql.ts","../src/resources/tags.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","class BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly projectApiKey: string;\n\n constructor(baseHttpUrl: string, projectApiKey: string) {\n this.baseHttpUrl = baseHttpUrl;\n this.projectApiKey = projectApiKey;\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.projectApiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\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 } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 { 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 + \"/v1/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 + `/v1/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 + \"/v1/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 + `/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 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 * 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 { type RolloutParam, type SpanType } from \"@lmnr-ai/types\";\n\nimport { otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Connects to the SSE stream for rollout debugging sessions\n * Returns the Response object for streaming SSE events\n */\n public async connect({\n sessionId,\n name,\n params,\n signal,\n }: {\n sessionId: string;\n params: RolloutParam[];\n name: string;\n signal?: AbortSignal;\n }): Promise<Response> {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Accept': 'text/event-stream',\n },\n body: JSON.stringify({ name, params }),\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n return response;\n }\n\n public async delete({\n sessionId,\n }: {\n sessionId: string;\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"DELETE\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async setStatus({\n sessionId,\n status,\n }: {\n sessionId: string;\n status: 'PENDING' | 'RUNNING' | 'FINISHED' | 'STOPPED';\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/status`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ status }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async sendSpanUpdate({\n sessionId,\n span,\n }: {\n sessionId: string;\n span: {\n name: string;\n startTime: string;\n spanId: string;\n traceId: string;\n parentSpanId: string | undefined;\n attributes: Record<string, any>;\n spanType: SpanType;\n };\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/update`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({\n type: \"spanStart\",\n spanId: otelSpanIdToUUID(span.spanId),\n traceId: otelTraceIdToUUID(span.traceId),\n parentSpanId: span.parentSpanId ? otelSpanIdToUUID(span.parentSpanId) : undefined,\n attributes: span.attributes,\n startTime: span.startTime,\n name: span.name,\n spanType: span.spanType,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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}/v1/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","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\nimport { SqlResource } from \"./resources/sql\";\nimport { TagsResource } from \"./resources/tags\";\nimport { loadEnv } from \"./utils\";\n\nexport class LaminarClient {\n private baseUrl: string;\n private projectApiKey: string;\n private _browserEvents: BrowserEventsResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n\n constructor({\n baseUrl,\n projectApiKey,\n port,\n }: {\n baseUrl?: string,\n projectApiKey?: string,\n port?: number,\n } = {}) {\n loadEnv();\n this.projectApiKey = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\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.projectApiKey);\n this._datasets = new DatasetsResource(this.baseUrl, this.projectApiKey);\n this._evals = new EvalsResource(this.baseUrl, this.projectApiKey);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.projectApiKey);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.projectApiKey);\n this._sql = new SqlResource(this.baseUrl, this.projectApiKey);\n this._tags = new TagsResource(this.baseUrl, this.projectApiKey);\n }\n\n public get browserEvents() {\n return this._browserEvents;\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 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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["SDK_VERSION","logger","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.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","class BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly projectApiKey: string;\n\n constructor(baseHttpUrl: string, projectApiKey: string) {\n this.baseHttpUrl = baseHttpUrl;\n this.projectApiKey = projectApiKey;\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.projectApiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\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 } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 { 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 + \"/v1/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 + `/v1/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 + \"/v1/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 + `/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 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 * 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 { type RolloutParam, type SpanType } from \"@lmnr-ai/types\";\n\nimport { otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Connects to the SSE stream for rollout debugging sessions\n * Returns the Response object for streaming SSE events\n */\n public async connect({\n sessionId,\n name,\n params,\n signal,\n }: {\n sessionId: string;\n params: RolloutParam[];\n name: string;\n signal?: AbortSignal;\n }): Promise<Response> {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Accept': 'text/event-stream',\n },\n body: JSON.stringify({ name, params }),\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n return response;\n }\n\n public async delete({\n sessionId,\n }: {\n sessionId: string;\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"DELETE\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async setStatus({\n sessionId,\n status,\n }: {\n sessionId: string;\n status: 'PENDING' | 'RUNNING' | 'FINISHED' | 'STOPPED';\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/status`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ status }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async sendSpanUpdate({\n sessionId,\n span,\n }: {\n sessionId: string;\n span: {\n name: string;\n startTime: string;\n spanId: string;\n traceId: string;\n parentSpanId: string | undefined;\n attributes: Record<string, any>;\n spanType: SpanType;\n };\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/update`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({\n type: \"spanStart\",\n spanId: otelSpanIdToUUID(span.spanId),\n traceId: otelTraceIdToUUID(span.traceId),\n parentSpanId: span.parentSpanId ? otelSpanIdToUUID(span.parentSpanId) : undefined,\n attributes: span.attributes,\n startTime: span.startTime,\n name: span.name,\n spanType: span.spanType,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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}/v1/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","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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; 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 * @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 ): 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 + \"/v1/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 // 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(\n `Trace ${formattedTraceId} not found. The trace may not have been ` +\n \"flushed yet — call await Laminar.flush() and retry.\",\n );\n return;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\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 projectApiKey: string;\n private _browserEvents: BrowserEventsResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n private _traces: TracesResource;\n\n constructor({\n baseUrl,\n projectApiKey,\n port,\n }: {\n baseUrl?: string,\n projectApiKey?: string,\n port?: number,\n } = {}) {\n loadEnv();\n this.projectApiKey = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\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.projectApiKey);\n this._datasets = new DatasetsResource(this.baseUrl, this.projectApiKey);\n this._evals = new EvalsResource(this.baseUrl, this.projectApiKey);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.projectApiKey);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.projectApiKey);\n this._sql = new SqlResource(this.baseUrl, this.projectApiKey);\n this._tags = new TagsResource(this.baseUrl, this.projectApiKey);\n this._traces = new TracesResource(this.baseUrl, this.projectApiKey);\n }\n\n public get browserEvents() {\n return this._browserEvents;\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 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"],"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;;;;ACRT,IAAM,eAAN,MAAmB;CAIjB,YAAY,aAAqB,eAAuB;EACtD,KAAK,cAAc;EACnB,KAAK,gBAAgB;;CAGvB,UAAoB;EAClB,OAAO;GACL,eAAe,UAAU,KAAK;GAC9B,gBAAgB;GAChB,QAAQ;GACT;;CAGH,MAAgB,YAAY,UAAoB;EAC9C,MAAM,WAAW,MAAM,SAAS,MAAM;EACtC,MAAM,IAAI,MAAM,GAAG,SAAS,OAAO,GAAG,WAAW;;;;;ACfrD,IAAa,wBAAb,cAA2C,aAAa;CACtD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;CAGnC,MAAa,KAAK,EAChB,WACA,SACA,UAKgB;EAChB,MAAM,UAAU;GACd;GACA;GACA;GACA,QAAQ,gBAAgB,IAAI;GAC5B,YAAYA;GACb;EAED,MAAM,aAAa,KAAK,UAAU,QAAQ;EAE1C,MAAM,mBAAmB,IADR,KAAK,CAAC,WAAW,EAAE,EAAE,MAAM,oBAAoB,CACnC,CAAC,QAAQ,CAAC,YAAY,IAAI,kBAAkB,OAAO,CAAC;EAEjF,MAAM,iBAAiB,MAAM,IADE,SAAS,iBACO,CAAC,aAAa;EAE7D,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,+BAA+B;GAC7E,QAAQ;GACR,SAAS;IACP,GAAG,KAAK,SAAS;IACjB,oBAAoB;IACrB;GACD,MAAM;GACP,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;ACnCtC,SAAgB,iBAAiB,SAAiD;CAChF,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,QACJ,SAAS,SACR,QAAQ,IAAI,gBAAgB,aAAa,EAAE,MAAM,IAClD;CAEF,QAAA,GAAA,KAAA,SACE,EACE,OACD,GAAA,GAAA,YAAA,YACU;EACT;EACA,cAAc;EACf,CAAC,CACH;;AAGH,MAAMC,WAAS,kBAAkB;AAEjC,MAAa,gBAAgB,OAC3B,iEAAiE,KAAK,GAAG;AAI3E,MAAa,gBAA4B;CAKvC,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAChE,OAAO,OAAO,YAAY;MAE1B,QAAA,GAAA,KAAA,KAAe;;AAInB,MAAa,oBAAoB,WAA2B;CAC1D,IAAI,KAAK,OAAO,aAAa;CAC7B,IAAI,GAAG,WAAW,KAAK,EACrB,KAAK,GAAG,MAAM,EAAE;CAElB,IAAI,GAAG,WAAW,IAChB,SAAO,KACL,WAAW,OAAO,uEAEnB;CAGH,IAAI,CAAC,cAAc,KAAK,GAAG,EAAE;EAC3B,SAAO,MACL,WAAW,OAAO,+DAEnB;EACD,OAAO,SAAS;;CAGlB,OAAO,GAAG,SAAS,IAAI,IAAI,CAAC,QAC1B,wEACA,iBACD;;AAGH,MAAa,qBAAqB,YAAgC;CAChE,IAAI,KAAK,QAAQ,aAAa;CAC9B,IAAI,GAAG,WAAW,KAAK,EACrB,KAAK,GAAG,MAAM,EAAE;CAElB,IAAI,GAAG,WAAW,IAChB,SAAO,KACL,YAAY,QAAQ,wEAErB;CAEH,IAAI,CAAC,cAAc,KAAK,GAAG,EAAE;EAC3B,SAAO,MACL,YAAY,QAAQ,+DAErB;EACD,OAAO,SAAS;;CAGlB,OAAO,GAAG,QACR,wEACA,iBACD;;AAGH,MAAa,gBAAmB,OAAU,WAAmB;CAC3D,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;CAGT,MAAM,MAAM,KAAK,UAAU,MAAM;CACjC,IAAI,IAAI,UAAU,QAChB,OAAO;CAGT,OAAO,IAAI,MAAM,GAAG,OAAO,GAAG;;AAGhC,MAAa,WACX,YAIS;CACT,MAAM,UAAU,QAAQ,IAAI,YAAY;CACxC,MAAM,SAAS,QAAQ,KAAK;CAI5B,MAAM,WAAW;EACf;EACA;EACA,QAAQ;EACR,QAAQ,QAAQ;EACjB;CAED,MAAM,WAAW,QAAQ,IAAI,kBAAkB;CAC/C,MAAM,UAAU,CAAC,SAAS,QAAQ,CAAC,SAAS,SAAS,MAAM,CAAC,aAAa,CAAC;CAE1E,MAAM,QAAQ,SAAS,SAAS,CAAC;CAEjC,CAAA,GAAA,OAAA,QAAO;EACL,MAAM,SAAS,SAAS,SAAS,KAAK,YAAY,KAAK,QAAQ,QAAQ,QAAQ,CAAC;EAChF;EACD,CAAC;;;;AC3HJ,MAAMC,WAAS,kBAAkB;AACjC,MAAM,6BAA6B;AACnC,MAAM,kCAAkC;AAExC,IAAa,mBAAb,cAAsC,aAAa;CACjD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;CAQnC,MAAa,eAAmC;EAC9C,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,gBAAgB;GAC9D,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;;;;CASxB,MAAa,iBAAiB,MAAkC;EAC9D,MAAM,SAAS,IAAI,gBAAgB,EAAE,MAAM,CAAC;EAC5C,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,gBAAgB,OAAO,UAAU,IACpD;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;;;;;;;;;CAcxB,MAAa,KAAW,EACtB,QACA,MACA,IACA,YAAY,iCACZ,gBAAgB,SAO8B;EAC9C,IAAI,CAAC,QAAQ,CAAC,IACZ,MAAM,IAAI,MAAM,qCAAqC;EAGvD,IAAI,QAAQ,IACV,MAAM,IAAI,MAAM,0CAA0C;EAG5D,IAAI,iBAAiB,CAAC,MACpB,MAAM,IAAI,MAAM,oDAAoD;EAGtE,MAAM,aAAa,OAAO,EAAE,MAAM,GAAG,EAAE,WAAW,IAAK;EACvD,MAAM,eAAe,KAAK,KAAK,OAAO,SAAS,UAAU;EAEzD,IAAI;EACJ,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,WAAW;GACjD,MAAM,WAAW,KAAK,MAAM,IAAI,UAAU,GAAG;GAC7C,SAAO,MAAM,iBAAiB,SAAS,MAAM,eAAe;GAE5D,MAAM,QAAQ,OAAO,MAAM,GAAG,IAAI,UAAU;GAC5C,MAAM,gBAAgB,MAAM,MAC1B,KAAK,cAAc,2BACnB;IACE,QAAQ;IACR,SAAS,KAAK,SAAS;IACvB,MAAM,KAAK,UAAU;KACnB,GAAG;KACH,YAAY,MAAM,KAAK,WAAW;MAChC,MAAM,MAAM;MACZ,QAAQ,MAAM,UAAU,EAAE;MAC1B,UAAU,MAAM,YAAY,EAAE;MAC/B,EAAE;KACH;KACD,CAAC;IACH,CACF;GAGD,IAAI,cAAc,WAAW,OAAO,cAAc,WAAW,KAC3D,MAAM,KAAK,YAAY,cAAc;GAGvC,WAAY,MAAM,cAAc,MAAM;;EAGxC,OAAO;;;;;;;;;;;;CAaT,MAAa,KAAW,EACtB,MACA,IACA,QAAQ,4BACR,SAAS,KAM8B;EACvC,IAAI,CAAC,QAAQ,CAAC,IACZ,MAAM,IAAI,MAAM,qCAAqC;EAGvD,IAAI,QAAQ,IACV,MAAM,IAAI,MAAM,0CAA0C;EAG5D,MAAM,YAAoC;GACxC,QAAQ,OAAO,UAAU;GACzB,OAAO,MAAM,UAAU;GACxB;EAED,IAAI,MACF,UAAU,OAAO;OAEjB,UAAU,YAAY;EAGxB,MAAM,SAAS,IAAI,gBAAgB,UAAU;EAE7C,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,2BAA2B,OAAO,UAAU,IAC/D;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;AClL1B,MAAMC,WAAS,kBAAkB;AACjC,MAAM,+CAA+C;AAErD,IAAa,gBAAb,cAAmC,aAAa;CAC9C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;CAWnC,MAAa,KACX,MACA,WACA,UACiC;EACjC,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa;GAC3D,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,MAAM,QAAQ;IACd,WAAW,aAAa;IACxB,UAAU,YAAY;IACvB,CAAC;GACH,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;;;;;;CAYxB,MAAa,OAAO,MAEI;EAEtB,QAAO,MADkB,KAAK,KAAK,MAAM,MAAM,MAAM,WAAW,MAAM,SAAS,EAC7D;;;;;;CAOpB,MAAa,iBACX,MACA,WACA,UACqB;EAErB,QAAO,MADkB,KAAK,KAAK,MAAM,WAAW,SAAS,EAC3C;;;;;;;;;;;;;;CAepB,MAAa,gBAAsB,EACjC,QACA,MACA,QACA,UACA,OACA,WAQsB;EACtB,MAAM,cAAc,SAAS;EAE7B,MAAM,mBAAmD;GACvD,IAAI;GACJ;GACA;GACA,OAAO,SAAS;GAChB,SAAS,WAAW,SAAS;GAC7B,gBAAgB,SAAS;GACzB;GACD;EAED,MAAM,KAAK,eAAe;GACxB;GACA,YAAY,CAAC,iBAAiB;GAC/B,CAAC;EAEF,OAAO;;;;;;;;;;;;CAaT,MAAa,gBAAmB,EAC9B,QACA,aACA,QACA,kBAMgB;EAChB,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,aAAa,OAAO,cAAc,eACrD;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB;IACA;IACD,CAAC;GACH,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;;;;;;;CAapC,MAAa,eAAwB,EACnC,QACA,YACA,aAKgB;EAChB,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc;GAChF,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,QAAQ,WAAW,KAAK,OACtB;KACE,GAAG;KACH,MAAM,aAAa,EAAE,MAAM,6CAA6C;KACxE,QAAQ,aAAa,EAAE,QAAQ,6CAA6C;KAC5E,gBAAgB,aACd,EAAE,gBACF,6CACD;KACF,EAAE;IACL,WAAW,aAAa;IACzB,CAAC;GACH,CAAC;EAEF,IAAI,SAAS,WAAW,KACtB,OAAO,MAAM,KAAK,oBAAoB;GACpC;GACA;GACA;GACD,CAAC;EAGJ,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;;;;;;;;CAcpC,MAAa,cAAoB,EAC/B,aACA,QACA,SAKuC;EACvC,SAAO,KACL,2EACD;EAED,MAAM,SAAS,IAAI,gBAAgB;GACjC,MAAM;GACN,QAAQ,OAAO,UAAU;GACzB,OAAO,MAAM,UAAU;GACxB,CAAC;EACF,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,2BAA2B,OAAO,UAAU,IAC/D;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAQ,MAAM,SAAS,MAAM;;CAG/B,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,SAAS;GACxF,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc;IAChF,QAAQ;IACR,SAAS,KAAK,SAAS;IACvB,MAAM,KAAK,UAAU;KACnB,QAAQ,WAAW,KAAK,OACtB;MACE,GAAG;MACH,MAAM,aAAa,EAAE,MAAM,OAAO;MAClC,QAAQ,aAAa,EAAE,QAAQ,OAAO;MACtC,gBAAgB,aAAa,EAAE,gBAAgB,OAAO;MACvD,EAAE;KACL,WAAW,aAAa;KACzB,CAAC;IACH,CAAC;GACF,eAAe;GACf,SAAS,KAAK,MAAM,SAAS,EAAE;GAC/B,IAAI,SAAS,WAAW,KACtB;;EAGJ,IAAI,gBAAgB,CAAC,aAAa,IAChC,MAAM,KAAK,YAAY,aAAa;;;;;;;;ACpQ1C,IAAa,qBAAb,cAAwC,aAAa;CACnD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BnC,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,QAAQ,GAClD,QAAQ,UACR,kBAAkB,QAAQ,QAAQ;GAQrC;OACI,IAAI,YAAY,WAAW,QAAQ,QAKxC,UAAU;GACR;GACA;GACA;GACA,QAAA;GACA,QATsB,aAAa,QAAQ,OAAO,GAChD,QAAQ,SACR,iBAAiB,QAAQ,OAAO;GAQnC;OAED,MAAM,IAAI,MAAM,iDAAiD;EAGnE,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,wBAAwB;GACtE,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,QAAQ;GAC9B,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;ACpGtC,IAAa,0BAAb,cAA6C,aAAa;CACxD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;CAOnC,MAAa,QAAQ,EACnB,WACA,MACA,QACA,UAMoB;EACpB,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,aAAa;GAC3E,QAAQ;GACR,SAAS;IACP,GAAG,KAAK,SAAS;IACjB,UAAU;IACX;GACD,MAAM,KAAK,UAAU;IAAE;IAAM;IAAQ,CAAC;GACtC;GACD,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,0BAA0B,SAAS,OAAO,GAAG,SAAS,aAAa;EAGrF,IAAI,CAAC,SAAS,MACZ,MAAM,IAAI,MAAM,mBAAmB;EAGrC,OAAO;;CAGT,MAAa,OAAO,EAClB,aAGC;EACD,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,aAAa;GAC3E,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;CAIpC,MAAa,UAAU,EACrB,WACA,UAIC;EACD,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,UAAU,UAAU;GAClF,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC;GACjC,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;CAIpC,MAAa,eAAe,EAC1B,WACA,QAYC;EACD,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,UAAU,UAAU;GAClF,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,MAAM;IACN,QAAQ,iBAAiB,KAAK,OAAO;IACrC,SAAS,kBAAkB,KAAK,QAAQ;IACxC,cAAc,KAAK,eAAe,iBAAiB,KAAK,aAAa,GAAG,KAAA;IACxE,YAAY,KAAK;IACjB,WAAW,KAAK;IAChB,MAAM,KAAK;IACX,UAAU,KAAK;IAChB,CAAC;GACH,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;AC5GtC,IAAa,cAAb,cAAiC,aAAa;CAC5C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;CAGnC,MAAa,MACX,KACA,aAAkC,EAAE,EACC;EACrC,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,gBAAgB;GAC/D,QAAQ;GACR,SAAS,EACP,GAAG,KAAK,SAAS,EAClB;GACD,MAAM,KAAK,UAAU;IACnB,OAAO;IACP;IACD,CAAC;GACH,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,QAAQ,MAAM,SAAS,MAAM,EAAE;;;;;;ACpBnC,IAAa,eAAb,cAAkC,aAAa;;CAE7C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCnC,MAAa,IACX,UACA,MACc;EACd,MAAM,YAAY,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC,KAAK;EACrD,MAAM,mBAAmB,aAAa,SAAS,GAC3C,WACA,kBAAkB,SAAS;EAE/B,MAAM,MAAM,KAAK,cAAc;EAC/B,MAAM,UAAU;GACd,WAAW;GACX,SAAS;GACV;EACD,MAAM,WAAW,MAAM,MACrB,KACA;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,QAAQ;GAC9B,CACF;EACD,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAElC,OAAO,SAAS,MAAM;;;;;;AChE1B,MAAM,SAAS,kBAAkB;AAEjC,IAAa,iBAAb,cAAoC,aAAa;;CAE/C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDnC,MAAa,aACX,SACA,UACe;EACf,IAAI,CAAC,YAAY,OAAO,KAAK,SAAS,CAAC,WAAW,GAChD,MAAM,IAAI,MAAM,sCAAsC;EAGxD,MAAM,mBAAmB,aAAa,QAAQ,GAC1C,UACA,kBAAkB,QAAQ;EAE9B,MAAM,MAAM,KAAK,cAAc;EAC/B,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,SAAS;IACT;IACD,CAAC;GACH,CAAC;EAEF,IAAI,SAAS,WAAW,KAAK;GAG3B,OAAO,KACL,SAAS,iBAAiB,6FAE3B;GACD;;EAGF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;ACnFtC,IAAa,gBAAb,MAA2B;CAYzB,YAAY,EACV,SACA,eACA,SAKE,EAAE,EAAE;EACN,SAAS;EACT,KAAK,gBAAgB,iBAAiB,QAAQ,IAAI;EAClD,MAAM,WAAW,SACf,SAAS,MAAM,aAAa,GACxB,SAAS,QAAQ,MAAM,aAAa,CAAE,GAAG,MAAM,EAAE,CAAC,GAClD;EACN,MAAM,iBAAiB,WAAW,QAAQ,IAAI,gBAC1C,QAAQ,OAAO,GAAG,CAAC,QAAQ,cAAc,GAAG;EAChD,KAAK,UAAU,GAAG,iBAAiB,sBAAsB,GAAG;EAC5D,KAAK,iBAAiB,IAAI,sBAAsB,KAAK,SAAS,KAAK,cAAc;EACjF,KAAK,YAAY,IAAI,iBAAiB,KAAK,SAAS,KAAK,cAAc;EACvE,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS,KAAK,cAAc;EACjE,KAAK,cAAc,IAAI,mBAAmB,KAAK,SAAS,KAAK,cAAc;EAC3E,KAAK,mBAAmB,IAAI,wBAAwB,KAAK,SAAS,KAAK,cAAc;EACrF,KAAK,OAAO,IAAI,YAAY,KAAK,SAAS,KAAK,cAAc;EAC7D,KAAK,QAAQ,IAAI,aAAa,KAAK,SAAS,KAAK,cAAc;EAC/D,KAAK,UAAU,IAAI,eAAe,KAAK,SAAS,KAAK,cAAc;;CAGrE,IAAW,gBAAgB;EACzB,OAAO,KAAK;;CAGd,IAAW,WAAW;EACpB,OAAO,KAAK;;CAGd,IAAW,QAAQ;EACjB,OAAO,KAAK;;CAGd,IAAW,aAAa;EACtB,OAAO,KAAK;;CAGd,IAAW,kBAAkB;EAC3B,OAAO,KAAK;;CAGd,IAAW,MAAM;EACf,OAAO,KAAK;;CAGd,IAAW,OAAO;EAChB,OAAO,KAAK;;CAGd,IAAW,SAAS;EAClB,OAAO,KAAK"}
|
package/dist/index.d.cts
CHANGED
|
@@ -348,6 +348,60 @@ declare class TagsResource extends BaseResource {
|
|
|
348
348
|
tag(trace_id: string, tags: string[] | string): Promise<any>;
|
|
349
349
|
}
|
|
350
350
|
//#endregion
|
|
351
|
+
//#region src/resources/traces.d.ts
|
|
352
|
+
declare class TracesResource extends BaseResource {
|
|
353
|
+
/** Resource for post-factum operations on existing traces. */
|
|
354
|
+
constructor(baseHttpUrl: string, projectApiKey: string);
|
|
355
|
+
/**
|
|
356
|
+
* Push a metadata patch to an existing trace.
|
|
357
|
+
*
|
|
358
|
+
* The patch is shallow-merged server-side into the trace's existing metadata
|
|
359
|
+
* (`existing || patch`, last-write-wins per top-level key). Useful for
|
|
360
|
+
* attaching post-factum signals — quality scores, human edits, triage labels —
|
|
361
|
+
* to a trace that has already finished. The patch does NOT extend `endTime`
|
|
362
|
+
* or change tokens / cost / top span / tags / span names. `numSpans` is
|
|
363
|
+
* incremented by 1 (paid by the virtual span that carried the patch through
|
|
364
|
+
* the ingestion queue) so the new ClickHouse row beats the prior version on
|
|
365
|
+
* `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.
|
|
366
|
+
*
|
|
367
|
+
* Compared to `Laminar.setTraceMetadata` (which sets metadata on the
|
|
368
|
+
* currently in-flight trace via OpenTelemetry attributes), this method
|
|
369
|
+
* operates on a finished trace by trace id, so it must be called after the
|
|
370
|
+
* trace has been flushed.
|
|
371
|
+
*
|
|
372
|
+
* A 404 response (the trace was not found in the project — typically because
|
|
373
|
+
* it has not been flushed yet) is logged as a warning and the call returns
|
|
374
|
+
* without throwing; any other non-OK status throws.
|
|
375
|
+
*
|
|
376
|
+
* @param traceId - The trace id to push metadata to. Accepts a UUID string
|
|
377
|
+
* or a 32-char OTel hex trace id.
|
|
378
|
+
* @param metadata - The metadata patch. Top-level keys are merged into the
|
|
379
|
+
* trace's existing metadata. Must be non-empty (the server rejects empty
|
|
380
|
+
* patches with 400).
|
|
381
|
+
* @example
|
|
382
|
+
* ```typescript
|
|
383
|
+
* import { Laminar, observe, LaminarClient } from "@lmnr-ai/lmnr";
|
|
384
|
+
* Laminar.initialize();
|
|
385
|
+
* const client = new LaminarClient();
|
|
386
|
+
*
|
|
387
|
+
* let traceId: string | null = null;
|
|
388
|
+
* await observe({ name: "generate" }, async () => {
|
|
389
|
+
* traceId = await Laminar.getTraceId();
|
|
390
|
+
* });
|
|
391
|
+
* await Laminar.flush();
|
|
392
|
+
*
|
|
393
|
+
* if (traceId) {
|
|
394
|
+
* await client.traces.pushMetadata(traceId, {
|
|
395
|
+
* score: 0.85,
|
|
396
|
+
* reviewer: "alice",
|
|
397
|
+
* needsReview: false,
|
|
398
|
+
* });
|
|
399
|
+
* }
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
pushMetadata(traceId: string, metadata: Record<string, unknown>): Promise<void>;
|
|
403
|
+
}
|
|
404
|
+
//#endregion
|
|
351
405
|
//#region src/index.d.ts
|
|
352
406
|
declare class LaminarClient {
|
|
353
407
|
private baseUrl;
|
|
@@ -359,6 +413,7 @@ declare class LaminarClient {
|
|
|
359
413
|
private _rolloutSessions;
|
|
360
414
|
private _sql;
|
|
361
415
|
private _tags;
|
|
416
|
+
private _traces;
|
|
362
417
|
constructor({
|
|
363
418
|
baseUrl,
|
|
364
419
|
projectApiKey,
|
|
@@ -375,6 +430,7 @@ declare class LaminarClient {
|
|
|
375
430
|
get rolloutSessions(): RolloutSessionsResource;
|
|
376
431
|
get sql(): SqlResource;
|
|
377
432
|
get tags(): TagsResource;
|
|
433
|
+
get traces(): TracesResource;
|
|
378
434
|
}
|
|
379
435
|
//#endregion
|
|
380
436
|
export { LaminarClient };
|
package/dist/index.d.mts
CHANGED
|
@@ -348,6 +348,60 @@ declare class TagsResource extends BaseResource {
|
|
|
348
348
|
tag(trace_id: string, tags: string[] | string): Promise<any>;
|
|
349
349
|
}
|
|
350
350
|
//#endregion
|
|
351
|
+
//#region src/resources/traces.d.ts
|
|
352
|
+
declare class TracesResource extends BaseResource {
|
|
353
|
+
/** Resource for post-factum operations on existing traces. */
|
|
354
|
+
constructor(baseHttpUrl: string, projectApiKey: string);
|
|
355
|
+
/**
|
|
356
|
+
* Push a metadata patch to an existing trace.
|
|
357
|
+
*
|
|
358
|
+
* The patch is shallow-merged server-side into the trace's existing metadata
|
|
359
|
+
* (`existing || patch`, last-write-wins per top-level key). Useful for
|
|
360
|
+
* attaching post-factum signals — quality scores, human edits, triage labels —
|
|
361
|
+
* to a trace that has already finished. The patch does NOT extend `endTime`
|
|
362
|
+
* or change tokens / cost / top span / tags / span names. `numSpans` is
|
|
363
|
+
* incremented by 1 (paid by the virtual span that carried the patch through
|
|
364
|
+
* the ingestion queue) so the new ClickHouse row beats the prior version on
|
|
365
|
+
* `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.
|
|
366
|
+
*
|
|
367
|
+
* Compared to `Laminar.setTraceMetadata` (which sets metadata on the
|
|
368
|
+
* currently in-flight trace via OpenTelemetry attributes), this method
|
|
369
|
+
* operates on a finished trace by trace id, so it must be called after the
|
|
370
|
+
* trace has been flushed.
|
|
371
|
+
*
|
|
372
|
+
* A 404 response (the trace was not found in the project — typically because
|
|
373
|
+
* it has not been flushed yet) is logged as a warning and the call returns
|
|
374
|
+
* without throwing; any other non-OK status throws.
|
|
375
|
+
*
|
|
376
|
+
* @param traceId - The trace id to push metadata to. Accepts a UUID string
|
|
377
|
+
* or a 32-char OTel hex trace id.
|
|
378
|
+
* @param metadata - The metadata patch. Top-level keys are merged into the
|
|
379
|
+
* trace's existing metadata. Must be non-empty (the server rejects empty
|
|
380
|
+
* patches with 400).
|
|
381
|
+
* @example
|
|
382
|
+
* ```typescript
|
|
383
|
+
* import { Laminar, observe, LaminarClient } from "@lmnr-ai/lmnr";
|
|
384
|
+
* Laminar.initialize();
|
|
385
|
+
* const client = new LaminarClient();
|
|
386
|
+
*
|
|
387
|
+
* let traceId: string | null = null;
|
|
388
|
+
* await observe({ name: "generate" }, async () => {
|
|
389
|
+
* traceId = await Laminar.getTraceId();
|
|
390
|
+
* });
|
|
391
|
+
* await Laminar.flush();
|
|
392
|
+
*
|
|
393
|
+
* if (traceId) {
|
|
394
|
+
* await client.traces.pushMetadata(traceId, {
|
|
395
|
+
* score: 0.85,
|
|
396
|
+
* reviewer: "alice",
|
|
397
|
+
* needsReview: false,
|
|
398
|
+
* });
|
|
399
|
+
* }
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
pushMetadata(traceId: string, metadata: Record<string, unknown>): Promise<void>;
|
|
403
|
+
}
|
|
404
|
+
//#endregion
|
|
351
405
|
//#region src/index.d.ts
|
|
352
406
|
declare class LaminarClient {
|
|
353
407
|
private baseUrl;
|
|
@@ -359,6 +413,7 @@ declare class LaminarClient {
|
|
|
359
413
|
private _rolloutSessions;
|
|
360
414
|
private _sql;
|
|
361
415
|
private _tags;
|
|
416
|
+
private _traces;
|
|
362
417
|
constructor({
|
|
363
418
|
baseUrl,
|
|
364
419
|
projectApiKey,
|
|
@@ -375,6 +430,7 @@ declare class LaminarClient {
|
|
|
375
430
|
get rolloutSessions(): RolloutSessionsResource;
|
|
376
431
|
get sql(): SqlResource;
|
|
377
432
|
get tags(): TagsResource;
|
|
433
|
+
get traces(): TracesResource;
|
|
378
434
|
}
|
|
379
435
|
//#endregion
|
|
380
436
|
export { LaminarClient };
|
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import pino from "pino";
|
|
|
4
4
|
import { PinoPretty } from "pino-pretty";
|
|
5
5
|
import { v4 } from "uuid";
|
|
6
6
|
//#region package.json
|
|
7
|
-
var version = "0.8.
|
|
7
|
+
var version = "0.8.26";
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/version.ts
|
|
10
10
|
function getLangVersion() {
|
|
@@ -69,7 +69,7 @@ function initializeLogger(options) {
|
|
|
69
69
|
minimumLevel: level
|
|
70
70
|
}));
|
|
71
71
|
}
|
|
72
|
-
const logger$
|
|
72
|
+
const logger$3 = initializeLogger();
|
|
73
73
|
const isStringUUID = (id) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);
|
|
74
74
|
const newUUID = () => {
|
|
75
75
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
@@ -78,9 +78,9 @@ const newUUID = () => {
|
|
|
78
78
|
const otelSpanIdToUUID = (spanId) => {
|
|
79
79
|
let id = spanId.toLowerCase();
|
|
80
80
|
if (id.startsWith("0x")) id = id.slice(2);
|
|
81
|
-
if (id.length !== 16) logger$
|
|
81
|
+
if (id.length !== 16) logger$3.warn(`Span ID ${spanId} is not 16 hex chars long. This is not a valid OpenTelemetry span ID.`);
|
|
82
82
|
if (!/^[0-9a-f]+$/.test(id)) {
|
|
83
|
-
logger$
|
|
83
|
+
logger$3.error(`Span ID ${spanId} is not a valid hex string. Generating a random UUID instead.`);
|
|
84
84
|
return newUUID();
|
|
85
85
|
}
|
|
86
86
|
return id.padStart(32, "0").replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, "$1-$2-$3-$4-$5");
|
|
@@ -88,9 +88,9 @@ const otelSpanIdToUUID = (spanId) => {
|
|
|
88
88
|
const otelTraceIdToUUID = (traceId) => {
|
|
89
89
|
let id = traceId.toLowerCase();
|
|
90
90
|
if (id.startsWith("0x")) id = id.slice(2);
|
|
91
|
-
if (id.length !== 32) logger$
|
|
91
|
+
if (id.length !== 32) logger$3.warn(`Trace ID ${traceId} is not 32 hex chars long. This is not a valid OpenTelemetry trace ID.`);
|
|
92
92
|
if (!/^[0-9a-f]+$/.test(id)) {
|
|
93
|
-
logger$
|
|
93
|
+
logger$3.error(`Trace ID ${traceId} is not a valid hex string. Generating a random UUID instead.`);
|
|
94
94
|
return newUUID();
|
|
95
95
|
}
|
|
96
96
|
return id.replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, "$1-$2-$3-$4-$5");
|
|
@@ -120,7 +120,7 @@ const loadEnv = (options) => {
|
|
|
120
120
|
};
|
|
121
121
|
//#endregion
|
|
122
122
|
//#region src/resources/datasets.ts
|
|
123
|
-
const logger$
|
|
123
|
+
const logger$2 = initializeLogger();
|
|
124
124
|
const DEFAULT_DATASET_PULL_LIMIT = 100;
|
|
125
125
|
const DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;
|
|
126
126
|
var DatasetsResource = class extends BaseResource {
|
|
@@ -175,7 +175,7 @@ var DatasetsResource = class extends BaseResource {
|
|
|
175
175
|
let response;
|
|
176
176
|
for (let i = 0; i < points.length; i += batchSize) {
|
|
177
177
|
const batchNum = Math.floor(i / batchSize) + 1;
|
|
178
|
-
logger$
|
|
178
|
+
logger$2.debug(`Pushing batch ${batchNum} of ${totalBatches}`);
|
|
179
179
|
const batch = points.slice(i, i + batchSize);
|
|
180
180
|
const fetchResponse = await fetch(this.baseHttpUrl + "/v1/datasets/datapoints", {
|
|
181
181
|
method: "POST",
|
|
@@ -225,7 +225,7 @@ var DatasetsResource = class extends BaseResource {
|
|
|
225
225
|
};
|
|
226
226
|
//#endregion
|
|
227
227
|
//#region src/resources/evals.ts
|
|
228
|
-
const logger = initializeLogger();
|
|
228
|
+
const logger$1 = initializeLogger();
|
|
229
229
|
const INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16e6;
|
|
230
230
|
var EvalsResource = class extends BaseResource {
|
|
231
231
|
constructor(baseHttpUrl, projectApiKey) {
|
|
@@ -361,7 +361,7 @@ var EvalsResource = class extends BaseResource {
|
|
|
361
361
|
* @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval
|
|
362
362
|
*/
|
|
363
363
|
async getDatapoints({ datasetName, offset, limit }) {
|
|
364
|
-
logger.warn("evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.");
|
|
364
|
+
logger$1.warn("evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.");
|
|
365
365
|
const params = new URLSearchParams({
|
|
366
366
|
name: datasetName,
|
|
367
367
|
offset: offset.toString(),
|
|
@@ -378,7 +378,7 @@ var EvalsResource = class extends BaseResource {
|
|
|
378
378
|
let length = initialLength;
|
|
379
379
|
let lastResponse = null;
|
|
380
380
|
for (let i = 0; i < maxRetries; i++) {
|
|
381
|
-
logger.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);
|
|
381
|
+
logger$1.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);
|
|
382
382
|
const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {
|
|
383
383
|
method: "POST",
|
|
384
384
|
headers: this.headers(),
|
|
@@ -599,6 +599,81 @@ var TagsResource = class extends BaseResource {
|
|
|
599
599
|
}
|
|
600
600
|
};
|
|
601
601
|
//#endregion
|
|
602
|
+
//#region src/resources/traces.ts
|
|
603
|
+
/** Resource for post-factum operations on existing traces. */
|
|
604
|
+
const logger = initializeLogger();
|
|
605
|
+
var TracesResource = class extends BaseResource {
|
|
606
|
+
/** Resource for post-factum operations on existing traces. */
|
|
607
|
+
constructor(baseHttpUrl, projectApiKey) {
|
|
608
|
+
super(baseHttpUrl, projectApiKey);
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Push a metadata patch to an existing trace.
|
|
612
|
+
*
|
|
613
|
+
* The patch is shallow-merged server-side into the trace's existing metadata
|
|
614
|
+
* (`existing || patch`, last-write-wins per top-level key). Useful for
|
|
615
|
+
* attaching post-factum signals — quality scores, human edits, triage labels —
|
|
616
|
+
* to a trace that has already finished. The patch does NOT extend `endTime`
|
|
617
|
+
* or change tokens / cost / top span / tags / span names. `numSpans` is
|
|
618
|
+
* incremented by 1 (paid by the virtual span that carried the patch through
|
|
619
|
+
* the ingestion queue) so the new ClickHouse row beats the prior version on
|
|
620
|
+
* `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.
|
|
621
|
+
*
|
|
622
|
+
* Compared to `Laminar.setTraceMetadata` (which sets metadata on the
|
|
623
|
+
* currently in-flight trace via OpenTelemetry attributes), this method
|
|
624
|
+
* operates on a finished trace by trace id, so it must be called after the
|
|
625
|
+
* trace has been flushed.
|
|
626
|
+
*
|
|
627
|
+
* A 404 response (the trace was not found in the project — typically because
|
|
628
|
+
* it has not been flushed yet) is logged as a warning and the call returns
|
|
629
|
+
* without throwing; any other non-OK status throws.
|
|
630
|
+
*
|
|
631
|
+
* @param traceId - The trace id to push metadata to. Accepts a UUID string
|
|
632
|
+
* or a 32-char OTel hex trace id.
|
|
633
|
+
* @param metadata - The metadata patch. Top-level keys are merged into the
|
|
634
|
+
* trace's existing metadata. Must be non-empty (the server rejects empty
|
|
635
|
+
* patches with 400).
|
|
636
|
+
* @example
|
|
637
|
+
* ```typescript
|
|
638
|
+
* import { Laminar, observe, LaminarClient } from "@lmnr-ai/lmnr";
|
|
639
|
+
* Laminar.initialize();
|
|
640
|
+
* const client = new LaminarClient();
|
|
641
|
+
*
|
|
642
|
+
* let traceId: string | null = null;
|
|
643
|
+
* await observe({ name: "generate" }, async () => {
|
|
644
|
+
* traceId = await Laminar.getTraceId();
|
|
645
|
+
* });
|
|
646
|
+
* await Laminar.flush();
|
|
647
|
+
*
|
|
648
|
+
* if (traceId) {
|
|
649
|
+
* await client.traces.pushMetadata(traceId, {
|
|
650
|
+
* score: 0.85,
|
|
651
|
+
* reviewer: "alice",
|
|
652
|
+
* needsReview: false,
|
|
653
|
+
* });
|
|
654
|
+
* }
|
|
655
|
+
* ```
|
|
656
|
+
*/
|
|
657
|
+
async pushMetadata(traceId, metadata) {
|
|
658
|
+
if (!metadata || Object.keys(metadata).length === 0) throw new Error("metadata must be a non-empty object");
|
|
659
|
+
const formattedTraceId = isStringUUID(traceId) ? traceId : otelTraceIdToUUID(traceId);
|
|
660
|
+
const url = this.baseHttpUrl + "/v1/traces/metadata";
|
|
661
|
+
const response = await fetch(url, {
|
|
662
|
+
method: "POST",
|
|
663
|
+
headers: this.headers(),
|
|
664
|
+
body: JSON.stringify({
|
|
665
|
+
traceId: formattedTraceId,
|
|
666
|
+
metadata
|
|
667
|
+
})
|
|
668
|
+
});
|
|
669
|
+
if (response.status === 404) {
|
|
670
|
+
logger.warn(`Trace ${formattedTraceId} not found. The trace may not have been flushed yet — call await Laminar.flush() and retry.`);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
if (!response.ok) await this.handleError(response);
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
//#endregion
|
|
602
677
|
//#region src/index.ts
|
|
603
678
|
var LaminarClient = class {
|
|
604
679
|
constructor({ baseUrl, projectApiKey, port } = {}) {
|
|
@@ -614,6 +689,7 @@ var LaminarClient = class {
|
|
|
614
689
|
this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.projectApiKey);
|
|
615
690
|
this._sql = new SqlResource(this.baseUrl, this.projectApiKey);
|
|
616
691
|
this._tags = new TagsResource(this.baseUrl, this.projectApiKey);
|
|
692
|
+
this._traces = new TracesResource(this.baseUrl, this.projectApiKey);
|
|
617
693
|
}
|
|
618
694
|
get browserEvents() {
|
|
619
695
|
return this._browserEvents;
|
|
@@ -636,6 +712,9 @@ var LaminarClient = class {
|
|
|
636
712
|
get tags() {
|
|
637
713
|
return this._tags;
|
|
638
714
|
}
|
|
715
|
+
get traces() {
|
|
716
|
+
return this._traces;
|
|
717
|
+
}
|
|
639
718
|
};
|
|
640
719
|
//#endregion
|
|
641
720
|
export { LaminarClient };
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["SDK_VERSION","logger","uuidv4","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.ts","../src/resources/sql.ts","../src/resources/tags.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","class BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly projectApiKey: string;\n\n constructor(baseHttpUrl: string, projectApiKey: string) {\n this.baseHttpUrl = baseHttpUrl;\n this.projectApiKey = projectApiKey;\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.projectApiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\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 } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 { 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 + \"/v1/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 + `/v1/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 + \"/v1/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 + `/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 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 * 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 { type RolloutParam, type SpanType } from \"@lmnr-ai/types\";\n\nimport { otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Connects to the SSE stream for rollout debugging sessions\n * Returns the Response object for streaming SSE events\n */\n public async connect({\n sessionId,\n name,\n params,\n signal,\n }: {\n sessionId: string;\n params: RolloutParam[];\n name: string;\n signal?: AbortSignal;\n }): Promise<Response> {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Accept': 'text/event-stream',\n },\n body: JSON.stringify({ name, params }),\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n return response;\n }\n\n public async delete({\n sessionId,\n }: {\n sessionId: string;\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"DELETE\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async setStatus({\n sessionId,\n status,\n }: {\n sessionId: string;\n status: 'PENDING' | 'RUNNING' | 'FINISHED' | 'STOPPED';\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/status`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ status }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async sendSpanUpdate({\n sessionId,\n span,\n }: {\n sessionId: string;\n span: {\n name: string;\n startTime: string;\n spanId: string;\n traceId: string;\n parentSpanId: string | undefined;\n attributes: Record<string, any>;\n spanType: SpanType;\n };\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/update`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({\n type: \"spanStart\",\n spanId: otelSpanIdToUUID(span.spanId),\n traceId: otelTraceIdToUUID(span.traceId),\n parentSpanId: span.parentSpanId ? otelSpanIdToUUID(span.parentSpanId) : undefined,\n attributes: span.attributes,\n startTime: span.startTime,\n name: span.name,\n spanType: span.spanType,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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}/v1/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","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\nimport { SqlResource } from \"./resources/sql\";\nimport { TagsResource } from \"./resources/tags\";\nimport { loadEnv } from \"./utils\";\n\nexport class LaminarClient {\n private baseUrl: string;\n private projectApiKey: string;\n private _browserEvents: BrowserEventsResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n\n constructor({\n baseUrl,\n projectApiKey,\n port,\n }: {\n baseUrl?: string,\n projectApiKey?: string,\n port?: number,\n } = {}) {\n loadEnv();\n this.projectApiKey = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\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.projectApiKey);\n this._datasets = new DatasetsResource(this.baseUrl, this.projectApiKey);\n this._evals = new EvalsResource(this.baseUrl, this.projectApiKey);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.projectApiKey);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.projectApiKey);\n this._sql = new SqlResource(this.baseUrl, this.projectApiKey);\n this._tags = new TagsResource(this.baseUrl, this.projectApiKey);\n }\n\n public get browserEvents() {\n return this._browserEvents;\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 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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["SDK_VERSION","logger","uuidv4","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.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","class BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly projectApiKey: string;\n\n constructor(baseHttpUrl: string, projectApiKey: string) {\n this.baseHttpUrl = baseHttpUrl;\n this.projectApiKey = projectApiKey;\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.projectApiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\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 } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 { 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 + \"/v1/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 + `/v1/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 + \"/v1/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 + `/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 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 * 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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 { type RolloutParam, type SpanType } from \"@lmnr-ai/types\";\n\nimport { otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Connects to the SSE stream for rollout debugging sessions\n * Returns the Response object for streaming SSE events\n */\n public async connect({\n sessionId,\n name,\n params,\n signal,\n }: {\n sessionId: string;\n params: RolloutParam[];\n name: string;\n signal?: AbortSignal;\n }): Promise<Response> {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Accept': 'text/event-stream',\n },\n body: JSON.stringify({ name, params }),\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n return response;\n }\n\n public async delete({\n sessionId,\n }: {\n sessionId: string;\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"DELETE\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async setStatus({\n sessionId,\n status,\n }: {\n sessionId: string;\n status: 'PENDING' | 'RUNNING' | 'FINISHED' | 'STOPPED';\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/status`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ status }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async sendSpanUpdate({\n sessionId,\n span,\n }: {\n sessionId: string;\n span: {\n name: string;\n startTime: string;\n spanId: string;\n traceId: string;\n parentSpanId: string | undefined;\n attributes: Record<string, any>;\n spanType: SpanType;\n };\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/update`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({\n type: \"spanStart\",\n spanId: otelSpanIdToUUID(span.spanId),\n traceId: otelTraceIdToUUID(span.traceId),\n parentSpanId: span.parentSpanId ? otelSpanIdToUUID(span.parentSpanId) : undefined,\n attributes: span.attributes,\n startTime: span.startTime,\n name: span.name,\n spanType: span.spanType,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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}/v1/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","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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 } 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, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\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; 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 * @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 ): 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 + \"/v1/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 // 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(\n `Trace ${formattedTraceId} not found. The trace may not have been ` +\n \"flushed yet — call await Laminar.flush() and retry.\",\n );\n return;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\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 projectApiKey: string;\n private _browserEvents: BrowserEventsResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n private _traces: TracesResource;\n\n constructor({\n baseUrl,\n projectApiKey,\n port,\n }: {\n baseUrl?: string,\n projectApiKey?: string,\n port?: number,\n } = {}) {\n loadEnv();\n this.projectApiKey = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\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.projectApiKey);\n this._datasets = new DatasetsResource(this.baseUrl, this.projectApiKey);\n this._evals = new EvalsResource(this.baseUrl, this.projectApiKey);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.projectApiKey);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.projectApiKey);\n this._sql = new SqlResource(this.baseUrl, this.projectApiKey);\n this._tags = new TagsResource(this.baseUrl, this.projectApiKey);\n this._traces = new TracesResource(this.baseUrl, this.projectApiKey);\n }\n\n public get browserEvents() {\n return this._browserEvents;\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 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"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmnr-ai/client",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.26",
|
|
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.20.3",
|
|
42
|
-
"@lmnr-ai/types": "0.8.
|
|
42
|
+
"@lmnr-ai/types": "0.8.26"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "tsdown",
|