mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-30 17:52:26 +01:00
Merge pull request #6473 from ShahabAhmed01/fix/scheduler-research-settings-guard-5049
fix(scheduler): fall back to defaults for non-numeric research settings
This commit is contained in:
+33
-3
@@ -355,6 +355,36 @@ def _normalize_chat_endpoint(url: str) -> str:
|
|||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_research_settings(get_setting_fn):
|
||||||
|
"""Resolve the scheduled-research settings with crash-proof fallbacks.
|
||||||
|
|
||||||
|
A hand-edited or agent-written data/settings.json can hold non-numeric
|
||||||
|
values for the research_* keys; the bare int() reads previously raised
|
||||||
|
inside TaskScheduler._execute_research_task and killed every scheduled
|
||||||
|
research run until settings.json was fixed by hand (#5049).
|
||||||
|
src/research_handler.py already guards the same reads defensively —
|
||||||
|
this mirrors that for the scheduler. Valid values pass through
|
||||||
|
unchanged (numeric strings like "4096" still parse).
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
max_tokens = int(get_setting_fn("research_max_tokens", 8192))
|
||||||
|
except (TypeError, ValueError, OverflowError):
|
||||||
|
max_tokens = 8192
|
||||||
|
try:
|
||||||
|
extraction_timeout = int(
|
||||||
|
get_setting_fn("research_extraction_timeout_seconds", 90) or 90
|
||||||
|
)
|
||||||
|
except (TypeError, ValueError, OverflowError):
|
||||||
|
extraction_timeout = 90
|
||||||
|
try:
|
||||||
|
extraction_concurrency = int(
|
||||||
|
get_setting_fn("research_extraction_concurrency", 3) or 3
|
||||||
|
)
|
||||||
|
except (TypeError, ValueError, OverflowError):
|
||||||
|
extraction_concurrency = 3
|
||||||
|
return max_tokens, extraction_timeout, extraction_concurrency
|
||||||
|
|
||||||
|
|
||||||
class TaskScheduler:
|
class TaskScheduler:
|
||||||
def __init__(self, session_manager):
|
def __init__(self, session_manager):
|
||||||
self._session_manager = session_manager
|
self._session_manager = session_manager
|
||||||
@@ -2187,9 +2217,9 @@ class TaskScheduler:
|
|||||||
pass
|
pass
|
||||||
endpoint_url = _normalize_chat_endpoint(endpoint_url)
|
endpoint_url = _normalize_chat_endpoint(endpoint_url)
|
||||||
|
|
||||||
max_tokens = int(get_setting("research_max_tokens", 8192))
|
max_tokens, extraction_timeout, extraction_concurrency = (
|
||||||
extraction_timeout = int(get_setting("research_extraction_timeout_seconds", 90) or 90)
|
_resolve_research_settings(get_setting)
|
||||||
extraction_concurrency = int(get_setting("research_extraction_concurrency", 3) or 3)
|
)
|
||||||
|
|
||||||
researcher = DeepResearcher(
|
researcher = DeepResearcher(
|
||||||
llm_endpoint=endpoint_url,
|
llm_endpoint=endpoint_url,
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
"""Guarded resolution of scheduled-research settings (#5049).
|
||||||
|
|
||||||
|
The scheduler reads ``research_max_tokens`` /
|
||||||
|
``research_extraction_timeout_seconds`` / ``research_extraction_concurrency``
|
||||||
|
from settings.json with bare ``int()`` casts. A hand-edited value like
|
||||||
|
``{"research_max_tokens": "invalid"}`` used to raise inside
|
||||||
|
``TaskScheduler._execute_research_task`` and kill every scheduled research
|
||||||
|
run until settings.json was fixed by hand.
|
||||||
|
|
||||||
|
``_resolve_research_settings`` must fall back to the documented defaults
|
||||||
|
(8192 / 90 / 3) for non-numeric input while preserving valid-value behavior
|
||||||
|
(numeric strings still parse). ``src/research_handler.py`` already guards the
|
||||||
|
same reads defensively; this is the scheduler's equivalent.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from src.task_scheduler import _resolve_research_settings
|
||||||
|
|
||||||
|
|
||||||
|
def _fake_get_setting(values):
|
||||||
|
"""A get_setting stand-in backed by a plain dict."""
|
||||||
|
|
||||||
|
def get(key, default=None):
|
||||||
|
return values.get(key, default)
|
||||||
|
|
||||||
|
return get
|
||||||
|
|
||||||
|
|
||||||
|
def test_non_numeric_values_fall_back_to_documented_defaults():
|
||||||
|
get = _fake_get_setting(
|
||||||
|
{
|
||||||
|
"research_max_tokens": "invalid",
|
||||||
|
"research_extraction_timeout_seconds": "bogus",
|
||||||
|
"research_extraction_concurrency": "not-a-number",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert _resolve_research_settings(get) == (8192, 90, 3)
|
||||||
|
|
||||||
|
|
||||||
|
def test_none_values_fall_back_to_documented_defaults():
|
||||||
|
get = _fake_get_setting(
|
||||||
|
{
|
||||||
|
"research_max_tokens": None,
|
||||||
|
"research_extraction_timeout_seconds": None,
|
||||||
|
"research_extraction_concurrency": None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert _resolve_research_settings(get) == (8192, 90, 3)
|
||||||
|
|
||||||
|
|
||||||
|
def test_numeric_strings_still_parse():
|
||||||
|
get = _fake_get_setting(
|
||||||
|
{
|
||||||
|
"research_max_tokens": "4096",
|
||||||
|
"research_extraction_timeout_seconds": "45",
|
||||||
|
"research_extraction_concurrency": "2",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert _resolve_research_settings(get) == (4096, 45, 2)
|
||||||
|
|
||||||
|
|
||||||
|
def test_missing_keys_keep_documented_defaults():
|
||||||
|
assert _resolve_research_settings(_fake_get_setting({})) == (8192, 90, 3)
|
||||||
|
|
||||||
|
|
||||||
|
def test_valid_ints_pass_through():
|
||||||
|
get = _fake_get_setting(
|
||||||
|
{
|
||||||
|
"research_max_tokens": 2048,
|
||||||
|
"research_extraction_timeout_seconds": 120,
|
||||||
|
"research_extraction_concurrency": 6,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert _resolve_research_settings(get) == (2048, 120, 6)
|
||||||
|
|
||||||
|
|
||||||
|
def test_non_finite_json_numbers_fall_back_individually():
|
||||||
|
"""JSON exponent overflow produces infinity, which int() cannot convert."""
|
||||||
|
keys = (
|
||||||
|
"research_max_tokens",
|
||||||
|
"research_extraction_timeout_seconds",
|
||||||
|
"research_extraction_concurrency",
|
||||||
|
)
|
||||||
|
valid = (4096, 45, 2)
|
||||||
|
defaults = (8192, 90, 3)
|
||||||
|
|
||||||
|
for non_finite in (json.loads("1e309"), json.loads("-1e309")):
|
||||||
|
for index, key in enumerate(keys):
|
||||||
|
values = dict(zip(keys, valid))
|
||||||
|
values[key] = non_finite
|
||||||
|
expected = list(valid)
|
||||||
|
expected[index] = defaults[index]
|
||||||
|
assert _resolve_research_settings(
|
||||||
|
_fake_get_setting(values)
|
||||||
|
) == tuple(expected)
|
||||||
Reference in New Issue
Block a user