import { get, post, put, del } from "../../utils/request"; // 智能体配置 // 智能推理下的智能体类型预设 ID // 'rag-qa' : 经典文档/FAQ 分块 RAG // 'wiki-qa' : Wiki 图谱导航问答 // 'hybrid-rag-wiki': Wiki + 分块混合检索 // 'custom' : 完全自定义(不应用预设) export type AgentType = 'rag-qa' | 'wiki-qa' | 'hybrid-rag-wiki' | 'data-analysis' | 'custom'; export interface QuestionSuggestionConfig { starters: { enabled: boolean; mode: 'curated' | 'knowledge' | 'hybrid'; items: string[]; count: number; }; follow_ups: { enabled: boolean; mode: 'generated' | 'knowledge' | 'hybrid'; count: number; model_id?: string; additional_instruction?: string; categories: Array<'clarify' | 'deepen' | 'action'>; max_context_turns: number; suppress_on_fallback: boolean; suppress_when_answer_asks_question: boolean; knowledge_fallback: boolean; allow_regenerate: boolean; }; } export type AgentRole = '' | 'general' | 'coordinator' | 'production' | 'qc' | 'service' | 'training_map'; export interface CustomAgentConfig { // ===== 基础设置 ===== role?: AgentRole; content_tags?: string[]; fusion_agent_ids?: string[]; agent_mode?: 'quick-answer' | 'smart-reasoning'; // 运行模式:quick-answer=RAG模式, smart-reasoning=ReAct Agent模式 // 智能推理模式下的类型预设,用于一键应用"系统提示词 + 工具 + KB 兼容性"组合 // 仅在 agent_mode === 'smart-reasoning' 时生效;quick-answer 模式忽略 agent_type?: AgentType; system_prompt?: string; // 统一系统提示词(使用 {{web_search_status}} 占位符动态控制行为) system_prompt_id?: string; // 引用的 prompt template ID(预设会填入此字段) context_template?: string; // 上下文模板(普通模式) // ===== 模型设置 ===== model_id?: string; rerank_model_id?: string; // ReRank 模型 ID temperature?: number; max_completion_tokens?: number; // 0 = 跟随系统默认(快速问答 2048;智能推理 4096,绑沙箱可写文件时 24576)。大于 0 为自定义上限 thinking?: boolean; // 是否启用思考模式(支持扩展思考的模型) citation_enabled?: boolean; // 是否在最终回答中输出知识库/网页来源引用(默认开启) // ===== Agent模式设置 ===== max_iterations?: number; // 最大迭代次数;-1 表示不限制 llm_call_timeout?: number; // LLM调用超时时间(秒) allowed_tools?: string[]; // 允许的工具 reflection_enabled?: boolean; // 是否启用反思 // MCP服务选择模式:all=全部启用的MCP服务, selected=指定服务, none=不使用MCP mcp_selection_mode?: 'all' | 'selected' | 'none'; mcp_services?: string[]; // 选择的MCP服务ID列表 // 对话中触发 OAuth 授权时的等待超时(秒):到点后自动跳过授权提示。 // <=0 时使用服务端默认超时。仅对使用 OAuth 的 MCP 服务生效。 mcp_auth_wait_timeout?: number; // ===== Skills设置(仅Agent模式)===== // Skills选择模式:all=全部预装, selected=指定, none=不使用 skills_selection_mode?: 'all' | 'selected' | 'none'; selected_skills?: string[]; // 选择的Skill名称列表 instruction_skill_ids?: string[]; // Markdown 指令技能,无需沙箱 // ===== 沙箱设置 ===== // 该智能体的技能脚本运行在哪个沙箱配置上;为空表示不启用沙箱执行。 // 指向逻辑配置而非某个具体版本,凭据轮换时无需重新指派每个智能体。 sandbox_config_id?: string; // ===== 知识库设置 ===== // 知识库选择模式:all=全部知识库, selected=指定知识库, none=不使用知识库 kb_selection_mode?: 'all' | 'selected' | 'none'; knowledge_bases?: string[]; // 是否仅在显式 @ 提及时检索知识库(默认: false) // true: 只有用户通过 @ 明确提及知识库/文档时才检索 // false: 根据 kb_selection_mode 自动检索知识库 retrieve_kb_only_when_mentioned?: boolean; // ===== 图片上传/多模态设置 ===== image_upload_enabled?: boolean; // 是否启用图片上传(默认: false) vlm_model_id?: string; // VLM模型ID(图片分析用) image_storage_provider?: string; // 图片存储提供商 audio_upload_enabled?: boolean; // 是否启用音频上传/ASR转录(默认: false) asr_model_id?: string; // ASR模型ID(音频转录用) // 附件图片理解 / 扫描件 OCR 开关(默认: false,开启会增加解析耗时) attachment_image_understanding?: boolean; // 扫描件 OCR 最大页数(0 = 使用全局默认 WEKNORA_CHAT_ATTACHMENT_OCR_MAX_PAGES) attachment_ocr_max_pages?: number; // 单轮问答等待附件解析完成的最长时间(秒,0 = 使用全局默认 WEKNORA_CHAT_ATTACHMENT_WAIT_TIMEOUT_SEC) attachment_parse_wait_timeout_sec?: number; // ===== 聊天附件解析引擎策略 ===== // 按文件类型选择解析引擎;优先级:请求 parser_engine > 智能体规则 > 租户规则 > auto chat_parser_engine_rules?: { file_types: string[]; engine: string }[]; // ===== 文件类型限制 ===== // 支持的文件类型(如 ["csv", "xlsx", "xls"]) // 为空表示支持所有文件类型 supported_file_types?: string[]; // ===== 网络搜索设置 ===== web_search_enabled?: boolean; web_search_provider_id?: string; web_search_max_results?: number; // ===== 多轮对话设置 ===== multi_turn_enabled?: boolean; // 是否启用多轮对话 history_turns?: number; // 保留历史轮数 // ===== 长期记忆 ===== // 该智能体是否可以读取用户的长期记忆。 // 缺省(旧数据)等同于 true:这是一个只能"关"的开关,空间设置关闭时 // 这里打开也不会生效。 memory_enabled?: boolean; // ===== 检索策略设置 ===== embedding_top_k?: number; // 向量召回TopK keyword_threshold?: number; // 关键词召回阈值 vector_threshold?: number; // 向量召回阈值 rerank_top_k?: number; // 重排TopK rerank_threshold?: number; // 重排阈值 // ===== 高级设置(主要用于普通模式)===== enable_query_expansion?: boolean; // 是否启用查询扩展 enable_rewrite?: boolean; // 是否启用问题改写 rewrite_prompt_system?: string; // 改写系统提示词 rewrite_prompt_user?: string; // 改写用户提示词模板 fallback_strategy?: 'fixed' | 'model'; // 兜底策略 fallback_response?: string; // 固定兜底回复 fallback_prompt?: string; // 兜底提示词(模型生成时) // 意图提示词:非检索意图(问候、闲聊等)时覆盖主系统提示词 intent_prompts?: Record; // ===== 已废弃字段(保留兼容)===== welcome_message?: string; question_suggestions?: QuestionSuggestionConfig; } // 智能体 export interface CustomAgent { digital_human?: { id: string; name: string; applied_version: number; active_version: number }; enabled?: boolean; visibility?: 'private' | 'global'; id: string; name: string; description?: string; avatar?: string; is_builtin: boolean; tenant_id?: number; created_by?: string; // creator_name 由后端 list 接口批量回填,仅用于列表卡片来源徽章。 creator_name?: string; config: CustomAgentConfig; created_at?: string; updated_at?: string; } // 创建智能体请求 export interface CreateAgentRequest { name: string; description?: string; avatar?: string; config?: CustomAgentConfig; } // 更新智能体请求 export interface UpdateAgentRequest { name: string; description?: string; avatar?: string; config?: CustomAgentConfig; } // 内置智能体 ID(常用的保留常量,便于代码引用) export const BUILTIN_QUICK_ANSWER_ID = 'builtin-quick-answer'; export const BUILTIN_SMART_REASONING_ID = 'builtin-smart-reasoning'; // AgentMode 常量 export const AGENT_MODE_QUICK_ANSWER = 'quick-answer'; export const AGENT_MODE_SMART_REASONING = 'smart-reasoning'; // Deprecated: Use BUILTIN_QUICK_ANSWER_ID instead export const BUILTIN_AGENT_NORMAL_ID = BUILTIN_QUICK_ANSWER_ID; // Deprecated: Use BUILTIN_SMART_REASONING_ID instead export const BUILTIN_AGENT_AGENT_ID = BUILTIN_SMART_REASONING_ID; // 获取智能体列表(包括内置智能体) // disabled_own_agent_ids: 当前空间在对话下拉中停用的「我的」智能体 ID,仅影响本空间 export function listAgents(params?: { /** * Optional creator filter; mirrors listKnowledgeBases. Built-in agents * (is_builtin=true) are always returned regardless of this filter so * the conversation dropdown never silently loses quick-answer / * smart-reasoning when a user picks "Created by me". */ creator?: 'all' | 'mine' | 'others'; }) { const qs = params?.creator && params.creator !== 'all' ? `?creator=${params.creator}` : ''; return get<{ data: CustomAgent[]; disabled_own_agent_ids?: string[] }>(`/api/v1/agents${qs}`); } // 获取智能体详情 export function getAgentById(id: string) { return get<{ data: CustomAgent }>(`/api/v1/agents/${id}`); } // 创建智能体 export function createAgent(data: CreateAgentRequest) { return post<{ data: CustomAgent }>('/api/v1/agents', data); } export function draftAgent(data: { model_id: string; requirement: string }) { return post<{ data: CreateAgentRequest }>('/api/v1/agents/draft', data, { timeout: 120000 }); } // 更新智能体 export function updateAgent(id: string, data: UpdateAgentRequest) { return put<{ data: CustomAgent }>(`/api/v1/agents/${id}`, data); } // 删除智能体 export function deleteAgent(id: string) { return del<{ success: boolean }>(`/api/v1/agents/${id}`); } // 复制智能体 export function copyAgent(id: string) { return post<{ data: CustomAgent }>(`/api/v1/agents/${id}/copy`); } // 判断是否为内置智能体(通过 agent.is_builtin 字段或 ID 前缀判断) export function isBuiltinAgent(agentId: string): boolean { return agentId.startsWith('builtin-'); } // 占位符定义 export interface PlaceholderDefinition { name: string; label: string; description: string; } // 占位符响应 export interface PlaceholdersResponse { all: PlaceholderDefinition[]; system_prompt: PlaceholderDefinition[]; agent_system_prompt: PlaceholderDefinition[]; context_template: PlaceholderDefinition[]; rewrite_system_prompt: PlaceholderDefinition[]; rewrite_prompt: PlaceholderDefinition[]; fallback_prompt: PlaceholderDefinition[]; } // 获取占位符定义 export function getPlaceholders() { return get<{ data: PlaceholdersResponse }>('/api/v1/agents/placeholders'); } // ===== 智能体类型预设 ===== // 后端 kb_filter 结构(见 internal/types/agent_type_preset.go) export interface AgentTypeKBFilter { any_of?: string[]; // KB 至少拥有其一 all_of?: string[]; // KB 必须全部拥有 none_of?: string[]; // KB 必须全部不拥有 } // KB 能力标签(后端 types.KBCapabilities 的 JSON) export interface KBCapabilities { vector: boolean; keyword: boolean; wiki: boolean; graph: boolean; faq: boolean; } // 预设的"自动填充"配置载荷:仅包含被预设覆盖的字段;其他字段不动 export interface AgentTypePresetConfig { system_prompt_id?: string; temperature?: number; max_iterations?: number; allowed_tools?: string[]; retain_retrieval_history?: boolean; faq_priority_enabled?: boolean; web_search_enabled?: boolean; supported_file_types?: string[]; kb_selection_mode?: 'all' | 'selected' | 'none'; } export interface AgentTypePresetI18n { label: string; description: string; } export interface AgentTypePreset { id: AgentType; i18n: Record; config?: AgentTypePresetConfig; // 为空表示"自定义"类型(无预设) kb_filter?: AgentTypeKBFilter; // 为空表示所有 KB 可选 } // 拉取类型预设列表(编辑器用) export function getAgentTypePresets() { return get<{ data: AgentTypePreset[] }>('/api/v1/agents/type-presets'); } // ===== IM渠道 ===== export interface IMChannel { id: string; tenant_id?: number; agent_id: string; // 'lark' is Feishu's international edition; it shares Feishu's credentials and modes. platform: 'wecom' | 'feishu' | 'lark' | 'slack' | 'telegram' | 'dingtalk' | 'mattermost' | 'wechat' | 'qqbot' | 'yunzhijia'; name: string; enabled: boolean; mode: 'webhook' | 'websocket' | 'longpoll'; output_mode: 'stream' | 'full'; session_mode?: 'user' | 'thread'; knowledge_base_id?: string; credentials: Record; created_at?: string; updated_at?: string; } export function listIMChannels(agentId: string) { return get<{ data: IMChannel[] }>(`/api/v1/agents/${agentId}/im-channels`); } // Tenant-wide overview row. Credentials are intentionally omitted — use // listIMChannels(agentId) when you need to edit a specific channel. export interface IMChannelOverview { id: string; tenant_id: number; agent_id: string; agent_name: string; // localized built-in name when the agent is built-in platform: IMChannel['platform']; name: string; enabled: boolean; mode: IMChannel['mode']; output_mode: IMChannel['output_mode']; session_mode?: IMChannel['session_mode']; bot_identity: string; created_at: string; updated_at: string; } export function listAllIMChannels() { return get<{ data: IMChannelOverview[] }>('/api/v1/im-channels'); } export function createIMChannel(agentId: string, data: Partial) { return post<{ data: IMChannel }>(`/api/v1/agents/${agentId}/im-channels`, data); } export function updateIMChannel(id: string, data: Partial) { return put<{ data: IMChannel }>(`/api/v1/im-channels/${id}`, data); } export function deleteIMChannel(id: string) { return del<{ success: boolean }>(`/api/v1/im-channels/${id}`); } export function toggleIMChannel(id: string) { return post<{ data: IMChannel }>(`/api/v1/im-channels/${id}/toggle`); } // ===== 推荐问题 ===== // 推荐问题 export interface SuggestedQuestion { question: string; source: 'faq' | 'document' | 'agent_config' | 'wiki'; knowledge_base_id?: string; } // 获取智能体推荐问题 // 根据智能体关联的知识库范围返回推荐问题,用于前端对话面板快捷提问 export function getSuggestedQuestions( agentId: string, params?: { knowledge_base_ids?: string[]; knowledge_ids?: string[]; tag_scopes?: Array<{ knowledge_base_id: string; tag_ids: string[] }>; limit?: number; } ) { const query = new URLSearchParams(); if (params?.knowledge_base_ids?.length) query.set('knowledge_base_ids', params.knowledge_base_ids.join(',')); if (params?.knowledge_ids?.length) query.set('knowledge_ids', params.knowledge_ids.join(',')); if (params?.tag_scopes?.length) query.set('tag_scopes', JSON.stringify(params.tag_scopes)); if (params?.limit) query.set('limit', String(params.limit)); const qs = query.toString(); return get<{ data: { questions: SuggestedQuestion[] } }>(`/api/v1/agents/${agentId}/suggested-questions${qs ? '?' + qs : ''}`); } // ===== WeChat QR Code Login ===== export interface WeChatQRCodeResult { qrcode_url: string; qrcode: string; } export interface WeChatQRCodeStatus { status: 'wait' | 'scaned' | 'confirmed' | 'expired'; credentials?: { bot_token: string; ilink_bot_id: string; ilink_user_id: string; }; baseurl?: string; } export function getWeChatQRCode() { return post<{ data: WeChatQRCodeResult }>('/api/v1/wechat/qrcode'); } export function pollWeChatQRCodeStatus(qrcode: string) { return post<{ data: WeChatQRCodeStatus }>('/api/v1/wechat/qrcode/status', { qrcode }); }