@matterfact/embed 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +191 -0
  2. package/dist/{chunk-R2ZEJARX.js → chunk-4AE5WINC.js} +233 -17
  3. package/dist/chunk-4AE5WINC.js.map +1 -0
  4. package/dist/{chunk-PNSYFXXU.js → chunk-CFDPCZO3.js} +233 -15
  5. package/dist/chunk-CFDPCZO3.js.map +1 -0
  6. package/dist/{chunk-UD7CAQXV.js → chunk-DXLHTFB4.js} +2 -2
  7. package/dist/chunk-RL6VIGWK.js +2 -0
  8. package/dist/chunk-TWMHQF7O.js +3 -0
  9. package/dist/chunk-TWMHQF7O.js.map +7 -0
  10. package/dist/{context-MVGSYIMB.js → context-HOOW63MO.js} +6 -2
  11. package/dist/context-SSQ4HUP3.js +3 -0
  12. package/dist/{context-ARBB2XD6.js.map → context-SSQ4HUP3.js.map} +1 -1
  13. package/dist/embed.js +1 -1
  14. package/dist/embed.js.map +2 -2
  15. package/dist/index.cjs +243 -14
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +92 -2
  18. package/dist/index.d.ts +92 -2
  19. package/dist/index.js +5 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/react.cjs +299 -16
  22. package/dist/react.cjs.map +1 -1
  23. package/dist/react.d.cts +172 -1
  24. package/dist/react.d.ts +172 -1
  25. package/dist/react.js +60 -4
  26. package/dist/react.js.map +1 -1
  27. package/dist/{snapshot-GL4YBMXD.js → snapshot-CRY2IBX6.js} +3 -3
  28. package/dist/{snapshot-GL4YBMXD.js.map → snapshot-CRY2IBX6.js.map} +1 -1
  29. package/dist/{snapshot-UGTXZVB6.js → snapshot-EYRXPLRC.js} +2 -2
  30. package/package.json +1 -1
  31. package/dist/chunk-PNSYFXXU.js.map +0 -1
  32. package/dist/chunk-R2ZEJARX.js.map +0 -1
  33. package/dist/chunk-UQCETVRF.js +0 -2
  34. package/dist/chunk-W52Q7G4J.js +0 -3
  35. package/dist/chunk-W52Q7G4J.js.map +0 -7
  36. package/dist/context-ARBB2XD6.js +0 -3
  37. /package/dist/{chunk-UD7CAQXV.js.map → chunk-DXLHTFB4.js.map} +0 -0
  38. /package/dist/{chunk-UQCETVRF.js.map → chunk-RL6VIGWK.js.map} +0 -0
  39. /package/dist/{context-MVGSYIMB.js.map → context-HOOW63MO.js.map} +0 -0
  40. /package/dist/{snapshot-UGTXZVB6.js.map → snapshot-EYRXPLRC.js.map} +0 -0
package/dist/react.d.cts CHANGED
@@ -24,6 +24,75 @@ interface PageEntity {
24
24
  text?: string;
25
25
  data?: Record<string, unknown>;
26
26
  }
