@lmnr-ai/lmnr 0.6.15 → 0.6.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { E as Evaluation } from './evaluations-DQXXNKaz.mjs';
2
+ import { E as Evaluation } from './evaluations-RNDL_lTo.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-DQXXNKaz.js';
2
+ import { E as Evaluation } from './evaluations-RNDL_lTo.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
@@ -40,7 +40,7 @@ var fs = __toESM(require("fs"));
40
40
  var glob = __toESM(require("glob"));
41
41
 
42
42
  // package.json
43
- var version = "0.6.15";
43
+ var version = "0.6.16";
44
44
 
45
45
  // src/utils.ts
46
46
  var import_api = require("@opentelemetry/api");
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 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\n var _evaluations: Evaluation<any, any, any>[] | undefined;\n\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.15\",\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 * as 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\";\nexport const HUMAN_EVALUATOR_OPTIONS = 'lmnr.span.human_evaluator_options';\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","logger","build","__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.16\",\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 * as 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\";\nexport const HUMAN_EVALUATOR_OPTIONS = 'lmnr.span.human_evaluator_options';\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","logger","build","__dirname","args"]}
package/dist/cli.mjs CHANGED
@@ -13,7 +13,7 @@ import * as fs from "fs";
13
13
  import * as glob from "glob";
14
14
 
15
15
  // package.json
16
- var version = "0.6.15";
16
+ var version = "0.6.16";
17
17
 
18
18
  // src/utils.ts
