@veltra/ai 2.0.0 → 2.1.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 (70) hide show
  1. package/dist/chat/index.d.ts +2 -2
  2. package/dist/chat/transports/openai.js +1 -1
  3. package/dist/chat/transports/openai.js.map +1 -1
  4. package/dist/chat/types.d.ts +37 -2
  5. package/dist/chat/use-chat.d.ts +23 -1
  6. package/dist/chat/use-chat.js +83 -8
  7. package/dist/chat/use-chat.js.map +1 -1
  8. package/dist/components/ai-chat/ai-chat.js +207 -46
  9. package/dist/components/ai-chat/ai-chat.js.map +1 -1
  10. package/dist/components/ai-chat/chat-input.js +37 -12
  11. package/dist/components/ai-chat/chat-input.js.map +1 -1
  12. package/dist/components/ai-chat/di.js.map +1 -1
  13. package/dist/components/ai-chat/message-item.js +101 -23
  14. package/dist/components/ai-chat/message-item.js.map +1 -1
  15. package/dist/components/ai-chat/message-list.js +217 -32
  16. package/dist/components/ai-chat/message-list.js.map +1 -1
  17. package/dist/components/ai-chat/model-picker.js +69 -46
  18. package/dist/components/ai-chat/model-picker.js.map +1 -1
  19. package/dist/components/ai-chat/queue-list.js +70 -0
  20. package/dist/components/ai-chat/queue-list.js.map +1 -0
  21. package/dist/components/ai-chat/side-panel.js +96 -0
  22. package/dist/components/ai-chat/side-panel.js.map +1 -0
  23. package/dist/components/ai-chat/style.d.ts +4 -0
  24. package/dist/components/ai-chat/style.js +4 -0
  25. package/dist/components/ai-chat/style2.css +457 -74
  26. package/dist/components/ai-chat/tool-call.js +60 -26
  27. package/dist/components/ai-chat/tool-call.js.map +1 -1
  28. package/dist/components/ai-orb/ai-orb.js +94 -0
  29. package/dist/components/ai-orb/ai-orb.js.map +1 -0
  30. package/dist/components/ai-orb/orb-renderer.js +411 -0
  31. package/dist/components/ai-orb/orb-renderer.js.map +1 -0
  32. package/dist/components/ai-orb/style.d.ts +1 -0
  33. package/dist/components/ai-orb/style.js +1 -0
  34. package/dist/components/ai-orb/style2.css +23 -0
  35. package/dist/index.d.ts +4 -2
  36. package/dist/index.js +2 -1
  37. package/dist/style.js +1 -0
  38. package/dist/types/ai-chat.d.ts +21 -7
  39. package/dist/types/ai-orb.d.ts +27 -0
  40. package/dist/types/index.d.ts +2 -1
  41. package/package.json +5 -5
  42. package/src/chat/__test__/use-chat.test.ts +224 -9
  43. package/src/chat/transports/__test__/openai.test.ts +78 -0
  44. package/src/chat/transports/openai.ts +2 -2
  45. package/src/chat/types.ts +37 -1
  46. package/src/chat/use-chat.ts +112 -9
  47. package/src/components/ai-chat/__test__/ai-chat.test.ts +588 -11
  48. package/src/components/ai-chat/ai-chat.vue +227 -31
  49. package/src/components/ai-chat/chat-input.vue +41 -11
  50. package/src/components/ai-chat/di.ts +2 -0
  51. package/src/components/ai-chat/message-item.vue +98 -11
  52. package/src/components/ai-chat/message-list.vue +261 -21
  53. package/src/components/ai-chat/model-picker.vue +110 -59
  54. package/src/components/ai-chat/queue-list.vue +63 -0
  55. package/src/components/ai-chat/side-panel.vue +76 -0
  56. package/src/components/ai-chat/style.scss +527 -74
  57. package/src/components/ai-chat/style.ts +4 -0
  58. package/src/components/ai-chat/tool-call.vue +86 -42
  59. package/src/components/ai-orb/__test__/ai-orb.test.ts +251 -0
  60. package/src/components/ai-orb/ai-orb.vue +107 -0
  61. package/src/components/ai-orb/index.ts +1 -0
  62. package/src/components/ai-orb/orb-renderer.ts +505 -0
  63. package/src/components/ai-orb/style.scss +10 -0
  64. package/src/components/ai-orb/style.ts +1 -0
  65. package/src/components/index.ts +1 -0
  66. package/src/style.ts +1 -0
  67. package/src/tools/ask-question/__test__/ask-question.test.ts +1 -1
  68. package/src/types/ai-chat.ts +21 -6
  69. package/src/types/ai-orb.ts +27 -0
  70. package/src/types/index.ts +1 -0
