Lightning.AiAssistant (Lightning v2.13.5)

View Source

The AI assistant context module for Lightning workflows.

This module provides a comprehensive interface for managing AI-powered chat sessions within the Lightning platform. It handles two main types of AI assistance:

  1. Job-specific assistance - Helps users with coding tasks, debugging, and adaptor-specific guidance for individual workflow jobs
  2. Workflow template generation - Assists in creating complete workflow templates from natural language descriptions

Summary

Functions

Associates a workflow with a chat session.

Creates a new chat session for job-specific AI assistance.

Creates a new chat session for workflow template generation.

Checks if the AI assistant feature is enabled via application configuration.

Checks if the Apollo AI service endpoint is reachable and responding.

Finds all pending user messages in a chat session.

Retrieves a chat session by ID with all related data preloaded.

Checks if additional sessions are available beyond the current count.

Returns paginated chat sessions with metadata for improved user experience.

Records that a user has read and accepted the AI assistant disclaimer.

Adds job-specific context to a chat session for enhanced AI assistance.

Queries the AI assistant for job-specific code assistance.

Queries the AI service for workflow template generation.

Saves a message to an existing chat session.

Returns the maximum allowed length for chat session titles.

Updates the status of a specific message within a chat session.

Checks if a user has acknowledged the AI assistant disclaimer recently.

Functions

associate_workflow(session, workflow)

Associates a workflow with a chat session.

Links a generated workflow to the session that created it, enabling tracking and future modifications through the same conversation context.

Parameters

  • session - The %ChatSession{} that generated the workflow
  • workflow - The %Workflow{} struct to associate

Returns

  • {:ok, session} - Successfully linked workflow to session
  • {:error, changeset} - Association failed with validation errors

Examples

{:ok, updated_session} = AiAssistant.associate_workflow(session, new_workflow)

create_session(job, user, content)

Creates a new chat session for job-specific AI assistance.

Initializes a new session with:

  • Generated UUID
  • Association with the specified job and user
  • Auto-generated title from the initial message content
  • Job's expression and adaptor context
  • The initial user message

Parameters

  • job - The %Job{} struct this session will assist with
  • user - The %User{} creating the session
  • content - Initial message content that will become the session title

Returns

  • {:ok, session} - Successfully created session with initial message
  • {:error, changeset} - Validation errors during creation

Examples

case AiAssistant.create_session(job, current_user, "Help debug my HTTP request") do
  {:ok, session} ->
    # Session created successfully
  {:error, changeset} ->
    # Handle validation errors
end

create_workflow_session(project, user, content)

Creates a new chat session for workflow template generation.

Initializes a session specifically for creating workflow templates:

  • Associates with a project rather than a specific job
  • Sets session type to "workflow_template"
  • Includes the initial user message describing the desired workflow

Parameters

  • project - The %Project{} struct where the workflow will be created
  • user - The %User{} requesting the workflow template
  • content - Description of the desired workflow functionality

Returns

  • {:ok, session} - Successfully created workflow session
  • {:error, changeset} - Validation errors during creation

Examples

case AiAssistant.create_workflow_session(project, user, "Create a daily data sync from Salesforce to PostgreSQL") do
  {:ok, session} ->
    # Ready to generate workflow template
  {:error, changeset} ->
    # Handle errors
end

enabled?()

@spec enabled?() :: boolean()

Checks if the AI assistant feature is enabled via application configuration.

Verifies that both the Apollo endpoint URL and API key are properly configured, which are required for AI functionality.

Returns

true if AI assistant is properly configured and enabled, false otherwise.

Examples

if AiAssistant.enabled?() do
  # Show AI assistant UI elements
else
  # Hide AI features or show configuration message
end

endpoint_available?()

@spec endpoint_available?() :: boolean()

Checks if the Apollo AI service endpoint is reachable and responding.

Performs a connectivity test to ensure the external AI service is available before attempting to make actual queries.

Returns

true if the Apollo endpoint responds successfully, false otherwise.

Examples

case AiAssistant.endpoint_available?() do
  true ->
    # Proceed with AI queries
  false ->
    # Show service unavailable message
end

find_pending_user_messages(session)

@spec find_pending_user_messages(Lightning.AiAssistant.ChatSession.t()) :: [
  Lightning.AiAssistant.ChatMessage.t()
]

Finds all pending user messages in a chat session.

