The global provider bootstrap froze all three ModelRuntime mutation
methods after startup, so a provider extension that fetched an updated
model catalog had that work silently discarded.
registerProvider is now applied when the provider ID is already in the
frozen baseline and the incoming config equals the recorded baseline in
every field except `models`. Refreshing extensions re-send a complete
provider config rather than a models-only delta, so the test is
"equal except models", not "contains only models".
Everything else stays a logged no-op: unknown provider IDs, any change
to name/baseUrl/apiKey/api/streamSimple/headers/authHeader/oauth/
refreshModels, native registration, and unregistration. Function-valued
fields compare by reference and so always read as a mismatch, which is
the intended conservative direction.
An accepted update rebases the stored baseline from Pi's merged record,
so repeat refreshes work and an unchanged replay is correctly ignored
rather than re-applied on every session start. The accept path stays
synchronous and never awaits or networks; Pi's own trailing
fire-and-forget local refresh is untouched.
Relaxes the provider policy from 'global config only' to 'global sources':
providers registered by agent-dir (global) extensions are learned once at
daemon startup and allowed on the shared runtime; project-extension
registrations are still rejected with a session warning. Global extensions
load identically for every session, so their providers are daemon-consistent
and cannot leak project state (#76).
- Shim now allows allowlisted ids through and also covers Pi 0.81's native
provider path (registerNativeProvider), closing a bypass.
- Startup learning step loads only global extensions against a scratch cwd
and diffs the runtime's registered provider ids.
- Bumps @earendil-works/* dev/peer ranges to >=0.81.1 <0.82; adapts to the
Agent.streamFn -> streamFunction rename.
- Docs, changeset, unit and acceptance tests updated (global-extension allow
path, late re-registration a la pi-tensorx, native provider rule).
PI WEB only supports globally configured providers (Pi built-ins,
agent-dir models.json, environment credentials). A daemon-wide shim on
the shared ModelRuntime swallows extension registerProvider calls and
makes unregisterProvider a no-op, so one workspace's extensions can no
longer corrupt the provider set of concurrent sessions (issue #76).
Rejections during a services load surface as session warnings through
the existing diagnostics pipeline; late registrations from session
event handlers broadcast a notification to active sessions. Everything
else extensions register keeps working.
Requires manual restart of pi-web-sessiond.service (daemon wiring changed).