AI request schema for PhoenixKit AI system.
Tracks every AI API request for usage history and statistics. Used for monitoring costs, performance, and debugging.
Schema Fields
Request Identity
endpoint_uuid: Foreign key to the AI endpoint usedendpoint_name: Denormalized endpoint name for historical displayprompt_uuid: Foreign key to the AI prompt used (if request used a prompt template)prompt_name: Denormalized prompt name for historical displayuser_uuid: Foreign key to the user who made the request (nullable if user deleted)slot_index: Which slot was used (deprecated, for backward compatibility)
Request Details
model: Model identifier (e.g., "anthropic/claude-3-haiku")request_type: Type of request (e.g., "text_completion", "chat", "embedding", "tts", "image", "image_edit", "vision")
Token Usage
input_tokens: Number of tokens in the promptoutput_tokens: Number of tokens in the responsetotal_tokens: Total tokens used (input + output)
Performance & Cost
cost: What the call cost in US dollars, aDecimal(when known)latency_ms: Response time in millisecondsstatus: Request status - "success", "error", or "timeout"error_message: Error details if status is not "success"
Metadata
metadata: Additional context (temperature, max_tokens, etc.)metadata.answered_model: on chat and embedding rows, the model the provider says answered, where it is not the one asked for inmodel(answered_model/1). Image and vision rows record the answered model inmodelitself.metadata.provider_error: on a failed call, what the provider said —status,code,message(trimmed, key-shaped words redacted) andretry_after_sfor an error that is not about money.
Status Types
success- Request completed successfullyerror- Request failed with an errortimeout- Request timed out
Usage Examples
# Log a successful request
{:ok, request} = PhoenixKitAI.create_request(%{
endpoint_uuid: endpoint.uuid,
endpoint_name: "Claude Fast",
user_uuid: user.uuid,
model: "anthropic/claude-3-haiku",
request_type: "chat",
input_tokens: 150,
output_tokens: 320,
total_tokens: 470,
latency_ms: 850,
status: "success",
metadata: %{"temperature" => 0.7}
})
# Log a failed request
{:ok, request} = PhoenixKitAI.create_request(%{
endpoint_uuid: endpoint.uuid,
endpoint_name: "Claude Fast",
model: "anthropic/claude-3-haiku",
status: "error",
error_message: "Rate limit exceeded"
})
Summary
Functions
The model the provider says answered (metadata.answered_model), where it
is not the one asked for; nil otherwise.
The core status_badge status that colours a request's status: green for
a success, red for an error, amber for a timeout. The label stays
status_label/1.
Creates a changeset for request creation.
Formats a cost in dollars for display, with the precision the amount needs
Formats the latency for display.
Formats the token count for display.
Whether the row is a call the guard refused before any HTTP
(metadata.refused). Its status is "error"; the Usage tab marks it and
filters on it as "refused".
Extracts the model name without provider prefix.
Returns a CSS class for the status badge.
Returns a human-readable, gettext-translated status label.
Returns the list of valid request types.
Returns the list of valid status types.
Types
@type t() :: %PhoenixKitAI.Request{ __meta__: term(), cost: term(), endpoint: term(), endpoint_name: term(), endpoint_uuid: term(), error_message: term(), input_tokens: term(), inserted_at: term(), latency_ms: term(), metadata: term(), model: term(), output_tokens: term(), prompt: term(), prompt_name: term(), prompt_uuid: term(), request_type: term(), slot_index: term(), status: term(), total_tokens: term(), updated_at: term(), user: term(), user_uuid: term(), uuid: term() }
Functions
The model the provider says answered (metadata.answered_model), where it
is not the one asked for; nil otherwise.
The core status_badge status that colours a request's status: green for
a success, red for an error, amber for a timeout. The label stays
status_label/1.
Creates a changeset for request creation.
Formats a cost in dollars for display, with the precision the amount needs:
= $0.01: 2 decimal places ($0.05, $1.23)
= $0.0001: 4 decimal places ($0.0012)
= $0.000001: 6 decimal places ($0.000030)
$0: at least 10 decimal places, more for an amount that needs them to show three significant digits, up to the column's 18 ($0.0000000400, $0.00000000000141)
Formats the latency for display.
Formats the token count for display.
Whether the row is a call the guard refused before any HTTP
(metadata.refused). Its status is "error"; the Usage tab marks it and
filters on it as "refused".
Extracts the model name without provider prefix.
Returns a CSS class for the status badge.
Returns a human-readable, gettext-translated status label.
Literal-call clauses are required so mix gettext.extract picks the
strings up — a gettext(status) call over a variable wouldn't make
it into the .pot.
@spec valid_request_types() :: [String.t()]
Returns the list of valid request types.
@spec valid_statuses() :: [String.t()]
Returns the list of valid status types.