@jeffreycao/copilot-api 1.10.35 → 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.
@@ -1,5 +1,5 @@
1
- import { _ as resolveMappedModel, a as getModelMappings, b as PATHS, c as getRawProviderConfig, d as isMessagesApiEnabled, f as isResponsesApiContextManagementEnabled, i as getExtraPromptForModel, l as getReasoningEffortForModel, m as isResponsesApiWebSocketEnabled, n as getClaudeTokenMultiplier, o as getModelResponsesApiCompactThreshold$1, p as isResponsesApiWebSearchEnabled, r as getConfig, s as getProviderConfig, t as getAnthropicApiKey, u as getSmallModel, v as setModelMappings } from "./config-CgDUUqnp.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-DOY13eB0.js";
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
- applyModelDefaults(payload, modelConfig);
4260
- if (providerConfig.type === "openai-responses") return await handleOpenAIResponsesProviderMessages(c, {
4261
- modelConfig,
4262
- payload,
4263
- provider,
4264
- providerConfig
4265
- });
4266
- if (providerConfig.type === "openai-compatible") return await handleOpenAICompatibleProviderMessages(c, {
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-BURXrRxA.js.map
5973
+ //# sourceMappingURL=server-xtwGZKXj.js.map