import { type LLMCallTraceContext, type LLMToolResult } from '../LLMService.typedefs'; import { type LLMReporterInterface } from '../utilities/reporter'; import { type LLMSchemaInterface } from '../utilities/schema'; import { type LLMToolObservationOptions } from '../utilities/llmTracing'; import { type LLMPromptBinding, type LLMPromptRegistry } from '../client/defineLLMPrompts'; import { type LLMAgentInlineRunOptions, type LLMAgentRunResult } from '../client/agentRun.typedefs'; import { LLMAgent, type LLMAgentDefinition } from '../client/LLMAgent'; import { type LLMAgentCallServices, type LLMPromptResolutionCall } from '../client/agentRunner'; import { type LLMClientCallContext, type LLMClientEngineConfig, type LLMCompilePromptOptions, type LLMDescribePromptOptions, type LLMGeneratedSpeech, type LLMGeneratedTranscript, type LLMGenerateOptions, type LLMGenerateResult, type LLMGenerateSpeechOptions, type LLMGenerateTranscriptOptions, type LLMPlainMessage, type LLMPromptDescription, type LLMProviderServiceScope, type LLMReporterInvocation, type LLMToolResultContext, type LLMTraceContextScope } from '../client/llmClient.typedefs'; import { type LLMVariableValue } from '../client/promptSnapshot.typedefs'; import { type ResolvedPrompt } from '../client/promptRegistry.runtime'; /** * The client's single implementation. `createLLMClient` owns its construction * and exposes only the `LLMClient` surface, so every call path — `generate`, * `countTokens`, `runAgent`, `describePrompt`, `compilePrompt` — shares one * prompt resolution, one credentials lookup, one reporter/trace context, and one * error taxonomy. */ export declare class LLMClientEngine implements LLMAgentCallServices { private readonly gateway; private readonly registry; private readonly runtime; private readonly credentials; private readonly reporter; private readonly buildReporterContextFor; private readonly logger; private readonly staticContext; private readonly toolResultNormalizer; private readonly agentRunner; constructor(config: LLMClientEngineConfig); generate(prompt: Key, options: LLMGenerateOptions, Schema>): Promise; generateSpeech(prompt: Key, options: LLMGenerateSpeechOptions>): Promise; generateTranscript(prompt: Key, options: LLMGenerateTranscriptOptions>): Promise; defineAgent(definition: LLMAgentDefinition, Key>): LLMAgent, Key>; runAgent(promptOrAgent: Key | LLMAgent>, options: LLMAgentInlineRunOptions, Registry, Record>): Promise>>; countTokens(prompt: Key, options: { variables: Record; history?: LLMPlainMessage[]; }): Promise; compilePrompt(prompt: Key, options: LLMCompilePromptOptions>): Promise; describePrompt(prompt: Key, options?: LLMDescribePromptOptions): Promise; resolvePrompt(promptName: string, binding: LLMPromptBinding, variables: Record, call: LLMPromptResolutionCall): Promise; private static toResolutionOverrides; /** * The single place a tool's return value becomes what the model reads. The * package's own coercion always runs first, so a client-supplied normalizer * never sees a malformed value and cannot reintroduce one. */ normalizeToolResult(context: LLMToolResultContext): LLMToolResult; withAgentObservation(name: string, input: unknown, fn: () => Promise): Promise; withToolObservation(name: string, input: unknown, fn: () => Promise, options?: LLMToolObservationOptions): Promise; private runCompletion; /** * Builds the provider message envelope from the resolved prompt. A `text` * prompt is one user message. A `chat` prompt preserves the structure the * prompt declares: a leading `system` message maps to `instructions`, the final * `user` message is the request, and any messages between them join the * call-supplied history in order. */ private buildMessageEnvelope; private findLastUserIndex; private callProvider; unwrapResult(resolved: ResolvedPrompt, schema: LLMSchemaInterface | undefined, sendResult: { text?: string; data?: unknown; parseError?: string; }): unknown; toTaxonomyError(error: unknown, resolved: ResolvedPrompt, abortSignal?: AbortSignal): Error; buildAssistanceService(options: LLMProviderServiceScope): Promise>>; getBinding(promptName: string): LLMPromptBinding | undefined; private buildCompletionService; private buildTextToSpeechService; private buildSpeechToTextService; /** * Resolves credentials for the product this call belongs to. The per-call * context wins over the static one: the client is built once per process, so * its static product is only ever the one its builder knew, while a call site * that resolves the product from its own subject knows better. */ private resolveProviderOptions; private buildUserMessage; private buildHistory; private toCompletionMessage; /** * Delegates the reporter's payload to the composition root. The gateway never * shapes it: those fields are a downstream contract (DWH columns and the * dashboards built on their exact values), so inventing a key or a string * here would silently break analytics rather than fail a build. * * The active trace scope's context travels along as `scopeContext`, so the * composition root can fall back to what the surrounding operation declared * when the call itself names nothing. */ buildReporterContext(resolved: ResolvedPrompt, callContext: LLMClientCallContext | undefined, invocation?: LLMReporterInvocation): unknown; /** * Builds the per-call trace context every client path threads into the gateway * service. The structural `prompt` names the observation and carries the * managed prompt version, so the generation the service records on success and * on error is the single one Langfuse links to that prompt — the client never * records a second observation of its own. * * `userId`, `sessionId` and `tags` travel as typed trace fields and never * through `serializeCallContext`, which is the metadata path. The user * therefore appears twice — typed here and, as it always has, inside the * metadata bag the existing dashboards read. */ private buildCallContexts; buildTraceContext(scope: LLMTraceContextScope): LLMCallTraceContext; /** * The call context holds the user as whatever the application uses for its * own ids, while Langfuse holds it as a string. Absent stays absent, so a * call that names no user leaves the trace's user field for the scope to fill. */ private toTraceUserId; private serializeCallContext; private extractStatus; private isRetryableStatus; }