feat: conversion-driven extensions — resolvers, DefineTool, hooks, ops controls
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:
@@ -97,12 +97,23 @@ func (r *Registry) expand(spec string, visiting []string) ([]element, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Bare token: must be a registered alias.
|
||||
// Bare token: a registered alias, or a dynamic resolver hit.
|
||||
r.mu.RLock()
|
||||
target, isAlias := r.aliases[raw]
|
||||
_, isProvider := r.providers[raw]
|
||||
resolvers := slices.Clone(r.resolvers)
|
||||
r.mu.RUnlock()
|
||||
|
||||
if !isAlias {
|
||||
// Resolvers run without the lock — they may call back into the
|
||||
// registry (and DB-backed ones block on I/O).
|
||||
for _, res := range resolvers {
|
||||
if spec, ok := res.Resolve(raw); ok && spec != "" {
|
||||
target, isAlias = spec, true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !isAlias {
|
||||
if isProvider {
|
||||
return nil, fmt.Errorf("%q is a provider, not an alias — use %q", raw, raw+"/<model-id>")
|
||||
|
||||
Reference in New Issue
Block a user