/**
* Copyright 2025 Vybestack LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @plan PLAN-20250120-DEBUGLOGGING.P15
* @requirement REQ-INT-001.1
*/
import OpenAI from 'openai';
import { type IContent } from '../../services/history/IContent.js';
import { type IProviderConfig } from '../types/IProviderConfig.js';
import { BaseProvider, type NormalizedGenerateChatOptions } from '../BaseProvider.js';
import { type OAuthManager } from '../../auth/precedence.js';
import { type IModel } from '../IModel.js';
import { type IProvider } from '../IProvider.js';
export declare class OpenAIProvider extends BaseProvider implements IProvider {
private readonly textToolParser;
private readonly toolCallPipeline;
private readonly toolCallProcessingMode;
private getLogger;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-003
* Constructor reduced to minimal initialization - no state captured
*/
constructor(apiKey: string | undefined, baseURL?: string, config?: IProviderConfig, oauthManager?: OAuthManager);
/**
* Create HTTP/HTTPS agents with socket configuration for local AI servers
* Returns undefined if no socket settings are configured
*
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-003
* Now sources ephemeral settings from call options instead of provider config
*/
private createHttpAgents;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-002
* Extract model parameters from normalized options instead of settings service
*/
private extractModelParamsFromOptions;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-003
* Resolve runtime key from normalized options for client scoping
*/
private resolveRuntimeKey;
/**
* Tool formatter instances cannot be shared between stateless calls,
* so construct a fresh one for every invocation.
*
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-003
*/
private createToolFormatter;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P09
* @requirement:REQ-SP4-002
* Instantiates a fresh OpenAI client per call to preserve stateless behaviour.
*/
private instantiateClient;
/**
* Coerce provider "content" (which may be a string or an array-of-parts)
* into a plain string. Defensive for OpenAI-compatible providers that emit
* structured content blocks.
*/
private coerceMessageContentToString;
/**
* Sanitize raw tool argument payloads before JSON parsing:
* - Remove thinking blocks (..., etc.).
* - Strip Markdown code fences (```json ... ```).
* - Try to isolate the main JSON object if wrapped in prose.
*/
private sanitizeToolArgumentsString;
/**
* Parse Kimi-K2 `<|tool_calls_section_begin|> ... <|tool_calls_section_end|>`
* blocks out of a text string.
*
* - Returns cleanedText with the whole section removed.
* - Returns ToolCallBlock[] constructed from the section contents.
*
* This is used for HF/vLLM-style Kimi deployments where `tool_calls` is empty
* and all tool info is only encoded in the text template.
*/
private extractKimiToolCallsFromText;
/**
* Clean Kimi K2 tool call tokens from thinking content.
* Used when extracting thinking from tags that may contain embedded tool calls.
* @issue #749
*/
private cleanThinkingContent;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P09
* @requirement:REQ-SP4-002
* @requirement:REQ-LOCAL-001
* Creates a client scoped to the active runtime metadata without caching.
* Local endpoints (localhost, private IPs) are allowed without authentication
* to support local AI servers like Ollama.
*/
private mergeInvocationHeaders;
protected getClient(options: NormalizedGenerateChatOptions): Promise;
/**
* Check if OAuth is supported for this provider
* Qwen endpoints support OAuth, standard OpenAI does not
*/
protected supportsOAuth(): boolean;
getModels(): Promise;
private getFallbackModels;
getDefaultModel(): string;
/**
* Get the currently selected model
*/
getCurrentModel(): string;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P09
* @requirement:REQ-SP4-002
* No-op retained for compatibility because clients are no longer cached.
*/
clearClientCache(runtimeKey?: string): void;
/**
* Override isAuthenticated for qwen provider to check OAuth directly
*/
isAuthenticated(): Promise;
/**
* Clear all provider state (for provider switching)
* Clears both OpenAI client cache and auth token cache
*/
clearState(): void;
getServerTools(): string[];
invokeServerTool(toolName: string, _params: unknown, _config?: unknown, _signal?: AbortSignal): Promise;
/**
* @plan PLAN-20250218-STATELESSPROVIDER.P04
* @requirement REQ-SP-001
* @pseudocode base-provider.md lines 7-15
* @pseudocode provider-invocation.md lines 8-12
*/
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P09
* @requirement:REQ-SP4-002
* Generate chat completion with per-call client instantiation.
*/
protected generateChatCompletionWithOptions(options: NormalizedGenerateChatOptions): AsyncIterableIterator;
private normalizeToolCallArguments;
private buildToolResponseContent;
/**
* Build messages with optional reasoning_content based on settings.
*
* @plan PLAN-20251202-THINKING.P14
* @requirement REQ-THINK-004, REQ-THINK-006
*/
private buildMessagesWithReasoning;
/**
* Validates tool message sequence to ensure each tool message has a corresponding tool_calls
* This prevents "messages with role 'tool' must be a response to a preceeding message with 'tool_calls'" errors
*
* Only validates when there are tool_calls present in conversation to avoid breaking isolated tool response tests
*
* @param messages - The converted OpenAI messages to validate
* @returns The validated messages with invalid tool messages removed
*/
private validateToolMessageSequence;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-003
* Legacy implementation for chat completion using accumulated tool calls approach
*/
private generateLegacyChatCompletionImpl;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-002
* Memoization of model parameters disabled for stateless provider
*/
setModelParams(_params: Record | undefined): void;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-003
* Gets model parameters from SettingsService per call (stateless)
*/
getModelParams(): Record | undefined;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-003
* Internal implementation for chat completion using normalized options
* Routes to appropriate implementation based on toolCallProcessingMode
*/
private generateChatCompletionImpl;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-003
* Pipeline implementation for chat completion using optimized tool call pipeline
*/
private generatePipelineChatCompletionImpl;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-003
* Legacy implementation for chat completion using accumulated tool calls approach
*/
getToolFormat(): string;
/**
* Parse tool response from API (placeholder for future response parsing)
* @param response The raw API response
* @returns Parsed tool response
*/
parseToolResponse(response: unknown): unknown;
/**
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
* @requirement:REQ-SP4-003
* Determines whether a response should be retried based on error codes
* @param error The error object from the API response
* @returns true if the request should be retried, false otherwise
*/
shouldRetryResponse(error: unknown): boolean;
/**
* Parse reasoning_content from streaming delta.
*
* @plan PLAN-20251202-THINKING.P11, PLAN-20251202-THINKING.P16
* @requirement REQ-THINK-003.1, REQ-THINK-003.3, REQ-THINK-003.4, REQ-KIMI-REASONING-001.1
* @issue #749
*/
private parseStreamingReasoningDelta;
/**
* Parse reasoning_content from non-streaming message.
*
* @plan PLAN-20251202-THINKING.P11, PLAN-20251202-THINKING.P16
* @requirement REQ-THINK-003.2, REQ-THINK-003.3, REQ-THINK-003.4, REQ-KIMI-REASONING-001.2
* @issue #749
*/
private parseNonStreamingReasoning;
private buildContinuationMessages;
/**
* Request continuation after tool calls when model returned no text.
* This is a helper to avoid code duplication between legacy and pipeline paths.
*
* @plan PLAN-20250120-DEBUGLOGGING.P15
* @issue #584, #764 (CodeRabbit review)
*/
private requestContinuationAfterToolCalls;
}