@opentiny/tiny-robot-cli 0.5.2-alpha.15 → 0.5.2-alpha.17

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 (51) hide show
  1. package/README.md +1 -38
  2. package/bin/commands/add.js +268 -552
  3. package/bin/utils.js +44 -144
  4. package/package.json +3 -5
  5. package/templates/basic/.env.example +0 -8
  6. package/templates/basic/README.md +22 -53
  7. package/templates/basic/index.html +2 -2
  8. package/templates/basic/package.json +16 -12
  9. package/templates/basic/public/modelcontextprotocol.png +0 -0
  10. package/templates/basic/src/App.vue +119 -112
  11. package/templates/basic/src/components/ChatList.vue +82 -0
  12. package/templates/basic/src/components/ChatSender.vue +125 -0
  13. package/templates/basic/src/components/ConversationHistory.vue +136 -0
  14. package/templates/basic/src/components/HistoryDrawerButton.vue +43 -0
  15. package/templates/basic/src/components/McpServerPickerButton.vue +278 -0
  16. package/templates/basic/src/components/ThemeToggleButton.vue +44 -0
  17. package/templates/basic/src/components/icons/IconDeepThink.vue +29 -0
  18. package/templates/basic/src/components/icons/IconModelAliyunBailian.vue +51 -0
  19. package/templates/basic/src/components/icons/IconModelDeepseek.vue +29 -0
  20. package/templates/basic/src/components/icons/IconMoon.vue +29 -0
  21. package/templates/basic/src/components/icons/IconPlugin.vue +29 -0
  22. package/templates/basic/src/components/icons/IconSun.vue +35 -0
  23. package/templates/basic/src/components/icons/IconWebSearch.vue +36 -0
  24. package/templates/basic/src/components/icons/index.ts +7 -0
  25. package/templates/basic/src/composables/useChat.ts +129 -0
  26. package/templates/basic/src/composables/useMcp.ts +170 -0
  27. package/templates/basic/src/composables/useModel.ts +82 -0
  28. package/templates/basic/src/main.ts +2 -2
  29. package/templates/basic/src/mcpServers.ts +40 -0
  30. package/templates/basic/src/models.ts +81 -0
  31. package/templates/basic/tsconfig.app.json +5 -2
  32. package/templates/basic/tsconfig.node.json +6 -3
  33. package/templates/basic/vite.config.ts +1 -6
  34. package/templates/chat/.env.example +0 -9
  35. package/templates/chat/src/TinyRobotChat.vue +27 -88
  36. package/templates/basic/public/favicon.svg +0 -1
  37. package/templates/basic/public/icons.svg +0 -24
  38. package/templates/chat/README.md +0 -46
  39. package/templates/chat/index.html +0 -12
  40. package/templates/chat/package.json +0 -28
  41. package/templates/chat/src/components/ComposerTools.vue +0 -99
  42. package/templates/chat/src/components/WindowHeader.vue +0 -192
  43. package/templates/chat/src/composables/useWindow.ts +0 -83
  44. package/templates/chat/src/config/chat-runtime.ts +0 -82
  45. package/templates/chat/src/config/chat-ui.ts +0 -290
  46. package/templates/chat/src/index.css +0 -116
  47. package/templates/chat/src/main.ts +0 -7
  48. package/templates/chat/tsconfig.app.json +0 -13
  49. package/templates/chat/tsconfig.json +0 -7
  50. package/templates/chat/tsconfig.node.json +0 -19
  51. package/templates/chat/vite.config.ts +0 -16
