Skip to content

refactor(agents): collapse per-task agents into flagship skills - #2995

Open
kovtcharov wants to merge 6 commits into
amd:mainfrom
kovtcharov:feat/collapse-agents-to-skills
Open

refactor(agents): collapse per-task agents into flagship skills#2995
kovtcharov wants to merge 6 commits into
amd:mainfrom
kovtcharov:feat/collapse-agents-to-skills

Conversation

@kovtcharov

@kovtcharov kovtcharov commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

GAIA shipped 19 agent packages and a user could reach two of them. Everything except email and the gaia flagship showed in the TUI as "not published on the Agent Hub yet" — no daemon sidecar spec, no launchable catalog row, no install path. Meanwhile several of those packages defined zero tools of their own: they were a system prompt wrapped in a wheel, and the prompt described tools the flagship already registers.

This deletes thirteen of them and moves the part worth keeping — the procedural knowledge — into SKILL.md files the flagship loads on demand. Adding a capability is now writing markdown, not shipping a package with a manifest, a CI workflow, a publish slot, and a docs page. Net: -98,000 lines.

Deleted: code, routing, blender, sd, emr, analyst, browser, docqa, doc-search, fileio, summarize, jira, docker. Kept: gaia (flagship), chat (its base class), email, plus hello-world / word-count / connectors-demo as teaching templates that are no longer catalog agents.

Two new skills carry the deleted prose forward — file-ops and summarize (its style tables and fold-forward chunking procedure). data-explore, research-report and document-brief already existed and cover analyst, browser and the two RAG duplicates.

Jira and Docker come back as connectors — scoped in #2989 and #2990. Docker needs a security decision first: docker build executes arbitrary code, and GAIA only grants a skill shell access through a reviewed per-binary policy.

What a user will notice

  • gaia analyze | browse | summarize | blender | sd | jira | docker and gaia mcp docker are gone, along with the gaia-code and gaia-emr console scripts.
  • gaia api now exposes exactly one model, gaia — the flagship. Its map previously held one entry, the routing agent, which routed to the code agent; both are deleted, so the endpoint is now pointed at the agent that actually ships. Any OpenAI-compatible client (VSCode, curl, an SDK) works against it.
  • gaia download --list and gaia init --profile no longer offer profiles for deleted agents, and the MCP bridge stopped advertising gaia.eval, which nothing has ever implemented.
  • The Agent Hub catalog and TUI agent list drop the eight rows that could never launch.
🔍 Also removed, and why

Dead weight that only existed to serve a deleted agent:

  • src/gaia/apps/{jira,summarize,docker} — standalone apps importing deleted agent classes.
  • src/gaia/mcp/blender_mcp_{client,server}.py — a Blender-addon socket protocol on port 9876, not MCP.
  • src/gaia/mcp/servers/docker_mcp.py — a thin wrapper around DockerAgent.
  • The MCP bridge's gaia.jira / gaia.blender.create / gaia.summarize tools and /jira /summarize endpoints, plus the multipart-upload path only /summarize used (mcp_bridge.py: 953 → 624 lines).
  • The blender extra (bpy), the data-lite / web-lite legacy registry aliases, stale FRAMEWORK_PATHS entries that would have filtered a user's own frames out of their traceback, and the blender/jira/docker Claude specialist definitions.

src/gaia/sd/mixin.py is kept — image generation stays available on ChatAgent behind the existing enable_sd_tools flag; only the standalone agent is gone.

Docs: 38 pages deleted, 39 edited, docs/docs.json pruned. All 194 nav entries verified to resolve to a real file.

