Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/interfaze/_client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import os
from typing import Any, Dict, Optional
from typing import Any, Dict, Optional, Union

from openai import AsyncOpenAI, OpenAI

Expand Down Expand Up @@ -46,6 +46,14 @@ def _build_headers(
return headers


# OpenAI() fills `organization` / `project` from OPENAI_ORG_ID / OPENAI_PROJECT_ID and sends them
# as OpenAI-Organization / OpenAI-Project headers. Those are OpenAI account ids, so keep them off
# Interfaze requests unless they were passed in explicitly.
def _drop_openai_env_ids(client: Union[OpenAI, AsyncOpenAI], kwargs: Dict[str, Any]) -> None:
client.organization = kwargs.get("organization")
client.project = kwargs.get("project")


class Interfaze:
def __init__(
self,
Expand All @@ -68,6 +76,7 @@ def __init__(
),
**kwargs,
)
_drop_openai_env_ids(self.openai, kwargs)
self.chat = Chat(self.openai)
self.models = self.openai.models
self.tasks = Tasks(self.chat.completions)
Expand Down Expand Up @@ -95,6 +104,7 @@ def __init__(
),
**kwargs,
)
_drop_openai_env_ids(self.openai, kwargs)
self.chat = AsyncChat(self.openai)
self.models = self.openai.models
self.tasks = AsyncTasks(self.chat.completions)
27 changes: 27 additions & 0 deletions tests/test_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,33 @@ def test_default_headers_omit_control_flags_when_unset():
assert "x-admin-key" not in h


@respx.mock
def test_openai_org_and_project_env_not_sent(monkeypatch):
monkeypatch.setenv("OPENAI_ORG_ID", "org-from-env")
monkeypatch.setenv("OPENAI_PROJECT_ID", "proj_from_env")
route = mock_json(BASIC)
Interfaze(api_key="t").chat.completions.create(messages=[{"role": "user", "content": "x"}])
h = last_headers(route)
assert "openai-organization" not in h and "openai-project" not in h

asyncio.run(
AsyncInterfaze(api_key="t").chat.completions.create(messages=[{"role": "user", "content": "x"}])
)
h = last_headers(route)
assert "openai-organization" not in h and "openai-project" not in h


@respx.mock
def test_explicit_openai_org_and_project_still_sent(monkeypatch):
monkeypatch.setenv("OPENAI_ORG_ID", "org-from-env")
route = mock_json(BASIC)
Interfaze(api_key="t", organization="org-explicit", project="proj_explicit").chat.completions.create(
messages=[{"role": "user", "content": "x"}]
)
h = last_headers(route)
assert h["openai-organization"] == "org-explicit" and h["openai-project"] == "proj_explicit"


@respx.mock
def test_per_request_extra_headers_override_client_default():
route = mock_json(BASIC)
Expand Down