okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

Aly Raffauffeat(progress): reduce preview parsing from O(s*n^2) to O(n)60cce3a

main
5.8 KiB159 linesraw
1// Proxy history and encoded provider-state IDs have malformed and truncated wire inputs the E2E flow cannot reliably generate.
2import albedo/harness/extensions/proxy/chat
3import albedo/openai_api/types
4import gleam/dynamic/decode
5import gleam/json
6import gleam/list
7import gleam/option.{None, Some}
8import gleam/string
9
10fn parse(body: String) -> Result(chat.Completion, String) {
11  chat.parse(<<body:utf8>>)
12}
13
14fn inputs(completion: chat.Completion) -> List(types.Input) {
15  list.map(completion.history, fn(entry) { entry.input })
16}
17
18pub fn tool_history_becomes_replay_and_tool_output_test() -> List(types.Tool) {
19  let assert Ok(completion) =
20    parse(
21      "{\"model\":\"p/m\",\"messages\":[{\"role\":\"user\",\"content\":\"go\"},{\"role\":\"assistant\",\"content\":null,\"tool_calls\":[{\"id\":\"c1\",\"type\":\"function\",\"function\":{\"name\":\"bash\",\"arguments\":\"{}\"}}]},{\"role\":\"tool\",\"tool_call_id\":\"c1\",\"content\":\"ok\"}],\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"bash\"}}]}",
22    )
23  let assert [
24    types.User("go"),
25    types.Replay(item),
26    types.ToolOutput("c1", "ok", []),
27  ] = inputs(completion)
28  assert types.inspect_item(
29      item,
30      decode.at(["tool_calls"], decode.list(decode.at(["id"], decode.string))),
31    )
32    == Ok(["c1"])
33  let assert [types.Tool("bash", "", _, False)] = completion.request.tools
34}
35
36pub fn remote_images_are_refused_test() -> Nil {
37  let assert Error(message) =
38    parse(
39      "{\"model\":\"p/m\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"image_url\",\"image_url\":{\"url\":\"https://x/y.png\"}}]}]}",
40    )
41  assert string.contains(message, "data urls")
42}
43
44pub fn provider_state_rides_back_in_the_first_call_id_test() -> Nil {
45  let carried = chat.carry(responses_turn(), "cx", types.Responses)
46  let assert [first, second] = carried.tool_calls
47  assert string.starts_with(first.id, "call_1__albedo__")
48  assert second.id == "call_2"
49  // Strict clients accept only [A-Za-z0-9_-] in ids.
50  assert string.to_graphemes(first.id)
51    |> list.all(fn(c) {
52      string.contains(
53        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-",
54        c,
55      )
56    })
57  let assert Ok(completion) = parse(echoed(carried))
58  let assert [_, reasoning, call, first_result, second_result] =
59    completion.history
60  // The native items return tagged with the profile that produced them.
61  assert reasoning.provider == Some("cx")
62  let assert types.Replay(item) = reasoning.input
63  assert types.replay_protocol(item) == types.Responses
64  assert types.inspect_item(
65      item,
66      decode.at(["encrypted_content"], decode.string),
67    )
68    == Ok("opaque-state")
69  assert call.provider == Some("cx")
70  // Results point at the provider's own call ids again.
71  assert first_result.input == types.ToolOutput("call_1", "ok", [])
72  assert second_result.input == types.ToolOutput("call_2", "ok", [])
73}
74
75pub fn damaged_state_falls_back_to_portable_history_test() -> Nil {
76  let assert Ok(completion) =
77    parse(
78      "{\"model\":\"cx/m\",\"messages\":[{\"role\":\"assistant\",\"content\":null,\"tool_calls\":[{\"id\":\"call_1__albedo__not-state\",\"type\":\"function\",\"function\":{\"name\":\"bash\",\"arguments\":\"{}\"}}]},{\"role\":\"tool\",\"tool_call_id\":\"call_1__albedo__not-state\",\"content\":\"ok\"}]}",
79    )
80  let assert [call, result] = completion.history
81  assert call.provider == None
82  let assert types.Replay(item) = call.input
83  assert types.inspect_item(
84      item,
85      decode.at(["tool_calls"], decode.list(decode.at(["id"], decode.string))),
86    )
87    == Ok(["call_1"])
88  assert result.input == types.ToolOutput("call_1", "ok", [])
89}
90
91/// Clients that normalize ids (LiteLLM #37849) must not corrupt a replay.
92/// Short cuts can remove only the zlib checksum and leave complete JSON, so
93/// every one replays portably instead of trusting unverified state.
94pub fn a_shortened_carried_id_replays_portably_test() -> Nil {
95  let carried = chat.carry(responses_turn(), "cx", types.Responses)
96  let assert [first, second] = carried.tool_calls
97  list.each([1, 2, 3, 4, 5, 6], fn(n) {
98    let cut = string.drop_end(first.id, n)
99    let shortened =
100      types.Turn(..carried, tool_calls: [
101        types.ToolCall(..first, id: cut),
102        second,
103      ])
104    let assert Ok(completion) = parse(echoed(shortened))
105    let assert [_, call, first_result, _] = completion.history
106    assert call.provider == None
107    assert first_result.input == types.ToolOutput("call_1", "ok", [])
108  })
109}
110
111fn responses_turn() -> types.Turn {
112  let assert Ok(reasoning) =
113    json.parse(
114      "{\"type\":\"reasoning\",\"id\":\"rs_1\",\"summary\":[],\"encrypted_content\":\"opaque-state\"}",
115      types.replay_decoder(types.Responses),
116    )
117  let assert Ok(call) =
118    json.parse(
119      "{\"type\":\"function_call\",\"call_id\":\"call_1\",\"name\":\"bash\",\"arguments\":\"{}\",\"status\":\"completed\"}",
120      types.replay_decoder(types.Responses),
121    )
122  types.Turn(
123    Some("r"),
124    [reasoning, call],
125    [
126      types.ToolCall("call_1", "bash", "{}"),
127      types.ToolCall("call_2", "bash", "{}"),
128    ],
129    None,
130    types.ToolCalls,
131    None,
132    [#("call_1", 0), #("call_2", 1)],
133  )
134}
135
136/// What a client sends back after this turn: plain chat with our ids.
137fn echoed(turn: types.Turn) -> String {
138  let calls =
139    turn.tool_calls
140    |> list.map(fn(call) {
141      "{\"id\":\""
142      <> call.id
143      <> "\",\"type\":\"function\",\"function\":{\"name\":\"bash\",\"arguments\":\"{}\"}}"
144    })
145    |> string.join(",")
146  let results =
147    turn.tool_calls
148    |> list.map(fn(call) {
149      ",{\"role\":\"tool\",\"tool_call_id\":\""
150      <> call.id
151      <> "\",\"content\":\"ok\"}"
152    })
153    |> string.concat
154  "{\"model\":\"cx/m\",\"messages\":[{\"role\":\"user\",\"content\":\"go\"},{\"role\":\"assistant\",\"content\":null,\"tool_calls\":["
155  <> calls
156  <> "]}"
157  <> results
158  <> "]}"
159}