@burdenoff/fe-libs 2026.1004.2 → 2026.1004.4

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 (56) hide show
  1. package/dist/chrome/mobileTabBar/useVisibleNavItems.d.ts +9 -0
  2. package/dist/chrome/mobileTabBar/useVisibleNavItems.d.ts.map +1 -1
  3. package/dist/chrome/mobileTabBar/useVisibleNavItems.js +3 -1
  4. package/dist/shared/assistant/api.d.ts +6 -0
  5. package/dist/shared/assistant/api.d.ts.map +1 -1
  6. package/dist/shared/assistant/api.js +5 -3
  7. package/dist/shared/assistant/i18nManifest.d.ts +3 -0
  8. package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
  9. package/dist/shared/assistant/i18nManifest.js +3 -0
  10. package/dist/shared/assistant/index.d.ts +8 -0
  11. package/dist/shared/assistant/index.d.ts.map +1 -1
  12. package/dist/shared/assistant/localUiCommandCopy.d.ts +18 -0
  13. package/dist/shared/assistant/localUiCommandCopy.d.ts.map +1 -1
  14. package/dist/shared/assistant/localUiCommandCopy.js +22 -2
  15. package/dist/shared/assistant/localUiCommands.d.ts +63 -26
  16. package/dist/shared/assistant/localUiCommands.d.ts.map +1 -1
  17. package/dist/shared/assistant/localUiCommands.js +128 -59
  18. package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
  19. package/dist/shared/assistant/ui/AssistantChatArea.js +884 -750
  20. package/dist/shared/assistant/ui/AssistantMarkdownRenderer.d.ts +3 -34
  21. package/dist/shared/assistant/ui/AssistantMarkdownRenderer.d.ts.map +1 -1
  22. package/dist/shared/assistant/ui/AssistantMarkdownRenderer.js +83 -119
  23. package/dist/shared/assistant/ui/composer/AssistantConnectSourceItem.js +2 -1
  24. package/dist/shared/assistant/ui/composer/connectSource.js +2 -1
  25. package/dist/shared/assistant/uiActions/assistantHref.d.ts +36 -0
  26. package/dist/shared/assistant/uiActions/assistantHref.d.ts.map +1 -0
  27. package/dist/shared/assistant/uiActions/assistantHref.js +46 -0
  28. package/dist/shared/assistant/uiActions/deixis.d.ts +29 -0
  29. package/dist/shared/assistant/uiActions/deixis.d.ts.map +1 -0
  30. package/dist/shared/assistant/uiActions/deixis.js +54 -0
  31. package/dist/shared/assistant/uiActions/entityRoutes.d.ts +49 -0
  32. package/dist/shared/assistant/uiActions/entityRoutes.d.ts.map +1 -0
  33. package/dist/shared/assistant/uiActions/entityRoutes.js +53 -0
  34. package/dist/shared/assistant/uiActions/inAppLinks.d.ts +28 -0
  35. package/dist/shared/assistant/uiActions/inAppLinks.d.ts.map +1 -0
  36. package/dist/shared/assistant/uiActions/inAppLinks.js +51 -0
  37. package/dist/shared/assistant/uiActions/linkContext.d.ts +52 -0
  38. package/dist/shared/assistant/uiActions/linkContext.d.ts.map +1 -0
  39. package/dist/shared/assistant/uiActions/linkContext.js +60 -0
  40. package/dist/shared/assistant/uiActions/recordNames.d.ts +73 -0
  41. package/dist/shared/assistant/uiActions/recordNames.d.ts.map +1 -0
  42. package/dist/shared/assistant/uiActions/recordNames.js +75 -0
  43. package/dist/shared/assistant/uiActions/resolveTarget.d.ts +43 -0
  44. package/dist/shared/assistant/uiActions/resolveTarget.d.ts.map +1 -0
  45. package/dist/shared/assistant/uiActions/resolveTarget.js +49 -0
  46. package/dist/shared/assistant/uiActions/uiCatalogue.d.ts +30 -0
  47. package/dist/shared/assistant/uiActions/uiCatalogue.d.ts.map +1 -0
  48. package/dist/shared/assistant/uiActions/uiCatalogue.js +22 -0
  49. package/dist/shared/components/assistantWidget/MessageContent.js +4 -3
  50. package/dist/shared/tours/TourPlayerProvider.d.ts +12 -0
  51. package/dist/shared/tours/TourPlayerProvider.d.ts.map +1 -1
  52. package/dist/shared/tours/TourPlayerProvider.js +1 -1
  53. package/dist/shared/tours/tourTrigger/MobileTourSheet.d.ts.map +1 -1
  54. package/dist/shared/tours/tourTrigger/MobileTourSheet.js +16 -15
  55. package/dist/shared-assistant.js +198 -190
  56. package/package.json +3 -1