19
19
  import { TraceFlags } from "@opentelemetry/api";
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 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\n var _evaluations: Evaluation<any, any, any>[] | undefined;\n\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.15\",\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 * as 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\";\nexport const HUMAN_EVALUATOR_OPTIONS = 'lmnr.span.human_evaluator_options';\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"]}
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.16\",\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 * as 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\";\nexport const HUMAN_EVALUATOR_OPTIONS = 'lmnr.span.human_evaluator_options';\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"]}
@@ -560,6 +560,12 @@ interface InitializeOptions {
560
560
  * Defaults to https://api.lmnr.ai:8443
561
561
  */
562
562
  baseUrl?: string;
563
+ /**
564
+ * The Laminar API HTTP endpoint for sending traces data. Optional.
565
+ * Defaults to baseUrl. Only use this if you want to proxy HTTP requests
566
+ * through a different host.
567
+ */
568
+ baseHttpUrl?: string;
563
569
  /**
564
570
  * Whether to disable batching. Optional.
565
571
  * Defaults to false.
@@ -865,6 +871,11 @@ interface EvaluatorConfig {
865
871
  * Do NOT include the port in the URL, use `httpPort` and `grpcPort` instead.
866
872
  */
867
873
  baseUrl?: string;
874
+ /**
875
+ * The base HTTP URL of the Laminar API. If not provided, the default is
876
+ * `baseUrl`. Only use this if you want to proxy HTTP requests through a different host.
877
+ */
878
+ baseHttpUrl?: string;
868
879
  /**
869
880
  * The HTTP port of the Laminar API. If not provided, the default is 443.
870
881
  */
@@ -560,6 +560,12 @@ interface InitializeOptions {
560
560
  * Defaults to https://api.lmnr.ai:8443
561
561
  */
562
562
  baseUrl?: string;
563
+ /**
564
+ * The Laminar API HTTP endpoint for sending traces data. Optional.
565
+ * Defaults to baseUrl. Only use this if you want to proxy HTTP requests
566
+ * through a different host.
567
+ */
568
+ baseHttpUrl?: string;
563
569
  /**
564
570
  * Whether to disable batching. Optional.
565
571
  * Defaults to false.
@@ -865,6 +871,11 @@ interface EvaluatorConfig {
865
871
  * Do NOT include the port in the URL, use `httpPort` and `grpcPort` instead.
866
872
  */
867
873
  baseUrl?: string;
874
+ /**
875
+ * The base HTTP URL of the Laminar API. If not provided, the default is
876
+ * `baseUrl`. Only use this if you want to proxy HTTP requests through a different host.
877
+ */
878
+ baseHttpUrl?: string;
868
879
  /**
869
880
  * The HTTP port of the Laminar API. If not provided, the default is 443.
870
881
  */
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-DQXXNKaz.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-DQXXNKaz.mjs';
1
+ import { T as TraceType, L as LaminarSpanContext, a as TracingLevel, I as InitializeOptions, S as StringUUID } from './evaluations-RNDL_lTo.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-RNDL_lTo.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';
@@ -199,6 +199,7 @@ declare const LaminarAttributes: {
199
199
  interface LaminarInitializeProps {
200
200
  projectApiKey?: string;
201
201
  baseUrl?: string;
202
+ baseHttpUrl?: string;
202
203
  httpPort?: number;
203
204
  grpcPort?: number;
204
205
  instrumentModules?: InitializeOptions["instrumentModules"];
@@ -224,6 +225,8 @@ declare class Laminar {
224
225
  * @param {string} props.baseUrl - Laminar API url. Do not include the port, use
225
226
  * `httpPort` and `grpcPort` instead.
226
227
  * If not specified, defaults to https://api.lmnr.ai.
228
+ * @param {string} props.baseHttpUrl - Laminar API http url. If not specified, defaults to
229
+ * baseUrl. Only use this if you want to proxy HTTP requests through a different host.
227
230
  * @param {number} props.httpPort - Laminar API http port.
228
231
  * If not specified, defaults to 443.
229
232
  * @param {number} props.grpcPort - Laminar API grpc port.
@@ -263,7 +266,7 @@ declare class Laminar {
263
266
  *
264
267
  * @throws {Error} - If project API key is not set
265
268
  */
266
- static initialize({ projectApiKey, baseUrl, httpPort, grpcPort, instrumentModules, disableBatch, traceExportTimeoutMillis, logLevel, maxExportBatchSize, forceHttp, }?: LaminarInitializeProps): void;
269
+ static initialize({ projectApiKey, baseUrl, baseHttpUrl, httpPort, grpcPort, instrumentModules, disableBatch, traceExportTimeoutMillis, logLevel, maxExportBatchSize, forceHttp, }?: LaminarInitializeProps): void;
267
270
  /**
268
271
  * Patch modules manually. Use this in setups where {@link Laminar.initialize()}
269
272
  * and in particular its `instrumentModules` option is not working, e.g. in
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-DQXXNKaz.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-DQXXNKaz.js';
1
+ import { T as TraceType, L as LaminarSpanContext, a as TracingLevel, I as InitializeOptions, S as StringUUID } from './evaluations-RNDL_lTo.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-RNDL_lTo.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';
@@ -199,6 +199,7 @@ declare const LaminarAttributes: {
199
199
  interface LaminarInitializeProps {
200
200
  projectApiKey?: string;
201
201
  baseUrl?: string;
202
+ baseHttpUrl?: string;
202
203
  httpPort?: number;
203
204
  grpcPort?: number;
204
205
  instrumentModules?: InitializeOptions["instrumentModules"];
@@ -224,6 +225,8 @@ declare class Laminar {
224
225
  * @param {string} props.baseUrl - Laminar API url. Do not include the port, use
225
226
  * `httpPort` and `grpcPort` instead.
226
227
  * If not specified, defaults to https://api.lmnr.ai.
228
+ * @param {string} props.baseHttpUrl - Laminar API http url. If not specified, defaults to
229
+ * baseUrl. Only use this if you want to proxy HTTP requests through a different host.
227
230
  * @param {number} props.httpPort - Laminar API http port.
228
231
  * If not specified, defaults to 443.
229
232
  * @param {number} props.grpcPort - Laminar API grpc port.
@@ -263,7 +266,7 @@ declare class Laminar {
263
266
  *
264
267
  * @throws {Error} - If project API key is not set
265
268
  */
266
- static initialize({ projectApiKey, baseUrl, httpPort, grpcPort, instrumentModules, disableBatch, traceExportTimeoutMillis, logLevel, maxExportBatchSize, forceHttp, }?: LaminarInitializeProps): void;
269
+ static initialize({ projectApiKey, baseUrl, baseHttpUrl, httpPort, grpcPort, instrumentModules, disableBatch, traceExportTimeoutMillis, logLevel, maxExportBatchSize, forceHttp, }?: LaminarInitializeProps): void;
267
270
  /**
268
271
  * Patch modules manually. Use this in setups where {@link Laminar.initialize()}
269
272
  * and in particular its `instrumentModules` option is not working, e.g. in
package/dist/index.js CHANGED
@@ -485,7 +485,7 @@ var AgentResource = class extends BaseResource {
485
485
  };
486
486
 
487
487
  // package.json
488
- var version = "0.6.15";
488
+ var version = "0.6.16";
489
489
 
490
490
  // src/version.ts
491
491
  var getLangVersion = () => {
@@ -1017,6 +1017,8 @@ var Laminar = class {
1017
1017
  * @param {string} props.baseUrl - Laminar API url. Do not include the port, use
1018
1018
  * `httpPort` and `grpcPort` instead.
1019
1019
  * If not specified, defaults to https://api.lmnr.ai.
1020
+ * @param {string} props.baseHttpUrl - Laminar API http url. If not specified, defaults to
1021
+ * baseUrl. Only use this if you want to proxy HTTP requests through a different host.
1020
1022
  * @param {number} props.httpPort - Laminar API http port.
1021
1023
  * If not specified, defaults to 443.
1022
1024
  * @param {number} props.grpcPort - Laminar API grpc port.
@@ -1059,6 +1061,7 @@ var Laminar = class {
1059
1061
  static initialize({
1060
1062
  projectApiKey,
1061
1063
  baseUrl,
1064
+ baseHttpUrl,
1062
1065
  httpPort,
1063
1066
  grpcPort,
1064
1067
  instrumentModules,
@@ -1076,12 +1079,15 @@ var Laminar = class {
1076
1079
  }
1077
1080
  this.projectApiKey = key;
1078
1081
  const url = baseUrl ?? process?.env?.LMNR_BASE_URL ?? "https://api.lmnr.ai";
1079
- const port = httpPort ?? (url.match(/:\d{1,5}$/g) ? parseInt(url.match(/:\d{1,5}$/g)[0].slice(1)) : 443);
1082
+ const httpUrl = baseHttpUrl ?? url;
1083
+ const port = httpPort ?? (httpUrl.match(/:\d{1,5}$/g) ? parseInt(httpUrl.match(/:\d{1,5}$/g)[0].slice(1)) : 443);
1080
1084
  const urlWithoutSlash = url.replace(/\/$/, "").replace(/:\d{1,5}$/g, "");
1081
- this.baseHttpUrl = `${urlWithoutSlash}:${port}`;
1085
+ const httpUrlWithoutSlash = httpUrl.replace(/\/$/, "").replace(/:\d{1,5}$/g, "");
1086
+ this.baseHttpUrl = `${httpUrlWithoutSlash}:${port}`;
1082
1087
  this.isInitialized = true;
1083
1088
  initializeTracing({
1084
1089
  baseUrl: urlWithoutSlash,
1090
+ baseHttpUrl: httpUrlWithoutSlash,
1085
1091
  apiKey: this.projectApiKey,
1086
1092
  port: grpcPort,
1087
1093
  forceHttp,
@@ -3332,7 +3338,7 @@ var tracerProvider;
3332
3338
  var _baseHttpUrl = "https://api.lmnr.ai:443";
3333
3339
  var _apiKey;
3334
3340
  var startTracing = (options) => {
3335
- _baseHttpUrl = `${options.baseUrl}:${options.httpPort ?? 443}`;
3341
+ _baseHttpUrl = `${options.baseHttpUrl ?? options.baseUrl}:${options.httpPort ?? 443}`;
3336
3342
  _apiKey = options.apiKey;
3337
3343
  const instrumentations = initializeLaminarInstrumentations({
3338
3344
  baseUrl: _baseHttpUrl,
@@ -3802,8 +3808,9 @@ var Evaluation = class {
3802
3808
  );
3803
3809
  }
3804
3810
  const url = config?.baseUrl ?? process?.env?.LMNR_BASE_URL ?? "https://api.lmnr.ai";
3805
- const httpPort = config?.httpPort ?? (url.match(/:\d{1,5}$/g) ? parseInt(url.match(/:\d{1,5}$/g)[0].slice(1)) : 443);
3806
- const urlWithoutSlash = url.replace(/\/$/, "").replace(/:\d{1,5}$/g, "");
3811
+ const httpUrl = config?.baseHttpUrl ?? url;
3812
+ const httpPort = config?.httpPort ?? (httpUrl.match(/:\d{1,5}$/g) ? parseInt(httpUrl.match(/:\d{1,5}$/g)[0].slice(1)) : 443);
3813
+ const urlWithoutSlash = httpUrl.replace(/\/$/, "").replace(/:\d{1,5}$/g, "");
3807
3814
  const baseHttpUrl = `${urlWithoutSlash}:${httpPort}`;
3808
3815
  this.client = new LaminarClient({
3809
3816
  baseUrl: baseHttpUrl,
@@ -3824,8 +3831,9 @@ var Evaluation = class {
3824
3831
  }
3825
3832
  Laminar.initialize({
3826
3833
  projectApiKey: config?.projectApiKey,
3827
- baseUrl: config?.baseUrl,
3828
- httpPort: config?.httpPort,
3834
+ baseUrl: url,
3835
+ baseHttpUrl,
3836
+ httpPort,
3829
3837
  grpcPort: config?.grpcPort,
3830
3838
  instrumentModules: config?.instrumentModules,
3831
3839
  disableBatch: this.traceDisableBatch,