@nxisai/nxis 2.2.4 → 2.3.1
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/.github/workflows/deploy.yml +115 -76
- package/build/nxis.js +1 -1
- package/build/webmcp/execute.d.ts +20 -2
- package/build/webmcp/register.d.ts +0 -1
- package/build/webmcp/types.d.ts +13 -61
- package/build/webmcp.js +1 -1
- package/package.json +2 -5
- package/src/webmcp/execute.ts +5 -5
- package/src/webmcp/register.ts +44 -43
- package/src/webmcp/types.ts +18 -72
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name: Deploy nxis.js to S3
|
|
1
|
+
name: Deploy nxis.js to S3, GitHub Packages and npm
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
@@ -6,18 +6,29 @@ on:
|
|
|
6
6
|
- main
|
|
7
7
|
workflow_dispatch:
|
|
8
8
|
|
|
9
|
+
# Every job that installs needs GitHub Packages: @nxisai/webmcp resolves from
|
|
10
|
+
# there (package-lock.json), and the repo's .npmrc is not committed, so
|
|
11
|
+
# setup-node supplies the scope mapping and GITHUB_TOKEN the auth.
|
|
9
12
|
jobs:
|
|
10
|
-
|
|
13
|
+
# Type-checked and built on each Node a consumer is likely to build with.
|
|
14
|
+
test:
|
|
11
15
|
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
packages: read
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
node-version: ['20', '22']
|
|
12
23
|
|
|
13
24
|
steps:
|
|
14
25
|
- name: Checkout code
|
|
15
26
|
uses: actions/checkout@v4
|
|
16
27
|
|
|
17
|
-
- name: Setup Node.js
|
|
28
|
+
- name: Setup Node.js ${{ matrix.node-version }}
|
|
18
29
|
uses: actions/setup-node@v4
|
|
19
30
|
with:
|
|
20
|
-
node-version:
|
|
31
|
+
node-version: ${{ matrix.node-version }}
|
|
21
32
|
cache: 'npm'
|
|
22
33
|
registry-url: 'https://npm.pkg.github.com'
|
|
23
34
|
scope: '@nxisai'
|
|
@@ -27,36 +38,37 @@ jobs:
|
|
|
27
38
|
env:
|
|
28
39
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
29
40
|
|
|
41
|
+
# skipLibCheck: the TypeScript this package builds with predates the
|
|
42
|
+
# current @types/node, whose declarations it cannot parse.
|
|
43
|
+
- name: Typecheck
|
|
44
|
+
run: npx tsc --noEmit -p . --skipLibCheck
|
|
45
|
+
|
|
30
46
|
- name: Build project
|
|
31
47
|
env:
|
|
32
48
|
NXIS_API_HOST: ${{ vars.NXIS_API_HOST || secrets.NXIS_API_HOST }}
|
|
33
|
-
run:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
uses: aws-actions/configure-aws-credentials@v4
|
|
37
|
-
with:
|
|
38
|
-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
39
|
-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
40
|
-
aws-region: ${{ vars.AWS_REGION || secrets.AWS_REGION }}
|
|
41
|
-
|
|
42
|
-
- name: Deploy to S3
|
|
43
|
-
run: aws s3 cp build/nxis.js s3://nxis-ai-static/nxis.js
|
|
49
|
+
run: |
|
|
50
|
+
npx rollup --config rollup.config.js
|
|
51
|
+
npm run build:types
|
|
44
52
|
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
# Built and packed once, here. S3 and both registries ship these exact bytes,
|
|
54
|
+
# so the nxis.js a site loads from S3 is the one in the published package.
|
|
55
|
+
#
|
|
56
|
+
# Stages: test → build → deploy-s3 → publish-gpr / publish-npmjs.
|
|
57
|
+
build:
|
|
58
|
+
needs: test
|
|
47
59
|
runs-on: ubuntu-latest
|
|
48
60
|
permissions:
|
|
49
61
|
contents: read
|
|
50
|
-
packages:
|
|
62
|
+
packages: read
|
|
51
63
|
|
|
52
64
|
steps:
|
|
53
65
|
- name: Checkout code
|
|
54
66
|
uses: actions/checkout@v4
|
|
55
67
|
|
|
56
|
-
- name: Setup Node.js
|
|
68
|
+
- name: Setup Node.js
|
|
57
69
|
uses: actions/setup-node@v4
|
|
58
70
|
with:
|
|
59
|
-
node-version: '
|
|
71
|
+
node-version: '22'
|
|
60
72
|
cache: 'npm'
|
|
61
73
|
registry-url: 'https://npm.pkg.github.com'
|
|
62
74
|
scope: '@nxisai'
|
|
@@ -66,83 +78,110 @@ jobs:
|
|
|
66
78
|
env:
|
|
67
79
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
68
80
|
|
|
69
|
-
- name: Build
|
|
81
|
+
- name: Build project
|
|
70
82
|
env:
|
|
71
83
|
NXIS_API_HOST: ${{ vars.NXIS_API_HOST || secrets.NXIS_API_HOST }}
|
|
72
84
|
run: |
|
|
73
|
-
npx rollup --config rollup.config.js
|
|
85
|
+
npx rollup --config rollup.config.js
|
|
74
86
|
npm run build:types
|
|
75
87
|
|
|
76
|
-
|
|
88
|
+
# Published as @nxisai/nxis; the repo's package is unscoped `nxis`.
|
|
89
|
+
- name: Scope the package
|
|
77
90
|
run: npm pkg set name='@nxisai/nxis'
|
|
78
91
|
|
|
92
|
+
- name: Pack the tarball
|
|
93
|
+
run: npm pack
|
|
94
|
+
|
|
95
|
+
- name: Upload the tarball
|
|
96
|
+
uses: actions/upload-artifact@v4
|
|
97
|
+
with:
|
|
98
|
+
name: package-tarball
|
|
99
|
+
path: '*.tgz'
|
|
100
|
+
if-no-files-found: error
|
|
101
|
+
retention-days: 7
|
|
102
|
+
|
|
103
|
+
# Its own stage, ahead of publishing: a version reaches the registries only
|
|
104
|
+
# once its nxis.js is live on S3.
|
|
105
|
+
deploy-s3:
|
|
106
|
+
needs: build
|
|
107
|
+
runs-on: ubuntu-latest
|
|
108
|
+
|
|
109
|
+
steps:
|
|
110
|
+
- name: Download the tarball
|
|
111
|
+
uses: actions/download-artifact@v4
|
|
112
|
+
with:
|
|
113
|
+
name: package-tarball
|
|
114
|
+
|
|
115
|
+
# The browser bundle, from the tarball itself rather than a second build.
|
|
116
|
+
- name: Extract nxis.js
|
|
117
|
+
run: tar -xzf ./*.tgz package/build/nxis.js
|
|
118
|
+
|
|
119
|
+
- name: Configure AWS credentials
|
|
120
|
+
uses: aws-actions/configure-aws-credentials@v4
|
|
121
|
+
with:
|
|
122
|
+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
123
|
+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
124
|
+
aws-region: ${{ vars.AWS_REGION || secrets.AWS_REGION }}
|
|
125
|
+
|
|
126
|
+
- name: Deploy to S3
|
|
127
|
+
run: aws s3 cp package/build/nxis.js s3://nxis-ai-static/nxis.js
|
|
128
|
+
|
|
129
|
+
publish-gpr:
|
|
130
|
+
needs: deploy-s3
|
|
131
|
+
runs-on: ubuntu-latest
|
|
132
|
+
permissions:
|
|
133
|
+
contents: read
|
|
134
|
+
packages: write
|
|
135
|
+
|
|
136
|
+
steps:
|
|
137
|
+
- name: Setup Node.js for GitHub Packages
|
|
138
|
+
uses: actions/setup-node@v4
|
|
139
|
+
with:
|
|
140
|
+
node-version: '22'
|
|
141
|
+
registry-url: 'https://npm.pkg.github.com'
|
|
142
|
+
scope: '@nxisai'
|
|
143
|
+
|
|
144
|
+
- name: Download the tarball
|
|
145
|
+
uses: actions/download-artifact@v4
|
|
146
|
+
with:
|
|
147
|
+
name: package-tarball
|
|
148
|
+
|
|
149
|
+
# Publishing a tarball rather than a directory. npm runs no lifecycle
|
|
150
|
+
# scripts on one, so nothing can rebuild over the artifact that was tested.
|
|
79
151
|
- name: Publish to GitHub Packages
|
|
80
|
-
run: npm publish
|
|
152
|
+
run: npm publish ./*.tgz
|
|
81
153
|
env:
|
|
82
154
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
83
155
|
|
|
156
|
+
# Independent of publish-gpr: a version already on GitHub Packages must not
|
|
157
|
+
# keep it off npm.
|
|
84
158
|
publish-npmjs:
|
|
85
|
-
needs:
|
|
159
|
+
needs: deploy-s3
|
|
86
160
|
runs-on: ubuntu-latest
|
|
87
161
|
permissions:
|
|
88
162
|
contents: read
|
|
89
|
-
|
|
163
|
+
# Required for npm Trusted Publishing (OIDC) — no npm token needed
|
|
164
|
+
id-token: write
|
|
90
165
|
|
|
91
166
|
steps:
|
|
92
|
-
- name: Checkout code
|
|
93
|
-
uses: actions/checkout@v4
|
|
94
|
-
|
|
95
167
|
- name: Setup Node.js for npm
|
|
96
168
|
uses: actions/setup-node@v4
|
|
97
169
|
with:
|
|
98
|
-
node-version: '
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
- name: Write .npmrc (auth both registries)
|
|
102
|
-
run: |
|
|
103
|
-
if [ -z "$NPM_TOKEN" ]; then
|
|
104
|
-
echo "::error::NPM_TOKEN secret is empty"; exit 1
|
|
105
|
-
fi
|
|
106
|
-
echo "NPM_TOKEN length: ${#NPM_TOKEN}"
|
|
107
|
-
# Unquoted heredoc so the shell expands the token values into the file
|
|
108
|
-
cat > .npmrc <<EOF
|
|
109
|
-
@nxisai:registry=https://npm.pkg.github.com
|
|
110
|
-
//npm.pkg.github.com/:_authToken=${GH_TOKEN}
|
|
111
|
-
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
|
112
|
-
always-auth=true
|
|
113
|
-
EOF
|
|
114
|
-
env:
|
|
115
|
-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
116
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
117
|
-
|
|
118
|
-
- name: Install dependencies
|
|
119
|
-
run: |
|
|
120
|
-
npm ci
|
|
121
|
-
rm -f .npmrc
|
|
170
|
+
node-version: '22'
|
|
171
|
+
registry-url: 'https://registry.npmjs.org'
|
|
122
172
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
npm run build:types
|
|
173
|
+
# Trusted publishing requires npm >= 11.5.1, and Node 22 still bundles
|
|
174
|
+
# npm 10.x. Pinned to a major rather than @latest: npm 12 raised its Node
|
|
175
|
+
# floor, and an unpinned @latest broke this step in nxis-webmcp.
|
|
176
|
+
- name: Update npm for trusted publishing
|
|
177
|
+
run: npm install -g npm@^11.5.1
|
|
129
178
|
|
|
130
|
-
- name:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
- name: Rewrite .npmrc for npmjs publish
|
|
136
|
-
run: |
|
|
137
|
-
# Drop the @nxisai->GitHub Packages scope mapping (only needed for install).
|
|
138
|
-
# For a scoped package, that mapping overrides publishConfig.registry and
|
|
139
|
-
# --registry, so it must be gone for the publish to route to npmjs.
|
|
140
|
-
cat > .npmrc <<EOF
|
|
141
|
-
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
|
142
|
-
always-auth=true
|
|
143
|
-
EOF
|
|
144
|
-
env:
|
|
145
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
179
|
+
- name: Download the tarball
|
|
180
|
+
uses: actions/download-artifact@v4
|
|
181
|
+
with:
|
|
182
|
+
name: package-tarball
|
|
146
183
|
|
|
184
|
+
# No checkout and no scope mapping, so nothing routes this scoped
|
|
185
|
+
# publish to GitHub Packages.
|
|
147
186
|
- name: Publish to npm
|
|
148
|
-
run: npm publish --access public
|
|
187
|
+
run: npm publish ./*.tgz --access public
|
package/build/nxis.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(){const e={NXIS_API_HOST:"https://proxy.nxis.ai"};try{if(process)return process.env=Object.assign({},process.env),void Object.assign(process.env,e)}catch(e){}globalThis.process={env:e}}();class e extends Error{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}}var t;!function(e){e[e.OK=0]="OK",e[e.INVALID_ARGUMENT=3]="INVALID_ARGUMENT",e[e.NOT_FOUND=5]="NOT_FOUND",e[e.PERMISSION_DENIED=7]="PERMISSION_DENIED",e[e.RESOURCE_EXHAUSTED=8]="RESOURCE_EXHAUSTED",e[e.INTERNAL=13]="INTERNAL",e[e.UNAUTHENTICATED=16]="UNAUTHENTICATED"}(t||(t={})),t.OK,t.INVALID_ARGUMENT,t.NOT_FOUND,t.PERMISSION_DENIED,t.RESOURCE_EXHAUSTED,t.INTERNAL,t.UNAUTHENTICATED;class n extends Error{constructor(e,t,o){super(o),this.code=e,this.httpStatus=t,this.name="ProxyError",Object.setPrototypeOf(this,n.prototype)}get isRetryable(){return this.code===t.RESOURCE_EXHAUSTED||this.code===t.INTERNAL}get isAuthError(){return this.code===t.UNAUTHENTICATED||this.code===t.PERMISSION_DENIED}static fromResponse(e,t){return new n(t.code,e,t.message)}}function o(e){return null===e?"null":Array.isArray(e)?"array":typeof e}function r(e,t){if(e===t)return!0;if(o(e)!==o(t))return!1;if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>r(e,t[n]));if("object"===o(e)){const n=e,o=t,i=Object.keys(n);return i.length===Object.keys(o).length&&i.every(e=>r(n[e],o[e]))}return!1}function i(e,t,n="$"){if(!t||"object"!=typeof t)return[];const a=[];if(void 0===t.const||r(e,t.const)||a.push({path:n,message:`must equal const ${JSON.stringify(t.const)}`}),t.enum&&!t.enum.some(t=>r(e,t))&&a.push({path:n,message:`must be one of ${JSON.stringify(t.enum)}`}),void 0!==t.type){const r=Array.isArray(t.type)?t.type:[t.type];if(!r.some(t=>function(e,t){switch(t){case"object":return"object"===o(e);case"array":return Array.isArray(e);case"string":return"string"==typeof e;case"number":return"number"==typeof e&&Number.isFinite(e);case"integer":return"number"==typeof e&&Number.isInteger(e);case"boolean":return"boolean"==typeof e;case"null":return null===e;default:return!0}}(e,t)))return a.push({path:n,message:`expected type ${r.join(" | ")}, got ${o(e)}`}),a}if("string"==typeof e&&(void 0!==t.minLength&&e.length<t.minLength&&a.push({path:n,message:`must be at least ${t.minLength} characters`}),void 0!==t.maxLength&&e.length>t.maxLength&&a.push({path:n,message:`must be at most ${t.maxLength} characters`}),void 0!==t.pattern)){let o=null;try{o=new RegExp(t.pattern,"u")}catch{}o&&!o.test(e)&&a.push({path:n,message:`must match pattern ${t.pattern}`})}if("number"==typeof e&&(void 0!==t.minimum&&e<t.minimum&&a.push({path:n,message:`must be >= ${t.minimum}`}),void 0!==t.maximum&&e>t.maximum&&a.push({path:n,message:`must be <= ${t.maximum}`})),Array.isArray(e)&&(void 0!==t.minItems&&e.length<t.minItems&&a.push({path:n,message:`must have at least ${t.minItems} items`}),void 0!==t.maxItems&&e.length>t.maxItems&&a.push({path:n,message:`must have at most ${t.maxItems} items`}),t.items&&e.forEach((e,o)=>{a.push(...i(e,t.items,`${n}[${o}]`))})),"object"===o(e)&&!Array.isArray(e)&&null!==e){const o=e;for(const e of t.required??[])e in o||a.push({path:n,message:`missing required property "${e}"`});const r=t.properties??{};for(const[e,t]of Object.entries(r))e in o&&a.push(...i(o[e],t,`${n}.${e}`));if(!1===t.additionalProperties)for(const e of Object.keys(o))e in r||a.push({path:n,message:`unexpected property "${e}"`});else if(t.additionalProperties&&"object"==typeof t.additionalProperties)for(const e of Object.keys(o))e in r||a.push(...i(o[e],t.additionalProperties,`${n}.${e}`))}if(t.allOf)for(const o of t.allOf)a.push(...i(e,o,n));if(t.anyOf&&t.anyOf.length>0){t.anyOf.some(t=>0===i(e,t,n).length)||a.push({path:n,message:"does not match any schema in anyOf"})}if(t.oneOf&&t.oneOf.length>0){const o=t.oneOf.filter(t=>0===i(e,t,n).length).length;1!==o&&a.push({path:n,message:`must match exactly one schema in oneOf (matched ${o})`})}return a}var a,s,l,u,c,d,f=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)},p=function(e,t,n,o,r){if("m"===o)throw new TypeError("Private method is not writable");if("a"===o&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===o?r.call(e,n):r?r.value=n:t.set(e,n),n};const m={type:"object"};function h(e,t){if("function"==typeof DOMException)return new DOMException(e,t);const n=new Error(e);return n.name=t,n}function v(e){if(!e||"object"!=typeof e)throw new TypeError("Tool descriptor must be an object.");if("string"!=typeof e.name||0===e.name.length)throw new TypeError("Tool descriptor requires a non-empty string 'name'.");if("string"!=typeof e.description)throw new TypeError(`Tool "${e.name}" requires a string 'description'.`);if("function"!=typeof e.execute)throw new TypeError(`Tool "${e.name}" requires an 'execute' function.`);if(void 0!==e.inputSchema&&"object"!=typeof e.inputSchema)throw new TypeError(`Tool "${e.name}": 'inputSchema' must be an object.`)}class g extends EventTarget{constructor(){super(...arguments),a.add(this),s.set(this,new Map),l.set(this,null),u.set(this,!1)}get ontoolchange(){return f(this,l,"f")}set ontoolchange(e){f(this,l,"f")&&this.removeEventListener("toolchange",f(this,l,"f")),p(this,l,"function"==typeof e?e:null,"f"),f(this,l,"f")&&this.addEventListener("toolchange",f(this,l,"f"))}registerTool(e,t={}){v(e);const{signal:n,exposedTo:o}=t;if(n?.aborted)return;f(this,a,"m",c).call(this,e.name);const r={tool:e,exposedTo:o?[...o]:void 0,pageLevel:!1};if(n){const t=()=>f(this,a,"m",c).call(this,e.name,r,!0);n.addEventListener("abort",t,{once:!0}),r.abortListener={signal:n,listener:t}}f(this,s,"f").set(e.name,r),f(this,a,"m",d).call(this)}provideContext(e={}){const t=e.tools??[];for(const e of t)v(e);if(new Set(t.map(e=>e.name)).size!==t.length)throw new TypeError("provideContext(): duplicate tool names in 'tools'.");for(const[e,t]of f(this,s,"f"))t.pageLevel&&f(this,a,"m",c).call(this,e);for(const e of t){if(f(this,s,"f").has(e.name))throw h(`provideContext(): tool "${e.name}" is already registered via registerTool().`,"InvalidStateError");f(this,s,"f").set(e.name,{tool:e,exposedTo:void 0,pageLevel:!0})}f(this,a,"m",d).call(this)}async getTools(e={}){e.fromOrigins;const t="undefined"!=typeof location?location.origin:void 0;return[...f(this,s,"f").values()].map(({tool:e})=>{const n={name:e.name,description:e.description,inputSchema:structuredClone(e.inputSchema??m)};return e.annotations&&(n.annotations=structuredClone(e.annotations)),t&&(n.origin=t),n})}async executeTool(e,t,n={}){const o=f(this,s,"f").get(e);if(!o)throw h(`No tool registered with name "${e}".`,"NotFoundError");if(n.signal?.aborted)throw h("Tool execution was aborted.","AbortError");let r;if(null==t||""===t)r={};else if("string"==typeof t)try{r=JSON.parse(t)}catch(t){throw new TypeError(`executeTool("${e}"): input is not valid JSON: ${t.message}`)}else r=t;if(null===r||"object"!=typeof r||Array.isArray(r))throw new TypeError(`executeTool("${e}"): input must be a JSON object.`);const a=i(r,o.tool.inputSchema??m);if(a.length>0){const t=a.map(e=>`${e.path}: ${e.message}`).join("; ");throw new TypeError(`executeTool("${e}"): invalid input — ${t}`)}const l=new AbortController,u=n.signal,c=()=>l.abort(u?.reason);u?.addEventListener("abort",c,{once:!0});try{const t=await o.tool.execute(r,{signal:l.signal,toolName:e});if(u?.aborted)throw h("Tool execution was aborted.","AbortError");return function(e){return null==e?{content:[]}:"string"==typeof e?{content:[{type:"text",text:e}]}:"object"==typeof e&&Array.isArray(e.content)?e:{content:[{type:"text",text:JSON.stringify(e)}]}}(t)}catch(e){if(u?.aborted||e instanceof Error&&"AbortError"===e.name)throw h("Tool execution was aborted.","AbortError");return function(e){return{isError:!0,content:[{type:"text",text:e instanceof Error?`${e.name}: ${e.message}`:String(e)}]}}(e)}finally{u?.removeEventListener("abort",c)}}unregisterTool(e){const t=f(this,a,"m",c).call(this,e);return t&&f(this,a,"m",d).call(this),t}clearContext(){if(0!==f(this,s,"f").size){for(const e of[...f(this,s,"f").keys()])f(this,a,"m",c).call(this,e);f(this,a,"m",d).call(this)}}}function y(e,t){Object.defineProperty(e,"modelContext",{value:t,writable:!1,enumerable:!0,configurable:!0})}s=new WeakMap,l=new WeakMap,u=new WeakMap,a=new WeakSet,c=function(e,t,n=!1){const o=f(this,s,"f").get(e);return!!o&&((!t||o===t)&&(o.abortListener&&o.abortListener.signal.removeEventListener("abort",o.abortListener.listener),f(this,s,"f").delete(e),n&&f(this,a,"m",d).call(this),!0))},d=function(){f(this,u,"f")||(p(this,u,!0,"f"),queueMicrotask(()=>{p(this,u,!1,"f"),this.dispatchEvent(new Event("toolchange"))}))};const w=["AskAction","SearchAction","SubscribeAction","RegisterAction","BuyAction","OrderAction","AddAction","ScheduleAction","ReserveAction","RsvpAction","ApplyAction","QuoteAction","DownloadAction","ReviewAction","CommentAction","TrackAction","CommunicateAction","InteractAction"];const b="https://nxis.ai/ns#";function E(e,t,n){var o;return null!==(o=e[t])&&void 0!==o?o:e[n]}function x(e,t){return E(e,t,"https://schema.org/"+t)}function A(e,t){const n=x(e,t);return"string"==typeof n?n:null}function N(e,t,n){const o=E(e,t,n);return Array.isArray(o)?o:[]}function $(e){if(Array.isArray(e)){const t=[];for(const n of e)t.push(...$(n));return t}if(e&&"object"==typeof e){const t=e;if(Array.isArray(t["@graph"])){const e=[];for(const n of t["@graph"])e.push(...$(n));return e}return[t]}return[]}function T(e){var t;if(!e||"object"!=typeof e)return null;const n=e,o="string"==typeof n["@type"]?n["@type"]:null;if(!o)return null;if(!o.endsWith("Action")&&!function(e){return w.includes(e)}(o))return null;const r="string"==typeof n["@id"]?n["@id"]:null,i=A(n,"name"),a=function(e){var t,n;if(!e||"object"!=typeof e)return null;const o=e,r=null!==(n=null===(t=A(o,"httpMethod"))||void 0===t?void 0:t.toUpperCase())&&void 0!==n?n:null;if(!r)return null;const i={"@type":"EntryPoint",httpMethod:r},a=A(o,"encodingType");null!==a&&(i.encodingType=a);const s=A(o,"urlTemplate");null!==s&&(i.urlTemplate=s);const l=E(o,"nxis:targetKind",b+"targetKind");"selfPage"!==l&&"clientSide"!==l||(i["nxis:targetKind"]=l);const u=E(o,"nxis:pageUrl",b+"pageUrl");"string"==typeof u&&(i["nxis:pageUrl"]=u);const c=E(o,"nxis:jsHandled",b+"jsHandled");!0===c&&(i["nxis:jsHandled"]=!0);return i}(x(n,"target"));if(!r||!i||!a)return null;const s=N(n,"nxis:input",b+"input").map(L).filter(e=>null!==e),l=null!==(t=A(n,"description"))&&void 0!==t?t:function(e,t,n){const o=e.replace(/^.*[/#]/,"").replace(/Action$/,"").toLowerCase(),r=n.map(e=>e.valueName).join(", ");if(0===n.length)return`Trigger the ${o} action "${t}".`;return`Fill the ${o} form "${t}" with fields: ${r}.`}(o,i,s);return{"@context":n["@context"],"@type":o,"@id":r,name:i,description:l,target:a,input:s.length>0?s:void 0,"nxis:extractedAt":E(n,"nxis:extractedAt",b+"extractedAt")}}function L(e){if(!e||"object"!=typeof e)return null;const t=e,n=A(t,"valueName");if(!n)return null;const o=E(t,"nxis:valueType",b+"valueType"),r={"@type":"PropertyValueSpecification",valueName:n,"nxis:valueType":"string"==typeof o?o:"string"},i=A(t,"description");null!==i&&(r.description=i),!0===x(t,"valueRequired")&&(r.valueRequired=!0);const a=A(t,"defaultValue");null!==a&&(r.defaultValue=a);const s=e=>{const n=x(t,e);return"number"==typeof n?n:null},l=s("valueMinLength");null!==l&&(r.valueMinLength=l);const u=s("valueMaxLength");null!==u&&(r.valueMaxLength=u);const c=s("minValue");null!==c&&(r.minValue=c);const d=s("maxValue");null!==d&&(r.maxValue=d);const f=s("stepValue");null!==f&&(r.stepValue=f);const p=A(t,"valuePattern");null!==p&&(r.valuePattern=p),!0===x(t,"multipleValues")&&(r.multipleValues=!0),!0===x(t,"readonlyValue")&&(r.readonlyValue=!0);const m=N(t,"nxis:valueOption",b+"valueOption");if(m.length>0){const e=m.filter(e=>e&&"object"==typeof e&&null!==A(e,"value")).map(e=>{var t;const n=e;return{"@type":"nxis:ValueOption",value:A(n,"value"),name:null!==(t=A(n,"name"))&&void 0!==t?t:void 0}});e.length>0&&(r["nxis:valueOption"]=e)}return r}function O(e){switch(e){case"string":case"date":case"file":default:return"string";case"number":return"number";case"integer":return"integer";case"boolean":return"boolean"}}function S(e){const t={type:O(e["nxis:valueType"])},n=function(e){if("date"===e)return"date"}(e["nxis:valueType"]);if(n&&(t.format=n),e.description&&(t.description=e.description),void 0!==e.defaultValue&&(t.default=function(e,t){switch(t){case"number":case"integer":{const t=Number(e);return isNaN(t)?e:t}case"boolean":return"true"===e||"1"===e;default:return e}}(e.defaultValue,e["nxis:valueType"])),void 0!==e.valueMinLength&&(t.minLength=e.valueMinLength),void 0!==e.valueMaxLength&&(t.maxLength=e.valueMaxLength),e.valuePattern){const n=e.valuePattern,o=n.startsWith("^")&&n.endsWith("$")?n:`^${n}$`;t.pattern=o}void 0!==e.minValue&&(t.minimum=e.minValue),void 0!==e.maxValue&&(t.maximum=e.maxValue),void 0!==e.stepValue&&(t.multipleOf=e.stepValue),e.readonlyValue&&(t.readOnly=!0);const o=e["nxis:valueOption"];if(o&&o.length>0){t.enum=o.map(e=>e.value);if(o.some(e=>void 0!==e.name&&e.name!==e.value)){const e=o.filter(e=>e.name&&e.name!==e.value).map(e=>`${e.value} = "${e.name}"`).join(", "),n=t.description?`${t.description}. `:"";t.description=`${n}Values: ${e}`}}return t}function k(e){const t=Array.from(document.querySelectorAll("form"));if(0===t.length)return null;const n=function(e){return e.input?e.input.map(e=>e.valueName):[]}(e);let o;if(o=!e.target.urlTemplate?t:function(e,t,n){const o=function(e){const t=e.replace(/\{[^}]*\}/g,"");try{return new URL(t,window.location.href)}catch(e){return null}}(t);return e.filter(e=>{if((e.method||"GET").toUpperCase()!==n.toUpperCase())return!1;if(!o)return!0;const t=function(e){const t=e.getAttribute("action");if(!t||"#"===t||t.startsWith("#")||""===t)return window.location.href.split("#")[0].split("?")[0];if(t.startsWith("javascript:"))return window.location.href.split("#")[0].split("?")[0];try{return new URL(t,window.location.href).href}catch(e){return t}}(e);return function(e,t){let n;try{n=new URL(e,window.location.href)}catch(e){return!1}if(n.origin!==t.origin)return!1;const o=n.pathname.replace(/\/+$/,""),r=t.pathname.replace(/\/+$/,"");return""===r||(o===r||o.startsWith(r+"/")||r.startsWith(o+"/"))}(t,o)})}(t,e.target.urlTemplate,e.target.httpMethod),0===o.length&&(o=t),1===o.length)return o[0];const r=o.map(e=>({form:e,controlNames:j(e)})).filter(({controlNames:e})=>n.every(t=>e.has(t)));return 0===r.length?(console.warn(`[nxis/webmcp] No field-set match for action "${e.name}". Expected fields: [${n.join(", ")}]. Falling back to first candidate.`),o[0]):1===r.length?r[0].form:(r.sort((e,t)=>e.controlNames.size-t.controlNames.size),r[0].controlNames.size===r[1].controlNames.size?(console.warn(`[nxis/webmcp] Ambiguous form match for action "${e.name}". ${r.length} forms have identical field sets. Returning null.`),null):r[0].form)}function j(e){const t=new Set,n=e.elements;for(let e=0;e<n.length;e++){const o=n[e];o.name&&t.add(o.name)}return t}function C(e,t){var n;return(null!==(n=e.input)&&void 0!==n?n:[]).map(e=>function(e,t){var n;const o=t=>({valueName:e.valueName,pvs:e,strategy:t}),r=function(e,t){const n=[],o=e.elements;for(let e=0;e<o.length;e++){const r=o[e];r.name===t&&n.push(r)}return n}(t,e.valueName),i=null!==(n=r[0])&&void 0!==n?n:null;if(!i)return o({kind:"skip",reason:`No control found with name="${e.valueName}"`});if(i instanceof HTMLInputElement&&"radio"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"radio"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Radio group "${e.valueName}" has no enabled options`}):o({kind:"radio",name:e.valueName,elements:t})}if(i instanceof HTMLInputElement&&"checkbox"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"checkbox"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Checkbox "${e.valueName}" is disabled`}):t.length>1?o({kind:"checkboxGroup",name:e.valueName,elements:t}):o({kind:"checked",element:t[0]})}if(!0===i.readOnly||null!==i.getAttribute("readonly"))return o({kind:"skip",reason:`Control "${e.valueName}" is readonly in the DOM`});if(i.disabled)return o({kind:"skip",reason:`Control "${e.valueName}" is disabled`});if(i instanceof HTMLSelectElement){const e=[];for(let t=0;t<i.options.length;t++){const n=i.options[t];n.value&&e.push(n.value)}return o(i.multiple?{kind:"multiSelect",element:i,allowedValues:e}:{kind:"select",element:i,allowedValues:e})}if(i instanceof HTMLTextAreaElement)return o({kind:"value",element:i});if(i instanceof HTMLInputElement)return o({kind:"value",element:i});return o({kind:"skip",reason:`Unsupported control type for "${e.valueName}"`})}(e,t))}async function I(e,t){var n,o;const r=function(e){const t=e.target["nxis:pageUrl"];if(!t)return null;try{const n=new URL(t),o=new URL(window.location.href);if(n.origin!==o.origin||n.pathname!==o.pathname)return`Action "${e.name}" was extracted from ${n.origin}${n.pathname} but the current page is ${o.origin}${o.pathname}. The form may have moved or changed.`}catch(e){return null}return null}(e),i=k(e);if(!i){const t=`Form not found for action "${e.name}". The page may have changed since the tool was registered.`,n={success:!1,submitted:!1,message:r?`Warning: ${r} ${t}`:t,filled:[],skipped:[]};return r&&(n.stale=!0),JSON.stringify(n)}const a=C(e,i),s=null!==(n=e.input)&&void 0!==n?n:[],l=[],u=[];let c=!1;for(const e of s)!e.valueRequired||void 0!==t[e.valueName]&&null!==t[e.valueName]||(c=!0,u.push({field:e.valueName,reason:`Required field '${e.valueName}' was not provided. Expected type: ${e["nxis:valueType"]}.`}));for(const e of a){const n=t[e.valueName];if(null==n){u.some(t=>t.field===e.valueName)||u.push({field:e.valueName,reason:"No value provided (optional field)."});continue}const o=R(e,n);!1===o.ok?u.push({field:e.valueName,reason:o.reason}):l.push(e.valueName)}await new Promise(e=>setTimeout(e,0));for(const e of a)if("value"===e.strategy.kind&&l.includes(e.valueName)){const n=e.strategy.element,r=_(null!==(o=t[e.valueName])&&void 0!==o?o:"");n.value!==r&&(u.push({field:e.valueName,reason:`Value was set to "${r}" but the DOM now shows "${n.value}". A framework may have reverted it.`}),l.splice(l.indexOf(e.valueName),1))}const d=l.length>0&&!c;let f=!1;d&&(f=function(e){try{return"function"==typeof e.requestSubmit?e.requestSubmit():e.submit(),!0}catch(e){return console.warn("[nxis/webmcp] Form submission failed:",e),!1}}(i));const p={success:d,submitted:f,message:M(l,u,f,r),filled:l,skipped:u};return r&&(p.stale=!0),JSON.stringify(p)}function M(e,t,n,o){const r=[];if(o&&r.push(`Warning: ${o}`),0===e.length&&0===t.length)return r.push("No fields were filled. Verify field names match the input schema."),r.join(" ");if(e.length>0&&r.push(`Filled ${e.length} field(s): ${e.join(", ")}.`),t.length>0){const e=t.map(e=>`${e.field} (${e.reason})`).join("; ");r.push(`Skipped ${t.length}: ${e}`)}return n?r.push("Form submitted."):e.length>0&&r.push("Form was NOT submitted due to missing required fields or fill errors."),r.join(" ")}function R(e,t){const{strategy:n}=e;switch(n.kind){case"skip":return{ok:!1,reason:n.reason};case"value":return function(e,t){var n;const o=null===(n=Object.getOwnPropertyDescriptor(e instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,"value"))||void 0===n?void 0:n.set;o?o.call(e,t):e.value=t;return e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,_(t));case"checked":return function(e,t){return e.checked=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const t=e.trim().toLowerCase();return""!==t&&"false"!==t&&"0"!==t&&"off"!==t&&"no"!==t}return Boolean(e)}(t),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,t);case"radio":return function(e,t){var n,o;const r=String(t),i=null!==(o=null!==(n=e.find(e=>e.value===r))&&void 0!==n?n:e.find(e=>e.value.toLowerCase()===r.toLowerCase()))&&void 0!==o?o:e.find(e=>function(e){var t;if(e.labels&&e.labels.length>0)return(null!==(t=e.labels[0].textContent)&&void 0!==t?t:"").trim();return e.value}(e).toLowerCase()===r.toLowerCase());if(!i){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`Value "${r}" is not an allowed option for radio "${e[0].name}". Allowed: [${t}].`}}return i.checked=!0,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.elements,t);case"checkboxGroup":return function(e,t){const n=(Array.isArray(t)?t:[t]).map(e=>String(e)),o=n.map(e=>e.toLowerCase());let r=!1;for(const t of e){const e=n.includes(t.value)||o.includes(t.value.toLowerCase());t.checked=e,e&&(r=!0),t.dispatchEvent(new Event("change",{bubbles:!0}))}if(!r){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`None of [${n.join(", ")}] match checkbox group "${e[0].name}". Allowed: [${t}].`}}return{ok:!0}}(n.elements,t);case"select":return function(e,t,n){const o=U(e,t,n);if(null===o)return{ok:!1,reason:`Value "${t}" is not an allowed option for "${e.name}". Allowed: [${n.join(", ")}].`};return e.value=o,e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,String(t),n.allowedValues);case"multiSelect":return function(e,t,n){const o=(Array.isArray(t)?t:[t]).map(e=>String(e)),r=new Set,i=[];for(const t of o){const o=U(e,t,n);null===o?i.push(t):r.add(o)}if(0===r.size)return{ok:!1,reason:`None of [${o.join(", ")}] are allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};for(const t of Array.from(e.options))t.selected=r.has(t.value);if(e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),i.length>0)return{ok:!1,reason:`Selected [${Array.from(r).join(", ")}] but [${i.join(", ")}] are not allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};return{ok:!0}}(n.element,t,n.allowedValues);default:return{ok:!1,reason:`Unsupported fill strategy for field "${e.valueName}".`}}}function _(e){return Array.isArray(e)?e.map(e=>String(e)).join(","):String(e)}function U(e,t,n){if(n.includes(t))return t;const o=n.find(e=>e.toLowerCase()===t.toLowerCase());if(o)return o;for(const n of Array.from(e.options))if(n.text.toLowerCase()===t.toLowerCase())return n.value;return null}function V(e){var t;const n=!1!==(null==e?void 0:e.observe),o=null!==(t=null==e?void 0:e.doc)&&void 0!==t?t:"undefined"!=typeof document?document:void 0;if(!o)return console.warn("[nxis/webmcp] No document available (not running in a browser). Tools will not be registered."),()=>{};!function(e={}){const{force:t=!1,installNavigatorAlias:n=!0}=e,o="undefined"!=typeof document&&document.modelContext||"undefined"!=typeof navigator&&navigator.modelContext||void 0;if(o&&!t)return o;const r=new g;"undefined"!=typeof document&&y(document,r),n&&"undefined"!=typeof navigator&&y(navigator,r)}();const r=function(e){var t,n;const o=null!==(n=null===(t=e.defaultView)||void 0===t?void 0:t.navigator)&&void 0!==n?n:"undefined"!=typeof navigator?navigator:void 0;return e.modelContext||(null==o?void 0:o.modelContext)||null}(o);if(!r)return console.warn("[nxis/webmcp] WebMCP API not available — document.modelContext is undefined. Tools will not be registered."),()=>{};const i=new AbortController;(null==e?void 0:e.signal)&&(e.signal.aborted?i.abort():e.signal.addEventListener("abort",()=>i.abort()));const a={ids:new Set,names:new Set};P(o,r,i,a);let s=null;return n&&(s=function(e,t,n,o){const r=new MutationObserver(r=>{(function(e){for(const t of e)for(const e of Array.from(t.addedNodes)){if(H(e))return!0;if(e instanceof Element&&e.querySelector('script[type="application/ld+json"]'))return!0}return!1})(r)&&P(e,t,n,o)});return n.signal.addEventListener("abort",()=>r.disconnect()),r.observe(e.documentElement,{childList:!0,subtree:!0}),r}(o,r,i,a)),()=>{i.abort(),s&&(s.disconnect(),s=null)}}function P(e,t,n,o){const r=function(e=("undefined"!=typeof document?document:void 0)){const t=[];if(!e)return t;const n=e.querySelectorAll('script[type="application/ld+json"]');for(const e of Array.from(n)){const n=e.textContent;if(!n)continue;let o;try{o=JSON.parse(n)}catch(e){continue}const r=$(o);for(const e of r){const n=T(e);n&&t.push(n)}}return t}(e);let i=0;for(const e of r)if(!o.ids.has(e["@id"]))try{D(e,t,n,o),o.ids.add(e["@id"]),i++}catch(t){console.warn(`[nxis/webmcp] Failed to register tool for action "${e.name}":`,t)}i>0&&console.info(`[nxis/webmcp] Registered ${i} tool(s) (${o.ids.size} total) from ${r.length} action(s).`)}function D(e,t,n,o){const r=function(e){var t;const n={},o=[],r=null!==(t=e.input)&&void 0!==t?t:[];for(const e of r){const t=S(e);if(e.multipleValues){const o={type:"array",items:t};void 0!==e.valueMinLength&&(o.minItems=e.valueMinLength,delete t.minLength),void 0!==e.valueMaxLength&&(o.maxItems=e.valueMaxLength,delete t.maxLength),e.description&&(o.description=e.description,delete t.description),n[e.valueName]=o}else n[e.valueName]=t;e.valueRequired&&o.push(e.valueName)}const i={type:"object",properties:n};return o.length>0&&(i.required=o),i}(e),i=function(e,t){if(!t.has(e))return e;for(let n=2;;n++){const o=`_${n}`,r=e.slice(0,64-o.length)+o;if(!t.has(r))return r}}(function(e){return e.toLowerCase().replace(/[\s-]+/g,"_").replace(/[^a-z0-9_]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").slice(0,64)||"unnamed_action"}(e.name),o.names);t.registerTool({name:i,description:e.description,inputSchema:r,annotations:{readOnlyHint:!1,untrustedContentHint:!0,"ai.nxis/actionId":e["@id"]},execute:async t=>I(e,t)},{signal:n.signal}),o.names.add(i)}function H(e){return e instanceof HTMLScriptElement&&"application/ld+json"===e.type}function q(t){t instanceof e?console.warn(JSON.parse(t.message).message):console.error(`Unable to retrieve structured data for ${window.location.href}`)}!function(){var t,o;const r=window.__NXIS_CONFIG__,i=null!==(o=null===(t=null==r?void 0:r.webmcp)||void 0===t?void 0:t.mode)&&void 0!==o?o:"browser";if("ssr"===i)return void V();const a=process.env.NXIS_API_HOST,s=new Headers,l=new URL(`${a}/v1/nxis:inject`);l.search=function(e){var t,n;const o=new URLSearchParams;return(null===(t=e.organization_id)||void 0===t?void 0:t.value)&&o.append("organization_id",e.organization_id.value),(null===(n=e.site_id)||void 0===n?void 0:n.value)&&o.append("site_id",e.site_id.value),o.append("uri",e.uri.href),e.referrer&&o.append("referrer",e.referrer),o}({organization_id:{value:null==r?void 0:r.org_id},site_id:{value:null==r?void 0:r.site_id},uri:new URL(window.location.href),referrer:document.referrer}).toString(),(null==r?void 0:r.sub_id)&&s.set("X-NXIS-SUBSCRIPTION",r.sub_id),s.set("Content-Type","application/json"),s.set("User-Agent",navigator.userAgent),fetch(`${l}`,{headers:s}).then(t=>async function(t,o){const r=null!=o?o:"unknown";if(200===t.status){const n=await t.json();if((null==n?void 0:n.data)&&Object.keys(n.data).length>0)return n;throw new e(JSON.stringify({message:`No Nxis resource found for ${r}`}))}const i=await async function(e){try{return await e.json()}catch(e){return null}}(t);if(void 0!==(null==i?void 0:i.code)&&(null==i?void 0:i.message))throw n.fromResponse(t.status,i);switch(t.status){case 500:throw new n(13,500,"An internal server error occurred, please contact technical support.");case 502:throw new n(13,502,"An internal server error occurred, please contact technical support.");case 503:throw new n(8,503,"Service is temporarily unavailable, please try again later.");default:throw new n(13,t.status,`Unexpected response status: ${t.status}`)}}(t,window.location.href)).then(e=>{!function(e){if(e.data&&Object.keys(e.data).length>0){const t=document.createComment("Nxis.ai"),n=document.createComment("End Nxis.ai"),o=document.createElement("script");o.setAttribute("type","application/ld+json"),o.textContent=JSON.stringify(e.data),document.head.appendChild(o),o.before(t),o.after(n)}}(e),"browser"===i&&V()}).catch(q)}();
|
|
1
|
+
!function(){const e={NXIS_API_HOST:"https://proxy.nxis.ai"};try{if(process)return process.env=Object.assign({},process.env),void Object.assign(process.env,e)}catch(e){}globalThis.process={env:e}}();class e extends Error{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}}var t;!function(e){e[e.OK=0]="OK",e[e.INVALID_ARGUMENT=3]="INVALID_ARGUMENT",e[e.NOT_FOUND=5]="NOT_FOUND",e[e.PERMISSION_DENIED=7]="PERMISSION_DENIED",e[e.RESOURCE_EXHAUSTED=8]="RESOURCE_EXHAUSTED",e[e.INTERNAL=13]="INTERNAL",e[e.UNAUTHENTICATED=16]="UNAUTHENTICATED"}(t||(t={})),t.OK,t.INVALID_ARGUMENT,t.NOT_FOUND,t.PERMISSION_DENIED,t.RESOURCE_EXHAUSTED,t.INTERNAL,t.UNAUTHENTICATED;class n extends Error{constructor(e,t,o){super(o),this.code=e,this.httpStatus=t,this.name="ProxyError",Object.setPrototypeOf(this,n.prototype)}get isRetryable(){return this.code===t.RESOURCE_EXHAUSTED||this.code===t.INTERNAL}get isAuthError(){return this.code===t.UNAUTHENTICATED||this.code===t.PERMISSION_DENIED}static fromResponse(e,t){return new n(t.code,e,t.message)}}var o,r,i=function(e,t,n,o,r){if("m"===o)throw new TypeError("Private method is not writable");if("a"===o&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===o?r.call(e,n):r?r.value=n:t.set(e,n),n},a=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)};class s extends Event{constructor(e,t={}){super(e,t),o.set(this,void 0),i(this,o,`${t.toolName??""}`,"f")}get toolName(){return a(this,o,"f")}}o=new WeakMap;class l extends Event{constructor(e,t={}){super(e,t),r.set(this,void 0),i(this,r,`${t.toolName??""}`,"f")}get toolName(){return a(this,r,"f")}}r=new WeakMap;var u,c,d,f,p,m,h,v,g,w,y=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)};const b=/^[A-Za-z0-9_.-]{1,128}$/;function E(e,t){return"function"==typeof DOMException?new DOMException(e,t):Object.assign(new Error(e),{name:t})}function T(e){setTimeout(e,0)}function x(e){return`${e}`}function N(e){const t=x(e);return"function"==typeof t.toWellFormed?t.toWellFormed():t.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,"�")}function A(e){return"object"==typeof e&&null!==e||"function"==typeof e}function $(e){const t=JSON.stringify(e);if(void 0===t)throw new TypeError("The value cannot be serialized as JSON.");return t}function S(e,t){if(null==e)return{};if(!A(e))throw new TypeError(`The provided value is not of type '${t}'.`);return e}function j(e,t,n){const o=e[t];if(void 0===o)throw new TypeError(`Failed to read the '${t}' property from '${n}': Required member is undefined.`);return o}function O(e){const t=S(e,"ToolAnnotations"),n=e=>void 0!==t[e]&&Boolean(t[e]);return{consequentialHint:n("consequentialHint"),debugging:n("debugging"),readOnlyHint:n("readOnlyHint"),untrustedContentHint:n("untrustedContentHint")}}function C(e,t){if(void 0!==e){if("function"==typeof AbortSignal&&!(e instanceof AbortSignal))throw new TypeError(`Failed to read the 'signal' property from '${t}': The provided value is not of type 'AbortSignal'.`);return e}}function k(e,t,n){if(void 0!==e){if(!A(e)||"function"!=typeof e[Symbol.iterator])throw new TypeError(`Failed to read the '${t}' property from '${n}': The provided value cannot be converted to a sequence.`);return[...e].map(N)}}function L(e){const t="RegisteredTool",n=S(e,t);if(void 0!==n.annotations&&O(n.annotations),x(j(n,"description",t)),void 0!==n.inputSchema&&!A(n.inputSchema))throw new TypeError(`Failed to read the 'inputSchema' property from '${t}': The provided value is not of type 'object'.`);const o=x(j(n,"name",t)),r=N(j(n,"origin",t));void 0!==n.title&&x(n.title);const i=j(n,"window",t);if(!function(e){return"undefined"==typeof window?e===globalThis:A(e)&&e.window===e}(i))throw new TypeError(`Failed to read the 'window' property from '${t}': The provided value is not of type 'Window'.`);return{name:o,origin:r,window:i}}function M(){return"undefined"!=typeof window?window:globalThis}function P(){return"undefined"!=typeof location?location.origin:"http://localhost"}function I(e){return e.map(e=>{let t;try{t=new URL(e)}catch{throw E(`"${e}" is not a valid origin.`,"SecurityError")}if(!function(e){if("null"===e.origin)return!1;if("https:"===e.protocol||"wss:"===e.protocol)return!0;const t=e.hostname;return!("localhost"!==t&&!t.endsWith(".localhost"))||/^127(?:\.\d{1,3}){3}$/.test(t)||"[::1]"===t}(t))throw E(`"${e}" is not a potentially trustworthy origin.`,"SecurityError");return t.origin})}function R(){const e=globalThis,t="undefined"!=typeof location?location.protocol:"";return!1===e.originAgentCluster&&"file:"!==t?E("This page's agent cluster is not origin-keyed.","SecurityError"):function(){if("undefined"==typeof document)return!0;const e=document,t=e.permissionsPolicy??e.featurePolicy;if(!t?.features||!t.allowsFeature)return!0;try{return!t.features().includes("tools")||t.allowsFeature("tools")}catch{return!0}}()?null:E("The 'tools' permissions policy does not allow this document to use tools.","NotAllowedError")}class U extends EventTarget{constructor(){super(...arguments),u.add(this),c.set(this,new Map),d.set(this,new Map),f.set(this,{}),p.set(this,{})}get ontoolchange(){return y(this,f,"f").toolchange??null}set ontoolchange(e){y(this,u,"m",w).call(this,"toolchange",e)}get ontoolactivated(){return y(this,f,"f").toolactivated??null}set ontoolactivated(e){y(this,u,"m",w).call(this,"toolactivated",e)}get ontoolcancel(){return y(this,f,"f").toolcancel??null}set ontoolcancel(e){y(this,u,"m",w).call(this,"toolcancel",e)}registerTool(e,t={}){let n,o,r;try{n=function(e){const t="ModelContextTool",n=S(e,t),o=void 0===n.annotations?void 0:O(n.annotations),r=x(j(n,"description",t)),i=j(n,"execute",t);if("function"!=typeof i)throw new TypeError(`Failed to read the 'execute' property from '${t}': The provided value is not a function.`);const a=n.inputSchema;if(void 0!==a&&!A(a))throw new TypeError(`Failed to read the 'inputSchema' property from '${t}': The provided value is not of type 'object'.`);return{annotations:o,description:r,execute:i,inputSchema:a,name:x(j(n,"name",t)),title:void 0===n.title?void 0:N(n.title)}}(e);const i=S(t,"ModelContextRegisterToolOptions");r=k(i.exposedTo,"exposedTo","ModelContextRegisterToolOptions"),o=C(i.signal,"ModelContextRegisterToolOptions")}catch(e){return Promise.reject(e)}const i=R();if(i)return Promise.reject(i);const a=n.name;if(y(this,c,"f").has(a))return Promise.reject(E(`A tool named "${a}" is already registered.`,"InvalidStateError"));if(!b.test(a))return Promise.reject(E(`"${a}" is not a valid tool name: 1 to 128 ASCII letters, digits, "_", "-" or ".".`,"InvalidStateError"));if(""===n.description)return Promise.reject(E("A tool's description must not be empty.","InvalidStateError"));let s="";if(void 0!==n.inputSchema)try{s=$(n.inputSchema)}catch(e){return Promise.reject(e)}if(o?.aborted)return Promise.reject(o.reason);let l,d=[];if(r)try{d=I(r)}catch(e){return Promise.reject(e)}const f=new Promise((e,t)=>l={resolve:e,reject:t});if(o){const e=o;e.addEventListener("abort",()=>{y(this,u,"m",v).call(this,a),l.reject(e.reason)},{once:!0})}return y(this,c,"f").set(a,{name:a,title:n.title??null,description:n.description,inputSchema:s,annotations:void 0===n.annotations?null:O(n.annotations),exposedOrigins:d,tool:n}),y(this,u,"m",g).call(this),T(()=>l.resolve()),f}getTools(e={}){let t;try{t=k(S(e,"ModelContextGetToolOptions").fromOrigins,"fromOrigins","ModelContextGetToolOptions")}catch(e){return Promise.reject(e)}const n=R();if(n)return Promise.reject(n);if(t)try{I(t)}catch(e){return Promise.reject(e)}return new Promise(e=>{const t=P(),n=M(),o=[...y(this,c,"f").values()].map(e=>{const o={};return e.annotations&&(o.annotations={...e.annotations}),o.description=e.description,""!==e.inputSchema&&(o.inputSchema=JSON.parse(e.inputSchema)),o.name=e.name,o.origin=t,o.title=e.title??"",o.window=n,o});o.sort((e,t)=>e.name<t.name?-1:e.name>t.name?1:0),T(()=>e(o))})}executeTool(e,t,n={}){let o,r;try{o=L(e),r=C(S(n,"ModelContextExecuteToolOptions").signal,"ModelContextExecuteToolOptions")}catch(e){return Promise.reject(e)}const i=R();if(i)return Promise.reject(i);let a,s,l;try{a=new URL(o.origin).origin}catch{return Promise.reject(E(`"${o.origin}" is not a valid origin.`,"NotSupportedError"))}if("null"===a)return Promise.reject(E("A tool's origin must not be opaque.","NotSupportedError"));if(!A(t))return Promise.reject(new TypeError("Failed to execute 'executeTool' on 'ModelContext': The input is not an object."));try{s=$(t)}catch(e){return Promise.reject(e)}const f=new Promise((e,t)=>l={resolve:e,reject:t}),p=Symbol("tool execution");if(r){if(r.aborted)return Promise.reject(r.reason);const e=r;e.addEventListener("abort",()=>{l.reject(e.reason),T(()=>y(this,u,"m",h).call(this,p))},{once:!0})}const v=()=>T(()=>l.reject(E("The tool could not be executed.","UnknownError")));return T(()=>{if(o.window!==M()||P()!==a)return v();if(!y(this,c,"f").has(o.name))return v();const e={toolName:o.name,controller:new AbortController,started:!1,complete:(e,t)=>{y(this,d,"f").has(p)&&(y(this,d,"f").delete(p),T(()=>t?l.resolve(e):l.reject(E("The tool's execution failed.","UnknownError"))))}};y(this,d,"f").set(p,e),T(()=>y(this,u,"m",m).call(this,o.name,s,e))}),f}}function _(e,t){e in globalThis||Object.defineProperty(globalThis,e,{value:t,writable:!0,enumerable:!1,configurable:!0})}c=new WeakMap,d=new WeakMap,f=new WeakMap,p=new WeakMap,u=new WeakSet,m=function(e,t,n){const o=y(this,c,"f").get(e);if(!o)return n.complete(null,!1);let r;try{r=JSON.parse(t)}catch{return n.complete(null,!1)}if(!A(r))return n.complete(null,!1);this.dispatchEvent(new s("toolactivated",{toolName:o.name})),n.started=!0;const i={signal:n.controller.signal};let a;try{a=Promise.resolve(o.tool.execute.call(void 0,r,i))}catch(e){a=Promise.reject(e)}a.then(e=>{if(!n.started)return;let t;n.started=!1;try{t=$(e)}catch{return n.complete(null,!1)}n.complete(t,!0)},()=>{n.started&&(n.started=!1,n.complete(null,!1))})},h=function(e){const t=y(this,d,"f").get(e);t&&(y(this,d,"f").delete(e),T(()=>{t.started&&(t.started=!1,t.controller.abort(),this.dispatchEvent(new l("toolcancel",{toolName:t.toolName})))}))},v=function(e){y(this,c,"f").delete(e)&&y(this,u,"m",g).call(this)},g=function(){T(()=>this.dispatchEvent(new Event("toolchange")))},w=function(e,t){const n="function"==typeof t?t:null;if(y(this,f,"f")[e]=n,n&&!y(this,p,"f")[e]){const t=t=>{const n=y(this,f,"f")[e];n&&!1===n.call(this,t)&&t.preventDefault()};y(this,p,"f")[e]=t,this.addEventListener(e,t)}else!n&&y(this,p,"f")[e]&&(this.removeEventListener(e,y(this,p,"f")[e]),delete y(this,p,"f")[e])};const D=["AskAction","SearchAction","SubscribeAction","RegisterAction","BuyAction","OrderAction","AddAction","ScheduleAction","ReserveAction","RsvpAction","ApplyAction","QuoteAction","DownloadAction","ReviewAction","CommentAction","TrackAction","CommunicateAction","InteractAction"];const V="https://nxis.ai/ns#";function F(e,t,n){var o;return null!==(o=e[t])&&void 0!==o?o:e[n]}function H(e,t){return F(e,t,"https://schema.org/"+t)}function W(e,t){const n=H(e,t);return"string"==typeof n?n:null}function q(e,t,n){const o=F(e,t,n);return Array.isArray(o)?o:[]}function z(e){if(Array.isArray(e)){const t=[];for(const n of e)t.push(...z(n));return t}if(e&&"object"==typeof e){const t=e;if(Array.isArray(t["@graph"])){const e=[];for(const n of t["@graph"])e.push(...z(n));return e}return[t]}return[]}function G(e){var t;if(!e||"object"!=typeof e)return null;const n=e,o="string"==typeof n["@type"]?n["@type"]:null;if(!o)return null;if(!o.endsWith("Action")&&!function(e){return D.includes(e)}(o))return null;const r="string"==typeof n["@id"]?n["@id"]:null,i=W(n,"name"),a=function(e){var t,n;if(!e||"object"!=typeof e)return null;const o=e,r=null!==(n=null===(t=W(o,"httpMethod"))||void 0===t?void 0:t.toUpperCase())&&void 0!==n?n:null;if(!r)return null;const i={"@type":"EntryPoint",httpMethod:r},a=W(o,"encodingType");null!==a&&(i.encodingType=a);const s=W(o,"urlTemplate");null!==s&&(i.urlTemplate=s);const l=F(o,"nxis:targetKind",V+"targetKind");"selfPage"!==l&&"clientSide"!==l||(i["nxis:targetKind"]=l);const u=F(o,"nxis:pageUrl",V+"pageUrl");"string"==typeof u&&(i["nxis:pageUrl"]=u);const c=F(o,"nxis:jsHandled",V+"jsHandled");!0===c&&(i["nxis:jsHandled"]=!0);return i}(H(n,"target"));if(!r||!i||!a)return null;const s=q(n,"nxis:input",V+"input").map(X).filter(e=>null!==e),l=null!==(t=W(n,"description"))&&void 0!==t?t:function(e,t,n){const o=e.replace(/^.*[/#]/,"").replace(/Action$/,"").toLowerCase(),r=n.map(e=>e.valueName).join(", ");if(0===n.length)return`Trigger the ${o} action "${t}".`;return`Fill the ${o} form "${t}" with fields: ${r}.`}(o,i,s);return{"@context":n["@context"],"@type":o,"@id":r,name:i,description:l,target:a,input:s.length>0?s:void 0,"nxis:extractedAt":F(n,"nxis:extractedAt",V+"extractedAt")}}function X(e){if(!e||"object"!=typeof e)return null;const t=e,n=W(t,"valueName");if(!n)return null;const o=F(t,"nxis:valueType",V+"valueType"),r={"@type":"PropertyValueSpecification",valueName:n,"nxis:valueType":"string"==typeof o?o:"string"},i=W(t,"description");null!==i&&(r.description=i),!0===H(t,"valueRequired")&&(r.valueRequired=!0);const a=W(t,"defaultValue");null!==a&&(r.defaultValue=a);const s=e=>{const n=H(t,e);return"number"==typeof n?n:null},l=s("valueMinLength");null!==l&&(r.valueMinLength=l);const u=s("valueMaxLength");null!==u&&(r.valueMaxLength=u);const c=s("minValue");null!==c&&(r.minValue=c);const d=s("maxValue");null!==d&&(r.maxValue=d);const f=s("stepValue");null!==f&&(r.stepValue=f);const p=W(t,"valuePattern");null!==p&&(r.valuePattern=p),!0===H(t,"multipleValues")&&(r.multipleValues=!0),!0===H(t,"readonlyValue")&&(r.readonlyValue=!0);const m=q(t,"nxis:valueOption",V+"valueOption");if(m.length>0){const e=m.filter(e=>e&&"object"==typeof e&&null!==W(e,"value")).map(e=>{var t;const n=e;return{"@type":"nxis:ValueOption",value:W(n,"value"),name:null!==(t=W(n,"name"))&&void 0!==t?t:void 0}});e.length>0&&(r["nxis:valueOption"]=e)}return r}function J(e){switch(e){case"string":case"date":case"file":default:return"string";case"number":return"number";case"integer":return"integer";case"boolean":return"boolean"}}function B(e){var t;const n={},o=[],r=null!==(t=e.input)&&void 0!==t?t:[];for(const e of r){const t=K(e);if(e.multipleValues){const o={type:"array",items:t};void 0!==e.valueMinLength&&(o.minItems=e.valueMinLength,delete t.minLength),void 0!==e.valueMaxLength&&(o.maxItems=e.valueMaxLength,delete t.maxLength),e.description&&(o.description=e.description,delete t.description),n[e.valueName]=o}else n[e.valueName]=t;e.valueRequired&&o.push(e.valueName)}const i={type:"object",properties:n};return o.length>0&&(i.required=o),i}function K(e){const t={type:J(e["nxis:valueType"])},n=function(e){if("date"===e)return"date"}(e["nxis:valueType"]);if(n&&(t.format=n),e.description&&(t.description=e.description),void 0!==e.defaultValue&&(t.default=function(e,t){switch(t){case"number":case"integer":{const t=Number(e);return isNaN(t)?e:t}case"boolean":return"true"===e||"1"===e;default:return e}}(e.defaultValue,e["nxis:valueType"])),void 0!==e.valueMinLength&&(t.minLength=e.valueMinLength),void 0!==e.valueMaxLength&&(t.maxLength=e.valueMaxLength),e.valuePattern){const n=e.valuePattern,o=n.startsWith("^")&&n.endsWith("$")?n:`^${n}$`;t.pattern=o}void 0!==e.minValue&&(t.minimum=e.minValue),void 0!==e.maxValue&&(t.maximum=e.maxValue),void 0!==e.stepValue&&(t.multipleOf=e.stepValue),e.readonlyValue&&(t.readOnly=!0);const o=e["nxis:valueOption"];if(o&&o.length>0){t.enum=o.map(e=>e.value);if(o.some(e=>void 0!==e.name&&e.name!==e.value)){const e=o.filter(e=>e.name&&e.name!==e.value).map(e=>`${e.value} = "${e.name}"`).join(", "),n=t.description?`${t.description}. `:"";t.description=`${n}Values: ${e}`}}return t}function Q(e){const t=Array.from(document.querySelectorAll("form"));if(0===t.length)return null;const n=function(e){return e.input?e.input.map(e=>e.valueName):[]}(e);let o;if(o=!e.target.urlTemplate?t:function(e,t,n){const o=function(e){const t=e.replace(/\{[^}]*\}/g,"");try{return new URL(t,window.location.href)}catch(e){return null}}(t);return e.filter(e=>{if((e.method||"GET").toUpperCase()!==n.toUpperCase())return!1;if(!o)return!0;const t=function(e){const t=e.getAttribute("action");if(!t||"#"===t||t.startsWith("#")||""===t)return window.location.href.split("#")[0].split("?")[0];if(t.startsWith("javascript:"))return window.location.href.split("#")[0].split("?")[0];try{return new URL(t,window.location.href).href}catch(e){return t}}(e);return function(e,t){let n;try{n=new URL(e,window.location.href)}catch(e){return!1}if(n.origin!==t.origin)return!1;const o=n.pathname.replace(/\/+$/,""),r=t.pathname.replace(/\/+$/,"");return""===r||(o===r||o.startsWith(r+"/")||r.startsWith(o+"/"))}(t,o)})}(t,e.target.urlTemplate,e.target.httpMethod),0===o.length&&(o=t),1===o.length)return o[0];const r=o.map(e=>({form:e,controlNames:Z(e)})).filter(({controlNames:e})=>n.every(t=>e.has(t)));return 0===r.length?(console.warn(`[nxis/webmcp] No field-set match for action "${e.name}". Expected fields: [${n.join(", ")}]. Falling back to first candidate.`),o[0]):1===r.length?r[0].form:(r.sort((e,t)=>e.controlNames.size-t.controlNames.size),r[0].controlNames.size===r[1].controlNames.size?(console.warn(`[nxis/webmcp] Ambiguous form match for action "${e.name}". ${r.length} forms have identical field sets. Returning null.`),null):r[0].form)}function Z(e){const t=new Set,n=e.elements;for(let e=0;e<n.length;e++){const o=n[e];o.name&&t.add(o.name)}return t}function Y(e,t){var n;return(null!==(n=e.input)&&void 0!==n?n:[]).map(e=>function(e,t){var n;const o=t=>({valueName:e.valueName,pvs:e,strategy:t}),r=function(e,t){const n=[],o=e.elements;for(let e=0;e<o.length;e++){const r=o[e];r.name===t&&n.push(r)}return n}(t,e.valueName),i=null!==(n=r[0])&&void 0!==n?n:null;if(!i)return o({kind:"skip",reason:`No control found with name="${e.valueName}"`});if(i instanceof HTMLInputElement&&"radio"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"radio"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Radio group "${e.valueName}" has no enabled options`}):o({kind:"radio",name:e.valueName,elements:t})}if(i instanceof HTMLInputElement&&"checkbox"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"checkbox"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Checkbox "${e.valueName}" is disabled`}):t.length>1?o({kind:"checkboxGroup",name:e.valueName,elements:t}):o({kind:"checked",element:t[0]})}if(!0===i.readOnly||null!==i.getAttribute("readonly"))return o({kind:"skip",reason:`Control "${e.valueName}" is readonly in the DOM`});if(i.disabled)return o({kind:"skip",reason:`Control "${e.valueName}" is disabled`});if(i instanceof HTMLSelectElement){const e=[];for(let t=0;t<i.options.length;t++){const n=i.options[t];n.value&&e.push(n.value)}return o(i.multiple?{kind:"multiSelect",element:i,allowedValues:e}:{kind:"select",element:i,allowedValues:e})}if(i instanceof HTMLTextAreaElement)return o({kind:"value",element:i});if(i instanceof HTMLInputElement)return o({kind:"value",element:i});return o({kind:"skip",reason:`Unsupported control type for "${e.valueName}"`})}(e,t))}async function ee(e,t){var n,o;const r=function(e){const t=e.target["nxis:pageUrl"];if(!t)return null;try{const n=new URL(t),o=new URL(window.location.href);if(n.origin!==o.origin||n.pathname!==o.pathname)return`Action "${e.name}" was extracted from ${n.origin}${n.pathname} but the current page is ${o.origin}${o.pathname}. The form may have moved or changed.`}catch(e){return null}return null}(e),i=Q(e);if(!i){const t=`Form not found for action "${e.name}". The page may have changed since the tool was registered.`,n={success:!1,submitted:!1,message:r?`Warning: ${r} ${t}`:t,filled:[],skipped:[]};return r&&(n.stale=!0),n}const a=Y(e,i),s=null!==(n=e.input)&&void 0!==n?n:[],l=[],u=[];let c=!1;for(const e of s)!e.valueRequired||void 0!==t[e.valueName]&&null!==t[e.valueName]||(c=!0,u.push({field:e.valueName,reason:`Required field '${e.valueName}' was not provided. Expected type: ${e["nxis:valueType"]}.`}));for(const e of a){const n=t[e.valueName];if(null==n){u.some(t=>t.field===e.valueName)||u.push({field:e.valueName,reason:"No value provided (optional field)."});continue}const o=ne(e,n);!1===o.ok?u.push({field:e.valueName,reason:o.reason}):l.push(e.valueName)}await new Promise(e=>setTimeout(e,0));for(const e of a)if("value"===e.strategy.kind&&l.includes(e.valueName)){const n=e.strategy.element,r=oe(null!==(o=t[e.valueName])&&void 0!==o?o:"");n.value!==r&&(u.push({field:e.valueName,reason:`Value was set to "${r}" but the DOM now shows "${n.value}". A framework may have reverted it.`}),l.splice(l.indexOf(e.valueName),1))}const d=l.length>0&&!c;let f=!1;d&&(f=function(e){try{return"function"==typeof e.requestSubmit?e.requestSubmit():e.submit(),!0}catch(e){return console.warn("[nxis/webmcp] Form submission failed:",e),!1}}(i));const p={success:d,submitted:f,message:te(l,u,f,r),filled:l,skipped:u};return r&&(p.stale=!0),p}function te(e,t,n,o){const r=[];if(o&&r.push(`Warning: ${o}`),0===e.length&&0===t.length)return r.push("No fields were filled. Verify field names match the input schema."),r.join(" ");if(e.length>0&&r.push(`Filled ${e.length} field(s): ${e.join(", ")}.`),t.length>0){const e=t.map(e=>`${e.field} (${e.reason})`).join("; ");r.push(`Skipped ${t.length}: ${e}`)}return n?r.push("Form submitted."):e.length>0&&r.push("Form was NOT submitted due to missing required fields or fill errors."),r.join(" ")}function ne(e,t){const{strategy:n}=e;switch(n.kind){case"skip":return{ok:!1,reason:n.reason};case"value":return function(e,t){var n;const o=null===(n=Object.getOwnPropertyDescriptor(e instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,"value"))||void 0===n?void 0:n.set;o?o.call(e,t):e.value=t;return e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,oe(t));case"checked":return function(e,t){return e.checked=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const t=e.trim().toLowerCase();return""!==t&&"false"!==t&&"0"!==t&&"off"!==t&&"no"!==t}return Boolean(e)}(t),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,t);case"radio":return function(e,t){var n,o;const r=String(t),i=null!==(o=null!==(n=e.find(e=>e.value===r))&&void 0!==n?n:e.find(e=>e.value.toLowerCase()===r.toLowerCase()))&&void 0!==o?o:e.find(e=>function(e){var t;if(e.labels&&e.labels.length>0)return(null!==(t=e.labels[0].textContent)&&void 0!==t?t:"").trim();return e.value}(e).toLowerCase()===r.toLowerCase());if(!i){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`Value "${r}" is not an allowed option for radio "${e[0].name}". Allowed: [${t}].`}}return i.checked=!0,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.elements,t);case"checkboxGroup":return function(e,t){const n=(Array.isArray(t)?t:[t]).map(e=>String(e)),o=n.map(e=>e.toLowerCase());let r=!1;for(const t of e){const e=n.includes(t.value)||o.includes(t.value.toLowerCase());t.checked=e,e&&(r=!0),t.dispatchEvent(new Event("change",{bubbles:!0}))}if(!r){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`None of [${n.join(", ")}] match checkbox group "${e[0].name}". Allowed: [${t}].`}}return{ok:!0}}(n.elements,t);case"select":return function(e,t,n){const o=re(e,t,n);if(null===o)return{ok:!1,reason:`Value "${t}" is not an allowed option for "${e.name}". Allowed: [${n.join(", ")}].`};return e.value=o,e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,String(t),n.allowedValues);case"multiSelect":return function(e,t,n){const o=(Array.isArray(t)?t:[t]).map(e=>String(e)),r=new Set,i=[];for(const t of o){const o=re(e,t,n);null===o?i.push(t):r.add(o)}if(0===r.size)return{ok:!1,reason:`None of [${o.join(", ")}] are allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};for(const t of Array.from(e.options))t.selected=r.has(t.value);if(e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),i.length>0)return{ok:!1,reason:`Selected [${Array.from(r).join(", ")}] but [${i.join(", ")}] are not allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};return{ok:!0}}(n.element,t,n.allowedValues);default:return{ok:!1,reason:`Unsupported fill strategy for field "${e.valueName}".`}}}function oe(e){return Array.isArray(e)?e.map(e=>String(e)).join(","):String(e)}function re(e,t,n){if(n.includes(t))return t;const o=n.find(e=>e.toLowerCase()===t.toLowerCase());if(o)return o;for(const n of Array.from(e.options))if(n.text.toLowerCase()===t.toLowerCase())return n.value;return null}function ie(e){var t;const n=!1!==(null==e?void 0:e.observe),o=null!==(t=null==e?void 0:e.doc)&&void 0!==t?t:"undefined"!=typeof document?document:void 0;if(!o)return console.warn("[nxis/webmcp] No document available (not running in a browser). Tools will not be registered."),()=>{};!function(e={}){const{force:t=!1,installNavigatorAlias:n=!1}=e,o="undefined"!=typeof document&&document.modelContext||"undefined"!=typeof navigator&&navigator.modelContext||void 0;if(o&&!t)return o;if(!1===globalThis.isSecureContext)return;let r;if(_("ModelContext",U),_("ToolActivatedEvent",s),_("ToolCancelEvent",l),"undefined"!=typeof document){const e=globalThis.Document;if(e&&document instanceof e){const t=new WeakMap;Object.defineProperty(e.prototype,"modelContext",{get(){if(!(this instanceof e))throw new TypeError("Illegal invocation");let n=t.get(this);return n||t.set(this,n=new U),n},enumerable:!0,configurable:!0}),Object.prototype.hasOwnProperty.call(document,"modelContext")&&delete document.modelContext}else Object.defineProperty(document,"modelContext",{value:new U,writable:!1,enumerable:!0,configurable:!0});r=document.modelContext}else r=new U;n&&"undefined"!=typeof navigator&&Object.defineProperty(navigator,"modelContext",{value:r,writable:!1,enumerable:!0,configurable:!0})}();const r=function(e){var t,n;const o=null!==(n=null===(t=e.defaultView)||void 0===t?void 0:t.navigator)&&void 0!==n?n:"undefined"!=typeof navigator?navigator:void 0;return e.modelContext||(null==o?void 0:o.modelContext)||null}(o);if(!r)return console.warn("[nxis/webmcp] WebMCP API not available — document.modelContext is undefined. Tools will not be registered."),()=>{};const i=new AbortController;(null==e?void 0:e.signal)&&(e.signal.aborted?i.abort():e.signal.addEventListener("abort",()=>i.abort()));const a={ids:new Set,names:new Set};ae(o,r,i,a);let u=null;return n&&(u=function(e,t,n,o){const r=new MutationObserver(r=>{(function(e){for(const t of e)for(const e of Array.from(t.addedNodes)){if(se(e))return!0;if(e instanceof Element&&e.querySelector('script[type="application/ld+json"]'))return!0}return!1})(r)&&ae(e,t,n,o)});return n.signal.addEventListener("abort",()=>r.disconnect()),r.observe(e.documentElement,{childList:!0,subtree:!0}),r}(o,r,i,a)),()=>{i.abort(),u&&(u.disconnect(),u=null)}}async function ae(e,t,n,o){const r=function(e=("undefined"!=typeof document?document:void 0)){const t=[];if(!e)return t;const n=e.querySelectorAll('script[type="application/ld+json"]');for(const e of Array.from(n)){const n=e.textContent;if(!n)continue;let o;try{o=JSON.parse(n)}catch(e){continue}const r=z(o);for(const e of r){const n=G(e);n&&t.push(n)}}return t}(e).filter(e=>!o.ids.has(e["@id"])),i=await Promise.all(r.map(e=>async function(e,t,n,o){const r=function(e,t){if(!t.has(e))return e;for(let n=2;;n++){const o=`_${n}`,r=e.slice(0,64-o.length)+o;if(!t.has(r))return r}}(function(e){return e.toLowerCase().replace(/[\s-]+/g,"_").replace(/[^a-z0-9_]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").slice(0,64)||"unnamed_action"}(e.name),o.names);o.ids.add(e["@id"]),o.names.add(r);try{const o={name:r,description:e.description||`Fill in and submit the "${e.name}" form.`,inputSchema:B(e),annotations:{readOnlyHint:!1,untrustedContentHint:!0,"ai.nxis/actionId":e["@id"]},execute:t=>ee(e,t)};return await t.registerTool(o,{signal:n.signal}),!0}catch(t){return n.signal.aborted||(o.ids.delete(e["@id"]),o.names.delete(r),console.warn(`[nxis/webmcp] Failed to register tool for action "${e.name}":`,t)),!1}}(e,t,n,o))),a=i.filter(Boolean).length;a>0&&console.info(`[nxis/webmcp] Registered ${a} tool(s) (${o.ids.size} total) from ${r.length} new action(s).`)}function se(e){return e instanceof HTMLScriptElement&&"application/ld+json"===e.type}function le(t){t instanceof e?console.warn(JSON.parse(t.message).message):console.error(`Unable to retrieve structured data for ${window.location.href}`)}!function(){var t,o;const r=window.__NXIS_CONFIG__,i=null!==(o=null===(t=null==r?void 0:r.webmcp)||void 0===t?void 0:t.mode)&&void 0!==o?o:"browser";if("ssr"===i)return void ie();const a=process.env.NXIS_API_HOST,s=new Headers,l=new URL(`${a}/v1/nxis:inject`);l.search=function(e){var t,n;const o=new URLSearchParams;return(null===(t=e.organization_id)||void 0===t?void 0:t.value)&&o.append("organization_id",e.organization_id.value),(null===(n=e.site_id)||void 0===n?void 0:n.value)&&o.append("site_id",e.site_id.value),o.append("uri",e.uri.href),e.referrer&&o.append("referrer",e.referrer),o}({organization_id:{value:null==r?void 0:r.org_id},site_id:{value:null==r?void 0:r.site_id},uri:new URL(window.location.href),referrer:document.referrer}).toString(),(null==r?void 0:r.sub_id)&&s.set("X-NXIS-SUBSCRIPTION",r.sub_id),s.set("Content-Type","application/json"),s.set("User-Agent",navigator.userAgent),fetch(`${l}`,{headers:s}).then(t=>async function(t,o){const r=null!=o?o:"unknown";if(200===t.status){const n=await t.json();if((null==n?void 0:n.data)&&Object.keys(n.data).length>0)return n;throw new e(JSON.stringify({message:`No Nxis resource found for ${r}`}))}const i=await async function(e){try{return await e.json()}catch(e){return null}}(t);if(void 0!==(null==i?void 0:i.code)&&(null==i?void 0:i.message))throw n.fromResponse(t.status,i);switch(t.status){case 500:throw new n(13,500,"An internal server error occurred, please contact technical support.");case 502:throw new n(13,502,"An internal server error occurred, please contact technical support.");case 503:throw new n(8,503,"Service is temporarily unavailable, please try again later.");default:throw new n(13,t.status,`Unexpected response status: ${t.status}`)}}(t,window.location.href)).then(e=>{!function(e){if(e.data&&Object.keys(e.data).length>0){const t=document.createComment("Nxis.ai"),n=document.createComment("End Nxis.ai"),o=document.createElement("script");o.setAttribute("type","application/ld+json"),o.textContent=JSON.stringify(e.data),document.head.appendChild(o),o.before(t),o.after(n)}}(e),"browser"===i&&ie()}).catch(le)}();
|
|
@@ -11,6 +11,24 @@
|
|
|
11
11
|
* @internal
|
|
12
12
|
*/
|
|
13
13
|
import { NxisAction } from './contract';
|
|
14
|
+
/** Result of executing an action fill. */
|
|
15
|
+
export interface FillResult {
|
|
16
|
+
/** Whether the fill was meaningful (at least one field filled, no fatal errors). */
|
|
17
|
+
success: boolean;
|
|
18
|
+
/** Whether the form was submitted after filling. */
|
|
19
|
+
submitted: boolean;
|
|
20
|
+
/** Human-readable summary for agent self-correction. */
|
|
21
|
+
message: string;
|
|
22
|
+
/** Fields that were successfully filled. */
|
|
23
|
+
filled: string[];
|
|
24
|
+
/** Fields that were skipped (with actionable reasons). */
|
|
25
|
+
skipped: Array<{
|
|
26
|
+
field: string;
|
|
27
|
+
reason: string;
|
|
28
|
+
}>;
|
|
29
|
+
/** True when the action was extracted from a different page than the current one. */
|
|
30
|
+
stale?: boolean;
|
|
31
|
+
}
|
|
14
32
|
/**
|
|
15
33
|
* Execute a form fill action.
|
|
16
34
|
*
|
|
@@ -19,6 +37,6 @@ import { NxisAction } from './contract';
|
|
|
19
37
|
*
|
|
20
38
|
* @param action - The NxisAction describing the form.
|
|
21
39
|
* @param args - The argument values to fill, keyed by valueName.
|
|
22
|
-
* @returns
|
|
40
|
+
* @returns The fill result. The WebMCP registry serializes it as JSON for the agent.
|
|
23
41
|
*/
|
|
24
|
-
export declare function executeAction(action: NxisAction, args: Record<string, unknown>): Promise<
|
|
42
|
+
export declare function executeAction(action: NxisAction, args: Record<string, unknown>): Promise<FillResult>;
|
package/build/webmcp/types.d.ts
CHANGED
|
@@ -1,27 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type declarations for the WebMCP imperative API.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* The API itself — `document.modelContext`, and the global `Document`
|
|
5
|
+
* augmentation — is typed by `@nxisai/webmcp`, which follows the WebMCP spec
|
|
6
|
+
* (https://webmachinelearning.github.io/webmcp/). This file adds only what
|
|
7
|
+
* NxisAI tools carry beyond it.
|
|
6
8
|
*
|
|
7
|
-
* `document.modelContext` is canonical (Chrome 150+).
|
|
8
|
-
* `navigator.modelContext` is deprecated but supported as fallback.
|
|
9
|
-
*
|
|
10
|
-
* @see https://developer.chrome.com/docs/ai/webmcp/imperative-api
|
|
11
9
|
* @internal
|
|
12
10
|
*/
|
|
11
|
+
import type { ModelContextAPI, ModelContextTool as SpecModelContextTool, ToolAnnotations as SpecToolAnnotations } from '@nxisai/webmcp';
|
|
12
|
+
/** The ModelContext interface exposed on `document.modelContext`. */
|
|
13
|
+
export type ModelContext = ModelContextAPI;
|
|
13
14
|
/** Annotations that hint to the agent how to treat a tool. */
|
|
14
|
-
export interface ToolAnnotations {
|
|
15
|
-
/**
|
|
16
|
-
* If true, the tool only reads data and does not mutate the page.
|
|
17
|
-
* Set to `false` for form-filling tools (we mutate input values).
|
|
18
|
-
*/
|
|
19
|
-
readOnlyHint?: boolean;
|
|
20
|
-
/**
|
|
21
|
-
* If true, the tool's output contains untrusted content from the page.
|
|
22
|
-
* Always `true` for NxisAI tools — we infer from content we don't control.
|
|
23
|
-
*/
|
|
24
|
-
untrustedContentHint?: boolean;
|
|
15
|
+
export interface ToolAnnotations extends SpecToolAnnotations {
|
|
25
16
|
/**
|
|
26
17
|
* The `@id` of the Action this tool was generated from.
|
|
27
18
|
*
|
|
@@ -29,53 +20,14 @@ export interface ToolAnnotations {
|
|
|
29
20
|
* collision, so it does not identify the action on its own. A client holding
|
|
30
21
|
* the same action from elsewhere — the site's MCP server, say — matches the
|
|
31
22
|
* two by this.
|
|
23
|
+
*
|
|
24
|
+
* Not one of the spec's hints, so `getTools()` does not report it: a spec
|
|
25
|
+
* registry keeps only `readOnlyHint`, `untrustedContentHint`,
|
|
26
|
+
* `consequentialHint` and `debugging`.
|
|
32
27
|
*/
|
|
33
28
|
'ai.nxis/actionId'?: string;
|
|
34
29
|
}
|
|
35
30
|
/** The shape passed to `modelContext.registerTool()`. */
|
|
36
|
-
export interface ModelContextTool {
|
|
37
|
-
/** Tool name — unique within the document. */
|
|
38
|
-
name: string;
|
|
39
|
-
/** Human-readable description of what the tool does. */
|
|
40
|
-
description: string;
|
|
41
|
-
/**
|
|
42
|
-
* JSON Schema describing the tool's input parameters.
|
|
43
|
-
* Passed as a plain object (type: "object" with properties).
|
|
44
|
-
*/
|
|
45
|
-
inputSchema: Record<string, unknown>;
|
|
46
|
-
/** Behavioral hints for the agent. */
|
|
31
|
+
export interface ModelContextTool extends Omit<SpecModelContextTool, 'annotations'> {
|
|
47
32
|
annotations?: ToolAnnotations;
|
|
48
|
-
/**
|
|
49
|
-
* Called by the agent to execute the tool.
|
|
50
|
-
* Must return a string (JSON-serialized result).
|
|
51
|
-
*/
|
|
52
|
-
execute: (args: Record<string, unknown>) => string | Promise<string>;
|
|
53
|
-
}
|
|
54
|
-
/** Options for `modelContext.registerTool()`. */
|
|
55
|
-
export interface RegisterToolOptions {
|
|
56
|
-
/** AbortSignal to unregister the tool when aborted. */
|
|
57
|
-
signal?: AbortSignal;
|
|
58
|
-
}
|
|
59
|
-
/** The ModelContext interface exposed on `document.modelContext`. */
|
|
60
|
-
export interface ModelContext extends EventTarget {
|
|
61
|
-
/** Register a tool for agents to discover and invoke. */
|
|
62
|
-
registerTool(tool: ModelContextTool, options?: RegisterToolOptions): void;
|
|
63
|
-
/** Get all currently registered tools. */
|
|
64
|
-
getTools(): ModelContextTool[];
|
|
65
|
-
}
|
|
66
|
-
declare global {
|
|
67
|
-
interface Document {
|
|
68
|
-
/**
|
|
69
|
-
* The WebMCP model context (canonical, Chrome 150+).
|
|
70
|
-
* Tools are per-Document, not per-Navigator.
|
|
71
|
-
*/
|
|
72
|
-
modelContext?: ModelContext;
|
|
73
|
-
}
|
|
74
|
-
interface Navigator {
|
|
75
|
-
/**
|
|
76
|
-
* @deprecated Use `document.modelContext` instead.
|
|
77
|
-
* Deprecated as of Chrome 150.0.7861.0.
|
|
78
|
-
*/
|
|
79
|
-
modelContext?: ModelContext;
|
|
80
|
-
}
|
|
81
33
|
}
|
package/build/webmcp.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function e(e){return null===e?"null":Array.isArray(e)?"array":typeof e}function t(n,o){if(n===o)return!0;if(e(n)!==e(o))return!1;if(Array.isArray(n)&&Array.isArray(o))return n.length===o.length&&n.every((e,n)=>t(e,o[n]));if("object"===e(n)){const e=n,r=o,i=Object.keys(e);return i.length===Object.keys(r).length&&i.every(n=>t(e[n],r[n]))}return!1}function n(o,r,i="$"){if(!r||"object"!=typeof r)return[];const a=[];if(void 0===r.const||t(o,r.const)||a.push({path:i,message:`must equal const ${JSON.stringify(r.const)}`}),r.enum&&!r.enum.some(e=>t(o,e))&&a.push({path:i,message:`must be one of ${JSON.stringify(r.enum)}`}),void 0!==r.type){const t=Array.isArray(r.type)?r.type:[r.type];if(!t.some(t=>function(t,n){switch(n){case"object":return"object"===e(t);case"array":return Array.isArray(t);case"string":return"string"==typeof t;case"number":return"number"==typeof t&&Number.isFinite(t);case"integer":return"number"==typeof t&&Number.isInteger(t);case"boolean":return"boolean"==typeof t;case"null":return null===t;default:return!0}}(o,t)))return a.push({path:i,message:`expected type ${t.join(" | ")}, got ${e(o)}`}),a}if("string"==typeof o&&(void 0!==r.minLength&&o.length<r.minLength&&a.push({path:i,message:`must be at least ${r.minLength} characters`}),void 0!==r.maxLength&&o.length>r.maxLength&&a.push({path:i,message:`must be at most ${r.maxLength} characters`}),void 0!==r.pattern)){let e=null;try{e=new RegExp(r.pattern,"u")}catch{}e&&!e.test(o)&&a.push({path:i,message:`must match pattern ${r.pattern}`})}if("number"==typeof o&&(void 0!==r.minimum&&o<r.minimum&&a.push({path:i,message:`must be >= ${r.minimum}`}),void 0!==r.maximum&&o>r.maximum&&a.push({path:i,message:`must be <= ${r.maximum}`})),Array.isArray(o)&&(void 0!==r.minItems&&o.length<r.minItems&&a.push({path:i,message:`must have at least ${r.minItems} items`}),void 0!==r.maxItems&&o.length>r.maxItems&&a.push({path:i,message:`must have at most ${r.maxItems} items`}),r.items&&o.forEach((e,t)=>{a.push(...n(e,r.items,`${i}[${t}]`))})),"object"===e(o)&&!Array.isArray(o)&&null!==o){const e=o;for(const t of r.required??[])t in e||a.push({path:i,message:`missing required property "${t}"`});const t=r.properties??{};for(const[o,r]of Object.entries(t))o in e&&a.push(...n(e[o],r,`${i}.${o}`));if(!1===r.additionalProperties)for(const n of Object.keys(e))n in t||a.push({path:i,message:`unexpected property "${n}"`});else if(r.additionalProperties&&"object"==typeof r.additionalProperties)for(const o of Object.keys(e))o in t||a.push(...n(e[o],r.additionalProperties,`${i}.${o}`))}if(r.allOf)for(const e of r.allOf)a.push(...n(o,e,i));if(r.anyOf&&r.anyOf.length>0){r.anyOf.some(e=>0===n(o,e,i).length)||a.push({path:i,message:"does not match any schema in anyOf"})}if(r.oneOf&&r.oneOf.length>0){const e=r.oneOf.filter(e=>0===n(o,e,i).length).length;1!==e&&a.push({path:i,message:`must match exactly one schema in oneOf (matched ${e})`})}return a}var o,r,i,a,s,l,u=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)},c=function(e,t,n,o,r){if("m"===o)throw new TypeError("Private method is not writable");if("a"===o&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===o?r.call(e,n):r?r.value=n:t.set(e,n),n};const f={type:"object"};function d(e,t){if("function"==typeof DOMException)return new DOMException(e,t);const n=new Error(e);return n.name=t,n}function p(e){if(!e||"object"!=typeof e)throw new TypeError("Tool descriptor must be an object.");if("string"!=typeof e.name||0===e.name.length)throw new TypeError("Tool descriptor requires a non-empty string 'name'.");if("string"!=typeof e.description)throw new TypeError(`Tool "${e.name}" requires a string 'description'.`);if("function"!=typeof e.execute)throw new TypeError(`Tool "${e.name}" requires an 'execute' function.`);if(void 0!==e.inputSchema&&"object"!=typeof e.inputSchema)throw new TypeError(`Tool "${e.name}": 'inputSchema' must be an object.`)}class m extends EventTarget{constructor(){super(...arguments),o.add(this),r.set(this,new Map),i.set(this,null),a.set(this,!1)}get ontoolchange(){return u(this,i,"f")}set ontoolchange(e){u(this,i,"f")&&this.removeEventListener("toolchange",u(this,i,"f")),c(this,i,"function"==typeof e?e:null,"f"),u(this,i,"f")&&this.addEventListener("toolchange",u(this,i,"f"))}registerTool(e,t={}){p(e);const{signal:n,exposedTo:i}=t;if(n?.aborted)return;u(this,o,"m",s).call(this,e.name);const a={tool:e,exposedTo:i?[...i]:void 0,pageLevel:!1};if(n){const t=()=>u(this,o,"m",s).call(this,e.name,a,!0);n.addEventListener("abort",t,{once:!0}),a.abortListener={signal:n,listener:t}}u(this,r,"f").set(e.name,a),u(this,o,"m",l).call(this)}provideContext(e={}){const t=e.tools??[];for(const e of t)p(e);if(new Set(t.map(e=>e.name)).size!==t.length)throw new TypeError("provideContext(): duplicate tool names in 'tools'.");for(const[e,t]of u(this,r,"f"))t.pageLevel&&u(this,o,"m",s).call(this,e);for(const e of t){if(u(this,r,"f").has(e.name))throw d(`provideContext(): tool "${e.name}" is already registered via registerTool().`,"InvalidStateError");u(this,r,"f").set(e.name,{tool:e,exposedTo:void 0,pageLevel:!0})}u(this,o,"m",l).call(this)}async getTools(e={}){e.fromOrigins;const t="undefined"!=typeof location?location.origin:void 0;return[...u(this,r,"f").values()].map(({tool:e})=>{const n={name:e.name,description:e.description,inputSchema:structuredClone(e.inputSchema??f)};return e.annotations&&(n.annotations=structuredClone(e.annotations)),t&&(n.origin=t),n})}async executeTool(e,t,o={}){const i=u(this,r,"f").get(e);if(!i)throw d(`No tool registered with name "${e}".`,"NotFoundError");if(o.signal?.aborted)throw d("Tool execution was aborted.","AbortError");let a;if(null==t||""===t)a={};else if("string"==typeof t)try{a=JSON.parse(t)}catch(t){throw new TypeError(`executeTool("${e}"): input is not valid JSON: ${t.message}`)}else a=t;if(null===a||"object"!=typeof a||Array.isArray(a))throw new TypeError(`executeTool("${e}"): input must be a JSON object.`);const s=n(a,i.tool.inputSchema??f);if(s.length>0){const t=s.map(e=>`${e.path}: ${e.message}`).join("; ");throw new TypeError(`executeTool("${e}"): invalid input — ${t}`)}const l=new AbortController,c=o.signal,p=()=>l.abort(c?.reason);c?.addEventListener("abort",p,{once:!0});try{const t=await i.tool.execute(a,{signal:l.signal,toolName:e});if(c?.aborted)throw d("Tool execution was aborted.","AbortError");return function(e){return null==e?{content:[]}:"string"==typeof e?{content:[{type:"text",text:e}]}:"object"==typeof e&&Array.isArray(e.content)?e:{content:[{type:"text",text:JSON.stringify(e)}]}}(t)}catch(e){if(c?.aborted||e instanceof Error&&"AbortError"===e.name)throw d("Tool execution was aborted.","AbortError");return function(e){return{isError:!0,content:[{type:"text",text:e instanceof Error?`${e.name}: ${e.message}`:String(e)}]}}(e)}finally{c?.removeEventListener("abort",p)}}unregisterTool(e){const t=u(this,o,"m",s).call(this,e);return t&&u(this,o,"m",l).call(this),t}clearContext(){if(0!==u(this,r,"f").size){for(const e of[...u(this,r,"f").keys()])u(this,o,"m",s).call(this,e);u(this,o,"m",l).call(this)}}}function h(e,t){Object.defineProperty(e,"modelContext",{value:t,writable:!1,enumerable:!0,configurable:!0})}r=new WeakMap,i=new WeakMap,a=new WeakMap,o=new WeakSet,s=function(e,t,n=!1){const i=u(this,r,"f").get(e);return!!i&&((!t||i===t)&&(i.abortListener&&i.abortListener.signal.removeEventListener("abort",i.abortListener.listener),u(this,r,"f").delete(e),n&&u(this,o,"m",l).call(this),!0))},l=function(){u(this,a,"f")||(c(this,a,!0,"f"),queueMicrotask(()=>{c(this,a,!1,"f"),this.dispatchEvent(new Event("toolchange"))}))};const v=["AskAction","SearchAction","SubscribeAction","RegisterAction","BuyAction","OrderAction","AddAction","ScheduleAction","ReserveAction","RsvpAction","ApplyAction","QuoteAction","DownloadAction","ReviewAction","CommentAction","TrackAction","CommunicateAction","InteractAction"];function g(e){return v.includes(e)}const y="https://nxis.ai/ns#";function b(e,t,n){var o;return null!==(o=e[t])&&void 0!==o?o:e[n]}function w(e,t){return b(e,t,"https://schema.org/"+t)}function x(e,t){const n=w(e,t);return"string"==typeof n?n:null}function $(e,t,n){const o=b(e,t,n);return Array.isArray(o)?o:[]}function A(e=("undefined"!=typeof document?document:void 0)){const t=[];if(!e)return t;const n=e.querySelectorAll('script[type="application/ld+json"]');for(const e of Array.from(n)){const n=e.textContent;if(!n)continue;let o;try{o=JSON.parse(n)}catch(e){continue}const r=E(o);for(const e of r){const n=T(e);n&&t.push(n)}}return t}function E(e){if(Array.isArray(e)){const t=[];for(const n of e)t.push(...E(n));return t}if(e&&"object"==typeof e){const t=e;if(Array.isArray(t["@graph"])){const e=[];for(const n of t["@graph"])e.push(...E(n));return e}return[t]}return[]}function T(e){var t;if(!e||"object"!=typeof e)return null;const n=e,o="string"==typeof n["@type"]?n["@type"]:null;if(!o)return null;if(!o.endsWith("Action")&&!g(o))return null;const r="string"==typeof n["@id"]?n["@id"]:null,i=x(n,"name"),a=function(e){var t,n;if(!e||"object"!=typeof e)return null;const o=e,r=null!==(n=null===(t=x(o,"httpMethod"))||void 0===t?void 0:t.toUpperCase())&&void 0!==n?n:null;if(!r)return null;const i={"@type":"EntryPoint",httpMethod:r},a=x(o,"encodingType");null!==a&&(i.encodingType=a);const s=x(o,"urlTemplate");null!==s&&(i.urlTemplate=s);const l=b(o,"nxis:targetKind",y+"targetKind");"selfPage"!==l&&"clientSide"!==l||(i["nxis:targetKind"]=l);const u=b(o,"nxis:pageUrl",y+"pageUrl");"string"==typeof u&&(i["nxis:pageUrl"]=u);const c=b(o,"nxis:jsHandled",y+"jsHandled");!0===c&&(i["nxis:jsHandled"]=!0);return i}(w(n,"target"));if(!r||!i||!a)return null;const s=$(n,"nxis:input",y+"input").map(L).filter(e=>null!==e),l=null!==(t=x(n,"description"))&&void 0!==t?t:function(e,t,n){const o=e.replace(/^.*[/#]/,"").replace(/Action$/,"").toLowerCase(),r=n.map(e=>e.valueName).join(", ");if(0===n.length)return`Trigger the ${o} action "${t}".`;return`Fill the ${o} form "${t}" with fields: ${r}.`}(o,i,s);return{"@context":n["@context"],"@type":o,"@id":r,name:i,description:l,target:a,input:s.length>0?s:void 0,"nxis:extractedAt":b(n,"nxis:extractedAt",y+"extractedAt")}}function L(e){if(!e||"object"!=typeof e)return null;const t=e,n=x(t,"valueName");if(!n)return null;const o=b(t,"nxis:valueType",y+"valueType"),r={"@type":"PropertyValueSpecification",valueName:n,"nxis:valueType":"string"==typeof o?o:"string"},i=x(t,"description");null!==i&&(r.description=i),!0===w(t,"valueRequired")&&(r.valueRequired=!0);const a=x(t,"defaultValue");null!==a&&(r.defaultValue=a);const s=e=>{const n=w(t,e);return"number"==typeof n?n:null},l=s("valueMinLength");null!==l&&(r.valueMinLength=l);const u=s("valueMaxLength");null!==u&&(r.valueMaxLength=u);const c=s("minValue");null!==c&&(r.minValue=c);const f=s("maxValue");null!==f&&(r.maxValue=f);const d=s("stepValue");null!==d&&(r.stepValue=d);const p=x(t,"valuePattern");null!==p&&(r.valuePattern=p),!0===w(t,"multipleValues")&&(r.multipleValues=!0),!0===w(t,"readonlyValue")&&(r.readonlyValue=!0);const m=$(t,"nxis:valueOption",y+"valueOption");if(m.length>0){const e=m.filter(e=>e&&"object"==typeof e&&null!==x(e,"value")).map(e=>{var t;const n=e;return{"@type":"nxis:ValueOption",value:x(n,"value"),name:null!==(t=x(n,"name"))&&void 0!==t?t:void 0}});e.length>0&&(r["nxis:valueOption"]=e)}return r}function N(e){switch(e){case"string":case"date":case"file":default:return"string";case"number":return"number";case"integer":return"integer";case"boolean":return"boolean"}}function k(e){var t;const n={},o=[],r=null!==(t=e.input)&&void 0!==t?t:[];for(const e of r){const t=j(e);if(e.multipleValues){const o={type:"array",items:t};void 0!==e.valueMinLength&&(o.minItems=e.valueMinLength,delete t.minLength),void 0!==e.valueMaxLength&&(o.maxItems=e.valueMaxLength,delete t.maxLength),e.description&&(o.description=e.description,delete t.description),n[e.valueName]=o}else n[e.valueName]=t;e.valueRequired&&o.push(e.valueName)}const i={type:"object",properties:n};return o.length>0&&(i.required=o),i}function j(e){const t={type:N(e["nxis:valueType"])},n=function(e){if("date"===e)return"date"}(e["nxis:valueType"]);if(n&&(t.format=n),e.description&&(t.description=e.description),void 0!==e.defaultValue&&(t.default=function(e,t){switch(t){case"number":case"integer":{const t=Number(e);return isNaN(t)?e:t}case"boolean":return"true"===e||"1"===e;default:return e}}(e.defaultValue,e["nxis:valueType"])),void 0!==e.valueMinLength&&(t.minLength=e.valueMinLength),void 0!==e.valueMaxLength&&(t.maxLength=e.valueMaxLength),e.valuePattern){const n=e.valuePattern,o=n.startsWith("^")&&n.endsWith("$")?n:`^${n}$`;t.pattern=o}void 0!==e.minValue&&(t.minimum=e.minValue),void 0!==e.maxValue&&(t.maximum=e.maxValue),void 0!==e.stepValue&&(t.multipleOf=e.stepValue),e.readonlyValue&&(t.readOnly=!0);const o=e["nxis:valueOption"];if(o&&o.length>0){t.enum=o.map(e=>e.value);if(o.some(e=>void 0!==e.name&&e.name!==e.value)){const e=o.filter(e=>e.name&&e.name!==e.value).map(e=>`${e.value} = "${e.name}"`).join(", "),n=t.description?`${t.description}. `:"";t.description=`${n}Values: ${e}`}}return t}function S(e){const t=Array.from(document.querySelectorAll("form"));if(0===t.length)return null;const n=function(e){return e.input?e.input.map(e=>e.valueName):[]}(e);let o;if(o=!e.target.urlTemplate?t:function(e,t,n){const o=function(e){const t=e.replace(/\{[^}]*\}/g,"");try{return new URL(t,window.location.href)}catch(e){return null}}(t);return e.filter(e=>{if((e.method||"GET").toUpperCase()!==n.toUpperCase())return!1;if(!o)return!0;const t=function(e){const t=e.getAttribute("action");if(!t||"#"===t||t.startsWith("#")||""===t)return window.location.href.split("#")[0].split("?")[0];if(t.startsWith("javascript:"))return window.location.href.split("#")[0].split("?")[0];try{return new URL(t,window.location.href).href}catch(e){return t}}(e);return function(e,t){let n;try{n=new URL(e,window.location.href)}catch(e){return!1}if(n.origin!==t.origin)return!1;const o=n.pathname.replace(/\/+$/,""),r=t.pathname.replace(/\/+$/,"");return""===r||(o===r||o.startsWith(r+"/")||r.startsWith(o+"/"))}(t,o)})}(t,e.target.urlTemplate,e.target.httpMethod),0===o.length&&(o=t),1===o.length)return o[0];const r=o.map(e=>({form:e,controlNames:O(e)})).filter(({controlNames:e})=>n.every(t=>e.has(t)));return 0===r.length?(console.warn(`[nxis/webmcp] No field-set match for action "${e.name}". Expected fields: [${n.join(", ")}]. Falling back to first candidate.`),o[0]):1===r.length?r[0].form:(r.sort((e,t)=>e.controlNames.size-t.controlNames.size),r[0].controlNames.size===r[1].controlNames.size?(console.warn(`[nxis/webmcp] Ambiguous form match for action "${e.name}". ${r.length} forms have identical field sets. Returning null.`),null):r[0].form)}function O(e){const t=new Set,n=e.elements;for(let e=0;e<n.length;e++){const o=n[e];o.name&&t.add(o.name)}return t}function C(e,t){var n;return(null!==(n=e.input)&&void 0!==n?n:[]).map(e=>function(e,t){var n;const o=t=>({valueName:e.valueName,pvs:e,strategy:t}),r=function(e,t){const n=[],o=e.elements;for(let e=0;e<o.length;e++){const r=o[e];r.name===t&&n.push(r)}return n}(t,e.valueName),i=null!==(n=r[0])&&void 0!==n?n:null;if(!i)return o({kind:"skip",reason:`No control found with name="${e.valueName}"`});if(i instanceof HTMLInputElement&&"radio"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"radio"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Radio group "${e.valueName}" has no enabled options`}):o({kind:"radio",name:e.valueName,elements:t})}if(i instanceof HTMLInputElement&&"checkbox"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"checkbox"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Checkbox "${e.valueName}" is disabled`}):t.length>1?o({kind:"checkboxGroup",name:e.valueName,elements:t}):o({kind:"checked",element:t[0]})}if(!0===i.readOnly||null!==i.getAttribute("readonly"))return o({kind:"skip",reason:`Control "${e.valueName}" is readonly in the DOM`});if(i.disabled)return o({kind:"skip",reason:`Control "${e.valueName}" is disabled`});if(i instanceof HTMLSelectElement){const e=[];for(let t=0;t<i.options.length;t++){const n=i.options[t];n.value&&e.push(n.value)}return o(i.multiple?{kind:"multiSelect",element:i,allowedValues:e}:{kind:"select",element:i,allowedValues:e})}if(i instanceof HTMLTextAreaElement)return o({kind:"value",element:i});if(i instanceof HTMLInputElement)return o({kind:"value",element:i});return o({kind:"skip",reason:`Unsupported control type for "${e.valueName}"`})}(e,t))}async function M(e,t){var n,o;const r=function(e){const t=e.target["nxis:pageUrl"];if(!t)return null;try{const n=new URL(t),o=new URL(window.location.href);if(n.origin!==o.origin||n.pathname!==o.pathname)return`Action "${e.name}" was extracted from ${n.origin}${n.pathname} but the current page is ${o.origin}${o.pathname}. The form may have moved or changed.`}catch(e){return null}return null}(e),i=S(e);if(!i){const t=`Form not found for action "${e.name}". The page may have changed since the tool was registered.`,n={success:!1,submitted:!1,message:r?`Warning: ${r} ${t}`:t,filled:[],skipped:[]};return r&&(n.stale=!0),JSON.stringify(n)}const a=C(e,i),s=null!==(n=e.input)&&void 0!==n?n:[],l=[],u=[];let c=!1;for(const e of s)!e.valueRequired||void 0!==t[e.valueName]&&null!==t[e.valueName]||(c=!0,u.push({field:e.valueName,reason:`Required field '${e.valueName}' was not provided. Expected type: ${e["nxis:valueType"]}.`}));for(const e of a){const n=t[e.valueName];if(null==n){u.some(t=>t.field===e.valueName)||u.push({field:e.valueName,reason:"No value provided (optional field)."});continue}const o=q(e,n);!1===o.ok?u.push({field:e.valueName,reason:o.reason}):l.push(e.valueName)}await new Promise(e=>setTimeout(e,0));for(const e of a)if("value"===e.strategy.kind&&l.includes(e.valueName)){const n=e.strategy.element,r=I(null!==(o=t[e.valueName])&&void 0!==o?o:"");n.value!==r&&(u.push({field:e.valueName,reason:`Value was set to "${r}" but the DOM now shows "${n.value}". A framework may have reverted it.`}),l.splice(l.indexOf(e.valueName),1))}const f=l.length>0&&!c;let d=!1;f&&(d=function(e){try{return"function"==typeof e.requestSubmit?e.requestSubmit():e.submit(),!0}catch(e){return console.warn("[nxis/webmcp] Form submission failed:",e),!1}}(i));const p={success:f,submitted:d,message:V(l,u,d,r),filled:l,skipped:u};return r&&(p.stale=!0),JSON.stringify(p)}function V(e,t,n,o){const r=[];if(o&&r.push(`Warning: ${o}`),0===e.length&&0===t.length)return r.push("No fields were filled. Verify field names match the input schema."),r.join(" ");if(e.length>0&&r.push(`Filled ${e.length} field(s): ${e.join(", ")}.`),t.length>0){const e=t.map(e=>`${e.field} (${e.reason})`).join("; ");r.push(`Skipped ${t.length}: ${e}`)}return n?r.push("Form submitted."):e.length>0&&r.push("Form was NOT submitted due to missing required fields or fill errors."),r.join(" ")}function q(e,t){const{strategy:n}=e;switch(n.kind){case"skip":return{ok:!1,reason:n.reason};case"value":return function(e,t){var n;const o=null===(n=Object.getOwnPropertyDescriptor(e instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,"value"))||void 0===n?void 0:n.set;o?o.call(e,t):e.value=t;return e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,I(t));case"checked":return function(e,t){return e.checked=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const t=e.trim().toLowerCase();return""!==t&&"false"!==t&&"0"!==t&&"off"!==t&&"no"!==t}return Boolean(e)}(t),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,t);case"radio":return function(e,t){var n,o;const r=String(t),i=null!==(o=null!==(n=e.find(e=>e.value===r))&&void 0!==n?n:e.find(e=>e.value.toLowerCase()===r.toLowerCase()))&&void 0!==o?o:e.find(e=>function(e){var t;if(e.labels&&e.labels.length>0)return(null!==(t=e.labels[0].textContent)&&void 0!==t?t:"").trim();return e.value}(e).toLowerCase()===r.toLowerCase());if(!i){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`Value "${r}" is not an allowed option for radio "${e[0].name}". Allowed: [${t}].`}}return i.checked=!0,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.elements,t);case"checkboxGroup":return function(e,t){const n=(Array.isArray(t)?t:[t]).map(e=>String(e)),o=n.map(e=>e.toLowerCase());let r=!1;for(const t of e){const e=n.includes(t.value)||o.includes(t.value.toLowerCase());t.checked=e,e&&(r=!0),t.dispatchEvent(new Event("change",{bubbles:!0}))}if(!r){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`None of [${n.join(", ")}] match checkbox group "${e[0].name}". Allowed: [${t}].`}}return{ok:!0}}(n.elements,t);case"select":return function(e,t,n){const o=P(e,t,n);if(null===o)return{ok:!1,reason:`Value "${t}" is not an allowed option for "${e.name}". Allowed: [${n.join(", ")}].`};return e.value=o,e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,String(t),n.allowedValues);case"multiSelect":return function(e,t,n){const o=(Array.isArray(t)?t:[t]).map(e=>String(e)),r=new Set,i=[];for(const t of o){const o=P(e,t,n);null===o?i.push(t):r.add(o)}if(0===r.size)return{ok:!1,reason:`None of [${o.join(", ")}] are allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};for(const t of Array.from(e.options))t.selected=r.has(t.value);if(e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),i.length>0)return{ok:!1,reason:`Selected [${Array.from(r).join(", ")}] but [${i.join(", ")}] are not allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};return{ok:!0}}(n.element,t,n.allowedValues);default:return{ok:!1,reason:`Unsupported fill strategy for field "${e.valueName}".`}}}function I(e){return Array.isArray(e)?e.map(e=>String(e)).join(","):String(e)}function P(e,t,n){if(n.includes(t))return t;const o=n.find(e=>e.toLowerCase()===t.toLowerCase());if(o)return o;for(const n of Array.from(e.options))if(n.text.toLowerCase()===t.toLowerCase())return n.value;return null}function R(e){var t;const n=!1!==(null==e?void 0:e.observe),o=null!==(t=null==e?void 0:e.doc)&&void 0!==t?t:"undefined"!=typeof document?document:void 0;if(!o)return console.warn("[nxis/webmcp] No document available (not running in a browser). Tools will not be registered."),()=>{};!function(e={}){const{force:t=!1,installNavigatorAlias:n=!0}=e,o="undefined"!=typeof document&&document.modelContext||"undefined"!=typeof navigator&&navigator.modelContext||void 0;if(o&&!t)return o;const r=new m;"undefined"!=typeof document&&h(document,r),n&&"undefined"!=typeof navigator&&h(navigator,r)}();const r=function(e){var t,n;const o=null!==(n=null===(t=e.defaultView)||void 0===t?void 0:t.navigator)&&void 0!==n?n:"undefined"!=typeof navigator?navigator:void 0;return e.modelContext||(null==o?void 0:o.modelContext)||null}(o);if(!r)return console.warn("[nxis/webmcp] WebMCP API not available — document.modelContext is undefined. Tools will not be registered."),()=>{};const i=new AbortController;(null==e?void 0:e.signal)&&(e.signal.aborted?i.abort():e.signal.addEventListener("abort",()=>i.abort()));const a={ids:new Set,names:new Set};H(o,r,i,a);let s=null;return n&&(s=function(e,t,n,o){const r=new MutationObserver(r=>{(function(e){for(const t of e)for(const e of Array.from(t.addedNodes)){if(W(e))return!0;if(e instanceof Element&&e.querySelector('script[type="application/ld+json"]'))return!0}return!1})(r)&&H(e,t,n,o)});return n.signal.addEventListener("abort",()=>r.disconnect()),r.observe(e.documentElement,{childList:!0,subtree:!0}),r}(o,r,i,a)),()=>{i.abort(),s&&(s.disconnect(),s=null)}}function H(e,t,n,o){const r=A(e);let i=0;for(const e of r)if(!o.ids.has(e["@id"]))try{U(e,t,n,o),o.ids.add(e["@id"]),i++}catch(t){console.warn(`[nxis/webmcp] Failed to register tool for action "${e.name}":`,t)}i>0&&console.info(`[nxis/webmcp] Registered ${i} tool(s) (${o.ids.size} total) from ${r.length} action(s).`)}function U(e,t,n,o){const r=k(e),i=function(e,t){if(!t.has(e))return e;for(let n=2;;n++){const o=`_${n}`,r=e.slice(0,64-o.length)+o;if(!t.has(r))return r}}(function(e){return e.toLowerCase().replace(/[\s-]+/g,"_").replace(/[^a-z0-9_]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").slice(0,64)||"unnamed_action"}(e.name),o.names);t.registerTool({name:i,description:e.description,inputSchema:r,annotations:{readOnlyHint:!1,untrustedContentHint:!0,"ai.nxis/actionId":e["@id"]},execute:async t=>M(e,t)},{signal:n.signal}),o.names.add(i)}function W(e){return e instanceof HTMLScriptElement&&"application/ld+json"===e.type}export{v as ACTION_SUBTYPES,k as buildInputSchema,g as isActionType,A as readActions,R as registerActions};
|
|
1
|
+
var e,t,n=function(e,t,n,o,r){if("m"===o)throw new TypeError("Private method is not writable");if("a"===o&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===o?r.call(e,n):r?r.value=n:t.set(e,n),n},o=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)};class r extends Event{constructor(t,o={}){super(t,o),e.set(this,void 0),n(this,e,`${o.toolName??""}`,"f")}get toolName(){return o(this,e,"f")}}e=new WeakMap;class i extends Event{constructor(e,o={}){super(e,o),t.set(this,void 0),n(this,t,`${o.toolName??""}`,"f")}get toolName(){return o(this,t,"f")}}t=new WeakMap;var a,l,s,u,c,d,f,p,m,h,v=function(e,t,n,o){if("a"===n&&!o)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?o:"a"===n?o.call(e):o?o.value:t.get(e)};const g=/^[A-Za-z0-9_.-]{1,128}$/;function w(e,t){return"function"==typeof DOMException?new DOMException(e,t):Object.assign(new Error(e),{name:t})}function y(e){setTimeout(e,0)}function b(e){return`${e}`}function x(e){const t=b(e);return"function"==typeof t.toWellFormed?t.toWellFormed():t.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,"�")}function T(e){return"object"==typeof e&&null!==e||"function"==typeof e}function $(e){const t=JSON.stringify(e);if(void 0===t)throw new TypeError("The value cannot be serialized as JSON.");return t}function E(e,t){if(null==e)return{};if(!T(e))throw new TypeError(`The provided value is not of type '${t}'.`);return e}function A(e,t,n){const o=e[t];if(void 0===o)throw new TypeError(`Failed to read the '${t}' property from '${n}': Required member is undefined.`);return o}function j(e){const t=E(e,"ToolAnnotations"),n=e=>void 0!==t[e]&&Boolean(t[e]);return{consequentialHint:n("consequentialHint"),debugging:n("debugging"),readOnlyHint:n("readOnlyHint"),untrustedContentHint:n("untrustedContentHint")}}function N(e,t){if(void 0!==e){if("function"==typeof AbortSignal&&!(e instanceof AbortSignal))throw new TypeError(`Failed to read the 'signal' property from '${t}': The provided value is not of type 'AbortSignal'.`);return e}}function k(e,t,n){if(void 0!==e){if(!T(e)||"function"!=typeof e[Symbol.iterator])throw new TypeError(`Failed to read the '${t}' property from '${n}': The provided value cannot be converted to a sequence.`);return[...e].map(x)}}function S(e){const t="RegisteredTool",n=E(e,t);if(void 0!==n.annotations&&j(n.annotations),b(A(n,"description",t)),void 0!==n.inputSchema&&!T(n.inputSchema))throw new TypeError(`Failed to read the 'inputSchema' property from '${t}': The provided value is not of type 'object'.`);const o=b(A(n,"name",t)),r=x(A(n,"origin",t));void 0!==n.title&&b(n.title);const i=A(n,"window",t);if(!function(e){return"undefined"==typeof window?e===globalThis:T(e)&&e.window===e}(i))throw new TypeError(`Failed to read the 'window' property from '${t}': The provided value is not of type 'Window'.`);return{name:o,origin:r,window:i}}function C(){return"undefined"!=typeof window?window:globalThis}function L(){return"undefined"!=typeof location?location.origin:"http://localhost"}function M(e){return e.map(e=>{let t;try{t=new URL(e)}catch{throw w(`"${e}" is not a valid origin.`,"SecurityError")}if(!function(e){if("null"===e.origin)return!1;if("https:"===e.protocol||"wss:"===e.protocol)return!0;const t=e.hostname;return!("localhost"!==t&&!t.endsWith(".localhost"))||/^127(?:\.\d{1,3}){3}$/.test(t)||"[::1]"===t}(t))throw w(`"${e}" is not a potentially trustworthy origin.`,"SecurityError");return t.origin})}function P(){const e=globalThis,t="undefined"!=typeof location?location.protocol:"";return!1===e.originAgentCluster&&"file:"!==t?w("This page's agent cluster is not origin-keyed.","SecurityError"):function(){if("undefined"==typeof document)return!0;const e=document,t=e.permissionsPolicy??e.featurePolicy;if(!t?.features||!t.allowsFeature)return!0;try{return!t.features().includes("tools")||t.allowsFeature("tools")}catch{return!0}}()?null:w("The 'tools' permissions policy does not allow this document to use tools.","NotAllowedError")}class O extends EventTarget{constructor(){super(...arguments),a.add(this),l.set(this,new Map),s.set(this,new Map),u.set(this,{}),c.set(this,{})}get ontoolchange(){return v(this,u,"f").toolchange??null}set ontoolchange(e){v(this,a,"m",h).call(this,"toolchange",e)}get ontoolactivated(){return v(this,u,"f").toolactivated??null}set ontoolactivated(e){v(this,a,"m",h).call(this,"toolactivated",e)}get ontoolcancel(){return v(this,u,"f").toolcancel??null}set ontoolcancel(e){v(this,a,"m",h).call(this,"toolcancel",e)}registerTool(e,t={}){let n,o,r;try{n=function(e){const t="ModelContextTool",n=E(e,t),o=void 0===n.annotations?void 0:j(n.annotations),r=b(A(n,"description",t)),i=A(n,"execute",t);if("function"!=typeof i)throw new TypeError(`Failed to read the 'execute' property from '${t}': The provided value is not a function.`);const a=n.inputSchema;if(void 0!==a&&!T(a))throw new TypeError(`Failed to read the 'inputSchema' property from '${t}': The provided value is not of type 'object'.`);return{annotations:o,description:r,execute:i,inputSchema:a,name:b(A(n,"name",t)),title:void 0===n.title?void 0:x(n.title)}}(e);const i=E(t,"ModelContextRegisterToolOptions");r=k(i.exposedTo,"exposedTo","ModelContextRegisterToolOptions"),o=N(i.signal,"ModelContextRegisterToolOptions")}catch(e){return Promise.reject(e)}const i=P();if(i)return Promise.reject(i);const s=n.name;if(v(this,l,"f").has(s))return Promise.reject(w(`A tool named "${s}" is already registered.`,"InvalidStateError"));if(!g.test(s))return Promise.reject(w(`"${s}" is not a valid tool name: 1 to 128 ASCII letters, digits, "_", "-" or ".".`,"InvalidStateError"));if(""===n.description)return Promise.reject(w("A tool's description must not be empty.","InvalidStateError"));let u="";if(void 0!==n.inputSchema)try{u=$(n.inputSchema)}catch(e){return Promise.reject(e)}if(o?.aborted)return Promise.reject(o.reason);let c,d=[];if(r)try{d=M(r)}catch(e){return Promise.reject(e)}const f=new Promise((e,t)=>c={resolve:e,reject:t});if(o){const e=o;e.addEventListener("abort",()=>{v(this,a,"m",p).call(this,s),c.reject(e.reason)},{once:!0})}return v(this,l,"f").set(s,{name:s,title:n.title??null,description:n.description,inputSchema:u,annotations:void 0===n.annotations?null:j(n.annotations),exposedOrigins:d,tool:n}),v(this,a,"m",m).call(this),y(()=>c.resolve()),f}getTools(e={}){let t;try{t=k(E(e,"ModelContextGetToolOptions").fromOrigins,"fromOrigins","ModelContextGetToolOptions")}catch(e){return Promise.reject(e)}const n=P();if(n)return Promise.reject(n);if(t)try{M(t)}catch(e){return Promise.reject(e)}return new Promise(e=>{const t=L(),n=C(),o=[...v(this,l,"f").values()].map(e=>{const o={};return e.annotations&&(o.annotations={...e.annotations}),o.description=e.description,""!==e.inputSchema&&(o.inputSchema=JSON.parse(e.inputSchema)),o.name=e.name,o.origin=t,o.title=e.title??"",o.window=n,o});o.sort((e,t)=>e.name<t.name?-1:e.name>t.name?1:0),y(()=>e(o))})}executeTool(e,t,n={}){let o,r;try{o=S(e),r=N(E(n,"ModelContextExecuteToolOptions").signal,"ModelContextExecuteToolOptions")}catch(e){return Promise.reject(e)}const i=P();if(i)return Promise.reject(i);let u,c,p;try{u=new URL(o.origin).origin}catch{return Promise.reject(w(`"${o.origin}" is not a valid origin.`,"NotSupportedError"))}if("null"===u)return Promise.reject(w("A tool's origin must not be opaque.","NotSupportedError"));if(!T(t))return Promise.reject(new TypeError("Failed to execute 'executeTool' on 'ModelContext': The input is not an object."));try{c=$(t)}catch(e){return Promise.reject(e)}const m=new Promise((e,t)=>p={resolve:e,reject:t}),h=Symbol("tool execution");if(r){if(r.aborted)return Promise.reject(r.reason);const e=r;e.addEventListener("abort",()=>{p.reject(e.reason),y(()=>v(this,a,"m",f).call(this,h))},{once:!0})}const g=()=>y(()=>p.reject(w("The tool could not be executed.","UnknownError")));return y(()=>{if(o.window!==C()||L()!==u)return g();if(!v(this,l,"f").has(o.name))return g();const e={toolName:o.name,controller:new AbortController,started:!1,complete:(e,t)=>{v(this,s,"f").has(h)&&(v(this,s,"f").delete(h),y(()=>t?p.resolve(e):p.reject(w("The tool's execution failed.","UnknownError"))))}};v(this,s,"f").set(h,e),y(()=>v(this,a,"m",d).call(this,o.name,c,e))}),m}}function V(e,t){e in globalThis||Object.defineProperty(globalThis,e,{value:t,writable:!0,enumerable:!1,configurable:!0})}l=new WeakMap,s=new WeakMap,u=new WeakMap,c=new WeakMap,a=new WeakSet,d=function(e,t,n){const o=v(this,l,"f").get(e);if(!o)return n.complete(null,!1);let i;try{i=JSON.parse(t)}catch{return n.complete(null,!1)}if(!T(i))return n.complete(null,!1);this.dispatchEvent(new r("toolactivated",{toolName:o.name})),n.started=!0;const a={signal:n.controller.signal};let s;try{s=Promise.resolve(o.tool.execute.call(void 0,i,a))}catch(e){s=Promise.reject(e)}s.then(e=>{if(!n.started)return;let t;n.started=!1;try{t=$(e)}catch{return n.complete(null,!1)}n.complete(t,!0)},()=>{n.started&&(n.started=!1,n.complete(null,!1))})},f=function(e){const t=v(this,s,"f").get(e);t&&(v(this,s,"f").delete(e),y(()=>{t.started&&(t.started=!1,t.controller.abort(),this.dispatchEvent(new i("toolcancel",{toolName:t.toolName})))}))},p=function(e){v(this,l,"f").delete(e)&&v(this,a,"m",m).call(this)},m=function(){y(()=>this.dispatchEvent(new Event("toolchange")))},h=function(e,t){const n="function"==typeof t?t:null;if(v(this,u,"f")[e]=n,n&&!v(this,c,"f")[e]){const t=t=>{const n=v(this,u,"f")[e];n&&!1===n.call(this,t)&&t.preventDefault()};v(this,c,"f")[e]=t,this.addEventListener(e,t)}else!n&&v(this,c,"f")[e]&&(this.removeEventListener(e,v(this,c,"f")[e]),delete v(this,c,"f")[e])};const F=["AskAction","SearchAction","SubscribeAction","RegisterAction","BuyAction","OrderAction","AddAction","ScheduleAction","ReserveAction","RsvpAction","ApplyAction","QuoteAction","DownloadAction","ReviewAction","CommentAction","TrackAction","CommunicateAction","InteractAction"];function R(e){return F.includes(e)}const H="https://nxis.ai/ns#";function W(e,t,n){var o;return null!==(o=e[t])&&void 0!==o?o:e[n]}function U(e,t){return W(e,t,"https://schema.org/"+t)}function q(e,t){const n=U(e,t);return"string"==typeof n?n:null}function I(e,t,n){const o=W(e,t,n);return Array.isArray(o)?o:[]}function D(e=("undefined"!=typeof document?document:void 0)){const t=[];if(!e)return t;const n=e.querySelectorAll('script[type="application/ld+json"]');for(const e of Array.from(n)){const n=e.textContent;if(!n)continue;let o;try{o=JSON.parse(n)}catch(e){continue}const r=_(o);for(const e of r){const n=z(e);n&&t.push(n)}}return t}function _(e){if(Array.isArray(e)){const t=[];for(const n of e)t.push(..._(n));return t}if(e&&"object"==typeof e){const t=e;if(Array.isArray(t["@graph"])){const e=[];for(const n of t["@graph"])e.push(..._(n));return e}return[t]}return[]}function z(e){var t;if(!e||"object"!=typeof e)return null;const n=e,o="string"==typeof n["@type"]?n["@type"]:null;if(!o)return null;if(!o.endsWith("Action")&&!R(o))return null;const r="string"==typeof n["@id"]?n["@id"]:null,i=q(n,"name"),a=function(e){var t,n;if(!e||"object"!=typeof e)return null;const o=e,r=null!==(n=null===(t=q(o,"httpMethod"))||void 0===t?void 0:t.toUpperCase())&&void 0!==n?n:null;if(!r)return null;const i={"@type":"EntryPoint",httpMethod:r},a=q(o,"encodingType");null!==a&&(i.encodingType=a);const l=q(o,"urlTemplate");null!==l&&(i.urlTemplate=l);const s=W(o,"nxis:targetKind",H+"targetKind");"selfPage"!==s&&"clientSide"!==s||(i["nxis:targetKind"]=s);const u=W(o,"nxis:pageUrl",H+"pageUrl");"string"==typeof u&&(i["nxis:pageUrl"]=u);const c=W(o,"nxis:jsHandled",H+"jsHandled");!0===c&&(i["nxis:jsHandled"]=!0);return i}(U(n,"target"));if(!r||!i||!a)return null;const l=I(n,"nxis:input",H+"input").map(B).filter(e=>null!==e),s=null!==(t=q(n,"description"))&&void 0!==t?t:function(e,t,n){const o=e.replace(/^.*[/#]/,"").replace(/Action$/,"").toLowerCase(),r=n.map(e=>e.valueName).join(", ");if(0===n.length)return`Trigger the ${o} action "${t}".`;return`Fill the ${o} form "${t}" with fields: ${r}.`}(o,i,l);return{"@context":n["@context"],"@type":o,"@id":r,name:i,description:s,target:a,input:l.length>0?l:void 0,"nxis:extractedAt":W(n,"nxis:extractedAt",H+"extractedAt")}}function B(e){if(!e||"object"!=typeof e)return null;const t=e,n=q(t,"valueName");if(!n)return null;const o=W(t,"nxis:valueType",H+"valueType"),r={"@type":"PropertyValueSpecification",valueName:n,"nxis:valueType":"string"==typeof o?o:"string"},i=q(t,"description");null!==i&&(r.description=i),!0===U(t,"valueRequired")&&(r.valueRequired=!0);const a=q(t,"defaultValue");null!==a&&(r.defaultValue=a);const l=e=>{const n=U(t,e);return"number"==typeof n?n:null},s=l("valueMinLength");null!==s&&(r.valueMinLength=s);const u=l("valueMaxLength");null!==u&&(r.valueMaxLength=u);const c=l("minValue");null!==c&&(r.minValue=c);const d=l("maxValue");null!==d&&(r.maxValue=d);const f=l("stepValue");null!==f&&(r.stepValue=f);const p=q(t,"valuePattern");null!==p&&(r.valuePattern=p),!0===U(t,"multipleValues")&&(r.multipleValues=!0),!0===U(t,"readonlyValue")&&(r.readonlyValue=!0);const m=I(t,"nxis:valueOption",H+"valueOption");if(m.length>0){const e=m.filter(e=>e&&"object"==typeof e&&null!==q(e,"value")).map(e=>{var t;const n=e;return{"@type":"nxis:ValueOption",value:q(n,"value"),name:null!==(t=q(n,"name"))&&void 0!==t?t:void 0}});e.length>0&&(r["nxis:valueOption"]=e)}return r}function G(e){switch(e){case"string":case"date":case"file":default:return"string";case"number":return"number";case"integer":return"integer";case"boolean":return"boolean"}}function J(e){var t;const n={},o=[],r=null!==(t=e.input)&&void 0!==t?t:[];for(const e of r){const t=K(e);if(e.multipleValues){const o={type:"array",items:t};void 0!==e.valueMinLength&&(o.minItems=e.valueMinLength,delete t.minLength),void 0!==e.valueMaxLength&&(o.maxItems=e.valueMaxLength,delete t.maxLength),e.description&&(o.description=e.description,delete t.description),n[e.valueName]=o}else n[e.valueName]=t;e.valueRequired&&o.push(e.valueName)}const i={type:"object",properties:n};return o.length>0&&(i.required=o),i}function K(e){const t={type:G(e["nxis:valueType"])},n=function(e){if("date"===e)return"date"}(e["nxis:valueType"]);if(n&&(t.format=n),e.description&&(t.description=e.description),void 0!==e.defaultValue&&(t.default=function(e,t){switch(t){case"number":case"integer":{const t=Number(e);return isNaN(t)?e:t}case"boolean":return"true"===e||"1"===e;default:return e}}(e.defaultValue,e["nxis:valueType"])),void 0!==e.valueMinLength&&(t.minLength=e.valueMinLength),void 0!==e.valueMaxLength&&(t.maxLength=e.valueMaxLength),e.valuePattern){const n=e.valuePattern,o=n.startsWith("^")&&n.endsWith("$")?n:`^${n}$`;t.pattern=o}void 0!==e.minValue&&(t.minimum=e.minValue),void 0!==e.maxValue&&(t.maximum=e.maxValue),void 0!==e.stepValue&&(t.multipleOf=e.stepValue),e.readonlyValue&&(t.readOnly=!0);const o=e["nxis:valueOption"];if(o&&o.length>0){t.enum=o.map(e=>e.value);if(o.some(e=>void 0!==e.name&&e.name!==e.value)){const e=o.filter(e=>e.name&&e.name!==e.value).map(e=>`${e.value} = "${e.name}"`).join(", "),n=t.description?`${t.description}. `:"";t.description=`${n}Values: ${e}`}}return t}function Q(e){const t=Array.from(document.querySelectorAll("form"));if(0===t.length)return null;const n=function(e){return e.input?e.input.map(e=>e.valueName):[]}(e);let o;if(o=!e.target.urlTemplate?t:function(e,t,n){const o=function(e){const t=e.replace(/\{[^}]*\}/g,"");try{return new URL(t,window.location.href)}catch(e){return null}}(t);return e.filter(e=>{if((e.method||"GET").toUpperCase()!==n.toUpperCase())return!1;if(!o)return!0;const t=function(e){const t=e.getAttribute("action");if(!t||"#"===t||t.startsWith("#")||""===t)return window.location.href.split("#")[0].split("?")[0];if(t.startsWith("javascript:"))return window.location.href.split("#")[0].split("?")[0];try{return new URL(t,window.location.href).href}catch(e){return t}}(e);return function(e,t){let n;try{n=new URL(e,window.location.href)}catch(e){return!1}if(n.origin!==t.origin)return!1;const o=n.pathname.replace(/\/+$/,""),r=t.pathname.replace(/\/+$/,"");return""===r||(o===r||o.startsWith(r+"/")||r.startsWith(o+"/"))}(t,o)})}(t,e.target.urlTemplate,e.target.httpMethod),0===o.length&&(o=t),1===o.length)return o[0];const r=o.map(e=>({form:e,controlNames:Z(e)})).filter(({controlNames:e})=>n.every(t=>e.has(t)));return 0===r.length?(console.warn(`[nxis/webmcp] No field-set match for action "${e.name}". Expected fields: [${n.join(", ")}]. Falling back to first candidate.`),o[0]):1===r.length?r[0].form:(r.sort((e,t)=>e.controlNames.size-t.controlNames.size),r[0].controlNames.size===r[1].controlNames.size?(console.warn(`[nxis/webmcp] Ambiguous form match for action "${e.name}". ${r.length} forms have identical field sets. Returning null.`),null):r[0].form)}function Z(e){const t=new Set,n=e.elements;for(let e=0;e<n.length;e++){const o=n[e];o.name&&t.add(o.name)}return t}function X(e,t){var n;return(null!==(n=e.input)&&void 0!==n?n:[]).map(e=>function(e,t){var n;const o=t=>({valueName:e.valueName,pvs:e,strategy:t}),r=function(e,t){const n=[],o=e.elements;for(let e=0;e<o.length;e++){const r=o[e];r.name===t&&n.push(r)}return n}(t,e.valueName),i=null!==(n=r[0])&&void 0!==n?n:null;if(!i)return o({kind:"skip",reason:`No control found with name="${e.valueName}"`});if(i instanceof HTMLInputElement&&"radio"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"radio"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Radio group "${e.valueName}" has no enabled options`}):o({kind:"radio",name:e.valueName,elements:t})}if(i instanceof HTMLInputElement&&"checkbox"===i.type){const t=r.filter(e=>e instanceof HTMLInputElement&&"checkbox"===e.type&&!e.disabled);return 0===t.length?o({kind:"skip",reason:`Checkbox "${e.valueName}" is disabled`}):t.length>1?o({kind:"checkboxGroup",name:e.valueName,elements:t}):o({kind:"checked",element:t[0]})}if(!0===i.readOnly||null!==i.getAttribute("readonly"))return o({kind:"skip",reason:`Control "${e.valueName}" is readonly in the DOM`});if(i.disabled)return o({kind:"skip",reason:`Control "${e.valueName}" is disabled`});if(i instanceof HTMLSelectElement){const e=[];for(let t=0;t<i.options.length;t++){const n=i.options[t];n.value&&e.push(n.value)}return o(i.multiple?{kind:"multiSelect",element:i,allowedValues:e}:{kind:"select",element:i,allowedValues:e})}if(i instanceof HTMLTextAreaElement)return o({kind:"value",element:i});if(i instanceof HTMLInputElement)return o({kind:"value",element:i});return o({kind:"skip",reason:`Unsupported control type for "${e.valueName}"`})}(e,t))}async function Y(e,t){var n,o;const r=function(e){const t=e.target["nxis:pageUrl"];if(!t)return null;try{const n=new URL(t),o=new URL(window.location.href);if(n.origin!==o.origin||n.pathname!==o.pathname)return`Action "${e.name}" was extracted from ${n.origin}${n.pathname} but the current page is ${o.origin}${o.pathname}. The form may have moved or changed.`}catch(e){return null}return null}(e),i=Q(e);if(!i){const t=`Form not found for action "${e.name}". The page may have changed since the tool was registered.`,n={success:!1,submitted:!1,message:r?`Warning: ${r} ${t}`:t,filled:[],skipped:[]};return r&&(n.stale=!0),n}const a=X(e,i),l=null!==(n=e.input)&&void 0!==n?n:[],s=[],u=[];let c=!1;for(const e of l)!e.valueRequired||void 0!==t[e.valueName]&&null!==t[e.valueName]||(c=!0,u.push({field:e.valueName,reason:`Required field '${e.valueName}' was not provided. Expected type: ${e["nxis:valueType"]}.`}));for(const e of a){const n=t[e.valueName];if(null==n){u.some(t=>t.field===e.valueName)||u.push({field:e.valueName,reason:"No value provided (optional field)."});continue}const o=te(e,n);!1===o.ok?u.push({field:e.valueName,reason:o.reason}):s.push(e.valueName)}await new Promise(e=>setTimeout(e,0));for(const e of a)if("value"===e.strategy.kind&&s.includes(e.valueName)){const n=e.strategy.element,r=ne(null!==(o=t[e.valueName])&&void 0!==o?o:"");n.value!==r&&(u.push({field:e.valueName,reason:`Value was set to "${r}" but the DOM now shows "${n.value}". A framework may have reverted it.`}),s.splice(s.indexOf(e.valueName),1))}const d=s.length>0&&!c;let f=!1;d&&(f=function(e){try{return"function"==typeof e.requestSubmit?e.requestSubmit():e.submit(),!0}catch(e){return console.warn("[nxis/webmcp] Form submission failed:",e),!1}}(i));const p={success:d,submitted:f,message:ee(s,u,f,r),filled:s,skipped:u};return r&&(p.stale=!0),p}function ee(e,t,n,o){const r=[];if(o&&r.push(`Warning: ${o}`),0===e.length&&0===t.length)return r.push("No fields were filled. Verify field names match the input schema."),r.join(" ");if(e.length>0&&r.push(`Filled ${e.length} field(s): ${e.join(", ")}.`),t.length>0){const e=t.map(e=>`${e.field} (${e.reason})`).join("; ");r.push(`Skipped ${t.length}: ${e}`)}return n?r.push("Form submitted."):e.length>0&&r.push("Form was NOT submitted due to missing required fields or fill errors."),r.join(" ")}function te(e,t){const{strategy:n}=e;switch(n.kind){case"skip":return{ok:!1,reason:n.reason};case"value":return function(e,t){var n;const o=null===(n=Object.getOwnPropertyDescriptor(e instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype,"value"))||void 0===n?void 0:n.set;o?o.call(e,t):e.value=t;return e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,ne(t));case"checked":return function(e,t){return e.checked=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const t=e.trim().toLowerCase();return""!==t&&"false"!==t&&"0"!==t&&"off"!==t&&"no"!==t}return Boolean(e)}(t),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,t);case"radio":return function(e,t){var n,o;const r=String(t),i=null!==(o=null!==(n=e.find(e=>e.value===r))&&void 0!==n?n:e.find(e=>e.value.toLowerCase()===r.toLowerCase()))&&void 0!==o?o:e.find(e=>function(e){var t;if(e.labels&&e.labels.length>0)return(null!==(t=e.labels[0].textContent)&&void 0!==t?t:"").trim();return e.value}(e).toLowerCase()===r.toLowerCase());if(!i){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`Value "${r}" is not an allowed option for radio "${e[0].name}". Allowed: [${t}].`}}return i.checked=!0,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.elements,t);case"checkboxGroup":return function(e,t){const n=(Array.isArray(t)?t:[t]).map(e=>String(e)),o=n.map(e=>e.toLowerCase());let r=!1;for(const t of e){const e=n.includes(t.value)||o.includes(t.value.toLowerCase());t.checked=e,e&&(r=!0),t.dispatchEvent(new Event("change",{bubbles:!0}))}if(!r){const t=e.map(e=>e.value).join(", ");return{ok:!1,reason:`None of [${n.join(", ")}] match checkbox group "${e[0].name}". Allowed: [${t}].`}}return{ok:!0}}(n.elements,t);case"select":return function(e,t,n){const o=oe(e,t,n);if(null===o)return{ok:!1,reason:`Value "${t}" is not an allowed option for "${e.name}". Allowed: [${n.join(", ")}].`};return e.value=o,e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0}}(n.element,String(t),n.allowedValues);case"multiSelect":return function(e,t,n){const o=(Array.isArray(t)?t:[t]).map(e=>String(e)),r=new Set,i=[];for(const t of o){const o=oe(e,t,n);null===o?i.push(t):r.add(o)}if(0===r.size)return{ok:!1,reason:`None of [${o.join(", ")}] are allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};for(const t of Array.from(e.options))t.selected=r.has(t.value);if(e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),i.length>0)return{ok:!1,reason:`Selected [${Array.from(r).join(", ")}] but [${i.join(", ")}] are not allowed options for "${e.name}". Allowed: [${n.join(", ")}].`};return{ok:!0}}(n.element,t,n.allowedValues);default:return{ok:!1,reason:`Unsupported fill strategy for field "${e.valueName}".`}}}function ne(e){return Array.isArray(e)?e.map(e=>String(e)).join(","):String(e)}function oe(e,t,n){if(n.includes(t))return t;const o=n.find(e=>e.toLowerCase()===t.toLowerCase());if(o)return o;for(const n of Array.from(e.options))if(n.text.toLowerCase()===t.toLowerCase())return n.value;return null}function re(e){var t;const n=!1!==(null==e?void 0:e.observe),o=null!==(t=null==e?void 0:e.doc)&&void 0!==t?t:"undefined"!=typeof document?document:void 0;if(!o)return console.warn("[nxis/webmcp] No document available (not running in a browser). Tools will not be registered."),()=>{};!function(e={}){const{force:t=!1,installNavigatorAlias:n=!1}=e,o="undefined"!=typeof document&&document.modelContext||"undefined"!=typeof navigator&&navigator.modelContext||void 0;if(o&&!t)return o;if(!1===globalThis.isSecureContext)return;let a;if(V("ModelContext",O),V("ToolActivatedEvent",r),V("ToolCancelEvent",i),"undefined"!=typeof document){const e=globalThis.Document;if(e&&document instanceof e){const t=new WeakMap;Object.defineProperty(e.prototype,"modelContext",{get(){if(!(this instanceof e))throw new TypeError("Illegal invocation");let n=t.get(this);return n||t.set(this,n=new O),n},enumerable:!0,configurable:!0}),Object.prototype.hasOwnProperty.call(document,"modelContext")&&delete document.modelContext}else Object.defineProperty(document,"modelContext",{value:new O,writable:!1,enumerable:!0,configurable:!0});a=document.modelContext}else a=new O;n&&"undefined"!=typeof navigator&&Object.defineProperty(navigator,"modelContext",{value:a,writable:!1,enumerable:!0,configurable:!0})}();const a=function(e){var t,n;const o=null!==(n=null===(t=e.defaultView)||void 0===t?void 0:t.navigator)&&void 0!==n?n:"undefined"!=typeof navigator?navigator:void 0;return e.modelContext||(null==o?void 0:o.modelContext)||null}(o);if(!a)return console.warn("[nxis/webmcp] WebMCP API not available — document.modelContext is undefined. Tools will not be registered."),()=>{};const l=new AbortController;(null==e?void 0:e.signal)&&(e.signal.aborted?l.abort():e.signal.addEventListener("abort",()=>l.abort()));const s={ids:new Set,names:new Set};ie(o,a,l,s);let u=null;return n&&(u=function(e,t,n,o){const r=new MutationObserver(r=>{(function(e){for(const t of e)for(const e of Array.from(t.addedNodes)){if(ae(e))return!0;if(e instanceof Element&&e.querySelector('script[type="application/ld+json"]'))return!0}return!1})(r)&&ie(e,t,n,o)});return n.signal.addEventListener("abort",()=>r.disconnect()),r.observe(e.documentElement,{childList:!0,subtree:!0}),r}(o,a,l,s)),()=>{l.abort(),u&&(u.disconnect(),u=null)}}async function ie(e,t,n,o){const r=D(e).filter(e=>!o.ids.has(e["@id"])),i=await Promise.all(r.map(e=>async function(e,t,n,o){const r=function(e,t){if(!t.has(e))return e;for(let n=2;;n++){const o=`_${n}`,r=e.slice(0,64-o.length)+o;if(!t.has(r))return r}}(function(e){return e.toLowerCase().replace(/[\s-]+/g,"_").replace(/[^a-z0-9_]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").slice(0,64)||"unnamed_action"}(e.name),o.names);o.ids.add(e["@id"]),o.names.add(r);try{const o={name:r,description:e.description||`Fill in and submit the "${e.name}" form.`,inputSchema:J(e),annotations:{readOnlyHint:!1,untrustedContentHint:!0,"ai.nxis/actionId":e["@id"]},execute:t=>Y(e,t)};return await t.registerTool(o,{signal:n.signal}),!0}catch(t){return n.signal.aborted||(o.ids.delete(e["@id"]),o.names.delete(r),console.warn(`[nxis/webmcp] Failed to register tool for action "${e.name}":`,t)),!1}}(e,t,n,o))),a=i.filter(Boolean).length;a>0&&console.info(`[nxis/webmcp] Registered ${a} tool(s) (${o.ids.size} total) from ${r.length} new action(s).`)}function ae(e){return e instanceof HTMLScriptElement&&"application/ld+json"===e.type}export{F as ACTION_SUBTYPES,J as buildInputSchema,R as isActionType,D as readActions,re as registerActions};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxisai/nxis",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Javascript client for Nxis AI",
|
|
5
5
|
"main": "build/index.cjs.js",
|
|
6
6
|
"module": "build/index.esm.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"rollup-plugin-uglify": "^4.0.0"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@nxisai/webmcp": "^0.
|
|
51
|
+
"@nxisai/webmcp": "^0.2.0",
|
|
52
52
|
"tslib": "^2.3.1",
|
|
53
53
|
"typescript": "^4.4.3",
|
|
54
54
|
"uuid": "^14.0.0",
|
|
@@ -56,8 +56,5 @@
|
|
|
56
56
|
},
|
|
57
57
|
"overrides": {
|
|
58
58
|
"serialize-javascript": "^7.0.5"
|
|
59
|
-
},
|
|
60
|
-
"publishConfig": {
|
|
61
|
-
"registry": "https://registry.npmjs.org"
|
|
62
59
|
}
|
|
63
60
|
}
|
package/src/webmcp/execute.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { reconcileFields, ReconciledField } from './reconcile';
|
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
|
|
22
22
|
/** Result of executing an action fill. */
|
|
23
|
-
interface FillResult {
|
|
23
|
+
export interface FillResult {
|
|
24
24
|
/** Whether the fill was meaningful (at least one field filled, no fatal errors). */
|
|
25
25
|
success: boolean;
|
|
26
26
|
/** Whether the form was submitted after filling. */
|
|
@@ -52,12 +52,12 @@ type FieldFillOutcome =
|
|
|
52
52
|
*
|
|
53
53
|
* @param action - The NxisAction describing the form.
|
|
54
54
|
* @param args - The argument values to fill, keyed by valueName.
|
|
55
|
-
* @returns
|
|
55
|
+
* @returns The fill result. The WebMCP registry serializes it as JSON for the agent.
|
|
56
56
|
*/
|
|
57
57
|
export async function executeAction(
|
|
58
58
|
action: NxisAction,
|
|
59
59
|
args: Record<string, unknown>
|
|
60
|
-
): Promise<
|
|
60
|
+
): Promise<FillResult> {
|
|
61
61
|
// Step 0: Staleness — the action records the page it was extracted from.
|
|
62
62
|
// If the live page differs, the form may have moved or changed; surface a
|
|
63
63
|
// non-fatal warning so the agent can weigh the result.
|
|
@@ -78,7 +78,7 @@ export async function executeAction(
|
|
|
78
78
|
if (staleWarning) {
|
|
79
79
|
result.stale = true;
|
|
80
80
|
}
|
|
81
|
-
return
|
|
81
|
+
return result;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
// Step 2: Reconcile fields
|
|
@@ -165,7 +165,7 @@ export async function executeAction(
|
|
|
165
165
|
result.stale = true;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
return
|
|
168
|
+
return result;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
// ---------------------------------------------------------------------------
|
package/src/webmcp/register.ts
CHANGED
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
* @internal
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import './types'; // Augment Document/Navigator with modelContext
|
|
14
13
|
import { installWebMCPPolyfill } from '@nxisai/webmcp';
|
|
14
|
+
import type { ModelContextTool as SpecModelContextTool } from '@nxisai/webmcp';
|
|
15
15
|
import { NxisAction } from './contract';
|
|
16
16
|
import { readActions } from './parse';
|
|
17
17
|
import { buildInputSchema } from './schema';
|
|
18
18
|
import { executeAction } from './execute';
|
|
19
|
-
import type { ModelContext } from './types';
|
|
19
|
+
import type { ModelContext, ModelContextTool } from './types';
|
|
20
20
|
|
|
21
21
|
// ---------------------------------------------------------------------------
|
|
22
22
|
// Public types
|
|
@@ -90,7 +90,7 @@ export function registerActions(options?: RegisterOptions): () => void {
|
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
// Initial registration
|
|
93
|
-
registerFromDocument(doc, modelContext, controller, registry);
|
|
93
|
+
void registerFromDocument(doc, modelContext, controller, registry);
|
|
94
94
|
|
|
95
95
|
// SPA re-scan via MutationObserver (always-on, opt-out via observe: false)
|
|
96
96
|
let observer: MutationObserver | null = null;
|
|
@@ -134,73 +134,74 @@ function getModelContext(doc: Document): ModelContext | null {
|
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
136
|
* Register tools for all Action specs found in the document.
|
|
137
|
+
*
|
|
138
|
+
* Registration is asynchronous — `registerTool` returns a promise, and every
|
|
139
|
+
* refusal arrives through it — so each action's `@id` and tool name are
|
|
140
|
+
* reserved as soon as it is attempted, and a later pass (the observer's) cannot
|
|
141
|
+
* try the same one while this pass waits.
|
|
137
142
|
*/
|
|
138
|
-
function registerFromDocument(
|
|
143
|
+
async function registerFromDocument(
|
|
139
144
|
doc: Document,
|
|
140
145
|
modelContext: ModelContext,
|
|
141
146
|
controller: AbortController,
|
|
142
147
|
registry: Registry
|
|
143
|
-
): void {
|
|
144
|
-
const actions = readActions(doc);
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// De-dupe by @id
|
|
149
|
-
if (registry.ids.has(action['@id'])) continue;
|
|
150
|
-
|
|
151
|
-
try {
|
|
152
|
-
registerSingleAction(action, modelContext, controller, registry);
|
|
153
|
-
registry.ids.add(action['@id']);
|
|
154
|
-
registeredThisPass++;
|
|
155
|
-
} catch (err) {
|
|
156
|
-
console.warn(
|
|
157
|
-
`[nxis/webmcp] Failed to register tool for action "${action.name}":`,
|
|
158
|
-
err
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
148
|
+
): Promise<void> {
|
|
149
|
+
const actions = readActions(doc).filter((action) => !registry.ids.has(action['@id']));
|
|
150
|
+
const outcomes = await Promise.all(
|
|
151
|
+
actions.map((action) => registerSingleAction(action, modelContext, controller, registry))
|
|
152
|
+
);
|
|
162
153
|
|
|
154
|
+
const registeredThisPass = outcomes.filter(Boolean).length;
|
|
163
155
|
if (registeredThisPass > 0) {
|
|
164
156
|
console.info(
|
|
165
157
|
`[nxis/webmcp] Registered ${registeredThisPass} tool(s) ` +
|
|
166
|
-
`(${registry.ids.size} total) from ${actions.length} action(s).`
|
|
158
|
+
`(${registry.ids.size} total) from ${actions.length} new action(s).`
|
|
167
159
|
);
|
|
168
160
|
}
|
|
169
161
|
}
|
|
170
162
|
|
|
171
163
|
/**
|
|
172
164
|
* Register a single NxisAction as a WebMCP tool.
|
|
165
|
+
*
|
|
166
|
+
* @returns Whether the registry accepted it.
|
|
173
167
|
*/
|
|
174
|
-
function registerSingleAction(
|
|
168
|
+
async function registerSingleAction(
|
|
175
169
|
action: NxisAction,
|
|
176
170
|
modelContext: ModelContext,
|
|
177
171
|
controller: AbortController,
|
|
178
172
|
registry: Registry
|
|
179
|
-
):
|
|
180
|
-
const inputSchema = buildInputSchema(action);
|
|
173
|
+
): Promise<boolean> {
|
|
181
174
|
const name = uniqueToolName(sanitizeToolName(action.name), registry.names);
|
|
175
|
+
registry.ids.add(action['@id']);
|
|
176
|
+
registry.names.add(name);
|
|
182
177
|
|
|
183
|
-
|
|
184
|
-
{
|
|
178
|
+
try {
|
|
179
|
+
const tool: ModelContextTool = {
|
|
185
180
|
name,
|
|
186
|
-
description:
|
|
187
|
-
|
|
181
|
+
// A registry refuses an empty description (WebMCP: InvalidStateError).
|
|
182
|
+
description: action.description || `Fill in and submit the "${action.name}" form.`,
|
|
183
|
+
inputSchema: buildInputSchema(action),
|
|
188
184
|
annotations: {
|
|
189
185
|
readOnlyHint: false,
|
|
190
186
|
untrustedContentHint: true,
|
|
191
187
|
// Which action this is, independent of the name it was given.
|
|
192
188
|
'ai.nxis/actionId': action['@id'],
|
|
193
189
|
},
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
190
|
+
// The fill result as an object: the registry serializes it once, as JSON.
|
|
191
|
+
execute: (args: Record<string, unknown>) => executeAction(action, args),
|
|
192
|
+
};
|
|
193
|
+
await modelContext.registerTool(tool as SpecModelContextTool, { signal: controller.signal });
|
|
194
|
+
return true;
|
|
195
|
+
} catch (err) {
|
|
196
|
+
// Torn down while registering: not a failure.
|
|
197
|
+
if (controller.signal.aborted) return false;
|
|
198
|
+
// Release the reservation, so a failed registerTool doesn't consume the base name and push
|
|
199
|
+
// the next action to a suffix, and a later pass can try this action again.
|
|
200
|
+
registry.ids.delete(action['@id']);
|
|
201
|
+
registry.names.delete(name);
|
|
202
|
+
console.warn(`[nxis/webmcp] Failed to register tool for action "${action.name}":`, err);
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
204
205
|
}
|
|
205
206
|
|
|
206
207
|
/**
|
|
@@ -218,7 +219,7 @@ function createObserver(
|
|
|
218
219
|
): MutationObserver {
|
|
219
220
|
const observer = new MutationObserver((mutations) => {
|
|
220
221
|
if (mutationsAddJsonLd(mutations)) {
|
|
221
|
-
registerFromDocument(doc, modelContext, controller, registry);
|
|
222
|
+
void registerFromDocument(doc, modelContext, controller, registry);
|
|
222
223
|
}
|
|
223
224
|
});
|
|
224
225
|
|
|
@@ -258,7 +259,7 @@ function isJsonLdScript(node: Node): boolean {
|
|
|
258
259
|
/**
|
|
259
260
|
* Sanitize an action name to a valid snake_case tool name.
|
|
260
261
|
* Converts hyphens and spaces to underscores, strips invalid chars.
|
|
261
|
-
*
|
|
262
|
+
* Kept to [a-z0-9_] and 64 chars — within WebMCP's 1–128 of [A-Za-z0-9_.-].
|
|
262
263
|
*/
|
|
263
264
|
function sanitizeToolName(name: string): string {
|
|
264
265
|
return name
|
package/src/webmcp/types.ts
CHANGED
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type declarations for the WebMCP imperative API.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* The API itself — `document.modelContext`, and the global `Document`
|
|
5
|
+
* augmentation — is typed by `@nxisai/webmcp`, which follows the WebMCP spec
|
|
6
|
+
* (https://webmachinelearning.github.io/webmcp/). This file adds only what
|
|
7
|
+
* NxisAI tools carry beyond it.
|
|
6
8
|
*
|
|
7
|
-
* `document.modelContext` is canonical (Chrome 150+).
|
|
8
|
-
* `navigator.modelContext` is deprecated but supported as fallback.
|
|
9
|
-
*
|
|
10
|
-
* @see https://developer.chrome.com/docs/ai/webmcp/imperative-api
|
|
11
9
|
* @internal
|
|
12
10
|
*/
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
import type {
|
|
13
|
+
ModelContextAPI,
|
|
14
|
+
ModelContextTool as SpecModelContextTool,
|
|
15
|
+
ToolAnnotations as SpecToolAnnotations,
|
|
16
|
+
} from '@nxisai/webmcp';
|
|
17
|
+
|
|
18
|
+
/** The ModelContext interface exposed on `document.modelContext`. */
|
|
19
|
+
export type ModelContext = ModelContextAPI;
|
|
17
20
|
|
|
18
21
|
/** Annotations that hint to the agent how to treat a tool. */
|
|
19
|
-
export interface ToolAnnotations {
|
|
20
|
-
/**
|
|
21
|
-
* If true, the tool only reads data and does not mutate the page.
|
|
22
|
-
* Set to `false` for form-filling tools (we mutate input values).
|
|
23
|
-
*/
|
|
24
|
-
readOnlyHint?: boolean;
|
|
25
|
-
/**
|
|
26
|
-
* If true, the tool's output contains untrusted content from the page.
|
|
27
|
-
* Always `true` for NxisAI tools — we infer from content we don't control.
|
|
28
|
-
*/
|
|
29
|
-
untrustedContentHint?: boolean;
|
|
22
|
+
export interface ToolAnnotations extends SpecToolAnnotations {
|
|
30
23
|
/**
|
|
31
24
|
* The `@id` of the Action this tool was generated from.
|
|
32
25
|
*
|
|
@@ -34,62 +27,15 @@ export interface ToolAnnotations {
|
|
|
34
27
|
* collision, so it does not identify the action on its own. A client holding
|
|
35
28
|
* the same action from elsewhere — the site's MCP server, say — matches the
|
|
36
29
|
* two by this.
|
|
30
|
+
*
|
|
31
|
+
* Not one of the spec's hints, so `getTools()` does not report it: a spec
|
|
32
|
+
* registry keeps only `readOnlyHint`, `untrustedContentHint`,
|
|
33
|
+
* `consequentialHint` and `debugging`.
|
|
37
34
|
*/
|
|
38
35
|
'ai.nxis/actionId'?: string;
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
/** The shape passed to `modelContext.registerTool()`. */
|
|
42
|
-
export interface ModelContextTool {
|
|
43
|
-
/** Tool name — unique within the document. */
|
|
44
|
-
name: string;
|
|
45
|
-
/** Human-readable description of what the tool does. */
|
|
46
|
-
description: string;
|
|
47
|
-
/**
|
|
48
|
-
* JSON Schema describing the tool's input parameters.
|
|
49
|
-
* Passed as a plain object (type: "object" with properties).
|
|
50
|
-
*/
|
|
51
|
-
inputSchema: Record<string, unknown>;
|
|
52
|
-
/** Behavioral hints for the agent. */
|
|
39
|
+
export interface ModelContextTool extends Omit<SpecModelContextTool, 'annotations'> {
|
|
53
40
|
annotations?: ToolAnnotations;
|
|
54
|
-
/**
|
|
55
|
-
* Called by the agent to execute the tool.
|
|
56
|
-
* Must return a string (JSON-serialized result).
|
|
57
|
-
*/
|
|
58
|
-
execute: (args: Record<string, unknown>) => string | Promise<string>;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Options for `modelContext.registerTool()`. */
|
|
62
|
-
export interface RegisterToolOptions {
|
|
63
|
-
/** AbortSignal to unregister the tool when aborted. */
|
|
64
|
-
signal?: AbortSignal;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** The ModelContext interface exposed on `document.modelContext`. */
|
|
68
|
-
export interface ModelContext extends EventTarget {
|
|
69
|
-
/** Register a tool for agents to discover and invoke. */
|
|
70
|
-
registerTool(tool: ModelContextTool, options?: RegisterToolOptions): void;
|
|
71
|
-
/** Get all currently registered tools. */
|
|
72
|
-
getTools(): ModelContextTool[];
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// ---------------------------------------------------------------------------
|
|
76
|
-
// Global augmentation
|
|
77
|
-
// ---------------------------------------------------------------------------
|
|
78
|
-
|
|
79
|
-
declare global {
|
|
80
|
-
interface Document {
|
|
81
|
-
/**
|
|
82
|
-
* The WebMCP model context (canonical, Chrome 150+).
|
|
83
|
-
* Tools are per-Document, not per-Navigator.
|
|
84
|
-
*/
|
|
85
|
-
modelContext?: ModelContext;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
interface Navigator {
|
|
89
|
-
/**
|
|
90
|
-
* @deprecated Use `document.modelContext` instead.
|
|
91
|
-
* Deprecated as of Chrome 150.0.7861.0.
|
|
92
|
-
*/
|
|
93
|
-
modelContext?: ModelContext;
|
|
94
|
-
}
|
|
95
41
|
}
|