@modelnex/sdk 0.5.28 → 0.5.29

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.mjs CHANGED
@@ -27,6 +27,60 @@ function resolveSocketIoTransports(serverUrl, order) {
27
27
 
28
28
  // src/auto-extract.ts
29
29
  import { useState, useEffect as useEffect2, useRef as useRef2, useCallback as useCallback2 } from "react";
30
+
31
+ // src/utils/dev-logging.ts
32
+ function isSdkDebugEnabled(devMode) {
33
+ if (devMode) return true;
34
+ if (typeof window !== "undefined" && Boolean(window.MODELNEX_DEBUG)) {
35
+ return true;
36
+ }
37
+ return process.env.NODE_ENV === "development";
38
+ }
39
+ function emitSdkDebugLog(message, payload, options) {
40
+ if (!isSdkDebugEnabled(options?.devMode)) return;
41
+ if (payload && Object.keys(payload).length > 0) {
42
+ console.log(message, payload);
43
+ } else {
44
+ console.log(message);
45
+ }
46
+ if (options?.dispatchEvent && typeof window !== "undefined") {
47
+ window.dispatchEvent(new CustomEvent("modelnex-debug", { detail: { msg: message, data: payload } }));
48
+ }
49
+ }
50
+ function sanitizeActionList(actions) {
51
+ if (!Array.isArray(actions) || actions.length === 0) return void 0;
52
+ return actions.map(({ actionId }) => ({ actionId }));
53
+ }
54
+ function sanitizeAgentDebug(debug) {
55
+ if (!debug) return void 0;
56
+ const actions = sanitizeActionList(debug.actions);
57
+ const traces = Array.isArray(debug.traces) && debug.traces.length > 0 ? debug.traces.map((trace) => ({
58
+ step: trace.step,
59
+ actions: sanitizeActionList(trace.actions) ?? [],
60
+ results: Array.isArray(trace.results) && trace.results.length > 0 ? trace.results.map(({ actionId, success }) => ({ actionId, success })) : void 0
61
+ })) : void 0;
62
+ if ((!actions || actions.length === 0) && (!traces || traces.length === 0)) {
63
+ return void 0;
64
+ }
65
+ return {
66
+ ...actions ? { actions } : {},
67
+ ...traces ? { traces } : {}
68
+ };
69
+ }
70
+ function sanitizeChatMessages(messages, devMode) {
71
+ const includeDebug = isSdkDebugEnabled(devMode);
72
+ return messages.map((message) => {
73
+ if (message.role !== "assistant") {
74
+ return message;
75
+ }
76
+ return {
77
+ ...message,
78
+ debug: includeDebug ? sanitizeAgentDebug(message.debug) : void 0
79
+ };
80
+ });
81
+ }
82
+
83
+ // src/auto-extract.ts
30
84
  function simpleHash(str) {
31
85
  let hash = 0;
32
86
  for (let i = 0; i < str.length; i++) {
@@ -290,7 +344,7 @@ function extractInteractiveElements() {
290
344
  }
291
345
  return elements;
292
346
  }
293
- function useAutoExtract() {
347
+ function useAutoExtract(devMode) {
294
348
  const [elements, setElements] = useState([]);
295
349
  const timerRef = useRef2(null);
296
350
  const lastSnapshotRef = useRef2("");
@@ -308,9 +362,11 @@ function useAutoExtract() {
308
362
  })));
309
363
  if (snapshot === lastSnapshotRef.current) return;
310
364
  lastSnapshotRef.current = snapshot;
311
- console.log(`[ModelNex AutoExtract] Found ${extracted.length} interactive elements`, extracted.map((e) => ({ fp: e.fingerprint, role: e.role, text: e.text.slice(0, 30) })));
365
+ emitSdkDebugLog("[ModelNex AutoExtract] Scan complete", {
366
+ elementCount: extracted.length
367
+ }, { devMode });
312
368
  setElements(extracted);
313
- }, []);
369
+ }, [devMode]);
314
370
  useEffect2(() => {
315
371
  const initialTimer = setTimeout(scan, 300);
316
372
  const observer = new MutationObserver((mutations) => {
@@ -625,7 +681,8 @@ function useModelNexSocket({
625
681
  setStagingFields,
626
682
  setExecutedFields,
627
683
  onSocketId,
628
- websiteId
684
+ websiteId,
685
+ devMode
629
686
  }) {
630
687
  const socketRef = useRef3(null);
631
688
  const actionsRef = useRef3(actions);
@@ -658,12 +715,14 @@ function useModelNexSocket({
658
715
  allTaggedElements: tagsRef.current ? Array.from(tagsRef.current.values()) : void 0
659
716
  });
660
717
  socket.on("connect", () => {
661
- console.log("ModelNex SDK: Connected to agent server", socket.id);
718
+ emitSdkDebugLog("[ModelNex SDK] Connected to agent server", {
719
+ socketId: socket.id ?? null
720
+ }, { devMode });
662
721
  onSocketId?.(socket.id || null);
663
722
  socket.emit("client:sync", buildSyncPayload());
664
723
  });
665
724
  socket.on("disconnect", () => {
666
- console.log("ModelNex SDK: Disconnected from agent server");
725
+ emitSdkDebugLog("[ModelNex SDK] Disconnected from agent server", void 0, { devMode });
667
726
  onSocketId?.(null);
668
727
  });
669
728
  socket.on("agent:request_context", () => {
@@ -689,12 +748,11 @@ function useModelNexSocket({
689
748
  reasoning
690
749
  }) => {
691
750
  const log = (msg, data) => {
692
- console.log(msg, data ?? "");
693
- window.dispatchEvent(new CustomEvent("modelnex-debug", { detail: { msg, data } }));
751
+ emitSdkDebugLog(msg, data, { devMode, dispatchEvent: true });
694
752
  };
695
753
  if (reasoning || params?.fingerprint) {
696
754
  window.dispatchEvent(new CustomEvent("modelnex-action-start", {
697
- detail: { actionId, fingerprint: params?.fingerprint ?? null, reasoning: reasoning ?? "" }
755
+ detail: { actionId, fingerprint: params?.fingerprint ?? null }
698
756
  }));
699
757
  }
700
758
  const sendResult = (success, result, error) => {
@@ -705,17 +763,18 @@ function useModelNexSocket({
705
763
  const currentActions = actionsRef.current;
706
764
  log("[SDK] agent:execute received", {
707
765
  actionId,
708
- params,
709
- registeredActions: Array.from(currentActions.keys())
766
+ executionId: executionId ?? null,
767
+ fieldId: fieldId ?? null,
768
+ hasParams: params != null
710
769
  });
711
770
  const NAV_ACTION_IDS = ["navigate_to_documents", "navigate_to_templates", "navigate_to_inbox", "navigate_to_settings", "navigate_to_template", "navigate_to_document", "navigate_to_folder", "navigate_editor_step"];
712
771
  const action = currentActions.get(actionId);
713
772
  if (action) {
714
773
  try {
715
774
  const validatedParams = action.schema.parse(params);
716
- log("[SDK] Executing", { actionId, validatedParams });
775
+ log("[SDK] Executing action", { actionId });
717
776
  const execResult = await action.execute(validatedParams);
718
- log("[SDK] Execute completed", { actionId });
777
+ log("[SDK] Action completed", { actionId });
719
778
  sendResult(true, execResult);
720
779
  if (NAV_ACTION_IDS.includes(actionId)) {
721
780
  requestAnimationFrame(() => {
@@ -739,25 +798,29 @@ function useModelNexSocket({
739
798
  }
740
799
  } catch (err) {
741
800
  const errMsg = err instanceof Error ? err.message : String(err);
742
- console.error(`[ModelNex SDK] Execution failed for ${actionId}`, err);
801
+ console.error(`[ModelNex SDK] Execution failed for ${actionId}: ${errMsg}`);
802
+ if (isSdkDebugEnabled(devMode)) {
803
+ window.dispatchEvent(
804
+ new CustomEvent("modelnex-debug", {
805
+ detail: { msg: "[SDK] Execution failed", data: { actionId, error: errMsg } }
806
+ })
807
+ );
808
+ }
809
+ sendResult(false, void 0, errMsg);
810
+ }
811
+ } else {
812
+ const errMsg = `Action not found: ${actionId}`;
813
+ console.warn(`[ModelNex SDK] ${errMsg}`);
814
+ if (isSdkDebugEnabled(devMode)) {
743
815
  window.dispatchEvent(
744
816
  new CustomEvent("modelnex-debug", {
745
- detail: { msg: "[SDK] Execution failed", data: { actionId, error: errMsg } }
817
+ detail: {
818
+ msg: "[SDK] Action not found",
819
+ data: { actionId }
820
+ }
746
821
  })
747
822
  );
748
- sendResult(false, void 0, errMsg);
749
823
  }
750
- } else {
751
- const errMsg = `Action not found: ${actionId}`;
752
- console.warn("[ModelNex SDK]", errMsg, "Available:", Array.from(currentActions.keys()));
753
- window.dispatchEvent(
754
- new CustomEvent("modelnex-debug", {
755
- detail: {
756
- msg: "[SDK] Action not found",
757
- data: { actionId, available: Array.from(actions.keys()) }
758
- }
759
- })
760
- );
761
824
  sendResult(false, void 0, errMsg);
762
825
  }
763
826
  }
@@ -2486,6 +2549,56 @@ function useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl
2486
2549
  // src/constants.ts
2487
2550
  var DEFAULT_MODELNEX_SERVER_URL = "https://api.modelnex.com";
2488
2551
 
2552
+ // src/utils/dev-mode.ts
2553
+ var DEV_MODE_KEY_GLOBAL_NAMES = ["__MODELNEX_DEV_MODE_KEY__", "MODELNEX_DEV_MODE_KEY"];
2554
+ var devModeValidationCache = /* @__PURE__ */ new Map();
2555
+ function normalizeDevModeKey(value) {
2556
+ if (typeof value !== "string") return void 0;
2557
+ const normalized = value.trim();
2558
+ return normalized || void 0;
2559
+ }
2560
+ function resolveInjectedDevModeKey(explicitDevModeKey) {
2561
+ const normalizedExplicitKey = normalizeDevModeKey(explicitDevModeKey);
2562
+ if (normalizedExplicitKey) return normalizedExplicitKey;
2563
+ if (typeof window === "undefined") return void 0;
2564
+ const browserWindow = window;
2565
+ for (const globalName of DEV_MODE_KEY_GLOBAL_NAMES) {
2566
+ const normalizedGlobalKey = normalizeDevModeKey(browserWindow[globalName]);
2567
+ if (normalizedGlobalKey) return normalizedGlobalKey;
2568
+ }
2569
+ const scriptInjectedKey = typeof document !== "undefined" ? normalizeDevModeKey(
2570
+ document.querySelector("script[data-modelnex-dev-mode-key]")?.dataset.modelnexDevModeKey
2571
+ ) : void 0;
2572
+ if (scriptInjectedKey) return scriptInjectedKey;
2573
+ return void 0;
2574
+ }
2575
+ async function validateInjectedDevModeKey(serverUrl, websiteId, devModeKey) {
2576
+ const normalizedWebsiteId = websiteId.trim();
2577
+ const normalizedDevModeKey = devModeKey.trim();
2578
+ if (!normalizedWebsiteId || !normalizedDevModeKey) return false;
2579
+ const cacheKey = `${serverUrl}::${normalizedWebsiteId}::${normalizedDevModeKey}`;
2580
+ const cached = devModeValidationCache.get(cacheKey);
2581
+ if (cached) {
2582
+ return cached;
2583
+ }
2584
+ const validationPromise = fetch(
2585
+ `${serverUrl.replace(/\/$/, "")}/api/websites/${encodeURIComponent(normalizedWebsiteId)}/dev-mode/verify`,
2586
+ {
2587
+ method: "POST",
2588
+ headers: {
2589
+ "Content-Type": "application/json"
2590
+ },
2591
+ body: JSON.stringify({ key: normalizedDevModeKey })
2592
+ }
2593
+ ).then(async (response) => {
2594
+ if (!response.ok) return false;
2595
+ const payload = await response.json().catch(() => null);
2596
+ return payload?.enabled === true;
2597
+ }).catch(() => false);
2598
+ devModeValidationCache.set(cacheKey, validationPromise);
2599
+ return validationPromise;
2600
+ }
2601
+
2489
2602
  // src/hooks/useRunCommand.ts
2490
2603
  import { useCallback as useCallback5, useContext as useContext2 } from "react";
2491
2604
  function searchTaggedElementsForQuery(store, query, limit = 8) {
@@ -2528,7 +2641,10 @@ function useRunCommand(serverUrlOverride) {
2528
2641
  if (!res.ok) {
2529
2642
  throw new Error(data?.error ?? `Request failed: ${res.status}`);
2530
2643
  }
2531
- return data;
2644
+ return {
2645
+ ...data,
2646
+ debug: sanitizeAgentDebug(data?.debug)
2647
+ };
2532
2648
  },
2533
2649
  [baseUrl, tagStore]
2534
2650
  );
@@ -3436,7 +3552,9 @@ function useTourPlayback({
3436
3552
  const socket = tourSocketPool.acquire(serverUrl);
3437
3553
  socketRef.current = socket;
3438
3554
  const handleConnect = () => {
3439
- console.log("[TourClient] Connected to tour agent server:", socket.id);
3555
+ emitSdkDebugLog("[TourClient] Connected to tour agent server", {
3556
+ socketId: socket.id ?? null
3557
+ }, { devMode: devModeRef.current });
3440
3558
  const profile = userProfileRef.current;
3441
3559
  const currentWebsiteId = websiteIdRef.current;
3442
3560
  if (currentWebsiteId && profile?.userId) {
@@ -3453,7 +3571,9 @@ function useTourPlayback({
3453
3571
  setServerState(payload);
3454
3572
  };
3455
3573
  const handleCommandCancel = (payload) => {
3456
- console.log("[TourClient] Received command_cancel:", payload);
3574
+ emitSdkDebugLog("[TourClient] Received command cancel", {
3575
+ commandBatchId: payload.commandBatchId ?? null
3576
+ }, { devMode: devModeRef.current });
3457
3577
  if (payload.commandBatchId && activeCommandBatchIdRef.current === payload.commandBatchId) {
3458
3578
  activeCommandBatchIdRef.current = null;
3459
3579
  activeExecutionTokenRef.current++;
@@ -3468,14 +3588,22 @@ function useTourPlayback({
3468
3588
  const ownerKey = createTourPlaybackOwnerKey(serverUrl, websiteIdRef.current, experienceTypeRef.current);
3469
3589
  if (!shouldExecuteTourCommandBatch(isActiveRef.current) || !hasTourPlaybackOwnership(ownerKey, playbackOwnerIdRef.current)) {
3470
3590
  const activeType = experienceTypeRef.current;
3471
- console.log("[TourClient] Ignoring command batch for inactive playback hook:", activeType, payload.stepIndex);
3591
+ emitSdkDebugLog("[TourClient] Ignoring command batch for inactive playback hook", {
3592
+ experienceType: activeType,
3593
+ stepIndex: payload.stepIndex
3594
+ }, { devMode: devModeRef.current });
3472
3595
  return;
3473
3596
  }
3474
3597
  const emitIfOpen = (ev, data) => {
3475
3598
  if (socketRef.current !== socket) return;
3476
3599
  emitSocketEvent(socket, ev, data);
3477
3600
  };
3478
- console.log("[TourClient] Received command batch:", payload.stepIndex, payload.commands);
3601
+ const commandBatchId = payload.commandBatchId ?? null;
3602
+ emitSdkDebugLog("[TourClient] Received command batch", {
3603
+ stepIndex: payload.stepIndex,
3604
+ commandCount: Array.isArray(payload.commands) ? payload.commands.length : 0,
3605
+ commandBatchId
3606
+ }, { devMode: devModeRef.current });
3479
3607
  runCleanup(pendingManualWaitCleanupRef.current);
3480
3608
  pendingManualWaitCleanupRef.current = null;
3481
3609
  if (voiceInputResolveRef.current) {
@@ -3485,7 +3613,6 @@ function useTourPlayback({
3485
3613
  }
3486
3614
  setPlaybackState("executing");
3487
3615
  commandInFlightRef.current = true;
3488
- const commandBatchId = payload.commandBatchId ?? null;
3489
3616
  turnIdRef.current = payload.turnId ?? turnIdRef.current;
3490
3617
  const clearCommandBatchId = () => {
3491
3618
  if (activeCommandBatchIdRef.current === commandBatchId) {
@@ -3531,7 +3658,7 @@ function useTourPlayback({
3531
3658
  }
3532
3659
  }
3533
3660
  if (!payload.commands || !Array.isArray(payload.commands)) {
3534
- console.warn("[TourClient] Payload commands is not an array:", payload);
3661
+ console.warn("[TourClient] Command batch payload was invalid.");
3535
3662
  commandInFlightRef.current = false;
3536
3663
  emitIfOpen("tour:action_result", {
3537
3664
  success: false,
@@ -3580,7 +3707,9 @@ function useTourPlayback({
3580
3707
  };
3581
3708
  const executeOne = async (action) => {
3582
3709
  assertNotInterrupted();
3583
- console.log("[TourClient] Executing action:", action?.type, action?.params ? JSON.stringify(action.params).slice(0, 120) : "");
3710
+ emitSdkDebugLog("[TourClient] Executing action", {
3711
+ actionType: action?.type ?? "unknown"
3712
+ }, { devMode: devModeRef.current });
3584
3713
  const currentStep = tourRef.current?.steps?.[stepIndexRef.current] ?? null;
3585
3714
  const executeTimeline = async (params = {}) => {
3586
3715
  const segments = Array.isArray(params.segments) ? params.segments : [];
@@ -3684,7 +3813,7 @@ function useTourPlayback({
3684
3813
  }
3685
3814
  removeHighlight();
3686
3815
  await performInteractiveClick(targetEl);
3687
- const { waitForDomSettle: waitForDomSettleClick } = await import("./dom-sync-L5KIP45X.mjs");
3816
+ const { waitForDomSettle: waitForDomSettleClick } = await import("./dom-sync-GABDEODR.mjs");
3688
3817
  await waitForDomSettleClick({ timeoutMs: 3e3, debounceMs: 300 });
3689
3818
  return { result: "clicked" };
3690
3819
  }
@@ -3721,7 +3850,7 @@ function useTourPlayback({
3721
3850
  throw new Error("navigate_to_url missing url");
3722
3851
  }
3723
3852
  await navigateToTourUrl(nextUrl);
3724
- const { waitForDomSettle: waitForDomSettleNav } = await import("./dom-sync-L5KIP45X.mjs");
3853
+ const { waitForDomSettle: waitForDomSettleNav } = await import("./dom-sync-GABDEODR.mjs");
3725
3854
  await waitForDomSettleNav({ timeoutMs: 3e3, debounceMs: 300 });
3726
3855
  return { result: nextUrl };
3727
3856
  }
@@ -3745,7 +3874,7 @@ function useTourPlayback({
3745
3874
  if (action.params?.wait !== false) {
3746
3875
  await res.json();
3747
3876
  }
3748
- const { waitForDomSettle } = await import("./dom-sync-L5KIP45X.mjs");
3877
+ const { waitForDomSettle } = await import("./dom-sync-GABDEODR.mjs");
3749
3878
  await waitForDomSettle({ timeoutMs: 3e3, debounceMs: 300 });
3750
3879
  await syncAOM();
3751
3880
  return { result: action.params?.command ?? "executed" };
@@ -3767,7 +3896,7 @@ function useTourPlayback({
3767
3896
  handleTourEnd();
3768
3897
  return { result: "ended" };
3769
3898
  }
3770
- console.warn("[TourClient] Unknown action type:", action?.type, "- skipping");
3899
+ console.warn(`[TourClient] Unknown action type: ${String(action?.type ?? "unknown")}. Skipping.`);
3771
3900
  return { result: "unknown_action_skipped" };
3772
3901
  };
3773
3902
  try {
@@ -3823,14 +3952,15 @@ function useTourPlayback({
3823
3952
  clearCommandBatchId();
3824
3953
  return;
3825
3954
  }
3826
- console.error("[TourClient] Command batch execution failed:", err);
3955
+ const errMsg = err instanceof Error ? err.message : String(err);
3956
+ console.error(`[TourClient] Command batch execution failed: ${errMsg}`);
3827
3957
  if (reviewModeRef.current && activeTourId && activePreviewRunId) {
3828
3958
  void logPreviewEvent(serverUrl, toursApiBaseRef.current, activeTourId, activePreviewRunId, websiteId, {
3829
3959
  stepOrder: stepIndexRef.current,
3830
3960
  eventType: "command_batch_failed",
3831
3961
  payload: {
3832
3962
  commandBatchId,
3833
- error: String(err),
3963
+ error: errMsg,
3834
3964
  partialResults: results
3835
3965
  },
3836
3966
  status: "active",
@@ -3840,7 +3970,7 @@ function useTourPlayback({
3840
3970
  emitIfOpen("tour:action_result", {
3841
3971
  success: false,
3842
3972
  reason: "execution_error",
3843
- error: String(err),
3973
+ error: errMsg,
3844
3974
  results,
3845
3975
  commandBatchId,
3846
3976
  runId: runIdRef.current,
@@ -3866,7 +3996,10 @@ function useTourPlayback({
3866
3996
  let manualWaitTarget = await resolveTargetElement2(waitTargetHints, currentStep);
3867
3997
  if (inputLikeWait && preferredWaitTarget && manualWaitTarget && manualWaitTarget !== preferredWaitTarget && !isEditableWaitTarget(manualWaitTarget) && isEditableWaitTarget(preferredWaitTarget)) {
3868
3998
  manualWaitTarget = preferredWaitTarget;
3869
- console.log("[TourClient] wait_for_input: preferring current editable target over hinted step target", manualWaitTarget);
3999
+ emitSdkDebugLog("[TourClient] wait_for_input preferred highlighted editable target", {
4000
+ stepIndex: stepIndexRef.current,
4001
+ event: waitEvent
4002
+ }, { devMode: devModeRef.current });
3870
4003
  }
3871
4004
  if (manualWaitTarget) {
3872
4005
  const manualWait = createManualWaitForTarget(manualWaitTarget, waitEvent, currentStep);
@@ -3880,7 +4013,10 @@ function useTourPlayback({
3880
4013
  manualWaitPromise = manualWait.promise;
3881
4014
  manualWaitKind = manualWait.kind;
3882
4015
  pendingManualWaitCleanupRef.current = manualWait.cleanup;
3883
- console.log("[TourClient] wait_for_input: using current editable target as fallback wait target", preferredWaitTarget);
4016
+ emitSdkDebugLog("[TourClient] wait_for_input using fallback editable target", {
4017
+ stepIndex: stepIndexRef.current,
4018
+ event: waitEvent
4019
+ }, { devMode: devModeRef.current });
3884
4020
  }
3885
4021
  if (!manualWaitPromise && inputLikeWait) {
3886
4022
  const firstInput = document.querySelector(
@@ -3891,7 +4027,10 @@ function useTourPlayback({
3891
4027
  manualWaitPromise = manualWait.promise;
3892
4028
  manualWaitKind = manualWait.kind;
3893
4029
  pendingManualWaitCleanupRef.current = manualWait.cleanup;
3894
- console.log("[TourClient] wait_for_input: no target found, falling back to first visible editable element", firstInput);
4030
+ emitSdkDebugLog("[TourClient] wait_for_input falling back to first editable element", {
4031
+ stepIndex: stepIndexRef.current,
4032
+ event: waitEvent
4033
+ }, { devMode: devModeRef.current });
3895
4034
  }
3896
4035
  }
3897
4036
  setPlaybackState(manualWaitKind ? "waiting_input" : "waiting_voice");
@@ -3936,7 +4075,7 @@ function useTourPlayback({
3936
4075
  if (!transcript) {
3937
4076
  return;
3938
4077
  }
3939
- const { waitForDomSettle } = await import("./dom-sync-L5KIP45X.mjs");
4078
+ const { waitForDomSettle } = await import("./dom-sync-GABDEODR.mjs");
3940
4079
  await waitForDomSettle({ timeoutMs: 1500, debounceMs: 200 });
3941
4080
  await syncAOM();
3942
4081
  emitIfOpen("tour:user_input", {
@@ -3973,12 +4112,17 @@ function useTourPlayback({
3973
4112
  const tour = tourData.tourContext ?? tourRef.current;
3974
4113
  const expType = experienceTypeRef.current;
3975
4114
  if (tour?.type && tour.type !== expType) {
3976
- console.log(`[TourClient] Ignoring ${tour.type} start (this hook is for ${expType})`);
4115
+ emitSdkDebugLog("[TourClient] Ignoring tour start for mismatched experience type", {
4116
+ incomingType: tour.type,
4117
+ hookType: expType
4118
+ }, { devMode: devModeRef.current });
3977
4119
  return;
3978
4120
  }
3979
4121
  const ownerKey = createTourPlaybackOwnerKey(serverUrl, websiteIdRef.current, expType);
3980
4122
  if (!claimTourPlaybackOwnership(ownerKey, playbackOwnerIdRef.current)) {
3981
- console.log(`[TourClient] Ignoring ${expType} start because another hook already owns playback`);
4123
+ emitSdkDebugLog("[TourClient] Ignoring tour start because playback ownership is already claimed", {
4124
+ experienceType: expType
4125
+ }, { devMode: devModeRef.current });
3982
4126
  return;
3983
4127
  }
3984
4128
  claimedPlaybackOwnerKeyRef.current = ownerKey;
@@ -4003,6 +4147,8 @@ function useTourPlayback({
4003
4147
  },
4004
4148
  currentStepOrder: 0
4005
4149
  });
4150
+ } else if (tour?.id && userProfile?.userId) {
4151
+ void recordTourEvent(serverUrl, toursApiBaseRef.current, tour.id, userProfile.userId, "started", websiteId);
4006
4152
  }
4007
4153
  try {
4008
4154
  const { generateMinifiedAOM: generateMinifiedAOM2 } = await import("./aom-HDYNCIOY.mjs");
@@ -4015,7 +4161,8 @@ function useTourPlayback({
4015
4161
  });
4016
4162
  }
4017
4163
  } catch (e) {
4018
- console.warn("[TourClient] Initial DOM sync failed:", e);
4164
+ const errMsg = e instanceof Error ? e.message : String(e);
4165
+ console.warn(`[TourClient] Initial DOM sync failed: ${errMsg}`);
4019
4166
  }
4020
4167
  };
4021
4168
  const handleTourUpdate = (payload) => {
@@ -4053,12 +4200,11 @@ function useTourPlayback({
4053
4200
  return;
4054
4201
  }
4055
4202
  if (isDev) {
4056
- console.log(`%c[ModelNex Tour] ${entry.type}`, "color: #3b82f6; font-weight: bold", entry);
4057
- if (typeof window !== "undefined") {
4058
- window.dispatchEvent(new CustomEvent("modelnex-debug", {
4059
- detail: { msg: `[Tour Timeline] ${entry.type}`, data: entry }
4060
- }));
4061
- }
4203
+ emitSdkDebugLog(`[Tour Timeline] ${entry.type}`, {
4204
+ stepIndex: entry?.data?.stepIndex ?? null,
4205
+ runId: entry?.data?.runId ?? null,
4206
+ turnId: entry?.data?.turnId ?? null
4207
+ }, { devMode: devModeRef.current, dispatchEvent: true });
4062
4208
  }
4063
4209
  };
4064
4210
  socket.on("connect", handleConnect);
@@ -4069,7 +4215,7 @@ function useTourPlayback({
4069
4215
  socket.on("tour:update", handleTourUpdate);
4070
4216
  socket.on("tour:end", handleTourEndEvent);
4071
4217
  socket.on("tour:debug_log", handleDebugLog);
4072
- console.log("[ModelNex SDK] Tour playback initialized. Debug logs enabled:", devModeRef.current || process.env.NODE_ENV === "development");
4218
+ emitSdkDebugLog("[ModelNex SDK] Tour playback initialized", void 0, { devMode: devModeRef.current });
4073
4219
  return () => {
4074
4220
  socket.off("connect", handleConnect);
4075
4221
  socket.off("tour:server_state", handleServerState);
@@ -4180,6 +4326,8 @@ function useTourPlayback({
4180
4326
  status: "stopped",
4181
4327
  currentStepOrder: stepIndexRef.current
4182
4328
  });
4329
+ } else if (tourRef.current?.id && userProfile?.userId) {
4330
+ void recordTourEvent(serverUrl, toursApiBaseRef.current, tourRef.current.id, userProfile.userId, "cancelled", websiteId);
4183
4331
  }
4184
4332
  if (reviewModeRef.current) {
4185
4333
  if (tourRef.current?.id) {
@@ -4252,7 +4400,9 @@ function useTourPlayback({
4252
4400
  isPlaybackActive: isActiveRef.current,
4253
4401
  startRequested: startRequestedRef.current
4254
4402
  })) {
4255
- console.log("[TourClient] Ignoring duplicate start request while playback is already active or starting:", tour.id);
4403
+ emitSdkDebugLog("[TourClient] Ignoring duplicate start request while playback is already active or starting", {
4404
+ tourId: tour.id
4405
+ }, { devMode: devModeRef.current });
4256
4406
  return;
4257
4407
  }
4258
4408
  setPendingTour(null);
@@ -4268,7 +4418,9 @@ function useTourPlayback({
4268
4418
  }
4269
4419
  const ownerKey = createTourPlaybackOwnerKey(serverUrl, websiteIdRef.current, tour.type ?? experienceTypeRef.current);
4270
4420
  if (!claimTourPlaybackOwnership(ownerKey, playbackOwnerIdRef.current)) {
4271
- console.log("[TourClient] Ignoring duplicate start request because another hook already owns this experience:", tour.id);
4421
+ emitSdkDebugLog("[TourClient] Ignoring duplicate start request because another hook already owns this experience", {
4422
+ tourId: tour.id
4423
+ }, { devMode: devModeRef.current });
4272
4424
  return;
4273
4425
  }
4274
4426
  claimedPlaybackOwnerKeyRef.current = ownerKey;
@@ -4291,7 +4443,8 @@ function useTourPlayback({
4291
4443
  setPreviewRunId(previewRun.id);
4292
4444
  previewRunIdRef.current = previewRun.id;
4293
4445
  } catch (err) {
4294
- console.warn("[TourClient] Failed to create preview run:", err);
4446
+ const errMsg = err instanceof Error ? err.message : String(err);
4447
+ console.warn(`[TourClient] Failed to create preview run: ${errMsg}`);
4295
4448
  setReviewStatusMessage("Preview review logging is unavailable.");
4296
4449
  setPreviewRunId(null);
4297
4450
  previewRunIdRef.current = null;
@@ -4340,7 +4493,7 @@ function useTourPlayback({
4340
4493
  if (!tour) {
4341
4494
  clearActiveDraftPreview(experienceType);
4342
4495
  persistSuppressedDraftPreview(draftPreview);
4343
- console.warn("[ModelNex] Tour fetch failed:", tourId, experienceType, "(Check ModelNex server is running and CORS allows this origin)");
4496
+ console.warn(`[ModelNex] Tour fetch failed for ${experienceType}:${tourId}. Check the ModelNex server and CORS configuration.`);
4344
4497
  return;
4345
4498
  }
4346
4499
  if (cancelled) {
@@ -4363,7 +4516,8 @@ function useTourPlayback({
4363
4516
  await runTour(tour, previewOptions);
4364
4517
  }
4365
4518
  } catch (err) {
4366
- console.warn("[ModelNex] Tour test failed:", err);
4519
+ const errMsg = err instanceof Error ? err.message : String(err);
4520
+ console.warn(`[ModelNex] Tour test failed: ${errMsg}`);
4367
4521
  }
4368
4522
  })();
4369
4523
  return () => {
@@ -4473,7 +4627,8 @@ function useTourPlayback({
4473
4627
  setPlaybackState("executing");
4474
4628
  }
4475
4629
  } catch (err) {
4476
- console.warn("[TourClient] Failed to submit review feedback:", err);
4630
+ const errMsg = err instanceof Error ? err.message : String(err);
4631
+ console.warn(`[TourClient] Failed to submit review feedback: ${errMsg}`);
4477
4632
  setReviewStatusMessage("Unable to save correction.");
4478
4633
  } finally {
4479
4634
  setReviewSubmitting(false);
@@ -4514,23 +4669,29 @@ function useTourPlayback({
4514
4669
  }, [voice]);
4515
4670
  const handleVoiceInput = useCallback7((transcript) => {
4516
4671
  const text = transcript.trim();
4517
- console.log("[TourAgent] handleVoiceInput called with text:", text);
4672
+ emitSdkDebugLog("[TourAgent] Voice input received", {
4673
+ textLength: text.length
4674
+ }, { devMode: devModeRef.current });
4518
4675
  if (!text) return;
4519
4676
  if (interruptExecution(text)) {
4520
4677
  return;
4521
4678
  }
4522
4679
  if (voiceInputResolveRef.current) {
4523
- console.log("[TourAgent] Resolving loop waiting_voice with text:", text);
4680
+ emitSdkDebugLog("[TourAgent] Resolving waiting voice input", void 0, { devMode: devModeRef.current });
4524
4681
  voiceInputResolveRef.current(text);
4525
4682
  } else if (isSocketWritable(socketRef.current)) {
4526
- console.log("[TourAgent] Forwarding ambient voice to server:", text);
4683
+ emitSdkDebugLog("[TourAgent] Forwarding ambient voice input to server", {
4684
+ textLength: text.length
4685
+ }, { devMode: devModeRef.current });
4527
4686
  emitSocketEvent(socketRef.current, "tour:user_input", {
4528
4687
  transcript: text,
4529
4688
  runId: runIdRef.current,
4530
4689
  turnId: turnIdRef.current
4531
4690
  });
4532
4691
  } else {
4533
- console.log("[TourAgent] buffering voice input because socket is not ready:", text);
4692
+ emitSdkDebugLog("[TourAgent] Buffering voice input until socket is ready", {
4693
+ textLength: text.length
4694
+ }, { devMode: devModeRef.current });
4534
4695
  pendingInputBufRef.current = text;
4535
4696
  }
4536
4697
  }, [interruptExecution]);
@@ -5685,7 +5846,6 @@ function useVoice(serverUrl) {
5685
5846
  setIsListening(false);
5686
5847
  }, [stopLiveSttTransport]);
5687
5848
  const startListening = useCallback9((onResult, onInterruption, onError, options = {}) => {
5688
- console.log("[Voice] startListening called, options:", options);
5689
5849
  stopListening();
5690
5850
  listeningSessionIdRef.current = createVoiceDebugId("stt");
5691
5851
  listeningStartedAtRef.current = performance.now();
@@ -5899,7 +6059,9 @@ function useVoice(serverUrl) {
5899
6059
  recorder.start(LIVE_STT_TIMESLICE_MS);
5900
6060
  }
5901
6061
  setIsListening(true);
5902
- console.log("[Voice] Live STT pipeline active (Deepgram streaming + WebRTC loopback)");
6062
+ emitVoiceDebug("stt_live_pipeline_active", {
6063
+ listeningSessionId: listeningSessionIdRef.current
6064
+ });
5903
6065
  } catch (err) {
5904
6066
  const normalizedError = normalizeSttError(err);
5905
6067
  console.warn("[Voice] Failed to start live STT recorder:", normalizedError);
@@ -8720,7 +8882,7 @@ function AgentTraces({ debug, command, defaultExpanded = true }) {
8720
8882
  },
8721
8883
  children: [
8722
8884
  /* @__PURE__ */ jsxs3("span", { children: [
8723
- "Agent traces (",
8885
+ "Execution summary (",
8724
8886
  traces.length,
8725
8887
  " step",
8726
8888
  traces.length !== 1 ? "s" : "",
@@ -8736,21 +8898,9 @@ function AgentTraces({ debug, command, defaultExpanded = true }) {
8736
8898
  /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "8px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: command })
8737
8899
  ] }),
8738
8900
  !hasTraceContent ? /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "12px", padding: "8px", background: "#fef3c7", borderRadius: "4px", borderLeft: "3px solid #f59e0b" }, children: [
8739
- /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, color: "#92400e", marginBottom: "4px" }, children: "No trace data" }),
8740
- /* @__PURE__ */ jsx4("div", { style: { fontSize: "10px", color: "#71717a", marginBottom: "6px" }, children: "The server may not have OPENROUTER_API_KEY set, or the request failed before the agent ran." }),
8741
- /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "8px", background: "#fff", borderRadius: "4px", fontSize: "10px", overflow: "auto", maxHeight: "120px", color: "#27272a" }, children: JSON.stringify(debug, null, 2) })
8901
+ /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, color: "#92400e", marginBottom: "4px" }, children: "No safe debug summary" }),
8902
+ /* @__PURE__ */ jsx4("div", { style: { fontSize: "10px", color: "#71717a" }, children: "Verbose prompts, reasoning, and raw tool payloads are intentionally hidden by the SDK." })
8742
8903
  ] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
8743
- debug.llmInput && traces.length === 0 && /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "12px" }, children: [
8744
- /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, color: "#3f3f46", marginBottom: "4px" }, children: "Input \u2192 agent" }),
8745
- /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "6px" }, children: [
8746
- /* @__PURE__ */ jsx4("div", { style: { fontSize: "10px", color: "#a1a1aa", marginBottom: "2px" }, children: "System" }),
8747
- /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "8px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: "80px", overflow: "auto" }, children: debug.llmInput.systemPrompt ?? "(empty)" })
8748
- ] }),
8749
- /* @__PURE__ */ jsxs3("div", { children: [
8750
- /* @__PURE__ */ jsx4("div", { style: { fontSize: "10px", color: "#a1a1aa", marginBottom: "2px" }, children: "User" }),
8751
- /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "8px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: "80px", overflow: "auto" }, children: debug.llmInput.userMessage ?? "(empty)" })
8752
- ] })
8753
- ] }),
8754
8904
  traces.map((t) => {
8755
8905
  const isStepExpanded = expandedSteps.has(t.step);
8756
8906
  return /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "12px", paddingBottom: "12px", borderBottom: "1px solid #e4e4e7" }, children: [
@@ -8783,31 +8933,6 @@ function AgentTraces({ debug, command, defaultExpanded = true }) {
8783
8933
  }
8784
8934
  ),
8785
8935
  isStepExpanded && /* @__PURE__ */ jsxs3(Fragment2, { children: [
8786
- t.reasoning && /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "6px" }, children: [
8787
- /* @__PURE__ */ jsx4("div", { style: { color: "#71717a", marginBottom: "2px" }, children: "Reasoning" }),
8788
- /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "6px", background: "#fef3c7", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: "100px", overflow: "auto", borderLeft: "3px solid #f59e0b", color: "#451a03" }, children: t.reasoning })
8789
- ] }),
8790
- t.llmInput && /* @__PURE__ */ jsxs3(Fragment2, { children: [
8791
- /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "6px" }, children: [
8792
- /* @__PURE__ */ jsx4("div", { style: { color: "#71717a", marginBottom: "2px" }, children: "Input \u2192 agent" }),
8793
- /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "4px" }, children: [
8794
- /* @__PURE__ */ jsx4("div", { style: { fontSize: "10px", color: "#a1a1aa", marginBottom: "2px" }, children: "System" }),
8795
- /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "6px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: "80px", overflow: "auto" }, children: t.llmInput.systemPrompt ?? "(empty)" })
8796
- ] }),
8797
- /* @__PURE__ */ jsxs3("div", { children: [
8798
- /* @__PURE__ */ jsx4("div", { style: { fontSize: "10px", color: "#a1a1aa", marginBottom: "2px" }, children: "User" }),
8799
- /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "6px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: "60px", overflow: "auto" }, children: t.llmInput.userMessage ?? "(empty)" })
8800
- ] })
8801
- ] }),
8802
- /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "6px" }, children: [
8803
- /* @__PURE__ */ jsx4("div", { style: { color: "#71717a", marginBottom: "2px" }, children: "Output \u2190 agent" }),
8804
- /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "6px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: "60px", overflow: "auto" }, children: t.llmOutput ?? "(empty)" })
8805
- ] })
8806
- ] }),
8807
- !t.llmInput && /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "6px" }, children: [
8808
- /* @__PURE__ */ jsx4("div", { style: { color: "#71717a", marginBottom: "2px" }, children: "LLM output" }),
8809
- /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "6px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: "60px", overflow: "auto" }, children: t.llmOutput ?? "(empty)" })
8810
- ] }),
8811
8936
  /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "6px" }, children: [
8812
8937
  /* @__PURE__ */ jsx4("div", { style: { color: "#71717a", marginBottom: "2px" }, children: "Actions" }),
8813
8938
  /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "6px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: JSON.stringify(t.actions, null, 2) })
@@ -8819,10 +8944,6 @@ function AgentTraces({ debug, command, defaultExpanded = true }) {
8819
8944
  ] })
8820
8945
  ] }, t.step);
8821
8946
  }),
8822
- traces.length === 0 && debug.llmOutput && debug.llmOutput.length > 0 && /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "12px" }, children: [
8823
- /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, color: "#3f3f46", marginBottom: "4px" }, children: "LLM output" }),
8824
- /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "8px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: debug.llmOutput.join("\n\n") })
8825
- ] }),
8826
8947
  traces.length === 0 && (debug.actions?.length ?? 0) > 0 && /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "12px" }, children: [
8827
8948
  /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, color: "#3f3f46", marginBottom: "4px" }, children: "Executed actions" }),
8828
8949
  /* @__PURE__ */ jsx4("pre", { style: { margin: 0, padding: "8px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: JSON.stringify(debug.actions, null, 2) })
@@ -9018,7 +9139,6 @@ function ModelNexChatBubble({
9018
9139
  tagStore.setTagsBatch(data.tags, true);
9019
9140
  lastAutoTaggedUrlRef.current = currentUrl;
9020
9141
  localStorage.setItem(storageKey, "true");
9021
- console.log(`[ModelNex] Auto-tagged ${data.tags.length} elements for ${currentUrl}`);
9022
9142
  }
9023
9143
  } catch (err) {
9024
9144
  console.warn("[ModelNex] Auto-tag error:", err);
@@ -9182,12 +9302,9 @@ function ModelNexChatBubble({
9182
9302
  };
9183
9303
  const listeningExperience = resolveTourListeningExperience(preferredExperience, listeningState);
9184
9304
  preferredListeningExperienceRef.current = listeningExperience;
9185
- console.log("[ChatBubble] startTourListening called. listeningState:", listeningState, "preferredExperience:", preferredExperience, "listeningExperience:", listeningExperience);
9186
9305
  if (!canStartTourListening(listeningState)) {
9187
- console.log("[ChatBubble] startTourListening bailed out early.");
9188
9306
  return;
9189
9307
  }
9190
- console.log("[ChatBubble] Proceeding to startTourListening...");
9191
9308
  sttActiveRef.current = true;
9192
9309
  updateTourSttError(null);
9193
9310
  resetFloatingLiveTranscriptSuppression();
@@ -9393,7 +9510,7 @@ function ModelNexChatBubble({
9393
9510
  content: summary || fallbackContent,
9394
9511
  summary: summary ?? void 0,
9395
9512
  nextSteps: nextSteps ?? void 0,
9396
- debug: data?.debug ?? void 0
9513
+ debug: devMode ? data?.debug ?? void 0 : void 0
9397
9514
  }
9398
9515
  ]);
9399
9516
  } catch (err) {
@@ -10436,7 +10553,7 @@ function ModelNexChatBubble({
10436
10553
  )
10437
10554
  }
10438
10555
  ),
10439
- msg.role === "assistant" && msg.debug && /* @__PURE__ */ jsx4(AgentTraces, { debug: msg.debug, command: messages[i - 1]?.content ?? "" })
10556
+ msg.role === "assistant" && devMode && msg.debug && /* @__PURE__ */ jsx4(AgentTraces, { debug: msg.debug, command: messages[i - 1]?.content ?? "" })
10440
10557
  ] }, i)),
10441
10558
  loading && /* @__PURE__ */ jsx4("div", { style: { display: "flex", justifyContent: "flex-start" }, children: /* @__PURE__ */ jsxs3(
10442
10559
  "div",
@@ -11415,6 +11532,7 @@ var ModelNexProvider = ({
11415
11532
  userProfile,
11416
11533
  toursApiBase,
11417
11534
  devMode,
11535
+ devModeKey,
11418
11536
  serverUrl: serverUrlProp
11419
11537
  }) => {
11420
11538
  const serverUrl = serverUrlProp ?? DEFAULT_MODELNEX_SERVER_URL;
@@ -11437,6 +11555,25 @@ var ModelNexProvider = ({
11437
11555
  const [voiceMuted, setVoiceMuted] = useState15(false);
11438
11556
  const [socketId, setSocketId] = useState15(null);
11439
11557
  const [actions, setActions] = useState15(/* @__PURE__ */ new Map());
11558
+ const [validatedBrowserDevMode, setValidatedBrowserDevMode] = useState15(false);
11559
+ const resolvedDevModeKey = useMemo5(() => resolveInjectedDevModeKey(devModeKey), [devModeKey]);
11560
+ useEffect19(() => {
11561
+ let cancelled = false;
11562
+ if (!websiteId || !resolvedDevModeKey) {
11563
+ setValidatedBrowserDevMode(false);
11564
+ return () => {
11565
+ cancelled = true;
11566
+ };
11567
+ }
11568
+ void validateInjectedDevModeKey(serverUrl, websiteId, resolvedDevModeKey).then((enabled) => {
11569
+ if (cancelled) return;
11570
+ setValidatedBrowserDevMode(enabled);
11571
+ });
11572
+ return () => {
11573
+ cancelled = true;
11574
+ };
11575
+ }, [resolvedDevModeKey, serverUrl, websiteId]);
11576
+ const effectiveDevMode = Boolean(devMode) || validatedBrowserDevMode;
11440
11577
  const registerAction = useCallback14((action) => {
11441
11578
  setActions((prev) => {
11442
11579
  const next = new Map(prev);
@@ -11451,7 +11588,7 @@ var ModelNexProvider = ({
11451
11588
  return next;
11452
11589
  });
11453
11590
  }, []);
11454
- const extractedElements = useAutoExtract();
11591
+ const extractedElements = useAutoExtract(effectiveDevMode);
11455
11592
  const tagStore = useTagStore({ serverUrl, websiteId });
11456
11593
  useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl, websiteId, toursApiBase, userProfile);
11457
11594
  const CHAT_STORAGE_KEY = "modelnex-chat-messages";
@@ -11460,21 +11597,32 @@ var ModelNexProvider = ({
11460
11597
  try {
11461
11598
  const stored = sessionStorage.getItem(CHAT_STORAGE_KEY);
11462
11599
  if (stored) {
11463
- setChatMessagesRaw(JSON.parse(stored));
11600
+ setChatMessagesRaw(sanitizeChatMessages(JSON.parse(stored), effectiveDevMode));
11464
11601
  }
11465
11602
  } catch {
11466
11603
  }
11467
- }, []);
11604
+ }, [effectiveDevMode]);
11605
+ useEffect19(() => {
11606
+ setChatMessagesRaw((prev) => {
11607
+ const next = sanitizeChatMessages(prev, effectiveDevMode);
11608
+ try {
11609
+ sessionStorage.setItem(CHAT_STORAGE_KEY, JSON.stringify(next));
11610
+ } catch {
11611
+ }
11612
+ return next;
11613
+ });
11614
+ }, [effectiveDevMode]);
11468
11615
  const setChatMessages = useCallback14((action) => {
11469
11616
  setChatMessagesRaw((prev) => {
11470
- const next = typeof action === "function" ? action(prev) : action;
11617
+ const resolved = typeof action === "function" ? action(prev) : action;
11618
+ const next = sanitizeChatMessages(resolved, effectiveDevMode);
11471
11619
  try {
11472
11620
  sessionStorage.setItem(CHAT_STORAGE_KEY, JSON.stringify(next));
11473
11621
  } catch {
11474
11622
  }
11475
11623
  return next;
11476
11624
  });
11477
- }, []);
11625
+ }, [effectiveDevMode]);
11478
11626
  useModelNexSocket({
11479
11627
  serverUrl,
11480
11628
  actions,
@@ -11486,7 +11634,8 @@ var ModelNexProvider = ({
11486
11634
  setStagingFields,
11487
11635
  setExecutedFields,
11488
11636
  onSocketId: setSocketId,
11489
- websiteId
11637
+ websiteId,
11638
+ devMode: effectiveDevMode
11490
11639
  });
11491
11640
  useFieldHighlight(stagingFields, executedFields, setExecutedFields);
11492
11641
  useEffect19(() => {
@@ -11521,9 +11670,9 @@ var ModelNexProvider = ({
11521
11670
  voiceMuted,
11522
11671
  setVoiceMuted,
11523
11672
  socketId,
11524
- devMode
11673
+ devMode: effectiveDevMode
11525
11674
  }),
11526
- [serverUrl, commandUrl, registerAction, unregisterAction, activeAgentActions, stagingFields, highlightActions, studioMode, recordingMode, extractedElements, tagStore, chatMessages, websiteId, userProfile?.userId, userProfile?.type, userProfile?.isNewUser, toursApiBase, voiceMuted, socketId, devMode]
11675
+ [serverUrl, commandUrl, registerAction, unregisterAction, activeAgentActions, stagingFields, highlightActions, studioMode, recordingMode, extractedElements, tagStore, chatMessages, websiteId, userProfile?.userId, userProfile?.type, userProfile?.isNewUser, toursApiBase, voiceMuted, socketId, effectiveDevMode]
11527
11676
  );
11528
11677
  return React8.createElement(
11529
11678
  ModelNexContext.Provider,