| 1 |
|
defmodule Elita do |
| 2 |
|
use GenServer |
| 3 |
|
|
| 4 |
|
import Cfgs, only: [load: 1] |
| 5 |
|
import History, only: [record: 1] |
| 6 |
|
import Llm, only: [llm: 1] |
| 7 |
|
import Map, only: [merge: 2, get: 2] |
| 8 |
|
import Mem, only: [create: 1] |
| 9 |
|
import Msg, only: [user: 1] |
| 10 |
|
import Reply, only: [deliver: 2] |
| 11 |
|
import String, only: [trim: 1] |
| 12 |
|
import Keyword, only: [get: 3] |
| 13 |
|
import Utils.Normalize, only: [name: 1] |
| 14 |
|
import Process, only: [flag: 2] |
| 15 |
|
import Elita.Enlist, only: [handle: 4, cleanup: 1, release: 1] |
| 16 |
|
import Elita.Vault, only: [restore: 1, save: 2] |
| 17 |
|
import Tools |
| 18 |
|
|
| 19 |
21 |
defdelegate spawn(name, configs), to: Elita.Boot |
| 20 |
37 |
defdelegate spawn(name, configs, opts), to: Elita.Boot |
| 21 |
1 |
defdelegate prime(), to: Elita.Boot |
| 22 |
42 |
defdelegate dispatch(name, msg), to: Elita.Boot |
| 23 |
59 |
defdelegate request(name, msg), to: Elita.Boot |
| 24 |
|
|
| 25 |
|
@impl true |
| 26 |
:-( |
def init({name, configs}), do: init({name, configs, [sender: name]}) |
| 27 |
|
|
| 28 |
|
@impl true |
| 29 |
|
def init({name, configs, opts}) do |
| 30 |
58 |
with {:ok, opts, name, configs} <- |
| 31 |
|
handle({name(name), :puppet}, opts, name, configs) do |
| 32 |
58 |
prepare(opts, name, configs) |
| 33 |
|
end |
| 34 |
|
end |
| 35 |
|
|
| 36 |
|
defp prepare(opts, name, configs) do |
| 37 |
58 |
flag(:trap_exit, true) |
| 38 |
58 |
setup(opts, name, configs) |
| 39 |
|
end |
| 40 |
|
|
| 41 |
58 |
defp setup(opts, name, configs) do |
| 42 |
58 |
settings = get(opts, :tape_env, %{}) |
| 43 |
58 |
create(name) |
| 44 |
58 |
seed(get(settings, :tape)) |
| 45 |
|
{:ok, state(name, configs, opts, settings)} |
| 46 |
|
end |
| 47 |
|
|
| 48 |
|
defp state(name, configs, opts, settings) do |
| 49 |
58 |
base = base(name, configs) |
| 50 |
58 |
sender = get(opts, :sender, name) |
| 51 |
58 |
skip = get(opts, :skip_logs, false) |
| 52 |
58 |
merge(merge(base, settings), %{sender: sender, skip_logs: skip}) |
| 53 |
|
end |
| 54 |
|
|
| 55 |
|
defp base(name, configs) do |
| 56 |
58 |
history = restore(name) |
| 57 |
58 |
%{name: name, config: load(configs), history: history, configs: configs} |
| 58 |
|
end |
| 59 |
|
|
| 60 |
21 |
defp seed(nil), do: :ok |
| 61 |
37 |
defp seed(_), do: :rand.seed(:exsss, {1, 2, 3}) |
| 62 |
|
@impl true |
| 63 |
:-( |
def handle_call({:ask, msg}, from, state), do: handle_call({:act, msg}, from, state) |
| 64 |
|
@impl true |
| 65 |
59 |
def handle_call({:act, msg}, _, state), do: act(msg, state) |
| 66 |
|
@impl true |
| 67 |
42 |
def handle_cast({:act, msg}, state) do |
| 68 |
42 |
{_, _, state} = act(msg, state) |
| 69 |
|
{:noreply, state} |
| 70 |
|
end |
| 71 |
|
|
| 72 |
|
defp act(msg, %{configs: configs, history: history} = state) do |
| 73 |
101 |
history = branch("judge" in configs, history, user(msg)) |
| 74 |
101 |
act(%{state | history: history}) |
| 75 |
|
end |
| 76 |
|
|
| 77 |
:-( |
defp branch(true, _, msg), do: [msg] |
| 78 |
101 |
defp branch(false, history, msg), do: history ++ [msg] |
| 79 |
|
|
| 80 |
|
defp act(state) do |
| 81 |
189 |
state |> llm() |> exec() |> record() |> done() |
| 82 |
|
end |
| 83 |
|
|
| 84 |
88 |
defp done({:act, state}), do: act(state) |
| 85 |
|
|
| 86 |
|
defp done({:reply, txt, %{name: name, history: history} = state}) do |
| 87 |
101 |
deliver(name, trim(txt)) |
| 88 |
101 |
save(name, history) |
| 89 |
101 |
{:reply, trim(txt), state} |
| 90 |
|
end |
| 91 |
|
|
| 92 |
|
@impl true |
| 93 |
37 |
def terminate(:normal, state), do: cleanup(state) |
| 94 |
:-( |
def terminate(:shutdown, state), do: cleanup(state) |
| 95 |
:-( |
def terminate({:shutdown, _}, state), do: cleanup(state) |
| 96 |
:-( |
def terminate(_reason, state), do: release(state) |
| 97 |
|
end |