27
+ /**
28
+ * How a route's content is classified, for the annotated site map.
29
+ *
30
+ * The host DECORATES the site map we auto-derive (see `SiteMapEntry`) so the agent
31
+ * knows which routes carry MATTERFACT content and of what kind — app-wide awareness
32
+ * it can navigate toward. This is CLASSIFICATION only: no per-instance ids, and never
33
+ * a capability token. The concrete artifact/document on the CURRENT page still arrives
34
+ * via `host.context` entities / `host.artifactGrants`, resolved per page.
35
+ *
36
+ * - `mf-artifact` — a co-embedded matterfact artifact (its slug); the token stays on
37
+ * the live iframe / grant, never here.
38
+ * - `mf-document` — a matterfact document (dossier/report), resolved to an MF_DOC_ID
39
+ * host-side per page.
40
+ * - `host-data` — the host's own data; not a matterfact entity.
41
+ */
42
+ type ContentClass = {
43
+ kind: 'mf-artifact';
44
+ slug: string;
45
+ } | {
46
+ kind: 'mf-document';
47
+ doctype: string;
48
+ } | {
49
+ kind: 'host-data';
50
+ };
51
+ /**
52
+ * One route in the annotated site map: the path pattern + label we derived, plus the
53
+ * host's content classification. `current` marks the route the user is on.
54
+ */
55
+ interface SiteMapEntry {
56
+ /** Route pattern or path, e.g. '/app/company/:ticker/dossier'. */
57
+ path: string;
58
+ /** Human label for the route ('Company Dossier'). */
59
+ label?: string;
60
+ /** The host's classification of this route's content, when it annotated it. */
61
+ content?: ContentClass;
62
+ current?: boolean;
63
+ }
64
+ /**
65
+ * A DECLARED artifact grant — the `<MatterfactAgent artifacts>` prop (or
66
+ * `window.matterfact.artifacts`). Same wire shape as a grant discovered by scanning
67
+ * co-embedded `<MatterfactArtifact>` iframes, plus an optional `label`; it feeds the
68
+ * SAME `host.artifactGrants` channel. This is how a host makes a board reachable from
69
+ * a route where its iframe ISN'T mounted, without hidden zero-size iframes smuggling
70
+ * the token into the DOM. The token stays in the grant channel, never in message text.
71
+ */
72
+ interface DeclaredArtifact {
73
+ slug: string;
74
+ owner: string;
75
+ token: string;
76
+ label?: string;
77
+ }
78
+ /**
79
+ * One host-tool lifecycle event, surfaced to the host via `onToolEvent` (and the dev
80
+ * panel) — the host's own telemetry hook. Fired loader-side; a throwing or slow
81
+ * callback here NEVER blocks or breaks the call path.
82
+ *
83
+ * - `advertise` — the merged tool list changed (fired with the new set's names).
84
+ * - `call` — a tool call is about to run (`args` present).
85
+ * - `result` — the call settled (`ok`/`error`/`ms`).
86
+ */
87
+ interface ToolEvent {
88
+ phase: 'advertise' | 'call' | 'result';
89
+ name: string;
90
+ toolClass: 'hoist' | 'mf' | 'app';
91
+ args?: unknown;
92
+ ok?: boolean;
93
+ error?: string;
94
+ ms?: number;
95
+ }
27
96
 
