@jeffreycao/copilot-api 1.11.1 → 1.11.3

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-t4js93GE.js");
47
47
  await runMain(defineCommand({
48
48
  meta: {
49
49
  name: "copilot-api",
@@ -2343,7 +2343,7 @@ const prepareMessagesApiPayload = (payload, selectedModel) => {
2343
2343
  payload.thinking = { type: "adaptive" };
2344
2344
  if (!hasThinking) payload.thinking.display = "summarized";
2345
2345
  if (shouldSummarizeThinkingDisplayForModel(payload.model)) payload.thinking.display = "summarized";
2346
- let effort = getReasoningEffortForModel(payload.model);
2346
+ let effort = payload.output_config?.effort ?? getReasoningEffortForModel(payload.model);
2347
2347
  if (effort === "none" || effort === "minimal") effort = "low";
2348
2348
  const reasoningEffort = selectedModel.capabilities.supports.reasoning_effort;
2349
2349
  if (reasoningEffort && !reasoningEffort.includes(effort)) effort = reasoningEffort.at(-1);
@@ -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,
@@ -5625,34 +5791,54 @@ const createProviderResponsesUsageRecorder = (payload, provider) => {
5625
5791
  sessionId: sessionAffinity ?? ""
5626
5792
  });
5627
5793
  };
5628
- const streamProviderResponses = (c, upstreamResponse, options) => {
5794
+ const streamProviderResponses = async (c, upstreamResponse, options) => {
5795
+ const iterator = upstreamResponse[Symbol.asyncIterator]();
5796
+ const firstResult = await iterator.next();
5797
+ if (firstResult.done) throw new HTTPError(`Empty stream from ${options.provider} responses`, new Response("", { status: 502 }));
5798
+ const firstChunk = firstResult.value;
5799
+ if (firstChunk.data && firstChunk.data !== "[DONE]") {
5800
+ const event = parseProviderResponsesStreamEvent(firstChunk.data, {
5801
+ normalizeCodex: options.normalizeCodex,
5802
+ provider: options.provider
5803
+ });
5804
+ if (event?.type === "error") {
5805
+ const errorEvent = event;
5806
+ const statusCode = errorEvent.status_code ?? 500;
5807
+ return c.json({ error: {
5808
+ message: errorEvent.message,
5809
+ ...errorEvent.error
5810
+ } }, statusCode, errorEvent.headers ?? void 0);
5811
+ }
5812
+ }
5629
5813
  return streamSSE(c, async (stream) => {
5630
5814
  let usage = {};
5631
- try {
5632
- for await (const chunk of upstreamResponse) {
5633
- debugJson(logger$2, "Responses stream chunk:", chunk);
5634
- let responseChunk = chunk;
5635
- let event = null;
5636
- if (chunk.data && chunk.data !== "[DONE]") {
5637
- event = parseProviderResponsesStreamEvent(chunk.data, {
5638
- normalizeCodex: options.normalizeCodex,
5639
- provider: options.provider
5640
- });
5641
- if (event && options.normalizeCodex) responseChunk = {
5642
- ...chunk,
5643
- data: JSON.stringify(event),
5644
- event: event.type
5645
- };
5646
- }
5647
- if (event) {
5648
- const nextUsage = getResponsesStreamEventUsage(event);
5649
- if (nextUsage) usage = nextUsage;
5650
- }
5651
- await stream.writeSSE({
5652
- data: responseChunk.data ?? "",
5653
- event: responseChunk.event
5815
+ const writeChunk = async (chunk) => {
5816
+ debugJson(logger$2, "Responses stream chunk:", chunk);
5817
+ let responseChunk = chunk;
5818
+ let event = null;
5819
+ if (chunk.data && chunk.data !== "[DONE]") {
5820
+ event = parseProviderResponsesStreamEvent(chunk.data, {
5821
+ normalizeCodex: options.normalizeCodex,
5822
+ provider: options.provider
5654
5823
  });
5824
+ if (event && options.normalizeCodex) responseChunk = {
5825
+ ...chunk,
5826
+ data: JSON.stringify(event),
5827
+ event: event.type
5828
+ };
5829
+ }
5830
+ if (event) {
5831
+ const nextUsage = getResponsesStreamEventUsage(event);
5832
+ if (nextUsage) usage = nextUsage;
5655
5833
  }
5834
+ await stream.writeSSE({
5835
+ data: responseChunk.data ?? "",
5836
+ event: responseChunk.event
5837
+ });
5838
+ };
5839
+ try {
5840
+ await writeChunk(firstChunk);
5841
+ for await (const chunk of { [Symbol.asyncIterator]: () => iterator }) await writeChunk(chunk);
5656
5842
  } finally {
5657
5843
  options.recordUsage(usage);
5658
5844
  }
@@ -5970,4 +6156,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
5970
6156
  //#endregion
5971
6157
  export { server };
5972
6158
 
5973
- //# sourceMappingURL=server-BxCf-DN5.js.map
6159
+ //# sourceMappingURL=server-CSpOUSFF.js.map