@lobehub/chat 0.111.5 → 0.112.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/.env.example +1 -1
  2. package/.i18nrc.js +1 -0
  3. package/CHANGELOG.md +84 -0
  4. package/README.md +2 -2
  5. package/README.zh-CN.md +2 -2
  6. package/docs/Deployment/Environment-Variable.md +1 -1
  7. package/docs/Deployment/Environment-Variable.zh-CN.md +1 -1
  8. package/docs/Deployment/Upstream-Sync.md +1 -1
  9. package/docs/Deployment/Upstream-Sync.zh-CN.md +1 -1
  10. package/docs/Home.md +26 -26
  11. package/docs/Plugins/Plugin-Development.md +1 -1
  12. package/docs/Plugins/Plugin-Development.zh-CN.md +1 -1
  13. package/docs/_Sidebar.md +20 -20
  14. package/locales/en_US/chat.json +12 -12
  15. package/locales/en_US/common.json +13 -13
  16. package/locales/en_US/error.json +16 -14
  17. package/locales/en_US/market.json +2 -2
  18. package/locales/en_US/migration.json +4 -4
  19. package/locales/en_US/plugin.json +75 -38
  20. package/locales/en_US/setting.json +7 -7
  21. package/locales/fr_FR/chat.json +11 -11
  22. package/locales/fr_FR/common.json +14 -14
  23. package/locales/fr_FR/error.json +12 -10
  24. package/locales/fr_FR/plugin.json +42 -5
  25. package/locales/fr_FR/setting.json +12 -12
  26. package/locales/fr_FR/welcome.json +3 -3
  27. package/locales/ja_JP/chat.json +1 -1
  28. package/locales/ja_JP/common.json +3 -3
  29. package/locales/ja_JP/error.json +16 -14
  30. package/locales/ja_JP/migration.json +4 -4
  31. package/locales/ja_JP/plugin.json +70 -33
  32. package/locales/ja_JP/setting.json +1 -1
  33. package/locales/ko_KR/chat.json +1 -1
  34. package/locales/ko_KR/common.json +3 -3
  35. package/locales/ko_KR/error.json +16 -14
  36. package/locales/ko_KR/migration.json +4 -4
  37. package/locales/ko_KR/plugin.json +71 -34
  38. package/locales/ko_KR/setting.json +1 -1
  39. package/locales/ru_RU/chat.json +1 -1
  40. package/locales/ru_RU/common.json +3 -3
  41. package/locales/ru_RU/error.json +16 -14
  42. package/locales/ru_RU/market.json +2 -2
  43. package/locales/ru_RU/migration.json +4 -4
  44. package/locales/ru_RU/plugin.json +71 -34
  45. package/locales/ru_RU/setting.json +1 -1
  46. package/locales/zh_CN/chat.json +1 -1
  47. package/locales/zh_CN/common.json +1 -1
  48. package/locales/zh_CN/error.json +2 -0
  49. package/locales/zh_CN/plugin.json +42 -5
  50. package/locales/zh_CN/setting.json +1 -1
  51. package/locales/zh_TW/chat.json +1 -1
  52. package/locales/zh_TW/common.json +3 -3
  53. package/locales/zh_TW/error.json +16 -14
  54. package/locales/zh_TW/market.json +2 -2
  55. package/locales/zh_TW/migration.json +4 -4
  56. package/locales/zh_TW/plugin.json +98 -61
  57. package/locales/zh_TW/setting.json +1 -1
  58. package/package.json +3 -1
  59. package/scripts/docsWorkflow/index.ts +5 -2
  60. package/scripts/docsWorkflow/toc.ts +2 -2
  61. package/scripts/i18nWorkflow/genDiff.ts +7 -8
  62. package/scripts/i18nWorkflow/utils.ts +0 -14
  63. package/scripts/readmeWorkflow/syncPluginIndex.ts +9 -11
  64. package/src/app/api/plugins/route.ts +2 -4
  65. package/src/app/api/proxy/route.ts +10 -0
  66. package/src/app/chat/features/ChatInput/ActionBar/Tools/ToolItem.tsx +3 -8
  67. package/src/app/chat/features/ChatInput/ActionBar/Tools/index.tsx +3 -3
  68. package/src/app/chat/features/Conversation/ChatList/Error/index.tsx +6 -0
  69. package/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx +1 -1
  70. package/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/Settings.tsx +7 -5
  71. package/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/index.tsx +2 -2
  72. package/src/app/chat/features/Conversation/ChatList/Plugins/Render/DefaultType/index.tsx +6 -4
  73. package/src/app/chat/features/Conversation/ChatList/Plugins/Render/index.tsx +2 -2
  74. package/src/app/chat/features/Migration/ExportConfigButton.tsx +1 -1
  75. package/src/app/market/features/AgentDetailContent/AgentInfo/index.tsx +1 -0
  76. package/src/app/market/features/AgentDetailContent/AgentInfo/style.ts +1 -9
  77. package/src/app/settings/common/Common.tsx +5 -7
  78. package/src/app/settings/features/UpgradeAlert.tsx +2 -2
  79. package/src/components/FileList/FileItem.tsx +4 -2
  80. package/src/components/HotKeys/index.tsx +5 -4
  81. package/src/const/plugin.ts +1 -0
  82. package/src/const/url.ts +1 -0
  83. package/src/const/version.ts +0 -3
  84. package/src/features/AgentSetting/AgentPlugin/AddPluginButton.tsx +2 -2
  85. package/src/features/AgentSetting/AgentPlugin/LocalPluginItem.tsx +19 -53
  86. package/src/features/AgentSetting/AgentPlugin/index.tsx +5 -11
  87. package/src/features/AgentSetting/store/initialState.ts +1 -1
  88. package/src/features/PluginDetailModal/APIs.tsx +44 -0
  89. package/src/features/PluginDetailModal/Meta.tsx +59 -0
  90. package/src/features/PluginDetailModal/index.tsx +79 -0
  91. package/src/features/PluginDevModal/PluginPreview.tsx +8 -10
  92. package/src/features/PluginDevModal/UrlManifestForm.tsx +131 -0
  93. package/src/features/PluginDevModal/index.tsx +31 -32
  94. package/src/features/PluginSettings/index.tsx +1 -1
  95. package/src/features/PluginStore/AddPluginButton.tsx +47 -0
  96. package/src/features/PluginStore/InstalledPluginList.tsx +54 -0
  97. package/src/features/PluginStore/OnlineList.tsx +95 -0
  98. package/src/features/PluginStore/PluginItem/Action.tsx +118 -0
  99. package/src/features/PluginStore/PluginItem/EditCustomPlugin.tsx +50 -0
  100. package/src/features/PluginStore/PluginItem/PluginTag.tsx +58 -0
  101. package/src/features/PluginStore/PluginItem/index.tsx +73 -0
  102. package/src/features/PluginStore/index.tsx +20 -92
  103. package/src/hooks/usePlatform.ts +15 -0
  104. package/src/locales/default/chat.ts +1 -1
  105. package/src/locales/default/common.ts +1 -1
  106. package/src/locales/default/error.ts +2 -0
  107. package/src/locales/default/plugin.ts +41 -4
  108. package/src/locales/default/setting.ts +1 -1
  109. package/src/services/__tests__/__snapshots__/plugin.test.ts.snap +154 -0
  110. package/src/services/__tests__/chat.test.ts +1 -1
  111. package/src/services/__tests__/global.test.ts +57 -0
  112. package/src/services/__tests__/openai/OpenAPI_V3.json +245 -0
  113. package/src/services/__tests__/openai/plugin.json +22 -0
  114. package/src/services/__tests__/plugin.test.ts +90 -1
  115. package/src/services/__tests__/share.test.ts +86 -0
  116. package/src/services/_url.ts +2 -0
  117. package/src/services/global.ts +15 -0
  118. package/src/services/plugin.ts +99 -15
  119. package/src/services/share.ts +34 -0
  120. package/src/store/chat/actions/enhance.test.ts +15 -15
  121. package/src/store/chat/actions/message.test.ts +3 -2
  122. package/src/store/chat/actions/plugin.test.ts +281 -0
  123. package/src/store/chat/actions/plugin.ts +22 -3
  124. package/src/store/chat/actions/share.ts +2 -2
  125. package/src/store/chat/actions/topic.test.ts +12 -4
  126. package/src/store/global/slices/common.ts +2 -2
  127. package/src/store/session/selectors.ts +1 -1
  128. package/src/store/session/slices/agent/selectors.ts +1 -1
  129. package/src/store/tool/helpers.ts +8 -1
  130. package/src/store/tool/slices/customPlugin/action.ts +4 -1
  131. package/src/store/tool/slices/plugin/selectors.test.ts +22 -3
  132. package/src/store/tool/slices/plugin/selectors.ts +24 -5
  133. package/src/store/tool/slices/store/selectors.test.ts +18 -1
  134. package/src/store/tool/slices/store/selectors.ts +14 -3
  135. package/src/styles/antdOverride.ts +7 -0
  136. package/src/types/openai/chat.ts +0 -1
  137. package/src/types/openai/plugin.ts +57 -0
  138. package/src/types/tool/index.ts +1 -2
  139. package/src/types/tool/plugin.ts +13 -1
  140. package/src/types/tool/tool.ts +1 -0
  141. package/src/types/translate.ts +0 -1
  142. package/src/utils/platform.ts +8 -5
  143. package/src/features/PluginDevModal/UrlModeForm.tsx +0 -98
  144. package/src/features/PluginSettingsModal/index.tsx +0 -59
  145. package/src/features/PluginStore/PluginItem.tsx +0 -82
  146. package/src/features/PluginStore/PluginSettings.tsx +0 -40
  147. package/src/services/latestVersion.ts +0 -11
  148. package/src/services/shareGPT.ts +0 -28
