plugin-ai-api 1.1.1 → 1.1.2

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 (108) hide show
  1. package/README.md +51 -12
  2. package/dist/client/185.c47663fefaeb0e5b.js +10 -0
  3. package/dist/client/562.9012cfd1fa04303d.js +10 -0
  4. package/dist/client/685.b5b1e0a5b825d253.js +10 -0
  5. package/dist/client/index.js +1 -1
  6. package/dist/client-v2/185.b552dc91ec2371ba.js +10 -0
  7. package/dist/client-v2/562.db2984167250b1be.js +10 -0
  8. package/dist/client-v2/685.cf16e5b829e06f85.js +10 -0
  9. package/dist/client-v2/index.js +1 -1
  10. package/dist/externalVersion.js +8 -8
  11. package/dist/locale/en-US.json +175 -139
  12. package/dist/locale/vi-VN.json +40 -2
  13. package/dist/locale/zh-CN.json +40 -2
  14. package/dist/server/collections/ai-api-model-metadata.js +26 -0
  15. package/dist/server/collections/ai-api-response-records.js +101 -0
  16. package/dist/server/collections/ai-api-virtual-models.js +68 -0
  17. package/dist/server/middleware/response-record-resource.js +66 -0
  18. package/dist/server/middleware/role-permission.js +43 -18
  19. package/dist/server/migrations/20260901000000-remove-default-group-members.js +60 -0
  20. package/dist/server/migrations/20260902000000-seed-default-role-permissions.js +55 -0
  21. package/dist/server/migrations/20260903000000-seed-sample-response-records.js +170 -0
  22. package/dist/server/plugin.js +66 -16
  23. package/dist/server/routes/chat-completions.js +38 -6
  24. package/dist/server/routes/completions.js +16 -4
  25. package/dist/server/routes/embeddings.js +25 -6
  26. package/dist/server/routes/models.js +29 -0
  27. package/dist/server/routes/responses.js +530 -0
  28. package/dist/server/routes/router.js +65 -10
  29. package/dist/server/usage.js +25 -4
  30. package/dist/server/utils/direct-llm-context.js +1 -1
  31. package/dist/server/utils/resolve-service.js +24 -0
  32. package/dist/server/utils/response-store.js +138 -0
  33. package/dist/server/utils/responses-format.js +686 -0
  34. package/dist/server/utils/responses-stream.js +330 -0
  35. package/dist/server/utils/virtual-models.js +238 -0
  36. package/dist/server/validation.js +44 -2
  37. package/dist/swagger.js +137 -0
  38. package/package.json +34 -32
  39. package/src/__tests__/locale.test.ts +43 -0
  40. package/src/client/__tests__/settings-registration.test.tsx +1 -0
  41. package/src/client/plugin.tsx +9 -1
  42. package/src/client-v2/__tests__/settings-registration.test.tsx +1 -0
  43. package/src/client-v2/pages/ModelMetadataPage.tsx +44 -0
  44. package/src/client-v2/pages/ModelRoutingPage.tsx +238 -0
  45. package/src/client-v2/pages/UsageGroupsPage.tsx +75 -38
  46. package/src/client-v2/plugin.tsx +8 -0
  47. package/src/locale/en-US.json +175 -139
  48. package/src/locale/vi-VN.json +40 -2
  49. package/src/locale/zh-CN.json +40 -2
  50. package/src/server/__tests__/embeddings.test.ts +184 -0
  51. package/src/server/__tests__/models.test.ts +21 -1
  52. package/src/server/__tests__/response-record-resource.test.ts +50 -0
  53. package/src/server/__tests__/response-store-integration.test.ts +341 -0
  54. package/src/server/__tests__/response-store.test.ts +195 -0
  55. package/src/server/__tests__/responses-contract.test.ts +469 -0
  56. package/src/server/__tests__/responses-format.test.ts +299 -0
  57. package/src/server/__tests__/responses-router.test.ts +182 -0
  58. package/src/server/__tests__/responses-streaming.test.ts +368 -0
  59. package/src/server/__tests__/responses.test.ts +462 -0
  60. package/src/server/__tests__/role-permission.test.ts +139 -0
  61. package/src/server/__tests__/seed-role-permission.test.ts +88 -0
  62. package/src/server/__tests__/types/responses-sdk.types.test-d.ts +23 -0
  63. package/src/server/__tests__/usage-groups.test.ts +96 -0
  64. package/src/server/__tests__/usage-route.test.ts +1 -0
  65. package/src/server/__tests__/usage.test.ts +14 -0
  66. package/src/server/__tests__/validation.test.ts +66 -7
  67. package/src/server/__tests__/virtual-model-routing.test.ts +589 -0
  68. package/src/server/collections/ai-api-model-metadata.ts +26 -0
  69. package/src/server/collections/ai-api-response-records.ts +77 -0
  70. package/src/server/collections/ai-api-virtual-models.ts +58 -0
  71. package/src/server/middleware/response-record-resource.ts +44 -0
  72. package/src/server/middleware/role-permission.ts +69 -35
  73. package/src/server/migrations/20260901000000-remove-default-group-members.ts +56 -0
  74. package/src/server/migrations/20260902000000-seed-default-role-permissions.ts +46 -0
  75. package/src/server/migrations/20260903000000-seed-sample-response-records.ts +162 -0
  76. package/src/server/plugin.ts +84 -20
  77. package/src/server/resource/ai-api-config.ts +2 -1
  78. package/src/server/routes/agent-completions.ts +3 -0
  79. package/src/server/routes/chat-completions.ts +34 -10
  80. package/src/server/routes/completions.ts +16 -4
  81. package/src/server/routes/embeddings.ts +32 -10
  82. package/src/server/routes/models.ts +34 -0
  83. package/src/server/routes/responses.ts +640 -0
  84. package/src/server/routes/router.ts +81 -12
  85. package/src/server/services/__tests__/file-processor.test.ts +1 -0
  86. package/src/server/usage.ts +29 -2
  87. package/src/server/utils/app-observability.ts +1 -1
  88. package/src/server/utils/direct-llm-context.ts +2 -1
  89. package/src/server/utils/openai-format.ts +1 -0
  90. package/src/server/utils/resolve-service.ts +39 -1
  91. package/src/server/utils/response-store.ts +148 -0
  92. package/src/server/utils/responses-format.ts +974 -0
  93. package/src/server/utils/responses-stream.ts +384 -0
  94. package/src/server/utils/virtual-models.ts +320 -0
  95. package/src/server/validation.ts +49 -0
  96. package/src/swagger.ts +139 -0
  97. package/dist/client/562.44b16aad4718b4c7.js +0 -10
  98. package/dist/client/685.ae483e17b6b49c98.js +0 -10
  99. package/dist/client-v2/562.45d5c504433be38b.js +0 -10
  100. package/dist/client-v2/685.1030370b309b7d4b.js +0 -10
  101. package/dist/server/collections/ai-api-user-permissions.js +0 -67
  102. package/dist/server/collections/ai-api-user-quota-buckets.js +0 -54
  103. package/dist/server/collections/ai-api-user-quota-policies.js +0 -63
  104. package/dist/server/resource/ai-api-usage-groups.js +0 -168
  105. package/src/server/collections/ai-api-user-permissions.ts +0 -46
  106. package/src/server/collections/ai-api-user-quota-buckets.ts +0 -24
  107. package/src/server/collections/ai-api-user-quota-policies.ts +0 -33
  108. package/src/server/resource/ai-api-usage-groups.ts +0 -171
