libre-webui 0.15.1 → 0.16.1

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.
Files changed (205) hide show
  1. package/README.md +18 -8
  2. package/backend/dist/db.d.ts.map +1 -1
  3. package/backend/dist/db.js +63 -0
  4. package/backend/dist/db.js.map +1 -1
  5. package/backend/dist/index.d.ts.map +1 -1
  6. package/backend/dist/index.js +4 -4
  7. package/backend/dist/index.js.map +1 -1
  8. package/backend/dist/routes/chat.d.ts.map +1 -1
  9. package/backend/dist/routes/chat.js +93 -10
  10. package/backend/dist/routes/chat.js.map +1 -1
  11. package/backend/dist/routes/imageGen.d.ts.map +1 -1
  12. package/backend/dist/routes/imageGen.js +52 -29
  13. package/backend/dist/routes/imageGen.js.map +1 -1
  14. package/backend/dist/routes/plugins.d.ts.map +1 -1
  15. package/backend/dist/routes/plugins.js +226 -42
  16. package/backend/dist/routes/plugins.js.map +1 -1
  17. package/backend/dist/routes/preferences.d.ts.map +1 -1
  18. package/backend/dist/routes/preferences.js +5 -4
  19. package/backend/dist/routes/preferences.js.map +1 -1
  20. package/backend/dist/routes/tts.js +2 -2
  21. package/backend/dist/routes/tts.js.map +1 -1
  22. package/backend/dist/routes/work.d.ts.map +1 -1
  23. package/backend/dist/routes/work.js +2 -1
  24. package/backend/dist/routes/work.js.map +1 -1
  25. package/backend/dist/services/assistantCompletionService.d.ts +2 -1
  26. package/backend/dist/services/assistantCompletionService.d.ts.map +1 -1
  27. package/backend/dist/services/assistantCompletionService.js +3 -1
  28. package/backend/dist/services/assistantCompletionService.js.map +1 -1
  29. package/backend/dist/services/chatGenerationService.d.ts +5 -3
  30. package/backend/dist/services/chatGenerationService.d.ts.map +1 -1
  31. package/backend/dist/services/chatGenerationService.js +18 -6
  32. package/backend/dist/services/chatGenerationService.js.map +1 -1
  33. package/backend/dist/services/chatRequestService.d.ts +6 -4
  34. package/backend/dist/services/chatRequestService.d.ts.map +1 -1
  35. package/backend/dist/services/chatRequestService.js +10 -2
  36. package/backend/dist/services/chatRequestService.js.map +1 -1
  37. package/backend/dist/services/chatService.d.ts +2 -2
  38. package/backend/dist/services/chatService.d.ts.map +1 -1
  39. package/backend/dist/services/chatService.js +29 -17
  40. package/backend/dist/services/chatService.js.map +1 -1
  41. package/backend/dist/services/embeddingService.js +1 -1
  42. package/backend/dist/services/embeddingService.js.map +1 -1
  43. package/backend/dist/services/pluginActivationService.d.ts +11 -0
  44. package/backend/dist/services/pluginActivationService.d.ts.map +1 -0
  45. package/backend/dist/services/pluginActivationService.js +163 -0
  46. package/backend/dist/services/pluginActivationService.js.map +1 -0
  47. package/backend/dist/services/pluginCapabilityRegistryService.d.ts +1 -1
  48. package/backend/dist/services/pluginCapabilityRegistryService.d.ts.map +1 -1
  49. package/backend/dist/services/pluginCapabilityRegistryService.js +1 -1
  50. package/backend/dist/services/pluginCapabilityRegistryService.js.map +1 -1
  51. package/backend/dist/services/pluginCredentialsService.d.ts +16 -8
  52. package/backend/dist/services/pluginCredentialsService.d.ts.map +1 -1
  53. package/backend/dist/services/pluginCredentialsService.js +47 -14
  54. package/backend/dist/services/pluginCredentialsService.js.map +1 -1
  55. package/backend/dist/services/pluginEmbeddingService.d.ts +2 -2
  56. package/backend/dist/services/pluginEmbeddingService.d.ts.map +1 -1
  57. package/backend/dist/services/pluginEmbeddingService.js +33 -13
  58. package/backend/dist/services/pluginEmbeddingService.js.map +1 -1
  59. package/backend/dist/services/pluginImageGenerationService.d.ts +11 -7
  60. package/backend/dist/services/pluginImageGenerationService.d.ts.map +1 -1
  61. package/backend/dist/services/pluginImageGenerationService.js +265 -81
  62. package/backend/dist/services/pluginImageGenerationService.js.map +1 -1
  63. package/backend/dist/services/pluginService.d.ts +97 -26
  64. package/backend/dist/services/pluginService.d.ts.map +1 -1
  65. package/backend/dist/services/pluginService.js +797 -178
  66. package/backend/dist/services/pluginService.js.map +1 -1
  67. package/backend/dist/services/pluginTTSService.d.ts +4 -4
  68. package/backend/dist/services/pluginTTSService.d.ts.map +1 -1
  69. package/backend/dist/services/pluginTTSService.js +24 -28
  70. package/backend/dist/services/pluginTTSService.js.map +1 -1
  71. package/backend/dist/services/pluginVariablesService.d.ts +6 -1
  72. package/backend/dist/services/pluginVariablesService.d.ts.map +1 -1
  73. package/backend/dist/services/pluginVariablesService.js +59 -1
  74. package/backend/dist/services/pluginVariablesService.js.map +1 -1
  75. package/backend/dist/services/preferencesService.d.ts +2 -2
  76. package/backend/dist/services/preferencesService.d.ts.map +1 -1
  77. package/backend/dist/services/preferencesService.js +78 -10
  78. package/backend/dist/services/preferencesService.js.map +1 -1
  79. package/backend/dist/services/titleGenerationService.d.ts +6 -4
  80. package/backend/dist/services/titleGenerationService.d.ts.map +1 -1
  81. package/backend/dist/services/titleGenerationService.js +9 -5
  82. package/backend/dist/services/titleGenerationService.js.map +1 -1
  83. package/backend/dist/services/workAgentService.d.ts +5 -2
  84. package/backend/dist/services/workAgentService.d.ts.map +1 -1
  85. package/backend/dist/services/workAgentService.js +315 -44
  86. package/backend/dist/services/workAgentService.js.map +1 -1
  87. package/backend/dist/services/workModelProviderService.d.ts +6 -3
  88. package/backend/dist/services/workModelProviderService.d.ts.map +1 -1
  89. package/backend/dist/services/workModelProviderService.js +243 -19
  90. package/backend/dist/services/workModelProviderService.js.map +1 -1
  91. package/backend/dist/services/workRuntimeService.d.ts +18 -1
  92. package/backend/dist/services/workRuntimeService.d.ts.map +1 -1
  93. package/backend/dist/services/workRuntimeService.js +62 -11
  94. package/backend/dist/services/workRuntimeService.js.map +1 -1
  95. package/backend/dist/services/workTaskService.d.ts +2 -0
  96. package/backend/dist/services/workTaskService.d.ts.map +1 -1
  97. package/backend/dist/services/workTaskService.js +89 -14
  98. package/backend/dist/services/workTaskService.js.map +1 -1
  99. package/backend/dist/storage.d.ts.map +1 -1
  100. package/backend/dist/storage.js +9 -6
  101. package/backend/dist/storage.js.map +1 -1
  102. package/backend/dist/storageMappers.d.ts +3 -0
  103. package/backend/dist/storageMappers.d.ts.map +1 -1
  104. package/backend/dist/storageMappers.js +3 -0
  105. package/backend/dist/storageMappers.js.map +1 -1
  106. package/backend/dist/types/index.d.ts +54 -1
  107. package/backend/dist/types/index.d.ts.map +1 -1
  108. package/backend/dist/types/index.js.map +1 -1
  109. package/backend/dist/types/work.d.ts +1 -1
  110. package/backend/dist/types/work.d.ts.map +1 -1
  111. package/backend/dist/utils/chatContext.d.ts +13 -1
  112. package/backend/dist/utils/chatContext.d.ts.map +1 -1
  113. package/backend/dist/utils/chatContext.js +52 -0
  114. package/backend/dist/utils/chatContext.js.map +1 -1
  115. package/backend/dist/utils/chatProviderSelection.d.ts +15 -0
  116. package/backend/dist/utils/chatProviderSelection.d.ts.map +1 -0
  117. package/backend/dist/utils/chatProviderSelection.js +59 -0
  118. package/backend/dist/utils/chatProviderSelection.js.map +1 -0
  119. package/backend/dist/utils/imageGenerationValidation.d.ts +3 -0
  120. package/backend/dist/utils/imageGenerationValidation.d.ts.map +1 -0
  121. package/backend/dist/utils/imageGenerationValidation.js +55 -0
  122. package/backend/dist/utils/imageGenerationValidation.js.map +1 -0
  123. package/backend/dist/utils/openAIResponsesAdapter.d.ts +88 -0
  124. package/backend/dist/utils/openAIResponsesAdapter.d.ts.map +1 -0
  125. package/backend/dist/utils/openAIResponsesAdapter.js +521 -0
  126. package/backend/dist/utils/openAIResponsesAdapter.js.map +1 -0
  127. package/backend/dist/utils/pluginChatAdapter.d.ts +7 -4
  128. package/backend/dist/utils/pluginChatAdapter.d.ts.map +1 -1
  129. package/backend/dist/utils/pluginChatAdapter.js +33 -5
  130. package/backend/dist/utils/pluginChatAdapter.js.map +1 -1
  131. package/backend/dist/utils/pluginChatContext.d.ts.map +1 -1
  132. package/backend/dist/utils/pluginChatContext.js +5 -1
  133. package/backend/dist/utils/pluginChatContext.js.map +1 -1
  134. package/backend/dist/utils/pluginConnectionVariables.d.ts +6 -0
  135. package/backend/dist/utils/pluginConnectionVariables.d.ts.map +1 -0
  136. package/backend/dist/utils/pluginConnectionVariables.js +52 -0
  137. package/backend/dist/utils/pluginConnectionVariables.js.map +1 -0
  138. package/backend/dist/utils/pluginDefinitionTrust.d.ts +9 -0
  139. package/backend/dist/utils/pluginDefinitionTrust.d.ts.map +1 -0
  140. package/backend/dist/utils/pluginDefinitionTrust.js +71 -0
  141. package/backend/dist/utils/pluginDefinitionTrust.js.map +1 -0
  142. package/backend/dist/utils/pluginStreamAdapter.d.ts +3 -0
  143. package/backend/dist/utils/pluginStreamAdapter.d.ts.map +1 -1
  144. package/backend/dist/utils/pluginStreamAdapter.js +410 -0
  145. package/backend/dist/utils/pluginStreamAdapter.js.map +1 -1
  146. package/backend/dist/utils/pluginStreaming.d.ts +7 -1
  147. package/backend/dist/utils/pluginStreaming.d.ts.map +1 -1
  148. package/backend/dist/utils/pluginStreaming.js +12 -1
  149. package/backend/dist/utils/pluginStreaming.js.map +1 -1
  150. package/backend/dist/utils/pluginValidation.d.ts +20 -2
  151. package/backend/dist/utils/pluginValidation.d.ts.map +1 -1
  152. package/backend/dist/utils/pluginValidation.js +187 -17
  153. package/backend/dist/utils/pluginValidation.js.map +1 -1
  154. package/backend/dist/utils/pluginVariableValidation.d.ts +7 -0
  155. package/backend/dist/utils/pluginVariableValidation.d.ts.map +1 -1
  156. package/backend/dist/utils/pluginVariableValidation.js +79 -4
  157. package/backend/dist/utils/pluginVariableValidation.js.map +1 -1
  158. package/backend/dist/websocketServer.d.ts.map +1 -1
  159. package/backend/dist/websocketServer.js +16 -3
  160. package/backend/dist/websocketServer.js.map +1 -1
  161. package/backend/package.json +1 -1
  162. package/frontend/dist/assets/index-BVgyQN3z.js +5 -0
  163. package/frontend/dist/assets/index-Dme2Ozol.css +1 -0
  164. package/frontend/dist/index.html +3 -3
  165. package/frontend/dist/js/{ArtifactContainer-BHSBrlQB.js → ArtifactContainer-CbMAYwvr.js} +1 -1
  166. package/frontend/dist/js/{ArtifactDemoPage-BHGJmJAT.js → ArtifactDemoPage-CWDhGWrz.js} +1 -1
  167. package/frontend/dist/js/ArtifactSlideOutPanel-CzUpDM59.js +1 -0
  168. package/frontend/dist/js/ChatPage-D0fdzy7a.js +16 -0
  169. package/frontend/dist/js/{FirstTimeSetup-BYWAVAdE.js → FirstTimeSetup-CfnOmy9w.js} +1 -1
  170. package/frontend/dist/js/GalleryPage-CMkCur9v.js +1 -0
  171. package/frontend/dist/js/LibreClawPage-CHEfny1k.js +1 -0
  172. package/frontend/dist/js/ModelSelector-COnlNsVM.js +1 -0
  173. package/frontend/dist/js/ModelsPage-nxheiYJp.js +2 -0
  174. package/frontend/dist/js/PersonasPage-C2pqDsWA.js +13 -0
  175. package/frontend/dist/js/{RichMessageContent-BdU5vXz9.js → RichMessageContent-Cz9y-bgl.js} +1 -1
  176. package/frontend/dist/js/SettingsModal-B6Se68Hd.js +1 -0
  177. package/frontend/dist/js/UserManagementPage-DQeL-Twp.js +1 -0
  178. package/frontend/dist/js/WorkPage-AcZMp8OB.js +2 -0
  179. package/frontend/dist/js/api-Fi-lJlfu.js +19 -0
  180. package/frontend/dist/js/{estree-Bu_-Wi6O.js → estree-BRklD62a.js} +1 -1
  181. package/frontend/dist/js/{html-Ca764Rus.js → html-BgGIAGmn.js} +1 -1
  182. package/frontend/dist/js/{markdown-DaiQGPEs.js → markdown-CM2nBJJi.js} +1 -1
  183. package/frontend/dist/js/{standalone-DWWnsbIr.js → standalone-CUBo-NGt.js} +1 -1
  184. package/frontend/dist/js/{typescript-CatjJeHm.js → typescript-Dcy9qxSB.js} +1 -1
  185. package/frontend/dist/js/useBaseQuery-CFTidwqz.js +1 -0
  186. package/frontend/dist/js/useQuery-UsSBfWzs.js +1 -0
  187. package/package.json +2 -2
  188. package/plugins/github.json +1 -2
  189. package/plugins/huggingface.json +30 -30
  190. package/plugins/openai.json +53 -22
  191. package/frontend/dist/assets/index-DkShhNBf.js +0 -5
  192. package/frontend/dist/assets/index-bdSWBsAM.css +0 -1
  193. package/frontend/dist/js/ArtifactSlideOutPanel-s8vcE5Ea.js +0 -1
  194. package/frontend/dist/js/ChatPage-B6Hm_pdu.js +0 -16
  195. package/frontend/dist/js/GalleryPage-CH4f65q8.js +0 -1
  196. package/frontend/dist/js/LibreClawPage-CcH7M3mJ.js +0 -1
  197. package/frontend/dist/js/ModelSelector-T1KZtIde.js +0 -1
  198. package/frontend/dist/js/ModelsPage-C1bM_Yoc.js +0 -2
  199. package/frontend/dist/js/PersonasPage-T_PrhnPG.js +0 -13
  200. package/frontend/dist/js/SettingsModal-BVj-D1L4.js +0 -1
  201. package/frontend/dist/js/UserManagementPage-Pix71oRW.js +0 -1
  202. package/frontend/dist/js/WorkPage-DdOVGyj_.js +0 -2
  203. package/frontend/dist/js/api-Do6u0tMM.js +0 -19
  204. package/frontend/dist/js/useBaseQuery-CVNuhuID.js +0 -1
  205. package/frontend/dist/js/useQuery-CYhC_da4.js +0 -1
