chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
import httpx
|
||||
|
||||
from opensquilla.tools.envelope import build_tool_failure_envelope
|
||||
from opensquilla.tools.types import RetryableToolInputError, SafeToolError
|
||||
|
||||
|
||||
def test_type_error_tool_failure_is_model_retriable_without_raw_traceback() -> None:
|
||||
envelope = build_tool_failure_envelope(
|
||||
TypeError("secret raw argument detail"),
|
||||
"write_file",
|
||||
)
|
||||
|
||||
assert envelope["status"] == "error"
|
||||
assert envelope["tool"] == "write_file"
|
||||
assert envelope["error_class"] == "TypeError"
|
||||
assert envelope["retry_allowed"] is True
|
||||
assert "tool schema" in envelope["user_message"]
|
||||
assert "secret raw argument detail" not in envelope["user_message"]
|
||||
|
||||
|
||||
def test_httpx_timeout_exception_is_retriable_with_specific_message() -> None:
|
||||
envelope = build_tool_failure_envelope(
|
||||
httpx.TimeoutException("secret endpoint"),
|
||||
"web_fetch",
|
||||
)
|
||||
|
||||
assert envelope["error_class"] == "TimeoutException"
|
||||
assert envelope["retry_allowed"] is True
|
||||
assert "timed out" in envelope["user_message"]
|
||||
assert "secret endpoint" not in envelope["user_message"]
|
||||
|
||||
|
||||
def test_httpx_connect_error_is_retriable_with_specific_message() -> None:
|
||||
envelope = build_tool_failure_envelope(
|
||||
httpx.ConnectError("secret host"),
|
||||
"web_fetch",
|
||||
)
|
||||
|
||||
assert envelope["error_class"] == "ConnectError"
|
||||
assert envelope["retry_allowed"] is True
|
||||
assert "could not connect" in envelope["user_message"]
|
||||
assert "secret host" not in envelope["user_message"]
|
||||
|
||||
|
||||
def test_json_decode_error_has_specific_message() -> None:
|
||||
envelope = build_tool_failure_envelope(
|
||||
json.JSONDecodeError("secret payload", "not-json", 0),
|
||||
"web_fetch",
|
||||
)
|
||||
|
||||
assert envelope["error_class"] == "JSONDecodeError"
|
||||
assert envelope["retry_allowed"] is False
|
||||
assert "invalid response payload" in envelope["user_message"]
|
||||
assert "secret payload" not in envelope["user_message"]
|
||||
|
||||
|
||||
def test_policy_denial_envelope_has_exactly_five_keys() -> None:
|
||||
envelope = build_tool_failure_envelope(
|
||||
PermissionError("raw denied detail"),
|
||||
"exec_command",
|
||||
policy_denial=True,
|
||||
error_class_override="PolicyDenied",
|
||||
user_message_override="Blocked by policy.",
|
||||
)
|
||||
|
||||
assert set(envelope) == {
|
||||
"status",
|
||||
"tool",
|
||||
"error_class",
|
||||
"user_message",
|
||||
"retry_allowed",
|
||||
}
|
||||
assert envelope["status"] == "error"
|
||||
assert envelope["tool"] == "exec_command"
|
||||
assert envelope["error_class"] == "PolicyDenied"
|
||||
assert envelope["user_message"] == "Blocked by policy."
|
||||
assert envelope["retry_allowed"] is False
|
||||
|
||||
|
||||
def test_safe_tool_error_instance_message_preserves_five_key_shape() -> None:
|
||||
envelope = build_tool_failure_envelope(
|
||||
SafeToolError("PDF file not found: input.pdf (resolved=/workspace/input.pdf)", "secret"),
|
||||
"pdf",
|
||||
)
|
||||
|
||||
assert set(envelope) == {
|
||||
"status",
|
||||
"tool",
|
||||
"error_class",
|
||||
"user_message",
|
||||
"retry_allowed",
|
||||
}
|
||||
assert envelope["status"] == "error"
|
||||
assert envelope["tool"] == "pdf"
|
||||
assert envelope["error_class"] == "SafeToolError"
|
||||
assert "PDF file not found" in envelope["user_message"]
|
||||
assert "secret" not in envelope["user_message"]
|
||||
|
||||
|
||||
def test_retryable_tool_input_error_marks_model_correctable_failures() -> None:
|
||||
envelope = build_tool_failure_envelope(
|
||||
RetryableToolInputError(
|
||||
"edit_file could not find old_text. Read the file and retry with exact text."
|
||||
),
|
||||
"edit_file",
|
||||
)
|
||||
|
||||
assert set(envelope) == {
|
||||
"status",
|
||||
"tool",
|
||||
"error_class",
|
||||
"user_message",
|
||||
"retry_allowed",
|
||||
}
|
||||
assert envelope["tool"] == "edit_file"
|
||||
assert envelope["error_class"] == "RetryableToolInputError"
|
||||
assert envelope["retry_allowed"] is True
|
||||
assert "retry with exact text" in envelope["user_message"]
|
||||
|
||||
|
||||
def test_image_attachment_path_safe_tool_error_is_not_generic_internal_error() -> None:
|
||||
envelope = build_tool_failure_envelope(
|
||||
SafeToolError(
|
||||
"Image path is not accessible by the image tool: ab367.png. "
|
||||
"Pass a real local file path or HTTP(S) URL. If this is a chat attachment, "
|
||||
"answer from the attached image directly instead of calling the image tool.",
|
||||
"resolved=/secret/workspace/ab367.png",
|
||||
),
|
||||
"image",
|
||||
)
|
||||
|
||||
assert set(envelope) == {
|
||||
"status",
|
||||
"tool",
|
||||
"error_class",
|
||||
"user_message",
|
||||
"retry_allowed",
|
||||
}
|
||||
assert envelope["tool"] == "image"
|
||||
assert envelope["error_class"] == "SafeToolError"
|
||||
assert envelope["retry_allowed"] is False
|
||||
assert "not accessible by the image tool" in envelope["user_message"]
|
||||
assert "chat attachment" in envelope["user_message"]
|
||||
assert "internal error" not in envelope["user_message"]
|
||||
assert "secret" not in envelope["user_message"]
|
||||
Reference in New Issue
Block a user