foley.agent.decompose
decompose_context — narrative passage → a sparse, salience-ranked event list.
The moat of the SELECT stage (report 05 §2): turning prose into a tastefully sparse,
correctly-diegetic SoundEvent list is the hard, defensible part —
not the CLAP encoder. Two impls sit behind the Decomposer
seam:
KeywordDecomposer— the deterministic default and the hermetic CI fake: a built-in cue lexicon, zero dependencies, same passage → identical list.AnthropicDecomposer— the LLM-backed impl behind thefoley[agent]extra;anthropicis imported lazily inside.decomposeonly, soimport foleystays dol-only.
decompose_context() is the pure tool wrapper (Python-API == agent == future-MCP
surface): it resolves the default decomposer, calls it, and records the GenAI span on
the real path.
- class foley.agent.decompose.AnthropicDecomposer(*, client=None, model: str = 'claude-opus-4-8', max_tokens: int = 2000)[source]
LLM-backed decomposer (
foley[agent]): Claude → a structured event list.anthropicis imported lazily insidedecompose()soimport foleystays dol-only. Stashes the returnedMessageonself.last_responsesodecompose_context()can record the GenAI span (token usage / model / stop_reason). Model, thinking, and structured-output shape follow theclaude-apiconventions (claude-opus-4-8, adaptive thinking — neverbudget_tokens).- decompose(context: str, *, max_events: int = 6, seconds: float | None = None) list[SoundEvent][source]
Call Claude and round-trip each event through
SoundEvent.from_dict().
- class foley.agent.decompose.KeywordDecomposer[source]
Deterministic cue-lexicon decomposer — the zero-dependency default and CI fake.
Scans the passage against
_CUE_LEXICON, emits oneSoundEventper matched cue in first-appearance order (so salience descends with reading order), dedupes by canonical query, and truncates tomax_events(the sparse density budget). No RNG, no network, noanthropic— same passage → identical list.- decompose(context: str, *, max_events: int = 6, seconds: float | None = None) list[SoundEvent][source]
Return
<= max_eventsdeterministicSoundEvents forcontext.- Parameters:
context – The narrative passage.
max_events – The sparse density cap (the salience budget).
seconds – Accepted for signature parity (the per-second density window is a later refinement); ignored here.
- foley.agent.decompose.decompose_context(context: str, *, max_events: int = 6, seconds: float | None = None, decomposer: Decomposer | None = None, _span=None) list[SoundEvent][source]
Decompose a passage into
<= max_eventssparseSoundEvents.The pure SELECT tool (Python-API == agent == future-MCP surface): resolves the default decomposer when
decomposerisNone, calls it, and records the GenAI span on the real path (the fake’slast_responseisNone→ no-op).- Parameters:
context – The narrative passage.
max_events – The sparse density cap.
seconds – Optional passage duration (density-window hint; forwarded, else ignored).
decomposer – An injected
Decomposer(the DI seam); defaults to_default_decomposer()._span – Internal — the obs span handle
find()opens for GenAI recording.