libre-webui 0.17.0 → 0.18.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/backend/dist/db.d.ts.map +1 -1
- package/backend/dist/db.js +150 -6
- package/backend/dist/db.js.map +1 -1
- package/backend/dist/index.d.ts.map +1 -1
- package/backend/dist/index.js +15 -10
- package/backend/dist/index.js.map +1 -1
- package/backend/dist/middleware/auth.d.ts.map +1 -1
- package/backend/dist/middleware/auth.js +35 -3
- package/backend/dist/middleware/auth.js.map +1 -1
- package/backend/dist/models/userModel.d.ts +23 -0
- package/backend/dist/models/userModel.d.ts.map +1 -1
- package/backend/dist/models/userModel.js +89 -24
- package/backend/dist/models/userModel.js.map +1 -1
- package/backend/dist/routes/agentCli.d.ts.map +1 -1
- package/backend/dist/routes/agentCli.js +2 -0
- package/backend/dist/routes/agentCli.js.map +1 -1
- package/backend/dist/routes/auth.d.ts.map +1 -1
- package/backend/dist/routes/auth.js +46 -33
- 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 +3 -1
- 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 +49 -41
- package/backend/dist/routes/documents.js.map +1 -1
- package/backend/dist/routes/embeddings.js +2 -2
- package/backend/dist/routes/embeddings.js.map +1 -1
- package/backend/dist/routes/huggingfaceHub.d.ts.map +1 -1
- package/backend/dist/routes/huggingfaceHub.js +3 -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 +2 -0
- package/backend/dist/routes/imageGen.js.map +1 -1
- package/backend/dist/routes/media.d.ts +3 -0
- package/backend/dist/routes/media.d.ts.map +1 -0
- package/backend/dist/routes/media.js +429 -0
- package/backend/dist/routes/media.js.map +1 -0
- package/backend/dist/routes/ollama.d.ts.map +1 -1
- package/backend/dist/routes/ollama.js +15 -83
- 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 +2 -0
- 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 +28 -0
- package/backend/dist/routes/plugins.js.map +1 -1
- package/backend/dist/routes/systemDiagnostics.d.ts +3 -0
- package/backend/dist/routes/systemDiagnostics.d.ts.map +1 -0
- package/backend/dist/routes/systemDiagnostics.js +49 -0
- package/backend/dist/routes/systemDiagnostics.js.map +1 -0
- package/backend/dist/routes/tts.d.ts.map +1 -1
- package/backend/dist/routes/tts.js +4 -0
- 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 +58 -0
- 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 +84 -0
- package/backend/dist/routes/work.js.map +1 -1
- package/backend/dist/services/authService.d.ts +15 -9
- package/backend/dist/services/authService.d.ts.map +1 -1
- package/backend/dist/services/authService.js +34 -29
- package/backend/dist/services/authService.js.map +1 -1
- package/backend/dist/services/chatRequestService.d.ts +8 -2
- package/backend/dist/services/chatRequestService.d.ts.map +1 -1
- package/backend/dist/services/chatRequestService.js +30 -3
- package/backend/dist/services/chatRequestService.js.map +1 -1
- package/backend/dist/services/documentService.d.ts +11 -10
- package/backend/dist/services/documentService.d.ts.map +1 -1
- package/backend/dist/services/documentService.js +62 -54
- package/backend/dist/services/documentService.js.map +1 -1
- package/backend/dist/services/encryptionService.d.ts.map +1 -1
- package/backend/dist/services/encryptionService.js +18 -8
- package/backend/dist/services/encryptionService.js.map +1 -1
- package/backend/dist/services/galleryService.d.ts +23 -1
- package/backend/dist/services/galleryService.d.ts.map +1 -1
- package/backend/dist/services/galleryService.js +125 -8
- package/backend/dist/services/galleryService.js.map +1 -1
- package/backend/dist/services/mediaGenerationJobService.d.ts +25 -0
- package/backend/dist/services/mediaGenerationJobService.d.ts.map +1 -0
- package/backend/dist/services/mediaGenerationJobService.js +82 -0
- package/backend/dist/services/mediaGenerationJobService.js.map +1 -0
- package/backend/dist/services/pluginAudioGenerationService.d.ts +34 -0
- package/backend/dist/services/pluginAudioGenerationService.d.ts.map +1 -0
- package/backend/dist/services/pluginAudioGenerationService.js +211 -0
- package/backend/dist/services/pluginAudioGenerationService.js.map +1 -0
- package/backend/dist/services/pluginCapabilityRegistryService.d.ts.map +1 -1
- package/backend/dist/services/pluginCapabilityRegistryService.js +6 -0
- package/backend/dist/services/pluginCapabilityRegistryService.js.map +1 -1
- package/backend/dist/services/pluginEmbeddingService.d.ts +2 -0
- package/backend/dist/services/pluginEmbeddingService.d.ts.map +1 -1
- package/backend/dist/services/pluginEmbeddingService.js +66 -35
- package/backend/dist/services/pluginEmbeddingService.js.map +1 -1
- package/backend/dist/services/pluginImageGenerationService.d.ts +2 -0
- package/backend/dist/services/pluginImageGenerationService.d.ts.map +1 -1
- package/backend/dist/services/pluginImageGenerationService.js +63 -38
- package/backend/dist/services/pluginImageGenerationService.js.map +1 -1
- package/backend/dist/services/pluginService.d.ts +38 -1
- package/backend/dist/services/pluginService.d.ts.map +1 -1
- package/backend/dist/services/pluginService.js +390 -69
- package/backend/dist/services/pluginService.js.map +1 -1
- package/backend/dist/services/pluginTTSService.d.ts +2 -0
- package/backend/dist/services/pluginTTSService.d.ts.map +1 -1
- package/backend/dist/services/pluginTTSService.js +27 -2
- package/backend/dist/services/pluginTTSService.js.map +1 -1
- package/backend/dist/services/pluginUsageService.d.ts +82 -0
- package/backend/dist/services/pluginUsageService.d.ts.map +1 -0
- package/backend/dist/services/pluginUsageService.js +238 -0
- package/backend/dist/services/pluginUsageService.js.map +1 -0
- package/backend/dist/services/pluginVideoGenerationService.d.ts +45 -0
- package/backend/dist/services/pluginVideoGenerationService.d.ts.map +1 -0
- package/backend/dist/services/pluginVideoGenerationService.js +198 -0
- package/backend/dist/services/pluginVideoGenerationService.js.map +1 -0
- package/backend/dist/services/preferencesService.d.ts.map +1 -1
- package/backend/dist/services/preferencesService.js +15 -1
- package/backend/dist/services/preferencesService.js.map +1 -1
- package/backend/dist/services/registrationPolicy.d.ts +5 -0
- package/backend/dist/services/registrationPolicy.d.ts.map +1 -0
- package/backend/dist/services/registrationPolicy.js +21 -0
- package/backend/dist/services/registrationPolicy.js.map +1 -0
- package/backend/dist/services/simpleGitHubOAuth.d.ts.map +1 -1
- package/backend/dist/services/simpleGitHubOAuth.js +8 -12
- 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 +7 -12
- package/backend/dist/services/simpleHuggingFaceOAuth.js.map +1 -1
- package/backend/dist/services/systemDiagnosticsService.d.ts +117 -0
- package/backend/dist/services/systemDiagnosticsService.d.ts.map +1 -0
- package/backend/dist/services/systemDiagnosticsService.js +326 -0
- package/backend/dist/services/systemDiagnosticsService.js.map +1 -0
- package/backend/dist/services/turnstileService.d.ts +2 -1
- package/backend/dist/services/turnstileService.d.ts.map +1 -1
- package/backend/dist/services/turnstileService.js +28 -2
- package/backend/dist/services/turnstileService.js.map +1 -1
- package/backend/dist/services/workModelProviderService.d.ts +3 -0
- package/backend/dist/services/workModelProviderService.d.ts.map +1 -1
- package/backend/dist/services/workModelProviderService.js +37 -4
- package/backend/dist/services/workModelProviderService.js.map +1 -1
- package/backend/dist/services/workPreviewProxyService.d.ts +27 -0
- package/backend/dist/services/workPreviewProxyService.d.ts.map +1 -0
- package/backend/dist/services/workPreviewProxyService.js +514 -0
- package/backend/dist/services/workPreviewProxyService.js.map +1 -0
- package/backend/dist/services/workRuntimeService.d.ts +22 -1
- package/backend/dist/services/workRuntimeService.d.ts.map +1 -1
- package/backend/dist/services/workRuntimeService.js +287 -8
- package/backend/dist/services/workRuntimeService.js.map +1 -1
- package/backend/dist/storage.d.ts.map +1 -1
- package/backend/dist/storage.js +3 -3
- package/backend/dist/storage.js.map +1 -1
- package/backend/dist/types/index.d.ts +77 -1
- 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 +31 -0
- package/backend/dist/types/work.d.ts.map +1 -1
- 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 +4 -4
- package/backend/dist/utils/chatDocumentContext.js.map +1 -1
- package/backend/dist/utils/pluginDefinitionTrust.js +1 -1
- package/backend/dist/utils/pluginValidation.d.ts +3 -2
- package/backend/dist/utils/pluginValidation.d.ts.map +1 -1
- package/backend/dist/utils/pluginValidation.js +30 -2
- package/backend/dist/utils/pluginValidation.js.map +1 -1
- package/backend/dist/utils/workGit.d.ts +14 -0
- package/backend/dist/utils/workGit.d.ts.map +1 -0
- package/backend/dist/utils/workGit.js +207 -0
- package/backend/dist/utils/workGit.js.map +1 -0
- package/backend/dist/websocketServer.d.ts +1 -0
- package/backend/dist/websocketServer.d.ts.map +1 -1
- package/backend/dist/websocketServer.js +108 -24
- package/backend/dist/websocketServer.js.map +1 -1
- package/backend/dist/workTerminalServer.d.ts.map +1 -1
- package/backend/dist/workTerminalServer.js +3 -1
- package/backend/dist/workTerminalServer.js.map +1 -1
- package/backend/package.json +1 -1
- package/frontend/dist/assets/index-ChhWhug2.css +1 -0
- package/frontend/dist/assets/index-CmZntyR1.js +3 -0
- package/frontend/dist/index.html +26 -6
- package/frontend/dist/js/ArtifactContainer-CBAbdoIJ.js +1 -0
- package/frontend/dist/js/{ArtifactDemoPage-B4qsvUnF.js → ArtifactDemoPage-BWN0MWCx.js} +1 -1
- package/frontend/dist/js/ArtifactSlideOutPanel-D-AvYkfk.js +1 -0
- package/frontend/dist/js/ChatPage-w2FkF_fE.js +16 -0
- package/frontend/dist/js/FirstTimeSetup-CzBxl7UH.js +1 -0
- package/frontend/dist/js/GalleryPage-Cv8pniRW.js +1 -0
- package/frontend/dist/js/HomePage-Vyj4ndU4.js +1 -0
- package/frontend/dist/js/LibreClawPage-CYhLgQB-.js +1 -0
- package/frontend/dist/js/{ModelManagerModals-DMoEav1l.js → ModelManagerModals-C2rwHd01.js} +1 -1
- package/frontend/dist/js/ModelSelector-D7kDjZV9.js +1 -0
- package/frontend/dist/js/ModelsPage-BnUddkrs.js +2 -0
- package/frontend/dist/js/PersonasPage-BL5XlrEm.js +13 -0
- package/frontend/dist/js/PluginUsagePage-BXqweCCs.js +1 -0
- package/frontend/dist/js/{RichMessageContent-BJ49VN9j.js → RichMessageContent-nAEaPTpH.js} +2 -2
- package/frontend/dist/js/SettingsModal-DZYCI5-y.js +1 -0
- package/frontend/dist/js/SystemPage-jdHYfn9A.js +1 -0
- package/frontend/dist/js/UserManagementPage-BpOnt6os.js +1 -0
- package/frontend/dist/js/WorkPage-DAp1T1dl.js +5 -0
- package/frontend/dist/js/api-BCqWXjZI.js +19 -0
- package/frontend/dist/js/appStore-CDM6V5ny.js +2 -0
- package/frontend/dist/js/ar-DS8gs8WK.js +2 -0
- package/frontend/dist/js/{authStore-mOYH_AXI.js → authStore-Bl5ofD_h.js} +3 -3
- package/frontend/dist/js/bn-CrMPJwTR.js +2 -0
- package/frontend/dist/js/cs-BL116Ezu.js +2 -0
- package/frontend/dist/js/da-TDNaKzqy.js +2 -0
- package/frontend/dist/js/de-DkIqdAB5.js +2 -0
- package/frontend/dist/js/es-CHRXt6Fd.js +2 -0
- package/frontend/dist/js/{estree-0vwU39qX.js → estree-BFya-bSu.js} +1 -1
- package/frontend/dist/js/fr-8715yUKq.js +2 -0
- package/frontend/dist/js/hi-C2O08SBU.js +2 -0
- package/frontend/dist/js/{html-CApr2Bvi.js → html-DJot0Wwf.js} +1 -1
- package/frontend/dist/js/id-Dq7UXUEV.js +2 -0
- package/frontend/dist/js/is-B3dbbhSl.js +2 -0
- package/frontend/dist/js/it-CLSuu2K7.js +2 -0
- package/frontend/dist/js/ja-CthrqyCR.js +2 -0
- package/frontend/dist/js/ko-BJvFDJ82.js +2 -0
- package/frontend/dist/js/{markdown-C78Qc6xu.js → markdown-CXwWsPYG.js} +1 -1
- package/frontend/dist/js/ms-QV0202Mj.js +2 -0
- package/frontend/dist/js/nl-Dob1m1pV.js +2 -0
- package/frontend/dist/js/pl-urfOKnYI.js +2 -0
- package/frontend/dist/js/pt-D52Xkpi0.js +2 -0
- package/frontend/dist/js/ru-CwnW9Xe2.js +2 -0
- package/frontend/dist/js/{standalone-DmLfI4Qj.js → standalone-C0NjJpWr.js} +1 -1
- package/frontend/dist/js/sv-BNclj-Fo.js +2 -0
- package/frontend/dist/js/th-BlQ4PL57.js +2 -0
- package/frontend/dist/js/tr-B80aZ1px.js +2 -0
- package/frontend/dist/js/{typescript-Bcq62agC.js → typescript-d0TUM2-0.js} +1 -1
- package/frontend/dist/js/ui-vendor-ChfdHf5M.js +177 -0
- package/frontend/dist/js/uk-DZuuaI56.js +2 -0
- package/frontend/dist/js/vi-Bg42fPfF.js +2 -0
- package/frontend/dist/js/zh-BSt87zs6.js +2 -0
- package/package.json +3 -3
- package/plugins/openrouter.json +89 -0
- package/backend/dist/services/systemSettingsService.d.ts +0 -12
- package/backend/dist/services/systemSettingsService.d.ts.map +0 -1
- package/backend/dist/services/systemSettingsService.js +0 -70
- package/backend/dist/services/systemSettingsService.js.map +0 -1
- package/frontend/dist/assets/index-BqI0kezz.css +0 -1
- package/frontend/dist/assets/index-CRC6g6bL.js +0 -3
- package/frontend/dist/js/ArtifactContainer-Cdy-973y.js +0 -1
- package/frontend/dist/js/ArtifactSlideOutPanel-CmKgQ4eD.js +0 -1
- package/frontend/dist/js/ChatPage-CYT69oBR.js +0 -16
- package/frontend/dist/js/FirstTimeSetup-C8LdLP5J.js +0 -1
- package/frontend/dist/js/GalleryPage-Bm89pnS8.js +0 -1
- package/frontend/dist/js/HomePage-CeCYnMUG.js +0 -1
- package/frontend/dist/js/LibreClawPage-DGMEV6dm.js +0 -1
- package/frontend/dist/js/ModelSelector-DXPdGdQ_.js +0 -1
- package/frontend/dist/js/ModelsPage-D-FIy2x-.js +0 -2
- package/frontend/dist/js/PersonasPage-CIrEVFo5.js +0 -13
- package/frontend/dist/js/SettingsModal-CxtOXPY7.js +0 -1
- package/frontend/dist/js/UserManagementPage-BfyYGGFQ.js +0 -1
- package/frontend/dist/js/WorkPage-C7bW6Hxx.js +0 -4
- package/frontend/dist/js/api-DCD41-l9.js +0 -19
- package/frontend/dist/js/appStore-Bw-8Exsx.js +0 -2
- package/frontend/dist/js/ar-BAHlIvy0.js +0 -2
- package/frontend/dist/js/bn-BxquDVbd.js +0 -2
- package/frontend/dist/js/cs-C4DoKzRm.js +0 -2
- package/frontend/dist/js/da-CFslpGTw.js +0 -2
- package/frontend/dist/js/de-ChudoRh2.js +0 -2
- package/frontend/dist/js/es-B36fefE-.js +0 -2
- package/frontend/dist/js/fr-BSVeTM5W.js +0 -2
- package/frontend/dist/js/hi-BGoFbl5V.js +0 -2
- package/frontend/dist/js/id-BfYs2p_j.js +0 -2
- package/frontend/dist/js/is-DZ1MS-5A.js +0 -2
- package/frontend/dist/js/it-CXtrPCG1.js +0 -2
- package/frontend/dist/js/ja-FPJ_NK_y.js +0 -2
- package/frontend/dist/js/ko-DVwD4ZZF.js +0 -2
- package/frontend/dist/js/ms-PKPP0RX3.js +0 -2
- package/frontend/dist/js/nl-DWM5HJZ8.js +0 -2
- package/frontend/dist/js/pl-B9va8Tuf.js +0 -2
- package/frontend/dist/js/pt-P0IQi-Zr.js +0 -2
- package/frontend/dist/js/ru-Ca2bxYnc.js +0 -2
- package/frontend/dist/js/sv-DI4RDwyZ.js +0 -2
- package/frontend/dist/js/th-DN0bDS9d.js +0 -2
- package/frontend/dist/js/tr-ChqMv5Q4.js +0 -2
- package/frontend/dist/js/ui-vendor-DohPFHDW.js +0 -177
- package/frontend/dist/js/uk-Cr51h_XQ.js +0 -2
- package/frontend/dist/js/useBaseQuery-BAOlhjar.js +0 -1
- package/frontend/dist/js/useQuery-CcRqxveh.js +0 -1
- package/frontend/dist/js/vi-D4OhoVMH.js +0 -2
- package/frontend/dist/js/zh-Bvau7hlR.js +0 -2
|
@@ -22,10 +22,12 @@ import axios from 'axios';
|
|
|
22
22
|
import pluginCredentialsService from './pluginCredentialsService.js';
|
|
23
23
|
import pluginVariablesService from './pluginVariablesService.js';
|
|
24
24
|
import pluginActivationService from './pluginActivationService.js';
|
|
25
|
+
import { PluginAudioGenerationService } from './pluginAudioGenerationService.js';
|
|
25
26
|
import { PluginCapabilityRegistryService } from './pluginCapabilityRegistryService.js';
|
|
26
27
|
import { PluginEmbeddingService } from './pluginEmbeddingService.js';
|
|
27
28
|
import { PluginImageGenerationService } from './pluginImageGenerationService.js';
|
|
28
29
|
import { PluginTTSService } from './pluginTTSService.js';
|
|
30
|
+
import { PluginVideoGenerationService } from './pluginVideoGenerationService.js';
|
|
29
31
|
import { applyPluginDefinitionPolicy, buildPluginChatPayload, convertProviderResponse, getOpenAICompatibleSamplingParameters, resolvePluginChatParameters, toOpenAICompatibleMessages, } from '../utils/pluginChatAdapter.js';
|
|
30
32
|
import { streamAnthropicResponse, streamOpenAICompatibleResponse, streamOpenAIResponsesResponse, } from '../utils/pluginStreamAdapter.js';
|
|
31
33
|
import { applyModelEndpointTemplate, assertSafePluginEndpoint, buildPluginAuthHeaders, buildPluginModelDiscoveryHeaders, pluginRequiresApiKey, resolvePluginApiConfig, resolvePluginEndpoint, resolvePluginModelsEndpoint, validatePluginModel, } from '../utils/pluginValidation.js';
|
|
@@ -34,6 +36,7 @@ import { resolveBundledPluginsDir } from '../utils/packagePaths.js';
|
|
|
34
36
|
import { getDatabaseSafe } from '../db.js';
|
|
35
37
|
import { createOpenAIResponsesStateScope, createPluginCredentialFingerprint, OPENAI_RESPONSES_INCOMPLETE_REASON_METADATA_KEY, } from '../utils/openAIResponsesAdapter.js';
|
|
36
38
|
import { getPluginConnectionVariableNames } from '../utils/pluginConnectionVariables.js';
|
|
39
|
+
import pluginUsageService from './pluginUsageService.js';
|
|
37
40
|
import { getPluginDefinitionFingerprint, matchesBundledPluginTrustAnchor, } from '../utils/pluginDefinitionTrust.js';
|
|
38
41
|
const logger = createLogger('plugins');
|
|
39
42
|
const readPositiveIntEnv = (name, fallback) => {
|
|
@@ -77,6 +80,7 @@ function getPluginRoutingAuthProjection(plugin) {
|
|
|
77
80
|
return {
|
|
78
81
|
name,
|
|
79
82
|
endpoint: capability.endpoint ?? null,
|
|
83
|
+
models_endpoint: capability.models_endpoint ?? null,
|
|
80
84
|
endpoint_variable: config.endpoint_variable ?? capability.endpoint_variable ?? null,
|
|
81
85
|
};
|
|
82
86
|
});
|
|
@@ -118,6 +122,10 @@ export class PluginService {
|
|
|
118
122
|
this.discoveredModelsUpdatedAt = new Map();
|
|
119
123
|
this.discoveryAttemptedAt = new Map();
|
|
120
124
|
this.inflightDiscovery = new Map();
|
|
125
|
+
this.discoveredCapabilityModelsCache = new Map();
|
|
126
|
+
this.discoveredCapabilityModelsUpdatedAt = new Map();
|
|
127
|
+
this.capabilityDiscoveryAttemptedAt = new Map();
|
|
128
|
+
this.inflightCapabilityDiscovery = new Map();
|
|
121
129
|
this.bundledRoutingProjectionCache = new Map();
|
|
122
130
|
this.bundledPluginsDir = resolveBundledPluginsDir(import.meta.url);
|
|
123
131
|
this.legacyPluginsDir = path.join(process.cwd(), 'plugins');
|
|
@@ -134,6 +142,7 @@ export class PluginService {
|
|
|
134
142
|
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
135
143
|
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
136
144
|
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
145
|
+
recordUsage: usage => pluginUsageService.record(usage),
|
|
137
146
|
});
|
|
138
147
|
this.ttsService = new PluginTTSService({
|
|
139
148
|
getAllPlugins: userId => this.getActivePlugins(userId),
|
|
@@ -141,6 +150,7 @@ export class PluginService {
|
|
|
141
150
|
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
142
151
|
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
143
152
|
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
153
|
+
recordUsage: usage => pluginUsageService.record(usage),
|
|
144
154
|
});
|
|
145
155
|
this.imageGenerationService = new PluginImageGenerationService({
|
|
146
156
|
getAllPlugins: userId => this.getActivePlugins(userId),
|
|
@@ -148,6 +158,23 @@ export class PluginService {
|
|
|
148
158
|
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
149
159
|
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
150
160
|
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
161
|
+
recordUsage: usage => pluginUsageService.record(usage),
|
|
162
|
+
});
|
|
163
|
+
this.audioGenerationService = new PluginAudioGenerationService({
|
|
164
|
+
getAllPlugins: userId => this.getActivePlugins(userId),
|
|
165
|
+
getPlugin: (id, userId) => this.getPlugin(id, userId),
|
|
166
|
+
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
167
|
+
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
168
|
+
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
169
|
+
recordUsage: usage => pluginUsageService.record(usage),
|
|
170
|
+
});
|
|
171
|
+
this.videoGenerationService = new PluginVideoGenerationService({
|
|
172
|
+
getAllPlugins: userId => this.getActivePlugins(userId),
|
|
173
|
+
getPlugin: (id, userId) => this.getPlugin(id, userId),
|
|
174
|
+
getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
|
|
175
|
+
getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
|
|
176
|
+
validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
|
|
177
|
+
recordUsage: usage => pluginUsageService.record(usage),
|
|
151
178
|
});
|
|
152
179
|
this.capabilityRegistryService = new PluginCapabilityRegistryService({
|
|
153
180
|
getAllPlugins: userId => this.getActivePlugins(userId),
|
|
@@ -157,6 +184,65 @@ export class PluginService {
|
|
|
157
184
|
discoveredModelsCacheKey(pluginId, userId) {
|
|
158
185
|
return `${userId}:${pluginId}`;
|
|
159
186
|
}
|
|
187
|
+
discoveredCapabilityModelsCacheKey(pluginId, capability, userId) {
|
|
188
|
+
return `${userId}:${pluginId}:${capability}`;
|
|
189
|
+
}
|
|
190
|
+
getDiscoveredCapabilityModels(pluginId, capability, userId) {
|
|
191
|
+
const effectiveUserId = userId || 'default';
|
|
192
|
+
const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, effectiveUserId);
|
|
193
|
+
if (this.discoveredCapabilityModelsCache.has(cacheKey)) {
|
|
194
|
+
return this.discoveredCapabilityModelsCache.get(cacheKey) || undefined;
|
|
195
|
+
}
|
|
196
|
+
const db = getDatabaseSafe();
|
|
197
|
+
if (!db) {
|
|
198
|
+
this.discoveredCapabilityModelsCache.set(cacheKey, null);
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
const row = db
|
|
203
|
+
.prepare(`SELECT models_json, updated_at
|
|
204
|
+
FROM plugin_discovered_capability_models
|
|
205
|
+
WHERE user_id = ? AND plugin_id = ? AND capability = ?`)
|
|
206
|
+
.get(effectiveUserId, pluginId, capability);
|
|
207
|
+
if (!row) {
|
|
208
|
+
this.discoveredCapabilityModelsCache.set(cacheKey, null);
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
const parsed = JSON.parse(row.models_json);
|
|
212
|
+
const models = Array.isArray(parsed)
|
|
213
|
+
? Array.from(new Set(parsed.filter((model) => typeof model === 'string' && model.length > 0)))
|
|
214
|
+
: [];
|
|
215
|
+
if (models.length === 0) {
|
|
216
|
+
this.discoveredCapabilityModelsCache.set(cacheKey, null);
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
this.discoveredCapabilityModelsCache.set(cacheKey, models);
|
|
220
|
+
this.discoveredCapabilityModelsUpdatedAt.set(cacheKey, row.updated_at);
|
|
221
|
+
return models;
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
logger.warn('Failed to read discovered %s models for plugin %s:', capability, pluginId, error);
|
|
225
|
+
this.discoveredCapabilityModelsCache.set(cacheKey, null);
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
storeDiscoveredCapabilityModels(pluginId, capability, models, userId) {
|
|
230
|
+
const effectiveUserId = userId || 'default';
|
|
231
|
+
const uniqueModels = Array.from(new Set(models));
|
|
232
|
+
const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, effectiveUserId);
|
|
233
|
+
const discoveredAt = Date.now();
|
|
234
|
+
this.discoveredCapabilityModelsCache.set(cacheKey, uniqueModels);
|
|
235
|
+
this.discoveredCapabilityModelsUpdatedAt.set(cacheKey, discoveredAt);
|
|
236
|
+
const db = getDatabaseSafe();
|
|
237
|
+
if (!db)
|
|
238
|
+
return;
|
|
239
|
+
db.prepare(`INSERT INTO plugin_discovered_capability_models
|
|
240
|
+
(user_id, plugin_id, capability, models_json, updated_at)
|
|
241
|
+
VALUES (?, ?, ?, ?, ?)
|
|
242
|
+
ON CONFLICT(user_id, plugin_id, capability) DO UPDATE SET
|
|
243
|
+
models_json = excluded.models_json,
|
|
244
|
+
updated_at = excluded.updated_at`).run(effectiveUserId, pluginId, capability, JSON.stringify(uniqueModels), discoveredAt);
|
|
245
|
+
}
|
|
160
246
|
getDiscoveredModels(pluginId, userId) {
|
|
161
247
|
const effectiveUserId = userId || 'default';
|
|
162
248
|
const cacheKey = this.discoveredModelsCacheKey(pluginId, effectiveUserId);
|
|
@@ -219,6 +305,7 @@ export class PluginService {
|
|
|
219
305
|
}
|
|
220
306
|
}
|
|
221
307
|
clearDiscoveredModels(pluginId, userId) {
|
|
308
|
+
this.clearDiscoveredCapabilityModels(pluginId, userId);
|
|
222
309
|
const db = getDatabaseSafe();
|
|
223
310
|
if (userId) {
|
|
224
311
|
const cacheKey = this.discoveredModelsCacheKey(pluginId, userId);
|
|
@@ -251,13 +338,58 @@ export class PluginService {
|
|
|
251
338
|
logger.warn('Failed to clear discovered models for plugin %s:', pluginId, error);
|
|
252
339
|
}
|
|
253
340
|
}
|
|
341
|
+
clearDiscoveredCapabilityModels(pluginId, userId) {
|
|
342
|
+
const db = getDatabaseSafe();
|
|
343
|
+
if (userId) {
|
|
344
|
+
for (const capability of ['image', 'tts', 'audio', 'video']) {
|
|
345
|
+
const key = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId);
|
|
346
|
+
this.discoveredCapabilityModelsCache.delete(key);
|
|
347
|
+
this.discoveredCapabilityModelsUpdatedAt.delete(key);
|
|
348
|
+
this.capabilityDiscoveryAttemptedAt.delete(key);
|
|
349
|
+
}
|
|
350
|
+
if (db) {
|
|
351
|
+
db.prepare(`DELETE FROM plugin_discovered_capability_models
|
|
352
|
+
WHERE user_id = ? AND plugin_id = ?`).run(userId, pluginId);
|
|
353
|
+
}
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
for (const key of this.discoveredCapabilityModelsCache.keys()) {
|
|
357
|
+
if (['image', 'tts', 'audio', 'video'].some(capability => key.endsWith(`:${pluginId}:${capability}`))) {
|
|
358
|
+
this.discoveredCapabilityModelsCache.delete(key);
|
|
359
|
+
this.discoveredCapabilityModelsUpdatedAt.delete(key);
|
|
360
|
+
this.capabilityDiscoveryAttemptedAt.delete(key);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (db) {
|
|
364
|
+
db.prepare('DELETE FROM plugin_discovered_capability_models WHERE plugin_id = ?').run(pluginId);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
254
367
|
applyDiscoveredModels(plugin, userId) {
|
|
255
368
|
if (!this.canUseStoredConnectionOverrides(userId) &&
|
|
256
369
|
pluginVariablesService.hasStoredConnectionOverride(plugin.id, userId, plugin.variables, getPluginConnectionVariableNames(plugin))) {
|
|
257
370
|
return plugin;
|
|
258
371
|
}
|
|
259
372
|
const models = this.getDiscoveredModels(plugin.id, userId);
|
|
260
|
-
|
|
373
|
+
const capabilities = plugin.capabilities
|
|
374
|
+
? { ...plugin.capabilities }
|
|
375
|
+
: undefined;
|
|
376
|
+
if (capabilities) {
|
|
377
|
+
for (const capability of ['image', 'tts', 'audio', 'video']) {
|
|
378
|
+
const definition = capabilities[capability];
|
|
379
|
+
const discovered = this.getDiscoveredCapabilityModels(plugin.id, capability, userId);
|
|
380
|
+
if (definition && discovered) {
|
|
381
|
+
capabilities[capability] = {
|
|
382
|
+
...definition,
|
|
383
|
+
model_map: [...discovered],
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
...plugin,
|
|
390
|
+
...(models ? { model_map: [...models] } : {}),
|
|
391
|
+
...(capabilities ? { capabilities } : {}),
|
|
392
|
+
};
|
|
261
393
|
}
|
|
262
394
|
ensurePluginsDirectory() {
|
|
263
395
|
if (!fs.existsSync(this.pluginsDir)) {
|
|
@@ -566,6 +698,98 @@ export class PluginService {
|
|
|
566
698
|
new Promise(resolve => setTimeout(resolve, modelDiscoveryRefreshDeadlineMs()).unref?.()),
|
|
567
699
|
]);
|
|
568
700
|
}
|
|
701
|
+
async discoverCapabilityModels(pluginId, capability, userId) {
|
|
702
|
+
const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId || 'default');
|
|
703
|
+
const inflight = this.inflightCapabilityDiscovery.get(cacheKey);
|
|
704
|
+
if (inflight)
|
|
705
|
+
return inflight;
|
|
706
|
+
const attempt = this.runCapabilityModelDiscovery(pluginId, capability, userId).finally(() => this.inflightCapabilityDiscovery.delete(cacheKey));
|
|
707
|
+
this.inflightCapabilityDiscovery.set(cacheKey, attempt);
|
|
708
|
+
return attempt;
|
|
709
|
+
}
|
|
710
|
+
isCapabilityModelDiscoveryDue(pluginId, capability, userId) {
|
|
711
|
+
const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId || 'default');
|
|
712
|
+
const attemptedAt = this.capabilityDiscoveryAttemptedAt.get(cacheKey);
|
|
713
|
+
if (attemptedAt && Date.now() - attemptedAt < modelDiscoveryRetryMs()) {
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
const models = this.getDiscoveredCapabilityModels(pluginId, capability, userId);
|
|
717
|
+
const updatedAt = this.discoveredCapabilityModelsUpdatedAt.get(cacheKey);
|
|
718
|
+
return (!models || !updatedAt || Date.now() - updatedAt >= modelDiscoveryTtlMs());
|
|
719
|
+
}
|
|
720
|
+
async refreshStaleCapabilityModels(capability, userId) {
|
|
721
|
+
const due = this.getActivePlugins(userId).filter(plugin => {
|
|
722
|
+
const definition = plugin.capabilities?.[capability];
|
|
723
|
+
return (Boolean(definition?.models_endpoint) &&
|
|
724
|
+
this.isCapabilityModelDiscoveryDue(plugin.id, capability, userId));
|
|
725
|
+
});
|
|
726
|
+
if (due.length === 0)
|
|
727
|
+
return;
|
|
728
|
+
const refreshes = Promise.all(due.map(plugin => this.discoverCapabilityModels(plugin.id, capability, userId).catch(() => undefined)));
|
|
729
|
+
await Promise.race([
|
|
730
|
+
refreshes,
|
|
731
|
+
new Promise(resolve => setTimeout(resolve, modelDiscoveryRefreshDeadlineMs()).unref?.()),
|
|
732
|
+
]);
|
|
733
|
+
}
|
|
734
|
+
async runCapabilityModelDiscovery(pluginId, capability, userId) {
|
|
735
|
+
const plugin = this.getPlugin(pluginId, userId);
|
|
736
|
+
const definition = plugin?.capabilities?.[capability];
|
|
737
|
+
if (!plugin || !definition) {
|
|
738
|
+
return {
|
|
739
|
+
models: [],
|
|
740
|
+
outcome: 'unavailable',
|
|
741
|
+
reason: `Plugin has no ${capability} capability`,
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
if (!definition.models_endpoint) {
|
|
745
|
+
return { models: definition.model_map, outcome: 'unchanged' };
|
|
746
|
+
}
|
|
747
|
+
const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId || 'default');
|
|
748
|
+
this.capabilityDiscoveryAttemptedAt.set(cacheKey, Date.now());
|
|
749
|
+
const modelsEndpoint = definition.models_endpoint;
|
|
750
|
+
assertSafePluginEndpoint(modelsEndpoint, `${capability} model discovery endpoint`);
|
|
751
|
+
const apiKey = this.getApiKey(plugin, userId);
|
|
752
|
+
if (pluginRequiresApiKey(plugin) && !apiKey) {
|
|
753
|
+
return {
|
|
754
|
+
models: definition.model_map,
|
|
755
|
+
outcome: 'missing_credentials',
|
|
756
|
+
reason: this.describeMissingCredential(plugin),
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
try {
|
|
760
|
+
const response = await axios.get(modelsEndpoint, {
|
|
761
|
+
headers: buildPluginModelDiscoveryHeaders(plugin, apiKey, modelsEndpoint),
|
|
762
|
+
timeout: MODEL_DISCOVERY_REQUEST_TIMEOUT_MS,
|
|
763
|
+
maxRedirects: 0,
|
|
764
|
+
});
|
|
765
|
+
const data = response.data?.data;
|
|
766
|
+
const models = Array.isArray(data)
|
|
767
|
+
? Array.from(new Set(data
|
|
768
|
+
.map((entry) => entry?.id)
|
|
769
|
+
.filter((id) => typeof id === 'string' && id.length > 0)))
|
|
770
|
+
: [];
|
|
771
|
+
if (models.length === 0) {
|
|
772
|
+
return {
|
|
773
|
+
models: definition.model_map,
|
|
774
|
+
outcome: 'unavailable',
|
|
775
|
+
reason: 'The provider returned no models',
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
const previous = definition.model_map;
|
|
779
|
+
this.storeDiscoveredCapabilityModels(pluginId, capability, models, userId);
|
|
780
|
+
return {
|
|
781
|
+
models,
|
|
782
|
+
outcome: JSON.stringify(previous) === JSON.stringify(models)
|
|
783
|
+
? 'unchanged'
|
|
784
|
+
: 'updated',
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
catch (error) {
|
|
788
|
+
const reason = describeModelDiscoveryFailure(error);
|
|
789
|
+
logger.debug('[Plugin] %s model discovery unavailable for %s (%s)', capability, pluginId, reason);
|
|
790
|
+
return { models: definition.model_map, outcome: 'unavailable', reason };
|
|
791
|
+
}
|
|
792
|
+
}
|
|
569
793
|
/**
|
|
570
794
|
* Say why no key was usable. An environment key is deliberately ignored for a
|
|
571
795
|
* provider whose definition was installed into the writable plugins directory,
|
|
@@ -602,7 +826,7 @@ export class PluginService {
|
|
|
602
826
|
reason: this.describeMissingCredential(plugin),
|
|
603
827
|
};
|
|
604
828
|
}
|
|
605
|
-
const headers = buildPluginModelDiscoveryHeaders(plugin, apiKey);
|
|
829
|
+
const headers = buildPluginModelDiscoveryHeaders(plugin, apiKey, modelsEndpoint);
|
|
606
830
|
try {
|
|
607
831
|
const response = await axios.get(modelsEndpoint, {
|
|
608
832
|
headers,
|
|
@@ -810,7 +1034,12 @@ export class PluginService {
|
|
|
810
1034
|
}
|
|
811
1035
|
// Wait for discovery so the activation response and the UI's first reload
|
|
812
1036
|
// observe the same user-scoped model catalog.
|
|
813
|
-
await
|
|
1037
|
+
await Promise.all([
|
|
1038
|
+
this.discoverModels(id, userId).catch(() => []),
|
|
1039
|
+
...['image', 'tts', 'audio', 'video']
|
|
1040
|
+
.filter(capability => plugin.capabilities?.[capability]?.models_endpoint)
|
|
1041
|
+
.map(capability => this.discoverCapabilityModels(id, capability, userId).catch(() => undefined)),
|
|
1042
|
+
]);
|
|
814
1043
|
return true;
|
|
815
1044
|
}
|
|
816
1045
|
// Deactivate a specific plugin
|
|
@@ -897,18 +1126,45 @@ export class PluginService {
|
|
|
897
1126
|
const providerStateScope = apiMode === 'responses'
|
|
898
1127
|
? createOpenAIResponsesStateScope(activePlugin.id, model, processedEndpoint, createPluginCredentialFingerprint(apiKey))
|
|
899
1128
|
: undefined;
|
|
900
|
-
const headers = buildPluginAuthHeaders(activePlugin, apiKey);
|
|
1129
|
+
const headers = buildPluginAuthHeaders(activePlugin, apiKey, processedEndpoint);
|
|
901
1130
|
const { payload, headers: payloadHeaders } = buildPluginChatPayload(activePlugin, model, messages, options, pluginVars, false, apiMode, providerStateScope);
|
|
902
1131
|
Object.assign(headers, payloadHeaders);
|
|
1132
|
+
const startedAt = Date.now();
|
|
903
1133
|
try {
|
|
904
1134
|
const response = await axios.post(processedEndpoint, payload, {
|
|
905
1135
|
headers,
|
|
906
1136
|
timeout: 60000, // 60 second timeout
|
|
907
1137
|
maxRedirects: 0,
|
|
908
1138
|
});
|
|
909
|
-
|
|
1139
|
+
const normalized = convertProviderResponse(activePlugin, response.data, model, apiMode, providerStateScope);
|
|
1140
|
+
pluginUsageService.record({
|
|
1141
|
+
userId,
|
|
1142
|
+
pluginId: activePlugin.id,
|
|
1143
|
+
pluginName: activePlugin.name,
|
|
1144
|
+
capability: 'chat',
|
|
1145
|
+
model,
|
|
1146
|
+
status: 'success',
|
|
1147
|
+
durationMs: Date.now() - startedAt,
|
|
1148
|
+
tokens: normalized.usage
|
|
1149
|
+
? {
|
|
1150
|
+
promptTokens: normalized.usage.prompt_tokens,
|
|
1151
|
+
completionTokens: normalized.usage.completion_tokens,
|
|
1152
|
+
totalTokens: normalized.usage.total_tokens,
|
|
1153
|
+
}
|
|
1154
|
+
: undefined,
|
|
1155
|
+
});
|
|
1156
|
+
return normalized;
|
|
910
1157
|
}
|
|
911
1158
|
catch (error) {
|
|
1159
|
+
pluginUsageService.record({
|
|
1160
|
+
userId,
|
|
1161
|
+
pluginId: activePlugin.id,
|
|
1162
|
+
pluginName: activePlugin.name,
|
|
1163
|
+
capability: 'chat',
|
|
1164
|
+
model,
|
|
1165
|
+
status: 'error',
|
|
1166
|
+
durationMs: Date.now() - startedAt,
|
|
1167
|
+
});
|
|
912
1168
|
logger.error(`Plugin request failed for ${activePlugin.id}:`, error);
|
|
913
1169
|
if (error && typeof error === 'object' && 'response' in error) {
|
|
914
1170
|
const axiosError = error;
|
|
@@ -948,7 +1204,7 @@ export class PluginService {
|
|
|
948
1204
|
const providerStateScope = apiMode === 'responses'
|
|
949
1205
|
? createOpenAIResponsesStateScope(activePlugin.id, model, processedEndpoint, createPluginCredentialFingerprint(apiKey))
|
|
950
1206
|
: undefined;
|
|
951
|
-
const headers = buildPluginAuthHeaders(activePlugin, apiKey);
|
|
1207
|
+
const headers = buildPluginAuthHeaders(activePlugin, apiKey, processedEndpoint);
|
|
952
1208
|
let payload;
|
|
953
1209
|
if (activePlugin.id === 'anthropic' || apiMode === 'responses') {
|
|
954
1210
|
const pluginRequest = buildPluginChatPayload(activePlugin, model, messages, options, pluginVars, true, apiMode, providerStateScope);
|
|
@@ -966,77 +1222,124 @@ export class PluginService {
|
|
|
966
1222
|
stream: true,
|
|
967
1223
|
};
|
|
968
1224
|
}
|
|
969
|
-
const
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1225
|
+
const startedAt = Date.now();
|
|
1226
|
+
let status = 'cancelled';
|
|
1227
|
+
let tokenUsage;
|
|
1228
|
+
const captureUsage = (chunk) => {
|
|
1229
|
+
if (chunk.type !== 'usage' || !chunk.usage)
|
|
1230
|
+
return;
|
|
1231
|
+
const { promptTokens, completionTokens, totalTokens } = chunk.usage;
|
|
1232
|
+
if (promptTokens === undefined &&
|
|
1233
|
+
completionTokens === undefined &&
|
|
1234
|
+
totalTokens === undefined) {
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
const prompt = promptTokens ?? 0;
|
|
1238
|
+
const completion = completionTokens ?? 0;
|
|
1239
|
+
tokenUsage = {
|
|
1240
|
+
promptTokens: prompt,
|
|
1241
|
+
completionTokens: completion,
|
|
1242
|
+
totalTokens: totalTokens ?? prompt + completion,
|
|
1243
|
+
};
|
|
1244
|
+
};
|
|
1245
|
+
const forward = async function* (chunks) {
|
|
1246
|
+
for await (const chunk of chunks) {
|
|
1247
|
+
captureUsage(chunk);
|
|
1248
|
+
yield chunk;
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
try {
|
|
1252
|
+
const response = await fetch(processedEndpoint, {
|
|
1253
|
+
method: 'POST',
|
|
1254
|
+
headers,
|
|
1255
|
+
body: JSON.stringify(payload),
|
|
1256
|
+
redirect: 'error',
|
|
1257
|
+
});
|
|
1258
|
+
if (activePlugin.id === 'anthropic') {
|
|
1259
|
+
yield* forward(streamAnthropicResponse(response));
|
|
1260
|
+
}
|
|
1261
|
+
else if (apiMode === 'responses') {
|
|
1262
|
+
const contentType = response.headers.get('content-type') || '';
|
|
1263
|
+
if (!contentType.includes('text/event-stream')) {
|
|
1264
|
+
if (!response.ok) {
|
|
1265
|
+
const errorText = await response.text();
|
|
1266
|
+
throw new Error(`Plugin API error: ${response.status} - ${errorText.slice(0, 200)}`);
|
|
1267
|
+
}
|
|
1268
|
+
const normalized = convertProviderResponse(activePlugin, (await response.json()), model, apiMode, providerStateScope);
|
|
1269
|
+
const choice = normalized.choices[0];
|
|
1270
|
+
const message = choice?.message;
|
|
1271
|
+
if (typeof message?.content === 'string' && message.content) {
|
|
1272
|
+
yield { type: 'content', content: message.content };
|
|
1273
|
+
}
|
|
1274
|
+
if (typeof message?.reasoning_content === 'string' &&
|
|
1275
|
+
message.reasoning_content) {
|
|
1276
|
+
yield {
|
|
1277
|
+
type: 'reasoning',
|
|
1278
|
+
content: message.reasoning_content,
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
for (const call of message?.tool_calls || []) {
|
|
1282
|
+
yield {
|
|
1283
|
+
type: 'tool_call',
|
|
1284
|
+
toolCall: {
|
|
1285
|
+
id: call.id,
|
|
1286
|
+
name: call.function.name,
|
|
1287
|
+
arguments: call.function.arguments,
|
|
1288
|
+
...(call.providerMetadata
|
|
1289
|
+
? { providerMetadata: call.providerMetadata }
|
|
1290
|
+
: {}),
|
|
1291
|
+
},
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
if (normalized.usage) {
|
|
1295
|
+
const usageChunk = {
|
|
1296
|
+
type: 'usage',
|
|
1297
|
+
usage: {
|
|
1298
|
+
promptTokens: normalized.usage.prompt_tokens,
|
|
1299
|
+
completionTokens: normalized.usage.completion_tokens,
|
|
1300
|
+
totalTokens: normalized.usage.total_tokens,
|
|
1301
|
+
},
|
|
1302
|
+
};
|
|
1303
|
+
captureUsage(usageChunk);
|
|
1304
|
+
yield usageChunk;
|
|
1305
|
+
}
|
|
1306
|
+
const incompleteReason = typeof normalized.providerMetadata?.[OPENAI_RESPONSES_INCOMPLETE_REASON_METADATA_KEY] === 'string'
|
|
1307
|
+
? normalized.providerMetadata[OPENAI_RESPONSES_INCOMPLETE_REASON_METADATA_KEY]
|
|
1308
|
+
: undefined;
|
|
999
1309
|
yield {
|
|
1000
|
-
type: '
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
: {}),
|
|
1008
|
-
},
|
|
1310
|
+
type: 'done',
|
|
1311
|
+
...(incompleteReason
|
|
1312
|
+
? { doneReason: `incomplete:${incompleteReason}` }
|
|
1313
|
+
: {}),
|
|
1314
|
+
...(normalized.providerMetadata
|
|
1315
|
+
? { providerMetadata: normalized.providerMetadata }
|
|
1316
|
+
: {}),
|
|
1009
1317
|
};
|
|
1010
1318
|
}
|
|
1011
|
-
|
|
1012
|
-
yield
|
|
1013
|
-
type: 'usage',
|
|
1014
|
-
usage: {
|
|
1015
|
-
promptTokens: normalized.usage.prompt_tokens,
|
|
1016
|
-
completionTokens: normalized.usage.completion_tokens,
|
|
1017
|
-
totalTokens: normalized.usage.total_tokens,
|
|
1018
|
-
},
|
|
1019
|
-
};
|
|
1319
|
+
else {
|
|
1320
|
+
yield* forward(streamOpenAIResponsesResponse(response, providerStateScope));
|
|
1020
1321
|
}
|
|
1021
|
-
const incompleteReason = typeof normalized.providerMetadata?.[OPENAI_RESPONSES_INCOMPLETE_REASON_METADATA_KEY] === 'string'
|
|
1022
|
-
? normalized.providerMetadata[OPENAI_RESPONSES_INCOMPLETE_REASON_METADATA_KEY]
|
|
1023
|
-
: undefined;
|
|
1024
|
-
yield {
|
|
1025
|
-
type: 'done',
|
|
1026
|
-
...(incompleteReason
|
|
1027
|
-
? { doneReason: `incomplete:${incompleteReason}` }
|
|
1028
|
-
: {}),
|
|
1029
|
-
...(normalized.providerMetadata
|
|
1030
|
-
? { providerMetadata: normalized.providerMetadata }
|
|
1031
|
-
: {}),
|
|
1032
|
-
};
|
|
1033
1322
|
}
|
|
1034
1323
|
else {
|
|
1035
|
-
yield*
|
|
1324
|
+
yield* forward(streamOpenAICompatibleResponse(response));
|
|
1036
1325
|
}
|
|
1326
|
+
status = 'success';
|
|
1037
1327
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1328
|
+
catch (error) {
|
|
1329
|
+
status = 'error';
|
|
1330
|
+
throw error;
|
|
1331
|
+
}
|
|
1332
|
+
finally {
|
|
1333
|
+
pluginUsageService.record({
|
|
1334
|
+
userId,
|
|
1335
|
+
pluginId: activePlugin.id,
|
|
1336
|
+
pluginName: activePlugin.name,
|
|
1337
|
+
capability: 'chat',
|
|
1338
|
+
model,
|
|
1339
|
+
status,
|
|
1340
|
+
durationMs: Date.now() - startedAt,
|
|
1341
|
+
tokens: tokenUsage,
|
|
1342
|
+
});
|
|
1040
1343
|
}
|
|
1041
1344
|
}
|
|
1042
1345
|
// Validate plugin structure
|
|
@@ -1152,6 +1455,24 @@ export class PluginService {
|
|
|
1152
1455
|
getPluginsByCapability(capabilityType, userId) {
|
|
1153
1456
|
return this.capabilityRegistryService.getPluginsByCapability(capabilityType, userId);
|
|
1154
1457
|
}
|
|
1458
|
+
getAvailableAudioGenModels(userId) {
|
|
1459
|
+
return this.audioGenerationService.getAvailableModels(userId);
|
|
1460
|
+
}
|
|
1461
|
+
executeAudioGenRequest(model, prompt, options) {
|
|
1462
|
+
return this.audioGenerationService.generate(model, prompt, options);
|
|
1463
|
+
}
|
|
1464
|
+
getAvailableVideoGenModels(userId) {
|
|
1465
|
+
return this.videoGenerationService.getAvailableModels(userId);
|
|
1466
|
+
}
|
|
1467
|
+
submitVideoGenRequest(model, prompt, options) {
|
|
1468
|
+
return this.videoGenerationService.submit(model, prompt, options);
|
|
1469
|
+
}
|
|
1470
|
+
pollVideoGenRequest(model, providerJobId, pluginId, userId) {
|
|
1471
|
+
return this.videoGenerationService.poll(model, providerJobId, pluginId, userId);
|
|
1472
|
+
}
|
|
1473
|
+
downloadVideoGenResult(model, providerJobId, pluginId, userId) {
|
|
1474
|
+
return this.videoGenerationService.download(model, providerJobId, pluginId, userId);
|
|
1475
|
+
}
|
|
1155
1476
|
}
|
|
1156
1477
|
export default new PluginService();
|
|
1157
1478
|
//# sourceMappingURL=pluginService.js.map
|