@nexface/tools 0.1.13 → 0.1.14
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.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.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 +6 -9
- package/dist/registration.js +3 -2
- package/dist/runtime.d.ts +4 -2
- package/dist/runtime.js +103 -44
- package/dist/shared/definition.js +0 -1
- 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 +38 -12
- 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/types.js.map +0 -1
- package/dist/webmcp.js.map +0 -1
package/dist/runtime.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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";
|
|
7
8
|
import { OperationTracker } from "./operation-runtime.js";
|
|
8
9
|
import { isValidAgentContextName } from "./definition.js";
|
|
9
10
|
import { assertAgentToolInputSchema, validateAgentToolInput } from "./shared/schema.js";
|
|
10
|
-
import { createBrowserToolset
|
|
11
|
+
import { createBrowserToolset } from "./browser/toolset.js";
|
|
11
12
|
const CONTEXT_ERROR_CODES = [
|
|
12
13
|
"CONTEXT_DISPOSED",
|
|
13
14
|
"CONTEXT_NAME_MISMATCH",
|
|
@@ -20,9 +21,9 @@ export function isToolRuntimeError(error) {
|
|
|
20
21
|
if (!error || typeof error !== "object")
|
|
21
22
|
return false;
|
|
22
23
|
const candidate = error;
|
|
23
|
-
if (candidate.type !== "tool_runtime_error"
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
if (candidate.type !== "tool_runtime_error" ||
|
|
25
|
+
typeof candidate.message !== "string" ||
|
|
26
|
+
typeof candidate.code !== "string") {
|
|
26
27
|
return false;
|
|
27
28
|
}
|
|
28
29
|
if (candidate.domain === "tool") {
|
|
@@ -43,9 +44,7 @@ function assertContextName(name) {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
function normalizeContextValue(value, path = "value", seen = new WeakSet()) {
|
|
46
|
-
if (value === null
|
|
47
|
-
|| typeof value === "string"
|
|
48
|
-
|| typeof value === "boolean") {
|
|
47
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
49
48
|
return value;
|
|
50
49
|
}
|
|
51
50
|
if (typeof value === "number") {
|
|
@@ -82,8 +81,8 @@ function normalizeContextValue(value, path = "value", seen = new WeakSet()) {
|
|
|
82
81
|
}
|
|
83
82
|
function normalizeContext(context) {
|
|
84
83
|
assertContextName(context.name);
|
|
85
|
-
if (context.description !== undefined
|
|
86
|
-
|
|
84
|
+
if (context.description !== undefined &&
|
|
85
|
+
(typeof context.description !== "string" || !context.description.trim())) {
|
|
87
86
|
throw new AgentContextError("INVALID_CONTEXT", "Context description must be a non-empty string when provided.");
|
|
88
87
|
}
|
|
89
88
|
return {
|
|
@@ -123,6 +122,8 @@ export function getInternalToolRuntime(runtime) {
|
|
|
123
122
|
export class ToolRuntimeImplementation extends EventTarget {
|
|
124
123
|
[toolRuntimeBrand] = true;
|
|
125
124
|
#bindings = new Map();
|
|
125
|
+
#routeSearch;
|
|
126
|
+
#visibleNavigation = new Set();
|
|
126
127
|
#contexts = new Map();
|
|
127
128
|
#contextRevision = 0;
|
|
128
129
|
#browserToolset;
|
|
@@ -136,16 +137,22 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
136
137
|
beginInternalOperation(options = {}) {
|
|
137
138
|
return this.#operations.begin(options);
|
|
138
139
|
}
|
|
139
|
-
endBridgeOperation(handle) {
|
|
140
|
+
endBridgeOperation(handle) {
|
|
141
|
+
return this.#operations.disposeBridge(handle);
|
|
142
|
+
}
|
|
140
143
|
setTaskProgress = (handle, progress) => this.#operations.setTaskProgress(handle, progress);
|
|
141
144
|
setOperationWaiting = (handle, waiting) => this.#operations.setWaitingForUser(handle, waiting);
|
|
142
145
|
getActivitySnapshot = () => this.#operations.getSnapshot();
|
|
143
146
|
subscribeActivity = (listener) => this.#operations.subscribe(listener);
|
|
144
|
-
requestOperationCancel(id) {
|
|
147
|
+
requestOperationCancel(id) {
|
|
148
|
+
this.#operations.requestCancel(id);
|
|
149
|
+
}
|
|
145
150
|
setPageActionFeedback(listener) {
|
|
146
151
|
this.#pageActionFeedback = listener;
|
|
147
|
-
return () => {
|
|
148
|
-
this.#pageActionFeedback
|
|
152
|
+
return () => {
|
|
153
|
+
if (this.#pageActionFeedback === listener)
|
|
154
|
+
this.#pageActionFeedback = undefined;
|
|
155
|
+
};
|
|
149
156
|
}
|
|
150
157
|
#emitExecution(event) {
|
|
151
158
|
this.#operations.observe(event);
|
|
@@ -153,10 +160,40 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
153
160
|
}
|
|
154
161
|
constructor(options = {}) {
|
|
155
162
|
super();
|
|
156
|
-
if (options.pageAutomation !== undefined &&
|
|
157
|
-
typeof options.pageAutomation !== "boolean") {
|
|
163
|
+
if (options.pageAutomation !== undefined && typeof options.pageAutomation !== "boolean") {
|
|
158
164
|
throw new AgentToolError("INVALID_INPUT", "pageAutomation must be a boolean.");
|
|
159
165
|
}
|
|
166
|
+
if (options.routeSearch !== undefined && typeof options.routeSearch !== "boolean") {
|
|
167
|
+
throw new AgentToolError("INVALID_INPUT", "routeSearch must be a boolean.");
|
|
168
|
+
}
|
|
169
|
+
this.#routeSearch = options.routeSearch ?? false;
|
|
170
|
+
if (this.#routeSearch)
|
|
171
|
+
this.register(searchToolDefinition, ({ query, queries }) => {
|
|
172
|
+
if (query !== undefined && queries !== undefined)
|
|
173
|
+
throw new AgentToolError("INVALID_INPUT", "Use either query or queries, not both.");
|
|
174
|
+
const searchQueries = queries === undefined ? (query === undefined ? undefined : [query]) : [...queries];
|
|
175
|
+
if (searchQueries?.some((phrase) => typeof phrase !== "string" || !phrase.trim()))
|
|
176
|
+
throw new AgentToolError("INVALID_INPUT", "Search queries must contain nonblank strings.");
|
|
177
|
+
const navigation = this.getRegisteredTools().filter(({ definition }) => definition.effect === "navigate");
|
|
178
|
+
const candidates = searchQueries === undefined
|
|
179
|
+
? navigation
|
|
180
|
+
: searchNavigationTools(navigation, searchQueries.map((phrase) => phrase.trim()));
|
|
181
|
+
if (searchQueries !== undefined) {
|
|
182
|
+
const previous = this.#visibleNavigation;
|
|
183
|
+
this.#visibleNavigation = new Set(candidates);
|
|
184
|
+
for (const tool of new Set([...previous, ...candidates])) {
|
|
185
|
+
if (previous.has(tool) === this.#visibleNavigation.has(tool))
|
|
186
|
+
continue;
|
|
187
|
+
this.dispatchEvent(new DetailEvent("toolchange", Object.freeze({
|
|
188
|
+
toolName: tool.definition.name,
|
|
189
|
+
change: "visibility",
|
|
190
|
+
})));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
tools: candidates.map(({ definition: { name, description } }) => ({ name, description })),
|
|
195
|
+
};
|
|
196
|
+
});
|
|
160
197
|
this.#browserToolset = options.pageAutomation ? createBrowserToolset() : undefined;
|
|
161
198
|
runtimeInternals.set(this, this);
|
|
162
199
|
const controller = Object.freeze({
|
|
@@ -165,6 +202,7 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
165
202
|
setTaskProgress: this.setTaskProgress,
|
|
166
203
|
getOperationSnapshot: () => this.getActivitySnapshot().operation,
|
|
167
204
|
subscribeOperation: this.subscribeActivity,
|
|
205
|
+
getRegisteredTools: () => this.getRegisteredTools(),
|
|
168
206
|
});
|
|
169
207
|
Object.defineProperty(this, runtimeControllerSymbol, { value: controller });
|
|
170
208
|
}
|
|
@@ -196,9 +234,7 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
196
234
|
definition,
|
|
197
235
|
get confirmation() {
|
|
198
236
|
const confirmation = options.getConfirmation?.();
|
|
199
|
-
return confirmation === undefined
|
|
200
|
-
? undefined
|
|
201
|
-
: Object.freeze({ ...confirmation });
|
|
237
|
+
return confirmation === undefined ? undefined : Object.freeze({ ...confirmation });
|
|
202
238
|
},
|
|
203
239
|
lifecycleSignal: lifecycleController.signal,
|
|
204
240
|
});
|
|
@@ -207,9 +243,7 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
207
243
|
definition,
|
|
208
244
|
runtimeTool,
|
|
209
245
|
execute,
|
|
210
|
-
...(options.getConfirmation
|
|
211
|
-
? { getConfirmation: options.getConfirmation }
|
|
212
|
-
: {}),
|
|
246
|
+
...(options.getConfirmation ? { getConfirmation: options.getConfirmation } : {}),
|
|
213
247
|
lifecycleController,
|
|
214
248
|
};
|
|
215
249
|
this.#bindings.set(definition.name, binding);
|
|
@@ -224,6 +258,7 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
224
258
|
disposed = true;
|
|
225
259
|
options.signal?.removeEventListener("abort", dispose);
|
|
226
260
|
this.#bindings.delete(definition.name);
|
|
261
|
+
this.#visibleNavigation.delete(runtimeTool);
|
|
227
262
|
lifecycleController.abort();
|
|
228
263
|
this.dispatchEvent(new DetailEvent("toolchange", Object.freeze({
|
|
229
264
|
toolName: definition.name,
|
|
@@ -337,21 +372,27 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
337
372
|
revision: this.#contextRevision,
|
|
338
373
|
}));
|
|
339
374
|
}
|
|
375
|
+
getRegisteredTools() {
|
|
376
|
+
return [...this.#bindings.values()]
|
|
377
|
+
.map(({ runtimeTool }) => runtimeTool)
|
|
378
|
+
.filter(({ definition }) => !this.#routeSearch || definition !== searchToolDefinition)
|
|
379
|
+
.sort((left, right) => compareStrings(left.definition.name, right.definition.name));
|
|
380
|
+
}
|
|
340
381
|
getWebMcpTools() {
|
|
341
382
|
return [...this.#bindings.values()]
|
|
342
383
|
.map(({ runtimeTool }) => runtimeTool)
|
|
384
|
+
.filter((tool) => !this.#routeSearch ||
|
|
385
|
+
tool.definition.effect !== "navigate" ||
|
|
386
|
+
this.#visibleNavigation.has(tool))
|
|
343
387
|
.sort((left, right) => compareStrings(left.definition.name, right.definition.name));
|
|
344
388
|
}
|
|
345
389
|
isRegistered(name) {
|
|
346
390
|
return this.#bindings.has(name);
|
|
347
391
|
}
|
|
348
392
|
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));
|
|
393
|
+
const applicationTools = this.getWebMcpTools();
|
|
394
|
+
const browserTools = (this.#browserToolset?.definitions ?? []).map((definition) => this.#getBrowserRuntimeTool(definition));
|
|
395
|
+
return [...applicationTools, ...browserTools].sort((left, right) => compareStrings(left.definition.name, right.definition.name));
|
|
355
396
|
}
|
|
356
397
|
waitForTool(definition, options = {}) {
|
|
357
398
|
const isTargetRegistered = () => this.#bindings.has(definition.name);
|
|
@@ -374,8 +415,7 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
374
415
|
};
|
|
375
416
|
const onToolChange = (event) => {
|
|
376
417
|
const detail = event.detail;
|
|
377
|
-
if (detail?.toolName !== definition.name
|
|
378
|
-
|| detail.change !== "registered")
|
|
418
|
+
if (detail?.toolName !== definition.name || detail.change !== "registered")
|
|
379
419
|
return;
|
|
380
420
|
if (isTargetRegistered())
|
|
381
421
|
settle(resolve);
|
|
@@ -401,7 +441,11 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
401
441
|
}
|
|
402
442
|
execute(tool, input, options = {}) {
|
|
403
443
|
const label = options.progressLabel?.trim().replace(/\s+/g, " ").slice(0, 48);
|
|
404
|
-
options = {
|
|
444
|
+
options = {
|
|
445
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
446
|
+
...(label ? { progressLabel: label } : {}),
|
|
447
|
+
...(options[pageDecisionSymbol] ? { [pageDecisionSymbol]: true } : {}),
|
|
448
|
+
};
|
|
405
449
|
const definition = tool.definition;
|
|
406
450
|
const name = definition.name;
|
|
407
451
|
const binding = this.#bindings.get(name);
|
|
@@ -417,8 +461,8 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
417
461
|
if (!browserHandler) {
|
|
418
462
|
return Promise.reject(new AgentToolError("UNKNOWN_TOOL", `Unknown tool: ${name}.`));
|
|
419
463
|
}
|
|
420
|
-
if (!browserToolset?.definitions.some((candidate) => candidate === definition)
|
|
421
|
-
|
|
464
|
+
if (!browserToolset?.definitions.some((candidate) => candidate === definition) ||
|
|
465
|
+
this.#getBrowserRuntimeTool(definition) !== tool) {
|
|
422
466
|
return Promise.reject(new AgentToolError("CONTRACT_MISMATCH", `Tool "${name}" is registered with a different Definition.`));
|
|
423
467
|
}
|
|
424
468
|
return this.#enqueue((operationId) => this.#observeExecution(tool, input, options.signal, async (onFeedback, assertActive) => {
|
|
@@ -460,7 +504,9 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
460
504
|
};
|
|
461
505
|
// Reserve the tail before invoking executors or notifying synchronous listeners.
|
|
462
506
|
let settleTail;
|
|
463
|
-
const tail = new Promise((resolve) => {
|
|
507
|
+
const tail = new Promise((resolve) => {
|
|
508
|
+
settleTail = resolve;
|
|
509
|
+
});
|
|
464
510
|
this.#executionTail = tail;
|
|
465
511
|
const queuedExecution = previous ? previous.then(start) : start();
|
|
466
512
|
let execution = queuedExecution;
|
|
@@ -492,9 +538,13 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
492
538
|
const target = binding.resolveTarget?.(input);
|
|
493
539
|
return target?.isConnected ? target : undefined;
|
|
494
540
|
}
|
|
495
|
-
if (this.#browserRuntimeTools.get(tool.definition) !== tool ||
|
|
541
|
+
if (this.#browserRuntimeTools.get(tool.definition) !== tool ||
|
|
542
|
+
!input ||
|
|
543
|
+
typeof input !== "object")
|
|
496
544
|
return undefined;
|
|
497
|
-
return this.#browserToolset?.handlers
|
|
545
|
+
return this.#browserToolset?.handlers
|
|
546
|
+
.get(tool.definition.name)
|
|
547
|
+
?.resolveTarget?.(input);
|
|
498
548
|
}
|
|
499
549
|
async #observeExecution(tool, input, signal, execute, progressLabel, operationId) {
|
|
500
550
|
const running = {
|
|
@@ -511,7 +561,10 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
511
561
|
const assertActive = () => {
|
|
512
562
|
signal?.throwIfAborted();
|
|
513
563
|
if (presentation && this.#pageActionFeedback !== presentation) {
|
|
514
|
-
throw new PageCommandError({
|
|
564
|
+
throw new PageCommandError({
|
|
565
|
+
code: "EXECUTION_CANCELLED",
|
|
566
|
+
message: "Page action presentation was detached.",
|
|
567
|
+
});
|
|
515
568
|
}
|
|
516
569
|
};
|
|
517
570
|
this.#emitExecution(running);
|
|
@@ -520,26 +573,33 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
520
573
|
const result = await execute(async (feedback) => {
|
|
521
574
|
assertActive();
|
|
522
575
|
if (presentation)
|
|
523
|
-
await measurePagePhase("presentation", async () => {
|
|
576
|
+
await measurePagePhase("presentation", async () => {
|
|
577
|
+
await presentation(running, feedback, signal);
|
|
578
|
+
});
|
|
524
579
|
assertActive();
|
|
525
580
|
}, assertActive);
|
|
526
581
|
signal?.throwIfAborted();
|
|
527
582
|
this.#emitExecution({
|
|
528
|
-
...running,
|
|
583
|
+
...running,
|
|
584
|
+
status: "success",
|
|
585
|
+
finishedAt: Date.now(),
|
|
586
|
+
result,
|
|
529
587
|
});
|
|
530
588
|
return result;
|
|
531
589
|
}
|
|
532
590
|
catch (error) {
|
|
533
591
|
this.#emitExecution({
|
|
534
|
-
...running,
|
|
535
|
-
|
|
592
|
+
...running,
|
|
593
|
+
status: "error",
|
|
594
|
+
cancelled: signal?.aborted === true,
|
|
595
|
+
finishedAt: Date.now(),
|
|
596
|
+
error,
|
|
536
597
|
});
|
|
537
598
|
throw error;
|
|
538
599
|
}
|
|
539
600
|
}
|
|
540
601
|
async #executeApplication(name, input, options, binding, operationId) {
|
|
541
|
-
const id = globalThis.crypto?.randomUUID?.()
|
|
542
|
-
?? `${Date.now()}-${Math.random()}`;
|
|
602
|
+
const id = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
|
|
543
603
|
const startedAt = Date.now();
|
|
544
604
|
const running = {
|
|
545
605
|
...(operationId ? { operationId } : {}),
|
|
@@ -599,4 +659,3 @@ export class ToolRuntimeImplementation extends EventTarget {
|
|
|
599
659
|
return runtimeTool;
|
|
600
660
|
}
|
|
601
661
|
}
|
|
602
|
-
//# sourceMappingURL=runtime.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;
|
package/dist/shared/schema.js
CHANGED
|
@@ -3,8 +3,17 @@ const types = new Set(["object", "array", "string", "number", "integer", "boolea
|
|
|
3
3
|
const counts = ["minLength", "maxLength", "minItems", "maxItems"];
|
|
4
4
|
const bounds = ["minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum"];
|
|
5
5
|
const keywords = new Set([
|
|
6
|
-
"type",
|
|
7
|
-
|
|
6
|
+
"type",
|
|
7
|
+
"description",
|
|
8
|
+
"properties",
|
|
9
|
+
"required",
|
|
10
|
+
"items",
|
|
11
|
+
"enum",
|
|
12
|
+
"additionalProperties",
|
|
13
|
+
...counts,
|
|
14
|
+
...bounds,
|
|
15
|
+
"pattern",
|
|
16
|
+
"uniqueItems",
|
|
8
17
|
]);
|
|
9
18
|
const checkedSchemas = new WeakSet();
|
|
10
19
|
const patterns = new WeakMap();
|
|
@@ -24,7 +33,9 @@ function assertJson(value, path, ancestors = new Set()) {
|
|
|
24
33
|
invalid(path, "must be JSON-compatible.");
|
|
25
34
|
if (ancestors.has(value))
|
|
26
35
|
invalid(path, "must not contain circular references.");
|
|
27
|
-
if (!Array.isArray(value) &&
|
|
36
|
+
if (!Array.isArray(value) &&
|
|
37
|
+
Object.getPrototypeOf(value) !== Object.prototype &&
|
|
38
|
+
Object.getPrototypeOf(value) !== null) {
|
|
28
39
|
invalid(path, "must be a plain JSON object.");
|
|
29
40
|
}
|
|
30
41
|
if (Object.getOwnPropertySymbols(value).length)
|
|
@@ -85,7 +96,8 @@ function assertSchema(value, path) {
|
|
|
85
96
|
invalid(`${path}.${key}`, "must be a non-negative integer.");
|
|
86
97
|
}
|
|
87
98
|
for (const key of bounds) {
|
|
88
|
-
if (value[key] !== undefined &&
|
|
99
|
+
if (value[key] !== undefined &&
|
|
100
|
+
(typeof value[key] !== "number" || !Number.isFinite(value[key])))
|
|
89
101
|
invalid(`${path}.${key}`, "must be a finite number.");
|
|
90
102
|
}
|
|
91
103
|
if (value.pattern !== undefined) {
|
|
@@ -95,7 +107,8 @@ function assertSchema(value, path) {
|
|
|
95
107
|
}
|
|
96
108
|
if (value.enum !== undefined && (!Array.isArray(value.enum) || value.enum.length === 0))
|
|
97
109
|
invalid(`${path}.enum`, "must be a non-empty array.");
|
|
98
|
-
if (Array.isArray(value.enum) &&
|
|
110
|
+
if (Array.isArray(value.enum) &&
|
|
111
|
+
value.enum.some((item, index, entries) => entries.slice(0, index).some((other) => jsonEqual(item, other))))
|
|
99
112
|
invalid(`${path}.enum`, "must contain unique values.");
|
|
100
113
|
if (value.properties !== undefined) {
|
|
101
114
|
if (value.type !== "object" || !isRecord(value.properties))
|
|
@@ -104,7 +117,10 @@ function assertSchema(value, path) {
|
|
|
104
117
|
assertSchema(property, `${path}.properties.${name}`);
|
|
105
118
|
}
|
|
106
119
|
if (value.required !== undefined) {
|
|
107
|
-
if (value.type !== "object" ||
|
|
120
|
+
if (value.type !== "object" ||
|
|
121
|
+
!Array.isArray(value.required) ||
|
|
122
|
+
value.required.some((name) => typeof name !== "string") ||
|
|
123
|
+
new Set(value.required).size !== value.required.length)
|
|
108
124
|
invalid(`${path}.required`, "must contain unique property names.");
|
|
109
125
|
const properties = value.properties;
|
|
110
126
|
if (value.required.some((name) => !properties || !Object.hasOwn(properties, name)))
|
|
@@ -118,7 +134,7 @@ function assertSchema(value, path) {
|
|
|
118
134
|
}
|
|
119
135
|
export function assertAgentToolInputSchema(value, path = "inputSchema") {
|
|
120
136
|
if (!isRecord(value) || value.type !== "object")
|
|
121
|
-
invalid(path,
|
|
137
|
+
invalid(path, "root type must be object.");
|
|
122
138
|
if (checkedSchemas.has(value))
|
|
123
139
|
return;
|
|
124
140
|
const frozen = assertJson(value, path);
|
|
@@ -130,21 +146,29 @@ function jsonEqual(left, right) {
|
|
|
130
146
|
if (left === right)
|
|
131
147
|
return true;
|
|
132
148
|
if (Array.isArray(left) && Array.isArray(right))
|
|
133
|
-
return left.length === right.length && left.every((item, index) => jsonEqual(item, right[index]));
|
|
149
|
+
return (left.length === right.length && left.every((item, index) => jsonEqual(item, right[index])));
|
|
134
150
|
if (!isRecord(left) || !isRecord(right))
|
|
135
151
|
return false;
|
|
136
152
|
const keys = Object.keys(left);
|
|
137
|
-
return keys.length === Object.keys(right).length &&
|
|
153
|
+
return (keys.length === Object.keys(right).length &&
|
|
154
|
+
keys.every((key) => Object.hasOwn(right, key) && jsonEqual(left[key], right[key])));
|
|
138
155
|
}
|
|
139
156
|
function typeMatches(schema, value) {
|
|
140
157
|
switch (schema.type) {
|
|
141
|
-
case undefined:
|
|
142
|
-
|
|
143
|
-
case "
|
|
144
|
-
|
|
145
|
-
case "
|
|
146
|
-
|
|
147
|
-
|
|
158
|
+
case undefined:
|
|
159
|
+
return true;
|
|
160
|
+
case "null":
|
|
161
|
+
return value === null;
|
|
162
|
+
case "array":
|
|
163
|
+
return Array.isArray(value);
|
|
164
|
+
case "object":
|
|
165
|
+
return isRecord(value);
|
|
166
|
+
case "integer":
|
|
167
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
168
|
+
case "number":
|
|
169
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
170
|
+
default:
|
|
171
|
+
return typeof value === schema.type;
|
|
148
172
|
}
|
|
149
173
|
}
|
|
150
174
|
export function validateAgentToolInput(schema, value, path = "input") {
|
|
@@ -177,7 +201,8 @@ export function validateAgentToolInput(schema, value, path = "input") {
|
|
|
177
201
|
errors.push(`${path} must have at least ${schema.minItems} items.`);
|
|
178
202
|
if (schema.maxItems !== undefined && value.length > schema.maxItems)
|
|
179
203
|
errors.push(`${path} must have at most ${schema.maxItems} items.`);
|
|
180
|
-
if (schema.uniqueItems &&
|
|
204
|
+
if (schema.uniqueItems &&
|
|
205
|
+
value.some((item, index) => value.slice(0, index).some((other) => jsonEqual(item, other))))
|
|
181
206
|
errors.push(`${path} must contain unique items.`);
|
|
182
207
|
if (schema.items)
|
|
183
208
|
value.forEach((item, index) => errors.push(...validateAgentToolInput(schema.items, item, `${path}[${index}]`)));
|
|
@@ -188,7 +213,9 @@ export function validateAgentToolInput(schema, value, path = "input") {
|
|
|
188
213
|
errors.push(`${path}.${key} is required.`);
|
|
189
214
|
}
|
|
190
215
|
for (const [key, item] of Object.entries(value)) {
|
|
191
|
-
const property = schema.properties && Object.hasOwn(schema.properties, key)
|
|
216
|
+
const property = schema.properties && Object.hasOwn(schema.properties, key)
|
|
217
|
+
? schema.properties[key]
|
|
218
|
+
: undefined;
|
|
192
219
|
if (property)
|
|
193
220
|
errors.push(...validateAgentToolInput(property, item, `${path}.${key}`));
|
|
194
221
|
else if (schema.additionalProperties === false)
|
|
@@ -197,4 +224,3 @@ export function validateAgentToolInput(schema, value, path = "input") {
|
|
|
197
224
|
}
|
|
198
225
|
return errors;
|
|
199
226
|
}
|
|
200
|
-
//# sourceMappingURL=schema.js.map
|