Class AbstractLlmClient

java.lang.Object
org.codelibs.fess.llm.AbstractLlmClient
All Implemented Interfaces:
LlmClient

public abstract class AbstractLlmClient extends Object implements LlmClient
Abstract base class for LLM client implementations. Provides shared infrastructure (HTTP client, availability checking) and default implementations of RAG workflow methods with injectable prompt templates. Subclasses implement provider-specific chat/streamChat and checkAvailabilityNow.
  • Field Details

    • objectMapper

      protected static final com.fasterxml.jackson.databind.ObjectMapper objectMapper
      Shared ObjectMapper instance for JSON processing.
    • CONTEXT_TRUNCATION_BUFFER

      protected static final int CONTEXT_TRUNCATION_BUFFER
      Buffer size reserved when truncating context to fit within max chars limit.
      See Also:
    • httpClient

      protected org.apache.hc.client5.http.impl.classic.CloseableHttpClient httpClient
      The HTTP client used for API communication.
    • cachedAvailability

      protected volatile Boolean cachedAvailability
      Cached availability status of the LLM provider.
    • availabilityCheckTask

      protected org.codelibs.core.timer.TimeoutTask availabilityCheckTask
      The scheduled task for periodic availability checks.
    • concurrencyLimiter

      protected volatile Semaphore concurrencyLimiter
      Semaphore for limiting concurrent LLM requests. Initialized lazily in init().
    • systemPrompt

      protected String systemPrompt
      The system prompt for LLM interactions.
    • intentDetectionPrompt

      protected String intentDetectionPrompt
      The prompt for detecting user intent.
    • unclearIntentSystemPrompt

      protected String unclearIntentSystemPrompt
      The system prompt for handling unclear intents.
    • noResultsSystemPrompt

      protected String noResultsSystemPrompt
      The system prompt for handling no results.
    • documentNotFoundSystemPrompt

      protected String documentNotFoundSystemPrompt
      The system prompt for handling document not found.
    • evaluationPrompt

      protected String evaluationPrompt
      The prompt for evaluating responses.
    • answerGenerationSystemPrompt

      protected String answerGenerationSystemPrompt
      The system prompt for answer generation.
    • summarySystemPrompt

      protected String summarySystemPrompt
      The system prompt for summary generation.
    • faqAnswerSystemPrompt

      protected String faqAnswerSystemPrompt
      The system prompt for FAQ answer generation.
    • directAnswerSystemPrompt

      protected String directAnswerSystemPrompt
      The system prompt for direct answer generation.
    • queryRegenerationPrompt

      protected String queryRegenerationPrompt
      The prompt for query regeneration.
    • LOG_RESPONSE_HEAD_MAX_CHARS

      protected static final int LOG_RESPONSE_HEAD_MAX_CHARS
      Maximum length of an LLM response prefix surfaced in WARN-level operator logs.
      See Also:
    • TRUNCATION_FINISH_REASONS

      protected static final Set<String> TRUNCATION_FINISH_REASONS
      Provider-specific finish-reason values that indicate the LLM stopped because it ran out of output token budget (truncated response). Includes:
      • length - OpenAI / Ollama
      • MAX_TOKENS - Gemini
      • max_tokens - Anthropic
      • model_length - some self-hosted endpoints
  • Constructor Details

    • AbstractLlmClient

      public AbstractLlmClient()
      Default constructor.
  • Method Details

    • register

      public void register()
      Registers this client with the LlmClientManager. Called via postConstruct before init().
    • init

      public void init()
      Initializes the HTTP client and starts availability checking. Should be called from subclass init() methods.
    • configureProxy

      protected void configureProxy(org.apache.hc.client5.http.impl.classic.HttpClientBuilder builder)
      Configures proxy settings on the HTTP client builder if a proxy is configured. Reads proxy configuration via getProxyHost(), getProxyPort(), getProxyUsername(), and getProxyPassword(). When username is provided, registers a BasicCredentialsProvider for proxy authentication.
      Parameters:
      builder - the HTTP client builder to configure
    • getProxyHost

      protected String getProxyHost()
      Gets the HTTP proxy host. Defaults to http.proxy.host from FessConfig.
      Returns:
      the proxy host, or null/blank if no proxy is configured
    • getProxyPort

      protected Integer getProxyPort()
      Gets the HTTP proxy port. Defaults to http.proxy.port from FessConfig.
      Returns:
      the proxy port, or null if no proxy is configured
    • getProxyUsername

      protected String getProxyUsername()
      Gets the HTTP proxy username. Defaults to http.proxy.username from FessConfig.
      Returns:
      the proxy username, or null/blank if no proxy authentication is required
    • getProxyPassword

      protected String getProxyPassword()
      Gets the HTTP proxy password. Defaults to http.proxy.password from FessConfig.
      Returns:
      the proxy password, or null if no proxy authentication is required
    • destroy

      public void destroy()
      Cleans up resources.
    • startAvailabilityCheck

      protected void startAvailabilityCheck()
      Starts periodic availability checking if RAG chat is enabled.
    • updateAvailability

      protected void updateAvailability()
      Updates the cached availability state.
    • isAvailable

      public boolean isAvailable()
      Description copied from interface: LlmClient
      Checks if this LLM client is available and properly configured.
      Specified by:
      isAvailable in interface LlmClient
      Returns:
      true if the client is available, false otherwise
    • getHttpClient

      public org.apache.hc.client5.http.impl.classic.CloseableHttpClient getHttpClient()
      Gets the HTTP client, initializing it if necessary.
      Returns:
      the HTTP client
    • checkAvailabilityNow

      protected abstract boolean checkAvailabilityNow()
      Performs the actual availability check against the LLM provider.
      Returns:
      true if the provider is available
    • getTimeout

      protected abstract int getTimeout()
      Gets the request timeout in milliseconds.
      Returns:
      the timeout in milliseconds
    • getModel

      protected abstract String getModel()
      Gets the model name.
      Returns:
      the model name
    • getAvailabilityCheckInterval

      protected abstract int getAvailabilityCheckInterval()
      Gets the availability check interval in seconds.
      Returns:
      the interval in seconds
    • isRagChatEnabled

      protected abstract boolean isRagChatEnabled()
      Checks if RAG chat feature is enabled.
      Returns:
      true if RAG chat is enabled
    • getLlmType

      protected abstract String getLlmType()
      Gets the configured LLM type.
      Returns:
      the LLM type from configuration
    • getConfigPrefix

      protected abstract String getConfigPrefix()
      Gets the configuration prefix for this provider. Used to look up per-prompt-type parameters from FessConfig.
      Returns:
      the config prefix (e.g. "rag.llm.openai")
    • getSystemPrompt

      protected String getSystemPrompt()
      Gets the base system prompt for RAG chat responses.
      Returns:
      the system prompt
    • getIntentDetectionPrompt

      protected String getIntentDetectionPrompt()
      Gets the intent detection prompt template.
      Returns:
      the intent detection prompt
    • getUnclearIntentSystemPrompt

      protected String getUnclearIntentSystemPrompt()
      Gets the system prompt for unclear intent responses.
      Returns:
      the unclear intent system prompt
    • getNoResultsSystemPrompt

      protected String getNoResultsSystemPrompt()
      Gets the system prompt for no-results responses.
      Returns:
      the no-results system prompt
    • getDocumentNotFoundSystemPrompt

      protected String getDocumentNotFoundSystemPrompt()
      Gets the system prompt for document-not-found responses.
      Returns:
      the document-not-found system prompt
    • getEvaluationPrompt

      protected String getEvaluationPrompt()
      Gets the evaluation prompt for relevance checking.
      Returns:
      the evaluation prompt
    • getAnswerGenerationSystemPrompt

      protected String getAnswerGenerationSystemPrompt()
      Gets the system prompt for answer generation.
      Returns:
      the answer generation system prompt
    • getSummarySystemPrompt

      protected String getSummarySystemPrompt()
      Gets the system prompt for summary generation.
      Returns:
      the summary system prompt
    • getFaqAnswerSystemPrompt

      protected String getFaqAnswerSystemPrompt()
      Gets the system prompt for FAQ answer generation.
      Returns:
      the FAQ answer system prompt
    • getDirectAnswerSystemPrompt

      protected String getDirectAnswerSystemPrompt()
      Gets the system prompt for direct answer generation.
      Returns:
      the direct answer system prompt
    • getQueryRegenerationPrompt

      protected String getQueryRegenerationPrompt()
      Gets the query regeneration prompt template.
      Returns:
      the query regeneration prompt
    • setSystemPrompt

      public void setSystemPrompt(String systemPrompt)
      Sets the system prompt for LLM interactions.
      Parameters:
      systemPrompt - the system prompt
    • setIntentDetectionPrompt

      public void setIntentDetectionPrompt(String intentDetectionPrompt)
      Sets the prompt for detecting user intent.
      Parameters:
      intentDetectionPrompt - the intent detection prompt
    • setUnclearIntentSystemPrompt

      public void setUnclearIntentSystemPrompt(String unclearIntentSystemPrompt)
      Sets the system prompt for handling unclear intents.
      Parameters:
      unclearIntentSystemPrompt - the unclear intent system prompt
    • setNoResultsSystemPrompt

      public void setNoResultsSystemPrompt(String noResultsSystemPrompt)
      Sets the system prompt for handling no results.
      Parameters:
      noResultsSystemPrompt - the no results system prompt
    • setDocumentNotFoundSystemPrompt

      public void setDocumentNotFoundSystemPrompt(String documentNotFoundSystemPrompt)
      Sets the system prompt for handling document not found.
      Parameters:
      documentNotFoundSystemPrompt - the document not found system prompt
    • setEvaluationPrompt

      public void setEvaluationPrompt(String evaluationPrompt)
      Sets the prompt for evaluating responses.
      Parameters:
      evaluationPrompt - the evaluation prompt
    • setAnswerGenerationSystemPrompt

      public void setAnswerGenerationSystemPrompt(String answerGenerationSystemPrompt)
      Sets the system prompt for answer generation.
      Parameters:
      answerGenerationSystemPrompt - the answer generation system prompt
    • setSummarySystemPrompt

      public void setSummarySystemPrompt(String summarySystemPrompt)
      Sets the system prompt for summary generation.
      Parameters:
      summarySystemPrompt - the summary system prompt
    • setFaqAnswerSystemPrompt

      public void setFaqAnswerSystemPrompt(String faqAnswerSystemPrompt)
      Sets the system prompt for FAQ answer generation.
      Parameters:
      faqAnswerSystemPrompt - the FAQ answer system prompt
    • setDirectAnswerSystemPrompt

      public void setDirectAnswerSystemPrompt(String directAnswerSystemPrompt)
      Sets the system prompt for direct answer generation.
      Parameters:
      directAnswerSystemPrompt - the direct answer system prompt
    • setQueryRegenerationPrompt

      public void setQueryRegenerationPrompt(String queryRegenerationPrompt)
      Sets the prompt for query regeneration.
      Parameters:
      queryRegenerationPrompt - the query regeneration prompt
    • getConfigInt

      protected int getConfigInt(String keySuffix, int defaultValue)
      Gets an integer configuration value using the config prefix and key suffix. Returns the configured value if it is a positive integer, otherwise returns the default.
      Parameters:
      keySuffix - the key suffix (appended to getConfigPrefix() + ".")
      defaultValue - the default value
      Returns:
      the configured or default value
    • getContextMaxChars

      protected abstract int getContextMaxChars(String promptType)
      Gets the maximum characters for context building for a specific prompt type. Each LlmClient implementation defines per-prompt-type defaults appropriate for its target model.
      Parameters:
      promptType - the prompt type (e.g., "answer", "summary", "faq")
      Returns:
      the maximum characters
    • getEvaluationMaxRelevantDocs

      protected abstract int getEvaluationMaxRelevantDocs()
      Gets the maximum number of relevant documents for evaluation.
      Returns:
      the maximum number of relevant documents
    • getEvaluationDescriptionMaxChars

      protected abstract int getEvaluationDescriptionMaxChars()
      Gets the maximum number of characters for evaluation description.
      Returns:
      the maximum number of characters
    • getHistoryMaxChars

      protected int getHistoryMaxChars()
      Gets the maximum characters for conversation history in LLM requests. Each LlmClient implementation should override to define defaults appropriate for its target model. The default returns 4000 for backward compatibility.
      Returns:
      the maximum history characters
    • getIntentHistoryMaxMessages

      protected int getIntentHistoryMaxMessages()
      Gets the maximum number of history messages for intent detection. The default returns 6. Override in subclasses for provider-specific tuning.
      Returns:
      the maximum number of messages
    • getIntentHistoryMaxChars

      protected int getIntentHistoryMaxChars()
      Gets the maximum characters for intent detection history. The default returns 3000. Override in subclasses for provider-specific tuning.
      Returns:
      the maximum characters
    • getHistoryAssistantMaxChars

      public int getHistoryAssistantMaxChars()
      Gets the maximum characters for assistant message content in history. The default returns 800. Override in subclasses for provider-specific tuning.
      Specified by:
      getHistoryAssistantMaxChars in interface LlmClient
      Returns:
      the maximum characters
    • getHistoryAssistantSummaryMaxChars

      public int getHistoryAssistantSummaryMaxChars()
      Gets the maximum characters for assistant summary content in history. The default returns 800. Override in subclasses for provider-specific tuning.
      Specified by:
      getHistoryAssistantSummaryMaxChars in interface LlmClient
      Returns:
      the maximum characters
    • getMaxConcurrentRequests

      protected int getMaxConcurrentRequests()
      Gets the maximum number of concurrent requests to the LLM provider. Default is 5. Override or configure via rag.llm.{provider}.max.concurrent.requests.
      Returns:
      the maximum concurrent requests
    • getConcurrencyWaitTimeoutMs

      protected long getConcurrencyWaitTimeoutMs()
      Gets the timeout for waiting to acquire a concurrency permit (ms). Default is 30000ms. Override or configure via rag.llm.{provider}.concurrency.wait.timeout.
      Returns:
      the wait timeout in milliseconds
    • chatWithConcurrencyControl

      protected LlmChatResponse chatWithConcurrencyControl(LlmChatRequest request)
      Executes a chat request with concurrency control via Semaphore.
      Parameters:
      request - the chat request
      Returns:
      the chat response
      Throws:
      LlmException - if too many concurrent requests or interrupted
    • streamChatWithConcurrencyControl

      protected void streamChatWithConcurrencyControl(LlmChatRequest request, LlmStreamCallback callback)
      Executes a streaming chat request with concurrency control via Semaphore.
      Parameters:
      request - the chat request
      callback - the streaming callback
      Throws:
      LlmException - if too many concurrent requests or interrupted
    • applyPromptTypeParams

      protected void applyPromptTypeParams(LlmChatRequest request, String promptType)
      Applies per-prompt-type parameters to the request from configuration. Reads temperature, max.tokens, and thinking.budget from config using the pattern: {configPrefix}.{promptType}.{paramName} Subclasses can override to add provider-specific parameters (e.g. reasoning_effort, top_p).
      Parameters:
      request - the LLM chat request
      promptType - the prompt type (e.g. "intent", "evaluation", "answer")
    • getUserLocale

      protected Locale getUserLocale()
      Gets the user's locale from the current request context.
      Returns:
      the user's locale, or default locale if not in request context
    • getLanguageInstruction

      protected String getLanguageInstruction()
      Gets the language instruction based on the user's locale.
      Returns:
      the language instruction string, or empty string if locale is English
    • resolveLanguageInstruction

      protected String resolveLanguageInstruction(String prompt)
      Resolves the {{languageInstruction}} placeholder in a prompt.
      Parameters:
      prompt - the prompt template
      Returns:
      the prompt with language instruction resolved
    • detectIntent

      public IntentDetectionResult detectIntent(String userMessage)
      Description copied from interface: LlmClient
      Detects the intent of a user message.
      Specified by:
      detectIntent in interface LlmClient
      Parameters:
      userMessage - the user's message
      Returns:
      the detected intent with extracted keywords
    • detectIntent

      public IntentDetectionResult detectIntent(String userMessage, List<LlmMessage> history)
      Description copied from interface: LlmClient
      Detects the intent of a user message with conversation history context.
      Specified by:
      detectIntent in interface LlmClient
      Parameters:
      userMessage - the user's message
      history - the conversation history for context
      Returns:
      the detected intent with extracted keywords
    • evaluateResults

      public RelevanceEvaluationResult evaluateResults(String userMessage, String query, List<Map<String,Object>> searchResults)
      Description copied from interface: LlmClient
      Evaluates search results for relevance to the user's question.
      Specified by:
      evaluateResults in interface LlmClient
      Parameters:
      userMessage - the original user message
      query - the search query used
      searchResults - the search results to evaluate
      Returns:
      evaluation result with relevant document IDs
    • generateAnswer

      public LlmChatResponse generateAnswer(String userMessage, List<Map<String,Object>> documents, List<LlmMessage> history)
      Description copied from interface: LlmClient
      Generates an answer using document content (synchronous version for non-enhanced flow).
      Specified by:
      generateAnswer in interface LlmClient
      Parameters:
      userMessage - the user's message
      documents - the documents with content
      history - the conversation history
      Returns:
      the chat response
    • regenerateQuery

      public String regenerateQuery(String userMessage, String failedQuery, String failureReason, List<LlmMessage> history)
      Description copied from interface: LlmClient
      Regenerates a search query when the previous query failed to produce relevant results.
      Specified by:
      regenerateQuery in interface LlmClient
      Parameters:
      userMessage - the user's original message
      failedQuery - the query that failed
      failureReason - the reason for failure ("no_results" or "no_relevant_results")
      history - the conversation history
      Returns:
      a new query string, or the userMessage if regeneration fails
    • streamGenerateAnswer

      public void streamGenerateAnswer(String userMessage, List<Map<String,Object>> documents, List<LlmMessage> history, LlmStreamCallback callback)
      Description copied from interface: LlmClient
      Generates an answer using document content (streaming version for enhanced flow).
      Specified by:
      streamGenerateAnswer in interface LlmClient
      Parameters:
      userMessage - the user's message
      documents - the documents with content
      history - the conversation history
      callback - the streaming callback
    • generateUnclearIntentResponse

      public void generateUnclearIntentResponse(String userMessage, List<LlmMessage> history, LlmStreamCallback callback)
      Description copied from interface: LlmClient
      Generates a response asking user for clarification when intent is unclear.
      Specified by:
      generateUnclearIntentResponse in interface LlmClient
      Parameters:
      userMessage - the user's message
      history - the conversation history
      callback - the streaming callback
    • generateNoResultsResponse

      public void generateNoResultsResponse(String userMessage, List<LlmMessage> history, LlmStreamCallback callback)
      Description copied from interface: LlmClient
      Generates a response when no relevant documents are found.
      Specified by:
      generateNoResultsResponse in interface LlmClient
      Parameters:
      userMessage - the user's message
      history - the conversation history
      callback - the streaming callback
    • generateDocumentNotFoundResponse

      public void generateDocumentNotFoundResponse(String userMessage, String documentUrl, List<LlmMessage> history, LlmStreamCallback callback)
      Description copied from interface: LlmClient
      Generates a response when the specified document URL is not found.
      Specified by:
      generateDocumentNotFoundResponse in interface LlmClient
      Parameters:
      userMessage - the user's message
      documentUrl - the URL that was not found
      history - the conversation history
      callback - the streaming callback
    • generateSummaryResponse

      public void generateSummaryResponse(String userMessage, List<Map<String,Object>> documents, List<LlmMessage> history, LlmStreamCallback callback)
      Description copied from interface: LlmClient
      Generates a summary of the specified documents.
      Specified by:
      generateSummaryResponse in interface LlmClient
      Parameters:
      userMessage - the user's message
      documents - the documents to summarize
      history - the conversation history
      callback - the streaming callback
    • generateFaqAnswerResponse

      public void generateFaqAnswerResponse(String userMessage, List<Map<String,Object>> documents, List<LlmMessage> history, LlmStreamCallback callback)
      Description copied from interface: LlmClient
      Generates an FAQ answer using document content (streaming). Uses a prompt optimized for direct, concise FAQ-style answers.
      Specified by:
      generateFaqAnswerResponse in interface LlmClient
      Parameters:
      userMessage - the user's message
      documents - the documents with content
      history - the conversation history
      callback - the streaming callback
    • generateDirectAnswer

      public void generateDirectAnswer(String userMessage, List<LlmMessage> history, LlmStreamCallback callback)
      Generates a direct answer without document search. This method is currently not called from the streamChatEnhanced() flow, but is provided as an extension point for future DIRECT_ANSWER intent support.
      Specified by:
      generateDirectAnswer in interface LlmClient
      Parameters:
      userMessage - the user's message
      history - the conversation history
      callback - the streaming callback
    • wrapUserInput

      protected String wrapUserInput(String userMessage)
      Wraps user input with delimiters, escaping any closing tags in the content.
      Parameters:
      userMessage - the user's message to wrap
      Returns:
      the wrapped user input
    • buildIntentDetectionSystemPrompt

      protected String buildIntentDetectionSystemPrompt()
      Builds the system prompt for intent detection by removing the user-specific placeholders.
      Returns:
      the system prompt for intent detection
    • addIntentHistory

      protected void addIntentHistory(LlmChatRequest request, List<LlmMessage> history)
      Adds conversation history as structured messages for intent detection.
      Parameters:
      request - the LLM chat request
      history - the conversation history
    • buildEvaluationPrompt

      protected String buildEvaluationPrompt(String userMessage, String query, List<Map<String,Object>> searchResults)
      Builds the evaluation prompt for relevance checking.
      Parameters:
      userMessage - the user's message
      query - the search query
      searchResults - the search results to evaluate
      Returns:
      the evaluation prompt
    • stripHtmlTags

      protected String stripHtmlTags(String text)
      Strips HTML tags from the given text.
      Parameters:
      text - the text to strip HTML tags from
      Returns:
      the text without HTML tags
    • sanitizeDocumentContent

      protected String sanitizeDocumentContent(String text)
      Sanitizes document content by escaping delimiter-like sequences to prevent boundary spoofing in LLM prompts.
      Parameters:
      text - the text to sanitize
      Returns:
      the sanitized text with delimiter sequences escaped
    • buildContext

      protected String buildContext(List<Map<String,Object>> documents, String promptType)
      Builds context from document content for the LLM prompt.
      Parameters:
      documents - the search result documents
      promptType - the prompt type (e.g., "answer", "summary", "faq")
      Returns:
      the context string
    • buildStreamingRequest

      protected LlmChatRequest buildStreamingRequest(String userMessage, String context, List<LlmMessage> history)
      Builds a streaming LLM chat request with conversation history.
      Parameters:
      userMessage - the user's message
      context - the context from search results
      history - the conversation history
      Returns:
      the LLM chat request
    • addHistoryWithBudget

      protected void addHistoryWithBudget(LlmChatRequest request, List<LlmMessage> history, int budgetChars)
      Adds conversation history to the request, truncating from oldest to fit within the character budget.
      Parameters:
      request - the LLM chat request
      history - the conversation history (oldest first)
      budgetChars - the maximum total characters for history messages
    • parseIntentResponse

      protected IntentDetectionResult parseIntentResponse(String response, String userMessage)
      Parses the LLM response and extracts intent detection result.
      Parameters:
      response - the JSON response from LLM
      userMessage - the original user message
      Returns:
      the parsed intent detection result
    • parseEvaluationResponse

      protected RelevanceEvaluationResult parseEvaluationResponse(String response, List<Map<String,Object>> searchResults)
      Parses the evaluation response from LLM.
      Parameters:
      response - the LLM response
      searchResults - the search results
      Returns:
      the parsed evaluation result
    • stripCodeFences

      protected String stripCodeFences(String response)
      Strips code fence markers from JSON response.
      Parameters:
      response - the response that may contain code fences
      Returns:
      the response with code fences removed
    • extractJsonString

      protected String extractJsonString(String json, String key)
      Extracts a string value from JSON response using Jackson parser.
      Parameters:
      json - the JSON response
      key - the key to extract
      Returns:
      the extracted string value
    • extractJsonStringFallback

      protected String extractJsonStringFallback(String json, String key)
      Fallback regex-based extraction for string values.
      Parameters:
      json - the JSON response
      key - the key to extract
      Returns:
      the extracted string value
    • extractJsonBoolean

      protected boolean extractJsonBoolean(String json, String key)
      Extracts a boolean value from JSON response.
      Parameters:
      json - the JSON response
      key - the key to extract
      Returns:
      the extracted boolean value
    • extractJsonArray

      protected List<String> extractJsonArray(String json, String key)
      Extracts a string array from JSON response.
      Parameters:
      json - the JSON response
      key - the key to extract
      Returns:
      the extracted string array
    • extractJsonIntArray

      protected List<Integer> extractJsonIntArray(String json, String key)
      Extracts an integer array from JSON response.
      Parameters:
      json - the JSON response
      key - the key to extract
      Returns:
      the extracted integer array
    • resolveErrorCode

      protected String resolveErrorCode(int statusCode)
      Resolves an HTTP status code to an LlmException error code.
      Parameters:
      statusCode - the HTTP status code
      Returns:
      the corresponding error code
    • truncateForLog

      protected String truncateForLog(String response)
      Returns a bounded prefix of an LLM response suitable for WARN-level logging. Limits operator log volume and reduces accidental exposure of user-supplied text or retrieved context that may appear inside a malformed response. The full payload remains available at DEBUG via the surrounding callers.
      Parameters:
      response - the raw LLM response (may be null)
      Returns:
      a truncated, log-safe prefix; "null" when response is null
    • isTruncatedFinish

      protected boolean isTruncatedFinish(String finishReason)
      Checks if a finish reason indicates that the LLM response was truncated by the output token limit (provider-agnostic).
      Parameters:
      finishReason - the finish reason reported by the LLM provider
      Returns:
      true if the reason indicates truncation
    • isEmptyContentWithLengthFinish

      protected boolean isEmptyContentWithLengthFinish(LlmChatResponse response)
      Checks if the LLM response has empty/blank content combined with a truncation finish reason. This typically indicates that a reasoning model consumed all tokens for internal reasoning, leaving no tokens for actual output content.
      Parameters:
      response - the LLM chat response
      Returns:
      true if content is empty/blank and finish reason indicates truncation
    • getStringValue

      protected String getStringValue(Map<String,Object> map, String key)
      Gets a string value from a map.
      Parameters:
      map - the map to get the value from
      key - the key to look up
      Returns:
      the string value, or an empty string if not found
    • addHistory

      protected void addHistory(LlmChatRequest request, List<LlmMessage> history)
      Adds conversation history to the request.
      Parameters:
      request - the LLM chat request
      history - the conversation history