opencode-copilot-account-switcher 0.10.9 → 0.10.10

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.
@@ -238,12 +238,20 @@ function buildConsumptionToast(input) {
238
238
  variant: "warning",
239
239
  };
240
240
  }
241
+ if (input.reason === "unbound-fallback") {
242
+ return {
243
+ message: `已使用 ${input.accountName}(异常无绑定 agent 入口,已按用户回合处理)`,
244
+ variant: "warning",
245
+ };
246
+ }
241
247
  return {
242
248
  message: `已使用 ${input.accountName}(${toConsumptionReasonText(input.reason)})`,
243
249
  variant: "info",
244
250
  };
245
251
  }
246
252
  function shouldShowConsumptionToast(input) {
253
+ if (input.reason === "regular")
254
+ return false;
247
255
  if (input.reason === "subagent")
248
256
  return input.isFirstUse;
249
257
  if (input.reason === "compaction")
@@ -449,7 +457,13 @@ export function buildPluginHooks(input) {
449
457
  },
450
458
  throwOnError: true,
451
459
  }).catch(() => undefined);
460
+ const canDetermineSessionAncestry = session !== undefined;
452
461
  const isTrueChildSession = typeof session?.data?.parentID === "string" && session.data.parentID.length > 0;
462
+ if (canDetermineSessionAncestry && !isTrueChildSession && requestInput.hasExistingBinding === false) {
463
+ return {
464
+ reason: "unbound-fallback",
465
+ };
466
+ }
453
467
  return {
454
468
  reason: isTrueChildSession ? "subagent" : "regular",
455
469
  };
@@ -540,8 +554,24 @@ export function buildPluginHooks(input) {
540
554
  const selectionRequest = finalized?.request ?? request;
541
555
  const selectionInit = finalized?.init ?? init;
542
556
  const initiator = getMergedRequestHeader(selectionRequest, selectionInit, "x-initiator");
543
- const allowReselect = initiator === "user";
544
557
  const candidates = latestStore ? resolveCopilotModelAccounts(latestStore, modelID) : [];
558
+ if (candidates.length === 0) {
559
+ const outbound = stripInternalSessionHeader(request, init);
560
+ return config.fetch(outbound.request, outbound.init);
561
+ }
562
+ const hasExistingBinding = sessionID.length > 0 && sessionAccountBindings.has(sessionID);
563
+ const classification = sessionID.length > 0
564
+ ? await classifyRequestReason({
565
+ sessionID,
566
+ hasExistingBinding,
567
+ request: selectionRequest,
568
+ init: selectionInit,
569
+ })
570
+ : {
571
+ reason: toReasonByInitiator(initiator),
572
+ };
573
+ const selectionAllowReselect = classification.reason === "user-reselect"
574
+ || classification.reason === "unbound-fallback";
545
575
  const hasExplicitModelGroup = Boolean(latestStore
546
576
  && typeof modelID === "string"
547
577
  && modelID.length > 0
@@ -563,7 +593,7 @@ export function buildPluginHooks(input) {
563
593
  ? chooseCandidateAccount({
564
594
  candidates,
565
595
  sessionID,
566
- allowReselect,
596
+ allowReselect: selectionAllowReselect,
567
597
  sessionBindings: sessionAccountBindings,
568
598
  loads,
569
599
  random,
@@ -574,11 +604,6 @@ export function buildPluginHooks(input) {
574
604
  return config.fetch(outbound.request, outbound.init);
575
605
  }
576
606
  const candidateNames = candidates.map((item) => item.name);
577
- const classification = sessionID.length > 0
578
- ? await classifyRequestReason({ sessionID, request: selectionRequest, init: selectionInit })
579
- : {
580
- reason: toReasonByInitiator(initiator),
581
- };
582
607
  let decisionLoads = loadMapToRecord(loads, candidateNames);
583
608
  let decisionReason = classification.reason;
584
609
  let decisionSwitched = false;
@@ -616,15 +641,15 @@ export function buildPluginHooks(input) {
616
641
  }
617
642
  let nextRequest = request;
618
643
  let nextInit = init;
619
- if (isFirstUse) {
620
- const currentInitiator = getMergedRequestHeader(request, init, "x-initiator");
621
- if (currentInitiator === "agent") {
622
- const rewritten = mergeAndRewriteRequestHeaders(request, init, (headers) => {
623
- headers.delete("x-initiator");
624
- });
625
- nextRequest = rewritten.request;
626
- nextInit = rewritten.init;
627
- }
644
+ const currentInitiator = getMergedRequestHeader(request, init, "x-initiator");
645
+ const shouldStripAgentInitiator = classification.reason === "unbound-fallback"
646
+ || (isFirstUse && currentInitiator === "agent");
647
+ if (shouldStripAgentInitiator && currentInitiator === "agent") {
648
+ const rewritten = mergeAndRewriteRequestHeaders(request, init, (headers) => {
649
+ headers.delete("x-initiator");
650
+ });
651
+ nextRequest = rewritten.request;
652
+ nextInit = rewritten.init;
628
653
  }
629
654
  const auth = {
630
655
  type: "oauth",
@@ -69,7 +69,7 @@ export type RouteDecisionEvent = {
69
69
  groupSource: "model" | "active";
70
70
  candidateNames: string[];
71
71
  loads: Record<string, number>;
72
- reason: "regular" | "subagent" | "compaction" | "user-reselect" | "rate-limit-switch";
72
+ reason: "regular" | "subagent" | "compaction" | "user-reselect" | "unbound-fallback" | "rate-limit-switch";
73
73
  switched: boolean;
74
74
  switchFrom?: string;
75
75
  switchBlockedBy?: "no-cooled-down-candidate" | "replacement-load-higher" | "routing-state-read-failed" | "no-replacement-candidate";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-copilot-account-switcher",
3
- "version": "0.10.9",
3
+ "version": "0.10.10",
4
4
  "description": "GitHub Copilot account switcher plugin for OpenCode",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",