@agentscope-ai/chat 1.1.56 ā 1.1.58
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/bin/cli.js +81 -17
- package/components/Sender/demo/basic.tsx +1 -1
- package/components/Sender/index.tsx +12 -3
- package/lib/Sender/index.js +11 -2
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
const { program } = require('commander');
|
|
4
4
|
const { execSync } = require('child_process');
|
|
5
5
|
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const crypto = require('crypto');
|
|
6
8
|
|
|
7
9
|
function execSyncSafe(command) {
|
|
8
10
|
try {
|
|
@@ -11,11 +13,43 @@ function execSyncSafe(command) {
|
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
15
|
|
|
16
|
+
function getFileHash(filePath) {
|
|
17
|
+
try {
|
|
18
|
+
const data = fs.readFileSync(filePath);
|
|
19
|
+
return crypto.createHash('md5').update(data).digest('hex');
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getCacheFile() {
|
|
26
|
+
return path.join(__dirname, '.webui-cache.json');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function loadCache() {
|
|
30
|
+
try {
|
|
31
|
+
const cacheFile = getCacheFile();
|
|
32
|
+
if (fs.existsSync(cacheFile)) {
|
|
33
|
+
return JSON.parse(fs.readFileSync(cacheFile, 'utf-8'));
|
|
34
|
+
}
|
|
35
|
+
} catch (error) {
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function saveCache(cache) {
|
|
41
|
+
try {
|
|
42
|
+
fs.writeFileSync(getCacheFile(), JSON.stringify(cache, null, 2));
|
|
43
|
+
} catch (error) {
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
14
47
|
program
|
|
15
48
|
.name('agentscope-runtime-webui')
|
|
16
49
|
.description('Start the AgentScope Runtime WebUI service')
|
|
17
50
|
.option('-u, --url <url>', 'The backend API address')
|
|
18
51
|
.option('-t, --token <token>', 'The authentication token')
|
|
52
|
+
.option('-f, --force', 'Force re-extract WebUI even if it exists')
|
|
19
53
|
.parse(process.argv);
|
|
20
54
|
|
|
21
55
|
const options = program.opts();
|
|
@@ -24,15 +58,55 @@ async function startServer() {
|
|
|
24
58
|
console.log('\nš Starting AgentScope Runtime WebUI...\n');
|
|
25
59
|
|
|
26
60
|
try {
|
|
27
|
-
execSyncSafe(`npx rimraf ${__dirname}/starter_webui`);
|
|
28
|
-
execSyncSafe(`npx rimraf ${__dirname}/__MACOSX`);
|
|
29
|
-
execSyncSafe(
|
|
30
|
-
`npx decompress-cli ${__dirname}/starter_webui.zip --out-dir ${__dirname}`,
|
|
31
|
-
);
|
|
32
|
-
|
|
33
61
|
const targetDir = path.join(__dirname, 'starter_webui');
|
|
62
|
+
const nodeModulesDir = path.join(targetDir, 'node_modules');
|
|
63
|
+
const zipFile = path.join(__dirname, 'starter_webui.zip');
|
|
64
|
+
const cache = loadCache();
|
|
65
|
+
const currentZipHash = getFileHash(zipFile);
|
|
66
|
+
|
|
67
|
+
let shouldDecompress = false;
|
|
68
|
+
|
|
69
|
+
// Force decompress if --force flag is set
|
|
70
|
+
if (options.force) {
|
|
71
|
+
console.log('ā ļø Force mode: removing existing WebUI...');
|
|
72
|
+
execSyncSafe(`npx rimraf ${targetDir}`);
|
|
73
|
+
execSyncSafe(`npx rimraf ${__dirname}/__MACOSX`);
|
|
74
|
+
shouldDecompress = true;
|
|
75
|
+
} else if (!fs.existsSync(targetDir)) {
|
|
76
|
+
// Decompress if target directory doesn't exist
|
|
77
|
+
console.log('š¦ Decompressing WebUI for the first time...');
|
|
78
|
+
shouldDecompress = true;
|
|
79
|
+
} else if (cache && cache.zipHash && currentZipHash && cache.zipHash !== currentZipHash) {
|
|
80
|
+
// Decompress if zip file has changed
|
|
81
|
+
console.log('š WebUI zip file has changed, re-extracting...');
|
|
82
|
+
execSyncSafe(`npx rimraf ${targetDir}`);
|
|
83
|
+
execSyncSafe(`npx rimraf ${__dirname}/__MACOSX`);
|
|
84
|
+
shouldDecompress = true;
|
|
85
|
+
} else {
|
|
86
|
+
console.log('ā
WebUI is up to date, skipping decompression.');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (shouldDecompress) {
|
|
90
|
+
execSyncSafe(
|
|
91
|
+
`npx decompress-cli ${zipFile} --out-dir ${__dirname}`,
|
|
92
|
+
);
|
|
93
|
+
// Save cache after successful decompression
|
|
94
|
+
saveCache({ zipHash: currentZipHash, timestamp: Date.now() });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Only run npm install if node_modules doesn't exist
|
|
98
|
+
if (!fs.existsSync(nodeModulesDir)) {
|
|
99
|
+
console.log('š¦ Installing dependencies...');
|
|
100
|
+
execSync(`npm install`, {
|
|
101
|
+
cwd: targetDir,
|
|
102
|
+
stdio: 'inherit',
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
console.log('ā
Dependencies already installed, skipping npm install.');
|
|
106
|
+
}
|
|
107
|
+
|
|
34
108
|
execSync(
|
|
35
|
-
`npm
|
|
109
|
+
`npm run dev`,
|
|
36
110
|
{
|
|
37
111
|
cwd: targetDir,
|
|
38
112
|
stdio: 'inherit',
|
|
@@ -43,16 +117,6 @@ async function startServer() {
|
|
|
43
117
|
}
|
|
44
118
|
},
|
|
45
119
|
);
|
|
46
|
-
|
|
47
|
-
process.on('SIGINT', () => {
|
|
48
|
-
server.close();
|
|
49
|
-
process.exit(0);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
process.on('SIGTERM', () => {
|
|
53
|
-
server.close();
|
|
54
|
-
process.exit(0);
|
|
55
|
-
});
|
|
56
120
|
} catch (error) {
|
|
57
121
|
console.error(error);
|
|
58
122
|
process.exit(1);
|
|
@@ -3,5 +3,5 @@ import { ChatInput } from '@agentscope-ai/chat';
|
|
|
3
3
|
|
|
4
4
|
export default function () {
|
|
5
5
|
const [value, setValue] = useState('Hello, Alibaba Cloud Spark Chat!');
|
|
6
|
-
return <ChatInput placeholder='Please type here...' value={value} onChange={setValue}></ChatInput>
|
|
6
|
+
return <ChatInput placeholder='Please type here...' value={value} onChange={setValue} maxLength={100}></ChatInput>
|
|
7
7
|
}
|
|
@@ -430,8 +430,14 @@ const ForwardSender = React.forwardRef<SenderRef, SenderProps>((props, ref) => {
|
|
|
430
430
|
isCompositionRef.current = true;
|
|
431
431
|
};
|
|
432
432
|
|
|
433
|
-
const onInternalCompositionEnd = () => {
|
|
433
|
+
const onInternalCompositionEnd = (e: React.CompositionEvent<HTMLTextAreaElement>) => {
|
|
434
434
|
isCompositionRef.current = false;
|
|
435
|
+
if (props.maxLength) {
|
|
436
|
+
const currentValue = (e.target as HTMLTextAreaElement).value;
|
|
437
|
+
if (currentValue.length > props.maxLength) {
|
|
438
|
+
triggerValueChange(currentValue.slice(0, props.maxLength));
|
|
439
|
+
}
|
|
440
|
+
}
|
|
435
441
|
};
|
|
436
442
|
|
|
437
443
|
const onInternalPressEnter: TextareaProps['onPressEnter'] = (e) => {
|
|
@@ -533,7 +539,10 @@ const ForwardSender = React.forwardRef<SenderRef, SenderProps>((props, ref) => {
|
|
|
533
539
|
autoSize={autoSize}
|
|
534
540
|
value={innerValue.slice(0, props.maxLength || Number.MAX_SAFE_INTEGER)}
|
|
535
541
|
onChange={(event) => {
|
|
536
|
-
|
|
542
|
+
let nextValue = (event.target as HTMLTextAreaElement).value;
|
|
543
|
+
if (props.maxLength && !isCompositionRef.current && nextValue.length > props.maxLength) {
|
|
544
|
+
nextValue = nextValue.slice(0, props.maxLength);
|
|
545
|
+
}
|
|
537
546
|
triggerValueChange(
|
|
538
547
|
nextValue,
|
|
539
548
|
event as React.ChangeEvent<HTMLTextAreaElement>,
|
|
@@ -639,7 +648,7 @@ const ForwardSender = React.forwardRef<SenderRef, SenderProps>((props, ref) => {
|
|
|
639
648
|
>
|
|
640
649
|
{
|
|
641
650
|
props.maxLength ? <div className={`${actionListCls}-length`}>
|
|
642
|
-
{innerValue.length}/{props.maxLength}
|
|
651
|
+
{Math.min(innerValue.length, props.maxLength)}/{props.maxLength}
|
|
643
652
|
</div> : null
|
|
644
653
|
}
|
|
645
654
|
<ActionButtonContext.Provider
|
package/lib/Sender/index.js
CHANGED
|
@@ -225,8 +225,14 @@ var ForwardSender = /*#__PURE__*/React.forwardRef(function (props, ref) {
|
|
|
225
225
|
var onInternalCompositionStart = function onInternalCompositionStart() {
|
|
226
226
|
isCompositionRef.current = true;
|
|
227
227
|
};
|
|
228
|
-
var onInternalCompositionEnd = function onInternalCompositionEnd() {
|
|
228
|
+
var onInternalCompositionEnd = function onInternalCompositionEnd(e) {
|
|
229
229
|
isCompositionRef.current = false;
|
|
230
|
+
if (props.maxLength) {
|
|
231
|
+
var currentValue = e.target.value;
|
|
232
|
+
if (currentValue.length > props.maxLength) {
|
|
233
|
+
triggerValueChange(currentValue.slice(0, props.maxLength));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
230
236
|
};
|
|
231
237
|
var onInternalPressEnter = function onInternalPressEnter(e) {
|
|
232
238
|
var canSubmit = !isCompositionRef.current && !suggestionOpenRef.current;
|
|
@@ -326,6 +332,9 @@ var ForwardSender = /*#__PURE__*/React.forwardRef(function (props, ref) {
|
|
|
326
332
|
value: innerValue.slice(0, props.maxLength || Number.MAX_SAFE_INTEGER),
|
|
327
333
|
onChange: function onChange(event) {
|
|
328
334
|
var nextValue = event.target.value;
|
|
335
|
+
if (props.maxLength && !isCompositionRef.current && nextValue.length > props.maxLength) {
|
|
336
|
+
nextValue = nextValue.slice(0, props.maxLength);
|
|
337
|
+
}
|
|
329
338
|
triggerValueChange(nextValue, event);
|
|
330
339
|
if (hasSuggestions) {
|
|
331
340
|
var nextSlashCommandKeyword = getSlashCommandKeyword(nextValue);
|
|
@@ -413,7 +422,7 @@ var ForwardSender = /*#__PURE__*/React.forwardRef(function (props, ref) {
|
|
|
413
422
|
style: styles.actions,
|
|
414
423
|
children: [props.maxLength ? /*#__PURE__*/_jsxs("div", {
|
|
415
424
|
className: "".concat(actionListCls, "-length"),
|
|
416
|
-
children: [innerValue.length, "/", props.maxLength]
|
|
425
|
+
children: [Math.min(innerValue.length, props.maxLength), "/", props.maxLength]
|
|
417
426
|
}) : null, /*#__PURE__*/_jsx(ActionButtonContext.Provider, {
|
|
418
427
|
value: contextValue,
|
|
419
428
|
children: actionNode
|