feat(guardrails): context-aware flock slot — saturated calls give up instead of wedging (#28)

This commit is contained in:
Smokey committed 2026-10-28 06:46:15 -06:00
1 parent c957bdd3f6
commit acc09331b8
2 files changed
+36 -10

No files matched your search

+16 -2
View File
@@ -128,6 +128,17 @@ func (f *Flock) pick(nest Nest, n int) []string {
return out
}
// reserve takes a flock slot, honoring ctx: a saturated flock waits for a
// slot, but gives up when the context ends instead of wedging the caller.
func (f *Flock) reserve(ctx context.Context) (func(), bool) {
select {
case f.sem <- struct{}{}:
return func() { <-f.sem }, true
case <-ctx.Done():
return nil, false
}
}
// ask is the only way any crow touches the model: budget, flock cap, timeout, log.
func (f *Flock) ask(ctx context.Context, w Watcher, crow, system, prompt string, budgets ...*Budget) (string, error) {
for _, b := range budgets {
@@ -136,8 +147,11 @@ func (f *Flock) ask(ctx context.Context, w Watcher, crow, system, prompt string,
return "", err
}
}
f.sem <- struct{}{}
defer func() { <-f.sem }()
release, slot := f.reserve(ctx)
if !slot {
return "", fmt.Errorf("flock at cap: %w", ctx.Err())
}
defer release()
if w != nil {
w.Flying(crow)