@alvin0/ai-agent-sdk-provider-copilot 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.
@@ -0,0 +1,1297 @@
1
+ import { AgentSdkError, ModelInvocationContext, RetryPolicyConfig, SafeErrorRecord } from "@alvin0/ai-agent-sdk-core";
2
+ import { ComposableModelProviderPlugin, CredentialOperationOptions, CredentialStore, ModelTarget } from "@alvin0/ai-agent-sdk-core/provider";
3
+ import { HttpModelAdapter, ProtocolRequest, ProtocolSseEvent, ProtocolStreamChunk, ProviderCatalogModel, ProviderRequestLogger, RuntimeModelDiscoveryContext, RuntimeWireProtocol } from "@alvin0/ai-agent-sdk-provider-http";
4
+ import { ChatCompletionsDialect } from "@alvin0/ai-agent-sdk-protocol-openai-chat-completions";
5
+ import { ResponsesDialect } from "@alvin0/ai-agent-sdk-protocol-responses";
6
+ //#region src/catalog.d.ts
7
+ /** Path of the catalog surface, relative to the pinned Copilot base URL. */
8
+ declare const COPILOT_CATALOG_PATH = "/models";
9
+ /** Maximum raw catalog bytes when the caller configures none. */
10
+ declare const COPILOT_DEFAULT_MAX_CATALOG_BYTES: number;
11
+ /** Maximum catalog entries accepted when the caller configures none. */
12
+ declare const COPILOT_DEFAULT_MAX_CATALOG_MODELS = 2048;
13
+ /** Maximum catalog response chunks accepted when the caller configures none. */
14
+ declare const COPILOT_DEFAULT_MAX_CATALOG_CHUNKS = 10000;
15
+ /** Catalog request deadline when the caller configures none. */
16
+ declare const COPILOT_DEFAULT_CATALOG_TIMEOUT_MS = 30000;
17
+ /**
18
+ * Which endpoint a generation model is dispatched to.
19
+ *
20
+ * Declared HERE rather than in `./router.ts`, where the router's own types live,
21
+ * for one structural reason: `./router.ts` imports {@link CopilotGenerationModel}
22
+ * from this module, so the dependency edge already runs router → catalog. Putting
23
+ * the endpoint union in the router would make it run both ways, which the repo's
24
+ * source-ownership check forbids and which nothing here needs. `./router.ts`
25
+ * re-exports this type, so the router remains the module a reader goes to for
26
+ * endpoint selection.
27
+ */
28
+ type CopilotEndpoint = 'responses' | 'chat-completions';
29
+ /** Why an entry was left out of both catalogs. */
30
+ type CopilotOmitReason =
31
+ /** capabilities.type is not one of the recognized values. */
32
+ 'capability-type-unrecognized' |
33
+ /** No usable id. */
34
+ 'model-id-missing';
35
+ /** One entry that was dropped, with the reason an operator needs to see it. */
36
+ interface CopilotOmittedModel {
37
+ /** The entry's id, or `''` when it had none — the reason says which. */
38
+ readonly id: string;
39
+ /** Why it was dropped. */
40
+ readonly reason: CopilotOmitReason;
41
+ }
42
+ /** A generation model, plus whatever the catalog disclosed about its endpoint. */
43
+ interface CopilotGenerationModel {
44
+ /** The SDK catalog model, handed to `provider-http` unchanged. */
45
+ readonly model: ProviderCatalogModel;
46
+ /**
47
+ * The endpoint the catalog disclosed, when it disclosed one.
48
+ *
49
+ * `undefined` means UNKNOWN, not "not supported". The router handles those two
50
+ * states differently (Requirement 8.6).
51
+ */
52
+ readonly declaredEndpoint: CopilotEndpoint | undefined;
53
+ }
54
+ /**
55
+ * An embedding model, carrying only the facts the catalog stated.
56
+ *
57
+ * Deliberately NOT a {@link ProviderCatalogModel}: an embedding model has no
58
+ * context window or output cap to report, and `Copilot_Embedding_Adapter` needs
59
+ * different facts (batch ceiling, whether a requested dimension count is
60
+ * honoured). Every field but `id` is optional because every one of them is absent
61
+ * from some real entry.
62
+ */
63
+ interface CopilotEmbeddingModel {
64
+ /** Wire model id, passed to the endpoint verbatim. */
65
+ readonly id: string;
66
+ /** Display label, when the catalog supplied one. */
67
+ readonly name?: string;
68
+ /** Model family, when disclosed; embedding compatibility identity is derived from it. */
69
+ readonly family?: string;
70
+ /** Token ceiling for one input, from `limits.max_context_window_tokens`. */
71
+ readonly maxInputTokens?: number;
72
+ /** Ceiling on inputs per request, from `limits.max_inputs`. */
73
+ readonly maxInputs?: number;
74
+ /** Whether `supports.dimensions` was stated, and what it said. */
75
+ readonly supportsDimensions?: boolean;
76
+ }
77
+ /** The result of one discovery, partitioned. */
78
+ interface CopilotCatalogSnapshot {
79
+ /** Models usable for generation, each with its preliminary endpoint disclosure. */
80
+ readonly generation: readonly CopilotGenerationModel[];
81
+ /** Models usable for embedding. */
82
+ readonly embedding: readonly CopilotEmbeddingModel[];
83
+ /** Dropped entries with their reasons — these go to observation, not to a catalog. */
84
+ readonly omitted: readonly CopilotOmittedModel[];
85
+ }
86
+ /** Resolved bounds for one catalog read. Every field is a bound, never "unlimited". */
87
+ interface CopilotCatalogLimits {
88
+ /** Maximum raw response bytes. */
89
+ readonly maxBytes: number;
90
+ /** Maximum entries accepted before the response is called malformed. */
91
+ readonly maxModels: number;
92
+ /** Maximum response chunks. */
93
+ readonly maxChunks: number;
94
+ /** Deadline for the catalog request AND its body read. */
95
+ readonly timeoutMs: number;
96
+ /** Permit an `http:` base URL for a trusted local test endpoint. */
97
+ readonly allowInsecureHttp?: boolean;
98
+ }
99
+ /**
100
+ * The caller-facing catalog options, in the spelling `CopilotProviderOptions` uses.
101
+ *
102
+ * Split into two groups on purpose. The four `max*`/`timeout` values bound ONE
103
+ * read and are resolved here by {@link resolveCopilotCatalogLimits}. The three
104
+ * cache values (TTL, stale TTL, failure backoff) bound how often reads happen at
105
+ * all, and `provider-http` already owns that policy — {@link
106
+ * copilotCatalogCacheOptions} forwards them without a default, so an unset option
107
+ * keeps the runtime's own default instead of this package pinning a second one
108
+ * (Requirement 8.7).
109
+ */
110
+ interface CopilotCatalogOptions {
111
+ /** Maximum raw catalog bytes. Defaults to {@link COPILOT_DEFAULT_MAX_CATALOG_BYTES}. */
112
+ readonly maxCatalogBytes?: number;
113
+ /** Maximum catalog entries. Defaults to {@link COPILOT_DEFAULT_MAX_CATALOG_MODELS}. */
114
+ readonly maxCatalogModels?: number;
115
+ /** Maximum catalog response chunks. Defaults to {@link COPILOT_DEFAULT_MAX_CATALOG_CHUNKS}. */
116
+ readonly maxCatalogChunks?: number;
117
+ /** Catalog request deadline. Defaults to {@link COPILOT_DEFAULT_CATALOG_TIMEOUT_MS}. */
118
+ readonly catalogTimeoutMs?: number;
119
+ /** How long a discovered catalog stays fresh. */
120
+ readonly catalogTtlMs?: number;
121
+ /** How long a stale catalog may still be served while a refresh is attempted. */
122
+ readonly catalogStaleTtlMs?: number;
123
+ /** How long to wait before retrying discovery after it failed. */
124
+ readonly catalogFailureBackoffMs?: number;
125
+ /** Permit an `http:` base URL for a trusted local test endpoint. */
126
+ readonly allowInsecureHttp?: boolean;
127
+ }
128
+ /**
129
+ * Resolve the per-read bounds, rejecting a value that cannot bound anything.
130
+ *
131
+ * Validation happens here rather than at the read, so a `0` or a `NaN` in the
132
+ * configuration is a construction-time error instead of a silently disabled limit
133
+ * discovered under load (Requirement 8.2).
134
+ * @param options - the caller's catalog options.
135
+ * @returns the four resolved bounds plus the insecure-HTTP opt-in.
136
+ * @throws RangeError when a configured bound is not a positive safe integer.
137
+ */
138
+ declare function resolveCopilotCatalogLimits(options?: CopilotCatalogOptions): CopilotCatalogLimits;
139
+ /**
140
+ * Forward the three cache-policy options, and only the ones that were set.
141
+ *
142
+ * A conditional spread rather than defaults: `provider-http` owns catalog caching,
143
+ * and a default written here would override the runtime's own without anyone
144
+ * asking for it (Requirement 8.7).
145
+ * @param options - the caller's catalog options.
146
+ * @returns an object carrying only the cache options the caller supplied.
147
+ */
148
+ declare function copilotCatalogCacheOptions(options?: CopilotCatalogOptions): {
149
+ readonly catalogTtlMs?: number;
150
+ readonly catalogStaleTtlMs?: number;
151
+ readonly catalogFailureBackoffMs?: number;
152
+ };
153
+ /**
154
+ * Read `GET {baseUrl}/models` and partition it.
155
+ *
156
+ * The base URL is re-pinned here from `context.baseUrl` rather than trusted as a
157
+ * string: the catalog is the first Copilot call an adapter makes, and a pin
158
+ * compared before dispatch is the only check that runs before the resolved
159
+ * `Authorization` header leaves the process.
160
+ * @param context - the discovery context `provider-http` supplies: base URL,
161
+ * already-resolved headers, and the operation's signal.
162
+ * @param limits - bounds from {@link resolveCopilotCatalogLimits}.
163
+ * @param fetchImpl - HTTP implementation, injected for tests and non-browser runtimes.
164
+ * @returns the partitioned snapshot; an empty one when the endpoint answered a
165
+ * non-2xx status, because a catalog that could not be fetched is advisory too.
166
+ * @throws AgentSdkError with `COPILOT_REDIRECT_REJECTED` on any redirect shape, or
167
+ * `COPILOT_CATALOG_MALFORMED` when the response is the wrong shape structurally.
168
+ * @throws RangeError when the response exceeds a configured bound.
169
+ */
170
+ declare function discoverCopilotModels(context: RuntimeModelDiscoveryContext, limits: CopilotCatalogLimits, fetchImpl: typeof globalThis.fetch): Promise<CopilotCatalogSnapshot>;
171
+ /**
172
+ * Partition an already-read catalog body.
173
+ *
174
+ * Exported separately from the fetch so the partition is testable — and readable —
175
+ * as what it is: a pure function from a parsed body to three lists.
176
+ * @param body - the parsed root object of the catalog response.
177
+ * @param maxModels - entry-count ceiling; exceeding it is structural, not per-entry.
178
+ * @returns the partitioned snapshot.
179
+ * @throws AgentSdkError with `COPILOT_CATALOG_MALFORMED` when `data` is not an
180
+ * array or holds more than `maxModels` entries.
181
+ */
182
+ declare function partitionCopilotCatalog(body: Record<string, unknown>, maxModels: number): CopilotCatalogSnapshot;
183
+ //#endregion
184
+ //#region src/common/identity.d.ts
185
+ /**
186
+ * The two Copilot endpoint constants and the editor-header override type, in the
187
+ * leaf layer so every module that has to speak to the Copilot surface can reach
188
+ * them.
189
+ *
190
+ * They BELONG to `../adapter.ts` — that module is the public door, documents the
191
+ * client-identity tradeoff, and re-exports everything here. The values live one
192
+ * layer down for the same structural reason `COPILOT_ERROR_CODES` does:
193
+ * `../catalog.ts` needs {@link COPILOT_BASE_URL} and `../exchange.ts` needs the
194
+ * two editor headers, while `../adapter.ts` builds the catalog reader and the
195
+ * token cache. Declaring the constants in `../adapter.ts` would make that edge
196
+ * run both ways, which the repo's circular-dependency check forbids. Copying the
197
+ * strings instead would be worse: a client identity that exists in two places is
198
+ * a client identity that can disagree with itself.
199
+ *
200
+ * Read `../adapter.ts` for what these values mean, why they are overridable
201
+ * options rather than hidden constants, and what is still outstanding on each.
202
+ *
203
+ * @module ai-agent-sdk/providers/copilot/identity
204
+ */
205
+ /** The Copilot API base. Documented on the re-export in `../adapter.ts`. */
206
+ declare const COPILOT_BASE_URL = "https://api.githubcopilot.com";
207
+ /** Default `Editor-Version`. Documented on the re-export in `../adapter.ts`. */
208
+ declare const COPILOT_EDITOR_VERSION = "vscode/1.99.0";
209
+ /** Default `Editor-Plugin-Version`. Documented on the re-export in `../adapter.ts`. */
210
+ declare const COPILOT_EDITOR_PLUGIN_VERSION = "copilot-chat/0.26.0";
211
+ /**
212
+ * Overrides for the two editor headers.
213
+ *
214
+ * Each field is independent: leaving one undefined keeps that header's exported
215
+ * default rather than dropping the header, because a dropped header is an HTTP
216
+ * 400 rather than a lenient request.
217
+ */
218
+ interface CopilotEditorHeaders {
219
+ /** Overrides {@link COPILOT_EDITOR_VERSION}. */
220
+ readonly editorVersion?: string;
221
+ /** Overrides {@link COPILOT_EDITOR_PLUGIN_VERSION}. */
222
+ readonly editorPluginVersion?: string;
223
+ }
224
+ //#endregion
225
+ //#region src/common/store-types.d.ts
226
+ /**
227
+ * The long-lived GitHub user token, prefixed `ghu_`.
228
+ *
229
+ * It DOES NOT rotate when it is exchanged for a `Copilot_Api_Token`. That is the
230
+ * structural difference from Codex's single-use refresh token, and it is why the
231
+ * credential file is written exactly once at login and only read from then on.
232
+ */
233
+ interface CopilotGitHubToken {
234
+ /** The token value. Never put this in an error message or a trace. */
235
+ readonly token: string;
236
+ /** Token type as declared by the endpoint, when present. Diagnostics only. */
237
+ readonly tokenType?: string;
238
+ /** Granted scope, when the endpoint discloses it. Diagnostics only. */
239
+ readonly scope?: string;
240
+ }
241
+ /** Session identity, limited to what the endpoint actually discloses. */
242
+ interface CopilotAccountIdentity {
243
+ readonly login?: string;
244
+ readonly id?: number;
245
+ readonly name?: string;
246
+ }
247
+ /**
248
+ * The persisted credential document.
249
+ *
250
+ * Four things are deliberately absent, each one a decision:
251
+ *
252
+ * - **No `Copilot_Api_Token`.** The short-lived token lives ~25 minutes;
253
+ * persisting it adds a write path and a second secret on disk while saving
254
+ * nothing, because the next process run almost always has to exchange again.
255
+ * - **No refresh-token field.** There is no refresh token in this model.
256
+ * `Copilot_Token_Exchange` does not consume the credential, so there is
257
+ * nothing to rotate.
258
+ * - **No `last_refresh`.** Codex needs it as a fallback when `exp` is
259
+ * unreadable. Copilot reads `expires_at` straight from the exchange response,
260
+ * and that response lives in memory rather than in this file, so a
261
+ * file-age fallback would have nothing to say.
262
+ * - **No API-key-equivalent config.** This surface rejects personal access
263
+ * tokens, so a "use an API key instead of OAuth" configuration has no
264
+ * situation to represent.
265
+ */
266
+ interface CopilotAuthFile {
267
+ /**
268
+ * Structure version. Reading a file with an unknown version is an error, not
269
+ * an implicit migration.
270
+ */
271
+ readonly version: 1;
272
+ readonly github: CopilotGitHubToken;
273
+ readonly account?: CopilotAccountIdentity;
274
+ /** The OAuth client id that minted this token; used to diagnose a 403. */
275
+ readonly clientId?: string;
276
+ /** Login time, ISO-8601. */
277
+ readonly obtainedAt?: string;
278
+ }
279
+ /**
280
+ * @deprecated Read/write variant, kept only for symmetry with Codex. Normal
281
+ * runtime composition uses {@link CopilotCredentialStore}.
282
+ */
283
+ interface CopilotAuthStore {
284
+ readonly location: string;
285
+ read(): Promise<CopilotAuthFile | undefined>;
286
+ write(file: CopilotAuthFile): Promise<void>;
287
+ }
288
+ /** Compare-and-swap variant used by normal runtime composition. */
289
+ type CopilotCredentialStore = CredentialStore<CopilotAuthFile>;
290
+ //#endregion
291
+ //#region src/router.d.ts
292
+ /**
293
+ * Model id prefixes dispatched to `/responses` when the catalog says nothing.
294
+ *
295
+ * Exported and overridable for the same reason `COPILOT_EDITOR_VERSION` is: this
296
+ * is a fact about a remote endpoint that WILL go stale, and a user has to be able
297
+ * to correct it without waiting for a release.
298
+ * `CopilotProviderOptions.responsesModelPrefixes` ADDS to this list rather than
299
+ * replacing it, so an override cannot silently drop the prefixes shipped here.
300
+ *
301
+ * Kept deliberately short. A prefix that matches too much pushes models toward
302
+ * the endpoint where guessing wrong costs the request (see the module note), so
303
+ * an absent prefix is the cheaper error.
304
+ */
305
+ declare const COPILOT_RESPONSES_MODEL_PREFIXES: readonly string[];
306
+ /** The endpoint chosen for one model id, and who chose it. */
307
+ interface CopilotEndpointDecision {
308
+ /** The model id the decision is keyed by, verbatim as the caller spelled it. */
309
+ readonly model: string;
310
+ /** The endpoint the request goes to. */
311
+ readonly endpoint: CopilotEndpoint;
312
+ /** Wire protocol id of the sub-protocol that serves {@link endpoint}. */
313
+ readonly protocolId: string;
314
+ /**
315
+ * Which step of the decision order produced this.
316
+ *
317
+ * Reported to observation (Requirement 9.8) so that when a model runs against
318
+ * the wrong endpoint, the log says who decided rather than leaving an operator
319
+ * to reconstruct it.
320
+ */
321
+ readonly source: 'override' | 'catalog' | 'allowlist' | 'default';
322
+ }
323
+ /** Memoized, append-only endpoint selection for one adapter instance. */
324
+ interface CopilotEndpointRouter {
325
+ /**
326
+ * Decide the endpoint for a model id.
327
+ *
328
+ * MEMOIZED AND APPEND-ONLY: a key that already has a decision is returned
329
+ * unchanged and never recomputed. This is the mechanism that makes
330
+ * Requirement 9.7 hold — no code path can change its mind between two retries.
331
+ * @param modelId - the wire model id of the request being dispatched.
332
+ * @returns the decision for that model, recording it on first sight.
333
+ */
334
+ decide(modelId: string): CopilotEndpointDecision;
335
+ /**
336
+ * Feed in discovered catalog metadata.
337
+ *
338
+ * Adds ONLY keys that have no decision yet; an id already decided is skipped
339
+ * even when the metadata now disagrees with the recorded decision.
340
+ * @param models - the generation half of a {@link CopilotGenerationModel} list.
341
+ */
342
+ learn(models: readonly CopilotGenerationModel[]): void;
343
+ /**
344
+ * Every decision recorded so far, in the order it was recorded.
345
+ * @returns a frozen snapshot, for `--models` and for the conformance harness.
346
+ */
347
+ snapshot(): readonly CopilotEndpointDecision[];
348
+ }
349
+ /** Construction options for {@link createCopilotEndpointRouter}. */
350
+ interface CopilotEndpointRouterOptions {
351
+ /**
352
+ * Endpoints pinned by the application, keyed by model id. Wins over every
353
+ * other source, including a catalog disclosure that contradicts it.
354
+ */
355
+ readonly overrides?: Readonly<Record<string, CopilotEndpoint>>;
356
+ /**
357
+ * The full responses-prefix allowlist to use.
358
+ *
359
+ * The caller passes the already-merged list — `copilotAdapter` spreads
360
+ * {@link COPILOT_RESPONSES_MODEL_PREFIXES} first and the user's additions
361
+ * after — so the "adds, never replaces" rule is visible at the call site
362
+ * instead of hidden in here. Defaults to the shipped list when omitted.
363
+ */
364
+ readonly prefixes?: readonly string[];
365
+ }
366
+ /**
367
+ * Build a router for one adapter instance.
368
+ *
369
+ * Overrides are validated HERE, not at dispatch: a typo in
370
+ * `endpointOverrides` is a configuration mistake, and a configuration mistake
371
+ * that surfaces while building the provider is cheaper than one that surfaces on
372
+ * the first request to one particular model.
373
+ * @param options - overrides and the merged prefix allowlist.
374
+ * @returns a router whose `decisions` map only ever grows.
375
+ * @throws AgentSdkError with `COPILOT_ENDPOINT_OVERRIDE_INVALID` when an
376
+ * override pins an endpoint that does not exist.
377
+ */
378
+ declare function createCopilotEndpointRouter(options?: CopilotEndpointRouterOptions): CopilotEndpointRouter;
379
+ //#endregion
380
+ //#region src/dual-protocol.d.ts
381
+ /** Protocol id the HTTP layer reports for every Copilot request. */
382
+ declare const COPILOT_DUAL_PROTOCOL_ID = "copilot-dual";
383
+ /**
384
+ * The Copilot dialect, FLAT on purpose.
385
+ *
386
+ * Declared in this module rather than in `./adapter.ts` — where the design's file
387
+ * map lists it — for one structural reason: `copilotAdapter` builds the composite,
388
+ * so the source edge already runs adapter → dual-protocol, and the two projection
389
+ * functions are runtime values. Declaring them in `./adapter.ts` would make that
390
+ * edge bidirectional, which the repo's circular-dependency check forbids. The
391
+ * public placement is preserved by re-export: `./adapter.ts` re-exports this type
392
+ * and both projections, the same way `./router.ts` re-exports `CopilotEndpoint`
393
+ * from `./catalog.ts`. DD-2 also puts ownership here —
394
+ * "the composite owns the two pure projection functions".
395
+ *
396
+ * Every field is a primitive or a string array. See rule 2 in the module note for
397
+ * why nesting the two sub-dialects instead would be a silent-data-loss bug.
398
+ */
399
+ interface CopilotDialect {
400
+ /** Send temperature/top_p. Both endpoints accept them; some models refuse. */
401
+ readonly sampling: boolean;
402
+ /** Send the output-token limit. */
403
+ readonly maxOutputTokens: boolean;
404
+ /** Send JSON-schema structured output. */
405
+ readonly structuredOutputs: boolean;
406
+ /** Declare tools in the request. */
407
+ readonly tools: boolean;
408
+ /** Responses only: `store`. */
409
+ readonly store: boolean;
410
+ /** Responses only: `include`. */
411
+ readonly include: readonly string[];
412
+ /** Responses only: `reasoning.summary`. `'none'` asks for no summary at all. */
413
+ readonly reasoningSummary: 'auto' | 'concise' | 'detailed' | 'none';
414
+ /** Chat Completions only: `stream_options.include_usage`. */
415
+ readonly streamUsage: boolean;
416
+ /** Chat Completions only: the role the system prompt travels under. */
417
+ readonly systemRole: 'system' | 'developer';
418
+ /** Chat Completions only: `parallel_tool_calls`. */
419
+ readonly parallelToolCalls: boolean;
420
+ /** Prompt/session cache key, used by BOTH branches. */
421
+ readonly promptCacheKey?: string;
422
+ }
423
+ /**
424
+ * Conservative defaults, matching each sub-protocol's own defaults where the two
425
+ * agree.
426
+ *
427
+ * `store: false` because retaining prompts on someone else's server is an explicit
428
+ * decision, `include` carries `reasoning.encrypted_content` because without it a
429
+ * reasoning model loses its chain of thought across a tool call, and
430
+ * `parallelToolCalls: false` because older gateways reject the field outright.
431
+ */
432
+ declare const COPILOT_DEFAULT_DIALECT: CopilotDialect;
433
+ /**
434
+ * Project the Copilot dialect onto the Responses dialect.
435
+ *
436
+ * PURE and TOTAL: every {@link CopilotDialect} flag has exactly one destination
437
+ * here or none at all. `tools`, `streamUsage`, `systemRole` and
438
+ * `parallelToolCalls` have no Responses destination and are DROPPED rather than
439
+ * bent into a nearby flag — Responses declares tools from the request itself and
440
+ * has no `reasoning_effort`-style neighbour worth guessing at.
441
+ *
442
+ * `reasoningSummary: 'none'` is expressed by ABSENCE, because that is how the
443
+ * Responses serializer spells "ask for no summary" (`summary` is only sent when
444
+ * the knob is defined). {@link resolvedResponsesDialect} therefore drops the
445
+ * sub-protocol's own `reasoningSummary` default before merging, so this branch of
446
+ * the projection is not overwritten by it.
447
+ * @param dialect - the resolved Copilot dialect for this request.
448
+ * @returns the Responses knobs this dialect determines, and only those.
449
+ */
450
+ declare function toResponsesDialect(dialect: CopilotDialect): Partial<ResponsesDialect>;
451
+ /**
452
+ * Project the Copilot dialect onto the Chat Completions dialect.
453
+ *
454
+ * PURE and TOTAL, same rule as {@link toResponsesDialect}: `store`, `include` and
455
+ * `reasoningSummary` have no Chat Completions destination and are dropped —
456
+ * `reasoningEffort` is a different knob (how hard to think, not whether to report
457
+ * a summary), so mapping onto it would be a guess dressed as a translation.
458
+ *
459
+ * Two flags change type on the way across, and each mapping is total:
460
+ *
461
+ * | Copilot | Chat Completions |
462
+ * | --- | --- |
463
+ * | `maxOutputTokens: true` | `maxTokensField: 'max_tokens'` |
464
+ * | `maxOutputTokens: false` | `maxTokensField: false` |
465
+ * | `structuredOutputs: true` | `structuredOutputs: 'json-schema'` |
466
+ * | `structuredOutputs: false` | `structuredOutputs: false` |
467
+ *
468
+ * The accepted cost of the first row: a caller cannot reach
469
+ * `'max_completion_tokens'` through {@link CopilotDialect}. Copilot's
470
+ * `/chat/completions` takes `max_tokens`, and the models that demand the newer
471
+ * spelling are the ones the router sends to `/responses` anyway, so the boolean
472
+ * buys a flag a caller can reason about and costs a spelling no Copilot model has
473
+ * been observed to need.
474
+ * @param dialect - the resolved Copilot dialect for this request.
475
+ * @returns the Chat Completions knobs this dialect determines, and only those.
476
+ */
477
+ declare function toChatCompletionsDialect(dialect: CopilotDialect): Partial<ChatCompletionsDialect>;
478
+ /**
479
+ * The parts of a sub-protocol the composite uses.
480
+ *
481
+ * Structural rather than an import of either package's own definition type, so
482
+ * that a test can hand in a stub and so that neither sub-protocol's marker fields
483
+ * become part of this contract.
484
+ */
485
+ interface CopilotSubProtocol<Dialect extends object> {
486
+ /** Reported on the decision as `protocolId`. */
487
+ readonly id: string;
488
+ /** Merged UNDER the projection by the composite; never read by the runtime. */
489
+ readonly defaultDialect: Dialect;
490
+ readonly endpointPath: (request: ProtocolRequest, dialect: Dialect) => string;
491
+ readonly protocolHeaders?: (dialect: Dialect) => Readonly<Record<string, string>>;
492
+ readonly serialize: (request: ProtocolRequest, dialect: Dialect) => Readonly<Record<string, unknown>>;
493
+ readonly translate: (events: AsyncIterable<ProtocolSseEvent>, request: ProtocolRequest, displayName: string) => AsyncGenerator<ProtocolStreamChunk>;
494
+ }
495
+ /** The `/responses` half. `openAiResponsesProtocol` satisfies this. */
496
+ type ResponsesProtocolLike = CopilotSubProtocol<ResponsesDialect>;
497
+ /** The `/chat/completions` half. `openAiChatCompletionsProtocol` satisfies this. */
498
+ type ChatCompletionsProtocolLike = CopilotSubProtocol<ChatCompletionsDialect>;
499
+ /** Construction options for {@link copilotDualProtocol}. */
500
+ interface CopilotDualProtocolOptions {
501
+ /** Decides, once per model id, which branch a request takes. */
502
+ readonly router: CopilotEndpointRouter;
503
+ /** The protocol serving `/responses`. */
504
+ readonly responses: ResponsesProtocolLike;
505
+ /** The protocol serving `/chat/completions`. */
506
+ readonly chat: ChatCompletionsProtocolLike;
507
+ /**
508
+ * Synchronous, best-effort observer of every endpoint decision (Requirement
509
+ * 9.8).
510
+ *
511
+ * Carries `{ model, endpoint, protocolId, source }` — no prompt and no
512
+ * credential, because an observer is a diagnostic channel and neither of those
513
+ * is diagnostic. Throwing in here does NOT affect the request: the error is
514
+ * trapped, since a broken log sink must not decide whether a generation runs.
515
+ */
516
+ readonly onDecision?: (decision: CopilotEndpointDecision) => void;
517
+ }
518
+ /**
519
+ * Build the composite protocol.
520
+ *
521
+ * @param options - the router, the two sub-protocols, and the optional observer.
522
+ * @returns a `RuntimeWireProtocol<CopilotDialect>` with id `'copilot-dual'`.
523
+ */
524
+ declare function copilotDualProtocol(options: CopilotDualProtocolOptions): RuntimeWireProtocol<CopilotDialect>;
525
+ //#endregion
526
+ //#region src/auth.d.ts
527
+ /**
528
+ * The command that produces a credential, named in every message that tells a
529
+ * caller how to fix a credential problem.
530
+ *
531
+ * Exported so the token-exchange path names the SAME command: a 401 and a 403
532
+ * there both end in "sign in again", and two copies of that string are two
533
+ * strings that can drift apart.
534
+ */
535
+ declare const COPILOT_LOGIN_COMMAND = "npm run provider:copilot:login-device";
536
+ /**
537
+ * An in-memory {@link CopilotAuthStore} — the read/write variant (Requirement 6.4).
538
+ *
539
+ * The read/write variant exists for symmetry with Codex; normal runtime
540
+ * composition uses {@link memoryCopilotCredentialStore}, the compare-and-swap
541
+ * variant.
542
+ * @param initial - the file the store starts with, or nothing for an empty store.
543
+ * @returns a store backed by a single mutable slot.
544
+ */
545
+ declare function memoryCopilotAuthStore(initial?: CopilotAuthFile): CopilotAuthStore;
546
+ /**
547
+ * An in-memory compare-and-swap store, for deterministic runtime and tests
548
+ * (Requirements 6.2, 6.4).
549
+ *
550
+ * Values are `structuredClone`d in BOTH directions, which is the point of this
551
+ * double: a caller that mutates the object it wrote, or the object it read, must
552
+ * not be able to change what the store holds. Without the clone a test could pass
553
+ * for the wrong reason — the store and the caller sharing one object rather than
554
+ * the store having committed anything.
555
+ *
556
+ * A commit whose `expectedRevision` disagrees with the current revision raises
557
+ * {@link COPILOT_ERROR_CODES.CREDENTIAL_REVISION_CONFLICT} (Requirement 6.3), the
558
+ * Copilot-owned code, so exactly one of two concurrent commits wins and the loser
559
+ * can tell why it lost.
560
+ * @param initial - the file the store starts with, or nothing for an empty store.
561
+ * @returns a compare-and-swap store over a single mutable slot.
562
+ */
563
+ declare function memoryCopilotCredentialStore(initial?: CopilotAuthFile): CopilotCredentialStore;
564
+ /**
565
+ * One read of the credential store, carried through a single operation.
566
+ *
567
+ * `revision` travels with `file` rather than being re-read later, because the
568
+ * token cache keys on the pair: a file that changed under us has a different
569
+ * revision even when the token value happens to be identical.
570
+ */
571
+ interface CopilotCredentialSnapshot {
572
+ readonly file: CopilotAuthFile;
573
+ /** The revision at read time, or `null` for a store with no revisions. */
574
+ readonly revision: string | null;
575
+ /** The store's human-readable location, named in diagnostics. */
576
+ readonly label: string;
577
+ }
578
+ /**
579
+ * Require a usable `GitHub_User_Token`, with a message that says how to get one.
580
+ *
581
+ * Three shapes of "there is no credential" — an empty store, a file with no
582
+ * `github` field, and a `github.token` that is the empty string — collapse into
583
+ * the SAME code, because to the person reading the error they are one problem
584
+ * with one fix. That code is the SDK's own {@link MISSING_CREDENTIAL_CODE} rather
585
+ * than a Copilot-specific one, so a consumer does not have to write a second
586
+ * branch for a situation it already handles, and the message carries the command
587
+ * to run `Copilot_Login_Cli` (Requirement 13.4).
588
+ *
589
+ * The token value is never interpolated into the message; only the store's label
590
+ * is (Requirement 13.7).
591
+ * @param file - the credential file, or `undefined` when the store was empty.
592
+ * @param label - the store location named in the diagnostic.
593
+ * @returns the long-lived GitHub token.
594
+ */
595
+ declare function requireGitHubToken(file: CopilotAuthFile | undefined, label: string): CopilotGitHubToken;
596
+ /** Exchange this long before the `Copilot_Api_Token` actually expires. */
597
+ declare const COPILOT_TOKEN_EXCHANGE_MARGIN_MS: number;
598
+ /**
599
+ * The part of a `Copilot_Api_Token` that {@link shouldExchange} reads.
600
+ *
601
+ * Declared here rather than imported so this module owns no dependency on the
602
+ * exchange module: expiry arithmetic is the whole of what the decision needs, and
603
+ * `CopilotApiToken` — which carries the token value and the declared endpoint
604
+ * besides — satisfies this shape structurally, so `shouldExchange` accepts one
605
+ * with no conversion and there is only ever one declaration of the full type.
606
+ */
607
+ interface CopilotTokenExpiry {
608
+ /** Expiry instant in epoch MILLISECONDS, derived from the endpoint's `expires_at`. */
609
+ readonly expiresAtMs: number;
610
+ /** The endpoint's `refresh_in` hint, in seconds, when it sent one. Advisory. */
611
+ readonly refreshInSeconds?: number;
612
+ }
613
+ /**
614
+ * Whether a token exchange has to happen before the next request.
615
+ *
616
+ * A pure function of three values that reads no global clock, so a property test
617
+ * can place `now` at every boundary without a fake timer (Requirements 5.2, 5.3).
618
+ * `undefined` — no token yet — is always `true`.
619
+ *
620
+ * `expires_at` is the authority and `refresh_in` is advisory: the hint may only
621
+ * SHORTEN the refresh moment, never lengthen it. The endpoint is allowed to ask
622
+ * for an earlier exchange; it is not allowed to ask this SDK to hold a token past
623
+ * the expiry it announced itself.
624
+ *
625
+ * There is deliberately no fallback branch. `shouldRefresh` in
626
+ * `provider-codex/src/auth.ts` decodes a JWT for `exp` and falls back to a
627
+ * `last_refresh` age when it cannot; a `Copilot_Api_Token` is not a JWT this SDK
628
+ * has any business reading, and the expiry is stated outright in the exchange
629
+ * response body. With no second source, a fallback would have to invent a
630
+ * lifetime, and an invented lifetime violates the no-inference principle.
631
+ *
632
+ * Because the decision is made BEFORE dispatch, a 401 from the Copilot base URL
633
+ * always means the credential is genuinely dead rather than "the token expired
634
+ * mid-flight" — which is what lets auth failures stay non-retryable
635
+ * (Requirement 5.8).
636
+ * @param api - the cached token, or `undefined` when there is none.
637
+ * @param now - current time in epoch milliseconds.
638
+ * @param marginMs - exchange this long before expiry.
639
+ * @returns true when an exchange is due.
640
+ */
641
+ declare function shouldExchange(api: CopilotTokenExpiry | undefined, now: number, marginMs?: number): boolean;
642
+ //#endregion
643
+ //#region src/common/http.d.ts
644
+ /** Shared HTTP settings. Every field is optional and every default is a bound, not "unlimited". */
645
+ interface CopilotHttpOptions {
646
+ /** Cancellation for the request and for the body read. */
647
+ readonly signal?: AbortSignal;
648
+ /** HTTP implementation, for tests and non-browser runtimes. */
649
+ readonly fetch?: typeof globalThis.fetch;
650
+ /** Deadline for one request. Defaults to {@link COPILOT_DEFAULT_REQUEST_TIMEOUT_MS}. */
651
+ readonly requestTimeoutMs?: number;
652
+ /** Maximum response bytes. Defaults to {@link COPILOT_DEFAULT_MAX_RESPONSE_BYTES}. */
653
+ readonly maxResponseBytes?: number;
654
+ /** Maximum response chunks. Defaults to {@link COPILOT_DEFAULT_MAX_RESPONSE_CHUNKS}. */
655
+ readonly maxResponseChunks?: number;
656
+ /**
657
+ * Permit an `http:` origin for a trusted local test endpoint. Defaults to false.
658
+ *
659
+ * A separate, explicitly enabled option rather than a lenient default, because
660
+ * cleartext HTTP here carries a bearer token (Requirement 2.2).
661
+ */
662
+ readonly allowInsecureIssuer?: boolean;
663
+ }
664
+ //#endregion
665
+ //#region src/exchange.d.ts
666
+ /** GitHub's API base, where the token-exchange surface lives. */
667
+ declare const DEFAULT_GITHUB_API_BASE_URL = "https://api.github.com";
668
+ /** Path of the token-exchange surface. */
669
+ declare const COPILOT_TOKEN_EXCHANGE_PATH = "/copilot_internal/v2/token";
670
+ /** Settings for one token exchange. Every field is optional; every default is a bound. */
671
+ interface CopilotExchangeOptions extends CopilotHttpOptions {
672
+ /** Overrides {@link DEFAULT_GITHUB_API_BASE_URL}; pinned as its own origin. */
673
+ readonly githubApiBaseUrl?: string;
674
+ /** Overrides for the two mandatory editor headers. */
675
+ readonly editorHeaders?: CopilotEditorHeaders;
676
+ /**
677
+ * Further secret values to strike out of any body this exchange retains,
678
+ * beyond the credential it sends itself.
679
+ *
680
+ * Requirement 13.7 is stated over BOTH tokens, not just the one a given request
681
+ * carries, and an exchange knows only its own. The remaining value — the
682
+ * `Copilot_Api_Token` currently held — reaches this path from
683
+ * {@link createCopilotTokenCache}, which is the one component holding both at
684
+ * once. Without it, a body echoing the live API token back would travel into
685
+ * `cause` intact, because the redaction here would be looking for the wrong
686
+ * string.
687
+ */
688
+ readonly additionalSecrets?: readonly string[];
689
+ }
690
+ /**
691
+ * The result of one `Copilot_Token_Exchange`, held in process memory only.
692
+ *
693
+ * Structurally satisfies `CopilotTokenExpiry` from `./auth.ts`, so `shouldExchange`
694
+ * accepts one of these with no conversion.
695
+ */
696
+ interface CopilotApiToken {
697
+ /** Bearer token for the Copilot API base. Short-lived, ~25 minutes. */
698
+ readonly token: string;
699
+ /** Expiry instant in epoch MILLISECONDS, derived from `expires_at` (seconds). */
700
+ readonly expiresAtMs: number;
701
+ /** The endpoint's `refresh_in` hint in seconds, when it sent a usable one. ADVISORY. */
702
+ readonly refreshInSeconds?: number;
703
+ /**
704
+ * The endpoint's declared `endpoints.api`, when present.
705
+ *
706
+ * MUST NOT be used as a base URL. A server-designated base URL is a redirect
707
+ * under another name, and Requirements 3.8/7.8 settled that this SDK does not
708
+ * follow provider-controlled redirection. This field exists so `--status` can
709
+ * print it and so a configuration drift is visible. See DD-6.
710
+ */
711
+ readonly declaredApiEndpoint?: string;
712
+ }
713
+ /**
714
+ * Exchange a `GitHub_User_Token` for a `Copilot_Api_Token`.
715
+ *
716
+ * The long-lived credential is NOT consumed: nothing here writes to a store, and
717
+ * the persisted value is left exactly as it was (Requirement 3.4).
718
+ * @param github - the long-lived GitHub user token. Its value never reaches an
719
+ * error message, and any occurrence of it in a response body is redacted before
720
+ * the body is retained as a cause (Requirement 13.7).
721
+ * @param options - base URL override, injected fetch, signal, and the read bounds.
722
+ * @returns the short-lived token plus its expiry and the advisory fields.
723
+ * @throws AgentSdkError with `COPILOT_ENDPOINT_ORIGIN_INVALID` or
724
+ * `COPILOT_REDIRECT_REJECTED`, or {@link CopilotTokenExchangeError} with
725
+ * `COPILOT_TENANT_UNSUPPORTED`, `COPILOT_CREDENTIAL_REJECTED`,
726
+ * `COPILOT_TOKEN_EXCHANGE_FAILED` or `COPILOT_TOKEN_MALFORMED`, per the
727
+ * classification order in the module note.
728
+ */
729
+ declare function exchangeCopilotToken(github: CopilotGitHubToken, options?: CopilotExchangeOptions): Promise<CopilotApiToken>;
730
+ /**
731
+ * A cache entry, bound to exactly the credential that produced it.
732
+ *
733
+ * The pair `(sourceToken, sourceRevision)` is the whole key: signing in as a
734
+ * different account invalidates the entry the moment the store returns a
735
+ * different token value, with no TTL involved and no clock consulted.
736
+ */
737
+ interface CopilotTokenCacheEntry {
738
+ /** The token this credential produced. */
739
+ readonly api: CopilotApiToken;
740
+ /** The `GitHub_User_Token` value used. Compared with `===`. */
741
+ readonly sourceToken: string;
742
+ /** The store revision at read time, or `null` for a store without revisions. */
743
+ readonly sourceRevision: string | null;
744
+ }
745
+ /**
746
+ * The process-memory cache in front of {@link exchangeCopilotToken}.
747
+ *
748
+ * Owned by an adapter instance, and injectable through the adapter's `tokenCache`
749
+ * option so several routes sharing one unchanged credential exchange once rather
750
+ * than once per route.
751
+ */
752
+ interface CopilotTokenCache {
753
+ /**
754
+ * Return a live `Copilot_Api_Token` for this credential, exchanging when due.
755
+ *
756
+ * Concurrent calls that all need an exchange are COALESCED into exactly one
757
+ * in-flight exchange (Requirement 5.4).
758
+ * @param source - one read of the credential store, revision included.
759
+ * @param operation - the calling operation; only its signal is read, and it
760
+ * bounds THIS caller's wait, never the shared exchange.
761
+ * @param context - invocation context for the observation record, when there is one.
762
+ * @returns a token that is live as of the decision moment.
763
+ */
764
+ acquire(source: CopilotCredentialSnapshot, operation: CredentialOperationOptions, context?: ModelInvocationContext): Promise<CopilotApiToken>;
765
+ /** Drop the current entry; used when the API surface rejects a token before its expiry. */
766
+ invalidate(): void;
767
+ }
768
+ /** Provider name recorded on the credential-operation observation by default. */
769
+ declare const COPILOT_PROVIDER_ID = "copilot";
770
+ /** Settings for {@link createCopilotTokenCache}: the exchange settings, plus a clock. */
771
+ interface CopilotTokenCacheOptions extends CopilotExchangeOptions {
772
+ /**
773
+ * Provider name on the observation record. Defaults to {@link COPILOT_PROVIDER_ID}.
774
+ *
775
+ * An adapter with a custom `id` passes it here so the record names the provider
776
+ * the caller configured rather than the family.
777
+ */
778
+ readonly providerId?: string;
779
+ /** Exchange this long before expiry. Defaults to `COPILOT_TOKEN_EXCHANGE_MARGIN_MS`. */
780
+ readonly marginMs?: number;
781
+ /**
782
+ * The clock the exchange decision reads, injectable so a test places `now`
783
+ * exactly on a boundary instead of waiting for one.
784
+ */
785
+ readonly now?: () => number;
786
+ }
787
+ /**
788
+ * Build a token cache over one set of exchange settings.
789
+ *
790
+ * ## The mistake this is written to avoid
791
+ *
792
+ * The shared exchange gets its OWN `AbortController` plus its own deadline, and
793
+ * NEVER any single caller's signal. Were the caller's signal handed to it, the
794
+ * first caller to abort would cancel the exchange every other caller is waiting
795
+ * on, and those callers would fail for a reason that has nothing to do with them.
796
+ * Instead each caller — the one that started the exchange included — races the
797
+ * shared promise against its OWN signal: an aborted caller leaves, and the
798
+ * exchange still completes for everyone else (Property 18).
799
+ *
800
+ * The observation therefore counts exchanges actually DISPATCHED rather than
801
+ * callers served, which is what makes the coalescing observable instead of merely
802
+ * claimed (Property 52). It is recorded with the `'refresh'` operation name: that
803
+ * parameter's union is closed at `'resolve' | 'refresh' | 'login'`, widening it
804
+ * would change a public type of `provider-http`, and Requirement 18.4 forbids
805
+ * that — see DD-7.
806
+ *
807
+ * ## Two paths deliberately absent
808
+ *
809
+ * There is no revision-conflict recovery, unlike `provider-codex`. That path
810
+ * exists there because a Codex refresh token rotates and is single-use, so a lost
811
+ * race destroys a credential. A `GitHub_User_Token` does not rotate and an
812
+ * exchange does not consume it, so two racing processes simply exchange twice —
813
+ * and a branch no situation reaches is a branch nothing verifies (DD-8).
814
+ *
815
+ * Nothing here writes to a store. The `Copilot_Api_Token` is never persisted: it
816
+ * lives ~25 minutes, so persisting it would add a second secret on disk, a second
817
+ * write path, and a new state to reason about, to save one request inside a
818
+ * 25-minute window (DD-9, Requirement 3.3).
819
+ *
820
+ * A failure is returned to every waiting caller as-is and never retried here — an
821
+ * endpoint that rejected the credential will reject it again, and this layer has
822
+ * no way to change that (Requirement 5.8, Property 19).
823
+ * @param options - exchange settings, the observation provider name, the margin
824
+ * and the clock. `options.signal` is deliberately IGNORED for the exchange
825
+ * itself; per-caller cancellation travels through `operation.signal`.
826
+ * @returns a cache over a single credential slot.
827
+ */
828
+ declare function createCopilotTokenCache(options?: CopilotTokenCacheOptions): CopilotTokenCache;
829
+ //#endregion
830
+ //#region src/adapter.d.ts
831
+ /** Registry id, provider family, and observation label when the caller sets none. */
832
+ declare const COPILOT_ROUTE_ID = "copilot";
833
+ /** Display name reported by the adapter and the plugin. */
834
+ declare const COPILOT_DISPLAY_NAME = "GitHub Copilot";
835
+ /**
836
+ * Everything a Copilot route can be configured with.
837
+ *
838
+ * The `authStore` is REQUIRED and injected: paths, the filesystem and the
839
+ * environment belong to `Copilot_Node_Auth`, so a Universal package cannot supply
840
+ * a default here (Requirement 6.1). Every other field is optional, and an absent
841
+ * one is spread away rather than passed as `undefined` — see
842
+ * {@link copilotAdapter}.
843
+ */
844
+ interface CopilotProviderOptions {
845
+ /**
846
+ * Where the credentials live: the compare-and-swap variant.
847
+ *
848
+ * This is the main path. {@link copilotAdapter} also accepts the read/write
849
+ * variant through an overload; `copilotPlugin` does not, because transactional
850
+ * registration and a store with no revisions are a poor pair.
851
+ */
852
+ readonly authStore: CopilotCredentialStore;
853
+ /** Endpoint base; defaults to `COPILOT_BASE_URL`. */
854
+ readonly baseUrl?: string;
855
+ /**
856
+ * Permit a cleartext `http:` base URL.
857
+ *
858
+ * Explicit opt-in rather than a lenient default, because every request to this
859
+ * surface carries a bearer token (Requirement 2.2).
860
+ */
861
+ readonly allowInsecureHttp?: boolean;
862
+ /** Overrides for the two mandatory editor headers (Requirement 2.4). */
863
+ readonly editorHeaders?: CopilotEditorHeaders;
864
+ /** Pin an endpoint for specific model ids, overriding the router (Requirement 9.6). */
865
+ readonly endpointOverrides?: Readonly<Record<string, CopilotEndpoint>>;
866
+ /**
867
+ * Extra model-id prefixes treated as `/responses`-capable when the catalog says
868
+ * nothing.
869
+ *
870
+ * ADDS to `COPILOT_RESPONSES_MODEL_PREFIXES`; it cannot replace it, so an
871
+ * override never silently drops a prefix this package ships.
872
+ */
873
+ readonly responsesModelPrefixes?: readonly string[];
874
+ /** Synchronous, best-effort observer of every endpoint decision (Requirement 9.8). */
875
+ readonly onEndpointDecision?: (decision: CopilotEndpointDecision) => void;
876
+ /**
877
+ * A token cache shared with other routes.
878
+ *
879
+ * Pass one cache to several routes backed by the SAME credential and they
880
+ * exchange once between them instead of once each.
881
+ */
882
+ readonly tokenCache?: CopilotTokenCache;
883
+ /** Exchange this long before the API token expires. */
884
+ readonly exchangeMarginMs?: number;
885
+ /** GitHub API base, where the token exchange lives; pinned as its own origin. */
886
+ readonly githubApiBaseUrl?: string;
887
+ /**
888
+ * The model catalog.
889
+ *
890
+ * Left undefined, the adapter DISCOVERS it: which models an account may call
891
+ * depends on its plan, its organisation policy and the editor identity the
892
+ * request presents, so no hardcoded list is right for two accounts at once
893
+ * (Requirement 8.1).
894
+ */
895
+ readonly models?: readonly ProviderCatalogModel[];
896
+ /** Maximum raw catalog bytes. */
897
+ readonly maxCatalogBytes?: number;
898
+ /** Maximum catalog entries; more than this is a malformed catalog, not a truncated one. */
899
+ readonly maxCatalogModels?: number;
900
+ /** Maximum catalog response chunks. */
901
+ readonly maxCatalogChunks?: number;
902
+ /** Catalog request deadline. */
903
+ readonly catalogTimeoutMs?: number;
904
+ /** How long a discovered catalog stays fresh. */
905
+ readonly catalogTtlMs?: number;
906
+ /** How long a stale catalog may still be served while a refresh runs. */
907
+ readonly catalogStaleTtlMs?: number;
908
+ /** How long to wait before retrying discovery after it failed. */
909
+ readonly catalogFailureBackoffMs?: number;
910
+ /** Dialect overrides, merged shallowly over `COPILOT_DEFAULT_DIALECT`. */
911
+ readonly dialect?: Partial<CopilotDialect>;
912
+ /** Output cap when neither caller nor catalog names one. */
913
+ readonly defaultMaxTokens?: number;
914
+ /** Context capacity assumed for an uncatalogued model. */
915
+ readonly defaultContextWindow?: number;
916
+ /** Idle bound while a stream read is outstanding. */
917
+ readonly streamIdleTimeoutMs?: number;
918
+ /** Deadline for one request. */
919
+ readonly requestTimeoutMs?: number;
920
+ /** Maximum serialized request bytes. */
921
+ readonly maxRequestBytes?: number;
922
+ /** Maximum response bytes. */
923
+ readonly maxResponseBytes?: number;
924
+ /** Maximum response chunks. */
925
+ readonly maxResponseChunks?: number;
926
+ /** Maximum SSE events in one stream. */
927
+ readonly maxSseEvents?: number;
928
+ /** Maximum characters in one SSE event. */
929
+ readonly maxSseEventChars?: number;
930
+ /** Maximum bytes read from a non-success response (Requirement 13.6). */
931
+ readonly maxErrorBodyBytes?: number;
932
+ /** Deadline granted to {@link requestLogger} before the request proceeds anyway. */
933
+ readonly requestLoggerTimeoutMs?: number;
934
+ /** Retry policy this route owns (Requirement 7.7). */
935
+ readonly retryPolicy?: RetryPolicyConfig;
936
+ /**
937
+ * Exact wire-request observer.
938
+ *
939
+ * BEST-EFFORT: credentials are redacted by the transport, the logger's deadline
940
+ * is `requestLoggerTimeoutMs`, and a logger that overruns or throws does not
941
+ * stop the request (Requirement 14.5).
942
+ */
943
+ readonly requestLogger?: ProviderRequestLogger;
944
+ /** HTTP implementation, for tests and non-browser runtimes. */
945
+ readonly fetch?: typeof globalThis.fetch;
946
+ /** Registry id; defaults to {@link COPILOT_ROUTE_ID}. */
947
+ readonly id?: string;
948
+ /** Routes the plugin installs; defaults to `[id]`. */
949
+ readonly routes?: readonly string[];
950
+ /** Default model; a string form requires exactly one route (Requirement 7.5). */
951
+ readonly defaultModel?: string | ModelTarget;
952
+ }
953
+ /**
954
+ * The same options against the read/write store variant.
955
+ *
956
+ * Kept for symmetry with `provider-codex` and with the two store contracts
957
+ * (Requirement 7.3). It has no revisions, so a commit cannot be
958
+ * compare-and-swapped — which costs nothing here, since nothing on the Copilot
959
+ * credential path writes.
960
+ */
961
+ interface CopilotLegacyProviderOptions extends Omit<CopilotProviderOptions, 'authStore'> {
962
+ /** Where the credentials live: the read/write variant. */
963
+ readonly authStore: CopilotAuthStore;
964
+ }
965
+ /**
966
+ * Create a Copilot adapter.
967
+ *
968
+ * Both store variants are accepted, and the variant is chosen by INSPECTING THE
969
+ * MARKER through `captureCopilotStore` — which reads data properties only and
970
+ * performs no storage I/O, so building a provider cannot run a line of the
971
+ * caller's code (Requirement 7.3).
972
+ * @param options - credential store, endpoint, catalog, dialect and transport settings.
973
+ * @returns the adapter, ready to register.
974
+ * @throws AgentSdkError with `CREDENTIAL_STORE_INVALID` when `authStore` is
975
+ * neither store variant, or `COPILOT_ENDPOINT_OVERRIDE_INVALID` when
976
+ * `endpointOverrides` pins an endpoint that does not exist.
977
+ */
978
+ declare function copilotAdapter(options: CopilotProviderOptions): HttpModelAdapter;
979
+ declare function copilotAdapter(options: CopilotLegacyProviderOptions): HttpModelAdapter;
980
+ /** Plugin options; the CAS store variant only. */
981
+ type CopilotPluginOptions = CopilotProviderOptions;
982
+ /**
983
+ * The transactional plugin for installing the Copilot provider.
984
+ *
985
+ * Composition follows `codexPlugin`: `id` defaults to {@link COPILOT_ROUTE_ID},
986
+ * `family` is `'copilot'`, `routes` defaults to `[id]`, and a string
987
+ * `defaultModel` requires exactly one route so the model target's provider can be
988
+ * inferred (Requirements 7.4, 7.5).
989
+ *
990
+ * One difference from Codex: there is no overload per store variant. The
991
+ * compare-and-swap store is the main path here, the read/write variant exists for
992
+ * symmetry, and {@link copilotAdapter} is where it is accepted (Requirement 6.2).
993
+ * The marker is checked at construction rather than at setup so a wrong store is
994
+ * reported while the runtime is being composed, not on the first generation.
995
+ * @param options - the same options {@link copilotAdapter} takes, CAS store only.
996
+ * @returns a composable plugin registering one Copilot adapter.
997
+ * @throws TypeError when `authStore` is not the compare-and-swap variant, or when
998
+ * a string `defaultModel` is paired with anything but exactly one route.
999
+ */
1000
+ declare function copilotPlugin(options: CopilotPluginOptions): ComposableModelProviderPlugin & {
1001
+ readonly family: 'copilot';
1002
+ };
1003
+ //#endregion
1004
+ //#region src/common/error-codes.d.ts
1005
+ /**
1006
+ * The Copilot error codes, in the leaf layer so the shared HTTP modules can reach
1007
+ * them.
1008
+ *
1009
+ * The taxonomy BELONGS to `../errors.ts` — that module is the public door, and it
1010
+ * re-exports everything here. The definition lives one layer down for a structural
1011
+ * reason: `common/` is a leaf, and `common/http.ts` needs
1012
+ * `ENDPOINT_ORIGIN_INVALID` and `COPILOT_REDIRECT_REJECTED` to throw. Importing
1013
+ * them from a root module would make `common/` depend on the root while the root
1014
+ * already depends on `common/`, which is the source-ownership cycle the repo's
1015
+ * package-graph check forbids. Duplicating the two strings instead would be worse:
1016
+ * a code that exists in two places is a code that can disagree with itself.
1017
+ *
1018
+ * Read `../errors.ts` for the taxonomy's rationale, including the three situations
1019
+ * that deliberately get an EXISTING SDK code rather than a Copilot one.
1020
+ *
1021
+ * @module ai-agent-sdk/providers/copilot/error-codes
1022
+ */
1023
+ /**
1024
+ * Stable codes for the failures that are specific to Copilot.
1025
+ *
1026
+ * Frozen, and flat strings rather than a TS enum, for the same reason the core
1027
+ * taxonomy is: a consumer routes on the value, and the value has to survive
1028
+ * serialization into a log line.
1029
+ */
1030
+ declare const COPILOT_ERROR_CODES: Readonly<{
1031
+ /** The token-exchange surface rejected the credential: a PAT, or a non-allowlisted OAuth App. */
1032
+ readonly CREDENTIAL_REJECTED: 'COPILOT_CREDENTIAL_REJECTED';
1033
+ /** Token exchange failed for a reason that is not the credential. */
1034
+ readonly TOKEN_EXCHANGE_FAILED: 'COPILOT_TOKEN_EXCHANGE_FAILED';
1035
+ /** The token-exchange response carried no readable `expires_at`, or was not JSON. */
1036
+ readonly TOKEN_MALFORMED: 'COPILOT_TOKEN_MALFORMED';
1037
+ /** A `*.ghe.com` data-residency tenant has no token-exchange surface. */
1038
+ readonly TENANT_UNSUPPORTED: 'COPILOT_TENANT_UNSUPPORTED';
1039
+ /** The endpoint rejected the request for missing `Editor_Headers`. */
1040
+ readonly EDITOR_HEADERS_MISSING: 'COPILOT_EDITOR_HEADERS_MISSING';
1041
+ /** The target URL is not on the same origin as the configured issuer/base URL. */
1042
+ readonly ENDPOINT_ORIGIN_INVALID: 'COPILOT_ENDPOINT_ORIGIN_INVALID';
1043
+ /** The response was a redirect; this SDK does not follow it. */
1044
+ readonly REDIRECT_REJECTED: 'COPILOT_REDIRECT_REJECTED';
1045
+ /** Device flow: the user denied the request. */
1046
+ readonly DEVICE_LOGIN_DENIED: 'COPILOT_DEVICE_LOGIN_DENIED';
1047
+ /** Device flow: the code expired server-side. */
1048
+ readonly DEVICE_LOGIN_EXPIRED: 'COPILOT_DEVICE_LOGIN_EXPIRED';
1049
+ /** Device flow: the absolute 15-minute bound passed without approval. */
1050
+ readonly DEVICE_LOGIN_TIMEOUT: 'COPILOT_DEVICE_LOGIN_TIMEOUT';
1051
+ /** Device flow: failed for any other reason. */
1052
+ readonly DEVICE_LOGIN_FAILED: 'COPILOT_DEVICE_LOGIN_FAILED';
1053
+ /** A credential commit found a revision other than the expected one. */
1054
+ readonly CREDENTIAL_REVISION_CONFLICT: 'COPILOT_CREDENTIAL_REVISION_CONFLICT';
1055
+ /** The `/models` response was the wrong shape at the structural level. */
1056
+ readonly CATALOG_MALFORMED: 'COPILOT_CATALOG_MALFORMED';
1057
+ /** `endpointOverrides` pinned a model to an endpoint that does not exist. */
1058
+ readonly ENDPOINT_OVERRIDE_INVALID: 'COPILOT_ENDPOINT_OVERRIDE_INVALID';
1059
+ }>;
1060
+ /** One of the codes {@link COPILOT_ERROR_CODES} owns. */
1061
+ type CopilotErrorCode = (typeof COPILOT_ERROR_CODES)[keyof typeof COPILOT_ERROR_CODES];
1062
+ //#endregion
1063
+ //#region src/errors.d.ts
1064
+ /** A sanitized cause plus the message it is allowed to travel with. */
1065
+ interface CopilotCredentialFailure {
1066
+ /** SDK-authored text. Never carries a token value, because nothing interpolates one in. */
1067
+ readonly message: string;
1068
+ /** The cause, reduced to serializable facts; `undefined` when there was none. */
1069
+ readonly cause: SafeErrorRecord | undefined;
1070
+ }
1071
+ /**
1072
+ * Build the inputs for an error on the Copilot credential path.
1073
+ *
1074
+ * This is the ONLY door: {@link CopilotTokenExchangeError} and
1075
+ * {@link CopilotDeviceLoginError} take a {@link CopilotCredentialFailure} rather
1076
+ * than a raw `cause`, so there is no code path that can attach an unfiltered
1077
+ * value to a credential-path error. `message` is SDK-authored text; a
1078
+ * `GitHub_User_Token` or a `Copilot_Api_Token` is never interpolated into it, and
1079
+ * response bodies reach `cause` only after the bounded read has replaced every
1080
+ * occurrence of the tokens held in memory with `[REDACTED]` (Requirement 13.7).
1081
+ * @param message - SDK-authored, actionable text. No token values.
1082
+ * @param cause - the caught value, if any; filtered before it is retained.
1083
+ * @returns the sanitized pair an error class accepts.
1084
+ */
1085
+ declare function credentialFailure(message: string, cause?: unknown): CopilotCredentialFailure;
1086
+ /** Whether a token-exchange failure can ever succeed on a retry. */
1087
+ type CopilotTokenExchangeFailureKind = 'permanent' | 'transient';
1088
+ /**
1089
+ * A `Copilot_Token_Exchange` that did not produce a token.
1090
+ *
1091
+ * `kind` exists because `code` alone does not answer the only question a caller
1092
+ * has to answer next: `TOKEN_EXCHANGE_FAILED` covers both a 5xx worth waiting out
1093
+ * and a 4xx that will fail identically forever.
1094
+ */
1095
+ declare class CopilotTokenExchangeError extends AgentSdkError {
1096
+ /** Retry classification for this failure. */
1097
+ readonly kind: CopilotTokenExchangeFailureKind;
1098
+ /**
1099
+ * @param failure - message and filtered cause from {@link credentialFailure}.
1100
+ * @param code - the Copilot code for this row of the classification table.
1101
+ * @param kind - whether a retry could ever succeed.
1102
+ */
1103
+ constructor(failure: CopilotCredentialFailure, code: CopilotErrorCode, kind: CopilotTokenExchangeFailureKind);
1104
+ }
1105
+ /** Why a device login ended without a token. */
1106
+ type CopilotDeviceLoginReason = 'denied' | 'expired' | 'timeout' | 'aborted' | 'failed';
1107
+ /**
1108
+ * A device login that ended without a `GitHub_User_Token`.
1109
+ *
1110
+ * The `code` is derived from `reason` rather than passed in, so the two can never
1111
+ * disagree — a caller reading `code` and a caller reading `reason` always see the
1112
+ * same outcome.
1113
+ */
1114
+ declare class CopilotDeviceLoginError extends AgentSdkError {
1115
+ /** The distinguishable reason the flow ended. */
1116
+ readonly reason: CopilotDeviceLoginReason;
1117
+ /**
1118
+ * @param failure - message and filtered cause from {@link credentialFailure}.
1119
+ * @param reason - the outcome; decides the `code`, with `aborted` mapping to
1120
+ * {@link MODEL_ERROR_CODES.ABORTED} rather than a Copilot-specific code.
1121
+ */
1122
+ constructor(failure: CopilotCredentialFailure, reason: CopilotDeviceLoginReason);
1123
+ }
1124
+ //#endregion
1125
+ //#region src/oauth.d.ts
1126
+ /** GitHub's OAuth issuer. */
1127
+ declare const DEFAULT_COPILOT_OAUTH_ISSUER = "https://github.com";
1128
+ /**
1129
+ * Default OAuth client id. Public, not a secret.
1130
+ *
1131
+ * This is the client id published in GitHub's own editor-plugin sources (the
1132
+ * value `copilot.vim` and the other Copilot editor integrations ship in the
1133
+ * clear), which is why it is on the allowlist that
1134
+ * `copilot_internal/v2/token` checks. Sending it means this SDK signs in AS that
1135
+ * editor client. See the module note for why that makes it a named option
1136
+ * instead of a hidden constant.
1137
+ *
1138
+ * ⚠ UNVERIFIED against a live account. Recorded 2026-09-10 from public editor
1139
+ * integration sources only; no sign-in against a real Copilot account has
1140
+ * confirmed THIS client id.
1141
+ *
1142
+ * The 2026-09-10 live run that confirmed the two editor headers did NOT confirm
1143
+ * this value, and could not: it was handed an existing `ghu_` user-to-server token
1144
+ * out of band, so it exercised the EXCHANGE (which answered 200 for that token)
1145
+ * while never running the device flow that would put this `client_id` on the wire.
1146
+ * What that run does establish is the shape of the claim still outstanding — the
1147
+ * exchange endpoint and the allowlist check are live and reachable, and the only
1148
+ * untested link is whether they accept a token minted by this particular app.
1149
+ *
1150
+ * TODO(copilot-identity): confirm on a real Copilot account, then replace this
1151
+ * warning with the confirmation date. To confirm: run the device flow against
1152
+ * `https://github.com/login/device/code` with this `client_id` and
1153
+ * `scope=read:user`, approve it on a Copilot-enabled account, then exchange the
1154
+ * resulting user token at `GET https://api.github.com/copilot_internal/v2/token`.
1155
+ * The client id is confirmed when that exchange returns a Copilot token rather
1156
+ * than 401/403. A non-allowlisted client id fails at the exchange, not at
1157
+ * sign-in, so the device flow succeeding on its own proves nothing — and equally,
1158
+ * an exchange that succeeds for a token this flow did not mint proves nothing
1159
+ * about this constant.
1160
+ */
1161
+ declare const COPILOT_OAUTH_CLIENT_ID = "Iv1.b507a08c87ecfe98";
1162
+ /** Requested scope; enough to exchange a token and read identity, no more. */
1163
+ declare const COPILOT_OAUTH_SCOPE = "read:user";
1164
+ /**
1165
+ * The absolute ceiling on one device login, INDEPENDENT of the server's
1166
+ * `expires_in`.
1167
+ *
1168
+ * `expires_in` is honoured when it is shorter — there is no point polling a code
1169
+ * the server has already retired. It is not honoured when it is longer: a server
1170
+ * that answers `expires_in: 86400` would otherwise hang a CLI for a day, and this
1171
+ * SDK is not the right place to hold that terminal hostage (Requirement 4.3).
1172
+ */
1173
+ declare const COPILOT_DEVICE_CODE_MAX_WAIT_MS: number;
1174
+ /** Poll interval used when the device-code response states none. */
1175
+ declare const COPILOT_DEFAULT_POLL_INTERVAL_SECONDS = 5;
1176
+ /**
1177
+ * Seconds added on every `slow_down`, per RFC 8628 §3.5.
1178
+ *
1179
+ * The increment is what makes the wait STRICTLY increase even when the server
1180
+ * repeats `slow_down` without a new `interval`. Without it, a server that only
1181
+ * ever says "slow down" would be polled at exactly the rate it just objected to.
1182
+ */
1183
+ declare const COPILOT_SLOW_DOWN_INCREMENT_SECONDS = 5;
1184
+ /**
1185
+ * The warning shown beside the user code, worded exactly as the Codex device
1186
+ * prompt words it.
1187
+ *
1188
+ * A device code is a bearer of authorization that the user types into a page they
1189
+ * navigated to themselves. The one attack that works is getting somebody to type
1190
+ * an attacker's code, so the prompt has to say so; and it lives here rather than
1191
+ * in the CLI so every front end that renders a Copilot prompt renders the same
1192
+ * sentence.
1193
+ */
1194
+ declare const COPILOT_DEVICE_LOGIN_WARNING = "Only continue if YOU started this login. If someone sent you this code, stop.";
1195
+ /**
1196
+ * The scheduler the poll loop waits on, injectable so no test waits real time.
1197
+ *
1198
+ * `now` travels with the timer rather than sitting in a second option, because
1199
+ * the two are read together on every iteration: a fake timer that advances
1200
+ * pending callbacks while `Date.now()` stands still would let a test satisfy the
1201
+ * 15-minute bound by accident, in either direction. Handing both through one
1202
+ * object makes "virtual clock" a single substitution (Properties 11, 12, 14).
1203
+ */
1204
+ interface CopilotTimer {
1205
+ /** Schedule `handler` after `ms`; returns whatever handle `clear` accepts. */
1206
+ readonly setTimeout: (handler: () => void, ms: number) => unknown;
1207
+ /** Cancel a handle from {@link CopilotTimer.setTimeout}. */
1208
+ readonly clearTimeout: (handle: unknown) => void;
1209
+ /** Current time in epoch milliseconds. */
1210
+ readonly now: () => number;
1211
+ }
1212
+ /** The real scheduler: `setTimeout`, `clearTimeout` and `Date.now`. */
1213
+ declare const DEFAULT_COPILOT_TIMER: CopilotTimer;
1214
+ /**
1215
+ * Settings for both device-flow legs.
1216
+ *
1217
+ * Extends {@link CopilotHttpOptions}, so the issuer pin, the deadline and the two
1218
+ * read bounds are the same ones every other Copilot call site uses
1219
+ * (Requirement 4.7). `oauthIssuer` is named rather than called `issuer` because
1220
+ * this package pins THREE origins independently and the field name is what says
1221
+ * which one is being set.
1222
+ */
1223
+ interface CopilotOAuthOptions extends CopilotHttpOptions {
1224
+ /** OAuth issuer base URL; defaults to {@link DEFAULT_COPILOT_OAUTH_ISSUER}. */
1225
+ readonly oauthIssuer?: string;
1226
+ /** OAuth client id; defaults to {@link COPILOT_OAUTH_CLIENT_ID}. */
1227
+ readonly clientId?: string;
1228
+ /** Requested scope; defaults to {@link COPILOT_OAUTH_SCOPE}. */
1229
+ readonly scope?: string;
1230
+ /** Scheduler for the poll wait; defaults to {@link DEFAULT_COPILOT_TIMER}. */
1231
+ readonly timer?: CopilotTimer;
1232
+ }
1233
+ /** A pending device authorization the user has to approve. */
1234
+ interface CopilotDeviceCode {
1235
+ /** URL to open in a browser. Displayed to the user; never fetched by this SDK. */
1236
+ readonly verificationUrl: string;
1237
+ /** One-time code the user types there. */
1238
+ readonly userCode: string;
1239
+ /** Opaque handle this SDK polls with. Never shown to the user. */
1240
+ readonly deviceCode: string;
1241
+ /** Seconds to wait between polls, as the server asked. */
1242
+ readonly intervalSeconds: number;
1243
+ /** Seconds until the server retires the code. */
1244
+ readonly expiresInSeconds: number;
1245
+ }
1246
+ /** Progress reported while a device login runs. */
1247
+ interface CopilotLoginProgress {
1248
+ /** The code is ready; show it, with {@link COPILOT_DEVICE_LOGIN_WARNING}. */
1249
+ readonly onPrompt?: (code: CopilotDeviceCode) => void;
1250
+ /** Called before each poll, with the interval currently in effect. */
1251
+ readonly onPoll?: (elapsedMs: number, intervalSeconds: number) => void;
1252
+ }
1253
+ /** Result of a completed device login. */
1254
+ interface CopilotLoginResult {
1255
+ /** Where the credential was written. Always present. */
1256
+ readonly location: string;
1257
+ /** GitHub login, when the endpoint discloses one. */
1258
+ readonly login: string | undefined;
1259
+ /** Numeric account id, when the endpoint discloses one. */
1260
+ readonly accountId: number | undefined;
1261
+ /** Granted scope, when the endpoint discloses it. */
1262
+ readonly scope: string | undefined;
1263
+ }
1264
+ /**
1265
+ * Start a device authorization.
1266
+ *
1267
+ * `Accept: application/json` is set here as well as on the token leg. It is
1268
+ * load-bearing on the token leg (see {@link pollForCopilotToken}) and harmless
1269
+ * here, and setting it on both keeps the pair from drifting into "one of the two
1270
+ * legs parses JSON".
1271
+ * @param options - issuer, client id, scope, cancellation and read bounds.
1272
+ * @returns the code, the URL and the timings to show the user.
1273
+ * @throws CopilotDeviceLoginError with `reason: 'aborted'` when the caller's
1274
+ * signal aborts, or `reason: 'failed'` when the endpoint answers with anything
1275
+ * other than a usable device authorization.
1276
+ */
1277
+ declare function requestCopilotDeviceCode(options?: CopilotOAuthOptions): Promise<CopilotDeviceCode>;
1278
+ /**
1279
+ * Run a full device login and persist the resulting `GitHub_User_Token`.
1280
+ *
1281
+ * The store is read BEFORE the flow starts, so the commit carries the revision
1282
+ * that was current when the login began and a concurrent login loses the race
1283
+ * loudly instead of silently overwriting. Nothing else is written: the
1284
+ * `GitHub_User_Token` does not rotate, so this is the only write in the whole
1285
+ * Copilot credential path.
1286
+ * @param store - the credential store to write, in either variant.
1287
+ * @param options - issuer, client id, scope, cancellation, bounds and timer.
1288
+ * @param progress - prompt and poll notifications for a CLI to render.
1289
+ * @returns the store location plus whatever identity the endpoint disclosed.
1290
+ * @throws CopilotDeviceLoginError with `reason` distinguishing `denied`,
1291
+ * `expired`, `timeout`, `aborted` and `failed`.
1292
+ */
1293
+ declare function runCopilotDeviceLogin(store: CopilotCredentialStore, options?: CopilotOAuthOptions, progress?: CopilotLoginProgress): Promise<CopilotLoginResult>;
1294
+ declare function runCopilotDeviceLogin(store: CopilotAuthStore, options?: CopilotOAuthOptions, progress?: CopilotLoginProgress): Promise<CopilotLoginResult>;
1295
+ //#endregion
1296
+ export { COPILOT_BASE_URL, COPILOT_CATALOG_PATH, COPILOT_DEFAULT_CATALOG_TIMEOUT_MS, COPILOT_DEFAULT_DIALECT, COPILOT_DEFAULT_MAX_CATALOG_BYTES, COPILOT_DEFAULT_MAX_CATALOG_CHUNKS, COPILOT_DEFAULT_MAX_CATALOG_MODELS, COPILOT_DEFAULT_POLL_INTERVAL_SECONDS, COPILOT_DEVICE_CODE_MAX_WAIT_MS, COPILOT_DEVICE_LOGIN_WARNING, COPILOT_DISPLAY_NAME, COPILOT_DUAL_PROTOCOL_ID, COPILOT_EDITOR_PLUGIN_VERSION, COPILOT_EDITOR_VERSION, COPILOT_ERROR_CODES, COPILOT_LOGIN_COMMAND, COPILOT_OAUTH_CLIENT_ID, COPILOT_OAUTH_SCOPE, COPILOT_PROVIDER_ID, COPILOT_RESPONSES_MODEL_PREFIXES, COPILOT_ROUTE_ID, COPILOT_SLOW_DOWN_INCREMENT_SECONDS, COPILOT_TOKEN_EXCHANGE_MARGIN_MS, COPILOT_TOKEN_EXCHANGE_PATH, type ChatCompletionsProtocolLike, type CopilotAccountIdentity, type CopilotApiToken, type CopilotAuthFile, type CopilotAuthStore, type CopilotCatalogLimits, type CopilotCatalogOptions, type CopilotCatalogSnapshot, type CopilotCredentialFailure, type CopilotCredentialSnapshot, type CopilotCredentialStore, type CopilotDeviceCode, CopilotDeviceLoginError, type CopilotDeviceLoginReason, type CopilotDialect, type CopilotDualProtocolOptions, type CopilotEditorHeaders, type CopilotEmbeddingModel, type CopilotEndpoint, type CopilotEndpointDecision, type CopilotEndpointRouter, type CopilotEndpointRouterOptions, type CopilotErrorCode, type CopilotExchangeOptions, type CopilotGenerationModel, type CopilotGitHubToken, type CopilotLegacyProviderOptions, type CopilotLoginProgress, type CopilotLoginResult, type CopilotOAuthOptions, type CopilotOmitReason, type CopilotOmittedModel, type CopilotPluginOptions, type CopilotProviderOptions, type CopilotSubProtocol, type CopilotTimer, type CopilotTokenCache, type CopilotTokenCacheEntry, type CopilotTokenCacheOptions, CopilotTokenExchangeError, type CopilotTokenExchangeFailureKind, type CopilotTokenExpiry, DEFAULT_COPILOT_OAUTH_ISSUER, DEFAULT_COPILOT_TIMER, DEFAULT_GITHUB_API_BASE_URL, type ResponsesProtocolLike, copilotAdapter, copilotCatalogCacheOptions, copilotDualProtocol, copilotPlugin, createCopilotEndpointRouter, createCopilotTokenCache, credentialFailure, discoverCopilotModels, exchangeCopilotToken, memoryCopilotAuthStore, memoryCopilotCredentialStore, partitionCopilotCatalog, requestCopilotDeviceCode, requireGitHubToken, resolveCopilotCatalogLimits, runCopilotDeviceLogin, shouldExchange, toChatCompletionsDialect, toResponsesDialect };
1297
+ //# sourceMappingURL=index.d.ts.map