@nexface/tools 0.1.13 → 0.1.14

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.
Files changed (83) hide show
  1. package/dist/browser/actions.js +34 -10
  2. package/dist/browser/controller.js +53 -74
  3. package/dist/browser/diagnostics.js +8 -3
  4. package/dist/browser/dom.js +12 -28
  5. package/dist/browser/feedback.js +6 -5
  6. package/dist/browser/focus.js +0 -1
  7. package/dist/browser/locator.js +3 -9
  8. package/dist/browser/prompt.generated.js +0 -1
  9. package/dist/browser/prompt.js +0 -1
  10. package/dist/browser/snapshot.js +10 -22
  11. package/dist/browser/toolset.js +42 -36
  12. package/dist/browser/types.d.ts +1 -1
  13. package/dist/browser/types.js +0 -1
  14. package/dist/browser/worker-runner.js +0 -1
  15. package/dist/definition.d.ts +1 -3
  16. package/dist/definition.js +2 -2
  17. package/dist/index.browser.js +0 -1
  18. package/dist/index.js +0 -1
  19. package/dist/internal-react.d.ts +1 -1
  20. package/dist/internal-react.js +3 -4
  21. package/dist/internal-types.js +0 -1
  22. package/dist/navigation.js +0 -1
  23. package/dist/operation-lock.js +36 -2
  24. package/dist/operation-runtime.js +41 -13
  25. package/dist/operation-surface.js +118 -41
  26. package/dist/operation-types.js +0 -1
  27. package/dist/operation-view.d.ts +1 -1
  28. package/dist/operation-view.js +120 -60
  29. package/dist/react.js +6 -9
  30. package/dist/registration.js +3 -2
  31. package/dist/runtime.d.ts +4 -2
  32. package/dist/runtime.js +103 -44
  33. package/dist/shared/definition.js +0 -1
  34. package/dist/shared/errors.d.ts +1 -1
  35. package/dist/shared/errors.js +0 -1
  36. package/dist/shared/page-protocol.js +0 -1
  37. package/dist/shared/page-tools.js +0 -1
  38. package/dist/shared/runtime-controller.d.ts +1 -0
  39. package/dist/shared/runtime-controller.js +0 -1
  40. package/dist/shared/runtime-execution.js +0 -1
  41. package/dist/shared/schema.js +45 -19
  42. package/dist/styles.css +879 -109
  43. package/dist/tool-search.d.ts +11 -0
  44. package/dist/tool-search.js +117 -0
  45. package/dist/types.js +0 -1
  46. package/dist/webmcp.js +38 -12
  47. package/package.json +6 -2
  48. package/dist/browser/actions.js.map +0 -1
  49. package/dist/browser/controller.js.map +0 -1
  50. package/dist/browser/diagnostics.js.map +0 -1
  51. package/dist/browser/dom.js.map +0 -1
  52. package/dist/browser/feedback.js.map +0 -1
  53. package/dist/browser/focus.js.map +0 -1
  54. package/dist/browser/locator.js.map +0 -1
  55. package/dist/browser/prompt.generated.js.map +0 -1
  56. package/dist/browser/prompt.js.map +0 -1
  57. package/dist/browser/snapshot.js.map +0 -1
  58. package/dist/browser/toolset.js.map +0 -1
  59. package/dist/browser/types.js.map +0 -1
  60. package/dist/browser/worker-runner.js.map +0 -1
  61. package/dist/definition.js.map +0 -1
  62. package/dist/index.browser.js.map +0 -1
  63. package/dist/index.js.map +0 -1
  64. package/dist/internal-react.js.map +0 -1
  65. package/dist/internal-types.js.map +0 -1
  66. package/dist/navigation.js.map +0 -1
  67. package/dist/operation-lock.js.map +0 -1
  68. package/dist/operation-runtime.js.map +0 -1
  69. package/dist/operation-surface.js.map +0 -1
  70. package/dist/operation-types.js.map +0 -1
  71. package/dist/operation-view.js.map +0 -1
  72. package/dist/react.js.map +0 -1
  73. package/dist/registration.js.map +0 -1
  74. package/dist/runtime.js.map +0 -1
  75. package/dist/shared/definition.js.map +0 -1
  76. package/dist/shared/errors.js.map +0 -1
  77. package/dist/shared/page-protocol.js.map +0 -1
  78. package/dist/shared/page-tools.js.map +0 -1
  79. package/dist/shared/runtime-controller.js.map +0 -1
  80. package/dist/shared/runtime-execution.js.map +0 -1
  81. package/dist/shared/schema.js.map +0 -1
  82. package/dist/types.js.map +0 -1
  83. package/dist/webmcp.js.map +0 -1
