Skip to content

Commit 55af2b5

Browse files
committed
v0.7.3: v0.7.3: revamped provider settings UI with template-based presentation, expanded default model catalog and pricing, replaced pin feature with folder-based organization, UI refinements, and conversation copy support
1 parent 6343f86 commit 55af2b5

28 files changed

Lines changed: 1888 additions & 395 deletions

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@
2525
<img src="https://img.shields.io/badge/platform-Linux%20·%20macOS%20·%20Windows-lightgrey" alt="Platform" />
2626
</p>
2727

28+
<p align="center">
29+
<img src="propaganda/mainpage.jpg" width="800" alt="Main Interface" />
30+
</p>
31+
32+
<p align="center">
33+
<img src="propaganda/chatinner.jpg" width="800" alt="Chat Interface" />
34+
</p>
35+
36+
<p align="center">
37+
<img src="propaganda/providersetting.jpg" width="800" alt="Model Provider Settings" />
38+
</p>
39+
2840
---
2941

3042
## What is Tofu?

README_CN.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@
2121
<img src="https://img.shields.io/badge/platform-Linux%20·%20macOS%20·%20Windows-lightgrey" alt="Platform" />
2222
</p>
2323

24+
<p align="center">
25+
<img src="propaganda/mainpage.jpg" width="800" alt="主界面" />
26+
</p>
27+
28+
<p align="center">
29+
<img src="propaganda/chatinner.jpg" width="800" alt="对话界面" />
30+
</p>
31+
32+
<p align="center">
33+
<img src="propaganda/providersetting.jpg" width="800" alt="模型服务商设置" />
34+
</p>
35+
2436
---
2537

2638
## Tofu 是什么?

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.7.2
1+
0.7.3

