feat(chat): unify resource chips and browse recent files in @ mention
Add recent=true to knowledge search so the mention picker can list recent files without a keyword, and consolidate KB/FAQ/file chip styling across chat input and message history.
This commit is contained in:
@@ -458,16 +458,19 @@ export function searchKnowledge(
|
||||
offset = 0,
|
||||
limit = 20,
|
||||
fileTypes?: string[],
|
||||
options?: { agent_id?: string }
|
||||
options?: { agent_id?: string; recent?: boolean }
|
||||
) {
|
||||
const query = new URLSearchParams();
|
||||
query.set('keyword', keyword);
|
||||
if (keyword) {
|
||||
query.set('keyword', keyword);
|
||||
}
|
||||
query.set('offset', String(offset));
|
||||
query.set('limit', String(limit));
|
||||
if (fileTypes && fileTypes.length > 0) {
|
||||
query.set('file_types', fileTypes.join(','));
|
||||
}
|
||||
if (options?.agent_id) query.set('agent_id', options.agent_id);
|
||||
if (options?.recent) query.set('recent', 'true');
|
||||
return get(`/api/v1/knowledge/search?${query.toString()}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -1099,16 +1099,19 @@ const loadMentionItems = async (q: string, resetIndex = true, append = false) =>
|
||||
const toolsAllowFiles = !hasAgentConfig.value || toolsConsumeFiles(agentAllowedTools.value);
|
||||
const shouldLoadFiles = kbModeAllowsFiles && toolsAllowFiles;
|
||||
|
||||
// 后端 /knowledge/search 要求非空 keyword;打开 @ 面板时仅展示本地 KB 列表,
|
||||
// 用户输入搜索词后再拉取文件结果。
|
||||
// 空关键词时显式请求最近文件;有关键词时返回匹配文件。
|
||||
// `recent=true` 只用于浏览态,避免其他搜索调用漏传关键词时静默退化为最近列表。
|
||||
const fileSearchKeyword = q.trim();
|
||||
if (shouldLoadFiles && fileSearchKeyword) {
|
||||
if (shouldLoadFiles) {
|
||||
mentionLoading.value = true;
|
||||
try {
|
||||
const fileTypesParam = agentSupportedFileTypes.value.length > 0 ? agentSupportedFileTypes.value : undefined;
|
||||
const sourceTenantId = settingsStore.selectedAgentSourceTenantId;
|
||||
const agentId = selectedAgentId.value;
|
||||
const searchOptions = sourceTenantId && agentId ? { agent_id: agentId } : undefined;
|
||||
const searchOptions = {
|
||||
...(sourceTenantId && agentId ? { agent_id: agentId } : {}),
|
||||
recent: !fileSearchKeyword,
|
||||
};
|
||||
const res: any = await searchKnowledge(
|
||||
fileSearchKeyword,
|
||||
mentionOffset.value,
|
||||
@@ -2366,6 +2369,8 @@ const getImgSrc = (url: string) => {
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
@import './css/chat-resource-chips.less';
|
||||
|
||||
.answers-input {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
@@ -2418,18 +2423,24 @@ const getImgSrc = (url: string) => {
|
||||
}
|
||||
|
||||
.mention-chip {
|
||||
.chat-resource-chip-surface();
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 3px 6px 3px 5px;
|
||||
border-radius: 6px;
|
||||
gap: 5px;
|
||||
min-height: 26px;
|
||||
padding: 3px 7px 3px 6px;
|
||||
border-radius: var(--td-radius-medium, 6px);
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
cursor: default;
|
||||
transition: background 0.2s, border-color 0.2s, box-shadow 0.2s;
|
||||
border: .5px solid transparent;
|
||||
color: var(--td-text-color-primary, #1f2937);
|
||||
line-height: 1.3;
|
||||
transition: background 0.15s, border-color 0.15s;
|
||||
line-height: 18px;
|
||||
|
||||
&:hover {
|
||||
.chat-resource-chip-hover();
|
||||
}
|
||||
}
|
||||
|
||||
.mention-chip__icon-wrap {
|
||||
@@ -2441,7 +2452,6 @@ const getImgSrc = (url: string) => {
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.mention-chip__icon {
|
||||
@@ -2493,7 +2503,7 @@ const getImgSrc = (url: string) => {
|
||||
line-height: 1;
|
||||
font-weight: 400;
|
||||
cursor: pointer;
|
||||
opacity: 0.45;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.15s, background 0.15s, color 0.15s;
|
||||
color: currentColor;
|
||||
flex-shrink: 0;
|
||||
@@ -2505,72 +2515,39 @@ const getImgSrc = (url: string) => {
|
||||
|
||||
.mention-chip__remove:hover {
|
||||
opacity: 1;
|
||||
background: rgba(0, 0, 0, 0.08);
|
||||
background: var(--td-bg-color-component);
|
||||
color: var(--td-text-color-primary, #1f2937);
|
||||
}
|
||||
|
||||
/* 知识库:浅绿/青色调 */
|
||||
/* 标签表面保持中性,仅用图标颜色表达资源类型。 */
|
||||
.mention-chip--kb {
|
||||
background: rgba(5, 192, 95, 0.08);
|
||||
border-color: rgba(5, 192, 95, 0.25);
|
||||
color: var(--td-text-color-primary, #1f2937);
|
||||
color: var(--td-text-color-primary);
|
||||
}
|
||||
|
||||
.mention-chip--kb .mention-chip__icon-wrap {
|
||||
background: rgba(5, 192, 95, 0.12);
|
||||
color: var(--td-brand-color, #07c05f);
|
||||
}
|
||||
|
||||
.mention-chip--kb:hover {
|
||||
background: rgba(5, 192, 95, 0.12);
|
||||
border-color: rgba(5, 192, 95, 0.35);
|
||||
}
|
||||
|
||||
/* FAQ:浅紫/靛色调 */
|
||||
.mention-chip--faq {
|
||||
background: rgba(107, 114, 228, 0.08);
|
||||
border-color: rgba(107, 114, 228, 0.25);
|
||||
color: var(--td-text-color-primary, #1f2937);
|
||||
color: var(--td-text-color-primary);
|
||||
}
|
||||
|
||||
.mention-chip--faq .mention-chip__icon-wrap {
|
||||
background: rgba(107, 114, 228, 0.12);
|
||||
color: var(--td-brand-color);
|
||||
color: var(--weknora-faq-color, #0052d9);
|
||||
}
|
||||
|
||||
.mention-chip--faq:hover {
|
||||
background: rgba(107, 114, 228, 0.12);
|
||||
border-color: rgba(107, 114, 228, 0.35);
|
||||
}
|
||||
|
||||
/* 文件:浅灰/中性色 */
|
||||
.mention-chip--file {
|
||||
background: var(--td-bg-color-secondarycontainer, #f3f4f6);
|
||||
border-color: var(--td-component-stroke, #e5e7eb);
|
||||
color: var(--td-text-color-primary, #1f2937);
|
||||
color: var(--td-text-color-primary);
|
||||
}
|
||||
|
||||
.mention-chip--file .mention-chip__icon-wrap {
|
||||
background: rgba(107, 114, 128, 0.12);
|
||||
color: var(--td-text-color-secondary, #6b7280);
|
||||
}
|
||||
|
||||
.mention-chip--file:hover {
|
||||
background: var(--td-bg-color-component, #e5e7eb);
|
||||
border-color: var(--td-component-stroke, #d1d5db);
|
||||
}
|
||||
|
||||
/* 智能体预配置:虚线边框区分 */
|
||||
.mention-chip--agent {
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.mention-chip--agent.mention-chip--kb {
|
||||
border-color: rgba(5, 192, 95, 0.4);
|
||||
}
|
||||
|
||||
.mention-chip--agent.mention-chip--faq {
|
||||
border-color: rgba(107, 114, 228, 0.4);
|
||||
border-color: var(--td-component-border);
|
||||
}
|
||||
|
||||
:deep(.t-textarea__inner) {
|
||||
@@ -2709,16 +2686,18 @@ const getImgSrc = (url: string) => {
|
||||
|
||||
.kb-btn {
|
||||
height: 28px;
|
||||
padding: 0 10px;
|
||||
min-width: auto;
|
||||
width: 30px;
|
||||
padding: 0;
|
||||
min-width: 30px;
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
background: var(--td-bg-color-secondarycontainer);
|
||||
color: var(--td-brand-color);
|
||||
box-shadow: inset 0 0 0 1px var(--td-component-stroke);
|
||||
|
||||
&:hover {
|
||||
background: rgba(16, 185, 129, 0.15);
|
||||
background: var(--td-bg-color-secondarycontainer-hover);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2731,23 +2710,26 @@ const getImgSrc = (url: string) => {
|
||||
}
|
||||
|
||||
&.active:hover {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
background: var(--td-bg-color-secondarycontainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.kb-count {
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -4px;
|
||||
min-width: 16px;
|
||||
height: 16px;
|
||||
padding: 0 4px;
|
||||
top: -5px;
|
||||
right: -5px;
|
||||
min-width: 15px;
|
||||
height: 15px;
|
||||
padding: 0 3px;
|
||||
background: var(--td-brand-color);
|
||||
color: white;
|
||||
font-size: 10px;
|
||||
color: var(--td-text-color-anti, #fff);
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
border-radius: 8px;
|
||||
line-height: 15px;
|
||||
border: 2px solid var(--td-bg-color-container);
|
||||
border-radius: var(--td-radius-round, 999px);
|
||||
box-sizing: content-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
:key="item.id"
|
||||
placement="right-start"
|
||||
trigger="hover"
|
||||
:show-arrow="true"
|
||||
:delay="[200, 0]"
|
||||
:show-arrow="false"
|
||||
:delay="[320, 80]"
|
||||
:disabled="isScrolling"
|
||||
:overlay-class-name="'mention-detail-popup'"
|
||||
:overlay-inner-class-name="'mention-detail-popup-wrap'"
|
||||
@@ -28,7 +28,7 @@
|
||||
</div>
|
||||
<div class="item-main">
|
||||
<span class="name">{{ item.name }}</span>
|
||||
<span class="count">({{ item.count || 0 }})</span>
|
||||
<span class="count">{{ item.count || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<template #content>
|
||||
@@ -82,8 +82,8 @@
|
||||
:key="item.id"
|
||||
placement="right-start"
|
||||
trigger="hover"
|
||||
:show-arrow="true"
|
||||
:delay="[200, 0]"
|
||||
:show-arrow="false"
|
||||
:delay="[320, 80]"
|
||||
:disabled="isScrolling"
|
||||
:overlay-class-name="'mention-detail-popup'"
|
||||
:overlay-inner-class-name="'mention-detail-popup-wrap'"
|
||||
@@ -301,59 +301,62 @@ const scrollToItem = (index: number) => {
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
background: var(--td-bg-color-container, #fff);
|
||||
border: 1px solid var(--td-component-border, #e7e9eb);
|
||||
border-radius: var(--td-radius-medium, 6px);
|
||||
box-shadow: var(--td-shadow-2, 0 3px 14px 2px rgba(0, 0, 0, 0.05));
|
||||
width: 300px;
|
||||
max-height: 360px;
|
||||
border: 1px solid var(--td-component-stroke, #e7e9eb);
|
||||
border-radius: var(--td-radius-extraLarge, 12px);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1), 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
width: 288px;
|
||||
max-height: 344px;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 4px 0;
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.mention-group {
|
||||
padding: 4px 0;
|
||||
padding: 2px 0 5px;
|
||||
}
|
||||
|
||||
.mention-group:not(:last-child) {
|
||||
border-bottom: 1px solid var(--td-component-border, #f0f0f0);
|
||||
border-bottom: 1px solid var(--td-component-stroke, #f0f0f0);
|
||||
}
|
||||
|
||||
.mention-group-header {
|
||||
padding: 8px 12px 4px;
|
||||
padding: 7px 14px 5px;
|
||||
font-size: var(--td-font-size-mark-small, 12px);
|
||||
font-weight: 600;
|
||||
color: var(--td-text-color-secondary, #999);
|
||||
line-height: 18px;
|
||||
color: var(--td-text-color-placeholder, #999);
|
||||
}
|
||||
|
||||
.mention-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
margin: 0 4px;
|
||||
min-height: 40px;
|
||||
padding: 7px 10px;
|
||||
margin: 1px 6px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
border-radius: var(--td-radius-default, 3px);
|
||||
border-radius: var(--td-radius-medium, 6px);
|
||||
color: var(--td-text-color-primary, #333);
|
||||
font-size: var(--td-font-size-body-medium, 14px);
|
||||
font-family: var(--app-font-family);
|
||||
transition: background 0.2s cubic-bezier(0.38, 0, 0.24, 1);
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.mention-item:hover {
|
||||
background: var(--td-bg-color-container-hover, #f3f3f3);
|
||||
background: var(--td-bg-color-secondarycontainer, #f3f3f3);
|
||||
}
|
||||
|
||||
.mention-item.active {
|
||||
background: var(--td-brand-color-light, #e9f8ec);
|
||||
color: var(--td-brand-color, #07c05f);
|
||||
background: var(--td-bg-color-secondarycontainer, #f3f3f3);
|
||||
color: var(--td-text-color-primary, #333);
|
||||
}
|
||||
|
||||
.icon-wrap {
|
||||
position: relative;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -361,11 +364,10 @@ const scrollToItem = (index: number) => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: var(--td-radius-small, 2px);
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
flex-shrink: 0;
|
||||
/* background: var(--td-bg-color-secondarycontainer, #f3f3f3); */
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 右下角组织角标:柔和小圆 + 绿色/灰色 icon,不刺眼 */
|
||||
@@ -399,9 +401,11 @@ const scrollToItem = (index: number) => {
|
||||
}
|
||||
|
||||
.mention-item.active .icon {
|
||||
/* Active state keeps the colored icon but maybe adjusts background or just inherits */
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
color: var(--td-brand-color);
|
||||
}
|
||||
|
||||
.mention-item.active .faq-icon {
|
||||
color: var(--weknora-faq-color, #0052d9);
|
||||
}
|
||||
|
||||
.item-main {
|
||||
@@ -413,6 +417,7 @@ const scrollToItem = (index: number) => {
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -425,9 +430,11 @@ const scrollToItem = (index: number) => {
|
||||
}
|
||||
|
||||
.count {
|
||||
margin-left: auto;
|
||||
flex-shrink: 0;
|
||||
font-size: var(--td-font-size-mark-small, 12px);
|
||||
color: var(--td-text-color-secondary, #999);
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: var(--td-text-color-placeholder, #999);
|
||||
}
|
||||
|
||||
.org-name {
|
||||
@@ -451,7 +458,7 @@ const scrollToItem = (index: number) => {
|
||||
}
|
||||
|
||||
.empty {
|
||||
padding: 24px 12px;
|
||||
padding: 28px 16px;
|
||||
text-align: center;
|
||||
color: var(--td-text-color-placeholder, #999);
|
||||
font-size: var(--td-font-size-body-medium, 14px);
|
||||
@@ -467,16 +474,16 @@ const scrollToItem = (index: number) => {
|
||||
<style>
|
||||
/* 详情浮层在 Teleport 中,需全局样式 */
|
||||
.mention-detail-popup-wrap.t-popup__content {
|
||||
padding: 12px;
|
||||
max-width: 320px;
|
||||
min-width: 240px;
|
||||
}
|
||||
/* 箭头对齐到触发条目的垂直中心(条目高约36px,箭头应在距顶部约18px处) */
|
||||
.mention-detail-popup.t-popup[data-popper-placement^="right"] > .t-popup__arrow {
|
||||
top: 14px !important;
|
||||
min-width: 220px;
|
||||
max-width: 280px;
|
||||
padding: 13px 14px;
|
||||
border: 1px solid var(--td-component-stroke);
|
||||
border-radius: var(--td-radius-large, 9px);
|
||||
background: var(--td-bg-color-container);
|
||||
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.1), 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.mention-detail-content {
|
||||
font-size: var(--td-font-size-body-medium, 14px);
|
||||
font-size: var(--td-font-size-body-small, 12px);
|
||||
color: var(--td-text-color-primary, #333);
|
||||
line-height: 1.5;
|
||||
}
|
||||
@@ -494,26 +501,30 @@ const scrollToItem = (index: number) => {
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 6px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.mention-detail-content .detail-name {
|
||||
font-weight: 600;
|
||||
font-size: var(--td-font-size-body-large, 14px);
|
||||
font-size: var(--td-font-size-body-medium, 14px);
|
||||
line-height: 20px;
|
||||
word-break: break-word;
|
||||
}
|
||||
.mention-detail-content .detail-type-badge {
|
||||
flex-shrink: 0;
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--td-radius-small, 2px);
|
||||
padding: 1px 6px;
|
||||
border: 1px solid var(--td-component-stroke);
|
||||
border-radius: var(--td-radius-medium, 6px);
|
||||
font-size: var(--td-font-size-mark-small, 12px);
|
||||
line-height: 18px;
|
||||
}
|
||||
.mention-detail-content .detail-type-badge.doc {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
color: var(--td-success-color);
|
||||
background: var(--td-bg-color-secondarycontainer);
|
||||
color: var(--td-brand-color);
|
||||
}
|
||||
.mention-detail-content .detail-type-badge.faq {
|
||||
background: rgba(0, 82, 217, 0.1);
|
||||
color: var(--td-brand-color);
|
||||
border-color: rgba(0, 82, 217, 0.16);
|
||||
background: rgba(0, 82, 217, 0.08);
|
||||
color: var(--weknora-faq-color, #0052d9);
|
||||
}
|
||||
.mention-detail-content .detail-desc {
|
||||
margin: 0 0 8px;
|
||||
@@ -532,7 +543,7 @@ const scrollToItem = (index: number) => {
|
||||
color: var(--td-text-color-placeholder, #999);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
gap: 5px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.mention-detail-content .detail-readonly-hint {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@import './chat-resource-chips.less';
|
||||
|
||||
.answer-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
.chat-resource-chip-surface() {
|
||||
background: var(--td-bg-color-secondarycontainer);
|
||||
border: 1px solid var(--td-component-stroke);
|
||||
color: var(--td-text-color-primary);
|
||||
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--td-bg-color-container) 72%, transparent);
|
||||
}
|
||||
|
||||
.chat-resource-chip-hover() {
|
||||
background: var(--td-bg-color-secondarycontainer-hover);
|
||||
border-color: var(--td-component-border);
|
||||
}
|
||||
|
||||
.chat-mentioned-items(@justify: flex-start) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
justify-content: @justify;
|
||||
max-width: 100%;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.chat-mentioned-tag() {
|
||||
.chat-resource-chip-surface();
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
min-height: 26px;
|
||||
max-width: 200px;
|
||||
padding: 3px 8px;
|
||||
border-radius: var(--td-radius-medium, 6px);
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 18px;
|
||||
cursor: default;
|
||||
|
||||
&.kb-tag .tag_icon {
|
||||
color: var(--td-brand-color);
|
||||
}
|
||||
|
||||
&.faq-tag .tag_icon {
|
||||
color: var(--weknora-faq-color, #0052d9);
|
||||
}
|
||||
|
||||
&.file-tag .tag_icon {
|
||||
color: var(--td-text-color-secondary);
|
||||
}
|
||||
|
||||
.tag_icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tag_name {
|
||||
overflow: hidden;
|
||||
color: currentColor;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
@@ -328,59 +328,11 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.mentioned_items {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
justify-content: flex-start;
|
||||
max-width: 100%;
|
||||
margin-bottom: 2px;
|
||||
.chat-mentioned-items();
|
||||
}
|
||||
|
||||
.mentioned_tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
max-width: 200px;
|
||||
cursor: default;
|
||||
transition: all 0.15s;
|
||||
background: rgba(7, 192, 95, 0.06);
|
||||
border: 1px solid rgba(7, 192, 95, 0.2);
|
||||
color: var(--td-text-color-primary);
|
||||
|
||||
&.kb-tag {
|
||||
.tag_icon {
|
||||
color: var(--td-brand-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.faq-tag {
|
||||
.tag_icon {
|
||||
color: var(--td-warning-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.file-tag {
|
||||
.tag_icon {
|
||||
color: var(--td-text-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.tag_icon {
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tag_name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: currentColor;
|
||||
}
|
||||
.chat-mentioned-tag();
|
||||
}
|
||||
|
||||
.fallback-icon-btn {
|
||||
|
||||
@@ -147,6 +147,8 @@ const closePreImg = () => {
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
@import '../../../components/css/chat-resource-chips.less';
|
||||
|
||||
.user_msg_container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -156,59 +158,11 @@ const closePreImg = () => {
|
||||
}
|
||||
|
||||
.mentioned_items {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
justify-content: flex-end;
|
||||
max-width: 100%;
|
||||
margin-bottom: 2px;
|
||||
.chat-mentioned-items(flex-end);
|
||||
}
|
||||
|
||||
.mentioned_tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 3px 8px;
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
max-width: 200px;
|
||||
cursor: default;
|
||||
transition: all 0.15s;
|
||||
background: rgba(7, 192, 95, 0.06);
|
||||
border: 1px solid rgba(7, 192, 95, 0.2);
|
||||
color: var(--td-text-color-primary);
|
||||
|
||||
&.kb-tag {
|
||||
.tag_icon {
|
||||
color: var(--td-brand-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.faq-tag {
|
||||
.tag_icon {
|
||||
color: var(--td-warning-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.file-tag {
|
||||
.tag_icon {
|
||||
color: var(--td-text-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.tag_icon {
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tag_name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: currentColor;
|
||||
}
|
||||
.chat-mentioned-tag();
|
||||
}
|
||||
|
||||
.user_msg_container {
|
||||
|
||||
@@ -1811,7 +1811,7 @@ func (h *KnowledgeHandler) UpdateImageInfo(c *gin.Context) {
|
||||
|
||||
// SearchKnowledge godoc
|
||||
// @Summary Search knowledge
|
||||
// @Description Search knowledge files by keyword. When agent_id is set (shared agent), scope is the agent's configured knowledge bases.
|
||||
// @Description Search knowledge files by keyword. Pass recent=true without a keyword to browse recent files. When agent_id is set (shared agent), scope is the agent's configured knowledge bases.
|
||||
// @Tags Knowledge
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
@@ -1820,6 +1820,7 @@ func (h *KnowledgeHandler) UpdateImageInfo(c *gin.Context) {
|
||||
// @Param limit query int false "Limit for pagination (default 20)"
|
||||
// @Param file_types query string false "Comma-separated file extensions to filter (e.g., csv,xlsx)"
|
||||
// @Param agent_id query string false "Shared agent ID (search within agent's KB scope)"
|
||||
// @Param recent query bool false "Return recent files when keyword is empty"
|
||||
// @Success 200 {object} map[string]interface{} "Search results"
|
||||
// @Failure 400 {object} errors.AppError "Invalid request"
|
||||
// @Security Bearer
|
||||
@@ -1831,18 +1832,19 @@ func (h *KnowledgeHandler) SearchKnowledge(c *gin.Context) {
|
||||
ctx = context.WithValue(ctx, types.UserIDContextKey, userID)
|
||||
}
|
||||
// Accept both ?keyword= (legacy / upstream name) and ?query= (what most
|
||||
// MCP / agent integrations send). Falling silently back to an unsorted
|
||||
// listing when both are empty caused the "all queries return the same 5
|
||||
// newest cards" footgun — return 400 instead so the caller gets a clear
|
||||
// signal that the search wasn't query-driven.
|
||||
// MCP / agent integrations send). Empty input is only valid for an explicit
|
||||
// recent-file browse request; ordinary callers still get a clear 400 instead
|
||||
// of silently receiving the same newest cards for every missing query.
|
||||
keyword := c.Query("keyword")
|
||||
if keyword == "" {
|
||||
keyword = c.Query("query")
|
||||
}
|
||||
if strings.TrimSpace(keyword) == "" {
|
||||
recent, _ := strconv.ParseBool(c.DefaultQuery("recent", "false"))
|
||||
if strings.TrimSpace(keyword) == "" && !recent {
|
||||
c.Error(errors.NewBadRequestError("missing search keyword: pass ?keyword=... or ?query=..."))
|
||||
return
|
||||
}
|
||||
keyword = strings.TrimSpace(keyword)
|
||||
offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user