@jeffreycao/copilot-api 1.10.36 → 1.11.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.
@@ -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-CHTEbXZd.js";
1
+ import { a as getMessageApiWebSearchModel, c as getProviderConfig, d as getSmallModel, f as isMessagesApiEnabled, h as isResponsesApiWebSocketEnabled, i as getExtraPromptForModel, l as getRawProviderConfig, m as isResponsesApiWebSearchEnabled, n as getClaudeTokenMultiplier, o as getModelMappings, p as isResponsesApiContextManagementEnabled, r as getConfig, s as getModelResponsesApiCompactThreshold$1, t as getAnthropicApiKey, u as getReasoningEffortForModel, v as resolveMappedModel, x as PATHS, y as setModelMappings } from "./config-DA-Jdm0G.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-mo4KkQSp.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),
@@ -4001,6 +4004,52 @@ const stringifyToolSearchArguments = (argumentsValue) => {
4001
4004
  return;
4002
4005
  }
4003
4006
  };
4007
+ //#endregion
4008
+ //#region src/lib/subagent.ts
4009
+ const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
4010
+ //#endregion
4011
+ //#region src/routes/messages/subagent-marker.ts
4012
+ const parseSubagentMarkerFromFirstUser = (payload) => {
4013
+ const firstUserMessage = payload.messages.find((msg) => msg.role === "user" && Array.isArray(msg.content));
4014
+ if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return null;
4015
+ for (const block of firstUserMessage.content) {
4016
+ if (block.type !== "text") continue;
4017
+ const marker = parseSubagentMarkerFromSystemReminder(block.text);
4018
+ if (marker) return marker;
4019
+ }
4020
+ return null;
4021
+ };
4022
+ const parseSubagentMarkerFromSystemReminder = (text) => {
4023
+ const startTag = "<system-reminder>";
4024
+ const endTag = "</system-reminder>";
4025
+ let searchFrom = 0;
4026
+ while (true) {
4027
+ const reminderStart = text.indexOf(startTag, searchFrom);
4028
+ if (reminderStart === -1) break;
4029
+ const contentStart = reminderStart + 17;
4030
+ const reminderEnd = text.indexOf(endTag, contentStart);
4031
+ if (reminderEnd === -1) break;
4032
+ const reminderContent = text.slice(contentStart, reminderEnd);
4033
+ const markerIndex = reminderContent.indexOf(subagentMarkerPrefix);
4034
+ if (markerIndex === -1) {
4035
+ searchFrom = reminderEnd + 18;
4036
+ continue;
4037
+ }
4038
+ const markerJson = reminderContent.slice(markerIndex + 19).trim();
4039
+ try {
4040
+ const parsed = JSON.parse(markerJson);
4041
+ if (!parsed.session_id || !parsed.agent_id || !parsed.agent_type) {
4042
+ searchFrom = reminderEnd + 18;
4043
+ continue;
4044
+ }
4045
+ return parsed;
4046
+ } catch {
4047
+ searchFrom = reminderEnd + 18;
4048
+ continue;
4049
+ }
4050
+ }
4051
+ return null;
4052
+ };
4004
4053
  const DEFAULT_RESPONSES_COMPACT_THRESHOLD_RATIO = .9;
