Packages
fnord
0.8.58
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/services/conversation/interrupts.ex
defmodule Services.Conversation.Interrupts do
@moduledoc """
Queue for injecting user messages into a conversation mid-completion.
This GenServer stores a FIFO list of pending injected user messages per
conversation pid. AI.Completion will drain and apply these messages at safe
checkpoints before sending a model request or between tool-call rounds.
"""
use GenServer
@type msg :: AI.Util.msg()
@doc """
Start the interrupt queue server.
"""
@spec start_link(Keyword.t()) :: GenServer.on_start()
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, %{}, Keyword.merge([name: __MODULE__], opts))
end
@doc """
Enqueue an injected user message for the given conversation pid.
"""
@spec request(pid(), String.t()) :: :ok
def request(conversation_pid, content)
when is_pid(conversation_pid) and
is_binary(content) do
msg = AI.Util.user_msg("[User Interjection] " <> content)
GenServer.cast(__MODULE__, {:enqueue, conversation_pid, msg})
:ok
end
@doc """
Drain all pending injected messages for a conversation.
Returns an empty list if none are pending.
"""
@spec take_all(pid()) :: [msg]
def take_all(conversation_pid) when is_pid(conversation_pid) do
GenServer.call(__MODULE__, {:take_all, conversation_pid})
end
@doc """
Returns true if any interrupts are pending for the conversation pid.
"""
@spec pending?(pid()) :: boolean()
def pending?(conversation_pid) when is_pid(conversation_pid) do
GenServer.call(__MODULE__, {:pending, conversation_pid})
end
# ---------------------------------------------------------------------------
# GenServer callbacks
# ---------------------------------------------------------------------------
@impl true
@spec init(map()) :: {:ok, map()}
def init(state), do: {:ok, state}
@impl true
@spec handle_cast({:enqueue, pid(), msg}, map()) :: {:noreply, map()}
def handle_cast({:enqueue, pid, msg}, state) do
{:noreply, Map.update(state, pid, [msg], fn list -> list ++ [msg] end)}
end
@impl true
@spec handle_call({:take_all, pid()}, GenServer.from(), map()) :: {:reply, [msg], map()}
def handle_call({:take_all, pid}, _from, state) do
{msgs, new_state} = Map.pop(state, pid, [])
{:reply, msgs, new_state}
end
@impl true
@spec handle_call({:pending, pid()}, GenServer.from(), map()) :: {:reply, boolean(), map()}
def handle_call({:pending, pid}, _from, state) do
{:reply, Map.has_key?(state, pid), state}
end
end