Files
ha-openai-compatible/custom_components/openai_compatible/translations/en.json
T
Adam SmithandClaude Opus 5 6a599e092a feat: ask for the model on the first screen of the endpoint flow
The model field was one screen too late. Reported directly: "this is where
I would have expected to see the model dropdown", on the AI Task init step
that showed only Name and the recommended checkbox.

- CONF_CHAT_MODEL moves from async_step_additional to async_step_init for
  conversation and ai_task_data, so all four endpoint types now ask on the
  first screen. stt and tts already did.
- UNSUPPORTED_MODELS is validated there too, since the recommended path
  creates the subentry from that step and would otherwise skip the check.
- model_list.default_model() picks what to preselect: RECOMMENDED_CHAT_MODEL
  only when the provider actually serves it (or discovery returned nothing),
  otherwise the first advertised model. Offering a stranger's gpt-4o-mini to
  a LiteLLM user preselects a model that fails on first use.

This is the trade I got wrong last commit. I kept the field on the second
step to avoid touching 71 ported tests, having judged them unfixable
mechanically. They were not: the 71 were ~13 functions under parametrize,
and test_subentry_switching's data is already a list of per-step dicts, so
moving a model between steps is moving a key between two dicts. Two scripted
passes moved 14 of them; 5 needed reasoning about (an error that now surfaces
on init rather than the next step, and four cases whose expected data gains
the now-always-recorded model).

async_fetch_model_ids now also catches non-OpenAIError exceptions. Found via
a ported test whose client is a MagicMock: the TypeError from awaiting it
escaped and broke the whole form. A real proxy returning a payload the SDK
cannot parse would do the same, and this runs inside a dialog with a working
free-text fallback, so nothing it raises justifies taking the form down.

Also fixes a string that was simply false on a third-party provider, again
reported from the UI: "Store requests and responses in OpenAI" / "stored by
OpenAI and visible in your OpenAI dashboard logs". It now describes the
Responses API store flag and says support varies. Swept the other 43
OpenAI-mentioning strings while there -- the rest are [%key:...%]
self-references or this fork's own action names, and no other option text
makes a claim about who stores the data.

Local: 170 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NxJYWgGJtCw13qUHZtG8ki
2026-09-17 23:18:02 -04:00

334 lines
13 KiB
JSON

