@query-farm/vgi 0.9.0 → 0.11.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.
@@ -58,6 +58,13 @@ export declare function formatRange(ge?: number, le?: number, gt?: number, lt?:
58
58
  * no field). Mirrors Python's `_constraint_kwargs`.
59
59
  */
60
60
  export declare function constraintSpecFields(constraints: ArgumentConstraints | undefined): Pick<ArgumentSpec, "defaultJson" | "choicesJson" | "rangeNotation" | "pattern">;
61
+ /**
62
+ * Enforce a bind-time const value against its declared {@link ArgumentConstraints},
63
+ * throwing {@link ArgumentValidationError} on violation. Mirrors the Python SDK's
64
+ * `Arg._validate`: numeric range (`ge`/`le`/`gt`/`lt`), closed choice set, and
65
+ * regex `pattern`. A `null`/`undefined` value skips its value constraints.
66
+ */
67
+ export declare function validateConstConstraints(name: string, constraints: ArgumentConstraints, value: unknown): void;
61
68
  /**
62
69
  * Convert ArgumentSpecs to an Arrow Schema with VGI metadata keys.
63
70
  * Positional arguments come first (in order), named arguments follow.
@@ -1,5 +1,6 @@
1
1
  import { type VgiSchema, type VgiBatch, type VgiDataType } from "../arrow/index.js";
2
2
  import type { Arguments } from "../arguments/arguments.js";
3
+ import { type ArgumentConstraints } from "../arguments/argument-spec.js";
3
4
  import type { VgiFunction } from "./types.js";
4
5
  import type { FunctionExample } from "./types.js";
5
6
  export declare const GROUP_COLUMN_NAME = "__vgi_group_id";
@@ -70,6 +71,13 @@ export interface AggregateFunctionConfig<TArgs = Record<string, any>, TState = a
70
71
  onBind?: (params: AggregateBindParams<TArgs>) => VgiDataType | Promise<VgiDataType>;
71
72
  /** Optional per-arg default values (positional only here). */
72
73
  argDefaults?: Record<string, any>;
74
+ /**
75
+ * Per-argument discovery constraints (choices / ge / le / gt / lt / pattern),
76
+ * keyed by argument name. Surfaced via `vgi_function_arguments()` and enforced
77
+ * at aggregate_bind for const params: a value violating a declared constraint
78
+ * fails the bind with an ArgumentValidationError.
79
+ */
80
+ argConstraints?: Record<string, ArgumentConstraints>;
73
81
  initialState: (params: AggregateBindParams<TArgs>) => TState;
74
82
  /**
75
83
  * Fold a batch of input rows into the provided per-group state map.
@@ -2,6 +2,7 @@ import { type VgiSchema, type VgiDataType } from "../arrow/index.js";
2
2
  import type { OutputCollector } from "@query-farm/vgi-rpc";
3
3
  import type { BindRequest, InitRequest, GlobalInitResponse, TableCardinality } from "../protocol/types.js";
4
4
  import type { VgiFunction, FunctionExample } from "./types.js";
5
+ import { type ArgumentConstraints } from "../arguments/argument-spec.js";
5
6
  import { type PushdownFilters } from "../filter-pushdown/index.js";
6
7
  import type { ColumnStatistics } from "../util/statistics.js";
7
8
  import { FunctionStability, type NullHandling, type OrderPreservation, type OrderDependence, type DistinctDependence } from "../types.js";
@@ -41,6 +42,13 @@ export interface TableFunctionConfig<TArgs = Record<string, any>, TState = null>
41
42
  argDocs?: Record<string, string>;
42
43
  /** Argument defaults */
43
44
  argDefaults?: Record<string, any>;
45
+ /**
46
+ * Per-argument discovery constraints (choices / ge / le / gt / lt / pattern),
47
+ * keyed by argument name. Surfaced via `vgi_function_arguments()` for agent
48
+ * discovery AND enforced at bind: a value violating a declared constraint
49
+ * fails the bind with an ArgumentValidationError.
50
+ */
51
+ argConstraints?: Record<string, ArgumentConstraints>;
44
52
  /** Names of args that accept variable number of arguments */
45
53
  varargs?: string[];
46
54
  /** Bind: return output schema. May be async — handlers `await` the result. */
package/dist/index.js CHANGED
@@ -2717,6 +2717,55 @@ function constraintSpecFields(constraints) {
2717
2717
  }
2718
2718
  return fields;
2719
2719
  }
