@liujitcn/kratos-admin-system 0.0.65 → 0.0.66

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 (41) hide show
  1. package/README.md +5 -3
  2. package/dist/package/declarations/src/api/base/v1/ai_knowledge.d.ts +7 -0
  3. package/dist/package/declarations/src/api/system/admin/v1/ai_provider.d.ts +3 -1
  4. package/dist/package/declarations/src/api/system/admin/v1/ai_query.d.ts +10 -0
  5. package/dist/package/declarations/src/api/system/admin/v1/ai_session.d.ts +9 -0
  6. package/dist/package/declarations/src/locales/generated.d.ts +1801 -1553
  7. package/dist/package/declarations/src/rpc/base/v1/ai_knowledge.d.ts +22 -0
  8. package/dist/package/declarations/src/rpc/base/v1/ai_message.d.ts +2 -0
  9. package/dist/package/declarations/src/rpc/system/admin/v1/ai_provider.d.ts +63 -5
  10. package/dist/package/declarations/src/rpc/system/admin/v1/ai_query.d.ts +73 -0
  11. package/dist/package/declarations/src/rpc/system/admin/v1/ai_session.d.ts +114 -0
  12. package/dist/package/declarations/src/views/ai/chat/components/ChatPanel.vue.d.ts +9 -2
  13. package/dist/package/declarations/src/views/ai/chat/components/XSender.vue.d.ts +7 -0
  14. package/dist/package/declarations/src/views/ai/query/index.vue.d.ts +3 -0
  15. package/dist/package/declarations/src/views/ai/session/index.vue.d.ts +3 -0
  16. package/dist/package/src/api/base/v1/ai_knowledge.ts +22 -0
  17. package/dist/package/src/api/system/admin/v1/ai_provider.ts +7 -0
  18. package/dist/package/src/api/system/admin/v1/ai_query.ts +25 -0
  19. package/dist/package/src/api/system/admin/v1/ai_session.ts +25 -0
  20. package/dist/package/src/components/account/ChangePasswordForm.vue +1 -1
  21. package/dist/package/src/components/tenant-project/TenantProjectSelect.vue +21 -4
  22. package/dist/package/src/locales/en-US.json +354 -292
  23. package/dist/package/src/locales/ja-JP.json +351 -289
  24. package/dist/package/src/locales/zh-CN.json +351 -289
  25. package/dist/package/src/locales/zh-TW.json +351 -289
  26. package/dist/package/src/rpc/base/v1/ai_knowledge.ts +33 -0
  27. package/dist/package/src/rpc/base/v1/ai_message.ts +2 -0
  28. package/dist/package/src/rpc/system/admin/v1/ai_provider.ts +68 -5
  29. package/dist/package/src/rpc/system/admin/v1/ai_query.ts +89 -0
  30. package/dist/package/src/rpc/system/admin/v1/ai_session.ts +131 -0
  31. package/dist/package/src/views/ai/chat/components/ChatPanel.vue +18 -0
  32. package/dist/package/src/views/ai/chat/components/XSender.vue +101 -0
  33. package/dist/package/src/views/ai/chat/index.vue +22 -2
  34. package/dist/package/src/views/ai/query/index.vue +222 -0
  35. package/dist/package/src/views/ai/session/index.vue +422 -0
  36. package/dist/package/src/views/base/ai-provider/index.vue +201 -155
  37. package/dist/package/src/views/base/message-provider/index.vue +2 -2
  38. package/dist/package/src/views/base/oauth-provider/index.vue +2 -2
  39. package/dist/package/src/views/base/tenant-project-grant/index.vue +9 -4
  40. package/dist/package/src/views/tool/code-gen/config.ts +1 -0
  41. package/package.json +2 -2
