PhoenixKitAgent.UserConfig (PhoenixKitAgent v0.1.0)

Copy Markdown View Source

The assistant settings of one user (spec §5.4, §7) and how they combine with the module's.

What is in effect

effective/1 is the one place the turn loop reads a user's settings: the user's own value (PhoenixKitAgent.Schemas.UserSettings), else the module default (PhoenixKitAgent.Config). A nil field means "the default"; 0 is a real limit. A blank prompt is no prompt. The model (endpoint_uuid) is read when a turn starts, so a change takes effect with the next turn of any chat (spec §14, В6).

enabled?/1 is the user's own switch: false only when an admin switched the assistant off for them (it never grants the agent permission).

Who writes what

  • The user — put_personal_instructions/3 and get_personal_instructions/2, for their own personal_instructions only. Like PhoenixKitAgent.Conversations they act for a live browser session and need impersonated: boolean in the options; an impersonated session, a revoked one, a user without agent or one switched off is refused. The write replaces that one column, so nothing an admin set can change through it.
  • An admin — admin_update/4, with the scope of a person who holds agent.manage (checked again here, so a caller that forgets is refused). It writes the switch, the model, the admin's prompt, the limits and the notice flags (UserSettings.admin_changeset/2) and records who changed which fields for whom in the core Activity log — field names only, never a prompt text. An Owner's settings are changed by an Owner only, and a form opened before someone else's save does not overwrite it (expected:).

Summary

Types

The settings in force for a user.

Functions

Saves what an admin sets for target_user_uuid (attrs as UserSettings.admin_changeset/2 casts them) on behalf of actor_scope, which must hold agent.manage — and be an Owner when the target is one: an Owner's assistant is not set by the people an Owner manages. The row is created if the user has none, and locked while it is changed.

Whether user_uuid is one of agent_users/0.

The people the assistant is for: active users who hold agent through a role (and the Owners, who hold every permission), by e-mail. The admin screen lists these.

The settings in force for user_uuid: their own value, else the module default (see the moduledoc). own lists the fields (model, prompt, limits) the user's row sets itself.

effective/1 for several users with one query and one read of the module defaults: %{user_uuid => effective}.

Whether the assistant is not switched off for the user (see the moduledoc).

The endpoints the assistant's turns use now: the module default and every user's own model. It backs the endpoints of the agent.chat AI task (PhoenixKitAgent.ai_tasks/0).

The user's settings row as it is stored, for the admin's form: an unsaved %UserSettings{} when they have none. nil for a malformed uuid.

The session user's own personal instructions (nil when none). Refusals are those of PhoenixKitAgent.Conversations.

Whether actor_scope may set the assistant of target_user_uuid with admin_update/4: it holds agent.manage, and is an Owner if the target is.

Sets the session user's own personal instructions (a blank text clears them). They are the user's, ranked below the module's and the admin's prompt (spec §7.1). Only this one column is written, whatever else the row holds; a text over 4000 characters, or one that is not text, is {:error, changeset} and nothing is written.

The people who may be chosen to be told when someone reaches a limit (agent_limit_watchers, spec §7.4): active users who hold agent.manage through a role, the Owners, and whoever is a watcher now, by e-mail.

Types

effective()

@type effective() :: %{
  user_uuid: String.t(),
  enabled?: boolean(),
  endpoint_uuid: String.t() | nil,
  system_prompt: String.t() | nil,
  personal_instructions: String.t() | nil,
  daily_cost_limit_micro_usd: non_neg_integer(),
  monthly_cost_limit_micro_usd: non_neg_integer(),
  daily_turn_limit: non_neg_integer(),
  max_attachment_mb: non_neg_integer(),
  max_attachments_per_message: non_neg_integer(),
  notify_on_limit: boolean(),
  own: [atom()]
}

The settings in force for a user.

Functions

admin_update(actor_scope, target_user_uuid, attrs, opts \\ [])

@spec admin_update(PhoenixKit.Users.Auth.Scope.t() | nil, term(), map(), keyword()) ::
  {:ok, PhoenixKitAgent.Schemas.UserSettings.t(), [atom()]}
  | {:error,
     :forbidden
     | :not_found
     | :stale
     | {:model_unfit | :model_unverified, [atom()]}
     | Ecto.Changeset.t()}

