@query-farm/vgi 0.10.0 → 0.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@query-farm/vgi",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "TypeScript framework for extending DuckDB with user-defined functions via the Vector Gateway Interface (VGI) over Arrow IPC.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Query Farm LLC (https://query.farm)",
@@ -15,7 +15,11 @@
15
15
 
16
16
  import { type VgiSchema, schema, type VgiField, field, type VgiBatch, type VgiDataType, nullType, isNull } from "../arrow/index.js";
17
17
  import type { Arguments } from "../arguments/arguments.js";
18
- import type { ArgumentSpec } from "../arguments/argument-spec.js";
18
+ import {
19
+ constraintSpecFields,
20
+ type ArgumentSpec,
21
+ type ArgumentConstraints,
22
+ } from "../arguments/argument-spec.js";
19
23
  import type {
20
24
  FunctionMeta,
21
25
  VgiFunction,
@@ -123,6 +127,13 @@ export interface AggregateFunctionConfig<TArgs = Record<string, any>, TState = a
123
127
  onBind?: (params: AggregateBindParams<TArgs>) => VgiDataType | Promise<VgiDataType>;
124
128
  /** Optional per-arg default values (positional only here). */
125
129
  argDefaults?: Record<string, any>;
130
+ /**
131
+ * Per-argument discovery constraints (choices / ge / le / gt / lt / pattern),
132
+ * keyed by argument name. Surfaced via `vgi_function_arguments()` and enforced
133
+ * at aggregate_bind for const params: a value violating a declared constraint
134
+ * fails the bind with an ArgumentValidationError.
135
+ */
136
+ argConstraints?: Record<string, ArgumentConstraints>;
126
137
 
127
138
  initialState: (params: AggregateBindParams<TArgs>) => TState;
128
139
  /**
@@ -342,6 +353,7 @@ export function defineAggregate<TArgs = Record<string, any>, TState = any>(
342
353
  isAnyType,
343
354
  isVarargs: varargsSet.has(name),
344
355
  isConst,
356
+ ...constraintSpecFields(config.argConstraints?.[name]),
345
357
  });
346
358
  }
347
359
  }
@@ -29,7 +29,12 @@ import type {
29
29
  StreamHandlers,
30
30
  FunctionExample,
31
31
  } from "./types.js";
32
- import type { ArgumentSpec } from "../arguments/argument-spec.js";
32
+ import {
33
+ constraintSpecFields,
34
+ validateConstConstraints,
35
+ type ArgumentSpec,
36
+ type ArgumentConstraints,
37
+ } from "../arguments/argument-spec.js";
33
38
  import { batchToScalarDict, batchToSecretDict, projectSchema, safeNumber } from "../util/arrow/index.js";
34
39
  import {
35
40
  buildJoinKeysLookup,
@@ -166,6 +171,13 @@ export interface TableFunctionConfig<
166
171
  argDocs?: Record<string, string>;
167
172
  /** Argument defaults */
168
173
  argDefaults?: Record<string, any>;
174
+ /**
175
+ * Per-argument discovery constraints (choices / ge / le / gt / lt / pattern),
176
+ * keyed by argument name. Surfaced via `vgi_function_arguments()` for agent
177
+ * discovery AND enforced at bind: a value violating a declared constraint
178
+ * fails the bind with an ArgumentValidationError.
179
+ */
180
+ argConstraints?: Record<string, ArgumentConstraints>;
169
181
  /** Names of args that accept variable number of arguments */
170
182
  varargs?: string[];
171
183
  /** Bind: return output schema. May be async — handlers `await` the result. */
@@ -273,6 +285,7 @@ export function defineTableFunction<
273
285
  isAnyType: isAny,
274
286
  isVarargs: varargsSet.has(name),
275
287
  doc: config.argDocs?.[name],
288
+ ...constraintSpecFields(config.argConstraints?.[name]),
276
289
  });
277
290
  }
278
291
  }
@@ -318,6 +331,9 @@ export function defineTableFunction<
318
331
  }
319
332
  // Arrow Int64 values come through as BigInt — coerce to number
320
333
  if (typeof val === "bigint") val = safeNumber(val);
334
+ // Enforce declared constraints at bind (table args are all bind-time).
335
+ const constraints = config.argConstraints?.[spec.name];
336
+ if (constraints) validateConstConstraints(spec.name, constraints, val);
321
337
  args[spec.name] = val;
322
338
  }
323
339
  return args as TArgs;
@@ -32,6 +32,7 @@ import {
32
32
  type AggregateBindParams,
33
33
  } from "../../functions/aggregate.js";
34
34
  import { Arguments } from "../../arguments/arguments.js";
35
+ import { validateConstConstraints } from "../../arguments/argument-spec.js";
35
36
  import {
36
37
  REQUEST_PARAMS_SCHEMA,
37
38
  RESULT_BINARY_SCHEMA,
@@ -310,8 +311,9 @@ function extractArgMap(
310
311
  }
311
312
  }
312
313
  for (let i = 0; i < constNames.length; i++) {
314
+ let v: any;
313
315
  try {
314
- let v = args.get(i);
316
+ v = args.get(i);
315
317
  // Decode DECIMAL scalars (DuckDB serializes 0.5-style literals as
316
318
  // DECIMAL(2,1), which Arrow stores as the unscaled integer — a raw
317
319
  // BigInt here). Scale back to float using the declared scale.
@@ -323,14 +325,22 @@ function extractArgMap(
323
325
  } else if (typeof v === "bigint") {
324
326
  v = Number(v);
325
327
  }
326
- out[constNames[i]] = v;
327
328
  } catch {
328
329
  // args.get throws when the arg isn't set — fall back to the declared
329
330
  // default so aggregates called without an explicit const value still
330
331
  // see it in update/finalize.
331
332
  const def = cfg.argDefaults?.[constNames[i]];
332
333
  if (def !== undefined) out[constNames[i]] = def;
334
+ continue;
333
335
  }
336
+ // Enforce declared constraints on the supplied value. This sits OUTSIDE the
337
+ // try above so a constraint violation propagates as a bind error rather than
338
+ // being swallowed and silently replaced by the default.
339
+ const constraints = cfg.argConstraints?.[constNames[i]];
340
+ if (constraints !== undefined) {
341
+ validateConstConstraints(constNames[i], constraints, v);
342
+ }
343
+ out[constNames[i]] = v;
334
344
  }
335
345
  // Non-const args aren't in the wire Arguments, but users may still want
336
346
  // defaults surfaced for `params.args` — apply them here.