@nexface/tools 0.1.1-alpha.1 → 0.1.1-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.
Files changed (76) hide show
  1. package/dist/browser/controller.js +5 -4
  2. package/dist/browser/controller.js.map +1 -1
  3. package/dist/browser/dom.js +1 -2
  4. package/dist/browser/dom.js.map +1 -1
  5. package/dist/browser/feedback.js.map +1 -1
  6. package/dist/browser/focus.d.ts +2 -0
  7. package/dist/browser/focus.js +15 -0
  8. package/dist/browser/focus.js.map +1 -0
  9. package/dist/browser/locator.js.map +1 -1
  10. package/dist/browser/prompt.d.ts +1 -1
  11. package/dist/browser/prompt.generated.d.ts +1 -1
  12. package/dist/browser/prompt.generated.js +2 -2
  13. package/dist/browser/prompt.generated.js.map +1 -1
  14. package/dist/browser/prompt.js.map +1 -1
  15. package/dist/browser/snapshot.js.map +1 -1
  16. package/dist/browser/toolset.d.ts +12 -6
  17. package/dist/browser/toolset.js +18 -7
  18. package/dist/browser/toolset.js.map +1 -1
  19. package/dist/browser/types.js.map +1 -1
  20. package/dist/browser/worker-runner.js.map +1 -1
  21. package/dist/definition.js +10 -5
  22. package/dist/definition.js.map +1 -1
  23. package/dist/errors.d.ts +10 -0
  24. package/dist/errors.js +34 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/index.browser.d.ts +3 -0
  27. package/dist/index.browser.js +4 -0
  28. package/dist/index.browser.js.map +1 -0
  29. package/dist/index.d.ts +4 -3
  30. package/dist/index.js +2 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/internal-react.d.ts +1 -1
  33. package/dist/internal-react.js +0 -1
  34. package/dist/internal-react.js.map +1 -1
  35. package/dist/internal-types.d.ts +1 -0
  36. package/dist/internal-types.js.map +1 -1
  37. package/dist/internal.d.ts +3 -2
  38. package/dist/internal.js +1 -0
  39. package/dist/internal.js.map +1 -1
  40. package/dist/navigation.js.map +1 -1
  41. package/dist/operation-lock.d.ts +3 -0
  42. package/dist/operation-lock.js +46 -0
  43. package/dist/operation-lock.js.map +1 -0
  44. package/dist/operation-runtime.d.ts +44 -0
  45. package/dist/operation-runtime.js +153 -0
  46. package/dist/operation-runtime.js.map +1 -0
  47. package/dist/operation-surface.d.ts +1 -1
  48. package/dist/operation-surface.js +109 -65
  49. package/dist/operation-surface.js.map +1 -1
  50. package/dist/operation-types.d.ts +1 -1
  51. package/dist/operation-types.js.map +1 -1
  52. package/dist/operation-view.d.ts +8 -2
  53. package/dist/operation-view.js +30 -61
  54. package/dist/operation-view.js.map +1 -1
  55. package/dist/react.js.map +1 -1
  56. package/dist/registration.d.ts +11 -0
  57. package/dist/registration.js +12 -0
  58. package/dist/registration.js.map +1 -0
  59. package/dist/runtime.d.ts +45 -12
  60. package/dist/runtime.js +73 -81
  61. package/dist/runtime.js.map +1 -1
  62. package/dist/schema.d.ts +1 -0
  63. package/dist/schema.js +185 -32
  64. package/dist/schema.js.map +1 -1
  65. package/dist/styles.css +11 -7
  66. package/dist/types.d.ts +11 -1
  67. package/dist/types.js.map +1 -1
  68. package/dist/webmcp.js +163 -9
  69. package/dist/webmcp.js.map +1 -1
  70. package/package.json +7 -12
  71. package/dist/operation-host.d.ts +0 -17
  72. package/dist/operation-host.js +0 -9
  73. package/dist/operation-host.js.map +0 -1
  74. package/dist/react-entry.d.ts +0 -2
  75. package/dist/react-entry.js +0 -3
  76. package/dist/react-entry.js.map +0 -1