2720
+ function toNumber(value) {
2721
+ if (typeof value === "number")
2722
+ return value;
2723
+ if (typeof value === "bigint")
2724
+ return Number(value);
2725
+ return;
2726
+ }
2727
+ function choiceEquals(choice, value) {
2728
+ const cn = toNumber(choice);
2729
+ const vn = toNumber(value);
2730
+ if (cn !== undefined && vn !== undefined)
2731
+ return cn === vn;
2732
+ return choice === value;
2733
+ }
2734
+ function validateConstConstraints(name, constraints, value) {
2735
+ if (value === null || value === undefined)
2736
+ return;
2737
+ const num = toNumber(value);
2738
+ if (num !== undefined) {
2739
+ if (constraints.ge !== undefined && num < constraints.ge) {
2740
+ throw new ArgumentValidationError(`argument '${name}' must be >= ${constraints.ge}`);
2741
+ }
2742
+ if (constraints.le !== undefined && num > constraints.le) {
2743
+ throw new ArgumentValidationError(`argument '${name}' must be <= ${constraints.le}`);
2744
+ }
2745
+ if (constraints.gt !== undefined && num <= constraints.gt) {
2746
+ throw new ArgumentValidationError(`argument '${name}' must be > ${constraints.gt}`);
2747
+ }
2748
+ if (constraints.lt !== undefined && num >= constraints.lt) {
2749
+ throw new ArgumentValidationError(`argument '${name}' must be < ${constraints.lt}`);
2750
+ }
2751
+ }
2752
+ if (constraints.choices !== undefined && constraints.choices.length > 0) {
2753
+ if (!constraints.choices.some((c) => choiceEquals(c, value))) {
2754
+ throw new ArgumentValidationError(`argument '${name}' must be one of ${JSON.stringify([...constraints.choices])}`);
2755
+ }
2756
+ }
2757
+ if (constraints.pattern !== undefined && typeof value === "string") {
2758
+ let re;
2759
+ try {
2760
+ re = new RegExp(constraints.pattern);
2761
+ } catch {
2762
+ re = undefined;
2763
+ }
2764
+ if (re !== undefined && !re.test(value)) {
2765
+ throw new ArgumentValidationError(`argument '${name}' must match pattern ${JSON.stringify(constraints.pattern)}`);
2766
+ }
2767
+ }
2768
+ }
2720
2769
  function argumentSpecSortKey(spec) {
2721
2770
  if (typeof spec.position === "number") {
2722
2771
  return [0, spec.position];
@@ -2884,6 +2933,14 @@ function defineScalarFunction(config) {
2884
2933
  }
2885
2934
  }
2886
2935
  }
2936
+ const constConstraints = new Map;
2937
+ if (config.parameters) {
2938
+ for (const p of config.parameters) {
2939
+ if (p.const && (p.choices !== undefined || p.ge !== undefined || p.le !== undefined || p.gt !== undefined || p.lt !== undefined || p.pattern !== undefined)) {
2940
+ constConstraints.set(p.name, p);
2941
+ }
2942
+ }
2943
+ }
2887
2944
  const meta = {
2888
2945
  name: config.name,
2889
2946
  description: config.description,
@@ -2910,7 +2967,11 @@ function defineScalarFunction(config) {
2910
2967
  let constIdx = 0;
2911
2968
  for (const spec of specs) {
2912
2969
  if (spec.isConst) {
2913
- constArgs[spec.name] = request.arguments.get(constIdx, undefined);
2970
+ const value = request.arguments.get(constIdx, undefined);
2971
+ constArgs[spec.name] = value;
2972
+ const constraints = constConstraints.get(spec.name);
2973
+ if (constraints)
2974
+ validateConstConstraints(spec.name, constraints, value);
2914
2975
  constIdx++;
2915
2976
  }
2916
2977
  }
@@ -3803,7 +3864,8 @@ function defineTableFunction(config) {
3803
3864
  arrowType: isAny ? nullType2() : type,
3804
3865
  isAnyType: isAny,
3805
3866
  isVarargs: varargsSet.has(name),
3806
- doc: config.argDocs?.[name]
3867
+ doc: config.argDocs?.[name],
3868
+ ...constraintSpecFields(config.argConstraints?.[name])
3807
3869
  });
3808
3870
  }
3809
3871
  }
@@ -3842,6 +3904,9 @@ function defineTableFunction(config) {
3842
3904
  }
3843
3905
  if (typeof val === "bigint")
3844
3906
  val = safeNumber(val);
3907
+ const constraints = config.argConstraints?.[spec.name];
3908
+ if (constraints)
3909
+ validateConstConstraints(spec.name, constraints, val);
3845
3910
  args[spec.name] = val;
3846
3911
  }
3847
3912
  return args;
@@ -4117,7 +4182,8 @@ function defineAggregate(config) {
4117
4182
  arrowType: isAnyType2 ? nullType2() : type,
4118
4183
  isAnyType: isAnyType2,
4119
4184
  isVarargs: varargsSet.has(name),
4120
- isConst
4185
+ isConst,
4186
+ ...constraintSpecFields(config.argConstraints?.[name])
4121
4187
  });
4122
4188
  }
4123
4189
  }
@@ -9079,8 +9145,9 @@ function extractArgMap(cfg, args) {
9079
9145
  }
9080
9146
  }
9081
9147
  for (let i = 0;i < constNames.length; i++) {
9148
+ let v;
9082
9149
  try {
9083
- let v = args.get(i);
9150
+ v = args.get(i);
9084
9151
  const field3 = args.argumentsSchema?.fields.find((f) => f.name === `positional_${i}`);
9085
9152
  if (field3 && isDecimal(field3.type)) {
9086
9153
  const scale = field3.type.scale;
@@ -9091,12 +9158,17 @@ function extractArgMap(cfg, args) {
9091
9158
  } else if (typeof v === "bigint") {
9092
9159
  v = Number(v);
9093
9160
  }
9094
- out[constNames[i]] = v;
9095
9161
  } catch {
9096
9162
  const def = cfg.argDefaults?.[constNames[i]];
9097
9163
  if (def !== undefined)
9098
9164
  out[constNames[i]] = def;
9165
+ continue;
9166
+ }
9167
+ const constraints = cfg.argConstraints?.[constNames[i]];
9168
+ if (constraints !== undefined) {
9169
+ validateConstConstraints(constNames[i], constraints, v);
9099
9170
  }
9171
+ out[constNames[i]] = v;
9100
9172
  }
9101
9173
  if (cfg.argDefaults) {
9102
9174
  for (const [name, def] of Object.entries(cfg.argDefaults)) {
@@ -10996,4 +11068,4 @@ export {
10996
11068
  ArgumentValidationError
10997
11069
  };
10998
11070
 
10999
- //# debugId=B8E8A46EBC37A19064756E2164756E21
11071
+ //# debugId=606DBE277F7C8D1D64756E2164756E21