black-yt commited on
Commit
a3e8543
·
1 Parent(s): 1798fcc

Sync provider sampling omit runtime

Browse files
README.md CHANGED
@@ -162,8 +162,9 @@ Configure these as Hugging Face Space secrets before starting the app:
162
  | `RH_SPACE_RETENTION_SECONDS` | `21600` | Delete inactive runs older than this many seconds. |
163
  | `RH_SPACE_MAX_RUNS` | `40` | Keep at most this many inactive runs. |
164
  | `RH_SPACE_CLEANUP_INTERVAL_SECONDS` | `900` | Background cleanup interval. |
165
- | `WEBFETCH_TIMEOUT_SECONDS` | `180` | Overall timeout for one WebFetch tool call. |
166
- | `WEBFETCH_MAX_CHARS` | `30000` | Hard maximum characters returned by one URL-only WebFetch call. |
 
167
  | `RH_COLLECTION_ENABLED` | `true` | Automatically collect completed hosted runs. |
168
  | `RH_COLLECTION_DATASET_REPO` | `InternScience/ResearchHarness-Data` | Dataset repo that receives trajectory PRs. |
169
  | `RH_COLLECTION_BATCH_SIZE` | `5` | Create one dataset PR after this many collected runs. |
 
162
  | `RH_SPACE_RETENTION_SECONDS` | `21600` | Delete inactive runs older than this many seconds. |
163
  | `RH_SPACE_MAX_RUNS` | `40` | Keep at most this many inactive runs. |
164
  | `RH_SPACE_CLEANUP_INTERVAL_SECONDS` | `900` | Background cleanup interval. |
165
+ | `WEBFETCH_TIMEOUT_SECONDS` | `300` | Overall timeout for one WebFetch tool call. |
166
+ | `WEBFETCH_MAX_CHARS` | `16384` | Hard maximum characters returned by one URL-only WebFetch call. |
167
+ | `OMIT_GENERATE_PARAMS` | empty | Comma-separated sampling params not sent to providers that reject them, for example `presence_penalty`. |
168
  | `RH_COLLECTION_ENABLED` | `true` | Automatically collect completed hosted runs. |
169
  | `RH_COLLECTION_DATASET_REPO` | `InternScience/ResearchHarness-Data` | Dataset repo that receives trajectory PRs. |
170
  | `RH_COLLECTION_BATCH_SIZE` | `5` | Create one dataset PR after this many collected runs. |
VERSION CHANGED
@@ -1 +1 @@
1
- v0.0.51
 
1
+ v0.0.52
agent_base/provider_compat.py CHANGED
@@ -1,8 +1,29 @@
1
  import re
 
2
  from typing import Any
3
 
4
 
5
  _MODEL_NAME_SPLIT_RE = re.compile(r"[/:\s]+")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
 
8
  def model_rejects_sampling_params(model_name: str) -> bool:
@@ -28,12 +49,18 @@ def apply_sampling_params(
28
  temperature: Any = None,
29
  top_p: Any = None,
30
  presence_penalty: Any = None,
 
31
  ) -> None:
 
32
  if model_rejects_sampling_params(model_name):
33
  return
34
- if temperature is not None:
35
  request_kwargs["temperature"] = temperature
36
- if top_p is not None:
37
  request_kwargs["top_p"] = top_p
38
- if presence_penalty is not None and not model_rejects_presence_penalty(model_name):
 
 
 
 
39
  request_kwargs["presence_penalty"] = presence_penalty
 
1
  import re
2
+ from collections.abc import Iterable
3
  from typing import Any
4
 
5
 
6
  _MODEL_NAME_SPLIT_RE = re.compile(r"[/:\s]+")
7
+ OMITTABLE_GENERATE_PARAMS = frozenset({"temperature", "top_p", "presence_penalty"})
8
+
9
+
10
+ def normalize_omit_generate_params(value: Any) -> tuple[str, ...]:
11
+ if value is None or value == "":
12
+ return ()
13
+ if isinstance(value, str):
14
+ parts = [part.strip() for part in value.split(",")]
15
+ elif isinstance(value, dict):
16
+ raise ValueError("omit_generate_params must be a string or a sequence of strings.")
17
+ elif isinstance(value, Iterable):
18
+ parts = [str(part).strip() for part in value]
19
+ else:
20
+ raise ValueError("omit_generate_params must be a string or a sequence of strings.")
21
+ normalized = tuple(part for part in parts if part)
22
+ unknown = sorted(set(normalized) - OMITTABLE_GENERATE_PARAMS)
23
+ if unknown:
24
+ allowed = ", ".join(sorted(OMITTABLE_GENERATE_PARAMS))
25
+ raise ValueError(f"Unsupported omit_generate_params values: {unknown}. Allowed values: {allowed}.")
26
+ return normalized
27
 
28
 
29
  def model_rejects_sampling_params(model_name: str) -> bool:
 
49
  temperature: Any = None,
50
  top_p: Any = None,
51
  presence_penalty: Any = None,
52
+ omit_generate_params: Any = None,
53
  ) -> None:
