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

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 (87) hide show
  1. package/dist/browser/actions.js +34 -10
  2. package/dist/browser/controller.js +91 -76
  3. package/dist/browser/diagnostics.js +8 -3
  4. package/dist/browser/dom.js +23 -30
  5. package/dist/browser/feedback.js +6 -5
  6. package/dist/browser/focus.d.ts +0 -1
  7. package/dist/browser/focus.js +1 -13
  8. package/dist/browser/locator.js +3 -9
  9. package/dist/browser/prompt.d.ts +1 -1
  10. package/dist/browser/prompt.generated.d.ts +1 -1
  11. package/dist/browser/prompt.generated.js +9 -4
  12. package/dist/browser/prompt.js +0 -1
  13. package/dist/browser/snapshot.js +199 -117
  14. package/dist/browser/toolset.js +42 -36
  15. package/dist/browser/types.d.ts +1 -1
  16. package/dist/browser/types.js +0 -1
  17. package/dist/browser/worker-runner.js +0 -1
  18. package/dist/definition.d.ts +1 -3
  19. package/dist/definition.js +2 -2
  20. package/dist/index.browser.js +0 -1
  21. package/dist/index.js +0 -1
  22. package/dist/internal-react.d.ts +1 -1
  23. package/dist/internal-react.js +3 -4
  24. package/dist/internal-types.js +0 -1
  25. package/dist/navigation.js +0 -1
  26. package/dist/operation-lock.d.ts +1 -1
  27. package/dist/operation-lock.js +36 -19
  28. package/dist/operation-runtime.js +41 -13
  29. package/dist/operation-surface.js +118 -41
  30. package/dist/operation-types.js +0 -1
  31. package/dist/operation-view.d.ts +1 -1
  32. package/dist/operation-view.js +232 -82
  33. package/dist/react.js +9 -14
  34. package/dist/registration.js +4 -3
  35. package/dist/runtime.d.ts +4 -2
  36. package/dist/runtime.js +114 -52
  37. package/dist/shared/definition.js +2 -3
  38. package/dist/shared/errors.d.ts +1 -1
  39. package/dist/shared/errors.js +0 -1
  40. package/dist/shared/page-protocol.js +0 -1
  41. package/dist/shared/page-tools.js +2 -3
  42. package/dist/shared/runtime-controller.d.ts +1 -0
  43. package/dist/shared/runtime-controller.js +0 -1
  44. package/dist/shared/runtime-execution.js +0 -1
  45. package/dist/shared/schema.js +45 -19
  46. package/dist/styles.css +882 -109
  47. package/dist/tool-search.d.ts +11 -0
  48. package/dist/tool-search.js +117 -0
  49. package/dist/types.js +0 -1
  50. package/dist/webmcp.js +39 -13
  51. package/package.json +8 -4
  52. package/dist/browser/actions.js.map +0 -1
  53. package/dist/browser/controller.js.map +0 -1
  54. package/dist/browser/diagnostics.js.map +0 -1
  55. package/dist/browser/dom.js.map +0 -1
  56. package/dist/browser/feedback.js.map +0 -1
  57. package/dist/browser/focus.js.map +0 -1
  58. package/dist/browser/locator.js.map +0 -1
  59. package/dist/browser/prompt.generated.js.map +0 -1
  60. package/dist/browser/prompt.js.map +0 -1
  61. package/dist/browser/snapshot.js.map +0 -1
  62. package/dist/browser/toolset.js.map +0 -1
  63. package/dist/browser/types.js.map +0 -1
  64. package/dist/browser/worker-runner.js.map +0 -1
  65. package/dist/definition.js.map +0 -1
  66. package/dist/index.browser.js.map +0 -1
  67. package/dist/index.js.map +0 -1
  68. package/dist/internal-react.js.map +0 -1
  69. package/dist/internal-types.js.map +0 -1
  70. package/dist/navigation.js.map +0 -1
  71. package/dist/operation-lock.js.map +0 -1
  72. package/dist/operation-runtime.js.map +0 -1
  73. package/dist/operation-surface.js.map +0 -1
  74. package/dist/operation-types.js.map +0 -1
  75. package/dist/operation-view.js.map +0 -1
  76. package/dist/react.js.map +0 -1
  77. package/dist/registration.js.map +0 -1
  78. package/dist/runtime.js.map +0 -1
  79. package/dist/shared/definition.js.map +0 -1
  80. package/dist/shared/errors.js.map +0 -1
  81. package/dist/shared/page-protocol.js.map +0 -1
  82. package/dist/shared/page-tools.js.map +0 -1
  83. package/dist/shared/runtime-controller.js.map +0 -1
  84. package/dist/shared/runtime-execution.js.map +0 -1
  85. package/dist/shared/schema.js.map +0 -1
  86. package/dist/types.js.map +0 -1
  87. package/dist/webmcp.js.map +0 -1
