Add support for resolving agent-type registry package references in agents.<name> #121

Closed
opened 2026-08-08 20:54:33 +00:00 by CoreRasurae · 1 comment
Member

Metadata

  • Commit Message: feat(agents): resolve agent- and route-type registry package references in agents.<name> and routes.<name>
  • Branch: feature/agent-package-references

Background and context

The Actor Configuration Standard (docs/index.md §4.1) only defines two shapes for an
agents.<name> entry: an inline type:/config: mapping, or a template:/
agent_template: instantiation from a template-type component registered under
templates.agents (§8.7). The Package Registry Standard (docs/actor-registry-standard.md
§3.2) separately defines a plain agent-type package (prefix pkg_agt_) — "Agent
definitions that can be referenced in actor configurations" — as its own package type,
distinct from template (prefix pkg_tpl_).

There is currently no field or mechanism anywhere in cleveractors that resolves a bare
agent-type package reference (local:<path> or host:namespace/name[@version], per
Package Registry Standard §5.3) into a usable agent. The only working
reference-resolution mechanism for agents is SkillLoader/SkillReferenceResolver, and
that only resolves skills: entries on an already-instantiated type: llm agent, not the
agents.<name> entry itself — create_executor's own docstring (src/cleveractors/runtime.py
lines ~299-314) is explicit that local_store/registry_api_key are scoped to skills:
resolution only.

Current behavior

Using the library's documented create_executor entry point
(docs/guides/reasoning-aware-llm-agents.md) with a bare package-reference agent entry:

from cleveractors.runtime import create_executor

executor = create_executor(
    config_dict={
        "agents": {
            "worker": "local:worker-agent.yaml",  # an agent-type package reference
        },
        "routes": {
            "main": {
                "type": "graph",
                "nodes": {"build": {"type": "agent", "agent": "worker"}},
                "edges": [
                    {"source": "start", "target": "build"},
                    {"source": "build", "target": "end"},
                ],
            },
        },
    },
    credentials=None,
    local_store=my_local_store,
)
await executor.execute("hello")

fails with:

AttributeError: 'str' object has no attribute 'get'

Root cause: AgentFactory.create_agent/_create_agent_instance
(src/cleveractors/agents/factory.py lines ~196-213) unconditionally treats
agents_config[agent_name] as a mapping (agent_config.get("type", "llm")), with no
branch for a bare reference string. create_executor already accepts local_store and
registry_api_key (used today only for skills: resolution), so the plumbing needed to
resolve such a reference is present in the call signature but not wired to agent creation.

The same gap exists for a template:/agent_template: mapping whose value is such a
reference: AgentFactory has no awareness of the template/agent_template keys at all
(that recognition exists only in reactive/config_parser.py's ReactiveConfig parsing and
core/application.py's _create_agents, neither of which AgentFactory/Executor uses).
So agents.<name>: {"agent_template": "local:worker-agent.yaml"} produces no error at all
via this path — it silently degrades to an empty type: llm agent (no "type"/"config"
key present), a related but distinct failure mode tracked in #122.

Scope update — the identical bug class also affects routes.<name>

During implementation, this same reference-resolution gap was confirmed to also affect the
routes section, for the exact same reason: the Package Registry Standard (§3.2) defines
graph-type (pkg_grh_) and stream-type (pkg_str_) packages as "route definitions that
can be used as components in larger systems", but docs/index.md §5.1's routes grammar
never named a bare-reference form either, and cleveractors.runtime_dispatch._execute_graph/
_execute_graph_stream exhibit the identical code defect: main = routes.get("main", {})
followed by main.get("nodes", {}) assumes main is a mapping, so routes.main: "local:main-graph.yaml" fails with the same raw AttributeError.

Because both gaps share one root cause and one fix shape, they are addressed together in
this issue/PR rather than split into a separate issue, per maintainer direction. See
docs/adr/ADR-2037-agent-and-route-package-reference-resolution.md for the consolidated
decision record (D-1 through D-6 cover agents.<name>; D-7 through D-9 cover
routes.<name>). This project's implementation resolves a routes.<name> reference only
for the single routes.main entry _execute_graph/_execute_graph_stream read, fixed to
package_type="graph" (stream routes are not reachable via create_executor's dispatch
table); docs/index.md §5.1.1 itself documents the extension generically for both package
types, per an implementation-agnostic Actor Configuration Standard.

Expected behavior

When agents.<name> is a bare string (a local:, registry:/host-qualified, or ID:
reference per Package Registry Standard §5.3/§7.3) rather than a mapping, AgentFactory
should resolve it — via the same local_store/registry_api_key plumbing already used by
SkillLoader — to the referenced agent-type package's content, and use that content's
type/config fields to construct the agent, exactly as if that content had been inlined
under type:/config:.

Likewise, when routes.main is a bare string, the graph-actor dispatch path should resolve
it to the referenced graph-type package's content and use its route fields (nodes,
edges, ...) exactly as if inlined under the routes.main mapping form.

