feat: add deep thinking mode
This commit is contained in:
parent
02ab023ad7
commit
2f4ea590a8
@ -53,6 +53,7 @@ from modules.easter_egg_manager import EasterEggManager
|
||||
from modules.personalization_manager import (
|
||||
load_personalization_config,
|
||||
build_personalization_prompt,
|
||||
THINKING_MODE_OPTIONS,
|
||||
)
|
||||
try:
|
||||
from config.limits import THINKING_FAST_INTERVAL
|
||||
@ -86,6 +87,11 @@ class MainTerminal:
|
||||
|
||||
# 初始化组件
|
||||
self.api_client = DeepSeekClient(thinking_mode=thinking_mode)
|
||||
self.thinking_mode_option = "smart" if thinking_mode else "fast"
|
||||
self.default_thinking_mode_option = self.thinking_mode_option
|
||||
self.deep_thinking_mode = self.thinking_mode_option == "deep"
|
||||
self.api_client.deep_thinking_mode = self.deep_thinking_mode
|
||||
self.set_thinking_mode_option(self.thinking_mode_option)
|
||||
self.context_manager = ContextManager(project_path, data_dir=str(self.data_dir))
|
||||
self.context_manager.main_terminal = self
|
||||
self.container_mount_path = TERMINAL_SANDBOX_MOUNT_PATH or "/workspace"
|
||||
@ -205,6 +211,17 @@ class MainTerminal:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def set_thinking_mode_option(self, option: str):
|
||||
previous_option = getattr(self, "thinking_mode_option", "fast")
|
||||
normalized = option if option in THINKING_MODE_OPTIONS else "fast"
|
||||
self.thinking_mode_option = normalized
|
||||
self.thinking_mode = normalized in ("smart", "deep")
|
||||
self.deep_thinking_mode = normalized == "deep"
|
||||
self.api_client.thinking_mode = self.thinking_mode
|
||||
self.api_client.deep_thinking_mode = self.deep_thinking_mode
|
||||
if previous_option != normalized:
|
||||
self.api_client.start_new_task()
|
||||
|
||||
def update_container_session(self, session: Optional["ContainerHandle"]):
|
||||
self._apply_container_session(session)
|
||||
if getattr(self, "terminal_manager", None):
|
||||
@ -352,6 +369,10 @@ class MainTerminal:
|
||||
for key, category in TOOL_CATEGORIES.items():
|
||||
self.tool_category_states[key] = False if key in disabled_categories else category.default_enabled
|
||||
self._refresh_disabled_tools()
|
||||
default_mode = effective_config.get("default_mode")
|
||||
if isinstance(default_mode, str) and default_mode in THINKING_MODE_OPTIONS:
|
||||
self.default_thinking_mode_option = default_mode
|
||||
self.set_thinking_mode_option(default_mode)
|
||||
|
||||
|
||||
def _handle_read_tool(self, arguments: Dict) -> Dict:
|
||||
@ -700,7 +721,7 @@ class MainTerminal:
|
||||
assistant_content_parts = []
|
||||
|
||||
# 添加思考内容
|
||||
if final_thinking:
|
||||
if final_thinking and not self.deep_thinking_mode:
|
||||
assistant_content_parts.append(f"<think>\n{final_thinking}\n</think>")
|
||||
|
||||
# 添加回复内容
|
||||
@ -714,7 +735,8 @@ class MainTerminal:
|
||||
self.context_manager.add_conversation(
|
||||
"assistant",
|
||||
assistant_content,
|
||||
collected_tool_calls if collected_tool_calls else None
|
||||
collected_tool_calls if collected_tool_calls else None,
|
||||
reasoning_content=final_thinking if self.deep_thinking_mode else None
|
||||
)
|
||||
|
||||
# 3. 保存独立的tool消息
|
||||
@ -2360,6 +2382,8 @@ class MainTerminal:
|
||||
tool_calls = conv.get("tool_calls") or []
|
||||
if tool_calls and self._tool_calls_followed_by_tools(conversation, idx, tool_calls):
|
||||
message["tool_calls"] = tool_calls
|
||||
if conv.get("reasoning_content") and self.thinking_mode_option == "deep":
|
||||
message["reasoning_content"] = conv["reasoning_content"]
|
||||
messages.append(message)
|
||||
|
||||
elif conv["role"] == "tool":
|
||||
|
||||
@ -21,6 +21,7 @@ MAX_CONSIDERATION_ITEMS = 10
|
||||
TONE_PRESETS = ["健谈", "幽默", "直言不讳", "鼓励性", "诗意", "企业商务", "打破常规", "同理心"]
|
||||
THINKING_INTERVAL_MIN = 1
|
||||
THINKING_INTERVAL_MAX = 50
|
||||
THINKING_MODE_OPTIONS = ("fast", "smart", "deep")
|
||||
|
||||
DEFAULT_PERSONALIZATION_CONFIG: Dict[str, Any] = {
|
||||
"enabled": False,
|
||||
@ -31,6 +32,7 @@ DEFAULT_PERSONALIZATION_CONFIG: Dict[str, Any] = {
|
||||
"considerations": [],
|
||||
"thinking_interval": None,
|
||||
"disabled_tool_categories": [],
|
||||
"default_mode": "fast",
|
||||
}
|
||||
|
||||
__all__ = [
|
||||
@ -38,6 +40,9 @@ __all__ = [
|
||||
"DEFAULT_PERSONALIZATION_CONFIG",
|
||||
"TONE_PRESETS",
|
||||
"MAX_CONSIDERATION_ITEMS",
|
||||
"THINKING_INTERVAL_MIN",
|
||||
"THINKING_INTERVAL_MAX",
|
||||
"THINKING_MODE_OPTIONS",
|
||||
"load_personalization_config",
|
||||
"save_personalization_config",
|
||||
"ensure_personalization_config",
|
||||
@ -123,6 +128,10 @@ def sanitize_personalization_payload(
|
||||
base["disabled_tool_categories"] = _sanitize_tool_categories(data.get("disabled_tool_categories"), allowed_tool_categories)
|
||||
else:
|
||||
base["disabled_tool_categories"] = _sanitize_tool_categories(base.get("disabled_tool_categories"), allowed_tool_categories)
|
||||
if "default_mode" in data:
|
||||
base["default_mode"] = _sanitize_default_mode(data.get("default_mode"))
|
||||
else:
|
||||
base["default_mode"] = _sanitize_default_mode(base.get("default_mode"))
|
||||
return base
|
||||
|
||||
|
||||
@ -222,3 +231,11 @@ def _sanitize_tool_categories(value: Any, allowed: set) -> list:
|
||||
if candidate not in result:
|
||||
result.append(candidate)
|
||||
return result
|
||||
|
||||
|
||||
def _sanitize_default_mode(value: Any) -> str:
|
||||
if isinstance(value, str):
|
||||
normalized = value.strip()
|
||||
if normalized in THINKING_MODE_OPTIONS:
|
||||
return normalized
|
||||
return DEFAULT_PERSONALIZATION_CONFIG["default_mode"]
|
||||
|
||||
@ -63,6 +63,7 @@
|
||||
:icon-style="iconStyle"
|
||||
:agent-version="agentVersion"
|
||||
:thinking-mode="thinkingMode"
|
||||
:thinking-mode-option="thinkingModeOption"
|
||||
:is-connected="isConnected"
|
||||
:panel-menu-open="panelMenuOpen"
|
||||
:panel-mode="panelMode"
|
||||
@ -147,12 +148,14 @@
|
||||
:is-connected="isConnected"
|
||||
:streaming-message="streamingMessage"
|
||||
:uploading="uploading"
|
||||
:thinking-mode="thinkingMode"
|
||||
:quick-menu-open="quickMenuOpen"
|
||||
:tool-menu-open="toolMenuOpen"
|
||||
:tool-settings="toolSettings"
|
||||
:tool-settings-loading="toolSettingsLoading"
|
||||
:settings-open="settingsOpen"
|
||||
:mode-menu-open="modeMenuOpen"
|
||||
:thinking-mode-option="thinkingModeOption"
|
||||
:mode-options="modeOptions"
|
||||
:compressing="compressing"
|
||||
:current-conversation-id="currentConversationId"
|
||||
:icon-style="iconStyle"
|
||||
@ -166,7 +169,8 @@
|
||||
@send-or-stop="handleSendOrStop"
|
||||
@quick-upload="handleQuickUpload"
|
||||
@toggle-tool-menu="toggleToolMenu"
|
||||
@quick-mode-toggle="handleQuickModeToggle"
|
||||
@toggle-mode-menu="toggleModeMenu"
|
||||
@select-mode="selectThinkingMode"
|
||||
@toggle-settings="toggleSettings"
|
||||
@update-tool-category="updateToolCategory"
|
||||
@realtime-terminal="handleRealtimeTerminalClick"
|
||||
@ -280,6 +284,7 @@
|
||||
:icon-style="iconStyle"
|
||||
:agent-version="agentVersion"
|
||||
:thinking-mode="thinkingMode"
|
||||
:thinking-mode-option="thinkingModeOption"
|
||||
:is-connected="isConnected"
|
||||
:panel-menu-open="panelMenuOpen"
|
||||
:panel-mode="panelMode"
|
||||
|
||||
@ -97,6 +97,11 @@ if (window.visualViewport) {
|
||||
}
|
||||
|
||||
const ENABLE_APP_DEBUG_LOGS = false;
|
||||
const MODE_OPTIONS = [
|
||||
{ value: 'fast', label: '快速模式', description: '即时响应', icon: 'zap' },
|
||||
{ value: 'smart', label: '思考模式', description: '智能调度', icon: 'brain' },
|
||||
{ value: 'deep', label: '深度思考模式', description: '全程推理', icon: 'brain' }
|
||||
];
|
||||
function debugLog(...args) {
|
||||
if (!ENABLE_APP_DEBUG_LOGS) {
|
||||
return;
|
||||
@ -135,7 +140,8 @@ const appOptions = {
|
||||
|
||||
// 工具控制菜单
|
||||
icons: ICONS,
|
||||
toolCategoryIcons: TOOL_CATEGORY_ICON_MAP
|
||||
toolCategoryIcons: TOOL_CATEGORY_ICON_MAP,
|
||||
modeOptions: MODE_OPTIONS
|
||||
}
|
||||
},
|
||||
|
||||
@ -199,7 +205,8 @@ const appOptions = {
|
||||
'stopRequested',
|
||||
'projectPath',
|
||||
'agentVersion',
|
||||
'thinkingMode'
|
||||
'thinkingMode',
|
||||
'thinkingModeOption'
|
||||
]),
|
||||
...mapState(useFileStore, ['contextMenu', 'fileTree', 'expandedFolders', 'todoList']),
|
||||
...mapWritableState(useUiStore, [
|
||||
@ -250,7 +257,8 @@ const appOptions = {
|
||||
'inputIsFocused',
|
||||
'quickMenuOpen',
|
||||
'toolMenuOpen',
|
||||
'settingsOpen'
|
||||
'settingsOpen',
|
||||
'modeMenuOpen'
|
||||
]),
|
||||
...mapWritableState(useToolStore, [
|
||||
'preparingTools',
|
||||
@ -483,6 +491,8 @@ const appOptions = {
|
||||
inputSetToolMenuOpen: 'setToolMenuOpen',
|
||||
inputToggleSettingsMenu: 'toggleSettingsMenu',
|
||||
inputSetSettingsOpen: 'setSettingsOpen',
|
||||
inputToggleModeMenu: 'toggleModeMenu',
|
||||
inputSetModeMenuOpen: 'setModeMenuOpen',
|
||||
inputSetMessage: 'setInputMessage',
|
||||
inputClearMessage: 'clearInputMessage',
|
||||
inputSetLineCount: 'setInputLineCount',
|
||||
@ -1042,7 +1052,7 @@ const appOptions = {
|
||||
const statusData = await statusResponse.json();
|
||||
this.projectPath = statusData.project_path || '';
|
||||
this.agentVersion = statusData.version || this.agentVersion;
|
||||
this.thinkingMode = !!statusData.thinking_mode;
|
||||
this.applyThinkingModeSnapshot(statusData);
|
||||
this.applyStatusSnapshot(statusData);
|
||||
await this.fetchUsageQuota();
|
||||
|
||||
@ -1817,20 +1827,28 @@ const appOptions = {
|
||||
return this.subAgentFetch();
|
||||
},
|
||||
|
||||
async toggleThinkingMode() {
|
||||
const nextMode = !this.thinkingMode;
|
||||
async setThinkingModeOption(option) {
|
||||
if (!this.isConnected || this.streamingMessage) {
|
||||
return;
|
||||
}
|
||||
if (!this.modeOptions.some((item) => item.value === option)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/api/thinking-mode', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ thinking_mode: nextMode })
|
||||
body: JSON.stringify({ mode: option })
|
||||
});
|
||||
const data = await response.json();
|
||||
if (response.ok && data.success) {
|
||||
const actual = typeof data.data === 'boolean' ? data.data : nextMode;
|
||||
this.thinkingMode = actual;
|
||||
const payload = data.data || {};
|
||||
this.applyThinkingModeSnapshot({
|
||||
thinking_mode_option: payload.mode || option,
|
||||
thinking_mode: typeof payload.thinking_mode === 'boolean' ? payload.thinking_mode : undefined
|
||||
});
|
||||
return;
|
||||
}
|
||||
throw new Error(data.message || data.error || '切换失败');
|
||||
@ -1838,12 +1856,40 @@ const appOptions = {
|
||||
console.error('切换思考模式失败:', error);
|
||||
this.uiPushToast({
|
||||
title: '切换思考模式失败',
|
||||
message: error.message || '请稍后重试',
|
||||
message: error?.message || '请稍后重试',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
applyThinkingModeSnapshot(payload) {
|
||||
const normalized = this.normalizeModeOption(
|
||||
payload && payload.thinking_mode_option,
|
||||
Object.prototype.hasOwnProperty.call(payload || {}, 'thinking_mode') ? payload!.thinking_mode : undefined,
|
||||
Object.prototype.hasOwnProperty.call(payload || {}, 'deep_thinking_mode') ? payload!.deep_thinking_mode : undefined
|
||||
);
|
||||
this.thinkingModeOption = normalized;
|
||||
this.thinkingMode = normalized !== 'fast';
|
||||
},
|
||||
|
||||
normalizeModeOption(option, fallback, deepFlag) {
|
||||
if (typeof deepFlag === 'boolean') {
|
||||
if (deepFlag) {
|
||||
return 'deep';
|
||||
}
|
||||
if (!deepFlag && option === 'deep') {
|
||||
return fallback ? 'smart' : 'fast';
|
||||
}
|
||||
}
|
||||
if (typeof option === 'string' && this.modeOptions.some((item) => item.value === option)) {
|
||||
return option;
|
||||
}
|
||||
if (typeof fallback === 'boolean') {
|
||||
return fallback ? 'smart' : 'fast';
|
||||
}
|
||||
return 'fast';
|
||||
},
|
||||
|
||||
triggerFileUpload() {
|
||||
if (this.uploading) {
|
||||
return;
|
||||
@ -1994,6 +2040,7 @@ const appOptions = {
|
||||
const nextState = this.inputToggleToolMenu();
|
||||
if (nextState) {
|
||||
this.inputSetSettingsOpen(false);
|
||||
this.inputSetModeMenuOpen(false);
|
||||
if (!this.quickMenuOpen) {
|
||||
this.inputOpenQuickMenu();
|
||||
}
|
||||
@ -2003,6 +2050,28 @@ const appOptions = {
|
||||
}
|
||||
},
|
||||
|
||||
toggleModeMenu() {
|
||||
if (!this.isConnected) {
|
||||
return;
|
||||
}
|
||||
const nextState = this.inputToggleModeMenu();
|
||||
if (nextState) {
|
||||
this.inputSetToolMenuOpen(false);
|
||||
this.inputSetSettingsOpen(false);
|
||||
if (!this.quickMenuOpen) {
|
||||
this.inputOpenQuickMenu();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
selectThinkingMode(option) {
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
this.setThinkingModeOption(option);
|
||||
this.inputSetModeMenuOpen(false);
|
||||
},
|
||||
|
||||
toggleQuickMenu() {
|
||||
if (!this.isConnected) {
|
||||
return;
|
||||
@ -2025,7 +2094,20 @@ const appOptions = {
|
||||
if (!this.isConnected || this.streamingMessage) {
|
||||
return;
|
||||
}
|
||||
this.toggleThinkingMode();
|
||||
const next = this.nextModeOption();
|
||||
this.setThinkingModeOption(next);
|
||||
},
|
||||
|
||||
nextModeOption() {
|
||||
const order = this.modeOptions.map((item) => item.value);
|
||||
if (!order.length) {
|
||||
return 'fast';
|
||||
}
|
||||
const currentIndex = order.indexOf(this.thinkingModeOption);
|
||||
if (currentIndex === -1) {
|
||||
return order[0];
|
||||
}
|
||||
return order[(currentIndex + 1) % order.length] || order[0];
|
||||
},
|
||||
|
||||
handleInputChange() {
|
||||
@ -2217,6 +2299,7 @@ const appOptions = {
|
||||
const nextState = this.inputToggleSettingsMenu();
|
||||
if (nextState) {
|
||||
this.inputSetToolMenuOpen(false);
|
||||
this.inputSetModeMenuOpen(false);
|
||||
if (!this.quickMenuOpen) {
|
||||
this.inputOpenQuickMenu();
|
||||
}
|
||||
|
||||
@ -41,18 +41,21 @@
|
||||
:is-connected="isConnected"
|
||||
:uploading="uploading"
|
||||
:streaming-message="streamingMessage"
|
||||
:thinking-mode="thinkingMode"
|
||||
:tool-menu-open="toolMenuOpen"
|
||||
:tool-settings="toolSettings"
|
||||
:tool-settings-loading="toolSettingsLoading"
|
||||
:settings-open="settingsOpen"
|
||||
:mode-menu-open="modeMenuOpen"
|
||||
:thinking-mode-option="thinkingModeOption"
|
||||
:mode-options="modeOptions"
|
||||
:compressing="compressing"
|
||||
:current-conversation-id="currentConversationId"
|
||||
:icon-style="iconStyle"
|
||||
:tool-category-icon="toolCategoryIcon"
|
||||
@quick-upload="triggerQuickUpload"
|
||||
@toggle-tool-menu="$emit('toggle-tool-menu')"
|
||||
@quick-mode-toggle="$emit('quick-mode-toggle')"
|
||||
@toggle-mode-menu="$emit('toggle-mode-menu')"
|
||||
@select-mode="value => $emit('select-mode', value)"
|
||||
@toggle-settings="$emit('toggle-settings')"
|
||||
@update-tool-category="(id, enabled) => $emit('update-tool-category', id, enabled)"
|
||||
@realtime-terminal="$emit('realtime-terminal')"
|
||||
@ -81,7 +84,8 @@ const emit = defineEmits([
|
||||
'send-or-stop',
|
||||
'quick-upload',
|
||||
'toggle-tool-menu',
|
||||
'quick-mode-toggle',
|
||||
'toggle-mode-menu',
|
||||
'select-mode',
|
||||
'toggle-settings',
|
||||
'update-tool-category',
|
||||
'realtime-terminal',
|
||||
@ -98,16 +102,18 @@ const props = defineProps<{
|
||||
isConnected: boolean;
|
||||
streamingMessage: boolean;
|
||||
uploading: boolean;
|
||||
thinkingMode: boolean;
|
||||
quickMenuOpen: boolean;
|
||||
toolMenuOpen: boolean;
|
||||
toolSettings: Array<{ id: string; label: string; enabled: boolean }>;
|
||||
toolSettingsLoading: boolean;
|
||||
settingsOpen: boolean;
|
||||
modeMenuOpen: boolean;
|
||||
compressing: boolean;
|
||||
currentConversationId: string | null;
|
||||
iconStyle: (key: string) => Record<string, string>;
|
||||
toolCategoryIcon: (categoryId: string) => string;
|
||||
thinkingModeOption: string;
|
||||
modeOptions: Array<{ value: string; label: string; description: string; icon: string }>;
|
||||
}>();
|
||||
|
||||
const inputStore = useInputStore();
|
||||
|
||||
@ -15,11 +15,14 @@
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="menu-entry"
|
||||
@click="$emit('quick-mode-toggle')"
|
||||
class="menu-entry has-submenu"
|
||||
@click.stop="$emit('toggle-mode-menu')"
|
||||
:disabled="streamingMessage || !isConnected"
|
||||
>
|
||||
{{ thinkingMode ? '快速模式' : '思考模式' }}
|
||||
<span class="submenu-label">
|
||||
<span>{{ modeLabel }}</span>
|
||||
</span>
|
||||
<span class="entry-arrow">›</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -93,11 +96,35 @@
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<transition name="submenu-slide">
|
||||
<div class="quick-submenu mode-submenu" v-if="modeMenuOpen">
|
||||
<div class="submenu-list">
|
||||
<button
|
||||
v-for="mode in resolvedModeOptions"
|
||||
:key="mode.value"
|
||||
type="button"
|
||||
class="menu-entry submenu-entry"
|
||||
:class="{ active: thinkingModeOption === mode.value }"
|
||||
@click.stop="$emit('select-mode', mode.value)"
|
||||
:disabled="streamingMessage || !isConnected"
|
||||
>
|
||||
<span class="submenu-label">
|
||||
<span class="icon icon-sm" :style="getIconStyle(mode.icon)" aria-hidden="true"></span>
|
||||
<span>{{ mode.label }}</span>
|
||||
</span>
|
||||
<span class="entry-arrow">{{ mode.description }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
defineOptions({ name: 'QuickMenu' });
|
||||
|
||||
const props = defineProps<{
|
||||
@ -105,22 +132,25 @@ const props = defineProps<{
|
||||
isConnected: boolean;
|
||||
uploading: boolean;
|
||||
streamingMessage: boolean;
|
||||
thinkingMode: boolean;
|
||||
thinkingModeOption: string;
|
||||
toolMenuOpen: boolean;
|
||||
toolSettings: Array<{ id: string; label: string; enabled: boolean }>;
|
||||
toolSettingsLoading: boolean;
|
||||
settingsOpen: boolean;
|
||||
modeMenuOpen: boolean;
|
||||
compressing: boolean;
|
||||
currentConversationId: string | null;
|
||||
iconStyle?: (key: string) => Record<string, string>;
|
||||
toolCategoryIcon: (categoryId: string) => string;
|
||||
modeOptions: Array<{ value: string; label: string; description: string; icon: string }>;
|
||||
}>();
|
||||
|
||||
defineEmits<{
|
||||
(event: 'quick-upload'): void;
|
||||
(event: 'toggle-tool-menu'): void;
|
||||
(event: 'quick-mode-toggle'): void;
|
||||
(event: 'toggle-settings'): void;
|
||||
(event: 'toggle-mode-menu'): void;
|
||||
(event: 'select-mode', option: string): void;
|
||||
(event: 'update-tool-category', id: string, enabled: boolean): void;
|
||||
(event: 'realtime-terminal'): void;
|
||||
(event: 'toggle-focus-panel'): void;
|
||||
@ -129,4 +159,23 @@ defineEmits<{
|
||||
}>();
|
||||
|
||||
const getIconStyle = (key: string) => (props.iconStyle ? props.iconStyle(key) : {});
|
||||
const DEFAULT_MODE_OPTIONS = [
|
||||
{ value: 'fast', label: '快速模式', description: '即时响应', icon: 'zap' },
|
||||
{ value: 'smart', label: '思考模式', description: '智能调度', icon: 'brain' },
|
||||
{ value: 'deep', label: '深度思考模式', description: '全程推理', icon: 'brain' }
|
||||
];
|
||||
const resolvedModeOptions = computed(() => {
|
||||
const source =
|
||||
Array.isArray(props.modeOptions) && props.modeOptions.length ? props.modeOptions : DEFAULT_MODE_OPTIONS;
|
||||
return source.map((item) => ({
|
||||
value: item.value,
|
||||
label: item.label || item.value,
|
||||
description: item.description || '',
|
||||
icon: item.icon || (item.value === 'fast' ? 'zap' : 'brain')
|
||||
}));
|
||||
});
|
||||
const modeLabel = computed(() => {
|
||||
const found = resolvedModeOptions.value.find((option) => option.value === props.thinkingModeOption);
|
||||
return found ? found.label : '快速模式';
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -14,15 +14,15 @@
|
||||
<button
|
||||
type="button"
|
||||
class="mode-indicator"
|
||||
:class="{ thinking: thinkingMode, fast: !thinkingMode }"
|
||||
:title="thinkingMode ? '思考模式(点击切换)' : '快速模式(点击切换)'"
|
||||
:class="modeIndicatorClass"
|
||||
:title="modeTitle"
|
||||
@click="$emit('toggle-thinking-mode')"
|
||||
>
|
||||
<transition name="mode-icon" mode="out-in">
|
||||
<span
|
||||
class="icon icon-sm"
|
||||
:style="iconStyle(thinkingMode ? 'brain' : 'zap')"
|
||||
:key="thinkingMode ? 'brain' : 'zap'"
|
||||
:style="iconStyle(modeIconKey)"
|
||||
:key="modeIconKey"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</transition>
|
||||
@ -142,6 +142,7 @@ const props = defineProps<{
|
||||
iconStyle: (key: string) => Record<string, string>;
|
||||
agentVersion: string | null;
|
||||
thinkingMode: boolean;
|
||||
thinkingModeOption: 'fast' | 'smart' | 'deep';
|
||||
isConnected: boolean;
|
||||
panelMenuOpen: boolean;
|
||||
panelMode: 'files' | 'todo' | 'subAgents';
|
||||
@ -155,6 +156,26 @@ defineEmits<{
|
||||
}>();
|
||||
|
||||
const panelMenuWrapper = ref<HTMLElement | null>(null);
|
||||
const MODE_LABELS: Record<string, string> = {
|
||||
fast: '快速模式(点击切换)',
|
||||
smart: '思考模式(点击切换)',
|
||||
deep: '深度思考模式(点击切换)'
|
||||
};
|
||||
const MODE_ICONS: Record<string, string> = {
|
||||
fast: 'zap',
|
||||
smart: 'brain',
|
||||
deep: 'brain'
|
||||
};
|
||||
const modeIndicatorClass = computed(() => {
|
||||
const option = props.thinkingModeOption || (props.thinkingMode ? 'smart' : 'fast');
|
||||
return {
|
||||
fast: option === 'fast',
|
||||
smart: option === 'smart',
|
||||
deep: option === 'deep'
|
||||
};
|
||||
});
|
||||
const modeTitle = computed(() => MODE_LABELS[props.thinkingModeOption] || MODE_LABELS[props.thinkingMode ? 'smart' : 'fast']);
|
||||
const modeIconKey = computed(() => MODE_ICONS[props.thinkingModeOption] || MODE_ICONS[props.thinkingMode ? 'smart' : 'fast']);
|
||||
const panelStyle = computed(() => {
|
||||
if (props.collapsed) {
|
||||
return {
|
||||
|
||||
@ -69,6 +69,25 @@
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="mode-preference">
|
||||
<div class="mode-preference-header">
|
||||
<span class="mode-preference-title">默认运行模式</span>
|
||||
<span class="mode-preference-hint">用于新任务的默认推理方式</span>
|
||||
</div>
|
||||
<div class="mode-option-grid">
|
||||
<button
|
||||
v-for="option in modeOptions"
|
||||
:key="option.value"
|
||||
type="button"
|
||||
class="mode-option-chip"
|
||||
:class="{ active: form.default_mode === option.value }"
|
||||
@click.prevent="personalization.setDefaultMode(option.value)"
|
||||
>
|
||||
<span class="mode-option-label">{{ option.label }}</span>
|
||||
<span class="mode-option-desc">{{ option.description }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="personalization-sections">
|
||||
<div class="personal-left-column">
|
||||
<div class="personal-section personal-info">
|
||||
@ -297,7 +316,8 @@ const {
|
||||
toggleUpdating,
|
||||
toolCategories,
|
||||
thinkingIntervalDefault,
|
||||
thinkingIntervalRange
|
||||
thinkingIntervalRange,
|
||||
modeOptions
|
||||
} = storeToRefs(personalization);
|
||||
|
||||
const activeTab = ref<'preferences' | 'behavior'>('preferences');
|
||||
|
||||
@ -529,7 +529,7 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
ctx.socket.on('system_ready', (data) => {
|
||||
ctx.projectPath = data.project_path || '';
|
||||
ctx.agentVersion = data.version || ctx.agentVersion;
|
||||
ctx.thinkingMode = !!data.thinking_mode;
|
||||
ctx.applyThinkingModeSnapshot(data);
|
||||
socketLog('系统就绪:', data);
|
||||
|
||||
// 系统就绪后立即加载对话列表
|
||||
@ -630,9 +630,7 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
if (status.conversation && status.conversation.current_id) {
|
||||
ctx.currentConversationId = status.conversation.current_id;
|
||||
}
|
||||
if (typeof status.thinking_mode !== 'undefined') {
|
||||
ctx.thinkingMode = !!status.thinking_mode;
|
||||
}
|
||||
ctx.applyThinkingModeSnapshot(status);
|
||||
});
|
||||
|
||||
// AI消息开始
|
||||
|
||||
@ -8,6 +8,7 @@ interface ConnectionState {
|
||||
projectPath: string;
|
||||
agentVersion: string;
|
||||
thinkingMode: boolean;
|
||||
thinkingModeOption: 'fast' | 'smart' | 'deep';
|
||||
}
|
||||
|
||||
export const useConnectionStore = defineStore('connection', {
|
||||
@ -17,7 +18,8 @@ export const useConnectionStore = defineStore('connection', {
|
||||
stopRequested: false,
|
||||
projectPath: '',
|
||||
agentVersion: '',
|
||||
thinkingMode: true
|
||||
thinkingMode: false,
|
||||
thinkingModeOption: 'fast'
|
||||
}),
|
||||
actions: {
|
||||
setSocket(socket: Socket | null) {
|
||||
@ -43,9 +45,27 @@ export const useConnectionStore = defineStore('connection', {
|
||||
},
|
||||
setThinkingMode(value: boolean) {
|
||||
this.thinkingMode = !!value;
|
||||
if (!value) {
|
||||
this.thinkingModeOption = 'fast';
|
||||
} else if (this.thinkingModeOption === 'fast') {
|
||||
this.thinkingModeOption = 'smart';
|
||||
}
|
||||
},
|
||||
setThinkingModeOption(option: string) {
|
||||
if (!['fast', 'smart', 'deep'].includes(option)) {
|
||||
return;
|
||||
}
|
||||
this.thinkingModeOption = option as ConnectionState['thinkingModeOption'];
|
||||
this.thinkingMode = option !== 'fast';
|
||||
},
|
||||
toggleThinkingMode() {
|
||||
this.thinkingMode = !this.thinkingMode;
|
||||
if (this.thinkingModeOption === 'fast') {
|
||||
this.setThinkingModeOption('smart');
|
||||
} else if (this.thinkingModeOption === 'smart') {
|
||||
this.setThinkingModeOption('deep');
|
||||
} else {
|
||||
this.setThinkingModeOption('fast');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -8,6 +8,7 @@ interface InputState {
|
||||
quickMenuOpen: boolean;
|
||||
toolMenuOpen: boolean;
|
||||
settingsOpen: boolean;
|
||||
modeMenuOpen: boolean;
|
||||
}
|
||||
|
||||
export const useInputStore = defineStore('input', {
|
||||
@ -18,7 +19,8 @@ export const useInputStore = defineStore('input', {
|
||||
inputIsFocused: false,
|
||||
quickMenuOpen: false,
|
||||
toolMenuOpen: false,
|
||||
settingsOpen: false
|
||||
settingsOpen: false,
|
||||
modeMenuOpen: false
|
||||
}),
|
||||
actions: {
|
||||
setInputMessage(value: string) {
|
||||
@ -44,6 +46,7 @@ export const useInputStore = defineStore('input', {
|
||||
if (!open) {
|
||||
this.toolMenuOpen = false;
|
||||
this.settingsOpen = false;
|
||||
this.modeMenuOpen = false;
|
||||
}
|
||||
},
|
||||
toggleQuickMenu() {
|
||||
@ -55,6 +58,7 @@ export const useInputStore = defineStore('input', {
|
||||
this.quickMenuOpen = false;
|
||||
this.toolMenuOpen = false;
|
||||
this.settingsOpen = false;
|
||||
this.modeMenuOpen = false;
|
||||
},
|
||||
toggleToolMenu() {
|
||||
this.toolMenuOpen = !this.toolMenuOpen;
|
||||
@ -69,6 +73,13 @@ export const useInputStore = defineStore('input', {
|
||||
},
|
||||
setSettingsOpen(open: boolean) {
|
||||
this.settingsOpen = open;
|
||||
},
|
||||
toggleModeMenu() {
|
||||
this.modeMenuOpen = !this.modeMenuOpen;
|
||||
return this.modeMenuOpen;
|
||||
},
|
||||
setModeMenuOpen(open: boolean) {
|
||||
this.modeMenuOpen = open;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -9,6 +9,7 @@ interface PersonalForm {
|
||||
considerations: string[];
|
||||
thinking_interval: number | null;
|
||||
disabled_tool_categories: string[];
|
||||
default_mode: string;
|
||||
}
|
||||
|
||||
interface PersonalizationState {
|
||||
@ -28,10 +29,16 @@ interface PersonalizationState {
|
||||
toolCategories: Array<{ id: string; label: string }>;
|
||||
thinkingIntervalDefault: number;
|
||||
thinkingIntervalRange: { min: number; max: number };
|
||||
modeOptions: Array<{ value: string; label: string; description: string }>;
|
||||
}
|
||||
|
||||
const DEFAULT_INTERVAL = 10;
|
||||
const DEFAULT_INTERVAL_RANGE = { min: 1, max: 50 };
|
||||
const DEFAULT_MODE_OPTIONS = [
|
||||
{ value: 'fast', label: '快速模式', description: '即时响应' },
|
||||
{ value: 'smart', label: '思考模式', description: '智能调度' },
|
||||
{ value: 'deep', label: '深度思考模式', description: '全程推理' }
|
||||
];
|
||||
|
||||
const defaultForm = (): PersonalForm => ({
|
||||
enabled: false,
|
||||
@ -41,7 +48,8 @@ const defaultForm = (): PersonalForm => ({
|
||||
tone: '',
|
||||
considerations: [],
|
||||
thinking_interval: null,
|
||||
disabled_tool_categories: []
|
||||
disabled_tool_categories: [],
|
||||
default_mode: 'fast'
|
||||
});
|
||||
|
||||
export const usePersonalizationStore = defineStore('personalization', {
|
||||
@ -61,7 +69,8 @@ export const usePersonalizationStore = defineStore('personalization', {
|
||||
form: defaultForm(),
|
||||
toolCategories: [],
|
||||
thinkingIntervalDefault: DEFAULT_INTERVAL,
|
||||
thinkingIntervalRange: { ...DEFAULT_INTERVAL_RANGE }
|
||||
thinkingIntervalRange: { ...DEFAULT_INTERVAL_RANGE },
|
||||
modeOptions: [...DEFAULT_MODE_OPTIONS]
|
||||
}),
|
||||
actions: {
|
||||
async openDrawer() {
|
||||
@ -121,7 +130,10 @@ export const usePersonalizationStore = defineStore('personalization', {
|
||||
tone: data.tone || '',
|
||||
considerations: Array.isArray(data.considerations) ? [...data.considerations] : [],
|
||||
thinking_interval: typeof data.thinking_interval === 'number' ? data.thinking_interval : null,
|
||||
disabled_tool_categories: Array.isArray(data.disabled_tool_categories) ? data.disabled_tool_categories.filter((item: unknown) => typeof item === 'string') : []
|
||||
disabled_tool_categories: Array.isArray(data.disabled_tool_categories)
|
||||
? data.disabled_tool_categories.filter((item: unknown) => typeof item === 'string')
|
||||
: [],
|
||||
default_mode: typeof data.default_mode === 'string' ? data.default_mode : 'fast'
|
||||
};
|
||||
this.clearFeedback();
|
||||
},
|
||||
@ -150,6 +162,26 @@ export const usePersonalizationStore = defineStore('personalization', {
|
||||
} else {
|
||||
this.toolCategories = [];
|
||||
}
|
||||
if (payload && Array.isArray(payload.thinking_mode_options) && payload.thinking_mode_options.length) {
|
||||
this.modeOptions = payload.thinking_mode_options
|
||||
.map((value: string) => {
|
||||
const preset = DEFAULT_MODE_OPTIONS.find((option) => option.value === value);
|
||||
if (preset) {
|
||||
return preset;
|
||||
}
|
||||
return { value, label: value, description: '' };
|
||||
})
|
||||
.filter((item: { value: string }) => !!item.value);
|
||||
} else {
|
||||
this.modeOptions = [...DEFAULT_MODE_OPTIONS];
|
||||
}
|
||||
if (!this.modeOptions.some((option) => option.value === this.form.default_mode)) {
|
||||
const fallback = this.modeOptions[0]?.value || 'fast';
|
||||
this.form = {
|
||||
...this.form,
|
||||
default_mode: fallback
|
||||
};
|
||||
}
|
||||
},
|
||||
clearFeedback() {
|
||||
this.status = '';
|
||||
@ -281,6 +313,20 @@ export const usePersonalizationStore = defineStore('personalization', {
|
||||
};
|
||||
this.clearFeedback();
|
||||
},
|
||||
setDefaultMode(mode: string) {
|
||||
if (!mode) {
|
||||
return;
|
||||
}
|
||||
const valid = this.modeOptions.some((option) => option.value === mode);
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
this.form = {
|
||||
...this.form,
|
||||
default_mode: mode
|
||||
};
|
||||
this.clearFeedback();
|
||||
},
|
||||
updateNewConsideration(value: string) {
|
||||
this.newConsideration = value;
|
||||
this.clearFeedback();
|
||||
|
||||
@ -259,6 +259,11 @@
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.quick-submenu.mode-submenu {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.menu-entry.submenu-entry {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
@ -268,6 +273,15 @@
|
||||
color: var(--claude-text-secondary);
|
||||
}
|
||||
|
||||
.menu-entry.submenu-entry.active {
|
||||
background: rgba(189, 93, 58, 0.1);
|
||||
border: 1px solid rgba(189, 93, 58, 0.3);
|
||||
}
|
||||
|
||||
.menu-entry.submenu-entry.active .entry-arrow {
|
||||
color: var(--claude-accent);
|
||||
}
|
||||
|
||||
.menu-entry.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@ -170,6 +170,67 @@
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.mode-preference {
|
||||
margin-bottom: 18px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.mode-preference-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.mode-preference-title {
|
||||
font-weight: 600;
|
||||
color: var(--claude-text);
|
||||
}
|
||||
|
||||
.mode-preference-hint {
|
||||
font-size: 13px;
|
||||
color: var(--claude-text-secondary);
|
||||
}
|
||||
|
||||
.mode-option-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.mode-option-chip {
|
||||
border: 1px solid rgba(118, 103, 84, 0.3);
|
||||
border-radius: 16px;
|
||||
padding: 10px 14px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
text-align: left;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
|
||||
}
|
||||
|
||||
.mode-option-chip:hover {
|
||||
border-color: var(--claude-accent);
|
||||
}
|
||||
|
||||
.mode-option-chip.active {
|
||||
border-color: var(--claude-accent);
|
||||
background: rgba(189, 93, 58, 0.08);
|
||||
box-shadow: 0 6px 20px rgba(189, 93, 58, 0.15);
|
||||
}
|
||||
|
||||
.mode-option-label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mode-option-desc {
|
||||
font-size: 13px;
|
||||
color: var(--claude-text-secondary);
|
||||
}
|
||||
|
||||
.personalization-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 200px minmax(0, 1fr);
|
||||
|
||||
@ -137,6 +137,16 @@
|
||||
box-shadow: 0 8px 20px rgba(255, 204, 77, 0.35);
|
||||
}
|
||||
|
||||
.mode-indicator.smart {
|
||||
background: var(--claude-accent);
|
||||
box-shadow: 0 8px 20px rgba(189, 93, 58, 0.25);
|
||||
}
|
||||
|
||||
.mode-indicator.deep {
|
||||
background: linear-gradient(135deg, #7c5dfa, #4b32c3);
|
||||
box-shadow: 0 8px 20px rgba(76, 50, 195, 0.35);
|
||||
}
|
||||
|
||||
.mode-indicator .icon {
|
||||
--icon-size: 18px;
|
||||
color: inherit;
|
||||
|
||||
@ -46,6 +46,7 @@ class DeepSeekClient:
|
||||
"model_id": THINKING_MODEL_ID or MODEL_ID
|
||||
}
|
||||
self.thinking_mode = thinking_mode # True=智能思考模式, False=快速模式
|
||||
self.deep_thinking_mode = False
|
||||
self.web_mode = web_mode # Web模式标志,用于禁用print输出
|
||||
# 兼容旧代码路径
|
||||
self.api_base_url = self.fast_api_config["base_url"]
|
||||
@ -57,6 +58,7 @@ class DeepSeekClient:
|
||||
self.force_thinking_next_call = False # 单次强制思考
|
||||
self.skip_thinking_next_call = False # 单次强制快速
|
||||
self.last_call_used_thinking = False # 最近一次调用是否使用思考模型
|
||||
self.deep_thinking_mode = False
|
||||
|
||||
def _print(self, message: str, end: str = "\n", flush: bool = False):
|
||||
"""安全的打印函数,在Web模式下不输出"""
|
||||
@ -154,6 +156,8 @@ class DeepSeekClient:
|
||||
|
||||
def get_current_thinking_mode(self) -> bool:
|
||||
"""获取当前应该使用的思考模式"""
|
||||
if self.deep_thinking_mode:
|
||||
return True
|
||||
if not self.thinking_mode:
|
||||
return False
|
||||
if self.force_thinking_next_call:
|
||||
|
||||
@ -57,6 +57,7 @@ from modules.personalization_manager import (
|
||||
save_personalization_config,
|
||||
THINKING_INTERVAL_MIN,
|
||||
THINKING_INTERVAL_MAX,
|
||||
THINKING_MODE_OPTIONS,
|
||||
)
|
||||
from modules.user_container_manager import UserContainerManager
|
||||
from modules.usage_tracker import UsageTracker
|
||||
@ -484,6 +485,13 @@ def with_terminal(func):
|
||||
return jsonify({"error": str(exc), "code": "resource_busy"}), 503
|
||||
if not terminal or not workspace:
|
||||
return jsonify({"error": "System not initialized"}), 503
|
||||
preferred_mode = session.get('thinking_mode_option')
|
||||
if not preferred_mode:
|
||||
preferred_mode = getattr(terminal, "default_thinking_mode_option", "fast")
|
||||
session['thinking_mode_option'] = preferred_mode
|
||||
if preferred_mode != getattr(terminal, "thinking_mode_option", None):
|
||||
terminal.set_thinking_mode_option(preferred_mode)
|
||||
session['thinking_mode'] = terminal.thinking_mode
|
||||
kwargs.update({
|
||||
'terminal': terminal,
|
||||
'workspace': workspace,
|
||||
@ -661,6 +669,11 @@ def apply_thinking_schedule(terminal: WebTerminal):
|
||||
client.skip_thinking_next_call = False
|
||||
return
|
||||
state = get_thinking_state(terminal)
|
||||
if getattr(terminal, "deep_thinking_mode", False):
|
||||
client.force_thinking_next_call = False
|
||||
client.skip_thinking_next_call = False
|
||||
state["fast_streak"] = 0
|
||||
return
|
||||
awaiting_writes = getattr(terminal, "pending_append_request", None) or getattr(terminal, "pending_modify_request", None)
|
||||
if awaiting_writes:
|
||||
client.skip_thinking_next_call = True
|
||||
@ -699,6 +712,9 @@ def update_thinking_after_call(terminal: WebTerminal):
|
||||
if not getattr(terminal, "thinking_mode", False):
|
||||
return
|
||||
state = get_thinking_state(terminal)
|
||||
if getattr(terminal, "deep_thinking_mode", False):
|
||||
state["fast_streak"] = 0
|
||||
return
|
||||
if terminal.api_client.last_call_used_thinking:
|
||||
state["fast_streak"] = 0
|
||||
else:
|
||||
@ -831,7 +847,9 @@ def login():
|
||||
|
||||
session['logged_in'] = True
|
||||
session['username'] = record.username
|
||||
session['thinking_mode'] = app.config.get('DEFAULT_THINKING_MODE', False)
|
||||
default_mode_option = app.config.get('DEFAULT_THINKING_MODE_OPTION', 'fast')
|
||||
session['thinking_mode_option'] = default_mode_option if default_mode_option in THINKING_MODE_OPTIONS else 'fast'
|
||||
session['thinking_mode'] = session['thinking_mode_option'] != 'fast'
|
||||
session.permanent = True
|
||||
clear_failures("login", identifier=client_ip)
|
||||
workspace = user_manager.ensure_user_workspace(record.username)
|
||||
@ -979,6 +997,8 @@ def get_status(terminal: WebTerminal, workspace: UserWorkspace, username: str):
|
||||
print(f"[Status] 获取当前对话信息失败: {e}")
|
||||
|
||||
status['project_path'] = str(workspace.project_path)
|
||||
status['thinking_mode_option'] = getattr(terminal, "thinking_mode_option", "fast")
|
||||
status['deep_thinking_mode'] = getattr(terminal, "deep_thinking_mode", False)
|
||||
try:
|
||||
status['container'] = container_manager.get_container_status(username)
|
||||
except Exception as exc:
|
||||
@ -1041,11 +1061,16 @@ def update_thinking_mode(terminal: WebTerminal, workspace: UserWorkspace, userna
|
||||
"""切换思考模式"""
|
||||
try:
|
||||
data = request.get_json() or {}
|
||||
desired_mode = bool(data.get('thinking_mode'))
|
||||
terminal.thinking_mode = desired_mode
|
||||
terminal.api_client.thinking_mode = desired_mode
|
||||
mode_option = data.get('mode')
|
||||
if isinstance(mode_option, str) and mode_option not in THINKING_MODE_OPTIONS:
|
||||
mode_option = None
|
||||
if not mode_option:
|
||||
desired_mode = bool(data.get('thinking_mode'))
|
||||
mode_option = "smart" if desired_mode else "fast"
|
||||
terminal.set_thinking_mode_option(mode_option)
|
||||
terminal.api_client.start_new_task()
|
||||
session['thinking_mode'] = desired_mode
|
||||
session['thinking_mode_option'] = mode_option
|
||||
session['thinking_mode'] = terminal.thinking_mode
|
||||
# 更新当前对话的元数据
|
||||
ctx = terminal.context_manager
|
||||
if ctx.current_conversation_id:
|
||||
@ -1055,7 +1080,7 @@ def update_thinking_mode(terminal: WebTerminal, workspace: UserWorkspace, userna
|
||||
messages=ctx.conversation_history,
|
||||
project_path=str(ctx.project_path),
|
||||
todo_list=ctx.todo_list,
|
||||
thinking_mode=desired_mode
|
||||
thinking_mode=terminal.thinking_mode
|
||||
)
|
||||
except Exception as exc:
|
||||
print(f"[API] 保存思考模式到对话失败: {exc}")
|
||||
@ -1065,7 +1090,11 @@ def update_thinking_mode(terminal: WebTerminal, workspace: UserWorkspace, userna
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"data": status.get("thinking_mode")
|
||||
"data": {
|
||||
"thinking_mode": terminal.thinking_mode,
|
||||
"mode": terminal.thinking_mode_option,
|
||||
"deep": terminal.deep_thinking_mode
|
||||
}
|
||||
})
|
||||
except Exception as exc:
|
||||
print(f"[API] 切换思考模式失败: {exc}")
|
||||
@ -1091,7 +1120,8 @@ def get_personalization_settings(terminal: WebTerminal, workspace: UserWorkspace
|
||||
"thinking_interval_range": {
|
||||
"min": THINKING_INTERVAL_MIN,
|
||||
"max": THINKING_INTERVAL_MAX
|
||||
}
|
||||
},
|
||||
"thinking_mode_options": THINKING_MODE_OPTIONS
|
||||
})
|
||||
except Exception as exc:
|
||||
return jsonify({"success": False, "error": str(exc)}), 500
|
||||
@ -1108,6 +1138,8 @@ def update_personalization_settings(terminal: WebTerminal, workspace: UserWorksp
|
||||
config = save_personalization_config(workspace.data_dir, payload)
|
||||
try:
|
||||
terminal.apply_personalization_preferences(config)
|
||||
session['thinking_mode_option'] = getattr(terminal, "thinking_mode_option", session.get('thinking_mode_option', 'fast'))
|
||||
session['thinking_mode'] = terminal.thinking_mode
|
||||
except Exception as exc:
|
||||
debug_log(f"应用个性化偏好失败: {exc}")
|
||||
return jsonify({
|
||||
@ -1118,7 +1150,8 @@ def update_personalization_settings(terminal: WebTerminal, workspace: UserWorksp
|
||||
"thinking_interval_range": {
|
||||
"min": THINKING_INTERVAL_MIN,
|
||||
"max": THINKING_INTERVAL_MAX
|
||||
}
|
||||
},
|
||||
"thinking_mode_options": THINKING_MODE_OPTIONS
|
||||
})
|
||||
except ValueError as exc:
|
||||
return jsonify({"success": False, "error": str(exc)}), 400
|
||||
@ -3791,14 +3824,17 @@ async def handle_task_with_sender(terminal: WebTerminal, message, sender, client
|
||||
"content": assistant_content,
|
||||
"tool_calls": tool_calls
|
||||
}
|
||||
reasoning_payload = current_thinking if getattr(web_terminal, "deep_thinking_mode", False) else None
|
||||
if reasoning_payload:
|
||||
assistant_message["reasoning_content"] = reasoning_payload
|
||||
|
||||
messages.append(assistant_message)
|
||||
if assistant_content or current_thinking or tool_calls:
|
||||
if assistant_content or reasoning_payload or tool_calls:
|
||||
web_terminal.context_manager.add_conversation(
|
||||
"assistant",
|
||||
assistant_content,
|
||||
tool_calls=tool_calls if tool_calls else None,
|
||||
reasoning_content=current_thinking or None
|
||||
reasoning_content=reasoning_payload
|
||||
)
|
||||
|
||||
# 为下一轮迭代重置流状态标志,但保留 full_response 供上面保存使用
|
||||
@ -4312,7 +4348,9 @@ def initialize_system(path: str, thinking_mode: bool = False):
|
||||
print(f"[Init] 自动修复: {'开启' if AUTO_FIX_TOOL_CALL else '关闭'}")
|
||||
print(f"[Init] 调试日志: {DEBUG_LOG_FILE}")
|
||||
|
||||
default_option = "smart" if thinking_mode else "fast"
|
||||
app.config['DEFAULT_THINKING_MODE'] = thinking_mode
|
||||
app.config['DEFAULT_THINKING_MODE_OPTION'] = default_option
|
||||
print(f"{OUTPUT_FORMATS['success']} Web系统初始化完成(多用户模式)")
|
||||
|
||||
def run_server(path: str, thinking_mode: bool = False, port: int = DEFAULT_PORT, debug: bool = False):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user