54
+ omitted = set(normalize_omit_generate_params(omit_generate_params))
55
  if model_rejects_sampling_params(model_name):
56
  return
57
+ if temperature is not None and "temperature" not in omitted:
58
  request_kwargs["temperature"] = temperature
59
+ if top_p is not None and "top_p" not in omitted:
60
  request_kwargs["top_p"] = top_p
61
+ if (
62
+ presence_penalty is not None
63
+ and "presence_penalty" not in omitted
64
+ and not model_rejects_presence_penalty(model_name)
65
+ ):
66
  request_kwargs["presence_penalty"] = presence_penalty
agent_base/react_agent.py CHANGED
@@ -16,7 +16,7 @@ from agent_base.base import BaseAgent
16
  from agent_base.console_utils import ConsoleEventPrinter
17
  from agent_base.context_compact import compact_messages, should_compact_messages
18
  from agent_base.model_profiles import resolve_model_profile
19
- from agent_base.provider_compat import apply_sampling_params
20
  from agent_base.prompt import composed_system_prompt
21
  from agent_base.session_state import AgentSessionState, CompactionRecord, persist_session_state, resolve_session_state_path
22
  from agent_base.trace_utils import FlatTraceWriter
@@ -632,10 +632,17 @@ def image_context_trace_text(result: Any) -> str:
632
  return text
633
 
634
 
635
- def default_llm_config(model_name: Optional[str] = None, extra_body: Optional[dict[str, Any]] = None) -> dict:
 
 
 
 
636
  selected_model = str(model_name or "").strip() or default_model_name()
637
  if extra_body is not None and not isinstance(extra_body, dict):
638
  raise ValueError("extra_body must be a dict.")
 
 
 
639
  config = {
640
  "model": selected_model,
641
  "api_key": os.environ.get("API_KEY", "EMPTY"),
@@ -656,6 +663,8 @@ def default_llm_config(model_name: Optional[str] = None, extra_body: Optional[di
656
  "presence_penalty": float(os.environ.get("PRESENCE_PENALTY", str(DEFAULT_PRESENCE_PENALTY))),
657
  },
658
  }
 
 
659
  if extra_body:
660
  config["extra_body"] = dict(extra_body)
661
  return config
@@ -751,7 +760,14 @@ class MultiTurnReactAgent(BaseAgent):
751
  self.tool_map = {tool_name: tool_registry[tool_name] for tool_name in requested_tools}
752
  self.tool_names = list(self.tool_map.keys())
753
  self.model = str(llm["model"])
754
- self.llm_generate_cfg = llm["generate_cfg"]
 
 
 
 
 
 
 
755
  self.trace_dir = Path(trace_dir) if trace_dir else None
756
  self.trace_path: Optional[Path] = None
757
  self.session_state_path: Optional[Path] = None
@@ -837,6 +853,7 @@ class MultiTurnReactAgent(BaseAgent):
837
  if presence_penalty is not None
838
  else self.llm_generate_cfg.get("presence_penalty", 1.1)
839
  ),
 
840
  )
841
  if self.llm_extra_body:
842
  request_kwargs["extra_body"] = dict(self.llm_extra_body)
@@ -1578,6 +1595,17 @@ def _parse_cli_args(
1578
  metavar="JSON",
1579
  help="Provider-specific OpenAI-compatible request extra_body JSON object.",
1580
  )
 
 
 
 
 
 
 
 
 
 
 
1581
  args = parser.parse_args(argv)
1582
  if args.tool_names and args.extra_tools:
1583
  raise ValueError("--tool defines the complete tool set and cannot be combined with --extra-tool.")
@@ -1590,6 +1618,9 @@ def _parse_cli_args(
1590
  if not isinstance(parsed_extra_body, dict):
1591
  raise ValueError("--llm-extra-body-json must be a JSON object.")
1592
  llm_extra_body = parsed_extra_body
 
 
 
1593
 
1594
  prompt_text = ""
1595
  if args.prompt_file:
@@ -1611,6 +1642,7 @@ def _parse_cli_args(
1611
  validate_named_tools(args.tool_names) if args.tool_names else [],
1612
  resolve_extra_tool_names(args.extra_tools),
1613
  llm_extra_body,
 
1614
  )
1615
 
1616
 
@@ -1629,6 +1661,7 @@ def main(argv: Optional[list[str]] = None) -> int:
1629
  tool_names,
1630
  extra_tools,
1631
  llm_extra_body,
 
1632
  ) = _parse_cli_args(argv or sys.argv[1:])
1633
  agent_cls = resolve_agent_class_for_role_prompt_files(role_prompt_files)
1634
  forbidden_tools = set(getattr(agent_cls, "forbidden_tool_names", set()))
@@ -1644,7 +1677,7 @@ def main(argv: Optional[list[str]] = None) -> int:
1644
  if extra_tools
1645
  else None
1646
  ),
1647
- llm=default_llm_config(extra_body=llm_extra_body),
1648
  trace_dir=trace_dir,
1649
  role_prompt=role_prompt or None,
1650
  )
 