@@ -5,26 +5,314 @@
5
5
  $root-name: ai-chat;
6
6
 
7
7
  @include m.b($root-name) {
8
- display: flex;
9
- flex-direction: column;
10
8
  height: 100%;
11
9
  min-height: 0;
12
10
  font-size: fn.use-var(font-size-main, default);
13
11
  color: fn.use-var(text-color, main);
12
+ // 底层背景与卡片(输入区 / 侧面板等 bg-color-top 元素)形成柔和对比,替代分割线
13
+ background-color: fn.use-var(bg-color, bottom);
14
14
 
15
- @include m.e(list) {
16
- flex: 1;
15
+ // 会话主列(消息列表 + 队列 + 输入区):内容限宽居中,面板开合时排版不形变
16
+ @include m.e(main) {
17
+ min-width: 0;
17
18
  min-height: 0;
19
+ display: flex;
20
+ flex-direction: column;
21
+ align-items: center;
22
+ padding: 0 fn.use-var(gap, default);
23
+
24
+ // 空会话:列表区与末尾占位各分一半剩余空间,输入区垂直居中,
25
+ // 欢迎区(orb + 快捷提问)贴于输入区上方并与之左对齐;有消息后自动回落到底部
26
+ @include m.is(empty) {
27
+ &::after {
28
+ content: '';
29
+ flex: 1;
30
+ }
31
+ }
18
32
  }
19
33
 
20
- @include m.e(welcome) {
34
+ // 拖拽中:固定光标,并禁用面板内容指针事件(避免 iframe 等内容吞掉 mousemove)
35
+ @include m.is(resizing) {
36
+ cursor: col-resize;
37
+
38
+ .u-#{$root-name}__panel-body {
39
+ pointer-events: none;
40
+ }
41
+ }
42
+
43
+ // 右侧侧边面板(renderTo: 'panel' 的工具渲染区),宽度由 ULayout 列轨控制。
44
+ // 悬浮卡片形态:面板本体透明,以内边距让出与会话区的间距(代替生硬的左分割线),
45
+ // 圆角卡片仅靠底层背景对比与阴影区分;面板元素始终保持整轨宽度,避免宽度观测回环
46
+ @include m.e(panel) {
47
+ min-width: 0;
48
+ padding: fn.use-var(gap, small);
49
+ padding-left: calc(fn.use-var(gap, small) / 2);
50
+ box-sizing: border-box;
51
+ animation: u-ai-chat-panel-in 0.2s ease-out;
52
+
53
+ @media (prefers-reduced-motion: reduce) {
54
+ animation: none;
55
+ }
56
+ }
57
+
58
+ @include m.e(panel-card) {
59
+ display: flex;
60
+ flex-direction: column;
21
61
  height: 100%;
62
+ min-height: 0;
63
+ overflow: hidden;
64
+ border-radius: fn.use-var(radius, large);
65
+ background-color: fn.use-var(bg-color, top);
66
+ box-shadow: fn.use-var(shadow, sm);
67
+ }
68
+
69
+ @keyframes u-ai-chat-panel-in {
70
+ from {
71
+ transform: translateX(16px);
72
+ opacity: 0;
73
+ }
74
+
75
+ to {
76
+ transform: translateX(0);
77
+ opacity: 1;
78
+ }
79
+ }
80
+
81
+ // 面板头部:无下分割线,靠留白与卡片边界区分内容区
82
+ @include m.e(panel-header) {
83
+ flex: none;
84
+ @include m.flex(flex, flex-start, center);
85
+ gap: fn.use-var(gap, small);
86
+ padding: fn.use-var(gap, default);
87
+ padding-bottom: fn.use-var(gap, small);
88
+ }
89
+
90
+ // 头部图标做成圆角底托,状态色只作用于图标本身
91
+ @include m.e(panel-icon) {
92
+ flex-shrink: 0;
93
+ width: 26px;
94
+ height: 26px;
95
+ border-radius: fn.use-var(radius, small);
96
+ background-color: fn.use-var(bg-color, middle);
97
+ font-size: 14px;
22
98
  @include m.flex(flex, center, center);
99
+
100
+ @include m.is(active) {
101
+ color: fn.use-var(color, primary);
102
+ }
103
+
104
+ @include m.is(warning) {
105
+ color: fn.use-var(color, warning);
106
+ }
107
+
108
+ @include m.is(success) {
109
+ color: fn.use-var(color, success);
110
+ }
111
+
112
+ @include m.is(danger) {
113
+ color: fn.use-var(color, danger);
114
+ }
115
+ }
116
+
117
+ @include m.e(panel-title) {
118
+ flex: 1;
119
+ min-width: 0;
120
+ @include m.ellipsis;
121
+ font-weight: 600;
122
+ color: fn.use-var(text-color, title);
123
+ }
124
+
125
+ @include m.e(panel-close) {
126
+ flex-shrink: 0;
127
+ width: 22px;
128
+ height: 22px;
129
+ border-radius: 50%;
130
+ cursor: pointer;
23
131
  color: fn.use-var(text-color, assist);
132
+ transition:
133
+ color 0.15s ease,
134
+ background-color 0.15s ease;
135
+ @include m.flex(flex, center, center);
136
+
137
+ &:hover {
138
+ color: fn.use-var(text-color, main);
139
+ background-color: fn.use-var(bg-color, hover);
140
+ }
141
+ }
142
+
143
+ @include m.e(panel-body) {
144
+ flex: 1;
145
+ min-height: 0;
146
+ }
147
+
148
+ @include m.e(panel-fallback) {
149
+ margin: 0;
24
150
  padding: fn.use-var(gap, default);
151
+ font-family: fn.use-var(font-family, code);
152
+ font-size: fn.use-var(font-size-main, small);
153
+ line-height: 1.5;
154
+ white-space: pre-wrap;
155
+ word-break: break-all;
156
+ }
157
+
158
+ // 面板工具卡片内的「查看面板」入口
159
+ @include m.e(tool-call-panel-entry) {
160
+ @include m.flex(flex, flex-start, center);
161
+ gap: fn.use-var(gap, small);
162
+ }
163
+
164
+ @include m.e(tool-call-panel-hint) {
165
+ color: fn.use-var(text-color, assist);
166
+ }
167
+
168
+ @include m.e(list-wrap) {
169
+ position: relative;
170
+ flex: 1;
171
+ min-height: 0;
172
+ width: 100%;
173
+ max-width: 800px;
174
+ display: flex;
175
+ flex-direction: column;
176
+ }
177
+
178
+ @include m.e(list) {
179
+ flex: 1;
180
+ min-height: 0;
181
+
182
+ // 内容不足一屏时撑满滚动视口并按列排布,空会话欢迎区才能占满整列做底部对齐
183
+ .u-scroll__content {
184
+ min-height: 100%;
185
+ display: flex;
186
+ flex-direction: column;
187
+ }
188
+ }
189
+
190
+ // 欢迎区仅在空会话渲染:占满整列并底部对齐,使其贴在居中的输入区上方
191
+ @include m.e(welcome) {
192
+ flex: 1;
193
+ @include m.flex(flex, center, flex-end);
194
+ color: fn.use-var(text-color, assist);
195
+ padding: fn.use-var(gap, default) 0;
25
196
  text-align: center;
26
197
  }
27
198
 
199
+ @include m.e(welcome-inner) {
200
+ // 固定锚点:球钉在左侧不动(与输入框左对齐),文本气泡只向右延展
201
+ //(轮换 / 不同长度文案都不会让球瞬移)
202
+ @include m.flex(flex, flex-start, center);
203
+ gap: fn.use-var(gap, default);
204
+ width: 100%;
205
+ }
206
+
207
+ @include m.e(welcome-item-wrap) {
208
+ flex: 1;
209
+ min-width: 0;
210
+ display: flex;
211
+ align-items: center;
212
+ // 预留两行高度:长文案换行时行高不抖动
213
+ min-height: 54px;
214
+ }
215
+
216
+ @include m.e(welcome-item) {
217
+ max-width: 100%;
218
+ padding: fn.use-var(gap, small) fn.use-var(gap, default);
219
+ border: none;
220
+ border-radius: fn.use-var(radius, large);
221
+ background-color: fn.use-var(bg-color, top);
222
+ color: fn.use-var(text-color, second);
223
+ font-size: 13px;
224
+ text-align: left;
225
+ cursor: pointer;
226
+ transition:
227
+ color 0.15s ease,
228
+ background-color 0.15s ease;
229
+
230
+ &:hover {
231
+ color: fn.use-var(color, primary);
232
+ background-color: fn.use-var(color, primary, 'light-9');
233
+ }
234
+ }
235
+
236
+ // 欢迎语逐条轮换的切换过渡
237
+ @include m.em(welcome, 'swap-enter-active') {
238
+ transition:
239
+ opacity 0.18s ease,
240
+ transform 0.18s ease;
241
+ }
242
+
243
+ @include m.em(welcome, 'swap-leave-active') {
244
+ transition:
245
+ opacity 0.12s ease,
246
+ transform 0.12s ease;
247
+ }
248
+
249
+ @include m.em(welcome, 'swap-enter-from') {
250
+ opacity: 0;
251
+ transform: translateY(6px);
252
+ }
253
+
254
+ @include m.em(welcome, 'swap-leave-to') {
255
+ opacity: 0;
256
+ transform: translateY(-6px);
257
+ }
258
+
259
+ // 生成中的统一工作状态指示(列表末尾)
260
+ @include m.e(working) {
261
+ @include m.flex(flex, flex-start, center);
262
+ gap: fn.use-var(gap, small);
263
+ padding: 0 fn.use-var(gap, default) fn.use-var(gap, small);
264
+ }
265
+
266
+ @include m.e(working-text) {
267
+ font-size: fn.use-var(font-size-main, small);
268
+ }
269
+
270
+ // 「最新消息」悬浮按钮:上翻浏览时出现,点击回到底部
271
+ @include m.e(to-latest) {
272
+ position: absolute;
273
+ top: fn.use-var(gap, small);
274
+ left: 50%;
275
+ transform: translateX(-50%);
276
+ z-index: 1;
277
+ @include m.flex(flex, center, center);
278
+ gap: 4px;
279
+ padding: 4px 12px;
280
+ border: none;
281
+ border-radius: 999px;
282
+ background-color: fn.use-var(bg-color, top);
283
+ color: fn.use-var(text-color, second);
284
+ font-size: fn.use-var(font-size-main, small);
285
+ box-shadow: 0 2px 8px fn.color-a(shadow, 20, color);
286
+ cursor: pointer;
287
+ transition: color 0.15s ease;
288
+
289
+ &:hover {
290
+ color: fn.use-var(color, primary);
291
+ }
292
+ }
293
+
294
+ @include m.em(to-latest, 'fade-enter-active') {
295
+ transition:
296
+ opacity 0.15s ease,
297
+ transform 0.15s ease;
298
+ }
299
+
300
+ @include m.em(to-latest, 'fade-leave-active') {
301
+ transition:
302
+ opacity 0.1s ease,
303
+ transform 0.1s ease;
304
+ }
305
+
306
+ @include m.em(to-latest, 'fade-enter-from') {
307
+ opacity: 0;
308
+ transform: translateX(-50%) translateY(-4px);
309
+ }
310
+
311
+ @include m.em(to-latest, 'fade-leave-to') {
312
+ opacity: 0;
313
+ transform: translateX(-50%) translateY(-4px);
314
+ }
315
+
28
316
  @include m.e(message) {
29
317
  padding: fn.use-var(gap, small) fn.use-var(gap, default);
30
318
 
@@ -63,7 +351,33 @@ $root-name: ai-chat;
63
351
  }
64
352
 
65
353
  @include m.e(message-content) {
66
- line-height: 1.7;
354
+ font-size: 13px;
355
+ line-height: 1.6;
356
+ // 压缩 markstream 流式排版:正文字号 / 行高 / 标题档位 / 块级间距(变量见 markstream-vue 样式表)
357
+ --ms-text-body: 13px;
358
+ --ms-leading-body: 1.6;
359
+ --ms-text-h1: 1.55em;
360
+ --ms-text-h2: 1.35em;
361
+ --ms-text-h3: 1.15em;
362
+ --ms-text-h4: 1em;
363
+ --ms-text-h5: 1em;
364
+ --ms-text-h6: 1em;
365
+ --ms-flow-heading-1-mt: 0.9em;
366
+ --ms-flow-heading-1-mb: 0.35em;
367
+ --ms-flow-heading-2-mt: 0.8em;
368
+ --ms-flow-heading-2-mb: 0.3em;
369
+ --ms-flow-heading-3-mt: 0.7em;
370
+ --ms-flow-heading-3-mb: 0.25em;
371
+ --ms-flow-paragraph-y: 0.55em;
372
+ --ms-flow-list-y: 0.45em;
373
+ --ms-flow-list-item-y: 0.08em;
374
+ --ms-flow-list-indent: 1.3em;
375
+ --ms-flow-codeblock-y: 0.7em;
376
+ --ms-flow-blockquote-y: 0.55em;
377
+ --ms-flow-table-y: 0.7em;
378
+ --ms-flow-hr-y: 0.9em;
379
+ --ms-flow-admonition-y: 0.7em;
380
+ --ms-flow-diagram-y: 0.7em;
67
381
  }
68
382
 
69
383
  @include m.e(message-status) {
@@ -73,61 +387,92 @@ $root-name: ai-chat;
73
387
  }
74
388
 
75
389
  @include m.e(message-actions) {
76
- margin-top: fn.use-var(gap, small);
77
- color: fn.use-var(text-color, assist);
78
- cursor: pointer;
79
- display: inline-flex;
80
-
81
- &:hover {
82
- color: fn.use-var(color, primary);
83
- }
390
+ display: flex;
391
+ flex-wrap: wrap;
392
+ gap: fn.use-var(gap, small);
84
393
  }
85
394
 
86
395
  // 思考过程
87
396
  @include m.e(reasoning) {
88
- margin-bottom: fn.use-var(gap, small);
397
+ margin-bottom: 4px;
89
398
  color: fn.use-var(text-color, assist);
90
399
 
91
400
  @include m.is(expanded) {
92
401
  @include m.bem($root-name, 'reasoning-chevron') {
93
- transform: rotate(180deg);
402
+ transform: rotate(90deg);
94
403
  }
95
404
  }
96
405
  }
97
406
 
98
407
  @include m.e(reasoning-header) {
99
408
  @include m.flex(flex, flex-start, center);
100
- gap: fn.use-var(gap, small);
409
+ gap: 4px;
101
410
  cursor: pointer;
102
411
  user-select: none;
103
412
  font-size: fn.use-var(font-size-main, small);
104
413
  }
105
414
 
415
+ @include m.e(reasoning-title) {
416
+ line-height: 1.5;
417
+ }
418
+
106
419
  @include m.e(reasoning-chevron) {
420
+ font-size: 12px;
107
421
  transition: transform 0.2s;
108
422
  }
109
423
 
110
424
  @include m.e(reasoning-content) {
111
- margin-top: fn.use-var(gap, small);
112
- padding-left: fn.use-var(gap, default);
425
+ margin-top: 4px;
426
+ padding-left: fn.use-var(gap, small);
113
427
  border-left: fn.use-var(border-muted);
428
+ }
429
+
430
+ @include m.e(reasoning-text) {
431
+ padding-right: 4px;
114
432
  white-space: pre-wrap;
115
433
  word-break: break-word;
116
434
  font-size: fn.use-var(font-size-main, small);
117
- line-height: 1.6;
435
+ line-height: 1.55;
118
436
  }
119
437
 
120
- // 工具调用卡片
438
+ // 工具调用卡片(复用 UCollapseItem:头部经 #header 插槽自定义,body 为折叠内容区)
121
439
  @include m.e(tool-call) {
122
- margin: fn.use-var(gap, small) 0;
440
+ margin: 4px 0;
441
+ background-color: fn.use-var(bg-color, top);
442
+ font-size: fn.use-var(font-size-main, small);
443
+
444
+ // 相邻工具卡片保持紧凑间距(覆盖 UCollapseItem 的兄弟间距)
445
+ & + #{fn.bem($root-name, tool-call)} {
446
+ margin-top: 4px;
447
+ }
448
+
449
+ // 覆盖 UCollapseItem 默认头部/内容区节奏,保持紧凑单行头
450
+ .u-collapse__header {
451
+ gap: 6px;
452
+ padding: 5px fn.use-var(gap, small);
453
+ font-weight: 400;
454
+ letter-spacing: normal;
455
+ }
456
+
457
+ .u-collapse__content {
458
+ border-top: fn.use-var(border-muted);
459
+ padding: fn.use-var(gap, small);
460
+ line-height: 1.5;
461
+ }
462
+ }
463
+
464
+ @include m.e(tool-call-chevron) {
465
+ flex-shrink: 0;
466
+ font-size: 12px;
467
+ color: fn.use-var(text-color, assist);
123
468
  }
124
469
 
125
470
  @include m.e(tool-call-status) {
126
471
  flex-shrink: 0;
472
+ font-size: 13px;
127
473
 
128
- @include m.is(loading) {
474
+ @include m.is(active) {
129
475
  color: fn.use-var(color, primary);
130
- animation: u-ai-chat-rotate 1s linear infinite;
131
476
  }
132
477
 
133
478
  @include m.is(warning) {
@@ -144,8 +489,7 @@ $root-name: ai-chat;
144
489
  }
145
490
 
146
491
  @include m.e(tool-call-name) {
147
- font-family: fn.use-var(font-family, code);
148
- font-size: fn.use-var(font-size-main, small);
492
+ font-weight: 500;
149
493
  color: fn.use-var(text-color, title);
150
494
  flex-shrink: 0;
151
495
  }
@@ -155,31 +499,34 @@ $root-name: ai-chat;
155
499
  min-width: 0;
156
500
  @include m.ellipsis;
157
501
  color: fn.use-var(text-color, assist);
158
- font-size: fn.use-var(font-size-main, small);
159
502
  }
160
503
 
161
504
  @include m.e(tool-call-confirm) {
162
505
  flex-shrink: 0;
163
506
  @include m.flex(flex, flex-start, center);
164
- gap: fn.use-var(gap, small);
507
+ gap: 4px;
165
508
  }
166
509
 
167
510
  @include m.e(tool-call-section) {
168
- font-size: fn.use-var(font-size-main, small);
169
511
  color: fn.use-var(text-color, assist);
170
- margin: fn.use-var(gap, small) 0;
512
+ margin-bottom: 4px;
513
+
514
+ &:not(:first-child) {
515
+ margin-top: fn.use-var(gap, small);
516
+ }
171
517
  }
172
518
 
173
519
  @include m.e(tool-call-code) {
174
520
  margin: 0;
175
- padding: fn.use-var(gap, small);
176
- border-radius: fn.use-var(radius, default);
521
+ padding: 4px fn.use-var(gap, small);
522
+ border-radius: fn.use-var(radius, small);
177
523
  background-color: fn.use-var(bg-color, bottom);
178
524
  font-family: fn.use-var(font-family, code);
179
525
  font-size: fn.use-var(font-size-main, small);
526
+ line-height: 1.5;
180
527
  white-space: pre-wrap;
181
528
  word-break: break-all;
182
- max-height: 240px;
529
+ max-height: 200px;
183
530
  overflow: auto;
184
531
  }
185
532
 
@@ -339,18 +686,88 @@ $root-name: ai-chat;
339
686
  color: fn.use-var(text-color, assist);
340
687
  }
341
688
 
342
- // 输入区
689
+ // 待发送队列(生成中提交的消息在此排队)
690
+ @include m.e(queue) {
691
+ flex-shrink: 0;
692
+ width: 100%;
693
+ max-width: 800px;
694
+ box-sizing: border-box;
695
+ margin-bottom: 4px;
696
+ border-radius: fn.use-var(radius, default);
697
+ background-color: fn.use-var(bg-color, middle);
698
+ padding: 4px;
699
+ font-size: fn.use-var(font-size-main, small);
700
+ }
701
+
702
+ @include m.e(queue-head) {
703
+ padding: 2px 6px;
704
+ color: fn.use-var(text-color, assist);
705
+ }
706
+
707
+ @include m.e(queue-item) {
708
+ @include m.flex(flex, flex-start, center);
709
+ gap: 6px;
710
+ padding: 3px 6px;
711
+ border-radius: fn.use-var(radius, small);
712
+
713
+ &:hover {
714
+ background-color: fn.use-var(bg-color, hover);
715
+ }
716
+ }
717
+
718
+ @include m.e(queue-text) {
719
+ flex: 1;
720
+ min-width: 0;
721
+ @include m.ellipsis;
722
+ color: fn.use-var(text-color, main);
723
+ }
724
+
725
+ @include m.e(queue-actions) {
726
+ flex-shrink: 0;
727
+ @include m.flex(flex, flex-start, center);
728
+ gap: 2px;
729
+ }
730
+
731
+ @include m.e(queue-action) {
732
+ @include m.flex(flex, flex-start, center);
733
+ gap: 2px;
734
+ border: none;
735
+ background: none;
736
+ padding: 1px 4px;
737
+ border-radius: fn.use-var(radius, small);
738
+ color: fn.use-var(text-color, assist);
739
+ font-size: inherit;
740
+ font-family: inherit;
741
+ white-space: nowrap;
742
+ cursor: pointer;
743
+ transition:
744
+ color 0.15s ease,
745
+ background-color 0.15s ease;
746
+
747
+ &:hover {
748
+ color: fn.use-var(color, primary);
749
+ background-color: fn.use-var(color, primary, 'light-9');
750
+ }
751
+
752
+ @include m.m(primary) {
753
+ color: fn.use-var(color, primary);
754
+ }
755
+ }
756
+
757
+ // 输入区:无边框卡片,聚焦时用柔和的主色描边提示
343
758
  @include m.e(input-area) {
344
759
  flex-shrink: 0;
345
- margin: fn.use-var(gap, default);
346
- margin-top: fn.use-var(gap, small);
347
- border: fn.use-var(border-muted);
760
+ width: 100%;
761
+ max-width: 800px;
762
+ box-sizing: border-box;
763
+ margin: fn.use-var(gap, small) 0 fn.use-var(gap, default);
348
764
  border-radius: fn.use-var(radius, large);
349
765
  background-color: fn.use-var(bg-color, top);
350
766
  padding: fn.use-var(gap, small);
767
+ transition: box-shadow 0.15s ease;
351
768
 
352
769
  &:focus-within {
353
- border-color: fn.use-var(color, primary);
770
+ box-shadow: 0 0 0 1px fn.use-var(color, primary);
354
771
  }
355
772
  }
356
773
 
@@ -477,24 +894,16 @@ $root-name: ai-chat;
477
894
  }