Test plan

  • python util/lint.py --all — clean, exit 0

  • All 13 skills parse via parse_skill_file, and every tool each one declares in tools_required exists in the flagship's live registry (66 tools, 0 gaps) — verified by instantiating GaiaAgent and diffing, since tools_required is advisory and a gap fails mid-run rather than at load

  • gaia --help lists no deleted command; each removed command is rejected; gaia mcp --help has no docker

  • gaia api: /v1/models returns an empty list and a request for a deleted model 404s with an actionable message

  • MCP bridge boots with 2 agents / 3 tools; a deleted tool returns a clean "not implemented"

  • gaia api end to end: /v1/models lists gaia, registry.get_agent("gaia") builds the flagship with the SSE handler installed and 61 tools registered, and an unknown model 404s with an actionable message

  • cd tui && go build ./... && go test ./... — all packages pass

  • docs/docs.json: 194 nav pages, 0 missing files

  • pytest tests/unit full run, compared against the same run on unmodified main:

    main this branch
    passed 9098 9068
    failed 617 615
    errors 480 480

    Those failures are pre-existing and environmental: the sandbox this ran in blocks the loopback socket asyncio.new_event_loop() needs on Windows, tripping the repo's hermetic-network guard (tests/unit/conftest.py, untouched here). A set-diff of failing node ids found exactly one genuine regression — the starter-skill guard rejecting request_user_input — fixed in the second commit. Every other difference reproduces identically on main when run in isolation. The 30 fewer passes are tests deleted along with their agents.

  • Launch the flagship in the TUI and exercise a collapsed capability end to end — e.g. load data-explore and confirm it calls create_table/query_data instead of fabricating. Needs a machine with Lemonade running; not done yet.

Review notes

The riskiest edits are not the deletions — they are the three files that had a deleted agent threaded through shared logic: src/gaia/cli.py (dispatch + parsers), src/gaia/mcp/mcp_bridge.py (tool routing), and tests/test_api.py (every request now 404s at model_exists before reaching validation, so the live-server success-path tests were removed rather than left to rot).

Thirteen agent packages are gone: code, routing, blender, sd, emr, analyst,
browser, docqa, doc-search, fileio, summarize, jira, docker. Their capability
now comes from the flagship agent's tool surface driven by a SKILL.md, which is
where new capability belongs — a skill is a markdown file, an agent was a wheel
with a manifest, CI, docs, and a publish slot.

Most of them were never reachable: only email and gaia have a daemon sidecar
spec or a launchable TUI catalog row, so the rest showed as "not published on
the Agent Hub yet" and could not be installed at all. Several defined zero tools
of their own and consisted entirely of a system prompt already covered by the
flagship's 66 registered tools.

Two new skills carry forward the prose worth keeping: file-ops (from fileio) and
summarize (the style tables and fold-forward chunking from summarize's
prompts.py). data-explore, research-report and document-brief already existed
and cover analyst, browser and docqa/doc-search.

Also removed as dead weight: the jira/summarize/docker standalone apps, the
Blender MCP client/server pair, the Docker MCP server, the MCP bridge's
jira/blender/summarize surfaces and the multipart upload path that only the
summarize endpoint used, the bpy extra, and the blender/jira/docker Claude
specialist definitions.

Behaviour changes a user can see:
- `gaia analyze|browse|summarize|blender|sd|jira|docker` and `gaia mcp docker`
  are gone, as are the gaia-code and gaia-emr console scripts.
- `gaia api` exposes no models: AGENT_MODELS held one entry, the routing agent,
  which routed to the code agent.
- hello-world, word-count and connectors-demo stay as teaching templates and are
  no longer catalog agents.

Jira and Docker return as connectors, scoped in amd#2989 and amd#2990.
@github-actions github-actions Bot added documentation Documentation changes dependencies Dependency updates devops DevOps/infrastructure changes mcp MCP integration changes cli CLI changes tests Test changes electron Electron app changes agents agent::email Email agent changes agent::analyst Analyst agent changes agent::sd Stable Diffusion agent changes agent::fileio FileIO agent changes agent::emr Medical-intake (EMR) agent changes agent::docqa DocumentQA agent changes agent::browser Browser agent changes agent::summarize Summarizer agent changes agent::connectors-demo Connectors-demo agent changes agent::code Code agent changes agent::blender Blender agent changes agent::docker Docker agent changes agent::routing Routing agent changes agent::jira Jira agent changes agent::examples Hub tutorial/example agents (hello-world, word-count, doc-search) tui Go terminal UI (gaia-tui) labels Aug 18, 2026
Ovtcharov added 2 commits August 18, 2026 02:26
The starter-pack guard checks tools_required against the tools mixins
register plus a short whitelist of the tools ChatAgent registers inline. The
whitelist was missing request_user_input, so the new file-ops skill failed the
guard for declaring a tool the flagship really does register — asking the user
before a destructive write is the whole point of that skill.