index.html

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<link rel="stylesheet" href="static/vendor/google-fonts-local.css">
1717
<link rel="stylesheet" href="static/vendor/github-dark.min.css">
1818
<link rel="stylesheet" href="static/vendor/katex/katex.min.css">
19-
<link rel="stylesheet" href="static/styles.css?v=0.7.2">
19+
<link rel="stylesheet" href="static/styles.css?v=0.7.3">
2020
<script>
2121
// Prevent flash of wrong theme — apply before render (default: tofu)
2222
(function(){var t=localStorage.getItem('claude_ui_theme')||'tofu';document.documentElement.setAttribute('data-theme',t);})();
@@ -40,7 +40,8 @@
4040
var stubs = ['handleKeyDown','sendMessage','newChat','togglePresetDropdown',
4141
'cycleTheme','toggleDebug','toggleSidebar','openSettings','toggleCodeExec',
4242
'toggleBrowser','toggleMemory','toggleSwarm','toggleAutoTranslate',
43-
'toggleAutoApply','selectThinkingDepth','cycleSearchMode','enterImageGenMode'];
43+
'toggleAutoApply','selectThinkingDepth','cycleSearchMode','enterImageGenMode',
44+
'toggleSidebarSearch','closeSidebarSearch'];
4445
for (var i = 0; i < stubs.length; i++) {
4546
(function(name) {
4647
window[name] = function() { _notReady(); };
@@ -83,6 +84,9 @@
8384
<div class="sidebar-header">
8485
<h1><svg class="sidebar-tofu-icon" width="22" height="22" viewBox="0 0 32 32" fill="none"><defs><linearGradient id="sTop" x1="0" y1="0" x2=".5" y2="1"><stop offset="0%" stop-color="#fef8ec"/><stop offset="100%" stop-color="#fdf2d7"/></linearGradient><linearGradient id="sFront" x1="0" y1="0" x2=".2" y2="1"><stop offset="0%" stop-color="#fdf4dc"/><stop offset="100%" stop-color="#f5e8c8"/></linearGradient><linearGradient id="sSide" x1="0" y1="0" x2="1" y2=".7"><stop offset="0%" stop-color="#ecdcc0"/><stop offset="100%" stop-color="#dcc8a4"/></linearGradient></defs><path d="M15.3 4.6 L6.4 9.6 L16.3 16 L26.2 10.5Z" fill="url(#sTop)"/><path d="M6.4 9.6 L6.1 21.1 L17.2 27.2 L16.3 16Z" fill="url(#sFront)"/><path d="M16.3 16 L17.2 27.2 L25.9 22.3 L26.2 10.5Z" fill="url(#sSide)"/><path d="M15.3 4.6 L6.4 9.6 L6.1 21.1 L17.2 27.2 L25.9 22.3 L26.2 10.5Z" stroke="#1a1520" stroke-width=".6" stroke-linejoin="round" fill="none"/><rect x="7.8" y="14.2" width="2.6" height="3.3" rx=".3" fill="#1a1520"/><rect x="9.2" y="14.5" width=".9" height="1.2" rx=".2" fill="white" opacity=".9"/><rect x="13.1" y="16.5" width="2.6" height="3.8" rx=".3" fill="#1a1520"/><rect x="14.5" y="16.9" width=".9" height="1.3" rx=".2" fill="white" opacity=".9"/><path d="M10.1 20.1 Q12 21.6 13.9 20.1" stroke="#1a1520" stroke-width=".5" fill="none" stroke-linecap="round" opacity=".45"/><ellipse cx="8" cy="18.4" rx="1" ry=".7" fill="#ffaaa2" opacity=".5"/><ellipse cx="15" cy="21.3" rx="1.1" ry=".7" fill="#feaca5" opacity=".5"/></svg><span class="sidebar-brand"><span class="sidebar-brand-t">T</span><span class="sidebar-brand-o">o</span><span class="sidebar-brand-f">f</span><span class="sidebar-brand-u">u</span></span></h1>
8586
<div style="display:flex;gap:4px;align-items:center;">
87+
<button class="action-btn" id="sidebarSearchToggle" onclick="toggleSidebarSearch()" title="搜索对话">
88+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><line x1="16.5" y1="16.5" x2="21" y2="21"/></svg>
89+
</button>
8690
<button class="action-btn" onclick="openDailyReport()" title="My Day">
8791
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
8892
</button>
@@ -94,20 +98,21 @@ <h1><svg class="sidebar-tofu-icon" width="22" height="22" viewBox="0 0 32 32" fi
9498
</button>
9599
</div>
96100
</div>
97-
<button class="new-chat-btn" onclick="newChat()">
98-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
99-
New Chat
100-
</button>
101-
<div class="sidebar-search-wrapper">
101+
<div class="sidebar-action-row">
102+
<button class="new-chat-btn" onclick="newChat()">
103+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
104+
New Chat
105+
</button>
106+
</div>
107+
<div class="sidebar-search-wrapper" id="sidebarSearchWrapper" style="display:none">
102108
<div class="sidebar-search-box">
103109
<span class="sidebar-search-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><line x1="16.5" y1="16.5" x2="21" y2="21"/></svg></span>
104110
<input type="text" class="sidebar-search-input" id="sidebarSearchInput" placeholder="Search conversations..." autocomplete="off" spellcheck="false">
105-
<button class="sidebar-search-clear" id="sidebarSearchClear" onclick="clearSidebarSearch()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
111+
<button class="sidebar-search-clear" id="sidebarSearchClear" onclick="closeSidebarSearch()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
106112
</div>
107113
<div class="sidebar-search-stats" id="sidebarSearchStats"></div>
108114
</div>
109-
<div class="conv-pinned-zone" id="convPinnedZone"></div>
110-
<div class="conv-freeze-border" id="convFreezeBorder"><span class="conv-freeze-border-dot"></span></div>
115+
<div class="folder-tabs" id="folderTabs"></div>
111116
<div class="conversations-list" id="convList"></div>
112117
</aside>
113118
<main class="main">
@@ -549,6 +554,19 @@ <h3>设置</h3>
549554
<div id="tradingRestartHint" class="settings-hint-banner" style="display:none;">需要重启服务器才能生效</div>
550555
</div>
551556

557+
<div class="settings-group">
558+
<div class="settings-toggle-row">
559+
<div>
560+
<span class="settings-toggle-label">调试模式</span>
561+
<div class="settings-toggle-desc">显示 trace_id、复制会话 ID 按钮等开发调试信息</div>
562+
</div>
563+
<label class="stg-toggle">
564+
<input type="checkbox" id="settingDebugMode">
565+
<span class="stg-toggle-track"><span class="stg-toggle-thumb"></span></span>
566+
</label>
567+
</div>
568+
</div>
569+
552570

553571
</div>
554572

@@ -938,7 +956,7 @@ <h3>设置</h3>
938956
<div class="mcp-install-modal-desc" id="mcpInstallDesc"></div>
939957

940958
<a class="mcp-app-repo" id="mcpInstallRepo" href="#" target="_blank" rel="noopener" style="display:none">
941-
<svg width="10" height="10" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
959+
<svg width="9" height="9" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
942960
Source Repo
943961
</a>
944962
</div>
@@ -1394,23 +1412,23 @@ <h3>Apply Code to File</h3>
13941412
</div>
13951413

13961414
<!-- html2canvas: lazy-loaded on first Export click (199KB, avoids DevTools freeze) -->
1397-
<script defer src="static/js/idb-cache.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1398-
<script defer src="static/js/core.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1399-
<script defer src="static/js/export-images.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1400-
<script defer src="static/js/branch.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1401-
<script defer src="static/js/ui.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1415+
<script defer src="static/js/idb-cache.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1416+
<script defer src="static/js/core.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1417+
<script defer src="static/js/export-images.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1418+
<script defer src="static/js/branch.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1419+
<script defer src="static/js/ui.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
14021420
<!-- Feature modules (extracted from main.js) -->
1403-
<script defer src="static/js/log-clean.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1404-
<script defer src="static/js/translation.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1405-
<script defer src="static/js/upload.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1406-
<script defer src="static/js/image-gen.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1407-
<script defer src="static/js/project.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1408-
<script defer src="static/js/memory.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1409-
<script defer src="static/js/scheduler.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1410-
<script defer src="static/js/timer.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1411-
<script defer src="static/js/myday.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1412-
<script defer src="static/js/settings.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1413-
<script defer src="static/js/main.js?v=0.7.2" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1421+
<script defer src="static/js/log-clean.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1422+
<script defer src="static/js/translation.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1423+
<script defer src="static/js/upload.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1424+
<script defer src="static/js/image-gen.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1425+
<script defer src="static/js/project.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1426+
<script defer src="static/js/memory.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1427+
<script defer src="static/js/scheduler.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1428+
<script defer src="static/js/timer.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1429+
<script defer src="static/js/myday.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1430+
<script defer src="static/js/settings.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
1431+
<script defer src="static/js/main.js?v=0.7.3" onload="_onScriptLoad()" onerror="_onScriptError(event)"></script>
14141432
<script>
14151433
// Feature flags — show/hide optional modules
14161434
var _featureFlags = {};

lib/__init__.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
'DOUBAO_MODEL', 'CLAUDE_SONNET_MODEL',
1313
'IMAGE_GEN_MODEL', 'EMBEDDING_MODELS',
1414
'TRADING_ENABLED',
15+
'DEBUG_MODE',
1516
'FETCH_TOP_N', 'FETCH_TIMEOUT',
1617
'FETCH_MAX_CHARS_SEARCH', 'FETCH_MAX_CHARS_DIRECT',
1718
'FETCH_MAX_CHARS_PDF', 'FETCH_MAX_BYTES',
@@ -166,6 +167,31 @@ def _resolve_trading_enabled():
166167
TRADING_ENABLED = _resolve_trading_enabled()
167168

168169

170+
# ── Debug Mode (default OFF — shows trace_id, conv-copy-id in sidebar) ──
171+
def _resolve_debug_mode():
172+
"""Resolve DEBUG_MODE from env-var or persistent features.json.
173+
174+
Priority: env-var > data/config/features.json > default(OFF).
175+
When enabled, shows trace_id in finish tags and copy-conv-id button in sidebar.
176+
"""
177+
env_val = os.environ.get('DEBUG_MODE')
178+
if env_val is not None:
179+
return env_val == '1'
180+
_features_path = _config_path('features.json')
181+
try:
182+
if os.path.isfile(_features_path):
183+
with open(_features_path) as f:
184+
feats = _json.load(f)
185+
if isinstance(feats, dict) and 'debug_mode' in feats:
186+
return bool(feats['debug_mode'])
187+
except Exception as _e:
188+
import logging as _logging
189+
_logging.getLogger(__name__).debug('Could not read features.json: %s', _e)
190+
return False # default OFF
191+
192+
DEBUG_MODE = _resolve_debug_mode()
193+
194+
169195
# ── Cache Extended TTL (default ON — use 1h TTL for stable prefix) ──
170196
# When enabled, system prompt + tools get 1-hour cache TTL, while the
171197
# conversation tail keeps the default 5-minute TTL. This eliminates
@@ -533,6 +559,8 @@ def _rcfg(env_key, saved_key, default):
533559

534560
# Trading flag
535561
_mod.TRADING_ENABLED = _resolve_trading_enabled()
562+
# Debug mode flag
563+
_mod.DEBUG_MODE = _resolve_debug_mode()
536564

537565
# Model defaults (from model_defaults section)
538566
_md = _SAVED_CONFIG.get('model_defaults', {})

lib/fetch/utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ def _decode_bytes(raw, hint):
388388
'trello.com',
389389
'canva.com',
390390
'v0.dev',
391+
'volcengine.com',
391392
})
392393

393394
# Playwright 需要 JS 渲染的最小可提取文本长度阈值
@@ -412,6 +413,8 @@ def _looks_like_spa_shell(raw_html, extracted_text):
412413
判定为 SPA 空壳的条件 (需满足 至少一个):
413414
A) HTML 中包含典型 SPA 挂载点标记 (id="root"/"app"/__next 等) 且文本极少
414415
B) HTML > 2KB 但提取文本 < 100 字符 (大 HTML 却没内容, 强信号)
416+
C) <noscript> 中包含 "enable JavaScript" 且有 SPA 挂载点 (最强信号 —
417+
即使导航菜单贡献了较多文字, 真实内容仍需 JS 渲染, 如 volcengine.com)
415418
"""
416419
if not raw_html:
417420
return False
@@ -435,6 +438,29 @@ def _looks_like_spa_shell(raw_html, extracted_text):
435438
if html_len > 2000 and text_len < 100:
436439
return True
437440

441+
# C) <noscript> 中明确要求启用 JavaScript + SPA 挂载点 = 确定是 SPA
442+
# 很多 SPA 框架 (React/Vue/Angular/Modern.js) 在 <noscript> 中放置
443+
# "You need to enable JavaScript to run this app" 之类的提示。
444+
# 这种情况下即使 HTML 中有导航菜单等文字 (导致 text_len 较高),
445+
# 真实页面内容也必须靠 JS 渲染。只在有 SPA 挂载点时才触发,避免
446+
# 误判那些仅因增强功能而提示 JS 的非 SPA 页面。
447+
if has_spa_marker:
448+
# 搜索 <noscript> 块中的 JS-required 提示
449+
noscript_re = re.compile(r'<noscript[^>]*>(.*?)</noscript>', re.I | re.DOTALL)
450+
for m in noscript_re.finditer(html_str[:50000]):
451+
ns_text = m.group(1).lower()
452+
if any(kw in ns_text for kw in (
453+
'enable javascript', 'requires javascript',
454+
'javascript is required', 'javascript is disabled',
455+
'need to enable javascript', 'need javascript',
456+
'activate javascript', 'turn on javascript',
457+
'启用 javascript', '需要启用 javascript',
458+
'请启用 javascript', '开启 javascript',
459+
)):
460+
logger.debug('SPA noscript+marker detected (text=%d) — '
461+
'JS required message in <noscript>', text_len)
462+
return True
463+
438464
return False
439465

440466

lib/llm_client.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ def _is_stream_only_error(error_text: str) -> bool:
179179
is_gemini,
180180
is_glm,
181181
is_gpt,
182+
is_kimi,
182183
is_longcat,
183184
is_minimax,
184185
is_qwen,
@@ -636,6 +637,7 @@ def build_body(model, messages, *, max_tokens=128000, temperature=1.0,
636637
637638
Handles provider-specific parameters automatically:
638639
• Claude: thinking.type='adaptive', effort param, cache breakpoints
640+
• Kimi: thinking.type='enabled'/'disabled', fixed temp (1.0/0.6)
639641
• GLM: thinking.type='enabled', temperature clamped to (0, 1)
640642
• Doubao: thinking.type='enabled'/'disabled'
641643
• LongCat: enable_thinking flag, temperature adjustment
@@ -801,6 +803,27 @@ def build_body(model, messages, *, max_tokens=128000, temperature=1.0,
801803
else:
802804
body['thinking'] = {'type': 'disabled'}
803805
body['temperature'] = max(temperature, 0.01) if temperature else 0.7
806+
elif not _tf and is_kimi(model):
807+
# Moonshot Kimi (K2/K2.5) uses thinking.type format:
808+
# {"thinking": {"type": "enabled"}} — enables thinking
809+
# {"thinking": {"type": "disabled"}} — disables thinking
810+
# K2.5: temperature fixed at 1.0 (thinking) or 0.6 (non-thinking).
811+
# K2.5: top_p/n/presence_penalty/frequency_penalty are also fixed;
812+
# sending non-default values causes HTTP 400.
813+
# K2-thinking: thinking is always on, ignore disable request.
814+
# Reasoning output uses `reasoning_content` field (already handled).
815+
# Docs: https://platform.moonshot.ai/docs/guide/kimi-k2-5-quickstart
816+
_is_k2_thinking = 'k2-thinking' in model.lower() and 'turbo' not in model.lower()
817+
if _is_k2_thinking or thinking_enabled:
818+
body['thinking'] = {'type': 'enabled'}
819+
body['temperature'] = 1.0
820+
else:
821+
body['thinking'] = {'type': 'disabled'}
822+
body['temperature'] = 0.6
823+
# Remove parameters that K2.5 rejects with non-default values
824+
body.pop('top_p', None)
825+
body.pop('presence_penalty', None)
826+
body.pop('frequency_penalty', None)
804827
elif not _tf and is_minimax(model):
805828
# MiniMax M2.5/M2.7/M2.1: send reasoning_split=True so the API returns
806829
# thinking content in a separate reasoning_details field instead of

0 commit comments

Comments
 (0)