@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.js CHANGED
@@ -121,7 +121,6 @@ function waitForDomSettle(options = {}) {
121
121
  if (!resolved) {
122
122
  resolved = true;
123
123
  cleanup();
124
- console.log("[DOM Sync] Forced resolution by max timeout");
125
124
  resolve();
126
125
  }
127
126
  }, Math.max(timeoutMs, minWaitMs));
@@ -237,6 +236,60 @@ function resolveSocketIoTransports(serverUrl, order) {
237
236
 
238
237
  // src/auto-extract.ts
239
238
  var import_react2 = require("react");
239
+
240
+ // src/utils/dev-logging.ts
241
+ function isSdkDebugEnabled(devMode) {
242
+ if (devMode) return true;
243
+ if (typeof window !== "undefined" && Boolean(window.MODELNEX_DEBUG)) {
244
+ return true;
245
+ }
246
+ return process.env.NODE_ENV === "development";
247
+ }
248
+ function emitSdkDebugLog(message, payload, options) {
249
+ if (!isSdkDebugEnabled(options?.devMode)) return;
250
+ if (payload && Object.keys(payload).length > 0) {
251
+ console.log(message, payload);
252
+ } else {
253
+ console.log(message);
254
+ }
255
+ if (options?.dispatchEvent && typeof window !== "undefined") {
256
+ window.dispatchEvent(new CustomEvent("modelnex-debug", { detail: { msg: message, data: payload } }));
257
+ }
258
+ }
259
+ function sanitizeActionList(actions) {
260
+ if (!Array.isArray(actions) || actions.length === 0) return void 0;
261
+ return actions.map(({ actionId }) => ({ actionId }));
262
+ }
263
+ function sanitizeAgentDebug(debug) {
264
+ if (!debug) return void 0;
265
+ const actions = sanitizeActionList(debug.actions);
266
+ const traces = Array.isArray(debug.traces) && debug.traces.length > 0 ? debug.traces.map((trace) => ({
267
+ step: trace.step,
268
+ actions: sanitizeActionList(trace.actions) ?? [],
269
+ results: Array.isArray(trace.results) && trace.results.length > 0 ? trace.results.map(({ actionId, success }) => ({ actionId, success })) : void 0
270
+ })) : void 0;
271
+ if ((!actions || actions.length === 0) && (!traces || traces.length === 0)) {
272
+ return void 0;
273
+ }
274
+ return {
275
+ ...actions ? { actions } : {},
276
+ ...traces ? { traces } : {}
277
+ };
278
+ }
279
+ function sanitizeChatMessages(messages, devMode) {
280
+ const includeDebug = isSdkDebugEnabled(devMode);
281
+ return messages.map((message) => {
282
+ if (message.role !== "assistant") {
283
+ return message;
284
+ }
285
+ return {
286
+ ...message,
287
+ debug: includeDebug ? sanitizeAgentDebug(message.debug) : void 0
288
+ };
289
+ });
290
+ }
291
+
292
+ // src/auto-extract.ts
240
293
  function simpleHash(str) {
241
294
  let hash = 0;
242
295
  for (let i = 0; i < str.length; i++) {
@@ -500,7 +553,7 @@ function extractInteractiveElements() {
500
553
  }
501
554
  return elements;
502
555
  }
503
- function useAutoExtract() {
556
+ function useAutoExtract(devMode) {
504
557
  const [elements, setElements] = (0, import_react2.useState)([]);
505
558
  const timerRef = (0, import_react2.useRef)(null);
506
559
  const lastSnapshotRef = (0, import_react2.useRef)("");
@@ -518,9 +571,11 @@ function useAutoExtract() {
518
571
  })));
519
572
  if (snapshot === lastSnapshotRef.current) return;
520
573
  lastSnapshotRef.current = snapshot;
521
- console.log(`[ModelNex AutoExtract] Found ${extracted.length} interactive elements`, extracted.map((e) => ({ fp: e.fingerprint, role: e.role, text: e.text.slice(0, 30) })));
574
+ emitSdkDebugLog("[ModelNex AutoExtract] Scan complete", {
575
+ elementCount: extracted.length
576
+ }, { devMode });
522
577
  setElements(extracted);
523
- }, []);
578
+ }, [devMode]);
524
579
  (0, import_react2.useEffect)(() => {
525
580
  const initialTimer = setTimeout(scan, 300);
526
581
  const observer = new MutationObserver((mutations) => {
@@ -835,7 +890,8 @@ function useModelNexSocket({
835
890
  setStagingFields,
836
891
  setExecutedFields,
837
892
  onSocketId,
838
- websiteId
893
+ websiteId,
894
+ devMode
839
895
  }) {
840
896
  const socketRef = (0, import_react3.useRef)(null);
841
897
  const actionsRef = (0, import_react3.useRef)(actions);
@@ -868,12 +924,14 @@ function useModelNexSocket({
868
924
  allTaggedElements: tagsRef.current ? Array.from(tagsRef.current.values()) : void 0
869
925
  });
870
926
  socket.on("connect", () => {
871
- console.log("ModelNex SDK: Connected to agent server", socket.id);
927
+ emitSdkDebugLog("[ModelNex SDK] Connected to agent server", {
928
+ socketId: socket.id ?? null
929
+ }, { devMode });
872
930
  onSocketId?.(socket.id || null);
873
931
  socket.emit("client:sync", buildSyncPayload());
874
932
  });
875
933
  socket.on("disconnect", () => {
876
- console.log("ModelNex SDK: Disconnected from agent server");
934
+ emitSdkDebugLog("[ModelNex SDK] Disconnected from agent server", void 0, { devMode });
877
935
  onSocketId?.(null);
878
936
  });
879
937
  socket.on("agent:request_context", () => {
@@ -899,12 +957,11 @@ function useModelNexSocket({
899
957
  reasoning
900
958
  }) => {
901
959
  const log = (msg, data) => {
902
- console.log(msg, data ?? "");
903
- window.dispatchEvent(new CustomEvent("modelnex-debug", { detail: { msg, data } }));
960
+ emitSdkDebugLog(msg, data, { devMode, dispatchEvent: true });
904
961
  };
905
962
  if (reasoning || params?.fingerprint) {
906
963
  window.dispatchEvent(new CustomEvent("modelnex-action-start", {
907
- detail: { actionId, fingerprint: params?.fingerprint ?? null, reasoning: reasoning ?? "" }
964
+ detail: { actionId, fingerprint: params?.fingerprint ?? null }
908
965
  }));
909
966
  }
910
967
  const sendResult = (success, result, error) => {
@@ -915,17 +972,18 @@ function useModelNexSocket({
915
972
  const currentActions = actionsRef.current;
916
973
  log("[SDK] agent:execute received", {
917
974
  actionId,
918
- params,
919
- registeredActions: Array.from(currentActions.keys())
975
+ executionId: executionId ?? null,
976
+ fieldId: fieldId ?? null,
977
+ hasParams: params != null
920
978
  });
921
979
  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"];
922
980
  const action = currentActions.get(actionId);
923
981
  if (action) {
924
982
  try {
925
983
  const validatedParams = action.schema.parse(params);
926
- log("[SDK] Executing", { actionId, validatedParams });
984
+ log("[SDK] Executing action", { actionId });
927
985
  const execResult = await action.execute(validatedParams);
928
- log("[SDK] Execute completed", { actionId });
986
+ log("[SDK] Action completed", { actionId });
929
987
  sendResult(true, execResult);
930
988
  if (NAV_ACTION_IDS.includes(actionId)) {
931
989
  requestAnimationFrame(() => {
@@ -949,25 +1007,29 @@ function useModelNexSocket({
949
1007
  }
950
1008
  } catch (err) {
951
1009
  const errMsg = err instanceof Error ? err.message : String(err);
952
- console.error(`[ModelNex SDK] Execution failed for ${actionId}`, err);
1010
+ console.error(`[ModelNex SDK] Execution failed for ${actionId}: ${errMsg}`);
1011
+ if (isSdkDebugEnabled(devMode)) {
1012
+ window.dispatchEvent(
1013
+ new CustomEvent("modelnex-debug", {
1014
+ detail: { msg: "[SDK] Execution failed", data: { actionId, error: errMsg } }
1015
+ })
1016
+ );
1017
+ }
1018
+ sendResult(false, void 0, errMsg);
1019
+ }
1020
+ } else {
1021
+ const errMsg = `Action not found: ${actionId}`;
1022
+ console.warn(`[ModelNex SDK] ${errMsg}`);
1023
+ if (isSdkDebugEnabled(devMode)) {
953
1024
  window.dispatchEvent(
954
1025
  new CustomEvent("modelnex-debug", {
955
- detail: { msg: "[SDK] Execution failed", data: { actionId, error: errMsg } }
1026
+ detail: {
1027
+ msg: "[SDK] Action not found",
1028
+ data: { actionId }
1029
+ }
956
1030
  })
957
1031
  );
958
- sendResult(false, void 0, errMsg);
959
1032
  }
960
- } else {
961
- const errMsg = `Action not found: ${actionId}`;
962
- console.warn("[ModelNex SDK]", errMsg, "Available:", Array.from(currentActions.keys()));
963
- window.dispatchEvent(
964
- new CustomEvent("modelnex-debug", {
965
- detail: {
966
- msg: "[SDK] Action not found",
967
- data: { actionId, available: Array.from(actions.keys()) }
968
- }
969
- })
970
- );
971
1033
  sendResult(false, void 0, errMsg);
972
1034
  }
973
1035
  }
@@ -2696,6 +2758,56 @@ function useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl
2696
2758
  // src/constants.ts
2697
2759
  var DEFAULT_MODELNEX_SERVER_URL = "https://api.modelnex.com";
2698
2760
 
2761
+ // src/utils/dev-mode.ts
2762
+ var DEV_MODE_KEY_GLOBAL_NAMES = ["__MODELNEX_DEV_MODE_KEY__", "MODELNEX_DEV_MODE_KEY"];
2763
+ var devModeValidationCache = /* @__PURE__ */ new Map();
2764
+ function normalizeDevModeKey(value) {
2765
+ if (typeof value !== "string") return void 0;
2766
+ const normalized = value.trim();
2767
+ return normalized || void 0;
2768
+ }
2769
+ function resolveInjectedDevModeKey(explicitDevModeKey) {
2770
+ const normalizedExplicitKey = normalizeDevModeKey(explicitDevModeKey);
2771
+ if (normalizedExplicitKey) return normalizedExplicitKey;
2772
+ if (typeof window === "undefined") return void 0;
2773
+ const browserWindow = window;
2774
+ for (const globalName of DEV_MODE_KEY_GLOBAL_NAMES) {
2775
+ const normalizedGlobalKey = normalizeDevModeKey(browserWindow[globalName]);
2776
+ if (normalizedGlobalKey) return normalizedGlobalKey;
2777
+ }
2778
+ const scriptInjectedKey = typeof document !== "undefined" ? normalizeDevModeKey(
2779
+ document.querySelector("script[data-modelnex-dev-mode-key]")?.dataset.modelnexDevModeKey
2780
+ ) : void 0;
2781
+ if (scriptInjectedKey) return scriptInjectedKey;
2782
+ return void 0;
2783
+ }
2784
+ async function validateInjectedDevModeKey(serverUrl, websiteId, devModeKey) {
2785
+ const normalizedWebsiteId = websiteId.trim();
2786
+ const normalizedDevModeKey = devModeKey.trim();
2787
+ if (!normalizedWebsiteId || !normalizedDevModeKey) return false;
2788
+ const cacheKey = `${serverUrl}::${normalizedWebsiteId}::${normalizedDevModeKey}`;
2789
+ const cached = devModeValidationCache.get(cacheKey);
2790
+ if (cached) {
2791
+ return cached;
2792
+ }
2793
+ const validationPromise = fetch(
2794
+ `${serverUrl.replace(/\/$/, "")}/api/websites/${encodeURIComponent(normalizedWebsiteId)}/dev-mode/verify`,
2795
+ {
2796
+ method: "POST",
2797
+ headers: {
2798
+ "Content-Type": "application/json"
2799
+ },
2800
+ body: JSON.stringify({ key: normalizedDevModeKey })
2801
+ }
2802
+ ).then(async (response) => {
2803
+ if (!response.ok) return false;
2804
+ const payload = await response.json().catch(() => null);
2805
+ return payload?.enabled === true;
2806
+ }).catch(() => false);
2807
+ devModeValidationCache.set(cacheKey, validationPromise);
2808
+ return validationPromise;
2809
+ }
2810
+
2699
2811
  // src/hooks/useRunCommand.ts
2700
2812
  var import_react9 = require("react");
2701
2813
  function searchTaggedElementsForQuery(store, query, limit = 8) {
@@ -2738,7 +2850,10 @@ function useRunCommand(serverUrlOverride) {
2738
2850
  if (!res.ok) {
2739
2851
  throw new Error(data?.error ?? `Request failed: ${res.status}`);
2740
2852
  }
2741
- return data;
2853
+ return {
2854
+ ...data,
2855
+ debug: sanitizeAgentDebug(data?.debug)
2856
+ };
2742
2857
  },
2743
2858
  [baseUrl, tagStore]
2744
2859
  );
@@ -3646,7 +3761,9 @@ function useTourPlayback({
3646
3761
  const socket = tourSocketPool.acquire(serverUrl);
3647
3762
  socketRef.current = socket;
3648
3763
  const handleConnect = () => {
3649
- console.log("[TourClient] Connected to tour agent server:", socket.id);
3764
+ emitSdkDebugLog("[TourClient] Connected to tour agent server", {
3765
+ socketId: socket.id ?? null
3766
+ }, { devMode: devModeRef.current });
3650
3767
  const profile = userProfileRef.current;
3651
3768
  const currentWebsiteId = websiteIdRef.current;
3652
3769
  if (currentWebsiteId && profile?.userId) {
@@ -3663,7 +3780,9 @@ function useTourPlayback({
3663
3780
  setServerState(payload);
3664
3781
  };
3665
3782
  const handleCommandCancel = (payload) => {
3666
- console.log("[TourClient] Received command_cancel:", payload);
3783
+ emitSdkDebugLog("[TourClient] Received command cancel", {
3784
+ commandBatchId: payload.commandBatchId ?? null
3785
+ }, { devMode: devModeRef.current });
3667
3786
  if (payload.commandBatchId && activeCommandBatchIdRef.current === payload.commandBatchId) {
3668
3787
  activeCommandBatchIdRef.current = null;
3669
3788
  activeExecutionTokenRef.current++;
@@ -3678,14 +3797,22 @@ function useTourPlayback({
3678
3797
  const ownerKey = createTourPlaybackOwnerKey(serverUrl, websiteIdRef.current, experienceTypeRef.current);
3679
3798
  if (!shouldExecuteTourCommandBatch(isActiveRef.current) || !hasTourPlaybackOwnership(ownerKey, playbackOwnerIdRef.current)) {
3680
3799
  const activeType = experienceTypeRef.current;
3681
- console.log("[TourClient] Ignoring command batch for inactive playback hook:", activeType, payload.stepIndex);
3800
+ emitSdkDebugLog("[TourClient] Ignoring command batch for inactive playback hook", {
3801
+ experienceType: activeType,
3802
+ stepIndex: payload.stepIndex
3803
+ }, { devMode: devModeRef.current });
3682
3804
  return;
3683
3805
  }
3684
3806
  const emitIfOpen = (ev, data) => {
3685
3807
  if (socketRef.current !== socket) return;
3686
3808
  emitSocketEvent(socket, ev, data);
3687
3809
  };
3688
- console.log("[TourClient] Received command batch:", payload.stepIndex, payload.commands);
3810
+ const commandBatchId = payload.commandBatchId ?? null;
3811
+ emitSdkDebugLog("[TourClient] Received command batch", {
3812
+ stepIndex: payload.stepIndex,
3813
+ commandCount: Array.isArray(payload.commands) ? payload.commands.length : 0,
3814
+ commandBatchId
3815
+ }, { devMode: devModeRef.current });
3689
3816
  runCleanup(pendingManualWaitCleanupRef.current);
3690
3817
  pendingManualWaitCleanupRef.current = null;
3691
3818
  if (voiceInputResolveRef.current) {
@@ -3695,7 +3822,6 @@ function useTourPlayback({
3695
3822
  }
3696
3823
  setPlaybackState("executing");
3697
3824
  commandInFlightRef.current = true;
3698
- const commandBatchId = payload.commandBatchId ?? null;
3699
3825
  turnIdRef.current = payload.turnId ?? turnIdRef.current;
3700
3826
  const clearCommandBatchId = () => {
3701
3827
  if (activeCommandBatchIdRef.current === commandBatchId) {
@@ -3741,7 +3867,7 @@ function useTourPlayback({
3741
3867
  }
3742
3868
  }
3743
3869
  if (!payload.commands || !Array.isArray(payload.commands)) {
3744
- console.warn("[TourClient] Payload commands is not an array:", payload);
3870
+ console.warn("[TourClient] Command batch payload was invalid.");
3745
3871
  commandInFlightRef.current = false;
3746
3872
  emitIfOpen("tour:action_result", {
3747
3873
  success: false,
@@ -3790,7 +3916,9 @@ function useTourPlayback({
3790
3916
  };
3791
3917
  const executeOne = async (action) => {
3792
3918
  assertNotInterrupted();
3793
- console.log("[TourClient] Executing action:", action?.type, action?.params ? JSON.stringify(action.params).slice(0, 120) : "");
3919
+ emitSdkDebugLog("[TourClient] Executing action", {
3920
+ actionType: action?.type ?? "unknown"
3921
+ }, { devMode: devModeRef.current });
3794
3922
  const currentStep = tourRef.current?.steps?.[stepIndexRef.current] ?? null;
3795
3923
  const executeTimeline = async (params = {}) => {
3796
3924
  const segments = Array.isArray(params.segments) ? params.segments : [];
@@ -3977,7 +4105,7 @@ function useTourPlayback({
3977
4105
  handleTourEnd();
3978
4106
  return { result: "ended" };
3979
4107
  }
3980
- console.warn("[TourClient] Unknown action type:", action?.type, "- skipping");
4108
+ console.warn(`[TourClient] Unknown action type: ${String(action?.type ?? "unknown")}. Skipping.`);
3981
4109
  return { result: "unknown_action_skipped" };
3982
4110
  };
3983
4111
  try {
@@ -4033,14 +4161,15 @@ function useTourPlayback({
4033
4161
  clearCommandBatchId();
4034
4162
  return;
4035
4163
  }
4036
- console.error("[TourClient] Command batch execution failed:", err);
4164
+ const errMsg = err instanceof Error ? err.message : String(err);
4165
+ console.error(`[TourClient] Command batch execution failed: ${errMsg}`);
4037
4166
  if (reviewModeRef.current && activeTourId && activePreviewRunId) {
4038
4167
  void logPreviewEvent(serverUrl, toursApiBaseRef.current, activeTourId, activePreviewRunId, websiteId, {
4039
4168
  stepOrder: stepIndexRef.current,
4040
4169
  eventType: "command_batch_failed",
4041
4170
  payload: {
4042
4171
  commandBatchId,
4043
- error: String(err),
4172
+ error: errMsg,
4044
4173
  partialResults: results
4045
4174
  },
4046
4175
  status: "active",
@@ -4050,7 +4179,7 @@ function useTourPlayback({
4050
4179
  emitIfOpen("tour:action_result", {
4051
4180
  success: false,
4052
4181
  reason: "execution_error",
4053
- error: String(err),
4182
+ error: errMsg,
4054
4183
  results,
4055
4184
  commandBatchId,
4056
4185
  runId: runIdRef.current,
@@ -4076,7 +4205,10 @@ function useTourPlayback({
4076
4205
  let manualWaitTarget = await resolveTargetElement2(waitTargetHints, currentStep);
4077
4206
  if (inputLikeWait && preferredWaitTarget && manualWaitTarget && manualWaitTarget !== preferredWaitTarget && !isEditableWaitTarget(manualWaitTarget) && isEditableWaitTarget(preferredWaitTarget)) {
4078
4207
  manualWaitTarget = preferredWaitTarget;
4079
- console.log("[TourClient] wait_for_input: preferring current editable target over hinted step target", manualWaitTarget);
4208
+ emitSdkDebugLog("[TourClient] wait_for_input preferred highlighted editable target", {
4209
+ stepIndex: stepIndexRef.current,
4210
+ event: waitEvent
4211
+ }, { devMode: devModeRef.current });
4080
4212
  }
4081
4213
  if (manualWaitTarget) {
4082
4214
  const manualWait = createManualWaitForTarget(manualWaitTarget, waitEvent, currentStep);
@@ -4090,7 +4222,10 @@ function useTourPlayback({
4090
4222
  manualWaitPromise = manualWait.promise;
4091
4223
  manualWaitKind = manualWait.kind;
4092
4224
  pendingManualWaitCleanupRef.current = manualWait.cleanup;
4093
- console.log("[TourClient] wait_for_input: using current editable target as fallback wait target", preferredWaitTarget);
4225
+ emitSdkDebugLog("[TourClient] wait_for_input using fallback editable target", {
4226
+ stepIndex: stepIndexRef.current,
4227
+ event: waitEvent
4228
+ }, { devMode: devModeRef.current });
4094
4229
  }
4095
4230
  if (!manualWaitPromise && inputLikeWait) {
4096
4231
  const firstInput = document.querySelector(
@@ -4101,7 +4236,10 @@ function useTourPlayback({
4101
4236
  manualWaitPromise = manualWait.promise;
4102
4237
  manualWaitKind = manualWait.kind;
4103
4238
  pendingManualWaitCleanupRef.current = manualWait.cleanup;
4104
- console.log("[TourClient] wait_for_input: no target found, falling back to first visible editable element", firstInput);
4239
+ emitSdkDebugLog("[TourClient] wait_for_input falling back to first editable element", {
4240
+ stepIndex: stepIndexRef.current,
4241
+ event: waitEvent
4242
+ }, { devMode: devModeRef.current });
4105
4243
  }
4106
4244
  }
4107
4245
  setPlaybackState(manualWaitKind ? "waiting_input" : "waiting_voice");
@@ -4183,12 +4321,17 @@ function useTourPlayback({
4183
4321
  const tour = tourData.tourContext ?? tourRef.current;
4184
4322
  const expType = experienceTypeRef.current;
4185
4323
  if (tour?.type && tour.type !== expType) {
4186
- console.log(`[TourClient] Ignoring ${tour.type} start (this hook is for ${expType})`);
4324
+ emitSdkDebugLog("[TourClient] Ignoring tour start for mismatched experience type", {
4325
+ incomingType: tour.type,
4326
+ hookType: expType
4327
+ }, { devMode: devModeRef.current });
4187
4328
  return;
4188
4329
  }
4189
4330
  const ownerKey = createTourPlaybackOwnerKey(serverUrl, websiteIdRef.current, expType);
4190
4331
  if (!claimTourPlaybackOwnership(ownerKey, playbackOwnerIdRef.current)) {
4191
- console.log(`[TourClient] Ignoring ${expType} start because another hook already owns playback`);
4332
+ emitSdkDebugLog("[TourClient] Ignoring tour start because playback ownership is already claimed", {
4333
+ experienceType: expType
4334
+ }, { devMode: devModeRef.current });
4192
4335
  return;
4193
4336
  }
4194
4337
  claimedPlaybackOwnerKeyRef.current = ownerKey;
@@ -4213,6 +4356,8 @@ function useTourPlayback({
4213
4356
  },
4214
4357
  currentStepOrder: 0
4215
4358
  });
4359
+ } else if (tour?.id && userProfile?.userId) {
4360
+ void recordTourEvent(serverUrl, toursApiBaseRef.current, tour.id, userProfile.userId, "started", websiteId);
4216
4361
  }
4217
4362
  try {
4218
4363
  const { generateMinifiedAOM: generateMinifiedAOM2 } = await Promise.resolve().then(() => (init_aom(), aom_exports));
@@ -4225,7 +4370,8 @@ function useTourPlayback({
4225
4370
  });
4226
4371
  }
4227
4372
  } catch (e) {
4228
- console.warn("[TourClient] Initial DOM sync failed:", e);
4373
+ const errMsg = e instanceof Error ? e.message : String(e);
4374
+ console.warn(`[TourClient] Initial DOM sync failed: ${errMsg}`);
4229
4375
  }
4230
4376
  };
4231
4377
  const handleTourUpdate = (payload) => {
@@ -4263,12 +4409,11 @@ function useTourPlayback({
4263
4409
  return;
4264
4410
  }
4265
4411
  if (isDev) {
4266
- console.log(`%c[ModelNex Tour] ${entry.type}`, "color: #3b82f6; font-weight: bold", entry);
4267
- if (typeof window !== "undefined") {
4268
- window.dispatchEvent(new CustomEvent("modelnex-debug", {
4269
- detail: { msg: `[Tour Timeline] ${entry.type}`, data: entry }
4270
- }));
4271
- }
4412
+ emitSdkDebugLog(`[Tour Timeline] ${entry.type}`, {
4413
+ stepIndex: entry?.data?.stepIndex ?? null,
4414
+ runId: entry?.data?.runId ?? null,
4415
+ turnId: entry?.data?.turnId ?? null
4416
+ }, { devMode: devModeRef.current, dispatchEvent: true });
4272
4417
  }
4273
4418
  };
4274
4419
  socket.on("connect", handleConnect);
@@ -4279,7 +4424,7 @@ function useTourPlayback({
4279
4424
  socket.on("tour:update", handleTourUpdate);
4280
4425
  socket.on("tour:end", handleTourEndEvent);
4281
4426
  socket.on("tour:debug_log", handleDebugLog);
4282
- console.log("[ModelNex SDK] Tour playback initialized. Debug logs enabled:", devModeRef.current || process.env.NODE_ENV === "development");
4427
+ emitSdkDebugLog("[ModelNex SDK] Tour playback initialized", void 0, { devMode: devModeRef.current });
4283
4428
  return () => {
4284
4429
  socket.off("connect", handleConnect);
4285
4430
  socket.off("tour:server_state", handleServerState);
@@ -4390,6 +4535,8 @@ function useTourPlayback({
4390
4535
  status: "stopped",
4391
4536
  currentStepOrder: stepIndexRef.current
4392
4537
  });
4538
+ } else if (tourRef.current?.id && userProfile?.userId) {
4539
+ void recordTourEvent(serverUrl, toursApiBaseRef.current, tourRef.current.id, userProfile.userId, "cancelled", websiteId);
4393
4540
  }
4394
4541
  if (reviewModeRef.current) {
4395
4542
  if (tourRef.current?.id) {
@@ -4462,7 +4609,9 @@ function useTourPlayback({
4462
4609
  isPlaybackActive: isActiveRef.current,
4463
4610
  startRequested: startRequestedRef.current
4464
4611
  })) {
4465
- console.log("[TourClient] Ignoring duplicate start request while playback is already active or starting:", tour.id);
4612
+ emitSdkDebugLog("[TourClient] Ignoring duplicate start request while playback is already active or starting", {
4613
+ tourId: tour.id
4614
+ }, { devMode: devModeRef.current });
4466
4615
  return;
4467
4616
  }
4468
4617
  setPendingTour(null);
@@ -4478,7 +4627,9 @@ function useTourPlayback({
4478
4627
  }
4479
4628
  const ownerKey = createTourPlaybackOwnerKey(serverUrl, websiteIdRef.current, tour.type ?? experienceTypeRef.current);
4480
4629
  if (!claimTourPlaybackOwnership(ownerKey, playbackOwnerIdRef.current)) {
4481
- console.log("[TourClient] Ignoring duplicate start request because another hook already owns this experience:", tour.id);
4630
+ emitSdkDebugLog("[TourClient] Ignoring duplicate start request because another hook already owns this experience", {
4631
+ tourId: tour.id
4632
+ }, { devMode: devModeRef.current });
4482
4633
  return;
4483
4634
  }
4484
4635
  claimedPlaybackOwnerKeyRef.current = ownerKey;
@@ -4501,7 +4652,8 @@ function useTourPlayback({
4501
4652
  setPreviewRunId(previewRun.id);
4502
4653
  previewRunIdRef.current = previewRun.id;
4503
4654
  } catch (err) {
4504
- console.warn("[TourClient] Failed to create preview run:", err);
4655
+ const errMsg = err instanceof Error ? err.message : String(err);
4656
+ console.warn(`[TourClient] Failed to create preview run: ${errMsg}`);
4505
4657
  setReviewStatusMessage("Preview review logging is unavailable.");
4506
4658
  setPreviewRunId(null);
4507
4659
  previewRunIdRef.current = null;
@@ -4550,7 +4702,7 @@ function useTourPlayback({
4550
4702
  if (!tour) {
4551
4703
  clearActiveDraftPreview(experienceType);
4552
4704
  persistSuppressedDraftPreview(draftPreview);
4553
- console.warn("[ModelNex] Tour fetch failed:", tourId, experienceType, "(Check ModelNex server is running and CORS allows this origin)");
4705
+ console.warn(`[ModelNex] Tour fetch failed for ${experienceType}:${tourId}. Check the ModelNex server and CORS configuration.`);
4554
4706
  return;
4555
4707
  }
4556
4708
  if (cancelled) {
@@ -4573,7 +4725,8 @@ function useTourPlayback({
4573
4725
  await runTour(tour, previewOptions);
4574
4726
  }
4575
4727
  } catch (err) {
4576
- console.warn("[ModelNex] Tour test failed:", err);
4728
+ const errMsg = err instanceof Error ? err.message : String(err);
4729
+ console.warn(`[ModelNex] Tour test failed: ${errMsg}`);
4577
4730
  }
4578
4731
  })();
4579
4732
  return () => {
@@ -4683,7 +4836,8 @@ function useTourPlayback({
4683
4836
  setPlaybackState("executing");
4684
4837
  }
4685
4838
  } catch (err) {
4686
- console.warn("[TourClient] Failed to submit review feedback:", err);
4839
+ const errMsg = err instanceof Error ? err.message : String(err);
4840
+ console.warn(`[TourClient] Failed to submit review feedback: ${errMsg}`);
4687
4841
  setReviewStatusMessage("Unable to save correction.");
4688
4842
  } finally {
4689
4843
  setReviewSubmitting(false);
@@ -4724,23 +4878,29 @@ function useTourPlayback({
4724
4878
  }, [voice]);
4725
4879
  const handleVoiceInput = (0, import_react12.useCallback)((transcript) => {
4726
4880
  const text = transcript.trim();
4727
- console.log("[TourAgent] handleVoiceInput called with text:", text);
4881
+ emitSdkDebugLog("[TourAgent] Voice input received", {
4882
+ textLength: text.length
4883
+ }, { devMode: devModeRef.current });
4728
4884
  if (!text) return;
4729
4885
  if (interruptExecution(text)) {
4730
4886
  return;
4731
4887
  }
4732
4888
  if (voiceInputResolveRef.current) {
4733
- console.log("[TourAgent] Resolving loop waiting_voice with text:", text);
4889
+ emitSdkDebugLog("[TourAgent] Resolving waiting voice input", void 0, { devMode: devModeRef.current });
4734
4890
  voiceInputResolveRef.current(text);
4735
4891
  } else if (isSocketWritable(socketRef.current)) {
4736
- console.log("[TourAgent] Forwarding ambient voice to server:", text);
4892
+ emitSdkDebugLog("[TourAgent] Forwarding ambient voice input to server", {
4893
+ textLength: text.length
4894
+ }, { devMode: devModeRef.current });
4737
4895
  emitSocketEvent(socketRef.current, "tour:user_input", {
4738
4896
  transcript: text,
4739
4897
  runId: runIdRef.current,
4740
4898
  turnId: turnIdRef.current
4741
4899
  });
4742
4900
  } else {
4743
- console.log("[TourAgent] buffering voice input because socket is not ready:", text);
4901
+ emitSdkDebugLog("[TourAgent] Buffering voice input until socket is ready", {
4902
+ textLength: text.length
4903
+ }, { devMode: devModeRef.current });
4744
4904
  pendingInputBufRef.current = text;
4745
4905
  }
4746
4906
  }, [interruptExecution]);
@@ -5895,7 +6055,6 @@ function useVoice(serverUrl) {
5895
6055
  setIsListening(false);
5896
6056
  }, [stopLiveSttTransport]);
5897
6057
  const startListening = (0, import_react14.useCallback)((onResult, onInterruption, onError, options = {}) => {
5898
- console.log("[Voice] startListening called, options:", options);
5899
6058
  stopListening();
5900
6059
  listeningSessionIdRef.current = createVoiceDebugId("stt");
5901
6060
  listeningStartedAtRef.current = performance.now();
@@ -6109,7 +6268,9 @@ function useVoice(serverUrl) {
6109
6268
  recorder.start(LIVE_STT_TIMESLICE_MS);
6110
6269
  }
6111
6270
  setIsListening(true);
6112
- console.log("[Voice] Live STT pipeline active (Deepgram streaming + WebRTC loopback)");
6271
+ emitVoiceDebug("stt_live_pipeline_active", {
6272
+ listeningSessionId: listeningSessionIdRef.current
6273
+ });
6113
6274
  } catch (err) {
6114
6275
  const normalizedError = normalizeSttError(err);
6115
6276
  console.warn("[Voice] Failed to start live STT recorder:", normalizedError);
@@ -8931,7 +9092,7 @@ function AgentTraces({ debug, command, defaultExpanded = true }) {
8931
9092
  },
8932
9093
  children: [
8933
9094
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
8934
- "Agent traces (",
9095
+ "Execution summary (",
8935
9096
  traces.length,
8936
9097
  " step",
8937
9098
  traces.length !== 1 ? "s" : "",
@@ -8947,21 +9108,9 @@ function AgentTraces({ debug, command, defaultExpanded = true }) {
8947
9108
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { style: { margin: 0, padding: "8px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: command })
8948
9109
  ] }),
8949
9110
  !hasTraceContent ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "12px", padding: "8px", background: "#fef3c7", borderRadius: "4px", borderLeft: "3px solid #f59e0b" }, children: [
8950
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontWeight: 600, color: "#92400e", marginBottom: "4px" }, children: "No trace data" }),
8951
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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." }),
8952
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { style: { margin: 0, padding: "8px", background: "#fff", borderRadius: "4px", fontSize: "10px", overflow: "auto", maxHeight: "120px", color: "#27272a" }, children: JSON.stringify(debug, null, 2) })
9111
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontWeight: 600, color: "#92400e", marginBottom: "4px" }, children: "No safe debug summary" }),
9112
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "10px", color: "#71717a" }, children: "Verbose prompts, reasoning, and raw tool payloads are intentionally hidden by the SDK." })
8953
9113
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
8954
- debug.llmInput && traces.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "12px" }, children: [
8955
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontWeight: 600, color: "#3f3f46", marginBottom: "4px" }, children: "Input \u2192 agent" }),
8956
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "6px" }, children: [
8957
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "10px", color: "#a1a1aa", marginBottom: "2px" }, children: "System" }),
8958
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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)" })
8959
- ] }),
8960
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
8961
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "10px", color: "#a1a1aa", marginBottom: "2px" }, children: "User" }),
8962
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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)" })
8963
- ] })
8964
- ] }),
8965
9114
  traces.map((t) => {
8966
9115
  const isStepExpanded = expandedSteps.has(t.step);
8967
9116
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "12px", paddingBottom: "12px", borderBottom: "1px solid #e4e4e7" }, children: [
@@ -8994,31 +9143,6 @@ function AgentTraces({ debug, command, defaultExpanded = true }) {
8994
9143
  }
8995
9144
  ),
8996
9145
  isStepExpanded && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
8997
- t.reasoning && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "6px" }, children: [
8998
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#71717a", marginBottom: "2px" }, children: "Reasoning" }),
8999
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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 })
9000
- ] }),
9001
- t.llmInput && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
9002
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "6px" }, children: [
9003
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#71717a", marginBottom: "2px" }, children: "Input \u2192 agent" }),
9004
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "4px" }, children: [
9005
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "10px", color: "#a1a1aa", marginBottom: "2px" }, children: "System" }),
9006
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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)" })
9007
- ] }),
9008
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
9009
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "10px", color: "#a1a1aa", marginBottom: "2px" }, children: "User" }),
9010
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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)" })
9011
- ] })
9012
- ] }),
9013
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "6px" }, children: [
9014
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#71717a", marginBottom: "2px" }, children: "Output \u2190 agent" }),
9015
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { style: { margin: 0, padding: "6px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: "60px", overflow: "auto" }, children: t.llmOutput ?? "(empty)" })
9016
- ] })
9017
- ] }),
9018
- !t.llmInput && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "6px" }, children: [
9019
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#71717a", marginBottom: "2px" }, children: "LLM output" }),
9020
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { style: { margin: 0, padding: "6px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: "60px", overflow: "auto" }, children: t.llmOutput ?? "(empty)" })
9021
- ] }),
9022
9146
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "6px" }, children: [
9023
9147
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#71717a", marginBottom: "2px" }, children: "Actions" }),
9024
9148
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { style: { margin: 0, padding: "6px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: JSON.stringify(t.actions, null, 2) })
@@ -9030,10 +9154,6 @@ function AgentTraces({ debug, command, defaultExpanded = true }) {
9030
9154
  ] })
9031
9155
  ] }, t.step);
