Skip to content

Harden OpenAI-compatible AI adapter requests#488

Open
jtc268 wants to merge 2 commits into
profullstack:masterfrom
jtc268:harden-ai-adapter-requests
Open

Harden OpenAI-compatible AI adapter requests#488
jtc268 wants to merge 2 commits into
profullstack:masterfrom
jtc268:harden-ai-adapter-requests

Conversation

@jtc268
Copy link
Copy Markdown

@jtc268 jtc268 commented May 30, 2026

Summary

  • normalize configured base URLs for Groq, DeepSeek, Mistral, xAI, and Cerebras before appending /v1/chat/completions
  • redact provider API keys from non-2xx response excerpts before surfacing adapter errors
  • add regression coverage for trailing-slash base URLs and redacted error bodies across all five adapters

Tests

  • pnpm vitest run packages/ai/groq/src/index.test.ts packages/ai/deepseek/src/index.test.ts packages/ai/mistral/src/index.test.ts packages/ai/xai/src/index.test.ts packages/ai/cerebras/src/index.test.ts
  • pnpm --filter './packages/ai/{groq,deepseek,mistral,xai,cerebras}' typecheck

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 30, 2026

Greptile Summary

This PR hardens the five OpenAI-compatible AI adapters (Groq, DeepSeek, Mistral, xAI, Cerebras) by normalizing trailing slashes from configured base URLs and redacting provider API keys from error messages before surfacing them to callers.

  • URL normalization: each adapter now runs .replace(/\/+$/, '') on the base URL before appending /v1/chat/completions, preventing double-slash endpoint paths when a user-supplied baseUrl has a trailing slash.
  • Key redaction: error handling now correctly calls redact(await res.text(), apiKey) before .slice(0, 200), so the full response body is sanitised first and no key fragment survives truncation. Tests use a 190-character prefix to verify the boundary case.
  • Test coverage: each adapter gains two new test cases — one for trailing-slash URL normalization and one for boundary-straddling key redaction — replacing the simpler single error-message assertions.

Confidence Score: 5/5

Safe to merge — the redact-before-slice ordering is correct across all five adapters, and the boundary-case tests validate the key behaviour.

All five adapters correctly call redact on the full response body before truncating to 200 characters, so no API key fragment can survive into the error message. URL normalization is a simple regex strip. The duplicated helper functions are a maintenance concern but carry no runtime risk.

No files require special attention. The only note is that redact and chatCompletionsUrl are duplicated across all five adapter files — worth consolidating in a follow-up, but not blocking.

Important Files Changed

Filename Overview
packages/ai/groq/src/index.ts Adds chatCompletionsUrl() and redact() helpers; error handling now correctly calls redact on full body before slicing to 200 chars.
packages/ai/deepseek/src/index.ts Same pattern as groq: URL normalization and redact-before-slice applied correctly.
packages/ai/mistral/src/index.ts Same pattern as groq: URL normalization and redact-before-slice applied correctly.
packages/ai/xai/src/index.ts Same pattern as groq: URL normalization and redact-before-slice applied correctly.
packages/ai/cerebras/src/index.ts Same pattern as groq: URL normalization and redact-before-slice applied correctly.
packages/ai/groq/src/index.test.ts Replaces single error test with two new tests: trailing-slash URL normalization and boundary-straddling key redaction.
packages/ai/deepseek/src/index.test.ts Mirrors groq test changes with DeepSeek-specific status code (401) and env key.
packages/ai/mistral/src/index.test.ts Mirrors groq test changes with Mistral-specific status code (400) and env key.
packages/ai/xai/src/index.test.ts Mirrors groq test changes with xAI-specific status code (403) and env key.
packages/ai/cerebras/src/index.test.ts Mirrors groq test changes with Cerebras-specific status code (500) and env key.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant Adapter
    participant chatCompletionsUrl
    participant fetch
    participant redact

    Caller->>Adapter: generate(ctx, prompt, opts, config)
    Adapter->>chatCompletionsUrl: baseUrl (may have trailing slash)
    chatCompletionsUrl-->>Adapter: normalized URL (/v1/chat/completions)
    Adapter->>fetch: POST normalized URL
    alt res.ok
        fetch-->>Adapter: 2xx JSON response
        Adapter-->>Caller: "{ text, model, tokens }"
    else !res.ok
        fetch-->>Adapter: non-2xx response
        Adapter->>redact: res.text() + apiKey
        redact-->>Adapter: sanitised body (key replaced with [redacted])
        Adapter->>Adapter: .slice(0, 200)
        Adapter-->>Caller: throw Error("Provider STATUS: truncated-sanitised-body")
    end
Loading

Reviews (2): Last reviewed commit: "Redact adapter errors before truncating" | Re-trigger Greptile

Comment thread packages/ai/groq/src/index.ts Outdated
Comment thread packages/ai/cerebras/src/index.ts Outdated
Comment thread packages/ai/deepseek/src/index.ts Outdated
Comment thread packages/ai/mistral/src/index.ts Outdated
Comment thread packages/ai/xai/src/index.ts Outdated
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.

1 participant