@@ -1,82 +0,0 @@
1
- import type { ChatMcpServers, ChatProviderConfig } from '@opentiny/tiny-robot-chat'
2
- import { IconBailian, IconDeepseek } from '@opentiny/tiny-robot-svgs'
3
-
4
- export interface McpExample {
5
- id: string
6
- title: string
7
- request: string
8
- }
9
-
10
- export const mcpExamples: McpExample[] = [
11
- { id: 'weather', title: '查询北京天气', request: '查询北京今天的天气,并给出出行建议' },
12
- { id: 'coffee', title: '查询附近咖啡店', request: '查询我附近的咖啡店,并按距离排序' },
13
- { id: 'exchange-rate', title: '获取当前汇率', request: '查询人民币兑美元的当前汇率' },
14
- ]
15
-
16
- export const mcpServers: ChatMcpServers = [
17
- {
18
- id: 'amap-maps',
19
- name: '高德地图',
20
- description: '覆盖地图、导航、地理编码、天气、路径规划、距离测量、关键词搜索和周边搜索等地理信息服务。',
21
- baseUrl: import.meta.env.VITE_AMAP_MCP_URL?.trim() || 'https://dashscope.aliyuncs.com/api/v1/mcps/amap-maps/mcp',
22
- icon: 'https://img.alicdn.com/imgextra/i4/O1CN01iPPabT1EGRN6uatHP_!!6000000000324-0-tps-512-512.jpg',
23
- headers: import.meta.env.VITE_ALIYUN_DASHSCOPE_KEY?.trim()
24
- ? { Authorization: `Bearer ${import.meta.env.VITE_ALIYUN_DASHSCOPE_KEY.trim()}` }
25
- : undefined,
26
- },
27
- {
28
- id: 'model-context-protocol-mcp',
29
- name: 'Model Context Protocol MCP',
30
- description: 'MCP Server',
31
- baseUrl: '/modelcontextprotocol-mcp',
32
- installed: true,
33
- },
34
- ]
35
-
36
- export const modelProviders: ChatProviderConfig[] = [
37
- {
38
- type: 'qwen',
39
- label: 'DashScope',
40
- apiUrl: import.meta.env.VITE_QWEN_API_URL?.trim() || undefined,
41
- apiKey: import.meta.env.VITE_ALIYUN_DASHSCOPE_KEY?.trim(),
42
- models: [
43
- {
44
- id: 'qwen3.7-flash',
45
- label: 'Qwen3.7 Flash',
46
- icon: IconBailian,
47
- capabilities: { thinking: true, search: true },
48
- },
49
- {
50
- id: 'qwen3.7-plus',
51
- label: 'Qwen3.7 Plus',
52
- icon: IconBailian,
53
- capabilities: { thinking: true, search: true },
54
- },
55
- {
56
- id: 'qwen3.7-max',
57
- label: 'Qwen3.7 Max',
58
- icon: IconBailian,
59
- capabilities: { thinking: true, search: true },
60
- },
61
- ],
62
- },
63
- {
64
- type: 'deepseek',
65
- apiUrl: import.meta.env.VITE_DEEPSEEK_API_URL?.trim() || undefined,
66
- apiKey: import.meta.env.VITE_DEEPSEEK_API_KEY?.trim(),
67
- models: [
68
- {
69
- id: 'deepseek-v4-flash',
70
- label: 'DeepSeek V4 Flash',
71
- icon: IconDeepseek,
72
- capabilities: { thinking: true },
73
- },
74
- {
75
- id: 'deepseek-v4-pro',
76
- label: 'DeepSeek V4 Pro',
77
- icon: IconDeepseek,
78
- capabilities: { thinking: true },
79
- },
80
- ],
81
- },
82
- ]
@@ -1,290 +0,0 @@
1
- import type { LayoutFloatingOptions } from '@opentiny/tiny-robot'
2
- import type { ChatSenderOptions, ChatUIOptions } from '@opentiny/tiny-robot-chat'
3
- import type { TemplateItem } from '@opentiny/tiny-robot'
4
- import { IconAi, IconEdit, IconHistory, IconNewSession, IconSparkles, IconUser } from '@opentiny/tiny-robot-svgs'
5
- import { h, type CSSProperties } from 'vue'
6
-
7
- export interface ChatUiConfigOptions {
8
- floatingOptions: Readonly<LayoutFloatingOptions>
9
- templateExtensions: NonNullable<ChatSenderOptions['extensions']>
10
- }
11
-
12
- export interface ChatMenuItem {
13
- id: string
14
- title: string
15
- icon: unknown
16
- action: 'mcp' | 'template' | 'history' | 'new-session' | 'mode'
17
- }
18
-
19
- export const composerMenus: ChatMenuItem[] = [
20
- { id: 'quick-query', title: '常用查询', icon: IconSparkles, action: 'mcp' },
21
- { id: 'templates', title: '模板', icon: IconEdit, action: 'template' },
22
- ]
23
-
24
- export const windowMenus: ChatMenuItem[] = [
25
- { id: 'new-session', title: '新会话', icon: IconNewSession, action: 'new-session' },
26
- { id: 'history', title: '历史会话', icon: IconHistory, action: 'history' },
27
- { id: 'mode', title: '窗口模式', icon: IconSparkles, action: 'mode' },
28
- ]
29
-
30
- export interface PromptItemData {
31
- label: string
32
- description: string
33
- emoji: string
34
- badge?: string
35
- }
36
-
37
- export const PROMPT_ITEMS_DATA: PromptItemData[] = [
38
- {
39
- label: '日常助理场景',
40
- description: '今天需要我帮你安排日程,规划旅行,还是起草一封邮件?',
41
- emoji: '🧠',
42
- badge: 'NEW',
43
- },
44
- {
45
- label: '学习/知识型场景',
46
- description: '有什么想了解的吗?可以是"Vue3 和 React 的区别"!',
47
- emoji: '🤔',
48
- },
49
- {
50
- label: '创意生成场景',
51
- description: '想写段文案、起个名字,还是来点灵感?',
52
- emoji: '✨',
53
- },
54
- {
55
- label: 'MCP 工具调用',
56
- description: '搜索:北京天气(输入「搜索」「MCP」「工具」等关键词可触发模拟 MCP 工具调用)',
57
- emoji: '🔧',
58
- },
59
- ]
60
-
61
- export const prompts = PROMPT_ITEMS_DATA
62
-
63
- export interface TemplateSuggestionItem {
64
- id: string
65
- text: string
66
- template: TemplateItem[]
67
- }
68
-
69
- export const templateSuggestions: TemplateSuggestionItem[] = [
70
- {
71
- id: 'write',
72
- text: '帮我写作',
73
- template: [
74
- { id: 'write-prefix', type: 'text', content: '请帮我撰写一篇' },
75
- {
76
- id: 'write-kind',
77
- type: 'select',
78
- content: '',
79
- placeholder: '文章类型',
80
- options: [
81
- { label: '公告', value: '公告' },
82
- { label: '方案', value: '方案' },
83
- { label: '邮件', value: '邮件' },
84
- ],
85
- },
86
- { id: 'write-topic-prefix', type: 'text', content: ',主题是' },
87
- { id: 'write-topic', type: 'block', content: '主题' },
88
- { id: 'write-tone-prefix', type: 'text', content: ',语气是' },
89
- {
90
- id: 'write-tone',
91
- type: 'select',
92
- content: '',
93
- placeholder: '语气类型',
94
- options: [
95
- { label: '正式', value: '正式' },
96
- { label: '轻松', value: '轻松' },
97
- { label: '专业', value: '专业' },
98
- ],
99
- },
100
- { id: 'write-description-prefix', type: 'text', content: ',具体内容是' },
101
- { id: 'write-description', type: 'block', content: '详细描述' },
102
- ],
103
- },
104
- {
105
- id: 'translate',
106
- text: '翻译',
107
- template: [
108
- { id: 'translate-source-prefix', type: 'text', content: '请将以下' },
109
- {
110
- id: 'translate-source-language',
111
- type: 'select',
112
- content: '',
113
- placeholder: '源语言',
114
- options: [
115
- { label: '中文', value: '中文' },
116
- { label: '英文', value: '英文' },
117
- { label: '日语', value: '日语' },
118
- ],
119
- },
120
- { id: 'translate-content-prefix', type: 'text', content: '内容翻译成' },
121
- {
122
- id: 'translate-target-language',
123
- type: 'select',
124
- content: '',
125
- placeholder: '目标语言',
126
- options: [
127
- { label: '中文', value: '中文' },
128
- { label: '英文', value: '英文' },
129
- { label: '日语', value: '日语' },
130
- ],
131
- },
132
- { id: 'translate-content-suffix', type: 'text', content: ',内容是' },
133
- { id: 'translate-content', type: 'block', content: '需要翻译的内容' },
134
- ],
135
- },
136
- {
137
- id: 'code-review',
138
- text: '代码审查',
139
- template: [
140
- { id: 'code-review-prefix', type: 'text', content: '请帮我审查以下' },
141
- {
142
- id: 'code-review-language',
143
- type: 'select',
144
- content: '',
145
- placeholder: '代码语言',
146
- options: [
147
- { label: 'JavaScript', value: 'JavaScript' },
148
- { label: 'TypeScript', value: 'TypeScript' },
149
- { label: 'Python', value: 'Python' },
150
- ],
151
- },
152
- { id: 'code-review-focus-prefix', type: 'text', content: '代码,关注' },
153
- {
154
- id: 'code-review-focus',
155
- type: 'select',
156
- content: '',
157
- placeholder: '关注方向',
158
- options: [
159
- { label: '性能', value: '性能' },
160
- { label: '安全', value: '安全' },
161
- { label: '可读性', value: '可读性' },
162
- ],
163
- },
164
- { id: 'code-review-content-prefix', type: 'text', content: '方面,代码如下:' },
165
- { id: 'code-review-content', type: 'block', content: '代码内容' },
166
- ],
167
- },
168
- {
169
- id: 'email-compose',
170
- text: '写邮件',
171
- template: [
172
- { id: 'email-compose-prefix', type: 'text', content: '请帮我起草一封' },
173
- {
174
- id: 'email-compose-type',
175
- type: 'select',
176
- content: '',
177
- placeholder: '邮件类型',
178
- options: [
179
- { label: '正式', value: '正式' },
180
- { label: '非正式', value: '非正式' },
181
- ],
182
- },
183
- { id: 'email-compose-recipient-prefix', type: 'text', content: '邮件,发送给' },
184
- { id: 'email-compose-recipient', type: 'block', content: '收件人角色' },
185
- { id: 'email-compose-subject-prefix', type: 'text', content: ',主题是' },
186
- { id: 'email-compose-subject', type: 'block', content: '邮件主题' },
187
- { id: 'email-compose-content-prefix', type: 'text', content: ',内容是关于' },
188
- { id: 'email-compose-content', type: 'block', content: '邮件内容' },
189
- ],
190
- },
191
- {
192
- id: 'interview-questions',
193
- text: '面试问题',
194
- template: [
195
- { id: 'interview-questions-prefix', type: 'text', content: '请为' },
196
- { id: 'interview-questions-role', type: 'block', content: '岗位名称' },
197
- { id: 'interview-questions-skill-prefix', type: 'text', content: '岗位,针对' },
198
- { id: 'interview-questions-skill', type: 'block', content: '技能领域' },
199
- { id: 'interview-questions-count-prefix', type: 'text', content: '方向,设计' },
200
- {
201
- id: 'interview-questions-count',
202
- type: 'select',
203
- content: '',
204
- placeholder: '问题数量',
205
- options: [
206
- { label: '3', value: '3' },
207
- { label: '5', value: '5' },
208
- { label: '10', value: '10' },
209
- ],
210
- },
211
- { id: 'interview-questions-difficulty-prefix', type: 'text', content: '个难度为' },
212
- {
213
- id: 'interview-questions-difficulty',
214
- type: 'select',
215
- content: '',
216
- placeholder: '岗位难度',
217
- options: [
218
- { label: '简单', value: '简单' },
219
- { label: '中等', value: '中等' },
220
- { label: '困难', value: '困难' },
221
- ],
222
- },
223
- { id: 'interview-questions-suffix', type: 'text', content: '的面试问题' },
224
- ],
225
- },
226
- ]
227
-
228
- export interface TemplateCategory {
229
- id: string
230
- title: string
231
- items: TemplateSuggestionItem[]
232
- }
233
-
234
- export const templateCategories: TemplateCategory[] = [
235
- { id: 'writing', title: '写作表达', items: [templateSuggestions[0]] },
236
- { id: 'language', title: '语言处理', items: [templateSuggestions[1]] },
237
- { id: 'engineering', title: '研发协作', items: [templateSuggestions[2]] },
238
- { id: 'communication', title: '工作沟通', items: [templateSuggestions[3]] },
239
- { id: 'growth', title: '人才发展', items: [templateSuggestions[4]] },
240
- ]
241
-
242
- const promptItems = PROMPT_ITEMS_DATA.map((item) => ({
243
- ...item,
244
- icon: h('span', { style: { fontSize: '18px' } as CSSProperties }, item.emoji) as never,
245
- }))
246
-
247
- export function createChatUi(options: ChatUiConfigOptions): ChatUIOptions {
248
- return {
249
- history: false,
250
- welcome: {
251
- title: 'TinyRobot',
252
- description: '您好,我是TinyRobot,您专属的 AI 智能专家',
253
- icon: h(IconAi, { style: { fontSize: '48px' } }) as never,
254
- },
255
- prompts: { items: promptItems, wrap: true, itemClass: 'prompt-item' },
256
- bubble: {
257
- autoScroll: true,
258
- bubbleList: {
259
- roleConfigs: {
260
- assistant: { placement: 'start', avatar: h(IconAi, { style: { fontSize: '32px' } }) as never },
261
- user: { placement: 'end', avatar: h(IconUser, { style: { fontSize: '32px' } }) as never },
262
- system: { hidden: true },
263
- },
264
- },
265
- },
266
- model: { appendTo: '.chat-add-window' },
267
- layout: {
268
- heightMode: 'parent',
269
- leftAside: false,
270
- rightAside: {
271
- mode: 'drawer',
272
- width: 400,
273
- defaultOpen: false,
274
- },
275
- surface: { mode: 'floating', floatingOptions: options.floatingOptions },
276
- emptyState: 'center',
277
- composer: { welcome: 'footer' },
278
- contentMaxWidth: 1280,
279
- panelPadding: 0,
280
- panelGap: 0,
281
- } as ChatUIOptions['layout'],
282
- sender: {
283
- mode: 'multiple',
284
- clearable: true,
285
- showWordLimit: true,
286
- maxLength: 2000,
287
- extensions: options.templateExtensions,
288
- },
289
- }
290
- }
@@ -1,116 +0,0 @@
1
- :root {
2
- font-family:
3
- Inter,
4
- -apple-system,
5
- BlinkMacSystemFont,
6
- 'Segoe UI',
7
- sans-serif;
8
- color: #1f2329;
9
- }
10
- * {
11
- box-sizing: border-box;
12
- }
13
- html,
14
- body,
15
- #app {
16
- width: 100%;
17
- height: 100%;
18
- min-height: 0;
19
- margin: 0;
20
- }
21
- body {
22
- overflow: hidden;
23
- }
24
- .chat-add-app {
25
- position: relative;
26
- container-type: inline-size;
27
- display: flex;
28
- width: 100%;
29
- height: 100%;
30
- min-width: 0;
31
- min-height: 0;
32
- }
33
- .chat-add-launcher {
34
- position: fixed;
35
- right: 24px;
36
- bottom: 24px;
37
- z-index: var(--tr-z-index-popover, 1000);
38
- display: inline-flex;
39
- align-items: center;
40
- justify-content: center;
41
- width: 56px;
42
- height: 56px;
43
- padding: 0;
44
- border: 0;
45
- border-radius: 50%;
46
- background: var(--tr-color-primary);
47
- color: #fff;
48
- box-shadow: 0 8px 24px rgb(0 0 0 / 20%);
49
- cursor: pointer;
50
- }
51
- .chat-add-launcher:hover {
52
- background: var(--tr-color-primary-hover);
53
- }
54
- .chat-add-launcher:focus-visible {
55
- outline: 2px solid var(--tr-color-primary);
56
- outline-offset: 3px;
57
- }
58
- .chat-add-window {
59
- container-type: inline-size;
60
- --tr-layout-bg-default: var(--tr-container-bg-default);
61
- --tr-chat-ui-header-bg: var(--tr-container-bg-default);
62
- --tr-chat-ui-main-bg: var(--tr-page-bg-default);
63
- --tr-chat-ui-footer-bg: var(--tr-page-bg-default);
64
- --tr-suggestion-popover-width: min(440px, calc(100cqw - 16px));
65
- width: 100%;
66
- min-width: 0;
67
- min-height: 0;
68
- }
69
- .chat-add-window .tr-welcome {
70
- box-sizing: border-box;
71
- width: 100%;
72
- padding: 24px 24px 0;
73
- }
74
- .chat-add-window .tr-welcome__title-wrapper {
75
- display: flex;
76
- align-items: center;
77
- justify-content: center;
78
- }
79
- .chat-add-window .tr-prompts {
80
- --tr-prompts-gap: 16px;
81
- box-sizing: border-box;
82
- width: 100%;
83
- padding: 16px 24px;
84
- }
85
- .chat-add-window .prompt-item {
86
- flex: 0 0 calc((100% - 16px) / 2);
87
- box-sizing: border-box;
88
- min-width: 0;
89
- }
90
- .chat-add-window--floating {
91
- border-radius: var(--tr-layout-floating-radius);
92
- box-shadow: var(--tr-layout-floating-shadow);
93
- overflow: hidden;
94
- }
95
- .chat-add-window--fullscreen {
96
- border-radius: 0;
97
- box-shadow: none;
98
- }
99
- @container (max-width: 519px) {
100
- .chat-add-launcher {
101
- right: 16px;
102
- bottom: 16px;
103
- }
104
- .chat-add-window .prompt-item {
105
- flex-basis: 100%;
106
- }
107
- .chat-add-window .tr-welcome {
108
- padding-inline: 12px;
109
- }
110
- .chat-add-window .tr-prompts {
111
- padding-inline: 12px;
112
- }
113
- .chat-add-window .tr-bubble__avatar {
114
- display: none;
115
- }
116
- }
@@ -1,7 +0,0 @@
1
- import { createApp } from 'vue'
2
- import '@opentiny/tiny-robot/dist/style.css'
3
- import '@opentiny/tiny-robot-chat/dist/style.css'
4
- import './index.css'
5
- import TinyRobotChat from './TinyRobotChat.vue'
6
-
7
- createApp(TinyRobotChat).mount('#app')
@@ -1,13 +0,0 @@
1
- {
2
- "extends": "@vue/tsconfig/tsconfig.dom.json",
3
- "compilerOptions": {
4
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
5
- "types": ["vite/client"],
6
- "allowArbitraryExtensions": true,
7
- "noUnusedLocals": true,
8
- "noUnusedParameters": true,
9
- "erasableSyntaxOnly": true,
10
- "noFallthroughCasesInSwitch": true
11
- },
12
- "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
13
- }
@@ -1,7 +0,0 @@
1
- {
2
- "files": [],
3
- "references": [
4
- { "path": "./tsconfig.app.json" },
5
- { "path": "./tsconfig.node.json" }
6
- ]
7
- }
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
- "target": "es2023",
5
- "lib": ["ES2023"],
6
- "types": ["node"],
7
- "skipLibCheck": true,
8
- "module": "nodenext",
9
- "allowImportingTsExtensions": true,
10
- "verbatimModuleSyntax": true,
11
- "moduleDetection": "force",
12
- "noEmit": true,
13
- "noUnusedLocals": true,
14
- "noUnusedParameters": true,
15
- "erasableSyntaxOnly": true,
16
- "noFallthroughCasesInSwitch": true
17
- },
18
- "include": ["vite.config.ts"]
19
- }
@@ -1,16 +0,0 @@
1
- import { defineConfig } from 'vite'
2
- import vue from '@vitejs/plugin-vue'
3
-
4
- // https://vite.dev/config/
5
- export default defineConfig({
6
- plugins: [vue()],
7
- server: {
8
- proxy: {
9
- '/modelcontextprotocol-mcp': {
10
- target: 'https://modelcontextprotocol.io/mcp',
11
- changeOrigin: true,
12
- rewrite: (path) => path.replace(/^\/modelcontextprotocol-mcp/, ''),
13
- },
14
- },
15
- },
16
- })