Media proxy
Skill gooseworks-ai/goose-skills/skills/ads/capabilities/media-proxy
Shared helper that routes ALL paid media generation (FAL image/video, ElevenLabs music) through the GooseWorks proxies so every call bills the Ads agent — never a provider SDK's default host. Host-swaps the FAL queue URLs, loads the agent token from ~/.gooseworks/credentials.json, and returns the result CDN URL. Every video-ad media capability imports this; templates never call a provider directly.From its SKILL.md
npx -y skills add gooseworks-ai/goose-skills --skill media-proxyAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- reads credentialsReads from 1 credential source: `~/.gooseworks/credentials.json`.
- runs commandsInstructs the agent to run 2 commands, including `resume.py --list` and 1 more.
- fetches URLsInstructs the agent to fetch 2 URLs, including <api_base>/api/internal/fal-proxy and 1 more.
SKILL.md
3.2 KB, 751 tokens by cl100k_base, as published. Nobody here has run it
media-proxy
The foundation capability for paid media in the video-ad pipeline. It fixes the
auth-path conflict where engine scripts called FAL/ElevenLabs directly (billing
the wrong account): all paid calls now go through
<api_base>/api/internal/{fal-proxy,elevenlabs-proxy} with ?token=&agent_id=, which
bills the Ads agent.
Crash-resume (never lose / double-bill a paid render)
A FAL submit BILLS immediately, but the local backend can blip during a multi-minute render. Two built-in protections (automatic for every capability that imports this):
-
Poll-through-outage —
_fal_run's poll loop re-attaches to the same status/result URL throughconnection refused/ timeout blips instead of crashing. -
Persist + resume — each submit's
request_id+ poll URLs are written to~/.gooseworks/pending-fal-jobs/. If the poller still dies, re-attach instead of re-firing (re-firing double-bills):resume_fal(request_id)in Python, or the CLI:resume.py --list # resumable (submitted, unfinished) jobs resume.py --request-id <id> --out final.mp4 # poll to completion + downloadresume_falNEVER re-submits, so it can't double-charge.
Use it
from media_proxy import fal_generate, fal_generate_video, eleven_music, download
# image (nano-banana / gpt-image / etc.) — inputs must be PUBLIC urls
img = fal_generate("fal-ai/nano-banana/edit",
{"prompt": p, "image_urls": [product_url], "aspect_ratio": "9:16"})
# video i2v (kling / seedance / veo)
vid = fal_generate_video("fal-ai/kling-video/v2.1/standard/image-to-video",
{"prompt": p, "image_url": keyframe_url, "duration": "10"})
# music bed
eleven_music(prompt, 10500, "music.mp3", force_instrumental=True)
Contracts (load-bearing)
- Bills the Ads agent —
?token=&agent_id=from~/.gooseworks/credentials.json(the CLI writes it; rungooseworks loginif missing). - Host-swap the FAL queue URLs — submit returns
status_url/response_urlonqueue.fal.run; the helper rewrites them to the proxy base (keeps the path). Never pollqueue.fal.rundirectly (401 + burns credits). - FAL inputs that are local files must be PUBLIC urls. The orchestrator hosts a
local image/audio via the MCP
get_upload_url→get_download_urlpresigned URL and passes THAT url in. This module does not do MCP uploads (prefer the presigned url;fal-storage-proxymay 404). - Only the final
*.fal.mediaurl is a real public URL — everything else is behind the proxy.
Related
- Used by
create-image-fal,create-video-fal,create-music-elevenlabs. - The
goose-videoorchestrator hosts local inputs (MCP upload → presign) before calling these.
What ships with it: 4 files
17.5 KB alongside SKILL.md, 2 of them executable
scripts/
- media_proxy.pyruns14.9 KB
- resume.pyruns2.2 KB
tests/
- smoke-test.md183 B
- skill.meta.json259 B