Skip to content

Make consistent OPENAI base url#1579

Merged
jasperblues merged 1 commit intomainfrom
bugfix/consistent-base-url
Apr 6, 2026
Merged

Make consistent OPENAI base url#1579
jasperblues merged 1 commit intomainfrom
bugfix/consistent-base-url

Conversation

@jasperblues
Copy link
Copy Markdown
Contributor

Fix inconsistent /v1 in OpenAI-compatible base URLs

Problem

Spring AI's OpenAiApi.builder().baseUrl() appends /v1 internally. The openai-java SDK (OpenAIOkHttpClient) does NOT — it uses the URL as-is. Both read OPENAI_BASE_URL, which is set without /v1 for Spring AI compatibility. This mismatch causes issues in several places.

Fixes

  • OpenAiCompatibleModelFactory.mistral() — base URL included /v1, producing double /v1/v1/ through Spring AI
  • OpenAiCompatibleModelFactory.byok() KDoc — example URL included /v1, misleading for Spring AI consumers
  • OpenAiCompatibleModelFactoryByokSpecTest — test example URL included /v1
  • LLMOpenAiGuardRailsIntegrationITOpenAIOkHttpClient.fromEnv() used OPENAI_BASE_URL without /v1, producing 404s on the moderation endpoint

New file

  • OpenAiCompatibleModelFactoryByokIT — IT tests that validate BYOK buildValidated() against real provider APIs (OpenAI, DeepSeek, Mistral, Gemini). Each test is gated by @EnabledIfEnvironmentVariable so it skips cleanly without the corresponding API key.

Details

OpenAiCompatibleModelFactory.mistral()

Before: ByokSpec("https://api.mistral.ai/v1", ...) — Spring AI appends /v1 internally, producing https://api.mistral.ai/v1/v1/chat/completions (confirmed 404 via curl).

After: ByokSpec("https://api.mistral.ai", ...) — Spring AI appends /v1, producing the correct https://api.mistral.ai/v1/chat/completions (confirmed 200 via curl and BYOK IT test).

LLMOpenAiGuardRailsIntegrationIT

Before: OpenAIOkHttpClient.fromEnv() — reads OPENAI_BASE_URL (spring AI compatible version of https://api.openai.com), SDK appends /moderations directly → hits https://api.openai.com/moderations → 404. This was masked by the previous try/catch pattern in testThinkingCreateObject — the NotFoundException was silently swallowed because it wasn't a GuardRailViolationException. Only surfaced after #1577 replaced the catch with assertThrows.

After: Explicit builder reads OPENAI_BASE_URL and appends /v1https://api.openai.com/v1, SDK appends /moderations → hits https://api.openai.com/v1/moderations → 200. Moderation correctly flags the content (violence category) and GuardRailViolationException is thrown.

Verified

  • All 15 unit tests in embabel-agent-openai pass.
  • OpenAiCompatibleModelFactoryByokIT — 3 passed (OpenAI, DeepSeek, Mistral), 1 skipped (Gemini, no key). Mistral confirmed working against the real API after the /v1 fix.
  • LLMOpenAiGuardRailsIntegrationIT.testThinkingCreateObject now passes.

Fun fact

The guardrails test prompt mentions blowing up crocodiles in Florida. Southern Florida is actually the only place in the world where alligators and crocodiles coexist — the American crocodile (Crocodylus acutus) lives alongside the American alligator in the Everglades. The more you know.

@jasperblues jasperblues requested a review from igordayen April 6, 2026 00:14
Copy link
Copy Markdown
Contributor

@igordayen igordayen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Jasper, so running IT time2time in bulk actually helps:)

@jasperblues jasperblues merged commit 4c27995 into main Apr 6, 2026
10 checks passed
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 6, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants