The module settings (phoenix_kit_settings, keys agent_*) and their
defaults. A per-user value (PhoenixKitAgent.Schemas.UserSettings) wins over
these; these win over the built-in defaults below.
| Key | Default |
|---|---|
agent_enabled | false (see PhoenixKitAgent.enabled?/0) |
agent_default_endpoint_uuid | none — the AI endpoint the assistant uses |
agent_vision_endpoint_uuid | none — describes images for a model without image input |
agent_system_prompt | none — the module's system prompt (JSON {"text": …}) |
agent_daily_cost_limit_micro_usd | 1_000_000 ($1) |
agent_monthly_cost_limit_micro_usd | 10_000_000 ($10) |
agent_daily_turn_limit | 200 |
agent_max_attachment_mb | 20 |
agent_max_attachments_per_message | 5 |
agent_limit_watchers | none — JSON {"uuids": […]} of user uuids; none = every Owner |
agent_max_tool_rounds | 8 |
agent_turn_deadline_s | 300 |
agent_history_chars | 24_000 |
agent_tool_result_chars | 12_000 |
agent_capture_ai_content | false |
Money is in micro-dollars ($1 = 1_000_000); the AI journal keeps dollars
(phoenix_kit_ai_requests.cost), read through cost_to_micro/1. A stored
value that is not a whole number, or is outside its range (below), reads as
the default. A limit of 0 is a real limit (nothing allowed); a technical
value must be positive.
Core keeps a string setting to 1000 characters, so the two settings that can
be longer — the module prompt and the watchers — are JSON settings
(value_json), written by put_system_prompt/2 and put_limit_watchers/2.
The two models are written by put_default_endpoint/2 and
put_vision_endpoint/2, which take only an AI endpoint that chats and fits
its AI task (agent.chat, agent.attachment).
Every writer records the change with who made it (actor_uuid: in opts)
in the core Activity log: through the settings history (setting.changed,
with the values before and after) — except the module prompt, whose text
must not be kept there (nor in the query log that history's write goes
to): it is written without that history, and its change is recorded as
agent.settings_updated with the field name only.
agent_capture_ai_content is on only when it reads exactly "true": then the
bodies of the assistant's model calls are written to the AI request journal,
where every holder of the ai permission reads them. Only an Owner may switch
it: put_capture_ai_content/2 does not check that, its caller (the Settings
page, PhoenixKitAgent.Web.SettingsLive) does.
Summary
Types
Why put_default_endpoint/2 or put_vision_endpoint/2 wrote nothing.
Functions
Whether the bodies of the assistant's model calls go to the AI journal.
A cost in dollars as the AI journal keeps it (PhoenixKitAI.Request.cost,
a Decimal, finer than a micro-dollar at times) as whole micro-dollars,
rounded half up: $0.0000025 is 3. nil (no cost known) stays nil.
A sum is rounded once, after it is added up, never row by row.
The AI endpoint the assistant uses by default, or nil.
Validates the defaults form; see save_defaults/2.
The current defaults as the form shows them: string values, money in dollars.
How many characters of earlier messages go into the model's context.
The module's default per-user limits.
The users told when someone hits a limit (agent_limit_watchers). Empty means
every Owner; who those are is decided where the notice is sent.
Most model ↔ tool rounds in one turn.
Micro-dollars as dollars for a form field: 1_500_000 is "1.5".
Switches agent_capture_ai_content. opts go to PhoenixKit.Settings
(actor_uuid:, source:). The caller checks that the person is an Owner.
Sets the AI endpoint the assistant uses by default
(agent_default_endpoint_uuid), or none (nil). Only an existing endpoint
that chats is taken; anything else is {:error, :invalid_endpoint} and
nothing is written. A newly chosen endpoint must fit the agent.chat AI
task (PhoenixKitAI.Tasks.check_selection/2): one whose model is known not
to take tools is {:error, {:model_unfit, missing}}, one nobody knows
takes them {:error, {:model_unverified, unclear}}, and nothing is
written; the endpoint already set is not checked again. opts go to
PhoenixKit.Settings (actor_uuid:, source:). The caller checks
agent.manage.
Sets who is told when someone hits a limit (agent_limit_watchers): user
uuids, repeats dropped; an empty list means every Owner. Anything that is
not a uuid is {:error, :invalid_uuid} and nothing is written. The caller
checks agent.manage.
Sets the module's system prompt (agent_system_prompt); a blank one means
none. NUL characters are cut (the database refuses them); a prompt over
16000 characters is {:error, changeset} and nothing is written —
it goes into every request. A change is recorded in the Activity log as
agent.settings_updated by actor_uuid: (in opts), with the field name
and never the text (see the moduledoc). The caller checks agent.manage.
Sets the AI endpoint that describes pictures for a model that does not see
them (agent_vision_endpoint_uuid), or none (nil); as
put_default_endpoint/2, against the agent.attachment AI task (its model
must take pictures).
Takes user_uuid out of agent_limit_watchers, under the setting's row lock
(a concurrent change of the list is not lost). {:ok, :unchanged} when it was
not in the list.
Saves the defaults form: dollars become micro-dollars; every value is checked
against its range and nothing is written unless all are valid. Only values
that differ from what is in effect are written, so an untouched built-in
default stays unstored (and follows a later change of the default). They are
written in one transaction (PhoenixKit.Settings.update_settings_batch/2):
a write the database refuses leaves every setting as it was and is
{:error, :not_saved}. opts go to PhoenixKit.Settings (actor_uuid:,
source:) so the change is in the settings history with who made it.
The module's system prompt, or nil.
How many characters of one tool result go to the model (and are kept).
Deadline of a whole turn, in seconds.
Dollars typed by a person ("2,5", "0.05") as micro-dollars: {:ok, integer}, {:error, :fraction} when finer than a millionth of a dollar,
{:error, reason} for anything that is not a non-negative amount.
The AI endpoint that describes images for a model without image input, or nil.
Types
@type endpoint_refusal() :: :invalid_endpoint | {:model_unfit | :model_unverified, [atom()]}
Why put_default_endpoint/2 or put_vision_endpoint/2 wrote nothing.
Functions
@spec capture_ai_content?() :: boolean()
Whether the bodies of the assistant's model calls go to the AI journal.
@spec cost_to_micro(Decimal.t() | nil) :: non_neg_integer() | nil
A cost in dollars as the AI journal keeps it (PhoenixKitAI.Request.cost,
a Decimal, finer than a micro-dollar at times) as whole micro-dollars,
rounded half up: $0.0000025 is 3. nil (no cost known) stays nil.
A sum is rounded once, after it is added up, never row by row.
@spec default_endpoint_uuid() :: String.t() | nil
The AI endpoint the assistant uses by default, or nil.
@spec defaults_changeset(map()) :: Ecto.Changeset.t()
Validates the defaults form; see save_defaults/2.
The current defaults as the form shows them: string values, money in dollars.
@spec history_chars() :: pos_integer()
How many characters of earlier messages go into the model's context.
@spec limit_defaults() :: %{required(atom()) => non_neg_integer()}
The module's default per-user limits.
@spec limit_watchers() :: [String.t()]
The users told when someone hits a limit (agent_limit_watchers). Empty means
every Owner; who those are is decided where the notice is sent.
@spec max_tool_rounds() :: pos_integer()
Most model ↔ tool rounds in one turn.
@spec micro_to_usd(non_neg_integer()) :: String.t()
Micro-dollars as dollars for a form field: 1_500_000 is "1.5".
@spec put_capture_ai_content(boolean(), keyword()) :: {:ok, term()} | {:error, Ecto.Changeset.t()}
Switches agent_capture_ai_content. opts go to PhoenixKit.Settings
(actor_uuid:, source:). The caller checks that the person is an Owner.
@spec put_default_endpoint(String.t() | nil, keyword()) :: {:ok, term()} | {:error, endpoint_refusal() | Ecto.Changeset.t()}
Sets the AI endpoint the assistant uses by default
(agent_default_endpoint_uuid), or none (nil). Only an existing endpoint
that chats is taken; anything else is {:error, :invalid_endpoint} and
nothing is written. A newly chosen endpoint must fit the agent.chat AI
task (PhoenixKitAI.Tasks.check_selection/2): one whose model is known not
to take tools is {:error, {:model_unfit, missing}}, one nobody knows
takes them {:error, {:model_unverified, unclear}}, and nothing is
written; the endpoint already set is not checked again. opts go to
PhoenixKit.Settings (actor_uuid:, source:). The caller checks
agent.manage.
@spec put_limit_watchers([String.t()], keyword()) :: {:ok, term()} | {:error, :invalid_uuid | Ecto.Changeset.t()}
Sets who is told when someone hits a limit (agent_limit_watchers): user
uuids, repeats dropped; an empty list means every Owner. Anything that is
not a uuid is {:error, :invalid_uuid} and nothing is written. The caller
checks agent.manage.
@spec put_system_prompt(String.t() | nil, keyword()) :: {:ok, term()} | {:error, Ecto.Changeset.t()}
Sets the module's system prompt (agent_system_prompt); a blank one means
none. NUL characters are cut (the database refuses them); a prompt over
16000 characters is {:error, changeset} and nothing is written —
it goes into every request. A change is recorded in the Activity log as
agent.settings_updated by actor_uuid: (in opts), with the field name
and never the text (see the moduledoc). The caller checks agent.manage.
@spec put_vision_endpoint(String.t() | nil, keyword()) :: {:ok, term()} | {:error, endpoint_refusal() | Ecto.Changeset.t()}
Sets the AI endpoint that describes pictures for a model that does not see
them (agent_vision_endpoint_uuid), or none (nil); as
put_default_endpoint/2, against the agent.attachment AI task (its model
must take pictures).
@spec remove_limit_watcher(String.t()) :: {:ok, term()} | {:error, Ecto.Changeset.t()}
Takes user_uuid out of agent_limit_watchers, under the setting's row lock
(a concurrent change of the list is not lost). {:ok, :unchanged} when it was
not in the list.
@spec save_defaults(map(), keyword()) :: {:ok, [String.t()]} | {:error, Ecto.Changeset.t() | :not_saved}
Saves the defaults form: dollars become micro-dollars; every value is checked
against its range and nothing is written unless all are valid. Only values
that differ from what is in effect are written, so an untouched built-in
default stays unstored (and follows a later change of the default). They are
written in one transaction (PhoenixKit.Settings.update_settings_batch/2):
a write the database refuses leaves every setting as it was and is
{:error, :not_saved}. opts go to PhoenixKit.Settings (actor_uuid:,
source:) so the change is in the settings history with who made it.
@spec system_prompt() :: String.t() | nil
The module's system prompt, or nil.
@spec tool_result_chars() :: pos_integer()
How many characters of one tool result go to the model (and are kept).
@spec turn_deadline_s() :: pos_integer()
Deadline of a whole turn, in seconds.
@spec usd_to_micro(term()) :: {:ok, non_neg_integer()} | {:error, atom()}
Dollars typed by a person ("2,5", "0.05") as micro-dollars: {:ok, integer}, {:error, :fraction} when finer than a millionth of a dollar,
{:error, reason} for anything that is not a non-negative amount.
@spec vision_endpoint_uuid() :: String.t() | nil
The AI endpoint that describes images for a model without image input, or nil.