4005
4054
  const responsesUtilsDependencies = {
4006
4055
  getModelResponsesApiCompactThreshold: getModelResponsesApiCompactThreshold$1,
@@ -4149,6 +4198,340 @@ const containsVisionContent = (value) => {
4149
4198
  return false;
4150
4199
  };
4151
4200
  //#endregion
4201
+ //#region src/routes/messages/web-search/backend.ts
4202
+ /** Builds the Responses API web_search tool object from the Anthropic config. */
4203
+ const buildResponsesWebSearchTool = (config) => {
4204
+ const tool = { type: "web_search" };
4205
+ const filters = {};
4206
+ if (config.allowedDomains?.length) filters.allowed_domains = config.allowedDomains;
4207
+ if (config.blockedDomains?.length) filters.blocked_domains = config.blockedDomains;
4208
+ if (Object.keys(filters).length > 0) tool.filters = filters;
4209
+ if (config.userLocation) tool.user_location = config.userLocation;
4210
+ return tool;
4211
+ };
4212
+ const isMessageItem = (item) => item.type === "message";
4213
+ const isValidUrlCitation = (annotation, seenUrls) => {
4214
+ const ann = annotation;
4215
+ return ann.type === "url_citation" && Boolean(ann.url) && !seenUrls.has(ann.url);
4216
+ };
4217
+ const collectTextParts = (blocks, seenUrls) => {
4218
+ const textParts = [];
4219
+ const sources = [];
4220
+ for (const block of blocks ?? []) {
4221
+ if (block.type !== "output_text") continue;
4222
+ if (block.text) textParts.push(block.text);
4223
+ for (const annotation of block.annotations ?? []) {
4224
+ if (!isValidUrlCitation(annotation, seenUrls)) continue;
4225
+ const ann = annotation;
4226
+ seenUrls.add(ann.url);
4227
+ sources.push({
4228
+ url: ann.url,
4229
+ title: ann.title ?? ann.url
4230
+ });
4231
+ }
4232
+ }
4233
+ return {
4234
+ textParts,
4235
+ sources
4236
+ };
4237
+ };
4238
+ const collectQuery = (item, queries) => {
4239
+ if (item.action?.queries?.length) queries.push(...item.action.queries);
4240
+ else if (item.action?.query) queries.push(item.action.query);
4241
+ };
4242
+ /**
4243
+ * Extracts the answer text, deduped sources, and run queries from a GPT
4244
+ * /responses web_search result.
4245
+ */
4246
+ const extractWebSearchResult = (result) => {
4247
+ const textParts = [];
4248
+ const sources = [];
4249
+ const seenUrls = /* @__PURE__ */ new Set();
4250
+ const queries = [];
4251
+ for (const item of result.output) {
4252
+ if (isMessageItem(item)) {
4253
+ const collected = collectTextParts(item.content, seenUrls);
4254
+ textParts.push(...collected.textParts);
4255
+ sources.push(...collected.sources);
4256
+ continue;
4257
+ }
4258
+ if (item.type === "web_search_call") collectQuery(item, queries);
4259
+ }
4260
+ return {
4261
+ answerText: textParts.join("\n\n").trim() || (result.output_text ?? "").trim(),
4262
+ sources,
4263
+ queries
4264
+ };
4265
+ };
4266
+ //#endregion
4267
+ //#region src/routes/messages/web-search/fulfill.ts
4268
+ const webSearchFlowDependencies = {
4269
+ createResponses,
4270
+ createUsageRecorder: (payload, sessionId, webSearchModel) => createCopilotTokenUsageRecorder({
4271
+ endpoint: "responses",
4272
+ fallbackSessionId: sessionId,
4273
+ model: webSearchModel ?? payload.model,
4274
+ sessionId: parseUserIdMetadata(payload.metadata?.user_id).sessionId
4275
+ })
4276
+ };
4277
+ const isWebSearchServerTool = (tool) => typeof tool.type === "string" && tool.type.startsWith("web_search") && !tool.input_schema;
4278
+ /** True when the payload carries an Anthropic server-side web_search tool. */
4279
+ const hasWebSearchServerTool = (payload) => Array.isArray(payload.tools) && payload.tools.some(isWebSearchServerTool);
4280
+ /**
4281
+ * True when web_search is the ONLY tool in the request. Mixing web_search with
4282
+ * other tools is intentionally unsupported, so only these requests are switched
4283
+ * to the web search model.
4284
+ */
4285
+ const isWebSearchOnlyRequest = (payload) => Array.isArray(payload.tools) && payload.tools.length > 0 && payload.tools.every(isWebSearchServerTool);
4286
+ /** Removes web_search server tools (used for unsupported mixed-tool requests). */
4287
+ const stripWebSearchServerTool = (payload) => {
4288
+ if (!Array.isArray(payload.tools)) return;
4289
+ payload.tools = payload.tools.filter((tool) => !isWebSearchServerTool(tool));
4290
+ };
4291
+ const resolveWebSearchRoute = (payload, options) => {
4292
+ const { webSearchModel, responsesWebSearchEnabled } = options;
4293
+ if (!webSearchModel || !isWebSearchOnlyRequest(payload)) return { kind: "strip" };
4294
+ const alias = parseProviderModelAlias(webSearchModel);
4295
+ if (alias) return {
4296
+ kind: "provider",
4297
+ alias
4298
+ };
4299
+ if (responsesWebSearchEnabled) return {
4300
+ kind: "responses",
4301
+ model: webSearchModel
4302
+ };
4303
+ return { kind: "strip" };
4304
+ };
4305
+ const extractWebSearchConfig = (payload) => {
4306
+ const tool = payload.tools?.find(isWebSearchServerTool);
4307
+ return {
4308
+ allowedDomains: tool?.allowed_domains,
4309
+ blockedDomains: tool?.blocked_domains,
4310
+ userLocation: tool?.user_location
4311
+ };
4312
+ };
4313
+ const buildWebSearchResultBlock = (toolUseId, extract) => {
4314
+ return {
4315
+ type: "web_search_tool_result",
4316
+ tool_use_id: toolUseId,
4317
+ content: extract.sources.map((source) => ({
4318
+ type: "web_search_result",
4319
+ url: source.url,
4320
+ title: source.title,
4321
+ page_age: source.page_age ?? null,
4322
+ encrypted_content: ""
4323
+ }))
4324
+ };
4325
+ };
4326
+ /**
4327
+ * Reconstructs a native Anthropic assistant response from the GPT web search
4328
+ * result: one server_tool_use + web_search_tool_result pair, then the answer.
4329
+ */
4330
+ const buildResponseContent = (requestId, extract) => {
4331
+ const blocks = [];
4332
+ const query = extract.queries[0] ?? "";
4333
+ if (extract.sources.length > 0 || query) {
4334
+ const toolUseId = `srvtoolu_${getUUID(requestId)}`;
4335
+ blocks.push({
4336
+ type: "server_tool_use",
4337
+ id: toolUseId,
4338
+ name: "web_search",
4339
+ input: { query }
4340
+ }, buildWebSearchResultBlock(toolUseId, extract));
4341
+ }
4342
+ blocks.push({
4343
+ type: "text",
4344
+ text: extract.answerText
4345
+ });
4346
+ return blocks;
4347
+ };
4348
+ const prepareWebSearchResponsesPayload = (payload, options = {}) => {
4349
+ const config = extractWebSearchConfig(payload);
4350
+ const responsesPayload = translateAnthropicMessagesToResponsesPayload({
4351
+ ...payload,
4352
+ model: options.model ?? payload.model,
4353
+ tools: [],
4354
+ stream: false
4355
+ }, options.subagentAgentId);
4356
+ responsesPayload.tools = [buildResponsesWebSearchTool(config)];
4357
+ responsesPayload.tool_choice = void 0;
4358
+ return responsesPayload;
4359
+ };
4360
+ const reconstructWebSearchResponse = (payload, result, options) => {
4361
+ const extract = extractWebSearchResult(result);
4362
+ return {
4363
+ extract,
4364
+ response: {
4365
+ id: result.id || getUUID(options.requestId),
4366
+ type: "message",
4367
+ role: "assistant",
4368
+ content: buildResponseContent(options.requestId, extract),
4369
+ model: payload.model,
4370
+ stop_reason: "end_turn",
4371
+ stop_sequence: null,
4372
+ usage: {
4373
+ input_tokens: result.usage?.input_tokens ?? 0,
4374
+ output_tokens: result.usage?.output_tokens ?? 0,
4375
+ server_tool_use: { web_search_requests: Math.max(extract.queries.length, 1) }
4376
+ }
4377
+ }
4378
+ };
4379
+ };
4380
+ const createUsageRecorder = (payload, sessionId, webSearchModel) => webSearchFlowDependencies.createUsageRecorder(payload, sessionId, webSearchModel);
4381
+ /**
4382
+ * Entry point for web-search detection and routing on /v1/messages.
4383
+ * Called after model mapping but before provider alias resolution and
4384
+ * preprocessing. Returns a Response when web search is handled (provider
4385
+ * reroute or responses-native), or `null` when no web_search tool is
4386
+ * present or the tool was stripped (caller continues normal flow).
4387
+ *
4388
+ * Uses a callback for provider forwarding to avoid circular imports.
4389
+ */
4390
+ const tryHandleWebSearch = async (c, payload, options) => {
4391
+ if (!hasWebSearchServerTool(payload)) return null;
4392
+ const route = resolveWebSearchRoute(payload, {
4393
+ webSearchModel: getMessageApiWebSearchModel(),
4394
+ responsesWebSearchEnabled: isResponsesApiWebSearchEnabled()
4395
+ });
4396
+ if (route.kind === "provider") {
4397
+ payload.model = route.alias.model;
4398
+ return await options.forwardToProvider(c, payload, route.alias.provider);
4399
+ }
4400
+ if (route.kind === "responses") {
4401
+ const subagentMarker = parseSubagentMarkerFromFirstUser(payload);
4402
+ let sessionId = getRootSessionId(payload, c);
4403
+ const requestId = generateRequestIdFromPayload(payload, sessionId);
4404
+ if (!sessionId) sessionId = getUUID(requestId);
4405
+ const compactType = getCompactType(payload);
4406
+ return await handleWebSearchViaResponses(c, payload, {
4407
+ subagentMarker,
4408
+ webSearchModel: route.model,
4409
+ requestId,
4410
+ sessionId,
4411
+ compactType,
4412
+ logger: options.logger
4413
+ });
4414
+ }
4415
+ stripWebSearchServerTool(payload);
4416
+ return null;
4417
+ };
4418
+ /**
4419
+ * Handles a web-search-only Claude (Messages API) request by switching it to a
4420
+ * Responses-capable GPT model (`webSearchModel`), running Copilot's native
4421
+ * /responses web_search in a single call, and reconstructing native Anthropic
4422
+ * server_tool_use + web_search_tool_result blocks. Streaming and non-streaming
4423
+ * are both supported (streaming replays the result as a synthetic SSE stream).
4424
+ */
4425
+ const handleWebSearchViaResponses = async (c, payload, options) => {
4426
+ const { logger, webSearchModel } = options;
4427
+ const wantsStream = Boolean(payload.stream);
4428
+ const responsesPayload = prepareWebSearchResponsesPayload(payload, {
4429
+ model: webSearchModel,
4430
+ subagentAgentId: options.subagentMarker?.agent_id
4431
+ });
4432
+ const selectedModel = findEndpointModel(webSearchModel);
4433
+ const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
4434
+ const transport = getResponsesTransportForModel(selectedModel, { compactType: options.compactType }) ?? "http";
4435
+ logger.debug(`Switching web search request to model: ${webSearchModel} ${JSON.stringify(responsesPayload)}`);
4436
+ const result = await webSearchFlowDependencies.createResponses(responsesPayload, {
4437
+ vision,
4438
+ initiator,
4439
+ transport,
4440
+ subagentMarker: options.subagentMarker,
4441
+ requestId: options.requestId,
4442
+ sessionId: options.sessionId,
4443
+ compactType: options.compactType
4444
+ });
4445
+ const { extract, response } = reconstructWebSearchResponse(payload, result, { requestId: options.requestId });
4446
+ logger.debug(`Web search via responses: ${extract.queries.length} quer(y/ies), ${extract.sources.length} source(s), ${JSON.stringify(result)}`);
4447
+ createUsageRecorder(payload, options.sessionId, webSearchModel)(normalizeResponsesUsage(result.usage));
4448
+ if (!wantsStream) return c.json(response);
4449
+ return streamSSE(c, async (stream) => {
4450
+ for (const event of buildSyntheticStreamEvents(response)) await stream.writeSSE({
4451
+ event: event.type,
4452
+ data: JSON.stringify(event)
4453
+ });
4454
+ });
4455
+ };
4456
+ const blockToStreamEvents = (block, index) => {
4457
+ const start = (contentBlock) => ({
4458
+ type: "content_block_start",
4459
+ index,
4460
+ content_block: contentBlock
4461
+ });
4462
+ const stop = {
4463
+ type: "content_block_stop",
4464
+ index
4465
+ };
4466
+ switch (block.type) {
4467
+ case "text": return [
4468
+ start({
4469
+ type: "text",
4470
+ text: ""
4471
+ }),
4472
+ {
4473
+ type: "content_block_delta",
4474
+ index,
4475
+ delta: {
4476
+ type: "text_delta",
4477
+ text: block.text
4478
+ }
4479
+ },
4480
+ stop
4481
+ ];
4482
+ case "server_tool_use": return [
4483
+ start({
4484
+ type: "server_tool_use",
4485
+ id: block.id,
4486
+ name: block.name,
4487
+ input: {}
4488
+ }),
4489
+ {
4490
+ type: "content_block_delta",
4491
+ index,
4492
+ delta: {
4493
+ type: "input_json_delta",
4494
+ partial_json: JSON.stringify(block.input)
4495
+ }
4496
+ },
4497
+ stop
4498
+ ];
4499
+ case "web_search_tool_result": return [start(block), stop];
4500
+ default: return [start(block), stop];
4501
+ }
4502
+ };
4503
+ const buildSyntheticStreamEvents = (response) => {
4504
+ const events = [];
4505
+ events.push({
4506
+ type: "message_start",
4507
+ message: {
4508
+ id: response.id,
4509
+ type: "message",
4510
+ role: "assistant",
4511
+ content: [],
4512
+ model: response.model,
4513
+ stop_reason: null,
4514
+ stop_sequence: null,
4515
+ usage: {
4516
+ ...response.usage,
4517
+ output_tokens: 0
4518
+ }
4519
+ }
4520
+ });
4521
+ response.content.forEach((block, index) => {
4522
+ events.push(...blockToStreamEvents(block, index));
4523
+ });
4524
+ events.push({
4525
+ type: "message_delta",
4526
+ delta: {
4527
+ stop_reason: response.stop_reason,
4528
+ stop_sequence: response.stop_sequence
4529
+ },
4530
+ usage: { output_tokens: response.usage.output_tokens }
4531
+ }, { type: "message_stop" });
4532
+ return events;
4533
+ };
4534
+ //#endregion
4152
4535
  //#region src/services/codex/get-models.ts
4153
4536
  const CODEX_MODELS = [
4154
4537
  {
@@ -4257,18 +4640,31 @@ async function handleProviderMessagesForProvider(c, options) {
4257
4640
  });
4258
4641
  normalizeSystemMessages(payload);
4259
4642
  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
4271
- });
4643
+ if (providerConfig.type === "openai-responses") {
4644
+ if (hasWebSearchServerTool(payload)) {
4645
+ if (isWebSearchOnlyRequest(payload)) return await handleOpenAIResponsesProviderWebSearchMessages(c, {
4646
+ payload,
4647
+ provider,
4648
+ providerConfig
4649
+ });
4650
+ stripWebSearchServerTool(payload);
4651
+ }
4652
+ return await handleOpenAIResponsesProviderMessages(c, {
4653
+ modelConfig,
4654
+ payload,
4655
+ provider,
4656
+ providerConfig
4657
+ });
4658
+ }
4659
+ if (providerConfig.type === "openai-compatible") {
4660
+ stripWebSearchServerTool(payload);
4661
+ return await handleOpenAICompatibleProviderMessages(c, {
4662
+ modelConfig,
4663
+ payload,
4664
+ provider,
4665
+ providerConfig
4666
+ });
4667
+ }
4272
4668
  applyMissingExtraBody(payload, { extraBody: modelConfig?.extraBody });
