From c039174124fd4678545c50be67e3a24e7a4fad97 Mon Sep 17 00:00:00 2001 From: thdxr <826656+thdxr@users.noreply.github.com> Date: Tue, 15 Sep 2026 04:29:37 +0000 Subject: [PATCH] fix(core): reuse models across credential switches Credential changes altered the provider snapshot even when the available provider definitions stayed identical. That forced every retained Location to rematerialize its full active model catalog. Reuse the snapshot when availability is unchanged, while preserving rebuilds for real provider and account-bound inventory changes. --- packages/core/src/provider.ts | 8 +++++++ packages/core/test/catalog.test.ts | 37 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/packages/core/src/provider.ts b/packages/core/src/provider.ts index f1bfe668aa66..85df8076c998 100644 --- a/packages/core/src/provider.ts +++ b/packages/core/src/provider.ts @@ -366,6 +366,14 @@ const layer = Layer.effect( if (integration?.connections.length) return true return record.provider.integrationID === undefined && !integration }) + if ( + cached?.records === records && + cached.value.available.length === available.length && + cached.value.available.every((record, index) => record === available[index]) + ) { + cached = { ...cached, access } + return cached.value + } const value = freeze({ records, available, providers: available.map((record) => record.provider) }, true) cached = { records, access, value } return value diff --git a/packages/core/test/catalog.test.ts b/packages/core/test/catalog.test.ts index 61fc7e75ff7a..d3fcc37b5dd9 100644 --- a/packages/core/test/catalog.test.ts +++ b/packages/core/test/catalog.test.ts @@ -148,6 +148,43 @@ describe("Provider and Model", () => { }).pipe(Effect.scoped, Effect.provide(localProviderLayer)) }) + it.effect("reuses materialized models when the active credential changes", () => + Effect.gen(function* () { + const providers = yield* Provider.Service + const models = yield* Model.Service + const integrations = yield* Integration.Service + const credentials = yield* Credential.Service + const providerID = Provider.ID.make("switchable") + const integrationID = Integration.ID.make(providerID) + yield* integrations.transform((editor) => editor.update(integrationID, () => {})) + yield* providers.transform((editor) => + editor.add({ + info: Provider.Info.empty(providerID), + models: Array.from({ length: 1_000 }, (_, index) => + Model.Info.default(providerID, Model.ID.make(`model-${index}`)), + ), + }), + ) + expect(yield* models.available()).toEqual([]) + + const first = yield* credentials.create({ + integrationID, + value: Credential.Key.make({ type: "key", key: "first" }), + }) + const materialized = yield* models.available() + expect(materialized).toHaveLength(1_000) + + yield* credentials.create({ + integrationID, + value: Credential.Key.make({ type: "key", key: "second" }), + }) + expect(yield* models.available()).toBe(materialized) + + yield* credentials.activate(first.id) + expect(yield* models.available()).toBe(materialized) + }), + ) + it.effect("derives availability from a provider's integration", () => { const integrationID = Integration.ID.make("gateway") const providerID = Provider.ID.make("remote")