478
895
  }
479
896
 
480
- @keyframes u-ai-chat-rotate {
481
- from {
482
- transform: rotate(0deg);
483
- }
484
- to {
485
- transform: rotate(360deg);
486
- }
487
- }
488
-
489
897
  // 模型选择面板经 teleport 挂载到 popper 容器,不处于 .u-ai-chat 内,需独立定义
490
898
  .u-#{$root-name}__model-panel {
491
- display: flex;
492
- flex-direction: column;
493
- gap: 1px;
494
899
  padding: 4px;
495
900
  user-select: none;
496
901
 
497
- .u-#{$root-name}__model-option {
902
+ .u-#{$root-name}__model-panel-list {
903
+ min-width: 0;
904
+ }
905
+
906
+ .u-#{$root-name}__model-option-main {
498
907
  padding: 6px 8px;
499
908
  border-radius: calc(fn.use-var(radius, default) + 1px);
500
909
  cursor: pointer;
@@ -507,14 +916,59 @@ $root-name: ai-chat;
507
916
 
508
917
  .u-#{$root-name}__model-option-head {
509
918
  @include m.flex(flex, space-between, center);
510
- gap: 16px;
919
+ gap: 12px;
511
920
  color: fn.use-var(text-color, main);
512
921
  }
513
922
 