@@ -1,46 +1,23 @@
1
- import { Icon, Modal, SearchBar } from '@lobehub/ui';
2
- import { Button, Empty, Segmented } from 'antd';
3
- import { createStyles } from 'antd-style';
4
- import isEqual from 'fast-deep-equal';
5
- import { ServerCrash } from 'lucide-react';
6
- import { memo, useState } from 'react';
1
+ import { Modal } from '@lobehub/ui';
2
+ import { Segmented } from 'antd';
3
+ import { memo } from 'react';
7
4
  import { useTranslation } from 'react-i18next';
8
5
  import { Center, Flexbox } from 'react-layout-kit';
9
6
 
10
7
  import MobilePadding from '@/components/MobilePadding';
11
8
  import { useToolStore } from '@/store/tool';
12
- import { pluginStoreSelectors } from '@/store/tool/selectors';
13
9
 
14
- import Loading from './Loading';
15
- import PluginItem from './PluginItem';
16
-
17
- const useStyles = createStyles(({ css, token }) => ({
18
- header: css`
19
- color: ${token.colorTextDescription};
20
-
21
- > div {
22
- flex: 1;
23
- }
24
- `,
25
- }));
10
+ import InstalledPluginList from './InstalledPluginList';
11
+ import OnlineList from './OnlineList';
26
12
 
