@helpai/elements 0.21.0 → 0.22.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.
- package/configurator.mjs +85 -72
- package/elements-web-component.esm.js +25 -25
- package/elements-web-component.esm.js.map +3 -3
- package/elements.cjs.js +27 -27
- package/elements.cjs.js.map +4 -4
- package/elements.esm.js +27 -27
- package/elements.esm.js.map +4 -4
- package/elements.js +24 -24
- package/elements.js.map +4 -4
- package/index.d.ts +45 -1
- package/index.mjs +143 -4
- package/package.json +1 -1
- package/schema.d.ts +66 -50
- package/schema.json +64 -0
- package/schema.mjs +90 -75
- package/web-component.mjs +25 -4
package/schema.json
CHANGED
|
@@ -1839,6 +1839,38 @@
|
|
|
1839
1839
|
]
|
|
1840
1840
|
]
|
|
1841
1841
|
},
|
|
1842
|
+
"tracking": {
|
|
1843
|
+
"type": "object",
|
|
1844
|
+
"properties": {
|
|
1845
|
+
"enabled": {
|
|
1846
|
+
"description": "Master switch. Default `false` — no hits are sent until the deployment turns tracking on.",
|
|
1847
|
+
"type": "boolean"
|
|
1848
|
+
},
|
|
1849
|
+
"endpoint": {
|
|
1850
|
+
"description": "Pixel collector URL. Default: `https://t.<brand domain>/api/ai-elements/px.gif`. Must be a full URL.",
|
|
1851
|
+
"type": "string",
|
|
1852
|
+
"maxLength": 2048,
|
|
1853
|
+
"format": "uri"
|
|
1854
|
+
},
|
|
1855
|
+
"sampleRate": {
|
|
1856
|
+
"description": "Per-visitor sampling 0..1 (decided once per page load, keeping funnels intact). Default `1`.",
|
|
1857
|
+
"type": "number",
|
|
1858
|
+
"minimum": 0,
|
|
1859
|
+
"maximum": 1
|
|
1860
|
+
}
|
|
1861
|
+
},
|
|
1862
|
+
"additionalProperties": {},
|
|
1863
|
+
"description": "Anonymous usage tracking for the widget owner — GA-style pixel events (open, send, form submit, …) with page / device / locale dimensions. Never includes message content; visitors are identified only by the widget's anonymous visitorId.",
|
|
1864
|
+
"examples": [
|
|
1865
|
+
{
|
|
1866
|
+
"enabled": true
|
|
1867
|
+
},
|
|
1868
|
+
{
|
|
1869
|
+
"enabled": true,
|
|
1870
|
+
"sampleRate": 0.5
|
|
1871
|
+
}
|
|
1872
|
+
]
|
|
1873
|
+
},
|
|
1842
1874
|
"site": {
|
|
1843
1875
|
"description": "Site config — applies in `mode: \"page\"`. Comes from the start-conversation response, not user-edited."
|
|
1844
1876
|
},
|
|
@@ -3556,6 +3588,38 @@
|
|
|
3556
3588
|
}
|
|
3557
3589
|
]
|
|
3558
3590
|
]
|
|
3591
|
+
},
|
|
3592
|
+
"tracking": {
|
|
3593
|
+
"type": "object",
|
|
3594
|
+
"properties": {
|
|
3595
|
+
"enabled": {
|
|
3596
|
+
"description": "Master switch. Default `false` — no hits are sent until the deployment turns tracking on.",
|
|
3597
|
+
"type": "boolean"
|
|
3598
|
+
},
|
|
3599
|
+
"endpoint": {
|
|
3600
|
+
"description": "Pixel collector URL. Default: `https://t.<brand domain>/api/ai-elements/px.gif`. Must be a full URL.",
|
|
3601
|
+
"type": "string",
|
|
3602
|
+
"maxLength": 2048,
|
|
3603
|
+
"format": "uri"
|
|
3604
|
+
},
|
|
3605
|
+
"sampleRate": {
|
|
3606
|
+
"description": "Per-visitor sampling 0..1 (decided once per page load, keeping funnels intact). Default `1`.",
|
|
3607
|
+
"type": "number",
|
|
3608
|
+
"minimum": 0,
|
|
3609
|
+
"maximum": 1
|
|
3610
|
+
}
|
|
3611
|
+
},
|
|
3612
|
+
"additionalProperties": {},
|
|
3613
|
+
"description": "Anonymous usage tracking for the widget owner — GA-style pixel events (open, send, form submit, …) with page / device / locale dimensions. Never includes message content; visitors are identified only by the widget's anonymous visitorId.",
|
|
3614
|
+
"examples": [
|
|
3615
|
+
{
|
|
3616
|
+
"enabled": true
|
|
3617
|
+
},
|
|
3618
|
+
{
|
|
3619
|
+
"enabled": true,
|
|
3620
|
+
"sampleRate": 0.5
|
|
3621
|
+
}
|
|
3622
|
+
]
|
|
3559
3623
|
}
|
|
3560
3624
|
},
|
|
3561
3625
|
"additionalProperties": {}
|
package/schema.mjs
CHANGED
|
@@ -17,7 +17,7 @@ var localeSchema = z.string().min(1).max(35).describe("BCP-47 locale tag (e.g. `
|
|
|
17
17
|
var uuid7Schema = z.uuidv7().describe("UUID v7 (RFC 9562) \u2014 the single id format for visitor / conversation / message / file / content ids.");
|
|
18
18
|
|
|
19
19
|
// src/schema/widget.ts
|
|
20
|
-
import { z as
|
|
20
|
+
import { z as z16 } from "zod";
|
|
21
21
|
|
|
22
22
|
// src/schema/widget/presentation.ts
|
|
23
23
|
import { z as z3 } from "zod";
|
|
@@ -560,11 +560,23 @@ var modulesSchema = z14.array(moduleSchema).max(4).describe(
|
|
|
560
560
|
]
|
|
561
561
|
});
|
|
562
562
|
|
|
563
|
+
// src/schema/widget/tracking.ts
|
|
564
|
+
import { z as z15 } from "zod";
|
|
565
|
+
var trackingSchema = z15.object({
|
|
566
|
+
enabled: z15.boolean().optional().describe("Master switch. Default `false` \u2014 no hits are sent until the deployment turns tracking on."),
|
|
567
|
+
endpoint: z15.url().max(2048).optional().describe("Pixel collector URL. Default: `https://t.<brand domain>/api/ai-elements/px.gif`. Must be a full URL."),
|
|
568
|
+
sampleRate: z15.number().min(0).max(1).optional().describe("Per-visitor sampling 0..1 (decided once per page load, keeping funnels intact). Default `1`.")
|
|
569
|
+
}).loose().describe(
|
|
570
|
+
"Anonymous usage tracking for the widget owner \u2014 GA-style pixel events (open, send, form submit, \u2026) with page / device / locale dimensions. Never includes message content; visitors are identified only by the widget's anonymous visitorId."
|
|
571
|
+
).meta({
|
|
572
|
+
examples: [{ enabled: true }, { enabled: true, sampleRate: 0.5 }]
|
|
573
|
+
});
|
|
574
|
+
|
|
563
575
|
// src/schema/widget.ts
|
|
564
|
-
var endpointsSchema =
|
|
565
|
-
upload:
|
|
566
|
-
transcribe:
|
|
567
|
-
submitForm:
|
|
576
|
+
var endpointsSchema = z16.object({
|
|
577
|
+
upload: z16.string().min(1).max(2048).default("/ai/agent/upload-file"),
|
|
578
|
+
transcribe: z16.string().min(1).max(2048).default("/ai/agent/transcribe-audio"),
|
|
579
|
+
submitForm: z16.string().min(1).max(2048).default("/ai/agent/submit-form").describe(
|
|
568
580
|
"Form submission endpoint. The widget POSTs each completed form's values here (fire-and-forget), keyed by the same visitorId + conversationId as the conversation; the payload carries `formId` + `trigger` so the backend can route. Optional \u2014 a 404 is ignored."
|
|
569
581
|
)
|
|
570
582
|
}).loose().describe("HTTP endpoint overrides. Paths are appended to baseUrl; absolute URLs are accepted too.").meta({
|
|
@@ -574,14 +586,14 @@ var endpointsSchema = z15.object({
|
|
|
574
586
|
{ submitForm: "https://crm.acme.com/leads" }
|
|
575
587
|
]
|
|
576
588
|
});
|
|
577
|
-
var userContextSchema =
|
|
578
|
-
id:
|
|
579
|
-
email:
|
|
580
|
-
name:
|
|
581
|
-
plan:
|
|
582
|
-
role:
|
|
583
|
-
phone:
|
|
584
|
-
}).catchall(
|
|
589
|
+
var userContextSchema = z16.object({
|
|
590
|
+
id: z16.string().min(1).max(200).optional().describe("Host's stable id for the user \u2014 informational context the agent/backend can key on (not auth)."),
|
|
591
|
+
email: z16.string().min(1).max(320).optional().describe("User email \u2014 surfaced to the agent for context (optional)."),
|
|
592
|
+
name: z16.string().min(1).max(200).optional().describe("Display name \u2014 shown in the Home greeting (`{name}`) and conversation transcripts (optional)."),
|
|
593
|
+
plan: z16.string().min(1).max(120).optional().describe("Subscription / pricing tier, e.g. `pro` (optional)."),
|
|
594
|
+
role: z16.string().min(1).max(120).optional().describe("The user's role on the host site, e.g. `admin` (optional)."),
|
|
595
|
+
phone: z16.string().min(1).max(40).optional().describe("Phone number (optional).")
|
|
596
|
+
}).catchall(z16.union([z16.string(), z16.number(), z16.boolean()])).describe(
|
|
585
597
|
"Host-asserted end-user context (informational, untrusted \u2014 not authentication). Recognised `id` / `email` / `name` / `plan` / `role` / `phone` plus any extra custom scalar fields forwarded to the agent."
|
|
586
598
|
).meta({
|
|
587
599
|
examples: [{ id: "u_123" }, { id: "u_123", email: "alex@acme.com", name: "Alex Lee", plan: "pro" }]
|
|
@@ -597,31 +609,31 @@ var PAGE_AREA_SUGGESTIONS = [
|
|
|
597
609
|
"account",
|
|
598
610
|
"blog"
|
|
599
611
|
];
|
|
600
|
-
var pageContextSchema =
|
|
601
|
-
area:
|
|
602
|
-
url:
|
|
603
|
-
path:
|
|
604
|
-
title:
|
|
605
|
-
}).catchall(
|
|
612
|
+
var pageContextSchema = z16.object({
|
|
613
|
+
area: z16.string().min(1).max(64).optional().describe(`Host-defined surface the visitor is on. Free-form; suggested: ${PAGE_AREA_SUGGESTIONS.join(" | ")}.`),
|
|
614
|
+
url: z16.string().min(1).max(2048).optional().describe("Full page URL. Auto-filled from the host page when omitted."),
|
|
615
|
+
path: z16.string().min(1).max(2048).optional().describe("Page path, e.g. `/pricing/enterprise`."),
|
|
616
|
+
title: z16.string().min(1).max(300).optional().describe("Human-readable page title.")
|
|
617
|
+
}).catchall(z16.union([z16.string(), z16.number(), z16.boolean()])).describe(
|
|
606
618
|
"Host-asserted page/visit context (informational, untrusted). Where the visitor is + the surface (`area`) they're using, plus any custom scalar fields, forwarded to the agent."
|
|
607
619
|
).meta({ examples: [{ area: "pricing", path: "/pricing" }, { area: "help-desk" }] });
|
|
608
|
-
var connectionConfigSchema =
|
|
609
|
-
widgetId:
|
|
620
|
+
var connectionConfigSchema = z16.object({
|
|
621
|
+
widgetId: z16.string().min(1).max(80).default("default").describe(
|
|
610
622
|
"Stable per-instance id used to namespace localStorage keys. Set this when mounting more than one widget on the same page so their conversation state doesn't collide."
|
|
611
623
|
),
|
|
612
|
-
publicKey:
|
|
624
|
+
publicKey: z16.string().min(1).max(200).optional().describe(
|
|
613
625
|
"Workspace-scoped public key (`agent_pk_\u2026`) issued from the dashboard. Sent on every API call as the `x-public-key` header."
|
|
614
626
|
),
|
|
615
|
-
aiAgentDeploymentId:
|
|
627
|
+
aiAgentDeploymentId: z16.string().min(1).max(200).optional().describe(
|
|
616
628
|
"Deployment UUID from the dashboard. Picks which agent / settings bundle answers this mount. Sent as `x-ai-agent-deployment-id`."
|
|
617
629
|
),
|
|
618
|
-
baseUrl:
|
|
630
|
+
baseUrl: z16.string().min(1).max(2048).optional().describe(
|
|
619
631
|
"Full backend origin (e.g. `https://help.ai/api`). Set this to point at your staging / self-hosted / custom backend. Default: the brand's `defaultBaseUrl` baked at build time."
|
|
620
632
|
),
|
|
621
633
|
userContext: userContextSchema.optional(),
|
|
622
634
|
pageContext: pageContextSchema.optional(),
|
|
623
635
|
endpoints: endpointsSchema.optional(),
|
|
624
|
-
debug:
|
|
636
|
+
debug: z16.union([z16.boolean(), z16.enum(["off", "error", "warn", "info", "debug", "trace"])]).optional().describe(
|
|
625
637
|
'Console log verbosity. `false` / `"off"` silences everything (default in production). `true` \u2192 `"debug"`. Levels `error` / `warn` / `info` / `debug` / `trace` gate output additively. Use `"trace"` to capture per-chunk SSE frames + every state transition. Also toggleable at runtime via `chat.setDebug(level)` or `?<brand>-debug=trace` in the page URL \u2014 the URL beats this option, this option beats the persisted `localStorage` value.'
|
|
626
638
|
)
|
|
627
639
|
}).loose().describe(
|
|
@@ -641,7 +653,7 @@ var connectionConfigSchema = z15.object({
|
|
|
641
653
|
}
|
|
642
654
|
]
|
|
643
655
|
});
|
|
644
|
-
var widgetSettingsSchema =
|
|
656
|
+
var widgetSettingsSchema = z16.object({
|
|
645
657
|
presentation: presentationSchema.optional(),
|
|
646
658
|
behavior: behaviorSchema.optional(),
|
|
647
659
|
theme: themeFieldSchema.default("auto").describe("Theme preference (`auto` follows OS) or a tokens override object (`accent`, `radius`, `fontFamily`)."),
|
|
@@ -653,9 +665,10 @@ var widgetSettingsSchema = z15.object({
|
|
|
653
665
|
footer: footerSchema.optional(),
|
|
654
666
|
features: featureFlagsSchema.optional(),
|
|
655
667
|
forms: formsSchema.optional(),
|
|
656
|
-
modules: modulesSchema.optional()
|
|
668
|
+
modules: modulesSchema.optional(),
|
|
669
|
+
tracking: trackingSchema.optional()
|
|
657
670
|
}).loose().describe(
|
|
658
|
-
"Portal-configurable widget settings \u2014
|
|
671
|
+
"Portal-configurable widget settings \u2014 fourteen sections, one per dashboard tab. The backend pushes this same shape on `/ai/agent/start-conversation` under `config`."
|
|
659
672
|
).meta({
|
|
660
673
|
examples: [
|
|
661
674
|
{ presentation: { mode: "floating", position: "bottom-right" }, theme: "auto" },
|
|
@@ -673,10 +686,10 @@ var widgetSettingsSchema = z15.object({
|
|
|
673
686
|
});
|
|
674
687
|
var widgetConfigSchema = connectionConfigSchema.extend({
|
|
675
688
|
...widgetSettingsSchema.shape,
|
|
676
|
-
site:
|
|
689
|
+
site: z16.unknown().optional().describe(
|
|
677
690
|
'Site config \u2014 applies in `mode: "page"`. Comes from the start-conversation response, not user-edited.'
|
|
678
691
|
),
|
|
679
|
-
blocks:
|
|
692
|
+
blocks: z16.unknown().optional().describe('Blocks (nav + link cards) \u2014 applies in `mode: "page"`. Comes from the start-conversation response.')
|
|
680
693
|
}).describe(
|
|
681
694
|
"Full client widget config \u2014 connection (where + auth) + widget settings (look + behaviour) + page-mode extras. This is what the runtime parses on `mount()` / `init()`. Mode-specific constraints (e.g. `position` only meaningful in `floating`) are NOT enforced here \u2014 the runtime silently ignores irrelevant fields rather than rejecting them so the same object can flow across mode changes."
|
|
682
695
|
).meta({
|
|
@@ -699,49 +712,49 @@ var widgetSettingsPartialSchema = widgetSettingsSchema.partial();
|
|
|
699
712
|
var connectionConfigPartialSchema = connectionConfigSchema.partial();
|
|
700
713
|
|
|
701
714
|
// src/schema/deployment.ts
|
|
702
|
-
import { z as
|
|
715
|
+
import { z as z17 } from "zod";
|
|
703
716
|
var serverConfigSchema = widgetSettingsSchema.partial();
|
|
704
|
-
var siteConfigSchema =
|
|
705
|
-
title:
|
|
717
|
+
var siteConfigSchema = z17.object({
|
|
718
|
+
title: z17.string().min(1).max(120).optional().describe("Brand / site name. Used as the logo's alt-text fallback."),
|
|
706
719
|
logo: assetSchema.optional().describe("Brand logo shown at the top of the page-mode sidebar."),
|
|
707
720
|
logoDark: assetSchema.optional().describe(
|
|
708
721
|
"Optional dark-theme logo variant. Falls back to `logo` when the active theme is light or `logoDark` is unset."
|
|
709
722
|
)
|
|
710
723
|
}).loose();
|
|
711
|
-
var blocksConfigSchema =
|
|
712
|
-
navigation:
|
|
713
|
-
linkCards:
|
|
724
|
+
var blocksConfigSchema = z17.object({
|
|
725
|
+
navigation: z17.array(linkSchema).max(100).optional().describe("Sidebar navigation links (vertical list, primary nav)."),
|
|
726
|
+
linkCards: z17.array(linkSchema).max(100).optional().describe("Sidebar link cards (richer entries with optional `description`).")
|
|
714
727
|
}).loose();
|
|
715
|
-
var handshakeWelcomeMessageSchema =
|
|
716
|
-
id:
|
|
717
|
-
role:
|
|
718
|
-
text:
|
|
728
|
+
var handshakeWelcomeMessageSchema = z17.object({
|
|
729
|
+
id: z17.string(),
|
|
730
|
+
role: z17.enum(["assistant", "system"]),
|
|
731
|
+
text: z17.string()
|
|
719
732
|
}).loose();
|
|
720
|
-
var handshakeWelcomeSuggestionSchema =
|
|
721
|
-
id:
|
|
722
|
-
label:
|
|
723
|
-
text:
|
|
733
|
+
var handshakeWelcomeSuggestionSchema = z17.object({
|
|
734
|
+
id: z17.string(),
|
|
735
|
+
label: z17.string(),
|
|
736
|
+
text: z17.string().optional()
|
|
724
737
|
}).loose();
|
|
725
|
-
var rebindReasonSchema =
|
|
726
|
-
var startConversationResponseSchema =
|
|
727
|
-
deployment:
|
|
728
|
-
id:
|
|
729
|
-
name:
|
|
738
|
+
var rebindReasonSchema = z17.enum(["conflict", "expired", "invalid"]);
|
|
739
|
+
var startConversationResponseSchema = z17.object({
|
|
740
|
+
deployment: z17.object({
|
|
741
|
+
id: z17.string(),
|
|
742
|
+
name: z17.string(),
|
|
730
743
|
// Page URL identifier — present on every deployment; unique per host.
|
|
731
744
|
// Used to mount page deployments via `?slug=…`.
|
|
732
|
-
slug:
|
|
733
|
-
publicKey:
|
|
745
|
+
slug: z17.string().optional(),
|
|
746
|
+
publicKey: z17.string().optional()
|
|
734
747
|
// Deliberately no `type` / `channel` here. Deployment-level
|
|
735
748
|
// taxonomy is a backend categorization concern — the widget's
|
|
736
749
|
// rendering choice flows from `widget.presentation.mode`, not
|
|
737
750
|
// the deployment record's category. `.loose()` lets any such
|
|
738
751
|
// backend field pass through without typing.
|
|
739
752
|
}).loose(),
|
|
740
|
-
agent:
|
|
741
|
-
id:
|
|
742
|
-
name:
|
|
743
|
-
title:
|
|
744
|
-
status:
|
|
753
|
+
agent: z17.object({
|
|
754
|
+
id: z17.string(),
|
|
755
|
+
name: z17.string(),
|
|
756
|
+
title: z17.string().optional(),
|
|
757
|
+
status: z17.enum(["online", "away", "offline"]).optional()
|
|
745
758
|
}).loose(),
|
|
746
759
|
/**
|
|
747
760
|
* Deployment-wide widget configuration the dashboard admin saved
|
|
@@ -751,26 +764,26 @@ var startConversationResponseSchema = z16.object({
|
|
|
751
764
|
config: serverConfigSchema.optional(),
|
|
752
765
|
site: siteConfigSchema.optional(),
|
|
753
766
|
blocks: blocksConfigSchema.optional(),
|
|
754
|
-
welcome:
|
|
755
|
-
messages:
|
|
756
|
-
suggestions:
|
|
767
|
+
welcome: z17.object({
|
|
768
|
+
messages: z17.array(handshakeWelcomeMessageSchema).optional(),
|
|
769
|
+
suggestions: z17.array(handshakeWelcomeSuggestionSchema).optional()
|
|
757
770
|
}).loose().optional(),
|
|
758
|
-
visitorId:
|
|
759
|
-
conversationId:
|
|
760
|
-
canContinue:
|
|
761
|
-
messages:
|
|
771
|
+
visitorId: z17.string(),
|
|
772
|
+
conversationId: z17.string(),
|
|
773
|
+
canContinue: z17.boolean(),
|
|
774
|
+
messages: z17.array(z17.unknown()),
|
|
762
775
|
/**
|
|
763
776
|
* Form submissions recorded for this conversation — echoed like
|
|
764
777
|
* `messages` so the widget reconstructs the collapsed "form submitted"
|
|
765
778
|
* timeline markers on resume. `createdAt` is ISO-8601 (a serialized
|
|
766
779
|
* Mongo ISODate — same format as message `createdAt`).
|
|
767
780
|
*/
|
|
768
|
-
formSubmissions:
|
|
769
|
-
|
|
770
|
-
formId:
|
|
771
|
-
trigger:
|
|
772
|
-
skipped:
|
|
773
|
-
createdAt:
|
|
781
|
+
formSubmissions: z17.array(
|
|
782
|
+
z17.object({
|
|
783
|
+
formId: z17.string(),
|
|
784
|
+
trigger: z17.string(),
|
|
785
|
+
skipped: z17.boolean().optional(),
|
|
786
|
+
createdAt: z17.iso.datetime().optional()
|
|
774
787
|
}).loose()
|
|
775
788
|
).optional(),
|
|
776
789
|
/**
|
|
@@ -779,11 +792,11 @@ var startConversationResponseSchema = z16.object({
|
|
|
779
792
|
* what THIS visitor toggled inside the widget, not the
|
|
780
793
|
* deployment's admin-set defaults.
|
|
781
794
|
*/
|
|
782
|
-
userPrefs:
|
|
795
|
+
userPrefs: z17.record(z17.string(), z17.unknown()).optional(),
|
|
783
796
|
// Present only when the server rotated the request `visitorId` /
|
|
784
797
|
// `conversationId`. Purely advisory — client must adopt the response ids
|
|
785
798
|
// verbatim regardless of whether this block is present.
|
|
786
|
-
rebind:
|
|
799
|
+
rebind: z17.object({
|
|
787
800
|
visitorId: rebindReasonSchema.optional(),
|
|
788
801
|
conversationId: rebindReasonSchema.optional()
|
|
789
802
|
}).loose().optional()
|
|
@@ -798,7 +811,8 @@ var COMMON_SECTIONS = [
|
|
|
798
811
|
"footer",
|
|
799
812
|
"i18n",
|
|
800
813
|
"features",
|
|
801
|
-
"feedback"
|
|
814
|
+
"feedback",
|
|
815
|
+
"tracking"
|
|
802
816
|
];
|
|
803
817
|
var MODE_EXTRAS = {
|
|
804
818
|
floating: ["presentation", "behavior", "modules", "launcher"],
|
|
@@ -819,15 +833,15 @@ function widgetSettingsSchemaForMode(mode) {
|
|
|
819
833
|
var ALL_MODES = ["floating", "inline", "standalone", "page", "modal", "drawer"];
|
|
820
834
|
|
|
821
835
|
// src/schema/json-schema.ts
|
|
822
|
-
import { z as
|
|
836
|
+
import { z as z19 } from "zod";
|
|
823
837
|
function emitJsonSchema() {
|
|
824
838
|
return {
|
|
825
839
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
826
840
|
title: "@helpai/elements config",
|
|
827
841
|
description: "Canonical config schemas for the embeddable AI agent elements widget.",
|
|
828
842
|
definitions: {
|
|
829
|
-
WidgetConfig:
|
|
830
|
-
StartConversationResponse:
|
|
843
|
+
WidgetConfig: z19.toJSONSchema(widgetConfigSchema),
|
|
844
|
+
StartConversationResponse: z19.toJSONSchema(startConversationResponseSchema)
|
|
831
845
|
}
|
|
832
846
|
};
|
|
833
847
|
}
|
|
@@ -895,6 +909,7 @@ export {
|
|
|
895
909
|
themeOverridesSchema,
|
|
896
910
|
themePreferenceSchema,
|
|
897
911
|
toolRefSchema,
|
|
912
|
+
trackingSchema,
|
|
898
913
|
userContextSchema,
|
|
899
914
|
uuid7Schema,
|
|
900
915
|
voiceModeSchema,
|
package/web-component.mjs
CHANGED
|
@@ -453,6 +453,11 @@ var DEFAULT_FEATURES = {
|
|
|
453
453
|
humanInLoop: true
|
|
454
454
|
};
|
|
455
455
|
var DEFAULT_FORMS = { list: [], byTrigger: {} };
|
|
456
|
+
var DEFAULT_TRACKING = {
|
|
457
|
+
enabled: false,
|
|
458
|
+
endpoint: `https://t.${BRAND.domain}/api/ai-elements/px.gif`,
|
|
459
|
+
sampleRate: 1
|
|
460
|
+
};
|
|
456
461
|
var DEFAULT_ENDPOINTS = {
|
|
457
462
|
upload: "/ai/agent/upload-file",
|
|
458
463
|
transcribe: "/ai/agent/transcribe-audio",
|
|
@@ -547,6 +552,7 @@ function resolveOptions(rawOpts) {
|
|
|
547
552
|
poweredBy: resolvePoweredBy(footer.poweredBy),
|
|
548
553
|
composer: resolveComposer(opts.composer),
|
|
549
554
|
modules: resolveModules(opts.modules),
|
|
555
|
+
tracking: resolveTracking(opts.tracking),
|
|
550
556
|
storage: opts.storage ?? defaultStorage,
|
|
551
557
|
onMessage: opts.onMessage,
|
|
552
558
|
onOpen: opts.onOpen,
|
|
@@ -579,6 +585,16 @@ function resolveHaptics(overrides) {
|
|
|
579
585
|
events: overrides?.events
|
|
580
586
|
};
|
|
581
587
|
}
|
|
588
|
+
function resolveTracking(overrides) {
|
|
589
|
+
const sampleRate = overrides?.sampleRate ?? DEFAULT_TRACKING.sampleRate;
|
|
590
|
+
return {
|
|
591
|
+
enabled: overrides?.enabled ?? DEFAULT_TRACKING.enabled,
|
|
592
|
+
endpoint: overrides?.endpoint ?? DEFAULT_TRACKING.endpoint,
|
|
593
|
+
// Clamp instead of reject — a malformed rate must never turn a
|
|
594
|
+
// disabled tracker on or crash resolve (no Zod on the IIFE path).
|
|
595
|
+
sampleRate: Math.min(1, Math.max(0, Number.isFinite(sampleRate) ? sampleRate : 1))
|
|
596
|
+
};
|
|
597
|
+
}
|
|
582
598
|
function resolvePoweredBy(overrides) {
|
|
583
599
|
const brandDefault = {
|
|
584
600
|
text: `Powered by ${BRAND.displayName}`,
|
|
@@ -721,6 +737,7 @@ var SECTION_KEYS = [
|
|
|
721
737
|
"i18n",
|
|
722
738
|
"footer",
|
|
723
739
|
"features",
|
|
740
|
+
"tracking",
|
|
724
741
|
"endpoints"
|
|
725
742
|
];
|
|
726
743
|
function mergeServerConfig(user, server) {
|
|
@@ -4805,6 +4822,7 @@ function LoadingSpinner({ label }) {
|
|
|
4805
4822
|
import { jsx as jsx17, jsxs as jsxs14 } from "preact/jsx-runtime";
|
|
4806
4823
|
var p15 = BRAND.cssPrefix;
|
|
4807
4824
|
var STICK_THRESHOLD = 120;
|
|
4825
|
+
var INTERACTION_GRACE_MS = 350;
|
|
4808
4826
|
var DIVIDER_IDLE_MS = 1200;
|
|
4809
4827
|
function MessageList({
|
|
4810
4828
|
messagesSig,
|
|
@@ -4825,6 +4843,8 @@ function MessageList({
|
|
|
4825
4843
|
const hasHydratedRef = useRef5(false);
|
|
4826
4844
|
const detachedRef = useRef5(false);
|
|
4827
4845
|
const interactingRef = useRef5(false);
|
|
4846
|
+
const interactionEndedAtRef = useRef5(0);
|
|
4847
|
+
const inInteractionGrace = () => interactingRef.current || performance.now() - interactionEndedAtRef.current < INTERACTION_GRACE_MS;
|
|
4828
4848
|
const autoPinAtRef = useRef5(0);
|
|
4829
4849
|
const pinBottom = (el) => {
|
|
4830
4850
|
autoPinAtRef.current = performance.now();
|
|
@@ -4865,7 +4885,7 @@ function MessageList({
|
|
|
4865
4885
|
pinBottom(el);
|
|
4866
4886
|
return;
|
|
4867
4887
|
}
|
|
4868
|
-
if (detachedRef.current ||
|
|
4888
|
+
if (detachedRef.current || inInteractionGrace()) return;
|
|
4869
4889
|
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
4870
4890
|
if (distanceFromBottom < STICK_THRESHOLD) pinBottom(el);
|
|
4871
4891
|
}, [messages.value.length]);
|
|
@@ -4875,7 +4895,7 @@ function MessageList({
|
|
|
4875
4895
|
const last = messages.value.at(-1);
|
|
4876
4896
|
if (!last) return;
|
|
4877
4897
|
const pinIfNear = () => {
|
|
4878
|
-
if (detachedRef.current ||
|
|
4898
|
+
if (detachedRef.current || inInteractionGrace()) return;
|
|
4879
4899
|
const distance = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
4880
4900
|
if (distance < STICK_THRESHOLD * 2) pinBottom(el);
|
|
4881
4901
|
};
|
|
@@ -4925,6 +4945,7 @@ function MessageList({
|
|
|
4925
4945
|
};
|
|
4926
4946
|
const endInteraction = () => {
|
|
4927
4947
|
interactingRef.current = false;
|
|
4948
|
+
interactionEndedAtRef.current = performance.now();
|
|
4928
4949
|
};
|
|
4929
4950
|
const onPointerDown = () => {
|
|
4930
4951
|
interactingRef.current = true;
|
|
@@ -5631,10 +5652,10 @@ function createHomeNav(initialTab, tabs, onSwitch) {
|
|
|
5631
5652
|
sig.value = { ...sig.value, activeTab: tab };
|
|
5632
5653
|
onSwitch?.(tab);
|
|
5633
5654
|
},
|
|
5634
|
-
push(
|
|
5655
|
+
push(screen2) {
|
|
5635
5656
|
const s = sig.value;
|
|
5636
5657
|
const stack = s.stacks[s.activeTab] ?? [];
|
|
5637
|
-
sig.value = { ...s, stacks: { ...s.stacks, [s.activeTab]: [...stack,
|
|
5658
|
+
sig.value = { ...s, stacks: { ...s.stacks, [s.activeTab]: [...stack, screen2] } };
|
|
5638
5659
|
},
|
|
5639
5660
|
pop() {
|
|
5640
5661
|
const s = sig.value;
|