9032
9156
  }),
9033
- traces.length === 0 && debug.llmOutput && debug.llmOutput.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "12px" }, children: [
9034
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontWeight: 600, color: "#3f3f46", marginBottom: "4px" }, children: "LLM output" }),
9035
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { style: { margin: 0, padding: "8px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: debug.llmOutput.join("\n\n") })
9036
- ] }),
9037
9157
  traces.length === 0 && (debug.actions?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "12px" }, children: [
9038
9158
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontWeight: 600, color: "#3f3f46", marginBottom: "4px" }, children: "Executed actions" }),
9039
9159
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { style: { margin: 0, padding: "8px", background: "#f4f4f5", borderRadius: "4px", whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: JSON.stringify(debug.actions, null, 2) })
@@ -9229,7 +9349,6 @@ function ModelNexChatBubble({
9229
9349
  tagStore.setTagsBatch(data.tags, true);
9230
9350
  lastAutoTaggedUrlRef.current = currentUrl;
9231
9351
  localStorage.setItem(storageKey, "true");
9232
- console.log(`[ModelNex] Auto-tagged ${data.tags.length} elements for ${currentUrl}`);
9233
9352
  }
9234
9353
  } catch (err) {
9235
9354
  console.warn("[ModelNex] Auto-tag error:", err);
@@ -9393,12 +9512,9 @@ function ModelNexChatBubble({
9393
9512
  };
9394
9513
  const listeningExperience = resolveTourListeningExperience(preferredExperience, listeningState);
9395
9514
  preferredListeningExperienceRef.current = listeningExperience;
9396
- console.log("[ChatBubble] startTourListening called. listeningState:", listeningState, "preferredExperience:", preferredExperience, "listeningExperience:", listeningExperience);
9397
9515
  if (!canStartTourListening(listeningState)) {
9398
- console.log("[ChatBubble] startTourListening bailed out early.");
9399
9516
  return;
9400
9517
  }
9401
- console.log("[ChatBubble] Proceeding to startTourListening...");
9402
9518
  sttActiveRef.current = true;
9403
9519
  updateTourSttError(null);
9404
9520
  resetFloatingLiveTranscriptSuppression();
@@ -9604,7 +9720,7 @@ function ModelNexChatBubble({
9604
9720
  content: summary || fallbackContent,
9605
9721
  summary: summary ?? void 0,
9606
9722
  nextSteps: nextSteps ?? void 0,
9607
- debug: data?.debug ?? void 0
9723
+ debug: devMode ? data?.debug ?? void 0 : void 0
9608
9724
  }
9609
9725
  ]);
9610
9726
  } catch (err) {
@@ -10647,7 +10763,7 @@ function ModelNexChatBubble({
10647
10763
  )
10648
10764
  }
10649
10765
  ),
