keep compact agent core tools available

This commit is contained in:
pewdiepie-archdaemon
2026-09-17 18:47:04 +00:00
parent 25ff725c1d
commit 4d7c9d44d1
5 changed files with 53 additions and 39 deletions
+4 -39
View File
@@ -3390,8 +3390,8 @@ def setup_chat_routes(
if _clean_v3_preview:
from dataclasses import replace
from src.clean_agent_preview import (
MODE, NATIVE_WORKSPACE_TOOLS, PREVIEW_TOOLS, canonical,
scope_preview_contract, tool_family,
INTERACTIVE_CORE_TOOLS, MODE, NATIVE_WORKSPACE_TOOLS, PREVIEW_TOOLS, canonical,
scope_preview_contract,
)
from src.turn_contract import resolve_full_inventory_contract
_warm_canonical = {canonical(name) for name in _warm_tools}
@@ -3414,41 +3414,6 @@ def setup_chat_routes(
if canonical(s['function']['name']) != 'bash'
or canonical(s['function']['name']) in _warm_canonical
]
# Browser automation is a deliberate capability, not a side
# effect of merely enabling ordinary Web search. Once a clean
# turn successfully uses it, typed execution evidence keeps it
# warm for the conversation so referential follow-ups can
# inspect the same page.
if (
_explicit_browser_intent
and not set(_selected_tools or ()).intersection(
{'web_search', 'web_fetch'}
)
):
# Navigation and interaction are browser operations. Do
# not make the model choose between a site browser and the
# search/fetch APIs after the request has already made
# that distinction. An explicitly named brokered search or
# fetch tool is stronger than the generic URL/open signal;
# preserving it also prevents the browser-only filter from
# intersecting an exact web_fetch contract down to zero
# tools. A later turn can explicitly ask for Web search as
# a fallback.
_preview_schemas = [
s for s in _preview_schemas
if tool_family(s['function']['name']) != 'search_browser'
or canonical(s['function']['name']) in (
{'private_browser'} | NATIVE_WORKSPACE_TOOLS
)
or canonical(s['function']['name']) in _warm_canonical
]
elif not _clean_v3_private_browser_warm and not (
_native_workspace_contract and _local_browser_render_intent
) and 'private_browser' not in _warm_canonical:
_preview_schemas = [
s for s in _preview_schemas
if canonical(s['function']['name']) != 'private_browser'
]
_turn_contract = scope_preview_contract(
replace(resolve_full_inventory_contract(
schemas=_preview_schemas,
@@ -3467,9 +3432,9 @@ def setup_chat_routes(
# OCR operation. Exact operations therefore stay exact;
# ordinary native turns retain warm and workspace tools.
extra_tools=(
frozenset()
INTERACTIVE_CORE_TOOLS
if _exact_selected_native_chain
else _warm_tools | (
else INTERACTIVE_CORE_TOOLS | _warm_tools | (
NATIVE_WORKSPACE_TOOLS | (
{"private_browser"} if _local_browser_render_intent else frozenset()
)
+7
View File
@@ -102,6 +102,13 @@ PREVIEW_TOOLS = (
READ_TOOLS | SAFE_WRITE_TOOLS | EXPLICIT_EXECUTE_TOOLS | SAFE_UI_TOOLS
| BROKERED_JOB_TOOLS | CONTRACT_REQUIRED_TOOLS
)
# Keep a small recovery-capable surface on every interactive compact agent
# turn. Routing still adds domain tools, while policy and action guards remain
# authoritative for execution. Python is deliberately excluded here because
# the WebUI does not own a confined workspace.
INTERACTIVE_CORE_TOOLS = frozenset({
'web_search', 'web_fetch', 'private_browser', 'bash', 'ask_user',
})
# The interactive compact-v5 surface above stays unchanged. These tools are
# added only for a server-validated ``odysseus-native`` request with an active,
# confined workspace. This lets the model-specific clean runtime serve native
+11
View File
@@ -3970,6 +3970,17 @@ def requested_capabilities(message: str, history: Iterable = (), *, active_docum
# Keep the common ``nees`` typo because a missed route leaves the model
# with no way to answer and encourages it to ask unnecessary questions.
return frozenset({"search_browser"})
if (
re.search(r"\b(?:online|on\s+the\s+(?:web|internet))\b", text, re.I)
and re.search(
r"\b(?:find|look|search|check|locate|get|download|available|manual|guide|docs?)\b",
text,
re.I,
)
):
# Explicitly asking Odysseus to look online is sufficient web intent,
# including referential follow-ups such as "Can you look online?".
return frozenset({"search_browser"})
if (
len(concrete_urls) >= 2
and re.search(r"\b(?:open|fetch|read|retrieve|check|use)\b", text, re.I)
+22
View File
@@ -3093,6 +3093,28 @@ def test_preview_contract_keeps_only_routed_family_from_trained_inventory():
assert scoped.active_capabilities == {'notes'}
def test_preview_contract_adds_safe_interactive_core_beside_routed_tools():
core = {'web_search', 'web_fetch', 'private_browser', 'bash', 'ask_user'}
schemas = [
schema for schema in FUNCTION_TOOL_SCHEMAS
if schema['function']['name'] in core | {'manage_notes'}
]
preview = resolve_full_inventory_contract(schemas=schemas, policy=ToolPolicy())
routed = SimpleNamespace(
unavailable=frozenset(), offered=frozenset({'manage_notes'}),
required=frozenset({'manage_notes'}), capabilities=frozenset({'notes'}),
required_read_operation=None,
)
scoped = scope_preview_contract(
preview, routed, {'notes'}, extra_tools=core,
)
assert scoped.offered == core | {'manage_notes'}
assert scoped.required == {'manage_notes'}
assert {schema['function']['name'] for schema in scoped.schemas()} == core | {'manage_notes'}
def test_preview_contract_keeps_available_family_when_an_independent_family_is_unavailable():
schemas = [s for s in FUNCTION_TOOL_SCHEMAS if s['function']['name'] in {
'write_file', 'web_search',
+9
View File
@@ -34,6 +34,15 @@ def test_latest_topic_info_and_common_news_typo_route_to_web_search():
assert requested_capabilities(prompt) == frozenset({"search_browser"})
@pytest.mark.parametrize("prompt", [
"I'm using a WIKING fireplace; can I find an English manual online?",
"Can you look online",
"Could you search online for the operator's manual?",
])
def test_explicit_online_lookup_requests_route_to_web_search(prompt):
assert requested_capabilities(prompt) == frozenset({"search_browser"})
def test_successfully_used_tool_stays_offered_when_next_turn_routes_elsewhere():
contract = resolve(
{"notes"},