package/dist/schema.js CHANGED
@@ -1,44 +1,197 @@
1
+ const types = new Set(["object", "array", "string", "number", "integer", "boolean", "null"]);
2
+ const counts = ["minLength", "maxLength", "minItems", "maxItems"];
3
+ const bounds = ["minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum"];
4
+ const keywords = new Set([
5
+ "type", "description", "properties", "required", "items", "enum", "additionalProperties",
6
+ ...counts, ...bounds, "pattern", "uniqueItems",
7
+ ]);
8
+ const checkedSchemas = new WeakSet();
9
+ const patterns = new WeakMap();
10
+ function invalid(path, message) {
11
+ throw new TypeError(`${path} ${message}`);
12
+ }
13
+ function isRecord(value) {
14
+ return value !== null && typeof value === "object" && !Array.isArray(value);
15
+ }
16
+ // Only deeply frozen, JSON-compatible values can safely share validation results.
17
+ function assertJson(value, path, ancestors = new Set()) {
18
+ if (value === null || typeof value === "string" || typeof value === "boolean")
19
+ return true;
20
+ if (typeof value === "number" && Number.isFinite(value))
21
+ return true;
22
+ if (typeof value !== "object" || value === null)
23
+ invalid(path, "must be JSON-compatible.");
24
+ if (ancestors.has(value))
25
+ invalid(path, "must not contain circular references.");
26
+ if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
27
+ invalid(path, "must be a plain JSON object.");
28
+ }
29
+ if (Object.getOwnPropertySymbols(value).length)
30
+ invalid(path, "must not contain symbol properties.");
31
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
32
+ if (!descriptor.enumerable && !(Array.isArray(value) && key === "length"))
33
+ invalid(`${path}.${key}`, "must be enumerable.");
34
+ if (descriptor.get || descriptor.set)
35
+ invalid(`${path}.${key}`, "must be a data property.");
36
+ }
37
+ if (Array.isArray(value)) {
38
+ for (let index = 0; index < value.length; index++) {
39
+ if (!Object.hasOwn(value, index))
40
+ invalid(`${path}[${index}]`, "must not be a sparse array slot.");
41
+ }
42
+ }
43
+ ancestors.add(value);
44
+ let frozen = Object.isFrozen(value);
45
+ for (const [key, child] of Object.entries(value)) {
46
+ const childFrozen = assertJson(child, `${path}.${key}`, ancestors);
47
+ frozen = frozen && childFrozen;
48
+ }
49
+ ancestors.delete(value);
50
+ return frozen;
51
+ }
52
+ function patternFor(schema, path) {
53
+ const source = schema.pattern;
54
+ const cached = patterns.get(schema);
55
+ if (cached?.source === source)
56
+ return cached.regex;
57
+ let regex;
58
+ try {
59
+ regex = new RegExp(source, "u");
60
+ }
61
+ catch {
62
+ invalid(`${path}.pattern`, "must be a valid Unicode regular expression.");
63
+ }
64
+ patterns.set(schema, { source, regex });
65
+ return regex;
66
+ }
67
+ function assertSchema(value, path) {
68
+ if (!isRecord(value))
69
+ invalid(path, "must be an object.");
70
+ const unexpected = Object.keys(value).filter((key) => !keywords.has(key));
71
+ if (unexpected.length)
72
+ invalid(path, `has unsupported fields: ${unexpected.join(", ")}.`);
73
+ if (value.type !== undefined && (typeof value.type !== "string" || !types.has(value.type)))
74
+ invalid(`${path}.type`, "is not supported.");
75
+ if (value.description !== undefined && typeof value.description !== "string")
76
+ invalid(`${path}.description`, "must be a string.");
77
+ for (const key of ["additionalProperties", "uniqueItems"]) {
78
+ if (value[key] !== undefined && typeof value[key] !== "boolean")
79
+ invalid(`${path}.${key}`, "must be a boolean.");
80
+ }
81
+ for (const key of counts) {
82
+ const count = value[key];
83
+ if (count !== undefined && (typeof count !== "number" || !Number.isInteger(count) || count < 0))
84
+ invalid(`${path}.${key}`, "must be a non-negative integer.");
85
+ }
86
+ for (const key of bounds) {
87
+ if (value[key] !== undefined && (typeof value[key] !== "number" || !Number.isFinite(value[key])))
88
+ invalid(`${path}.${key}`, "must be a finite number.");
89
+ }
90
+ if (value.pattern !== undefined) {
91
+ if (typeof value.pattern !== "string")
92
+ invalid(`${path}.pattern`, "must be a string.");
93
+ patternFor(value, path);
94
+ }
95
+ if (value.enum !== undefined && (!Array.isArray(value.enum) || value.enum.length === 0))
96
+ invalid(`${path}.enum`, "must be a non-empty array.");
97
+ if (Array.isArray(value.enum) && value.enum.some((item, index, entries) => entries.slice(0, index).some((other) => jsonEqual(item, other))))
98
+ invalid(`${path}.enum`, "must contain unique values.");
99
+ if (value.properties !== undefined) {
100
+ if (value.type !== "object" || !isRecord(value.properties))
101
+ invalid(`${path}.properties`, "requires an object schema.");
102
+ for (const [name, property] of Object.entries(value.properties))
103
+ assertSchema(property, `${path}.properties.${name}`);
104
+ }
105
+ if (value.required !== undefined) {
106
+ if (value.type !== "object" || !Array.isArray(value.required) || value.required.some((name) => typeof name !== "string") || new Set(value.required).size !== value.required.length)
107
+ invalid(`${path}.required`, "must contain unique property names.");
108
+ const properties = value.properties;
109
+ if (value.required.some((name) => !properties || !Object.hasOwn(properties, name)))
110
+ invalid(`${path}.required`, "must reference declared properties.");
111
+ }
112
+ if (value.items !== undefined) {
113
+ if (value.type !== "array")
114
+ invalid(`${path}.items`, "requires an array schema.");
115
+ assertSchema(value.items, `${path}.items`);
116
+ }
117
+ }
118
+ export function assertAgentToolInputSchema(value, path = "inputSchema") {
119
+ if (!isRecord(value) || value.type !== "object")
120
+ invalid(path, 'root type must be object.');
121
+ if (checkedSchemas.has(value))
122
+ return;
123
+ const frozen = assertJson(value, path);
124
+ assertSchema(value, path);
125
+ if (frozen)
126
+ checkedSchemas.add(value);
127
+ }
128
+ function jsonEqual(left, right) {
129
+ if (left === right)
130
+ return true;
131
+ if (Array.isArray(left) && Array.isArray(right))
132
+ return left.length === right.length && left.every((item, index) => jsonEqual(item, right[index]));
133
+ if (!isRecord(left) || !isRecord(right))
134
+ return false;
135
+ const keys = Object.keys(left);
136
+ return keys.length === Object.keys(right).length && keys.every((key) => Object.hasOwn(right, key) && jsonEqual(left[key], right[key]));
137
+ }
1
138
  function typeMatches(schema, value) {
2
139
  switch (schema.type) {
3
- case undefined:
4
- return true;
5
- case "null":
6
- return value === null;
7
- case "array":
8
- return Array.isArray(value);
9
- case "object":
10
- return value !== null && typeof value === "object" && !Array.isArray(value);
11
- case "integer":
12
- return typeof value === "number" && Number.isInteger(value);
13
- default:
14
- return typeof value === schema.type;
140
+ case undefined: return true;
141
+ case "null": return value === null;
142
+ case "array": return Array.isArray(value);
143
+ case "object": return isRecord(value);
144
+ case "integer": return typeof value === "number" && Number.isInteger(value);
145
+ case "number": return typeof value === "number" && Number.isFinite(value);
146
+ default: return typeof value === schema.type;
15
147
  }
16
148
  }