@@ -0,0 +1,33 @@
1
+ // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
+ // versions:
3
+ // protoc-gen-ts_proto v2.11.8
4
+ // protoc unknown
5
+ // source: base/v1/ai_knowledge.proto
6
+
7
+ /* eslint-disable */
8
+
9
+ /** AI知识库选项查询请求。 */
10
+ export interface ListAiKnowledgeOptionsRequest {
11
+ }
12
+
13
+ /** AI知识库选项查询响应。 */
14
+ export interface ListAiKnowledgeOptionsResponse {
15
+ /** 知识库选项列表 */
16
+ options: AiKnowledgeOption[];
17
+ }
18
+
19
+ /** AI知识库选项。 */
20
+ export interface AiKnowledgeOption {
21
+ /** 知识库ID */
22
+ id: number;
23
+ /** 知识库名称 */
24
+ name: string;
25
+ /** 文档数量 */
26
+ doc_count: number;
27
+ }
28
+
29
+ /** AI 知识库选项查询服务。 */
30
+ export interface AiKnowledgeService {
31
+ /** 查询可用的AI知识库选项。 */
32
+ ListAiKnowledgeOptions(request: ListAiKnowledgeOptionsRequest): Promise<ListAiKnowledgeOptionsResponse>;
33
+ }
@@ -53,6 +53,8 @@ export interface SendAiMessageRequest {
53
53
  provider_id: number;
54
54
  /** 所选模型名称 */
55
55
  model_name: string;
56
+ /** 所选知识库ID列表 */
57
+ knowledge_base_ids: number[];
56
58
  }
57
59
 
58
60
  /** AI 助手失败消息重试请求 */
@@ -8,6 +8,24 @@
8
8
  import type { Status } from "../../../common/v1/enum";
9
9
  import type { Empty } from "../../../google/protobuf/empty";
10
10
 
11
+ /** AI模型分类枚举。 */
12
+ export enum AiModelCategory {
13
+ /** AI_MODEL_CATEGORY_UNSPECIFIED - 未指定AI模型分类。 */
14
+ AI_MODEL_CATEGORY_UNSPECIFIED = 0,
15
+ /** AI_MODEL_CATEGORY_CHAT - 对话模型。 */
16
+ AI_MODEL_CATEGORY_CHAT = 1,
17
+ /** AI_MODEL_CATEGORY_EMBEDDING - 向量模型。 */
18
+ AI_MODEL_CATEGORY_EMBEDDING = 2,
19
+ /** AI_MODEL_CATEGORY_RERANK - 重排序模型。 */
20
+ AI_MODEL_CATEGORY_RERANK = 3,
21
+ /** AI_MODEL_CATEGORY_IMAGE - 图片模型。 */
22
+ AI_MODEL_CATEGORY_IMAGE = 4,
23
+ /** AI_MODEL_CATEGORY_VIDEO - 视频模型。 */
24
+ AI_MODEL_CATEGORY_VIDEO = 5,
25
+ /** AI_MODEL_CATEGORY_AUDIO - 音频模型。 */
26
+ AI_MODEL_CATEGORY_AUDIO = 6,
27
+ }
28
+
11
29
  /** AI供应商分页查询条件。 */
