feat(personalization): 个人空间支持配置对话标题生成模型
新增 title_model 配置,复用子智能体模型库条目生成对话标题: - 个人空间「常规」页签新增「标题生成模型」下拉菜单(复用子智能体 模型列表,general 页签挂载时加载) - 标题生成改为使用所选子智能体模型 profile;未配置时回落模型库 default_model,移除 AGENT_TITLE_* 环境变量覆盖与主智能体默认 模型回退(个人空间为唯一配置来源) - personalization 白名单注册 title_model 键(默认值 + sanitize)
This commit is contained in:
parent
55b3ee44b7
commit
deaa1560a5
@ -82,6 +82,7 @@ DEFAULT_PERSONALIZATION_CONFIG: Dict[str, Any] = {
|
|||||||
"default_permission_mode": "unrestricted",
|
"default_permission_mode": "unrestricted",
|
||||||
"default_work_mode": "plan", # 默认运行模式:plan / ask / execute
|
"default_work_mode": "plan", # 默认运行模式:plan / ask / execute
|
||||||
"auto_generate_title": True,
|
"auto_generate_title": True,
|
||||||
|
"title_model": "", # 对话标题生成使用的子智能体模型条目名(空=跟随主对话默认模型)
|
||||||
"recent_conversations_prompt_enabled": False,
|
"recent_conversations_prompt_enabled": False,
|
||||||
"recent_conversations_prompt_limit": RECENT_CONVERSATIONS_PROMPT_LIMIT_DEFAULT,
|
"recent_conversations_prompt_limit": RECENT_CONVERSATIONS_PROMPT_LIMIT_DEFAULT,
|
||||||
"project_memory_inject_limit": PROJECT_MEMORY_INJECT_LIMIT_DEFAULT, # 项目记忆索引最大注入条数:None-无上限 / >=5-该值
|
"project_memory_inject_limit": PROJECT_MEMORY_INJECT_LIMIT_DEFAULT, # 项目记忆索引最大注入条数:None-无上限 / >=5-该值
|
||||||
@ -278,6 +279,7 @@ def sanitize_personalization_payload(
|
|||||||
else "medium"
|
else "medium"
|
||||||
)
|
)
|
||||||
base["auto_generate_title"] = bool(data.get("auto_generate_title", base["auto_generate_title"]))
|
base["auto_generate_title"] = bool(data.get("auto_generate_title", base["auto_generate_title"]))
|
||||||
|
base["title_model"] = str(data.get("title_model", base.get("title_model", "")) or "").strip()
|
||||||
base["recent_conversations_prompt_enabled"] = bool(
|
base["recent_conversations_prompt_enabled"] = bool(
|
||||||
data.get("recent_conversations_prompt_enabled", base.get("recent_conversations_prompt_enabled", False))
|
data.get("recent_conversations_prompt_enabled", base.get("recent_conversations_prompt_enabled", False))
|
||||||
)
|
)
|
||||||
|
|||||||
@ -18,7 +18,7 @@ from config import DATA_DIR
|
|||||||
from config.sub_agent import SUB_AGENT_MODELS_CONFIG_FILE
|
from config.sub_agent import SUB_AGENT_MODELS_CONFIG_FILE
|
||||||
from modules.personalization_manager import REVIEW_AGENT_KEYS
|
from modules.personalization_manager import REVIEW_AGENT_KEYS
|
||||||
|
|
||||||
__all__ = ["resolve_review_agent_config", "REVIEW_AGENT_KEYS"]
|
__all__ = ["resolve_review_agent_config", "resolve_sub_agent_model_profile", "REVIEW_AGENT_KEYS"]
|
||||||
|
|
||||||
|
|
||||||
def _load_model_entry(model_name: str) -> Dict[str, Any]:
|
def _load_model_entry(model_name: str) -> Dict[str, Any]:
|
||||||
@ -52,6 +52,15 @@ def _load_model_entry(model_name: str) -> Dict[str, Any]:
|
|||||||
return model_map.get(chosen)
|
return model_map.get(chosen)
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_sub_agent_model_profile(model_name: str) -> Dict[str, Any]:
|
||||||
|
"""按名称从子智能体模型库解析模型 profile(APIClient.apply_profile 格式)。
|
||||||
|
|
||||||
|
名称留空或不存在时回落模型库 default_model(模型库也不可用时返回 None,
|
||||||
|
由调用方决定兜底行为)。
|
||||||
|
"""
|
||||||
|
return _load_model_entry(str(model_name).strip() if model_name and str(model_name).strip() else "")
|
||||||
|
|
||||||
|
|
||||||
def resolve_review_agent_config(agent_key: str) -> Dict[str, Any]:
|
def resolve_review_agent_config(agent_key: str) -> Dict[str, Any]:
|
||||||
"""解析指定审核智能体的完整运行配置。
|
"""解析指定审核智能体的完整运行配置。
|
||||||
|
|
||||||
|
|||||||
@ -112,7 +112,7 @@ from modules.i18n import tr
|
|||||||
conversation_bp = Blueprint('conversation', __name__)
|
conversation_bp = Blueprint('conversation', __name__)
|
||||||
|
|
||||||
|
|
||||||
def generate_conversation_title_background(web_terminal: WebTerminal, conversation_id: str, user_message: str, username: str):
|
def generate_conversation_title_background(web_terminal: WebTerminal, conversation_id: str, user_message: str, username: str, title_model: str = ""):
|
||||||
"""在后台生成对话标题并更新索引、推送给前端。"""
|
"""在后台生成对话标题并更新索引、推送给前端。"""
|
||||||
return _generate_conversation_title_background(
|
return _generate_conversation_title_background(
|
||||||
web_terminal=web_terminal,
|
web_terminal=web_terminal,
|
||||||
@ -122,6 +122,7 @@ def generate_conversation_title_background(web_terminal: WebTerminal, conversati
|
|||||||
socketio_instance=socketio,
|
socketio_instance=socketio,
|
||||||
title_prompt_path=TITLE_PROMPT_PATH,
|
title_prompt_path=TITLE_PROMPT_PATH,
|
||||||
debug_logger=debug_log,
|
debug_logger=debug_log,
|
||||||
|
title_model=title_model,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -11,7 +10,6 @@ from typing import Any, Dict, List, Optional
|
|||||||
from core.web_terminal import WebTerminal
|
from core.web_terminal import WebTerminal
|
||||||
from config import LOGS_DIR
|
from config import LOGS_DIR
|
||||||
from utils.api_client import APIClient
|
from utils.api_client import APIClient
|
||||||
from config.model_profiles import get_default_model_key, get_model_profile
|
|
||||||
|
|
||||||
TITLE_DEBUG_DIR = Path(LOGS_DIR).expanduser().resolve() / "title_debug"
|
TITLE_DEBUG_DIR = Path(LOGS_DIR).expanduser().resolve() / "title_debug"
|
||||||
TITLE_DEBUG_FILE = TITLE_DEBUG_DIR / "title_generation.log"
|
TITLE_DEBUG_FILE = TITLE_DEBUG_DIR / "title_generation.log"
|
||||||
@ -32,44 +30,33 @@ def _title_debug_log(message: str, **extra: Any) -> None:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _env_optional(name: str) -> Optional[str]:
|
|
||||||
"""从环境变量获取可选配置(已由 config/__init__.py 统一注入)。"""
|
|
||||||
value = os.environ.get(name)
|
|
||||||
if value is None:
|
|
||||||
return None
|
|
||||||
value = value.strip()
|
|
||||||
return value or None
|
|
||||||
|
|
||||||
|
|
||||||
async def _generate_title_async(
|
async def _generate_title_async(
|
||||||
user_message: str,
|
user_message: str,
|
||||||
title_prompt_path,
|
title_prompt_path,
|
||||||
debug_logger,
|
debug_logger,
|
||||||
|
model_profile: Optional[Dict[str, Any]] = None,
|
||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
"""使用快速模型生成对话标题。"""
|
"""使用子智能体模型生成对话标题。
|
||||||
|
|
||||||
|
model_profile 来自个人空间「标题生成模型」配置解析出的子智能体模型库条目
|
||||||
|
(未配置时为模型库 default_model)。个人空间是唯一配置来源:不使用主智能体
|
||||||
|
默认模型,也不支持 AGENT_TITLE_* 环境变量覆盖;profile 缺失或应用失败时
|
||||||
|
直接放弃生成(带日志),不做其他回退。
|
||||||
|
"""
|
||||||
if not user_message:
|
if not user_message:
|
||||||
_title_debug_log("skip_empty_user_message")
|
_title_debug_log("skip_empty_user_message")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
client = APIClient(thinking_mode=False, web_mode=True)
|
client = APIClient(thinking_mode=False, web_mode=True)
|
||||||
|
if not model_profile:
|
||||||
|
_title_debug_log("title_model_profile_missing")
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
default_model = get_default_model_key()
|
client.apply_profile(model_profile)
|
||||||
client.model_key = default_model
|
_title_debug_log("title_model_profile_applied", model_name=model_profile.get("name"))
|
||||||
client.apply_profile(get_model_profile(default_model))
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
_title_debug_log("default_title_model_profile_failed", error=str(exc))
|
_title_debug_log("title_model_profile_failed", error=str(exc), model_name=model_profile.get("name"))
|
||||||
title_base = _env_optional("AGENT_TITLE_API_BASE_URL")
|
return None
|
||||||
title_key = _env_optional("AGENT_TITLE_API_KEY")
|
|
||||||
title_model = _env_optional("AGENT_TITLE_MODEL_ID")
|
|
||||||
if title_base:
|
|
||||||
client.fast_api_config["base_url"] = title_base
|
|
||||||
client.api_base_url = title_base
|
|
||||||
if title_key:
|
|
||||||
client.fast_api_config["api_key"] = title_key
|
|
||||||
client.api_key = title_key
|
|
||||||
if title_model:
|
|
||||||
client.fast_api_config["model_id"] = title_model
|
|
||||||
client.model_id = title_model
|
|
||||||
_title_debug_log("start_generate_title", user_message_preview=str(user_message)[:200], user_message_len=len(str(user_message)))
|
_title_debug_log("start_generate_title", user_message_preview=str(user_message)[:200], user_message_len=len(str(user_message)))
|
||||||
_title_debug_log(
|
_title_debug_log(
|
||||||
"title_api_config",
|
"title_api_config",
|
||||||
@ -118,13 +105,27 @@ def generate_conversation_title_background(
|
|||||||
socketio_instance,
|
socketio_instance,
|
||||||
title_prompt_path,
|
title_prompt_path,
|
||||||
debug_logger,
|
debug_logger,
|
||||||
|
title_model: str = "",
|
||||||
):
|
):
|
||||||
"""在后台生成对话标题并更新索引、推送给前端。"""
|
"""在后台生成对话标题并更新索引、推送给前端。
|
||||||
|
|
||||||
|
title_model 为个人空间配置的子智能体模型条目名(空 = 子智能体模型库
|
||||||
|
default_model)。个人空间是唯一配置来源。
|
||||||
|
"""
|
||||||
if not conversation_id or not user_message:
|
if not conversation_id or not user_message:
|
||||||
return
|
return
|
||||||
|
|
||||||
async def _runner():
|
async def _runner():
|
||||||
title = await _generate_title_async(user_message, title_prompt_path, debug_logger)
|
try:
|
||||||
|
from modules.review_agent_config import resolve_sub_agent_model_profile
|
||||||
|
# 未配置(空)时回落子智能体模型库 default_model,个人空间为唯一配置来源
|
||||||
|
model_profile = resolve_sub_agent_model_profile(title_model)
|
||||||
|
except Exception:
|
||||||
|
model_profile = None
|
||||||
|
if model_profile is None:
|
||||||
|
_title_debug_log("title_model_profile_unavailable", title_model=title_model, conversation_id=conversation_id)
|
||||||
|
return
|
||||||
|
title = await _generate_title_async(user_message, title_prompt_path, debug_logger, model_profile=model_profile)
|
||||||
if not title:
|
if not title:
|
||||||
_title_debug_log("title_not_generated", conversation_id=conversation_id, username=username)
|
_title_debug_log("title_not_generated", conversation_id=conversation_id, username=username)
|
||||||
return
|
return
|
||||||
|
|||||||
@ -104,7 +104,7 @@ from .chat_flow_runner_helpers import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def generate_conversation_title_background(web_terminal: WebTerminal, conversation_id: str, user_message: str, username: str):
|
def generate_conversation_title_background(web_terminal: WebTerminal, conversation_id: str, user_message: str, username: str, title_model: str = ""):
|
||||||
return _generate_conversation_title_background(
|
return _generate_conversation_title_background(
|
||||||
web_terminal=web_terminal,
|
web_terminal=web_terminal,
|
||||||
conversation_id=conversation_id,
|
conversation_id=conversation_id,
|
||||||
@ -113,6 +113,7 @@ def generate_conversation_title_background(web_terminal: WebTerminal, conversati
|
|||||||
socketio_instance=socketio,
|
socketio_instance=socketio,
|
||||||
title_prompt_path=TITLE_PROMPT_PATH,
|
title_prompt_path=TITLE_PROMPT_PATH,
|
||||||
debug_logger=debug_log,
|
debug_logger=debug_log,
|
||||||
|
title_model=title_model,
|
||||||
)
|
)
|
||||||
|
|
||||||
def detect_malformed_tool_call(text):
|
def detect_malformed_tool_call(text):
|
||||||
|
|||||||
@ -1855,7 +1855,8 @@ async def handle_task_with_sender(
|
|||||||
web_terminal,
|
web_terminal,
|
||||||
conv_id,
|
conv_id,
|
||||||
message,
|
message,
|
||||||
username
|
username,
|
||||||
|
personal_config.get("title_model", "")
|
||||||
)
|
)
|
||||||
|
|
||||||
# 自动深层压缩(用户输入后触发)
|
# 自动深层压缩(用户输入后触发)
|
||||||
|
|||||||
@ -874,14 +874,16 @@ watch(
|
|||||||
if (isVisible && tab === 'review-agents') {
|
if (isVisible && tab === 'review-agents') {
|
||||||
loadSubAgentModels();
|
loadSubAgentModels();
|
||||||
}
|
}
|
||||||
if (
|
if (isVisible && tab === 'general') {
|
||||||
isVisible &&
|
// 「标题生成模型」菜单复用子智能体模型库,需在常规页签也加载模型列表
|
||||||
tab === 'general' &&
|
loadSubAgentModels();
|
||||||
isAppShell.value &&
|
if (
|
||||||
!appUpdateInfo.value &&
|
isAppShell.value &&
|
||||||
!appUpdateChecking.value
|
!appUpdateInfo.value &&
|
||||||
) {
|
!appUpdateChecking.value
|
||||||
checkAppUpdate();
|
) {
|
||||||
|
checkAppUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -32,6 +32,10 @@ const sandboxShowWizard = computed(() => {
|
|||||||
*/
|
*/
|
||||||
const ctx = inject<Record<string, any>>('personalizationDrawer')!;
|
const ctx = inject<Record<string, any>>('personalizationDrawer')!;
|
||||||
const {
|
const {
|
||||||
|
activeDropdown,
|
||||||
|
activeTheme,
|
||||||
|
closeDropdown,
|
||||||
|
floatingMenuStyle,
|
||||||
personalization,
|
personalization,
|
||||||
form,
|
form,
|
||||||
startTutorial,
|
startTutorial,
|
||||||
@ -42,7 +46,9 @@ const {
|
|||||||
appUpdateStateText,
|
appUpdateStateText,
|
||||||
appUpdateChecking,
|
appUpdateChecking,
|
||||||
checkAppUpdate,
|
checkAppUpdate,
|
||||||
downloadLatestApp
|
downloadLatestApp,
|
||||||
|
subAgentModels,
|
||||||
|
toggleDropdown
|
||||||
} = ctx;
|
} = ctx;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -65,6 +71,52 @@ const {
|
|||||||
/>
|
/>
|
||||||
<FancyCheck :checked="form.auto_generate_title" />
|
<FancyCheck :checked="form.auto_generate_title" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<!-- 标题生成模型:复用子智能体模型库配置(个人空间为唯一配置来源) -->
|
||||||
|
<div class="settings-select-row">
|
||||||
|
<span class="settings-row-copy">
|
||||||
|
<span class="settings-row-title">{{ $t('personalization.titleModelTitle') }}</span>
|
||||||
|
<span class="settings-row-desc">{{ $t('personalization.titleModelDesc') }}</span>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="settings-select-wrap"
|
||||||
|
:class="{ open: activeDropdown === 'title-model' }"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="settings-select-button"
|
||||||
|
@click="toggleDropdown('title-model')"
|
||||||
|
>
|
||||||
|
{{ form.title_model || $t('personalization.defaultModelOption') }}
|
||||||
|
<span class="select-chevron" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
:class="['settings-floating-menu', { dark: activeTheme === 'dark' }]"
|
||||||
|
:style="activeDropdown === 'title-model' ? floatingMenuStyle : undefined"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="settings-menu-option"
|
||||||
|
:class="{ selected: !form.title_model }"
|
||||||
|
@click="personalization.updateField({ key: 'title_model', value: '' }); closeDropdown()"
|
||||||
|
>
|
||||||
|
<strong>{{ $t('personalization.defaultModelOption') }}</strong><span>{{ $t('personalization.titleDefaultModelDesc') }}</span><svg viewBox="0 0 24 24"><path d="M5 12.5 9.5 17 19 7" /></svg>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-for="m in subAgentModels"
|
||||||
|
:key="m.name"
|
||||||
|
type="button"
|
||||||
|
class="settings-menu-option"
|
||||||
|
:class="{ selected: form.title_model === m.name }"
|
||||||
|
@click="personalization.updateField({ key: 'title_model', value: m.name }); closeDropdown()"
|
||||||
|
>
|
||||||
|
<strong>{{ m.name }}</strong><span>{{ m.modes }} · {{ m.multimodal || $t('personalization.textOnly') }}</span><svg viewBox="0 0 24 24"><path d="M5 12.5 9.5 17 19 7" /></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="settings-action-row">
|
<div class="settings-action-row">
|
||||||
<span class="settings-row-copy">
|
<span class="settings-row-copy">
|
||||||
<span class="settings-row-title">{{ $t('personalization.tutorialTitle') }}</span>
|
<span class="settings-row-title">{{ $t('personalization.tutorialTitle') }}</span>
|
||||||
|
|||||||
@ -330,6 +330,9 @@ export default {
|
|||||||
reviewAgentWorkflowReviewDesc: 'Judges whether stage output meets the bar at workflow review nodes',
|
reviewAgentWorkflowReviewDesc: 'Judges whether stage output meets the bar at workflow review nodes',
|
||||||
reviewModelEmptyDesc: 'Leave empty to use the model library default',
|
reviewModelEmptyDesc: 'Leave empty to use the model library default',
|
||||||
reviewDefaultModelDesc: 'Uses the model library default_model',
|
reviewDefaultModelDesc: 'Uses the model library default_model',
|
||||||
|
titleModelTitle: 'Title generation model',
|
||||||
|
titleModelDesc: 'Choose the AI model used to generate conversation titles, shared with sub-agents',
|
||||||
|
titleDefaultModelDesc: 'Uses the sub-agent model library default',
|
||||||
reviewThinkingDesc: 'Falls back to fast mode automatically when the model does not support thinking',
|
reviewThinkingDesc: 'Falls back to fast mode automatically when the model does not support thinking',
|
||||||
timeoutTitle: 'Review request timeout',
|
timeoutTitle: 'Review request timeout',
|
||||||
timeoutDesc: 'Single model request timeout (5-3600 seconds)',
|
timeoutDesc: 'Single model request timeout (5-3600 seconds)',
|
||||||
|
|||||||
@ -331,6 +331,9 @@ export default {
|
|||||||
reviewAgentWorkflowReviewDesc: '工作流审核节点判断阶段产出是否达标',
|
reviewAgentWorkflowReviewDesc: '工作流审核节点判断阶段产出是否达标',
|
||||||
reviewModelEmptyDesc: '留空则使用模型库默认模型',
|
reviewModelEmptyDesc: '留空则使用模型库默认模型',
|
||||||
reviewDefaultModelDesc: '使用模型库的 default_model',
|
reviewDefaultModelDesc: '使用模型库的 default_model',
|
||||||
|
titleModelTitle: '标题生成模型',
|
||||||
|
titleModelDesc: '选择用于生成对话标题的 AI 模型,与子智能体共用模型库',
|
||||||
|
titleDefaultModelDesc: '使用子智能体模型库的默认模型',
|
||||||
reviewThinkingDesc: '模型不支持思考时自动回落快速模式',
|
reviewThinkingDesc: '模型不支持思考时自动回落快速模式',
|
||||||
timeoutTitle: '审核请求超时',
|
timeoutTitle: '审核请求超时',
|
||||||
timeoutDesc: '单次模型请求超时(5-3600 秒)',
|
timeoutDesc: '单次模型请求超时(5-3600 秒)',
|
||||||
|
|||||||
@ -94,6 +94,8 @@ interface PersonalForm {
|
|||||||
communication_style: CommunicationStyle;
|
communication_style: CommunicationStyle;
|
||||||
conversation_continuity: ConversationContinuity;
|
conversation_continuity: ConversationContinuity;
|
||||||
auto_generate_title: boolean;
|
auto_generate_title: boolean;
|
||||||
|
/** 标题生成模型(子智能体模型库条目名);留空 = 模型库 default_model */
|
||||||
|
title_model: string;
|
||||||
recent_conversations_prompt_enabled: boolean;
|
recent_conversations_prompt_enabled: boolean;
|
||||||
recent_conversations_prompt_limit: number | string;
|
recent_conversations_prompt_limit: number | string;
|
||||||
project_memory_inject_limit: number | string | null;
|
project_memory_inject_limit: number | string | null;
|
||||||
@ -300,6 +302,7 @@ const defaultForm = (): PersonalForm => ({
|
|||||||
communication_style: 'default',
|
communication_style: 'default',
|
||||||
conversation_continuity: 'medium',
|
conversation_continuity: 'medium',
|
||||||
auto_generate_title: true,
|
auto_generate_title: true,
|
||||||
|
title_model: '',
|
||||||
recent_conversations_prompt_enabled: false,
|
recent_conversations_prompt_enabled: false,
|
||||||
recent_conversations_prompt_limit: DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT,
|
recent_conversations_prompt_limit: DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT,
|
||||||
project_memory_inject_limit: DEFAULT_PROJECT_MEMORY_INJECT_LIMIT,
|
project_memory_inject_limit: DEFAULT_PROJECT_MEMORY_INJECT_LIMIT,
|
||||||
@ -515,6 +518,7 @@ export const usePersonalizationStore = defineStore('personalization', {
|
|||||||
? data.conversation_continuity
|
? data.conversation_continuity
|
||||||
: 'medium',
|
: 'medium',
|
||||||
auto_generate_title: data.auto_generate_title !== false,
|
auto_generate_title: data.auto_generate_title !== false,
|
||||||
|
title_model: typeof data.title_model === 'string' ? data.title_model : '',
|
||||||
recent_conversations_prompt_enabled: !!data.recent_conversations_prompt_enabled,
|
recent_conversations_prompt_enabled: !!data.recent_conversations_prompt_enabled,
|
||||||
recent_conversations_prompt_limit: this.normalizeRecentConversationsPromptLimit(
|
recent_conversations_prompt_limit: this.normalizeRecentConversationsPromptLimit(
|
||||||
data.recent_conversations_prompt_limit
|
data.recent_conversations_prompt_limit
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user