feat: add unload on_agent_switch builtin hook#2684
Merged
dgageot merged 2 commits intodocker:mainfrom May 7, 2026
Merged
Conversation
Member
|
There are a lot of unrelated changes in this PR and a lot of conflicts |
74a73aa to
e1322e2
Compare
e1322e2 to
09de0a9
Compare
rumpl
approved these changes
May 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Re-implementation of #2660 as a builtin hook instead of explicit runtime calls. Opened to compare the two designs side by side.
What
Adds an
unloadon_agent_switch builtin hook that asks every model on the previous agent to release its resources when the runtime hands control to another agent. Today only Docker Model Runner ships aprovider.Unloader; everything else is silently skipped, so wiring the hook on a cross-provider chain is harmless.Opt in via the standard hook YAML — no new flag, no auto-injection:
DMR's
_unloadURL is derived frombase_url(replacing the trailing/v1); a per-providerunload_apifield overrides it for non-standard deployments. Errors are logged and swallowed, each call is bounded to 10 s — agent switching never blocks on a slow or unreachable engine.How it compares to #2660
r.unloadOnSwitch(...)calls inagent_delegation.goandruntime.goon_agent_switchmachinerycache_response,redact_secrets, … in the schema and docson_agent_switchhooksprovider,dmr,openai,baseprovider,dmrThe single trade-off vs. #2660:
LocalRuntime.SetCurrentAgent(the TUI agent picker) doesn't currently fireon_agent_switchhooks, so the hook-based version doesn't cover that path. Closing the gap is a one-line change inSetCurrentAgentthat benefits every other on-switch hook too — happy to do it as a follow-up if we go with this approach.Files
Feature
pkg/model/provider/provider.go—Unloaderinterfacepkg/model/provider/dmr/unload.go(+ tests) — DMRUnload, default URL derivation, override resolution, HTTP POSTpkg/model/provider/defaults.go— plumbunload_apifromProviderConfiginto the model'sprovider_optspkg/config/latest/types.go(+ tests) —ProviderConfig.UnloadAPIfield,ModelConfig.UnloadAPI()accessorpkg/runtime/unload.go(+ tests) —BuiltinUnloadconst + the closure registered onLocalRuntimepkg/runtime/runtime.go— registration inNewLocalRuntimeSchema, docs, example
agent-schema.json—unload_apifield,unloadbuiltin in the command-list blurbdocs/configuration/hooks/index.md— built-ins table row + on_agent_switch sectiondocs/providers/dmr/index.md— "Unloading models on agent switch" section, single-tenant warning calloutdocs/providers/custom/index.md—unload_apirow in the provider properties tableexamples/unload_on_switch.yaml(+examples/README.mdrow)Other things in this branch
The third commit (
fix lint: …) cleans up 29 pre-existing lint offences that were sitting in the tree (3govet/inline, 20modernize/slicesbackward, 6Lint/SlogContextual). I noticed them while runningtask lintagainst my changes and fixed them in a separate commit — happy to split into a separate PR if preferred.One thing worth flagging:
golangci-lint --fixrewrotetruncateOldToolContentinpkg/session/session.gofromfor i := ...; i--tofor _, v := range slices.Backward(...)and changedmsg := &result[i]tomsg := &v. The latter points to the loop-local copy, somsg.Content = …was silently mutating the copy and the function no longer truncated anything. I corrected it tofor i := range slices.Backward(result) { msg := &result[i] }. Worth being aware of when running--fixelsewhere.Validation
task build✅task test✅ (full suite)task lint✅ — 0 offences (tree was at 29 before)unload_apiplumbing through provider-config merge.