mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-20 15:33:54 +00:00
feat: configure X Search reasoning effort
This commit is contained in:
parent
0144743b21
commit
5befa15aba
5 changed files with 87 additions and 0 deletions
|
|
@ -3303,6 +3303,9 @@ DEFAULT_CONFIG = {
|
|||
# recommended default; any Grok model with x_search tool
|
||||
# access works.
|
||||
"model": "grok-4.5",
|
||||
# Optional reasoning effort sent to xAI Responses API models that
|
||||
# support it. Leave null to preserve the selected model's default.
|
||||
"reasoning_effort": None,
|
||||
# Request timeout in seconds (minimum 30). x_search can take
|
||||
# 60-120s for complex queries — the default is generous.
|
||||
"timeout_seconds": 180,
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ def test_x_search_posts_responses_request(monkeypatch):
|
|||
assert captured["headers"]["User-Agent"] == f"Hermes-Agent/{__version__}"
|
||||
assert captured["json"]["model"] == "grok-4.5"
|
||||
assert captured["json"]["store"] is False
|
||||
assert "reasoning" not in captured["json"]
|
||||
assert tool_def["type"] == "x_search"
|
||||
assert tool_def["allowed_x_handles"] == ["xai", "grok"]
|
||||
assert tool_def["from_date"] == "2026-04-01"
|
||||
|
|
@ -424,6 +425,49 @@ def test_x_search_honors_config_model_and_timeout(monkeypatch, tmp_path):
|
|||
assert captured["timeout"] == 45
|
||||
|
||||
|
||||
def test_x_search_honors_config_reasoning_effort(monkeypatch):
|
||||
"""Configured reasoning effort reaches the xAI Responses request."""
|
||||
from tools.x_search_tool import x_search_tool
|
||||
|
||||
monkeypatch.setenv("XAI_API_KEY", "xai-test-key")
|
||||
monkeypatch.setattr(
|
||||
"tools.x_search_tool._load_x_search_config",
|
||||
lambda: {"reasoning_effort": "low", "retries": 0},
|
||||
)
|
||||
captured = {}
|
||||
|
||||
def _fake_post(url, headers=None, json=None, timeout=None):
|
||||
assert json is not None
|
||||
captured["reasoning"] = json.get("reasoning")
|
||||
return _FakeResponse({"output_text": "Reasoning configured."})
|
||||
|
||||
monkeypatch.setattr("requests.post", _fake_post)
|
||||
|
||||
result = json.loads(x_search_tool(query="anything"))
|
||||
|
||||
assert result["success"] is True
|
||||
assert captured["reasoning"] == {"effort": "low"}
|
||||
|
||||
|
||||
def test_x_search_rejects_invalid_config_reasoning_effort(monkeypatch):
|
||||
"""A typo must fail closed instead of silently using xAI's default effort."""
|
||||
from tools.x_search_tool import x_search_tool
|
||||
|
||||
monkeypatch.setenv("XAI_API_KEY", "xai-test-key")
|
||||
monkeypatch.setattr(
|
||||
"tools.x_search_tool._load_x_search_config",
|
||||
lambda: {"reasoning_effort": "minimal"},
|
||||
)
|
||||
_no_post_allowed(monkeypatch)
|
||||
|
||||
result = json.loads(x_search_tool(query="anything"))
|
||||
|
||||
assert result["error"] == (
|
||||
"x_search.reasoning_effort must be one of: low, medium, high, xhigh "
|
||||
"(got 'minimal')"
|
||||
)
|
||||
|
||||
|
||||
def test_x_search_registered_in_registry_with_check_fn():
|
||||
"""The tool is registered under the x_search toolset with the gating check_fn."""
|
||||
import tools.x_search_tool # noqa: F401 — ensures registration runs
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ DEFAULT_XAI_BASE_URL = "https://api.x.ai/v1"
|
|||
DEFAULT_X_SEARCH_MODEL = "grok-4.5"
|
||||
DEFAULT_X_SEARCH_TIMEOUT_SECONDS = 180
|
||||
DEFAULT_X_SEARCH_RETRIES = 2
|
||||
X_SEARCH_REASONING_EFFORTS = ("low", "medium", "high", "xhigh")
|
||||
MAX_HANDLES = 10
|
||||
|
||||
|
||||
|
|
@ -80,6 +81,22 @@ def _get_x_search_model() -> str:
|
|||
return (str(cfg.get("model") or "").strip() or DEFAULT_X_SEARCH_MODEL)
|
||||
|
||||
|
||||
def _get_x_search_reasoning_effort() -> Optional[str]:
|
||||
cfg = _load_x_search_config()
|
||||
raw_value = cfg.get("reasoning_effort")
|
||||
if raw_value is None or not str(raw_value).strip():
|
||||
return None
|
||||
|
||||
effort = str(raw_value).strip().lower()
|
||||
if effort not in X_SEARCH_REASONING_EFFORTS:
|
||||
allowed = ", ".join(X_SEARCH_REASONING_EFFORTS)
|
||||
raise ValueError(
|
||||
f"x_search.reasoning_effort must be one of: {allowed} "
|
||||
f"(got {raw_value!r})"
|
||||
)
|
||||
return effort
|
||||
|
||||
|
||||
def _get_x_search_timeout_seconds() -> int:
|
||||
cfg = _load_x_search_config()
|
||||
raw_value = cfg.get("timeout_seconds", DEFAULT_X_SEARCH_TIMEOUT_SECONDS)
|
||||
|
|
@ -299,6 +316,11 @@ def x_search_tool(
|
|||
except ValueError as exc:
|
||||
return tool_error(str(exc))
|
||||
|
||||
try:
|
||||
reasoning_effort = _get_x_search_reasoning_effort()
|
||||
except ValueError as exc:
|
||||
return tool_error(str(exc))
|
||||
|
||||
tool_def: Dict[str, Any] = {"type": "x_search"}
|
||||
if allowed:
|
||||
tool_def["allowed_x_handles"] = allowed
|
||||
|
|
@ -324,6 +346,8 @@ def x_search_tool(
|
|||
"tools": [tool_def],
|
||||
"store": False,
|
||||
}
|
||||
if reasoning_effort:
|
||||
payload["reasoning"] = {"effort": reasoning_effort}
|
||||
|
||||
timeout_seconds = _get_x_search_timeout_seconds()
|
||||
max_retries = _get_x_search_retries()
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ x_search:
|
|||
# with x_search tool access works.
|
||||
model: grok-4.5
|
||||
|
||||
# Optional reasoning effort: low, medium, high, or xhigh. When omitted,
|
||||
# the selected model's default applies. xhigh is supported only by
|
||||
# models that document it, such as grok-4.20-multi-agent.
|
||||
reasoning_effort: low
|
||||
|
||||
# Request timeout in seconds. x_search can take 60–120s for
|
||||
# complex queries — the default is generous. Minimum: 30.
|
||||
timeout_seconds: 180
|
||||
|
|
@ -63,6 +68,10 @@ x_search:
|
|||
retries: 2
|
||||
```
|
||||
|
||||
`reasoning_effort` is sent to the xAI Responses API as
|
||||
`reasoning: {effort: ...}`. Leave it unset for models that do not support
|
||||
configurable reasoning. Invalid values fail before an API request is made.
|
||||
|
||||
## Tool parameters
|
||||
|
||||
The agent calls `x_search` with these arguments:
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@ x_search:
|
|||
# x_search 工具访问权限的 Grok 模型均可使用。
|
||||
model: grok-4.5
|
||||
|
||||
# 可选推理强度:low、medium、high 或 xhigh。省略时使用所选模型的默认值。
|
||||
# xhigh 仅适用于明确支持它的模型,例如 grok-4.20-multi-agent。
|
||||
reasoning_effort: low
|
||||
|
||||
# 请求超时时间(秒)。复杂查询的 x_search 可能需要 60–120 秒,
|
||||
# 默认值较为宽松。最小值:30。
|
||||
timeout_seconds: 180
|
||||
|
|
@ -59,6 +63,9 @@ x_search:
|
|||
retries: 2
|
||||
```
|
||||
|
||||
`reasoning_effort` 会以 `reasoning: {effort: ...}` 的形式发送到 xAI
|
||||
Responses API。不支持可配置推理的模型应留空。无效值会在发起 API 请求前失败。
|
||||
|
||||
## 工具参数
|
||||
|
||||
agent 调用 `x_search` 时使用以下参数:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue