feat: Enhance error handling by introducing ErrorResponse class and updating logErrorResponse method

This commit is contained in:
extio-de
2026-05-10 18:46:30 +02:00
parent 47c278309b
commit f97d758afd
6 changed files with 28 additions and 21 deletions

View File

@@ -1,7 +1,5 @@
package de.extio.lmlib.client.oai.completion;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.Duration;
@@ -19,12 +17,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatusCode;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestClientResponseException;
import com.fasterxml.jackson.annotation.JsonInclude;
import tools.jackson.core.JacksonException;
import tools.jackson.core.json.JsonReadFeature;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.ObjectMapper;
@@ -171,13 +169,17 @@ public abstract class AbstractCompletionClient implements Client, DisposableBean
return this.getModelNames(modelProfile, false).stream().findFirst().orElse("");
}
protected void logErrorResponse(final HttpStatusCode statusCode, final InputStream responseBody) {
protected String getErrorMessage(final String errorBody) {
try {
LOGGER.warn("Error response from server: {} {}", statusCode, new String(responseBody.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8));
final var errorResponse = this.objectMapper.readValue(errorBody, ErrorResponse.class);
if (errorResponse != null && errorResponse.error() != null && errorResponse.error().message() != null && !errorResponse.error().message().isBlank()) {
return errorResponse.error().message();
}
catch (final IOException e) {
LOGGER.warn("Error response from server: {} <failed to read response body: {}>", statusCode, e.getMessage());
}
catch (final JacksonException e) {
LOGGER.debug("Failed to parse error response body", e);
}
return errorBody;
}
private List<String> loadModelNames(final ModelProfile modelProfile) {

View File

@@ -0,0 +1,10 @@
package de.extio.lmlib.client.oai.completion;
import com.fasterxml.jackson.annotation.JsonProperty;
public record ErrorResponse(@JsonProperty("error") ErrorMessage error) {
public record ErrorMessage(@JsonProperty("message") String message) {
}
}

View File

@@ -81,8 +81,10 @@ public class ChatCompletionClient extends AbstractCompletionClient {
.body(requestBody)
.exchange((clientRequest, clientResponse) -> {
if (clientResponse.getStatusCode().isError()) {
this.logErrorResponse(clientResponse.getStatusCode(), clientResponse.getBody());
throw new IllegalStateException("Error response from server: " + clientResponse.getStatusCode());
final var errorBody = new String(clientResponse.getBody().readAllBytes(), StandardCharsets.UTF_8);
final var errorMessage = this.getErrorMessage(errorBody);
LOGGER.warn("Error response from server: {} {}", clientResponse.getStatusCode(), errorMessage);
throw new IllegalStateException("Error response from server: " + clientResponse.getStatusCode() + " " + errorMessage);
}
if (chunkConsumer == null) {

View File

@@ -83,8 +83,10 @@ public class TextCompletionClient extends AbstractCompletionClient {
.body(requestBody)
.exchange((clientRequest, clientResponse) -> {
if (clientResponse.getStatusCode().isError()) {
this.logErrorResponse(clientResponse.getStatusCode(), clientResponse.getBody());
throw new IllegalStateException("Error response from server: " + clientResponse.getStatusCode());
final var errorBody = new String(clientResponse.getBody().readAllBytes(), StandardCharsets.UTF_8);
final var errorMessage = this.getErrorMessage(errorBody);
LOGGER.warn("Error response from server: {} {}", clientResponse.getStatusCode(), errorMessage);
throw new IllegalStateException("Error response from server: " + clientResponse.getStatusCode() + " " + errorMessage);
}
if (chunkConsumer == null) {

View File

@@ -130,7 +130,7 @@ public class OllamaClient implements Client {
.exchange((clientRequest, clientResponse) -> {
if (clientResponse.getStatusCode().isError()) {
this.logErrorResponse(clientResponse.getStatusCode(), clientResponse.getBody());
throw new IllegalStateException("Error response from server: " + clientResponse.getStatusCode());
throw new IllegalStateException("Error response from server: " + clientResponse.getStatusCode() + " " + clientResponse.getBody());
}
if (chunkConsumer == null) {
final var ollamaResponse = this.objectMapper.readValue(clientResponse.getBody(), OllamaChatResponse.class);

View File

@@ -106,15 +106,6 @@ public class OpenRouterClient extends ChatCompletionClient {
return metadata == null ? OpenAiProviderDialect.ChatTokenLimitParameterMode.MAX_COMPLETION_TOKENS : metadata.tokenLimitParameterMode();
}
@Override
protected OpenAiProviderDialect.ReasoningEffort reasoningEffort(final ModelProfile modelProfile) {
if (!this.sendReasoning(modelProfile)) {
return null;
}
final var reasoningEffort = super.reasoningEffort(modelProfile);
return reasoningEffort == null ? OpenAiProviderDialect.ReasoningEffort.MEDIUM : reasoningEffort;
}
private OpenRouterModelDiscovery.ResolvedOpenRouterModelMetadata resolveMetadata(final ModelProfile modelProfile) {
if (modelProfile == null || modelProfile.modelProvider() != ModelProvider.OPENROUTER) {
return null;