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