Migrate OpenAI provider to Responses API#50
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
OpenAI provider on Responses API; split out OpenAI-compatible backends; rework error handling
GPT-5.4 with both
toolsandreasoning_effortis rejected on/v1/chat/completions— OpenAI now points that combination at/v1/responses. Rather than branch the OpenAI provider per model family, this PR moveswippy.llm.openaientirely onto the Responses API and pulls everything that needs Chat Completions (Ollama, vLLM, llama.cpp, OpenRouter, Together, Groq, Fireworks, Mistral, etc.) into a separatewippy.llm.openai_compatprovider.Error handling across all providers (OpenAI, OpenAI-compatible, Claude, Bedrock, Google) was reworked.
Provider split
wippy.llm.openai→/v1/responsesonly. Required fortools+reasoning_efforton GPT-5.4; also unlocksprevious_response_id, encrypted reasoning persistence,minimal/xhigheffort, and the new SSE event model.wippy.llm.openai_compat→/v1/chat/completions, with its ownOPENAI_COMPAT_*env vars. Drop-in for any OpenAI-compatible endpoint. Keeps OpenRouterreasoning_detailspassthrough and the full sampling parameter set (frequency_penalty,presence_penalty,stop,seed).Embeddings keep their own endpoint and are unaffected.
Responses API mapping
messages→input[]items;system/developerextracted into a top-levelinstructionsfield.function_callandfunction_call_outputare now top-level items rather than nested under an assistant message.nameandparametersat the top level;strictdefaults tofalseto keep existing schemas working.max_tokens→max_output_tokens;reasoning_effort→reasoning.effortwith the full range (minimal/low/medium/high/xhigh).text.format.json_schemainstead ofresponse_format.response.output_text.delta,response.function_call_arguments.{delta,done},response.reasoning_summary_text.delta,response.completed,response.failed.Error handling
A single fluent path replaces
output.to_structured_error(...)and per-mappermap_error_response:mapper.classify_error(http_err) -> (kind, message, details)is now a pure function in every mapper. Noerrors.new(...)calls outsideoutput.lua.output.errors.<op>(contract_args)reads_provider_idandmodeldirectly fromcontract_args— handlers no longer pass literal strings.build_errorinoutput.luais the single observability point:logger:named("llm"):error(...)for every provider error, with kind, retryable, provider, operation, model, and the calling user (resolved automatically fromsecurity.actor()).ERROR_KIND_MAPuses stdliberrors.RATE_LIMITED/errors.UNAVAILABLE/ etc. instead of hardcoded kind strings.(nil, structured_error)on the error path; the publicllm.*API still returns(result, err_string)via aformat_errorshim.ErrorBuilder,ClassifyError,ErrorContract,ErrorBuilderFactory) added so the linter follows the fluent chain.Backwards compatibility
llm.generate / structured_output / embed / statusAPI is unchanged.wippy.llm.openaiwithOPENAI_BASE_URLpointed at Ollama, vLLM, OpenRouter, Together, etc. needs to switch the provider towippy.llm.openai_compat:providerand useOPENAI_COMPAT_BASE_URL. Same wire format as before for those backends.Tests
Mapper unit tests cover input mapping, tool format, options (including
minimal/xhigheffort), output items, refusal, incomplete→length, encrypted_reasoning round-trip, and error classification. Handler tests adapted to(response, err). SSE stream tests rewritten to the named-event format. Status-handler tests are unchanged — those still use the data-driven{ success, status, message }shape on purpose.output.to_structured_errorandmapper.map_error_responseare gone from production code; integration tests' error-path assertions migrated toerr:kind()/err:message().