@agentscope-ai/chat 1.1.58 → 1.1.59-beta.1775119922876

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.
Files changed (37) hide show
  1. package/bin/starter_webui/README.md +75 -0
  2. package/bin/starter_webui/eslint.config.js +28 -0
  3. package/bin/starter_webui/index.html +12 -0
  4. package/bin/starter_webui/package.json +34 -0
  5. package/bin/starter_webui/src/App.tsx +20 -0
  6. package/bin/starter_webui/src/components/Chat/OptionsPanel/FormItem.tsx +37 -0
  7. package/bin/starter_webui/src/components/Chat/OptionsPanel/OptionsEditor.tsx +160 -0
  8. package/bin/starter_webui/src/components/Chat/OptionsPanel/defaultConfig.ts +41 -0
  9. package/bin/starter_webui/src/components/Chat/OptionsPanel/index.tsx +27 -0
  10. package/bin/starter_webui/src/components/Chat/index.tsx +45 -0
  11. package/bin/starter_webui/src/components/Chat/sessionApi/index.ts +53 -0
  12. package/bin/starter_webui/src/main.tsx +9 -0
  13. package/bin/starter_webui/src/vite-env.d.ts +4 -0
  14. package/bin/starter_webui/tsconfig.app.json +24 -0
  15. package/bin/starter_webui/tsconfig.json +7 -0
  16. package/bin/starter_webui/tsconfig.node.json +22 -0
  17. package/bin/starter_webui/vite.config.ts +11 -0
  18. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/README.md +75 -0
  19. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/eslint.config.js +28 -0
  20. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/index.html +12 -0
  21. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/package.json +34 -0
  22. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/src/App.tsx +20 -0
  23. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/src/components/Chat/defaultConfig.ts +45 -0
  24. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/src/components/Chat/index.tsx +11 -0
  25. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/src/main.tsx +9 -0
  26. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/src/vite-env.d.ts +4 -0
  27. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/tsconfig.app.json +24 -0
  28. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/tsconfig.json +7 -0
  29. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/tsconfig.node.json +22 -0
  30. package/components/AgentScopeRuntimeWebUI/bailian-high-code-webui/vite.config.ts +7 -0
  31. package/components/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatController.tsx +15 -0
  32. package/components/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatRequest.tsx +6 -3
  33. package/components/AgentScopeRuntimeWebUI/core/Context/defaultSessionApi.ts +8 -3
  34. package/lib/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatController.js +19 -2
  35. package/lib/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatRequest.js +72 -63
  36. package/lib/AgentScopeRuntimeWebUI/core/Context/defaultSessionApi.js +8 -3
  37. package/package.json +1 -1
