mirror of
https://github.com/TencentCloud/TencentDB-Agent-Memory
synced 2026-07-10 12:34:27 +00:00
feat(llm): add disableThinking option to suppress reasoning in extraction models (#228)
Support multiple inference engines and model providers via a strategy
enum so each receives its own thinking-disabling field in
chat-completion request bodies.
Strategies:
- "vllm" → chat_template_kwargs: { enable_thinking: false } (vLLM / SGLang)
- "deepseek" → enable_thinking: false (DeepSeek official API)
- "dashscope" → enable_thinking: false (Alibaba DashScope / Qwen)
- "openai" → reasoning_effort: "low" (OpenAI o-series, cannot fully disable)
- "anthropic" → thinking: { type: "disabled" } (Anthropic Claude)
- "kimi" → thinking: { type: "disabled" } (Kimi / Moonshot)
- "gemini" → thinking_config: { thinking_budget: 0 } (Google Gemini)
Defaults to false (no wrapper). Also accepts boolean true as a shorthand
for "vllm" for convenience.
Covered paths:
- StandaloneLLMRunner (OpenClaw plugin + gateway): llm.disableThinking,
wired through parseConfig, tdai-core, seed-runtime, and gateway config
(TDAI_LLM_DISABLE_THINKING env also accepts strategy names).
- Offload local mode (L1/L1.5/L2): separate offload.disableThinking.
The fetch wrapper lives in src/utils/no-think-fetch.ts with a
STRATEGY_TRANSFORMERS map for clean dispatch. StandaloneLLMRunner builds
it once in the constructor; LocalLlmClient caches it at construction
time and passes it through to callLlm().
Add vitest unit tests for all 7 strategies, normalization, validation,
embedding skip, and non-JSON tolerance (20 tests total).
Signed-off-by: jackson.jia <jiazhenghua0@gmail.com>
This commit is contained in:
@@ -7,6 +7,9 @@
|
||||
* Minimal config (zero config): {} — all fields have sensible defaults.
|
||||
*/
|
||||
|
||||
import type { DisableThinkingStrategy } from "./utils/no-think-fetch.js";
|
||||
import { normalizeDisableThinking } from "./utils/no-think-fetch.js";
|
||||
|
||||
// ============================
|
||||
// Type definitions
|
||||
// ============================
|
||||
@@ -203,6 +206,17 @@ export interface StandaloneLLMOverrideConfig {
|
||||
maxTokens: number;
|
||||
/** Request timeout in milliseconds (default: 120000). */
|
||||
timeoutMs: number;
|
||||
/**
|
||||
* Controls how thinking/reasoning is disabled for the LLM endpoint (default: false).
|
||||
* - `false`: no thinking-disabling wrapper (default)
|
||||
* - `"vllm"`: vLLM/SGLang — `chat_template_kwargs: { enable_thinking: false }`
|
||||
* - `"deepseek"`: DeepSeek official API — top-level `enable_thinking: false`
|
||||
* - `"dashscope"`: Alibaba DashScope (Qwen) — top-level `enable_thinking: false`
|
||||
* - `"openai"`: OpenAI o-series — `reasoning_effort: "low"` (cannot fully disable)
|
||||
* - `"anthropic"` / `"kimi"`: Anthropic Claude / Kimi (Moonshot) — `thinking: { type: "disabled" }`
|
||||
* - `"gemini"`: Google Gemini — `thinking_config: { thinking_budget: 0 }`
|
||||
*/
|
||||
disableThinking: DisableThinkingStrategy;
|
||||
}
|
||||
|
||||
/** Context Offload settings — controls multi-layer context compression. */
|
||||
@@ -222,6 +236,12 @@ export interface OffloadConfig {
|
||||
model?: string;
|
||||
/** LLM temperature (default: 0.2) */
|
||||
temperature: number;
|
||||
/**
|
||||
* Controls how thinking/reasoning is disabled for the offload local-mode LLM (default: false).
|
||||
* See `StandaloneLLMOverrideConfig.disableThinking` for the full list of strategies.
|
||||
* Applies only to `mode: "local"`.
|
||||
*/
|
||||
disableThinking: DisableThinkingStrategy;
|
||||
/** Force-trigger L1 when pending tool pairs >= this threshold (default: 4) */
|
||||
forceTriggerThreshold: number;
|
||||
/** Custom data directory (absolute path). Default: ~/.openclaw/context-offload */
|
||||
@@ -459,6 +479,7 @@ export function parseConfig(raw: Record<string, unknown> | undefined): MemoryTda
|
||||
mode: offloadMode,
|
||||
model: optStr(offloadGroup, "model"),
|
||||
temperature: num(offloadGroup, "temperature") ?? 0.2,
|
||||
disableThinking: normalizeDisableThinking(boolOrStr(offloadGroup, "disableThinking")),
|
||||
forceTriggerThreshold: num(offloadGroup, "forceTriggerThreshold") ?? 4,
|
||||
dataDir: optStr(offloadGroup, "dataDir"),
|
||||
defaultContextWindow: num(offloadGroup, "defaultContextWindow") ?? 200000,
|
||||
@@ -561,6 +582,7 @@ export function parseConfig(raw: Record<string, unknown> | undefined): MemoryTda
|
||||
model: str(llmGroup, "model") ?? "gpt-4o",
|
||||
maxTokens: num(llmGroup, "maxTokens") ?? 4096,
|
||||
timeoutMs: num(llmGroup, "timeoutMs") ?? 120_000,
|
||||
disableThinking: normalizeDisableThinking(boolOrStr(llmGroup, "disableThinking")),
|
||||
};
|
||||
})(),
|
||||
offload,
|
||||
@@ -597,6 +619,14 @@ function bool(src: Record<string, unknown>, key: string): boolean | undefined {
|
||||
return typeof v === "boolean" ? v : undefined;
|
||||
}
|
||||
|
||||
/** Read a field that may be boolean or string. */
|
||||
function boolOrStr(src: Record<string, unknown>, key: string): boolean | string | undefined {
|
||||
const v = src[key];
|
||||
if (typeof v === "boolean") return v;
|
||||
if (typeof v === "string" && v.trim()) return v.trim();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function strArray(src: Record<string, unknown>, key: string): string[] | undefined {
|
||||
const v = src[key];
|
||||
if (!Array.isArray(v)) return undefined;
|
||||
|
||||
Reference in New Issue
Block a user