@midscene/playground-app 1.7.5-beta-20260421030751.0 → 1.7.5
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/es/PreviewRenderer.mjs +1 -0
- package/dist/es/ScrcpyPanel.mjs +64 -7
- package/dist/es/controller/ai-config.mjs +4 -1
- package/dist/es/controller/selectors.mjs +19 -5
- package/dist/es/controller/single-flight.mjs +13 -0
- package/dist/es/controller/usePlaygroundController.mjs +78 -34
- package/dist/es/panels/PlaygroundConversationPanel.mjs +7 -2
- package/dist/es/runtime-info.mjs +3 -1
- package/dist/lib/PreviewRenderer.js +1 -0
- package/dist/lib/ScrcpyPanel.js +64 -7
- package/dist/lib/controller/ai-config.js +8 -2
- package/dist/lib/controller/selectors.js +19 -5
- package/dist/lib/controller/single-flight.js +47 -0
- package/dist/lib/controller/usePlaygroundController.js +76 -32
- package/dist/lib/panels/PlaygroundConversationPanel.js +7 -2
- package/dist/lib/runtime-info.js +3 -1
- package/dist/types/PlaygroundPreview.d.ts +1 -1
- package/dist/types/PreviewRenderer.d.ts +1 -1
- package/dist/types/ScrcpyPanel.d.ts +3 -2
- package/dist/types/controller/ai-config.d.ts +1 -0
- package/dist/types/controller/single-flight.d.ts +3 -0
- package/dist/types/controller/usePlaygroundController.d.ts +8 -1
- package/dist/types/panels/PlaygroundConversationPanel.d.ts +5 -1
- package/dist/types/runtime-info.d.ts +1 -0
- package/package.json +4 -4
|
@@ -119,6 +119,7 @@ function PreviewRenderer({ connectingOverlay, onScrcpyStatusChange, renderErrorO
|
|
|
119
119
|
description: "This session did not expose a preview capability in runtime metadata."
|
|
120
120
|
}) : scrcpyAvailable ? /*#__PURE__*/ jsx(ScrcpyPanel, {
|
|
121
121
|
connectingOverlay: connectingOverlay,
|
|
122
|
+
deviceId: previewConnection.deviceId,
|
|
122
123
|
onStatusChange: onScrcpyStatusChange,
|
|
123
124
|
renderErrorOverlay: renderErrorOverlay,
|
|
124
125
|
serverUrl: previewConnection.scrcpyUrl
|
package/dist/es/ScrcpyPanel.mjs
CHANGED
|
@@ -32,8 +32,50 @@ function _async_to_generator(fn) {
|
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
+
function _define_property(obj, key, value) {
|
|
36
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
37
|
+
value: value,
|
|
38
|
+
enumerable: true,
|
|
39
|
+
configurable: true,
|
|
40
|
+
writable: true
|
|
41
|
+
});
|
|
42
|
+
else obj[key] = value;
|
|
43
|
+
return obj;
|
|
44
|
+
}
|
|
45
|
+
function _object_spread(target) {
|
|
46
|
+
for(var i = 1; i < arguments.length; i++){
|
|
47
|
+
var source = null != arguments[i] ? arguments[i] : {};
|
|
48
|
+
var ownKeys = Object.keys(source);
|
|
49
|
+
if ("function" == typeof Object.getOwnPropertySymbols) ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
50
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
51
|
+
}));
|
|
52
|
+
ownKeys.forEach(function(key) {
|
|
53
|
+
_define_property(target, key, source[key]);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return target;
|
|
57
|
+
}
|
|
58
|
+
function ScrcpyPanel_ownKeys(object, enumerableOnly) {
|
|
59
|
+
var keys = Object.keys(object);
|
|
60
|
+
if (Object.getOwnPropertySymbols) {
|
|
61
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
62
|
+
if (enumerableOnly) symbols = symbols.filter(function(sym) {
|
|
63
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
64
|
+
});
|
|
65
|
+
keys.push.apply(keys, symbols);
|
|
66
|
+
}
|
|
67
|
+
return keys;
|
|
68
|
+
}
|
|
69
|
+
function _object_spread_props(target, source) {
|
|
70
|
+
source = null != source ? source : {};
|
|
71
|
+
if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
72
|
+
else ScrcpyPanel_ownKeys(Object(source)).forEach(function(key) {
|
|
73
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
74
|
+
});
|
|
75
|
+
return target;
|
|
76
|
+
}
|
|
35
77
|
const { Text } = Typography;
|
|
36
|
-
function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, serverUrl, metadataTimeoutMs = SCRCPY_METADATA_TIMEOUT_MS, reconnectInterval = 3000 }) {
|
|
78
|
+
function ScrcpyPanel({ connectingOverlay, deviceId, onStatusChange, renderErrorOverlay, serverUrl, metadataTimeoutMs = SCRCPY_METADATA_TIMEOUT_MS, reconnectInterval = 3000 }) {
|
|
37
79
|
const canvasStageRef = useRef(null);
|
|
38
80
|
const socketRef = useRef(null);
|
|
39
81
|
const decoderRef = useRef(null);
|
|
@@ -58,10 +100,11 @@ function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, se
|
|
|
58
100
|
setRetryNonce((current)=>current + 1);
|
|
59
101
|
}, []);
|
|
60
102
|
useEffect(()=>{
|
|
61
|
-
null == onStatusChange || onStatusChange(status);
|
|
103
|
+
null == onStatusChange || onStatusChange(status, statusText);
|
|
62
104
|
}, [
|
|
63
105
|
onStatusChange,
|
|
64
|
-
status
|
|
106
|
+
status,
|
|
107
|
+
statusText
|
|
65
108
|
]);
|
|
66
109
|
const clearCanvas = ()=>{
|
|
67
110
|
const stage = canvasStageRef.current;
|
|
@@ -92,7 +135,12 @@ function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, se
|
|
|
92
135
|
return;
|
|
93
136
|
}
|
|
94
137
|
let disposed = false;
|
|
138
|
+
let connectTimer = null;
|
|
95
139
|
const cleanup = ()=>{
|
|
140
|
+
if (connectTimer) {
|
|
141
|
+
clearTimeout(connectTimer);
|
|
142
|
+
connectTimer = null;
|
|
143
|
+
}
|
|
96
144
|
clearMetadataTimeout();
|
|
97
145
|
if (reconnectTimerRef.current) {
|
|
98
146
|
clearTimeout(reconnectTimerRef.current);
|
|
@@ -137,7 +185,10 @@ function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, se
|
|
|
137
185
|
const socket = io(serverUrl, {
|
|
138
186
|
withCredentials: true,
|
|
139
187
|
reconnection: false,
|
|
140
|
-
timeout: 10000
|
|
188
|
+
timeout: 10000,
|
|
189
|
+
transports: [
|
|
190
|
+
'websocket'
|
|
191
|
+
]
|
|
141
192
|
});
|
|
142
193
|
socketRef.current = socket;
|
|
143
194
|
const videoStream = createScrcpyVideoStream(socket);
|
|
@@ -155,9 +206,11 @@ function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, se
|
|
|
155
206
|
socketRef.current = null;
|
|
156
207
|
scheduleReconnect();
|
|
157
208
|
}, metadataTimeoutMs);
|
|
158
|
-
socket.emit('connect-device', {
|
|
209
|
+
socket.emit('connect-device', _object_spread_props(_object_spread({}, 'string' == typeof deviceId && deviceId.trim() ? {
|
|
210
|
+
deviceId: deviceId.trim()
|
|
211
|
+
} : {}), {
|
|
159
212
|
maxSize: 1024
|
|
160
|
-
});
|
|
213
|
+
}));
|
|
161
214
|
});
|
|
162
215
|
socket.on('preview-status', (event)=>{
|
|
163
216
|
if (disposed || !isScrcpyPreviewStatusEvent(event)) return;
|
|
@@ -217,12 +270,16 @@ function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, se
|
|
|
217
270
|
scheduleReconnect();
|
|
218
271
|
});
|
|
219
272
|
};
|
|
220
|
-
|
|
273
|
+
connectTimer = setTimeout(()=>{
|
|
274
|
+
connectTimer = null;
|
|
275
|
+
connect();
|
|
276
|
+
}, 0);
|
|
221
277
|
return ()=>{
|
|
222
278
|
disposed = true;
|
|
223
279
|
cleanup();
|
|
224
280
|
};
|
|
225
281
|
}, [
|
|
282
|
+
deviceId,
|
|
226
283
|
metadataTimeoutMs,
|
|
227
284
|
reconnectInterval,
|
|
228
285
|
retryNonce,
|
|
@@ -27,6 +27,9 @@ function _async_to_generator(fn) {
|
|
|
27
27
|
function hasPlaygroundAiConfig(config) {
|
|
28
28
|
return Object.keys(config).length > 0;
|
|
29
29
|
}
|
|
30
|
+
function serializePlaygroundAiConfig(config) {
|
|
31
|
+
return JSON.stringify(Object.entries(config).sort(([leftKey], [rightKey])=>leftKey.localeCompare(rightKey)));
|
|
32
|
+
}
|
|
30
33
|
function applyPlaygroundAiConfig(playgroundSDK, config) {
|
|
31
34
|
return _async_to_generator(function*() {
|
|
32
35
|
if (!hasPlaygroundAiConfig(config)) return false;
|
|
@@ -34,4 +37,4 @@ function applyPlaygroundAiConfig(playgroundSDK, config) {
|
|
|
34
37
|
return true;
|
|
35
38
|
})();
|
|
36
39
|
}
|
|
37
|
-
export { applyPlaygroundAiConfig, hasPlaygroundAiConfig };
|
|
40
|
+
export { applyPlaygroundAiConfig, hasPlaygroundAiConfig, serializePlaygroundAiConfig };
|
|
@@ -41,19 +41,33 @@ function _object_spread_props(target, source) {
|
|
|
41
41
|
return target;
|
|
42
42
|
}
|
|
43
43
|
function buildConversationConfig(state, playgroundConfig) {
|
|
44
|
-
|
|
44
|
+
const defaultConfig = {
|
|
45
45
|
showContextPreview: false,
|
|
46
46
|
layout: 'vertical',
|
|
47
|
-
showVersionInfo:
|
|
48
|
-
enableScrollToBottom:
|
|
47
|
+
showVersionInfo: false,
|
|
48
|
+
enableScrollToBottom: false,
|
|
49
49
|
serverMode: true,
|
|
50
|
-
showEnvConfigReminder:
|
|
50
|
+
showEnvConfigReminder: false,
|
|
51
|
+
showClearButton: false,
|
|
52
|
+
showSystemMessageHeader: false,
|
|
53
|
+
promptInputChrome: {
|
|
54
|
+
variant: 'minimal',
|
|
55
|
+
placeholder: 'Type a message',
|
|
56
|
+
primaryActionLabel: 'Action'
|
|
57
|
+
},
|
|
58
|
+
executionFlow: {
|
|
59
|
+
collapsible: true
|
|
60
|
+
},
|
|
51
61
|
deviceType: state.deviceType,
|
|
52
62
|
executionUx: {
|
|
53
63
|
hints: state.executionUxHints,
|
|
54
64
|
countdownSeconds: state.countdownSeconds
|
|
55
65
|
}
|
|
56
|
-
}
|
|
66
|
+
};
|
|
67
|
+
return _object_spread_props(_object_spread({}, defaultConfig, playgroundConfig), {
|
|
68
|
+
executionFlow: _object_spread({}, defaultConfig.executionFlow, null == playgroundConfig ? void 0 : playgroundConfig.executionFlow),
|
|
69
|
+
executionUx: _object_spread({}, defaultConfig.executionUx, null == playgroundConfig ? void 0 : playgroundConfig.executionUx)
|
|
70
|
+
});
|
|
57
71
|
}
|
|
58
72
|
function buildConversationBranding(runtimeInfo, title, appVersion, deviceType, branding) {
|
|
59
73
|
var _runtimeInfo_title, _runtimeInfo_platformId, _ref, _ref1;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function runSingleFlight(pendingRef, task) {
|
|
2
|
+
if (pendingRef.current) return pendingRef.current;
|
|
3
|
+
const taskPromise = task();
|
|
4
|
+
const pendingState = {
|
|
5
|
+
promise: null
|
|
6
|
+
};
|
|
7
|
+
pendingState.promise = taskPromise.finally(()=>{
|
|
8
|
+
if (pendingRef.current === pendingState.promise) pendingRef.current = null;
|
|
9
|
+
});
|
|
10
|
+
pendingRef.current = pendingState.promise;
|
|
11
|
+
return pendingState.promise;
|
|
12
|
+
}
|
|
13
|
+
export { runSingleFlight };
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { PlaygroundSDK } from "@midscene/playground";
|
|
2
2
|
import { useEnvConfig } from "@midscene/visualizer";
|
|
3
3
|
import { Form, message } from "antd";
|
|
4
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { resolveAutoCreateSessionInput } from "../session-setup.mjs";
|
|
6
6
|
import { buildSessionInitialValues, resolveSessionViewState } from "../session-state.mjs";
|
|
7
7
|
import { useServerStatus } from "../useServerStatus.mjs";
|
|
8
|
-
import { applyPlaygroundAiConfig, hasPlaygroundAiConfig } from "./ai-config.mjs";
|
|
8
|
+
import { applyPlaygroundAiConfig, hasPlaygroundAiConfig, serializePlaygroundAiConfig } from "./ai-config.mjs";
|
|
9
9
|
import { resolveAutoCreateDecision, serializeAutoCreateInput, shouldResetAutoCreateBlock } from "./auto-create.mjs";
|
|
10
|
+
import { runSingleFlight } from "./single-flight.mjs";
|
|
10
11
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
11
12
|
try {
|
|
12
13
|
var info = gen[key](arg);
|
|
@@ -79,8 +80,18 @@ function getPlatformSelectorFieldKey(setup) {
|
|
|
79
80
|
var _setup_platformSelector;
|
|
80
81
|
return null == setup ? void 0 : null == (_setup_platformSelector = setup.platformSelector) ? void 0 : _setup_platformSelector.fieldKey;
|
|
81
82
|
}
|
|
82
|
-
function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollIntervalMs = 5000, countdownSeconds = 3 }) {
|
|
83
|
+
function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollIntervalMs = 5000, countdownSeconds = 3, initialFormValues }) {
|
|
83
84
|
const [form] = Form.useForm();
|
|
85
|
+
const initialFormValuesRef = useRef(initialFormValues);
|
|
86
|
+
useLayoutEffect(()=>{
|
|
87
|
+
const seed = initialFormValuesRef.current;
|
|
88
|
+
if (!seed) return;
|
|
89
|
+
for (const [key, value] of Object.entries(seed))if (void 0 === form.getFieldValue(key)) form.setFieldsValue({
|
|
90
|
+
[key]: value
|
|
91
|
+
});
|
|
92
|
+
}, [
|
|
93
|
+
form
|
|
94
|
+
]);
|
|
84
95
|
var _Form_useWatch;
|
|
85
96
|
const formValues = null != (_Form_useWatch = Form.useWatch([], form)) ? _Form_useWatch : {};
|
|
86
97
|
const [countdown, setCountdown] = useState(null);
|
|
@@ -89,6 +100,9 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
89
100
|
const [sessionLoading, setSessionLoading] = useState(false);
|
|
90
101
|
const [sessionMutating, setSessionMutating] = useState(false);
|
|
91
102
|
const aiConfig = useEnvConfig((state)=>state.config);
|
|
103
|
+
const aiConfigSignature = useMemo(()=>serializePlaygroundAiConfig(aiConfig), [
|
|
104
|
+
aiConfig
|
|
105
|
+
]);
|
|
92
106
|
const platformSelectorFieldKey = getPlatformSelectorFieldKey(sessionSetup);
|
|
93
107
|
const selectedPlatformId = 'string' == typeof platformSelectorFieldKey ? formValues[platformSelectorFieldKey] : void 0;
|
|
94
108
|
const playgroundSDK = useMemo(()=>new PlaygroundSDK({
|
|
@@ -101,26 +115,50 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
101
115
|
const sessionViewState = useMemo(()=>resolveSessionViewState(runtimeInfo), [
|
|
102
116
|
runtimeInfo
|
|
103
117
|
]);
|
|
118
|
+
const countdownTimerRef = useRef(null);
|
|
119
|
+
const countdownResolveRef = useRef(null);
|
|
120
|
+
const mountedRef = useRef(true);
|
|
121
|
+
const lastSetupPlatformIdRef = useRef(void 0);
|
|
122
|
+
const autoCreateSignatureRef = useRef(null);
|
|
123
|
+
const autoCreateBlockedSignatureRef = useRef(null);
|
|
124
|
+
const sessionMutatingRef = useRef(false);
|
|
125
|
+
const appliedAiConfigSignatureRef = useRef(null);
|
|
126
|
+
const pendingCreateSessionRef = useRef(null);
|
|
127
|
+
const pendingAiConfigApplicationRef = useRef(null);
|
|
104
128
|
const applyAiConfig = useCallback(()=>_async_to_generator(function*() {
|
|
105
|
-
if (!hasPlaygroundAiConfig(aiConfig))
|
|
106
|
-
|
|
107
|
-
|
|
129
|
+
if (!hasPlaygroundAiConfig(aiConfig)) {
|
|
130
|
+
appliedAiConfigSignatureRef.current = null;
|
|
131
|
+
pendingAiConfigApplicationRef.current = null;
|
|
108
132
|
return true;
|
|
109
|
-
} catch (error) {
|
|
110
|
-
const errorMessage = error instanceof Error ? error.message : 'Failed to apply AI configuration';
|
|
111
|
-
message.error(errorMessage);
|
|
112
|
-
return false;
|
|
113
133
|
}
|
|
134
|
+
if (appliedAiConfigSignatureRef.current === aiConfigSignature) return true;
|
|
135
|
+
const pendingApplication = pendingAiConfigApplicationRef.current;
|
|
136
|
+
if ((null == pendingApplication ? void 0 : pendingApplication.signature) === aiConfigSignature) return pendingApplication.promise;
|
|
137
|
+
const pendingApplicationState = {
|
|
138
|
+
promise: Promise.resolve(true),
|
|
139
|
+
signature: aiConfigSignature
|
|
140
|
+
};
|
|
141
|
+
const applyPromise = (()=>_async_to_generator(function*() {
|
|
142
|
+
try {
|
|
143
|
+
yield applyPlaygroundAiConfig(playgroundSDK, aiConfig);
|
|
144
|
+
appliedAiConfigSignatureRef.current = aiConfigSignature;
|
|
145
|
+
return true;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to apply AI configuration';
|
|
148
|
+
message.error(errorMessage);
|
|
149
|
+
return false;
|
|
150
|
+
} finally{
|
|
151
|
+
if (pendingAiConfigApplicationRef.current === pendingApplicationState) pendingAiConfigApplicationRef.current = null;
|
|
152
|
+
}
|
|
153
|
+
})())();
|
|
154
|
+
pendingApplicationState.promise = applyPromise;
|
|
155
|
+
pendingAiConfigApplicationRef.current = pendingApplicationState;
|
|
156
|
+
return applyPromise;
|
|
114
157
|
})(), [
|
|
115
158
|
aiConfig,
|
|
159
|
+
aiConfigSignature,
|
|
116
160
|
playgroundSDK
|
|
117
161
|
]);
|
|
118
|
-
const countdownTimerRef = useRef(null);
|
|
119
|
-
const countdownResolveRef = useRef(null);
|
|
120
|
-
const mountedRef = useRef(true);
|
|
121
|
-
const lastSetupPlatformIdRef = useRef(void 0);
|
|
122
|
-
const autoCreateSignatureRef = useRef(null);
|
|
123
|
-
const autoCreateBlockedSignatureRef = useRef(null);
|
|
124
162
|
const finishCountdown = useCallback(()=>{
|
|
125
163
|
if (null !== countdownTimerRef.current) {
|
|
126
164
|
window.clearInterval(countdownTimerRef.current);
|
|
@@ -198,23 +236,27 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
198
236
|
playgroundSDK
|
|
199
237
|
]);
|
|
200
238
|
const createSession = useCallback((input, options)=>_async_to_generator(function*() {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
239
|
+
return runSingleFlight(pendingCreateSessionRef, ()=>_async_to_generator(function*() {
|
|
240
|
+
try {
|
|
241
|
+
sessionMutatingRef.current = true;
|
|
242
|
+
setSessionMutating(true);
|
|
243
|
+
if (!(yield applyAiConfig())) return false;
|
|
244
|
+
const values = null != input ? input : yield form.validateFields();
|
|
245
|
+
yield playgroundSDK.createSession(values);
|
|
246
|
+
if (shouldResetAutoCreateBlock(options)) autoCreateBlockedSignatureRef.current = null;
|
|
247
|
+
if (!(null == options ? void 0 : options.silent)) message.success('Agent created');
|
|
248
|
+
yield refreshServerState();
|
|
249
|
+
return true;
|
|
250
|
+
} catch (error) {
|
|
251
|
+
if (error.errorFields) return false;
|
|
252
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to create Agent';
|
|
253
|
+
message.error(errorMessage);
|
|
254
|
+
return false;
|
|
255
|
+
} finally{
|
|
256
|
+
sessionMutatingRef.current = false;
|
|
257
|
+
setSessionMutating(false);
|
|
258
|
+
}
|
|
259
|
+
})());
|
|
218
260
|
})(), [
|
|
219
261
|
applyAiConfig,
|
|
220
262
|
form,
|
|
@@ -224,6 +266,7 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
224
266
|
const destroySession = useCallback(()=>_async_to_generator(function*() {
|
|
225
267
|
try {
|
|
226
268
|
autoCreateBlockedSignatureRef.current = serializeAutoCreateInput(resolveAutoCreateSessionInput(sessionSetup, form.getFieldsValue(true)));
|
|
269
|
+
sessionMutatingRef.current = true;
|
|
227
270
|
setSessionMutating(true);
|
|
228
271
|
yield playgroundSDK.destroySession();
|
|
229
272
|
message.success('Session disconnected');
|
|
@@ -233,6 +276,7 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
233
276
|
const errorMessage = error instanceof Error ? error.message : 'Failed to disconnect session';
|
|
234
277
|
message.error(errorMessage);
|
|
235
278
|
} finally{
|
|
279
|
+
sessionMutatingRef.current = false;
|
|
236
280
|
setSessionMutating(false);
|
|
237
281
|
}
|
|
238
282
|
})(), [
|
|
@@ -298,7 +342,7 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
298
342
|
autoCreateSignatureRef.current = null;
|
|
299
343
|
return;
|
|
300
344
|
}
|
|
301
|
-
if (!serverOnline || sessionLoading || sessionMutating || sessionSetupError) return;
|
|
345
|
+
if (!serverOnline || sessionLoading || sessionMutating || sessionMutatingRef.current || sessionSetupError) return;
|
|
302
346
|
const autoCreateInput = resolveAutoCreateSessionInput(sessionSetup, form.getFieldsValue(true));
|
|
303
347
|
const { signature, shouldCreate } = resolveAutoCreateDecision({
|
|
304
348
|
autoCreateInput,
|
|
@@ -30,7 +30,8 @@ function _async_to_generator(fn) {
|
|
|
30
30
|
});
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
const PLAYGROUND_CONVERSATION_SKIN_CLASS = 'playground-conversation-skin';
|
|
34
|
+
function PlaygroundConversationPanel({ controller, appVersion, title = 'Playground', branding, playgroundConfig, header, className, playgroundClassName, notConnectedFallback }) {
|
|
34
35
|
const { state, actions } = controller;
|
|
35
36
|
const mergedConfig = buildConversationConfig(state, playgroundConfig);
|
|
36
37
|
const mergedBranding = buildConversationBranding(state.runtimeInfo, title, appVersion, state.deviceType, branding);
|
|
@@ -105,7 +106,11 @@ function PlaygroundConversationPanel({ controller, appVersion, title = 'Playgrou
|
|
|
105
106
|
playgroundSDK: state.playgroundSDK,
|
|
106
107
|
config: mergedConfig,
|
|
107
108
|
branding: mergedBranding,
|
|
108
|
-
className:
|
|
109
|
+
className: [
|
|
110
|
+
'playground-container',
|
|
111
|
+
PLAYGROUND_CONVERSATION_SKIN_CLASS,
|
|
112
|
+
playgroundClassName
|
|
113
|
+
].filter(Boolean).join(' ')
|
|
109
114
|
}) : void 0 !== notConnectedFallback ? /*#__PURE__*/ jsx(Fragment, {
|
|
110
115
|
children: notConnectedFallback
|
|
111
116
|
}) : /*#__PURE__*/ jsx(SessionSetupPanel, {
|
package/dist/es/runtime-info.mjs
CHANGED
|
@@ -100,7 +100,8 @@ function resolvePreviewConnectionInfo(runtimeInfo, serverUrl) {
|
|
|
100
100
|
}
|
|
101
101
|
if ('scrcpy' === preview.kind) {
|
|
102
102
|
var _runtimeInfo_metadata, _preview_custom;
|
|
103
|
-
|
|
103
|
+
const runtimeDeviceId = 'string' == typeof (null == runtimeInfo ? void 0 : null == (_runtimeInfo_metadata = runtimeInfo.metadata) ? void 0 : _runtimeInfo_metadata.deviceId) ? runtimeInfo.metadata.deviceId.trim() : void 0;
|
|
104
|
+
if (isRemoteAndroidDeviceId(runtimeDeviceId)) return {
|
|
104
105
|
type: 'screenshot'
|
|
105
106
|
};
|
|
106
107
|
const scrcpyPort = Number(null == (_preview_custom = preview.custom) ? void 0 : _preview_custom.scrcpyPort);
|
|
@@ -114,6 +115,7 @@ function resolvePreviewConnectionInfo(runtimeInfo, serverUrl) {
|
|
|
114
115
|
return url.toString();
|
|
115
116
|
})() : void 0;
|
|
116
117
|
return {
|
|
118
|
+
deviceId: runtimeDeviceId,
|
|
117
119
|
type: 'scrcpy',
|
|
118
120
|
scrcpyPort: resolvedScrcpyPort,
|
|
119
121
|
scrcpyUrl
|
|
@@ -147,6 +147,7 @@ function PreviewRenderer({ connectingOverlay, onScrcpyStatusChange, renderErrorO
|
|
|
147
147
|
description: "This session did not expose a preview capability in runtime metadata."
|
|
148
148
|
}) : scrcpyAvailable ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_ScrcpyPanel_js_namespaceObject.ScrcpyPanel, {
|
|
149
149
|
connectingOverlay: connectingOverlay,
|
|
150
|
+
deviceId: previewConnection.deviceId,
|
|
150
151
|
onStatusChange: onScrcpyStatusChange,
|
|
151
152
|
renderErrorOverlay: renderErrorOverlay,
|
|
152
153
|
serverUrl: previewConnection.scrcpyUrl
|
package/dist/lib/ScrcpyPanel.js
CHANGED
|
@@ -60,8 +60,50 @@ function _async_to_generator(fn) {
|
|
|
60
60
|
});
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
+
function _define_property(obj, key, value) {
|
|
64
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
65
|
+
value: value,
|
|
66
|
+
enumerable: true,
|
|
67
|
+
configurable: true,
|
|
68
|
+
writable: true
|
|
69
|
+
});
|
|
70
|
+
else obj[key] = value;
|
|
71
|
+
return obj;
|
|
72
|
+
}
|
|
73
|
+
function _object_spread(target) {
|
|
74
|
+
for(var i = 1; i < arguments.length; i++){
|
|
75
|
+
var source = null != arguments[i] ? arguments[i] : {};
|
|
76
|
+
var ownKeys = Object.keys(source);
|
|
77
|
+
if ("function" == typeof Object.getOwnPropertySymbols) ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
78
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
79
|
+
}));
|
|
80
|
+
ownKeys.forEach(function(key) {
|
|
81
|
+
_define_property(target, key, source[key]);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return target;
|
|
85
|
+
}
|
|
86
|
+
function ScrcpyPanel_ownKeys(object, enumerableOnly) {
|
|
87
|
+
var keys = Object.keys(object);
|
|
88
|
+
if (Object.getOwnPropertySymbols) {
|
|
89
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
90
|
+
if (enumerableOnly) symbols = symbols.filter(function(sym) {
|
|
91
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
92
|
+
});
|
|
93
|
+
keys.push.apply(keys, symbols);
|
|
94
|
+
}
|
|
95
|
+
return keys;
|
|
96
|
+
}
|
|
97
|
+
function _object_spread_props(target, source) {
|
|
98
|
+
source = null != source ? source : {};
|
|
99
|
+
if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
100
|
+
else ScrcpyPanel_ownKeys(Object(source)).forEach(function(key) {
|
|
101
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
102
|
+
});
|
|
103
|
+
return target;
|
|
104
|
+
}
|
|
63
105
|
const { Text } = external_antd_namespaceObject.Typography;
|
|
64
|
-
function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, serverUrl, metadataTimeoutMs = external_scrcpy_preview_js_namespaceObject.SCRCPY_METADATA_TIMEOUT_MS, reconnectInterval = 3000 }) {
|
|
106
|
+
function ScrcpyPanel({ connectingOverlay, deviceId, onStatusChange, renderErrorOverlay, serverUrl, metadataTimeoutMs = external_scrcpy_preview_js_namespaceObject.SCRCPY_METADATA_TIMEOUT_MS, reconnectInterval = 3000 }) {
|
|
65
107
|
const canvasStageRef = (0, external_react_namespaceObject.useRef)(null);
|
|
66
108
|
const socketRef = (0, external_react_namespaceObject.useRef)(null);
|
|
67
109
|
const decoderRef = (0, external_react_namespaceObject.useRef)(null);
|
|
@@ -86,10 +128,11 @@ function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, se
|
|
|
86
128
|
setRetryNonce((current)=>current + 1);
|
|
87
129
|
}, []);
|
|
88
130
|
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
89
|
-
null == onStatusChange || onStatusChange(status);
|
|
131
|
+
null == onStatusChange || onStatusChange(status, statusText);
|
|
90
132
|
}, [
|
|
91
133
|
onStatusChange,
|
|
92
|
-
status
|
|
134
|
+
status,
|
|
135
|
+
statusText
|
|
93
136
|
]);
|
|
94
137
|
const clearCanvas = ()=>{
|
|
95
138
|
const stage = canvasStageRef.current;
|
|
@@ -120,7 +163,12 @@ function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, se
|
|
|
120
163
|
return;
|
|
121
164
|
}
|
|
122
165
|
let disposed = false;
|
|
166
|
+
let connectTimer = null;
|
|
123
167
|
const cleanup = ()=>{
|
|
168
|
+
if (connectTimer) {
|
|
169
|
+
clearTimeout(connectTimer);
|
|
170
|
+
connectTimer = null;
|
|
171
|
+
}
|
|
124
172
|
clearMetadataTimeout();
|
|
125
173
|
if (reconnectTimerRef.current) {
|
|
126
174
|
clearTimeout(reconnectTimerRef.current);
|
|
@@ -165,7 +213,10 @@ function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, se
|
|
|
165
213
|
const socket = (0, external_socket_io_client_namespaceObject.io)(serverUrl, {
|
|
166
214
|
withCredentials: true,
|
|
167
215
|
reconnection: false,
|
|
168
|
-
timeout: 10000
|
|
216
|
+
timeout: 10000,
|
|
217
|
+
transports: [
|
|
218
|
+
'websocket'
|
|
219
|
+
]
|
|
169
220
|
});
|
|
170
221
|
socketRef.current = socket;
|
|
171
222
|
const videoStream = (0, external_scrcpy_stream_js_namespaceObject.createScrcpyVideoStream)(socket);
|
|
@@ -183,9 +234,11 @@ function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, se
|
|
|
183
234
|
socketRef.current = null;
|
|
184
235
|
scheduleReconnect();
|
|
185
236
|
}, metadataTimeoutMs);
|
|
186
|
-
socket.emit('connect-device', {
|
|
237
|
+
socket.emit('connect-device', _object_spread_props(_object_spread({}, 'string' == typeof deviceId && deviceId.trim() ? {
|
|
238
|
+
deviceId: deviceId.trim()
|
|
239
|
+
} : {}), {
|
|
187
240
|
maxSize: 1024
|
|
188
|
-
});
|
|
241
|
+
}));
|
|
189
242
|
});
|
|
190
243
|
socket.on('preview-status', (event)=>{
|
|
191
244
|
if (disposed || !(0, external_scrcpy_preview_js_namespaceObject.isScrcpyPreviewStatusEvent)(event)) return;
|
|
@@ -245,12 +298,16 @@ function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, se
|
|
|
245
298
|
scheduleReconnect();
|
|
246
299
|
});
|
|
247
300
|
};
|
|
248
|
-
|
|
301
|
+
connectTimer = setTimeout(()=>{
|
|
302
|
+
connectTimer = null;
|
|
303
|
+
connect();
|
|
304
|
+
}, 0);
|
|
249
305
|
return ()=>{
|
|
250
306
|
disposed = true;
|
|
251
307
|
cleanup();
|
|
252
308
|
};
|
|
253
309
|
}, [
|
|
310
|
+
deviceId,
|
|
254
311
|
metadataTimeoutMs,
|
|
255
312
|
reconnectInterval,
|
|
256
313
|
retryNonce,
|
|
@@ -25,7 +25,8 @@ var __webpack_exports__ = {};
|
|
|
25
25
|
__webpack_require__.r(__webpack_exports__);
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
27
|
applyPlaygroundAiConfig: ()=>applyPlaygroundAiConfig,
|
|
28
|
-
hasPlaygroundAiConfig: ()=>hasPlaygroundAiConfig
|
|
28
|
+
hasPlaygroundAiConfig: ()=>hasPlaygroundAiConfig,
|
|
29
|
+
serializePlaygroundAiConfig: ()=>serializePlaygroundAiConfig
|
|
29
30
|
});
|
|
30
31
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
31
32
|
try {
|
|
@@ -56,6 +57,9 @@ function _async_to_generator(fn) {
|
|
|
56
57
|
function hasPlaygroundAiConfig(config) {
|
|
57
58
|
return Object.keys(config).length > 0;
|
|
58
59
|
}
|
|
60
|
+
function serializePlaygroundAiConfig(config) {
|
|
61
|
+
return JSON.stringify(Object.entries(config).sort(([leftKey], [rightKey])=>leftKey.localeCompare(rightKey)));
|
|
62
|
+
}
|
|
59
63
|
function applyPlaygroundAiConfig(playgroundSDK, config) {
|
|
60
64
|
return _async_to_generator(function*() {
|
|
61
65
|
if (!hasPlaygroundAiConfig(config)) return false;
|
|
@@ -65,9 +69,11 @@ function applyPlaygroundAiConfig(playgroundSDK, config) {
|
|
|
65
69
|
}
|
|
66
70
|
exports.applyPlaygroundAiConfig = __webpack_exports__.applyPlaygroundAiConfig;
|
|
67
71
|
exports.hasPlaygroundAiConfig = __webpack_exports__.hasPlaygroundAiConfig;
|
|
72
|
+
exports.serializePlaygroundAiConfig = __webpack_exports__.serializePlaygroundAiConfig;
|
|
68
73
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
69
74
|
"applyPlaygroundAiConfig",
|
|
70
|
-
"hasPlaygroundAiConfig"
|
|
75
|
+
"hasPlaygroundAiConfig",
|
|
76
|
+
"serializePlaygroundAiConfig"
|
|
71
77
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
72
78
|
Object.defineProperty(exports, '__esModule', {
|
|
73
79
|
value: true
|
|
@@ -70,19 +70,33 @@ function _object_spread_props(target, source) {
|
|
|
70
70
|
return target;
|
|
71
71
|
}
|
|
72
72
|
function buildConversationConfig(state, playgroundConfig) {
|
|
73
|
-
|
|
73
|
+
const defaultConfig = {
|
|
74
74
|
showContextPreview: false,
|
|
75
75
|
layout: 'vertical',
|
|
76
|
-
showVersionInfo:
|
|
77
|
-
enableScrollToBottom:
|
|
76
|
+
showVersionInfo: false,
|
|
77
|
+
enableScrollToBottom: false,
|
|
78
78
|
serverMode: true,
|
|
79
|
-
showEnvConfigReminder:
|
|
79
|
+
showEnvConfigReminder: false,
|
|
80
|
+
showClearButton: false,
|
|
81
|
+
showSystemMessageHeader: false,
|
|
82
|
+
promptInputChrome: {
|
|
83
|
+
variant: 'minimal',
|
|
84
|
+
placeholder: 'Type a message',
|
|
85
|
+
primaryActionLabel: 'Action'
|
|
86
|
+
},
|
|
87
|
+
executionFlow: {
|
|
88
|
+
collapsible: true
|
|
89
|
+
},
|
|
80
90
|
deviceType: state.deviceType,
|
|
81
91
|
executionUx: {
|
|
82
92
|
hints: state.executionUxHints,
|
|
83
93
|
countdownSeconds: state.countdownSeconds
|
|
84
94
|
}
|
|
85
|
-
}
|
|
95
|
+
};
|
|
96
|
+
return _object_spread_props(_object_spread({}, defaultConfig, playgroundConfig), {
|
|
97
|
+
executionFlow: _object_spread({}, defaultConfig.executionFlow, null == playgroundConfig ? void 0 : playgroundConfig.executionFlow),
|
|
98
|
+
executionUx: _object_spread({}, defaultConfig.executionUx, null == playgroundConfig ? void 0 : playgroundConfig.executionUx)
|
|
99
|
+
});
|
|
86
100
|
}
|
|
87
101
|
function buildConversationBranding(runtimeInfo, title, appVersion, deviceType, branding) {
|
|
88
102
|
var _runtimeInfo_title, _runtimeInfo_platformId, _ref, _ref1;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
runSingleFlight: ()=>runSingleFlight
|
|
28
|
+
});
|
|
29
|
+
function runSingleFlight(pendingRef, task) {
|
|
30
|
+
if (pendingRef.current) return pendingRef.current;
|
|
31
|
+
const taskPromise = task();
|
|
32
|
+
const pendingState = {
|
|
33
|
+
promise: null
|
|
34
|
+
};
|
|
35
|
+
pendingState.promise = taskPromise.finally(()=>{
|
|
36
|
+
if (pendingRef.current === pendingState.promise) pendingRef.current = null;
|
|
37
|
+
});
|
|
38
|
+
pendingRef.current = pendingState.promise;
|
|
39
|
+
return pendingState.promise;
|
|
40
|
+
}
|
|
41
|
+
exports.runSingleFlight = __webpack_exports__.runSingleFlight;
|
|
42
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
43
|
+
"runSingleFlight"
|
|
44
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
45
|
+
Object.defineProperty(exports, '__esModule', {
|
|
46
|
+
value: true
|
|
47
|
+
});
|
|
@@ -35,6 +35,7 @@ const external_session_state_js_namespaceObject = require("../session-state.js")
|
|
|
35
35
|
const external_useServerStatus_js_namespaceObject = require("../useServerStatus.js");
|
|
36
36
|
const external_ai_config_js_namespaceObject = require("./ai-config.js");
|
|
37
37
|
const external_auto_create_js_namespaceObject = require("./auto-create.js");
|
|
38
|
+
const external_single_flight_js_namespaceObject = require("./single-flight.js");
|
|
38
39
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
39
40
|
try {
|
|
40
41
|
var info = gen[key](arg);
|
|
@@ -107,8 +108,18 @@ function getPlatformSelectorFieldKey(setup) {
|
|
|
107
108
|
var _setup_platformSelector;
|
|
108
109
|
return null == setup ? void 0 : null == (_setup_platformSelector = setup.platformSelector) ? void 0 : _setup_platformSelector.fieldKey;
|
|
109
110
|
}
|
|
110
|
-
function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollIntervalMs = 5000, countdownSeconds = 3 }) {
|
|
111
|
+
function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollIntervalMs = 5000, countdownSeconds = 3, initialFormValues }) {
|
|
111
112
|
const [form] = external_antd_namespaceObject.Form.useForm();
|
|
113
|
+
const initialFormValuesRef = (0, external_react_namespaceObject.useRef)(initialFormValues);
|
|
114
|
+
(0, external_react_namespaceObject.useLayoutEffect)(()=>{
|
|
115
|
+
const seed = initialFormValuesRef.current;
|
|
116
|
+
if (!seed) return;
|
|
117
|
+
for (const [key, value] of Object.entries(seed))if (void 0 === form.getFieldValue(key)) form.setFieldsValue({
|
|
118
|
+
[key]: value
|
|
119
|
+
});
|
|
120
|
+
}, [
|
|
121
|
+
form
|
|
122
|
+
]);
|
|
112
123
|
var _Form_useWatch;
|
|
113
124
|
const formValues = null != (_Form_useWatch = external_antd_namespaceObject.Form.useWatch([], form)) ? _Form_useWatch : {};
|
|
114
125
|
const [countdown, setCountdown] = (0, external_react_namespaceObject.useState)(null);
|
|
@@ -117,6 +128,9 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
117
128
|
const [sessionLoading, setSessionLoading] = (0, external_react_namespaceObject.useState)(false);
|
|
118
129
|
const [sessionMutating, setSessionMutating] = (0, external_react_namespaceObject.useState)(false);
|
|
119
130
|
const aiConfig = (0, visualizer_namespaceObject.useEnvConfig)((state)=>state.config);
|
|
131
|
+
const aiConfigSignature = (0, external_react_namespaceObject.useMemo)(()=>(0, external_ai_config_js_namespaceObject.serializePlaygroundAiConfig)(aiConfig), [
|
|
132
|
+
aiConfig
|
|
133
|
+
]);
|
|
120
134
|
const platformSelectorFieldKey = getPlatformSelectorFieldKey(sessionSetup);
|
|
121
135
|
const selectedPlatformId = 'string' == typeof platformSelectorFieldKey ? formValues[platformSelectorFieldKey] : void 0;
|
|
122
136
|
const playgroundSDK = (0, external_react_namespaceObject.useMemo)(()=>new playground_namespaceObject.PlaygroundSDK({
|
|
@@ -129,26 +143,50 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
129
143
|
const sessionViewState = (0, external_react_namespaceObject.useMemo)(()=>(0, external_session_state_js_namespaceObject.resolveSessionViewState)(runtimeInfo), [
|
|
130
144
|
runtimeInfo
|
|
131
145
|
]);
|
|
146
|
+
const countdownTimerRef = (0, external_react_namespaceObject.useRef)(null);
|
|
147
|
+
const countdownResolveRef = (0, external_react_namespaceObject.useRef)(null);
|
|
148
|
+
const mountedRef = (0, external_react_namespaceObject.useRef)(true);
|
|
149
|
+
const lastSetupPlatformIdRef = (0, external_react_namespaceObject.useRef)(void 0);
|
|
150
|
+
const autoCreateSignatureRef = (0, external_react_namespaceObject.useRef)(null);
|
|
151
|
+
const autoCreateBlockedSignatureRef = (0, external_react_namespaceObject.useRef)(null);
|
|
152
|
+
const sessionMutatingRef = (0, external_react_namespaceObject.useRef)(false);
|
|
153
|
+
const appliedAiConfigSignatureRef = (0, external_react_namespaceObject.useRef)(null);
|
|
154
|
+
const pendingCreateSessionRef = (0, external_react_namespaceObject.useRef)(null);
|
|
155
|
+
const pendingAiConfigApplicationRef = (0, external_react_namespaceObject.useRef)(null);
|
|
132
156
|
const applyAiConfig = (0, external_react_namespaceObject.useCallback)(()=>_async_to_generator(function*() {
|
|
133
|
-
if (!(0, external_ai_config_js_namespaceObject.hasPlaygroundAiConfig)(aiConfig))
|
|
134
|
-
|
|
135
|
-
|
|
157
|
+
if (!(0, external_ai_config_js_namespaceObject.hasPlaygroundAiConfig)(aiConfig)) {
|
|
158
|
+
appliedAiConfigSignatureRef.current = null;
|
|
159
|
+
pendingAiConfigApplicationRef.current = null;
|
|
136
160
|
return true;
|
|
137
|
-
} catch (error) {
|
|
138
|
-
const errorMessage = error instanceof Error ? error.message : 'Failed to apply AI configuration';
|
|
139
|
-
external_antd_namespaceObject.message.error(errorMessage);
|
|
140
|
-
return false;
|
|
141
161
|
}
|
|
162
|
+
if (appliedAiConfigSignatureRef.current === aiConfigSignature) return true;
|
|
163
|
+
const pendingApplication = pendingAiConfigApplicationRef.current;
|
|
164
|
+
if ((null == pendingApplication ? void 0 : pendingApplication.signature) === aiConfigSignature) return pendingApplication.promise;
|
|
165
|
+
const pendingApplicationState = {
|
|
166
|
+
promise: Promise.resolve(true),
|
|
167
|
+
signature: aiConfigSignature
|
|
168
|
+
};
|
|
169
|
+
const applyPromise = (()=>_async_to_generator(function*() {
|
|
170
|
+
try {
|
|
171
|
+
yield (0, external_ai_config_js_namespaceObject.applyPlaygroundAiConfig)(playgroundSDK, aiConfig);
|
|
172
|
+
appliedAiConfigSignatureRef.current = aiConfigSignature;
|
|
173
|
+
return true;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to apply AI configuration';
|
|
176
|
+
external_antd_namespaceObject.message.error(errorMessage);
|
|
177
|
+
return false;
|
|
178
|
+
} finally{
|
|
179
|
+
if (pendingAiConfigApplicationRef.current === pendingApplicationState) pendingAiConfigApplicationRef.current = null;
|
|
180
|
+
}
|
|
181
|
+
})())();
|
|
182
|
+
pendingApplicationState.promise = applyPromise;
|
|
183
|
+
pendingAiConfigApplicationRef.current = pendingApplicationState;
|
|
184
|
+
return applyPromise;
|
|
142
185
|
})(), [
|
|
143
186
|
aiConfig,
|
|
187
|
+
aiConfigSignature,
|
|
144
188
|
playgroundSDK
|
|
145
189
|
]);
|
|
146
|
-
const countdownTimerRef = (0, external_react_namespaceObject.useRef)(null);
|
|
147
|
-
const countdownResolveRef = (0, external_react_namespaceObject.useRef)(null);
|
|
148
|
-
const mountedRef = (0, external_react_namespaceObject.useRef)(true);
|
|
149
|
-
const lastSetupPlatformIdRef = (0, external_react_namespaceObject.useRef)(void 0);
|
|
150
|
-
const autoCreateSignatureRef = (0, external_react_namespaceObject.useRef)(null);
|
|
151
|
-
const autoCreateBlockedSignatureRef = (0, external_react_namespaceObject.useRef)(null);
|
|
152
190
|
const finishCountdown = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
153
191
|
if (null !== countdownTimerRef.current) {
|
|
154
192
|
window.clearInterval(countdownTimerRef.current);
|
|
@@ -226,23 +264,27 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
226
264
|
playgroundSDK
|
|
227
265
|
]);
|
|
228
266
|
const createSession = (0, external_react_namespaceObject.useCallback)((input, options)=>_async_to_generator(function*() {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
267
|
+
return (0, external_single_flight_js_namespaceObject.runSingleFlight)(pendingCreateSessionRef, ()=>_async_to_generator(function*() {
|
|
268
|
+
try {
|
|
269
|
+
sessionMutatingRef.current = true;
|
|
270
|
+
setSessionMutating(true);
|
|
271
|
+
if (!(yield applyAiConfig())) return false;
|
|
272
|
+
const values = null != input ? input : yield form.validateFields();
|
|
273
|
+
yield playgroundSDK.createSession(values);
|
|
274
|
+
if ((0, external_auto_create_js_namespaceObject.shouldResetAutoCreateBlock)(options)) autoCreateBlockedSignatureRef.current = null;
|
|
275
|
+
if (!(null == options ? void 0 : options.silent)) external_antd_namespaceObject.message.success('Agent created');
|
|
276
|
+
yield refreshServerState();
|
|
277
|
+
return true;
|
|
278
|
+
} catch (error) {
|
|
279
|
+
if (error.errorFields) return false;
|
|
280
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to create Agent';
|
|
281
|
+
external_antd_namespaceObject.message.error(errorMessage);
|
|
282
|
+
return false;
|
|
283
|
+
} finally{
|
|
284
|
+
sessionMutatingRef.current = false;
|
|
285
|
+
setSessionMutating(false);
|
|
286
|
+
}
|
|
287
|
+
})());
|
|
246
288
|
})(), [
|
|
247
289
|
applyAiConfig,
|
|
248
290
|
form,
|
|
@@ -252,6 +294,7 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
252
294
|
const destroySession = (0, external_react_namespaceObject.useCallback)(()=>_async_to_generator(function*() {
|
|
253
295
|
try {
|
|
254
296
|
autoCreateBlockedSignatureRef.current = (0, external_auto_create_js_namespaceObject.serializeAutoCreateInput)((0, external_session_setup_js_namespaceObject.resolveAutoCreateSessionInput)(sessionSetup, form.getFieldsValue(true)));
|
|
297
|
+
sessionMutatingRef.current = true;
|
|
255
298
|
setSessionMutating(true);
|
|
256
299
|
yield playgroundSDK.destroySession();
|
|
257
300
|
external_antd_namespaceObject.message.success('Session disconnected');
|
|
@@ -261,6 +304,7 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
261
304
|
const errorMessage = error instanceof Error ? error.message : 'Failed to disconnect session';
|
|
262
305
|
external_antd_namespaceObject.message.error(errorMessage);
|
|
263
306
|
} finally{
|
|
307
|
+
sessionMutatingRef.current = false;
|
|
264
308
|
setSessionMutating(false);
|
|
265
309
|
}
|
|
266
310
|
})(), [
|
|
@@ -326,7 +370,7 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
326
370
|
autoCreateSignatureRef.current = null;
|
|
327
371
|
return;
|
|
328
372
|
}
|
|
329
|
-
if (!serverOnline || sessionLoading || sessionMutating || sessionSetupError) return;
|
|
373
|
+
if (!serverOnline || sessionLoading || sessionMutating || sessionMutatingRef.current || sessionSetupError) return;
|
|
330
374
|
const autoCreateInput = (0, external_session_setup_js_namespaceObject.resolveAutoCreateSessionInput)(sessionSetup, form.getFieldsValue(true));
|
|
331
375
|
const { signature, shouldCreate } = (0, external_auto_create_js_namespaceObject.resolveAutoCreateDecision)({
|
|
332
376
|
autoCreateInput,
|
|
@@ -58,7 +58,8 @@ function _async_to_generator(fn) {
|
|
|
58
58
|
});
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
|
-
|
|
61
|
+
const PLAYGROUND_CONVERSATION_SKIN_CLASS = 'playground-conversation-skin';
|
|
62
|
+
function PlaygroundConversationPanel({ controller, appVersion, title = 'Playground', branding, playgroundConfig, header, className, playgroundClassName, notConnectedFallback }) {
|
|
62
63
|
const { state, actions } = controller;
|
|
63
64
|
const mergedConfig = (0, selectors_js_namespaceObject.buildConversationConfig)(state, playgroundConfig);
|
|
64
65
|
const mergedBranding = (0, selectors_js_namespaceObject.buildConversationBranding)(state.runtimeInfo, title, appVersion, state.deviceType, branding);
|
|
@@ -133,7 +134,11 @@ function PlaygroundConversationPanel({ controller, appVersion, title = 'Playgrou
|
|
|
133
134
|
playgroundSDK: state.playgroundSDK,
|
|
134
135
|
config: mergedConfig,
|
|
135
136
|
branding: mergedBranding,
|
|
136
|
-
className:
|
|
137
|
+
className: [
|
|
138
|
+
'playground-container',
|
|
139
|
+
PLAYGROUND_CONVERSATION_SKIN_CLASS,
|
|
140
|
+
playgroundClassName
|
|
141
|
+
].filter(Boolean).join(' ')
|
|
137
142
|
}) : void 0 !== notConnectedFallback ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(jsx_runtime_namespaceObject.Fragment, {
|
|
138
143
|
children: notConnectedFallback
|
|
139
144
|
}) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_SessionSetupPanel_js_namespaceObject.SessionSetupPanel, {
|
package/dist/lib/runtime-info.js
CHANGED
|
@@ -132,7 +132,8 @@ function resolvePreviewConnectionInfo(runtimeInfo, serverUrl) {
|
|
|
132
132
|
}
|
|
133
133
|
if ('scrcpy' === preview.kind) {
|
|
134
134
|
var _runtimeInfo_metadata, _preview_custom;
|
|
135
|
-
|
|
135
|
+
const runtimeDeviceId = 'string' == typeof (null == runtimeInfo ? void 0 : null == (_runtimeInfo_metadata = runtimeInfo.metadata) ? void 0 : _runtimeInfo_metadata.deviceId) ? runtimeInfo.metadata.deviceId.trim() : void 0;
|
|
136
|
+
if (isRemoteAndroidDeviceId(runtimeDeviceId)) return {
|
|
136
137
|
type: 'screenshot'
|
|
137
138
|
};
|
|
138
139
|
const scrcpyPort = Number(null == (_preview_custom = preview.custom) ? void 0 : _preview_custom.scrcpyPort);
|
|
@@ -146,6 +147,7 @@ function resolvePreviewConnectionInfo(runtimeInfo, serverUrl) {
|
|
|
146
147
|
return url.toString();
|
|
147
148
|
})() : void 0;
|
|
148
149
|
return {
|
|
150
|
+
deviceId: runtimeDeviceId,
|
|
149
151
|
type: 'scrcpy',
|
|
150
152
|
scrcpyPort: resolvedScrcpyPort,
|
|
151
153
|
scrcpyUrl
|
|
@@ -4,7 +4,7 @@ import type { ScrcpyErrorOverlayRenderer } from './ScrcpyPanel';
|
|
|
4
4
|
import type { ScrcpyPreviewStatus } from './scrcpy-preview';
|
|
5
5
|
export interface PlaygroundPreviewProps {
|
|
6
6
|
connectingOverlay?: ReactNode;
|
|
7
|
-
onScrcpyStatusChange?: (status: ScrcpyPreviewStatus) => void;
|
|
7
|
+
onScrcpyStatusChange?: (status: ScrcpyPreviewStatus, statusText: string) => void;
|
|
8
8
|
renderErrorOverlay?: ScrcpyErrorOverlayRenderer;
|
|
9
9
|
playgroundSDK: PlaygroundSDK;
|
|
10
10
|
runtimeInfo: PlaygroundRuntimeInfo | null;
|
|
@@ -4,7 +4,7 @@ import { type ScrcpyErrorOverlayRenderer } from './ScrcpyPanel';
|
|
|
4
4
|
import type { ScrcpyPreviewStatus } from './scrcpy-preview';
|
|
5
5
|
interface PreviewRendererProps {
|
|
6
6
|
connectingOverlay?: ReactNode;
|
|
7
|
-
onScrcpyStatusChange?: (status: ScrcpyPreviewStatus) => void;
|
|
7
|
+
onScrcpyStatusChange?: (status: ScrcpyPreviewStatus, statusText: string) => void;
|
|
8
8
|
renderErrorOverlay?: ScrcpyErrorOverlayRenderer;
|
|
9
9
|
playgroundSDK: PlaygroundSDK;
|
|
10
10
|
runtimeInfo: PlaygroundRuntimeInfo | null;
|
|
@@ -9,11 +9,12 @@ export interface ScrcpyErrorOverlayContext {
|
|
|
9
9
|
export type ScrcpyErrorOverlayRenderer = (context: ScrcpyErrorOverlayContext) => ReactNode;
|
|
10
10
|
interface ScrcpyPanelProps {
|
|
11
11
|
connectingOverlay?: ReactNode;
|
|
12
|
-
|
|
12
|
+
deviceId?: string;
|
|
13
|
+
onStatusChange?: (status: ScrcpyPreviewStatus, statusText: string) => void;
|
|
13
14
|
renderErrorOverlay?: ScrcpyErrorOverlayRenderer;
|
|
14
15
|
serverUrl?: string;
|
|
15
16
|
metadataTimeoutMs?: number;
|
|
16
17
|
reconnectInterval?: number;
|
|
17
18
|
}
|
|
18
|
-
export declare function ScrcpyPanel({ connectingOverlay, onStatusChange, renderErrorOverlay, serverUrl, metadataTimeoutMs, reconnectInterval, }: ScrcpyPanelProps): React.JSX.Element;
|
|
19
|
+
export declare function ScrcpyPanel({ connectingOverlay, deviceId, onStatusChange, renderErrorOverlay, serverUrl, metadataTimeoutMs, reconnectInterval, }: ScrcpyPanelProps): React.JSX.Element;
|
|
19
20
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PlaygroundSDK } from '@midscene/playground';
|
|
2
2
|
export type PlaygroundAiConfig = Record<string, string>;
|
|
3
3
|
export declare function hasPlaygroundAiConfig(config: PlaygroundAiConfig): boolean;
|
|
4
|
+
export declare function serializePlaygroundAiConfig(config: PlaygroundAiConfig): string;
|
|
4
5
|
export declare function applyPlaygroundAiConfig(playgroundSDK: Pick<PlaygroundSDK, 'overrideConfig'>, config: PlaygroundAiConfig): Promise<boolean>;
|
|
@@ -5,5 +5,12 @@ export interface UsePlaygroundControllerOptions {
|
|
|
5
5
|
defaultDeviceType?: DeviceType;
|
|
6
6
|
pollIntervalMs?: number;
|
|
7
7
|
countdownSeconds?: number;
|
|
8
|
+
/**
|
|
9
|
+
* Seed values written into the session-setup form on the first render.
|
|
10
|
+
* Useful for pre-selecting a default platform so the initial
|
|
11
|
+
* `refreshSessionSetup` poll already has a `platformId`, instead of
|
|
12
|
+
* returning a generic "Choose a platform" setup.
|
|
13
|
+
*/
|
|
14
|
+
initialFormValues?: Record<string, unknown>;
|
|
8
15
|
}
|
|
9
|
-
export declare function usePlaygroundController({ serverUrl, defaultDeviceType, pollIntervalMs, countdownSeconds, }: UsePlaygroundControllerOptions): PlaygroundControllerResult;
|
|
16
|
+
export declare function usePlaygroundController({ serverUrl, defaultDeviceType, pollIntervalMs, countdownSeconds, initialFormValues, }: UsePlaygroundControllerOptions): PlaygroundControllerResult;
|
|
@@ -10,6 +10,10 @@ export interface PlaygroundConversationPanelProps {
|
|
|
10
10
|
playgroundConfig?: Partial<UniversalPlaygroundConfig>;
|
|
11
11
|
header?: ReactNode;
|
|
12
12
|
className?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Extra class appended to the inner `UniversalPlayground` root.
|
|
15
|
+
*/
|
|
16
|
+
playgroundClassName?: string;
|
|
13
17
|
/**
|
|
14
18
|
* Custom content shown while the session is not yet connected.
|
|
15
19
|
* When supplied, replaces the built-in `SessionSetupPanel`, letting hosts
|
|
@@ -17,4 +21,4 @@ export interface PlaygroundConversationPanelProps {
|
|
|
17
21
|
*/
|
|
18
22
|
notConnectedFallback?: ReactNode;
|
|
19
23
|
}
|
|
20
|
-
export declare function PlaygroundConversationPanel({ controller, appVersion, title, branding, playgroundConfig, header, className, notConnectedFallback, }: PlaygroundConversationPanelProps): import("react").JSX.Element;
|
|
24
|
+
export declare function PlaygroundConversationPanel({ controller, appVersion, title, branding, playgroundConfig, header, className, playgroundClassName, notConnectedFallback, }: PlaygroundConversationPanelProps): import("react").JSX.Element;
|
|
@@ -2,6 +2,7 @@ import type { PlaygroundRuntimeInfo } from '@midscene/playground';
|
|
|
2
2
|
import type { DeviceType, ExecutionUxHint } from '@midscene/visualizer';
|
|
3
3
|
export interface PreviewConnectionInfo {
|
|
4
4
|
type: 'none' | 'screenshot' | 'mjpeg' | 'scrcpy';
|
|
5
|
+
deviceId?: string;
|
|
5
6
|
mjpegUrl?: string;
|
|
6
7
|
scrcpyUrl?: string;
|
|
7
8
|
scrcpyPort?: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/playground-app",
|
|
3
|
-
"version": "1.7.5
|
|
3
|
+
"version": "1.7.5",
|
|
4
4
|
"description": "Reusable React shell for Midscene playground applications",
|
|
5
5
|
"repository": "https://github.com/web-infra-dev/midscene",
|
|
6
6
|
"homepage": "https://midscenejs.com/",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"antd": "^5.21.6",
|
|
29
29
|
"react-resizable-panels": "2.0.22",
|
|
30
30
|
"socket.io-client": "4.8.1",
|
|
31
|
-
"@midscene/playground": "1.7.5
|
|
32
|
-
"@midscene/shared": "1.7.5
|
|
33
|
-
"@midscene/visualizer": "1.7.5
|
|
31
|
+
"@midscene/playground": "1.7.5",
|
|
32
|
+
"@midscene/shared": "1.7.5",
|
|
33
|
+
"@midscene/visualizer": "1.7.5"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@rsbuild/plugin-less": "^1.5.0",
|