99c95af64e
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.
73 lines
2.5 KiB
YAML
73 lines
2.5 KiB
YAML
name: resolve_movie_destination
|
|
|
|
summary: >
|
|
Compute destination paths for a movie file (file move).
|
|
|
|
description: |
|
|
Resolves the target movie folder and full destination filename for a movie
|
|
release. Returns paths only — does not move anything. Movies do not have
|
|
the existing-folder disambiguation problem that TV shows have (each
|
|
release lands in its own folder named after the canonical title + year +
|
|
tech).
|
|
|
|
when_to_use: |
|
|
Use after analyze_release has identified the release as a movie
|
|
(media_type=movie). TMDB must already be queried for the canonical title
|
|
and release year.
|
|
|
|
when_not_to_use: |
|
|
- TV shows in any form: use resolve_season_destination /
|
|
resolve_episode_destination / resolve_series_destination.
|
|
- Documentaries when they're treated as series rather than standalone
|
|
films: route them through the TV-show resolvers.
|
|
|
|
next_steps: |
|
|
- On status=ok: call move_to_destination with the source video file and
|
|
destination=library_file.
|
|
- On status=error: surface the message; do not move.
|
|
|
|
parameters:
|
|
release_name:
|
|
description: Raw release folder or file name.
|
|
why_needed: |
|
|
Drives extraction of quality/source/codec/group/edition tokens, which
|
|
become part of both the movie folder and filename so each release is
|
|
self-describing on disk.
|
|
example: Inception.2010.1080p.BluRay.x265-GROUP
|
|
|
|
source_file:
|
|
description: Absolute path to the source video file on disk.
|
|
why_needed: |
|
|
Used to read the file extension for the destination filename.
|
|
example: /downloads/Inception.2010.1080p.BluRay.x265-GROUP/movie.mkv
|
|
|
|
tmdb_title:
|
|
description: Canonical movie title from TMDB.
|
|
why_needed: |
|
|
Title prefix for the destination folder/file; ensures the library
|
|
uses the canonical title and not a sanitized release-name title.
|
|
example: Inception
|
|
|
|
tmdb_year:
|
|
description: Movie release year from TMDB.
|
|
why_needed: |
|
|
Disambiguates remakes that share a title (Dune 1984 vs Dune 2021)
|
|
and locks the folder identity in time.
|
|
example: "2010"
|
|
|
|
returns:
|
|
ok:
|
|
description: Paths resolved; ready to move.
|
|
fields:
|
|
movie_folder: Absolute path to the movie folder.
|
|
library_file: Absolute path to the destination .mkv file (move target).
|
|
movie_folder_name: Folder name for display.
|
|
filename: Destination filename for display.
|
|
is_new_folder: True if the movie folder doesn't exist yet.
|
|
|
|
error:
|
|
description: Resolution failed.
|
|
fields:
|
|
error: Short error code (e.g. library_not_set).
|
|
message: Human-readable explanation.
|