923
+ .u-#{$root-name}__model-option-name {
924
+ @include m.ellipsis;
925
+ }
926
+
927
+ .u-#{$root-name}__model-option-actions {
928
+ @include m.flex(flex, flex-start, center);
929
+ flex-shrink: 0;
930
+ gap: 6px;
931
+ }
932
+
514
933
  .u-#{$root-name}__model-option-check {
515
934
  flex-shrink: 0;
516
935
  font-size: 14px;
517
936
  color: fn.use-var(color, primary);
937
+
938
+ @include m.is(hidden) {
939
+ visibility: hidden;
940
+ }
941
+ }
942
+
943
+ .u-#{$root-name}__model-option-reasoning {
944
+ @include m.flex(flex, flex-start, center);
945
+ gap: 2px;
946
+ flex-shrink: 0;
947
+ padding: 1px 6px;
948
+ border: none;
949
+ border-radius: fn.use-var(radius, small);
950
+ background: fn.use-var(color, primary, 'light-9');
951
+ color: fn.use-var(color, primary);
952
+ font-size: fn.use-var(font-size-main, small);
953
+ cursor: pointer;
954
+ transition:
955
+ background-color 0.15s ease,
956
+ color 0.15s ease;
957
+
958
+ &:hover {
959
+ background: fn.use-var(color, primary, 'light-7');
960
+ }
961
+ }
962
+
963
+ .u-#{$root-name}__model-option-reasoning-arrow {
964
+ font-size: 12px;
965
+ transition: transform 0.2s ease;
966
+ }
967
+
968
+ .u-#{$root-name}__model-option-reasoning.is-expanded {
969
+ .u-#{$root-name}__model-option-reasoning-arrow {
970
+ transform: rotate(180deg);
971
+ }
518
972
  }
