@modelnex/sdk 0.5.38 → 0.5.40
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.js +127 -26
- package/dist/index.mjs +127 -26
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3305,6 +3305,22 @@ function createTourSocketPool({
|
|
|
3305
3305
|
}
|
|
3306
3306
|
var tourSocketPool = createTourSocketPool();
|
|
3307
3307
|
|
|
3308
|
+
// src/utils/reviewModeToggle.ts
|
|
3309
|
+
function isReviewModeEnabled(devMode, requestedReviewMode) {
|
|
3310
|
+
return Boolean(devMode && requestedReviewMode);
|
|
3311
|
+
}
|
|
3312
|
+
function getReviewModeToggleConfig(playbackState) {
|
|
3313
|
+
const isPaused = playbackState === "paused";
|
|
3314
|
+
return {
|
|
3315
|
+
icon: isPaused ? "\u25B6" : "\u23F8",
|
|
3316
|
+
label: isPaused ? "Continue Workflow" : "Pause for Feedback",
|
|
3317
|
+
shouldResume: isPaused
|
|
3318
|
+
};
|
|
3319
|
+
}
|
|
3320
|
+
function shouldCaptureReviewDraft(isReviewMode, playbackState) {
|
|
3321
|
+
return isReviewMode && playbackState === "paused";
|
|
3322
|
+
}
|
|
3323
|
+
|
|
3308
3324
|
// src/utils/tourTransport.ts
|
|
3309
3325
|
function compactCaptureEventForTransport(event) {
|
|
3310
3326
|
return {
|
|
@@ -3726,6 +3742,20 @@ function isValueBearingElement(element) {
|
|
|
3726
3742
|
element && (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)
|
|
3727
3743
|
);
|
|
3728
3744
|
}
|
|
3745
|
+
var DEFAULT_TEXT_INPUT_IDLE_COMMIT_MS = 700;
|
|
3746
|
+
var DEFAULT_SELECTION_INPUT_IDLE_COMMIT_MS = 250;
|
|
3747
|
+
function getManualInputCommitPolicy(target) {
|
|
3748
|
+
const tagName = String(target.tagName || "").toLowerCase();
|
|
3749
|
+
const role = String(target.role || "").toLowerCase();
|
|
3750
|
+
const inputType = String(target.type || "").toLowerCase();
|
|
3751
|
+
const isContentEditable = Boolean(target.isContentEditable);
|
|
3752
|
+
const isSelectionLike = tagName === "select" || role === "combobox" || ["checkbox", "radio", "range", "color", "date", "datetime-local", "month", "time", "week"].includes(inputType);
|
|
3753
|
+
return {
|
|
3754
|
+
idleCommitMs: isSelectionLike ? DEFAULT_SELECTION_INPUT_IDLE_COMMIT_MS : DEFAULT_TEXT_INPUT_IDLE_COMMIT_MS,
|
|
3755
|
+
commitOnBlur: !isSelectionLike || tagName === "select" || role === "combobox" || isContentEditable,
|
|
3756
|
+
commitOnChange: true
|
|
3757
|
+
};
|
|
3758
|
+
}
|
|
3729
3759
|
function resolveWaitTargetElement(element) {
|
|
3730
3760
|
if (isValueBearingElement(element) || element.isContentEditable) {
|
|
3731
3761
|
return element;
|
|
@@ -3745,9 +3775,40 @@ function readWaitTargetValue(element) {
|
|
|
3745
3775
|
if (isValueBearingElement(element)) {
|
|
3746
3776
|
return element.value.trim();
|
|
3747
3777
|
}
|
|
3778
|
+
const genericValue = element.value;
|
|
3779
|
+
if (typeof genericValue === "string") {
|
|
3780
|
+
return genericValue.trim();
|
|
3781
|
+
}
|
|
3782
|
+
if (typeof genericValue === "number" && Number.isFinite(genericValue)) {
|
|
3783
|
+
return String(genericValue).trim();
|
|
3784
|
+
}
|
|
3748
3785
|
if (element.isContentEditable) {
|
|
3749
3786
|
return (element.textContent || "").trim();
|
|
3750
3787
|
}
|
|
3788
|
+
const ariaValueText = element.getAttribute("aria-valuetext");
|
|
3789
|
+
if (typeof ariaValueText === "string" && ariaValueText.trim()) {
|
|
3790
|
+
return ariaValueText.trim();
|
|
3791
|
+
}
|
|
3792
|
+
const ariaValueNow = element.getAttribute("aria-valuenow");
|
|
3793
|
+
if (typeof ariaValueNow === "string" && ariaValueNow.trim()) {
|
|
3794
|
+
return ariaValueNow.trim();
|
|
3795
|
+
}
|
|
3796
|
+
if (element.getAttribute("role") === "textbox" || element.getAttribute("role") === "combobox") {
|
|
3797
|
+
const nestedControl = element.querySelector(
|
|
3798
|
+
'input:not([type="hidden"]):not([disabled]), textarea:not([disabled]), select:not([disabled]), [contenteditable="true"], [role="textbox"], [role="combobox"]'
|
|
3799
|
+
);
|
|
3800
|
+
if (nestedControl && nestedControl !== element) {
|
|
3801
|
+
const nestedValue = readWaitTargetValue(nestedControl);
|
|
3802
|
+
if (nestedValue) {
|
|
3803
|
+
return nestedValue;
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
return (element.textContent || "").trim();
|
|
3807
|
+
}
|
|
3808
|
+
const shadowInput = findInputInShadowRoot(element);
|
|
3809
|
+
if (shadowInput) {
|
|
3810
|
+
return shadowInput.value.trim();
|
|
3811
|
+
}
|
|
3751
3812
|
return "";
|
|
3752
3813
|
}
|
|
3753
3814
|
function buildManualCompletionTranscript(step, eventName) {
|
|
@@ -3769,6 +3830,12 @@ function createManualWaitForTarget(rawTarget, eventName, step) {
|
|
|
3769
3830
|
const target = resolveWaitTargetElement(rawTarget);
|
|
3770
3831
|
const completionTranscript = buildManualCompletionTranscript(step, eventName);
|
|
3771
3832
|
const isInputLikeEvent = isInputLikeWait(eventName, step);
|
|
3833
|
+
const commitPolicy = getManualInputCommitPolicy({
|
|
3834
|
+
tagName: target.tagName,
|
|
3835
|
+
role: target.getAttribute("role"),
|
|
3836
|
+
type: target.type ?? null,
|
|
3837
|
+
isContentEditable: target.isContentEditable
|
|
3838
|
+
});
|
|
3772
3839
|
if (isInputLikeEvent && readWaitTargetValue(target)) {
|
|
3773
3840
|
const initialValue = readWaitTargetValue(target);
|
|
3774
3841
|
return {
|
|
@@ -3780,6 +3847,8 @@ function createManualWaitForTarget(rawTarget, eventName, step) {
|
|
|
3780
3847
|
let cleanup = () => void 0;
|
|
3781
3848
|
const promise = new Promise((resolve) => {
|
|
3782
3849
|
const listeners2 = [];
|
|
3850
|
+
let observer = null;
|
|
3851
|
+
let idleTimer = null;
|
|
3783
3852
|
let settled = false;
|
|
3784
3853
|
const finish = () => {
|
|
3785
3854
|
if (settled) return;
|
|
@@ -3792,20 +3861,61 @@ function createManualWaitForTarget(rawTarget, eventName, step) {
|
|
|
3792
3861
|
listeners2.push({ node, type, handler });
|
|
3793
3862
|
};
|
|
3794
3863
|
if (isInputLikeEvent) {
|
|
3795
|
-
const
|
|
3864
|
+
const clearIdleCommit = () => {
|
|
3865
|
+
if (idleTimer) {
|
|
3866
|
+
clearTimeout(idleTimer);
|
|
3867
|
+
idleTimer = null;
|
|
3868
|
+
}
|
|
3869
|
+
};
|
|
3870
|
+
const scheduleIdleCommit = () => {
|
|
3871
|
+
const currentValue = readWaitTargetValue(target);
|
|
3872
|
+
if (!currentValue) {
|
|
3873
|
+
clearIdleCommit();
|
|
3874
|
+
return;
|
|
3875
|
+
}
|
|
3876
|
+
clearIdleCommit();
|
|
3877
|
+
idleTimer = setTimeout(() => {
|
|
3878
|
+
idleTimer = null;
|
|
3879
|
+
finish();
|
|
3880
|
+
}, commitPolicy.idleCommitMs);
|
|
3881
|
+
};
|
|
3882
|
+
const handleImmediateCommitEvent = () => {
|
|
3796
3883
|
const currentValue = readWaitTargetValue(target);
|
|
3797
3884
|
if (currentValue) {
|
|
3885
|
+
clearIdleCommit();
|
|
3798
3886
|
finish();
|
|
3799
3887
|
}
|
|
3800
3888
|
};
|
|
3801
|
-
addListener(target, "input",
|
|
3802
|
-
|
|
3803
|
-
|
|
3889
|
+
addListener(target, "input", scheduleIdleCommit);
|
|
3890
|
+
if (commitPolicy.commitOnChange) {
|
|
3891
|
+
addListener(target, "change", handleImmediateCommitEvent);
|
|
3892
|
+
}
|
|
3893
|
+
if (commitPolicy.commitOnBlur) {
|
|
3894
|
+
addListener(target, "blur", handleImmediateCommitEvent);
|
|
3895
|
+
}
|
|
3896
|
+
if (typeof MutationObserver !== "undefined") {
|
|
3897
|
+
observer = new MutationObserver(() => {
|
|
3898
|
+
scheduleIdleCommit();
|
|
3899
|
+
});
|
|
3900
|
+
observer.observe(target, {
|
|
3901
|
+
subtree: true,
|
|
3902
|
+
childList: true,
|
|
3903
|
+
characterData: true,
|
|
3904
|
+
attributes: true,
|
|
3905
|
+
attributeFilter: ["value", "aria-valuetext", "aria-valuenow", "aria-activedescendant"]
|
|
3906
|
+
});
|
|
3907
|
+
}
|
|
3804
3908
|
} else {
|
|
3805
3909
|
const handleActionEvent = () => finish();
|
|
3806
3910
|
addListener(target, eventName, handleActionEvent);
|
|
3807
3911
|
}
|
|
3808
3912
|
cleanup = () => {
|
|
3913
|
+
if (idleTimer) {
|
|
3914
|
+
clearTimeout(idleTimer);
|
|
3915
|
+
idleTimer = null;
|
|
3916
|
+
}
|
|
3917
|
+
observer?.disconnect();
|
|
3918
|
+
observer = null;
|
|
3809
3919
|
listeners2.forEach(({ node, type, handler }) => node.removeEventListener(type, handler));
|
|
3810
3920
|
listeners2.length = 0;
|
|
3811
3921
|
};
|
|
@@ -4826,7 +4936,7 @@ function useTourPlayback({
|
|
|
4826
4936
|
}
|
|
4827
4937
|
claimedPlaybackOwnerKeyRef.current = ownerKey;
|
|
4828
4938
|
startRequestedRef.current = true;
|
|
4829
|
-
const shouldReview = Boolean(options?.reviewMode);
|
|
4939
|
+
const shouldReview = isReviewModeEnabled(devModeRef.current, Boolean(options?.reviewMode));
|
|
4830
4940
|
resetCaptionSuppression();
|
|
4831
4941
|
setReviewStatusMessage(null);
|
|
4832
4942
|
setIsReviewMode(shouldReview);
|
|
@@ -8804,19 +8914,6 @@ function isTourListeningSessionActive(state) {
|
|
|
8804
8914
|
return state.isTourActive || state.isOnboardingActive || Boolean(state.startingExperienceType);
|
|
8805
8915
|
}
|
|
8806
8916
|
|
|
8807
|
-
// src/utils/reviewModeToggle.ts
|
|
8808
|
-
function getReviewModeToggleConfig(playbackState) {
|
|
8809
|
-
const isPaused = playbackState === "paused";
|
|
8810
|
-
return {
|
|
8811
|
-
icon: isPaused ? "\u25B6" : "\u23F8",
|
|
8812
|
-
label: isPaused ? "Continue Workflow" : "Pause for Feedback",
|
|
8813
|
-
shouldResume: isPaused
|
|
8814
|
-
};
|
|
8815
|
-
}
|
|
8816
|
-
function shouldCaptureReviewDraft(isReviewMode, playbackState) {
|
|
8817
|
-
return isReviewMode && playbackState === "paused";
|
|
8818
|
-
}
|
|
8819
|
-
|
|
8820
8917
|
// src/utils/reviewVoiceRouting.ts
|
|
8821
8918
|
function resolveSinglePlaybackTranscriptTarget(snapshot) {
|
|
8822
8919
|
return shouldCaptureReviewDraft(snapshot.isReviewMode, snapshot.playbackState) ? "review_draft" : "playback";
|
|
@@ -9613,6 +9710,7 @@ function ModelNexChatBubble({
|
|
|
9613
9710
|
const tourPlayback = (0, import_react18.useMemo)(() => createPlaybackView("tour"), [createPlaybackView]);
|
|
9614
9711
|
const onboardingPlayback = (0, import_react18.useMemo)(() => createPlaybackView("onboarding"), [createPlaybackView]);
|
|
9615
9712
|
const tourReviewToggle = getReviewModeToggleConfig(tourPlayback.playbackState);
|
|
9713
|
+
const tourReviewModeEnabled = isReviewModeEnabled(devMode, tourPlayback.isReviewMode);
|
|
9616
9714
|
const lastAutoTaggedUrlRef = (0, import_react18.useRef)(null);
|
|
9617
9715
|
const handleAutoTag = (0, import_react18.useCallback)(async () => {
|
|
9618
9716
|
if (!ctx) return;
|
|
@@ -9660,6 +9758,7 @@ function ModelNexChatBubble({
|
|
|
9660
9758
|
}
|
|
9661
9759
|
}, [authoringMode, handleAutoTag, ctx?.extractedElements.length, window.location.pathname]);
|
|
9662
9760
|
const onboardingReviewToggle = getReviewModeToggleConfig(onboardingPlayback.playbackState);
|
|
9761
|
+
const onboardingReviewModeEnabled = isReviewModeEnabled(devMode, onboardingPlayback.isReviewMode);
|
|
9663
9762
|
const pendingPrompt = playbackController.pendingPrompt;
|
|
9664
9763
|
const pendingNotificationType = (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.notificationType ?? "bubble_card";
|
|
9665
9764
|
const isPlaybackActive = tourPlayback.isActive || onboardingPlayback.isActive;
|
|
@@ -10429,7 +10528,7 @@ function ModelNexChatBubble({
|
|
|
10429
10528
|
]
|
|
10430
10529
|
}
|
|
10431
10530
|
) }),
|
|
10432
|
-
tourPlayback.isActive &&
|
|
10531
|
+
tourPlayback.isActive && tourReviewModeEnabled && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
10433
10532
|
"div",
|
|
10434
10533
|
{
|
|
10435
10534
|
style: {
|
|
@@ -10724,7 +10823,7 @@ function ModelNexChatBubble({
|
|
|
10724
10823
|
] })
|
|
10725
10824
|
] })
|
|
10726
10825
|
] }),
|
|
10727
|
-
|
|
10826
|
+
onboardingReviewModeEnabled && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
10728
10827
|
"div",
|
|
10729
10828
|
{
|
|
10730
10829
|
style: {
|
|
@@ -10830,7 +10929,7 @@ function ModelNexChatBubble({
|
|
|
10830
10929
|
}
|
|
10831
10930
|
),
|
|
10832
10931
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
10833
|
-
!
|
|
10932
|
+
!onboardingReviewModeEnabled && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
10834
10933
|
"button",
|
|
10835
10934
|
{
|
|
10836
10935
|
onClick: onboardingPlayback.repeatStep,
|
|
@@ -10842,7 +10941,7 @@ function ModelNexChatBubble({
|
|
|
10842
10941
|
"button",
|
|
10843
10942
|
{
|
|
10844
10943
|
onClick: onboardingPlayback.skipTour,
|
|
10845
|
-
style: { flex:
|
|
10944
|
+
style: { flex: onboardingReviewModeEnabled ? 1 : 0.6, borderRadius: "12px", border: "1px solid rgba(220,38,38,0.18)", background: "#fff5f5", color: "#b91c1c", padding: "11px 14px", cursor: "pointer", fontWeight: 700, fontSize: "13px" },
|
|
10846
10945
|
children: "Exit"
|
|
10847
10946
|
}
|
|
10848
10947
|
)
|
|
@@ -10883,7 +10982,7 @@ function ModelNexChatBubble({
|
|
|
10883
10982
|
) })
|
|
10884
10983
|
] }),
|
|
10885
10984
|
tourCurrentStep && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { borderRadius: "14px", background: TOUR_THEME.card, border: `1px solid ${TOUR_THEME.cardBorder}`, padding: "14px" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "15px", lineHeight: 1.55 }, children: tourCurrentStep.ask || tourCurrentStep.narration || tourCurrentStep.goal }) }),
|
|
10886
|
-
|
|
10985
|
+
tourReviewModeEnabled && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
10887
10986
|
"div",
|
|
10888
10987
|
{
|
|
10889
10988
|
style: {
|
|
@@ -11337,6 +11436,7 @@ function ModelNexOnboardingPanel({
|
|
|
11337
11436
|
}) {
|
|
11338
11437
|
const ctx = (0, import_react19.useContext)(ModelNexContext);
|
|
11339
11438
|
const serverUrl = ctx?.serverUrl ?? DEFAULT_MODELNEX_SERVER_URL;
|
|
11439
|
+
const devMode = ctx?.devMode ?? false;
|
|
11340
11440
|
const voice = useVoice(serverUrl);
|
|
11341
11441
|
const audioLevels = useAudioLevel(voice.isListening);
|
|
11342
11442
|
const [input, setInput] = (0, import_react19.useState)("");
|
|
@@ -11372,6 +11472,7 @@ function ModelNexOnboardingPanel({
|
|
|
11372
11472
|
handleVoiceInput: playback.handleVoiceInput
|
|
11373
11473
|
});
|
|
11374
11474
|
const reviewToggle = getReviewModeToggleConfig(playback.playbackState);
|
|
11475
|
+
const reviewModeEnabled = isReviewModeEnabled(devMode, playback.isReviewMode);
|
|
11375
11476
|
(0, import_react19.useEffect)(() => {
|
|
11376
11477
|
playbackVoiceRoutingRef.current = {
|
|
11377
11478
|
isReviewMode: playback.isReviewMode,
|
|
@@ -11796,7 +11897,7 @@ function ModelNexOnboardingPanel({
|
|
|
11796
11897
|
] })
|
|
11797
11898
|
] }),
|
|
11798
11899
|
sttError === "not-allowed" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "12px", color: "#b45309", lineHeight: 1.4, padding: "8px 12px", borderRadius: "10px", background: "#fef3c7" }, children: "Microphone blocked. Allow access in your browser to use voice commands." }),
|
|
11799
|
-
|
|
11900
|
+
reviewModeEnabled && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
11800
11901
|
"div",
|
|
11801
11902
|
{
|
|
11802
11903
|
style: {
|
|
@@ -11907,7 +12008,7 @@ function ModelNexOnboardingPanel({
|
|
|
11907
12008
|
] })
|
|
11908
12009
|
] }),
|
|
11909
12010
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { padding: "0 18px 18px", display: "flex", gap: "8px" }, children: [
|
|
11910
|
-
|
|
12011
|
+
reviewModeEnabled && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
11911
12012
|
"button",
|
|
11912
12013
|
{
|
|
11913
12014
|
type: "button",
|
|
@@ -11934,7 +12035,7 @@ function ModelNexOnboardingPanel({
|
|
|
11934
12035
|
"button",
|
|
11935
12036
|
{
|
|
11936
12037
|
onClick: playback.repeatStep,
|
|
11937
|
-
style: { flex:
|
|
12038
|
+
style: { flex: reviewModeEnabled ? 0.6 : 1, borderRadius: "12px", border: "1px solid rgba(15,23,42,0.12)", background: "#fff", padding: "11px 14px", cursor: "pointer", fontWeight: 600 },
|
|
11938
12039
|
children: "Repeat"
|
|
11939
12040
|
}
|
|
11940
12041
|
),
|
package/dist/index.mjs
CHANGED
|
@@ -3094,6 +3094,22 @@ function createTourSocketPool({
|
|
|
3094
3094
|
}
|
|
3095
3095
|
var tourSocketPool = createTourSocketPool();
|
|
3096
3096
|
|
|
3097
|
+
// src/utils/reviewModeToggle.ts
|
|
3098
|
+
function isReviewModeEnabled(devMode, requestedReviewMode) {
|
|
3099
|
+
return Boolean(devMode && requestedReviewMode);
|
|
3100
|
+
}
|
|
3101
|
+
function getReviewModeToggleConfig(playbackState) {
|
|
3102
|
+
const isPaused = playbackState === "paused";
|
|
3103
|
+
return {
|
|
3104
|
+
icon: isPaused ? "\u25B6" : "\u23F8",
|
|
3105
|
+
label: isPaused ? "Continue Workflow" : "Pause for Feedback",
|
|
3106
|
+
shouldResume: isPaused
|
|
3107
|
+
};
|
|
3108
|
+
}
|
|
3109
|
+
function shouldCaptureReviewDraft(isReviewMode, playbackState) {
|
|
3110
|
+
return isReviewMode && playbackState === "paused";
|
|
3111
|
+
}
|
|
3112
|
+
|
|
3097
3113
|
// src/utils/tourTransport.ts
|
|
3098
3114
|
function compactCaptureEventForTransport(event) {
|
|
3099
3115
|
return {
|
|
@@ -3515,6 +3531,20 @@ function isValueBearingElement(element) {
|
|
|
3515
3531
|
element && (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)
|
|
3516
3532
|
);
|
|
3517
3533
|
}
|
|
3534
|
+
var DEFAULT_TEXT_INPUT_IDLE_COMMIT_MS = 700;
|
|
3535
|
+
var DEFAULT_SELECTION_INPUT_IDLE_COMMIT_MS = 250;
|
|
3536
|
+
function getManualInputCommitPolicy(target) {
|
|
3537
|
+
const tagName = String(target.tagName || "").toLowerCase();
|
|
3538
|
+
const role = String(target.role || "").toLowerCase();
|
|
3539
|
+
const inputType = String(target.type || "").toLowerCase();
|
|
3540
|
+
const isContentEditable = Boolean(target.isContentEditable);
|
|
3541
|
+
const isSelectionLike = tagName === "select" || role === "combobox" || ["checkbox", "radio", "range", "color", "date", "datetime-local", "month", "time", "week"].includes(inputType);
|
|
3542
|
+
return {
|
|
3543
|
+
idleCommitMs: isSelectionLike ? DEFAULT_SELECTION_INPUT_IDLE_COMMIT_MS : DEFAULT_TEXT_INPUT_IDLE_COMMIT_MS,
|
|
3544
|
+
commitOnBlur: !isSelectionLike || tagName === "select" || role === "combobox" || isContentEditable,
|
|
3545
|
+
commitOnChange: true
|
|
3546
|
+
};
|
|
3547
|
+
}
|
|
3518
3548
|
function resolveWaitTargetElement(element) {
|
|
3519
3549
|
if (isValueBearingElement(element) || element.isContentEditable) {
|
|
3520
3550
|
return element;
|
|
@@ -3534,9 +3564,40 @@ function readWaitTargetValue(element) {
|
|
|
3534
3564
|
if (isValueBearingElement(element)) {
|
|
3535
3565
|
return element.value.trim();
|
|
3536
3566
|
}
|
|
3567
|
+
const genericValue = element.value;
|
|
3568
|
+
if (typeof genericValue === "string") {
|
|
3569
|
+
return genericValue.trim();
|
|
3570
|
+
}
|
|
3571
|
+
if (typeof genericValue === "number" && Number.isFinite(genericValue)) {
|
|
3572
|
+
return String(genericValue).trim();
|
|
3573
|
+
}
|
|
3537
3574
|
if (element.isContentEditable) {
|
|
3538
3575
|
return (element.textContent || "").trim();
|
|
3539
3576
|
}
|
|
3577
|
+
const ariaValueText = element.getAttribute("aria-valuetext");
|
|
3578
|
+
if (typeof ariaValueText === "string" && ariaValueText.trim()) {
|
|
3579
|
+
return ariaValueText.trim();
|
|
3580
|
+
}
|
|
3581
|
+
const ariaValueNow = element.getAttribute("aria-valuenow");
|
|
3582
|
+
if (typeof ariaValueNow === "string" && ariaValueNow.trim()) {
|
|
3583
|
+
return ariaValueNow.trim();
|
|
3584
|
+
}
|
|
3585
|
+
if (element.getAttribute("role") === "textbox" || element.getAttribute("role") === "combobox") {
|
|
3586
|
+
const nestedControl = element.querySelector(
|
|
3587
|
+
'input:not([type="hidden"]):not([disabled]), textarea:not([disabled]), select:not([disabled]), [contenteditable="true"], [role="textbox"], [role="combobox"]'
|
|
3588
|
+
);
|
|
3589
|
+
if (nestedControl && nestedControl !== element) {
|
|
3590
|
+
const nestedValue = readWaitTargetValue(nestedControl);
|
|
3591
|
+
if (nestedValue) {
|
|
3592
|
+
return nestedValue;
|
|
3593
|
+
}
|
|
3594
|
+
}
|
|
3595
|
+
return (element.textContent || "").trim();
|
|
3596
|
+
}
|
|
3597
|
+
const shadowInput = findInputInShadowRoot(element);
|
|
3598
|
+
if (shadowInput) {
|
|
3599
|
+
return shadowInput.value.trim();
|
|
3600
|
+
}
|
|
3540
3601
|
return "";
|
|
3541
3602
|
}
|
|
3542
3603
|
function buildManualCompletionTranscript(step, eventName) {
|
|
@@ -3558,6 +3619,12 @@ function createManualWaitForTarget(rawTarget, eventName, step) {
|
|
|
3558
3619
|
const target = resolveWaitTargetElement(rawTarget);
|
|
3559
3620
|
const completionTranscript = buildManualCompletionTranscript(step, eventName);
|
|
3560
3621
|
const isInputLikeEvent = isInputLikeWait(eventName, step);
|
|
3622
|
+
const commitPolicy = getManualInputCommitPolicy({
|
|
3623
|
+
tagName: target.tagName,
|
|
3624
|
+
role: target.getAttribute("role"),
|
|
3625
|
+
type: target.type ?? null,
|
|
3626
|
+
isContentEditable: target.isContentEditable
|
|
3627
|
+
});
|
|
3561
3628
|
if (isInputLikeEvent && readWaitTargetValue(target)) {
|
|
3562
3629
|
const initialValue = readWaitTargetValue(target);
|
|
3563
3630
|
return {
|
|
@@ -3569,6 +3636,8 @@ function createManualWaitForTarget(rawTarget, eventName, step) {
|
|
|
3569
3636
|
let cleanup = () => void 0;
|
|
3570
3637
|
const promise = new Promise((resolve) => {
|
|
3571
3638
|
const listeners2 = [];
|
|
3639
|
+
let observer = null;
|
|
3640
|
+
let idleTimer = null;
|
|
3572
3641
|
let settled = false;
|
|
3573
3642
|
const finish = () => {
|
|
3574
3643
|
if (settled) return;
|
|
@@ -3581,20 +3650,61 @@ function createManualWaitForTarget(rawTarget, eventName, step) {
|
|
|
3581
3650
|
listeners2.push({ node, type, handler });
|
|
3582
3651
|
};
|
|
3583
3652
|
if (isInputLikeEvent) {
|
|
3584
|
-
const
|
|
3653
|
+
const clearIdleCommit = () => {
|
|
3654
|
+
if (idleTimer) {
|
|
3655
|
+
clearTimeout(idleTimer);
|
|
3656
|
+
idleTimer = null;
|
|
3657
|
+
}
|
|
3658
|
+
};
|
|
3659
|
+
const scheduleIdleCommit = () => {
|
|
3660
|
+
const currentValue = readWaitTargetValue(target);
|
|
3661
|
+
if (!currentValue) {
|
|
3662
|
+
clearIdleCommit();
|
|
3663
|
+
return;
|
|
3664
|
+
}
|
|
3665
|
+
clearIdleCommit();
|
|
3666
|
+
idleTimer = setTimeout(() => {
|
|
3667
|
+
idleTimer = null;
|
|
3668
|
+
finish();
|
|
3669
|
+
}, commitPolicy.idleCommitMs);
|
|
3670
|
+
};
|
|
3671
|
+
const handleImmediateCommitEvent = () => {
|
|
3585
3672
|
const currentValue = readWaitTargetValue(target);
|
|
3586
3673
|
if (currentValue) {
|
|
3674
|
+
clearIdleCommit();
|
|
3587
3675
|
finish();
|
|
3588
3676
|
}
|
|
3589
3677
|
};
|
|
3590
|
-
addListener(target, "input",
|
|
3591
|
-
|
|
3592
|
-
|
|
3678
|
+
addListener(target, "input", scheduleIdleCommit);
|
|
3679
|
+
if (commitPolicy.commitOnChange) {
|
|
3680
|
+
addListener(target, "change", handleImmediateCommitEvent);
|
|
3681
|
+
}
|
|
3682
|
+
if (commitPolicy.commitOnBlur) {
|
|
3683
|
+
addListener(target, "blur", handleImmediateCommitEvent);
|
|
3684
|
+
}
|
|
3685
|
+
if (typeof MutationObserver !== "undefined") {
|
|
3686
|
+
observer = new MutationObserver(() => {
|
|
3687
|
+
scheduleIdleCommit();
|
|
3688
|
+
});
|
|
3689
|
+
observer.observe(target, {
|
|
3690
|
+
subtree: true,
|
|
3691
|
+
childList: true,
|
|
3692
|
+
characterData: true,
|
|
3693
|
+
attributes: true,
|
|
3694
|
+
attributeFilter: ["value", "aria-valuetext", "aria-valuenow", "aria-activedescendant"]
|
|
3695
|
+
});
|
|
3696
|
+
}
|
|
3593
3697
|
} else {
|
|
3594
3698
|
const handleActionEvent = () => finish();
|
|
3595
3699
|
addListener(target, eventName, handleActionEvent);
|
|
3596
3700
|
}
|
|
3597
3701
|
cleanup = () => {
|
|
3702
|
+
if (idleTimer) {
|
|
3703
|
+
clearTimeout(idleTimer);
|
|
3704
|
+
idleTimer = null;
|
|
3705
|
+
}
|
|
3706
|
+
observer?.disconnect();
|
|
3707
|
+
observer = null;
|
|
3598
3708
|
listeners2.forEach(({ node, type, handler }) => node.removeEventListener(type, handler));
|
|
3599
3709
|
listeners2.length = 0;
|
|
3600
3710
|
};
|
|
@@ -4615,7 +4725,7 @@ function useTourPlayback({
|
|
|
4615
4725
|
}
|
|
4616
4726
|
claimedPlaybackOwnerKeyRef.current = ownerKey;
|
|
4617
4727
|
startRequestedRef.current = true;
|
|
4618
|
-
const shouldReview = Boolean(options?.reviewMode);
|
|
4728
|
+
const shouldReview = isReviewModeEnabled(devModeRef.current, Boolean(options?.reviewMode));
|
|
4619
4729
|
resetCaptionSuppression();
|
|
4620
4730
|
setReviewStatusMessage(null);
|
|
4621
4731
|
setIsReviewMode(shouldReview);
|
|
@@ -8592,19 +8702,6 @@ function isTourListeningSessionActive(state) {
|
|
|
8592
8702
|
return state.isTourActive || state.isOnboardingActive || Boolean(state.startingExperienceType);
|
|
8593
8703
|
}
|
|
8594
8704
|
|
|
8595
|
-
// src/utils/reviewModeToggle.ts
|
|
8596
|
-
function getReviewModeToggleConfig(playbackState) {
|
|
8597
|
-
const isPaused = playbackState === "paused";
|
|
8598
|
-
return {
|
|
8599
|
-
icon: isPaused ? "\u25B6" : "\u23F8",
|
|
8600
|
-
label: isPaused ? "Continue Workflow" : "Pause for Feedback",
|
|
8601
|
-
shouldResume: isPaused
|
|
8602
|
-
};
|
|
8603
|
-
}
|
|
8604
|
-
function shouldCaptureReviewDraft(isReviewMode, playbackState) {
|
|
8605
|
-
return isReviewMode && playbackState === "paused";
|
|
8606
|
-
}
|
|
8607
|
-
|
|
8608
8705
|
// src/utils/reviewVoiceRouting.ts
|
|
8609
8706
|
function resolveSinglePlaybackTranscriptTarget(snapshot) {
|
|
8610
8707
|
return shouldCaptureReviewDraft(snapshot.isReviewMode, snapshot.playbackState) ? "review_draft" : "playback";
|
|
@@ -9401,6 +9498,7 @@ function ModelNexChatBubble({
|
|
|
9401
9498
|
const tourPlayback = useMemo3(() => createPlaybackView("tour"), [createPlaybackView]);
|
|
9402
9499
|
const onboardingPlayback = useMemo3(() => createPlaybackView("onboarding"), [createPlaybackView]);
|
|
9403
9500
|
const tourReviewToggle = getReviewModeToggleConfig(tourPlayback.playbackState);
|
|
9501
|
+
const tourReviewModeEnabled = isReviewModeEnabled(devMode, tourPlayback.isReviewMode);
|
|
9404
9502
|
const lastAutoTaggedUrlRef = useRef13(null);
|
|
9405
9503
|
const handleAutoTag = useCallback12(async () => {
|
|
9406
9504
|
if (!ctx) return;
|
|
@@ -9448,6 +9546,7 @@ function ModelNexChatBubble({
|
|
|
9448
9546
|
}
|
|
9449
9547
|
}, [authoringMode, handleAutoTag, ctx?.extractedElements.length, window.location.pathname]);
|
|
9450
9548
|
const onboardingReviewToggle = getReviewModeToggleConfig(onboardingPlayback.playbackState);
|
|
9549
|
+
const onboardingReviewModeEnabled = isReviewModeEnabled(devMode, onboardingPlayback.isReviewMode);
|
|
9451
9550
|
const pendingPrompt = playbackController.pendingPrompt;
|
|
9452
9551
|
const pendingNotificationType = (onboardingPlayback.pendingTour || tourPlayback.pendingTour)?.notificationType ?? "bubble_card";
|
|
9453
9552
|
const isPlaybackActive = tourPlayback.isActive || onboardingPlayback.isActive;
|
|
@@ -10217,7 +10316,7 @@ function ModelNexChatBubble({
|
|
|
10217
10316
|
]
|
|
10218
10317
|
}
|
|
10219
10318
|
) }),
|
|
10220
|
-
tourPlayback.isActive &&
|
|
10319
|
+
tourPlayback.isActive && tourReviewModeEnabled && /* @__PURE__ */ jsxs3(
|
|
10221
10320
|
"div",
|
|
10222
10321
|
{
|
|
10223
10322
|
style: {
|
|
@@ -10512,7 +10611,7 @@ function ModelNexChatBubble({
|
|
|
10512
10611
|
] })
|
|
10513
10612
|
] })
|
|
10514
10613
|
] }),
|
|
10515
|
-
|
|
10614
|
+
onboardingReviewModeEnabled && /* @__PURE__ */ jsxs3(
|
|
10516
10615
|
"div",
|
|
10517
10616
|
{
|
|
10518
10617
|
style: {
|
|
@@ -10618,7 +10717,7 @@ function ModelNexChatBubble({
|
|
|
10618
10717
|
}
|
|
10619
10718
|
),
|
|
10620
10719
|
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
10621
|
-
!
|
|
10720
|
+
!onboardingReviewModeEnabled && /* @__PURE__ */ jsx4(
|
|
10622
10721
|
"button",
|
|
10623
10722
|
{
|
|
10624
10723
|
onClick: onboardingPlayback.repeatStep,
|
|
@@ -10630,7 +10729,7 @@ function ModelNexChatBubble({
|
|
|
10630
10729
|
"button",
|
|
10631
10730
|
{
|
|
10632
10731
|
onClick: onboardingPlayback.skipTour,
|
|
10633
|
-
style: { flex:
|
|
10732
|
+
style: { flex: onboardingReviewModeEnabled ? 1 : 0.6, borderRadius: "12px", border: "1px solid rgba(220,38,38,0.18)", background: "#fff5f5", color: "#b91c1c", padding: "11px 14px", cursor: "pointer", fontWeight: 700, fontSize: "13px" },
|
|
10634
10733
|
children: "Exit"
|
|
10635
10734
|
}
|
|
10636
10735
|
)
|
|
@@ -10671,7 +10770,7 @@ function ModelNexChatBubble({
|
|
|
10671
10770
|
) })
|
|
10672
10771
|
] }),
|
|
10673
10772
|
tourCurrentStep && /* @__PURE__ */ jsx4("div", { style: { borderRadius: "14px", background: TOUR_THEME.card, border: `1px solid ${TOUR_THEME.cardBorder}`, padding: "14px" }, children: /* @__PURE__ */ jsx4("div", { style: { fontSize: "15px", lineHeight: 1.55 }, children: tourCurrentStep.ask || tourCurrentStep.narration || tourCurrentStep.goal }) }),
|
|
10674
|
-
|
|
10773
|
+
tourReviewModeEnabled && /* @__PURE__ */ jsxs3(
|
|
10675
10774
|
"div",
|
|
10676
10775
|
{
|
|
10677
10776
|
style: {
|
|
@@ -11125,6 +11224,7 @@ function ModelNexOnboardingPanel({
|
|
|
11125
11224
|
}) {
|
|
11126
11225
|
const ctx = useContext6(ModelNexContext);
|
|
11127
11226
|
const serverUrl = ctx?.serverUrl ?? DEFAULT_MODELNEX_SERVER_URL;
|
|
11227
|
+
const devMode = ctx?.devMode ?? false;
|
|
11128
11228
|
const voice = useVoice(serverUrl);
|
|
11129
11229
|
const audioLevels = useAudioLevel(voice.isListening);
|
|
11130
11230
|
const [input, setInput] = useState14("");
|
|
@@ -11160,6 +11260,7 @@ function ModelNexOnboardingPanel({
|
|
|
11160
11260
|
handleVoiceInput: playback.handleVoiceInput
|
|
11161
11261
|
});
|
|
11162
11262
|
const reviewToggle = getReviewModeToggleConfig(playback.playbackState);
|
|
11263
|
+
const reviewModeEnabled = isReviewModeEnabled(devMode, playback.isReviewMode);
|
|
11163
11264
|
useEffect18(() => {
|
|
11164
11265
|
playbackVoiceRoutingRef.current = {
|
|
11165
11266
|
isReviewMode: playback.isReviewMode,
|
|
@@ -11584,7 +11685,7 @@ function ModelNexOnboardingPanel({
|
|
|
11584
11685
|
] })
|
|
11585
11686
|
] }),
|
|
11586
11687
|
sttError === "not-allowed" && /* @__PURE__ */ jsx5("div", { style: { fontSize: "12px", color: "#b45309", lineHeight: 1.4, padding: "8px 12px", borderRadius: "10px", background: "#fef3c7" }, children: "Microphone blocked. Allow access in your browser to use voice commands." }),
|
|
11587
|
-
|
|
11688
|
+
reviewModeEnabled && /* @__PURE__ */ jsxs4(
|
|
11588
11689
|
"div",
|
|
11589
11690
|
{
|
|
11590
11691
|
style: {
|
|
@@ -11695,7 +11796,7 @@ function ModelNexOnboardingPanel({
|
|
|
11695
11796
|
] })
|
|
11696
11797
|
] }),
|
|
11697
11798
|
/* @__PURE__ */ jsxs4("div", { style: { padding: "0 18px 18px", display: "flex", gap: "8px" }, children: [
|
|
11698
|
-
|
|
11799
|
+
reviewModeEnabled && /* @__PURE__ */ jsxs4(
|
|
11699
11800
|
"button",
|
|
11700
11801
|
{
|
|
11701
11802
|
type: "button",
|
|
@@ -11722,7 +11823,7 @@ function ModelNexOnboardingPanel({
|
|
|
11722
11823
|
"button",
|
|
11723
11824
|
{
|
|
11724
11825
|
onClick: playback.repeatStep,
|
|
11725
|
-
style: { flex:
|
|
11826
|
+
style: { flex: reviewModeEnabled ? 0.6 : 1, borderRadius: "12px", border: "1px solid rgba(15,23,42,0.12)", background: "#fff", padding: "11px 14px", cursor: "pointer", fontWeight: 600 },
|
|
11726
11827
|
children: "Repeat"
|
|
11727
11828
|
}
|
|
11728
11829
|
),
|