"""ActionState 统一响应信封测试.""" from src.ai.models.action_state import ActionState, ErrorDetail from src.ai.models.chat import ChatData, ChatResponse, Usage class TestActionState: """ActionState 信封测试.""" def test_ok_success(self) -> None: """ok() 返回成功响应.""" data = ChatData(content="hello", model="gpt-4o", usage=Usage()) resp = ActionState.ok(data) assert resp.success is True assert resp.data is not None assert resp.data.content == "hello" assert resp.error is None def test_error_response(self) -> None: """error_response() 返回错误响应.""" resp = ActionState.error_response( code="AI_LLM_UNAVAILABLE", message="all providers failed", details={"tried": ["openai"]}, trace_id="req-123", ) assert resp.success is False assert resp.data is None assert resp.error is not None assert resp.error.code == "AI_LLM_UNAVAILABLE" assert resp.error.message == "all providers failed" assert resp.error.details == {"tried": ["openai"]} assert resp.error.trace_id == "req-123" def test_degraded_sets_flags(self) -> None: """degraded() 在 data 上设置 degraded + degraded_reason.""" data = ChatData(content="fallback", model="gpt-4o", usage=Usage()) resp = ActionState.degraded(data, "llm unavailable") assert resp.success is True assert resp.error is None assert resp.data is not None assert resp.data.degraded is True assert resp.data.degraded_reason == "llm unavailable" def test_error_detail_alias(self) -> None: """ErrorDetail 支持 traceId alias.""" err = ErrorDetail(code="AI_INTERNAL_ERROR", message="boom", trace_id="t-1") assert err.trace_id == "t-1" # 序列化使用 alias dumped = err.model_dump(by_alias=True) assert dumped["traceId"] == "t-1" def test_chat_response_inherits_action_state(self) -> None: """ChatResponse 继承 ActionState[ChatData].""" data = ChatData(content="hi", model="m", usage=Usage()) resp = ChatResponse.ok(data) assert resp.success is True assert resp.data.content == "hi" def test_error_response_without_optional_fields(self) -> None: """error_response() 可选字段缺省.""" resp = ActionState.error_response("AI_INTERNAL_ERROR", "fail") assert resp.error is not None assert resp.error.details is None assert resp.error.trace_id is None