Verified the same way as the rest of the list: the `def` must exist in the chat
agent's source, so a rename drops the name instead of silently passing.
`gaia api` started but served nothing: its model map held one entry, the
routing agent, which routed to the code agent — both deleted. It now exposes
the flagship as the model `gaia`, so any OpenAI-compatible client (VSCode,
curl, an SDK) drives the agent that actually ships. Verified end to end:
/v1/models lists it, the agent constructs with the SSE handler installed, and
an unknown model still 404s with an actionable message.

That needed one plumbing fix: ChatAgentConfig never forwarded `output_handler`
to the base Agent, so there was no way to hand a ChatAgent the SSE handler the
API server streams through.

Also stopped three commands describing things that no longer exist:

- `gaia download --list` advertised Code/Blender/Jira/Docker agent profiles.
  The SD entry stays but is relabelled — the SD tool mixin is still here, the
  standalone agent is not.
- `gaia init --profile code` installed models for a deleted agent.
- The MCP bridge advertised `gaia.eval`, which nothing has ever implemented —
  it was the last entry in the manifest with no handler behind it.

Docs updated to match: the API reference, spec, SDK page and VSCode guide all
said the model list was empty by default.
@github-actions github-actions Bot added llm LLM backend changes performance Performance-critical changes labels Aug 18, 2026
`execute_python_file` runs a .py file in a subprocess — arbitrary code
execution — but it was the one dangerous tool missing from the confirmation
gate. `run_shell_command` sits behind both the gate AND a read-only command
allowlist; this had neither, so it was the weakest link in the set.

It mattered little while the OpenAI-compatible server exposed nothing. Now that
it serves the flagship, an unattended caller reaches a 61-tool agent, so the gap
closes here. Verified: the tool is refused and the file does not run.

Also from review of this branch:

- Dropped `python-multipart` from core install_requires. It was there because
  the MCP bridge imported it at module load to parse multipart uploads for the
  summarize endpoint; that endpoint and the import are gone, and nothing else
  under src/ imports it. It stays in the `api` and `ui` extras, which do.
- Removed `send_sse_headers` and `stream_sse` from the bridge — the deleted
  summarize endpoint was their only caller.
- Corrected an ApiAgent docstring that claimed `GaiaAgent -> gaia`; the default
  it documents would produce `gaia-gaia`, and the flagship is served under the
  `gaia` key in AGENT_MODELS instead.
Ovtcharov and others added 2 commits August 18, 2026 11:33
The one that mattered: deleting the browse/analyze branch left its trailing
`agent.close()` behind, stitched into the chat branch's cleanup one level too
deep — inside `except Exception: pass`. Neither ChatAgent nor the base Agent
has a `close()`, and the `hasattr` guard that used to protect it went with the
deleted block, so a `gaia chat` run where `stop_watching()` raised would have
turned a graceful exit into an AttributeError escaping the `finally` and hiding
the original error. Also swept the tree for that whole bug class (a statement
stranded after `pass`, an unreachable statement after `return`) — nothing else.

The summarize skill told the model to pass `summary_type` values the tool
rejects. `summarize_document` validates against exactly brief/detailed/bullets,
while the skill named `executive`, `action_items`, `participants` and friends in
backticks — inherited from the deleted agent, which validated those itself. The
most natural transcript ask, "what were the action items", would have returned
an error instead of a summary. The style vocabulary stays as prose guidance; the
skill now says which three values are real.

