/ agent / lmstudio_reasoning.py
lmstudio_reasoning.py
 1  """LM Studio reasoning-effort resolution shared by the chat-completions
 2  transport and run_agent's iteration-limit summary path.
 3  
 4  LM Studio publishes per-model ``capabilities.reasoning.allowed_options`` (e.g.
 5  ``["off","on"]`` for toggle-style models, ``["off","minimal","low"]`` for
 6  graduated models). We map the user's ``reasoning_config`` onto LM Studio's
 7  OpenAI-compatible vocabulary, then clamp against the model's allowed set so
 8  the server doesn't 400 on an unsupported effort.
 9  """
10  
11  from __future__ import annotations
12  
13  from typing import List, Optional
14  
15  # LM Studio accepts these top-level reasoning_effort values via its
16  # OpenAI-compatible chat.completions endpoint.
17  _LM_VALID_EFFORTS = {"none", "minimal", "low", "medium", "high", "xhigh"}
18  
19  # Toggle-style models publish allowed_options as ["off","on"] in /api/v1/models.
20  # Map them onto the OpenAI-compatible request vocabulary.
21  _LM_EFFORT_ALIASES = {"off": "none", "on": "medium"}
22  
23  
24  def resolve_lmstudio_effort(
25      reasoning_config: Optional[dict],
26      allowed_options: Optional[List[str]],
27  ) -> Optional[str]:
28      """Return the ``reasoning_effort`` string to send to LM Studio, or ``None``.
29  
30      ``None`` means "omit the field": the user picked a level the model can't
31      honor, so let LM Studio fall back to the model's declared default rather
32      than silently substituting a different effort. When ``allowed_options`` is
33      falsy (probe failed), skip clamping and send the resolved effort anyway.
34      """
35      effort = "medium"
36      if reasoning_config and isinstance(reasoning_config, dict):
37          if reasoning_config.get("enabled") is False:
38              effort = "none"
39          else:
40              raw = (reasoning_config.get("effort") or "").strip().lower()
41              raw = _LM_EFFORT_ALIASES.get(raw, raw)
42              if raw in _LM_VALID_EFFORTS:
43                  effort = raw
44      if allowed_options:
45          allowed = {_LM_EFFORT_ALIASES.get(opt, opt) for opt in allowed_options}
46          if effort not in allowed:
47              return None
48      return effort