Commit Graph

1 Commits

Author SHA1 Message Date
francwa 99c95af64e feat(agent): YAML tool specs as the LLM-facing semantic layer
Introduce a first-class semantic layer for tool descriptions, separated
from Python signatures (which stay the source of truth for types and
required-ness).

New
- alfred/agent/tools/spec.py — ToolSpec / ParameterSpec / ReturnsSpec
  dataclasses with strict YAML validation (ToolSpecError on malformed
  or inconsistent specs). compile_description() builds the rich text
  passed to the LLM as Tool.description, with sections for summary,
  description, when_to_use, when_not_to_use, next_steps, and returns.
  compile_parameter_description() injects the 'why_needed' field next
  to each parameter so the LLM sees the *intent* of each argument.
- alfred/agent/tools/spec_loader.py — discovers tools/specs/*.yaml,
  enforces filename ↔ spec.name match, rejects duplicates.
- alfred/agent/tools/specs/ — one YAML per tool:
    * resolve_season_destination.yaml
    * resolve_episode_destination.yaml
    * resolve_movie_destination.yaml
    * resolve_series_destination.yaml
    * move_to_destination.yaml

Refactor
- alfred/agent/registry.py
    * _create_tool_from_function now takes an optional ToolSpec.
      When provided, the long description + per-parameter descriptions
      come from the spec; types and required-ness still come from the
      Python signature.
    * Cross-validates spec.parameters against the function signature —
      crashes on missing or extra entries.
    * make_tools() loads all specs at startup and hands the right one
      to each tool. Tools without a spec fall back to the old
      docstring-only behaviour, so the 14 not-yet-migrated tools keep
      working unchanged.
    * Adds 'array' and 'object' to the Python→JSON type mapping and
      handles Optional[X] / X | None annotations.

- alfred/agent/tools/filesystem.py
    * Drops the '_tool' suffix on the 4 resolve_* wrappers (option 1:
      alias the use-case imports as _resolve_*). Tool names exposed to
      the LLM now match the underlying use case verbatim.
    * Wrapper docstrings shrink to a one-liner pointing to the YAML
      spec — no more duplicated when_to_use/Args/Returns in Python.

Verified
- make_tools() loads 19 tools (5 with YAML spec, 14 doc-only).
- Compiled descriptions render cleanly with all sections.
2026-05-14 18:06:27 +02:00