@@ -0,0 +1,49 @@
1
+ /**
2
+ * ★ BOFF-8060 (N1b, C4b-lite): product-declared ENTITY routes — pages of one
3
+ * record (`/bigconsole/dashboards/:id`) that no sidebar entry names, so
4
+ * "take me there" cannot find them in the navigation. A product declares the
5
+ * templates it owns; the matcher below is the only thing that ever treats a
6
+ * path as one.
7
+ *
8
+ * PURE: no React, no DOM. The default is NO routes, so every product behaves
9
+ * as before until it supplies some.
10
+ *
11
+ * ★★ WHY THE `exclude` LISTS EXIST. A template like `/healthybowl/crops/:id`
12
+ * also matches `/healthybowl/crops/fields`, which is a STATIC page of the
13
+ * router and not a crop. Every param lists the router's static siblings it must
14
+ * never swallow. A router guard test in each app renders every template and
15
+ * every static sibling to prove the two lists agree with the real router.
16
+ */
17
+ export type EntityParamKind = "id" | "slug" | "int";
18
+ export interface EntityParam {
19
+ kind: EntityParamKind;
20
+ /** Static sibling segments of the router this param must never match (case-insensitive: the router is). */
21
+ exclude?: readonly string[];
22
+ }
23
+ export interface AssistantEntityRoute {
24
+ /** Stable id, e.g. `bigconsole-dashboard`. The resolved target is `entity:<id>`. */
25
+ id: string;
26
+ /** A path template: `/bigconsole/dashboards/:id`. A segment starting `:` is a param. */
27
+ pattern: string;
28
+ /** One entry per param in `pattern`. */
29
+ params: Readonly<Record<string, EntityParam>>;
30
+ /**
31
+ * The id of a navigation entry the person must be able to SEE (the whole
32
+ * visible tree, groups included) for this route to resolve. Absent: a
33
+ * product-declared static route, which resolves for everyone who reaches it.
34
+ */
35
+ visibleWith?: string;
36
+ /** What the page is called in a sentence: `{ key: "entity.dashboard", fallback: "dashboard" }`. */
37
+ noun: {
38
+ key: string;
39
+ fallback: string;
40
+ };
41
+ }
42
+ export interface EntityMatch {
43
+ route: AssistantEntityRoute;
44
+ params: Record<string, string>;
45
+ }
46
+ export declare function matchEntityRoute(path: string, routes: readonly AssistantEntityRoute[]): EntityMatch | null;
47
+ /** Fill a template with params, or null when one is missing or invalid. Used by record adapters. */
48
+ export declare function fillEntityRoute(route: AssistantEntityRoute, params: Readonly<Record<string, string>>): string | null;
49
+ //# sourceMappingURL=entityRoutes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityRoutes.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/entityRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;AAEpD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,2GAA2G;IAC3G,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,oFAAoF;IACpF,EAAE,EAAE,MAAM,CAAC;IACX,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAC9C;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mGAAmG;IACnG,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC;AAoBD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,oBAAoB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAeD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,oBAAoB,EAAE,GACtC,WAAW,GAAG,IAAI,CA8BpB;AAED,oGAAoG;AACpG,wBAAgB,eAAe,CAC7B,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACvC,MAAM,GAAG,IAAI,CAef"}
@@ -0,0 +1,53 @@
1
+ //#region src/shared/assistant/uiActions/entityRoutes.ts
2
+ var e = {
3
+ id: /^[A-Za-z0-9_-]{1,128}$/,
4
+ slug: /^[A-Za-z0-9_.-]{1,128}$/,
5
+ int: /^[0-9]{1,9}$/
6
+ };
7
+ function t(t, n) {
8
+ return !(!e[t].test(n) || t === "slug" && (n === "." || n === ".." || n.includes("..")));
9
+ }
10
+ function n(e) {
11
+ if (!e.startsWith("/") || e.startsWith("//") || e.includes("?") || e.includes("#") || /%(?:2f|5c|2e)/i.test(e) || e.includes("\\")) return null;
12
+ let t = (e.length > 1 && e.endsWith("/") ? e.slice(0, -1) : e).slice(1).split("/");
13
+ return t.some((e) => e === "") ? null : t;
14
+ }
15
+ function r(e, r) {
16
+ let i = n(e);
17
+ if (i === null) return null;
18
+ for (let e of r) {
19
+ let n = e.pattern.slice(1).split("/");
20
+ if (n.length !== i.length) continue;
21
+ let r = {}, a = !0;
22
+ for (let o = 0; o < n.length && a; o += 1) {
23
+ let s = n[o] ?? "", c = i[o] ?? "";
24
+ if (!s.startsWith(":")) {
25
+ a = s.toLowerCase() === c.toLowerCase();
26
+ continue;
27
+ }
28
+ let l = s.slice(1), u = e.params[l];
29
+ a = u !== void 0 && t(u.kind, c) && !(u.exclude ?? []).some((e) => e.toLowerCase() === c.toLowerCase()), a && (r[l] = c);
30
+ }
31
+ if (a) return {
32
+ route: e,
33
+ params: r
34
+ };
35
+ }
36
+ return null;
37
+ }
38
+ function i(e, t) {
39
+ let n = [];
40
+ for (let r of e.pattern.slice(1).split("/")) {
41
+ if (!r.startsWith(":")) {
42
+ n.push(r);
43
+ continue;
44
+ }
45
+ let e = t[r.slice(1)];
46
+ if (e === void 0) return null;
47
+ n.push(e);
48
+ }
49
+ let i = `/${n.join("/")}`;
50
+ return r(i, [e]) ? i : null;
51
+ }
52
+ //#endregion
53
+ export { i as fillEntityRoute, r as matchEntityRoute };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * ★ BOFF-8060 (N1b, C3b-link): the in-app links of one assistant reply, in the
3
+ * order the person reads them. "Take me there" acts on exactly these.
4
+ *
5
+ * PURE: markdown text in, paths out — no React and no DOM. It parses with the
6
+ * parser react-markdown 10 uses (`remark-parse` + `remark-gfm`), and judges
7
+ * every href with the SAME functions the renderer judges it with
8
+ * (`assistantUrlTransform`, `classifyAssistantHref`, `assistantRoutePath`), so
9
+ * a link is "in-app" here exactly when the renderer draws it as an in-app
10
+ * anchor. A parity test renders a corpus through the real renderer and
11
+ * compares the two sets.
12
+ *
13
+ * What is NOT a link the person can click, and so is never acted on:
14
+ * - code (fenced or inline) and raw HTML — the renderer prints them as text;
15
+ * - an image (a picture is not a link; `![x](/a)` has no anchor);
16
+ * - a reference whose definition does not exist;
17
+ * - an href the policy blocks, or one that leaves the app (external, a
18
+ * protocol-relative `//host`, `/\host`).
19
+ */
20
+ export interface InAppLink {
21
+ /** What the link says, at most `LINK_TEXT_MAX` characters (the path when it says nothing). */
22
+ text: string;
23
+ /** The router path: pathname + search + hash, never an absolute URL. */
24
+ path: string;
25
+ }
26
+ export declare const LINK_TEXT_MAX = 80;
27
+ export declare function extractInAppLinks(markdown: string): InAppLink[];
28
+ //# sourceMappingURL=inAppLinks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inAppLinks.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/inAppLinks.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,SAAS;IACxB,8FAA8F;IAC9F,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,aAAa,KAAK,CAAC;AA0DhC,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CA0B/D"}
@@ -0,0 +1,51 @@
1
+ import e from "../../../node_modules/remark-parse/lib/index.js";
2
+ import { unified as t } from "../../../node_modules/unified/lib/index.js";
3
+ import n from "../../../node_modules/remark-gfm/lib/index.js";
4
+ import { assistantRoutePath as r, classifyAssistantHref as i, transformAssistantUrl as a } from "./assistantHref.js";
5
+ //#region src/shared/assistant/uiActions/inAppLinks.ts
6
+ var o = 80, s = t().use(e).use(n), c = (e) => e.trim().replace(/\s+/g, " ").toLowerCase(), l = new Set([
7
+ "code",
8
+ "inlineCode",
9
+ "html",
10
+ "image",
11
+ "imageReference",
12
+ "definition"
13
+ ]);
14
+ function u(e) {
15
+ return e.type === "text" || e.type === "inlineCode" ? e.value ?? "" : e.type === "image" || e.type === "imageReference" ? e.alt ?? "" : (e.children ?? []).map(u).join("");
16
+ }
17
+ function d(e, t) {
18
+ if (e.type === "definition" && e.identifier !== void 0 && e.url !== void 0) {
19
+ let n = c(e.identifier);
20
+ t.has(n) || t.set(n, e.url);
21
+ }
22
+ for (let n of e.children ?? []) d(n, t);
23
+ }
24
+ function f(e) {
25
+ let t = a(e, "href", "a");
26
+ return i(t) === "internal" ? r(t) : null;
27
+ }
28
+ function p(e) {
29
+ if (!e.trim()) return [];
30
+ let t = s.parse(e), n = /* @__PURE__ */ new Map();
31
+ d(t, n);
32
+ let r = [], i = /* @__PURE__ */ new Set(), a = (e) => {
33
+ if (l.has(e.type)) return;
34
+ let t;
35
+ if (e.type === "link" ? t = e.url : e.type === "linkReference" && e.identifier !== void 0 && (t = n.get(c(e.identifier))), t !== void 0) {
36
+ let n = f(t);
37
+ if (n !== null && !i.has(n)) {
38
+ i.add(n);
39
+ let t = u(e).replace(/\s+/g, " ").trim();
40
+ r.push({
41
+ text: (t || n).slice(0, 80),
42
+ path: n
43
+ });
44
+ }
45
+ }
46
+ for (let t of e.children ?? []) a(t);
47
+ };
48
+ return a(t), r;
49
+ }
50
+ //#endregion
51
+ export { o as LINK_TEXT_MAX, p as extractInAppLinks };
@@ -0,0 +1,52 @@
1
+ import { LocalDestination } from '../localUiCommands';
2
+ import { ResolveContext, ResolvedLinks } from './resolveTarget';
3
+ /**
4
+ * ★ BOFF-8060 (N1b): what "take me there" and "the second one" act on, built
5
+ * LIVE at send time from the conversation — never from render state, never
6
+ * from a re-query of the registry for candidates.
7
+ *
8
+ * Both are limited to the NEWEST assistant message on the surface the command
9
+ * came from (chat thread for a typed command, that voice session's spoken
10
+ * turns for a spoken one) and only while no later person message exists there.
11
+ * A hidden reply from another conversation, an older reply and a reply of the
12
+ * other surface are never read.
13
+ */
14
+ export interface SurfaceMessage {
15
+ id: string;
16
+ role: string;
17
+ metadata?: ({
18
+ voice?: boolean;
19
+ voiceSessionId?: string;
20
+ localAction?: unknown;
21
+ } & Record<string, unknown>) | undefined;
22
+ }
23
+ /** The newest assistant message on the surface, or null when a person message came after it. */
24
+ export declare function latestReplyOnSurface<T extends SurfaceMessage>(messages: readonly T[], voiceSessionId: string | undefined): T | null;
25
+ export declare function rememberPresentedList(messageId: string, candidates: readonly LocalDestination[]): void;
26
+ export declare const presentedListFor: (messageId: string) => LocalDestination[] | undefined;
27
+ /** @internal for tests */
28
+ export declare const clearPresentedLists: () => void;
29
+ export interface PendingChoice {
30
+ /** One entry per line shown; null where that line can no longer be opened. null overall: unreadable (an entity list after a reload). */
31
+ candidates: ReadonlyArray<LocalDestination | null> | null;
32
+ /**
33
+ * The ids the list's record carries, kept so a reply that merely points at an
34
+ * unreadable list can keep it pending (the next pick must not reach a model
35
+ * that never saw the list either).
36
+ */
37
+ candidateIds: readonly string[];
38
+ }
39
+ export interface NavigationContext {
40
+ links: ResolvedLinks;
41
+ pendingChoice: PendingChoice | null;
42
+ }
43
+ /**
44
+ * @param text what the person SEES of the message (`spokenTurnText`), never raw
45
+ * content: a link inside a tool-step description is not a link they saw.
46
+ */
47
+ export declare function buildNavigationContext(input: {
48
+ reply: SurfaceMessage | null;
49
+ text: string;
50
+ resolve: ResolveContext;
51
+ }): NavigationContext | null;
52
+ //# sourceMappingURL=linkContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linkContext.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/linkContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;GAUG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EACL,CAAC;QACC,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC5B,SAAS,CAAC;CACf;AAYD,gGAAgG;AAChG,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,cAAc,EAC3D,QAAQ,EAAE,SAAS,CAAC,EAAE,EACtB,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,CAAC,GAAG,IAAI,CAQV;AAaD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,SAAS,gBAAgB,EAAE,GACtC,IAAI,CAWN;AAED,eAAO,MAAM,gBAAgB,GAC3B,WAAW,MAAM,KAChB,gBAAgB,EAAE,GAAG,SAAqC,CAAC;AAE9D,0BAA0B;AAC1B,eAAO,MAAM,mBAAmB,QAAO,IAAyB,CAAC;AAIjE,MAAM,WAAW,aAAa;IAC5B,wIAAwI;IACxI,UAAU,EAAE,aAAa,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D;;;;OAIG;IACH,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,aAAa,CAAC;IACrB,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;CACrC;AAiDD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,cAAc,CAAC;CACzB,GAAG,iBAAiB,GAAG,IAAI,CAI3B"}
@@ -0,0 +1,60 @@
1
+ import { isEntityTarget as e, resolveInAppLinks as t, resolveUiTarget as n } from "./resolveTarget.js";
2
+ import { extractInAppLinks as r } from "./inAppLinks.js";
3
+ //#region src/shared/assistant/uiActions/linkContext.ts
4
+ var i = (e, t) => {
5
+ let n = e.metadata?.voice === !0;
6
+ return t === void 0 ? !n : n && e.metadata?.voiceSessionId === t;
7
+ };
8
+ function a(e, t) {
9
+ for (let n = e.length - 1; n >= 0; --n) {
10
+ let r = e[n];
11
+ if (!(!r || !i(r, t))) {
12
+ if (r.role === "user") return null;
13
+ if (r.role === "assistant") return r;
14
+ }
15
+ }
16
+ return null;
17
+ }
18
+ var o = 50, s = /* @__PURE__ */ new Map();
19
+ function c(e, t) {
20
+ for (s.delete(e), s.set(e, t.map((e) => ({ ...e }))); s.size > o;) {
21
+ let e = s.keys().next();
22
+ if (e.done) break;
23
+ s.delete(e.value);
24
+ }
25
+ }
26
+ var l = (e) => s.get(e), u = () => s.clear(), d = null, f = (e) => {
27
+ if (d?.text === e) return d.links;
28
+ let t = r(e);
29
+ return d = {
30
+ text: e,
31
+ links: t
32
+ }, t;
33
+ };
34
+ function p(t, r) {
35
+ let i = t.metadata?.localAction;
36
+ if (typeof i != "object" || !i) return null;
37
+ let a = i;
38
+ if (a.kind !== "choose-destination") return null;
39
+ let o = l(t.id);
40
+ if (o) return {
41
+ candidates: o.map((t) => n(t.path, r, e(t) ? t.label : void 0)),
42
+ candidateIds: o.map((e) => e.id)
43
+ };
44
+ let s = Array.isArray(a.candidateIds) ? a.candidateIds : [], c = s.filter((e) => typeof e == "string"), u = s.map((e) => typeof e == "string" ? r.destinations.find((t) => t.id === e) ?? null : null);
45
+ return u.length === 0 || u.some((e) => e === null) ? {
46
+ candidates: null,
47
+ candidateIds: c
48
+ } : {
49
+ candidates: u,
50
+ candidateIds: c
51
+ };
52
+ }
53
+ function m(e) {
54
+ return e.reply ? {
55
+ links: t(f(e.text), e.resolve),
56
+ pendingChoice: p(e.reply, e.resolve)
57
+ } : null;
58
+ }
59
+ //#endregion
60
+ export { m as buildNavigationContext, u as clearPresentedLists, a as latestReplyOnSurface, l as presentedListFor, c as rememberPresentedList };
@@ -0,0 +1,73 @@
1
+ import { LocalDestination } from '../localUiCommands';
2
+ import { AssistantEntityRoute } from './entityRoutes';
3
+ /**
4
+ * ★ BOFF-8060 (N1b, named records): "open the Coffee Shop Sales dashboard".
5
+ *
6
+ * A PRODUCT ADAPTER knows how to look one kind of record up by name through the
7
+ * product's own (RBAC-filtered) API; this module is the PURE half — the grammar
8
+ * that recognises such a request and the plan that turns the adapters' answers
9
+ * into "open it", "which of these?" or "nothing found". Nothing here reaches
10
+ * the network.
11
+ *
12
+ * Rules that keep it safe:
13
+ * - an adapter can only produce a path by FILLING an entity route the product
14
+ * declared (`fillEntityRoute` re-validates it), never an arbitrary string;
15
+ * - the route's `visibleWith` navigation entry must be in the person's visible
16
+ * tree, or the adapter is not consulted at all;
17
+ * - no match is NOT an answer: the sentence goes to the model as before.
18
+ */
19
+ export interface AssistantRecordMatch {
20
+ /** The route params that identify the record (`{ id: "…" }`). */
21
+ params: Readonly<Record<string, string>>;
22
+ /** The record's own name, as the person sees it in the app. */
23
+ name: string;
24
+ }
25
+ export interface AssistantRecordAdapter {
26
+ /** Stable id, e.g. `bigconsole-dashboard`. */
27
+ id: string;
28
+ /** What people call the kind, lower case, singular and plural: `["dashboard", "dashboards"]`. */
29
+ nouns: readonly string[];
30
+ /** The kind's name in a sentence (translated): `{ key: "entity.dashboard", fallback: "dashboard" }`. */
31
+ noun: {
32
+ key: string;
33
+ fallback: string;
34
+ };
35
+ /** The id of the `AssistantEntityRoute` a match opens. */
36
+ entityRouteId: string;
37
+ /**
38
+ * The records this person may open whose name fits `name`. Called only for a
39
+ * recognised request. A rejection counts as "none found"; it is aborted when
40
+ * the panel stops waiting.
41
+ */
42
+ find: (name: string, signal: AbortSignal) => Promise<readonly AssistantRecordMatch[]>;
43
+ }
44
+ export interface RecordRequest {
45
+ /** The name as said, lower case. */
46
+ name: string;
47
+ /** Adapters named by the sentence's noun; empty: every adapter. */
48
+ adapterIds: string[];
49
+ }
50
+ export declare function parseRecordRequest(utterance: string, adapters: readonly Pick<AssistantRecordAdapter, "id" | "nouns">[]): RecordRequest | null;
51
+ export interface RecordAnswer {
52
+ adapter: Pick<AssistantRecordAdapter, "id">;
53
+ route: AssistantEntityRoute;
54
+ /** The kind's translated name. */
55
+ noun: string;
56
+ matches: readonly AssistantRecordMatch[];
57
+ }
58
+ export type RecordPlan = {
59
+ kind: "none";
60
+ } | {
61
+ kind: "open";
62
+ destination: LocalDestination;
63
+ } | {
64
+ kind: "choose";
65
+ /** `kinds`: the same name in different kinds of record; `records`: several of one kind. */
66
+ why: "kinds" | "records";
67
+ candidates: LocalDestination[];
68
+ /** The distinct kind names among the candidates, in order. */
69
+ nouns: string[];
70
+ };
71
+ export declare const RECORD_CHOICE_MAX = 4;
72
+ export declare function planRecordResolution(name: string, answers: readonly RecordAnswer[]): RecordPlan;
73
+ //# sourceMappingURL=recordNames.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recordNames.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/recordNames.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAmB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG5E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACzC,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,8CAA8C;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,iGAAiG;IACjG,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,wGAAwG;IACxG,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,IAAI,EAAE,CACJ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,KAChB,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,aAAa;IAC5B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AA4CD,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,IAAI,CAAC,sBAAsB,EAAE,IAAI,GAAG,OAAO,CAAC,EAAE,GAChE,aAAa,GAAG,IAAI,CA6CtB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,IAAI,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;IAC5C,KAAK,EAAE,oBAAoB,CAAC;IAC5B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;CAC1C;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,gBAAgB,CAAA;CAAE,GAC/C;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,2FAA2F;IAC3F,GAAG,EAAE,OAAO,GAAG,SAAS,CAAC;IACzB,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEN,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAkBnC,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,SAAS,YAAY,EAAE,GAC/B,UAAU,CA8CZ"}
@@ -0,0 +1,75 @@
1
+ import { fillEntityRoute as e } from "./entityRoutes.js";
2
+ import { ENTITY_TARGET_PREFIX as t } from "./resolveTarget.js";
3
+ //#region src/shared/assistant/uiActions/recordNames.ts
4
+ var n = (e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), r = new Set(/* @__PURE__ */ "it.that.this.there.here.back.them.those.one.link.page.screen.list.tab.section.view.all.my.the.new.first.second.third.fourth.last.next.previous.settings".split(".")), i = /(?:^| )(?:page|screen|list|tab|section|view|settings|menu)$/, a = 60, o = "(?:open|go to|take me to|pull up|bring up|navigate to|switch to|show me)", s = "(?:open|go to|take me to|pull up|bring up|navigate to)";
5
+ function c(e, t) {
6
+ if (t.length === 0) return null;
7
+ let c = (e) => t.filter((t) => t.nouns.includes(e)).map((e) => e.id), l = [...new Set(t.flatMap((e) => e.nouns))].sort((e, t) => t.length - e.length), u = (e) => {
8
+ let t = e.trim();
9
+ return t.length >= 2 && t.length <= a && !r.has(t) && !i.test(t);
10
+ };
11
+ if (l.length > 0) {
12
+ let t = l.map((e) => n(e)).join("|"), r = RegExp(`^${o} (?:the |my )?(${t}) (?:(?:called|named) )?(.+)$`).exec(e);
13
+ if (r && u(r[2] ?? "")) {
14
+ let e = c(r[1] ?? "");
15
+ if (e.length > 0) return {
16
+ name: (r[2] ?? "").trim(),
17
+ adapterIds: e
18
+ };
19
+ }
20
+ let i = RegExp(`^${o} (?:the |my )?(.+?) (${t})$`).exec(e);
21
+ if (i && u(i[1] ?? "")) {
22
+ let e = c(i[2] ?? "");
23
+ if (e.length > 0) return {
24
+ name: (i[1] ?? "").trim(),
25
+ adapterIds: e
26
+ };
27
+ }
28
+ }
29
+ let d = RegExp(`^${s} (?:the |my )?(.+)$`).exec(e);
30
+ return d && u(d[1] ?? "") && (d[1] ?? "").length >= 3 ? {
31
+ name: (d[1] ?? "").trim(),
32
+ adapterIds: []
33
+ } : null;
34
+ }
35
+ var l = 4, u = (e) => e.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ").trim();
36
+ function d(e, t) {
37
+ let n = t.split(" ");
38
+ return e.split(" ").every((e) => n.some((t) => t.startsWith(e)));
39
+ }
40
+ function f(n, r) {
41
+ let i = u(n);
42
+ if (!i) return { kind: "none" };
43
+ let a = [];
44
+ for (let n of r) for (let r of n.matches) {
45
+ let o = e(n.route, r.params);
46
+ if (o === null) continue;
47
+ let s = u(r.name), c = s === i;
48
+ !c && !d(i, s) || a.some((e) => e.destination.path === o) || a.push({
49
+ adapterId: n.adapter.id,
50
+ noun: n.noun,
51
+ exact: c,
52
+ destination: {
53
+ id: `${t}${n.route.id}`,
54
+ label: r.name.trim().slice(0, 80) || n.noun,
55
+ path: o,
56
+ context: n.noun
57
+ }
58
+ });
59
+ }
60
+ let o = a.some((e) => e.exact) ? a.filter((e) => e.exact) : a, s = o[0];
61
+ if (!s) return { kind: "none" };
62
+ if (o.length === 1) return {
63
+ kind: "open",
64
+ destination: s.destination
65
+ };
66
+ let c = new Set(o.map((e) => e.adapterId)), l = o.slice(0, 4);
67
+ return {
68
+ kind: "choose",
69
+ why: c.size > 1 ? "kinds" : "records",
70
+ candidates: l.map((e) => e.destination),
71
+ nouns: [...new Set(l.map((e) => e.noun))]
72
+ };
73
+ }
74
+ //#endregion
75
+ export { l as RECORD_CHOICE_MAX, c as parseRecordRequest, f as planRecordResolution };
@@ -0,0 +1,43 @@
1
+ import { LocalDestination } from '../localUiCommands';
2
+ import { AssistantEntityRoute } from './entityRoutes';
3
+ import { InAppLink } from './inAppLinks';
4
+ /**
5
+ * ★ BOFF-8060 (N1b): which of the in-app paths a reply linked the panel may
6
+ * take the person to. PURE.
7
+ *
8
+ * A path resolves only to a place the person is already offered:
9
+ * 1. a NAVIGATION destination — what the RBAC-filtered sidebar shows
10
+ * (`navDestinations`), matched by its target path or its own path;
11
+ * 2. a product-declared ENTITY route whose `visibleWith` navigation entry is in
12
+ * the person's visible tree — or a declared static route with no
13
+ * `visibleWith` (the product's reviewed decision).
14
+ * Anything else is "unresolved": the panel says it cannot open that link, and
15
+ * the person can still click it themselves.
16
+ */
17
+ export interface ResolveContext {
18
+ destinations: readonly LocalDestination[];
19
+ entityRoutes?: readonly AssistantEntityRoute[] | undefined;
20
+ /** Every id in the person's visible navigation tree, groups and parents included. */
21
+ visibleNavIds: ReadonlySet<string>;
22
+ /** The translated noun of an entity route ("dashboard"); default: its English fallback. */
23
+ nounLabel?: ((noun: AssistantEntityRoute["noun"]) => string) | undefined;
24
+ }
25
+ /** The entity-target id prefix: `entity:<routeId>`. */
26
+ export declare const ENTITY_TARGET_PREFIX = "entity:";
27
+ export declare function isEntityTarget(target: Pick<LocalDestination, "id">): boolean;
28
+ /** Every `id` in a navigation tree (the VISIBLE one), children included. */
29
+ export declare function navEntryIds(entries: readonly {
30
+ id: string;
31
+ children?: readonly {
32
+ id: string;
33
+ }[] | undefined;
34
+ }[]): Set<string>;
35
+ export declare function resolveUiTarget(path: string, context: ResolveContext, linkText?: string): LocalDestination | null;
36
+ export interface ResolvedLinks {
37
+ /** In reply order, de-duplicated by path. */
38
+ targets: LocalDestination[];
39
+ /** How many in-app links the reply has that did NOT resolve. */
40
+ unresolved: number;
41
+ }
42
+ export declare function resolveInAppLinks(links: readonly InAppLink[], context: ResolveContext): ResolvedLinks;
43
+ //# sourceMappingURL=resolveTarget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveTarget.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/resolveTarget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAoB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC1C,YAAY,CAAC,EAAE,SAAS,oBAAoB,EAAE,GAAG,SAAS,CAAC;IAC3D,qFAAqF;IACrF,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,2FAA2F;IAC3F,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;CAC1E;AAKD,uDAAuD;AACvD,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,OAAO,CAE5E;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CACzB,OAAO,EAAE,SAAS;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,SAAS,CAAC;CAClD,EAAE,GACF,GAAG,CAAC,MAAM,CAAC,CAkBb;AAKD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,gBAAgB,GAAG,IAAI,CAgCzB;AAED,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,OAAO,EAAE,cAAc,GACtB,aAAa,CAUf"}
@@ -0,0 +1,49 @@
1
+ import { matchEntityRoute as e } from "./entityRoutes.js";
2
+ import { isCurrentPath as t } from "../localUiCommands.js";
3
+ //#region src/shared/assistant/uiActions/resolveTarget.ts
4
+ var n = /\[?REDACTED_[A-Z_]+\]?|%5BREDACTED_/i, r = "entity:";
5
+ function i(e) {
6
+ return e.id.startsWith(r);
7
+ }
8
+ function a(e) {
9
+ let t = /* @__PURE__ */ new Set(), n = (e) => {
10
+ for (let r of e) t.add(r.id), r.children?.length && n(r.children);
11
+ };
12
+ return n(e), t;
13
+ }
14
+ var o = (e) => e.split("#")[0]?.split("?")[0] ?? e;
15
+ function s(i, a, s) {
16
+ if (!i.startsWith("/") || i.startsWith("//") || n.test(i)) return null;
17
+ for (let e of a.destinations) {
18
+ if ([e.path, ...e.aliases ?? []].find((e) => t(e, i)) === void 0) continue;
19
+ let n = t(e.path, i);
20
+ return {
21
+ ...e,
22
+ path: n ? i : e.path
23
+ };
24
+ }
25
+ let c = e(i, a.entityRoutes ?? []);
26
+ if (c === null) return null;
27
+ let { route: l } = c;
28
+ if (l.visibleWith !== void 0 && !a.visibleNavIds.has(l.visibleWith)) return null;
29
+ let u = a.nounLabel ? a.nounLabel(l.noun) : l.noun.fallback;
30
+ return {
31
+ id: `${r}${l.id}`,
32
+ label: (s ?? "").trim() || u,
33
+ path: o(i),
34
+ context: u
35
+ };
36
+ }
37
+ function c(e, t) {
38
+ let n = [], r = 0;
39
+ for (let i of e) {
40
+ let e = s(i.path, t, i.text);
41
+ e === null ? r += 1 : n.some((t) => t.path === e.path) || n.push(e);
42
+ }
43
+ return {
44
+ targets: n,
45
+ unresolved: r
46
+ };
47
+ }
48
+ //#endregion
49
+ export { r as ENTITY_TARGET_PREFIX, i as isEntityTarget, a as navEntryIds, c as resolveInAppLinks, s as resolveUiTarget };
@@ -0,0 +1,30 @@
1
+ import { LocalDestination } from '../localUiCommands';
2
+ /**
3
+ * ★ BOFF-8060 (N1b, §4.9 — N2 plumbing, DORMANT): the pages this person may be
4
+ * sent to, offered to the model so a future (N2) rule can point at the right
5
+ * one. Nothing consumes it yet: a product must opt in
6
+ * (`LocalUiCommandOptions.uiCatalogue`), and an older sandbox ignores an
7
+ * unknown body key — the same precedent as `conversationId` and `writeReply`.
8
+ * The field stays labelled `source` until the N2 image is live.
9
+ *
10
+ * It is built ONLY from what the RBAC-filtered sidebar really shows: never
11
+ * from the optimistic list shown while permissions load, never when a
12
+ * permission fetch failed, and never from a simulated role's navigation.
13
+ */
14
+ export interface AssistantUiCatalogueEntry {
15
+ id: string;
16
+ label: string;
17
+ context?: string;
18
+ path: string;
19
+ }
20
+ export interface AssistantUiCatalogue {
21
+ v: 1;
22
+ entries: AssistantUiCatalogueEntry[];
23
+ }
24
+ export declare const UI_CATALOGUE_MAX_ENTRIES = 120;
25
+ export declare const UI_CATALOGUE_MAX_BYTES: number;
26
+ export declare function buildUiCatalogue(destinations: readonly LocalDestination[], gate: {
27
+ permissionsSettled: boolean;
28
+ simulating: boolean;
29
+ }): AssistantUiCatalogue | null;
30
+ //# sourceMappingURL=uiCatalogue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uiCatalogue.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/uiCatalogue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,CAAC,EAAE,CAAC,CAAC;IACL,OAAO,EAAE,yBAAyB,EAAE,CAAC;CACtC;AAED,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,sBAAsB,QAAW,CAAC;AAK/C,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,SAAS,gBAAgB,EAAE,EACzC,IAAI,EAAE;IAAE,kBAAkB,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GACzD,oBAAoB,GAAG,IAAI,CAkB7B"}
@@ -0,0 +1,22 @@
1
+ //#region src/shared/assistant/uiActions/uiCatalogue.ts
2
+ var e = 120, t = 8 * 1024, n = (e) => new TextEncoder().encode(JSON.stringify(e)).length;
3
+ function r(e, t) {
4
+ if (!t.permissionsSettled || t.simulating) return null;
5
+ let r = [];
6
+ for (let t of e.slice(0, 120)) r.push({
7
+ id: t.id,
8
+ label: t.label,
9
+ ...t.context ? { context: t.context } : {},
10
+ path: t.path
11
+ });
12
+ for (; r.length > 0 && n({
13
+ v: 1,
14
+ entries: r
15
+ }) > 8192;) r.pop();
16
+ return r.length > 0 ? {
17
+ v: 1,
18
+ entries: r
19
+ } : null;
20
+ }
21
+ //#endregion
22
+ export { t as UI_CATALOGUE_MAX_BYTES, e as UI_CATALOGUE_MAX_ENTRIES, r as buildUiCatalogue };
@@ -1,4 +1,5 @@
1
- import { assistantRoutePath as e, browserShouldHandle as t, classifyAssistantHref as n } from "../../assistant/ui/AssistantMarkdownRenderer.js";
1
+ import { assistantRoutePath as e, classifyAssistantHref as t } from "../../assistant/uiActions/assistantHref.js";
2
+ import { browserShouldHandle as n } from "../../assistant/ui/AssistantMarkdownRenderer.js";
2
3
  import { Fragment as r } from "react";
3
4
  import { Fragment as i, jsx as a } from "react/jsx-runtime";
4
5
  //#region src/shared/components/assistantWidget/MessageContent.tsx
@@ -11,12 +12,12 @@ var c = ({ content: c, onNavigate: l }) => {
11
12
  for (let i of c.matchAll(f)) {
12
13
  let [o, f, p] = i, m = i.index ?? 0;
13
14
  m > d && u.push(/* @__PURE__ */ a(r, { children: c.slice(d, m) }, `t${String(d)}`));
14
- let h = p ? n(p) : "blocked", g = h === "internal" ? e(p) : null, _ = h === "external" && s(p);
15
+ let h = p ? t(p) : "blocked", g = h === "internal" ? e(p) : null, _ = h === "external" && s(p);
15
16
  f && p && (g || _) ? u.push(/* @__PURE__ */ a("a", {
16
17
  href: g ?? p,
17
18
  "data-testid": "assistant-message-link",
18
19
  ...g ? { onClick: l ? (e) => {
19
- t(e) || (e.preventDefault(), l(g));
20
+ n(e) || (e.preventDefault(), l(g));
20
21
  } : void 0 } : {
21
22
  target: "_blank",
22
23
  rel: "noopener noreferrer"