@nomomon/ai-sdk-provider-github-copilot 0.1.0 → 0.1.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.
package/README.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # AI SDK Provider for GitHub Copilot
2
2
 
3
- Vercel AI SDK community provider for GitHub Copilot - use `streamText`, `generateText`, and related AI SDK APIs with GitHub Copilot as the backend model.
3
+ [![Tests](https://img.shields.io/github/actions/workflow/status/nomomon/ai-sdk-provider-github-copilot/test.yml?branch=main&label=tests)](https://github.com/nomomon/ai-sdk-provider-github-copilot/actions)
4
+ [![codecov](https://codecov.io/gh/nomomon/ai-sdk-provider-github-copilot/graph/badge.svg)](https://codecov.io/gh/nomomon/ai-sdk-provider-github-copilot)
5
+ [![GitHub Packages](https://img.shields.io/badge/GitHub-Packages-blue?logo=github)](https://github.com/nomomon/ai-sdk-provider-github-copilot/pkgs/npm/ai-sdk-provider-github-copilot)
6
+ [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
7
+ [![Node](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
8
+ [![Fully AI Generated](https://img.shields.io/badge/fully-AI%20generated-purple?logo=openai)](https://github.com/nomomon/ai-sdk-provider-github-copilot)
9
+
10
+ Vercel AI SDK community provider for GitHub Copilot — use `streamText`, `generateText`, and related AI SDK APIs with GitHub Copilot as the backend model.
11
+
12
+ ---
4
13
 
5
14
  ## Installation
6
15
 
@@ -48,13 +57,7 @@ for await (const chunk of result.textStream) {
48
57
 
49
58
  ## Models
50
59
 
51
- Use model IDs available via Copilot CLI, for example:
52
-
53
- - `gpt-5` - GPT-5 (when available)
54
- - `claude-sonnet-4.5` - Claude Sonnet
55
- - `claude-opus-4` - Claude Opus
56
-
57
- Run `copilot models` to list available models in your environment.
60
+ Use model IDs available via Copilot CLI. Run `copilot -i /models` to list available models in your environment.
58
61
 
59
62
  ## Configuration
60
63
 
@@ -79,7 +82,7 @@ const model = githubCopilot("gpt-5", {
79
82
 
80
83
  ### Custom tools
81
84
 
82
- Pass tools via provider settings using Copilot's `defineTool`:
85
+ Pass tools via provider settings using Copilot's `defineTool`. Tool support varies by model; verify with Copilot CLI or documentation.
83
86
 
84
87
  ```typescript
85
88
  import { defineTool } from "@github/copilot-sdk";
@@ -101,6 +104,10 @@ const model = githubCopilot("gpt-5", {
101
104
  });
102
105
  ```
103
106
 
107
+ ## Development
108
+
109
+ Tests live in `tests/` (not colocated with source) to keep the published `src/` tree clean and to exclude test files from the build. Each source module has a corresponding `tests/*.test.ts` file. Run `npm test` or `npm run test:coverage` for coverage with thresholds.
110
+
104
111
  ## Limitations
105
112
 
106
113
  - **Requires Copilot CLI** - Must be installed and authenticated
@@ -109,6 +116,7 @@ const model = githubCopilot("gpt-5", {
109
116
  - **Unsupported parameters** - `temperature`, `maxTokens`, `topP`, etc. are not supported by the Copilot CLI and will be ignored (warnings emitted)
110
117
  - **Structured outputs** - Native JSON schema support may be limited; consider prompt engineering for structured responses
111
118
  - **Session-based** - Each generate/stream creates a new session; no built-in multi-session continuity across separate AI SDK calls
119
+ - **Model capabilities** - Tools, reasoning, and other features may vary by model; capabilities are determined by Copilot CLI
112
120
 
113
121
  ## Disclaimer
114
122
 
@@ -120,4 +128,4 @@ const model = githubCopilot("gpt-5", {
120
128
 
121
129
  ## License
122
130
 
123
- MIT
131
+ [MIT](LICENSE)
package/dist/index.cjs CHANGED
@@ -42,7 +42,7 @@ function isAbortError(error) {
42
42
  }
43
43
  return false;
44
44
  }
45
- function handleCopilotError(error, _context) {
45
+ function handleCopilotError(error) {
46
46
  if (isAbortError(error)) {
47
47
  throw error;
48
48
  }
@@ -57,9 +57,220 @@ function handleCopilotError(error, _context) {
57
57
  });
58
58
  }
59
59
 
60
- // src/convert-to-copilot-messages.ts
60
+ // src/conversion/map-copilot-finish-reason.ts
61
+ function mapCopilotFinishReason() {
62
+ return {
63
+ unified: "stop",
64
+ raw: void 0
65
+ };
66
+ }
67
+
68
+ // src/conversion/usage.ts
69
+ function createEmptyUsage() {
70
+ return {
71
+ inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },
72
+ outputTokens: { total: 0, text: void 0, reasoning: void 0 },
73
+ raw: void 0
74
+ };
75
+ }
76
+ function convertCopilotUsage(event) {
77
+ const inputTokens = event.inputTokens ?? 0;
78
+ const outputTokens = event.outputTokens ?? 0;
79
+ const cacheRead = event.cacheReadTokens ?? 0;
80
+ const cacheWrite = event.cacheWriteTokens ?? 0;
81
+ return {
82
+ inputTokens: {
83
+ total: inputTokens + cacheRead + cacheWrite,
84
+ noCache: inputTokens,
85
+ cacheRead,
86
+ cacheWrite
87
+ },
88
+ outputTokens: {
89
+ total: outputTokens,
90
+ text: outputTokens,
91
+ reasoning: void 0
92
+ },
93
+ raw: event
94
+ };
95
+ }
96
+ function createStreamEventHandler(params) {
97
+ const { controller, session } = params;
98
+ let textPartId;
99
+ let usage = createEmptyUsage();
100
+ const toolStates = /* @__PURE__ */ new Map();
101
+ const finishStream = () => {
102
+ if (textPartId) {
103
+ controller.enqueue({ type: "text-end", id: textPartId });
104
+ }
105
+ controller.enqueue({
106
+ type: "finish",
107
+ finishReason: mapCopilotFinishReason(),
108
+ usage
109
+ });
110
+ controller.close();
111
+ void session.destroy();
112
+ };
113
+ const handleError = (message) => {
114
+ controller.enqueue({
115
+ type: "error",
116
+ error: new Error(message)
117
+ });
118
+ controller.close();
119
+ void session.destroy();
120
+ };
121
+ return (event) => {
122
+ switch (event.type) {
123
+ case "assistant.message_delta": {
124
+ const delta = event.data.deltaContent;
125
+ if (delta) {
126
+ if (!textPartId) {
127
+ textPartId = providerUtils.generateId();
128
+ controller.enqueue({ type: "text-start", id: textPartId });
129
+ }
130
+ controller.enqueue({
131
+ type: "text-delta",
132
+ id: textPartId,
133
+ delta
134
+ });
135
+ }
136
+ break;
137
+ }
138
+ case "assistant.reasoning_delta": {
139
+ const delta = event.data.deltaContent;
140
+ if (delta) {
141
+ const reasoningId = providerUtils.generateId();
142
+ controller.enqueue({ type: "reasoning-start", id: reasoningId });
143
+ controller.enqueue({
144
+ type: "reasoning-delta",
145
+ id: reasoningId,
146
+ delta
147
+ });
148
+ controller.enqueue({ type: "reasoning-end", id: reasoningId });
149
+ }
150
+ break;
151
+ }
152
+ case "assistant.message": {
153
+ const { content, toolRequests } = event.data;
154
+ if (content && !textPartId) {
155
+ textPartId = providerUtils.generateId();
156
+ controller.enqueue({ type: "text-start", id: textPartId });
157
+ controller.enqueue({
158
+ type: "text-delta",
159
+ id: textPartId,
160
+ delta: content
161
+ });
162
+ controller.enqueue({ type: "text-end", id: textPartId });
163
+ }
164
+ if (toolRequests?.length) {
165
+ for (const tr of toolRequests) {
166
+ const toolId = tr.toolCallId;
167
+ let state = toolStates.get(toolId);
168
+ if (!state) {
169
+ state = {
170
+ name: tr.name,
171
+ inputStarted: false,
172
+ callEmitted: false
173
+ };
174
+ toolStates.set(toolId, state);
175
+ }
176
+ if (!state.inputStarted) {
177
+ controller.enqueue({
178
+ type: "tool-input-start",
179
+ id: toolId,
180
+ toolName: tr.name,
181
+ providerExecuted: true,
182
+ dynamic: true
183
+ });
184
+ state.inputStarted = true;
185
+ }
186
+ const args = tr.arguments ?? {};
187
+ controller.enqueue({
188
+ type: "tool-input-delta",
189
+ id: toolId,
190
+ delta: JSON.stringify(args)
191
+ });
192
+ controller.enqueue({ type: "tool-input-end", id: toolId });
193
+ if (!state.callEmitted) {
194
+ controller.enqueue({
195
+ type: "tool-call",
196
+ toolCallId: toolId,
197
+ toolName: tr.name,
198
+ input: typeof args === "string" ? args : JSON.stringify(args),
199
+ providerExecuted: true,
200
+ dynamic: true
201
+ });
202
+ state.callEmitted = true;
203
+ }
204
+ }
205
+ }
206
+ break;
207
+ }
208
+ case "tool.execution_start": {
209
+ const { toolCallId, toolName } = event.data;
210
+ let state = toolStates.get(toolCallId);
211
+ if (!state) {
212
+ state = {
213
+ name: toolName,
214
+ inputStarted: true,
215
+ callEmitted: false
216
+ };
217
+ toolStates.set(toolCallId, state);
218
+ }
219
+ if (!state.callEmitted) {
220
+ controller.enqueue({
221
+ type: "tool-input-start",
222
+ id: toolCallId,
223
+ toolName,
224
+ providerExecuted: true,
225
+ dynamic: true
226
+ });
227
+ controller.enqueue({ type: "tool-input-end", id: toolCallId });
228
+ controller.enqueue({
229
+ type: "tool-call",
230
+ toolCallId,
231
+ toolName,
232
+ input: "{}",
233
+ providerExecuted: true,
234
+ dynamic: true
235
+ });
236
+ state.callEmitted = true;
237
+ }
238
+ break;
239
+ }
240
+ case "tool.execution_complete": {
241
+ const { toolCallId, success, result, error } = event.data;
242
+ const toolNameStr = toolStates.get(toolCallId)?.name ?? "unknown";
243
+ const resultContent = success && result?.content ? result.content : error?.message ?? "Tool execution failed";
244
+ controller.enqueue({
245
+ type: "tool-result",
246
+ toolCallId,
247
+ toolName: toolNameStr,
248
+ result: resultContent,
249
+ isError: !success,
250
+ dynamic: true
251
+ });
252
+ break;
253
+ }
254
+ case "assistant.usage": {
255
+ usage = convertCopilotUsage(event.data);
256
+ break;
257
+ }
258
+ case "session.idle":
259
+ finishStream();
260
+ break;
261
+ case "session.error":
262
+ handleError(event.data.message ?? "Session error");
263
+ break;
264
+ }
265
+ };
266
+ }
267
+
268
+ // src/conversion/convert-to-copilot-messages.ts
61
269
  var IMAGE_URL_WARNING = "Image URLs are not supported by this provider; supply file paths as attachments.";
62
270
  var IMAGE_BASE64_WARNING = "Base64/image data URLs require file paths. Write to temp file and pass path, or use attachments with path.";
271
+ function isImagePart(part) {
272
+ return part.type === "image";
273
+ }
63
274
  function convertToCopilotMessages(prompt) {
64
275
  const messages = [];
65
276
  const warnings = [];
@@ -95,7 +306,7 @@ function convertToCopilotMessages(prompt) {
95
306
  } else if (fileInfo.warning) {
96
307
  warnings.push(fileInfo.warning);
97
308
  }
98
- } else if (part.type === "image") {
309
+ } else if (isImagePart(part)) {
99
310
  warnings.push(IMAGE_BASE64_WARNING);
100
311
  }
101
312
  }
@@ -181,41 +392,50 @@ function extractFileAttachment(part) {
181
392
  return {};
182
393
  }
183
394
 
184
- // src/map-copilot-finish-reason.ts
185
- function mapCopilotFinishReason() {
395
+ // src/model/session-setup.ts
396
+ async function prepareSession(input) {
397
+ const {
398
+ prompt,
399
+ options,
400
+ streaming,
401
+ buildSessionConfig,
402
+ generateWarnings,
403
+ getClient,
404
+ systemMessageFromSettings
405
+ } = input;
406
+ const {
407
+ prompt: promptText,
408
+ systemMessage,
409
+ attachments,
410
+ warnings: msgWarnings
411
+ } = convertToCopilotMessages(prompt);
412
+ const warnings = [
413
+ ...generateWarnings(options),
414
+ ...msgWarnings?.map((m) => ({ type: "other", message: m })) ?? []
415
+ ];
416
+ const client = getClient();
417
+ if (client.getState() !== "connected") {
418
+ await client.start();
419
+ }
420
+ const session = await client.createSession({
421
+ ...buildSessionConfig(streaming),
422
+ systemMessage: systemMessage ? { mode: "append", content: systemMessage } : systemMessageFromSettings
423
+ });
186
424
  return {
187
- unified: "stop",
188
- raw: void 0
425
+ prompt: promptText,
426
+ attachments,
427
+ warnings,
428
+ session
189
429
  };
190
430
  }
191
431
 
192
- // src/github-copilot-language-model.ts
193
- function createEmptyUsage() {
194
- return {
195
- inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },
196
- outputTokens: { total: 0, text: void 0, reasoning: void 0 },
197
- raw: void 0
198
- };
199
- }
200
- function convertCopilotUsage(event) {
201
- const inputTokens = event.inputTokens ?? 0;
202
- const outputTokens = event.outputTokens ?? 0;
203
- const cacheRead = event.cacheReadTokens ?? 0;
204
- const cacheWrite = 0;
205
- return {
206
- inputTokens: {
207
- total: inputTokens + cacheRead + cacheWrite,
208
- noCache: inputTokens,
209
- cacheRead,
210
- cacheWrite
211
- },
212
- outputTokens: {
213
- total: outputTokens,
214
- text: outputTokens,
215
- reasoning: void 0
216
- },
217
- raw: event
432
+ // src/model/github-copilot-language-model.ts
433
+ var SEND_AND_WAIT_TIMEOUT_MS = 6e4;
434
+ function addAbortListener(signal, onAbort) {
435
+ if (!signal) return () => {
218
436
  };
437
+ signal.addEventListener("abort", onAbort, { once: true });
438
+ return () => signal.removeEventListener("abort", onAbort);
219
439
  }
220
440
  var GitHubCopilotLanguageModel = class {
221
441
  specificationVersion = "v3";
@@ -267,34 +487,27 @@ var GitHubCopilotLanguageModel = class {
267
487
  }
268
488
  return warnings;
269
489
  }
270
- async doGenerate(options) {
271
- const {
272
- prompt,
273
- systemMessage,
274
- attachments,
275
- warnings: msgWarnings
276
- } = convertToCopilotMessages(options.prompt);
277
- const warnings = [
278
- ...this.generateWarnings(options),
279
- ...msgWarnings?.map((m) => ({ type: "other", message: m })) ?? []
280
- ];
281
- const client = this.getClient();
282
- if (client.getState() !== "connected") {
283
- await client.start();
284
- }
285
- const session = await client.createSession({
286
- ...this.buildSessionConfig(false),
287
- systemMessage: systemMessage ? { mode: "append", content: systemMessage } : this.settings.systemMessage
490
+ async prepareSessionForCall(options, streaming) {
491
+ return prepareSession({
492
+ prompt: options.prompt,
493
+ options,
494
+ streaming,
495
+ buildSessionConfig: (s) => this.buildSessionConfig(s),
496
+ generateWarnings: (o) => this.generateWarnings(o),
497
+ getClient: this.getClient,
498
+ systemMessageFromSettings: this.settings.systemMessage
288
499
  });
289
- let abortListener;
290
- if (options.abortSignal) {
291
- abortListener = () => session.abort();
292
- options.abortSignal.addEventListener("abort", abortListener, { once: true });
293
- }
500
+ }
501
+ async doGenerate(options) {
502
+ const { prompt, attachments, warnings, session } = await this.prepareSessionForCall(
503
+ options,
504
+ false
505
+ );
506
+ const removeAbortListener = addAbortListener(options.abortSignal, () => session.abort());
294
507
  try {
295
508
  const result = await session.sendAndWait(
296
509
  { prompt, attachments },
297
- options.abortSignal?.aborted ? 0 : 6e4
510
+ options.abortSignal?.aborted ? 0 : SEND_AND_WAIT_TIMEOUT_MS
298
511
  );
299
512
  const content = [];
300
513
  const text = result?.data?.content ?? "";
@@ -323,12 +536,10 @@ var GitHubCopilotLanguageModel = class {
323
536
  if (isAbortError(error)) {
324
537
  throw options.abortSignal?.aborted ? options.abortSignal.reason : error;
325
538
  }
326
- handleCopilotError(error, { promptExcerpt: prompt.substring(0, 200) });
327
- return void 0;
539
+ handleCopilotError(error);
540
+ throw new Error("Unreachable: handleCopilotError always throws");
328
541
  } finally {
329
- if (options.abortSignal && abortListener) {
330
- options.abortSignal.removeEventListener("abort", abortListener);
331
- }
542
+ removeAbortListener();
332
543
  try {
333
544
  await session.destroy();
334
545
  } catch {
@@ -336,196 +547,27 @@ var GitHubCopilotLanguageModel = class {
336
547
  }
337
548
  }
338
549
  async doStream(options) {
339
- const {
340
- prompt,
341
- systemMessage,
342
- attachments,
343
- warnings: msgWarnings
344
- } = convertToCopilotMessages(options.prompt);
345
- const warnings = [
346
- ...this.generateWarnings(options),
347
- ...msgWarnings?.map((m) => ({ type: "other", message: m })) ?? []
348
- ];
349
- const client = this.getClient();
350
- if (client.getState() !== "connected") {
351
- await client.start();
352
- }
353
- const session = await client.createSession({
354
- ...this.buildSessionConfig(true),
355
- systemMessage: systemMessage ? { mode: "append", content: systemMessage } : this.settings.systemMessage
356
- });
550
+ const { prompt, attachments, warnings, session } = await this.prepareSessionForCall(
551
+ options,
552
+ true
553
+ );
357
554
  const abortController = new AbortController();
358
- let abortListener;
359
555
  if (options.abortSignal?.aborted) {
360
556
  abortController.abort(options.abortSignal.reason);
361
- } else if (options.abortSignal) {
362
- abortListener = () => {
363
- session.abort();
364
- abortController.abort(options.abortSignal?.reason);
365
- };
366
- options.abortSignal.addEventListener("abort", abortListener, { once: true });
367
557
  }
558
+ const removeAbortListener = addAbortListener(options.abortSignal, () => {
559
+ session.abort();
560
+ abortController.abort(options.abortSignal?.reason);
561
+ });
368
562
  const stream = new ReadableStream({
369
563
  start: async (controller) => {
370
- let textPartId;
371
- let usage = createEmptyUsage();
372
- const toolStates = /* @__PURE__ */ new Map();
373
564
  try {
374
565
  controller.enqueue({ type: "stream-start", warnings });
375
- session.on((event) => {
376
- if (event.type === "assistant.message_delta") {
377
- const delta = event.data?.deltaContent;
378
- if (delta) {
379
- if (!textPartId) {
380
- textPartId = providerUtils.generateId();
381
- controller.enqueue({ type: "text-start", id: textPartId });
382
- }
383
- controller.enqueue({
384
- type: "text-delta",
385
- id: textPartId,
386
- delta
387
- });
388
- }
389
- } else if (event.type === "assistant.reasoning_delta") {
390
- const delta = event.data?.deltaContent;
391
- if (delta) {
392
- const reasoningId = providerUtils.generateId();
393
- controller.enqueue({ type: "reasoning-start", id: reasoningId });
394
- controller.enqueue({
395
- type: "reasoning-delta",
396
- id: reasoningId,
397
- delta
398
- });
399
- controller.enqueue({ type: "reasoning-end", id: reasoningId });
400
- }
401
- } else if (event.type === "assistant.message") {
402
- const data = event.data;
403
- if (data?.content && !textPartId) {
404
- textPartId = providerUtils.generateId();
405
- controller.enqueue({ type: "text-start", id: textPartId });
406
- controller.enqueue({
407
- type: "text-delta",
408
- id: textPartId,
409
- delta: data.content
410
- });
411
- controller.enqueue({ type: "text-end", id: textPartId });
412
- }
413
- if (data?.toolRequests?.length) {
414
- for (const tr of data.toolRequests) {
415
- const toolId = tr.toolCallId;
416
- let state = toolStates.get(toolId);
417
- if (!state) {
418
- state = {
419
- name: tr.name,
420
- inputStarted: false,
421
- callEmitted: false
422
- };
423
- toolStates.set(toolId, state);
424
- }
425
- if (!state.inputStarted) {
426
- controller.enqueue({
427
- type: "tool-input-start",
428
- id: toolId,
429
- toolName: tr.name,
430
- providerExecuted: true,
431
- dynamic: true
432
- });
433
- state.inputStarted = true;
434
- }
435
- const args = tr.arguments ?? {};
436
- controller.enqueue({
437
- type: "tool-input-delta",
438
- id: toolId,
439
- delta: JSON.stringify(args)
440
- });
441
- controller.enqueue({ type: "tool-input-end", id: toolId });
442
- if (!state.callEmitted) {
443
- controller.enqueue({
444
- type: "tool-call",
445
- toolCallId: toolId,
446
- toolName: tr.name,
447
- input: typeof args === "string" ? args : JSON.stringify(args),
448
- providerExecuted: true,
449
- dynamic: true
450
- });
451
- state.callEmitted = true;
452
- }
453
- }
454
- }
455
- } else if (event.type === "tool.execution_start") {
456
- const data = event.data;
457
- if (data) {
458
- const toolId = data.toolCallId;
459
- let state = toolStates.get(toolId);
460
- if (!state) {
461
- state = {
462
- name: data.toolName,
463
- inputStarted: true,
464
- callEmitted: false
465
- };
466
- toolStates.set(toolId, state);
467
- }
468
- if (!state.callEmitted) {
469
- controller.enqueue({
470
- type: "tool-input-start",
471
- id: toolId,
472
- toolName: data.toolName,
473
- providerExecuted: true,
474
- dynamic: true
475
- });
476
- controller.enqueue({ type: "tool-input-end", id: toolId });
477
- controller.enqueue({
478
- type: "tool-call",
479
- toolCallId: toolId,
480
- toolName: data.toolName,
481
- input: "{}",
482
- providerExecuted: true,
483
- dynamic: true
484
- });
485
- state.callEmitted = true;
486
- }
487
- }
488
- } else if (event.type === "tool.execution_complete") {
489
- const evt = event;
490
- const data = evt.data;
491
- if (data) {
492
- const toolName = data.toolName ?? "unknown";
493
- const result = data.success && data.result?.content ? data.result.content : data.error?.message ?? "Tool execution failed";
494
- controller.enqueue({
495
- type: "tool-result",
496
- toolCallId: data.toolCallId,
497
- toolName,
498
- result,
499
- isError: !data.success,
500
- dynamic: true
501
- });
502
- }
503
- } else if (event.type === "assistant.usage") {
504
- const data = event.data;
505
- if (data) {
506
- usage = convertCopilotUsage(data);
507
- }
508
- } else if (event.type === "session.idle") {
509
- if (textPartId) {
510
- controller.enqueue({ type: "text-end", id: textPartId });
511
- }
512
- controller.enqueue({
513
- type: "finish",
514
- finishReason: mapCopilotFinishReason(),
515
- usage
516
- });
517
- controller.close();
518
- void session.destroy();
519
- } else if (event.type === "session.error") {
520
- const data = event.data;
521
- controller.enqueue({
522
- type: "error",
523
- error: new Error(data?.message ?? "Session error")
524
- });
525
- controller.close();
526
- void session.destroy();
527
- }
566
+ const handleEvent = createStreamEventHandler({
567
+ controller,
568
+ session
528
569
  });
570
+ session.on(handleEvent);
529
571
  await session.send({ prompt, attachments });
530
572
  } catch (error) {
531
573
  if (isAbortError(error)) {
@@ -534,20 +576,16 @@ var GitHubCopilotLanguageModel = class {
534
576
  error: options.abortSignal?.aborted ? options.abortSignal.reason : error
535
577
  });
536
578
  } else {
537
- handleCopilotError(error, { promptExcerpt: prompt.substring(0, 200) });
579
+ handleCopilotError(error);
538
580
  }
539
581
  controller.close();
540
582
  await session.destroy();
541
583
  } finally {
542
- if (options.abortSignal && abortListener) {
543
- options.abortSignal.removeEventListener("abort", abortListener);
544
- }
584
+ removeAbortListener();
545
585
  }
546
586
  },
547
587
  cancel: () => {
548
- if (options.abortSignal && abortListener) {
549
- options.abortSignal.removeEventListener("abort", abortListener);
550
- }
588
+ removeAbortListener();
551
589
  }
552
590
  });
553
591
  return {