fix(gif): stop making agents discover the API by failing
Closes mort#1522. 23% of all code_exec calls across two production runs (9 of 39) failed on gifsmith API misuse, hitting 7 of 14 workers. The recovery was always the same shape: another round trip spent printing gifsmith's own source — or, in one case, running `dir(gifsmith)` — to learn what the module contains. Three distinct causes, three fixes. **Unguessable re-exports → `__all__`, plus the two that were missing.** The module exported SOME matplotlib artists and not others, and the only way to find out which was to fail: two workers wrote `from gifsmith import PathPatch` and got an ImportError while `FancyBboxPatch` beside it worked. `PathPatch` and `Path` are now exported, on the rule "the drawing vocabulary, whole". `__all__` states the surface — and it also fixes what made self-service expensive: `dir(gifsmith)` returned 24 names of which nine were incidental imports (glob, os, shutil, subprocess, sys, traceback...), several being things a scene author should never touch. SKILL.md now carries the same list, so the question should not arise. **Near-miss constructor kwargs → an error that names the miss.** `background=` is accepted as an alias for `bg` (it is the obvious synonym, and an agent reached for it). `force=` is rejected with the reason it was tempting — `render(force="mp4")` really does take it, which makes it read like an Animation-level setting. Anything else gets a difflib near-match and the valid list. Both failures were one round trip each, and both are the kind a message fixes for free. **Scenes fail at render time → dry-run every scene at t=0 first.** A NameError in scene 4 used to surface only after scenes 0-3 were fully rendered, and with a streaming pipe open, after frames had gone into the encoder. Two workers lost a whole render each to `RuntimeError: every scene failed`, learning one broken name per attempt. One frame per scene now reports EVERY broken scene in a single pass, before any scratch dir or ffmpeg pipe exists. Per-scene isolation is preserved exactly: a scene that fails the dry run is marked and skipped rather than re-run to fail identically, the others still ship, and only an all-scenes-broken program raises early — which is precisely the case that was paying for a full setup to learn nothing. Verified against the production failures: `Animation(background=…)` now works, `Animation(force=…)` explains itself, `Animation(backgrnd=…)` suggests `background`, every name in `__all__` resolves, no incidental import leaks into it, and the dry run marks exactly the broken scenes while leaving the good ones untouched. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
+10
-1
@@ -76,9 +76,18 @@ bottom of this skill) as `{"name": "gifsmith.py", "file_id": "<that id>"}`, then
|
||||
write ONE `code_exec` call:
|
||||
|
||||
```python
|
||||
# gifsmith re-exports the drawing vocabulary, so this one import is enough:
|
||||
# gifsmith re-exports the drawing vocabulary, so this one import is enough.
|
||||
# The COMPLETE importable list (there is nothing else — don't guess, and don't
|
||||
# spend a call on dir(gifsmith)):
|
||||
# Animation
|
||||
# Arc Circle Ellipse FancyBboxPatch PathPatch Path Polygon Rectangle Wedge
|
||||
# Image ImageDraw ImageFont (PIL, for mode="pil")
|
||||
# np plt (numpy / pyplot, for anything else)
|
||||
# GIF_MAX_SECONDS GIF_MAX_BYTES
|
||||
from gifsmith import Animation, Circle, Ellipse, Rectangle, Polygon, Wedge, np
|
||||
anim = Animation(width=640, height=480, fps=15) # canvas locked here
|
||||
# Animation() takes ONLY width, height, fps, dpi, bg (background= also works).
|
||||
# Everything about the output — format, size, audio — is set on render().
|
||||
|
||||
# ---- cast: defined ONCE, called from every scene ----
|
||||
def draw_steve(ax, x, y, rage=0.0):
|
||||
|
||||
Reference in New Issue
Block a user