### Install Dependencies with Mix Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use this command to fetch and install project dependencies. ```bash mix deps.get ``` -------------------------------- ### Build Prompts with OpenAI.Responses.Prompt Source: https://context7.com/vkryukov/openai_responses/llms.txt Compose prompts by adding developer, system, and user messages using pure functions. This example demonstrates building a prompt with a specific model and then appending/prepending messages. ```elixir alias OpenAI.Responses alias OpenAI.Responses.Prompt # Build a prompt with different roles opts = %{} |> Prompt.add_developer("You are a helpful assistant. Be concise.") |> Prompt.add_system("Current date: 2024-01-15") |> Prompt.add_user("What day of the week is it?") |> Map.put(:model, "gpt-4.1-mini") response = Responses.create!(opts) IO.puts(response.text) # Append and prepend messages opts = %{input: "Hello"} |> Prompt.prepend(%{role: :developer, content: "Speak formally"}) |> Prompt.append("Please help me") # Result: input contains developer message, then "Hello", then "Please help me" ``` -------------------------------- ### Define schema using list format Source: https://github.com/vkryukov/openai_responses/blob/main/CHANGELOG.md Examples of using list syntax for schema definitions, providing flexibility for options and array types. ```elixir [:string, %{description: "Full name"}] ``` ```elixir [:string, [description: "Full name"]] ``` ```elixir [:array, :string] ``` -------------------------------- ### List All OpenAI Models with Pricing Source: https://context7.com/vkryukov/openai_responses/llms.txt Obtain a list of all available OpenAI models along with their pricing information using `Pricing.list_models/0`. This function returns a list of models, and the example shows how to take the first few. ```elixir alias OpenAI.Responses.Pricing # List all models with pricing models = Pricing.list_models() IO.inspect(Enum.take(models, 5)) ``` -------------------------------- ### GET /models Source: https://context7.com/vkryukov/openai_responses/llms.txt Retrieves a list of available OpenAI models, with optional filtering by model ID pattern. ```APIDOC ## GET /models ### Description Lists all available OpenAI models. Accepts an optional filter string to match against model IDs. ### Method GET ### Endpoint OpenAI.Responses.list_models/0 ### Parameters #### Query Parameters - **filter** (string) - Optional - A string pattern to filter the returned model IDs. ### Response #### Success Response (200) - **models** (list) - A list of model objects containing model details. ``` -------------------------------- ### Get Pricing for OpenAI Models Source: https://context7.com/vkryukov/openai_responses/llms.txt Retrieve pricing information for specific OpenAI models using `Pricing.get_pricing/1`. Prices are stored as Decimal values per million tokens for accurate cost calculations. ```elixir alias OpenAI.Responses.Pricing # Get pricing for a specific model pricing = Pricing.get_pricing("gpt-4.1-mini") IO.inspect(pricing) # => %{ # input: #Decimal<0.40>, # cached_input: #Decimal<0.10>, # output: #Decimal<1.60> # } ``` -------------------------------- ### Define union types in schema Source: https://github.com/vkryukov/openai_responses/blob/main/CHANGELOG.md Examples of using the anyOf specification for union types in schema definitions. ```elixir {:anyOf, [:string, :number]} ``` ```elixir [:anyOf, [:string, :number]] ``` -------------------------------- ### Implement Retry Logic for API Errors Source: https://context7.com/vkryukov/openai_responses/llms.txt Handle OpenAI API errors by implementing retry logic using the `retryable?/1` function. This example shows how to retry requests with exponential backoff for specific error types like rate limits or server errors. ```elixir alias OpenAI.Responses alias OpenAI.Responses.Error defmodule MyApp.AI do def create_with_retry(opts, max_retries \ 3) do do_create(opts, max_retries, 0) end defp do_create(opts, max_retries, attempt) when attempt < max_retries do case Responses.create(opts) do {:ok, response} -> {:ok, response} {:error, %Error{} = error} -> if Error.retryable?(error) do # Exponential backoff :timer.sleep(:math.pow(2, attempt) * 1000 |> trunc()) do_create(opts, max_retries, attempt + 1) else {:error, error} end {:error, %Req.TransportError{} = error} -> if Error.retryable?(error) do :timer.sleep(:math.pow(2, attempt) * 1000 |> trunc()) do_create(opts, max_retries, attempt + 1) else {:error, error} end end end defp do_create(_opts, _max_retries, _attempt), do: {:error, :max_retries_exceeded} end # Check if specific errors are retryable Error.retryable?(%Error{status: 429}) # => true (rate limit) Error.retryable?(%Error{status: 500}) # => true (server error) Error.retryable?(%Error{status: 400}) # => false (bad request) Error.retryable?(%Req.TransportError{reason: :timeout}) # => true ``` -------------------------------- ### Generate Project Documentation with Mix Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Generate Hex documentation for the Elixir project. ```bash mix docs ``` -------------------------------- ### Create response with map options Source: https://github.com/vkryukov/openai_responses/blob/main/CHANGELOG.md Demonstrates using a map for options in the create function, supporting mixed atom and string keys. ```elixir Responses.create(%{input: "Hello", model: "gpt-4o"}) ``` -------------------------------- ### Get Enumerable for Stream Processing Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `stream/1` to obtain an Elixir Stream for processing streaming responses. ```elixir OpenAI.Responses.stream(prompt) ``` -------------------------------- ### Configure OpenAI.Responses Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Add the dependency to your mix.exs file and set the API key via environment variables. ```elixir # Add to mix.exs {:openai_responses, "~> 0.8.4"} # Set API key via environment variable export OPENAI_API_KEY="your-key" ``` -------------------------------- ### GET /responses/stream Source: https://context7.com/vkryukov/openai_responses/llms.txt Returns an Elixir Stream that yields chunks from the OpenAI API as they arrive, allowing for incremental processing. ```APIDOC ## GET /responses/stream ### Description Returns an Elixir Stream that yields chunks from the OpenAI API as they arrive. Each chunk is wrapped in `{:ok, chunk}` or `{:error, reason}` tuples. ### Method GET ### Parameters #### Query Parameters - **input** (string) - Required - The prompt or input text. - **model** (string) - Required - The model identifier. ``` -------------------------------- ### Extract Text from Response Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `extract_text/1` to get assistant messages from raw API responses. This function is idempotent. ```elixir OpenAI.Responses.Response.extract_text(raw_response) ``` -------------------------------- ### Extract Function Calls from Response Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `extract_function_calls/1` to get function call data from API responses. This function is idempotent. ```elixir OpenAI.Responses.Response.extract_function_calls(raw_response) ``` -------------------------------- ### Follow-up with Reasoning Models (Settings Preserved) Source: https://context7.com/vkryukov/openai_responses/llms.txt When using `create/2` with reasoning models, settings like `model` and `reasoning.effort` are preserved from the previous response unless explicitly overridden. ```elixir alias OpenAI.Responses # Follow-up with reasoning models (settings preserved) first = Responses.create!( input: "Complex math problem", model: "gpt-5-mini", reasoning: %{effort: "high"} ) # Inherits gpt-5-mini and high reasoning effort second = Responses.create!(first, input: "Can you verify that answer?") ``` -------------------------------- ### Prepare Payload with Options Normalization Source: https://github.com/vkryukov/openai_responses/blob/main/README.md Demonstrates how to prepare a payload, preserving specific text verbosity while setting the format to JSON Schema. Options are normalized to string-keyed maps internally. ```elixir payload = OpenAI.Responses.Internal.prepare_payload(%{ input: "test", text: %{verbosity: "low"}, schema: %{name: :string}, model: "gpt-4.1-mini" }) # payload["text"]["verbosity"] == "low" # payload["text"]["format"]["type"] == "json_schema" ``` -------------------------------- ### Extract JSON from Response Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `extract_json/1` to get structured JSON data from API responses. It automatically calls `extract_text/1` if needed. This function is idempotent. ```elixir OpenAI.Responses.Response.extract_json(raw_response) ``` -------------------------------- ### Get Elixir Stream for Event Processing Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `stream/1` to obtain an Elixir Stream that yields `{:ok, chunk}` or `{:error, reason}` tuples for Server-Sent Events. ```elixir OpenAI.Responses.Stream.stream(prompt) ``` -------------------------------- ### Create Response and Track Costs Source: https://github.com/vkryukov/openai_responses/blob/main/README.md Shows how to create a response and inspect its cost, which is represented using Decimal types for high precision. Includes conversion to float for cents. ```elixir {:ok, response} = Responses.create(input: "Explain quantum computing", model: "gpt-4.1-mini") # All cost values are Decimal for precision IO.inspect(response.cost) # => %{ # input_cost: #Decimal<0.0004>, # output_cost: #Decimal<0.0008>, # total_cost: #Decimal<0.0012>, # cached_discount: #Decimal<0> # } # Convert to float if needed total_in_cents = response.cost.total_cost |> Decimal.mult(100) |> Decimal.to_float() ``` -------------------------------- ### Run Tests with Mix Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Execute project tests. By default, API integration tests are excluded. ```bash mix test ``` -------------------------------- ### create/1 and create!/1 Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Creates a new AI response. The bang version raises on error. ```APIDOC ## create/1 and create!/1 ### Description Creates a new AI response. The bang version raises on error. ### Parameters #### Request Body - **input** (string) - Required - The prompt or input text for the model. - **model** (string) - Required - The model identifier (e.g., "gpt-4.1-mini"). - **temperature** (float) - Optional - Sampling temperature. - **max_tokens** (integer) - Optional - Maximum tokens to generate. - **schema** (map) - Optional - Schema for structured output. - **stream** (function) - Optional - Callback function for streaming responses. ### Response - **response** (struct) - The response object containing text, parsed data, function calls, and cost. ``` -------------------------------- ### run/2 and run!/2 Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Automates function calling by repeatedly calling functions until completion. ```APIDOC ## run/2 and run!/2 ### Description Automates function calling by repeatedly calling functions until completion. ### Parameters - **options** (keyword list) - Required - Includes input, tools, and model. - **functions** (map) - Required - A map of function names to implementation functions. ``` -------------------------------- ### Process Streaming Responses Incrementally Source: https://context7.com/vkryukov/openai_responses/llms.txt Use `OpenAI.Responses.stream/1` to get an Elixir Stream that yields response chunks as they arrive. This is useful for processing responses incrementally without waiting for the entire response to complete. Each chunk is wrapped in `{:ok, chunk}` or `{:error, reason}`. ```elixir alias OpenAI.Responses # Process all stream events Responses.stream(input: "Write a short story", model: "gpt-4.1-mini") |> Enum.each(fn {:ok, %{event: "response.output_text.delta", data: %{"delta" => text}}} -> IO.write(text) {:ok, %{event: "response.completed"}} -> IO.puts("\n[Complete]") {:error, reason} -> IO.puts("Error: #{inspect(reason)}") _ -> :ok end) ``` ```elixir # Collect only text deltas text = Responses.stream(input: "Explain recursion", model: "gpt-4.1-mini") |> Stream.filter(fn {:ok, %{event: "response.output_text.delta"}} -> true _ -> false end) |> Stream.map(fn {:ok, chunk} -> chunk.data["delta"] end) |> Enum.join() ``` ```elixir # Accumulate with error tracking result = Responses.stream(input: "Count to 10", model: "gpt-4.1-mini") |> Enum.reduce(%{text: "", errors: []}, fn {:ok, %{event: "response.output_text.delta", data: %{"delta" => delta}}}, acc -> %{acc | text: acc.text <> delta} {:error, reason}, acc -> %{acc | errors: [reason | acc.errors]} _, acc -> acc end) ``` -------------------------------- ### List Available OpenAI Models with Options Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `list_models/1` to retrieve a list of available models with specific options. ```elixir OpenAI.Responses.list_models(options) ``` -------------------------------- ### Compose Prompts with Helpers Source: https://github.com/vkryukov/openai_responses/blob/main/CHANGELOG.md Use prompt helpers to build input structures for OpenAI API calls. ```elixir alias OpenAI.Responses.Prompt opts = %{} opts = Prompt.add_developer(opts, "Talk like a pirate.") opts = Prompt.add_user(opts, "Write me a haiku about Elixir") opts = Map.put(opts, :model, "gpt-4.1-mini") response = OpenAI.Responses.create!(opts) ``` -------------------------------- ### Compile Elixir Project with Mix Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Compile the Elixir project to ensure all modules are built. ```bash mix compile ``` -------------------------------- ### OpenAI.Responses.create!/1 Source: https://context7.com/vkryukov/openai_responses/llms.txt Same as `create/1` but raises an exception on failure instead of returning an error tuple. Returns the Response struct directly, making it convenient for scripts and when you want to handle errors via exceptions. ```APIDOC ## OpenAI.Responses.create!/1 ### Description Same as `create/1` but raises an exception on failure instead of returning an error tuple. Returns the Response struct directly, making it convenient for scripts and when you want to handle errors via exceptions. ### Method POST ### Endpoint /v1/chat/completions (inferred) ### Parameters #### Request Body - **input** (string | list) - Required - The prompt or conversation history. - **model** (string) - Required - The model to use (e.g., "gpt-4.1-mini"). - **temperature** (float) - Optional - Controls randomness. Lower values make output more focused and deterministic. - **max_tokens** (integer) - Optional - The maximum number of tokens to generate. - **reasoning** (map) - Optional - Specifies reasoning parameters, e.g., `%{effort: "high"}`. ### Request Example ```elixir alias OpenAI.Responses # Direct response without tuple unwrapping response = Responses.create!( input: "What is the capital of France?", model: "gpt-4.1-mini" ) IO.puts(response.text) # Chain operations easily response = Responses.create!( input: [ %{role: :developer, content: "Talk like a pirate."}, %{role: :user, content: "What's the weather like?"} ], model: "gpt-4.1-mini" ) IO.puts(response.text) ``` ### Response #### Success Response (200) - **text** (string) - The generated text response. - **json** (map | nil) - Parsed JSON if the response is structured. - **function_calls** (list) - Extracted function calls. - **cost** (map) - Cost information including input, output, and total costs. - **raw** (map) - The raw API response body. #### Response Example ```elixir %OpenAI.Responses.Response{ text: "The capital of France is Paris.", cost: %{input_cost: #Decimal<...>, output_cost: #Decimal<...>, total_cost: #Decimal<...>} } ``` ``` -------------------------------- ### Implement a chat application with context Source: https://context7.com/vkryukov/openai_responses/llms.txt Demonstrates a recursive loop for multi-turn conversations using streaming responses. ```elixir defmodule Chat do alias OpenAI.Responses def run do IO.puts("AI Chat (type /exit to quit)") IO.puts(String.duplicate("=", 40)) loop(nil) end defp loop(previous_response) do input = IO.gets("\nYou: ") |> String.trim() case input do "/exit" -> IO.puts("\nGoodbye!") _ -> IO.write("\nAI: ") response = if previous_response do # Continue conversation with context Responses.create!( previous_response, input: input, stream: Responses.Stream.delta(&IO.write/1) ) else # Start new conversation Responses.create!( input: input, model: "gpt-4.1-mini", stream: Responses.Stream.delta(&IO.write/1) ) end IO.puts("") loop(response) end end end Chat.run() ``` -------------------------------- ### Create AI Response with Additional Options Source: https://context7.com/vkryukov/openai_responses/llms.txt Pass a map to `Responses.create/1` to include additional parameters like `temperature` and `max_tokens` for more control over the AI's output. ```elixir alias OpenAI.Responses # Using a map with additional options {:ok, response} = Responses.create(%{ input: "Explain quantum computing in one sentence", model: "gpt-4.1-mini", temperature: 0.7, max_tokens: 100 }) ``` -------------------------------- ### OpenAI.Responses.create/1 Source: https://context7.com/vkryukov/openai_responses/llms.txt Creates a new AI response from the OpenAI API. Accepts a keyword list or map of options including `input`, `model`, `temperature`, `max_tokens`, and other OpenAI parameters. Returns `{:ok, %Response{}}` on success or `{:error, term}` on failure. ```APIDOC ## OpenAI.Responses.create/1 ### Description Creates a new AI response from the OpenAI API. Accepts a keyword list or map of options including `input`, `model`, `temperature`, `max_tokens`, and other OpenAI parameters. Returns `{:ok, %Response{}}` on success or `{:error, term}` on failure. The response struct contains extracted text, parsed JSON (for structured outputs), function calls, cost information, and the raw API response body. ### Method POST ### Endpoint /v1/chat/completions (inferred) ### Parameters #### Request Body - **input** (string | list) - Required - The prompt or conversation history. - **model** (string) - Required - The model to use (e.g., "gpt-4.1-mini"). - **temperature** (float) - Optional - Controls randomness. Lower values make output more focused and deterministic. - **max_tokens** (integer) - Optional - The maximum number of tokens to generate. - **reasoning** (map) - Optional - Specifies reasoning parameters, e.g., `%{effort: "high"}`. ### Request Example ```elixir alias OpenAI.Responses # Basic usage with keyword list {:ok, response} = Responses.create( input: "Write me a haiku about Elixir", model: "gpt-4.1-mini" ) IO.puts(response.text) # Using a map with additional options {:ok, response} = Responses.create(%{ input: "Explain quantum computing in one sentence", model: "gpt-4.1-mini", temperature: 0.7, max_tokens: 100 }) # Using reasoning models {:ok, response} = Responses.create( input: "Solve this logic puzzle: ...", model: "gpt-5-mini", reasoning: %{effort: "high"} ) # Access cost information IO.inspect(response.cost) ``` ### Response #### Success Response (200) - **text** (string) - The generated text response. - **json** (map | nil) - Parsed JSON if the response is structured. - **function_calls** (list) - Extracted function calls. - **cost** (map) - Cost information including input, output, and total costs. - **raw** (map) - The raw API response body. #### Response Example ```json { "text": "Concurrent streams flow,\nPattern matching guides the way,\nFault-tolerant code.", "cost": { "input_cost": #Decimal<0.0004>, "output_cost": #Decimal<0.0008>, "total_cost": #Decimal<0.0012>, "cached_discount": #Decimal<0> } } ``` ``` -------------------------------- ### Run All Tests Including API Integration Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Execute all tests, including those that make real API calls. ```bash mix test --include api ``` -------------------------------- ### Chain Operations with create!/1 Source: https://context7.com/vkryukov/openai_responses/llms.txt The `create!/1` function is useful for chaining operations, especially when dealing with conversational context or sequential AI tasks. ```elixir alias OpenAI.Responses # Chain operations easily response = Responses.create!( input: [ %{role: :developer, content: "Talk like a pirate."}, %{role: :user, content: "What's the weather like?"} ], model: "gpt-4.1-mini" ) IO.puts(response.text) # => "Arrr, matey! The weather be fine for sailin' today!" ``` -------------------------------- ### Configure OpenAI API Key via Environment Variable Source: https://context7.com/vkryukov/openai_responses/llms.txt Set the `OPENAI_API_KEY` environment variable to authenticate with the OpenAI API. ```bash # Environment variable export OPENAI_API_KEY="your-api-key" ``` -------------------------------- ### Create Streaming AI Response (Raises on Error) Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `create!/2` with a stream option for streaming AI responses that raises an exception on error. Ensure API key is configured. ```elixir OpenAI.Responses.create!(prompt, stream: true) ``` -------------------------------- ### Create AI Response (Raises Exception on Failure) Source: https://context7.com/vkryukov/openai_responses/llms.txt Use `Responses.create!/1` for scenarios where you prefer exceptions over error tuples. This is convenient for scripts or when error handling is managed via exceptions. ```elixir alias OpenAI.Responses # Direct response without tuple unwrapping response = Responses.create!( input: "What is the capital of France?", model: "gpt-4.1-mini" ) IO.puts(response.text) # => "The capital of France is Paris." ``` -------------------------------- ### create/2 and create!/2 Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Creates follow-up responses maintaining conversation state. ```APIDOC ## create/2 and create!/2 ### Description Creates follow-up responses maintaining conversation state on the OpenAI side. Preserves specific generation settings like model, reasoning effort, and verbosity. ### Parameters - **previous_response** (struct) - Required - The previous response object. - **options** (keyword list) - Required - Options including input and optional schema overrides. ``` -------------------------------- ### Compose Prompts with Roles and Function Calls Source: https://github.com/vkryukov/openai_responses/blob/main/README.md Utilize Prompt helpers to construct messages with roles (developer, user, system) and handle function calls by executing them and appending their outputs. ```elixir alias OpenAI.Responses alias OpenAI.Responses.Prompt # Compose a prompt with roles opts = %{} opts = Prompt.add_developer(opts, "Talk like a pirate.") opts = Prompt.add_user(opts, "Write me a haiku about Elixir") opts = Map.put(opts, :model, "gpt-4.1-mini") response = Responses.create!(opts) IO.puts(response.text) # Prepend a system message opts = Prompt.add_system(opts, "You are a helpful coach") followup = Responses.create!(opts) # Handling function calls: execute and append outputs functions = %{ "get_time" => fn %{} -> DateTime.utc_now() |> to_string() end } {:ok, with_calls} = Responses.create(input: "What time is it?", tools: [ Responses.Schema.build_function("get_time", "Get UTC time", %{}) ], model: "gpt-4.1-mini") opts = Prompt.add_function_outputs(%{input: []}, with_calls.function_calls, functions) final = Responses.create!(with_calls, opts) IO.puts(final.text) ``` -------------------------------- ### Build Function Calling Tool Schema Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `build_function/3` to construct schemas for function calling tools, specifying name, description, and parameters. ```elixir OpenAI.Responses.Schema.build_function("tool_name", "description", %{parameters: schema}) ``` -------------------------------- ### Create Synchronous AI Response (Raises on Error) Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `create!/1` for a synchronous AI response that raises an exception on error. Ensure API key is configured. ```elixir OpenAI.Responses.create!(prompt) ``` -------------------------------- ### list_models/0 and list_models/1 Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Lists available OpenAI models. ```APIDOC ## list_models/0 and list_models/1 ### Description Lists available OpenAI models with optional filtering. ### Parameters - **pattern** (string) - Optional - Pattern to filter model names. ``` -------------------------------- ### Compose inputs with Prompt helpers in Elixir Source: https://github.com/vkryukov/openai_responses/blob/main/CHANGELOG.md Use Prompt helpers to build complex input structures before calling create!. ```elixir alias OpenAI.Responses.Prompt opts = %{} |> Prompt.add_developer("Talk like a pirate.") |> Prompt.add_user("Write me a haiku about Elixir") |> Map.put(:model, "gpt-4.1-mini") OpenAI.Responses.create!(opts) ``` -------------------------------- ### Migrate manual function calling in Elixir Source: https://github.com/vkryukov/openai_responses/blob/main/CHANGELOG.md Replace manual function call handling with the Prompt.add_function_outputs helper. ```elixir outputs = OpenAI.Responses.call_functions(response.function_calls, functions) {:ok, final} = OpenAI.Responses.create(response, input: outputs) ``` ```elixir alias OpenAI.Responses.Prompt opts = Prompt.add_function_outputs(%{input: []}, response.function_calls, functions) {:ok, final} = OpenAI.Responses.create(response, opts) ``` -------------------------------- ### Automate Function Calling Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Use run/2 or run!/2 to execute tools and resolve function calls automatically. ```elixir # Define functions functions = %{ "get_weather" => fn %{"location" => loc} -> "15°C in #{loc}" end } # Define tools weather_tool = Responses.Schema.build_function( "get_weather", "Get weather for a location", %{location: :string} ) # Run conversation responses = Responses.run( [input: "What's the weather in Paris?", tools: [weather_tool], model: "gpt-4.1-mini"], functions ) # Last response has final answer final_answer = List.last(responses).text ``` -------------------------------- ### Configure API Key via Environment Variable Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Set the `OPENAI_API_KEY` environment variable to configure the API key. ```bash export OPENAI_API_KEY="your-key" ``` -------------------------------- ### Create Basic AI Response Source: https://context7.com/vkryukov/openai_responses/llms.txt Use `Responses.create/1` with a keyword list to generate a basic AI response. Access the extracted text via the `.text` attribute of the response struct. ```elixir alias OpenAI.Responses # Basic usage with keyword list {:ok, response} = Responses.create( input: "Write me a haiku about Elixir", model: "gpt-4.1-mini" ) IO.puts(response.text) # => "Concurrent streams flow, # Pattern matching guides the way, # Fault-tolerant code." ``` -------------------------------- ### List Available OpenAI Models Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `list_models/0` to retrieve a list of available models. ```elixir OpenAI.Responses.list_models() ``` -------------------------------- ### Stream with Callback and Complete Response Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `stream_with_callback/2` to stream responses while providing a callback function. It returns `{:ok, %Response{}}` with complete metadata upon completion. ```elixir OpenAI.Responses.Stream.stream_with_callback(prompt, callback_function) ``` -------------------------------- ### Create Streaming AI Response Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `create/2` with a stream option for streaming AI responses. Ensure API key is configured. ```elixir OpenAI.Responses.create(prompt, stream: true) ``` -------------------------------- ### POST /responses/create Source: https://context7.com/vkryukov/openai_responses/llms.txt Generates a response from the OpenAI model based on the provided input and schema. Supports object and array schemas for structured output. ```APIDOC ## POST /responses/create ### Description Generates a response from the OpenAI model. The library automatically converts Elixir syntax to JSON Schema format and parses the response into `response.parsed`. ### Method POST ### Parameters #### Request Body - **input** (string) - Required - The prompt or input text for the model. - **schema** (map/tuple) - Required - The schema definition for the expected output. Can be a map for objects or `{:array, schema}` for lists. - **model** (string) - Required - The model identifier (e.g., "gpt-4.1-mini"). ### Request Example { "input": "Extract user info from: John Doe, @johndoe, john@example.com", "schema": { "name": "string", "username": {"string": {"pattern": "^@[a-zA-Z0-9_]+$"}}, "email": {"string": {"format": "email"}} }, "model": "gpt-4.1-mini" } ### Response #### Success Response (200) - **parsed** (map/array) - The structured response data parsed according to the provided schema. ``` -------------------------------- ### Simple Terminal Chat Implementation Source: https://github.com/vkryukov/openai_responses/blob/main/README.md A basic Elixir module for creating an interactive terminal chat with an AI, supporting conversation history and graceful exit. ```elixir defmodule Chat do alias OpenAI.Responses def run do IO.puts("Simple AI Chat (type /exit or /quit to end)") IO.puts("=" |> String.duplicate(40)) loop(nil) end defp loop(previous_response) do input = IO.gets("\nYou: ") |> String.trim() case input do cmd when cmd in ["/exit", "/quit"] -> IO.puts("\nGoodbye!") _ -> IO.write("\nAI: ") response = if previous_response do Responses.create!( previous_response, input: input, stream: Responses.Stream.delta(&IO.write/1) ) else Responses.create!( input: input, model: "gpt-4.1-mini", stream: Responses.Stream.delta(&IO.write/1) ) end IO.puts("") # Add newline after response loop(response) end end end # Run the chat Chat.run() ``` -------------------------------- ### Helper Callback for Simple Text Streaming Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `delta/1` as a helper callback function for processing text deltas in simple text streaming scenarios. ```elixir OpenAI.Responses.Stream.delta(text_delta) ``` -------------------------------- ### Execute Function Outputs Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Manually execute function calls and append results to the prompt using Prompt.add_function_outputs/3. ```elixir # Get a response with function calls {:ok, response} = Responses.create( input: "What's the weather in Paris?", tools: [weather_tool], model: "gpt-4.1-mini" ) # Define function implementations functions = %{ "get_weather" => fn %{"location" => loc} -> # Custom logic before/after the actual call result = fetch_weather_data(loc) log_api_call(:weather, loc) # Result must be JSON-encodable (map, list, string, number, boolean, nil) %{temperature: result.temp, unit: "C", conditions: result.conditions} end } alias OpenAI.Responses.Prompt # Execute functions and append outputs to the prompt opts = Prompt.add_function_outputs(%{input: []}, response.function_calls, functions) # Continue conversation with custom context or extra messages {:ok, final} = Responses.create(response, Prompt.append(opts, %{role: :user, content: "Convert to Fahrenheit"}) ) ``` -------------------------------- ### Create Synchronous AI Response Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `create/1` for a synchronous AI response. Ensure API key is configured. ```elixir OpenAI.Responses.create(prompt) ``` -------------------------------- ### Build Function Tool Definition Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Creates function tool definitions for function calling. ```elixir tool = Schema.build_function( "search_products", "Search for products by name and category", %{ query: {:string, description: "Search query"}, category: {:string, enum: ["electronics", "books", "clothing"]}, max_results: {:integer, minimum: 1, maximum: 100, description: "Max results to return"} } ) # Use with create response = Responses.create!( input: "Find me some laptops", tools: [tool], model: "gpt-4.1-mini" ) ``` -------------------------------- ### Configure API Key via Application Config Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Set the API key in the application's configuration file. ```elixir config :openai_responses, :openai_api_key, "your-key" ``` -------------------------------- ### Set OpenAI API Key via Environment Variable Source: https://github.com/vkryukov/openai_responses/blob/main/README.md Configure your OpenAI API key by exporting it as an environment variable. ```bash export OPENAI_API_KEY="your-api-key" ``` -------------------------------- ### Run Conversation with Function Calling Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `run/2` to execute conversations with automatic function calling. Ensure API key is configured. ```elixir OpenAI.Responses.run(conversation, tools) ``` -------------------------------- ### Configure function calling loops in Elixir Source: https://github.com/vkryukov/openai_responses/blob/main/CHANGELOG.md Include the model in the options list when using run/2 for function calling loops. ```elixir OpenAI.Responses.run([input: "question", tools: [tool], model: "gpt-4.1-mini"], functions) ``` -------------------------------- ### Execute Function Calls Source: https://github.com/vkryukov/openai_responses/blob/main/CHANGELOG.md Execute function calls and append outputs to the prompt chain. ```elixir functions = %{"get_time" => fn %{} -> DateTime.utc_now() |> to_string() end} opts = Prompt.add_function_outputs(%{input: []}, response.function_calls, functions) final = OpenAI.Responses.create!(response, opts) ``` -------------------------------- ### Create AI Response with Reasoning Models Source: https://context7.com/vkryukov/openai_responses/llms.txt Utilize reasoning models by specifying the `reasoning` option with an `effort` level. This is useful for complex problem-solving tasks. ```elixir alias OpenAI.Responses # Using reasoning models {:ok, response} = Responses.create( input: "Solve this logic puzzle: ...", model: "gpt-5-mini", reasoning: %{effort: "high"} ) ``` -------------------------------- ### Build JSON Schema for Structured Outputs Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `build_output/1` to convert Elixir syntax into JSON Schema format for structured outputs. ```elixir OpenAI.Responses.Schema.build_output(elixir_syntax) ``` -------------------------------- ### OpenAI.Responses.create/2 Source: https://context7.com/vkryukov/openai_responses/llms.txt Creates a follow-up response based on a previous response, maintaining conversation context. Automatically includes the previous response ID and preserves LLM options (model, reasoning.effort, text.verbosity) unless explicitly overridden. ```APIDOC ## OpenAI.Responses.create/2 ### Description Creates a follow-up response based on a previous response, maintaining conversation context. Automatically includes the previous response ID and preserves LLM options (model, reasoning.effort, text.verbosity) unless explicitly overridden. Schema/format settings are not preserved between calls. ### Method POST ### Endpoint /v1/chat/completions (inferred) ### Parameters #### Path Parameters - **previous_response** (OpenAI.Responses.Response) - Required - The previous response object to continue the conversation from. #### Request Body - **input** (string | list) - Required - The new prompt or message in the conversation. - **model** (string) - Optional - Overrides the model used in the previous response. - **reasoning** (map) - Optional - Overrides the reasoning parameters from the previous response. ### Request Example ```elixir alias OpenAI.Responses # Initial question first = Responses.create!( input: "What is Elixir?", model: "gpt-4.1-mini" ) IO.puts(first.text) # Follow-up maintains context followup = Responses.create!(first, input: "What are its main features?") IO.puts(followup.text) # Follow-up with reasoning models (settings preserved) first = Responses.create!( input: "Complex math problem", model: "gpt-5-mini", reasoning: %{effort: "high"} ) # Inherits gpt-5-mini and high reasoning effort second = Responses.create!(first, input: "Can you verify that answer?") # Override preserved settings third = Responses.create!(first, input: "Simplify the explanation", reasoning: %{effort: "low"} ) ``` ### Response #### Success Response (200) - **text** (string) - The generated text response. - **json** (map | nil) - Parsed JSON if the response is structured. - **function_calls** (list) - Extracted function calls. - **cost** (map) - Cost information including input, output, and total costs. - **raw** (map) - The raw API response body. #### Response Example ```elixir %OpenAI.Responses.Response{ text: "Elixir's main features include:\n 1. Concurrency via lightweight processes\n 2. Pattern matching\n 3. Fault tolerance through supervision trees...", cost: %{input_cost: #Decimal<...>, output_cost: #Decimal<...>, total_cost: #Decimal<...>} } ``` ``` -------------------------------- ### List Available Models Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Retrieve a list of available models, optionally filtered by a string pattern. ```elixir # List all models models = Responses.list_models() # Filter by pattern gpt_models = Responses.list_models("gpt") ``` -------------------------------- ### OpenAI.Responses.Schema.build_function/3 Source: https://context7.com/vkryukov/openai_responses/llms.txt Builds a function calling tool schema for use with OpenAI's function calling feature. ```APIDOC ## OpenAI.Responses.Schema.build_function/3 ### Description Builds a function calling tool schema for use with OpenAI's function calling feature. Takes a function name, description, and parameter definitions. ### Parameters - **name** (string) - Required - The name of the function. - **description** (string) - Required - A description of what the function does. - **parameters** (map) - Required - Parameter definitions in the same format as build_output/1. ### Response - **Tool Schema** (map) - Returns a map containing the function name, type, description, and parameter specifications. ``` -------------------------------- ### Calculate OpenAI API costs manually Source: https://context7.com/vkryukov/openai_responses/llms.txt Use the Decimal library to calculate costs based on token counts and model pricing. ```elixir input_tokens = 1000 output_tokens = 500 pricing = Pricing.get_pricing("gpt-4.1-mini") input_cost = Decimal.mult(Decimal.div(Decimal.new(input_tokens), 1_000_000), pricing.input) output_cost = Decimal.mult(Decimal.div(Decimal.new(output_tokens), 1_000_000), pricing.output) total = Decimal.add(input_cost, output_cost) IO.puts("Estimated cost: $#{total}") ``` -------------------------------- ### Create Follow-up Response with Context Source: https://context7.com/vkryukov/openai_responses/llms.txt Use `Responses.create/2` to generate a follow-up response that maintains conversation context by automatically including the previous response ID. ```elixir alias OpenAI.Responses # Initial question first = Responses.create!( input: "What is Elixir?", model: "gpt-4.1-mini" ) IO.puts(first.text) # => "Elixir is a functional programming language..." # Follow-up maintains context followup = Responses.create!(first, input: "What are its main features?") IO.puts(followup.text) # => "Elixir's main features include: # 1. Concurrency via lightweight processes # 2. Pattern matching # 3. Fault tolerance through supervision trees..." ``` -------------------------------- ### Create AI Responses Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Generate responses using create/1 or create!/1, supporting simple text, structured output schemas, and streaming callbacks. ```elixir # Simple text input {:ok, response} = Responses.create(input: "Write a haiku", model: "gpt-4.1-mini") response = Responses.create!(input: "Write a haiku", model: "gpt-4.1-mini") # With options {:ok, response} = Responses.create( input: "Explain quantum physics", model: "gpt-4.1-mini", temperature: 0.7, max_tokens: 500 ) # With structured output response = Responses.create!( input: "List 3 facts", model: "gpt-4.1-mini", schema: %{facts: {:array, :string}} ) response.parsed # => %{"facts" => ["fact1", "fact2", "fact3"]} # With streaming callback Responses.create( input: "Tell a story", model: "gpt-4.1-mini", stream: fn {:ok, %{event: "response.output_text.delta", data: %{"delta" => text}}} -> IO.write(text) :ok _ -> :ok end ) ``` -------------------------------- ### Add Dependency to mix.exs Source: https://github.com/vkryukov/openai_responses/blob/main/README.md Add the openai_responses library to your project's dependencies in the mix.exs file. ```elixir def deps do [ {:openai_responses, "~> 0.8.4"} ] end ``` -------------------------------- ### Run Conversation with Function Calling (Raises on Error) Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `run!/2` for conversations with automatic function calling that raises an exception on error. Ensure API key is configured. ```elixir OpenAI.Responses.run!(conversation, tools) ``` -------------------------------- ### POST /chat/completions Source: https://context7.com/vkryukov/openai_responses/llms.txt Creates a chat completion, supporting both new conversations and continuing existing ones with context. ```APIDOC ## POST /chat/completions ### Description Initiates or continues a chat conversation. Supports streaming responses via the `stream` option. ### Method POST ### Endpoint OpenAI.Responses.create!/1 or OpenAI.Responses.create!/2 ### Parameters #### Request Body - **input** (string) - Required - The user prompt or message. - **model** (string) - Optional - The model ID to use (e.g., "gpt-4.1-mini"). - **stream** (function) - Optional - A callback function for handling streaming deltas. ### Response #### Success Response (200) - **response** (map) - The completion response object containing the AI's reply. ``` -------------------------------- ### Build Function Schema with OpenAI.Responses.Schema.build_function/3 Source: https://context7.com/vkryukov/openai_responses/llms.txt Creates a JSON Schema for OpenAI's function calling feature. Define function name, description, and parameters. Use this to enable the model to call your custom functions. ```elixir alias OpenAI.Responses alias OpenAI.Responses.Schema # Simple function with one parameter weather_tool = Schema.build_function( "get_weather", "Get current temperature for a given location", %{location: {:string, description: "City and country, e.g., Paris, France"}} ) ``` ```elixir # Function with multiple parameters search_tool = Schema.build_function( "search_products", "Search for products in the catalog", %{ query: {:string, description: "Search query"}, category: {:string, enum: ["electronics", "clothing", "books"]}, max_price: {:number, description: "Maximum price filter"}, in_stock_only: :boolean } ) ``` ```elixir # Use with create/1 response = Responses.create!( input: "What's the weather in Tokyo?", tools: [weather_tool], model: "gpt-4.1-mini" ) IO.inspect(response.function_calls) ``` -------------------------------- ### OpenAI.Responses.Schema.build_output/1 Source: https://context7.com/vkryukov/openai_responses/llms.txt Converts Elixir syntax into JSON Schema format for structured outputs, supporting various types, constraints, and nested structures. ```APIDOC ## OpenAI.Responses.Schema.build_output/1 ### Description Converts Elixir syntax to JSON Schema format for structured outputs. Accepts maps or keyword lists where keys are field names and values are type specifications. ### Parameters - **schema** (map/keyword list) - Required - A definition of the desired output structure using Elixir types (e.g., :string, :integer, :boolean, :number) or complex types (arrays, objects, unions). ### Response - **JSON Schema** (map) - Returns a valid JSON Schema structure. ``` -------------------------------- ### Override Preserved Settings in Follow-up Source: https://context7.com/vkryukov/openai_responses/llms.txt Demonstrates how to override preserved settings, such as `reasoning.effort`, when creating a follow-up response using `create/2`. ```elixir alias OpenAI.Responses # Override preserved settings third = Responses.create!(first, input: "Simplify the explanation", reasoning: %{effort: "low"} ) ``` -------------------------------- ### Low-Level API Request Function Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `request/1` for making low-level API requests. ```elixir OpenAI.Responses.request(params) ``` -------------------------------- ### Update OpenAIResponses function calls Source: https://github.com/vkryukov/openai_responses/blob/main/CHANGELOG.md Replaces positional parameters with keyword lists for create, stream, and parse functions. ```elixir OpenAIResponses.create(model: "model", prompt: "prompt") ``` -------------------------------- ### Build JSON Schema Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Converts Elixir syntax to JSON Schema for structured outputs. ```elixir # Simple types schema = Schema.build_output(%{ name: :string, age: :integer, active: :boolean }) # With constraints schema = Schema.build_output(%{ email: {:string, format: "email"}, username: {:string, pattern: "^[a-z]+$", min_length: 3}, score: {:number, minimum: 0, maximum: 100} }) # Arrays and nested objects schema = Schema.build_output(%{ tags: {:array, :string}, addresses: {:array, %{ street: :string, city: :string, country: :string }} }) # Union types schema = Schema.build_output(%{ result: {:anyOf, [:string, :number, :boolean]} }) # Arrays at the root level (automatic wrapping) {:ok, response} = Responses.create( input: "List 3 US presidents", schema: {:array, %{ name: :string, birth_year: :integer, facts: {:array, :string} }}, model: "gpt-4.1-mini" ) # response.parsed is a list (the library wraps/unpacks automatically) ``` -------------------------------- ### Perform Low-Level API Requests Source: https://github.com/vkryukov/openai_responses/blob/main/usage-rules.md Execute custom API requests using the request/1 function. ```elixir {:ok, response} = Responses.request( url: "/models", method: :get ) ``` -------------------------------- ### Execute Function Calls from Response Source: https://github.com/vkryukov/openai_responses/blob/main/CLAUDE.md Use `call_functions/2` to manually execute function calls identified in a response. ```elixir OpenAI.Responses.call_functions(response, functions) ```