@langfuse/client 4.0.0-beta.4 → 4.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -210,7 +210,7 @@ var MediaManager = class _MediaManager {
210
210
  const uint8Content = new Uint8Array(
211
211
  await mediaContent.arrayBuffer()
212
212
  );
213
- const base64MediaContent = (0, import_core.uint8ArrayToBase64)(uint8Content);
213
+ const base64MediaContent = (0, import_core.bytesToBase64)(uint8Content);
214
214
  const base64DataUri = `data:${mediaData.contentType};base64,${base64MediaContent}`;
215
215
  referenceStringToMediaContentMap.set(
216
216
  referenceString,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/LangfuseClient.ts","../src/dataset/index.ts","../src/media/index.ts","../src/prompt/promptManager.ts","../src/prompt/promptCache.ts","../src/prompt/promptClients.ts","../src/prompt/types.ts","../src/score/index.ts"],"sourcesContent":["export * from \"./LangfuseClient.js\";\nexport * from \"./prompt/index.js\";\nexport * from \"./score/index.js\";\nexport * from \"./dataset/index.js\";\nexport * from \"./media/index.js\";\n","import {\n LangfuseAPIClient,\n LANGFUSE_SDK_VERSION,\n getGlobalLogger,\n getEnv,\n} from \"@langfuse/core\";\n\nimport { DatasetManager } from \"./dataset/index.js\";\nimport { MediaManager } from \"./media/index.js\";\nimport { PromptManager } from \"./prompt/index.js\";\nimport { ScoreManager } from \"./score/index.js\";\n\n/**\n * Configuration parameters for initializing a LangfuseClient instance.\n *\n * @public\n */\nexport interface LangfuseClientParams {\n /**\n * Public API key for authentication with Langfuse.\n * Can also be provided via LANGFUSE_PUBLIC_KEY environment variable.\n */\n publicKey?: string;\n\n /**\n * Secret API key for authentication with Langfuse.\n * Can also be provided via LANGFUSE_SECRET_KEY environment variable.\n */\n secretKey?: string;\n\n /**\n * Base URL of the Langfuse instance to connect to.\n * Can also be provided via LANGFUSE_BASE_URL environment variable.\n *\n * @defaultValue \"https://cloud.langfuse.com\"\n */\n baseUrl?: string;\n\n /**\n * Request timeout in seconds.\n * Can also be provided via LANGFUSE_TIMEOUT environment variable.\n *\n * @defaultValue 5\n */\n timeout?: number;\n\n /**\n * Additional HTTP headers to include with API requests.\n */\n additionalHeaders?: Record<string, string>;\n}\n\n/**\n * Main client for interacting with the Langfuse API.\n *\n * The LangfuseClient provides access to all Langfuse functionality including:\n * - Prompt management and retrieval\n * - Dataset operations\n * - Score creation and management\n * - Media upload and handling\n * - Direct API access for advanced use cases\n *\n * @example\n * ```typescript\n * // Initialize with explicit credentials\n * const langfuse = new LangfuseClient({\n * publicKey: \"pk_...\",\n * secretKey: \"sk_...\",\n * baseUrl: \"https://cloud.langfuse.com\"\n * });\n *\n * // Or use environment variables\n * const langfuse = new LangfuseClient();\n *\n * // Use the client\n * const prompt = await langfuse.prompt.get(\"my-prompt\");\n * const compiledPrompt = prompt.compile({ variable: \"value\" });\n * ```\n *\n * @public\n */\nexport class LangfuseClient {\n /**\n * Direct access to the underlying Langfuse API client.\n * Use this for advanced API operations not covered by the high-level managers.\n */\n public api: LangfuseAPIClient;\n\n /**\n * Manager for prompt operations including creation, retrieval, and caching.\n */\n public prompt: PromptManager;\n\n /**\n * Manager for dataset operations including retrieval and item linking.\n */\n public dataset: DatasetManager;\n\n /**\n * Manager for score creation and batch processing.\n */\n public score: ScoreManager;\n\n /**\n * Manager for media upload and reference resolution.\n */\n public media: MediaManager;\n\n private baseUrl: string;\n private projectId: string | null = null;\n\n /**\n * @deprecated Use prompt.get instead\n */\n public getPrompt: typeof PromptManager.prototype.get;\n /**\n * @deprecated Use prompt.create instead\n */\n public createPrompt: typeof PromptManager.prototype.create;\n /**\n * @deprecated Use prompt.update instead\n */\n public updatePrompt: typeof PromptManager.prototype.update;\n /**\n * @deprecated Use dataset.get instead\n */\n public getDataset: typeof DatasetManager.prototype.get;\n /**\n * @deprecated Use api.trace.get instead\n */\n public fetchTrace: typeof LangfuseAPIClient.prototype.trace.get;\n /**\n * @deprecated Use api.trace.list instead\n */\n public fetchTraces: typeof LangfuseAPIClient.prototype.trace.list;\n /**\n * @deprecated Use api.observations.get instead\n */\n public fetchObservation: typeof LangfuseAPIClient.prototype.observations.get;\n /**\n * @deprecated Use api.observations.list instead\n */\n public fetchObservations: typeof LangfuseAPIClient.prototype.observations.getMany;\n /**\n * @deprecated Use api.sessions.get instead\n */\n public fetchSessions: typeof LangfuseAPIClient.prototype.sessions.get;\n /**\n * @deprecated Use api.datasets.getRun instead\n */\n public getDatasetRun: typeof LangfuseAPIClient.prototype.datasets.getRun;\n /**\n * @deprecated Use api.datasets.getRuns instead\n */\n public getDatasetRuns: typeof LangfuseAPIClient.prototype.datasets.getRuns;\n /**\n * @deprecated Use api.datasets.create instead\n */\n public createDataset: typeof LangfuseAPIClient.prototype.datasets.create;\n /**\n * @deprecated Use api.datasetItems.get instead\n */\n public getDatasetItem: typeof LangfuseAPIClient.prototype.datasetItems.get;\n /**\n * @deprecated Use api.datasetItems.create instead\n */\n public createDatasetItem: typeof LangfuseAPIClient.prototype.datasetItems.create;\n /**\n * @deprecated Use api.media.get instead\n */\n public fetchMedia: typeof LangfuseAPIClient.prototype.media.get;\n /**\n * @deprecated Use media.resolveReferences instead\n */\n public resolveMediaReferences: typeof MediaManager.prototype.resolveReferences;\n\n /**\n * Creates a new LangfuseClient instance.\n *\n * @param params - Configuration parameters. If not provided, will use environment variables.\n *\n * @throws Will log warnings if required credentials are not provided\n *\n * @example\n * ```typescript\n * // With explicit configuration\n * const client = new LangfuseClient({\n * publicKey: \"pk_...\",\n * secretKey: \"sk_...\",\n * baseUrl: \"https://your-instance.langfuse.com\"\n * });\n *\n * // Using environment variables\n * const client = new LangfuseClient();\n * ```\n */\n constructor(params?: LangfuseClientParams) {\n const logger = getGlobalLogger();\n\n const publicKey = params?.publicKey ?? getEnv(\"LANGFUSE_PUBLIC_KEY\");\n const secretKey = params?.secretKey ?? getEnv(\"LANGFUSE_SECRET_KEY\");\n this.baseUrl =\n params?.baseUrl ??\n getEnv(\"LANGFUSE_BASE_URL\") ??\n getEnv(\"LANGFUSE_BASEURL\") ?? // legacy v2\n \"https://cloud.langfuse.com\";\n\n if (!publicKey) {\n logger.warn(\n \"No public key provided in constructor or as LANGFUSE_PUBLIC_KEY env var. Client operations will fail.\",\n );\n }\n if (!secretKey) {\n logger.warn(\n \"No secret key provided in constructor or as LANGFUSE_SECRET_KEY env var. Client operations will fail.\",\n );\n }\n const timeoutSeconds =\n params?.timeout ?? Number(getEnv(\"LANGFUSE_TIMEOUT\") ?? 5);\n\n this.api = new LangfuseAPIClient({\n baseUrl: this.baseUrl,\n username: publicKey,\n password: secretKey,\n xLangfusePublicKey: publicKey,\n xLangfuseSdkVersion: LANGFUSE_SDK_VERSION,\n xLangfuseSdkName: \"javascript\",\n environment: \"\", // noop as baseUrl is set\n headers: params?.additionalHeaders,\n });\n\n logger.debug(\"Initialized LangfuseClient with params:\", {\n publicKey,\n baseUrl: this.baseUrl,\n timeoutSeconds,\n });\n\n this.prompt = new PromptManager({ apiClient: this.api });\n this.dataset = new DatasetManager({ apiClient: this.api });\n this.score = new ScoreManager({ apiClient: this.api });\n this.media = new MediaManager({ apiClient: this.api });\n\n // Keep v3 compat by exposing old interface\n this.getPrompt = this.prompt.get.bind(this.prompt); // keep correct this context for cache access\n this.createPrompt = this.prompt.create.bind(this.prompt);\n this.updatePrompt = this.prompt.update.bind(this.prompt);\n this.getDataset = this.dataset.get;\n this.fetchTrace = this.api.trace.get;\n this.fetchTraces = this.api.trace.list;\n this.fetchObservation = this.api.observations.get;\n this.fetchObservations = this.api.observations.getMany;\n this.fetchSessions = this.api.sessions.get;\n this.getDatasetRun = this.api.datasets.getRun;\n this.getDatasetRuns = this.api.datasets.getRuns;\n this.createDataset = this.api.datasets.create;\n this.getDatasetItem = this.api.datasetItems.get;\n this.createDatasetItem = this.api.datasetItems.create;\n this.fetchMedia = this.api.media.get;\n this.resolveMediaReferences = this.media.resolveReferences;\n }\n\n /**\n * Flushes any pending score events to the Langfuse API.\n *\n * This method ensures all queued scores are sent immediately rather than\n * waiting for the automatic flush interval or batch size threshold.\n *\n * @returns Promise that resolves when all pending scores have been sent\n *\n * @example\n * ```typescript\n * langfuse.score.create({ name: \"quality\", value: 0.8 });\n * await langfuse.flush(); // Ensures the score is sent immediately\n * ```\n */\n public async flush() {\n return this.score.flush();\n }\n\n /**\n * Gracefully shuts down the client by flushing all pending data.\n *\n * This method should be called before your application exits to ensure\n * all data is sent to Langfuse.\n *\n * @returns Promise that resolves when shutdown is complete\n *\n * @example\n * ```typescript\n * // Before application exit\n * await langfuse.shutdown();\n * ```\n */\n public async shutdown() {\n return this.score.shutdown();\n }\n\n /**\n * Generates a URL to view a specific trace in the Langfuse UI.\n *\n * @param traceId - The ID of the trace to generate a URL for\n * @returns Promise that resolves to the trace URL\n *\n * @example\n * ```typescript\n * const traceId = \"trace-123\";\n * const url = await langfuse.getTraceUrl(traceId);\n * console.log(`View trace at: ${url}`);\n * ```\n */\n public async getTraceUrl(traceId: string) {\n let projectId = this.projectId;\n\n if (!projectId) {\n projectId = (await this.api.projects.get()).data[0].id;\n this.projectId = projectId;\n }\n\n const traceUrl = `${this.baseUrl}/project/${projectId}/traces/${traceId}`;\n\n return traceUrl;\n }\n}\n","import {\n LangfuseAPIClient,\n Dataset,\n DatasetRunItem,\n DatasetItem,\n} from \"@langfuse/core\";\nimport { Span } from \"@opentelemetry/api\";\n\n/**\n * Function type for linking dataset items to OpenTelemetry spans.\n * This allows dataset items to be associated with specific traces for experiment tracking.\n *\n * @param obj - Object containing the OpenTelemetry span\n * @param runName - Name of the dataset run\n * @param runArgs - Optional arguments for the dataset run\n * @returns Promise that resolves to the created dataset run item\n *\n * @public\n */\nexport type LinkDatasetItemFunction = (\n obj: { otelSpan: Span },\n runName: string,\n runArgs?: {\n /** Description of the dataset run */\n description?: string;\n /** Additional metadata for the dataset run */\n metadata?: any;\n },\n) => Promise<DatasetRunItem>;\n\n/**\n * Manager for dataset operations in Langfuse.\n *\n * Provides methods to retrieve datasets and their items, with automatic\n * pagination handling and convenient linking functionality for experiments.\n *\n * @public\n */\nexport class DatasetManager {\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new DatasetManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n }\n\n /**\n * Retrieves a dataset by name along with all its items.\n *\n * This method automatically handles pagination to fetch all dataset items\n * and enhances each item with a `link` function for easy experiment tracking.\n *\n * @param name - The name of the dataset to retrieve\n * @param options - Optional configuration for fetching\n * @param options.fetchItemsPageSize - Number of items to fetch per page (default: 50)\n *\n * @returns Promise that resolves to the dataset with enhanced items\n *\n * @example\n * ```typescript\n * const dataset = await langfuse.dataset.get(\"my-dataset\");\n *\n * for (const item of dataset.items) {\n * // Use the item data for your experiment\n * const result = await processItem(item.input);\n *\n * // Link the result to the dataset item\n * await item.link(\n * { otelSpan: currentSpan },\n * \"experiment-run-1\",\n * { description: \"Testing new model\" }\n * );\n * }\n * ```\n */\n async get(\n name: string,\n options?: {\n fetchItemsPageSize: number;\n },\n ): Promise<\n Dataset & {\n items: (DatasetItem & { link: LinkDatasetItemFunction })[];\n }\n > {\n const dataset = await this.apiClient.datasets.get(name);\n const items: DatasetItem[] = [];\n\n let page = 1;\n\n while (true) {\n const itemsResponse = await this.apiClient.datasetItems.list({\n datasetName: name,\n limit: options?.fetchItemsPageSize ?? 50,\n page,\n });\n\n items.push(...itemsResponse.data);\n\n if (itemsResponse.meta.totalPages <= page) {\n break;\n }\n\n page++;\n }\n\n const returnDataset = {\n ...dataset,\n items: items.map((item) => ({\n ...item,\n link: this.createDatasetItemLinkFunction(item),\n })),\n };\n\n return returnDataset;\n }\n\n /**\n * Creates a link function for a specific dataset item.\n *\n * @param item - The dataset item to create a link function for\n * @returns A function that can link the item to OpenTelemetry spans\n * @internal\n */\n private createDatasetItemLinkFunction(\n item: DatasetItem,\n ): LinkDatasetItemFunction {\n const linkFunction = async (\n obj: { otelSpan: Span },\n runName: string,\n runArgs?: {\n description?: string;\n metadata?: any;\n },\n ): Promise<DatasetRunItem> => {\n return await this.apiClient.datasetRunItems.create({\n runName,\n datasetItemId: item.id,\n traceId: obj.otelSpan.spanContext().traceId,\n runDescription: runArgs?.description,\n metadata: runArgs?.metadata,\n });\n };\n\n return linkFunction;\n }\n}\n","import {\n LangfuseAPIClient,\n ParsedMediaReference,\n MediaContentType,\n getGlobalLogger,\n uint8ArrayToBase64,\n} from \"@langfuse/core\";\n\n/**\n * Parameters for resolving media references in objects.\n *\n * @template T - The type of the object being processed\n * @public\n */\nexport type LangfuseMediaResolveMediaReferencesParams<T> = {\n /** The object to process for media references */\n obj: T;\n /** The format to resolve media references to (currently only \"base64DataUri\" is supported) */\n resolveWith: \"base64DataUri\";\n /** Maximum depth to traverse when processing nested objects (default: 10) */\n maxDepth?: number;\n};\n\n/**\n * Manager for media operations in Langfuse.\n *\n * Provides methods to resolve media references in objects by replacing\n * them with actual media content (e.g., base64 data URIs).\n *\n * @public\n */\nexport class MediaManager {\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new MediaManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n }\n\n /**\n * Replaces media reference strings in an object with base64 data URIs.\n *\n * This method recursively traverses an object looking for media reference strings\n * in the format \"@@@langfuseMedia:...@@@\". When found, it fetches the actual media\n * content from Langfuse and replaces the reference string with a base64 data URI.\n *\n * If fetching media content fails for a reference string, a warning is logged\n * and the reference string is left unchanged.\n *\n * @param params - Configuration object\n * @returns A deep copy of the input object with media references resolved\n *\n * @example\n * ```typescript\n * const obj = {\n * image: \"@@@langfuseMedia:type=image/jpeg|id=123|source=bytes@@@\",\n * nested: {\n * pdf: \"@@@langfuseMedia:type=application/pdf|id=456|source=bytes@@@\"\n * }\n * };\n *\n * const result = await langfuse.media.resolveReferences({\n * obj,\n * resolveWith: \"base64DataUri\"\n * });\n *\n * // Result:\n * // {\n * // image: \"data:image/jpeg;base64,/9j/4AAQSkZJRg...\",\n * // nested: {\n * // pdf: \"data:application/pdf;base64,JVBERi0xLjcK...\"\n * // }\n * // }\n * ```\n */\n public async resolveReferences<T>(\n params: LangfuseMediaResolveMediaReferencesParams<T>,\n ): Promise<T> {\n const { obj, maxDepth = 10 } = params;\n\n const traverse = async <T>(obj: T, depth: number): Promise<T> => {\n if (depth > maxDepth) {\n return obj;\n }\n\n // Handle string with potential media references\n if (typeof obj === \"string\") {\n const regex = /@@@langfuseMedia:.+?@@@/g;\n const referenceStringMatches = obj.match(regex);\n if (!referenceStringMatches) {\n return obj;\n }\n\n let result = obj;\n const referenceStringToMediaContentMap = new Map<string, string>();\n\n await Promise.all(\n referenceStringMatches.map(async (referenceString) => {\n try {\n const parsedMediaReference =\n MediaManager.parseReferenceString(referenceString);\n const mediaData = await this.apiClient.media.get(\n parsedMediaReference.mediaId,\n );\n const mediaContent = await fetch(mediaData.url, {\n method: \"GET\",\n headers: {},\n });\n if (mediaContent.status !== 200) {\n throw new Error(\"Failed to fetch media content\");\n }\n\n const uint8Content = new Uint8Array(\n await mediaContent.arrayBuffer(),\n );\n\n const base64MediaContent = uint8ArrayToBase64(uint8Content);\n const base64DataUri = `data:${mediaData.contentType};base64,${base64MediaContent}`;\n\n referenceStringToMediaContentMap.set(\n referenceString,\n base64DataUri,\n );\n } catch (error) {\n getGlobalLogger().warn(\n \"Error fetching media content for reference string\",\n referenceString,\n error,\n );\n }\n }),\n );\n\n for (const [\n referenceString,\n base64MediaContent,\n ] of referenceStringToMediaContentMap.entries()) {\n result = result.replaceAll(referenceString, base64MediaContent) as T &\n string;\n }\n\n return result;\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return Promise.all(\n obj.map(async (item) => await traverse(item, depth + 1)),\n ) as Promise<T>;\n }\n\n // Handle objects\n if (typeof obj === \"object\" && obj !== null) {\n return Object.fromEntries(\n await Promise.all(\n Object.entries(obj).map(async ([key, value]) => [\n key,\n await traverse(value, depth + 1),\n ]),\n ),\n );\n }\n\n return obj;\n };\n\n return traverse(obj, 0);\n }\n\n /**\n * Parses a media reference string into a ParsedMediaReference.\n *\n * Example reference string:\n * \"@@@langfuseMedia:type=image/jpeg|id=some-uuid|source=base64DataUri@@@\"\n *\n * @param referenceString - The reference string to parse.\n * @returns An object with the mediaId, source, and contentType.\n *\n * @throws Error if the reference string is invalid or missing required fields.\n */\n public static parseReferenceString(\n referenceString: string,\n ): ParsedMediaReference {\n const prefix = \"@@@langfuseMedia:\";\n const suffix = \"@@@\";\n\n if (!referenceString.startsWith(prefix)) {\n throw new Error(\n \"Reference string does not start with '@@@langfuseMedia:type='\",\n );\n }\n\n if (!referenceString.endsWith(suffix)) {\n throw new Error(\"Reference string does not end with '@@@'\");\n }\n\n const content = referenceString.slice(prefix.length, -suffix.length);\n\n const pairs = content.split(\"|\");\n const parsedData: { [key: string]: string } = {};\n\n for (const pair of pairs) {\n const [key, value] = pair.split(\"=\", 2);\n parsedData[key] = value;\n }\n\n if (\n !(\"type\" in parsedData && \"id\" in parsedData && \"source\" in parsedData)\n ) {\n throw new Error(\"Missing required fields in reference string\");\n }\n\n return {\n mediaId: parsedData[\"id\"],\n source: parsedData[\"source\"],\n contentType: parsedData[\"type\"] as MediaContentType,\n };\n }\n}\n","import {\n CreatePromptRequest,\n getGlobalLogger,\n LangfuseAPIClient,\n PlaceholderMessage,\n Prompt,\n ChatMessage,\n} from \"@langfuse/core\";\n\nimport { LangfusePromptCache } from \"./promptCache.js\";\nimport {\n ChatPromptClient,\n TextPromptClient,\n LangfusePromptClient,\n} from \"./promptClients.js\";\nimport {\n ChatMessageType,\n CreateChatPromptBodyWithPlaceholders,\n} from \"./types.js\";\n\n/**\n * Manager for prompt operations in Langfuse.\n *\n * Provides methods to create, retrieve, and manage prompts with built-in caching\n * for optimal performance. Supports both text and chat prompts with variable\n * substitution and placeholder functionality.\n *\n * @public\n */\nexport class PromptManager {\n private cache: LangfusePromptCache;\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new PromptManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n const { apiClient } = params;\n\n this.apiClient = apiClient;\n this.cache = new LangfusePromptCache();\n }\n\n get logger() {\n return getGlobalLogger();\n }\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (chat prompt)\n * @returns Promise that resolves to a ChatPromptClient\n */\n async create(\n body: CreateChatPromptBodyWithPlaceholders,\n ): Promise<ChatPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (text prompt)\n * @returns Promise that resolves to a TextPromptClient\n */\n async create(\n body: Omit<CreatePromptRequest.Text, \"type\"> & { type?: \"text\" },\n ): Promise<TextPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (chat prompt)\n * @returns Promise that resolves to a ChatPromptClient\n */\n async create(body: CreatePromptRequest.Chat): Promise<ChatPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * Supports both text and chat prompts. Chat prompts can include placeholders\n * for dynamic content insertion.\n *\n * @param body - The prompt data to create\n * @returns Promise that resolves to the appropriate prompt client\n *\n * @example\n * ```typescript\n * // Create a text prompt\n * const textPrompt = await langfuse.prompt.create({\n * name: \"greeting\",\n * prompt: \"Hello {{name}}!\",\n * type: \"text\"\n * });\n *\n * // Create a chat prompt\n * const chatPrompt = await langfuse.prompt.create({\n * name: \"conversation\",\n * type: \"chat\",\n * prompt: [\n * { role: \"system\", content: \"You are a helpful assistant.\" },\n * { role: \"user\", content: \"{{user_message}}\" }\n * ]\n * });\n * ```\n */\n async create(\n body:\n | CreatePromptRequest.Chat\n | (Omit<CreatePromptRequest.Text, \"type\"> & { type?: \"text\" })\n | CreateChatPromptBodyWithPlaceholders,\n ): Promise<LangfusePromptClient> {\n const requestBody: CreatePromptRequest =\n body.type === \"chat\"\n ? {\n ...body,\n prompt: body.prompt.map((item) => {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n return {\n type: ChatMessageType.Placeholder,\n name: (item as PlaceholderMessage).name,\n };\n } else {\n // Handle regular ChatMessage (without type field) from API\n return { type: ChatMessageType.ChatMessage, ...item };\n }\n }),\n }\n : {\n ...body,\n type: body.type ?? \"text\",\n };\n\n const promptResponse = await this.apiClient.prompts.create(requestBody);\n\n if (promptResponse.type === \"chat\") {\n return new ChatPromptClient(promptResponse);\n }\n\n return new TextPromptClient(promptResponse);\n }\n\n /**\n * Updates the labels of an existing prompt version.\n *\n * @param params - Update parameters\n * @param params.name - Name of the prompt to update\n * @param params.version - Version number of the prompt to update\n * @param params.newLabels - New labels to apply to the prompt version\n *\n * @returns Promise that resolves to the updated prompt\n *\n * @example\n * ```typescript\n * const updatedPrompt = await langfuse.prompt.update({\n * name: \"my-prompt\",\n * version: 1,\n * newLabels: [\"production\", \"v2\"]\n * });\n * ```\n */\n async update(params: {\n name: string;\n version: number;\n newLabels: string[];\n }): Promise<Prompt> {\n const { name, version, newLabels } = params;\n\n const newPrompt = await this.apiClient.promptVersion.update(name, version, {\n newLabels,\n });\n\n this.cache.invalidate(name);\n\n return newPrompt;\n }\n\n /**\n * Retrieves a text prompt by name.\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to a TextPromptClient\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback text content if prompt fetch fails */\n fallback?: string;\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Specify text prompt type */\n type?: \"text\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<TextPromptClient>;\n\n /**\n * Retrieves a chat prompt by name.\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to a ChatPromptClient\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback chat messages if prompt fetch fails */\n fallback?: ChatMessage[];\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Specify chat prompt type */\n type: \"chat\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<ChatPromptClient>;\n\n /**\n * Retrieves a prompt by name with intelligent caching.\n *\n * This method implements sophisticated caching behavior:\n * - Fresh prompts are returned immediately from cache\n * - Expired prompts are returned from cache while being refreshed in background\n * - Cache misses trigger immediate fetch with optional fallback support\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to the appropriate prompt client\n *\n * @example\n * ```typescript\n * // Get latest version with caching\n * const prompt = await langfuse.prompt.get(\"my-prompt\");\n *\n * // Get specific version\n * const v2Prompt = await langfuse.prompt.get(\"my-prompt\", {\n * version: 2\n * });\n *\n * // Get with label filter\n * const prodPrompt = await langfuse.prompt.get(\"my-prompt\", {\n * label: \"production\"\n * });\n *\n * // Get with fallback\n * const promptWithFallback = await langfuse.prompt.get(\"my-prompt\", {\n * type: \"text\",\n * fallback: \"Hello {{name}}!\"\n * });\n * ```\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback content if prompt fetch fails */\n fallback?: ChatMessage[] | string;\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Prompt type (auto-detected if not specified) */\n type?: \"chat\" | \"text\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<LangfusePromptClient> {\n const cacheKey = this.cache.createKey({\n name,\n label: options?.label,\n });\n const cachedPrompt = this.cache.getIncludingExpired(cacheKey);\n if (!cachedPrompt || options?.cacheTtlSeconds === 0) {\n try {\n return await this.fetchPromptAndUpdateCache({\n name,\n version: options?.version,\n label: options?.label,\n cacheTtlSeconds: options?.cacheTtlSeconds,\n maxRetries: options?.maxRetries,\n fetchTimeoutMs: options?.fetchTimeoutMs,\n });\n } catch (err) {\n if (options?.fallback) {\n const sharedFallbackParams = {\n name,\n version: options?.version ?? 0,\n labels: options.label ? [options.label] : [],\n cacheTtlSeconds: options?.cacheTtlSeconds,\n config: {},\n tags: [],\n };\n\n if (options.type === \"chat\") {\n return new ChatPromptClient(\n {\n ...sharedFallbackParams,\n type: \"chat\",\n prompt: (options.fallback as ChatMessage[]).map((msg) => ({\n type: ChatMessageType.ChatMessage,\n ...msg,\n })),\n },\n true,\n );\n } else {\n return new TextPromptClient(\n {\n ...sharedFallbackParams,\n type: \"text\",\n prompt: options.fallback as string,\n },\n true,\n );\n }\n }\n\n throw err;\n }\n }\n\n if (cachedPrompt.isExpired) {\n // If the cache is not currently being refreshed, start refreshing it and register the promise in the cache\n if (!this.cache.isRefreshing(cacheKey)) {\n const refreshPromptPromise = this.fetchPromptAndUpdateCache({\n name,\n version: options?.version,\n label: options?.label,\n cacheTtlSeconds: options?.cacheTtlSeconds,\n maxRetries: options?.maxRetries,\n fetchTimeoutMs: options?.fetchTimeoutMs,\n }).catch(() => {\n this.logger.warn(\n `Failed to refresh prompt cache '${cacheKey}', stale cache will be used until next refresh succeeds.`,\n );\n });\n this.cache.addRefreshingPromise(cacheKey, refreshPromptPromise);\n }\n\n return cachedPrompt.value;\n }\n\n return cachedPrompt.value;\n }\n\n private async fetchPromptAndUpdateCache(params: {\n name: string;\n version?: number;\n cacheTtlSeconds?: number;\n label?: string;\n maxRetries?: number;\n fetchTimeoutMs?: number;\n }): Promise<LangfusePromptClient> {\n const cacheKey = this.cache.createKey(params);\n\n try {\n const {\n name,\n version,\n cacheTtlSeconds,\n label,\n maxRetries,\n fetchTimeoutMs,\n } = params;\n\n const data = await this.apiClient.prompts.get(\n name,\n {\n version,\n label,\n },\n {\n maxRetries,\n timeoutInSeconds: fetchTimeoutMs ? fetchTimeoutMs / 1_000 : undefined,\n },\n );\n\n let prompt: LangfusePromptClient;\n if (data.type === \"chat\") {\n prompt = new ChatPromptClient(data);\n } else {\n prompt = new TextPromptClient(data);\n }\n\n this.cache.set(cacheKey, prompt, cacheTtlSeconds);\n\n return prompt;\n } catch (error) {\n this.logger.error(`Error fetching prompt '${cacheKey}':`, error);\n\n throw error;\n }\n }\n}\n","import { getGlobalLogger } from \"@langfuse/core\";\n\nimport type { LangfusePromptClient } from \"./promptClients.js\";\n\nexport const DEFAULT_PROMPT_CACHE_TTL_SECONDS = 60;\n\nclass LangfusePromptCacheItem {\n private _expiry: number;\n\n constructor(\n public value: LangfusePromptClient,\n ttlSeconds: number,\n ) {\n this._expiry = Date.now() + ttlSeconds * 1000;\n }\n\n get isExpired(): boolean {\n return Date.now() > this._expiry;\n }\n}\nexport class LangfusePromptCache {\n private _cache: Map<string, LangfusePromptCacheItem>;\n private _defaultTtlSeconds: number;\n private _refreshingKeys: Map<string, Promise<void>>;\n\n constructor() {\n this._cache = new Map<string, LangfusePromptCacheItem>();\n this._defaultTtlSeconds = DEFAULT_PROMPT_CACHE_TTL_SECONDS;\n this._refreshingKeys = new Map<string, Promise<void>>();\n }\n\n public getIncludingExpired(key: string): LangfusePromptCacheItem | null {\n return this._cache.get(key) ?? null;\n }\n\n public createKey(params: {\n name: string;\n version?: number;\n label?: string;\n }): string {\n const { name, version, label } = params;\n const parts = [name];\n\n if (version !== undefined) {\n parts.push(\"version:\" + version.toString());\n } else if (label !== undefined) {\n parts.push(\"label:\" + label);\n } else {\n parts.push(\"label:production\");\n }\n\n return parts.join(\"-\");\n }\n\n public set(\n key: string,\n value: LangfusePromptClient,\n ttlSeconds?: number,\n ): void {\n const effectiveTtlSeconds = ttlSeconds ?? this._defaultTtlSeconds;\n this._cache.set(\n key,\n new LangfusePromptCacheItem(value, effectiveTtlSeconds),\n );\n }\n\n public addRefreshingPromise(key: string, promise: Promise<any>): void {\n this._refreshingKeys.set(key, promise);\n promise\n .then(() => {\n this._refreshingKeys.delete(key);\n })\n .catch(() => {\n this._refreshingKeys.delete(key);\n });\n }\n\n public isRefreshing(key: string): boolean {\n return this._refreshingKeys.has(key);\n }\n\n public invalidate(promptName: string): void {\n getGlobalLogger().debug(\n \"Invalidating cache keys for\",\n promptName,\n this._cache.keys(),\n );\n\n for (const key of this._cache.keys()) {\n if (key.startsWith(promptName)) {\n this._cache.delete(key);\n }\n }\n }\n}\n","import {\n Prompt,\n ChatMessage,\n BasePrompt,\n ChatMessageWithPlaceholders,\n} from \"@langfuse/core\";\nimport mustache from \"mustache\";\n\nimport {\n ChatMessageOrPlaceholder,\n ChatMessageType,\n LangchainMessagesPlaceholder,\n} from \"./types.js\";\n\nmustache.escape = function (text) {\n return text;\n};\n\n/**\n * Base class for all prompt clients.\n *\n * @internal\n */\nabstract class BasePromptClient {\n /** The name of the prompt */\n public readonly name: string;\n /** The version number of the prompt */\n public readonly version: number;\n /** Configuration object associated with the prompt */\n public readonly config: unknown;\n /** Labels associated with the prompt */\n public readonly labels: string[];\n /** Tags associated with the prompt */\n public readonly tags: string[];\n /** Whether this prompt client is using fallback content */\n public readonly isFallback: boolean;\n /** The type of prompt (\"text\" or \"chat\") */\n public readonly type: \"text\" | \"chat\";\n /** Optional commit message for the prompt version */\n public readonly commitMessage: string | null | undefined;\n\n /**\n * Creates a new BasePromptClient instance.\n *\n * @param prompt - The base prompt data\n * @param isFallback - Whether this is fallback content\n * @param type - The prompt type\n * @internal\n */\n constructor(prompt: BasePrompt, isFallback = false, type: \"text\" | \"chat\") {\n this.name = prompt.name;\n this.version = prompt.version;\n this.config = prompt.config;\n this.labels = prompt.labels;\n this.tags = prompt.tags;\n this.isFallback = isFallback;\n this.type = type;\n this.commitMessage = prompt.commitMessage;\n }\n\n /** Gets the raw prompt content */\n abstract get prompt(): string | ChatMessageWithPlaceholders[];\n\n /** Sets the raw prompt content */\n abstract set prompt(value: string | ChatMessageWithPlaceholders[]);\n\n /**\n * Compiles the prompt by substituting variables and resolving placeholders.\n *\n * @param variables - Key-value pairs for variable substitution\n * @param placeholders - Key-value pairs for placeholder resolution\n * @returns The compiled prompt content\n */\n abstract compile(\n variables?: Record<string, string>,\n placeholders?: Record<string, any>,\n ): string | ChatMessage[] | (ChatMessageOrPlaceholder | any)[];\n\n /**\n * Converts the prompt to a format compatible with LangChain.\n *\n * @param options - Options for conversion\n * @param options.placeholders - Placeholders to resolve during conversion\n * @returns The prompt in LangChain-compatible format\n */\n public abstract getLangchainPrompt(options?: {\n placeholders?: Record<string, any>;\n }):\n | string\n | ChatMessage[]\n | ChatMessageOrPlaceholder[]\n | (ChatMessage | LangchainMessagesPlaceholder | any)[];\n\n protected _transformToLangchainVariables(content: string): string {\n const jsonEscapedContent = this.escapeJsonForLangchain(content);\n\n return jsonEscapedContent.replace(/\\{\\{(\\w+)\\}\\}/g, \"{$1}\");\n }\n\n /**\n * Escapes every curly brace that is part of a JSON object by doubling it.\n *\n * A curly brace is considered “JSON-related” when, after skipping any immediate\n * whitespace, the next non-whitespace character is a single (') or double (\") quote.\n *\n * Braces that are already doubled (e.g. `{{variable}}` placeholders) are left untouched.\n *\n * @param text - Input string that may contain JSON snippets.\n * @returns The string with JSON-related braces doubled.\n */\n protected escapeJsonForLangchain(text: string): string {\n const out: string[] = []; // collected characters\n const stack: boolean[] = []; // true = “this { belongs to JSON”, false = normal “{”\n let i = 0;\n const n = text.length;\n\n while (i < n) {\n const ch = text[i];\n\n // ---------- opening brace ----------\n if (ch === \"{\") {\n // leave existing “{{ …” untouched\n if (i + 1 < n && text[i + 1] === \"{\") {\n out.push(\"{{\");\n i += 2;\n continue;\n }\n\n // look ahead to find the next non-space character\n let j = i + 1;\n while (j < n && /\\s/.test(text[j])) {\n j++;\n }\n\n const isJson = j < n && (text[j] === \"'\" || text[j] === '\"');\n out.push(isJson ? \"{{\" : \"{\");\n stack.push(isJson); // remember how this “{” was treated\n i += 1;\n continue;\n }\n\n // ---------- closing brace ----------\n if (ch === \"}\") {\n // leave existing “… }}” untouched\n if (i + 1 < n && text[i + 1] === \"}\") {\n out.push(\"}}\");\n i += 2;\n continue;\n }\n\n const isJson = stack.pop() ?? false;\n out.push(isJson ? \"}}\" : \"}\");\n i += 1;\n continue;\n }\n\n // ---------- any other character ----------\n out.push(ch);\n i += 1;\n }\n\n return out.join(\"\");\n }\n\n /**\n * Serializes the prompt client to JSON.\n *\n * @returns JSON string representation of the prompt\n */\n public abstract toJSON(): string;\n}\n\n/**\n * Client for working with text-based prompts.\n *\n * Provides methods to compile text prompts with variable substitution\n * and convert them to LangChain-compatible formats.\n *\n * @public\n */\nexport class TextPromptClient extends BasePromptClient {\n /** The original prompt response from the API */\n public readonly promptResponse: Prompt.Text;\n /** The text content of the prompt */\n public readonly prompt: string;\n\n /**\n * Creates a new TextPromptClient instance.\n *\n * @param prompt - The text prompt data\n * @param isFallback - Whether this is fallback content\n */\n constructor(prompt: Prompt.Text, isFallback = false) {\n super(prompt, isFallback, \"text\");\n this.promptResponse = prompt;\n this.prompt = prompt.prompt;\n }\n\n /**\n * Compiles the text prompt by substituting variables.\n *\n * Uses Mustache templating to replace {{variable}} placeholders with provided values.\n *\n * @param variables - Key-value pairs for variable substitution\n * @param _placeholders - Ignored for text prompts\n * @returns The compiled text with variables substituted\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"greeting\", { type: \"text\" });\n * const compiled = prompt.compile({ name: \"Alice\" });\n * // If prompt is \"Hello {{name}}!\", result is \"Hello Alice!\"\n * ```\n */\n compile(\n variables?: Record<string, string>,\n _placeholders?: Record<string, any>,\n ): string {\n return mustache.render(this.promptResponse.prompt, variables ?? {});\n }\n\n /**\n * Converts the prompt to LangChain PromptTemplate format.\n *\n * Transforms Mustache-style {{variable}} syntax to LangChain's {variable} format.\n *\n * @param _options - Ignored for text prompts\n * @returns The prompt string compatible with LangChain PromptTemplate\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"greeting\", { type: \"text\" });\n * const langchainFormat = prompt.getLangchainPrompt();\n * // Transforms \"Hello {{name}}!\" to \"Hello {name}!\"\n * ```\n */\n public getLangchainPrompt(_options?: {\n placeholders?: Record<string, any>;\n }): string {\n return this._transformToLangchainVariables(this.prompt);\n }\n\n public toJSON(): string {\n return JSON.stringify({\n name: this.name,\n prompt: this.prompt,\n version: this.version,\n isFallback: this.isFallback,\n tags: this.tags,\n labels: this.labels,\n type: this.type,\n config: this.config,\n });\n }\n}\n\n/**\n * Client for working with chat-based prompts.\n *\n * Provides methods to compile chat prompts with variable substitution and\n * placeholder resolution, and convert them to LangChain-compatible formats.\n *\n * @public\n */\nexport class ChatPromptClient extends BasePromptClient {\n /** The original prompt response from the API */\n public readonly promptResponse: Prompt.Chat;\n /** The chat messages that make up the prompt */\n public readonly prompt: ChatMessageWithPlaceholders[];\n\n /**\n * Creates a new ChatPromptClient instance.\n *\n * @param prompt - The chat prompt data\n * @param isFallback - Whether this is fallback content\n */\n constructor(prompt: Prompt.Chat, isFallback = false) {\n const normalizedPrompt = ChatPromptClient.normalizePrompt(prompt.prompt);\n const typedPrompt: Prompt.Chat = {\n ...prompt,\n prompt: normalizedPrompt,\n };\n\n super(typedPrompt, isFallback, \"chat\");\n this.promptResponse = typedPrompt;\n this.prompt = normalizedPrompt;\n }\n\n private static normalizePrompt(\n prompt: ChatMessage[] | ChatMessageWithPlaceholders[],\n ): ChatMessageWithPlaceholders[] {\n // Convert ChatMessages to ChatMessageWithPlaceholders for backward compatibility\n return prompt.map((item): ChatMessageWithPlaceholders => {\n if (\"type\" in item) {\n // Already has type field (new format)\n return item as ChatMessageWithPlaceholders;\n } else {\n // Plain ChatMessage (legacy format) - add type field\n return {\n type: ChatMessageType.ChatMessage,\n ...item,\n } as ChatMessageWithPlaceholders;\n }\n });\n }\n\n /**\n * Compiles the chat prompt by replacing placeholders and variables.\n *\n * First resolves placeholders with provided values, then applies variable substitution\n * to message content using Mustache templating. Unresolved placeholders remain\n * as placeholder objects in the output.\n *\n * @param variables - Key-value pairs for Mustache variable substitution in message content\n * @param placeholders - Key-value pairs where keys are placeholder names and values are ChatMessage arrays\n * @returns Array of ChatMessage objects and unresolved placeholder objects\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"conversation\", { type: \"chat\" });\n * const compiled = prompt.compile(\n * { user_name: \"Alice\" },\n * { examples: [{ role: \"user\", content: \"Hello\" }, { role: \"assistant\", content: \"Hi!\" }] }\n * );\n * ```\n */\n compile(\n variables?: Record<string, string>,\n placeholders?: Record<string, any>,\n ): (ChatMessageOrPlaceholder | any)[] {\n const messagesWithPlaceholdersReplaced: (ChatMessageOrPlaceholder | any)[] =\n [];\n const placeholderValues = placeholders ?? {};\n\n for (const item of this.prompt) {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n const placeholderValue = placeholderValues[item.name];\n if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length > 0 &&\n placeholderValue.every(\n (msg) =>\n typeof msg === \"object\" && \"role\" in msg && \"content\" in msg,\n )\n ) {\n messagesWithPlaceholdersReplaced.push(\n ...(placeholderValue as ChatMessage[]),\n );\n } else if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length === 0\n ) {\n // Empty array provided - skip placeholder (don't include it)\n } else if (placeholderValue !== undefined) {\n // Non-standard placeholder value format, just stringfiy\n messagesWithPlaceholdersReplaced.push(\n JSON.stringify(placeholderValue),\n );\n } else {\n // Keep unresolved placeholder in the output\n messagesWithPlaceholdersReplaced.push(\n item as { type: ChatMessageType.Placeholder } & typeof item,\n );\n }\n } else if (\n \"role\" in item &&\n \"content\" in item &&\n item.type === ChatMessageType.ChatMessage\n ) {\n messagesWithPlaceholdersReplaced.push({\n role: item.role,\n content: item.content,\n });\n }\n }\n\n return messagesWithPlaceholdersReplaced.map((item) => {\n if (\n typeof item === \"object\" &&\n item !== null &&\n \"role\" in item &&\n \"content\" in item\n ) {\n return {\n ...item,\n content: mustache.render(item.content, variables ?? {}),\n };\n } else {\n // Return placeholder or stringified value as-is\n return item;\n }\n });\n }\n\n /**\n * Converts the prompt to LangChain ChatPromptTemplate format.\n *\n * Resolves placeholders with provided values and converts unresolved ones\n * to LangChain MessagesPlaceholder objects. Transforms variables from\n * {{var}} to {var} format without rendering them.\n *\n * @param options - Configuration object\n * @param options.placeholders - Key-value pairs for placeholder resolution\n * @returns Array of ChatMessage objects and LangChain MessagesPlaceholder objects\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"conversation\", { type: \"chat\" });\n * const langchainFormat = prompt.getLangchainPrompt({\n * placeholders: { examples: [{ role: \"user\", content: \"Hello\" }] }\n * });\n * ```\n */\n public getLangchainPrompt(options?: {\n placeholders?: Record<string, any>;\n }): (ChatMessage | LangchainMessagesPlaceholder | any)[] {\n const messagesWithPlaceholdersReplaced: (\n | ChatMessage\n | LangchainMessagesPlaceholder\n | any\n )[] = [];\n const placeholderValues = options?.placeholders ?? {};\n\n for (const item of this.prompt) {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n const placeholderValue = placeholderValues[item.name];\n if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length > 0 &&\n placeholderValue.every(\n (msg) =>\n typeof msg === \"object\" && \"role\" in msg && \"content\" in msg,\n )\n ) {\n // Complete placeholder fill-in, replace with it\n messagesWithPlaceholdersReplaced.push(\n ...(placeholderValue as ChatMessage[]).map((msg) => {\n return {\n role: msg.role,\n content: this._transformToLangchainVariables(msg.content),\n };\n }),\n );\n } else if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length === 0\n ) {\n // Skip empty array placeholder\n } else if (placeholderValue !== undefined) {\n // Non-standard placeholder value, just stringify and add directly\n messagesWithPlaceholdersReplaced.push(\n JSON.stringify(placeholderValue),\n );\n } else {\n // Convert unresolved placeholder to Langchain MessagesPlaceholder\n messagesWithPlaceholdersReplaced.push({\n variableName: item.name,\n optional: false,\n });\n }\n } else if (\n \"role\" in item &&\n \"content\" in item &&\n item.type === ChatMessageType.ChatMessage\n ) {\n messagesWithPlaceholdersReplaced.push({\n role: item.role,\n content: this._transformToLangchainVariables(item.content),\n });\n }\n }\n\n return messagesWithPlaceholdersReplaced;\n }\n\n public toJSON(): string {\n return JSON.stringify({\n name: this.name,\n prompt: this.promptResponse.prompt.map((item) => {\n if (\"type\" in item && item.type === ChatMessageType.ChatMessage) {\n const { type: _, ...messageWithoutType } = item;\n return messageWithoutType;\n }\n return item;\n }),\n version: this.version,\n isFallback: this.isFallback,\n tags: this.tags,\n labels: this.labels,\n type: this.type,\n config: this.config,\n });\n }\n}\n\n/**\n * Union type representing either a text or chat prompt client.\n *\n * @public\n */\nexport type LangfusePromptClient = TextPromptClient | ChatPromptClient;\n","import {\n ChatMessage,\n PlaceholderMessage,\n ChatMessageWithPlaceholders,\n CreatePromptRequest,\n} from \"@langfuse/core\";\n\n/**\n * Enumeration of chat message types in Langfuse prompts.\n *\n * @public\n */\nexport enum ChatMessageType {\n /** Regular chat message with role and content */\n ChatMessage = \"chatmessage\",\n /** Placeholder for dynamic content insertion */\n Placeholder = \"placeholder\",\n}\n\n/**\n * Union type representing either a chat message or a placeholder.\n *\n * Used in compiled prompts where placeholders may remain unresolved.\n *\n * @public\n */\nexport type ChatMessageOrPlaceholder =\n | ChatMessage\n | ({ type: ChatMessageType.Placeholder } & PlaceholderMessage);\n\n/**\n * Represents a LangChain MessagesPlaceholder object.\n *\n * Used when converting Langfuse prompts to LangChain format,\n * unresolved placeholders become LangChain MessagesPlaceholder objects.\n *\n * @public\n */\nexport type LangchainMessagesPlaceholder = {\n /** Name of the variable that will provide the messages */\n variableName: string;\n /** Whether the placeholder is optional (defaults to false) */\n optional?: boolean;\n};\n\n/**\n * Type for creating chat prompts that support both regular messages and placeholders.\n *\n * Extends the standard chat prompt creation request to allow mixed content types.\n *\n * @public\n */\nexport type CreateChatPromptBodyWithPlaceholders = {\n /** Specifies this is a chat prompt */\n type: \"chat\";\n} & Omit<CreatePromptRequest.Chat, \"type\" | \"prompt\"> & {\n /** Array of chat messages and/or placeholders */\n prompt: (ChatMessage | ChatMessageWithPlaceholders)[];\n };\n","import {\n LangfuseAPIClient,\n IngestionEvent,\n getEnv,\n generateUUID,\n ScoreBody,\n getGlobalLogger,\n safeSetTimeout,\n IngestionResponse,\n} from \"@langfuse/core\";\nimport { Span, trace } from \"@opentelemetry/api\";\n\nconst MAX_QUEUE_SIZE = 100_000; // prevent memory leaks\nconst MAX_BATCH_SIZE = 100;\n\n/**\n * Manager for creating and batching score events in Langfuse.\n *\n * The ScoreManager handles automatic batching and flushing of score events\n * to optimize API usage. Scores are automatically sent when the queue reaches\n * a certain size or after a time interval.\n *\n * @public\n */\nexport class ScoreManager {\n private apiClient: LangfuseAPIClient;\n private eventQueue: IngestionEvent[] = [];\n private flushPromise: Promise<void> | null = null;\n private flushTimer: any = null;\n private flushAtCount: number;\n private flushIntervalSeconds: number;\n\n /**\n * Creates a new ScoreManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n\n const envFlushAtCount = getEnv(\"LANGFUSE_FLUSH_AT\");\n const envFlushIntervalSeconds = getEnv(\"LANGFUSE_FLUSH_INTERVAL\");\n\n this.flushAtCount = envFlushAtCount ? Number(envFlushAtCount) : 10;\n this.flushIntervalSeconds = envFlushIntervalSeconds\n ? Number(envFlushIntervalSeconds)\n : 1;\n }\n\n get logger() {\n return getGlobalLogger();\n }\n\n /**\n * Creates a new score event and adds it to the processing queue.\n *\n * Scores are queued and sent in batches for efficiency. The score will be\n * automatically sent when the queue reaches the flush threshold or after\n * the flush interval expires.\n *\n * @param data - The score data to create\n *\n * @example\n * ```typescript\n * langfuse.score.create({\n * name: \"quality\",\n * value: 0.85,\n * traceId: \"trace-123\",\n * comment: \"High quality response\"\n * });\n * ```\n */\n public create(data: ScoreBody): void {\n const scoreData: ScoreBody = {\n ...data,\n id: data.id ?? generateUUID(),\n environment: data.environment ?? getEnv(\"LANGFUSE_TRACING_ENVIRONMENT\"),\n };\n\n const scoreIngestionEvent: IngestionEvent = {\n id: generateUUID(),\n type: \"score-create\",\n timestamp: new Date().toISOString(),\n body: scoreData,\n };\n\n if (this.eventQueue.length >= MAX_QUEUE_SIZE) {\n this.logger.error(\n `Score queue is at max size ${MAX_QUEUE_SIZE}. Dropping score.`,\n );\n return;\n }\n\n this.eventQueue.push(scoreIngestionEvent);\n\n if (this.eventQueue.length >= this.flushAtCount) {\n this.flushPromise = this.flush();\n } else if (!this.flushTimer) {\n this.flushTimer = safeSetTimeout(() => {\n this.flushPromise = this.flush();\n }, this.flushIntervalSeconds * 1_000);\n }\n }\n\n /**\n * Creates a score for a specific observation using its OpenTelemetry span.\n *\n * This method automatically extracts the trace ID and observation ID from\n * the provided span context.\n *\n * @param observation - Object containing the OpenTelemetry span\n * @param data - Score data (traceId and observationId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startSpan } from '@langfuse/tracing';\n *\n * const span = startSpan({ name: \"my-operation\" });\n * langfuse.score.observation(\n * { otelSpan: span },\n * { name: \"accuracy\", value: 0.92 }\n * );\n * ```\n */\n public observation(\n observation: { otelSpan: Span },\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const { spanId, traceId } = observation.otelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n observationId: spanId,\n });\n }\n\n /**\n * Creates a score for a trace using an OpenTelemetry span.\n *\n * This method automatically extracts the trace ID from the provided\n * span context and creates a trace-level score.\n *\n * @param observation - Object containing the OpenTelemetry span\n * @param data - Score data (traceId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startSpan } from '@langfuse/tracing';\n *\n * const span = startSpan({ name: \"my-operation\" });\n * langfuse.score.trace(\n * { otelSpan: span },\n * { name: \"overall_quality\", value: 0.88 }\n * );\n * ```\n */\n public trace(\n observation: { otelSpan: Span },\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const { traceId } = observation.otelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n });\n }\n\n /**\n * Creates a score for the currently active observation.\n *\n * This method automatically detects the active OpenTelemetry span and\n * creates an observation-level score. If no active span is found,\n * a warning is logged and the operation is skipped.\n *\n * @param data - Score data (traceId and observationId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startActiveSpan } from '@langfuse/tracing';\n *\n * startActiveSpan({ name: \"my-operation\" }, (span) => {\n * // Inside the active span\n * langfuse.score.activeObservation({\n * name: \"relevance\",\n * value: 0.95\n * });\n * });\n * ```\n */\n public activeObservation(\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const currentOtelSpan = trace.getActiveSpan();\n if (!currentOtelSpan) {\n this.logger.warn(\"No active span in context to score.\");\n\n return;\n }\n\n const { spanId, traceId } = currentOtelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n observationId: spanId,\n });\n }\n\n /**\n * Creates a score for the currently active trace.\n *\n * This method automatically detects the active OpenTelemetry span and\n * creates a trace-level score. If no active span is found,\n * a warning is logged and the operation is skipped.\n *\n * @param data - Score data (traceId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startActiveSpan } from '@langfuse/tracing';\n *\n * startActiveSpan({ name: \"my-operation\" }, (span) => {\n * // Inside the active span\n * langfuse.score.activeTrace({\n * name: \"user_satisfaction\",\n * value: 4,\n * comment: \"User rated 4 out of 5 stars\"\n * });\n * });\n * ```\n */\n public activeTrace(\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const currentOtelSpan = trace.getActiveSpan();\n if (!currentOtelSpan) {\n this.logger.warn(\"No active span in context to score trace.\");\n\n return;\n }\n\n const { traceId } = currentOtelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n });\n }\n\n private async handleFlush() {\n try {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n const promises: Promise<IngestionResponse | void>[] = [];\n\n while (this.eventQueue.length > 0) {\n const batch = this.eventQueue.splice(0, MAX_BATCH_SIZE);\n\n promises.push(\n this.apiClient.ingestion\n .batch({ batch })\n .then((res) => {\n if (res.errors?.length > 0) {\n this.logger.error(\"Error ingesting scores:\", res.errors);\n }\n })\n .catch((err) => {\n this.logger.error(\"Failed to export score batch:\", err);\n }),\n );\n }\n\n await Promise.all(promises);\n } catch (err) {\n this.logger.error(\"Error flushing Score Manager: \", err);\n } finally {\n this.flushPromise = null;\n }\n }\n\n /**\n * Flushes all pending score events to the Langfuse API.\n *\n * This method ensures all queued scores are sent immediately rather than\n * waiting for the automatic flush interval or batch size threshold.\n *\n * @returns Promise that resolves when all pending scores have been sent\n *\n * @example\n * ```typescript\n * langfuse.score.create({ name: \"quality\", value: 0.8 });\n * await langfuse.score.flush(); // Ensures the score is sent immediately\n * ```\n */\n public async flush() {\n return this.flushPromise ?? this.handleFlush();\n }\n\n /**\n * Gracefully shuts down the score manager by flushing all pending scores.\n *\n * This method should be called before your application exits to ensure\n * all score data is sent to Langfuse.\n *\n * @returns Promise that resolves when shutdown is complete\n *\n * @example\n * ```typescript\n * // Before application exit\n * await langfuse.score.shutdown();\n * ```\n */\n public async shutdown() {\n await this.flush();\n }\n}\n"],"mappings":"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","names":["import_core","obj","import_core","import_core","ChatMessageType","mustache","import_core"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/LangfuseClient.ts","../src/dataset/index.ts","../src/media/index.ts","../src/prompt/promptManager.ts","../src/prompt/promptCache.ts","../src/prompt/promptClients.ts","../src/prompt/types.ts","../src/score/index.ts"],"sourcesContent":["export * from \"./LangfuseClient.js\";\nexport * from \"./prompt/index.js\";\nexport * from \"./score/index.js\";\nexport * from \"./dataset/index.js\";\nexport * from \"./media/index.js\";\n","import {\n LangfuseAPIClient,\n LANGFUSE_SDK_VERSION,\n getGlobalLogger,\n getEnv,\n} from \"@langfuse/core\";\n\nimport { DatasetManager } from \"./dataset/index.js\";\nimport { MediaManager } from \"./media/index.js\";\nimport { PromptManager } from \"./prompt/index.js\";\nimport { ScoreManager } from \"./score/index.js\";\n\n/**\n * Configuration parameters for initializing a LangfuseClient instance.\n *\n * @public\n */\nexport interface LangfuseClientParams {\n /**\n * Public API key for authentication with Langfuse.\n * Can also be provided via LANGFUSE_PUBLIC_KEY environment variable.\n */\n publicKey?: string;\n\n /**\n * Secret API key for authentication with Langfuse.\n * Can also be provided via LANGFUSE_SECRET_KEY environment variable.\n */\n secretKey?: string;\n\n /**\n * Base URL of the Langfuse instance to connect to.\n * Can also be provided via LANGFUSE_BASE_URL environment variable.\n *\n * @defaultValue \"https://cloud.langfuse.com\"\n */\n baseUrl?: string;\n\n /**\n * Request timeout in seconds.\n * Can also be provided via LANGFUSE_TIMEOUT environment variable.\n *\n * @defaultValue 5\n */\n timeout?: number;\n\n /**\n * Additional HTTP headers to include with API requests.\n */\n additionalHeaders?: Record<string, string>;\n}\n\n/**\n * Main client for interacting with the Langfuse API.\n *\n * The LangfuseClient provides access to all Langfuse functionality including:\n * - Prompt management and retrieval\n * - Dataset operations\n * - Score creation and management\n * - Media upload and handling\n * - Direct API access for advanced use cases\n *\n * @example\n * ```typescript\n * // Initialize with explicit credentials\n * const langfuse = new LangfuseClient({\n * publicKey: \"pk_...\",\n * secretKey: \"sk_...\",\n * baseUrl: \"https://cloud.langfuse.com\"\n * });\n *\n * // Or use environment variables\n * const langfuse = new LangfuseClient();\n *\n * // Use the client\n * const prompt = await langfuse.prompt.get(\"my-prompt\");\n * const compiledPrompt = prompt.compile({ variable: \"value\" });\n * ```\n *\n * @public\n */\nexport class LangfuseClient {\n /**\n * Direct access to the underlying Langfuse API client.\n * Use this for advanced API operations not covered by the high-level managers.\n */\n public api: LangfuseAPIClient;\n\n /**\n * Manager for prompt operations including creation, retrieval, and caching.\n */\n public prompt: PromptManager;\n\n /**\n * Manager for dataset operations including retrieval and item linking.\n */\n public dataset: DatasetManager;\n\n /**\n * Manager for score creation and batch processing.\n */\n public score: ScoreManager;\n\n /**\n * Manager for media upload and reference resolution.\n */\n public media: MediaManager;\n\n private baseUrl: string;\n private projectId: string | null = null;\n\n /**\n * @deprecated Use prompt.get instead\n */\n public getPrompt: typeof PromptManager.prototype.get;\n /**\n * @deprecated Use prompt.create instead\n */\n public createPrompt: typeof PromptManager.prototype.create;\n /**\n * @deprecated Use prompt.update instead\n */\n public updatePrompt: typeof PromptManager.prototype.update;\n /**\n * @deprecated Use dataset.get instead\n */\n public getDataset: typeof DatasetManager.prototype.get;\n /**\n * @deprecated Use api.trace.get instead\n */\n public fetchTrace: typeof LangfuseAPIClient.prototype.trace.get;\n /**\n * @deprecated Use api.trace.list instead\n */\n public fetchTraces: typeof LangfuseAPIClient.prototype.trace.list;\n /**\n * @deprecated Use api.observations.get instead\n */\n public fetchObservation: typeof LangfuseAPIClient.prototype.observations.get;\n /**\n * @deprecated Use api.observations.list instead\n */\n public fetchObservations: typeof LangfuseAPIClient.prototype.observations.getMany;\n /**\n * @deprecated Use api.sessions.get instead\n */\n public fetchSessions: typeof LangfuseAPIClient.prototype.sessions.get;\n /**\n * @deprecated Use api.datasets.getRun instead\n */\n public getDatasetRun: typeof LangfuseAPIClient.prototype.datasets.getRun;\n /**\n * @deprecated Use api.datasets.getRuns instead\n */\n public getDatasetRuns: typeof LangfuseAPIClient.prototype.datasets.getRuns;\n /**\n * @deprecated Use api.datasets.create instead\n */\n public createDataset: typeof LangfuseAPIClient.prototype.datasets.create;\n /**\n * @deprecated Use api.datasetItems.get instead\n */\n public getDatasetItem: typeof LangfuseAPIClient.prototype.datasetItems.get;\n /**\n * @deprecated Use api.datasetItems.create instead\n */\n public createDatasetItem: typeof LangfuseAPIClient.prototype.datasetItems.create;\n /**\n * @deprecated Use api.media.get instead\n */\n public fetchMedia: typeof LangfuseAPIClient.prototype.media.get;\n /**\n * @deprecated Use media.resolveReferences instead\n */\n public resolveMediaReferences: typeof MediaManager.prototype.resolveReferences;\n\n /**\n * Creates a new LangfuseClient instance.\n *\n * @param params - Configuration parameters. If not provided, will use environment variables.\n *\n * @throws Will log warnings if required credentials are not provided\n *\n * @example\n * ```typescript\n * // With explicit configuration\n * const client = new LangfuseClient({\n * publicKey: \"pk_...\",\n * secretKey: \"sk_...\",\n * baseUrl: \"https://your-instance.langfuse.com\"\n * });\n *\n * // Using environment variables\n * const client = new LangfuseClient();\n * ```\n */\n constructor(params?: LangfuseClientParams) {\n const logger = getGlobalLogger();\n\n const publicKey = params?.publicKey ?? getEnv(\"LANGFUSE_PUBLIC_KEY\");\n const secretKey = params?.secretKey ?? getEnv(\"LANGFUSE_SECRET_KEY\");\n this.baseUrl =\n params?.baseUrl ??\n getEnv(\"LANGFUSE_BASE_URL\") ??\n getEnv(\"LANGFUSE_BASEURL\") ?? // legacy v2\n \"https://cloud.langfuse.com\";\n\n if (!publicKey) {\n logger.warn(\n \"No public key provided in constructor or as LANGFUSE_PUBLIC_KEY env var. Client operations will fail.\",\n );\n }\n if (!secretKey) {\n logger.warn(\n \"No secret key provided in constructor or as LANGFUSE_SECRET_KEY env var. Client operations will fail.\",\n );\n }\n const timeoutSeconds =\n params?.timeout ?? Number(getEnv(\"LANGFUSE_TIMEOUT\") ?? 5);\n\n this.api = new LangfuseAPIClient({\n baseUrl: this.baseUrl,\n username: publicKey,\n password: secretKey,\n xLangfusePublicKey: publicKey,\n xLangfuseSdkVersion: LANGFUSE_SDK_VERSION,\n xLangfuseSdkName: \"javascript\",\n environment: \"\", // noop as baseUrl is set\n headers: params?.additionalHeaders,\n });\n\n logger.debug(\"Initialized LangfuseClient with params:\", {\n publicKey,\n baseUrl: this.baseUrl,\n timeoutSeconds,\n });\n\n this.prompt = new PromptManager({ apiClient: this.api });\n this.dataset = new DatasetManager({ apiClient: this.api });\n this.score = new ScoreManager({ apiClient: this.api });\n this.media = new MediaManager({ apiClient: this.api });\n\n // Keep v3 compat by exposing old interface\n this.getPrompt = this.prompt.get.bind(this.prompt); // keep correct this context for cache access\n this.createPrompt = this.prompt.create.bind(this.prompt);\n this.updatePrompt = this.prompt.update.bind(this.prompt);\n this.getDataset = this.dataset.get;\n this.fetchTrace = this.api.trace.get;\n this.fetchTraces = this.api.trace.list;\n this.fetchObservation = this.api.observations.get;\n this.fetchObservations = this.api.observations.getMany;\n this.fetchSessions = this.api.sessions.get;\n this.getDatasetRun = this.api.datasets.getRun;\n this.getDatasetRuns = this.api.datasets.getRuns;\n this.createDataset = this.api.datasets.create;\n this.getDatasetItem = this.api.datasetItems.get;\n this.createDatasetItem = this.api.datasetItems.create;\n this.fetchMedia = this.api.media.get;\n this.resolveMediaReferences = this.media.resolveReferences;\n }\n\n /**\n * Flushes any pending score events to the Langfuse API.\n *\n * This method ensures all queued scores are sent immediately rather than\n * waiting for the automatic flush interval or batch size threshold.\n *\n * @returns Promise that resolves when all pending scores have been sent\n *\n * @example\n * ```typescript\n * langfuse.score.create({ name: \"quality\", value: 0.8 });\n * await langfuse.flush(); // Ensures the score is sent immediately\n * ```\n */\n public async flush() {\n return this.score.flush();\n }\n\n /**\n * Gracefully shuts down the client by flushing all pending data.\n *\n * This method should be called before your application exits to ensure\n * all data is sent to Langfuse.\n *\n * @returns Promise that resolves when shutdown is complete\n *\n * @example\n * ```typescript\n * // Before application exit\n * await langfuse.shutdown();\n * ```\n */\n public async shutdown() {\n return this.score.shutdown();\n }\n\n /**\n * Generates a URL to view a specific trace in the Langfuse UI.\n *\n * @param traceId - The ID of the trace to generate a URL for\n * @returns Promise that resolves to the trace URL\n *\n * @example\n * ```typescript\n * const traceId = \"trace-123\";\n * const url = await langfuse.getTraceUrl(traceId);\n * console.log(`View trace at: ${url}`);\n * ```\n */\n public async getTraceUrl(traceId: string) {\n let projectId = this.projectId;\n\n if (!projectId) {\n projectId = (await this.api.projects.get()).data[0].id;\n this.projectId = projectId;\n }\n\n const traceUrl = `${this.baseUrl}/project/${projectId}/traces/${traceId}`;\n\n return traceUrl;\n }\n}\n","import {\n LangfuseAPIClient,\n Dataset,\n DatasetRunItem,\n DatasetItem,\n} from \"@langfuse/core\";\nimport { Span } from \"@opentelemetry/api\";\n\n/**\n * Function type for linking dataset items to OpenTelemetry spans.\n * This allows dataset items to be associated with specific traces for experiment tracking.\n *\n * @param obj - Object containing the OpenTelemetry span\n * @param runName - Name of the dataset run\n * @param runArgs - Optional arguments for the dataset run\n * @returns Promise that resolves to the created dataset run item\n *\n * @public\n */\nexport type LinkDatasetItemFunction = (\n obj: { otelSpan: Span },\n runName: string,\n runArgs?: {\n /** Description of the dataset run */\n description?: string;\n /** Additional metadata for the dataset run */\n metadata?: any;\n },\n) => Promise<DatasetRunItem>;\n\n/**\n * Manager for dataset operations in Langfuse.\n *\n * Provides methods to retrieve datasets and their items, with automatic\n * pagination handling and convenient linking functionality for experiments.\n *\n * @public\n */\nexport class DatasetManager {\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new DatasetManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n }\n\n /**\n * Retrieves a dataset by name along with all its items.\n *\n * This method automatically handles pagination to fetch all dataset items\n * and enhances each item with a `link` function for easy experiment tracking.\n *\n * @param name - The name of the dataset to retrieve\n * @param options - Optional configuration for fetching\n * @param options.fetchItemsPageSize - Number of items to fetch per page (default: 50)\n *\n * @returns Promise that resolves to the dataset with enhanced items\n *\n * @example\n * ```typescript\n * const dataset = await langfuse.dataset.get(\"my-dataset\");\n *\n * for (const item of dataset.items) {\n * // Use the item data for your experiment\n * const result = await processItem(item.input);\n *\n * // Link the result to the dataset item\n * await item.link(\n * { otelSpan: currentSpan },\n * \"experiment-run-1\",\n * { description: \"Testing new model\" }\n * );\n * }\n * ```\n */\n async get(\n name: string,\n options?: {\n fetchItemsPageSize: number;\n },\n ): Promise<\n Dataset & {\n items: (DatasetItem & { link: LinkDatasetItemFunction })[];\n }\n > {\n const dataset = await this.apiClient.datasets.get(name);\n const items: DatasetItem[] = [];\n\n let page = 1;\n\n while (true) {\n const itemsResponse = await this.apiClient.datasetItems.list({\n datasetName: name,\n limit: options?.fetchItemsPageSize ?? 50,\n page,\n });\n\n items.push(...itemsResponse.data);\n\n if (itemsResponse.meta.totalPages <= page) {\n break;\n }\n\n page++;\n }\n\n const returnDataset = {\n ...dataset,\n items: items.map((item) => ({\n ...item,\n link: this.createDatasetItemLinkFunction(item),\n })),\n };\n\n return returnDataset;\n }\n\n /**\n * Creates a link function for a specific dataset item.\n *\n * @param item - The dataset item to create a link function for\n * @returns A function that can link the item to OpenTelemetry spans\n * @internal\n */\n private createDatasetItemLinkFunction(\n item: DatasetItem,\n ): LinkDatasetItemFunction {\n const linkFunction = async (\n obj: { otelSpan: Span },\n runName: string,\n runArgs?: {\n description?: string;\n metadata?: any;\n },\n ): Promise<DatasetRunItem> => {\n return await this.apiClient.datasetRunItems.create({\n runName,\n datasetItemId: item.id,\n traceId: obj.otelSpan.spanContext().traceId,\n runDescription: runArgs?.description,\n metadata: runArgs?.metadata,\n });\n };\n\n return linkFunction;\n }\n}\n","import {\n LangfuseAPIClient,\n ParsedMediaReference,\n MediaContentType,\n getGlobalLogger,\n bytesToBase64,\n} from \"@langfuse/core\";\n\n/**\n * Parameters for resolving media references in objects.\n *\n * @template T - The type of the object being processed\n * @public\n */\nexport type LangfuseMediaResolveMediaReferencesParams<T> = {\n /** The object to process for media references */\n obj: T;\n /** The format to resolve media references to (currently only \"base64DataUri\" is supported) */\n resolveWith: \"base64DataUri\";\n /** Maximum depth to traverse when processing nested objects (default: 10) */\n maxDepth?: number;\n};\n\n/**\n * Manager for media operations in Langfuse.\n *\n * Provides methods to resolve media references in objects by replacing\n * them with actual media content (e.g., base64 data URIs).\n *\n * @public\n */\nexport class MediaManager {\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new MediaManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n }\n\n /**\n * Replaces media reference strings in an object with base64 data URIs.\n *\n * This method recursively traverses an object looking for media reference strings\n * in the format \"@@@langfuseMedia:...@@@\". When found, it fetches the actual media\n * content from Langfuse and replaces the reference string with a base64 data URI.\n *\n * If fetching media content fails for a reference string, a warning is logged\n * and the reference string is left unchanged.\n *\n * @param params - Configuration object\n * @returns A deep copy of the input object with media references resolved\n *\n * @example\n * ```typescript\n * const obj = {\n * image: \"@@@langfuseMedia:type=image/jpeg|id=123|source=bytes@@@\",\n * nested: {\n * pdf: \"@@@langfuseMedia:type=application/pdf|id=456|source=bytes@@@\"\n * }\n * };\n *\n * const result = await langfuse.media.resolveReferences({\n * obj,\n * resolveWith: \"base64DataUri\"\n * });\n *\n * // Result:\n * // {\n * // image: \"data:image/jpeg;base64,/9j/4AAQSkZJRg...\",\n * // nested: {\n * // pdf: \"data:application/pdf;base64,JVBERi0xLjcK...\"\n * // }\n * // }\n * ```\n */\n public async resolveReferences<T>(\n params: LangfuseMediaResolveMediaReferencesParams<T>,\n ): Promise<T> {\n const { obj, maxDepth = 10 } = params;\n\n const traverse = async <T>(obj: T, depth: number): Promise<T> => {\n if (depth > maxDepth) {\n return obj;\n }\n\n // Handle string with potential media references\n if (typeof obj === \"string\") {\n const regex = /@@@langfuseMedia:.+?@@@/g;\n const referenceStringMatches = obj.match(regex);\n if (!referenceStringMatches) {\n return obj;\n }\n\n let result = obj;\n const referenceStringToMediaContentMap = new Map<string, string>();\n\n await Promise.all(\n referenceStringMatches.map(async (referenceString) => {\n try {\n const parsedMediaReference =\n MediaManager.parseReferenceString(referenceString);\n const mediaData = await this.apiClient.media.get(\n parsedMediaReference.mediaId,\n );\n const mediaContent = await fetch(mediaData.url, {\n method: \"GET\",\n headers: {},\n });\n if (mediaContent.status !== 200) {\n throw new Error(\"Failed to fetch media content\");\n }\n\n const uint8Content = new Uint8Array(\n await mediaContent.arrayBuffer(),\n );\n\n const base64MediaContent = bytesToBase64(uint8Content);\n const base64DataUri = `data:${mediaData.contentType};base64,${base64MediaContent}`;\n\n referenceStringToMediaContentMap.set(\n referenceString,\n base64DataUri,\n );\n } catch (error) {\n getGlobalLogger().warn(\n \"Error fetching media content for reference string\",\n referenceString,\n error,\n );\n }\n }),\n );\n\n for (const [\n referenceString,\n base64MediaContent,\n ] of referenceStringToMediaContentMap.entries()) {\n result = result.replaceAll(referenceString, base64MediaContent) as T &\n string;\n }\n\n return result;\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return Promise.all(\n obj.map(async (item) => await traverse(item, depth + 1)),\n ) as Promise<T>;\n }\n\n // Handle objects\n if (typeof obj === \"object\" && obj !== null) {\n return Object.fromEntries(\n await Promise.all(\n Object.entries(obj).map(async ([key, value]) => [\n key,\n await traverse(value, depth + 1),\n ]),\n ),\n );\n }\n\n return obj;\n };\n\n return traverse(obj, 0);\n }\n\n /**\n * Parses a media reference string into a ParsedMediaReference.\n *\n * Example reference string:\n * \"@@@langfuseMedia:type=image/jpeg|id=some-uuid|source=base64DataUri@@@\"\n *\n * @param referenceString - The reference string to parse.\n * @returns An object with the mediaId, source, and contentType.\n *\n * @throws Error if the reference string is invalid or missing required fields.\n */\n public static parseReferenceString(\n referenceString: string,\n ): ParsedMediaReference {\n const prefix = \"@@@langfuseMedia:\";\n const suffix = \"@@@\";\n\n if (!referenceString.startsWith(prefix)) {\n throw new Error(\n \"Reference string does not start with '@@@langfuseMedia:type='\",\n );\n }\n\n if (!referenceString.endsWith(suffix)) {\n throw new Error(\"Reference string does not end with '@@@'\");\n }\n\n const content = referenceString.slice(prefix.length, -suffix.length);\n\n const pairs = content.split(\"|\");\n const parsedData: { [key: string]: string } = {};\n\n for (const pair of pairs) {\n const [key, value] = pair.split(\"=\", 2);\n parsedData[key] = value;\n }\n\n if (\n !(\"type\" in parsedData && \"id\" in parsedData && \"source\" in parsedData)\n ) {\n throw new Error(\"Missing required fields in reference string\");\n }\n\n return {\n mediaId: parsedData[\"id\"],\n source: parsedData[\"source\"],\n contentType: parsedData[\"type\"] as MediaContentType,\n };\n }\n}\n","import {\n CreatePromptRequest,\n getGlobalLogger,\n LangfuseAPIClient,\n PlaceholderMessage,\n Prompt,\n ChatMessage,\n} from \"@langfuse/core\";\n\nimport { LangfusePromptCache } from \"./promptCache.js\";\nimport {\n ChatPromptClient,\n TextPromptClient,\n LangfusePromptClient,\n} from \"./promptClients.js\";\nimport {\n ChatMessageType,\n CreateChatPromptBodyWithPlaceholders,\n} from \"./types.js\";\n\n/**\n * Manager for prompt operations in Langfuse.\n *\n * Provides methods to create, retrieve, and manage prompts with built-in caching\n * for optimal performance. Supports both text and chat prompts with variable\n * substitution and placeholder functionality.\n *\n * @public\n */\nexport class PromptManager {\n private cache: LangfusePromptCache;\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new PromptManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n const { apiClient } = params;\n\n this.apiClient = apiClient;\n this.cache = new LangfusePromptCache();\n }\n\n get logger() {\n return getGlobalLogger();\n }\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (chat prompt)\n * @returns Promise that resolves to a ChatPromptClient\n */\n async create(\n body: CreateChatPromptBodyWithPlaceholders,\n ): Promise<ChatPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (text prompt)\n * @returns Promise that resolves to a TextPromptClient\n */\n async create(\n body: Omit<CreatePromptRequest.Text, \"type\"> & { type?: \"text\" },\n ): Promise<TextPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (chat prompt)\n * @returns Promise that resolves to a ChatPromptClient\n */\n async create(body: CreatePromptRequest.Chat): Promise<ChatPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * Supports both text and chat prompts. Chat prompts can include placeholders\n * for dynamic content insertion.\n *\n * @param body - The prompt data to create\n * @returns Promise that resolves to the appropriate prompt client\n *\n * @example\n * ```typescript\n * // Create a text prompt\n * const textPrompt = await langfuse.prompt.create({\n * name: \"greeting\",\n * prompt: \"Hello {{name}}!\",\n * type: \"text\"\n * });\n *\n * // Create a chat prompt\n * const chatPrompt = await langfuse.prompt.create({\n * name: \"conversation\",\n * type: \"chat\",\n * prompt: [\n * { role: \"system\", content: \"You are a helpful assistant.\" },\n * { role: \"user\", content: \"{{user_message}}\" }\n * ]\n * });\n * ```\n */\n async create(\n body:\n | CreatePromptRequest.Chat\n | (Omit<CreatePromptRequest.Text, \"type\"> & { type?: \"text\" })\n | CreateChatPromptBodyWithPlaceholders,\n ): Promise<LangfusePromptClient> {\n const requestBody: CreatePromptRequest =\n body.type === \"chat\"\n ? {\n ...body,\n prompt: body.prompt.map((item) => {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n return {\n type: ChatMessageType.Placeholder,\n name: (item as PlaceholderMessage).name,\n };\n } else {\n // Handle regular ChatMessage (without type field) from API\n return { type: ChatMessageType.ChatMessage, ...item };\n }\n }),\n }\n : {\n ...body,\n type: body.type ?? \"text\",\n };\n\n const promptResponse = await this.apiClient.prompts.create(requestBody);\n\n if (promptResponse.type === \"chat\") {\n return new ChatPromptClient(promptResponse);\n }\n\n return new TextPromptClient(promptResponse);\n }\n\n /**\n * Updates the labels of an existing prompt version.\n *\n * @param params - Update parameters\n * @param params.name - Name of the prompt to update\n * @param params.version - Version number of the prompt to update\n * @param params.newLabels - New labels to apply to the prompt version\n *\n * @returns Promise that resolves to the updated prompt\n *\n * @example\n * ```typescript\n * const updatedPrompt = await langfuse.prompt.update({\n * name: \"my-prompt\",\n * version: 1,\n * newLabels: [\"production\", \"v2\"]\n * });\n * ```\n */\n async update(params: {\n name: string;\n version: number;\n newLabels: string[];\n }): Promise<Prompt> {\n const { name, version, newLabels } = params;\n\n const newPrompt = await this.apiClient.promptVersion.update(name, version, {\n newLabels,\n });\n\n this.cache.invalidate(name);\n\n return newPrompt;\n }\n\n /**\n * Retrieves a text prompt by name.\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to a TextPromptClient\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback text content if prompt fetch fails */\n fallback?: string;\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Specify text prompt type */\n type?: \"text\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<TextPromptClient>;\n\n /**\n * Retrieves a chat prompt by name.\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to a ChatPromptClient\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback chat messages if prompt fetch fails */\n fallback?: ChatMessage[];\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Specify chat prompt type */\n type: \"chat\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<ChatPromptClient>;\n\n /**\n * Retrieves a prompt by name with intelligent caching.\n *\n * This method implements sophisticated caching behavior:\n * - Fresh prompts are returned immediately from cache\n * - Expired prompts are returned from cache while being refreshed in background\n * - Cache misses trigger immediate fetch with optional fallback support\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to the appropriate prompt client\n *\n * @example\n * ```typescript\n * // Get latest version with caching\n * const prompt = await langfuse.prompt.get(\"my-prompt\");\n *\n * // Get specific version\n * const v2Prompt = await langfuse.prompt.get(\"my-prompt\", {\n * version: 2\n * });\n *\n * // Get with label filter\n * const prodPrompt = await langfuse.prompt.get(\"my-prompt\", {\n * label: \"production\"\n * });\n *\n * // Get with fallback\n * const promptWithFallback = await langfuse.prompt.get(\"my-prompt\", {\n * type: \"text\",\n * fallback: \"Hello {{name}}!\"\n * });\n * ```\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback content if prompt fetch fails */\n fallback?: ChatMessage[] | string;\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Prompt type (auto-detected if not specified) */\n type?: \"chat\" | \"text\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<LangfusePromptClient> {\n const cacheKey = this.cache.createKey({\n name,\n label: options?.label,\n });\n const cachedPrompt = this.cache.getIncludingExpired(cacheKey);\n if (!cachedPrompt || options?.cacheTtlSeconds === 0) {\n try {\n return await this.fetchPromptAndUpdateCache({\n name,\n version: options?.version,\n label: options?.label,\n cacheTtlSeconds: options?.cacheTtlSeconds,\n maxRetries: options?.maxRetries,\n fetchTimeoutMs: options?.fetchTimeoutMs,\n });\n } catch (err) {\n if (options?.fallback) {\n const sharedFallbackParams = {\n name,\n version: options?.version ?? 0,\n labels: options.label ? [options.label] : [],\n cacheTtlSeconds: options?.cacheTtlSeconds,\n config: {},\n tags: [],\n };\n\n if (options.type === \"chat\") {\n return new ChatPromptClient(\n {\n ...sharedFallbackParams,\n type: \"chat\",\n prompt: (options.fallback as ChatMessage[]).map((msg) => ({\n type: ChatMessageType.ChatMessage,\n ...msg,\n })),\n },\n true,\n );\n } else {\n return new TextPromptClient(\n {\n ...sharedFallbackParams,\n type: \"text\",\n prompt: options.fallback as string,\n },\n true,\n );\n }\n }\n\n throw err;\n }\n }\n\n if (cachedPrompt.isExpired) {\n // If the cache is not currently being refreshed, start refreshing it and register the promise in the cache\n if (!this.cache.isRefreshing(cacheKey)) {\n const refreshPromptPromise = this.fetchPromptAndUpdateCache({\n name,\n version: options?.version,\n label: options?.label,\n cacheTtlSeconds: options?.cacheTtlSeconds,\n maxRetries: options?.maxRetries,\n fetchTimeoutMs: options?.fetchTimeoutMs,\n }).catch(() => {\n this.logger.warn(\n `Failed to refresh prompt cache '${cacheKey}', stale cache will be used until next refresh succeeds.`,\n );\n });\n this.cache.addRefreshingPromise(cacheKey, refreshPromptPromise);\n }\n\n return cachedPrompt.value;\n }\n\n return cachedPrompt.value;\n }\n\n private async fetchPromptAndUpdateCache(params: {\n name: string;\n version?: number;\n cacheTtlSeconds?: number;\n label?: string;\n maxRetries?: number;\n fetchTimeoutMs?: number;\n }): Promise<LangfusePromptClient> {\n const cacheKey = this.cache.createKey(params);\n\n try {\n const {\n name,\n version,\n cacheTtlSeconds,\n label,\n maxRetries,\n fetchTimeoutMs,\n } = params;\n\n const data = await this.apiClient.prompts.get(\n name,\n {\n version,\n label,\n },\n {\n maxRetries,\n timeoutInSeconds: fetchTimeoutMs ? fetchTimeoutMs / 1_000 : undefined,\n },\n );\n\n let prompt: LangfusePromptClient;\n if (data.type === \"chat\") {\n prompt = new ChatPromptClient(data);\n } else {\n prompt = new TextPromptClient(data);\n }\n\n this.cache.set(cacheKey, prompt, cacheTtlSeconds);\n\n return prompt;\n } catch (error) {\n this.logger.error(`Error fetching prompt '${cacheKey}':`, error);\n\n throw error;\n }\n }\n}\n","import { getGlobalLogger } from \"@langfuse/core\";\n\nimport type { LangfusePromptClient } from \"./promptClients.js\";\n\nexport const DEFAULT_PROMPT_CACHE_TTL_SECONDS = 60;\n\nclass LangfusePromptCacheItem {\n private _expiry: number;\n\n constructor(\n public value: LangfusePromptClient,\n ttlSeconds: number,\n ) {\n this._expiry = Date.now() + ttlSeconds * 1000;\n }\n\n get isExpired(): boolean {\n return Date.now() > this._expiry;\n }\n}\nexport class LangfusePromptCache {\n private _cache: Map<string, LangfusePromptCacheItem>;\n private _defaultTtlSeconds: number;\n private _refreshingKeys: Map<string, Promise<void>>;\n\n constructor() {\n this._cache = new Map<string, LangfusePromptCacheItem>();\n this._defaultTtlSeconds = DEFAULT_PROMPT_CACHE_TTL_SECONDS;\n this._refreshingKeys = new Map<string, Promise<void>>();\n }\n\n public getIncludingExpired(key: string): LangfusePromptCacheItem | null {\n return this._cache.get(key) ?? null;\n }\n\n public createKey(params: {\n name: string;\n version?: number;\n label?: string;\n }): string {\n const { name, version, label } = params;\n const parts = [name];\n\n if (version !== undefined) {\n parts.push(\"version:\" + version.toString());\n } else if (label !== undefined) {\n parts.push(\"label:\" + label);\n } else {\n parts.push(\"label:production\");\n }\n\n return parts.join(\"-\");\n }\n\n public set(\n key: string,\n value: LangfusePromptClient,\n ttlSeconds?: number,\n ): void {\n const effectiveTtlSeconds = ttlSeconds ?? this._defaultTtlSeconds;\n this._cache.set(\n key,\n new LangfusePromptCacheItem(value, effectiveTtlSeconds),\n );\n }\n\n public addRefreshingPromise(key: string, promise: Promise<any>): void {\n this._refreshingKeys.set(key, promise);\n promise\n .then(() => {\n this._refreshingKeys.delete(key);\n })\n .catch(() => {\n this._refreshingKeys.delete(key);\n });\n }\n\n public isRefreshing(key: string): boolean {\n return this._refreshingKeys.has(key);\n }\n\n public invalidate(promptName: string): void {\n getGlobalLogger().debug(\n \"Invalidating cache keys for\",\n promptName,\n this._cache.keys(),\n );\n\n for (const key of this._cache.keys()) {\n if (key.startsWith(promptName)) {\n this._cache.delete(key);\n }\n }\n }\n}\n","import {\n Prompt,\n ChatMessage,\n BasePrompt,\n ChatMessageWithPlaceholders,\n} from \"@langfuse/core\";\nimport mustache from \"mustache\";\n\nimport {\n ChatMessageOrPlaceholder,\n ChatMessageType,\n LangchainMessagesPlaceholder,\n} from \"./types.js\";\n\nmustache.escape = function (text) {\n return text;\n};\n\n/**\n * Base class for all prompt clients.\n *\n * @internal\n */\nabstract class BasePromptClient {\n /** The name of the prompt */\n public readonly name: string;\n /** The version number of the prompt */\n public readonly version: number;\n /** Configuration object associated with the prompt */\n public readonly config: unknown;\n /** Labels associated with the prompt */\n public readonly labels: string[];\n /** Tags associated with the prompt */\n public readonly tags: string[];\n /** Whether this prompt client is using fallback content */\n public readonly isFallback: boolean;\n /** The type of prompt (\"text\" or \"chat\") */\n public readonly type: \"text\" | \"chat\";\n /** Optional commit message for the prompt version */\n public readonly commitMessage: string | null | undefined;\n\n /**\n * Creates a new BasePromptClient instance.\n *\n * @param prompt - The base prompt data\n * @param isFallback - Whether this is fallback content\n * @param type - The prompt type\n * @internal\n */\n constructor(prompt: BasePrompt, isFallback = false, type: \"text\" | \"chat\") {\n this.name = prompt.name;\n this.version = prompt.version;\n this.config = prompt.config;\n this.labels = prompt.labels;\n this.tags = prompt.tags;\n this.isFallback = isFallback;\n this.type = type;\n this.commitMessage = prompt.commitMessage;\n }\n\n /** Gets the raw prompt content */\n abstract get prompt(): string | ChatMessageWithPlaceholders[];\n\n /** Sets the raw prompt content */\n abstract set prompt(value: string | ChatMessageWithPlaceholders[]);\n\n /**\n * Compiles the prompt by substituting variables and resolving placeholders.\n *\n * @param variables - Key-value pairs for variable substitution\n * @param placeholders - Key-value pairs for placeholder resolution\n * @returns The compiled prompt content\n */\n abstract compile(\n variables?: Record<string, string>,\n placeholders?: Record<string, any>,\n ): string | ChatMessage[] | (ChatMessageOrPlaceholder | any)[];\n\n /**\n * Converts the prompt to a format compatible with LangChain.\n *\n * @param options - Options for conversion\n * @param options.placeholders - Placeholders to resolve during conversion\n * @returns The prompt in LangChain-compatible format\n */\n public abstract getLangchainPrompt(options?: {\n placeholders?: Record<string, any>;\n }):\n | string\n | ChatMessage[]\n | ChatMessageOrPlaceholder[]\n | (ChatMessage | LangchainMessagesPlaceholder | any)[];\n\n protected _transformToLangchainVariables(content: string): string {\n const jsonEscapedContent = this.escapeJsonForLangchain(content);\n\n return jsonEscapedContent.replace(/\\{\\{(\\w+)\\}\\}/g, \"{$1}\");\n }\n\n /**\n * Escapes every curly brace that is part of a JSON object by doubling it.\n *\n * A curly brace is considered “JSON-related” when, after skipping any immediate\n * whitespace, the next non-whitespace character is a single (') or double (\") quote.\n *\n * Braces that are already doubled (e.g. `{{variable}}` placeholders) are left untouched.\n *\n * @param text - Input string that may contain JSON snippets.\n * @returns The string with JSON-related braces doubled.\n */\n protected escapeJsonForLangchain(text: string): string {\n const out: string[] = []; // collected characters\n const stack: boolean[] = []; // true = “this { belongs to JSON”, false = normal “{”\n let i = 0;\n const n = text.length;\n\n while (i < n) {\n const ch = text[i];\n\n // ---------- opening brace ----------\n if (ch === \"{\") {\n // leave existing “{{ …” untouched\n if (i + 1 < n && text[i + 1] === \"{\") {\n out.push(\"{{\");\n i += 2;\n continue;\n }\n\n // look ahead to find the next non-space character\n let j = i + 1;\n while (j < n && /\\s/.test(text[j])) {\n j++;\n }\n\n const isJson = j < n && (text[j] === \"'\" || text[j] === '\"');\n out.push(isJson ? \"{{\" : \"{\");\n stack.push(isJson); // remember how this “{” was treated\n i += 1;\n continue;\n }\n\n // ---------- closing brace ----------\n if (ch === \"}\") {\n // leave existing “… }}” untouched\n if (i + 1 < n && text[i + 1] === \"}\") {\n out.push(\"}}\");\n i += 2;\n continue;\n }\n\n const isJson = stack.pop() ?? false;\n out.push(isJson ? \"}}\" : \"}\");\n i += 1;\n continue;\n }\n\n // ---------- any other character ----------\n out.push(ch);\n i += 1;\n }\n\n return out.join(\"\");\n }\n\n /**\n * Serializes the prompt client to JSON.\n *\n * @returns JSON string representation of the prompt\n */\n public abstract toJSON(): string;\n}\n\n/**\n * Client for working with text-based prompts.\n *\n * Provides methods to compile text prompts with variable substitution\n * and convert them to LangChain-compatible formats.\n *\n * @public\n */\nexport class TextPromptClient extends BasePromptClient {\n /** The original prompt response from the API */\n public readonly promptResponse: Prompt.Text;\n /** The text content of the prompt */\n public readonly prompt: string;\n\n /**\n * Creates a new TextPromptClient instance.\n *\n * @param prompt - The text prompt data\n * @param isFallback - Whether this is fallback content\n */\n constructor(prompt: Prompt.Text, isFallback = false) {\n super(prompt, isFallback, \"text\");\n this.promptResponse = prompt;\n this.prompt = prompt.prompt;\n }\n\n /**\n * Compiles the text prompt by substituting variables.\n *\n * Uses Mustache templating to replace {{variable}} placeholders with provided values.\n *\n * @param variables - Key-value pairs for variable substitution\n * @param _placeholders - Ignored for text prompts\n * @returns The compiled text with variables substituted\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"greeting\", { type: \"text\" });\n * const compiled = prompt.compile({ name: \"Alice\" });\n * // If prompt is \"Hello {{name}}!\", result is \"Hello Alice!\"\n * ```\n */\n compile(\n variables?: Record<string, string>,\n _placeholders?: Record<string, any>,\n ): string {\n return mustache.render(this.promptResponse.prompt, variables ?? {});\n }\n\n /**\n * Converts the prompt to LangChain PromptTemplate format.\n *\n * Transforms Mustache-style {{variable}} syntax to LangChain's {variable} format.\n *\n * @param _options - Ignored for text prompts\n * @returns The prompt string compatible with LangChain PromptTemplate\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"greeting\", { type: \"text\" });\n * const langchainFormat = prompt.getLangchainPrompt();\n * // Transforms \"Hello {{name}}!\" to \"Hello {name}!\"\n * ```\n */\n public getLangchainPrompt(_options?: {\n placeholders?: Record<string, any>;\n }): string {\n return this._transformToLangchainVariables(this.prompt);\n }\n\n public toJSON(): string {\n return JSON.stringify({\n name: this.name,\n prompt: this.prompt,\n version: this.version,\n isFallback: this.isFallback,\n tags: this.tags,\n labels: this.labels,\n type: this.type,\n config: this.config,\n });\n }\n}\n\n/**\n * Client for working with chat-based prompts.\n *\n * Provides methods to compile chat prompts with variable substitution and\n * placeholder resolution, and convert them to LangChain-compatible formats.\n *\n * @public\n */\nexport class ChatPromptClient extends BasePromptClient {\n /** The original prompt response from the API */\n public readonly promptResponse: Prompt.Chat;\n /** The chat messages that make up the prompt */\n public readonly prompt: ChatMessageWithPlaceholders[];\n\n /**\n * Creates a new ChatPromptClient instance.\n *\n * @param prompt - The chat prompt data\n * @param isFallback - Whether this is fallback content\n */\n constructor(prompt: Prompt.Chat, isFallback = false) {\n const normalizedPrompt = ChatPromptClient.normalizePrompt(prompt.prompt);\n const typedPrompt: Prompt.Chat = {\n ...prompt,\n prompt: normalizedPrompt,\n };\n\n super(typedPrompt, isFallback, \"chat\");\n this.promptResponse = typedPrompt;\n this.prompt = normalizedPrompt;\n }\n\n private static normalizePrompt(\n prompt: ChatMessage[] | ChatMessageWithPlaceholders[],\n ): ChatMessageWithPlaceholders[] {\n // Convert ChatMessages to ChatMessageWithPlaceholders for backward compatibility\n return prompt.map((item): ChatMessageWithPlaceholders => {\n if (\"type\" in item) {\n // Already has type field (new format)\n return item as ChatMessageWithPlaceholders;\n } else {\n // Plain ChatMessage (legacy format) - add type field\n return {\n type: ChatMessageType.ChatMessage,\n ...item,\n } as ChatMessageWithPlaceholders;\n }\n });\n }\n\n /**\n * Compiles the chat prompt by replacing placeholders and variables.\n *\n * First resolves placeholders with provided values, then applies variable substitution\n * to message content using Mustache templating. Unresolved placeholders remain\n * as placeholder objects in the output.\n *\n * @param variables - Key-value pairs for Mustache variable substitution in message content\n * @param placeholders - Key-value pairs where keys are placeholder names and values are ChatMessage arrays\n * @returns Array of ChatMessage objects and unresolved placeholder objects\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"conversation\", { type: \"chat\" });\n * const compiled = prompt.compile(\n * { user_name: \"Alice\" },\n * { examples: [{ role: \"user\", content: \"Hello\" }, { role: \"assistant\", content: \"Hi!\" }] }\n * );\n * ```\n */\n compile(\n variables?: Record<string, string>,\n placeholders?: Record<string, any>,\n ): (ChatMessageOrPlaceholder | any)[] {\n const messagesWithPlaceholdersReplaced: (ChatMessageOrPlaceholder | any)[] =\n [];\n const placeholderValues = placeholders ?? {};\n\n for (const item of this.prompt) {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n const placeholderValue = placeholderValues[item.name];\n if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length > 0 &&\n placeholderValue.every(\n (msg) =>\n typeof msg === \"object\" && \"role\" in msg && \"content\" in msg,\n )\n ) {\n messagesWithPlaceholdersReplaced.push(\n ...(placeholderValue as ChatMessage[]),\n );\n } else if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length === 0\n ) {\n // Empty array provided - skip placeholder (don't include it)\n } else if (placeholderValue !== undefined) {\n // Non-standard placeholder value format, just stringfiy\n messagesWithPlaceholdersReplaced.push(\n JSON.stringify(placeholderValue),\n );\n } else {\n // Keep unresolved placeholder in the output\n messagesWithPlaceholdersReplaced.push(\n item as { type: ChatMessageType.Placeholder } & typeof item,\n );\n }\n } else if (\n \"role\" in item &&\n \"content\" in item &&\n item.type === ChatMessageType.ChatMessage\n ) {\n messagesWithPlaceholdersReplaced.push({\n role: item.role,\n content: item.content,\n });\n }\n }\n\n return messagesWithPlaceholdersReplaced.map((item) => {\n if (\n typeof item === \"object\" &&\n item !== null &&\n \"role\" in item &&\n \"content\" in item\n ) {\n return {\n ...item,\n content: mustache.render(item.content, variables ?? {}),\n };\n } else {\n // Return placeholder or stringified value as-is\n return item;\n }\n });\n }\n\n /**\n * Converts the prompt to LangChain ChatPromptTemplate format.\n *\n * Resolves placeholders with provided values and converts unresolved ones\n * to LangChain MessagesPlaceholder objects. Transforms variables from\n * {{var}} to {var} format without rendering them.\n *\n * @param options - Configuration object\n * @param options.placeholders - Key-value pairs for placeholder resolution\n * @returns Array of ChatMessage objects and LangChain MessagesPlaceholder objects\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"conversation\", { type: \"chat\" });\n * const langchainFormat = prompt.getLangchainPrompt({\n * placeholders: { examples: [{ role: \"user\", content: \"Hello\" }] }\n * });\n * ```\n */\n public getLangchainPrompt(options?: {\n placeholders?: Record<string, any>;\n }): (ChatMessage | LangchainMessagesPlaceholder | any)[] {\n const messagesWithPlaceholdersReplaced: (\n | ChatMessage\n | LangchainMessagesPlaceholder\n | any\n )[] = [];\n const placeholderValues = options?.placeholders ?? {};\n\n for (const item of this.prompt) {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n const placeholderValue = placeholderValues[item.name];\n if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length > 0 &&\n placeholderValue.every(\n (msg) =>\n typeof msg === \"object\" && \"role\" in msg && \"content\" in msg,\n )\n ) {\n // Complete placeholder fill-in, replace with it\n messagesWithPlaceholdersReplaced.push(\n ...(placeholderValue as ChatMessage[]).map((msg) => {\n return {\n role: msg.role,\n content: this._transformToLangchainVariables(msg.content),\n };\n }),\n );\n } else if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length === 0\n ) {\n // Skip empty array placeholder\n } else if (placeholderValue !== undefined) {\n // Non-standard placeholder value, just stringify and add directly\n messagesWithPlaceholdersReplaced.push(\n JSON.stringify(placeholderValue),\n );\n } else {\n // Convert unresolved placeholder to Langchain MessagesPlaceholder\n messagesWithPlaceholdersReplaced.push({\n variableName: item.name,\n optional: false,\n });\n }\n } else if (\n \"role\" in item &&\n \"content\" in item &&\n item.type === ChatMessageType.ChatMessage\n ) {\n messagesWithPlaceholdersReplaced.push({\n role: item.role,\n content: this._transformToLangchainVariables(item.content),\n });\n }\n }\n\n return messagesWithPlaceholdersReplaced;\n }\n\n public toJSON(): string {\n return JSON.stringify({\n name: this.name,\n prompt: this.promptResponse.prompt.map((item) => {\n if (\"type\" in item && item.type === ChatMessageType.ChatMessage) {\n const { type: _, ...messageWithoutType } = item;\n return messageWithoutType;\n }\n return item;\n }),\n version: this.version,\n isFallback: this.isFallback,\n tags: this.tags,\n labels: this.labels,\n type: this.type,\n config: this.config,\n });\n }\n}\n\n/**\n * Union type representing either a text or chat prompt client.\n *\n * @public\n */\nexport type LangfusePromptClient = TextPromptClient | ChatPromptClient;\n","import {\n ChatMessage,\n PlaceholderMessage,\n ChatMessageWithPlaceholders,\n CreatePromptRequest,\n} from \"@langfuse/core\";\n\n/**\n * Enumeration of chat message types in Langfuse prompts.\n *\n * @public\n */\nexport enum ChatMessageType {\n /** Regular chat message with role and content */\n ChatMessage = \"chatmessage\",\n /** Placeholder for dynamic content insertion */\n Placeholder = \"placeholder\",\n}\n\n/**\n * Union type representing either a chat message or a placeholder.\n *\n * Used in compiled prompts where placeholders may remain unresolved.\n *\n * @public\n */\nexport type ChatMessageOrPlaceholder =\n | ChatMessage\n | ({ type: ChatMessageType.Placeholder } & PlaceholderMessage);\n\n/**\n * Represents a LangChain MessagesPlaceholder object.\n *\n * Used when converting Langfuse prompts to LangChain format,\n * unresolved placeholders become LangChain MessagesPlaceholder objects.\n *\n * @public\n */\nexport type LangchainMessagesPlaceholder = {\n /** Name of the variable that will provide the messages */\n variableName: string;\n /** Whether the placeholder is optional (defaults to false) */\n optional?: boolean;\n};\n\n/**\n * Type for creating chat prompts that support both regular messages and placeholders.\n *\n * Extends the standard chat prompt creation request to allow mixed content types.\n *\n * @public\n */\nexport type CreateChatPromptBodyWithPlaceholders = {\n /** Specifies this is a chat prompt */\n type: \"chat\";\n} & Omit<CreatePromptRequest.Chat, \"type\" | \"prompt\"> & {\n /** Array of chat messages and/or placeholders */\n prompt: (ChatMessage | ChatMessageWithPlaceholders)[];\n };\n","import {\n LangfuseAPIClient,\n IngestionEvent,\n getEnv,\n generateUUID,\n ScoreBody,\n getGlobalLogger,\n safeSetTimeout,\n IngestionResponse,\n} from \"@langfuse/core\";\nimport { Span, trace } from \"@opentelemetry/api\";\n\nconst MAX_QUEUE_SIZE = 100_000; // prevent memory leaks\nconst MAX_BATCH_SIZE = 100;\n\n/**\n * Manager for creating and batching score events in Langfuse.\n *\n * The ScoreManager handles automatic batching and flushing of score events\n * to optimize API usage. Scores are automatically sent when the queue reaches\n * a certain size or after a time interval.\n *\n * @public\n */\nexport class ScoreManager {\n private apiClient: LangfuseAPIClient;\n private eventQueue: IngestionEvent[] = [];\n private flushPromise: Promise<void> | null = null;\n private flushTimer: any = null;\n private flushAtCount: number;\n private flushIntervalSeconds: number;\n\n /**\n * Creates a new ScoreManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n\n const envFlushAtCount = getEnv(\"LANGFUSE_FLUSH_AT\");\n const envFlushIntervalSeconds = getEnv(\"LANGFUSE_FLUSH_INTERVAL\");\n\n this.flushAtCount = envFlushAtCount ? Number(envFlushAtCount) : 10;\n this.flushIntervalSeconds = envFlushIntervalSeconds\n ? Number(envFlushIntervalSeconds)\n : 1;\n }\n\n get logger() {\n return getGlobalLogger();\n }\n\n /**\n * Creates a new score event and adds it to the processing queue.\n *\n * Scores are queued and sent in batches for efficiency. The score will be\n * automatically sent when the queue reaches the flush threshold or after\n * the flush interval expires.\n *\n * @param data - The score data to create\n *\n * @example\n * ```typescript\n * langfuse.score.create({\n * name: \"quality\",\n * value: 0.85,\n * traceId: \"trace-123\",\n * comment: \"High quality response\"\n * });\n * ```\n */\n public create(data: ScoreBody): void {\n const scoreData: ScoreBody = {\n ...data,\n id: data.id ?? generateUUID(),\n environment: data.environment ?? getEnv(\"LANGFUSE_TRACING_ENVIRONMENT\"),\n };\n\n const scoreIngestionEvent: IngestionEvent = {\n id: generateUUID(),\n type: \"score-create\",\n timestamp: new Date().toISOString(),\n body: scoreData,\n };\n\n if (this.eventQueue.length >= MAX_QUEUE_SIZE) {\n this.logger.error(\n `Score queue is at max size ${MAX_QUEUE_SIZE}. Dropping score.`,\n );\n return;\n }\n\n this.eventQueue.push(scoreIngestionEvent);\n\n if (this.eventQueue.length >= this.flushAtCount) {\n this.flushPromise = this.flush();\n } else if (!this.flushTimer) {\n this.flushTimer = safeSetTimeout(() => {\n this.flushPromise = this.flush();\n }, this.flushIntervalSeconds * 1_000);\n }\n }\n\n /**\n * Creates a score for a specific observation using its OpenTelemetry span.\n *\n * This method automatically extracts the trace ID and observation ID from\n * the provided span context.\n *\n * @param observation - Object containing the OpenTelemetry span\n * @param data - Score data (traceId and observationId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startSpan } from '@langfuse/tracing';\n *\n * const span = startSpan({ name: \"my-operation\" });\n * langfuse.score.observation(\n * { otelSpan: span },\n * { name: \"accuracy\", value: 0.92 }\n * );\n * ```\n */\n public observation(\n observation: { otelSpan: Span },\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const { spanId, traceId } = observation.otelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n observationId: spanId,\n });\n }\n\n /**\n * Creates a score for a trace using an OpenTelemetry span.\n *\n * This method automatically extracts the trace ID from the provided\n * span context and creates a trace-level score.\n *\n * @param observation - Object containing the OpenTelemetry span\n * @param data - Score data (traceId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startSpan } from '@langfuse/tracing';\n *\n * const span = startSpan({ name: \"my-operation\" });\n * langfuse.score.trace(\n * { otelSpan: span },\n * { name: \"overall_quality\", value: 0.88 }\n * );\n * ```\n */\n public trace(\n observation: { otelSpan: Span },\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const { traceId } = observation.otelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n });\n }\n\n /**\n * Creates a score for the currently active observation.\n *\n * This method automatically detects the active OpenTelemetry span and\n * creates an observation-level score. If no active span is found,\n * a warning is logged and the operation is skipped.\n *\n * @param data - Score data (traceId and observationId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startActiveSpan } from '@langfuse/tracing';\n *\n * startActiveSpan({ name: \"my-operation\" }, (span) => {\n * // Inside the active span\n * langfuse.score.activeObservation({\n * name: \"relevance\",\n * value: 0.95\n * });\n * });\n * ```\n */\n public activeObservation(\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const currentOtelSpan = trace.getActiveSpan();\n if (!currentOtelSpan) {\n this.logger.warn(\"No active span in context to score.\");\n\n return;\n }\n\n const { spanId, traceId } = currentOtelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n observationId: spanId,\n });\n }\n\n /**\n * Creates a score for the currently active trace.\n *\n * This method automatically detects the active OpenTelemetry span and\n * creates a trace-level score. If no active span is found,\n * a warning is logged and the operation is skipped.\n *\n * @param data - Score data (traceId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startActiveSpan } from '@langfuse/tracing';\n *\n * startActiveSpan({ name: \"my-operation\" }, (span) => {\n * // Inside the active span\n * langfuse.score.activeTrace({\n * name: \"user_satisfaction\",\n * value: 4,\n * comment: \"User rated 4 out of 5 stars\"\n * });\n * });\n * ```\n */\n public activeTrace(\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const currentOtelSpan = trace.getActiveSpan();\n if (!currentOtelSpan) {\n this.logger.warn(\"No active span in context to score trace.\");\n\n return;\n }\n\n const { traceId } = currentOtelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n });\n }\n\n private async handleFlush() {\n try {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n const promises: Promise<IngestionResponse | void>[] = [];\n\n while (this.eventQueue.length > 0) {\n const batch = this.eventQueue.splice(0, MAX_BATCH_SIZE);\n\n promises.push(\n this.apiClient.ingestion\n .batch({ batch })\n .then((res) => {\n if (res.errors?.length > 0) {\n this.logger.error(\"Error ingesting scores:\", res.errors);\n }\n })\n .catch((err) => {\n this.logger.error(\"Failed to export score batch:\", err);\n }),\n );\n }\n\n await Promise.all(promises);\n } catch (err) {\n this.logger.error(\"Error flushing Score Manager: \", err);\n } finally {\n this.flushPromise = null;\n }\n }\n\n /**\n * Flushes all pending score events to the Langfuse API.\n *\n * This method ensures all queued scores are sent immediately rather than\n * waiting for the automatic flush interval or batch size threshold.\n *\n * @returns Promise that resolves when all pending scores have been sent\n *\n * @example\n * ```typescript\n * langfuse.score.create({ name: \"quality\", value: 0.8 });\n * await langfuse.score.flush(); // Ensures the score is sent immediately\n * ```\n */\n public async flush() {\n return this.flushPromise ?? this.handleFlush();\n }\n\n /**\n * Gracefully shuts down the score manager by flushing all pending scores.\n *\n * This method should be called before your application exits to ensure\n * all score data is sent to Langfuse.\n *\n * @returns Promise that resolves when shutdown is complete\n *\n * @example\n * ```typescript\n * // Before application exit\n * await langfuse.score.shutdown();\n * ```\n */\n public async shutdown() {\n await this.flush();\n }\n}\n"],"mappings":"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","names":["import_core","obj","import_core","import_core","ChatMessageType","mustache","import_core"]}
