Eai.Chat (eai v1.0.3)

Copy Markdown

Main conversation GenServer managing multi-session chat history and async LLM tasks.

Summary

Functions

Returns a specification to start this module under a supervisor.

Explicitly close a chat session and release its history.

Ensure a chat session exists in state.sessions. If the session already exists, this is a no-op (returns :ok and state is unchanged). If the session does NOT exist, an empty session is materialized in state.sessions and :ok is returned.

Export chat session history to a gzip file.

Get full message history for a chat session.

Force interrupt current LLM task (async mode only).

List all active chat sessions with message count and status.

Load chat history from a gzip file and replace session's messages.

Send a message to LLM and get response (or enter interactive mode).

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

close_chat_session(name)

Explicitly close a chat session and release its history.

Cannot close "default" session.

Options

  • name (string) — Session name to close.

Returns

:ok on success. {:error, :cannot_close_default} when closing the "default" session. {:error, :not_found} when the session does not exist. {:error, :busy, message} when a task is still running in the session.

Example

iex> Eai.Chat.close_chat_session("research")
:ok

ensure_session_exists(chat_session \\ "default")

Ensure a chat session exists in state.sessions. If the session already exists, this is a no-op (returns :ok and state is unchanged). If the session does NOT exist, an empty session is materialized in state.sessions and :ok is returned.

This is used by Eai.System.restore_from_gzip/1 to PRE-CREATE every session in the snapshot before writing any messages, so that Eai.Chat.list_chat_sessions/0 sees the full set of sessions during the restore window. Without this pre-create, sessions appear one-by-one as replace_history/3 is called, and a concurrent observer could see an inconsistent state.

Options

  • chat_session (string) — Session name. Default: "default".

Returns

:ok

export_history(file_path, chat_session \\ "default")

Export chat session history to a gzip file.

Called by LLM tool export_chat_session_context or manually.

Options

  • file_path (string) — Destination file path.
  • chat_session (string) — Session to export. Default: "default"

Returns

`{:ok, info}` or `{:error, reason}`

Example

iex> Eai.Chat.export_history("/tmp/session.gz", "work")
{:ok, %{size_bytes: 5432, message_count: 42}}

get_history(chat_session \\ "default")

Get full message history for a chat session.

Options

  • chat_session (string) — Session name. Default: "default"

Returns

List of Eai.Message.t() in conversation order.

interrupt!(chat_session \\ "default")

Force interrupt current LLM task (async mode only).

Sets interrupt flag; next task poll injects Ctrl+C to running PTY process. Only works in async :human mode (sync mode blocks IEx).

Options

  • chat_session (string) — Session to interrupt. Default: "default"

Example

iex> Eai.Chat.interrupt!("work")
:ok

list_chat_sessions()

List all active chat sessions with message count and status.

Returns

`[{session_name, message_count, status}, ...]`
where status is `:idle` or `:busy`

replace_history(file_path, chat_session \\ "default", format \\ "converse")

Load chat history from a gzip file and replace session's messages.

Options

  • file_path (string) — Source gzip file path.
  • chat_session (string) — Target session. Default: "default"
  • format (string) — Message format. Default: "converse"
    • "converse" — already in Eai.Message IR format
    • "openai" — needs OpenAI adapter conversion
    • "anthropic" — needs Anthropic adapter conversion

Returns

`{:ok, info}` or `{:error, reason}`

Example

iex> Eai.Chat.replace_history("/tmp/session.gz", "work_restored")
{:ok, %{message_count: 42, chat_session: "work_restored"}}

snapshot_messages_bytes(chat_session_id)

start_link(opts \\ [])

talk(opts \\ [])

Send a message to LLM and get response (or enter interactive mode).

