@github/copilot-sdk 1.0.14 → 1.0.15-preview.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,6 @@
1
1
  const sharedTextDecoder = new TextDecoder("utf-8", { fatal: false });
2
2
  const sharedTextEncoder = new TextEncoder();
3
+ const HTTP_RESPONSE_READ_AHEAD_BYTES = 32 * 1024;
3
4
  const kBridge = /* @__PURE__ */ Symbol("copilotWebSocketResponseBridge");
4
5
  const kCompletion = /* @__PURE__ */ Symbol("copilotWebSocketCompletion");
5
6
  const kOpen = /* @__PURE__ */ Symbol("copilotWebSocketOpen");
@@ -238,7 +239,9 @@ function createCopilotRequestAdapter(handler, getServerRpc) {
238
239
  const message = err instanceof Error ? err.message : String(err);
239
240
  await finalize(exchange, 502, message);
240
241
  } finally {
241
- pending.delete(exchange.requestId);
242
+ if (pending.get(exchange.requestId) === exchange) {
243
+ pending.delete(exchange.requestId);
244
+ }
242
245
  }
243
246
  }
244
247
  return {
@@ -251,6 +254,13 @@ function createCopilotRequestAdapter(handler, getServerRpc) {
251
254
  async httpRequestChunk(params) {
252
255
  routeChunk(getOrCreate(params.requestId), params);
253
256
  return {};
257
+ },
258
+ cancelPending() {
259
+ const exchanges = [...pending.values()];
260
+ pending.clear();
261
+ for (const exchange of exchanges) {
262
+ exchange.pushCancel("RPC connection closed");
263
+ }
254
264
  }
255
265
  };
256
266
  }
@@ -499,30 +509,156 @@ async function drainAsync(stream) {
499
509
  return out;
500
510
  }
501
511
  async function streamResponse(response, exchange) {
502
- await exchange.startResponse({
503
- status: response.status,
504
- statusText: response.statusText || void 0,
505
- headers: headersToMultiMap(response.headers)
506
- });
507
- const body = response.body;
508
- if (!body) {
509
- await exchange.endResponse();
510
- return;
511
- }
512
- const reader = body.getReader();
512
+ const reader = response.body ? new HttpResponseReader(response.body, exchange.signal) : void 0;
513
513
  try {
514
- for (; ; ) {
515
- const { value, done } = await reader.read();
516
- if (done) {
517
- break;
518
- }
519
- if (value && value.byteLength > 0) {
520
- await exchange.writeResponse(value);
514
+ await exchange.startResponse({
515
+ status: response.status,
516
+ statusText: response.statusText || void 0,
517
+ headers: headersToMultiMap(response.headers)
518
+ });
519
+ if (reader) {
520
+ for (; ; ) {
521
+ const chunk = await reader.nextChunk();
522
+ if (!chunk) {
523
+ break;
524
+ }
525
+ await exchange.writeResponse(chunk);
521
526
  }
522
527
  }
523
528
  await exchange.endResponse();
524
529
  } finally {
525
- reader.releaseLock();
530
+ await reader?.dispose();
531
+ }
532
+ }
533
+ class HttpResponseReader {
534
+ #reader;
535
+ #signal;
536
+ #frames = [];
537
+ #pump;
538
+ #onAbort;
539
+ #queued = 0;
540
+ #done = false;
541
+ #cancelled = false;
542
+ #hasError = false;
543
+ #error;
544
+ #dataWaker;
545
+ #spaceWaker;
546
+ #cancelPromise;
547
+ constructor(body, signal) {
548
+ this.#reader = body.getReader();
549
+ this.#signal = signal;
550
+ this.#onAbort = () => {
551
+ void this.cancel(signal.reason);
552
+ };
553
+ signal.addEventListener("abort", this.#onAbort, { once: true });
554
+ this.#pump = this.#pumpSource();
555
+ if (signal.aborted) {
556
+ this.#onAbort();
557
+ }
558
+ }
559
+ async nextChunk() {
560
+ while (this.#frames.length === 0 && !this.#done && !this.#hasError) {
561
+ await new Promise((resolve) => {
562
+ this.#dataWaker = resolve;
563
+ });
564
+ }
565
+ if (this.#frames.length > 0) {
566
+ const chunk = this.#takeQueued();
567
+ this.#wakeSpace();
568
+ return chunk;
569
+ }
570
+ if (this.#hasError) {
571
+ this.#hasError = false;
572
+ throw this.#error;
573
+ }
574
+ return void 0;
575
+ }
576
+ #takeQueued() {
577
+ const frames = this.#frames;
578
+ const total = this.#queued;
579
+ this.#queued = 0;
580
+ if (frames.length === 1) {
581
+ return frames.pop();
582
+ }
583
+ const chunk = new Uint8Array(total);
584
+ let offset = 0;
585
+ for (const frame of frames) {
586
+ chunk.set(frame, offset);
587
+ offset += frame.byteLength;
588
+ }
589
+ frames.length = 0;
590
+ return chunk;
591
+ }
592
+ async dispose() {
593
+ this.#signal.removeEventListener("abort", this.#onAbort);
594
+ if (!this.#done) {
595
+ await this.cancel();
596
+ } else if (this.#cancelPromise) {
597
+ await this.#cancelPromise;
598
+ }
599
+ await this.#pump;
600
+ }
601
+ cancel(reason) {
602
+ if (this.#done) {
603
+ return Promise.resolve();
604
+ }
605
+ if (!this.#cancelPromise) {
606
+ this.#cancelled = true;
607
+ this.#done = true;
608
+ this.#hasError = true;
609
+ this.#error = reason instanceof Error ? reason : new Error("HTTP response body cancelled.");
610
+ this.#frames.length = 0;
611
+ this.#queued = 0;
612
+ this.#wakeData();
613
+ this.#wakeSpace();
614
+ this.#cancelPromise = this.#reader.cancel(reason).catch(() => void 0);
615
+ }
616
+ return this.#cancelPromise;
617
+ }
618
+ async #pumpSource() {
619
+ try {
620
+ while (!this.#cancelled) {
621
+ while (this.#queued >= HTTP_RESPONSE_READ_AHEAD_BYTES && !this.#cancelled) {
622
+ await new Promise((resolve) => {
623
+ this.#spaceWaker = resolve;
624
+ });
625
+ }
626
+ if (this.#cancelled) {
627
+ return;
628
+ }
629
+ const { value, done } = await this.#reader.read();
630
+ if (done) {
631
+ return;
632
+ }
633
+ if (value.byteLength > 0) {
634
+ this.#frames.push(value);
635
+ this.#queued += value.byteLength;
636
+ this.#wakeData();
637
+ continue;
638
+ }
639
+ await new Promise((resolve) => setImmediate(resolve));
640
+ }
641
+ } catch (error) {
642
+ if (!this.#cancelled) {
643
+ this.#hasError = true;
644
+ this.#error = error;
645
+ }
646
+ } finally {
647
+ this.#done = true;
648
+ this.#wakeData();
649
+ this.#wakeSpace();
650
+ this.#reader.releaseLock();
651
+ }
652
+ }
653
+ #wakeData() {
654
+ const waker = this.#dataWaker;
655
+ this.#dataWaker = void 0;
656
+ waker?.();
657
+ }
658
+ #wakeSpace() {
659
+ const waker = this.#spaceWaker;
660
+ this.#spaceWaker = void 0;
661
+ waker?.();
526
662
  }
527
663
  }
528
664
  function headersToMultiMap(headers) {