package/dist/index.mjs CHANGED
@@ -96,7 +96,7 @@ var DatasetManager = class {
96
96
  // src/media/index.ts
97
97
  import {
98
98
  getGlobalLogger,
99
- uint8ArrayToBase64
99
+ bytesToBase64
100
100
  } from "@langfuse/core";
101
101
  var MediaManager = class _MediaManager {
102
102
  /**
@@ -175,7 +175,7 @@ var MediaManager = class _MediaManager {
175
175
  const uint8Content = new Uint8Array(
176
176
  await mediaContent.arrayBuffer()
177
177
  );
178
- const base64MediaContent = uint8ArrayToBase64(uint8Content);
178
+ const base64MediaContent = bytesToBase64(uint8Content);
179
179
  const base64DataUri = `data:${mediaData.contentType};base64,${base64MediaContent}`;
180
180
  referenceStringToMediaContentMap.set(
181
181
  referenceString,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/LangfuseClient.ts","../src/dataset/index.ts","../src/media/index.ts","../src/prompt/promptManager.ts","../src/prompt/promptCache.ts","../src/prompt/promptClients.ts","../src/prompt/types.ts","../src/score/index.ts"],"sourcesContent":["import {\n LangfuseAPIClient,\n LANGFUSE_SDK_VERSION,\n getGlobalLogger,\n getEnv,\n} from \"@langfuse/core\";\n\nimport { DatasetManager } from \"./dataset/index.js\";\nimport { MediaManager } from \"./media/index.js\";\nimport { PromptManager } from \"./prompt/index.js\";\nimport { ScoreManager } from \"./score/index.js\";\n\n/**\n * Configuration parameters for initializing a LangfuseClient instance.\n *\n * @public\n */\nexport interface LangfuseClientParams {\n /**\n * Public API key for authentication with Langfuse.\n * Can also be provided via LANGFUSE_PUBLIC_KEY environment variable.\n */\n publicKey?: string;\n\n /**\n * Secret API key for authentication with Langfuse.\n * Can also be provided via LANGFUSE_SECRET_KEY environment variable.\n */\n secretKey?: string;\n\n /**\n * Base URL of the Langfuse instance to connect to.\n * Can also be provided via LANGFUSE_BASE_URL environment variable.\n *\n * @defaultValue \"https://cloud.langfuse.com\"\n */\n baseUrl?: string;\n\n /**\n * Request timeout in seconds.\n * Can also be provided via LANGFUSE_TIMEOUT environment variable.\n *\n * @defaultValue 5\n */\n timeout?: number;\n\n /**\n * Additional HTTP headers to include with API requests.\n */\n additionalHeaders?: Record<string, string>;\n}\n\n/**\n * Main client for interacting with the Langfuse API.\n *\n * The LangfuseClient provides access to all Langfuse functionality including:\n * - Prompt management and retrieval\n * - Dataset operations\n * - Score creation and management\n * - Media upload and handling\n * - Direct API access for advanced use cases\n *\n * @example\n * ```typescript\n * // Initialize with explicit credentials\n * const langfuse = new LangfuseClient({\n * publicKey: \"pk_...\",\n * secretKey: \"sk_...\",\n * baseUrl: \"https://cloud.langfuse.com\"\n * });\n *\n * // Or use environment variables\n * const langfuse = new LangfuseClient();\n *\n * // Use the client\n * const prompt = await langfuse.prompt.get(\"my-prompt\");\n * const compiledPrompt = prompt.compile({ variable: \"value\" });\n * ```\n *\n * @public\n */\nexport class LangfuseClient {\n /**\n * Direct access to the underlying Langfuse API client.\n * Use this for advanced API operations not covered by the high-level managers.\n */\n public api: LangfuseAPIClient;\n\n /**\n * Manager for prompt operations including creation, retrieval, and caching.\n */\n public prompt: PromptManager;\n\n /**\n * Manager for dataset operations including retrieval and item linking.\n */\n public dataset: DatasetManager;\n\n /**\n * Manager for score creation and batch processing.\n */\n public score: ScoreManager;\n\n /**\n * Manager for media upload and reference resolution.\n */\n public media: MediaManager;\n\n private baseUrl: string;\n private projectId: string | null = null;\n\n /**\n * @deprecated Use prompt.get instead\n */\n public getPrompt: typeof PromptManager.prototype.get;\n /**\n * @deprecated Use prompt.create instead\n */\n public createPrompt: typeof PromptManager.prototype.create;\n /**\n * @deprecated Use prompt.update instead\n */\n public updatePrompt: typeof PromptManager.prototype.update;\n /**\n * @deprecated Use dataset.get instead\n */\n public getDataset: typeof DatasetManager.prototype.get;\n /**\n * @deprecated Use api.trace.get instead\n */\n public fetchTrace: typeof LangfuseAPIClient.prototype.trace.get;\n /**\n * @deprecated Use api.trace.list instead\n */\n public fetchTraces: typeof LangfuseAPIClient.prototype.trace.list;\n /**\n * @deprecated Use api.observations.get instead\n */\n public fetchObservation: typeof LangfuseAPIClient.prototype.observations.get;\n /**\n * @deprecated Use api.observations.list instead\n */\n public fetchObservations: typeof LangfuseAPIClient.prototype.observations.getMany;\n /**\n * @deprecated Use api.sessions.get instead\n */\n public fetchSessions: typeof LangfuseAPIClient.prototype.sessions.get;\n /**\n * @deprecated Use api.datasets.getRun instead\n */\n public getDatasetRun: typeof LangfuseAPIClient.prototype.datasets.getRun;\n /**\n * @deprecated Use api.datasets.getRuns instead\n */\n public getDatasetRuns: typeof LangfuseAPIClient.prototype.datasets.getRuns;\n /**\n * @deprecated Use api.datasets.create instead\n */\n public createDataset: typeof LangfuseAPIClient.prototype.datasets.create;\n /**\n * @deprecated Use api.datasetItems.get instead\n */\n public getDatasetItem: typeof LangfuseAPIClient.prototype.datasetItems.get;\n /**\n * @deprecated Use api.datasetItems.create instead\n */\n public createDatasetItem: typeof LangfuseAPIClient.prototype.datasetItems.create;\n /**\n * @deprecated Use api.media.get instead\n */\n public fetchMedia: typeof LangfuseAPIClient.prototype.media.get;\n /**\n * @deprecated Use media.resolveReferences instead\n */\n public resolveMediaReferences: typeof MediaManager.prototype.resolveReferences;\n\n /**\n * Creates a new LangfuseClient instance.\n *\n * @param params - Configuration parameters. If not provided, will use environment variables.\n *\n * @throws Will log warnings if required credentials are not provided\n *\n * @example\n * ```typescript\n * // With explicit configuration\n * const client = new LangfuseClient({\n * publicKey: \"pk_...\",\n * secretKey: \"sk_...\",\n * baseUrl: \"https://your-instance.langfuse.com\"\n * });\n *\n * // Using environment variables\n * const client = new LangfuseClient();\n * ```\n */\n constructor(params?: LangfuseClientParams) {\n const logger = getGlobalLogger();\n\n const publicKey = params?.publicKey ?? getEnv(\"LANGFUSE_PUBLIC_KEY\");\n const secretKey = params?.secretKey ?? getEnv(\"LANGFUSE_SECRET_KEY\");\n this.baseUrl =\n params?.baseUrl ??\n getEnv(\"LANGFUSE_BASE_URL\") ??\n getEnv(\"LANGFUSE_BASEURL\") ?? // legacy v2\n \"https://cloud.langfuse.com\";\n\n if (!publicKey) {\n logger.warn(\n \"No public key provided in constructor or as LANGFUSE_PUBLIC_KEY env var. Client operations will fail.\",\n );\n }\n if (!secretKey) {\n logger.warn(\n \"No secret key provided in constructor or as LANGFUSE_SECRET_KEY env var. Client operations will fail.\",\n );\n }\n const timeoutSeconds =\n params?.timeout ?? Number(getEnv(\"LANGFUSE_TIMEOUT\") ?? 5);\n\n this.api = new LangfuseAPIClient({\n baseUrl: this.baseUrl,\n username: publicKey,\n password: secretKey,\n xLangfusePublicKey: publicKey,\n xLangfuseSdkVersion: LANGFUSE_SDK_VERSION,\n xLangfuseSdkName: \"javascript\",\n environment: \"\", // noop as baseUrl is set\n headers: params?.additionalHeaders,\n });\n\n logger.debug(\"Initialized LangfuseClient with params:\", {\n publicKey,\n baseUrl: this.baseUrl,\n timeoutSeconds,\n });\n\n this.prompt = new PromptManager({ apiClient: this.api });\n this.dataset = new DatasetManager({ apiClient: this.api });\n this.score = new ScoreManager({ apiClient: this.api });\n this.media = new MediaManager({ apiClient: this.api });\n\n // Keep v3 compat by exposing old interface\n this.getPrompt = this.prompt.get.bind(this.prompt); // keep correct this context for cache access\n this.createPrompt = this.prompt.create.bind(this.prompt);\n this.updatePrompt = this.prompt.update.bind(this.prompt);\n this.getDataset = this.dataset.get;\n this.fetchTrace = this.api.trace.get;\n this.fetchTraces = this.api.trace.list;\n this.fetchObservation = this.api.observations.get;\n this.fetchObservations = this.api.observations.getMany;\n this.fetchSessions = this.api.sessions.get;\n this.getDatasetRun = this.api.datasets.getRun;\n this.getDatasetRuns = this.api.datasets.getRuns;\n this.createDataset = this.api.datasets.create;\n this.getDatasetItem = this.api.datasetItems.get;\n this.createDatasetItem = this.api.datasetItems.create;\n this.fetchMedia = this.api.media.get;\n this.resolveMediaReferences = this.media.resolveReferences;\n }\n\n /**\n * Flushes any pending score events to the Langfuse API.\n *\n * This method ensures all queued scores are sent immediately rather than\n * waiting for the automatic flush interval or batch size threshold.\n *\n * @returns Promise that resolves when all pending scores have been sent\n *\n * @example\n * ```typescript\n * langfuse.score.create({ name: \"quality\", value: 0.8 });\n * await langfuse.flush(); // Ensures the score is sent immediately\n * ```\n */\n public async flush() {\n return this.score.flush();\n }\n\n /**\n * Gracefully shuts down the client by flushing all pending data.\n *\n * This method should be called before your application exits to ensure\n * all data is sent to Langfuse.\n *\n * @returns Promise that resolves when shutdown is complete\n *\n * @example\n * ```typescript\n * // Before application exit\n * await langfuse.shutdown();\n * ```\n */\n public async shutdown() {\n return this.score.shutdown();\n }\n\n /**\n * Generates a URL to view a specific trace in the Langfuse UI.\n *\n * @param traceId - The ID of the trace to generate a URL for\n * @returns Promise that resolves to the trace URL\n *\n * @example\n * ```typescript\n * const traceId = \"trace-123\";\n * const url = await langfuse.getTraceUrl(traceId);\n * console.log(`View trace at: ${url}`);\n * ```\n */\n public async getTraceUrl(traceId: string) {\n let projectId = this.projectId;\n\n if (!projectId) {\n projectId = (await this.api.projects.get()).data[0].id;\n this.projectId = projectId;\n }\n\n const traceUrl = `${this.baseUrl}/project/${projectId}/traces/${traceId}`;\n\n return traceUrl;\n }\n}\n","import {\n LangfuseAPIClient,\n Dataset,\n DatasetRunItem,\n DatasetItem,\n} from \"@langfuse/core\";\nimport { Span } from \"@opentelemetry/api\";\n\n/**\n * Function type for linking dataset items to OpenTelemetry spans.\n * This allows dataset items to be associated with specific traces for experiment tracking.\n *\n * @param obj - Object containing the OpenTelemetry span\n * @param runName - Name of the dataset run\n * @param runArgs - Optional arguments for the dataset run\n * @returns Promise that resolves to the created dataset run item\n *\n * @public\n */\nexport type LinkDatasetItemFunction = (\n obj: { otelSpan: Span },\n runName: string,\n runArgs?: {\n /** Description of the dataset run */\n description?: string;\n /** Additional metadata for the dataset run */\n metadata?: any;\n },\n) => Promise<DatasetRunItem>;\n\n/**\n * Manager for dataset operations in Langfuse.\n *\n * Provides methods to retrieve datasets and their items, with automatic\n * pagination handling and convenient linking functionality for experiments.\n *\n * @public\n */\nexport class DatasetManager {\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new DatasetManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n }\n\n /**\n * Retrieves a dataset by name along with all its items.\n *\n * This method automatically handles pagination to fetch all dataset items\n * and enhances each item with a `link` function for easy experiment tracking.\n *\n * @param name - The name of the dataset to retrieve\n * @param options - Optional configuration for fetching\n * @param options.fetchItemsPageSize - Number of items to fetch per page (default: 50)\n *\n * @returns Promise that resolves to the dataset with enhanced items\n *\n * @example\n * ```typescript\n * const dataset = await langfuse.dataset.get(\"my-dataset\");\n *\n * for (const item of dataset.items) {\n * // Use the item data for your experiment\n * const result = await processItem(item.input);\n *\n * // Link the result to the dataset item\n * await item.link(\n * { otelSpan: currentSpan },\n * \"experiment-run-1\",\n * { description: \"Testing new model\" }\n * );\n * }\n * ```\n */\n async get(\n name: string,\n options?: {\n fetchItemsPageSize: number;\n },\n ): Promise<\n Dataset & {\n items: (DatasetItem & { link: LinkDatasetItemFunction })[];\n }\n > {\n const dataset = await this.apiClient.datasets.get(name);\n const items: DatasetItem[] = [];\n\n let page = 1;\n\n while (true) {\n const itemsResponse = await this.apiClient.datasetItems.list({\n datasetName: name,\n limit: options?.fetchItemsPageSize ?? 50,\n page,\n });\n\n items.push(...itemsResponse.data);\n\n if (itemsResponse.meta.totalPages <= page) {\n break;\n }\n\n page++;\n }\n\n const returnDataset = {\n ...dataset,\n items: items.map((item) => ({\n ...item,\n link: this.createDatasetItemLinkFunction(item),\n })),\n };\n\n return returnDataset;\n }\n\n /**\n * Creates a link function for a specific dataset item.\n *\n * @param item - The dataset item to create a link function for\n * @returns A function that can link the item to OpenTelemetry spans\n * @internal\n */\n private createDatasetItemLinkFunction(\n item: DatasetItem,\n ): LinkDatasetItemFunction {\n const linkFunction = async (\n obj: { otelSpan: Span },\n runName: string,\n runArgs?: {\n description?: string;\n metadata?: any;\n },\n ): Promise<DatasetRunItem> => {\n return await this.apiClient.datasetRunItems.create({\n runName,\n datasetItemId: item.id,\n traceId: obj.otelSpan.spanContext().traceId,\n runDescription: runArgs?.description,\n metadata: runArgs?.metadata,\n });\n };\n\n return linkFunction;\n }\n}\n","import {\n LangfuseAPIClient,\n ParsedMediaReference,\n MediaContentType,\n getGlobalLogger,\n uint8ArrayToBase64,\n} from \"@langfuse/core\";\n\n/**\n * Parameters for resolving media references in objects.\n *\n * @template T - The type of the object being processed\n * @public\n */\nexport type LangfuseMediaResolveMediaReferencesParams<T> = {\n /** The object to process for media references */\n obj: T;\n /** The format to resolve media references to (currently only \"base64DataUri\" is supported) */\n resolveWith: \"base64DataUri\";\n /** Maximum depth to traverse when processing nested objects (default: 10) */\n maxDepth?: number;\n};\n\n/**\n * Manager for media operations in Langfuse.\n *\n * Provides methods to resolve media references in objects by replacing\n * them with actual media content (e.g., base64 data URIs).\n *\n * @public\n */\nexport class MediaManager {\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new MediaManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n }\n\n /**\n * Replaces media reference strings in an object with base64 data URIs.\n *\n * This method recursively traverses an object looking for media reference strings\n * in the format \"@@@langfuseMedia:...@@@\". When found, it fetches the actual media\n * content from Langfuse and replaces the reference string with a base64 data URI.\n *\n * If fetching media content fails for a reference string, a warning is logged\n * and the reference string is left unchanged.\n *\n * @param params - Configuration object\n * @returns A deep copy of the input object with media references resolved\n *\n * @example\n * ```typescript\n * const obj = {\n * image: \"@@@langfuseMedia:type=image/jpeg|id=123|source=bytes@@@\",\n * nested: {\n * pdf: \"@@@langfuseMedia:type=application/pdf|id=456|source=bytes@@@\"\n * }\n * };\n *\n * const result = await langfuse.media.resolveReferences({\n * obj,\n * resolveWith: \"base64DataUri\"\n * });\n *\n * // Result:\n * // {\n * // image: \"data:image/jpeg;base64,/9j/4AAQSkZJRg...\",\n * // nested: {\n * // pdf: \"data:application/pdf;base64,JVBERi0xLjcK...\"\n * // }\n * // }\n * ```\n */\n public async resolveReferences<T>(\n params: LangfuseMediaResolveMediaReferencesParams<T>,\n ): Promise<T> {\n const { obj, maxDepth = 10 } = params;\n\n const traverse = async <T>(obj: T, depth: number): Promise<T> => {\n if (depth > maxDepth) {\n return obj;\n }\n\n // Handle string with potential media references\n if (typeof obj === \"string\") {\n const regex = /@@@langfuseMedia:.+?@@@/g;\n const referenceStringMatches = obj.match(regex);\n if (!referenceStringMatches) {\n return obj;\n }\n\n let result = obj;\n const referenceStringToMediaContentMap = new Map<string, string>();\n\n await Promise.all(\n referenceStringMatches.map(async (referenceString) => {\n try {\n const parsedMediaReference =\n MediaManager.parseReferenceString(referenceString);\n const mediaData = await this.apiClient.media.get(\n parsedMediaReference.mediaId,\n );\n const mediaContent = await fetch(mediaData.url, {\n method: \"GET\",\n headers: {},\n });\n if (mediaContent.status !== 200) {\n throw new Error(\"Failed to fetch media content\");\n }\n\n const uint8Content = new Uint8Array(\n await mediaContent.arrayBuffer(),\n );\n\n const base64MediaContent = uint8ArrayToBase64(uint8Content);\n const base64DataUri = `data:${mediaData.contentType};base64,${base64MediaContent}`;\n\n referenceStringToMediaContentMap.set(\n referenceString,\n base64DataUri,\n );\n } catch (error) {\n getGlobalLogger().warn(\n \"Error fetching media content for reference string\",\n referenceString,\n error,\n );\n }\n }),\n );\n\n for (const [\n referenceString,\n base64MediaContent,\n ] of referenceStringToMediaContentMap.entries()) {\n result = result.replaceAll(referenceString, base64MediaContent) as T &\n string;\n }\n\n return result;\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return Promise.all(\n obj.map(async (item) => await traverse(item, depth + 1)),\n ) as Promise<T>;\n }\n\n // Handle objects\n if (typeof obj === \"object\" && obj !== null) {\n return Object.fromEntries(\n await Promise.all(\n Object.entries(obj).map(async ([key, value]) => [\n key,\n await traverse(value, depth + 1),\n ]),\n ),\n );\n }\n\n return obj;\n };\n\n return traverse(obj, 0);\n }\n\n /**\n * Parses a media reference string into a ParsedMediaReference.\n *\n * Example reference string:\n * \"@@@langfuseMedia:type=image/jpeg|id=some-uuid|source=base64DataUri@@@\"\n *\n * @param referenceString - The reference string to parse.\n * @returns An object with the mediaId, source, and contentType.\n *\n * @throws Error if the reference string is invalid or missing required fields.\n */\n public static parseReferenceString(\n referenceString: string,\n ): ParsedMediaReference {\n const prefix = \"@@@langfuseMedia:\";\n const suffix = \"@@@\";\n\n if (!referenceString.startsWith(prefix)) {\n throw new Error(\n \"Reference string does not start with '@@@langfuseMedia:type='\",\n );\n }\n\n if (!referenceString.endsWith(suffix)) {\n throw new Error(\"Reference string does not end with '@@@'\");\n }\n\n const content = referenceString.slice(prefix.length, -suffix.length);\n\n const pairs = content.split(\"|\");\n const parsedData: { [key: string]: string } = {};\n\n for (const pair of pairs) {\n const [key, value] = pair.split(\"=\", 2);\n parsedData[key] = value;\n }\n\n if (\n !(\"type\" in parsedData && \"id\" in parsedData && \"source\" in parsedData)\n ) {\n throw new Error(\"Missing required fields in reference string\");\n }\n\n return {\n mediaId: parsedData[\"id\"],\n source: parsedData[\"source\"],\n contentType: parsedData[\"type\"] as MediaContentType,\n };\n }\n}\n","import {\n CreatePromptRequest,\n getGlobalLogger,\n LangfuseAPIClient,\n PlaceholderMessage,\n Prompt,\n ChatMessage,\n} from \"@langfuse/core\";\n\nimport { LangfusePromptCache } from \"./promptCache.js\";\nimport {\n ChatPromptClient,\n TextPromptClient,\n LangfusePromptClient,\n} from \"./promptClients.js\";\nimport {\n ChatMessageType,\n CreateChatPromptBodyWithPlaceholders,\n} from \"./types.js\";\n\n/**\n * Manager for prompt operations in Langfuse.\n *\n * Provides methods to create, retrieve, and manage prompts with built-in caching\n * for optimal performance. Supports both text and chat prompts with variable\n * substitution and placeholder functionality.\n *\n * @public\n */\nexport class PromptManager {\n private cache: LangfusePromptCache;\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new PromptManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n const { apiClient } = params;\n\n this.apiClient = apiClient;\n this.cache = new LangfusePromptCache();\n }\n\n get logger() {\n return getGlobalLogger();\n }\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (chat prompt)\n * @returns Promise that resolves to a ChatPromptClient\n */\n async create(\n body: CreateChatPromptBodyWithPlaceholders,\n ): Promise<ChatPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (text prompt)\n * @returns Promise that resolves to a TextPromptClient\n */\n async create(\n body: Omit<CreatePromptRequest.Text, \"type\"> & { type?: \"text\" },\n ): Promise<TextPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (chat prompt)\n * @returns Promise that resolves to a ChatPromptClient\n */\n async create(body: CreatePromptRequest.Chat): Promise<ChatPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * Supports both text and chat prompts. Chat prompts can include placeholders\n * for dynamic content insertion.\n *\n * @param body - The prompt data to create\n * @returns Promise that resolves to the appropriate prompt client\n *\n * @example\n * ```typescript\n * // Create a text prompt\n * const textPrompt = await langfuse.prompt.create({\n * name: \"greeting\",\n * prompt: \"Hello {{name}}!\",\n * type: \"text\"\n * });\n *\n * // Create a chat prompt\n * const chatPrompt = await langfuse.prompt.create({\n * name: \"conversation\",\n * type: \"chat\",\n * prompt: [\n * { role: \"system\", content: \"You are a helpful assistant.\" },\n * { role: \"user\", content: \"{{user_message}}\" }\n * ]\n * });\n * ```\n */\n async create(\n body:\n | CreatePromptRequest.Chat\n | (Omit<CreatePromptRequest.Text, \"type\"> & { type?: \"text\" })\n | CreateChatPromptBodyWithPlaceholders,\n ): Promise<LangfusePromptClient> {\n const requestBody: CreatePromptRequest =\n body.type === \"chat\"\n ? {\n ...body,\n prompt: body.prompt.map((item) => {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n return {\n type: ChatMessageType.Placeholder,\n name: (item as PlaceholderMessage).name,\n };\n } else {\n // Handle regular ChatMessage (without type field) from API\n return { type: ChatMessageType.ChatMessage, ...item };\n }\n }),\n }\n : {\n ...body,\n type: body.type ?? \"text\",\n };\n\n const promptResponse = await this.apiClient.prompts.create(requestBody);\n\n if (promptResponse.type === \"chat\") {\n return new ChatPromptClient(promptResponse);\n }\n\n return new TextPromptClient(promptResponse);\n }\n\n /**\n * Updates the labels of an existing prompt version.\n *\n * @param params - Update parameters\n * @param params.name - Name of the prompt to update\n * @param params.version - Version number of the prompt to update\n * @param params.newLabels - New labels to apply to the prompt version\n *\n * @returns Promise that resolves to the updated prompt\n *\n * @example\n * ```typescript\n * const updatedPrompt = await langfuse.prompt.update({\n * name: \"my-prompt\",\n * version: 1,\n * newLabels: [\"production\", \"v2\"]\n * });\n * ```\n */\n async update(params: {\n name: string;\n version: number;\n newLabels: string[];\n }): Promise<Prompt> {\n const { name, version, newLabels } = params;\n\n const newPrompt = await this.apiClient.promptVersion.update(name, version, {\n newLabels,\n });\n\n this.cache.invalidate(name);\n\n return newPrompt;\n }\n\n /**\n * Retrieves a text prompt by name.\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to a TextPromptClient\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback text content if prompt fetch fails */\n fallback?: string;\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Specify text prompt type */\n type?: \"text\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<TextPromptClient>;\n\n /**\n * Retrieves a chat prompt by name.\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to a ChatPromptClient\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback chat messages if prompt fetch fails */\n fallback?: ChatMessage[];\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Specify chat prompt type */\n type: \"chat\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<ChatPromptClient>;\n\n /**\n * Retrieves a prompt by name with intelligent caching.\n *\n * This method implements sophisticated caching behavior:\n * - Fresh prompts are returned immediately from cache\n * - Expired prompts are returned from cache while being refreshed in background\n * - Cache misses trigger immediate fetch with optional fallback support\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to the appropriate prompt client\n *\n * @example\n * ```typescript\n * // Get latest version with caching\n * const prompt = await langfuse.prompt.get(\"my-prompt\");\n *\n * // Get specific version\n * const v2Prompt = await langfuse.prompt.get(\"my-prompt\", {\n * version: 2\n * });\n *\n * // Get with label filter\n * const prodPrompt = await langfuse.prompt.get(\"my-prompt\", {\n * label: \"production\"\n * });\n *\n * // Get with fallback\n * const promptWithFallback = await langfuse.prompt.get(\"my-prompt\", {\n * type: \"text\",\n * fallback: \"Hello {{name}}!\"\n * });\n * ```\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback content if prompt fetch fails */\n fallback?: ChatMessage[] | string;\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Prompt type (auto-detected if not specified) */\n type?: \"chat\" | \"text\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<LangfusePromptClient> {\n const cacheKey = this.cache.createKey({\n name,\n label: options?.label,\n });\n const cachedPrompt = this.cache.getIncludingExpired(cacheKey);\n if (!cachedPrompt || options?.cacheTtlSeconds === 0) {\n try {\n return await this.fetchPromptAndUpdateCache({\n name,\n version: options?.version,\n label: options?.label,\n cacheTtlSeconds: options?.cacheTtlSeconds,\n maxRetries: options?.maxRetries,\n fetchTimeoutMs: options?.fetchTimeoutMs,\n });\n } catch (err) {\n if (options?.fallback) {\n const sharedFallbackParams = {\n name,\n version: options?.version ?? 0,\n labels: options.label ? [options.label] : [],\n cacheTtlSeconds: options?.cacheTtlSeconds,\n config: {},\n tags: [],\n };\n\n if (options.type === \"chat\") {\n return new ChatPromptClient(\n {\n ...sharedFallbackParams,\n type: \"chat\",\n prompt: (options.fallback as ChatMessage[]).map((msg) => ({\n type: ChatMessageType.ChatMessage,\n ...msg,\n })),\n },\n true,\n );\n } else {\n return new TextPromptClient(\n {\n ...sharedFallbackParams,\n type: \"text\",\n prompt: options.fallback as string,\n },\n true,\n );\n }\n }\n\n throw err;\n }\n }\n\n if (cachedPrompt.isExpired) {\n // If the cache is not currently being refreshed, start refreshing it and register the promise in the cache\n if (!this.cache.isRefreshing(cacheKey)) {\n const refreshPromptPromise = this.fetchPromptAndUpdateCache({\n name,\n version: options?.version,\n label: options?.label,\n cacheTtlSeconds: options?.cacheTtlSeconds,\n maxRetries: options?.maxRetries,\n fetchTimeoutMs: options?.fetchTimeoutMs,\n }).catch(() => {\n this.logger.warn(\n `Failed to refresh prompt cache '${cacheKey}', stale cache will be used until next refresh succeeds.`,\n );\n });\n this.cache.addRefreshingPromise(cacheKey, refreshPromptPromise);\n }\n\n return cachedPrompt.value;\n }\n\n return cachedPrompt.value;\n }\n\n private async fetchPromptAndUpdateCache(params: {\n name: string;\n version?: number;\n cacheTtlSeconds?: number;\n label?: string;\n maxRetries?: number;\n fetchTimeoutMs?: number;\n }): Promise<LangfusePromptClient> {\n const cacheKey = this.cache.createKey(params);\n\n try {\n const {\n name,\n version,\n cacheTtlSeconds,\n label,\n maxRetries,\n fetchTimeoutMs,\n } = params;\n\n const data = await this.apiClient.prompts.get(\n name,\n {\n version,\n label,\n },\n {\n maxRetries,\n timeoutInSeconds: fetchTimeoutMs ? fetchTimeoutMs / 1_000 : undefined,\n },\n );\n\n let prompt: LangfusePromptClient;\n if (data.type === \"chat\") {\n prompt = new ChatPromptClient(data);\n } else {\n prompt = new TextPromptClient(data);\n }\n\n this.cache.set(cacheKey, prompt, cacheTtlSeconds);\n\n return prompt;\n } catch (error) {\n this.logger.error(`Error fetching prompt '${cacheKey}':`, error);\n\n throw error;\n }\n }\n}\n","import { getGlobalLogger } from \"@langfuse/core\";\n\nimport type { LangfusePromptClient } from \"./promptClients.js\";\n\nexport const DEFAULT_PROMPT_CACHE_TTL_SECONDS = 60;\n\nclass LangfusePromptCacheItem {\n private _expiry: number;\n\n constructor(\n public value: LangfusePromptClient,\n ttlSeconds: number,\n ) {\n this._expiry = Date.now() + ttlSeconds * 1000;\n }\n\n get isExpired(): boolean {\n return Date.now() > this._expiry;\n }\n}\nexport class LangfusePromptCache {\n private _cache: Map<string, LangfusePromptCacheItem>;\n private _defaultTtlSeconds: number;\n private _refreshingKeys: Map<string, Promise<void>>;\n\n constructor() {\n this._cache = new Map<string, LangfusePromptCacheItem>();\n this._defaultTtlSeconds = DEFAULT_PROMPT_CACHE_TTL_SECONDS;\n this._refreshingKeys = new Map<string, Promise<void>>();\n }\n\n public getIncludingExpired(key: string): LangfusePromptCacheItem | null {\n return this._cache.get(key) ?? null;\n }\n\n public createKey(params: {\n name: string;\n version?: number;\n label?: string;\n }): string {\n const { name, version, label } = params;\n const parts = [name];\n\n if (version !== undefined) {\n parts.push(\"version:\" + version.toString());\n } else if (label !== undefined) {\n parts.push(\"label:\" + label);\n } else {\n parts.push(\"label:production\");\n }\n\n return parts.join(\"-\");\n }\n\n public set(\n key: string,\n value: LangfusePromptClient,\n ttlSeconds?: number,\n ): void {\n const effectiveTtlSeconds = ttlSeconds ?? this._defaultTtlSeconds;\n this._cache.set(\n key,\n new LangfusePromptCacheItem(value, effectiveTtlSeconds),\n );\n }\n\n public addRefreshingPromise(key: string, promise: Promise<any>): void {\n this._refreshingKeys.set(key, promise);\n promise\n .then(() => {\n this._refreshingKeys.delete(key);\n })\n .catch(() => {\n this._refreshingKeys.delete(key);\n });\n }\n\n public isRefreshing(key: string): boolean {\n return this._refreshingKeys.has(key);\n }\n\n public invalidate(promptName: string): void {\n getGlobalLogger().debug(\n \"Invalidating cache keys for\",\n promptName,\n this._cache.keys(),\n );\n\n for (const key of this._cache.keys()) {\n if (key.startsWith(promptName)) {\n this._cache.delete(key);\n }\n }\n }\n}\n","import {\n Prompt,\n ChatMessage,\n BasePrompt,\n ChatMessageWithPlaceholders,\n} from \"@langfuse/core\";\nimport mustache from \"mustache\";\n\nimport {\n ChatMessageOrPlaceholder,\n ChatMessageType,\n LangchainMessagesPlaceholder,\n} from \"./types.js\";\n\nmustache.escape = function (text) {\n return text;\n};\n\n/**\n * Base class for all prompt clients.\n *\n * @internal\n */\nabstract class BasePromptClient {\n /** The name of the prompt */\n public readonly name: string;\n /** The version number of the prompt */\n public readonly version: number;\n /** Configuration object associated with the prompt */\n public readonly config: unknown;\n /** Labels associated with the prompt */\n public readonly labels: string[];\n /** Tags associated with the prompt */\n public readonly tags: string[];\n /** Whether this prompt client is using fallback content */\n public readonly isFallback: boolean;\n /** The type of prompt (\"text\" or \"chat\") */\n public readonly type: \"text\" | \"chat\";\n /** Optional commit message for the prompt version */\n public readonly commitMessage: string | null | undefined;\n\n /**\n * Creates a new BasePromptClient instance.\n *\n * @param prompt - The base prompt data\n * @param isFallback - Whether this is fallback content\n * @param type - The prompt type\n * @internal\n */\n constructor(prompt: BasePrompt, isFallback = false, type: \"text\" | \"chat\") {\n this.name = prompt.name;\n this.version = prompt.version;\n this.config = prompt.config;\n this.labels = prompt.labels;\n this.tags = prompt.tags;\n this.isFallback = isFallback;\n this.type = type;\n this.commitMessage = prompt.commitMessage;\n }\n\n /** Gets the raw prompt content */\n abstract get prompt(): string | ChatMessageWithPlaceholders[];\n\n /** Sets the raw prompt content */\n abstract set prompt(value: string | ChatMessageWithPlaceholders[]);\n\n /**\n * Compiles the prompt by substituting variables and resolving placeholders.\n *\n * @param variables - Key-value pairs for variable substitution\n * @param placeholders - Key-value pairs for placeholder resolution\n * @returns The compiled prompt content\n */\n abstract compile(\n variables?: Record<string, string>,\n placeholders?: Record<string, any>,\n ): string | ChatMessage[] | (ChatMessageOrPlaceholder | any)[];\n\n /**\n * Converts the prompt to a format compatible with LangChain.\n *\n * @param options - Options for conversion\n * @param options.placeholders - Placeholders to resolve during conversion\n * @returns The prompt in LangChain-compatible format\n */\n public abstract getLangchainPrompt(options?: {\n placeholders?: Record<string, any>;\n }):\n | string\n | ChatMessage[]\n | ChatMessageOrPlaceholder[]\n | (ChatMessage | LangchainMessagesPlaceholder | any)[];\n\n protected _transformToLangchainVariables(content: string): string {\n const jsonEscapedContent = this.escapeJsonForLangchain(content);\n\n return jsonEscapedContent.replace(/\\{\\{(\\w+)\\}\\}/g, \"{$1}\");\n }\n\n /**\n * Escapes every curly brace that is part of a JSON object by doubling it.\n *\n * A curly brace is considered “JSON-related” when, after skipping any immediate\n * whitespace, the next non-whitespace character is a single (') or double (\") quote.\n *\n * Braces that are already doubled (e.g. `{{variable}}` placeholders) are left untouched.\n *\n * @param text - Input string that may contain JSON snippets.\n * @returns The string with JSON-related braces doubled.\n */\n protected escapeJsonForLangchain(text: string): string {\n const out: string[] = []; // collected characters\n const stack: boolean[] = []; // true = “this { belongs to JSON”, false = normal “{”\n let i = 0;\n const n = text.length;\n\n while (i < n) {\n const ch = text[i];\n\n // ---------- opening brace ----------\n if (ch === \"{\") {\n // leave existing “{{ …” untouched\n if (i + 1 < n && text[i + 1] === \"{\") {\n out.push(\"{{\");\n i += 2;\n continue;\n }\n\n // look ahead to find the next non-space character\n let j = i + 1;\n while (j < n && /\\s/.test(text[j])) {\n j++;\n }\n\n const isJson = j < n && (text[j] === \"'\" || text[j] === '\"');\n out.push(isJson ? \"{{\" : \"{\");\n stack.push(isJson); // remember how this “{” was treated\n i += 1;\n continue;\n }\n\n // ---------- closing brace ----------\n if (ch === \"}\") {\n // leave existing “… }}” untouched\n if (i + 1 < n && text[i + 1] === \"}\") {\n out.push(\"}}\");\n i += 2;\n continue;\n }\n\n const isJson = stack.pop() ?? false;\n out.push(isJson ? \"}}\" : \"}\");\n i += 1;\n continue;\n }\n\n // ---------- any other character ----------\n out.push(ch);\n i += 1;\n }\n\n return out.join(\"\");\n }\n\n /**\n * Serializes the prompt client to JSON.\n *\n * @returns JSON string representation of the prompt\n */\n public abstract toJSON(): string;\n}\n\n/**\n * Client for working with text-based prompts.\n *\n * Provides methods to compile text prompts with variable substitution\n * and convert them to LangChain-compatible formats.\n *\n * @public\n */\nexport class TextPromptClient extends BasePromptClient {\n /** The original prompt response from the API */\n public readonly promptResponse: Prompt.Text;\n /** The text content of the prompt */\n public readonly prompt: string;\n\n /**\n * Creates a new TextPromptClient instance.\n *\n * @param prompt - The text prompt data\n * @param isFallback - Whether this is fallback content\n */\n constructor(prompt: Prompt.Text, isFallback = false) {\n super(prompt, isFallback, \"text\");\n this.promptResponse = prompt;\n this.prompt = prompt.prompt;\n }\n\n /**\n * Compiles the text prompt by substituting variables.\n *\n * Uses Mustache templating to replace {{variable}} placeholders with provided values.\n *\n * @param variables - Key-value pairs for variable substitution\n * @param _placeholders - Ignored for text prompts\n * @returns The compiled text with variables substituted\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"greeting\", { type: \"text\" });\n * const compiled = prompt.compile({ name: \"Alice\" });\n * // If prompt is \"Hello {{name}}!\", result is \"Hello Alice!\"\n * ```\n */\n compile(\n variables?: Record<string, string>,\n _placeholders?: Record<string, any>,\n ): string {\n return mustache.render(this.promptResponse.prompt, variables ?? {});\n }\n\n /**\n * Converts the prompt to LangChain PromptTemplate format.\n *\n * Transforms Mustache-style {{variable}} syntax to LangChain's {variable} format.\n *\n * @param _options - Ignored for text prompts\n * @returns The prompt string compatible with LangChain PromptTemplate\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"greeting\", { type: \"text\" });\n * const langchainFormat = prompt.getLangchainPrompt();\n * // Transforms \"Hello {{name}}!\" to \"Hello {name}!\"\n * ```\n */\n public getLangchainPrompt(_options?: {\n placeholders?: Record<string, any>;\n }): string {\n return this._transformToLangchainVariables(this.prompt);\n }\n\n public toJSON(): string {\n return JSON.stringify({\n name: this.name,\n prompt: this.prompt,\n version: this.version,\n isFallback: this.isFallback,\n tags: this.tags,\n labels: this.labels,\n type: this.type,\n config: this.config,\n });\n }\n}\n\n/**\n * Client for working with chat-based prompts.\n *\n * Provides methods to compile chat prompts with variable substitution and\n * placeholder resolution, and convert them to LangChain-compatible formats.\n *\n * @public\n */\nexport class ChatPromptClient extends BasePromptClient {\n /** The original prompt response from the API */\n public readonly promptResponse: Prompt.Chat;\n /** The chat messages that make up the prompt */\n public readonly prompt: ChatMessageWithPlaceholders[];\n\n /**\n * Creates a new ChatPromptClient instance.\n *\n * @param prompt - The chat prompt data\n * @param isFallback - Whether this is fallback content\n */\n constructor(prompt: Prompt.Chat, isFallback = false) {\n const normalizedPrompt = ChatPromptClient.normalizePrompt(prompt.prompt);\n const typedPrompt: Prompt.Chat = {\n ...prompt,\n prompt: normalizedPrompt,\n };\n\n super(typedPrompt, isFallback, \"chat\");\n this.promptResponse = typedPrompt;\n this.prompt = normalizedPrompt;\n }\n\n private static normalizePrompt(\n prompt: ChatMessage[] | ChatMessageWithPlaceholders[],\n ): ChatMessageWithPlaceholders[] {\n // Convert ChatMessages to ChatMessageWithPlaceholders for backward compatibility\n return prompt.map((item): ChatMessageWithPlaceholders => {\n if (\"type\" in item) {\n // Already has type field (new format)\n return item as ChatMessageWithPlaceholders;\n } else {\n // Plain ChatMessage (legacy format) - add type field\n return {\n type: ChatMessageType.ChatMessage,\n ...item,\n } as ChatMessageWithPlaceholders;\n }\n });\n }\n\n /**\n * Compiles the chat prompt by replacing placeholders and variables.\n *\n * First resolves placeholders with provided values, then applies variable substitution\n * to message content using Mustache templating. Unresolved placeholders remain\n * as placeholder objects in the output.\n *\n * @param variables - Key-value pairs for Mustache variable substitution in message content\n * @param placeholders - Key-value pairs where keys are placeholder names and values are ChatMessage arrays\n * @returns Array of ChatMessage objects and unresolved placeholder objects\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"conversation\", { type: \"chat\" });\n * const compiled = prompt.compile(\n * { user_name: \"Alice\" },\n * { examples: [{ role: \"user\", content: \"Hello\" }, { role: \"assistant\", content: \"Hi!\" }] }\n * );\n * ```\n */\n compile(\n variables?: Record<string, string>,\n placeholders?: Record<string, any>,\n ): (ChatMessageOrPlaceholder | any)[] {\n const messagesWithPlaceholdersReplaced: (ChatMessageOrPlaceholder | any)[] =\n [];\n const placeholderValues = placeholders ?? {};\n\n for (const item of this.prompt) {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n const placeholderValue = placeholderValues[item.name];\n if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length > 0 &&\n placeholderValue.every(\n (msg) =>\n typeof msg === \"object\" && \"role\" in msg && \"content\" in msg,\n )\n ) {\n messagesWithPlaceholdersReplaced.push(\n ...(placeholderValue as ChatMessage[]),\n );\n } else if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length === 0\n ) {\n // Empty array provided - skip placeholder (don't include it)\n } else if (placeholderValue !== undefined) {\n // Non-standard placeholder value format, just stringfiy\n messagesWithPlaceholdersReplaced.push(\n JSON.stringify(placeholderValue),\n );\n } else {\n // Keep unresolved placeholder in the output\n messagesWithPlaceholdersReplaced.push(\n item as { type: ChatMessageType.Placeholder } & typeof item,\n );\n }\n } else if (\n \"role\" in item &&\n \"content\" in item &&\n item.type === ChatMessageType.ChatMessage\n ) {\n messagesWithPlaceholdersReplaced.push({\n role: item.role,\n content: item.content,\n });\n }\n }\n\n return messagesWithPlaceholdersReplaced.map((item) => {\n if (\n typeof item === \"object\" &&\n item !== null &&\n \"role\" in item &&\n \"content\" in item\n ) {\n return {\n ...item,\n content: mustache.render(item.content, variables ?? {}),\n };\n } else {\n // Return placeholder or stringified value as-is\n return item;\n }\n });\n }\n\n /**\n * Converts the prompt to LangChain ChatPromptTemplate format.\n *\n * Resolves placeholders with provided values and converts unresolved ones\n * to LangChain MessagesPlaceholder objects. Transforms variables from\n * {{var}} to {var} format without rendering them.\n *\n * @param options - Configuration object\n * @param options.placeholders - Key-value pairs for placeholder resolution\n * @returns Array of ChatMessage objects and LangChain MessagesPlaceholder objects\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"conversation\", { type: \"chat\" });\n * const langchainFormat = prompt.getLangchainPrompt({\n * placeholders: { examples: [{ role: \"user\", content: \"Hello\" }] }\n * });\n * ```\n */\n public getLangchainPrompt(options?: {\n placeholders?: Record<string, any>;\n }): (ChatMessage | LangchainMessagesPlaceholder | any)[] {\n const messagesWithPlaceholdersReplaced: (\n | ChatMessage\n | LangchainMessagesPlaceholder\n | any\n )[] = [];\n const placeholderValues = options?.placeholders ?? {};\n\n for (const item of this.prompt) {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n const placeholderValue = placeholderValues[item.name];\n if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length > 0 &&\n placeholderValue.every(\n (msg) =>\n typeof msg === \"object\" && \"role\" in msg && \"content\" in msg,\n )\n ) {\n // Complete placeholder fill-in, replace with it\n messagesWithPlaceholdersReplaced.push(\n ...(placeholderValue as ChatMessage[]).map((msg) => {\n return {\n role: msg.role,\n content: this._transformToLangchainVariables(msg.content),\n };\n }),\n );\n } else if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length === 0\n ) {\n // Skip empty array placeholder\n } else if (placeholderValue !== undefined) {\n // Non-standard placeholder value, just stringify and add directly\n messagesWithPlaceholdersReplaced.push(\n JSON.stringify(placeholderValue),\n );\n } else {\n // Convert unresolved placeholder to Langchain MessagesPlaceholder\n messagesWithPlaceholdersReplaced.push({\n variableName: item.name,\n optional: false,\n });\n }\n } else if (\n \"role\" in item &&\n \"content\" in item &&\n item.type === ChatMessageType.ChatMessage\n ) {\n messagesWithPlaceholdersReplaced.push({\n role: item.role,\n content: this._transformToLangchainVariables(item.content),\n });\n }\n }\n\n return messagesWithPlaceholdersReplaced;\n }\n\n public toJSON(): string {\n return JSON.stringify({\n name: this.name,\n prompt: this.promptResponse.prompt.map((item) => {\n if (\"type\" in item && item.type === ChatMessageType.ChatMessage) {\n const { type: _, ...messageWithoutType } = item;\n return messageWithoutType;\n }\n return item;\n }),\n version: this.version,\n isFallback: this.isFallback,\n tags: this.tags,\n labels: this.labels,\n type: this.type,\n config: this.config,\n });\n }\n}\n\n/**\n * Union type representing either a text or chat prompt client.\n *\n * @public\n */\nexport type LangfusePromptClient = TextPromptClient | ChatPromptClient;\n","import {\n ChatMessage,\n PlaceholderMessage,\n ChatMessageWithPlaceholders,\n CreatePromptRequest,\n} from \"@langfuse/core\";\n\n/**\n * Enumeration of chat message types in Langfuse prompts.\n *\n * @public\n */\nexport enum ChatMessageType {\n /** Regular chat message with role and content */\n ChatMessage = \"chatmessage\",\n /** Placeholder for dynamic content insertion */\n Placeholder = \"placeholder\",\n}\n\n/**\n * Union type representing either a chat message or a placeholder.\n *\n * Used in compiled prompts where placeholders may remain unresolved.\n *\n * @public\n */\nexport type ChatMessageOrPlaceholder =\n | ChatMessage\n | ({ type: ChatMessageType.Placeholder } & PlaceholderMessage);\n\n/**\n * Represents a LangChain MessagesPlaceholder object.\n *\n * Used when converting Langfuse prompts to LangChain format,\n * unresolved placeholders become LangChain MessagesPlaceholder objects.\n *\n * @public\n */\nexport type LangchainMessagesPlaceholder = {\n /** Name of the variable that will provide the messages */\n variableName: string;\n /** Whether the placeholder is optional (defaults to false) */\n optional?: boolean;\n};\n\n/**\n * Type for creating chat prompts that support both regular messages and placeholders.\n *\n * Extends the standard chat prompt creation request to allow mixed content types.\n *\n * @public\n */\nexport type CreateChatPromptBodyWithPlaceholders = {\n /** Specifies this is a chat prompt */\n type: \"chat\";\n} & Omit<CreatePromptRequest.Chat, \"type\" | \"prompt\"> & {\n /** Array of chat messages and/or placeholders */\n prompt: (ChatMessage | ChatMessageWithPlaceholders)[];\n };\n","import {\n LangfuseAPIClient,\n IngestionEvent,\n getEnv,\n generateUUID,\n ScoreBody,\n getGlobalLogger,\n safeSetTimeout,\n IngestionResponse,\n} from \"@langfuse/core\";\nimport { Span, trace } from \"@opentelemetry/api\";\n\nconst MAX_QUEUE_SIZE = 100_000; // prevent memory leaks\nconst MAX_BATCH_SIZE = 100;\n\n/**\n * Manager for creating and batching score events in Langfuse.\n *\n * The ScoreManager handles automatic batching and flushing of score events\n * to optimize API usage. Scores are automatically sent when the queue reaches\n * a certain size or after a time interval.\n *\n * @public\n */\nexport class ScoreManager {\n private apiClient: LangfuseAPIClient;\n private eventQueue: IngestionEvent[] = [];\n private flushPromise: Promise<void> | null = null;\n private flushTimer: any = null;\n private flushAtCount: number;\n private flushIntervalSeconds: number;\n\n /**\n * Creates a new ScoreManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n\n const envFlushAtCount = getEnv(\"LANGFUSE_FLUSH_AT\");\n const envFlushIntervalSeconds = getEnv(\"LANGFUSE_FLUSH_INTERVAL\");\n\n this.flushAtCount = envFlushAtCount ? Number(envFlushAtCount) : 10;\n this.flushIntervalSeconds = envFlushIntervalSeconds\n ? Number(envFlushIntervalSeconds)\n : 1;\n }\n\n get logger() {\n return getGlobalLogger();\n }\n\n /**\n * Creates a new score event and adds it to the processing queue.\n *\n * Scores are queued and sent in batches for efficiency. The score will be\n * automatically sent when the queue reaches the flush threshold or after\n * the flush interval expires.\n *\n * @param data - The score data to create\n *\n * @example\n * ```typescript\n * langfuse.score.create({\n * name: \"quality\",\n * value: 0.85,\n * traceId: \"trace-123\",\n * comment: \"High quality response\"\n * });\n * ```\n */\n public create(data: ScoreBody): void {\n const scoreData: ScoreBody = {\n ...data,\n id: data.id ?? generateUUID(),\n environment: data.environment ?? getEnv(\"LANGFUSE_TRACING_ENVIRONMENT\"),\n };\n\n const scoreIngestionEvent: IngestionEvent = {\n id: generateUUID(),\n type: \"score-create\",\n timestamp: new Date().toISOString(),\n body: scoreData,\n };\n\n if (this.eventQueue.length >= MAX_QUEUE_SIZE) {\n this.logger.error(\n `Score queue is at max size ${MAX_QUEUE_SIZE}. Dropping score.`,\n );\n return;\n }\n\n this.eventQueue.push(scoreIngestionEvent);\n\n if (this.eventQueue.length >= this.flushAtCount) {\n this.flushPromise = this.flush();\n } else if (!this.flushTimer) {\n this.flushTimer = safeSetTimeout(() => {\n this.flushPromise = this.flush();\n }, this.flushIntervalSeconds * 1_000);\n }\n }\n\n /**\n * Creates a score for a specific observation using its OpenTelemetry span.\n *\n * This method automatically extracts the trace ID and observation ID from\n * the provided span context.\n *\n * @param observation - Object containing the OpenTelemetry span\n * @param data - Score data (traceId and observationId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startSpan } from '@langfuse/tracing';\n *\n * const span = startSpan({ name: \"my-operation\" });\n * langfuse.score.observation(\n * { otelSpan: span },\n * { name: \"accuracy\", value: 0.92 }\n * );\n * ```\n */\n public observation(\n observation: { otelSpan: Span },\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const { spanId, traceId } = observation.otelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n observationId: spanId,\n });\n }\n\n /**\n * Creates a score for a trace using an OpenTelemetry span.\n *\n * This method automatically extracts the trace ID from the provided\n * span context and creates a trace-level score.\n *\n * @param observation - Object containing the OpenTelemetry span\n * @param data - Score data (traceId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startSpan } from '@langfuse/tracing';\n *\n * const span = startSpan({ name: \"my-operation\" });\n * langfuse.score.trace(\n * { otelSpan: span },\n * { name: \"overall_quality\", value: 0.88 }\n * );\n * ```\n */\n public trace(\n observation: { otelSpan: Span },\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const { traceId } = observation.otelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n });\n }\n\n /**\n * Creates a score for the currently active observation.\n *\n * This method automatically detects the active OpenTelemetry span and\n * creates an observation-level score. If no active span is found,\n * a warning is logged and the operation is skipped.\n *\n * @param data - Score data (traceId and observationId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startActiveSpan } from '@langfuse/tracing';\n *\n * startActiveSpan({ name: \"my-operation\" }, (span) => {\n * // Inside the active span\n * langfuse.score.activeObservation({\n * name: \"relevance\",\n * value: 0.95\n * });\n * });\n * ```\n */\n public activeObservation(\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const currentOtelSpan = trace.getActiveSpan();\n if (!currentOtelSpan) {\n this.logger.warn(\"No active span in context to score.\");\n\n return;\n }\n\n const { spanId, traceId } = currentOtelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n observationId: spanId,\n });\n }\n\n /**\n * Creates a score for the currently active trace.\n *\n * This method automatically detects the active OpenTelemetry span and\n * creates a trace-level score. If no active span is found,\n * a warning is logged and the operation is skipped.\n *\n * @param data - Score data (traceId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startActiveSpan } from '@langfuse/tracing';\n *\n * startActiveSpan({ name: \"my-operation\" }, (span) => {\n * // Inside the active span\n * langfuse.score.activeTrace({\n * name: \"user_satisfaction\",\n * value: 4,\n * comment: \"User rated 4 out of 5 stars\"\n * });\n * });\n * ```\n */\n public activeTrace(\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const currentOtelSpan = trace.getActiveSpan();\n if (!currentOtelSpan) {\n this.logger.warn(\"No active span in context to score trace.\");\n\n return;\n }\n\n const { traceId } = currentOtelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n });\n }\n\n private async handleFlush() {\n try {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n const promises: Promise<IngestionResponse | void>[] = [];\n\n while (this.eventQueue.length > 0) {\n const batch = this.eventQueue.splice(0, MAX_BATCH_SIZE);\n\n promises.push(\n this.apiClient.ingestion\n .batch({ batch })\n .then((res) => {\n if (res.errors?.length > 0) {\n this.logger.error(\"Error ingesting scores:\", res.errors);\n }\n })\n .catch((err) => {\n this.logger.error(\"Failed to export score batch:\", err);\n }),\n );\n }\n\n await Promise.all(promises);\n } catch (err) {\n this.logger.error(\"Error flushing Score Manager: \", err);\n } finally {\n this.flushPromise = null;\n }\n }\n\n /**\n * Flushes all pending score events to the Langfuse API.\n *\n * This method ensures all queued scores are sent immediately rather than\n * waiting for the automatic flush interval or batch size threshold.\n *\n * @returns Promise that resolves when all pending scores have been sent\n *\n * @example\n * ```typescript\n * langfuse.score.create({ name: \"quality\", value: 0.8 });\n * await langfuse.score.flush(); // Ensures the score is sent immediately\n * ```\n */\n public async flush() {\n return this.flushPromise ?? this.handleFlush();\n }\n\n /**\n * Gracefully shuts down the score manager by flushing all pending scores.\n *\n * This method should be called before your application exits to ensure\n * all score data is sent to Langfuse.\n *\n * @returns Promise that resolves when shutdown is complete\n *\n * @example\n * ```typescript\n * // Before application exit\n * await langfuse.score.shutdown();\n * ```\n */\n public async shutdown() {\n await this.flush();\n }\n}\n"],"mappings":"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","names":["LangfuseAPIClient","getGlobalLogger","getEnv","obj","getGlobalLogger","getGlobalLogger","ChatMessageType","getGlobalLogger","getGlobalLogger","getGlobalLogger","getEnv","LangfuseAPIClient"]}
1
+ {"version":3,"sources":["../src/LangfuseClient.ts","../src/dataset/index.ts","../src/media/index.ts","../src/prompt/promptManager.ts","../src/prompt/promptCache.ts","../src/prompt/promptClients.ts","../src/prompt/types.ts","../src/score/index.ts"],"sourcesContent":["import {\n LangfuseAPIClient,\n LANGFUSE_SDK_VERSION,\n getGlobalLogger,\n getEnv,\n} from \"@langfuse/core\";\n\nimport { DatasetManager } from \"./dataset/index.js\";\nimport { MediaManager } from \"./media/index.js\";\nimport { PromptManager } from \"./prompt/index.js\";\nimport { ScoreManager } from \"./score/index.js\";\n\n/**\n * Configuration parameters for initializing a LangfuseClient instance.\n *\n * @public\n */\nexport interface LangfuseClientParams {\n /**\n * Public API key for authentication with Langfuse.\n * Can also be provided via LANGFUSE_PUBLIC_KEY environment variable.\n */\n publicKey?: string;\n\n /**\n * Secret API key for authentication with Langfuse.\n * Can also be provided via LANGFUSE_SECRET_KEY environment variable.\n */\n secretKey?: string;\n\n /**\n * Base URL of the Langfuse instance to connect to.\n * Can also be provided via LANGFUSE_BASE_URL environment variable.\n *\n * @defaultValue \"https://cloud.langfuse.com\"\n */\n baseUrl?: string;\n\n /**\n * Request timeout in seconds.\n * Can also be provided via LANGFUSE_TIMEOUT environment variable.\n *\n * @defaultValue 5\n */\n timeout?: number;\n\n /**\n * Additional HTTP headers to include with API requests.\n */\n additionalHeaders?: Record<string, string>;\n}\n\n/**\n * Main client for interacting with the Langfuse API.\n *\n * The LangfuseClient provides access to all Langfuse functionality including:\n * - Prompt management and retrieval\n * - Dataset operations\n * - Score creation and management\n * - Media upload and handling\n * - Direct API access for advanced use cases\n *\n * @example\n * ```typescript\n * // Initialize with explicit credentials\n * const langfuse = new LangfuseClient({\n * publicKey: \"pk_...\",\n * secretKey: \"sk_...\",\n * baseUrl: \"https://cloud.langfuse.com\"\n * });\n *\n * // Or use environment variables\n * const langfuse = new LangfuseClient();\n *\n * // Use the client\n * const prompt = await langfuse.prompt.get(\"my-prompt\");\n * const compiledPrompt = prompt.compile({ variable: \"value\" });\n * ```\n *\n * @public\n */\nexport class LangfuseClient {\n /**\n * Direct access to the underlying Langfuse API client.\n * Use this for advanced API operations not covered by the high-level managers.\n */\n public api: LangfuseAPIClient;\n\n /**\n * Manager for prompt operations including creation, retrieval, and caching.\n */\n public prompt: PromptManager;\n\n /**\n * Manager for dataset operations including retrieval and item linking.\n */\n public dataset: DatasetManager;\n\n /**\n * Manager for score creation and batch processing.\n */\n public score: ScoreManager;\n\n /**\n * Manager for media upload and reference resolution.\n */\n public media: MediaManager;\n\n private baseUrl: string;\n private projectId: string | null = null;\n\n /**\n * @deprecated Use prompt.get instead\n */\n public getPrompt: typeof PromptManager.prototype.get;\n /**\n * @deprecated Use prompt.create instead\n */\n public createPrompt: typeof PromptManager.prototype.create;\n /**\n * @deprecated Use prompt.update instead\n */\n public updatePrompt: typeof PromptManager.prototype.update;\n /**\n * @deprecated Use dataset.get instead\n */\n public getDataset: typeof DatasetManager.prototype.get;\n /**\n * @deprecated Use api.trace.get instead\n */\n public fetchTrace: typeof LangfuseAPIClient.prototype.trace.get;\n /**\n * @deprecated Use api.trace.list instead\n */\n public fetchTraces: typeof LangfuseAPIClient.prototype.trace.list;\n /**\n * @deprecated Use api.observations.get instead\n */\n public fetchObservation: typeof LangfuseAPIClient.prototype.observations.get;\n /**\n * @deprecated Use api.observations.list instead\n */\n public fetchObservations: typeof LangfuseAPIClient.prototype.observations.getMany;\n /**\n * @deprecated Use api.sessions.get instead\n */\n public fetchSessions: typeof LangfuseAPIClient.prototype.sessions.get;\n /**\n * @deprecated Use api.datasets.getRun instead\n */\n public getDatasetRun: typeof LangfuseAPIClient.prototype.datasets.getRun;\n /**\n * @deprecated Use api.datasets.getRuns instead\n */\n public getDatasetRuns: typeof LangfuseAPIClient.prototype.datasets.getRuns;\n /**\n * @deprecated Use api.datasets.create instead\n */\n public createDataset: typeof LangfuseAPIClient.prototype.datasets.create;\n /**\n * @deprecated Use api.datasetItems.get instead\n */\n public getDatasetItem: typeof LangfuseAPIClient.prototype.datasetItems.get;\n /**\n * @deprecated Use api.datasetItems.create instead\n */\n public createDatasetItem: typeof LangfuseAPIClient.prototype.datasetItems.create;\n /**\n * @deprecated Use api.media.get instead\n */\n public fetchMedia: typeof LangfuseAPIClient.prototype.media.get;\n /**\n * @deprecated Use media.resolveReferences instead\n */\n public resolveMediaReferences: typeof MediaManager.prototype.resolveReferences;\n\n /**\n * Creates a new LangfuseClient instance.\n *\n * @param params - Configuration parameters. If not provided, will use environment variables.\n *\n * @throws Will log warnings if required credentials are not provided\n *\n * @example\n * ```typescript\n * // With explicit configuration\n * const client = new LangfuseClient({\n * publicKey: \"pk_...\",\n * secretKey: \"sk_...\",\n * baseUrl: \"https://your-instance.langfuse.com\"\n * });\n *\n * // Using environment variables\n * const client = new LangfuseClient();\n * ```\n */\n constructor(params?: LangfuseClientParams) {\n const logger = getGlobalLogger();\n\n const publicKey = params?.publicKey ?? getEnv(\"LANGFUSE_PUBLIC_KEY\");\n const secretKey = params?.secretKey ?? getEnv(\"LANGFUSE_SECRET_KEY\");\n this.baseUrl =\n params?.baseUrl ??\n getEnv(\"LANGFUSE_BASE_URL\") ??\n getEnv(\"LANGFUSE_BASEURL\") ?? // legacy v2\n \"https://cloud.langfuse.com\";\n\n if (!publicKey) {\n logger.warn(\n \"No public key provided in constructor or as LANGFUSE_PUBLIC_KEY env var. Client operations will fail.\",\n );\n }\n if (!secretKey) {\n logger.warn(\n \"No secret key provided in constructor or as LANGFUSE_SECRET_KEY env var. Client operations will fail.\",\n );\n }\n const timeoutSeconds =\n params?.timeout ?? Number(getEnv(\"LANGFUSE_TIMEOUT\") ?? 5);\n\n this.api = new LangfuseAPIClient({\n baseUrl: this.baseUrl,\n username: publicKey,\n password: secretKey,\n xLangfusePublicKey: publicKey,\n xLangfuseSdkVersion: LANGFUSE_SDK_VERSION,\n xLangfuseSdkName: \"javascript\",\n environment: \"\", // noop as baseUrl is set\n headers: params?.additionalHeaders,\n });\n\n logger.debug(\"Initialized LangfuseClient with params:\", {\n publicKey,\n baseUrl: this.baseUrl,\n timeoutSeconds,\n });\n\n this.prompt = new PromptManager({ apiClient: this.api });\n this.dataset = new DatasetManager({ apiClient: this.api });\n this.score = new ScoreManager({ apiClient: this.api });\n this.media = new MediaManager({ apiClient: this.api });\n\n // Keep v3 compat by exposing old interface\n this.getPrompt = this.prompt.get.bind(this.prompt); // keep correct this context for cache access\n this.createPrompt = this.prompt.create.bind(this.prompt);\n this.updatePrompt = this.prompt.update.bind(this.prompt);\n this.getDataset = this.dataset.get;\n this.fetchTrace = this.api.trace.get;\n this.fetchTraces = this.api.trace.list;\n this.fetchObservation = this.api.observations.get;\n this.fetchObservations = this.api.observations.getMany;\n this.fetchSessions = this.api.sessions.get;\n this.getDatasetRun = this.api.datasets.getRun;\n this.getDatasetRuns = this.api.datasets.getRuns;\n this.createDataset = this.api.datasets.create;\n this.getDatasetItem = this.api.datasetItems.get;\n this.createDatasetItem = this.api.datasetItems.create;\n this.fetchMedia = this.api.media.get;\n this.resolveMediaReferences = this.media.resolveReferences;\n }\n\n /**\n * Flushes any pending score events to the Langfuse API.\n *\n * This method ensures all queued scores are sent immediately rather than\n * waiting for the automatic flush interval or batch size threshold.\n *\n * @returns Promise that resolves when all pending scores have been sent\n *\n * @example\n * ```typescript\n * langfuse.score.create({ name: \"quality\", value: 0.8 });\n * await langfuse.flush(); // Ensures the score is sent immediately\n * ```\n */\n public async flush() {\n return this.score.flush();\n }\n\n /**\n * Gracefully shuts down the client by flushing all pending data.\n *\n * This method should be called before your application exits to ensure\n * all data is sent to Langfuse.\n *\n * @returns Promise that resolves when shutdown is complete\n *\n * @example\n * ```typescript\n * // Before application exit\n * await langfuse.shutdown();\n * ```\n */\n public async shutdown() {\n return this.score.shutdown();\n }\n\n /**\n * Generates a URL to view a specific trace in the Langfuse UI.\n *\n * @param traceId - The ID of the trace to generate a URL for\n * @returns Promise that resolves to the trace URL\n *\n * @example\n * ```typescript\n * const traceId = \"trace-123\";\n * const url = await langfuse.getTraceUrl(traceId);\n * console.log(`View trace at: ${url}`);\n * ```\n */\n public async getTraceUrl(traceId: string) {\n let projectId = this.projectId;\n\n if (!projectId) {\n projectId = (await this.api.projects.get()).data[0].id;\n this.projectId = projectId;\n }\n\n const traceUrl = `${this.baseUrl}/project/${projectId}/traces/${traceId}`;\n\n return traceUrl;\n }\n}\n","import {\n LangfuseAPIClient,\n Dataset,\n DatasetRunItem,\n DatasetItem,\n} from \"@langfuse/core\";\nimport { Span } from \"@opentelemetry/api\";\n\n/**\n * Function type for linking dataset items to OpenTelemetry spans.\n * This allows dataset items to be associated with specific traces for experiment tracking.\n *\n * @param obj - Object containing the OpenTelemetry span\n * @param runName - Name of the dataset run\n * @param runArgs - Optional arguments for the dataset run\n * @returns Promise that resolves to the created dataset run item\n *\n * @public\n */\nexport type LinkDatasetItemFunction = (\n obj: { otelSpan: Span },\n runName: string,\n runArgs?: {\n /** Description of the dataset run */\n description?: string;\n /** Additional metadata for the dataset run */\n metadata?: any;\n },\n) => Promise<DatasetRunItem>;\n\n/**\n * Manager for dataset operations in Langfuse.\n *\n * Provides methods to retrieve datasets and their items, with automatic\n * pagination handling and convenient linking functionality for experiments.\n *\n * @public\n */\nexport class DatasetManager {\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new DatasetManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n }\n\n /**\n * Retrieves a dataset by name along with all its items.\n *\n * This method automatically handles pagination to fetch all dataset items\n * and enhances each item with a `link` function for easy experiment tracking.\n *\n * @param name - The name of the dataset to retrieve\n * @param options - Optional configuration for fetching\n * @param options.fetchItemsPageSize - Number of items to fetch per page (default: 50)\n *\n * @returns Promise that resolves to the dataset with enhanced items\n *\n * @example\n * ```typescript\n * const dataset = await langfuse.dataset.get(\"my-dataset\");\n *\n * for (const item of dataset.items) {\n * // Use the item data for your experiment\n * const result = await processItem(item.input);\n *\n * // Link the result to the dataset item\n * await item.link(\n * { otelSpan: currentSpan },\n * \"experiment-run-1\",\n * { description: \"Testing new model\" }\n * );\n * }\n * ```\n */\n async get(\n name: string,\n options?: {\n fetchItemsPageSize: number;\n },\n ): Promise<\n Dataset & {\n items: (DatasetItem & { link: LinkDatasetItemFunction })[];\n }\n > {\n const dataset = await this.apiClient.datasets.get(name);\n const items: DatasetItem[] = [];\n\n let page = 1;\n\n while (true) {\n const itemsResponse = await this.apiClient.datasetItems.list({\n datasetName: name,\n limit: options?.fetchItemsPageSize ?? 50,\n page,\n });\n\n items.push(...itemsResponse.data);\n\n if (itemsResponse.meta.totalPages <= page) {\n break;\n }\n\n page++;\n }\n\n const returnDataset = {\n ...dataset,\n items: items.map((item) => ({\n ...item,\n link: this.createDatasetItemLinkFunction(item),\n })),\n };\n\n return returnDataset;\n }\n\n /**\n * Creates a link function for a specific dataset item.\n *\n * @param item - The dataset item to create a link function for\n * @returns A function that can link the item to OpenTelemetry spans\n * @internal\n */\n private createDatasetItemLinkFunction(\n item: DatasetItem,\n ): LinkDatasetItemFunction {\n const linkFunction = async (\n obj: { otelSpan: Span },\n runName: string,\n runArgs?: {\n description?: string;\n metadata?: any;\n },\n ): Promise<DatasetRunItem> => {\n return await this.apiClient.datasetRunItems.create({\n runName,\n datasetItemId: item.id,\n traceId: obj.otelSpan.spanContext().traceId,\n runDescription: runArgs?.description,\n metadata: runArgs?.metadata,\n });\n };\n\n return linkFunction;\n }\n}\n","import {\n LangfuseAPIClient,\n ParsedMediaReference,\n MediaContentType,\n getGlobalLogger,\n bytesToBase64,\n} from \"@langfuse/core\";\n\n/**\n * Parameters for resolving media references in objects.\n *\n * @template T - The type of the object being processed\n * @public\n */\nexport type LangfuseMediaResolveMediaReferencesParams<T> = {\n /** The object to process for media references */\n obj: T;\n /** The format to resolve media references to (currently only \"base64DataUri\" is supported) */\n resolveWith: \"base64DataUri\";\n /** Maximum depth to traverse when processing nested objects (default: 10) */\n maxDepth?: number;\n};\n\n/**\n * Manager for media operations in Langfuse.\n *\n * Provides methods to resolve media references in objects by replacing\n * them with actual media content (e.g., base64 data URIs).\n *\n * @public\n */\nexport class MediaManager {\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new MediaManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n }\n\n /**\n * Replaces media reference strings in an object with base64 data URIs.\n *\n * This method recursively traverses an object looking for media reference strings\n * in the format \"@@@langfuseMedia:...@@@\". When found, it fetches the actual media\n * content from Langfuse and replaces the reference string with a base64 data URI.\n *\n * If fetching media content fails for a reference string, a warning is logged\n * and the reference string is left unchanged.\n *\n * @param params - Configuration object\n * @returns A deep copy of the input object with media references resolved\n *\n * @example\n * ```typescript\n * const obj = {\n * image: \"@@@langfuseMedia:type=image/jpeg|id=123|source=bytes@@@\",\n * nested: {\n * pdf: \"@@@langfuseMedia:type=application/pdf|id=456|source=bytes@@@\"\n * }\n * };\n *\n * const result = await langfuse.media.resolveReferences({\n * obj,\n * resolveWith: \"base64DataUri\"\n * });\n *\n * // Result:\n * // {\n * // image: \"data:image/jpeg;base64,/9j/4AAQSkZJRg...\",\n * // nested: {\n * // pdf: \"data:application/pdf;base64,JVBERi0xLjcK...\"\n * // }\n * // }\n * ```\n */\n public async resolveReferences<T>(\n params: LangfuseMediaResolveMediaReferencesParams<T>,\n ): Promise<T> {\n const { obj, maxDepth = 10 } = params;\n\n const traverse = async <T>(obj: T, depth: number): Promise<T> => {\n if (depth > maxDepth) {\n return obj;\n }\n\n // Handle string with potential media references\n if (typeof obj === \"string\") {\n const regex = /@@@langfuseMedia:.+?@@@/g;\n const referenceStringMatches = obj.match(regex);\n if (!referenceStringMatches) {\n return obj;\n }\n\n let result = obj;\n const referenceStringToMediaContentMap = new Map<string, string>();\n\n await Promise.all(\n referenceStringMatches.map(async (referenceString) => {\n try {\n const parsedMediaReference =\n MediaManager.parseReferenceString(referenceString);\n const mediaData = await this.apiClient.media.get(\n parsedMediaReference.mediaId,\n );\n const mediaContent = await fetch(mediaData.url, {\n method: \"GET\",\n headers: {},\n });\n if (mediaContent.status !== 200) {\n throw new Error(\"Failed to fetch media content\");\n }\n\n const uint8Content = new Uint8Array(\n await mediaContent.arrayBuffer(),\n );\n\n const base64MediaContent = bytesToBase64(uint8Content);\n const base64DataUri = `data:${mediaData.contentType};base64,${base64MediaContent}`;\n\n referenceStringToMediaContentMap.set(\n referenceString,\n base64DataUri,\n );\n } catch (error) {\n getGlobalLogger().warn(\n \"Error fetching media content for reference string\",\n referenceString,\n error,\n );\n }\n }),\n );\n\n for (const [\n referenceString,\n base64MediaContent,\n ] of referenceStringToMediaContentMap.entries()) {\n result = result.replaceAll(referenceString, base64MediaContent) as T &\n string;\n }\n\n return result;\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return Promise.all(\n obj.map(async (item) => await traverse(item, depth + 1)),\n ) as Promise<T>;\n }\n\n // Handle objects\n if (typeof obj === \"object\" && obj !== null) {\n return Object.fromEntries(\n await Promise.all(\n Object.entries(obj).map(async ([key, value]) => [\n key,\n await traverse(value, depth + 1),\n ]),\n ),\n );\n }\n\n return obj;\n };\n\n return traverse(obj, 0);\n }\n\n /**\n * Parses a media reference string into a ParsedMediaReference.\n *\n * Example reference string:\n * \"@@@langfuseMedia:type=image/jpeg|id=some-uuid|source=base64DataUri@@@\"\n *\n * @param referenceString - The reference string to parse.\n * @returns An object with the mediaId, source, and contentType.\n *\n * @throws Error if the reference string is invalid or missing required fields.\n */\n public static parseReferenceString(\n referenceString: string,\n ): ParsedMediaReference {\n const prefix = \"@@@langfuseMedia:\";\n const suffix = \"@@@\";\n\n if (!referenceString.startsWith(prefix)) {\n throw new Error(\n \"Reference string does not start with '@@@langfuseMedia:type='\",\n );\n }\n\n if (!referenceString.endsWith(suffix)) {\n throw new Error(\"Reference string does not end with '@@@'\");\n }\n\n const content = referenceString.slice(prefix.length, -suffix.length);\n\n const pairs = content.split(\"|\");\n const parsedData: { [key: string]: string } = {};\n\n for (const pair of pairs) {\n const [key, value] = pair.split(\"=\", 2);\n parsedData[key] = value;\n }\n\n if (\n !(\"type\" in parsedData && \"id\" in parsedData && \"source\" in parsedData)\n ) {\n throw new Error(\"Missing required fields in reference string\");\n }\n\n return {\n mediaId: parsedData[\"id\"],\n source: parsedData[\"source\"],\n contentType: parsedData[\"type\"] as MediaContentType,\n };\n }\n}\n","import {\n CreatePromptRequest,\n getGlobalLogger,\n LangfuseAPIClient,\n PlaceholderMessage,\n Prompt,\n ChatMessage,\n} from \"@langfuse/core\";\n\nimport { LangfusePromptCache } from \"./promptCache.js\";\nimport {\n ChatPromptClient,\n TextPromptClient,\n LangfusePromptClient,\n} from \"./promptClients.js\";\nimport {\n ChatMessageType,\n CreateChatPromptBodyWithPlaceholders,\n} from \"./types.js\";\n\n/**\n * Manager for prompt operations in Langfuse.\n *\n * Provides methods to create, retrieve, and manage prompts with built-in caching\n * for optimal performance. Supports both text and chat prompts with variable\n * substitution and placeholder functionality.\n *\n * @public\n */\nexport class PromptManager {\n private cache: LangfusePromptCache;\n private apiClient: LangfuseAPIClient;\n\n /**\n * Creates a new PromptManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n const { apiClient } = params;\n\n this.apiClient = apiClient;\n this.cache = new LangfusePromptCache();\n }\n\n get logger() {\n return getGlobalLogger();\n }\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (chat prompt)\n * @returns Promise that resolves to a ChatPromptClient\n */\n async create(\n body: CreateChatPromptBodyWithPlaceholders,\n ): Promise<ChatPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (text prompt)\n * @returns Promise that resolves to a TextPromptClient\n */\n async create(\n body: Omit<CreatePromptRequest.Text, \"type\"> & { type?: \"text\" },\n ): Promise<TextPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * @param body - The prompt data to create (chat prompt)\n * @returns Promise that resolves to a ChatPromptClient\n */\n async create(body: CreatePromptRequest.Chat): Promise<ChatPromptClient>;\n\n /**\n * Creates a new prompt in Langfuse.\n *\n * Supports both text and chat prompts. Chat prompts can include placeholders\n * for dynamic content insertion.\n *\n * @param body - The prompt data to create\n * @returns Promise that resolves to the appropriate prompt client\n *\n * @example\n * ```typescript\n * // Create a text prompt\n * const textPrompt = await langfuse.prompt.create({\n * name: \"greeting\",\n * prompt: \"Hello {{name}}!\",\n * type: \"text\"\n * });\n *\n * // Create a chat prompt\n * const chatPrompt = await langfuse.prompt.create({\n * name: \"conversation\",\n * type: \"chat\",\n * prompt: [\n * { role: \"system\", content: \"You are a helpful assistant.\" },\n * { role: \"user\", content: \"{{user_message}}\" }\n * ]\n * });\n * ```\n */\n async create(\n body:\n | CreatePromptRequest.Chat\n | (Omit<CreatePromptRequest.Text, \"type\"> & { type?: \"text\" })\n | CreateChatPromptBodyWithPlaceholders,\n ): Promise<LangfusePromptClient> {\n const requestBody: CreatePromptRequest =\n body.type === \"chat\"\n ? {\n ...body,\n prompt: body.prompt.map((item) => {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n return {\n type: ChatMessageType.Placeholder,\n name: (item as PlaceholderMessage).name,\n };\n } else {\n // Handle regular ChatMessage (without type field) from API\n return { type: ChatMessageType.ChatMessage, ...item };\n }\n }),\n }\n : {\n ...body,\n type: body.type ?? \"text\",\n };\n\n const promptResponse = await this.apiClient.prompts.create(requestBody);\n\n if (promptResponse.type === \"chat\") {\n return new ChatPromptClient(promptResponse);\n }\n\n return new TextPromptClient(promptResponse);\n }\n\n /**\n * Updates the labels of an existing prompt version.\n *\n * @param params - Update parameters\n * @param params.name - Name of the prompt to update\n * @param params.version - Version number of the prompt to update\n * @param params.newLabels - New labels to apply to the prompt version\n *\n * @returns Promise that resolves to the updated prompt\n *\n * @example\n * ```typescript\n * const updatedPrompt = await langfuse.prompt.update({\n * name: \"my-prompt\",\n * version: 1,\n * newLabels: [\"production\", \"v2\"]\n * });\n * ```\n */\n async update(params: {\n name: string;\n version: number;\n newLabels: string[];\n }): Promise<Prompt> {\n const { name, version, newLabels } = params;\n\n const newPrompt = await this.apiClient.promptVersion.update(name, version, {\n newLabels,\n });\n\n this.cache.invalidate(name);\n\n return newPrompt;\n }\n\n /**\n * Retrieves a text prompt by name.\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to a TextPromptClient\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback text content if prompt fetch fails */\n fallback?: string;\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Specify text prompt type */\n type?: \"text\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<TextPromptClient>;\n\n /**\n * Retrieves a chat prompt by name.\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to a ChatPromptClient\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback chat messages if prompt fetch fails */\n fallback?: ChatMessage[];\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Specify chat prompt type */\n type: \"chat\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<ChatPromptClient>;\n\n /**\n * Retrieves a prompt by name with intelligent caching.\n *\n * This method implements sophisticated caching behavior:\n * - Fresh prompts are returned immediately from cache\n * - Expired prompts are returned from cache while being refreshed in background\n * - Cache misses trigger immediate fetch with optional fallback support\n *\n * @param name - Name of the prompt to retrieve\n * @param options - Optional retrieval configuration\n * @returns Promise that resolves to the appropriate prompt client\n *\n * @example\n * ```typescript\n * // Get latest version with caching\n * const prompt = await langfuse.prompt.get(\"my-prompt\");\n *\n * // Get specific version\n * const v2Prompt = await langfuse.prompt.get(\"my-prompt\", {\n * version: 2\n * });\n *\n * // Get with label filter\n * const prodPrompt = await langfuse.prompt.get(\"my-prompt\", {\n * label: \"production\"\n * });\n *\n * // Get with fallback\n * const promptWithFallback = await langfuse.prompt.get(\"my-prompt\", {\n * type: \"text\",\n * fallback: \"Hello {{name}}!\"\n * });\n * ```\n */\n async get(\n name: string,\n options?: {\n /** Specific version to retrieve (defaults to latest) */\n version?: number;\n /** Label to filter by */\n label?: string;\n /** Cache TTL in seconds (0 to disable caching) */\n cacheTtlSeconds?: number;\n /** Fallback content if prompt fetch fails */\n fallback?: ChatMessage[] | string;\n /** Maximum retry attempts for failed requests */\n maxRetries?: number;\n /** Prompt type (auto-detected if not specified) */\n type?: \"chat\" | \"text\";\n /** Request timeout in milliseconds */\n fetchTimeoutMs?: number;\n },\n ): Promise<LangfusePromptClient> {\n const cacheKey = this.cache.createKey({\n name,\n label: options?.label,\n });\n const cachedPrompt = this.cache.getIncludingExpired(cacheKey);\n if (!cachedPrompt || options?.cacheTtlSeconds === 0) {\n try {\n return await this.fetchPromptAndUpdateCache({\n name,\n version: options?.version,\n label: options?.label,\n cacheTtlSeconds: options?.cacheTtlSeconds,\n maxRetries: options?.maxRetries,\n fetchTimeoutMs: options?.fetchTimeoutMs,\n });\n } catch (err) {\n if (options?.fallback) {\n const sharedFallbackParams = {\n name,\n version: options?.version ?? 0,\n labels: options.label ? [options.label] : [],\n cacheTtlSeconds: options?.cacheTtlSeconds,\n config: {},\n tags: [],\n };\n\n if (options.type === \"chat\") {\n return new ChatPromptClient(\n {\n ...sharedFallbackParams,\n type: \"chat\",\n prompt: (options.fallback as ChatMessage[]).map((msg) => ({\n type: ChatMessageType.ChatMessage,\n ...msg,\n })),\n },\n true,\n );\n } else {\n return new TextPromptClient(\n {\n ...sharedFallbackParams,\n type: \"text\",\n prompt: options.fallback as string,\n },\n true,\n );\n }\n }\n\n throw err;\n }\n }\n\n if (cachedPrompt.isExpired) {\n // If the cache is not currently being refreshed, start refreshing it and register the promise in the cache\n if (!this.cache.isRefreshing(cacheKey)) {\n const refreshPromptPromise = this.fetchPromptAndUpdateCache({\n name,\n version: options?.version,\n label: options?.label,\n cacheTtlSeconds: options?.cacheTtlSeconds,\n maxRetries: options?.maxRetries,\n fetchTimeoutMs: options?.fetchTimeoutMs,\n }).catch(() => {\n this.logger.warn(\n `Failed to refresh prompt cache '${cacheKey}', stale cache will be used until next refresh succeeds.`,\n );\n });\n this.cache.addRefreshingPromise(cacheKey, refreshPromptPromise);\n }\n\n return cachedPrompt.value;\n }\n\n return cachedPrompt.value;\n }\n\n private async fetchPromptAndUpdateCache(params: {\n name: string;\n version?: number;\n cacheTtlSeconds?: number;\n label?: string;\n maxRetries?: number;\n fetchTimeoutMs?: number;\n }): Promise<LangfusePromptClient> {\n const cacheKey = this.cache.createKey(params);\n\n try {\n const {\n name,\n version,\n cacheTtlSeconds,\n label,\n maxRetries,\n fetchTimeoutMs,\n } = params;\n\n const data = await this.apiClient.prompts.get(\n name,\n {\n version,\n label,\n },\n {\n maxRetries,\n timeoutInSeconds: fetchTimeoutMs ? fetchTimeoutMs / 1_000 : undefined,\n },\n );\n\n let prompt: LangfusePromptClient;\n if (data.type === \"chat\") {\n prompt = new ChatPromptClient(data);\n } else {\n prompt = new TextPromptClient(data);\n }\n\n this.cache.set(cacheKey, prompt, cacheTtlSeconds);\n\n return prompt;\n } catch (error) {\n this.logger.error(`Error fetching prompt '${cacheKey}':`, error);\n\n throw error;\n }\n }\n}\n","import { getGlobalLogger } from \"@langfuse/core\";\n\nimport type { LangfusePromptClient } from \"./promptClients.js\";\n\nexport const DEFAULT_PROMPT_CACHE_TTL_SECONDS = 60;\n\nclass LangfusePromptCacheItem {\n private _expiry: number;\n\n constructor(\n public value: LangfusePromptClient,\n ttlSeconds: number,\n ) {\n this._expiry = Date.now() + ttlSeconds * 1000;\n }\n\n get isExpired(): boolean {\n return Date.now() > this._expiry;\n }\n}\nexport class LangfusePromptCache {\n private _cache: Map<string, LangfusePromptCacheItem>;\n private _defaultTtlSeconds: number;\n private _refreshingKeys: Map<string, Promise<void>>;\n\n constructor() {\n this._cache = new Map<string, LangfusePromptCacheItem>();\n this._defaultTtlSeconds = DEFAULT_PROMPT_CACHE_TTL_SECONDS;\n this._refreshingKeys = new Map<string, Promise<void>>();\n }\n\n public getIncludingExpired(key: string): LangfusePromptCacheItem | null {\n return this._cache.get(key) ?? null;\n }\n\n public createKey(params: {\n name: string;\n version?: number;\n label?: string;\n }): string {\n const { name, version, label } = params;\n const parts = [name];\n\n if (version !== undefined) {\n parts.push(\"version:\" + version.toString());\n } else if (label !== undefined) {\n parts.push(\"label:\" + label);\n } else {\n parts.push(\"label:production\");\n }\n\n return parts.join(\"-\");\n }\n\n public set(\n key: string,\n value: LangfusePromptClient,\n ttlSeconds?: number,\n ): void {\n const effectiveTtlSeconds = ttlSeconds ?? this._defaultTtlSeconds;\n this._cache.set(\n key,\n new LangfusePromptCacheItem(value, effectiveTtlSeconds),\n );\n }\n\n public addRefreshingPromise(key: string, promise: Promise<any>): void {\n this._refreshingKeys.set(key, promise);\n promise\n .then(() => {\n this._refreshingKeys.delete(key);\n })\n .catch(() => {\n this._refreshingKeys.delete(key);\n });\n }\n\n public isRefreshing(key: string): boolean {\n return this._refreshingKeys.has(key);\n }\n\n public invalidate(promptName: string): void {\n getGlobalLogger().debug(\n \"Invalidating cache keys for\",\n promptName,\n this._cache.keys(),\n );\n\n for (const key of this._cache.keys()) {\n if (key.startsWith(promptName)) {\n this._cache.delete(key);\n }\n }\n }\n}\n","import {\n Prompt,\n ChatMessage,\n BasePrompt,\n ChatMessageWithPlaceholders,\n} from \"@langfuse/core\";\nimport mustache from \"mustache\";\n\nimport {\n ChatMessageOrPlaceholder,\n ChatMessageType,\n LangchainMessagesPlaceholder,\n} from \"./types.js\";\n\nmustache.escape = function (text) {\n return text;\n};\n\n/**\n * Base class for all prompt clients.\n *\n * @internal\n */\nabstract class BasePromptClient {\n /** The name of the prompt */\n public readonly name: string;\n /** The version number of the prompt */\n public readonly version: number;\n /** Configuration object associated with the prompt */\n public readonly config: unknown;\n /** Labels associated with the prompt */\n public readonly labels: string[];\n /** Tags associated with the prompt */\n public readonly tags: string[];\n /** Whether this prompt client is using fallback content */\n public readonly isFallback: boolean;\n /** The type of prompt (\"text\" or \"chat\") */\n public readonly type: \"text\" | \"chat\";\n /** Optional commit message for the prompt version */\n public readonly commitMessage: string | null | undefined;\n\n /**\n * Creates a new BasePromptClient instance.\n *\n * @param prompt - The base prompt data\n * @param isFallback - Whether this is fallback content\n * @param type - The prompt type\n * @internal\n */\n constructor(prompt: BasePrompt, isFallback = false, type: \"text\" | \"chat\") {\n this.name = prompt.name;\n this.version = prompt.version;\n this.config = prompt.config;\n this.labels = prompt.labels;\n this.tags = prompt.tags;\n this.isFallback = isFallback;\n this.type = type;\n this.commitMessage = prompt.commitMessage;\n }\n\n /** Gets the raw prompt content */\n abstract get prompt(): string | ChatMessageWithPlaceholders[];\n\n /** Sets the raw prompt content */\n abstract set prompt(value: string | ChatMessageWithPlaceholders[]);\n\n /**\n * Compiles the prompt by substituting variables and resolving placeholders.\n *\n * @param variables - Key-value pairs for variable substitution\n * @param placeholders - Key-value pairs for placeholder resolution\n * @returns The compiled prompt content\n */\n abstract compile(\n variables?: Record<string, string>,\n placeholders?: Record<string, any>,\n ): string | ChatMessage[] | (ChatMessageOrPlaceholder | any)[];\n\n /**\n * Converts the prompt to a format compatible with LangChain.\n *\n * @param options - Options for conversion\n * @param options.placeholders - Placeholders to resolve during conversion\n * @returns The prompt in LangChain-compatible format\n */\n public abstract getLangchainPrompt(options?: {\n placeholders?: Record<string, any>;\n }):\n | string\n | ChatMessage[]\n | ChatMessageOrPlaceholder[]\n | (ChatMessage | LangchainMessagesPlaceholder | any)[];\n\n protected _transformToLangchainVariables(content: string): string {\n const jsonEscapedContent = this.escapeJsonForLangchain(content);\n\n return jsonEscapedContent.replace(/\\{\\{(\\w+)\\}\\}/g, \"{$1}\");\n }\n\n /**\n * Escapes every curly brace that is part of a JSON object by doubling it.\n *\n * A curly brace is considered “JSON-related” when, after skipping any immediate\n * whitespace, the next non-whitespace character is a single (') or double (\") quote.\n *\n * Braces that are already doubled (e.g. `{{variable}}` placeholders) are left untouched.\n *\n * @param text - Input string that may contain JSON snippets.\n * @returns The string with JSON-related braces doubled.\n */\n protected escapeJsonForLangchain(text: string): string {\n const out: string[] = []; // collected characters\n const stack: boolean[] = []; // true = “this { belongs to JSON”, false = normal “{”\n let i = 0;\n const n = text.length;\n\n while (i < n) {\n const ch = text[i];\n\n // ---------- opening brace ----------\n if (ch === \"{\") {\n // leave existing “{{ …” untouched\n if (i + 1 < n && text[i + 1] === \"{\") {\n out.push(\"{{\");\n i += 2;\n continue;\n }\n\n // look ahead to find the next non-space character\n let j = i + 1;\n while (j < n && /\\s/.test(text[j])) {\n j++;\n }\n\n const isJson = j < n && (text[j] === \"'\" || text[j] === '\"');\n out.push(isJson ? \"{{\" : \"{\");\n stack.push(isJson); // remember how this “{” was treated\n i += 1;\n continue;\n }\n\n // ---------- closing brace ----------\n if (ch === \"}\") {\n // leave existing “… }}” untouched\n if (i + 1 < n && text[i + 1] === \"}\") {\n out.push(\"}}\");\n i += 2;\n continue;\n }\n\n const isJson = stack.pop() ?? false;\n out.push(isJson ? \"}}\" : \"}\");\n i += 1;\n continue;\n }\n\n // ---------- any other character ----------\n out.push(ch);\n i += 1;\n }\n\n return out.join(\"\");\n }\n\n /**\n * Serializes the prompt client to JSON.\n *\n * @returns JSON string representation of the prompt\n */\n public abstract toJSON(): string;\n}\n\n/**\n * Client for working with text-based prompts.\n *\n * Provides methods to compile text prompts with variable substitution\n * and convert them to LangChain-compatible formats.\n *\n * @public\n */\nexport class TextPromptClient extends BasePromptClient {\n /** The original prompt response from the API */\n public readonly promptResponse: Prompt.Text;\n /** The text content of the prompt */\n public readonly prompt: string;\n\n /**\n * Creates a new TextPromptClient instance.\n *\n * @param prompt - The text prompt data\n * @param isFallback - Whether this is fallback content\n */\n constructor(prompt: Prompt.Text, isFallback = false) {\n super(prompt, isFallback, \"text\");\n this.promptResponse = prompt;\n this.prompt = prompt.prompt;\n }\n\n /**\n * Compiles the text prompt by substituting variables.\n *\n * Uses Mustache templating to replace {{variable}} placeholders with provided values.\n *\n * @param variables - Key-value pairs for variable substitution\n * @param _placeholders - Ignored for text prompts\n * @returns The compiled text with variables substituted\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"greeting\", { type: \"text\" });\n * const compiled = prompt.compile({ name: \"Alice\" });\n * // If prompt is \"Hello {{name}}!\", result is \"Hello Alice!\"\n * ```\n */\n compile(\n variables?: Record<string, string>,\n _placeholders?: Record<string, any>,\n ): string {\n return mustache.render(this.promptResponse.prompt, variables ?? {});\n }\n\n /**\n * Converts the prompt to LangChain PromptTemplate format.\n *\n * Transforms Mustache-style {{variable}} syntax to LangChain's {variable} format.\n *\n * @param _options - Ignored for text prompts\n * @returns The prompt string compatible with LangChain PromptTemplate\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"greeting\", { type: \"text\" });\n * const langchainFormat = prompt.getLangchainPrompt();\n * // Transforms \"Hello {{name}}!\" to \"Hello {name}!\"\n * ```\n */\n public getLangchainPrompt(_options?: {\n placeholders?: Record<string, any>;\n }): string {\n return this._transformToLangchainVariables(this.prompt);\n }\n\n public toJSON(): string {\n return JSON.stringify({\n name: this.name,\n prompt: this.prompt,\n version: this.version,\n isFallback: this.isFallback,\n tags: this.tags,\n labels: this.labels,\n type: this.type,\n config: this.config,\n });\n }\n}\n\n/**\n * Client for working with chat-based prompts.\n *\n * Provides methods to compile chat prompts with variable substitution and\n * placeholder resolution, and convert them to LangChain-compatible formats.\n *\n * @public\n */\nexport class ChatPromptClient extends BasePromptClient {\n /** The original prompt response from the API */\n public readonly promptResponse: Prompt.Chat;\n /** The chat messages that make up the prompt */\n public readonly prompt: ChatMessageWithPlaceholders[];\n\n /**\n * Creates a new ChatPromptClient instance.\n *\n * @param prompt - The chat prompt data\n * @param isFallback - Whether this is fallback content\n */\n constructor(prompt: Prompt.Chat, isFallback = false) {\n const normalizedPrompt = ChatPromptClient.normalizePrompt(prompt.prompt);\n const typedPrompt: Prompt.Chat = {\n ...prompt,\n prompt: normalizedPrompt,\n };\n\n super(typedPrompt, isFallback, \"chat\");\n this.promptResponse = typedPrompt;\n this.prompt = normalizedPrompt;\n }\n\n private static normalizePrompt(\n prompt: ChatMessage[] | ChatMessageWithPlaceholders[],\n ): ChatMessageWithPlaceholders[] {\n // Convert ChatMessages to ChatMessageWithPlaceholders for backward compatibility\n return prompt.map((item): ChatMessageWithPlaceholders => {\n if (\"type\" in item) {\n // Already has type field (new format)\n return item as ChatMessageWithPlaceholders;\n } else {\n // Plain ChatMessage (legacy format) - add type field\n return {\n type: ChatMessageType.ChatMessage,\n ...item,\n } as ChatMessageWithPlaceholders;\n }\n });\n }\n\n /**\n * Compiles the chat prompt by replacing placeholders and variables.\n *\n * First resolves placeholders with provided values, then applies variable substitution\n * to message content using Mustache templating. Unresolved placeholders remain\n * as placeholder objects in the output.\n *\n * @param variables - Key-value pairs for Mustache variable substitution in message content\n * @param placeholders - Key-value pairs where keys are placeholder names and values are ChatMessage arrays\n * @returns Array of ChatMessage objects and unresolved placeholder objects\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"conversation\", { type: \"chat\" });\n * const compiled = prompt.compile(\n * { user_name: \"Alice\" },\n * { examples: [{ role: \"user\", content: \"Hello\" }, { role: \"assistant\", content: \"Hi!\" }] }\n * );\n * ```\n */\n compile(\n variables?: Record<string, string>,\n placeholders?: Record<string, any>,\n ): (ChatMessageOrPlaceholder | any)[] {\n const messagesWithPlaceholdersReplaced: (ChatMessageOrPlaceholder | any)[] =\n [];\n const placeholderValues = placeholders ?? {};\n\n for (const item of this.prompt) {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n const placeholderValue = placeholderValues[item.name];\n if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length > 0 &&\n placeholderValue.every(\n (msg) =>\n typeof msg === \"object\" && \"role\" in msg && \"content\" in msg,\n )\n ) {\n messagesWithPlaceholdersReplaced.push(\n ...(placeholderValue as ChatMessage[]),\n );\n } else if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length === 0\n ) {\n // Empty array provided - skip placeholder (don't include it)\n } else if (placeholderValue !== undefined) {\n // Non-standard placeholder value format, just stringfiy\n messagesWithPlaceholdersReplaced.push(\n JSON.stringify(placeholderValue),\n );\n } else {\n // Keep unresolved placeholder in the output\n messagesWithPlaceholdersReplaced.push(\n item as { type: ChatMessageType.Placeholder } & typeof item,\n );\n }\n } else if (\n \"role\" in item &&\n \"content\" in item &&\n item.type === ChatMessageType.ChatMessage\n ) {\n messagesWithPlaceholdersReplaced.push({\n role: item.role,\n content: item.content,\n });\n }\n }\n\n return messagesWithPlaceholdersReplaced.map((item) => {\n if (\n typeof item === \"object\" &&\n item !== null &&\n \"role\" in item &&\n \"content\" in item\n ) {\n return {\n ...item,\n content: mustache.render(item.content, variables ?? {}),\n };\n } else {\n // Return placeholder or stringified value as-is\n return item;\n }\n });\n }\n\n /**\n * Converts the prompt to LangChain ChatPromptTemplate format.\n *\n * Resolves placeholders with provided values and converts unresolved ones\n * to LangChain MessagesPlaceholder objects. Transforms variables from\n * {{var}} to {var} format without rendering them.\n *\n * @param options - Configuration object\n * @param options.placeholders - Key-value pairs for placeholder resolution\n * @returns Array of ChatMessage objects and LangChain MessagesPlaceholder objects\n *\n * @example\n * ```typescript\n * const prompt = await langfuse.prompt.get(\"conversation\", { type: \"chat\" });\n * const langchainFormat = prompt.getLangchainPrompt({\n * placeholders: { examples: [{ role: \"user\", content: \"Hello\" }] }\n * });\n * ```\n */\n public getLangchainPrompt(options?: {\n placeholders?: Record<string, any>;\n }): (ChatMessage | LangchainMessagesPlaceholder | any)[] {\n const messagesWithPlaceholdersReplaced: (\n | ChatMessage\n | LangchainMessagesPlaceholder\n | any\n )[] = [];\n const placeholderValues = options?.placeholders ?? {};\n\n for (const item of this.prompt) {\n if (\"type\" in item && item.type === ChatMessageType.Placeholder) {\n const placeholderValue = placeholderValues[item.name];\n if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length > 0 &&\n placeholderValue.every(\n (msg) =>\n typeof msg === \"object\" && \"role\" in msg && \"content\" in msg,\n )\n ) {\n // Complete placeholder fill-in, replace with it\n messagesWithPlaceholdersReplaced.push(\n ...(placeholderValue as ChatMessage[]).map((msg) => {\n return {\n role: msg.role,\n content: this._transformToLangchainVariables(msg.content),\n };\n }),\n );\n } else if (\n Array.isArray(placeholderValue) &&\n placeholderValue.length === 0\n ) {\n // Skip empty array placeholder\n } else if (placeholderValue !== undefined) {\n // Non-standard placeholder value, just stringify and add directly\n messagesWithPlaceholdersReplaced.push(\n JSON.stringify(placeholderValue),\n );\n } else {\n // Convert unresolved placeholder to Langchain MessagesPlaceholder\n messagesWithPlaceholdersReplaced.push({\n variableName: item.name,\n optional: false,\n });\n }\n } else if (\n \"role\" in item &&\n \"content\" in item &&\n item.type === ChatMessageType.ChatMessage\n ) {\n messagesWithPlaceholdersReplaced.push({\n role: item.role,\n content: this._transformToLangchainVariables(item.content),\n });\n }\n }\n\n return messagesWithPlaceholdersReplaced;\n }\n\n public toJSON(): string {\n return JSON.stringify({\n name: this.name,\n prompt: this.promptResponse.prompt.map((item) => {\n if (\"type\" in item && item.type === ChatMessageType.ChatMessage) {\n const { type: _, ...messageWithoutType } = item;\n return messageWithoutType;\n }\n return item;\n }),\n version: this.version,\n isFallback: this.isFallback,\n tags: this.tags,\n labels: this.labels,\n type: this.type,\n config: this.config,\n });\n }\n}\n\n/**\n * Union type representing either a text or chat prompt client.\n *\n * @public\n */\nexport type LangfusePromptClient = TextPromptClient | ChatPromptClient;\n","import {\n ChatMessage,\n PlaceholderMessage,\n ChatMessageWithPlaceholders,\n CreatePromptRequest,\n} from \"@langfuse/core\";\n\n/**\n * Enumeration of chat message types in Langfuse prompts.\n *\n * @public\n */\nexport enum ChatMessageType {\n /** Regular chat message with role and content */\n ChatMessage = \"chatmessage\",\n /** Placeholder for dynamic content insertion */\n Placeholder = \"placeholder\",\n}\n\n/**\n * Union type representing either a chat message or a placeholder.\n *\n * Used in compiled prompts where placeholders may remain unresolved.\n *\n * @public\n */\nexport type ChatMessageOrPlaceholder =\n | ChatMessage\n | ({ type: ChatMessageType.Placeholder } & PlaceholderMessage);\n\n/**\n * Represents a LangChain MessagesPlaceholder object.\n *\n * Used when converting Langfuse prompts to LangChain format,\n * unresolved placeholders become LangChain MessagesPlaceholder objects.\n *\n * @public\n */\nexport type LangchainMessagesPlaceholder = {\n /** Name of the variable that will provide the messages */\n variableName: string;\n /** Whether the placeholder is optional (defaults to false) */\n optional?: boolean;\n};\n\n/**\n * Type for creating chat prompts that support both regular messages and placeholders.\n *\n * Extends the standard chat prompt creation request to allow mixed content types.\n *\n * @public\n */\nexport type CreateChatPromptBodyWithPlaceholders = {\n /** Specifies this is a chat prompt */\n type: \"chat\";\n} & Omit<CreatePromptRequest.Chat, \"type\" | \"prompt\"> & {\n /** Array of chat messages and/or placeholders */\n prompt: (ChatMessage | ChatMessageWithPlaceholders)[];\n };\n","import {\n LangfuseAPIClient,\n IngestionEvent,\n getEnv,\n generateUUID,\n ScoreBody,\n getGlobalLogger,\n safeSetTimeout,\n IngestionResponse,\n} from \"@langfuse/core\";\nimport { Span, trace } from \"@opentelemetry/api\";\n\nconst MAX_QUEUE_SIZE = 100_000; // prevent memory leaks\nconst MAX_BATCH_SIZE = 100;\n\n/**\n * Manager for creating and batching score events in Langfuse.\n *\n * The ScoreManager handles automatic batching and flushing of score events\n * to optimize API usage. Scores are automatically sent when the queue reaches\n * a certain size or after a time interval.\n *\n * @public\n */\nexport class ScoreManager {\n private apiClient: LangfuseAPIClient;\n private eventQueue: IngestionEvent[] = [];\n private flushPromise: Promise<void> | null = null;\n private flushTimer: any = null;\n private flushAtCount: number;\n private flushIntervalSeconds: number;\n\n /**\n * Creates a new ScoreManager instance.\n *\n * @param params - Configuration object containing the API client\n * @internal\n */\n constructor(params: { apiClient: LangfuseAPIClient }) {\n this.apiClient = params.apiClient;\n\n const envFlushAtCount = getEnv(\"LANGFUSE_FLUSH_AT\");\n const envFlushIntervalSeconds = getEnv(\"LANGFUSE_FLUSH_INTERVAL\");\n\n this.flushAtCount = envFlushAtCount ? Number(envFlushAtCount) : 10;\n this.flushIntervalSeconds = envFlushIntervalSeconds\n ? Number(envFlushIntervalSeconds)\n : 1;\n }\n\n get logger() {\n return getGlobalLogger();\n }\n\n /**\n * Creates a new score event and adds it to the processing queue.\n *\n * Scores are queued and sent in batches for efficiency. The score will be\n * automatically sent when the queue reaches the flush threshold or after\n * the flush interval expires.\n *\n * @param data - The score data to create\n *\n * @example\n * ```typescript\n * langfuse.score.create({\n * name: \"quality\",\n * value: 0.85,\n * traceId: \"trace-123\",\n * comment: \"High quality response\"\n * });\n * ```\n */\n public create(data: ScoreBody): void {\n const scoreData: ScoreBody = {\n ...data,\n id: data.id ?? generateUUID(),\n environment: data.environment ?? getEnv(\"LANGFUSE_TRACING_ENVIRONMENT\"),\n };\n\n const scoreIngestionEvent: IngestionEvent = {\n id: generateUUID(),\n type: \"score-create\",\n timestamp: new Date().toISOString(),\n body: scoreData,\n };\n\n if (this.eventQueue.length >= MAX_QUEUE_SIZE) {\n this.logger.error(\n `Score queue is at max size ${MAX_QUEUE_SIZE}. Dropping score.`,\n );\n return;\n }\n\n this.eventQueue.push(scoreIngestionEvent);\n\n if (this.eventQueue.length >= this.flushAtCount) {\n this.flushPromise = this.flush();\n } else if (!this.flushTimer) {\n this.flushTimer = safeSetTimeout(() => {\n this.flushPromise = this.flush();\n }, this.flushIntervalSeconds * 1_000);\n }\n }\n\n /**\n * Creates a score for a specific observation using its OpenTelemetry span.\n *\n * This method automatically extracts the trace ID and observation ID from\n * the provided span context.\n *\n * @param observation - Object containing the OpenTelemetry span\n * @param data - Score data (traceId and observationId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startSpan } from '@langfuse/tracing';\n *\n * const span = startSpan({ name: \"my-operation\" });\n * langfuse.score.observation(\n * { otelSpan: span },\n * { name: \"accuracy\", value: 0.92 }\n * );\n * ```\n */\n public observation(\n observation: { otelSpan: Span },\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const { spanId, traceId } = observation.otelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n observationId: spanId,\n });\n }\n\n /**\n * Creates a score for a trace using an OpenTelemetry span.\n *\n * This method automatically extracts the trace ID from the provided\n * span context and creates a trace-level score.\n *\n * @param observation - Object containing the OpenTelemetry span\n * @param data - Score data (traceId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startSpan } from '@langfuse/tracing';\n *\n * const span = startSpan({ name: \"my-operation\" });\n * langfuse.score.trace(\n * { otelSpan: span },\n * { name: \"overall_quality\", value: 0.88 }\n * );\n * ```\n */\n public trace(\n observation: { otelSpan: Span },\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const { traceId } = observation.otelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n });\n }\n\n /**\n * Creates a score for the currently active observation.\n *\n * This method automatically detects the active OpenTelemetry span and\n * creates an observation-level score. If no active span is found,\n * a warning is logged and the operation is skipped.\n *\n * @param data - Score data (traceId and observationId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startActiveSpan } from '@langfuse/tracing';\n *\n * startActiveSpan({ name: \"my-operation\" }, (span) => {\n * // Inside the active span\n * langfuse.score.activeObservation({\n * name: \"relevance\",\n * value: 0.95\n * });\n * });\n * ```\n */\n public activeObservation(\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const currentOtelSpan = trace.getActiveSpan();\n if (!currentOtelSpan) {\n this.logger.warn(\"No active span in context to score.\");\n\n return;\n }\n\n const { spanId, traceId } = currentOtelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n observationId: spanId,\n });\n }\n\n /**\n * Creates a score for the currently active trace.\n *\n * This method automatically detects the active OpenTelemetry span and\n * creates a trace-level score. If no active span is found,\n * a warning is logged and the operation is skipped.\n *\n * @param data - Score data (traceId will be auto-populated)\n *\n * @example\n * ```typescript\n * import { startActiveSpan } from '@langfuse/tracing';\n *\n * startActiveSpan({ name: \"my-operation\" }, (span) => {\n * // Inside the active span\n * langfuse.score.activeTrace({\n * name: \"user_satisfaction\",\n * value: 4,\n * comment: \"User rated 4 out of 5 stars\"\n * });\n * });\n * ```\n */\n public activeTrace(\n data: Omit<\n ScoreBody,\n \"traceId\" | \"sessionId\" | \"observationId\" | \"datasetRunId\"\n >,\n ) {\n const currentOtelSpan = trace.getActiveSpan();\n if (!currentOtelSpan) {\n this.logger.warn(\"No active span in context to score trace.\");\n\n return;\n }\n\n const { traceId } = currentOtelSpan.spanContext();\n\n this.create({\n ...data,\n traceId,\n });\n }\n\n private async handleFlush() {\n try {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n const promises: Promise<IngestionResponse | void>[] = [];\n\n while (this.eventQueue.length > 0) {\n const batch = this.eventQueue.splice(0, MAX_BATCH_SIZE);\n\n promises.push(\n this.apiClient.ingestion\n .batch({ batch })\n .then((res) => {\n if (res.errors?.length > 0) {\n this.logger.error(\"Error ingesting scores:\", res.errors);\n }\n })\n .catch((err) => {\n this.logger.error(\"Failed to export score batch:\", err);\n }),\n );\n }\n\n await Promise.all(promises);\n } catch (err) {\n this.logger.error(\"Error flushing Score Manager: \", err);\n } finally {\n this.flushPromise = null;\n }\n }\n\n /**\n * Flushes all pending score events to the Langfuse API.\n *\n * This method ensures all queued scores are sent immediately rather than\n * waiting for the automatic flush interval or batch size threshold.\n *\n * @returns Promise that resolves when all pending scores have been sent\n *\n * @example\n * ```typescript\n * langfuse.score.create({ name: \"quality\", value: 0.8 });\n * await langfuse.score.flush(); // Ensures the score is sent immediately\n * ```\n */\n public async flush() {\n return this.flushPromise ?? this.handleFlush();\n }\n\n /**\n * Gracefully shuts down the score manager by flushing all pending scores.\n *\n * This method should be called before your application exits to ensure\n * all score data is sent to Langfuse.\n *\n * @returns Promise that resolves when shutdown is complete\n *\n * @example\n * ```typescript\n * // Before application exit\n * await langfuse.score.shutdown();\n * ```\n */\n public async shutdown() {\n await this.flush();\n }\n}\n"],"mappings":"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","names":["LangfuseAPIClient","getGlobalLogger","getEnv","obj","getGlobalLogger","getGlobalLogger","ChatMessageType","getGlobalLogger","getGlobalLogger","getGlobalLogger","getEnv","LangfuseAPIClient"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langfuse/client",
3
- "version": "4.0.0-beta.4",
3
+ "version": "4.0.0-beta.6",
4
4
  "description": "Langfuse API client for universal JavaScript environments",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -21,7 +21,7 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "mustache": "^4.2.0",
24
- "@langfuse/core": "^4.0.0-beta.4"
24
+ "@langfuse/core": "^4.0.0-beta.6"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "@opentelemetry/api": "^1.9.0"