diff --git a/src/Responses/Batches/BatchResponse.php b/src/Responses/Batches/BatchResponse.php index 86c269f8..17c54895 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 27a884b5..ab450cc6 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}> @@ -21,6 +22,8 @@ class ThreadRunStreamResponse implements ResponseContract */ use ArrayAccessible; + use FakeableForStreamedResponse; + private function __construct( public readonly string $event, public readonly ThreadResponse|ThreadRunResponse|ThreadRunStepResponse|ThreadRunStepDeltaResponse|ThreadMessageResponse|ThreadMessageDeltaResponse $response, 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/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..23c4a25a --- /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); +});