Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
17 kB · 407 lines
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408import albedo/openai_api/sseimport albedo/openai_api/streamimport albedo/openai_api/typesimport gleam/dynamic/decodeimport gleam/jsonimport gleam/option.{type Option, None, Some}
pub fn responses_normalizes_deltas_and_preserves_authoritative_output_test() { let state = stream.new(types.Responses) let assert Ok(#(state, [types.Started("resp_1")], None)) = send( state, "response.created", "{\"type\":\"response.created\",\"response\":{\"id\":\"resp_1\"}}", ) let assert Ok(#(state, [], None)) = send(state, "future.event", "{\"type\":\"future.event\",\"opaque\":true}") let assert Ok(#(state, [types.TextDelta(1, 2, "hello")], None)) = send( state, "response.output_text.delta", "{\"type\":\"response.output_text.delta\",\"output_index\":1,\"content_index\":2,\"delta\":\"hello\"}", ) let assert Ok(#(state, [types.ArgumentsDelta(2, "{\"x\":")], None)) = send( state, "response.function_call_arguments.delta", "{\"type\":\"response.function_call_arguments.delta\",\"output_index\":2,\"delta\":\"{\\\"x\\\":\"}", ) let completed = "{\"type\":\"response.completed\",\"response\":{\"id\":\"resp_1\",\"output\":[{\"type\":\"reasoning\",\"id\":\"rs_1\",\"encrypted_content\":\"ciphertext\",\"phase\":\"analysis\",\"summary\":[]},{\"type\":\"message\",\"id\":\"msg_1\",\"role\":\"assistant\",\"content\":[{\"type\":\"output_text\",\"text\":\"hello\",\"annotations\":[]}]},{\"type\":\"function_call\",\"call_id\":\"call_1\",\"name\":\"lookup\",\"arguments\":\"{\\\"x\\\":1}\",\"status\":\"completed\"}],\"usage\":{\"input_tokens\":11,\"output_tokens\":7,\"input_tokens_details\":{\"cached_tokens\":4}}}}" let assert Ok(#( _, [], Some(types.Turn( Some("resp_1"), [reasoning, _, _], [types.ToolCall("call_1", "lookup", "{\"x\":1}")], Some(types.Usage(11, 7, Some(4))), types.ToolCalls, )), )) = send(state, "response.completed", completed) let decoder = { use encrypted <- decode.field("encrypted_content", decode.string) use phase <- decode.field("phase", decode.string) decode.success(#(encrypted, phase)) } assert types.inspect_item(reasoning, decoder) == Ok(#("ciphertext", "analysis"))}
pub fn responses_incomplete_never_exposes_executable_calls_test() { let data = "{\"type\":\"response.incomplete\",\"response\":{\"output\":[{\"type\":\"function_call\",\"call_id\":\"danger\",\"name\":\"delete\",\"arguments\":\"{}\"}],\"incomplete_details\":{\"reason\":\"max_output_tokens\"}}}" let assert Ok(#( _, [], Some(types.Turn(None, [_], [], None, types.LengthLimit)), )) = send(stream.new(types.Responses), "response.incomplete", data)}
pub fn responses_provider_failures_and_malformed_fields_are_typed_test() { let failed = "{\"type\":\"response.failed\",\"response\":{\"error\":{\"message\":\"capacity\"}}}" assert send(stream.new(types.Responses), "response.failed", failed) == Error(types.ProviderError("capacity")) let malformed = "{\"type\":\"response.created\",\"response\":{\"id\":42}}" let assert Error(types.InvalidEvent(_)) = send(stream.new(types.Responses), "response.created", malformed) let unsupported = "{\"type\":\"response.custom_tool_call_input.delta\",\"delta\":\"rm\"}" assert send( stream.new(types.Responses), "response.custom_tool_call_input.delta", unsupported, ) == Error(types.Unsupported( "unsupported Responses semantic event: response.custom_tool_call_input.delta", ))}
pub fn chat_accumulates_interleaved_tools_usage_and_native_replay_test() { let state = stream.new(types.ChatCompletions) let first = "{\"id\":\"chat_1\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"hel\",\"reasoning_content\":\"think \"},\"finish_reason\":null}]}" let assert Ok(#( state, [ types.Started("chat_1"), types.ThinkingDelta("think "), types.TextDelta(0, 0, "hel"), ], None, )) = send(state, "", first) let one = "{\"id\":\"chat_1\",\"choices\":[{\"index\":0,\"delta\":{\"tool_calls\":[{\"index\":1,\"id\":\"call_b\",\"type\":\"function\",\"function\":{\"name\":\"beta\",\"arguments\":\"{\\\"b\\\":\"}},{\"index\":0,\"id\":\"call_a\",\"type\":\"function\",\"function\":{\"name\":\"alpha\",\"arguments\":\"{\\\"a\\\":\"}}]},\"finish_reason\":null}]}" let assert Ok(#( state, [types.ArgumentsDelta(1, "{\"b\":"), types.ArgumentsDelta(0, "{\"a\":")], None, )) = send(state, "", one) let two = "{\"id\":\"chat_1\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"lo\",\"refusal\":\"no\",\"reasoning_content\":\"carefully\",\"tool_calls\":[{\"index\":0,\"function\":{\"arguments\":\"1}\"}},{\"index\":1,\"function\":{\"arguments\":\"2}\"}}]},\"finish_reason\":\"tool_calls\"}]}" let assert Ok(#(state, events, None)) = send(state, "", two) assert events == [ types.ThinkingDelta("carefully"), types.TextDelta(0, 0, "lo"), types.ArgumentsDelta(0, "1}"), types.ArgumentsDelta(1, "2}"), ] let usage = "{\"id\":\"chat_1\",\"choices\":[],\"usage\":{\"prompt_tokens\":5,\"completion_tokens\":8,\"total_tokens\":13,\"prompt_tokens_details\":{\"cached_tokens\":0}}}" let assert Ok(#(state, [], None)) = send(state, "", usage) let assert Ok(#( _, [], Some(types.Turn( Some("chat_1"), [message], [ types.ToolCall("call_a", "alpha", "{\"a\":1}"), types.ToolCall("call_b", "beta", "{\"b\":2}"), ], Some(types.Usage(5, 8, Some(0))), types.ToolCalls, )), )) = send(state, "", "[DONE]") let decoder = { use content <- decode.field("content", decode.string) use refusal <- decode.field("refusal", decode.string) use reasoning <- decode.field("reasoning_content", decode.string) use tool_ids <- decode.field( "tool_calls", decode.list({ use id <- decode.field("id", decode.string) decode.success(id) }), ) decode.success(#(content, refusal, reasoning, tool_ids)) } assert types.inspect_item(message, decoder) == Ok(#("hello", "no", "think carefully", ["call_a", "call_b"]))}
pub fn cache_usage_details_tolerate_null_and_reject_malformed_values_test() { let responses_null = "{\"type\":\"response.completed\",\"response\":{\"output\":[],\"usage\":{\"input_tokens\":3,\"output_tokens\":2,\"input_tokens_details\":null}}}" let assert Ok(#( _, [], Some(types.Turn(_, [], [], Some(types.Usage(3, 2, None)), _)), )) = send(stream.new(types.Responses), "", responses_null)
let chat_null = "{\"choices\":[{\"index\":0,\"delta\":{},\"finish_reason\":\"stop\"}],\"usage\":{\"prompt_tokens\":3,\"completion_tokens\":2,\"prompt_tokens_details\":null}}" let assert Ok(#(state, _, None)) = send(stream.new(types.ChatCompletions), "", chat_null) let assert Ok(#( _, [], Some(types.Turn(_, _, [], Some(types.Usage(3, 2, None)), _)), )) = send(state, "", "[DONE]")
let responses_malformed = "{\"type\":\"response.completed\",\"response\":{\"output\":[],\"usage\":{\"input_tokens\":3,\"output_tokens\":2,\"input_tokens_details\":{\"cached_tokens\":\"3\"}}}}" let assert Error(types.InvalidEvent(_)) = send(stream.new(types.Responses), "", responses_malformed)
let chat_malformed = "{\"choices\":[],\"usage\":{\"prompt_tokens\":3,\"completion_tokens\":2,\"prompt_tokens_details\":{\"cached_tokens\":\"3\"}}}" let assert Error(types.InvalidEvent(_)) = send(stream.new(types.ChatCompletions), "", chat_malformed)}
pub fn responses_streams_reasoning_apart_from_the_answer_test() { let state = stream.new(types.Responses) let assert Ok(#(state, [types.ThinkingDelta("weigh ")], None)) = send( state, "", "{\"type\":\"response.reasoning_summary_text.delta\",\"output_index\":0,\"summary_index\":0,\"delta\":\"weigh \"}", ) let assert Ok(#(_state, [types.ThinkingDelta("options")], None)) = send( state, "", "{\"type\":\"response.reasoning_text.delta\",\"output_index\":0,\"content_index\":0,\"delta\":\"options\"}", )}
pub fn responses_separates_reasoning_summary_parts_test() { let part = fn(index) { "{\"type\":\"response.reasoning_summary_part.added\",\"output_index\":0,\"summary_index\":" <> index <> ",\"part\":{\"type\":\"summary_text\",\"text\":\"\"}}" } let state = stream.new(types.Responses) let assert Ok(#(state, [], None)) = send(state, "", part("0")) let assert Ok(#(_state, [types.ThinkingDelta("\n\n")], None)) = send(state, "", part("1"))}
pub fn chat_streams_one_thinking_event_per_delta_test() { let chunk = "{\"choices\":[{\"index\":0,\"delta\":{\"reasoning\":\"r1\",\"reasoning_content\":\"c1\"}}]}" let assert Ok(#(_state, events, None)) = send(stream.new(types.ChatCompletions), "", chunk) assert events == [types.ThinkingDelta("c1")]}
pub fn chat_rejects_multiple_choices_and_nonempty_unknown_semantics_test() { let multiple = "{\"choices\":[{\"index\":0,\"delta\":{}},{\"index\":1,\"delta\":{}}]}" assert send(stream.new(types.ChatCompletions), "", multiple) == Error(types.Unsupported("multiple chat completion choices")) let audio = "{\"choices\":[{\"index\":0,\"delta\":{\"audio\":{\"id\":\"a\"}}}]}" let assert Error(types.InvalidEvent(_)) = send(stream.new(types.ChatCompletions), "", audio)}
pub fn chat_requires_finish_and_suppresses_partial_tools_on_limits_test() { assert send(stream.new(types.ChatCompletions), "", "[DONE]") == Error(types.InvalidEvent("[DONE] before chat finish reason")) let partial = "{\"choices\":[{\"index\":0,\"delta\":{\"tool_calls\":[{\"index\":0,\"id\":\"call_partial\",\"type\":\"function\",\"function\":{\"name\":\"unsafe\",\"arguments\":\"{\"}}]},\"finish_reason\":\"length\"}]}" let assert Ok(#(state, _, None)) = send(stream.new(types.ChatCompletions), "", partial) let assert Ok(#( _, [], Some(types.Turn(None, [message], [], None, types.LengthLimit)), )) = send(state, "", "[DONE]") let decoder = { use calls <- decode.optional_field( "tool_calls", None, decode.optional(decode.list(decode.dynamic)), ) decode.success(calls) } assert types.inspect_item(message, decoder) == Ok(None)}
pub fn malformed_json_and_content_filter_finish_are_typed_test() { let assert Error(types.InvalidEvent(_)) = send(stream.new(types.ChatCompletions), "", "{") let assert Error(types.InvalidEvent(_)) = send(stream.new(types.Responses), "", "[]")
let filtered = "{\"choices\":[{\"index\":0,\"delta\":{\"content\":\"safe prefix\"},\"finish_reason\":\"content_filter\"}]}" let assert Ok(#(state, _, None)) = send(stream.new(types.ChatCompletions), "", filtered) let assert Ok(#(_, [], Some(types.Turn(_, _, [], _, types.ContentFiltered)))) = send(state, "", "[DONE]")}
pub fn chat_preserves_other_finish_reason_test() { let chunk = "{\"choices\":[{\"index\":0,\"delta\":{\"content\":\"x\"},\"finish_reason\":\"model_shutdown\"}]}" let assert Ok(#(state, _, None)) = send(stream.new(types.ChatCompletions), "", chunk) let assert Ok(#( _, [], Some(types.Turn(_, _, [], _, types.OtherFinish("model_shutdown"))), )) = send(state, "", "[DONE]")}
fn send( state: stream.State, name: String, data: String,) -> Result(#(stream.State, List(types.Event), Option(types.Turn)), types.Error) { stream.feed(state, sse.Event(name, data))}
pub fn chat_assembles_name_fragments_and_encodes_tool_only_content_as_null_test() { let first = "{\"choices\":[{\"index\":0,\"delta\":{\"tool_calls\":[{\"index\":0,\"id\":\"call1\",\"function\":{\"name\":\"read_\",\"arguments\":\"{\"}}]}}]}" let second = "{\"choices\":[{\"index\":0,\"delta\":{\"tool_calls\":[{\"index\":0,\"function\":{\"name\":\"file\",\"arguments\":\"}\"}}]},\"finish_reason\":\"tool_calls\"}]}" let assert Ok(#(state, _, None)) = send(stream.new(types.ChatCompletions), "", first) let assert Ok(#(state, _, None)) = send(state, "", second) let assert Ok(#(state, _, Some(turn))) = send(state, "", "[DONE]") assert turn.tool_calls == [types.ToolCall("call1", "read_file", "{}")] let assert [item] = turn.output let encoded = types.replay_json(item) |> json.to_string assert json.parse( encoded, decode.at(["content"], decode.optional(decode.string)), ) == Ok(None) let assert Error(types.InvalidEvent(_)) = send(state, "", "[DONE]")}
pub fn chat_rejects_data_after_finish_reason_test() { let first = "{\"choices\":[{\"index\":0,\"delta\":{},\"finish_reason\":\"stop\"}]}" let late = "{\"choices\":[{\"index\":0,\"delta\":{\"content\":\"late\"}}]}" let assert Ok(#(state, _, None)) = send(stream.new(types.ChatCompletions), "", first) let assert Error(types.InvalidEvent(_)) = send(state, "", late)}
pub fn responses_keeps_refusal_in_final_item_test() { let delta = "{\"type\":\"response.refusal.delta\",\"output_index\":0,\"content_index\":0,\"delta\":\"no\"}" let final = "{\"type\":\"response.completed\",\"response\":{\"output\":[{\"type\":\"message\",\"role\":\"assistant\",\"content\":[{\"type\":\"refusal\",\"refusal\":\"no\"}]}]}}" let assert Ok(#(state, _, None)) = send(stream.new(types.Responses), "", delta) let assert Ok(#(_, _, Some(turn))) = send(state, "", final) let assert [item] = turn.output assert types.inspect_item( item, decode.at(["content"], decode.list(decode.at(["refusal"], decode.string))), ) == Ok(["no"])}
pub fn chat_streamed_provider_error_is_reported_test() { assert send( stream.new(types.ChatCompletions), "", "{\"error\":{\"message\":\"rate limited\"}}", ) == Error(types.ProviderError("rate limited"))}
pub fn responses_rejects_incomplete_call_in_completed_response_test() { let event = "{\"type\":\"response.completed\",\"response\":{\"output\":[{\"type\":\"function_call\",\"call_id\":\"c\",\"name\":\"tool\",\"arguments\":\"{}\",\"status\":\"in_progress\"}]}}" let assert Error(types.InvalidEvent(_)) = send(stream.new(types.Responses), "", event)}
pub fn compatible_reasoning_fields_are_preserved_without_renaming_test() { let first = "{\"choices\":[{\"index\":0,\"delta\":{\"reasoning\":\"r1\",\"reasoning_content\":\"c1\"}}]}" let second = "{\"choices\":[{\"index\":0,\"delta\":{\"reasoning\":\"r2\",\"reasoning_content\":\"c2\",\"content\":\"answer\"},\"finish_reason\":\"stop\"}]}" let assert Ok(#(state, _, None)) = send(stream.new(types.ChatCompletions), "", first) let assert Ok(#(state, _, None)) = send(state, "", second) let assert Ok(#(_, _, Some(turn))) = send(state, "", "[DONE]") let assert [item] = turn.output assert types.inspect_item(item, decode.at(["reasoning"], decode.string)) == Ok("r1r2") assert types.inspect_item( item, decode.at(["reasoning_content"], decode.string), ) == Ok("c1c2")}
pub fn reasoning_details_merge_fragments_by_index_and_keep_metadata_test() { let first = "{\"choices\":[{\"index\":0,\"delta\":{\"reasoning\":\"a\",\"reasoning_details\":[{\"type\":\"reasoning.text\",\"index\":0,\"format\":\"unknown\",\"text\":\"a\"}]}}]}" let second = "{\"choices\":[{\"index\":0,\"delta\":{\"reasoning\":\"b\",\"reasoning_details\":[{\"type\":\"reasoning.text\",\"index\":0,\"format\":\"unknown\",\"text\":\"b\"}],\"content\":\"answer\"},\"finish_reason\":\"stop\"}]}" let assert Ok(#(state, _, None)) = send(stream.new(types.ChatCompletions), "", first) let assert Ok(#(state, _, None)) = send(state, "", second) let assert Ok(#(_, _, Some(turn))) = send(state, "", "[DONE]") let assert [item] = turn.output assert types.inspect_item( item, decode.at( ["reasoning_details"], decode.list(decode.at(["text"], decode.string)), ), ) == Ok(["ab"]) assert types.inspect_item( item, decode.at( ["reasoning_details"], decode.list(decode.at(["format"], decode.string)), ), ) == Ok(["unknown"])}
pub fn responses_uses_streamed_done_items_when_terminal_output_is_empty_test() { let state = stream.new(types.Responses) let done = "{\"type\":\"response.output_item.done\",\"output_index\":0,\"item\":{\"type\":\"function_call\",\"call_id\":\"call_1\",\"name\":\"python\",\"arguments\":\"{\\\"code\\\":\\\"20 + 22\\\",\\\"timeout_ms\\\":1000}\",\"status\":\"completed\"}}" let assert Ok(#(state, [], None)) = send(state, "", done) let completed = "{\"type\":\"response.completed\",\"response\":{\"id\":\"resp_1\",\"output\":[],\"usage\":{\"input_tokens\":10,\"output_tokens\":5}}}" let assert Ok(#( _, [types.Started("resp_1")], Some(types.Turn( Some("resp_1"), [_], [types.ToolCall("call_1", "python", arguments)], _, types.ToolCalls, )), )) = send(state, "", completed) assert arguments == "{\"code\":\"20 + 22\",\"timeout_ms\":1000}"}