@opentiny/tiny-robot-cli 0.5.2-alpha.16 → 0.5.2-alpha.18

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 (53) hide show
  1. package/README.md +1 -49
  2. package/bin/commands/add.js +270 -561
  3. package/bin/commands/create.js +3 -6
  4. package/bin/utils.js +45 -147
  5. package/package.json +3 -5
  6. package/templates/basic/.env.example +0 -8
  7. package/templates/basic/README.md +22 -53
  8. package/templates/basic/index.html +2 -2
  9. package/templates/basic/package.json +16 -12
  10. package/templates/basic/public/modelcontextprotocol.png +0 -0
  11. package/templates/basic/src/App.vue +119 -112
  12. package/templates/basic/src/components/ChatList.vue +82 -0
  13. package/templates/basic/src/components/ChatSender.vue +125 -0
  14. package/templates/basic/src/components/ConversationHistory.vue +136 -0
  15. package/templates/basic/src/components/HistoryDrawerButton.vue +43 -0
  16. package/templates/basic/src/components/McpServerPickerButton.vue +278 -0
  17. package/templates/basic/src/components/ThemeToggleButton.vue +44 -0
  18. package/templates/basic/src/components/icons/IconDeepThink.vue +29 -0
  19. package/templates/basic/src/components/icons/IconModelAliyunBailian.vue +51 -0
  20. package/templates/basic/src/components/icons/IconModelDeepseek.vue +29 -0
  21. package/templates/basic/src/components/icons/IconMoon.vue +29 -0
  22. package/templates/basic/src/components/icons/IconPlugin.vue +29 -0
  23. package/templates/basic/src/components/icons/IconSun.vue +35 -0
  24. package/templates/basic/src/components/icons/IconWebSearch.vue +36 -0
  25. package/templates/basic/src/components/icons/index.ts +7 -0
  26. package/templates/basic/src/composables/useChat.ts +129 -0
  27. package/templates/basic/src/composables/useMcp.ts +170 -0
  28. package/templates/basic/src/composables/useModel.ts +82 -0
  29. package/templates/basic/src/main.ts +2 -2
  30. package/templates/basic/src/mcpServers.ts +40 -0
  31. package/templates/basic/src/models.ts +81 -0
  32. package/templates/basic/tsconfig.app.json +5 -2
  33. package/templates/basic/tsconfig.node.json +6 -3
  34. package/templates/basic/vite.config.ts +1 -6
  35. package/templates/chat/.env.example +0 -9
  36. package/templates/chat/src/TinyRobotChat.vue +27 -88
  37. package/bin/runtime-version.js +0 -37
  38. package/templates/basic/public/favicon.svg +0 -1
  39. package/templates/basic/public/icons.svg +0 -24
  40. package/templates/chat/README.md +0 -46
  41. package/templates/chat/index.html +0 -12
  42. package/templates/chat/package.json +0 -28
  43. package/templates/chat/src/components/ComposerTools.vue +0 -99
  44. package/templates/chat/src/components/WindowHeader.vue +0 -192
  45. package/templates/chat/src/composables/useWindow.ts +0 -83
  46. package/templates/chat/src/config/chat-runtime.ts +0 -82
  47. package/templates/chat/src/config/chat-ui.ts +0 -290
  48. package/templates/chat/src/index.css +0 -109
  49. package/templates/chat/src/main.ts +0 -7
  50. package/templates/chat/tsconfig.app.json +0 -13
  51. package/templates/chat/tsconfig.json +0 -7
  52. package/templates/chat/tsconfig.node.json +0 -19
  53. package/templates/chat/vite.config.ts +0 -16
@@ -1,96 +1,35 @@
1
1
  <script setup lang="ts">
2
- import type { HistoryMenuItem, PromptProps, TemplateItem } from '@opentiny/tiny-robot'
3
- import { TrSender, TrThemeProvider as TrTheme } from '@opentiny/tiny-robot'
4
- import { TrChat, useChatHistoryItems, useLocalChatRuntime, type ChatHistoryItem } from '@opentiny/tiny-robot-chat'
5
- import { IconAi } from '@opentiny/tiny-robot-svgs'
6
- import { computed, reactive, ref } from 'vue'
7
- import ComposerTools from './components/ComposerTools.vue'
8
- import WindowHeader from './components/WindowHeader.vue'
9
- import { composerMenus, createChatUi, templateCategories } from './config/chat-ui'
10
- import { mcpExamples, mcpServers, modelProviders } from './config/chat-runtime'
11
- import { useWindow } from './composables/useWindow'
2
+ import type { ChatMcpServerConfig, ChatModelOption } from '@opentiny/tiny-robot/experimental'
3
+ import { TrThemeProvider } from '@opentiny/tiny-robot'
4
+ import { TrChat } from '@opentiny/tiny-robot/experimental'
5
+ import { ref } from 'vue'
12
6
 
