feat: conversion-driven extensions — resolvers, DefineTool, hooks, ops controls
CI / Tidy (push) Successful in 9m31s
CI / Build & Test (push) Successful in 10m13s

Phase 9a (ADR-0014): Registry.RegisterResolver for dynamic tiers;
DefineTool[Args] typed tools; Usage cache/reasoning detail fields wired
through anthropic/openai/google; WithPromptCaching (Anthropic
cache_control); agent supervision hooks (WithMaxStepsFunc, WithSteer,
WithCompactor, WithToolErrorLimits + ErrToolLoop); health
Bench/Unbench/Snapshot; ChainConfig.Observer failover events.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 13:30:06 +02:00
parent 04b21fdad2
commit 0147a79d18
21 changed files with 767 additions and 29 deletions
+9
View File
@@ -91,10 +91,17 @@ func chainDo[T any](ctx context.Context, c *chain, req llm.Request, attempt func
var zero T
var failures []error
observe := func(ev FailoverEvent) {
if c.cfg.Observer != nil {
c.cfg.Observer(ev)
}
}
for _, t := range c.targets {
if !c.tracker.Available(t.key) {
until := c.tracker.BackedOffUntil(t.key)
failures = append(failures, fmt.Errorf("%s: skipped (backed off until %s)", t.key, until.Format("15:04:05.000")))
observe(FailoverEvent{Target: t.key, Skipped: true})
continue
}
@@ -119,6 +126,7 @@ func chainDo[T any](ctx context.Context, c *chain, req llm.Request, attempt func
class := c.cfg.classify(err)
if class == llm.ClassPermanent {
observe(FailoverEvent{Target: t.key, Err: err, Class: class, Attempt: attemptN})
if errors.Is(err, llm.ErrModelNotFound) || errors.Is(err, llm.ErrUnsupported) || c.cfg.AdvanceOnPermanent {
// Not a health problem (or policy says keep going):
// advance without penalizing the target.
@@ -134,6 +142,7 @@ func chainDo[T any](ctx context.Context, c *chain, req llm.Request, attempt func
// attempts remain — but advance as soon as the tracker benches
// it (a freshly backed-off target is not worth more retries).
benched := c.tracker.ReportFailure(t.key)
observe(FailoverEvent{Target: t.key, Err: err, Class: class, Attempt: attemptN, Benched: benched})
if !benched && attemptN < retries {
continue
}