@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.
- package/dist/browser/actions.js +34 -10
- package/dist/browser/controller.js +91 -76
- package/dist/browser/diagnostics.js +8 -3
- package/dist/browser/dom.js +23 -30
- 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 +9 -4
- package/dist/browser/prompt.js +0 -1
- package/dist/browser/snapshot.js +199 -117
- 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/browser/toolset.js
CHANGED
|
@@ -27,11 +27,7 @@ const DEFAULT_SNAPSHOT_LIMITS = {
|
|
|
27
27
|
fullMaxVisitedNodes: 40_000,
|
|
28
28
|
};
|
|
29
29
|
function isIgnoredMutationNode(node) {
|
|
30
|
-
const element = node instanceof Element
|
|
31
|
-
? node
|
|
32
|
-
: node instanceof Text
|
|
33
|
-
? node.parentElement
|
|
34
|
-
: null;
|
|
30
|
+
const element = node instanceof Element ? node : node instanceof Text ? node.parentElement : null;
|
|
35
31
|
return Boolean(element?.closest("[data-nexface-ignore]"));
|
|
36
32
|
}
|
|
37
33
|
function isRelevantMutation(record) {
|
|
@@ -40,8 +36,7 @@ function isRelevantMutation(record) {
|
|
|
40
36
|
if (record.type !== "childList")
|
|
41
37
|
return true;
|
|
42
38
|
const changedNodes = [...record.addedNodes, ...record.removedNodes];
|
|
43
|
-
return
|
|
44
|
-
|| changedNodes.some((node) => !isIgnoredMutationNode(node)));
|
|
39
|
+
return changedNodes.length === 0 || changedNodes.some((node) => !isIgnoredMutationNode(node));
|
|
45
40
|
}
|
|
46
41
|
let activeHistoryPatch;
|
|
47
42
|
function subscribeHistoryChanges(subscriber) {
|
|
@@ -223,12 +218,12 @@ function validateInput(definition, input) {
|
|
|
223
218
|
}
|
|
224
219
|
}
|
|
225
220
|
export function browserToolsAvailable() {
|
|
226
|
-
return (typeof window !== "undefined"
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
221
|
+
return (typeof window !== "undefined" &&
|
|
222
|
+
typeof document !== "undefined" &&
|
|
223
|
+
typeof Worker !== "undefined" &&
|
|
224
|
+
typeof Blob !== "undefined" &&
|
|
225
|
+
typeof URL?.createObjectURL === "function" &&
|
|
226
|
+
typeof MutationObserver !== "undefined");
|
|
232
227
|
}
|
|
233
228
|
export function createBrowserToolset(options = {}) {
|
|
234
229
|
if (!browserToolsAvailable()) {
|
|
@@ -236,19 +231,14 @@ export function createBrowserToolset(options = {}) {
|
|
|
236
231
|
}
|
|
237
232
|
const limits = {
|
|
238
233
|
...DEFAULT_EXECUTION_LIMITS,
|
|
239
|
-
maxDurationMs: options.limits?.maxDurationMs
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
?? DEFAULT_EXECUTION_LIMITS.maxResultChars,
|
|
243
|
-
singleActionTimeoutMs: options.limits?.singleActionTimeoutMs
|
|
244
|
-
?? DEFAULT_EXECUTION_LIMITS.singleActionTimeoutMs,
|
|
234
|
+
maxDurationMs: options.limits?.maxDurationMs ?? DEFAULT_EXECUTION_LIMITS.maxDurationMs,
|
|
235
|
+
maxResultChars: options.limits?.maxResultChars ?? DEFAULT_EXECUTION_LIMITS.maxResultChars,
|
|
236
|
+
singleActionTimeoutMs: options.limits?.singleActionTimeoutMs ?? DEFAULT_EXECUTION_LIMITS.singleActionTimeoutMs,
|
|
245
237
|
};
|
|
246
238
|
const snapshotLimits = {
|
|
247
239
|
...DEFAULT_SNAPSHOT_LIMITS,
|
|
248
|
-
viewportMaxChars: options.snapshotLimits?.viewportMaxChars
|
|
249
|
-
|
|
250
|
-
fullMaxChars: options.snapshotLimits?.fullMaxChars
|
|
251
|
-
?? DEFAULT_SNAPSHOT_LIMITS.fullMaxChars,
|
|
240
|
+
viewportMaxChars: options.snapshotLimits?.viewportMaxChars ?? DEFAULT_SNAPSHOT_LIMITS.viewportMaxChars,
|
|
241
|
+
fullMaxChars: options.snapshotLimits?.fullMaxChars ?? DEFAULT_SNAPSHOT_LIMITS.fullMaxChars,
|
|
252
242
|
};
|
|
253
243
|
const feedback = new ActionFeedback();
|
|
254
244
|
const controller = new PageController(limits, feedback);
|
|
@@ -285,7 +275,8 @@ export function createBrowserToolset(options = {}) {
|
|
|
285
275
|
const scope = normalizedInput.scope;
|
|
286
276
|
const deadline = performance.now() + limits.maxDurationMs;
|
|
287
277
|
signal.throwIfAborted();
|
|
288
|
-
return (await observe(scope, { deadline, signal }, pageDecision ? "actions" : "text"))
|
|
278
|
+
return (await observe(scope, { deadline, signal }, pageDecision ? "actions" : "text"))
|
|
279
|
+
.snapshot;
|
|
289
280
|
},
|
|
290
281
|
};
|
|
291
282
|
const executeObserved = async (signal, execute, cancel, mode = "code", onFeedback, assertActive) => {
|
|
@@ -316,7 +307,8 @@ export function createBrowserToolset(options = {}) {
|
|
|
316
307
|
}
|
|
317
308
|
result = await measurePagePhase("execution", () => execute(activeRegistry, workerBudget));
|
|
318
309
|
signal.throwIfAborted();
|
|
319
|
-
if (result.error &&
|
|
310
|
+
if (result.error &&
|
|
311
|
+
["EXECUTION_TIMEOUT", "WORKER_ERROR", "EXECUTION_OUTCOME_UNKNOWN"].includes(result.error.code)) {
|
|
320
312
|
result.error.code = "EXECUTION_OUTCOME_UNKNOWN";
|
|
321
313
|
}
|
|
322
314
|
if (!result.ok && result.completedActions.length === 0) {
|
|
@@ -325,9 +317,7 @@ export function createBrowserToolset(options = {}) {
|
|
|
325
317
|
try {
|
|
326
318
|
const settled = await measurePagePhase("settle", () => tracker.waitForSettle({ deadline, signal }));
|
|
327
319
|
signal.throwIfAborted();
|
|
328
|
-
if (settled.timedOut
|
|
329
|
-
&& settled.urlChanged
|
|
330
|
-
&& !settled.mutationObservedAfterUrlChange) {
|
|
320
|
+
if (settled.timedOut && settled.urlChanged && !settled.mutationObservedAfterUrlChange) {
|
|
331
321
|
result.snapshotUnavailable = true;
|
|
332
322
|
return expireRefs(result);
|
|
333
323
|
}
|
|
@@ -382,7 +372,9 @@ export function createBrowserToolset(options = {}) {
|
|
|
382
372
|
if (!bundle || bundle.snapshot.snapshotId !== input.snapshotId)
|
|
383
373
|
return undefined;
|
|
384
374
|
const selected = bundle.actions?.get(input.actionId);
|
|
385
|
-
if (!selected ||
|
|
375
|
+
if (!selected ||
|
|
376
|
+
selected.command.method === "scrollBy" ||
|
|
377
|
+
selected.command.method === "waitForTimeout")
|
|
386
378
|
return undefined;
|
|
387
379
|
const target = selected.command.target;
|
|
388
380
|
const element = target?.type === "ref" ? bundle.registry.refs.get(target.ref)?.element : undefined;
|
|
@@ -396,14 +388,21 @@ export function createBrowserToolset(options = {}) {
|
|
|
396
388
|
const selected = bundle.actions.get(input.actionId);
|
|
397
389
|
if (!selected)
|
|
398
390
|
throw new AgentToolError("INVALID_INPUT", "Action is not a candidate of this observation.");
|
|
399
|
-
if (selected.command.method === "fill"
|
|
391
|
+
if (selected.command.method === "fill"
|
|
392
|
+
? typeof input.text !== "string" || !input.text.trim()
|
|
393
|
+
: input.text !== undefined) {
|
|
400
394
|
throw new AgentToolError("INVALID_INPUT", "Only fill actions require a non-empty text value.");
|
|
401
395
|
}
|
|
402
396
|
if (selected.command.method === "selectOption") {
|
|
403
397
|
const target = selected.command.target;
|
|
404
398
|
const element = target.type === "ref" ? bundle.registry.refs.get(target.ref)?.element : undefined;
|
|
405
|
-
const options = element instanceof HTMLSelectElement
|
|
406
|
-
|
|
399
|
+
const options = element instanceof HTMLSelectElement
|
|
400
|
+
? [...element.options].filter((option) => option.value === selected.command.args[0])
|
|
401
|
+
: [];
|
|
402
|
+
if (options.length !== 1 ||
|
|
403
|
+
options[0].disabled ||
|
|
404
|
+
options[0].closest("optgroup[disabled]") ||
|
|
405
|
+
options[0].label.slice(0, 500) !== selected.candidate.option) {
|
|
407
406
|
throw new AgentToolError("INVALID_INPUT", "The observed option changed or is no longer available. Observe again.");
|
|
408
407
|
}
|
|
409
408
|
}
|
|
@@ -413,7 +412,9 @@ export function createBrowserToolset(options = {}) {
|
|
|
413
412
|
let timer;
|
|
414
413
|
try {
|
|
415
414
|
const command = {
|
|
416
|
-
...selected.command,
|
|
415
|
+
...selected.command,
|
|
416
|
+
executionId,
|
|
417
|
+
commandSeq: 1,
|
|
417
418
|
args: selected.command.method === "fill" ? [input.text] : selected.command.args,
|
|
418
419
|
};
|
|
419
420
|
const response = await Promise.race([
|
|
@@ -421,7 +422,8 @@ export function createBrowserToolset(options = {}) {
|
|
|
421
422
|
if (selected.optionElement) {
|
|
422
423
|
const target = selected.command.target;
|
|
423
424
|
const element = target.type === "ref" ? registry.refs.get(target.ref)?.element : undefined;
|
|
424
|
-
if (!selected.optionElement.isConnected ||
|
|
425
|
+
if (!selected.optionElement.isConnected ||
|
|
426
|
+
selected.optionElement.closest("select") !== element) {
|
|
425
427
|
throw new AgentToolError("INVALID_INPUT", "The observed option was replaced. Observe again.");
|
|
426
428
|
}
|
|
427
429
|
}
|
|
@@ -434,7 +436,12 @@ export function createBrowserToolset(options = {}) {
|
|
|
434
436
|
}),
|
|
435
437
|
]);
|
|
436
438
|
const receipt = controller.completeExecution(executionId);
|
|
437
|
-
return {
|
|
439
|
+
return {
|
|
440
|
+
executionId,
|
|
441
|
+
...receipt,
|
|
442
|
+
ok: response.ok,
|
|
443
|
+
...(response.error ? { error: response.error } : {}),
|
|
444
|
+
};
|
|
438
445
|
}
|
|
439
446
|
finally {
|
|
440
447
|
clearTimeout(timer);
|
|
@@ -449,4 +456,3 @@ export function createBrowserToolset(options = {}) {
|
|
|
449
456
|
handlers: new Map(toolHandlers.map((tool) => [tool.definition.name, tool])),
|
|
450
457
|
};
|
|
451
458
|
}
|
|
452
|
-
//# sourceMappingURL=toolset.js.map
|
package/dist/browser/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ObservedAction } from "./actions.js";
|
|
2
2
|
import type { PageSnapshot } from "../shared/page-protocol.js";
|
|
3
|
-
export type { SnapshotScope, SnapshotFormat, SemanticState, PageActionCandidate, PageSnapshot } from "../shared/page-protocol.js";
|
|
3
|
+
export type { SnapshotScope, SnapshotFormat, SemanticState, PageActionCandidate, PageSnapshot, } from "../shared/page-protocol.js";
|
|
4
4
|
export interface RefTarget {
|
|
5
5
|
element: Element;
|
|
6
6
|
identity: string;
|
package/dist/browser/types.js
CHANGED
package/dist/definition.d.ts
CHANGED
|
@@ -8,7 +8,5 @@ export declare function isValidAgentContextName(name: string): boolean;
|
|
|
8
8
|
export declare function defineAgentTool<TResult = unknown>(metadata: AgentToolMetadataInput): AgentToolDefinition<Record<string, never>, TResult>;
|
|
9
9
|
export declare function defineAgentTool<TInput = never, TResult = unknown, const TSchema extends AgentToolInputSchema = AgentToolInputSchema>(metadata: AgentToolMetadataInput & {
|
|
10
10
|
inputSchema: TSchema;
|
|
11
|
-
}): AgentToolDefinition<[
|
|
12
|
-
TInput
|
|
13
|
-
] extends [never] ? InferJsonSchema<TSchema> : TInput, TResult>;
|
|
11
|
+
}): AgentToolDefinition<[TInput] extends [never] ? InferJsonSchema<TSchema> : TInput, TResult>;
|
|
14
12
|
export {};
|
package/dist/definition.js
CHANGED
|
@@ -6,7 +6,8 @@ const emptyInputSchema = Object.freeze({
|
|
|
6
6
|
});
|
|
7
7
|
const agentNamePattern = /^[A-Za-z0-9_-]{1,64}$/;
|
|
8
8
|
const reservedContextNames = new Set([
|
|
9
|
-
"nxf_applyAction",
|
|
9
|
+
"nxf_applyAction",
|
|
10
|
+
"nxf_delegatePageTask",
|
|
10
11
|
"nxf_callAppTool",
|
|
11
12
|
"nxf_finish",
|
|
12
13
|
"nxf_getSnapshot",
|
|
@@ -33,4 +34,3 @@ export function defineAgentTool(metadata) {
|
|
|
33
34
|
inputSchema: metadata.inputSchema === undefined ? emptyInputSchema : metadata.inputSchema,
|
|
34
35
|
});
|
|
35
36
|
}
|
|
36
|
-
//# sourceMappingURL=definition.js.map
|
package/dist/index.browser.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -4,4 +4,3 @@ export { AgentOperationSurface } from "./operation-surface.js";
|
|
|
4
4
|
export { createToolRuntime, isToolRuntimeError, } from "./runtime.js";
|
|
5
5
|
export { AgentContext, ToolsProvider, AgentUIAction, useAgentContext, useAgentNavigation, useAgentTool, } from "./react.js";
|
|
6
6
|
export { registerAgentTool } from "./registration.js";
|
|
7
|
-
//# sourceMappingURL=index.js.map
|
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
|