| 1 |
|
defmodule History do |
| 2 |
|
import Enum, only: [any?: 2, find_value: 3, filter: 2, map: 2] |
| 3 |
|
import Msg, only: [result: 2] |
| 4 |
|
|
| 5 |
|
def record({parts, state}) do |
| 6 |
189 |
record(parts, state) |
| 7 |
|
end |
| 8 |
|
|
| 9 |
|
def record(parts, state) when is_list(parts) do |
| 10 |
189 |
{messages, text} = craft(parts) |
| 11 |
189 |
route(any?(parts, &done?/1), text, state, messages) |
| 12 |
|
end |
| 13 |
|
|
| 14 |
|
def record({:error, reason}, state) do |
| 15 |
:-( |
{:reply, "Error: #{reason}", state} |
| 16 |
|
end |
| 17 |
|
|
| 18 |
88 |
defp route(true, _text, state, messages) do |
| 19 |
88 |
{:act, %{state | history: state.history ++ messages}} |
| 20 |
|
end |
| 21 |
|
|
| 22 |
|
defp route(false, text, state, messages) do |
| 23 |
101 |
{:reply, text, %{state | history: state.history ++ messages}} |
| 24 |
|
end |
| 25 |
|
|
| 26 |
189 |
defp craft(parts) do |
| 27 |
189 |
text = find_value(parts, "", &text/1) |
| 28 |
189 |
content = extract(parts) |
| 29 |
|
{msgs(content, parts), text} |
| 30 |
|
end |
| 31 |
|
|
| 32 |
|
defp msgs(content, parts) do |
| 33 |
189 |
msg(content) ++ wrap(parts) |
| 34 |
|
end |
| 35 |
|
|
| 36 |
8 |
defp msg([]), do: [] |
| 37 |
181 |
defp msg(content), do: [%{role: "assistant", content: content}] |
| 38 |
|
|
| 39 |
|
defp wrap(parts) do |
| 40 |
189 |
gather(any?(parts, &done?/1), parts) |
| 41 |
|
end |
| 42 |
|
|
| 43 |
88 |
defp gather(true, parts), do: harvest(parts) |
| 44 |
101 |
defp gather(false, _parts), do: [] |
| 45 |
|
|
| 46 |
|
defp extract(parts) do |
| 47 |
|
parts |
| 48 |
|
|> filter(&rich?/1) |
| 49 |
189 |
|> map(&form/1) |
| 50 |
|
end |
| 51 |
|
|
| 52 |
|
defp harvest(parts) do |
| 53 |
|
parts |
| 54 |
|
|> filter(&done?/1) |
| 55 |
88 |
|> map(&pack/1) |
| 56 |
|
end |
| 57 |
|
|
| 58 |
146 |
defp rich?(%{"text" => _}), do: true |
| 59 |
129 |
defp rich?(%{"tool_use" => _}), do: true |
| 60 |
:-( |
defp rich?(_), do: false |
| 61 |
|
|
| 62 |
|
defp form(%{"text" => text}) do |
| 63 |
146 |
%{type: "text", text: text} |
| 64 |
|
end |
| 65 |
|
|
| 66 |
|
defp form(%{ |
| 67 |
|
"tool_use" => %{"id" => id, "name" => name, "input" => input} |
| 68 |
|
}) do |
| 69 |
129 |
%{type: "tool_use", id: id, name: name, input: input} |
| 70 |
|
end |
| 71 |
|
|
| 72 |
|
defp pack(%{"tool_use" => %{"id" => id}, "result" => result}) do |
| 73 |
129 |
result(id, stringify(result)) |
| 74 |
|
end |
| 75 |
|
|
| 76 |
146 |
defp text(%{"text" => text}), do: text |
| 77 |
41 |
defp text(_), do: nil |
| 78 |
|
|
| 79 |
305 |
defp done?(%{"result" => _}), do: true |
| 80 |
345 |
defp done?(_), do: false |
| 81 |
|
|
| 82 |
127 |
defp stringify(c) when is_binary(c), do: c |
| 83 |
2 |
defp stringify(c), do: inspect(c) |
| 84 |
|
end |