@nexface/tools 0.1.15-alpha.0 → 0.1.15-alpha.2

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 (88) 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.d.ts +1 -1
  19. package/dist/index.js +1 -2
  20. package/dist/internal-react.d.ts +1 -1
  21. package/dist/internal-react.js +3 -4
  22. package/dist/internal-types.js +0 -1
  23. package/dist/navigation.js +0 -1
  24. package/dist/operation-lock.js +36 -2
  25. package/dist/operation-runtime.js +41 -13
  26. package/dist/operation-surface.js +118 -41
  27. package/dist/operation-types.js +0 -1
  28. package/dist/operation-view.d.ts +1 -1
  29. package/dist/operation-view.js +120 -60
  30. package/dist/react.js +12 -17
  31. package/dist/registration.d.ts +3 -6
  32. package/dist/registration.js +8 -27
  33. package/dist/runtime.d.ts +19 -4
  34. package/dist/runtime.js +125 -47
  35. package/dist/shared/definition.js +2 -3
  36. package/dist/shared/errors.d.ts +1 -1
  37. package/dist/shared/errors.js +0 -1
  38. package/dist/shared/page-protocol.js +0 -1
  39. package/dist/shared/page-tools.js +0 -1
  40. package/dist/shared/runtime-controller.d.ts +1 -0
  41. package/dist/shared/runtime-controller.js +0 -1
  42. package/dist/shared/runtime-execution.js +0 -1
  43. package/dist/shared/schema.js +45 -19
  44. package/dist/styles.css +879 -109
  45. package/dist/tool-search.d.ts +11 -0
  46. package/dist/tool-search.js +117 -0
  47. package/dist/types.js +0 -1
  48. package/dist/webmcp.js +39 -13
  49. package/package.json +6 -2
  50. package/dist/browser/actions.js.map +0 -1
  51. package/dist/browser/controller.js.map +0 -1
  52. package/dist/browser/diagnostics.js.map +0 -1
  53. package/dist/browser/dom.js.map +0 -1
  54. package/dist/browser/feedback.js.map +0 -1
  55. package/dist/browser/focus.js.map +0 -1
  56. package/dist/browser/locator.js.map +0 -1
  57. package/dist/browser/prompt.generated.js.map +0 -1
  58. package/dist/browser/prompt.js.map +0 -1
  59. package/dist/browser/snapshot.js.map +0 -1
  60. package/dist/browser/toolset.js.map +0 -1
  61. package/dist/browser/types.js.map +0 -1
  62. package/dist/browser/worker-runner.js.map +0 -1
  63. package/dist/definition.js.map +0 -1
  64. package/dist/index.browser.js.map +0 -1
  65. package/dist/index.js.map +0 -1
  66. package/dist/internal-react.js.map +0 -1
  67. package/dist/internal-types.js.map +0 -1
  68. package/dist/navigation.js.map +0 -1
  69. package/dist/operation-lock.js.map +0 -1
  70. package/dist/operation-runtime.js.map +0 -1
  71. package/dist/operation-surface.js.map +0 -1
  72. package/dist/operation-types.js.map +0 -1
  73. package/dist/operation-view.js.map +0 -1
  74. package/dist/react.js.map +0 -1
  75. package/dist/registration.js.map +0 -1
  76. package/dist/runtime.js.map +0 -1
  77. package/dist/shared/definition.js.map +0 -1
  78. package/dist/shared/errors.js.map +0 -1
  79. package/dist/shared/page-protocol.js.map +0 -1
  80. package/dist/shared/page-tools.js.map +0 -1
  81. package/dist/shared/runtime-controller.js.map +0 -1
  82. package/dist/shared/runtime-execution.js.map +0 -1
  83. package/dist/shared/schema.js.map +0 -1
  84. package/dist/shared/tool-registry.d.ts +0 -6
  85. package/dist/shared/tool-registry.js +0 -10
  86. package/dist/shared/tool-registry.js.map +0 -1
  87. package/dist/types.js.map +0 -1
  88. package/dist/webmcp.js.map +0 -1
@@ -9,9 +9,6 @@ export declare function registerAgentTool<TInput, TResult>(definition: AgentTool
9
9
  execute: RegisteredAgentTool<TInput, TResult>["execute"];
10
10
  requiresConfirmation?: never;
11
11
  }): RegisteredAgentTool<TInput, TResult>;