13
- const runtime = useLocalChatRuntime({ modelProviders, mcpServers })
14
- const window = reactive(useWindow())
15
- const chatRef = ref<{ send: (payload: { text: string }) => Promise<boolean> } | null>(null)
16
- const currentTemplate = ref<TemplateItem[]>([])
17
- const showHistory = ref(false)
18
- const historyData = useChatHistoryItems({ conversations: () => runtime.conversations.value, defaultTitle: '' })
19
- const activeConversationId = computed(() => runtime.activeConversation.value?.id)
20
- const templateExtensions = [TrSender.template(currentTemplate as never, { appendTo: '.chat-add-window' })]
21
- const chatUi = computed(() => createChatUi({ floatingOptions: window.floatingOptions, templateExtensions }))
7
+ const show = ref(false)
8
+ const fullscreen = ref(false)
22
9
 
23
- function handlePromptClick({ item }: { item: PromptProps }): void {
24
- if (item.description) void chatRef.value?.send({ text: item.description })
25
- }
10
+ const chatModelOptions: ChatModelOption[] = [
11
+ {
12
+ id: 'deepseek-chat',
13
+ provider: 'deepseek',
14
+ name: 'DeepSeek V4 Flash',
15
+ model: 'deepseek-v4-flash',
16
+ apiUrl: 'https://api.deepseek.com/chat/completions',
17
+ apiKey: import.meta.env.VITE_DEEPSEEK_API_KEY || '',
18
+ },
19
+ ]
26
20
 
27
- function handleNewSession(): void {
28
- void runtime.actions.createConversation()
29
- showHistory.value = false
30
- }
31
-
32
- function handleHistorySelect(item: ChatHistoryItem): void {
33
- void runtime.actions.switchConversation(item.raw.id)
34
- showHistory.value = false
35
- }
36
-
37
- function handleHistoryRename(title: string, item: ChatHistoryItem): void {
38
- void runtime.actions.renameConversation(item.raw.id, title)
39
- }
40
-
41
- function handleHistoryAction(action: HistoryMenuItem, item: ChatHistoryItem): void {
42
- if (action.id === 'delete') void runtime.actions.deleteConversation(item.raw.id)
43
- }
21
+ const chatMcpServers: Record<string, ChatMcpServerConfig> = {}
44
22
  </script>
45
23
 
46
24
  <template>
47
- <TrTheme>
48
- <main class="chat-add-app">
49
- <button
50
- v-if="!window.show"
51
- class="chat-add-launcher"
52
- type="button"
53
- title="打开 TinyRobot"
54
- aria-label="打开 TinyRobot"
55
- @click="window.open"
56
- >
57
- <IconAi style="font-size: 32px" />
58
- </button>
59
- <TrChat
60
- v-if="window.show"
61
- ref="chatRef"
62
- :class="['chat-add-window', `chat-add-window--${window.displayMode}`]"
63
- :style="window.layoutStyle"
64
- :runtime="runtime"
65
- :ui="chatUi"
66
- v-model:floating-state="window.floatingState"
67
- @prompt-click="handlePromptClick"
68
- >
69
- <template #layout-header>
70
- <WindowHeader
71
- :display-mode="window.displayMode"
72
- :show-history="showHistory"
73
- :history-data="historyData"
74
- :active-conversation-id="activeConversationId"
75
- @new-session="handleNewSession"
76
- @select-history="handleHistorySelect"
77
- @rename-history="handleHistoryRename"
78
- @history-action="handleHistoryAction"
79
- @update:show-history="showHistory = $event"
80
- @change-mode="window.setDisplayMode"
81
- @close="window.close"
82
- />
83
- </template>
84
- <template #composer-before="{ submit }">
85
- <ComposerTools
86
- v-model:current-template="currentTemplate"
87
- :template-categories="templateCategories"
88
- :mcp-examples="mcpExamples"
89
- :menus="composerMenus"
90
- :submit="submit"
91
- />
92
- </template>
93
- </TrChat>
94
- </main>
95
- </TrTheme>
25
+ <TrThemeProvider>
26
+ <TrChat
27
+ v-model:show="show"
28
+ v-model:fullscreen="fullscreen"
29
+ title="TrChat Preview"
30
+ system-prompt="You are a helpful assistant."
31
+ :model-options="chatModelOptions"
32
+ :mcp-servers="chatMcpServers"
33
+ />
34
+ </TrThemeProvider>
96
35
  </template>
