Skip to content

feat: experimental keyless CLI backend with auto-fallback and ASR fallback#11

Open
dull-bird wants to merge 4 commits into
microsoft:mainfrom
dull-bird:feature/cli-backend-keyless-video
Open

feat: experimental keyless CLI backend with auto-fallback and ASR fallback#11
dull-bird wants to merge 4 commits into
microsoft:mainfrom
dull-bird:feature/cli-backend-keyless-video

Conversation

@dull-bird

@dull-bird dull-bird commented Jul 24, 2026

Copy link
Copy Markdown

Summary

This PR adds an experimental, opt-in way to run Resource2Skill without Azure OpenAI or Gemini API keys by using locally authenticated agent CLIs (currently Claude Code) as the LLM backend, and by analyzing YouTube videos from yt-dlp subtitles + ffmpeg keyframes instead of Gemini native video understanding.

It now also auto-detects the keyless path when API keys are missing, and falls back to local ASR when a video has no native subtitles.

Changes

  • "core/llm_cli.py": new CLI LLM backend for Claude Code. Supports multi-turn conversations via session resume ("--resume") and emulates OpenAI function calling with a strict JSON envelope protocol.
  • "core/llm.py": dispatch to the CLI backend when "R2S_LLM_BACKEND=cli" and "R2S_CLI_TOOL=claude" are set. Existing API-key paths remain the default and are unchanged.
  • "core/llm.py": auto-fallback to CLI when "AZURE_OPENAI_API_KEY" is missing and an agent CLI (claude, codex, kimi, omp) is on PATH.
  • "core/analyzer_cli_video.py": new "R2S_VIDEO_BACKEND=cli" path. Fetches auto-generated VTT subtitles (with rolling-caption dedup), extracts key frames, and asks Claude Code to reason over the transcript + image paths.
  • "core/analyzer.py": lazy-import "google-genai" so the CLI video path can run without the Gemini SDK installed, and auto-fallback to "R2S_VIDEO_BACKEND=cli" when "GEMINI_API_KEY" is missing.
  • "core/analyzer_cli_video.py": ASR fallback when no native VTT is found. Supports "R2S_VIDEO_ASR=auto|faster-whisper|whisper" and "R2S_VIDEO_ASR_MODEL=tiny|base|small".
  • "skill/Resource2Skill/SKILL.md": agent connector updated with skill discovery, default behavior, and ASR options.
  • "README.md" / ".env.example": document the new no-key setup and ASR variables.

Verification

  • Multi-turn memory test: model recalls a codeword across resume sessions.
  • Tool-protocol test: model emits "tool_calls", harness executes, result is incorporated.
  • "python cli.py domains" and "python cli.py validate-domain --domain web" run without API keys.
  • Dry-run agent loop completes iterations without backend errors.
  • Reproduced one skill from the official HF dataset ("microsoft/RESOURCE2SKILL") on a 65s CSS typewriter tutorial; the CLI subtitle+frame analysis produced the same core mechanism ("steps()" + "overflow:hidden" + blinking cursor) as the official Gemini-based skill.
  • ASR fallback benchmark on a 60s English YouTube clip (M4 Macbook Air):
    • faster-whisper tiny: ~4s
    • openai-whisper tiny: ~21s
    • faster-whisper base: ~25s, noticeably more accurate than tiny
  • Native VTT path still works; forced no-subtitle fallback produces a valid VTT.

Scope / Limitations

  • Only "claude" is implemented. "codex", "kimi", and "omp" are reserved via "R2S_CLI_TOOL" but currently raise "not supported yet".
  • "R2S_VIDEO_BACKEND=cli" image ingestion works best with Claude Code; kimi/codex/omp have not been verified for local image input.
  • "python cli.py build" (embeddings) still needs a Gemini key unless keyword-only retrieval is acceptable.
  • ASR fallback requires "faster-whisper" or "openai-whisper" installed; first model download is ~40MB (tiny) to ~150MB (base). Transcription speed depends on CPU.

Backward Compatibility

