From bdc1cd3992291677d3bb89464343f73f2f15b3ca Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Mon, 13 Apr 2026 13:14:33 +0100 Subject: [PATCH] Prevent callback return value from halting stream The delta branch in decode_responses_event now explicitly returns :ok after invoking the callback, so a callback returning {:error, _} cannot be mistaken for a stream-level error by decode_events. --- lib/open_ai/api.ex | 1 + test/open_ai/api_test.exs | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/open_ai/api.ex b/lib/open_ai/api.ex index 3c02897f..2dc15f4b 100644 --- a/lib/open_ai/api.ex +++ b/lib/open_ai/api.ex @@ -125,6 +125,7 @@ defmodule OpenAI.API do case JSON.decode!(json) do %{"type" => "response.output_text.delta", "delta" => delta} -> cb.(delta) + :ok %{"type" => "error", "error" => %{"message" => message}} -> {:error, message} diff --git a/test/open_ai/api_test.exs b/test/open_ai/api_test.exs index 744ce79b..778567cc 100644 --- a/test/open_ai/api_test.exs +++ b/test/open_ai/api_test.exs @@ -89,6 +89,30 @@ defmodule OpenAI.APITest do assert_received {:chunk, " world"} end + test "callback return value does not affect stream processing" do + Req.Test.stub(__MODULE__, fn conn -> + body = + "data: #{JSON.encode!(%{"type" => "response.output_text.delta", "delta" => "Hello"})}\n\n" <> + "data: #{JSON.encode!(%{"type" => "response.output_text.delta", "delta" => " world"})}\n\n" <> + "data: #{JSON.encode!(%{"type" => "response.completed"})}\n\n" + + conn + |> Plug.Conn.put_resp_content_type("text/event-stream") + |> Plug.Conn.send_resp(200, body) + end) + + test_pid = self() + + cb = fn chunk -> + send(test_pid, {:chunk, chunk}) + {:error, "callback error"} + end + + assert :ok = API.chat_stream([], "instructions", "gpt-4.1", 0.7, @config, cb) + assert_received {:chunk, "Hello"} + assert_received {:chunk, " world"} + end + @tag :capture_log test "returns error on non-2xx response" do Req.Test.stub(__MODULE__, fn conn ->