28
97
  /**
29
98
  * The Hoist adapter — a pure transform from a `HoistRuntime` (already read out of
@@ -46,6 +115,64 @@ interface HoistActionsConfig {
46
115
  navigate: 'off' | 'confirm' | 'auto';
47
116
  }
48
117
 
118
+ /**
119
+ * The host-tool registry — the ONE place the three tool classes are merged into the
120
+ * single list the widget advertises, and the ONE execution path for calling any of
121
+ * them.
122
+ *
123
+ * Three classes, distinguished by who owns the contract and who runs the code:
124
+ *
125
+ * - `hoist.*` matterfact-defined, matterfact-implemented. The loader adapter runs
126
+ * them (today: `hoist.navigate`). Gated on `window.XH` + the host's
127
+ * `hoist.actions` policy. See `hoist-runtime.ts`.
128
+ * - `mf.*` matterfact-defined, HOST-implemented. WE fix the name, schema and
129
+ * agent semantics (the description is authored HERE, not per
130
+ * integration); the host supplies the function via `resolve.*`. Today:
131
+ * `mf.resolveDocument`, `mf.resolveArtifact`.
132
+ * - `app.*` host-defined, host-implemented. Anything the host advertises via
133
+ * `tools`. Normalised into the `app.` namespace so it can never shadow
134
+ * ours.
135
+ *
136
+ * Everything downstream (the widget's confirm gate, the backend dispatcher) is already
137
+ * generic over "a tool with a name/schema/confirm and a call round-trip" — this module
138
+ * is purely the loader-side composition + dispatch, so `hoist-runtime.ts` stays one
139
+ * adapter rather than the whole surface.
140
+ *
141
+ * SECURITY: `mf.*`/`app.*` handlers are HOST code. Their results and error strings pass
142
+ * through `redact()` before leaving the page, exactly like the hoist adapter's; a
143
+ * handler that throws or hangs becomes a normal `{ok:false}` result, never an exception
144
+ * into `context.ts`. And the SERVER decides which of these an app may actually expose
145
+ * (the `host_tools` policy) — advertising here is necessary but not sufficient.
146
+ */
147
+
148
+ /** A host-supplied resolver: matterfact fixes the contract, the host implements it. */
149
+ interface HostResolvers {
150
+ document?: (args: {
151
+ doctype: string;
152
+ key: string;
153
+ }) => Promise<{
154
+ id: string;
155
+ label: string;
156
+ href?: string;
157
+ }>;
158
+ artifact?: (args: {
159
+ slug: string;
160
+ }) => Promise<{
161
+ id: string;
162
+ owner: string;
163
+ token: string;
164
+ label: string;
165
+ }>;
166
+ }
167
+ /** A host-defined tool (the `tools` prop): a WebMCP-shaped descriptor plus its handler. */
168
+ interface HostToolDef {
169
+ name: string;
170
+ description: string;
171
+ inputSchema?: Record<string, unknown>;
172
+ confirm?: 'auto' | 'required';
173
+ handler: (args: Record<string, unknown>) => unknown | Promise<unknown>;
174
+ }
175
+
49
176
  interface MatterfactAgentProps {
50
177
  /** Publishable key (`pk_…`) identifying this embed app. Public, origin-scoped. */
51
178
  publishableKey: string;
@@ -108,8 +235,52 @@ interface MatterfactAgentProps {
108
235
  * carry. See `writeActionsGlobal` below.
109
236
  */
110
237
  actions?: HoistActionsConfig;
238
+ /**
239
+ * The app's site map, annotated with each route's content class — so the agent knows
240
+ * which routes carry matterfact content (a co-embedded artifact, a document/report) or
241
+ * the host's own data, and can navigate toward them.
242
+ *
243
+ * Classification only: give the route pattern + label + a `content` tag; NEVER a
244
+ * capability token (the concrete artifact/document on the current page arrives via page
245
+ * context / the live iframe). Sugar over `window.matterfact.sitemap`, read by the loader
246
+ * on load and on navigation.
247
+ */
248
+ sitemap?: SiteMapEntry[];
249
+ /**
250
+ * Declared artifact grants — make a board reachable from ANY route, even ones where
251
+ * its `<MatterfactArtifact>` iframe isn't mounted. Replaces the pattern of mounting
252
+ * hidden zero-size iframes purely to smuggle a read token into the DOM. The token
253
+ * rides the grant channel, never message text. Sugar over `window.matterfact.artifacts`.
254
+ */
255
+ artifacts?: DeclaredArtifact[];
256
+ /**
257
+ * matterfact-defined resolver contracts the HOST implements. matterfact fixes the tool
258
+ * name, schema and agent semantics (so an integration spends no instruction budget on
259
+ * them); you supply the function.
260
+ *
261
+ * - `document({doctype, key})` → `{id, label, href?}` — resolve an off-page matterfact
262
+ * document (dossier/report) to its id, e.g. via your own content-location lookup.
263
+ * - `artifact({slug})` → `{id, owner, token, label}` — resolve an artifact to a read grant.
264
+ *
265
+ * The agent calls these when the site map shows the content lives on another route, and
266
+ * renders the result as an `<MFRef>` chip. Sugar over `window.matterfact.resolve`.
267
+ */
268
+ resolve?: HostResolvers;
269
+ /**
270
+ * Host-defined tools (`app.*`): your own functions, offered to the agent WebMCP-style.
271
+ * Each is `{name, description, inputSchema?, confirm?, handler}`; the name is normalised
272
+ * into the `app.` namespace. A tool is only actually exposed if this app's server-side
273
+ * policy allows it. Sugar over `window.matterfact.tools`.
274
+ */
275
+ tools?: HostToolDef[];
276
+ /**
277
+ * Host telemetry hook: fired on every host-tool advertise/call/result so you can pipe
278
+ * calls into your own observability. Never blocks or breaks the call path — a throw here
279
+ * is swallowed. Sugar over `window.matterfact.onToolEvent`.
280
+ */
281
+ onToolEvent?: (e: ToolEvent) => void;
111
282
  }
112
- declare function MatterfactAgent({ publishableKey, widgetOrigin, surface, theme, getAuthToken, getPageContext, inline, className, style, pageContext, dev, actions, }: MatterfactAgentProps): react_jsx_runtime.JSX.Element | null;
283
+ declare function MatterfactAgent({ publishableKey, widgetOrigin, surface, theme, getAuthToken, getPageContext, inline, className, style, pageContext, dev, actions, sitemap, artifacts, resolve, tools, onToolEvent, }: MatterfactAgentProps): react_jsx_runtime.JSX.Element | null;
113
284
  interface MatterfactArtifactProps {
114
285
  /** The artifact's slug/name. */
115
286
  slug: string;
package/dist/react.d.ts CHANGED
@@ -24,6 +24,75 @@ interface PageEntity {
24
24
  text?: string;
25
25
  data?: Record<string, unknown>;
26
26
  }
27
+ /**
28
+ * How a route's content is classified, for the annotated site map.
29
+ *
30
+ * The host DECORATES the site map we auto-derive (see `SiteMapEntry`) so the agent
31
+ * knows which routes carry MATTERFACT content and of what kind — app-wide awareness
32
+ * it can navigate toward. This is CLASSIFICATION only: no per-instance ids, and never
33
+ * a capability token. The concrete artifact/document on the CURRENT page still arrives
34
+ * via `host.context` entities / `host.artifactGrants`, resolved per page.
35
+ *
36
+ * - `mf-artifact` — a co-embedded matterfact artifact (its slug); the token stays on
37
+ * the live iframe / grant, never here.
38
+ * - `mf-document` — a matterfact document (dossier/report), resolved to an MF_DOC_ID
39
+ * host-side per page.
40
+ * - `host-data` — the host's own data; not a matterfact entity.
41
+ */
42
+ type ContentClass = {
43
+ kind: 'mf-artifact';
44
+ slug: string;
45
+ } | {
46
+ kind: 'mf-document';
47
+ doctype: string;
48
+ } | {
49
+ kind: 'host-data';
50
+ };
51
+ /**
52
+ * One route in the annotated site map: the path pattern + label we derived, plus the
53
+ * host's content classification. `current` marks the route the user is on.
54
+ */
55
+ interface SiteMapEntry {
56
+ /** Route pattern or path, e.g. '/app/company/:ticker/dossier'. */
57
+ path: string;
58
+ /** Human label for the route ('Company Dossier'). */
59
+ label?: string;
60
+ /** The host's classification of this route's content, when it annotated it. */
61
+ content?: ContentClass;
62
+ current?: boolean;
63
+ }
64
+ /**
65
+ * A DECLARED artifact grant — the `<MatterfactAgent artifacts>` prop (or
66
+ * `window.matterfact.artifacts`). Same wire shape as a grant discovered by scanning
67
+ * co-embedded `<MatterfactArtifact>` iframes, plus an optional `label`; it feeds the
68
+ * SAME `host.artifactGrants` channel. This is how a host makes a board reachable from
69
+ * a route where its iframe ISN'T mounted, without hidden zero-size iframes smuggling
70
+ * the token into the DOM. The token stays in the grant channel, never in message text.
71
+ */
72
+ interface DeclaredArtifact {
73
+ slug: string;
74
+ owner: string;
75
+ token: string;
76
+ label?: string;
77
+ }
78
+ /**
79
+ * One host-tool lifecycle event, surfaced to the host via `onToolEvent` (and the dev
80
+ * panel) — the host's own telemetry hook. Fired loader-side; a throwing or slow
81
+ * callback here NEVER blocks or breaks the call path.
82
+ *
83
+ * - `advertise` — the merged tool list changed (fired with the new set's names).
84
+ * - `call` — a tool call is about to run (`args` present).
85
+ * - `result` — the call settled (`ok`/`error`/`ms`).
86
+ */
87
+ interface ToolEvent {
88
+ phase: 'advertise' | 'call' | 'result';
89
+ name: string;
90
+ toolClass: 'hoist' | 'mf' | 'app';
91
+ args?: unknown;
92
+ ok?: boolean;
93
+ error?: string;
94
+ ms?: number;
95
+ }
27
96
 
28
97
  /**
29
98
  * The Hoist adapter — a pure transform from a `HoistRuntime` (already read out of
@@ -46,6 +115,64 @@ interface HoistActionsConfig {
46
115
  navigate: 'off' | 'confirm' | 'auto';
47
116
  }
48
117
 
118
+ /**
119
+ * The host-tool registry — the ONE place the three tool classes are merged into the
120
+ * single list the widget advertises, and the ONE execution path for calling any of
121
+ * them.
122
+ *
123
+ * Three classes, distinguished by who owns the contract and who runs the code:
124
+ *
125
+ * - `hoist.*` matterfact-defined, matterfact-implemented. The loader adapter runs
126
+ * them (today: `hoist.navigate`). Gated on `window.XH` + the host's
127
+ * `hoist.actions` policy. See `hoist-runtime.ts`.
128
+ * - `mf.*` matterfact-defined, HOST-implemented. WE fix the name, schema and
129
+ * agent semantics (the description is authored HERE, not per
130
+ * integration); the host supplies the function via `resolve.*`. Today:
131
+ * `mf.resolveDocument`, `mf.resolveArtifact`.
132
+ * - `app.*` host-defined, host-implemented. Anything the host advertises via
133
+ * `tools`. Normalised into the `app.` namespace so it can never shadow
134
+ * ours.
135
+ *
136
+ * Everything downstream (the widget's confirm gate, the backend dispatcher) is already
137
+ * generic over "a tool with a name/schema/confirm and a call round-trip" — this module
138
+ * is purely the loader-side composition + dispatch, so `hoist-runtime.ts` stays one
139
+ * adapter rather than the whole surface.
140
+ *
141
+ * SECURITY: `mf.*`/`app.*` handlers are HOST code. Their results and error strings pass
142
+ * through `redact()` before leaving the page, exactly like the hoist adapter's; a
143
+ * handler that throws or hangs becomes a normal `{ok:false}` result, never an exception
144
+ * into `context.ts`. And the SERVER decides which of these an app may actually expose
145
+ * (the `host_tools` policy) — advertising here is necessary but not sufficient.
146
+ */
147
+
148
+ /** A host-supplied resolver: matterfact fixes the contract, the host implements it. */
149
+ interface HostResolvers {
150
+ document?: (args: {
151
+ doctype: string;
152
+ key: string;
153
+ }) => Promise<{
154
+ id: string;
155
+ label: string;
156
+ href?: string;
157
+ }>;
158
+ artifact?: (args: {
159
+ slug: string;
160
+ }) => Promise<{
161
+ id: string;
162
+ owner: string;
163
+ token: string;
164
+ label: string;
165
+ }>;
166
+ }
167
+ /** A host-defined tool (the `tools` prop): a WebMCP-shaped descriptor plus its handler. */
168
+ interface HostToolDef {
169
+ name: string;
170
+ description: string;
171
+ inputSchema?: Record<string, unknown>;
172
+ confirm?: 'auto' | 'required';
173
+ handler: (args: Record<string, unknown>) => unknown | Promise<unknown>;
174
+ }
175
+
49
176
  interface MatterfactAgentProps {
50
177
  /** Publishable key (`pk_…`) identifying this embed app. Public, origin-scoped. */
51
178
  publishableKey: string;
@@ -108,8 +235,52 @@ interface MatterfactAgentProps {
108
235
  * carry. See `writeActionsGlobal` below.
109
236
  */
110
237
  actions?: HoistActionsConfig;
238
+ /**
239
+ * The app's site map, annotated with each route's content class — so the agent knows
240
+ * which routes carry matterfact content (a co-embedded artifact, a document/report) or
241
+ * the host's own data, and can navigate toward them.
242
+ *
243
+ * Classification only: give the route pattern + label + a `content` tag; NEVER a
244
+ * capability token (the concrete artifact/document on the current page arrives via page
245
+ * context / the live iframe). Sugar over `window.matterfact.sitemap`, read by the loader
246
+ * on load and on navigation.
247
+ */
248
+ sitemap?: SiteMapEntry[];
249
+ /**
250
+ * Declared artifact grants — make a board reachable from ANY route, even ones where
251
+ * its `<MatterfactArtifact>` iframe isn't mounted. Replaces the pattern of mounting
252
+ * hidden zero-size iframes purely to smuggle a read token into the DOM. The token
253
+ * rides the grant channel, never message text. Sugar over `window.matterfact.artifacts`.
254
+ */
255
+ artifacts?: DeclaredArtifact[];
256
+ /**
257
+ * matterfact-defined resolver contracts the HOST implements. matterfact fixes the tool
258
+ * name, schema and agent semantics (so an integration spends no instruction budget on
259
+ * them); you supply the function.
260
+ *
261
+ * - `document({doctype, key})` → `{id, label, href?}` — resolve an off-page matterfact
262
+ * document (dossier/report) to its id, e.g. via your own content-location lookup.
263
+ * - `artifact({slug})` → `{id, owner, token, label}` — resolve an artifact to a read grant.
264
+ *
265
+ * The agent calls these when the site map shows the content lives on another route, and
266
+ * renders the result as an `<MFRef>` chip. Sugar over `window.matterfact.resolve`.
267
+ */
268
+ resolve?: HostResolvers;
269
+ /**
270
+ * Host-defined tools (`app.*`): your own functions, offered to the agent WebMCP-style.
271
+ * Each is `{name, description, inputSchema?, confirm?, handler}`; the name is normalised
272
+ * into the `app.` namespace. A tool is only actually exposed if this app's server-side
273
+ * policy allows it. Sugar over `window.matterfact.tools`.
274
+ */
275
+ tools?: HostToolDef[];
276
+ /**
277
+ * Host telemetry hook: fired on every host-tool advertise/call/result so you can pipe
278
+ * calls into your own observability. Never blocks or breaks the call path — a throw here
279
+ * is swallowed. Sugar over `window.matterfact.onToolEvent`.
280
+ */
281
+ onToolEvent?: (e: ToolEvent) => void;
111
282
  }
112
- declare function MatterfactAgent({ publishableKey, widgetOrigin, surface, theme, getAuthToken, getPageContext, inline, className, style, pageContext, dev, actions, }: MatterfactAgentProps): react_jsx_runtime.JSX.Element | null;
283
+ declare function MatterfactAgent({ publishableKey, widgetOrigin, surface, theme, getAuthToken, getPageContext, inline, className, style, pageContext, dev, actions, sitemap, artifacts, resolve, tools, onToolEvent, }: MatterfactAgentProps): react_jsx_runtime.JSX.Element | null;
113
284
  interface MatterfactArtifactProps {
114
285
  /** The artifact's slug/name. */
115
286
  slug: string;
package/dist/react.js CHANGED
@@ -5,7 +5,7 @@
5
5
  import { useEffect, useRef } from "react";
6
6
 
7
7
  // src/protocol.ts
8
- var PROTOCOL_VERSION = 2;
8
+ var PROTOCOL_VERSION = 3;
9
9
  var CHANNEL = "mf-embed";
10
10
  function envelope(payload, id) {
11
11
  return {
@@ -575,6 +575,9 @@ var EmbedHost = class {
575
575
  case "widget.needsAuth":
576
576
  void this.provideAuth();
577
577
  break;
578
+ case "widget.navigate":
579
+ void this.loadContext().then((m) => m.navigateHost(msg.href));
580
+ break;
578
581
  }
579
582
  }
580
583
  /**
@@ -691,7 +694,7 @@ var EmbedHost = class {
691
694
  }
692
695
  }
693
696
  loadContext() {
694
- this.context ?? (this.context = import("./context-MVGSYIMB.js").then((m) => {
697
+ this.context ?? (this.context = import("./context-HOOW63MO.js").then((m) => {
695
698
  m.start(
696
699
  this.send,
697
700
  this.config.origin,
@@ -739,6 +742,41 @@ function writeActionsGlobal(actions) {
739
742
  const mf = w.matterfact ?? (w.matterfact = {});
740
743
  mf.hoist = { ...mf.hoist, actions: actions ?? { navigate: "off" } };
741
744
  }
745
+ function writeSitemapGlobal(sitemap) {
746
+ if (typeof window === "undefined" || sitemap === void 0) return;
747
+ const w = window;
748
+ (w.matterfact ?? (w.matterfact = {})).sitemap = sitemap;
749
+ }
750
+ function writeToolGlobals(artifacts, resolve, tools, onToolEvent) {
751
+ if (typeof window === "undefined") return;
752
+ const mf = window.matterfact ?? (window.matterfact = {});
753
+ mf.artifacts = artifacts ?? [];
754
+ mf.resolve = resolve ?? {};
755
+ mf.tools = tools ?? [];
756
+ mf.onToolEvent = onToolEvent;
757
+ }
758
+ function toolDescriptorKey(artifacts, resolve, tools) {
759
+ return JSON.stringify({
760
+ // Artifact identity is data (slug/owner/label), not a function.
761
+ artifacts: (artifacts ?? []).map((a) => ({
762
+ slug: a.slug,
763
+ owner: a.owner,
764
+ label: a.label
765
+ })),
766
+ // For resolvers, only WHICH contracts are present changes the advertised set.
767
+ resolve: {
768
+ document: typeof resolve?.document === "function",
769
+ artifact: typeof resolve?.artifact === "function"
770
+ },
771
+ // For host tools, the advertised descriptor — never the handler.
772
+ tools: (tools ?? []).map((t) => ({
773
+ name: t.name,
774
+ description: t.description,
775
+ inputSchema: t.inputSchema,
776
+ confirm: t.confirm
777
+ }))
778
+ });
779
+ }
742
780
  function MatterfactAgent({
743
781
  publishableKey,
744
782
  widgetOrigin,
@@ -751,7 +789,12 @@ function MatterfactAgent({
751
789
  style,
752
790
  pageContext,
753
791
  dev,
754
- actions
792
+ actions,
793
+ sitemap,
794
+ artifacts,
795
+ resolve,
796
+ tools,
797
+ onToolEvent
755
798
  }) {
756
799
  const authRef = useRef(getAuthToken);
757
800
  authRef.current = getAuthToken;
@@ -761,10 +804,19 @@ function MatterfactAgent({
761
804
  actionsRef.current = actions;
762
805
  const actionsKey = JSON.stringify(actions ?? null);
763
806
  const slot = useRef(null);
807
+ const sitemapKey = JSON.stringify(sitemap ?? null);
808
+ useEffect(() => {
809
+ writeSitemapGlobal(sitemap);
810
+ }, [sitemapKey]);
811
+ useEffect(() => {
812
+ writeToolGlobals(artifacts, resolve, tools, onToolEvent);
813
+ });
814
+ const toolsKey = toolDescriptorKey(artifacts, resolve, tools);
764
815
  useEffect(() => {
765
816
  if (typeof window === "undefined") return;
766
817
  if (inline && !slot.current) return;
767
818
  writeActionsGlobal(actionsRef.current);
819
+ writeToolGlobals(artifacts, resolve, tools, onToolEvent);
768
820
  const config = {
769
821
  publishableKey,
770
822
  origin: widgetOrigin || DEFAULT_ORIGIN,
@@ -795,7 +847,11 @@ function MatterfactAgent({
795
847
  inline,
796
848
  pageContext,
797
849
  dev,
798
- actionsKey
850
+ actionsKey,
851
+ // A change to the advertised tool SHAPE remounts so start() re-advertises under it;
852
+ // a change to only a handler body or callback identity does not (see toolDescriptorKey).
853
+ toolsKey
854
+ // eslint-disable-next-line react-hooks/exhaustive-deps
799
855
  ]);
800
856
  if (!inline) return null;
801
857
  return /* @__PURE__ */ jsx(