foley.agent.tools#
The SELECT orchestration: find() / plan() + the small pure tool wrappers.
This is the one seam that serves the Python API, the agent loop, and the future MCP
server (#12) — the same functions, three surfaces (report 05 §5.2). It OWNS every
side-effecting call (search → gate → verify → decide → generate →
place); decide() is a pure tail step that only branches.
find() opens one foley.obs.run('find') scope, so the nested
foley.search() / foley.generate() façade calls aggregate into a single
reproducible run-manifest (report 10 §1.3); each stage emits a typed
Step and each LLM rung a GenAI span. The plan it emits
is the sparse SoundDesignTimeline subset — WEAVE (#8) resolves
anchors, mix, and mastering.
import foley stays dol-only: foley.search / foley.generate and the
generation-error hierarchy are imported lazily inside the functions that call them.
Functions
|
An upper bound on what one |
|
The headline: a narrative context → verified, license-clean sound candidates. |
|
Generate a clip for |
|
Emit the SPARSE per-item plan subset ( |
|
Fold verified candidates into the SPARSE |
|
Hybrid search for one query, or a multi-query RRF-merge (the SELECT retrieval tool). |
- foley.agent.tools.estimate_find_usd(*, max_events=6, backend='auto', llm=None, k=10, verify='listen', max_refine_loops=1, max_generations=1, injected=None, context_chars=0)[source]#
An upper bound on what one
find()run can spend, orNoneif unknown.Every generation (
max_generationsper event throughbackend) plus every LLM call the default rungs could make: one decomposition,max_refine_loopsrefinements per event,kjudge calls per retrieval pass above theclaprung, and one re-verification per generation. Injected rungs are the caller’s to meter (their real calls are still checked one by one).
- foley.agent.tools.find(context, *, max_events=6, seconds=None, intended_use=None, backend='auto', verify='listen', stream=False, k=10, tau_retrieve=0.5, tau_clap=0.35, max_refine_loops=1, budget=None, library=None, decomposer=None, judge=None, refiner=None, llm=None)[source]#
The headline: a narrative context → verified, license-clean sound candidates.
decompose → (per event) refine/search → verify_match ladder → decide (with the fail-closed license gate FIRST) → place(report 05 §5). Works out of the box —foley.find("She pushed open the heavy oak door; rain hammered outside.")— with deterministic defaults; every model / threshold / seam is an optional keyword.- Parameters:
context (
str) – The narrative passage.max_events (
int) – The sparse density cap on decomposed events.seconds (
Optional[float]) – Optional passage duration (density-window hint; forwarded).intended_use (
Optional[IntendedUse]) – The caller’s rights intent (default:foley.licensing.DEFAULT_INTENDED_USE— commercial publishing; NC / SA material is refused unless you pass a different intent).backend (
str) – Generation backend for the fallback ('auto'→foley.generate’s default).verify (
Union[str,VerifyLevel]) – The max verify rung —'clap'|'listen'|'judge'.stream (
bool) – IfTrue, return a generator yielding oneCandidateper resolved event; else return the collectedlist.k (
int) – Retrieval shortlist depth per query.tau_retrieve (
float) – Confidence threshold to auto-accept a retrieved clip.tau_clap (
float) – Theclap-rung gate threshold.max_refine_loops (
int) – Max refine→re-retrieve passes per event (also the defaultBudget).budget (
Optional[Budget]) – An explicitBudget(overridesmax_refine_loops). It is also the run’s spend cap:Budget(max_usd=...)(default $1; $3 whenllm='anthropic'or$FOLEY_LLM=anthropic, whose default run is bounded at about $2.52 —foley.cost.DEFAULT_MAX_USD_BY_LLM) bounds every paid call the run makes — generations and paid LLM rungs — cumulatively, and a call of unknown cost needsBudget(approve_unknown_cost=True)(#57).library – Target
SoundLibrary(default: the process-wide default).refiner (decomposer / judge /) – Injected DI seams (
Decomposer/Judge/Refiner); each defaults to thellmprovider’s implementation.llm (
Optional[str]) – Which LLM the decompose / refine / judge rungs use when not injected —'fake'|'local'|'anthropic'.Nonereads$FOLEY_LLM, then falls back to the free default (a configured local endpoint, else the deterministic fake). A key being present never opts in to paid calls.
- Return type:
- Returns:
list[Candidate](stream=False) or anIterator[Candidate](stream=True) — one verified, license-clean candidate per resolved event.
- foley.agent.tools.generate_sound(query, *, backend='auto', library=None)[source]#
Generate a clip for
query(the fallback tool) — a thin wrapper overfoley.generate.Returns a
Candidate(origin=generated); raises theGenerationErrorhierarchy on refusal / no-result (caught fail-closed by_generate_and_reverify()).- Return type:
- foley.agent.tools.place_in_timeline(clip, *, onset=None, gain=0.0, layer=Layer.sfx_fg, loop=False)[source]#
Emit the SPARSE per-item plan subset (
clip_ref·onset·gain·layer·loop) — no more.onsetstays a SYMBOLIC anchor string (never a resolved offset); mix / processing / alignment / mastering are WEAVE’s (#8) job, not SELECT’s.- Return type:
- foley.agent.tools.plan(candidates, *, transcript=None)[source]#
Fold verified candidates into the SPARSE
SoundDesignTimeline(the SELECT→WEAVE bridge).One
TimelineItemper candidate (onset·gain·layer·looponly, from itsSoundEvent), joined to the run-artifact viarun_manifest_ref— the reserved #8plan_refslot is filled when called inside an activefoley.obsrun scope (None-safe otherwise).
- foley.agent.tools.search_sounds(queries, *, k=10, library=None, filters=None)[source]#
Hybrid search for one query, or a multi-query RRF-merge (the SELECT retrieval tool).
Delegates a single query VERBATIM to
SoundLibrary.search()(so the retrieval ranking the nDCG@10 gate measures is untouched); a multi-query list runs each query and RRF-merges (k=RRF_K) — the query-expansion recall lever, exercised only on a refine pass.- Parameters:
- Return type: