170 lines
6.0 KiB
Python
Executable File
170 lines
6.0 KiB
Python
Executable File
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import unittest
|
|
import urllib.error
|
|
from unittest.mock import patch
|
|
|
|
from cognitive_agent.infrastructure.llm.openai_responses import OpenAIIntentInterpreter
|
|
|
|
|
|
INTENT = {
|
|
"detected_domains": ["seat"],
|
|
"requests": [
|
|
{
|
|
"domain": "seat",
|
|
"capability": "seat.set_ventilation",
|
|
"target_scope": "driver",
|
|
"operation": "activate",
|
|
"parameters": [
|
|
{"name": "state", "value": "on"},
|
|
{"name": "level", "value": 1},
|
|
],
|
|
"reason": "Driver requested seat ventilation.",
|
|
}
|
|
],
|
|
"ambiguities": [],
|
|
"decision_summary": ["打开主驾座椅通风"],
|
|
"confidence": 0.99,
|
|
}
|
|
|
|
|
|
class FakeResponse:
|
|
def __init__(self, body: str) -> None:
|
|
self.body = body.encode("utf-8")
|
|
|
|
def __enter__(self) -> FakeResponse:
|
|
return self
|
|
|
|
def __exit__(self, *_args: object) -> None:
|
|
return None
|
|
|
|
def read(self) -> bytes:
|
|
return self.body
|
|
|
|
|
|
class OpenAIResponsesTests(unittest.TestCase):
|
|
def test_non_streaming_structured_output(self) -> None:
|
|
response_body = json.dumps({"output_text": json.dumps(INTENT)})
|
|
environment = {
|
|
"OPENAI_API_KEY": "test-key",
|
|
"OPENAI_STREAM": "false",
|
|
}
|
|
|
|
with patch.dict(os.environ, environment, clear=False):
|
|
interpreter = OpenAIIntentInterpreter()
|
|
with patch(
|
|
"cognitive_agent.infrastructure.llm.openai_responses.urllib.request.urlopen",
|
|
return_value=FakeResponse(response_body),
|
|
) as urlopen:
|
|
result = interpreter.interpret(
|
|
"主驾还有点闷",
|
|
{
|
|
"last_target": "driver",
|
|
"devices": {
|
|
"driver": {
|
|
"ventilation": {"state": "on", "level": 1}
|
|
}
|
|
},
|
|
},
|
|
)
|
|
|
|
request_payload = json.loads(urlopen.call_args.args[0].data.decode("utf-8"))
|
|
self.assertEqual(result, INTENT)
|
|
self.assertNotIn("stream", request_payload)
|
|
self.assertIn("capability registry", request_payload["input"][1]["content"][0]["text"])
|
|
self.assertIn('"level": 1', request_payload["input"][2]["content"][0]["text"])
|
|
|
|
def test_streaming_structured_output(self) -> None:
|
|
intent_text = json.dumps(INTENT, ensure_ascii=False)
|
|
stream_body = "\n".join(
|
|
[
|
|
"event: response.output_text.delta",
|
|
f"data: {json.dumps({'type': 'response.output_text.delta', 'delta': intent_text[:30]}, ensure_ascii=False)}",
|
|
"",
|
|
"event: response.output_text.done",
|
|
f"data: {json.dumps({'type': 'response.output_text.done', 'text': intent_text}, ensure_ascii=False)}",
|
|
"",
|
|
"data: [DONE]",
|
|
]
|
|
)
|
|
environment = {
|
|
"OPENAI_API_KEY": "test-key",
|
|
"OPENAI_STREAM": "true",
|
|
}
|
|
|
|
with patch.dict(os.environ, environment, clear=False):
|
|
interpreter = OpenAIIntentInterpreter()
|
|
with patch(
|
|
"cognitive_agent.infrastructure.llm.openai_responses.urllib.request.urlopen",
|
|
return_value=FakeResponse(stream_body),
|
|
) as urlopen:
|
|
result = interpreter.interpret("打开主驾座椅通风")
|
|
|
|
request_payload = json.loads(urlopen.call_args.args[0].data.decode("utf-8"))
|
|
self.assertEqual(result, INTENT)
|
|
self.assertTrue(request_payload["stream"])
|
|
|
|
def test_retries_transient_network_failure(self) -> None:
|
|
response_body = json.dumps({"output_text": json.dumps(INTENT)})
|
|
environment = {
|
|
"OPENAI_API_KEY": "test-key",
|
|
"OPENAI_STREAM": "false",
|
|
"OPENAI_MAX_RETRIES": "1",
|
|
}
|
|
|
|
with patch.dict(os.environ, environment, clear=False):
|
|
interpreter = OpenAIIntentInterpreter()
|
|
with patch(
|
|
"cognitive_agent.infrastructure.llm.openai_responses.urllib.request.urlopen",
|
|
side_effect=[urllib.error.URLError("temporary TLS EOF"), FakeResponse(response_body)],
|
|
) as urlopen, patch(
|
|
"cognitive_agent.infrastructure.llm.openai_responses.time.sleep"
|
|
) as sleep:
|
|
result = interpreter.interpret("打开主驾座椅通风")
|
|
|
|
self.assertEqual(result, INTENT)
|
|
self.assertEqual(urlopen.call_count, 2)
|
|
sleep.assert_called_once_with(1)
|
|
|
|
def test_retries_transient_error_inside_stream(self) -> None:
|
|
error_stream = "data: " + json.dumps(
|
|
{
|
|
"type": "error",
|
|
"error": {
|
|
"type": "service_unavailable_error",
|
|
"code": "server_is_overloaded",
|
|
"message": "try again",
|
|
},
|
|
}
|
|
)
|
|
intent_text = json.dumps(INTENT, ensure_ascii=False)
|
|
success_stream = "data: " + json.dumps(
|
|
{"type": "response.output_text.done", "text": intent_text},
|
|
ensure_ascii=False,
|
|
)
|
|
environment = {
|
|
"OPENAI_API_KEY": "test-key",
|
|
"OPENAI_STREAM": "true",
|
|
"OPENAI_MAX_RETRIES": "1",
|
|
}
|
|
|
|
with patch.dict(os.environ, environment, clear=False):
|
|
interpreter = OpenAIIntentInterpreter()
|
|
with patch(
|
|
"cognitive_agent.infrastructure.llm.openai_responses.urllib.request.urlopen",
|
|
side_effect=[FakeResponse(error_stream), FakeResponse(success_stream)],
|
|
) as urlopen, patch(
|
|
"cognitive_agent.infrastructure.llm.openai_responses.time.sleep"
|
|
) as sleep:
|
|
result = interpreter.interpret("打开主驾座椅通风")
|
|
|
|
self.assertEqual(result, INTENT)
|
|
self.assertEqual(urlopen.call_count, 2)
|
|
sleep.assert_called_once_with(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|