diff --git a/frontend/src/api/chat/streame.ts b/frontend/src/api/chat/streame.ts
index eaa9657b..1d08b900 100644
--- a/frontend/src/api/chat/streame.ts
+++ b/frontend/src/api/chat/streame.ts
@@ -200,7 +200,7 @@ export function useStream() {
let chunkHandler: ((data: any) => void) | null = null
// 注册块处理器
- const onChunk = (handler: () => void) => {
+ const onChunk = (handler: (data: any) => void) => {
chunkHandler = handler
}
diff --git a/frontend/src/api/tenant/index.ts b/frontend/src/api/tenant/index.ts
index a785a83b..162a91e1 100644
--- a/frontend/src/api/tenant/index.ts
+++ b/frontend/src/api/tenant/index.ts
@@ -89,7 +89,7 @@ export async function listAllTenants(): Promise<{ success: boolean; data?: { ite
* 重置租户的 API Key。成功后返回新的明文 Key,旧 Key 立即失效。
*/
export async function resetTenantApiKey(
- tenantId: number,
+ tenantId: string | number,
): Promise<{ success: boolean; data?: { api_key: string }; message?: string }> {
try {
const response = await post(`/api/v1/tenants/${tenantId}/api-key`)
diff --git a/frontend/src/components/AgentEmbedChannelPanel.vue b/frontend/src/components/AgentEmbedChannelPanel.vue
index ba28ca19..674efd90 100644
--- a/frontend/src/components/AgentEmbedChannelPanel.vue
+++ b/frontend/src/components/AgentEmbedChannelPanel.vue
@@ -31,7 +31,7 @@
handleChannelMenuClick(data, ch)">
+ @click="handleChannelMenuClick($event, ch)">
diff --git a/frontend/src/components/AgentSelector.vue b/frontend/src/components/AgentSelector.vue
index 7848e61a..573d3502 100644
--- a/frontend/src/components/AgentSelector.vue
+++ b/frontend/src/components/AgentSelector.vue
@@ -204,6 +204,10 @@ type AgentDetailTarget = {
sharedMeta?: { org_name?: string; shared_by_username?: string };
};
+type SharedAgentSelection = Omit & {
+ agent: CustomAgent;
+};
+
const dropdownStyle = ref>({});
const activeDetail = ref(null);
const detailAnchorEl = ref(null);
@@ -232,13 +236,21 @@ const builtinAgents = computed(() => {
const customAgents = computed(() => agentsList.value.filter(a => !a.is_builtin));
-const sharedAgentsList = computed(() =>
- (orgStore.sharedAgents || []).filter(shared => !shared.disabled_by_me),
+const toCustomAgent = (agent: SharedAgentInfo['agent']): CustomAgent => ({
+ is_builtin: false,
+ config: {},
+ ...agent,
+});
+
+const sharedAgentsList = computed(() =>
+ (orgStore.sharedAgents || [])
+ .filter(shared => !shared.disabled_by_me)
+ .map(shared => ({ ...shared, agent: toCustomAgent(shared.agent) })),
);
const currentAgentSourceTenantId = computed(() => settingsStore.selectedAgentSourceTenantId ?? null);
-const isSharedAgentSelected = (shared: SharedAgentInfo) =>
+const isSharedAgentSelected = (shared: SharedAgentSelection) =>
props.currentAgentId === shared.agent.id && currentAgentSourceTenantId.value === String(shared.source_tenant_id);
const isMyAgentSelected = (agent: CustomAgent) =>
@@ -394,8 +406,8 @@ const onOptionEnter = (agent: CustomAgent, event: MouseEvent, sourceTenantId?: s
scheduleDetailPanelPosition();
};
-const onSharedOptionEnter = (shared: SharedAgentInfo, event: MouseEvent) => {
- onOptionEnter(shared.agent as CustomAgent, event, String(shared.source_tenant_id), {
+const onSharedOptionEnter = (shared: SharedAgentSelection, event: MouseEvent) => {
+ onOptionEnter(shared.agent, event, String(shared.source_tenant_id), {
org_name: shared.org_name,
shared_by_username: shared.shared_by_username,
});
@@ -430,13 +442,13 @@ const selectAgent = (agent: CustomAgent) => {
emit('select', agent);
};
-const selectSharedAgent = (shared: SharedAgentInfo) => {
+const selectSharedAgent = (shared: SharedAgentSelection) => {
const sourceTenantId = String(shared.source_tenant_id);
if (getAgentNotReadyLabels(shared.agent, sourceTenantId).length > 0) {
- emitAgentNotReady(shared.agent as CustomAgent, sourceTenantId);
+ emitAgentNotReady(shared.agent, sourceTenantId);
return;
}
- emit('select', shared.agent as CustomAgent, sourceTenantId);
+ emit('select', shared.agent, sourceTenantId);
};
const goToSettings = (agent: CustomAgent, sourceTenantId?: string) => {
diff --git a/frontend/src/components/IMChannelPanel.vue b/frontend/src/components/IMChannelPanel.vue
index 398ee378..9600220b 100644
--- a/frontend/src/components/IMChannelPanel.vue
+++ b/frontend/src/components/IMChannelPanel.vue
@@ -33,7 +33,7 @@
handleChannelMenuClick(data, channel)">
+ @click="handleChannelMenuClick($event, channel)">
diff --git a/frontend/src/components/ModelEditorDialog.vue b/frontend/src/components/ModelEditorDialog.vue
index 40a0762d..90f38c99 100644
--- a/frontend/src/components/ModelEditorDialog.vue
+++ b/frontend/src/components/ModelEditorDialog.vue
@@ -967,7 +967,7 @@ const selectModelType = async (type: EditorModelType) => {
formData.value.provider = 'generic'
formData.value.baseUrl = ''
} else {
- handleProviderChange(formData.value.provider)
+ handleProviderChange(formData.value.provider || 'generic')
}
if (showThinkingControlField.value && !isEdit.value) {
thinkingControlManual.value = false
@@ -1319,7 +1319,7 @@ const checkRemoteAPI = async () => {
// 对话模型(KnowledgeQA)
result = await checkRemoteModel({
modelName: formData.value.modelName,
- baseUrl: formData.value.baseUrl,
+ baseUrl: formData.value.baseUrl || '',
apiKey: formData.value.apiKey || '',
provider: formData.value.provider,
...idPayload,
@@ -1332,7 +1332,7 @@ const checkRemoteAPI = async () => {
result = await testEmbeddingModel({
source: 'remote',
modelName: formData.value.modelName,
- baseUrl: formData.value.baseUrl,
+ baseUrl: formData.value.baseUrl || '',
apiKey: formData.value.apiKey || '',
dimension: formData.value.dimension,
supportsDimensionOverride: formData.value.supportsDimensionOverride ?? false,
@@ -1360,7 +1360,7 @@ const checkRemoteAPI = async () => {
: {}
result = await checkRerankModel({
modelName: formData.value.modelName,
- baseUrl: formData.value.baseUrl,
+ baseUrl: formData.value.baseUrl || '',
apiKey: formData.value.apiKey || '',
provider: formData.value.provider,
...idPayload,
@@ -1375,7 +1375,7 @@ const checkRemoteAPI = async () => {
// VLLM 使用 checkRemoteModel 进行基础连接测试
result = await checkRemoteModel({
modelName: formData.value.modelName,
- baseUrl: formData.value.baseUrl,
+ baseUrl: formData.value.baseUrl || '',
apiKey: formData.value.apiKey || '',
provider: formData.value.provider,
...idPayload,
@@ -1387,7 +1387,7 @@ const checkRemoteAPI = async () => {
// ASR 模型(语音识别)— 使用专用的 ASR 测试接口(/v1/audio/transcriptions)
result = await checkASRModel({
modelName: formData.value.modelName,
- baseUrl: formData.value.baseUrl,
+ baseUrl: formData.value.baseUrl || '',
apiKey: formData.value.apiKey || '',
provider: formData.value.provider,
...idPayload,
diff --git a/frontend/src/components/manual-knowledge-editor.vue b/frontend/src/components/manual-knowledge-editor.vue
index 84a14773..560951c9 100644
--- a/frontend/src/components/manual-knowledge-editor.vue
+++ b/frontend/src/components/manual-knowledge-editor.vue
@@ -414,7 +414,7 @@ const previewHTML = computed(() => {
return `${t('manualEditor.preview.empty')}
`
}
const safeMarkdown = safeMarkdownToHTML(form.content)
- const html = marked.parse(safeMarkdown)
+ const html = marked.parse(safeMarkdown, { async: false })
return sanitizeHTML(html)
})
diff --git a/frontend/src/components/menu.vue b/frontend/src/components/menu.vue
index ababf30c..1924c5f5 100644
--- a/frontend/src/components/menu.vue
+++ b/frontend/src/components/menu.vue
@@ -482,6 +482,7 @@ const filteredGroupedSessions = computed(() => {
bucket.items.map((item) => ({
...item,
path: `chat/${item.id}`,
+ title: item.title || '',
})),
dateBucketLabels.value,
(session) => classifyDateBucket(session.updated_at || session.created_at),
diff --git a/frontend/src/composables/useChatStreamHandler.ts b/frontend/src/composables/useChatStreamHandler.ts
index 3f33095e..f3e53b24 100644
--- a/frontend/src/composables/useChatStreamHandler.ts
+++ b/frontend/src/composables/useChatStreamHandler.ts
@@ -259,7 +259,8 @@ export function useChatStreamHandler(options: UseChatStreamHandlerOptions) {
const events: ChatMessage[] = []
if (agentSteps && Array.isArray(agentSteps) && agentSteps.length > 0) {
- agentSteps.forEach((step: ChatMessage) => {
+ agentSteps.forEach((rawStep) => {
+ const step = rawStep as ChatMessage
const stepTimestamp = step.timestamp ? new Date(String(step.timestamp)).getTime() : 0
const toolCalls = step.tool_calls
const hasToolCalls = toolCalls && Array.isArray(toolCalls) && toolCalls.length > 0
diff --git a/frontend/src/stores/editorResources.ts b/frontend/src/stores/editorResources.ts
index ee9b0293..c49e786c 100644
--- a/frontend/src/stores/editorResources.ts
+++ b/frontend/src/stores/editorResources.ts
@@ -13,7 +13,7 @@ import {
} from '@/api/system'
import { listMCPServices, type MCPService } from '@/api/mcp-service'
import { listSkills, type SkillInfo } from '@/api/skill'
-import { getAgentTypePresets, getPlaceholders, type AgentTypePreset, type PlaceholderDefinition } from '@/api/agent'
+import { getAgentTypePresets, getPlaceholders, type AgentTypePreset, type PlaceholdersResponse } from '@/api/agent'
import { getTenantRetrievalConfig } from '@/api/retrieval'
const CACHE_TTL_MS = 60_000
@@ -38,7 +38,7 @@ export const useEditorResourcesStore = defineStore('editorResources', () => {
const skillsAvailable = ref(true)
const agentTypePresets = ref([])
const promptTemplates = ref(null)
- const placeholders = ref([])
+ const placeholders = ref(null)
const tenantRetrievalConfig = ref | null>(null)
const parserEngines = ref([])
const systemInfo = ref(null)
@@ -114,7 +114,7 @@ export const useEditorResourcesStore = defineStore('editorResources', () => {
async function ensurePlaceholders(force = false): Promise {
return runOnce('placeholders', force, async () => {
const placeholdersRes = await getPlaceholders()
- placeholders.value = placeholdersRes?.data ?? []
+ placeholders.value = placeholdersRes?.data ?? null
loadedAt.value.placeholders = Date.now()
})
}
@@ -166,7 +166,7 @@ export const useEditorResourcesStore = defineStore('editorResources', () => {
skills.value = []
agentTypePresets.value = []
promptTemplates.value = null
- placeholders.value = []
+ placeholders.value = null
tenantRetrievalConfig.value = null
parserEngines.value = []
systemInfo.value = null
diff --git a/frontend/src/stores/settings.ts b/frontend/src/stores/settings.ts
index f7cf8e56..9af40c66 100644
--- a/frontend/src/stores/settings.ts
+++ b/frontend/src/stores/settings.ts
@@ -18,6 +18,7 @@ interface Settings {
selectedTags: Array<{ id: string; name: string; kbId: string; kbName?: string }>;
selectedMCPServices: string[];
selectedSkills: string[];
+ selectedTools?: string[];
modelConfig: ModelConfig; // 模型配置
ollamaConfig: OllamaConfig; // Ollama配置
webSearchEnabled: boolean; // 网络搜索是否启用
diff --git a/frontend/src/utils/request.ts b/frontend/src/utils/request.ts
index 152e9be9..bc90c901 100644
--- a/frontend/src/utils/request.ts
+++ b/frontend/src/utils/request.ts
@@ -246,14 +246,14 @@ instance.interceptors.response.use(
}
);
-export function get(url: string, config?: any) {
- return instance.get(url, config);
+export function get(url: string, config?: any): Promise {
+ return instance.get(url, config) as unknown as Promise;
}
-export async function getDown(url: string) {
- let res = await instance.get(url, {
+export async function getDown(url: string): Promise {
+ const res = await instance.get(url, {
responseType: "blob",
- });
+ }) as unknown as Blob;
return res
}
@@ -262,7 +262,7 @@ export function postUpload(
data = {},
onUploadProgress?: (progressEvent: any) => void,
config: any = {},
-) {
+): Promise {
return instance.post(url, data, {
...config,
headers: {
@@ -271,26 +271,26 @@ export function postUpload(
...(config.headers || {}),
},
onUploadProgress: onUploadProgress || config.onUploadProgress,
- });
+ }) as unknown as Promise;
}
-export function postChat(url: string, data = {}) {
+export function postChat(url: string, data = {}): Promise {
return instance.post(url, data, {
headers: {
"Content-Type": "text/event-stream;charset=utf-8",
"X-Request-ID": `${generateRandomString(12)}`,
},
- });
+ }) as unknown as Promise;
}
-export function post(url: string, data = {}, config?: any) {
- return instance.post(url, data, config);
+export function post(url: string, data = {}, config?: any): Promise {
+ return instance.post(url, data, config) as unknown as Promise;
}
-export function put(url: string, data = {}) {
- return instance.put(url, data);
+export function put(url: string, data = {}, config?: any): Promise {
+ return instance.put(url, data, config) as unknown as Promise;
}
-export function del(url: string, data?: any) {
- return instance.delete(url, { data });
+export function del(url: string, data?: any): Promise {
+ return instance.delete(url, { data }) as unknown as Promise;
}
diff --git a/frontend/src/utils/security.ts b/frontend/src/utils/security.ts
index 22a70f18..f462c767 100644
--- a/frontend/src/utils/security.ts
+++ b/frontend/src/utils/security.ts
@@ -69,7 +69,7 @@ export function sanitizeHTML(html: string): string {
try {
const preparedHTML = protectProviderImageSrcInHTML(html);
- return DOMPurify.sanitize(preparedHTML, DOMPurifyConfig);
+ return DOMPurify.sanitize(preparedHTML, DOMPurifyConfig as unknown as Config);
} catch (error) {
console.error('HTML sanitization failed:', error);
// 如果清理失败,返回转义的纯文本
@@ -85,7 +85,7 @@ export function sanitizeMarkdownHTML(html: string): string {
try {
const preparedHTML = protectProviderImageSrcInHTML(html);
- return DOMPurify.sanitize(preparedHTML, markdownDomPurifyConfig as Config);
+ return DOMPurify.sanitize(preparedHTML, markdownDomPurifyConfig as unknown as Config);
} catch (error) {
console.error('Markdown HTML sanitization failed:', error);
return escapeHTML(html);
diff --git a/frontend/src/views/agent/AgentEditorModal.vue b/frontend/src/views/agent/AgentEditorModal.vue
index 4d7af6ef..c5d58ff1 100644
--- a/frontend/src/views/agent/AgentEditorModal.vue
+++ b/frontend/src/views/agent/AgentEditorModal.vue
@@ -2994,7 +2994,9 @@ const loadDependencies = async () => {
webSearchProviderList.value = chatResources.webSearchProviders as WebSearchProviderEntity[];
- placeholderData.value = editorResources.placeholders as PlaceholderDefinition[];
+ if (editorResources.placeholders) {
+ placeholderData.value = editorResources.placeholders;
+ }
const rc = editorResources.tenantRetrievalConfig as Record | null;
if (rc?.embedding_top_k) defaultEmbeddingTopK.value = rc.embedding_top_k;
diff --git a/frontend/src/views/chat/components/AgentStreamDisplay.vue b/frontend/src/views/chat/components/AgentStreamDisplay.vue
index 06bf5b12..aadda260 100644
--- a/frontend/src/views/chat/components/AgentStreamDisplay.vue
+++ b/frontend/src/views/chat/components/AgentStreamDisplay.vue
@@ -719,6 +719,7 @@ interface SessionData {
isAgentMode?: boolean;
agentEventStream?: any[];
knowledge_references?: any[];
+ [key: string]: unknown;
}
const props = defineProps<{
@@ -1617,7 +1618,7 @@ const onRootClick = (e: Event) => {
const slug = wikiEl.getAttribute('data-slug');
// Determine the relevant KB ID
- const kbId = getKbIdForWiki(slug);
+ const kbId = getKbIdForWiki(slug || '');
if (kbId && slug) {
openWikiDrawer(kbId, slug);
diff --git a/frontend/src/views/chat/components/McpOAuthCard.vue b/frontend/src/views/chat/components/McpOAuthCard.vue
index 1ece3bb0..0efb990d 100644
--- a/frontend/src/views/chat/components/McpOAuthCard.vue
+++ b/frontend/src/views/chat/components/McpOAuthCard.vue
@@ -81,8 +81,8 @@ const { t } = useI18n()
const authorizing = ref(false)
const canceling = ref(false)
const now = ref(Date.now())
-let clock: ReturnType | null = null
-let poll: ReturnType | null = null
+let clock: number | null = null
+let poll: number | null = null
const deadline = computed(() => {
const base = (props.requestedAt || 0) * 1000
@@ -138,7 +138,7 @@ function formatCountdown(s: number): string {
function stopPoll() {
if (poll) {
- clearInterval(poll)
+ window.clearInterval(poll)
poll = null
}
}
@@ -248,13 +248,13 @@ const authorize = async () => {
}
onMounted(() => {
- clock = setInterval(() => {
+ clock = window.setInterval(() => {
now.value = Date.now()
}, 1000)
})
onBeforeUnmount(() => {
- if (clock) clearInterval(clock)
+ if (clock) window.clearInterval(clock)
stopPoll()
})
diff --git a/frontend/src/views/chat/components/ToolResultRenderer.vue b/frontend/src/views/chat/components/ToolResultRenderer.vue
index d3e29263..3c64818c 100644
--- a/frontend/src/views/chat/components/ToolResultRenderer.vue
+++ b/frontend/src/views/chat/components/ToolResultRenderer.vue
@@ -59,7 +59,7 @@