Repository navigation
template import creates LLC agents without the adapter checks the hire path applies #14800
Description
Activity
- added 6 commits that reference this issue
on Aug 22, 2026 Fixed — verified on base
Merged via #14808 with 10/10 required checks and 12/12 python-suite shards.
Verified againstorigin/Dev_new_gui:check result adapter_unavailable_reasoninllc/adapters/base.py1 _import_agentgated2 references a resolved or "claude_code"default remaining0 What it was
_import_agentinserted intoagent_org_nodeswith anadapter_typefrom an
imported template and asked neither of the questions the hire route asks. So the
gate added in #14797 covered one of the two paths that create runnable agents.Skipped with a warning rather than failing: a template may legitimately be imported
onto a host provisioned afterwards, and the response already carrieswarningsand
skipped.The part the review caught, worth recording
My first version resolved
agent.get("adapter_type") or "claude_code"and validated
that, while the INSERT bound the raw field. Wrong twice over:- the value checked was not the value persisted — an omitted type was checked as
claude_codeand written as NULL claude_codewas the wrong default anyway; the scheduler reads a missing
adapter_typeasautobot_agent, which runs in-process and is deliberately
absent from the registry
ordinary in-process agent (no adapter_type) OLD=SKIP NEW=import <-- regression declared claude_code, CLI absent OLD=SKIP NEW=SKIP declared unknown adapter OLD=SKIP NEW=SKIPA gate that breaks the ordinary case to catch the unusual one is a bad trade, and I
made it by copying the hire route's default into a place where the runtime default
differs. Only a declared type is checked now, and the gate reads the same
expression the INSERT binds.The test asserting the omitted case is gated was asserting the regression. It now
asserts the opposite, plus one that reads the persisted bind value rather than the
source text.Not covered
#14811 — a skipped manager leaves imported subordinates with a
reports_to
pointing at a never-inserted UUID, and the column has no FK. Pre-existing, but this
change widens it: a CLI-less host can now skip an entire manager subtree.- the value checked was not the value persisted — an omitted type was checked as
The company-template import creates agents with an unchecked adapter_type
autobot-backend/llc/services/portability.py:621-660(_import_agent, reached from:251) inserts straight intoagent_org_nodeswithadapter_typetaken from animported JSON template:
INSERT INTO agent_org_nodes (... company_id, adapter_type, adapter_config, heartbeat_cron, ...)There is no registration check and no availability check on that path.
Why it matters
POST /companies/{id}/agent-hiresrejects an unregisteredadapter_type, and nowalso rejects one whose adapter cannot run on this deployment (#14797). The import
path creates the same kind of row — a real, heartbeat-dispatched agent — with
neither check.
So a template naming
claude_codeon a host without the CLI, or naming an adaptertype that does not exist at all, produces exactly the symptom the hire-time checks
exist to prevent: the agent is created, every heartbeat is skipped, and it looks
degraded forever with no indication why.
This is pre-existing — the import path never had these checks, and #14797 did
not introduce the asymmetry. Filing it so the gate is not mistaken for complete:
right now it covers one of the two paths that create runnable agents.
Fix
Route
_import_agentthrough the same two checks before insert. The import responseschema already carries
warningsandskipped, so an unrunnable adapter can bereported rather than silently created — which is likely better than failing the
whole import, since a template may legitimately be imported onto a host that will be
provisioned afterwards.
Acceptance criteria
adapter_typeis unregistered does not silentlycreate an agent
warningsorskippedrather than created silentlyadapter_typeand asserts the outcome atthe API boundary, not at the helper
one definition, not two
Found during review of #14797. Refs #12681.