@@ -0,0 +1,75 @@
1
+ # agentscope-runtime-starter-webui
2
+
3
+ ## node version
4
+
5
+ > =22
6
+
7
+ ## install
8
+
9
+ ```
10
+ $ npm run install
11
+ ```
12
+
13
+ ## dev
14
+
15
+ ```
16
+ $ npm run dev
17
+ ```
18
+
19
+ ## build
20
+
21
+ ```
22
+ $ npm run build
23
+ ```
24
+
25
+ ## Core Code
26
+ ```tsx
27
+ import { AgentScopeRuntimeWebUI } from '@agentscope-ai/chat';
28
+
29
+ const options = {
30
+ theme: {
31
+ colorPrimary: '#615CED',
32
+ darkMode: true,
33
+ prefix: 'agentscope-runtime-webui',
34
+ leftHeader: {
35
+ logo: 'https://img.alicdn.com/imgextra/i2/O1CN01lmoGYn1kjoXATy4PX_!!6000000004720-2-tps-200-200.png',
36
+ title: 'Runtime WebUI',
37
+ },
38
+ },
39
+ sender: {
40
+ maxLength: 10000,
41
+ disclaimer:
42
+ 'AI can also make mistakes, so please check carefully and use it with caution',
43
+ },
44
+
45
+ welcome: {
46
+ greeting: 'Hello, how can I help you today?',
47
+ description:
48
+ 'I am a helpful assistant that can help you with your questions.',
49
+ avatar:
50
+ 'https://img.alicdn.com/imgextra/i2/O1CN01lmoGYn1kjoXATy4PX_!!6000000004720-2-tps-200-200.png',
51
+ prompts: [
52
+ {
53
+ value: 'Hello',
54
+ },
55
+ {
56
+ value: 'How are you?',
57
+ },
58
+ {
59
+ value: 'What can you do?',
60
+ },
61
+ ],
62
+ },
63
+ api: {
64
+ baseURL: 'YOUR_API_URL',
65
+ token: 'YOUR_API_TOKEN', // is not required
66
+ },
67
+ };
68
+
69
+
70
+ <AgentScopeRuntimeWebUI
71
+ options={options}
72
+ />
73
+
74
+
75
+ ```
@@ -0,0 +1,28 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import tseslint from 'typescript-eslint'
6
+
7
+ export default tseslint.config(
8
+ { ignores: ['dist'] },
9
+ {
10
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
11
+ files: ['**/*.{ts,tsx}'],
12
+ languageOptions: {
13
+ ecmaVersion: 2020,
14
+ globals: globals.browser,
15
+ },
16
+ plugins: {
17
+ 'react-hooks': reactHooks,
18
+ 'react-refresh': reactRefresh,
19
+ },
20
+ rules: {
21
+ ...reactHooks.configs.recommended.rules,
22
+ 'react-refresh/only-export-components': [
23
+ 'warn',
24
+ { allowConstantExport: true },
25
+ ],
26
+ },
27
+ },
28
+ )
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>AgentScope Runtime Starter WebUI</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "agentscope-runtime-starter-webui",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite --host",
8
+ "build": "tsc -b && vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "@agentscope-ai/icons": "^1.0.46",
14
+ "@agentscope-ai/chat": "^1.1.44",
15
+ "@agentscope-ai/design": "^1.0.19",
16
+ "antd": "^5.29.1",
17
+ "antd-style": "^3.7.1",
18
+ "react": "^18",
19
+ "react-dom": "^18"
20
+ },
21
+ "devDependencies": {
22
+ "@eslint/js": "^9.25.0",
23
+ "@types/react": "^18",
24
+ "@types/react-dom": "^18",
25
+ "@vitejs/plugin-react": "^4.4.1",
26
+ "eslint": "^9.25.0",
27
+ "eslint-plugin-react-hooks": "^5.2.0",
28
+ "eslint-plugin-react-refresh": "^0.4.19",
29
+ "globals": "^16.0.0",
30
+ "typescript": "~5.8.3",
31
+ "typescript-eslint": "^8.30.1",
32
+ "vite": "^6.3.5"
33
+ }
34
+ }
@@ -0,0 +1,20 @@
1
+ import Chat from './components/Chat';
2
+
3
+ import { createGlobalStyle } from 'antd-style';
4
+
5
+
6
+ const GlobalStyle = createGlobalStyle`
7
+ * {
8
+ margin: 0;
9
+ box-sizing: border-box;
10
+ }
11
+ `;
12
+
13
+ function App() {
14
+ return <>
15
+ <GlobalStyle />
16
+ <Chat />
17
+ </>
18
+ }
19
+
20
+ export default App
@@ -0,0 +1,37 @@
1
+ import { Form } from 'antd';
2
+ import { createStyles } from 'antd-style';
3
+
4
+
5
+ interface FormItemProps {
6
+ name: string | string[];
7
+ label: string;
8
+ isList?: boolean;
9
+ children: any;
10
+ normalize?: (value: any) => any;
11
+ }
12
+
13
+
14
+ const useStyles = createStyles(({ token }) => ({
15
+ label: {
16
+ marginBottom: 6,
17
+ fontSize: 12,
18
+ color: token.colorTextSecondary,
19
+ },
20
+
21
+ }));
22
+
23
+ export default function FormItem(props: FormItemProps) {
24
+ const { styles } = useStyles();
25
+
26
+
27
+ const node = props.isList ?
28
+ <Form.List name={props.name}>{props.children}</Form.List> :
29
+ <Form.Item name={props.name} normalize={props.normalize}>{props.children}</Form.Item>;
30
+
31
+
32
+ return <div>
33
+ {props.label && <div className={styles.label}>{props.label}</div>}
34
+ {node}
35
+ </div>
36
+
37
+ }
@@ -0,0 +1,160 @@
1
+ import React from 'react';
2
+ import { Form, Input, ColorPicker, Flex, Divider, InputNumber } from 'antd';
3
+ import { createStyles } from 'antd-style';
4
+ import { Button, IconButton, Switch } from '@agentscope-ai/design'
5
+ import { SparkDeleteLine, SparkPlusLine } from '@agentscope-ai/icons';
6
+ import FormItem from './FormItem';
7
+ import defaultConfig from './defaultConfig';
8
+
9
+ const useStyles = createStyles(({ token }) => ({
10
+ container: {
11
+ height: '100%',
12
+ display: 'flex',
13
+ flexDirection: 'column',
14
+ },
15
+
16
+ form: {
17
+ height: 0,
18
+ flex: 1,
19
+ padding: '8px 16px 16px 16px',
20
+ overflow: 'auto',
21
+ },
22
+ actions: {
23
+ padding: 16,
24
+ display: 'flex',
25
+ borderTop: `1px solid ${token.colorBorderSecondary}`,
26
+ justifyContent: 'flex-end',
27
+ gap: 16,
28
+ }
29
+
30
+ }));
31
+
32
+ interface OptionsEditorProps {
33
+ value?: any;
34
+ onChange?: any;
35
+ }
36
+
37
+ const OptionsEditor: React.FC<OptionsEditorProps> = ({
38
+ value,
39
+ onChange,
40
+ }) => {
41
+ const { styles } = useStyles();
42
+ const [form] = Form.useForm();
43
+
44
+
45
+ const handleSave = () => {
46
+ form.validateFields().then((values) => {
47
+ onChange(values);
48
+ });
49
+ };
50
+
51
+ const handleReset = () => {
52
+ form.setFieldsValue(defaultConfig);
53
+ };
54
+
55
+ return (
56
+ <div className={styles.container}>
57
+ <Form
58
+ className={styles.form}
59
+ form={form}
60
+ layout="vertical"
61
+ initialValues={value}
62
+ >
63
+
64
+
65
+ <Divider orientation="left">Theme</Divider>
66
+
67
+ <FormItem name={['theme', 'colorPrimary']} label="colorPrimary" normalize={value => value.toHexString()}>
68
+ <ColorPicker />
69
+ </FormItem>
70
+
71
+ <FormItem name={['theme', 'colorBgBase']} label="colorBgBase" normalize={value => value.toHexString()}>
72
+ <ColorPicker />
73
+ </FormItem>
74
+
75
+ <FormItem name={['theme', 'colorTextBase']} label="colorTextBase" normalize={value => value.toHexString()}>
76
+ <ColorPicker />
77
+ </FormItem>
78
+
79
+ <FormItem name={['theme', 'darkMode']} label="darkMode" >
80
+ <Switch />
81
+ </FormItem>
82
+
83
+ <FormItem name={['theme', 'leftHeader', 'logo']} label="leftHeader.logo" >
84
+ <Input />
85
+ </FormItem>
86
+
87
+ <FormItem name={['theme', 'leftHeader', 'title']} label="leftHeader.title" >
88
+ <Input />
89
+ </FormItem>
90
+
91
+ <Divider orientation="left">Sender</Divider>
92
+
93
+
94
+ <FormItem name={['sender', 'disclaimer']} label="disclaimer" >
95
+ <Input />
96
+ </FormItem>
97
+
98
+
99
+
100
+
101
+ <FormItem name={['sender', 'maxLength']} label="maxLength" >
102
+ <InputNumber min={1000} />
103
+ </FormItem>
104
+
105
+ <Divider orientation="left">Welcome</Divider>
106
+
107
+
108
+ <FormItem name={['welcome', 'greeting']} label="greeting" >
109
+ <Input />
110
+ </FormItem>
111
+
112
+ <FormItem name={['welcome', 'description']} label="description" >
113
+ <Input />
114
+ </FormItem>
115
+
116
+ <FormItem name={['welcome', 'avatar']} label="avatar" >
117
+ <Input />
118
+ </FormItem>
119
+
120
+
121
+ <FormItem name={['welcome', 'prompts']} isList label="prompts" >
122
+ {(fields: { key: string, name: string }[], { add, remove }: { add: (item: any) => void, remove: (name: string) => void }) => {
123
+ return <div>
124
+ {fields.map(field => {
125
+ return <Flex key={field.key} gap={6}>
126
+ <Form.Item style={{ flex: 1 }} key={field.key} name={[field.name, 'value']}>
127
+ <Input />
128
+ </Form.Item>
129
+ <IconButton icon={<SparkPlusLine />} onClick={() => add({})}></IconButton>
130
+ <IconButton icon={<SparkDeleteLine />} onClick={() => remove(field.name)}></IconButton>
131
+ </Flex>
132
+ })}
133
+ </div>
134
+ }}
135
+ </FormItem>
136
+
137
+
138
+ <Divider orientation="left">API</Divider>
139
+
140
+ <FormItem name={['api', 'baseURL']} label="baseURL" >
141
+ <Input />
142
+ </FormItem>
143
+
144
+ <FormItem name={['api', 'token']} label="token" >
145
+ <Input />
146
+ </FormItem>
147
+ </Form>
148
+
149
+ <div className={styles.actions}>
150
+ <Button onClick={handleReset}>Reset</Button>
151
+ <Button type="primary" onClick={handleSave}>
152
+ Save & Copy
153
+ </Button>
154
+ </div>
155
+ </div>
156
+ );
157
+ };
158
+
159
+ export default OptionsEditor;
160
+
@@ -0,0 +1,41 @@
1
+ export default {
2
+ theme: {
3
+ colorPrimary: '#615CED',
4
+ darkMode: true,
5
+ prefix: 'agentscope-runtime-webui',
6
+ leftHeader: {
7
+ logo: 'https://img.alicdn.com/imgextra/i2/O1CN01lmoGYn1kjoXATy4PX_!!6000000004720-2-tps-200-200.png',
8
+ title: 'Runtime WebUI',
9
+ },
10
+ },
11
+ sender: {
12
+ attachments: false,
13
+ maxLength: 10000,
14
+ disclaimer:
15
+ 'AI can also make mistakes, so please check carefully and use it with caution',
16
+ },
17
+
18
+ welcome: {
19
+ greeting: 'Hello, how can I help you today?',
20
+ description:
21
+ 'I am a helpful assistant that can help you with your questions.',
22
+ avatar:
23
+ 'https://img.alicdn.com/imgextra/i2/O1CN01lmoGYn1kjoXATy4PX_!!6000000004720-2-tps-200-200.png',
24
+ prompts: [
25
+ {
26
+ value: 'Hello',
27
+ },
28
+ {
29
+ value: 'How are you?',
30
+ },
31
+ {
32
+ value: 'What can you do?',
33
+ },
34
+ ],
35
+ },
36
+ api: {
37
+ baseURL: BASE_URL,
38
+ token: TOKEN,
39
+ },
40
+ };
41
+
@@ -0,0 +1,27 @@
1
+ import { SparkSettingLine } from "@agentscope-ai/icons";
2
+ import { IconButton, Drawer } from "@agentscope-ai/design";
3
+ import { useState } from "react";
4
+ import OptionsEditor from "./OptionsEditor";
5
+
6
+ interface OptionsPanelProps {
7
+ value?: any;
8
+ onChange?: any;
9
+ }
10
+
11
+ export default function OptionsPanel(props: OptionsPanelProps) {
12
+ const [open, setOpen] = useState(false);
13
+
14
+ return <>
15
+ <IconButton onClick={() => setOpen(true)} icon={<SparkSettingLine />} bordered={false} />
16
+ <Drawer
17
+ destroyOnHidden
18
+ open={open}
19
+ onClose={() => setOpen(false)}
20
+ styles={{ body: { padding: 0 }, header: { padding: 8 } }}>
21
+ <OptionsEditor value={props.value} onChange={(v: typeof props.value) => {
22
+ setOpen(false);
23
+ props.onChange(v);
24
+ }} />
25
+ </Drawer>
26
+ </>
27
+ }
@@ -0,0 +1,45 @@
1
+ import { AgentScopeRuntimeWebUI, IAgentScopeRuntimeWebUIOptions } from '@agentscope-ai/chat';
2
+ import OptionsPanel from './OptionsPanel';
3
+ import { useMemo } from 'react';
4
+ import sessionApi from './sessionApi';
5
+ import { useLocalStorageState } from 'ahooks';
6
+ import defaultConfig from './OptionsPanel/defaultConfig';
7
+
8
+ export default function () {
9
+ const [optionsConfig, setOptionsConfig] = useLocalStorageState('agent-scope-runtime-webui-options', {
10
+ defaultValue: defaultConfig,
11
+ listenStorageChange: true,
12
+ });
13
+
14
+ const options = useMemo(() => {
15
+ const rightHeader = <OptionsPanel value={optionsConfig} onChange={(v: typeof optionsConfig) => {
16
+ setOptionsConfig(prev => ({
17
+ ...prev,
18
+ ...v,
19
+ }));
20
+ }} />;
21
+
22
+
23
+
24
+ return {
25
+ ...optionsConfig,
26
+ session: {
27
+ multiple: true,
28
+ api: sessionApi,
29
+ },
30
+ theme: {
31
+ ...optionsConfig.theme,
32
+ rightHeader,
33
+ },
34
+ };
35
+ }, [optionsConfig]);
36
+
37
+
38
+
39
+
40
+ return <div style={{ height: '100vh' }}>
41
+ <AgentScopeRuntimeWebUI
42
+ options={options as unknown as IAgentScopeRuntimeWebUIOptions}
43
+ />
44
+ </div>;
45
+ }
@@ -0,0 +1,53 @@
1
+ import {
2
+ IAgentScopeRuntimeWebUISession,
3
+ IAgentScopeRuntimeWebUISessionAPI,
4
+ } from '@agentscope-ai/chat';
5
+
6
+ class SessionApi implements IAgentScopeRuntimeWebUISessionAPI {
7
+ private lsKey: string;
8
+ private sessionList: IAgentScopeRuntimeWebUISession[];
9
+
10
+ constructor() {
11
+ this.lsKey = 'agent-scope-runtime-webui-sessions';
12
+ this.sessionList = [];
13
+ }
14
+
15
+ async getSessionList() {
16
+ this.sessionList = JSON.parse(localStorage.getItem(this.lsKey) || '[]');
17
+ return [...this.sessionList];
18
+ }
19
+
20
+ async getSession(sessionId: string) {
21
+ return this.sessionList.find((session) => session.id === sessionId) as IAgentScopeRuntimeWebUISession;
22
+ }
23
+
24
+ async updateSession(session: Partial<IAgentScopeRuntimeWebUISession>) {
25
+ const index = this.sessionList.findIndex((item) => item.id === session.id);
26
+ if (index > -1) {
27
+ this.sessionList[index] = {
28
+ ...this.sessionList[index],
29
+ ...session,
30
+ };
31
+ localStorage.setItem(this.lsKey, JSON.stringify(this.sessionList));
32
+ }
33
+
34
+ return [...this.sessionList];
35
+ }
36
+
37
+ async createSession(session: Partial<IAgentScopeRuntimeWebUISession>) {
38
+ session.id = Date.now().toString();
39
+ this.sessionList.unshift(session as IAgentScopeRuntimeWebUISession);
40
+ localStorage.setItem(this.lsKey, JSON.stringify(this.sessionList));
41
+ return [...this.sessionList];
42
+ }
43
+
44
+ async removeSession(session: Partial<IAgentScopeRuntimeWebUISession>) {
45
+ this.sessionList = this.sessionList.filter(
46
+ (item) => item.id !== session.id,
47
+ );
48
+ localStorage.setItem(this.lsKey, JSON.stringify(this.sessionList));
49
+ return [...this.sessionList];
50
+ }
51
+ }
52
+
53
+ export default new SessionApi();
@@ -0,0 +1,9 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import App from './App.tsx'
4
+
5
+ createRoot(document.getElementById('root')!).render(
6
+ <StrictMode>
7
+ <App />
8
+ </StrictMode>,
9
+ )
@@ -0,0 +1,4 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare const BASE_URL: string;
4
+ declare const TOKEN: string;
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "ES2020",
5
+ "useDefineForClassFields": true,
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
+ "module": "ESNext",
8
+ "skipLibCheck": true,
9
+
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "moduleDetection": "force",
13
+ "noEmit": true,
14
+ "jsx": "react-jsx",
15
+
16
+ "strict": true,
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true,
19
+ "erasableSyntaxOnly": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "noUncheckedSideEffectImports": true
22
+ },
23
+ "include": ["src"]
24
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ "moduleResolution": "bundler",
10
+ "allowImportingTsExtensions": true,
11
+ "moduleDetection": "force",
12
+ "noEmit": true,
13
+
14
+ "strict": true,
15
+ "noUnusedLocals": true,
16
+ "noUnusedParameters": true,
17
+ "erasableSyntaxOnly": true,
18
+ "noFallthroughCasesInSwitch": true,
19
+ "noUncheckedSideEffectImports": true
20
+ },
21
+ "include": ["vite.config.ts"]
22
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ export default defineConfig({
5
+ define: {
6
+ BASE_URL: JSON.stringify(process.env.BASE_URL || ''),
7
+ TOKEN: JSON.stringify(process.env.TOKEN || ''),
8
+ MOBILE: false,
9
+ },
10
+ plugins: [react()],
11
+ })
@@ -0,0 +1,75 @@
1
+ # agentscope-runtime-starter-webui
2
+
3
+ ## node version
4
+
5
+ > =22
6
+
7
+ ## install
8
+
9
+ ```
10
+ $ npm run install
11
+ ```
12
+
13
+ ## dev
14
+
15
+ ```
16
+ $ npm run dev
17
+ ```
18
+
19
+ ## build
20
+
21
+ ```
22
+ $ npm run build
23
+ ```
24
+
25
+ ## Core Code
26
+ ```tsx
27
+ import { AgentScopeRuntimeWebUI } from '@agentscope-ai/chat';
28
+
29
+ const options = {
30
+ theme: {
31
+ colorPrimary: '#615CED',
32
+ darkMode: true,
33
+ prefix: 'agentscope-runtime-webui',
34
+ leftHeader: {
35
+ logo: 'https://img.alicdn.com/imgextra/i2/O1CN01lmoGYn1kjoXATy4PX_!!6000000004720-2-tps-200-200.png',
36
+ title: 'Runtime WebUI',
37
+ },
38
+ },
39
+ sender: {
40
+ maxLength: 10000,
41
+ disclaimer:
42
+ 'AI can also make mistakes, so please check carefully and use it with caution',
43
+ },
44
+
45
+ welcome: {
46
+ greeting: 'Hello, how can I help you today?',
47
+ description:
48
+ 'I am a helpful assistant that can help you with your questions.',
49
+ avatar:
50
+ 'https://img.alicdn.com/imgextra/i2/O1CN01lmoGYn1kjoXATy4PX_!!6000000004720-2-tps-200-200.png',
51
+ prompts: [
52
+ {
53
+ value: 'Hello',
54
+ },
55
+ {
56
+ value: 'How are you?',
57
+ },
58
+ {
59
+ value: 'What can you do?',
60
+ },
61
+ ],
62
+ },
63
+ api: {
64
+ baseURL: 'YOUR_API_URL',
65
+ token: 'YOUR_API_TOKEN', // is not required
66
+ },
67
+ };
68
+
69
+
70
+ <AgentScopeRuntimeWebUI
71
+ options={options}
72
+ />
73
+
74
+
75
+ ```
@@ -0,0 +1,28 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import tseslint from 'typescript-eslint'
6
+
7
+ export default tseslint.config(
8
+ { ignores: ['dist'] },
9
+ {
10
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
11
+ files: ['**/*.{ts,tsx}'],
12
+ languageOptions: {
13
+ ecmaVersion: 2020,
14
+ globals: globals.browser,
15
+ },
16
+ plugins: {
17
+ 'react-hooks': reactHooks,
18
+ 'react-refresh': reactRefresh,
19
+ },
20
+ rules: {
21
+ ...reactHooks.configs.recommended.rules,
22
+ 'react-refresh/only-export-components': [
23
+ 'warn',
24
+ { allowConstantExport: true },
25
+ ],
26
+ },
27
+ },
28
+ )
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>AgentScope Runtime Starter WebUI</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "agentscope-runtime-starter-webui",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite --host",
8
+ "build": "tsc -b && vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "@agentscope-ai/icons": "^1.0.46",
14
+ "@agentscope-ai/chat": "file://Users/ls/GitHub/agentscope-spark-design/packages/spark-chat",
15
+ "@agentscope-ai/design": "^1.0.19",
16
+ "antd": "^5.29.1",
17
+ "antd-style": "^3.7.1",
18
+ "react": "^18",
19
+ "react-dom": "^18"
20
+ },
21
+ "devDependencies": {
22
+ "@eslint/js": "^9.25.0",
23
+ "@types/react": "^18",
24
+ "@types/react-dom": "^18",
25
+ "@vitejs/plugin-react": "^4.4.1",
26
+ "eslint": "^9.25.0",
27
+ "eslint-plugin-react-hooks": "^5.2.0",
28
+ "eslint-plugin-react-refresh": "^0.4.19",
29
+ "globals": "^16.0.0",
30
+ "typescript": "~5.8.3",
31
+ "typescript-eslint": "^8.30.1",
32
+ "vite": "^6.3.5"
33
+ }
34
+ }
@@ -0,0 +1,20 @@
1
+ import Chat from './components/Chat';
2
+
3
+ import { createGlobalStyle } from 'antd-style';
4
+
5
+
6
+ const GlobalStyle = createGlobalStyle`
7
+ * {
8
+ margin: 0;
9
+ box-sizing: border-box;
10
+ }
11
+ `;
12
+
13
+ function App() {
14
+ return <>
15
+ <GlobalStyle />
16
+ <Chat />
17
+ </>
18
+ }
19
+
20
+ export default App
@@ -0,0 +1,45 @@
1
+ export default {
2
+ theme: {
3
+ colorPrimary: '#615CED',
4
+ darkMode: true,
5
+ prefix: 'agentscope-runtime-webui',
6
+ leftHeader: {
7
+ logo: 'https://img.alicdn.com/imgextra/i2/O1CN01lmoGYn1kjoXATy4PX_!!6000000004720-2-tps-200-200.png',
8
+ title: 'Runtime WebUI',
9
+ },
10
+ },
11
+ sender: {
12
+ attachments: false,
13
+ maxLength: 10000,
14
+ disclaimer:
15
+ 'AI can also make mistakes, so please check carefully and use it with caution',
16
+ },
17
+ session: {
18
+ multiple: false,
19
+ },
20
+
21
+ welcome: {
22
+ greeting: 'Hello, how can I help you today?',
23
+ description:
24
+ 'I am a helpful assistant that can help you with your questions.',
25
+ avatar:
26
+ 'https://img.alicdn.com/imgextra/i2/O1CN01lmoGYn1kjoXATy4PX_!!6000000004720-2-tps-200-200.png',
27
+ prompts: [
28
+ {
29
+ value: 'Hello',
30
+ },
31
+ {
32
+ value: 'How are you?',
33
+ },
34
+ {
35
+ value: 'What can you do?',
36
+ },
37
+ ],
38
+ },
39
+ api: {
40
+ baseURL: 'https://highcodnvvwbdks-ptzchpamaz.cn-beijing.fcapp.run/process',
41
+ token: '32a3e4da-528a-462d-a270-74b10cb21d75',
42
+ enableHistoryMessages: true,
43
+ },
44
+ };
45
+
@@ -0,0 +1,11 @@
1
+ import { AgentScopeRuntimeWebUI, IAgentScopeRuntimeWebUIOptions } from '@agentscope-ai/chat';
2
+ import defaultConfig from './defaultConfig';
3
+
4
+ export default function () {
5
+
6
+ return <div style={{ height: '100vh' }}>
7
+ <AgentScopeRuntimeWebUI
8
+ options={defaultConfig as unknown as IAgentScopeRuntimeWebUIOptions}
9
+ />
10
+ </div>;
11
+ }
@@ -0,0 +1,9 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import App from './App.tsx'
4
+
5
+ createRoot(document.getElementById('root')!).render(
6
+ <StrictMode>
7
+ <App />
8
+ </StrictMode>,
9
+ )
@@ -0,0 +1,4 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare const BASE_URL: string;
4
+ declare const TOKEN: string;
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "ES2020",
5
+ "useDefineForClassFields": true,
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
+ "module": "ESNext",
8
+ "skipLibCheck": true,
9
+
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "moduleDetection": "force",
13
+ "noEmit": true,
14
+ "jsx": "react-jsx",
15
+
16
+ "strict": true,
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true,
19
+ "erasableSyntaxOnly": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "noUncheckedSideEffectImports": true
22
+ },
23
+ "include": ["src"]
24
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ "moduleResolution": "bundler",
10
+ "allowImportingTsExtensions": true,
11
+ "moduleDetection": "force",
12
+ "noEmit": true,
13
+
14
+ "strict": true,
15
+ "noUnusedLocals": true,
16
+ "noUnusedParameters": true,
17
+ "erasableSyntaxOnly": true,
18
+ "noFallthroughCasesInSwitch": true,
19
+ "noUncheckedSideEffectImports": true
20
+ },
21
+ "include": ["vite.config.ts"]
22
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ export default defineConfig({
5
+ define: {},
6
+ plugins: [react()],
7
+ })
@@ -124,6 +124,8 @@ export default function useChatController() {
124
124
 
125
125
  /**
126
126
  * 处理 SSE 重连(切回未完成的对话时)
127
+ * If the reconnect API returns no body or the stream ends without a completion event,
128
+ * treat it as idle: remove the empty placeholder and reset loading.
127
129
  */
128
130
  const handleReconnect = useCallback(async (sessionId: string) => {
129
131
  currentQARef.current.abortController = new AbortController();
@@ -132,6 +134,19 @@ export default function useChatController() {
132
134
  messageHandler.createResponseMessage();
133
135
 
134
136
  await reconnect(sessionId);
137
+
138
+ // If the response is still in 'generating' state after reconnect completes,
139
+ // onFinish() was never called (no response body, or stream closed without a completion event).
140
+ // Treat as idle: remove the empty placeholder and reset loading.
141
+ // HTTP errors and normal SSE completions both call onFinish() → msgStatus becomes 'finished',
142
+ // so they are correctly excluded from this cleanup.
143
+ if (currentQARef.current.response?.msgStatus === 'generating') {
144
+ setLoading(false);
145
+ if (currentQARef.current.response?.id) {
146
+ messageHandler.removeMessageById(currentQARef.current.response.id);
147
+ }
148
+ currentQARef.current.response = undefined;
149
+ }
135
150
  }, [messageHandler, reconnect, setLoading]);
136
151
 
137
152
  // 监听会话切换,断开当前 SSE 连接(不通知后端取消)并重置状态
@@ -66,7 +66,8 @@ export default function useChatRequest(options: UseChatRequestOptions) {
66
66
  });
67
67
 
68
68
  if (!response.ok) {
69
- response.json().then(data => {
69
+ try {
70
+ const data = await response.json();
70
71
  const res = agentScopeRuntimeResponseBuilder.handle({
71
72
  object: 'message',
72
73
  type: AgentScopeRuntimeMessageType.ERROR,
@@ -84,8 +85,10 @@ export default function useChatRequest(options: UseChatRequestOptions) {
84
85
  data: res,
85
86
  }
86
87
  ];
87
- onFinish();
88
- });
88
+ } catch {
89
+ // Ignore JSON parse errors — still call onFinish to reset loading state
90
+ }
91
+ onFinish();
89
92
  return;
90
93
  }
91
94
 
@@ -48,9 +48,14 @@ function createStorageSessionStore(multiple: boolean) {
48
48
  return {
49
49
  async getSessionList() {
50
50
  load();
51
- if (!multiple && sessionList.length > 1) {
52
- sessionList = sessionList.slice(0, 1);
53
- persist();
51
+ if (!multiple) {
52
+ if (sessionList.length === 0) {
53
+ sessionList = [normalizeSession({})];
54
+ persist();
55
+ } else if (sessionList.length > 1) {
56
+ sessionList = sessionList.slice(0, 1);
57
+ persist();
58
+ }
54
59
  }
55
60
  return [...sessionList];
56
61
  },
@@ -179,9 +179,13 @@ export default function useChatController() {
179
179
 
180
180
  /**
181
181
  * 处理 SSE 重连(切回未完成的对话时)
182
+ * If the reconnect API returns no body or the stream ends without a completion event,
183
+ * treat it as idle: remove the empty placeholder and reset loading.
182
184
  */
183
185
  var handleReconnect = useCallback( /*#__PURE__*/function () {
184
186
  var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(sessionId) {
187
+ var _currentQARef$current;
188
+ var _currentQARef$current2;
185
189
  return _regeneratorRuntime().wrap(function _callee4$(_context4) {
186
190
  while (1) switch (_context4.prev = _context4.next) {
187
191
  case 0:
@@ -191,6 +195,19 @@ export default function useChatController() {
191
195
  _context4.next = 5;
192
196
  return reconnect(sessionId);
193
197
  case 5:
198
+ // If the response is still in 'generating' state after reconnect completes,
199
+ // onFinish() was never called (no response body, or stream closed without a completion event).
200
+ // Treat as idle: remove the empty placeholder and reset loading.
201
+ // HTTP errors and normal SSE completions both call onFinish() → msgStatus becomes 'finished',
202
+ // so they are correctly excluded from this cleanup.
203
+ if (((_currentQARef$current = currentQARef.current.response) === null || _currentQARef$current === void 0 ? void 0 : _currentQARef$current.msgStatus) === 'generating') {
204
+ setLoading(false);
205
+ if ((_currentQARef$current2 = currentQARef.current.response) !== null && _currentQARef$current2 !== void 0 && _currentQARef$current2.id) {
206
+ messageHandler.removeMessageById(currentQARef.current.response.id);
207
+ }
208
+ currentQARef.current.response = undefined;
209
+ }
210
+ case 6:
194
211
  case "end":
195
212
  return _context4.stop();
196
213
  }
@@ -203,8 +220,8 @@ export default function useChatController() {
203
220
 
204
221
  // 监听会话切换,断开当前 SSE 连接(不通知后端取消)并重置状态
205
222
  useEffect(function () {
206
- var _currentQARef$current;
207
- (_currentQARef$current = currentQARef.current.abortController) === null || _currentQARef$current === void 0 || _currentQARef$current.abort();
223
+ var _currentQARef$current3;
224
+ (_currentQARef$current3 = currentQARef.current.abortController) === null || _currentQARef$current3 === void 0 || _currentQARef$current3.abort();
208
225
  currentQARef.current = {
209
226
  request: undefined,
210
227
  response: undefined,
@@ -102,7 +102,7 @@ export default function useChatRequest(options) {
102
102
  }(), []);
103
103
  var processSSEResponse = useCallback( /*#__PURE__*/function () {
104
104
  var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(response) {
105
- var currentApiOptions, agentScopeRuntimeResponseBuilder, _iteratorAbruptCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, chunk, _currentQARef$current, _res$output, _currentQARef$current2, responseParser, chunkData, res;
105
+ var currentApiOptions, agentScopeRuntimeResponseBuilder, data, res, _iteratorAbruptCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, chunk, _currentQARef$current, _res$output, _currentQARef$current2, responseParser, chunkData, _res;
106
106
  return _regeneratorRuntime().wrap(function _callee2$(_context2) {
107
107
  while (1) switch (_context2.prev = _context2.next) {
108
108
  case 0:
@@ -113,46 +113,55 @@ export default function useChatRequest(options) {
113
113
  created_at: 0
114
114
  });
115
115
  if (response.ok) {
116
- _context2.next = 5;
116
+ _context2.next = 15;
117
117
  break;
118
118
  }
119
- response.json().then(function (data) {
120
- var res = agentScopeRuntimeResponseBuilder.handle({
121
- object: 'message',
122
- type: AgentScopeRuntimeMessageType.ERROR,
123
- content: [],
124
- id: 'error',
125
- role: 'assistant',
126
- status: AgentScopeRuntimeRunStatus.Failed,
127
- code: String(response.status),
128
- message: JSON.stringify(data)
129
- });
130
- currentQARef.current.response.cards = [{
131
- code: 'AgentScopeRuntimeResponseCard',
132
- data: res
133
- }];
134
- onFinish();
119
+ _context2.prev = 3;
120
+ _context2.next = 6;
121
+ return response.json();
122
+ case 6:
123
+ data = _context2.sent;
124
+ res = agentScopeRuntimeResponseBuilder.handle({
125
+ object: 'message',
126
+ type: AgentScopeRuntimeMessageType.ERROR,
127
+ content: [],
128
+ id: 'error',
129
+ role: 'assistant',
130
+ status: AgentScopeRuntimeRunStatus.Failed,
131
+ code: String(response.status),
132
+ message: JSON.stringify(data)
135
133
  });
134
+ currentQARef.current.response.cards = [{
135
+ code: 'AgentScopeRuntimeResponseCard',
136
+ data: res
137
+ }];
138
+ _context2.next = 13;
139
+ break;
140
+ case 11:
141
+ _context2.prev = 11;
142
+ _context2.t0 = _context2["catch"](3);
143
+ case 13:
144
+ onFinish();
136
145
  return _context2.abrupt("return");
137
- case 5:
138
- _context2.prev = 5;
146
+ case 15:
147
+ _context2.prev = 15;
139
148
  _iteratorAbruptCompletion2 = false;
140
149
  _didIteratorError2 = false;
141
- _context2.prev = 8;
150
+ _context2.prev = 18;
142
151
  _iterator2 = _asyncIterator(Stream({
143
152
  readableStream: response.body
144
153
  }));
145
- case 10:
146
- _context2.next = 12;
154
+ case 20:
155
+ _context2.next = 22;
147
156
  return _iterator2.next();
148
- case 12:
157
+ case 22:
149
158
  if (!(_iteratorAbruptCompletion2 = !(_step2 = _context2.sent).done)) {
150
- _context2.next = 29;
159
+ _context2.next = 39;
151
160
  break;
152
161
  }
153
162
  chunk = _step2.value;
154
163
  if (!(((_currentQARef$current = currentQARef.current.response) === null || _currentQARef$current === void 0 ? void 0 : _currentQARef$current.msgStatus) === 'interrupted')) {
155
- _context2.next = 20;
164
+ _context2.next = 30;
156
165
  break;
157
166
  }
158
167
  (_currentQARef$current2 = currentQARef.current.abortController) === null || _currentQARef$current2 === void 0 || _currentQARef$current2.abort();
@@ -166,72 +175,72 @@ export default function useChatRequest(options) {
166
175
  data: agentScopeRuntimeResponseBuilder.cancel()
167
176
  }];
168
177
  updateMessage(currentQARef.current.response);
169
- return _context2.abrupt("break", 29);
170
- case 20:
178
+ return _context2.abrupt("break", 39);
179
+ case 30:
171
180
  responseParser = apiOptionsRef.current.responseParser || JSON.parse;
172
181
  chunkData = responseParser(chunk.data);
173
- res = agentScopeRuntimeResponseBuilder.handle(chunkData);
174
- if (!(res.status !== AgentScopeRuntimeRunStatus.Failed && !((_res$output = res.output) !== null && _res$output !== void 0 && (_res$output = _res$output[0]) !== null && _res$output !== void 0 && (_res$output = _res$output.content) !== null && _res$output !== void 0 && _res$output.length))) {
175
- _context2.next = 25;
182
+ _res = agentScopeRuntimeResponseBuilder.handle(chunkData);
183
+ if (!(_res.status !== AgentScopeRuntimeRunStatus.Failed && !((_res$output = _res.output) !== null && _res$output !== void 0 && (_res$output = _res$output[0]) !== null && _res$output !== void 0 && (_res$output = _res$output.content) !== null && _res$output !== void 0 && _res$output.length))) {
184
+ _context2.next = 35;
176
185
  break;
177
186
  }
178
- return _context2.abrupt("continue", 26);
179
- case 25:
187
+ return _context2.abrupt("continue", 36);
188
+ case 35:
180
189
  if (currentQARef.current.response) {
181
190
  currentQARef.current.response.cards = [{
182
191
  code: 'AgentScopeRuntimeResponseCard',
183
- data: res
192
+ data: _res
184
193
  }];
185
- if (res.status === AgentScopeRuntimeRunStatus.Completed || res.status === AgentScopeRuntimeRunStatus.Failed) {
194
+ if (_res.status === AgentScopeRuntimeRunStatus.Completed || _res.status === AgentScopeRuntimeRunStatus.Failed) {
186
195
  onFinish();
187
196
  } else {
188
197
  updateMessage(currentQARef.current.response);
189
198
  }
190
199
  }
191
- case 26:
200
+ case 36:
192
201
  _iteratorAbruptCompletion2 = false;
193
- _context2.next = 10;
202
+ _context2.next = 20;
194
203
  break;
195
- case 29:
196
- _context2.next = 35;
204
+ case 39:
205
+ _context2.next = 45;
197
206
  break;
198
- case 31:
199
- _context2.prev = 31;
200
- _context2.t0 = _context2["catch"](8);
207
+ case 41:
208
+ _context2.prev = 41;
209
+ _context2.t1 = _context2["catch"](18);
201
210
  _didIteratorError2 = true;
202
- _iteratorError2 = _context2.t0;
203
- case 35:
204
- _context2.prev = 35;
205
- _context2.prev = 36;
211
+ _iteratorError2 = _context2.t1;
212
+ case 45:
213
+ _context2.prev = 45;
214
+ _context2.prev = 46;
206
215
  if (!(_iteratorAbruptCompletion2 && _iterator2.return != null)) {
207
- _context2.next = 40;
216
+ _context2.next = 50;
208
217
  break;
209
218
  }
210
- _context2.next = 40;
219
+ _context2.next = 50;
211
220
  return _iterator2.return();
212
- case 40:
213
- _context2.prev = 40;
221
+ case 50:
222
+ _context2.prev = 50;
214
223
  if (!_didIteratorError2) {
215
- _context2.next = 43;
224
+ _context2.next = 53;
216
225
  break;
217
226
  }
218
227
  throw _iteratorError2;
219
- case 43:
220
- return _context2.finish(40);
221
- case 44:
222
- return _context2.finish(35);
223
- case 45:
224
- _context2.next = 50;
228
+ case 53:
229
+ return _context2.finish(50);
230
+ case 54:
231
+ return _context2.finish(45);
232
+ case 55:
233
+ _context2.next = 60;
225
234
  break;
226
- case 47:
227
- _context2.prev = 47;
228
- _context2.t1 = _context2["catch"](5);
229
- console.error(_context2.t1);
230
- case 50:
235
+ case 57:
236
+ _context2.prev = 57;
237
+ _context2.t2 = _context2["catch"](15);
238
+ console.error(_context2.t2);
239
+ case 60:
231
240
  case "end":
232
241
  return _context2.stop();
233
242
  }
234
- }, _callee2, null, [[5, 47], [8, 31, 35, 45], [36,, 40, 44]]);
243
+ }, _callee2, null, [[3, 11], [15, 57], [18, 41, 45, 55], [46,, 50, 54]]);
235
244
  }));
236
245
  return function (_x2) {
237
246
  return _ref2.apply(this, arguments);
@@ -52,9 +52,14 @@ function createStorageSessionStore(multiple) {
52
52
  while (1) switch (_context.prev = _context.next) {
53
53
  case 0:
54
54
  load();
55
- if (!multiple && sessionList.length > 1) {
56
- sessionList = sessionList.slice(0, 1);
57
- persist();
55
+ if (!multiple) {
56
+ if (sessionList.length === 0) {
57
+ sessionList = [normalizeSession({})];
58
+ persist();
59
+ } else if (sessionList.length > 1) {
60
+ sessionList = sessionList.slice(0, 1);
61
+ persist();
62
+ }
58
63
  }
59
64
  return _context.abrupt("return", _toConsumableArray(sessionList));
60
65
  case 3:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentscope-ai/chat",
3
- "version": "1.1.58",
3
+ "version": "1.1.59-beta.1775119922876",
4
4
  "description": "a free and open-source chat framework for building excellent LLM-powered chat experiences",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": [