Retrieves messages that have been sent by users but are still waiting for processing or AI responses. Useful for identifying stuck or failed requests.

Parameters

  • session - The %ChatSession{} to search

Returns

List of %ChatMessage{} structs with :role of :user and :status of :pending.

Examples

pending_messages = AiAssistant.find_pending_user_messages(session)

if length(pending_messages) > 0 do
  # Handle stuck messages
end

get_session!(id)

Retrieves a chat session by ID with all related data preloaded.

Fetches a complete chat session including:

  • All non-cancelled messages ordered by creation time
  • User information for each message
  • Session metadata
  • Project information (for workflow template sessions)

Parameters

  • id - UUID string of the session to retrieve

Returns

A ChatSession struct with preloaded :messages and nested :user data. For workflow template sessions, the :project association is also preloaded.

Raises

Ecto.NoResultsError if no session exists with the given ID.

Examples

# Job session
session = AiAssistant.get_session!("123e4567-e89b-12d3-a456-426614174000")
IO.puts("Session has # {length(session.messages)} messages")

# Workflow template session (includes project)
session = AiAssistant.get_session!("workflow-session-id")
IO.puts("Workflow for project: # {session.project.name}")

has_more_sessions?(resource, current_count)

@spec has_more_sessions?(
  Lightning.Projects.Project.t() | Lightning.Workflows.Job.t(),
  integer()
) ::
  boolean()

Checks if additional sessions are available beyond the current count.

This is a convenience function to determine if there are more sessions to load without fetching the actual data. Useful for "Load More" UI patterns.

Parameters

  • resource - A %Project{} or %Job{} struct
  • current_count - Number of sessions already loaded

Returns

true if more sessions exist, false otherwise.

Examples

if AiAssistant.has_more_sessions?(project, 20) do
  # Show "Load More" button
end

list_sessions(resource, sort_direction \\ :desc, opts \\ [])

Returns paginated chat sessions with metadata for improved user experience.

Retrieves chat sessions associated with either a Project (workflow template sessions) or a Job (job-specific sessions). Results are paginated and include total counts and navigation metadata.

Parameters

  • resource - A %Project{}, %Job{}, or %Snapshot.Job{} struct to filter sessions by
  • sort_direction - Sort order, either :asc or :desc (default: :desc)
  • opts - Keyword list of options:
    • :offset - Number of records to skip (default: 0)
    • :limit - Maximum number of records to return (default: 20)

Returns

A map containing:

  • :sessions - List of ChatSession structs with preloaded data
  • :pagination - PaginationMeta struct with navigation information

Examples

# Get recent sessions for a project
%{sessions: sessions, pagination: meta} =
  AiAssistant.list_sessions(project, :desc, offset: 0, limit: 10)

# Get older sessions for a job
%{sessions: sessions, pagination: meta} =
  AiAssistant.list_sessions(job, :asc, offset: 10, limit: 5)

mark_disclaimer_read(user)

@spec mark_disclaimer_read(Lightning.Accounts.User.t()) ::
  {:ok, Lightning.Accounts.User.t()}

Records that a user has read and accepted the AI assistant disclaimer.

Updates the user's preferences with a timestamp indicating when they acknowledged the AI assistant terms and conditions.

Parameters

  • user - The %User{} who read the disclaimer

Returns

{:ok, user} - Successfully recorded disclaimer acceptance.

Examples

{:ok, updated_user} = AiAssistant.mark_disclaimer_read(current_user)

put_expression_and_adaptor(session, expression, adaptor)

Adds job-specific context to a chat session for enhanced AI assistance.

Enriches a session with the job's expression code and adaptor information, enabling the AI to provide more targeted and relevant assistance.

Parameters

  • session - The %ChatSession{} to enhance
  • expression - The job's expression code as a string
  • adaptor - The adaptor name/identifier for the job

Returns

An updated ChatSession struct with :expression and :adaptor fields populated. The adaptor is resolved through Lightning.AdaptorRegistry.

Examples

enhanced_session = AiAssistant.put_expression_and_adaptor(
  session,
  "fn(state) => { return {...state, processed: true}; }",
  "@openfn/language-http"
)

query(session, content, opts \\ %{})

Queries the AI assistant for job-specific code assistance.

Sends a user query to the Apollo AI service along with job context (expression and adaptor) and conversation history. The AI provides targeted assistance for coding tasks, debugging, and adaptor-specific guidance.

