@huyooo/ai-chat-frontend-react 0.2.19 → 0.2.20
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.
- package/dist/index.css +228 -3
- package/dist/index.d.ts +62 -3
- package/dist/index.js +1 -1
- package/package.json +7 -3
package/dist/index.css
CHANGED
|
@@ -772,11 +772,11 @@
|
|
|
772
772
|
position: relative;
|
|
773
773
|
display: flex;
|
|
774
774
|
align-items: center;
|
|
775
|
-
width: 100%;
|
|
776
775
|
padding: 10px 16px;
|
|
777
776
|
background: var(--chat-muted, #2a2a2a);
|
|
778
777
|
border-radius: 8px;
|
|
779
778
|
overflow: hidden;
|
|
779
|
+
box-sizing: border-box;
|
|
780
780
|
}
|
|
781
781
|
.loading-indicator.has-content-above {
|
|
782
782
|
margin-top: 8px;
|
|
@@ -836,6 +836,64 @@
|
|
|
836
836
|
border-radius: 10px;
|
|
837
837
|
border: 1px solid var(--chat-border, #333);
|
|
838
838
|
}
|
|
839
|
+
.token-usage,
|
|
840
|
+
.response-duration {
|
|
841
|
+
display: inline-flex;
|
|
842
|
+
align-items: center;
|
|
843
|
+
gap: 3px;
|
|
844
|
+
font-size: 11px;
|
|
845
|
+
color: var(--chat-text-muted, #888);
|
|
846
|
+
cursor: default;
|
|
847
|
+
}
|
|
848
|
+
.token-usage {
|
|
849
|
+
position: relative;
|
|
850
|
+
}
|
|
851
|
+
.token-usage:hover .usage-tooltip {
|
|
852
|
+
opacity: 1;
|
|
853
|
+
visibility: visible;
|
|
854
|
+
transform: translateX(-50%) translateY(0);
|
|
855
|
+
}
|
|
856
|
+
.usage-tooltip {
|
|
857
|
+
position: absolute;
|
|
858
|
+
bottom: calc(100% + 6px);
|
|
859
|
+
left: 50%;
|
|
860
|
+
transform: translateX(-50%) translateY(4px);
|
|
861
|
+
display: flex;
|
|
862
|
+
flex-direction: column;
|
|
863
|
+
gap: 2px;
|
|
864
|
+
padding: 6px 10px;
|
|
865
|
+
background: var(--chat-bg, #1e1e1e);
|
|
866
|
+
border: 1px solid var(--chat-border, #444);
|
|
867
|
+
border-radius: 6px;
|
|
868
|
+
font-size: 11px;
|
|
869
|
+
color: var(--chat-text-muted, #aaa);
|
|
870
|
+
white-space: nowrap;
|
|
871
|
+
opacity: 0;
|
|
872
|
+
visibility: hidden;
|
|
873
|
+
transition:
|
|
874
|
+
opacity 0.15s,
|
|
875
|
+
visibility 0.15s,
|
|
876
|
+
transform 0.15s;
|
|
877
|
+
pointer-events: none;
|
|
878
|
+
z-index: 10;
|
|
879
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
880
|
+
}
|
|
881
|
+
.usage-tooltip::after {
|
|
882
|
+
content: "";
|
|
883
|
+
position: absolute;
|
|
884
|
+
top: 100%;
|
|
885
|
+
left: 50%;
|
|
886
|
+
transform: translateX(-50%);
|
|
887
|
+
border: 4px solid transparent;
|
|
888
|
+
border-top-color: var(--chat-border, #444);
|
|
889
|
+
}
|
|
890
|
+
.usage-tooltip-total {
|
|
891
|
+
border-top: 1px solid var(--chat-border, #333);
|
|
892
|
+
padding-top: 2px;
|
|
893
|
+
margin-top: 1px;
|
|
894
|
+
color: var(--chat-text, #ccc);
|
|
895
|
+
font-weight: 500;
|
|
896
|
+
}
|
|
839
897
|
.action-buttons {
|
|
840
898
|
display: flex;
|
|
841
899
|
align-items: center;
|
|
@@ -2595,6 +2653,8 @@ body {
|
|
|
2595
2653
|
/* src/components/input/DropdownSelector.css */
|
|
2596
2654
|
.dropdown-selector {
|
|
2597
2655
|
position: relative;
|
|
2656
|
+
}
|
|
2657
|
+
.dropdown-selector .selector-trigger {
|
|
2598
2658
|
display: flex;
|
|
2599
2659
|
align-items: center;
|
|
2600
2660
|
gap: 4px;
|
|
@@ -2609,12 +2669,12 @@ body {
|
|
|
2609
2669
|
cursor: pointer;
|
|
2610
2670
|
transition: all 0.15s;
|
|
2611
2671
|
}
|
|
2612
|
-
.dropdown-selector:
|
|
2672
|
+
.dropdown-selector:not(.disabled) .selector-trigger:hover {
|
|
2613
2673
|
background: rgba(0, 0, 0, 0.06);
|
|
2614
2674
|
background: color-mix(in srgb, var(--chat-text, #ccc) 10%, transparent);
|
|
2615
2675
|
color: var(--chat-text, #ccc);
|
|
2616
2676
|
}
|
|
2617
|
-
.dropdown-selector.disabled {
|
|
2677
|
+
.dropdown-selector.disabled .selector-trigger {
|
|
2618
2678
|
opacity: 0.6;
|
|
2619
2679
|
cursor: not-allowed;
|
|
2620
2680
|
}
|
|
@@ -3079,6 +3139,79 @@ body {
|
|
|
3079
3139
|
margin: 0;
|
|
3080
3140
|
}
|
|
3081
3141
|
|
|
3142
|
+
/* src/components/message/parts/PlanPart.css */
|
|
3143
|
+
.plan-steps {
|
|
3144
|
+
display: flex;
|
|
3145
|
+
flex-direction: column;
|
|
3146
|
+
gap: 6px;
|
|
3147
|
+
padding: 2px 0;
|
|
3148
|
+
}
|
|
3149
|
+
.plan-step {
|
|
3150
|
+
display: flex;
|
|
3151
|
+
align-items: center;
|
|
3152
|
+
gap: 8px;
|
|
3153
|
+
font-size: 13px;
|
|
3154
|
+
line-height: 1.5;
|
|
3155
|
+
color: var(--chat-text-muted, #999);
|
|
3156
|
+
transition: color 0.2s ease;
|
|
3157
|
+
}
|
|
3158
|
+
.plan-step--done {
|
|
3159
|
+
color: var(--chat-success, #22c55e);
|
|
3160
|
+
}
|
|
3161
|
+
.plan-step--in_progress {
|
|
3162
|
+
color: var(--chat-plan-accent, #8b5cf6);
|
|
3163
|
+
font-weight: 500;
|
|
3164
|
+
}
|
|
3165
|
+
.plan-step--failed {
|
|
3166
|
+
color: var(--chat-error, #ef4444);
|
|
3167
|
+
}
|
|
3168
|
+
.plan-step--pending {
|
|
3169
|
+
color: var(--chat-text-muted, #666);
|
|
3170
|
+
}
|
|
3171
|
+
.plan-step-icon {
|
|
3172
|
+
display: flex;
|
|
3173
|
+
align-items: center;
|
|
3174
|
+
justify-content: center;
|
|
3175
|
+
width: 16px;
|
|
3176
|
+
height: 16px;
|
|
3177
|
+
flex-shrink: 0;
|
|
3178
|
+
font-size: 12px;
|
|
3179
|
+
}
|
|
3180
|
+
.plan-icon-done {
|
|
3181
|
+
color: var(--chat-success, #22c55e);
|
|
3182
|
+
font-weight: bold;
|
|
3183
|
+
}
|
|
3184
|
+
.plan-icon-progress {
|
|
3185
|
+
display: flex;
|
|
3186
|
+
align-items: center;
|
|
3187
|
+
justify-content: center;
|
|
3188
|
+
}
|
|
3189
|
+
.plan-spinner {
|
|
3190
|
+
width: 12px;
|
|
3191
|
+
height: 12px;
|
|
3192
|
+
border: 2px solid var(--chat-plan-accent, #8b5cf6);
|
|
3193
|
+
border-top-color: transparent;
|
|
3194
|
+
border-radius: 50%;
|
|
3195
|
+
animation: plan-spin 0.8s linear infinite;
|
|
3196
|
+
}
|
|
3197
|
+
.plan-icon-failed {
|
|
3198
|
+
color: var(--chat-error, #ef4444);
|
|
3199
|
+
font-weight: bold;
|
|
3200
|
+
}
|
|
3201
|
+
.plan-icon-pending {
|
|
3202
|
+
color: var(--chat-text-muted, #666);
|
|
3203
|
+
font-size: 10px;
|
|
3204
|
+
}
|
|
3205
|
+
.plan-step-title {
|
|
3206
|
+
flex: 1;
|
|
3207
|
+
word-break: break-word;
|
|
3208
|
+
}
|
|
3209
|
+
@keyframes plan-spin {
|
|
3210
|
+
to {
|
|
3211
|
+
transform: rotate(360deg);
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3082
3215
|
/* src/components/message/PartsRenderer.css */
|
|
3083
3216
|
.parts-renderer {
|
|
3084
3217
|
display: flex;
|
|
@@ -4355,3 +4488,95 @@ body {
|
|
|
4355
4488
|
color: var(--chat-text-muted, #888);
|
|
4356
4489
|
margin-top: 8px;
|
|
4357
4490
|
}
|
|
4491
|
+
.skill-form {
|
|
4492
|
+
display: flex;
|
|
4493
|
+
flex-direction: column;
|
|
4494
|
+
gap: 8px;
|
|
4495
|
+
padding: 0 0 8px 0;
|
|
4496
|
+
}
|
|
4497
|
+
.skill-input {
|
|
4498
|
+
width: 100%;
|
|
4499
|
+
padding: 8px 12px;
|
|
4500
|
+
background: var(--chat-input-bg, #1e1e1e);
|
|
4501
|
+
border: 1px solid var(--chat-border, #333);
|
|
4502
|
+
border-radius: 6px;
|
|
4503
|
+
color: var(--chat-text, #fff);
|
|
4504
|
+
font-size: 13px;
|
|
4505
|
+
outline: none;
|
|
4506
|
+
box-sizing: border-box;
|
|
4507
|
+
}
|
|
4508
|
+
.skill-input:focus,
|
|
4509
|
+
.skill-textarea:focus {
|
|
4510
|
+
border-color: var(--chat-primary, #4f8fff);
|
|
4511
|
+
}
|
|
4512
|
+
.skill-textarea {
|
|
4513
|
+
width: 100%;
|
|
4514
|
+
padding: 8px 12px;
|
|
4515
|
+
background: var(--chat-input-bg, #1e1e1e);
|
|
4516
|
+
border: 1px solid var(--chat-border, #333);
|
|
4517
|
+
border-radius: 6px;
|
|
4518
|
+
color: var(--chat-text, #fff);
|
|
4519
|
+
font-size: 13px;
|
|
4520
|
+
outline: none;
|
|
4521
|
+
resize: vertical;
|
|
4522
|
+
font-family: inherit;
|
|
4523
|
+
box-sizing: border-box;
|
|
4524
|
+
}
|
|
4525
|
+
.skill-form-actions {
|
|
4526
|
+
display: flex;
|
|
4527
|
+
gap: 8px;
|
|
4528
|
+
justify-content: flex-end;
|
|
4529
|
+
}
|
|
4530
|
+
.skill-btn {
|
|
4531
|
+
padding: 6px 16px;
|
|
4532
|
+
border: none;
|
|
4533
|
+
border-radius: 6px;
|
|
4534
|
+
font-size: 13px;
|
|
4535
|
+
cursor: pointer;
|
|
4536
|
+
}
|
|
4537
|
+
.skill-btn-primary {
|
|
4538
|
+
background: var(--chat-primary, #4f8fff);
|
|
4539
|
+
color: #fff;
|
|
4540
|
+
}
|
|
4541
|
+
.skill-btn-primary:disabled {
|
|
4542
|
+
opacity: 0.5;
|
|
4543
|
+
cursor: not-allowed;
|
|
4544
|
+
}
|
|
4545
|
+
.skill-btn-secondary {
|
|
4546
|
+
background: var(--chat-border, #333);
|
|
4547
|
+
color: var(--chat-text, #fff);
|
|
4548
|
+
}
|
|
4549
|
+
.skill-actions {
|
|
4550
|
+
display: flex;
|
|
4551
|
+
align-items: center;
|
|
4552
|
+
gap: 4px;
|
|
4553
|
+
flex-shrink: 0;
|
|
4554
|
+
}
|
|
4555
|
+
.skill-action-btn {
|
|
4556
|
+
display: flex;
|
|
4557
|
+
align-items: center;
|
|
4558
|
+
justify-content: center;
|
|
4559
|
+
width: 28px;
|
|
4560
|
+
height: 28px;
|
|
4561
|
+
border: none;
|
|
4562
|
+
background: transparent;
|
|
4563
|
+
color: var(--chat-text-muted, #888);
|
|
4564
|
+
border-radius: 4px;
|
|
4565
|
+
cursor: pointer;
|
|
4566
|
+
}
|
|
4567
|
+
.skill-action-btn:hover {
|
|
4568
|
+
background: var(--chat-border, #333);
|
|
4569
|
+
color: var(--chat-text, #fff);
|
|
4570
|
+
}
|
|
4571
|
+
.skill-action-delete:hover {
|
|
4572
|
+
color: var(--chat-error, #ef4444);
|
|
4573
|
+
}
|
|
4574
|
+
.skill-badge {
|
|
4575
|
+
display: inline-block;
|
|
4576
|
+
margin-left: 6px;
|
|
4577
|
+
padding: 1px 6px;
|
|
4578
|
+
font-size: 11px;
|
|
4579
|
+
color: var(--chat-text-muted, #888);
|
|
4580
|
+
background: var(--chat-border, #333);
|
|
4581
|
+
border-radius: 4px;
|
|
4582
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export { ChatAdapter, ChatEvent, ChatEventType, ChatMode, ChatOptions, MessageRecord, ModelOption, ProviderType, SessionRecord, ThinkingMode } from '@huyooo/ai-chat-types';
|
|
2
|
+
import { ChatMode as ChatMode$1, ThinkingMode, ModelOption as ModelOption$1, SessionRecord as SessionRecord$1, ChatAdapter, AutoRunConfig, SkillRecord } from '@huyooo/ai-chat-bridge-electron/renderer';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
import { FC, ReactNode, ComponentType } from 'react';
|
|
5
5
|
export { CodeBlock as CodeBlockType, ContentBlock, ContentBlockType, SearchResultItem, TextBlock as TextBlockType, WeatherData, getLanguageDisplayName, highlightCode, parseContent, renderMarkdown } from '@huyooo/ai-chat-shared';
|
|
@@ -125,6 +125,18 @@ interface ErrorPart$1 {
|
|
|
125
125
|
category?: string;
|
|
126
126
|
retryable?: boolean;
|
|
127
127
|
}
|
|
128
|
+
/** 计划步骤 */
|
|
129
|
+
interface PlanStepItem {
|
|
130
|
+
id: string;
|
|
131
|
+
title: string;
|
|
132
|
+
status: 'pending' | 'in_progress' | 'done' | 'failed';
|
|
133
|
+
}
|
|
134
|
+
/** 计划进度 Part(由 update_plan 工具的 resultType:'plan' 生成) */
|
|
135
|
+
interface PlanPart {
|
|
136
|
+
type: 'plan';
|
|
137
|
+
steps: PlanStepItem[];
|
|
138
|
+
status: 'running' | 'done';
|
|
139
|
+
}
|
|
128
140
|
/** 天气 Part(由 get_weather 工具生成)*/
|
|
129
141
|
interface WeatherPart {
|
|
130
142
|
type: 'weather';
|
|
@@ -142,7 +154,7 @@ interface CustomPart {
|
|
|
142
154
|
[key: string]: unknown;
|
|
143
155
|
}
|
|
144
156
|
/** 内置 Part 联合类型 */
|
|
145
|
-
type BuiltinPart = TextPart$1 | CodePart | ThinkingPart$1 | SearchPart$1 | ToolCallPart$1 | ImagePart$1 | ErrorPart$1;
|
|
157
|
+
type BuiltinPart = TextPart$1 | CodePart | ThinkingPart$1 | SearchPart$1 | ToolCallPart$1 | ImagePart$1 | ErrorPart$1 | PlanPart;
|
|
146
158
|
/** 内容 Part 联合类型(包含内置和扩展类型)*/
|
|
147
159
|
type ContentPart = BuiltinPart | WeatherPart | CustomPart;
|
|
148
160
|
/** 内容 Part 类型字符串 */
|
|
@@ -176,6 +188,8 @@ interface ChatMessage {
|
|
|
176
188
|
images?: string[];
|
|
177
189
|
/** 是否正在加载 */
|
|
178
190
|
loading?: boolean;
|
|
191
|
+
/** Agent 当前阶段(后端通过 agent_status 事件推送,thinking=显示 loading) */
|
|
192
|
+
agentPhase?: 'thinking';
|
|
179
193
|
/** 是否已复制 */
|
|
180
194
|
copied?: boolean;
|
|
181
195
|
/** 消息时间戳 */
|
|
@@ -184,6 +198,23 @@ interface ChatMessage {
|
|
|
184
198
|
error?: ErrorDetails;
|
|
185
199
|
/** 是否被用户中止 */
|
|
186
200
|
aborted?: boolean;
|
|
201
|
+
/** Token 使用统计(done 事件携带) */
|
|
202
|
+
usage?: {
|
|
203
|
+
promptTokens: number;
|
|
204
|
+
completionTokens: number;
|
|
205
|
+
totalTokens: number;
|
|
206
|
+
reasoningTokens?: number;
|
|
207
|
+
cachedTokens?: number;
|
|
208
|
+
};
|
|
209
|
+
/** 响应耗时(毫秒) */
|
|
210
|
+
duration?: number;
|
|
211
|
+
/** 计费信息(云端模式,done 后由 ai-server 返回) */
|
|
212
|
+
billing?: {
|
|
213
|
+
pointsConsumed: number;
|
|
214
|
+
remainingPoints: number;
|
|
215
|
+
costYuan?: number;
|
|
216
|
+
model?: string;
|
|
217
|
+
};
|
|
187
218
|
}
|
|
188
219
|
/** 获取消息的纯文本内容(用于复制、保存等) */
|
|
189
220
|
declare function getMessageText(message: ChatMessage): string;
|
|
@@ -275,6 +306,9 @@ declare function useChat(options: UseChatOptions): {
|
|
|
275
306
|
description: string;
|
|
276
307
|
}[];
|
|
277
308
|
saveEnabledTools: (tools: string[] | undefined) => Promise<void>;
|
|
309
|
+
skills: SkillRecord[];
|
|
310
|
+
loadSkills: () => Promise<void>;
|
|
311
|
+
toggleSkill: (id: string) => Promise<void>;
|
|
278
312
|
};
|
|
279
313
|
|
|
280
314
|
/**
|
|
@@ -291,6 +325,10 @@ interface ChatInputContextValue {
|
|
|
291
325
|
isLoading: boolean;
|
|
292
326
|
/** Electron adapter(用于 @ 文件选择) */
|
|
293
327
|
adapter?: ChatAdapter;
|
|
328
|
+
/** Skills 列表 */
|
|
329
|
+
skills?: SkillRecord[];
|
|
330
|
+
/** 切换 Skill 启用状态 */
|
|
331
|
+
toggleSkill?: (id: string) => void;
|
|
294
332
|
setMode: (value: ChatMode) => void;
|
|
295
333
|
setModel: (value: string) => void;
|
|
296
334
|
setWebSearch: (value: boolean) => void;
|
|
@@ -396,6 +434,14 @@ declare const ChatPanel: react.ForwardRefExoticComponent<ChatPanelProps & react.
|
|
|
396
434
|
* 新架构:使用 ContentPart 数组渲染消息内容
|
|
397
435
|
*/
|
|
398
436
|
|
|
437
|
+
/** Token 使用统计 */
|
|
438
|
+
interface TokenUsage {
|
|
439
|
+
promptTokens: number;
|
|
440
|
+
completionTokens: number;
|
|
441
|
+
totalTokens: number;
|
|
442
|
+
reasoningTokens?: number;
|
|
443
|
+
cachedTokens?: number;
|
|
444
|
+
}
|
|
399
445
|
interface MessageBubbleProps {
|
|
400
446
|
role: 'user' | 'assistant';
|
|
401
447
|
/** 内容 parts 数组 - 新架构核心 */
|
|
@@ -408,10 +454,23 @@ interface MessageBubbleProps {
|
|
|
408
454
|
images?: string[];
|
|
409
455
|
/** 是否正在加载 */
|
|
410
456
|
loading?: boolean;
|
|
457
|
+
/** Agent 当前阶段(后端推送,thinking=显示 loading) */
|
|
458
|
+
agentPhase?: 'thinking';
|
|
411
459
|
/** 是否已复制 */
|
|
412
460
|
copied?: boolean;
|
|
413
461
|
/** 消息时间戳 */
|
|
414
462
|
timestamp?: Date | string | number;
|
|
463
|
+
/** Token 使用统计 */
|
|
464
|
+
usage?: TokenUsage;
|
|
465
|
+
/** 响应耗时(毫秒) */
|
|
466
|
+
duration?: number;
|
|
467
|
+
/** 计费信息(云端模式) */
|
|
468
|
+
billing?: {
|
|
469
|
+
pointsConsumed: number;
|
|
470
|
+
remainingPoints: number;
|
|
471
|
+
costYuan?: number;
|
|
472
|
+
model?: string;
|
|
473
|
+
};
|
|
415
474
|
onCopy?: () => void;
|
|
416
475
|
onRegenerate?: () => void;
|
|
417
476
|
/** 编辑用户消息后重新发送 */
|