mirror of
https://github.com/andrewyng/openworker.git
synced 2026-09-03 04:49:26 +00:00
feat: support custom Responses endpoints
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""OpenAI Responses provider — native OpenAI models via `/v1/responses`.
|
||||
"""OpenAI Responses provider — native and compatible models via `/responses`.
|
||||
|
||||
Chat Completions rejects function tools combined with any `reasoning_effort` other than
|
||||
`none` on GPT-5.6+ ("use /v1/responses"), which had reasoning pinned OFF for native OpenAI
|
||||
@@ -8,9 +8,10 @@ reasoning + tools at real effort levels, streamed reasoning summaries (→ the s
|
||||
chain-of-thought continuity across tool round-trips via `store: false` +
|
||||
`include: ["reasoning.encrypted_content"]` — nothing retained server-side.
|
||||
|
||||
Routing: the `openai` provider entry with NO custom base_url builds this class; a custom
|
||||
endpoint (Azure, vLLM, any OpenAI-compatible gateway) and every compat vendor keep the
|
||||
Chat Completions `OpenAIProvider` (registry.py).
|
||||
Routing: the `openai` provider entry with NO custom base_url builds this class. Most custom
|
||||
endpoints (Azure, vLLM, and the existing compat vendors) keep the Chat Completions
|
||||
`OpenAIProvider`; vendors that explicitly implement the Responses wire can opt into this
|
||||
class with their own base URL (registry.py).
|
||||
|
||||
Like the other native providers, this is mostly a pair of pure converters from the
|
||||
canonical OpenAI-chat-shaped history to Responses `input` items. What the converters
|
||||
@@ -289,14 +290,16 @@ class OpenAIResponsesProvider(ProviderClient):
|
||||
default_model: str = "gpt-5.6-sol",
|
||||
api_key: Optional[str] = None,
|
||||
secrets: Any = None,
|
||||
base_url: Optional[str] = None,
|
||||
):
|
||||
# Same deferred-client contract as OpenAIProvider: built lazily so an engine can be
|
||||
# assembled before any key exists; key resolves at call time (explicit → env →
|
||||
# SecretStore). Tests inject a `client` directly. No base_url — a custom endpoint
|
||||
# routes to the Chat Completions provider instead (registry.py).
|
||||
# SecretStore). Tests inject a `client` directly. `base_url` is opt-in: stock OpenAI
|
||||
# leaves it unset, while Responses-compatible vendors can supply their own endpoint.
|
||||
self._client = client
|
||||
self._api_key = api_key
|
||||
self._secrets = secrets
|
||||
self._base_url = (base_url or "").strip().rstrip("/") or None
|
||||
self.default_model = default_model
|
||||
|
||||
def _ensure_client(self) -> Any:
|
||||
@@ -310,7 +313,10 @@ class OpenAIResponsesProvider(ProviderClient):
|
||||
"No model API key configured. Set OPENAI_API_KEY in the environment, "
|
||||
"or add your key in Manage → Settings."
|
||||
)
|
||||
self._client = OpenAI(api_key=key)
|
||||
kwargs = {"api_key": key}
|
||||
if self._base_url:
|
||||
kwargs["base_url"] = self._base_url
|
||||
self._client = OpenAI(**kwargs)
|
||||
return self._client
|
||||
|
||||
def _request_kwargs(
|
||||
|
||||
@@ -17,6 +17,43 @@ from coworker.providers.openai_responses import (
|
||||
convert_tools,
|
||||
)
|
||||
|
||||
|
||||
def test_responses_custom_base_url_reaches_sdk(monkeypatch):
|
||||
captured: dict = {}
|
||||
|
||||
def fake_openai(**kwargs):
|
||||
captured.update(kwargs)
|
||||
return SimpleNamespace()
|
||||
|
||||
monkeypatch.setattr("openai.OpenAI", fake_openai)
|
||||
provider = OpenAIResponsesProvider(
|
||||
api_key="ark-key",
|
||||
base_url="https://ark.example/api/v3/",
|
||||
)
|
||||
|
||||
provider._ensure_client()
|
||||
|
||||
assert captured == {
|
||||
"api_key": "ark-key",
|
||||
"base_url": "https://ark.example/api/v3",
|
||||
}
|
||||
|
||||
|
||||
def test_stock_openai_responses_path_unchanged(monkeypatch):
|
||||
"""Lockdown: stock OpenAI must not receive a vendor base URL."""
|
||||
captured: dict = {}
|
||||
|
||||
def fake_openai(**kwargs):
|
||||
captured.update(kwargs)
|
||||
return SimpleNamespace()
|
||||
|
||||
monkeypatch.setattr("openai.OpenAI", fake_openai)
|
||||
provider = OpenAIResponsesProvider(api_key="openai-key")
|
||||
|
||||
provider._ensure_client()
|
||||
|
||||
assert captured == {"api_key": "openai-key"}
|
||||
|
||||
# -- fakes ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user