feat: add reasoning_effort configuration support for Doubao/GPT-5 models (#947)

* feat: Add reasoning effort configuration support

* Add `reasoning_effort` parameter to model config and agent initialization
* Support reasoning effort levels (minimal/low/medium/high) for Doubao/GPT-5 models
* Add UI controls in input box for reasoning effort selection
* Update doubao-seed-1.8 example config with reasoning effort support

Fixes & Cleanup:
* Ensure UTF-8 encoding for file operations
* Remove unused imports

* fix: set reasoning_effort to None for unsupported models

* fix: unit test error

* Update frontend/src/components/workspace/input-box.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
Zhiyunyao
2026-03-02 20:49:41 +08:00
committed by GitHub
parent e399d09e8f
commit a138d5388a
21 changed files with 212 additions and 33 deletions

View File

@@ -256,6 +256,7 @@ def make_lead_agent(config: RunnableConfig):
from src.tools import get_available_tools
thinking_enabled = config.get("configurable", {}).get("thinking_enabled", True)
reasoning_effort = config.get("configurable", {}).get("reasoning_effort", None)
requested_model_name = config.get("configurable", {}).get("model_name") or config.get("configurable", {}).get("model")
model_name = _resolve_model_name(requested_model_name)
if model_name is None:
@@ -274,8 +275,9 @@ def make_lead_agent(config: RunnableConfig):
thinking_enabled = False
logger.info(
"thinking_enabled: %s, model_name: %s, is_plan_mode: %s, subagent_enabled: %s, max_concurrent_subagents: %s",
"thinking_enabled: %s, reasoning_effort: %s, model_name: %s, is_plan_mode: %s, subagent_enabled: %s, max_concurrent_subagents: %s",
thinking_enabled,
reasoning_effort,
model_name,
is_plan_mode,
subagent_enabled,
@@ -289,13 +291,14 @@ def make_lead_agent(config: RunnableConfig):
{
"model_name": model_name or "default",
"thinking_enabled": thinking_enabled,
"reasoning_effort": reasoning_effort,
"is_plan_mode": is_plan_mode,
"subagent_enabled": subagent_enabled,
}
)
return create_agent(
model=create_chat_model(name=model_name, thinking_enabled=thinking_enabled),
model=create_chat_model(name=model_name, thinking_enabled=thinking_enabled, reasoning_effort=reasoning_effort),
tools=get_available_tools(model_name=model_name, subagent_enabled=subagent_enabled),
middleware=_build_middlewares(config, model_name=model_name),
system_prompt=apply_prompt_template(subagent_enabled=subagent_enabled, max_concurrent_subagents=max_concurrent_subagents),

View File

@@ -400,6 +400,7 @@ class DeerFlowClient:
"display_name": getattr(model, "display_name", None),
"description": getattr(model, "description", None),
"supports_thinking": getattr(model, "supports_thinking", False),
"supports_reasoning_effort": getattr(model, "supports_reasoning_effort", False),
}
for model in self._app_config.models
]
@@ -458,6 +459,7 @@ class DeerFlowClient:
"display_name": getattr(model, "display_name", None),
"description": getattr(model, "description", None),
"supports_thinking": getattr(model, "supports_thinking", False),
"supports_reasoning_effort": getattr(model, "supports_reasoning_effort", False),
}
# ------------------------------------------------------------------

View File

@@ -72,7 +72,7 @@ class AppConfig(BaseModel):
AppConfig: The loaded config.
"""
resolved_path = cls.resolve_config_path(config_path)
with open(resolved_path) as f:
with open(resolved_path, encoding="utf-8") as f:
config_data = yaml.safe_load(f)
config_data = cls.resolve_env_variables(config_data)

View File

@@ -133,7 +133,7 @@ class ExtensionsConfig(BaseModel):
# Return empty config if extensions config file is not found
return cls(mcp_servers={}, skills={})
with open(resolved_path) as f:
with open(resolved_path, encoding="utf-8") as f:
config_data = json.load(f)
cls.resolve_env_variables(config_data)

View File

@@ -14,6 +14,7 @@ class ModelConfig(BaseModel):
model: str = Field(..., description="Model name")
model_config = ConfigDict(extra="allow")
supports_thinking: bool = Field(default_factory=lambda: False, description="Whether the model supports thinking")
supports_reasoning_effort: bool = Field(default_factory=lambda: False, description="Whether the model supports reasoning effort")
when_thinking_enabled: dict | None = Field(
default_factory=lambda: None,
description="Extra settings to be passed to the model when thinking is enabled",

View File

@@ -13,6 +13,7 @@ class ModelResponse(BaseModel):
display_name: str | None = Field(None, description="Human-readable name")
description: str | None = Field(None, description="Model description")
supports_thinking: bool = Field(default=False, description="Whether model supports thinking mode")
supports_reasoning_effort: bool = Field(default=False, description="Whether model supports reasoning effort")
class ModelsListResponse(BaseModel):
@@ -63,6 +64,7 @@ async def list_models() -> ModelsListResponse:
display_name=model.display_name,
description=model.description,
supports_thinking=model.supports_thinking,
supports_reasoning_effort=model.supports_reasoning_effort,
)
for model in config.models
]
@@ -107,4 +109,5 @@ async def get_model(model_name: str) -> ModelResponse:
display_name=model.display_name,
description=model.description,
supports_thinking=model.supports_thinking,
supports_reasoning_effort=model.supports_reasoning_effort,
)

View File

@@ -32,6 +32,7 @@ def create_chat_model(name: str | None = None, thinking_enabled: bool = False, *
"display_name",
"description",
"supports_thinking",
"supports_reasoning_effort",
"when_thinking_enabled",
"supports_vision",
},
@@ -40,6 +41,11 @@ def create_chat_model(name: str | None = None, thinking_enabled: bool = False, *
if not model_config.supports_thinking:
raise ValueError(f"Model {name} does not support thinking. Set `supports_thinking` to true in the `config.yaml` to enable thinking.") from None
model_settings_from_config.update(model_config.when_thinking_enabled)
if not thinking_enabled and model_config.when_thinking_enabled and model_config.when_thinking_enabled.get("extra_body", {}).get("thinking", {}).get("type"):
kwargs.update({"extra_body": {"thinking": {"type": "disabled"}}})
kwargs.update({"reasoning_effort": "minimal"})
if not model_config.supports_reasoning_effort:
kwargs.update({"reasoning_effort": None})
model_instance = model_class(**kwargs, **model_settings_from_config)
if is_tracing_enabled():

View File

@@ -1,7 +1,4 @@
from importlib import import_module
from typing import TypeVar
T = TypeVar("T")
def resolve_variable[T](