From ba7959b60dda8d8542b23b08466e92374e806f51 Mon Sep 17 00:00:00 2001 From: Kyle Nash Date: Thu, 4 Jul 2024 16:40:20 +0100 Subject: [PATCH 1/2] Testing - Add test coverage for assistants streaming and ability to use fake responses --- .../Threads/Runs/ThreadRunStreamResponse.php | 2 + .../Runs/ThreadRunStreamResponseFixture.txt | 41 ++++++++++++ .../ThreadRunStreamInvalidEventResponse.txt | 2 + .../ThreadRunStreamMessageDeltaResponse.txt | 2 + .../ThreadRunStreamMessageResponse.txt | 2 + .../Streams/ThreadRunStreamResponse.txt | 41 ++++++++++++ .../ThreadRunStreamRunStepDeltaResponse.txt | 2 + .../ThreadRunStreamStepRunCreatedResponse.txt | 2 + .../ThreadRunStreamThreadCreatedResponse.txt | 2 + tests/Fixtures/ThreadRun.php | 48 ++++++++++++++ .../Threads/Runs/ThreadRunStreamResponse.php | 65 +++++++++++++++++++ 11 files changed, 209 insertions(+) create mode 100644 src/Testing/Responses/Fixtures/Threads/Runs/ThreadRunStreamResponseFixture.txt create mode 100644 tests/Fixtures/Streams/ThreadRunStreamInvalidEventResponse.txt create mode 100644 tests/Fixtures/Streams/ThreadRunStreamMessageDeltaResponse.txt create mode 100644 tests/Fixtures/Streams/ThreadRunStreamMessageResponse.txt create mode 100644 tests/Fixtures/Streams/ThreadRunStreamResponse.txt create mode 100644 tests/Fixtures/Streams/ThreadRunStreamRunStepDeltaResponse.txt create mode 100644 tests/Fixtures/Streams/ThreadRunStreamStepRunCreatedResponse.txt create mode 100644 tests/Fixtures/Streams/ThreadRunStreamThreadCreatedResponse.txt create mode 100644 tests/Responses/Threads/Runs/ThreadRunStreamResponse.php diff --git a/src/Responses/Threads/Runs/ThreadRunStreamResponse.php b/src/Responses/Threads/Runs/ThreadRunStreamResponse.php index 3c6c41a3..423e703d 100644 --- a/src/Responses/Threads/Runs/ThreadRunStreamResponse.php +++ b/src/Responses/Threads/Runs/ThreadRunStreamResponse.php @@ -10,6 +10,7 @@ use OpenAI\Responses\Threads\Runs\Steps\Delta\ThreadRunStepDeltaResponse; use OpenAI\Responses\Threads\Runs\Steps\ThreadRunStepResponse; use OpenAI\Responses\Threads\ThreadResponse; +use OpenAI\Testing\Responses\Concerns\FakeableForStreamedResponse; /** * @implements ResponseContract}> @@ -20,6 +21,7 @@ class ThreadRunStreamResponse implements ResponseContract * @use ArrayAccessible}> */ use ArrayAccessible; + use FakeableForStreamedResponse; private function __construct( public readonly string $event, diff --git a/src/Testing/Responses/Fixtures/Threads/Runs/ThreadRunStreamResponseFixture.txt b/src/Testing/Responses/Fixtures/Threads/Runs/ThreadRunStreamResponseFixture.txt new file mode 100644 index 00000000..74781b70 --- /dev/null +++ b/src/Testing/Responses/Fixtures/Threads/Runs/ThreadRunStreamResponseFixture.txt @@ -0,0 +1,41 @@ +event: thread.created +data: {"id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","object":"thread","created_at":1720104398,"metadata":{"user":"John Doe"},"tool_resources":{"code_interpreter":{"file_ids":[]}}} +event: thread.run.created +data: {"id":"run_s1X8yAjuUBlwhGrqiahzfnH7","object":"thread.run","created_at":1720104398,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","status":"queued","started_at ":null,"expires_at ":1720104998,"cancelled_at ":null,"failed_at ":null,"completed_at ":null,"required_action ":null,"last_error ":null,"model":"gpt-4 o","instructions":"You are a very useful assistant","tools":[{"type":"code_interpreter"},{"type":"file_search","file_search":{"max_num_results":50}},{"type":"function","function":{"name":"get_weather","description":"Determine weather in my location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The city and state e.g. San Francisco, CA"},"unit":{"type":"string","enum":["c","f"]}},"required":["location"]}}}],"tool_resources":{"code_interpreter":{"file_ids":[]}},"metadata":{"user":"John Doe"},"temperature":0.7,"top_p":1.0,"max_completion_tokens":null,"max_prompt_tokens":null,"truncation_strategy":{"type":"auto","last_messages":null},"incomplete_details":null,"usage":null,"response_format":"auto","tool_choice":"auto","parallel_tool_calls":true} +event: thread.run.queued +data: {"id":"run_s1X8yAjuUBlwhGrqiahzfnH7","object":"thread.run","created_at":1720104398,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","status":"queued","started_at":null,"expires_at":1720104998,"cancelled_at":null,"failed_at":null,"completed_at":null,"required_action":null,"last_error":null,"model":"gpt-4o","instructions":"You are a very useful assistant.","tools":[{"type":"code_interpreter"},{"type":"file_search","file_search":{"max_num_results":50}},{"type":"function","function":{"name":"get_weather","description":"Determine weather in my location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The city and state e.g. San Francisco, CA"},"unit":{"type":"string","enum":["c","f"]}},"required":["location"]}}}],"tool_resources":{"code_interpreter":{"file_ids":[]}},"metadata":{"user":"John Doe"},"temperature":0.7,"top_p":1.0,"max_completion_tokens":null,"max_prompt_tokens":null,"truncation_strategy":{"type":"auto","last_messages":null},"incomplete_details":null,"usage":null,"response_format":"auto","tool_choice":"auto","parallel_tool_calls":true} +event: thread.run.in_progress +data: {"id":"run_s1X8yAjuUBlwhGrqiahzfnH7","object":"thread.run","created_at":1720104398,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","status":"in_progress","started_at":1720104398,"expires_at":1720104998,"cancelled_at":null,"failed_at":null,"completed_at":null,"required_action":null,"last_error":null,"model":"gpt-4o","instructions":"You are a very useful assistant.","tools":[{"type":"code_interpreter"},{"type":"file_search","file_search":{"max_num_results":50}},{"type":"function","function":{"name":"get_weather","description":"Determine weather in my location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The city and state e.g. San Francisco, CA"},"unit":{"type":"string","enum":["c","f"]}},"required":["location"]}}}],"tool_resources":{"code_interpreter":{"file_ids":[]}},"metadata":{"user":"John Doe"},"temperature":0.7,"top_p":1.0,"max_completion_tokens":null,"max_prompt_tokens":null,"truncation_strategy":{"type":"auto","last_messages":null},"incomplete_details":null,"usage":null,"response_format":"auto","tool_choice":"auto","parallel_tool_calls":true} +event: thread.run.step.created +data: {"id":"step_3P1u5J5Rs95lypEfvQ3rMdPL","object":"thread.run.step","created_at":1720104399,"run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","type":"message_creation","status":"in_progress","cancelled_at":null,"completed_at":null,"expires_at":1720104998,"failed_at":null,"last_error":null,"step_details":{"type":"message_creation","message_creation":{"message_id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd"}},"usage":null} +event: thread.run.step.in_progress +data: {"id":"step_3P1u5J5Rs95lypEfvQ3rMdPL","object":"thread.run.step","created_at":1720104399,"run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","type":"message_creation","status":"in_progress","cancelled_at":null,"completed_at":null,"expires_at":1720104998,"failed_at":null,"last_error":null,"step_details":{"type":"message_creation","message_creation":{"message_id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd"}},"usage":null} +event: thread.message.created +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message","created_at":1720104399,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","status":"in_progress","incomplete_details":null,"incomplete_at":null,"completed_at":null,"role":"assistant","content":[],"attachments":[],"metadata":{}} +event: thread.message.in_progress +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message","created_at":1720104399,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","status":"in_progress","incomplete_details":null,"incomplete_at":null,"completed_at":null,"role":"assistant","content":[],"attachments":[],"metadata":{}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":"Hello","annotations":[]}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":"!"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" How"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" can"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" I"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" assist"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" you"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" today"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":"?"}}]}} +event: thread.message.completed +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message","created_at":1720104399,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","status":"completed","incomplete_details":null,"incomplete_at":null,"completed_at":1720104399,"role":"assistant","content":[{"type":"text","text":{"value":"Hello! How can I assist you today?","annotations":[]}}],"attachments":[],"metadata":{}} +event: thread.run.step.completed +data: {"id":"step_3P1u5J5Rs95lypEfvQ3rMdPL","object":"thread.run.step","created_at":1720104399,"run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","type":"message_creation","status":"completed","cancelled_at":null,"completed_at":1720104399,"expires_at":1720104998,"failed_at":null,"last_error":null,"step_details":{"type":"message_creation","message_creation":{"message_id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd"}},"usage":{"prompt_tokens":1138,"completion_tokens":11,"total_tokens":1149}} +event: thread.run.completed +data: {"id":"run_s1X8yAjuUBlwhGrqiahzfnH7","object":"thread.run","created_at":1720104398,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","status":"completed","started_at":1720104398,"expires_at":null,"cancelled_at":null,"failed_at":null,"completed_at":1720104399,"required_action":null,"last_error":null,"model":"gpt-4o","instructions":"You are a very useful assistant.","tools":[{"type":"code_interpreter"},{"type":"file_search","file_search":{"max_num_results":50}},{"type":"function","function":{"name":"get_weather","description":"Determine weather in my location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The city and state e.g. San Francisco, CA"},"unit":{"type":"string","enum":["c","f"]}},"required":["location"]}}}],"tool_resources":{"code_interpreter":{"file_ids":[]}},"metadata":{"user":"John Doe"},"temperature":0.7,"top_p":1.0,"max_completion_tokens":null,"max_prompt_tokens":null,"truncation_strategy":{"type":"auto","last_messages":null},"incomplete_details":null,"usage":{"prompt_tokens":1138,"completion_tokens":11,"total_tokens":1149},"response_format":"auto","tool_choice":"auto","parallel_tool_calls":true} +event: done diff --git a/tests/Fixtures/Streams/ThreadRunStreamInvalidEventResponse.txt b/tests/Fixtures/Streams/ThreadRunStreamInvalidEventResponse.txt new file mode 100644 index 00000000..cc97d535 --- /dev/null +++ b/tests/Fixtures/Streams/ThreadRunStreamInvalidEventResponse.txt @@ -0,0 +1,2 @@ +event: this.is.invalid +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message","created_at":1720104399,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","status":"completed","incomplete_details":null,"incomplete_at":null,"completed_at":1720104399,"role":"assistant","content":[{"type":"text","text":{"value":"Hello! How can I assist you today?","annotations":[]}}],"attachments":[],"metadata":{}} diff --git a/tests/Fixtures/Streams/ThreadRunStreamMessageDeltaResponse.txt b/tests/Fixtures/Streams/ThreadRunStreamMessageDeltaResponse.txt new file mode 100644 index 00000000..0603c61b --- /dev/null +++ b/tests/Fixtures/Streams/ThreadRunStreamMessageDeltaResponse.txt @@ -0,0 +1,2 @@ +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":"Hello","annotations":[]}}]}} diff --git a/tests/Fixtures/Streams/ThreadRunStreamMessageResponse.txt b/tests/Fixtures/Streams/ThreadRunStreamMessageResponse.txt new file mode 100644 index 00000000..ad149f14 --- /dev/null +++ b/tests/Fixtures/Streams/ThreadRunStreamMessageResponse.txt @@ -0,0 +1,2 @@ +event: thread.message.completed +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message","created_at":1720104399,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","status":"completed","incomplete_details":null,"incomplete_at":null,"completed_at":1720104399,"role":"assistant","content":[{"type":"text","text":{"value":"Hello! How can I assist you today?","annotations":[]}}],"attachments":[],"metadata":{}} diff --git a/tests/Fixtures/Streams/ThreadRunStreamResponse.txt b/tests/Fixtures/Streams/ThreadRunStreamResponse.txt new file mode 100644 index 00000000..1138e695 --- /dev/null +++ b/tests/Fixtures/Streams/ThreadRunStreamResponse.txt @@ -0,0 +1,41 @@ +event: thread.created +data: {"id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","object":"thread","created_at":1720104398,"metadata":{"user":"John Doe"},"tool_resources":{"code_interpreter":{"file_ids":[]}}} +event: thread.run.created +data: {"id":"run_s1X8yAjuUBlwhGrqiahzfnH7","object":"thread.run","created_at":1720104398,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","status":"queued","started_at":null,"expires_at":1720104998,"cancelled_at":null,"failed_at":null,"completed_at":null,"required_action":null,"last_error":null,"model":"gpt-4 o","instructions":"You are a very useful assistant","tools":[{"type":"code_interpreter"},{"type":"file_search","file_search":{"max_num_results":50}},{"type":"function","function":{"name":"get_weather","description":"Determine weather in my location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The city and state e.g. San Francisco, CA"},"unit":{"type":"string","enum":["c","f"]}},"required":["location"]}}}],"tool_resources":{"code_interpreter":{"file_ids":[]}},"metadata":{"user":"John Doe"},"temperature":0.7,"top_p":1.0,"max_completion_tokens":null,"max_prompt_tokens":null,"truncation_strategy":{"type":"auto","last_messages":null},"incomplete_details":null,"usage":null,"response_format":"auto","tool_choice":"auto","parallel_tool_calls":true} +event: thread.run.queued +data: {"id":"run_s1X8yAjuUBlwhGrqiahzfnH7","object":"thread.run","created_at":1720104398,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","status":"queued","started_at":null,"expires_at":1720104998,"cancelled_at":null,"failed_at":null,"completed_at":null,"required_action":null,"last_error":null,"model":"gpt-4o","instructions":"You are a very useful assistant.","tools":[{"type":"code_interpreter"},{"type":"file_search","file_search":{"max_num_results":50}},{"type":"function","function":{"name":"get_weather","description":"Determine weather in my location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The city and state e.g. San Francisco, CA"},"unit":{"type":"string","enum":["c","f"]}},"required":["location"]}}}],"tool_resources":{"code_interpreter":{"file_ids":[]}},"metadata":{"user":"John Doe"},"temperature":0.7,"top_p":1.0,"max_completion_tokens":null,"max_prompt_tokens":null,"truncation_strategy":{"type":"auto","last_messages":null},"incomplete_details":null,"usage":null,"response_format":"auto","tool_choice":"auto","parallel_tool_calls":true} +event: thread.run.in_progress +data: {"id":"run_s1X8yAjuUBlwhGrqiahzfnH7","object":"thread.run","created_at":1720104398,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","status":"in_progress","started_at":1720104398,"expires_at":1720104998,"cancelled_at":null,"failed_at":null,"completed_at":null,"required_action":null,"last_error":null,"model":"gpt-4o","instructions":"You are a very useful assistant.","tools":[{"type":"code_interpreter"},{"type":"file_search","file_search":{"max_num_results":50}},{"type":"function","function":{"name":"get_weather","description":"Determine weather in my location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The city and state e.g. San Francisco, CA"},"unit":{"type":"string","enum":["c","f"]}},"required":["location"]}}}],"tool_resources":{"code_interpreter":{"file_ids":[]}},"metadata":{"user":"John Doe"},"temperature":0.7,"top_p":1.0,"max_completion_tokens":null,"max_prompt_tokens":null,"truncation_strategy":{"type":"auto","last_messages":null},"incomplete_details":null,"usage":null,"response_format":"auto","tool_choice":"auto","parallel_tool_calls":true} +event: thread.run.step.created +data: {"id":"step_3P1u5J5Rs95lypEfvQ3rMdPL","object":"thread.run.step","created_at":1720104399,"run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","type":"message_creation","status":"in_progress","cancelled_at":null,"completed_at":null,"expires_at":1720104998,"failed_at":null,"last_error":null,"step_details":{"type":"message_creation","message_creation":{"message_id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd"}},"usage":null} +event: thread.run.step.in_progress +data: {"id":"step_3P1u5J5Rs95lypEfvQ3rMdPL","object":"thread.run.step","created_at":1720104399,"run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","type":"message_creation","status":"in_progress","cancelled_at":null,"completed_at":null,"expires_at":1720104998,"failed_at":null,"last_error":null,"step_details":{"type":"message_creation","message_creation":{"message_id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd"}},"usage":null} +event: thread.message.created +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message","created_at":1720104399,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","status":"in_progress","incomplete_details":null,"incomplete_at":null,"completed_at":null,"role":"assistant","content":[],"attachments":[],"metadata":{}} +event: thread.message.in_progress +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message","created_at":1720104399,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","status":"in_progress","incomplete_details":null,"incomplete_at":null,"completed_at":null,"role":"assistant","content":[],"attachments":[],"metadata":{}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":"Hello","annotations":[]}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":"!"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" How"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" can"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" I"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" assist"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" you"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":" today"}}]}} +event: thread.message.delta +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message.delta","delta":{"content":[{"index":0,"type":"text","text":{"value":"?"}}]}} +event: thread.message.completed +data: {"id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd","object":"thread.message","created_at":1720104399,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","status":"completed","incomplete_details":null,"incomplete_at":null,"completed_at":1720104399,"role":"assistant","content":[{"type":"text","text":{"value":"Hello! How can I assist you today?","annotations":[]}}],"attachments":[],"metadata":{}} +event: thread.run.step.completed +data: {"id":"step_3P1u5J5Rs95lypEfvQ3rMdPL","object":"thread.run.step","created_at":1720104399,"run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","type":"message_creation","status":"completed","cancelled_at":null,"completed_at":1720104399,"expires_at":1720104998,"failed_at":null,"last_error":null,"step_details":{"type":"message_creation","message_creation":{"message_id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd"}},"usage":{"prompt_tokens":1138,"completion_tokens":11,"total_tokens":1149}} +event: thread.run.completed +data: {"id":"run_s1X8yAjuUBlwhGrqiahzfnH7","object":"thread.run","created_at":1720104398,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","status":"completed","started_at":1720104398,"expires_at":null,"cancelled_at":null,"failed_at":null,"completed_at":1720104399,"required_action":null,"last_error":null,"model":"gpt-4o","instructions":"You are a very useful assistant.","tools":[{"type":"code_interpreter"},{"type":"file_search","file_search":{"max_num_results":50}},{"type":"function","function":{"name":"get_weather","description":"Determine weather in my location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The city and state e.g. San Francisco, CA"},"unit":{"type":"string","enum":["c","f"]}},"required":["location"]}}}],"tool_resources":{"code_interpreter":{"file_ids":[]}},"metadata":{"user":"John Doe"},"temperature":0.7,"top_p":1.0,"max_completion_tokens":null,"max_prompt_tokens":null,"truncation_strategy":{"type":"auto","last_messages":null},"incomplete_details":null,"usage":{"prompt_tokens":1138,"completion_tokens":11,"total_tokens":1149},"response_format":"auto","tool_choice":"auto","parallel_tool_calls":true} +event: done diff --git a/tests/Fixtures/Streams/ThreadRunStreamRunStepDeltaResponse.txt b/tests/Fixtures/Streams/ThreadRunStreamRunStepDeltaResponse.txt new file mode 100644 index 00000000..7db20a2d --- /dev/null +++ b/tests/Fixtures/Streams/ThreadRunStreamRunStepDeltaResponse.txt @@ -0,0 +1,2 @@ +event: thread.run.step.delta +data: {"id":"step_rQmJPtF2uOyGhSCCHqk1zoVd","object":"thread.run.step.delta","delta":{"step_details":{"type":"tool_calls","tool_calls":[{"index":0,"type":"code_interpreter","code_interpreter":{"input":" '"}}]}}} diff --git a/tests/Fixtures/Streams/ThreadRunStreamStepRunCreatedResponse.txt b/tests/Fixtures/Streams/ThreadRunStreamStepRunCreatedResponse.txt new file mode 100644 index 00000000..6c56e68e --- /dev/null +++ b/tests/Fixtures/Streams/ThreadRunStreamStepRunCreatedResponse.txt @@ -0,0 +1,2 @@ +event: thread.run.step.created +data: {"id":"step_3P1u5J5Rs95lypEfvQ3rMdPL","object":"thread.run.step","created_at":1720104399,"run_id":"run_s1X8yAjuUBlwhGrqiahzfnH7","assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","type":"message_creation","status":"in_progress","cancelled_at":null,"completed_at":null,"expires_at":1720104998,"failed_at":null,"last_error":null,"step_details":{"type":"message_creation","message_creation":{"message_id":"msg_zKgPBqNcqb7qYP2bBA3tVyTd"}},"usage":null} diff --git a/tests/Fixtures/Streams/ThreadRunStreamThreadCreatedResponse.txt b/tests/Fixtures/Streams/ThreadRunStreamThreadCreatedResponse.txt new file mode 100644 index 00000000..f7423ab8 --- /dev/null +++ b/tests/Fixtures/Streams/ThreadRunStreamThreadCreatedResponse.txt @@ -0,0 +1,2 @@ +event: thread.run.created +data: {"id":"run_s1X8yAjuUBlwhGrqiahzfnH7","object":"thread.run","created_at":1720104398,"assistant_id":"asst_JA9Pc6eQ744nbec10slSz5BU","thread_id":"thread_sSbvUX4J1FqlUZBv6BaBbOj4","status":"queued","started_at":null,"expires_at":1720104998,"cancelled_at":null,"failed_at":null,"completed_at":null,"required_action":null,"last_error":null,"model":"gpt-4 o","instructions":"You are a very useful assistant","tools":[{"type":"code_interpreter"},{"type":"file_search","file_search":{"max_num_results":50}},{"type":"function","function":{"name":"get_weather","description":"Determine weather in my location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The city and state e.g. San Francisco, CA"},"unit":{"type":"string","enum":["c","f"]}},"required":["location"]}}}],"tool_resources":{"code_interpreter":{"file_ids":[]}},"metadata":{"user":"John Doe"},"temperature":0.7,"top_p":1.0,"max_completion_tokens":null,"max_prompt_tokens":null,"truncation_strategy":{"type":"auto","last_messages":null},"incomplete_details":null,"usage":null,"response_format":"auto","tool_choice":"auto","parallel_tool_calls":true} diff --git a/tests/Fixtures/ThreadRun.php b/tests/Fixtures/ThreadRun.php index 8559cf45..2f75ae4b 100644 --- a/tests/Fixtures/ThreadRun.php +++ b/tests/Fixtures/ThreadRun.php @@ -355,3 +355,51 @@ function threadRunListResource(): array 'has_more' => false, ]; } + +/** + * @return resource + */ +function messageDeltaThreadRunStream() +{ + return fopen(__DIR__.'/Streams/ThreadRunStreamMessageDeltaResponse.txt', 'r'); +} + +/** + * @return resource + */ +function runCreatedThreadRunStream() +{ + return fopen(__DIR__.'/Streams/ThreadRunStreamThreadCreatedResponse.txt', 'r'); +} + +/** + * @return resource + */ +function runCreatedThreadStepCreatedStream() +{ + return fopen(__DIR__.'/Streams/ThreadRunStreamStepRunCreatedResponse.txt', 'r'); +} + +/** + * @return resource + */ +function runCreatedThreadMessageCreatedStream() +{ + return fopen(__DIR__.'/Streams/ThreadRunStreamMessageResponse.txt', 'r'); +} + +/** + * @return resource + */ +function runCreatedThreadRunStepDeltaStream() +{ + return fopen(__DIR__.'/Streams/ThreadRunStreamRunStepDeltaResponse.txt', 'r'); +} + +/** + * @return resource + */ +function runCreatedThreadInvalidEventStream() +{ + return fopen(__DIR__.'/Streams/ThreadRunStreamInvalidEventResponse.txt', 'r'); +} diff --git a/tests/Responses/Threads/Runs/ThreadRunStreamResponse.php b/tests/Responses/Threads/Runs/ThreadRunStreamResponse.php new file mode 100644 index 00000000..3a60d677 --- /dev/null +++ b/tests/Responses/Threads/Runs/ThreadRunStreamResponse.php @@ -0,0 +1,65 @@ +getIterator()->current()->response) + ->toBeInstanceOf(ThreadResponse::class) + ->id->toBe('thread_sSbvUX4J1FqlUZBv6BaBbOj4'); +}); + +test('handles message delta', function () { + $response = ThreadRunStreamResponse::fake(messageDeltaThreadRunStream()); + + expect($response->getIterator()->current()->response) + ->toBeInstanceOf(ThreadMessageDeltaResponse::class) + ->id->toBe('msg_zKgPBqNcqb7qYP2bBA3tVyTd'); +}); + +test('handles thread created', function () { + $response = ThreadRunStreamResponse::fake(runCreatedThreadRunStream()); + + expect($response->getIterator()->current()->response) + ->toBeInstanceOf(ThreadRunResponse::class) + ->id->toBe('run_s1X8yAjuUBlwhGrqiahzfnH7'); +}); + +test('handles thread run step', function () { + $response = ThreadRunStreamResponse::fake(runCreatedThreadStepCreatedStream()); + + expect($response->getIterator()->current()->response) + ->toBeInstanceOf(ThreadRunStepResponse::class) + ->id->toBe('step_3P1u5J5Rs95lypEfvQ3rMdPL'); +}); + +test('handles message created', function () { + $response = ThreadRunStreamResponse::fake(runCreatedThreadMessageCreatedStream()); + + expect($response->getIterator()->current()->response) + ->toBeInstanceOf(ThreadMessageResponse::class) + ->id->toBe('msg_zKgPBqNcqb7qYP2bBA3tVyTd'); +}); + +test('handles thread run delta', function () { + $response = ThreadRunStreamResponse::fake(runCreatedThreadRunStepDeltaStream()); + + expect($response->getIterator()->current()->response) + ->toBeInstanceOf(ThreadRunStepDeltaResponse::class) + ->id->toBe('step_rQmJPtF2uOyGhSCCHqk1zoVd'); +}); + +test('handles invalid event', function () { + $response = ThreadRunStreamResponse::fake(runCreatedThreadInvalidEventStream()); + + expect(fn() => $response->getIterator()->current()->response) + ->toThrow(UnknownEventException::class); +}); From f3db07b86e6d5ae5e3c7aa7bce9f7ee301f4f335 Mon Sep 17 00:00:00 2001 From: Kyle Nash Date: Thu, 4 Jul 2024 16:46:14 +0100 Subject: [PATCH 2/2] Run lint and rector --- src/Responses/Batches/BatchResponse.php | 2 +- src/Responses/Threads/Runs/ThreadRunStreamResponse.php | 1 + .../Fixtures/Batches/BatchListResponseFixture.php | 10 +++++----- .../Fixtures/Batches/BatchResponseFixture.php | 2 +- .../Responses/Threads/Runs/ThreadRunStreamResponse.php | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Responses/Batches/BatchResponse.php b/src/Responses/Batches/BatchResponse.php index f92afae3..78413c6b 100644 --- a/src/Responses/Batches/BatchResponse.php +++ b/src/Responses/Batches/BatchResponse.php @@ -25,7 +25,7 @@ final class BatchResponse implements ResponseContract, ResponseHasMetaInformatio use HasMetaInformation; /** - * @param array $metadata + * @param array|null $metadata */ private function __construct( public string $id, diff --git a/src/Responses/Threads/Runs/ThreadRunStreamResponse.php b/src/Responses/Threads/Runs/ThreadRunStreamResponse.php index 423e703d..e0c6f014 100644 --- a/src/Responses/Threads/Runs/ThreadRunStreamResponse.php +++ b/src/Responses/Threads/Runs/ThreadRunStreamResponse.php @@ -21,6 +21,7 @@ class ThreadRunStreamResponse implements ResponseContract * @use ArrayAccessible}> */ use ArrayAccessible; + use FakeableForStreamedResponse; private function __construct( diff --git a/src/Testing/Responses/Fixtures/Batches/BatchListResponseFixture.php b/src/Testing/Responses/Fixtures/Batches/BatchListResponseFixture.php index e578c66c..e58aaf89 100644 --- a/src/Testing/Responses/Fixtures/Batches/BatchListResponseFixture.php +++ b/src/Testing/Responses/Fixtures/Batches/BatchListResponseFixture.php @@ -17,11 +17,11 @@ final class BatchListResponseFixture 'status' => 'completed', 'output_file_id' => 'file-cvaTdG', 'error_file_id' => 'file-HOWS94', - 'created_at' => 1711471533, - 'in_progress_at' => 1711471538, - 'expires_at' => 1711557933, - 'finalizing_at' => 1711493133, - 'completed_at' => 1711493163, + 'created_at' => 1_711_471_533, + 'in_progress_at' => 1_711_471_538, + 'expires_at' => 1_711_557_933, + 'finalizing_at' => 1_711_493_133, + 'completed_at' => 1_711_493_163, 'failed_at' => null, 'expired_at' => null, 'cancelling_at' => null, diff --git a/src/Testing/Responses/Fixtures/Batches/BatchResponseFixture.php b/src/Testing/Responses/Fixtures/Batches/BatchResponseFixture.php index 7a51f543..97d55591 100644 --- a/src/Testing/Responses/Fixtures/Batches/BatchResponseFixture.php +++ b/src/Testing/Responses/Fixtures/Batches/BatchResponseFixture.php @@ -14,7 +14,7 @@ final class BatchResponseFixture 'status' => 'validating', 'output_file_id' => null, 'error_file_id' => null, - 'created_at' => 1711471533, + 'created_at' => 1_711_471_533, 'in_progress_at' => null, 'expires_at' => null, 'finalizing_at' => null, diff --git a/tests/Responses/Threads/Runs/ThreadRunStreamResponse.php b/tests/Responses/Threads/Runs/ThreadRunStreamResponse.php index 3a60d677..23c4a25a 100644 --- a/tests/Responses/Threads/Runs/ThreadRunStreamResponse.php +++ b/tests/Responses/Threads/Runs/ThreadRunStreamResponse.php @@ -60,6 +60,6 @@ test('handles invalid event', function () { $response = ThreadRunStreamResponse::fake(runCreatedThreadInvalidEventStream()); - expect(fn() => $response->getIterator()->current()->response) + expect(fn () => $response->getIterator()->current()->response) ->toThrow(UnknownEventException::class); });