import type {SettingTabBuilder} from "../../setting/builder"; import {confirmDialog} from "../../../dialog/confirmDialog"; import {showMessage} from "../../../dialog/message"; import {fetchPost} from "../../../util/fetch"; import { getProvidersBlockKeywords, getModelPickerKeywords, genMcpServersBlockHtml, getMcpServersBlockKeywords, mountMcpServersBlock, genEmbeddingStatsHtml, getEmbeddingStatsKeywords, mountEmbeddingStatsBlock, mountEmbeddingTestBtn, mountRerankTestBtn, mountDecisionTestBtn, } from "./aiUi"; import { genProviderCardsHtml, mountProviderCards, genGroupedModelPickerHtml, mountGroupedModelPicker, } from "./aiProviderUi"; import { getAgentCapabilityKeywords, mountAgentCapabilityBlock, } from "./aiCapabilityUi"; import { getUserSkillsBlockKeywords, mountUserSkillsBlock, } from "./aiSkillUi"; import {isAgentStreamingMarkdownEnabled, setAgentStreamingMarkdownEnabled} from "./agentStreamingMarkdown"; import {openSkillManager} from "../../../ai/skills/manager"; import {openAgentInstructions} from "./aiInstructions"; import {genMcpOAuthHtml, mountMcpOAuth} from "./mcpOAuthUi"; const registerAiProvidersGroup = (tab: SettingTabBuilder) => { const group = tab.group("providers", window.siyuan.languages.apiProvider); group.slot({ key: "providers", keywords: getProvidersBlockKeywords(), html: genProviderCardsHtml, afterMount: mountProviderCards, }); }; const registerAiEditingGroup = (tab: SettingTabBuilder) => { const groupId = "editing"; const group = tab.group(groupId, window.siyuan.languages.editor); group.slot({ key: "editingModelPicker", keywords: getModelPickerKeywords(groupId), html: () => genGroupedModelPickerHtml(groupId), afterMount: (root) => { mountGroupedModelPicker(root, groupId); }, }); group.number("ai.editing.maxCompletionTokens", { title: window.siyuan.languages.apiMaxTokens, desc: window.siyuan.languages.apiMaxTokensTip, min: 0, }); group.number("ai.editing.maxHistoryMessages", { title: window.siyuan.languages.apiMaxContexts, desc: window.siyuan.languages.apiMaxContextsTip, min: 1, max: 64, }); group.number("ai.editing.temperature", { title: window.siyuan.languages.apiTemperature, desc: window.siyuan.languages.apiTemperatureTip, min: 0, max: 2, step: "0.1", }); }; const registerAiAgentGroup = (tab: SettingTabBuilder) => { const groupId = "agent"; const group = tab.group(groupId, window.siyuan.languages.agentChat); group.slot({ key: "agentModelPicker", keywords: getModelPickerKeywords(groupId), html: () => genGroupedModelPickerHtml(groupId), afterMount: (root) => { mountGroupedModelPicker(root, groupId); }, }); group.number("ai.agent.maxCompletionTokens", { title: window.siyuan.languages.apiMaxTokens, desc: window.siyuan.languages.apiMaxTokensTip, min: 0, }); group.button({ id: "aiAgentInstructions", title: window.siyuan.languages.agentInstructions, desc: window.siyuan.languages.agentInstructionsTip, label: window.siyuan.languages.edit, icon: "iconEdit", afterMount: root => { root.querySelector("#aiAgentInstructions")?.addEventListener("click", openAgentInstructions); }, }); group.switch("agentStreamingMarkdown", { title: window.siyuan.languages.agentStreamingMarkdown, desc: window.siyuan.languages.agentStreamingMarkdownTip, readConfig: isAgentStreamingMarkdownEnabled, save: (value) => setAgentStreamingMarkdownEnabled(value === true), }); group.number("ai.agent.maxToolCallRounds", { title: window.siyuan.languages.agentMaxToolCallRounds, desc: window.siyuan.languages.agentMaxToolCallRoundsTip, min: 0, }); group.number("ai.agent.temperature", { title: window.siyuan.languages.apiTemperature, desc: window.siyuan.languages.apiTemperatureTip, min: 0, max: 2, step: "0.1", }); group.number("ai.agent.sessionTimeout", { title: window.siyuan.languages.agentTimeout, desc: window.siyuan.languages.agentTimeoutTip, min: 0, max: 3600, unit: "s", }); group.number("ai.agent.streamIdleTimeout", { title: window.siyuan.languages.agentStreamIdleTimeout, desc: window.siyuan.languages.agentStreamIdleTimeoutTip, min: 1, max: 600, unit: "s", }); group.number("ai.agent.confirmTimeout", { title: window.siyuan.languages.agentConfirmTimeout, desc: window.siyuan.languages.agentConfirmTimeoutTip, min: 0, unit: "s", }); group.number("ai.agent.maxRetries", { title: window.siyuan.languages.agentMaxRetries, desc: window.siyuan.languages.agentMaxRetriesTip, min: 0, max: 10, }); group.button({ id: "aiAgentCapabilities", title: window.siyuan.languages.agentCapabilities, desc: window.siyuan.languages.agentCapabilitiesTip, label: window.siyuan.languages.config, icon: "iconSettings", keywords: getAgentCapabilityKeywords(), afterMount: mountAgentCapabilityBlock, }); }; const registerAiDecisionGroup = (tab: SettingTabBuilder) => { const group = tab.group("decision", window.siyuan.languages.decisionModel); group.switch("ai.decision.enabled", { title: window.siyuan.languages.decisionModel, desc: window.siyuan.languages.decisionModelTip, }); group.textBlock("ai.decision.endpoint", { spellcheck: false, title: window.siyuan.languages.apiEndpoint, desc: window.siyuan.languages.decisionEndpointTip, mode: "input-text", }); group.textBlock("ai.decision.apiKey", { spellcheck: false, title: window.siyuan.languages.apiKey, desc: window.siyuan.languages.apiKeyTip, mode: "input-password", }); group.textBlock("ai.decision.name", { spellcheck: false, title: window.siyuan.languages.apiModel, desc: window.siyuan.languages.apiModelTip, mode: "input-text", afterMount: mountDecisionTestBtn, }); group.number("ai.decision.timeout", { title: window.siyuan.languages.apiTimeout, desc: window.siyuan.languages.apiTimeoutTip, min: 1, max: 600, unit: "s", }); }; const registerAiImageGenerationGroup = (tab: SettingTabBuilder) => { const groupId = "imageGeneration"; const group = tab.group(groupId, window.siyuan.languages.aiImageGeneration); group.slot({ key: "imageGenerationModelPicker", keywords: getModelPickerKeywords(groupId), html: () => genGroupedModelPickerHtml(groupId), afterMount: (root) => { mountGroupedModelPicker(root, groupId); }, }); group.number("ai.imageGeneration.requestTimeout", { title: window.siyuan.languages.apiTimeout, desc: window.siyuan.languages.apiTimeoutTip, min: 1, max: 600, unit: "s", }); }; const registerAiSkillsGroup = (tab: SettingTabBuilder) => { const group = tab.group("skills", window.siyuan.languages.tokenCatSkills); group.button({ id: "aiWorkspaceSkills", title: window.siyuan.languages.agentWorkspaceSkills, desc: window.siyuan.languages.agentWorkspaceSkillsTip, label: window.siyuan.languages.manage, icon: "iconSettings", afterMount: root => { root.querySelector("#aiWorkspaceSkills")?.addEventListener("click", () => openSkillManager(root)); }, }); group.button({ id: "aiUserSkills", title: window.siyuan.languages.agentUserSkills, desc: window.siyuan.languages.agentUserSkillsTip, label: window.siyuan.languages.config, icon: "iconSettings", keywords: getUserSkillsBlockKeywords(), afterMount: mountUserSkillsBlock, }); }; const registerAiMcpGroup = (tab: SettingTabBuilder) => { const group = tab.group("mcp", window.siyuan.languages.configGroupMcp); group.slot({ key: "mcpOAuthServer", keywords: [window.siyuan.languages.mcpOAuthServer, "OAuth", "ChatGPT"], html: genMcpOAuthHtml, afterMount: mountMcpOAuth, }); group.slot({ key: "mcpServers", keywords: getMcpServersBlockKeywords(), html: genMcpServersBlockHtml, afterMount: mountMcpServersBlock, }); }; const registerAiEmbeddingGroup = (tab: SettingTabBuilder) => { const group = tab.group("embedding", window.siyuan.languages.configGroupEmbedding); group.switch("ai.embedding.enabled", { title: window.siyuan.languages.semanticSearch, desc: window.siyuan.languages.semanticSearchTip, }); group.textBlock("ai.embedding.baseURL", { spellcheck: false, title: window.siyuan.languages.apiBaseURL, desc: window.siyuan.languages.apiBaseURLEmbeddingTip, mode: "input-text", }); group.textBlock("ai.embedding.apiKey", { spellcheck: false, title: window.siyuan.languages.apiKey, desc: window.siyuan.languages.apiKeyTip, mode: "input-password", }); group.textBlock("ai.embedding.name", { spellcheck: false, title: window.siyuan.languages.apiModel, desc: window.siyuan.languages.apiModelTip, mode: "input-text", afterMount: mountEmbeddingTestBtn, }); group.number("ai.embedding.dimensions", { title: window.siyuan.languages.apiDimensions, desc: window.siyuan.languages.apiDimensionsTip, min: 0, }); group.number("ai.embedding.timeout", { title: window.siyuan.languages.apiTimeout, desc: window.siyuan.languages.apiTimeoutTip, min: 1, unit: "s", }); // 独立的嵌入索引重建按钮,不与全局重建索引耦合 group.button({ id: "rebuildEmbeddingIndex", title: window.siyuan.languages.rebuildEmbeddingIndex, desc: window.siyuan.languages.rebuildEmbeddingIndexTip, label: window.siyuan.languages.rebuildEmbeddingIndex, icon: "iconRefresh", afterMount: (root) => { root.querySelector("#rebuildEmbeddingIndex")?.addEventListener("click", () => { confirmDialog(window.siyuan.languages.rebuildEmbeddingIndex, window.siyuan.languages.rebuildEmbeddingIndexConfirmTip, () => { fetchPost("/api/ai/reindexEmbedding", {}, () => { showMessage(window.siyuan.languages.rebuildEmbeddingIndexStarted); }); }); }); }, }); // 嵌入索引进度条 + 统计数字(只读展示,slot 注入) group.slot({ key: "embeddingStats", keywords: getEmbeddingStatsKeywords(), html: genEmbeddingStatsHtml, afterMount: mountEmbeddingStatsBlock, }); }; const registerAiRerankGroup = (tab: SettingTabBuilder) => { const group = tab.group("rerank", window.siyuan.languages.configGroupRerank); group.switch("ai.rerank.enabled", { title: window.siyuan.languages.rerankModel, desc: window.siyuan.languages.rerankTip, }); group.select("ai.rerank.requestFormat", { title: window.siyuan.languages.rerankRequestFormat, desc: window.siyuan.languages.rerankRequestFormatTip, options: [ {value: "cohere", label: window.siyuan.languages.rerankRequestFormatCohere}, {value: "dashscope", label: window.siyuan.languages.rerankRequestFormatDashScope}, ], }); group.textBlock("ai.rerank.endpoint", { spellcheck: false, title: window.siyuan.languages.apiEndpoint, desc: window.siyuan.languages.apiEndpointRerankTip, mode: "input-text", }); group.textBlock("ai.rerank.apiKey", { spellcheck: false, title: window.siyuan.languages.apiKey, desc: window.siyuan.languages.apiKeyTip, mode: "input-password", }); group.textBlock("ai.rerank.name", { spellcheck: false, title: window.siyuan.languages.apiModel, desc: window.siyuan.languages.apiModelTip, mode: "input-text", afterMount: mountRerankTestBtn, }); group.number("ai.rerank.candidateCount", { title: window.siyuan.languages.rerankCandidateCount, desc: window.siyuan.languages.rerankCandidateCountTip, min: 5, max: 100, }); group.number("ai.rerank.timeout", { title: window.siyuan.languages.apiTimeout, desc: window.siyuan.languages.apiTimeoutTip, min: 1, unit: "s", }); }; export const registerAiTab = (tab: SettingTabBuilder) => { registerAiProvidersGroup(tab); registerAiEditingGroup(tab); registerAiAgentGroup(tab); registerAiDecisionGroup(tab); registerAiSkillsGroup(tab); registerAiImageGenerationGroup(tab); registerAiMcpGroup(tab); registerAiEmbeddingGroup(tab); registerAiRerankGroup(tab); };