Saves what an admin sets for target_user_uuid (attrs as UserSettings.admin_changeset/2 casts them) on behalf of actor_scope, which must hold agent.manage — and be an Owner when the target is one: an Owner's assistant is not set by the people an Owner manages. The row is created if the user has none, and locked while it is changed.

expected: %{field => value} in opts is what the caller's form showed when it was opened: when the stored row no longer holds those values (an admin saved in between), nothing is written and the answer is {:error, :stale}, so a stale form never overwrites that change unseen. Fields not named there do not count.

Returns {:ok, settings, changed_fields}; when fields changed, the actor, the user (as the resource of the entry) and the field names go to the core Activity log (action agent.user_settings_updated) — no values, and no notification for the user. {:error, :forbidden} without the permission (or for an Owner's settings, to a non-Owner), {:error, :not_found} for an unknown user, {:error, changeset} for an invalid value (nothing is written). A newly chosen model must fit the agent.chat AI task (PhoenixKitAI.Tasks.check_selection/2): one known not to take tools is {:error, {:model_unfit, missing}}, one nobody knows takes them {:error, {:model_unverified, unclear}}, and nothing is written; none (the module default) and the model already saved are not checked.

agent_user?(user_uuid)

@spec agent_user?(term()) :: boolean()

Whether user_uuid is one of agent_users/0.

agent_users()

@spec agent_users() :: [PhoenixKit.Users.Auth.User.t()]

The people the assistant is for: active users who hold agent through a role (and the Owners, who hold every permission), by e-mail. The admin screen lists these.

effective(user_uuid)

@spec effective(String.t()) :: effective()

The settings in force for user_uuid: their own value, else the module default (see the moduledoc). own lists the fields (model, prompt, limits) the user's row sets itself.

effective_many(user_uuids)

@spec effective_many([String.t()]) :: %{required(String.t()) => effective()}

effective/1 for several users with one query and one read of the module defaults: %{user_uuid => effective}.

enabled?(user_uuid)

@spec enabled?(String.t()) :: boolean()

Whether the assistant is not switched off for the user (see the moduledoc).

endpoint_uuids()

@spec endpoint_uuids() :: [String.t()]

The endpoints the assistant's turns use now: the module default and every user's own model. It backs the endpoints of the agent.chat AI task (PhoenixKitAgent.ai_tasks/0).

get(user_uuid)

The user's settings row as it is stored, for the admin's form: an unsaved %UserSettings{} when they have none. nil for a malformed uuid.

get_personal_instructions(session_ref, opts)

@spec get_personal_instructions(
  PhoenixKitAgent.Conversations.session_ref(),
  keyword()
) ::
  {:ok, String.t() | nil} | {:error, PhoenixKitAgent.Conversations.refusal()}

The session user's own personal instructions (nil when none). Refusals are those of PhoenixKitAgent.Conversations.

may_configure?(actor_scope, target_user_uuid)

@spec may_configure?(PhoenixKit.Users.Auth.Scope.t() | nil, term()) :: boolean()

Whether actor_scope may set the assistant of target_user_uuid with admin_update/4: it holds agent.manage, and is an Owner if the target is.

put_personal_instructions(session_ref, text, opts)

@spec put_personal_instructions(
  PhoenixKitAgent.Conversations.session_ref(),
  term(),
  keyword()
) ::
  {:ok, String.t() | nil}
  | {:error, PhoenixKitAgent.Conversations.refusal() | Ecto.Changeset.t()}

Sets the session user's own personal instructions (a blank text clears them). They are the user's, ranked below the module's and the admin's prompt (spec §7.1). Only this one column is written, whatever else the row holds; a text over 4000 characters, or one that is not text, is {:error, changeset} and nothing is written.

watcher_candidates()

@spec watcher_candidates() :: [PhoenixKit.Users.Auth.User.t()]

The people who may be chosen to be told when someone reaches a limit (agent_limit_watchers, spec §7.4): active users who hold agent.manage through a role, the Owners, and whoever is a watcher now, by e-mail.