bug(tool): spec resources: dict format silently ignored — Tool.from_config() only reads resource_slots: list #2068

Open
opened 2026-04-03 03:47:52 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/tool-from-config-resources-dict-format
  • Commit Message: fix(tool): support spec-compliant resources: dict format in Tool.from_config()
  • Milestone: v3.7.0
  • Parent Epic: #392

Problem Description

The specification (docs/specification.md) defines the canonical tool YAML format using a resources: key with a dict format, where each key is the slot name and the value is the slot definition:

tool:
  name: local/run-migrations
  description: "Run database migrations for the API service"
  source: custom
  resources:
    db:
      type: local/database
      access: read_write
      required: true
      description: "Target database for migrations"
  capability:
    writes: true
    checkpointable: true
  code: |
    return {}

However, Tool.from_config() in src/cleveragents/domain/models/core/tool.py reads resource slots using:

config.get("resource_slots", [])

This expects a list format (each item having an explicit name field), which is the format used in examples/tools/ but not the format defined in the specification. When a spec-compliant YAML with resources: dict is passed to Tool.from_config(), the resources: key is silently ignored — not recognised, not warned about — resulting in a tool with zero resource slots.

Reproduction

import yaml
from cleveragents.domain.models.core.tool import Tool

spec_yaml = """
tool:
  name: local/run-migrations
  description: Run database migrations
  source: custom
  resources:
    db:
      type: local/database
      access: read_write
      required: true
      description: Target database
  code: 'return {}'
"""
config = yaml.safe_load(spec_yaml)['tool']
t = Tool.from_config(config)
print(len(t.resource_slots))  # Prints 0 — resource bindings silently ignored!

Impact

Severity: High. Any spec-compliant tool YAML file that uses the resources: dict format will silently lose all resource slot definitions. This causes runtime failures when the tool attempts to access bound resources, with no error or warning at parse time.

Affected Surfaces

  • src/cleveragents/domain/models/core/tool.pyTool.from_config() method
  • agents tool add CLI command (uses Tool.from_config() internally)

Root Cause

Tool.from_config() calls config.get("resource_slots", []) but the spec's canonical key is resources: (dict). The examples in examples/tools/ use the non-spec resource_slots: list format, masking the discrepancy.

Expected Fix

Tool.from_config() must accept both formats:

  1. resources: dict format (spec-canonical) — keys are slot names, values are slot definitions
  2. resource_slots: list format (legacy/examples) — each item has an explicit name field

Per the project rule that the specification is always considered correct, the resources: dict format must be treated as the primary format. A ValueError (or at minimum a logged warning) should be raised if an unknown top-level key is encountered, to prevent future silent data loss.

Subtasks

  • Write a failing Behave scenario in features/ that proves Tool.from_config() silently drops resources: dict bindings (TDD — must be merged to master before the fix)
  • Update Tool.from_config() to detect and parse the resources: dict format, converting each key/value pair into a resource slot
  • Retain backward-compatible support for the existing resource_slots: list format
  • Add argument validation / ValueError if both resources: and resource_slots: are present simultaneously (ambiguous config)
  • Add a Behave scenario covering the resource_slots: list format to ensure no regression
  • Add a Behave scenario covering the agents tool add CLI command with a spec-compliant resources: YAML
  • Update examples/tools/ example files to use the spec-canonical resources: dict format (or add a note explaining both formats)
  • Ensure all type annotations in Tool.from_config() remain valid and pass nox -e typecheck