@@ -1,14 +1,33 @@
1
1
  import { CursorIcon as Cursor } from "@phosphor-icons/react/Cursor";
2
2
  import { SparkleIcon as Sparkle } from "@phosphor-icons/react/Sparkle";
3
3
  import * as React from "react";
4
- import { useCallback, useLayoutEffect, useEffect, useRef, useState } from "react";
4
+ import { useCallback, useLayoutEffect, useEffect, useRef, useState, } from "react";
5
5
  import { createPortal } from "react-dom";
6
6
  import { PageCommandError } from "./browser/locator.js";
7
7
  import { lockOperationSurface } from "./operation-lock.js";
8
- const center = (rect) => ({ left: rect.left + rect.width / 2, top: rect.top + rect.height / 2 });
8
+ const intersect = (a, b) => {
9
+ if (!a)
10
+ return undefined;
11
+ const left = Math.max(a.left, b.left);
12
+ const top = Math.max(a.top, b.top);
13
+ const right = Math.min(a.left + a.width, b.left + b.width);
14
+ const bottom = Math.min(a.top + a.height, b.top + b.height);
15
+ return right > left && bottom > top
16
+ ? { left, top, width: right - left, height: bottom - top }
17
+ : undefined;
18
+ };
19
+ const sameRect = (a, b) => a === b ||
20
+ Boolean(a && b && a.left === b.left && a.top === b.top && a.width === b.width && a.height === b.height);
21
+ const center = (rect) => ({
22
+ left: rect.left + rect.width / 2,
23
+ top: rect.top + rect.height / 2,
24
+ });
9
25
  const distance = (a, b) => Math.hypot(a.left - b.left, a.top - b.top);
