mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-20 13:52:24 +02:00
bound search attempts by research depth
This commit is contained in:
@@ -1934,7 +1934,7 @@ def dependent_write_prerequisite_error(turn_contract, name, successful_required_
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def bounded_research_tool_policy(offered, *, searches=0, retrievals=0):
|
def bounded_research_tool_policy(offered, *, searches=0, retrievals=0, search_limit=2):
|
||||||
"""Bound research loops after enough discovery evidence has been gathered.
|
"""Bound research loops after enough discovery evidence has been gathered.
|
||||||
|
|
||||||
Two searches are enough to choose a source in the ordinary research flow.
|
Two searches are enough to choose a source in the ordinary research flow.
|
||||||
@@ -1943,7 +1943,7 @@ def bounded_research_tool_policy(offered, *, searches=0, retrievals=0):
|
|||||||
so unrelated calendar, email, document, and media turns are unchanged.
|
so unrelated calendar, email, document, and media turns are unchanged.
|
||||||
"""
|
"""
|
||||||
schemas = list(offered or ())
|
schemas = list(offered or ())
|
||||||
if searches < 2:
|
if searches < max(1, int(search_limit)):
|
||||||
return schemas, None, False
|
return schemas, None, False
|
||||||
schemas = [
|
schemas = [
|
||||||
schema for schema in schemas
|
schema for schema in schemas
|
||||||
@@ -3791,6 +3791,7 @@ async def stream_preview(*, endpoint_url, model, messages, headers, turn_contrac
|
|||||||
successful_duplicate_counts = {}
|
successful_duplicate_counts = {}
|
||||||
empty_search_intents = {}
|
empty_search_intents = {}
|
||||||
successful_search_intents = []
|
successful_search_intents = []
|
||||||
|
web_search_attempts = 0
|
||||||
empty_web_search_attempts = 0
|
empty_web_search_attempts = 0
|
||||||
successful_web_searches = 0
|
successful_web_searches = 0
|
||||||
successful_web_retrievals = 0
|
successful_web_retrievals = 0
|
||||||
@@ -3922,6 +3923,7 @@ async def stream_preview(*, endpoint_url, model, messages, headers, turn_contrac
|
|||||||
round_offered,
|
round_offered,
|
||||||
searches=successful_web_searches,
|
searches=successful_web_searches,
|
||||||
retrievals=successful_web_retrievals,
|
retrievals=successful_web_retrievals,
|
||||||
|
search_limit=(2 if broad_current_web_request(direct_user_text) else 1),
|
||||||
)
|
)
|
||||||
round_max_tokens = (
|
round_max_tokens = (
|
||||||
min(request_max_tokens, 4096)
|
min(request_max_tokens, 4096)
|
||||||
@@ -4433,6 +4435,16 @@ async def stream_preview(*, endpoint_url, model, messages, headers, turn_contrac
|
|||||||
'page evidence or a different navigation strategy.'
|
'page evidence or a different navigation strategy.'
|
||||||
)
|
)
|
||||||
if tool_type == 'web_search':
|
if tool_type == 'web_search':
|
||||||
|
web_search_attempts += 1
|
||||||
|
if web_search_attempts > 4:
|
||||||
|
suppressed_tool_until_round['web_search'] = round_limit + 1
|
||||||
|
force_no_tools_next_round = True
|
||||||
|
calls += 1
|
||||||
|
raise ValueError(
|
||||||
|
'The bounded search-attempt budget is exhausted. Do not search '
|
||||||
|
'again; answer from usable evidence already gathered, or clearly '
|
||||||
|
'report what could not be verified and suggest a concrete next step.'
|
||||||
|
)
|
||||||
search_intent = normalized_search_intent(args.get('query'))
|
search_intent = normalized_search_intent(args.get('query'))
|
||||||
if repeated_search_refinement(
|
if repeated_search_refinement(
|
||||||
args.get('query'), successful_search_intents,
|
args.get('query'), successful_search_intents,
|
||||||
@@ -4782,7 +4794,8 @@ async def stream_preview(*, endpoint_url, model, messages, headers, turn_contrac
|
|||||||
'reason': 'web_fetch_boilerplate_fallback',
|
'reason': 'web_fetch_boilerplate_fallback',
|
||||||
})
|
})
|
||||||
if not failed and canonical(actual_tool) == 'web_search':
|
if not failed and canonical(actual_tool) == 'web_search':
|
||||||
successful_web_searches += 1
|
if result.get('evidence_status') != 'empty':
|
||||||
|
successful_web_searches += 1
|
||||||
successful_intent = normalized_search_intent(args.get('query'))
|
successful_intent = normalized_search_intent(args.get('query'))
|
||||||
if successful_intent and result.get('evidence_status') != 'empty':
|
if successful_intent and result.get('evidence_status') != 'empty':
|
||||||
successful_search_intents.append(successful_intent)
|
successful_search_intents.append(successful_intent)
|
||||||
|
|||||||
@@ -3961,6 +3961,8 @@ def broad_web_briefing_request(message: str) -> bool:
|
|||||||
return True
|
return True
|
||||||
if re.search(r"\b(?:news|headlines?|top\s+stories|news\s+roundup)\b", text, re.I):
|
if re.search(r"\b(?:news|headlines?|top\s+stories|news\s+roundup)\b", text, re.I):
|
||||||
return True
|
return True
|
||||||
|
if re.search(r"\b(?:research|investigate|deep[ -]?dive)\b", text, re.I):
|
||||||
|
return True
|
||||||
if (
|
if (
|
||||||
re.search(r"\b(?:latest|recent|current|today(?:'s)?|right\s+now)\b", text, re.I)
|
re.search(r"\b(?:latest|recent|current|today(?:'s)?|right\s+now)\b", text, re.I)
|
||||||
and re.search(
|
and re.search(
|
||||||
@@ -3985,7 +3987,10 @@ def requested_capabilities(message: str, history: Iterable = (), *, active_docum
|
|||||||
text = lead["request"].strip()
|
text = lead["request"].strip()
|
||||||
history = tuple(history)
|
history = tuple(history)
|
||||||
concrete_urls = re.findall(r"\bhttps?://[^\s<>\"']+", raw_text, re.I)
|
concrete_urls = re.findall(r"\bhttps?://[^\s<>\"']+", raw_text, re.I)
|
||||||
if broad_web_briefing_request(text):
|
if (
|
||||||
|
broad_web_briefing_request(text)
|
||||||
|
and not re.search(r"\b(?:research|investigate|deep[ -]?dive)\b", text, re.I)
|
||||||
|
):
|
||||||
return frozenset({"search_browser"})
|
return frozenset({"search_browser"})
|
||||||
if re.search(r"\b(?:web_search|web_fetch)\b", raw_text, re.I):
|
if re.search(r"\b(?:web_search|web_fetch)\b", raw_text, re.I):
|
||||||
# Explicit native-tool requests are stronger than incidental domain
|
# Explicit native-tool requests are stronger than incidental domain
|
||||||
|
|||||||
@@ -1054,6 +1054,22 @@ def test_bounded_research_policy_forces_fetch_after_two_searches():
|
|||||||
assert active is True
|
assert active is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_narrow_lookup_policy_forces_retrieval_after_one_successful_search():
|
||||||
|
schemas = [
|
||||||
|
{'type': 'function', 'function': {'name': name, 'parameters': {}}}
|
||||||
|
for name in ('web_search', 'web_fetch', 'private_browser')
|
||||||
|
]
|
||||||
|
offered, choice, active = bounded_research_tool_policy(
|
||||||
|
schemas, searches=1, retrievals=0, search_limit=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert [schema['function']['name'] for schema in offered] == [
|
||||||
|
'web_fetch', 'private_browser',
|
||||||
|
]
|
||||||
|
assert choice == {'type': 'function', 'function': {'name': 'web_fetch'}}
|
||||||
|
assert active is True
|
||||||
|
|
||||||
|
|
||||||
def test_bounded_research_policy_reserves_synthesis_after_retrieval():
|
def test_bounded_research_policy_reserves_synthesis_after_retrieval():
|
||||||
schemas = [
|
schemas = [
|
||||||
{'type': 'function', 'function': {'name': name, 'parameters': {}}}
|
{'type': 'function', 'function': {'name': name, 'parameters': {}}}
|
||||||
|
|||||||
Reference in New Issue
Block a user