perf(stream): validate delta maps without rebuilding them
OTP 28 medians used 2.4% fewer reductions for text and 4.9% fewer with reasoning; plain-text timing was unchanged. Keep string-key validation; all 212 Gleam tests passed.
5 unmodified lines6789101112131415165 unmodified lines [?_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}]].
object_fields_test_() -> [?_assertEqual({ok, Value}, albedo_openai_json:object_fields(Value)) || Value <- [#{}, #{<<"content">> => <<"hello">>, <<"opaque">> => [1, #{}]}]] ++ [?_assertEqual({error, #{}}, albedo_openai_json:object_fields(Value)) || Value <- [null, [], 42, <<"x">>, #{content => <<"hello">>}, #{<<"content">> => <<"hello">>, 1 => null}]].213 unmodified linesExpand all214215216217218219220221222223224225226227228229160 unmodified linesExpand all213 unmodified linesExpand all send(stream.new(types.ChatCompletions), "", data) })}
pub fn chat_rejects_non_object_deltas_test() -> Nil { list.each(["null", "[]", "42", "\"x\"", "false"], fn(value) { let data = "{\"choices\":[{\"index\":0,\"delta\":" <> 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 all12234567 unmodified lines141516171819202122232425262728293031323334353640 unmodified lines-module(albedo_openai_json).-export([encode/1, null/0, flatten/1, data_url/2, base64_string/1, semantically_empty/1]).-export([encode/1, null/0, flatten/1, data_url/2, base64_string/1, semantically_empty/1, object_fields/1]).
encode(Value) -> json:encode(Value).
null() -> null.7 unmodified linessemantically_empty({}) -> true;semantically_empty(Value) when is_map(Value) -> map_size(Value) =:= 0;semantically_empty(_) -> false.
%% Validate the typed key contract while retaining the original map and values.object_fields(Value) when is_map(Value) -> case has_string_keys(maps:iterator(Value)) of true -> {ok, Value}; false -> {error, #{}} end;object_fields(_) -> {error, #{}}.
has_string_keys(Iterator) -> case maps:next(Iterator) of none -> true; {Key, _, Next} when is_binary(Key) -> has_string_keys(Next); _ -> false end.
%% 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 lines118 unmodified linesExpand all11912012112212312312412512612725 unmodified lines153154155156157158159160161162163164165359 unmodified linesExpand all118 unmodified linesExpand all decode.success(Choice(index, delta, finish))}
fn delta_decoder() -> decode.Decoder(Delta) { use fields <- decode.then(decode.dict(decode.string, decode.dynamic)) use fields <- decode.then(decode.new_primitive_decoder("Dict", object_fields)) case unsupported_field(fields) { Some(field) -> decode.failure( Delta(None, None, None, reasoning.empty_delta(), []),25 unmodified lines } }}
@external(erlang, "albedo_openai_json", "object_fields")fn object_fields( value: dynamic.Dynamic,) -> Result(Dict(String, dynamic.Dynamic), Dict(String, dynamic.Dynamic))
fn non_empty_string() -> decode.Decoder(Option(String)) { decode.optional(decode.string) |> decode.map(fn(value) { case value {359 unmodified linesExpand all