UNPKG

@helicone/helpers

Version:

A Node.js wrapper for some of Helicone's common functionalities

466 lines (459 loc) 17.3 kB
import { ChatCompletionCreateParamsNonStreaming, ChatCompletionContentPart, ChatCompletionDeveloperMessageParam, ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam, ChatCompletionAssistantMessageParam, ChatCompletionToolMessageParam, ChatCompletionFunctionMessageParam, ChatCompletionCreateParamsStreaming, ChatCompletionCreateParams } from 'openai/resources/chat/completions'; type IHeliconeManualLogger = { apiKey: string; headers?: Record<string, string>; loggingEndpoint?: string; }; type ILogRequest = { model: string; [key: string]: any; }; interface HeliconeEventTool { _type: "tool"; toolName: string; input: any; [key: string]: any; } interface HeliconeEventVectorDB { _type: "vector_db"; operation: "search" | "insert" | "delete" | "update"; text?: string; vector?: number[]; topK?: number; filter?: object; databaseName?: string; [key: string]: any; } interface HeliconeEventData { _type: "data"; name: string; meta?: Record<string, any>; [key: string]: any; } type HeliconeCustomEventRequest = HeliconeEventTool | HeliconeEventVectorDB | HeliconeEventData; type HeliconeLogRequest = ILogRequest | HeliconeCustomEventRequest; type Stream<T> = AsyncIterable<T> & { tee(): [Stream<T>, Stream<T>]; toReadableStream(): ReadableStream<T>; }; /** * HeliconeLogBuilder provides a simplified way to handle streaming LLM responses * with better error handling and async support. */ declare class HeliconeLogBuilder { private logger; private request; private additionalHeaders?; private startTime; private endTime; private responseBody; private error; private timeToFirstToken?; private streamTexts; private status; private wasCancelled; private streamState; private attachedStream; /** * Creates a new HeliconeLogBuilder * @param logger - The HeliconeManualLogger instance to use for logging * @param request - The request object to log * @param additionalHeaders - Additional headers to send with the request */ constructor(logger: HeliconeManualLogger, request: HeliconeLogRequest, additionalHeaders?: Record<string, string>); /** * Sets an error that occurred during the request * @param error - The error that occurred */ setError(error: any): void; /** * Collects streaming responses and converts them to a readable stream * while also capturing the response for logging * @param stream - The stream from an LLM provider response * @returns A ReadableStream that can be returned to the client */ toReadableStream<T>(stream: Stream<T>): ReadableStream; addAdditionalHeaders(headers: Record<string, string>): void; /** * Attaches a stream to the log builder, this will consume the stream and log it on sendLog * @param stream - The stream to attach */ attachStream<T>(stream: Stream<T>): Promise<void>; /** * Sets the response body for non-streaming responses * @param body - The response body */ setResponse(body: string): void; private waitForStreamToFinish; private consumeStream; /** * Sends the log to Helicone * @returns A Promise that resolves when logging is complete */ sendLog(): Promise<void>; } declare class HeliconeManualLogger { private apiKey; private headers; private LOGGING_ENDPOINT; constructor(opts: IHeliconeManualLogger); private getLoggingEndpoint; /** * Creates a log builder for more flexible stream handling with error management * @param request - The request object to log * @param additionalHeaders - Additional headers to send with the request * @returns A HeliconeLogBuilder instance */ logBuilder(request: HeliconeLogRequest, additionalHeaders?: Record<string, string>): HeliconeLogBuilder; /** * Logs a custom request to Helicone * @param request - The request object to log * @param operation - The operation which will be executed and logged * @param additionalHeaders - Additional headers to send with the request * @returns The result of the `operation` function */ logRequest<T>(request: HeliconeLogRequest, operation: (resultRecorder: HeliconeResultRecorder) => Promise<T>, additionalHeaders?: Record<string, string>, provider?: string): Promise<T>; /** * Logs a single stream to Helicone * @param request - The request object to log * @param stream - The ReadableStream to consume and log * @param additionalHeaders - Additional headers to send with the request * @returns A Promise that resolves when logging is complete */ logSingleStream(request: HeliconeLogRequest, stream: ReadableStream, additionalHeaders?: Record<string, string>): Promise<void>; /** * Logs a single request with a response body to Helicone * @param request - The request object to log * @param body - The response body as a string * @param additionalHeaders - Additional headers to send with the request * @param latencyMs - The latency of the request in milliseconds * @returns A Promise that resolves when logging is complete * * @example * ```typescript * helicone.logSingleRequest(request, body, { additionalHeaders: { "Helicone-User-Id": userId }, latencyMs: 1000 }); * ``` */ logSingleRequest(request: HeliconeLogRequest, body: string, options: { additionalHeaders?: Record<string, string>; latencyMs?: number; }): Promise<void>; /** * Logs a streaming operation to Helicone * @param request - The request object to log * @param operation - The operation which will be executed and logged, with access to a stream recorder * @param additionalHeaders - Additional headers to send with the request * @returns The result of the `operation` function * * @example * ```typescript * const response = await llmProvider.createChatCompletion({ stream: true, ... }); * const [stream1, stream2] = response.tee(); * * helicone.logStream( * requestBody, * async (resultRecorder) => { * resultRecorder.attachStream(stream2.toReadableStream()); * return stream1; * }, * { "Helicone-User-Id": userId } * ); * ``` */ logStream<T>(request: HeliconeLogRequest, operation: (resultRecorder: HeliconeStreamResultRecorder) => Promise<T>, additionalHeaders?: Record<string, string>): Promise<T>; sendLog(request: HeliconeLogRequest, response: Record<string, any> | string, options: { startTime: number; endTime: number; additionalHeaders?: Record<string, string>; timeToFirstToken?: number; status?: number; provider?: string; }): Promise<void>; } /** * Recorder for handling and processing streams in Helicone logging * Used to capture and process streaming responses from LLM providers */ declare class HeliconeStreamResultRecorder { private streams; firstChunkTimeUnix: number | null; constructor(); /** * Attaches a ReadableStream to be processed * @param stream - The ReadableStream to attach */ attachStream(stream: ReadableStream): void; /** * Processes all attached streams and returns their contents as strings * @returns Promise resolving to an array of strings containing the content of each stream */ getStreamTexts(): Promise<string[]>; } /** * Recorder for handling and storing results in Helicone logging * Used to capture non-streaming responses from operations */ declare class HeliconeResultRecorder { private results; /** * Appends data to the results object * @param data - The data to append to the results */ appendResults(data: Record<string, any>): void; /** * Gets the current results * @returns The current results object */ getResults(): Record<string, any>; } interface PromptPartialVariable { prompt_id: string; index: number; environment?: string; raw: string; } interface ValidationError { variable: string; expected: string; value: any; } interface Prompt2025Version { id: string; model: string; prompt_id: string; major_version: number; minor_version: number; commit_message: string; environment?: string; created_at: string; s3_url?: string; } /** * Cache control configuration for Anthropic's prompt caching feature. * * When using Anthropic models through the Helicone AI Gateway, you can enable * prompt caching to reduce costs and latency for repeated prompts. * * @example * ```typescript * const message = { * role: "user", * content: "Analyze this document...", * cache_control: { type: "ephemeral", ttl: "5m" } * }; * ``` */ interface CacheControl { /** Cache type - currently only ephemeral caching is supported */ type: "ephemeral"; /** Time-to-live for the cached content */ ttl?: "5m" | "1h"; } /** * Document content part type for Anthropic extended context with citations. * This is specific to Anthropic and not part of the standard OpenAI API. */ interface ChatCompletionContentPartDocument { type: "document"; source: { type: "text"; media_type: string; data: string; }; title?: string; citations?: { enabled: boolean; }; } /** * OpenAI content part extended with optional cache control and document support. * Allows individual content parts within a message to have cache control. * Includes Anthropic-specific document type for extended context features. */ type HeliconeChatCompletionContentPart = (ChatCompletionContentPart | ChatCompletionContentPartDocument) & { cache_control?: CacheControl; }; /** * OpenAI message with optional cache control support */ type HeliconeMessageParam<T> = Omit<T, 'content'> & { content: string | HeliconeChatCompletionContentPart[] | null; cache_control?: CacheControl; }; type HeliconeChatCompletionMessageParam = HeliconeMessageParam<ChatCompletionDeveloperMessageParam> | HeliconeMessageParam<ChatCompletionSystemMessageParam> | HeliconeMessageParam<ChatCompletionUserMessageParam> | HeliconeMessageParam<ChatCompletionAssistantMessageParam> | HeliconeMessageParam<ChatCompletionToolMessageParam> | HeliconeMessageParam<ChatCompletionFunctionMessageParam>; /** * Non-streaming completion params with optional messages */ type ChatCompletionCreateParamsNonStreamingPartialMessages = Omit<ChatCompletionCreateParamsNonStreaming, 'messages'> & { messages?: HeliconeChatCompletionMessageParam[]; }; /** * Streaming completion params with optional messages */ type ChatCompletionCreateParamsStreamingPartialMessages = Omit<ChatCompletionCreateParamsStreaming, 'messages'> & { messages?: HeliconeChatCompletionMessageParam[]; }; /** * Parameters for using Helicone prompt templates. * * @example * ```typescript * const promptParams = { * prompt_id: "XXXXXX", * version_id: "5d4ec7d7-5725-46c2-ad26-41ddf6287527", // optional * environment: "production", // optional - targets specific environment * inputs: { * name: "John", * age: 20, * } * }; * ``` */ type HeliconePromptParams = { /** The unique identifier for your Helicone prompt template */ prompt_id?: string; /** The deployment environment to target for the prompt */ environment?: string; /** Optional version ID. If not provided, uses the latest version */ version_id?: string; /** * Key-value pairs to interpolate into your prompt template. * Keys should match the variable names in your template. */ inputs?: Record<string, any>; }; /** * OpenAI ChatCompletion parameters extended with Helicone prompt template support. * Use this type when creating non-streaming chat completions with Helicone prompts. * * @example * ```typescript * const response = await openai.chat.completions.create({ * prompt_id: "123", * model: "gpt-4o", * messages: [ * // Message-level cache control (string content) * { * role: "user", * content: "Hello!", * cache_control: { type: "ephemeral", ttl: "5m" }, * }, * // Content-part-level cache control (array content, no message-level cache) * { * role: "user", * content: [ * { * type: "text", * text: "Analyze this document", * cache_control: { type: "ephemeral", ttl: "1h" }, * }, * { * type: "text", * text: "Additional context", * }, * ], * }, * ], * inputs: { * name: "John", * age: 20, * }, * } as HeliconeChatCreateParams); * ``` */ type HeliconeChatCreateParams = ChatCompletionCreateParamsNonStreamingPartialMessages & HeliconePromptParams; /** * OpenAI ChatCompletion parameters extended with Helicone prompt template support for streaming responses. * Use this type when creating streaming chat completions with Helicone prompts. * * @example * ```typescript * const stream = await openai.chat.completions.create({ * prompt_id: "123", * model: "gpt-4o", * messages: [ * // Content-part-level cache control only (no message-level cache allowed) * { * role: "user", * content: [ * { * type: "text", * text: "Process this data", * cache_control: { type: "ephemeral", ttl: "5m" }, * }, * { * type: "text", * text: "Additional data without cache", * }, * ], * }, * ], * stream: true, * inputs: { * name: "John", * age: 20, * }, * } as HeliconeChatCreateParamsStreaming); * ``` */ type HeliconeChatCreateParamsStreaming = ChatCompletionCreateParamsStreamingPartialMessages & HeliconePromptParams; interface HeliconePromptManagerOptions { apiKey: string; baseUrl?: string; } declare class HeliconePromptManager { private apiKey; private baseUrl; constructor(options: HeliconePromptManagerOptions); /** * Finds the prompt version dynamically based on prompt params * @param params - The chat completion parameters containing prompt_id, optional version_id, inputs, and other OpenAI parameters * @returns Object containing the compiled prompt body and any validation/substitution errors */ pullPromptVersion(params: HeliconePromptParams): Promise<Prompt2025Version>; /** * Pulls a prompt body from Helicone storage by prompt ID and optional version ID * @param promptId - The unique identifier of the prompt * @param versionId - Optional version ID, if not provided uses production version * @returns The raw prompt body from storage */ pullPromptBody(params: HeliconePromptParams): Promise<ChatCompletionCreateParams>; /** * Pulls a prompt body from Helicone storage by version ID * @param versionId - The unique identifier of the prompt version * @returns The raw prompt body from storage */ pullPromptBodyByVersionId(versionId: string): Promise<ChatCompletionCreateParams>; /** * Extracts all prompt partial variables from a source prompt body. * @param sourcePromptBody - The source prompt body to extract prompt partial variables from * @returns Array of unique prompt partial variables found in the body */ extractPromptPartials(sourcePromptBody: ChatCompletionCreateParams): PromptPartialVariable[]; getPromptPartialSubstitutionValue(promptPartial: PromptPartialVariable, sourceBody: ChatCompletionCreateParams): string; /** * Merge * @param params - The chat completion parameters containing prompt_id, optional version_id, inputs, and other OpenAI parameters * @param sourcePromptBody - The source prompt body to merge with * @param promptPartialInputs - Optional map of prompt partial inputs for substitution (if not provided, prompt partials will not be substituted) * @returns Object containing the compiled prompt body and any validation/substitution errors */ mergePromptBody(params: HeliconeChatCreateParams | HeliconeChatCreateParamsStreaming, sourcePromptBody: ChatCompletionCreateParams, promptPartialInputs?: Record<string, any>): Promise<{ body: ChatCompletionCreateParams; errors: ValidationError[]; }>; /** * Retrieves and merges prompt body with input parameters and variable substitution * @param params - The chat completion parameters containing prompt_id, optional version_id, inputs, and other OpenAI parameters * @returns Object containing the compiled prompt body and any validation/substitution errors */ getPromptBody(params: HeliconeChatCreateParams | HeliconeChatCreateParamsStreaming): Promise<{ body: ChatCompletionCreateParams; errors: ValidationError[]; }>; private getPromptVersion; private getProductionVersion; private getEnvironmentVersion; private fetchPromptBodyFromS3; } export { type HeliconeChatCreateParams, type HeliconeChatCreateParamsStreaming, HeliconeLogBuilder, HeliconeManualLogger, HeliconePromptManager, type HeliconePromptParams };