@opentiny/tiny-robot-cli 0.5.2-alpha.13 → 0.5.2-alpha.14

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 (48) hide show
  1. package/README.md +32 -5
  2. package/bin/commands/add.js +589 -198
  3. package/bin/utils.js +139 -47
  4. package/package.json +4 -3
  5. package/templates/basic/.env.example +8 -0
  6. package/templates/basic/README.md +53 -22
  7. package/templates/basic/index.html +2 -2
  8. package/templates/basic/package.json +12 -16
  9. package/templates/basic/public/favicon.svg +1 -0
  10. package/templates/basic/public/icons.svg +24 -0
  11. package/templates/basic/src/App.vue +112 -119
  12. package/templates/basic/src/main.ts +2 -2
  13. package/templates/basic/tsconfig.app.json +2 -5
  14. package/templates/basic/tsconfig.node.json +3 -6
  15. package/templates/basic/vite.config.ts +6 -1
  16. package/templates/chat/.env.example +8 -0
  17. package/templates/chat/README.md +21 -13
  18. package/templates/chat/package.json +5 -5
  19. package/templates/chat/src/TinyRobotChat.vue +52 -132
  20. package/templates/chat/src/components/ComposerTools.vue +99 -0
  21. package/templates/chat/src/{tiny-robot-chat/components → components}/WindowHeader.vue +1 -1
  22. package/templates/chat/src/{tiny-robot-chat/composables → composables}/useWindow.ts +8 -18
  23. package/templates/chat/src/config/chat-runtime.ts +82 -0
  24. package/templates/chat/src/{tiny-robot-chat/config → config}/chat-ui.ts +22 -4
  25. package/templates/chat/src/index.css +116 -0
  26. package/templates/chat/src/main.ts +3 -0
  27. package/templates/basic/public/modelcontextprotocol.png +0 -0
  28. package/templates/basic/src/components/ChatList.vue +0 -82
  29. package/templates/basic/src/components/ChatSender.vue +0 -125
  30. package/templates/basic/src/components/ConversationHistory.vue +0 -136
  31. package/templates/basic/src/components/HistoryDrawerButton.vue +0 -43
  32. package/templates/basic/src/components/McpServerPickerButton.vue +0 -278
  33. package/templates/basic/src/components/ThemeToggleButton.vue +0 -44
  34. package/templates/basic/src/components/icons/IconDeepThink.vue +0 -29
  35. package/templates/basic/src/components/icons/IconModelAliyunBailian.vue +0 -51
  36. package/templates/basic/src/components/icons/IconModelDeepseek.vue +0 -29
  37. package/templates/basic/src/components/icons/IconMoon.vue +0 -29
  38. package/templates/basic/src/components/icons/IconPlugin.vue +0 -29
  39. package/templates/basic/src/components/icons/IconSun.vue +0 -35
  40. package/templates/basic/src/components/icons/IconWebSearch.vue +0 -36
  41. package/templates/basic/src/components/icons/index.ts +0 -7
  42. package/templates/basic/src/composables/useChat.ts +0 -129
  43. package/templates/basic/src/composables/useMcp.ts +0 -170
  44. package/templates/basic/src/composables/useModel.ts +0 -82
  45. package/templates/basic/src/mcpServers.ts +0 -40
  46. package/templates/basic/src/models.ts +0 -81
  47. package/templates/chat/src/tiny-robot-chat/components/ComposerTools.vue +0 -72
  48. package/templates/chat/src/tiny-robot-chat/config/chat-runtime.ts +0 -26