`GET /v1/models` built a full agent just to read two integers off it. That was
cheap when the entry was the routing agent and expensive now that it is the
flagship, whose constructor opens RAG, scratchpad and memory handles and an HTTP
session — on an endpoint clients poll at startup. It now checks the class and
only instantiates an actual ApiAgent: 291ms first call, 2ms after, no handles.

Smaller: `gaia init --profile` advertised `code` in argparse choices after the
profile was deleted; the `sd` profile's quick-start printed `gaia sd`, a command
this branch removed; `gaia download`'s epilog demoed `--agent code`; a
`wait_for_user` helper whose only caller was a Blender demo; scripts/jira_smoke.py
imported two deleted modules; and assorted docstrings, menu strings and plan-doc
links still pointed at agents that no longer exist.
@kovtcharov-amd
kovtcharov-amd marked this pull request as ready for review August 20, 2026 17:23
@kovtcharov-amd
kovtcharov-amd self-requested a review as a code owner August 20, 2026 17:23
@github-actions

Copy link
Copy Markdown
Contributor

Verdict: Request changes

This collapses roughly fourteen per-task agents (code, analyst, browser, jira, docker, blender, sd, summarize, emr, docqa, routing, fileio, doc-search) into skills the flagship agent loads on demand, leaving gaia, chat and email as the only shipped agents. The deletion itself is unusually clean — I traced the CLI, the agent registry, the Lemonade and init profiles, the docs navigation, the CI matrices and the TUI catalog, and found no dangling import or dispatch branch left behind. Two things should be fixed before merge, both small.

The one genuinely new piece of logic here has no test. The change that lets the API server hand the flagship agent its streaming output handler is what makes /v1/chat/completions work at all after this collapse — and every test in that area substitutes a stand-in agent instead of building the real one. Rename that field or let the startup parameters drift and CI stays green while the endpoint breaks for real users. Add one test that constructs the flagship exactly the way the API server does.

The Blender workshop notebook is now dead. It walks a reader through installing a Blender add-on from a file this PR deletes, and imports a module that no longer exists. Delete it alongside the rest of the Blender surface (the workshop index mentions it too), or mark it as removed.

Real-world evidence

No evidence bundle was produced for this run, and the shell and gh tooling were unavailable to me, so I could not read the PR description to check whether evidence is linked there. This verdict rests on static review of the diff alone. Nothing here is inference-dependent — it is deletions plus one config field — but the surfaces it touches are all exercisable, and a short gaia api start followed by GET /v1/models and one non-streaming /v1/chat/completions round-trip against the flagship would show the path that the first point above says is untested. If that evidence is already on the PR, this note is satisfied.

🔍 Technical details

Issues Found

🟡 New output_handler wiring is untested end-to-end (hub/agents/chat/python/gaia_agent_chat/agent.py:94)

