libre-webui 0.15.0 → 0.16.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 +26 -10
- package/backend/dist/db.d.ts.map +1 -1
- package/backend/dist/db.js +63 -0
- package/backend/dist/db.js.map +1 -1
- package/backend/dist/index.d.ts.map +1 -1
- package/backend/dist/index.js +4 -4
- package/backend/dist/index.js.map +1 -1
- package/backend/dist/routes/chat.d.ts.map +1 -1
- package/backend/dist/routes/chat.js +93 -10
- package/backend/dist/routes/chat.js.map +1 -1
- package/backend/dist/routes/imageGen.d.ts.map +1 -1
- package/backend/dist/routes/imageGen.js +52 -29
- package/backend/dist/routes/imageGen.js.map +1 -1
- package/backend/dist/routes/plugins.d.ts.map +1 -1
- package/backend/dist/routes/plugins.js +218 -41
- 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 +5 -4
- package/backend/dist/routes/preferences.js.map +1 -1
- package/backend/dist/routes/tts.js +2 -2
- package/backend/dist/routes/tts.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 +3 -1
- package/backend/dist/services/assistantCompletionService.js.map +1 -1
- package/backend/dist/services/chatGenerationService.d.ts +5 -3
- package/backend/dist/services/chatGenerationService.d.ts.map +1 -1
- package/backend/dist/services/chatGenerationService.js +18 -6
- package/backend/dist/services/chatGenerationService.js.map +1 -1
- package/backend/dist/services/chatRequestService.d.ts +6 -4
- package/backend/dist/services/chatRequestService.d.ts.map +1 -1
- package/backend/dist/services/chatRequestService.js +10 -2
- package/backend/dist/services/chatRequestService.js.map +1 -1
- package/backend/dist/services/chatService.d.ts +2 -2
- package/backend/dist/services/chatService.d.ts.map +1 -1
- package/backend/dist/services/chatService.js +29 -17
- package/backend/dist/services/chatService.js.map +1 -1
- package/backend/dist/services/embeddingService.js +1 -1
- package/backend/dist/services/embeddingService.js.map +1 -1
- package/backend/dist/services/pluginActivationService.d.ts +11 -0
- package/backend/dist/services/pluginActivationService.d.ts.map +1 -0
- package/backend/dist/services/pluginActivationService.js +163 -0
- package/backend/dist/services/pluginActivationService.js.map +1 -0
- package/backend/dist/services/pluginCapabilityRegistryService.d.ts +1 -1
- package/backend/dist/services/pluginCapabilityRegistryService.d.ts.map +1 -1
- package/backend/dist/services/pluginCapabilityRegistryService.js +1 -1
- package/backend/dist/services/pluginCapabilityRegistryService.js.map +1 -1
- package/backend/dist/services/pluginCredentialsService.d.ts +16 -8
- package/backend/dist/services/pluginCredentialsService.d.ts.map +1 -1
- package/backend/dist/services/pluginCredentialsService.js +47 -14
- package/backend/dist/services/pluginCredentialsService.js.map +1 -1
- package/backend/dist/services/pluginEmbeddingService.d.ts +2 -2
- package/backend/dist/services/pluginEmbeddingService.d.ts.map +1 -1
- package/backend/dist/services/pluginEmbeddingService.js +33 -13
- package/backend/dist/services/pluginEmbeddingService.js.map +1 -1
- package/backend/dist/services/pluginImageGenerationService.d.ts +11 -7
- package/backend/dist/services/pluginImageGenerationService.d.ts.map +1 -1
- package/backend/dist/services/pluginImageGenerationService.js +265 -81
- package/backend/dist/services/pluginImageGenerationService.js.map +1 -1
- package/backend/dist/services/pluginService.d.ts +55 -25
- package/backend/dist/services/pluginService.d.ts.map +1 -1
- package/backend/dist/services/pluginService.js +663 -174
- package/backend/dist/services/pluginService.js.map +1 -1
- package/backend/dist/services/pluginTTSService.d.ts +4 -4
- package/backend/dist/services/pluginTTSService.d.ts.map +1 -1
- package/backend/dist/services/pluginTTSService.js +24 -28
- package/backend/dist/services/pluginTTSService.js.map +1 -1
- package/backend/dist/services/pluginVariablesService.d.ts +6 -1
- package/backend/dist/services/pluginVariablesService.d.ts.map +1 -1
- package/backend/dist/services/pluginVariablesService.js +59 -1
- package/backend/dist/services/pluginVariablesService.js.map +1 -1
- package/backend/dist/services/preferencesService.d.ts +2 -2
- package/backend/dist/services/preferencesService.d.ts.map +1 -1
- package/backend/dist/services/preferencesService.js +78 -10
- package/backend/dist/services/preferencesService.js.map +1 -1
- package/backend/dist/services/titleGenerationService.d.ts +6 -4
- package/backend/dist/services/titleGenerationService.d.ts.map +1 -1
- package/backend/dist/services/titleGenerationService.js +9 -5
- package/backend/dist/services/titleGenerationService.js.map +1 -1
- package/backend/dist/services/workAgentGuidance.d.ts +1 -0
- package/backend/dist/services/workAgentGuidance.d.ts.map +1 -1
- package/backend/dist/services/workAgentGuidance.js +2 -0
- package/backend/dist/services/workAgentGuidance.js.map +1 -1
- package/backend/dist/services/workAgentService.d.ts +5 -2
- package/backend/dist/services/workAgentService.d.ts.map +1 -1
- package/backend/dist/services/workAgentService.js +379 -53
- package/backend/dist/services/workAgentService.js.map +1 -1
- package/backend/dist/services/workModelProviderService.d.ts +8 -3
- package/backend/dist/services/workModelProviderService.d.ts.map +1 -1
- package/backend/dist/services/workModelProviderService.js +293 -33
- package/backend/dist/services/workModelProviderService.js.map +1 -1
- package/backend/dist/services/workTaskService.d.ts +2 -0
- package/backend/dist/services/workTaskService.d.ts.map +1 -1
- package/backend/dist/services/workTaskService.js +89 -14
- package/backend/dist/services/workTaskService.js.map +1 -1
- package/backend/dist/storage.d.ts.map +1 -1
- package/backend/dist/storage.js +9 -6
- package/backend/dist/storage.js.map +1 -1
- package/backend/dist/storageMappers.d.ts +3 -0
- package/backend/dist/storageMappers.d.ts.map +1 -1
- package/backend/dist/storageMappers.js +3 -0
- package/backend/dist/storageMappers.js.map +1 -1
- package/backend/dist/types/index.d.ts +54 -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 +1 -1
- package/backend/dist/types/work.d.ts.map +1 -1
- package/backend/dist/utils/chatContext.d.ts +13 -1
- package/backend/dist/utils/chatContext.d.ts.map +1 -1
- package/backend/dist/utils/chatContext.js +52 -0
- package/backend/dist/utils/chatContext.js.map +1 -1
- package/backend/dist/utils/chatProviderSelection.d.ts +15 -0
- package/backend/dist/utils/chatProviderSelection.d.ts.map +1 -0
- package/backend/dist/utils/chatProviderSelection.js +59 -0
- package/backend/dist/utils/chatProviderSelection.js.map +1 -0
- package/backend/dist/utils/imageGenerationValidation.d.ts +3 -0
- package/backend/dist/utils/imageGenerationValidation.d.ts.map +1 -0
- package/backend/dist/utils/imageGenerationValidation.js +55 -0
- package/backend/dist/utils/imageGenerationValidation.js.map +1 -0
- package/backend/dist/utils/ollamaLibrary.d.ts.map +1 -1
- package/backend/dist/utils/ollamaLibrary.js +81 -8
- package/backend/dist/utils/ollamaLibrary.js.map +1 -1
- package/backend/dist/utils/openAIResponsesAdapter.d.ts +88 -0
- package/backend/dist/utils/openAIResponsesAdapter.d.ts.map +1 -0
- package/backend/dist/utils/openAIResponsesAdapter.js +521 -0
- package/backend/dist/utils/openAIResponsesAdapter.js.map +1 -0
- package/backend/dist/utils/pluginChatAdapter.d.ts +7 -4
- package/backend/dist/utils/pluginChatAdapter.d.ts.map +1 -1
- package/backend/dist/utils/pluginChatAdapter.js +33 -5
- package/backend/dist/utils/pluginChatAdapter.js.map +1 -1
- package/backend/dist/utils/pluginChatContext.d.ts.map +1 -1
- package/backend/dist/utils/pluginChatContext.js +5 -1
- package/backend/dist/utils/pluginChatContext.js.map +1 -1
- package/backend/dist/utils/pluginConnectionVariables.d.ts +6 -0
- package/backend/dist/utils/pluginConnectionVariables.d.ts.map +1 -0
- package/backend/dist/utils/pluginConnectionVariables.js +52 -0
- package/backend/dist/utils/pluginConnectionVariables.js.map +1 -0
- package/backend/dist/utils/pluginDefinitionTrust.d.ts +9 -0
- package/backend/dist/utils/pluginDefinitionTrust.d.ts.map +1 -0
- package/backend/dist/utils/pluginDefinitionTrust.js +71 -0
- package/backend/dist/utils/pluginDefinitionTrust.js.map +1 -0
- package/backend/dist/utils/pluginStreamAdapter.d.ts +3 -0
- package/backend/dist/utils/pluginStreamAdapter.d.ts.map +1 -1
- package/backend/dist/utils/pluginStreamAdapter.js +410 -0
- package/backend/dist/utils/pluginStreamAdapter.js.map +1 -1
- package/backend/dist/utils/pluginStreaming.d.ts +7 -1
- package/backend/dist/utils/pluginStreaming.d.ts.map +1 -1
- package/backend/dist/utils/pluginStreaming.js +12 -1
- package/backend/dist/utils/pluginStreaming.js.map +1 -1
- package/backend/dist/utils/pluginValidation.d.ts +21 -2
- package/backend/dist/utils/pluginValidation.d.ts.map +1 -1
- package/backend/dist/utils/pluginValidation.js +190 -17
- package/backend/dist/utils/pluginValidation.js.map +1 -1
- package/backend/dist/utils/pluginVariableValidation.d.ts +7 -0
- package/backend/dist/utils/pluginVariableValidation.d.ts.map +1 -1
- package/backend/dist/utils/pluginVariableValidation.js +79 -4
- package/backend/dist/utils/pluginVariableValidation.js.map +1 -1
- package/backend/dist/websocketServer.d.ts.map +1 -1
- package/backend/dist/websocketServer.js +16 -3
- package/backend/dist/websocketServer.js.map +1 -1
- package/backend/package.json +1 -1
- package/frontend/dist/assets/index-CKV9Lnj8.js +5 -0
- package/frontend/dist/assets/index-Dme2Ozol.css +1 -0
- package/frontend/dist/index.html +4 -4
- package/frontend/dist/js/{ArtifactContainer-CXfmVx8T.js → ArtifactContainer-B0uVR8Z9.js} +1 -1
- package/frontend/dist/js/{ArtifactDemoPage-B1_AuMd2.js → ArtifactDemoPage-DBVPHFxk.js} +1 -1
- package/frontend/dist/js/{ArtifactSlideOutPanel-C0eTguNL.js → ArtifactSlideOutPanel-Cg5kAwv9.js} +1 -1
- package/frontend/dist/js/ChatPage-CPHlIZqU.js +16 -0
- package/frontend/dist/js/{FirstTimeSetup-DOoZUaRs.js → FirstTimeSetup-DksL5arK.js} +1 -1
- package/frontend/dist/js/GalleryPage-1mdUGo_N.js +1 -0
- package/frontend/dist/js/LibreClawPage-qGr1Jy8p.js +1 -0
- package/frontend/dist/js/{ModelManagerModals-DneqFQJC.js → ModelManagerModals-DltRprHU.js} +1 -1
- package/frontend/dist/js/ModelSelector-CUnwRmNU.js +1 -0
- package/frontend/dist/js/ModelsPage-DMYVg3LT.js +2 -0
- package/frontend/dist/js/PersonasPage-Ct-KKW-j.js +13 -0
- package/frontend/dist/js/{RichMessageContent-WQLdJ5jq.js → RichMessageContent-CGBAcUES.js} +1 -1
- package/frontend/dist/js/SettingsModal-BVj3gFCS.js +1 -0
- package/frontend/dist/js/UserManagementPage-D3tLGtTu.js +1 -0
- package/frontend/dist/js/WorkPage-DhTjy-kf.js +2 -0
- package/frontend/dist/js/api-YWoSobKv.js +19 -0
- package/frontend/dist/js/{ar-CCVY0-7X.js → ar-KceI0PfT.js} +1 -1
- package/frontend/dist/js/{bn-CoU5CSph.js → bn-DsKo2dzS.js} +1 -1
- package/frontend/dist/js/{cs-CR6pjIbG.js → cs-6UKhKj0A.js} +1 -1
- package/frontend/dist/js/{da-CkyYITRz.js → da-CJgZ3YuL.js} +1 -1
- package/frontend/dist/js/{de-DwNANzB-.js → de-BZAmOuCT.js} +1 -1
- package/frontend/dist/js/{es-TxygiaVQ.js → es-CD4u7no9.js} +1 -1
- package/frontend/dist/js/{estree-DPzMpjFm.js → estree-PDLT672k.js} +1 -1
- package/frontend/dist/js/{fr-DvEqVpZr.js → fr-Cou2jOS3.js} +1 -1
- package/frontend/dist/js/{hi-CyrWkyh7.js → hi-ZxkbNCyB.js} +1 -1
- package/frontend/dist/js/{html-R50jmBYq.js → html-CkhF9wDQ.js} +1 -1
- package/frontend/dist/js/{id-PJjIGHGM.js → id-DT9CqaWQ.js} +1 -1
- package/frontend/dist/js/{is-ChXcN1tI.js → is-BWSbAIoq.js} +1 -1
- package/frontend/dist/js/{it-DsgM8-MJ.js → it-CdNoTXm3.js} +1 -1
- package/frontend/dist/js/{ja-ivtt80N2.js → ja-CIuQg0xv.js} +1 -1
- package/frontend/dist/js/{ko-B8l_Ice1.js → ko-BWRUjDOH.js} +1 -1
- package/frontend/dist/js/{markdown-C08x2H-K.js → markdown-B1iNUbse.js} +1 -1
- package/frontend/dist/js/{ms-DoUBI6Qi.js → ms-gJstIj2a.js} +1 -1
- package/frontend/dist/js/{nl-DsX5Hj8m.js → nl-CydjVNUw.js} +1 -1
- package/frontend/dist/js/{pl-Db_NKL4x.js → pl-DPN9mAa5.js} +1 -1
- package/frontend/dist/js/{pt-CpzBhb5J.js → pt-MRXGqIjQ.js} +1 -1
- package/frontend/dist/js/{ru-DCXvJyXJ.js → ru-CvQ9GkJF.js} +1 -1
- package/frontend/dist/js/{standalone-DpMZUvjd.js → standalone-CCd6rkf-.js} +1 -1
- package/frontend/dist/js/{sv-DcVoybc7.js → sv-BxS2fvhU.js} +1 -1
- package/frontend/dist/js/{th-D0G7HyQn.js → th-DMxyn6e4.js} +1 -1
- package/frontend/dist/js/{tr-CMDOh4Aq.js → tr-BTPldUaA.js} +1 -1
- package/frontend/dist/js/{typescript-B6y_hxBm.js → typescript-DKJ1uM5L.js} +1 -1
- package/frontend/dist/js/ui-vendor-CAFEDSaO.js +177 -0
- package/frontend/dist/js/{uk-D2MMa6LP.js → uk-BGxZOKgp.js} +1 -1
- package/frontend/dist/js/useBaseQuery-MuQj7vA5.js +1 -0
- package/frontend/dist/js/useQuery-CYGPkxWR.js +1 -0
- package/frontend/dist/js/{vi-B8uHT8yh.js → vi-82JkwFsQ.js} +1 -1
- package/frontend/dist/js/{zh-CNqa_15K.js → zh-Bxxfwci3.js} +1 -1
- package/package.json +3 -2
- package/plugins/github.json +1 -2
- package/plugins/huggingface.json +30 -30
- package/plugins/mlx-lm.json +55 -0
- package/plugins/openai.json +53 -22
- package/frontend/dist/assets/index-Bv-twCuY.css +0 -1
- package/frontend/dist/assets/index-uCHBH_PM.js +0 -5
- package/frontend/dist/js/ChatPage-1bK0gDBy.js +0 -16
- package/frontend/dist/js/GalleryPage-6WwyH3kt.js +0 -1
- package/frontend/dist/js/LibreClawPage-ChHVfPLb.js +0 -1
- package/frontend/dist/js/ModelsPage-Dw6wdiMt.js +0 -2
- package/frontend/dist/js/PersonasPage-BxdI2e1-.js +0 -13
- package/frontend/dist/js/SettingsModal-C-cK6TNb.js +0 -1
- package/frontend/dist/js/UserManagementPage-DqjNXPkf.js +0 -1
- package/frontend/dist/js/WorkPage-MGR3odo6.js +0 -2
- package/frontend/dist/js/api-DD5qhhLf.js +0 -19
- package/frontend/dist/js/ui-vendor-DUqvZsfs.js +0 -177
- package/frontend/dist/js/useBaseQuery-Duml3DYp.js +0 -1
- package/frontend/dist/js/useQuery-C0lZwNoc.js +0 -1
|
@@ -15,11 +15,15 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import axios from 'axios';
|
|
18
|
+
import { createHash } from 'crypto';
|
|
18
19
|
import { getOpenAICompatibleSamplingParameters, resolvePluginChatParameters, } from '../utils/pluginChatAdapter.js';
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
20
|
+
import { OPENAI_RESPONSES_OUTPUT_ITEMS_METADATA_KEY, OPENAI_RESPONSES_STATE_SCOPE_METADATA_KEY, createOpenAIResponsesStateScope, createPluginCredentialFingerprint, normalizeOpenAIResponsesResponse, toOpenAIResponsesInput, toOpenAIResponsesTools, } from '../utils/openAIResponsesAdapter.js';
|
|
21
|
+
import { streamAnthropicResponse, streamOpenAICompatibleResponse, streamOpenAIResponsesResponse, } from '../utils/pluginStreamAdapter.js';
|
|
22
|
+
import { applyModelEndpointTemplate, assertSafePluginEndpoint, buildPluginAuthHeaders, inferPluginApiMode, pluginRequiresApiKey, resolvePluginApiConfig, validatePluginModel, } from '../utils/pluginValidation.js';
|
|
21
23
|
import ollamaService from './ollamaService.js';
|
|
22
24
|
import pluginService from './pluginService.js';
|
|
25
|
+
export const WORK_TOOL_ARGUMENTS_ERROR_METADATA_KEY = 'libreToolArgumentsError';
|
|
26
|
+
export const WORK_TOOL_ARGUMENTS_ERROR_MESSAGE = 'The provider returned incomplete or invalid JSON for this tool call, likely because its output-token limit was reached. Retry with a smaller payload; split large write_file content into focused files.';
|
|
23
27
|
export class WorkModelProviderError extends Error {
|
|
24
28
|
constructor(message, status, code) {
|
|
25
29
|
super(message);
|
|
@@ -67,6 +71,55 @@ export class WorkModelProviderService {
|
|
|
67
71
|
throw new WorkModelProviderError(`Model "${cleaned}" does not advertise tool support.`, 422, 'WORK_MODEL_TOOLS_UNSUPPORTED');
|
|
68
72
|
}
|
|
69
73
|
}
|
|
74
|
+
getResponsesStateScope(model, provider, userId) {
|
|
75
|
+
if (provider.providerType !== 'plugin')
|
|
76
|
+
return undefined;
|
|
77
|
+
const providerId = provider.providerId?.trim();
|
|
78
|
+
if (!providerId)
|
|
79
|
+
return undefined;
|
|
80
|
+
const plugin = this.dependencies.plugins.getPlugin(providerId, userId);
|
|
81
|
+
if (!plugin || !plugin.active || !plugin.model_map.includes(model)) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
const variables = this.dependencies.plugins.getPluginVariables(plugin, userId);
|
|
85
|
+
const apiConfig = resolvePluginApiConfig(plugin, variables);
|
|
86
|
+
if (apiConfig.apiMode !== 'responses')
|
|
87
|
+
return undefined;
|
|
88
|
+
const endpoint = applyModelEndpointTemplate(apiConfig.endpoint, model);
|
|
89
|
+
const apiKey = this.dependencies.plugins.getApiKey(plugin, userId);
|
|
90
|
+
if (pluginRequiresApiKey(plugin) && !apiKey)
|
|
91
|
+
return undefined;
|
|
92
|
+
return createOpenAIResponsesStateScope(plugin.id, model, endpoint, createPluginCredentialFingerprint(apiKey));
|
|
93
|
+
}
|
|
94
|
+
getRoutingFingerprint(model, provider, userId) {
|
|
95
|
+
if (provider.providerType === 'ollama') {
|
|
96
|
+
assertOllamaProvider(provider);
|
|
97
|
+
return createHash('sha256')
|
|
98
|
+
.update(JSON.stringify({
|
|
99
|
+
version: 1,
|
|
100
|
+
providerType: 'ollama',
|
|
101
|
+
model,
|
|
102
|
+
}))
|
|
103
|
+
.digest('hex');
|
|
104
|
+
}
|
|
105
|
+
const plugin = this.requireExactPlugin(provider.providerId, model, userId);
|
|
106
|
+
const variables = this.dependencies.plugins.getPluginVariables(plugin, userId);
|
|
107
|
+
const apiConfig = resolvePluginApiConfig(plugin, variables);
|
|
108
|
+
const endpoint = applyModelEndpointTemplate(apiConfig.endpoint, model);
|
|
109
|
+
assertSafePluginEndpoint(endpoint, 'Work model endpoint');
|
|
110
|
+
const apiKey = this.dependencies.plugins.getApiKey(plugin, userId);
|
|
111
|
+
return createHash('sha256')
|
|
112
|
+
.update(JSON.stringify({
|
|
113
|
+
version: 2,
|
|
114
|
+
providerType: 'plugin',
|
|
115
|
+
providerId: plugin.id,
|
|
116
|
+
model,
|
|
117
|
+
apiMode: apiConfig.apiMode,
|
|
118
|
+
endpoint,
|
|
119
|
+
credentialFingerprint: createPluginCredentialFingerprint(apiKey),
|
|
120
|
+
}))
|
|
121
|
+
.digest('hex');
|
|
122
|
+
}
|
|
70
123
|
async generateChatResponse(request, provider, userId, signal) {
|
|
71
124
|
if (provider.providerType === 'ollama') {
|
|
72
125
|
assertOllamaProvider(provider);
|
|
@@ -86,17 +139,18 @@ export class WorkModelProviderService {
|
|
|
86
139
|
}
|
|
87
140
|
hasConfiguredPlugin(userId) {
|
|
88
141
|
return this.dependencies.plugins
|
|
89
|
-
.getActivePlugins()
|
|
142
|
+
.getActivePlugins(userId)
|
|
90
143
|
.filter(isWorkPlugin)
|
|
91
144
|
.some(plugin => plugin.model_map.length > 0 &&
|
|
92
|
-
|
|
145
|
+
(!pluginRequiresApiKey(plugin) ||
|
|
146
|
+
Boolean(this.dependencies.plugins.getApiKey(plugin, userId))));
|
|
93
147
|
}
|
|
94
148
|
requireExactPlugin(providerId, model, userId) {
|
|
95
149
|
const cleanedProviderId = providerId?.trim();
|
|
96
150
|
if (!cleanedProviderId) {
|
|
97
151
|
throw new WorkModelProviderError('A plugin provider ID is required.', 400, 'WORK_PLUGIN_ID_REQUIRED');
|
|
98
152
|
}
|
|
99
|
-
const plugin = this.dependencies.plugins.getPlugin(cleanedProviderId);
|
|
153
|
+
const plugin = this.dependencies.plugins.getPlugin(cleanedProviderId, userId);
|
|
100
154
|
if (!plugin || !plugin.active) {
|
|
101
155
|
throw new WorkModelProviderError(`Plugin "${cleanedProviderId}" is not active.`, 422, 'WORK_PLUGIN_UNAVAILABLE');
|
|
102
156
|
}
|
|
@@ -104,30 +158,37 @@ export class WorkModelProviderService {
|
|
|
104
158
|
if (!plugin.model_map.includes(model)) {
|
|
105
159
|
throw new WorkModelProviderError(`Model "${model}" is not configured for plugin "${plugin.id}".`, 422, 'WORK_PLUGIN_MODEL_UNAVAILABLE');
|
|
106
160
|
}
|
|
107
|
-
|
|
161
|
+
resolvePluginApiConfig(plugin, this.dependencies.plugins.getPluginVariables(plugin, userId));
|
|
162
|
+
if (pluginRequiresApiKey(plugin) &&
|
|
163
|
+
!this.dependencies.plugins.getApiKey(plugin, userId)) {
|
|
108
164
|
throw new WorkModelProviderError(`API key not found for plugin ${plugin.id}.`, 422, 'WORK_PLUGIN_CREDENTIALS_MISSING');
|
|
109
165
|
}
|
|
110
166
|
return plugin;
|
|
111
167
|
}
|
|
112
168
|
async generatePluginResponse(plugin, request, userId, signal) {
|
|
113
169
|
validatePluginModel(request.model);
|
|
170
|
+
const variables = this.dependencies.plugins.getPluginVariables(plugin, userId);
|
|
171
|
+
const apiConfig = resolvePluginApiConfig(plugin, variables);
|
|
172
|
+
const endpoint = applyModelEndpointTemplate(apiConfig.endpoint, request.model);
|
|
173
|
+
assertSafePluginEndpoint(endpoint, 'Work model endpoint');
|
|
114
174
|
const apiKey = this.dependencies.plugins.getApiKey(plugin, userId);
|
|
115
|
-
if (!apiKey) {
|
|
175
|
+
if (pluginRequiresApiKey(plugin) && !apiKey) {
|
|
116
176
|
throw new WorkModelProviderError(`API key not found for plugin ${plugin.id}.`, 422, 'WORK_PLUGIN_CREDENTIALS_MISSING');
|
|
117
177
|
}
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
178
|
+
const providerStateScope = apiConfig.apiMode === 'responses'
|
|
179
|
+
? createOpenAIResponsesStateScope(plugin.id, request.model, endpoint, createPluginCredentialFingerprint(apiKey))
|
|
180
|
+
: undefined;
|
|
121
181
|
const headers = buildPluginAuthHeaders(plugin, apiKey);
|
|
122
|
-
const { payload, extraHeaders } = buildPluginWorkPayload(plugin, request, variables);
|
|
182
|
+
const { payload, extraHeaders } = buildPluginWorkPayload(plugin, request, variables, apiConfig.apiMode, providerStateScope);
|
|
123
183
|
Object.assign(headers, extraHeaders);
|
|
124
184
|
try {
|
|
125
185
|
const response = await this.dependencies.post(endpoint, payload, {
|
|
126
186
|
headers,
|
|
127
187
|
signal,
|
|
128
188
|
timeout: 300000,
|
|
189
|
+
maxRedirects: 0,
|
|
129
190
|
});
|
|
130
|
-
return normalizePluginWorkResponse(plugin, response.data, request.model);
|
|
191
|
+
return normalizePluginWorkResponse(plugin, response.data, request.model, apiConfig.apiMode, providerStateScope);
|
|
131
192
|
}
|
|
132
193
|
catch (error) {
|
|
133
194
|
if (signal?.aborted)
|
|
@@ -210,18 +271,23 @@ export class WorkModelProviderService {
|
|
|
210
271
|
}
|
|
211
272
|
async generatePluginStream(plugin, request, userId, observer, signal) {
|
|
212
273
|
validatePluginModel(request.model);
|
|
274
|
+
const variables = this.dependencies.plugins.getPluginVariables(plugin, userId);
|
|
275
|
+
const apiConfig = resolvePluginApiConfig(plugin, variables);
|
|
276
|
+
let endpoint = applyModelEndpointTemplate(apiConfig.endpoint, request.model);
|
|
277
|
+
assertSafePluginEndpoint(endpoint, 'Work model endpoint');
|
|
213
278
|
const apiKey = this.dependencies.plugins.getApiKey(plugin, userId);
|
|
214
|
-
if (!apiKey) {
|
|
279
|
+
if (pluginRequiresApiKey(plugin) && !apiKey) {
|
|
215
280
|
throw new WorkModelProviderError(`API key not found for plugin ${plugin.id}.`, 422, 'WORK_PLUGIN_CREDENTIALS_MISSING');
|
|
216
281
|
}
|
|
217
|
-
const
|
|
218
|
-
|
|
282
|
+
const providerStateScope = apiConfig.apiMode === 'responses'
|
|
283
|
+
? createOpenAIResponsesStateScope(plugin.id, request.model, endpoint, createPluginCredentialFingerprint(apiKey))
|
|
284
|
+
: undefined;
|
|
219
285
|
if (plugin.id === 'gemini') {
|
|
220
286
|
endpoint = geminiStreamingEndpoint(endpoint);
|
|
221
287
|
}
|
|
222
288
|
assertSafePluginEndpoint(endpoint, 'Work model endpoint');
|
|
223
289
|
const headers = buildPluginAuthHeaders(plugin, apiKey);
|
|
224
|
-
const { payload, extraHeaders } = buildPluginWorkPayload(plugin, { ...request, stream: true }, variables);
|
|
290
|
+
const { payload, extraHeaders } = buildPluginWorkPayload(plugin, { ...request, stream: true }, variables, apiConfig.apiMode, providerStateScope);
|
|
225
291
|
Object.assign(headers, extraHeaders);
|
|
226
292
|
const timeoutSignal = AbortSignal.timeout(300000);
|
|
227
293
|
const requestSignal = signal
|
|
@@ -233,13 +299,14 @@ export class WorkModelProviderService {
|
|
|
233
299
|
headers,
|
|
234
300
|
body: JSON.stringify(payload),
|
|
235
301
|
signal: requestSignal,
|
|
302
|
+
redirect: 'error',
|
|
236
303
|
});
|
|
237
304
|
const contentType = response.headers.get('content-type') || '';
|
|
238
305
|
if (response.ok &&
|
|
239
306
|
!contentType.includes('text/event-stream') &&
|
|
240
307
|
!contentType.includes('application/x-ndjson')) {
|
|
241
308
|
const data = (await response.json());
|
|
242
|
-
const normalized = normalizePluginWorkResponse(plugin, data, request.model);
|
|
309
|
+
const normalized = normalizePluginWorkResponse(plugin, data, request.model, apiConfig.apiMode, providerStateScope);
|
|
243
310
|
if (normalized.message.thinking) {
|
|
244
311
|
observer.onReasoning?.(normalized.message.thinking);
|
|
245
312
|
}
|
|
@@ -252,7 +319,9 @@ export class WorkModelProviderService {
|
|
|
252
319
|
? streamAnthropicResponse(response)
|
|
253
320
|
: plugin.id === 'gemini'
|
|
254
321
|
? streamGeminiWorkResponse(response)
|
|
255
|
-
:
|
|
322
|
+
: apiConfig.apiMode === 'responses'
|
|
323
|
+
? streamOpenAIResponsesResponse(response, providerStateScope)
|
|
324
|
+
: streamOpenAICompatibleResponse(response);
|
|
256
325
|
return await collectPluginWorkStream(chunks, request.model, observer);
|
|
257
326
|
}
|
|
258
327
|
catch (error) {
|
|
@@ -267,7 +336,7 @@ export class WorkModelProviderService {
|
|
|
267
336
|
}
|
|
268
337
|
}
|
|
269
338
|
}
|
|
270
|
-
export function buildPluginWorkPayload(plugin, request, variables = {}) {
|
|
339
|
+
export function buildPluginWorkPayload(plugin, request, variables = {}, apiMode = resolvePluginApiConfig(plugin, variables).apiMode, providerStateScope) {
|
|
271
340
|
const options = (request.options || {});
|
|
272
341
|
const params = resolvePluginChatParameters(options, variables);
|
|
273
342
|
if (plugin.id === 'anthropic') {
|
|
@@ -282,6 +351,24 @@ export function buildPluginWorkPayload(plugin, request, variables = {}) {
|
|
|
282
351
|
extraHeaders: {},
|
|
283
352
|
};
|
|
284
353
|
}
|
|
354
|
+
if (apiMode === 'responses') {
|
|
355
|
+
const sampling = getOpenAICompatibleSamplingParameters(plugin, params);
|
|
356
|
+
const tools = toOpenAIResponsesTools(request.tools || []);
|
|
357
|
+
return {
|
|
358
|
+
payload: {
|
|
359
|
+
model: request.model,
|
|
360
|
+
input: toOpenAIResponsesWorkInput(request.messages, providerStateScope),
|
|
361
|
+
...(tools.length ? { tools, tool_choice: 'auto' } : {}),
|
|
362
|
+
temperature: sampling.temperature,
|
|
363
|
+
top_p: sampling.top_p,
|
|
364
|
+
max_output_tokens: params.maxTokens,
|
|
365
|
+
stream: Boolean(request.stream),
|
|
366
|
+
store: false,
|
|
367
|
+
include: ['reasoning.encrypted_content'],
|
|
368
|
+
},
|
|
369
|
+
extraHeaders: {},
|
|
370
|
+
};
|
|
371
|
+
}
|
|
285
372
|
return {
|
|
286
373
|
payload: {
|
|
287
374
|
model: request.model,
|
|
@@ -295,13 +382,17 @@ export function buildPluginWorkPayload(plugin, request, variables = {}) {
|
|
|
295
382
|
extraHeaders: {},
|
|
296
383
|
};
|
|
297
384
|
}
|
|
298
|
-
export function normalizePluginWorkResponse(plugin, response, model
|
|
385
|
+
export function normalizePluginWorkResponse(plugin, response, model, apiMode = plugin.api_mode ||
|
|
386
|
+
inferPluginApiMode(plugin.endpoint), providerStateScope) {
|
|
299
387
|
if (plugin.id === 'anthropic') {
|
|
300
388
|
return normalizeAnthropicWorkResponse(response, model);
|
|
301
389
|
}
|
|
302
390
|
if (plugin.id === 'gemini') {
|
|
303
391
|
return normalizeGeminiWorkResponse(response, model);
|
|
304
392
|
}
|
|
393
|
+
if (apiMode === 'responses') {
|
|
394
|
+
return normalizeOpenAIResponsesWorkResponse(response, model, providerStateScope);
|
|
395
|
+
}
|
|
305
396
|
return normalizeOpenAIWorkResponse(response, model);
|
|
306
397
|
}
|
|
307
398
|
export function toOpenAIWorkMessages(messages) {
|
|
@@ -342,12 +433,94 @@ export function toOpenAIWorkMessages(messages) {
|
|
|
342
433
|
role: 'tool',
|
|
343
434
|
content: message.content,
|
|
344
435
|
name: message.tool_name,
|
|
345
|
-
tool_call_id: matching?.id || `work-tool-${messageIndex}`,
|
|
436
|
+
tool_call_id: message.tool_call_id || matching?.id || `work-tool-${messageIndex}`,
|
|
346
437
|
};
|
|
347
438
|
}
|
|
348
439
|
return { role: message.role, content: message.content };
|
|
349
440
|
});
|
|
350
441
|
}
|
|
442
|
+
export function toOpenAIResponsesWorkInput(messages, expectedStateScope) {
|
|
443
|
+
const input = [];
|
|
444
|
+
let pendingCalls = [];
|
|
445
|
+
for (const [messageIndex, message] of messages.entries()) {
|
|
446
|
+
if (message.role === 'assistant') {
|
|
447
|
+
const toolCalls = normalizeOutboundToolCalls(message.tool_calls);
|
|
448
|
+
const responseOutputItems = Array.isArray(message.providerMetadata?.[OPENAI_RESPONSES_OUTPUT_ITEMS_METADATA_KEY])
|
|
449
|
+
? message.providerMetadata[OPENAI_RESPONSES_OUTPUT_ITEMS_METADATA_KEY]
|
|
450
|
+
: [];
|
|
451
|
+
const replayableOutputItems = expectedStateScope === undefined ||
|
|
452
|
+
message.providerMetadata?.[OPENAI_RESPONSES_STATE_SCOPE_METADATA_KEY] === expectedStateScope
|
|
453
|
+
? responseOutputItems.flatMap(rawItem => {
|
|
454
|
+
const item = asObject(rawItem);
|
|
455
|
+
return item ? [{ ...item }] : [];
|
|
456
|
+
})
|
|
457
|
+
: [];
|
|
458
|
+
if (replayableOutputItems.length > 0) {
|
|
459
|
+
pendingCalls = replayableOutputItems.flatMap(item => {
|
|
460
|
+
if (item.type !== 'function_call')
|
|
461
|
+
return [];
|
|
462
|
+
const id = typeof item.call_id === 'string'
|
|
463
|
+
? item.call_id
|
|
464
|
+
: typeof item.id === 'string'
|
|
465
|
+
? item.id
|
|
466
|
+
: undefined;
|
|
467
|
+
return id && typeof item.name === 'string'
|
|
468
|
+
? [{ id, name: item.name }]
|
|
469
|
+
: [];
|
|
470
|
+
});
|
|
471
|
+
input.push(...replayableOutputItems);
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
pendingCalls = toolCalls.map(call => ({
|
|
475
|
+
id: String(call.id),
|
|
476
|
+
name: String(call.function.name),
|
|
477
|
+
}));
|
|
478
|
+
// Compatibility for Work messages created before full Responses output
|
|
479
|
+
// items were retained.
|
|
480
|
+
for (const call of toolCalls) {
|
|
481
|
+
const metadata = asObject(call.providerMetadata);
|
|
482
|
+
const reasoningItems = Array.isArray(metadata?.openAIResponsesReasoningItems)
|
|
483
|
+
? metadata.openAIResponsesReasoningItems
|
|
484
|
+
: [];
|
|
485
|
+
for (const rawItem of reasoningItems) {
|
|
486
|
+
const item = asObject(rawItem);
|
|
487
|
+
if (item?.type === 'reasoning') {
|
|
488
|
+
input.push({ ...item });
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
input.push(...toOpenAIResponsesInput([
|
|
493
|
+
{
|
|
494
|
+
role: 'assistant',
|
|
495
|
+
content: message.content,
|
|
496
|
+
tool_calls: toolCalls,
|
|
497
|
+
},
|
|
498
|
+
]));
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
if (message.role === 'tool') {
|
|
502
|
+
const matchingIndex = pendingCalls.findIndex(call => !message.tool_name || call.name === message.tool_name);
|
|
503
|
+
const matching = matchingIndex >= 0
|
|
504
|
+
? pendingCalls.splice(matchingIndex, 1)[0]
|
|
505
|
+
: undefined;
|
|
506
|
+
input.push(...toOpenAIResponsesInput([
|
|
507
|
+
{
|
|
508
|
+
role: 'tool',
|
|
509
|
+
content: message.content,
|
|
510
|
+
name: message.tool_name,
|
|
511
|
+
tool_call_id: message.tool_call_id ||
|
|
512
|
+
matching?.id ||
|
|
513
|
+
`work-tool-${messageIndex}`,
|
|
514
|
+
},
|
|
515
|
+
]));
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
input.push(...toOpenAIResponsesInput([
|
|
519
|
+
{ role: message.role, content: message.content },
|
|
520
|
+
]));
|
|
521
|
+
}
|
|
522
|
+
return input;
|
|
523
|
+
}
|
|
351
524
|
function buildAnthropicWorkPayload(model, messages, tools, maxTokens, stream = false) {
|
|
352
525
|
const system = messages
|
|
353
526
|
.filter(message => message.role === 'system')
|
|
@@ -523,6 +696,45 @@ function normalizeOpenAIWorkResponse(response, model) {
|
|
|
523
696
|
? message.reasoning_content
|
|
524
697
|
: '');
|
|
525
698
|
}
|
|
699
|
+
function normalizeOpenAIResponsesWorkResponse(response, model, providerStateScope) {
|
|
700
|
+
const normalized = normalizeOpenAIResponsesResponse(response, model, providerStateScope);
|
|
701
|
+
const choice = normalized.choices[0];
|
|
702
|
+
const message = asObject(choice?.message);
|
|
703
|
+
if (!message) {
|
|
704
|
+
throw new WorkModelProviderError('Plugin returned an invalid Responses API response.', 502, 'WORK_PLUGIN_INVALID_RESPONSE');
|
|
705
|
+
}
|
|
706
|
+
const reasoning = typeof message.reasoning_content === 'string'
|
|
707
|
+
? message.reasoning_content
|
|
708
|
+
: '';
|
|
709
|
+
const toolCalls = normalizeInboundToolCalls(message.tool_calls);
|
|
710
|
+
if (reasoning && toolCalls[0]) {
|
|
711
|
+
toolCalls[0].providerMetadata = {
|
|
712
|
+
...asObject(toolCalls[0].providerMetadata),
|
|
713
|
+
openAIReasoningContent: reasoning,
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
const incompleteReason = response.status === 'incomplete'
|
|
717
|
+
? typeof asObject(response.incomplete_details)?.reason === 'string'
|
|
718
|
+
? String(asObject(response.incomplete_details)?.reason)
|
|
719
|
+
: 'unknown'
|
|
720
|
+
: undefined;
|
|
721
|
+
return {
|
|
722
|
+
...workResponse(model, contentText(message.content), toolCalls, reasoning, {
|
|
723
|
+
...(normalized.providerMetadata
|
|
724
|
+
? { providerMetadata: normalized.providerMetadata }
|
|
725
|
+
: {}),
|
|
726
|
+
...(incompleteReason
|
|
727
|
+
? { doneReason: `incomplete:${incompleteReason}` }
|
|
728
|
+
: {}),
|
|
729
|
+
}),
|
|
730
|
+
...(normalized.usage
|
|
731
|
+
? {
|
|
732
|
+
prompt_eval_count: normalized.usage.prompt_tokens,
|
|
733
|
+
eval_count: normalized.usage.completion_tokens,
|
|
734
|
+
}
|
|
735
|
+
: {}),
|
|
736
|
+
};
|
|
737
|
+
}
|
|
526
738
|
function normalizeAnthropicWorkResponse(response, model) {
|
|
527
739
|
const blocks = Array.isArray(response.content) ? response.content : [];
|
|
528
740
|
const text = [];
|
|
@@ -590,7 +802,7 @@ function normalizeGeminiWorkResponse(response, model) {
|
|
|
590
802
|
}
|
|
591
803
|
return workResponse(model, text.join(''), calls, reasoning.join(''));
|
|
592
804
|
}
|
|
593
|
-
function workResponse(model, content, toolCalls, reasoning = '') {
|
|
805
|
+
function workResponse(model, content, toolCalls, reasoning = '', options = {}) {
|
|
594
806
|
return {
|
|
595
807
|
model,
|
|
596
808
|
created_at: new Date().toISOString(),
|
|
@@ -599,14 +811,20 @@ function workResponse(model, content, toolCalls, reasoning = '') {
|
|
|
599
811
|
content,
|
|
600
812
|
...(reasoning ? { thinking: reasoning } : {}),
|
|
601
813
|
tool_calls: toolCalls,
|
|
814
|
+
...(options.providerMetadata
|
|
815
|
+
? { providerMetadata: options.providerMetadata }
|
|
816
|
+
: {}),
|
|
602
817
|
},
|
|
603
818
|
done: true,
|
|
819
|
+
...(options.doneReason ? { done_reason: options.doneReason } : {}),
|
|
604
820
|
};
|
|
605
821
|
}
|
|
606
822
|
async function collectPluginWorkStream(chunks, model, observer) {
|
|
607
823
|
let content = '';
|
|
608
824
|
let reasoning = '';
|
|
609
825
|
let usage = {};
|
|
826
|
+
let doneReason;
|
|
827
|
+
let providerMetadata;
|
|
610
828
|
const toolCalls = [];
|
|
611
829
|
for await (const chunk of chunks) {
|
|
612
830
|
if (chunk.type === 'content') {
|
|
@@ -625,7 +843,15 @@ async function collectPluginWorkStream(chunks, model, observer) {
|
|
|
625
843
|
continue;
|
|
626
844
|
}
|
|
627
845
|
if (chunk.type === 'tool_call') {
|
|
628
|
-
const
|
|
846
|
+
const parsedArguments = parseToolArgumentsWithStatus(chunk.toolCall.arguments);
|
|
847
|
+
const metadata = {
|
|
848
|
+
...chunk.toolCall.providerMetadata,
|
|
849
|
+
...(parsedArguments.error
|
|
850
|
+
? {
|
|
851
|
+
[WORK_TOOL_ARGUMENTS_ERROR_METADATA_KEY]: parsedArguments.error,
|
|
852
|
+
}
|
|
853
|
+
: {}),
|
|
854
|
+
};
|
|
629
855
|
toolCalls.push({
|
|
630
856
|
id: chunk.toolCall.id || `work-plugin-${toolCalls.length}`,
|
|
631
857
|
...(typeof metadata?.geminiThoughtSignature === 'string'
|
|
@@ -639,9 +865,16 @@ async function collectPluginWorkStream(chunks, model, observer) {
|
|
|
639
865
|
: {}),
|
|
640
866
|
function: {
|
|
641
867
|
name: chunk.toolCall.name,
|
|
642
|
-
arguments:
|
|
868
|
+
arguments: parsedArguments.arguments,
|
|
643
869
|
},
|
|
644
870
|
});
|
|
871
|
+
continue;
|
|
872
|
+
}
|
|
873
|
+
if (chunk.type === 'done') {
|
|
874
|
+
doneReason = chunk.doneReason;
|
|
875
|
+
providerMetadata = chunk.providerMetadata
|
|
876
|
+
? { ...providerMetadata, ...chunk.providerMetadata }
|
|
877
|
+
: providerMetadata;
|
|
645
878
|
}
|
|
646
879
|
}
|
|
647
880
|
if (reasoning && toolCalls[0]) {
|
|
@@ -655,7 +888,10 @@ async function collectPluginWorkStream(chunks, model, observer) {
|
|
|
655
888
|
}
|
|
656
889
|
}
|
|
657
890
|
return {
|
|
658
|
-
...workResponse(model, content, toolCalls, reasoning
|
|
891
|
+
...workResponse(model, content, toolCalls, reasoning, {
|
|
892
|
+
...(providerMetadata ? { providerMetadata } : {}),
|
|
893
|
+
...(doneReason ? { doneReason } : {}),
|
|
894
|
+
}),
|
|
659
895
|
prompt_eval_count: usage.promptTokens,
|
|
660
896
|
eval_count: usage.completionTokens,
|
|
661
897
|
};
|
|
@@ -808,19 +1044,29 @@ function normalizeInboundToolCalls(value) {
|
|
|
808
1044
|
const fn = asObject(call?.function);
|
|
809
1045
|
if (!fn || typeof fn.name !== 'string')
|
|
810
1046
|
return [];
|
|
811
|
-
const
|
|
1047
|
+
const parsedArguments = parseToolArgumentsWithStatus(fn.arguments);
|
|
1048
|
+
const providerMetadata = {
|
|
1049
|
+
...asObject(call?.providerMetadata),
|
|
1050
|
+
...(parsedArguments.error
|
|
1051
|
+
? {
|
|
1052
|
+
[WORK_TOOL_ARGUMENTS_ERROR_METADATA_KEY]: parsedArguments.error,
|
|
1053
|
+
}
|
|
1054
|
+
: {}),
|
|
1055
|
+
};
|
|
812
1056
|
return [
|
|
813
1057
|
{
|
|
814
1058
|
id: typeof call?.id === 'string' ? call.id : `work-plugin-${index}`,
|
|
815
1059
|
...(typeof call?.thoughtSignature === 'string'
|
|
816
1060
|
? { thoughtSignature: call.thoughtSignature }
|
|
817
1061
|
: {}),
|
|
818
|
-
...(providerMetadata
|
|
1062
|
+
...(Object.keys(providerMetadata).length > 0
|
|
1063
|
+
? { providerMetadata }
|
|
1064
|
+
: {}),
|
|
819
1065
|
function: {
|
|
820
1066
|
name: fn.name,
|
|
821
|
-
arguments: typeof fn.arguments === 'string'
|
|
1067
|
+
arguments: typeof fn.arguments === 'string' && !parsedArguments.error
|
|
822
1068
|
? fn.arguments
|
|
823
|
-
:
|
|
1069
|
+
: parsedArguments.arguments,
|
|
824
1070
|
},
|
|
825
1071
|
},
|
|
826
1072
|
];
|
|
@@ -844,18 +1090,32 @@ function toAnthropicTools(tools) {
|
|
|
844
1090
|
});
|
|
845
1091
|
}
|
|
846
1092
|
function parseToolArguments(value) {
|
|
1093
|
+
return parseToolArgumentsWithStatus(value).arguments;
|
|
1094
|
+
}
|
|
1095
|
+
function parseToolArgumentsWithStatus(value) {
|
|
847
1096
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
848
|
-
return value;
|
|
1097
|
+
return { arguments: value };
|
|
849
1098
|
}
|
|
850
1099
|
if (typeof value === 'string') {
|
|
1100
|
+
if (!value.trim())
|
|
1101
|
+
return { arguments: {} };
|
|
851
1102
|
try {
|
|
852
|
-
|
|
1103
|
+
const parsed = asObject(JSON.parse(value));
|
|
1104
|
+
return parsed
|
|
1105
|
+
? { arguments: parsed }
|
|
1106
|
+
: {
|
|
1107
|
+
arguments: {},
|
|
1108
|
+
error: WORK_TOOL_ARGUMENTS_ERROR_MESSAGE,
|
|
1109
|
+
};
|
|
853
1110
|
}
|
|
854
1111
|
catch {
|
|
855
|
-
return {
|
|
1112
|
+
return {
|
|
1113
|
+
arguments: {},
|
|
1114
|
+
error: WORK_TOOL_ARGUMENTS_ERROR_MESSAGE,
|
|
1115
|
+
};
|
|
856
1116
|
}
|
|
857
1117
|
}
|
|
858
|
-
return {};
|
|
1118
|
+
return { arguments: {} };
|
|
859
1119
|
}
|
|
860
1120
|
function contentText(value) {
|
|
861
1121
|
if (typeof value === 'string')
|