@lmnr-ai/lmnr 0.6.11 → 0.6.12

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/cli.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { E as Evaluation } from './evaluations-DUmIeesJ.mjs';
2
+ import { E as Evaluation } from './evaluations-Ch9Bet5y.mjs';
3
3
  import '@anthropic-ai/sdk';
4
4
  import '@aws-sdk/client-bedrock-runtime';
5
5
  import '@azure/openai';
package/dist/cli.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { E as Evaluation } from './evaluations-DUmIeesJ.js';
2
+ import { E as Evaluation } from './evaluations-Ch9Bet5y.js';
3
3
  import '@anthropic-ai/sdk';
4
4
  import '@aws-sdk/client-bedrock-runtime';
5
5
  import '@azure/openai';
package/dist/cli.js CHANGED
@@ -36,11 +36,11 @@ __export(cli_exports, {
36
36
  module.exports = __toCommonJS(cli_exports);
37
37
  var import_argparse = require("argparse");
38
38
  var esbuild = __toESM(require("esbuild"));
39
- var glob = __toESM(require("glob"));
40
39
  var fs = __toESM(require("fs"));
40
+ var glob = __toESM(require("glob"));
41
41
 
42
42
  // package.json
43
- var version = "0.6.11";
43
+ var version = "0.6.12";
44
44
 
45
45
  // src/utils.ts
46
46
  var import_api = require("@opentelemetry/api");
@@ -97,6 +97,25 @@ var getDirname = () => {
97
97
 
98
98
  // src/cli.ts
99
99
  var logger2 = initializeLogger();
100
+ var createSkipDynamicImportsPlugin = (skipModules) => ({
101
+ name: "skip-dynamic-imports",
102
+ setup(build2) {
103
+ if (!skipModules || skipModules.length === 0) return;
104
+ build2.onResolve({ filter: /.*/ }, (args) => {
105
+ if (args.kind === "dynamic-import" && skipModules.includes(args.path)) {
106
+ logger2.warn(`Skipping dynamic import: ${args.path}`);
107
+ return {
108
+ path: args.path,
109
+ namespace: "lmnr-skip-dynamic-import"
110
+ };
111
+ }
112
+ });
113
+ build2.onLoad({ filter: /.*/, namespace: "lmnr-skip-dynamic-import" }, (args) => ({
114
+ contents: "export default {};",
115
+ loader: "js"
116
+ }));
117
+ }
118
+ });
100
119
  function loadModule({
101
120
  filename,
102
121
  moduleText
@@ -146,6 +165,14 @@ async function cli() {
146
165
  help: "Output file to write the results to. Outputs are written in JSON format.",
147
166
  nargs: "?"
148
167
  });
168
+ parserEval.add_argument("--external-packages", {
169
+ help: "[ADVANCED] List of packages to pass as external to esbuild. This will not link the packages directly into the eval file, but will instead require them at runtime. Read more: https://esbuild.github.io/api/#external",
170
+ nargs: "*"
171
+ });
172
+ parserEval.add_argument("--dynamic-imports-to-skip", {
173
+ help: "[ADVANCED] List of module names to skip when encountered as dynamic imports. These dynamic imports will resolve to an empty module to prevent build failures. This is meant to skip the imports that are not used in the evaluation itself.",
174
+ nargs: "*"
175
+ });
149
176
  parserEval.set_defaults({
150
177
  func: async (args2) => {
151
178
  let files;
@@ -180,7 +207,11 @@ async function cli() {
180
207
  "puppeteer",
181
208
  "puppeteer-core",
182
209
  "playwright-core",
183
- "fsevents"
210
+ "fsevents",
211
+ ...args2.external_packages ? args2.external_packages : []
212
+ ],
213
+ plugins: [
214
+ createSkipDynamicImportsPlugin(args2.dynamic_imports_to_skip || [])
184
215
  ],
185
216
  treeShaking: true
186
217
  };
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../package.json","../src/utils.ts","../src/opentelemetry-lib/tracing/attributes.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { ArgumentParser } from \"argparse\";\nimport * as esbuild from \"esbuild\";\nimport * as glob from \"glob\";\nimport * as fs from \"fs\";\n\nimport { version } from \"../package.json\";\nimport { Evaluation } from \"./evaluations\";\nimport { getDirname, initializeLogger } from \"./utils\";\n\nconst logger = initializeLogger();\n\ndeclare global {\n // eslint-disable-next-line no-var\n var _evaluations: Evaluation<any, any, any>[] | undefined;\n // eslint-disable-next-line no-var\n var _set_global_evaluation: boolean;\n}\n\nexport function loadModule({\n filename,\n moduleText,\n}: {\n filename: string;\n moduleText: string;\n}): Evaluation<any, any, any>[] {\n globalThis._evaluations = [];\n globalThis._set_global_evaluation = true;\n\n const __filename = filename;\n const __dirname = getDirname();\n\n // add some arguments for proper cjs/esm interop\n\n /* eslint-disable @typescript-eslint/no-implied-eval */\n new Function(\n \"require\",\n \"module\",\n \"__filename\",\n \"__dirname\",\n moduleText,\n )(\n require,\n module,\n __filename,\n __dirname,\n );\n /* eslint-enable @typescript-eslint/no-implied-eval */\n\n // Return the modified _evals global variable\n return globalThis._evaluations!;\n}\n\nasync function cli() {\n const [, , ...args] = process.argv;\n\n // Use argparse, which is the port of the python library\n const parser = new ArgumentParser({\n prog: \"lmnr\",\n description: \"CLI for Laminar. Use `lmnr <subcommand> --help` for more information.\",\n });\n\n parser.add_argument(\"-v\", \"--version\", { action: \"version\", version });\n\n const subparsers = parser.add_subparsers({\n title: \"subcommands\",\n dest: \"subcommand\",\n });\n\n const parserEval = subparsers.add_parser(\"eval\", {\n description: \"Run an evaluation\",\n help: \"Run an evaluation\",\n });\n\n parserEval.add_argument(\"files\", {\n help: \"A file or files containing the evaluation to run. If no file is provided, \" +\n \"the evaluation will run all `*.eval.ts|js` files in the `evals` directory. \" +\n \"If multiple files are provided, the evaluation will run each file in order.\",\n nargs: \"*\",\n });\n\n parserEval.add_argument(\"--fail-on-error\", {\n help: \"Fail on error. If specified, will fail if encounters a file that cannot be run\",\n action: \"store_true\",\n });\n\n parserEval.add_argument(\"--output-file\", {\n help: \"Output file to write the results to. Outputs are written in JSON format.\",\n nargs: \"?\",\n });\n\n parserEval.set_defaults({\n func: async (args: any) => {\n let files: string[];\n if (args.files && args.files.length > 0) {\n files = args.files.flatMap((file: string) => glob.sync(file));\n } else {\n // No files provided, use default pattern\n files = glob.sync('evals/**/*.eval.{ts,js}');\n }\n\n files.sort();\n\n if (files.length === 0) {\n logger.error(\"No evaluation files found. Please provide a file or \" +\n \"ensure there are eval files that are named like `*.eval.{ts,js}` in\" +\n \"the `evals` directory or its subdirectories.\");\n process.exit(1);\n }\n\n if (args.files.length === 0) {\n logger.info(`Located ${files.length} evaluation files in evals/`);\n } else {\n logger.info(`Running ${files.length} evaluation files.`);\n }\n\n const scores: { file: string, scores: Record<string, number> }[] = [];\n\n for (const file of files) {\n logger.info(`Loading ${file}...`);\n const buildOptions = {\n bundle: true,\n platform: \"node\" as esbuild.Platform,\n entryPoints: [file],\n outfile: `tmp_out_${file}.js`,\n write: false, // will be loaded in memory as a temp file\n external: [\n \"node_modules/*\",\n \"playwright\",\n \"puppeteer\",\n \"puppeteer-core\",\n \"playwright-core\",\n \"fsevents\",\n ],\n treeShaking: true,\n };\n\n const result = await esbuild.build(buildOptions);\n\n if (!result.outputFiles) {\n logger.error(\"Error when building: No output files found \" +\n \"it is likely that all eval files are not valid TypeScript or JavaScript files.\");\n if (args.fail_on_error) {\n process.exit(1);\n }\n continue;\n }\n\n const outputFileText = result.outputFiles[0].text;\n\n const evaluations = loadModule({\n filename: file,\n moduleText: outputFileText,\n });\n\n logger.info(`Loaded ${evaluations.length} evaluations from ${file}`);\n\n for (const evaluation of evaluations) {\n if (!evaluation?.run) {\n logger.error(`Evaluation ${file} does not properly call evaluate()`);\n if (args.fail_on_error) {\n process.exit(1);\n }\n continue;\n }\n\n const evalScores = await evaluation.run();\n scores.push({ file, scores: evalScores });\n }\n }\n\n if (args.output_file) {\n fs.writeFileSync(args.output_file, JSON.stringify(scores, null, 2));\n }\n },\n });\n\n parser.set_defaults({\n func: () => {\n parser.print_help();\n process.exit(0);\n },\n });\n\n const parsed = parser.parse_args(args);\n await parsed.func(parsed);\n}\n\ncli().catch((err) => {\n logger.error(err instanceof Error ? err.message : err);\n throw err;\n});\n","{\n \"name\": \"@lmnr-ai/lmnr\",\n \"version\": \"0.6.11\",\n \"description\": \"TypeScript SDK for Laminar AI\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"scripts\": {\n \"build\": \"tsup\",\n \"test\": \"tsx --test test/*.test.ts\",\n \"lint\": \"eslint\",\n \"lint:fix\": \"eslint --fix\"\n },\n \"files\": [\n \"dist\",\n \"assets\"\n ],\n \"bin\": {\n \"lmnr\": \"./dist/cli.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/lmnr-ai/lmnr-ts.git\"\n },\n \"keywords\": [\n \"laminar\",\n \"lmnr\",\n \"sdk\",\n \"lmnr.ai\"\n ],\n \"author\": \"founders@lmnr.ai\",\n \"license\": \"Apache-2.0\",\n \"bugs\": {\n \"url\": \"https://github.com/lmnr-ai/lmnr-ts/issues\"\n },\n \"homepage\": \"https://github.com/lmnr-ai/lmnr-ts#README\",\n \"devDependencies\": {\n \"@anthropic-ai/sdk\": \"^0.39.0\",\n \"@aws-sdk/client-bedrock-runtime\": \"^3.835.0\",\n \"@azure/openai\": \"^2.0.0\",\n \"@browserbasehq/stagehand\": \"^1.14.0\",\n \"@eslint/eslintrc\": \"^3.3.1\",\n \"@eslint/js\": \"^9.29.0\",\n \"@google-cloud/aiplatform\": \"^4.2.0\",\n \"@google-cloud/vertexai\": \"^1.10.0\",\n \"@langchain/core\": \"^0.3.61\",\n \"@pinecone-database/pinecone\": \"^5.1.2\",\n \"@playwright/test\": \"^1.53.1\",\n \"@qdrant/js-client-rest\": \"^1.14.1\",\n \"@stylistic/eslint-plugin-js\": \"^4.4.1\",\n \"@types/argparse\": \"^2.0.17\",\n \"@types/cli-progress\": \"^3.11.6\",\n \"@types/node\": \"^24.0.3\",\n \"@types/semver\": \"^7.7.0\",\n \"@types/uuid\": \"^10.0.0\",\n \"chromadb\": \"^2.4.6\",\n \"cohere-ai\": \"^7.17.1\",\n \"eslint-plugin-simple-import-sort\": \"^12.1.1\",\n \"eslint-plugin-unused-imports\": \"^4.1.4\",\n \"langchain\": \"^0.3.29\",\n \"llamaindex\": \"^0.9.19\",\n \"nock\": \"^14.0.5\",\n \"openai\": \"^4.104.0\",\n \"playwright\": \"^1.53.1\",\n \"puppeteer\": \"^24.10.2\",\n \"puppeteer-core\": \"^24.10.2\",\n \"together-ai\": \"^0.14.0\",\n \"tsup\": \"^8.5.0\",\n \"tsx\": \"^4.20.3\",\n \"typescript\": \"^5.8.3\",\n \"typescript-eslint\": \"^8.35.0\"\n },\n \"dependencies\": {\n \"@grpc/grpc-js\": \"^1.13.4\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/context-async-hooks\": \"^1.30.1\",\n \"@opentelemetry/core\": \"^1.30.1\",\n \"@opentelemetry/exporter-trace-otlp-grpc\": \"^0.57.2\",\n \"@opentelemetry/exporter-trace-otlp-proto\": \"^0.57.2\",\n \"@opentelemetry/instrumentation\": \"^0.57.2\",\n \"@opentelemetry/otlp-exporter-base\": \"^0.57.2\",\n \"@opentelemetry/otlp-grpc-exporter-base\": \"^0.57.2\",\n \"@opentelemetry/resources\": \"^1.30.1\",\n \"@opentelemetry/sdk-node\": \"^0.57.2\",\n \"@opentelemetry/sdk-trace-base\": \"^1.30.1\",\n \"@opentelemetry/sdk-trace-base-v2\": \"npm:@opentelemetry/sdk-trace-base@2.0.0\",\n \"@opentelemetry/sdk-trace-node\": \"^1.30.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.34.0\",\n \"@traceloop/ai-semantic-conventions\": \"^0.12.0\",\n \"@traceloop/instrumentation-anthropic\": \"^0.12.0\",\n \"@traceloop/instrumentation-azure\": \"^0.12.0\",\n \"@traceloop/instrumentation-bedrock\": \"^0.12.0\",\n \"@traceloop/instrumentation-chromadb\": \"^0.12.0\",\n \"@traceloop/instrumentation-cohere\": \"^0.12.0\",\n \"@traceloop/instrumentation-langchain\": \"^0.12.0\",\n \"@traceloop/instrumentation-llamaindex\": \"^0.12.0\",\n \"@traceloop/instrumentation-openai\": \"^0.12.0\",\n \"@traceloop/instrumentation-pinecone\": \"^0.12.0\",\n \"@traceloop/instrumentation-qdrant\": \"^0.12.0\",\n \"@traceloop/instrumentation-together\": \"^0.12.1\",\n \"@traceloop/instrumentation-vertexai\": \"^0.12.0\",\n \"argparse\": \"^2.0.1\",\n \"cli-progress\": \"^3.12.0\",\n \"esbuild\": \"^0.25.5\",\n \"glob\": \"^11.0.3\",\n \"pino\": \"^9.7.0\",\n \"pino-pretty\": \"^13.0.0\",\n \"uuid\": \"^11.1.0\",\n \"zod\": \"^3.25.67\"\n }\n}","import { AttributeValue, SpanContext, TraceFlags } from '@opentelemetry/api';\nimport path from \"path\";\nimport pino, { Level } from 'pino';\nimport pinoPretty from 'pino-pretty';\nimport { fileURLToPath } from \"url\";\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { LaminarSpanContext } from './types';\nimport { ASSOCIATION_PROPERTIES } from './opentelemetry-lib/tracing/attributes';\n\nexport function initializeLogger(options?: { colorize?: boolean, level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level = options?.level\n ?? (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level)\n ?? 'info';\n\n return pino(pinoPretty({\n colorize,\n minimumLevel: level,\n }));\n}\n\nconst logger = initializeLogger();\n\nexport type StringUUID = `${string}-${string}-${string}-${string}-${string}`;\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(`Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.');\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(`Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.');\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): string => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(`Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.');\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(`Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.');\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 );\n};\n\nexport const uuidToOtelTraceId = (uuid: string): string => uuid.replace(/-/g, '');\nexport const uuidToOtelSpanId = (uuid: string): string => uuid.replace(/-/g, '').slice(16);\n\n/**\n * This is a simple implementation of a semaphore to replicate\n * the behavior of the `asyncio.Semaphore` in Python.\n */\nexport class Semaphore {\n /**\n * Number of permits available.\n */\n private _value: number;\n /**\n * List of promises that will be resolved when a permit becomes available.\n */\n private _waiters: ((...args: any[]) => any)[] = [];\n\n constructor(value = 1) {\n if (value < 0) {\n throw new Error(\"Semaphore value must be >= 0\");\n }\n this._value = value;\n this._waiters = [];\n }\n\n async acquire() {\n if (this._value > 0) {\n this._value--;\n return;\n }\n\n // Create a promise that will be resolved when a permit becomes available\n return new Promise(resolve => {\n this._waiters.push(resolve);\n });\n }\n\n release() {\n if (this._waiters.length > 0) {\n // If there are waiters, wake up the first one\n const resolve = this._waiters.shift();\n resolve?.();\n } else {\n this._value++;\n }\n }\n\n // Python-like context manager functionality\n async using<T>(fn: (...args: any[]) => Promise<T>) {\n try {\n await this.acquire();\n return await fn();\n } finally {\n this.release();\n }\n }\n}\n\nexport const tryToOtelSpanContext = (\n spanContext: LaminarSpanContext | Record<string, unknown> | string | SpanContext,\n): SpanContext => {\n if (typeof spanContext === 'string') {\n try {\n const record = JSON.parse(spanContext) as Record<string, unknown>;\n return recordToOtelSpanContext(record);\n } catch (e) {\n throw new Error(`Failed to parse span context ${spanContext}. ` +\n 'The string must be a json representation of a LaminarSpanContext.'\n + `Error: ${e instanceof Error ? e.message : String(e)}`);\n }\n } else if (isRecord(spanContext)) {\n // This covers the `LaminarSpanContext` case too.\n return recordToOtelSpanContext(spanContext);\n } else if (typeof spanContext.traceId === 'string'\n && typeof spanContext.spanId === 'string'\n && spanContext.traceId.length === 32\n && spanContext.spanId.length === 16) {\n logger.warn('The span context is already an OpenTelemetry SpanContext. ' +\n 'Returning it as is. Please use `LaminarSpanContext` objects instead.');\n return spanContext;\n }\n else {\n throw new Error(`Invalid span context ${JSON.stringify(spanContext)}. ` +\n 'Must be a LaminarSpanContext or its json representation.');\n }\n};\n\nconst recordToOtelSpanContext = (record: Record<string, unknown>): SpanContext => {\n if (typeof record.spanId === 'string' && typeof record.traceId === 'string') {\n return {\n spanId: uuidToOtelSpanId(record?.spanId ?? record?.['span_id']),\n traceId: uuidToOtelTraceId(record?.traceId ?? record?.['trace_id']),\n isRemote: record?.isRemote ?? record?.['is_remote'] ?? false,\n traceFlags: record?.traceFlags ?? TraceFlags.SAMPLED,\n } as SpanContext;\n } else {\n throw new Error(`Invalid span context ${JSON.stringify(record)}. ` +\n 'Must be a json representation of a LaminarSpanContext.');\n }\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && !Array.isArray(value) && value !== null;\n\n\nexport const getDirname = () => {\n if (typeof __dirname !== 'undefined') {\n return __dirname;\n }\n\n if (typeof import.meta?.url !== 'undefined') {\n return path.dirname(fileURLToPath(import.meta.url));\n }\n\n return process.cwd();\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 isOtelAttributeValueType = (value: unknown): value is AttributeValue => {\n if (typeof value === 'string'\n || typeof value === 'number'\n || typeof value === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n const allStrings = value.every(value => (value == null) || typeof value === 'string');\n const allNumbers = value.every(value => (value == null) || typeof value === 'number');\n const allBooleans = value.every(value => (value == null) || typeof value === 'boolean');\n return allStrings || allNumbers || allBooleans;\n }\n return false;\n};\n\nexport const metadataToAttributes = (metadata: Record<string, unknown>): Record<string, AttributeValue> => {\n return Object.fromEntries(\n Object.entries(metadata).map(([key, value]) => {\n if (isOtelAttributeValueType(value)) {\n return [`${ASSOCIATION_PROPERTIES}.metadata.${key}`, value];\n } else {\n return [`${ASSOCIATION_PROPERTIES}.metadata.${key}`, JSON.stringify(value)];\n }\n }),\n );\n};\n","import { SpanAttributes } from '@traceloop/ai-semantic-conventions';\n\nexport const SPAN_INPUT = \"lmnr.span.input\";\nexport const SPAN_OUTPUT = \"lmnr.span.output\";\nexport const SPAN_TYPE = \"lmnr.span.type\";\nexport const SPAN_PATH = \"lmnr.span.path\";\nexport const SPAN_IDS_PATH = \"lmnr.span.ids_path\";\nexport const SPAN_INSTRUMENTATION_SOURCE = \"lmnr.span.instrumentation_source\";\nexport const SPAN_SDK_VERSION = \"lmnr.span.sdk_version\";\nexport const SPAN_LANGUAGE_VERSION = \"lmnr.span.language_version\";\nexport const OVERRIDE_PARENT_SPAN = \"lmnr.internal.override_parent_span\";\nexport const TRACE_HAS_BROWSER_SESSION = \"lmnr.internal.has_browser_session\";\nexport const EXTRACTED_FROM_NEXT_JS = \"lmnr.span.extracted_from.next_js\";\n\nexport const ASSOCIATION_PROPERTIES = \"lmnr.association.properties\";\nexport const SESSION_ID = \"lmnr.association.properties.session_id\";\nexport const USER_ID = \"lmnr.association.properties.user_id\";\nexport const TRACE_TYPE = \"lmnr.association.properties.trace_type\";\n\nexport const ASSOCIATION_PROPERTIES_OVERRIDES: Record<string, string> = {\n \"span_type\": SPAN_TYPE,\n};\n\nexport const LaminarAttributes = {\n // == This is the minimum set of attributes for a proper LLM span ==\n //\n // not SpanAttributes.LLM_USAGE_PROMPT_TOKENS\n INPUT_TOKEN_COUNT: \"gen_ai.usage.input_tokens\",\n // not SpanAttributes.LLM_USAGE_COMPLETION_TOKENS\n OUTPUT_TOKEN_COUNT: \"gen_ai.usage.output_tokens\",\n TOTAL_TOKEN_COUNT: SpanAttributes.LLM_USAGE_TOTAL_TOKENS,\n PROVIDER: SpanAttributes.LLM_SYSTEM,\n REQUEST_MODEL: SpanAttributes.LLM_REQUEST_MODEL,\n RESPONSE_MODEL: SpanAttributes.LLM_RESPONSE_MODEL,\n //\n // == End of minimum set ==\n // == Additional attributes ==\n //\n INPUT_COST: \"gen_ai.usage.input_cost\",\n OUTPUT_COST: \"gen_ai.usage.output_cost\",\n TOTAL_COST: \"gen_ai.usage.cost\",\n //\n // == End of additional attributes ==\n};\n"],"mappings":"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","names":["pino","pinoPretty","path","logger","__dirname","args"]}
1
+ {"version":3,"sources":["../src/cli.ts","../package.json","../src/utils.ts","../src/opentelemetry-lib/tracing/attributes.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { ArgumentParser } from \"argparse\";\nimport * as esbuild from \"esbuild\";\nimport * as fs from \"fs\";\nimport * as glob from \"glob\";\n\nimport { version } from \"../package.json\";\nimport { Evaluation } from \"./evaluations\";\nimport { getDirname, initializeLogger } from \"./utils\";\n\nconst logger = initializeLogger();\n\n// esbuild plugin to skip dynamic imports\nconst createSkipDynamicImportsPlugin = (skipModules: string[]): esbuild.Plugin => ({\n name: 'skip-dynamic-imports',\n setup(build) {\n if (!skipModules || skipModules.length === 0) return;\n\n build.onResolve({ filter: /.*/ }, (args) => {\n // Only handle dynamic imports\n if (args.kind === 'dynamic-import' && skipModules.includes(args.path)) {\n logger.warn(`Skipping dynamic import: ${args.path}`);\n // Return a virtual module that exports an empty object\n return {\n path: args.path,\n namespace: 'lmnr-skip-dynamic-import',\n };\n }\n });\n\n // Provide empty module content for skipped dynamic imports\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n build.onLoad({ filter: /.*/, namespace: 'lmnr-skip-dynamic-import' }, (args) => ({\n contents: 'export default {};',\n loader: 'js',\n }));\n },\n});\n\ndeclare global {\n // eslint-disable-next-line no-var\n var _evaluations: Evaluation<any, any, any>[] | undefined;\n // eslint-disable-next-line no-var\n var _set_global_evaluation: boolean;\n}\n\nexport function loadModule({\n filename,\n moduleText,\n}: {\n filename: string;\n moduleText: string;\n}): Evaluation<any, any, any>[] {\n globalThis._evaluations = [];\n globalThis._set_global_evaluation = true;\n\n const __filename = filename;\n const __dirname = getDirname();\n\n // add some arguments for proper cjs/esm interop\n\n /* eslint-disable @typescript-eslint/no-implied-eval */\n new Function(\n \"require\",\n \"module\",\n \"__filename\",\n \"__dirname\",\n moduleText,\n )(\n require,\n module,\n __filename,\n __dirname,\n );\n /* eslint-enable @typescript-eslint/no-implied-eval */\n\n // Return the modified _evals global variable\n return globalThis._evaluations;\n}\n\nasync function cli() {\n const [, , ...args] = process.argv;\n\n // Use argparse, which is the port of the python library\n const parser = new ArgumentParser({\n prog: \"lmnr\",\n description: \"CLI for Laminar. Use `lmnr <subcommand> --help` for more information.\",\n });\n\n parser.add_argument(\"-v\", \"--version\", { action: \"version\", version });\n\n const subparsers = parser.add_subparsers({\n title: \"subcommands\",\n dest: \"subcommand\",\n });\n\n const parserEval = subparsers.add_parser(\"eval\", {\n description: \"Run an evaluation\",\n help: \"Run an evaluation\",\n });\n\n parserEval.add_argument(\"files\", {\n help: \"A file or files containing the evaluation to run. If no file is provided, \" +\n \"the evaluation will run all `*.eval.ts|js` files in the `evals` directory. \" +\n \"If multiple files are provided, the evaluation will run each file in order.\",\n nargs: \"*\",\n });\n\n parserEval.add_argument(\"--fail-on-error\", {\n help: \"Fail on error. If specified, will fail if encounters a file that cannot be run\",\n action: \"store_true\",\n });\n\n parserEval.add_argument(\"--output-file\", {\n help: \"Output file to write the results to. Outputs are written in JSON format.\",\n nargs: \"?\",\n });\n\n parserEval.add_argument(\"--external-packages\", {\n help: \"[ADVANCED] List of packages to pass as external to esbuild. This will not link \" +\n \"the packages directly into the eval file, but will instead require them at runtime. \" +\n \"Read more: https://esbuild.github.io/api/#external\",\n nargs: \"*\",\n });\n\n parserEval.add_argument(\"--dynamic-imports-to-skip\", {\n help: \"[ADVANCED] List of module names to skip when encountered as dynamic imports. \" +\n \"These dynamic imports will resolve to an empty module to prevent build failures. \" +\n \"This is meant to skip the imports that are not used in the evaluation itself.\",\n nargs: \"*\",\n });\n\n parserEval.set_defaults({\n func: async (args: any) => {\n let files: string[];\n if (args.files && args.files.length > 0) {\n files = args.files.flatMap((file: string) => glob.sync(file));\n } else {\n // No files provided, use default pattern\n files = glob.sync('evals/**/*.eval.{ts,js}');\n }\n\n files.sort();\n\n if (files.length === 0) {\n logger.error(\"No evaluation files found. Please provide a file or \" +\n \"ensure there are eval files that are named like `*.eval.{ts,js}` in\" +\n \"the `evals` directory or its subdirectories.\");\n process.exit(1);\n }\n\n if (args.files.length === 0) {\n logger.info(`Located ${files.length} evaluation files in evals/`);\n } else {\n logger.info(`Running ${files.length} evaluation files.`);\n }\n\n const scores: { file: string, scores: Record<string, number> }[] = [];\n\n for (const file of files) {\n logger.info(`Loading ${file}...`);\n const buildOptions = {\n bundle: true,\n platform: \"node\" as esbuild.Platform,\n entryPoints: [file],\n outfile: `tmp_out_${file}.js`,\n write: false, // will be loaded in memory as a temp file\n external: [\n \"node_modules/*\",\n \"playwright\",\n \"puppeteer\",\n \"puppeteer-core\",\n \"playwright-core\",\n \"fsevents\",\n ...(args.external_packages ? args.external_packages : []),\n ],\n plugins: [\n createSkipDynamicImportsPlugin(args.dynamic_imports_to_skip || []),\n ],\n treeShaking: true,\n };\n\n const result = await esbuild.build(buildOptions);\n\n if (!result.outputFiles) {\n logger.error(\"Error when building: No output files found \" +\n \"it is likely that all eval files are not valid TypeScript or JavaScript files.\");\n if (args.fail_on_error) {\n process.exit(1);\n }\n continue;\n }\n\n const outputFileText = result.outputFiles[0].text;\n\n const evaluations = loadModule({\n filename: file,\n moduleText: outputFileText,\n });\n\n logger.info(`Loaded ${evaluations.length} evaluations from ${file}`);\n\n for (const evaluation of evaluations) {\n if (!evaluation?.run) {\n logger.error(`Evaluation ${file} does not properly call evaluate()`);\n if (args.fail_on_error) {\n process.exit(1);\n }\n continue;\n }\n\n const evalScores = await evaluation.run();\n scores.push({ file, scores: evalScores });\n }\n }\n\n if (args.output_file) {\n fs.writeFileSync(args.output_file, JSON.stringify(scores, null, 2));\n }\n },\n });\n\n parser.set_defaults({\n func: () => {\n parser.print_help();\n process.exit(0);\n },\n });\n\n const parsed = parser.parse_args(args);\n await parsed.func(parsed);\n}\n\ncli().catch((err) => {\n logger.error(err instanceof Error ? err.message : err);\n throw err;\n});\n","{\n \"name\": \"@lmnr-ai/lmnr\",\n \"version\": \"0.6.12\",\n \"description\": \"TypeScript SDK for Laminar AI\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"scripts\": {\n \"build\": \"tsup\",\n \"test\": \"tsx --test test/*.test.ts\",\n \"lint\": \"eslint\",\n \"lint:fix\": \"eslint --fix\"\n },\n \"files\": [\n \"dist\",\n \"assets\"\n ],\n \"bin\": {\n \"lmnr\": \"./dist/cli.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/lmnr-ai/lmnr-ts.git\"\n },\n \"keywords\": [\n \"laminar\",\n \"lmnr\",\n \"sdk\",\n \"lmnr.ai\"\n ],\n \"author\": \"founders@lmnr.ai\",\n \"license\": \"Apache-2.0\",\n \"bugs\": {\n \"url\": \"https://github.com/lmnr-ai/lmnr-ts/issues\"\n },\n \"homepage\": \"https://github.com/lmnr-ai/lmnr-ts#README\",\n \"devDependencies\": {\n \"@anthropic-ai/sdk\": \"^0.39.0\",\n \"@aws-sdk/client-bedrock-runtime\": \"^3.835.0\",\n \"@azure/openai\": \"^2.0.0\",\n \"@browserbasehq/stagehand\": \"^2.3.1\",\n \"@eslint/eslintrc\": \"^3.3.1\",\n \"@eslint/js\": \"^9.29.0\",\n \"@google-cloud/aiplatform\": \"^4.2.0\",\n \"@google-cloud/vertexai\": \"^1.10.0\",\n \"@langchain/core\": \"^0.3.61\",\n \"@pinecone-database/pinecone\": \"^5.1.2\",\n \"@playwright/test\": \"^1.53.1\",\n \"@qdrant/js-client-rest\": \"^1.14.1\",\n \"@stylistic/eslint-plugin\": \"^5.0.0\",\n \"@types/argparse\": \"^2.0.17\",\n \"@types/cli-progress\": \"^3.11.6\",\n \"@types/node\": \"^24.0.3\",\n \"@types/semver\": \"^7.7.0\",\n \"@types/uuid\": \"^10.0.0\",\n \"chromadb\": \"^2.4.6\",\n \"cohere-ai\": \"^7.17.1\",\n \"eslint-plugin-simple-import-sort\": \"^12.1.1\",\n \"eslint-plugin-unused-imports\": \"^4.1.4\",\n \"langchain\": \"^0.3.29\",\n \"llamaindex\": \"^0.9.19\",\n \"nock\": \"^14.0.5\",\n \"openai\": \"^4.104.0\",\n \"playwright\": \"^1.53.1\",\n \"puppeteer\": \"^24.10.2\",\n \"puppeteer-core\": \"^24.10.2\",\n \"together-ai\": \"^0.14.0\",\n \"tsup\": \"^8.5.0\",\n \"tsx\": \"^4.20.3\",\n \"typescript\": \"^5.8.3\",\n \"typescript-eslint\": \"^8.35.0\"\n },\n \"dependencies\": {\n \"@grpc/grpc-js\": \"^1.13.4\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/context-async-hooks\": \"^1.30.1\",\n \"@opentelemetry/core\": \"^1.30.1\",\n \"@opentelemetry/exporter-trace-otlp-grpc\": \"^0.57.2\",\n \"@opentelemetry/exporter-trace-otlp-proto\": \"^0.57.2\",\n \"@opentelemetry/instrumentation\": \"^0.57.2\",\n \"@opentelemetry/otlp-exporter-base\": \"^0.57.2\",\n \"@opentelemetry/otlp-grpc-exporter-base\": \"^0.57.2\",\n \"@opentelemetry/resources\": \"^1.30.1\",\n \"@opentelemetry/sdk-node\": \"^0.57.2\",\n \"@opentelemetry/sdk-trace-base\": \"^1.30.1\",\n \"@opentelemetry/sdk-trace-base-v2\": \"npm:@opentelemetry/sdk-trace-base@2.0.0\",\n \"@opentelemetry/sdk-trace-node\": \"^1.30.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.34.0\",\n \"@traceloop/ai-semantic-conventions\": \"^0.12.0\",\n \"@traceloop/instrumentation-anthropic\": \"^0.12.0\",\n \"@traceloop/instrumentation-azure\": \"^0.12.0\",\n \"@traceloop/instrumentation-bedrock\": \"^0.12.0\",\n \"@traceloop/instrumentation-chromadb\": \"^0.12.0\",\n \"@traceloop/instrumentation-cohere\": \"^0.12.0\",\n \"@traceloop/instrumentation-langchain\": \"^0.12.0\",\n \"@traceloop/instrumentation-llamaindex\": \"^0.12.0\",\n \"@traceloop/instrumentation-openai\": \"^0.12.0\",\n \"@traceloop/instrumentation-pinecone\": \"^0.12.0\",\n \"@traceloop/instrumentation-qdrant\": \"^0.12.0\",\n \"@traceloop/instrumentation-together\": \"^0.12.1\",\n \"@traceloop/instrumentation-vertexai\": \"^0.12.0\",\n \"argparse\": \"^2.0.1\",\n \"cli-progress\": \"^3.12.0\",\n \"esbuild\": \"^0.25.5\",\n \"glob\": \"^11.0.3\",\n \"pino\": \"^9.7.0\",\n \"pino-pretty\": \"^13.0.0\",\n \"uuid\": \"^11.1.0\",\n \"zod\": \"^3.25.67\"\n }\n}","import { AttributeValue, SpanContext, TraceFlags } from '@opentelemetry/api';\nimport path from \"path\";\nimport pino, { Level } from 'pino';\nimport pinoPretty from 'pino-pretty';\nimport { fileURLToPath } from \"url\";\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { ASSOCIATION_PROPERTIES } from './opentelemetry-lib/tracing/attributes';\nimport { LaminarSpanContext } from './types';\n\nexport function initializeLogger(options?: { colorize?: boolean, level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level = options?.level\n ?? (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level)\n ?? 'info';\n\n return pino(pinoPretty({\n colorize,\n minimumLevel: level,\n }));\n}\n\nconst logger = initializeLogger();\n\nexport type StringUUID = `${string}-${string}-${string}-${string}-${string}`;\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(`Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.');\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(`Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.');\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): string => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(`Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.');\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(`Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.');\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 );\n};\n\nexport const uuidToOtelTraceId = (uuid: string): string => uuid.replace(/-/g, '');\nexport const uuidToOtelSpanId = (uuid: string): string => uuid.replace(/-/g, '').slice(16);\n\n/**\n * This is a simple implementation of a semaphore to replicate\n * the behavior of the `asyncio.Semaphore` in Python.\n */\nexport class Semaphore {\n /**\n * Number of permits available.\n */\n private _value: number;\n /**\n * List of promises that will be resolved when a permit becomes available.\n */\n private _waiters: ((...args: any[]) => any)[] = [];\n\n constructor(value = 1) {\n if (value < 0) {\n throw new Error(\"Semaphore value must be >= 0\");\n }\n this._value = value;\n this._waiters = [];\n }\n\n async acquire() {\n if (this._value > 0) {\n this._value--;\n return;\n }\n\n // Create a promise that will be resolved when a permit becomes available\n return new Promise(resolve => {\n this._waiters.push(resolve);\n });\n }\n\n release() {\n if (this._waiters.length > 0) {\n // If there are waiters, wake up the first one\n const resolve = this._waiters.shift();\n resolve?.();\n } else {\n this._value++;\n }\n }\n\n // Python-like context manager functionality\n async using<T>(fn: (...args: any[]) => Promise<T>) {\n try {\n await this.acquire();\n return await fn();\n } finally {\n this.release();\n }\n }\n}\n\nexport const tryToOtelSpanContext = (\n spanContext: LaminarSpanContext | Record<string, unknown> | string | SpanContext,\n): SpanContext => {\n if (typeof spanContext === 'string') {\n try {\n const record = JSON.parse(spanContext) as Record<string, unknown>;\n return recordToOtelSpanContext(record);\n } catch (e) {\n throw new Error(`Failed to parse span context ${spanContext}. ` +\n 'The string must be a json representation of a LaminarSpanContext.'\n + `Error: ${e instanceof Error ? e.message : String(e)}`);\n }\n } else if (isRecord(spanContext)) {\n // This covers the `LaminarSpanContext` case too.\n return recordToOtelSpanContext(spanContext);\n } else if (typeof spanContext.traceId === 'string'\n && typeof spanContext.spanId === 'string'\n && spanContext.traceId.length === 32\n && spanContext.spanId.length === 16) {\n logger.warn('The span context is already an OpenTelemetry SpanContext. ' +\n 'Returning it as is. Please use `LaminarSpanContext` objects instead.');\n return spanContext;\n }\n else {\n throw new Error(`Invalid span context ${JSON.stringify(spanContext)}. ` +\n 'Must be a LaminarSpanContext or its json representation.');\n }\n};\n\nconst recordToOtelSpanContext = (record: Record<string, unknown>): SpanContext => {\n if (typeof record.spanId === 'string' && typeof record.traceId === 'string') {\n return {\n spanId: uuidToOtelSpanId(record?.spanId ?? record?.['span_id']),\n traceId: uuidToOtelTraceId(record?.traceId ?? record?.['trace_id']),\n isRemote: record?.isRemote ?? record?.['is_remote'] ?? false,\n traceFlags: record?.traceFlags ?? TraceFlags.SAMPLED,\n } as SpanContext;\n } else {\n throw new Error(`Invalid span context ${JSON.stringify(record)}. ` +\n 'Must be a json representation of a LaminarSpanContext.');\n }\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && !Array.isArray(value) && value !== null;\n\n\nexport const getDirname = () => {\n if (typeof __dirname !== 'undefined') {\n return __dirname;\n }\n\n if (typeof import.meta?.url !== 'undefined') {\n return path.dirname(fileURLToPath(import.meta.url));\n }\n\n return process.cwd();\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 isOtelAttributeValueType = (value: unknown): value is AttributeValue => {\n if (typeof value === 'string'\n || typeof value === 'number'\n || typeof value === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n const allStrings = value.every(value => (value == null) || typeof value === 'string');\n const allNumbers = value.every(value => (value == null) || typeof value === 'number');\n const allBooleans = value.every(value => (value == null) || typeof value === 'boolean');\n return allStrings || allNumbers || allBooleans;\n }\n return false;\n};\n\nexport const metadataToAttributes = (\n metadata: Record<string, unknown>,\n): Record<string, AttributeValue> => Object.fromEntries(\n Object.entries(metadata).map(([key, value]) => {\n if (isOtelAttributeValueType(value)) {\n return [`${ASSOCIATION_PROPERTIES}.metadata.${key}`, value];\n } else {\n return [`${ASSOCIATION_PROPERTIES}.metadata.${key}`, JSON.stringify(value)];\n }\n }),\n);\n","import { SpanAttributes } from '@traceloop/ai-semantic-conventions';\n\nexport const SPAN_INPUT = \"lmnr.span.input\";\nexport const SPAN_OUTPUT = \"lmnr.span.output\";\nexport const SPAN_TYPE = \"lmnr.span.type\";\nexport const SPAN_PATH = \"lmnr.span.path\";\nexport const SPAN_IDS_PATH = \"lmnr.span.ids_path\";\nexport const SPAN_INSTRUMENTATION_SOURCE = \"lmnr.span.instrumentation_source\";\nexport const SPAN_SDK_VERSION = \"lmnr.span.sdk_version\";\nexport const SPAN_LANGUAGE_VERSION = \"lmnr.span.language_version\";\nexport const OVERRIDE_PARENT_SPAN = \"lmnr.internal.override_parent_span\";\nexport const TRACE_HAS_BROWSER_SESSION = \"lmnr.internal.has_browser_session\";\nexport const EXTRACTED_FROM_NEXT_JS = \"lmnr.span.extracted_from.next_js\";\n\nexport const ASSOCIATION_PROPERTIES = \"lmnr.association.properties\";\nexport const SESSION_ID = \"lmnr.association.properties.session_id\";\nexport const USER_ID = \"lmnr.association.properties.user_id\";\nexport const TRACE_TYPE = \"lmnr.association.properties.trace_type\";\n\nexport const ASSOCIATION_PROPERTIES_OVERRIDES: Record<string, string> = {\n \"span_type\": SPAN_TYPE,\n};\n\nexport const LaminarAttributes = {\n // == This is the minimum set of attributes for a proper LLM span ==\n //\n // not SpanAttributes.LLM_USAGE_PROMPT_TOKENS\n INPUT_TOKEN_COUNT: \"gen_ai.usage.input_tokens\",\n // not SpanAttributes.LLM_USAGE_COMPLETION_TOKENS\n OUTPUT_TOKEN_COUNT: \"gen_ai.usage.output_tokens\",\n TOTAL_TOKEN_COUNT: SpanAttributes.LLM_USAGE_TOTAL_TOKENS,\n PROVIDER: SpanAttributes.LLM_SYSTEM,\n REQUEST_MODEL: SpanAttributes.LLM_REQUEST_MODEL,\n RESPONSE_MODEL: SpanAttributes.LLM_RESPONSE_MODEL,\n //\n // == End of minimum set ==\n // == Additional attributes ==\n //\n INPUT_COST: \"gen_ai.usage.input_cost\",\n OUTPUT_COST: \"gen_ai.usage.output_cost\",\n TOTAL_COST: \"gen_ai.usage.cost\",\n //\n // == End of additional attributes ==\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,sBAA+B;AAC/B,cAAyB;AACzB,SAAoB;AACpB,WAAsB;;;ACHpB,cAAW;;;ACFb,iBAAwD;AACxD,kBAAiB;AACjB,kBAA4B;AAC5B,yBAAuB;AACvB,iBAA8B;AAC9B,kBAA6B;;;ACL7B,qCAA+B;AAuBxB,IAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA,EAI/B,mBAAmB;AAAA;AAAA,EAEnB,oBAAoB;AAAA,EACpB,mBAAmB,8CAAe;AAAA,EAClC,UAAU,8CAAe;AAAA,EACzB,eAAe,8CAAe;AAAA,EAC9B,gBAAgB,8CAAe;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/B,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,YAAY;AAAA;AAAA;AAGd;;;AD3CA;AAUO,SAAS,iBAAiB,SAAiD;AAChF,QAAM,WAAW,SAAS,YAAY;AACtC,QAAM,QAAQ,SAAS,SACjB,QAAQ,IAAI,gBAAgB,YAAY,GAAG,KAAK,KACjD;AAEL,aAAO,YAAAA,aAAK,mBAAAC,SAAW;AAAA,IACrB;AAAA,IACA,cAAc;AAAA,EAChB,CAAC,CAAC;AACJ;AAEA,IAAM,SAAS,iBAAiB;AAyKzB,IAAM,aAAa,MAAM;AAC9B,MAAI,OAAO,cAAc,aAAa;AACpC,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,aAAa,QAAQ,aAAa;AAC3C,WAAO,YAAAC,QAAK,YAAQ,0BAAc,YAAY,GAAG,CAAC;AAAA,EACpD;AAEA,SAAO,QAAQ,IAAI;AACrB;;;AF9LA,IAAMC,UAAS,iBAAiB;AAGhC,IAAM,iCAAiC,CAAC,iBAA2C;AAAA,EACjF,MAAM;AAAA,EACN,MAAMC,QAAO;AACX,QAAI,CAAC,eAAe,YAAY,WAAW,EAAG;AAE9C,IAAAA,OAAM,UAAU,EAAE,QAAQ,KAAK,GAAG,CAAC,SAAS;AAE1C,UAAI,KAAK,SAAS,oBAAoB,YAAY,SAAS,KAAK,IAAI,GAAG;AACrE,QAAAD,QAAO,KAAK,4BAA4B,KAAK,IAAI,EAAE;AAEnD,eAAO;AAAA,UACL,MAAM,KAAK;AAAA,UACX,WAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF,CAAC;AAID,IAAAC,OAAM,OAAO,EAAE,QAAQ,MAAM,WAAW,2BAA2B,GAAG,CAAC,UAAU;AAAA,MAC/E,UAAU;AAAA,MACV,QAAQ;AAAA,IACV,EAAE;AAAA,EACJ;AACF;AASO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AACF,GAGgC;AAC9B,aAAW,eAAe,CAAC;AAC3B,aAAW,yBAAyB;AAEpC,QAAM,aAAa;AACnB,QAAMC,aAAY,WAAW;AAK7B,MAAI;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACAA;AAAA,EACF;AAIA,SAAO,WAAW;AACpB;AAEA,eAAe,MAAM;AACnB,QAAM,CAAC,EAAE,EAAE,GAAG,IAAI,IAAI,QAAQ;AAG9B,QAAM,SAAS,IAAI,+BAAe;AAAA,IAChC,MAAM;AAAA,IACN,aAAa;AAAA,EACf,CAAC;AAED,SAAO,aAAa,MAAM,aAAa,EAAE,QAAQ,WAAW,QAAQ,CAAC;AAErE,QAAM,aAAa,OAAO,eAAe;AAAA,IACvC,OAAO;AAAA,IACP,MAAM;AAAA,EACR,CAAC;AAED,QAAM,aAAa,WAAW,WAAW,QAAQ;AAAA,IAC/C,aAAa;AAAA,IACb,MAAM;AAAA,EACR,CAAC;AAED,aAAW,aAAa,SAAS;AAAA,IAC/B,MAAM;AAAA,IAGN,OAAO;AAAA,EACT,CAAC;AAED,aAAW,aAAa,mBAAmB;AAAA,IACzC,MAAM;AAAA,IACN,QAAQ;AAAA,EACV,CAAC;AAED,aAAW,aAAa,iBAAiB;AAAA,IACvC,MAAM;AAAA,IACN,OAAO;AAAA,EACT,CAAC;AAED,aAAW,aAAa,uBAAuB;AAAA,IAC7C,MAAM;AAAA,IAGN,OAAO;AAAA,EACT,CAAC;AAED,aAAW,aAAa,6BAA6B;AAAA,IACnD,MAAM;AAAA,IAGN,OAAO;AAAA,EACT,CAAC;AAED,aAAW,aAAa;AAAA,IACtB,MAAM,OAAOC,UAAc;AACzB,UAAI;AACJ,UAAIA,MAAK,SAASA,MAAK,MAAM,SAAS,GAAG;AACvC,gBAAQA,MAAK,MAAM,QAAQ,CAAC,SAAsB,UAAK,IAAI,CAAC;AAAA,MAC9D,OAAO;AAEL,gBAAa,UAAK,yBAAyB;AAAA,MAC7C;AAEA,YAAM,KAAK;AAEX,UAAI,MAAM,WAAW,GAAG;AACtB,QAAAH,QAAO,MAAM,qKAEmC;AAChD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,UAAIG,MAAK,MAAM,WAAW,GAAG;AAC3B,QAAAH,QAAO,KAAK,WAAW,MAAM,MAAM,6BAA6B;AAAA,MAClE,OAAO;AACL,QAAAA,QAAO,KAAK,WAAW,MAAM,MAAM,oBAAoB;AAAA,MACzD;AAEA,YAAM,SAA6D,CAAC;AAEpE,iBAAW,QAAQ,OAAO;AACxB,QAAAA,QAAO,KAAK,WAAW,IAAI,KAAK;AAChC,cAAM,eAAe;AAAA,UACnB,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,aAAa,CAAC,IAAI;AAAA,UAClB,SAAS,WAAW,IAAI;AAAA,UACxB,OAAO;AAAA;AAAA,UACP,UAAU;AAAA,YACR;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,GAAIG,MAAK,oBAAoBA,MAAK,oBAAoB,CAAC;AAAA,UACzD;AAAA,UACA,SAAS;AAAA,YACP,+BAA+BA,MAAK,2BAA2B,CAAC,CAAC;AAAA,UACnE;AAAA,UACA,aAAa;AAAA,QACf;AAEA,cAAM,SAAS,MAAc,cAAM,YAAY;AAE/C,YAAI,CAAC,OAAO,aAAa;AACvB,UAAAH,QAAO,MAAM,2HACqE;AAClF,cAAIG,MAAK,eAAe;AACtB,oBAAQ,KAAK,CAAC;AAAA,UAChB;AACA;AAAA,QACF;AAEA,cAAM,iBAAiB,OAAO,YAAY,CAAC,EAAE;AAE7C,cAAM,cAAc,WAAW;AAAA,UAC7B,UAAU;AAAA,UACV,YAAY;AAAA,QACd,CAAC;AAED,QAAAH,QAAO,KAAK,UAAU,YAAY,MAAM,qBAAqB,IAAI,EAAE;AAEnE,mBAAW,cAAc,aAAa;AACpC,cAAI,CAAC,YAAY,KAAK;AACpB,YAAAA,QAAO,MAAM,cAAc,IAAI,oCAAoC;AACnE,gBAAIG,MAAK,eAAe;AACtB,sBAAQ,KAAK,CAAC;AAAA,YAChB;AACA;AAAA,UACF;AAEA,gBAAM,aAAa,MAAM,WAAW,IAAI;AACxC,iBAAO,KAAK,EAAE,MAAM,QAAQ,WAAW,CAAC;AAAA,QAC1C;AAAA,MACF;AAEA,UAAIA,MAAK,aAAa;AACpB,QAAG,iBAAcA,MAAK,aAAa,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,MACpE;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO,aAAa;AAAA,IAClB,MAAM,MAAM;AACV,aAAO,WAAW;AAClB,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAED,QAAM,SAAS,OAAO,WAAW,IAAI;AACrC,QAAM,OAAO,KAAK,MAAM;AAC1B;AAEA,IAAI,EAAE,MAAM,CAAC,QAAQ;AACnB,EAAAH,QAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,GAAG;AACrD,QAAM;AACR,CAAC;","names":["pino","pinoPretty","path","logger","build","__dirname","args"]}
package/dist/cli.mjs CHANGED
@@ -9,11 +9,11 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
9
9
  // src/cli.ts
10
10
  import { ArgumentParser } from "argparse";
11
11
  import * as esbuild from "esbuild";
12
- import * as glob from "glob";
13
12
  import * as fs from "fs";
13
+ import * as glob from "glob";
14
14
 
15
15
  // package.json
16
- var version = "0.6.11";
16
+ var version = "0.6.12";
17
17
 
18
18
  // src/utils.ts
19
19
  import { TraceFlags } from "@opentelemetry/api";
@@ -69,6 +69,25 @@ var getDirname = () => {
69
69
 
70
70
  // src/cli.ts
71
71
  var logger2 = initializeLogger();
72
+ var createSkipDynamicImportsPlugin = (skipModules) => ({
73
+ name: "skip-dynamic-imports",
74
+ setup(build2) {
75
+ if (!skipModules || skipModules.length === 0) return;
76
+ build2.onResolve({ filter: /.*/ }, (args) => {
77
+ if (args.kind === "dynamic-import" && skipModules.includes(args.path)) {
78
+ logger2.warn(`Skipping dynamic import: ${args.path}`);
79
+ return {
80
+ path: args.path,
81
+ namespace: "lmnr-skip-dynamic-import"
82
+ };
83
+ }
84
+ });
85
+ build2.onLoad({ filter: /.*/, namespace: "lmnr-skip-dynamic-import" }, (args) => ({
86
+ contents: "export default {};",
87
+ loader: "js"
88
+ }));
89
+ }
90
+ });
72
91
  function loadModule({
73
92
  filename,
74
93
  moduleText
@@ -118,6 +137,14 @@ async function cli() {
118
137
  help: "Output file to write the results to. Outputs are written in JSON format.",
119
138
  nargs: "?"
120
139
  });
140
+ parserEval.add_argument("--external-packages", {
141
+ help: "[ADVANCED] List of packages to pass as external to esbuild. This will not link the packages directly into the eval file, but will instead require them at runtime. Read more: https://esbuild.github.io/api/#external",
142
+ nargs: "*"
143
+ });
144
+ parserEval.add_argument("--dynamic-imports-to-skip", {
145
+ help: "[ADVANCED] List of module names to skip when encountered as dynamic imports. These dynamic imports will resolve to an empty module to prevent build failures. This is meant to skip the imports that are not used in the evaluation itself.",
146
+ nargs: "*"
147
+ });
121
148
  parserEval.set_defaults({
122
149
  func: async (args2) => {
123
150
  let files;
@@ -152,7 +179,11 @@ async function cli() {
152
179
  "puppeteer",
153
180
  "puppeteer-core",
154
181
  "playwright-core",
155
- "fsevents"
182
+ "fsevents",
183
+ ...args2.external_packages ? args2.external_packages : []
184
+ ],
185
+ plugins: [
186
+ createSkipDynamicImportsPlugin(args2.dynamic_imports_to_skip || [])
156
187
  ],
157
188
  treeShaking: true
158
189
  };
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../package.json","../src/utils.ts","../src/opentelemetry-lib/tracing/attributes.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { ArgumentParser } from \"argparse\";\nimport * as esbuild from \"esbuild\";\nimport * as glob from \"glob\";\nimport * as fs from \"fs\";\n\nimport { version } from \"../package.json\";\nimport { Evaluation } from \"./evaluations\";\nimport { getDirname, initializeLogger } from \"./utils\";\n\nconst logger = initializeLogger();\n\ndeclare global {\n // eslint-disable-next-line no-var\n var _evaluations: Evaluation<any, any, any>[] | undefined;\n // eslint-disable-next-line no-var\n var _set_global_evaluation: boolean;\n}\n\nexport function loadModule({\n filename,\n moduleText,\n}: {\n filename: string;\n moduleText: string;\n}): Evaluation<any, any, any>[] {\n globalThis._evaluations = [];\n globalThis._set_global_evaluation = true;\n\n const __filename = filename;\n const __dirname = getDirname();\n\n // add some arguments for proper cjs/esm interop\n\n /* eslint-disable @typescript-eslint/no-implied-eval */\n new Function(\n \"require\",\n \"module\",\n \"__filename\",\n \"__dirname\",\n moduleText,\n )(\n require,\n module,\n __filename,\n __dirname,\n );\n /* eslint-enable @typescript-eslint/no-implied-eval */\n\n // Return the modified _evals global variable\n return globalThis._evaluations!;\n}\n\nasync function cli() {\n const [, , ...args] = process.argv;\n\n // Use argparse, which is the port of the python library\n const parser = new ArgumentParser({\n prog: \"lmnr\",\n description: \"CLI for Laminar. Use `lmnr <subcommand> --help` for more information.\",\n });\n\n parser.add_argument(\"-v\", \"--version\", { action: \"version\", version });\n\n const subparsers = parser.add_subparsers({\n title: \"subcommands\",\n dest: \"subcommand\",\n });\n\n const parserEval = subparsers.add_parser(\"eval\", {\n description: \"Run an evaluation\",\n help: \"Run an evaluation\",\n });\n\n parserEval.add_argument(\"files\", {\n help: \"A file or files containing the evaluation to run. If no file is provided, \" +\n \"the evaluation will run all `*.eval.ts|js` files in the `evals` directory. \" +\n \"If multiple files are provided, the evaluation will run each file in order.\",\n nargs: \"*\",\n });\n\n parserEval.add_argument(\"--fail-on-error\", {\n help: \"Fail on error. If specified, will fail if encounters a file that cannot be run\",\n action: \"store_true\",\n });\n\n parserEval.add_argument(\"--output-file\", {\n help: \"Output file to write the results to. Outputs are written in JSON format.\",\n nargs: \"?\",\n });\n\n parserEval.set_defaults({\n func: async (args: any) => {\n let files: string[];\n if (args.files && args.files.length > 0) {\n files = args.files.flatMap((file: string) => glob.sync(file));\n } else {\n // No files provided, use default pattern\n files = glob.sync('evals/**/*.eval.{ts,js}');\n }\n\n files.sort();\n\n if (files.length === 0) {\n logger.error(\"No evaluation files found. Please provide a file or \" +\n \"ensure there are eval files that are named like `*.eval.{ts,js}` in\" +\n \"the `evals` directory or its subdirectories.\");\n process.exit(1);\n }\n\n if (args.files.length === 0) {\n logger.info(`Located ${files.length} evaluation files in evals/`);\n } else {\n logger.info(`Running ${files.length} evaluation files.`);\n }\n\n const scores: { file: string, scores: Record<string, number> }[] = [];\n\n for (const file of files) {\n logger.info(`Loading ${file}...`);\n const buildOptions = {\n bundle: true,\n platform: \"node\" as esbuild.Platform,\n entryPoints: [file],\n outfile: `tmp_out_${file}.js`,\n write: false, // will be loaded in memory as a temp file\n external: [\n \"node_modules/*\",\n \"playwright\",\n \"puppeteer\",\n \"puppeteer-core\",\n \"playwright-core\",\n \"fsevents\",\n ],\n treeShaking: true,\n };\n\n const result = await esbuild.build(buildOptions);\n\n if (!result.outputFiles) {\n logger.error(\"Error when building: No output files found \" +\n \"it is likely that all eval files are not valid TypeScript or JavaScript files.\");\n if (args.fail_on_error) {\n process.exit(1);\n }\n continue;\n }\n\n const outputFileText = result.outputFiles[0].text;\n\n const evaluations = loadModule({\n filename: file,\n moduleText: outputFileText,\n });\n\n logger.info(`Loaded ${evaluations.length} evaluations from ${file}`);\n\n for (const evaluation of evaluations) {\n if (!evaluation?.run) {\n logger.error(`Evaluation ${file} does not properly call evaluate()`);\n if (args.fail_on_error) {\n process.exit(1);\n }\n continue;\n }\n\n const evalScores = await evaluation.run();\n scores.push({ file, scores: evalScores });\n }\n }\n\n if (args.output_file) {\n fs.writeFileSync(args.output_file, JSON.stringify(scores, null, 2));\n }\n },\n });\n\n parser.set_defaults({\n func: () => {\n parser.print_help();\n process.exit(0);\n },\n });\n\n const parsed = parser.parse_args(args);\n await parsed.func(parsed);\n}\n\ncli().catch((err) => {\n logger.error(err instanceof Error ? err.message : err);\n throw err;\n});\n","{\n \"name\": \"@lmnr-ai/lmnr\",\n \"version\": \"0.6.11\",\n \"description\": \"TypeScript SDK for Laminar AI\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"scripts\": {\n \"build\": \"tsup\",\n \"test\": \"tsx --test test/*.test.ts\",\n \"lint\": \"eslint\",\n \"lint:fix\": \"eslint --fix\"\n },\n \"files\": [\n \"dist\",\n \"assets\"\n ],\n \"bin\": {\n \"lmnr\": \"./dist/cli.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/lmnr-ai/lmnr-ts.git\"\n },\n \"keywords\": [\n \"laminar\",\n \"lmnr\",\n \"sdk\",\n \"lmnr.ai\"\n ],\n \"author\": \"founders@lmnr.ai\",\n \"license\": \"Apache-2.0\",\n \"bugs\": {\n \"url\": \"https://github.com/lmnr-ai/lmnr-ts/issues\"\n },\n \"homepage\": \"https://github.com/lmnr-ai/lmnr-ts#README\",\n \"devDependencies\": {\n \"@anthropic-ai/sdk\": \"^0.39.0\",\n \"@aws-sdk/client-bedrock-runtime\": \"^3.835.0\",\n \"@azure/openai\": \"^2.0.0\",\n \"@browserbasehq/stagehand\": \"^1.14.0\",\n \"@eslint/eslintrc\": \"^3.3.1\",\n \"@eslint/js\": \"^9.29.0\",\n \"@google-cloud/aiplatform\": \"^4.2.0\",\n \"@google-cloud/vertexai\": \"^1.10.0\",\n \"@langchain/core\": \"^0.3.61\",\n \"@pinecone-database/pinecone\": \"^5.1.2\",\n \"@playwright/test\": \"^1.53.1\",\n \"@qdrant/js-client-rest\": \"^1.14.1\",\n \"@stylistic/eslint-plugin-js\": \"^4.4.1\",\n \"@types/argparse\": \"^2.0.17\",\n \"@types/cli-progress\": \"^3.11.6\",\n \"@types/node\": \"^24.0.3\",\n \"@types/semver\": \"^7.7.0\",\n \"@types/uuid\": \"^10.0.0\",\n \"chromadb\": \"^2.4.6\",\n \"cohere-ai\": \"^7.17.1\",\n \"eslint-plugin-simple-import-sort\": \"^12.1.1\",\n \"eslint-plugin-unused-imports\": \"^4.1.4\",\n \"langchain\": \"^0.3.29\",\n \"llamaindex\": \"^0.9.19\",\n \"nock\": \"^14.0.5\",\n \"openai\": \"^4.104.0\",\n \"playwright\": \"^1.53.1\",\n \"puppeteer\": \"^24.10.2\",\n \"puppeteer-core\": \"^24.10.2\",\n \"together-ai\": \"^0.14.0\",\n \"tsup\": \"^8.5.0\",\n \"tsx\": \"^4.20.3\",\n \"typescript\": \"^5.8.3\",\n \"typescript-eslint\": \"^8.35.0\"\n },\n \"dependencies\": {\n \"@grpc/grpc-js\": \"^1.13.4\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/context-async-hooks\": \"^1.30.1\",\n \"@opentelemetry/core\": \"^1.30.1\",\n \"@opentelemetry/exporter-trace-otlp-grpc\": \"^0.57.2\",\n \"@opentelemetry/exporter-trace-otlp-proto\": \"^0.57.2\",\n \"@opentelemetry/instrumentation\": \"^0.57.2\",\n \"@opentelemetry/otlp-exporter-base\": \"^0.57.2\",\n \"@opentelemetry/otlp-grpc-exporter-base\": \"^0.57.2\",\n \"@opentelemetry/resources\": \"^1.30.1\",\n \"@opentelemetry/sdk-node\": \"^0.57.2\",\n \"@opentelemetry/sdk-trace-base\": \"^1.30.1\",\n \"@opentelemetry/sdk-trace-base-v2\": \"npm:@opentelemetry/sdk-trace-base@2.0.0\",\n \"@opentelemetry/sdk-trace-node\": \"^1.30.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.34.0\",\n \"@traceloop/ai-semantic-conventions\": \"^0.12.0\",\n \"@traceloop/instrumentation-anthropic\": \"^0.12.0\",\n \"@traceloop/instrumentation-azure\": \"^0.12.0\",\n \"@traceloop/instrumentation-bedrock\": \"^0.12.0\",\n \"@traceloop/instrumentation-chromadb\": \"^0.12.0\",\n \"@traceloop/instrumentation-cohere\": \"^0.12.0\",\n \"@traceloop/instrumentation-langchain\": \"^0.12.0\",\n \"@traceloop/instrumentation-llamaindex\": \"^0.12.0\",\n \"@traceloop/instrumentation-openai\": \"^0.12.0\",\n \"@traceloop/instrumentation-pinecone\": \"^0.12.0\",\n \"@traceloop/instrumentation-qdrant\": \"^0.12.0\",\n \"@traceloop/instrumentation-together\": \"^0.12.1\",\n \"@traceloop/instrumentation-vertexai\": \"^0.12.0\",\n \"argparse\": \"^2.0.1\",\n \"cli-progress\": \"^3.12.0\",\n \"esbuild\": \"^0.25.5\",\n \"glob\": \"^11.0.3\",\n \"pino\": \"^9.7.0\",\n \"pino-pretty\": \"^13.0.0\",\n \"uuid\": \"^11.1.0\",\n \"zod\": \"^3.25.67\"\n }\n}","import { AttributeValue, SpanContext, TraceFlags } from '@opentelemetry/api';\nimport path from \"path\";\nimport pino, { Level } from 'pino';\nimport pinoPretty from 'pino-pretty';\nimport { fileURLToPath } from \"url\";\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { LaminarSpanContext } from './types';\nimport { ASSOCIATION_PROPERTIES } from './opentelemetry-lib/tracing/attributes';\n\nexport function initializeLogger(options?: { colorize?: boolean, level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level = options?.level\n ?? (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level)\n ?? 'info';\n\n return pino(pinoPretty({\n colorize,\n minimumLevel: level,\n }));\n}\n\nconst logger = initializeLogger();\n\nexport type StringUUID = `${string}-${string}-${string}-${string}-${string}`;\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(`Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.');\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(`Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.');\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): string => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(`Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.');\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(`Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.');\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 );\n};\n\nexport const uuidToOtelTraceId = (uuid: string): string => uuid.replace(/-/g, '');\nexport const uuidToOtelSpanId = (uuid: string): string => uuid.replace(/-/g, '').slice(16);\n\n/**\n * This is a simple implementation of a semaphore to replicate\n * the behavior of the `asyncio.Semaphore` in Python.\n */\nexport class Semaphore {\n /**\n * Number of permits available.\n */\n private _value: number;\n /**\n * List of promises that will be resolved when a permit becomes available.\n */\n private _waiters: ((...args: any[]) => any)[] = [];\n\n constructor(value = 1) {\n if (value < 0) {\n throw new Error(\"Semaphore value must be >= 0\");\n }\n this._value = value;\n this._waiters = [];\n }\n\n async acquire() {\n if (this._value > 0) {\n this._value--;\n return;\n }\n\n // Create a promise that will be resolved when a permit becomes available\n return new Promise(resolve => {\n this._waiters.push(resolve);\n });\n }\n\n release() {\n if (this._waiters.length > 0) {\n // If there are waiters, wake up the first one\n const resolve = this._waiters.shift();\n resolve?.();\n } else {\n this._value++;\n }\n }\n\n // Python-like context manager functionality\n async using<T>(fn: (...args: any[]) => Promise<T>) {\n try {\n await this.acquire();\n return await fn();\n } finally {\n this.release();\n }\n }\n}\n\nexport const tryToOtelSpanContext = (\n spanContext: LaminarSpanContext | Record<string, unknown> | string | SpanContext,\n): SpanContext => {\n if (typeof spanContext === 'string') {\n try {\n const record = JSON.parse(spanContext) as Record<string, unknown>;\n return recordToOtelSpanContext(record);\n } catch (e) {\n throw new Error(`Failed to parse span context ${spanContext}. ` +\n 'The string must be a json representation of a LaminarSpanContext.'\n + `Error: ${e instanceof Error ? e.message : String(e)}`);\n }\n } else if (isRecord(spanContext)) {\n // This covers the `LaminarSpanContext` case too.\n return recordToOtelSpanContext(spanContext);\n } else if (typeof spanContext.traceId === 'string'\n && typeof spanContext.spanId === 'string'\n && spanContext.traceId.length === 32\n && spanContext.spanId.length === 16) {\n logger.warn('The span context is already an OpenTelemetry SpanContext. ' +\n 'Returning it as is. Please use `LaminarSpanContext` objects instead.');\n return spanContext;\n }\n else {\n throw new Error(`Invalid span context ${JSON.stringify(spanContext)}. ` +\n 'Must be a LaminarSpanContext or its json representation.');\n }\n};\n\nconst recordToOtelSpanContext = (record: Record<string, unknown>): SpanContext => {\n if (typeof record.spanId === 'string' && typeof record.traceId === 'string') {\n return {\n spanId: uuidToOtelSpanId(record?.spanId ?? record?.['span_id']),\n traceId: uuidToOtelTraceId(record?.traceId ?? record?.['trace_id']),\n isRemote: record?.isRemote ?? record?.['is_remote'] ?? false,\n traceFlags: record?.traceFlags ?? TraceFlags.SAMPLED,\n } as SpanContext;\n } else {\n throw new Error(`Invalid span context ${JSON.stringify(record)}. ` +\n 'Must be a json representation of a LaminarSpanContext.');\n }\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && !Array.isArray(value) && value !== null;\n\n\nexport const getDirname = () => {\n if (typeof __dirname !== 'undefined') {\n return __dirname;\n }\n\n if (typeof import.meta?.url !== 'undefined') {\n return path.dirname(fileURLToPath(import.meta.url));\n }\n\n return process.cwd();\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 isOtelAttributeValueType = (value: unknown): value is AttributeValue => {\n if (typeof value === 'string'\n || typeof value === 'number'\n || typeof value === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n const allStrings = value.every(value => (value == null) || typeof value === 'string');\n const allNumbers = value.every(value => (value == null) || typeof value === 'number');\n const allBooleans = value.every(value => (value == null) || typeof value === 'boolean');\n return allStrings || allNumbers || allBooleans;\n }\n return false;\n};\n\nexport const metadataToAttributes = (metadata: Record<string, unknown>): Record<string, AttributeValue> => {\n return Object.fromEntries(\n Object.entries(metadata).map(([key, value]) => {\n if (isOtelAttributeValueType(value)) {\n return [`${ASSOCIATION_PROPERTIES}.metadata.${key}`, value];\n } else {\n return [`${ASSOCIATION_PROPERTIES}.metadata.${key}`, JSON.stringify(value)];\n }\n }),\n );\n};\n","import { SpanAttributes } from '@traceloop/ai-semantic-conventions';\n\nexport const SPAN_INPUT = \"lmnr.span.input\";\nexport const SPAN_OUTPUT = \"lmnr.span.output\";\nexport const SPAN_TYPE = \"lmnr.span.type\";\nexport const SPAN_PATH = \"lmnr.span.path\";\nexport const SPAN_IDS_PATH = \"lmnr.span.ids_path\";\nexport const SPAN_INSTRUMENTATION_SOURCE = \"lmnr.span.instrumentation_source\";\nexport const SPAN_SDK_VERSION = \"lmnr.span.sdk_version\";\nexport const SPAN_LANGUAGE_VERSION = \"lmnr.span.language_version\";\nexport const OVERRIDE_PARENT_SPAN = \"lmnr.internal.override_parent_span\";\nexport const TRACE_HAS_BROWSER_SESSION = \"lmnr.internal.has_browser_session\";\nexport const EXTRACTED_FROM_NEXT_JS = \"lmnr.span.extracted_from.next_js\";\n\nexport const ASSOCIATION_PROPERTIES = \"lmnr.association.properties\";\nexport const SESSION_ID = \"lmnr.association.properties.session_id\";\nexport const USER_ID = \"lmnr.association.properties.user_id\";\nexport const TRACE_TYPE = \"lmnr.association.properties.trace_type\";\n\nexport const ASSOCIATION_PROPERTIES_OVERRIDES: Record<string, string> = {\n \"span_type\": SPAN_TYPE,\n};\n\nexport const LaminarAttributes = {\n // == This is the minimum set of attributes for a proper LLM span ==\n //\n // not SpanAttributes.LLM_USAGE_PROMPT_TOKENS\n INPUT_TOKEN_COUNT: \"gen_ai.usage.input_tokens\",\n // not SpanAttributes.LLM_USAGE_COMPLETION_TOKENS\n OUTPUT_TOKEN_COUNT: \"gen_ai.usage.output_tokens\",\n TOTAL_TOKEN_COUNT: SpanAttributes.LLM_USAGE_TOTAL_TOKENS,\n PROVIDER: SpanAttributes.LLM_SYSTEM,\n REQUEST_MODEL: SpanAttributes.LLM_REQUEST_MODEL,\n RESPONSE_MODEL: SpanAttributes.LLM_RESPONSE_MODEL,\n //\n // == End of minimum set ==\n // == Additional attributes ==\n //\n INPUT_COST: \"gen_ai.usage.input_cost\",\n OUTPUT_COST: \"gen_ai.usage.output_cost\",\n TOTAL_COST: \"gen_ai.usage.cost\",\n //\n // == End of additional attributes ==\n};\n"],"mappings":"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","names":["logger","__dirname","args"]}
1
+ {"version":3,"sources":["../src/cli.ts","../package.json","../src/utils.ts","../src/opentelemetry-lib/tracing/attributes.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { ArgumentParser } from \"argparse\";\nimport * as esbuild from \"esbuild\";\nimport * as fs from \"fs\";\nimport * as glob from \"glob\";\n\nimport { version } from \"../package.json\";\nimport { Evaluation } from \"./evaluations\";\nimport { getDirname, initializeLogger } from \"./utils\";\n\nconst logger = initializeLogger();\n\n// esbuild plugin to skip dynamic imports\nconst createSkipDynamicImportsPlugin = (skipModules: string[]): esbuild.Plugin => ({\n name: 'skip-dynamic-imports',\n setup(build) {\n if (!skipModules || skipModules.length === 0) return;\n\n build.onResolve({ filter: /.*/ }, (args) => {\n // Only handle dynamic imports\n if (args.kind === 'dynamic-import' && skipModules.includes(args.path)) {\n logger.warn(`Skipping dynamic import: ${args.path}`);\n // Return a virtual module that exports an empty object\n return {\n path: args.path,\n namespace: 'lmnr-skip-dynamic-import',\n };\n }\n });\n\n // Provide empty module content for skipped dynamic imports\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n build.onLoad({ filter: /.*/, namespace: 'lmnr-skip-dynamic-import' }, (args) => ({\n contents: 'export default {};',\n loader: 'js',\n }));\n },\n});\n\ndeclare global {\n // eslint-disable-next-line no-var\n var _evaluations: Evaluation<any, any, any>[] | undefined;\n // eslint-disable-next-line no-var\n var _set_global_evaluation: boolean;\n}\n\nexport function loadModule({\n filename,\n moduleText,\n}: {\n filename: string;\n moduleText: string;\n}): Evaluation<any, any, any>[] {\n globalThis._evaluations = [];\n globalThis._set_global_evaluation = true;\n\n const __filename = filename;\n const __dirname = getDirname();\n\n // add some arguments for proper cjs/esm interop\n\n /* eslint-disable @typescript-eslint/no-implied-eval */\n new Function(\n \"require\",\n \"module\",\n \"__filename\",\n \"__dirname\",\n moduleText,\n )(\n require,\n module,\n __filename,\n __dirname,\n );\n /* eslint-enable @typescript-eslint/no-implied-eval */\n\n // Return the modified _evals global variable\n return globalThis._evaluations;\n}\n\nasync function cli() {\n const [, , ...args] = process.argv;\n\n // Use argparse, which is the port of the python library\n const parser = new ArgumentParser({\n prog: \"lmnr\",\n description: \"CLI for Laminar. Use `lmnr <subcommand> --help` for more information.\",\n });\n\n parser.add_argument(\"-v\", \"--version\", { action: \"version\", version });\n\n const subparsers = parser.add_subparsers({\n title: \"subcommands\",\n dest: \"subcommand\",\n });\n\n const parserEval = subparsers.add_parser(\"eval\", {\n description: \"Run an evaluation\",\n help: \"Run an evaluation\",\n });\n\n parserEval.add_argument(\"files\", {\n help: \"A file or files containing the evaluation to run. If no file is provided, \" +\n \"the evaluation will run all `*.eval.ts|js` files in the `evals` directory. \" +\n \"If multiple files are provided, the evaluation will run each file in order.\",\n nargs: \"*\",\n });\n\n parserEval.add_argument(\"--fail-on-error\", {\n help: \"Fail on error. If specified, will fail if encounters a file that cannot be run\",\n action: \"store_true\",\n });\n\n parserEval.add_argument(\"--output-file\", {\n help: \"Output file to write the results to. Outputs are written in JSON format.\",\n nargs: \"?\",\n });\n\n parserEval.add_argument(\"--external-packages\", {\n help: \"[ADVANCED] List of packages to pass as external to esbuild. This will not link \" +\n \"the packages directly into the eval file, but will instead require them at runtime. \" +\n \"Read more: https://esbuild.github.io/api/#external\",\n nargs: \"*\",\n });\n\n parserEval.add_argument(\"--dynamic-imports-to-skip\", {\n help: \"[ADVANCED] List of module names to skip when encountered as dynamic imports. \" +\n \"These dynamic imports will resolve to an empty module to prevent build failures. \" +\n \"This is meant to skip the imports that are not used in the evaluation itself.\",\n nargs: \"*\",\n });\n\n parserEval.set_defaults({\n func: async (args: any) => {\n let files: string[];\n if (args.files && args.files.length > 0) {\n files = args.files.flatMap((file: string) => glob.sync(file));\n } else {\n // No files provided, use default pattern\n files = glob.sync('evals/**/*.eval.{ts,js}');\n }\n\n files.sort();\n\n if (files.length === 0) {\n logger.error(\"No evaluation files found. Please provide a file or \" +\n \"ensure there are eval files that are named like `*.eval.{ts,js}` in\" +\n \"the `evals` directory or its subdirectories.\");\n process.exit(1);\n }\n\n if (args.files.length === 0) {\n logger.info(`Located ${files.length} evaluation files in evals/`);\n } else {\n logger.info(`Running ${files.length} evaluation files.`);\n }\n\n const scores: { file: string, scores: Record<string, number> }[] = [];\n\n for (const file of files) {\n logger.info(`Loading ${file}...`);\n const buildOptions = {\n bundle: true,\n platform: \"node\" as esbuild.Platform,\n entryPoints: [file],\n outfile: `tmp_out_${file}.js`,\n write: false, // will be loaded in memory as a temp file\n external: [\n \"node_modules/*\",\n \"playwright\",\n \"puppeteer\",\n \"puppeteer-core\",\n \"playwright-core\",\n \"fsevents\",\n ...(args.external_packages ? args.external_packages : []),\n ],\n plugins: [\n createSkipDynamicImportsPlugin(args.dynamic_imports_to_skip || []),\n ],\n treeShaking: true,\n };\n\n const result = await esbuild.build(buildOptions);\n\n if (!result.outputFiles) {\n logger.error(\"Error when building: No output files found \" +\n \"it is likely that all eval files are not valid TypeScript or JavaScript files.\");\n if (args.fail_on_error) {\n process.exit(1);\n }\n continue;\n }\n\n const outputFileText = result.outputFiles[0].text;\n\n const evaluations = loadModule({\n filename: file,\n moduleText: outputFileText,\n });\n\n logger.info(`Loaded ${evaluations.length} evaluations from ${file}`);\n\n for (const evaluation of evaluations) {\n if (!evaluation?.run) {\n logger.error(`Evaluation ${file} does not properly call evaluate()`);\n if (args.fail_on_error) {\n process.exit(1);\n }\n continue;\n }\n\n const evalScores = await evaluation.run();\n scores.push({ file, scores: evalScores });\n }\n }\n\n if (args.output_file) {\n fs.writeFileSync(args.output_file, JSON.stringify(scores, null, 2));\n }\n },\n });\n\n parser.set_defaults({\n func: () => {\n parser.print_help();\n process.exit(0);\n },\n });\n\n const parsed = parser.parse_args(args);\n await parsed.func(parsed);\n}\n\ncli().catch((err) => {\n logger.error(err instanceof Error ? err.message : err);\n throw err;\n});\n","{\n \"name\": \"@lmnr-ai/lmnr\",\n \"version\": \"0.6.12\",\n \"description\": \"TypeScript SDK for Laminar AI\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"scripts\": {\n \"build\": \"tsup\",\n \"test\": \"tsx --test test/*.test.ts\",\n \"lint\": \"eslint\",\n \"lint:fix\": \"eslint --fix\"\n },\n \"files\": [\n \"dist\",\n \"assets\"\n ],\n \"bin\": {\n \"lmnr\": \"./dist/cli.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/lmnr-ai/lmnr-ts.git\"\n },\n \"keywords\": [\n \"laminar\",\n \"lmnr\",\n \"sdk\",\n \"lmnr.ai\"\n ],\n \"author\": \"founders@lmnr.ai\",\n \"license\": \"Apache-2.0\",\n \"bugs\": {\n \"url\": \"https://github.com/lmnr-ai/lmnr-ts/issues\"\n },\n \"homepage\": \"https://github.com/lmnr-ai/lmnr-ts#README\",\n \"devDependencies\": {\n \"@anthropic-ai/sdk\": \"^0.39.0\",\n \"@aws-sdk/client-bedrock-runtime\": \"^3.835.0\",\n \"@azure/openai\": \"^2.0.0\",\n \"@browserbasehq/stagehand\": \"^2.3.1\",\n \"@eslint/eslintrc\": \"^3.3.1\",\n \"@eslint/js\": \"^9.29.0\",\n \"@google-cloud/aiplatform\": \"^4.2.0\",\n \"@google-cloud/vertexai\": \"^1.10.0\",\n \"@langchain/core\": \"^0.3.61\",\n \"@pinecone-database/pinecone\": \"^5.1.2\",\n \"@playwright/test\": \"^1.53.1\",\n \"@qdrant/js-client-rest\": \"^1.14.1\",\n \"@stylistic/eslint-plugin\": \"^5.0.0\",\n \"@types/argparse\": \"^2.0.17\",\n \"@types/cli-progress\": \"^3.11.6\",\n \"@types/node\": \"^24.0.3\",\n \"@types/semver\": \"^7.7.0\",\n \"@types/uuid\": \"^10.0.0\",\n \"chromadb\": \"^2.4.6\",\n \"cohere-ai\": \"^7.17.1\",\n \"eslint-plugin-simple-import-sort\": \"^12.1.1\",\n \"eslint-plugin-unused-imports\": \"^4.1.4\",\n \"langchain\": \"^0.3.29\",\n \"llamaindex\": \"^0.9.19\",\n \"nock\": \"^14.0.5\",\n \"openai\": \"^4.104.0\",\n \"playwright\": \"^1.53.1\",\n \"puppeteer\": \"^24.10.2\",\n \"puppeteer-core\": \"^24.10.2\",\n \"together-ai\": \"^0.14.0\",\n \"tsup\": \"^8.5.0\",\n \"tsx\": \"^4.20.3\",\n \"typescript\": \"^5.8.3\",\n \"typescript-eslint\": \"^8.35.0\"\n },\n \"dependencies\": {\n \"@grpc/grpc-js\": \"^1.13.4\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/context-async-hooks\": \"^1.30.1\",\n \"@opentelemetry/core\": \"^1.30.1\",\n \"@opentelemetry/exporter-trace-otlp-grpc\": \"^0.57.2\",\n \"@opentelemetry/exporter-trace-otlp-proto\": \"^0.57.2\",\n \"@opentelemetry/instrumentation\": \"^0.57.2\",\n \"@opentelemetry/otlp-exporter-base\": \"^0.57.2\",\n \"@opentelemetry/otlp-grpc-exporter-base\": \"^0.57.2\",\n \"@opentelemetry/resources\": \"^1.30.1\",\n \"@opentelemetry/sdk-node\": \"^0.57.2\",\n \"@opentelemetry/sdk-trace-base\": \"^1.30.1\",\n \"@opentelemetry/sdk-trace-base-v2\": \"npm:@opentelemetry/sdk-trace-base@2.0.0\",\n \"@opentelemetry/sdk-trace-node\": \"^1.30.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.34.0\",\n \"@traceloop/ai-semantic-conventions\": \"^0.12.0\",\n \"@traceloop/instrumentation-anthropic\": \"^0.12.0\",\n \"@traceloop/instrumentation-azure\": \"^0.12.0\",\n \"@traceloop/instrumentation-bedrock\": \"^0.12.0\",\n \"@traceloop/instrumentation-chromadb\": \"^0.12.0\",\n \"@traceloop/instrumentation-cohere\": \"^0.12.0\",\n \"@traceloop/instrumentation-langchain\": \"^0.12.0\",\n \"@traceloop/instrumentation-llamaindex\": \"^0.12.0\",\n \"@traceloop/instrumentation-openai\": \"^0.12.0\",\n \"@traceloop/instrumentation-pinecone\": \"^0.12.0\",\n \"@traceloop/instrumentation-qdrant\": \"^0.12.0\",\n \"@traceloop/instrumentation-together\": \"^0.12.1\",\n \"@traceloop/instrumentation-vertexai\": \"^0.12.0\",\n \"argparse\": \"^2.0.1\",\n \"cli-progress\": \"^3.12.0\",\n \"esbuild\": \"^0.25.5\",\n \"glob\": \"^11.0.3\",\n \"pino\": \"^9.7.0\",\n \"pino-pretty\": \"^13.0.0\",\n \"uuid\": \"^11.1.0\",\n \"zod\": \"^3.25.67\"\n }\n}","import { AttributeValue, SpanContext, TraceFlags } from '@opentelemetry/api';\nimport path from \"path\";\nimport pino, { Level } from 'pino';\nimport pinoPretty from 'pino-pretty';\nimport { fileURLToPath } from \"url\";\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { ASSOCIATION_PROPERTIES } from './opentelemetry-lib/tracing/attributes';\nimport { LaminarSpanContext } from './types';\n\nexport function initializeLogger(options?: { colorize?: boolean, level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level = options?.level\n ?? (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level)\n ?? 'info';\n\n return pino(pinoPretty({\n colorize,\n minimumLevel: level,\n }));\n}\n\nconst logger = initializeLogger();\n\nexport type StringUUID = `${string}-${string}-${string}-${string}-${string}`;\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(`Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.');\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(`Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.');\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): string => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(`Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.');\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(`Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.');\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 );\n};\n\nexport const uuidToOtelTraceId = (uuid: string): string => uuid.replace(/-/g, '');\nexport const uuidToOtelSpanId = (uuid: string): string => uuid.replace(/-/g, '').slice(16);\n\n/**\n * This is a simple implementation of a semaphore to replicate\n * the behavior of the `asyncio.Semaphore` in Python.\n */\nexport class Semaphore {\n /**\n * Number of permits available.\n */\n private _value: number;\n /**\n * List of promises that will be resolved when a permit becomes available.\n */\n private _waiters: ((...args: any[]) => any)[] = [];\n\n constructor(value = 1) {\n if (value < 0) {\n throw new Error(\"Semaphore value must be >= 0\");\n }\n this._value = value;\n this._waiters = [];\n }\n\n async acquire() {\n if (this._value > 0) {\n this._value--;\n return;\n }\n\n // Create a promise that will be resolved when a permit becomes available\n return new Promise(resolve => {\n this._waiters.push(resolve);\n });\n }\n\n release() {\n if (this._waiters.length > 0) {\n // If there are waiters, wake up the first one\n const resolve = this._waiters.shift();\n resolve?.();\n } else {\n this._value++;\n }\n }\n\n // Python-like context manager functionality\n async using<T>(fn: (...args: any[]) => Promise<T>) {\n try {\n await this.acquire();\n return await fn();\n } finally {\n this.release();\n }\n }\n}\n\nexport const tryToOtelSpanContext = (\n spanContext: LaminarSpanContext | Record<string, unknown> | string | SpanContext,\n): SpanContext => {\n if (typeof spanContext === 'string') {\n try {\n const record = JSON.parse(spanContext) as Record<string, unknown>;\n return recordToOtelSpanContext(record);\n } catch (e) {\n throw new Error(`Failed to parse span context ${spanContext}. ` +\n 'The string must be a json representation of a LaminarSpanContext.'\n + `Error: ${e instanceof Error ? e.message : String(e)}`);\n }\n } else if (isRecord(spanContext)) {\n // This covers the `LaminarSpanContext` case too.\n return recordToOtelSpanContext(spanContext);\n } else if (typeof spanContext.traceId === 'string'\n && typeof spanContext.spanId === 'string'\n && spanContext.traceId.length === 32\n && spanContext.spanId.length === 16) {\n logger.warn('The span context is already an OpenTelemetry SpanContext. ' +\n 'Returning it as is. Please use `LaminarSpanContext` objects instead.');\n return spanContext;\n }\n else {\n throw new Error(`Invalid span context ${JSON.stringify(spanContext)}. ` +\n 'Must be a LaminarSpanContext or its json representation.');\n }\n};\n\nconst recordToOtelSpanContext = (record: Record<string, unknown>): SpanContext => {\n if (typeof record.spanId === 'string' && typeof record.traceId === 'string') {\n return {\n spanId: uuidToOtelSpanId(record?.spanId ?? record?.['span_id']),\n traceId: uuidToOtelTraceId(record?.traceId ?? record?.['trace_id']),\n isRemote: record?.isRemote ?? record?.['is_remote'] ?? false,\n traceFlags: record?.traceFlags ?? TraceFlags.SAMPLED,\n } as SpanContext;\n } else {\n throw new Error(`Invalid span context ${JSON.stringify(record)}. ` +\n 'Must be a json representation of a LaminarSpanContext.');\n }\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && !Array.isArray(value) && value !== null;\n\n\nexport const getDirname = () => {\n if (typeof __dirname !== 'undefined') {\n return __dirname;\n }\n\n if (typeof import.meta?.url !== 'undefined') {\n return path.dirname(fileURLToPath(import.meta.url));\n }\n\n return process.cwd();\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 isOtelAttributeValueType = (value: unknown): value is AttributeValue => {\n if (typeof value === 'string'\n || typeof value === 'number'\n || typeof value === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n const allStrings = value.every(value => (value == null) || typeof value === 'string');\n const allNumbers = value.every(value => (value == null) || typeof value === 'number');\n const allBooleans = value.every(value => (value == null) || typeof value === 'boolean');\n return allStrings || allNumbers || allBooleans;\n }\n return false;\n};\n\nexport const metadataToAttributes = (\n metadata: Record<string, unknown>,\n): Record<string, AttributeValue> => Object.fromEntries(\n Object.entries(metadata).map(([key, value]) => {\n if (isOtelAttributeValueType(value)) {\n return [`${ASSOCIATION_PROPERTIES}.metadata.${key}`, value];\n } else {\n return [`${ASSOCIATION_PROPERTIES}.metadata.${key}`, JSON.stringify(value)];\n }\n }),\n);\n","import { SpanAttributes } from '@traceloop/ai-semantic-conventions';\n\nexport const SPAN_INPUT = \"lmnr.span.input\";\nexport const SPAN_OUTPUT = \"lmnr.span.output\";\nexport const SPAN_TYPE = \"lmnr.span.type\";\nexport const SPAN_PATH = \"lmnr.span.path\";\nexport const SPAN_IDS_PATH = \"lmnr.span.ids_path\";\nexport const SPAN_INSTRUMENTATION_SOURCE = \"lmnr.span.instrumentation_source\";\nexport const SPAN_SDK_VERSION = \"lmnr.span.sdk_version\";\nexport const SPAN_LANGUAGE_VERSION = \"lmnr.span.language_version\";\nexport const OVERRIDE_PARENT_SPAN = \"lmnr.internal.override_parent_span\";\nexport const TRACE_HAS_BROWSER_SESSION = \"lmnr.internal.has_browser_session\";\nexport const EXTRACTED_FROM_NEXT_JS = \"lmnr.span.extracted_from.next_js\";\n\nexport const ASSOCIATION_PROPERTIES = \"lmnr.association.properties\";\nexport const SESSION_ID = \"lmnr.association.properties.session_id\";\nexport const USER_ID = \"lmnr.association.properties.user_id\";\nexport const TRACE_TYPE = \"lmnr.association.properties.trace_type\";\n\nexport const ASSOCIATION_PROPERTIES_OVERRIDES: Record<string, string> = {\n \"span_type\": SPAN_TYPE,\n};\n\nexport const LaminarAttributes = {\n // == This is the minimum set of attributes for a proper LLM span ==\n //\n // not SpanAttributes.LLM_USAGE_PROMPT_TOKENS\n INPUT_TOKEN_COUNT: \"gen_ai.usage.input_tokens\",\n // not SpanAttributes.LLM_USAGE_COMPLETION_TOKENS\n OUTPUT_TOKEN_COUNT: \"gen_ai.usage.output_tokens\",\n TOTAL_TOKEN_COUNT: SpanAttributes.LLM_USAGE_TOTAL_TOKENS,\n PROVIDER: SpanAttributes.LLM_SYSTEM,\n REQUEST_MODEL: SpanAttributes.LLM_REQUEST_MODEL,\n RESPONSE_MODEL: SpanAttributes.LLM_RESPONSE_MODEL,\n //\n // == End of minimum set ==\n // == Additional attributes ==\n //\n INPUT_COST: \"gen_ai.usage.input_cost\",\n OUTPUT_COST: \"gen_ai.usage.output_cost\",\n TOTAL_COST: \"gen_ai.usage.cost\",\n //\n // == End of additional attributes ==\n};\n"],"mappings":"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","names":["logger","build","__dirname","args"]}
@@ -333,17 +333,28 @@ declare class EvalsResource extends BaseResource {
333
333
  *
334
334
  * @param {string} name - Name of the evaluation
335
335
  * @param {string} groupName - Group name of the evaluation
336
+ * @param {Record<string, any>} metadata - Optional metadata
336
337
  * @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization
337
338
  */
338
- init(name?: string, groupName?: string): Promise<InitEvaluationResponse>;
339
+ init(name?: string, groupName?: string, metadata?: Record<string, any>): Promise<InitEvaluationResponse>;
339
340
  /**
340
341
  * Create a new evaluation and return its ID.
341
342
  *
342
343
  * @param {string} [name] - Optional name of the evaluation
343
344
  * @param {string} [groupName] - An identifier to group evaluations
345
+ * @param {Record<string, any>} [metadata] - Optional metadata
344
346
  * @returns {Promise<StringUUID>} The evaluation ID
345
347
  */
346
- createEvaluation(name?: string, groupName?: string): Promise<StringUUID>;
348
+ create(args?: {
349
+ name?: string;
350
+ groupName?: string;
351
+ metadata?: Record<string, any>;
352
+ }): Promise<StringUUID>;
353
+ /**
354
+ * Create a new evaluation and return its ID.
355
+ * @deprecated use `create` instead.
356
+ */
357
+ createEvaluation(name?: string, groupName?: string, metadata?: Record<string, any>): Promise<StringUUID>;
347
358
  /**
348
359
  * Create a datapoint for an evaluation.
349
360
  *
@@ -447,7 +458,7 @@ declare class TagsResource extends BaseResource {
447
458
  * }
448
459
  * ```
449
460
  */
450
- tag(trace_id: string | StringUUID, tags: string[] | string): Promise<any>;
461
+ tag(trace_id: string, tags: string[] | string): Promise<any>;
451
462
  }
452
463
 
453
464
  declare class LaminarClient {
@@ -898,6 +909,10 @@ interface EvaluationConstructorProps<D, T, O> {
898
909
  * group_id can be visually compared. Defaults to "default".
899
910
  */
900
911
  groupName?: string;
912
+ /**
913
+ * Optional metadata to evaluation
914
+ */
915
+ metadata?: Record<string, any>;
901
916
  /**
902
917
  * Optional override configurations for the evaluator.
903
918
  */
@@ -911,13 +926,14 @@ declare class Evaluation<D, T, O> {
911
926
  private evaluators;
912
927
  private groupName?;
913
928
  private name?;
929
+ private metadata?;
914
930
  private concurrencyLimit;
915
931
  private traceDisableBatch;
916
932
  private traceExportTimeoutMillis?;
917
933
  private traceExportBatchSize;
918
934
  private uploadPromises;
919
935
  private client;
920
- constructor({ data, executor, evaluators, groupName, name, config, }: EvaluationConstructorProps<D, T, O>);
936
+ constructor({ data, executor, evaluators, groupName, name, metadata, config, }: EvaluationConstructorProps<D, T, O>);
921
937
  run(): Promise<Record<string, number>>;
922
938
  evaluateInBatches(evalId: StringUUID): Promise<EvaluationDatapoint<D, T, O>[]>;
923
939
  private evaluateDatapoint;
@@ -938,8 +954,9 @@ declare class Evaluation<D, T, O> {
938
954
  * returns.
939
955
  * @param props.name Optional name of the evaluation. Used to easily identify
940
956
  * the evaluation in the group.
957
+ * @param props.metadata Optional metadata to evaluation
941
958
  * @param props.config Optional override configurations for the evaluator.
942
959
  */
943
- declare function evaluate<D, T, O>({ data, executor, evaluators, groupName, name, config, }: EvaluationConstructorProps<D, T, O>): Promise<void>;
960
+ declare function evaluate<D, T, O>({ data, executor, evaluators, groupName, name, metadata, config, }: EvaluationConstructorProps<D, T, O>): Promise<void>;
944
961
 
945
962
  export { type ChatMessage as C, type Datapoint as D, Evaluation as E, HumanEvaluator as H, type InitializeOptions as I, type LaminarSpanContext as L, type NodeInput as N, type StringUUID as S, type TraceType as T, TracingLevel as a, LaminarClient as b, EvaluationDataset as c, LaminarDataset as d, evaluate as e, type EvaluatorFunction as f, type EvaluatorFunctionReturn as g, type EvaluationDatapoint as h, type Event as i };
@@ -333,17 +333,28 @@ declare class EvalsResource extends BaseResource {
333
333
  *
334
334
  * @param {string} name - Name of the evaluation
335
335
  * @param {string} groupName - Group name of the evaluation
336
+ * @param {Record<string, any>} metadata - Optional metadata
336
337
  * @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization
337
338
  */
338
- init(name?: string, groupName?: string): Promise<InitEvaluationResponse>;
339
+ init(name?: string, groupName?: string, metadata?: Record<string, any>): Promise<InitEvaluationResponse>;
339
340
  /**
340
341
  * Create a new evaluation and return its ID.
341
342
  *
342
343
  * @param {string} [name] - Optional name of the evaluation
343
344
  * @param {string} [groupName] - An identifier to group evaluations
345
+ * @param {Record<string, any>} [metadata] - Optional metadata
344
346
  * @returns {Promise<StringUUID>} The evaluation ID
345
347
  */
346
- createEvaluation(name?: string, groupName?: string): Promise<StringUUID>;
348
+ create(args?: {
349
+ name?: string;
350
+ groupName?: string;
351
+ metadata?: Record<string, any>;
352
+ }): Promise<StringUUID>;
353
+ /**
354
+ * Create a new evaluation and return its ID.
355
+ * @deprecated use `create` instead.
356
+ */
357
+ createEvaluation(name?: string, groupName?: string, metadata?: Record<string, any>): Promise<StringUUID>;
347
358
  /**
348
359
  * Create a datapoint for an evaluation.
349
360
  *
@@ -447,7 +458,7 @@ declare class TagsResource extends BaseResource {
447
458
  * }
448
459
  * ```
449
460
  */
450
- tag(trace_id: string | StringUUID, tags: string[] | string): Promise<any>;
461
+ tag(trace_id: string, tags: string[] | string): Promise<any>;
451
462
  }
452
463
 
453
464
  declare class LaminarClient {
@@ -898,6 +909,10 @@ interface EvaluationConstructorProps<D, T, O> {
898
909
  * group_id can be visually compared. Defaults to "default".
899
910
  */
900
911
  groupName?: string;
912
+ /**
913
+ * Optional metadata to evaluation
914
+ */
915
+ metadata?: Record<string, any>;
901
916
  /**
902
917
  * Optional override configurations for the evaluator.
903
918
  */
@@ -911,13 +926,14 @@ declare class Evaluation<D, T, O> {
911
926
  private evaluators;
912
927
  private groupName?;
913
928
  private name?;
929
+ private metadata?;
914
930
  private concurrencyLimit;
915
931
  private traceDisableBatch;
916
932
  private traceExportTimeoutMillis?;
917
933
  private traceExportBatchSize;
918
934
  private uploadPromises;
919
935
  private client;
920
- constructor({ data, executor, evaluators, groupName, name, config, }: EvaluationConstructorProps<D, T, O>);
936
+ constructor({ data, executor, evaluators, groupName, name, metadata, config, }: EvaluationConstructorProps<D, T, O>);
921
937
  run(): Promise<Record<string, number>>;
922
938
  evaluateInBatches(evalId: StringUUID): Promise<EvaluationDatapoint<D, T, O>[]>;
923
939
  private evaluateDatapoint;
@@ -938,8 +954,9 @@ declare class Evaluation<D, T, O> {
938
954
  * returns.
939
955
  * @param props.name Optional name of the evaluation. Used to easily identify
940
956
  * the evaluation in the group.
957
+ * @param props.metadata Optional metadata to evaluation
941
958
  * @param props.config Optional override configurations for the evaluator.
942
959
  */
943
- declare function evaluate<D, T, O>({ data, executor, evaluators, groupName, name, config, }: EvaluationConstructorProps<D, T, O>): Promise<void>;
960
+ declare function evaluate<D, T, O>({ data, executor, evaluators, groupName, name, metadata, config, }: EvaluationConstructorProps<D, T, O>): Promise<void>;
944
961
 
945
962
  export { type ChatMessage as C, type Datapoint as D, Evaluation as E, HumanEvaluator as H, type InitializeOptions as I, type LaminarSpanContext as L, type NodeInput as N, type StringUUID as S, type TraceType as T, TracingLevel as a, LaminarClient as b, EvaluationDataset as c, LaminarDataset as d, evaluate as e, type EvaluatorFunction as f, type EvaluatorFunctionReturn as g, type EvaluationDatapoint as h, type Event as i };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TraceType, L as LaminarSpanContext, a as TracingLevel, I as InitializeOptions, S as StringUUID } from './evaluations-DUmIeesJ.mjs';
2
- export { C as ChatMessage, D as Datapoint, c as Dataset, h as EvaluationDatapoint, f as EvaluatorFunction, g as EvaluatorFunctionReturn, i as Event, H as HumanEvaluator, b as LaminarClient, d as LaminarDataset, N as NodeInput, e as evaluate } from './evaluations-DUmIeesJ.mjs';
1
+ import { T as TraceType, L as LaminarSpanContext, a as TracingLevel, I as InitializeOptions, S as StringUUID } from './evaluations-Ch9Bet5y.mjs';
2
+ export { C as ChatMessage, D as Datapoint, c as Dataset, h as EvaluationDatapoint, f as EvaluatorFunction, g as EvaluatorFunctionReturn, i as Event, H as HumanEvaluator, b as LaminarClient, d as LaminarDataset, N as NodeInput, e as evaluate } from './evaluations-Ch9Bet5y.mjs';
3
3
  import { Context, AttributeValue, TimeInput, Span as Span$2, Tracer, TracerProvider } from '@opentelemetry/api';
4
4
  export { Span } from '@opentelemetry/api';
5
5
  import { SpanProcessor, SpanExporter, Span, ReadableSpan } from '@opentelemetry/sdk-trace-base';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TraceType, L as LaminarSpanContext, a as TracingLevel, I as InitializeOptions, S as StringUUID } from './evaluations-DUmIeesJ.js';
2
- export { C as ChatMessage, D as Datapoint, c as Dataset, h as EvaluationDatapoint, f as EvaluatorFunction, g as EvaluatorFunctionReturn, i as Event, H as HumanEvaluator, b as LaminarClient, d as LaminarDataset, N as NodeInput, e as evaluate } from './evaluations-DUmIeesJ.js';
1
+ import { T as TraceType, L as LaminarSpanContext, a as TracingLevel, I as InitializeOptions, S as StringUUID } from './evaluations-Ch9Bet5y.js';
2
+ export { C as ChatMessage, D as Datapoint, c as Dataset, h as EvaluationDatapoint, f as EvaluatorFunction, g as EvaluatorFunctionReturn, i as Event, H as HumanEvaluator, b as LaminarClient, d as LaminarDataset, N as NodeInput, e as evaluate } from './evaluations-Ch9Bet5y.js';
3
3
  import { Context, AttributeValue, TimeInput, Span as Span$2, Tracer, TracerProvider } from '@opentelemetry/api';
4
4
  export { Span } from '@opentelemetry/api';
5
5
  import { SpanProcessor, SpanExporter, Span, ReadableSpan } from '@opentelemetry/sdk-trace-base';