AGENT_MODELS["gaia"] now resolves to gaia_agent.agent.GaiaAgent, and GaiaAgent.__init__ funnels **kwargs straight into the GaiaAgentConfig dataclass (hub/agents/gaia/python/gaia_agent/agent.py:192). AgentRegistry.get_agent injects output_handler=SSEOutputHandler(...) into init_params (src/gaia/api/agent_registry.py:158), so the new ChatAgentConfig.output_handler field is the only reason that construction doesn't raise TypeError. Nothing asserts it:

  • tests/unit/api/test_sse_confirmation_gate.py:254 patches _load_agent_class to return _ApiAgent, a plain Agent subclass that takes output_handler as a normal kwarg — the dataclass path is never exercised.
  • tests/test_api.py mocks get_agent wholesale.
  • hub/agents/gaia/python/tests/ has no construction-with-handler case (grep -rn output_handler across the repo's tests returns three hits, none of them building a real ChatAgent/GaiaAgent).

One test in hub/agents/gaia/python/tests/ along the lines of GaiaAgent(**AGENT_MODELS["gaia"]["init_params"], output_handler=SSEOutputHandler()) (with gaia.agents.base.agent.AgentSDK patched, as the neighbouring tests do) pins the contract that the API server actually depends on.

🟡 workshop/blender.ipynb references files this PR deletes

Three live references to removed modules:

  • workshop/blender.ipynb:201 — "navigate to <root>/src/gaia/mcp/blender_mcp_server.py" (deleted here)
  • workshop/blender.ipynb:238,337,509from gaia.mcp.blender_mcp_client import MCPClient (deleted here)
  • workshop/docs/workshop.md also mentions the Blender session

CLAUDE.md's rule is that a functional change updates every doc that describes it. docs/, docs.json, .github/labeler.yml, .github/dependabot.yml and the TUI catalog were all swept correctly — workshop/ is the one that got missed.

Nits

🟢 Garbled comment (tests/test_api.py:321)

        # The model-existence check runs before the empty-messages check, so
        # stub the registry to let this test exercise the message-validation
        # branch it's named for.

🟢 Garbled docstring (tests/unit/api/test_sse_confirmation_gate.py:249)

        AGENT_MODELS holds only the flagship now, not the agent this probe
        stubs, so a fake entry is patched in here to exercise the get_agent()
        wiring this test actually targets.

🟢 Import smoke-check no longer covers the flagship (util/lint.py:417)

The list drops every per-task agent (correct) but keeps only gaia_agent_chat. The agent that now carries the whole product isn't checked:

        ("from", "gaia_agent_chat", "ChatAgent", "Chat agent", True),
        ("from", "gaia_agent.agent", "GaiaAgent", "Flagship agent", True),

Same list exists in util/lint.ps1:349.

🟢 Stale CI summary line (.github/workflows/test_gaia_cli_linux.yml:302)

Still echoes "✅ Summarizer CLI integration (gaia summarize command)" for a command this PR removes. That workflow isn't otherwise in the diff, so the line just prints a false claim in the job summary.

Strengths

  • The python-multipart base-dependency removal is correctly scoped. It was pinned at base level only because gaia-mcp parsed multipart uploads at import time; that parser is gone, and the [api] / [ui] extras that actually mount FastAPI UploadFile routes (src/gaia/ui/routers/files.py:63, documents.py:333, agents.py:294) still pin it. Easy thing to get wrong; this got it right.
  • list_models now checks issubclass before instantiating (src/gaia/api/agent_registry.py:200). Clients poll /v1/models on startup, and the old code built an agent — opening its DB handles and HTTP session — just to read two integers. Good catch bundled into the rename.
  • execute_python_file added to TOOLS_REQUIRING_CONFIRMATION (src/gaia/agents/base/agent.py:120), with a comment that names the actual reason (no read-only allowlist behind it, unlike run_shell_command).
  • The deletion is genuinely self-consistent. setup.py, install_hints.py, errors.py:FRAMEWORK_PATHS, registry._LEGACY_ID_ALIASES, AGENT_PROFILES, INIT_PROFILES, the argparse subparsers and their main() dispatch branches, mcp.json, mcp_bridge.py, the Go seed catalog and its tests all moved together. grep for the removed package names across src/, tests/ and tui/ comes back clean apart from the workshop notebook above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent::analyst Analyst agent changes agent::blender Blender agent changes agent::browser Browser agent changes agent::code Code agent changes agent::connectors-demo Connectors-demo agent changes agent::docker Docker agent changes agent::docqa DocumentQA agent changes agent::email Email agent changes agent::emr Medical-intake (EMR) agent changes agent::examples Hub tutorial/example agents (hello-world, word-count, doc-search) agent::fileio FileIO agent changes agent::jira Jira agent changes agent::routing Routing agent changes agent::sd Stable Diffusion agent changes agent::summarize Summarizer agent changes agents cli CLI changes dependencies Dependency updates devops DevOps/infrastructure changes documentation Documentation changes electron Electron app changes llm LLM backend changes mcp MCP integration changes performance Performance-critical changes tests Test changes tui Go terminal UI (gaia-tui)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants