@nick3/copilot-api 1.2.4 → 1.3.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.
- package/README.md +218 -22
- package/dist/{accounts-manager-eec8Wj3_.js → accounts-manager-BeKvbv0T.js} +109 -8
- package/dist/accounts-manager-BeKvbv0T.js.map +1 -0
- package/dist/main.js +13 -9
- package/dist/main.js.map +1 -1
- package/dist/{server-Cxlbm6kJ.js → server-D3A61KAx.js} +314 -95
- package/dist/server-D3A61KAx.js.map +1 -0
- package/package.json +1 -1
- package/dist/accounts-manager-eec8Wj3_.js.map +0 -1
- package/dist/server-Cxlbm6kJ.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HTTPError, PATHS, accountFromState, accountsManager, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getAliasTargetSet, getConfig, getCopilotUsage, getExtraPromptForModel, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getReasoningEffortForModel, getRootSessionId, getSmallModel, getUUID, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isNullish, isResponsesApiContextManagementModel, listAccountsFromRegistry, mergeConfigWithDefaults, shouldCompactUseSmallModel, sleep, state } from "./accounts-manager-
|
|
1
|
+
import { HTTPError, PATHS, accountFromState, accountsManager, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getAliasTargetSet, getConfig, getCopilotUsage, getExtraPromptForModel, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getProviderConfig, getReasoningEffortForModel, getRootSessionId, getSmallModel, getUUID, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isNullish, isResponsesApiContextManagementModel, listAccountsFromRegistry, mergeConfigWithDefaults, prepareInteractionHeaders, shouldCompactUseSmallModel, sleep, state } from "./accounts-manager-BeKvbv0T.js";
|
|
2
2
|
import consola from "consola";
|
|
3
3
|
import fs, { readFile } from "node:fs/promises";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -2234,11 +2234,7 @@ const createResponses = async (payload, { vision, initiator, upstreamRequestId,
|
|
|
2234
2234
|
...copilotHeaders(ctx, vision, upstreamRequestId),
|
|
2235
2235
|
"x-initiator": initiator
|
|
2236
2236
|
};
|
|
2237
|
-
|
|
2238
|
-
headers["x-initiator"] = "agent";
|
|
2239
|
-
headers["x-interaction-type"] = "conversation-subagent";
|
|
2240
|
-
}
|
|
2241
|
-
if (sessionId) headers["x-interaction-id"] = sessionId;
|
|
2237
|
+
prepareInteractionHeaders(sessionId, Boolean(subagentMarker), headers);
|
|
2242
2238
|
payload.service_tier = null;
|
|
2243
2239
|
const response = await fetch(`${copilotBaseUrl(ctx)}/responses`, {
|
|
2244
2240
|
method: "POST",
|
|
@@ -2718,8 +2714,7 @@ const createChatCompletions = async (payload, account, options) => {
|
|
|
2718
2714
|
...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
|
|
2719
2715
|
"x-initiator": options?.subagentMarker ? "agent" : initiator
|
|
2720
2716
|
};
|
|
2721
|
-
|
|
2722
|
-
if (options?.sessionId) headers["x-interaction-id"] = options.sessionId;
|
|
2717
|
+
prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
|
|
2723
2718
|
const upstreamPayload = applyDefaultReasoningEffort(payload);
|
|
2724
2719
|
const response = await fetch(`${copilotBaseUrl(ctx)}/chat/completions`, {
|
|
2725
2720
|
method: "POST",
|
|
@@ -2736,7 +2731,7 @@ const createChatCompletions = async (payload, account, options) => {
|
|
|
2736
2731
|
|
|
2737
2732
|
//#endregion
|
|
2738
2733
|
//#region src/routes/chat-completions/handler.ts
|
|
2739
|
-
const logger$
|
|
2734
|
+
const logger$6 = createHandlerLogger("chat-completions-handler");
|
|
2740
2735
|
const CHAT_COMPLETIONS_ENDPOINT$1 = "/chat/completions";
|
|
2741
2736
|
async function handleCompletion$1(c) {
|
|
2742
2737
|
await checkRateLimit(state);
|
|
@@ -2766,7 +2761,7 @@ async function handleCompletion$1(c) {
|
|
|
2766
2761
|
reason: "MODEL_NOT_SUPPORTED"
|
|
2767
2762
|
});
|
|
2768
2763
|
}
|
|
2769
|
-
logger$
|
|
2764
|
+
logger$6.debug("Request payload:", JSON.stringify(payload).slice(-400));
|
|
2770
2765
|
const selection = await accountsManager.selectAccountForRequest([{
|
|
2771
2766
|
modelId: clientModel,
|
|
2772
2767
|
endpoint: CHAT_COMPLETIONS_ENDPOINT$1
|
|
@@ -2885,9 +2880,9 @@ function selectionFailureResponse$2(c, params) {
|
|
|
2885
2880
|
async function logTokenCountForRequest(params) {
|
|
2886
2881
|
try {
|
|
2887
2882
|
const tokenCount = await getTokenCount(params.payload, params.selectedModel);
|
|
2888
|
-
logger$
|
|
2883
|
+
logger$6.info("Current token count:", tokenCount);
|
|
2889
2884
|
} catch (error) {
|
|
2890
|
-
logger$
|
|
2885
|
+
logger$6.warn("Failed to calculate token count:", error);
|
|
2891
2886
|
}
|
|
2892
2887
|
}
|
|
2893
2888
|
function applyDefaultMaxTokens(payload, selectedModel) {
|
|
@@ -2896,7 +2891,7 @@ function applyDefaultMaxTokens(payload, selectedModel) {
|
|
|
2896
2891
|
...payload,
|
|
2897
2892
|
max_tokens: selectedModel.capabilities.limits.max_output_tokens
|
|
2898
2893
|
};
|
|
2899
|
-
logger$
|
|
2894
|
+
logger$6.debug("Set max_tokens to:", JSON.stringify(updated.max_tokens));
|
|
2900
2895
|
return updated;
|
|
2901
2896
|
}
|
|
2902
2897
|
async function handleStreamingRequest(params) {
|
|
@@ -2928,7 +2923,7 @@ async function handleStreamingRequest(params) {
|
|
|
2928
2923
|
premiumUnlimitedBefore,
|
|
2929
2924
|
response
|
|
2930
2925
|
});
|
|
2931
|
-
logger$
|
|
2926
|
+
logger$6.debug("Streaming response");
|
|
2932
2927
|
return streamSSE(c, (stream) => streamChatCompletionsAndLog$1({
|
|
2933
2928
|
stream,
|
|
2934
2929
|
response,
|
|
@@ -2981,7 +2976,7 @@ async function handleNonStreamingUpstreamResponse(params) {
|
|
|
2981
2976
|
let errorMessage;
|
|
2982
2977
|
const finishedAtMs = Date.now();
|
|
2983
2978
|
try {
|
|
2984
|
-
logger$
|
|
2979
|
+
logger$6.debug("Non-streaming response:", JSON.stringify(response));
|
|
2985
2980
|
return c.json(response);
|
|
2986
2981
|
} catch (error) {
|
|
2987
2982
|
const details = extractErrorDetails(error);
|
|
@@ -3031,7 +3026,7 @@ async function streamChatCompletionsAndLog$1(params) {
|
|
|
3031
3026
|
if (ttfbMs === void 0) ttfbMs = Date.now() - request.startedAtMs;
|
|
3032
3027
|
const usage = await extractUsageFromChunk(chunk);
|
|
3033
3028
|
if (usage) lastUsage = usage;
|
|
3034
|
-
logger$
|
|
3029
|
+
logger$6.debug("Streaming chunk:", JSON.stringify(chunk));
|
|
3035
3030
|
await stream.writeSSE(chunk);
|
|
3036
3031
|
}
|
|
3037
3032
|
} catch (error) {
|
|
@@ -3039,7 +3034,7 @@ async function streamChatCompletionsAndLog$1(params) {
|
|
|
3039
3034
|
errorName = details.errorName;
|
|
3040
3035
|
errorStatus = details.errorStatus;
|
|
3041
3036
|
errorMessage = details.errorMessage;
|
|
3042
|
-
logger$
|
|
3037
|
+
logger$6.warn("Streaming error:", error);
|
|
3043
3038
|
} finally {
|
|
3044
3039
|
const finishedAtMs = Date.now();
|
|
3045
3040
|
await accountsManager.finalizeQuota(account, reservation);
|
|
@@ -3096,13 +3091,13 @@ async function handleNonStreamingRequest(params) {
|
|
|
3096
3091
|
});
|
|
3097
3092
|
finishedAtMs = Date.now();
|
|
3098
3093
|
if (!isNonStreaming$1(response)) {
|
|
3099
|
-
logger$
|
|
3094
|
+
logger$6.debug("Unexpected streaming response");
|
|
3100
3095
|
return streamSSE(c, async (stream) => {
|
|
3101
3096
|
for await (const chunk of response) await stream.writeSSE(chunk);
|
|
3102
3097
|
});
|
|
3103
3098
|
}
|
|
3104
3099
|
usage = normalizeChatCompletionsUsage(response.usage);
|
|
3105
|
-
logger$
|
|
3100
|
+
logger$6.debug("Non-streaming response:", JSON.stringify(response));
|
|
3106
3101
|
return c.json(response);
|
|
3107
3102
|
} catch (error) {
|
|
3108
3103
|
finishedAtMs = Date.now();
|
|
@@ -3319,6 +3314,57 @@ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, s
|
|
|
3319
3314
|
}
|
|
3320
3315
|
}
|
|
3321
3316
|
|
|
3317
|
+
//#endregion
|
|
3318
|
+
//#region src/lib/models.ts
|
|
3319
|
+
const findEndpointModel = (sdkModelId) => {
|
|
3320
|
+
const models = state.models?.data ?? [];
|
|
3321
|
+
const exactMatch = models.find((m) => m.id === sdkModelId);
|
|
3322
|
+
if (exactMatch) return exactMatch;
|
|
3323
|
+
const normalized = _normalizeSdkModelId(sdkModelId);
|
|
3324
|
+
if (!normalized) return;
|
|
3325
|
+
const modelName = `claude-${normalized.family}-${normalized.version}`;
|
|
3326
|
+
const model = models.find((m) => m.id === modelName);
|
|
3327
|
+
if (model) return model;
|
|
3328
|
+
};
|
|
3329
|
+
/**
|
|
3330
|
+
* Normalizes an SDK model ID to extract the model family and version.
|
|
3331
|
+
* this method from github copilot extension
|
|
3332
|
+
* Examples:
|
|
3333
|
+
* - "claude-opus-4-5-20251101" -> { family: "opus", version: "4.5" }
|
|
3334
|
+
* - "claude-3-5-sonnet-20241022" -> { family: "sonnet", version: "3.5" }
|
|
3335
|
+
* - "claude-sonnet-4-20250514" -> { family: "sonnet", version: "4" }
|
|
3336
|
+
* - "claude-haiku-3-5-20250514" -> { family: "haiku", version: "3.5" }
|
|
3337
|
+
* - "claude-haiku-4.5" -> { family: "haiku", version: "4.5" }
|
|
3338
|
+
*/
|
|
3339
|
+
const _normalizeSdkModelId = (sdkModelId) => {
|
|
3340
|
+
const withoutDate = sdkModelId.toLowerCase().replace(/-\d{8}$/, "");
|
|
3341
|
+
const pattern1 = withoutDate.match(/^claude-(\w+)-(\d+)-(\d+)$/);
|
|
3342
|
+
if (pattern1) return {
|
|
3343
|
+
family: pattern1[1],
|
|
3344
|
+
version: `${pattern1[2]}.${pattern1[3]}`
|
|
3345
|
+
};
|
|
3346
|
+
const pattern2 = withoutDate.match(/^claude-(\d+)-(\d+)-(\w+)$/);
|
|
3347
|
+
if (pattern2) return {
|
|
3348
|
+
family: pattern2[3],
|
|
3349
|
+
version: `${pattern2[1]}.${pattern2[2]}`
|
|
3350
|
+
};
|
|
3351
|
+
const pattern3 = withoutDate.match(/^claude-(\w+)-(\d+)\.(\d+)$/);
|
|
3352
|
+
if (pattern3) return {
|
|
3353
|
+
family: pattern3[1],
|
|
3354
|
+
version: `${pattern3[2]}.${pattern3[3]}`
|
|
3355
|
+
};
|
|
3356
|
+
const pattern4 = withoutDate.match(/^claude-(\w+)-(\d+)$/);
|
|
3357
|
+
if (pattern4) return {
|
|
3358
|
+
family: pattern4[1],
|
|
3359
|
+
version: pattern4[2]
|
|
3360
|
+
};
|
|
3361
|
+
const pattern5 = withoutDate.match(/^claude-(\d+)-(\w+)$/);
|
|
3362
|
+
if (pattern5) return {
|
|
3363
|
+
family: pattern5[2],
|
|
3364
|
+
version: pattern5[1]
|
|
3365
|
+
};
|
|
3366
|
+
};
|
|
3367
|
+
|
|
3322
3368
|
//#endregion
|
|
3323
3369
|
//#region src/routes/messages/utils.ts
|
|
3324
3370
|
function mapOpenAIStopReasonToAnthropic(finishReason) {
|
|
@@ -3374,11 +3420,11 @@ const mergeToolResultForClaude = (anthropicPayload) => {
|
|
|
3374
3420
|
msg.content = mergeToolResult(toolResults, textBlocks);
|
|
3375
3421
|
}
|
|
3376
3422
|
};
|
|
3377
|
-
const estimateInputTokens = async (payload, selectedModel, logger$
|
|
3423
|
+
const estimateInputTokens = async (payload, selectedModel, logger$7) => {
|
|
3378
3424
|
try {
|
|
3379
3425
|
return (await getTokenCount(payload, selectedModel)).input;
|
|
3380
3426
|
} catch (error) {
|
|
3381
|
-
logger$
|
|
3427
|
+
logger$7.warn("Failed to estimate input tokens for message_start", error);
|
|
3382
3428
|
return;
|
|
3383
3429
|
}
|
|
3384
3430
|
};
|
|
@@ -3443,7 +3489,7 @@ const maybeBlockOriginalModelName = (context) => {
|
|
|
3443
3489
|
//#region src/routes/messages/non-stream-translation.ts
|
|
3444
3490
|
const THINKING_TEXT = "Thinking...";
|
|
3445
3491
|
function translateToOpenAI(payload) {
|
|
3446
|
-
const modelId =
|
|
3492
|
+
const modelId = payload.model;
|
|
3447
3493
|
const model = state.models?.data.find((m) => m.id === modelId);
|
|
3448
3494
|
const thinkingBudget = getThinkingBudget(payload, model);
|
|
3449
3495
|
return {
|
|
@@ -3464,56 +3510,27 @@ function getThinkingBudget(payload, model) {
|
|
|
3464
3510
|
const thinking = payload.thinking;
|
|
3465
3511
|
if (model && thinking) {
|
|
3466
3512
|
const maxThinkingBudget = Math.min(model.capabilities.supports.max_thinking_budget ?? 0, (model.capabilities.limits.max_output_tokens ?? 0) - 1);
|
|
3467
|
-
|
|
3513
|
+
thinking.budget_tokens ??= maxThinkingBudget;
|
|
3514
|
+
if (maxThinkingBudget > 0) {
|
|
3468
3515
|
const budgetTokens = Math.min(thinking.budget_tokens, maxThinkingBudget);
|
|
3469
3516
|
return Math.max(budgetTokens, model.capabilities.supports.min_thinking_budget ?? 1024);
|
|
3470
3517
|
}
|
|
3471
3518
|
}
|
|
3472
3519
|
}
|
|
3473
|
-
function
|
|
3474
|
-
|
|
3475
|
-
else if (model.startsWith("claude-opus-4-")) return model.replace(/^claude-opus-4-.*/, "claude-opus-4");
|
|
3476
|
-
return model;
|
|
3477
|
-
}
|
|
3478
|
-
function translateAnthropicMessagesToOpenAI(payload, modelId, thinkingBudget) {
|
|
3479
|
-
const systemMessages = handleSystemPrompt(payload.system, modelId, thinkingBudget);
|
|
3520
|
+
function translateAnthropicMessagesToOpenAI(payload, modelId, _thinkingBudget) {
|
|
3521
|
+
const systemMessages = handleSystemPrompt(payload.system);
|
|
3480
3522
|
const otherMessages = payload.messages.flatMap((message) => message.role === "user" ? handleUserMessage(message) : handleAssistantMessage(message, modelId));
|
|
3481
|
-
if (modelId.startsWith("claude") && thinkingBudget) {
|
|
3482
|
-
const reminder = "<system-reminder>you MUST follow interleaved_thinking_protocol</system-reminder>";
|
|
3483
|
-
const firstUserIndex = otherMessages.findIndex((m) => m.role === "user");
|
|
3484
|
-
if (firstUserIndex !== -1) {
|
|
3485
|
-
const userMessage = otherMessages[firstUserIndex];
|
|
3486
|
-
if (typeof userMessage.content === "string") userMessage.content = reminder + "\n\n" + userMessage.content;
|
|
3487
|
-
else if (Array.isArray(userMessage.content)) userMessage.content = [{
|
|
3488
|
-
type: "text",
|
|
3489
|
-
text: reminder
|
|
3490
|
-
}, ...userMessage.content];
|
|
3491
|
-
}
|
|
3492
|
-
}
|
|
3493
3523
|
return [...systemMessages, ...otherMessages];
|
|
3494
3524
|
}
|
|
3495
|
-
function handleSystemPrompt(system
|
|
3525
|
+
function handleSystemPrompt(system) {
|
|
3496
3526
|
if (!system) return [];
|
|
3497
|
-
let extraPrompt = "";
|
|
3498
|
-
if (modelId.startsWith("claude") && thinkingBudget) extraPrompt = `
|
|
3499
|
-
<interleaved_thinking_protocol>
|
|
3500
|
-
ABSOLUTE REQUIREMENT - NON-NEGOTIABLE:
|
|
3501
|
-
The current thinking_mode is interleaved, Whenever you have the result of a function call, think carefully , MUST output a thinking block
|
|
3502
|
-
RULES:
|
|
3503
|
-
Tool result → thinking block (ALWAYS, no exceptions)
|
|
3504
|
-
This is NOT optional - it is a hard requirement
|
|
3505
|
-
The thinking block must contain substantive reasoning (minimum 3-5 sentences)
|
|
3506
|
-
Think about: what the results mean, what to do next, how to answer the user
|
|
3507
|
-
NEVER skip this step, even if the result seems simple or obvious
|
|
3508
|
-
</interleaved_thinking_protocol>`;
|
|
3509
3527
|
if (typeof system === "string") return [{
|
|
3510
3528
|
role: "system",
|
|
3511
|
-
content: system
|
|
3529
|
+
content: system
|
|
3512
3530
|
}];
|
|
3513
3531
|
else return [{
|
|
3514
3532
|
role: "system",
|
|
3515
|
-
content: system.map((block
|
|
3516
|
-
if (index === 0) return block.text + extraPrompt;
|
|
3533
|
+
content: system.map((block) => {
|
|
3517
3534
|
return block.text;
|
|
3518
3535
|
}).join("\n\n")
|
|
3519
3536
|
}];
|
|
@@ -3685,7 +3702,8 @@ async function handleCountTokens(c) {
|
|
|
3685
3702
|
const anthropicBeta = c.req.header("anthropic-beta");
|
|
3686
3703
|
const anthropicPayload = await c.req.json();
|
|
3687
3704
|
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
3688
|
-
const selectedModel =
|
|
3705
|
+
const selectedModel = findEndpointModel(anthropicPayload.model);
|
|
3706
|
+
anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
|
|
3689
3707
|
if (!selectedModel) {
|
|
3690
3708
|
consola.warn("Model not found, returning default token count");
|
|
3691
3709
|
return c.json({ input_tokens: 1 });
|
|
@@ -4246,8 +4264,7 @@ const createMessages = async (payload, account, options) => {
|
|
|
4246
4264
|
...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
|
|
4247
4265
|
"x-initiator": options?.subagentMarker ? "agent" : initiator
|
|
4248
4266
|
};
|
|
4249
|
-
|
|
4250
|
-
if (options?.sessionId) headers["x-interaction-id"] = options.sessionId;
|
|
4267
|
+
prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
|
|
4251
4268
|
const anthropicBeta = buildAnthropicBetaHeader(options?.anthropicBetaHeader, payload.thinking);
|
|
4252
4269
|
if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
|
|
4253
4270
|
const response = await fetch(`${copilotBaseUrl(ctx)}/v1/messages`, {
|
|
@@ -4567,7 +4584,7 @@ const parseSubagentMarkerFromSystemReminder = (text) => {
|
|
|
4567
4584
|
|
|
4568
4585
|
//#endregion
|
|
4569
4586
|
//#region src/routes/messages/handler.ts
|
|
4570
|
-
const logger$
|
|
4587
|
+
const logger$5 = createHandlerLogger("messages-handler");
|
|
4571
4588
|
const CHAT_COMPLETIONS_ENDPOINT = "/chat/completions";
|
|
4572
4589
|
const RESPONSES_ENDPOINT$1 = "/responses";
|
|
4573
4590
|
const MESSAGES_ENDPOINT = "/v1/messages";
|
|
@@ -4582,21 +4599,21 @@ async function handleCompletion(c) {
|
|
|
4582
4599
|
const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
|
|
4583
4600
|
const userAgent = c.req.header("user-agent") ?? void 0;
|
|
4584
4601
|
const anthropicPayload = await c.req.json();
|
|
4585
|
-
logger$
|
|
4602
|
+
logger$5.debug("Anthropic request payload:", JSON.stringify(anthropicPayload));
|
|
4586
4603
|
const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
|
|
4587
4604
|
const initiatorOverride = subagentMarker ? "agent" : void 0;
|
|
4588
|
-
if (subagentMarker) logger$
|
|
4605
|
+
if (subagentMarker) logger$5.debug("Detected Subagent marker:", JSON.stringify(subagentMarker));
|
|
4589
4606
|
const sessionId = getRootSessionId(anthropicPayload, c);
|
|
4590
|
-
logger$
|
|
4607
|
+
logger$5.debug("Extracted session ID:", sessionId);
|
|
4591
4608
|
const anthropicBeta = c.req.header("anthropic-beta");
|
|
4592
4609
|
const isCompact = isCompactRequest(anthropicPayload);
|
|
4593
4610
|
if (anthropicBeta && isWarmupProbeRequest(anthropicPayload)) anthropicPayload.model = getSmallModel();
|
|
4594
4611
|
if (isCompact) {
|
|
4595
|
-
logger$
|
|
4612
|
+
logger$5.debug("Is compact request:", isCompact);
|
|
4596
4613
|
if (shouldCompactUseSmallModel()) anthropicPayload.model = getSmallModel();
|
|
4597
4614
|
} else mergeToolResultForClaude(anthropicPayload);
|
|
4598
4615
|
const upstreamRequestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
|
|
4599
|
-
logger$
|
|
4616
|
+
logger$5.debug("Generated request ID:", upstreamRequestId);
|
|
4600
4617
|
const clientModel = anthropicPayload.model;
|
|
4601
4618
|
const streamRequested = Boolean(anthropicPayload.stream);
|
|
4602
4619
|
const rawUserId = anthropicPayload.metadata?.user_id;
|
|
@@ -4624,17 +4641,19 @@ async function handleCompletion(c) {
|
|
|
4624
4641
|
if (blockedResponse) return blockedResponse;
|
|
4625
4642
|
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
4626
4643
|
const fallbackInitiator = initiatorOverride ?? getChatInitiator(openAIPayload.messages);
|
|
4644
|
+
const endpointModel = findEndpointModel(clientModel);
|
|
4645
|
+
const resolvedClientModel = endpointModel?.id ?? clientModel;
|
|
4627
4646
|
const selection = await accountsManager.selectAccountForRequest([
|
|
4628
4647
|
{
|
|
4629
|
-
modelId:
|
|
4648
|
+
modelId: resolvedClientModel,
|
|
4630
4649
|
endpoint: MESSAGES_ENDPOINT
|
|
4631
4650
|
},
|
|
4632
4651
|
{
|
|
4633
|
-
modelId:
|
|
4652
|
+
modelId: resolvedClientModel,
|
|
4634
4653
|
endpoint: RESPONSES_ENDPOINT$1
|
|
4635
4654
|
},
|
|
4636
4655
|
{
|
|
4637
|
-
modelId: openAIPayload.model,
|
|
4656
|
+
modelId: endpointModel?.id ?? openAIPayload.model,
|
|
4638
4657
|
endpoint: CHAT_COMPLETIONS_ENDPOINT
|
|
4639
4658
|
}
|
|
4640
4659
|
]);
|
|
@@ -4716,7 +4735,7 @@ async function handleCompletion(c) {
|
|
|
4716
4735
|
}
|
|
4717
4736
|
const handleWithChatCompletions = async (params) => {
|
|
4718
4737
|
const { c, openAIPayload, initiatorOverride, subagentMarker, sessionId, selectedModel, instr } = params;
|
|
4719
|
-
logger$
|
|
4738
|
+
logger$5.debug("Translated OpenAI request payload:", JSON.stringify(openAIPayload));
|
|
4720
4739
|
const ctx = toAccountContext(instr.account);
|
|
4721
4740
|
const initiator = initiatorOverride ?? getChatInitiator(openAIPayload.messages);
|
|
4722
4741
|
instr.initiator = initiator;
|
|
@@ -4740,9 +4759,9 @@ const handleWithChatCompletions = async (params) => {
|
|
|
4740
4759
|
response,
|
|
4741
4760
|
instr
|
|
4742
4761
|
});
|
|
4743
|
-
logger$
|
|
4762
|
+
logger$5.debug("Streaming response from Copilot");
|
|
4744
4763
|
const fallbackEnabled = isMessageStartInputTokensFallbackEnabled();
|
|
4745
|
-
const estimatedInputTokens = fallbackEnabled ? await estimateInputTokens(openAIPayload, selectedModel, logger$
|
|
4764
|
+
const estimatedInputTokens = fallbackEnabled ? await estimateInputTokens(openAIPayload, selectedModel, logger$5) : void 0;
|
|
4746
4765
|
const historicalUsage = fallbackEnabled && instr.promptCacheKey && instr.safetyIdentifier ? instr.store.getLastCompletedUsageBySession({
|
|
4747
4766
|
promptCacheKey: instr.promptCacheKey,
|
|
4748
4767
|
safetyIdentifier: instr.safetyIdentifier,
|
|
@@ -4761,7 +4780,7 @@ const handleWithResponsesApi = async (params) => {
|
|
|
4761
4780
|
const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload, selectedModel.id);
|
|
4762
4781
|
applyResponsesApiContextManagement(responsesPayload, selectedModel.capabilities.limits.max_prompt_tokens);
|
|
4763
4782
|
compactInputByLatestCompaction(responsesPayload);
|
|
4764
|
-
logger$
|
|
4783
|
+
logger$5.debug("Translated Responses payload:", JSON.stringify(responsesPayload));
|
|
4765
4784
|
const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
|
|
4766
4785
|
const resolvedInitiator = initiatorOverride ?? initiator;
|
|
4767
4786
|
const ctx = toAccountContext(instr.account);
|
|
@@ -4783,9 +4802,9 @@ const handleWithResponsesApi = async (params) => {
|
|
|
4783
4802
|
});
|
|
4784
4803
|
}
|
|
4785
4804
|
if (responsesPayload.stream && isAsyncIterable$1(response)) {
|
|
4786
|
-
logger$
|
|
4805
|
+
logger$5.debug("Streaming response from Copilot (Responses API)");
|
|
4787
4806
|
const fallbackEnabled = isMessageStartInputTokensFallbackEnabled();
|
|
4788
|
-
const estimatedInputTokens = fallbackEnabled ? await estimateInputTokens(openAIPayload, selectedModel, logger$
|
|
4807
|
+
const estimatedInputTokens = fallbackEnabled ? await estimateInputTokens(openAIPayload, selectedModel, logger$5) : void 0;
|
|
4789
4808
|
const historicalUsage = fallbackEnabled && instr.promptCacheKey && instr.safetyIdentifier ? instr.store.getLastCompletedUsageBySession({
|
|
4790
4809
|
promptCacheKey: instr.promptCacheKey,
|
|
4791
4810
|
safetyIdentifier: instr.safetyIdentifier,
|
|
@@ -4870,9 +4889,9 @@ async function handleChatCompletionsNonStreaming(params) {
|
|
|
4870
4889
|
let errorMessage;
|
|
4871
4890
|
const finishedAtMs = Date.now();
|
|
4872
4891
|
try {
|
|
4873
|
-
logger$
|
|
4892
|
+
logger$5.debug("Non-streaming response from Copilot:", JSON.stringify(response));
|
|
4874
4893
|
const anthropicResponse = translateToAnthropic(response);
|
|
4875
|
-
logger$
|
|
4894
|
+
logger$5.debug("Translated Anthropic response:", JSON.stringify(anthropicResponse));
|
|
4876
4895
|
return c.json(anthropicResponse);
|
|
4877
4896
|
} catch (error) {
|
|
4878
4897
|
const details = extractErrorDetails(error);
|
|
@@ -4920,7 +4939,7 @@ async function streamChatCompletionsAndLog(params) {
|
|
|
4920
4939
|
try {
|
|
4921
4940
|
for await (const rawEvent of response) {
|
|
4922
4941
|
if (ttfbMs === void 0) ttfbMs = Date.now() - instr.startedAtMs;
|
|
4923
|
-
logger$
|
|
4942
|
+
logger$5.debug("Copilot raw stream event:", JSON.stringify(rawEvent));
|
|
4924
4943
|
const { data: rawData } = rawEvent;
|
|
4925
4944
|
const data = typeof rawData === "string" ? rawData : await rawData;
|
|
4926
4945
|
if (data === "[DONE]") break;
|
|
@@ -4929,7 +4948,7 @@ async function streamChatCompletionsAndLog(params) {
|
|
|
4929
4948
|
if (chunk.usage) lastUsage = normalizeChatCompletionsUsage(chunk.usage);
|
|
4930
4949
|
const events$1 = translateChunkToAnthropicEvents(chunk, streamState);
|
|
4931
4950
|
for (const event of events$1) {
|
|
4932
|
-
logger$
|
|
4951
|
+
logger$5.debug("Translated Anthropic event:", JSON.stringify(event));
|
|
4933
4952
|
await stream.writeSSE({
|
|
4934
4953
|
event: event.type,
|
|
4935
4954
|
data: JSON.stringify(event)
|
|
@@ -4941,7 +4960,7 @@ async function streamChatCompletionsAndLog(params) {
|
|
|
4941
4960
|
errorName = details.errorName;
|
|
4942
4961
|
errorStatus = details.errorStatus;
|
|
4943
4962
|
errorMessage = details.errorMessage;
|
|
4944
|
-
logger$
|
|
4963
|
+
logger$5.warn("Streaming error:", error);
|
|
4945
4964
|
if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
4946
4965
|
} finally {
|
|
4947
4966
|
const finishedAtMs = Date.now();
|
|
@@ -4992,9 +5011,9 @@ async function handleResponsesNonStreaming(params) {
|
|
|
4992
5011
|
const finishedAtMs = Date.now();
|
|
4993
5012
|
try {
|
|
4994
5013
|
usage = extractResponsesUsageFromResult(result);
|
|
4995
|
-
logger$
|
|
5014
|
+
logger$5.debug("Non-streaming Responses result:", JSON.stringify(result).slice(-400));
|
|
4996
5015
|
const anthropicResponse = translateResponsesResultToAnthropic(result);
|
|
4997
|
-
logger$
|
|
5016
|
+
logger$5.debug("Translated Anthropic response:", JSON.stringify(anthropicResponse));
|
|
4998
5017
|
return c.json(anthropicResponse);
|
|
4999
5018
|
} catch (error) {
|
|
5000
5019
|
const details = extractErrorDetails(error);
|
|
@@ -5024,7 +5043,7 @@ async function handleResponsesNonStreaming(params) {
|
|
|
5024
5043
|
async function ensureResponsesStreamCompleted(params) {
|
|
5025
5044
|
const { stream, streamState, setStreamError } = params;
|
|
5026
5045
|
if (streamState.messageCompleted) return;
|
|
5027
|
-
logger$
|
|
5046
|
+
logger$5.warn("Responses stream ended without completion; sending error event");
|
|
5028
5047
|
const msg = "Responses stream ended without completion";
|
|
5029
5048
|
const errorEvent = buildErrorEvent(msg);
|
|
5030
5049
|
setStreamError("StreamIncomplete", msg);
|
|
@@ -5057,21 +5076,21 @@ async function streamResponsesAndLog$1(params) {
|
|
|
5057
5076
|
}
|
|
5058
5077
|
const data = chunk.data;
|
|
5059
5078
|
if (!data) continue;
|
|
5060
|
-
logger$
|
|
5079
|
+
logger$5.debug("Responses raw stream event:", data);
|
|
5061
5080
|
const parsed = JSON.parse(data);
|
|
5062
5081
|
const u = extractResponsesUsageFromStreamEvent(parsed);
|
|
5063
5082
|
if (u.usageJson) lastUsage = u;
|
|
5064
5083
|
const events$1 = translateResponsesStreamEvent(parsed, streamState);
|
|
5065
5084
|
for (const event of events$1) {
|
|
5066
5085
|
const eventData = JSON.stringify(event);
|
|
5067
|
-
logger$
|
|
5086
|
+
logger$5.debug("Translated Anthropic event:", eventData);
|
|
5068
5087
|
await stream.writeSSE({
|
|
5069
5088
|
event: event.type,
|
|
5070
5089
|
data: eventData
|
|
5071
5090
|
});
|
|
5072
5091
|
}
|
|
5073
5092
|
if (streamState.messageCompleted) {
|
|
5074
|
-
logger$
|
|
5093
|
+
logger$5.debug("Message completed, ending stream");
|
|
5075
5094
|
break;
|
|
5076
5095
|
}
|
|
5077
5096
|
}
|
|
@@ -5088,7 +5107,7 @@ async function streamResponsesAndLog$1(params) {
|
|
|
5088
5107
|
errorName = details.errorName;
|
|
5089
5108
|
errorStatus = details.errorStatus;
|
|
5090
5109
|
errorMessage = details.errorMessage;
|
|
5091
|
-
logger$
|
|
5110
|
+
logger$5.warn("Streaming error:", error);
|
|
5092
5111
|
if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5093
5112
|
} finally {
|
|
5094
5113
|
const finishedAtMs = Date.now();
|
|
@@ -5138,7 +5157,7 @@ async function handleMessagesNonStreaming(params) {
|
|
|
5138
5157
|
let errorMessage;
|
|
5139
5158
|
const finishedAtMs = Date.now();
|
|
5140
5159
|
try {
|
|
5141
|
-
logger$
|
|
5160
|
+
logger$5.debug("Non-streaming Messages result:", JSON.stringify(response).slice(-400));
|
|
5142
5161
|
return c.json(response);
|
|
5143
5162
|
} catch (error) {
|
|
5144
5163
|
const details = extractErrorDetails(error);
|
|
@@ -5172,7 +5191,7 @@ const parseMessagesStreamUsage = (data) => {
|
|
|
5172
5191
|
if (parsed.type !== "message_delta" || !parsed.usage) return null;
|
|
5173
5192
|
return normalizeMessagesUsage(parsed.usage);
|
|
5174
5193
|
} catch (error) {
|
|
5175
|
-
logger$
|
|
5194
|
+
logger$5.warn("Failed to parse messages stream event", error);
|
|
5176
5195
|
return null;
|
|
5177
5196
|
}
|
|
5178
5197
|
};
|
|
@@ -5189,7 +5208,7 @@ async function streamMessagesAndLog(params) {
|
|
|
5189
5208
|
const eventNameRaw = rawEvent.event;
|
|
5190
5209
|
const eventName = typeof eventNameRaw === "string" && eventNameRaw.length > 0 ? eventNameRaw : "message";
|
|
5191
5210
|
const data = rawEvent.data ?? "";
|
|
5192
|
-
logger$
|
|
5211
|
+
logger$5.debug("Messages raw stream event:", data);
|
|
5193
5212
|
const usage = parseMessagesStreamUsage(data);
|
|
5194
5213
|
if (usage) lastUsage = usage;
|
|
5195
5214
|
await stream.writeSSE({
|
|
@@ -5202,7 +5221,7 @@ async function streamMessagesAndLog(params) {
|
|
|
5202
5221
|
errorName = details.errorName;
|
|
5203
5222
|
errorStatus = details.errorStatus;
|
|
5204
5223
|
errorMessage = details.errorMessage;
|
|
5205
|
-
logger$
|
|
5224
|
+
logger$5.warn("Streaming error:", error);
|
|
5206
5225
|
if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5207
5226
|
} finally {
|
|
5208
5227
|
const finishedAtMs = Date.now();
|
|
@@ -5237,7 +5256,7 @@ const handleWithMessagesApi = async (params) => {
|
|
|
5237
5256
|
anthropicPayload.thinking = { type: "adaptive" };
|
|
5238
5257
|
anthropicPayload.output_config = { effort: getAnthropicEffortForModel(anthropicPayload.model) };
|
|
5239
5258
|
}
|
|
5240
|
-
logger$
|
|
5259
|
+
logger$5.debug("Translated Messages payload:", JSON.stringify(anthropicPayload));
|
|
5241
5260
|
const ctx = toAccountContext(instr.account);
|
|
5242
5261
|
const initiator = initiatorOverride ?? getMessagesInitiator(anthropicPayload);
|
|
5243
5262
|
instr.initiator = initiator;
|
|
@@ -5258,7 +5277,7 @@ const handleWithMessagesApi = async (params) => {
|
|
|
5258
5277
|
});
|
|
5259
5278
|
}
|
|
5260
5279
|
if (isAsyncIterable$1(response)) {
|
|
5261
|
-
logger$
|
|
5280
|
+
logger$5.debug("Streaming response from Copilot (Messages API)");
|
|
5262
5281
|
return streamSSE(c, (stream) => streamMessagesAndLog({
|
|
5263
5282
|
stream,
|
|
5264
5283
|
response,
|
|
@@ -5342,6 +5361,204 @@ modelRoutes.get("/", async (c) => {
|
|
|
5342
5361
|
}
|
|
5343
5362
|
});
|
|
5344
5363
|
|
|
5364
|
+
//#endregion
|
|
5365
|
+
//#region src/routes/provider/messages/count-tokens-handler.ts
|
|
5366
|
+
const logger$4 = createHandlerLogger("provider-count-tokens-handler");
|
|
5367
|
+
const createFallbackModel = (modelId) => ({
|
|
5368
|
+
capabilities: {
|
|
5369
|
+
family: "provider",
|
|
5370
|
+
limits: {},
|
|
5371
|
+
object: "model_capabilities",
|
|
5372
|
+
supports: {},
|
|
5373
|
+
tokenizer: "o200k_base",
|
|
5374
|
+
type: "chat"
|
|
5375
|
+
},
|
|
5376
|
+
id: modelId,
|
|
5377
|
+
model_picker_enabled: false,
|
|
5378
|
+
name: modelId,
|
|
5379
|
+
object: "model",
|
|
5380
|
+
preview: false,
|
|
5381
|
+
vendor: "provider",
|
|
5382
|
+
version: "unknown"
|
|
5383
|
+
});
|
|
5384
|
+
async function handleProviderCountTokens(c) {
|
|
5385
|
+
const provider = c.req.param("provider");
|
|
5386
|
+
try {
|
|
5387
|
+
const anthropicPayload = await c.req.json();
|
|
5388
|
+
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
5389
|
+
const modelId = anthropicPayload.model.trim();
|
|
5390
|
+
let selectedModel = state.models?.data.find((model) => model.id === modelId);
|
|
5391
|
+
if (!selectedModel && modelId) selectedModel = createFallbackModel(modelId);
|
|
5392
|
+
if (!selectedModel) {
|
|
5393
|
+
logger$4.warn("provider.count_tokens.model_not_found", {
|
|
5394
|
+
provider,
|
|
5395
|
+
model: anthropicPayload.model
|
|
5396
|
+
});
|
|
5397
|
+
return c.json({ input_tokens: 1 });
|
|
5398
|
+
}
|
|
5399
|
+
const tokenCount = await getTokenCount(openAIPayload, selectedModel);
|
|
5400
|
+
const finalTokenCount = tokenCount.input + tokenCount.output;
|
|
5401
|
+
logger$4.debug("provider.count_tokens.success", {
|
|
5402
|
+
provider,
|
|
5403
|
+
model: anthropicPayload.model,
|
|
5404
|
+
input_tokens: finalTokenCount
|
|
5405
|
+
});
|
|
5406
|
+
return c.json({ input_tokens: finalTokenCount });
|
|
5407
|
+
} catch (error) {
|
|
5408
|
+
logger$4.error("provider.count_tokens.error", {
|
|
5409
|
+
provider,
|
|
5410
|
+
error
|
|
5411
|
+
});
|
|
5412
|
+
return c.json({ input_tokens: 1 });
|
|
5413
|
+
}
|
|
5414
|
+
}
|
|
5415
|
+
|
|
5416
|
+
//#endregion
|
|
5417
|
+
//#region src/services/providers/anthropic-proxy.ts
|
|
5418
|
+
const FORWARDABLE_HEADERS = [
|
|
5419
|
+
"anthropic-version",
|
|
5420
|
+
"anthropic-beta",
|
|
5421
|
+
"accept",
|
|
5422
|
+
"user-agent"
|
|
5423
|
+
];
|
|
5424
|
+
const STRIPPED_RESPONSE_HEADERS = [
|
|
5425
|
+
"connection",
|
|
5426
|
+
"content-encoding",
|
|
5427
|
+
"content-length",
|
|
5428
|
+
"keep-alive",
|
|
5429
|
+
"proxy-authenticate",
|
|
5430
|
+
"proxy-authorization",
|
|
5431
|
+
"te",
|
|
5432
|
+
"trailer",
|
|
5433
|
+
"transfer-encoding",
|
|
5434
|
+
"upgrade"
|
|
5435
|
+
];
|
|
5436
|
+
function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
|
|
5437
|
+
const headers = {
|
|
5438
|
+
"content-type": "application/json",
|
|
5439
|
+
accept: "application/json",
|
|
5440
|
+
"x-api-key": providerConfig.apiKey
|
|
5441
|
+
};
|
|
5442
|
+
for (const headerName of FORWARDABLE_HEADERS) {
|
|
5443
|
+
const headerValue = requestHeaders.get(headerName);
|
|
5444
|
+
if (headerValue) headers[headerName] = headerValue;
|
|
5445
|
+
}
|
|
5446
|
+
return headers;
|
|
5447
|
+
}
|
|
5448
|
+
function createProviderProxyResponse(upstreamResponse) {
|
|
5449
|
+
const headers = new Headers(upstreamResponse.headers);
|
|
5450
|
+
for (const headerName of STRIPPED_RESPONSE_HEADERS) headers.delete(headerName);
|
|
5451
|
+
return new Response(upstreamResponse.body, {
|
|
5452
|
+
headers,
|
|
5453
|
+
status: upstreamResponse.status,
|
|
5454
|
+
statusText: upstreamResponse.statusText
|
|
5455
|
+
});
|
|
5456
|
+
}
|
|
5457
|
+
async function forwardProviderMessages(providerConfig, payload, requestHeaders) {
|
|
5458
|
+
return await fetch(`${providerConfig.baseUrl}/v1/messages`, {
|
|
5459
|
+
method: "POST",
|
|
5460
|
+
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
|
|
5461
|
+
body: JSON.stringify(payload)
|
|
5462
|
+
});
|
|
5463
|
+
}
|
|
5464
|
+
async function forwardProviderModels(providerConfig, requestHeaders) {
|
|
5465
|
+
return await fetch(`${providerConfig.baseUrl}/v1/models`, {
|
|
5466
|
+
method: "GET",
|
|
5467
|
+
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders)
|
|
5468
|
+
});
|
|
5469
|
+
}
|
|
5470
|
+
|
|
5471
|
+
//#endregion
|
|
5472
|
+
//#region src/routes/provider/messages/handler.ts
|
|
5473
|
+
const logger$3 = createHandlerLogger("provider-messages-handler");
|
|
5474
|
+
async function handleProviderMessages(c) {
|
|
5475
|
+
const provider = c.req.param("provider");
|
|
5476
|
+
const providerConfig = getProviderConfig(provider);
|
|
5477
|
+
if (!providerConfig) return c.json({ error: {
|
|
5478
|
+
message: `Provider '${provider}' not found or disabled`,
|
|
5479
|
+
type: "invalid_request_error"
|
|
5480
|
+
} }, 404);
|
|
5481
|
+
try {
|
|
5482
|
+
const payload = await c.req.json();
|
|
5483
|
+
const modelConfig = providerConfig.models?.[payload.model];
|
|
5484
|
+
payload.temperature ??= modelConfig?.temperature;
|
|
5485
|
+
payload.top_p ??= modelConfig?.topP;
|
|
5486
|
+
payload.top_k ??= modelConfig?.topK;
|
|
5487
|
+
logger$3.debug("provider.messages.request", JSON.stringify({
|
|
5488
|
+
payload,
|
|
5489
|
+
provider
|
|
5490
|
+
}));
|
|
5491
|
+
const upstreamResponse = await forwardProviderMessages(providerConfig, payload, c.req.raw.headers);
|
|
5492
|
+
const contentType = upstreamResponse.headers.get("content-type") ?? "";
|
|
5493
|
+
if (Boolean(payload.stream) && contentType.includes("text/event-stream")) {
|
|
5494
|
+
logger$3.debug("provider.messages.streaming");
|
|
5495
|
+
return streamSSE(c, async (stream) => {
|
|
5496
|
+
for await (const event of events(upstreamResponse)) {
|
|
5497
|
+
const eventName = event.event;
|
|
5498
|
+
const data = event.data ?? "";
|
|
5499
|
+
logger$3.debug("provider.messages.raw_stream_event", data);
|
|
5500
|
+
await stream.writeSSE({
|
|
5501
|
+
event: eventName,
|
|
5502
|
+
data
|
|
5503
|
+
});
|
|
5504
|
+
}
|
|
5505
|
+
});
|
|
5506
|
+
}
|
|
5507
|
+
return createProviderProxyResponse(upstreamResponse);
|
|
5508
|
+
} catch (error) {
|
|
5509
|
+
logger$3.error("provider.messages.error", {
|
|
5510
|
+
provider,
|
|
5511
|
+
error
|
|
5512
|
+
});
|
|
5513
|
+
throw error;
|
|
5514
|
+
}
|
|
5515
|
+
}
|
|
5516
|
+
|
|
5517
|
+
//#endregion
|
|
5518
|
+
//#region src/routes/provider/messages/route.ts
|
|
5519
|
+
const providerMessageRoutes = new Hono();
|
|
5520
|
+
providerMessageRoutes.post("/", async (c) => {
|
|
5521
|
+
try {
|
|
5522
|
+
return await handleProviderMessages(c);
|
|
5523
|
+
} catch (error) {
|
|
5524
|
+
return await forwardError(c, error);
|
|
5525
|
+
}
|
|
5526
|
+
});
|
|
5527
|
+
providerMessageRoutes.post("/count_tokens", async (c) => {
|
|
5528
|
+
try {
|
|
5529
|
+
return await handleProviderCountTokens(c);
|
|
5530
|
+
} catch (error) {
|
|
5531
|
+
return await forwardError(c, error);
|
|
5532
|
+
}
|
|
5533
|
+
});
|
|
5534
|
+
|
|
5535
|
+
//#endregion
|
|
5536
|
+
//#region src/routes/provider/models/route.ts
|
|
5537
|
+
const logger$2 = createHandlerLogger("provider-models-handler");
|
|
5538
|
+
const providerModelRoutes = new Hono();
|
|
5539
|
+
providerModelRoutes.get("/", async (c) => {
|
|
5540
|
+
const provider = c.req.param("provider") ?? "";
|
|
5541
|
+
try {
|
|
5542
|
+
const providerConfig = getProviderConfig(provider);
|
|
5543
|
+
if (!providerConfig) return c.json({ error: {
|
|
5544
|
+
message: `Provider '${provider}' not found or disabled`,
|
|
5545
|
+
type: "invalid_request_error"
|
|
5546
|
+
} }, 404);
|
|
5547
|
+
const upstreamResponse = await forwardProviderModels(providerConfig, c.req.raw.headers);
|
|
5548
|
+
logger$2.debug("provider.models.response", {
|
|
5549
|
+
provider,
|
|
5550
|
+
statusCode: upstreamResponse.status
|
|
5551
|
+
});
|
|
5552
|
+
return createProviderProxyResponse(upstreamResponse);
|
|
5553
|
+
} catch (error) {
|
|
5554
|
+
logger$2.error("provider.models.error", {
|
|
5555
|
+
provider,
|
|
5556
|
+
error
|
|
5557
|
+
});
|
|
5558
|
+
return await forwardError(c, error);
|
|
5559
|
+
}
|
|
5560
|
+
});
|
|
5561
|
+
|
|
5345
5562
|
//#endregion
|
|
5346
5563
|
//#region src/routes/responses/stream-id-sync.ts
|
|
5347
5564
|
const createStreamIdTracker = () => ({ outputItems: /* @__PURE__ */ new Map() });
|
|
@@ -5922,7 +6139,9 @@ server.route("/v1/models", modelRoutes);
|
|
|
5922
6139
|
server.route("/v1/embeddings", embeddingRoutes);
|
|
5923
6140
|
server.route("/v1/responses", responsesRoutes);
|
|
5924
6141
|
server.route("/v1/messages", messageRoutes);
|
|
6142
|
+
server.route("/:provider/v1/messages", providerMessageRoutes);
|
|
6143
|
+
server.route("/:provider/v1/models", providerModelRoutes);
|
|
5925
6144
|
|
|
5926
6145
|
//#endregion
|
|
5927
6146
|
export { server };
|
|
5928
|
-
//# sourceMappingURL=server-
|
|
6147
|
+
//# sourceMappingURL=server-D3A61KAx.js.map
|