519
973
 
520
974
  .u-#{$root-name}__model-option-desc {
@@ -523,42 +977,41 @@ $root-name: ai-chat;
523
977
  color: fn.use-var(text-color, assist);
524
978
  }
525
979
 
526
- .u-#{$root-name}__model-divider {
527
- height: 0;
528
- margin: 4px 8px;
529
- border-top: 1px solid fn.use-var(border, color);
530
- }
980
+ // 内联思考强度:grid 行高 0fr → 1fr 过渡,展开/收起平滑无跳变
981
+ .u-#{$root-name}__reasoning-levels {
982
+ display: grid;
983
+ grid-template-rows: 0fr;
984
+ transition: grid-template-rows 0.2s cubic-bezier(0.4, 0, 0.2, 1);
531
985
 
532
- .u-#{$root-name}__reasoning-row {
533
- @include m.flex(flex, space-between, center);
534
- padding: 6px 8px;
535
- border-radius: calc(fn.use-var(radius, default) + 1px);
536
- color: fn.use-var(text-color, main);
537
- cursor: pointer;
538
- transition: background-color 0.15s ease;
539
-
540
- &:hover {
541
- background-color: var(--u-nav-hover-bg);
986
+ @include m.is(expanded) {
987
+ grid-template-rows: 1fr;
542
988
  }
543
989
  }
