Renamed the inherited pi-ai ModelsStreamTransforms interface to ModelsRequestTransforms because its header transformation now applies to all authenticated provider requests.
Changed JSON and RPC message_update events to emit only assistantMessageEvent deltas, removing the cumulative message and assistantMessageEvent.partial fields that caused quadratic output growth. Clients that need partial messages must assemble deltas between message_start and message_end; the latter remains authoritative (#7290).
ModelRegistry.getApiKeyAndHeaders() now returns ProviderHeaders with string | null values and preserves null header-deletion markers. Extensions that inspect returned headers must handle null; extensions forwarding them to pi-ai streams should pass them through unchanged. This prevents placeholder OpenAI credentials from being sent through Cloudflare AI Gateway (#7030).
Changed ModelRegistry.refresh() to accept ModelsRefreshOptions and return ModelsRefreshResult instead of discarding cancellation and provider errors.
Changed ModelRuntime.setRuntimeApiKey() to accept auth cancellation options rather than catalog refresh options. Call refresh({ providers: [providerId], signal }) separately when remote freshness is required.
Required config-form extension OAuth refreshToken(credentials, signal) callbacks to accept and honor a concrete abort signal.
Replaced dynamic provider refresh context store access with the read-only context.stored snapshot and generation-checked context.publish() transaction.
Providers built with createProvider({ fetchModels }): no catalog-publication migration is required. Before and after, return the fetched models and register the resulting provider; createProvider() owns restoration, persistence, and in-memory publication.
// Before
const beforeProvider = createProvider({
// ...
fetchModels: async ({ signal }) => {
const response = await fetch(catalogUrl, { signal });
return parseModels(await response.json());
},
});
pi.registerProvider(beforeProvider);
// After: unchanged
const afterProvider = createProvider({
// ...
fetchModels: async ({ signal }) => {
const response = await fetch(catalogUrl, { signal });
return parseModels(await response.json());
},
});
pi.registerProvider(afterProvider);
Handwritten native Provider.refreshModels(): replace direct store access and pre-publication mutation with generation-guarded publications.
// Before
refreshModels: async (context) => {
const stored = await context.store.read();
if (stored) currentModels = stored.models;
if (!context.allowNetwork) return;
const refreshed = await fetchModels(context.signal);
currentModels = refreshed;
await context.store.write({ models: refreshed, checkedAt: Date.now() });
},
// After
refreshModels: async (context) => {
if (context.stored) {
const restored = context.stored.models;
if (!(await context.publish({
update: () => { currentModels = restored; },
}))) return;
}
if (!context.allowNetwork) return;
const refreshed = await fetchModels(context.signal);
if (context.signal.aborted) return;
await context.publish({
persist: { models: refreshed, checkedAt: Date.now() },
update: () => { currentModels = refreshed; },
});
},
For the config-form pi.registerProvider(name, { refreshModels }), callbacks that only return models remain unchanged; pi publishes the returned list. If such a callback previously used context.store for custom persistence, read context.stored and call context.publish({ persist: entry }). In publish(), omit persist to leave storage unchanged, pass a ModelsStoreEntry to write it, or pass persist: null to delete it.
Replaced the inherited pi-agent-core harness session model with the v4 lane-based Session, SessionStorage, and SessionRepo APIs, including durable operation records, global facts, shared sequence numbers, and tree-scoped lane views.
Promoted the inherited v2 session and AgentHarness API from pi-agent-core's experimental entrypoint to its default export and removed the experimental subpaths.
Removed the inherited legacy JSONL and in-memory repository APIs. Use pi-agent-core's v4 JsonlSessionRepo or InMemorySessionRepo, both implementing the new SessionRepo contract.
Added the inherited required pi-agent-core FileSystem.renameFile() operation for atomic JSONL publication; custom harness file-system implementations must provide same-filesystem replacement semantics (#7707 by @davidbrai).
Replaced experimental remote-session list summaries with durable SessionMetadata; RemoteSession.sessions no longer exposes runtime phase, model, thinking, attachment, or lock state, which remains available from acquired SessionSnapshot values (#7708).