12
30
  export interface PageAiProviderRequest {
13
31
  /** 供应商名称 */
@@ -48,8 +66,6 @@ export interface AiProviderForm {
48
66
  api_key: string;
49
67
  /** 是否已保存模型密钥 */
50
68
  api_key_configured: boolean;
51
- /** 多模型JSON数组 */
52
- models_json: string;
53
69
  /** 排序值 */
54
70
  sort: number;
55
71
  /** Provider稳定标识 */
@@ -58,6 +74,28 @@ export interface AiProviderForm {
58
74
  config:
59
75
  | { [key: string]: any }
60
76
  | undefined;
77
+ /** 供应商下的AI模型列表 */
78
+ models: AiProviderModelForm[];
79
+ /** 状态 */
80
+ status: Status;
81
+ }
82
+
83
+ /** AI供应商模型维护表单;provider_id由所属供应商表单隐式给定。 */
84
+ export interface AiProviderModelForm {
85
+ /** 模型ID;新增时为0 */
86
+ id: number;
87
+ /** 模型名称,供应商API标识 */
88
+ model_name: string;
89
+ /** 显示名称 */
90
+ display_name: string;
91
+ /** 模型分类:枚举【AiModelCategory】 */
92
+ category: AiModelCategory;
93
+ /** 分类个性化配置JSON对象 */
94
+ config:
95
+ | { [key: string]: any }
96
+ | undefined;
97
+ /** 排序值 */
98
+ sort: number;
61
99
  /** 状态 */
62
100
  status: Status;
63
101
  }
@@ -74,7 +112,7 @@ export interface UpdateAiProviderRequest {
74
112
  ai_provider: AiProviderForm | undefined;
75
113
  }
76
114
 
77
- /** 测试AI供应商全部模型请求。 */
115
+ /** 测试AI供应商模型请求。 */
78
116
  export interface TestAiProviderModelsRequest {
79
117
  /** 待测试的AI供应商草稿 */
80
118
  ai_provider: AiProviderForm | undefined;
@@ -98,6 +136,26 @@ export interface TestAiProviderModelsResponse {
98
136
  results: AiProviderModelTestResult[];
99
137
  }
100
138
 
139
+ /** 查询AI供应商选项请求。 */
140
+ export interface ListAiProviderOptionsRequest {
141
+ }
142
+
143
+ /** 查询AI供应商选项响应。 */
144
+ export interface ListAiProviderOptionsResponse {
145
+ /** 已启用的AI供应商列表 */
146
+ options: AiProviderOption[];
147
+ }
148
+
149
+ /** AI供应商选项。 */
150
+ export interface AiProviderOption {
151
+ /** 供应商ID */
152
+ id: number;
153
+ /** 供应商名称 */
154
+ name: string;
155
+ /** Provider稳定标识 */
156
+ provider: string;
157
+ }
158
+
101
159
  /** 删除AI供应商请求。 */
102
160
  export interface DeleteAiProviderRequest {
103
161
  /** 供应商ID */
@@ -122,12 +180,12 @@ export interface AiProvider {
122
180
  base_url: string;
123
181
  /** 是否已保存模型密钥 */
124
182
  api_key_configured: boolean;
125
- /** 模型名称列表 */
126
- model_names: string[];
127
183
  /** 排序值 */
128
184
  sort: number;
129
185
  /** Provider稳定标识 */
130
186
  provider: string;
187
+ /** 供应商下的模型名称列表 */
188
+ model_names: string[];
131
189
  /** 状态 */
132
190
  status: Status;
133
191
  /** 创建时间 */
@@ -140,6 +198,11 @@ export interface AiProvider {
140
198
  export interface AiProviderService {
141
199
  /** 分页查询AI供应商。 */
142
200
  PageAiProvider(request: PageAiProviderRequest): Promise<PageAiProviderResponse>;
201
+ /**
202
+ * 查询已启用的AI供应商选项。
203
+ * 字面路径必须先于 /{id} 声明:gorilla mux 按注册顺序匹配,否则会被 {id} 路由抢占。
204
+ */
205
+ ListAiProviderOptions(request: ListAiProviderOptionsRequest): Promise<ListAiProviderOptionsResponse>;
143
206
  /** 查询AI供应商表单。 */
144
207
  GetAiProvider(request: GetAiProviderRequest): Promise<AiProviderForm>;
145
208
  /** 创建AI供应商。 */
@@ -0,0 +1,89 @@
1
+ // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
+ // versions:
3
+ // protoc-gen-ts_proto v2.11.8
4
+ // protoc unknown
5
+ // source: system/admin/v1/ai_query.proto
6
+
7
+ /* eslint-disable */
8
+
9
+ /** 智能问数状态枚举。 */
10
+ export enum AiQueryStatus {
11
+ /** AI_QUERY_STATUS_UNSPECIFIED - 未指定智能问数状态。 */
12
+ AI_QUERY_STATUS_UNSPECIFIED = 0,
13
+ /** AI_QUERY_STATUS_SUCCESS - 成功。 */
14
+ AI_QUERY_STATUS_SUCCESS = 1,
15
+ /** AI_QUERY_STATUS_FAILED - 失败。 */
16
+ AI_QUERY_STATUS_FAILED = 2,
17
+ }
18
+
19
+ /** 智能问数分页查询条件。 */
20
+ export interface PageAiQueryRequest {
21
+ /** 问题内容 */
22
+ question: string;
23
+ /** 问数状态:枚举【AiQueryStatus】 */
24
+ status?:
25
+ | AiQueryStatus
26
+ | undefined;
27
+ /** 当前页码 */
28
+ page_num: number;
29
+ /** 每页行数 */
30
+ page_size: number;
31
+ }
32
+
33
+ /** 智能问数分页响应。 */
34
+ export interface PageAiQueryResponse {
35
+ /** 智能问数记录列表 */
36
+ queries: AiQueryRecord[];
37
+ /** 总数 */
38
+ total: number;
39
+ }
40
+
41
+ /** 查询智能问数记录请求。 */
42
+ export interface GetAiQueryRequest {
43
+ /** 记录ID */
44
+ id: number;
45
+ }
46
+
47
+ /** 智能问数结果快照行。 */
48
+ export interface AiQueryResultRow {
49
+ /** 行数据 */
50
+ values: string[];
51
+ }
52
+
53
+ /** 智能问数记录。 */
54
+ export interface AiQueryRecord {
55
+ /** 记录ID */
56
+ id: number;
57
+ /** 租户ID */
58
+ tenant_id: number;
59
+ /** 用户ID */
60
+ user_id: number;
61
+ /** 用户账号 */
62
+ user_name: string;
63
+ /** 自然语言问题 */
64
+ question: string;
65
+ /** 生成的只读SQL */
66
+ sql: string;
67
+ /** 问数状态:枚举【AiQueryStatus】 */
68
+ status: AiQueryStatus;
69
+ /** 结果行数 */
70
+ row_count: number;
71
+ /** SQL执行耗时毫秒 */
72
+ elapsed_ms: number;
73
+ /** 失败原因 */
74
+ error_msg: string;
75
+ /** 结果快照列名,仅详情返回 */
76
+ result_columns: string[];
77
+ /** 结果快照数据行,仅详情返回 */
78
+ result_rows: AiQueryResultRow[];
79
+ /** 创建时间 */
80
+ created_at: string;
81
+ }
82
+
83
+ /** 智能问数记录管理服务。 */
84
+ export interface AiQueryService {
85
+ /** 分页查询智能问数记录。 */
86
+ PageAiQuery(request: PageAiQueryRequest): Promise<PageAiQueryResponse>;
87
+ /** 查询智能问数记录详情。 */
88
+ GetAiQuery(request: GetAiQueryRequest): Promise<AiQueryRecord>;
89
+ }
@@ -0,0 +1,131 @@
1
+ // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
+ // versions:
3
+ // protoc-gen-ts_proto v2.11.8
4
+ // protoc unknown
5
+ // source: system/admin/v1/ai_session.proto
6
+
7
+ /* eslint-disable */
8
+ import type { AiMessageStatus } from "../../../base/v1/ai_session";
9
+ import type { Terminal } from "../../../base/v1/ai_tool";
10
+
11
+ /** AI会话分页查询条件。 */
12
+ export interface PageAiSessionRequest {
13
+ /** 会话标题 */
14
+ title: string;
15
+ /** 终端类型:枚举【Terminal】 */
16
+ terminal?:
17
+ | Terminal
18
+ | undefined;
19
+ /** 当前页码 */
20
+ page_num: number;
21
+ /** 每页行数 */
22
+ page_size: number;
23
+ }
24
+
25
+ /** AI会话分页响应。 */
26
+ export interface PageAiSessionResponse {
27
+ /** 会话列表 */
28
+ sessions: AiSessionRecord[];
29
+ /** 总数 */
30
+ total: number;
31
+ }
32
+
33
+ /** AI会话分页记录。 */
34
+ export interface AiSessionRecord {
35
+ /** 会话ID */
36
+ id: number;
37
+ /** 所属用户ID */
38
+ user_id: number;
39
+ /** 用户账号 */
40
+ user_name: string;
41
+ /** 用户昵称 */
42
+ nick_name: string;
43
+ /** 会话标题 */
44
+ title: string;
45
+ /** 会话摘要 */
46
+ summary: string;
47
+ /** 终端类型:枚举【Terminal】 */
48
+ terminal: Terminal;
49
+ /** 消息轮次数 */
50
+ message_count: number;
51
+ /** 累计输入Token数 */
52
+ input_tokens: number;
53
+ /** 累计输出Token数 */
54
+ output_tokens: number;
55
+ /** 累计缓存Token数 */
56
+ cache_tokens: number;
57
+ /** 累计总Token数 */
58
+ total_tokens: number;
59
+ /** 创建时间 */
60
+ created_at: string;
61
+ /** 更新时间 */
62
+ updated_at: string;
63
+ }
64
+
65
+ /** 分页查询AI会话消息请求。 */
66
+ export interface PageAiSessionMessageRequest {
67
+ /** 会话ID */
68
+ id: number;
69
+ /** 当前页码 */
70
+ page_num: number;
71
+ /** 每页行数 */
72
+ page_size: number;
73
+ }
74
+
75
+ /** 分页查询AI会话消息响应。 */
76
+ export interface PageAiSessionMessageResponse {
77
+ /** 消息列表 */
78
+ messages: AiSessionMessageRecord[];
79
+ /** 总数 */
80
+ total: number;
81
+ }
82
+
83
+ /** AI会话消息记录。 */
84
+ export interface AiSessionMessageRecord {
85
+ /** 消息ID */
86
+ id: number;
87
+ /** 用户输入内容 */
88
+ input_content: string;
89
+ /** AI回复内容 */
90
+ output_content: string;
91
+ /** 回复使用的模型名称 */
92
+ model: string;
93
+ /** 消息生成状态:枚举【AiMessageStatus】 */
94
+ status: AiMessageStatus;
95
+ /** 输入Token数 */
96
+ input_tokens: number;
97
+ /** 输出Token数 */
98
+ output_tokens: number;
99
+ /** 缓存Token数 */
100
+ cache_tokens: number;
101
+ /** 总Token数 */
102
+ total_tokens: number;
103
+ /** 首Token耗时毫秒 */
104
+ first_token_ms: number;
105
+ /** 总耗时毫秒 */
106
+ duration_ms: number;
107
+ /** 附件列表 */
108
+ attachments: AiSessionMessageAttachment[];
109
+ /** 创建时间 */
110
+ created_at: string;
111
+ }
112
+
113
+ /** AI会话消息附件。 */
114
+ export interface AiSessionMessageAttachment {
115
+ /** 附件名称 */
116
+ name: string;
117
+ /** 附件大小 */
118
+ size: number;
119
+ /** 附件地址 */
120
+ url: string;
121
+ /** 附件 MIME 类型 */
122
+ mime_type: string;
123
+ }
124
+
125
+ /** AI会话管理服务。 */
126
+ export interface AiSessionService {
127
+ /** 分页查询AI会话。 */
128
+ PageAiSession(request: PageAiSessionRequest): Promise<PageAiSessionResponse>;
129
+ /** 分页查询AI会话消息。 */
130
+ PageAiSessionMessage(request: PageAiSessionMessageRequest): Promise<PageAiSessionMessageResponse>;
131
+ }
@@ -53,8 +53,11 @@
53
53
  :model-providers="modelProviders"
54
54
  :provider-id="providerId"
55
55
  :model-name="modelName"
56
+ :knowledge-options="knowledgeOptions"
57
+ :knowledge-ids="knowledgeIds"
56
58
  @submit="handleSubmit"
57
59
  @model-change="handleModelChange"
60
+ @knowledge-change="handleKnowledgeChange"
58
61
  />
59
62
  </div>
60
63
  </div>
@@ -336,8 +339,11 @@
336
339
  :model-providers="modelProviders"
337
340
  :provider-id="providerId"
338
341
  :model-name="modelName"
342
+ :knowledge-options="knowledgeOptions"
343
+ :knowledge-ids="knowledgeIds"
339
344
  @submit="handleSubmit"
340
345
  @model-change="handleModelChange"
346
+ @knowledge-change="handleKnowledgeChange"
341
347
  />
342
348
  </div>
343
349
  </template>
@@ -356,6 +362,7 @@ import { formatDateTime } from "@liujitcn/kratos-admin-core/format";
356
362
  import type { AiAction } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_message";
357
363
  import { type AiAttachment, type AiSession } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_session";
358
364
  import type { AiProviderModelOption } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_provider";
365
+ import type { AiKnowledgeOption } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_knowledge";
359
366
  import type { AiShortcut, AiToolCall } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_tool";
360
367
  import { AiMessageStatus } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_session";
361
368
  import { resolvePersistedMessage } from "../../../../utils/persisted-message";
@@ -501,6 +508,10 @@ const props = defineProps<{
501
508
  providerId: number;
502
509
  /** 当前选择的模型名称。 */
503
510
  modelName: string;
511
+ /** 当前可供选择的知识库。 */
512
+ knowledgeOptions: AiKnowledgeOption[];
513
+ /** 当前选择的知识库编号列表。 */
514
+ knowledgeIds: number[];
504
515
  }>();
505
516
 
506
517
  const emit = defineEmits<{
@@ -508,6 +519,8 @@ const emit = defineEmits<{
508
519
  submit: [payload: SubmitPayload];
509
520
  /** 更新当前选择的供应商和模型。 */
510
521
  modelChange: [providerId: number, modelName: string];
522
+ /** 更新当前选择的知识库编号列表。 */
523
+ knowledgeChange: [knowledgeIds: number[]];
511
524
  /** 触发消息级操作。 */
512
525
  messageAction: [payload: { action: ChatMessageAction; item: ChatMessageItem }];
513
526
  /** 提交当前用户消息的文本编辑。 */
@@ -648,6 +661,11 @@ function handleModelChange(providerId: number, modelName: string) {
648
661
  emit("modelChange", providerId, modelName);
649
662
  }
650
663
 
664
+ /** 更新当前选择的知识库编号列表。 */
665
+ function handleKnowledgeChange(knowledgeIds: number[]) {
666
+ emit("knowledgeChange", knowledgeIds);
667
+ }
668
+
651
669
  /** 点击快捷入口时提交对应入口动作。 */
652
670
  function handleShortcutClick(shortcut: AiShortcut) {
653
671
  emit("submit", {
@@ -126,6 +126,72 @@
126
126
  {{ t("system.ai.model.empty") }}
127
127
  </div>
128
128
  </el-popover>
129
+ <el-popover
130
+ ref="knowledgePopoverRef"
131
+ placement="top-start"
132
+ :width="324"
133
+ trigger="click"
134
+ :show-arrow="false"
135
+ :persistent="false"
136
+ popper-class="agent-model-popper"
137
+ >
138
+ <template #reference>
139
+ <button
140
+ class="agent-model-selector"
141
+ :class="{ 'is-disabled': sending || !knowledgeOptions.length, 'is-selected': selectedKnowledgeCount > 0 }"
142
+ type="button"
143
+ :disabled="sending || !knowledgeOptions.length"
144
+ :aria-label="t('system.ai.knowledge.title')"
145
+ >
146
+ <el-icon class="agent-model-selector__spark"><Collection /></el-icon>
147
+ <span class="agent-model-selector__label">{{
148
+ selectedKnowledgeCount > 0
149
+ ? t("system.ai.knowledge.selected_count", { count: selectedKnowledgeCount })
150
+ : t("system.ai.knowledge.title")
151
+ }}</span>
152
+ <el-icon class="agent-model-selector__arrow"><ArrowDown /></el-icon>
153
+ </button>
154
+ </template>
155
+ <div v-if="knowledgeOptions.length" class="agent-model-panel">
156
+ <div class="agent-model-panel__head">
157
+ <span class="agent-model-panel__title">{{ t("system.ai.knowledge.title") }}</span>
158
+ <span class="agent-model-panel__meta">{{
159
+ t("system.ai.knowledge.select_hint")
160
+ }}</span>
161
+ </div>
162
+ <div class="agent-model-panel__list">
163
+ <button
164
+ v-for="option in knowledgeOptions"
165
+ :key="option.id"
166
+ class="agent-model-row"
167
+ :class="{ 'is-selected': isKnowledgeSelected(option.id) }"
168
+ type="button"
169
+ @click="handleKnowledgeToggle(option.id)"
170
+ >
171
+ <span class="agent-model-row__name">{{ option.name }}</span>
172
+ <span v-if="option.doc_count" class="agent-model-row__raw">{{
173
+ t("system.ai.knowledge.doc_count", { count: option.doc_count })
174
+ }}</span>
175
+ <el-icon v-if="isKnowledgeSelected(option.id)" class="agent-model-row__check">
176
+ <Check />
177
+ </el-icon>
178
+ </button>
179
+ </div>
180
+ <button
181
+ v-if="aiKnowledgeRoute"
182
+ class="agent-model-panel__manage"
183
+ type="button"
184
+ @click="openKnowledgeManage"
185
+ >
186
+ <el-icon><Setting /></el-icon>
187
+ <span>{{ t("system.ai.knowledge.manage") }}</span>
188
+ <el-icon class="agent-model-panel__manage-arrow"><ArrowRight /></el-icon>
189
+ </button>
190
+ </div>
191
+ <div v-else class="agent-model-panel agent-model-panel--empty">
192
+ {{ t("system.ai.knowledge.empty") }}
193
+ </div>
194
+ </el-popover>
129
195
  <el-tooltip
130
196
  :content="recording ? t('system.ai.chat.action.stop_voice_input') : t('system.ai.chat.action.voice_input')"
131
197
  placement="top"
@@ -181,6 +247,7 @@ import {
181
247
  ArrowDown,
182
248
  ArrowRight,
183
249
  Check,
250
+ Collection,
184
251
  Loading,
185
252
  MagicStick,
186
253
  Microphone,
@@ -195,6 +262,7 @@ import { useAuthStore } from "@liujitcn/kratos-admin-core/stores/runtime";
195
262
  import { defFileService } from "@liujitcn/kratos-admin-core/api/base/v1/file";
196
263
  import type { AiAttachment } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_session";
197
264
  import type { AiProviderModelOption } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_provider";
265
+ import type { AiKnowledgeOption } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_knowledge";
198
266
  import type { SubmitPayload } from "../types";
199
267
  import { buildAIAttachmentFileCard } from "../attachment";
200
268
  import { fallbackModelDisplayName } from "../modelDisplay";
@@ -210,6 +278,10 @@ const props = defineProps<{
210
278
  providerId: number;
211
279
  /** 当前选择的模型名称。 */
212
280
  modelName: string;
281
+ /** 当前可供选择的知识库。 */
282
+ knowledgeOptions: AiKnowledgeOption[];
283
+ /** 当前选择的知识库编号列表。 */
284
+ knowledgeIds: number[];
213
285
  }>();
214
286
 
215
287
  const emit = defineEmits<{
@@ -217,6 +289,8 @@ const emit = defineEmits<{
217
289
  submit: [payload: SubmitPayload];
218
290
  /** 更新当前选择的供应商和模型。 */
219
291
  "model-change": [providerId: number, modelName: string];
292
+ /** 更新当前选择的知识库编号列表。 */
293
+ "knowledge-change": [knowledgeIds: number[]];
220
294
  }>();
221
295
 
222
296
  const senderRef = ref<InstanceType<typeof BaseXSender>>();
@@ -249,6 +323,9 @@ const selectedModelDisplayName = computed(() => {
249
323
  const aiProviderRoute = computed(() =>
250
324
  authStore.flatMenuListGet.find(item => item.name === "AiProvider" && item.path)
251
325
  );
326
+ const aiKnowledgeRoute = computed(() =>
327
+ authStore.flatMenuListGet.find(item => item.name === "AiKnowledge" && item.path)
328
+ );
252
329
  const uploading = ref(false);
253
330
  const maxAttachmentCount = 6;
254
331
  const maxAttachmentSizeMB = 20;
@@ -323,6 +400,30 @@ async function openModelManage() {
323
400
  await navigateTo(router, aiProviderRoute.value.path);
324
401
  }
325
402
 
403
+ const knowledgePopoverRef = ref<InstanceType<typeof ElPopover>>();
404
+
405
+ const selectedKnowledgeCount = computed(() => props.knowledgeIds.length);
406
+
407
+ /** 判断知识库是否在当前选择中。 */
408
+ function isKnowledgeSelected(knowledgeId: number) {
409
+ return props.knowledgeIds.includes(knowledgeId);
410
+ }
411
+
412
+ /** 切换知识库选择状态并同步父组件。 */
413
+ function handleKnowledgeToggle(knowledgeId: number) {
414
+ const current = new Set(props.knowledgeIds);
415
+ if (current.has(knowledgeId)) current.delete(knowledgeId);
416
+ else current.add(knowledgeId);
417
+ emit("knowledge-change", [...current]);
418
+ }
419
+
420
+ /** 跳转到 AI 知识库管理页。 */
421
+ async function openKnowledgeManage() {
422
+ if (!aiKnowledgeRoute.value?.path) return;
423
+ knowledgePopoverRef.value?.hide();
424
+ await navigateTo(router, aiKnowledgeRoute.value.path);
425
+ }
426
+
326
427
  /** 读取输入内容并发送给父组件。 */
327
428
  function handleSubmit() {
328
429
  if (uploading.value) return;
@@ -30,8 +30,11 @@
30
30
  :model-providers="modelProviders"
31
31
  :provider-id="selectedProviderId"
32
32
  :model-name="selectedModelName"
33
+ :knowledge-options="knowledgeOptions"
34
+ :knowledge-ids="selectedKnowledgeIds"
33
35
  @submit="handleSubmit"
34
36
  @model-change="handleModelChange"
37
+ @knowledge-change="handleKnowledgeChange"
35
38
  @message-action="handleMessageAction"
36
39
  @message-edit="handleEditMessage"
37
40
  >
@@ -59,9 +62,11 @@ import { defAiMessageService } from "@liujitcn/kratos-admin-system/api/base/v1/a
59
62
  import { defAiSessionService } from "@liujitcn/kratos-admin-system/api/base/v1/ai_session";
60
63
  import { defAiToolService } from "@liujitcn/kratos-admin-system/api/base/v1/ai_tool";
61
64
  import { defAiModelService } from "@liujitcn/kratos-admin-system/api/base/v1/ai_provider";
65
+ import { defAiKnowledgeService } from "@liujitcn/kratos-admin-system/api/base/v1/ai_knowledge";
62
66
  import type { AiAction } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_message";
63
67
  import type { AiSession } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_session";
64
68
  import type { AiProviderModelOption } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_provider";
69
+ import type { AiKnowledgeOption } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_knowledge";
65
70
  import type { AiShortcut } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_tool";
66
71
  import { AiMessageStatus } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_session";
67
72
  import { Terminal } from "@liujitcn/kratos-admin-system/rpc/base/v1/ai_tool";
@@ -112,6 +117,8 @@ const starterShortcuts = ref<AiShortcut[]>([]);
112
117
  const modelProviders = ref<AiProviderModelOption[]>([]);
113
118
  const selectedProviderId = ref(0);
114
119
  const selectedModelName = ref("");
120
+ const knowledgeOptions = ref<AiKnowledgeOption[]>([]);
121
+ const selectedKnowledgeIds = ref<number[]>([]);
115
122
  const messages = ref<Record<string, ChatMessageItem[]>>({});
116
123
  const pendingDeltaMap = new Map<string, AiStreamPayload>();
117
124
  const runningStreamTaskMap = new Map<string, AiStreamTask>();
@@ -229,6 +236,7 @@ async function runAiStreamTask(sessionID: string, payload: SubmitPayload) {
229
236
  content: payload.text,
230
237
  provider_id: selectedProviderId.value,
231
238
  model_name: selectedModelName.value,
239
+ knowledge_base_ids: selectedKnowledgeIds.value,
232
240
  attachments: payload.attachments.map(item => ({
233
241
  id: item.id,
234
242
  name: item.name,
@@ -657,16 +665,23 @@ async function loadAiShortcuts() {
657
665
  if (loadingShortcuts.value) return;
658
666
  loadingShortcuts.value = true;
659
667
  try {
660
- const [response, providerResponse] = await Promise.all([
668
+ const [response, providerResponse, knowledgeResponse] = await Promise.all([
661
669
  defAiToolService.ListAiShortcut({ terminal: Terminal.TERMINAL_ADMIN }),
662
- defAiModelService.ListAiProviderModelOptions({})
670
+ defAiModelService.ListAiProviderModelOptions({}),
671
+ defAiKnowledgeService.ListAiKnowledgeOptions({})
663
672
  ]);
664
673
  starterShortcuts.value = normalizeStarterShortcuts(response.shortcuts);
665
674
  modelProviders.value = providerResponse.providers ?? [];
675
+ knowledgeOptions.value = knowledgeResponse.options ?? [];
676
+ // 知识库可能已被删除,剔除无效选择。
677
+ selectedKnowledgeIds.value = selectedKnowledgeIds.value.filter(id =>
678
+ knowledgeOptions.value.some(option => option.id === id)
679
+ );
666
680
  applyModelSelection();
667
681
  } catch {
668
682
  starterShortcuts.value = [];
669
683
  modelProviders.value = [];
684
+ knowledgeOptions.value = [];
670
685
  selectedProviderId.value = 0;
671
686
  selectedModelName.value = "";
672
687
  } finally {
@@ -701,6 +716,11 @@ function handleModelChange(providerId: number, modelName: string) {
701
716
  saveModelSelection({ provider_id: providerId, model_name: modelName });
702
717
  }
703
718
 
719
+ /** 更新当前聊天检索注入的知识库选择。 */
720
+ function handleKnowledgeChange(knowledgeIds: number[]) {
721
+ selectedKnowledgeIds.value = knowledgeIds;
722
+ }
723
+
704
724
  /** 使指定会话仍在途的消息列表请求失效。 */
705
725
  function invalidateLoadMessages(sessionID: string) {
706
726
  loadMessagesSeq.set(sessionID, (loadMessagesSeq.get(sessionID) ?? 0) + 1);