opencode-copilot-account-switcher 0.10.7 → 0.10.8

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.
@@ -3,7 +3,6 @@ const RETRYABLE_MESSAGES = [
3
3
  "load failed",
4
4
  "failed to fetch",
5
5
  "network request failed",
6
- "sse read timed out",
7
6
  "unable to connect",
8
7
  "econnreset",
9
8
  "etimedout",
@@ -490,8 +489,9 @@ function stripOpenAIItemId(part) {
490
489
  };
491
490
  }
492
491
  function getInternalPatchClient(client) {
493
- const patch = client?._client?.patch;
494
- return typeof patch === "function" ? patch : undefined;
492
+ const internalClient = client?._client;
493
+ const patch = internalClient?.patch;
494
+ return typeof patch === "function" ? patch.bind(internalClient) : undefined;
495
495
  }
496
496
  function collectSessionRepairMatches(messages, predicate) {
497
497
  return (messages?.data ?? []).flatMap((message) => {
@@ -1077,21 +1077,25 @@ function withStreamDebugLogs(response, request) {
1077
1077
  }
1078
1078
  catch (error) {
1079
1079
  const message = getErrorMessage(error);
1080
+ const isSseReadTimeout = message.includes("sse read timed out");
1080
1081
  const retryable = RETRYABLE_MESSAGES.some((part) => message.includes(part));
1081
1082
  if (isDebugEnabled()) {
1082
1083
  debugLog("sse stream read error", {
1083
1084
  url: rawUrl,
1084
1085
  message,
1085
1086
  retryableByMessage: retryable,
1087
+ bypassedTimeoutWrap: isSseReadTimeout,
1086
1088
  });
1087
1089
  }
1088
- controller.error(retryable
1089
- ? toRetryableApiCallError(error, request, {
1090
- group: "stream",
1091
- statusCode: response.status,
1092
- responseHeaders: response.headers,
1093
- })
1094
- : error);
1090
+ controller.error(isSseReadTimeout
1091
+ ? error
1092
+ : retryable
1093
+ ? toRetryableApiCallError(error, request, {
1094
+ group: "stream",
1095
+ statusCode: response.status,
1096
+ responseHeaders: response.headers,
1097
+ })
1098
+ : error);
1095
1099
  }
1096
1100
  };
1097
1101
  void pump();
@@ -55,7 +55,18 @@ export declare function buildPluginHooks(input: {
55
55
  loadOfficialConfig?: (input: {
56
56
  getAuth: () => Promise<CopilotAuthState | undefined>;
57
57
  provider?: CopilotProviderConfig;
58
+ baseFetch?: typeof fetch;
59
+ version?: string;
58
60
  }) => Promise<OfficialCopilotConfig | undefined>;
61
+ finalizeRequestForSelection?: (input: {
62
+ request: Request | URL | string;
63
+ init?: RequestInit;
64
+ getAuth: () => Promise<CopilotAuthState | undefined>;
65
+ provider?: CopilotProviderConfig;
66
+ }) => Promise<{
67
+ request: Request | URL | string;
68
+ init?: RequestInit;
69
+ } | undefined>;
59
70
  loadOfficialChatHeaders?: (input: {
60
71
  client?: object;
61
72
  directory?: string;
@@ -479,12 +479,42 @@ export function buildPluginHooks(input) {
479
479
  const loader = async (getAuth, provider) => {
480
480
  const authOverride = new AsyncLocalStorage();
481
481
  const getScopedAuth = async () => authOverride.getStore() ?? getAuth();
482
+ const providerConfig = provider;
482
483
  const config = await loadOfficialConfig({
483
484
  getAuth: getScopedAuth,
484
- provider: provider,
485
+ provider: providerConfig,
485
486
  });
486
487
  if (!config)
487
488
  return {};
489
+ const finalizeRequestForSelection = input.finalizeRequestForSelection
490
+ ?? (input.loadOfficialConfig
491
+ ? undefined
492
+ : async (selectionInput) => {
493
+ let captured;
494
+ const captureConfig = await loadOfficialConfig({
495
+ getAuth: getScopedAuth,
496
+ provider: providerConfig,
497
+ baseFetch: async (nextRequest, nextInit) => {
498
+ captured = {
499
+ request: nextRequest,
500
+ init: nextInit,
501
+ };
502
+ return new Response("{}", {
503
+ status: 200,
504
+ headers: {
505
+ "content-type": "application/json",
506
+ },
507
+ });
508
+ },
509
+ });
510
+ if (!captureConfig)
511
+ return undefined;
512
+ const inspectionRequest = selectionInput.request instanceof Request
513
+ ? selectionInput.request.clone()
514
+ : selectionInput.request;
515
+ await captureConfig.fetch(inspectionRequest, selectionInput.init).catch(() => undefined);
516
+ return captured;
517
+ });
488
518
  const store = await loadStore().catch(() => undefined);
489
519
  const retryStore = readRetryStoreContext(store);
490
520
  const fetchWithModelAccount = async (request, init) => {
@@ -500,7 +530,15 @@ export function buildPluginHooks(input) {
500
530
  maxEntries: touchWriteCacheMaxEntries,
501
531
  });
502
532
  const sessionID = getInternalSessionID(request, init);
503
- const initiator = getMergedRequestHeader(request, init, "x-initiator");
533
+ const finalized = await finalizeRequestForSelection?.({
534
+ request,
535
+ init,
536
+ getAuth: getScopedAuth,
537
+ provider: providerConfig,
538
+ }).catch(() => undefined);
539
+ const selectionRequest = finalized?.request ?? request;
540
+ const selectionInit = finalized?.init ?? init;
541
+ const initiator = getMergedRequestHeader(selectionRequest, selectionInit, "x-initiator");
504
542
  const allowReselect = initiator === "user";
505
543
  const candidates = latestStore ? resolveCopilotModelAccounts(latestStore, modelID) : [];
506
544
  const hasExplicitModelGroup = Boolean(latestStore
@@ -536,7 +574,7 @@ export function buildPluginHooks(input) {
536
574
  }
537
575
  const candidateNames = candidates.map((item) => item.name);
538
576
  const classification = sessionID.length > 0
539
- ? await classifyRequestReason({ sessionID, request, init })
577
+ ? await classifyRequestReason({ sessionID, request: selectionRequest, init: selectionInit })
540
578
  : {
541
579
  reason: toReasonByInitiator(initiator),
542
580
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-copilot-account-switcher",
3
- "version": "0.10.7",
3
+ "version": "0.10.8",
4
4
  "description": "GitHub Copilot account switcher plugin for OpenCode",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",