libre-webui 0.21.2 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +308 -328
- package/backend/dist/cli/migrateSqliteToPostgres.d.ts +2 -0
- package/backend/dist/cli/migrateSqliteToPostgres.d.ts.map +1 -0
- package/backend/dist/cli/migrateSqliteToPostgres.js +113 -0
- package/backend/dist/cli/migrateSqliteToPostgres.js.map +1 -0
- package/backend/dist/cli/recoveryBackup.d.ts +3 -0
- package/backend/dist/cli/recoveryBackup.d.ts.map +1 -0
- package/backend/dist/cli/recoveryBackup.js +251 -0
- package/backend/dist/cli/recoveryBackup.js.map +1 -0
- package/backend/dist/cli/recoveryInventory.d.ts +2 -0
- package/backend/dist/cli/recoveryInventory.d.ts.map +1 -0
- package/backend/dist/cli/recoveryInventory.js +109 -0
- package/backend/dist/cli/recoveryInventory.js.map +1 -0
- package/backend/dist/db.d.ts +27 -0
- package/backend/dist/db.d.ts.map +1 -1
- package/backend/dist/db.js +333 -16
- package/backend/dist/db.js.map +1 -1
- package/backend/dist/env.d.ts.map +1 -1
- package/backend/dist/env.js +12 -2
- package/backend/dist/env.js.map +1 -1
- package/backend/dist/index.d.ts.map +1 -1
- package/backend/dist/index.js +235 -47
- package/backend/dist/index.js.map +1 -1
- package/backend/dist/main.d.ts +2 -0
- package/backend/dist/main.d.ts.map +1 -0
- package/backend/dist/main.js +137 -0
- package/backend/dist/main.js.map +1 -0
- package/backend/dist/middleware/auth.d.ts.map +1 -1
- package/backend/dist/middleware/auth.js +7 -3
- package/backend/dist/middleware/auth.js.map +1 -1
- package/backend/dist/middleware/chatCancellationAdmission.d.ts +7 -0
- package/backend/dist/middleware/chatCancellationAdmission.d.ts.map +1 -0
- package/backend/dist/middleware/chatCancellationAdmission.js +17 -0
- package/backend/dist/middleware/chatCancellationAdmission.js.map +1 -0
- package/backend/dist/middleware/coordinatedRateLimit.d.ts +18 -0
- package/backend/dist/middleware/coordinatedRateLimit.d.ts.map +1 -0
- package/backend/dist/middleware/coordinatedRateLimit.js +52 -0
- package/backend/dist/middleware/coordinatedRateLimit.js.map +1 -0
- package/backend/dist/middleware/sharedRateLimit.d.ts +26 -0
- package/backend/dist/middleware/sharedRateLimit.d.ts.map +1 -0
- package/backend/dist/middleware/sharedRateLimit.js +99 -0
- package/backend/dist/middleware/sharedRateLimit.js.map +1 -0
- package/backend/dist/models/personaModel.d.ts +1 -26
- package/backend/dist/models/personaModel.d.ts.map +1 -1
- package/backend/dist/models/personaModel.js +54 -247
- package/backend/dist/models/personaModel.js.map +1 -1
- package/backend/dist/models/userModel.d.ts +23 -66
- package/backend/dist/models/userModel.d.ts.map +1 -1
- package/backend/dist/models/userModel.js +110 -187
- package/backend/dist/models/userModel.js.map +1 -1
- package/backend/dist/persistence/chatGenerationTypes.d.ts +24 -0
- package/backend/dist/persistence/chatGenerationTypes.d.ts.map +1 -0
- package/backend/dist/persistence/chatGenerationTypes.js +7 -0
- package/backend/dist/persistence/chatGenerationTypes.js.map +1 -0
- package/backend/dist/persistence/extensionTypes.d.ts +185 -0
- package/backend/dist/persistence/extensionTypes.d.ts.map +1 -0
- package/backend/dist/persistence/extensionTypes.js +13 -0
- package/backend/dist/persistence/extensionTypes.js.map +1 -0
- package/backend/dist/persistence/identityDeletionTypes.d.ts +16 -0
- package/backend/dist/persistence/identityDeletionTypes.d.ts.map +1 -0
- package/backend/dist/persistence/identityDeletionTypes.js +7 -0
- package/backend/dist/persistence/identityDeletionTypes.js.map +1 -0
- package/backend/dist/persistence/index.d.ts +48 -0
- package/backend/dist/persistence/index.d.ts.map +1 -0
- package/backend/dist/persistence/index.js +159 -0
- package/backend/dist/persistence/index.js.map +1 -0
- package/backend/dist/persistence/postgresConfig.d.ts +32 -0
- package/backend/dist/persistence/postgresConfig.d.ts.map +1 -0
- package/backend/dist/persistence/postgresConfig.js +91 -0
- package/backend/dist/persistence/postgresConfig.js.map +1 -0
- package/backend/dist/persistence/postgresCoreMigration.d.ts +8 -0
- package/backend/dist/persistence/postgresCoreMigration.d.ts.map +1 -0
- package/backend/dist/persistence/postgresCoreMigration.js +179 -0
- package/backend/dist/persistence/postgresCoreMigration.js.map +1 -0
- package/backend/dist/persistence/postgresDatabase.d.ts +40 -0
- package/backend/dist/persistence/postgresDatabase.d.ts.map +1 -0
- package/backend/dist/persistence/postgresDatabase.js +148 -0
- package/backend/dist/persistence/postgresDatabase.js.map +1 -0
- package/backend/dist/persistence/postgresExtensionMigration.d.ts +4 -0
- package/backend/dist/persistence/postgresExtensionMigration.d.ts.map +1 -0
- package/backend/dist/persistence/postgresExtensionMigration.js +143 -0
- package/backend/dist/persistence/postgresExtensionMigration.js.map +1 -0
- package/backend/dist/persistence/postgresExtensionRepositories.d.ts +6 -0
- package/backend/dist/persistence/postgresExtensionRepositories.d.ts.map +1 -0
- package/backend/dist/persistence/postgresExtensionRepositories.js +550 -0
- package/backend/dist/persistence/postgresExtensionRepositories.js.map +1 -0
- package/backend/dist/persistence/postgresImportState.d.ts +9 -0
- package/backend/dist/persistence/postgresImportState.d.ts.map +1 -0
- package/backend/dist/persistence/postgresImportState.js +64 -0
- package/backend/dist/persistence/postgresImportState.js.map +1 -0
- package/backend/dist/persistence/postgresMigrationRegistry.d.ts +4 -0
- package/backend/dist/persistence/postgresMigrationRegistry.d.ts.map +1 -0
- package/backend/dist/persistence/postgresMigrationRegistry.js +33 -0
- package/backend/dist/persistence/postgresMigrationRegistry.js.map +1 -0
- package/backend/dist/persistence/postgresMigrationTypes.d.ts +24 -0
- package/backend/dist/persistence/postgresMigrationTypes.d.ts.map +1 -0
- package/backend/dist/persistence/postgresMigrationTypes.js +7 -0
- package/backend/dist/persistence/postgresMigrationTypes.js.map +1 -0
- package/backend/dist/persistence/postgresMigrations.d.ts +15 -0
- package/backend/dist/persistence/postgresMigrations.d.ts.map +1 -0
- package/backend/dist/persistence/postgresMigrations.js +333 -0
- package/backend/dist/persistence/postgresMigrations.js.map +1 -0
- package/backend/dist/persistence/postgresPersistence.d.ts +17 -0
- package/backend/dist/persistence/postgresPersistence.d.ts.map +1 -0
- package/backend/dist/persistence/postgresPersistence.js +332 -0
- package/backend/dist/persistence/postgresPersistence.js.map +1 -0
- package/backend/dist/persistence/postgresPluginDefinitionMigration.d.ts +4 -0
- package/backend/dist/persistence/postgresPluginDefinitionMigration.d.ts.map +1 -0
- package/backend/dist/persistence/postgresPluginDefinitionMigration.js +40 -0
- package/backend/dist/persistence/postgresPluginDefinitionMigration.js.map +1 -0
- package/backend/dist/persistence/postgresResourceRepositories.d.ts +7 -0
- package/backend/dist/persistence/postgresResourceRepositories.d.ts.map +1 -0
- package/backend/dist/persistence/postgresResourceRepositories.js +776 -0
- package/backend/dist/persistence/postgresResourceRepositories.js.map +1 -0
- package/backend/dist/persistence/postgresSchemaInspector.d.ts +14 -0
- package/backend/dist/persistence/postgresSchemaInspector.d.ts.map +1 -0
- package/backend/dist/persistence/postgresSchemaInspector.js +817 -0
- package/backend/dist/persistence/postgresSchemaInspector.js.map +1 -0
- package/backend/dist/persistence/resourceTypes.d.ts +207 -0
- package/backend/dist/persistence/resourceTypes.d.ts.map +1 -0
- package/backend/dist/persistence/resourceTypes.js +38 -0
- package/backend/dist/persistence/resourceTypes.js.map +1 -0
- package/backend/dist/persistence/sqliteExtensionRepositories.d.ts +4 -0
- package/backend/dist/persistence/sqliteExtensionRepositories.d.ts.map +1 -0
- package/backend/dist/persistence/sqliteExtensionRepositories.js +494 -0
- package/backend/dist/persistence/sqliteExtensionRepositories.js.map +1 -0
- package/backend/dist/persistence/sqliteMigrations.d.ts +93 -0
- package/backend/dist/persistence/sqliteMigrations.d.ts.map +1 -0
- package/backend/dist/persistence/sqliteMigrations.js +2232 -0
- package/backend/dist/persistence/sqliteMigrations.js.map +1 -0
- package/backend/dist/persistence/sqlitePersistence.d.ts +23 -0
- package/backend/dist/persistence/sqlitePersistence.d.ts.map +1 -0
- package/backend/dist/persistence/sqlitePersistence.js +596 -0
- package/backend/dist/persistence/sqlitePersistence.js.map +1 -0
- package/backend/dist/persistence/sqliteResourceRepositories.d.ts +4 -0
- package/backend/dist/persistence/sqliteResourceRepositories.d.ts.map +1 -0
- package/backend/dist/persistence/sqliteResourceRepositories.js +663 -0
- package/backend/dist/persistence/sqliteResourceRepositories.js.map +1 -0
- package/backend/dist/persistence/sqliteSyncExecutor.d.ts +5 -0
- package/backend/dist/persistence/sqliteSyncExecutor.d.ts.map +1 -0
- package/backend/dist/persistence/sqliteSyncExecutor.js +19 -0
- package/backend/dist/persistence/sqliteSyncExecutor.js.map +1 -0
- package/backend/dist/persistence/sqliteToPostgresMigration.d.ts +80 -0
- package/backend/dist/persistence/sqliteToPostgresMigration.d.ts.map +1 -0
- package/backend/dist/persistence/sqliteToPostgresMigration.js +1543 -0
- package/backend/dist/persistence/sqliteToPostgresMigration.js.map +1 -0
- package/backend/dist/persistence/types.d.ts +131 -0
- package/backend/dist/persistence/types.d.ts.map +1 -0
- package/backend/dist/persistence/types.js +18 -0
- package/backend/dist/persistence/types.js.map +1 -0
- package/backend/dist/persistence/voiceProfileNameLookup.d.ts +9 -0
- package/backend/dist/persistence/voiceProfileNameLookup.d.ts.map +1 -0
- package/backend/dist/persistence/voiceProfileNameLookup.js +15 -0
- package/backend/dist/persistence/voiceProfileNameLookup.js.map +1 -0
- package/backend/dist/platform/coordination/index.d.ts +7 -0
- package/backend/dist/platform/coordination/index.d.ts.map +1 -0
- package/backend/dist/platform/coordination/index.js +24 -0
- package/backend/dist/platform/coordination/index.js.map +1 -0
- package/backend/dist/platform/coordination/localCoordinator.d.ts +49 -0
- package/backend/dist/platform/coordination/localCoordinator.d.ts.map +1 -0
- package/backend/dist/platform/coordination/localCoordinator.js +380 -0
- package/backend/dist/platform/coordination/localCoordinator.js.map +1 -0
- package/backend/dist/platform/coordination/redisCoordinator.d.ts +83 -0
- package/backend/dist/platform/coordination/redisCoordinator.d.ts.map +1 -0
- package/backend/dist/platform/coordination/redisCoordinator.js +726 -0
- package/backend/dist/platform/coordination/redisCoordinator.js.map +1 -0
- package/backend/dist/platform/coordination/service.d.ts +11 -0
- package/backend/dist/platform/coordination/service.d.ts.map +1 -0
- package/backend/dist/platform/coordination/service.js +55 -0
- package/backend/dist/platform/coordination/service.js.map +1 -0
- package/backend/dist/platform/coordination/sharedAdmission.d.ts +53 -0
- package/backend/dist/platform/coordination/sharedAdmission.d.ts.map +1 -0
- package/backend/dist/platform/coordination/sharedAdmission.js +194 -0
- package/backend/dist/platform/coordination/sharedAdmission.js.map +1 -0
- package/backend/dist/platform/coordination/types.d.ts +76 -0
- package/backend/dist/platform/coordination/types.d.ts.map +1 -0
- package/backend/dist/platform/coordination/types.js +32 -0
- package/backend/dist/platform/coordination/types.js.map +1 -0
- package/backend/dist/platform/events/durableEventGateway.d.ts +54 -0
- package/backend/dist/platform/events/durableEventGateway.d.ts.map +1 -0
- package/backend/dist/platform/events/durableEventGateway.js +262 -0
- package/backend/dist/platform/events/durableEventGateway.js.map +1 -0
- package/backend/dist/platform/events/index.d.ts +3 -0
- package/backend/dist/platform/events/index.d.ts.map +1 -0
- package/backend/dist/platform/events/index.js +8 -0
- package/backend/dist/platform/events/index.js.map +1 -0
- package/backend/dist/platform/events/service.d.ts +8 -0
- package/backend/dist/platform/events/service.d.ts.map +1 -0
- package/backend/dist/platform/events/service.js +25 -0
- package/backend/dist/platform/events/service.js.map +1 -0
- package/backend/dist/platform/jobs/chatGenerationEnqueuer.d.ts +3 -0
- package/backend/dist/platform/jobs/chatGenerationEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/chatGenerationEnqueuer.js +55 -0
- package/backend/dist/platform/jobs/chatGenerationEnqueuer.js.map +1 -0
- package/backend/dist/platform/jobs/documentIngestionEnqueuer.d.ts +3 -0
- package/backend/dist/platform/jobs/documentIngestionEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/documentIngestionEnqueuer.js +38 -0
- package/backend/dist/platform/jobs/documentIngestionEnqueuer.js.map +1 -0
- package/backend/dist/platform/jobs/domainJobContracts.d.ts +30 -0
- package/backend/dist/platform/jobs/domainJobContracts.d.ts.map +1 -0
- package/backend/dist/platform/jobs/domainJobContracts.js +53 -0
- package/backend/dist/platform/jobs/domainJobContracts.js.map +1 -0
- package/backend/dist/platform/jobs/domainJobHandlers.d.ts +11 -0
- package/backend/dist/platform/jobs/domainJobHandlers.d.ts.map +1 -0
- package/backend/dist/platform/jobs/domainJobHandlers.js +612 -0
- package/backend/dist/platform/jobs/domainJobHandlers.js.map +1 -0
- package/backend/dist/platform/jobs/durableEventIdentity.d.ts +8 -0
- package/backend/dist/platform/jobs/durableEventIdentity.d.ts.map +1 -0
- package/backend/dist/platform/jobs/durableEventIdentity.js +33 -0
- package/backend/dist/platform/jobs/durableEventIdentity.js.map +1 -0
- package/backend/dist/platform/jobs/durableJobRuntime.d.ts +57 -0
- package/backend/dist/platform/jobs/durableJobRuntime.d.ts.map +1 -0
- package/backend/dist/platform/jobs/durableJobRuntime.js +131 -0
- package/backend/dist/platform/jobs/durableJobRuntime.js.map +1 -0
- package/backend/dist/platform/jobs/durableJobRuntimeBackend.d.ts +28 -0
- package/backend/dist/platform/jobs/durableJobRuntimeBackend.d.ts.map +1 -0
- package/backend/dist/platform/jobs/durableJobRuntimeBackend.js +62 -0
- package/backend/dist/platform/jobs/durableJobRuntimeBackend.js.map +1 -0
- package/backend/dist/platform/jobs/durableJobService.d.ts +85 -0
- package/backend/dist/platform/jobs/durableJobService.d.ts.map +1 -0
- package/backend/dist/platform/jobs/durableJobService.js +726 -0
- package/backend/dist/platform/jobs/durableJobService.js.map +1 -0
- package/backend/dist/platform/jobs/durableJobTypes.d.ts +195 -0
- package/backend/dist/platform/jobs/durableJobTypes.d.ts.map +1 -0
- package/backend/dist/platform/jobs/durableJobTypes.js +72 -0
- package/backend/dist/platform/jobs/durableJobTypes.js.map +1 -0
- package/backend/dist/platform/jobs/embeddedDurableJobWorker.d.ts +87 -0
- package/backend/dist/platform/jobs/embeddedDurableJobWorker.d.ts.map +1 -0
- package/backend/dist/platform/jobs/embeddedDurableJobWorker.js +429 -0
- package/backend/dist/platform/jobs/embeddedDurableJobWorker.js.map +1 -0
- package/backend/dist/platform/jobs/identityDeletionEnqueuer.d.ts +3 -0
- package/backend/dist/platform/jobs/identityDeletionEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/identityDeletionEnqueuer.js +36 -0
- package/backend/dist/platform/jobs/identityDeletionEnqueuer.js.map +1 -0
- package/backend/dist/platform/jobs/index.d.ts +18 -0
- package/backend/dist/platform/jobs/index.d.ts.map +1 -0
- package/backend/dist/platform/jobs/index.js +34 -0
- package/backend/dist/platform/jobs/index.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.d.ts +4 -0
- package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.js +25 -0
- package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.d.ts +4 -0
- package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.js +23 -0
- package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobMigration.d.ts +11 -0
- package/backend/dist/platform/jobs/postgresDurableJobMigration.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobMigration.js +106 -0
- package/backend/dist/platform/jobs/postgresDurableJobMigration.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobRepository.d.ts +88 -0
- package/backend/dist/platform/jobs/postgresDurableJobRepository.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobRepository.js +1185 -0
- package/backend/dist/platform/jobs/postgresDurableJobRepository.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobService.d.ts +86 -0
- package/backend/dist/platform/jobs/postgresDurableJobService.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobService.js +696 -0
- package/backend/dist/platform/jobs/postgresDurableJobService.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobWorker.d.ts +53 -0
- package/backend/dist/platform/jobs/postgresDurableJobWorker.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobWorker.js +393 -0
- package/backend/dist/platform/jobs/postgresDurableJobWorker.js.map +1 -0
- package/backend/dist/platform/jobs/resourceDeletionEnqueuer.d.ts +3 -0
- package/backend/dist/platform/jobs/resourceDeletionEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/resourceDeletionEnqueuer.js +43 -0
- package/backend/dist/platform/jobs/resourceDeletionEnqueuer.js.map +1 -0
- package/backend/dist/platform/jobs/sqliteDurableJobRepository.d.ts +166 -0
- package/backend/dist/platform/jobs/sqliteDurableJobRepository.d.ts.map +1 -0
- package/backend/dist/platform/jobs/sqliteDurableJobRepository.js +1008 -0
- package/backend/dist/platform/jobs/sqliteDurableJobRepository.js.map +1 -0
- package/backend/dist/platform/jobs/videoGenerationEnqueuer.d.ts +4 -0
- package/backend/dist/platform/jobs/videoGenerationEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/videoGenerationEnqueuer.js +46 -0
- package/backend/dist/platform/jobs/videoGenerationEnqueuer.js.map +1 -0
- package/backend/dist/platform/jobs/workExecutionEnqueuer.d.ts +3 -0
- package/backend/dist/platform/jobs/workExecutionEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/workExecutionEnqueuer.js +38 -0
- package/backend/dist/platform/jobs/workExecutionEnqueuer.js.map +1 -0
- package/backend/dist/platform/ollamaRuntimeConfig.d.ts +40 -0
- package/backend/dist/platform/ollamaRuntimeConfig.d.ts.map +1 -0
- package/backend/dist/platform/ollamaRuntimeConfig.js +72 -0
- package/backend/dist/platform/ollamaRuntimeConfig.js.map +1 -0
- package/backend/dist/platform/recovery/backupArchive.d.ts +120 -0
- package/backend/dist/platform/recovery/backupArchive.d.ts.map +1 -0
- package/backend/dist/platform/recovery/backupArchive.js +842 -0
- package/backend/dist/platform/recovery/backupArchive.js.map +1 -0
- package/backend/dist/platform/recovery/index.d.ts +3 -0
- package/backend/dist/platform/recovery/index.d.ts.map +1 -0
- package/backend/dist/platform/recovery/index.js +8 -0
- package/backend/dist/platform/recovery/index.js.map +1 -0
- package/backend/dist/platform/recovery/teamBackupArchive.d.ts +98 -0
- package/backend/dist/platform/recovery/teamBackupArchive.d.ts.map +1 -0
- package/backend/dist/platform/recovery/teamBackupArchive.js +1203 -0
- package/backend/dist/platform/recovery/teamBackupArchive.js.map +1 -0
- package/backend/dist/platform/runtimeConfig.d.ts +70 -0
- package/backend/dist/platform/runtimeConfig.d.ts.map +1 -0
- package/backend/dist/platform/runtimeConfig.js +205 -0
- package/backend/dist/platform/runtimeConfig.js.map +1 -0
- package/backend/dist/platform/storage/aesGcmKeyring.d.ts +26 -0
- package/backend/dist/platform/storage/aesGcmKeyring.d.ts.map +1 -0
- package/backend/dist/platform/storage/aesGcmKeyring.js +135 -0
- package/backend/dist/platform/storage/aesGcmKeyring.js.map +1 -0
- package/backend/dist/platform/storage/blobReferenceRepository.d.ts +36 -0
- package/backend/dist/platform/storage/blobReferenceRepository.d.ts.map +1 -0
- package/backend/dist/platform/storage/blobReferenceRepository.js +117 -0
- package/backend/dist/platform/storage/blobReferenceRepository.js.map +1 -0
- package/backend/dist/platform/storage/blobStore.d.ts +111 -0
- package/backend/dist/platform/storage/blobStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/blobStore.js +46 -0
- package/backend/dist/platform/storage/blobStore.js.map +1 -0
- package/backend/dist/platform/storage/documentVectorIndex.d.ts +44 -0
- package/backend/dist/platform/storage/documentVectorIndex.d.ts.map +1 -0
- package/backend/dist/platform/storage/documentVectorIndex.js +110 -0
- package/backend/dist/platform/storage/documentVectorIndex.js.map +1 -0
- package/backend/dist/platform/storage/durableBlobQuotaPolicy.d.ts +82 -0
- package/backend/dist/platform/storage/durableBlobQuotaPolicy.d.ts.map +1 -0
- package/backend/dist/platform/storage/durableBlobQuotaPolicy.js +583 -0
- package/backend/dist/platform/storage/durableBlobQuotaPolicy.js.map +1 -0
- package/backend/dist/platform/storage/index.d.ts +19 -0
- package/backend/dist/platform/storage/index.d.ts.map +1 -0
- package/backend/dist/platform/storage/index.js +35 -0
- package/backend/dist/platform/storage/index.js.map +1 -0
- package/backend/dist/platform/storage/localEncryptedBlobStore.d.ts +120 -0
- package/backend/dist/platform/storage/localEncryptedBlobStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/localEncryptedBlobStore.js +1205 -0
- package/backend/dist/platform/storage/localEncryptedBlobStore.js.map +1 -0
- package/backend/dist/platform/storage/personaMemoryIndexing.d.ts +12 -0
- package/backend/dist/platform/storage/personaMemoryIndexing.d.ts.map +1 -0
- package/backend/dist/platform/storage/personaMemoryIndexing.js +25 -0
- package/backend/dist/platform/storage/personaMemoryIndexing.js.map +1 -0
- package/backend/dist/platform/storage/pgVectorStore.d.ts +37 -0
- package/backend/dist/platform/storage/pgVectorStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/pgVectorStore.js +493 -0
- package/backend/dist/platform/storage/pgVectorStore.js.map +1 -0
- package/backend/dist/platform/storage/platformDomainRepositories.d.ts +244 -0
- package/backend/dist/platform/storage/platformDomainRepositories.d.ts.map +1 -0
- package/backend/dist/platform/storage/platformDomainRepositories.js +7 -0
- package/backend/dist/platform/storage/platformDomainRepositories.js.map +1 -0
- package/backend/dist/platform/storage/platformStorageRuntime.d.ts +35 -0
- package/backend/dist/platform/storage/platformStorageRuntime.d.ts.map +1 -0
- package/backend/dist/platform/storage/platformStorageRuntime.js +299 -0
- package/backend/dist/platform/storage/platformStorageRuntime.js.map +1 -0
- package/backend/dist/platform/storage/postgresPlatformDomainRepositories.d.ts +4 -0
- package/backend/dist/platform/storage/postgresPlatformDomainRepositories.d.ts.map +1 -0
- package/backend/dist/platform/storage/postgresPlatformDomainRepositories.js +1017 -0
- package/backend/dist/platform/storage/postgresPlatformDomainRepositories.js.map +1 -0
- package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.d.ts +4 -0
- package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.d.ts.map +1 -0
- package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.js +40 -0
- package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.js.map +1 -0
- package/backend/dist/platform/storage/resourceContentCleanup.d.ts +29 -0
- package/backend/dist/platform/storage/resourceContentCleanup.d.ts.map +1 -0
- package/backend/dist/platform/storage/resourceContentCleanup.js +100 -0
- package/backend/dist/platform/storage/resourceContentCleanup.js.map +1 -0
- package/backend/dist/platform/storage/resourceDeletionLifecycle.d.ts +14 -0
- package/backend/dist/platform/storage/resourceDeletionLifecycle.d.ts.map +1 -0
- package/backend/dist/platform/storage/resourceDeletionLifecycle.js +31 -0
- package/backend/dist/platform/storage/resourceDeletionLifecycle.js.map +1 -0
- package/backend/dist/platform/storage/s3EncryptedBlobStore.d.ts +140 -0
- package/backend/dist/platform/storage/s3EncryptedBlobStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/s3EncryptedBlobStore.js +1309 -0
- package/backend/dist/platform/storage/s3EncryptedBlobStore.js.map +1 -0
- package/backend/dist/platform/storage/sqliteEncryptedVectorStore.d.ts +71 -0
- package/backend/dist/platform/storage/sqliteEncryptedVectorStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/sqliteEncryptedVectorStore.js +766 -0
- package/backend/dist/platform/storage/sqliteEncryptedVectorStore.js.map +1 -0
- package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.d.ts +4 -0
- package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.d.ts.map +1 -0
- package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.js +1037 -0
- package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.js.map +1 -0
- package/backend/dist/platform/storage/sqliteToTeamStorageMigration.d.ts +25 -0
- package/backend/dist/platform/storage/sqliteToTeamStorageMigration.d.ts.map +1 -0
- package/backend/dist/platform/storage/sqliteToTeamStorageMigration.js +1292 -0
- package/backend/dist/platform/storage/sqliteToTeamStorageMigration.js.map +1 -0
- package/backend/dist/platform/storage/storageFactory.d.ts +81 -0
- package/backend/dist/platform/storage/storageFactory.d.ts.map +1 -0
- package/backend/dist/platform/storage/storageFactory.js +518 -0
- package/backend/dist/platform/storage/storageFactory.js.map +1 -0
- package/backend/dist/platform/storage/storageSchemaContracts.d.ts +22 -0
- package/backend/dist/platform/storage/storageSchemaContracts.d.ts.map +1 -0
- package/backend/dist/platform/storage/storageSchemaContracts.js +299 -0
- package/backend/dist/platform/storage/storageSchemaContracts.js.map +1 -0
- package/backend/dist/platform/storage/vectorStore.d.ts +117 -0
- package/backend/dist/platform/storage/vectorStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/vectorStore.js +40 -0
- package/backend/dist/platform/storage/vectorStore.js.map +1 -0
- package/backend/dist/platform/workPersistence/index.d.ts +9 -0
- package/backend/dist/platform/workPersistence/index.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/index.js +14 -0
- package/backend/dist/platform/workPersistence/index.js.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.d.ts +9 -0
- package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.js +47 -0
- package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.js.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.d.ts +3 -0
- package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.js +28 -0
- package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.js.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkMigration.d.ts +3 -0
- package/backend/dist/platform/workPersistence/postgresWorkMigration.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkMigration.js +101 -0
- package/backend/dist/platform/workPersistence/postgresWorkMigration.js.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkPersistence.d.ts +79 -0
- package/backend/dist/platform/workPersistence/postgresWorkPersistence.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkPersistence.js +521 -0
- package/backend/dist/platform/workPersistence/postgresWorkPersistence.js.map +1 -0
- package/backend/dist/platform/workPersistence/service.d.ts +6 -0
- package/backend/dist/platform/workPersistence/service.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/service.js +27 -0
- package/backend/dist/platform/workPersistence/service.js.map +1 -0
- package/backend/dist/platform/workPersistence/sqliteWorkPersistence.d.ts +77 -0
- package/backend/dist/platform/workPersistence/sqliteWorkPersistence.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/sqliteWorkPersistence.js +463 -0
- package/backend/dist/platform/workPersistence/sqliteWorkPersistence.js.map +1 -0
- package/backend/dist/platform/workPersistence/types.d.ts +159 -0
- package/backend/dist/platform/workPersistence/types.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/types.js +13 -0
- package/backend/dist/platform/workPersistence/types.js.map +1 -0
- package/backend/dist/platform/workPersistence/workExecutionTypes.d.ts +13 -0
- package/backend/dist/platform/workPersistence/workExecutionTypes.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/workExecutionTypes.js +7 -0
- package/backend/dist/platform/workPersistence/workExecutionTypes.js.map +1 -0
- package/backend/dist/platform/workPersistence/workMessageContentCodec.d.ts +8 -0
- package/backend/dist/platform/workPersistence/workMessageContentCodec.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/workMessageContentCodec.js +25 -0
- package/backend/dist/platform/workPersistence/workMessageContentCodec.js.map +1 -0
- package/backend/dist/platform/workPersistence/workTextSafety.d.ts +3 -0
- package/backend/dist/platform/workPersistence/workTextSafety.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/workTextSafety.js +8 -0
- package/backend/dist/platform/workPersistence/workTextSafety.js.map +1 -0
- package/backend/dist/routes/agentCli.js +1 -1
- package/backend/dist/routes/agentCli.js.map +1 -1
- package/backend/dist/routes/artifacts.d.ts.map +1 -1
- package/backend/dist/routes/artifacts.js +2 -1
- package/backend/dist/routes/artifacts.js.map +1 -1
- package/backend/dist/routes/auth.d.ts.map +1 -1
- package/backend/dist/routes/auth.js +64 -18
- package/backend/dist/routes/auth.js.map +1 -1
- package/backend/dist/routes/chat.d.ts.map +1 -1
- package/backend/dist/routes/chat.js +519 -85
- package/backend/dist/routes/chat.js.map +1 -1
- package/backend/dist/routes/documents.d.ts.map +1 -1
- package/backend/dist/routes/documents.js +136 -28
- package/backend/dist/routes/documents.js.map +1 -1
- package/backend/dist/routes/embeddings.d.ts.map +1 -1
- package/backend/dist/routes/embeddings.js +2 -1
- package/backend/dist/routes/embeddings.js.map +1 -1
- package/backend/dist/routes/health.d.ts +3 -0
- package/backend/dist/routes/health.d.ts.map +1 -0
- package/backend/dist/routes/health.js +52 -0
- package/backend/dist/routes/health.js.map +1 -0
- package/backend/dist/routes/huggingfaceHub.d.ts.map +1 -1
- package/backend/dist/routes/huggingfaceHub.js +2 -1
- package/backend/dist/routes/huggingfaceHub.js.map +1 -1
- package/backend/dist/routes/imageGen.d.ts.map +1 -1
- package/backend/dist/routes/imageGen.js +42 -10
- package/backend/dist/routes/imageGen.js.map +1 -1
- package/backend/dist/routes/jobs.d.ts +3 -0
- package/backend/dist/routes/jobs.d.ts.map +1 -0
- package/backend/dist/routes/jobs.js +117 -0
- package/backend/dist/routes/jobs.js.map +1 -0
- package/backend/dist/routes/libreClaw.d.ts.map +1 -1
- package/backend/dist/routes/libreClaw.js +10 -7
- package/backend/dist/routes/libreClaw.js.map +1 -1
- package/backend/dist/routes/media.d.ts.map +1 -1
- package/backend/dist/routes/media.js +523 -77
- package/backend/dist/routes/media.js.map +1 -1
- package/backend/dist/routes/notes.d.ts.map +1 -1
- package/backend/dist/routes/notes.js +21 -21
- package/backend/dist/routes/notes.js.map +1 -1
- package/backend/dist/routes/ollama.d.ts.map +1 -1
- package/backend/dist/routes/ollama.js +40 -12
- package/backend/dist/routes/ollama.js.map +1 -1
- package/backend/dist/routes/personas.d.ts.map +1 -1
- package/backend/dist/routes/personas.js +4 -2
- package/backend/dist/routes/personas.js.map +1 -1
- package/backend/dist/routes/plugins.d.ts.map +1 -1
- package/backend/dist/routes/plugins.js +79 -51
- package/backend/dist/routes/plugins.js.map +1 -1
- package/backend/dist/routes/preferences.d.ts.map +1 -1
- package/backend/dist/routes/preferences.js +290 -25
- package/backend/dist/routes/preferences.js.map +1 -1
- package/backend/dist/routes/search.d.ts.map +1 -1
- package/backend/dist/routes/search.js +23 -14
- package/backend/dist/routes/search.js.map +1 -1
- package/backend/dist/routes/stt.d.ts +9 -0
- package/backend/dist/routes/stt.d.ts.map +1 -0
- package/backend/dist/routes/stt.js +217 -0
- package/backend/dist/routes/stt.js.map +1 -0
- package/backend/dist/routes/systemDiagnostics.d.ts.map +1 -1
- package/backend/dist/routes/systemDiagnostics.js +2 -1
- package/backend/dist/routes/systemDiagnostics.js.map +1 -1
- package/backend/dist/routes/tts.d.ts.map +1 -1
- package/backend/dist/routes/tts.js +577 -28
- package/backend/dist/routes/tts.js.map +1 -1
- package/backend/dist/routes/users.d.ts.map +1 -1
- package/backend/dist/routes/users.js +16 -25
- package/backend/dist/routes/users.js.map +1 -1
- package/backend/dist/routes/work.d.ts.map +1 -1
- package/backend/dist/routes/work.js +167 -113
- package/backend/dist/routes/work.js.map +1 -1
- package/backend/dist/services/agentAccessService.d.ts +2 -2
- package/backend/dist/services/agentAccessService.d.ts.map +1 -1
- package/backend/dist/services/agentAccessService.js +5 -14
- package/backend/dist/services/agentAccessService.js.map +1 -1
- package/backend/dist/services/agentCliService.d.ts +3 -2
- package/backend/dist/services/agentCliService.d.ts.map +1 -1
- package/backend/dist/services/agentCliService.js +44 -16
- package/backend/dist/services/agentCliService.js.map +1 -1
- package/backend/dist/services/assistantCompletionService.d.ts +2 -1
- package/backend/dist/services/assistantCompletionService.d.ts.map +1 -1
- package/backend/dist/services/assistantCompletionService.js +7 -3
- package/backend/dist/services/assistantCompletionService.js.map +1 -1
- package/backend/dist/services/authService.d.ts +7 -2
- package/backend/dist/services/authService.d.ts.map +1 -1
- package/backend/dist/services/authService.js +23 -10
- package/backend/dist/services/authService.js.map +1 -1
- package/backend/dist/services/chatGenerationService.d.ts +5 -4
- package/backend/dist/services/chatGenerationService.d.ts.map +1 -1
- package/backend/dist/services/chatGenerationService.js +23 -17
- package/backend/dist/services/chatGenerationService.js.map +1 -1
- package/backend/dist/services/chatRequestService.d.ts +4 -3
- package/backend/dist/services/chatRequestService.d.ts.map +1 -1
- package/backend/dist/services/chatRequestService.js +3 -3
- package/backend/dist/services/chatRequestService.js.map +1 -1
- package/backend/dist/services/chatService.d.ts +66 -16
- package/backend/dist/services/chatService.d.ts.map +1 -1
- package/backend/dist/services/chatService.js +402 -111
- package/backend/dist/services/chatService.js.map +1 -1
- package/backend/dist/services/codexOAuthService.d.ts +2 -2
- package/backend/dist/services/codexOAuthService.d.ts.map +1 -1
- package/backend/dist/services/codexOAuthService.js +63 -7
- package/backend/dist/services/codexOAuthService.js.map +1 -1
- package/backend/dist/services/dataArchiveService.d.ts +88 -0
- package/backend/dist/services/dataArchiveService.d.ts.map +1 -0
- package/backend/dist/services/dataArchiveService.js +1027 -0
- package/backend/dist/services/dataArchiveService.js.map +1 -0
- package/backend/dist/services/documentService.d.ts +67 -14
- package/backend/dist/services/documentService.d.ts.map +1 -1
- package/backend/dist/services/documentService.js +938 -193
- package/backend/dist/services/documentService.js.map +1 -1
- package/backend/dist/services/durableChatCompletion.d.ts +16 -0
- package/backend/dist/services/durableChatCompletion.d.ts.map +1 -0
- package/backend/dist/services/durableChatCompletion.js +34 -0
- package/backend/dist/services/durableChatCompletion.js.map +1 -0
- package/backend/dist/services/durableChatGenerationService.d.ts +19 -0
- package/backend/dist/services/durableChatGenerationService.d.ts.map +1 -0
- package/backend/dist/services/durableChatGenerationService.js +341 -0
- package/backend/dist/services/durableChatGenerationService.js.map +1 -0
- package/backend/dist/services/embeddingService.d.ts +1 -1
- package/backend/dist/services/embeddingService.d.ts.map +1 -1
- package/backend/dist/services/embeddingService.js +16 -13
- package/backend/dist/services/embeddingService.js.map +1 -1
- package/backend/dist/services/encryptionService.d.ts +28 -1
- package/backend/dist/services/encryptionService.d.ts.map +1 -1
- package/backend/dist/services/encryptionService.js +131 -51
- package/backend/dist/services/encryptionService.js.map +1 -1
- package/backend/dist/services/followUpService.d.ts +1 -1
- package/backend/dist/services/followUpService.d.ts.map +1 -1
- package/backend/dist/services/followUpService.js +1 -1
- package/backend/dist/services/followUpService.js.map +1 -1
- package/backend/dist/services/galleryService.d.ts +38 -37
- package/backend/dist/services/galleryService.d.ts.map +1 -1
- package/backend/dist/services/galleryService.js +356 -251
- package/backend/dist/services/galleryService.js.map +1 -1
- package/backend/dist/services/healthService.d.ts +65 -0
- package/backend/dist/services/healthService.d.ts.map +1 -0
- package/backend/dist/services/healthService.js +379 -0
- package/backend/dist/services/healthService.js.map +1 -0
- package/backend/dist/services/legacyCiphertextIntegrity.d.ts +40 -0
- package/backend/dist/services/legacyCiphertextIntegrity.d.ts.map +1 -0
- package/backend/dist/services/legacyCiphertextIntegrity.js +406 -0
- package/backend/dist/services/legacyCiphertextIntegrity.js.map +1 -0
- package/backend/dist/services/mediaGenerationJobService.d.ts +27 -5
- package/backend/dist/services/mediaGenerationJobService.d.ts.map +1 -1
- package/backend/dist/services/mediaGenerationJobService.js +185 -55
- package/backend/dist/services/mediaGenerationJobService.js.map +1 -1
- package/backend/dist/services/memoryService.d.ts +7 -83
- package/backend/dist/services/memoryService.d.ts.map +1 -1
- package/backend/dist/services/memoryService.js +428 -573
- package/backend/dist/services/memoryService.js.map +1 -1
- package/backend/dist/services/memoryUtils.d.ts.map +1 -1
- package/backend/dist/services/memoryUtils.js +8 -1
- package/backend/dist/services/memoryUtils.js.map +1 -1
- package/backend/dist/services/modelAccessService.d.ts +3 -3
- package/backend/dist/services/modelAccessService.d.ts.map +1 -1
- package/backend/dist/services/modelAccessService.js +8 -16
- package/backend/dist/services/modelAccessService.js.map +1 -1
- package/backend/dist/services/mutationEngineService.d.ts +0 -7
- package/backend/dist/services/mutationEngineService.d.ts.map +1 -1
- package/backend/dist/services/mutationEngineService.js +7 -78
- package/backend/dist/services/mutationEngineService.js.map +1 -1
- package/backend/dist/services/ollamaService.d.ts +4 -4
- package/backend/dist/services/ollamaService.d.ts.map +1 -1
- package/backend/dist/services/ollamaService.js +97 -34
- package/backend/dist/services/ollamaService.js.map +1 -1
- package/backend/dist/services/personaService.d.ts.map +1 -1
- package/backend/dist/services/personaService.js +19 -54
- package/backend/dist/services/personaService.js.map +1 -1
- package/backend/dist/services/pluginActivationService.d.ts +6 -5
- package/backend/dist/services/pluginActivationService.d.ts.map +1 -1
- package/backend/dist/services/pluginActivationService.js +36 -76
- package/backend/dist/services/pluginActivationService.js.map +1 -1
- package/backend/dist/services/pluginAudioGenerationService.d.ts +11 -6
- package/backend/dist/services/pluginAudioGenerationService.d.ts.map +1 -1
- package/backend/dist/services/pluginAudioGenerationService.js +74 -16
- package/backend/dist/services/pluginAudioGenerationService.js.map +1 -1
- package/backend/dist/services/pluginCacheInvalidation.d.ts +38 -0
- package/backend/dist/services/pluginCacheInvalidation.d.ts.map +1 -0
- package/backend/dist/services/pluginCacheInvalidation.js +198 -0
- package/backend/dist/services/pluginCacheInvalidation.js.map +1 -0
- package/backend/dist/services/pluginCapabilityRegistryService.d.ts +3 -3
- package/backend/dist/services/pluginCapabilityRegistryService.d.ts.map +1 -1
- package/backend/dist/services/pluginCapabilityRegistryService.js +11 -7
- package/backend/dist/services/pluginCapabilityRegistryService.js.map +1 -1
- package/backend/dist/services/pluginCredentialsService.d.ts +9 -8
- package/backend/dist/services/pluginCredentialsService.d.ts.map +1 -1
- package/backend/dist/services/pluginCredentialsService.js +48 -89
- package/backend/dist/services/pluginCredentialsService.js.map +1 -1
- package/backend/dist/services/pluginEmbeddingService.d.ts +8 -7
- package/backend/dist/services/pluginEmbeddingService.d.ts.map +1 -1
- package/backend/dist/services/pluginEmbeddingService.js +13 -11
- package/backend/dist/services/pluginEmbeddingService.js.map +1 -1
- package/backend/dist/services/pluginImageGenerationService.d.ts +10 -8
- package/backend/dist/services/pluginImageGenerationService.d.ts.map +1 -1
- package/backend/dist/services/pluginImageGenerationService.js +119 -14
- package/backend/dist/services/pluginImageGenerationService.js.map +1 -1
- package/backend/dist/services/pluginSTTService.d.ts +47 -0
- package/backend/dist/services/pluginSTTService.d.ts.map +1 -0
- package/backend/dist/services/pluginSTTService.js +199 -0
- package/backend/dist/services/pluginSTTService.js.map +1 -0
- package/backend/dist/services/pluginService.d.ts +94 -40
- package/backend/dist/services/pluginService.d.ts.map +1 -1
- package/backend/dist/services/pluginService.js +799 -274
- package/backend/dist/services/pluginService.js.map +1 -1
- package/backend/dist/services/pluginTTSService.d.ts +26 -8
- package/backend/dist/services/pluginTTSService.d.ts.map +1 -1
- package/backend/dist/services/pluginTTSService.js +277 -25
- package/backend/dist/services/pluginTTSService.js.map +1 -1
- package/backend/dist/services/pluginUsageService.d.ts +4 -4
- package/backend/dist/services/pluginUsageService.d.ts.map +1 -1
- package/backend/dist/services/pluginUsageService.js +44 -93
- package/backend/dist/services/pluginUsageService.js.map +1 -1
- package/backend/dist/services/pluginVariablesService.d.ts +14 -7
- package/backend/dist/services/pluginVariablesService.d.ts.map +1 -1
- package/backend/dist/services/pluginVariablesService.js +116 -81
- package/backend/dist/services/pluginVariablesService.js.map +1 -1
- package/backend/dist/services/pluginVideoGenerationService.d.ts +19 -8
- package/backend/dist/services/pluginVideoGenerationService.d.ts.map +1 -1
- package/backend/dist/services/pluginVideoGenerationService.js +116 -20
- package/backend/dist/services/pluginVideoGenerationService.js.map +1 -1
- package/backend/dist/services/preferencesService.d.ts +31 -21
- package/backend/dist/services/preferencesService.d.ts.map +1 -1
- package/backend/dist/services/preferencesService.js +104 -102
- package/backend/dist/services/preferencesService.js.map +1 -1
- package/backend/dist/services/recoveryInventoryService.d.ts +244 -0
- package/backend/dist/services/recoveryInventoryService.d.ts.map +1 -0
- package/backend/dist/services/recoveryInventoryService.js +1436 -0
- package/backend/dist/services/recoveryInventoryService.js.map +1 -0
- package/backend/dist/services/simpleGitHubOAuth.js +3 -3
- package/backend/dist/services/simpleGitHubOAuth.js.map +1 -1
- package/backend/dist/services/simpleHuggingFaceOAuth.d.ts.map +1 -1
- package/backend/dist/services/simpleHuggingFaceOAuth.js +3 -3
- package/backend/dist/services/simpleHuggingFaceOAuth.js.map +1 -1
- package/backend/dist/services/systemDiagnosticsService.d.ts.map +1 -1
- package/backend/dist/services/systemDiagnosticsService.js +2 -2
- package/backend/dist/services/systemDiagnosticsService.js.map +1 -1
- package/backend/dist/services/systemSettingsService.d.ts +5 -0
- package/backend/dist/services/systemSettingsService.d.ts.map +1 -0
- package/backend/dist/services/systemSettingsService.js +24 -0
- package/backend/dist/services/systemSettingsService.js.map +1 -0
- package/backend/dist/services/titleGenerationService.d.ts +1 -1
- package/backend/dist/services/titleGenerationService.d.ts.map +1 -1
- package/backend/dist/services/titleGenerationService.js +15 -4
- package/backend/dist/services/titleGenerationService.js.map +1 -1
- package/backend/dist/services/voiceProfileService.d.ts +44 -0
- package/backend/dist/services/voiceProfileService.d.ts.map +1 -0
- package/backend/dist/services/voiceProfileService.js +195 -0
- package/backend/dist/services/voiceProfileService.js.map +1 -0
- package/backend/dist/services/webSearchService.d.ts +7 -7
- package/backend/dist/services/webSearchService.d.ts.map +1 -1
- package/backend/dist/services/webSearchService.js +40 -35
- package/backend/dist/services/webSearchService.js.map +1 -1
- package/backend/dist/services/websocketTicketService.d.ts +39 -0
- package/backend/dist/services/websocketTicketService.d.ts.map +1 -0
- package/backend/dist/services/websocketTicketService.js +183 -0
- package/backend/dist/services/websocketTicketService.js.map +1 -0
- package/backend/dist/services/workAccessService.d.ts +3 -3
- package/backend/dist/services/workAccessService.d.ts.map +1 -1
- package/backend/dist/services/workAccessService.js +8 -16
- package/backend/dist/services/workAccessService.js.map +1 -1
- package/backend/dist/services/workAdminService.d.ts +3 -3
- package/backend/dist/services/workAdminService.d.ts.map +1 -1
- package/backend/dist/services/workAdminService.js +4 -4
- package/backend/dist/services/workAdminService.js.map +1 -1
- package/backend/dist/services/workAgentService.d.ts +25 -1
- package/backend/dist/services/workAgentService.d.ts.map +1 -1
- package/backend/dist/services/workAgentService.js +294 -126
- package/backend/dist/services/workAgentService.js.map +1 -1
- package/backend/dist/services/workEventService.d.ts +15 -2
- package/backend/dist/services/workEventService.d.ts.map +1 -1
- package/backend/dist/services/workEventService.js +201 -3
- package/backend/dist/services/workEventService.js.map +1 -1
- package/backend/dist/services/workKubernetesDriver.d.ts +8 -7
- package/backend/dist/services/workKubernetesDriver.d.ts.map +1 -1
- package/backend/dist/services/workKubernetesDriver.js +65 -21
- package/backend/dist/services/workKubernetesDriver.js.map +1 -1
- package/backend/dist/services/workModelProviderService.d.ts +2 -2
- package/backend/dist/services/workModelProviderService.d.ts.map +1 -1
- package/backend/dist/services/workModelProviderService.js +38 -34
- package/backend/dist/services/workModelProviderService.js.map +1 -1
- package/backend/dist/services/workPolicyService.d.ts +7 -7
- package/backend/dist/services/workPolicyService.d.ts.map +1 -1
- package/backend/dist/services/workPolicyService.js +50 -51
- package/backend/dist/services/workPolicyService.js.map +1 -1
- package/backend/dist/services/workPreviewProxyService.d.ts +8 -8
- package/backend/dist/services/workPreviewProxyService.d.ts.map +1 -1
- package/backend/dist/services/workPreviewProxyService.js +47 -44
- package/backend/dist/services/workPreviewProxyService.js.map +1 -1
- package/backend/dist/services/workRuntimeDriver.d.ts +21 -18
- package/backend/dist/services/workRuntimeDriver.d.ts.map +1 -1
- package/backend/dist/services/workRuntimeDriver.js +69 -20
- package/backend/dist/services/workRuntimeDriver.js.map +1 -1
- package/backend/dist/services/workRuntimeService.d.ts +18 -13
- package/backend/dist/services/workRuntimeService.d.ts.map +1 -1
- package/backend/dist/services/workRuntimeService.js +438 -194
- package/backend/dist/services/workRuntimeService.js.map +1 -1
- package/backend/dist/services/workRuntimeShared.d.ts +2 -0
- package/backend/dist/services/workRuntimeShared.d.ts.map +1 -1
- package/backend/dist/services/workRuntimeShared.js.map +1 -1
- package/backend/dist/services/workTaskService.d.ts +42 -36
- package/backend/dist/services/workTaskService.d.ts.map +1 -1
- package/backend/dist/services/workTaskService.js +445 -350
- package/backend/dist/services/workTaskService.js.map +1 -1
- package/backend/dist/services/workTerminalService.d.ts +1 -1
- package/backend/dist/services/workTerminalService.d.ts.map +1 -1
- package/backend/dist/services/workTerminalService.js +33 -6
- package/backend/dist/services/workTerminalService.js.map +1 -1
- package/backend/dist/storage.d.ts +72 -40
- package/backend/dist/storage.d.ts.map +1 -1
- package/backend/dist/storage.js +312 -660
- package/backend/dist/storage.js.map +1 -1
- package/backend/dist/types/index.d.ts +28 -0
- package/backend/dist/types/index.d.ts.map +1 -1
- package/backend/dist/types/index.js.map +1 -1
- package/backend/dist/types/work.d.ts +7 -2
- package/backend/dist/types/work.d.ts.map +1 -1
- package/backend/dist/utils/chatCancellation.d.ts +48 -0
- package/backend/dist/utils/chatCancellation.d.ts.map +1 -0
- package/backend/dist/utils/chatCancellation.js +152 -0
- package/backend/dist/utils/chatCancellation.js.map +1 -0
- package/backend/dist/utils/chatDocumentContext.d.ts +1 -1
- package/backend/dist/utils/chatDocumentContext.d.ts.map +1 -1
- package/backend/dist/utils/chatDocumentContext.js +11 -5
- package/backend/dist/utils/chatDocumentContext.js.map +1 -1
- package/backend/dist/utils/chatStreamCoalescer.d.ts +15 -0
- package/backend/dist/utils/chatStreamCoalescer.d.ts.map +1 -0
- package/backend/dist/utils/chatStreamCoalescer.js +59 -0
- package/backend/dist/utils/chatStreamCoalescer.js.map +1 -0
- package/backend/dist/utils/dataDirectory.d.ts +49 -0
- package/backend/dist/utils/dataDirectory.d.ts.map +1 -0
- package/backend/dist/utils/dataDirectory.js +291 -0
- package/backend/dist/utils/dataDirectory.js.map +1 -0
- package/backend/dist/utils/generationUtils.d.ts.map +1 -1
- package/backend/dist/utils/generationUtils.js +18 -6
- package/backend/dist/utils/generationUtils.js.map +1 -1
- package/backend/dist/utils/jwt.d.ts.map +1 -1
- package/backend/dist/utils/jwt.js +2 -3
- package/backend/dist/utils/jwt.js.map +1 -1
- package/backend/dist/utils/ollamaModelDefaults.d.ts.map +1 -1
- package/backend/dist/utils/ollamaModelDefaults.js +2 -7
- package/backend/dist/utils/ollamaModelDefaults.js.map +1 -1
- package/backend/dist/utils/ollamaStreaming.d.ts +2 -1
- package/backend/dist/utils/ollamaStreaming.d.ts.map +1 -1
- package/backend/dist/utils/ollamaStreaming.js +49 -11
- package/backend/dist/utils/ollamaStreaming.js.map +1 -1
- package/backend/dist/utils/pluginConnectionVariables.d.ts.map +1 -1
- package/backend/dist/utils/pluginConnectionVariables.js +11 -3
- package/backend/dist/utils/pluginConnectionVariables.js.map +1 -1
- package/backend/dist/utils/pluginDefinitionTrust.d.ts.map +1 -1
- package/backend/dist/utils/pluginDefinitionTrust.js +4 -3
- package/backend/dist/utils/pluginDefinitionTrust.js.map +1 -1
- package/backend/dist/utils/pluginStreaming.d.ts +2 -1
- package/backend/dist/utils/pluginStreaming.d.ts.map +1 -1
- package/backend/dist/utils/pluginStreaming.js +5 -1
- package/backend/dist/utils/pluginStreaming.js.map +1 -1
- package/backend/dist/utils/pluginUpload.d.ts +1 -0
- package/backend/dist/utils/pluginUpload.d.ts.map +1 -1
- package/backend/dist/utils/pluginUpload.js +9 -2
- package/backend/dist/utils/pluginUpload.js.map +1 -1
- package/backend/dist/utils/pluginValidation.d.ts.map +1 -1
- package/backend/dist/utils/pluginValidation.js +29 -1
- package/backend/dist/utils/pluginValidation.js.map +1 -1
- package/backend/dist/utils/sttAudioUpload.d.ts +24 -0
- package/backend/dist/utils/sttAudioUpload.d.ts.map +1 -0
- package/backend/dist/utils/sttAudioUpload.js +500 -0
- package/backend/dist/utils/sttAudioUpload.js.map +1 -0
- package/backend/dist/utils/ttsVoiceCloneUpload.d.ts +34 -0
- package/backend/dist/utils/ttsVoiceCloneUpload.d.ts.map +1 -0
- package/backend/dist/utils/ttsVoiceCloneUpload.js +224 -0
- package/backend/dist/utils/ttsVoiceCloneUpload.js.map +1 -0
- package/backend/dist/utils/websocketMessages.d.ts +2 -1
- package/backend/dist/utils/websocketMessages.d.ts.map +1 -1
- package/backend/dist/utils/websocketMessages.js +16 -2
- package/backend/dist/utils/websocketMessages.js.map +1 -1
- package/backend/dist/websocketServer.d.ts +4 -1
- package/backend/dist/websocketServer.d.ts.map +1 -1
- package/backend/dist/websocketServer.js +290 -44
- package/backend/dist/websocketServer.js.map +1 -1
- package/backend/dist/workTerminalServer.d.ts +9 -0
- package/backend/dist/workTerminalServer.d.ts.map +1 -1
- package/backend/dist/workTerminalServer.js +221 -52
- package/backend/dist/workTerminalServer.js.map +1 -1
- package/backend/dist/worker.d.ts +2 -0
- package/backend/dist/worker.d.ts.map +1 -0
- package/backend/dist/worker.js +250 -0
- package/backend/dist/worker.js.map +1 -0
- package/backend/package.json +19 -9
- package/bin/cli.js +126 -99
- package/bin/runtime-paths.js +108 -0
- package/frontend/dist/artifact-runtime/.build-fingerprint +1 -1
- package/frontend/dist/artifact-runtime/framer-motion.js +5 -5
- package/frontend/dist/artifact-runtime/lucide-react.js +1 -1
- package/frontend/dist/assets/index-CUhEG7E2.js +33 -0
- package/frontend/dist/assets/index-kxtZQLV6.css +1 -0
- package/frontend/dist/assets/{markdown-math-ClQbWekD.css → markdown-math-ClTedVi7.css} +1 -1
- package/frontend/dist/index.html +36 -18
- package/frontend/dist/js/{ArtifactContainer-C_UdeK4k.js → ArtifactContainer-BTEDhBnv.js} +1 -1
- package/frontend/dist/js/{ArtifactDemoPage-D3AuvuR5.js → ArtifactDemoPage-B0gN3YTl.js} +1 -1
- package/frontend/dist/js/{ArtifactSandboxFrame-BiXl9iGD.js → ArtifactSandboxFrame-CLBXQkZs.js} +3 -3
- package/frontend/dist/js/{ArtifactSlideOutPanel-CvgS3sfQ.js → ArtifactSlideOutPanel-CfqHPFdE.js} +1 -1
- package/frontend/dist/js/{Button-DcBM7gdH.js → Button-BV44cTnj.js} +1 -1
- package/frontend/dist/js/ChatPage-DIkAXZWA.js +23 -0
- package/frontend/dist/js/{FirstTimeSetup-B9742i3H.js → FirstTimeSetup-B8phXGNA.js} +1 -1
- package/frontend/dist/js/GalleryPage-W4uI043I.js +1 -0
- package/frontend/dist/js/HomePage-DlxehbyO.js +1 -0
- package/frontend/dist/js/{LibreClawPage-Ds6pqEyk.js → LibreClawPage-CgD0_G_F.js} +1 -1
- package/frontend/dist/js/{ModelManagerModals-BBNg2fxs.js → ModelManagerModals-D7jIT3v1.js} +1 -1
- package/frontend/dist/js/{ModelSelector-CJfJYwxh.js → ModelSelector-BYxJU1UV.js} +1 -1
- package/frontend/dist/js/ModelsPage-C4XdCKP5.js +2 -0
- package/frontend/dist/js/NotesPage-CDECOl4V.js +1 -0
- package/frontend/dist/js/{OptimizedSyntaxHighlighter-CWYUn9Oe.js → OptimizedSyntaxHighlighter-XwqZEoTf.js} +1 -1
- package/frontend/dist/js/{PersonasPage-CbQVv9OM.js → PersonasPage-CjSLPrgS.js} +2 -2
- package/frontend/dist/js/PluginUsagePage-DJOXJuH4.js +1 -0
- package/frontend/dist/js/RichMessageContent-Debeh6bi.js +3 -0
- package/frontend/dist/js/SettingsModal-cUqAeYUP.js +1 -0
- package/frontend/dist/js/{SettingsToggle-Uz2jvV64.js → SettingsToggle-WTa0rgvY.js} +1 -1
- package/frontend/dist/js/{SystemPage-CIBDZTWB.js → SystemPage-DxPw0GS7.js} +1 -1
- package/frontend/dist/js/UserManagementPage-CEdYFe_Z.js +1 -0
- package/frontend/dist/js/WorkPage-DDVeuG_9.js +6 -0
- package/frontend/dist/js/api-IzobHGND.js +14 -0
- package/frontend/dist/js/appStore-DKwC2vgn.js +2 -0
- package/frontend/dist/js/ar-xTSvTq05.js +2 -0
- package/frontend/dist/js/authStore-OaTuapL7.js +4 -0
- package/frontend/dist/js/{babel-CmENXdZw.js → babel-D24oDI9y.js} +1 -1
- package/frontend/dist/js/bn-iYAsohEA.js +2 -0
- package/frontend/dist/js/chatStore-DXGUVLXD.js +3 -0
- package/frontend/dist/js/{config-CV8L89A5.js → config-DPEEuTAe.js} +1 -1
- package/frontend/dist/js/cs-YBHN88Hb.js +2 -0
- package/frontend/dist/js/da-D7qlLy_k.js +2 -0
- package/frontend/dist/js/de-DV671k2c.js +2 -0
- package/frontend/dist/js/es-kyBgzNq-.js +2 -0
- package/frontend/dist/js/{estree-Lx6fK8Ug.js → estree-ChwJsD2w.js} +1 -1
- package/frontend/dist/js/fr-Cw1vut7I.js +2 -0
- package/frontend/dist/js/hi-DWEFC024.js +2 -0
- package/frontend/dist/js/{html-Dx5reqmV.js → html-DFrVjciF.js} +1 -1
- package/frontend/dist/js/id-DlMHjjy0.js +2 -0
- package/frontend/dist/js/is-B9E_a7dG.js +2 -0
- package/frontend/dist/js/it-DawmVbLC.js +2 -0
- package/frontend/dist/js/ja-DmVvwY3W.js +2 -0
- package/frontend/dist/js/ko-DzOPpkVs.js +2 -0
- package/frontend/dist/js/{markdown-Bd5G8zQB.js → markdown-FLLx7b67.js} +1 -1
- package/frontend/dist/js/markdown-core-BmPPZiuD.js +31 -0
- package/frontend/dist/js/{markdown-math-B7FlYsmr.js → markdown-math-mH7AZ_mb.js} +6 -6
- package/frontend/dist/js/{messageCodeStyles-CUWSpffv.js → messageCodeStyles-CBkkZY4n.js} +1 -1
- package/frontend/dist/js/ms-DpsaOPht.js +2 -0
- package/frontend/dist/js/nl-B1d8W22n.js +2 -0
- package/frontend/dist/js/pl-nCncRVgt.js +2 -0
- package/frontend/dist/js/{postcss-B5WIGhAY.js → postcss-Bx9CTcIc.js} +1 -1
- package/frontend/dist/js/pt-DHw8fGuu.js +2 -0
- package/frontend/dist/js/{react-vendor-DPNXrO-8.js → react-vendor-C5yShNlM.js} +1 -1
- package/frontend/dist/js/{router-vendor-Ca9zqOqT.js → router-vendor-CbPDks39.js} +1 -1
- package/frontend/dist/js/ru-Derl_YP_.js +2 -0
- package/frontend/dist/js/{standalone-DLNXiOUi.js → standalone-i8-5bg5p.js} +1 -1
- package/frontend/dist/js/sv-pJAfBVo0.js +2 -0
- package/frontend/dist/js/{syntax-highlight-Ca9bHsaz.js → syntax-highlight-3EEX6CGL.js} +3 -3
- package/frontend/dist/js/th-C_7fIGnk.js +2 -0
- package/frontend/dist/js/tr-CPqsJvaP.js +2 -0
- package/frontend/dist/js/{typescript-YKxslwSt.js → typescript-CQ3x-Uni.js} +1 -1
- package/frontend/dist/js/{ui-Dw6jDKxN.js → ui-BHhR3Vok.js} +2 -2
- package/frontend/dist/js/ui-vendor-D3Ahl1x5.js +177 -0
- package/frontend/dist/js/uk-3o8P_kFi.js +2 -0
- package/frontend/dist/js/{useTranslation-t1quV8ce.js → useTranslation-C3ei3mJq.js} +1 -1
- package/frontend/dist/js/{utils-iKndEgla.js → utils-CuC1beTY.js} +1 -1
- package/frontend/dist/js/{utils-vendor-1zob7nK9.js → utils-vendor-BBa8OxtB.js} +1 -1
- package/frontend/dist/js/vi-Dv6N7OVD.js +2 -0
- package/frontend/dist/js/{workApi-LrQmhNxb.js → workApi-Czu69yWS.js} +2 -2
- package/frontend/dist/js/{yaml-QD4znPfZ.js → yaml-DioTxVLA.js} +1 -1
- package/frontend/dist/js/zh-qg5iqtPi.js +2 -0
- package/package.json +16 -5
- package/plugins/huggingface.json +12 -3
- package/plugins/llama-cpp.json +18 -6
- package/plugins/longcat-audiodit.json +114 -0
- package/plugins/openai.json +18 -0
- package/frontend/dist/assets/index-CN7wpzUO.js +0 -26
- package/frontend/dist/assets/index-Dqkx5o2y.css +0 -1
- package/frontend/dist/js/ChatPage-DBEi-FSO.js +0 -16
- package/frontend/dist/js/GalleryPage-BL0x_xl7.js +0 -1
- package/frontend/dist/js/HomePage-Ukn2Y-BG.js +0 -1
- package/frontend/dist/js/ModelsPage-CDPJM-LA.js +0 -2
- package/frontend/dist/js/NotesPage-DJ-_MSI1.js +0 -1
- package/frontend/dist/js/PluginUsagePage-D69rQvFl.js +0 -1
- package/frontend/dist/js/RichMessageContent-DfuCu6PB.js +0 -3
- package/frontend/dist/js/SettingsModal-D87lWSx4.js +0 -1
- package/frontend/dist/js/UserManagementPage-DzMnFKDG.js +0 -1
- package/frontend/dist/js/WorkPage-D84JNdjS.js +0 -6
- package/frontend/dist/js/api-DhmVEJr2.js +0 -14
- package/frontend/dist/js/appStore-BsqeY2tS.js +0 -2
- package/frontend/dist/js/ar-BgCHB9_9.js +0 -2
- package/frontend/dist/js/authStore-DanfaPdm.js +0 -4
- package/frontend/dist/js/bn-Cr8_opuR.js +0 -2
- package/frontend/dist/js/chatStore-C25ywAXQ.js +0 -3
- package/frontend/dist/js/cs-Bb9gXpfH.js +0 -2
- package/frontend/dist/js/da-JfdGHjAw.js +0 -2
- package/frontend/dist/js/de-CczkCOVx.js +0 -2
- package/frontend/dist/js/es-n_0cjhn7.js +0 -2
- package/frontend/dist/js/fr-Pno128cn.js +0 -2
- package/frontend/dist/js/hi-DBCdcL4p.js +0 -2
- package/frontend/dist/js/id-85QDk-wA.js +0 -2
- package/frontend/dist/js/is-9MuKmBft.js +0 -2
- package/frontend/dist/js/it-C5mz9I3H.js +0 -2
- package/frontend/dist/js/ja-Cu90QTBd.js +0 -2
- package/frontend/dist/js/ko-CSdgcMgq.js +0 -2
- package/frontend/dist/js/markdown-core-DHnR5Hw8.js +0 -16
- package/frontend/dist/js/ms-IQMi6HBU.js +0 -2
- package/frontend/dist/js/nl-BwpdTgvn.js +0 -2
- package/frontend/dist/js/pl-zq8ctKrQ.js +0 -2
- package/frontend/dist/js/pt-BIQu7dBu.js +0 -2
- package/frontend/dist/js/ru-BT5-Z0F9.js +0 -2
- package/frontend/dist/js/sv-B1_q6-Uj.js +0 -2
- package/frontend/dist/js/th-BiLLwq0A.js +0 -2
- package/frontend/dist/js/tr-NZbkkeKs.js +0 -2
- package/frontend/dist/js/ui-vendor-xUzKqAXI.js +0 -177
- package/frontend/dist/js/uk-CGu1pg-F.js +0 -2
- package/frontend/dist/js/vi-ClvH5JZg.js +0 -2
- package/frontend/dist/js/zh-Jgjy3uAG.js +0 -2
|
@@ -23,24 +23,97 @@ import codexOAuthService, { CODEX_OAUTH_PLUGIN_ID, } from './codexOAuthService.j
|
|
|
23
23
|
import { userModel } from '../models/userModel.js';
|
|
24
24
|
import pluginCredentialsService from './pluginCredentialsService.js';
|
|
25
25
|
import pluginVariablesService from './pluginVariablesService.js';
|
|
26
|
+
import { ensurePluginCacheInvalidationSubscription, publishPluginCacheInvalidation, registerPluginCacheInvalidationListener, } from './pluginCacheInvalidation.js';
|
|
26
27
|
import pluginActivationService from './pluginActivationService.js';
|
|
27
28
|
import { PluginAudioGenerationService } from './pluginAudioGenerationService.js';
|
|
28
29
|
import { PluginCapabilityRegistryService } from './pluginCapabilityRegistryService.js';
|
|
29
30
|
import { PluginEmbeddingService } from './pluginEmbeddingService.js';
|
|
30
31
|
import { PluginImageGenerationService } from './pluginImageGenerationService.js';
|
|
32
|
+
import { PluginSTTService } from './pluginSTTService.js';
|
|
31
33
|
import { PluginTTSService } from './pluginTTSService.js';
|
|
32
34
|
import { PluginVideoGenerationService } from './pluginVideoGenerationService.js';
|
|
33
35
|
import { applyPluginDefinitionPolicy, buildPluginChatPayload, convertProviderResponse, getOpenAICompatibleSamplingParameters, resolvePluginChatParameters, toOpenAICompatibleMessages, } from '../utils/pluginChatAdapter.js';
|
|
34
36
|
import { streamAnthropicResponse, streamOpenAICompatibleResponse, streamOpenAIResponsesResponse, } from '../utils/pluginStreamAdapter.js';
|
|
35
37
|
import { applyModelEndpointTemplate, assertSafePluginEndpoint, buildPluginAuthHeaders, buildPluginModelDiscoveryHeaders, pluginRequiresApiKey, resolvePluginApiConfig, resolvePluginEndpoint, resolvePluginModelsEndpoint, validatePluginModel, } from '../utils/pluginValidation.js';
|
|
36
38
|
import { createLogger } from '../utils/logger.js';
|
|
39
|
+
import { isChatGenerationCancelled, throwIfChatGenerationCancelled, } from '../utils/chatCancellation.js';
|
|
37
40
|
import { resolveBundledPluginsDir } from '../utils/packagePaths.js';
|
|
38
|
-
import {
|
|
41
|
+
import { BACKEND_DIRECTORY, PROJECT_DIRECTORY, resolveDataDirectory, resolveLegacyPluginsDirectories, resolvePhysicalPathCandidate, resolvePluginsDirectory, } from '../utils/dataDirectory.js';
|
|
42
|
+
import { getPersistence } from '../persistence/index.js';
|
|
39
43
|
import { createOpenAIResponsesStateScope, createPluginCredentialFingerprint, OPENAI_RESPONSES_INCOMPLETE_REASON_METADATA_KEY, } from '../utils/openAIResponsesAdapter.js';
|
|
40
44
|
import { getPluginConnectionVariableNames } from '../utils/pluginConnectionVariables.js';
|
|
41
45
|
import pluginUsageService from './pluginUsageService.js';
|
|
42
46
|
import { getPluginDefinitionFingerprint, matchesBundledPluginTrustAnchor, } from '../utils/pluginDefinitionTrust.js';
|
|
47
|
+
import { encryptionService } from './encryptionService.js';
|
|
43
48
|
const logger = createLogger('plugins');
|
|
49
|
+
const hasSymlinkPathComponentFromRoot = (root, target) => {
|
|
50
|
+
const resolvedRoot = path.resolve(root);
|
|
51
|
+
const resolvedTarget = path.resolve(target);
|
|
52
|
+
const relative = path.relative(resolvedRoot, resolvedTarget);
|
|
53
|
+
if (relative === '..' ||
|
|
54
|
+
relative.startsWith(`..${path.sep}`) ||
|
|
55
|
+
path.isAbsolute(relative)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
let current = resolvedRoot;
|
|
59
|
+
for (const component of relative.split(path.sep)) {
|
|
60
|
+
if (!component)
|
|
61
|
+
continue;
|
|
62
|
+
current = path.join(current, component);
|
|
63
|
+
try {
|
|
64
|
+
if (fs.lstatSync(current).isSymbolicLink())
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error.code === 'ENOENT')
|
|
69
|
+
return false;
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
};
|
|
75
|
+
const isRegularPluginDirectory = (directory) => {
|
|
76
|
+
try {
|
|
77
|
+
const stat = fs.lstatSync(directory);
|
|
78
|
+
return stat.isDirectory() && !stat.isSymbolicLink();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const isRegularPluginDefinition = (filePath) => {
|
|
85
|
+
try {
|
|
86
|
+
if (!isRegularPluginDirectory(path.dirname(filePath)))
|
|
87
|
+
return false;
|
|
88
|
+
const stat = fs.lstatSync(filePath);
|
|
89
|
+
return stat.isFile() && !stat.isSymbolicLink();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const readRegularPluginDefinition = (filePath) => {
|
|
96
|
+
if (!isRegularPluginDirectory(path.dirname(filePath))) {
|
|
97
|
+
throw new Error('Plugin definition directory is not a regular directory');
|
|
98
|
+
}
|
|
99
|
+
const namedStat = fs.lstatSync(filePath);
|
|
100
|
+
if (!namedStat.isFile() || namedStat.isSymbolicLink()) {
|
|
101
|
+
throw new Error('Plugin definition is not a regular file');
|
|
102
|
+
}
|
|
103
|
+
const descriptor = fs.openSync(filePath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
|
|
104
|
+
try {
|
|
105
|
+
const openedStat = fs.fstatSync(descriptor);
|
|
106
|
+
if (!openedStat.isFile() ||
|
|
107
|
+
openedStat.dev !== namedStat.dev ||
|
|
108
|
+
openedStat.ino !== namedStat.ino) {
|
|
109
|
+
throw new Error('Plugin definition changed during inspection');
|
|
110
|
+
}
|
|
111
|
+
return fs.readFileSync(descriptor, 'utf8');
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
fs.closeSync(descriptor);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
44
117
|
const readPositiveIntEnv = (name, fallback) => {
|
|
45
118
|
const parsed = Number(process.env[name]);
|
|
46
119
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
@@ -84,6 +157,9 @@ function getPluginRoutingAuthProjection(plugin) {
|
|
|
84
157
|
endpoint: capability.endpoint ?? null,
|
|
85
158
|
models_endpoint: capability.models_endpoint ?? null,
|
|
86
159
|
endpoint_variable: config.endpoint_variable ?? capability.endpoint_variable ?? null,
|
|
160
|
+
models_endpoint_variable: config.models_endpoint_variable ?? null,
|
|
161
|
+
voice_clone_endpoint: config.voice_clone_endpoint ?? null,
|
|
162
|
+
voice_clone_endpoint_variable: config.voice_clone_endpoint_variable ?? null,
|
|
87
163
|
};
|
|
88
164
|
});
|
|
89
165
|
const definitions = new Map((plugin.variables || []).map(definition => [definition.name, definition]));
|
|
@@ -119,7 +195,7 @@ function getPluginRoutingAuthProjection(plugin) {
|
|
|
119
195
|
});
|
|
120
196
|
}
|
|
121
197
|
export class PluginService {
|
|
122
|
-
constructor() {
|
|
198
|
+
constructor(options = {}) {
|
|
123
199
|
this.discoveredModelsCache = new Map();
|
|
124
200
|
this.discoveredModelsUpdatedAt = new Map();
|
|
125
201
|
this.discoveryAttemptedAt = new Map();
|
|
@@ -128,84 +204,229 @@ export class PluginService {
|
|
|
128
204
|
this.discoveredCapabilityModelsUpdatedAt = new Map();
|
|
129
205
|
this.capabilityDiscoveryAttemptedAt = new Map();
|
|
130
206
|
this.inflightCapabilityDiscovery = new Map();
|
|
207
|
+
this.discoveryCacheRevisions = new Map();
|
|
208
|
+
this.capabilityDiscoveryCacheRevisions = new Map();
|
|
131
209
|
this.bundledRoutingProjectionCache = new Map();
|
|
210
|
+
this.sharedDefinitionIds = new Set();
|
|
211
|
+
this.sharedPluginDefinitions =
|
|
212
|
+
getPersistence(encryptionService).dialect === 'postgres';
|
|
132
213
|
this.bundledPluginsDir = resolveBundledPluginsDir(import.meta.url);
|
|
133
|
-
this.
|
|
134
|
-
this.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
214
|
+
this.pluginsDir = resolvePluginsDirectory();
|
|
215
|
+
this.legacyPluginsDirs =
|
|
216
|
+
options.legacyPluginsDirectories ?? resolveLegacyPluginsDirectories();
|
|
217
|
+
const activePluginDirectories = new Set([this.bundledPluginsDir, this.pluginsDir, ...this.legacyPluginsDirs].map(directory => resolvePhysicalPathCandidate(directory)));
|
|
218
|
+
this.historicalPluginConflictDirs = options.legacyPluginsDirectories
|
|
219
|
+
? []
|
|
220
|
+
: resolveLegacyPluginsDirectories(process.env, {
|
|
221
|
+
historicalWorkingDirectory: process.cwd(),
|
|
222
|
+
}).filter(directory => !activePluginDirectories.has(resolvePhysicalPathCandidate(directory)));
|
|
223
|
+
this.pluginReadDirs = this.sharedPluginDefinitions
|
|
224
|
+
? [this.bundledPluginsDir]
|
|
225
|
+
: Array.from(new Set([
|
|
226
|
+
this.bundledPluginsDir,
|
|
227
|
+
...this.legacyPluginsDirs,
|
|
228
|
+
this.pluginsDir,
|
|
229
|
+
]));
|
|
230
|
+
if (this.sharedPluginDefinitions) {
|
|
231
|
+
this.assertNoLocalCustomDefinitions();
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
this.ensurePluginsDirectory();
|
|
235
|
+
}
|
|
142
236
|
this.embeddingService = new PluginEmbeddingService({
|
|
143
|
-
getAllPlugins: userId => this.
|
|
237
|
+
getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
|
|
144
238
|
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
145
239
|
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
146
240
|
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
147
241
|
recordUsage: usage => pluginUsageService.record(usage),
|
|
148
242
|
});
|
|
149
243
|
this.ttsService = new PluginTTSService({
|
|
150
|
-
getAllPlugins: userId => this.
|
|
151
|
-
getPlugin: (id, userId) => this.
|
|
244
|
+
getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
|
|
245
|
+
getPlugin: (id, userId) => this.getPluginUnchecked(id, userId),
|
|
246
|
+
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
247
|
+
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
248
|
+
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
249
|
+
recordUsage: usage => pluginUsageService.record(usage),
|
|
250
|
+
});
|
|
251
|
+
this.sttService = new PluginSTTService({
|
|
252
|
+
getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
|
|
253
|
+
getPlugin: (id, userId) => this.getPluginUnchecked(id, userId),
|
|
152
254
|
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
153
255
|
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
154
256
|
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
155
257
|
recordUsage: usage => pluginUsageService.record(usage),
|
|
156
258
|
});
|
|
157
259
|
this.imageGenerationService = new PluginImageGenerationService({
|
|
158
|
-
getAllPlugins: userId => this.
|
|
159
|
-
getPlugin: (id, userId) => this.
|
|
260
|
+
getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
|
|
261
|
+
getPlugin: (id, userId) => this.getPluginUnchecked(id, userId),
|
|
160
262
|
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
161
263
|
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
162
264
|
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
163
265
|
recordUsage: usage => pluginUsageService.record(usage),
|
|
164
266
|
});
|
|
165
267
|
this.audioGenerationService = new PluginAudioGenerationService({
|
|
166
|
-
getAllPlugins: userId => this.
|
|
167
|
-
getPlugin: (id, userId) => this.
|
|
268
|
+
getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
|
|
269
|
+
getPlugin: (id, userId) => this.getPluginUnchecked(id, userId),
|
|
168
270
|
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
169
271
|
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
170
272
|
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
171
273
|
recordUsage: usage => pluginUsageService.record(usage),
|
|
172
274
|
});
|
|
173
275
|
this.videoGenerationService = new PluginVideoGenerationService({
|
|
174
|
-
getAllPlugins: userId => this.
|
|
175
|
-
getPlugin: (id, userId) => this.
|
|
276
|
+
getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
|
|
277
|
+
getPlugin: (id, userId) => this.getPluginUnchecked(id, userId),
|
|
176
278
|
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
177
279
|
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
178
280
|
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
179
281
|
recordUsage: usage => pluginUsageService.record(usage),
|
|
180
282
|
});
|
|
181
283
|
this.capabilityRegistryService = new PluginCapabilityRegistryService({
|
|
182
|
-
getAllPlugins: userId => this.
|
|
284
|
+
getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
|
|
183
285
|
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
184
286
|
});
|
|
185
287
|
}
|
|
288
|
+
repositories() {
|
|
289
|
+
return getPersistence(encryptionService).repositories.extensions;
|
|
290
|
+
}
|
|
291
|
+
async ensureCacheInvalidation() {
|
|
292
|
+
this.removeCacheInvalidationListener ?? (this.removeCacheInvalidationListener = registerPluginCacheInvalidationListener(invalidation => this.invalidateRuntimeCaches(invalidation)));
|
|
293
|
+
await ensurePluginCacheInvalidationSubscription();
|
|
294
|
+
}
|
|
295
|
+
bumpDiscoveryRevision(key) {
|
|
296
|
+
this.discoveryCacheRevisions.set(key, (this.discoveryCacheRevisions.get(key) ?? 0) + 1);
|
|
297
|
+
}
|
|
298
|
+
bumpCapabilityDiscoveryRevision(key) {
|
|
299
|
+
this.capabilityDiscoveryCacheRevisions.set(key, (this.capabilityDiscoveryCacheRevisions.get(key) ?? 0) + 1);
|
|
300
|
+
}
|
|
301
|
+
invalidateRuntimeCaches(invalidation) {
|
|
302
|
+
const completionKeys = new Set([
|
|
303
|
+
...this.discoveredModelsCache.keys(),
|
|
304
|
+
...this.discoveredModelsUpdatedAt.keys(),
|
|
305
|
+
...this.discoveryAttemptedAt.keys(),
|
|
306
|
+
...this.inflightDiscovery.keys(),
|
|
307
|
+
...this.discoveryCacheRevisions.keys(),
|
|
308
|
+
]);
|
|
309
|
+
const capabilityKeys = new Set([
|
|
310
|
+
...this.discoveredCapabilityModelsCache.keys(),
|
|
311
|
+
...this.discoveredCapabilityModelsUpdatedAt.keys(),
|
|
312
|
+
...this.capabilityDiscoveryAttemptedAt.keys(),
|
|
313
|
+
...this.inflightCapabilityDiscovery.keys(),
|
|
314
|
+
...this.capabilityDiscoveryCacheRevisions.keys(),
|
|
315
|
+
]);
|
|
316
|
+
const completionMatches = (key) => {
|
|
317
|
+
if (invalidation.scope === 'plugin-user') {
|
|
318
|
+
return (key ===
|
|
319
|
+
this.discoveredModelsCacheKey(invalidation.pluginId, invalidation.userId));
|
|
320
|
+
}
|
|
321
|
+
if (invalidation.scope === 'plugin') {
|
|
322
|
+
return key.endsWith(`:${invalidation.pluginId}`);
|
|
323
|
+
}
|
|
324
|
+
return key.startsWith(`${invalidation.userId}:`);
|
|
325
|
+
};
|
|
326
|
+
const capabilityMatches = (key) => {
|
|
327
|
+
if (invalidation.scope === 'plugin-user') {
|
|
328
|
+
return key.startsWith(`${invalidation.userId}:${invalidation.pluginId}:`);
|
|
329
|
+
}
|
|
330
|
+
if (invalidation.scope === 'plugin') {
|
|
331
|
+
return key.includes(`:${invalidation.pluginId}:`);
|
|
332
|
+
}
|
|
333
|
+
return key.startsWith(`${invalidation.userId}:`);
|
|
334
|
+
};
|
|
335
|
+
for (const key of completionKeys) {
|
|
336
|
+
if (!completionMatches(key))
|
|
337
|
+
continue;
|
|
338
|
+
this.discoveredModelsCache.delete(key);
|
|
339
|
+
this.discoveredModelsUpdatedAt.delete(key);
|
|
340
|
+
this.discoveryAttemptedAt.delete(key);
|
|
341
|
+
this.inflightDiscovery.delete(key);
|
|
342
|
+
this.bumpDiscoveryRevision(key);
|
|
343
|
+
}
|
|
344
|
+
for (const key of capabilityKeys) {
|
|
345
|
+
if (!capabilityMatches(key))
|
|
346
|
+
continue;
|
|
347
|
+
this.discoveredCapabilityModelsCache.delete(key);
|
|
348
|
+
this.discoveredCapabilityModelsUpdatedAt.delete(key);
|
|
349
|
+
this.capabilityDiscoveryAttemptedAt.delete(key);
|
|
350
|
+
this.inflightCapabilityDiscovery.delete(key);
|
|
351
|
+
this.bumpCapabilityDiscoveryRevision(key);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
ensureLegacyActivationMigration() {
|
|
355
|
+
if (this.sharedPluginDefinitions)
|
|
356
|
+
return Promise.resolve();
|
|
357
|
+
this.legacyActivationMigration ?? (this.legacyActivationMigration = pluginActivationService.migrateLegacyStatus([...this.pluginReadDirs]
|
|
358
|
+
.reverse()
|
|
359
|
+
.filter(pluginsDir => path.resolve(pluginsDir) !== path.resolve(this.bundledPluginsDir)), pluginId => this.canMigrateLegacyActivation(pluginId)));
|
|
360
|
+
return this.legacyActivationMigration;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Team replicas must never pick a provider definition from node-local disk.
|
|
364
|
+
* Refuse startup when an old writable definition is present so an operator
|
|
365
|
+
* has to migrate it deliberately instead of getting replica-dependent
|
|
366
|
+
* routing, credentials, or activation state.
|
|
367
|
+
*/
|
|
368
|
+
assertNoLocalCustomDefinitions() {
|
|
369
|
+
const bundledDirectory = path.resolve(this.bundledPluginsDir);
|
|
370
|
+
const directories = new Set([
|
|
371
|
+
this.pluginsDir,
|
|
372
|
+
...this.legacyPluginsDirs,
|
|
373
|
+
...this.historicalPluginConflictDirs,
|
|
374
|
+
]);
|
|
375
|
+
for (const directory of directories) {
|
|
376
|
+
if (path.resolve(directory) === bundledDirectory)
|
|
377
|
+
continue;
|
|
378
|
+
let entries;
|
|
379
|
+
try {
|
|
380
|
+
const stat = fs.lstatSync(directory);
|
|
381
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
382
|
+
throw new Error(`Plugin definition path ${directory} is not a physical directory`);
|
|
383
|
+
}
|
|
384
|
+
entries = fs.readdirSync(directory, { withFileTypes: true });
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
if (error.code === 'ENOENT')
|
|
388
|
+
continue;
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
391
|
+
if (entries.some(entry => entry.name.endsWith('.json'))) {
|
|
392
|
+
throw new Error(`Local custom plugin definitions exist at ${directory}. PostgreSQL mode requires definitions in the shared database; run the SQLite-to-PostgreSQL migration with the plugin directory before starting any replica.`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
parseSharedPluginDefinition(row) {
|
|
397
|
+
this.sharedDefinitionIds.add(row.plugin_id);
|
|
398
|
+
if (row.approved_by_user_id === null || row.approved_at === null) {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
const plugin = JSON.parse(row.definition_json);
|
|
403
|
+
if (!this.validatePlugin(plugin) ||
|
|
404
|
+
plugin.id !== row.plugin_id ||
|
|
405
|
+
getPluginDefinitionFingerprint(plugin) !== row.definition_fingerprint) {
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
return applyPluginDefinitionPolicy(plugin);
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
186
414
|
discoveredModelsCacheKey(pluginId, userId) {
|
|
187
415
|
return `${userId}:${pluginId}`;
|
|
188
416
|
}
|
|
189
417
|
discoveredCapabilityModelsCacheKey(pluginId, capability, userId) {
|
|
190
418
|
return `${userId}:${pluginId}:${capability}`;
|
|
191
419
|
}
|
|
192
|
-
getDiscoveredCapabilityModels(pluginId, capability, userId) {
|
|
420
|
+
async getDiscoveredCapabilityModels(pluginId, capability, userId) {
|
|
421
|
+
await this.ensureCacheInvalidation();
|
|
193
422
|
const effectiveUserId = userId || 'default';
|
|
194
423
|
const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, effectiveUserId);
|
|
195
|
-
if (this.
|
|
424
|
+
if (!this.sharedPluginDefinitions &&
|
|
425
|
+
this.discoveredCapabilityModelsCache.has(cacheKey)) {
|
|
196
426
|
return this.discoveredCapabilityModelsCache.get(cacheKey) || undefined;
|
|
197
427
|
}
|
|
198
|
-
const db = getDatabaseSafe();
|
|
199
|
-
if (!db) {
|
|
200
|
-
this.discoveredCapabilityModelsCache.set(cacheKey, null);
|
|
201
|
-
return undefined;
|
|
202
|
-
}
|
|
203
428
|
try {
|
|
204
|
-
const row =
|
|
205
|
-
.prepare(`SELECT models_json, updated_at
|
|
206
|
-
FROM plugin_discovered_capability_models
|
|
207
|
-
WHERE user_id = ? AND plugin_id = ? AND capability = ?`)
|
|
208
|
-
.get(effectiveUserId, pluginId, capability);
|
|
429
|
+
const row = await this.repositories().pluginDiscovery.getCapability(pluginId, capability, effectiveUserId);
|
|
209
430
|
if (!row) {
|
|
210
431
|
this.discoveredCapabilityModelsCache.set(cacheKey, null);
|
|
211
432
|
return undefined;
|
|
@@ -228,38 +449,38 @@ export class PluginService {
|
|
|
228
449
|
return undefined;
|
|
229
450
|
}
|
|
230
451
|
}
|
|
231
|
-
storeDiscoveredCapabilityModels(pluginId, capability, models, userId) {
|
|
452
|
+
async storeDiscoveredCapabilityModels(pluginId, capability, models, userId) {
|
|
453
|
+
await this.ensureCacheInvalidation();
|
|
232
454
|
const effectiveUserId = userId || 'default';
|
|
233
455
|
const uniqueModels = Array.from(new Set(models));
|
|
234
456
|
const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, effectiveUserId);
|
|
235
457
|
const discoveredAt = Date.now();
|
|
458
|
+
await this.repositories().pluginDiscovery.upsertCapability({
|
|
459
|
+
user_id: effectiveUserId,
|
|
460
|
+
plugin_id: pluginId,
|
|
461
|
+
capability,
|
|
462
|
+
models_json: JSON.stringify(uniqueModels),
|
|
463
|
+
updated_at: discoveredAt,
|
|
464
|
+
});
|
|
236
465
|
this.discoveredCapabilityModelsCache.set(cacheKey, uniqueModels);
|
|
237
466
|
this.discoveredCapabilityModelsUpdatedAt.set(cacheKey, discoveredAt);
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
getDiscoveredModels(pluginId, userId) {
|
|
467
|
+
await publishPluginCacheInvalidation({
|
|
468
|
+
version: 1,
|
|
469
|
+
scope: 'plugin-user',
|
|
470
|
+
pluginId,
|
|
471
|
+
userId: effectiveUserId,
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
async getDiscoveredModels(pluginId, userId) {
|
|
475
|
+
await this.ensureCacheInvalidation();
|
|
249
476
|
const effectiveUserId = userId || 'default';
|
|
250
477
|
const cacheKey = this.discoveredModelsCacheKey(pluginId, effectiveUserId);
|
|
251
|
-
if (this.
|
|
478
|
+
if (!this.sharedPluginDefinitions &&
|
|
479
|
+
this.discoveredModelsCache.has(cacheKey)) {
|
|
252
480
|
return this.discoveredModelsCache.get(cacheKey) || undefined;
|
|
253
481
|
}
|
|
254
|
-
const db = getDatabaseSafe();
|
|
255
|
-
if (!db) {
|
|
256
|
-
this.discoveredModelsCache.set(cacheKey, null);
|
|
257
|
-
return undefined;
|
|
258
|
-
}
|
|
259
482
|
try {
|
|
260
|
-
const row =
|
|
261
|
-
.prepare('SELECT models_json, updated_at FROM plugin_discovered_models WHERE user_id = ? AND plugin_id = ?')
|
|
262
|
-
.get(effectiveUserId, pluginId);
|
|
483
|
+
const row = await this.repositories().pluginDiscovery.get(pluginId, effectiveUserId);
|
|
263
484
|
if (!row) {
|
|
264
485
|
this.discoveredModelsCache.set(cacheKey, null);
|
|
265
486
|
return undefined;
|
|
@@ -284,44 +505,52 @@ export class PluginService {
|
|
|
284
505
|
return undefined;
|
|
285
506
|
}
|
|
286
507
|
}
|
|
287
|
-
storeDiscoveredModels(pluginId, models, userId) {
|
|
508
|
+
async storeDiscoveredModels(pluginId, models, userId) {
|
|
509
|
+
await this.ensureCacheInvalidation();
|
|
288
510
|
const effectiveUserId = userId || 'default';
|
|
289
511
|
const uniqueModels = Array.from(new Set(models));
|
|
290
512
|
const cacheKey = this.discoveredModelsCacheKey(pluginId, effectiveUserId);
|
|
291
513
|
const discoveredAt = Date.now();
|
|
292
|
-
this.discoveredModelsCache.set(cacheKey, uniqueModels);
|
|
293
|
-
this.discoveredModelsUpdatedAt.set(cacheKey, discoveredAt);
|
|
294
|
-
const db = getDatabaseSafe();
|
|
295
|
-
if (!db)
|
|
296
|
-
return;
|
|
297
514
|
try {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
515
|
+
await this.repositories().pluginDiscovery.upsert({
|
|
516
|
+
user_id: effectiveUserId,
|
|
517
|
+
plugin_id: pluginId,
|
|
518
|
+
models_json: JSON.stringify(uniqueModels),
|
|
519
|
+
updated_at: discoveredAt,
|
|
520
|
+
});
|
|
521
|
+
this.discoveredModelsCache.set(cacheKey, uniqueModels);
|
|
522
|
+
this.discoveredModelsUpdatedAt.set(cacheKey, discoveredAt);
|
|
523
|
+
await publishPluginCacheInvalidation({
|
|
524
|
+
version: 1,
|
|
525
|
+
scope: 'plugin-user',
|
|
526
|
+
pluginId,
|
|
527
|
+
userId: effectiveUserId,
|
|
528
|
+
});
|
|
304
529
|
}
|
|
305
530
|
catch (error) {
|
|
306
531
|
logger.warn('Failed to persist discovered models for plugin %s:', pluginId, error);
|
|
307
532
|
}
|
|
308
533
|
}
|
|
309
|
-
clearDiscoveredModels(pluginId, userId) {
|
|
310
|
-
this.
|
|
311
|
-
|
|
534
|
+
async clearDiscoveredModels(pluginId, userId) {
|
|
535
|
+
await this.ensureCacheInvalidation();
|
|
536
|
+
await this.clearDiscoveredCapabilityModels(pluginId, userId);
|
|
312
537
|
if (userId) {
|
|
313
538
|
const cacheKey = this.discoveredModelsCacheKey(pluginId, userId);
|
|
314
539
|
this.discoveredModelsCache.set(cacheKey, null);
|
|
315
540
|
this.discoveredModelsUpdatedAt.delete(cacheKey);
|
|
316
541
|
this.discoveryAttemptedAt.delete(cacheKey);
|
|
317
|
-
if (!db)
|
|
318
|
-
return;
|
|
319
542
|
try {
|
|
320
|
-
|
|
543
|
+
await this.repositories().pluginDiscovery.delete(pluginId, userId);
|
|
321
544
|
}
|
|
322
545
|
catch (error) {
|
|
323
546
|
logger.warn('Failed to clear discovered models for plugin %s:', pluginId, error);
|
|
324
547
|
}
|
|
548
|
+
await publishPluginCacheInvalidation({
|
|
549
|
+
version: 1,
|
|
550
|
+
scope: 'plugin-user',
|
|
551
|
+
pluginId,
|
|
552
|
+
userId,
|
|
553
|
+
});
|
|
325
554
|
return;
|
|
326
555
|
}
|
|
327
556
|
for (const key of this.discoveredModelsCache.keys()) {
|
|
@@ -331,54 +560,65 @@ export class PluginService {
|
|
|
331
560
|
this.discoveryAttemptedAt.delete(key);
|
|
332
561
|
}
|
|
333
562
|
}
|
|
334
|
-
if (!db)
|
|
335
|
-
return;
|
|
336
563
|
try {
|
|
337
|
-
|
|
564
|
+
await this.repositories().pluginDiscovery.delete(pluginId);
|
|
338
565
|
}
|
|
339
566
|
catch (error) {
|
|
340
567
|
logger.warn('Failed to clear discovered models for plugin %s:', pluginId, error);
|
|
341
568
|
}
|
|
569
|
+
await publishPluginCacheInvalidation({
|
|
570
|
+
version: 1,
|
|
571
|
+
scope: 'plugin',
|
|
572
|
+
pluginId,
|
|
573
|
+
});
|
|
342
574
|
}
|
|
343
|
-
clearDiscoveredCapabilityModels(pluginId, userId) {
|
|
344
|
-
const db = getDatabaseSafe();
|
|
575
|
+
async clearDiscoveredCapabilityModels(pluginId, userId) {
|
|
345
576
|
if (userId) {
|
|
346
|
-
for (const capability of [
|
|
577
|
+
for (const capability of [
|
|
578
|
+
'image',
|
|
579
|
+
'stt',
|
|
580
|
+
'tts',
|
|
581
|
+
'audio',
|
|
582
|
+
'video',
|
|
583
|
+
]) {
|
|
347
584
|
const key = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId);
|
|
348
585
|
this.discoveredCapabilityModelsCache.delete(key);
|
|
349
586
|
this.discoveredCapabilityModelsUpdatedAt.delete(key);
|
|
350
587
|
this.capabilityDiscoveryAttemptedAt.delete(key);
|
|
351
588
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
589
|
+
// The discovery repository removes both completion and capability rows
|
|
590
|
+
// atomically, which prevents stale partial catalogs after reset.
|
|
591
|
+
await this.repositories().pluginDiscovery.delete(pluginId, userId);
|
|
356
592
|
return;
|
|
357
593
|
}
|
|
358
594
|
for (const key of this.discoveredCapabilityModelsCache.keys()) {
|
|
359
|
-
if (['image', 'tts', 'audio', 'video'].some(capability => key.endsWith(`:${pluginId}:${capability}`))) {
|
|
595
|
+
if (['image', 'stt', 'tts', 'audio', 'video'].some(capability => key.endsWith(`:${pluginId}:${capability}`))) {
|
|
360
596
|
this.discoveredCapabilityModelsCache.delete(key);
|
|
361
597
|
this.discoveredCapabilityModelsUpdatedAt.delete(key);
|
|
362
598
|
this.capabilityDiscoveryAttemptedAt.delete(key);
|
|
363
599
|
}
|
|
364
600
|
}
|
|
365
|
-
|
|
366
|
-
db.prepare('DELETE FROM plugin_discovered_capability_models WHERE plugin_id = ?').run(pluginId);
|
|
367
|
-
}
|
|
601
|
+
await this.repositories().pluginDiscovery.delete(pluginId);
|
|
368
602
|
}
|
|
369
|
-
applyDiscoveredModels(plugin, userId) {
|
|
370
|
-
if (!this.canUseStoredConnectionOverrides(userId) &&
|
|
371
|
-
pluginVariablesService.hasStoredConnectionOverride(plugin.id, userId, plugin.variables, getPluginConnectionVariableNames(plugin))) {
|
|
603
|
+
async applyDiscoveredModels(plugin, userId) {
|
|
604
|
+
if (!(await this.canUseStoredConnectionOverrides(userId)) &&
|
|
605
|
+
(await pluginVariablesService.hasStoredConnectionOverride(plugin.id, userId, plugin.variables, getPluginConnectionVariableNames(plugin)))) {
|
|
372
606
|
return plugin;
|
|
373
607
|
}
|
|
374
|
-
const models = this.getDiscoveredModels(plugin.id, userId);
|
|
608
|
+
const models = await this.getDiscoveredModels(plugin.id, userId);
|
|
375
609
|
const capabilities = plugin.capabilities
|
|
376
610
|
? { ...plugin.capabilities }
|
|
377
611
|
: undefined;
|
|
378
612
|
if (capabilities) {
|
|
379
|
-
for (const capability of [
|
|
613
|
+
for (const capability of [
|
|
614
|
+
'image',
|
|
615
|
+
'stt',
|
|
616
|
+
'tts',
|
|
617
|
+
'audio',
|
|
618
|
+
'video',
|
|
619
|
+
]) {
|
|
380
620
|
const definition = capabilities[capability];
|
|
381
|
-
const discovered = this.getDiscoveredCapabilityModels(plugin.id, capability, userId);
|
|
621
|
+
const discovered = await this.getDiscoveredCapabilityModels(plugin.id, capability, userId);
|
|
382
622
|
if (definition && discovered) {
|
|
383
623
|
capabilities[capability] = {
|
|
384
624
|
...definition,
|
|
@@ -394,8 +634,76 @@ export class PluginService {
|
|
|
394
634
|
};
|
|
395
635
|
}
|
|
396
636
|
ensurePluginsDirectory() {
|
|
397
|
-
|
|
637
|
+
const dataDirectory = resolveDataDirectory();
|
|
638
|
+
const configuredRelativeToData = path.relative(dataDirectory, this.pluginsDir);
|
|
639
|
+
const configuredPathRoot = configuredRelativeToData === '' ||
|
|
640
|
+
(configuredRelativeToData !== '..' &&
|
|
641
|
+
!configuredRelativeToData.startsWith(`..${path.sep}`) &&
|
|
642
|
+
!path.isAbsolute(configuredRelativeToData))
|
|
643
|
+
? dataDirectory
|
|
644
|
+
: process.env.PLUGINS_DIR?.trim() &&
|
|
645
|
+
!path.isAbsolute(process.env.PLUGINS_DIR.trim())
|
|
646
|
+
? PROJECT_DIRECTORY
|
|
647
|
+
: path.dirname(this.pluginsDir);
|
|
648
|
+
try {
|
|
649
|
+
if (hasSymlinkPathComponentFromRoot(configuredPathRoot, this.pluginsDir)) {
|
|
650
|
+
throw new Error('PLUGINS_DIR cannot contain a symbolic-link path component');
|
|
651
|
+
}
|
|
652
|
+
const pluginsStat = fs.lstatSync(this.pluginsDir);
|
|
653
|
+
if (!pluginsStat.isDirectory() || pluginsStat.isSymbolicLink()) {
|
|
654
|
+
throw new Error('PLUGINS_DIR must be a physical directory, not a symlink or special file');
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
catch (error) {
|
|
658
|
+
if (error.code !== 'ENOENT')
|
|
659
|
+
throw error;
|
|
398
660
|
fs.mkdirSync(this.pluginsDir, { recursive: true });
|
|
661
|
+
const createdStat = fs.lstatSync(this.pluginsDir);
|
|
662
|
+
if (!createdStat.isDirectory() || createdStat.isSymbolicLink()) {
|
|
663
|
+
throw new Error('PLUGINS_DIR could not be created safely');
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
for (const legacyDirectory of this.legacyPluginsDirs) {
|
|
667
|
+
const relativeToBackend = path.relative(BACKEND_DIRECTORY, legacyDirectory);
|
|
668
|
+
const legacyRoot = relativeToBackend === '' ||
|
|
669
|
+
(relativeToBackend !== '..' &&
|
|
670
|
+
!relativeToBackend.startsWith(`..${path.sep}`) &&
|
|
671
|
+
!path.isAbsolute(relativeToBackend))
|
|
672
|
+
? BACKEND_DIRECTORY
|
|
673
|
+
: path.dirname(legacyDirectory);
|
|
674
|
+
if (hasSymlinkPathComponentFromRoot(legacyRoot, legacyDirectory)) {
|
|
675
|
+
throw new Error('A legacy plugin path contains a symbolic-link component; refusing to follow it');
|
|
676
|
+
}
|
|
677
|
+
const legacyStat = (() => {
|
|
678
|
+
try {
|
|
679
|
+
return fs.lstatSync(legacyDirectory);
|
|
680
|
+
}
|
|
681
|
+
catch (error) {
|
|
682
|
+
if (error.code === 'ENOENT')
|
|
683
|
+
return null;
|
|
684
|
+
throw error;
|
|
685
|
+
}
|
|
686
|
+
})();
|
|
687
|
+
if (legacyStat &&
|
|
688
|
+
(!legacyStat.isDirectory() || legacyStat.isSymbolicLink())) {
|
|
689
|
+
throw new Error('A legacy plugin path is not a physical directory; refusing to follow it');
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
for (const historicalDirectory of this.historicalPluginConflictDirs) {
|
|
693
|
+
let historicalEntries;
|
|
694
|
+
try {
|
|
695
|
+
historicalEntries = fs.readdirSync(historicalDirectory, {
|
|
696
|
+
withFileTypes: true,
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
catch (error) {
|
|
700
|
+
if (error.code === 'ENOENT')
|
|
701
|
+
continue;
|
|
702
|
+
throw new Error(`Historical plugin directory ${historicalDirectory} cannot be inspected safely`);
|
|
703
|
+
}
|
|
704
|
+
if (historicalEntries.some(entry => entry.name.endsWith('.json'))) {
|
|
705
|
+
throw new Error(`Legacy plugin definitions exist at ${historicalDirectory}, where the relative PLUGINS_DIR previously resolved from the caller working directory. Move them into ${this.pluginsDir} or configure an absolute PLUGINS_DIR; Libre will not silently choose between them.`);
|
|
706
|
+
}
|
|
399
707
|
}
|
|
400
708
|
}
|
|
401
709
|
bundledPluginPath(id) {
|
|
@@ -405,19 +713,12 @@ export class PluginService {
|
|
|
405
713
|
return (path.resolve(filePath) === this.bundledPluginPath(plugin.id) &&
|
|
406
714
|
matchesBundledPluginTrustAnchor(plugin));
|
|
407
715
|
}
|
|
408
|
-
isPluginDefinitionApproved(plugin, filePath) {
|
|
716
|
+
async isPluginDefinitionApproved(plugin, filePath) {
|
|
409
717
|
if (this.isAnchoredBundledDefinition(plugin, filePath)) {
|
|
410
718
|
return true;
|
|
411
719
|
}
|
|
412
|
-
const db = getDatabaseSafe();
|
|
413
|
-
if (!db)
|
|
414
|
-
return false;
|
|
415
720
|
try {
|
|
416
|
-
const row =
|
|
417
|
-
.prepare(`SELECT definition_fingerprint, source_path
|
|
418
|
-
FROM plugin_definition_approvals
|
|
419
|
-
WHERE plugin_id = ?`)
|
|
420
|
-
.get(plugin.id);
|
|
721
|
+
const row = await this.repositories().pluginApprovals.find(plugin.id);
|
|
421
722
|
return (row?.definition_fingerprint ===
|
|
422
723
|
getPluginDefinitionFingerprint(plugin) &&
|
|
423
724
|
row.source_path === path.resolve(filePath));
|
|
@@ -427,46 +728,30 @@ export class PluginService {
|
|
|
427
728
|
return false;
|
|
428
729
|
}
|
|
429
730
|
}
|
|
430
|
-
approvePluginDefinition(plugin, filePath, userId) {
|
|
431
|
-
if (!this.canUseStoredConnectionOverrides(userId)) {
|
|
731
|
+
async approvePluginDefinition(plugin, filePath, userId) {
|
|
732
|
+
if (!(await this.canUseStoredConnectionOverrides(userId))) {
|
|
432
733
|
throw new Error('Administrator approval is required');
|
|
433
734
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
VALUES (?, ?, ?, ?, ?)
|
|
442
|
-
ON CONFLICT(plugin_id) DO UPDATE SET
|
|
443
|
-
definition_fingerprint = excluded.definition_fingerprint,
|
|
444
|
-
source_path = excluded.source_path,
|
|
445
|
-
approved_by_user_id = excluded.approved_by_user_id,
|
|
446
|
-
approved_at = excluded.approved_at`).run(plugin.id, getPluginDefinitionFingerprint(plugin), path.resolve(filePath), userId, Date.now());
|
|
447
|
-
}
|
|
448
|
-
removePluginDefinitionApproval(pluginId) {
|
|
449
|
-
const db = getDatabaseSafe();
|
|
450
|
-
if (!db)
|
|
451
|
-
return;
|
|
452
|
-
db.prepare('DELETE FROM plugin_definition_approvals WHERE plugin_id = ?').run(pluginId);
|
|
735
|
+
await this.repositories().pluginApprovals.upsert({
|
|
736
|
+
plugin_id: plugin.id,
|
|
737
|
+
definition_fingerprint: getPluginDefinitionFingerprint(plugin),
|
|
738
|
+
source_path: path.resolve(filePath),
|
|
739
|
+
approved_by_user_id: userId,
|
|
740
|
+
approved_at: Date.now(),
|
|
741
|
+
});
|
|
453
742
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
db.transaction(() => {
|
|
460
|
-
db.prepare('DELETE FROM plugin_activations WHERE plugin_id = ?').run(pluginId);
|
|
461
|
-
db.prepare('DELETE FROM plugin_definition_approvals WHERE plugin_id = ?').run(pluginId);
|
|
462
|
-
})();
|
|
743
|
+
async removePluginDefinitionApproval(pluginId) {
|
|
744
|
+
await this.repositories().pluginApprovals.delete(pluginId);
|
|
745
|
+
}
|
|
746
|
+
async revokePluginDefinitionConsent(pluginId) {
|
|
747
|
+
await this.repositories().pluginApprovals.revokeConsent(pluginId);
|
|
463
748
|
}
|
|
464
749
|
canMigrateLegacyActivation(pluginId) {
|
|
465
750
|
const effectivePath = this.resolveEffectivePluginFilePath(pluginId);
|
|
466
751
|
if (!effectivePath)
|
|
467
752
|
return false;
|
|
468
753
|
try {
|
|
469
|
-
const parsedPlugin = JSON.parse(
|
|
754
|
+
const parsedPlugin = JSON.parse(readRegularPluginDefinition(effectivePath));
|
|
470
755
|
return (this.validatePlugin(parsedPlugin) &&
|
|
471
756
|
parsedPlugin.id === pluginId &&
|
|
472
757
|
this.isAnchoredBundledDefinition(parsedPlugin, effectivePath));
|
|
@@ -482,9 +767,31 @@ export class PluginService {
|
|
|
482
767
|
for (const pluginsDir of [...this.pluginReadDirs].reverse()) {
|
|
483
768
|
const resolvedDirectory = path.resolve(pluginsDir);
|
|
484
769
|
const candidate = path.resolve(pluginsDir, `${sanitizedId}.json`);
|
|
485
|
-
if (candidate.startsWith(resolvedDirectory)
|
|
770
|
+
if (!candidate.startsWith(resolvedDirectory))
|
|
771
|
+
continue;
|
|
772
|
+
const directoryStat = (() => {
|
|
773
|
+
try {
|
|
774
|
+
return fs.lstatSync(pluginsDir);
|
|
775
|
+
}
|
|
776
|
+
catch {
|
|
777
|
+
return null;
|
|
778
|
+
}
|
|
779
|
+
})();
|
|
780
|
+
if (directoryStat &&
|
|
781
|
+
(!directoryStat.isDirectory() || directoryStat.isSymbolicLink())) {
|
|
782
|
+
// Preserve precedence while forcing the no-follow reader to reject the
|
|
783
|
+
// unsafe path instead of falling back to a lower-priority definition.
|
|
486
784
|
return candidate;
|
|
487
785
|
}
|
|
786
|
+
try {
|
|
787
|
+
fs.lstatSync(candidate);
|
|
788
|
+
// Return invalid named entries too. The strict reader will reject them,
|
|
789
|
+
// preventing a symlink/special-file shadow from revealing a bundled ID.
|
|
790
|
+
return candidate;
|
|
791
|
+
}
|
|
792
|
+
catch {
|
|
793
|
+
// Continue to lower-priority sources only when the named entry is absent.
|
|
794
|
+
}
|
|
488
795
|
}
|
|
489
796
|
return null;
|
|
490
797
|
}
|
|
@@ -503,7 +810,7 @@ export class PluginService {
|
|
|
503
810
|
return null;
|
|
504
811
|
}
|
|
505
812
|
try {
|
|
506
|
-
const parsedPlugin = JSON.parse(
|
|
813
|
+
const parsedPlugin = JSON.parse(readRegularPluginDefinition(bundledPath));
|
|
507
814
|
if (!this.validatePlugin(parsedPlugin) ||
|
|
508
815
|
parsedPlugin.id !== sanitizedId ||
|
|
509
816
|
!matchesBundledPluginTrustAnchor(parsedPlugin)) {
|
|
@@ -521,6 +828,10 @@ export class PluginService {
|
|
|
521
828
|
}
|
|
522
829
|
}
|
|
523
830
|
usesTrustedBundledRouting(plugin) {
|
|
831
|
+
if (this.sharedPluginDefinitions &&
|
|
832
|
+
this.sharedDefinitionIds.has(plugin.id)) {
|
|
833
|
+
return false;
|
|
834
|
+
}
|
|
524
835
|
const effectivePath = this.resolveEffectivePluginFilePath(plugin.id);
|
|
525
836
|
const bundledPath = this.bundledPluginPath(plugin.id);
|
|
526
837
|
if (!effectivePath || effectivePath !== bundledPath)
|
|
@@ -529,18 +840,12 @@ export class PluginService {
|
|
|
529
840
|
return (bundledProjection !== null &&
|
|
530
841
|
getPluginRoutingAuthProjection(plugin) === bundledProjection);
|
|
531
842
|
}
|
|
532
|
-
isPluginActive(pluginId, userId) {
|
|
533
|
-
return pluginActivationService.getActivePluginIds(userId).has(pluginId);
|
|
843
|
+
async isPluginActive(pluginId, userId) {
|
|
844
|
+
return (await pluginActivationService.getActivePluginIds(userId)).has(pluginId);
|
|
534
845
|
}
|
|
535
|
-
canUseStoredConnectionOverrides(userId) {
|
|
536
|
-
const db = getDatabaseSafe();
|
|
537
|
-
if (!db)
|
|
538
|
-
return false;
|
|
846
|
+
async canUseStoredConnectionOverrides(userId) {
|
|
539
847
|
try {
|
|
540
|
-
|
|
541
|
-
.prepare('SELECT role FROM users WHERE id = ?')
|
|
542
|
-
.get(userId || 'default');
|
|
543
|
-
return row?.role === 'admin';
|
|
848
|
+
return ((await userModel.getUserById(userId || 'default'))?.role === 'admin');
|
|
544
849
|
}
|
|
545
850
|
catch (error) {
|
|
546
851
|
logger.warn('Failed to resolve plugin routing permission:', error);
|
|
@@ -553,7 +858,7 @@ export class PluginService {
|
|
|
553
858
|
* @param userId Optional user ID for per-user credentials
|
|
554
859
|
* @returns The API key or null if not found
|
|
555
860
|
*/
|
|
556
|
-
getApiKey(plugin, userId) {
|
|
861
|
+
async getApiKey(plugin, userId) {
|
|
557
862
|
if (plugin.id === CODEX_OAUTH_PLUGIN_ID) {
|
|
558
863
|
// Resolved from the server's Codex CLI sign-in, never user credentials.
|
|
559
864
|
// A writable same-ID definition must never receive the server user's
|
|
@@ -563,13 +868,13 @@ export class PluginService {
|
|
|
563
868
|
? codexOAuthService.getCachedAccessToken()
|
|
564
869
|
: null;
|
|
565
870
|
}
|
|
566
|
-
const hasHonoredConnectionOverride = this.canUseStoredConnectionOverrides(userId) &&
|
|
567
|
-
pluginVariablesService.hasStoredConnectionOverride(plugin.id, userId, plugin.variables, getPluginConnectionVariableNames(plugin));
|
|
871
|
+
const hasHonoredConnectionOverride = (await this.canUseStoredConnectionOverrides(userId)) &&
|
|
872
|
+
(await pluginVariablesService.hasStoredConnectionOverride(plugin.id, userId, plugin.variables, getPluginConnectionVariableNames(plugin)));
|
|
568
873
|
const usesTrustedBundledRouting = this.usesTrustedBundledRouting(plugin);
|
|
569
874
|
const allowTrustedFallback = usesTrustedBundledRouting && !hasHonoredConnectionOverride;
|
|
570
875
|
return pluginCredentialsService.getApiKey(plugin.id, plugin.auth.key_env, userId, {
|
|
571
876
|
allowEnvironmentFallback: allowTrustedFallback,
|
|
572
|
-
expectedRoutingAuthFingerprint: this.getCredentialRoutingAuthFingerprint(plugin, userId),
|
|
877
|
+
expectedRoutingAuthFingerprint: await this.getCredentialRoutingAuthFingerprint(plugin, userId),
|
|
573
878
|
allowLegacyUnboundCredential: allowTrustedFallback,
|
|
574
879
|
});
|
|
575
880
|
}
|
|
@@ -577,8 +882,8 @@ export class PluginService {
|
|
|
577
882
|
* Bind a user credential to the exact routing/authentication contract in
|
|
578
883
|
* effect when they save it. Generation controls are intentionally excluded.
|
|
579
884
|
*/
|
|
580
|
-
getCredentialRoutingAuthFingerprint(plugin, userId) {
|
|
581
|
-
const variables = this.getPluginVariables(plugin, userId);
|
|
885
|
+
async getCredentialRoutingAuthFingerprint(plugin, userId) {
|
|
886
|
+
const variables = await this.getPluginVariables(plugin, userId);
|
|
582
887
|
const effectiveConnectionValues = Array.from(getPluginConnectionVariableNames(plugin), name => {
|
|
583
888
|
const definition = plugin.variables?.find(candidate => candidate.name === name);
|
|
584
889
|
if (!definition)
|
|
@@ -588,11 +893,18 @@ export class PluginService {
|
|
|
588
893
|
value: variables[name] ?? definition.default ?? '',
|
|
589
894
|
};
|
|
590
895
|
});
|
|
591
|
-
const
|
|
896
|
+
const sharedDefinition = this.sharedPluginDefinitions
|
|
897
|
+
? await this.repositories().pluginDefinitions.find(plugin.id)
|
|
898
|
+
: null;
|
|
899
|
+
if (sharedDefinition)
|
|
900
|
+
this.sharedDefinitionIds.add(plugin.id);
|
|
901
|
+
const effectivePath = sharedDefinition
|
|
902
|
+
? null
|
|
903
|
+
: this.resolveEffectivePluginFilePath(plugin.id);
|
|
592
904
|
let effectiveDefinitionFingerprint = getPluginDefinitionFingerprint(plugin);
|
|
593
905
|
if (effectivePath) {
|
|
594
906
|
try {
|
|
595
|
-
const effectiveDefinition = JSON.parse(
|
|
907
|
+
const effectiveDefinition = JSON.parse(readRegularPluginDefinition(effectivePath));
|
|
596
908
|
if (this.validatePlugin(effectiveDefinition) &&
|
|
597
909
|
effectiveDefinition.id === plugin.id) {
|
|
598
910
|
effectiveDefinitionFingerprint =
|
|
@@ -608,7 +920,11 @@ export class PluginService {
|
|
|
608
920
|
plugin_id: plugin.id,
|
|
609
921
|
plugin_type: plugin.type,
|
|
610
922
|
trusted_bundled_source: this.usesTrustedBundledRouting(plugin),
|
|
611
|
-
effective_source_path:
|
|
923
|
+
effective_source_path: sharedDefinition
|
|
924
|
+
? 'database:plugin_definitions'
|
|
925
|
+
: effectivePath
|
|
926
|
+
? path.resolve(effectivePath)
|
|
927
|
+
: null,
|
|
612
928
|
effective_definition_fingerprint: effectiveDefinitionFingerprint,
|
|
613
929
|
routing_auth_projection: getPluginRoutingAuthProjection(plugin),
|
|
614
930
|
effective_connection_values: effectiveConnectionValues,
|
|
@@ -618,12 +934,12 @@ export class PluginService {
|
|
|
618
934
|
/**
|
|
619
935
|
* Get resolved variable values for a plugin (decrypted, typed).
|
|
620
936
|
*/
|
|
621
|
-
getPluginVariables(plugin, userId) {
|
|
937
|
+
async getPluginVariables(plugin, userId) {
|
|
622
938
|
if (!plugin.variables || plugin.variables.length === 0) {
|
|
623
939
|
return {};
|
|
624
940
|
}
|
|
625
|
-
const variables = pluginVariablesService.getResolvedVariables(plugin.id, plugin.variables, userId);
|
|
626
|
-
if (this.canUseStoredConnectionOverrides(userId))
|
|
941
|
+
const variables = await pluginVariablesService.getResolvedVariables(plugin.id, plugin.variables, userId);
|
|
942
|
+
if (await this.canUseStoredConnectionOverrides(userId))
|
|
627
943
|
return variables;
|
|
628
944
|
return Object.fromEntries(Object.entries(variables).map(([name, value]) => {
|
|
629
945
|
if (!getPluginConnectionVariableNames(plugin).has(name)) {
|
|
@@ -646,8 +962,8 @@ export class PluginService {
|
|
|
646
962
|
* boundary ordered prevents a rejected override from ever selecting an
|
|
647
963
|
* environment credential.
|
|
648
964
|
*/
|
|
649
|
-
resolveOperationEndpoint(plugin, userId) {
|
|
650
|
-
return resolvePluginApiConfig(plugin, this.getPluginVariables(plugin, userId)).endpoint;
|
|
965
|
+
async resolveOperationEndpoint(plugin, userId) {
|
|
966
|
+
return resolvePluginApiConfig(plugin, await this.getPluginVariables(plugin, userId)).endpoint;
|
|
651
967
|
}
|
|
652
968
|
/**
|
|
653
969
|
* Attempt to auto-discover available models from a plugin's full API endpoint.
|
|
@@ -665,12 +981,16 @@ export class PluginService {
|
|
|
665
981
|
* is fresh.
|
|
666
982
|
*/
|
|
667
983
|
async discoverModelsResult(pluginId, userId) {
|
|
984
|
+
await this.ensureCacheInvalidation();
|
|
668
985
|
const cacheKey = this.discoveredModelsCacheKey(pluginId, userId || 'default');
|
|
669
986
|
const inflight = this.inflightDiscovery.get(cacheKey);
|
|
670
987
|
if (inflight)
|
|
671
988
|
return inflight;
|
|
672
|
-
const
|
|
673
|
-
|
|
989
|
+
const revision = this.discoveryCacheRevisions.get(cacheKey) ?? 0;
|
|
990
|
+
const attempt = this.runModelDiscovery(pluginId, userId, revision).finally(() => {
|
|
991
|
+
if (this.inflightDiscovery.get(cacheKey) === attempt) {
|
|
992
|
+
this.inflightDiscovery.delete(cacheKey);
|
|
993
|
+
}
|
|
674
994
|
});
|
|
675
995
|
this.inflightDiscovery.set(cacheKey, attempt);
|
|
676
996
|
return attempt;
|
|
@@ -680,13 +1000,13 @@ export class PluginService {
|
|
|
680
1000
|
* immediately; stored ones age out after the TTL. Both cases are gated by a
|
|
681
1001
|
* per-plugin backoff so a failing provider is not probed on every request.
|
|
682
1002
|
*/
|
|
683
|
-
isModelDiscoveryDue(pluginId, userId) {
|
|
1003
|
+
async isModelDiscoveryDue(pluginId, userId) {
|
|
684
1004
|
const cacheKey = this.discoveredModelsCacheKey(pluginId, userId || 'default');
|
|
685
1005
|
const attemptedAt = this.discoveryAttemptedAt.get(cacheKey);
|
|
686
1006
|
if (attemptedAt && Date.now() - attemptedAt < modelDiscoveryRetryMs()) {
|
|
687
1007
|
return false;
|
|
688
1008
|
}
|
|
689
|
-
const models = this.getDiscoveredModels(pluginId, userId);
|
|
1009
|
+
const models = await this.getDiscoveredModels(pluginId, userId);
|
|
690
1010
|
const updatedAt = this.discoveredModelsUpdatedAt.get(cacheKey);
|
|
691
1011
|
if (!models || !updatedAt)
|
|
692
1012
|
return true;
|
|
@@ -699,8 +1019,13 @@ export class PluginService {
|
|
|
699
1019
|
* the next request.
|
|
700
1020
|
*/
|
|
701
1021
|
async refreshStaleModels(userId) {
|
|
702
|
-
const due =
|
|
703
|
-
|
|
1022
|
+
const due = [];
|
|
1023
|
+
for (const plugin of await this.getActivePlugins(userId)) {
|
|
1024
|
+
if ((plugin.type === 'completion' || plugin.type === 'chat') &&
|
|
1025
|
+
(await this.isModelDiscoveryDue(plugin.id, userId))) {
|
|
1026
|
+
due.push(plugin);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
704
1029
|
if (due.length === 0)
|
|
705
1030
|
return;
|
|
706
1031
|
const refreshes = Promise.all(due.map(plugin => this.discoverModels(plugin.id, userId).catch(() => [])));
|
|
@@ -710,30 +1035,39 @@ export class PluginService {
|
|
|
710
1035
|
]);
|
|
711
1036
|
}
|
|
712
1037
|
async discoverCapabilityModels(pluginId, capability, userId) {
|
|
1038
|
+
await this.ensureCacheInvalidation();
|
|
713
1039
|
const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId || 'default');
|
|
714
1040
|
const inflight = this.inflightCapabilityDiscovery.get(cacheKey);
|
|
715
1041
|
if (inflight)
|
|
716
1042
|
return inflight;
|
|
717
|
-
const
|
|
1043
|
+
const revision = this.capabilityDiscoveryCacheRevisions.get(cacheKey) ?? 0;
|
|
1044
|
+
const attempt = this.runCapabilityModelDiscovery(pluginId, capability, userId, revision).finally(() => {
|
|
1045
|
+
if (this.inflightCapabilityDiscovery.get(cacheKey) === attempt) {
|
|
1046
|
+
this.inflightCapabilityDiscovery.delete(cacheKey);
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
718
1049
|
this.inflightCapabilityDiscovery.set(cacheKey, attempt);
|
|
719
1050
|
return attempt;
|
|
720
1051
|
}
|
|
721
|
-
isCapabilityModelDiscoveryDue(pluginId, capability, userId) {
|
|
1052
|
+
async isCapabilityModelDiscoveryDue(pluginId, capability, userId) {
|
|
722
1053
|
const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId || 'default');
|
|
723
1054
|
const attemptedAt = this.capabilityDiscoveryAttemptedAt.get(cacheKey);
|
|
724
1055
|
if (attemptedAt && Date.now() - attemptedAt < modelDiscoveryRetryMs()) {
|
|
725
1056
|
return false;
|
|
726
1057
|
}
|
|
727
|
-
const models = this.getDiscoveredCapabilityModels(pluginId, capability, userId);
|
|
1058
|
+
const models = await this.getDiscoveredCapabilityModels(pluginId, capability, userId);
|
|
728
1059
|
const updatedAt = this.discoveredCapabilityModelsUpdatedAt.get(cacheKey);
|
|
729
1060
|
return (!models || !updatedAt || Date.now() - updatedAt >= modelDiscoveryTtlMs());
|
|
730
1061
|
}
|
|
731
1062
|
async refreshStaleCapabilityModels(capability, userId) {
|
|
732
|
-
const due =
|
|
1063
|
+
const due = [];
|
|
1064
|
+
for (const plugin of await this.getActivePlugins(userId)) {
|
|
733
1065
|
const definition = plugin.capabilities?.[capability];
|
|
734
|
-
|
|
735
|
-
this.isCapabilityModelDiscoveryDue(plugin.id, capability, userId))
|
|
736
|
-
|
|
1066
|
+
if (Boolean(definition?.models_endpoint) &&
|
|
1067
|
+
(await this.isCapabilityModelDiscoveryDue(plugin.id, capability, userId))) {
|
|
1068
|
+
due.push(plugin);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
737
1071
|
if (due.length === 0)
|
|
738
1072
|
return;
|
|
739
1073
|
const refreshes = Promise.all(due.map(plugin => this.discoverCapabilityModels(plugin.id, capability, userId).catch(() => undefined)));
|
|
@@ -742,8 +1076,8 @@ export class PluginService {
|
|
|
742
1076
|
new Promise(resolve => setTimeout(resolve, modelDiscoveryRefreshDeadlineMs()).unref?.()),
|
|
743
1077
|
]);
|
|
744
1078
|
}
|
|
745
|
-
async runCapabilityModelDiscovery(pluginId, capability, userId) {
|
|
746
|
-
const plugin = this.getPlugin(pluginId, userId);
|
|
1079
|
+
async runCapabilityModelDiscovery(pluginId, capability, userId, expectedRevision) {
|
|
1080
|
+
const plugin = await this.getPlugin(pluginId, userId);
|
|
747
1081
|
const definition = plugin?.capabilities?.[capability];
|
|
748
1082
|
if (!plugin || !definition) {
|
|
749
1083
|
return {
|
|
@@ -757,9 +1091,20 @@ export class PluginService {
|
|
|
757
1091
|
}
|
|
758
1092
|
const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId || 'default');
|
|
759
1093
|
this.capabilityDiscoveryAttemptedAt.set(cacheKey, Date.now());
|
|
760
|
-
const
|
|
1094
|
+
const config = definition.config && typeof definition.config === 'object'
|
|
1095
|
+
? definition.config
|
|
1096
|
+
: {};
|
|
1097
|
+
const modelsEndpointVariable = config.models_endpoint_variable;
|
|
1098
|
+
const pluginVariables = await this.getPluginVariables(plugin, userId);
|
|
1099
|
+
const modelsEndpointOverride = typeof modelsEndpointVariable === 'string'
|
|
1100
|
+
? pluginVariables[modelsEndpointVariable]
|
|
1101
|
+
: undefined;
|
|
1102
|
+
const modelsEndpoint = typeof modelsEndpointOverride === 'string' &&
|
|
1103
|
+
modelsEndpointOverride.trim().length > 0
|
|
1104
|
+
? this.validateEndpointUrl(modelsEndpointOverride.trim())
|
|
1105
|
+
: definition.models_endpoint;
|
|
761
1106
|
assertSafePluginEndpoint(modelsEndpoint, `${capability} model discovery endpoint`);
|
|
762
|
-
const apiKey = this.getApiKey(plugin, userId);
|
|
1107
|
+
const apiKey = await this.getApiKey(plugin, userId);
|
|
763
1108
|
if (pluginRequiresApiKey(plugin) && !apiKey) {
|
|
764
1109
|
return {
|
|
765
1110
|
models: definition.model_map,
|
|
@@ -787,7 +1132,15 @@ export class PluginService {
|
|
|
787
1132
|
};
|
|
788
1133
|
}
|
|
789
1134
|
const previous = definition.model_map;
|
|
790
|
-
this.
|
|
1135
|
+
if ((this.capabilityDiscoveryCacheRevisions.get(cacheKey) ?? 0) !==
|
|
1136
|
+
expectedRevision) {
|
|
1137
|
+
return {
|
|
1138
|
+
models: previous,
|
|
1139
|
+
outcome: 'unavailable',
|
|
1140
|
+
reason: 'Provider configuration changed during discovery',
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
await this.storeDiscoveredCapabilityModels(pluginId, capability, models, userId);
|
|
791
1144
|
return {
|
|
792
1145
|
models,
|
|
793
1146
|
outcome: JSON.stringify(previous) === JSON.stringify(models)
|
|
@@ -816,19 +1169,19 @@ export class PluginService {
|
|
|
816
1169
|
}
|
|
817
1170
|
return 'No API key is configured for this provider.';
|
|
818
1171
|
}
|
|
819
|
-
async runModelDiscovery(pluginId, userId) {
|
|
820
|
-
const plugin = this.getPlugin(pluginId, userId);
|
|
1172
|
+
async runModelDiscovery(pluginId, userId, expectedRevision) {
|
|
1173
|
+
const plugin = await this.getPlugin(pluginId, userId);
|
|
821
1174
|
if (!plugin) {
|
|
822
1175
|
return { models: [], outcome: 'unavailable', reason: 'Plugin not found' };
|
|
823
1176
|
}
|
|
824
1177
|
this.discoveryAttemptedAt.set(this.discoveredModelsCacheKey(pluginId, userId || 'default'), Date.now());
|
|
825
|
-
const pluginVars = this.getPluginVariables(plugin, userId);
|
|
1178
|
+
const pluginVars = await this.getPluginVariables(plugin, userId);
|
|
826
1179
|
const { endpoint: effectiveEndpoint } = resolvePluginApiConfig(plugin, pluginVars);
|
|
827
1180
|
const modelsEndpoint = resolvePluginModelsEndpoint(effectiveEndpoint, typeof pluginVars.models_endpoint === 'string'
|
|
828
1181
|
? pluginVars.models_endpoint
|
|
829
1182
|
: undefined);
|
|
830
1183
|
assertSafePluginEndpoint(modelsEndpoint, 'model discovery endpoint');
|
|
831
|
-
const apiKey = this.getApiKey(plugin, userId);
|
|
1184
|
+
const apiKey = await this.getApiKey(plugin, userId);
|
|
832
1185
|
if (pluginRequiresApiKey(plugin) && !apiKey) {
|
|
833
1186
|
logger.debug('[Plugin] Model discovery for %s has no usable API key; keeping the existing catalog', pluginId);
|
|
834
1187
|
return {
|
|
@@ -851,8 +1204,17 @@ export class PluginService {
|
|
|
851
1204
|
if (models.length > 0) {
|
|
852
1205
|
logger.debug('[Plugin] Auto-discovered %d models for %s:', models.length, pluginId, models);
|
|
853
1206
|
const previousModels = plugin.model_map;
|
|
854
|
-
this.
|
|
855
|
-
|
|
1207
|
+
const cacheKey = this.discoveredModelsCacheKey(pluginId, userId || 'default');
|
|
1208
|
+
if ((this.discoveryCacheRevisions.get(cacheKey) ?? 0) !==
|
|
1209
|
+
expectedRevision) {
|
|
1210
|
+
return {
|
|
1211
|
+
models: previousModels,
|
|
1212
|
+
outcome: 'unavailable',
|
|
1213
|
+
reason: 'Provider configuration changed during discovery',
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
await this.storeDiscoveredModels(pluginId, models, userId);
|
|
1217
|
+
const stored = (await this.getDiscoveredModels(pluginId, userId)) || models;
|
|
856
1218
|
return {
|
|
857
1219
|
models: stored,
|
|
858
1220
|
outcome: JSON.stringify(stored) === JSON.stringify(previousModels)
|
|
@@ -874,26 +1236,46 @@ export class PluginService {
|
|
|
874
1236
|
}
|
|
875
1237
|
}
|
|
876
1238
|
// List all installed plugins
|
|
877
|
-
|
|
1239
|
+
async getAllPluginsUnchecked(userId) {
|
|
1240
|
+
await this.ensureLegacyActivationMigration();
|
|
878
1241
|
const plugins = new Map();
|
|
879
|
-
const activePluginIds = pluginActivationService.getActivePluginIds(userId);
|
|
1242
|
+
const activePluginIds = await pluginActivationService.getActivePluginIds(userId);
|
|
880
1243
|
for (const pluginsDir of this.pluginReadDirs) {
|
|
881
|
-
|
|
1244
|
+
const directoryStat = (() => {
|
|
1245
|
+
try {
|
|
1246
|
+
return fs.lstatSync(pluginsDir);
|
|
1247
|
+
}
|
|
1248
|
+
catch {
|
|
1249
|
+
return null;
|
|
1250
|
+
}
|
|
1251
|
+
})();
|
|
1252
|
+
if (!directoryStat) {
|
|
1253
|
+
continue;
|
|
1254
|
+
}
|
|
1255
|
+
if (!directoryStat.isDirectory() || directoryStat.isSymbolicLink()) {
|
|
1256
|
+
plugins.clear();
|
|
1257
|
+
logger.error('Ignoring unsafe plugin directory %s and every lower-priority definition', pluginsDir);
|
|
882
1258
|
continue;
|
|
883
1259
|
}
|
|
884
1260
|
try {
|
|
885
|
-
const
|
|
886
|
-
for (const
|
|
1261
|
+
const entries = fs.readdirSync(pluginsDir, { withFileTypes: true });
|
|
1262
|
+
for (const entry of entries) {
|
|
1263
|
+
const file = entry.name;
|
|
887
1264
|
if (file.endsWith('.json') && !file.startsWith('.')) {
|
|
888
1265
|
const filenameId = path.basename(file, '.json');
|
|
889
1266
|
try {
|
|
890
1267
|
const filePath = path.join(pluginsDir, file);
|
|
891
|
-
|
|
1268
|
+
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
1269
|
+
plugins.delete(filenameId);
|
|
1270
|
+
logger.error('Ignoring non-regular plugin definition %s', filePath);
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
const content = readRegularPluginDefinition(filePath);
|
|
892
1274
|
const parsedPlugin = JSON.parse(content);
|
|
893
1275
|
// Validate plugin structure
|
|
894
1276
|
if (this.validatePlugin(parsedPlugin) &&
|
|
895
1277
|
parsedPlugin.id === filenameId) {
|
|
896
|
-
if (!this.isPluginDefinitionApproved(parsedPlugin, filePath)) {
|
|
1278
|
+
if (!(await this.isPluginDefinitionApproved(parsedPlugin, filePath))) {
|
|
897
1279
|
// A later writable definition shadows an earlier bundled
|
|
898
1280
|
// definition even while quarantined.
|
|
899
1281
|
plugins.delete(parsedPlugin.id);
|
|
@@ -901,7 +1283,7 @@ export class PluginService {
|
|
|
901
1283
|
}
|
|
902
1284
|
const plugin = applyPluginDefinitionPolicy(parsedPlugin);
|
|
903
1285
|
plugin.active = activePluginIds.has(plugin.id);
|
|
904
|
-
plugins.set(plugin.id, this.applyDiscoveredModels(plugin, userId));
|
|
1286
|
+
plugins.set(plugin.id, await this.applyDiscoveredModels(plugin, userId));
|
|
905
1287
|
}
|
|
906
1288
|
else if (parsedPlugin.id !== filenameId) {
|
|
907
1289
|
plugins.delete(filenameId);
|
|
@@ -924,41 +1306,84 @@ export class PluginService {
|
|
|
924
1306
|
logger.error(`Failed to read plugins directory ${pluginsDir}:`, error);
|
|
925
1307
|
}
|
|
926
1308
|
}
|
|
927
|
-
|
|
1309
|
+
if (this.sharedPluginDefinitions) {
|
|
1310
|
+
const definitions = await this.repositories().pluginDefinitions.list();
|
|
1311
|
+
const currentDefinitionIds = new Set(definitions.map(definition => definition.plugin_id));
|
|
1312
|
+
for (const pluginId of this.sharedDefinitionIds) {
|
|
1313
|
+
if (!currentDefinitionIds.has(pluginId)) {
|
|
1314
|
+
this.sharedDefinitionIds.delete(pluginId);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
for (const definition of definitions) {
|
|
1318
|
+
// The shared row has precedence over bundled release assets even when
|
|
1319
|
+
// corrupt or unapproved, preserving quarantine rather than silently
|
|
1320
|
+
// changing the provider route on another replica.
|
|
1321
|
+
plugins.delete(definition.plugin_id);
|
|
1322
|
+
const plugin = this.parseSharedPluginDefinition(definition);
|
|
1323
|
+
if (!plugin) {
|
|
1324
|
+
logger.error('Ignoring invalid or unapproved shared plugin definition %s', definition.plugin_id);
|
|
1325
|
+
continue;
|
|
1326
|
+
}
|
|
1327
|
+
plugin.active = activePluginIds.has(plugin.id);
|
|
1328
|
+
plugins.set(plugin.id, await this.applyDiscoveredModels(plugin, userId));
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return Array.from(plugins.values());
|
|
1332
|
+
}
|
|
1333
|
+
async getAllPlugins(userId) {
|
|
1334
|
+
const plugins = await this.getAllPluginsUnchecked(userId);
|
|
1335
|
+
const visible = [];
|
|
1336
|
+
for (const plugin of plugins) {
|
|
1337
|
+
if (await this.isPluginVisibleToUser(plugin, userId)) {
|
|
1338
|
+
visible.push(plugin);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
return visible;
|
|
928
1342
|
}
|
|
929
1343
|
/**
|
|
930
1344
|
* The codex-oauth plugin rides the server user's ChatGPT sign-in, so it is
|
|
931
1345
|
* administrator-only and hidden entirely when no sign-in exists.
|
|
932
1346
|
*/
|
|
933
|
-
isPluginVisibleToUser(plugin, userId) {
|
|
1347
|
+
async isPluginVisibleToUser(plugin, userId) {
|
|
934
1348
|
if (plugin.id !== CODEX_OAUTH_PLUGIN_ID)
|
|
935
1349
|
return true;
|
|
936
1350
|
if (!codexOAuthService.isAvailable())
|
|
937
1351
|
return false;
|
|
938
1352
|
if (!userId)
|
|
939
1353
|
return false;
|
|
940
|
-
return userModel.getUserById(userId)?.role === 'admin';
|
|
1354
|
+
return (await userModel.getUserById(userId))?.role === 'admin';
|
|
941
1355
|
}
|
|
942
1356
|
// Get a specific plugin by ID
|
|
943
|
-
|
|
1357
|
+
async loadPlugin(id, userId) {
|
|
1358
|
+
await this.ensureLegacyActivationMigration();
|
|
944
1359
|
// Sanitize the ID to prevent path traversal
|
|
945
1360
|
const sanitizedId = sanitize(id);
|
|
946
1361
|
if (!sanitizedId || sanitizedId !== id) {
|
|
947
1362
|
logger.error('Invalid plugin ID provided:', id);
|
|
948
1363
|
return null;
|
|
949
1364
|
}
|
|
1365
|
+
if (this.sharedPluginDefinitions) {
|
|
1366
|
+
const definition = await this.repositories().pluginDefinitions.find(sanitizedId);
|
|
1367
|
+
if (definition) {
|
|
1368
|
+
const plugin = this.parseSharedPluginDefinition(definition);
|
|
1369
|
+
if (!plugin)
|
|
1370
|
+
return null;
|
|
1371
|
+
plugin.active = await this.isPluginActive(plugin.id, userId);
|
|
1372
|
+
return this.applyDiscoveredModels(plugin, userId);
|
|
1373
|
+
}
|
|
1374
|
+
this.sharedDefinitionIds.delete(sanitizedId);
|
|
1375
|
+
}
|
|
950
1376
|
const filePath = this.resolveEffectivePluginFilePath(sanitizedId);
|
|
951
1377
|
if (!filePath)
|
|
952
1378
|
return null;
|
|
953
1379
|
try {
|
|
954
|
-
const content =
|
|
1380
|
+
const content = readRegularPluginDefinition(filePath);
|
|
955
1381
|
const parsedPlugin = JSON.parse(content);
|
|
956
1382
|
if (this.validatePlugin(parsedPlugin) &&
|
|
957
1383
|
parsedPlugin.id === sanitizedId &&
|
|
958
|
-
this.isPluginDefinitionApproved(parsedPlugin, filePath)
|
|
959
|
-
this.isPluginVisibleToUser(parsedPlugin, userId)) {
|
|
1384
|
+
(await this.isPluginDefinitionApproved(parsedPlugin, filePath))) {
|
|
960
1385
|
const plugin = applyPluginDefinitionPolicy(parsedPlugin);
|
|
961
|
-
plugin.active = this.isPluginActive(plugin.id, userId);
|
|
1386
|
+
plugin.active = await this.isPluginActive(plugin.id, userId);
|
|
962
1387
|
return this.applyDiscoveredModels(plugin, userId);
|
|
963
1388
|
}
|
|
964
1389
|
}
|
|
@@ -967,15 +1392,29 @@ export class PluginService {
|
|
|
967
1392
|
}
|
|
968
1393
|
return null;
|
|
969
1394
|
}
|
|
1395
|
+
async getPluginUnchecked(id, userId) {
|
|
1396
|
+
if (id === CODEX_OAUTH_PLUGIN_ID)
|
|
1397
|
+
return null;
|
|
1398
|
+
return this.loadPlugin(id, userId);
|
|
1399
|
+
}
|
|
1400
|
+
async getPlugin(id, userId) {
|
|
1401
|
+
const plugin = await this.loadPlugin(id, userId);
|
|
1402
|
+
if (!plugin || !(await this.isPluginVisibleToUser(plugin, userId))) {
|
|
1403
|
+
return null;
|
|
1404
|
+
}
|
|
1405
|
+
return plugin;
|
|
1406
|
+
}
|
|
970
1407
|
// Install or update a plugin
|
|
971
|
-
installPlugin(pluginData, approvedByUserId) {
|
|
1408
|
+
async installPlugin(pluginData, approvedByUserId) {
|
|
1409
|
+
if (!this.sharedPluginDefinitions)
|
|
1410
|
+
this.ensurePluginsDirectory();
|
|
972
1411
|
if (!this.validatePlugin(pluginData)) {
|
|
973
1412
|
throw new Error('Invalid plugin structure');
|
|
974
1413
|
}
|
|
975
1414
|
if (pluginData.id === CODEX_OAUTH_PLUGIN_ID) {
|
|
976
1415
|
throw new Error('The bundled Codex OAuth plugin ID is reserved');
|
|
977
1416
|
}
|
|
978
|
-
if (!this.canUseStoredConnectionOverrides(approvedByUserId)) {
|
|
1417
|
+
if (!(await this.canUseStoredConnectionOverrides(approvedByUserId))) {
|
|
979
1418
|
throw new Error('Administrator approval is required');
|
|
980
1419
|
}
|
|
981
1420
|
const now = Date.now();
|
|
@@ -988,6 +1427,20 @@ export class PluginService {
|
|
|
988
1427
|
const safeId = plugin.id.replace(/[^a-zA-Z0-9_.-]/g, '');
|
|
989
1428
|
if (safeId !== plugin.id)
|
|
990
1429
|
throw new Error('Invalid plugin ID');
|
|
1430
|
+
if (this.sharedPluginDefinitions) {
|
|
1431
|
+
await this.repositories().pluginDefinitions.replaceApproved({
|
|
1432
|
+
plugin_id: plugin.id,
|
|
1433
|
+
definition_json: JSON.stringify(plugin, null, 2),
|
|
1434
|
+
definition_fingerprint: getPluginDefinitionFingerprint(plugin),
|
|
1435
|
+
approved_by_user_id: approvedByUserId,
|
|
1436
|
+
approved_at: now,
|
|
1437
|
+
created_at: plugin.created_at || now,
|
|
1438
|
+
updated_at: now,
|
|
1439
|
+
});
|
|
1440
|
+
this.sharedDefinitionIds.add(plugin.id);
|
|
1441
|
+
await this.clearDiscoveredModels(plugin.id);
|
|
1442
|
+
return plugin;
|
|
1443
|
+
}
|
|
991
1444
|
const filePath = path.resolve(this.pluginsDir, `${safeId}.json`);
|
|
992
1445
|
if (!filePath.startsWith(path.resolve(this.pluginsDir))) {
|
|
993
1446
|
throw new Error('Path traversal detected');
|
|
@@ -995,8 +1448,8 @@ export class PluginService {
|
|
|
995
1448
|
// Revoke definition approval and every user's activation before replacing
|
|
996
1449
|
// bytes on disk. Any crash or write failure therefore leaves the provider
|
|
997
1450
|
// quarantined and inactive.
|
|
998
|
-
this.revokePluginDefinitionConsent(plugin.id);
|
|
999
|
-
this.clearDiscoveredModels(plugin.id);
|
|
1451
|
+
await this.revokePluginDefinitionConsent(plugin.id);
|
|
1452
|
+
await this.clearDiscoveredModels(plugin.id);
|
|
1000
1453
|
const temporaryPath = path.resolve(this.pluginsDir, `.${safeId}.${process.pid}.${Date.now()}.tmp`);
|
|
1001
1454
|
try {
|
|
1002
1455
|
fs.writeFileSync(temporaryPath, JSON.stringify(plugin, null, 2), {
|
|
@@ -1010,11 +1463,11 @@ export class PluginService {
|
|
|
1010
1463
|
}
|
|
1011
1464
|
throw error;
|
|
1012
1465
|
}
|
|
1013
|
-
this.approvePluginDefinition(plugin, filePath, approvedByUserId);
|
|
1466
|
+
await this.approvePluginDefinition(plugin, filePath, approvedByUserId);
|
|
1014
1467
|
return plugin;
|
|
1015
1468
|
}
|
|
1016
1469
|
// Delete a plugin
|
|
1017
|
-
deletePlugin(id) {
|
|
1470
|
+
async deletePlugin(id) {
|
|
1018
1471
|
// Validate the ID parameter using a strict pattern (allows dots for version numbers like 1.6b)
|
|
1019
1472
|
const idPattern = /^[a-zA-Z0-9._-]+$/;
|
|
1020
1473
|
if (!idPattern.test(id)) {
|
|
@@ -1027,23 +1480,37 @@ export class PluginService {
|
|
|
1027
1480
|
logger.error('Plugin ID failed sanitization:', id);
|
|
1028
1481
|
return false;
|
|
1029
1482
|
}
|
|
1483
|
+
if (this.sharedPluginDefinitions) {
|
|
1484
|
+
try {
|
|
1485
|
+
const removed = await this.repositories().pluginDefinitions.deleteWithState(id);
|
|
1486
|
+
if (!removed)
|
|
1487
|
+
return false;
|
|
1488
|
+
this.sharedDefinitionIds.delete(id);
|
|
1489
|
+
await this.clearDiscoveredModels(id);
|
|
1490
|
+
return true;
|
|
1491
|
+
}
|
|
1492
|
+
catch (error) {
|
|
1493
|
+
logger.error('Failed to delete shared plugin %s:', sanitizedId, error);
|
|
1494
|
+
return false;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1030
1497
|
const bundledDirectory = path.resolve(this.bundledPluginsDir);
|
|
1031
|
-
const writablePluginDirs = Array.from(new Set([this.pluginsDir, this.
|
|
1498
|
+
const writablePluginDirs = Array.from(new Set([this.pluginsDir, ...this.legacyPluginsDirs])).filter(pluginsDir => path.resolve(pluginsDir) !== bundledDirectory);
|
|
1032
1499
|
const filePath = writablePluginDirs
|
|
1033
1500
|
.map(pluginsDir => path.resolve(pluginsDir, `${sanitizedId}.json`))
|
|
1034
|
-
.find(candidate =>
|
|
1501
|
+
.find(candidate => isRegularPluginDefinition(candidate));
|
|
1035
1502
|
if (!filePath) {
|
|
1036
1503
|
logger.error('File path is invalid or does not exist:', filePath);
|
|
1037
1504
|
return false;
|
|
1038
1505
|
}
|
|
1039
1506
|
try {
|
|
1040
1507
|
fs.unlinkSync(filePath);
|
|
1041
|
-
pluginActivationService.deletePlugin(id);
|
|
1042
|
-
this.removePluginDefinitionApproval(id);
|
|
1508
|
+
await pluginActivationService.deletePlugin(id);
|
|
1509
|
+
await this.removePluginDefinitionApproval(id);
|
|
1043
1510
|
// Clean up stored variables
|
|
1044
|
-
pluginVariablesService.deletePluginVariables(id);
|
|
1045
|
-
pluginCredentialsService.deleteAllPluginCredentials(id);
|
|
1046
|
-
this.clearDiscoveredModels(id);
|
|
1511
|
+
await pluginVariablesService.deletePluginVariables(id);
|
|
1512
|
+
await pluginCredentialsService.deleteAllPluginCredentials(id);
|
|
1513
|
+
await this.clearDiscoveredModels(id);
|
|
1047
1514
|
return true;
|
|
1048
1515
|
}
|
|
1049
1516
|
catch (error) {
|
|
@@ -1053,21 +1520,31 @@ export class PluginService {
|
|
|
1053
1520
|
}
|
|
1054
1521
|
// Activate a plugin
|
|
1055
1522
|
async activatePlugin(id, userId) {
|
|
1056
|
-
const plugin = this.getPlugin(id, userId);
|
|
1523
|
+
const plugin = await this.getPlugin(id, userId);
|
|
1057
1524
|
if (!plugin) {
|
|
1058
1525
|
throw new Error('Plugin not found');
|
|
1059
1526
|
}
|
|
1060
|
-
if (!pluginActivationService.activate(id, userId)) {
|
|
1527
|
+
if (!(await pluginActivationService.activate(id, userId))) {
|
|
1061
1528
|
throw new Error('Failed to persist plugin activation');
|
|
1062
1529
|
}
|
|
1063
1530
|
// Wait for discovery so the activation response and the UI's first reload
|
|
1064
|
-
// observe the same user-scoped model catalog.
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1531
|
+
// observe the same user-scoped model catalog. These writes are deliberately
|
|
1532
|
+
// sequential: each persisted catalog publishes a cross-replica plugin-user
|
|
1533
|
+
// invalidation. Running sibling discoveries concurrently would make the
|
|
1534
|
+
// first completed catalog advance every sibling's configuration revision,
|
|
1535
|
+
// causing the remaining valid results to be discarded as stale.
|
|
1536
|
+
await this.discoverModels(id, userId).catch(() => []);
|
|
1537
|
+
for (const capability of [
|
|
1538
|
+
'image',
|
|
1539
|
+
'stt',
|
|
1540
|
+
'tts',
|
|
1541
|
+
'audio',
|
|
1542
|
+
'video',
|
|
1543
|
+
]) {
|
|
1544
|
+
if (!plugin.capabilities?.[capability]?.models_endpoint)
|
|
1545
|
+
continue;
|
|
1546
|
+
await this.discoverCapabilityModels(id, capability, userId).catch(() => undefined);
|
|
1547
|
+
}
|
|
1071
1548
|
return true;
|
|
1072
1549
|
}
|
|
1073
1550
|
// Deactivate a specific plugin
|
|
@@ -1076,34 +1553,34 @@ export class PluginService {
|
|
|
1076
1553
|
return pluginActivationService.deactivate(id, userId);
|
|
1077
1554
|
}
|
|
1078
1555
|
// Get the active plugin for a specific model
|
|
1079
|
-
getActivePluginForModel(model, userId, pluginId) {
|
|
1556
|
+
async getActivePluginForModel(model, userId, pluginId) {
|
|
1080
1557
|
if (pluginId) {
|
|
1081
|
-
const plugin = this.getPlugin(pluginId, userId);
|
|
1558
|
+
const plugin = await this.getPlugin(pluginId, userId);
|
|
1082
1559
|
if (!plugin) {
|
|
1083
1560
|
throw new Error(`Plugin not found: ${pluginId}`);
|
|
1084
1561
|
}
|
|
1085
|
-
if (!this.isPluginActive(pluginId, userId)) {
|
|
1562
|
+
if (!(await this.isPluginActive(pluginId, userId))) {
|
|
1086
1563
|
throw new Error(`Plugin is not active: ${pluginId}`);
|
|
1087
1564
|
}
|
|
1088
1565
|
if (!plugin.model_map.includes(model)) {
|
|
1089
1566
|
throw new Error(`Model ${model} is not supported by plugin ${pluginId}`);
|
|
1090
1567
|
}
|
|
1091
|
-
this.resolveOperationEndpoint(plugin, userId);
|
|
1092
|
-
const apiKey = this.getApiKey(plugin, userId);
|
|
1568
|
+
await this.resolveOperationEndpoint(plugin, userId);
|
|
1569
|
+
const apiKey = await this.getApiKey(plugin, userId);
|
|
1093
1570
|
if (pluginRequiresApiKey(plugin) && !apiKey) {
|
|
1094
1571
|
throw new Error(`API key not found for plugin ${pluginId} (save a provider credential in Settings)`);
|
|
1095
1572
|
}
|
|
1096
1573
|
return plugin;
|
|
1097
1574
|
}
|
|
1098
1575
|
// Only route through plugins the user explicitly activated.
|
|
1099
|
-
const activePlugins = this.getActivePlugins(userId);
|
|
1576
|
+
const activePlugins = await this.getActivePlugins(userId);
|
|
1100
1577
|
// Find the active plugin that supports this model
|
|
1101
1578
|
for (const plugin of activePlugins) {
|
|
1102
1579
|
if (plugin.model_map.includes(model)) {
|
|
1103
1580
|
// Local OpenAI-compatible servers can explicitly opt out of auth by
|
|
1104
1581
|
// leaving both auth fields empty.
|
|
1105
|
-
this.resolveOperationEndpoint(plugin, userId);
|
|
1106
|
-
const apiKey = this.getApiKey(plugin, userId);
|
|
1582
|
+
await this.resolveOperationEndpoint(plugin, userId);
|
|
1583
|
+
const apiKey = await this.getApiKey(plugin, userId);
|
|
1107
1584
|
if (pluginRequiresApiKey(plugin) && !apiKey) {
|
|
1108
1585
|
continue;
|
|
1109
1586
|
}
|
|
@@ -1113,30 +1590,34 @@ export class PluginService {
|
|
|
1113
1590
|
return null;
|
|
1114
1591
|
}
|
|
1115
1592
|
// Get all currently active plugins
|
|
1116
|
-
getActivePlugins(userId) {
|
|
1117
|
-
const allPlugins = this.getAllPlugins(userId);
|
|
1593
|
+
async getActivePlugins(userId) {
|
|
1594
|
+
const allPlugins = await this.getAllPlugins(userId);
|
|
1118
1595
|
const activePlugins = allPlugins.filter(plugin => plugin.active);
|
|
1119
1596
|
return activePlugins;
|
|
1120
1597
|
}
|
|
1598
|
+
async getActivePluginsUnchecked(userId) {
|
|
1599
|
+
return (await this.getAllPluginsUnchecked(userId)).filter(plugin => plugin.active && plugin.id !== CODEX_OAUTH_PLUGIN_ID);
|
|
1600
|
+
}
|
|
1121
1601
|
// Legacy method for backward compatibility - returns first active plugin
|
|
1122
|
-
getActivePlugin(userId) {
|
|
1123
|
-
const activePlugins = this.getActivePlugins(userId);
|
|
1602
|
+
async getActivePlugin(userId) {
|
|
1603
|
+
const activePlugins = await this.getActivePlugins(userId);
|
|
1124
1604
|
return activePlugins.length > 0 ? activePlugins[0] : null;
|
|
1125
1605
|
}
|
|
1126
1606
|
// Get plugin status
|
|
1127
|
-
getPluginStatus(userId) {
|
|
1128
|
-
const plugins = this.getAllPlugins(userId);
|
|
1129
|
-
return plugins.map(plugin => ({
|
|
1607
|
+
async getPluginStatus(userId) {
|
|
1608
|
+
const plugins = await this.getAllPlugins(userId);
|
|
1609
|
+
return Promise.all(plugins.map(async (plugin) => ({
|
|
1130
1610
|
id: plugin.id,
|
|
1131
1611
|
active: plugin.active || false,
|
|
1132
1612
|
available: !pluginRequiresApiKey(plugin) ||
|
|
1133
|
-
this.getApiKey(plugin, userId) !== null,
|
|
1134
|
-
}));
|
|
1613
|
+
(await this.getApiKey(plugin, userId)) !== null,
|
|
1614
|
+
})));
|
|
1135
1615
|
}
|
|
1136
1616
|
// Execute a chat request through the active plugin
|
|
1137
|
-
async executePluginRequest(model, messages, options = {}, userId, pluginId) {
|
|
1617
|
+
async executePluginRequest(model, messages, options = {}, userId, pluginId, signal) {
|
|
1618
|
+
throwIfChatGenerationCancelled(signal);
|
|
1138
1619
|
validatePluginModel(model);
|
|
1139
|
-
const activePlugin = this.getActivePluginForModel(model, userId, pluginId);
|
|
1620
|
+
const activePlugin = await this.getActivePluginForModel(model, userId, pluginId);
|
|
1140
1621
|
if (!activePlugin) {
|
|
1141
1622
|
throw new Error(`No active plugin found for model: ${model}`);
|
|
1142
1623
|
}
|
|
@@ -1144,11 +1625,11 @@ export class PluginService {
|
|
|
1144
1625
|
throw new Error(`Model ${model} is not supported by plugin ${activePlugin.id}`);
|
|
1145
1626
|
}
|
|
1146
1627
|
if (activePlugin.id === CODEX_OAUTH_PLUGIN_ID) {
|
|
1147
|
-
await codexOAuthService.ensureFreshToken();
|
|
1628
|
+
await codexOAuthService.ensureFreshToken(signal);
|
|
1148
1629
|
// The codex endpoint only answers as an SSE stream; aggregate it here
|
|
1149
1630
|
// so non-streaming callers still get a complete response.
|
|
1150
1631
|
let aggregated = '';
|
|
1151
|
-
for await (const chunk of this.executePluginStreamRequest(model, messages, options, userId, activePlugin.id)) {
|
|
1632
|
+
for await (const chunk of this.executePluginStreamRequest(model, messages, options, userId, activePlugin.id, signal)) {
|
|
1152
1633
|
if (chunk.type === 'content' && chunk.content) {
|
|
1153
1634
|
aggregated += chunk.content;
|
|
1154
1635
|
}
|
|
@@ -1157,11 +1638,11 @@ export class PluginService {
|
|
|
1157
1638
|
choices: [{ message: { role: 'assistant', content: aggregated } }],
|
|
1158
1639
|
};
|
|
1159
1640
|
}
|
|
1160
|
-
const pluginVars = this.getPluginVariables(activePlugin, userId);
|
|
1641
|
+
const pluginVars = await this.getPluginVariables(activePlugin, userId);
|
|
1161
1642
|
const { apiMode, endpoint: effectiveEndpoint } = resolvePluginApiConfig(activePlugin, pluginVars);
|
|
1162
1643
|
const processedEndpoint = applyModelEndpointTemplate(effectiveEndpoint, model);
|
|
1163
1644
|
assertSafePluginEndpoint(processedEndpoint, 'endpoint URL constructed');
|
|
1164
|
-
const apiKey = this.getApiKey(activePlugin, userId);
|
|
1645
|
+
const apiKey = await this.getApiKey(activePlugin, userId);
|
|
1165
1646
|
if (pluginRequiresApiKey(activePlugin) && !apiKey) {
|
|
1166
1647
|
throw new Error(`API key not found for plugin ${activePlugin.id} (save a provider credential in Settings)`);
|
|
1167
1648
|
}
|
|
@@ -1177,6 +1658,7 @@ export class PluginService {
|
|
|
1177
1658
|
headers,
|
|
1178
1659
|
timeout: 60000, // 60 second timeout
|
|
1179
1660
|
maxRedirects: 0,
|
|
1661
|
+
signal,
|
|
1180
1662
|
});
|
|
1181
1663
|
const normalized = convertProviderResponse(activePlugin, response.data, model, apiMode, providerStateScope);
|
|
1182
1664
|
pluginUsageService.record({
|
|
@@ -1198,16 +1680,22 @@ export class PluginService {
|
|
|
1198
1680
|
return normalized;
|
|
1199
1681
|
}
|
|
1200
1682
|
catch (error) {
|
|
1683
|
+
const cancelled = isChatGenerationCancelled(error, signal);
|
|
1201
1684
|
pluginUsageService.record({
|
|
1202
1685
|
userId,
|
|
1203
1686
|
pluginId: activePlugin.id,
|
|
1204
1687
|
pluginName: activePlugin.name,
|
|
1205
1688
|
capability: 'chat',
|
|
1206
1689
|
model,
|
|
1207
|
-
status: 'error',
|
|
1690
|
+
status: cancelled ? 'cancelled' : 'error',
|
|
1208
1691
|
durationMs: Date.now() - startedAt,
|
|
1209
1692
|
});
|
|
1210
|
-
|
|
1693
|
+
if (!cancelled) {
|
|
1694
|
+
logger.error(`Plugin request failed for ${activePlugin.id}:`, error);
|
|
1695
|
+
}
|
|
1696
|
+
if (cancelled) {
|
|
1697
|
+
throw error;
|
|
1698
|
+
}
|
|
1211
1699
|
if (error && typeof error === 'object' && 'response' in error) {
|
|
1212
1700
|
const axiosError = error;
|
|
1213
1701
|
throw new Error(`Plugin API error: ${axiosError.response.status} - ${axiosError.response.data?.error?.message || axiosError.response.statusText}`);
|
|
@@ -1226,9 +1714,10 @@ export class PluginService {
|
|
|
1226
1714
|
* Returns an async generator that yields SSE delta content strings.
|
|
1227
1715
|
* Also collects tool_calls from the stream.
|
|
1228
1716
|
*/
|
|
1229
|
-
async *executePluginStreamRequest(model, messages, options = {}, userId, pluginId) {
|
|
1717
|
+
async *executePluginStreamRequest(model, messages, options = {}, userId, pluginId, signal) {
|
|
1718
|
+
throwIfChatGenerationCancelled(signal);
|
|
1230
1719
|
validatePluginModel(model);
|
|
1231
|
-
const activePlugin = this.getActivePluginForModel(model, userId, pluginId);
|
|
1720
|
+
const activePlugin = await this.getActivePluginForModel(model, userId, pluginId);
|
|
1232
1721
|
if (!activePlugin) {
|
|
1233
1722
|
throw new Error(`No active plugin found for model: ${model}`);
|
|
1234
1723
|
}
|
|
@@ -1236,13 +1725,13 @@ export class PluginService {
|
|
|
1236
1725
|
throw new Error(`Model ${model} is not supported by plugin ${activePlugin.id}`);
|
|
1237
1726
|
}
|
|
1238
1727
|
if (activePlugin.id === CODEX_OAUTH_PLUGIN_ID) {
|
|
1239
|
-
await codexOAuthService.ensureFreshToken();
|
|
1728
|
+
await codexOAuthService.ensureFreshToken(signal);
|
|
1240
1729
|
}
|
|
1241
|
-
const pluginVars = this.getPluginVariables(activePlugin, userId);
|
|
1730
|
+
const pluginVars = await this.getPluginVariables(activePlugin, userId);
|
|
1242
1731
|
const { apiMode, endpoint: effectiveEndpoint } = resolvePluginApiConfig(activePlugin, pluginVars);
|
|
1243
1732
|
const processedEndpoint = applyModelEndpointTemplate(effectiveEndpoint, model);
|
|
1244
1733
|
assertSafePluginEndpoint(processedEndpoint);
|
|
1245
|
-
const apiKey = this.getApiKey(activePlugin, userId);
|
|
1734
|
+
const apiKey = await this.getApiKey(activePlugin, userId);
|
|
1246
1735
|
if (pluginRequiresApiKey(activePlugin) && !apiKey) {
|
|
1247
1736
|
throw new Error(`API key not found for plugin ${activePlugin.id} (save a provider credential in Settings)`);
|
|
1248
1737
|
}
|
|
@@ -1301,6 +1790,7 @@ export class PluginService {
|
|
|
1301
1790
|
headers,
|
|
1302
1791
|
body: JSON.stringify(payload),
|
|
1303
1792
|
redirect: 'error',
|
|
1793
|
+
signal,
|
|
1304
1794
|
});
|
|
1305
1795
|
if (activePlugin.id === 'anthropic') {
|
|
1306
1796
|
yield* forward(streamAnthropicResponse(response));
|
|
@@ -1377,7 +1867,7 @@ export class PluginService {
|
|
|
1377
1867
|
status = 'success';
|
|
1378
1868
|
}
|
|
1379
1869
|
catch (error) {
|
|
1380
|
-
status = 'error';
|
|
1870
|
+
status = isChatGenerationCancelled(error, signal) ? 'cancelled' : 'error';
|
|
1381
1871
|
throw error;
|
|
1382
1872
|
}
|
|
1383
1873
|
finally {
|
|
@@ -1436,23 +1926,29 @@ export class PluginService {
|
|
|
1436
1926
|
pluginRecord.model_map.length > 0);
|
|
1437
1927
|
}
|
|
1438
1928
|
// Export plugin to JSON
|
|
1439
|
-
exportPlugin(id, userId) {
|
|
1929
|
+
async exportPlugin(id, userId) {
|
|
1440
1930
|
return this.getPlugin(id, userId);
|
|
1441
1931
|
}
|
|
1442
1932
|
// Import plugin from JSON data
|
|
1443
|
-
importPlugin(pluginData, approvedByUserId) {
|
|
1933
|
+
async importPlugin(pluginData, approvedByUserId) {
|
|
1444
1934
|
// Validate and clean the plugin data
|
|
1445
1935
|
if (!this.validatePlugin(pluginData)) {
|
|
1446
1936
|
throw new Error('Invalid plugin data');
|
|
1447
1937
|
}
|
|
1938
|
+
if (this.sharedPluginDefinitions) {
|
|
1939
|
+
const existing = await this.repositories().pluginDefinitions.find(pluginData.id);
|
|
1940
|
+
if (existing && this.parseSharedPluginDefinition(existing)) {
|
|
1941
|
+
throw new Error(`Plugin with ID ${pluginData.id} already exists`);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1448
1944
|
// Check if plugin already exists
|
|
1449
1945
|
const existingPluginPath = this.resolveEffectivePluginFilePath(pluginData.id);
|
|
1450
1946
|
if (existingPluginPath) {
|
|
1451
1947
|
try {
|
|
1452
|
-
const existingPlugin = JSON.parse(
|
|
1948
|
+
const existingPlugin = JSON.parse(readRegularPluginDefinition(existingPluginPath));
|
|
1453
1949
|
if (this.validatePlugin(existingPlugin) &&
|
|
1454
1950
|
existingPlugin.id === pluginData.id &&
|
|
1455
|
-
this.isPluginDefinitionApproved(existingPlugin, existingPluginPath)) {
|
|
1951
|
+
(await this.isPluginDefinitionApproved(existingPlugin, existingPluginPath))) {
|
|
1456
1952
|
throw new Error(`Plugin with ID ${pluginData.id} already exists`);
|
|
1457
1953
|
}
|
|
1458
1954
|
}
|
|
@@ -1470,59 +1966,88 @@ export class PluginService {
|
|
|
1470
1966
|
// ============================================
|
|
1471
1967
|
// Capability Methods
|
|
1472
1968
|
// ============================================
|
|
1473
|
-
getPluginForTTS(model, pluginId, userId) {
|
|
1969
|
+
async getPluginForTTS(model, pluginId, userId) {
|
|
1474
1970
|
return this.ttsService.getPluginForTTS(model, pluginId, userId);
|
|
1475
1971
|
}
|
|
1476
|
-
getPluginForEmbedding(model, pluginId, userId) {
|
|
1972
|
+
async getPluginForEmbedding(model, pluginId, userId) {
|
|
1477
1973
|
return this.embeddingService.getPluginForEmbedding(model, pluginId, userId);
|
|
1478
1974
|
}
|
|
1479
|
-
getAvailableEmbeddingModels(userId) {
|
|
1975
|
+
async getAvailableEmbeddingModels(userId) {
|
|
1480
1976
|
return this.embeddingService.getAvailableEmbeddingModels(userId);
|
|
1481
1977
|
}
|
|
1482
|
-
async executeEmbeddingRequest(model, input, pluginId, userId) {
|
|
1483
|
-
return this.embeddingService.executeEmbeddingRequest(model, input, pluginId, userId);
|
|
1978
|
+
async executeEmbeddingRequest(model, input, pluginId, userId, signal) {
|
|
1979
|
+
return this.embeddingService.executeEmbeddingRequest(model, input, pluginId, userId, signal);
|
|
1484
1980
|
}
|
|
1485
|
-
getAvailableTTSModels(userId) {
|
|
1981
|
+
async getAvailableTTSModels(userId) {
|
|
1486
1982
|
return this.ttsService.getAvailableTTSModels(userId);
|
|
1487
1983
|
}
|
|
1984
|
+
async getAvailableSTTModels(userId) {
|
|
1985
|
+
return this.sttService.getAvailableModels(userId);
|
|
1986
|
+
}
|
|
1987
|
+
executeSTTRequest(model, audio, options) {
|
|
1988
|
+
return this.sttService.transcribe(model, audio, options);
|
|
1989
|
+
}
|
|
1488
1990
|
async executeTTSRequest(model, input, options = {}) {
|
|
1489
1991
|
return this.ttsService.executeTTSRequest(model, input, options);
|
|
1490
1992
|
}
|
|
1491
|
-
|
|
1993
|
+
async executeVoiceCloneRequest(model, input, referenceAudio, options = {}) {
|
|
1994
|
+
return this.ttsService.executeVoiceCloneRequest(model, input, referenceAudio, options);
|
|
1995
|
+
}
|
|
1996
|
+
async getTTSConfig(pluginId, userId) {
|
|
1492
1997
|
return this.ttsService.getTTSConfig(pluginId, userId);
|
|
1493
1998
|
}
|
|
1494
|
-
getPluginForImageGen(model, pluginId, userId) {
|
|
1999
|
+
async getPluginForImageGen(model, pluginId, userId) {
|
|
1495
2000
|
return this.imageGenerationService.getPluginForImageGen(model, pluginId, userId);
|
|
1496
2001
|
}
|
|
1497
|
-
getAvailableImageGenModels(userId) {
|
|
2002
|
+
async getAvailableImageGenModels(userId) {
|
|
1498
2003
|
return this.imageGenerationService.getAvailableImageGenModels(userId);
|
|
1499
2004
|
}
|
|
1500
2005
|
async executeImageGenRequest(model, prompt, options) {
|
|
1501
2006
|
return this.imageGenerationService.executeImageGenRequest(model, prompt, options);
|
|
1502
2007
|
}
|
|
1503
|
-
getImageGenConfig(pluginId, userId) {
|
|
2008
|
+
async getImageGenConfig(pluginId, userId) {
|
|
1504
2009
|
return this.imageGenerationService.getImageGenConfig(pluginId, userId);
|
|
1505
2010
|
}
|
|
1506
|
-
getPluginsByCapability(capabilityType, userId) {
|
|
2011
|
+
async getPluginsByCapability(capabilityType, userId) {
|
|
1507
2012
|
return this.capabilityRegistryService.getPluginsByCapability(capabilityType, userId);
|
|
1508
2013
|
}
|
|
1509
|
-
getAvailableAudioGenModels(userId) {
|
|
2014
|
+
async getAvailableAudioGenModels(userId) {
|
|
1510
2015
|
return this.audioGenerationService.getAvailableModels(userId);
|
|
1511
2016
|
}
|
|
1512
2017
|
executeAudioGenRequest(model, prompt, options) {
|
|
1513
2018
|
return this.audioGenerationService.generate(model, prompt, options);
|
|
1514
2019
|
}
|
|
1515
|
-
getAvailableVideoGenModels(userId) {
|
|
2020
|
+
async getAvailableVideoGenModels(userId) {
|
|
1516
2021
|
return this.videoGenerationService.getAvailableModels(userId);
|
|
1517
2022
|
}
|
|
1518
2023
|
submitVideoGenRequest(model, prompt, options) {
|
|
1519
2024
|
return this.videoGenerationService.submit(model, prompt, options);
|
|
1520
2025
|
}
|
|
1521
|
-
pollVideoGenRequest(model, providerJobId, pluginId, userId) {
|
|
1522
|
-
return this.videoGenerationService.poll(model, providerJobId, pluginId, userId);
|
|
1523
|
-
}
|
|
1524
|
-
downloadVideoGenResult(model, providerJobId, pluginId, userId) {
|
|
1525
|
-
return this.videoGenerationService.download(model, providerJobId, pluginId, userId);
|
|
2026
|
+
pollVideoGenRequest(model, providerJobId, pluginId, userId, signal) {
|
|
2027
|
+
return this.videoGenerationService.poll(model, providerJobId, pluginId, userId, signal);
|
|
2028
|
+
}
|
|
2029
|
+
downloadVideoGenResult(model, providerJobId, pluginId, userId, signal) {
|
|
2030
|
+
return this.videoGenerationService.download(model, providerJobId, pluginId, userId, signal);
|
|
2031
|
+
}
|
|
2032
|
+
async canCancelVideoGenRequest(model, pluginId, userId) {
|
|
2033
|
+
return this.videoGenerationService.supportsCancellation(model, pluginId, userId);
|
|
2034
|
+
}
|
|
2035
|
+
cancelVideoGenRequest(model, providerJobId, pluginId, userId, signal) {
|
|
2036
|
+
return this.videoGenerationService.cancel(model, providerJobId, pluginId, userId, signal);
|
|
2037
|
+
}
|
|
2038
|
+
async closeCacheInvalidation() {
|
|
2039
|
+
this.removeCacheInvalidationListener?.();
|
|
2040
|
+
this.removeCacheInvalidationListener = undefined;
|
|
2041
|
+
this.discoveredModelsCache.clear();
|
|
2042
|
+
this.discoveredModelsUpdatedAt.clear();
|
|
2043
|
+
this.discoveryAttemptedAt.clear();
|
|
2044
|
+
this.inflightDiscovery.clear();
|
|
2045
|
+
this.discoveredCapabilityModelsCache.clear();
|
|
2046
|
+
this.discoveredCapabilityModelsUpdatedAt.clear();
|
|
2047
|
+
this.capabilityDiscoveryAttemptedAt.clear();
|
|
2048
|
+
this.inflightCapabilityDiscovery.clear();
|
|
2049
|
+
this.discoveryCacheRevisions.clear();
|
|
2050
|
+
this.capabilityDiscoveryCacheRevisions.clear();
|
|
1526
2051
|
}
|
|
1527
2052
|
}
|
|
1528
2053
|
export default new PluginService();
|