12
- export declare function createAgentToolRegistry(): {
13
- register<TInput, TResult>(definition: AgentToolDefinition<TInput, TResult>, options: {
14
- execute: RegisteredAgentTool<TInput, TResult>["execute"];
15
- requiresConfirmation?: never;
16
- }): () => void;
17
- };
12
+ export declare function assertAgentToolRegistration(definition: AgentToolDefinition<any, any>, options: {
13
+ execute: unknown;
14
+ }): void;
@@ -1,35 +1,16 @@
1
- import { defineAgentTool } from "./definition.js";
2
- import { toolRegistrySymbol } from "./shared/tool-registry.js";
3
1
  import { assertAgentToolInputSchema } from "./shared/schema.js";
4
2
  export function registerAgentTool(definition, options) {
5
- if (!definition || typeof definition.name !== "string" || typeof options?.execute !== "function") {
3
+ assertAgentToolRegistration(definition, options);
4
+ assertAgentToolInputSchema(definition.inputSchema, `Tool "${definition.name}" was not registered: inputSchema`);
5
+ return Object.freeze({ definition, execute: options.execute });
6
+ }
7
+ export function assertAgentToolRegistration(definition, options) {
8
+ if (!definition ||
9
+ typeof definition.name !== "string" ||
10
+ typeof options?.execute !== "function") {
6
11
  throw new TypeError("registerAgentTool requires a definition and execute function.");
7
12
  }
8
13
  if ("requiresConfirmation" in options) {
9
14
  throw new TypeError("Registered Agent tools do not support requiresConfirmation.");
10
15
  }
11
- assertAgentToolInputSchema(definition.inputSchema, `Tool "${definition.name}".inputSchema`);
12
- return Object.freeze({ definition, execute: options.execute });
13
- }
14
- export function createAgentToolRegistry() {
15
- const tools = new Map();
16
- const registry = {
17
- register(definition, options) {
18
- const validated = registerAgentTool(definition, options);
19
- if (tools.has(definition.name))
20
- throw new TypeError(`Tool "${definition.name}" is already registered.`);
21
- const copied = defineAgentTool(validated.definition);
22
- const tool = Object.freeze({ definition: copied, execute: validated.execute });
23
- tools.set(copied.name, tool);
24
- return () => {
25
- if (tools.get(copied.name) === tool)
26
- tools.delete(copied.name);
27
- };
28
- },
29
- };
30
- Object.defineProperty(registry, toolRegistrySymbol, {
31
- value: Object.freeze({ getTools: () => [...tools.values()] }),
32
- });
33
- return Object.freeze(registry);
34
16
  }
35
- //# sourceMappingURL=registration.js.map
package/dist/runtime.d.ts CHANGED
@@ -2,18 +2,20 @@ import { type InternalExecutionOptions } from "./shared/runtime-execution.js";
2
2
  import type { PageActionFeedback } from "./browser/feedback.js";
3
3
  import { type TaskProgress } from "./shared/runtime-controller.js";
4
4
  export { AgentToolError } from "./shared/errors.js";
5
+ import { type RegisteredAgentTool } from "./registration.js";
5
6
  import { OperationTracker, type RuntimeActivitySnapshot } from "./operation-runtime.js";
6
7
  import type { AgentContextEntry, AgentContextInput, AgentContextRegistration, AgentToolDefinition, AgentToolExecutor } from "./types.js";
7
8
  import type { AgentToolExecutionEvent } from "./internal-types.js";
8
9
  export interface ToolRuntimeOptions {
9
10
  readonly pageAutomation?: boolean;
11
+ readonly routeSearch?: boolean;
10
12
  }
11
13
  export interface ToolRuntimeToolChangeEvent {
12
14
  readonly toolName: string;
13
- readonly change: "registered" | "unregistered";
15
+ readonly change: "registered" | "unregistered" | "visibility";
14
16
  }
15
17
  declare const CONTEXT_ERROR_CODES: readonly ["CONTEXT_DISPOSED", "CONTEXT_NAME_MISMATCH", "DUPLICATE_CONTEXT", "INVALID_CONTEXT"];
16
- type AgentContextErrorCode = typeof CONTEXT_ERROR_CODES[number];
18
+ type AgentContextErrorCode = (typeof CONTEXT_ERROR_CODES)[number];
17
19
  export declare function isToolRuntimeError(error: unknown): error is {
18
20
  readonly type: "tool_runtime_error";
19
21
  readonly domain: "tool" | "context";
@@ -51,6 +53,14 @@ export interface ToolRuntime {
51
53
  beginOperation(options?: {
52
54
  onCancel?: () => void;
53
55
  }): ToolOperation;
56
+ /**
57
+ * Register a business tool outside React and return an idempotent unregister function.
58
+ * @remarks Copies the definition. Unregistration invalidates unstarted calls; running calls use their execution signal.
59
+ */
60
+ register<TInput, TResult>(definition: AgentToolDefinition<TInput, TResult>, options: {
61
+ execute: RegisteredAgentTool<TInput, TResult>["execute"];
62
+ requiresConfirmation?: never;
63
+ }): () => void;
54
64
  getTools(): readonly RuntimeAgentTool[];
55
65
  getContexts(options?: {
56
66
  signal?: AbortSignal;
@@ -121,7 +131,7 @@ export interface InternalToolRuntime extends ToolRuntime, EventTarget {
121
131
  requestOperationCancel(id: string): void;
122
132
  resolveTarget(tool: RuntimeAgentTool, input: unknown): HTMLElement | undefined;
123
133
  setPageActionFeedback(listener: (event: AgentToolExecutionEvent, feedback: PageActionFeedback, signal?: AbortSignal) => void | Promise<void>): () => void;
124
- register<TInput, TResult>(definition: AgentToolDefinition<TInput, TResult>, execute: AgentToolExecutor<TInput, TResult>, options?: {
134
+ bindTool<TInput, TResult>(definition: AgentToolDefinition<TInput, TResult>, execute: AgentToolExecutor<TInput, TResult>, options?: {
125
135
  signal?: AbortSignal;
126
136
  getConfirmation?: () => AgentToolConfirmationConfig | undefined;
127
137
  resolveTarget?: (input: unknown) => HTMLElement | undefined;
@@ -157,7 +167,11 @@ export declare class ToolRuntimeImplementation extends EventTarget implements To
157
167
  constructor(options?: ToolRuntimeOptions);
158
168
  on(eventName: "toolchange", listener: (event: ToolRuntimeToolChangeEvent) => void): () => void;
159
169
  on(eventName: "toolexecution", listener: (event: AgentToolExecutionEvent) => void): () => void;
160
- register<TInput, TResult>(definition: AgentToolDefinition<TInput, TResult>, execute: AgentToolExecutor<TInput, TResult>, options?: {
170
+ register<TInput, TResult>(definition: AgentToolDefinition<TInput, TResult>, options: {
171
+ execute: RegisteredAgentTool<TInput, TResult>["execute"];
172
+ requiresConfirmation?: never;
173
+ }): () => void;
174
+ bindTool<TInput, TResult>(definition: AgentToolDefinition<TInput, TResult>, execute: AgentToolExecutor<TInput, TResult>, options?: {
161
175
  signal?: AbortSignal;
162
176
  getConfirmation?: () => AgentToolConfirmationConfig | undefined;
163
177
  resolveTarget?: (input: unknown) => HTMLElement | undefined;
@@ -170,6 +184,7 @@ export declare class ToolRuntimeImplementation extends EventTarget implements To
170
184
  getContexts(options?: {
171
185
  signal?: AbortSignal;
172
186
  }): Promise<readonly AgentContextEntry[]>;
187
+ getRegisteredTools(): readonly RuntimeAgentTool[];
173
188
  getWebMcpTools(): readonly RuntimeAgentTool[];
174
189
  isRegistered(name: string): boolean;
175
190
  getTools(): readonly RuntimeAgentTool[];
package/dist/runtime.js CHANGED
@@ -1,13 +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";
8
+ import { assertAgentToolRegistration } from "./registration.js";
7
9
  import { OperationTracker } from "./operation-runtime.js";
8
- import { isValidAgentContextName } from "./definition.js";
10
+ import { defineAgentTool, isValidAgentContextName } from "./definition.js";
9
11
  import { assertAgentToolInputSchema, validateAgentToolInput } from "./shared/schema.js";
10
- import { createBrowserToolset, } from "./browser/toolset.js";
12
+ import { createBrowserToolset } from "./browser/toolset.js";
11
13
  const CONTEXT_ERROR_CODES = [
12
14
  "CONTEXT_DISPOSED",
13
15
  "CONTEXT_NAME_MISMATCH",
@@ -20,9 +22,9 @@ export function isToolRuntimeError(error) {
20
22
  if (!error || typeof error !== "object")
21
23
  return false;
22
24
  const candidate = error;
23
- if (candidate.type !== "tool_runtime_error"
24
- || typeof candidate.message !== "string"
25
- || typeof candidate.code !== "string") {
25
+ if (candidate.type !== "tool_runtime_error" ||
26
+ typeof candidate.message !== "string" ||
27
+ typeof candidate.code !== "string") {
26
28
  return false;
27
29
  }
28
30
  if (candidate.domain === "tool") {
@@ -43,9 +45,7 @@ function assertContextName(name) {
43
45
  }
44
46
  }
45
47
  function normalizeContextValue(value, path = "value", seen = new WeakSet()) {
46
- if (value === null
47
- || typeof value === "string"
48
- || typeof value === "boolean") {
48
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
49
49
  return value;
50
50
  }
51
51
  if (typeof value === "number") {
@@ -82,8 +82,8 @@ function normalizeContextValue(value, path = "value", seen = new WeakSet()) {
82
82
  }
83
83
  function normalizeContext(context) {
84
84
  assertContextName(context.name);
85
- if (context.description !== undefined
86
- && (typeof context.description !== "string" || !context.description.trim())) {
85
+ if (context.description !== undefined &&
86
+ (typeof context.description !== "string" || !context.description.trim())) {
87
87
  throw new AgentContextError("INVALID_CONTEXT", "Context description must be a non-empty string when provided.");
88
88
  }
89
89
  return {
@@ -123,6 +123,8 @@ export function getInternalToolRuntime(runtime) {
123
123
  export class ToolRuntimeImplementation extends EventTarget {
124
124
  [toolRuntimeBrand] = true;
125
125
  #bindings = new Map();
126
+ #routeSearch;
127
+ #visibleNavigation = new Set();
126
128
  #contexts = new Map();
127
129
  #contextRevision = 0;
128
130
  #browserToolset;
@@ -136,16 +138,22 @@ export class ToolRuntimeImplementation extends EventTarget {
136
138
  beginInternalOperation(options = {}) {
137
139
  return this.#operations.begin(options);
138
140
  }
139
- endBridgeOperation(handle) { return this.#operations.disposeBridge(handle); }
141
+ endBridgeOperation(handle) {
142
+ return this.#operations.disposeBridge(handle);
143
+ }
140
144
  setTaskProgress = (handle, progress) => this.#operations.setTaskProgress(handle, progress);
141
145
  setOperationWaiting = (handle, waiting) => this.#operations.setWaitingForUser(handle, waiting);
142
146
  getActivitySnapshot = () => this.#operations.getSnapshot();
143
147
  subscribeActivity = (listener) => this.#operations.subscribe(listener);
144
- requestOperationCancel(id) { this.#operations.requestCancel(id); }
148
+ requestOperationCancel(id) {
149
+ this.#operations.requestCancel(id);
150
+ }
145
151
  setPageActionFeedback(listener) {
146
152
  this.#pageActionFeedback = listener;
147
- return () => { if (this.#pageActionFeedback === listener)
148
- this.#pageActionFeedback = undefined; };
153
+ return () => {
154
+ if (this.#pageActionFeedback === listener)
155
+ this.#pageActionFeedback = undefined;
156
+ };
149
157
  }
150
158
  #emitExecution(event) {
151
159
  this.#operations.observe(event);
@@ -153,10 +161,40 @@ export class ToolRuntimeImplementation extends EventTarget {
153
161
  }
154
162
  constructor(options = {}) {
155
163
  super();
156
- if (options.pageAutomation !== undefined &&
157
- typeof options.pageAutomation !== "boolean") {
164
+ if (options.pageAutomation !== undefined && typeof options.pageAutomation !== "boolean") {
158
165
  throw new AgentToolError("INVALID_INPUT", "pageAutomation must be a boolean.");
159
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
+ });
160
198
  this.#browserToolset = options.pageAutomation ? createBrowserToolset() : undefined;
161
199
  runtimeInternals.set(this, this);
162
200
  const controller = Object.freeze({
@@ -165,6 +203,7 @@ export class ToolRuntimeImplementation extends EventTarget {
165
203
  setTaskProgress: this.setTaskProgress,
166
204
  getOperationSnapshot: () => this.getActivitySnapshot().operation,
167
205
  subscribeOperation: this.subscribeActivity,
206
+ getRegisteredTools: () => this.getRegisteredTools(),
168
207
  });
169
208
  Object.defineProperty(this, runtimeControllerSymbol, { value: controller });
170
209
  }
@@ -186,8 +225,26 @@ export class ToolRuntimeImplementation extends EventTarget {
186
225
  this.removeEventListener(eventName, handleEvent);
187
226
  };
188
227
  }
189
- register(definition, execute, options = {}) {
190
- assertAgentToolInputSchema(definition.inputSchema, `Tool "${definition.name}".inputSchema`);
228
+ register(definition, options) {
229
+ assertAgentToolRegistration(definition, options);
230
+ const execute = options.execute;
231
+ if (definition.inputSchema?.type !== "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 });
240
+ }
241
+ return this.#bindTool(copied, (input, { signal }) => execute(input, { signal }));
242
+ }
243
+ bindTool(definition, execute, options = {}) {
244
+ assertAgentToolInputSchema(definition.inputSchema, `Tool "${definition.name}" was not registered: inputSchema`);
245
+ return this.#bindTool(definition, execute, options);
246
+ }
247
+ #bindTool(definition, execute, options = {}) {
191
248
  if (this.#bindings.has(definition.name)) {
192
249
  throw new AgentToolError("DUPLICATE_BINDING", `Tool "${definition.name}" already has an active binding.`);
193
250
  }
@@ -196,9 +253,7 @@ export class ToolRuntimeImplementation extends EventTarget {
196
253
  definition,
197
254
  get confirmation() {
198
255
  const confirmation = options.getConfirmation?.();
199
- return confirmation === undefined
200
- ? undefined
201
- : Object.freeze({ ...confirmation });
256
+ return confirmation === undefined ? undefined : Object.freeze({ ...confirmation });
202
257
  },
203
258
  lifecycleSignal: lifecycleController.signal,
204
259
  });
@@ -207,9 +262,7 @@ export class ToolRuntimeImplementation extends EventTarget {
207
262
  definition,
208
263
  runtimeTool,
209
264
  execute,
210
- ...(options.getConfirmation
211
- ? { getConfirmation: options.getConfirmation }
212
- : {}),
265
+ ...(options.getConfirmation ? { getConfirmation: options.getConfirmation } : {}),
213
266
  lifecycleController,
214
267
  };
215
268
  this.#bindings.set(definition.name, binding);
@@ -224,6 +277,7 @@ export class ToolRuntimeImplementation extends EventTarget {
224
277
  disposed = true;
225
278
  options.signal?.removeEventListener("abort", dispose);
226
279
  this.#bindings.delete(definition.name);
280
+ this.#visibleNavigation.delete(runtimeTool);
227
281
  lifecycleController.abort();
228
282
  this.dispatchEvent(new DetailEvent("toolchange", Object.freeze({
229
283
  toolName: definition.name,
@@ -337,21 +391,27 @@ export class ToolRuntimeImplementation extends EventTarget {
337
391
  revision: this.#contextRevision,
338
392
  }));
339
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
+ }
340
400
  getWebMcpTools() {
341
401
  return [...this.#bindings.values()]
342
402
  .map(({ runtimeTool }) => runtimeTool)
403
+ .filter((tool) => !this.#routeSearch ||
404
+ tool.definition.effect !== "navigate" ||
405
+ this.#visibleNavigation.has(tool))
343
406
  .sort((left, right) => compareStrings(left.definition.name, right.definition.name));
344
407
  }
345
408
  isRegistered(name) {
346
409
  return this.#bindings.has(name);
347
410
  }
348
411
  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));
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));
355
415
  }
356
416
  waitForTool(definition, options = {}) {
357
417
  const isTargetRegistered = () => this.#bindings.has(definition.name);
@@ -374,8 +434,7 @@ export class ToolRuntimeImplementation extends EventTarget {
374
434
  };
375
435
  const onToolChange = (event) => {
376
436
  const detail = event.detail;
377
- if (detail?.toolName !== definition.name
378
- || detail.change !== "registered")
437
+ if (detail?.toolName !== definition.name || detail.change !== "registered")
379
438
  return;
380
439
  if (isTargetRegistered())
381
440
  settle(resolve);
@@ -401,7 +460,11 @@ export class ToolRuntimeImplementation extends EventTarget {
401
460
  }
402
461
  execute(tool, input, options = {}) {
403
462
  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 } : {}) };
463
+ options = {
464
+ ...(options.signal ? { signal: options.signal } : {}),
465
+ ...(label ? { progressLabel: label } : {}),
466
+ ...(options[pageDecisionSymbol] ? { [pageDecisionSymbol]: true } : {}),
467
+ };
405
468
  const definition = tool.definition;
406
469
  const name = definition.name;
407
470
  const binding = this.#bindings.get(name);
@@ -417,8 +480,8 @@ export class ToolRuntimeImplementation extends EventTarget {
417
480
  if (!browserHandler) {
418
481
  return Promise.reject(new AgentToolError("UNKNOWN_TOOL", `Unknown tool: ${name}.`));
419
482
  }
420
- if (!browserToolset?.definitions.some((candidate) => candidate === definition)
421
- || this.#getBrowserRuntimeTool(definition) !== tool) {
483
+ if (!browserToolset?.definitions.some((candidate) => candidate === definition) ||
484
+ this.#getBrowserRuntimeTool(definition) !== tool) {
422
485
  return Promise.reject(new AgentToolError("CONTRACT_MISMATCH", `Tool "${name}" is registered with a different Definition.`));
423
486
  }
424
487
  return this.#enqueue((operationId) => this.#observeExecution(tool, input, options.signal, async (onFeedback, assertActive) => {
@@ -460,7 +523,9 @@ export class ToolRuntimeImplementation extends EventTarget {
460
523
  };
461
524
  // Reserve the tail before invoking executors or notifying synchronous listeners.
462
525
  let settleTail;
463
- const tail = new Promise((resolve) => { settleTail = resolve; });
526
+ const tail = new Promise((resolve) => {
527
+ settleTail = resolve;
528
+ });
464
529
  this.#executionTail = tail;
465
530
  const queuedExecution = previous ? previous.then(start) : start();
466
531
  let execution = queuedExecution;
@@ -492,9 +557,13 @@ export class ToolRuntimeImplementation extends EventTarget {
492
557
  const target = binding.resolveTarget?.(input);
493
558
  return target?.isConnected ? target : undefined;
494
559
  }
495
- 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")
496
563
  return undefined;
497
- return this.#browserToolset?.handlers.get(tool.definition.name)?.resolveTarget?.(input);
564
+ return this.#browserToolset?.handlers
565
+ .get(tool.definition.name)
566
+ ?.resolveTarget?.(input);
498
567
  }
499
568
  async #observeExecution(tool, input, signal, execute, progressLabel, operationId) {
500
569
  const running = {
@@ -511,7 +580,10 @@ export class ToolRuntimeImplementation extends EventTarget {
511
580
  const assertActive = () => {
512
581
  signal?.throwIfAborted();
513
582
  if (presentation && this.#pageActionFeedback !== presentation) {
514
- 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
+ });
515
587
  }
516
588
  };
517
589
  this.#emitExecution(running);
@@ -520,26 +592,33 @@ export class ToolRuntimeImplementation extends EventTarget {
520
592
  const result = await execute(async (feedback) => {
521
593
  assertActive();
522
594
  if (presentation)
523
- await measurePagePhase("presentation", async () => { await presentation(running, feedback, signal); });
595
+ await measurePagePhase("presentation", async () => {
596
+ await presentation(running, feedback, signal);
597
+ });
524
598
  assertActive();
525
599
  }, assertActive);
526
600
  signal?.throwIfAborted();
527
601
  this.#emitExecution({
528
- ...running, status: "success", finishedAt: Date.now(), result,
602
+ ...running,
603
+ status: "success",
604
+ finishedAt: Date.now(),
605
+ result,
529
606
  });
530
607
  return result;
531
608
  }
532
609
  catch (error) {
533
610
  this.#emitExecution({
534
- ...running, status: "error", cancelled: signal?.aborted === true,
535
- finishedAt: Date.now(), error,
611
+ ...running,
612
+ status: "error",
613
+ cancelled: signal?.aborted === true,
614
+ finishedAt: Date.now(),
615
+ error,
536
616
  });
537
617
  throw error;
538
618
  }
539
619
  }
540
620
  async #executeApplication(name, input, options, binding, operationId) {
541
- const id = globalThis.crypto?.randomUUID?.()
542
- ?? `${Date.now()}-${Math.random()}`;
621
+ const id = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
543
622
  const startedAt = Date.now();
544
623
  const running = {
545
624
  ...(operationId ? { operationId } : {}),
@@ -599,4 +678,3 @@ export class ToolRuntimeImplementation extends EventTarget {
599
678
  return runtimeTool;
600
679
  }
601
680
  }
602
- //# 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