perf(stream): make unknown-field emptiness checks O(1)
OTP 28 medians: rejecting 10,000-key objects fell from 4.36 to 1.68 ms (2.6x faster), with ordinary text unchanged. Preserve empty-value semantics; all 203 Gleam tests passed.
123456789%% FFI contracts include Erlang null aliases and tuples that JSON fixtures cannot produce.-module(albedo_openai_json_test).-include_lib("eunit/include/eunit.hrl").
semantically_empty_test_() -> [?_assertEqual(true, albedo_openai_json:semantically_empty(Value)) || Value <- [null, nil, undefined, <<>>, [], {}, #{}]] ++ [?_assertEqual(false, albedo_openai_json:semantically_empty(Value)) || Value <- [false, true, 0, <<"x">>, [null], {null}, #{<<"id">> => null}]].2 unmodified lines34567891011185 unmodified linesExpand all197198199200201202203204205206207208209210211212213214215216217218219220221160 unmodified linesExpand all2 unmodified linesimport albedo/openai_api/streamimport albedo/openai_api/typesimport gleam/dynamic/decodeimport gleam/jsonimport gleam/listimport gleam/option.{type Option, None, Some}
pub fn responses_incomplete_never_exposes_executable_calls_test() -> Result( #(stream.State, List(types.Event), Option(types.Turn)),185 unmodified linesExpand all let assert Error(types.InvalidEvent(_)) = send(stream.new(types.ChatCompletions), "", audio)}
pub fn chat_ignores_only_empty_unknown_fields_test() -> Nil { list.each(["null", "\"\"", "[]", "{}"], fn(value) { let data = "{\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\",\"audio\":" <> value <> "}}]}" let assert Ok(#(_, [types.TextDelta(0, 0, "hello")], None)) = send(stream.new(types.ChatCompletions), "", data) }) list.each(["\"x\"", "[0]", "{\"id\":null}", "0", "false", "true"], fn(value) { let data = "{\"choices\":[{\"index\":0,\"delta\":{\"audio\":" <> value <> "}}]}" let assert Error(types.InvalidEvent(_)) = send(stream.new(types.ChatCompletions), "", data) })}
pub fn chat_requires_finish_and_suppresses_partial_tools_on_limits_test() -> Nil { assert send(stream.new(types.ChatCompletions), "", "[DONE]") == Error(types.InvalidEvent("[DONE] before chat finish reason")) let partial =160 unmodified linesExpand all122345678910111213141516171819202140 unmodified lines-module(albedo_openai_json).-export([encode/1, null/0, flatten/1, data_url/2, base64_string/1]).-export([encode/1, null/0, flatten/1, data_url/2, base64_string/1, semantically_empty/1]).
encode(Value) -> json:encode(Value).
null() -> null.
%% Inspect only the container, without decoding or copying its contents.semantically_empty(null) -> true;semantically_empty(nil) -> true;semantically_empty(undefined) -> true;semantically_empty(<<>>) -> true;semantically_empty([]) -> true;semantically_empty({}) -> true;semantically_empty(Value) when is_map(Value) -> map_size(Value) =:= 0;semantically_empty(_) -> false.
%% Binaries at least this large cross process boundaries by reference.-define(SHARED, 512).
%% One encoded input as iodata with its small fragments coalesced. Encoding40 unmodified lines206 unmodified linesExpand all207208209210211212213214215216217218219220221211212213214215216303 unmodified linesExpand all206 unmodified linesExpand all }) |> option.from_result}
fn semantically_empty(value: dynamic.Dynamic) -> Bool { case decode.run(value, decode.optional(decode.dynamic)) { Ok(None) -> True _ -> decode.run(value, decode.string) == Ok("") || decode.run(value, decode.list(decode.dynamic)) == Ok([]) || decode.run(value, decode.dict(decode.dynamic, decode.dynamic)) |> result.map(dict.is_empty) |> result.unwrap(False) }}@external(erlang, "albedo_openai_json", "semantically_empty")fn semantically_empty(value: dynamic.Dynamic) -> Bool
fn apply_chunk( state: State, chunk: Chunk,303 unmodified linesExpand all