@modelnex/sdk 0.5.25 → 0.5.27
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/dist/index.d.mts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +123 -32
- package/dist/index.mjs +123 -32
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -133,7 +133,7 @@ interface TourStep {
|
|
|
133
133
|
/** Optional onboarding-specific step metadata */
|
|
134
134
|
onboarding?: OnboardingStepMetadata;
|
|
135
135
|
}
|
|
136
|
-
type TourTrigger = 'first_visit' | 'feature_launch' | 'feature_unlocked' | 'feature_unlock' | 'new_feature' | 'manual';
|
|
136
|
+
type TourTrigger = 'first_visit' | 'return_visit' | 'feature_launch' | 'feature_unlocked' | 'feature_unlock' | 'new_feature' | 'manual';
|
|
137
137
|
type TourStartPolicy = 'immediate_start' | 'prompt_only' | 'manual_only';
|
|
138
138
|
type TourNotificationType = 'bubble_card' | 'modal';
|
|
139
139
|
interface TourVoiceConfig {
|
|
@@ -200,6 +200,12 @@ interface UserProfile {
|
|
|
200
200
|
type: string;
|
|
201
201
|
/** Whether this is a new user — triggers first_visit tours */
|
|
202
202
|
isNewUser?: boolean;
|
|
203
|
+
/** Optional feature facts used for feature-triggered tours */
|
|
204
|
+
features?: string[];
|
|
205
|
+
/** Backward-compatible facts bag for feature-triggered tours */
|
|
206
|
+
tourFacts?: {
|
|
207
|
+
features?: string[];
|
|
208
|
+
};
|
|
203
209
|
/** User ID for per-user completion state */
|
|
204
210
|
userId?: string;
|
|
205
211
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -133,7 +133,7 @@ interface TourStep {
|
|
|
133
133
|
/** Optional onboarding-specific step metadata */
|
|
134
134
|
onboarding?: OnboardingStepMetadata;
|
|
135
135
|
}
|
|
136
|
-
type TourTrigger = 'first_visit' | 'feature_launch' | 'feature_unlocked' | 'feature_unlock' | 'new_feature' | 'manual';
|
|
136
|
+
type TourTrigger = 'first_visit' | 'return_visit' | 'feature_launch' | 'feature_unlocked' | 'feature_unlock' | 'new_feature' | 'manual';
|
|
137
137
|
type TourStartPolicy = 'immediate_start' | 'prompt_only' | 'manual_only';
|
|
138
138
|
type TourNotificationType = 'bubble_card' | 'modal';
|
|
139
139
|
interface TourVoiceConfig {
|
|
@@ -200,6 +200,12 @@ interface UserProfile {
|
|
|
200
200
|
type: string;
|
|
201
201
|
/** Whether this is a new user — triggers first_visit tours */
|
|
202
202
|
isNewUser?: boolean;
|
|
203
|
+
/** Optional feature facts used for feature-triggered tours */
|
|
204
|
+
features?: string[];
|
|
205
|
+
/** Backward-compatible facts bag for feature-triggered tours */
|
|
206
|
+
tourFacts?: {
|
|
207
|
+
features?: string[];
|
|
208
|
+
};
|
|
203
209
|
/** User ID for per-user completion state */
|
|
204
210
|
userId?: string;
|
|
205
211
|
}
|
package/dist/index.js
CHANGED
|
@@ -2667,6 +2667,9 @@ function normalizeTrigger(trigger) {
|
|
|
2667
2667
|
if (trigger === "feature_launch" || trigger === "feature_unlocked" || trigger === "feature_unlock" || trigger === "new_feature") {
|
|
2668
2668
|
return "feature_launch";
|
|
2669
2669
|
}
|
|
2670
|
+
if (trigger === "return_visit") {
|
|
2671
|
+
return "return_visit";
|
|
2672
|
+
}
|
|
2670
2673
|
return trigger ?? "first_visit";
|
|
2671
2674
|
}
|
|
2672
2675
|
function getStartPolicy(tour) {
|
|
@@ -2675,10 +2678,22 @@ function getStartPolicy(tour) {
|
|
|
2675
2678
|
function getNotificationType(tour) {
|
|
2676
2679
|
return tour.notificationType ?? "bubble_card";
|
|
2677
2680
|
}
|
|
2681
|
+
function getUserProfileFeatures(userProfile) {
|
|
2682
|
+
const directFeatures = Array.isArray(userProfile.features) ? userProfile.features : [];
|
|
2683
|
+
const nestedFeatures = Array.isArray(userProfile.tourFacts?.features) ? userProfile.tourFacts.features : [];
|
|
2684
|
+
return [...new Set([...directFeatures, ...nestedFeatures].filter((value) => Boolean(value)))];
|
|
2685
|
+
}
|
|
2678
2686
|
function isTourEligible(tour, userProfile) {
|
|
2679
2687
|
switch (normalizeTrigger(tour.trigger)) {
|
|
2680
2688
|
case "first_visit":
|
|
2681
2689
|
return !!userProfile.isNewUser;
|
|
2690
|
+
case "return_visit":
|
|
2691
|
+
return userProfile.isNewUser === false;
|
|
2692
|
+
case "feature_launch": {
|
|
2693
|
+
const featureKey = tour.featureKey?.trim();
|
|
2694
|
+
if (!featureKey) return false;
|
|
2695
|
+
return getUserProfileFeatures(userProfile).includes(featureKey);
|
|
2696
|
+
}
|
|
2682
2697
|
case "manual":
|
|
2683
2698
|
return false;
|
|
2684
2699
|
default:
|
|
@@ -8119,7 +8134,7 @@ function getRecordingDraftStatusMessage(phase, experienceType) {
|
|
|
8119
8134
|
|
|
8120
8135
|
// src/utils/tour-listening.ts
|
|
8121
8136
|
function canStartTourListening(state) {
|
|
8122
|
-
const hasLiveOrPendingPlayback = state.isTourActive || state.isOnboardingActive || state.hasPendingTour || state.hasPendingOnboarding;
|
|
8137
|
+
const hasLiveOrPendingPlayback = state.isTourActive || state.isOnboardingActive || state.hasPendingTour || state.hasPendingOnboarding || Boolean(state.startingExperienceType);
|
|
8123
8138
|
return hasLiveOrPendingPlayback && !state.sttActive && state.sttSupported;
|
|
8124
8139
|
}
|
|
8125
8140
|
function resolveTourListeningExperience(preferredExperience, state) {
|
|
@@ -8196,6 +8211,58 @@ function buildTranscriptPreviewLines(transcript, options = {}) {
|
|
|
8196
8211
|
return lines.slice(-maxLines);
|
|
8197
8212
|
}
|
|
8198
8213
|
|
|
8214
|
+
// src/utils/pendingPromptUi.ts
|
|
8215
|
+
function isPendingReviewPrompt(pendingPrompt) {
|
|
8216
|
+
return Boolean(pendingPrompt?.options?.reviewMode);
|
|
8217
|
+
}
|
|
8218
|
+
function shouldRenderPendingPromptInline({
|
|
8219
|
+
pendingPrompt,
|
|
8220
|
+
isPlaybackActive,
|
|
8221
|
+
recordingMode
|
|
8222
|
+
}) {
|
|
8223
|
+
return Boolean(
|
|
8224
|
+
pendingPrompt && !isPlaybackActive && !recordingMode && !isPendingReviewPrompt(pendingPrompt)
|
|
8225
|
+
);
|
|
8226
|
+
}
|
|
8227
|
+
function shouldRenderPendingPromptModal({
|
|
8228
|
+
pendingPrompt,
|
|
8229
|
+
isPlaybackActive,
|
|
8230
|
+
recordingMode,
|
|
8231
|
+
pendingNotificationType
|
|
8232
|
+
}) {
|
|
8233
|
+
return Boolean(
|
|
8234
|
+
pendingPrompt && !isPlaybackActive && !recordingMode && isPendingReviewPrompt(pendingPrompt) && pendingNotificationType === "modal"
|
|
8235
|
+
);
|
|
8236
|
+
}
|
|
8237
|
+
function shouldAutoExpandForPendingPrompt({
|
|
8238
|
+
pendingPrompt,
|
|
8239
|
+
isPlaybackActive,
|
|
8240
|
+
recordingMode,
|
|
8241
|
+
pendingNotificationType
|
|
8242
|
+
}) {
|
|
8243
|
+
if (!pendingPrompt || isPlaybackActive || recordingMode) return false;
|
|
8244
|
+
return pendingNotificationType === "bubble_card" || shouldRenderPendingPromptInline({
|
|
8245
|
+
pendingPrompt,
|
|
8246
|
+
isPlaybackActive,
|
|
8247
|
+
recordingMode
|
|
8248
|
+
});
|
|
8249
|
+
}
|
|
8250
|
+
function getPendingPromptTitle(pendingPrompt) {
|
|
8251
|
+
return `I found a ${pendingPrompt.experienceType === "onboarding" ? "workflow" : "tour"} called "${pendingPrompt.tour.name}". Would you like to start it now?`;
|
|
8252
|
+
}
|
|
8253
|
+
function getPendingPromptReason(pendingPrompt) {
|
|
8254
|
+
if (pendingPrompt.tour.trigger === "first_visit") {
|
|
8255
|
+
return "This was surfaced because the current user matches the configured first-visit trigger.";
|
|
8256
|
+
}
|
|
8257
|
+
if (pendingPrompt.tour.trigger === "return_visit") {
|
|
8258
|
+
return "This was surfaced because the current user matches the configured return-visit trigger.";
|
|
8259
|
+
}
|
|
8260
|
+
if (pendingPrompt.tour.featureKey) {
|
|
8261
|
+
return `This was surfaced because the "${pendingPrompt.tour.featureKey}" trigger condition matched.`;
|
|
8262
|
+
}
|
|
8263
|
+
return "This was surfaced because the configured trigger condition matched.";
|
|
8264
|
+
}
|
|
8265
|
+
|
|
8199
8266
|
// src/utils/floatingLiveTranscript.ts
|
|
8200
8267
|
var floatingTranscriptEl = null;
|
|
8201
8268
|
var liveTranscriptSuppressed = false;
|
|
@@ -8915,7 +8982,20 @@ function ModelNexChatBubble({
|
|
|
8915
8982
|
}
|
|
8916
8983
|
}, [devMode, handleAutoTag, ctx?.extractedElements.length, window.location.pathname]);
|
|
8917
8984
|
const onboardingReviewToggle = getReviewModeToggleConfig(onboardingPlayback.playbackState);
|
|
8985
|
+
const pendingPrompt = playbackController.pendingPrompt;
|
|
8918
8986
|
const pendingNotificationType = (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.notificationType ?? "bubble_card";
|
|
8987
|
+
const isPlaybackActive = tourPlayback.isActive || onboardingPlayback.isActive;
|
|
8988
|
+
const renderPendingPromptInline = shouldRenderPendingPromptInline({
|
|
8989
|
+
pendingPrompt,
|
|
8990
|
+
isPlaybackActive,
|
|
8991
|
+
recordingMode
|
|
8992
|
+
});
|
|
8993
|
+
const renderPendingPromptModal = shouldRenderPendingPromptModal({
|
|
8994
|
+
pendingPrompt,
|
|
8995
|
+
isPlaybackActive,
|
|
8996
|
+
recordingMode,
|
|
8997
|
+
pendingNotificationType
|
|
8998
|
+
});
|
|
8919
8999
|
(0, import_react18.useEffect)(() => {
|
|
8920
9000
|
setHydrated(true);
|
|
8921
9001
|
try {
|
|
@@ -8982,10 +9062,15 @@ function ModelNexChatBubble({
|
|
|
8982
9062
|
}
|
|
8983
9063
|
}, [tourPlayback.isActive, onboardingPlayback.isActive]);
|
|
8984
9064
|
(0, import_react18.useEffect)(() => {
|
|
8985
|
-
if ((
|
|
9065
|
+
if (shouldAutoExpandForPendingPrompt({
|
|
9066
|
+
pendingPrompt,
|
|
9067
|
+
isPlaybackActive,
|
|
9068
|
+
recordingMode,
|
|
9069
|
+
pendingNotificationType
|
|
9070
|
+
})) {
|
|
8986
9071
|
setExpandedState(true);
|
|
8987
9072
|
}
|
|
8988
|
-
}, [
|
|
9073
|
+
}, [isPlaybackActive, pendingNotificationType, pendingPrompt, recordingMode, setExpandedState]);
|
|
8989
9074
|
const preferredListeningExperienceRef = (0, import_react18.useRef)(null);
|
|
8990
9075
|
const playbackVoiceRoutingRef = (0, import_react18.useRef)({
|
|
8991
9076
|
activeExperienceType,
|
|
@@ -9033,6 +9118,7 @@ function ModelNexChatBubble({
|
|
|
9033
9118
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
9034
9119
|
hasPendingTour: Boolean(tourPlayback.pendingTour),
|
|
9035
9120
|
hasPendingOnboarding: Boolean(onboardingPlayback.pendingTour),
|
|
9121
|
+
startingExperienceType,
|
|
9036
9122
|
sttActive: sttActiveRef.current,
|
|
9037
9123
|
sttSupported: voice.sttSupported
|
|
9038
9124
|
};
|
|
@@ -9078,19 +9164,20 @@ function ModelNexChatBubble({
|
|
|
9078
9164
|
tourPlayback.pendingTour,
|
|
9079
9165
|
onboardingPlayback.isActive,
|
|
9080
9166
|
onboardingPlayback.pendingTour,
|
|
9167
|
+
startingExperienceType,
|
|
9081
9168
|
voice,
|
|
9082
9169
|
handleVoiceTourInput,
|
|
9083
9170
|
updateTourListenReady,
|
|
9084
9171
|
updateTourSttError
|
|
9085
9172
|
]);
|
|
9086
9173
|
(0, import_react18.useEffect)(() => {
|
|
9087
|
-
const
|
|
9174
|
+
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
9088
9175
|
isTourActive: tourPlayback.isActive,
|
|
9089
9176
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
9090
9177
|
startingExperienceType
|
|
9091
9178
|
});
|
|
9092
|
-
const becameActive =
|
|
9093
|
-
previousTourActiveRef.current =
|
|
9179
|
+
const becameActive = isPlaybackActive2 && !previousTourActiveRef.current;
|
|
9180
|
+
previousTourActiveRef.current = isPlaybackActive2;
|
|
9094
9181
|
if (becameActive) {
|
|
9095
9182
|
try {
|
|
9096
9183
|
sessionStorage.setItem(TOUR_MINIMIZED_STORAGE_KEY, "true");
|
|
@@ -9099,7 +9186,7 @@ function ModelNexChatBubble({
|
|
|
9099
9186
|
setExpandedState(false, { rememberTourMinimize: true });
|
|
9100
9187
|
updateTourSttError(null);
|
|
9101
9188
|
}
|
|
9102
|
-
if (!
|
|
9189
|
+
if (!isPlaybackActive2) {
|
|
9103
9190
|
try {
|
|
9104
9191
|
sessionStorage.removeItem(TOUR_MINIMIZED_STORAGE_KEY);
|
|
9105
9192
|
} catch {
|
|
@@ -9126,12 +9213,12 @@ function ModelNexChatBubble({
|
|
|
9126
9213
|
}
|
|
9127
9214
|
}, [recordingMode, setExpandedState]);
|
|
9128
9215
|
(0, import_react18.useEffect)(() => {
|
|
9129
|
-
const
|
|
9216
|
+
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
9130
9217
|
isTourActive: tourPlayback.isActive,
|
|
9131
9218
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
9132
9219
|
startingExperienceType
|
|
9133
9220
|
});
|
|
9134
|
-
if (!
|
|
9221
|
+
if (!isPlaybackActive2) {
|
|
9135
9222
|
updateTourListenReady(false);
|
|
9136
9223
|
setTourLiveTranscript("");
|
|
9137
9224
|
hideFloatingLiveTranscript();
|
|
@@ -9140,12 +9227,12 @@ function ModelNexChatBubble({
|
|
|
9140
9227
|
updateTourListenReady(Boolean(voice.isListening && sttActiveRef.current));
|
|
9141
9228
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, voice.isListening, startingExperienceType, updateTourListenReady]);
|
|
9142
9229
|
(0, import_react18.useEffect)(() => {
|
|
9143
|
-
const
|
|
9230
|
+
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
9144
9231
|
isTourActive: tourPlayback.isActive,
|
|
9145
9232
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
9146
9233
|
startingExperienceType
|
|
9147
9234
|
});
|
|
9148
|
-
if (!
|
|
9235
|
+
if (!isPlaybackActive2 && sttActiveRef.current) {
|
|
9149
9236
|
sttActiveRef.current = false;
|
|
9150
9237
|
updateTourListenReady(false);
|
|
9151
9238
|
updateTourSttError(null);
|
|
@@ -9155,12 +9242,12 @@ function ModelNexChatBubble({
|
|
|
9155
9242
|
}
|
|
9156
9243
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, voice, startingExperienceType, updateTourListenReady, updateTourSttError]);
|
|
9157
9244
|
(0, import_react18.useEffect)(() => {
|
|
9158
|
-
const
|
|
9245
|
+
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
9159
9246
|
isTourActive: tourPlayback.isActive,
|
|
9160
9247
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
9161
9248
|
startingExperienceType
|
|
9162
9249
|
});
|
|
9163
|
-
if (!
|
|
9250
|
+
if (!isPlaybackActive2 || tourListenReady || !voice.sttSupported || tourSttError === "not-allowed") {
|
|
9164
9251
|
return;
|
|
9165
9252
|
}
|
|
9166
9253
|
const enableTourListeningFromGesture = (event) => {
|
|
@@ -9367,8 +9454,8 @@ function ModelNexChatBubble({
|
|
|
9367
9454
|
return (0, import_react_dom.createPortal)(
|
|
9368
9455
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: containerStyle, className, "data-modelnex-internal": "true", onMouseDown: stopEventPropagation, onClick: stopEventPropagation, children: [
|
|
9369
9456
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: GLOBAL_STYLES }),
|
|
9370
|
-
|
|
9371
|
-
const pt =
|
|
9457
|
+
renderPendingPromptModal && (() => {
|
|
9458
|
+
const pt = pendingPrompt?.tour;
|
|
9372
9459
|
const mc = pt?.presentation?.modalConfig || {};
|
|
9373
9460
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
9374
9461
|
"div",
|
|
@@ -9430,8 +9517,8 @@ function ModelNexChatBubble({
|
|
|
9430
9517
|
"button",
|
|
9431
9518
|
{
|
|
9432
9519
|
onClick: () => {
|
|
9433
|
-
const preferredExperience =
|
|
9434
|
-
if (
|
|
9520
|
+
const preferredExperience = pendingPrompt?.experienceType === "onboarding" ? "onboarding" : "tour";
|
|
9521
|
+
if (preferredExperience === "onboarding") {
|
|
9435
9522
|
onboardingPlayback.acceptPendingTour();
|
|
9436
9523
|
} else {
|
|
9437
9524
|
tourPlayback.acceptPendingTour();
|
|
@@ -9594,24 +9681,28 @@ function ModelNexChatBubble({
|
|
|
9594
9681
|
children: "Microphone access is blocked. Use the input box below, or allow microphone permission and tap the mic again."
|
|
9595
9682
|
}
|
|
9596
9683
|
),
|
|
9597
|
-
|
|
9684
|
+
renderPendingPromptInline && pendingPrompt && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", justifyContent: "flex-start" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
9598
9685
|
"div",
|
|
9599
9686
|
{
|
|
9600
9687
|
style: {
|
|
9601
|
-
|
|
9602
|
-
padding: "
|
|
9603
|
-
borderRadius: "
|
|
9604
|
-
|
|
9605
|
-
|
|
9688
|
+
maxWidth: "85%",
|
|
9689
|
+
padding: "12px 16px",
|
|
9690
|
+
borderRadius: "var(--modelnex-radius-inner, 16px)",
|
|
9691
|
+
borderBottomLeftRadius: 4,
|
|
9692
|
+
fontSize: "14px",
|
|
9693
|
+
lineHeight: 1.55,
|
|
9694
|
+
background: "var(--modelnex-bg, #fff)",
|
|
9695
|
+
color: "var(--modelnex-fg, #18181b)",
|
|
9696
|
+
border: "1px solid var(--modelnex-border, #e4e4e7)",
|
|
9697
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.02)"
|
|
9606
9698
|
},
|
|
9607
9699
|
children: [
|
|
9608
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
|
|
9609
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "
|
|
9610
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "12px", color: "#52525b", lineHeight: 1.45, marginBottom: "12px" }, children: (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.trigger === "first_visit" ? "Start a short walkthrough for this user now?" : (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.featureKey ? `A walkthrough is available for ${(onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.featureKey}.` : "A walkthrough is available for this user." }),
|
|
9700
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontWeight: 500, marginBottom: "8px" }, children: getPendingPromptTitle(pendingPrompt) }),
|
|
9701
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "12px", color: "#52525b", marginBottom: "12px" }, children: getPendingPromptReason(pendingPrompt) }),
|
|
9611
9702
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
9612
9703
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { className: "btn btn-primary btn-sm", onClick: () => {
|
|
9613
|
-
const preferredExperience =
|
|
9614
|
-
if (
|
|
9704
|
+
const preferredExperience = pendingPrompt.experienceType === "onboarding" ? "onboarding" : "tour";
|
|
9705
|
+
if (preferredExperience === "onboarding") {
|
|
9615
9706
|
onboardingPlayback.acceptPendingTour();
|
|
9616
9707
|
} else {
|
|
9617
9708
|
tourPlayback.acceptPendingTour();
|
|
@@ -9619,13 +9710,13 @@ function ModelNexChatBubble({
|
|
|
9619
9710
|
startTourListening(preferredExperience);
|
|
9620
9711
|
}, children: [
|
|
9621
9712
|
"Start ",
|
|
9622
|
-
|
|
9713
|
+
pendingPrompt.experienceType === "onboarding" ? "workflow" : "tour"
|
|
9623
9714
|
] }),
|
|
9624
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "btn btn-secondary btn-sm", onClick:
|
|
9715
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "btn btn-secondary btn-sm", onClick: pendingPrompt.experienceType === "onboarding" ? onboardingPlayback.dismissPendingTour : tourPlayback.dismissPendingTour, children: "Not now" })
|
|
9625
9716
|
] })
|
|
9626
9717
|
]
|
|
9627
9718
|
}
|
|
9628
|
-
),
|
|
9719
|
+
) }),
|
|
9629
9720
|
tourPlayback.isActive && tourPlayback.isReviewMode && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
9630
9721
|
"div",
|
|
9631
9722
|
{
|
|
@@ -10204,7 +10295,7 @@ function ModelNexChatBubble({
|
|
|
10204
10295
|
)
|
|
10205
10296
|
] })
|
|
10206
10297
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
10207
|
-
messages.length === 0 && !loading && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
10298
|
+
messages.length === 0 && !loading && !renderPendingPromptInline && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
10208
10299
|
"div",
|
|
10209
10300
|
{
|
|
10210
10301
|
style: {
|
package/dist/index.mjs
CHANGED
|
@@ -2457,6 +2457,9 @@ function normalizeTrigger(trigger) {
|
|
|
2457
2457
|
if (trigger === "feature_launch" || trigger === "feature_unlocked" || trigger === "feature_unlock" || trigger === "new_feature") {
|
|
2458
2458
|
return "feature_launch";
|
|
2459
2459
|
}
|
|
2460
|
+
if (trigger === "return_visit") {
|
|
2461
|
+
return "return_visit";
|
|
2462
|
+
}
|
|
2460
2463
|
return trigger ?? "first_visit";
|
|
2461
2464
|
}
|
|
2462
2465
|
function getStartPolicy(tour) {
|
|
@@ -2465,10 +2468,22 @@ function getStartPolicy(tour) {
|
|
|
2465
2468
|
function getNotificationType(tour) {
|
|
2466
2469
|
return tour.notificationType ?? "bubble_card";
|
|
2467
2470
|
}
|
|
2471
|
+
function getUserProfileFeatures(userProfile) {
|
|
2472
|
+
const directFeatures = Array.isArray(userProfile.features) ? userProfile.features : [];
|
|
2473
|
+
const nestedFeatures = Array.isArray(userProfile.tourFacts?.features) ? userProfile.tourFacts.features : [];
|
|
2474
|
+
return [...new Set([...directFeatures, ...nestedFeatures].filter((value) => Boolean(value)))];
|
|
2475
|
+
}
|
|
2468
2476
|
function isTourEligible(tour, userProfile) {
|
|
2469
2477
|
switch (normalizeTrigger(tour.trigger)) {
|
|
2470
2478
|
case "first_visit":
|
|
2471
2479
|
return !!userProfile.isNewUser;
|
|
2480
|
+
case "return_visit":
|
|
2481
|
+
return userProfile.isNewUser === false;
|
|
2482
|
+
case "feature_launch": {
|
|
2483
|
+
const featureKey = tour.featureKey?.trim();
|
|
2484
|
+
if (!featureKey) return false;
|
|
2485
|
+
return getUserProfileFeatures(userProfile).includes(featureKey);
|
|
2486
|
+
}
|
|
2472
2487
|
case "manual":
|
|
2473
2488
|
return false;
|
|
2474
2489
|
default:
|
|
@@ -7908,7 +7923,7 @@ function getRecordingDraftStatusMessage(phase, experienceType) {
|
|
|
7908
7923
|
|
|
7909
7924
|
// src/utils/tour-listening.ts
|
|
7910
7925
|
function canStartTourListening(state) {
|
|
7911
|
-
const hasLiveOrPendingPlayback = state.isTourActive || state.isOnboardingActive || state.hasPendingTour || state.hasPendingOnboarding;
|
|
7926
|
+
const hasLiveOrPendingPlayback = state.isTourActive || state.isOnboardingActive || state.hasPendingTour || state.hasPendingOnboarding || Boolean(state.startingExperienceType);
|
|
7912
7927
|
return hasLiveOrPendingPlayback && !state.sttActive && state.sttSupported;
|
|
7913
7928
|
}
|
|
7914
7929
|
function resolveTourListeningExperience(preferredExperience, state) {
|
|
@@ -7985,6 +8000,58 @@ function buildTranscriptPreviewLines(transcript, options = {}) {
|
|
|
7985
8000
|
return lines.slice(-maxLines);
|
|
7986
8001
|
}
|
|
7987
8002
|
|
|
8003
|
+
// src/utils/pendingPromptUi.ts
|
|
8004
|
+
function isPendingReviewPrompt(pendingPrompt) {
|
|
8005
|
+
return Boolean(pendingPrompt?.options?.reviewMode);
|
|
8006
|
+
}
|
|
8007
|
+
function shouldRenderPendingPromptInline({
|
|
8008
|
+
pendingPrompt,
|
|
8009
|
+
isPlaybackActive,
|
|
8010
|
+
recordingMode
|
|
8011
|
+
}) {
|
|
8012
|
+
return Boolean(
|
|
8013
|
+
pendingPrompt && !isPlaybackActive && !recordingMode && !isPendingReviewPrompt(pendingPrompt)
|
|
8014
|
+
);
|
|
8015
|
+
}
|
|
8016
|
+
function shouldRenderPendingPromptModal({
|
|
8017
|
+
pendingPrompt,
|
|
8018
|
+
isPlaybackActive,
|
|
8019
|
+
recordingMode,
|
|
8020
|
+
pendingNotificationType
|
|
8021
|
+
}) {
|
|
8022
|
+
return Boolean(
|
|
8023
|
+
pendingPrompt && !isPlaybackActive && !recordingMode && isPendingReviewPrompt(pendingPrompt) && pendingNotificationType === "modal"
|
|
8024
|
+
);
|
|
8025
|
+
}
|
|
8026
|
+
function shouldAutoExpandForPendingPrompt({
|
|
8027
|
+
pendingPrompt,
|
|
8028
|
+
isPlaybackActive,
|
|
8029
|
+
recordingMode,
|
|
8030
|
+
pendingNotificationType
|
|
8031
|
+
}) {
|
|
8032
|
+
if (!pendingPrompt || isPlaybackActive || recordingMode) return false;
|
|
8033
|
+
return pendingNotificationType === "bubble_card" || shouldRenderPendingPromptInline({
|
|
8034
|
+
pendingPrompt,
|
|
8035
|
+
isPlaybackActive,
|
|
8036
|
+
recordingMode
|
|
8037
|
+
});
|
|
8038
|
+
}
|
|
8039
|
+
function getPendingPromptTitle(pendingPrompt) {
|
|
8040
|
+
return `I found a ${pendingPrompt.experienceType === "onboarding" ? "workflow" : "tour"} called "${pendingPrompt.tour.name}". Would you like to start it now?`;
|
|
8041
|
+
}
|
|
8042
|
+
function getPendingPromptReason(pendingPrompt) {
|
|
8043
|
+
if (pendingPrompt.tour.trigger === "first_visit") {
|
|
8044
|
+
return "This was surfaced because the current user matches the configured first-visit trigger.";
|
|
8045
|
+
}
|
|
8046
|
+
if (pendingPrompt.tour.trigger === "return_visit") {
|
|
8047
|
+
return "This was surfaced because the current user matches the configured return-visit trigger.";
|
|
8048
|
+
}
|
|
8049
|
+
if (pendingPrompt.tour.featureKey) {
|
|
8050
|
+
return `This was surfaced because the "${pendingPrompt.tour.featureKey}" trigger condition matched.`;
|
|
8051
|
+
}
|
|
8052
|
+
return "This was surfaced because the configured trigger condition matched.";
|
|
8053
|
+
}
|
|
8054
|
+
|
|
7988
8055
|
// src/utils/floatingLiveTranscript.ts
|
|
7989
8056
|
var floatingTranscriptEl = null;
|
|
7990
8057
|
var liveTranscriptSuppressed = false;
|
|
@@ -8704,7 +8771,20 @@ function ModelNexChatBubble({
|
|
|
8704
8771
|
}
|
|
8705
8772
|
}, [devMode, handleAutoTag, ctx?.extractedElements.length, window.location.pathname]);
|
|
8706
8773
|
const onboardingReviewToggle = getReviewModeToggleConfig(onboardingPlayback.playbackState);
|
|
8774
|
+
const pendingPrompt = playbackController.pendingPrompt;
|
|
8707
8775
|
const pendingNotificationType = (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.notificationType ?? "bubble_card";
|
|
8776
|
+
const isPlaybackActive = tourPlayback.isActive || onboardingPlayback.isActive;
|
|
8777
|
+
const renderPendingPromptInline = shouldRenderPendingPromptInline({
|
|
8778
|
+
pendingPrompt,
|
|
8779
|
+
isPlaybackActive,
|
|
8780
|
+
recordingMode
|
|
8781
|
+
});
|
|
8782
|
+
const renderPendingPromptModal = shouldRenderPendingPromptModal({
|
|
8783
|
+
pendingPrompt,
|
|
8784
|
+
isPlaybackActive,
|
|
8785
|
+
recordingMode,
|
|
8786
|
+
pendingNotificationType
|
|
8787
|
+
});
|
|
8708
8788
|
useEffect17(() => {
|
|
8709
8789
|
setHydrated(true);
|
|
8710
8790
|
try {
|
|
@@ -8771,10 +8851,15 @@ function ModelNexChatBubble({
|
|
|
8771
8851
|
}
|
|
8772
8852
|
}, [tourPlayback.isActive, onboardingPlayback.isActive]);
|
|
8773
8853
|
useEffect17(() => {
|
|
8774
|
-
if ((
|
|
8854
|
+
if (shouldAutoExpandForPendingPrompt({
|
|
8855
|
+
pendingPrompt,
|
|
8856
|
+
isPlaybackActive,
|
|
8857
|
+
recordingMode,
|
|
8858
|
+
pendingNotificationType
|
|
8859
|
+
})) {
|
|
8775
8860
|
setExpandedState(true);
|
|
8776
8861
|
}
|
|
8777
|
-
}, [
|
|
8862
|
+
}, [isPlaybackActive, pendingNotificationType, pendingPrompt, recordingMode, setExpandedState]);
|
|
8778
8863
|
const preferredListeningExperienceRef = useRef13(null);
|
|
8779
8864
|
const playbackVoiceRoutingRef = useRef13({
|
|
8780
8865
|
activeExperienceType,
|
|
@@ -8822,6 +8907,7 @@ function ModelNexChatBubble({
|
|
|
8822
8907
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
8823
8908
|
hasPendingTour: Boolean(tourPlayback.pendingTour),
|
|
8824
8909
|
hasPendingOnboarding: Boolean(onboardingPlayback.pendingTour),
|
|
8910
|
+
startingExperienceType,
|
|
8825
8911
|
sttActive: sttActiveRef.current,
|
|
8826
8912
|
sttSupported: voice.sttSupported
|
|
8827
8913
|
};
|
|
@@ -8867,19 +8953,20 @@ function ModelNexChatBubble({
|
|
|
8867
8953
|
tourPlayback.pendingTour,
|
|
8868
8954
|
onboardingPlayback.isActive,
|
|
8869
8955
|
onboardingPlayback.pendingTour,
|
|
8956
|
+
startingExperienceType,
|
|
8870
8957
|
voice,
|
|
8871
8958
|
handleVoiceTourInput,
|
|
8872
8959
|
updateTourListenReady,
|
|
8873
8960
|
updateTourSttError
|
|
8874
8961
|
]);
|
|
8875
8962
|
useEffect17(() => {
|
|
8876
|
-
const
|
|
8963
|
+
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
8877
8964
|
isTourActive: tourPlayback.isActive,
|
|
8878
8965
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
8879
8966
|
startingExperienceType
|
|
8880
8967
|
});
|
|
8881
|
-
const becameActive =
|
|
8882
|
-
previousTourActiveRef.current =
|
|
8968
|
+
const becameActive = isPlaybackActive2 && !previousTourActiveRef.current;
|
|
8969
|
+
previousTourActiveRef.current = isPlaybackActive2;
|
|
8883
8970
|
if (becameActive) {
|
|
8884
8971
|
try {
|
|
8885
8972
|
sessionStorage.setItem(TOUR_MINIMIZED_STORAGE_KEY, "true");
|
|
@@ -8888,7 +8975,7 @@ function ModelNexChatBubble({
|
|
|
8888
8975
|
setExpandedState(false, { rememberTourMinimize: true });
|
|
8889
8976
|
updateTourSttError(null);
|
|
8890
8977
|
}
|
|
8891
|
-
if (!
|
|
8978
|
+
if (!isPlaybackActive2) {
|
|
8892
8979
|
try {
|
|
8893
8980
|
sessionStorage.removeItem(TOUR_MINIMIZED_STORAGE_KEY);
|
|
8894
8981
|
} catch {
|
|
@@ -8915,12 +9002,12 @@ function ModelNexChatBubble({
|
|
|
8915
9002
|
}
|
|
8916
9003
|
}, [recordingMode, setExpandedState]);
|
|
8917
9004
|
useEffect17(() => {
|
|
8918
|
-
const
|
|
9005
|
+
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
8919
9006
|
isTourActive: tourPlayback.isActive,
|
|
8920
9007
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
8921
9008
|
startingExperienceType
|
|
8922
9009
|
});
|
|
8923
|
-
if (!
|
|
9010
|
+
if (!isPlaybackActive2) {
|
|
8924
9011
|
updateTourListenReady(false);
|
|
8925
9012
|
setTourLiveTranscript("");
|
|
8926
9013
|
hideFloatingLiveTranscript();
|
|
@@ -8929,12 +9016,12 @@ function ModelNexChatBubble({
|
|
|
8929
9016
|
updateTourListenReady(Boolean(voice.isListening && sttActiveRef.current));
|
|
8930
9017
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, voice.isListening, startingExperienceType, updateTourListenReady]);
|
|
8931
9018
|
useEffect17(() => {
|
|
8932
|
-
const
|
|
9019
|
+
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
8933
9020
|
isTourActive: tourPlayback.isActive,
|
|
8934
9021
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
8935
9022
|
startingExperienceType
|
|
8936
9023
|
});
|
|
8937
|
-
if (!
|
|
9024
|
+
if (!isPlaybackActive2 && sttActiveRef.current) {
|
|
8938
9025
|
sttActiveRef.current = false;
|
|
8939
9026
|
updateTourListenReady(false);
|
|
8940
9027
|
updateTourSttError(null);
|
|
@@ -8944,12 +9031,12 @@ function ModelNexChatBubble({
|
|
|
8944
9031
|
}
|
|
8945
9032
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, voice, startingExperienceType, updateTourListenReady, updateTourSttError]);
|
|
8946
9033
|
useEffect17(() => {
|
|
8947
|
-
const
|
|
9034
|
+
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
8948
9035
|
isTourActive: tourPlayback.isActive,
|
|
8949
9036
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
8950
9037
|
startingExperienceType
|
|
8951
9038
|
});
|
|
8952
|
-
if (!
|
|
9039
|
+
if (!isPlaybackActive2 || tourListenReady || !voice.sttSupported || tourSttError === "not-allowed") {
|
|
8953
9040
|
return;
|
|
8954
9041
|
}
|
|
8955
9042
|
const enableTourListeningFromGesture = (event) => {
|
|
@@ -9156,8 +9243,8 @@ function ModelNexChatBubble({
|
|
|
9156
9243
|
return createPortal(
|
|
9157
9244
|
/* @__PURE__ */ jsxs3("div", { style: containerStyle, className, "data-modelnex-internal": "true", onMouseDown: stopEventPropagation, onClick: stopEventPropagation, children: [
|
|
9158
9245
|
/* @__PURE__ */ jsx4("style", { children: GLOBAL_STYLES }),
|
|
9159
|
-
|
|
9160
|
-
const pt =
|
|
9246
|
+
renderPendingPromptModal && (() => {
|
|
9247
|
+
const pt = pendingPrompt?.tour;
|
|
9161
9248
|
const mc = pt?.presentation?.modalConfig || {};
|
|
9162
9249
|
return /* @__PURE__ */ jsx4(
|
|
9163
9250
|
"div",
|
|
@@ -9219,8 +9306,8 @@ function ModelNexChatBubble({
|
|
|
9219
9306
|
"button",
|
|
9220
9307
|
{
|
|
9221
9308
|
onClick: () => {
|
|
9222
|
-
const preferredExperience =
|
|
9223
|
-
if (
|
|
9309
|
+
const preferredExperience = pendingPrompt?.experienceType === "onboarding" ? "onboarding" : "tour";
|
|
9310
|
+
if (preferredExperience === "onboarding") {
|
|
9224
9311
|
onboardingPlayback.acceptPendingTour();
|
|
9225
9312
|
} else {
|
|
9226
9313
|
tourPlayback.acceptPendingTour();
|
|
@@ -9383,24 +9470,28 @@ function ModelNexChatBubble({
|
|
|
9383
9470
|
children: "Microphone access is blocked. Use the input box below, or allow microphone permission and tap the mic again."
|
|
9384
9471
|
}
|
|
9385
9472
|
),
|
|
9386
|
-
|
|
9473
|
+
renderPendingPromptInline && pendingPrompt && /* @__PURE__ */ jsx4("div", { style: { display: "flex", justifyContent: "flex-start" }, children: /* @__PURE__ */ jsxs3(
|
|
9387
9474
|
"div",
|
|
9388
9475
|
{
|
|
9389
9476
|
style: {
|
|
9390
|
-
|
|
9391
|
-
padding: "
|
|
9392
|
-
borderRadius: "
|
|
9393
|
-
|
|
9394
|
-
|
|
9477
|
+
maxWidth: "85%",
|
|
9478
|
+
padding: "12px 16px",
|
|
9479
|
+
borderRadius: "var(--modelnex-radius-inner, 16px)",
|
|
9480
|
+
borderBottomLeftRadius: 4,
|
|
9481
|
+
fontSize: "14px",
|
|
9482
|
+
lineHeight: 1.55,
|
|
9483
|
+
background: "var(--modelnex-bg, #fff)",
|
|
9484
|
+
color: "var(--modelnex-fg, #18181b)",
|
|
9485
|
+
border: "1px solid var(--modelnex-border, #e4e4e7)",
|
|
9486
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.02)"
|
|
9395
9487
|
},
|
|
9396
9488
|
children: [
|
|
9397
|
-
/* @__PURE__ */ jsx4("div", { style: {
|
|
9398
|
-
/* @__PURE__ */ jsx4("div", { style: { fontSize: "
|
|
9399
|
-
/* @__PURE__ */ jsx4("div", { style: { fontSize: "12px", color: "#52525b", lineHeight: 1.45, marginBottom: "12px" }, children: (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.trigger === "first_visit" ? "Start a short walkthrough for this user now?" : (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.featureKey ? `A walkthrough is available for ${(onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.featureKey}.` : "A walkthrough is available for this user." }),
|
|
9489
|
+
/* @__PURE__ */ jsx4("div", { style: { fontWeight: 500, marginBottom: "8px" }, children: getPendingPromptTitle(pendingPrompt) }),
|
|
9490
|
+
/* @__PURE__ */ jsx4("div", { style: { fontSize: "12px", color: "#52525b", marginBottom: "12px" }, children: getPendingPromptReason(pendingPrompt) }),
|
|
9400
9491
|
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
9401
9492
|
/* @__PURE__ */ jsxs3("button", { className: "btn btn-primary btn-sm", onClick: () => {
|
|
9402
|
-
const preferredExperience =
|
|
9403
|
-
if (
|
|
9493
|
+
const preferredExperience = pendingPrompt.experienceType === "onboarding" ? "onboarding" : "tour";
|
|
9494
|
+
if (preferredExperience === "onboarding") {
|
|
9404
9495
|
onboardingPlayback.acceptPendingTour();
|
|
9405
9496
|
} else {
|
|
9406
9497
|
tourPlayback.acceptPendingTour();
|
|
@@ -9408,13 +9499,13 @@ function ModelNexChatBubble({
|
|
|
9408
9499
|
startTourListening(preferredExperience);
|
|
9409
9500
|
}, children: [
|
|
9410
9501
|
"Start ",
|
|
9411
|
-
|
|
9502
|
+
pendingPrompt.experienceType === "onboarding" ? "workflow" : "tour"
|
|
9412
9503
|
] }),
|
|
9413
|
-
/* @__PURE__ */ jsx4("button", { className: "btn btn-secondary btn-sm", onClick:
|
|
9504
|
+
/* @__PURE__ */ jsx4("button", { className: "btn btn-secondary btn-sm", onClick: pendingPrompt.experienceType === "onboarding" ? onboardingPlayback.dismissPendingTour : tourPlayback.dismissPendingTour, children: "Not now" })
|
|
9414
9505
|
] })
|
|
9415
9506
|
]
|
|
9416
9507
|
}
|
|
9417
|
-
),
|
|
9508
|
+
) }),
|
|
9418
9509
|
tourPlayback.isActive && tourPlayback.isReviewMode && /* @__PURE__ */ jsxs3(
|
|
9419
9510
|
"div",
|
|
9420
9511
|
{
|
|
@@ -9993,7 +10084,7 @@ function ModelNexChatBubble({
|
|
|
9993
10084
|
)
|
|
9994
10085
|
] })
|
|
9995
10086
|
] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
9996
|
-
messages.length === 0 && !loading && /* @__PURE__ */ jsx4(
|
|
10087
|
+
messages.length === 0 && !loading && !renderPendingPromptInline && /* @__PURE__ */ jsx4(
|
|
9997
10088
|
"div",
|
|
9998
10089
|
{
|
|
9999
10090
|
style: {
|