@@ -1,37 +0,0 @@
1
- import fs from 'node:fs'
2
- import { fileURLToPath } from 'node:url'
3
- import semver from 'semver'
4
-
5
- const CLI_PACKAGE_FILE = fileURLToPath(new URL('../package.json', import.meta.url))
6
-
7
- export function readCliVersion() {
8
- const packageJson = JSON.parse(fs.readFileSync(CLI_PACKAGE_FILE, 'utf8'))
9
- return packageJson.version
10
- }
11
-
12
- export function formatRuntimeSpecifier(version) {
13
- const parsedVersion = typeof version === 'string' ? semver.parse(version) : null
14
- const canonicalVersion = parsedVersion
15
- ? `${parsedVersion.version}${parsedVersion.build.length > 0 ? `+${parsedVersion.build.join('.')}` : ''}`
16
- : null
17
- if (!parsedVersion || canonicalVersion !== version) {
18
- throw new Error(`Runtime version must be a valid semantic version: ${String(version)}`)
19
- }
20
-
21
- return parsedVersion.prerelease.length > 0 ? version : `^${version}`
22
- }
23
-
24
- export function resolveRuntimeVersion(override) {
25
- const version = override ?? readCliVersion()
26
- return { version, specifier: formatRuntimeSpecifier(version) }
27
- }
28
-
29
- export function createRuntimeDependencies(specifier) {
30
- return {
31
- '@opentiny/tiny-robot': specifier,
32
- '@opentiny/tiny-robot-chat': specifier,
33
- '@opentiny/tiny-robot-kit': specifier,
34
- '@opentiny/tiny-robot-svgs': specifier,
35
- '@vueuse/core': '13.9.0',
36
- }
37
- }
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="48" height="46" fill="none" viewBox="0 0 48 46"><path fill="#863bff" d="M25.946 44.938c-.664.845-2.021.375-2.021-.698V33.937a2.26 2.26 0 0 0-2.262-2.262H10.287c-.92 0-1.456-1.04-.92-1.788l7.48-10.471c1.07-1.497 0-3.578-1.842-3.578H1.237c-.92 0-1.456-1.04-.92-1.788L10.013.474c.214-.297.556-.474.92-.474h28.894c.92 0 1.456 1.04.92 1.788l-7.48 10.471c-1.07 1.498 0 3.579 1.842 3.579h11.377c.943 0 1.473 1.088.89 1.83L25.947 44.94z" style="fill:#863bff;fill:color(display-p3 .5252 .23 1);fill-opacity:1"/><mask id="a" width="48" height="46" x="0" y="0" maskUnits="userSpaceOnUse" style="mask-type:alpha"><path fill="#000" d="M25.842 44.938c-.664.844-2.021.375-2.021-.698V33.937a2.26 2.26 0 0 0-2.262-2.262H10.183c-.92 0-1.456-1.04-.92-1.788l7.48-10.471c1.07-1.498 0-3.579-1.842-3.579H1.133c-.92 0-1.456-1.04-.92-1.787L9.91.473c.214-.297.556-.474.92-.474h28.894c.92 0 1.456 1.04.92 1.788l-7.48 10.471c-1.07 1.498 0 3.578 1.842 3.578h11.377c.943 0 1.473 1.088.89 1.832L25.843 44.94z" style="fill:#000;fill-opacity:1"/></mask><g mask="url(#a)"><g filter="url(#b)"><ellipse cx="5.508" cy="14.704" fill="#ede6ff" rx="5.508" ry="14.704" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -4.47 31.516)"/></g><g filter="url(#c)"><ellipse cx="10.399" cy="29.851" fill="#ede6ff" rx="10.399" ry="29.851" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -39.328 7.883)"/></g><g filter="url(#d)"><ellipse cx="5.508" cy="30.487" fill="#7e14ff" rx="5.508" ry="30.487" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.814 -25.913 -14.639)scale(1 -1)"/></g><g filter="url(#e)"><ellipse cx="5.508" cy="30.599" fill="#7e14ff" rx="5.508" ry="30.599" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.814 -32.644 -3.334)scale(1 -1)"/></g><g filter="url(#f)"><ellipse cx="5.508" cy="30.599" fill="#7e14ff" rx="5.508" ry="30.599" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -34.34 30.47)"/></g><g filter="url(#g)"><ellipse cx="14.072" cy="22.078" fill="#ede6ff" rx="14.072" ry="22.078" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="rotate(93.35 24.506 48.493)scale(-1 1)"/></g><g filter="url(#h)"><ellipse cx="3.47" cy="21.501" fill="#7e14ff" rx="3.47" ry="21.501" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.009 28.708 47.59)scale(-1 1)"/></g><g filter="url(#i)"><ellipse cx="3.47" cy="21.501" fill="#7e14ff" rx="3.47" ry="21.501" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.009 28.708 47.59)scale(-1 1)"/></g><g filter="url(#j)"><ellipse cx=".387" cy="8.972" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(39.51 .387 8.972)"/></g><g filter="url(#k)"><ellipse cx="47.523" cy="-6.092" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 47.523 -6.092)"/></g><g filter="url(#l)"><ellipse cx="41.412" cy="6.333" fill="#47bfff" rx="5.971" ry="9.665" style="fill:#47bfff;fill:color(display-p3 .2799 .748 1);fill-opacity:1" transform="rotate(37.892 41.412 6.333)"/></g><g filter="url(#m)"><ellipse cx="-1.879" cy="38.332" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 -1.88 38.332)"/></g><g filter="url(#n)"><ellipse cx="-1.879" cy="38.332" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 -1.88 38.332)"/></g><g filter="url(#o)"><ellipse cx="35.651" cy="29.907" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 35.651 29.907)"/></g><g filter="url(#p)"><ellipse cx="38.418" cy="32.4" fill="#47bfff" rx="5.971" ry="15.297" style="fill:#47bfff;fill:color(display-p3 .2799 .748 1);fill-opacity:1" transform="rotate(37.892 38.418 32.4)"/></g></g><defs><filter id="b" width="60.045" height="41.654" x="-19.77" y="16.149" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="c" width="90.34" height="51.437" x="-54.613" y="-7.533" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="d" width="79.355" height="29.4" x="-49.64" y="2.03" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="e" width="79.579" height="29.4" x="-45.045" y="20.029" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="f" width="79.579" height="29.4" x="-43.513" y="21.178" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="g" width="74.749" height="58.852" x="15.756" y="-17.901" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="h" width="61.377" height="25.362" x="23.548" y="2.284" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="i" width="61.377" height="25.362" x="23.548" y="2.284" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="j" width="56.045" height="63.649" x="-27.636" y="-22.853" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="k" width="54.814" height="64.646" x="20.116" y="-38.415" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="l" width="33.541" height="35.313" x="24.641" y="-11.323" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="m" width="54.814" height="64.646" x="-29.286" y="6.009" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="n" width="54.814" height="64.646" x="-29.286" y="6.009" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="o" width="54.814" height="64.646" x="8.244" y="-2.416" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="p" width="39.409" height="43.623" x="18.713" y="10.588" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter></defs></svg>
@@ -1,24 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg">
2
- <symbol id="bluesky-icon" viewBox="0 0 16 17">
3
- <g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
4
- <defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
5
- </symbol>
6
- <symbol id="discord-icon" viewBox="0 0 20 19">
7
- <path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
8
- </symbol>
9
- <symbol id="documentation-icon" viewBox="0 0 21 20">
10
- <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
11
- <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
12
- <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
13
- </symbol>
14
- <symbol id="github-icon" viewBox="0 0 19 19">
15
- <path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
16
- </symbol>
17
- <symbol id="social-icon" viewBox="0 0 20 20">
18
- <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
19
- <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
20
- </symbol>
21
- <symbol id="x-icon" viewBox="0 0 19 19">
22
- <path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
23
- </symbol>
24
- </svg>
@@ -1,46 +0,0 @@
1
- # TinyRobot Chat Add
2
-
3
- 这是一个独立的 Chat 扩展模板,提供通用工作助手场景的最小工程结构。
4
-
5
- ## 启动
6
-
7
- ```powershell
8
- pnpm dev
9
- ```
10
-
11
- ## 构建
12
-
13
- ```powershell
14
- pnpm type-check
15
- pnpm build
16
- ```
17
-
18
- ## 接入真实模型
19
-
20
- 复制项目根目录的 `.env.example` 为 `.env.local`,配置 `VITE_QWEN_API_URL`、`VITE_ALIYUN_DASHSCOPE_KEY`、`VITE_DEEPSEEK_API_URL` 和 `VITE_DEEPSEEK_API_KEY`,重启 Vite 后即可使用模型选择器中的真实模型。模板只提供 `.env.example`,不会自动创建 `.env`。配置读取逻辑位于 `src/config/chat-runtime.ts`;使用 `add chat` 注入后,对应文件位于 `src/tiny-robot-chat/config/chat-runtime.ts`。
21
-
22
- ## 模型配置
23
-
24
- 模型配置中的 `icon` 用于模型选择器触发器;在窄容器中,带图标的模型会只显示图标。Qwen 模型支持深度思考和联网搜索,DeepSeek 模型支持深度思考。
25
-
26
- DeepSeek 模型默认继承 `low`、`high`、`max` 三档思考强度,默认值为 `high`。开启 `深度思考` 后,模型选择器才会显示思考等级。业务侧可以在模型对象中通过 `efforts` 和 `defaultEffort` 覆盖选项;只有必须始终思考的模型才配置 `thinkingRequired: true`。
27
-
28
- ## MCP 代理
29
-
30
- 独立模板的 `vite.config.ts` 已配置 `/modelcontextprotocol-mcp` 代理。使用 `add chat` 时,CLI 不会复制或修改业务项目的 `vite.config.*`,需要手动把该代理配置添加到业务项目的 `server.proxy` 下,并重启 Vite。
31
-
32
- ## 目录职责
33
-
34
- - `src/config/chat-ui.ts`: Chat UI、提示词、模板和菜单配置。
35
- - `src/config/chat-runtime.ts`: MCP 示例和模型配置。
36
- - `src/components`: 窗口头部和输入区工具。
37
- - `src/composables/useWindow.ts`: floating、fullscreen 窗口状态。
38
- - `src/index.css`: 仅作用于 Chat 容器的组件样式和 Surface 样式变量,不重置宿主页面的全局样式。
39
-
40
- ## 替换数据
41
-
42
- 直接修改 `src/config/chat-ui.ts` 和 `src/config/chat-runtime.ts` 中导出的数据;组件通过 props 使用这些配置。
43
-
44
- ## 切换窗口模式
45
-
46
- 默认显示 AI 头像按钮,点击后展开 Chat。窗口头部提供 floating、fullscreen 两种模式。floating 支持拖拽、缩放和位置恢复;fullscreen 铺满对应区域,可使用 Escape 返回悬浮窗口。点击关闭后返回 AI 头像按钮。
@@ -1,12 +0,0 @@
1
- <!doctype html>
2
- <html lang="zh-CN">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Chat Add Template</title>
7
- </head>
8
- <body>
9
- <div id="app"></div>
10
- <script type="module" src="/src/main.ts"></script>
11
- </body>
12
- </html>
@@ -1,28 +0,0 @@
1
- {
2
- "name": "__PROJECT_NAME__",
3
- "private": true,
4
- "version": "0.0.0",
5
- "type": "module",
6
- "scripts": {
7
- "dev": "vite",
8
- "build": "vue-tsc -b && vite build",
9
- "preview": "vite preview",
10
- "type-check": "vue-tsc -b"
11
- },
12
- "dependencies": {
13
- "@opentiny/tiny-robot": "__TINY_ROBOT_VERSION__",
14
- "@opentiny/tiny-robot-chat": "__TINY_ROBOT_VERSION__",
15
- "@opentiny/tiny-robot-kit": "__TINY_ROBOT_VERSION__",
16
- "@opentiny/tiny-robot-svgs": "__TINY_ROBOT_VERSION__",
17
- "@vueuse/core": "13.9.0",
18
- "vue": "^3.5.40"
19
- },
20
- "devDependencies": {
21
- "@types/node": "^24.13.3",
22
- "@vitejs/plugin-vue": "^6.0.8",
23
- "@vue/tsconfig": "^0.9.1",
24
- "typescript": "~6.0.2",
25
- "vite": "^8.2.0",
26
- "vue-tsc": "^3.3.8"
27
- }
28
- }
@@ -1,99 +0,0 @@
1
- <script setup lang="ts">
2
- import type { SuggestionData, SuggestionItem, TemplateItem } from '@opentiny/tiny-robot'
3
- import { TrDropdownMenu, TrSuggestionPillButton, TrSuggestionPills, TrSuggestionPopover } from '@opentiny/tiny-robot'
4
- import type { ChatSenderSlotProps } from '@opentiny/tiny-robot-chat'
5
- import { IconSparkles } from '@opentiny/tiny-robot-svgs'
6
- import type { ChatMenuItem, TemplateCategory, TemplateSuggestionItem } from '../config/chat-ui'
7
- import type { McpExample } from '../config/chat-runtime'
8
- import { computed } from 'vue'
9
-
10
- const props = defineProps<{
11
- templateCategories: readonly TemplateCategory[]
12
- mcpExamples: readonly McpExample[]
13
- menus: readonly ChatMenuItem[]
14
- submit: ChatSenderSlotProps['submit']
15
- }>()
16
-
17
- const currentTemplate = defineModel<TemplateItem[]>('currentTemplate', { required: true })
18
- const suggestionData: SuggestionData = props.mcpExamples.map((item) => ({ id: item.id, text: item.request }))
19
- const mcpMenuItems = props.mcpExamples.map((item) => ({ id: item.id, text: item.request }))
20
- const mcpMenu = computed(() => props.menus.find((menu) => menu.action === 'mcp'))
21
- const templateMenus = computed(() =>
22
- props.templateCategories.map((category) => ({
23
- ...category,
24
- items: category.items.map((item) => ({ id: item.id, text: item.text, template: item })),
25
- })),
26
- )
27
- const overlayTarget = '.chat-add-window'
28
-
29
- function fillTemplate(template: TemplateSuggestionItem): void {
30
- currentTemplate.value = template.template.map((item) => ({ ...item }))
31
- }
32
-
33
- function submitSuggestion(item: SuggestionItem): void {
34
- props.submit({ text: item.text })
35
- }
36
- </script>
37
-
38
- <template>
39
- <div class="chat-add-tools">
40
- <TrSuggestionPopover :append-to="overlayTarget" :data="suggestionData" @item-click="submitSuggestion">
41
- <template #trigger>
42
- <TrSuggestionPillButton title="常用查询"
43
- ><IconSparkles style="font-size: 16px; color: #1476ff"
44
- /></TrSuggestionPillButton>
45
- </template>
46
- </TrSuggestionPopover>
47
- <TrSuggestionPills class="chat-add-tools__pills">
48
- <TrDropdownMenu
49
- v-if="mcpMenu"
50
- :append-to="overlayTarget"
51
- :items="mcpMenuItems"
52
- trigger="click"
53
- @item-click="(item) => submitSuggestion(item as SuggestionItem)"
54
- >
55
- <template #trigger
56
- ><TrSuggestionPillButton>{{ mcpMenu.title }}</TrSuggestionPillButton></template
57
- >
58
- </TrDropdownMenu>
59
- <TrDropdownMenu
60
- v-for="category in templateMenus"
61
- :key="category.id"
62
- :append-to="overlayTarget"
63
- :items="category.items as never"
64
- trigger="click"
65
- @item-click="(item) => fillTemplate((item as unknown as { template: TemplateSuggestionItem }).template)"
66
- >
67
- <template #trigger
68
- ><TrSuggestionPillButton>{{ category.title }}</TrSuggestionPillButton></template
69
- >
70
- </TrDropdownMenu>
71
- </TrSuggestionPills>
72
- </div>
73
- </template>
74
-
75
- <style scoped>
76
- .chat-add-tools {
77
- display: flex;
78
- box-sizing: border-box;
79
- width: 100%;
80
- min-width: 0;
81
- flex-shrink: 0;
82
- align-items: center;
83
- gap: 8px;
84
- padding: 8px 12px;
85
- }
86
- .chat-add-tools__pills {
87
- min-width: 0;
88
- flex: 1;
89
- }
90
- .chat-add-tools__pills :deep(.tr-suggestion-pills__container) {
91
- min-width: 0;
92
- mask: linear-gradient(to right, rgb(0 0 0 / 100%) 80%, rgb(0 0 0 / 0%) 100%);
93
- }
94
- @container (max-width: 519px) {
95
- .chat-add-tools {
96
- padding: 8px;
97
- }
98
- }
99
- </style>
@@ -1,192 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HistoryMenuItem } from '@opentiny/tiny-robot'
3
- import { TrHistory, TrIconButton } from '@opentiny/tiny-robot'
4
- import { IconClose, IconEnterFullScreen, IconHistory, IconNewSession } from '@opentiny/tiny-robot-svgs'
5
- import { h } from 'vue'
6
- import type { ChatHistoryItem } from '@opentiny/tiny-robot-chat'
7
- import type { DisplayMode } from '../composables/useWindow'
8
-
9
- const props = defineProps<{
10
- displayMode: DisplayMode
11
- showHistory: boolean
12
- historyData: readonly ChatHistoryItem[]
13
- activeConversationId?: string
14
- }>()
15
-
16
- const emit = defineEmits<{
17
- newSession: []
18
- selectHistory: [item: ChatHistoryItem]
19
- renameHistory: [title: string, item: ChatHistoryItem]
20
- historyAction: [action: HistoryMenuItem, item: ChatHistoryItem]
21
- 'update:showHistory': [value: boolean]
22
- changeMode: [mode: DisplayMode]
23
- close: []
24
- }>()
25
-
26
- const IconFloatWindow = h(
27
- 'svg',
28
- {
29
- xmlns: 'http://www.w3.org/2000/svg',
30
- width: 16,
31
- height: 16,
32
- fill: 'none',
33
- viewBox: '0 0 16 16',
34
- 'aria-hidden': 'true',
35
- },
36
- [
37
- h('path', {
38
- fill: 'currentColor',
39
- 'fill-rule': 'evenodd',
40
- d: 'M6.19 14.5H4q-.285 0-.54-.06c-.15-.04-.3-.08-.44-.14s-.27-.13-.4-.22c-.14-.09-.27-.2-.39-.32s-.23-.25-.32-.39c-.09-.13-.16-.26-.22-.4s-.1-.29-.14-.44c-.04-.17-.05-.35-.05-.53V4c0-.19.01-.37.05-.54.04-.15.08-.3.14-.44s.13-.27.22-.4c.09-.14.2-.27.32-.39s.25-.23.39-.32c.13-.09.26-.16.4-.22s.29-.1.44-.14c.17-.04.35-.05.54-.05h8c.18 0 .36.01.53.05.15.04.3.08.44.14s.27.13.4.22c.14.09.27.2.39.32s.23.25.32.39c.09.13.16.26.22.4s.1.29.14.44q.06.255.06.54v2.15c0 .28-.22.5-.5.5s-.5-.22-.5-.5V4c0-.12-.02-.23-.04-.35-.02-.08-.05-.16-.08-.24a2 2 0 0 0-.13-.23 1.5 1.5 0 0 0-.19-.25 1.5 1.5 0 0 0-.25-.19c-.07-.05-.15-.09-.23-.13a2 2 0 0 0-.24-.08c-.12-.02-.23-.03-.34-.03H4c-.12 0-.23.01-.35.03-.08.02-.16.05-.24.08-.08.04-.16.08-.23.13a1.5 1.5 0 0 0-.25.19 1.5 1.5 0 0 0-.19.25c-.05.07-.09.15-.13.23-.03.08-.06.16-.08.24-.02.12-.03.23-.03.35v8c0 .11.01.22.03.34.02.08.05.16.08.24.04.08.08.16.13.23.05.09.12.17.19.25.08.07.16.14.25.19.07.05.15.09.23.13.08.03.16.06.24.08.12.02.23.04.35.04h2.19c.28 0 .5.22.5.5s-.22.5-.5.5m7.12-6.97c-.1-.02-.21-.03-.31-.03H9c-.11 0-.22.01-.32.03-.09.02-.18.05-.27.08-.09.04-.17.08-.24.13-.09.06-.16.12-.24.19-.07.08-.13.15-.19.24-.05.07-.09.15-.13.24-.03.09-.06.18-.08.27-.02.1-.03.21-.03.32v4c0 .1.01.21.03.31.02.09.05.18.08.27.04.09.08.17.13.24.06.09.12.16.19.24.08.07.15.13.24.19.07.05.15.09.24.13.09.03.18.06.27.08.1.02.21.04.32.04h4c.1 0 .21-.02.31-.04.09-.02.18-.05.27-.08.09-.04.17-.08.24-.13.09-.06.16-.12.24-.19.07-.08.13-.15.19-.24.05-.07.09-.15.13-.24.03-.09.06-.18.08-.27.02-.1.04-.21.04-.31V9c0-.11-.02-.22-.04-.32-.02-.09-.05-.18-.08-.27-.04-.09-.08-.17-.13-.24-.06-.09-.12-.16-.19-.24-.08-.07-.15-.13-.24-.19-.07-.05-.15-.09-.24-.13-.09-.03-.18-.06-.27-.08M9 8.5h4c.06 0 .13.01.19.03.06.03.11.06.16.11s.08.1.11.16c.02.06.04.13.04.2v4c0 .06-.02.13-.04.19-.03.06-.06.11-.11.16s-.1.08-.16.11c-.06.02-.13.04-.19.04H9c-.07 0-.14-.02-.2-.04a.6.6 0 0 1-.16-.11.6.6 0 0 1-.11-.16.6.6 0 0 1-.03-.19V9c0-.07.01-.14.03-.2.03-.06.06-.11.11-.16s.1-.08.16-.11c.06-.02.13-.03.2-.03',
41
- }),
42
- ],
43
- )
44
- </script>
45
-
46
- <template>
47
- <div class="chat-add-header">
48
- <h1 class="chat-add-header__title">OpenTiny NEXT</h1>
49
- <div class="chat-add-header__actions">
50
- <TrIconButton :icon="IconNewSession" size="28" svg-size="20" title="新会话" @click="emit('newSession')" />
51
- <span class="chat-add-header__history-trigger">
52
- <TrIconButton
53
- :icon="IconHistory"
54
- size="28"
55
- svg-size="20"
56
- title="历史会话"
57
- @click="emit('update:showHistory', !props.showHistory)"
58
- />
59
- <div v-if="props.showHistory" class="chat-add-header__history-panel">
60
- <div class="chat-add-header__history-head">
61
- <h2>历史对话</h2>
62
- <TrIconButton
63
- :icon="IconClose"
64
- size="28"
65
- svg-size="20"
66
- title="关闭历史对话"
67
- @click="emit('update:showHistory', false)"
68
- />
69
- </div>
70
- <!-- @vue-generic {ChatHistoryItem} -->
71
- <TrHistory
72
- class="chat-add-header__history"
73
- :selected="props.activeConversationId"
74
- :search-bar="true"
75
- :data="props.historyData as ChatHistoryItem[]"
76
- @item-title-change="(title, item) => emit('renameHistory', title, item)"
77
- @item-click="(item) => emit('selectHistory', item)"
78
- @item-action="(action, item) => emit('historyAction', action, item)"
79
- />
80
- </div>
81
- </span>
82
- <TrIconButton
83
- v-if="props.displayMode === 'fullscreen'"
84
- :icon="IconFloatWindow"
85
- size="28"
86
- svg-size="20"
87
- title="切换为悬浮窗口"
88
- aria-label="切换为悬浮窗口"
89
- @click="emit('changeMode', 'floating')"
90
- />
91
- <TrIconButton
92
- v-if="props.displayMode !== 'fullscreen'"
93
- :icon="IconEnterFullScreen"
94
- size="28"
95
- svg-size="20"
96
- title="切换为全屏模式"
97
- aria-label="切换为全屏模式"
98
- @click="emit('changeMode', 'fullscreen')"
99
- />
100
- <TrIconButton :icon="IconClose" size="28" svg-size="20" title="关闭" @click="emit('close')" />
101
- </div>
102
- </div>
103
- </template>
104
-
105
- <style scoped>
106
- .chat-add-header {
107
- position: relative;
108
- display: flex;
109
- align-items: center;
110
- justify-content: space-between;
111
- box-sizing: border-box;
112
- min-width: 0;
113
- height: 56px;
114
- padding: 0 16px;
115
- background: var(--tr-layout-bg-default);
116
- }
117
- .chat-add-header__title {
118
- overflow: hidden;
119
- margin: 0;
120
- color: var(--tr-text-primary);
121
- font-size: 16px;
122
- font-weight: 600;
123
- line-height: 24px;
124
- text-overflow: ellipsis;
125
- white-space: nowrap;
126
- }
127
- .chat-add-header__actions {
128
- display: flex;
129
- flex-shrink: 0;
130
- align-items: center;
131
- gap: 4px;
132
- }
133
- .chat-add-header__history-trigger {
134
- position: relative;
135
- display: inline-flex;
136
- line-height: 0;
137
- }
138
- .chat-add-header__history-panel {
139
- position: absolute;
140
- top: calc(100% + 8px);
141
- right: 0;
142
- z-index: var(--tr-z-index-popover);
143
- display: flex;
144
- box-sizing: border-box;
145
- flex-direction: column;
146
- gap: 12px;
147
- width: 320px;
148
- height: 560px;
149
- padding: 16px;
150
- overflow: hidden;
151
- border: 1px solid var(--tr-border-color-default);
152
- border-radius: 12px;
153
- background: var(--tr-container-bg-default);
154
- box-shadow: var(--tr-shadow-sm);
155
- }
156
- .chat-add-header__history-head {
157
- display: flex;
158
- align-items: center;
159
- justify-content: space-between;
160
- flex-shrink: 0;
161
- }
162
- .chat-add-header__history-head h2 {
163
- margin: 0;
164
- color: var(--tr-text-primary);
165
- font-size: 16px;
166
- line-height: 24px;
167
- }
168
- .chat-add-header__history {
169
- min-height: 0;
170
- overflow-y: auto;
171
- flex: 1;
172
- }
173
- .chat-add-header__history {
174
- --tr-history-item-selected-bg: var(--tr-history-item-hover-bg);
175
- --tr-history-item-selected-color: var(--tr-color-primary);
176
- --tr-history-item-space-y: 4px;
177
- }
178
- @media (max-width: 640px) {
179
- .chat-add-header {
180
- height: 52px;
181
- padding: 0 10px;
182
- }
183
- .chat-add-header__history-panel {
184
- position: fixed;
185
- top: 52px;
186
- right: 8px;
187
- left: 8px;
188
- width: auto;
189
- height: min(560px, calc(100dvh - 68px));
190
- }
191
- }
192
- </style>