Options

  • :content (string) — User message. Required for :function mode.

  • :mod (:function | :human) — Execution mode. Default: :human

    • :function — one-shot, synchronous, returns {:ok, reply} or {:error, reason}
    • :human — interactive, type /s to send, /c to cancel
  • :timeout (integer) — Max wait for reply in milliseconds. Default: :infinity

  • :model (atom) — Model name: :deepseek, :claude_opus, :gpt4o, etc.

                  Default: `:deepseek`
  • :prompt (atom) — System prompt: :coder, :analyst, :momoka, etc.

                   Default: `:momoka`
  • :chara_card (atom) — Override model + prompt with character card.

                       Example: `:backend_engineer`. Overrides `:model` and `:prompt`.
  • :chat_session (string) — Conversation history isolation. Default: "default"

  • :pty_session_id (string) — PTY sandbox isolation. Default: same as :chat_session

  • :temperature (float | integer | nil) — Sampling temperature forwarded to the LLM provider as the "temperature" field in the HTTP body. Default: nil (provider default).

  • :top_p (float | nil) — Nucleus sampling cutoff (Anthropic / OpenAI / Bedrock inferenceConfig.topP). Default: nil (provider default).

  • :top_k (integer | nil) — Top-K sampling (Anthropic / Bedrock inferenceConfig.topK). OpenAI does NOT support — dropped at the OpenAI adapter. Default: nil (provider default).

  • :min_p (float | nil) — Min-P sampling. Reserved for future adapter support; no current adapter emits this field. Default: nil (provider default).

  • :max_tokens (integer | nil) — Maximum output tokens (Anthropic / OpenAI / Bedrock inferenceConfig.maxTokens). Default: nil (provider default).

  • :repetition_penalty (float | nil) — Repetition penalty. Reserved for future adapter support; no current adapter emits this field. Default: nil (provider default).

  • :frequency_penalty (float | nil) — OpenAI frequency penalty. Anthropic and Bedrock do NOT support — dropped at those adapters. Default: nil (provider default).

  • :presence_penalty (float | nil) — OpenAI presence penalty. Anthropic and Bedrock do NOT support — dropped at those adapters. Default: nil (provider default).

  • :stop_sequences (list of strings | nil) — Custom stop sequences (Anthropic stop_sequences, OpenAI stop, Bedrock inferenceConfig.stopSequences). Default: nil (provider default).

  • :seed (integer | nil) — Random seed for reproducibility (OpenAI; Bedrock inferenceConfig.seed). Anthropic does NOT support. Default: nil (provider default).

  • :anthropic_beta (list of strings | nil) — Optional list of Anthropic beta header strings to send (e.g. ["output-128k-2025-02-19"]). When multiple are given, joined with ", " per Anthropic's convention. Default: nil (no beta header sent — provider's default cap applies). Currently consumed only by :anthropic provider calls; harmless on other providers (the adapter does not read the value).

Precedence (per field, all 10 sampler fields + :anthropic_beta): talk/1 explicit opt > config/models/<name>.exs value > nil/omit. Step 7 stores the defaults in model config files (NOT in chara cards).

Examples

# Interactive
iex> Eai.Chat.talk()

# One-shot, defaults
iex> Eai.Chat.talk(content: "what time is it?", mod: :function)

# With model + prompt
iex> Eai.Chat.talk(content: "refactor", mod: :function, model: :claude_opus, prompt: :coder, timeout: 60_000)

# Multi-session isolation
iex> Eai.Chat.talk(content: "analyze", chat_session: "research", pty_session_id: "isolated")

# With chara card (overrides model + prompt)
iex> Eai.Chat.talk(content: "code review", mod: :function, chara_card: :backend_engineer)

Available Models, Prompts & Cards

iex> Eai.Models.names()        # => [:deepseek, :claude_opus, :gpt4o, ...]
iex> Eai.Prompts.names()       # => [:momoka, :coder, :analyst]
iex> Eai.Card.names()          # => [:backend_engineer, :frontend_dev, ...]

Returns

  • :function mode — {:ok, reply} on success, {:error, reason} on failure. When the chat session is currently busy, returns {:error, :busy, message} (note the 3-tuple shape, unified with :human mode).
  • :human mode — :ok after the interactive session ends, or {:error, :busy, message} if the session is already busy.
  • {:error, :invalid_mod} for an unknown :mod value.