| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152 |
- from __future__ import annotations
- import json
- import pytest
- from agent import FailureDetail, FailureDisposition, ToolExecutionError, ToolResult
- def test_failure_detail_is_bounded_json_safe_and_round_trips() -> None:
- failure = FailureDetail(
- code="INPUT_SCOPE_MISMATCH",
- message="x" * 3_000,
- disposition=FailureDisposition.REPLAN_TASK,
- source_tool="save_candidate",
- details={"task_id": "task-1", "scope": ["paragraph", 3]},
- )
- assert len(failure.message) == 2_000
- assert FailureDetail.from_dict(failure.to_dict()) == failure
- assert failure.fingerprint() == FailureDetail(
- code="INPUT_SCOPE_MISMATCH",
- message="different wording",
- disposition=FailureDisposition.REPLAN_TASK,
- source_tool="save_candidate",
- details={"task_id": "task-2", "scope": ["paragraph", 3]},
- ).fingerprint()
- def test_failure_detail_rejects_non_json_details() -> None:
- with pytest.raises(ValueError, match="JSON values"):
- FailureDetail(
- code="INVALID",
- message="invalid",
- disposition=FailureDisposition.RETRY_CALL,
- details={"value": object()},
- )
- def test_tool_result_exposes_structured_failure_to_model() -> None:
- failure = FailureDetail(
- code="REJECTED",
- message="retry with another value",
- disposition=FailureDisposition.RETRY_CALL,
- source_tool="sample",
- )
- result = ToolResult(title="rejected", output="context", failure=failure)
- payload = json.loads(result.to_llm_message())
- assert payload["failure"] == failure.to_dict()
- assert payload["output"] == "context"
- assert ToolExecutionError(failure).failure == failure
|