When the reference cannot be resolved (unknown scheme, missing package, network/registry
error), agent/route creation must fail with a clear AgentCreationError/ConfigurationError
naming the unresolved reference — never a raw AttributeError.

Acceptance criteria

  • agents.<name> accepts a bare reference string (in addition to the existing
    type:/config: and template:/agent_template: mapping forms).
  • A local:<path> reference resolves via the supplied LocalPackageStore and
    produces a working agent.
  • A host:namespace/name[@version] registry reference resolves via a RegistryClient
    using registry_api_key, mirroring the resolution already implemented for skills:.
  • An unresolvable reference raises AgentCreationError/ConfigurationError with a
    message naming the reference — not an AttributeError.
  • Works identically via both create_agent (sync) and acreate_agent (async).
  • Demonstrated end-to-end via create_executor against a real/local LLM endpoint using
    a config with an agents.<name> bare-string reference.
  • routes.main accepts a bare reference string (in addition to the existing mapping
    form), resolved to a graph-type package.
  • A local:<path> route reference resolves via the supplied LocalPackageStore and
    produces a working graph actor.
  • A host:namespace/name[@version] registry route reference resolves via a
    RegistryClient (package_type="graph").
  • An unresolvable route reference raises ConfigurationError naming the reference —
    not an AttributeError.
  • Demonstrated end-to-end via create_executor using a config with a routes.main
    bare-string reference.

Supporting information

  • docs/index.md §4.1, §4.1.1, §5.1, §5.1.1, §8.7 (Actor Configuration Standard — agent
    and route declaration forms)
  • docs/actor-registry-standard.md §3.2, §5.3, §7.3 (Package Registry Standard — package
    types and reference formats)
  • docs/adr/ADR-2037-agent-and-route-package-reference-resolution.md (consolidated decision
    record for this issue)
  • README.md "Quick start" / docs/guides/reasoning-aware-llm-agents.md (documented
    public entry points: ReactiveCleverAgentsApp, create_executor)
  • src/cleveractors/agents/factory.py (AgentFactory.create_agent/acreate_agent)
  • src/cleveractors/agents/agent_resolution.py (new AgentReferenceResolver)
  • src/cleveractors/route_resolution.py (new RouteReferenceResolver)
  • src/cleveractors/runtime_dispatch.py (_execute_graph/_execute_graph_stream
    routes.main normalisation)
  • src/cleveractors/runtime.py (create_executorlocal_store/
    registry_api_key currently scoped to skills: only)
  • src/cleveractors/agents/skill_resolution.py, src/cleveractors/agents/skills.py
    (existing working reference-resolution pattern mirrored by both new resolvers)

