chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
import structlog.testing
|
||||
|
||||
from opensquilla.engine.types import ToolCall
|
||||
from opensquilla.tools.dispatch import build_tool_handler
|
||||
from opensquilla.tools.registry import ToolRegistry
|
||||
from opensquilla.tools.types import (
|
||||
CallerKind,
|
||||
InteractionMode,
|
||||
ToolContext,
|
||||
ToolSpec,
|
||||
current_tool_context,
|
||||
)
|
||||
|
||||
|
||||
def _build_registry() -> ToolRegistry:
|
||||
registry = ToolRegistry()
|
||||
|
||||
async def denied() -> str:
|
||||
raise ValueError("bad argument")
|
||||
|
||||
async def pending() -> str:
|
||||
return (
|
||||
'{\"status\": \"approval_required\", \"approval_id\": \"abc123\",'
|
||||
' \"command\": \"rm /tmp/secret\", \"warning\": \"destructive\"}'
|
||||
)
|
||||
|
||||
async def required_echo(value: str) -> str:
|
||||
return value
|
||||
|
||||
registry.register(ToolSpec(name="denied", description="denied", parameters={}), denied)
|
||||
registry.register(ToolSpec(name="pending", description="pending", parameters={}), pending)
|
||||
registry.register(
|
||||
ToolSpec(
|
||||
name="required_echo",
|
||||
description="required echo",
|
||||
parameters={"value": {"type": "string"}},
|
||||
required=["value"],
|
||||
),
|
||||
required_echo,
|
||||
)
|
||||
return registry
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dispatch_tool_failed_log_includes_surface_context() -> None:
|
||||
handler = build_tool_handler(_build_registry())
|
||||
token = current_tool_context.set(
|
||||
ToolContext(
|
||||
is_owner=False,
|
||||
caller_kind=CallerKind.WEB,
|
||||
session_key="agent:main:demo",
|
||||
agent_id="main",
|
||||
)
|
||||
)
|
||||
try:
|
||||
with structlog.testing.capture_logs() as captured:
|
||||
result = await handler(
|
||||
ToolCall(tool_use_id="tc-1", tool_name="denied", arguments={})
|
||||
)
|
||||
|
||||
assert result.is_error is True
|
||||
assert any(event["event"] == "dispatch.tool_failed" for event in captured)
|
||||
event = next(event for event in captured if event["event"] == "dispatch.tool_failed")
|
||||
assert event["tool"] == "denied"
|
||||
assert event["tool_use_id"] == "tc-1"
|
||||
assert event["agent_id"] == "main"
|
||||
assert event["session_key"] == "agent:main:demo"
|
||||
finally:
|
||||
current_tool_context.reset(token)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dispatch_missing_required_log_records_shape_guidance_flag(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setenv("OPENSQUILLA_MISSING_REQUIRED_ARGUMENT_SHAPE_GUIDANCE", "1")
|
||||
handler = build_tool_handler(_build_registry())
|
||||
token = current_tool_context.set(
|
||||
ToolContext(
|
||||
is_owner=True,
|
||||
caller_kind=CallerKind.CLI,
|
||||
session_key="agent:main:shape-guidance",
|
||||
agent_id="main",
|
||||
)
|
||||
)
|
||||
try:
|
||||
with structlog.testing.capture_logs() as captured:
|
||||
result = await handler(
|
||||
ToolCall(
|
||||
tool_use_id="tc-shape",
|
||||
tool_name="required_echo",
|
||||
arguments={},
|
||||
)
|
||||
)
|
||||
|
||||
assert result.is_error is True
|
||||
event = next(
|
||||
event
|
||||
for event in captured
|
||||
if event["event"] == "dispatch.invalid_tool_arguments"
|
||||
)
|
||||
assert event["shape_guidance_enabled"] is True
|
||||
assert event["argument_keys"] == []
|
||||
assert event["missing"] == ["value"]
|
||||
assert event["session_key"] == "agent:main:shape-guidance"
|
||||
finally:
|
||||
current_tool_context.reset(token)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dispatch_unsupported_surface_log_includes_approval_id() -> None:
|
||||
handler = build_tool_handler(_build_registry())
|
||||
token = current_tool_context.set(
|
||||
ToolContext(
|
||||
is_owner=False,
|
||||
caller_kind=CallerKind.CRON,
|
||||
interaction_mode=InteractionMode.UNATTENDED,
|
||||
session_key="cron:system",
|
||||
agent_id="cron",
|
||||
)
|
||||
)
|
||||
try:
|
||||
with structlog.testing.capture_logs() as captured:
|
||||
result = await handler(
|
||||
ToolCall(tool_use_id="tc-2", tool_name="pending", arguments={}),
|
||||
)
|
||||
|
||||
assert result.is_error is False
|
||||
assert result.execution_status is not None
|
||||
assert result.execution_status["status"] == "unknown"
|
||||
assert result.execution_status["reason"] == "approval_pending"
|
||||
assert any(
|
||||
event["event"] == "dispatch.approval_required_unsupported_surface"
|
||||
for event in captured
|
||||
)
|
||||
event = next(
|
||||
event
|
||||
for event in captured
|
||||
if event["event"] == "dispatch.approval_required_unsupported_surface"
|
||||
)
|
||||
assert event["tool"] == "pending"
|
||||
assert event["surface"] == "cron"
|
||||
assert event["approval_id"] == "abc123"
|
||||
assert event["tool_use_id"] == "tc-2"
|
||||
assert event["agent_id"] == "cron"
|
||||
assert event["session_key"] == "cron:system"
|
||||
finally:
|
||||
current_tool_context.reset(token)
|
||||
Reference in New Issue
Block a user