@nexface/tools 0.1.15-alpha.1 → 0.1.15-alpha.3

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 +9 -14
  30. package/dist/registration.js +4 -3
  31. package/dist/runtime.d.ts +4 -2
  32. package/dist/runtime.js +112 -47
  33. package/dist/shared/definition.js +2 -3
  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 +39 -13
  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.d.ts CHANGED
@@ -8,13 +8,14 @@ import type { AgentContextEntry, AgentContextInput, AgentContextRegistration, Ag
8
8
  import type { AgentToolExecutionEvent } from "./internal-types.js";
9
9
  export interface ToolRuntimeOptions {
10
10
  readonly pageAutomation?: boolean;
11
+ readonly routeSearch?: boolean;
11
12
  }
12
13
  export interface ToolRuntimeToolChangeEvent {
13
14
  readonly toolName: string;
14
- readonly change: "registered" | "unregistered";
15
+ readonly change: "registered" | "unregistered" | "visibility";
15
16
  }
16
17
  declare const CONTEXT_ERROR_CODES: readonly ["CONTEXT_DISPOSED", "CONTEXT_NAME_MISMATCH", "DUPLICATE_CONTEXT", "INVALID_CONTEXT"];
17
- type AgentContextErrorCode = typeof CONTEXT_ERROR_CODES[number];
18
+ type AgentContextErrorCode = (typeof CONTEXT_ERROR_CODES)[number];
18
19
  export declare function isToolRuntimeError(error: unknown): error is {
19
20
  readonly type: "tool_runtime_error";
20
21
  readonly domain: "tool" | "context";
@@ -183,6 +184,7 @@ export declare class ToolRuntimeImplementation extends EventTarget implements To
183
184
  getContexts(options?: {
184
185
  signal?: AbortSignal;
185
186
  }): Promise<readonly AgentContextEntry[]>;
187
+ getRegisteredTools(): readonly RuntimeAgentTool[];
186
188
  getWebMcpTools(): readonly RuntimeAgentTool[];
187
189
  isRegistered(name: string): boolean;
188
190
  getTools(): readonly RuntimeAgentTool[];
package/dist/runtime.js CHANGED
@@ -1,14 +1,15 @@
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 { assertAgentToolRegistration } from "./registration.js";
8
9
  import { OperationTracker } from "./operation-runtime.js";
9
10
  import { defineAgentTool, isValidAgentContextName } from "./definition.js";
10
11
  import { assertAgentToolInputSchema, validateAgentToolInput } from "./shared/schema.js";
11
- import { createBrowserToolset, } from "./browser/toolset.js";
12
+ import { createBrowserToolset } from "./browser/toolset.js";
12
13
  const CONTEXT_ERROR_CODES = [
13
14
  "CONTEXT_DISPOSED",
14
15
  "CONTEXT_NAME_MISMATCH",
@@ -21,9 +22,9 @@ export function isToolRuntimeError(error) {
21
22
  if (!error || typeof error !== "object")
22
23
  return false;
23
24
  const candidate = error;
24
- if (candidate.type !== "tool_runtime_error"
25
- || typeof candidate.message !== "string"
26
- || typeof candidate.code !== "string") {
25
+ if (candidate.type !== "tool_runtime_error" ||
26
+ typeof candidate.message !== "string" ||
27
+ typeof candidate.code !== "string") {
27
28
  return false;
28
29
  }
29
30
  if (candidate.domain === "tool") {
@@ -44,9 +45,7 @@ function assertContextName(name) {
44
45
  }
45
46
  }
46
47
  function normalizeContextValue(value, path = "value", seen = new WeakSet()) {
47
- if (value === null
48
- || typeof value === "string"
49
- || typeof value === "boolean") {
48
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
50
49
  return value;
51
50
  }
52
51
  if (typeof value === "number") {
@@ -83,8 +82,8 @@ function normalizeContextValue(value, path = "value", seen = new WeakSet()) {
83
82
  }
84
83
  function normalizeContext(context) {
85
84
  assertContextName(context.name);
86
- if (context.description !== undefined
87
- && (typeof context.description !== "string" || !context.description.trim())) {
85
+ if (context.description !== undefined &&
86
+ (typeof context.description !== "string" || !context.description.trim())) {
88
87
  throw new AgentContextError("INVALID_CONTEXT", "Context description must be a non-empty string when provided.");
89
88
  }
90
89
  return {
@@ -124,6 +123,8 @@ export function getInternalToolRuntime(runtime) {
124
123
  export class ToolRuntimeImplementation extends EventTarget {
125
124
  [toolRuntimeBrand] = true;
126
125
  #bindings = new Map();
126
+ #routeSearch;
127
+ #visibleNavigation = new Set();
127
128
  #contexts = new Map();
128
129
  #contextRevision = 0;
129
130
  #browserToolset;
@@ -137,16 +138,22 @@ export class ToolRuntimeImplementation extends EventTarget {
137
138
  beginInternalOperation(options = {}) {
138
139
  return this.#operations.begin(options);
139
140
  }
140
- endBridgeOperation(handle) { return this.#operations.disposeBridge(handle); }
141
+ endBridgeOperation(handle) {
142
+ return this.#operations.disposeBridge(handle);
143
+ }
141
144
  setTaskProgress = (handle, progress) => this.#operations.setTaskProgress(handle, progress);
142
145
  setOperationWaiting = (handle, waiting) => this.#operations.setWaitingForUser(handle, waiting);
143
146
  getActivitySnapshot = () => this.#operations.getSnapshot();
144
147
  subscribeActivity = (listener) => this.#operations.subscribe(listener);
145
- requestOperationCancel(id) { this.#operations.requestCancel(id); }
148
+ requestOperationCancel(id) {
149
+ this.#operations.requestCancel(id);
150
+ }
146
151
  setPageActionFeedback(listener) {
147
152
  this.#pageActionFeedback = listener;
148
- return () => { if (this.#pageActionFeedback === listener)
149
- this.#pageActionFeedback = undefined; };
153
+ return () => {
154
+ if (this.#pageActionFeedback === listener)
155
+ this.#pageActionFeedback = undefined;
156
+ };
150
157
  }
151
158
  #emitExecution(event) {
152
159
  this.#operations.observe(event);
@@ -154,10 +161,40 @@ export class ToolRuntimeImplementation extends EventTarget {
154
161
  }
155
162
  constructor(options = {}) {
156
163
  super();
157
- if (options.pageAutomation !== undefined &&
158
- typeof options.pageAutomation !== "boolean") {
164
+ if (options.pageAutomation !== undefined && typeof options.pageAutomation !== "boolean") {
159
165
  throw new AgentToolError("INVALID_INPUT", "pageAutomation must be a boolean.");
160
166
  }
167
+ if (options.routeSearch !== undefined && typeof options.routeSearch !== "boolean") {
168
+ throw new AgentToolError("INVALID_INPUT", "routeSearch must be a boolean.");
169
+ }
170
+ this.#routeSearch = options.routeSearch ?? false;
171
+ if (this.#routeSearch)
172
+ this.bindTool(searchToolDefinition, ({ query, queries }) => {
173
+ if (query !== undefined && queries !== undefined)
174
+ throw new AgentToolError("INVALID_INPUT", "Use either query or queries, not both.");
175
+ const searchQueries = queries === undefined ? (query === undefined ? undefined : [query]) : [...queries];
176
+ if (searchQueries?.some((phrase) => typeof phrase !== "string" || !phrase.trim()))
177
+ throw new AgentToolError("INVALID_INPUT", "Search queries must contain nonblank strings.");
178
+ const navigation = this.getRegisteredTools().filter(({ definition }) => definition.effect === "navigate");
179
+ const candidates = searchQueries === undefined
180
+ ? navigation
181
+ : searchNavigationTools(navigation, searchQueries.map((phrase) => phrase.trim()));
182
+ if (searchQueries !== undefined) {
183
+ const previous = this.#visibleNavigation;
184
+ this.#visibleNavigation = new Set(candidates);
185
+ for (const tool of new Set([...previous, ...candidates])) {
186
+ if (previous.has(tool) === this.#visibleNavigation.has(tool))
187
+ continue;
188
+ this.dispatchEvent(new DetailEvent("toolchange", Object.freeze({
189
+ toolName: tool.definition.name,
190
+ change: "visibility",
191
+ })));
192
+ }
193
+ }
194
+ return {
195
+ tools: candidates.map(({ definition: { name, description } }) => ({ name, description })),
196
+ };
197
+ });
161
198
  this.#browserToolset = options.pageAutomation ? createBrowserToolset() : undefined;
162
199
  runtimeInternals.set(this, this);
163
200
  const controller = Object.freeze({
@@ -166,6 +203,7 @@ export class ToolRuntimeImplementation extends EventTarget {
166
203
  setTaskProgress: this.setTaskProgress,
167
204
  getOperationSnapshot: () => this.getActivitySnapshot().operation,
168
205
  subscribeOperation: this.subscribeActivity,
206
+ getRegisteredTools: () => this.getRegisteredTools(),
169
207
  });
170
208
  Object.defineProperty(this, runtimeControllerSymbol, { value: controller });
171
209
  }
@@ -191,13 +229,19 @@ export class ToolRuntimeImplementation extends EventTarget {
191
229
  assertAgentToolRegistration(definition, options);
192
230
  const execute = options.execute;
193
231
  if (definition.inputSchema?.type !== "object") {
194
- throw new TypeError(`Tool "${definition.name}".inputSchema root type must be object.`);
232
+ throw new TypeError(`Tool "${definition.name}" was not registered: inputSchema root type must be object.`);
233
+ }
234
+ let copied;
235
+ try {
236
+ copied = defineAgentTool(definition);
237
+ }
238
+ catch (cause) {
239
+ throw new TypeError(`Tool "${definition.name}" was not registered: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
195
240
  }
196
- const copied = defineAgentTool(definition);
197
241
  return this.#bindTool(copied, (input, { signal }) => execute(input, { signal }));
198
242
  }
199
243
  bindTool(definition, execute, options = {}) {
200
- assertAgentToolInputSchema(definition.inputSchema, `Tool "${definition.name}".inputSchema`);
244
+ assertAgentToolInputSchema(definition.inputSchema, `Tool "${definition.name}" was not registered: inputSchema`);
201
245
  return this.#bindTool(definition, execute, options);
202
246
  }
203
247
  #bindTool(definition, execute, options = {}) {
@@ -209,9 +253,7 @@ export class ToolRuntimeImplementation extends EventTarget {
209
253
  definition,
210
254
  get confirmation() {
211
255
  const confirmation = options.getConfirmation?.();
212
- return confirmation === undefined
213
- ? undefined
214
- : Object.freeze({ ...confirmation });
256
+ return confirmation === undefined ? undefined : Object.freeze({ ...confirmation });
215
257
  },
216
258
  lifecycleSignal: lifecycleController.signal,
217
259
  });
@@ -220,9 +262,7 @@ export class ToolRuntimeImplementation extends EventTarget {
220
262
  definition,
221
263
  runtimeTool,
222
264
  execute,
223
- ...(options.getConfirmation
224
- ? { getConfirmation: options.getConfirmation }
225
- : {}),
265
+ ...(options.getConfirmation ? { getConfirmation: options.getConfirmation } : {}),
226
266
  lifecycleController,
227
267
  };
228
268
  this.#bindings.set(definition.name, binding);
@@ -237,6 +277,7 @@ export class ToolRuntimeImplementation extends EventTarget {
237
277
  disposed = true;
238
278
  options.signal?.removeEventListener("abort", dispose);
239
279
  this.#bindings.delete(definition.name);
280
+ this.#visibleNavigation.delete(runtimeTool);
240
281
  lifecycleController.abort();
241
282
  this.dispatchEvent(new DetailEvent("toolchange", Object.freeze({
242
283
  toolName: definition.name,
@@ -350,21 +391,27 @@ export class ToolRuntimeImplementation extends EventTarget {
350
391
  revision: this.#contextRevision,
351
392
  }));
352
393
  }
394
+ getRegisteredTools() {
395
+ return [...this.#bindings.values()]
396
+ .map(({ runtimeTool }) => runtimeTool)
397
+ .filter(({ definition }) => !this.#routeSearch || definition !== searchToolDefinition)
398
+ .sort((left, right) => compareStrings(left.definition.name, right.definition.name));
399
+ }
353
400
  getWebMcpTools() {
354
401
  return [...this.#bindings.values()]
355
402
  .map(({ runtimeTool }) => runtimeTool)
403
+ .filter((tool) => !this.#routeSearch ||
404
+ tool.definition.effect !== "navigate" ||
405
+ this.#visibleNavigation.has(tool))
356
406
  .sort((left, right) => compareStrings(left.definition.name, right.definition.name));
357
407
  }
358
408
  isRegistered(name) {
359
409
  return this.#bindings.has(name);
360
410
  }
361
411
  getTools() {
362
- const applicationTools = [...this.#bindings.values()]
363
- .map(({ runtimeTool }) => runtimeTool);
364
- const browserTools = (this.#browserToolset?.definitions ?? [])
365
- .map((definition) => this.#getBrowserRuntimeTool(definition));
366
- return [...applicationTools, ...browserTools]
367
- .sort((left, right) => compareStrings(left.definition.name, right.definition.name));
412
+ const applicationTools = this.getWebMcpTools();
413
+ const browserTools = (this.#browserToolset?.definitions ?? []).map((definition) => this.#getBrowserRuntimeTool(definition));
414
+ return [...applicationTools, ...browserTools].sort((left, right) => compareStrings(left.definition.name, right.definition.name));
368
415
  }
369
416
  waitForTool(definition, options = {}) {
370
417
  const isTargetRegistered = () => this.#bindings.has(definition.name);
@@ -387,8 +434,7 @@ export class ToolRuntimeImplementation extends EventTarget {
387
434
  };
388
435
  const onToolChange = (event) => {
389
436
  const detail = event.detail;
390
- if (detail?.toolName !== definition.name
391
- || detail.change !== "registered")
437
+ if (detail?.toolName !== definition.name || detail.change !== "registered")
392
438
  return;
393
439
  if (isTargetRegistered())
394
440
  settle(resolve);
@@ -414,7 +460,11 @@ export class ToolRuntimeImplementation extends EventTarget {
414
460
  }
415
461
  execute(tool, input, options = {}) {
416
462
  const label = options.progressLabel?.trim().replace(/\s+/g, " ").slice(0, 48);
417
- options = { ...(options.signal ? { signal: options.signal } : {}), ...(label ? { progressLabel: label } : {}), ...(options[pageDecisionSymbol] ? { [pageDecisionSymbol]: true } : {}) };
463
+ options = {
464
+ ...(options.signal ? { signal: options.signal } : {}),
465
+ ...(label ? { progressLabel: label } : {}),
466
+ ...(options[pageDecisionSymbol] ? { [pageDecisionSymbol]: true } : {}),
467
+ };
418
468
  const definition = tool.definition;
419
469
  const name = definition.name;
420
470
  const binding = this.#bindings.get(name);
@@ -430,8 +480,8 @@ export class ToolRuntimeImplementation extends EventTarget {
430
480
  if (!browserHandler) {
431
481
  return Promise.reject(new AgentToolError("UNKNOWN_TOOL", `Unknown tool: ${name}.`));
432
482
  }
433
- if (!browserToolset?.definitions.some((candidate) => candidate === definition)
434
- || this.#getBrowserRuntimeTool(definition) !== tool) {
483
+ if (!browserToolset?.definitions.some((candidate) => candidate === definition) ||
484
+ this.#getBrowserRuntimeTool(definition) !== tool) {
435
485
  return Promise.reject(new AgentToolError("CONTRACT_MISMATCH", `Tool "${name}" is registered with a different Definition.`));
436
486
  }
437
487
  return this.#enqueue((operationId) => this.#observeExecution(tool, input, options.signal, async (onFeedback, assertActive) => {
@@ -473,7 +523,9 @@ export class ToolRuntimeImplementation extends EventTarget {
473
523
  };
474
524
  // Reserve the tail before invoking executors or notifying synchronous listeners.
475
525
  let settleTail;
476
- const tail = new Promise((resolve) => { settleTail = resolve; });
526
+ const tail = new Promise((resolve) => {
527
+ settleTail = resolve;
528
+ });
477
529
  this.#executionTail = tail;
478
530
  const queuedExecution = previous ? previous.then(start) : start();
479
531
  let execution = queuedExecution;
@@ -505,9 +557,13 @@ export class ToolRuntimeImplementation extends EventTarget {
505
557
  const target = binding.resolveTarget?.(input);
506
558
  return target?.isConnected ? target : undefined;
507
559
  }
508
- if (this.#browserRuntimeTools.get(tool.definition) !== tool || !input || typeof input !== "object")
560
+ if (this.#browserRuntimeTools.get(tool.definition) !== tool ||
561
+ !input ||
562
+ typeof input !== "object")
509
563
  return undefined;
510
- return this.#browserToolset?.handlers.get(tool.definition.name)?.resolveTarget?.(input);
564
+ return this.#browserToolset?.handlers
565
+ .get(tool.definition.name)
566
+ ?.resolveTarget?.(input);
511
567
  }
512
568
  async #observeExecution(tool, input, signal, execute, progressLabel, operationId) {
513
569
  const running = {
@@ -524,7 +580,10 @@ export class ToolRuntimeImplementation extends EventTarget {
524
580
  const assertActive = () => {
525
581
  signal?.throwIfAborted();
526
582
  if (presentation && this.#pageActionFeedback !== presentation) {
527
- throw new PageCommandError({ code: "EXECUTION_CANCELLED", message: "Page action presentation was detached." });
583
+ throw new PageCommandError({
584
+ code: "EXECUTION_CANCELLED",
585
+ message: "Page action presentation was detached.",
586
+ });
528
587
  }
529
588
  };
530
589
  this.#emitExecution(running);
@@ -533,26 +592,33 @@ export class ToolRuntimeImplementation extends EventTarget {
533
592
  const result = await execute(async (feedback) => {
534
593
  assertActive();
535
594
  if (presentation)
536
- await measurePagePhase("presentation", async () => { await presentation(running, feedback, signal); });
595
+ await measurePagePhase("presentation", async () => {
596
+ await presentation(running, feedback, signal);
597
+ });
537
598
  assertActive();
538
599
  }, assertActive);
539
600
  signal?.throwIfAborted();
540
601
  this.#emitExecution({
541
- ...running, status: "success", finishedAt: Date.now(), result,
602
+ ...running,
603
+ status: "success",
604
+ finishedAt: Date.now(),
605
+ result,
542
606
  });
543
607
  return result;
544
608
  }
545
609
  catch (error) {
546
610
  this.#emitExecution({
547
- ...running, status: "error", cancelled: signal?.aborted === true,
548
- finishedAt: Date.now(), error,
611
+ ...running,
612
+ status: "error",
613
+ cancelled: signal?.aborted === true,
614
+ finishedAt: Date.now(),
615
+ error,
549
616
  });
550
617
  throw error;
551
618
  }
552
619
  }
553
620
  async #executeApplication(name, input, options, binding, operationId) {
554
- const id = globalThis.crypto?.randomUUID?.()
555
- ?? `${Date.now()}-${Math.random()}`;
621
+ const id = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
556
622
  const startedAt = Date.now();
557
623
  const running = {
558
624
  ...(operationId ? { operationId } : {}),
@@ -612,4 +678,3 @@ export class ToolRuntimeImplementation extends EventTarget {
612
678
  return runtimeTool;
613
679
  }
614
680
  }
615
- //# sourceMappingURL=runtime.js.map
@@ -2,14 +2,14 @@
2
2
  import { assertAgentToolInputSchema } from "./schema.js";
3
3
  export function createAgentToolDefinition(metadata) {
4
4
  if (!metadata.description.trim())
5
- throw new Error("Tool description is required.");
5
+ throw new Error(`Tool "${metadata.name}": Tool description is required.`);
6
6
  if (metadata.inputSchema?.type !== "object") {
7
7
  throw new TypeError(`Tool inputSchema root type must be object. Tool "${metadata.name}".inputSchema.type is invalid.`);
8
8
  }
9
9
  assertAgentToolInputSchema(metadata.inputSchema, `Tool "${metadata.name}".inputSchema`);
10
10
  const effect = metadata.effect ?? "action";
11
11
  if (!["read", "action", "navigate"].includes(effect)) {
12
- throw new Error(`Invalid agent tool effect: ${String(effect)}.`);
12
+ throw new Error(`Tool "${metadata.name}": Invalid agent tool effect: ${String(effect)}.`);
13
13
  }
14
14
  return Object.freeze({
15
15
  name: metadata.name,
@@ -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