mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: updated declarative samples and handling of non-pydantic response formats (#5022)
* updated declarative samples and handling of non-pydantic response formats * fixed from comments * update docstring
This commit is contained in:
committed by
GitHub
Unverified
parent
6acab3d1d6
commit
519bb0cb2b
@@ -1912,9 +1912,7 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
args["usage_details"] = usage_details
|
||||
if structured_response:
|
||||
args["value"] = structured_response
|
||||
elif (response_format := options.get("response_format")) and isinstance(response_format, type):
|
||||
# Only pass response_format to ChatResponse if it's a Pydantic model type,
|
||||
# not a runtime JSON schema dict
|
||||
elif response_format := options.get("response_format"):
|
||||
args["response_format"] = response_format
|
||||
# Set continuation_token when background operation is still in progress
|
||||
if response.status and response.status in ("in_progress", "queued"):
|
||||
|
||||
@@ -485,6 +485,46 @@ async def test_response_format_parse_path_with_conversation_id() -> None:
|
||||
assert response.model == "test-model"
|
||||
|
||||
|
||||
async def test_response_format_dict_parse_path() -> None:
|
||||
"""Test get_response response_format parsing path for runtime JSON schema mappings."""
|
||||
client = OpenAIChatClient(model="test-model", api_key="test-key")
|
||||
response_format = {"type": "object", "properties": {"answer": {"type": "string"}}}
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.id = "response_123"
|
||||
mock_response.model = "test-model"
|
||||
mock_response.created_at = 1000000000
|
||||
mock_response.metadata = {}
|
||||
mock_response.output_parsed = None
|
||||
mock_response.output = []
|
||||
mock_response.usage = None
|
||||
mock_response.finish_reason = None
|
||||
mock_response.conversation = None
|
||||
mock_response.status = "completed"
|
||||
|
||||
mock_message_content = MagicMock()
|
||||
mock_message_content.type = "output_text"
|
||||
mock_message_content.text = '{"answer": "Parsed"}'
|
||||
mock_message_content.annotations = []
|
||||
mock_message_content.logprobs = None
|
||||
|
||||
mock_message_item = MagicMock()
|
||||
mock_message_item.type = "message"
|
||||
mock_message_item.content = [mock_message_content]
|
||||
mock_response.output = [mock_message_item]
|
||||
|
||||
with patch.object(client.client.responses, "create", return_value=mock_response):
|
||||
response = await client.get_response(
|
||||
messages=[Message(role="user", text="Test message")],
|
||||
options={"response_format": response_format},
|
||||
)
|
||||
|
||||
assert response.response_id == "response_123"
|
||||
assert response.value is not None
|
||||
assert isinstance(response.value, dict)
|
||||
assert response.value["answer"] == "Parsed"
|
||||
|
||||
|
||||
async def test_bad_request_error_non_content_filter() -> None:
|
||||
"""Test get_response BadRequestError without content_filter."""
|
||||
client = OpenAIChatClient(model="test-model", api_key="test-key")
|
||||
@@ -3297,12 +3337,10 @@ async def test_integration_options(
|
||||
assert isinstance(response.value, OutputStruct)
|
||||
assert "seattle" in response.value.location.lower()
|
||||
else:
|
||||
# Runtime JSON schema
|
||||
assert response.value is None, "No structured output, can't parse any json."
|
||||
response_value = json.loads(response.text)
|
||||
assert isinstance(response_value, dict)
|
||||
assert "location" in response_value
|
||||
assert "seattle" in response_value["location"].lower()
|
||||
assert response.value is not None
|
||||
assert isinstance(response.value, dict)
|
||||
assert "location" in response.value
|
||||
assert "seattle" in response.value["location"].lower()
|
||||
|
||||
|
||||
@pytest.mark.timeout(300)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from functools import wraps
|
||||
from pathlib import Path
|
||||
@@ -322,11 +321,10 @@ async def test_integration_options(
|
||||
assert isinstance(response.value, OutputStruct)
|
||||
assert "seattle" in response.value.location.lower()
|
||||
else:
|
||||
assert response.value is None
|
||||
response_value = json.loads(response.text)
|
||||
assert isinstance(response_value, dict)
|
||||
assert "location" in response_value
|
||||
assert "seattle" in response_value["location"].lower()
|
||||
assert response.value is not None
|
||||
assert isinstance(response.value, dict)
|
||||
assert "location" in response.value
|
||||
assert "seattle" in response.value["location"].lower()
|
||||
|
||||
|
||||
@pytest.mark.flaky
|
||||
|
||||
@@ -1421,6 +1421,31 @@ def test_response_format_dict_passthrough(openai_unit_test_env: dict[str, str])
|
||||
assert prepared_options["response_format"] == custom_format
|
||||
|
||||
|
||||
def test_parse_response_with_dict_response_format(openai_unit_test_env: dict[str, str]) -> None:
|
||||
"""Chat completions should parse dict response_format values into response.value."""
|
||||
client = OpenAIChatCompletionClient()
|
||||
response = client._parse_response_from_openai(
|
||||
ChatCompletion(
|
||||
id="test-response",
|
||||
object="chat.completion",
|
||||
created=1234567890,
|
||||
model="gpt-4o-mini",
|
||||
choices=[
|
||||
Choice(
|
||||
index=0,
|
||||
message=ChatCompletionMessage(role="assistant", content='{"answer": "Hello"}'),
|
||||
finish_reason="stop",
|
||||
)
|
||||
],
|
||||
),
|
||||
options={"response_format": {"type": "object", "properties": {"answer": {"type": "string"}}}},
|
||||
)
|
||||
|
||||
assert response.value is not None
|
||||
assert isinstance(response.value, dict)
|
||||
assert response.value["answer"] == "Hello"
|
||||
|
||||
|
||||
def test_multiple_function_calls_in_single_message(
|
||||
openai_unit_test_env: dict[str, str],
|
||||
) -> None:
|
||||
@@ -1635,12 +1660,10 @@ async def test_integration_options(
|
||||
assert isinstance(response.value, OutputStruct)
|
||||
assert "seattle" in response.value.location.lower()
|
||||
else:
|
||||
# Runtime JSON schema
|
||||
assert response.value is None, "No structured output, can't parse any json."
|
||||
response_value = json.loads(response.text)
|
||||
assert isinstance(response_value, dict)
|
||||
assert "location" in response_value
|
||||
assert "seattle" in response_value["location"].lower()
|
||||
assert response.value is not None
|
||||
assert isinstance(response.value, dict)
|
||||
assert "location" in response.value
|
||||
assert "seattle" in response.value["location"].lower()
|
||||
|
||||
|
||||
@pytest.mark.flaky
|
||||
|
||||
Reference in New Issue
Block a user