10
- const interrupted = () => new PageCommandError({ code: "EXECUTION_CANCELLED", message: "Page action presentation was interrupted." });
11
- function presentPointer(pointer, target, presentation) {
26
+ const interrupted = () => new PageCommandError({
27
+ code: "EXECUTION_CANCELLED",
28
+ message: "Page action presentation was interrupted.",
29
+ });
30
+ function presentPointer(pointer, target, resolvePosition, presentation) {
12
31
  let finished = false;
13
32
  const finish = (error) => {
14
33
  if (finished)
@@ -19,45 +38,112 @@ function presentPointer(pointer, target, presentation) {
19
38
  presentation.signal?.removeEventListener("abort", onAbort);
20
39
  presentation.finish(error);
21
40
  };
22
- const reached = () => pointer.isConnected && target.isConnected && distance(pointer.getBoundingClientRect(), center(target.getBoundingClientRect())) < 2;
41
+ const reached = () => {
42
+ const position = resolvePosition();
43
+ return Boolean(position &&
44
+ pointer.isConnected &&
45
+ target.isConnected &&
46
+ distance(pointer.getBoundingClientRect(), position) < 2);
47
+ };
23
48
  const onTransition = (event) => {
24
49
  if (event.target === pointer && event.propertyName === "transform" && reached())
25
50
  finish();
26
51
  };
27
52
  const onAbort = () => finish(interrupted());
28
- const timer = setTimeout(() => reached() ? finish() : finish(new PageCommandError({
29
- code: "ACTION_TIMEOUT", message: "Page action pointer did not reach its target in time.",
30
- })), 750);
53
+ const timer = setTimeout(() => reached()
54
+ ? finish()
55
+ : finish(new PageCommandError({
56
+ code: "ACTION_TIMEOUT",
57
+ message: "Page action pointer did not reach its target in time.",
58
+ })), 750);
31
59
  pointer.addEventListener("transitionend", onTransition);
32
60
  presentation.signal?.addEventListener("abort", onAbort, { once: true });
33
- queueMicrotask(() => { if (presentation.signal?.aborted)
34
- onAbort();
35
- else if (reached())
36
- finish(); });
61
+ queueMicrotask(() => {
62
+ if (presentation.signal?.aborted)
63
+ onAbort();
64
+ else if (reached())
65
+ finish();
66
+ });
37
67
  return () => finish(interrupted());
38
68
  }
39
- function FeedbackLabel({ feedback }) {
40
- return React.createElement("span", { className: "agent-operation__pointer-label", "data-browser-tool": feedback.centered ? "true" : undefined, "data-operation-effect": feedback.effect, title: feedback.label },
41
- feedback.effect === "processing" ? React.createElement("span", { className: "agent-operation__pointer-processing" }) : null,
42
- feedback.effect === "read" ? React.createElement("span", { className: "agent-operation__pointer-read-scan" },
43
- React.createElement("i", null),
44
- React.createElement("i", null),
45
- React.createElement("i", null),
46
- React.createElement("i", null),
47
- React.createElement("i", null)) : null,
48
- feedback.effect === "navigate" ? React.createElement("span", { className: "agent-operation__pointer-navigation-trail" }) : null,
49
- React.createElement("span", { className: "agent-operation__pointer-label-text" }, feedback.label));
69
+ function FeedbackLabel({ feedback, position, durationMs = 0, }) {
70
+ const label = useRef(null);
71
+ const measured = useRef(undefined);
72
+ const [placement, setPlacement] = useState();
73
+ const width = window.innerWidth;
74
+ const height = window.innerHeight;
75
+ useLayoutEffect(() => {
76
+ const element = label.current;
77
+ if (!element)
78
+ return;
79
+ const key = [feedback.label, feedback.effect, feedback.centered, width, height].join(";");
80
+ const resized = measured.current?.key !== key;
81
+ if (resized) {
82
+ const labelWidth = element.offsetWidth;
83
+ const labelHeight = element.offsetHeight;
84
+ measured.current = {
85
+ key,
86
+ width: labelWidth,
87
+ height: labelHeight,
88
+ left: element.offsetLeft - (feedback.centered ? labelWidth / 2 : 0),
89
+ top: element.offsetTop - (feedback.centered ? labelHeight / 2 : 0),
90
+ };
91
+ }
92
+ const size = measured.current;
93
+ const left = position.left + size.left;
94
+ const top = position.top + size.top;
95
+ const next = {
96
+ left: position.left + Math.max(12, Math.min(left, width - 12 - size.width)) - left,
97
+ top: position.top + Math.max(12, Math.min(top, height - 12 - size.height)) - top,
98
+ durationMs: resized ? 0 : durationMs,
99
+ };
100
+ setPlacement((current) => current?.left === next.left &&
101
+ current.top === next.top &&
102
+ (!resized || current.durationMs === next.durationMs)
103
+ ? current
104
+ : next);
105
+ }, [
106
+ feedback.label,
107
+ feedback.effect,
108
+ feedback.centered,
109
+ position.left,
110
+ position.top,
111
+ width,
112
+ height,
113
+ durationMs,
114
+ ]);
115
+ const current = placement ?? { ...position, durationMs: 0 };
116
+ return createPortal(React.createElement("div", { "aria-hidden": true, "data-nexface-ignore": true, className: "agent-operation__floating-label", style: {
117
+ "--agent-operation-pointer-x": `${current.left}px`,
118
+ "--agent-operation-pointer-y": `${current.top}px`,
119
+ "--agent-operation-pointer-duration": `${current.durationMs}ms`,
120
+ } },
121
+ React.createElement("span", { ref: label, style: { maxWidth: Math.max(0, Math.min(300, width * 0.48, width - 24)) }, className: "agent-operation__pointer-label", "data-browser-tool": feedback.centered ? "true" : undefined, "data-operation-effect": feedback.effect, title: feedback.label },
122
+ feedback.effect === "processing" ? (React.createElement("span", { className: "agent-operation__pointer-processing" })) : null,
123
+ feedback.effect === "read" ? (React.createElement("span", { className: "agent-operation__pointer-read-scan" },
124
+ React.createElement("i", null),
125
+ React.createElement("i", null),
126
+ React.createElement("i", null),
127
+ React.createElement("i", null),
128
+ React.createElement("i", null))) : null,
129
+ feedback.effect === "navigate" ? (React.createElement("span", { className: "agent-operation__pointer-navigation-trail" })) : null,
130
+ React.createElement("span", { className: "agent-operation__pointer-label-text" }, feedback.label))), document.body);
50
131
  }
51
- function FeedbackIndicator({ feedback, position }) {
132
+ function FeedbackIndicator({ feedback, position, }) {
52
133
  const [lastPosition, setLastPosition] = useState(position ?? feedback.position);
53
- useLayoutEffect(() => { if (position)
54
- setLastPosition(position); }, [position?.left, position?.top]);
134
+ useLayoutEffect(() => {
135
+ if (position)
136
+ setLastPosition(position);
137
+ }, [position?.left, position?.top]);
55
138
  const current = position ?? lastPosition;
56
- return current ? React.createElement("div", { "aria-hidden": true, className: "agent-operation__pointer-effect", "data-active": "true", "data-operation-effect": feedback.effect, style: { "--agent-operation-pointer-duration": "0ms", "--agent-operation-pointer-x": `${current.left}px`,
57
- "--agent-operation-pointer-y": `${current.top}px` } },
58
- React.createElement(FeedbackLabel, { feedback: feedback })) : null;
139
+ return current ? (React.createElement("div", { "aria-hidden": true, className: "agent-operation__pointer-effect", "data-active": "true", "data-operation-effect": feedback.effect, style: {
140
+ "--agent-operation-pointer-duration": "0ms",
141
+ "--agent-operation-pointer-x": `${current.left}px`,
142
+ "--agent-operation-pointer-y": `${current.top}px`,
143
+ } },
144
+ React.createElement(FeedbackLabel, { feedback: feedback, position: current }))) : null;
59
145
  }
60
- function AgentPointer({ active, feedback, targetPosition, surfaceCenter }) {
146
+ function AgentPointer({ active, feedback, targetPosition, surfaceCenter, resolvePosition, }) {
61
147
  const pointer = useRef(null);
62
148
  const [motion, setMotion] = useState();
63
149
  const action = feedback?.effect === "action" && (!feedback.requiresTarget || Boolean(targetPosition));
@@ -75,8 +161,11 @@ function AgentPointer({ active, feedback, targetPosition, surfaceCenter }) {
75
161
  return;
76
162
  }
77
163
  if (!motion) {
78
- setMotion({ position: feedback?.persistentCursor && surfaceCenter ? surfaceCenter : targetPosition,
79
- durationMs: 0, persistent: Boolean(feedback?.persistentCursor) });
164
+ setMotion({
165
+ position: feedback?.persistentCursor && surfaceCenter ? surfaceCenter : targetPosition,
166
+ durationMs: 0,
167
+ persistent: Boolean(feedback?.persistentCursor),
168
+ });
80
169
  return;
81
170
  }
82
171
  if (distance(motion.position, targetPosition) < 1) {
@@ -85,9 +174,14 @@ function AgentPointer({ active, feedback, targetPosition, surfaceCenter }) {
85
174
  return;
86
175
  }
87
176
  const from = pointer.current?.getBoundingClientRect() ?? motion.position;
88
- const durationMs = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ? 0
177
+ const durationMs = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches
178
+ ? 0
89
179
  : Math.round(Math.min(360, Math.max(180, 180 + distance(from, targetPosition) * 0.18)));
90
- setMotion({ position: targetPosition, durationMs, persistent: motion.persistent || Boolean(feedback?.persistentCursor) });
180
+ setMotion({
181
+ position: targetPosition,
182
+ durationMs,
183
+ persistent: motion.persistent || Boolean(feedback?.persistentCursor),
184
+ });
91
185
  }, [active, action, feedback?.id, targetPosition?.left, targetPosition?.top, motion]);
92
186
  const show = Boolean(active && motion && (motion.persistent || action));
93
187
  useLayoutEffect(() => {
@@ -98,20 +192,31 @@ function AgentPointer({ active, feedback, targetPosition, surfaceCenter }) {
98
192
  return;
99
193
  }
100
194
  if (show && pointer.current)
101
- return presentPointer(pointer.current, feedback.target, feedback.presentation);
102
- }, [active, show, feedback?.presentation, feedback?.target, Boolean(targetPosition)]);
103
- return show && motion ? React.createElement("div", { "aria-hidden": true, ref: pointer, className: "agent-operation__pointer-effect", "data-active": action, "data-operation-effect": action ? "action" : undefined, style: { "--agent-operation-pointer-duration": `${motion.durationMs}ms`,
104
- "--agent-operation-pointer-x": `${motion.position.left}px`, "--agent-operation-pointer-y": `${motion.position.top}px` } },
195
+ return presentPointer(pointer.current, feedback.target, resolvePosition, feedback.presentation);
196
+ }, [
197
+ active,
198
+ show,
199
+ feedback?.presentation,
200
+ feedback?.target,
201
+ Boolean(targetPosition),
202
+ resolvePosition,
203
+ ]);
204
+ return show && motion ? (React.createElement("div", { "aria-hidden": true, ref: pointer, className: "agent-operation__pointer-effect", "data-active": action, "data-operation-effect": action ? "action" : undefined, style: {
205
+ "--agent-operation-pointer-duration": `${motion.durationMs}ms`,
206
+ "--agent-operation-pointer-x": `${motion.position.left}px`,
207
+ "--agent-operation-pointer-y": `${motion.position.top}px`,
208
+ } },
105
209
  React.createElement("span", { className: "agent-operation__pointer-cursor" },
106
210
  React.createElement(Cursor, { className: "agent-operation__pointer", size: 24, weight: "fill" })),
107
- action && feedback ? React.createElement(FeedbackLabel, { feedback: feedback }) : null) : null;
211
+ action && feedback ? (React.createElement(FeedbackLabel, { feedback: feedback, position: motion.position, durationMs: motion.durationMs })) : null)) : null;
108
212
  }
109
- export function OperationOverlayView({ operation, feedback, progressHistory = [], running, humanHasControl = false, cancelling = false, onCancel: cancel, resolveSurface }) {
110
- const [, setGeometry] = useState("");
213
+ export function OperationOverlayView({ operation, feedback, progressHistory = [], running, humanHasControl = false, cancelling = false, onCancel: cancel, resolveSurface, }) {
214
+ const [geometry, setGeometry] = useState();
215
+ const geometryCache = useRef(undefined);
111
216
  const [historyOpen, setHistoryOpen] = useState(false);
112
217
  const [historyId] = useState(() => `nexface-operation-history-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`}`);
113
- const cancelButtonRef = useRef(null);
114
- const controllerShouldBeVisible = operation.status !== "cancelled" && (running || humanHasControl || operation.status === "failed");
218
+ const controllerShouldBeVisible = operation.status !== "cancelled" &&
219
+ (running || humanHasControl || operation.status === "failed");
115
220
  const [controllerVisibility, setControllerVisibility] = useState(controllerShouldBeVisible ? "visible" : undefined);
116
221
  useEffect(() => {
117
222
  if (controllerShouldBeVisible) {
@@ -119,23 +224,27 @@ export function OperationOverlayView({ operation, feedback, progressHistory = []
119
224
  return;
120
225
  }
121
226
  setHistoryOpen(false);
122
- setControllerVisibility((current) => current ? "exiting" : undefined);
227
+ setControllerVisibility((current) => (current ? "exiting" : undefined));
123
228
  const timer = setTimeout(() => setControllerVisibility(undefined), 300);
124
229
  return () => clearTimeout(timer);
125
230
  }, [controllerShouldBeVisible]);
126
- useEffect(() => { if (!progressHistory.length)
127
- setHistoryOpen(false); }, [progressHistory.length]);
231
+ useEffect(() => {
232
+ if (!progressHistory.length)
233
+ setHistoryOpen(false);
234
+ }, [progressHistory.length]);
235
+ const agentControlsSurface = running && !humanHasControl;
128
236
  useLayoutEffect(() => {
129
237
  const surface = resolveSurface?.();
130
- if (!surface || !running || humanHasControl)
238
+ if (!surface || !agentControlsSurface)
131
239
  return;
132
- return lockOperationSurface(surface, () => cancelButtonRef.current?.focus());
133
- }, [humanHasControl, resolveSurface, running]);
240
+ return lockOperationSurface(surface);
241
+ }, [agentControlsSurface, resolveSurface]);
134
242
  const readGeometry = useCallback(() => {
135
243
  const surface = resolveSurface?.();
136
244
  const resolvedTarget = feedback?.resolveTarget ? feedback.resolveTarget() : feedback?.target;
137
245
  const target = resolvedTarget?.isConnected && surface?.contains(resolvedTarget) ? resolvedTarget : undefined;
138
246
  return {
247
+ viewport: { left: 0, top: 0, width: window.innerWidth, height: window.innerHeight },
139
248
  surfaceRect: surface?.isConnected ? surface.getBoundingClientRect() : undefined,
140
249
  target,
141
250
  targetRect: target?.getBoundingClientRect(),
@@ -143,56 +252,98 @@ export function OperationOverlayView({ operation, feedback, progressHistory = []
143
252
  }, [resolveSurface, feedback?.target, feedback?.resolveTarget]);
144
253
  useLayoutEffect(() => {
145
254
  const update = () => {
146
- const { surfaceRect, targetRect } = readGeometry();
147
- const geometry = [surfaceRect, targetRect].map((rect) => {
148
- if (!rect)
149
- return "";
150
- return [rect.left, rect.top, rect.width, rect.height].join(",");
151
- }).join(";");
152
- setGeometry(geometry);
255
+ const next = readGeometry();
256
+ const previous = geometryCache.current;
257
+ if (previous?.source === readGeometry &&
258
+ previous.target === next.target &&
259
+ sameRect(previous.surfaceRect, next.surfaceRect) &&
260
+ sameRect(previous.targetRect, next.targetRect) &&
261
+ sameRect(previous.viewport, next.viewport))
262
+ return;
263
+ const measured = { ...next, source: readGeometry };
264
+ geometryCache.current = measured;
265
+ setGeometry(measured);
153
266
  };
154
267
  update();
155
268
  if (!running && !humanHasControl)
156
269
  return;
157
- let frame = requestAnimationFrame(function track() { update(); frame = requestAnimationFrame(track); });
270
+ let frame = requestAnimationFrame(function track() {
271
+ update();
272
+ frame = requestAnimationFrame(track);
273
+ });
158
274
  return () => cancelAnimationFrame(frame);
159
275
  }, [readGeometry, operation, running, humanHasControl]);
276
+ const resolvePosition = useCallback(() => {
277
+ const current = readGeometry();
278
+ const surface = intersect(current.surfaceRect, current.viewport);
279
+ const visible = surface ? intersect(current.targetRect, surface) : undefined;
280
+ return visible ? center(visible) : undefined;
281
+ }, [readGeometry]);
160
282
  if (typeof document === "undefined")
161
283
  return null;
162
- const { surfaceRect, target, targetRect: rect } = readGeometry();
284
+ const measured = geometry?.source === readGeometry ? geometry : readGeometry();
285
+ const surfaceRect = intersect(measured.surfaceRect, measured.viewport);
286
+ const { target } = measured;
287
+ const rect = surfaceRect ? intersect(measured.targetRect, surfaceRect) : undefined;
288
+ const targetInvisible = Boolean(target && !rect);
163
289
  const structuredTargetLost = Boolean(feedback?.requiresTarget && !target);
164
- const activeFeedback = !cancelling && !humanHasControl && !structuredTargetLost ? feedback : undefined;
290
+ const activeFeedback = !cancelling && !humanHasControl && !structuredTargetLost && !targetInvisible && surfaceRect
291
+ ? feedback
292
+ : undefined;
165
293
  const effect = activeFeedback?.effect;
166
294
  const highlightedRect = effect === "navigate" || activeFeedback?.centered ? undefined : rect;
167
- const agentControlsSurface = running && !humanHasControl;
168
295
  const operationFeedbackActive = Boolean(activeFeedback);
169
296
  const controllerMounted = Boolean(controllerVisibility);
170
297
  const controllerExiting = controllerVisibility === "exiting";
171
298
  const controllerLabel = humanHasControl ? undefined : operation.progressLabel;
172
299
  const compactStatusLabel = humanHasControl ? "等待你完成操作" : operation.progressLabel;
173
- const statusLabel = humanHasControl ? "等待你完成操作" : {
174
- running: "Agent 正在控制", completed: running ? "工具已完成,任务继续中" : "操作已完成",
175
- failed: running ? "Agent 正在处理错误" : "操作失败", cancelled: "任务已终止",
176
- }[operation.status];
300
+ const statusLabel = humanHasControl
301
+ ? "等待你完成操作"
302
+ : {
303
+ running: "Agent 正在控制",
304
+ completed: running ? "工具已完成,任务继续中" : "操作已完成",
305
+ failed: running ? "Agent 正在处理错误" : "操作失败",
306
+ cancelled: "任务已终止",
307
+ }[operation.status];
177
308
  const targetPosition = rect ? center(rect) : undefined;
178
309
  return createPortal(React.createElement("div", { className: "agent-operation", "data-nexface-ignore": true, "data-feedback-active": operationFeedbackActive, "data-structured-target-lost": structuredTargetLost, "data-human-control": humanHasControl, "data-operation-effect": effect ?? "action", "data-run-active": running, "data-status": operation.status },
179
- agentControlsSurface && surfaceRect ? React.createElement("div", { "aria-hidden": true, className: "agent-operation__surface", style: {
180
- ...(highlightedRect ? { "--agent-operation-cutout-height": `${highlightedRect.height}px`,
181
- "--agent-operation-cutout-left": `${highlightedRect.left - surfaceRect.left}px`,
182
- "--agent-operation-cutout-top": `${highlightedRect.top - surfaceRect.top}px`, "--agent-operation-cutout-width": `${highlightedRect.width}px` } : {}),
183
- height: surfaceRect.height, left: surfaceRect.left, top: surfaceRect.top, width: surfaceRect.width,
184
- } }) : null,
185
- activeFeedback && highlightedRect ? React.createElement("div", { "aria-hidden": true, className: "agent-operation__target", "data-operation-effect": effect, style: { height: highlightedRect.height, left: highlightedRect.left, top: highlightedRect.top, width: highlightedRect.width } }) : null,
186
- React.createElement(AgentPointer, { active: agentControlsSurface && !cancelling, feedback: feedback?.presentation ? feedback : activeFeedback, targetPosition: targetPosition, surfaceCenter: surfaceRect ? center(surfaceRect) : undefined }),
187
- activeFeedback && effect !== "action" && surfaceRect ? React.createElement(FeedbackIndicator, { key: activeFeedback.id, feedback: activeFeedback, position: activeFeedback.centered ? center(surfaceRect) : targetPosition }) : null,
188
- controllerMounted ? React.createElement("section", { "aria-live": "polite", className: "agent-operation__controller", "data-visibility": controllerExiting ? "exiting" : "visible", style: surfaceRect ? { left: surfaceRect.left + surfaceRect.width / 2, right: "auto", "--agent-operation-controller-x": "-50%", maxWidth: Math.max(0, surfaceRect.width - 32) } : undefined },
189
- historyOpen ? React.createElement("aside", { "aria-label": "\u672C\u6B21\u8FD0\u884C\u7684\u64CD\u4F5C\u8BB0\u5F55", className: "agent-operation__history", id: historyId },
310
+ agentControlsSurface && surfaceRect ? (React.createElement("div", { "aria-hidden": true, className: "agent-operation__surface", style: {
311
+ ...(highlightedRect
312
+ ? {
313
+ "--agent-operation-cutout-height": `${highlightedRect.height}px`,
314
+ "--agent-operation-cutout-left": `${highlightedRect.left - surfaceRect.left}px`,
315
+ "--agent-operation-cutout-top": `${highlightedRect.top - surfaceRect.top}px`,
316
+ "--agent-operation-cutout-width": `${highlightedRect.width}px`,
317
+ }
318
+ : {}),
319
+ height: surfaceRect.height,
320
+ left: surfaceRect.left,
321
+ top: surfaceRect.top,
322
+ width: surfaceRect.width,
323
+ } })) : null,
324
+ activeFeedback && highlightedRect ? (React.createElement("div", { "aria-hidden": true, className: "agent-operation__target", "data-operation-effect": effect, style: {
325
+ height: highlightedRect.height,
326
+ left: highlightedRect.left,
327
+ top: highlightedRect.top,
328
+ width: highlightedRect.width,
329
+ } })) : null,
330
+ React.createElement(AgentPointer, { active: agentControlsSurface && !cancelling && Boolean(surfaceRect) && !targetInvisible, feedback: feedback?.presentation ? feedback : activeFeedback, targetPosition: targetPosition, surfaceCenter: surfaceRect ? center(surfaceRect) : undefined, resolvePosition: resolvePosition }),
331
+ activeFeedback && effect !== "action" && surfaceRect ? (React.createElement(FeedbackIndicator, { key: activeFeedback.id, feedback: activeFeedback, position: activeFeedback.centered ? center(surfaceRect) : targetPosition })) : null,
332
+ controllerMounted ? (React.createElement("section", { "aria-live": "polite", className: "agent-operation__controller", "data-visibility": controllerExiting ? "exiting" : "visible", style: surfaceRect && surfaceRect.width >= 240
333
+ ? {
334
+ left: surfaceRect.left + surfaceRect.width / 2,
335
+ right: "auto",
336
+ "--agent-operation-controller-x": "-50%",
337
+ maxWidth: Math.max(0, surfaceRect.width - 32),
338
+ }
339
+ : undefined },
340
+ historyOpen ? (React.createElement("aside", { "aria-label": "\u672C\u6B21\u8FD0\u884C\u7684\u64CD\u4F5C\u8BB0\u5F55", className: "agent-operation__history", id: historyId },
190
341
  React.createElement("header", null,
191
342
  React.createElement("strong", null, "\u64CD\u4F5C\u8BB0\u5F55"),
192
343
  React.createElement("span", null, progressHistory.length)),
193
- React.createElement("ol", null, progressHistory.map(({ progressLabel: label, toolCallId }, index) => React.createElement("li", { key: toolCallId },
344
+ React.createElement("ol", null, progressHistory.map(({ progressLabel: label, toolCallId }, index) => (React.createElement("li", { key: toolCallId },
194
345
  React.createElement("span", { "aria-hidden": true }, index + 1),
195
- React.createElement("p", null, label))))) : null,
346
+ React.createElement("p", null, label))))))) : null,
196
347
  React.createElement("span", { "aria-hidden": true, className: "agent-operation__edge-flow" }),
197
348
  React.createElement("span", { "aria-hidden": true, className: "agent-operation__pause-mark" },
198
349
  React.createElement("i", null),
@@ -204,9 +355,8 @@ export function OperationOverlayView({ operation, feedback, progressHistory = []
204
355
  React.createElement("div", null,
205
356
  React.createElement("span", { className: "agent-operation__heading" },
206
357
  React.createElement("strong", null, controllerLabel)),
207
- statusLabel ? React.createElement("small", { className: "agent-operation__description" },
208
- React.createElement("span", { className: "agent-operation__status" }, statusLabel)) : null),
209
- (running || humanHasControl) && operation.status !== "cancelled" ? React.createElement("span", { className: "agent-operation__compact-status", title: compactStatusLabel }, compactStatusLabel) : null,
210
- cancel && (running || humanHasControl) && operation.status !== "cancelled" ? React.createElement("button", { ref: cancelButtonRef, className: "agent-operation__stop", type: "button", disabled: cancelling, onClick: cancel }, cancelling ? "正在终止" : "终止任务") : null) : null), document.body);
358
+ statusLabel ? (React.createElement("small", { className: "agent-operation__description" },
359
+ React.createElement("span", { className: "agent-operation__status" }, statusLabel))) : null),
360
+ (running || humanHasControl) && operation.status !== "cancelled" ? (React.createElement("span", { className: "agent-operation__compact-status", title: compactStatusLabel }, compactStatusLabel)) : null,
361
+ cancel && (running || humanHasControl) && operation.status !== "cancelled" ? (React.createElement("button", { className: "agent-operation__stop", type: "button", disabled: cancelling, onClick: cancel }, cancelling ? "正在终止" : "终止任务")) : null)) : null), document.body);
211
362
  }
212
- //# sourceMappingURL=operation-view.js.map
package/dist/react.js CHANGED
@@ -3,7 +3,7 @@ import { Children, Fragment, cloneElement, useCallback, useEffect, useLayoutEffe
3
3
  import { defineAgentTool } from "./definition.js";
4
4
  import { getAgentNavigationEntries, } from "./navigation.js";
5
5
  import { AgentToolError, getInternalToolRuntime } from "./runtime.js";
6
- import { InternalToolRuntimeScope, useInternalToolRuntime, } from "./internal-react.js";
6
+ import { InternalToolRuntimeScope, useInternalToolRuntime } from "./internal-react.js";
7
7
  import { connectToolRuntimeToWebMcp } from "./webmcp.js";
8
8
  const bindingInternals = new WeakMap();
9
9
  export function getAgentToolBindingInternals(binding) {
@@ -55,10 +55,10 @@ function createAgentToolBinding(toolName) {
55
55
  function useAgentBinding(definition, execute, options) {
56
56
  const runtime = useInternalToolRuntime();
57
57
  const confirmation = options.requiresConfirmation;
58
- if (confirmation !== undefined
59
- && (!confirmation
60
- || typeof confirmation !== "object"
61
- || (confirmation.mode !== "chat" && confirmation.mode !== "page"))) {
58
+ if (confirmation !== undefined &&
59
+ (!confirmation ||
60
+ typeof confirmation !== "object" ||
61
+ (confirmation.mode !== "chat" && confirmation.mode !== "page"))) {
62
62
  throw new Error("requiresConfirmation must explicitly use chat or page mode.");
63
63
  }
64
64
  const executeRef = useRef(execute);
@@ -82,9 +82,7 @@ export function useAgentTool(definition, execute, options = {}) {
82
82
  return useAgentBinding(definition, execute, options);
83
83
  }
84
84
  function getAgentNavigationExecutor(executors, key) {
85
- if (!executors
86
- || typeof executors !== "object"
87
- || !Object.hasOwn(executors, key)) {
85
+ if (!executors || typeof executors !== "object" || !Object.hasOwn(executors, key)) {
88
86
  throw new Error(`Missing navigation executor: ${key}.`);
89
87
  }
90
88
  const executor = executors[key];
@@ -203,9 +201,7 @@ function isHTMLElement(value) {
203
201
  return ElementConstructor !== undefined && value instanceof ElementConstructor;
204
202
  }
205
203
  function warnAgentUIAction(message) {
206
- if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
207
- console.warn(message);
208
- }
204
+ console.warn(message);
209
205
  }
210
206
  const eventAdapters = {
211
207
  click: {
@@ -286,8 +282,8 @@ export function AgentUIAction({ name, description, event = "click", children, })
286
282
  if (warnedChildRef.current !== warningType) {
287
283
  warnedChildRef.current = warningType;
288
284
  warnAgentUIAction(isFragment
289
- ? `AgentUIAction "${name}" does not support React.Fragment children.`
290
- : `AgentUIAction "${name}" needs a child with onClick.`);
285
+ ? `AgentUIAction "${name}" does not support React.Fragment children; the Tool is not registered.`
286
+ : `AgentUIAction "${name}" needs a child with onClick; the Tool is not registered.`);
291
287
  }
292
288
  return;
293
289
  }
@@ -365,4 +361,3 @@ export function AgentUIAction({ name, description, event = "click", children, })
365
361
  ref: mergedRef,
366
362
  });
367
363
  }
368
- //# sourceMappingURL=react.js.map
@@ -1,15 +1,16 @@
1
1
  import { assertAgentToolInputSchema } from "./shared/schema.js";
2
2
  export function registerAgentTool(definition, options) {
3
3
  assertAgentToolRegistration(definition, options);
4
- assertAgentToolInputSchema(definition.inputSchema, `Tool "${definition.name}".inputSchema`);
4
+ assertAgentToolInputSchema(definition.inputSchema, `Tool "${definition.name}" was not registered: inputSchema`);
5
5
  return Object.freeze({ definition, execute: options.execute });
6
6
  }
7
7
  export function assertAgentToolRegistration(definition, options) {
8
- if (!definition || typeof definition.name !== "string" || typeof options?.execute !== "function") {
8
+ if (!definition ||
9
+ typeof definition.name !== "string" ||
10
+ typeof options?.execute !== "function") {
9
11
  throw new TypeError("registerAgentTool requires a definition and execute function.");
10
12
  }
11
13
  if ("requiresConfirmation" in options) {
12
14
  throw new TypeError("Registered Agent tools do not support requiresConfirmation.");
13
15
  }
14
16
  }
15
- //# sourceMappingURL=registration.js.map
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[];