@midscene/visualizer 0.28.10-beta-20250919094051.0 → 0.28.10

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.
@@ -172,9 +172,29 @@ function Player(props) {
172
172
  const cameraState = useRef({
173
173
  ...basicCameraState
174
174
  });
175
- const repaintImage = async ()=>{
175
+ const resizeCanvasIfNeeded = async (newWidth, newHeight)=>{
176
+ if (app.screen.width !== newWidth || app.screen.height !== newHeight) {
177
+ app.renderer.resize(newWidth, newHeight);
178
+ if (divContainerRef.current) {
179
+ const aspectRatio = newWidth / newHeight;
180
+ divContainerRef.current.style.setProperty('--canvas-aspect-ratio', aspectRatio.toString());
181
+ }
182
+ const newBasicCameraState = {
183
+ left: 0,
184
+ top: 0,
185
+ width: newWidth,
186
+ pointerLeft: Math.round(newWidth / 2),
187
+ pointerTop: Math.round(newHeight / 2)
188
+ };
189
+ cameraState.current = newBasicCameraState;
190
+ }
191
+ };
192
+ const repaintImage = async (scriptWidth, scriptHeight)=>{
176
193
  const imgToUpdate = currentImg.current;
177
194
  if (!imgToUpdate) return void console.warn('no image to update');
195
+ const targetWidth = scriptWidth || imageWidth;
196
+ const targetHeight = scriptHeight || imageHeight;
197
+ await resizeCanvasIfNeeded(targetWidth, targetHeight);
178
198
  if (!getTextureFromCache(imgToUpdate)) {
179
199
  console.warn('image not loaded', imgToUpdate);
180
200
  await loadTexture(imgToUpdate);
@@ -188,8 +208,8 @@ function Player(props) {
188
208
  if (child) windowContentContainer.removeChild(child);
189
209
  sprite.label = mainImgLabel;
190
210
  sprite.zIndex = LAYER_ORDER_IMG;
191
- sprite.width = imageWidth;
192
- sprite.height = imageHeight;
211
+ sprite.width = targetWidth;
212
+ sprite.height = targetHeight;
193
213
  windowContentContainer.addChild(sprite);
194
214
  };
195
215
  const spinningPointer = (frame)=>{
@@ -247,9 +267,10 @@ function Player(props) {
247
267
  pointerSprite.current.zIndex = LAYER_ORDER_POINTER;
248
268
  windowContentContainer.addChild(pointerSprite.current);
249
269
  };
250
- const updateCamera = (state)=>{
270
+ const updateCamera = (state, currentWidth)=>{
251
271
  cameraState.current = state;
252
- const newScale = autoZoom ? Math.max(1, imageWidth / state.width) : 1;
272
+ const effectiveWidth = currentWidth || app.screen.width || imageWidth;
273
+ const newScale = autoZoom ? Math.max(1, effectiveWidth / state.width) : 1;
253
274
  windowContentContainer.scale.set(newScale);
254
275
  windowContentContainer.x = autoZoom ? Math.round(canvasPaddingLeft - state.left * newScale) : canvasPaddingLeft;
255
276
  windowContentContainer.y = autoZoom ? Math.round(canvasPaddingTop - state.top * newScale) : canvasPaddingTop;
@@ -263,6 +284,8 @@ function Player(props) {
263
284
  }
264
285
  };
265
286
  const cameraAnimation = async (targetState, duration, frame)=>{
287
+ const currentCanvasWidth = app.screen.width || imageWidth;
288
+ const currentCanvasHeight = app.screen.height || imageHeight;
266
289
  if (!autoZoom) {
267
290
  const currentState = {
268
291
  ...cameraState.current
@@ -282,7 +305,7 @@ function Player(props) {
282
305
  pointerLeft: startPointerLeft + (targetState.pointerLeft - startPointerLeft) * progress,
283
306
  pointerTop: startPointerTop + (targetState.pointerTop - startPointerTop) * progress
284
307
  };
285
- updateCamera(nextState);
308
+ updateCamera(nextState, currentCanvasWidth);
286
309
  if (elapsedTime < duration) frame(animate);
287
310
  else resolve();
288
311
  };
@@ -297,7 +320,7 @@ function Player(props) {
297
320
  const startTop = currentState.top;
298
321
  const startPointerLeft = currentState.pointerLeft;
299
322
  const startPointerTop = currentState.pointerTop;
300
- const startScale = currentState.width / imageWidth;
323
+ const startScale = currentState.width / currentCanvasWidth;
301
324
  const startTime = performance.now();
302
325
  const shouldMovePointer = 'number' == typeof targetState.pointerLeft && 'number' == typeof targetState.pointerTop && (targetState.pointerLeft !== startPointerLeft || targetState.pointerTop !== startPointerTop);
303
326
  const pointerMoveDuration = shouldMovePointer ? 0.375 * duration : 0;
@@ -322,19 +345,19 @@ function Player(props) {
322
345
  const cameraElapsedTime = elapsedTime - cameraMoveStart;
323
346
  const rawCameraProgress = Math.min(cameraElapsedTime / cameraMoveDuration, 1);
324
347
  const cameraProgress = cubicImage(rawCameraProgress);
325
- const targetScale = targetState.width / imageWidth;
348
+ const targetScale = targetState.width / currentCanvasWidth;
326
349
  const progressScale = startScale + (targetScale - startScale) * cameraProgress;
327
- const progressWidth = imageWidth * progressScale;
328
- const progressHeight = imageHeight * progressScale;
350
+ const progressWidth = currentCanvasWidth * progressScale;
351
+ const progressHeight = currentCanvasHeight * progressScale;
329
352
  nextState.width = progressWidth;
330
353
  const progressLeft = startLeft + (targetState.left - startLeft) * cameraProgress;
331
354
  const progressTop = startTop + (targetState.top - startTop) * cameraProgress;
332
- const horizontalExceed = progressLeft + progressWidth - imageWidth;
333
- const verticalExceed = progressTop + progressHeight - imageHeight;
355
+ const horizontalExceed = progressLeft + progressWidth - currentCanvasWidth;
356
+ const verticalExceed = progressTop + progressHeight - currentCanvasHeight;
334
357
  nextState.left = horizontalExceed > 0 ? progressLeft + horizontalExceed : progressLeft;
335
358
  nextState.top = verticalExceed > 0 ? progressTop + verticalExceed : progressTop;
336
359
  }
337
- updateCamera(nextState);
360
+ updateCamera(nextState, currentCanvasWidth);
338
361
  if (elapsedTime < duration) frame(animate);
339
362
  else resolve();
340
363
  };
@@ -471,7 +494,7 @@ function Player(props) {
471
494
  var _item_context;
472
495
  if (!item.img) throw new Error('img is required');
473
496
  currentImg.current = item.img;
474
- await repaintImage();
497
+ await repaintImage(item.imageWidth, item.imageHeight);
475
498
  const elements = (null == (_item_context = item.context) ? void 0 : _item_context.tree) ? treeToList(item.context.tree) : [];
476
499
  const highlightElements = item.highlightElement ? [
477
500
  item.highlightElement
@@ -488,7 +511,7 @@ function Player(props) {
488
511
  } else if ('img' === item.type) {
489
512
  if (item.img && item.img !== currentImg.current) {
490
513
  currentImg.current = item.img;
491
- await repaintImage();
514
+ await repaintImage(item.imageWidth, item.imageHeight);
492
515
  }
493
516
  if (item.camera) await cameraAnimation(item.camera, item.duration, frame);
494
517
  else await sleep(item.duration);
@@ -91,10 +91,10 @@
91
91
  .playground-container .middle-dialog-area .scroll-to-bottom-button {
92
92
  z-index: 10;
93
93
  background: #fff;
94
+ border: 1px solid rgba(0, 0, 0, .08);
94
95
  position: absolute;
95
96
  bottom: 10px;
96
97
  right: 0;
97
- box-shadow: 0 4px 8px rgba(0, 0, 0, .04);
98
98
  }
99
99
 
100
100
  .playground-container .middle-dialog-area .scroll-to-bottom-button:hover {
@@ -1,7 +1,7 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import icons, { ArrowDownOutlined, ClearOutlined, LoadingOutlined } from "@ant-design/icons";
3
3
  import { Button, Form, List, Tooltip, Typography, message } from "antd";
4
- import { useCallback, useEffect } from "react";
4
+ import { useCallback, useEffect, useMemo, useState } from "react";
5
5
  import { usePlaygroundExecution } from "../../hooks/usePlaygroundExecution.mjs";
6
6
  import { usePlaygroundState } from "../../hooks/usePlaygroundState.mjs";
7
7
  import { useEnvConfig } from "../../store/store.mjs";
@@ -11,7 +11,7 @@ import { PlaygroundResultView } from "../playground-result/index.mjs";
11
11
  import "./index.css";
12
12
  import avatar from "../../icons/avatar.mjs";
13
13
  import { PromptInput } from "../prompt-input/index.mjs";
14
- import { LocalStorageProvider } from "./providers/storage-provider.mjs";
14
+ import { createStorageProvider, detectBestStorageType } from "./providers/storage-provider.mjs";
15
15
  const { Text } = Typography;
16
16
  function getSDKId(sdk) {
17
17
  if (sdk.id && 'string' == typeof sdk.id) return `agent-${sdk.id}`;
@@ -41,11 +41,35 @@ function UniversalPlayground(param) {
41
41
  let { playgroundSDK, storage, contextProvider, config: componentConfig = {}, branding = {}, className = '', dryMode = false, showContextPreview = true } = param;
42
42
  const [form] = Form.useForm();
43
43
  const { config } = useEnvConfig();
44
- const effectiveStorage = (()=>{
44
+ const [sdkReady, setSdkReady] = useState(false);
45
+ useEffect(()=>{
46
+ const initializeSDK = async ()=>{
47
+ if (playgroundSDK && 'function' == typeof playgroundSDK.checkStatus) try {
48
+ await playgroundSDK.checkStatus();
49
+ setSdkReady(true);
50
+ } catch (error) {
51
+ console.warn('Failed to initialize SDK, using default namespace:', error);
52
+ setSdkReady(true);
53
+ }
54
+ else setSdkReady(true);
55
+ };
56
+ initializeSDK();
57
+ }, [
58
+ playgroundSDK
59
+ ]);
60
+ const effectiveStorage = useMemo(()=>{
45
61
  if (storage) return storage;
62
+ if (!sdkReady) return null;
46
63
  const namespace = componentConfig.storageNamespace || getSDKId(playgroundSDK);
47
- return new LocalStorageProvider(namespace);
48
- })();
64
+ const bestStorageType = detectBestStorageType();
65
+ console.log(`Using ${bestStorageType} storage for namespace: ${namespace}`);
66
+ return createStorageProvider(bestStorageType, namespace);
67
+ }, [
68
+ storage,
69
+ sdkReady,
70
+ componentConfig.storageNamespace,
71
+ playgroundSDK
72
+ ]);
49
73
  const { loading, setLoading, infoList, setInfoList, actionSpace, actionSpaceLoading, uiContextPreview, setUiContextPreview, showScrollToBottomButton, verticalMode, replayCounter, setReplayCounter, infoListRef, currentRunningIdRef, interruptedFlagRef, clearInfoList, handleScrollToBottom } = usePlaygroundState(playgroundSDK, effectiveStorage, contextProvider);
50
74
  const { handleRun: executeAction, handleStop, canStop } = usePlaygroundExecution(playgroundSDK, effectiveStorage, actionSpace, loading, setLoading, infoList, setInfoList, replayCounter, setReplayCounter, verticalMode, currentRunningIdRef, interruptedFlagRef);
51
75
  useEffect(()=>{
@@ -0,0 +1,207 @@
1
+ import { IndexedDBManager, createCleanupFunction, withErrorHandling } from "@midscene/shared/baseDB";
2
+ function _define_property(obj, key, value) {
3
+ if (key in obj) Object.defineProperty(obj, key, {
4
+ value: value,
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true
8
+ });
9
+ else obj[key] = value;
10
+ return obj;
11
+ }
12
+ const DB_NAME = 'midscene_playground';
13
+ const DB_VERSION = 1;
14
+ const MESSAGES_STORE = 'playground_messages';
15
+ const RESULTS_STORE = 'playground_results';
16
+ const MAX_STORED_MESSAGES = 100;
17
+ const MAX_STORED_RESULTS = 50;
18
+ class IndexedDBStorageProvider {
19
+ async saveMessages(messages) {
20
+ await withErrorHandling(async ()=>{
21
+ await this.dbManager.clear(MESSAGES_STORE);
22
+ const messagesToSave = messages.slice(-MAX_STORED_MESSAGES);
23
+ await Promise.all(messagesToSave.map((msg, index)=>{
24
+ const lightMessage = {
25
+ ...msg,
26
+ result: void 0
27
+ };
28
+ const data = {
29
+ id: msg.id || `msg-${index}`,
30
+ data: lightMessage,
31
+ timestamp: msg.timestamp ? msg.timestamp.getTime() : Date.now() + index
32
+ };
33
+ return this.dbManager.put(MESSAGES_STORE, data);
34
+ }));
35
+ }, 'Failed to save messages to IndexedDB', void 0, this.messagesCleanup);
36
+ }
37
+ async loadMessages() {
38
+ const result = await withErrorHandling(async ()=>{
39
+ const messages = await this.dbManager.getAll(MESSAGES_STORE, true);
40
+ if (0 === messages.length) return [];
41
+ return Promise.all(messages.map(async (msg)=>{
42
+ const item = msg.data;
43
+ const restoredItem = {
44
+ ...item,
45
+ timestamp: new Date(item.timestamp)
46
+ };
47
+ if ('result' === item.type && item.id) {
48
+ const fullResult = await this.loadResult(item.id);
49
+ if (fullResult) {
50
+ restoredItem.result = fullResult.result;
51
+ restoredItem.replayScriptsInfo = fullResult.replayScriptsInfo;
52
+ restoredItem.replayCounter = fullResult.replayCounter;
53
+ restoredItem.verticalMode = fullResult.verticalMode;
54
+ }
55
+ }
56
+ return restoredItem;
57
+ }));
58
+ }, 'Failed to load messages from IndexedDB', [], this.messagesCleanup);
59
+ return result || [];
60
+ }
61
+ async clearMessages() {
62
+ await withErrorHandling(async ()=>{
63
+ await Promise.all([
64
+ this.dbManager.clear(MESSAGES_STORE),
65
+ this.dbManager.clear(RESULTS_STORE)
66
+ ]);
67
+ }, 'Failed to clear messages from IndexedDB');
68
+ }
69
+ async saveResult(id, result) {
70
+ await withErrorHandling(async ()=>{
71
+ const compressedResult = this.compressResultForStorage(result);
72
+ const data = {
73
+ id,
74
+ data: compressedResult,
75
+ timestamp: Date.now(),
76
+ size: JSON.stringify(compressedResult).length
77
+ };
78
+ await this.dbManager.put(RESULTS_STORE, data);
79
+ }, 'Failed to save result to IndexedDB', void 0, this.resultsCleanup);
80
+ }
81
+ async loadResult(id) {
82
+ const result = await withErrorHandling(async ()=>{
83
+ const data = await this.dbManager.get(RESULTS_STORE, id);
84
+ return (null == data ? void 0 : data.data) || null;
85
+ }, 'Failed to load result from IndexedDB', null);
86
+ return result || null;
87
+ }
88
+ compressResultForStorage(result) {
89
+ var _result_result_dump, _result_result;
90
+ if (!(null == (_result_result = result.result) ? void 0 : null == (_result_result_dump = _result_result.dump) ? void 0 : _result_result_dump.executions)) return result;
91
+ const compressedExecutions = result.result.dump.executions.map((execution)=>{
92
+ var _execution_tasks;
93
+ return {
94
+ ...execution,
95
+ tasks: (null == (_execution_tasks = execution.tasks) ? void 0 : _execution_tasks.map((task)=>{
96
+ var _task_recorder;
97
+ var _this_compressScreenshotIfNeeded;
98
+ return {
99
+ ...task,
100
+ uiContext: task.uiContext ? {
101
+ ...task.uiContext,
102
+ screenshotBase64: null != (_this_compressScreenshotIfNeeded = this.compressScreenshotIfNeeded(task.uiContext.screenshotBase64)) ? _this_compressScreenshotIfNeeded : task.uiContext.screenshotBase64
103
+ } : task.uiContext,
104
+ recorder: null == (_task_recorder = task.recorder) ? void 0 : _task_recorder.map((record)=>({
105
+ ...record,
106
+ screenshot: this.compressScreenshotIfNeeded(record.screenshot)
107
+ }))
108
+ };
109
+ })) || []
110
+ };
111
+ });
112
+ return {
113
+ ...result,
114
+ result: {
115
+ ...result.result,
116
+ dump: {
117
+ ...result.result.dump,
118
+ executions: compressedExecutions
119
+ }
120
+ }
121
+ };
122
+ }
123
+ compressScreenshotIfNeeded(screenshot) {
124
+ if (!screenshot) return screenshot;
125
+ if (screenshot.length > 1048576) {
126
+ const sizeKB = Math.round(screenshot.length / 1024);
127
+ return `[COMPRESSED: ${sizeKB}KB screenshot removed for storage]`;
128
+ }
129
+ return screenshot;
130
+ }
131
+ async getStorageStats() {
132
+ const result = await withErrorHandling(async ()=>{
133
+ const [messageCount, resultCount] = await Promise.all([
134
+ this.dbManager.count(MESSAGES_STORE),
135
+ this.dbManager.count(RESULTS_STORE)
136
+ ]);
137
+ return {
138
+ messageCount,
139
+ resultCount
140
+ };
141
+ }, 'Failed to get storage statistics', {
142
+ messageCount: 0,
143
+ resultCount: 0
144
+ });
145
+ return result || {
146
+ messageCount: 0,
147
+ resultCount: 0
148
+ };
149
+ }
150
+ async cleanup() {
151
+ await Promise.all([
152
+ this.messagesCleanup(),
153
+ this.resultsCleanup()
154
+ ]);
155
+ }
156
+ constructor(namespace = 'playground'){
157
+ _define_property(this, "dbManager", void 0);
158
+ _define_property(this, "namespace", void 0);
159
+ _define_property(this, "messagesCleanup", void 0);
160
+ _define_property(this, "resultsCleanup", void 0);
161
+ this.namespace = namespace;
162
+ this.dbManager = new IndexedDBManager(`${DB_NAME}_${namespace}`, DB_VERSION, [
163
+ {
164
+ name: MESSAGES_STORE,
165
+ keyPath: 'id'
166
+ },
167
+ {
168
+ name: RESULTS_STORE,
169
+ keyPath: 'id'
170
+ }
171
+ ]);
172
+ this.messagesCleanup = createCleanupFunction(this.dbManager, MESSAGES_STORE, MAX_STORED_MESSAGES);
173
+ this.resultsCleanup = createCleanupFunction(this.dbManager, RESULTS_STORE, MAX_STORED_RESULTS);
174
+ }
175
+ }
176
+ class MemoryStorageProvider {
177
+ async saveMessages(messages) {
178
+ this.messages = [
179
+ ...messages
180
+ ];
181
+ }
182
+ async loadMessages() {
183
+ return [
184
+ ...this.messages
185
+ ];
186
+ }
187
+ async clearMessages() {
188
+ this.messages = [];
189
+ this.results.clear();
190
+ }
191
+ async saveResult(id, result) {
192
+ this.results.set(id, result);
193
+ }
194
+ constructor(){
195
+ _define_property(this, "messages", []);
196
+ _define_property(this, "results", new Map());
197
+ }
198
+ }
199
+ class NoOpStorageProvider {
200
+ async saveMessages(_messages) {}
201
+ async loadMessages() {
202
+ return [];
203
+ }
204
+ async clearMessages() {}
205
+ async saveResult(_id, _result) {}
206
+ }
207
+ export { IndexedDBStorageProvider, MemoryStorageProvider, NoOpStorageProvider };
@@ -1,3 +1,4 @@
1
+ import { IndexedDBStorageProvider, MemoryStorageProvider, NoOpStorageProvider } from "./indexeddb-storage-provider.mjs";
1
2
  function _define_property(obj, key, value) {
2
3
  if (key in obj) Object.defineProperty(obj, key, {
3
4
  value: value,
@@ -137,7 +138,7 @@ class LocalStorageProvider {
137
138
  this.resultsKey = `${namespace}-results`;
138
139
  }
139
140
  }
140
- class MemoryStorageProvider {
141
+ class storage_provider_MemoryStorageProvider {
141
142
  async saveMessages(messages) {
142
143
  this.messages = [
143
144
  ...messages
@@ -160,7 +161,7 @@ class MemoryStorageProvider {
160
161
  _define_property(this, "results", new Map());
161
162
  }
162
163
  }
163
- class NoOpStorageProvider {
164
+ class storage_provider_NoOpStorageProvider {
164
165
  async saveMessages(_messages) {}
165
166
  async loadMessages() {
166
167
  return [];
@@ -168,4 +169,42 @@ class NoOpStorageProvider {
168
169
  async clearMessages() {}
169
170
  async saveResult(_id, _result) {}
170
171
  }
171
- export { LocalStorageProvider, MemoryStorageProvider, NoOpStorageProvider };
172
+ var storage_provider_StorageType = /*#__PURE__*/ function(StorageType) {
173
+ StorageType["INDEXEDDB"] = "indexeddb";
174
+ StorageType["LOCALSTORAGE"] = "localStorage";
175
+ StorageType["MEMORY"] = "memory";
176
+ StorageType["NONE"] = "none";
177
+ return StorageType;
178
+ }({});
179
+ function createStorageProvider() {
180
+ let type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "indexeddb", namespace = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 'playground';
181
+ switch(type){
182
+ case "indexeddb":
183
+ if ('undefined' != typeof indexedDB) return new IndexedDBStorageProvider(namespace);
184
+ console.warn('IndexedDB not available, falling back to localStorage');
185
+ return createStorageProvider("localStorage", namespace);
186
+ case "localStorage":
187
+ if ('undefined' != typeof localStorage) return new LocalStorageProvider(namespace);
188
+ console.warn('localStorage not available, falling back to memory storage');
189
+ return createStorageProvider("memory", namespace);
190
+ case "memory":
191
+ return new storage_provider_MemoryStorageProvider();
192
+ case "none":
193
+ return new storage_provider_NoOpStorageProvider();
194
+ default:
195
+ throw new Error(`Unknown storage type: ${type}`);
196
+ }
197
+ }
198
+ function detectBestStorageType() {
199
+ if ('undefined' != typeof indexedDB) try {
200
+ indexedDB.open('test', 1).onerror = ()=>{};
201
+ return "indexeddb";
202
+ } catch (e) {}
203
+ if ('undefined' != typeof localStorage) try {
204
+ localStorage.setItem('test', 'test');
205
+ localStorage.removeItem('test');
206
+ return "localStorage";
207
+ } catch (e) {}
208
+ return "memory";
209
+ }
210
+ export { MemoryStorageProvider as IndexedDBMemoryStorageProvider, NoOpStorageProvider as IndexedDBNoOpStorageProvider, IndexedDBStorageProvider, LocalStorageProvider, storage_provider_MemoryStorageProvider as MemoryStorageProvider, storage_provider_NoOpStorageProvider as NoOpStorageProvider, storage_provider_StorageType as StorageType, createStorageProvider, detectBestStorageType };
@@ -1,4 +1,5 @@
1
1
  import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { createStorageProvider, detectBestStorageType } from "../component/universal-playground/providers/storage-provider.mjs";
2
3
  import { WELCOME_MESSAGE_TEMPLATE } from "../utils/constants.mjs";
3
4
  function usePlaygroundState(playgroundSDK, storage, contextProvider) {
4
5
  const [loading, setLoading] = useState(false);
@@ -12,7 +13,25 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
12
13
  const infoListRef = useRef(null);
13
14
  const currentRunningIdRef = useRef(null);
14
15
  const interruptedFlagRef = useRef({});
16
+ const initializedRef = useRef(false);
15
17
  useEffect(()=>{
18
+ const migrateFromOldNamespace = async ()=>{
19
+ const oldStorage = createStorageProvider(detectBestStorageType(), 'playground-default');
20
+ try {
21
+ if (null == oldStorage ? void 0 : oldStorage.loadMessages) {
22
+ const oldMessages = await oldStorage.loadMessages();
23
+ if (oldMessages.length > 1) {
24
+ console.log('Found data in old namespace, migrating...');
25
+ if (null == storage ? void 0 : storage.saveMessages) await storage.saveMessages(oldMessages);
26
+ if (oldStorage.clearMessages) await oldStorage.clearMessages();
27
+ return oldMessages;
28
+ }
29
+ }
30
+ } catch (error) {
31
+ console.debug('No data found in old namespace:', error);
32
+ }
33
+ return [];
34
+ };
16
35
  const initializeMessages = async ()=>{
17
36
  const welcomeMessage = {
18
37
  ...WELCOME_MESSAGE_TEMPLATE,
@@ -20,7 +39,8 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
20
39
  timestamp: new Date()
21
40
  };
22
41
  if (null == storage ? void 0 : storage.loadMessages) try {
23
- const storedMessages = await storage.loadMessages();
42
+ let storedMessages = await storage.loadMessages();
43
+ if (0 === storedMessages.length) storedMessages = await migrateFromOldNamespace();
24
44
  const hasWelcomeMessage = storedMessages.some((msg)=>'welcome' === msg.id);
25
45
  hasWelcomeMessage ? setInfoList(storedMessages) : setInfoList([
26
46
  welcomeMessage,
@@ -36,8 +56,13 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
36
56
  welcomeMessage
37
57
  ]);
38
58
  };
39
- if (0 === infoList.length) initializeMessages();
40
- }, []);
59
+ if (storage && !initializedRef.current) {
60
+ initializedRef.current = true;
61
+ initializeMessages();
62
+ } else if (!storage && 0 === infoList.length) initializeMessages();
63
+ }, [
64
+ storage
65
+ ]);
41
66
  useEffect(()=>{
42
67
  if ((null == storage ? void 0 : storage.saveMessages) && infoList.length > 1) storage.saveMessages(infoList).catch((error)=>{
43
68
  if (error instanceof DOMException && 'QuotaExceededError' === error.name) console.warn('Storage quota exceeded - some messages may not be saved persistently');
package/dist/es/index.mjs CHANGED
@@ -20,6 +20,6 @@ import { actionNameForType, getPlaceholderForType, staticAgentFromContext } from
20
20
  import { filterBase64Value, timeStr } from "./utils/index.mjs";
21
21
  import shiny_text from "./component/shiny-text/index.mjs";
22
22
  import universal_playground, { UniversalPlayground } from "./component/universal-playground/index.mjs";
23
- import { LocalStorageProvider, MemoryStorageProvider, NoOpStorageProvider } from "./component/universal-playground/providers/storage-provider.mjs";
23
+ import { IndexedDBStorageProvider, LocalStorageProvider, MemoryStorageProvider, NoOpStorageProvider, StorageType, createStorageProvider, detectBestStorageType } from "./component/universal-playground/providers/storage-provider.mjs";
24
24
  import { AgentContextProvider, BaseContextProvider, NoOpContextProvider, StaticContextProvider } from "./component/universal-playground/providers/context-provider.mjs";
25
- export { AgentContextProvider, BaseContextProvider, Blackboard, ContextPreview, EnvConfig, EnvConfigReminder, LocalStorageProvider, Logo, MemoryStorageProvider, NavActions, NoOpContextProvider, NoOpStorageProvider, Player, PlaygroundResultView, PromptInput, ServiceModeControl, shiny_text as ShinyText, StaticContextProvider, UniversalPlayground, universal_playground as UniversalPlaygroundDefault, actionNameForType, allScriptsFromDump, colorForName, filterBase64Value, generateAnimationScripts, getPlaceholderForType, globalThemeConfig, highlightColorForType, iconForStatus, safeOverrideAIConfig, staticAgentFromContext, timeCostStrElement, timeStr, useEnvConfig, useSafeOverrideAIConfig, useServerValid };
25
+ export { AgentContextProvider, BaseContextProvider, Blackboard, ContextPreview, EnvConfig, EnvConfigReminder, IndexedDBStorageProvider, LocalStorageProvider, Logo, MemoryStorageProvider, NavActions, NoOpContextProvider, NoOpStorageProvider, Player, PlaygroundResultView, PromptInput, ServiceModeControl, shiny_text as ShinyText, StaticContextProvider, StorageType, UniversalPlayground, universal_playground as UniversalPlaygroundDefault, actionNameForType, allScriptsFromDump, colorForName, createStorageProvider, detectBestStorageType, filterBase64Value, generateAnimationScripts, getPlaceholderForType, globalThemeConfig, highlightColorForType, iconForStatus, safeOverrideAIConfig, staticAgentFromContext, timeCostStrElement, timeStr, useEnvConfig, useSafeOverrideAIConfig, useServerValid };