@useago/sdk 1.13.2 → 1.13.3

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/CHANGELOG.md CHANGED
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.13.3] - 2026-10-13
11
+
12
+ ### Added
13
+
14
+ - **Form submission start notifications.** Use `form:submitting`, the
15
+ `onFormSubmitting` helper, or the widget callback to show a loading state
16
+ after validation and before submission starts. Concurrent submits share one
17
+ start notification; success and failure use the existing outcome events.
18
+
19
+ - **WebMCP `consequentialHint` and `debugging` annotations.** Both are now
20
+ supported in `webmcp.annotations` and forwarded to browser agents.
21
+ `consequentialHint` describes significant, real-world, or irreversible
22
+ effects; `debugging` marks developer tools. These annotations do not change
23
+ AGO's in-app agent or approval behavior. `consequentialHint` remains
24
+ independent of `requiresApproval`.
25
+
26
+ ## [1.13.1] - 2026-09-21
27
+
10
28
  ### Added
11
29
 
12
30
  - **`catalogue: "onDemand"` for navigation.** Route descriptions ride in the
@@ -746,6 +746,11 @@ export declare interface AgoClientEvents {
746
746
  result: unknown;
747
747
  error?: string;
748
748
  };
749
+ /** A validated form collector submission is about to call its submit target. */
750
+ "form:submitting": {
751
+ name: string;
752
+ values: Record<string, unknown>;
753
+ };
749
754
  /**
750
755
  * A form collector submitted successfully. `result` is the raw submit response
751
756
  * (POST body / handler return value / backend relay result) — the third-party
@@ -2246,16 +2251,21 @@ export declare interface TranscribeAudioOptions {
2246
2251
  signal?: AbortSignal;
2247
2252
  }
2248
2253
 
2249
- /** The MCP behavior hints AGO has no equivalent for. */
2254
+ /** Metadata for tools exposed through the WebMCP bridge. */
2250
2255
  declare interface WebMCPToolMeta {
2251
2256
  /**
2252
- * Both default to `false`, so only set what is true: `readOnlyHint` marks a
2253
- * function that changes nothing, `untrustedContentHint` one whose result may
2254
- * carry third-party text.
2257
+ * Optional WebMCP metadata; all fields default to `false` in WebMCP.
2258
+ * These annotations do not affect AGO's in-app agent or approval behavior.
2255
2259
  */
2256
2260
  annotations?: {
2261
+ /** The tool only reads data and does not change state. */
2257
2262
  readOnlyHint?: boolean;
2263
+ /** The output contains content untrusted by the tool author. */
2258
2264
  untrustedContentHint?: boolean;
2265
+ /** Significant, real-world, or irreversible effects; independent of requiresApproval. */
2266
+ consequentialHint?: boolean;
2267
+ /** Intended for debugging and developer tooling. */
2268
+ debugging?: boolean;
2259
2269
  };
2260
2270
  /**
2261
2271
  * This function navigates. The WebMCP call is held open until the function
package/dist/angular.d.ts CHANGED
@@ -746,6 +746,11 @@ export declare interface AgoClientEvents {
746
746
  result: unknown;
747
747
  error?: string;
748
748
  };
749
+ /** A validated form collector submission is about to call its submit target. */
750
+ "form:submitting": {
751
+ name: string;
752
+ values: Record<string, unknown>;
753
+ };
749
754
  /**
750
755
  * A form collector submitted successfully. `result` is the raw submit response
751
756
  * (POST body / handler return value / backend relay result) — the third-party
@@ -2246,16 +2251,21 @@ export declare interface TranscribeAudioOptions {
2246
2251
  signal?: AbortSignal;
2247
2252
  }
2248
2253
 
2249
- /** The MCP behavior hints AGO has no equivalent for. */
2254
+ /** Metadata for tools exposed through the WebMCP bridge. */
2250
2255
  declare interface WebMCPToolMeta {
2251
2256
  /**
2252
- * Both default to `false`, so only set what is true: `readOnlyHint` marks a
2253
- * function that changes nothing, `untrustedContentHint` one whose result may
2254
- * carry third-party text.
2257
+ * Optional WebMCP metadata; all fields default to `false` in WebMCP.
2258
+ * These annotations do not affect AGO's in-app agent or approval behavior.
2255
2259
  */
2256
2260
  annotations?: {
2261
+ /** The tool only reads data and does not change state. */
2257
2262
  readOnlyHint?: boolean;
2263
+ /** The output contains content untrusted by the tool author. */
2258
2264
  untrustedContentHint?: boolean;
2265
+ /** Significant, real-world, or irreversible effects; independent of requiresApproval. */
2266
+ consequentialHint?: boolean;
2267
+ /** Intended for debugging and developer tooling. */
2268
+ debugging?: boolean;
2259
2269
  };
2260
2270
  /**
2261
2271
  * This function navigates. The WebMCP call is held open until the function
@@ -1,11 +1,11 @@
1
1
  import { S as w, g as R } from "./types-D1ZrqVhr.js";
2
2
  var j = /^[a-zA-Z0-9_-]{1,40}$/, V = (s) => s == null || s === "";
3
3
  function S(s, e) {
4
- if ("anyOf" in s) return s.anyOf.some((c) => S(c, e));
5
- if ("allOf" in s) return s.allOf.every((c) => S(c, e));
4
+ if ("anyOf" in s) return s.anyOf.some((m) => S(m, e));
5
+ if ("allOf" in s) return s.allOf.every((m) => S(m, e));
6
6
  const l = e[s.property];
7
7
  if (V(l)) return !1;
8
- if (Array.isArray(s.value)) return s.value.some((c) => String(l) === String(c));
8
+ if (Array.isArray(s.value)) return s.value.some((m) => String(l) === String(m));
9
9
  if (!s.op) return String(l) === String(s.value);
10
10
  const i = Number(l), a = Number(s.value);
11
11
  if (Number.isNaN(i) || Number.isNaN(a)) return !1;
@@ -24,12 +24,12 @@ function S(s, e) {
24
24
  }
25
25
  function p(s, e) {
26
26
  const l = s.properties ?? {}, i = /* @__PURE__ */ new Set();
27
- for (const c of s.required ?? []) {
28
- const d = l[c]?.requiredWhen;
29
- (!d || S(d, e)) && i.add(c);
27
+ for (const m of s.required ?? []) {
28
+ const b = l[m]?.requiredWhen;
29
+ (!b || S(b, e)) && i.add(m);
30
30
  }
31
- for (const [c, d] of Object.entries(l)) d.requiredWhen && S(d.requiredWhen, e) && i.add(c);
32
- const a = [...i].filter((c) => V(e[c]));
31
+ for (const [m, b] of Object.entries(l)) b.requiredWhen && S(b.requiredWhen, e) && i.add(m);
32
+ const a = [...i].filter((m) => V(e[m]));
33
33
  return {
34
34
  missing: a,
35
35
  complete: a.length === 0
@@ -57,10 +57,10 @@ function L(s) {
57
57
  url: s.submit
58
58
  } : !1 : s.submit ?? !1;
59
59
  s.autoSubmit === !0 && !a && w.warn(`FormCollector "${e}": autoSubmit is ignored because no submit target is configured.`);
60
- const c = (s.autoSubmit ?? !0) && !!a, d = i.properties ?? {}, $ = (t) => {
60
+ const m = (s.autoSubmit ?? !0) && !!a, b = i.properties ?? {}, $ = (t) => {
61
61
  const r = {};
62
62
  for (const [o, n] of Object.entries(t)) {
63
- const u = d[o];
63
+ const u = b[o];
64
64
  if (u)
65
65
  if (n == null) r[o] = n;
66
66
  else if (u.type === "number" || u.type === "integer") {
@@ -69,22 +69,22 @@ function L(s) {
69
69
  } else u.type === "boolean" ? r[o] = typeof n == "boolean" ? n : n === "true" ? !0 : n === "false" ? !1 : !!n : r[o] = n;
70
70
  }
71
71
  return r;
72
- }, C = s.initialValues ?? {}, m = R({
72
+ }, C = s.initialValues ?? {}, c = R({
73
73
  values: C,
74
74
  submitted: !1
75
75
  }), F = (t) => {
76
- const r = m.get(), o = {
76
+ const r = c.get(), o = {
77
77
  ...r,
78
78
  values: {
79
79
  ...r.values,
80
80
  ...t
81
81
  }
82
82
  };
83
- return m.set(o), o;
83
+ return c.set(o), o;
84
84
  };
85
- let b = null;
85
+ let d = null;
86
86
  const k = (t, r) => {
87
- b?.emitFormEvent("form:error", {
87
+ d?.emitFormEvent("form:error", {
88
88
  name: e,
89
89
  values: t,
90
90
  error: r
@@ -92,7 +92,7 @@ function L(s) {
92
92
  };
93
93
  let h = null;
94
94
  const A = async () => {
95
- const { values: t } = m.get(), { complete: r, missing: o } = p(i, t);
95
+ const { values: t } = c.get(), { complete: r, missing: o } = p(i, t);
96
96
  if (!r) return {
97
97
  ok: !1,
98
98
  missing: o
@@ -101,8 +101,16 @@ function L(s) {
101
101
  ok: !1,
102
102
  error: "No submit target configured for this form collector."
103
103
  };
104
+ if (a.via === "backend" && !d) return {
105
+ ok: !1,
106
+ error: "Backend submit requires install(client) (or useFormCollector) first."
107
+ };
104
108
  const n = t;
105
109
  try {
110
+ d?.emitFormEvent("form:submitting", {
111
+ name: e,
112
+ values: n
113
+ });
106
114
  let u;
107
115
  if (a.via === "client") if ("handler" in a) u = await a.handler(n);
108
116
  else {
@@ -122,18 +130,12 @@ function L(s) {
122
130
  u = await f.json().catch(() => {
123
131
  });
124
132
  }
125
- else {
126
- if (!b) return {
127
- ok: !1,
128
- error: "Backend submit requires install(client) (or useFormCollector) first."
129
- };
130
- u = await b.submitFormCollector(e, n);
131
- }
132
- return m.set({
133
- ...m.get(),
133
+ else u = await d.submitFormCollector(e, n);
134
+ return c.set({
135
+ ...c.get(),
134
136
  submitted: !0,
135
137
  submitResult: u
136
- }), b?.emitFormEvent("form:submitted", {
138
+ }), d?.emitFormEvent("form:submitted", {
137
139
  name: e,
138
140
  values: n,
139
141
  result: u
@@ -155,8 +157,8 @@ function L(s) {
155
157
  h = null;
156
158
  }
157
159
  })(), h), q = async () => {
158
- if (!c || !a) return null;
159
- const { values: t, submitted: r } = m.get();
160
+ if (!m || !a) return null;
161
+ const { values: t, submitted: r } = c.get();
160
162
  return r || !p(i, t).complete ? null : N();
161
163
  }, x = {
162
164
  name: `update_${e}`,
@@ -182,7 +184,7 @@ function L(s) {
182
184
  };
183
185
  }
184
186
  }, y = [x];
185
- a && !c && y.push({
187
+ a && !m && y.push({
186
188
  name: `submit_${e}`,
187
189
  description: `Submit the completed "${e}" form. Only call this once every required field is collected and the user has confirmed. If fields are missing it returns them instead of submitting.`,
188
190
  parameters: {
@@ -195,7 +197,7 @@ function L(s) {
195
197
  const r = t.functionName ?? t.toolName;
196
198
  if (r)
197
199
  return r.startsWith(I) ? r.slice(8) : r;
198
- }, O = (t) => {
200
+ }, E = (t) => {
199
201
  let r = { ...C }, o = !1;
200
202
  for (const n of t) {
201
203
  const u = D(n);
@@ -204,16 +206,16 @@ function L(s) {
204
206
  ...$(n.arguments)
205
207
  }) : _ && u === _ && n.status?.toLowerCase() === "done" && (o = !0);
206
208
  }
207
- m.set({
209
+ c.set({
208
210
  values: r,
209
211
  submitted: o
210
212
  });
211
- }, g = `form:${e}`, v = `${g}:definition`, T = () => ({
213
+ }, g = `form:${e}`, v = `${g}:definition`, O = () => ({
212
214
  name: `Form definition: ${e}`,
213
215
  description: `${l} Some fields are conditionally required; the requiredWhen field in the schema tells you when each becomes required. The form schema is the following: ${JSON.stringify(i)}.`,
214
216
  stable: !0
215
- }), E = () => {
216
- const { values: t, submitted: r } = m.get(), { missing: o, complete: n } = p(i, t), u = a ? c ? " The form is submitted automatically as soon as every required field is filled, so there is no submit function to call." : ` When nothing is missing and the user confirms, call submit_${e}.` : "", f = r ? `The "${e}" form has been submitted.` : `You are currently collecting information from the user to fill the "${e}" form.`;
217
+ }), T = () => {
218
+ const { values: t, submitted: r } = c.get(), { missing: o, complete: n } = p(i, t), u = a ? m ? " The form is submitted automatically as soon as every required field is filled, so there is no submit function to call." : ` When nothing is missing and the user confirms, call submit_${e}.` : "", f = r ? `The "${e}" form has been submitted.` : `You are currently collecting information from the user to fill the "${e}" form.`;
217
219
  return {
218
220
  name: `Form: ${e}`,
219
221
  description: `${f} The form's schema and field requirements are in the "${v}" client context. Call update_${e} with any fields the user provides; ask only for what is still missing.${u}`,
@@ -225,40 +227,40 @@ function L(s) {
225
227
  }
226
228
  };
227
229
  }, P = (t) => {
228
- O((t.messages ?? []).flatMap((r) => r.toolCalls ?? []));
230
+ E((t.messages ?? []).flatMap((r) => r.toolCalls ?? []));
229
231
  };
230
232
  return {
231
233
  name: e,
232
- store: m,
234
+ store: c,
233
235
  functions: y,
234
236
  contextKey: g,
235
- contextProvider: E,
237
+ contextProvider: T,
236
238
  definitionContextKey: v,
237
- definitionContextProvider: T,
239
+ definitionContextProvider: O,
238
240
  install: (t) => {
239
- b = t;
241
+ d = t;
240
242
  for (const o of y) t.register(o);
241
- t.addDynamicContext(v, T), t.addDynamicContext(g, E);
242
- const r = m.subscribe(() => t.notifyContextChanged());
243
+ t.addDynamicContext(v, O), t.addDynamicContext(g, T);
244
+ const r = c.subscribe(() => t.notifyContextChanged());
243
245
  return t.on("conversation:loaded", P), () => {
244
246
  r();
245
247
  for (const o of y) t.unregisterFunction(o.name);
246
- t.removeDynamicContext(g), t.removeDynamicContext(v), t.off("conversation:loaded", P), b === t && (b = null);
248
+ t.removeDynamicContext(g), t.removeDynamicContext(v), t.off("conversation:loaded", P), d === t && (d = null);
247
249
  };
248
250
  },
249
- hydrate: O,
251
+ hydrate: E,
250
252
  submit: N,
251
- getValues: () => m.get().values,
253
+ getValues: () => c.get().values,
252
254
  setValues: (t) => {
253
255
  F($(t)), q();
254
256
  },
255
257
  reset: () => {
256
- m.set({
258
+ c.set({
257
259
  values: C,
258
260
  submitted: !1
259
261
  });
260
262
  },
261
- getStatus: () => p(i, m.get().values)
263
+ getStatus: () => p(i, c.get().values)
262
264
  };
263
265
  }
264
266
  async function K(s, e) {
@@ -0,0 +1 @@
1
+ const C=require("./types-DNr6XEwI.cjs");var W=/^[a-zA-Z0-9_-]{1,40}$/,V=n=>n==null||n==="";function S(n,e){if("anyOf"in n)return n.anyOf.some(c=>S(c,e));if("allOf"in n)return n.allOf.every(c=>S(c,e));const l=e[n.property];if(V(l))return!1;if(Array.isArray(n.value))return n.value.some(c=>String(l)===String(c));if(!n.op)return String(l)===String(n.value);const i=Number(l),a=Number(n.value);if(Number.isNaN(i)||Number.isNaN(a))return!1;switch(n.op){case">=":return i>=a;case"<=":return i<=a;case">":return i>a;case"<":return i<a;default:return C.logger.warn(`Unknown requiredWhen op "${n.op}"; treating as not required.`),!1}}function h(n,e){const l=n.properties??{},i=new Set;for(const c of n.required??[]){const b=l[c]?.requiredWhen;(!b||S(b,e))&&i.add(c)}for(const[c,b]of Object.entries(l))b.requiredWhen&&S(b.requiredWhen,e)&&i.add(c);const a=[...i].filter(c=>V(e[c]));return{missing:a,complete:a.length===0}}function B(n){const e={};for(const[l,i]of Object.entries(n.properties??{}))e[l]={type:i.type,...i.description!=null&&{description:i.description},...i.enum&&{enum:i.enum},...i.default!==void 0&&{default:i.default}};return{type:"object",properties:e,required:[]}}function A(n){const{name:e,description:l,schema:i}=n;if(!W.test(e))throw new Error(`Invalid form collector name "${e}": must match ${W} (it becomes the update_/submit_ function names).`);const a=typeof n.submit=="string"?n.submit?{via:"client",url:n.submit}:!1:n.submit??!1;n.autoSubmit===!0&&!a&&C.logger.warn(`FormCollector "${e}": autoSubmit is ignored because no submit target is configured.`);const c=(n.autoSubmit??!0)&&!!a,b=i.properties??{},$=t=>{const r={};for(const[o,s]of Object.entries(t)){const u=b[o];if(u)if(s==null)r[o]=s;else if(u.type==="number"||u.type==="integer"){const f=typeof s=="number"?s:Number(s);r[o]=Number.isNaN(f)?s:f}else u.type==="boolean"?r[o]=typeof s=="boolean"?s:s==="true"?!0:s==="false"?!1:!!s:r[o]=s}return r},F=n.initialValues??{},m=C.createStore({values:F,submitted:!1}),w=t=>{const r=m.get(),o={...r,values:{...r.values,...t}};return m.set(o),o};let d=null;const k=(t,r)=>{d?.emitFormEvent("form:error",{name:e,values:t,error:r})};let p=null;const I=async()=>{const{values:t}=m.get(),{complete:r,missing:o}=h(i,t);if(!r)return{ok:!1,missing:o};if(!a)return{ok:!1,error:"No submit target configured for this form collector."};if(a.via==="backend"&&!d)return{ok:!1,error:"Backend submit requires install(client) (or useFormCollector) first."};const s=t;try{d?.emitFormEvent("form:submitting",{name:e,values:s});let u;if(a.via==="client")if("handler"in a)u=await a.handler(s);else{const f=await fetch(a.url,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(s)});if(!f.ok){const j=`Submit failed: HTTP ${f.status}`;return k(s,j),{ok:!1,error:j}}u=await f.json().catch(()=>{})}else u=await d.submitFormCollector(e,s);return m.set({...m.get(),submitted:!0,submitResult:u}),d?.emitFormEvent("form:submitted",{name:e,values:s,result:u}),{ok:!0,result:u}}catch(u){const f=u instanceof Error?u.message:"Submit failed";return C.logger.error(`FormCollector "${e}" submit failed:`,u),k(s,f),{ok:!1,error:f}}},N=()=>p||(p=(async()=>{try{return await I()}finally{p=null}})(),p),q=async()=>{if(!c||!a)return null;const{values:t,submitted:r}=m.get();return r||!h(i,t).complete?null:N()},O={name:`update_${e}`,description:`Fill or update fields of the "${e}" form. ${l} Pass any subset of fields; call it repeatedly to fill the form as the user provides information. Returns the current values and which required fields are still missing.`,parameters:B(i),handler:async t=>{const r=w($(t)),{missing:o}=h(i,r.values),s=await q();return s?s.ok?{ok:!0,values:r.values,missing:o,submitted:!0}:{ok:!0,values:r.values,missing:o,submitted:!1,submitError:s.error}:{ok:!0,values:r.values,missing:o}}},y=[O];a&&!c&&y.push({name:`submit_${e}`,description:`Submit the completed "${e}" form. Only call this once every required field is collected and the user has confirmed. If fields are missing it returns them instead of submitting.`,parameters:{type:"object",properties:{}},handler:()=>N()});const D="client__",_=a?`submit_${e}`:null,R=t=>{const r=t.functionName??t.toolName;if(r)return r.startsWith(D)?r.slice(8):r},x=t=>{let r={...F},o=!1;for(const s of t){const u=R(s);u===O.name?s.arguments&&(r={...r,...$(s.arguments)}):_&&u===_&&s.status?.toLowerCase()==="done"&&(o=!0)}m.set({values:r,submitted:o})},g=`form:${e}`,v=`${g}:definition`,E=()=>({name:`Form definition: ${e}`,description:`${l} Some fields are conditionally required; the requiredWhen field in the schema tells you when each becomes required. The form schema is the following: ${JSON.stringify(i)}.`,stable:!0}),P=()=>{const{values:t,submitted:r}=m.get(),{missing:o,complete:s}=h(i,t),u=a?c?" The form is submitted automatically as soon as every required field is filled, so there is no submit function to call.":` When nothing is missing and the user confirms, call submit_${e}.`:"",f=r?`The "${e}" form has been submitted.`:`You are currently collecting information from the user to fill the "${e}" form.`;return{name:`Form: ${e}`,description:`${f} The form's schema and field requirements are in the "${v}" client context. Call update_${e} with any fields the user provides; ask only for what is still missing.${u}`,data:{values:t,missing:o,complete:s,submitted:r}}},T=t=>{x((t.messages??[]).flatMap(r=>r.toolCalls??[]))};return{name:e,store:m,functions:y,contextKey:g,contextProvider:P,definitionContextKey:v,definitionContextProvider:E,install:t=>{d=t;for(const o of y)t.register(o);t.addDynamicContext(v,E),t.addDynamicContext(g,P);const r=m.subscribe(()=>t.notifyContextChanged());return t.on("conversation:loaded",T),()=>{r();for(const o of y)t.unregisterFunction(o.name);t.removeDynamicContext(g),t.removeDynamicContext(v),t.off("conversation:loaded",T),d===t&&(d=null)}},hydrate:x,submit:N,getValues:()=>m.get().values,setValues:t=>{w($(t)),q()},reset:()=>{m.set({values:F,submitted:!1})},getStatus:()=>h(i,m.get().values)}}async function L(n,e){const l=await n.getFormCollector(e.name);return A({name:l.name,description:e.description??l.description,schema:e.schema??l.schema,submit:e.submit??l.submit,initialValues:e.initialValues,autoSubmit:e.autoSubmit??l.autoSubmit})}Object.defineProperty(exports,"createFormCollector",{enumerable:!0,get:function(){return A}});Object.defineProperty(exports,"deriveFormStatus",{enumerable:!0,get:function(){return h}});Object.defineProperty(exports,"loadFormCollector",{enumerable:!0,get:function(){return L}});
@@ -729,6 +729,11 @@ declare interface AgoClientEvents {
729
729
  result: unknown;
730
730
  error?: string;
731
731
  };
732
+ /** A validated form collector submission is about to call its submit target. */
733
+ "form:submitting": {
734
+ name: string;
735
+ values: Record<string, unknown>;
736
+ };
732
737
  /**
733
738
  * A form collector submitted successfully. `result` is the raw submit response
734
739
  * (POST body / handler return value / backend relay result) — the third-party
@@ -2086,16 +2091,21 @@ declare interface TranscribeAudioOptions {
2086
2091
  signal?: AbortSignal;
2087
2092
  }
2088
2093
 
2089
- /** The MCP behavior hints AGO has no equivalent for. */
2094
+ /** Metadata for tools exposed through the WebMCP bridge. */
2090
2095
  declare interface WebMCPToolMeta {
2091
2096
  /**
2092
- * Both default to `false`, so only set what is true: `readOnlyHint` marks a
2093
- * function that changes nothing, `untrustedContentHint` one whose result may
2094
- * carry third-party text.
2097
+ * Optional WebMCP metadata; all fields default to `false` in WebMCP.
2098
+ * These annotations do not affect AGO's in-app agent or approval behavior.
2095
2099
  */
2096
2100
  annotations?: {
2101
+ /** The tool only reads data and does not change state. */
2097
2102
  readOnlyHint?: boolean;
2103
+ /** The output contains content untrusted by the tool author. */
2098
2104
  untrustedContentHint?: boolean;
2105
+ /** Significant, real-world, or irreversible effects; independent of requiresApproval. */
2106
+ consequentialHint?: boolean;
2107
+ /** Intended for debugging and developer tooling. */
2108
+ debugging?: boolean;
2099
2109
  };
2100
2110
  /**
2101
2111
  * This function navigates. The WebMCP call is held open until the function
@@ -729,6 +729,11 @@ declare interface AgoClientEvents {
729
729
  result: unknown;
730
730
  error?: string;
731
731
  };
732
+ /** A validated form collector submission is about to call its submit target. */
733
+ "form:submitting": {
734
+ name: string;
735
+ values: Record<string, unknown>;
736
+ };
732
737
  /**
733
738
  * A form collector submitted successfully. `result` is the raw submit response
734
739
  * (POST body / handler return value / backend relay result) — the third-party
@@ -2086,16 +2091,21 @@ declare interface TranscribeAudioOptions {
2086
2091
  signal?: AbortSignal;
2087
2092
  }
2088
2093
 
2089
- /** The MCP behavior hints AGO has no equivalent for. */
2094
+ /** Metadata for tools exposed through the WebMCP bridge. */
2090
2095
  declare interface WebMCPToolMeta {
2091
2096
  /**
2092
- * Both default to `false`, so only set what is true: `readOnlyHint` marks a
2093
- * function that changes nothing, `untrustedContentHint` one whose result may
2094
- * carry third-party text.
2097
+ * Optional WebMCP metadata; all fields default to `false` in WebMCP.
2098
+ * These annotations do not affect AGO's in-app agent or approval behavior.
2095
2099
  */
2096
2100
  annotations?: {
2101
+ /** The tool only reads data and does not change state. */
2097
2102
  readOnlyHint?: boolean;
2103
+ /** The output contains content untrusted by the tool author. */
2098
2104
  untrustedContentHint?: boolean;
2105
+ /** Significant, real-world, or irreversible effects; independent of requiresApproval. */
2106
+ consequentialHint?: boolean;
2107
+ /** Intended for debugging and developer tooling. */
2108
+ debugging?: boolean;
2099
2109
  };
2100
2110
  /**
2101
2111
  * This function navigates. The WebMCP call is held open until the function
@@ -144,16 +144,21 @@ export declare const submitForm: ClientFunctionDefinition;
144
144
  */
145
145
  export declare const trackEvent: ClientFunctionDefinition;
146
146
 
147
- /** The MCP behavior hints AGO has no equivalent for. */
147
+ /** Metadata for tools exposed through the WebMCP bridge. */
148
148
  declare interface WebMCPToolMeta {
149
149
  /**
150
- * Both default to `false`, so only set what is true: `readOnlyHint` marks a
151
- * function that changes nothing, `untrustedContentHint` one whose result may
152
- * carry third-party text.
150
+ * Optional WebMCP metadata; all fields default to `false` in WebMCP.
151
+ * These annotations do not affect AGO's in-app agent or approval behavior.
153
152
  */
154
153
  annotations?: {
154
+ /** The tool only reads data and does not change state. */
155
155
  readOnlyHint?: boolean;
156
+ /** The output contains content untrusted by the tool author. */
156
157
  untrustedContentHint?: boolean;
158
+ /** Significant, real-world, or irreversible effects; independent of requiresApproval. */
159
+ consequentialHint?: boolean;
160
+ /** Intended for debugging and developer tooling. */
161
+ debugging?: boolean;
157
162
  };
158
163
  /**
159
164
  * This function navigates. The WebMCP call is held open until the function
package/dist/helpers.d.ts CHANGED
@@ -144,16 +144,21 @@ export declare const submitForm: ClientFunctionDefinition;
144
144
  */
145
145
  export declare const trackEvent: ClientFunctionDefinition;
146
146
 
147
- /** The MCP behavior hints AGO has no equivalent for. */
147
+ /** Metadata for tools exposed through the WebMCP bridge. */
148
148
  declare interface WebMCPToolMeta {
149
149
  /**
150
- * Both default to `false`, so only set what is true: `readOnlyHint` marks a
151
- * function that changes nothing, `untrustedContentHint` one whose result may
152
- * carry third-party text.
150
+ * Optional WebMCP metadata; all fields default to `false` in WebMCP.
151
+ * These annotations do not affect AGO's in-app agent or approval behavior.
153
152
  */
154
153
  annotations?: {
154
+ /** The tool only reads data and does not change state. */
155
155
  readOnlyHint?: boolean;
156
+ /** The output contains content untrusted by the tool author. */
156
157
  untrustedContentHint?: boolean;
158
+ /** Significant, real-world, or irreversible effects; independent of requiresApproval. */
159
+ consequentialHint?: boolean;
160
+ /** Intended for debugging and developer tooling. */
161
+ debugging?: boolean;
157
162
  };
158
163
  /**
159
164
  * This function navigates. The WebMCP call is held open until the function
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./types-DNr6XEwI.cjs"),f=require("./errors-o1IB5fEu.cjs"),S=require("./autoContinue-C3UsCvT5.cjs"),p=require("./createConversationSession-Digvn0GQ.cjs"),A=require("./createFormCollector-Cq7HWjtU.cjs"),w=require("./createMockClient-BPt1gSve.cjs");require("./testing.cjs");const g=require("./functions-CPs7omgM.cjs");function F(e){return e}function _(e,t){return e.on("message:complete",t),()=>e.off("message:complete",t)}function y(e,t){return e.on("message:chunk",t),()=>e.off("message:chunk",t)}function M(e,t){return e.on("message:start",t),()=>e.off("message:start",t)}function v(e,t){return e.on("message:error",t),()=>e.off("message:error",t)}function T(e,t){return e.on("toolCall:received",t),()=>e.off("toolCall:received",t)}function R(e,t){return e.on("form:submitted",t),()=>e.off("form:submitted",t)}function b(e,t){return e.on("form:error",t),()=>e.off("form:error",t)}function q(e,t){return e.on("function:invoke",t),()=>e.off("function:invoke",t)}async function*I(e,t,l){const i=[];let n=null,a=!1;const c=s=>{i.push(s),n?.()},m=s=>c({type:"start",data:s}),d=s=>c({type:"chunk",data:s}),r=s=>{c({type:"complete",data:s}),a=!0,n?.()},u=s=>{c({type:"error",data:s}),a=!0,n?.()},E=s=>c({type:"toolCall",data:s}),h=()=>{a=!0,n?.()};e.on("message:start",m),e.on("message:chunk",d),e.on("message:complete",r),e.on("message:error",u),e.on("message:stopped",h),e.on("toolCall:received",E),e.sendMessage(t,l).catch(()=>{a=!0,n?.()});try{for(;!a||i.length>0;)i.length>0?yield i.shift():(await new Promise(s=>{n=s}),n=null)}finally{e.off("message:start",m),e.off("message:chunk",d),e.off("message:complete",r),e.off("message:error",u),e.off("message:stopped",h),e.off("toolCall:received",E)}}function C(e){let t,l,i,n,a,c,m;if(typeof window<"u"&&window.AGO){const r=window.AGO;t=r.basepath,l=r.widgetId,i=r.agent||r.defaultAgent,n=r.permission,a=r.email,c=r.jwt,m=r.metadata}if(typeof document<"u"){const r=u=>document.querySelector(`meta[name="${u}"]`)?.getAttribute("content")||void 0;t=t||r("ago-base-url"),l=l||r("ago-widget-id"),i=i||r("ago-agent")||r("ago-agent-id"),n=n||r("ago-permission"),a=a||r("ago-user-email")}if(typeof document<"u"){const r=[document.body,...Array.from(document.querySelectorAll("script[data-ago-base-url]"))].filter(Boolean);for(const u of r)u&&(t=t||u.getAttribute("data-ago-base-url")||void 0,l=l||u.getAttribute("data-ago-widget-id")||void 0,i=i||u.getAttribute("data-ago-agent")||u.getAttribute("data-ago-agent-id")||void 0,n=n||u.getAttribute("data-ago-permission")||void 0,a=a||u.getAttribute("data-ago-user-email")||void 0)}t=e?.baseUrl||t,l=e?.widgetId||l,i=e?.agent||e?.defaultAgentId||i,n=e?.permission||n,a=e?.userEmail||a,c=e?.userJwt||c,e?.metadata!==void 0&&(m=e.metadata);const d=e?.debug;return t?{baseUrl:t,widgetId:l,agent:i,permission:n,language:e?.language,userEmail:a,userJwt:c,metadata:m,debug:d}:null}function U(e){const t=C(e);if(!t)throw new f.AgoError('createAgo(): could not detect AGO configuration. Set window.AGO, add <meta name="ago-base-url">, or pass { baseUrl } explicitly.',"config_missing_base_url");return new o.AgoClient(t)}function D(e,t){return{...e,handler:t}}exports.ActivityLedger=o.ActivityLedger;exports.AgoApiError=f.AgoApiError;exports.AgoClient=o.AgoClient;exports.AgoError=f.AgoError;exports.AgoFunctionError=f.AgoFunctionError;exports.AgoNetworkError=f.AgoNetworkError;exports.AgoStreamError=f.AgoStreamError;exports.ClientContextRegistry=o.ClientContextRegistry;exports.DEFAULT_MAX_ACTIVITY_ENTRIES=o.DEFAULT_MAX_ACTIVITY_ENTRIES;exports.DEFAULT_MAX_ERRORS=o.DEFAULT_MAX_ERRORS;exports.DEFAULT_MAX_ERROR_AGE_MS=o.DEFAULT_MAX_ERROR_AGE_MS;exports.ErrorWatcher=o.ErrorWatcher;exports.EventEmitter=o.EventEmitter;exports.FEEDBACK_REASONS=o.FEEDBACK_REASONS;exports.FunctionRegistry=o.FunctionRegistry;exports.SSEHandler=o.SSEHandler;exports.SignalCollector=o.SignalCollector;exports.attachAutoContinueAfterNavigation=S.attachAutoContinueAfterNavigation;exports.autoDetectConfig=C;exports.canInlineImage=o.canInlineImage;exports.copyToClipboard=g.copyToClipboard;exports.createAgo=U;exports.createAgoProactive=o.createAgoProactive;exports.createConversationSession=p.createConversationSession;exports.createFormCollector=A.createFormCollector;exports.createMessageStream=I;exports.createMockClient=w.createMockClient;exports.createStore=o.createStore;exports.defineFunction=F;exports.deriveFormStatus=A.deriveFormStatus;exports.formatFileSize=o.formatFileSize;exports.getLocalStorage=g.getLocalStorage;exports.getUserLocation=g.getUserLocation;exports.highlightElement=g.highlightElement;exports.isStreamNetworkError=o.isStreamNetworkError;exports.loadFormCollector=A.loadFormCollector;exports.logger=o.logger;exports.matchesRoutePattern=o.matchesRoutePattern;exports.matchesWhen=o.matchesWhen;exports.onFormError=b;exports.onFormSubmitted=R;exports.onFunctionInvoke=q;exports.onMessage=_;exports.onMessageChunk=y;exports.onMessageError=v;exports.onMessageStart=M;exports.onToolCall=T;exports.openUrl=g.openUrl;exports.partialDeepMatch=o.partialDeepMatch;exports.safeAttachmentUrl=o.safeAttachmentUrl;exports.scrollToElement=g.scrollToElement;exports.setLocalStorage=g.setLocalStorage;exports.setTheme=g.setTheme;exports.showConfirmDialog=g.showConfirmDialog;exports.showNotification=g.showNotification;exports.showToast=g.showToast;exports.submitForm=g.submitForm;exports.trackEvent=g.trackEvent;exports.validateConfig=o.validateConfig;exports.withHandler=D;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./types-DNr6XEwI.cjs"),f=require("./errors-o1IB5fEu.cjs"),C=require("./autoContinue-C3UsCvT5.cjs"),p=require("./createConversationSession-Digvn0GQ.cjs"),A=require("./createFormCollector-D_5SDuk9.cjs"),w=require("./createMockClient-BPt1gSve.cjs");require("./testing.cjs");const g=require("./functions-CPs7omgM.cjs");function F(e){return e}function _(e,t){return e.on("message:complete",t),()=>e.off("message:complete",t)}function y(e,t){return e.on("message:chunk",t),()=>e.off("message:chunk",t)}function M(e,t){return e.on("message:start",t),()=>e.off("message:start",t)}function b(e,t){return e.on("message:error",t),()=>e.off("message:error",t)}function v(e,t){return e.on("toolCall:received",t),()=>e.off("toolCall:received",t)}function T(e,t){return e.on("form:submitted",t),()=>e.off("form:submitted",t)}function R(e,t){return e.on("form:error",t),()=>e.off("form:error",t)}function q(e,t){return e.on("function:invoke",t),()=>e.off("function:invoke",t)}async function*I(e,t,m){const i=[];let n=null,a=!1;const l=s=>{i.push(s),n?.()},c=s=>l({type:"start",data:s}),d=s=>l({type:"chunk",data:s}),r=s=>{l({type:"complete",data:s}),a=!0,n?.()},u=s=>{l({type:"error",data:s}),a=!0,n?.()},E=s=>l({type:"toolCall",data:s}),S=()=>{a=!0,n?.()};e.on("message:start",c),e.on("message:chunk",d),e.on("message:complete",r),e.on("message:error",u),e.on("message:stopped",S),e.on("toolCall:received",E),e.sendMessage(t,m).catch(()=>{a=!0,n?.()});try{for(;!a||i.length>0;)i.length>0?yield i.shift():(await new Promise(s=>{n=s}),n=null)}finally{e.off("message:start",c),e.off("message:chunk",d),e.off("message:complete",r),e.off("message:error",u),e.off("message:stopped",S),e.off("toolCall:received",E)}}function U(e,t){return e.on("form:submitting",t),()=>e.off("form:submitting",t)}function h(e){let t,m,i,n,a,l,c;if(typeof window<"u"&&window.AGO){const r=window.AGO;t=r.basepath,m=r.widgetId,i=r.agent||r.defaultAgent,n=r.permission,a=r.email,l=r.jwt,c=r.metadata}if(typeof document<"u"){const r=u=>document.querySelector(`meta[name="${u}"]`)?.getAttribute("content")||void 0;t=t||r("ago-base-url"),m=m||r("ago-widget-id"),i=i||r("ago-agent")||r("ago-agent-id"),n=n||r("ago-permission"),a=a||r("ago-user-email")}if(typeof document<"u"){const r=[document.body,...Array.from(document.querySelectorAll("script[data-ago-base-url]"))].filter(Boolean);for(const u of r)u&&(t=t||u.getAttribute("data-ago-base-url")||void 0,m=m||u.getAttribute("data-ago-widget-id")||void 0,i=i||u.getAttribute("data-ago-agent")||u.getAttribute("data-ago-agent-id")||void 0,n=n||u.getAttribute("data-ago-permission")||void 0,a=a||u.getAttribute("data-ago-user-email")||void 0)}t=e?.baseUrl||t,m=e?.widgetId||m,i=e?.agent||e?.defaultAgentId||i,n=e?.permission||n,a=e?.userEmail||a,l=e?.userJwt||l,e?.metadata!==void 0&&(c=e.metadata);const d=e?.debug;return t?{baseUrl:t,widgetId:m,agent:i,permission:n,language:e?.language,userEmail:a,userJwt:l,metadata:c,debug:d}:null}function D(e){const t=h(e);if(!t)throw new f.AgoError('createAgo(): could not detect AGO configuration. Set window.AGO, add <meta name="ago-base-url">, or pass { baseUrl } explicitly.',"config_missing_base_url");return new o.AgoClient(t)}function L(e,t){return{...e,handler:t}}exports.ActivityLedger=o.ActivityLedger;exports.AgoApiError=f.AgoApiError;exports.AgoClient=o.AgoClient;exports.AgoError=f.AgoError;exports.AgoFunctionError=f.AgoFunctionError;exports.AgoNetworkError=f.AgoNetworkError;exports.AgoStreamError=f.AgoStreamError;exports.ClientContextRegistry=o.ClientContextRegistry;exports.DEFAULT_MAX_ACTIVITY_ENTRIES=o.DEFAULT_MAX_ACTIVITY_ENTRIES;exports.DEFAULT_MAX_ERRORS=o.DEFAULT_MAX_ERRORS;exports.DEFAULT_MAX_ERROR_AGE_MS=o.DEFAULT_MAX_ERROR_AGE_MS;exports.ErrorWatcher=o.ErrorWatcher;exports.EventEmitter=o.EventEmitter;exports.FEEDBACK_REASONS=o.FEEDBACK_REASONS;exports.FunctionRegistry=o.FunctionRegistry;exports.SSEHandler=o.SSEHandler;exports.SignalCollector=o.SignalCollector;exports.attachAutoContinueAfterNavigation=C.attachAutoContinueAfterNavigation;exports.autoDetectConfig=h;exports.canInlineImage=o.canInlineImage;exports.copyToClipboard=g.copyToClipboard;exports.createAgo=D;exports.createAgoProactive=o.createAgoProactive;exports.createConversationSession=p.createConversationSession;exports.createFormCollector=A.createFormCollector;exports.createMessageStream=I;exports.createMockClient=w.createMockClient;exports.createStore=o.createStore;exports.defineFunction=F;exports.deriveFormStatus=A.deriveFormStatus;exports.formatFileSize=o.formatFileSize;exports.getLocalStorage=g.getLocalStorage;exports.getUserLocation=g.getUserLocation;exports.highlightElement=g.highlightElement;exports.isStreamNetworkError=o.isStreamNetworkError;exports.loadFormCollector=A.loadFormCollector;exports.logger=o.logger;exports.matchesRoutePattern=o.matchesRoutePattern;exports.matchesWhen=o.matchesWhen;exports.onFormError=R;exports.onFormSubmitted=T;exports.onFormSubmitting=U;exports.onFunctionInvoke=q;exports.onMessage=_;exports.onMessageChunk=y;exports.onMessageError=b;exports.onMessageStart=M;exports.onToolCall=v;exports.openUrl=g.openUrl;exports.partialDeepMatch=o.partialDeepMatch;exports.safeAttachmentUrl=o.safeAttachmentUrl;exports.scrollToElement=g.scrollToElement;exports.setLocalStorage=g.setLocalStorage;exports.setTheme=g.setTheme;exports.showConfirmDialog=g.showConfirmDialog;exports.showNotification=g.showNotification;exports.showToast=g.showToast;exports.submitForm=g.submitForm;exports.trackEvent=g.trackEvent;exports.validateConfig=o.validateConfig;exports.withHandler=L;
package/dist/index.d.cts CHANGED
@@ -768,6 +768,11 @@ export declare interface AgoClientEvents {
768
768
  result: unknown;
769
769
  error?: string;
770
770
  };
771
+ /** A validated form collector submission is about to call its submit target. */
772
+ "form:submitting": {
773
+ name: string;
774
+ values: Record<string, unknown>;
775
+ };
771
776
  /**
772
777
  * A form collector submitted successfully. `result` is the raw submit response
773
778
  * (POST body / handler return value / backend relay result) — the third-party
@@ -2390,6 +2395,9 @@ export declare function onFormError(client: AgoClient, callback: (data: AgoClien
2390
2395
  */
2391
2396
  export declare function onFormSubmitted(client: AgoClient, callback: (data: AgoClientEvents["form:submitted"]) => void): () => void;
2392
2397
 
2398
+ /** Observe a validated form submission before its submit target runs. */
2399
+ export declare function onFormSubmitting(client: AgoClient, callback: (data: AgoClientEvents["form:submitting"]) => void): () => void;
2400
+
2393
2401
  /**
2394
2402
  * Subscribe to client function invocations.
2395
2403
  */
@@ -3353,16 +3361,21 @@ export declare interface TranscribeAudioOptions {
3353
3361
  */
3354
3362
  export declare function validateConfig(config: unknown, context?: string): asserts config is AgoConfig;
3355
3363
 
3356
- /** The MCP behavior hints AGO has no equivalent for. */
3364
+ /** Metadata for tools exposed through the WebMCP bridge. */
3357
3365
  export declare interface WebMCPToolMeta {
3358
3366
  /**
3359
- * Both default to `false`, so only set what is true: `readOnlyHint` marks a
3360
- * function that changes nothing, `untrustedContentHint` one whose result may
3361
- * carry third-party text.
3367
+ * Optional WebMCP metadata; all fields default to `false` in WebMCP.
3368
+ * These annotations do not affect AGO's in-app agent or approval behavior.
3362
3369
  */
3363
3370
  annotations?: {
3371
+ /** The tool only reads data and does not change state. */
3364
3372
  readOnlyHint?: boolean;
3373
+ /** The output contains content untrusted by the tool author. */
3365
3374
  untrustedContentHint?: boolean;
3375
+ /** Significant, real-world, or irreversible effects; independent of requiresApproval. */
3376
+ consequentialHint?: boolean;
3377
+ /** Intended for debugging and developer tooling. */
3378
+ debugging?: boolean;
3366
3379
  };
3367
3380
  /**
3368
3381
  * This function navigates. The WebMCP call is held open until the function
package/dist/index.d.ts CHANGED
@@ -768,6 +768,11 @@ export declare interface AgoClientEvents {
768
768
  result: unknown;
769
769
  error?: string;
770
770
  };
771
+ /** A validated form collector submission is about to call its submit target. */
772
+ "form:submitting": {
773
+ name: string;
774
+ values: Record<string, unknown>;
775
+ };
771
776
  /**
772
777
  * A form collector submitted successfully. `result` is the raw submit response
773
778
  * (POST body / handler return value / backend relay result) — the third-party
@@ -2390,6 +2395,9 @@ export declare function onFormError(client: AgoClient, callback: (data: AgoClien
2390
2395
  */
2391
2396
  export declare function onFormSubmitted(client: AgoClient, callback: (data: AgoClientEvents["form:submitted"]) => void): () => void;
2392
2397
 
2398
+ /** Observe a validated form submission before its submit target runs. */
2399
+ export declare function onFormSubmitting(client: AgoClient, callback: (data: AgoClientEvents["form:submitting"]) => void): () => void;
2400
+
2393
2401
  /**
2394
2402
  * Subscribe to client function invocations.
2395
2403
  */
@@ -3353,16 +3361,21 @@ export declare interface TranscribeAudioOptions {
3353
3361
  */
3354
3362
  export declare function validateConfig(config: unknown, context?: string): asserts config is AgoConfig;
3355
3363
 
3356
- /** The MCP behavior hints AGO has no equivalent for. */
3364
+ /** Metadata for tools exposed through the WebMCP bridge. */
3357
3365
  export declare interface WebMCPToolMeta {
3358
3366
  /**
3359
- * Both default to `false`, so only set what is true: `readOnlyHint` marks a
3360
- * function that changes nothing, `untrustedContentHint` one whose result may
3361
- * carry third-party text.
3367
+ * Optional WebMCP metadata; all fields default to `false` in WebMCP.
3368
+ * These annotations do not affect AGO's in-app agent or approval behavior.
3362
3369
  */
3363
3370
  annotations?: {
3371
+ /** The tool only reads data and does not change state. */
3364
3372
  readOnlyHint?: boolean;
3373
+ /** The output contains content untrusted by the tool author. */
3365
3374
  untrustedContentHint?: boolean;
3375
+ /** Significant, real-world, or irreversible effects; independent of requiresApproval. */
3376
+ consequentialHint?: boolean;
3377
+ /** Intended for debugging and developer tooling. */
3378
+ debugging?: boolean;
3366
3379
  };
3367
3380
  /**
3368
3381
  * This function navigates. The WebMCP call is held open until the function