foley.agent.policy#
The SELECT policy: the fail-closed rights gate + the single generate-vs-retrieve branch.
Two load-bearing invariants live here as two physically separate pure functions, so neither can bypass the other:
gate_candidates()— the ONLY rights-rejection point. Runs the fail-closedfoley.licensing.keep_sound()gate over the candidate set before anyverification/ranking (invariant #3), sets
Candidate.license_ok, and drops every non-Truecandidate.decide()— the ONLY generate-vs-retrieve branch. A pure function of an already-gated+verified set; it never callskeep/search/generate(thefoley.agent.toolsloop owns all side effects).
Budget bounds the refine→re-retrieve and generate loops so a hard event can’t
run away. This module is stdlib-only (imports only foley.base /
foley.licensing) and does no I/O and no obs — the loop emits the audit Steps.
Functions
|
The single generate-vs-retrieve branch — a PURE function (report 05 §4). |
|
Fail-closed license gate — run BEFORE verification/ranking (invariant #3). |
Classes
|
Bounded-cost accounting: per-event loop counts, and a cumulative dollar cap (#57). |
|
What |
|
The tiny result of |
- class foley.agent.policy.Budget(max_refine_loops=1, max_generations=1, allow_generate=True, max_usd=1.0, approve_unknown_cost=None, _refines=0, _gens=0, _spent_usd=0.0, _unknown_calls=0, _lock=<factory>)[source]#
Bases:
objectBounded-cost accounting: per-event loop counts, and a cumulative dollar cap (#57).
Two kinds of bound:
Per event —
max_refine_loops/max_generations: the loop callsrefine_ok()/gen_ok()to test, thenspend_refine()/spend_gen()to charge;reset()zeroes them at each event.Per run, cumulative —
max_usd(default $1): every paid call (generation, paid LLM rung) is checked withauthorize()before it is made and recorded withcharge()after.reset()never clears it, so the cap holds across the wholefind/scorerun. A call whose cost is unknown (estimateNone) is refused unlessapprove_unknown_cost(or$FOLEY_APPROVE_UNKNOWN_COST=1).
- authorize(estimate_usd, *, what)[source]#
Alias of
check()(kept for callers that only test affordability).- Return type:
- check(estimate_usd, *, what)[source]#
Raise if this run cannot afford
estimate_usd(nothing is reserved).- Return type:
- reserve(estimate_usd, *, what)[source]#
Check, then count
estimate_usdas spent at once (atomic under a lock).Reserving before the call is what keeps concurrent calls on one budget (MCP tools run in a threadpool) from all passing the check before any is charged.
settle()later replaces the reservation with the actual cost, if known.- Return type:
- reset()[source]#
Zero the spend counters so the caps apply per event, not per passage.
The
findloop calls this at the top of each event so one hard event’s refine/generate spend never starves later events (the documented per-event semantics).- Return type:
- class foley.agent.policy.DecideAction(*values)[source]#
-
What
decide()chose for one event (the single branch’s outcomes).
- class foley.agent.policy.Decision(action, candidate=None, reason='')[source]#
Bases:
objectThe tiny result of
decide();reasonfeeds the refine hint + the audit Step.
- foley.agent.policy.decide(event, kept, verified, *, tau_retrieve, budget, loop)[source]#
The single generate-vs-retrieve branch — a PURE function (report 05 §4).
Chooses among
DecideActionfrom the already-gated (kept) and already-verified (verified) sets. It performs no I/O and never callskeep/search/generate— thefoley.agent.toolsloop acts on the returnedDecision.Policy (report 05 §4):
a verified clip clearing
tau_retrieve→USE(the best one);verified-but-low-confidence with refine budget →
REFINE(feed the reason back);a non-diegetic cue, or a diegetic gap with no verified match, with generate budget →
GENERATE;otherwise →
DROP(silence), unless a lower-confidence verified clip exists and generation is off, in which case fall back to that best-effort pick.
- Parameters:
event (
SoundEvent) – The event being resolved.kept (
list[Candidate]) – The license-clean candidates (eachlicense_ok is True).verified (
list[Candidate]) – The subset ofkeptwhose verdict matched.tau_retrieve (
float) – The confidence threshold for auto-accepting a retrieved clip.budget (
Budget) – The per-event cost budget.loop (
int) – The current refine-loop index (for the audit reason).
- Return type:
- Returns:
A
Decision.
- foley.agent.policy.gate_candidates(candidates, intended_use)[source]#
Fail-closed license gate — run BEFORE verification/ranking (invariant #3).
For each candidate: apply
keep_sound()(any exception ⇒False, fail-closed), record the result oncandidate.license_ok, and keep ONLY where it isTrue— aNone(never gated) orFalseis dropped. This is the single rights-rejection point;verify_match()asserts its survivors are license-clean.- Parameters:
candidates (
list[Candidate]) – The retrieved shortlist (license_oktypicallyNone).intended_use (
IntendedUse) – The caller’s declared rights intent.
- Return type:
- Returns:
The license-clean sublist (each with
license_ok is True), order preserved.