plugin-ai-api 1.1.0 → 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.
- package/README.md +51 -12
- package/dist/client/185.c47663fefaeb0e5b.js +10 -0
- package/dist/client/562.9012cfd1fa04303d.js +10 -0
- package/dist/client/685.b5b1e0a5b825d253.js +10 -0
- package/dist/client/97.1bc5103fd9d995a8.js +10 -0
- package/dist/client/index.js +1 -1
- package/dist/client-v2/185.b552dc91ec2371ba.js +10 -0
- package/dist/client-v2/562.db2984167250b1be.js +10 -0
- package/dist/client-v2/685.cf16e5b829e06f85.js +10 -0
- package/dist/client-v2/97.96da323832251796.js +10 -0
- package/dist/client-v2/index.js +1 -1
- package/dist/externalVersion.js +8 -8
- package/dist/locale/en-US.json +38 -1
- package/dist/locale/vi-VN.json +177 -138
- package/dist/locale/zh-CN.json +177 -138
- package/dist/server/billing.js +17 -9
- package/dist/server/collections/ai-api-model-metadata.js +26 -0
- package/dist/server/collections/ai-api-model-prices.js +8 -0
- package/dist/server/collections/ai-api-response-records.js +101 -0
- package/dist/server/collections/ai-api-usage-records.js +1 -0
- package/dist/server/collections/ai-api-virtual-models.js +68 -0
- package/dist/server/middleware/response-record-resource.js +66 -0
- package/dist/server/middleware/role-permission.js +43 -18
- package/dist/server/migrations/20260827000000-add-cache-input-price.js +66 -0
- package/dist/server/migrations/20260901000000-remove-default-group-members.js +60 -0
- package/dist/server/migrations/20260902000000-seed-default-role-permissions.js +55 -0
- package/dist/server/migrations/20260903000000-seed-sample-response-records.js +170 -0
- package/dist/server/plugin.js +66 -16
- package/dist/server/routes/auth.js +16 -0
- package/dist/server/routes/chat-completions.js +38 -6
- package/dist/server/routes/completions.js +16 -4
- package/dist/server/routes/embeddings.js +34 -5
- package/dist/server/routes/models.js +29 -0
- package/dist/server/routes/responses.js +530 -0
- package/dist/server/routes/router.js +65 -10
- package/dist/server/usage.js +26 -4
- package/dist/server/utils/direct-llm-context.js +10 -9
- package/dist/server/utils/resolve-service.js +24 -0
- package/dist/server/utils/response-store.js +138 -0
- package/dist/server/utils/responses-format.js +686 -0
- package/dist/server/utils/responses-stream.js +330 -0
- package/dist/server/utils/virtual-models.js +238 -0
- package/dist/server/validation.js +45 -2
- package/dist/swagger.js +137 -0
- package/package.json +34 -32
- package/src/__tests__/locale.test.ts +43 -0
- package/src/client/__tests__/settings-registration.test.tsx +1 -0
- package/src/client/index.tsx +10 -10
- package/src/client/models/index.ts +12 -12
- package/src/client/plugin.tsx +9 -1
- package/src/client-v2/__tests__/settings-registration.test.tsx +1 -0
- package/src/client-v2/pages/ModelMetadataPage.tsx +44 -0
- package/src/client-v2/pages/ModelPricingPage.tsx +15 -0
- package/src/client-v2/pages/ModelRoutingPage.tsx +238 -0
- package/src/client-v2/pages/UsageGroupsPage.tsx +75 -38
- package/src/client-v2/plugin.tsx +8 -0
- package/src/index.ts +11 -11
- package/src/locale/en-US.json +38 -1
- package/src/locale/vi-VN.json +177 -138
- package/src/locale/zh-CN.json +177 -138
- package/src/server/__tests__/billing-quota.test.ts +8 -2
- package/src/server/__tests__/billing.test.ts +13 -0
- package/src/server/__tests__/embeddings.test.ts +184 -0
- package/src/server/__tests__/models.test.ts +21 -1
- package/src/server/__tests__/response-record-resource.test.ts +50 -0
- package/src/server/__tests__/response-store-integration.test.ts +341 -0
- package/src/server/__tests__/response-store.test.ts +195 -0
- package/src/server/__tests__/responses-contract.test.ts +469 -0
- package/src/server/__tests__/responses-format.test.ts +299 -0
- package/src/server/__tests__/responses-router.test.ts +182 -0
- package/src/server/__tests__/responses-streaming.test.ts +368 -0
- package/src/server/__tests__/responses.test.ts +462 -0
- package/src/server/__tests__/role-permission.test.ts +139 -0
- package/src/server/__tests__/seed-role-permission.test.ts +88 -0
- package/src/server/__tests__/types/responses-sdk.types.test-d.ts +23 -0
- package/src/server/__tests__/usage-groups.test.ts +96 -0
- package/src/server/__tests__/usage-route.test.ts +1 -0
- package/src/server/__tests__/usage.test.ts +15 -0
- package/src/server/__tests__/validation.test.ts +66 -7
- package/src/server/__tests__/virtual-model-routing.test.ts +589 -0
- package/src/server/billing.ts +29 -6
- package/src/server/collections/ai-api-model-metadata.ts +26 -0
- package/src/server/collections/ai-api-model-prices.ts +8 -0
- package/src/server/collections/ai-api-response-records.ts +77 -0
- package/src/server/collections/ai-api-usage-records.ts +1 -0
- package/src/server/collections/ai-api-virtual-models.ts +58 -0
- package/src/server/middleware/response-record-resource.ts +44 -0
- package/src/server/middleware/role-permission.ts +69 -35
- package/src/server/migrations/20260827000000-add-cache-input-price.ts +49 -0
- package/src/server/migrations/20260901000000-remove-default-group-members.ts +56 -0
- package/src/server/migrations/20260902000000-seed-default-role-permissions.ts +46 -0
- package/src/server/migrations/20260903000000-seed-sample-response-records.ts +162 -0
- package/src/server/plugin.ts +84 -20
- package/src/server/resource/ai-api-config.ts +2 -1
- package/src/server/routes/agent-completions.ts +3 -0
- package/src/server/routes/auth.ts +21 -1
- package/src/server/routes/chat-completions.ts +34 -10
- package/src/server/routes/completions.ts +16 -4
- package/src/server/routes/embeddings.ts +42 -6
- package/src/server/routes/models.ts +34 -0
- package/src/server/routes/responses.ts +640 -0
- package/src/server/routes/router.ts +81 -12
- package/src/server/services/__tests__/file-processor.test.ts +1 -0
- package/src/server/usage.ts +30 -2
- package/src/server/utils/app-observability.ts +1 -1
- package/src/server/utils/direct-llm-context.ts +23 -12
- package/src/server/utils/openai-format.ts +1 -0
- package/src/server/utils/resolve-service.ts +39 -1
- package/src/server/utils/response-store.ts +148 -0
- package/src/server/utils/responses-format.ts +974 -0
- package/src/server/utils/responses-stream.ts +384 -0
- package/src/server/utils/virtual-models.ts +320 -0
- package/src/server/validation.ts +50 -0
- package/src/swagger.ts +139 -0
- package/dist/client/562.44b16aad4718b4c7.js +0 -10
- package/dist/client/685.ae483e17b6b49c98.js +0 -10
- package/dist/client/97.9b6b2d2b01a4c060.js +0 -10
- package/dist/client-v2/562.45d5c504433be38b.js +0 -10
- package/dist/client-v2/685.1030370b309b7d4b.js +0 -10
- package/dist/client-v2/97.36a42eff36bb3d8a.js +0 -10
- package/dist/server/collections/ai-api-user-permissions.js +0 -67
- package/dist/server/collections/ai-api-user-quota-buckets.js +0 -54
- package/dist/server/collections/ai-api-user-quota-policies.js +0 -63
- package/dist/server/resource/ai-api-usage-groups.js +0 -168
- package/src/server/collections/ai-api-user-permissions.ts +0 -46
- package/src/server/collections/ai-api-user-quota-buckets.ts +0 -24
- package/src/server/collections/ai-api-user-quota-policies.ts +0 -33
- package/src/server/resource/ai-api-usage-groups.ts +0 -171
|
@@ -91,6 +91,22 @@ async function authenticateBearer(ctx) {
|
|
|
91
91
|
ctx.body = (0, import_openai_format.toOpenAIError)(401, "Invalid or expired API key", "invalid_request_error", "invalid_api_key");
|
|
92
92
|
return false;
|
|
93
93
|
}
|
|
94
|
+
if (jwt.blacklist) {
|
|
95
|
+
let blocked = false;
|
|
96
|
+
try {
|
|
97
|
+
blocked = await jwt.blacklist.has(decoded.jti ?? token);
|
|
98
|
+
} catch (err) {
|
|
99
|
+
ctx.log.error("AI API token blacklist check failed:", err);
|
|
100
|
+
ctx.status = 401;
|
|
101
|
+
ctx.body = (0, import_openai_format.toOpenAIError)(401, "Unable to verify API key status", "server_error");
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
if (blocked) {
|
|
105
|
+
ctx.status = 401;
|
|
106
|
+
ctx.body = (0, import_openai_format.toOpenAIError)(401, "API key has been revoked", "invalid_request_error", "invalid_api_key");
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
94
110
|
if (!decoded.roleName) {
|
|
95
111
|
ctx.status = 401;
|
|
96
112
|
ctx.body = (0, import_openai_format.toOpenAIError)(
|
|
@@ -27,16 +27,21 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
27
27
|
var chat_completions_exports = {};
|
|
28
28
|
__export(chat_completions_exports, {
|
|
29
29
|
applyProviderRequestParameters: () => applyProviderRequestParameters,
|
|
30
|
+
bindRequestTools: () => bindRequestTools,
|
|
30
31
|
extractFinishReason: () => extractFinishReason,
|
|
31
32
|
findContentBlockProblem: () => findContentBlockProblem,
|
|
32
33
|
findMessageProblem: () => findMessageProblem,
|
|
33
34
|
getProviderRequestParameters: () => getProviderRequestParameters,
|
|
34
35
|
handleChatCompletions: () => handleChatCompletions,
|
|
35
|
-
normalizeMessageContent: () => normalizeMessageContent
|
|
36
|
+
normalizeMessageContent: () => normalizeMessageContent,
|
|
37
|
+
normalizeToolCallChunks: () => normalizeToolCallChunks,
|
|
38
|
+
normalizeToolCalls: () => normalizeToolCalls,
|
|
39
|
+
processMessageContentFileBlocks: () => processMessageContentFileBlocks
|
|
36
40
|
});
|
|
37
41
|
module.exports = __toCommonJS(chat_completions_exports);
|
|
38
42
|
var import_openai_format = require("../utils/openai-format");
|
|
39
43
|
var import_resolve_service = require("../utils/resolve-service");
|
|
44
|
+
var import_virtual_models = require("../utils/virtual-models");
|
|
40
45
|
var import_streaming = require("../utils/streaming");
|
|
41
46
|
var import_user_permissions = require("../utils/user-permissions");
|
|
42
47
|
var import_request_cache = require("../utils/request-cache");
|
|
@@ -91,7 +96,16 @@ async function handleChatCompletions(ctx, plugin) {
|
|
|
91
96
|
return;
|
|
92
97
|
}
|
|
93
98
|
const stream = (0, import_streaming.isStreamingRequested)(body.stream);
|
|
94
|
-
const
|
|
99
|
+
const virtual = await (0, import_virtual_models.resolveVirtualModel)(ctx, body.model, body, "chat");
|
|
100
|
+
if ((virtual == null ? void 0 : virtual.status) === "unavailable") {
|
|
101
|
+
(0, import_virtual_models.respondVirtualModelUnavailable)(ctx, virtual);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if ((virtual == null ? void 0 : virtual.status) === "resolved") {
|
|
105
|
+
ctx.state.aiApiVirtualModel = virtual.virtualModel;
|
|
106
|
+
ctx.state.aiApiRoutingReason = virtual.reason;
|
|
107
|
+
}
|
|
108
|
+
const resolved = (virtual == null ? void 0 : virtual.resolved) ?? await (0, import_resolve_service.resolveModelString)(ctx, body.model);
|
|
95
109
|
if (!resolved) {
|
|
96
110
|
ctx.status = 404;
|
|
97
111
|
ctx.body = (0, import_openai_format.toOpenAIError)(
|
|
@@ -199,7 +213,7 @@ async function handleChatCompletions(ctx, plugin) {
|
|
|
199
213
|
chatModel,
|
|
200
214
|
langchainMessages,
|
|
201
215
|
completionId,
|
|
202
|
-
|
|
216
|
+
`${service.name}/${modelId}`,
|
|
203
217
|
providerRequestParameters
|
|
204
218
|
);
|
|
205
219
|
} else {
|
|
@@ -208,7 +222,7 @@ async function handleChatCompletions(ctx, plugin) {
|
|
|
208
222
|
chatModel,
|
|
209
223
|
langchainMessages,
|
|
210
224
|
completionId,
|
|
211
|
-
|
|
225
|
+
`${service.name}/${modelId}`,
|
|
212
226
|
providerRequestParameters
|
|
213
227
|
);
|
|
214
228
|
}
|
|
@@ -570,7 +584,21 @@ async function processFileBlockChain(block, ctx, plugin, depth) {
|
|
|
570
584
|
}
|
|
571
585
|
return next;
|
|
572
586
|
}
|
|
573
|
-
const GATEWAY_MANAGED_PARAMETERS = /* @__PURE__ */ new Set([
|
|
587
|
+
const GATEWAY_MANAGED_PARAMETERS = /* @__PURE__ */ new Set([
|
|
588
|
+
"model",
|
|
589
|
+
"messages",
|
|
590
|
+
"prompt",
|
|
591
|
+
"tools",
|
|
592
|
+
"tool_choice",
|
|
593
|
+
"stream",
|
|
594
|
+
"n",
|
|
595
|
+
// Responses API specific fields that should not be passed to providers
|
|
596
|
+
"input",
|
|
597
|
+
"previous_response_id",
|
|
598
|
+
"store",
|
|
599
|
+
"truncation",
|
|
600
|
+
"metadata"
|
|
601
|
+
]);
|
|
574
602
|
function getProviderRequestParameters(body) {
|
|
575
603
|
return Object.fromEntries(
|
|
576
604
|
Object.entries(body).filter(([name, value]) => !GATEWAY_MANAGED_PARAMETERS.has(name) && value !== void 0)
|
|
@@ -640,10 +668,14 @@ function serializeToolArguments(value) {
|
|
|
640
668
|
// Annotate the CommonJS export names for ESM import in node:
|
|
641
669
|
0 && (module.exports = {
|
|
642
670
|
applyProviderRequestParameters,
|
|
671
|
+
bindRequestTools,
|
|
643
672
|
extractFinishReason,
|
|
644
673
|
findContentBlockProblem,
|
|
645
674
|
findMessageProblem,
|
|
646
675
|
getProviderRequestParameters,
|
|
647
676
|
handleChatCompletions,
|
|
648
|
-
normalizeMessageContent
|
|
677
|
+
normalizeMessageContent,
|
|
678
|
+
normalizeToolCallChunks,
|
|
679
|
+
normalizeToolCalls,
|
|
680
|
+
processMessageContentFileBlocks
|
|
649
681
|
});
|
|
@@ -31,6 +31,7 @@ __export(completions_exports, {
|
|
|
31
31
|
module.exports = __toCommonJS(completions_exports);
|
|
32
32
|
var import_openai_format = require("../utils/openai-format");
|
|
33
33
|
var import_resolve_service = require("../utils/resolve-service");
|
|
34
|
+
var import_virtual_models = require("../utils/virtual-models");
|
|
34
35
|
var import_user_permissions = require("../utils/user-permissions");
|
|
35
36
|
var import_streaming = require("../utils/streaming");
|
|
36
37
|
var import_chat_completions = require("./chat-completions");
|
|
@@ -63,7 +64,16 @@ async function handleCompletions(ctx, plugin) {
|
|
|
63
64
|
return;
|
|
64
65
|
}
|
|
65
66
|
const stream = (0, import_streaming.isStreamingRequested)(body.stream);
|
|
66
|
-
const
|
|
67
|
+
const virtual = await (0, import_virtual_models.resolveVirtualModel)(ctx, body.model, body, "chat");
|
|
68
|
+
if ((virtual == null ? void 0 : virtual.status) === "unavailable") {
|
|
69
|
+
(0, import_virtual_models.respondVirtualModelUnavailable)(ctx, virtual);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if ((virtual == null ? void 0 : virtual.status) === "resolved") {
|
|
73
|
+
ctx.state.aiApiVirtualModel = virtual.virtualModel;
|
|
74
|
+
ctx.state.aiApiRoutingReason = virtual.reason;
|
|
75
|
+
}
|
|
76
|
+
const resolved = (virtual == null ? void 0 : virtual.resolved) ?? await (0, import_resolve_service.resolveModelString)(ctx, body.model);
|
|
67
77
|
if (!resolved) {
|
|
68
78
|
ctx.status = 404;
|
|
69
79
|
ctx.body = (0, import_openai_format.toOpenAIError)(
|
|
@@ -108,7 +118,8 @@ async function handleCompletions(ctx, plugin) {
|
|
|
108
118
|
};
|
|
109
119
|
if (body.temperature !== void 0) modelOptions.temperature = body.temperature;
|
|
110
120
|
if (body.top_p !== void 0) modelOptions.topP = body.top_p;
|
|
111
|
-
if (body.
|
|
121
|
+
if (body.max_completion_tokens !== void 0) modelOptions.maxTokens = body.max_completion_tokens;
|
|
122
|
+
else if (body.max_tokens !== void 0) modelOptions.maxTokens = body.max_tokens;
|
|
112
123
|
if (body.stop !== void 0) modelOptions.stop = body.stop;
|
|
113
124
|
const prompt = typeof body.prompt === "string" ? body.prompt : Array.isArray(body.prompt) ? body.prompt.join("\n") : String(body.prompt);
|
|
114
125
|
const messages = [{ role: "user", content: prompt }];
|
|
@@ -116,6 +127,7 @@ async function handleCompletions(ctx, plugin) {
|
|
|
116
127
|
serviceName: service.name,
|
|
117
128
|
modelId,
|
|
118
129
|
messages,
|
|
130
|
+
maxCompletionTokens: body.max_completion_tokens,
|
|
119
131
|
maxTokens: body.max_tokens
|
|
120
132
|
});
|
|
121
133
|
await (0, import_billing.prepareLlmBilling)(ctx, resolved);
|
|
@@ -140,7 +152,7 @@ async function handleCompletions(ctx, plugin) {
|
|
|
140
152
|
chatModel,
|
|
141
153
|
langchainMessages,
|
|
142
154
|
completionId,
|
|
143
|
-
|
|
155
|
+
`${service.name}/${modelId}`,
|
|
144
156
|
body.stream_options,
|
|
145
157
|
providerRequestParameters
|
|
146
158
|
);
|
|
@@ -150,7 +162,7 @@ async function handleCompletions(ctx, plugin) {
|
|
|
150
162
|
chatModel,
|
|
151
163
|
langchainMessages,
|
|
152
164
|
completionId,
|
|
153
|
-
|
|
165
|
+
`${service.name}/${modelId}`,
|
|
154
166
|
providerRequestParameters
|
|
155
167
|
);
|
|
156
168
|
}
|
|
@@ -31,9 +31,11 @@ __export(embeddings_exports, {
|
|
|
31
31
|
module.exports = __toCommonJS(embeddings_exports);
|
|
32
32
|
var import_openai_format = require("../utils/openai-format");
|
|
33
33
|
var import_resolve_service = require("../utils/resolve-service");
|
|
34
|
+
var import_virtual_models = require("../utils/virtual-models");
|
|
34
35
|
var import_user_permissions = require("../utils/user-permissions");
|
|
35
36
|
var import_request_cache = require("../utils/request-cache");
|
|
36
37
|
var import_usage = require("../usage");
|
|
38
|
+
var import_billing = require("../billing");
|
|
37
39
|
async function handleEmbeddings(ctx, plugin) {
|
|
38
40
|
const body = ctx.request.body;
|
|
39
41
|
if (!(body == null ? void 0 : body.model)) {
|
|
@@ -81,7 +83,16 @@ async function handleEmbeddings(ctx, plugin) {
|
|
|
81
83
|
ctx.body = (0, import_openai_format.toOpenAIError)(400, "'input' must be a string or array of strings", "invalid_request_error");
|
|
82
84
|
return;
|
|
83
85
|
}
|
|
84
|
-
const
|
|
86
|
+
const virtual = await (0, import_virtual_models.resolveVirtualModel)(ctx, body.model, body, "embedding");
|
|
87
|
+
if ((virtual == null ? void 0 : virtual.status) === "unavailable") {
|
|
88
|
+
(0, import_virtual_models.respondVirtualModelUnavailable)(ctx, virtual);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if ((virtual == null ? void 0 : virtual.status) === "resolved") {
|
|
92
|
+
ctx.state.aiApiVirtualModel = virtual.virtualModel;
|
|
93
|
+
ctx.state.aiApiRoutingReason = virtual.reason;
|
|
94
|
+
}
|
|
95
|
+
const resolved = (virtual == null ? void 0 : virtual.resolved) ?? await (0, import_resolve_service.resolveModelString)(ctx, body.model);
|
|
85
96
|
if (!resolved) {
|
|
86
97
|
ctx.status = 404;
|
|
87
98
|
ctx.body = (0, import_openai_format.toOpenAIError)(
|
|
@@ -135,6 +146,7 @@ async function handleEmbeddings(ctx, plugin) {
|
|
|
135
146
|
return;
|
|
136
147
|
}
|
|
137
148
|
try {
|
|
149
|
+
await (0, import_billing.prepareLlmBilling)(ctx, resolved);
|
|
138
150
|
const EmbeddingClass = providerMeta.embedding;
|
|
139
151
|
const embeddingProvider = new EmbeddingClass({
|
|
140
152
|
app: ctx.app,
|
|
@@ -144,12 +156,19 @@ async function handleEmbeddings(ctx, plugin) {
|
|
|
144
156
|
// The specific embedding model
|
|
145
157
|
});
|
|
146
158
|
const embeddingModel = embeddingProvider.createEmbedding();
|
|
159
|
+
(0, import_billing.markLlmProviderAttempted)(ctx);
|
|
147
160
|
const vectors = await embeddingModel.embedDocuments(inputs);
|
|
161
|
+
const estimatedInputTokens = Math.ceil(inputs.reduce((sum, s) => sum + s.length, 0) / 4);
|
|
162
|
+
const usage = {
|
|
163
|
+
prompt_tokens: estimatedInputTokens,
|
|
164
|
+
completion_tokens: 0,
|
|
165
|
+
total_tokens: estimatedInputTokens
|
|
166
|
+
};
|
|
167
|
+
(0, import_usage.setAiApiUsageResult)(ctx, usage);
|
|
148
168
|
ctx.status = 200;
|
|
149
169
|
ctx.set("Content-Type", "application/json");
|
|
150
|
-
(0, import_usage.setAiApiUsageUnavailable)(ctx);
|
|
151
170
|
ctx.body = (0, import_openai_format.toOpenAIEmbeddingsResponse)({
|
|
152
|
-
model:
|
|
171
|
+
model: `${service.name}/${modelId}`,
|
|
153
172
|
embeddings: vectors,
|
|
154
173
|
// LangChain's EmbeddingsInterface does not expose token counts.
|
|
155
174
|
promptTokens: null
|
|
@@ -157,11 +176,21 @@ async function handleEmbeddings(ctx, plugin) {
|
|
|
157
176
|
} catch (err) {
|
|
158
177
|
ctx.log.error("AI API embeddings error:", err);
|
|
159
178
|
if (!ctx.res.headersSent) {
|
|
160
|
-
|
|
161
|
-
ctx.
|
|
179
|
+
const isQuotaError = err instanceof import_billing.AiApiQuotaError;
|
|
180
|
+
ctx.status = isQuotaError ? 429 : 500;
|
|
181
|
+
if (isQuotaError) ctx.set("X-RateLimit-Reason", err.code);
|
|
182
|
+
ctx.body = (0, import_openai_format.toOpenAIError)(
|
|
183
|
+
ctx.status,
|
|
184
|
+
getErrorMessage(err, "Failed to generate embeddings"),
|
|
185
|
+
isQuotaError ? "quota_error" : "server_error",
|
|
186
|
+
isQuotaError ? err.code : void 0
|
|
187
|
+
);
|
|
162
188
|
}
|
|
163
189
|
}
|
|
164
190
|
}
|
|
191
|
+
function getErrorMessage(error, fallback) {
|
|
192
|
+
return error instanceof Error && error.message ? error.message : fallback;
|
|
193
|
+
}
|
|
165
194
|
// Annotate the CommonJS export names for ESM import in node:
|
|
166
195
|
0 && (module.exports = {
|
|
167
196
|
handleEmbeddings
|
|
@@ -27,6 +27,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
27
27
|
var models_exports = {};
|
|
28
28
|
__export(models_exports, {
|
|
29
29
|
buildModelObject: () => buildModelObject,
|
|
30
|
+
buildVirtualModelObject: () => buildVirtualModelObject,
|
|
30
31
|
handleGetModel: () => handleGetModel,
|
|
31
32
|
handleListModels: () => handleListModels
|
|
32
33
|
});
|
|
@@ -34,6 +35,7 @@ module.exports = __toCommonJS(models_exports);
|
|
|
34
35
|
var import_openai_format = require("../utils/openai-format");
|
|
35
36
|
var import_user_permissions = require("../utils/user-permissions");
|
|
36
37
|
var import_request_cache = require("../utils/request-cache");
|
|
38
|
+
var import_virtual_models = require("../utils/virtual-models");
|
|
37
39
|
async function handleListModels(ctx, plugin) {
|
|
38
40
|
var _a;
|
|
39
41
|
try {
|
|
@@ -73,6 +75,13 @@ async function handleListModels(ctx, plugin) {
|
|
|
73
75
|
models.push(buildModelObject(fullId, now, serviceLabel, meta));
|
|
74
76
|
}
|
|
75
77
|
}
|
|
78
|
+
try {
|
|
79
|
+
const virtualModels = await (0, import_virtual_models.listAccessibleVirtualModels)(ctx, scope, config == null ? void 0 : config.enabledLlmServices);
|
|
80
|
+
for (const virtualModel of virtualModels) {
|
|
81
|
+
models.push(buildVirtualModelObject(virtualModel, now));
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
76
85
|
ctx.status = 200;
|
|
77
86
|
ctx.body = {
|
|
78
87
|
object: "list",
|
|
@@ -121,6 +130,14 @@ async function handleGetModel(ctx, modelId, plugin) {
|
|
|
121
130
|
}
|
|
122
131
|
if (found) break;
|
|
123
132
|
}
|
|
133
|
+
if (!found) {
|
|
134
|
+
try {
|
|
135
|
+
const virtualModels = await (0, import_virtual_models.listAccessibleVirtualModels)(ctx, scope, config == null ? void 0 : config.enabledLlmServices);
|
|
136
|
+
const virtualModel = virtualModels.find((candidate) => candidate.name === modelId);
|
|
137
|
+
if (virtualModel) found = buildVirtualModelObject(virtualModel, now);
|
|
138
|
+
} catch {
|
|
139
|
+
}
|
|
140
|
+
}
|
|
124
141
|
if (!found) {
|
|
125
142
|
ctx.status = 404;
|
|
126
143
|
ctx.body = (0, import_openai_format.toOpenAIError)(404, `Model '${modelId}' not found`, "invalid_request_error", "model_not_found");
|
|
@@ -194,6 +211,17 @@ function buildModelObject(fullId, created, serviceLabel, meta) {
|
|
|
194
211
|
}
|
|
195
212
|
return model;
|
|
196
213
|
}
|
|
214
|
+
function buildVirtualModelObject(virtualModel, created) {
|
|
215
|
+
return {
|
|
216
|
+
id: virtualModel.name,
|
|
217
|
+
object: "model",
|
|
218
|
+
created,
|
|
219
|
+
owned_by: "ai-api-gateway",
|
|
220
|
+
virtual: true,
|
|
221
|
+
mode: virtualModel.mode,
|
|
222
|
+
description: `Virtual ${virtualModel.mode} alias routed to a concrete model based on the request shape.`
|
|
223
|
+
};
|
|
224
|
+
}
|
|
197
225
|
function toPositiveInt(value) {
|
|
198
226
|
const n = Number(value);
|
|
199
227
|
return Number.isSafeInteger(n) && n > 0 ? n : null;
|
|
@@ -235,6 +263,7 @@ function getRecommendedModelsForProvider(provider) {
|
|
|
235
263
|
// Annotate the CommonJS export names for ESM import in node:
|
|
236
264
|
0 && (module.exports = {
|
|
237
265
|
buildModelObject,
|
|
266
|
+
buildVirtualModelObject,
|
|
238
267
|
handleGetModel,
|
|
239
268
|
handleListModels
|
|
240
269
|
});
|