4273
4669
  debugJson(logger$5, "Translated provider.messages.request", {
4274
4670
  payload,
@@ -4301,6 +4697,35 @@ async function handleProviderMessagesForProvider(c, options) {
4301
4697
  throw error;
4302
4698
  }
4303
4699
  }
4700
+ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
4701
+ const { payload, provider, providerConfig } = options;
4702
+ const selectedModel = providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0;
4703
+ const responsesPayload = prepareWebSearchResponsesPayload(payload);
4704
+ applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
4705
+ compactInputByLatestCompaction(responsesPayload);
4706
+ debugJson(logger$5, "provider.messages.responses.web_search.request", {
4707
+ payload: responsesPayload,
4708
+ provider
4709
+ });
4710
+ if (providerConfig.name === "codex") return respondWebSearchProviderMessagesJson(c, {
4711
+ body: await forwardCodexResponses(responsesPayload, c.req.raw.headers, providerConfig.baseUrl),
4712
+ payload,
4713
+ provider
4714
+ });
4715
+ const upstreamResponse = await forwardProviderResponses(providerConfig, responsesPayload, c.req.raw.headers);
4716
+ if (!upstreamResponse.ok) {
4717
+ logger$5.error("Failed to create provider web search responses", {
4718
+ provider,
4719
+ upstreamResponse
4720
+ });
4721
+ throw new HTTPError("Failed to create provider web search responses", upstreamResponse);
4722
+ }
4723
+ return respondWebSearchProviderMessagesJson(c, {
4724
+ body: await upstreamResponse.json(),
4725
+ payload,
4726
+ provider
4727
+ });
4728
+ };
4304
4729
  const handleOpenAIResponsesProviderMessages = async (c, options) => {
4305
4730
  const { payload, provider, providerConfig } = options;
4306
4731
  const selectedModel = providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0;
@@ -4666,6 +5091,19 @@ const respondResponsesProviderMessagesJson = (c, options) => {
4666
5091
  if (providerConfig.name === "codex") logger$5.debug("provider.messages.codex.no_stream.result");
4667
5092
  return c.json(anthropicResponse);
4668
5093
  };
5094
+ const respondWebSearchProviderMessagesJson = (c, options) => {
5095
+ const { body, payload, provider } = options;
5096
+ createProviderMessagesUsageRecorder(payload, provider)(normalizeResponsesUsage(body.usage));
5097
+ const { extract, response } = reconstructWebSearchResponse(payload, body, { requestId: body.id || `${provider}:${payload.model}` });
5098
+ logger$5.debug(`provider.messages.responses.web_search: ${extract.queries.length} quer(y/ies), ${extract.sources.length} source(s)`);
5099
+ if (!payload.stream) return c.json(response);
5100
+ return streamSSE(c, async (stream) => {
5101
+ for (const event of buildSyntheticStreamEvents(response)) await stream.writeSSE({
5102
+ event: event.type,
5103
+ data: JSON.stringify(event)
5104
+ });
5105
+ });
5106
+ };
4669
5107
  const createProviderMessagesUsageRecorder = (payload, provider) => createProviderTokenUsageRecorder({
4670
5108
  endpoint: "provider_messages",
4671
5109
  model: payload.model,
@@ -4951,52 +5389,6 @@ const parseAnthropicStreamEvent = (data) => {
4951
5389
  }
4952
5390
  };
4953
5391
  //#endregion
4954
- //#region src/lib/subagent.ts
4955
- const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
4956
- //#endregion
4957
- //#region src/routes/messages/subagent-marker.ts
4958
- const parseSubagentMarkerFromFirstUser = (payload) => {
4959
- const firstUserMessage = payload.messages.find((msg) => msg.role === "user" && Array.isArray(msg.content));
4960
- if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return null;
4961
- for (const block of firstUserMessage.content) {
4962
- if (block.type !== "text") continue;
4963
- const marker = parseSubagentMarkerFromSystemReminder(block.text);
4964
- if (marker) return marker;
4965
- }
4966
- return null;
4967
- };
4968
- const parseSubagentMarkerFromSystemReminder = (text) => {
4969
- const startTag = "<system-reminder>";
4970
- const endTag = "</system-reminder>";
4971
- let searchFrom = 0;
4972
- while (true) {
4973
- const reminderStart = text.indexOf(startTag, searchFrom);
4974
- if (reminderStart === -1) break;
4975
- const contentStart = reminderStart + 17;
4976
- const reminderEnd = text.indexOf(endTag, contentStart);
4977
- if (reminderEnd === -1) break;
4978
- const reminderContent = text.slice(contentStart, reminderEnd);
4979
- const markerIndex = reminderContent.indexOf(subagentMarkerPrefix);
4980
- if (markerIndex === -1) {
4981
- searchFrom = reminderEnd + 18;
4982
- continue;
4983
- }
4984
- const markerJson = reminderContent.slice(markerIndex + 19).trim();
4985
- try {
4986
- const parsed = JSON.parse(markerJson);
4987
- if (!parsed.session_id || !parsed.agent_id || !parsed.agent_type) {
4988
- searchFrom = reminderEnd + 18;
4989
- continue;
4990
- }
4991
- return parsed;
4992
- } catch {
4993
- searchFrom = reminderEnd + 18;
4994
- continue;
4995
- }
4996
- }
4997
- return null;
4998
- };
4999
- //#endregion
5000
5392
  //#region src/routes/messages/handler.ts
5001
5393
  const logger$4 = createHandlerLogger("messages-handler");
5002
5394
  const messagesFlowHandlers = {
@@ -5009,6 +5401,14 @@ async function handleCompletion(c) {
5009
5401
  const requestedModel = anthropicPayload.model;
5010
5402
  anthropicPayload.model = resolveMappedModel(anthropicPayload.model);
5011
5403
  if (anthropicPayload.model !== requestedModel) consola.debug(`Resolved model mapping: ${requestedModel} -> ${anthropicPayload.model}`);
5404
+ const webSearchResult = await tryHandleWebSearch(c, anthropicPayload, {
5405
+ logger: logger$4,
5406
+ forwardToProvider: (ctx, payload, provider) => handleProviderMessagesForProvider(ctx, {
5407
+ payload,
5408
+ provider
5409
+ })
5410
+ });
5411
+ if (webSearchResult) return webSearchResult;
5012
5412
  const providerModelAlias = parseProviderModelAlias(anthropicPayload.model);
5013
5413
  if (providerModelAlias) {
5014
5414
  anthropicPayload.model = providerModelAlias.model;
@@ -5570,4 +5970,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
5570
5970
  //#endregion
5571
5971
  export { server };
5572
5972
 
5573
- //# sourceMappingURL=server-DYlw1xSW.js.map
5973
+ //# sourceMappingURL=server-BxCf-DN5.js.map