@@ -1,5 +1,5 @@
1
1
  import axios from 'axios';
2
- import type { OllamaChatMessage, OllamaChatRequest, OllamaChatResponse, Plugin } from '../types/index.js';
2
+ import type { OllamaChatMessage, OllamaChatRequest, OllamaChatResponse, Plugin, PluginApiMode } from '../types/index.js';
3
3
  import { type PluginVariables } from '../utils/pluginChatAdapter.js';
4
4
  import { type PluginStreamUsage } from '../utils/pluginStreamAdapter.js';
5
5
  import ollamaService from './ollamaService.js';
@@ -32,6 +32,8 @@ export declare class WorkModelProviderService {
32
32
  constructor(dependencies?: WorkModelProviderDependencies);
33
33
  availability(userId: string): Promise<WorkProviderAvailability>;
34
34
  assertModelSupportsTools(model: string, provider: WorkProviderSelection, userId: string): Promise<void>;
35
+ getResponsesStateScope(model: string, provider: WorkProviderSelection, userId: string): string | undefined;
36
+ getRoutingFingerprint(model: string, provider: WorkProviderSelection, userId: string): string;
35
37
  generateChatResponse(request: OllamaChatRequest, provider: WorkProviderSelection, userId: string, signal?: AbortSignal): Promise<OllamaChatResponse>;
36
38
  generateChatStreamResponse(request: OllamaChatRequest, provider: WorkProviderSelection, userId: string, observer: WorkModelStreamObserver, signal?: AbortSignal): Promise<OllamaChatResponse>;
37
39
  private hasConfiguredPlugin;
@@ -40,12 +42,13 @@ export declare class WorkModelProviderService {
40
42
  private generateOllamaStream;
41
43
  private generatePluginStream;
42
44
  }
43
- export declare function buildPluginWorkPayload(plugin: Plugin, request: OllamaChatRequest, variables?: PluginVariables): {
45
+ export declare function buildPluginWorkPayload(plugin: Plugin, request: OllamaChatRequest, variables?: PluginVariables, apiMode?: PluginApiMode, providerStateScope?: string): {
44
46
  payload: JsonObject;
45
47
  extraHeaders: Record<string, string>;
46
48
  };
47
- export declare function normalizePluginWorkResponse(plugin: Plugin, response: JsonObject, model: string): OllamaChatResponse;
49
+ export declare function normalizePluginWorkResponse(plugin: Plugin, response: JsonObject, model: string, apiMode?: PluginApiMode, providerStateScope?: string): OllamaChatResponse;
48
50
  export declare function toOpenAIWorkMessages(messages: OllamaChatMessage[]): JsonObject[];
51
+ export declare function toOpenAIResponsesWorkInput(messages: OllamaChatMessage[], expectedStateScope?: string): JsonObject[];
49
52
  export declare const workModelProviderService: WorkModelProviderService;
50
53
  export default workModelProviderService;
51
54
  //# sourceMappingURL=workModelProviderService.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workModelProviderService.d.ts","sourceRoot":"","sources":["../../src/services/workModelProviderService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workModelProviderService.d.ts","sourceRoot":"","sources":["../../src/services/workModelProviderService.ts"],"names":[],"mappings":"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"}
@@ -15,9 +15,11 @@
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 { streamAnthropicResponse, streamOpenAICompatibleResponse, } from '../utils/pluginStreamAdapter.js';
20
- import { applyModelEndpointTemplate, assertSafePluginEndpoint, buildPluginAuthHeaders, pluginRequiresApiKey, resolvePluginEndpoint, validatePluginModel, } from '../utils/pluginValidation.js';
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';
23
25
  export const WORK_TOOL_ARGUMENTS_ERROR_METADATA_KEY = 'libreToolArgumentsError';
@@ -69,6 +71,55 @@ export class WorkModelProviderService {
69
71
  throw new WorkModelProviderError(`Model "${cleaned}" does not advertise tool support.`, 422, 'WORK_MODEL_TOOLS_UNSUPPORTED');
70
72
  }
71
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
+ }
72
123
  async generateChatResponse(request, provider, userId, signal) {
73
124
  if (provider.providerType === 'ollama') {
74
125
  assertOllamaProvider(provider);
@@ -88,7 +139,7 @@ export class WorkModelProviderService {
88
139
  }
89
140
  hasConfiguredPlugin(userId) {
90
141
  return this.dependencies.plugins
91
- .getActivePlugins()
142
+ .getActivePlugins(userId)
92
143
  .filter(isWorkPlugin)
93
144
  .some(plugin => plugin.model_map.length > 0 &&
94
145
  (!pluginRequiresApiKey(plugin) ||
@@ -99,7 +150,7 @@ export class WorkModelProviderService {
99
150
  if (!cleanedProviderId) {
100
151
  throw new WorkModelProviderError('A plugin provider ID is required.', 400, 'WORK_PLUGIN_ID_REQUIRED');
101
152
  }
102
- const plugin = this.dependencies.plugins.getPlugin(cleanedProviderId);
153
+ const plugin = this.dependencies.plugins.getPlugin(cleanedProviderId, userId);
103
154
  if (!plugin || !plugin.active) {
104
155
  throw new WorkModelProviderError(`Plugin "${cleanedProviderId}" is not active.`, 422, 'WORK_PLUGIN_UNAVAILABLE');
105
156
  }
@@ -107,6 +158,7 @@ export class WorkModelProviderService {
107
158
  if (!plugin.model_map.includes(model)) {
108
159
  throw new WorkModelProviderError(`Model "${model}" is not configured for plugin "${plugin.id}".`, 422, 'WORK_PLUGIN_MODEL_UNAVAILABLE');
109
160
  }
161
+ resolvePluginApiConfig(plugin, this.dependencies.plugins.getPluginVariables(plugin, userId));
110
162
  if (pluginRequiresApiKey(plugin) &&
111
163
  !this.dependencies.plugins.getApiKey(plugin, userId)) {
112
164
  throw new WorkModelProviderError(`API key not found for plugin ${plugin.id}.`, 422, 'WORK_PLUGIN_CREDENTIALS_MISSING');
@@ -115,23 +167,28 @@ export class WorkModelProviderService {
115
167
  }
116
168
  async generatePluginResponse(plugin, request, userId, signal) {
117
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');
118
174
  const apiKey = this.dependencies.plugins.getApiKey(plugin, userId);
119
175
  if (pluginRequiresApiKey(plugin) && !apiKey) {
120
176
  throw new WorkModelProviderError(`API key not found for plugin ${plugin.id}.`, 422, 'WORK_PLUGIN_CREDENTIALS_MISSING');
121
177
  }
122
- const variables = this.dependencies.plugins.getPluginVariables(plugin, userId);
123
- const endpoint = applyModelEndpointTemplate(resolvePluginEndpoint(plugin.endpoint, variables.endpoint), request.model);
124
- assertSafePluginEndpoint(endpoint, 'Work model endpoint');
178
+ const providerStateScope = apiConfig.apiMode === 'responses'
179
+ ? createOpenAIResponsesStateScope(plugin.id, request.model, endpoint, createPluginCredentialFingerprint(apiKey))
180
+ : undefined;
125
181
  const headers = buildPluginAuthHeaders(plugin, apiKey);
126
- const { payload, extraHeaders } = buildPluginWorkPayload(plugin, request, variables);
182
+ const { payload, extraHeaders } = buildPluginWorkPayload(plugin, request, variables, apiConfig.apiMode, providerStateScope);
127
183
  Object.assign(headers, extraHeaders);
128
184
  try {
129
185
  const response = await this.dependencies.post(endpoint, payload, {
130
186
  headers,
131
187
  signal,
132
188
  timeout: 300000,
189
+ maxRedirects: 0,
133
190
  });
134
- return normalizePluginWorkResponse(plugin, response.data, request.model);
191
+ return normalizePluginWorkResponse(plugin, response.data, request.model, apiConfig.apiMode, providerStateScope);
135
192
  }
136
193
  catch (error) {
137
194
  if (signal?.aborted)
@@ -214,18 +271,23 @@ export class WorkModelProviderService {
214
271
  }
215
272
  async generatePluginStream(plugin, request, userId, observer, signal) {
216
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');
217
278
  const apiKey = this.dependencies.plugins.getApiKey(plugin, userId);
218
279
  if (pluginRequiresApiKey(plugin) && !apiKey) {
219
280
  throw new WorkModelProviderError(`API key not found for plugin ${plugin.id}.`, 422, 'WORK_PLUGIN_CREDENTIALS_MISSING');
220
281
  }
221
- const variables = this.dependencies.plugins.getPluginVariables(plugin, userId);
222
- let endpoint = applyModelEndpointTemplate(resolvePluginEndpoint(plugin.endpoint, variables.endpoint), request.model);
282
+ const providerStateScope = apiConfig.apiMode === 'responses'
283
+ ? createOpenAIResponsesStateScope(plugin.id, request.model, endpoint, createPluginCredentialFingerprint(apiKey))
284
+ : undefined;
223
285
  if (plugin.id === 'gemini') {
224
286
  endpoint = geminiStreamingEndpoint(endpoint);
225
287
  }
226
288
  assertSafePluginEndpoint(endpoint, 'Work model endpoint');
227
289
  const headers = buildPluginAuthHeaders(plugin, apiKey);
228
- const { payload, extraHeaders } = buildPluginWorkPayload(plugin, { ...request, stream: true }, variables);
290
+ const { payload, extraHeaders } = buildPluginWorkPayload(plugin, { ...request, stream: true }, variables, apiConfig.apiMode, providerStateScope);
229
291
  Object.assign(headers, extraHeaders);
230
292
  const timeoutSignal = AbortSignal.timeout(300000);
231
293
  const requestSignal = signal
@@ -237,13 +299,14 @@ export class WorkModelProviderService {
237
299
  headers,
238
300
  body: JSON.stringify(payload),
239
301
  signal: requestSignal,
302
+ redirect: 'error',
240
303
  });
241
304
  const contentType = response.headers.get('content-type') || '';
242
305
  if (response.ok &&
243
306
  !contentType.includes('text/event-stream') &&
244
307
  !contentType.includes('application/x-ndjson')) {
245
308
  const data = (await response.json());
246
- const normalized = normalizePluginWorkResponse(plugin, data, request.model);
309
+ const normalized = normalizePluginWorkResponse(plugin, data, request.model, apiConfig.apiMode, providerStateScope);
247
310
  if (normalized.message.thinking) {
248
311
  observer.onReasoning?.(normalized.message.thinking);
249
312
  }
@@ -256,7 +319,9 @@ export class WorkModelProviderService {
256
319
  ? streamAnthropicResponse(response)
257
320
  : plugin.id === 'gemini'
258
321
  ? streamGeminiWorkResponse(response)
259
- : streamOpenAICompatibleResponse(response);
322
+ : apiConfig.apiMode === 'responses'
323
+ ? streamOpenAIResponsesResponse(response, providerStateScope)
324
+ : streamOpenAICompatibleResponse(response);
260
325
  return await collectPluginWorkStream(chunks, request.model, observer);
261
326
  }
262
327
  catch (error) {
@@ -271,7 +336,7 @@ export class WorkModelProviderService {
271
336
  }
272
337
  }
273
338
  }
274
- export function buildPluginWorkPayload(plugin, request, variables = {}) {
339
+ export function buildPluginWorkPayload(plugin, request, variables = {}, apiMode = resolvePluginApiConfig(plugin, variables).apiMode, providerStateScope) {
275
340
  const options = (request.options || {});
276
341
  const params = resolvePluginChatParameters(options, variables);
277
342
  if (plugin.id === 'anthropic') {
@@ -286,6 +351,24 @@ export function buildPluginWorkPayload(plugin, request, variables = {}) {
286
351
  extraHeaders: {},
287
352
  };
288
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
+ }
289
372
  return {
290
373
  payload: {
291
374
  model: request.model,
@@ -299,13 +382,17 @@ export function buildPluginWorkPayload(plugin, request, variables = {}) {
299
382
  extraHeaders: {},
300
383
  };
301
384
  }
302
- export function normalizePluginWorkResponse(plugin, response, model) {
385
+ export function normalizePluginWorkResponse(plugin, response, model, apiMode = plugin.api_mode ||
386
+ inferPluginApiMode(plugin.endpoint), providerStateScope) {
303
387
  if (plugin.id === 'anthropic') {
304
388
  return normalizeAnthropicWorkResponse(response, model);
305
389
  }
306
390
  if (plugin.id === 'gemini') {
307
391
  return normalizeGeminiWorkResponse(response, model);
308
392
  }
393
+ if (apiMode === 'responses') {
394
+ return normalizeOpenAIResponsesWorkResponse(response, model, providerStateScope);
395
+ }
309
396
  return normalizeOpenAIWorkResponse(response, model);
310
397
  }
311
398
  export function toOpenAIWorkMessages(messages) {
@@ -346,12 +433,94 @@ export function toOpenAIWorkMessages(messages) {
346
433
  role: 'tool',
347
434
  content: message.content,
348
435
  name: message.tool_name,
349
- tool_call_id: matching?.id || `work-tool-${messageIndex}`,
436
+ tool_call_id: message.tool_call_id || matching?.id || `work-tool-${messageIndex}`,
350
437
  };
351
438
  }
352
439
  return { role: message.role, content: message.content };
353
440
  });
354
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
+ }
355
524
  function buildAnthropicWorkPayload(model, messages, tools, maxTokens, stream = false) {
356
525
  const system = messages
357
526
  .filter(message => message.role === 'system')
@@ -527,6 +696,45 @@ function normalizeOpenAIWorkResponse(response, model) {
527
696
  ? message.reasoning_content
528
697
  : '');
529
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
+ }
530
738
  function normalizeAnthropicWorkResponse(response, model) {
531
739
  const blocks = Array.isArray(response.content) ? response.content : [];
532
740
  const text = [];
@@ -594,7 +802,7 @@ function normalizeGeminiWorkResponse(response, model) {
594
802
  }
595
803
  return workResponse(model, text.join(''), calls, reasoning.join(''));
596
804
  }
597
- function workResponse(model, content, toolCalls, reasoning = '') {
805
+ function workResponse(model, content, toolCalls, reasoning = '', options = {}) {
598
806
  return {
599
807
  model,
600
808
  created_at: new Date().toISOString(),
@@ -603,14 +811,20 @@ function workResponse(model, content, toolCalls, reasoning = '') {
603
811
  content,
604
812
  ...(reasoning ? { thinking: reasoning } : {}),
605
813
  tool_calls: toolCalls,
814
+ ...(options.providerMetadata
815
+ ? { providerMetadata: options.providerMetadata }
816
+ : {}),
606
817
  },
607
818
  done: true,
819
+ ...(options.doneReason ? { done_reason: options.doneReason } : {}),
608
820
  };
609
821
  }
610
822
  async function collectPluginWorkStream(chunks, model, observer) {
611
823
  let content = '';
612
824
  let reasoning = '';
613
825
  let usage = {};
826
+ let doneReason;
827
+ let providerMetadata;
614
828
  const toolCalls = [];
615
829
  for await (const chunk of chunks) {
616
830
  if (chunk.type === 'content') {
@@ -654,6 +868,13 @@ async function collectPluginWorkStream(chunks, model, observer) {
654
868
  arguments: parsedArguments.arguments,
655
869
  },
656
870
  });
871
+ continue;
872
+ }
873
+ if (chunk.type === 'done') {
874
+ doneReason = chunk.doneReason;
875
+ providerMetadata = chunk.providerMetadata
876
+ ? { ...providerMetadata, ...chunk.providerMetadata }
877
+ : providerMetadata;
657
878
  }
658
879
  }
659
880
  if (reasoning && toolCalls[0]) {
@@ -667,7 +888,10 @@ async function collectPluginWorkStream(chunks, model, observer) {
667
888
  }
668
889
  }
669
890
  return {
670
- ...workResponse(model, content, toolCalls, reasoning),
891
+ ...workResponse(model, content, toolCalls, reasoning, {
892
+ ...(providerMetadata ? { providerMetadata } : {}),
893
+ ...(doneReason ? { doneReason } : {}),
894
+ }),
671
895
  prompt_eval_count: usage.promptTokens,
672
896
  eval_count: usage.completionTokens,
673
897
  };