@dylanrussell/agent-router 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/plugin.js CHANGED
@@ -729,9 +729,9 @@ function floatSafeRemainder(val, step) {
729
729
  return ratio - roundedRatio;
730
730
  }
731
731
  var EVALUATING = /* @__PURE__ */ Symbol("evaluating");
732
- function defineLazy(object2, key, getter) {
732
+ function defineLazy(object2, key2, getter) {
733
733
  let value = void 0;
734
- Object.defineProperty(object2, key, {
734
+ Object.defineProperty(object2, key2, {
735
735
  get() {
736
736
  if (value === EVALUATING) {
737
737
  return void 0;
@@ -743,7 +743,7 @@ function defineLazy(object2, key, getter) {
743
743
  return value;
744
744
  },
745
745
  set(v) {
746
- Object.defineProperty(object2, key, {
746
+ Object.defineProperty(object2, key2, {
747
747
  value: v
748
748
  // configurable: true,
749
749
  });
@@ -776,11 +776,11 @@ function cloneDef(schema) {
776
776
  function getElementAtPath(obj, path8) {
777
777
  if (!path8)
778
778
  return obj;
779
- return path8.reduce((acc, key) => acc?.[key], obj);
779
+ return path8.reduce((acc, key2) => acc?.[key2], obj);
780
780
  }
781
781
  function promiseAllObject(promisesObj) {
782
782
  const keys = Object.keys(promisesObj);
783
- const promises = keys.map((key) => promisesObj[key]);
783
+ const promises = keys.map((key2) => promisesObj[key2]);
784
784
  return Promise.all(promises).then((results) => {
785
785
  const resolvedObj = {};
786
786
  for (let i = 0; i < keys.length; i++) {
@@ -852,8 +852,8 @@ function shallowClone(o) {
852
852
  }
853
853
  function numKeys(data) {
854
854
  let keyCount = 0;
855
- for (const key in data) {
856
- if (Object.prototype.hasOwnProperty.call(data, key)) {
855
+ for (const key2 in data) {
856
+ if (Object.prototype.hasOwnProperty.call(data, key2)) {
857
857
  keyCount++;
858
858
  }
859
859
  }
@@ -1003,13 +1003,13 @@ function pick(schema, mask) {
1003
1003
  const def = mergeDefs(schema._zod.def, {
1004
1004
  get shape() {
1005
1005
  const newShape = {};
1006
- for (const key in mask) {
1007
- if (!(key in currDef.shape)) {
1008
- throw new Error(`Unrecognized key: "${key}"`);
1006
+ for (const key2 in mask) {
1007
+ if (!(key2 in currDef.shape)) {
1008
+ throw new Error(`Unrecognized key: "${key2}"`);
1009
1009
  }
1010
- if (!mask[key])
1010
+ if (!mask[key2])
1011
1011
  continue;
1012
- newShape[key] = currDef.shape[key];
1012
+ newShape[key2] = currDef.shape[key2];
1013
1013
  }
1014
1014
  assignProp(this, "shape", newShape);
1015
1015
  return newShape;
@@ -1028,13 +1028,13 @@ function omit(schema, mask) {
1028
1028
  const def = mergeDefs(schema._zod.def, {
1029
1029
  get shape() {
1030
1030
  const newShape = { ...schema._zod.def.shape };
1031
- for (const key in mask) {
1032
- if (!(key in currDef.shape)) {
1033
- throw new Error(`Unrecognized key: "${key}"`);
1031
+ for (const key2 in mask) {
1032
+ if (!(key2 in currDef.shape)) {
1033
+ throw new Error(`Unrecognized key: "${key2}"`);
1034
1034
  }
1035
- if (!mask[key])
1035
+ if (!mask[key2])
1036
1036
  continue;
1037
- delete newShape[key];
1037
+ delete newShape[key2];
1038
1038
  }
1039
1039
  assignProp(this, "shape", newShape);
1040
1040
  return newShape;
@@ -1051,8 +1051,8 @@ function extend(schema, shape) {
1051
1051
  const hasChecks = checks && checks.length > 0;
1052
1052
  if (hasChecks) {
1053
1053
  const existingShape = schema._zod.def.shape;
1054
- for (const key in shape) {
1055
- if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) {
1054
+ for (const key2 in shape) {
1055
+ if (Object.getOwnPropertyDescriptor(existingShape, key2) !== void 0) {
1056
1056
  throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.");
1057
1057
  }
1058
1058
  }
@@ -1108,23 +1108,23 @@ function partial(Class2, schema, mask) {
1108
1108
  const oldShape = schema._zod.def.shape;
1109
1109
  const shape = { ...oldShape };
1110
1110
  if (mask) {
1111
- for (const key in mask) {
1112
- if (!(key in oldShape)) {
1113
- throw new Error(`Unrecognized key: "${key}"`);
1111
+ for (const key2 in mask) {
1112
+ if (!(key2 in oldShape)) {
1113
+ throw new Error(`Unrecognized key: "${key2}"`);
1114
1114
  }
1115
- if (!mask[key])
1115
+ if (!mask[key2])
1116
1116
  continue;
1117
- shape[key] = Class2 ? new Class2({
1117
+ shape[key2] = Class2 ? new Class2({
1118
1118
  type: "optional",
1119
- innerType: oldShape[key]
1120
- }) : oldShape[key];
1119
+ innerType: oldShape[key2]
1120
+ }) : oldShape[key2];
1121
1121
  }
1122
1122
  } else {
1123
- for (const key in oldShape) {
1124
- shape[key] = Class2 ? new Class2({
1123
+ for (const key2 in oldShape) {
1124
+ shape[key2] = Class2 ? new Class2({
1125
1125
  type: "optional",
1126
- innerType: oldShape[key]
1127
- }) : oldShape[key];
1126
+ innerType: oldShape[key2]
1127
+ }) : oldShape[key2];
1128
1128
  }
1129
1129
  }
1130
1130
  assignProp(this, "shape", shape);
@@ -1140,22 +1140,22 @@ function required(Class2, schema, mask) {
1140
1140
  const oldShape = schema._zod.def.shape;
1141
1141
  const shape = { ...oldShape };
1142
1142
  if (mask) {
1143
- for (const key in mask) {
1144
- if (!(key in shape)) {
1145
- throw new Error(`Unrecognized key: "${key}"`);
1143
+ for (const key2 in mask) {
1144
+ if (!(key2 in shape)) {
1145
+ throw new Error(`Unrecognized key: "${key2}"`);
1146
1146
  }
1147
- if (!mask[key])
1147
+ if (!mask[key2])
1148
1148
  continue;
1149
- shape[key] = new Class2({
1149
+ shape[key2] = new Class2({
1150
1150
  type: "nonoptional",
1151
- innerType: oldShape[key]
1151
+ innerType: oldShape[key2]
1152
1152
  });
1153
1153
  }
1154
1154
  } else {
1155
- for (const key in oldShape) {
1156
- shape[key] = new Class2({
1155
+ for (const key2 in oldShape) {
1156
+ shape[key2] = new Class2({
1157
1157
  type: "nonoptional",
1158
- innerType: oldShape[key]
1158
+ innerType: oldShape[key2]
1159
1159
  });
1160
1160
  }
1161
1161
  }
@@ -2936,13 +2936,13 @@ var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
2936
2936
  return payload;
2937
2937
  };
2938
2938
  });
2939
- function handlePropertyResult(result, final, key, input, isOptionalIn, isOptionalOut) {
2940
- const isPresent = key in input;
2939
+ function handlePropertyResult(result, final, key2, input, isOptionalIn, isOptionalOut) {
2940
+ const isPresent = key2 in input;
2941
2941
  if (result.issues.length) {
2942
2942
  if (isOptionalIn && isOptionalOut && !isPresent) {
2943
2943
  return;
2944
2944
  }
2945
- final.issues.push(...prefixIssues(key, result.issues));
2945
+ final.issues.push(...prefixIssues(key2, result.issues));
2946
2946
  }
2947
2947
  if (!isPresent && !isOptionalIn) {
2948
2948
  if (!result.issues.length) {
@@ -2950,17 +2950,17 @@ function handlePropertyResult(result, final, key, input, isOptionalIn, isOptiona
2950
2950
  code: "invalid_type",
2951
2951
  expected: "nonoptional",
2952
2952
  input: void 0,
2953
- path: [key]
2953
+ path: [key2]
2954
2954
  });
2955
2955
  }
2956
2956
  return;
2957
2957
  }
2958
2958
  if (result.value === void 0) {
2959
2959
  if (isPresent) {
2960
- final.value[key] = void 0;
2960
+ final.value[key2] = void 0;
2961
2961
  }
2962
2962
  } else {
2963
- final.value[key] = result.value;
2963
+ final.value[key2] = result.value;
2964
2964
  }
2965
2965
  }
2966
2966
  function normalizeDef(def) {
@@ -2986,20 +2986,20 @@ function handleCatchall(proms, input, payload, ctx, def, inst) {
2986
2986
  const t = _catchall.def.type;
2987
2987
  const isOptionalIn = _catchall.optin === "optional";
2988
2988
  const isOptionalOut = _catchall.optout === "optional";
2989
- for (const key in input) {
2990
- if (key === "__proto__")
2989
+ for (const key2 in input) {
2990
+ if (key2 === "__proto__")
2991
2991
  continue;
2992
- if (keySet.has(key))
2992
+ if (keySet.has(key2))
2993
2993
  continue;
2994
2994
  if (t === "never") {
2995
- unrecognized.push(key);
2995
+ unrecognized.push(key2);
2996
2996
  continue;
2997
2997
  }
2998
- const r = _catchall.run({ value: input[key], issues: [] }, ctx);
2998
+ const r = _catchall.run({ value: input[key2], issues: [] }, ctx);
2999
2999
  if (r instanceof Promise) {
3000
- proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input, isOptionalIn, isOptionalOut)));
3000
+ proms.push(r.then((r2) => handlePropertyResult(r2, payload, key2, input, isOptionalIn, isOptionalOut)));
3001
3001
  } else {
3002
- handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut);
3002
+ handlePropertyResult(r, payload, key2, input, isOptionalIn, isOptionalOut);
3003
3003
  }
3004
3004
  }
3005
3005
  if (unrecognized.length) {
@@ -3035,12 +3035,12 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
3035
3035
  defineLazy(inst._zod, "propValues", () => {
3036
3036
  const shape = def.shape;
3037
3037
  const propValues = {};
3038
- for (const key in shape) {
3039
- const field = shape[key]._zod;
3038
+ for (const key2 in shape) {
3039
+ const field = shape[key2]._zod;
3040
3040
  if (field.values) {
3041
- propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set());
3041
+ propValues[key2] ?? (propValues[key2] = /* @__PURE__ */ new Set());
3042
3042
  for (const v of field.values)
3043
- propValues[key].add(v);
3043
+ propValues[key2].add(v);
3044
3044
  }
3045
3045
  }
3046
3046
  return propValues;
@@ -3063,15 +3063,15 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
3063
3063
  payload.value = {};
3064
3064
  const proms = [];
3065
3065
  const shape = value.shape;
3066
- for (const key of value.keys) {
3067
- const el = shape[key];
3066
+ for (const key2 of value.keys) {
3067
+ const el = shape[key2];
3068
3068
  const isOptionalIn = el._zod.optin === "optional";
3069
3069
  const isOptionalOut = el._zod.optout === "optional";
3070
- const r = el._zod.run({ value: input[key], issues: [] }, ctx);
3070
+ const r = el._zod.run({ value: input[key2], issues: [] }, ctx);
3071
3071
  if (r instanceof Promise) {
3072
- proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input, isOptionalIn, isOptionalOut)));
3072
+ proms.push(r.then((r2) => handlePropertyResult(r2, payload, key2, input, isOptionalIn, isOptionalOut)));
3073
3073
  } else {
3074
- handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut);
3074
+ handlePropertyResult(r, payload, key2, input, isOptionalIn, isOptionalOut);
3075
3075
  }
3076
3076
  }
3077
3077
  if (!catchall) {
@@ -3087,24 +3087,24 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
3087
3087
  const generateFastpass = (shape) => {
3088
3088
  const doc = new Doc(["shape", "payload", "ctx"]);
3089
3089
  const normalized = _normalized.value;
3090
- const parseStr = (key) => {
3091
- const k = esc(key);
3090
+ const parseStr = (key2) => {
3091
+ const k = esc(key2);
3092
3092
  return `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`;
3093
3093
  };
3094
3094
  doc.write(`const input = payload.value;`);
3095
3095
  const ids = /* @__PURE__ */ Object.create(null);
3096
3096
  let counter = 0;
3097
- for (const key of normalized.keys) {
3098
- ids[key] = `key_${counter++}`;
3097
+ for (const key2 of normalized.keys) {
3098
+ ids[key2] = `key_${counter++}`;
3099
3099
  }
3100
3100
  doc.write(`const newResult = {};`);
3101
- for (const key of normalized.keys) {
3102
- const id = ids[key];
3103
- const k = esc(key);
3104
- const schema = shape[key];
3101
+ for (const key2 of normalized.keys) {
3102
+ const id = ids[key2];
3103
+ const k = esc(key2);
3104
+ const schema = shape[key2];
3105
3105
  const isOptionalIn = schema?._zod?.optin === "optional";
3106
3106
  const isOptionalOut = schema?._zod?.optout === "optional";
3107
- doc.write(`const ${id} = ${parseStr(key)};`);
3107
+ doc.write(`const ${id} = ${parseStr(key2)};`);
3108
3108
  if (isOptionalIn && isOptionalOut) {
3109
3109
  doc.write(`
3110
3110
  if (${id}.issues.length) {
@@ -3416,17 +3416,17 @@ function mergeValues(a, b) {
3416
3416
  }
3417
3417
  if (isPlainObject(a) && isPlainObject(b)) {
3418
3418
  const bKeys = Object.keys(b);
3419
- const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
3419
+ const sharedKeys = Object.keys(a).filter((key2) => bKeys.indexOf(key2) !== -1);
3420
3420
  const newObj = { ...a, ...b };
3421
- for (const key of sharedKeys) {
3422
- const sharedValue = mergeValues(a[key], b[key]);
3421
+ for (const key2 of sharedKeys) {
3422
+ const sharedValue = mergeValues(a[key2], b[key2]);
3423
3423
  if (!sharedValue.valid) {
3424
3424
  return {
3425
3425
  valid: false,
3426
- mergeErrorPath: [key, ...sharedValue.mergeErrorPath]
3426
+ mergeErrorPath: [key2, ...sharedValue.mergeErrorPath]
3427
3427
  };
3428
3428
  }
3429
- newObj[key] = sharedValue.data;
3429
+ newObj[key2] = sharedValue.data;
3430
3430
  }
3431
3431
  return { valid: true, data: newObj };
3432
3432
  }
@@ -3561,9 +3561,9 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
3561
3561
  return handleTupleResults(itemResults, payload, items, input, optoutStart);
3562
3562
  };
3563
3563
  });
3564
- function getTupleOptStart(items, key) {
3564
+ function getTupleOptStart(items, key2) {
3565
3565
  for (let i = items.length - 1; i >= 0; i--) {
3566
- if (items[i]._zod[key] !== "optional")
3566
+ if (items[i]._zod[key2] !== "optional")
3567
3567
  return i + 1;
3568
3568
  }
3569
3569
  return 0;
@@ -3614,10 +3614,10 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
3614
3614
  if (values) {
3615
3615
  payload.value = {};
3616
3616
  const recordKeys = /* @__PURE__ */ new Set();
3617
- for (const key of values) {
3618
- if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
3619
- recordKeys.add(typeof key === "number" ? key.toString() : key);
3620
- const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
3617
+ for (const key2 of values) {
3618
+ if (typeof key2 === "string" || typeof key2 === "number" || typeof key2 === "symbol") {
3619
+ recordKeys.add(typeof key2 === "number" ? key2.toString() : key2);
3620
+ const keyResult = def.keyType._zod.run({ value: key2, issues: [] }, ctx);
3621
3621
  if (keyResult instanceof Promise) {
3622
3622
  throw new Error("Async schemas not supported in object keys currently");
3623
3623
  }
@@ -3626,34 +3626,34 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
3626
3626
  code: "invalid_key",
3627
3627
  origin: "record",
3628
3628
  issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
3629
- input: key,
3630
- path: [key],
3629
+ input: key2,
3630
+ path: [key2],
3631
3631
  inst
3632
3632
  });
3633
3633
  continue;
3634
3634
  }
3635
3635
  const outKey = keyResult.value;
3636
- const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
3636
+ const result = def.valueType._zod.run({ value: input[key2], issues: [] }, ctx);
3637
3637
  if (result instanceof Promise) {
3638
3638
  proms.push(result.then((result2) => {
3639
3639
  if (result2.issues.length) {
3640
- payload.issues.push(...prefixIssues(key, result2.issues));
3640
+ payload.issues.push(...prefixIssues(key2, result2.issues));
3641
3641
  }
3642
3642
  payload.value[outKey] = result2.value;
3643
3643
  }));
3644
3644
  } else {
3645
3645
  if (result.issues.length) {
3646
- payload.issues.push(...prefixIssues(key, result.issues));
3646
+ payload.issues.push(...prefixIssues(key2, result.issues));
3647
3647
  }
3648
3648
  payload.value[outKey] = result.value;
3649
3649
  }
3650
3650
  }
3651
3651
  }
3652
3652
  let unrecognized;
3653
- for (const key in input) {
3654
- if (!recordKeys.has(key)) {
3653
+ for (const key2 in input) {
3654
+ if (!recordKeys.has(key2)) {
3655
3655
  unrecognized = unrecognized ?? [];
3656
- unrecognized.push(key);
3656
+ unrecognized.push(key2);
3657
3657
  }
3658
3658
  }
3659
3659
  if (unrecognized && unrecognized.length > 0) {
@@ -3666,18 +3666,18 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
3666
3666
  }
3667
3667
  } else {
3668
3668
  payload.value = {};
3669
- for (const key of Reflect.ownKeys(input)) {
3670
- if (key === "__proto__")
3669
+ for (const key2 of Reflect.ownKeys(input)) {
3670
+ if (key2 === "__proto__")
3671
3671
  continue;
3672
- if (!Object.prototype.propertyIsEnumerable.call(input, key))
3672
+ if (!Object.prototype.propertyIsEnumerable.call(input, key2))
3673
3673
  continue;
3674
- let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
3674
+ let keyResult = def.keyType._zod.run({ value: key2, issues: [] }, ctx);
3675
3675
  if (keyResult instanceof Promise) {
3676
3676
  throw new Error("Async schemas not supported in object keys currently");
3677
3677
  }
3678
- const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length;
3678
+ const checkNumericKey = typeof key2 === "string" && number.test(key2) && keyResult.issues.length;
3679
3679
  if (checkNumericKey) {
3680
- const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
3680
+ const retryResult = def.keyType._zod.run({ value: Number(key2), issues: [] }, ctx);
3681
3681
  if (retryResult instanceof Promise) {
3682
3682
  throw new Error("Async schemas not supported in object keys currently");
3683
3683
  }
@@ -3687,30 +3687,30 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
3687
3687
  }
3688
3688
  if (keyResult.issues.length) {
3689
3689
  if (def.mode === "loose") {
3690
- payload.value[key] = input[key];
3690
+ payload.value[key2] = input[key2];
3691
3691
  } else {
3692
3692
  payload.issues.push({
3693
3693
  code: "invalid_key",
3694
3694
  origin: "record",
3695
3695
  issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
3696
- input: key,
3697
- path: [key],
3696
+ input: key2,
3697
+ path: [key2],
3698
3698
  inst
3699
3699
  });
3700
3700
  }
3701
3701
  continue;
3702
3702
  }
3703
- const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
3703
+ const result = def.valueType._zod.run({ value: input[key2], issues: [] }, ctx);
3704
3704
  if (result instanceof Promise) {
3705
3705
  proms.push(result.then((result2) => {
3706
3706
  if (result2.issues.length) {
3707
- payload.issues.push(...prefixIssues(key, result2.issues));
3707
+ payload.issues.push(...prefixIssues(key2, result2.issues));
3708
3708
  }
3709
3709
  payload.value[keyResult.value] = result2.value;
3710
3710
  }));
3711
3711
  } else {
3712
3712
  if (result.issues.length) {
3713
- payload.issues.push(...prefixIssues(key, result.issues));
3713
+ payload.issues.push(...prefixIssues(key2, result.issues));
3714
3714
  }
3715
3715
  payload.value[keyResult.value] = result.value;
3716
3716
  }
@@ -3737,15 +3737,15 @@ var $ZodMap = /* @__PURE__ */ $constructor("$ZodMap", (inst, def) => {
3737
3737
  }
3738
3738
  const proms = [];
3739
3739
  payload.value = /* @__PURE__ */ new Map();
3740
- for (const [key, value] of input) {
3741
- const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
3740
+ for (const [key2, value] of input) {
3741
+ const keyResult = def.keyType._zod.run({ value: key2, issues: [] }, ctx);
3742
3742
  const valueResult = def.valueType._zod.run({ value, issues: [] }, ctx);
3743
3743
  if (keyResult instanceof Promise || valueResult instanceof Promise) {
3744
3744
  proms.push(Promise.all([keyResult, valueResult]).then(([keyResult2, valueResult2]) => {
3745
- handleMapResult(keyResult2, valueResult2, payload, key, input, inst, ctx);
3745
+ handleMapResult(keyResult2, valueResult2, payload, key2, input, inst, ctx);
3746
3746
  }));
3747
3747
  } else {
3748
- handleMapResult(keyResult, valueResult, payload, key, input, inst, ctx);
3748
+ handleMapResult(keyResult, valueResult, payload, key2, input, inst, ctx);
3749
3749
  }
3750
3750
  }
3751
3751
  if (proms.length)
@@ -3753,10 +3753,10 @@ var $ZodMap = /* @__PURE__ */ $constructor("$ZodMap", (inst, def) => {
3753
3753
  return payload;
3754
3754
  };
3755
3755
  });
3756
- function handleMapResult(keyResult, valueResult, final, key, input, inst, ctx) {
3756
+ function handleMapResult(keyResult, valueResult, final, key2, input, inst, ctx) {
3757
3757
  if (keyResult.issues.length) {
3758
- if (propertyKeyTypes.has(typeof key)) {
3759
- final.issues.push(...prefixIssues(key, keyResult.issues));
3758
+ if (propertyKeyTypes.has(typeof key2)) {
3759
+ final.issues.push(...prefixIssues(key2, keyResult.issues));
3760
3760
  } else {
3761
3761
  final.issues.push({
3762
3762
  code: "invalid_key",
@@ -3768,15 +3768,15 @@ function handleMapResult(keyResult, valueResult, final, key, input, inst, ctx) {
3768
3768
  }
3769
3769
  }
3770
3770
  if (valueResult.issues.length) {
3771
- if (propertyKeyTypes.has(typeof key)) {
3772
- final.issues.push(...prefixIssues(key, valueResult.issues));
3771
+ if (propertyKeyTypes.has(typeof key2)) {
3772
+ final.issues.push(...prefixIssues(key2, valueResult.issues));
3773
3773
  } else {
3774
3774
  final.issues.push({
3775
3775
  origin: "map",
3776
3776
  code: "invalid_element",
3777
3777
  input,
3778
3778
  inst,
3779
- key,
3779
+ key: key2,
3780
3780
  issues: valueResult.issues.map((iss) => finalizeIssue(iss, ctx, config()))
3781
3781
  });
3782
3782
  }
@@ -11537,8 +11537,8 @@ function extractDefs(ctx, schema) {
11537
11537
  if (defId)
11538
11538
  seen.defId = defId;
11539
11539
  const schema2 = seen.schema;
11540
- for (const key in schema2) {
11541
- delete schema2[key];
11540
+ for (const key2 in schema2) {
11541
+ delete schema2[key2];
11542
11542
  }
11543
11543
  schema2.$ref = ref;
11544
11544
  };
@@ -11607,20 +11607,20 @@ function finalize(ctx, schema) {
11607
11607
  Object.assign(schema2, _cached);
11608
11608
  const isParentRef = zodSchema._zod.parent === ref;
11609
11609
  if (isParentRef) {
11610
- for (const key in schema2) {
11611
- if (key === "$ref" || key === "allOf")
11610
+ for (const key2 in schema2) {
11611
+ if (key2 === "$ref" || key2 === "allOf")
11612
11612
  continue;
11613
- if (!(key in _cached)) {
11614
- delete schema2[key];
11613
+ if (!(key2 in _cached)) {
11614
+ delete schema2[key2];
11615
11615
  }
11616
11616
  }
11617
11617
  }
11618
11618
  if (refSchema.$ref && refSeen.def) {
11619
- for (const key in schema2) {
11620
- if (key === "$ref" || key === "allOf")
11619
+ for (const key2 in schema2) {
11620
+ if (key2 === "$ref" || key2 === "allOf")
11621
11621
  continue;
11622
- if (key in refSeen.def && JSON.stringify(schema2[key]) === JSON.stringify(refSeen.def[key])) {
11623
- delete schema2[key];
11622
+ if (key2 in refSeen.def && JSON.stringify(schema2[key2]) === JSON.stringify(refSeen.def[key2])) {
11623
+ delete schema2[key2];
11624
11624
  }
11625
11625
  }
11626
11626
  }
@@ -11632,11 +11632,11 @@ function finalize(ctx, schema) {
11632
11632
  if (parentSeen?.schema.$ref) {
11633
11633
  schema2.$ref = parentSeen.schema.$ref;
11634
11634
  if (parentSeen.def) {
11635
- for (const key in schema2) {
11636
- if (key === "$ref" || key === "allOf")
11635
+ for (const key2 in schema2) {
11636
+ if (key2 === "$ref" || key2 === "allOf")
11637
11637
  continue;
11638
- if (key in parentSeen.def && JSON.stringify(schema2[key]) === JSON.stringify(parentSeen.def[key])) {
11639
- delete schema2[key];
11638
+ if (key2 in parentSeen.def && JSON.stringify(schema2[key2]) === JSON.stringify(parentSeen.def[key2])) {
11639
+ delete schema2[key2];
11640
11640
  }
11641
11641
  }
11642
11642
  }
@@ -11737,8 +11737,8 @@ function isTransforming(_schema, _ctx) {
11737
11737
  return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
11738
11738
  }
11739
11739
  if (def.type === "object") {
11740
- for (const key in def.shape) {
11741
- if (isTransforming(def.shape[key], ctx))
11740
+ for (const key2 in def.shape) {
11741
+ if (isTransforming(def.shape[key2], ctx))
11742
11742
  return true;
11743
11743
  }
11744
11744
  return false;
@@ -12027,15 +12027,15 @@ var objectProcessor = (schema, ctx, _json, params) => {
12027
12027
  json2.type = "object";
12028
12028
  json2.properties = {};
12029
12029
  const shape = def.shape;
12030
- for (const key in shape) {
12031
- json2.properties[key] = process2(shape[key], ctx, {
12030
+ for (const key2 in shape) {
12031
+ json2.properties[key2] = process2(shape[key2], ctx, {
12032
12032
  ...params,
12033
- path: [...params.path, "properties", key]
12033
+ path: [...params.path, "properties", key2]
12034
12034
  });
12035
12035
  }
12036
12036
  const allKeys = new Set(Object.keys(shape));
12037
- const requiredKeys = new Set([...allKeys].filter((key) => {
12038
- const v = def.shape[key]._zod;
12037
+ const requiredKeys = new Set([...allKeys].filter((key2) => {
12038
+ const v = def.shape[key2]._zod;
12039
12039
  if (ctx.io === "input") {
12040
12040
  return v.optin === void 0;
12041
12041
  } else {
@@ -12301,9 +12301,9 @@ function toJSONSchema(input, params) {
12301
12301
  };
12302
12302
  ctx2.external = external;
12303
12303
  for (const entry of registry2._idmap.entries()) {
12304
- const [key, schema] = entry;
12304
+ const [key2, schema] = entry;
12305
12305
  extractDefs(ctx2, schema);
12306
- schemas[key] = finalize(ctx2, schema);
12306
+ schemas[key2] = finalize(ctx2, schema);
12307
12307
  }
12308
12308
  if (Object.keys(defs).length > 0) {
12309
12309
  const defsSegment = ctx2.target === "draft-2020-12" ? "$defs" : "definitions";
@@ -12709,14 +12709,14 @@ function _installLazyMethods(inst, group, methods) {
12709
12709
  if (installed.has(group))
12710
12710
  return;
12711
12711
  installed.add(group);
12712
- for (const key in methods) {
12713
- const fn = methods[key];
12714
- Object.defineProperty(proto, key, {
12712
+ for (const key2 in methods) {
12713
+ const fn = methods[key2];
12714
+ Object.defineProperty(proto, key2, {
12715
12715
  configurable: true,
12716
12716
  enumerable: false,
12717
12717
  get() {
12718
12718
  const bound = fn.bind(this);
12719
- Object.defineProperty(this, key, {
12719
+ Object.defineProperty(this, key2, {
12720
12720
  configurable: true,
12721
12721
  writable: true,
12722
12722
  enumerable: true,
@@ -12725,7 +12725,7 @@ function _installLazyMethods(inst, group, methods) {
12725
12725
  return bound;
12726
12726
  },
12727
12727
  set(v) {
12728
- Object.defineProperty(this, key, {
12728
+ Object.defineProperty(this, key2, {
12729
12729
  configurable: true,
12730
12730
  writable: true,
12731
12731
  enumerable: true,
@@ -14113,11 +14113,11 @@ function resolveRef(ref, ctx) {
14113
14113
  }
14114
14114
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14115
14115
  if (path8[0] === defsKey) {
14116
- const key = path8[1];
14117
- if (!key || !ctx.defs[key]) {
14116
+ const key2 = path8[1];
14117
+ if (!key2 || !ctx.defs[key2]) {
14118
14118
  throw new Error(`Reference not found: ${ref}`);
14119
14119
  }
14120
- return ctx.defs[key];
14120
+ return ctx.defs[key2];
14121
14121
  }
14122
14122
  throw new Error(`Reference not found: ${ref}`);
14123
14123
  }
@@ -14303,9 +14303,9 @@ function convertBaseSchema(schema, ctx) {
14303
14303
  const shape = {};
14304
14304
  const properties = schema.properties || {};
14305
14305
  const requiredSet = new Set(schema.required || []);
14306
- for (const [key, propSchema] of Object.entries(properties)) {
14306
+ for (const [key2, propSchema] of Object.entries(properties)) {
14307
14307
  const propZodSchema = convertSchema(propSchema, ctx);
14308
- shape[key] = requiredSet.has(key) ? propZodSchema : propZodSchema.optional();
14308
+ shape[key2] = requiredSet.has(key2) ? propZodSchema : propZodSchema.optional();
14309
14309
  }
14310
14310
  if (schema.propertyNames) {
14311
14311
  const keySchema = convertSchema(schema.propertyNames, ctx);
@@ -14446,20 +14446,20 @@ function convertSchema(schema, ctx) {
14446
14446
  }
14447
14447
  const extraMeta = {};
14448
14448
  const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
14449
- for (const key of coreMetadataKeys) {
14450
- if (key in schema) {
14451
- extraMeta[key] = schema[key];
14449
+ for (const key2 of coreMetadataKeys) {
14450
+ if (key2 in schema) {
14451
+ extraMeta[key2] = schema[key2];
14452
14452
  }
14453
14453
  }
14454
14454
  const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
14455
- for (const key of contentMetadataKeys) {
14456
- if (key in schema) {
14457
- extraMeta[key] = schema[key];
14455
+ for (const key2 of contentMetadataKeys) {
14456
+ if (key2 in schema) {
14457
+ extraMeta[key2] = schema[key2];
14458
14458
  }
14459
14459
  }
14460
- for (const key of Object.keys(schema)) {
14461
- if (!RECOGNIZED_KEYS.has(key)) {
14462
- extraMeta[key] = schema[key];
14460
+ for (const key2 of Object.keys(schema)) {
14461
+ if (!RECOGNIZED_KEYS.has(key2)) {
14462
+ extraMeta[key2] = schema[key2];
14463
14463
  }
14464
14464
  }
14465
14465
  if (Object.keys(extraMeta).length > 0) {
@@ -14776,10 +14776,32 @@ function createFailover(routes, notice) {
14776
14776
  const notify = (message) => notice(`agent-router: ${message}`).catch(() => {
14777
14777
  });
14778
14778
  return {
14779
+ pending(sessionID) {
14780
+ const state = sessions.get(sessionID);
14781
+ return enabled && !state?.disabled && state?.pending ? { ...state.pending } : void 0;
14782
+ },
14779
14783
  active(sessionID) {
14780
14784
  const state = sessions.get(sessionID);
14781
14785
  return enabled && Boolean(state?.turn) && !state?.disabled;
14782
14786
  },
14787
+ /** Register an admission already selected by a separate policy; no retry occurs. */
14788
+ admit(sessionID, message) {
14789
+ if (!enabled) return;
14790
+ const chain = chains.get(message.agent);
14791
+ const index = chain?.findIndex((candidate) => same(candidate, message.model)) ?? -1;
14792
+ if (index < 0 || !sessions.has(sessionID) && sessions.size >= 1024) return;
14793
+ const state = sessions.get(sessionID) ?? { disabled: false, indices: /* @__PURE__ */ new Map() };
14794
+ state.disabled = false;
14795
+ state.indices.set(message.agent, index);
14796
+ state.pending = void 0;
14797
+ state.turn = {
14798
+ agent: message.agent,
14799
+ parent: message.id,
14800
+ model: { ...message.model },
14801
+ handled: false
14802
+ };
14803
+ sessions.set(sessionID, state);
14804
+ },
14783
14805
  disable() {
14784
14806
  enabled = false;
14785
14807
  sessions.clear();
@@ -15142,29 +15164,29 @@ function parseMapping(lines, startIdx, indent) {
15142
15164
  i++;
15143
15165
  continue;
15144
15166
  }
15145
- const key = stripKeyQuotes(line.text.slice(0, colon).trim());
15146
- if (key === "") {
15167
+ const key2 = stripKeyQuotes(line.text.slice(0, colon).trim());
15168
+ if (key2 === "") {
15147
15169
  i++;
15148
15170
  continue;
15149
15171
  }
15150
15172
  const rest = line.text.slice(colon + 1).trim();
15151
15173
  if (rest !== "") {
15152
- out[key] = parseFlowValue(rest);
15174
+ out[key2] = parseFlowValue(rest);
15153
15175
  i++;
15154
15176
  } else {
15155
15177
  const childIndent = lines[i + 1]?.indent ?? line.indent + 1;
15156
15178
  let j = i + 1;
15157
15179
  while (j < lines.length && (lines[j]?.indent ?? -1) >= childIndent) j++;
15158
15180
  if (j === i + 1) {
15159
- out[key] = null;
15181
+ out[key2] = null;
15160
15182
  i++;
15161
15183
  } else {
15162
15184
  const childBlock = lines.slice(i + 1, j);
15163
15185
  const firstChild = childBlock[0];
15164
15186
  if (firstChild?.text.trimStart().startsWith("- ")) {
15165
- out[key] = parseSequence(childBlock, childIndent);
15187
+ out[key2] = parseSequence(childBlock, childIndent);
15166
15188
  } else {
15167
- out[key] = parseMapping(childBlock, 0, childIndent).value;
15189
+ out[key2] = parseMapping(childBlock, 0, childIndent).value;
15168
15190
  }
15169
15191
  i = j;
15170
15192
  }
@@ -15276,24 +15298,24 @@ function setFrontmatterOptions(content, options) {
15276
15298
  for (let i = 0; i < lines.length; i++) {
15277
15299
  const m = /^([A-Za-z0-9_-]+):[ \t]*(.*)$/.exec(lines[i] ?? "");
15278
15300
  if (!m) continue;
15279
- const key = m[1] ?? "";
15280
- if (!(key in options)) continue;
15281
- handled.add(key);
15301
+ const key2 = m[1] ?? "";
15302
+ if (!(key2 in options)) continue;
15303
+ handled.add(key2);
15282
15304
  let end = i + 1;
15283
15305
  while (end < lines.length && /^[ \t]+/.test(lines[end] ?? "")) end++;
15284
- const value = options[key];
15306
+ const value = options[key2];
15285
15307
  if (value === null || value === void 0) {
15286
15308
  lines.splice(i, end - i);
15287
15309
  i--;
15288
15310
  } else {
15289
- lines.splice(i, end - i, `${key}: ${serializeOptionValue(value)}`);
15311
+ lines.splice(i, end - i, `${key2}: ${serializeOptionValue(value)}`);
15290
15312
  }
15291
15313
  }
15292
15314
  const appended = [];
15293
- for (const [key, value] of Object.entries(options)) {
15294
- if (handled.has(key)) continue;
15315
+ for (const [key2, value] of Object.entries(options)) {
15316
+ if (handled.has(key2)) continue;
15295
15317
  if (value === null || value === void 0) continue;
15296
- appended.push(`${key}: ${serializeOptionValue(value)}`);
15318
+ appended.push(`${key2}: ${serializeOptionValue(value)}`);
15297
15319
  }
15298
15320
  const nextBlock = appended.length > 0 ? lines.join(eol) + eol + appended.join(eol) : lines.join(eol);
15299
15321
  if (nextBlock === block) return content;
@@ -15731,6 +15753,364 @@ async function captureStack(paths, name, options = {}) {
15731
15753
  return { name, path: dest, agents: Object.keys(agents).length };
15732
15754
  }
15733
15755
 
15756
+ // src/core/pin-store.ts
15757
+ var Pins = external_exports.object({ version: external_exports.literal(1), sessionIDs: external_exports.array(external_exports.string().min(1)).max(1024) }).strict();
15758
+ var PIN_STORE_KEY = "quota-pins-v1";
15759
+ function createPinStore(storage) {
15760
+ let lane = Promise.resolve();
15761
+ let pending = 0;
15762
+ const read = async () => {
15763
+ const value = await storage.get(PIN_STORE_KEY);
15764
+ return new Set(value === void 0 ? [] : Pins.parse(value).sessionIDs);
15765
+ };
15766
+ const mutate = (sessionID, add, valid) => {
15767
+ if (pending >= 65) return Promise.reject(new Error("Session pin storage is busy; try again."));
15768
+ pending++;
15769
+ const operation = lane.then(async () => {
15770
+ const pins = await read();
15771
+ if (!valid()) throw new Error("Session pin operation was cancelled.");
15772
+ if (add) {
15773
+ if (!pins.has(sessionID) && pins.size >= 1024)
15774
+ throw new Error("Session pin capacity reached.");
15775
+ pins.add(sessionID);
15776
+ } else if (!pins.delete(sessionID)) return;
15777
+ await storage.set(PIN_STORE_KEY, { version: 1, sessionIDs: [...pins] });
15778
+ });
15779
+ lane = operation.then(
15780
+ () => {
15781
+ pending--;
15782
+ },
15783
+ () => {
15784
+ pending--;
15785
+ }
15786
+ );
15787
+ return operation;
15788
+ };
15789
+ return {
15790
+ async has(sessionID) {
15791
+ await lane;
15792
+ return (await read()).has(sessionID);
15793
+ },
15794
+ add: (sessionID, valid) => mutate(sessionID, true, valid),
15795
+ remove: (sessionID, valid = () => true) => mutate(sessionID, false, valid),
15796
+ drain: () => lane
15797
+ };
15798
+ }
15799
+
15800
+ // src/core/quota-preflight.ts
15801
+ import { Rpc } from "@opencode/plugin/rpc";
15802
+ var ID = external_exports.string().max(200).regex(/^[a-zA-Z0-9][a-zA-Z0-9._:/+-]*$/);
15803
+ var Candidate = external_exports.object({ providerID: ID, id: ID }).strict();
15804
+ var Result = Candidate.extend({
15805
+ status: external_exports.enum(["available", "exhausted", "unknown"]),
15806
+ checkedAt: external_exports.number().finite().nullable(),
15807
+ validUntil: external_exports.number().finite().nullable(),
15808
+ resetAt: external_exports.number().finite().nullable(),
15809
+ reason: external_exports.string(),
15810
+ accountRef: external_exports.string().nullable(),
15811
+ scopeRef: external_exports.string().nullable()
15812
+ }).strict();
15813
+ var QuotaOutput = external_exports.object({ candidates: external_exports.array(Result).max(64) }).strict();
15814
+ var UsageQuota = Rpc.define({
15815
+ id: "direct-api-usage",
15816
+ methods: {
15817
+ query: {
15818
+ input: external_exports.object({ candidates: external_exports.array(Candidate).max(64) }).strict(),
15819
+ output: QuotaOutput
15820
+ }
15821
+ },
15822
+ events: {}
15823
+ });
15824
+ var QuotaOptions = external_exports.object({ enabled: external_exports.boolean().default(false), allowPaidFallbacks: external_exports.boolean().default(false) }).strict();
15825
+ function quotaCandidate(entry) {
15826
+ const slash = entry.model.indexOf("/");
15827
+ return { providerID: entry.model.slice(0, slash), id: entry.model.slice(slash + 1) };
15828
+ }
15829
+ function effectiveQuotaStatus(candidate, results, now = Date.now()) {
15830
+ const matches = results.filter(
15831
+ (r) => r.providerID === candidate.providerID && r.id === candidate.id
15832
+ );
15833
+ const result = matches.length === 1 ? matches[0] : void 0;
15834
+ const bound = Boolean(result?.accountRef && result.scopeRef);
15835
+ const fresh = bound && result?.checkedAt !== null && result?.checkedAt !== void 0 && result.checkedAt > 0 && result.checkedAt <= now && result.validUntil !== null && result.validUntil > now && (result.resetAt === null || result.resetAt > now);
15836
+ return { status: fresh ? result?.status ?? "unknown" : "unknown", bound };
15837
+ }
15838
+ function chooseQuotaRoute(route, results, allowPaidFallbacks, now = Date.now(), startIndex = 0) {
15839
+ for (const [index, entry] of [route, ...route.fallbacks ?? []].entries()) {
15840
+ if (index < startIndex) continue;
15841
+ const candidate = quotaCandidate(entry);
15842
+ const { status, bound } = effectiveQuotaStatus(candidate, results, now);
15843
+ if (status === "exhausted") continue;
15844
+ if (index === 0 || bound || allowPaidFallbacks) return entry;
15845
+ }
15846
+ return void 0;
15847
+ }
15848
+ function createQuotaQuery(query, deadlineMs = 3e3, capacity = 16) {
15849
+ const pending = /* @__PURE__ */ new Set();
15850
+ let disposed = false;
15851
+ return {
15852
+ async read(candidates) {
15853
+ if (disposed || pending.size >= capacity) return [];
15854
+ const controller = new AbortController();
15855
+ pending.add(controller);
15856
+ let timer;
15857
+ const request = Promise.resolve().then(() => query({ candidates }, { signal: controller.signal })).then((value) => {
15858
+ const parsed = QuotaOutput.safeParse(value);
15859
+ return parsed.success ? parsed.data.candidates : [];
15860
+ }).catch(() => []).finally(() => pending.delete(controller));
15861
+ const timeout = new Promise((resolve) => {
15862
+ const stop = () => resolve([]);
15863
+ controller.signal.addEventListener("abort", stop, { once: true });
15864
+ timer = setTimeout(() => controller.abort(), deadlineMs);
15865
+ });
15866
+ try {
15867
+ return await Promise.race([request, timeout]);
15868
+ } finally {
15869
+ clearTimeout(timer);
15870
+ }
15871
+ },
15872
+ dispose() {
15873
+ disposed = true;
15874
+ for (const controller of pending) controller.abort();
15875
+ }
15876
+ };
15877
+ }
15878
+
15879
+ // src/quota-v2.ts
15880
+ var key = (model) => model ? `${model.providerID}/${model.id}#${model.variant === "default" ? "" : model.variant ?? ""}` : "";
15881
+ function createQuotaAdmission(ctx, routes, current) {
15882
+ const parsed = QuotaOptions.safeParse(ctx.options?.quotaPreflight ?? {});
15883
+ if (!parsed.success || !parsed.data.enabled) return void 0;
15884
+ const options = parsed.data;
15885
+ const query = createQuotaQuery((input, request) => ctx.rpc(UsageQuota).query(input, request));
15886
+ const owned = /* @__PURE__ */ new Map();
15887
+ const expected = /* @__PURE__ */ new Map();
15888
+ const busy = /* @__PURE__ */ new Set();
15889
+ const versions = /* @__PURE__ */ new Map();
15890
+ const controls = /* @__PURE__ */ new Set();
15891
+ const pinned = /* @__PURE__ */ new Set();
15892
+ const deletedControls = /* @__PURE__ */ new Set();
15893
+ const pinStore = createPinStore(ctx.storage);
15894
+ const reasons = /* @__PURE__ */ new Map();
15895
+ let disposed = false;
15896
+ const invalidate = (sessionID) => {
15897
+ if (busy.has(sessionID)) versions.set(sessionID, (versions.get(sessionID) ?? 0) + 1);
15898
+ };
15899
+ const reason = (sessionID, value, model) => {
15900
+ if (disposed) return;
15901
+ if (reasons.has(sessionID) || reasons.size < 1024) reasons.set(sessionID, value);
15902
+ console.info(`agent-router: [${sessionID}] ${value}${model ? ` ${key(model)}` : ""}`);
15903
+ };
15904
+ const isPinned = async (sessionID) => {
15905
+ if (pinned.has(sessionID)) return true;
15906
+ try {
15907
+ return await pinStore.has(sessionID);
15908
+ } catch {
15909
+ return true;
15910
+ }
15911
+ };
15912
+ const evaluate = async (route, pending) => {
15913
+ const candidates = [route, ...route.fallbacks ?? []].map(quotaCandidate).filter(
15914
+ (entry, index, all) => all.findIndex(
15915
+ (other) => other.providerID === entry.providerID && other.id === entry.id
15916
+ ) === index
15917
+ );
15918
+ const results = await query.read(candidates);
15919
+ return () => {
15920
+ const now = Date.now();
15921
+ const startIndex = pending ? Math.max(
15922
+ 0,
15923
+ [route, ...route.fallbacks ?? []].findIndex(
15924
+ (entry) => key({
15925
+ ...quotaCandidate(entry),
15926
+ ...entry.variant ? { variant: entry.variant } : {}
15927
+ }) === key(pending)
15928
+ )
15929
+ ) : 0;
15930
+ const choice = chooseQuotaRoute(route, results, options.allowPaidFallbacks, now, startIndex);
15931
+ return {
15932
+ choice,
15933
+ reason: !choice ? "no_eligible_fallback" : pending ? "staged_reactive_fallback" : choice.model !== route.model ? "known_exhaustion_fallback" : effectiveQuotaStatus(quotaCandidate(route), results, now).status === "available" ? "primary_available" : "primary_unknown"
15934
+ };
15935
+ };
15936
+ };
15937
+ return {
15938
+ isPinned,
15939
+ async status(sessionID) {
15940
+ const session = await ctx.session.get({ sessionID });
15941
+ const explicit = await isPinned(sessionID);
15942
+ const automatic = !explicit && (!session.model || owned.get(sessionID)?.model === key(session.model));
15943
+ const resolved = session.model ?? (session.agent ? (await ctx.agent.get({ agentID: session.agent })).data.model : void 0) ?? (await ctx.model.default()).data;
15944
+ return {
15945
+ sessionID,
15946
+ mode: automatic ? "automatic" : "pinned",
15947
+ model: resolved ? {
15948
+ providerID: resolved.providerID,
15949
+ id: resolved.id,
15950
+ ..."variant" in resolved && typeof resolved.variant === "string" ? { variant: resolved.variant } : {}
15951
+ } : null,
15952
+ reason: explicit ? "explicit_pin" : automatic ? reasons.get(sessionID) ?? "awaiting_next_turn" : "manual_or_preexisting_selection"
15953
+ };
15954
+ },
15955
+ async control(sessionID, action, pause) {
15956
+ if (disposed || !current())
15957
+ throw new Error("Router configuration changed; reload before changing session routing.");
15958
+ if (controls.has(sessionID) || controls.size >= 64)
15959
+ throw new Error("Session routing control is busy; try again.");
15960
+ if (action === "pin" && !pinned.has(sessionID) && pinned.size >= 1024)
15961
+ throw new Error("Session pin capacity reached.");
15962
+ controls.add(sessionID);
15963
+ invalidate(sessionID);
15964
+ const live = () => !disposed && current() && !deletedControls.has(sessionID);
15965
+ try {
15966
+ await pause();
15967
+ const session = await ctx.session.get({ sessionID });
15968
+ if (!live())
15969
+ throw new Error("Router stopped or session deleted before the control completed.");
15970
+ if (!session.agent || !routes[session.agent])
15971
+ throw new Error("No configured route for this session agent.");
15972
+ if (action === "pin") {
15973
+ owned.delete(sessionID);
15974
+ expected.delete(sessionID);
15975
+ await pinStore.add(sessionID, live);
15976
+ if (!live()) throw new Error("Router stopped or session deleted during pinning.");
15977
+ pinned.add(sessionID);
15978
+ if (!session.model) {
15979
+ const agent = await ctx.agent.get({ agentID: session.agent });
15980
+ const resolved = agent.data.model ?? (await ctx.model.default()).data;
15981
+ if (!resolved) throw new Error("No native model is resolved; routing remains pinned.");
15982
+ const latest = await ctx.session.get({ sessionID });
15983
+ if (!live()) throw new Error("Router stopped or session deleted during pinning.");
15984
+ if (latest.agent !== session.agent || key(latest.model) !== key(session.model))
15985
+ throw new Error(
15986
+ "Session selection changed while pinning; current selection remains pinned."
15987
+ );
15988
+ const model = {
15989
+ providerID: resolved.providerID,
15990
+ id: resolved.id,
15991
+ ..."variant" in resolved && typeof resolved.variant === "string" ? { variant: resolved.variant } : {}
15992
+ };
15993
+ await ctx.session.switchModel({ sessionID, model });
15994
+ }
15995
+ if (!live()) throw new Error("Router stopped or session deleted during pinning.");
15996
+ reason(sessionID, "explicit_pin", (await ctx.session.get({ sessionID })).model);
15997
+ } else {
15998
+ if (!owned.has(sessionID) && owned.size >= 1024)
15999
+ throw new Error("Automatic session capacity reached.");
16000
+ await pinStore.remove(sessionID, live);
16001
+ if (!live()) throw new Error("Router stopped; automatic routing was not resumed.");
16002
+ pinned.delete(sessionID);
16003
+ owned.set(sessionID, { agent: session.agent, model: key(session.model) });
16004
+ reason(sessionID, "automatic_next_explicit_turn", session.model);
16005
+ }
16006
+ } finally {
16007
+ controls.delete(sessionID);
16008
+ deletedControls.delete(sessionID);
16009
+ }
16010
+ },
16011
+ /** Called for every selection event, including before the first prompt. */
16012
+ event(sessionID, type, model) {
16013
+ if (type === "session.model.selected" && expected.get(sessionID) === key(model)) {
16014
+ expected.delete(sessionID);
16015
+ return true;
16016
+ }
16017
+ if ([
16018
+ "session.model.selected",
16019
+ "session.agent.selected",
16020
+ "session.execution.interrupted",
16021
+ "session.deleted"
16022
+ ].includes(type)) {
16023
+ owned.delete(sessionID);
16024
+ expected.delete(sessionID);
16025
+ invalidate(sessionID);
16026
+ if (type === "session.deleted") {
16027
+ if (controls.has(sessionID)) deletedControls.add(sessionID);
16028
+ pinned.delete(sessionID);
16029
+ reasons.delete(sessionID);
16030
+ return pinStore.remove(sessionID).then(() => false);
16031
+ }
16032
+ }
16033
+ return false;
16034
+ },
16035
+ async main(sessionID, session, pending) {
16036
+ if (disposed || !current() || session.parentID || !session.agent || busy.has(sessionID))
16037
+ return;
16038
+ if (busy.size >= 64) return;
16039
+ busy.add(sessionID);
16040
+ const generation = versions.get(sessionID) ?? 0;
16041
+ try {
16042
+ if (controls.has(sessionID) || await isPinned(sessionID)) return;
16043
+ if (disposed || controls.has(sessionID) || pinned.has(sessionID) || (versions.get(sessionID) ?? 0) !== generation)
16044
+ return;
16045
+ const route = routes[session.agent];
16046
+ if (!route) return;
16047
+ const previous = owned.get(sessionID);
16048
+ if (session.model && (!previous || previous.agent !== session.agent || previous.model !== key(session.model)))
16049
+ return;
16050
+ if (!owned.has(sessionID) && owned.size >= 1024) return;
16051
+ const choose = await evaluate(route, pending);
16052
+ if (disposed || !current() || (versions.get(sessionID) ?? 0) !== generation) return;
16053
+ const latest = await ctx.session.get({ sessionID });
16054
+ if (disposed || controls.has(sessionID) || pinned.has(sessionID) || latest.agent !== session.agent || key(latest.model) !== key(session.model) || (versions.get(sessionID) ?? 0) !== generation || !current())
16055
+ return;
16056
+ const decision = choose();
16057
+ const { choice } = decision;
16058
+ if (!choice) {
16059
+ reason(sessionID, decision.reason, session.model);
16060
+ return;
16061
+ }
16062
+ const model = {
16063
+ ...quotaCandidate(choice),
16064
+ ...choice.variant && choice.variant !== "default" ? { variant: choice.variant } : {}
16065
+ };
16066
+ if (key(model) !== key(session.model) && (session.model || choice.model !== route.model || choice.variant !== route.variant)) {
16067
+ expected.set(sessionID, key(model));
16068
+ try {
16069
+ await ctx.session.switchModel({ sessionID, model });
16070
+ } catch {
16071
+ expected.delete(sessionID);
16072
+ return;
16073
+ }
16074
+ }
16075
+ if (disposed || controls.has(sessionID) || pinned.has(sessionID) || (versions.get(sessionID) ?? 0) !== generation)
16076
+ return;
16077
+ owned.set(sessionID, { agent: session.agent, model: key(model) });
16078
+ reason(sessionID, decision.reason, model);
16079
+ return model;
16080
+ } finally {
16081
+ busy.delete(sessionID);
16082
+ versions.delete(sessionID);
16083
+ }
16084
+ },
16085
+ async child(event) {
16086
+ if (disposed || !current() || event.tool !== "subagent" || !event.input || typeof event.input !== "object")
16087
+ return;
16088
+ const input = event.input;
16089
+ if ("model" in input || "sessionID" in input || "session_id" in input || "task_id" in input || typeof input.agent !== "string")
16090
+ return;
16091
+ const route = routes[input.agent];
16092
+ if (!route) return;
16093
+ const originalAgent = input.agent;
16094
+ const choose = await evaluate(route);
16095
+ const { choice } = choose();
16096
+ if (!choice || disposed || !current() || input.agent !== originalAgent || "model" in input)
16097
+ return;
16098
+ input.model = choice.model + (choice.variant && choice.variant !== "default" ? `#${choice.variant}` : "");
16099
+ },
16100
+ async dispose() {
16101
+ disposed = true;
16102
+ query.dispose();
16103
+ owned.clear();
16104
+ expected.clear();
16105
+ versions.clear();
16106
+ controls.clear();
16107
+ pinned.clear();
16108
+ reasons.clear();
16109
+ await pinStore.drain();
16110
+ }
16111
+ };
16112
+ }
16113
+
15734
16114
  // src/v2.ts
15735
16115
  var variant = (value) => value === "default" ? void 0 : value ?? void 0;
15736
16116
  async function setupV2(ctx) {
@@ -15793,11 +16173,50 @@ async function setupV2(ctx) {
15793
16173
  const turns = /* @__PURE__ */ new Map();
15794
16174
  const kinds = /* @__PURE__ */ new Map();
15795
16175
  const ownSelections = /* @__PURE__ */ new Map();
16176
+ const quota = createQuotaAdmission(ctx, routes, () => state() === initial);
16177
+ if (quota) {
16178
+ await ctx.tool.transform((editor) => {
16179
+ const input = { type: "object", properties: {}, additionalProperties: false };
16180
+ for (const action of ["pin", "auto"])
16181
+ editor.add({
16182
+ name: `router_${action}`,
16183
+ description: action === "pin" ? "Only on an explicit user request: pin this session's current model and disable automatic quota/reactive routing. Takes no model or session arguments." : "Only on an explicit user request: resume quota-aware routing for this session on its NEXT explicit user turn. Does not send a prompt or switch immediately.",
16184
+ input,
16185
+ async execute(_input, context) {
16186
+ await quota.control(context.sessionID, action, async () => {
16187
+ turns.delete(context.sessionID);
16188
+ kinds.delete(context.sessionID);
16189
+ await failover.event({
16190
+ event: {
16191
+ type: "session.next.model.switched",
16192
+ properties: { sessionID: context.sessionID }
16193
+ }
16194
+ });
16195
+ });
16196
+ return { content: JSON.stringify(await quota.status(context.sessionID)) };
16197
+ }
16198
+ });
16199
+ editor.add({
16200
+ name: "router_routing_status",
16201
+ description: "Show this session's automatic/pinned routing mode, current model, and routing reason.",
16202
+ input,
16203
+ async execute(_input, context) {
16204
+ return { content: JSON.stringify(await quota.status(context.sessionID)) };
16205
+ }
16206
+ });
16207
+ });
16208
+ }
15796
16209
  const controller = new AbortController();
15797
16210
  const events = (async () => {
15798
16211
  for await (const event of ctx.event.subscribe({ signal: controller.signal })) {
15799
16212
  if (!("sessionID" in event.data)) continue;
15800
16213
  const sessionID = String(event.data.sessionID);
16214
+ if (await quota?.event(
16215
+ sessionID,
16216
+ event.type,
16217
+ event.type === "session.model.selected" ? event.data.model : void 0
16218
+ ))
16219
+ continue;
15801
16220
  if (!turns.has(sessionID)) continue;
15802
16221
  if (event.type === "session.model.selected") {
15803
16222
  const model = event.data.model;
@@ -15825,6 +16244,7 @@ async function setupV2(ctx) {
15825
16244
  await ctx.session.hook("model.request", (event) => {
15826
16245
  if (turns.has(event.sessionID)) kinds.set(event.sessionID, event.kind);
15827
16246
  });
16247
+ if (quota) await ctx.tool.hook("execute.before", (event) => quota.child(event));
15828
16248
  await ctx.session.hook("prompt", async (event) => {
15829
16249
  if (turns.get(event.sessionID)?.id === event.messageID) return;
15830
16250
  if (state() !== initial) {
@@ -15833,6 +16253,40 @@ async function setupV2(ctx) {
15833
16253
  return;
15834
16254
  }
15835
16255
  const session = await ctx.session.get({ sessionID: event.sessionID });
16256
+ if (turns.get(event.sessionID)?.id === event.messageID) return;
16257
+ if (quota) {
16258
+ if (session.parentID && await quota.isPinned(event.sessionID)) {
16259
+ turns.delete(event.sessionID);
16260
+ return;
16261
+ }
16262
+ const pending = failover.pending(event.sessionID);
16263
+ const selected = session.parentID ? session.model : await quota.main(
16264
+ event.sessionID,
16265
+ session,
16266
+ pending ? {
16267
+ providerID: pending.providerID,
16268
+ id: pending.modelID,
16269
+ variant: pending.variant
16270
+ } : void 0
16271
+ );
16272
+ if (!selected || !session.agent || !routes[session.agent]) {
16273
+ turns.delete(event.sessionID);
16274
+ return;
16275
+ }
16276
+ const message2 = {
16277
+ id: event.messageID,
16278
+ agent: session.agent,
16279
+ model: {
16280
+ providerID: selected.providerID,
16281
+ modelID: selected.id,
16282
+ variant: variant(selected.variant)
16283
+ }
16284
+ };
16285
+ failover.admit(event.sessionID, message2);
16286
+ if (!failover.active(event.sessionID)) return;
16287
+ turns.set(event.sessionID, message2);
16288
+ return;
16289
+ }
15836
16290
  if (!session.agent || !session.model || !routes[session.agent]) return;
15837
16291
  const message = {
15838
16292
  id: event.messageID,
@@ -15909,6 +16363,7 @@ async function setupV2(ctx) {
15909
16363
  });
15910
16364
  return async () => {
15911
16365
  controller.abort();
16366
+ await quota?.dispose();
15912
16367
  failover.disable();
15913
16368
  turns.clear();
15914
16369
  kinds.clear();
@@ -15918,7 +16373,7 @@ async function setupV2(ctx) {
15918
16373
  }
15919
16374
 
15920
16375
  // src/version.ts
15921
- var VERSION = "2.0.1";
16376
+ var VERSION = "2.1.0";
15922
16377
 
15923
16378
  // src/plugin.ts
15924
16379
  var tool = Object.assign(