mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-13 18:32:20 +02:00
keep compact agent core tools available
This commit is contained in:
+4
-39
@@ -3390,8 +3390,8 @@ def setup_chat_routes(
|
|||||||
if _clean_v3_preview:
|
if _clean_v3_preview:
|
||||||
from dataclasses import replace
|
from dataclasses import replace
|
||||||
from src.clean_agent_preview import (
|
from src.clean_agent_preview import (
|
||||||
MODE, NATIVE_WORKSPACE_TOOLS, PREVIEW_TOOLS, canonical,
|
INTERACTIVE_CORE_TOOLS, MODE, NATIVE_WORKSPACE_TOOLS, PREVIEW_TOOLS, canonical,
|
||||||
scope_preview_contract, tool_family,
|
scope_preview_contract,
|
||||||
)
|
)
|
||||||
from src.turn_contract import resolve_full_inventory_contract
|
from src.turn_contract import resolve_full_inventory_contract
|
||||||
_warm_canonical = {canonical(name) for name in _warm_tools}
|
_warm_canonical = {canonical(name) for name in _warm_tools}
|
||||||
@@ -3414,41 +3414,6 @@ def setup_chat_routes(
|
|||||||
if canonical(s['function']['name']) != 'bash'
|
if canonical(s['function']['name']) != 'bash'
|
||||||
or canonical(s['function']['name']) in _warm_canonical
|
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(
|
_turn_contract = scope_preview_contract(
|
||||||
replace(resolve_full_inventory_contract(
|
replace(resolve_full_inventory_contract(
|
||||||
schemas=_preview_schemas,
|
schemas=_preview_schemas,
|
||||||
@@ -3467,9 +3432,9 @@ def setup_chat_routes(
|
|||||||
# OCR operation. Exact operations therefore stay exact;
|
# OCR operation. Exact operations therefore stay exact;
|
||||||
# ordinary native turns retain warm and workspace tools.
|
# ordinary native turns retain warm and workspace tools.
|
||||||
extra_tools=(
|
extra_tools=(
|
||||||
frozenset()
|
INTERACTIVE_CORE_TOOLS
|
||||||
if _exact_selected_native_chain
|
if _exact_selected_native_chain
|
||||||
else _warm_tools | (
|
else INTERACTIVE_CORE_TOOLS | _warm_tools | (
|
||||||
NATIVE_WORKSPACE_TOOLS | (
|
NATIVE_WORKSPACE_TOOLS | (
|
||||||
{"private_browser"} if _local_browser_render_intent else frozenset()
|
{"private_browser"} if _local_browser_render_intent else frozenset()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -102,6 +102,13 @@ PREVIEW_TOOLS = (
|
|||||||
READ_TOOLS | SAFE_WRITE_TOOLS | EXPLICIT_EXECUTE_TOOLS | SAFE_UI_TOOLS
|
READ_TOOLS | SAFE_WRITE_TOOLS | EXPLICIT_EXECUTE_TOOLS | SAFE_UI_TOOLS
|
||||||
| BROKERED_JOB_TOOLS | CONTRACT_REQUIRED_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
|
# The interactive compact-v5 surface above stays unchanged. These tools are
|
||||||
# added only for a server-validated ``odysseus-native`` request with an active,
|
# added only for a server-validated ``odysseus-native`` request with an active,
|
||||||
# confined workspace. This lets the model-specific clean runtime serve native
|
# confined workspace. This lets the model-specific clean runtime serve native
|
||||||
|
|||||||
@@ -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
|
# Keep the common ``nees`` typo because a missed route leaves the model
|
||||||
# with no way to answer and encourages it to ask unnecessary questions.
|
# with no way to answer and encourages it to ask unnecessary questions.
|
||||||
return frozenset({"search_browser"})
|
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 (
|
if (
|
||||||
len(concrete_urls) >= 2
|
len(concrete_urls) >= 2
|
||||||
and re.search(r"\b(?:open|fetch|read|retrieve|check|use)\b", text, re.I)
|
and re.search(r"\b(?:open|fetch|read|retrieve|check|use)\b", text, re.I)
|
||||||
|
|||||||
@@ -3093,6 +3093,28 @@ def test_preview_contract_keeps_only_routed_family_from_trained_inventory():
|
|||||||
assert scoped.active_capabilities == {'notes'}
|
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():
|
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 {
|
schemas = [s for s in FUNCTION_TOOL_SCHEMAS if s['function']['name'] in {
|
||||||
'write_file', 'web_search',
|
'write_file', 'web_search',
|
||||||
|
|||||||
@@ -34,6 +34,15 @@ def test_latest_topic_info_and_common_news_typo_route_to_web_search():
|
|||||||
assert requested_capabilities(prompt) == frozenset({"search_browser"})
|
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():
|
def test_successfully_used_tool_stays_offered_when_next_turn_routes_elsewhere():
|
||||||
contract = resolve(
|
contract = resolve(
|
||||||
{"notes"},
|
{"notes"},
|
||||||
|
|||||||
Reference in New Issue
Block a user