17
149
  export function validateAgentToolInput(schema, value, path = "input") {
18
- if (!typeMatches(schema, value)) {
150
+ if (!typeMatches(schema, value))
19
151
  return [`${path} must be ${schema.type}.`];
152
+ const errors = [];
153
+ if (schema.enum && !schema.enum.some((item) => jsonEqual(item, value)))
154
+ errors.push(`${path} must be one of the declared enum values.`);
155
+ if (typeof value === "string") {
156
+ const length = Array.from(value).length;
157
+ if (schema.minLength !== undefined && length < schema.minLength)
158
+ errors.push(`${path} must have at least ${schema.minLength} characters.`);
159
+ if (schema.maxLength !== undefined && length > schema.maxLength)
160
+ errors.push(`${path} must have at most ${schema.maxLength} characters.`);
161
+ if (schema.pattern !== undefined && !patternFor(schema, path).test(value))
162
+ errors.push(`${path} must match pattern ${schema.pattern}.`);
20
163
  }
21
- if (schema.enum && !schema.enum.some((item) => Object.is(item, value))) {
22
- return [`${path} must be one of the declared enum values.`];
23
- }
24
- if (schema.type === "array" && Array.isArray(value) && schema.items) {
25
- return value.flatMap((item, index) => validateAgentToolInput(schema.items, item, `${path}[${index}]`));
164
+ if (typeof value === "number") {
165
+ if (schema.minimum !== undefined && value < schema.minimum)
166
+ errors.push(`${path} must be >= ${schema.minimum}.`);
167
+ if (schema.maximum !== undefined && value > schema.maximum)
168
+ errors.push(`${path} must be <= ${schema.maximum}.`);
169
+ if (schema.exclusiveMinimum !== undefined && value <= schema.exclusiveMinimum)
170
+ errors.push(`${path} must be > ${schema.exclusiveMinimum}.`);
171
+ if (schema.exclusiveMaximum !== undefined && value >= schema.exclusiveMaximum)
172
+ errors.push(`${path} must be < ${schema.exclusiveMaximum}.`);
26
173
  }
27
- if (schema.type !== "object" || value === null || typeof value !== "object") {
28
- return [];
174
+ if (Array.isArray(value)) {
175
+ if (schema.minItems !== undefined && value.length < schema.minItems)
176
+ errors.push(`${path} must have at least ${schema.minItems} items.`);
177
+ if (schema.maxItems !== undefined && value.length > schema.maxItems)
178
+ errors.push(`${path} must have at most ${schema.maxItems} items.`);
179
+ if (schema.uniqueItems && value.some((item, index) => value.slice(0, index).some((other) => jsonEqual(item, other))))
180
+ errors.push(`${path} must contain unique items.`);
181
+ if (schema.items)
182
+ value.forEach((item, index) => errors.push(...validateAgentToolInput(schema.items, item, `${path}[${index}]`)));
29
183
  }
30
- const record = value;
31
- const errors = [];
32
- for (const key of schema.required ?? []) {
33
- if (!(key in record))
34
- errors.push(`${path}.${key} is required.`);
35
- }
36
- for (const [key, item] of Object.entries(record)) {
37
- const property = schema.properties?.[key];
38
- if (property)
39
- errors.push(...validateAgentToolInput(property, item, `${path}.${key}`));
40
- else if (schema.additionalProperties === false) {
41
- errors.push(`${path}.${key} is not allowed.`);
184
+ if (isRecord(value)) {
185
+ for (const key of schema.required ?? []) {
186
+ if (!Object.hasOwn(value, key))
187
+ errors.push(`${path}.${key} is required.`);
188
+ }
189
+ for (const [key, item] of Object.entries(value)) {
190
+ const property = schema.properties && Object.hasOwn(schema.properties, key) ? schema.properties[key] : undefined;
191
+ if (property)
192
+ errors.push(...validateAgentToolInput(property, item, `${path}.${key}`));
193
+ else if (schema.additionalProperties === false)
194
+ errors.push(`${path}.${key} is not allowed.`);
42
195
  }
43
196
  }
44
197
  return errors;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAEA,SAAS,WAAW,CAAC,MAAkB,EAAE,KAAc;IACrD,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,IAAI,CAAC;QACd,KAAK,MAAM;YACT,OAAO,KAAK,KAAK,IAAI,CAAC;QACxB,KAAK,OAAO;YACV,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,KAAK,QAAQ;YACX,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9E,KAAK,SAAS;YACZ,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9D;YACE,OAAO,OAAO,KAAK,KAAK,MAAM,CAAC,IAAI,CAAC;IACxC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,MAAkB,EAClB,KAAc,EACd,IAAI,GAAG,OAAO;IAEd,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,IAAI,YAAY,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;QACvE,OAAO,CAAC,GAAG,IAAI,2CAA2C,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACpE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACnC,sBAAsB,CAAC,MAAM,CAAC,KAAM,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,KAAK,GAAG,CAAC,CACjE,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC5E,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,GAAG,eAAe,CAAC,CAAC;IACnE,CAAC;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,QAAQ;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;aAClF,IAAI,MAAM,CAAC,oBAAoB,KAAK,KAAK,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,GAAG,kBAAkB,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JsonSchema } from \"./types.js\";\n\nconst types = new Set([\"object\", \"array\", \"string\", \"number\", \"integer\", \"boolean\", \"null\"]);\nconst counts = [\"minLength\", \"maxLength\", \"minItems\", \"maxItems\"] as const;\nconst bounds = [\"minimum\", \"maximum\", \"exclusiveMinimum\", \"exclusiveMaximum\"] as const;\nconst keywords = new Set([\n \"type\", \"description\", \"properties\", \"required\", \"items\", \"enum\", \"additionalProperties\",\n ...counts, ...bounds, \"pattern\", \"uniqueItems\",\n]);\nconst checkedSchemas = new WeakSet<object>();\nconst patterns = new WeakMap<object, { source: string; regex: RegExp }>();\n\nfunction invalid(path: string, message: string): never {\n throw new TypeError(`${path} ${message}`);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n// Only deeply frozen, JSON-compatible values can safely share validation results.\nfunction assertJson(value: unknown, path: string, ancestors = new Set<object>()): boolean {\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") return true;\n if (typeof value === \"number\" && Number.isFinite(value)) return true;\n if (typeof value !== \"object\" || value === null) invalid(path, \"must be JSON-compatible.\");\n if (ancestors.has(value)) invalid(path, \"must not contain circular references.\");\n if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {\n invalid(path, \"must be a plain JSON object.\");\n }\n if (Object.getOwnPropertySymbols(value).length) invalid(path, \"must not contain symbol properties.\");\n for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {\n if (!descriptor.enumerable && !(Array.isArray(value) && key === \"length\")) invalid(`${path}.${key}`, \"must be enumerable.\");\n if (descriptor.get || descriptor.set) invalid(`${path}.${key}`, \"must be a data property.\");\n }\n if (Array.isArray(value)) {\n for (let index = 0; index < value.length; index++) {\n if (!Object.hasOwn(value, index)) invalid(`${path}[${index}]`, \"must not be a sparse array slot.\");\n }\n }\n ancestors.add(value);\n let frozen = Object.isFrozen(value);\n for (const [key, child] of Object.entries(value)) {\n const childFrozen = assertJson(child, `${path}.${key}`, ancestors);\n frozen = frozen && childFrozen;\n }\n ancestors.delete(value);\n return frozen;\n}\n\nfunction patternFor(schema: JsonSchema, path: string): RegExp {\n const source = schema.pattern!;\n const cached = patterns.get(schema);\n if (cached?.source === source) return cached.regex;\n let regex: RegExp;\n try {\n regex = new RegExp(source, \"u\");\n } catch {\n invalid(`${path}.pattern`, \"must be a valid Unicode regular expression.\");\n }\n patterns.set(schema, { source, regex });\n return regex;\n}\n\nfunction assertSchema(value: unknown, path: string): void {\n if (!isRecord(value)) invalid(path, \"must be an object.\");\n const unexpected = Object.keys(value).filter((key) => !keywords.has(key));\n if (unexpected.length) invalid(path, `has unsupported fields: ${unexpected.join(\", \")}.`);\n if (value.type !== undefined && (typeof value.type !== \"string\" || !types.has(value.type))) invalid(`${path}.type`, \"is not supported.\");\n if (value.description !== undefined && typeof value.description !== \"string\") invalid(`${path}.description`, \"must be a string.\");\n for (const key of [\"additionalProperties\", \"uniqueItems\"] as const) {\n if (value[key] !== undefined && typeof value[key] !== \"boolean\") invalid(`${path}.${key}`, \"must be a boolean.\");\n }\n for (const key of counts) {\n const count = value[key];\n if (count !== undefined && (typeof count !== \"number\" || !Number.isInteger(count) || count < 0)) invalid(`${path}.${key}`, \"must be a non-negative integer.\");\n }\n for (const key of bounds) {\n if (value[key] !== undefined && (typeof value[key] !== \"number\" || !Number.isFinite(value[key]))) invalid(`${path}.${key}`, \"must be a finite number.\");\n }\n if (value.pattern !== undefined) {\n if (typeof value.pattern !== \"string\") invalid(`${path}.pattern`, \"must be a string.\");\n patternFor(value as JsonSchema, path);\n }\n if (value.enum !== undefined && (!Array.isArray(value.enum) || value.enum.length === 0)) invalid(`${path}.enum`, \"must be a non-empty array.\");\n if (Array.isArray(value.enum) && value.enum.some((item, index, entries) => entries.slice(0, index).some((other) => jsonEqual(item, other)))) invalid(`${path}.enum`, \"must contain unique values.\");\n if (value.properties !== undefined) {\n if (value.type !== \"object\" || !isRecord(value.properties)) invalid(`${path}.properties`, \"requires an object schema.\");\n for (const [name, property] of Object.entries(value.properties)) assertSchema(property, `${path}.properties.${name}`);\n }\n if (value.required !== undefined) {\n if (value.type !== \"object\" || !Array.isArray(value.required) || value.required.some((name) => typeof name !== \"string\") || new Set(value.required).size !== value.required.length) invalid(`${path}.required`, \"must contain unique property names.\");\n const properties = value.properties as Record<string, unknown> | undefined;\n if (value.required.some((name) => !properties || !Object.hasOwn(properties, name))) invalid(`${path}.required`, \"must reference declared properties.\");\n }\n if (value.items !== undefined) {\n if (value.type !== \"array\") invalid(`${path}.items`, \"requires an array schema.\");\n assertSchema(value.items, `${path}.items`);\n }\n}\n\nexport function assertAgentToolInputSchema(value: unknown, path = \"inputSchema\"): void {\n if (!isRecord(value) || value.type !== \"object\") invalid(path, 'root type must be object.');\n if (checkedSchemas.has(value)) return;\n const frozen = assertJson(value, path);\n assertSchema(value, path);\n if (frozen) checkedSchemas.add(value);\n}\n\nfunction jsonEqual(left: unknown, right: unknown): boolean {\n if (left === right) return true;\n if (Array.isArray(left) && Array.isArray(right)) return left.length === right.length && left.every((item, index) => jsonEqual(item, right[index]));\n if (!isRecord(left) || !isRecord(right)) return false;\n const keys = Object.keys(left);\n return keys.length === Object.keys(right).length && keys.every((key) => Object.hasOwn(right, key) && jsonEqual(left[key], right[key]));\n}\n\nfunction typeMatches(schema: JsonSchema, value: unknown): boolean {\n switch (schema.type) {\n case undefined: return true;\n case \"null\": return value === null;\n case \"array\": return Array.isArray(value);\n case \"object\": return isRecord(value);\n case \"integer\": return typeof value === \"number\" && Number.isInteger(value);\n case \"number\": return typeof value === \"number\" && Number.isFinite(value);\n default: return typeof value === schema.type;\n }\n}\n\nexport function validateAgentToolInput(schema: JsonSchema, value: unknown, path = \"input\"): string[] {\n if (!typeMatches(schema, value)) return [`${path} must be ${schema.type}.`];\n const errors: string[] = [];\n if (schema.enum && !schema.enum.some((item) => jsonEqual(item, value))) errors.push(`${path} must be one of the declared enum values.`);\n if (typeof value === \"string\") {\n const length = Array.from(value).length;\n if (schema.minLength !== undefined && length < schema.minLength) errors.push(`${path} must have at least ${schema.minLength} characters.`);\n if (schema.maxLength !== undefined && length > schema.maxLength) errors.push(`${path} must have at most ${schema.maxLength} characters.`);\n if (schema.pattern !== undefined && !patternFor(schema, path).test(value)) errors.push(`${path} must match pattern ${schema.pattern}.`);\n }\n if (typeof value === \"number\") {\n if (schema.minimum !== undefined && value < schema.minimum) errors.push(`${path} must be >= ${schema.minimum}.`);\n if (schema.maximum !== undefined && value > schema.maximum) errors.push(`${path} must be <= ${schema.maximum}.`);\n if (schema.exclusiveMinimum !== undefined && value <= schema.exclusiveMinimum) errors.push(`${path} must be > ${schema.exclusiveMinimum}.`);\n if (schema.exclusiveMaximum !== undefined && value >= schema.exclusiveMaximum) errors.push(`${path} must be < ${schema.exclusiveMaximum}.`);\n }\n if (Array.isArray(value)) {\n if (schema.minItems !== undefined && value.length < schema.minItems) errors.push(`${path} must have at least ${schema.minItems} items.`);\n if (schema.maxItems !== undefined && value.length > schema.maxItems) errors.push(`${path} must have at most ${schema.maxItems} items.`);\n if (schema.uniqueItems && value.some((item, index) => value.slice(0, index).some((other) => jsonEqual(item, other)))) errors.push(`${path} must contain unique items.`);\n if (schema.items) value.forEach((item, index) => errors.push(...validateAgentToolInput(schema.items!, item, `${path}[${index}]`)));\n }\n if (isRecord(value)) {\n for (const key of schema.required ?? []) {\n if (!Object.hasOwn(value, key)) errors.push(`${path}.${key} is required.`);\n }\n for (const [key, item] of Object.entries(value)) {\n const property = schema.properties && Object.hasOwn(schema.properties, key) ? schema.properties[key] : undefined;\n if (property) errors.push(...validateAgentToolInput(property, item, `${path}.${key}`));\n else if (schema.additionalProperties === false) errors.push(`${path}.${key} is not allowed.`);\n }\n }\n return errors;\n}\n"]}
package/dist/styles.css CHANGED
@@ -8,11 +8,9 @@
8
8
  .agent-operation__pointer-effect { position: fixed; z-index: 2; top: 0; left: 0; width: 0; height: 0; opacity: 1; pointer-events: none; transform: translate3d(var(--agent-operation-pointer-x),var(--agent-operation-pointer-y),0); transition: transform var(--agent-operation-pointer-duration) cubic-bezier(.22,1,.36,1),opacity .12s ease-out; will-change: transform,opacity; }
9
9
  .agent-operation__pointer-effect[data-phase="hidden"] { opacity: 0; }
10
10
  .agent-operation__pointer-cursor { position: absolute; z-index: 1; top: -4px; left: -3px; display: block; width: 24px; height: 24px; transform-origin: 4px 4px; }
11
- .agent-operation__pointer-effect[data-active="true"][data-phase="resting"] .agent-operation__pointer-cursor { animation: agent-operation-pointer-float 1.6s ease-in-out infinite; }
12
- .agent-operation__pointer-effect[data-phase="arrived"] .agent-operation__pointer-cursor { animation: agent-operation-pointer-press .11s ease-out both; }
13
- .agent-operation__pointer-ripple { position: absolute; top: 0; left: 0; width: 64px; height: 64px; border: 2px solid rgba(79,124,255,.78); border-radius: 50%; opacity: 0; transform: translate(-50%,-50%) scale(.35); box-shadow: 0 0 18px rgba(96,156,245,.34); }
14
- .agent-operation__pointer-ripple--primary { animation: agent-operation-pointer-ripple var(--agent-operation-ripple-duration) ease-out both; }
15
11
  .agent-operation__pointer { position: relative; z-index: 2; display: block; color: #111827; filter: drop-shadow(0 0 1px #fff) drop-shadow(0 1px 2px rgba(15,23,42,.32)); }
12
+ .agent-operation__pointer-ripple { position: absolute; top: 0; left: 0; width: 64px; height: 64px; border: 2px solid rgba(79,124,255,.78); border-radius: 50%; opacity: 0; transform: translate(-50%,-50%) scale(.35); box-shadow: 0 0 18px rgba(96,156,245,.34); }
13
+ .agent-operation__pointer-ripple--primary { animation: agent-operation-pointer-ripple var(--agent-operation-ripple-duration) ease-out infinite; }
16
14
  .agent-operation__pointer-label { position: absolute; z-index: 2; top: 27px; left: 19px; display: flex; max-width: min(300px,48vw); overflow: hidden; align-items: center; gap: 9px; border: 1px solid rgba(24,24,27,.1); border-radius: 11px; padding: 7px 11px; color: #27272a; background: rgba(255,255,255,.97); box-shadow: 0 6px 20px rgba(15,23,42,.13); font: 500 13px/1.35 Inter,ui-sans-serif,system-ui,sans-serif; white-space: nowrap; }
17
15
  .agent-operation__pointer-label:is([data-operation-effect="read"],[data-operation-effect="navigate"]) { top: 12px; left: 10px; overflow: visible; gap: 5px; border: 0; padding: 0; background: transparent; box-shadow: none; }
18
16
  .agent-operation__pointer-label-text { overflow: hidden; text-overflow: ellipsis; }
@@ -66,8 +64,6 @@
66
64
  @keyframes agent-operation-edge-flow-reverse { 0% { right: -20%; opacity: 0; } 18%,76% { opacity: .8; } 100% { right: 100%; opacity: 0; } }
67
65
  @keyframes agent-operation-edge-breathe { 50% { border-color: rgba(103,232,249,.42); } }
68
66
  @keyframes agent-operation-pulse { 50% { border-color: #38bdf8; box-shadow: 0 0 0 6px rgba(99,102,241,.12),0 0 28px rgba(34,211,238,.4),0 0 58px rgba(79,70,229,.24); } }
69
- @keyframes agent-operation-pointer-float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
70
- @keyframes agent-operation-pointer-press { 0%,100% { transform: translate(0) scale(1); } 48% { transform: translate(1px,1px) scale(.94); } }
71
67
  @property --agent-operation-edge-primary-angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
72
68
  @property --agent-operation-edge-secondary-angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
73
69
  @keyframes agent-operation-surface-edge-primary { 0% { --agent-operation-edge-primary-angle: 0deg; animation-timing-function: cubic-bezier(.4,.25,.6,.75); } 100% { --agent-operation-edge-primary-angle: 360deg; } }
@@ -77,7 +73,7 @@
77
73
  @keyframes agent-operation-pointer-ripple { 0% { opacity: .82; transform: translate(-50%,-50%) scale(.35); } 100% { opacity: 0; transform: translate(-50%,-50%) scale(1.45); } }
78
74
  @keyframes agent-operation-pointer-read-bar { 0%,18%,100% { opacity: .34; transform: scaleY(.58); box-shadow: none; } 42% { opacity: 1; transform: scaleY(1.27); box-shadow: 0 0 6px rgba(96,156,245,.52); } 68% { opacity: .58; transform: scaleY(.78); box-shadow: none; } }
79
75
  @keyframes agent-operation-pointer-navigation-chevron { 0%,100% { opacity: .24; transform: translateX(-3px) rotate(45deg); } 48% { opacity: 1; transform: translateX(2px) rotate(45deg); } 72% { opacity: .62; transform: translateX(4px) rotate(45deg); } }
80
- @media (prefers-reduced-motion: reduce) { .agent-operation__surface,.agent-operation__target,.agent-operation__controller,.agent-operation__activity i,.agent-operation__edge-flow::before,.agent-operation__edge-flow::after,.agent-operation__pointer-cursor,.agent-operation__pointer-read-scan i,.agent-operation__pointer-navigation-trail::before,.agent-operation__pointer-navigation-trail::after { animation: none; } .agent-operation__pointer-effect { transition: none; } .agent-operation__pointer-ripple,.agent-operation__surface::before,.agent-operation__surface::after { display: none; } }
76
+ @media (prefers-reduced-motion: reduce) { .agent-operation__surface,.agent-operation__target,.agent-operation__controller,.agent-operation__activity i,.agent-operation__edge-flow::before,.agent-operation__edge-flow::after,.agent-operation__pointer-read-scan i,.agent-operation__pointer-navigation-trail::before,.agent-operation__pointer-navigation-trail::after { animation: none; } .agent-operation__pointer-effect { transition: none; } .agent-operation__surface::before,.agent-operation__surface::after { display: none; } }
81
77
  @media (max-width:520px) { .agent-operation__controller { --agent-operation-controller-x: 0%; right: 12px; bottom: 12px; left: 12px; width: auto; min-width: 0; } .agent-operation__controller>.agent-operation__history { width: 100%; } }
82
78
 
83
79
  .nexface-operation-surface { width: 100%; height: 100%; min-width: 0; min-height: 0; overflow: auto; }
@@ -187,3 +183,11 @@
187
183
  .agent-operation, .agent-operation *, .agent-operation::before, .agent-operation::after, .agent-operation *::before, .agent-operation *::after { box-sizing: border-box; }
188
184
  .agent-operation__pointer-navigation-trail::before,.agent-operation__pointer-navigation-trail::after { box-sizing: content-box; }
189
185
  .agent-operation__pointer-indicator { position: absolute; top: 12px; left: 10px; display: flex; align-items: center; gap: 5px; }
186
+
187
+ .agent-operation__pointer-processing { display: inline-block; flex: none; width: 16px; height: 16px; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: agent-operation-processing-spin .8s linear infinite; }
188
+ @keyframes agent-operation-processing-spin { to { transform: rotate(360deg); } }
189
+ @media (prefers-reduced-motion: reduce) { .agent-operation__pointer-processing { animation: none; } }
190
+
191
+ @media (prefers-reduced-motion: reduce) {
192
+ .agent-operation__pointer-ripple--primary { animation: none; opacity: .6; transform: translate(-50%,-50%) scale(1); }
193
+ }
package/dist/types.d.ts CHANGED
@@ -1,6 +1,16 @@
1
1
  export type JsonSchema = {
2
2
  type?: "object" | "array" | "string" | "number" | "integer" | "boolean" | "null";
3
3
  description?: string;
4
+ minLength?: number;
5
+ maxLength?: number;
6
+ pattern?: string;
7
+ minimum?: number;
8
+ maximum?: number;
9
+ exclusiveMinimum?: number;
10
+ exclusiveMaximum?: number;
11
+ minItems?: number;
12
+ maxItems?: number;
13
+ uniqueItems?: boolean;
4
14
  properties?: Record<string, JsonSchema>;
5
15
  required?: readonly string[];
6
16
  items?: JsonSchema;
@@ -53,7 +63,7 @@ export type AgentContextValue = string | number | boolean | null | readonly Agen
53
63
  };
54
64
  export interface AgentContextEntry {
55
65
  name: string;
56
- description: string;
66
+ description?: string;
57
67
  value: AgentContextValue;
58
68
  }
59
69
  export type AgentContextInput = AgentContextEntry;
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type JsonSchema = {\n type?: \"object\" | \"array\" | \"string\" | \"number\" | \"integer\" | \"boolean\" | \"null\";\n description?: string;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n minimum?: number;\n maximum?: number;\n exclusiveMinimum?: number;\n exclusiveMaximum?: number;\n minItems?: number;\n maxItems?: number;\n uniqueItems?: boolean;\n properties?: Record<string, JsonSchema>;\n required?: readonly string[];\n items?: JsonSchema;\n enum?: readonly unknown[];\n additionalProperties?: boolean;\n};\n\nexport type AgentToolInputSchema = JsonSchema & {\n type: \"object\";\n};\n\ntype Simplify<TValue> = { [TKey in keyof TValue]: TValue[TKey] };\n\ntype RequiredPropertyKeys<\n TSchema extends JsonSchema,\n TProperties extends Record<string, JsonSchema>,\n> = TSchema extends { readonly required: readonly (infer TKey)[] }\n ? Extract<TKey, keyof TProperties>\n : never;\n\ntype InferObjectSchema<\n TSchema extends JsonSchema,\n TProperties extends Record<string, JsonSchema>,\n> = keyof TProperties extends never\n ? TSchema extends { readonly additionalProperties: false }\n ? Record<string, never>\n : Record<string, unknown>\n : Simplify<{\n [TKey in RequiredPropertyKeys<TSchema, TProperties>]-?: InferJsonSchema<\n TProperties[TKey]\n >;\n } & {\n [TKey in Exclude<\n keyof TProperties,\n RequiredPropertyKeys<TSchema, TProperties>\n >]?: InferJsonSchema<TProperties[TKey]>;\n }> & (TSchema extends { readonly additionalProperties: false }\n ? unknown\n : Record<string, unknown>);\n\nexport type InferJsonSchema<TSchema extends JsonSchema> =\n TSchema extends { readonly enum: readonly (infer TValue)[] }\n ? TValue\n : TSchema extends { readonly type: \"string\" }\n ? string\n : TSchema extends { readonly type: \"number\" | \"integer\" }\n ? number\n : TSchema extends { readonly type: \"boolean\" }\n ? boolean\n : TSchema extends { readonly type: \"null\" }\n ? null\n : TSchema extends {\n readonly type: \"array\";\n readonly items: infer TItem extends JsonSchema;\n }\n ? InferJsonSchema<TItem>[]\n : TSchema extends { readonly type: \"array\" }\n ? unknown[]\n : TSchema extends {\n readonly type: \"object\";\n readonly properties: infer TProperties extends Record<\n string,\n JsonSchema\n >;\n }\n ? InferObjectSchema<TSchema, TProperties>\n : TSchema extends { readonly type: \"object\" }\n ? TSchema extends { readonly additionalProperties: false }\n ? Record<string, never>\n : Record<string, unknown>\n : unknown;\n\nexport type AgentContextValue =\n | string\n | number\n | boolean\n | null\n | readonly AgentContextValue[]\n | { readonly [key: string]: AgentContextValue };\n\nexport interface AgentContextEntry {\n name: string;\n description?: string;\n value: AgentContextValue;\n}\n\nexport type AgentContextInput = AgentContextEntry;\n\nexport interface AgentContextRegistration {\n update(context: AgentContextInput): void;\n dispose(): void;\n}\n\nexport interface AgentToolMetadata {\n name: string;\n description: string;\n inputSchema: AgentToolInputSchema;\n effect: AgentToolEffect;\n}\n\nexport type AgentToolEffect = \"read\" | \"action\" | \"navigate\";\n\nexport interface AgentToolDefinition<\n TInput = Record<string, unknown>,\n TResult = unknown,\n>\n extends AgentToolMetadata {\n readonly __input?: TInput;\n readonly __result?: TResult;\n}\n\nexport interface AgentToolExecutionContext {\n signal: AbortSignal;\n waitForTool(\n definition: AgentToolDefinition<any, any>,\n options?: { timeoutMs?: number },\n ): Promise<void>;\n}\n\nexport type AgentToolExecutor<TInput, TResult> = (\n input: TInput,\n context: AgentToolExecutionContext,\n) => TResult | Promise<TResult>;\n"]}
package/dist/webmcp.js CHANGED
@@ -2,19 +2,145 @@ function getWebMcpModelContext() {
2
2
  if (typeof document === "undefined")
3
3
  return undefined;
4
4
  const modelContext = document.modelContext;
5
- return typeof modelContext?.registerTool === "function"
6
- ? modelContext
7
- : undefined;
5
+ if (typeof modelContext?.registerTool === "function")
6
+ return modelContext;
7
+ if (typeof navigator === "undefined")
8
+ return undefined;
9
+ const legacy = navigator.modelContext;
10
+ if (typeof legacy?.registerTool !== "function" || typeof legacy.unregisterTool !== "function")
11
+ return undefined;
12
+ return adaptLegacyModelContext(legacy);
13
+ }
14
+ function adaptLegacyModelContext(legacy) {
15
+ return {
16
+ registerTool(tool, options = {}) {
17
+ const { signal } = options;
18
+ signal?.throwIfAborted();
19
+ // The legacy callback receives an agent, not execution cancellation options.
20
+ legacy.registerTool({ ...tool, execute: (input) => tool.execute(input) });
21
+ const unregister = () => {
22
+ try {
23
+ legacy.unregisterTool(tool.name);
24
+ }
25
+ catch (error) {
26
+ console.warn(`Unable to unregister WebMCP Tool "${tool.name}".`, error);
27
+ }
28
+ };
29
+ // Only a successful registration owns the name and may unregister it.
30
+ if (signal?.aborted)
31
+ unregister();
32
+ else
33
+ signal?.addEventListener("abort", unregister, { once: true });
34
+ return Promise.resolve();
35
+ },
36
+ };
8
37
  }
9
38
  function warnWebMcpRegistration(name, error) {
10
39
  console.warn(`Unable to register WebMCP Tool "${name}".`, error);
11
40
  }
41
+ const connections = new WeakMap();
42
+ const pendingDisposals = new Map();
43
+ function disposeUnusedConnection(runtime, connection) {
44
+ if (connection.refs || connections.get(runtime) !== connection)
45
+ return;
46
+ pendingDisposals.delete(runtime);
47
+ connections.delete(runtime);
48
+ connection.dispose();
49
+ }
12
50
  export function connectToolRuntimeToWebMcp(runtime) {
13
- const modelContext = getWebMcpModelContext();
14
- if (!modelContext)
15
- return () => undefined;
51
+ let connection = connections.get(runtime);
52
+ if (!connection) {
53
+ const modelContext = getWebMcpModelContext();
54
+ if (!modelContext)
55
+ return () => undefined;
56
+ // Release names before a replacement Runtime starts publishing its tools.
57
+ for (const [previousRuntime, previous] of pendingDisposals) {
58
+ disposeUnusedConnection(previousRuntime, previous);
59
+ }
60
+ // Install the shared connection before registration can synchronously notify listeners.
61
+ connection = { refs: 0, dispose: () => { } };
62
+ connections.set(runtime, connection);
63
+ connection.dispose = createConnection(runtime, modelContext);
64
+ }
65
+ pendingDisposals.delete(runtime);
66
+ connection.refs += 1;
67
+ const current = connection;
68
+ let released = false;
69
+ return () => {
70
+ if (released)
71
+ return;
72
+ released = true;
73
+ current.refs -= 1;
74
+ if (current.refs)
75
+ return;
76
+ // A same-Runtime reconnect can still reuse this connection in Strict Mode.
77
+ pendingDisposals.set(runtime, current);
78
+ queueMicrotask(() => disposeUnusedConnection(runtime, current));
79
+ };
80
+ }
81
+ function createConnection(runtime, modelContext) {
16
82
  const registrations = new Map();
17
83
  let disposed = false;
84
+ let operation;
85
+ const controls = new AbortController();
86
+ const begin = {
87
+ name: "beginOperation",
88
+ description: "Begin a continuous page operation before using page tools. Call endOperation with the returned operationId when all page work is done, before your final response. Repeated begin returns the same active operation. Omitting begin shows feedback only while each tool executes.",
89
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
90
+ execute: async (input, options = {}) => {
91
+ options.signal?.throwIfAborted();
92
+ controls.signal.throwIfAborted();
93
+ if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).length)
94
+ throw new TypeError("beginOperation requires {}.");
95
+ const current = runtime.getActivitySnapshot().operation;
96
+ if (operation && current?.id === operation.id) {
97
+ return { status: current.status === "ending" ? "ending" : "active", operationId: operation.id };
98
+ }
99
+ operation = undefined;
100
+ try {
101
+ operation = runtime.beginInternalOperation({ source: "webmcp" });
102
+ }
103
+ catch (error) {
104
+ if (error.code === "OPERATION_BUSY")
105
+ return { status: "busy" };
106
+ throw error;
107
+ }
108
+ return { status: "active", operationId: operation.id };
109
+ },
110
+ };
111
+ const end = {
112
+ name: "endOperation",
113
+ description: "End the page operation identified by operationId after all page work. Waits for its admitted tools to settle. Does not stop an external agent or undo changes.",
114
+ inputSchema: { type: "object", properties: { operationId: { type: "string" } }, required: ["operationId"], additionalProperties: false },
115
+ execute: async (input, options = {}) => {
116
+ options.signal?.throwIfAborted();
117
+ controls.signal.throwIfAborted();
118
+ const args = input;
119
+ if (!args || typeof args !== "object" || Array.isArray(args) || typeof args.operationId !== "string" || Object.keys(args).some((key) => key !== "operationId"))
120
+ throw new TypeError("endOperation requires { operationId: string }.");
121
+ const operationId = args.operationId;
122
+ const owned = operation;
123
+ if (!owned || owned.id !== operationId || runtime.getActivitySnapshot().operation?.id !== operationId)
124
+ return { status: "not_active", operationId };
125
+ await owned.end();
126
+ if (operation === owned)
127
+ operation = undefined;
128
+ return { status: "ended", operationId };
129
+ },
130
+ };
131
+ const registerControls = async () => {
132
+ try {
133
+ await modelContext.registerTool(end, { signal: controls.signal });
134
+ controls.signal.throwIfAborted();
135
+ await modelContext.registerTool(begin, { signal: controls.signal });
136
+ }
137
+ catch (error) {
138
+ const aborted = controls.signal.aborted;
139
+ controls.abort();
140
+ if (!disposed && !aborted)
141
+ warnWebMcpRegistration("beginOperation/endOperation", error);
142
+ }
143
+ };
18
144
  const register = (tool) => {
19
145
  const { definition } = tool;
20
146
  const controller = new AbortController();
@@ -25,8 +151,31 @@ export function connectToolRuntimeToWebMcp(runtime) {
25
151
  result = modelContext.registerTool({
26
152
  name: definition.name,
27
153
  description: definition.description,
28
- inputSchema: definition.inputSchema,
29
- execute: async (input) => runtime.execute(tool, input),
154
+ inputSchema: {
155
+ type: "object",
156
+ properties: {
157
+ input: definition.inputSchema ?? { type: "object", properties: {}, additionalProperties: false },
158
+ progressLabel: {
159
+ type: "string",
160
+ description: "Briefly describe this tool action in the user’s language. Do not expose internal identifiers or claim success before completion.",
161
+ },
162
+ },
163
+ required: ["input"],
164
+ additionalProperties: false,
165
+ },
166
+ execute: async (parameters, options = {}) => {
167
+ const args = parameters;
168
+ if (!args || typeof args !== "object" || Array.isArray(args)
169
+ || !args.input || typeof args.input !== "object" || Array.isArray(args.input)
170
+ || Object.keys(args).some((key) => key !== "input" && key !== "progressLabel")
171
+ || (args.progressLabel !== undefined && typeof args.progressLabel !== "string")) {
172
+ throw new TypeError("WebMCP tools require { input: object, progressLabel?: string }.");
173
+ }
174
+ return runtime.executeWithProgress(tool, args.input, {
175
+ ...(options.signal ? { signal: options.signal } : {}),
176
+ ...(typeof args.progressLabel === "string" ? { progressLabel: args.progressLabel } : {}),
177
+ });
178
+ },
30
179
  }, { signal: controller.signal });
31
180
  }
32
181
  catch (error) {
@@ -44,7 +193,7 @@ export function connectToolRuntimeToWebMcp(runtime) {
44
193
  });
45
194
  };
46
195
  const reconcile = () => {
47
- const tools = new Map(runtime.getWebMcpTools().map((tool) => [tool.definition.name, tool]));
196
+ const tools = new Map(runtime.getWebMcpTools().filter((tool) => !["beginOperation", "endOperation"].includes(tool.definition.name)).map((tool) => [tool.definition.name, tool]));
48
197
  for (const [name, registration] of registrations) {
49
198
  if (tools.get(name) === registration.tool)
50
199
  continue;
@@ -59,10 +208,15 @@ export function connectToolRuntimeToWebMcp(runtime) {
59
208
  const unsubscribeRuntime = runtime.on("toolchange", reconcile);
60
209
  modelContext.addEventListener?.("toolchange", reconcile);
61
210
  reconcile();
211
+ void registerControls();
62
212
  return () => {
63
213
  if (disposed)
64
214
  return;
65
215
  disposed = true;
216
+ controls.abort();
217
+ if (operation)
218
+ void runtime.endBridgeOperation(operation);
219
+ operation = undefined;
66
220
  unsubscribeRuntime();
67
221
  modelContext.removeEventListener?.("toolchange", reconcile);
68
222
  for (const registration of registrations.values()) {