package/dist/runtime.js CHANGED
@@ -1,13 +1,14 @@
1
+ import { searchNavigationTools, searchToolDefinition } from "./tool-search.js";
1
2
  import { pageDecisionSymbol } from "./shared/runtime-execution.js";
2
3
  import { PageCommandError } from "./browser/locator.js";
3
4
  import { measurePagePhase } from "./browser/diagnostics.js";
4
- import { runtimeControllerSymbol } from "./shared/runtime-controller.js";
5
+ import { runtimeControllerSymbol, } from "./shared/runtime-controller.js";
5
6
  import { AgentToolError, TOOL_ERROR_CODES } from "./shared/errors.js";
6
7
  export { AgentToolError } from "./shared/errors.js";
7
8
  import { OperationTracker } from "./operation-runtime.js";
8
9
  import { isValidAgentContextName } from "./definition.js";
9
10
  import { assertAgentToolInputSchema, validateAgentToolInput } from "./shared/schema.js";
10
- import { createBrowserToolset, } from "./browser/toolset.js";
11
+ import { createBrowserToolset } from "./browser/toolset.js";
11
12
  const CONTEXT_ERROR_CODES = [
12
13
  "CONTEXT_DISPOSED",
13
14
  "CONTEXT_NAME_MISMATCH",
@@ -20,9 +21,9 @@ export function isToolRuntimeError(error) {
20
21
  if (!error || typeof error !== "object")
21
22
  return false;
22
23
  const candidate = error;
23
- if (candidate.type !== "tool_runtime_error"
24
- || typeof candidate.message !== "string"
25
- || typeof candidate.code !== "string") {
24
+ if (candidate.type !== "tool_runtime_error" ||
25
+ typeof candidate.message !== "string" ||
26
+ typeof candidate.code !== "string") {
26
27
  return false;
27
28
  }
28
29
  if (candidate.domain === "tool") {
@@ -43,9 +44,7 @@ function assertContextName(name) {
43
44
  }
44
45
  }
45
46
  function normalizeContextValue(value, path = "value", seen = new WeakSet()) {
46
- if (value === null
47
- || typeof value === "string"
48
- || typeof value === "boolean") {
47
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
49
48
  return value;
50
49
  }
51
50
  if (typeof value === "number") {
@@ -82,8 +81,8 @@ function normalizeContextValue(value, path = "value", seen = new WeakSet()) {
82
81
  }
83
82
  function normalizeContext(context) {
84
83
  assertContextName(context.name);
85
- if (context.description !== undefined
86
- && (typeof context.description !== "string" || !context.description.trim())) {
84
+ if (context.description !== undefined &&
85
+ (typeof context.description !== "string" || !context.description.trim())) {
87
86
  throw new AgentContextError("INVALID_CONTEXT", "Context description must be a non-empty string when provided.");
88
87
  }
89
88
  return {
@@ -123,6 +122,8 @@ export function getInternalToolRuntime(runtime) {
123
122
  export class ToolRuntimeImplementation extends EventTarget {
124
123
  [toolRuntimeBrand] = true;
125
124
  #bindings = new Map();
125
+ #routeSearch;
126
+ #visibleNavigation = new Set();
126
127
  #contexts = new Map();
127
128
  #contextRevision = 0;
128
129
  #browserToolset;
@@ -136,16 +137,22 @@ export class ToolRuntimeImplementation extends EventTarget {
136
137
  beginInternalOperation(options = {}) {
137
138
  return this.#operations.begin(options);
138
139
  }
139
- endBridgeOperation(handle) { return this.#operations.disposeBridge(handle); }
140
+ endBridgeOperation(handle) {
141
+ return this.#operations.disposeBridge(handle);
142
+ }
140
143
  setTaskProgress = (handle, progress) => this.#operations.setTaskProgress(handle, progress);
141
144
  setOperationWaiting = (handle, waiting) => this.#operations.setWaitingForUser(handle, waiting);
142
145
  getActivitySnapshot = () => this.#operations.getSnapshot();
143
146
  subscribeActivity = (listener) => this.#operations.subscribe(listener);
144
- requestOperationCancel(id) { this.#operations.requestCancel(id); }
147
+ requestOperationCancel(id) {
148
+ this.#operations.requestCancel(id);
149
+ }
145
150
  setPageActionFeedback(listener) {
146
151
  this.#pageActionFeedback = listener;
147
- return () => { if (this.#pageActionFeedback === listener)
148
- this.#pageActionFeedback = undefined; };
152
+ return () => {
153
+ if (this.#pageActionFeedback === listener)
154
+ this.#pageActionFeedback = undefined;
155
+ };
149
156
  }
150
157
  #emitExecution(event) {
151
158
  this.#operations.observe(event);
@@ -153,10 +160,40 @@ export class ToolRuntimeImplementation extends EventTarget {
153
160
  }
154
161
  constructor(options = {}) {
155
162
  super();
156
- if (options.pageAutomation !== undefined &&
157
- typeof options.pageAutomation !== "boolean") {
163
+ if (options.pageAutomation !== undefined && typeof options.pageAutomation !== "boolean") {
158
164
  throw new AgentToolError("INVALID_INPUT", "pageAutomation must be a boolean.");
159
165
  }
166
+ if (options.routeSearch !== undefined && typeof options.routeSearch !== "boolean") {
167
+ throw new AgentToolError("INVALID_INPUT", "routeSearch must be a boolean.");
168
+ }
169
+ this.#routeSearch = options.routeSearch ?? false;
170
+ if (this.#routeSearch)
171
+ this.register(searchToolDefinition, ({ query, queries }) => {
172
+ if (query !== undefined && queries !== undefined)
173
+ throw new AgentToolError("INVALID_INPUT", "Use either query or queries, not both.");
174
+ const searchQueries = queries === undefined ? (query === undefined ? undefined : [query]) : [...queries];
175
+ if (searchQueries?.some((phrase) => typeof phrase !== "string" || !phrase.trim()))
176
+ throw new AgentToolError("INVALID_INPUT", "Search queries must contain nonblank strings.");
177
+ const navigation = this.getRegisteredTools().filter(({ definition }) => definition.effect === "navigate");
178
+ const candidates = searchQueries === undefined
179
+ ? navigation
180
+ : searchNavigationTools(navigation, searchQueries.map((phrase) => phrase.trim()));
181
+ if (searchQueries !== undefined) {
182
+ const previous = this.#visibleNavigation;
183
+ this.#visibleNavigation = new Set(candidates);
184
+ for (const tool of new Set([...previous, ...candidates])) {
185
+ if (previous.has(tool) === this.#visibleNavigation.has(tool))
186
+ continue;
187
+ this.dispatchEvent(new DetailEvent("toolchange", Object.freeze({
188
+ toolName: tool.definition.name,
189
+ change: "visibility",
190
+ })));
191
+ }
192
+ }
193
+ return {
194
+ tools: candidates.map(({ definition: { name, description } }) => ({ name, description })),
195
+ };
196
+ });
160
197
  this.#browserToolset = options.pageAutomation ? createBrowserToolset() : undefined;
161
198
  runtimeInternals.set(this, this);
162
199
  const controller = Object.freeze({
@@ -165,6 +202,7 @@ export class ToolRuntimeImplementation extends EventTarget {
165
202
  setTaskProgress: this.setTaskProgress,
166
203
  getOperationSnapshot: () => this.getActivitySnapshot().operation,
167
204
  subscribeOperation: this.subscribeActivity,
205
+ getRegisteredTools: () => this.getRegisteredTools(),
168
206
  });
169
207
  Object.defineProperty(this, runtimeControllerSymbol, { value: controller });
170
208
  }
@@ -196,9 +234,7 @@ export class ToolRuntimeImplementation extends EventTarget {
196
234
  definition,
197
235
  get confirmation() {
198
236
  const confirmation = options.getConfirmation?.();
199
- return confirmation === undefined
200
- ? undefined
201
- : Object.freeze({ ...confirmation });
237
+ return confirmation === undefined ? undefined : Object.freeze({ ...confirmation });
202
238
  },
203
239
  lifecycleSignal: lifecycleController.signal,
204
240
  });
@@ -207,9 +243,7 @@ export class ToolRuntimeImplementation extends EventTarget {
207
243
  definition,
208
244
  runtimeTool,
209
245
  execute,
210
- ...(options.getConfirmation
211
- ? { getConfirmation: options.getConfirmation }
212
- : {}),
246
+ ...(options.getConfirmation ? { getConfirmation: options.getConfirmation } : {}),
213
247
  lifecycleController,
214
248
  };
215
249
  this.#bindings.set(definition.name, binding);
@@ -224,6 +258,7 @@ export class ToolRuntimeImplementation extends EventTarget {
224
258
  disposed = true;
225
259
  options.signal?.removeEventListener("abort", dispose);
226
260
  this.#bindings.delete(definition.name);
261
+ this.#visibleNavigation.delete(runtimeTool);
227
262
  lifecycleController.abort();
228
263
  this.dispatchEvent(new DetailEvent("toolchange", Object.freeze({
229
264
  toolName: definition.name,
@@ -337,21 +372,27 @@ export class ToolRuntimeImplementation extends EventTarget {
337
372
  revision: this.#contextRevision,
338
373
  }));
339
374
  }
375
+ getRegisteredTools() {
376
+ return [...this.#bindings.values()]
377
+ .map(({ runtimeTool }) => runtimeTool)
378
+ .filter(({ definition }) => !this.#routeSearch || definition !== searchToolDefinition)
379
+ .sort((left, right) => compareStrings(left.definition.name, right.definition.name));
380
+ }
340
381
  getWebMcpTools() {
341
382
  return [...this.#bindings.values()]
342
383
  .map(({ runtimeTool }) => runtimeTool)
384
+ .filter((tool) => !this.#routeSearch ||
385
+ tool.definition.effect !== "navigate" ||
386
+ this.#visibleNavigation.has(tool))
343
387
  .sort((left, right) => compareStrings(left.definition.name, right.definition.name));
344
388
  }
345
389
  isRegistered(name) {
346
390
  return this.#bindings.has(name);
347
391
  }
348
392
  getTools() {
349
- const applicationTools = [...this.#bindings.values()]
350
- .map(({ runtimeTool }) => runtimeTool);
351
- const browserTools = (this.#browserToolset?.definitions ?? [])
352
- .map((definition) => this.#getBrowserRuntimeTool(definition));
353
- return [...applicationTools, ...browserTools]
354
- .sort((left, right) => compareStrings(left.definition.name, right.definition.name));
393
+ const applicationTools = this.getWebMcpTools();
394
+ const browserTools = (this.#browserToolset?.definitions ?? []).map((definition) => this.#getBrowserRuntimeTool(definition));
395
+ return [...applicationTools, ...browserTools].sort((left, right) => compareStrings(left.definition.name, right.definition.name));
355
396
  }
356
397
  waitForTool(definition, options = {}) {
357
398
  const isTargetRegistered = () => this.#bindings.has(definition.name);
@@ -374,8 +415,7 @@ export class ToolRuntimeImplementation extends EventTarget {
374
415
  };
375
416
  const onToolChange = (event) => {
376
417
  const detail = event.detail;
377
- if (detail?.toolName !== definition.name
378
- || detail.change !== "registered")
418
+ if (detail?.toolName !== definition.name || detail.change !== "registered")
379
419
  return;
380
420
  if (isTargetRegistered())
381
421
  settle(resolve);
@@ -401,7 +441,11 @@ export class ToolRuntimeImplementation extends EventTarget {
401
441
  }
402
442
  execute(tool, input, options = {}) {
403
443
  const label = options.progressLabel?.trim().replace(/\s+/g, " ").slice(0, 48);
404
- options = { ...(options.signal ? { signal: options.signal } : {}), ...(label ? { progressLabel: label } : {}), ...(options[pageDecisionSymbol] ? { [pageDecisionSymbol]: true } : {}) };
444
+ options = {
445
+ ...(options.signal ? { signal: options.signal } : {}),
446
+ ...(label ? { progressLabel: label } : {}),
447
+ ...(options[pageDecisionSymbol] ? { [pageDecisionSymbol]: true } : {}),
448
+ };
405
449
  const definition = tool.definition;
406
450
  const name = definition.name;
407
451
  const binding = this.#bindings.get(name);
@@ -417,8 +461,8 @@ export class ToolRuntimeImplementation extends EventTarget {
417
461
  if (!browserHandler) {
418
462
  return Promise.reject(new AgentToolError("UNKNOWN_TOOL", `Unknown tool: ${name}.`));
419
463
  }
420
- if (!browserToolset?.definitions.some((candidate) => candidate === definition)
421
- || this.#getBrowserRuntimeTool(definition) !== tool) {
464
+ if (!browserToolset?.definitions.some((candidate) => candidate === definition) ||
465
+ this.#getBrowserRuntimeTool(definition) !== tool) {
422
466
  return Promise.reject(new AgentToolError("CONTRACT_MISMATCH", `Tool "${name}" is registered with a different Definition.`));
423
467
  }
424
468
  return this.#enqueue((operationId) => this.#observeExecution(tool, input, options.signal, async (onFeedback, assertActive) => {
@@ -460,7 +504,9 @@ export class ToolRuntimeImplementation extends EventTarget {
460
504
  };
461
505
  // Reserve the tail before invoking executors or notifying synchronous listeners.
462
506
  let settleTail;
463
- const tail = new Promise((resolve) => { settleTail = resolve; });
507
+ const tail = new Promise((resolve) => {
508
+ settleTail = resolve;
509
+ });
464
510
  this.#executionTail = tail;
465
511
  const queuedExecution = previous ? previous.then(start) : start();
466
512
  let execution = queuedExecution;
@@ -492,9 +538,13 @@ export class ToolRuntimeImplementation extends EventTarget {
492
538
  const target = binding.resolveTarget?.(input);
493
539
  return target?.isConnected ? target : undefined;
494
540
  }
495
- if (this.#browserRuntimeTools.get(tool.definition) !== tool || !input || typeof input !== "object")
541
+ if (this.#browserRuntimeTools.get(tool.definition) !== tool ||
542
+ !input ||
543
+ typeof input !== "object")
496
544
  return undefined;
497
- return this.#browserToolset?.handlers.get(tool.definition.name)?.resolveTarget?.(input);
545
+ return this.#browserToolset?.handlers
546
+ .get(tool.definition.name)
547
+ ?.resolveTarget?.(input);
498
548
  }
499
549
  async #observeExecution(tool, input, signal, execute, progressLabel, operationId) {
500
550
  const running = {
@@ -511,7 +561,10 @@ export class ToolRuntimeImplementation extends EventTarget {
511
561
  const assertActive = () => {
512
562
  signal?.throwIfAborted();
513
563
  if (presentation && this.#pageActionFeedback !== presentation) {
514
- throw new PageCommandError({ code: "EXECUTION_CANCELLED", message: "Page action presentation was detached." });
564
+ throw new PageCommandError({
565
+ code: "EXECUTION_CANCELLED",
566
+ message: "Page action presentation was detached.",
567
+ });
515
568
  }
516
569
  };
517
570
  this.#emitExecution(running);
@@ -520,26 +573,33 @@ export class ToolRuntimeImplementation extends EventTarget {
520
573
  const result = await execute(async (feedback) => {
521
574
  assertActive();
522
575
  if (presentation)
523
- await measurePagePhase("presentation", async () => { await presentation(running, feedback, signal); });
576
+ await measurePagePhase("presentation", async () => {
577
+ await presentation(running, feedback, signal);
578
+ });
524
579
  assertActive();
525
580
  }, assertActive);
526
581
  signal?.throwIfAborted();
527
582
  this.#emitExecution({
528
- ...running, status: "success", finishedAt: Date.now(), result,
583
+ ...running,
584
+ status: "success",
585
+ finishedAt: Date.now(),
586
+ result,
529
587
  });
530
588
  return result;
531
589
  }
532
590
  catch (error) {
533
591
  this.#emitExecution({
534
- ...running, status: "error", cancelled: signal?.aborted === true,
535
- finishedAt: Date.now(), error,
592
+ ...running,
593
+ status: "error",
594
+ cancelled: signal?.aborted === true,
595
+ finishedAt: Date.now(),
596
+ error,
536
597
  });
537
598
  throw error;
538
599
  }
539
600
  }
540
601
  async #executeApplication(name, input, options, binding, operationId) {
541
- const id = globalThis.crypto?.randomUUID?.()
542
- ?? `${Date.now()}-${Math.random()}`;
602
+ const id = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
543
603
  const startedAt = Date.now();
544
604
  const running = {
545
605
  ...(operationId ? { operationId } : {}),
@@ -599,4 +659,3 @@ export class ToolRuntimeImplementation extends EventTarget {
599
659
  return runtimeTool;
600
660
  }
601
661
  }
602
- //# sourceMappingURL=runtime.js.map
@@ -30,4 +30,3 @@ function cloneAndFreeze(value) {
30
30
  }
31
31
  return value;
32
32
  }
33
- //# sourceMappingURL=definition.js.map
@@ -1,5 +1,5 @@
1
1
  export declare const TOOL_ERROR_CODES: readonly ["EXECUTION_OUTCOME_UNKNOWN", "ACTION_IN_FLIGHT", "ACTION_NOT_HANDLED", "ACTION_TARGET_UNAVAILABLE", "BROWSER_EXECUTION_FAILED", "BROWSER_SNAPSHOT_REQUIRED", "BROWSER_TOOLS_UNAVAILABLE", "CONTRACT_MISMATCH", "DUPLICATE_BINDING", "INVALID_INPUT", "INVALID_TOOL_RUNTIME", "OPERATION_BUSY", "TOOL_CANCELLED", "TOOL_CONFIRMATION_INVALIDATED", "TOOL_CONFIRMATION_REJECTED", "TOOL_ERROR", "TOOL_REGISTRATION_TIMEOUT", "TOOL_SKIPPED", "TOOL_UNAVAILABLE", "UNKNOWN_TOOL"];
2
- type AgentToolErrorCode = typeof TOOL_ERROR_CODES[number];
2
+ type AgentToolErrorCode = (typeof TOOL_ERROR_CODES)[number];
3
3
  export declare class AgentToolError extends Error {
4
4
  readonly code: AgentToolErrorCode;
5
5
  readonly details?: unknown | undefined;
@@ -33,4 +33,3 @@ export class AgentToolError extends Error {
33
33
  this.name = "ToolRuntimeError";
34
34
  }
35
35
  }
36
- //# sourceMappingURL=errors.js.map
@@ -1,3 +1,2 @@
1
1
  // Generated from shared/page-protocol.ts. Do not edit manually.
2
2
  export {};
3
- //# sourceMappingURL=page-protocol.js.map
@@ -40,4 +40,3 @@ export const applyActionTool = createAgentToolDefinition({
40
40
  additionalProperties: false,
41
41
  },
42
42
  });
43
- //# sourceMappingURL=page-tools.js.map
@@ -12,6 +12,7 @@ interface OperationSnapshot {
12
12
  readonly taskProgress?: TaskProgress;
13
13
  }
14
14
  export interface RuntimeController {
15
+ getRegisteredTools(): ReturnType<ToolRuntime["getTools"]>;
15
16
  beginInternalOperation(options?: {
16
17
  signal?: AbortSignal;
17
18
  onCancel?: () => void;
@@ -8,4 +8,3 @@ export function getRuntimeController(runtime) {
8
8
  }
9
9
  return controller;
10
10
  }
11
- //# sourceMappingURL=runtime-controller.js.map
@@ -1,3 +1,2 @@
1
1
  // Generated from shared/runtime-execution.ts. Do not edit manually.
2
2
  export const pageDecisionSymbol = Symbol.for("@nexface/tools/page-decision");
3
- //# sourceMappingURL=runtime-execution.js.map
@@ -3,8 +3,17 @@ const types = new Set(["object", "array", "string", "number", "integer", "boolea
3
3
  const counts = ["minLength", "maxLength", "minItems", "maxItems"];
4
4
  const bounds = ["minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum"];
5
5
  const keywords = new Set([
6
- "type", "description", "properties", "required", "items", "enum", "additionalProperties",
7
- ...counts, ...bounds, "pattern", "uniqueItems",
6
+ "type",
7
+ "description",
8
+ "properties",
9
+ "required",
10
+ "items",
11
+ "enum",
12
+ "additionalProperties",
13
+ ...counts,
14
+ ...bounds,
15
+ "pattern",
16
+ "uniqueItems",
8
17
  ]);
9
18
  const checkedSchemas = new WeakSet();
10
19
  const patterns = new WeakMap();
@@ -24,7 +33,9 @@ function assertJson(value, path, ancestors = new Set()) {
24
33
  invalid(path, "must be JSON-compatible.");
25
34
  if (ancestors.has(value))
26
35
  invalid(path, "must not contain circular references.");
27
- if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
36
+ if (!Array.isArray(value) &&
37
+ Object.getPrototypeOf(value) !== Object.prototype &&
38
+ Object.getPrototypeOf(value) !== null) {
28
39
  invalid(path, "must be a plain JSON object.");
29
40
  }
30
41
  if (Object.getOwnPropertySymbols(value).length)
@@ -85,7 +96,8 @@ function assertSchema(value, path) {
85
96
  invalid(`${path}.${key}`, "must be a non-negative integer.");
86
97
  }
87
98
  for (const key of bounds) {
88
- if (value[key] !== undefined && (typeof value[key] !== "number" || !Number.isFinite(value[key])))
99
+ if (value[key] !== undefined &&
100
+ (typeof value[key] !== "number" || !Number.isFinite(value[key])))
89
101
  invalid(`${path}.${key}`, "must be a finite number.");
90
102
  }
91
103
  if (value.pattern !== undefined) {
@@ -95,7 +107,8 @@ function assertSchema(value, path) {
95
107
  }
96
108
  if (value.enum !== undefined && (!Array.isArray(value.enum) || value.enum.length === 0))
97
109
  invalid(`${path}.enum`, "must be a non-empty array.");
98
- if (Array.isArray(value.enum) && value.enum.some((item, index, entries) => entries.slice(0, index).some((other) => jsonEqual(item, other))))
110
+ if (Array.isArray(value.enum) &&
111
+ value.enum.some((item, index, entries) => entries.slice(0, index).some((other) => jsonEqual(item, other))))
99
112
  invalid(`${path}.enum`, "must contain unique values.");
100
113
  if (value.properties !== undefined) {
101
114
  if (value.type !== "object" || !isRecord(value.properties))
@@ -104,7 +117,10 @@ function assertSchema(value, path) {
104
117
  assertSchema(property, `${path}.properties.${name}`);
105
118
  }
106
119
  if (value.required !== undefined) {
107
- if (value.type !== "object" || !Array.isArray(value.required) || value.required.some((name) => typeof name !== "string") || new Set(value.required).size !== value.required.length)
120
+ if (value.type !== "object" ||
121
+ !Array.isArray(value.required) ||
122
+ value.required.some((name) => typeof name !== "string") ||
123
+ new Set(value.required).size !== value.required.length)
108
124
  invalid(`${path}.required`, "must contain unique property names.");
109
125
  const properties = value.properties;
110
126
  if (value.required.some((name) => !properties || !Object.hasOwn(properties, name)))
@@ -118,7 +134,7 @@ function assertSchema(value, path) {
118
134
  }
119
135
  export function assertAgentToolInputSchema(value, path = "inputSchema") {
120
136
  if (!isRecord(value) || value.type !== "object")
121
- invalid(path, 'root type must be object.');
137
+ invalid(path, "root type must be object.");
122
138
  if (checkedSchemas.has(value))
123
139
  return;
124
140
  const frozen = assertJson(value, path);
@@ -130,21 +146,29 @@ function jsonEqual(left, right) {
130
146
  if (left === right)
131
147
  return true;
132
148
  if (Array.isArray(left) && Array.isArray(right))
133
- return left.length === right.length && left.every((item, index) => jsonEqual(item, right[index]));
149
+ return (left.length === right.length && left.every((item, index) => jsonEqual(item, right[index])));
134
150
  if (!isRecord(left) || !isRecord(right))
135
151
  return false;
136
152
  const keys = Object.keys(left);
137
- return keys.length === Object.keys(right).length && keys.every((key) => Object.hasOwn(right, key) && jsonEqual(left[key], right[key]));
153
+ return (keys.length === Object.keys(right).length &&
154
+ keys.every((key) => Object.hasOwn(right, key) && jsonEqual(left[key], right[key])));
138
155
  }
139
156
  function typeMatches(schema, value) {
140
157
  switch (schema.type) {
141
- case undefined: return true;
142
- case "null": return value === null;
143
- case "array": return Array.isArray(value);
144
- case "object": return isRecord(value);
145
- case "integer": return typeof value === "number" && Number.isInteger(value);
146
- case "number": return typeof value === "number" && Number.isFinite(value);
147
- default: return typeof value === schema.type;
158
+ case undefined:
159
+ return true;
160
+ case "null":
161
+ return value === null;
162
+ case "array":
163
+ return Array.isArray(value);
164
+ case "object":
165
+ return isRecord(value);
166
+ case "integer":
167
+ return typeof value === "number" && Number.isInteger(value);
168
+ case "number":
169
+ return typeof value === "number" && Number.isFinite(value);
170
+ default:
171
+ return typeof value === schema.type;
148
172
  }
149
173
  }
150
174
  export function validateAgentToolInput(schema, value, path = "input") {
@@ -177,7 +201,8 @@ export function validateAgentToolInput(schema, value, path = "input") {
177
201
  errors.push(`${path} must have at least ${schema.minItems} items.`);
178
202
  if (schema.maxItems !== undefined && value.length > schema.maxItems)
179
203
  errors.push(`${path} must have at most ${schema.maxItems} items.`);
180
- if (schema.uniqueItems && value.some((item, index) => value.slice(0, index).some((other) => jsonEqual(item, other))))
204
+ if (schema.uniqueItems &&
205
+ value.some((item, index) => value.slice(0, index).some((other) => jsonEqual(item, other))))
181
206
  errors.push(`${path} must contain unique items.`);
182
207
  if (schema.items)
183
208
  value.forEach((item, index) => errors.push(...validateAgentToolInput(schema.items, item, `${path}[${index}]`)));
@@ -188,7 +213,9 @@ export function validateAgentToolInput(schema, value, path = "input") {
188
213
  errors.push(`${path}.${key} is required.`);
189
214
  }
190
215
  for (const [key, item] of Object.entries(value)) {
191
- const property = schema.properties && Object.hasOwn(schema.properties, key) ? schema.properties[key] : undefined;
216
+ const property = schema.properties && Object.hasOwn(schema.properties, key)
217
+ ? schema.properties[key]
218
+ : undefined;
192
219
  if (property)
193
220
  errors.push(...validateAgentToolInput(property, item, `${path}.${key}`));
194
221
  else if (schema.additionalProperties === false)
@@ -197,4 +224,3 @@ export function validateAgentToolInput(schema, value, path = "input") {
197
224
  }
198
225
  return errors;
199
226
  }
200
- //# sourceMappingURL=schema.js.map