import type { CompletionRun, CompletionStats, ToolCall } from '@qvac/sdk'; export type OpenAiFinishReason = 'stop' | 'length' | 'tool_calls'; export interface DrainedCompletion { text: string; /** Concatenated `thinkingDelta` text; empty when the SDK captured no reasoning. */ thinking: string; toolCalls: ToolCall[]; stats: CompletionStats | undefined; /** * Terminal reason from the SDK `completionDone` event (`eos` / `length` / * `stopSequence` / `cancelled`), or undefined if the stream ended without * one. `error` and `cancelled` are never present here — `drainCompletion` * throws on both (502 for error, `InferenceCancelledError` for cancelled). */ stopReason: string | undefined; /** * OpenAI `usage.completion_tokens`: prefers SDK `stats.emittedTokens` * (addon-streamed pieces), then `stats.generatedTokens` (decode count), * then a whitespace word count. */ completionTokens: number; /** OpenAI `finish_reason`: `tool_calls` wins, then `length` on truncation, else `stop`. */ finishReason: OpenAiFinishReason; } /** * Single-pass consumer of an SDK completion run, shared by every * chat-category route (chat / completions / responses). Draining * `result.events` once yields content text, tool calls, stats and the * terminal `stopReason` together, so the OpenAI `finish_reason` and token * accounting are derived in one place instead of drifting per route. * * Pass `onToken` to stream content deltas as they arrive (SSE paths); omit * it for blocking responses. Pass `onThinking` to stream reasoning deltas the * same way — only produced when the caller enabled `captureThinking` on the * SDK request. */ export declare function drainCompletion(result: CompletionRun, onToken?: (token: string) => void, onThinking?: (token: string) => void): Promise; /** * OpenAI `usage.completion_tokens` for a drained run. * * Prefer SDK `emittedTokens` (non-empty addon stream pieces) over * `generatedTokens` (`llama_perf` `n_eval`), which can equal the predict / * `max_tokens` budget when fewer tokens were streamed. Normalized * `contentDelta` / `thinkingDelta` event counts are not used — those are * chunk boundaries, not tokenizer tokens. */ export declare function completionTokensFromStats(text: string, stats: CompletionStats | undefined): number; //# sourceMappingURL=completion-result.d.ts.map