Fix AI model registry staleness on self-hosted instances (#19427)
## Summary Fixes #19422. Self-hosted users hitting "No AI models are available" after configuring API keys via the admin panel were victims of a stale `AiModelRegistryService` cache. Only the four `addAiProvider` / `removeAiProvider` / `addModelToProvider` / `removeModelFromProvider` mutations called `refreshRegistry()` — setting an API key through `set/update/deleteDatabaseConfigVariable` left the registry pointing at the pre-mutation provider state. Rather than patch each mutation site (and re-introduce the same class of bug on the next one), the registry now invalidates lazily based on the LLM config-group hash, mirroring the pattern `WebSearchDriverFactory` already uses via `DriverFactoryBase`. Any mutation to an LLM-tagged config variable is picked up automatically on the next read — callers never have to remember to refresh. - Extracted `getConfigGroupHash` into a shared util reused by both `DriverFactoryBase` and `AiModelRegistryService` (and switched the hash to `JSON.stringify` so object-typed config vars like `AI_PROVIDERS` actually contribute meaningfully). - `AiModelRegistryService` gates all internal `Map` access behind private getters that call `ensureFresh()`, so future read paths can't accidentally observe stale state. Build path uses underscored backing fields directly to avoid recursing. - Dropped the now-redundant `refreshRegistry()` public method and its four call sites in `admin-panel.resolver.ts`. ## Test plan - [x] `nx typecheck twenty-server` passes - [x] Existing admin-panel + ai-models specs pass (79 tests) - [ ] Manual: on a self-hosted instance, set `OPENAI_API_KEY` (or another provider key) via the admin panel `setDatabaseConfigVariable` mutation and confirm AI features work without a server restart - [ ] Manual: existing flows (`addAiProvider`, `addModelToProvider`, etc.) still pick up new providers on the next read 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+4
-2
@@ -15,24 +15,26 @@ import { LogicFunctionResourceService } from 'src/engine/core-modules/logic-func
|
||||
import { SdkClientArchiveService } from 'src/engine/core-modules/sdk-client/sdk-client-archive.service';
|
||||
import { DriverFactoryBase } from 'src/engine/core-modules/twenty-config/dynamic-factory.base';
|
||||
import { ConfigVariablesGroup } from 'src/engine/core-modules/twenty-config/enums/config-variables-group.enum';
|
||||
import { ConfigGroupHashService } from 'src/engine/core-modules/twenty-config/services/config-group-hash.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
|
||||
@Injectable()
|
||||
export class LogicFunctionDriverFactory extends DriverFactoryBase<LogicFunctionDriver> {
|
||||
constructor(
|
||||
twentyConfigService: TwentyConfigService,
|
||||
configGroupHashService: ConfigGroupHashService,
|
||||
private readonly logicFunctionResourceService: LogicFunctionResourceService,
|
||||
private readonly sdkClientArchiveService: SdkClientArchiveService,
|
||||
private readonly cacheLockService: CacheLockService,
|
||||
) {
|
||||
super(twentyConfigService);
|
||||
super(twentyConfigService, configGroupHashService);
|
||||
}
|
||||
|
||||
protected buildConfigKey(): string {
|
||||
const driverType = this.twentyConfigService.get('LOGIC_FUNCTION_TYPE');
|
||||
|
||||
if (driverType === LogicFunctionDriverType.LAMBDA) {
|
||||
return `lambda|${this.getConfigGroupHash(ConfigVariablesGroup.LOGIC_FUNCTION_CONFIG)}`;
|
||||
return `lambda|${this.configGroupHashService.computeHash(ConfigVariablesGroup.LOGIC_FUNCTION_CONFIG)}`;
|
||||
}
|
||||
|
||||
return driverType;
|
||||
|
||||
Reference in New Issue
Block a user