Skip to content

Refactor Agent Registry Wiring and Fix Config Options#22011

Open
jmchilton wants to merge 6 commits intogalaxyproject:devfrom
jmchilton:agent_plumbing
Open

Refactor Agent Registry Wiring and Fix Config Options#22011
jmchilton wants to merge 6 commits intogalaxyproject:devfrom
jmchilton:agent_plumbing

Conversation

@jmchilton
Copy link
Member

Wire agent registry using our Lagom container instead of module-level singletons - pros and cons of course but this is the documented Galaxy best practice and I think has some real important upsides. Also fixes #21996 while I'm in there.

How to test the changes?

(Select all options that apply)

  • This is a refactoring of components with existing test coverage.

License

  • I agree to license these and all my past contributions to the core galaxy codebase under the MIT license.

@jmchilton jmchilton added kind/bug kind/refactoring cleanup or refactoring of existing code, no functional changes area/configuration Galaxy's configuration system labels Mar 9, 2026
@jmchilton jmchilton changed the title Agent plumbing Refactor Agent Registry Wiring and Fix Config Options Mar 9, 2026
@jmchilton
Copy link
Member Author

I started working on something unrelated and realized this went astray - config.agents was dead code laying around that should have been cleaned up and we should have attached this stuff to inference_services.

From the agent:

What agent_plumbing does (3 commits)

Good structural improvements:

  1. Removes global singleton agent_registry — replaced with build_default_registry() factory function, registry injected via Lagom DI in app.py
  2. Makes get_agent non-optional on GalaxyAgentDependencies — removes None checks, orchestrator no longer does from galaxy.agents import agent_registry (circular import smell removed)
  3. Adds per-agent enabled flagbuild_default_registry(config) reads config.agents to skip disabled agents, with "router always on" guard
  4. Removes HAS_AGENTS try/except guards in managers/agents.py and api/agents.py — treats pydantic-ai as a hard dependency
  5. Good test coverage — 7 new tests for registry building, disabled agents, error messages

The configuration problem

Yes, the branch went the wrong direction on config. It doubled down on config.agents (the dead config dict) for the enabled flag:

  • build_default_registry() reads config.agents[agent_type]["enabled"] to decide registration
  • AgentService.execute_agent() also checks config.agents as a guard
  • api/agents.py list endpoint checks config.agents for enabled status

But the actual runtime config that agents use for model/temperature/api_key is config.inference_services (read in base.py:_get_agent_config()). So now you have:

Concern Read from
model, temperature, api_key, api_base_url inference_services
enabled agents

Two config dicts for the same logical concept. An admin would need to configure both:

inference_services:
  custom_tool:
    model: "anthropic:claude-sonnet-4-5"
agents:
  custom_tool:
    enabled: false  # different dict!

What should probably happen

The enabled flag should live in inference_services alongside model/temperature, and config.agents / _load_agent_config() should be removed entirely. Something like:

inference_services:
  default:
    model: "gpt-4o-mini"
    temperature: 0.7
  custom_tool:
    enabled: false  # same place as model config

Then build_default_registry() and _get_agent_config() both read from inference_services — one config to rule them all.

The structural DI improvements in this branch (killing the global singleton, non-optional get_agent, removing HAS_AGENTS guards) are all good and worth keeping. It's just the config source that needs redirecting.

jmchilton and others added 6 commits March 16, 2026 16:40
Replace module-level agent_registry singleton with factory-based
Lagom registration. AgentService now receives registry via constructor
injection. API layer delegates to AgentService. Orchestrator uses
deps.get_agent callback. Remove dead _global_registry and vestigial
HAS_AGENTS guards (pydantic-ai is unconditional).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Disabled agents are now excluded from registry, hidden from
/api/ai/agents, and raise ConfigurationError if executed directly.
Router agent is always-on (warns if config says disabled).

Sync config defaults: remove phantom dataset_analyzer, add
orchestrator + tool_recommendation. Registry tracks disabled set
for clear error messages on handoff attempts.

Closes galaxyproject#21996

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pass concrete agent classes directly to register() instead of
iterating a list, avoiding mypy inferring the union as abstract.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…agents

config.agents (set by _load_agent_config()) was never read by the agent
framework — agents used inference_services for model/temperature/api_key.
The enabled flag was reading from config.agents while everything else
read inference_services, splitting config across two dicts.

Now all agent config lives under inference_services:
  inference_services:
    default: { model: gpt-4o-mini }
    custom_tool: { enabled: false }

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/configuration Galaxy's configuration system kind/bug kind/refactoring cleanup or refactoring of existing code, no functional changes

Projects

Status: Needs Review

Development

Successfully merging this pull request may close these issues.

Agent Enable/Disable Configuration Not Hooked Up?

1 participant