Default behavior is unchanged. Users can explicitly set "R2S_LLM_BACKEND=cli" and/or "R2S_VIDEO_BACKEND=cli" to use the new paths, or leave keys unset and let the system auto-fallback when a local CLI is available.

…me video analysis

- Add core/llm_cli.py: drive Claude Code as an LLM backend via session-resume
  multi-turn and a text tool-call protocol. Activated by R2S_LLM_BACKEND=cli.
- Wire dispatch in core/llm.py so call_azure_openai and call_llm route to the
  CLI backend without changing any call sites.
- Add core/analyzer_cli_video.py: R2S_VIDEO_BACKEND=cli analyzes YouTube videos
  using yt-dlp subtitles + ffmpeg keyframes instead of Gemini.
- Make google-genai import lazy in core/analyzer.py so the CLI video path can
  run without the Gemini SDK installed.
- Add skill/Resource2Skill/SKILL.md connector for agents to drive cli.py.
- Update README.md and .env.example with no-API-key setup instructions.
- Detect locally installed agent CLIs (claude, codex, kimi, omp) and default
  R2S_LLM_BACKEND=cli when AZURE_OPENAI_API_KEY is absent.
- Default R2S_VIDEO_BACKEND=cli when GEMINI_API_KEY is absent so video
  analysis uses yt-dlp subtitles + ffmpeg keyframes without configuration.
- Update skill/Resource2Skill/SKILL.md with discovery/retrieval instructions
  and explain the skill.json format.
- Update README no-key section with the new auto-fallback behavior.
@dull-bird

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

- Add _download_audio, _run_asr, and helpers to core/analyzer_cli_video.py.
- Support R2S_VIDEO_ASR=auto|faster-whisper|whisper and R2S_VIDEO_ASR_MODEL.
- Fallback only triggers after yt-dlp reports no native VTT subtitles.
- Benchmark: faster-whisper tiny is ~5x faster than openai-whisper tiny on a
  60s clip (3.9s vs 20.6s) at comparable quality.
- Update README, .env.example, and SKILL.md with the new env variables and
  limitations.
@dull-bird dull-bird changed the title feat: experimental keyless CLI backend (Claude Code) and subtitle+frame video analysis feat: experimental keyless CLI backend with auto-fallback and ASR fallback Jul 25, 2026

@waltstephen waltstephen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @dull-bird,

Thanks for contributing and sharing this keyless CLI path with the project. After narrowing the review, I think there are only two core issues to address before merge:

  1. core/llm_cli.py: isolate conversations. Sessions are identified only from the first two messages, so two independent identical runs can reuse the same Claude session, with the second run sent as Continue.. Please scope the session to each run or use an explicit conversation identity.

  2. The fallback should respect an explicitly supplied Gemini key. In core/analyzer.py and core/llm.py, backend selection checks the GEMINI_API_KEY environment variable but can ignore a valid per-call api_key= value and route the request to the CLI backend instead. Please include the explicit key when deciding whether fallback is needed.

One minor item: skill/Resource2Skill/SKILL.md currently fails the standard skill validator. Removing the unsupported author field and using a lowercase hyphen-case name should resolve it.

Thanks again for providing this contribution and making the work available to the community. Once these items are updated, I’ll take another pass.

@dull-bird

dull-bird commented Jul 27, 2026

Copy link
Copy Markdown
Author

Thanks for taking a look. I've pushed the fixes to feature/cli-backend-keyless-video (c9a9f77a).

I addressed three items:

  • CLI sessions are now isolated by conversation_id, and the agent loop generates a fresh run id per task.
  • Explicit api_key= now takes precedence over auto-fallback, so the code will not switch to the CLI backend by mistake.
  • skill/Resource2Skill/SKILL.md now uses a validator-friendly header format.

Verified with python -m pytest -q test_keyless_cli_backend.py, python cli.py validate-domain --domain web/ppt/excel/reaper/blender, and python -m pytest -q domains/ppt/test_pptmaster_r2s_validator.py.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants