Files
majordomo/docs/adr/0014-conversion-driven-extensions.md
steve 0147a79d18
CI / Tidy (push) Successful in 9m31s
CI / Build & Test (push) Successful in 10m13s
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>
2026-06-10 13:30:06 +02:00

2.6 KiB

ADR-0014: Conversion-driven extensions (resolvers, typed tools, hooks, ops controls)

Status: Accepted — 2026-06-10

Context

Executing the mort conversion (docs/mort-migration.md) surfaced seven capabilities mort's orchestration layer needs from its model substrate. Each is general-purpose — none encodes anything mort-specific — and each was promised in the migration blueprint.

Decision

  1. Registry.RegisterResolver — dynamic alias resolution for DB/ config-backed tiers. Checked after static aliases (static wins), in registration order, without holding the registry lock (resolvers do I/O); output expands recursively under the existing cycle guard.
  2. DefineTool[Args] — typed tools: parameters from SchemaFor[Args], arguments unmarshaled before the handler. Schema failure panics (startup-time programming error, mirroring NewToolbox).
  3. Usage detail fields — CacheReadTokens / CacheWriteTokens / ReasoningTokens, populated where providers report them (Anthropic cache fields; OpenAI prompt/completion detail objects; Google cached-content
    • thoughts). Input/Output remain totals; details are portions.
  4. WithPromptCaching — Anthropic top-level cache_control auto-placement; a no-op for providers that cache implicitly or not at all.
  5. Agent loop hooksWithMaxStepsFunc (dynamic ceiling, consulted every step, for supervisor budget adjustment), WithSteer (per-run message injection drained before each step), WithCompactor (pre-Generate transcript transformation; errors fall back to the original — losing a request to a broken summarizer is worse than a long prompt), WithToolErrorLimits (consecutive all-error steps and identical-call repeats end the run with ErrToolLoop + partial result). The canonical transcript in Result.Messages is always the uncompacted truth; compaction affects only what is sent.
  6. Manual health controlsTracker.Bench/Unbench/Snapshot for ops surfaces (".failover bench" commands, dashboards).
  7. ChainConfig.Observer — one synchronous callback per failover decision (failed attempt with classification, bench, benched-skip). This is a hook, not an observability stack; persistence/metrics remain the consumer's business (anti-creep guardrail intact).

Consequences

  • mort's tier resolver, .failover admin surface, failover-event log, run-critic budget control, steering, and compaction all rebase onto public API.
  • The agent loop gains supervision points without changing its never-panic, partial-result-on-error contract.