{
"config": {
"abort": {
"already_configured": "Service is already configured",
"reauth_successful": "Re-authentication was successful"
},
"error": {
"cannot_connect": "Failed to connect",
"credentials_in_url": "The base URL must not contain a username or password. Put authentication in the API key field instead.",
"invalid_auth": "Invalid authentication",
"invalid_base_url": "That does not look like a valid http(s) URL.",
"unknown": "Unexpected error"
},
"step": {
"reauth_confirm": {
"data": {
"api_key": "API key",
"base_url": "API base URL"
},
"data_description": {
"api_key": "The API key for this endpoint. Leave blank if it does not require authentication.",
"base_url": "The base URL of the OpenAI-compatible API, including any version path such as /v1. The endpoint must implement the Responses API."
},
"description": "Reauthentication required. Please enter your updated API key and confirm the API base URL."
},
"user": {
"data": {
"api_key": "API key",
"base_url": "API base URL",
"name": "Name"
},
"data_description": {
"api_key": "The API key for this endpoint. Leave blank if it does not require authentication.",
"base_url": "The base URL of the OpenAI-compatible API, including any version path such as /v1. The endpoint must implement the Responses API.",
"name": "A label for this provider, for example LiteLLM. Defaults to the endpoint's host."
},
"description": "Connect to an OpenAI-compatible API. One entry per server or provider; you add endpoints for individual models afterwards. See the [setup notes]({instructions_url}) for what the endpoint has to support."
}
}
},
"config_subentries": {
"ai_task_data": {
"abort": {
"entry_not_loaded": "Cannot add things while the configuration is disabled.",
"reconfigure_successful": "Reconfiguration was successful"
},
"entry_type": "AI task",
"error": {
"code_interpreter_minimal_reasoning": "Code interpreter is not supported with minimal reasoning effort",
"model_not_supported": "This model is not supported, please select a different model",
"web_search_minimal_reasoning": "Web search is currently not supported with minimal reasoning effort"
},
"initiate_flow": {
"reconfigure": "Reconfigure AI task",
"user": "Add AI task"
},
"step": {
"additional": {
"data": {
"chat_model": "Model",
"max_tokens": "Maximum tokens to return in response",
"store_responses": "Store requests and responses on the provider",
"temperature": "Temperature",
"top_p": "Top P"
},
"data_description": {
"store_responses": "Sets the Responses API store flag, asking the provider to keep requests and responses in its own logs. Support varies: OpenAI shows them in its dashboard, while many compatible servers ignore the flag entirely."
},
"title": "Additional settings"
},
"init": {
"data": {
"name": "Name",
"recommended": "Recommended model settings"
}
},
"model": {
"data": {
"code_interpreter": "Enable code interpreter tool",
"image_model": "Image generation model",
"inline_citations": "Include links in web search results",
"pro_mode": "Pro mode",
"reasoning_effort": "Reasoning effort",
"reasoning_summary": "Reasoning summary",
"search_context_size": "Search context size",
"service_tier": "Service tier",
"user_location": "Include home location",
"web_search": "Enable web search"
},
"data_description": {
"code_interpreter": "This tool, also known as the python tool to the model, allows it to run code to answer questions",
"image_model": "The model to use when generating images",
"inline_citations": "If disabled, additional prompt is added to ask the model to not include source citations",
"pro_mode": "Perform more model work to improve reliability on difficult tasks and return a single final answer",
"reasoning_effort": "How many reasoning tokens the model should generate before creating a response to the prompt",
"reasoning_summary": "Controls the length and detail of reasoning summaries provided by the model",
"search_context_size": "High level guidance for the amount of context window space to use for the search",
"service_tier": "Controls the cost and response time",
"user_location": "Refine search results based on geography",
"web_search": "Allow the model to search the web for the latest information before generating a response"
},
"title": "Model-specific options"
}
}
},
"conversation": {
"abort": {
"entry_not_loaded": "Cannot add things while the configuration is disabled.",
"reconfigure_successful": "Reconfiguration was successful"
},
"entry_type": "Conversation agent",
"error": {
"code_interpreter_minimal_reasoning": "Code interpreter is not supported with minimal reasoning effort",
"model_not_supported": "This model is not supported, please select a different model",
"web_search_minimal_reasoning": "Web search is currently not supported with minimal reasoning effort"
},
"initiate_flow": {
"reconfigure": "Reconfigure conversation agent",
"user": "Add conversation agent"
},
"step": {
"additional": {
"data": {
"chat_model": "Model",
"max_tokens": "Maximum tokens to return in response",
"store_responses": "Store requests and responses on the provider",
"temperature": "Temperature",
"top_p": "Top P"
},
"data_description": {
"store_responses": "Sets the Responses API store flag, asking the provider to keep requests and responses in its own logs. Support varies: OpenAI shows them in its dashboard, while many compatible servers ignore the flag entirely."
},
"title": "Additional settings"
},
"init": {
"data": {
"llm_hass_api": "Control Home Assistant",
"name": "Name",
"prompt": "Instructions",
"recommended": "Recommended model settings"
},
"data_description": {
"prompt": "Instruct how the LLM should respond. This can be a template."
}
},
"model": {
"data": {
"code_interpreter": "Enable code interpreter tool",
"image_model": "Image generation model",
"inline_citations": "Include links in web search results",
"pro_mode": "Pro mode",
"reasoning_effort": "Reasoning effort",
"reasoning_summary": "Reasoning summary",
"search_context_size": "Search context size",
"service_tier": "Service tier",
"user_location": "Include home location",
"web_search": "Enable web search"
},
"data_description": {
"code_interpreter": "This tool, also known as the python tool to the model, allows it to run code to answer questions",
"image_model": "The model to use when generating images",
"inline_citations": "If disabled, additional prompt is added to ask the model to not include source citations",
"pro_mode": "Perform more model work to improve reliability on difficult tasks and return a single final answer",
"reasoning_effort": "How many reasoning tokens the model should generate before creating a response to the prompt",
"reasoning_summary": "Controls the length and detail of reasoning summaries provided by the model",
"search_context_size": "High level guidance for the amount of context window space to use for the search",
"service_tier": "Controls the cost and response time",
"user_location": "Refine search results based on geography",
"web_search": "Allow the model to search the web for the latest information before generating a response"
},
"title": "Model-specific options"
}
}
},
"stt": {
"abort": {
"entry_not_loaded": "Cannot add things while the configuration is disabled.",
"reconfigure_successful": "Reconfiguration was successful"
},
"entry_type": "Speech-to-text",
"initiate_flow": {
"reconfigure": "Reconfigure speech-to-text service",
"user": "Add speech-to-text service"
},
"step": {
"init": {
"data": {
"chat_model": "Model",
"name": "Name",
"prompt": "Instructions"
},
"data_description": {
"chat_model": "The model to use to transcribe speech.",
"prompt": "Use this prompt to improve the quality of the transcripts. Translate to the pipeline language for best results. See the documentation for more details."
}
}
}
},
"tts": {
"abort": {
"entry_not_loaded": "Cannot add things while the configuration is disabled.",
"reconfigure_successful": "Reconfiguration was successful"
},
"entry_type": "Text-to-speech",
"initiate_flow": {
"reconfigure": "Reconfigure text-to-speech service",
"user": "Add text-to-speech service"
},
"step": {
"init": {
"data": {
"name": "Name",
"prompt": "Instructions",
"tts_speed": "Speed"
},
"data_description": {
"prompt": "Control aspects of speech, including accent, emotional range, intonation, impressions, speed of speech, tone, whispering, and more",
"tts_speed": "Speed of the generated speech"
}
}
}
}
},
"exceptions": {
"invalid_config_entry": {
"message": "Invalid config entry provided. Got {config_entry}"
}
},
"issues": {
"deprecated_generate_content": {
"description": "Action 'openai_compatible.generate_content' is deprecated and will be removed in the 2026.9.0 release. Please use the 'ai_task.generate_data' action instead",
"title": "Deprecated 'generate_content' action"
},
"deprecated_generate_image": {
"description": "Action 'openai_compatible.generate_image' is deprecated and will be removed in the 2026.9.0 release. Please use the 'ai_task.generate_image' action instead",
"title": "Deprecated 'generate_image' action"
},
"organization_verification_required": {
"description": "Your organization must be verified to use this model. Please go to {platform_settings} and select Verify Organization. If you just verified, it can take up to 15 minutes for access to propagate.",
"title": "Organization verification required"
}
},
"selector": {
"reasoning_effort": {
"options": {
"high": "High",
"low": "Low",
"max": "Max",
"medium": "Medium",
"minimal": "Minimal",
"none": "None",
"xhigh": "X-High"
}
},
"reasoning_summary": {
"options": {
"auto": "Auto",
"concise": "Concise",
"detailed": "Detailed",
"off": "Off"
}
},
"search_context_size": {
"options": {
"high": "High",
"low": "Low",
"medium": "Medium"
}
},
"service_tier": {
"options": {
"auto": "Auto",
"default": "Standard",
"flex": "Flex",
"priority": "Priority"
}
},
"verbosity": {
"options": {
"high": "High",
"low": "Low",
"medium": "Medium"
}
}
},
"services": {
"generate_content": {
"description": "Sends a conversational query to ChatGPT including any attached image or PDF files (deprecated)",
"fields": {
"config_entry": {
"description": "The config entry to use for this action",
"name": "Config entry"
},
"filenames": {
"description": "List of files to upload",
"name": "Files"
},
"prompt": {
"description": "The prompt to send",
"name": "Prompt"
}
},
"name": "Generate content (deprecated)"
},
"generate_image": {
"description": "Turns a prompt into an image (deprecated)",
"fields": {
"config_entry": {
"description": "The config entry to use for this action",
"name": "Config entry"
},
"prompt": {
"description": "The text to turn into an image",
"example": "A photo of a dog",
"name": "Prompt"
},
"quality": {
"description": "The quality of the image that will be generated",
"name": "Quality"
},
"size": {
"description": "The size of the image to generate",
"name": "Size"
},
"style": {
"description": "The style of the generated image",
"name": "Style"
}
},
"name": "Generate image (deprecated)"
}
}
}