@jeffreycao/copilot-api 1.10.36 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -4
- package/README.zh-CN.md +7 -4
- package/dist/{auth-DzjQQuSk.js → auth-BjmTG37p.js} +3 -3
- package/dist/{auth-DzjQQuSk.js.map → auth-BjmTG37p.js.map} +1 -1
- package/dist/{check-usage-DBfggFvQ.js → check-usage-BB_15i5y.js} +3 -3
- package/dist/{check-usage-DBfggFvQ.js.map → check-usage-BB_15i5y.js.map} +1 -1
- package/dist/{config-CgDUUqnp.js → config-Cni8ffEV.js} +14 -4
- package/dist/config-Cni8ffEV.js.map +1 -0
- package/dist/{debug-BEVHlRGL.js → debug-DCP0VOJy.js} +2 -2
- package/dist/{debug-BEVHlRGL.js.map → debug-DCP0VOJy.js.map} +1 -1
- package/dist/main.js +4 -4
- package/dist/{server-DYlw1xSW.js → server-xtwGZKXj.js} +415 -15
- package/dist/server-xtwGZKXj.js.map +1 -0
- package/dist/{start-B-xjF4KT.js → start-Gi73-qBt.js} +4 -4
- package/dist/{start-B-xjF4KT.js.map → start-Gi73-qBt.js.map} +1 -1
- package/dist/{token-CHTEbXZd.js → token-ZyYn_xJt.js} +11 -4
- package/dist/token-ZyYn_xJt.js.map +1 -0
- package/package.json +1 -1
- package/dist/config-CgDUUqnp.js.map +0 -1
- package/dist/server-DYlw1xSW.js.map +0 -1
- package/dist/token-CHTEbXZd.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as forwardError, C as prepareMessageProxyHeaders, E as compactMessageSections, F as createPooledWebSocketStream, I as createWebSocketUrl, M as generateTraceId, N as requestContext, O as compactSystemPromptStarts, P as resolveTraceId$1, R as state, S as prepareInteractionHeaders, T as compactAutoContinuePromptStarts, _ as getCopilotUsage, b as copilotWebSocketHeaders, d as generateRequestIdFromPayload, f as getRootSessionId, g as sleep, h as parseUserIdMetadata, j as forwardCodexResponses, m as isNullish, p as getUUID, r as setupCodexToken, s as cacheModels, v as copilotBaseUrl, x as prepareForCompact, y as copilotHeaders, z as HTTPError } from "./token-
|
|
1
|
+
import { S as PATHS, a as getMessageApiWebSearchModel, b as setModelMappings, c as getProviderConfig, d as getReasoningEffortForModel, f as getSmallModel, g as isResponsesApiWebSocketEnabled, h as isResponsesApiWebSearchEnabled, i as getExtraPromptForModel, l as getProviderMessageApiWebSearchModel, m as isResponsesApiContextManagementEnabled, n as getClaudeTokenMultiplier, o as getModelMappings, p as isMessagesApiEnabled, r as getConfig, s as getModelResponsesApiCompactThreshold$1, t as getAnthropicApiKey, u as getRawProviderConfig, y as resolveMappedModel } from "./config-Cni8ffEV.js";
|
|
2
|
+
import { B as forwardError, C as prepareMessageProxyHeaders, E as compactMessageSections, F as createPooledWebSocketStream, I as createWebSocketUrl, M as generateTraceId, N as requestContext, O as compactSystemPromptStarts, P as resolveTraceId$1, R as state, S as prepareInteractionHeaders, T as compactAutoContinuePromptStarts, _ as getCopilotUsage, b as copilotWebSocketHeaders, d as generateRequestIdFromPayload, f as getRootSessionId, g as sleep, h as parseUserIdMetadata, j as forwardCodexResponses, m as isNullish, p as getUUID, r as setupCodexToken, s as cacheModels, v as copilotBaseUrl, x as prepareForCompact, y as copilotHeaders, z as HTTPError } from "./token-ZyYn_xJt.js";
|
|
3
3
|
import { a as isDeferredToolName, c as parseMcpToolSearchSentinel, d as shouldEnableResponsesToolSearch, i as isBridgeToolSearchName, l as resolveBridgeToolSearchName, o as listDeferredToolNames, r as formatToolSearchBridgeArguments, s as normalizeToolSearchBridgeArguments, t as BRIDGE_TOOL_SEARCH_NAME, u as selectDeferredToolsByNames } from "./tool-search-wA-fLduL.js";
|
|
4
4
|
import consola from "consola";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
@@ -1020,6 +1020,7 @@ function createProviderProxyResponse(upstreamResponse, body) {
|
|
|
1020
1020
|
});
|
|
1021
1021
|
}
|
|
1022
1022
|
async function forwardProviderMessages(providerConfig, payload, requestHeaders) {
|
|
1023
|
+
consola.log(`<-- model: ${payload.model}`);
|
|
1023
1024
|
return await fetch(`${providerConfig.baseUrl}/v1/messages`, {
|
|
1024
1025
|
method: "POST",
|
|
1025
1026
|
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
|
|
@@ -1027,6 +1028,7 @@ async function forwardProviderMessages(providerConfig, payload, requestHeaders)
|
|
|
1027
1028
|
});
|
|
1028
1029
|
}
|
|
1029
1030
|
async function forwardProviderChatCompletions(providerConfig, payload, requestHeaders) {
|
|
1031
|
+
consola.log(`<-- model: ${payload.model}`);
|
|
1030
1032
|
return await fetch(`${providerConfig.baseUrl}/v1/chat/completions`, {
|
|
1031
1033
|
method: "POST",
|
|
1032
1034
|
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
|
|
@@ -1034,6 +1036,7 @@ async function forwardProviderChatCompletions(providerConfig, payload, requestHe
|
|
|
1034
1036
|
});
|
|
1035
1037
|
}
|
|
1036
1038
|
async function forwardProviderResponses(providerConfig, payload, requestHeaders) {
|
|
1039
|
+
consola.log(`<-- model: ${payload.model}`);
|
|
1037
1040
|
return await fetch(`${providerConfig.baseUrl}/v1/responses`, {
|
|
1038
1041
|
method: "POST",
|
|
1039
1042
|
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
|
|
@@ -4149,6 +4152,303 @@ const containsVisionContent = (value) => {
|
|
|
4149
4152
|
return false;
|
|
4150
4153
|
};
|
|
4151
4154
|
//#endregion
|
|
4155
|
+
//#region src/routes/messages/web-search/backend.ts
|
|
4156
|
+
/** Builds the Responses API web_search tool object from the Anthropic config. */
|
|
4157
|
+
const buildResponsesWebSearchTool = (config) => {
|
|
4158
|
+
const tool = { type: "web_search" };
|
|
4159
|
+
const filters = {};
|
|
4160
|
+
if (config.allowedDomains?.length) filters.allowed_domains = config.allowedDomains;
|
|
4161
|
+
if (config.blockedDomains?.length) filters.blocked_domains = config.blockedDomains;
|
|
4162
|
+
if (Object.keys(filters).length > 0) tool.filters = filters;
|
|
4163
|
+
if (config.userLocation) tool.user_location = config.userLocation;
|
|
4164
|
+
return tool;
|
|
4165
|
+
};
|
|
4166
|
+
const isMessageItem = (item) => item.type === "message";
|
|
4167
|
+
const isValidUrlCitation = (annotation, seenUrls) => {
|
|
4168
|
+
const ann = annotation;
|
|
4169
|
+
return ann.type === "url_citation" && Boolean(ann.url) && !seenUrls.has(ann.url);
|
|
4170
|
+
};
|
|
4171
|
+
const collectTextParts = (blocks, seenUrls) => {
|
|
4172
|
+
const textParts = [];
|
|
4173
|
+
const sources = [];
|
|
4174
|
+
for (const block of blocks ?? []) {
|
|
4175
|
+
if (block.type !== "output_text") continue;
|
|
4176
|
+
if (block.text) textParts.push(block.text);
|
|
4177
|
+
for (const annotation of block.annotations ?? []) {
|
|
4178
|
+
if (!isValidUrlCitation(annotation, seenUrls)) continue;
|
|
4179
|
+
const ann = annotation;
|
|
4180
|
+
seenUrls.add(ann.url);
|
|
4181
|
+
sources.push({
|
|
4182
|
+
url: ann.url,
|
|
4183
|
+
title: ann.title ?? ann.url
|
|
4184
|
+
});
|
|
4185
|
+
}
|
|
4186
|
+
}
|
|
4187
|
+
return {
|
|
4188
|
+
textParts,
|
|
4189
|
+
sources
|
|
4190
|
+
};
|
|
4191
|
+
};
|
|
4192
|
+
const collectQuery = (item, queries) => {
|
|
4193
|
+
if (item.action?.queries?.length) queries.push(...item.action.queries);
|
|
4194
|
+
else if (item.action?.query) queries.push(item.action.query);
|
|
4195
|
+
};
|
|
4196
|
+
/**
|
|
4197
|
+
* Extracts the answer text, deduped sources, and run queries from a GPT
|
|
4198
|
+
* /responses web_search result.
|
|
4199
|
+
*/
|
|
4200
|
+
const extractWebSearchResult = (result) => {
|
|
4201
|
+
const textParts = [];
|
|
4202
|
+
const sources = [];
|
|
4203
|
+
const seenUrls = /* @__PURE__ */ new Set();
|
|
4204
|
+
const queries = [];
|
|
4205
|
+
for (const item of result.output) {
|
|
4206
|
+
if (isMessageItem(item)) {
|
|
4207
|
+
const collected = collectTextParts(item.content, seenUrls);
|
|
4208
|
+
textParts.push(...collected.textParts);
|
|
4209
|
+
sources.push(...collected.sources);
|
|
4210
|
+
continue;
|
|
4211
|
+
}
|
|
4212
|
+
if (item.type === "web_search_call") collectQuery(item, queries);
|
|
4213
|
+
}
|
|
4214
|
+
return {
|
|
4215
|
+
answerText: textParts.join("\n\n").trim() || (result.output_text ?? "").trim(),
|
|
4216
|
+
sources,
|
|
4217
|
+
queries
|
|
4218
|
+
};
|
|
4219
|
+
};
|
|
4220
|
+
//#endregion
|
|
4221
|
+
//#region src/routes/messages/web-search/fulfill.ts
|
|
4222
|
+
const webSearchFlowDependencies = {
|
|
4223
|
+
createResponses,
|
|
4224
|
+
createUsageRecorder: (payload, sessionId, webSearchModel) => createCopilotTokenUsageRecorder({
|
|
4225
|
+
endpoint: "responses",
|
|
4226
|
+
fallbackSessionId: sessionId,
|
|
4227
|
+
model: webSearchModel ?? payload.model,
|
|
4228
|
+
sessionId: parseUserIdMetadata(payload.metadata?.user_id).sessionId
|
|
4229
|
+
})
|
|
4230
|
+
};
|
|
4231
|
+
const isWebSearchServerTool = (tool) => typeof tool.type === "string" && tool.type.startsWith("web_search") && !tool.input_schema;
|
|
4232
|
+
/** True when the payload carries an Anthropic server-side web_search tool. */
|
|
4233
|
+
const hasWebSearchServerTool = (payload) => Array.isArray(payload.tools) && payload.tools.some(isWebSearchServerTool);
|
|
4234
|
+
/**
|
|
4235
|
+
* True when web_search is the ONLY tool in the request. Mixing web_search with
|
|
4236
|
+
* other tools is intentionally unsupported, so only these requests are switched
|
|
4237
|
+
* to the web search model.
|
|
4238
|
+
*/
|
|
4239
|
+
const isWebSearchOnlyRequest = (payload) => Array.isArray(payload.tools) && payload.tools.length > 0 && payload.tools.every(isWebSearchServerTool);
|
|
4240
|
+
/** Removes web_search server tools (used for unsupported mixed-tool requests). */
|
|
4241
|
+
const stripWebSearchServerTool = (payload) => {
|
|
4242
|
+
if (!Array.isArray(payload.tools)) return;
|
|
4243
|
+
payload.tools = payload.tools.filter((tool) => !isWebSearchServerTool(tool));
|
|
4244
|
+
};
|
|
4245
|
+
const resolveWebSearchRoute = (payload, options) => {
|
|
4246
|
+
const { webSearchModel, responsesWebSearchEnabled } = options;
|
|
4247
|
+
if (!webSearchModel || !isWebSearchOnlyRequest(payload)) return { kind: "strip" };
|
|
4248
|
+
const alias = parseProviderModelAlias(webSearchModel);
|
|
4249
|
+
if (alias) return {
|
|
4250
|
+
kind: "provider",
|
|
4251
|
+
alias
|
|
4252
|
+
};
|
|
4253
|
+
if (responsesWebSearchEnabled) return {
|
|
4254
|
+
kind: "responses",
|
|
4255
|
+
model: webSearchModel
|
|
4256
|
+
};
|
|
4257
|
+
return { kind: "strip" };
|
|
4258
|
+
};
|
|
4259
|
+
const extractWebSearchConfig = (payload) => {
|
|
4260
|
+
const tool = payload.tools?.find(isWebSearchServerTool);
|
|
4261
|
+
return {
|
|
4262
|
+
allowedDomains: tool?.allowed_domains,
|
|
4263
|
+
blockedDomains: tool?.blocked_domains,
|
|
4264
|
+
userLocation: tool?.user_location
|
|
4265
|
+
};
|
|
4266
|
+
};
|
|
4267
|
+
const buildWebSearchResultBlock = (toolUseId, extract) => {
|
|
4268
|
+
return {
|
|
4269
|
+
type: "web_search_tool_result",
|
|
4270
|
+
tool_use_id: toolUseId,
|
|
4271
|
+
content: extract.sources.map((source) => ({
|
|
4272
|
+
type: "web_search_result",
|
|
4273
|
+
url: source.url,
|
|
4274
|
+
title: source.title,
|
|
4275
|
+
page_age: source.page_age ?? null,
|
|
4276
|
+
encrypted_content: ""
|
|
4277
|
+
}))
|
|
4278
|
+
};
|
|
4279
|
+
};
|
|
4280
|
+
/**
|
|
4281
|
+
* Reconstructs a native Anthropic assistant response from the GPT web search
|
|
4282
|
+
* result: one server_tool_use + web_search_tool_result pair, then the answer.
|
|
4283
|
+
*/
|
|
4284
|
+
const buildResponseContent = (requestId, extract) => {
|
|
4285
|
+
const blocks = [];
|
|
4286
|
+
const query = extract.queries[0] ?? "";
|
|
4287
|
+
if (extract.sources.length > 0 || query) {
|
|
4288
|
+
const toolUseId = `srvtoolu_${getUUID(requestId)}`;
|
|
4289
|
+
blocks.push({
|
|
4290
|
+
type: "server_tool_use",
|
|
4291
|
+
id: toolUseId,
|
|
4292
|
+
name: "web_search",
|
|
4293
|
+
input: { query }
|
|
4294
|
+
}, buildWebSearchResultBlock(toolUseId, extract));
|
|
4295
|
+
}
|
|
4296
|
+
blocks.push({
|
|
4297
|
+
type: "text",
|
|
4298
|
+
text: extract.answerText
|
|
4299
|
+
});
|
|
4300
|
+
return blocks;
|
|
4301
|
+
};
|
|
4302
|
+
const prepareWebSearchResponsesPayload = (payload, options = {}) => {
|
|
4303
|
+
const config = extractWebSearchConfig(payload);
|
|
4304
|
+
const responsesPayload = translateAnthropicMessagesToResponsesPayload({
|
|
4305
|
+
...payload,
|
|
4306
|
+
model: options.model ?? payload.model,
|
|
4307
|
+
tools: [],
|
|
4308
|
+
stream: false
|
|
4309
|
+
}, options.subagentAgentId);
|
|
4310
|
+
responsesPayload.tools = [buildResponsesWebSearchTool(config)];
|
|
4311
|
+
responsesPayload.tool_choice = void 0;
|
|
4312
|
+
return responsesPayload;
|
|
4313
|
+
};
|
|
4314
|
+
const reconstructWebSearchResponse = (payload, result, options) => {
|
|
4315
|
+
const extract = extractWebSearchResult(result);
|
|
4316
|
+
return {
|
|
4317
|
+
extract,
|
|
4318
|
+
response: {
|
|
4319
|
+
id: result.id || getUUID(options.requestId),
|
|
4320
|
+
type: "message",
|
|
4321
|
+
role: "assistant",
|
|
4322
|
+
content: buildResponseContent(options.requestId, extract),
|
|
4323
|
+
model: payload.model,
|
|
4324
|
+
stop_reason: "end_turn",
|
|
4325
|
+
stop_sequence: null,
|
|
4326
|
+
usage: {
|
|
4327
|
+
input_tokens: result.usage?.input_tokens ?? 0,
|
|
4328
|
+
output_tokens: result.usage?.output_tokens ?? 0,
|
|
4329
|
+
server_tool_use: { web_search_requests: Math.max(extract.queries.length, 1) }
|
|
4330
|
+
}
|
|
4331
|
+
}
|
|
4332
|
+
};
|
|
4333
|
+
};
|
|
4334
|
+
const createUsageRecorder = (payload, sessionId, webSearchModel) => webSearchFlowDependencies.createUsageRecorder(payload, sessionId, webSearchModel);
|
|
4335
|
+
/**
|
|
4336
|
+
* Handles a web-search-only Claude (Messages API) request by switching it to a
|
|
4337
|
+
* Responses-capable GPT model (`webSearchModel`), running Copilot's native
|
|
4338
|
+
* /responses web_search in a single call, and reconstructing native Anthropic
|
|
4339
|
+
* server_tool_use + web_search_tool_result blocks. Streaming and non-streaming
|
|
4340
|
+
* are both supported (streaming replays the result as a synthetic SSE stream).
|
|
4341
|
+
*/
|
|
4342
|
+
const handleWebSearchViaResponses = async (c, payload, options) => {
|
|
4343
|
+
const { logger, webSearchModel } = options;
|
|
4344
|
+
const wantsStream = Boolean(payload.stream);
|
|
4345
|
+
const responsesPayload = prepareWebSearchResponsesPayload(payload, {
|
|
4346
|
+
model: webSearchModel,
|
|
4347
|
+
subagentAgentId: options.subagentMarker?.agent_id
|
|
4348
|
+
});
|
|
4349
|
+
const selectedModel = findEndpointModel(webSearchModel);
|
|
4350
|
+
const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
|
|
4351
|
+
const transport = getResponsesTransportForModel(selectedModel, { compactType: options.compactType }) ?? "http";
|
|
4352
|
+
logger.debug(`Switching web search request to model: ${webSearchModel} ${JSON.stringify(responsesPayload)}`);
|
|
4353
|
+
const result = await webSearchFlowDependencies.createResponses(responsesPayload, {
|
|
4354
|
+
vision,
|
|
4355
|
+
initiator,
|
|
4356
|
+
transport,
|
|
4357
|
+
subagentMarker: options.subagentMarker,
|
|
4358
|
+
requestId: options.requestId,
|
|
4359
|
+
sessionId: options.sessionId,
|
|
4360
|
+
compactType: options.compactType
|
|
4361
|
+
});
|
|
4362
|
+
const { extract, response } = reconstructWebSearchResponse(payload, result, { requestId: options.requestId });
|
|
4363
|
+
logger.debug(`Web search via responses: ${extract.queries.length} quer(y/ies), ${extract.sources.length} source(s), ${JSON.stringify(result)}`);
|
|
4364
|
+
createUsageRecorder(payload, options.sessionId, webSearchModel)(normalizeResponsesUsage(result.usage));
|
|
4365
|
+
if (!wantsStream) return c.json(response);
|
|
4366
|
+
return streamSSE(c, async (stream) => {
|
|
4367
|
+
for (const event of buildSyntheticStreamEvents(response)) await stream.writeSSE({
|
|
4368
|
+
event: event.type,
|
|
4369
|
+
data: JSON.stringify(event)
|
|
4370
|
+
});
|
|
4371
|
+
});
|
|
4372
|
+
};
|
|
4373
|
+
const blockToStreamEvents = (block, index) => {
|
|
4374
|
+
const start = (contentBlock) => ({
|
|
4375
|
+
type: "content_block_start",
|
|
4376
|
+
index,
|
|
4377
|
+
content_block: contentBlock
|
|
4378
|
+
});
|
|
4379
|
+
const stop = {
|
|
4380
|
+
type: "content_block_stop",
|
|
4381
|
+
index
|
|
4382
|
+
};
|
|
4383
|
+
switch (block.type) {
|
|
4384
|
+
case "text": return [
|
|
4385
|
+
start({
|
|
4386
|
+
type: "text",
|
|
4387
|
+
text: ""
|
|
4388
|
+
}),
|
|
4389
|
+
{
|
|
4390
|
+
type: "content_block_delta",
|
|
4391
|
+
index,
|
|
4392
|
+
delta: {
|
|
4393
|
+
type: "text_delta",
|
|
4394
|
+
text: block.text
|
|
4395
|
+
}
|
|
4396
|
+
},
|
|
4397
|
+
stop
|
|
4398
|
+
];
|
|
4399
|
+
case "server_tool_use": return [
|
|
4400
|
+
start({
|
|
4401
|
+
type: "server_tool_use",
|
|
4402
|
+
id: block.id,
|
|
4403
|
+
name: block.name,
|
|
4404
|
+
input: {}
|
|
4405
|
+
}),
|
|
4406
|
+
{
|
|
4407
|
+
type: "content_block_delta",
|
|
4408
|
+
index,
|
|
4409
|
+
delta: {
|
|
4410
|
+
type: "input_json_delta",
|
|
4411
|
+
partial_json: JSON.stringify(block.input)
|
|
4412
|
+
}
|
|
4413
|
+
},
|
|
4414
|
+
stop
|
|
4415
|
+
];
|
|
4416
|
+
case "web_search_tool_result": return [start(block), stop];
|
|
4417
|
+
default: return [start(block), stop];
|
|
4418
|
+
}
|
|
4419
|
+
};
|
|
4420
|
+
const buildSyntheticStreamEvents = (response) => {
|
|
4421
|
+
const events = [];
|
|
4422
|
+
events.push({
|
|
4423
|
+
type: "message_start",
|
|
4424
|
+
message: {
|
|
4425
|
+
id: response.id,
|
|
4426
|
+
type: "message",
|
|
4427
|
+
role: "assistant",
|
|
4428
|
+
content: [],
|
|
4429
|
+
model: response.model,
|
|
4430
|
+
stop_reason: null,
|
|
4431
|
+
stop_sequence: null,
|
|
4432
|
+
usage: {
|
|
4433
|
+
...response.usage,
|
|
4434
|
+
output_tokens: 0
|
|
4435
|
+
}
|
|
4436
|
+
}
|
|
4437
|
+
});
|
|
4438
|
+
response.content.forEach((block, index) => {
|
|
4439
|
+
events.push(...blockToStreamEvents(block, index));
|
|
4440
|
+
});
|
|
4441
|
+
events.push({
|
|
4442
|
+
type: "message_delta",
|
|
4443
|
+
delta: {
|
|
4444
|
+
stop_reason: response.stop_reason,
|
|
4445
|
+
stop_sequence: response.stop_sequence
|
|
4446
|
+
},
|
|
4447
|
+
usage: { output_tokens: response.usage.output_tokens }
|
|
4448
|
+
}, { type: "message_stop" });
|
|
4449
|
+
return events;
|
|
4450
|
+
};
|
|
4451
|
+
//#endregion
|
|
4152
4452
|
//#region src/services/codex/get-models.ts
|
|
4153
4453
|
const CODEX_MODELS = [
|
|
4154
4454
|
{
|
|
@@ -4244,6 +4544,7 @@ async function handleProviderMessages(c) {
|
|
|
4244
4544
|
}
|
|
4245
4545
|
async function handleProviderMessagesForProvider(c, options) {
|
|
4246
4546
|
const { payload, provider } = options;
|
|
4547
|
+
const webSearchRerouteDepth = options.webSearchRerouteDepth ?? 0;
|
|
4247
4548
|
const providerConfig = await resolveProviderConfig(provider);
|
|
4248
4549
|
if (!providerConfig) return c.json({ error: {
|
|
4249
4550
|
message: `Provider '${provider}' not found or disabled`,
|
|
@@ -4256,19 +4557,41 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
4256
4557
|
provider
|
|
4257
4558
|
});
|
|
4258
4559
|
normalizeSystemMessages(payload);
|
|
4259
|
-
|
|
4260
|
-
if (
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
modelConfig,
|
|
4268
|
-
payload,
|
|
4269
|
-
provider,
|
|
4270
|
-
providerConfig
|
|
4560
|
+
const providerWebSearchRoute = webSearchRerouteDepth === 0 ? resolveProviderWebSearchRoute(payload, { provider }) : null;
|
|
4561
|
+
if (providerWebSearchRoute) return await handleProviderMessagesForProvider(c, {
|
|
4562
|
+
payload: {
|
|
4563
|
+
...payload,
|
|
4564
|
+
model: providerWebSearchRoute.model
|
|
4565
|
+
},
|
|
4566
|
+
provider: providerWebSearchRoute.provider,
|
|
4567
|
+
webSearchRerouteDepth: webSearchRerouteDepth + 1
|
|
4271
4568
|
});
|
|
4569
|
+
applyModelDefaults(payload, modelConfig);
|
|
4570
|
+
if (providerConfig.type === "openai-responses") {
|
|
4571
|
+
if (hasWebSearchServerTool(payload)) {
|
|
4572
|
+
if (isWebSearchOnlyRequest(payload)) return await handleOpenAIResponsesProviderWebSearchMessages(c, {
|
|
4573
|
+
payload,
|
|
4574
|
+
provider,
|
|
4575
|
+
providerConfig
|
|
4576
|
+
});
|
|
4577
|
+
stripWebSearchServerTool(payload);
|
|
4578
|
+
}
|
|
4579
|
+
return await handleOpenAIResponsesProviderMessages(c, {
|
|
4580
|
+
modelConfig,
|
|
4581
|
+
payload,
|
|
4582
|
+
provider,
|
|
4583
|
+
providerConfig
|
|
4584
|
+
});
|
|
4585
|
+
}
|
|
4586
|
+
if (providerConfig.type === "openai-compatible") {
|
|
4587
|
+
stripWebSearchServerTool(payload);
|
|
4588
|
+
return await handleOpenAICompatibleProviderMessages(c, {
|
|
4589
|
+
modelConfig,
|
|
4590
|
+
payload,
|
|
4591
|
+
provider,
|
|
4592
|
+
providerConfig
|
|
4593
|
+
});
|
|
4594
|
+
}
|
|
4272
4595
|
applyMissingExtraBody(payload, { extraBody: modelConfig?.extraBody });
|
|
4273
4596
|
debugJson(logger$5, "Translated provider.messages.request", {
|
|
4274
4597
|
payload,
|
|
@@ -4301,6 +4624,48 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
4301
4624
|
throw error;
|
|
4302
4625
|
}
|
|
4303
4626
|
}
|
|
4627
|
+
const resolveProviderWebSearchRoute = (payload, options) => {
|
|
4628
|
+
if (!hasWebSearchServerTool(payload) || !isWebSearchOnlyRequest(payload)) return null;
|
|
4629
|
+
const configuredModel = getProviderMessageApiWebSearchModel();
|
|
4630
|
+
if (!configuredModel) return null;
|
|
4631
|
+
const alias = parseProviderModelAlias(configuredModel);
|
|
4632
|
+
const provider = alias?.provider ?? options.provider;
|
|
4633
|
+
const model = alias?.model ?? configuredModel;
|
|
4634
|
+
if (provider === options.provider && model === payload.model) return null;
|
|
4635
|
+
return {
|
|
4636
|
+
model,
|
|
4637
|
+
provider
|
|
4638
|
+
};
|
|
4639
|
+
};
|
|
4640
|
+
const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
|
|
4641
|
+
const { payload, provider, providerConfig } = options;
|
|
4642
|
+
const selectedModel = providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0;
|
|
4643
|
+
const responsesPayload = prepareWebSearchResponsesPayload(payload);
|
|
4644
|
+
applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
|
|
4645
|
+
compactInputByLatestCompaction(responsesPayload);
|
|
4646
|
+
debugJson(logger$5, "provider.messages.responses.web_search.request", {
|
|
4647
|
+
payload: responsesPayload,
|
|
4648
|
+
provider
|
|
4649
|
+
});
|
|
4650
|
+
if (providerConfig.name === "codex") return respondWebSearchProviderMessagesJson(c, {
|
|
4651
|
+
body: await forwardCodexResponses(responsesPayload, c.req.raw.headers, providerConfig.baseUrl),
|
|
4652
|
+
payload,
|
|
4653
|
+
provider
|
|
4654
|
+
});
|
|
4655
|
+
const upstreamResponse = await forwardProviderResponses(providerConfig, responsesPayload, c.req.raw.headers);
|
|
4656
|
+
if (!upstreamResponse.ok) {
|
|
4657
|
+
logger$5.error("Failed to create provider web search responses", {
|
|
4658
|
+
provider,
|
|
4659
|
+
upstreamResponse
|
|
4660
|
+
});
|
|
4661
|
+
throw new HTTPError("Failed to create provider web search responses", upstreamResponse);
|
|
4662
|
+
}
|
|
4663
|
+
return respondWebSearchProviderMessagesJson(c, {
|
|
4664
|
+
body: await upstreamResponse.json(),
|
|
4665
|
+
payload,
|
|
4666
|
+
provider
|
|
4667
|
+
});
|
|
4668
|
+
};
|
|
4304
4669
|
const handleOpenAIResponsesProviderMessages = async (c, options) => {
|
|
4305
4670
|
const { payload, provider, providerConfig } = options;
|
|
4306
4671
|
const selectedModel = providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0;
|
|
@@ -4666,6 +5031,19 @@ const respondResponsesProviderMessagesJson = (c, options) => {
|
|
|
4666
5031
|
if (providerConfig.name === "codex") logger$5.debug("provider.messages.codex.no_stream.result");
|
|
4667
5032
|
return c.json(anthropicResponse);
|
|
4668
5033
|
};
|
|
5034
|
+
const respondWebSearchProviderMessagesJson = (c, options) => {
|
|
5035
|
+
const { body, payload, provider } = options;
|
|
5036
|
+
createProviderMessagesUsageRecorder(payload, provider)(normalizeResponsesUsage(body.usage));
|
|
5037
|
+
const { extract, response } = reconstructWebSearchResponse(payload, body, { requestId: body.id || `${provider}:${payload.model}` });
|
|
5038
|
+
logger$5.debug(`provider.messages.responses.web_search: ${extract.queries.length} quer(y/ies), ${extract.sources.length} source(s)`);
|
|
5039
|
+
if (!payload.stream) return c.json(response);
|
|
5040
|
+
return streamSSE(c, async (stream) => {
|
|
5041
|
+
for (const event of buildSyntheticStreamEvents(response)) await stream.writeSSE({
|
|
5042
|
+
event: event.type,
|
|
5043
|
+
data: JSON.stringify(event)
|
|
5044
|
+
});
|
|
5045
|
+
});
|
|
5046
|
+
};
|
|
4669
5047
|
const createProviderMessagesUsageRecorder = (payload, provider) => createProviderTokenUsageRecorder({
|
|
4670
5048
|
endpoint: "provider_messages",
|
|
4671
5049
|
model: payload.model,
|
|
@@ -5043,6 +5421,28 @@ async function handleCompletion(c) {
|
|
|
5043
5421
|
if (state.manualApprove) await awaitApproval();
|
|
5044
5422
|
const selectedModel = findEndpointModel(anthropicPayload.model);
|
|
5045
5423
|
anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
|
|
5424
|
+
if (hasWebSearchServerTool(anthropicPayload)) {
|
|
5425
|
+
const route = resolveWebSearchRoute(anthropicPayload, {
|
|
5426
|
+
webSearchModel: getMessageApiWebSearchModel(),
|
|
5427
|
+
responsesWebSearchEnabled: isResponsesApiWebSearchEnabled()
|
|
5428
|
+
});
|
|
5429
|
+
if (route.kind === "provider") {
|
|
5430
|
+
anthropicPayload.model = route.alias.model;
|
|
5431
|
+
return await handleProviderMessagesForProvider(c, {
|
|
5432
|
+
payload: anthropicPayload,
|
|
5433
|
+
provider: route.alias.provider
|
|
5434
|
+
});
|
|
5435
|
+
}
|
|
5436
|
+
if (route.kind === "responses") return await handleWebSearchViaResponses(c, anthropicPayload, {
|
|
5437
|
+
subagentMarker,
|
|
5438
|
+
webSearchModel: route.model,
|
|
5439
|
+
requestId,
|
|
5440
|
+
sessionId,
|
|
5441
|
+
compactType,
|
|
5442
|
+
logger: logger$4
|
|
5443
|
+
});
|
|
5444
|
+
stripWebSearchServerTool(anthropicPayload);
|
|
5445
|
+
}
|
|
5046
5446
|
if (shouldUseMessagesApi(selectedModel)) return await messagesFlowHandlers.handleWithMessagesApi(c, anthropicPayload, {
|
|
5047
5447
|
anthropicBetaHeader: anthropicBeta,
|
|
5048
5448
|
subagentMarker,
|
|
@@ -5570,4 +5970,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
|
|
|
5570
5970
|
//#endregion
|
|
5571
5971
|
export { server };
|
|
5572
5972
|
|
|
5573
|
-
//# sourceMappingURL=server-
|
|
5973
|
+
//# sourceMappingURL=server-xtwGZKXj.js.map
|