@midscene/visualizer 0.28.7-beta-20250912113807.0 → 0.28.7-beta-20250915040112.0

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.
@@ -1,26 +1,9 @@
1
- .history-modal-overlay {
2
- z-index: 1000;
3
- background: rgba(0, 0, 0, .45);
4
- justify-content: stretch;
5
- align-items: flex-end;
6
- display: flex;
7
- position: absolute;
8
- top: 0;
9
- bottom: 0;
10
- left: 0;
11
- right: 0;
12
- }
13
-
14
1
  .history-modal-container {
15
- z-index: 1001;
16
- background: #fff;
17
2
  border-radius: 12px 12px 0 0;
18
3
  flex-direction: column;
19
- width: 100%;
20
- height: 400px;
4
+ height: 70vh;
21
5
  display: flex;
22
6
  overflow: hidden;
23
- box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
24
7
  }
25
8
 
26
9
  .history-modal-container .history-modal-header {
@@ -131,3 +114,19 @@
131
114
  padding: 40px 20px;
132
115
  }
133
116
 
117
+ .ant-modal-wrap .ant-modal-content {
118
+ animation: .3s cubic-bezier(.4, 0, .2, 1) forwards slideUpFromBottom !important;
119
+ }
120
+
121
+ @keyframes slideUpFromBottom {
122
+ 0% {
123
+ opacity: 0;
124
+ transform: translateY(100%);
125
+ }
126
+
127
+ 100% {
128
+ opacity: 1;
129
+ transform: translateY(0);
130
+ }
131
+ }
132
+
@@ -1,5 +1,5 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { Button, Input, Typography } from "antd";
2
+ import { Button, Input, Modal, Typography } from "antd";
3
3
  import { useMemo, useState } from "react";
4
4
  import icons_close from "../../icons/close.mjs";
5
5
  import icons_history from "../../icons/history.mjs";
@@ -63,12 +63,50 @@ const HistorySelector = (param)=>{
63
63
  height: 24
64
64
  })
65
65
  }),