544
990
 
545
- .u-#{$root-name}__reasoning-row-value {
546
- @include m.flex(flex, flex-start, center);
547
- gap: 4px;
548
- color: fn.use-var(text-color, assist);
991
+ .u-#{$root-name}__reasoning-levels-inner {
992
+ min-height: 0;
993
+ overflow: hidden;
549
994
  }
550
995
 
551
996
  .u-#{$root-name}__reasoning-option {
552
997
  @include m.flex(flex, space-between, center);
553
- gap: 16px;
554
- padding: 6px 8px 6px 20px;
998
+ gap: 12px;
999
+ margin-left: 8px;
1000
+ padding: 5px 8px;
555
1001
  border-radius: calc(fn.use-var(radius, default) + 1px);
1002
+ font-size: fn.use-var(font-size-main, small);
556
1003
  color: fn.use-var(text-color, main);
557
1004
  cursor: pointer;
558
- transition: background-color 0.15s ease;
1005
+ transition:
1006
+ background-color 0.15s ease,
1007
+ color 0.15s ease;
559
1008
 
560
1009
  &:hover {
561
1010
  background-color: var(--u-nav-hover-bg);
562
1011
  }
1012
+
1013
+ @include m.is(active) {
1014
+ color: fn.use-var(color, primary);
1015
+ }
563
1016
  }
564
1017
  }