Definition of Done

  • A failing Behave test proving the bug is merged to master before any fix code is written
  • Tool.from_config() correctly parses the spec-canonical resources: dict format into resource slots
  • Tool.from_config() retains backward-compatible support for the resource_slots: list format
  • No silent data loss: unknown/unrecognised top-level config keys raise a ValueError or equivalent
  • All Behave scenarios in features/ pass (nox -e unit_tests)
  • All Robot Framework integration tests pass (nox -e integration_tests)
  • All nox stages pass (nox)
  • Coverage >= 97%

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/tool-from-config-resources-dict-format` - **Commit Message**: `fix(tool): support spec-compliant resources: dict format in Tool.from_config()` - **Milestone**: v3.7.0 - **Parent Epic**: #392 ## Problem Description The specification (`docs/specification.md`) defines the canonical tool YAML format using a `resources:` key with a **dict format**, where each key is the slot name and the value is the slot definition: ```yaml tool: name: local/run-migrations description: "Run database migrations for the API service" source: custom resources: db: type: local/database access: read_write required: true description: "Target database for migrations" capability: writes: true checkpointable: true code: | return {} ``` However, `Tool.from_config()` in `src/cleveragents/domain/models/core/tool.py` reads resource slots using: ```python config.get("resource_slots", []) ``` This expects a **list format** (each item having an explicit `name` field), which is the format used in `examples/tools/` but **not** the format defined in the specification. When a spec-compliant YAML with `resources:` dict is passed to `Tool.from_config()`, the `resources:` key is silently ignored — not recognised, not warned about — resulting in a tool with **zero resource slots**. ### Reproduction ```python import yaml from cleveragents.domain.models.core.tool import Tool spec_yaml = """ tool: name: local/run-migrations description: Run database migrations source: custom resources: db: type: local/database access: read_write required: true description: Target database code: 'return {}' """ config = yaml.safe_load(spec_yaml)['tool'] t = Tool.from_config(config) print(len(t.resource_slots)) # Prints 0 — resource bindings silently ignored! ``` ### Impact **Severity: High.** Any spec-compliant tool YAML file that uses the `resources:` dict format will silently lose all resource slot definitions. This causes runtime failures when the tool attempts to access bound resources, with no error or warning at parse time. ### Affected Surfaces - `src/cleveragents/domain/models/core/tool.py` — `Tool.from_config()` method - `agents tool add` CLI command (uses `Tool.from_config()` internally) ### Root Cause `Tool.from_config()` calls `config.get("resource_slots", [])` but the spec's canonical key is `resources:` (dict). The examples in `examples/tools/` use the non-spec `resource_slots:` list format, masking the discrepancy. ### Expected Fix `Tool.from_config()` must accept **both** formats: 1. `resources:` dict format (spec-canonical) — keys are slot names, values are slot definitions 2. `resource_slots:` list format (legacy/examples) — each item has an explicit `name` field Per the project rule that **the specification is always considered correct**, the `resources:` dict format must be treated as the primary format. A `ValueError` (or at minimum a logged warning) should be raised if an unknown top-level key is encountered, to prevent future silent data loss. ## Subtasks - [ ] Write a failing Behave scenario in `features/` that proves `Tool.from_config()` silently drops `resources:` dict bindings (TDD — must be merged to `master` before the fix) - [ ] Update `Tool.from_config()` to detect and parse the `resources:` dict format, converting each key/value pair into a resource slot - [ ] Retain backward-compatible support for the existing `resource_slots:` list format - [ ] Add argument validation / `ValueError` if both `resources:` and `resource_slots:` are present simultaneously (ambiguous config) - [ ] Add a Behave scenario covering the `resource_slots:` list format to ensure no regression - [ ] Add a Behave scenario covering the `agents tool add` CLI command with a spec-compliant `resources:` YAML - [ ] Update `examples/tools/` example files to use the spec-canonical `resources:` dict format (or add a note explaining both formats) - [ ] Ensure all type annotations in `Tool.from_config()` remain valid and pass `nox -e typecheck` ## Definition of Done - [ ] A failing Behave test proving the bug is merged to `master` before any fix code is written - [ ] `Tool.from_config()` correctly parses the spec-canonical `resources:` dict format into resource slots - [ ] `Tool.from_config()` retains backward-compatible support for the `resource_slots:` list format - [ ] No silent data loss: unknown/unrecognised top-level config keys raise a `ValueError` or equivalent - [ ] All Behave scenarios in `features/` pass (`nox -e unit_tests`) - [ ] All Robot Framework integration tests pass (`nox -e integration_tests`) - [ ] All nox stages pass (`nox`) - [ ] Coverage >= 97% --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.7.0 milestone 2026-04-03 03:47:56 +00:00
freemo self-assigned this 2026-04-03 16:58:11 +00:00
Owner

Thank you for filing this issue, @freemo.

This has been triaged and verified. Summary of triage decisions:

  • State: Verified — the bug is confirmed. Tool.from_config() reads resource_slots: (list format) but the specification defines resources: (dict format) as canonical. Silent data loss at parse time is a correctness issue.
  • Priority: High — any spec-compliant tool YAML silently loses all resource slot definitions, causing runtime failures with no error at parse time.
  • MoSCoW: Must Have — per CONTRIBUTING.md, the specification is the authoritative source of truth. Code must align with the spec. Silent data loss with no warning is unacceptable.
  • Milestone: v3.7.0 (as assigned) — appropriate given the tool system is part of the TUI milestone scope.
  • Story Points: 5 — moderate complexity due to dual-format support, backward compatibility, and TDD-first requirement.

Labels applied: Type/Bug, State/Verified, Priority/High, MoSCoW/Must have, Points/5.

The issue is well-structured with a clear reproduction case, root cause analysis, and TDD-first subtask breakdown. It is now in the backlog and will be picked up for implementation.


Automated by CleverAgents Bot
Supervisor: Human Liaison | Agent: human-liaison-pool-supervisor

Thank you for filing this issue, @freemo. This has been triaged and verified. Summary of triage decisions: - **State**: Verified — the bug is confirmed. `Tool.from_config()` reads `resource_slots:` (list format) but the specification defines `resources:` (dict format) as canonical. Silent data loss at parse time is a correctness issue. - **Priority**: High — any spec-compliant tool YAML silently loses all resource slot definitions, causing runtime failures with no error at parse time. - **MoSCoW**: Must Have — per CONTRIBUTING.md, the specification is the authoritative source of truth. Code must align with the spec. Silent data loss with no warning is unacceptable. - **Milestone**: v3.7.0 (as assigned) — appropriate given the tool system is part of the TUI milestone scope. - **Story Points**: 5 — moderate complexity due to dual-format support, backward compatibility, and TDD-first requirement. Labels applied: `Type/Bug`, `State/Verified`, `Priority/High`, `MoSCoW/Must have`, `Points/5`. The issue is well-structured with a clear reproduction case, root cause analysis, and TDD-first subtask breakdown. It is now in the backlog and will be picked up for implementation. --- **Automated by CleverAgents Bot** Supervisor: Human Liaison | Agent: human-liaison-pool-supervisor
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#392 Epic: Actor YAML & Compiler
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#2068
No description provided.