opencode-copilot-account-switcher 0.10.8 → 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")
@@ -418,11 +426,12 @@ export function buildPluginHooks(input) {
418
426
  reason: toReasonByInitiator(initiator),
419
427
  };
420
428
  }
421
- const sessionLookup = input.client?.session?.get;
422
- const messageLookup = input.client?.session?.message;
429
+ const sessionClient = input.client?.session;
430
+ const sessionLookup = sessionClient?.get;
431
+ const messageLookup = sessionClient?.message;
423
432
  const messageIDHeader = getMergedRequestHeader(requestInput.request, requestInput.init, INTERNAL_DEBUG_LINK_HEADER);
424
433
  if (typeof messageIDHeader === "string" && messageIDHeader.length > 0) {
425
- const currentMessage = await messageLookup?.({
434
+ const currentMessage = await messageLookup?.call(sessionClient, {
426
435
  path: {
427
436
  id: requestInput.sessionID,
428
437
  messageID: messageIDHeader,
@@ -439,7 +448,7 @@ export function buildPluginHooks(input) {
439
448
  };
440
449
  }
441
450
  }
442
- const session = await sessionLookup?.({
451
+ const session = await sessionLookup?.call(sessionClient, {
443
452
  path: {
444
453
  id: requestInput.sessionID,
445
454
  },
@@ -448,7 +457,13 @@ export function buildPluginHooks(input) {
448
457
  },
449
458
  throwOnError: true,
450
459
  }).catch(() => undefined);
460
+ const canDetermineSessionAncestry = session !== undefined;
451
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
+ }
452
467
  return {
453
468
  reason: isTrueChildSession ? "subagent" : "regular",
454
469
  };
@@ -539,8 +554,24 @@ export function buildPluginHooks(input) {
539
554
  const selectionRequest = finalized?.request ?? request;
540
555
  const selectionInit = finalized?.init ?? init;
541
556
  const initiator = getMergedRequestHeader(selectionRequest, selectionInit, "x-initiator");
542
- const allowReselect = initiator === "user";
543
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";
544
575
  const hasExplicitModelGroup = Boolean(latestStore
545
576
  && typeof modelID === "string"
546
577
  && modelID.length > 0
@@ -562,7 +593,7 @@ export function buildPluginHooks(input) {
562
593
  ? chooseCandidateAccount({
563
594
  candidates,
564
595
  sessionID,
565
- allowReselect,
596
+ allowReselect: selectionAllowReselect,
566
597
  sessionBindings: sessionAccountBindings,
567
598
  loads,
568
599
  random,
@@ -573,11 +604,6 @@ export function buildPluginHooks(input) {
573
604
  return config.fetch(outbound.request, outbound.init);
574
605
  }
575
606
  const candidateNames = candidates.map((item) => item.name);
576
- const classification = sessionID.length > 0
577
- ? await classifyRequestReason({ sessionID, request: selectionRequest, init: selectionInit })
578
- : {
579
- reason: toReasonByInitiator(initiator),
580
- };
581
607
  let decisionLoads = loadMapToRecord(loads, candidateNames);
582
608
  let decisionReason = classification.reason;
583
609
  let decisionSwitched = false;
@@ -615,15 +641,15 @@ export function buildPluginHooks(input) {
615
641
  }
616
642
  let nextRequest = request;
617
643
  let nextInit = init;
618
- if (isFirstUse) {
619
- const currentInitiator = getMergedRequestHeader(request, init, "x-initiator");
620
- if (currentInitiator === "agent") {
621
- const rewritten = mergeAndRewriteRequestHeaders(request, init, (headers) => {
622
- headers.delete("x-initiator");
623
- });
624
- nextRequest = rewritten.request;
625
- nextInit = rewritten.init;
626
- }
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;
627
653
  }
628
654
  const auth = {
629
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.8",
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",