Subtasks

  • Add a reference-detection branch in AgentFactory.create_agent/acreate_agent for a
    bare-string agents.<name> value.
  • Implement resolution against LocalPackageStore (local: scheme).
  • Implement resolution against RegistryClient (host-qualified scheme), threading
    registry_api_key the same way SkillLoader does.
  • Map resolved package content (flat shape) onto the type/config structure
    _instantiate expects.
  • Raise AgentCreationError/ConfigurationError (not AttributeError) on an
    unresolvable reference.
  • Add the identical reference-detection branch for a bare-string routes.main value in
    _execute_graph/_execute_graph_stream.
  • Implement route resolution against LocalPackageStore/RegistryClient
    (package_type="graph").
  • Fix the pre-existing duplicate routes.main re-fetch (parallel_execution
    computation) to reuse the normalised/resolved main value.
  • Tests (Behave): scenarios for local: and registry-reference agent AND route
    resolution, and for the unresolvable-reference error path on both.
  • Tests (Robot): integration test loading an agent-type package via a graph
    configuration's agents.<name> entry, and a graph-type package via routes.main.
  • Verify coverage >=97% via nox -s coverage_report.
  • Run nox (all default sessions), fix any errors.

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line of the commit message matches the
    Commit Message in Metadata exactly, followed by a blank line, then additional lines
    providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata
    exactly.
  • The commit is submitted as a pull request to master, reviewed, and merged
    before this issue is marked done.
