Skip to content

feat: Add openai-responses-api support and filter out unsupported models. - #22

Open
tinysnake wants to merge 1 commit into
getpipher:mainfrom
tinysnake:feat/openai-responses-api
Open

feat: Add openai-responses-api support and filter out unsupported models.#22
tinysnake wants to merge 1 commit into
getpipher:mainfrom
tinysnake:feat/openai-responses-api

Conversation

@tinysnake

Copy link
Copy Markdown

Summary

callVisionModel currently hardcodes one REST shape (POST {baseUrl}/chat/completions with a messages body and choices[].message.content parsing). Every model in pi-ai's registry carries a declared api type, and the delegate path already holds the full Model<Api> from modelRegistry.find() — so we can dispatch the request/response shape on that authority instead of guessing.

This PR makes vision delegation speak both openai-completions and openai-responses:

model.api Endpoint Request body Response parsing
openai-completions POST {baseUrl}/chat/completions messages[] with image_url data URL (unchanged) choices[].message.content || reasoning_content
openai-responses POST {baseUrl}/responses input[] with input_image / input_text, max_output_tokens (≥16), nested reasoning: { effort } output[].message.content[].output_text
anything else no network call throws a clear "unsupported API type" error

Motivation

With a openai-responses model (e.g. gpt-5.6-luna on opencode-go) configured as the vision model, delegation sent a well-formed request to the wrong endpoint semantics and failed with a 400 — the model registry already declared the correct API type, but the extension ignored it. Fallback (openai-codex) was also broken in that environment.

Behavior changes

  • Unsupported API types (anthropic-messages, google-generative-ai, …) now fail with an explicit error and flow into the existing retry/fallback path — classified as a client error, so no retry is wasted and the configured fallback model still fires. Previously they silently hit /chat/completions and failed confusingly.
  • Model pickers + auto-detect filter to supported types: visionCapableModels() and autoDetectDefaults() now use the new lib/supported.ts (isUsableVisionModel()), so users only see vision models the delegate path can actually run. Adding a future API type means relaxing one filter + adding one dispatch branch.

Testing

  • pnpm typecheck clean, pnpm test:run361 tests pass (was 353).
  • New tests:
    • responses request shape: /responses URL, input[] body, input_image/input_text, max_output_tokens ≥ 16, system role, nested reasoning.effort (and no flat reasoning_effort)
    • responses response parsing: output[].message.content[].output_text, empty-output → "no content" error
    • unsupported API type: clear error, zero network calls
    • integration: unsupported primary → no retry → fallback fires
    • auto-detect: anthropic-messages models filtered out; openai-responses models still picked
  • Verified end-to-end against opencode-go/gpt-5.6-luna (responses): image description returned correctly.

Support openai-responses models in callVisionModel: new responses path
(POST /responses, input[] body with input_image/input_text, max_output_tokens
>= 16, nested reasoning.effort, output_text parsing). chat/completions path
is preserved unchanged via a symmetric if/else dispatcher; unknown API types
throw a clear error and flow into the existing fallback.

Pickers and auto-detect filter to supported API types via new
lib/supported.ts so users never select a model that can't run.

Tests: +8 (responses request/response shape, unsupported-type error +
fallback, auto-detect filtering). 361 pass.
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