Parameters

  • session - The job-specific %ChatSession{} with expression and adaptor context
  • content - User's question or request for assistance

Returns

  • {:ok, session} - AI responded successfully, session updated with response
  • {:error, reason} - Query failed, reason is either a string error message or changeset

Examples

case AiAssistant.query(session, "Why is my HTTP request failing?") do
  {:ok, updated_session} ->
    # AI provided assistance, check session.messages for response
  {:error, "Request timed out. Please try again."} ->
    # Handle timeout
  {:error, changeset} ->
    # Handle validation errors
end

query_workflow(session, content, errors \\ nil)

@spec query_workflow(
  Lightning.AiAssistant.ChatSession.t(),
  String.t(),
  String.t() | nil
) ::
  {:ok, Lightning.AiAssistant.ChatSession.t()}
  | {:error, String.t() | Ecto.Changeset.t()}

Queries the AI service for workflow template generation.

Sends a request to generate or modify workflow templates based on user requirements. Can include validation errors from previous attempts to help the AI provide corrections.

Parameters

  • session - The workflow template %ChatSession{}
  • content - User's description of desired workflow functionality or modifications
  • errors - Optional string containing validation errors from previous workflow attempts

Returns

  • {:ok, session} - Workflow template generated successfully
  • {:error, reason} - Generation failed, reason is either a string error message or changeset

Examples

# Initial workflow request
{:ok, session} = AiAssistant.query_workflow(
  session,
  "Create a workflow that syncs Salesforce contacts to a Google Sheet daily"
)

# Request with error corrections
{:ok, session} = AiAssistant.query_workflow(
  session,
  "Fix the validation errors",
  "Invalid cron expression: '0 0 * * 8'"
)

save_message(session, message, usage \\ %{}, meta \\ nil)

@spec save_message(Lightning.AiAssistant.ChatSession.t(), map(), map(), map() | nil) ::
  {:ok, Lightning.AiAssistant.ChatSession.t()} | {:error, Ecto.Changeset.t()}

Saves a message to an existing chat session.

Adds a new message to the session's message history and updates the session. For assistant messages, this also triggers AI usage tracking and limit enforcement.

Parameters

  • session - The target %ChatSession{}
  • message - Map containing message data with keys like :role, :content, :user
  • usage - Map containing AI usage metrics (default: %{})
  • meta - Optional metadata to update on the session (default: nil)

Returns

  • {:ok, session} - Successfully saved message and updated session
  • {:error, changeset} - Validation or database errors

Examples

# Save user message
{:ok, updated_session} = AiAssistant.save_message(session, %{
  role: :user,
  content: "How do I handle errors?",
  user: current_user
})

# Save assistant response with usage tracking
{:ok, updated_session} = AiAssistant.save_message(session, %{
  role: :assistant,
  content: "Here's how to handle errors..."
}, %{tokens_used: 150, cost: 0.003})

title_max_length()

@spec title_max_length() :: non_neg_integer()

Returns the maximum allowed length for chat session titles.

Examples

iex> Lightning.AiAssistant.title_max_length()
40

update_message_status(session, message, status)

Updates the status of a specific message within a chat session.

Changes the status of an individual message (e.g., from :pending to :success or :error) and returns the refreshed session with updated data.

Parameters

  • session - The %ChatSession{} containing the message
  • message - The specific %ChatMessage{} to update
  • status - New status atom (e.g., :pending, :success, :error, :cancelled)

Returns

  • {:ok, session} - Successfully updated message, returns refreshed session
  • {:error, changeset} - Update failed with validation errors

Examples

# Mark a pending message as successful
{:ok, updated_session} = AiAssistant.update_message_status(
  session,
  pending_message,
  :success
)

# Mark a message as cancelled
{:ok, updated_session} = AiAssistant.update_message_status(
  session,
  message,
  :cancelled
)

user_has_read_disclaimer?(user)

@spec user_has_read_disclaimer?(Lightning.Accounts.User.t()) :: boolean()

Checks if a user has acknowledged the AI assistant disclaimer recently.

Verifies that the user has read and accepted the AI assistant terms and conditions within the last 24 hours. This ensures users are aware of AI limitations and usage terms.

Parameters

  • user - The %User{} struct to check

Returns

true if disclaimer was read within 24 hours, false otherwise.

Examples

if AiAssistant.user_has_read_disclaimer?(current_user) do
  # User can access AI features
else
  # Show disclaimer dialog
end