### Install OAuth Server Source: https://github.com/ash-project/ash_ai/blob/main/README.md Installs the ash_authentication_oauth2_server, which scaffolds OAuth resources and wires them into your Accounts domain. This is recommended for remote MCP clients. ```bash mix igniter.install ash_authentication_oauth2_server ``` -------------------------------- ### Define a basic tool Source: https://github.com/ash-project/ash_ai/blob/main/documentation/dsls/DSL-AshAi.md Expose an Ash action as a tool. This example exposes the 'read' action for the 'Artist' resource. ```elixir tool :list_artists, Artist, :read ``` -------------------------------- ### Install Ash Authentication with API Key Strategy Source: https://github.com/ash-project/ash_ai/blob/main/README.md Installs AshAuthentication with the API key strategy if not already installed, or adds the API key strategy if it's missing. This is suitable for clients configured with static credentials. ```bash mix igniter.install ash_authentication --auth-strategy api_key ``` ```bash mix ash_authentication.add_strategy api_key ``` -------------------------------- ### Install Ash AI with Igniter Source: https://github.com/ash-project/ash_ai/blob/main/README.md Use this command to install Ash AI quickly via the igniter tool. ```sh mix igniter.install ash_ai ``` -------------------------------- ### Define a tool with metadata for UI and invocation Source: https://github.com/ash-project/ash_ai/blob/main/documentation/dsls/DSL-AshAi.md Expose an Ash action with custom metadata, including UI templates and invocation messages for LLM interaction. This example is for getting a board. ```elixir tool :get_board, Board, :read, _meta: %{"openai/outputTemplate" => "ui://widget/kanban-board.html", "openai/toolInvocation/invoking" => "Preparing the board…", "openai/toolInvocation/invoked" => "Board ready."} ``` -------------------------------- ### Oban Configuration for Queues Source: https://github.com/ash-project/ash_ai/blob/main/README.md Example of configuring Oban queues in `config.exs`. This includes defining the 'artist_vectorizer' queue with a concurrency limit. ```elixir config :my_app, Oban, engine: Oban.Engines.Basic, notifier: Oban.Notifiers.Postgres, queues: [ default: 10, chat_responses: [limit: 10], conversations: [limit: 10], artist_vectorizer: [limit: 20], #set the limit of concurrent workers ], repo: MyApp.Repo, plugins: [{Oban.Plugins.Cron, []}] ``` -------------------------------- ### Project Setup with Ash AI Source: https://github.com/ash-project/ash_ai/blob/main/README.md A comprehensive command to set up a new Phoenix project with Ash, Ash Oban, Ash Postgres, Ash Phoenix, Ash Authentication Phoenix, and Ash AI. ```sh mix igniter.new my_app \ --with phx.new \ --install ash,ash_postgres,ash_phoenix \ --install ash_authentication_phoenix,ash_oban \ --install ash_ai@github:ash-project/ash_ai \ --auth-strategy password ``` -------------------------------- ### Define a tool with a UI shortcut Source: https://github.com/ash-project/ash_ai/blob/main/documentation/dsls/DSL-AshAi.md Expose an Ash action and specify a UI resource or URI for the client application. This example lists artists with a specific UI. ```elixir tool :list_artists, Artist, :read, ui: "ui://artists/list.html" ``` -------------------------------- ### Setup Ash AI Tools in a LangChain Chain Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Integrates Ash AI tools into a LangChain chain. Requires specifying the OTP app and a list of tools to be made available. ```elixir chain = %{ llm: LangChain.ChatModels.ChatOpenAI.new!(%{model: "gpt-4o"}), verbose: true } |> LangChain.Chains.LLMChain.new!() |> AshAi.setup_ash_ai(otp_app: :my_app, tools: [:list, :of, :tools]) ``` -------------------------------- ### GitHub Actions Step for Live LLM Tests Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/live-llm-testing.md Example GitHub Actions step to run live LLM tests on the main branch. Ensure API keys are set as secrets and use the `--only live_llm` flag. ```yaml # Example GitHub Actions step - name: Run live LLM tests if: github.ref == 'refs/heads/main' env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: mix test --only live_llm ``` -------------------------------- ### Expose Ash Resource Actions as Tools Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Define how actions from Ash resources are exposed as tools for LLMs to call. This example shows basic tool exposure and custom descriptions. ```elixir tools do tool :tool_name, Resource, :action_name # With custom description tool :read_posts, Post, :read do description "Read all blog posts with optional filtering" end # With loading relationships/calculations tool :read_posts_with_author, Post, :read do load [:author, :comment_count] end end ``` -------------------------------- ### Define a tool with a description Source: https://github.com/ash-project/ash_ai/blob/main/documentation/dsls/DSL-AshAi.md Expose an Ash action as a tool, providing a custom description for the LLM. This example is for creating a new artist. ```elixir tool :create_artist, Artist, :create, description: "Create a new artist" ``` -------------------------------- ### Expose Ash Actions as LLM Tools Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Configure Ash actions as tools for LLMs within your domain by using the 'tools' block. This example shows how to expose read, create, publish, and comment actions for different resources. ```elixir defmodule MyApp.Blog do use Ash.Domain, extensions: [AshAi] tools do tool :read_posts, MyApp.Blog.Post, :read do description "customize the tool description" end tool :create_post, MyApp.Blog.Post, :create tool :publish_post, MyApp.Blog.Post, :publish tool :read_comments, MyApp.Blog.Comment, :read end # Rest of domain definition... end ``` -------------------------------- ### Install Dev MCP Server Plug Source: https://github.com/ash-project/ash_ai/blob/main/README.md Add the AshAi.Mcp.Dev plug to your endpoint module within the code_reloading? block to enable the dev MCP server. The server is typically available at http://localhost:4000/ash_ai/mcp. ```elixir if code_reloading? do socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket plug AshAi.Mcp.Dev, # see the note below on protocol versions below protocol_version_statement: "2024-11-05", otp_app: :your_app ``` -------------------------------- ### Ash Resource with AshOban Extension Source: https://github.com/ash-project/ash_ai/blob/main/README.md Example of defining an Ash resource that includes the AshOban extension. This is a prerequisite for using the :ash_oban vectorization strategy. ```elixir defmodule MyApp.Artist do use Ash.Resource, extensions: [AshAi, AshOban] end ``` -------------------------------- ### Development MCP Server Setup Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Add the development MCP server to your Phoenix endpoint within a `code_reloading?` block for development environments. ```elixir if code_reloading? do socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket plug AshAi.Mcp.Dev, protocol_version_statement: "2024-11-05", otp_app: :your_app plug Phoenix.LiveReloader plug Phoenix.CodeReloader end ``` -------------------------------- ### Dynamic Embedding Model Configuration Source: https://github.com/ash-project/ash_ai/blob/main/README.md Example of configuring an embedding model dynamically with resource-specific options. The options are passed to the embedding model's functions. ```elixir embedding_model {MyApp.OpenAiEmbeddingModel, model: "a-specific-model"} ``` -------------------------------- ### Define Get Usage Rules MCP Action Source: https://github.com/ash-project/ash_ai/blob/main/notes/usage-rules-mcp-implementation-plan.md Defines the `get_usage_rules` action for the MCP tool, allowing retrieval of usage rules for specified packages. It returns an array of package rule objects, each containing the package name and its markdown rules content. Handles cases where packages may not have usage rules. ```elixir action :get_usage_rules, {:array, UsageRules} do argument :packages, {:array, :string}, description: "Package names to get usage rules for" # Returns: [%{package: "ash", rules: "...markdown content..."}] end ``` -------------------------------- ### OpenAI Embedding Model Implementation Source: https://github.com/ash-project/ash_ai/blob/main/README.md An example implementation of an embedding model using OpenAI's API via the Req library. It defines dimensions and the generation logic for embeddings. ```elixir defmodule Tunez.OpenAIEmbeddingModel do use AshAi.EmbeddingModel @impl true def dimensions(_opts), do: 3072 @impl true def generate(texts, _opts) do api_key = System.fetch_env!("OPEN_AI_API_KEY") headers = [ {"Authorization", "Bearer #{api_key}"}, {"Content-Type", "application/json"} ] body = %{ "input" => texts, "model" => "text-embedding-3-large" } response = Req.post!("https://api.openai.com/v1/embeddings", json: body, headers: headers ) case response.status do 200 -> response.body["data"] |> Enum.map(fn %{"embedding" => embedding} -> embedding end) |> then(&{:ok, &1}) _status -> {:error, response.body} end end end ``` -------------------------------- ### Start an Ash AI Chat Session Source: https://github.com/ash-project/ash_ai/blob/main/README.md Use this function to initiate an interactive chat session with your Ash application. Specify the actor and OTP app. The model defaults to 'openai:gpt-4o'. ```elixir defmodule MyApp.ChatBot do def iex_chat(actor \ nil) do AshAi.iex_chat( actor: actor, otp_app: :my_app, model: "openai:gpt-4o" ) end end ``` -------------------------------- ### Implement an Embedding Model Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Create a module implementing the AshAi.EmbeddingModel behavior to generate text embeddings. This example uses the OpenAI API for embedding generation and handles successful responses or errors. ```elixir defmodule MyApp.OpenAiEmbeddingModel do use AshAi.EmbeddingModel @impl true def dimensions(_opts), do: 3072 @impl true def generate(texts, _opts) do api_key = System.fetch_env!("OPEN_AI_API_KEY") headers = [ {"Authorization", "Bearer #{api_key}"}, {"Content-Type", "application/json"} ] body = %{ "input" => texts, "model" => "text-embedding-3-large" } response = Req.post!("https://api.openai.com/v1/embeddings", json: body, headers: headers ) case response.status do 200 -> response.body["data"] |> Enum.map(fn %{"embedding" => embedding} -> embedding end) |> then(&{:ok, &1}) _status -> {:error, response.body} end end end ``` -------------------------------- ### Create HNSW Vector Index in PostgreSQL Source: https://github.com/ash-project/ash_ai/blob/main/README.md Example of creating an HNSW index on a vector column in PostgreSQL for faster search performance. This trades higher memory usage for query speed. ```elixir postgres do table "embeddings" repo MyApp.Repo custom_statements do statement :vector_idx do up "CREATE INDEX vector_idx ON embeddings USING hnsw (vectorized_body vector_cosine_ops) WITH (m = 16, ef_construction = 64)" down "DROP INDEX vector_idx;" end end end ``` -------------------------------- ### Define a Custom Struct for Structured Outputs Source: https://github.com/ash-project/ash_ai/blob/main/README.md This example demonstrates defining a custom `Ash.TypedStruct` for structured outputs, ensuring complex data is returned in a predictable format. It's used as the return type for an action. ```elixir defmodule JobListing do use Ash.TypedStruct typed_struct do field :title, :string, allow_nil?: false field :company, :string, allow_nil?: false field :location, :string field :requirements, {:array, :string} end end action :parse_job, JobListing do argument :raw_content, :string, allow_nil?: false run prompt("openai:gpt-4o-mini", prompt: "Parse this job listing: <%= @input.arguments.raw_content %>", tools: false ) end ``` -------------------------------- ### Create and Migrate Test Database Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Use this command to set up the test database before running tests. It creates the database and applies any pending migrations. ```bash mix test.create && mix test.migrate ``` -------------------------------- ### Generate Documentation Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Create project documentation, typically in HTML format, from source code annotations. ```bash mix docs ``` -------------------------------- ### Configure MCP Pipeline with API Key Plug Source: https://github.com/ash-project/ash_ai/blob/main/README.md Sets up a pipeline for :mcp that uses the ApiKey.Plug to authenticate requests. This is useful for clients configured by hand with static credentials. Use 'required?: false' to allow unauthenticated users. ```elixir pipeline :mcp do plug AshAuthentication.Strategy.ApiKey.Plug, resource: YourApp.Accounts.User, # Use `required?: false` to allow unauthenticated # users to connect, for example if some tools # are publicly accessible. required?: false end ``` -------------------------------- ### Generate Test Migrations Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Create new database migration files for the test environment. ```bash mix test.generate_migrations ``` -------------------------------- ### Filter and Sort by Vector Cosine Distance Source: https://github.com/ash-project/ash_ai/blob/main/README.md Example of filtering and sorting query results based on vector cosine distance. Requires an embedding model to generate search vectors. ```elixir read :search do argument :query, :string, allow_nil?: false prepare before_action(fn query, context -> case YourEmbeddingModel.generate([query.arguments.query], []) do {:ok, [search_vector]} -> Ash.Query.filter( query, vector_cosine_distance(full_text_vector, ^search_vector) < 0.5 ) |> Ash.Query.sort( {calc(vector_cosine_distance(full_text_vector, ^search_vector), type: :float ), :asc} ) |> Ash.Query.limit(10) {:error, error} -> {:error, error} end end) end ``` -------------------------------- ### Write New Live LLM Tests with AshAi.LiveLLMCase Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/live-llm-testing.md Use the `AshAi.LiveLLMCase` test case module to write new live LLM tests. Tag tests with `:live_llm` and the specific provider (e.g., `:openai`). Use `require_provider!` to skip tests if a provider is not configured. ```elixir defmodule AshAi.LiveLLM.MyFeatureTest do use AshAi.LiveLLMCase, async: true describe "OpenAI feature" do @tag :live_llm @tag live_llm: :openai test "my test" do require_provider!(:openai) # Test code using @openai_model end end describe "Anthropic feature" do @tag :live_llm @tag live_llm: :anthropic test "my test" do require_provider!(:anthropic) # Test code using @anthropic_model end end end ``` -------------------------------- ### Set API Keys for Live LLM Tests Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/live-llm-testing.md Set your LLM provider API keys as environment variables before running live tests. Alternatively, use a `.env` file. ```bash export OPENAI_API_KEY="sk-..." export ANTHROPIC_API_KEY="sk-ant-..." ``` -------------------------------- ### Generate Chat Feature with LiveViews Source: https://github.com/ash-project/ash_ai/blob/main/README.md Use this command to generate chat resources and LiveViews. Ensure you have a user resource defined. ```bash mix ash_ai.gen.chat --live ``` -------------------------------- ### String EEx Template Prompt Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Use simple string templates for basic prompts, allowing access to @input and @context variables. ```elixir run prompt( ChatOpenAI.new!(%{model: "gpt-4o"}), prompt: "Analyze the sentiment of: <%= @input.arguments.text %>" ) ``` -------------------------------- ### Full Test Database Reset Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Perform a comprehensive reset including regenerating migrations and resetting the database. ```bash mix test.full_reset ``` -------------------------------- ### Define List Packages With Rules MCP Action Source: https://github.com/ash-project/ash_ai/blob/main/notes/usage-rules-mcp-implementation-plan.md Defines the `list_packages_with_rules` action for the MCP tool, which returns a list of package names that have associated usage rules. This enables AI assistants to discover available usage rules. ```elixir action :list_packages_with_rules, {:array, :string} do # Returns: ["ash", "ash_postgres", "igniter", ...] end ``` -------------------------------- ### Run Security Analysis Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Perform security analysis using Sobelow to identify potential vulnerabilities. Use --skip to ignore certain checks if needed. ```bash mix sobelow --skip ``` -------------------------------- ### Use Vector Expressions for Semantic Search Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Perform semantic search by using vector expressions in Ash Query filters and sorts. This example generates a search vector from a query string and filters results based on cosine distance. ```elixir read :semantic_search do argument :query, :string, allow_nil?: false prepare before_action(fn query, context -> case MyApp.OpenAiEmbeddingModel.generate([query.arguments.query], []) do {:ok, [search_vector]} -> Ash.Query.filter( query, vector_cosine_distance(full_text_vector, ^search_vector) < 0.5 ) |> Ash.Query.sort([ { calc(vector_cosine_distance( full_text_vector, ^search_vector )), :asc } ]) {:error, error} -> {:error, error} end end) end ``` -------------------------------- ### Check Code Formatting Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Verify if the code adheres to the project's formatting standards without making changes. ```bash mix format --check ``` -------------------------------- ### Run All Tests Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Execute all tests in the project to ensure code quality and functionality. ```bash mix test ``` -------------------------------- ### Configure ReqLLM Provider Keys Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/langchain-to-reqllm-migration.md Configure your LLM provider API keys under the `:req_llm` application in `config/runtime.exs`. Only include providers your application utilizes. ```elixir config :req_llm, openai_api_key: System.get_env("OPENAI_API_KEY"), anthropic_api_key: System.get_env("ANTHROPIC_API_KEY"), google_api_key: System.get_env("GOOGLE_API_KEY") ``` -------------------------------- ### Add Extra Tools to Prompt Actions Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/langchain-to-reqllm-migration.md For prompt-backed actions, use `extra_tools` to add arbitrary `ReqLLM.Tool`s. This replaces the older method of mutating the LangChain chain. ```elixir run prompt("openai:gpt-4o", tools: true, extra_tools: [ ReqLLM.Tool.new!( name: "lookup_weather", description: "Look up weather by city", parameter_schema: [city: [type: :string, required: true]], callback: fn %{"city" => city} -> {:ok, %{city: city, forecast: "sunny"}} end ) ], req_llm_opts: [trace_id: "abc"] ) ``` -------------------------------- ### Implement Tool Execution Callbacks Source: https://github.com/ash-project/ash_ai/blob/main/README.md Monitor tool execution in real-time by providing callbacks to `AshAi.ToolLoop.run/2`. This is useful for showing progress indicators, logging, metrics collection, or debugging. ```elixir AshAi.ToolLoop.run(messages, actor: current_user, on_tool_start: fn %AshAi.ToolStartEvent{} = event -> # event includes: tool_name, action, resource, arguments, actor, tenant IO.puts("Starting #{event.tool_name}...") end, on_tool_end: fn %AshAi.ToolEndEvent{} = event -> # event includes: tool_name, result ({:ok, ...} or {:error, ...}) IO.puts("Completed #{event.tool_name}") end ) ``` -------------------------------- ### Stream Tool Loop with Tenant Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/multi-tenancy-and-tenants.md Use this to stream tool results while specifying the tenant, actor, and OTP app. The tenant is forwarded into tool execution for consistent data access. ```elixir AshAi.ToolLoop.stream(messages, otp_app: :my_app, tools: true, actor: current_user, tenant: current_tenant ) ``` -------------------------------- ### Configure ReqLLM API Keys Source: https://github.com/ash-project/ash_ai/blob/main/README.md This snippet shows how to configure API keys for LLM providers like OpenAI, Anthropic, and Google within the `runtime.exs` file for ReqLLM. ```elixir config :req_llm, openai_api_key: System.fetch_env!("OPENAI_API_KEY") config :req_llm, anthropic_api_key: System.fetch_env!("ANTHROPIC_API_KEY") config :req_llm, google_api_key: System.fetch_env!("GOOGLE_API_KEY") ``` -------------------------------- ### Run Specific Test File Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Focus testing on a particular file by providing its path. ```bash mix test test/path/to/test_file.exs ``` -------------------------------- ### Generate Spark Cheat Sheets Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Generate cheat sheets for Spark DSL extensions, specifying the desired extensions. ```bash mix spark.cheat_sheets --extensions AshAi ``` -------------------------------- ### Use ReqLLM Model Spec in Prompt Actions Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/langchain-to-reqllm-migration.md When using the `prompt/2` macro, specify the LLM using ReqLLM's string model spec format. Ensure `tools: true` is set if tools are needed. ```elixir run prompt("openai:gpt-4o", prompt: "Summarize: <%= @input.arguments.text %>", tools: true ) ``` -------------------------------- ### Check Test Migrations Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Verify if the test database migrations are up to date with the defined schema. ```bash mix test.check_migrations ``` -------------------------------- ### Run All Code Quality Checks Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Execute a comprehensive suite of checks including formatting, Credo, Dialyzer, and Sobelow. ```bash mix check ``` -------------------------------- ### Run Live LLM Tests with Mix Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/live-llm-testing.md Use `mix test` with specific flags to control which live LLM tests are executed. The `--only live_llm` flag runs all live LLM tests. ```bash # Run all live LLM tests mix test --only live_llm ``` ```bash # Run only OpenAI tests mix test --only live_llm:openai ``` ```bash # Run only Anthropic tests mix test --only live_llm:anthropic ``` ```bash # Run all tests including live LLM tests mix test --include live_llm ``` ```bash # Run a specific live LLM test file mix test test/live_llm/tool_calling_test.exs --include live_llm ``` -------------------------------- ### Create an Action for Parsing Raw Content into Structured Data Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Defines an action that parses raw text content into a structured `JobListing` using an LLM. It configures the LLM with a specific model, API key, and temperature, and provides a custom prompt. ```elixir action :parse_raw, JobListing do argument :raw_content, :string, allow_nil?: false run prompt( fn _input, _context -> LangChain.ChatModels.ChatOpenAI.new!({ model: "gpt-4o-mini", api_key: System.get_env("OPENAI_API_KEY"), temperature: 0.1 }) end, prompt: """ Parse this job listing into structured data following the exact schema. Extract all available information and return as JSON: <%= @input.arguments.raw_content %> """, tools: false ) end ``` -------------------------------- ### System/User Tuple Prompt Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Separate system and user messages using a tuple. Both parts support EEx templating for dynamic content. ```elixir run prompt( ChatOpenAI.new!(%{model: "gpt-4o"}), prompt: {"You are a sentiment analyzer", "Analyze: <%= @input.arguments.text %>"} ) ``` -------------------------------- ### Define an MCP UI Resource Source: https://github.com/ash-project/ash_ai/blob/main/documentation/dsls/DSL-AshAi.md Use `mcp_ui_resource` to serve static HTML files for MCP Apps, rendered in a sandboxed iframe. Link tools to UI resources using the tool's `ui:` option or `_meta.ui.resourceUri`. ```elixir mcp_ui_resource name, uri ``` ```elixir mcp_ui_resource :artist_viewer, "ui://artists/viewer.html", html_path: "priv/mcp_apps/artist_viewer.html" ``` ```elixir mcp_ui_resource :artist_dashboard, "ui://artists/dashboard.html", html_path: "priv/mcp_apps/artist_dashboard.html", csp: [connect_domains: ["api.example.com"]] ``` -------------------------------- ### Define a tool with identity and load options Source: https://github.com/ash-project/ash_ai/blob/main/documentation/dsls/DSL-AshAi.md Expose an Ash action, specifying the identity for updates and including related data ('albums') in the response. This is for updating an artist. ```elixir tool :update_artist, Artist, :update, identity: :id, load: [:albums] ``` -------------------------------- ### Custom Adapter Configuration Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Specify a custom adapter or adapter options for controlling how the LLM is called. Use `tools: false` when not using tool calling. ```elixir # Use a specific adapter run prompt( ChatOpenAI.new!(%{model: "gpt-4o"}), adapter: AshAi.Actions.Prompt.Adapter.RequestJson, tools: false ) ``` ```elixir # Use an adapter with custom options run prompt( ChatOpenAI.new!(%{model: "gpt-4o"}), adapter: {AshAi.Actions.Prompt.Adapter.StructuredOutput, [some_option: :value]}, tools: false ) ``` -------------------------------- ### Run Credo for Code Analysis Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Perform static analysis using Credo to identify potential issues and enforce coding style. ```bash mix credo --strict ``` -------------------------------- ### Set Up Vectorization for a Resource Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Integrate Ash AI vectorization into an Ash resource by including the AshAi extension and defining a vectorize block. Specify text attributes for embedding generation, used attributes for updates, the embedding strategy, and the embedding model implementation. ```elixir defmodule MyApp.Artist do use Ash.Resource, extensions: [AshAi] vectorize do # For creating a single vector from multiple attributes full_text do text(fn record -> """ Name: #{record.name} Biography: #{record.biography} """ end) # Optional - only rebuild embeddings when these attributes change used_attributes [:name, :biography] end # Choose a strategy for updating embeddings strategy :ash_oban # Specify your embedding model implementation embedding_model MyApp.OpenAiEmbeddingModel end # Rest of resource definition... end ``` -------------------------------- ### Create a Prompt-Backed Action for Sentiment Analysis Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Defines an action that uses an LLM to analyze sentiment. It specifies constraints on the return type and exposes arguments to the prompt. Tools can be enabled for the LLM. ```elixir action :analyze_sentiment, :atom do constraints one_of: [:positive, :negative] description """ Analyzes the sentiment of a given piece of text to determine if it is overall positive or negative. """ argument :text, :string do allow_nil? false description "The text for analysis" end run prompt( LangChain.ChatModels.ChatOpenAI.new!(%{model: "gpt-4o"}), # Allow the model to use tools tools: true, # Or restrict to specific tools # tools: [:list, :of, :tool, :names], # Optionally provide a custom prompt template # prompt: "Analyze the sentiment of the following text: <%= @input.arguments.text %>" ) end ``` -------------------------------- ### Set OpenAI API Key Source: https://github.com/ash-project/ash_ai/blob/main/README.md Configure your OpenAI API key by setting the OPENAI_API_KEY environment variable. This is required for the default LLM provider. ```bash export OPENAI_API_KEY=sk-... ``` -------------------------------- ### Configure Tool Arguments and Loaded Data Source: https://github.com/ash-project/ash_ai/blob/main/README.md Customize tool definitions to control which attributes are accessible for filtering, sorting, aggregation, and response data. Use the `load` option to include relationships, calculations, and private attributes. ```elixir tools do # Returns only public attributes tool :read_posts, MyApp.Blog.Post, :read # Returns public attributes AND loaded relationships/calculations # Note: loaded fields can include private attributes tool :read_posts_with_details, MyApp.Blog.Post, :read, load: [:author, :comment_count, :internal_notes] end ``` -------------------------------- ### Configure Google API Key for Req LLM Source: https://github.com/ash-project/ash_ai/blob/main/documentation/models/gemini.md Add your Google API key to the `:req_llm` configuration in `config/runtime.exs`. This allows your application to authenticate with Google services. You can keep existing provider configurations alongside this. ```elixir config :req_llm, google_api_key: System.fetch_env!("GOOGLE_API_KEY"), # Optional: keep this if your app also uses OpenAI models. openai_api_key: System.get_env("OPENAI_API_KEY") ``` -------------------------------- ### Define an MCP Resource Source: https://github.com/ash-project/ash_ai/blob/main/documentation/dsls/DSL-AshAi.md Use `mcp_resource` to expose static or dynamic assets like files, images, or JSON to LLM models. The resource description defaults to the action's description but can be overridden. ```elixir mcp_resource name, uri, resource, action ``` ```elixir mcp_resource :artist_card, "file://info/artist_info.txt", Artist, :artist_info ``` ```elixir mcp_resource :artist_card, "file://ui/artist_card.html", Artist, :artist_card, mime_type: "text/html" ``` ```elixir mcp_resource :artist_data, "file://data/artist.json", Artist, :to_json, description: "Artist metadata as JSON", mime_type: "application/json" ``` -------------------------------- ### Run Dialyzer for Type Checking Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Utilize Dialyzer for static analysis of types to catch potential runtime errors. ```bash mix dialyzer ``` -------------------------------- ### Validate Migration with Mix Commands Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/langchain-to-reqllm-migration.md After migrating, run standard Elixir project checks to ensure the changes are correctly applied. This includes formatting, testing, and static analysis. ```bash mix format mix test mix check ``` -------------------------------- ### Configure MCP Pipeline with OAuth Bearer Plug Source: https://github.com/ash-project/ash_ai/blob/main/README.md Sets up a pipeline for :mcp that validates bearer tokens using the BearerPlug. This plug loads the user from the token's 'sub' claim and sets it as the conn's actor. Use 'required?: false' to allow unauthenticated users. ```elixir pipeline :mcp do plug AshAuthentication.Phoenix.Oauth2Server.BearerPlug, oauth2_server: YourApp.Oauth2Server, # Use `required?: false` to allow unauthenticated # users to connect, for example if some tools # are publicly accessible. required?: true end ``` -------------------------------- ### Define a Prompt-Backed Action for Sentiment Analysis Source: https://github.com/ash-project/ash_ai/blob/main/README.md This snippet defines an action to analyze text sentiment using an LLM. It specifies constraints, arguments, and delegates the implementation to a prompt with tools enabled. ```elixir action :analyze_sentiment, :atom do constraints one_of: [:positive, :negative] description """ Analyzes the sentiment of a given piece of text to determine if it is overall positive or negative. """ argument :text, :string do allow_nil? false description "The text for analysis" end run prompt("openai:gpt-4o", # setting `tools: true` allows it to use all exposed tools in your app tools: true, # alternatively you can restrict it to only a set of tools # tools: [:list, :of, :tool, :names] # provide an optional prompt, which is an EEx template # prompt: "Analyze the sentiment of the following text: <%= @input.arguments.description %>", # optional req_llm override for tests # req_llm: MyApp.MockReqLLM ) end ``` -------------------------------- ### Dynamic Function Prompt Generation Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Generate prompts dynamically using a function that can return any supported format based on input and context. Useful for complex logic. ```elixir run prompt( ChatOpenAI.new!(%{model: "gpt-4o"}), prompt: fn input, context -> base = [Message.new_system!("You are helpful")] history = input.arguments.conversation_history |> Enum.map(fn %{"role" => role, "content" => content} -> case role do "user" -> Message.new_user!(content) "assistant" -> Message.new_assistant!(content) end end) base ++ history end ) ``` -------------------------------- ### Reset Test Database Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Completely reset the test database to its initial state, typically by dropping and recreating it. ```bash mix test.reset ``` -------------------------------- ### Run Specific Test by Line Number Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Isolate and run a single test case by specifying the file path and line number. ```bash mix test test/path/to/test_file.exs:42 ``` -------------------------------- ### Optional Sanity Check for LangChain References Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/langchain-to-reqllm-migration.md Perform an optional sanity check by searching your project's codebase for any remaining references to 'LangChain' or 'langchain'. ```bash rg -n "LangChain|langchain" lib test config ``` -------------------------------- ### Generate Chat Feature with Custom User Resource Source: https://github.com/ash-project/ash_ai/blob/main/README.md If your user resource is not named `.Accounts.User`, specify it using the `--user` flag. ```bash mix ash_ai.gen.chat --live --user MyApp.CustomUser ``` -------------------------------- ### Add ReqLLM Dependency in mix.exs Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/langchain-to-reqllm-migration.md Add the ReqLLM dependency to your `mix.exs` file to replace the LangChain integration. Fetch dependencies after updating. ```elixir {:req_llm, "~> 1.7"} ``` ```bash mix deps.get ``` -------------------------------- ### Define Tools Directly on a Resource Source: https://github.com/ash-project/ash_ai/blob/main/README.md A shorthand for defining tools directly on a resource. This is equivalent to defining them on the domain for that specific resource. ```elixir defmodule MyApp.Blog.Post do use Ash.Resource, extensions: [AshAi] tools do tool :read_posts, :read tool :create_post, :create end end ``` -------------------------------- ### Usage Rules MCP Tool API Source: https://github.com/ash-project/ash_ai/blob/main/notes/usage-rules-mcp-implementation-plan.md This section details the two main tools exposed via the MCP server for interacting with package usage rules. ```APIDOC ## MCP Tool: get_usage_rules ### Description Retrieves the content of `usage-rules.md` files for specified packages. ### Method MCP Tool Action ### Endpoint N/A (MCP Tool) ### Parameters #### Query Parameters - **packages** (array of strings) - Required - A list of package names for which to retrieve usage rules. ### Request Example ```json { "action": "get_usage_rules", "arguments": { "packages": ["ash", "ash_postgres"] } } ``` ### Response #### Success Response (200) - **package** (string) - The name of the package. - **rules** (string) - The markdown content of the `usage-rules.md` file for the package. #### Response Example ```json [ { "package": "ash", "rules": "# Ash Usage Rules\n\n- Use the `Ash.start/1` function to initialize Ash." }, { "package": "ash_postgres", "rules": "# Ash Postgres Usage Rules\n\n- Ensure your database connection is properly configured." } ] ``` ## MCP Tool: list_packages_with_rules ### Description Lists all packages in the project that have a `usage-rules.md` file. ### Method MCP Tool Action ### Endpoint N/A (MCP Tool) ### Parameters None ### Request Example ```json { "action": "list_packages_with_rules", "arguments": {} } ``` ### Response #### Success Response (200) - Returns an array of strings, where each string is the name of a package that has usage rules. #### Response Example ```json ["ash", "ash_postgres", "igniter", ...] ``` ``` -------------------------------- ### Derive Tenant from Connection in MCP Server Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/multi-tenancy-and-tenants.md In the AshAi MCP HTTP server, derive the tenant from the incoming connection using Ash.PlugHelpers.get_tenant/1. Ensure your plugs correctly set the tenant on the connection. ```elixir tenant: Ash.PlugHelpers.get_tenant(conn) ``` -------------------------------- ### Configure Vectorization with Full-Text Search Source: https://github.com/ash-project/ash_ai/blob/main/README.md Define vectorization for a resource, specifying text extraction logic, attributes that trigger updates, attribute mappings, and the embedding model. Use `name` for multiple `full_text` configurations. ```elixir vectorize do full_text do text(fn record -> """ Name: #{record.name} Biography: #{record.biography} """ end) # When used_attributes are defined, embeddings will only be rebuilt when # the listed attributes are changed in an update action. used_attributes [:name, :biography] end strategy :after_action attributes(name: :vectorized_name, biography: :vectorized_biography) # See the section below on defining an embedding model embedding_model MyApp.OpenAiEmbeddingModel end ``` -------------------------------- ### Define Tools on an Ash Domain Source: https://github.com/ash-project/ash_ai/blob/main/README.md Expose actions from resources within a domain as tools. This is the primary way to define tools for AI integration. ```elixir defmodule MyApp.Blog do use Ash.Domain, extensions: [AshAi] tools do tool :read_posts, MyApp.Blog.Post, :read tool :create_post, MyApp.Blog.Post, :create tool :publish_post, MyApp.Blog.Post, :publish tool :read_comments, MyApp.Blog.Comment, :read end end ``` -------------------------------- ### Format Code Source: https://github.com/ash-project/ash_ai/blob/main/AGENTS.md Automatically format Elixir code according to project standards. ```bash mix format ``` -------------------------------- ### Regenerate Chat Code with ReqLLM Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/langchain-to-reqllm-migration.md If your application uses generated chat files, re-run the `mix ash_ai.gen.chat` command with your existing flags. The generated code will now utilize ReqLLM and `AshAi.ToolLoop`. ```bash mix ash_ai.gen.chat --live ``` -------------------------------- ### Customize Prompt Actions with transform_flow Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/langchain-to-reqllm-migration.md For complex prompt customization, use `transform_flow` to modify the ReqLLM flow state. This replaces the `modify_chain` approach used with LangChain. ```elixir run prompt("openai:gpt-4o", tools: [], transform_flow: fn flow_state, _context -> %{ flow_state | extra_tools: flow_state.extra_tools ++ [my_custom_tool], req_llm_opts: Keyword.put(flow_state.req_llm_opts, :trace_id, "abc") } end ) ``` -------------------------------- ### Dynamically Configure LLM for Sentiment Analysis Source: https://github.com/ash-project/ash_ai/blob/main/usage-rules.md Configures an LLM for an action using a function to allow for dynamic runtime settings like API keys and endpoints. The function receives input and context for configuration. ```elixir action :analyze_sentiment, :atom do argument :text, :string, allow_nil?: false run prompt( fn _input, _context -> LangChain.ChatModels.ChatOpenAI.new!({ model: "gpt-4o", # this can also be configured in application config, see langchain docs for more. api_key: System.get_env("OPENAI_API_KEY"), endpoint: System.get_env("OPENAI_ENDPOINT") }) end, tools: false ) end ``` -------------------------------- ### Define MCP Resources on an Ash Domain Source: https://github.com/ash-project/ash_ai/blob/main/README.md Expose static or dynamic content as MCP resources. These resources return content that LLMs can read and reference, unlike tools which perform actions. ```elixir defmodule MyApp.Blog do use Ash.Domain, extensions: [AshAi] mcp_resources do # Return HTML UI for a post # Description is inherited from the :render_card action mcp_resource :post_card, "file://ui/post_card.html", Post, :render_card do mime_type "text/html" end # Return JSON data with custom description mcp_resource :post_metadata, "file://data/post.json", Post, :metadata do description "Metadata about the post including author and tags", mime_type "application/json" end end end ``` -------------------------------- ### Add MCP Server Router Forward Source: https://github.com/ash-project/ash_ai/blob/main/README.md Integrates the AshAi.Mcp.Router into your Phoenix router under the '/mcp' scope. Configure the tools list and protocol version statement as needed. The 'otp_app' should match your application's OTP app name. ```elixir scope "/mcp" do pipe_through :mcp forward "/", AshAi.Mcp.Router, tools: [ :list, :of, :tools ], # For many tools, you will need to set the `protocol_version_statement` to the older version. protocol_version_statement: "2024-11-05", otp_app: :my_app end ``` -------------------------------- ### Manual Vectorization Strategy Configuration Source: https://github.com/ash-project/ash_ai/blob/main/README.md Configuration for the :manual vectorization strategy. Shows how to disable the automatic generation of the update action. ```elixir vectorize do full_text do ... end strategy :manual define_update_action_for_manual_strategy? false ... end ``` -------------------------------- ### Configure Embeddings with ReqLLM Source: https://github.com/ash-project/ash_ai/blob/main/documentation/topics/langchain-to-reqllm-migration.md When using embeddings, specify `AshAi.EmbeddingModels.ReqLLM` and provide explicit `model` and `dimensions`. This replaces previous embedding configurations. ```elixir vectorize do embedding_model {AshAi.EmbeddingModels.ReqLLM, model: "openai:text-embedding-3-small", dimensions: 1536 } end ```