diff --git a/mateclaw-ui/src/components/chat/ChatInput.vue b/mateclaw-ui/src/components/chat/ChatInput.vue
index 6ae1059c..56b35f31 100644
--- a/mateclaw-ui/src/components/chat/ChatInput.vue
+++ b/mateclaw-ui/src/components/chat/ChatInput.vue
@@ -136,14 +136,16 @@
-
+
@@ -239,6 +241,11 @@ interface Props {
enableTalkMode?: boolean
/** 深度思考开关状态 */
thinkingEnabled?: boolean
+ /**
+ * RFC-049 PR-1-UI: 当前 runtime 模型是否支持 reasoning_effort。false 时按钮灰掉,
+ * 不响应点击,tooltip 提示当前模型不支持深度思考。默认 true 以保持向后兼容。
+ */
+ thinkingSupported?: boolean
}
const props = withDefaults(defineProps(), {
@@ -257,6 +264,7 @@ const props = withDefaults(defineProps(), {
queueSize: 0,
enableTalkMode: false,
thinkingEnabled: false,
+ thinkingSupported: true,
})
const emit = defineEmits<{
@@ -598,6 +606,11 @@ defineExpose({
border-radius: 50%;
background: var(--el-color-primary, #409eff);
}
+/* RFC-049 PR-1-UI: model doesn't support reasoning_effort — stronger grayed state */
+.thinking-btn.unsupported {
+ opacity: 0.35;
+ cursor: not-allowed;
+}
.thinking-btn:hover:not(:disabled) {
color: var(--el-color-primary, #409eff);
background: var(--el-color-primary-light-9, rgba(64, 158, 255, 0.08));
diff --git a/mateclaw-ui/src/i18n/locales/en-US.ts b/mateclaw-ui/src/i18n/locales/en-US.ts
index a11e20ee..6e4af92b 100644
--- a/mateclaw-ui/src/i18n/locales/en-US.ts
+++ b/mateclaw-ui/src/i18n/locales/en-US.ts
@@ -165,6 +165,7 @@ export default {
messagePlaceholder: 'Type a message... (Enter to send, Shift+Enter for new line)',
thinkingOn: 'Deep thinking enabled',
thinkingOff: 'Click to enable deep thinking',
+ thinkingUnsupported: 'Current model does not support deep thinking',
subtitle: 'Your intelligent AI assistant powered by Spring AI Alibaba',
// Queue related
queuedSending: 'Sending queued message...',
diff --git a/mateclaw-ui/src/i18n/locales/zh-CN.ts b/mateclaw-ui/src/i18n/locales/zh-CN.ts
index e014e338..063db738 100644
--- a/mateclaw-ui/src/i18n/locales/zh-CN.ts
+++ b/mateclaw-ui/src/i18n/locales/zh-CN.ts
@@ -165,6 +165,7 @@ export default {
messagePlaceholder: '输入消息... (Enter 发送, Shift+Enter 换行)',
thinkingOn: '深度思考已开启',
thinkingOff: '点击开启深度思考',
+ thinkingUnsupported: '当前模型不支持深度思考',
subtitle: '基于 Spring AI Alibaba 的智能 AI 助手',
// 排队相关
queuedSending: '正在发送排队消息...',
diff --git a/mateclaw-ui/src/types/index.ts b/mateclaw-ui/src/types/index.ts
index 94c48aea..6b1e0607 100644
--- a/mateclaw-ui/src/types/index.ts
+++ b/mateclaw-ui/src/types/index.ts
@@ -586,6 +586,14 @@ export interface ProviderModelInfo {
probeOk?: boolean
/** Short error message when probeOk=false */
probeError?: string
+ /**
+ * RFC-049 PR-1-UI: whether the model's `ModelFamily` accepts the
+ * `reasoning_effort` parameter. Derived server-side from the model name;
+ * true only for the OpenAI reasoning family (gpt-5, o1, o3, o4 variants).
+ * Used by the thinking-depth selector to gray itself out on non-reasoning
+ * models.
+ */
+ supportsReasoningEffort?: boolean
}
export interface ProviderInfo {
diff --git a/mateclaw-ui/src/views/ChatConsole.vue b/mateclaw-ui/src/views/ChatConsole.vue
index 676f192d..548b7494 100644
--- a/mateclaw-ui/src/views/ChatConsole.vue
+++ b/mateclaw-ui/src/views/ChatConsole.vue
@@ -252,6 +252,7 @@
@deny="handleDeny"
:enable-talk-mode="!!selectedAgentId"
:thinking-enabled="thinkingEnabled"
+ :thinking-supported="currentModelSupportsReasoningEffort"
@toggle-thinking="thinkingEnabled = !thinkingEnabled"
@talk="showTalkMode = true"
/>
@@ -635,6 +636,26 @@ const currentRuntimeModel = computed(() => {
return currentAgent.value?.modelName || 'default'
})
+/**
+ * RFC-049 PR-1-UI: whether the active runtime model supports `reasoning_effort`.
+ * Drives the enable/disable state of the thinking-depth toggle in ChatInput:
+ * chat-type models that don't support thinking must not honor the "deep thinking"
+ * selection (product contract — UI reflects the backend gate).
+ *
+ * Source of truth: ProviderModelInfo.supportsReasoningEffort (set by backend via
+ * ModelFamily.detect(modelName) in ModelInfoDTO).
+ */
+const currentModelSupportsReasoningEffort = computed(() => {
+ const providerId = activeModels.value?.activeLlm?.providerId
+ const modelName = activeModels.value?.activeLlm?.model
+ if (!providerId || !modelName) return false
+ const provider = providers.value.find((p) => p.id === providerId)
+ if (!provider) return false
+ const all = [...(provider.models || []), ...(provider.extraModels || [])]
+ const hit = all.find((m) => m.id === modelName || m.name === modelName)
+ return Boolean(hit?.supportsReasoningEffort)
+})
+
const userInitial = computed(() => (localStorage.getItem('username') || 'U').charAt(0).toUpperCase())
const activeModelValue = computed(() => {