@@ -1,35 +0,0 @@
1
- <script setup lang="ts">
2
- withDefaults(
3
- defineProps<{
4
- size?: number
5
- }>(),
6
- {
7
- size: 24,
8
- },
9
- )
10
- </script>
11
-
12
- <template>
13
- <svg
14
- xmlns="http://www.w3.org/2000/svg"
15
- :width="size"
16
- :height="size"
17
- viewBox="0 0 24 24"
18
- fill="none"
19
- stroke="currentColor"
20
- stroke-width="2"
21
- stroke-linecap="round"
22
- stroke-linejoin="round"
23
- class="lucide lucide-sun-icon lucide-sun"
24
- >
25
- <circle cx="12" cy="12" r="4" />
26
- <path d="M12 2v2" />
27
- <path d="M12 20v2" />
28
- <path d="m4.93 4.93 1.41 1.41" />
29
- <path d="m17.66 17.66 1.41 1.41" />
30
- <path d="M2 12h2" />
31
- <path d="M20 12h2" />
32
- <path d="m6.34 17.66-1.41 1.41" />
33
- <path d="m19.07 4.93-1.41 1.41" />
34
- </svg>
35
- </template>
@@ -1,36 +0,0 @@
1
- <script setup lang="ts">
2
- withDefaults(
3
- defineProps<{
4
- size?: number
5
- }>(),
6
- {
7
- size: 24,
8
- },
9
- )
10
- </script>
11
-
12
- <template>
13
- <svg
14
- xmlns="http://www.w3.org/2000/svg"
15
- xmlns:xlink="http://www.w3.org/1999/xlink"
16
- :width="size"
17
- :height="size"
18
- viewBox="0 0 16 16"
19
- fill="none"
20
- >
21
- <defs>
22
- <clipPath id="clip98_50741">
23
- <rect id="联网搜索" width="16.000000" height="16.000000" fill="white" fill-opacity="0" />
24
- </clipPath>
25
- </defs>
26
- <g clip-path="url(#clip98_50741)">
27
- <path
28
- id="形状"
29
- d="M8 2C4.67 2 2 4.68 2 8C2 11.31 4.67 14 8 14C11.31 14 14 11.31 14 8C14 4.68 11.31 2 8 2ZM8 1C11.86 1 15 4.13 15 8C15 11.86 11.86 15 8 15C4.12 15 1 11.86 1 8C1 4.13 4.12 1 8 1ZM8 2C6.71 2 5.5 4.65 5.5 8C5.5 11.34 6.71 14 8 14C9.27 14 10.5 11.34 10.5 8C10.5 4.65 9.27 2 8 2ZM8 1C10.03 1 11.5 4.16 11.5 8C11.5 11.83 10.03 15 8 15C5.95 15 4.5 11.83 4.5 8C4.5 4.16 5.95 1 8 1ZM14.5 7.5C14.77 7.5 15 7.71 15 8C15 8.27 14.77 8.5 14.5 8.5L1.5 8.5C1.21 8.5 1 8.27 1 8C1 7.71 1.21 7.5 1.5 7.5L14.5 7.5Z"
30
- fill="currentColor"
31
- fill-opacity="1.000000"
32
- fill-rule="nonzero"
33
- />
34
- </g>
35
- </svg>
36
- </template>
@@ -1,7 +0,0 @@
1
- export { default as IconDeepThink } from './IconDeepThink.vue'
2
- export { default as IconModelAliyunBailian } from './IconModelAliyunBailian.vue'
3
- export { default as IconModelDeepseek } from './IconModelDeepseek.vue'
4
- export { default as IconMoon } from './IconMoon.vue'
5
- export { default as IconPlugin } from './IconPlugin.vue'
6
- export { default as IconSun } from './IconSun.vue'
7
- export { default as IconWebSearch } from './IconWebSearch.vue'
@@ -1,129 +0,0 @@
1
- import { sseStreamToGenerator, toolPlugin, useConversation } from '@opentiny/tiny-robot-kit'
2
- import { computed, ref } from 'vue'
3
- import type { McpServerKey } from '../mcpServers'
4
- import { useMcp } from './useMcp'
5
- import { useModel } from './useModel'
6
-
7
- function createChatStore() {
8
- const inputMessage = ref('')
9
- const modelStore = useModel()
10
- const mcpStore = useMcp()
11
- const { listTools, callTool } = mcpStore
12
- const { selectedModel, getSelectedModelParams } = modelStore
13
-
14
- const useConversationReturn = useConversation({
15
- useMessageOptions: {
16
- responseProvider: async (requestBody, abortSignal) => {
17
- const currentModel = selectedModel.value
18
- if (!currentModel) {
19
- throw new Error('No model selected.')
20
- }
21
- if (!currentModel.apiKey) {
22
- throw new Error(`Missing API key for provider "${currentModel.provider}".`)
23
- }
24
-
25
- const response = await fetch(currentModel.apiUrl, {
26
- method: 'POST',
27
- headers: {
28
- 'Content-Type': 'application/json',
29
- Authorization: `Bearer ${currentModel.apiKey}`,
30
- },
31
- body: JSON.stringify({
32
- ...requestBody,
33
- ...getSelectedModelParams(),
34
- stream: true,
35
- }),
36
- signal: abortSignal,
37
- })
38
-
39
- if (!response.ok) {
40
- const detail = await response.text().catch(() => '')
41
- throw new Error(`HTTP ${response.status}: ${response.statusText}${detail ? ` - ${detail}` : ''}`)
42
- }
43
-
44
- return sseStreamToGenerator(response, { signal: abortSignal })
45
- },
46
- initialMessages: [
47
- {
48
- role: 'system',
49
- content: 'You are a helpful assistant.',
50
- },
51
- ],
52
- plugins: [
53
- toolPlugin({
54
- getTools: async () => {
55
- const mcpTools = await listTools()
56
- return mcpTools.map((tool) => ({
57
- type: 'function',
58
- function: {
59
- name: tool.name,
60
- description: tool.description || '',
61
- parameters: (tool.inputSchema as Record<string, unknown> | undefined) || {
62
- type: 'object',
63
- properties: {},
64
- },
65
- },
66
- }))
67
- },
68
- callTool: async (toolCall) => {
69
- const toolName = toolCall.function?.name
70
- if (!toolName || !toolName.includes('__')) {
71
- throw new Error(`Unknown MCP tool name: ${toolName || '(empty)'}`)
72
- }
73
- const [serverKeyPart, ...nameParts] = toolName.split('__')
74
- const originalToolName = nameParts.join('__')
75
- const serverKey = serverKeyPart as McpServerKey
76
- if (!originalToolName) {
77
- throw new Error(`Unknown MCP tool name: ${toolName}`)
78
- }
79
- const args = JSON.parse(toolCall.function?.arguments || '{}') as Record<string, unknown>
80
- return await callTool(serverKey, originalToolName, args)
81
- },
82
- }),
83
- {
84
- onError({ currentTurn, error }) {
85
- console.error(error)
86
- currentTurn[currentTurn.length - 1].content = String(error)
87
- },
88
- },
89
- ],
90
- },
91
- autoSaveMessages: true,
92
- })
93
-
94
- const messages = computed(() => useConversationReturn.activeConversation.value?.engine.messages.value || [])
95
- const isProcessing = computed(
96
- () => useConversationReturn.activeConversation.value?.engine.isProcessing.value ?? false,
97
- )
98
-
99
- function sendMessage(content: string) {
100
- const value = content?.trim()
101
- if (!value || isProcessing.value) {
102
- return
103
- }
104
- if (!useConversationReturn.activeConversationId.value) {
105
- useConversationReturn.createConversation({ title: value.slice(0, 24) })
106
- }
107
- useConversationReturn.sendMessage(value)
108
- inputMessage.value = ''
109
- }
110
-
111
- return {
112
- ...useConversationReturn,
113
- ...modelStore,
114
- messages,
115
- inputMessage,
116
- isProcessing,
117
- sendMessage,
118
- }
119
- }
120
-
121
- type ChatStore = ReturnType<typeof createChatStore>
122
- let chatStore: ChatStore | null = null
123
-
124
- export function useChat() {
125
- if (!chatStore) {
126
- chatStore = createChatStore()
127
- }
128
- return chatStore
129
- }
@@ -1,170 +0,0 @@
1
- import { computed, ref } from 'vue'
2
- import { Client } from '@modelcontextprotocol/sdk/client'
3
- import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse'
4
- import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp'
5
- import type { CallToolRequest } from '@modelcontextprotocol/sdk/types'
6
- import { McpServers, type McpServerConfig, type McpServerKey } from '../mcpServers'
7
-
8
- type McpTool = Awaited<ReturnType<Client['listTools']>>['tools'][number]
9
- type McpToolCallResult = Awaited<ReturnType<Client['callTool']>>
10
-
11
- function createMcpClient(serverKey: McpServerKey, server: McpServerConfig) {
12
- const client = new Client({
13
- name: serverKey,
14
- version: '0.1.0',
15
- })
16
- const requestInit = {
17
- headers: server.headers,
18
- }
19
- const transport =
20
- server.type === 'streamableHttp'
21
- ? new StreamableHTTPClientTransport(new URL(server.baseUrl), { requestInit })
22
- : new SSEClientTransport(new URL(server.baseUrl), { requestInit })
23
- return { client, transport }
24
- }
25
-
26
- function getServerByKey(serverKey: McpServerKey): McpServerConfig {
27
- const server = McpServers[serverKey]
28
- if (!server) {
29
- throw new Error(`Unknown MCP server key: ${serverKey}`)
30
- }
31
- return server
32
- }
33
-
34
- async function listMcpToolsFromServer(serverKey: McpServerKey): Promise<McpTool[]> {
35
- const server = getServerByKey(serverKey)
36
- const { client, transport } = createMcpClient(serverKey, server)
37
- try {
38
- await client.connect(transport)
39
- const response = await client.listTools()
40
- return response.tools
41
- } finally {
42
- await client.close().catch(() => undefined)
43
- }
44
- }
45
-
46
- async function callMcpToolFromServer(
47
- serverKey: McpServerKey,
48
- toolName: string,
49
- args: CallToolRequest['params']['arguments'] = {},
50
- ): Promise<McpToolCallResult> {
51
- const server = getServerByKey(serverKey)
52
- const { client, transport } = createMcpClient(serverKey, server)
53
- try {
54
- await client.connect(transport)
55
- return await client.callTool({
56
- name: toolName,
57
- arguments: args,
58
- })
59
- } finally {
60
- await client.close().catch(() => undefined)
61
- }
62
- }
63
-
64
- function createMcpStore() {
65
- // Added servers are selectable from McpServers and start empty by default.
66
- const addedMcpServers = ref<McpServerKey[]>([])
67
- const inUseMcpServers = ref<McpServerKey[]>([])
68
-
69
- const availableMcpServers = computed(() => Object.keys(McpServers).map((serverKey) => serverKey as McpServerKey))
70
-
71
- function addMcpServer(serverKey: McpServerKey) {
72
- if (!McpServers[serverKey]) {
73
- throw new Error(`Unknown MCP server key: ${serverKey}`)
74
- }
75
- if (!addedMcpServers.value.includes(serverKey)) {
76
- addedMcpServers.value = [...addedMcpServers.value, serverKey]
77
- }
78
- // First add should enable the server immediately.
79
- if (!inUseMcpServers.value.includes(serverKey)) {
80
- inUseMcpServers.value = [...inUseMcpServers.value, serverKey]
81
- }
82
- }
83
-
84
- function toggleMcpServer(serverKey: McpServerKey) {
85
- if (!addedMcpServers.value.includes(serverKey)) {
86
- throw new Error(`MCP server "${serverKey}" is not added.`)
87
- }
88
- if (inUseMcpServers.value.includes(serverKey)) {
89
- inUseMcpServers.value = inUseMcpServers.value.filter((item) => item !== serverKey)
90
- return
91
- }
92
- inUseMcpServers.value = [...inUseMcpServers.value, serverKey]
93
- }
94
-
95
- function removeMcpServer(serverKey: McpServerKey) {
96
- if (!addedMcpServers.value.includes(serverKey)) {
97
- return
98
- }
99
- addedMcpServers.value = addedMcpServers.value.filter((item) => item !== serverKey)
100
- inUseMcpServers.value = inUseMcpServers.value.filter((item) => item !== serverKey)
101
- }
102
-
103
- function assertServerInUse(serverKey: McpServerKey) {
104
- if (!inUseMcpServers.value.includes(serverKey)) {
105
- throw new Error(`MCP server "${serverKey}" is not in use.`)
106
- }
107
- }
108
-
109
- async function listTools(serverKey?: McpServerKey): Promise<McpTool[]> {
110
- if (serverKey) {
111
- return listMcpToolsFromServer(serverKey)
112
- }
113
-
114
- const resultEntries = await Promise.allSettled(
115
- inUseMcpServers.value.map(async (key) => await listMcpToolsFromServer(key)),
116
- )
117
-
118
- const allTools: McpTool[] = []
119
- resultEntries.forEach((item, index) => {
120
- const serverKey = inUseMcpServers.value[index]
121
- if (!serverKey) {
122
- return
123
- }
124
- if (item.status === 'fulfilled') {
125
- item.value.forEach((tool, toolIndex) => {
126
- const originalName = typeof tool.name === 'string' ? tool.name : `tool_${toolIndex + 1}`
127
- allTools.push({
128
- ...tool,
129
- name: `${serverKey}__${originalName}`,
130
- })
131
- })
132
- return
133
- }
134
- console.error(`[MCP] Failed to list tools from "${serverKey}":`, item.reason)
135
- })
136
-
137
- return allTools
138
- }
139
-
140
- async function callTool(
141
- serverKey: McpServerKey,
142
- toolName: string,
143
- args: Record<string, unknown> = {},
144
- ): Promise<McpToolCallResult> {
145
- assertServerInUse(serverKey)
146
- return callMcpToolFromServer(serverKey, toolName, args)
147
- }
148
-
149
- return {
150
- McpServers,
151
- availableMcpServers,
152
- addedMcpServers,
153
- addMcpServer,
154
- inUseMcpServers,
155
- toggleMcpServer,
156
- removeMcpServer,
157
- listTools,
158
- callTool,
159
- }
160
- }
161
-
162
- type McpStore = ReturnType<typeof createMcpStore>
163
- let mcpStore: McpStore | null = null
164
-
165
- export function useMcp() {
166
- if (!mcpStore) {
167
- mcpStore = createMcpStore()
168
- }
169
- return mcpStore
170
- }
@@ -1,82 +0,0 @@
1
- import type { Component } from 'vue'
2
- import { computed, ref } from 'vue'
3
- import { ModelConfigs, type ModelConfigItem } from '../models'
4
-
5
- export interface ModelOption {
6
- id: string
7
- provider: string
8
- name: string
9
- model: string
10
- icon: Component
11
- apiUrl: string
12
- apiKey?: string
13
- capabilities?: ModelConfigItem['capabilities']
14
- }
15
-
16
- function createModelStore() {
17
- const modelOptions: ModelOption[] = Object.entries(ModelConfigs).flatMap(([provider, config]) =>
18
- config.models.map((modelItem) => ({
19
- id: `${provider}:${modelItem.model}`,
20
- provider,
21
- name: modelItem.name,
22
- model: modelItem.model,
23
- icon: config.icon,
24
- apiUrl: config.apiUrl,
25
- apiKey: config.apiKey?.trim(),
26
- capabilities: modelItem.capabilities,
27
- })),
28
- )
29
-
30
- const selectedModelId = ref(modelOptions[0]?.id || '')
31
- const selectedModel = computed<ModelOption | undefined>(() =>
32
- modelOptions.find((item) => item.id === selectedModelId.value),
33
- )
34
-
35
- const thinkingEnabled = ref(false)
36
- const searchEnabled = ref(false)
37
-
38
- const supportsThinking = computed(() => Boolean(selectedModel.value?.capabilities?.thinking))
39
- const supportsSearch = computed(() => Boolean(selectedModel.value?.capabilities?.search))
40
-
41
- const hasApiConfig = computed(() => {
42
- const current = selectedModel.value
43
- return Boolean(current?.apiUrl && current?.apiKey)
44
- })
45
-
46
- function getSelectedModelParams(): Record<string, unknown> {
47
- const current = selectedModel.value
48
- if (!current) {
49
- return {}
50
- }
51
-
52
- const { thinking, search } = current.capabilities ?? {}
53
-
54
- return {
55
- model: current.model,
56
- ...(thinkingEnabled.value && thinking ? thinking : {}),
57
- ...(searchEnabled.value && search ? search : {}),
58
- }
59
- }
60
-
61
- return {
62
- modelOptions,
63
- selectedModelId,
64
- selectedModel,
65
- thinkingEnabled,
66
- searchEnabled,
67
- supportsThinking,
68
- supportsSearch,
69
- hasApiConfig,
70
- getSelectedModelParams,
71
- }
72
- }
73
-
74
- type ModelStore = ReturnType<typeof createModelStore>
75
- let modelStore: ModelStore | null = null
76
-
77
- export function useModel() {
78
- if (!modelStore) {
79
- modelStore = createModelStore()
80
- }
81
- return modelStore
82
- }
@@ -1,40 +0,0 @@
1
- export type McpServerConfig = {
2
- type: 'sse' | 'streamableHttp'
3
- name: string
4
- description?: string
5
- baseUrl: string
6
- headers?: Record<string, string>
7
- logoUrl?: string
8
- }
9
-
10
- export const McpServers = {
11
- 'china-railway': {
12
- type: 'sse',
13
- description: '开源社区开发者封装,提供 12306购票信息查询等服务',
14
- name: '12306 车票查询',
15
- baseUrl: 'https://dashscope.aliyuncs.com/api/v1/mcps/china-railway/sse',
16
- logoUrl: 'https://img.alicdn.com/imgextra/i3/O1CN01yUKR7l1FrpKqvxNjt_!!6000000000541-2-tps-512-512.png',
17
- headers: {
18
- Authorization: `Bearer ${import.meta.env.VITE_ALIYUN_DASHSCOPE_KEY}`,
19
- },
20
- },
21
- 'amap-maps': {
22
- type: 'sse',
23
- description:
24
- '高德地图MCP Server现已覆盖15大核心接口,提供全场景覆盖的地理信息服务,包括生成专属地图、导航到目的地、打车、地理编码、逆地理编码、IP定位、天气查询、骑行路径规划、步行路径规划、驾车路径规划、公交路径规划、距离测量、关键词搜索、周边搜索、详情搜索等。',
25
- name: '高德地图',
26
- baseUrl: 'https://dashscope.aliyuncs.com/api/v1/mcps/amap-maps/sse',
27
- logoUrl: 'https://img.alicdn.com/imgextra/i4/O1CN01iPPabT1EGRN6uatHP_!!6000000000324-0-tps-512-512.jpg',
28
- headers: {
29
- Authorization: `Bearer ${import.meta.env.VITE_ALIYUN_DASHSCOPE_KEY}`,
30
- },
31
- },
32
- 'model-context-protocol-mcp': {
33
- type: 'streamableHttp',
34
- name: 'Model Context Protocol MCP',
35
- baseUrl: window.location.origin + '/modelcontextprotocol-mcp',
36
- logoUrl: window.location.origin + '/modelcontextprotocol.png',
37
- },
38
- } satisfies Record<string, McpServerConfig>
39
-
40
- export type McpServerKey = keyof typeof McpServers
@@ -1,81 +0,0 @@
1
- import { type Component } from 'vue'
2
- import { IconModelAliyunBailian, IconModelDeepseek } from './components/icons'
3
-
4
- export interface ModelCapabilities {
5
- thinking?: Record<string, unknown> | false
6
- search?: Record<string, unknown> | false
7
- }
8
-
9
- export interface ModelConfigItem {
10
- name: string
11
- model: string
12
- capabilities?: ModelCapabilities
13
- }
14
-
15
- export interface ProviderModelConfig {
16
- apiUrl: string
17
- icon: Component
18
- apiKey?: string
19
- models: ModelConfigItem[]
20
- }
21
-
22
- export const ModelConfigs: Record<string, ProviderModelConfig> = {
23
- aliyun: {
24
- apiUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',
25
- icon: IconModelAliyunBailian,
26
- apiKey: import.meta.env.VITE_ALIYUN_DASHSCOPE_KEY,
27
- models: [
28
- {
29
- name: 'Qwen Flash',
30
- model: 'qwen-flash',
31
- capabilities: {
32
- thinking: {
33
- enable_thinking: true,
34
- },
35
- search: {
36
- enable_search: true,
37
- },
38
- },
39
- },
40
- {
41
- name: 'Qwen Plus',
42
- model: 'qwen-plus',
43
- capabilities: {
44
- thinking: {
45
- enable_thinking: true,
46
- },
47
- search: {
48
- enable_search: true,
49
- },
50
- },
51
- },
52
- {
53
- name: 'Qwen Max',
54
- model: 'qwen-max',
55
- capabilities: {
56
- thinking: {
57
- enable_thinking: true,
58
- },
59
- search: {
60
- enable_search: true,
61
- },
62
- },
63
- },
64
- ],
65
- },
66
- deepseek: {
67
- apiUrl: 'https://api.deepseek.com/chat/completions',
68
- icon: IconModelDeepseek,
69
- apiKey: import.meta.env.VITE_DEEPSEEK_API_KEY,
70
- models: [
71
- {
72
- name: 'DeepSeek V4 Flash',
73
- model: 'deepseek-v4-flash',
74
- },
75
- {
76
- name: 'DeepSeek V4 Pro',
77
- model: 'deepseek-v4-pro',
78
- },
79
- ],
80
- },
81
- }
@@ -1,72 +0,0 @@
1
- <script setup lang="ts">
2
- import type { TemplateItem } from '@opentiny/tiny-robot'
3
- import { TrDropdownMenu, TrSuggestionPillButton, TrSuggestionPills } from '@opentiny/tiny-robot'
4
- import type { TemplateCategory, TemplateSuggestionItem } from '../config/chat-ui'
5
- import { computed } from 'vue'
6
-
7
- const props = defineProps<{
8
- templateCategories: readonly TemplateCategory[]
9
- }>()
10
-
11
- const currentTemplate = defineModel<TemplateItem[]>('currentTemplate', { required: true })
12
- const templateMenus = computed(() =>
13
- props.templateCategories.map((category) => ({
14
- ...category,
15
- items: category.items.map((item) => ({ id: item.id, text: item.text, template: item })),
16
- })),
17
- )
18
- const overlayTarget = '.chat-add-window'
19
-
20
- function fillTemplate(template: TemplateSuggestionItem): void {
21
- currentTemplate.value = template.template.map((item) => ({ ...item }))
22
- }
23
-
24
- function handleTemplateSelect(item: unknown): void {
25
- fillTemplate((item as { template: TemplateSuggestionItem }).template)
26
- }
27
- </script>
28
-
29
- <template>
30
- <div class="chat-add-tools">
31
- <TrSuggestionPills class="chat-add-tools__pills">
32
- <TrDropdownMenu
33
- v-for="category in templateMenus"
34
- :key="category.id"
35
- :append-to="overlayTarget"
36
- :items="category.items as never"
37
- trigger="click"
38
- @item-click="handleTemplateSelect"
39
- >
40
- <template #trigger
41
- ><TrSuggestionPillButton>{{ category.title }}</TrSuggestionPillButton></template
42
- >
43
- </TrDropdownMenu>
44
- </TrSuggestionPills>
45
- </div>
46
- </template>
47
-
48
- <style scoped>
49
- .chat-add-tools {
50
- display: flex;
51
- box-sizing: border-box;
52
- width: 100%;
53
- min-width: 0;
54
- flex-shrink: 0;
55
- align-items: center;
56
- gap: 8px;
57
- padding: 8px 12px;
58
- }
59
- .chat-add-tools__pills {
60
- min-width: 0;
61
- flex: 1;
62
- }
63
- .chat-add-tools__pills :deep(.tr-suggestion-pills__container) {
64
- min-width: 0;
65
- mask: linear-gradient(to right, rgb(0 0 0 / 100%) 80%, rgb(0 0 0 / 0%) 100%);
66
- }
67
- @container (max-width: 519px) {
68
- .chat-add-tools {
69
- padding: 8px;
70
- }
71
- }
72
- </style>
@@ -1,26 +0,0 @@
1
- import type { ChatMcpServers, ChatProviderConfig } from '@opentiny/tiny-robot-chat'
2
-
3
- export const mcpServers: ChatMcpServers = []
4
-
5
- export const modelProviders: ChatProviderConfig[] = [
6
- {
7
- type: 'qwen',
8
- label: 'DashScope',
9
- apiUrl: import.meta.env.VITE_QWEN_API_URL?.trim() || undefined,
10
- apiKey: import.meta.env.VITE_ALIYUN_DASHSCOPE_KEY?.trim(),
11
- models: [
12
- { id: 'qwen3.7-flash', label: 'Qwen3.7 Flash', capabilities: { thinking: true, search: true } },
13
- { id: 'qwen3.7-plus', label: 'Qwen3.7 Plus', capabilities: { thinking: true, search: true } },
14
- { id: 'qwen3.7-max', label: 'Qwen3.7 Max', capabilities: { thinking: true, search: true } },
15
- ],
16
- },
17
- {
18
- type: 'deepseek',
19
- apiUrl: import.meta.env.VITE_DEEPSEEK_API_URL?.trim() || undefined,
20
- apiKey: import.meta.env.VITE_DEEPSEEK_API_KEY?.trim(),
21
- models: [
22
- { id: 'deepseek-v4-flash', label: 'DeepSeek V4 Flash', capabilities: { thinking: true } },
23
- { id: 'deepseek-v4-pro', label: 'DeepSeek V4 Pro', capabilities: { thinking: true } },
24
- ],
25
- },
26
- ]