Local extension before_tool_call/after_tool_call hooks registered but
never fired after a scoped mid-run plugin activation (harness or memory
ensure) rebound the global hook runner to a narrow registry, dropping
hooks unique to the broader registry (#91918).
The runner is now created once and resolves hooks live on every dispatch
from the composed set of currently-live registries (the most recently
initialized registry, the active registry, and the pinned channel and
http-route surfaces) instead of freezing one registry. The loader's
one-shot preserve gate is removed since activation order no longer
matters. Per-plugin ownership prefers loaded records so a failed scoped
reload cannot shadow a healthy pinned registration (including a
fail-closed tool-call gate), and the explicitly initialized registry
stays highest precedence so SDK callers keep an authoritative registry.
Reuses the live-registry collector the agent-event bridge already uses
so both dispatch surfaces agree on what is live.
Treat refreshable manifest catalog rows as non-authoritative and load the owning plugin for runtime/cache-backed discovery. Adds focused regression coverage for entries-only and full discovery paths.
* fix: pin plugin workspace dir for sessions.list to avoid O(rows) memo busting
sessions.list was O(rows) slow under concurrent agent/cron load because
each row read a process-global active plugin-registry workspace dir
that was mutated by other turns between rows. The per-row memo key
changed every time, so loadPluginMetadataSnapshot scanned fresh
(~100ms per row).
Fix:
1. Add AsyncLocalStorage-based workspace dir pinning to
runtime-workspace-state.ts — withPinnedActivePluginRegistryWorkspaceDir()
snapshots the current workspace dir for the duration of a callback.
2. Wrap listSessionsFromStoreAsync body in the pin so all per-row
metadata lookups use a stable memo key.
Fixes#90814
* test(plugins): cover request-scoped workspace pins
* fix(plugins): pin canonical runtime workspace reads
* fix(plugins): preserve workspace pins across reloads
---------
Co-authored-by: lsr911 <lsr911@github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
* fix(ollama): repair retired cloud provider endpoint
Route configured Ollama Cloud provider ids through plugin doctor compatibility migrations so doctor --fix can rewrite the retired ai.ollama.com endpoint before runtime reads persisted config.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test(doctor): align provider fixture with typed config
Ensure the doctor registry provider-scoped migration test uses a fully typed provider fixture so the test type-check shard validates the intended behavior.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test(ollama): align doctor fixture with typed config
Use fully typed provider and model fixtures in the Ollama doctor contract tests so the extension test type-check shard validates the migration behavior.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(ollama): preserve custom cloud provider base url
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(ollama): avoid logging retired endpoint secrets
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Carry prepared manifest model-id normalization records through the runtime bridge so hot callers reuse existing metadata instead of consulting the snapshot fallback.
The final change preserves the existing no-prepared-record behavior, adds focused forwarding coverage, and removes the one-off proof script before landing.
Thanks @zeroaltitude.
Verification:
- 224 focused tests
- full CI run 27594070734
- real behavior proof run 27594081022
- final whole-branch autoreview clean
Co-authored-by: zeroaltitude <zeroaltitude@gmail.com>
Pinned session-extension registries now remain the owner even when empty, preventing later active registry churn from leaking agent-owned extensions into the gateway surface.