16
  from agent_base.console_utils import ConsoleEventPrinter
17
  from agent_base.context_compact import compact_messages, should_compact_messages
18
  from agent_base.model_profiles import resolve_model_profile
19
+ from agent_base.provider_compat import apply_sampling_params, normalize_omit_generate_params
20
  from agent_base.prompt import composed_system_prompt
21
  from agent_base.session_state import AgentSessionState, CompactionRecord, persist_session_state, resolve_session_state_path
22
  from agent_base.trace_utils import FlatTraceWriter
 
632
  return text
633
 
634
 
635
+ def default_llm_config(
636
+ model_name: Optional[str] = None,
637
+ extra_body: Optional[dict[str, Any]] = None,
638
+ omit_generate_params: Optional[str | Sequence[str]] = None,
639
+ ) -> dict:
640
  selected_model = str(model_name or "").strip() or default_model_name()
641
  if extra_body is not None and not isinstance(extra_body, dict):
642
  raise ValueError("extra_body must be a dict.")
643
+ resolved_omit_generate_params = normalize_omit_generate_params(
644
+ omit_generate_params if omit_generate_params is not None else os.environ.get("OMIT_GENERATE_PARAMS")
645
+ )
646
  config = {
647
  "model": selected_model,
648
  "api_key": os.environ.get("API_KEY", "EMPTY"),
 
663
  "presence_penalty": float(os.environ.get("PRESENCE_PENALTY", str(DEFAULT_PRESENCE_PENALTY))),
664
  },
665
  }
666
+ if resolved_omit_generate_params:
667
+ config["generate_cfg"]["omit_generate_params"] = resolved_omit_generate_params
668
  if extra_body:
669
  config["extra_body"] = dict(extra_body)
670
  return config
 
760
  self.tool_map = {tool_name: tool_registry[tool_name] for tool_name in requested_tools}
761
  self.tool_names = list(self.tool_map.keys())
762
  self.model = str(llm["model"])
763
+ self.llm_generate_cfg = dict(llm["generate_cfg"])
764
+ resolved_omit_generate_params = normalize_omit_generate_params(
765
+ self.llm_generate_cfg.get("omit_generate_params")
766
+ )
767
+ if resolved_omit_generate_params:
768
+ self.llm_generate_cfg["omit_generate_params"] = resolved_omit_generate_params
769
+ else:
770
+ self.llm_generate_cfg.pop("omit_generate_params", None)
771
  self.trace_dir = Path(trace_dir) if trace_dir else None
772
  self.trace_path: Optional[Path] = None
773
  self.session_state_path: Optional[Path] = None
 
853
  if presence_penalty is not None
854
  else self.llm_generate_cfg.get("presence_penalty", 1.1)
855
  ),
856
+ omit_generate_params=self.llm_generate_cfg.get("omit_generate_params"),
857
  )
858
  if self.llm_extra_body:
859
  request_kwargs["extra_body"] = dict(self.llm_extra_body)
 
1595
  metavar="JSON",
1596
  help="Provider-specific OpenAI-compatible request extra_body JSON object.",
1597
  )
1598
+ parser.add_argument(
1599
+ "--omit-generate-param",
1600
+ action="append",
1601
+ default=[],
1602
+ dest="omit_generate_params",
1603
+ metavar="NAME",
1604
+ help=(
1605
+ "Do not send one default sampling parameter to the provider. "
1606
+ "Allowed: temperature, top_p, presence_penalty. May be passed multiple times."
1607
+ ),
1608
+ )
1609
  args = parser.parse_args(argv)
1610
  if args.tool_names and args.extra_tools:
1611
  raise ValueError("--tool defines the complete tool set and cannot be combined with --extra-tool.")
 
1618
  if not isinstance(parsed_extra_body, dict):
1619
  raise ValueError("--llm-extra-body-json must be a JSON object.")
1620
  llm_extra_body = parsed_extra_body
1621
+ omit_generate_params = (
1622
+ normalize_omit_generate_params(args.omit_generate_params) if args.omit_generate_params else None
1623
+ )
1624
 
1625
  prompt_text = ""
1626
  if args.prompt_file:
 
1642
  validate_named_tools(args.tool_names) if args.tool_names else [],
1643
  resolve_extra_tool_names(args.extra_tools),
1644
  llm_extra_body,
1645
+ omit_generate_params,
1646
  )
1647
 
1648
 
 
1661
  tool_names,
1662
  extra_tools,
1663
  llm_extra_body,
1664
+ omit_generate_params,
1665
  ) = _parse_cli_args(argv or sys.argv[1:])
1666
  agent_cls = resolve_agent_class_for_role_prompt_files(role_prompt_files)
1667
  forbidden_tools = set(getattr(agent_cls, "forbidden_tool_names", set()))
 
1677
  if extra_tools
1678
  else None
1679
  ),
1680
+ llm=default_llm_config(extra_body=llm_extra_body, omit_generate_params=omit_generate_params),
1681
  trace_dir=trace_dir,
1682
  role_prompt=role_prompt or None,
1683
  )