10650
- msg.role === "assistant" && msg.debug && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AgentTraces, { debug: msg.debug, command: messages[i - 1]?.content ?? "" })
10766
+ msg.role === "assistant" && devMode && msg.debug && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AgentTraces, { debug: msg.debug, command: messages[i - 1]?.content ?? "" })
10651
10767
  ] }, i)),
10652
10768
  loading && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", justifyContent: "flex-start" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
10653
10769
  "div",
@@ -11626,6 +11742,7 @@ var ModelNexProvider = ({
11626
11742
  userProfile,
11627
11743
  toursApiBase,
11628
11744
  devMode,
11745
+ devModeKey,
11629
11746
  serverUrl: serverUrlProp
11630
11747
  }) => {
11631
11748
  const serverUrl = serverUrlProp ?? DEFAULT_MODELNEX_SERVER_URL;
@@ -11648,6 +11765,25 @@ var ModelNexProvider = ({
11648
11765
  const [voiceMuted, setVoiceMuted] = (0, import_react21.useState)(false);
11649
11766
  const [socketId, setSocketId] = (0, import_react21.useState)(null);
11650
11767
  const [actions, setActions] = (0, import_react21.useState)(/* @__PURE__ */ new Map());
11768
+ const [validatedBrowserDevMode, setValidatedBrowserDevMode] = (0, import_react21.useState)(false);
11769
+ const resolvedDevModeKey = (0, import_react21.useMemo)(() => resolveInjectedDevModeKey(devModeKey), [devModeKey]);
11770
+ (0, import_react21.useEffect)(() => {
11771
+ let cancelled = false;
11772
+ if (!websiteId || !resolvedDevModeKey) {
11773
+ setValidatedBrowserDevMode(false);
11774
+ return () => {
11775
+ cancelled = true;
11776
+ };
11777
+ }
11778
+ void validateInjectedDevModeKey(serverUrl, websiteId, resolvedDevModeKey).then((enabled) => {
11779
+ if (cancelled) return;
11780
+ setValidatedBrowserDevMode(enabled);
11781
+ });
11782
+ return () => {
11783
+ cancelled = true;
11784
+ };
11785
+ }, [resolvedDevModeKey, serverUrl, websiteId]);
11786
+ const effectiveDevMode = Boolean(devMode) || validatedBrowserDevMode;
11651
11787
  const registerAction = (0, import_react21.useCallback)((action) => {
11652
11788
  setActions((prev) => {
11653
11789
  const next = new Map(prev);
@@ -11662,7 +11798,7 @@ var ModelNexProvider = ({
11662
11798
  return next;
11663
11799
  });
11664
11800
  }, []);
11665
- const extractedElements = useAutoExtract();
11801
+ const extractedElements = useAutoExtract(effectiveDevMode);
11666
11802
  const tagStore = useTagStore({ serverUrl, websiteId });
11667
11803
  useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl, websiteId, toursApiBase, userProfile);
11668
11804
  const CHAT_STORAGE_KEY = "modelnex-chat-messages";
@@ -11671,21 +11807,32 @@ var ModelNexProvider = ({
11671
11807
  try {
11672
11808
  const stored = sessionStorage.getItem(CHAT_STORAGE_KEY);
11673
11809
  if (stored) {
11674
- setChatMessagesRaw(JSON.parse(stored));
11810
+ setChatMessagesRaw(sanitizeChatMessages(JSON.parse(stored), effectiveDevMode));
11675
11811
  }
11676
11812
  } catch {
11677
11813
  }
11678
- }, []);
11814
+ }, [effectiveDevMode]);
11815
+ (0, import_react21.useEffect)(() => {
11816
+ setChatMessagesRaw((prev) => {
11817
+ const next = sanitizeChatMessages(prev, effectiveDevMode);
11818
+ try {
11819
+ sessionStorage.setItem(CHAT_STORAGE_KEY, JSON.stringify(next));
11820
+ } catch {
11821
+ }
11822
+ return next;
11823
+ });
11824
+ }, [effectiveDevMode]);
11679
11825
  const setChatMessages = (0, import_react21.useCallback)((action) => {
11680
11826
  setChatMessagesRaw((prev) => {
11681
- const next = typeof action === "function" ? action(prev) : action;
11827
+ const resolved = typeof action === "function" ? action(prev) : action;
11828
+ const next = sanitizeChatMessages(resolved, effectiveDevMode);
11682
11829
  try {
11683
11830
  sessionStorage.setItem(CHAT_STORAGE_KEY, JSON.stringify(next));
11684
11831
  } catch {
11685
11832
  }
11686
11833
  return next;
11687
11834
  });
11688
- }, []);
11835
+ }, [effectiveDevMode]);
11689
11836
  useModelNexSocket({
11690
11837
  serverUrl,
11691
11838
  actions,
@@ -11697,7 +11844,8 @@ var ModelNexProvider = ({
11697
11844
  setStagingFields,
11698
11845
  setExecutedFields,
11699
11846
  onSocketId: setSocketId,
11700
- websiteId
11847
+ websiteId,
11848
+ devMode: effectiveDevMode
11701
11849
  });
11702
11850
  useFieldHighlight(stagingFields, executedFields, setExecutedFields);
11703
11851
  (0, import_react21.useEffect)(() => {
@@ -11732,9 +11880,9 @@ var ModelNexProvider = ({
11732
11880
  voiceMuted,
11733
11881
  setVoiceMuted,
11734
11882
  socketId,
11735
- devMode
11883
+ devMode: effectiveDevMode
11736
11884
  }),
11737
- [serverUrl, commandUrl, registerAction, unregisterAction, activeAgentActions, stagingFields, highlightActions, studioMode, recordingMode, extractedElements, tagStore, chatMessages, websiteId, userProfile?.userId, userProfile?.type, userProfile?.isNewUser, toursApiBase, voiceMuted, socketId, devMode]
11885
+ [serverUrl, commandUrl, registerAction, unregisterAction, activeAgentActions, stagingFields, highlightActions, studioMode, recordingMode, extractedElements, tagStore, chatMessages, websiteId, userProfile?.userId, userProfile?.type, userProfile?.isNewUser, toursApiBase, voiceMuted, socketId, effectiveDevMode]
11738
11886
  );
11739
11887
  return import_react21.default.createElement(
11740
11888
  ModelNexContext.Provider,