@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/internal-react.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type ToolRuntime, type InternalToolRuntime } from "./runtime.js";
|
|
|
3
3
|
export interface InternalToolRuntimeHostProps {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
}
|
|
6
|
-
export declare function InternalToolRuntimeHost({ children
|
|
6
|
+
export declare function InternalToolRuntimeHost({ children }: InternalToolRuntimeHostProps): ReactElement;
|
|
7
7
|
export declare function InternalToolRuntimeScope({ children, runtime, }: {
|
|
8
8
|
children: ReactNode;
|
|
9
9
|
runtime: ToolRuntime;
|
package/dist/internal-react.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { createContext, useContext, useMemo
|
|
2
|
+
import { createContext, useContext, useMemo } from "react";
|
|
3
3
|
import { createToolRuntime, getInternalToolRuntime, } from "./runtime.js";
|
|
4
4
|
const InternalToolRuntimeContext = createContext(null);
|
|
5
|
-
export function InternalToolRuntimeHost({ children
|
|
5
|
+
export function InternalToolRuntimeHost({ children }) {
|
|
6
6
|
const runtime = useMemo(() => createToolRuntime(), []);
|
|
7
|
-
return
|
|
7
|
+
return React.createElement(InternalToolRuntimeScope, { runtime: runtime }, children);
|
|
8
8
|
}
|
|
9
9
|
export function InternalToolRuntimeScope({ children, runtime, }) {
|
|
10
10
|
const internalRuntime = getInternalToolRuntime(runtime);
|
|
@@ -20,4 +20,3 @@ export function useInternalToolRuntime() {
|
|
|
20
20
|
export function useOptionalInternalToolRuntime() {
|
|
21
21
|
return useContext(InternalToolRuntimeContext);
|
|
22
22
|
}
|
|
23
|
-
//# sourceMappingURL=internal-react.js.map
|
package/dist/internal-types.js
CHANGED
package/dist/navigation.js
CHANGED
package/dist/operation-lock.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare function isOperationSurfaceLocked(surface: HTMLElement): boolean;
|
|
2
2
|
/** Block user input inside the surface without hiding DOM from page tools. */
|
|
3
|
-
export declare function lockOperationSurface(surface: HTMLElement
|
|
3
|
+
export declare function lockOperationSurface(surface: HTMLElement): () => void;
|
package/dist/operation-lock.js
CHANGED
|
@@ -1,36 +1,54 @@
|
|
|
1
|
-
import { isAgentActivation
|
|
1
|
+
import { isAgentActivation } from "./browser/focus.js";
|
|
2
2
|
const lockedSurfaces = new WeakSet();
|
|
3
3
|
export function isOperationSurfaceLocked(surface) {
|
|
4
4
|
return lockedSurfaces.has(surface);
|
|
5
5
|
}
|
|
6
6
|
/** Block user input inside the surface without hiding DOM from page tools. */
|
|
7
|
-
export function lockOperationSurface(surface
|
|
7
|
+
export function lockOperationSurface(surface) {
|
|
8
8
|
const previousBusy = surface.getAttribute("aria-busy");
|
|
9
9
|
const block = (event) => {
|
|
10
10
|
if ((event.type === "submit" || event.type === "reset") && isAgentActivation())
|
|
11
11
|
return;
|
|
12
12
|
if (!event.isTrusted)
|
|
13
13
|
return;
|
|
14
|
-
if (event.type === "focus" || event.type === "focusin") {
|
|
15
|
-
if (isAgentFocus())
|
|
16
|
-
return;
|
|
17
|
-
event.stopImmediatePropagation();
|
|
18
|
-
if (event.target instanceof HTMLElement)
|
|
19
|
-
event.target.blur();
|
|
20
|
-
redirectFocus?.();
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
if (event.type === "keydown" && event.key === "Tab") {
|
|
24
|
-
event.preventDefault();
|
|
25
|
-
event.stopImmediatePropagation();
|
|
26
|
-
redirectFocus?.();
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
14
|
event.preventDefault();
|
|
30
15
|
event.stopImmediatePropagation();
|
|
31
16
|
};
|
|
32
17
|
// Wheel and touch defaults are blocked here: React delegates them passively.
|
|
33
|
-
const events = [
|
|
18
|
+
const events = [
|
|
19
|
+
"mouseenter",
|
|
20
|
+
"mouseleave",
|
|
21
|
+
"pointerenter",
|
|
22
|
+
"pointerleave",
|
|
23
|
+
"pointerdown",
|
|
24
|
+
"pointerup",
|
|
25
|
+
"pointermove",
|
|
26
|
+
"pointerover",
|
|
27
|
+
"pointerout",
|
|
28
|
+
"mousedown",
|
|
29
|
+
"mouseup",
|
|
30
|
+
"mousemove",
|
|
31
|
+
"mouseover",
|
|
32
|
+
"mouseout",
|
|
33
|
+
"click",
|
|
34
|
+
"dblclick",
|
|
35
|
+
"auxclick",
|
|
36
|
+
"contextmenu",
|
|
37
|
+
"keydown",
|
|
38
|
+
"keyup",
|
|
39
|
+
"beforeinput",
|
|
40
|
+
"paste",
|
|
41
|
+
"cut",
|
|
42
|
+
"drop",
|
|
43
|
+
"dragstart",
|
|
44
|
+
"touchstart",
|
|
45
|
+
"touchmove",
|
|
46
|
+
"touchend",
|
|
47
|
+
"touchcancel",
|
|
48
|
+
"wheel",
|
|
49
|
+
"submit",
|
|
50
|
+
"reset",
|
|
51
|
+
];
|
|
34
52
|
lockedSurfaces.add(surface);
|
|
35
53
|
surface.setAttribute("aria-busy", "true");
|
|
36
54
|
for (const name of events)
|
|
@@ -45,4 +63,3 @@ export function lockOperationSurface(surface, redirectFocus) {
|
|
|
45
63
|
surface.setAttribute("aria-busy", previousBusy);
|
|
46
64
|
};
|
|
47
65
|
}
|
|
48
|
-
//# sourceMappingURL=operation-lock.js.map
|
|
@@ -4,17 +4,24 @@ export class OperationTracker {
|
|
|
4
4
|
#unscoped = 0;
|
|
5
5
|
#executions = new Map();
|
|
6
6
|
#listeners = new Set();
|
|
7
|
-
#snapshot = Object.freeze({
|
|
7
|
+
#snapshot = Object.freeze({
|
|
8
|
+
operation: null,
|
|
9
|
+
executions: Object.freeze([]),
|
|
10
|
+
});
|
|
8
11
|
getSnapshot = () => this.#snapshot;
|
|
9
12
|
subscribe = (listener) => {
|
|
10
13
|
this.#listeners.add(listener);
|
|
11
|
-
return () => {
|
|
14
|
+
return () => {
|
|
15
|
+
this.#listeners.delete(listener);
|
|
16
|
+
};
|
|
12
17
|
};
|
|
13
18
|
begin(options = {}) {
|
|
14
19
|
options.signal?.throwIfAborted();
|
|
15
20
|
const previous = this.#operation;
|
|
16
|
-
const replacing = previous &&
|
|
17
|
-
|
|
21
|
+
const replacing = previous &&
|
|
22
|
+
previous.handle === options.replaceWaiting &&
|
|
23
|
+
previous.snapshot.status === "waiting" &&
|
|
24
|
+
previous.pending === 0;
|
|
18
25
|
if (this.#unscoped || (previous && !replacing)) {
|
|
19
26
|
throw new AgentToolError("OPERATION_BUSY", "The Runtime already has an operation or outstanding tool calls.");
|
|
20
27
|
}
|
|
@@ -23,11 +30,22 @@ export class OperationTracker {
|
|
|
23
30
|
previous.resolveEnd();
|
|
24
31
|
}
|
|
25
32
|
let resolveEnd;
|
|
26
|
-
const endPromise = new Promise((resolve) => {
|
|
33
|
+
const endPromise = new Promise((resolve) => {
|
|
34
|
+
resolveEnd = resolve;
|
|
35
|
+
});
|
|
27
36
|
const id = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
|
|
28
37
|
const operation = {
|
|
29
|
-
snapshot: Object.freeze({
|
|
30
|
-
|
|
38
|
+
snapshot: Object.freeze({
|
|
39
|
+
id,
|
|
40
|
+
source: options.source ?? "host",
|
|
41
|
+
status: "running",
|
|
42
|
+
hasExecuted: false,
|
|
43
|
+
canCancel: Boolean(options.onCancel),
|
|
44
|
+
...(options.taskProgress ? { taskProgress: Object.freeze(options.taskProgress) } : {}),
|
|
45
|
+
}),
|
|
46
|
+
handle: undefined,
|
|
47
|
+
pending: 0,
|
|
48
|
+
resolveEnd,
|
|
31
49
|
...(options.onCancel ? { onCancel: options.onCancel } : {}),
|
|
32
50
|
removeAbort: () => options.signal?.removeEventListener("abort", onAbort),
|
|
33
51
|
};
|
|
@@ -42,7 +60,11 @@ export class OperationTracker {
|
|
|
42
60
|
if (this.#operation !== operation || operation.snapshot.status === "ending")
|
|
43
61
|
return endPromise;
|
|
44
62
|
operation.removeAbort();
|
|
45
|
-
operation.snapshot = Object.freeze({
|
|
63
|
+
operation.snapshot = Object.freeze({
|
|
64
|
+
...operation.snapshot,
|
|
65
|
+
status: "ending",
|
|
66
|
+
outcome: endOptions?.outcome ?? "completed",
|
|
67
|
+
});
|
|
46
68
|
this.#publish();
|
|
47
69
|
if (this.#finish(operation))
|
|
48
70
|
this.#publish();
|
|
@@ -77,8 +99,11 @@ export class OperationTracker {
|
|
|
77
99
|
}
|
|
78
100
|
requestCancel(id) {
|
|
79
101
|
const operation = this.#operation;
|
|
80
|
-
if (!operation ||
|
|
81
|
-
|
|
102
|
+
if (!operation ||
|
|
103
|
+
operation.snapshot.id !== id ||
|
|
104
|
+
!operation.onCancel ||
|
|
105
|
+
operation.snapshot.status === "ending" ||
|
|
106
|
+
operation.snapshot.status === "cancelling")
|
|
82
107
|
return;
|
|
83
108
|
const previous = operation.snapshot.status;
|
|
84
109
|
this.#update(operation, { status: "cancelling" });
|
|
@@ -123,7 +148,9 @@ export class OperationTracker {
|
|
|
123
148
|
if (event.status === "running") {
|
|
124
149
|
this.#executions.set(event.id, event);
|
|
125
150
|
const operation = this.#operation;
|
|
126
|
-
if (operation &&
|
|
151
|
+
if (operation &&
|
|
152
|
+
event.operationId === operation.snapshot.id &&
|
|
153
|
+
!operation.snapshot.hasExecuted) {
|
|
127
154
|
operation.snapshot = Object.freeze({ ...operation.snapshot, hasExecuted: true });
|
|
128
155
|
}
|
|
129
156
|
}
|
|
@@ -132,7 +159,9 @@ export class OperationTracker {
|
|
|
132
159
|
this.#publish();
|
|
133
160
|
}
|
|
134
161
|
#finish(operation) {
|
|
135
|
-
if (operation.pending ||
|
|
162
|
+
if (operation.pending ||
|
|
163
|
+
operation.snapshot.status !== "ending" ||
|
|
164
|
+
this.#operation !== operation)
|
|
136
165
|
return false;
|
|
137
166
|
this.#operation = undefined;
|
|
138
167
|
operation.resolveEnd();
|
|
@@ -151,4 +180,3 @@ export class OperationTracker {
|
|
|
151
180
|
listener();
|
|
152
181
|
}
|
|
153
182
|
}
|
|
154
|
-
//# sourceMappingURL=operation-runtime.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { flushSync } from "react-dom";
|
|
3
|
-
import { useCallback, useLayoutEffect, useRef, useState } from "react";
|
|
3
|
+
import { useCallback, useLayoutEffect, useRef, useState, } from "react";
|
|
4
4
|
import { useSyncExternalStore } from "use-sync-external-store/shim";
|
|
5
5
|
import { PageCommandError } from "./browser/locator.js";
|
|
6
6
|
import { getInternalToolRuntime } from "./runtime.js";
|
|
@@ -9,7 +9,8 @@ import { isAgentActivation } from "./browser/focus.js";
|
|
|
9
9
|
import { OperationOverlayView } from "./operation-view.js";
|
|
10
10
|
const BROWSER_TOOL_NAMES = new Set(["nxf_getSnapshot", "nxf_executeAction", "nxf_applyAction"]);
|
|
11
11
|
const belongsToOperation = (event, operation) => !operation || event.operationId === operation.id;
|
|
12
|
-
const canPresentInOperation = (event, operation) => belongsToOperation(event, operation) &&
|
|
12
|
+
const canPresentInOperation = (event, operation) => belongsToOperation(event, operation) &&
|
|
13
|
+
(!operation || operation.status === "running" || operation.status === "ending");
|
|
13
14
|
const surfaces = new WeakSet();
|
|
14
15
|
export function AgentOperationSurface(props) {
|
|
15
16
|
const element = useRef(null);
|
|
@@ -21,28 +22,34 @@ export function AgentOperationSurface(props) {
|
|
|
21
22
|
if (surfaces.has(props.toolRuntime))
|
|
22
23
|
throw new Error("Only one AgentOperationSurface is supported per Runtime.");
|
|
23
24
|
surfaces.add(props.toolRuntime);
|
|
24
|
-
return () => {
|
|
25
|
+
return () => {
|
|
26
|
+
surfaces.delete(props.toolRuntime);
|
|
27
|
+
};
|
|
25
28
|
}, [props.toolRuntime]);
|
|
26
29
|
const blockUserInput = useCallback((event) => {
|
|
27
30
|
if ((event.type === "submit" || event.type === "reset") && isAgentActivation())
|
|
28
31
|
return;
|
|
29
|
-
if (!element.current ||
|
|
32
|
+
if (!element.current ||
|
|
33
|
+
!isOperationSurfaceLocked(element.current) ||
|
|
34
|
+
!event.nativeEvent.isTrusted)
|
|
30
35
|
return;
|
|
31
36
|
event.preventDefault();
|
|
32
37
|
event.stopPropagation();
|
|
33
38
|
}, []);
|
|
34
39
|
const blockPassiveUserInput = useCallback((event) => {
|
|
35
|
-
if (!element.current ||
|
|
40
|
+
if (!element.current ||
|
|
41
|
+
!isOperationSurfaceLocked(element.current) ||
|
|
42
|
+
!event.nativeEvent.isTrusted)
|
|
36
43
|
return;
|
|
37
44
|
// Stop React's capture dispatch, but let the native event reach our non-passive
|
|
38
45
|
// surface listener. React's passive root listener cannot prevent scrolling.
|
|
39
46
|
event.isPropagationStopped = () => true;
|
|
40
47
|
}, []);
|
|
41
|
-
return React.createElement(React.Fragment, null,
|
|
48
|
+
return (React.createElement(React.Fragment, null,
|
|
42
49
|
React.createElement("div", { ref: element, className: "nexface-operation-surface", onClickCapture: blockUserInput, onDoubleClickCapture: blockUserInput, onAuxClickCapture: blockUserInput, onPointerDownCapture: blockUserInput, onPointerUpCapture: blockUserInput, onPointerMoveCapture: blockUserInput, onPointerOverCapture: blockUserInput, onPointerOutCapture: blockUserInput, onMouseDownCapture: blockUserInput, onMouseUpCapture: blockUserInput, onContextMenuCapture: blockUserInput, onMouseMoveCapture: blockUserInput, onMouseOverCapture: blockUserInput, onMouseOutCapture: blockUserInput, onWheelCapture: blockPassiveUserInput, onTouchStartCapture: blockPassiveUserInput, onTouchMoveCapture: blockPassiveUserInput, onTouchEndCapture: blockUserInput, onTouchCancelCapture: blockUserInput, onKeyDownCapture: blockUserInput, onKeyUpCapture: blockUserInput, onKeyPressCapture: blockUserInput, onBeforeInputCapture: blockUserInput, onPasteCapture: blockUserInput, onCutCapture: blockUserInput, onDropCapture: blockUserInput, onDragStartCapture: blockUserInput, onSubmitCapture: blockUserInput, onResetCapture: blockUserInput }, props.children),
|
|
43
|
-
React.createElement(OperationSurfaceContent, { ...props, element: element }));
|
|
50
|
+
React.createElement(OperationSurfaceContent, { ...props, element: element })));
|
|
44
51
|
}
|
|
45
|
-
function OperationSurfaceContent({ toolRuntime, element }) {
|
|
52
|
+
function OperationSurfaceContent({ toolRuntime, element, }) {
|
|
46
53
|
const runtime = getInternalToolRuntime(toolRuntime);
|
|
47
54
|
const activity = useSyncExternalStore(runtime.subscribeActivity, runtime.getActivitySnapshot, runtime.getActivitySnapshot);
|
|
48
55
|
const cycle = activity.operation;
|
|
@@ -58,15 +65,24 @@ function OperationSurfaceContent({ toolRuntime, element }) {
|
|
|
58
65
|
useLayoutEffect(() => runtime.setPageActionFeedback((event, feedback, signal) => {
|
|
59
66
|
const operation = runtime.getActivitySnapshot().operation;
|
|
60
67
|
if (signal?.aborted || !canPresentInOperation(event, operation))
|
|
61
|
-
throw new PageCommandError({
|
|
68
|
+
throw new PageCommandError({
|
|
69
|
+
code: "EXECUTION_CANCELLED",
|
|
70
|
+
message: "Page action presentation was interrupted.",
|
|
71
|
+
});
|
|
62
72
|
const target = feedback.target;
|
|
63
|
-
if (!feedback.effect ||
|
|
73
|
+
if (!feedback.effect ||
|
|
74
|
+
(feedback.effect === "action" &&
|
|
75
|
+
(!target?.isConnected || !element.current?.contains(target)))) {
|
|
64
76
|
setVisual(undefined);
|
|
65
77
|
return;
|
|
66
78
|
}
|
|
67
79
|
const next = {
|
|
68
|
-
id: crypto.randomUUID(),
|
|
69
|
-
|
|
80
|
+
id: crypto.randomUUID(),
|
|
81
|
+
effect: feedback.effect,
|
|
82
|
+
label: label(event),
|
|
83
|
+
centered: feedback.effect === "read",
|
|
84
|
+
persistentCursor: true,
|
|
85
|
+
requiresTarget: feedback.effect === "action",
|
|
70
86
|
...(target ? { target } : {}),
|
|
71
87
|
};
|
|
72
88
|
if (feedback.effect !== "action") {
|
|
@@ -98,32 +114,61 @@ function OperationSurfaceContent({ toolRuntime, element }) {
|
|
|
98
114
|
const page = BROWSER_TOOL_NAMES.has(event.name);
|
|
99
115
|
if (canDisplay && event.status === "running") {
|
|
100
116
|
if (page)
|
|
101
|
-
setVisual(event.name === "nxf_getSnapshot"
|
|
102
|
-
|
|
103
|
-
|
|
117
|
+
setVisual(event.name === "nxf_getSnapshot"
|
|
118
|
+
? {
|
|
119
|
+
event,
|
|
120
|
+
feedback: {
|
|
121
|
+
id: event.id,
|
|
122
|
+
effect: "read",
|
|
123
|
+
label: label(event),
|
|
124
|
+
centered: true,
|
|
125
|
+
},
|
|
126
|
+
}
|
|
127
|
+
: undefined);
|
|
104
128
|
else {
|
|
105
|
-
const target = event.tool.definition.effect === "navigate"
|
|
129
|
+
const target = event.tool.definition.effect === "navigate"
|
|
130
|
+
? element.current
|
|
131
|
+
: runtime.resolveTarget(event.tool, event.input);
|
|
106
132
|
if (target?.isConnected && element.current?.contains(target)) {
|
|
107
133
|
const rect = target.getBoundingClientRect();
|
|
108
|
-
setVisual({
|
|
109
|
-
|
|
110
|
-
|
|
134
|
+
setVisual({
|
|
135
|
+
event,
|
|
136
|
+
feedback: {
|
|
137
|
+
id: event.id,
|
|
138
|
+
effect: event.tool.definition.effect ?? "action",
|
|
139
|
+
label: label(event),
|
|
140
|
+
resolveTarget: () => event.tool.definition.effect === "navigate"
|
|
141
|
+
? (element.current ?? undefined)
|
|
142
|
+
: runtime.resolveTarget(event.tool, event.input),
|
|
143
|
+
position: { left: rect.left + rect.width / 2, top: rect.top + rect.height / 2 },
|
|
144
|
+
},
|
|
145
|
+
});
|
|
111
146
|
}
|
|
112
147
|
}
|
|
113
148
|
}
|
|
114
149
|
else if (canDisplay)
|
|
115
150
|
setVisual((current) => current?.event.id === event.id && current.event.operationId === event.operationId
|
|
116
|
-
? page
|
|
151
|
+
? page
|
|
152
|
+
? undefined
|
|
153
|
+
: { ...current, event }
|
|
154
|
+
: current);
|
|
117
155
|
if (page && !operation && event.status === "error")
|
|
118
156
|
setOutcome({ id: scope, status: event.cancelled ? "cancelled" : "failed" });
|
|
119
157
|
setHistory((current) => {
|
|
120
|
-
if (!belongsToOperation(event, operation) ||
|
|
158
|
+
if (!belongsToOperation(event, operation) ||
|
|
159
|
+
(event.status !== "running" && current.scope !== scope))
|
|
121
160
|
return current;
|
|
122
161
|
const entries = current.scope === scope ? current.entries : [];
|
|
123
|
-
const entry = {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
162
|
+
const entry = {
|
|
163
|
+
toolCallId: event.id,
|
|
164
|
+
progressLabel: `${event.progressLabel || "正在处理你的请求"} · ${event.cancelled ? "已取消" : event.status === "running" ? "执行中" : event.status === "success" ? "已完成" : "失败"}`,
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
scope,
|
|
168
|
+
entries: entries.some((item) => item.toolCallId === event.id)
|
|
169
|
+
? entries.map((item) => (item.toolCallId === event.id ? entry : item))
|
|
170
|
+
: [...entries, entry],
|
|
171
|
+
};
|
|
127
172
|
});
|
|
128
173
|
};
|
|
129
174
|
const unsubscribe = toolRuntime.on("toolexecution", onExecution);
|
|
@@ -136,25 +181,57 @@ function OperationSurfaceContent({ toolRuntime, element }) {
|
|
|
136
181
|
const waiting = cycle?.status === "waiting" && !executing;
|
|
137
182
|
const running = executing || (activated && cycle?.status !== "waiting");
|
|
138
183
|
const stopping = cycle?.status === "cancelling";
|
|
139
|
-
useLayoutEffect(() => {
|
|
140
|
-
|
|
184
|
+
useLayoutEffect(() => {
|
|
185
|
+
if (!running || waiting)
|
|
186
|
+
setVisual(undefined);
|
|
187
|
+
}, [running, waiting]);
|
|
141
188
|
const serverExecuting = cycle?.taskProgress?.phase === "tool";
|
|
142
189
|
const visualExecuting = Boolean(visual && activity.executions.some((event) => event.id === visual.event.id));
|
|
143
|
-
const currentVisual = !stopping &&
|
|
144
|
-
|
|
145
|
-
|
|
190
|
+
const currentVisual = !stopping &&
|
|
191
|
+
!waiting &&
|
|
192
|
+
visual &&
|
|
193
|
+
(!serverExecuting || (BROWSER_TOOL_NAMES.has(visual.event.name) && visualExecuting)) &&
|
|
194
|
+
canPresentInOperation(visual.event, cycle) &&
|
|
195
|
+
(cycle || visualExecuting)
|
|
196
|
+
? visual
|
|
197
|
+
: undefined;
|
|
146
198
|
const browserExecution = activity.executions.find((event) => BROWSER_TOOL_NAMES.has(event.name));
|
|
147
|
-
const progressLabel = currentVisual?.feedback.label ??
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
199
|
+
const progressLabel = currentVisual?.feedback.label ??
|
|
200
|
+
(waiting
|
|
201
|
+
? "等待你完成操作"
|
|
202
|
+
: stopping
|
|
203
|
+
? "正在终止"
|
|
204
|
+
: browserExecution
|
|
205
|
+
? browserExecution.progressLabel || "正在浏览网页"
|
|
206
|
+
: cycle?.taskProgress?.phase === "tool"
|
|
207
|
+
? cycle.taskProgress.progressLabel || "正在执行工具"
|
|
208
|
+
: cycle?.taskProgress
|
|
209
|
+
? "正在处理"
|
|
210
|
+
: "正在处理你的请求");
|
|
211
|
+
const operation = {
|
|
212
|
+
progressLabel,
|
|
213
|
+
status: currentVisual
|
|
214
|
+
? currentVisual.event.status === "running"
|
|
215
|
+
? "running"
|
|
216
|
+
: currentVisual.event.status === "success"
|
|
217
|
+
? "completed"
|
|
218
|
+
: "failed"
|
|
219
|
+
: running || waiting
|
|
220
|
+
? "running"
|
|
221
|
+
: outcome?.id === history.scope
|
|
222
|
+
? outcome.status
|
|
223
|
+
: "completed",
|
|
224
|
+
};
|
|
225
|
+
const feedback = currentVisual?.feedback ??
|
|
226
|
+
(serverExecuting && running && !waiting && !stopping
|
|
227
|
+
? {
|
|
228
|
+
id: cycle.taskProgress.toolCallId,
|
|
229
|
+
effect: "read",
|
|
230
|
+
label: progressLabel,
|
|
231
|
+
centered: true,
|
|
232
|
+
}
|
|
233
|
+
: undefined);
|
|
156
234
|
const resolveSurface = useCallback(() => element.current ?? undefined, [element]);
|
|
157
235
|
const entries = !cycle || history.scope === cycle.id ? history.entries : [];
|
|
158
|
-
return activated || executing || entries.length ? React.createElement(OperationOverlayView, { key: cycle?.id ?? history.scope, operation: operation, progressHistory: entries, running: running, humanHasControl: waiting, cancelling: stopping, ...(feedback ? { feedback } : {}), ...(cycle?.canCancel ? { onCancel: () => runtime.requestOperationCancel(cycle.id) } : {}), resolveSurface: resolveSurface }) : null;
|
|
236
|
+
return activated || executing || entries.length ? (React.createElement(OperationOverlayView, { key: cycle?.id ?? history.scope, operation: operation, progressHistory: entries, running: running, humanHasControl: waiting, cancelling: stopping, ...(feedback ? { feedback } : {}), ...(cycle?.canCancel ? { onCancel: () => runtime.requestOperationCancel(cycle.id) } : {}), resolveSurface: resolveSurface })) : null;
|
|
159
237
|
}
|
|
160
|
-
//# sourceMappingURL=operation-surface.js.map
|
package/dist/operation-types.js
CHANGED
package/dist/operation-view.d.ts
CHANGED
|
@@ -10,4 +10,4 @@ export interface OperationOverlayViewProps {
|
|
|
10
10
|
onCancel?(): void;
|
|
11
11
|
resolveSurface?(): HTMLElement | undefined;
|
|
12
12
|
}
|
|
13
|
-
export declare function OperationOverlayView({ operation, feedback, progressHistory, running, humanHasControl, cancelling, onCancel: cancel, resolveSurface }: OperationOverlayViewProps): React.ReactPortal | null;
|
|
13
|
+
export declare function OperationOverlayView({ operation, feedback, progressHistory, running, humanHasControl, cancelling, onCancel: cancel, resolveSurface, }: OperationOverlayViewProps): React.ReactPortal | null;
|