@jeffreycao/copilot-api 1.11.1 → 1.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -43,7 +43,7 @@ const { auth } = await import("./auth-D3ta3JW0.js");
43
43
  const { checkUsage } = await import("./check-usage-Dh0WqiLC.js");
44
44
  const { debug } = await import("./debug-BiX0ewij.js");
45
45
  const { mcp } = await import("./mcp-DZgcvqQY.js");
46
- const { start } = await import("./start-CFeefs3X.js");
46
+ const { start } = await import("./start-CUCHCtOg.js");
47
47
  await runMain(defineCommand({
48
48
  meta: {
49
49
  name: "copilot-api",
@@ -4351,7 +4351,7 @@ const prepareWebSearchResponsesPayload = (payload, options = {}) => {
4351
4351
  ...payload,
4352
4352
  model: options.model ?? payload.model,
4353
4353
  tools: [],
4354
- stream: false
4354
+ stream: true
4355
4355
  }, options.subagentAgentId);
4356
4356
  responsesPayload.tools = [buildResponsesWebSearchTool(config)];
4357
4357
  responsesPayload.tool_choice = void 0;
@@ -4377,6 +4377,143 @@ const reconstructWebSearchResponse = (payload, result, options) => {
4377
4377
  }
4378
4378
  };
4379
4379
  };
4380
+ const collectWebSearchResponsesStreamResult = async ({ errorMessagePrefix = "Web search responses stream", parseEvent = parseWebSearchResponsesStreamEvent, upstreamResponse, logger }) => {
4381
+ const state = createWebSearchResponsesStreamCollection();
4382
+ for await (const chunk of upstreamResponse) {
4383
+ debugJson(logger, "Received web search responses stream chunk:", chunk.data);
4384
+ if (chunk.event === "ping") continue;
4385
+ if (!chunk.data || chunk.data === "[DONE]") continue;
4386
+ const parsed = parseEvent(chunk.data);
4387
+ if (!parsed) continue;
4388
+ collectWebSearchResponsesStreamEvent(parsed, state);
4389
+ if (parsed.type === "error") throw new Error(getStreamErrorMessage(parsed) ?? `${errorMessagePrefix} failed`);
4390
+ if (isResponsesTerminalEvent(parsed)) return buildWebSearchResponsesStreamResult(state);
4391
+ }
4392
+ throw new Error(`${errorMessagePrefix} ended without a terminal event`);
4393
+ };
4394
+ const parseWebSearchResponsesStreamEvent = (data) => {
4395
+ try {
4396
+ return JSON.parse(data);
4397
+ } catch {
4398
+ return null;
4399
+ }
4400
+ };
4401
+ const isWebSearchResponsesStream = (value) => {
4402
+ return Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
4403
+ };
4404
+ const isResponsesTerminalEvent = (event) => (event.type === "response.completed" || event.type === "response.failed" || event.type === "response.incomplete") && getResponsesResult(event.response) !== void 0;
4405
+ const createWebSearchResponsesStreamCollection = () => ({
4406
+ outputItemsByIndex: /* @__PURE__ */ new Map(),
4407
+ textPartsByKey: /* @__PURE__ */ new Map()
4408
+ });
4409
+ const collectWebSearchResponsesStreamEvent = (event, state) => {
4410
+ if (event.type === "response.created") {
4411
+ state.createdResponse = getResponsesResult(event.response);
4412
+ return;
4413
+ }
4414
+ if (isResponsesTerminalEvent(event)) {
4415
+ state.terminalResponse = event.response;
4416
+ return;
4417
+ }
4418
+ if (event.type === "response.output_item.added" || event.type === "response.output_item.done") {
4419
+ const outputIndex = getNumber(event.output_index);
4420
+ const item = getRecord(event.item);
4421
+ if (outputIndex !== void 0 && item) state.outputItemsByIndex.set(outputIndex, item);
4422
+ return;
4423
+ }
4424
+ if (event.type === "response.output_text.delta") {
4425
+ const part = getOrCreateOutputTextPart(event, state);
4426
+ const delta = getString(event.delta);
4427
+ if (part && delta) part.text += delta;
4428
+ return;
4429
+ }
4430
+ if (event.type === "response.output_text.done") {
4431
+ const part = getOrCreateOutputTextPart(event, state);
4432
+ const text = getString(event.text);
4433
+ if (part && text !== void 0) part.text = text;
4434
+ return;
4435
+ }
4436
+ if (event.type === "response.output_text.annotation.added") {
4437
+ const part = getOrCreateOutputTextPart(event, state);
4438
+ const annotation = event.annotation;
4439
+ if (part && annotation !== void 0) part.annotations.push(annotation);
4440
+ return;
4441
+ }
4442
+ if (event.type === "response.content_part.done") collectDoneContentPart(event, state);
4443
+ };
4444
+ const buildWebSearchResponsesStreamResult = (state) => {
4445
+ const response = state.terminalResponse ?? state.createdResponse;
4446
+ if (!response) throw new Error("Web search responses stream ended without a response");
4447
+ const output = buildCollectedWebSearchOutput(state);
4448
+ return {
4449
+ ...response,
4450
+ output: output.length > 0 ? output : response.output
4451
+ };
4452
+ };
4453
+ const buildCollectedWebSearchOutput = (state) => [...state.outputItemsByIndex.entries()].sort(([leftIndex], [rightIndex]) => leftIndex - rightIndex).map(([outputIndex, item]) => mergeOutputItemWithCollectedText(outputIndex, item, state));
4454
+ const mergeOutputItemWithCollectedText = (outputIndex, item, state) => {
4455
+ if (item.type !== "message") return item;
4456
+ const collectedParts = getCollectedTextParts(outputIndex, state);
4457
+ if (collectedParts.length === 0) return item;
4458
+ const content = getArray(item.content);
4459
+ for (const part of collectedParts) {
4460
+ const existingPart = getRecord(content[part.contentIndex]);
4461
+ content[part.contentIndex] = {
4462
+ ...existingPart,
4463
+ type: "output_text",
4464
+ text: part.text,
4465
+ annotations: mergeAnnotations(existingPart?.annotations, part.annotations)
4466
+ };
4467
+ }
4468
+ return {
4469
+ ...item,
4470
+ content
4471
+ };
4472
+ };
4473
+ const collectDoneContentPart = (event, state) => {
4474
+ const partRecord = getRecord(getRecord(event)?.part);
4475
+ if (partRecord?.type !== "output_text") return;
4476
+ const part = getOrCreateOutputTextPart(event, state);
4477
+ if (!part) return;
4478
+ const text = getString(partRecord.text);
4479
+ if (text !== void 0) part.text = text;
4480
+ const annotations = getArray(partRecord.annotations);
4481
+ if (annotations.length > 0) part.annotations.push(...annotations);
4482
+ };
4483
+ const getOrCreateOutputTextPart = (event, state) => {
4484
+ const eventRecord = getRecord(event);
4485
+ const outputIndex = getNumber(eventRecord?.output_index);
4486
+ const contentIndex = getNumber(eventRecord?.content_index);
4487
+ if (outputIndex === void 0 || contentIndex === void 0) return;
4488
+ const key = `${outputIndex}:${contentIndex}`;
4489
+ let part = state.textPartsByKey.get(key);
4490
+ if (!part) {
4491
+ part = {
4492
+ annotations: [],
4493
+ contentIndex,
4494
+ itemId: getString(eventRecord?.item_id),
4495
+ outputIndex,
4496
+ text: ""
4497
+ };
4498
+ state.textPartsByKey.set(key, part);
4499
+ }
4500
+ return part;
4501
+ };
4502
+ const getCollectedTextParts = (outputIndex, state) => [...state.textPartsByKey.values()].filter((part) => part.outputIndex === outputIndex).sort((left, right) => left.contentIndex - right.contentIndex || (left.itemId ?? "").localeCompare(right.itemId ?? ""));
4503
+ const mergeAnnotations = (existingAnnotations, collectedAnnotations) => {
4504
+ const annotations = getArray(existingAnnotations);
4505
+ annotations.push(...collectedAnnotations);
4506
+ return annotations;
4507
+ };
4508
+ const getResponsesResult = (value) => getRecord(value);
4509
+ const getRecord = (value) => value && typeof value === "object" ? value : void 0;
4510
+ const getArray = (value) => Array.isArray(value) ? Array.from(value) : [];
4511
+ const getStreamErrorMessage = (event) => {
4512
+ const eventRecord = getRecord(event);
4513
+ return getString(getRecord(eventRecord?.error)?.message) ?? getString(eventRecord?.message);
4514
+ };
4515
+ const getNumber = (value) => typeof value === "number" ? value : void 0;
4516
+ const getString = (value) => typeof value === "string" ? value : void 0;
4380
4517
  const createUsageRecorder = (payload, sessionId, webSearchModel) => webSearchFlowDependencies.createUsageRecorder(payload, sessionId, webSearchModel);
4381
4518
  /**
4382
4519
  * Entry point for web-search detection and routing on /v1/messages.
@@ -4432,8 +4569,8 @@ const handleWebSearchViaResponses = async (c, payload, options) => {
4432
4569
  const selectedModel = findEndpointModel(webSearchModel);
4433
4570
  const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
4434
4571
  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, {
4572
+ debugJson(logger, `Switching web search request to model: ${webSearchModel}`, responsesPayload);
4573
+ const upstreamResult = await webSearchFlowDependencies.createResponses(responsesPayload, {
4437
4574
  vision,
4438
4575
  initiator,
4439
4576
  transport,
@@ -4442,8 +4579,13 @@ const handleWebSearchViaResponses = async (c, payload, options) => {
4442
4579
  sessionId: options.sessionId,
4443
4580
  compactType: options.compactType
4444
4581
  });
4582
+ const result = isWebSearchResponsesStream(upstreamResult) ? await collectWebSearchResponsesStreamResult({
4583
+ errorMessagePrefix: "Web search responses stream",
4584
+ upstreamResponse: upstreamResult,
4585
+ logger
4586
+ }) : upstreamResult;
4445
4587
  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)}`);
4588
+ debugJson(logger, `Web search via responses: ${extract.queries.length} quer(y/ies), ${extract.sources.length} source(s)`, result);
4447
4589
  createUsageRecorder(payload, options.sessionId, webSearchModel)(normalizeResponsesUsage(result.usage));
4448
4590
  if (!wantsStream) return c.json(response);
4449
4591
  return streamSSE(c, async (stream) => {
@@ -4701,17 +4843,31 @@ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
4701
4843
  const { payload, provider, providerConfig } = options;
4702
4844
  const selectedModel = providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0;
4703
4845
  const responsesPayload = prepareWebSearchResponsesPayload(payload);
4846
+ responsesPayload.stream = true;
4704
4847
  applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
4705
4848
  compactInputByLatestCompaction(responsesPayload);
4706
4849
  debugJson(logger$5, "provider.messages.responses.web_search.request", {
4707
4850
  payload: responsesPayload,
4708
4851
  provider
4709
4852
  });
4710
- if (providerConfig.name === "codex") return respondWebSearchProviderMessagesJson(c, {
4711
- body: await forwardCodexResponses(responsesPayload, c.req.raw.headers, providerConfig.baseUrl),
4712
- payload,
4713
- provider
4714
- });
4853
+ if (providerConfig.name === "codex") {
4854
+ const upstreamResponse = await forwardCodexResponses(responsesPayload, c.req.raw.headers, providerConfig.baseUrl);
4855
+ if (isResponsesStream$1(upstreamResponse)) return respondWebSearchProviderMessagesJson(c, {
4856
+ body: await collectWebSearchResponsesStreamResult({
4857
+ errorMessagePrefix: `${provider} web search responses stream`,
4858
+ parseEvent: (data) => parseResponsesProviderStreamChunk(data, providerConfig),
4859
+ upstreamResponse,
4860
+ logger: logger$5
4861
+ }),
4862
+ payload,
4863
+ provider
4864
+ });
4865
+ return respondWebSearchProviderMessagesJson(c, {
4866
+ body: upstreamResponse,
4867
+ payload,
4868
+ provider
4869
+ });
4870
+ }
4715
4871
  const upstreamResponse = await forwardProviderResponses(providerConfig, responsesPayload, c.req.raw.headers);
4716
4872
  if (!upstreamResponse.ok) {
4717
4873
  logger$5.error("Failed to create provider web search responses", {
@@ -4720,6 +4876,16 @@ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
4720
4876
  });
4721
4877
  throw new HTTPError("Failed to create provider web search responses", upstreamResponse);
4722
4878
  }
4879
+ if ((upstreamResponse.headers.get("content-type") ?? "").includes("text/event-stream")) return respondWebSearchProviderMessagesJson(c, {
4880
+ body: await collectWebSearchResponsesStreamResult({
4881
+ errorMessagePrefix: `${provider} web search responses stream`,
4882
+ parseEvent: (data) => parseResponsesProviderStreamChunk(data, providerConfig),
4883
+ upstreamResponse: events(upstreamResponse),
4884
+ logger: logger$5
4885
+ }),
4886
+ payload,
4887
+ provider
4888
+ });
4723
4889
  return respondWebSearchProviderMessagesJson(c, {
4724
4890
  body: await upstreamResponse.json(),
4725
4891
  payload,
@@ -5970,4 +6136,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
5970
6136
  //#endregion
5971
6137
  export { server };
5972
6138
 
5973
- //# sourceMappingURL=server-BxCf-DN5.js.map
6139
+ //# sourceMappingURL=server--yUElsYz.js.map