MockConfigEntry defaults to version=1, which triggers
async_migrate_integration on component setup; that legacy path
indexes entry.data[CONF_API_KEY] directly and raised KeyError for the
new optional-api-key entry in test_api_key_optional, before
async_setup_entry (and thus AsyncOpenAI) was ever reached. Pin both
entries in this file to version=2/minor_version=7, matching the
config flow's current VERSION/MINOR_VERSION and conftest's
mock_config_entry fixture.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01739Seac5eMAfNwFeiwV5r4
The OpenAI SDK rejects api_key=None, so all three client sites now
fall back to a PLACEHOLDER_API_KEY ("not-required") when the entry has
no key, letting an unauthenticated LiteLLM/proxy endpoint be configured
with the API key field left blank.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01739Seac5eMAfNwFeiwV5r4
New url_util.py (deliberately separate from the vendored files, so a
future upstream re-sync never conflicts with it): normalize_base_url
strips whitespace/trailing slashes and rejects non-http(s) or hostless
URLs; sanitize_url_for_logging masks embedded basic-auth credentials
for Task 7's discovery logging.
Wires normalization into config_flow.validate_input before the client
is built, with a new invalid_base_url form error.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01739Seac5eMAfNwFeiwV5r4
Adds CONF_BASE_URL/DEFAULT_BASE_URL and threads base_url through every
AsyncOpenAI construction site: config_flow.validate_input,
__init__.async_setup_entry, and config_flow's web-search geolocation
helper (_get_location_data) — the easy one to miss, since it would
otherwise silently talk to api.openai.com when the user configured a
different endpoint.
Fixes upstream-ported fixtures (conftest.mock_config_entry,
test_config_flow's inline MockConfigEntry/data-schema assertions) to
supply base_url now that the config-flow schema requires it.
No translations/en.json exists in this repo (only strings.json), so
only strings.json got the new "base_url" UI strings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01739Seac5eMAfNwFeiwV5r4
Ported from home-assistant/core tag 2026.9.2 (tests/components/openai_conversation):
conftest.py fixtures merged into tests/conftest.py, test_config_flow.py,
test_conversation.py and test_ai_task.py copied and rewritten for the fork's
custom_components.openai_compatible / "openai_compatible" domain.
Also copied as local test infrastructure (not core-only, self-contained):
- tests/__init__.py: the openai_conversation test package's own event-builder
helpers (create_message_item, create_function_tool_call_item, etc.) that
test_conversation.py and test_ai_task.py import via `from . import ...`.
- tests/snapshots/test_conversation.ambr: just the test_model_args snapshot
entry, the one surviving syrupy-based assertion (see deletions below).
Deleted from test_conversation.py — depend on tests.components.conversation's
MockChatLog/mock_chat_log fixture, which lives in home-assistant/core's own
tests tree and is not distributable via pytest-homeassistant-custom-component
(confirmed: not present in the installed package's file list):
- test_function_call
- test_function_call_without_reasoning
- test_reasoning_summary_off_omits_summary_key
- test_web_search
- test_web_search_remove_citations_gpt5
- test_code_interpreter
Their now-unused imports (create_code_interpreter_item, create_web_search_item,
CONF_CODE_INTERPRETER, CONF_REASONING_SUMMARY, the CONF_WEB_SEARCH* constants,
freezegun.freeze_time, ToolInput, datetime) were removed with them.
`from tests.common import MockConfigEntry` (core's own tests package, also not
shipped by pytest-homeassistant-custom-component) rewritten to
`from pytest_homeassistant_custom_component.common import MockConfigEntry`,
matching the convention already used in this fork's tests/test_init.py.
Not run locally: this workstation is Python 3.13, HA 2026.9 (and
pytest-homeassistant-custom-component) require 3.14, so no correct local
interpreter exists. Validated with `python3 -m py_compile` only; CI
(actions/setup-python@3.14) is the real test run.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01739Seac5eMAfNwFeiwV5r4
Verbatim copy from home-assistant/core at tag 2026.9.2, with only the
domain constant and manifest changed. Apache-2.0, attribution in NOTICE.
Also fixed self-references the domain rename left dangling: the
config_entry selector's `integration:` field in services.yaml, the
`[%key:component::openai_conversation::...%]` translation
cross-references in strings.json, the deprecated-action descriptions
naming the old domain, and config_flow.py's instructions_url (now
pointing at this repo instead of the core docs page).
Local pytest run skipped per owner decision (see prior commit); files
validated with py_compile / json.load / yaml.safe_load instead. CI
(added in the prior commit) is the real gate.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01739Seac5eMAfNwFeiwV5r4
Local pytest execution is skipped by owner decision: no release of
pytest-homeassistant-custom-component that pins a Home Assistant
2026.9.x floor installs on Python 3.13 (0.13.317+ requires Python
3.14, which this workstation does not have). requirements_test.txt
is pinned to the correct >=0.13.317 range for CI (Python 3.14) and
files are validated with py_compile instead of a local pytest run.
CI workflows (test.yaml, validate.yaml) moved forward from a later
task since, with local testing gone, CI is the only gate and must
exist before the code it gates.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01739Seac5eMAfNwFeiwV5r4