66
- isModalOpen && /*#__PURE__*/ jsx("div", {
67
- className: "history-modal-overlay",
68
- onClick: ()=>setIsModalOpen(false),
66
+ /*#__PURE__*/ jsx(Modal, {
67
+ open: isModalOpen,
68
+ onCancel: ()=>setIsModalOpen(false),
69
+ footer: null,
70
+ width: "100%",
71
+ closable: false,
72
+ centered: false,
73
+ transitionName: "",
74
+ maskTransitionName: "",
75
+ style: {
76
+ margin: 0,
77
+ padding: 0,
78
+ maxWidth: 'none',
79
+ top: 'auto',
80
+ bottom: 0
81
+ },
82
+ styles: {
83
+ wrapper: {
84
+ alignItems: 'flex-end',
85
+ justifyContent: 'center',
86
+ paddingBottom: 0,
87
+ display: 'flex'
88
+ },
89
+ body: {
90
+ height: '70vh',
91
+ padding: 0,
92
+ margin: 0
93
+ },
94
+ content: {
95
+ height: '70vh',
96
+ borderRadius: '12px 12px 0 0',
97
+ margin: 0,
98
+ padding: 0,
99
+ marginBottom: 0,
100
+ position: 'fixed',
101
+ bottom: 0,
102
+ left: 0,
103
+ right: 0
104
+ }
105
+ },
106
+ maskClosable: true,
107
+ destroyOnClose: true,
69
108
  children: /*#__PURE__*/ jsxs("div", {
70
109
  className: "history-modal-container",
71
- onClick: (e)=>e.stopPropagation(),
72
110
  children: [
73
111
  /*#__PURE__*/ jsxs("div", {
74
112
  className: "history-modal-header",
@@ -1,5 +1,6 @@
1
1
  .result-wrapper {
2
2
  justify-content: center;
3
+ align-items: center;
3
4
  height: 100%;
4
5
  margin: 4px 0;
5
6
  display: flex;
@@ -39,48 +40,22 @@
39
40
  .prompt-input-wrapper .mode-radio-group-wrapper {
40
41
  justify-content: space-between;
41
42
  align-items: center;
42
- gap: 8px;
43
43
  display: flex;
44
44
  }
45
45
 
46
46
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group {
47
- scrollbar-width: none;
48
- -ms-overflow-style: none;
49
47
  align-items: center;
50
- gap: 8px;
51
- width: 350px;
52
- min-width: 350px;
53
- max-width: 350px;
54
48
  height: 100%;
55
49
  display: flex;
56
- overflow-x: auto;
57
- overflow-y: hidden;
58
- }
59
-
60
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group::-webkit-scrollbar {
61
- display: none;
62
- }
63
-
64
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-form-item {
65
- flex-shrink: 0;
66
- margin: 0 !important;
67
- }
68
-
69
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-form-item .ant-radio-group {
70
- flex-wrap: nowrap;
71
- gap: 8px;
72
- display: flex;
73
50
  }
74
51
 
75
52
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper {
76
53
  height: 24px;
77
54
  box-shadow: none;
78
- white-space: nowrap;
79
55
  background-color: #f7f7f7;
80
56
  border: none;
81
57
  border-radius: 11px;
82
- flex-shrink: 0;
83
- margin-right: 0;
58
+ margin-right: 8px;
84
59
  padding: 0 8px;
85
60
  font-size: 12px;
86
61
  line-height: 24px;
@@ -104,18 +79,12 @@
104
79
  color: #fff;
105
80
  }
106
81
 
107
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-dropdown-trigger {
108
- flex-shrink: 0;
109
- }
110
-
111
82
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button {
112
83
  height: 24px;
113
84
  box-shadow: none;
114
- white-space: nowrap;
115
85
  background-color: #f7f7f7;
116
86
  border: none;
117
87
  border-radius: 11px;
118
- flex-shrink: 0;
119
88
  align-items: center;
120
89
  gap: 2px;
121
90
  max-width: 160px;
@@ -145,7 +114,6 @@
145
114
  }
146
115
 
147
116
  .prompt-input-wrapper .mode-radio-group-wrapper .action-icons {
148
- flex-shrink: 0;
149
117
  align-items: center;
150
118
  display: flex;
151
119
  }
@@ -1,5 +1,6 @@
1
1
  .result-wrapper {
2
2
  justify-content: center;
3
+ align-items: center;
3
4
  height: 100%;
4
5
  margin: 4px 0;
5
6
  display: flex;
@@ -54,7 +54,8 @@ const PlaygroundResultView = (param)=>{
54
54
  display: 'flex',
55
55
  flexDirection: 'column',
56
56
  flex: '1 1 auto',
57
- justifyContent: 'center'
57
+ justifyContent: 'center',
58
+ alignItems: 'center'
58
59
  },
59
60
  children: resultDataToShow
60
61
  });
@@ -5,48 +5,22 @@
5
5
  .prompt-input-wrapper .mode-radio-group-wrapper {
6
6
  justify-content: space-between;
7
7
  align-items: center;
8
- gap: 8px;
9
8
  display: flex;
10
9
  }
11
10
 
12
11
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group {
13
- scrollbar-width: none;
14
- -ms-overflow-style: none;
15
12
  align-items: center;
16
- gap: 8px;
17
- width: 350px;
18
- min-width: 350px;
19
- max-width: 350px;
20
13
  height: 100%;
21
14
  display: flex;
22
- overflow-x: auto;
23
- overflow-y: hidden;
24
- }
25
-
26
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group::-webkit-scrollbar {
27
- display: none;
28
- }
29
-
30
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-form-item {
31
- flex-shrink: 0;
32
- margin: 0 !important;
33
- }
34
-
35
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-form-item .ant-radio-group {
36
- flex-wrap: nowrap;
37
- gap: 8px;
38
- display: flex;
39
15
  }
40
16
 
41
17
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper {
42
18
  height: 24px;
43
19
  box-shadow: none;
44
- white-space: nowrap;
45
20
  background-color: #f7f7f7;
46
21
  border: none;
47
22
  border-radius: 11px;
48
- flex-shrink: 0;
49
- margin-right: 0;
23
+ margin-right: 8px;
50
24
  padding: 0 8px;
51
25
  font-size: 12px;
52
26
  line-height: 24px;
@@ -70,18 +44,12 @@
70
44
  color: #fff;
71
45
  }
72
46
 
73
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-dropdown-trigger {
74
- flex-shrink: 0;
75
- }
76
-
77
47
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button {
78
48
  height: 24px;
79
49
  box-shadow: none;
80
- white-space: nowrap;
81
50
  background-color: #f7f7f7;
82
51
  border: none;
83
52
  border-radius: 11px;
84
- flex-shrink: 0;
85
53
  align-items: center;
86
54
  gap: 2px;
87
55
  max-width: 160px;
@@ -111,7 +79,6 @@
111
79
  }
112
80
 
113
81
  .prompt-input-wrapper .mode-radio-group-wrapper .action-icons {
114
- flex-shrink: 0;
115
82
  align-items: center;
116
83
  display: flex;
117
84
  }
@@ -4,13 +4,13 @@
4
4
  width: 100%;
5
5
  height: 100vh;
6
6
  display: flex;
7
- position: relative;
8
7
  }
9
8
 
10
9
  .playground-container .command-form {
11
10
  flex-direction: column;
12
11
  width: 100%;
13
12
  height: 100%;
13
+ padding: 0 12px;
14
14
  display: flex;
15
15
  }
16
16
 
@@ -119,7 +119,7 @@
119
119
 
120
120
  .playground-container .user-message-container .user-message-bubble {
121
121
  color: rgba(0, 0, 0, .85);
122
- text-align: left;
122
+ text-align: center;
123
123
  background: #f2f4f7;
124
124
  border-radius: 12px;
125
125
  max-width: 80%;
@@ -11,12 +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";
15
14
  const { Text } = Typography;
16
- function getSDKId(sdk) {
17
- if (sdk.id && 'string' == typeof sdk.id) return `agent-${sdk.id}`;
18
- return 'playground-default';
19
- }
20
15
  function ErrorMessage(param) {
21
16
  let { error } = param;
22
17
  if (!error) return null;
@@ -41,13 +36,9 @@ function UniversalPlayground(param) {
41
36
  let { playgroundSDK, storage, contextProvider, config: componentConfig = {}, branding = {}, className = '', dryMode = false, showContextPreview = true } = param;
42
37
  const [form] = Form.useForm();
43
38
  const { deepThink, screenshotIncluded, domIncluded, config } = useEnvConfig();
44
- const effectiveStorage = (()=>{
45
- if (storage) return storage;
46
- const namespace = componentConfig.storageNamespace || getSDKId(playgroundSDK);
47
- return new LocalStorageProvider(namespace);
48
- })();
49
- const { loading, setLoading, infoList, setInfoList, actionSpace, actionSpaceLoading, uiContextPreview, setUiContextPreview, showScrollToBottomButton, verticalMode, replayCounter, setReplayCounter, infoListRef, currentRunningIdRef, interruptedFlagRef, clearInfoList, handleScrollToBottom } = usePlaygroundState(playgroundSDK, effectiveStorage, contextProvider);
50
- const { handleRun: executeAction, handleStop, canStop } = usePlaygroundExecution(playgroundSDK, effectiveStorage, actionSpace, loading, setLoading, infoList, setInfoList, replayCounter, setReplayCounter, verticalMode, currentRunningIdRef, interruptedFlagRef);
39
+ const enablePersistence = false !== componentConfig.enablePersistence;
40
+ const { loading, setLoading, infoList, setInfoList, actionSpace, actionSpaceLoading, uiContextPreview, setUiContextPreview, showScrollToBottomButton, verticalMode, replayCounter, setReplayCounter, infoListRef, currentRunningIdRef, interruptedFlagRef, clearInfoList, handleScrollToBottom } = usePlaygroundState(playgroundSDK, storage, contextProvider, enablePersistence);
41
+ const { handleRun: executeAction, handleStop, canStop } = usePlaygroundExecution(playgroundSDK, storage, actionSpace, loading, setLoading, infoList, setInfoList, replayCounter, setReplayCounter, verticalMode, currentRunningIdRef, interruptedFlagRef);
51
42
  useEffect(()=>{
52
43
  const completeConfig = {
53
44
  ...config,
@@ -55,7 +46,7 @@ function UniversalPlayground(param) {
55
46
  screenshotIncluded,
56
47
  domIncluded
57
48
  };
58
- if (null == playgroundSDK ? void 0 : playgroundSDK.overrideConfig) playgroundSDK.overrideConfig(completeConfig).catch((error)=>{
49
+ if (playgroundSDK.overrideConfig) playgroundSDK.overrideConfig(completeConfig).catch((error)=>{
59
50
  console.error('Failed to override SDK config:', error);
60
51
  });
61
52
  }, [
@@ -254,7 +245,7 @@ function UniversalPlayground(param) {
254
245
  /*#__PURE__*/ jsxs("div", {
255
246
  className: "bottom-input-section",
256
247
  children: [
257
- componentConfig.showEnvConfigReminder ? /*#__PURE__*/ jsx(EnvConfigReminder, {}) : null,
248
+ !componentConfig.serverMode && /*#__PURE__*/ jsx(EnvConfigReminder, {}),
258
249
  /*#__PURE__*/ jsx(PromptInput, {
259
250
  runButtonEnabled: runButtonEnabled,
260
251
  form: form,
@@ -7,7 +7,6 @@ const noReplayAPIs = [
7
7
  ];
8
8
  function usePlaygroundExecution(playgroundSDK, storage, actionSpace, loading, setLoading, infoList, setInfoList, replayCounter, setReplayCounter, verticalMode, currentRunningIdRef, interruptedFlagRef) {
9
9
  const handleRun = useCallback(async (value)=>{
10
- if (!playgroundSDK) return void console.warn('PlaygroundSDK is not available');
11
10
  const thisRunningId = Date.now();
12
11
  const actionType = value.type;
13
12
  const displayContent = `${value.type}: ${value.prompt || JSON.stringify(value.params)}`;
@@ -40,23 +39,18 @@ function usePlaygroundExecution(playgroundSDK, storage, actionSpace, loading, se
40
39
  try {
41
40
  currentRunningIdRef.current = thisRunningId;
42
41
  interruptedFlagRef.current[thisRunningId] = false;
43
- if (playgroundSDK.onProgressUpdate) playgroundSDK.onProgressUpdate(()=>{});
44
42
  if (playgroundSDK.onProgressUpdate) playgroundSDK.onProgressUpdate((tip)=>{
45
43
  if (interruptedFlagRef.current[thisRunningId]) return;
46
- setInfoList((prev)=>{
47
- const lastItem = prev[prev.length - 1];
48
- if (lastItem && 'progress' === lastItem.type && lastItem.content === tip) return prev;
49
- const progressItem = {
50
- id: `progress-${thisRunningId}-${Date.now()}`,
51
- type: 'progress',
52
- content: tip,
53
- timestamp: new Date()
54
- };
55
- return [
44
+ const progressItem = {
45
+ id: `progress-${thisRunningId}-${Date.now()}`,
46
+ type: 'progress',
47
+ content: tip,
48
+ timestamp: new Date()
49
+ };
50
+ setInfoList((prev)=>[
56
51
  ...prev,
57
52
  progressItem
58
- ];
59
- });
53
+ ]);
60
54
  });
61
55
  result.result = await playgroundSDK.executeAction(actionType, value, {
62
56
  requestId: thisRunningId.toString()
@@ -134,11 +128,10 @@ function usePlaygroundExecution(playgroundSDK, storage, actionSpace, loading, se
134
128
  ]);
135
129
  const handleStop = useCallback(async ()=>{
136
130
  const thisRunningId = currentRunningIdRef.current;
137
- if (thisRunningId && playgroundSDK && playgroundSDK.cancelExecution) try {
131
+ if (thisRunningId && playgroundSDK.cancelExecution) try {
138
132
  await playgroundSDK.cancelExecution(thisRunningId.toString());
139
133
  interruptedFlagRef.current[thisRunningId] = true;
140
134
  setLoading(false);
141
- if (playgroundSDK.onProgressUpdate) playgroundSDK.onProgressUpdate(()=>{});
142
135
  setInfoList((prev)=>prev.map((item)=>item.id === `system-${thisRunningId}` && item.loading ? {
143
136
  ...item,
144
137
  content: 'Operation stopped',
@@ -165,7 +158,7 @@ function usePlaygroundExecution(playgroundSDK, storage, actionSpace, loading, se
165
158
  setLoading,
166
159
  setInfoList
167
160
  ]);
168
- const canStop = loading && !!currentRunningIdRef.current && !!playgroundSDK && !!playgroundSDK.cancelExecution;
161
+ const canStop = loading && !!currentRunningIdRef.current && !!playgroundSDK.cancelExecution;
169
162
  return {
170
163
  handleRun,
171
164
  handleStop,
@@ -1,6 +1,7 @@
1
1
  import { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { WELCOME_MESSAGE_TEMPLATE } from "../utils/constants.mjs";
3
3
  function usePlaygroundState(playgroundSDK, storage, contextProvider) {
4
+ let enablePersistence = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : true;
4
5
  const [loading, setLoading] = useState(false);
5
6
  const [infoList, setInfoList] = useState([]);
6
7
  const [actionSpace, setActionSpace] = useState([]);
@@ -19,7 +20,7 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
19
20
  id: 'welcome',
20
21
  timestamp: new Date()
21
22
  };
22
- if (null == storage ? void 0 : storage.loadMessages) try {
23
+ if (enablePersistence && (null == storage ? void 0 : storage.loadMessages)) try {
23
24
  const storedMessages = await storage.loadMessages();
24
25
  const hasWelcomeMessage = storedMessages.some((msg)=>'welcome' === msg.id);
25
26
  hasWelcomeMessage ? setInfoList(storedMessages) : setInfoList([
@@ -39,12 +40,13 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
39
40
  if (0 === infoList.length) initializeMessages();
40
41
  }, []);
41
42
  useEffect(()=>{
42
- if ((null == storage ? void 0 : storage.saveMessages) && infoList.length > 1) storage.saveMessages(infoList).catch((error)=>{
43
+ if (enablePersistence && (null == storage ? void 0 : storage.saveMessages) && infoList.length > 1) storage.saveMessages(infoList).catch((error)=>{
43
44
  console.error('Failed to save messages:', error);
44
45
  });
45
46
  }, [
46
47
  infoList,
47
- storage
48
+ storage,
49
+ enablePersistence
48
50
  ]);
49
51
  useEffect(()=>{
50
52
  if (!(null == contextProvider ? void 0 : contextProvider.getUIContext) || uiContextPreview) return;
@@ -60,7 +62,6 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
60
62
  setActionSpaceLoading(true);
61
63
  try {
62
64
  var _contextProvider_getUIContext;
63
- if (!playgroundSDK) return void setActionSpace([]);
64
65
  const context = uiContextPreview || await (null == contextProvider ? void 0 : null == (_contextProvider_getUIContext = contextProvider.getUIContext) ? void 0 : _contextProvider_getUIContext.call(contextProvider));
65
66
  const space = await playgroundSDK.getActionSpace(context);
66
67
  setActionSpace(space || []);
@@ -134,13 +135,14 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
134
135
  setInfoList([
135
136
  welcomeMessage
136
137
  ]);
137
- if (null == storage ? void 0 : storage.clearMessages) try {
138
+ if (enablePersistence && (null == storage ? void 0 : storage.clearMessages)) try {
138
139
  await storage.clearMessages();
139
140
  } catch (error) {
140
141
  console.error('Failed to clear stored messages:', error);
141
142
  }
142
143
  }, [
143
- storage
144
+ storage,
145
+ enablePersistence
144
146
  ]);
145
147
  const refreshContext = useCallback(async ()=>{
146
148
  if (null == contextProvider ? void 0 : contextProvider.refreshContext) try {
@@ -1,26 +1,9 @@
1
- .history-modal-overlay {
2
- z-index: 1000;
3
- background: rgba(0, 0, 0, .45);
4
- justify-content: stretch;
5
- align-items: flex-end;
6
- display: flex;
7
- position: absolute;
8
- top: 0;
9
- bottom: 0;
10
- left: 0;
11
- right: 0;
12
- }
13
-
14
1
  .history-modal-container {
15
- z-index: 1001;
16
- background: #fff;
17
2
  border-radius: 12px 12px 0 0;
18
3
  flex-direction: column;
19
- width: 100%;
20
- height: 400px;
4
+ height: 70vh;
21
5
  display: flex;
22
6
  overflow: hidden;
23
- box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
24
7
  }
25
8
 
26
9
  .history-modal-container .history-modal-header {
@@ -131,3 +114,19 @@
131
114
  padding: 40px 20px;
132
115
  }
133
116
 
117
+ .ant-modal-wrap .ant-modal-content {
118
+ animation: .3s cubic-bezier(.4, 0, .2, 1) forwards slideUpFromBottom !important;
119
+ }
120
+
121
+ @keyframes slideUpFromBottom {
122
+ 0% {
123
+ opacity: 0;
124
+ transform: translateY(100%);
125
+ }
126
+
127
+ 100% {
128
+ opacity: 1;
129
+ transform: translateY(0);
130
+ }
131
+ }
132
+
@@ -103,12 +103,50 @@ const HistorySelector = (param)=>{
103
103
  height: 24
104
104
  })
105
105
  }),
106
- isModalOpen && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
107
- className: "history-modal-overlay",
108
- onClick: ()=>setIsModalOpen(false),
106
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_antd_namespaceObject.Modal, {
107
+ open: isModalOpen,
108
+ onCancel: ()=>setIsModalOpen(false),
109
+ footer: null,
110
+ width: "100%",
111
+ closable: false,
112
+ centered: false,
113
+ transitionName: "",
114
+ maskTransitionName: "",
115
+ style: {
116
+ margin: 0,
117
+ padding: 0,
118
+ maxWidth: 'none',
119
+ top: 'auto',
120
+ bottom: 0
121
+ },
122
+ styles: {
123
+ wrapper: {
124
+ alignItems: 'flex-end',
125
+ justifyContent: 'center',
126
+ paddingBottom: 0,
127
+ display: 'flex'
128
+ },
129
+ body: {
130
+ height: '70vh',
131
+ padding: 0,
132
+ margin: 0
133
+ },
134
+ content: {
135
+ height: '70vh',
136
+ borderRadius: '12px 12px 0 0',
137
+ margin: 0,
138
+ padding: 0,
139
+ marginBottom: 0,
140
+ position: 'fixed',
141
+ bottom: 0,
142
+ left: 0,
143
+ right: 0
144
+ }
145
+ },
146
+ maskClosable: true,
147
+ destroyOnClose: true,
109
148
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
110
149
  className: "history-modal-container",
111
- onClick: (e)=>e.stopPropagation(),
112
150
  children: [
113
151
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
114
152
  className: "history-modal-header",
@@ -1,5 +1,6 @@
1
1
  .result-wrapper {
2
2
  justify-content: center;
3
+ align-items: center;
3
4
  height: 100%;
4
5
  margin: 4px 0;
5
6
  display: flex;
@@ -39,48 +40,22 @@
39
40
  .prompt-input-wrapper .mode-radio-group-wrapper {
40
41
  justify-content: space-between;
41
42
  align-items: center;
42
- gap: 8px;
43
43
  display: flex;
44
44
  }
45
45
 
46
46
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group {
47
- scrollbar-width: none;
48
- -ms-overflow-style: none;
49
47
  align-items: center;
50
- gap: 8px;
51
- width: 350px;
52
- min-width: 350px;
53
- max-width: 350px;
54
48
  height: 100%;
55
49
  display: flex;
56
- overflow-x: auto;
57
- overflow-y: hidden;
58
- }
59
-
60
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group::-webkit-scrollbar {
61
- display: none;
62
- }
63
-
64
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-form-item {
65
- flex-shrink: 0;
66
- margin: 0 !important;
67
- }
68
-
69
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-form-item .ant-radio-group {
70
- flex-wrap: nowrap;
71
- gap: 8px;
72
- display: flex;
73
50
  }
74
51
 
75
52
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper {
76
53
  height: 24px;
77
54
  box-shadow: none;
78
- white-space: nowrap;
79
55
  background-color: #f7f7f7;
80
56
  border: none;
81
57
  border-radius: 11px;
82
- flex-shrink: 0;
83
- margin-right: 0;
58
+ margin-right: 8px;
84
59
  padding: 0 8px;
85
60
  font-size: 12px;
86
61
  line-height: 24px;
@@ -104,18 +79,12 @@
104
79
  color: #fff;
105
80
  }
106
81
 
107
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-dropdown-trigger {
108
- flex-shrink: 0;
109
- }
110
-
111
82
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button {
112
83
  height: 24px;
113
84
  box-shadow: none;
114
- white-space: nowrap;
115
85
  background-color: #f7f7f7;
116
86
  border: none;
117
87
  border-radius: 11px;
118
- flex-shrink: 0;
119
88
  align-items: center;
120
89
  gap: 2px;
121
90
  max-width: 160px;
@@ -145,7 +114,6 @@
145
114
  }
146
115
 
147
116
  .prompt-input-wrapper .mode-radio-group-wrapper .action-icons {
148
- flex-shrink: 0;
149
117
  align-items: center;
150
118
  display: flex;
151
119
  }
@@ -1,5 +1,6 @@
1
1
  .result-wrapper {
2
2
  justify-content: center;
3
+ align-items: center;
3
4
  height: 100%;
4
5
  margin: 4px 0;
5
6
  display: flex;
@@ -92,7 +92,8 @@ const PlaygroundResultView = (param)=>{
92
92
  display: 'flex',
93
93
  flexDirection: 'column',
94
94
  flex: '1 1 auto',
95
- justifyContent: 'center'
95
+ justifyContent: 'center',
96
+ alignItems: 'center'
96
97
  },
97
98
  children: resultDataToShow
98
99
  });
@@ -5,48 +5,22 @@
5
5
  .prompt-input-wrapper .mode-radio-group-wrapper {
6
6
  justify-content: space-between;
7
7
  align-items: center;
8
- gap: 8px;
9
8
  display: flex;
10
9
  }
11
10
 
12
11
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group {
13
- scrollbar-width: none;
14
- -ms-overflow-style: none;
15
12
  align-items: center;
16
- gap: 8px;
17
- width: 350px;
18
- min-width: 350px;
19
- max-width: 350px;
20
13
  height: 100%;
21
14
  display: flex;
22
- overflow-x: auto;
23
- overflow-y: hidden;
24
- }
25
-
26
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group::-webkit-scrollbar {
27
- display: none;
28
- }
29
-
30
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-form-item {
31
- flex-shrink: 0;
32
- margin: 0 !important;
33
- }
34
-
35
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-form-item .ant-radio-group {
36
- flex-wrap: nowrap;
37
- gap: 8px;
38
- display: flex;
39
15
  }
40
16
 
41
17
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper {
42
18
  height: 24px;
43
19
  box-shadow: none;
44
- white-space: nowrap;
45
20
  background-color: #f7f7f7;
46
21
  border: none;
47
22
  border-radius: 11px;
48
- flex-shrink: 0;
49
- margin-right: 0;
23
+ margin-right: 8px;
50
24
  padding: 0 8px;
51
25
  font-size: 12px;
52
26
  line-height: 24px;
@@ -70,18 +44,12 @@
70
44
  color: #fff;
71
45
  }
72
46
 
73
- .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-dropdown-trigger {
74
- flex-shrink: 0;
75
- }
76
-
77
47
  .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button {
78
48
  height: 24px;
79
49
  box-shadow: none;
80
- white-space: nowrap;
81
50
  background-color: #f7f7f7;
82
51
  border: none;
83
52
  border-radius: 11px;
84
- flex-shrink: 0;
85
53
  align-items: center;
86
54
  gap: 2px;
87
55
  max-width: 160px;
@@ -111,7 +79,6 @@
111
79
  }
112
80
 
113
81
  .prompt-input-wrapper .mode-radio-group-wrapper .action-icons {
114
- flex-shrink: 0;
115
82
  align-items: center;
116
83
  display: flex;
117
84
  }
@@ -4,13 +4,13 @@
4
4
  width: 100%;
5
5
  height: 100vh;
6
6
  display: flex;
7
- position: relative;
8
7
  }
9
8
 
10
9
  .playground-container .command-form {
11
10
  flex-direction: column;
12
11
  width: 100%;
13
12
  height: 100%;
13
+ padding: 0 12px;
14
14
  display: flex;
15
15
  }
16
16
 
@@ -119,7 +119,7 @@
119
119
 
120
120
  .playground-container .user-message-container .user-message-bubble {
121
121
  color: rgba(0, 0, 0, .85);
122
- text-align: left;
122
+ text-align: center;
123
123
  background: #f2f4f7;
124
124
  border-radius: 12px;
125
125
  max-width: 80%;
@@ -51,12 +51,7 @@ require("./index.css");
51
51
  const avatar_js_namespaceObject = require("../../icons/avatar.js");
52
52
  var avatar_js_default = /*#__PURE__*/ __webpack_require__.n(avatar_js_namespaceObject);
53
53
  const external_prompt_input_index_js_namespaceObject = require("../prompt-input/index.js");
54
- const storage_provider_js_namespaceObject = require("./providers/storage-provider.js");
55
54
  const { Text } = external_antd_namespaceObject.Typography;
56
- function getSDKId(sdk) {
57
- if (sdk.id && 'string' == typeof sdk.id) return `agent-${sdk.id}`;
58
- return 'playground-default';
59
- }
60
55
  function ErrorMessage(param) {
61
56
  let { error } = param;
62
57
  if (!error) return null;
@@ -81,13 +76,9 @@ function UniversalPlayground(param) {
81
76
  let { playgroundSDK, storage, contextProvider, config: componentConfig = {}, branding = {}, className = '', dryMode = false, showContextPreview = true } = param;
82
77
  const [form] = external_antd_namespaceObject.Form.useForm();
83
78
  const { deepThink, screenshotIncluded, domIncluded, config } = (0, store_js_namespaceObject.useEnvConfig)();
84
- const effectiveStorage = (()=>{
85
- if (storage) return storage;
86
- const namespace = componentConfig.storageNamespace || getSDKId(playgroundSDK);
87
- return new storage_provider_js_namespaceObject.LocalStorageProvider(namespace);
88
- })();
89
- const { loading, setLoading, infoList, setInfoList, actionSpace, actionSpaceLoading, uiContextPreview, setUiContextPreview, showScrollToBottomButton, verticalMode, replayCounter, setReplayCounter, infoListRef, currentRunningIdRef, interruptedFlagRef, clearInfoList, handleScrollToBottom } = (0, usePlaygroundState_js_namespaceObject.usePlaygroundState)(playgroundSDK, effectiveStorage, contextProvider);
90
- const { handleRun: executeAction, handleStop, canStop } = (0, usePlaygroundExecution_js_namespaceObject.usePlaygroundExecution)(playgroundSDK, effectiveStorage, actionSpace, loading, setLoading, infoList, setInfoList, replayCounter, setReplayCounter, verticalMode, currentRunningIdRef, interruptedFlagRef);
79
+ const enablePersistence = false !== componentConfig.enablePersistence;
80
+ const { loading, setLoading, infoList, setInfoList, actionSpace, actionSpaceLoading, uiContextPreview, setUiContextPreview, showScrollToBottomButton, verticalMode, replayCounter, setReplayCounter, infoListRef, currentRunningIdRef, interruptedFlagRef, clearInfoList, handleScrollToBottom } = (0, usePlaygroundState_js_namespaceObject.usePlaygroundState)(playgroundSDK, storage, contextProvider, enablePersistence);
81
+ const { handleRun: executeAction, handleStop, canStop } = (0, usePlaygroundExecution_js_namespaceObject.usePlaygroundExecution)(playgroundSDK, storage, actionSpace, loading, setLoading, infoList, setInfoList, replayCounter, setReplayCounter, verticalMode, currentRunningIdRef, interruptedFlagRef);
91
82
  (0, external_react_namespaceObject.useEffect)(()=>{
92
83
  const completeConfig = {
93
84
  ...config,
@@ -95,7 +86,7 @@ function UniversalPlayground(param) {
95
86
  screenshotIncluded,
96
87
  domIncluded
97
88
  };
98
- if (null == playgroundSDK ? void 0 : playgroundSDK.overrideConfig) playgroundSDK.overrideConfig(completeConfig).catch((error)=>{
89
+ if (playgroundSDK.overrideConfig) playgroundSDK.overrideConfig(completeConfig).catch((error)=>{
99
90
  console.error('Failed to override SDK config:', error);
100
91
  });
101
92
  }, [
@@ -294,7 +285,7 @@ function UniversalPlayground(param) {
294
285
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
295
286
  className: "bottom-input-section",
296
287
  children: [
297
- componentConfig.showEnvConfigReminder ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_env_config_reminder_index_js_namespaceObject.EnvConfigReminder, {}) : null,
288
+ !componentConfig.serverMode && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_env_config_reminder_index_js_namespaceObject.EnvConfigReminder, {}),
298
289
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_prompt_input_index_js_namespaceObject.PromptInput, {
299
290
  runButtonEnabled: runButtonEnabled,
300
291
  form: form,
@@ -35,7 +35,6 @@ const noReplayAPIs = [
35
35
  ];
36
36
  function usePlaygroundExecution(playgroundSDK, storage, actionSpace, loading, setLoading, infoList, setInfoList, replayCounter, setReplayCounter, verticalMode, currentRunningIdRef, interruptedFlagRef) {
37
37
  const handleRun = (0, external_react_namespaceObject.useCallback)(async (value)=>{
38
- if (!playgroundSDK) return void console.warn('PlaygroundSDK is not available');
39
38
  const thisRunningId = Date.now();
40
39
  const actionType = value.type;
41
40
  const displayContent = `${value.type}: ${value.prompt || JSON.stringify(value.params)}`;
@@ -68,23 +67,18 @@ function usePlaygroundExecution(playgroundSDK, storage, actionSpace, loading, se
68
67
  try {
69
68
  currentRunningIdRef.current = thisRunningId;
70
69
  interruptedFlagRef.current[thisRunningId] = false;
71
- if (playgroundSDK.onProgressUpdate) playgroundSDK.onProgressUpdate(()=>{});
72
70
  if (playgroundSDK.onProgressUpdate) playgroundSDK.onProgressUpdate((tip)=>{
73
71
  if (interruptedFlagRef.current[thisRunningId]) return;
74
- setInfoList((prev)=>{
75
- const lastItem = prev[prev.length - 1];
76
- if (lastItem && 'progress' === lastItem.type && lastItem.content === tip) return prev;
77
- const progressItem = {
78
- id: `progress-${thisRunningId}-${Date.now()}`,
79
- type: 'progress',
80
- content: tip,
81
- timestamp: new Date()
82
- };
83
- return [
72
+ const progressItem = {
73
+ id: `progress-${thisRunningId}-${Date.now()}`,
74
+ type: 'progress',
75
+ content: tip,
76
+ timestamp: new Date()
77
+ };
78
+ setInfoList((prev)=>[
84
79
  ...prev,
85
80
  progressItem
86
- ];
87
- });
81
+ ]);
88
82
  });
89
83
  result.result = await playgroundSDK.executeAction(actionType, value, {
90
84
  requestId: thisRunningId.toString()
@@ -162,11 +156,10 @@ function usePlaygroundExecution(playgroundSDK, storage, actionSpace, loading, se
162
156
  ]);
163
157
  const handleStop = (0, external_react_namespaceObject.useCallback)(async ()=>{
164
158
  const thisRunningId = currentRunningIdRef.current;
165
- if (thisRunningId && playgroundSDK && playgroundSDK.cancelExecution) try {
159
+ if (thisRunningId && playgroundSDK.cancelExecution) try {
166
160
  await playgroundSDK.cancelExecution(thisRunningId.toString());
167
161
  interruptedFlagRef.current[thisRunningId] = true;
168
162
  setLoading(false);
169
- if (playgroundSDK.onProgressUpdate) playgroundSDK.onProgressUpdate(()=>{});
170
163
  setInfoList((prev)=>prev.map((item)=>item.id === `system-${thisRunningId}` && item.loading ? {
171
164
  ...item,
172
165
  content: 'Operation stopped',
@@ -193,7 +186,7 @@ function usePlaygroundExecution(playgroundSDK, storage, actionSpace, loading, se
193
186
  setLoading,
194
187
  setInfoList
195
188
  ]);
196
- const canStop = loading && !!currentRunningIdRef.current && !!playgroundSDK && !!playgroundSDK.cancelExecution;
189
+ const canStop = loading && !!currentRunningIdRef.current && !!playgroundSDK.cancelExecution;
197
190
  return {
198
191
  handleRun,
199
192
  handleStop,
@@ -29,6 +29,7 @@ __webpack_require__.d(__webpack_exports__, {
29
29
  const external_react_namespaceObject = require("react");
30
30
  const constants_js_namespaceObject = require("../utils/constants.js");
31
31
  function usePlaygroundState(playgroundSDK, storage, contextProvider) {
32
+ let enablePersistence = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : true;
32
33
  const [loading, setLoading] = (0, external_react_namespaceObject.useState)(false);
33
34
  const [infoList, setInfoList] = (0, external_react_namespaceObject.useState)([]);
34
35
  const [actionSpace, setActionSpace] = (0, external_react_namespaceObject.useState)([]);
@@ -47,7 +48,7 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
47
48
  id: 'welcome',
48
49
  timestamp: new Date()
49
50
  };
50
- if (null == storage ? void 0 : storage.loadMessages) try {
51
+ if (enablePersistence && (null == storage ? void 0 : storage.loadMessages)) try {
51
52
  const storedMessages = await storage.loadMessages();
52
53
  const hasWelcomeMessage = storedMessages.some((msg)=>'welcome' === msg.id);
53
54
  hasWelcomeMessage ? setInfoList(storedMessages) : setInfoList([
@@ -67,12 +68,13 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
67
68
  if (0 === infoList.length) initializeMessages();
68
69
  }, []);
69
70
  (0, external_react_namespaceObject.useEffect)(()=>{
70
- if ((null == storage ? void 0 : storage.saveMessages) && infoList.length > 1) storage.saveMessages(infoList).catch((error)=>{
71
+ if (enablePersistence && (null == storage ? void 0 : storage.saveMessages) && infoList.length > 1) storage.saveMessages(infoList).catch((error)=>{
71
72
  console.error('Failed to save messages:', error);
72
73
  });
73
74
  }, [
74
75
  infoList,
75
- storage
76
+ storage,
77
+ enablePersistence
76
78
  ]);
77
79
  (0, external_react_namespaceObject.useEffect)(()=>{
78
80
  if (!(null == contextProvider ? void 0 : contextProvider.getUIContext) || uiContextPreview) return;
@@ -88,7 +90,6 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
88
90
  setActionSpaceLoading(true);
89
91
  try {
90
92
  var _contextProvider_getUIContext;
91
- if (!playgroundSDK) return void setActionSpace([]);
92
93
  const context = uiContextPreview || await (null == contextProvider ? void 0 : null == (_contextProvider_getUIContext = contextProvider.getUIContext) ? void 0 : _contextProvider_getUIContext.call(contextProvider));
93
94
  const space = await playgroundSDK.getActionSpace(context);
94
95
  setActionSpace(space || []);
@@ -162,13 +163,14 @@ function usePlaygroundState(playgroundSDK, storage, contextProvider) {
162
163
  setInfoList([
163
164
  welcomeMessage
164
165
  ]);
165
- if (null == storage ? void 0 : storage.clearMessages) try {
166
+ if (enablePersistence && (null == storage ? void 0 : storage.clearMessages)) try {
166
167
  await storage.clearMessages();
167
168
  } catch (error) {
168
169
  console.error('Failed to clear stored messages:', error);
169
170
  }
170
171
  }, [
171
- storage
172
+ storage,
173
+ enablePersistence
172
174
  ]);
173
175
  const refreshContext = (0, external_react_namespaceObject.useCallback)(async ()=>{
174
176
  if (null == contextProvider ? void 0 : contextProvider.refreshContext) try {
@@ -3,7 +3,7 @@ import type { FormValue, InfoListItem, PlaygroundSDKLike, StorageProvider } from
3
3
  /**
4
4
  * Hook for handling playground execution logic
5
5
  */
6
- export declare function usePlaygroundExecution(playgroundSDK: PlaygroundSDKLike | null, storage: StorageProvider | undefined, actionSpace: DeviceAction<unknown>[], loading: boolean, setLoading: (loading: boolean) => void, infoList: InfoListItem[], setInfoList: React.Dispatch<React.SetStateAction<InfoListItem[]>>, replayCounter: number, setReplayCounter: React.Dispatch<React.SetStateAction<number>>, verticalMode: boolean, currentRunningIdRef: React.MutableRefObject<number | null>, interruptedFlagRef: React.MutableRefObject<Record<number, boolean>>): {
6
+ export declare function usePlaygroundExecution(playgroundSDK: PlaygroundSDKLike, storage: StorageProvider | undefined, actionSpace: DeviceAction<unknown>[], loading: boolean, setLoading: (loading: boolean) => void, infoList: InfoListItem[], setInfoList: React.Dispatch<React.SetStateAction<InfoListItem[]>>, replayCounter: number, setReplayCounter: React.Dispatch<React.SetStateAction<number>>, verticalMode: boolean, currentRunningIdRef: React.MutableRefObject<number | null>, interruptedFlagRef: React.MutableRefObject<Record<number, boolean>>): {
7
7
  handleRun: (value: FormValue) => Promise<void>;
8
8
  handleStop: () => Promise<void>;
9
9
  canStop: boolean;
@@ -3,7 +3,7 @@ import type { ContextProvider, InfoListItem, PlaygroundSDKLike, StorageProvider
3
3
  /**
4
4
  * Hook for managing playground state
5
5
  */
6
- export declare function usePlaygroundState(playgroundSDK: PlaygroundSDKLike | null, storage?: StorageProvider, contextProvider?: ContextProvider): {
6
+ export declare function usePlaygroundState(playgroundSDK: PlaygroundSDKLike, storage?: StorageProvider, contextProvider?: ContextProvider, enablePersistence?: boolean): {
7
7
  loading: boolean;
8
8
  setLoading: import("react").Dispatch<import("react").SetStateAction<boolean>>;
9
9
  infoList: InfoListItem[];
@@ -117,7 +117,6 @@ export interface PlaygroundSDKLike {
117
117
  cancelExecution?(requestId: string): Promise<void>;
118
118
  overrideConfig?(config: any): Promise<void>;
119
119
  checkStatus?(): Promise<boolean>;
120
- id?: string;
121
120
  }
122
121
  export interface StorageProvider {
123
122
  saveMessages?(messages: InfoListItem[]): Promise<void>;
@@ -143,12 +142,11 @@ export interface InfoListItem {
143
142
  }
144
143
  export interface UniversalPlaygroundConfig {
145
144
  showContextPreview?: boolean;
146
- storageNamespace?: string;
145
+ enablePersistence?: boolean;
147
146
  layout?: 'vertical' | 'horizontal';
148
147
  showVersionInfo?: boolean;
149
148
  enableScrollToBottom?: boolean;
150
149
  serverMode?: boolean;
151
- showEnvConfigReminder?: boolean;
152
150
  }
153
151
  export interface PlaygroundBranding {
154
152
  title?: string;
@@ -156,7 +154,7 @@ export interface PlaygroundBranding {
156
154
  version?: string;
157
155
  }
158
156
  export interface UniversalPlaygroundProps {
159
- playgroundSDK: PlaygroundSDKLike | null;
157
+ playgroundSDK: PlaygroundSDKLike;
160
158
  storage?: StorageProvider;
161
159
  contextProvider?: ContextProvider;
162
160
  config?: UniversalPlaygroundConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/visualizer",
3
- "version": "0.28.7-beta-20250912113807.0",
3
+ "version": "0.28.7-beta-20250915040112.0",
4
4
  "repository": "https://github.com/web-infra-dev/midscene",
5
5
  "homepage": "https://midscenejs.com/",
6
6
  "types": "./dist/types/index.d.ts",
@@ -70,10 +70,10 @@
70
70
  "antd": "^5.21.6",
71
71
  "buffer": "6.0.3",
72
72
  "dayjs": "^1.11.11",
73
- "@midscene/core": "0.28.7-beta-20250912113807.0",
74
- "@midscene/shared": "0.28.7-beta-20250912113807.0",
75
- "@midscene/web": "0.28.7-beta-20250912113807.0",
76
- "@midscene/playground": "0.28.7-beta-20250912113807.0"
73
+ "@midscene/core": "0.28.7-beta-20250915040112.0",
74
+ "@midscene/playground": "0.28.7-beta-20250915040112.0",
75
+ "@midscene/web": "0.28.7-beta-20250915040112.0",
76
+ "@midscene/shared": "0.28.7-beta-20250915040112.0"
77
77
  },
78
78
  "license": "MIT",
79
79
  "scripts": {