You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
github-pr-reviewer and github-repo-monitor build their conversation payload from the agent server's current settings instead of the automation's configured LLM profile. Neither script reads AUTOMATION_MODEL:
The result: an automation created from these skills ignores the profile selected for it and runs on whatever profile happens to be active in the UI at the moment it fires.
skills/github-repo-monitor/scripts/main.py:439-452 has the same _get_agent_dict().
agent_settings.llm from GET /api/settings is the active profile, not the automation's.
This contradicts the documented contract
skills/openhands-automation/references/custom-automation.md:277-293 states that the service injects AUTOMATION_MODEL with the selected profile name and that scripts must honor it:
Calling workspace.get_llm() with no profile_name always uses the user's default LLM. The built-in prompt and plugin presets already follow the pattern above; custom scripts should too so the selected profile is honored regardless of trigger type or execution backend.
The service side works as documented — openhands/automation/dispatcher.py:253-254 sets env_vars["AUTOMATION_MODEL"], and the built-in presets (presets/prompt/sdk_main.py:95,290) consume it correctly. Only these two skill templates skip the step.
Observed on our shared OSS automation instance
agent-canvas 1.6.1, openhands-automation 1.3.1, local mode.
A triage automation generated from this pattern has profile gpt-5.6-sol configured. Every conversation it created today ran on a different model:
openai/gpt-5.5 was the active profile in the UI during that window. The inverse case confirms the mechanism: a sibling automation with no profile configured ran on openai/gpt-5.6-sol the previous evening — again the then-active profile. Runs from a preset-based automation on the same host, over the same dispatcher, honored their profile correctly:
So the environment variable is delivered to these runs; the scripts just never read it.
Impact
The per-automation LLM profile selector is silently a no-op for anything built from these two skills.
Because the LLM is read live at fire time, anyone switching the active profile in the UI silently changes which model every such automation uses — on a shared instance, without touching any automation.
Resolve the profile when AUTOMATION_MODEL is set, and fall back to current behavior when it is not:
def_get_agent_dict(agent_url: str, api_key: str) ->dict:
data=_fetch_settings(agent_url, api_key)
llm=data.get("agent_settings", {}).get("llm", {})
profile=os.environ.get("AUTOMATION_MODEL")
ifprofile:
req=urllib.request.Request(
f"{agent_url}/api/profiles/{quote(profile, safe='')}",
headers={"X-Session-API-Key": api_key, "X-Expose-Secrets": "plaintext"},
)
try:
withurllib.request.urlopen(req, timeout=HTTP_TIMEOUT) asr:
llm=json.loads(r.read())["config"]
llm["usage_id"] =f"profile:{profile}"excepturllib.error.HTTPErrorasexc:
ifexc.code!=404:
raise# profile renamed or deleted after the automation was createdprint(f"profile {profile!r} not found; falling back to active profile")
return {"kind": "Agent", "llm": llm, ...}
Two implementation notes:
X-Expose-Secrets: plaintext is required — without it config.api_key comes back null. This mirrors what the SDK does in openhands/sdk/workspace/remote/base.py:364-380.
StartConversationRequest exposes title_llm_profile and agent_profile_id but no field for the agent's LLM profile, so passing the resolved config inline is the only route over the REST API.
Worth auditing the other skills that create conversations directly for the same pattern.
Summary
github-pr-reviewerandgithub-repo-monitorbuild their conversation payload from the agent server's current settings instead of the automation's configured LLM profile. Neither script readsAUTOMATION_MODEL:The result: an automation created from these skills ignores the profile selected for it and runs on whatever profile happens to be active in the UI at the moment it fires.
Where
skills/github-pr-reviewer/scripts/main.py:301-308skills/github-repo-monitor/scripts/main.py:439-452has the same_get_agent_dict().agent_settings.llmfromGET /api/settingsis the active profile, not the automation's.This contradicts the documented contract
skills/openhands-automation/references/custom-automation.md:277-293states that the service injectsAUTOMATION_MODELwith the selected profile name and that scripts must honor it:The service side works as documented —
openhands/automation/dispatcher.py:253-254setsenv_vars["AUTOMATION_MODEL"], and the built-in presets (presets/prompt/sdk_main.py:95,290) consume it correctly. Only these two skill templates skip the step.Observed on our shared OSS automation instance
agent-canvas 1.6.1, openhands-automation 1.3.1, local mode.
A triage automation generated from this pattern has profile
gpt-5.6-solconfigured. Every conversation it created today ran on a different model:openai/gpt-5.5was the active profile in the UI during that window. The inverse case confirms the mechanism: a sibling automation with no profile configured ran onopenai/gpt-5.6-solthe previous evening — again the then-active profile. Runs from a preset-based automation on the same host, over the same dispatcher, honored their profile correctly:So the environment variable is delivered to these runs; the scripts just never read it.
Impact
Suggested fix
Resolve the profile when
AUTOMATION_MODELis set, and fall back to current behavior when it is not:Two implementation notes:
X-Expose-Secrets: plaintextis required — without itconfig.api_keycomes backnull. This mirrors what the SDK does inopenhands/sdk/workspace/remote/base.py:364-380.StartConversationRequestexposestitle_llm_profileandagent_profile_idbut no field for the agent's LLM profile, so passing the resolved config inline is the only route over the REST API.Worth auditing the other skills that create conversations directly for the same pattern.