mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: [BREAKING] Simplify API: ChatAgent -> Agent, ChatMessage -> Message (#3747)
* [BREAKING] Rename ChatAgent -> Agent, ChatMessage -> Message, ChatClientProtocol -> SupportsChatGetResponse Simplify the public API by removing redundant 'Chat' prefix from core types: - ChatAgent -> Agent - RawChatAgent -> RawAgent - ChatMessage -> Message - ChatClientProtocol -> SupportsChatGetResponse Also renamed internal WorkflowMessage (was Message in _runner_context) to avoid collision. No backward compatibility aliases - this is a clean breaking change. * [BREAKING] Rename Agent chat_client parameter to client * Fix rebase issues: WorkflowMessage references and broken markdown links * Fix formatting and lint issues from code quality checks * Fix import ordering in workflow sample files * fixed rebase * Fix test failures: use WorkflowMessage and A2AMessage after ChatMessage→Message rename - Replace Message(data=..., source_id=...) with WorkflowMessage(...) in workflow tests - Fix isinstance check in A2A agent to use A2AMessage instead of Message - Fix import in test_workflow_observability.py (Message→WorkflowMessage) * Fix lint, fmt, and sample errors after ChatMessage→Message rename - Auto-fix 70+ ruff lint issues across samples (ChatMessage→Message refs) - Fix HostedVectorStoreContent→Content.from_hosted_vector_store in file search sample - Fix _normalize_messages→normalize_messages in custom agent sample - Fix context.terminate→raise MiddlewareTermination in middleware samples - Fix with_update_hook→with_transform_hook in override middleware sample - Add TOptions_co import back to custom_chat_client sample - Add noqa for FastAPI File() default in chatkit sample - Fix B023 loop variable capture in weather agent sample * fix: update Agent constructor calls from chat_client to client in declaration-only tool tests * fix: add register_cleanup to devui lazy-loading proxy and type stub * fixed tests and updated new pieces * fix agui typevar * fix merge errors * fix merge conflicts * fiux merge * Remove unused links --------- Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
a4c9e43afb
commit
0521f5bed8
@@ -8,7 +8,7 @@ import pytest
|
||||
from openai.types.beta.assistant import Assistant
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from agent_framework import ChatAgent, HostedCodeInterpreterTool, HostedFileSearchTool, normalize_tools, tool
|
||||
from agent_framework import Agent, HostedCodeInterpreterTool, HostedFileSearchTool, normalize_tools, tool
|
||||
from agent_framework.exceptions import ServiceInitializationError
|
||||
from agent_framework.openai import OpenAIAssistantProvider
|
||||
from agent_framework.openai._shared import from_assistant_tools, to_assistant_tools
|
||||
@@ -202,7 +202,7 @@ class TestOpenAIAssistantProviderCreateAgent:
|
||||
instructions="You are helpful.",
|
||||
)
|
||||
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
assert agent.name == "CreatedAssistant"
|
||||
mock_async_openai.beta.assistants.create.assert_called_once()
|
||||
|
||||
@@ -235,7 +235,7 @@ class TestOpenAIAssistantProviderCreateAgent:
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
|
||||
# Verify tools were passed to create
|
||||
call_kwargs = mock_async_openai.beta.assistants.create.call_args.kwargs
|
||||
@@ -343,7 +343,7 @@ class TestOpenAIAssistantProviderCreateAgent:
|
||||
assert call_kwargs["response_format"]["json_schema"]["name"] == "WeatherResponse"
|
||||
|
||||
async def test_create_agent_returns_chat_agent(self, mock_async_openai: MagicMock) -> None:
|
||||
"""Test that create_agent returns a ChatAgent instance."""
|
||||
"""Test that create_agent returns a Agent instance."""
|
||||
provider = OpenAIAssistantProvider(mock_async_openai)
|
||||
|
||||
agent = await provider.create_agent(
|
||||
@@ -351,7 +351,7 @@ class TestOpenAIAssistantProviderCreateAgent:
|
||||
model="gpt-4",
|
||||
)
|
||||
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
|
||||
|
||||
# endregion
|
||||
@@ -369,7 +369,7 @@ class TestOpenAIAssistantProviderGetAgent:
|
||||
|
||||
agent = await provider.get_agent(assistant_id="asst_123")
|
||||
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
mock_async_openai.beta.assistants.retrieve.assert_called_once_with("asst_123")
|
||||
|
||||
async def test_get_agent_with_instructions_override(self, mock_async_openai: MagicMock) -> None:
|
||||
@@ -382,7 +382,7 @@ class TestOpenAIAssistantProviderGetAgent:
|
||||
)
|
||||
|
||||
# Agent should be created successfully with the custom instructions
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
assert agent.id == "asst_retrieved123"
|
||||
|
||||
async def test_get_agent_with_function_tools(self, mock_async_openai: MagicMock) -> None:
|
||||
@@ -398,7 +398,7 @@ class TestOpenAIAssistantProviderGetAgent:
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
|
||||
async def test_get_agent_validates_missing_function_tools(self, mock_async_openai: MagicMock) -> None:
|
||||
"""Test that missing function tools raise ValueError."""
|
||||
@@ -439,7 +439,7 @@ class TestOpenAIAssistantProviderGetAgent:
|
||||
agent = await provider.get_agent(assistant_id="asst_123")
|
||||
|
||||
# Hosted tools should be merged automatically
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
|
||||
|
||||
# endregion
|
||||
@@ -458,7 +458,7 @@ class TestOpenAIAssistantProviderAsAgent:
|
||||
|
||||
agent = provider.as_agent(assistant)
|
||||
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
# Verify no HTTP calls were made
|
||||
mock_async_openai.beta.assistants.create.assert_not_called()
|
||||
mock_async_openai.beta.assistants.retrieve.assert_not_called()
|
||||
@@ -477,7 +477,7 @@ class TestOpenAIAssistantProviderAsAgent:
|
||||
assert agent.id == "asst_wrap123"
|
||||
assert agent.name == "WrappedAssistant"
|
||||
# Instructions are passed to ChatOptions, not exposed as attribute
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
|
||||
def test_as_agent_with_instructions_override(self, mock_async_openai: MagicMock) -> None:
|
||||
"""Test as_agent with instruction override."""
|
||||
@@ -487,7 +487,7 @@ class TestOpenAIAssistantProviderAsAgent:
|
||||
agent = provider.as_agent(assistant, instructions="Override")
|
||||
|
||||
# Agent should be created successfully with override instructions
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
|
||||
def test_as_agent_validates_function_tools(self, mock_async_openai: MagicMock) -> None:
|
||||
"""Test that missing function tools raise ValueError."""
|
||||
@@ -506,7 +506,7 @@ class TestOpenAIAssistantProviderAsAgent:
|
||||
|
||||
agent = provider.as_agent(assistant, tools=[get_weather])
|
||||
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
|
||||
def test_as_agent_merges_hosted_tools(self, mock_async_openai: MagicMock) -> None:
|
||||
"""Test that hosted tools are merged automatically."""
|
||||
@@ -515,7 +515,7 @@ class TestOpenAIAssistantProviderAsAgent:
|
||||
|
||||
agent = provider.as_agent(assistant)
|
||||
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
|
||||
def test_as_agent_hosted_tools_not_required(self, mock_async_openai: MagicMock) -> None:
|
||||
"""Test that hosted tools don't require user implementations."""
|
||||
@@ -525,7 +525,7 @@ class TestOpenAIAssistantProviderAsAgent:
|
||||
# Should not raise - hosted tools don't need implementations
|
||||
agent = provider.as_agent(assistant)
|
||||
|
||||
assert isinstance(agent, ChatAgent)
|
||||
assert isinstance(agent, Agent)
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
@@ -11,17 +11,17 @@ from openai.types.beta.threads.runs import RunStep
|
||||
from pydantic import Field
|
||||
|
||||
from agent_framework import (
|
||||
Agent,
|
||||
AgentResponse,
|
||||
AgentResponseUpdate,
|
||||
AgentThread,
|
||||
ChatAgent,
|
||||
ChatClientProtocol,
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
ChatResponseUpdate,
|
||||
Content,
|
||||
HostedCodeInterpreterTool,
|
||||
HostedFileSearchTool,
|
||||
Message,
|
||||
SupportsChatGetResponse,
|
||||
tool,
|
||||
)
|
||||
from agent_framework.exceptions import ServiceInitializationError
|
||||
@@ -113,16 +113,16 @@ def mock_async_openai() -> MagicMock:
|
||||
|
||||
def test_init_with_client(mock_async_openai: MagicMock) -> None:
|
||||
"""Test OpenAIAssistantsClient initialization with existing client."""
|
||||
chat_client = create_test_openai_assistants_client(
|
||||
client = create_test_openai_assistants_client(
|
||||
mock_async_openai, model_id="gpt-4", assistant_id="existing-assistant-id", thread_id="test-thread-id"
|
||||
)
|
||||
|
||||
assert chat_client.client is mock_async_openai
|
||||
assert chat_client.model_id == "gpt-4"
|
||||
assert chat_client.assistant_id == "existing-assistant-id"
|
||||
assert chat_client.thread_id == "test-thread-id"
|
||||
assert not chat_client._should_delete_assistant # type: ignore
|
||||
assert isinstance(chat_client, ChatClientProtocol)
|
||||
assert client.client is mock_async_openai
|
||||
assert client.model_id == "gpt-4"
|
||||
assert client.assistant_id == "existing-assistant-id"
|
||||
assert client.thread_id == "test-thread-id"
|
||||
assert not client._should_delete_assistant # type: ignore
|
||||
assert isinstance(client, SupportsChatGetResponse)
|
||||
|
||||
|
||||
def test_init_auto_create_client(
|
||||
@@ -130,7 +130,7 @@ def test_init_auto_create_client(
|
||||
mock_async_openai: MagicMock,
|
||||
) -> None:
|
||||
"""Test OpenAIAssistantsClient initialization with auto-created client."""
|
||||
chat_client = OpenAIAssistantsClient(
|
||||
client = OpenAIAssistantsClient(
|
||||
model_id=openai_unit_test_env["OPENAI_CHAT_MODEL_ID"],
|
||||
assistant_name="TestAssistant",
|
||||
api_key=openai_unit_test_env["OPENAI_API_KEY"],
|
||||
@@ -138,11 +138,11 @@ def test_init_auto_create_client(
|
||||
async_client=mock_async_openai,
|
||||
)
|
||||
|
||||
assert chat_client.client is mock_async_openai
|
||||
assert chat_client.model_id == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
|
||||
assert chat_client.assistant_id is None
|
||||
assert chat_client.assistant_name == "TestAssistant"
|
||||
assert not chat_client._should_delete_assistant # type: ignore
|
||||
assert client.client is mock_async_openai
|
||||
assert client.model_id == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
|
||||
assert client.assistant_id is None
|
||||
assert client.assistant_name == "TestAssistant"
|
||||
assert not client._should_delete_assistant # type: ignore
|
||||
|
||||
|
||||
def test_init_validation_fail() -> None:
|
||||
@@ -172,31 +172,31 @@ def test_init_with_default_headers(openai_unit_test_env: dict[str, str]) -> None
|
||||
"""Test OpenAIAssistantsClient initialization with default headers."""
|
||||
default_headers = {"X-Unit-Test": "test-guid"}
|
||||
|
||||
chat_client = OpenAIAssistantsClient(
|
||||
client = OpenAIAssistantsClient(
|
||||
model_id="gpt-4",
|
||||
api_key=openai_unit_test_env["OPENAI_API_KEY"],
|
||||
default_headers=default_headers,
|
||||
)
|
||||
|
||||
assert chat_client.model_id == "gpt-4"
|
||||
assert isinstance(chat_client, ChatClientProtocol)
|
||||
assert client.model_id == "gpt-4"
|
||||
assert isinstance(client, SupportsChatGetResponse)
|
||||
|
||||
# Assert that the default header we added is present in the client's default headers
|
||||
for key, value in default_headers.items():
|
||||
assert key in chat_client.client.default_headers
|
||||
assert chat_client.client.default_headers[key] == value
|
||||
assert key in client.client.default_headers
|
||||
assert client.client.default_headers[key] == value
|
||||
|
||||
|
||||
async def test_get_assistant_id_or_create_existing_assistant(
|
||||
mock_async_openai: MagicMock,
|
||||
) -> None:
|
||||
"""Test _get_assistant_id_or_create when assistant_id is already provided."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai, assistant_id="existing-assistant-id")
|
||||
client = create_test_openai_assistants_client(mock_async_openai, assistant_id="existing-assistant-id")
|
||||
|
||||
assistant_id = await chat_client._get_assistant_id_or_create() # type: ignore
|
||||
assistant_id = await client._get_assistant_id_or_create() # type: ignore
|
||||
|
||||
assert assistant_id == "existing-assistant-id"
|
||||
assert not chat_client._should_delete_assistant # type: ignore
|
||||
assert not client._should_delete_assistant # type: ignore
|
||||
mock_async_openai.beta.assistants.create.assert_not_called()
|
||||
|
||||
|
||||
@@ -204,14 +204,12 @@ async def test_get_assistant_id_or_create_create_new(
|
||||
mock_async_openai: MagicMock,
|
||||
) -> None:
|
||||
"""Test _get_assistant_id_or_create when creating a new assistant."""
|
||||
chat_client = create_test_openai_assistants_client(
|
||||
mock_async_openai, model_id="gpt-4", assistant_name="TestAssistant"
|
||||
)
|
||||
client = create_test_openai_assistants_client(mock_async_openai, model_id="gpt-4", assistant_name="TestAssistant")
|
||||
|
||||
assistant_id = await chat_client._get_assistant_id_or_create() # type: ignore
|
||||
assistant_id = await client._get_assistant_id_or_create() # type: ignore
|
||||
|
||||
assert assistant_id == "test-assistant-id"
|
||||
assert chat_client._should_delete_assistant # type: ignore
|
||||
assert client._should_delete_assistant # type: ignore
|
||||
mock_async_openai.beta.assistants.create.assert_called_once()
|
||||
|
||||
|
||||
@@ -219,38 +217,38 @@ async def test_aclose_should_not_delete(
|
||||
mock_async_openai: MagicMock,
|
||||
) -> None:
|
||||
"""Test close when assistant should not be deleted."""
|
||||
chat_client = create_test_openai_assistants_client(
|
||||
client = create_test_openai_assistants_client(
|
||||
mock_async_openai, assistant_id="assistant-to-keep", should_delete_assistant=False
|
||||
)
|
||||
|
||||
await chat_client.close() # type: ignore
|
||||
await client.close() # type: ignore
|
||||
|
||||
# Verify assistant deletion was not called
|
||||
mock_async_openai.beta.assistants.delete.assert_not_called()
|
||||
assert not chat_client._should_delete_assistant # type: ignore
|
||||
assert not client._should_delete_assistant # type: ignore
|
||||
|
||||
|
||||
async def test_aclose_should_delete(mock_async_openai: MagicMock) -> None:
|
||||
"""Test close method calls cleanup."""
|
||||
chat_client = create_test_openai_assistants_client(
|
||||
client = create_test_openai_assistants_client(
|
||||
mock_async_openai, assistant_id="assistant-to-delete", should_delete_assistant=True
|
||||
)
|
||||
|
||||
await chat_client.close()
|
||||
await client.close()
|
||||
|
||||
# Verify assistant deletion was called
|
||||
mock_async_openai.beta.assistants.delete.assert_called_once_with("assistant-to-delete")
|
||||
assert not chat_client._should_delete_assistant # type: ignore
|
||||
assert not client._should_delete_assistant # type: ignore
|
||||
|
||||
|
||||
async def test_async_context_manager(mock_async_openai: MagicMock) -> None:
|
||||
"""Test async context manager functionality."""
|
||||
chat_client = create_test_openai_assistants_client(
|
||||
client = create_test_openai_assistants_client(
|
||||
mock_async_openai, assistant_id="assistant-to-delete", should_delete_assistant=True
|
||||
)
|
||||
|
||||
# Test context manager
|
||||
async with chat_client:
|
||||
async with client:
|
||||
pass # Just test that we can enter and exit
|
||||
|
||||
# Verify cleanup was called on exit
|
||||
@@ -262,7 +260,7 @@ def test_serialize(openai_unit_test_env: dict[str, str]) -> None:
|
||||
default_headers = {"X-Unit-Test": "test-guid"}
|
||||
|
||||
# Test basic initialization and to_dict
|
||||
chat_client = OpenAIAssistantsClient(
|
||||
client = OpenAIAssistantsClient(
|
||||
model_id="gpt-4",
|
||||
assistant_id="test-assistant-id",
|
||||
assistant_name="TestAssistant",
|
||||
@@ -272,7 +270,7 @@ def test_serialize(openai_unit_test_env: dict[str, str]) -> None:
|
||||
default_headers=default_headers,
|
||||
)
|
||||
|
||||
dumped_settings = chat_client.to_dict()
|
||||
dumped_settings = client.to_dict()
|
||||
|
||||
assert dumped_settings["model_id"] == "gpt-4"
|
||||
assert dumped_settings["assistant_id"] == "test-assistant-id"
|
||||
@@ -290,9 +288,9 @@ def test_serialize(openai_unit_test_env: dict[str, str]) -> None:
|
||||
|
||||
async def test_get_active_thread_run_none_thread_id(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _get_active_thread_run with None thread_id returns None."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
result = await chat_client._get_active_thread_run(None) # type: ignore
|
||||
result = await client._get_active_thread_run(None) # type: ignore
|
||||
|
||||
assert result is None
|
||||
# Should not call the API when thread_id is None
|
||||
@@ -302,7 +300,7 @@ async def test_get_active_thread_run_none_thread_id(mock_async_openai: MagicMock
|
||||
async def test_get_active_thread_run_with_active_run(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _get_active_thread_run finds an active run."""
|
||||
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Mock an active run (status not in completed states)
|
||||
mock_run = MagicMock()
|
||||
@@ -314,7 +312,7 @@ async def test_get_active_thread_run_with_active_run(mock_async_openai: MagicMoc
|
||||
|
||||
mock_async_openai.beta.threads.runs.list.return_value.__aiter__ = mock_runs_list
|
||||
|
||||
result = await chat_client._get_active_thread_run("thread-123") # type: ignore
|
||||
result = await client._get_active_thread_run("thread-123") # type: ignore
|
||||
|
||||
assert result == mock_run
|
||||
mock_async_openai.beta.threads.runs.list.assert_called_once_with(thread_id="thread-123", limit=1, order="desc")
|
||||
@@ -322,7 +320,7 @@ async def test_get_active_thread_run_with_active_run(mock_async_openai: MagicMoc
|
||||
|
||||
async def test_prepare_thread_create_new(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_thread creates new thread when thread_id is None."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Mock thread creation
|
||||
mock_thread = MagicMock()
|
||||
@@ -336,7 +334,7 @@ async def test_prepare_thread_create_new(mock_async_openai: MagicMock) -> None:
|
||||
"metadata": {"test": "true"},
|
||||
}
|
||||
|
||||
result = await chat_client._prepare_thread(None, None, run_options) # type: ignore
|
||||
result = await client._prepare_thread(None, None, run_options) # type: ignore
|
||||
|
||||
assert result == "new-thread-123"
|
||||
assert run_options["additional_messages"] == [] # Should be cleared
|
||||
@@ -349,7 +347,7 @@ async def test_prepare_thread_create_new(mock_async_openai: MagicMock) -> None:
|
||||
|
||||
async def test_prepare_thread_cancel_existing_run(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_thread cancels existing run when provided."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Mock an existing thread run
|
||||
mock_thread_run = MagicMock()
|
||||
@@ -357,7 +355,7 @@ async def test_prepare_thread_cancel_existing_run(mock_async_openai: MagicMock)
|
||||
|
||||
run_options: dict[str, Any] = {"additional_messages": []}
|
||||
|
||||
result = await chat_client._prepare_thread("thread-123", mock_thread_run, run_options) # type: ignore
|
||||
result = await client._prepare_thread("thread-123", mock_thread_run, run_options) # type: ignore
|
||||
|
||||
assert result == "thread-123"
|
||||
mock_async_openai.beta.threads.runs.cancel.assert_called_once_with(run_id="run-456", thread_id="thread-123")
|
||||
@@ -365,11 +363,11 @@ async def test_prepare_thread_cancel_existing_run(mock_async_openai: MagicMock)
|
||||
|
||||
async def test_prepare_thread_existing_no_run(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_thread with existing thread_id but no active run."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
run_options: dict[str, list[dict[str, str]]] = {"additional_messages": []}
|
||||
|
||||
result = await chat_client._prepare_thread("thread-123", None, run_options) # type: ignore
|
||||
result = await client._prepare_thread("thread-123", None, run_options) # type: ignore
|
||||
|
||||
assert result == "thread-123"
|
||||
# Should not call cancel since no thread_run provided
|
||||
@@ -378,7 +376,7 @@ async def test_prepare_thread_existing_no_run(mock_async_openai: MagicMock) -> N
|
||||
|
||||
async def test_process_stream_events_thread_run_created(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _process_stream_events with thread.run.created event."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a mock stream response for thread.run.created
|
||||
mock_response = MagicMock()
|
||||
@@ -396,7 +394,7 @@ async def test_process_stream_events_thread_run_created(mock_async_openai: Magic
|
||||
|
||||
thread_id = "thread-123"
|
||||
updates: list[ChatResponseUpdate] = []
|
||||
async for update in chat_client._process_stream_events(mock_stream, thread_id): # type: ignore
|
||||
async for update in client._process_stream_events(mock_stream, thread_id): # type: ignore
|
||||
updates.append(update)
|
||||
|
||||
# Should yield one ChatResponseUpdate for thread.run.created
|
||||
@@ -411,7 +409,7 @@ async def test_process_stream_events_thread_run_created(mock_async_openai: Magic
|
||||
|
||||
async def test_process_stream_events_message_delta_text(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _process_stream_events with thread.message.delta event containing text."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a mock TextDeltaBlock with proper spec
|
||||
mock_delta_block = MagicMock(spec=TextDeltaBlock)
|
||||
@@ -440,7 +438,7 @@ async def test_process_stream_events_message_delta_text(mock_async_openai: Magic
|
||||
|
||||
thread_id = "thread-456"
|
||||
updates: list[ChatResponseUpdate] = []
|
||||
async for update in chat_client._process_stream_events(mock_stream, thread_id): # type: ignore
|
||||
async for update in client._process_stream_events(mock_stream, thread_id): # type: ignore
|
||||
updates.append(update)
|
||||
|
||||
# Should yield one text update
|
||||
@@ -455,11 +453,11 @@ async def test_process_stream_events_message_delta_text(mock_async_openai: Magic
|
||||
|
||||
async def test_process_stream_events_requires_action(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _process_stream_events with thread.run.requires_action event."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Mock the _parse_function_calls_from_assistants method to return test content
|
||||
test_function_content = Content.from_function_call(call_id="call-123", name="test_func", arguments={"arg": "value"})
|
||||
chat_client._parse_function_calls_from_assistants = MagicMock(return_value=[test_function_content]) # type: ignore
|
||||
client._parse_function_calls_from_assistants = MagicMock(return_value=[test_function_content]) # type: ignore
|
||||
|
||||
# Create a mock Run object
|
||||
mock_run = MagicMock(spec=Run)
|
||||
@@ -479,7 +477,7 @@ async def test_process_stream_events_requires_action(mock_async_openai: MagicMoc
|
||||
|
||||
thread_id = "thread-789"
|
||||
updates: list[ChatResponseUpdate] = []
|
||||
async for update in chat_client._process_stream_events(mock_stream, thread_id): # type: ignore
|
||||
async for update in client._process_stream_events(mock_stream, thread_id): # type: ignore
|
||||
updates.append(update)
|
||||
|
||||
# Should yield one function call update
|
||||
@@ -493,13 +491,13 @@ async def test_process_stream_events_requires_action(mock_async_openai: MagicMoc
|
||||
assert update.raw_representation == mock_run
|
||||
|
||||
# Verify _parse_function_calls_from_assistants was called correctly
|
||||
chat_client._parse_function_calls_from_assistants.assert_called_once_with(mock_run, None) # type: ignore
|
||||
client._parse_function_calls_from_assistants.assert_called_once_with(mock_run, None) # type: ignore
|
||||
|
||||
|
||||
async def test_process_stream_events_run_step_created(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _process_stream_events with thread.run.step.created event."""
|
||||
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a mock RunStep object
|
||||
mock_run_step = MagicMock(spec=RunStep)
|
||||
@@ -520,7 +518,7 @@ async def test_process_stream_events_run_step_created(mock_async_openai: MagicMo
|
||||
|
||||
thread_id = "thread-789"
|
||||
updates: list[ChatResponseUpdate] = []
|
||||
async for update in chat_client._process_stream_events(mock_stream, thread_id): # type: ignore
|
||||
async for update in client._process_stream_events(mock_stream, thread_id): # type: ignore
|
||||
updates.append(update)
|
||||
|
||||
# The run step creation itself doesn't yield an update,
|
||||
@@ -533,7 +531,7 @@ async def test_process_stream_events_run_completed_with_usage(
|
||||
) -> None:
|
||||
"""Test _process_stream_events with thread.run.completed event containing usage."""
|
||||
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a mock Run object with usage information
|
||||
mock_usage = MagicMock()
|
||||
@@ -559,7 +557,7 @@ async def test_process_stream_events_run_completed_with_usage(
|
||||
|
||||
thread_id = "thread-999"
|
||||
updates: list[ChatResponseUpdate] = []
|
||||
async for update in chat_client._process_stream_events(mock_stream, thread_id): # type: ignore
|
||||
async for update in client._process_stream_events(mock_stream, thread_id): # type: ignore
|
||||
updates.append(update)
|
||||
|
||||
# Should yield one usage update
|
||||
@@ -582,7 +580,7 @@ async def test_process_stream_events_run_completed_with_usage(
|
||||
def test_parse_function_calls_from_assistants_basic(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _parse_function_calls_from_assistants with a simple function call."""
|
||||
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a mock Run event that requires action
|
||||
mock_run = MagicMock()
|
||||
@@ -599,7 +597,7 @@ def test_parse_function_calls_from_assistants_basic(mock_async_openai: MagicMock
|
||||
|
||||
# Call the method
|
||||
response_id = "response_456"
|
||||
contents = chat_client._parse_function_calls_from_assistants(mock_run, response_id) # type: ignore
|
||||
contents = client._parse_function_calls_from_assistants(mock_run, response_id) # type: ignore
|
||||
|
||||
# Test that one function call content was created
|
||||
assert len(contents) == 1
|
||||
@@ -685,7 +683,7 @@ def test_parse_run_step_with_mcp_tool_call(mock_async_openai: MagicMock) -> None
|
||||
|
||||
def test_prepare_options_basic(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with basic chat options."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create basic chat options as a dict
|
||||
options = {
|
||||
@@ -695,10 +693,10 @@ def test_prepare_options_basic(mock_async_openai: MagicMock) -> None:
|
||||
"top_p": 0.9,
|
||||
}
|
||||
|
||||
messages = [ChatMessage(role="user", text="Hello")]
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
|
||||
# Call the method
|
||||
run_options, tool_results = chat_client._prepare_options(messages, options) # type: ignore
|
||||
run_options, tool_results = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
# Check basic options were set
|
||||
assert run_options["max_completion_tokens"] == 100
|
||||
@@ -711,7 +709,7 @@ def test_prepare_options_basic(mock_async_openai: MagicMock) -> None:
|
||||
def test_prepare_options_with_tool_tool(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with a FunctionTool."""
|
||||
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a simple function for testing and decorate it
|
||||
@tool(approval_mode="never_require")
|
||||
@@ -724,10 +722,10 @@ def test_prepare_options_with_tool_tool(mock_async_openai: MagicMock) -> None:
|
||||
"tool_choice": "auto",
|
||||
}
|
||||
|
||||
messages = [ChatMessage(role="user", text="Hello")]
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
|
||||
# Call the method
|
||||
run_options, tool_results = chat_client._prepare_options(messages, options) # type: ignore
|
||||
run_options, tool_results = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
# Check tools were set correctly
|
||||
assert "tools" in run_options
|
||||
@@ -739,7 +737,7 @@ def test_prepare_options_with_tool_tool(mock_async_openai: MagicMock) -> None:
|
||||
|
||||
def test_prepare_options_with_code_interpreter(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with HostedCodeInterpreterTool."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a real HostedCodeInterpreterTool
|
||||
code_tool = HostedCodeInterpreterTool()
|
||||
@@ -749,10 +747,10 @@ def test_prepare_options_with_code_interpreter(mock_async_openai: MagicMock) ->
|
||||
"tool_choice": "auto",
|
||||
}
|
||||
|
||||
messages = [ChatMessage(role="user", text="Calculate something")]
|
||||
messages = [Message(role="user", text="Calculate something")]
|
||||
|
||||
# Call the method
|
||||
run_options, tool_results = chat_client._prepare_options(messages, options) # type: ignore
|
||||
run_options, tool_results = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
# Check code interpreter tool was set correctly
|
||||
assert "tools" in run_options
|
||||
@@ -763,16 +761,16 @@ def test_prepare_options_with_code_interpreter(mock_async_openai: MagicMock) ->
|
||||
|
||||
def test_prepare_options_tool_choice_none(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with tool_choice set to 'none' and no tools."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
options = {
|
||||
"tool_choice": "none",
|
||||
}
|
||||
|
||||
messages = [ChatMessage(role="user", text="Hello")]
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
|
||||
# Call the method
|
||||
run_options, tool_results = chat_client._prepare_options(messages, options) # type: ignore
|
||||
run_options, tool_results = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
# Should set tool_choice to none - no tools because none were provided
|
||||
assert run_options["tool_choice"] == "none"
|
||||
@@ -785,7 +783,7 @@ def test_prepare_options_tool_choice_none_with_tools(mock_async_openai: MagicMoc
|
||||
When tool_choice='none', the model won't call tools, but tools should still
|
||||
be sent to the API so they're available for future turns in the conversation.
|
||||
"""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a function tool
|
||||
@tool(approval_mode="never_require")
|
||||
@@ -797,10 +795,10 @@ def test_prepare_options_tool_choice_none_with_tools(mock_async_openai: MagicMoc
|
||||
"tools": [test_func],
|
||||
}
|
||||
|
||||
messages = [ChatMessage(role="user", text="Hello")]
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
|
||||
# Call the method
|
||||
run_options, tool_results = chat_client._prepare_options(messages, options) # type: ignore
|
||||
run_options, tool_results = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
# Should set tool_choice to none BUT still include tools
|
||||
assert run_options["tool_choice"] == "none"
|
||||
@@ -810,7 +808,7 @@ def test_prepare_options_tool_choice_none_with_tools(mock_async_openai: MagicMoc
|
||||
|
||||
def test_prepare_options_required_function(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with required function tool choice."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a required function tool choice as dict
|
||||
tool_choice = {"mode": "required", "required_function_name": "specific_function"}
|
||||
@@ -819,10 +817,10 @@ def test_prepare_options_required_function(mock_async_openai: MagicMock) -> None
|
||||
"tool_choice": tool_choice,
|
||||
}
|
||||
|
||||
messages = [ChatMessage(role="user", text="Hello")]
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
|
||||
# Call the method
|
||||
run_options, tool_results = chat_client._prepare_options(messages, options) # type: ignore
|
||||
run_options, tool_results = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
# Check required function tool choice was set correctly
|
||||
expected_tool_choice = {
|
||||
@@ -835,7 +833,7 @@ def test_prepare_options_required_function(mock_async_openai: MagicMock) -> None
|
||||
def test_prepare_options_with_file_search_tool(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with HostedFileSearchTool."""
|
||||
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a HostedFileSearchTool with max_results
|
||||
file_search_tool = HostedFileSearchTool(max_results=10)
|
||||
@@ -845,10 +843,10 @@ def test_prepare_options_with_file_search_tool(mock_async_openai: MagicMock) ->
|
||||
"tool_choice": "auto",
|
||||
}
|
||||
|
||||
messages = [ChatMessage(role="user", text="Search for information")]
|
||||
messages = [Message(role="user", text="Search for information")]
|
||||
|
||||
# Call the method
|
||||
run_options, tool_results = chat_client._prepare_options(messages, options) # type: ignore
|
||||
run_options, tool_results = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
# Check file search tool was set correctly
|
||||
assert "tools" in run_options
|
||||
@@ -860,7 +858,7 @@ def test_prepare_options_with_file_search_tool(mock_async_openai: MagicMock) ->
|
||||
|
||||
def test_prepare_options_with_mapping_tool(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with MutableMapping tool."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create a tool as a MutableMapping (dict)
|
||||
mapping_tool = {"type": "custom_tool", "parameters": {"setting": "value"}}
|
||||
@@ -870,10 +868,10 @@ def test_prepare_options_with_mapping_tool(mock_async_openai: MagicMock) -> None
|
||||
"tool_choice": "auto",
|
||||
}
|
||||
|
||||
messages = [ChatMessage(role="user", text="Use custom tool")]
|
||||
messages = [Message(role="user", text="Use custom tool")]
|
||||
|
||||
# Call the method
|
||||
run_options, tool_results = chat_client._prepare_options(messages, options) # type: ignore
|
||||
run_options, tool_results = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
# Check mapping tool was set correctly
|
||||
assert "tools" in run_options
|
||||
@@ -891,11 +889,11 @@ def test_prepare_options_with_pydantic_response_format(mock_async_openai: MagicM
|
||||
value: int
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
messages = [ChatMessage(role="user", text="Test")]
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
messages = [Message(role="user", text="Test")]
|
||||
options = {"response_format": TestResponse}
|
||||
|
||||
run_options, _ = chat_client._prepare_options(messages, options) # type: ignore
|
||||
run_options, _ = client._prepare_options(messages, options) # type: ignore
|
||||
|
||||
assert "response_format" in run_options
|
||||
assert run_options["response_format"]["type"] == "json_schema"
|
||||
@@ -905,15 +903,15 @@ def test_prepare_options_with_pydantic_response_format(mock_async_openai: MagicM
|
||||
|
||||
def test_prepare_options_with_system_message(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with system message converted to instructions."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
messages = [
|
||||
ChatMessage(role="system", text="You are a helpful assistant."),
|
||||
ChatMessage(role="user", text="Hello"),
|
||||
Message(role="system", text="You are a helpful assistant."),
|
||||
Message(role="user", text="Hello"),
|
||||
]
|
||||
|
||||
# Call the method
|
||||
run_options, tool_results = chat_client._prepare_options(messages, {}) # type: ignore
|
||||
run_options, tool_results = client._prepare_options(messages, {}) # type: ignore
|
||||
|
||||
# Check that additional_messages only contains the user message
|
||||
# System message should be converted to instructions (though this is handled internally)
|
||||
@@ -925,14 +923,14 @@ def test_prepare_options_with_system_message(mock_async_openai: MagicMock) -> No
|
||||
def test_prepare_options_with_image_content(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_options with image content."""
|
||||
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create message with image content
|
||||
image_content = Content.from_uri(uri="https://example.com/image.jpg", media_type="image/jpeg")
|
||||
messages = [ChatMessage(role="user", contents=[image_content])]
|
||||
messages = [Message(role="user", contents=[image_content])]
|
||||
|
||||
# Call the method
|
||||
run_options, tool_results = chat_client._prepare_options(messages, {}) # type: ignore
|
||||
run_options, tool_results = client._prepare_options(messages, {}) # type: ignore
|
||||
|
||||
# Check that image content was processed
|
||||
assert "additional_messages" in run_options
|
||||
@@ -946,9 +944,9 @@ def test_prepare_options_with_image_content(mock_async_openai: MagicMock) -> Non
|
||||
|
||||
def test_prepare_tool_outputs_for_assistants_empty(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_tool_outputs_for_assistants with empty list."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
run_id, tool_outputs = chat_client._prepare_tool_outputs_for_assistants([]) # type: ignore
|
||||
run_id, tool_outputs = client._prepare_tool_outputs_for_assistants([]) # type: ignore
|
||||
|
||||
assert run_id is None
|
||||
assert tool_outputs is None
|
||||
@@ -956,12 +954,12 @@ def test_prepare_tool_outputs_for_assistants_empty(mock_async_openai: MagicMock)
|
||||
|
||||
def test_prepare_tool_outputs_for_assistants_valid(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _prepare_tool_outputs_for_assistants with valid function results."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
call_id = json.dumps(["run-123", "call-456"])
|
||||
function_result = Content.from_function_result(call_id=call_id, result="Function executed successfully")
|
||||
|
||||
run_id, tool_outputs = chat_client._prepare_tool_outputs_for_assistants([function_result]) # type: ignore
|
||||
run_id, tool_outputs = client._prepare_tool_outputs_for_assistants([function_result]) # type: ignore
|
||||
|
||||
assert run_id == "run-123"
|
||||
assert tool_outputs is not None
|
||||
@@ -974,7 +972,7 @@ def test_prepare_tool_outputs_for_assistants_mismatched_run_ids(
|
||||
mock_async_openai: MagicMock,
|
||||
) -> None:
|
||||
"""Test _prepare_tool_outputs_for_assistants with mismatched run IDs."""
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai)
|
||||
client = create_test_openai_assistants_client(mock_async_openai)
|
||||
|
||||
# Create function results with different run IDs
|
||||
call_id1 = json.dumps(["run-123", "call-456"])
|
||||
@@ -982,7 +980,7 @@ def test_prepare_tool_outputs_for_assistants_mismatched_run_ids(
|
||||
function_result1 = Content.from_function_result(call_id=call_id1, result="Result 1")
|
||||
function_result2 = Content.from_function_result(call_id=call_id2, result="Result 2")
|
||||
|
||||
run_id, tool_outputs = chat_client._prepare_tool_outputs_for_assistants([function_result1, function_result2]) # type: ignore
|
||||
run_id, tool_outputs = client._prepare_tool_outputs_for_assistants([function_result1, function_result2]) # type: ignore
|
||||
|
||||
# Should only process the first one since run IDs don't match
|
||||
assert run_id == "run-123"
|
||||
@@ -994,36 +992,36 @@ def test_prepare_tool_outputs_for_assistants_mismatched_run_ids(
|
||||
def test_update_agent_name_and_description(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _update_agent_name_and_description method updates assistant_name when not already set."""
|
||||
# Test updating agent name when assistant_name is None
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai, assistant_name=None)
|
||||
client = create_test_openai_assistants_client(mock_async_openai, assistant_name=None)
|
||||
|
||||
# Call the private method to update agent name
|
||||
chat_client._update_agent_name_and_description("New Assistant Name") # type: ignore
|
||||
client._update_agent_name_and_description("New Assistant Name") # type: ignore
|
||||
|
||||
assert chat_client.assistant_name == "New Assistant Name"
|
||||
assert client.assistant_name == "New Assistant Name"
|
||||
|
||||
|
||||
def test_update_agent_name_and_description_existing(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _update_agent_name_and_description method doesn't override existing assistant_name."""
|
||||
# Test that existing assistant_name is not overridden
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai, assistant_name="Existing Assistant")
|
||||
client = create_test_openai_assistants_client(mock_async_openai, assistant_name="Existing Assistant")
|
||||
|
||||
# Call the private method to update agent name
|
||||
chat_client._update_agent_name_and_description("New Assistant Name") # type: ignore
|
||||
client._update_agent_name_and_description("New Assistant Name") # type: ignore
|
||||
|
||||
# Should keep the existing name
|
||||
assert chat_client.assistant_name == "Existing Assistant"
|
||||
assert client.assistant_name == "Existing Assistant"
|
||||
|
||||
|
||||
def test_update_agent_name_and_description_none(mock_async_openai: MagicMock) -> None:
|
||||
"""Test _update_agent_name_and_description method with None agent_name parameter."""
|
||||
# Test that None agent_name doesn't change anything
|
||||
chat_client = create_test_openai_assistants_client(mock_async_openai, assistant_name=None)
|
||||
client = create_test_openai_assistants_client(mock_async_openai, assistant_name=None)
|
||||
|
||||
# Call the private method with None
|
||||
chat_client._update_agent_name_and_description(None) # type: ignore
|
||||
client._update_agent_name_and_description(None) # type: ignore
|
||||
|
||||
# Should remain None
|
||||
assert chat_client.assistant_name is None
|
||||
assert client.assistant_name is None
|
||||
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
@@ -1039,17 +1037,17 @@ def get_weather(
|
||||
async def test_get_response() -> None:
|
||||
"""Test OpenAI Assistants Client response."""
|
||||
async with OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL) as openai_assistants_client:
|
||||
assert isinstance(openai_assistants_client, ChatClientProtocol)
|
||||
assert isinstance(openai_assistants_client, SupportsChatGetResponse)
|
||||
|
||||
messages: list[ChatMessage] = []
|
||||
messages: list[Message] = []
|
||||
messages.append(
|
||||
ChatMessage(
|
||||
Message(
|
||||
role="user",
|
||||
text="The weather in Seattle is currently sunny with a high of 25°C. "
|
||||
"It's a beautiful day for outdoor activities.",
|
||||
)
|
||||
)
|
||||
messages.append(ChatMessage(role="user", text="What's the weather like today?"))
|
||||
messages.append(Message(role="user", text="What's the weather like today?"))
|
||||
|
||||
# Test that the client can be used to get a response
|
||||
response = await openai_assistants_client.get_response(messages=messages)
|
||||
@@ -1064,10 +1062,10 @@ async def test_get_response() -> None:
|
||||
async def test_get_response_tools() -> None:
|
||||
"""Test OpenAI Assistants Client response with tools."""
|
||||
async with OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL) as openai_assistants_client:
|
||||
assert isinstance(openai_assistants_client, ChatClientProtocol)
|
||||
assert isinstance(openai_assistants_client, SupportsChatGetResponse)
|
||||
|
||||
messages: list[ChatMessage] = []
|
||||
messages.append(ChatMessage(role="user", text="What's the weather like in Seattle?"))
|
||||
messages: list[Message] = []
|
||||
messages.append(Message(role="user", text="What's the weather like in Seattle?"))
|
||||
|
||||
# Test that the client can be used to get a response
|
||||
response = await openai_assistants_client.get_response(
|
||||
@@ -1085,17 +1083,17 @@ async def test_get_response_tools() -> None:
|
||||
async def test_streaming() -> None:
|
||||
"""Test OpenAI Assistants Client streaming response."""
|
||||
async with OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL) as openai_assistants_client:
|
||||
assert isinstance(openai_assistants_client, ChatClientProtocol)
|
||||
assert isinstance(openai_assistants_client, SupportsChatGetResponse)
|
||||
|
||||
messages: list[ChatMessage] = []
|
||||
messages: list[Message] = []
|
||||
messages.append(
|
||||
ChatMessage(
|
||||
Message(
|
||||
role="user",
|
||||
text="The weather in Seattle is currently sunny with a high of 25°C. "
|
||||
"It's a beautiful day for outdoor activities.",
|
||||
)
|
||||
)
|
||||
messages.append(ChatMessage(role="user", text="What's the weather like today?"))
|
||||
messages.append(Message(role="user", text="What's the weather like today?"))
|
||||
|
||||
# Test that the client can be used to get a response
|
||||
response = openai_assistants_client.get_response(stream=True, messages=messages)
|
||||
@@ -1116,10 +1114,10 @@ async def test_streaming() -> None:
|
||||
async def test_streaming_tools() -> None:
|
||||
"""Test OpenAI Assistants Client streaming response with tools."""
|
||||
async with OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL) as openai_assistants_client:
|
||||
assert isinstance(openai_assistants_client, ChatClientProtocol)
|
||||
assert isinstance(openai_assistants_client, SupportsChatGetResponse)
|
||||
|
||||
messages: list[ChatMessage] = []
|
||||
messages.append(ChatMessage(role="user", text="What's the weather like in Seattle?"))
|
||||
messages: list[Message] = []
|
||||
messages.append(Message(role="user", text="What's the weather like in Seattle?"))
|
||||
|
||||
# Test that the client can be used to get a response
|
||||
response = openai_assistants_client.get_response(
|
||||
@@ -1148,7 +1146,7 @@ async def test_with_existing_assistant() -> None:
|
||||
# First create an assistant to use in the test
|
||||
async with OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL) as temp_client:
|
||||
# Get the assistant ID by triggering assistant creation
|
||||
messages = [ChatMessage(role="user", text="Hello")]
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
await temp_client.get_response(messages=messages)
|
||||
assistant_id = temp_client.assistant_id
|
||||
|
||||
@@ -1156,10 +1154,10 @@ async def test_with_existing_assistant() -> None:
|
||||
async with OpenAIAssistantsClient(
|
||||
model_id=INTEGRATION_TEST_MODEL, assistant_id=assistant_id
|
||||
) as openai_assistants_client:
|
||||
assert isinstance(openai_assistants_client, ChatClientProtocol)
|
||||
assert isinstance(openai_assistants_client, SupportsChatGetResponse)
|
||||
assert openai_assistants_client.assistant_id == assistant_id
|
||||
|
||||
messages = [ChatMessage(role="user", text="What can you do?")]
|
||||
messages = [Message(role="user", text="What can you do?")]
|
||||
|
||||
# Test that the client can be used to get a response
|
||||
response = await openai_assistants_client.get_response(messages=messages)
|
||||
@@ -1175,10 +1173,10 @@ async def test_with_existing_assistant() -> None:
|
||||
async def test_file_search() -> None:
|
||||
"""Test OpenAI Assistants Client response."""
|
||||
async with OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL) as openai_assistants_client:
|
||||
assert isinstance(openai_assistants_client, ChatClientProtocol)
|
||||
assert isinstance(openai_assistants_client, SupportsChatGetResponse)
|
||||
|
||||
messages: list[ChatMessage] = []
|
||||
messages.append(ChatMessage(role="user", text="What's the weather like today?"))
|
||||
messages: list[Message] = []
|
||||
messages.append(Message(role="user", text="What's the weather like today?"))
|
||||
|
||||
file_id, vector_store = await create_vector_store(openai_assistants_client)
|
||||
response = await openai_assistants_client.get_response(
|
||||
@@ -1201,10 +1199,10 @@ async def test_file_search() -> None:
|
||||
async def test_file_search_streaming() -> None:
|
||||
"""Test OpenAI Assistants Client response."""
|
||||
async with OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL) as openai_assistants_client:
|
||||
assert isinstance(openai_assistants_client, ChatClientProtocol)
|
||||
assert isinstance(openai_assistants_client, SupportsChatGetResponse)
|
||||
|
||||
messages: list[ChatMessage] = []
|
||||
messages.append(ChatMessage(role="user", text="What's the weather like today?"))
|
||||
messages: list[Message] = []
|
||||
messages.append(Message(role="user", text="What's the weather like today?"))
|
||||
|
||||
file_id, vector_store = await create_vector_store(openai_assistants_client)
|
||||
response = openai_assistants_client.get_response(
|
||||
@@ -1232,9 +1230,9 @@ async def test_file_search_streaming() -> None:
|
||||
@pytest.mark.flaky
|
||||
@skip_if_openai_integration_tests_disabled
|
||||
async def test_openai_assistants_agent_basic_run():
|
||||
"""Test ChatAgent basic run functionality with OpenAIAssistantsClient."""
|
||||
async with ChatAgent(
|
||||
chat_client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
"""Test Agent basic run functionality with OpenAIAssistantsClient."""
|
||||
async with Agent(
|
||||
client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
) as agent:
|
||||
# Run a simple query
|
||||
response = await agent.run("Hello! Please respond with 'Hello World' exactly.")
|
||||
@@ -1249,9 +1247,9 @@ async def test_openai_assistants_agent_basic_run():
|
||||
@pytest.mark.flaky
|
||||
@skip_if_openai_integration_tests_disabled
|
||||
async def test_openai_assistants_agent_basic_run_streaming():
|
||||
"""Test ChatAgent basic streaming functionality with OpenAIAssistantsClient."""
|
||||
async with ChatAgent(
|
||||
chat_client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
"""Test Agent basic streaming functionality with OpenAIAssistantsClient."""
|
||||
async with Agent(
|
||||
client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
) as agent:
|
||||
# Run streaming query
|
||||
full_message: str = ""
|
||||
@@ -1269,9 +1267,9 @@ async def test_openai_assistants_agent_basic_run_streaming():
|
||||
@pytest.mark.flaky
|
||||
@skip_if_openai_integration_tests_disabled
|
||||
async def test_openai_assistants_agent_thread_persistence():
|
||||
"""Test ChatAgent thread persistence across runs with OpenAIAssistantsClient."""
|
||||
async with ChatAgent(
|
||||
chat_client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
"""Test Agent thread persistence across runs with OpenAIAssistantsClient."""
|
||||
async with Agent(
|
||||
client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
instructions="You are a helpful assistant with good memory.",
|
||||
) as agent:
|
||||
# Create a new thread that will be reused
|
||||
@@ -1298,12 +1296,12 @@ async def test_openai_assistants_agent_thread_persistence():
|
||||
@pytest.mark.flaky
|
||||
@skip_if_openai_integration_tests_disabled
|
||||
async def test_openai_assistants_agent_existing_thread_id():
|
||||
"""Test ChatAgent with existing thread ID to continue conversations across agent instances."""
|
||||
"""Test Agent with existing thread ID to continue conversations across agent instances."""
|
||||
# First, create a conversation and capture the thread ID
|
||||
existing_thread_id = None
|
||||
|
||||
async with ChatAgent(
|
||||
chat_client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
async with Agent(
|
||||
client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=[get_weather],
|
||||
) as agent:
|
||||
@@ -1322,8 +1320,8 @@ async def test_openai_assistants_agent_existing_thread_id():
|
||||
|
||||
# Now continue with the same thread ID in a new agent instance
|
||||
|
||||
async with ChatAgent(
|
||||
chat_client=OpenAIAssistantsClient(thread_id=existing_thread_id),
|
||||
async with Agent(
|
||||
client=OpenAIAssistantsClient(thread_id=existing_thread_id),
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=[get_weather],
|
||||
) as agent:
|
||||
@@ -1343,10 +1341,10 @@ async def test_openai_assistants_agent_existing_thread_id():
|
||||
@pytest.mark.flaky
|
||||
@skip_if_openai_integration_tests_disabled
|
||||
async def test_openai_assistants_agent_code_interpreter():
|
||||
"""Test ChatAgent with code interpreter through OpenAIAssistantsClient."""
|
||||
"""Test Agent with code interpreter through OpenAIAssistantsClient."""
|
||||
|
||||
async with ChatAgent(
|
||||
chat_client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
async with Agent(
|
||||
client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
instructions="You are a helpful assistant that can write and execute Python code.",
|
||||
tools=[HostedCodeInterpreterTool()],
|
||||
) as agent:
|
||||
@@ -1365,8 +1363,8 @@ async def test_openai_assistants_agent_code_interpreter():
|
||||
async def test_agent_level_tool_persistence():
|
||||
"""Test that agent-level tools persist across multiple runs with OpenAI Assistants Client."""
|
||||
|
||||
async with ChatAgent(
|
||||
chat_client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
async with Agent(
|
||||
client=OpenAIAssistantsClient(model_id=INTEGRATION_TEST_MODEL),
|
||||
instructions="You are a helpful assistant that uses available tools.",
|
||||
tools=[get_weather], # Agent-level tool
|
||||
) as agent:
|
||||
|
||||
@@ -13,11 +13,11 @@ from pydantic import BaseModel
|
||||
from pytest import param
|
||||
|
||||
from agent_framework import (
|
||||
ChatClientProtocol,
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
Content,
|
||||
HostedWebSearchTool,
|
||||
Message,
|
||||
SupportsChatGetResponse,
|
||||
ToolProtocol,
|
||||
prepare_function_call_results,
|
||||
tool,
|
||||
@@ -40,7 +40,7 @@ def test_init(openai_unit_test_env: dict[str, str]) -> None:
|
||||
open_ai_chat_completion = OpenAIChatClient()
|
||||
|
||||
assert open_ai_chat_completion.model_id == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
|
||||
assert isinstance(open_ai_chat_completion, ChatClientProtocol)
|
||||
assert isinstance(open_ai_chat_completion, SupportsChatGetResponse)
|
||||
|
||||
|
||||
def test_init_validation_fail() -> None:
|
||||
@@ -55,7 +55,7 @@ def test_init_model_id_constructor(openai_unit_test_env: dict[str, str]) -> None
|
||||
open_ai_chat_completion = OpenAIChatClient(model_id=model_id)
|
||||
|
||||
assert open_ai_chat_completion.model_id == model_id
|
||||
assert isinstance(open_ai_chat_completion, ChatClientProtocol)
|
||||
assert isinstance(open_ai_chat_completion, SupportsChatGetResponse)
|
||||
|
||||
|
||||
def test_init_with_default_header(openai_unit_test_env: dict[str, str]) -> None:
|
||||
@@ -67,7 +67,7 @@ def test_init_with_default_header(openai_unit_test_env: dict[str, str]) -> None:
|
||||
)
|
||||
|
||||
assert open_ai_chat_completion.model_id == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
|
||||
assert isinstance(open_ai_chat_completion, ChatClientProtocol)
|
||||
assert isinstance(open_ai_chat_completion, SupportsChatGetResponse)
|
||||
|
||||
# Assert that the default header we added is present in the client's default headers
|
||||
for key, value in default_headers.items():
|
||||
@@ -154,7 +154,7 @@ def test_serialize_with_org_id(openai_unit_test_env: dict[str, str]) -> None:
|
||||
async def test_content_filter_exception_handling(openai_unit_test_env: dict[str, str]) -> None:
|
||||
"""Test that content filter errors are properly handled."""
|
||||
client = OpenAIChatClient()
|
||||
messages = [ChatMessage(role="user", text="test message")]
|
||||
messages = [Message(role="user", text="test message")]
|
||||
|
||||
# Create a mock BadRequestError with content_filter code
|
||||
mock_response = MagicMock()
|
||||
@@ -209,7 +209,7 @@ def get_weather(location: str) -> str:
|
||||
async def test_exception_message_includes_original_error_details() -> None:
|
||||
"""Test that exception messages include original error details in the new format."""
|
||||
client = OpenAIChatClient(model_id="test-model", api_key="test-key")
|
||||
messages = [ChatMessage(role="user", text="test message")]
|
||||
messages = [Message(role="user", text="test message")]
|
||||
|
||||
mock_response = MagicMock()
|
||||
original_error_message = "Invalid API request format"
|
||||
@@ -283,7 +283,7 @@ def test_function_result_falsy_values_handling(openai_unit_test_env: dict[str, s
|
||||
client = OpenAIChatClient()
|
||||
|
||||
# Test with empty list (falsy but not None)
|
||||
message_with_empty_list = ChatMessage(
|
||||
message_with_empty_list = Message(
|
||||
role="tool", contents=[Content.from_function_result(call_id="call-123", result=[])]
|
||||
)
|
||||
|
||||
@@ -292,7 +292,7 @@ def test_function_result_falsy_values_handling(openai_unit_test_env: dict[str, s
|
||||
assert openai_messages[0]["content"] == "[]" # Empty list should be JSON serialized
|
||||
|
||||
# Test with empty string (falsy but not None)
|
||||
message_with_empty_string = ChatMessage(
|
||||
message_with_empty_string = Message(
|
||||
role="tool", contents=[Content.from_function_result(call_id="call-456", result="")]
|
||||
)
|
||||
|
||||
@@ -301,9 +301,7 @@ def test_function_result_falsy_values_handling(openai_unit_test_env: dict[str, s
|
||||
assert openai_messages[0]["content"] == "" # Empty string should be preserved
|
||||
|
||||
# Test with False (falsy but not None)
|
||||
message_with_false = ChatMessage(
|
||||
role="tool", contents=[Content.from_function_result(call_id="call-789", result=False)]
|
||||
)
|
||||
message_with_false = Message(role="tool", contents=[Content.from_function_result(call_id="call-789", result=False)])
|
||||
|
||||
openai_messages = client._prepare_message_for_openai(message_with_false)
|
||||
assert len(openai_messages) == 1
|
||||
@@ -319,7 +317,7 @@ def test_function_result_exception_handling(openai_unit_test_env: dict[str, str]
|
||||
|
||||
# Test with exception (no result)
|
||||
test_exception = ValueError("Test error message")
|
||||
message_with_exception = ChatMessage(
|
||||
message_with_exception = Message(
|
||||
role="tool",
|
||||
contents=[
|
||||
Content.from_function_result(call_id="call-123", result="Error: Function failed.", exception=test_exception)
|
||||
@@ -609,7 +607,7 @@ def test_prepare_message_with_text_reasoning_content(openai_unit_test_env: dict[
|
||||
reasoning_content = Content.from_text_reasoning(text=None, protected_data=json.dumps(mock_reasoning_data))
|
||||
|
||||
# Message must have other content first for reasoning to attach to
|
||||
message = ChatMessage(
|
||||
message = Message(
|
||||
role="assistant",
|
||||
contents=[
|
||||
Content.from_text(text="The answer is 42."),
|
||||
@@ -652,17 +650,17 @@ def test_function_approval_content_is_skipped_in_preparation(openai_unit_test_en
|
||||
)
|
||||
|
||||
# Test that approval request is skipped
|
||||
message_with_request = ChatMessage(role="assistant", contents=[approval_request])
|
||||
message_with_request = Message(role="assistant", contents=[approval_request])
|
||||
prepared_request = client._prepare_message_for_openai(message_with_request)
|
||||
assert len(prepared_request) == 0 # Should be empty - approval content is skipped
|
||||
|
||||
# Test that approval response is skipped
|
||||
message_with_response = ChatMessage(role="user", contents=[approval_response])
|
||||
message_with_response = Message(role="user", contents=[approval_response])
|
||||
prepared_response = client._prepare_message_for_openai(message_with_response)
|
||||
assert len(prepared_response) == 0 # Should be empty - approval content is skipped
|
||||
|
||||
# Test with mixed content - approval should be skipped, text should remain
|
||||
mixed_message = ChatMessage(
|
||||
mixed_message = Message(
|
||||
role="assistant",
|
||||
contents=[
|
||||
Content.from_text(text="I need approval for this action."),
|
||||
@@ -752,7 +750,7 @@ def test_prepare_options_without_model_id(openai_unit_test_env: dict[str, str])
|
||||
client = OpenAIChatClient()
|
||||
client.model_id = None # Remove model_id
|
||||
|
||||
messages = [ChatMessage(role="user", text="test")]
|
||||
messages = [Message(role="user", text="test")]
|
||||
|
||||
with pytest.raises(ValueError, match="model_id must be a non-empty string"):
|
||||
client._prepare_options(messages, {})
|
||||
@@ -786,7 +784,7 @@ def test_prepare_options_with_instructions(openai_unit_test_env: dict[str, str])
|
||||
"""Test that instructions are prepended as system message."""
|
||||
client = OpenAIChatClient()
|
||||
|
||||
messages = [ChatMessage(role="user", text="Hello")]
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
options = {"instructions": "You are a helpful assistant."}
|
||||
|
||||
prepared_options = client._prepare_options(messages, options)
|
||||
@@ -802,7 +800,7 @@ def test_prepare_message_with_author_name(openai_unit_test_env: dict[str, str])
|
||||
"""Test that author_name is included in prepared message."""
|
||||
client = OpenAIChatClient()
|
||||
|
||||
message = ChatMessage(
|
||||
message = Message(
|
||||
role="user",
|
||||
author_name="TestUser",
|
||||
contents=[Content.from_text(text="Hello")],
|
||||
@@ -819,7 +817,7 @@ def test_prepare_message_with_tool_result_author_name(openai_unit_test_env: dict
|
||||
client = OpenAIChatClient()
|
||||
|
||||
# Tool messages should not have 'name' field (it's for function name instead)
|
||||
message = ChatMessage(
|
||||
message = Message(
|
||||
role="tool",
|
||||
author_name="ShouldNotAppear",
|
||||
contents=[Content.from_function_result(call_id="call_123", result="result")],
|
||||
@@ -836,7 +834,7 @@ def test_tool_choice_required_with_function_name(openai_unit_test_env: dict[str,
|
||||
"""Test that tool_choice with required mode and function name is correctly prepared."""
|
||||
client = OpenAIChatClient()
|
||||
|
||||
messages = [ChatMessage(role="user", text="test")]
|
||||
messages = [Message(role="user", text="test")]
|
||||
options = {
|
||||
"tools": [get_weather],
|
||||
"tool_choice": {"mode": "required", "required_function_name": "get_weather"},
|
||||
@@ -854,7 +852,7 @@ def test_response_format_dict_passthrough(openai_unit_test_env: dict[str, str])
|
||||
"""Test that response_format as dict is passed through directly."""
|
||||
client = OpenAIChatClient()
|
||||
|
||||
messages = [ChatMessage(role="user", text="test")]
|
||||
messages = [Message(role="user", text="test")]
|
||||
custom_format = {
|
||||
"type": "json_schema",
|
||||
"json_schema": {"name": "Test", "schema": {"type": "object"}},
|
||||
@@ -872,7 +870,7 @@ def test_multiple_function_calls_in_single_message(openai_unit_test_env: dict[st
|
||||
client = OpenAIChatClient()
|
||||
|
||||
# Create message with multiple function calls
|
||||
message = ChatMessage(
|
||||
message = Message(
|
||||
role="assistant",
|
||||
contents=[
|
||||
Content.from_function_call(call_id="call_1", name="func_1", arguments='{"a": 1}'),
|
||||
@@ -894,7 +892,7 @@ def test_prepare_options_removes_parallel_tool_calls_when_no_tools(openai_unit_t
|
||||
"""Test that parallel_tool_calls is removed when no tools are present."""
|
||||
client = OpenAIChatClient()
|
||||
|
||||
messages = [ChatMessage(role="user", text="test")]
|
||||
messages = [Message(role="user", text="test")]
|
||||
options = {"allow_multiple_tool_calls": True}
|
||||
|
||||
prepared_options = client._prepare_options(messages, options)
|
||||
@@ -906,7 +904,7 @@ def test_prepare_options_removes_parallel_tool_calls_when_no_tools(openai_unit_t
|
||||
async def test_streaming_exception_handling(openai_unit_test_env: dict[str, str]) -> None:
|
||||
"""Test that streaming errors are properly handled."""
|
||||
client = OpenAIChatClient()
|
||||
messages = [ChatMessage(role="user", text="test")]
|
||||
messages = [Message(role="user", text="test")]
|
||||
|
||||
# Create a mock error during streaming
|
||||
mock_error = Exception("Streaming error")
|
||||
@@ -1004,14 +1002,14 @@ async def test_integration_options(
|
||||
# Prepare test message
|
||||
if option_name.startswith("tools") or option_name.startswith("tool_choice"):
|
||||
# Use weather-related prompt for tool tests
|
||||
messages = [ChatMessage(role="user", text="What is the weather in Seattle?")]
|
||||
messages = [Message(role="user", text="What is the weather in Seattle?")]
|
||||
elif option_name.startswith("response_format"):
|
||||
# Use prompt that works well with structured output
|
||||
messages = [ChatMessage(role="user", text="The weather in Seattle is sunny")]
|
||||
messages.append(ChatMessage(role="user", text="What is the weather in Seattle?"))
|
||||
messages = [Message(role="user", text="The weather in Seattle is sunny")]
|
||||
messages.append(Message(role="user", text="What is the weather in Seattle?"))
|
||||
else:
|
||||
# Generic prompt for simple options
|
||||
messages = [ChatMessage(role="user", text="Say 'Hello World' briefly.")]
|
||||
messages = [Message(role="user", text="Say 'Hello World' briefly.")]
|
||||
|
||||
# Build options dict
|
||||
options: dict[str, Any] = {option_name: option_value}
|
||||
|
||||
@@ -14,7 +14,7 @@ from openai.types.chat.chat_completion_chunk import ChoiceDelta as ChunkChoiceDe
|
||||
from openai.types.chat.chat_completion_message import ChatCompletionMessage
|
||||
from pydantic import BaseModel
|
||||
|
||||
from agent_framework import ChatMessage, ChatResponseUpdate
|
||||
from agent_framework import ChatResponseUpdate, Message
|
||||
from agent_framework.exceptions import (
|
||||
ServiceResponseException,
|
||||
)
|
||||
@@ -27,7 +27,7 @@ async def mock_async_process_chat_stream_response(_):
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def chat_history() -> list[ChatMessage]:
|
||||
def chat_history() -> list[Message]:
|
||||
return []
|
||||
|
||||
|
||||
@@ -64,12 +64,12 @@ def mock_streaming_chat_completion_response() -> AsyncStream[ChatCompletionChunk
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock)
|
||||
async def test_cmc(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
mock_chat_completion_response: ChatCompletion,
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
mock_create.return_value = mock_chat_completion_response
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
|
||||
openai_chat_completion = OpenAIChatClient()
|
||||
await openai_chat_completion.get_response(messages=chat_history)
|
||||
@@ -83,12 +83,12 @@ async def test_cmc(
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock)
|
||||
async def test_cmc_chat_options(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
mock_chat_completion_response: ChatCompletion,
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
mock_create.return_value = mock_chat_completion_response
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
|
||||
openai_chat_completion = OpenAIChatClient()
|
||||
await openai_chat_completion.get_response(
|
||||
@@ -104,12 +104,12 @@ async def test_cmc_chat_options(
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock)
|
||||
async def test_cmc_no_fcc_in_response(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
mock_chat_completion_response: ChatCompletion,
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
mock_create.return_value = mock_chat_completion_response
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
orig_chat_history = deepcopy(chat_history)
|
||||
|
||||
openai_chat_completion = OpenAIChatClient()
|
||||
@@ -126,12 +126,12 @@ async def test_cmc_no_fcc_in_response(
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock)
|
||||
async def test_cmc_structured_output_no_fcc(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
mock_chat_completion_response: ChatCompletion,
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
mock_create.return_value = mock_chat_completion_response
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
|
||||
# Define a mock response format
|
||||
class Test(BaseModel):
|
||||
@@ -148,12 +148,12 @@ async def test_cmc_structured_output_no_fcc(
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock)
|
||||
async def test_scmc_chat_options(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
mock_streaming_chat_completion_response: AsyncStream[ChatCompletionChunk],
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
mock_create.return_value = mock_streaming_chat_completion_response
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
|
||||
openai_chat_completion = OpenAIChatClient()
|
||||
async for msg in openai_chat_completion.get_response(
|
||||
@@ -174,12 +174,12 @@ async def test_scmc_chat_options(
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock, side_effect=Exception)
|
||||
async def test_cmc_general_exception(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
mock_chat_completion_response: ChatCompletion,
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
mock_create.return_value = mock_chat_completion_response
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
|
||||
openai_chat_completion = OpenAIChatClient()
|
||||
with pytest.raises(ServiceResponseException):
|
||||
@@ -191,12 +191,12 @@ async def test_cmc_general_exception(
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock)
|
||||
async def test_cmc_additional_properties(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
mock_chat_completion_response: ChatCompletion,
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
mock_create.return_value = mock_chat_completion_response
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
|
||||
openai_chat_completion = OpenAIChatClient()
|
||||
await openai_chat_completion.get_response(messages=chat_history, options={"reasoning_effort": "low"})
|
||||
@@ -214,7 +214,7 @@ async def test_cmc_additional_properties(
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock)
|
||||
async def test_get_streaming(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
content1 = ChatCompletionChunk(
|
||||
@@ -234,7 +234,7 @@ async def test_get_streaming(
|
||||
stream = MagicMock(spec=AsyncStream)
|
||||
stream.__aiter__.return_value = [content1, content2]
|
||||
mock_create.return_value = stream
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
orig_chat_history = deepcopy(chat_history)
|
||||
|
||||
openai_chat_completion = OpenAIChatClient()
|
||||
@@ -254,7 +254,7 @@ async def test_get_streaming(
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock)
|
||||
async def test_get_streaming_singular(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
content1 = ChatCompletionChunk(
|
||||
@@ -274,7 +274,7 @@ async def test_get_streaming_singular(
|
||||
stream = MagicMock(spec=AsyncStream)
|
||||
stream.__aiter__.return_value = [content1, content2]
|
||||
mock_create.return_value = stream
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
orig_chat_history = deepcopy(chat_history)
|
||||
|
||||
openai_chat_completion = OpenAIChatClient()
|
||||
@@ -294,7 +294,7 @@ async def test_get_streaming_singular(
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock)
|
||||
async def test_get_streaming_structured_output_no_fcc(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
content1 = ChatCompletionChunk(
|
||||
@@ -314,7 +314,7 @@ async def test_get_streaming_structured_output_no_fcc(
|
||||
stream = MagicMock(spec=AsyncStream)
|
||||
stream.__aiter__.return_value = [content1, content2]
|
||||
mock_create.return_value = stream
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
|
||||
# Define a mock response format
|
||||
class Test(BaseModel):
|
||||
@@ -333,12 +333,12 @@ async def test_get_streaming_structured_output_no_fcc(
|
||||
@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock)
|
||||
async def test_get_streaming_no_fcc_in_response(
|
||||
mock_create: AsyncMock,
|
||||
chat_history: list[ChatMessage],
|
||||
chat_history: list[Message],
|
||||
mock_streaming_chat_completion_response: ChatCompletion,
|
||||
openai_unit_test_env: dict[str, str],
|
||||
):
|
||||
mock_create.return_value = mock_streaming_chat_completion_response
|
||||
chat_history.append(ChatMessage(role="user", text="hello world"))
|
||||
chat_history.append(Message(role="user", text="hello world"))
|
||||
orig_chat_history = deepcopy(chat_history)
|
||||
|
||||
openai_chat_completion = OpenAIChatClient()
|
||||
|
||||
@@ -27,8 +27,6 @@ from pydantic import BaseModel
|
||||
from pytest import param
|
||||
|
||||
from agent_framework import (
|
||||
ChatClientProtocol,
|
||||
ChatMessage,
|
||||
ChatOptions,
|
||||
ChatResponse,
|
||||
ChatResponseUpdate,
|
||||
@@ -38,6 +36,8 @@ from agent_framework import (
|
||||
HostedImageGenerationTool,
|
||||
HostedMCPTool,
|
||||
HostedWebSearchTool,
|
||||
Message,
|
||||
SupportsChatGetResponse,
|
||||
tool,
|
||||
)
|
||||
from agent_framework.exceptions import (
|
||||
@@ -106,7 +106,7 @@ def test_init(openai_unit_test_env: dict[str, str]) -> None:
|
||||
openai_responses_client = OpenAIResponsesClient()
|
||||
|
||||
assert openai_responses_client.model_id == openai_unit_test_env["OPENAI_RESPONSES_MODEL_ID"]
|
||||
assert isinstance(openai_responses_client, ChatClientProtocol)
|
||||
assert isinstance(openai_responses_client, SupportsChatGetResponse)
|
||||
|
||||
|
||||
def test_init_validation_fail() -> None:
|
||||
@@ -121,7 +121,7 @@ def test_init_model_id_constructor(openai_unit_test_env: dict[str, str]) -> None
|
||||
openai_responses_client = OpenAIResponsesClient(model_id=model_id)
|
||||
|
||||
assert openai_responses_client.model_id == model_id
|
||||
assert isinstance(openai_responses_client, ChatClientProtocol)
|
||||
assert isinstance(openai_responses_client, SupportsChatGetResponse)
|
||||
|
||||
|
||||
def test_init_with_default_header(openai_unit_test_env: dict[str, str]) -> None:
|
||||
@@ -133,7 +133,7 @@ def test_init_with_default_header(openai_unit_test_env: dict[str, str]) -> None:
|
||||
)
|
||||
|
||||
assert openai_responses_client.model_id == openai_unit_test_env["OPENAI_RESPONSES_MODEL_ID"]
|
||||
assert isinstance(openai_responses_client, ChatClientProtocol)
|
||||
assert isinstance(openai_responses_client, SupportsChatGetResponse)
|
||||
|
||||
# Assert that the default header we added is present in the client's default headers
|
||||
for key, value in default_headers.items():
|
||||
@@ -211,7 +211,7 @@ async def test_get_response_with_all_parameters() -> None:
|
||||
# Test with comprehensive parameter set - should fail due to invalid API key
|
||||
with pytest.raises(ServiceResponseException):
|
||||
await client.get_response(
|
||||
messages=[ChatMessage(role="user", text="Test message")],
|
||||
messages=[Message(role="user", text="Test message")],
|
||||
options={
|
||||
"include": ["message.output_text.logprobs"],
|
||||
"instructions": "You are a helpful assistant",
|
||||
@@ -255,7 +255,7 @@ async def test_web_search_tool_with_location() -> None:
|
||||
# Should raise an authentication error due to invalid API key
|
||||
with pytest.raises(ServiceResponseException):
|
||||
await client.get_response(
|
||||
messages=[ChatMessage(role="user", text="What's the weather?")],
|
||||
messages=[Message(role="user", text="What's the weather?")],
|
||||
options={"tools": [web_search_tool], "tool_choice": "auto"},
|
||||
)
|
||||
|
||||
@@ -270,7 +270,7 @@ async def test_file_search_tool_with_invalid_inputs() -> None:
|
||||
# Should raise an error due to invalid inputs
|
||||
with pytest.raises(ValueError, match="HostedFileSearchTool requires inputs to be of type"):
|
||||
await client.get_response(
|
||||
messages=[ChatMessage(role="user", text="Search files")],
|
||||
messages=[Message(role="user", text="Search files")],
|
||||
options={"tools": [file_search_tool]},
|
||||
)
|
||||
|
||||
@@ -284,7 +284,7 @@ async def test_code_interpreter_tool_variations() -> None:
|
||||
|
||||
with pytest.raises(ServiceResponseException):
|
||||
await client.get_response(
|
||||
messages=[ChatMessage(role="user", text="Run some code")],
|
||||
messages=[Message(role="user", text="Run some code")],
|
||||
options={"tools": [code_tool_empty]},
|
||||
)
|
||||
|
||||
@@ -295,7 +295,7 @@ async def test_code_interpreter_tool_variations() -> None:
|
||||
|
||||
with pytest.raises(ServiceResponseException):
|
||||
await client.get_response(
|
||||
messages=[ChatMessage(role="user", text="Process these files")],
|
||||
messages=[Message(role="user", text="Process these files")],
|
||||
options={"tools": [code_tool_with_files]},
|
||||
)
|
||||
|
||||
@@ -314,7 +314,7 @@ async def test_content_filter_exception() -> None:
|
||||
|
||||
with patch.object(client.client.responses, "create", side_effect=mock_error):
|
||||
with pytest.raises(OpenAIContentFilterException) as exc_info:
|
||||
await client.get_response(messages=[ChatMessage(role="user", text="Test message")])
|
||||
await client.get_response(messages=[Message(role="user", text="Test message")])
|
||||
|
||||
assert "content error" in str(exc_info.value)
|
||||
|
||||
@@ -329,7 +329,7 @@ async def test_hosted_file_search_tool_validation() -> None:
|
||||
|
||||
with pytest.raises((ValueError, ServiceInvalidRequestError)):
|
||||
await client.get_response(
|
||||
messages=[ChatMessage(role="user", text="Test")],
|
||||
messages=[Message(role="user", text="Test")],
|
||||
options={"tools": [empty_file_search_tool]},
|
||||
)
|
||||
|
||||
@@ -349,9 +349,9 @@ async def test_chat_message_parsing_with_function_calls() -> None:
|
||||
function_result = Content.from_function_result(call_id="test-call-id", result="Function executed successfully")
|
||||
|
||||
messages = [
|
||||
ChatMessage(role="user", text="Call a function"),
|
||||
ChatMessage(role="assistant", contents=[function_call]),
|
||||
ChatMessage(role="tool", contents=[function_result]),
|
||||
Message(role="user", text="Call a function"),
|
||||
Message(role="assistant", contents=[function_call]),
|
||||
Message(role="tool", contents=[function_result]),
|
||||
]
|
||||
|
||||
# This should exercise the message parsing logic - will fail due to invalid API key
|
||||
@@ -377,7 +377,7 @@ async def test_response_format_parse_path() -> None:
|
||||
|
||||
with patch.object(client.client.responses, "parse", return_value=mock_parsed_response):
|
||||
response = await client.get_response(
|
||||
messages=[ChatMessage(role="user", text="Test message")],
|
||||
messages=[Message(role="user", text="Test message")],
|
||||
options={"response_format": OutputStruct, "store": True},
|
||||
)
|
||||
assert response.response_id == "parsed_response_123"
|
||||
@@ -404,7 +404,7 @@ async def test_response_format_parse_path_with_conversation_id() -> None:
|
||||
|
||||
with patch.object(client.client.responses, "parse", return_value=mock_parsed_response):
|
||||
response = await client.get_response(
|
||||
messages=[ChatMessage(role="user", text="Test message")],
|
||||
messages=[Message(role="user", text="Test message")],
|
||||
options={"response_format": OutputStruct, "store": True},
|
||||
)
|
||||
assert response.response_id == "parsed_response_123"
|
||||
@@ -427,7 +427,7 @@ async def test_bad_request_error_non_content_filter() -> None:
|
||||
with patch.object(client.client.responses, "parse", side_effect=mock_error):
|
||||
with pytest.raises(ServiceResponseException) as exc_info:
|
||||
await client.get_response(
|
||||
messages=[ChatMessage(role="user", text="Test message")],
|
||||
messages=[Message(role="user", text="Test message")],
|
||||
options={"response_format": OutputStruct},
|
||||
)
|
||||
|
||||
@@ -448,7 +448,7 @@ async def test_streaming_content_filter_exception_handling() -> None:
|
||||
mock_create.side_effect.code = "content_filter"
|
||||
|
||||
with pytest.raises(OpenAIContentFilterException, match="service encountered a content error"):
|
||||
response_stream = client.get_response(stream=True, messages=[ChatMessage(role="user", text="Test")])
|
||||
response_stream = client.get_response(stream=True, messages=[Message(role="user", text="Test")])
|
||||
async for _ in response_stream:
|
||||
break
|
||||
|
||||
@@ -792,7 +792,7 @@ def test_prepare_message_for_openai_with_function_approval_response() -> None:
|
||||
function_call=function_call,
|
||||
)
|
||||
|
||||
message = ChatMessage(role="user", contents=[approval_response])
|
||||
message = Message(role="user", contents=[approval_response])
|
||||
call_id_to_id: dict[str, str] = {}
|
||||
|
||||
result = client._prepare_message_for_openai(message, call_id_to_id)
|
||||
@@ -814,7 +814,7 @@ def test_chat_message_with_error_content() -> None:
|
||||
error_code="TEST_ERR",
|
||||
)
|
||||
|
||||
message = ChatMessage(role="assistant", contents=[error_content])
|
||||
message = Message(role="assistant", contents=[error_content])
|
||||
call_id_to_id: dict[str, str] = {}
|
||||
|
||||
result = client._prepare_message_for_openai(message, call_id_to_id)
|
||||
@@ -839,7 +839,7 @@ def test_chat_message_with_usage_content() -> None:
|
||||
}
|
||||
)
|
||||
|
||||
message = ChatMessage(role="assistant", contents=[usage_content])
|
||||
message = Message(role="assistant", contents=[usage_content])
|
||||
call_id_to_id: dict[str, str] = {}
|
||||
|
||||
result = client._prepare_message_for_openai(message, call_id_to_id)
|
||||
@@ -1343,14 +1343,14 @@ async def test_end_to_end_mcp_approval_flow(span_exporter) -> None:
|
||||
# Patch the create call to return the two mocked responses in sequence
|
||||
with patch.object(client.client.responses, "create", side_effect=[mock_response1, mock_response2]) as mock_create:
|
||||
# First call: get the approval request
|
||||
response = await client.get_response(messages=[ChatMessage(role="user", text="Trigger approval")])
|
||||
response = await client.get_response(messages=[Message(role="user", text="Trigger approval")])
|
||||
assert response.messages[0].contents[0].type == "function_approval_request"
|
||||
req = response.messages[0].contents[0]
|
||||
assert req.id == "approval-1"
|
||||
|
||||
# Build a user approval and send it (include required function_call)
|
||||
approval = Content.from_function_approval_response(approved=True, id=req.id, function_call=req.function_call)
|
||||
approval_message = ChatMessage(role="user", contents=[approval])
|
||||
approval_message = Message(role="user", contents=[approval])
|
||||
_ = await client.get_response(messages=[approval_message])
|
||||
|
||||
# After approval is processed, the model is called again to get the final response
|
||||
@@ -1595,7 +1595,7 @@ def test_streaming_annotation_added_with_unknown_type() -> None:
|
||||
async def test_service_response_exception_includes_original_error_details() -> None:
|
||||
"""Test that ServiceResponseException messages include original error details in the new format."""
|
||||
client = OpenAIResponsesClient(model_id="test-model", api_key="test-key")
|
||||
messages = [ChatMessage(role="user", text="test message")]
|
||||
messages = [Message(role="user", text="test message")]
|
||||
|
||||
mock_response = MagicMock()
|
||||
original_error_message = "Request rate limit exceeded"
|
||||
@@ -1620,7 +1620,7 @@ async def test_service_response_exception_includes_original_error_details() -> N
|
||||
async def test_get_response_streaming_with_response_format() -> None:
|
||||
"""Test get_response streaming with response_format."""
|
||||
client = OpenAIResponsesClient(model_id="test-model", api_key="test-key")
|
||||
messages = [ChatMessage(role="user", text="Test streaming with format")]
|
||||
messages = [Message(role="user", text="Test streaming with format")]
|
||||
|
||||
# It will fail due to invalid API key, but exercises the code path
|
||||
with pytest.raises(ServiceResponseException):
|
||||
@@ -2126,7 +2126,7 @@ def test_parse_response_from_openai_image_generation_fallback():
|
||||
|
||||
async def test_prepare_options_store_parameter_handling() -> None:
|
||||
client = OpenAIResponsesClient(model_id="test-model", api_key="test-key")
|
||||
messages = [ChatMessage(role="user", text="Test message")]
|
||||
messages = [Message(role="user", text="Test message")]
|
||||
|
||||
test_conversation_id = "test-conversation-123"
|
||||
chat_options = ChatOptions(store=True, conversation_id=test_conversation_id)
|
||||
@@ -2152,7 +2152,7 @@ async def test_prepare_options_store_parameter_handling() -> None:
|
||||
async def test_conversation_id_precedence_kwargs_over_options() -> None:
|
||||
"""When both kwargs and options contain conversation_id, kwargs wins."""
|
||||
client = OpenAIResponsesClient(model_id="test-model", api_key="test-key")
|
||||
messages = [ChatMessage(role="user", text="Hello")]
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
|
||||
# options has a stale response id, kwargs carries the freshest one
|
||||
opts = {"conversation_id": "resp_old_123"}
|
||||
@@ -2259,14 +2259,14 @@ async def test_integration_options(
|
||||
# Prepare test message
|
||||
if option_name.startswith("tools") or option_name.startswith("tool_choice"):
|
||||
# Use weather-related prompt for tool tests
|
||||
messages = [ChatMessage(role="user", text="What is the weather in Seattle?")]
|
||||
messages = [Message(role="user", text="What is the weather in Seattle?")]
|
||||
elif option_name.startswith("response_format"):
|
||||
# Use prompt that works well with structured output
|
||||
messages = [ChatMessage(role="user", text="The weather in Seattle is sunny")]
|
||||
messages.append(ChatMessage(role="user", text="What is the weather in Seattle?"))
|
||||
messages = [Message(role="user", text="The weather in Seattle is sunny")]
|
||||
messages.append(Message(role="user", text="What is the weather in Seattle?"))
|
||||
else:
|
||||
# Generic prompt for simple options
|
||||
messages = [ChatMessage(role="user", text="Say 'Hello World' briefly.")]
|
||||
messages = [Message(role="user", text="Say 'Hello World' briefly.")]
|
||||
|
||||
# Build options dict
|
||||
options: dict[str, Any] = {option_name: option_value}
|
||||
@@ -2372,13 +2372,13 @@ async def test_integration_web_search() -> None:
|
||||
async def test_integration_file_search() -> None:
|
||||
openai_responses_client = OpenAIResponsesClient()
|
||||
|
||||
assert isinstance(openai_responses_client, ChatClientProtocol)
|
||||
assert isinstance(openai_responses_client, SupportsChatGetResponse)
|
||||
|
||||
file_id, vector_store = await create_vector_store(openai_responses_client)
|
||||
# Test that the client will use the web search tool
|
||||
response = await openai_responses_client.get_response(
|
||||
messages=[
|
||||
ChatMessage(
|
||||
Message(
|
||||
role="user",
|
||||
text="What is the weather today? Do a file search to find the answer.",
|
||||
)
|
||||
@@ -2403,14 +2403,14 @@ async def test_integration_file_search() -> None:
|
||||
async def test_integration_streaming_file_search() -> None:
|
||||
openai_responses_client = OpenAIResponsesClient()
|
||||
|
||||
assert isinstance(openai_responses_client, ChatClientProtocol)
|
||||
assert isinstance(openai_responses_client, SupportsChatGetResponse)
|
||||
|
||||
file_id, vector_store = await create_vector_store(openai_responses_client)
|
||||
# Test that the client will use the web search tool
|
||||
response = openai_responses_client.get_response(
|
||||
stream=True,
|
||||
messages=[
|
||||
ChatMessage(
|
||||
Message(
|
||||
role="user",
|
||||
text="What is the weather today? Do a file search to find the answer.",
|
||||
)
|
||||
@@ -2458,7 +2458,7 @@ def test_chat_response_with_continuation_token() -> None:
|
||||
|
||||
token = OpenAIContinuationToken(response_id="resp_123")
|
||||
response = ChatResponse(
|
||||
messages=ChatMessage(role="assistant", contents=[Content.from_text(text="Hello")]),
|
||||
messages=Message(role="assistant", contents=[Content.from_text(text="Hello")]),
|
||||
response_id="resp_123",
|
||||
continuation_token=token,
|
||||
)
|
||||
@@ -2469,7 +2469,7 @@ def test_chat_response_with_continuation_token() -> None:
|
||||
def test_chat_response_without_continuation_token() -> None:
|
||||
"""Test that ChatResponse defaults continuation_token to None."""
|
||||
response = ChatResponse(
|
||||
messages=ChatMessage(role="assistant", contents=[Content.from_text(text="Hello")]),
|
||||
messages=Message(role="assistant", contents=[Content.from_text(text="Hello")]),
|
||||
)
|
||||
assert response.continuation_token is None
|
||||
|
||||
@@ -2495,7 +2495,7 @@ def test_agent_response_with_continuation_token() -> None:
|
||||
|
||||
token = OpenAIContinuationToken(response_id="resp_789")
|
||||
response = AgentResponse(
|
||||
messages=ChatMessage(role="assistant", contents=[Content.from_text(text="done")]),
|
||||
messages=Message(role="assistant", contents=[Content.from_text(text="done")]),
|
||||
continuation_token=token,
|
||||
)
|
||||
assert response.continuation_token is not None
|
||||
@@ -2679,7 +2679,7 @@ async def test_prepare_options_excludes_continuation_token() -> None:
|
||||
"""Test that _prepare_options does not pass continuation_token to OpenAI API."""
|
||||
client = OpenAIResponsesClient(model_id="test-model", api_key="test-key")
|
||||
|
||||
messages = [ChatMessage(role="user", contents=[Content.from_text(text="Hello")])]
|
||||
messages = [Message(role="user", contents=[Content.from_text(text="Hello")])]
|
||||
options: dict[str, Any] = {
|
||||
"model_id": "test-model",
|
||||
"continuation_token": {"response_id": "resp_123"},
|
||||
|
||||
Reference in New Issue
Block a user