@nexface/tools 0.1.15-alpha.1 → 0.1.15-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/actions.js +34 -10
- package/dist/browser/controller.js +53 -74
- package/dist/browser/diagnostics.js +8 -3
- package/dist/browser/dom.js +12 -28
- package/dist/browser/feedback.js +6 -5
- package/dist/browser/focus.d.ts +0 -1
- package/dist/browser/focus.js +1 -13
- package/dist/browser/locator.js +3 -9
- package/dist/browser/prompt.d.ts +1 -1
- package/dist/browser/prompt.generated.d.ts +1 -1
- package/dist/browser/prompt.generated.js +6 -3
- package/dist/browser/prompt.js +0 -1
- package/dist/browser/snapshot.js +141 -120
- package/dist/browser/toolset.js +42 -36
- package/dist/browser/types.d.ts +1 -1
- package/dist/browser/types.js +0 -1
- package/dist/browser/worker-runner.js +0 -1
- package/dist/definition.d.ts +1 -3
- package/dist/definition.js +2 -2
- package/dist/index.browser.js +0 -1
- package/dist/index.js +0 -1
- package/dist/internal-react.d.ts +1 -1
- package/dist/internal-react.js +3 -4
- package/dist/internal-types.js +0 -1
- package/dist/navigation.js +0 -1
- package/dist/operation-lock.d.ts +1 -1
- package/dist/operation-lock.js +36 -19
- package/dist/operation-runtime.js +41 -13
- package/dist/operation-surface.js +118 -41
- package/dist/operation-types.js +0 -1
- package/dist/operation-view.d.ts +1 -1
- package/dist/operation-view.js +232 -82
- package/dist/react.js +9 -14
- package/dist/registration.js +4 -3
- package/dist/runtime.d.ts +4 -2
- package/dist/runtime.js +114 -52
- package/dist/shared/definition.js +2 -3
- package/dist/shared/errors.d.ts +1 -1
- package/dist/shared/errors.js +0 -1
- package/dist/shared/page-protocol.js +0 -1
- package/dist/shared/page-tools.js +2 -3
- package/dist/shared/runtime-controller.d.ts +1 -0
- package/dist/shared/runtime-controller.js +0 -1
- package/dist/shared/runtime-execution.js +0 -1
- package/dist/shared/schema.js +45 -19
- package/dist/styles.css +882 -109
- package/dist/tool-search.d.ts +11 -0
- package/dist/tool-search.js +117 -0
- package/dist/types.js +0 -1
- package/dist/webmcp.js +39 -13
- package/package.json +8 -4
- package/dist/browser/actions.js.map +0 -1
- package/dist/browser/controller.js.map +0 -1
- package/dist/browser/diagnostics.js.map +0 -1
- package/dist/browser/dom.js.map +0 -1
- package/dist/browser/feedback.js.map +0 -1
- package/dist/browser/focus.js.map +0 -1
- package/dist/browser/locator.js.map +0 -1
- package/dist/browser/prompt.generated.js.map +0 -1
- package/dist/browser/prompt.js.map +0 -1
- package/dist/browser/snapshot.js.map +0 -1
- package/dist/browser/toolset.js.map +0 -1
- package/dist/browser/types.js.map +0 -1
- package/dist/browser/worker-runner.js.map +0 -1
- package/dist/definition.js.map +0 -1
- package/dist/index.browser.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal-react.js.map +0 -1
- package/dist/internal-types.js.map +0 -1
- package/dist/navigation.js.map +0 -1
- package/dist/operation-lock.js.map +0 -1
- package/dist/operation-runtime.js.map +0 -1
- package/dist/operation-surface.js.map +0 -1
- package/dist/operation-types.js.map +0 -1
- package/dist/operation-view.js.map +0 -1
- package/dist/react.js.map +0 -1
- package/dist/registration.js.map +0 -1
- package/dist/runtime.js.map +0 -1
- package/dist/shared/definition.js.map +0 -1
- package/dist/shared/errors.js.map +0 -1
- package/dist/shared/page-protocol.js.map +0 -1
- package/dist/shared/page-tools.js.map +0 -1
- package/dist/shared/runtime-controller.js.map +0 -1
- package/dist/shared/runtime-execution.js.map +0 -1
- package/dist/shared/schema.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/webmcp.js.map +0 -1
package/dist/operation-view.js
CHANGED
|
@@ -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
|
|
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({
|
|
11
|
-
|
|
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 = () =>
|
|
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()
|
|
29
|
-
|
|
30
|
-
|
|
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(() => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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(() => {
|
|
54
|
-
|
|
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: {
|
|
57
|
-
"--agent-operation-pointer-
|
|
58
|
-
|
|
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({
|
|
79
|
-
|
|
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
|
|
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({
|
|
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
|
-
}, [
|
|
103
|
-
|
|
104
|
-
|
|
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
|
|
114
|
-
|
|
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(() => {
|
|
127
|
-
|
|
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 || !
|
|
238
|
+
if (!surface || !agentControlsSurface)
|
|
131
239
|
return;
|
|
132
|
-
return lockOperationSurface(surface
|
|
133
|
-
}, [
|
|
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
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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() {
|
|
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
|
|
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
|
|
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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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", {
|
|
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
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
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
|
package/dist/registration.js
CHANGED
|
@@ -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}"
|
|
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 ||
|
|
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[];
|