feat(media-use): use CLI free HeyGen usage (#2027)

* feat(media-use): use CLI free HeyGen usage

* fix(media-use): address #2027 R1 nits — gate cli-source header to OAuth, export origin constant

- X-HeyGen-Source is now sent only on OAuth (Bearer) requests, not API-key ones —
  the backend ignores it for API-key traffic (normal billing), so it was dead
  metadata there. buildAuthHeaders + heygenAuthHeaders + tests updated.
- Export HEYGEN_CLI_ORIGIN_HEADER ("X-HeyGen-Client-Origin") for future cli:<origin>
  consumers.
- Document the deliberate paid/X4 confirm-before-call decision on heygen.tts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv

* refactor(cli): drop unused origin-header export, dedup auth-client tests

Fallow flagged 5 findings on this PR:
- major: HEYGEN_CLI_ORIGIN_HEADER was exported but never emitted or
  imported — speculative dead code ("future consumers"). Remove it; a
  real consumer can add the constant when one exists.
- 4x minor duplication in client.test.ts: fold the repeated
  `.rejects.toSatisfy(auth-code)` assertion into expectAuthCode(), and the
  repeated try/catch scrubbed-message assertion into expectRejectionMessage().

No behavior change; auth/client tests still 17/17.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Miguel Ángel
2026-07-09 18:28:26 -04:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 1614dd3e5a
commit 3b93f516b4
12 changed files with 173 additions and 69 deletions
+16 -10
View File
@@ -8,13 +8,14 @@
// An entry exposes any of three capability methods — search / generate /
// process — plus { name }. media-use holds no keys; each external tool owns its
// own auth. Providers, by type:
// - heygen CLI: catalog + TTS, first for every type it serves (sub creds)
// - heygen CLI: catalog + TTS, first for every type it serves (OAuth free
// allowance first, then the user's HeyGen billing path)
// - mflux: local FLUX-class image gen, spec-selected to the machine's RAM
// (free, private, offline once cached)
// - codex CLI: image gen on the user's ChatGPT sub — the better-quality upsell
// and the fallback when no local model fits
// - Kokoro (via the hyperframes CLI): local voiceover, free/private default
// for the voice type, ahead of the paid HeyGen TTS upsell
// - Kokoro (via the hyperframes CLI): local voiceover, free/private fallback
// when HeyGen credentials are absent or --local-only is requested
//
// Generation is local-first, cloud-upsell. `ctx.provider` forces one provider
// (e.g. "make an image with codex").
@@ -35,9 +36,10 @@ import { codexImageGenerate } from "./codex-provider.mjs";
import { mfluxImageGenerate } from "./mflux-provider.mjs";
// Provider markers: `network` = hits a remote service (skipped by --local-only).
// `paid` = costs wallet credits (documentation for the agent's cost judgment,
// X4: agent-initiated paid should confirm). HeyGen catalog SEARCH is free;
// HeyGen TTS now costs credits, so it is the paid upsell behind local Kokoro.
// `paid` = may cost wallet credits after any OAuth/web-plan free allowance
// (documentation for the agent's cost judgment, X4: agent-initiated paid should
// confirm). HeyGen catalog SEARCH is free; HeyGen TTS is free for eligible
// OAuth CLI users up to the monthly allowance, then follows the user's billing.
const A = (name, caps) => ({ name, ...caps }); // local, free
const N = (name, caps) => ({ name, network: true, ...caps }); // remote, free
const P = (name, caps) => ({ name, network: true, paid: true, ...caps }); // remote, paid
@@ -67,11 +69,15 @@ const REGISTRY = {
N("favicon.ddg", { search: faviconSearch }),
],
voice: [
// Local Kokoro first (free, private, on-device via the hyperframes CLI, kept
// under --local-only), then HeyGen TTS as the higher-quality paid upsell and
// the fallback when Kokoro is not set up.
A("kokoro.local", { generate: localTtsGenerate }),
// HeyGen TTS first when credentialed so CLI/OAuth users consume the free
// web-plan allowance (10 min/month) before any paid path. --local-only skips
// it and keeps Kokoro as the private/offline fallback.
// Deliberately kept `paid` (X4 confirm-before-call) even though the first
// 10 min/month are free: the client can't know the remaining allowance, so
// confirming is safer than risking a silent charge once it's spent. (A
// tri-state "quota-first, paid after" would need backend quota state.)
P("heygen.tts", { generate: heygenTtsGenerate }),
A("kokoro.local", { generate: localTtsGenerate }),
],
brand: [
// Local design spec, not heygen — reads frame.md / design.md tokens.