## Metadata - **Commit Message**: `feat(agents): resolve agent- and route-type registry package references in agents.<name> and routes.<name>` - **Branch**: `feature/agent-package-references` ## Background and context The Actor Configuration Standard (`docs/index.md` §4.1) only defines two shapes for an `agents.<name>` entry: an inline `type:`/`config:` mapping, or a `template:`/ `agent_template:` instantiation from a **template**-type component registered under `templates.agents` (§8.7). The Package Registry Standard (`docs/actor-registry-standard.md` §3.2) separately defines a plain `agent`-type package (prefix `pkg_agt_`) — "Agent definitions that can be referenced in actor configurations" — as its own package type, distinct from `template` (prefix `pkg_tpl_`). There is currently no field or mechanism anywhere in `cleveractors` that resolves a bare `agent`-type package reference (`local:<path>` or `host:namespace/name[@version]`, per Package Registry Standard §5.3) into a usable agent. The only working reference-resolution mechanism for agents is `SkillLoader`/`SkillReferenceResolver`, and that only resolves `skills:` entries on an already-instantiated `type: llm` agent, not the `agents.<name>` entry itself — `create_executor`'s own docstring (`src/cleveractors/runtime.py` lines ~299-314) is explicit that `local_store`/`registry_api_key` are scoped to `skills:` resolution only. ## Current behavior Using the library's documented `create_executor` entry point (`docs/guides/reasoning-aware-llm-agents.md`) with a bare package-reference agent entry: ```python from cleveractors.runtime import create_executor executor = create_executor( config_dict={ "agents": { "worker": "local:worker-agent.yaml", # an agent-type package reference }, "routes": { "main": { "type": "graph", "nodes": {"build": {"type": "agent", "agent": "worker"}}, "edges": [ {"source": "start", "target": "build"}, {"source": "build", "target": "end"}, ], }, }, }, credentials=None, local_store=my_local_store, ) await executor.execute("hello") ``` fails with: ``` AttributeError: 'str' object has no attribute 'get' ``` Root cause: `AgentFactory.create_agent`/`_create_agent_instance` (`src/cleveractors/agents/factory.py` lines ~196-213) unconditionally treats `agents_config[agent_name]` as a mapping (`agent_config.get("type", "llm")`), with no branch for a bare reference string. `create_executor` already accepts `local_store` and `registry_api_key` (used today only for `skills:` resolution), so the plumbing needed to resolve such a reference is present in the call signature but not wired to agent creation. The same gap exists for a `template:`/`agent_template:` mapping whose value is such a reference: `AgentFactory` has no awareness of the `template`/`agent_template` keys at all (that recognition exists only in `reactive/config_parser.py`'s `ReactiveConfig` parsing and `core/application.py`'s `_create_agents`, neither of which `AgentFactory`/`Executor` uses). So `agents.<name>: {"agent_template": "local:worker-agent.yaml"}` produces no error at all via this path — it silently degrades to an empty `type: llm` agent (no `"type"`/`"config"` key present), a related but distinct failure mode tracked in #122. ## Scope update — the identical bug class also affects `routes.<name>` During implementation, this same reference-resolution gap was confirmed to also affect the `routes` section, for the exact same reason: the Package Registry Standard (§3.2) defines `graph`-type (`pkg_grh_`) and `stream`-type (`pkg_str_`) packages as "route definitions that can be used as components in larger systems", but `docs/index.md` §5.1's `routes` grammar never named a bare-reference form either, and `cleveractors.runtime_dispatch._execute_graph`/ `_execute_graph_stream` exhibit the identical code defect: `main = routes.get("main", {})` followed by `main.get("nodes", {})` assumes `main` is a mapping, so `routes.main: "local:main-graph.yaml"` fails with the same raw `AttributeError`. Because both gaps share one root cause and one fix shape, they are addressed together in this issue/PR rather than split into a separate issue, per maintainer direction. See `docs/adr/ADR-2037-agent-and-route-package-reference-resolution.md` for the consolidated decision record (D-1 through D-6 cover `agents.<name>`; D-7 through D-9 cover `routes.<name>`). This project's implementation resolves a `routes.<name>` reference only for the single `routes.main` entry `_execute_graph`/`_execute_graph_stream` read, fixed to `package_type="graph"` (stream routes are not reachable via `create_executor`'s dispatch table); `docs/index.md` §5.1.1 itself documents the extension generically for both package types, per an implementation-agnostic Actor Configuration Standard. ## Expected behavior When `agents.<name>` is a bare string (a `local:`, `registry:`/host-qualified, or `ID:` reference per Package Registry Standard §5.3/§7.3) rather than a mapping, `AgentFactory` should resolve it — via the same `local_store`/`registry_api_key` plumbing already used by `SkillLoader` — to the referenced `agent`-type package's content, and use that content's `type`/config fields to construct the agent, exactly as if that content had been inlined under `type:`/`config:`. Likewise, when `routes.main` is a bare string, the graph-actor dispatch path should resolve it to the referenced `graph`-type package's content and use its route fields (`nodes`, `edges`, ...) exactly as if inlined under the `routes.main` mapping form. When the reference cannot be resolved (unknown scheme, missing package, network/registry error), agent/route creation must fail with a clear `AgentCreationError`/`ConfigurationError` naming the unresolved reference — never a raw `AttributeError`. ## Acceptance criteria - [ ] `agents.<name>` accepts a bare reference string (in addition to the existing `type:`/`config:` and `template:`/`agent_template:` mapping forms). - [ ] A `local:<path>` reference resolves via the supplied `LocalPackageStore` and produces a working agent. - [ ] A `host:namespace/name[@version]` registry reference resolves via a `RegistryClient` using `registry_api_key`, mirroring the resolution already implemented for `skills:`. - [ ] An unresolvable reference raises `AgentCreationError`/`ConfigurationError` with a message naming the reference — not an `AttributeError`. - [ ] Works identically via both `create_agent` (sync) and `acreate_agent` (async). - [ ] Demonstrated end-to-end via `create_executor` against a real/local LLM endpoint using a config with an `agents.<name>` bare-string reference. - [ ] `routes.main` accepts a bare reference string (in addition to the existing mapping form), resolved to a `graph`-type package. - [ ] A `local:<path>` route reference resolves via the supplied `LocalPackageStore` and produces a working graph actor. - [ ] A `host:namespace/name[@version]` registry route reference resolves via a `RegistryClient` (`package_type="graph"`). - [ ] An unresolvable route reference raises `ConfigurationError` naming the reference — not an `AttributeError`. - [ ] Demonstrated end-to-end via `create_executor` using a config with a `routes.main` bare-string reference. ## Supporting information - `docs/index.md` §4.1, §4.1.1, §5.1, §5.1.1, §8.7 (Actor Configuration Standard — agent and route declaration forms) - `docs/actor-registry-standard.md` §3.2, §5.3, §7.3 (Package Registry Standard — package types and reference formats) - `docs/adr/ADR-2037-agent-and-route-package-reference-resolution.md` (consolidated decision record for this issue) - `README.md` "Quick start" / `docs/guides/reasoning-aware-llm-agents.md` (documented public entry points: `ReactiveCleverAgentsApp`, `create_executor`) - `src/cleveractors/agents/factory.py` (`AgentFactory.create_agent`/`acreate_agent`) - `src/cleveractors/agents/agent_resolution.py` (new `AgentReferenceResolver`) - `src/cleveractors/route_resolution.py` (new `RouteReferenceResolver`) - `src/cleveractors/runtime_dispatch.py` (`_execute_graph`/`_execute_graph_stream` — `routes.main` normalisation) - `src/cleveractors/runtime.py` (`create_executor` — `local_store`/ `registry_api_key` currently scoped to `skills:` only) - `src/cleveractors/agents/skill_resolution.py`, `src/cleveractors/agents/skills.py` (existing working reference-resolution pattern mirrored by both new resolvers) ## Subtasks - [ ] Add a reference-detection branch in `AgentFactory.create_agent`/`acreate_agent` for a bare-string `agents.<name>` value. - [ ] Implement resolution against `LocalPackageStore` (`local:` scheme). - [ ] Implement resolution against `RegistryClient` (host-qualified scheme), threading `registry_api_key` the same way `SkillLoader` does. - [ ] Map resolved package content (flat shape) onto the `type`/`config` structure `_instantiate` expects. - [ ] Raise `AgentCreationError`/`ConfigurationError` (not `AttributeError`) on an unresolvable reference. - [ ] Add the identical reference-detection branch for a bare-string `routes.main` value in `_execute_graph`/`_execute_graph_stream`. - [ ] Implement route resolution against `LocalPackageStore`/`RegistryClient` (`package_type="graph"`). - [ ] Fix the pre-existing duplicate `routes.main` re-fetch (`parallel_execution` computation) to reuse the normalised/resolved `main` value. - [ ] Tests (Behave): scenarios for `local:` and registry-reference agent AND route resolution, and for the unresolvable-reference error path on both. - [ ] Tests (Robot): integration test loading an `agent`-type package via a graph configuration's `agents.<name>` entry, and a `graph`-type package via `routes.main`. - [ ] Verify coverage >=97% via `nox -s coverage_report`. - [ ] Run `nox` (all default sessions), fix any errors. ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly. - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done.
Author
Member

Scope expanded during implementation: the same bare-string package-reference gap (raw AttributeError instead of resolving via the registry) was confirmed to also affect routes.<name> (for graph/stream-type packages), not just agents.<name>. Both are fixed together in this issue/PR per maintainer direction, since they share one root cause and one fix shape. See the updated issue description and docs/adr/ADR-2037-agent-and-route-package-reference-resolution.md for the consolidated decision record.

Scope expanded during implementation: the same bare-string package-reference gap (raw `AttributeError` instead of resolving via the registry) was confirmed to also affect `routes.<name>` (for `graph`/`stream`-type packages), not just `agents.<name>`. Both are fixed together in this issue/PR per maintainer direction, since they share one root cause and one fix shape. See the updated issue description and `docs/adr/ADR-2037-agent-and-route-package-reference-resolution.md` for the consolidated decision record.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
cleveragents/cleveractors-core#121
No description provided.