@helicone/helpers
Version:
A Node.js wrapper for some of Helicone's common functionalities
466 lines (459 loc) • 17.3 kB
TypeScript
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 };