@@ -0,0 +1,686 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __create = Object.create;
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ var __copyProps = (to, from, except, desc) => {
21
+ if (from && typeof from === "object" || typeof from === "function") {
22
+ for (let key of __getOwnPropNames(from))
23
+ if (!__hasOwnProp.call(to, key) && key !== except)
24
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
+ }
26
+ return to;
27
+ };
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
+ // If the importer is in node compatibility mode or this is not an ESM
30
+ // file that has been converted to a CommonJS file using a Babel-
31
+ // compatible transform (i.e. "__esModule" has not been set), then set
32
+ // "default" to the CommonJS "module.exports" for node compatibility.
33
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
+ mod
35
+ ));
36
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
+ var responses_format_exports = {};
38
+ __export(responses_format_exports, {
39
+ chatResultToResponse: () => chatResultToResponse,
40
+ createResponseOutputMessage: () => createResponseOutputMessage,
41
+ createResponseReasoningItem: () => createResponseReasoningItem,
42
+ extractReasoningText: () => extractReasoningText,
43
+ extractResponseIncompleteReason: () => extractResponseIncompleteReason,
44
+ extractResponseOutputText: () => extractResponseOutputText,
45
+ extractResponseServiceTier: () => extractResponseServiceTier,
46
+ findResponseInputProblem: () => findResponseInputProblem,
47
+ findResponseParameterProblem: () => findResponseParameterProblem,
48
+ findResponseToolChoiceProblem: () => findResponseToolChoiceProblem,
49
+ findResponseToolProblem: () => findResponseToolProblem,
50
+ findUnsupportedResponseInput: () => findUnsupportedResponseInput,
51
+ findUnsupportedResponseParameter: () => findUnsupportedResponseParameter,
52
+ generateResponseId: () => generateResponseId,
53
+ generateResponseItemId: () => generateResponseItemId,
54
+ isRecord: () => isRecord,
55
+ isResponseServiceTier: () => isResponseServiceTier,
56
+ responseIncompleteReason: () => responseIncompleteReason,
57
+ responseUsageFromOpenAIUsage: () => responseUsageFromOpenAIUsage,
58
+ responsesBodyToChatBody: () => responsesBodyToChatBody,
59
+ responsesInputToMessages: () => responsesInputToMessages,
60
+ responsesToolsToChatTools: () => responsesToolsToChatTools
61
+ });
62
+ module.exports = __toCommonJS(responses_format_exports);
63
+ var import_crypto = __toESM(require("crypto"));
64
+ function generateResponseId() {
65
+ return `resp_${import_crypto.default.randomBytes(16).toString("hex")}`;
66
+ }
67
+ function generateResponseItemId(prefix = "msg") {
68
+ return `${prefix}_${import_crypto.default.randomBytes(16).toString("hex")}`;
69
+ }
70
+ function isRecord(value) {
71
+ return typeof value === "object" && value !== null && !Array.isArray(value);
72
+ }
73
+ function responseImageToChatBlock(block) {
74
+ if (typeof block.image_url !== "string" || !block.image_url) return null;
75
+ return {
76
+ type: "image_url",
77
+ image_url: {
78
+ url: block.image_url,
79
+ ...typeof block.detail === "string" ? { detail: block.detail } : {}
80
+ }
81
+ };
82
+ }
83
+ function responseFileToChatBlock(block) {
84
+ if (typeof block.file_data === "string" && block.file_data) {
85
+ return {
86
+ type: "file",
87
+ file: {
88
+ file_data: block.file_data,
89
+ ...typeof block.filename === "string" ? { filename: block.filename } : {}
90
+ }
91
+ };
92
+ }
93
+ if (typeof block.file_url === "string" && block.file_url) {
94
+ return { type: "file_url", file_url: { url: block.file_url } };
95
+ }
96
+ return null;
97
+ }
98
+ function responseContentToChatContent(content) {
99
+ if (typeof content === "string") return content;
100
+ if (!Array.isArray(content)) return content;
101
+ return content.flatMap((block) => {
102
+ if (typeof block === "string") return [{ type: "text", text: block }];
103
+ if (!isRecord(block)) return [];
104
+ if ((block.type === "input_text" || block.type === "output_text") && typeof block.text === "string") {
105
+ return [{ type: "text", text: block.text }];
106
+ }
107
+ if (block.type === "input_image") {
108
+ const converted = responseImageToChatBlock(block);
109
+ return converted ? [converted] : [];
110
+ }
111
+ if (block.type === "input_file") {
112
+ const converted = responseFileToChatBlock(block);
113
+ return converted ? [converted] : [];
114
+ }
115
+ if (block.type === "text" || block.type === "image_url" || block.type === "file" || block.type === "file_url") {
116
+ return [block];
117
+ }
118
+ return [];
119
+ });
120
+ }
121
+ function messageItemToChatMessage(item) {
122
+ const role = typeof item.role === "string" ? item.role : void 0;
123
+ if (!role) return null;
124
+ return {
125
+ role,
126
+ content: responseContentToChatContent(item.content),
127
+ ...typeof item.phase === "string" ? { phase: item.phase } : {}
128
+ };
129
+ }
130
+ function functionCallToChatMessage(item) {
131
+ if (typeof item.call_id !== "string" || typeof item.name !== "string") return null;
132
+ return {
133
+ role: "assistant",
134
+ content: "",
135
+ tool_calls: [
136
+ {
137
+ id: item.call_id,
138
+ type: "function",
139
+ function: {
140
+ name: item.name,
141
+ arguments: typeof item.arguments === "string" ? item.arguments : "{}"
142
+ }
143
+ }
144
+ ]
145
+ };
146
+ }
147
+ function appendFunctionCall(messages, item) {
148
+ const message = functionCallToChatMessage(item);
149
+ if (!message) return false;
150
+ const previous = messages.at(-1);
151
+ const previousAdditional = isRecord(previous == null ? void 0 : previous.additional_kwargs) ? previous.additional_kwargs : {};
152
+ const hasReasoning = typeof previousAdditional.reasoning_content === "string" || isRecord(previousAdditional.reasoning);
153
+ if ((previous == null ? void 0 : previous.role) !== "assistant" || previous.content !== "" || (!Array.isArray(previous.tool_calls) || previous.tool_calls.length === 0) && !hasReasoning) {
154
+ messages.push(message);
155
+ return true;
156
+ }
157
+ const previousCalls = Array.isArray(previous.tool_calls) ? previous.tool_calls : [];
158
+ const nextCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
159
+ previous.tool_calls = [...previousCalls, ...nextCalls];
160
+ previous.additional_kwargs = {
161
+ ...isRecord(previous.additional_kwargs) ? previous.additional_kwargs : {},
162
+ tool_calls: previous.tool_calls
163
+ };
164
+ const responseMetadata2 = isRecord(previous.response_metadata) ? previous.response_metadata : {};
165
+ const output = Array.isArray(responseMetadata2.output) ? responseMetadata2.output : [];
166
+ previous.response_metadata = { ...responseMetadata2, output: [...output, item] };
167
+ return true;
168
+ }
169
+ function reasoningToChatMessage(item) {
170
+ const summary = Array.isArray(item.summary) ? item.summary.filter((part) => isRecord(part) && typeof part.text === "string").map((part) => part.text).join("\n") : "";
171
+ const content = Array.isArray(item.content) ? item.content.filter((part) => isRecord(part) && typeof part.text === "string").map((part) => part.text).join("\n") : "";
172
+ return {
173
+ role: "assistant",
174
+ content: "",
175
+ additional_kwargs: {
176
+ reasoning_content: content || summary,
177
+ reasoning: item
178
+ },
179
+ response_metadata: { output: [item] }
180
+ };
181
+ }
182
+ function appendReasoningItem(messages, item) {
183
+ const previous = messages.at(-1);
184
+ if ((previous == null ? void 0 : previous.role) === "assistant" && previous.content === "") {
185
+ const reasoning = reasoningToChatMessage(item);
186
+ previous.additional_kwargs = {
187
+ ...isRecord(previous.additional_kwargs) ? previous.additional_kwargs : {},
188
+ ...isRecord(reasoning.additional_kwargs) ? reasoning.additional_kwargs : {}
189
+ };
190
+ const responseMetadata2 = isRecord(previous.response_metadata) ? previous.response_metadata : {};
191
+ const output = Array.isArray(responseMetadata2.output) ? responseMetadata2.output : [];
192
+ previous.response_metadata = { ...responseMetadata2, output: [...output, item] };
193
+ return;
194
+ }
195
+ messages.push(reasoningToChatMessage(item));
196
+ }
197
+ function functionCallOutputToChatMessage(item) {
198
+ if (typeof item.call_id !== "string") return null;
199
+ return {
200
+ role: "tool",
201
+ content: responseContentToChatContent(item.output),
202
+ tool_call_id: item.call_id
203
+ };
204
+ }
205
+ function responsesInputToMessages(input, instructions) {
206
+ const messages = [];
207
+ if (typeof instructions === "string" && instructions) {
208
+ messages.push({ role: "developer", content: instructions });
209
+ }
210
+ if (typeof input === "string") return [...messages, { role: "user", content: input }];
211
+ if (!Array.isArray(input)) return messages;
212
+ for (const item of input) {
213
+ if (!isRecord(item)) continue;
214
+ if (item.type === "function_call") {
215
+ appendFunctionCall(messages, item);
216
+ continue;
217
+ }
218
+ if (item.type === "reasoning") {
219
+ appendReasoningItem(messages, item);
220
+ continue;
221
+ }
222
+ let message = null;
223
+ if (item.type === "function_call_output") message = functionCallOutputToChatMessage(item);
224
+ else if (item.type === "message" || typeof item.role === "string") message = messageItemToChatMessage(item);
225
+ if (message) messages.push(message);
226
+ }
227
+ return messages;
228
+ }
229
+ function responseFunctionToolToChatTool(tool) {
230
+ if (tool.type !== "function" || typeof tool.name !== "string") return null;
231
+ return {
232
+ type: "function",
233
+ function: {
234
+ name: tool.name,
235
+ ...typeof tool.description === "string" ? { description: tool.description } : {},
236
+ parameters: isRecord(tool.parameters) ? tool.parameters : {},
237
+ ...typeof tool.strict === "boolean" ? { strict: tool.strict } : {}
238
+ }
239
+ };
240
+ }
241
+ function responsesToolsToChatTools(tools) {
242
+ if (!Array.isArray(tools)) return void 0;
243
+ return tools.flatMap((tool) => {
244
+ if (!isRecord(tool)) return [];
245
+ const converted = responseFunctionToolToChatTool(tool);
246
+ return converted ? [converted] : [];
247
+ });
248
+ }
249
+ function responsesToolChoiceToChatToolChoice(toolChoice) {
250
+ if (!isRecord(toolChoice) || toolChoice.type !== "function" || typeof toolChoice.name !== "string") {
251
+ return toolChoice;
252
+ }
253
+ return { type: "function", function: { name: toolChoice.name } };
254
+ }
255
+ function responsesBodyToChatBody(body) {
256
+ const chatBody = {
257
+ model: body.model,
258
+ messages: responsesInputToMessages(body.input, body.instructions)
259
+ };
260
+ if (body.temperature !== void 0) chatBody.temperature = body.temperature;
261
+ if (body.top_p !== void 0) chatBody.top_p = body.top_p;
262
+ if (body.max_output_tokens !== void 0) chatBody.max_completion_tokens = body.max_output_tokens;
263
+ const tools = responsesToolsToChatTools(body.tools);
264
+ if (tools) chatBody.tools = tools;
265
+ if (body.tool_choice !== void 0) chatBody.tool_choice = responsesToolChoiceToChatToolChoice(body.tool_choice);
266
+ if (body.stream !== void 0) chatBody.stream = body.stream;
267
+ if (body.service_tier !== void 0 && body.service_tier !== null) chatBody.service_tier = body.service_tier;
268
+ if (body.prompt_cache_key !== void 0) chatBody.promptCacheKey = body.prompt_cache_key;
269
+ if (body.prompt_cache_retention !== void 0 && body.prompt_cache_retention !== null) {
270
+ chatBody.promptCacheRetention = body.prompt_cache_retention;
271
+ }
272
+ if (body.reasoning !== void 0 && body.reasoning !== null) chatBody.reasoning = body.reasoning;
273
+ if (body.safety_identifier !== void 0) chatBody.safety_identifier = body.safety_identifier;
274
+ if (body.text !== void 0) {
275
+ if (isRecord(body.text)) {
276
+ if (body.text.format !== void 0) chatBody.response_format = responsesTextFormatToChatFormat(body.text.format);
277
+ if (body.text.verbosity !== void 0) chatBody.verbosity = body.text.verbosity;
278
+ }
279
+ }
280
+ if (body.parallel_tool_calls !== void 0 && body.parallel_tool_calls !== null) {
281
+ chatBody.parallel_tool_calls = body.parallel_tool_calls;
282
+ }
283
+ if (body.user !== void 0) chatBody.user = body.user;
284
+ return chatBody;
285
+ }
286
+ function responseUsageFromOpenAIUsage(usage, reasoningTokens = 0) {
287
+ return {
288
+ input_tokens: (usage == null ? void 0 : usage.prompt_tokens) ?? 0,
289
+ input_tokens_details: { cached_tokens: (usage == null ? void 0 : usage.prompt_cache_tokens) ?? 0 },
290
+ output_tokens: (usage == null ? void 0 : usage.completion_tokens) ?? 0,
291
+ output_tokens_details: { reasoning_tokens: (usage == null ? void 0 : usage.reasoning_tokens) ?? reasoningTokens },
292
+ total_tokens: (usage == null ? void 0 : usage.total_tokens) ?? 0
293
+ };
294
+ }
295
+ function createResponseOutputMessage(text, status = "completed", id = generateResponseItemId("msg"), phase) {
296
+ return {
297
+ id,
298
+ type: "message",
299
+ status,
300
+ role: "assistant",
301
+ content: text ? [{ type: "output_text", text, annotations: [] }] : [],
302
+ ...phase === void 0 ? {} : { phase }
303
+ };
304
+ }
305
+ function extractResponseOutputText(value) {
306
+ if (!isRecord(value)) return "";
307
+ if (typeof value.content === "string") return value.content;
308
+ if (!Array.isArray(value.content)) return "";
309
+ return value.content.filter(
310
+ (block) => isRecord(block) && (block.type === "text" || block.type === "output_text")
311
+ ).map((block) => typeof block.text === "string" ? block.text : "").join("");
312
+ }
313
+ function toolCallToResponseFunctionCall(call) {
314
+ return {
315
+ id: generateResponseItemId("fc"),
316
+ type: "function_call",
317
+ status: "completed",
318
+ call_id: call.id,
319
+ name: call.function.name,
320
+ arguments: call.function.arguments
321
+ };
322
+ }
323
+ function createResponseReasoningItem(text) {
324
+ return {
325
+ id: generateResponseItemId("rs"),
326
+ type: "reasoning",
327
+ status: "completed",
328
+ summary: [],
329
+ content: text ? [{ type: "reasoning_text", text }] : []
330
+ };
331
+ }
332
+ function numberOrNull(value) {
333
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
334
+ }
335
+ function responseMetadata(value) {
336
+ if (!isRecord(value)) return null;
337
+ const entries = Object.entries(value).filter((entry) => typeof entry[1] === "string");
338
+ return Object.fromEntries(entries);
339
+ }
340
+ function chatResultToResponse(options) {
341
+ const {
342
+ id = generateResponseId(),
343
+ model,
344
+ content,
345
+ reasoningText,
346
+ usage,
347
+ toolCalls,
348
+ finishReason,
349
+ serviceTier,
350
+ requestBody,
351
+ status = responseIncompleteReason(finishReason) ? "incomplete" : "completed"
352
+ } = options;
353
+ const output = [];
354
+ if (reasoningText) output.push(createResponseReasoningItem(reasoningText));
355
+ if (content) output.push(createResponseOutputMessage(content));
356
+ if (toolCalls == null ? void 0 : toolCalls.length) output.push(...toolCalls.map(toolCallToResponseFunctionCall));
357
+ const now = Math.floor(Date.now() / 1e3);
358
+ return {
359
+ id,
360
+ object: "response",
361
+ created_at: now,
362
+ completed_at: status === "completed" ? now : null,
363
+ status,
364
+ error: null,
365
+ incomplete_details: status === "incomplete" ? { reason: responseIncompleteReason(finishReason) ?? "max_output_tokens" } : null,
366
+ instructions: typeof requestBody.instructions === "string" ? requestBody.instructions : null,
367
+ ...requestBody.max_output_tokens === void 0 ? {} : { max_output_tokens: numberOrNull(requestBody.max_output_tokens) },
368
+ model,
369
+ output,
370
+ output_text: content,
371
+ parallel_tool_calls: requestBody.parallel_tool_calls !== false,
372
+ ...requestBody.previous_response_id === void 0 ? {} : {
373
+ previous_response_id: typeof requestBody.previous_response_id === "string" ? requestBody.previous_response_id : null
374
+ },
375
+ prompt_cache_key: typeof requestBody.prompt_cache_key === "string" ? requestBody.prompt_cache_key : void 0,
376
+ prompt_cache_retention: requestBody.prompt_cache_retention === "in_memory" || requestBody.prompt_cache_retention === "24h" ? requestBody.prompt_cache_retention : requestBody.prompt_cache_retention === null ? null : void 0,
377
+ ...requestBody.reasoning === void 0 ? {} : { reasoning: isRecord(requestBody.reasoning) ? requestBody.reasoning : null },
378
+ safety_identifier: typeof requestBody.safety_identifier === "string" ? requestBody.safety_identifier : void 0,
379
+ service_tier: serviceTier ?? (isResponseServiceTier(requestBody.service_tier) ? requestBody.service_tier : "auto"),
380
+ temperature: numberOrNull(requestBody.temperature),
381
+ ...requestBody.text === void 0 ? {} : { text: isRecord(requestBody.text) ? requestBody.text : void 0 },
382
+ tool_choice: requestBody.tool_choice ?? "auto",
383
+ tools: Array.isArray(requestBody.tools) ? requestBody.tools : [],
384
+ top_p: numberOrNull(requestBody.top_p),
385
+ truncation: requestBody.truncation === "auto" ? "auto" : "disabled",
386
+ usage: responseUsageFromOpenAIUsage(usage),
387
+ user: typeof requestBody.user === "string" ? requestBody.user : void 0,
388
+ metadata: responseMetadata(requestBody.metadata)
389
+ };
390
+ }
391
+ function extractReasoningText(value) {
392
+ if (!isRecord(value)) return void 0;
393
+ const candidates = [
394
+ value.reasoning_content,
395
+ value.reasoning,
396
+ isRecord(value.additional_kwargs) ? value.additional_kwargs.reasoning_content : void 0,
397
+ isRecord(value.additional_kwargs) ? value.additional_kwargs.reasoning : void 0,
398
+ isRecord(value.response_metadata) ? value.response_metadata.reasoning_content : void 0,
399
+ isRecord(value.response_metadata) ? value.response_metadata.reasoning : void 0
400
+ ];
401
+ for (const candidate of candidates) {
402
+ const text = reasoningValueToText(candidate);
403
+ if (text) return text;
404
+ }
405
+ if (Array.isArray(value.content)) {
406
+ const text = value.content.filter(
407
+ (block) => isRecord(block) && (block.type === "reasoning" || block.type === "reasoning_content")
408
+ ).map(reasoningValueToText).filter((part) => Boolean(part)).join("");
409
+ if (text) return text;
410
+ }
411
+ return void 0;
412
+ }
413
+ function reasoningValueToText(value) {
414
+ if (typeof value === "string") return value || void 0;
415
+ if (!isRecord(value)) return void 0;
416
+ if (typeof value.reasoning === "string" && value.reasoning) return value.reasoning;
417
+ if (typeof value.text === "string" && value.text) return value.text;
418
+ if (typeof value.content === "string" && value.content) return value.content;
419
+ for (const key of ["content", "summary"]) {
420
+ const parts = value[key];
421
+ if (!Array.isArray(parts)) continue;
422
+ const text = parts.filter(isRecord).map((part) => typeof part.text === "string" ? part.text : "").filter(Boolean).join("");
423
+ if (text) return text;
424
+ }
425
+ return void 0;
426
+ }
427
+ function responseIncompleteReason(finishReason) {
428
+ if (finishReason === "length" || finishReason === "max_tokens" || finishReason === "max_output_tokens") {
429
+ return "max_output_tokens";
430
+ }
431
+ if (finishReason === "content_filter") return "content_filter";
432
+ return null;
433
+ }
434
+ function extractResponseIncompleteReason(value) {
435
+ if (!isRecord(value)) return void 0;
436
+ const metadataCandidates = [value.response_metadata, value.additional_kwargs, value];
437
+ for (const candidate of metadataCandidates) {
438
+ if (!isRecord(candidate)) continue;
439
+ if (candidate.status === "incomplete" && candidate.incomplete_details === null) return "max_output_tokens";
440
+ const details = candidate.incomplete_details;
441
+ if (!isRecord(details)) continue;
442
+ if (details.reason === "max_output_tokens" || details.reason === "content_filter") return details.reason;
443
+ }
444
+ return void 0;
445
+ }
446
+ function extractResponseServiceTier(value) {
447
+ if (!isRecord(value)) return void 0;
448
+ const responseMetadata2 = isRecord(value.response_metadata) ? value.response_metadata : void 0;
449
+ const candidate = (responseMetadata2 == null ? void 0 : responseMetadata2.service_tier) ?? (responseMetadata2 == null ? void 0 : responseMetadata2.serviceTier) ?? value.service_tier;
450
+ return isResponseServiceTier(candidate) ? candidate : void 0;
451
+ }
452
+ function isResponseServiceTier(value) {
453
+ return value === "auto" || value === "default" || value === "flex" || value === "scale" || value === "priority";
454
+ }
455
+ function findResponseParameterProblem(body) {
456
+ if (body.instructions !== void 0 && body.instructions !== null && typeof body.instructions !== "string") {
457
+ return "'instructions' must be a string or null";
458
+ }
459
+ const numberFields = [
460
+ { name: "max_output_tokens", min: 1, integer: true },
461
+ { name: "temperature", min: 0, max: 2 },
462
+ { name: "top_p", min: 0, max: 1 }
463
+ ];
464
+ for (const field of numberFields) {
465
+ const value = body[field.name];
466
+ if (value === void 0 || value === null) continue;
467
+ if (typeof value !== "number" || !Number.isFinite(value) || value < field.min || field.max !== void 0 && value > field.max || field.integer && !Number.isSafeInteger(value)) {
468
+ return `'${field.name}' must be ${field.integer ? "an integer" : "a number"} between ${field.min} and ${field.max ?? "the supported model limit"}`;
469
+ }
470
+ }
471
+ for (const name of ["parallel_tool_calls", "store", "stream"]) {
472
+ if (body[name] !== void 0 && body[name] !== null && typeof body[name] !== "boolean") {
473
+ return `'${name}' must be a boolean or null`;
474
+ }
475
+ }
476
+ for (const name of ["prompt_cache_key", "safety_identifier", "user"]) {
477
+ if (body[name] !== void 0 && typeof body[name] !== "string") {
478
+ return `'${name}' must be a string`;
479
+ }
480
+ }
481
+ if (typeof body.safety_identifier === "string" && body.safety_identifier.length > 64) {
482
+ return "'safety_identifier' must be at most 64 characters";
483
+ }
484
+ if (body.prompt_cache_retention !== void 0 && body.prompt_cache_retention !== null && body.prompt_cache_retention !== "in_memory" && body.prompt_cache_retention !== "24h") {
485
+ return "'prompt_cache_retention' must be 'in_memory', '24h', or null";
486
+ }
487
+ if (body.reasoning !== void 0 && body.reasoning !== null) {
488
+ if (!isRecord(body.reasoning)) return "'reasoning' must be an object or null";
489
+ const effort = body.reasoning.effort;
490
+ if (effort !== void 0 && effort !== null && effort !== "none" && effort !== "minimal" && effort !== "low" && effort !== "medium" && effort !== "high" && effort !== "xhigh") {
491
+ return "'reasoning.effort' must be none, minimal, low, medium, high, xhigh, or null";
492
+ }
493
+ }
494
+ if (body.text !== void 0 && body.text !== null) {
495
+ if (!isRecord(body.text)) return "'text' must be an object or null";
496
+ if (body.text.verbosity !== void 0 && body.text.verbosity !== null) {
497
+ if (body.text.verbosity !== "low" && body.text.verbosity !== "medium" && body.text.verbosity !== "high") {
498
+ return "'text.verbosity' must be low, medium, high, or null";
499
+ }
500
+ }
501
+ const format = body.text.format;
502
+ if (format !== void 0 && format !== null) {
503
+ if (!isRecord(format)) return "'text.format' must be an object or null";
504
+ if (format.type !== "text" && format.type !== "json_object" && format.type !== "json_schema") {
505
+ return "'text.format.type' must be text, json_object, or json_schema";
506
+ }
507
+ if (format.type === "json_schema" && (typeof format.name !== "string" || !format.name || !isRecord(format.schema))) {
508
+ return "'text.format' with type json_schema requires a non-empty name and an object schema";
509
+ }
510
+ }
511
+ }
512
+ if (body.previous_response_id !== void 0 && body.previous_response_id !== null) {
513
+ if (typeof body.previous_response_id !== "string" || !body.previous_response_id) {
514
+ return "'previous_response_id' must be a non-empty string or null";
515
+ }
516
+ }
517
+ return void 0;
518
+ }
519
+ function findUnsupportedResponseInput(input) {
520
+ if (!Array.isArray(input)) return void 0;
521
+ for (const item of input) {
522
+ if (!isRecord(item) || !Array.isArray(item.content)) continue;
523
+ for (const block of item.content) {
524
+ if (!isRecord(block)) continue;
525
+ if (block.type === "input_image" && typeof block.file_id === "string") {
526
+ return "input_image.file_id";
527
+ }
528
+ if (block.type === "input_file" && typeof block.file_id === "string") {
529
+ return "input_file.file_id";
530
+ }
531
+ }
532
+ }
533
+ return void 0;
534
+ }
535
+ function findResponseToolProblem(tools) {
536
+ if (tools === void 0) return void 0;
537
+ if (!Array.isArray(tools)) return "'tools' must be an array";
538
+ for (const [index, tool] of tools.entries()) {
539
+ if (!isRecord(tool)) return `tools[${index}] must be an object`;
540
+ if (tool.type !== "function") return `tool type '${String(tool.type ?? "unknown")}' is not supported`;
541
+ if (typeof tool.name !== "string" || !tool.name) return `tools[${index}].name must be a non-empty string`;
542
+ if (tool.parameters !== void 0 && tool.parameters !== null && !isRecord(tool.parameters)) {
543
+ return `tools[${index}].parameters must be an object or null`;
544
+ }
545
+ if (tool.strict !== void 0 && tool.strict !== null && typeof tool.strict !== "boolean") {
546
+ return `tools[${index}].strict must be a boolean or null`;
547
+ }
548
+ if (tool.description !== void 0 && tool.description !== null && typeof tool.description !== "string") {
549
+ return `tools[${index}].description must be a string or null`;
550
+ }
551
+ if (tool.defer_loading !== void 0) return `tools[${index}].defer_loading is not supported`;
552
+ }
553
+ return void 0;
554
+ }
555
+ function findResponseToolChoiceProblem(toolChoice) {
556
+ if (toolChoice === void 0) return void 0;
557
+ if (toolChoice === "auto" || toolChoice === "none" || toolChoice === "required") return void 0;
558
+ if (!isRecord(toolChoice)) return "'tool_choice' must be auto, none, required, or a function choice object";
559
+ if (toolChoice.type !== "function" || typeof toolChoice.name !== "string" || !toolChoice.name) {
560
+ return "'tool_choice' object must have type='function' and a non-empty name";
561
+ }
562
+ return void 0;
563
+ }
564
+ function findResponseInputProblem(input) {
565
+ if (typeof input === "string") return input.length > 0 ? void 0 : "'input' string must not be empty";
566
+ if (!Array.isArray(input)) return "'input' must be a string or an array";
567
+ if (input.length === 0) return "'input' array must not be empty";
568
+ for (const [index, item] of input.entries()) {
569
+ if (!isRecord(item)) return `input[${index}] must be an object`;
570
+ if (item.type === "function_call") {
571
+ if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string") {
572
+ return `input[${index}] function_call requires non-empty call_id and name strings plus string arguments`;
573
+ }
574
+ continue;
575
+ }
576
+ if (item.type === "reasoning") {
577
+ if (typeof item.id !== "string" || !item.id || !Array.isArray(item.summary)) {
578
+ return `input[${index}] reasoning requires a non-empty id and summary array`;
579
+ }
580
+ const invalidSummary = item.summary.some(
581
+ (part) => !isRecord(part) || part.type !== "summary_text" || typeof part.text !== "string"
582
+ );
583
+ if (invalidSummary) return `input[${index}].reasoning summary items must be summary_text objects`;
584
+ if (item.content !== void 0 && (!Array.isArray(item.content) || item.content.some(
585
+ (part) => !isRecord(part) || part.type !== "reasoning_text" || typeof part.text !== "string"
586
+ ))) {
587
+ return `input[${index}].reasoning content items must be reasoning_text objects`;
588
+ }
589
+ continue;
590
+ }
591
+ if (item.type === "function_call_output") {
592
+ if (typeof item.call_id !== "string" || !item.call_id || item.output === void 0) {
593
+ return `input[${index}] function_call_output requires call_id and output`;
594
+ }
595
+ if (typeof item.output !== "string" && (!Array.isArray(item.output) || item.output.some(
596
+ (part) => !isRecord(part) || part.type !== "input_text" && part.type !== "input_image" && part.type !== "input_file"
597
+ ))) {
598
+ return `input[${index}] function_call_output output must be a string or input content array`;
599
+ }
600
+ continue;
601
+ }
602
+ if (item.type === "message" || typeof item.role === "string") {
603
+ if (item.role !== "user" && item.role !== "assistant" && item.role !== "system" && item.role !== "developer") {
604
+ return `input[${index}].role is not supported`;
605
+ }
606
+ if (typeof item.content !== "string" && !Array.isArray(item.content)) {
607
+ return `input[${index}].content must be a string or an array`;
608
+ }
609
+ if (item.phase !== void 0 && item.phase !== null && item.phase !== "commentary" && item.phase !== "final_answer") {
610
+ return `input[${index}].phase must be commentary, final_answer, or null`;
611
+ }
612
+ if (Array.isArray(item.content)) {
613
+ for (const [contentIndex, block] of item.content.entries()) {
614
+ if (!isRecord(block) || typeof block.type !== "string") {
615
+ return `input[${index}].content[${contentIndex}] must be a typed object`;
616
+ }
617
+ if ((block.type === "input_text" || block.type === "output_text") && typeof block.text !== "string") {
618
+ return `input[${index}].content[${contentIndex}].text must be a string`;
619
+ }
620
+ if (block.type === "input_image" && typeof block.image_url !== "string" && typeof block.file_id !== "string") {
621
+ return `input[${index}].content[${contentIndex}] input_image requires image_url or file_id`;
622
+ }
623
+ if (block.type === "input_file" && typeof block.file_url !== "string" && typeof block.file_data !== "string" && typeof block.file_id !== "string") {
624
+ return `input[${index}].content[${contentIndex}] input_file requires file_url, file_data, or file_id`;
625
+ }
626
+ if (block.type !== "input_text" && block.type !== "output_text" && block.type !== "input_image" && block.type !== "input_file") {
627
+ return `input[${index}].content[${contentIndex}] type '${block.type}' is not supported`;
628
+ }
629
+ }
630
+ }
631
+ continue;
632
+ }
633
+ return `input[${index}] type '${String(item.type ?? "unknown")}' is not supported`;
634
+ }
635
+ return void 0;
636
+ }
637
+ function findUnsupportedResponseParameter(body) {
638
+ const unsupported = [
639
+ "background",
640
+ "context_management",
641
+ "conversation",
642
+ "include",
643
+ "max_tool_calls",
644
+ "prompt",
645
+ "stream_options",
646
+ "top_logprobs"
647
+ ];
648
+ return unsupported.find((name) => body[name] !== void 0);
649
+ }
650
+ function responsesTextFormatToChatFormat(format) {
651
+ if (!isRecord(format) || format.type !== "json_schema") return format;
652
+ return {
653
+ type: "json_schema",
654
+ json_schema: {
655
+ name: format.name,
656
+ schema: format.schema,
657
+ ...typeof format.description === "string" ? { description: format.description } : {},
658
+ ...typeof format.strict === "boolean" ? { strict: format.strict } : {}
659
+ }
660
+ };
661
+ }
662
+ // Annotate the CommonJS export names for ESM import in node:
663
+ 0 && (module.exports = {
664
+ chatResultToResponse,
665
+ createResponseOutputMessage,
666
+ createResponseReasoningItem,
667
+ extractReasoningText,
668
+ extractResponseIncompleteReason,
669
+ extractResponseOutputText,
670
+ extractResponseServiceTier,
671
+ findResponseInputProblem,
672
+ findResponseParameterProblem,
673
+ findResponseToolChoiceProblem,
674
+ findResponseToolProblem,
675
+ findUnsupportedResponseInput,
676
+ findUnsupportedResponseParameter,
677
+ generateResponseId,
678
+ generateResponseItemId,
679
+ isRecord,
680
+ isResponseServiceTier,
681
+ responseIncompleteReason,
682
+ responseUsageFromOpenAIUsage,
683
+ responsesBodyToChatBody,
684
+ responsesInputToMessages,
685
+ responsesToolsToChatTools
686
+ });