27
13
  interface PluginStoreProps {
28
14
  open?: boolean;
29
15
  setOpen: (open: boolean) => void;
30
16
  }
31
17
  export const PluginStore = memo<PluginStoreProps>(({ setOpen, open }) => {
32
- const [keywords, setKeywords] = useState<string>();
33
18
  const { t } = useTranslation('plugin');
34
- const { styles } = useStyles();
35
- const [listType, useFetchPluginList, installPlugins] = useToolStore((s) => [
36
- s.listType,
37
- s.useFetchPluginStore,
38
- s.installPlugins,
39
- ]);
40
19
 
41
- const pluginStoreList = useToolStore(pluginStoreSelectors.onlinePluginStore, isEqual);
42
- const { isLoading, error } = useFetchPluginList();
43
- const isEmpty = pluginStoreList.length === 0;
20
+ const [listType] = useToolStore((s) => [s.listType]);
44
21
 
45
22
  return (
46
23
  <Modal
@@ -55,69 +32,20 @@ export const PluginStore = memo<PluginStoreProps>(({ setOpen, open }) => {
55
32
  <MobilePadding>
56
33
  <Center>
57
34
  <Flexbox gap={24} width={'100%'}>
58
- <Flexbox align={'center'} gap={8} horizontal justify={'space-between'}>
59
- <Segmented
60
- block
61
- onChange={(v) => {
62
- useToolStore.setState({ listType: v as any });
63
- }}
64
- options={[
65
- { label: t('store.tabs.all'), value: 'all' },
66
- { label: t('store.tabs.installed'), value: 'installed' },
67
- ]}
68
- style={{ flex: 1 }}
69
- value={listType}
70
- />
71
- </Flexbox>
72
- {isLoading ? (
73
- <Loading />
74
- ) : isEmpty ? (
75
- <Center gap={12} padding={40}>
76
- {error ? (
77
- <>
78
- <Icon icon={ServerCrash} size={{ fontSize: 80 }} />
79
- {t('store.networkError')}
80
- </>
81
- ) : (
82
- <Empty
83
- description={t('store.empty')}
84
- image={Empty.PRESENTED_IMAGE_SIMPLE}
85
- ></Empty>
86
- )}
87
- </Center>
88
- ) : (
89
- <>
90
- <Flexbox className={styles.header} gap={8} horizontal>
91
- <SearchBar
92
- allowClear
93
- onChange={(e) => setKeywords(e.target.value)}
94
- placeholder={t('store.placeholder')}
95
- type={'block'}
96
- value={keywords}
97
- />
98
- {listType === 'all' && (
99
- <Button
100
- onClick={() => {
101
- installPlugins(pluginStoreList.map((item) => item.identifier));
102
- }}
103
- >
104
- {t('store.installAllPlugins')}
105
- </Button>
106
- )}
107
- </Flexbox>
108
-
109
- {pluginStoreList
110
- .filter((item) =>
111
- [item.meta.title, item.meta.description, item.author, ...(item.meta.tags || [])]
112
- .join('')
113
- .toLowerCase()
114
- .includes((keywords || '')?.toLowerCase()),
115
- )
116
- .map((item) => (
117
- <PluginItem key={item.identifier} {...item} />
118
- ))}
119
- </>
120
- )}
35
+ <Segmented
36
+ block
37
+ onChange={(v) => {
38
+ useToolStore.setState({ listType: v as any });
39
+ }}
40
+ options={[
41
+ { label: t('store.tabs.all'), value: 'all' },
42
+ { label: t('store.tabs.installed'), value: 'installed' },
43
+ ]}
44
+ style={{ flex: 1 }}
45
+ value={listType}
46
+ />
47
+
48
+ {listType === 'all' ? <OnlineList /> : <InstalledPluginList />}
121
49
  </Flexbox>
122
50
  </Center>
123
51
  </MobilePadding>
@@ -0,0 +1,15 @@
1
+ import { useRef } from 'react';
2
+
3
+ import { getBrowser, getPlatform } from '@/utils/platform';
4
+
5
+ export const usePlatform = () => {
6
+ const platform = useRef(getPlatform());
7
+ const browser = useRef(getBrowser());
8
+ return {
9
+ isApple: platform.current && ['Mac OS', 'iOS'].includes(platform.current),
10
+ isChrome: browser.current === 'Chrome',
11
+ isIOS: platform.current === 'iOS',
12
+ isMacOS: platform.current === 'Mac OS',
13
+ isSafari: browser.current === 'Safari',
14
+ };
15
+ };
@@ -2,7 +2,7 @@ export default {
2
2
  agentDefaultMessage:
3
3
  '你好,我是 **{{name}}**,你可以立即与我开始对话,也可以前往 [助手设置](/chat/settings#session={{id}}) 完善我的信息。',
4
4
  agentDefaultMessageWithSystemRole: '你好,我是 **{{name}}**,{{systemRole}},让我们开始对话吧!',
5
- backToBottom: '查看最新消息',
5
+ backToBottom: '跳转至当前',
6
6
  clearCurrentMessages: '清空当前会话消息',
7
7
  confirmClearCurrentMessages: '即将清空当前会话消息,清空后将无法找回,请确认你的操作',
8
8
  confirmRemoveSessionItemAlert: '即将删除该助手,删除后该将无法找回,请确认你的操作',
@@ -82,7 +82,7 @@ export default {
82
82
  temp: '临时',
83
83
  updateAgent: '更新助理信息',
84
84
  upgradeVersion: {
85
- action: '立即升级',
85
+ action: '升级',
86
86
  hasNew: '有可用更新',
87
87
  newVersion: '有新版本可用:{{version}}',
88
88
  },
@@ -29,6 +29,8 @@ export default {
29
29
  PluginSettingsInvalid: '该插件需要正确配置后才可以使用,请检查你的配置是否正确',
30
30
  PluginServerError:
31
31
  '插件服务端请求返回出错,请检查根据下面的报错信息检查你的插件描述文件、插件配置或服务端实现',
32
+ PluginGatewayError: '很抱歉,插件网关出现错误,请检查插件网关配置是否正确',
33
+ PluginOpenApiInitError: '很抱歉,OpenAPI 客户端初始化失败,请检查 OpenAPI 的配置信息是否正确',
32
34
 
33
35
  InvalidAccessCode: '密码不正确或为空,请输入正确的访问密码,或者添加自定义 OpenAI API Key',
34
36
  OpenAIBizError: '请求 OpenAI 服务出错,请根据以下信息排查或重试',
@@ -6,8 +6,25 @@ export default {
6
6
  on: '查看插件调用信息',
7
7
  response: '返回结果',
8
8
  },
9
+ detailModal: {
10
+ info: {
11
+ description: 'API 描述',
12
+ name: 'API 名称',
13
+ },
14
+ tabs: {
15
+ info: '插件能力',
16
+ manifest: '安装文件',
17
+ settings: '设置',
18
+ },
19
+ title: '插件详情',
20
+ },
9
21
  dev: {
10
22
  confirmDeleteDevPlugin: '即将删除该本地插件,删除后将无法找回,是否删除该插件?',
23
+ customParams: {
24
+ useProxy: {
25
+ label: '通过代理安装(如遇到跨域访问错误,可尝试开启该选项后重新安装)',
26
+ },
27
+ },
11
28
  deleteSuccess: '插件删除成功',
12
29
  manifest: {
13
30
  identifier: {
@@ -65,6 +82,10 @@ export default {
65
82
  metaConfig: '插件元信息配置',
66
83
  modalDesc:
67
84
  '添加自定义插件后,可用于插件开发验证,也可直接在会话中使用。插件开发请参考<1>开发文档↗</>',
85
+ openai: {
86
+ importUrl: '从 URL 链接导入',
87
+ schema: 'Schema',
88
+ },
68
89
  preview: {
69
90
  card: '预览插件展示效果',
70
91
  desc: '预览插件描述',
@@ -76,15 +97,23 @@ export default {
76
97
  manifest: '功能描述清单 (Manifest)',
77
98
  meta: '插件元信息',
78
99
  },
79
- title: '添加自定义插件',
100
+ title: {
101
+ create: '添加自定义插件',
102
+ edit: '编辑自定义插件',
103
+ },
104
+ type: {
105
+ lobe: 'LobeChat 插件',
106
+ openai: 'OpenAI 插件',
107
+ },
80
108
  update: '更新',
81
109
  updateSuccess: '插件设置更新成功',
82
110
  },
83
111
  error: {
84
112
  fetchError: '请求该 manifest 链接失败,请确保链接的有效性,并检查链接是否允许跨域访问',
85
113
  installError: '插件 {{name}} 安装失败',
86
- manifestInvalid: ' manifest 不符合规范,校验结果: \n\n {{error}}',
114
+ manifestInvalid: 'manifest 不符合规范,校验结果: \n\n {{error}}',
87
115
  noManifest: '描述文件不存在',
116
+ openAPIInvalid: 'OpenAPI 解析失败,错误: \n\n {{error}}',
88
117
  reinstallError: '插件 {{name}} 刷新失败',
89
118
  urlError: '该链接没有返回 JSON 格式的内容, 请确保是有效的链接',
90
119
  },
@@ -114,8 +143,17 @@ export default {
114
143
  title: '设置插件市场',
115
144
  },
116
145
  store: {
146
+ actions: {
147
+ confirmUninstall: '即将卸载该插件,卸载后将清除该插件配置,请确认你的操作',
148
+ detail: '详情',
149
+ install: '安装',
150
+ manifest: '编辑安装文件',
151
+ settings: '设置',
152
+ uninstall: '卸载',
153
+ },
154
+ communityPlugin: '三方社区',
155
+ customPlugin: '自定义',
117
156
  empty: '暂无已安装插件',
118
- install: '安装',
119
157
  installAllPlugins: '安装全部',
120
158
  networkError: '获取插件商店失败,请检测网络连接后重试',
121
159
  placeholder: '搜索插件名称介绍或关键词...',
@@ -125,6 +163,5 @@ export default {
125
163
  installed: '已安装',
126
164
  },
127
165
  title: '插件商店',
128
- uninstall: '卸载',
129
166
  },
130
167
  };
@@ -85,7 +85,7 @@ export default {
85
85
  waitingForMore: '更多模型正在 <1>计划接入</1> 中,敬请期待 ✨',
86
86
  },
87
87
  plugin: {
88
- addTooltip: '添加自定义插件',
88
+ addTooltip: '自定义插件',
89
89
  clearDeprecated: '移除无效插件',
90
90
  empty: '暂无已安装插件,欢迎前往 <1>插件商店</1> 探索',
91
91
  installStatus: {
@@ -0,0 +1,154 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`PluginService > can parse the OpenAI plugin 1`] = `
4
+ {
5
+ "api": [],
6
+ "homepage": "https://products.wolframalpha.com/api/commercial-termsofuse",
7
+ "identifier": "Wolfram",
8
+ "meta": {
9
+ "avatar": "https://www.wolframcdn.com/images/icons/Wolfram.png",
10
+ "description": "Access computation, math, curated knowledge & real-time data through Wolfram|Alpha and Wolfram Language.",
11
+ "title": "Wolfram",
12
+ },
13
+ "openapi": "https://www.wolframalpha.com/.well-known/apispec.json",
14
+ "settings": {
15
+ "properties": {
16
+ "apiAuthKey": {
17
+ "default": "18c4412dec6846eda6ec2fa95f144e1f",
18
+ "description": "API Key",
19
+ "format": "password",
20
+ "title": "API Key",
21
+ "type": "string",
22
+ },
23
+ },
24
+ "type": "object",
25
+ },
26
+ "type": "default",
27
+ "version": "1",
28
+ }
29
+ `;
30
+
31
+ exports[`PluginService > getPluginManifest > support OpenAPI manifest > should get plugin manifest 1`] = `
32
+ {
33
+ "$schema": "../node_modules/@lobehub/chat-plugin-sdk/schema.json",
34
+ "api": [
35
+ {
36
+ "description": "Read Course Segments",
37
+ "name": "read_course_segments_course_segments__get",
38
+ "parameters": {
39
+ "properties": {},
40
+ "type": "object",
41
+ },
42
+ },
43
+ {
44
+ "description": "Read Problem Set Item",
45
+ "name": "read_problem_set_item_problem_set__problem_set_id___question_number__get",
46
+ "parameters": {
47
+ "properties": {
48
+ "problem_set_id": {
49
+ "title": "Problem Set Id",
50
+ "type": "integer",
51
+ },
52
+ "question_number": {
53
+ "title": "Question Number",
54
+ "type": "integer",
55
+ },
56
+ },
57
+ "required": [
58
+ "problem_set_id",
59
+ "question_number",
60
+ ],
61
+ "type": "object",
62
+ },
63
+ },
64
+ {
65
+ "description": "Read Random Problem Set Items",
66
+ "name": "read_random_problem_set_items_problem_set_random__problem_set_id___n_items__get",
67
+ "parameters": {
68
+ "properties": {
69
+ "n_items": {
70
+ "title": "N Items",
71
+ "type": "integer",
72
+ },
73
+ "problem_set_id": {
74
+ "title": "Problem Set Id",
75
+ "type": "integer",
76
+ },
77
+ },
78
+ "required": [
79
+ "problem_set_id",
80
+ "n_items",
81
+ ],
82
+ "type": "object",
83
+ },
84
+ },
85
+ {
86
+ "description": "Read Range Of Problem Set Items",
87
+ "name": "read_range_of_problem_set_items_problem_set_range__problem_set_id___start___end__get",
88
+ "parameters": {
89
+ "properties": {
90
+ "end": {
91
+ "title": "End",
92
+ "type": "integer",
93
+ },
94
+ "problem_set_id": {
95
+ "title": "Problem Set Id",
96
+ "type": "integer",
97
+ },
98
+ "start": {
99
+ "title": "Start",
100
+ "type": "integer",
101
+ },
102
+ },
103
+ "required": [
104
+ "problem_set_id",
105
+ "start",
106
+ "end",
107
+ ],
108
+ "type": "object",
109
+ },
110
+ },
111
+ {
112
+ "description": "Read User Id",
113
+ "name": "read_user_id_user__get",
114
+ "parameters": {
115
+ "properties": {},
116
+ "type": "object",
117
+ },
118
+ },
119
+ ],
120
+ "author": "LobeHub",
121
+ "createAt": "2023-08-12",
122
+ "homepage": "https://github.com/lobehub/chat-plugin-realtime-weather",
123
+ "identifier": "realtime-weather",
124
+ "meta": {
125
+ "avatar": "🌈",
126
+ "description": "Get realtime weather information",
127
+ "tags": [
128
+ "weather",
129
+ "realtime",
130
+ ],
131
+ "title": "Realtime Weather",
132
+ },
133
+ "openapi": "http://fake-url.com/openapiUrl.json",
134
+ "settings": {
135
+ "properties": {
136
+ "HTTPBearer": {
137
+ "description": "HTTPBearer Bearer token",
138
+ "format": "password",
139
+ "title": "HTTPBearer",
140
+ "type": "string",
141
+ },
142
+ },
143
+ "required": [
144
+ "HTTPBearer",
145
+ ],
146
+ "type": "object",
147
+ },
148
+ "ui": {
149
+ "height": 310,
150
+ "url": "https://realtime-weather.chat-plugin.lobehub.com/iframe",
151
+ },
152
+ "version": "1",
153
+ }
154
+ `;
@@ -57,7 +57,7 @@ describe('ChatService', () => {
57
57
 
58
58
  expect(getChatCompletionSpy).toHaveBeenCalledWith(
59
59
  expect.objectContaining({
60
- functions: expect.arrayContaining([{ name: 'plugin1____api1____default' }]),
60
+ functions: expect.arrayContaining([{ name: 'plugin1____api1' }]),
61
61
  messages: expect.anything(),
62
62
  }),
63
63
  undefined,
@@ -0,0 +1,57 @@
1
+ import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
2
+
3
+ import { globalService } from '../global';
4
+
5
+ global.fetch = vi.fn();
6
+
7
+ beforeEach(() => {
8
+ vi.clearAllMocks();
9
+ });
10
+
11
+ describe('GlobalService', () => {
12
+ it('should return the latest version when fetch is successful', async () => {
13
+ // Arrange
14
+ const mockVersion = '1.0.0';
15
+ (fetch as Mock).mockResolvedValue({
16
+ json: () => Promise.resolve({ 'dist-tags': { latest: mockVersion } }),
17
+ });
18
+
19
+ // Act
20
+ const version = await globalService.getLatestVersion();
21
+
22
+ // Assert
23
+ expect(fetch).toHaveBeenCalledWith('https://registry.npmmirror.com/@lobehub/chat');
24
+ expect(version).toBe(mockVersion);
25
+ });
26
+
27
+ it('should return undefined if the latest version is not found in the response', async () => {
28
+ // Arrange
29
+ (fetch as Mock).mockResolvedValue({
30
+ json: () => Promise.resolve({}),
31
+ });
32
+
33
+ // Act
34
+ const version = await globalService.getLatestVersion();
35
+
36
+ // Assert
37
+ expect(version).toBeUndefined();
38
+ });
39
+
40
+ it('should throw an error when the fetch call fails', async () => {
41
+ // Arrange
42
+ (fetch as Mock).mockRejectedValue(new Error('Network error'));
43
+
44
+ // Act & Assert
45
+ await expect(globalService.getLatestVersion()).rejects.toThrow('Network error');
46
+ });
47
+
48
+ it('should handle non-JSON responses gracefully', async () => {
49
+ // Arrange
50
+ (fetch as Mock).mockResolvedValue({
51
+ json: () => Promise.reject(new SyntaxError('Unexpected token < in JSON at position 0')),
52
+ });
53
+
54
+ // Act & Assert
55
+ await expect(globalService.getLatestVersion()).rejects.toThrow(SyntaxError);
56
+ });
57
+ });