From de2c5db39855e7e619c8e2d6098ad30b599f7084 Mon Sep 17 00:00:00 2001 From: Patrick Erichsen Date: Wed, 23 Sep 2026 22:17:13 -0700 Subject: [PATCH] fix(skill-scan): forward optional reasoning effort to the model API --- skill-scan/README.md | 1 + skill-scan/README_zh.md | 1 + skill-scan/pytests/test_llm_request.py | 24 ++++++++++++++++++++++++ skill-scan/skill_scan/utils/llm.py | 6 ++++++ 4 files changed, 32 insertions(+) diff --git a/skill-scan/README.md b/skill-scan/README.md index 1a7cf86d0..03b9ddea4 100644 --- a/skill-scan/README.md +++ b/skill-scan/README.md @@ -144,6 +144,7 @@ Key environment variables: | `LLM_MODEL` / `OPENAI_MODEL` | Default model | `deepseek-v4-flash` | | `LLM_BASE_URL` / `OPENAI_BASE_URL` | Default base URL | `https://openrouter.ai/api/v1` | | `DEFAULT_MODEL_CONTEXT_WINDOW` | Main model context window | `128000` | +| `REASONING_EFFORT` | Optional reasoning effort (for example, `high`); supported values depend on the model and provider. Unset or blank values omit the API parameter. | Unset | | `LOG_LEVEL` | Log level | `INFO` | --- diff --git a/skill-scan/README_zh.md b/skill-scan/README_zh.md index 0dac273f5..626159090 100644 --- a/skill-scan/README_zh.md +++ b/skill-scan/README_zh.md @@ -144,6 +144,7 @@ asyncio.run(run()) | `LLM_MODEL` / `OPENAI_MODEL` | 默认模型 | `deepseek-v4-flash` | | `LLM_BASE_URL` / `OPENAI_BASE_URL` | 默认 Base URL | `https://openrouter.ai/api/v1` | | `DEFAULT_MODEL_CONTEXT_WINDOW` | 主模型上下文窗口 | `128000` | +| `REASONING_EFFORT` | 可选推理强度(例如 `high`);支持的值取决于模型和服务提供商。未设置或为空白时不发送该 API 参数。 | 未设置 | | `LOG_LEVEL` | 日志级别 | `INFO` | --- diff --git a/skill-scan/pytests/test_llm_request.py b/skill-scan/pytests/test_llm_request.py index 4c1ff6734..15f3999c8 100644 --- a/skill-scan/pytests/test_llm_request.py +++ b/skill-scan/pytests/test_llm_request.py @@ -6,6 +6,30 @@ from skill_scan.utils.llm import LLM +@pytest.mark.parametrize( + ("setting", "expected"), + [("high", "high"), (" medium ", "medium"), (None, None), ("", None), (" \t ", None)], +) +def test_chat_request_uses_optional_reasoning_effort(monkeypatch, setting, expected): + if setting is None: + monkeypatch.delenv("REASONING_EFFORT", raising=False) + else: + monkeypatch.setenv("REASONING_EFFORT", setting) + create = Mock(return_value=[]) + llm = object.__new__(LLM) + llm.model = "test-reasoning-model" + llm.client = SimpleNamespace( + chat=SimpleNamespace(completions=SimpleNamespace(create=create)) + ) + + llm.chat_stream([{"role": "user", "content": "test"}]) + + if expected is None: + assert "reasoning_effort" not in create.call_args.kwargs + else: + assert create.call_args.kwargs["reasoning_effort"] == expected + + def test_chat_request_omits_temperature(): create = Mock(return_value=[]) llm = object.__new__(LLM) diff --git a/skill-scan/skill_scan/utils/llm.py b/skill-scan/skill_scan/utils/llm.py index e4dc57f8e..e36bb57eb 100644 --- a/skill-scan/skill_scan/utils/llm.py +++ b/skill-scan/skill_scan/utils/llm.py @@ -22,6 +22,7 @@ import openai +from skill_scan.utils.config import get_env from skill_scan.utils.loging import logger @@ -74,11 +75,16 @@ def chat(self, message: list[dict], p=False, ret_usage=False) -> str | tuple[str def chat_stream(self, message: list[dict]) -> tuple[str, dict]: started = time.monotonic() + request_options = {} + reasoning_effort = (get_env("REASONING_EFFORT") or "").strip() + if reasoning_effort: + request_options["reasoning_effort"] = reasoning_effort response = self.client.chat.completions.create( model=self.model, messages=message, stream=True, stream_options={"include_usage": True}, + **request_options, ) ret = ""