Braintrust.Function (Braintrust v0.1.0)

View Source

Manage Braintrust functions.

Functions are versatile components that can serve as:

  • Tools: General purpose code invoked by LLMs for function calling
  • Scorers: Functions for scoring LLM output quality (0-1 range)
  • Prompts: Versioned prompt templates (also accessible via Braintrust.Prompt)

Examples

# List all functions
{:ok, functions} = Braintrust.Function.list()

# List scorers for a specific project
{:ok, scorers} = Braintrust.Function.list(
  project_id: "proj_xxx",
  function_type: "scorer"
)

# Get a function by ID
{:ok, func} = Braintrust.Function.get("func_xxx")

# Create a code-based scorer
{:ok, scorer} = Braintrust.Function.create(%{
  project_id: "proj_xxx",
  name: "relevance-scorer",
  slug: "relevance-scorer-v1",
  function_type: "scorer",
  function_data: %{
    type: "code",
    data: %{
      runtime: "node",
      code: "export default async function({ input, output, expected }) { ... }"
    }
  }
})

# Update a function
{:ok, func} = Braintrust.Function.update("func_xxx", %{
  description: "Updated description"
})

# Delete a function
{:ok, func} = Braintrust.Function.delete("func_xxx")

Function Types

TypeDescriptionUse Case
toolGeneral purpose codeFunction calling, API integrations
scorerQuality scoring (0-1)Evaluation metrics
promptVersioned promptsAlso via Braintrust.Prompt

Scorer Subtypes

Scorers can be implemented in different ways:

  • Code-based: TypeScript/Python scorers (fast, deterministic)
  • LLM-as-a-judge: Uses LLM to evaluate output (nuanced, subjective)
  • Pre-built autoevals: From autoevals library (ExactMatch, Levenshtein, etc.)

Pagination

The list/1 function supports cursor-based pagination:

# Get all functions as a list
{:ok, functions} = Braintrust.Function.list()

# Stream through functions lazily
Braintrust.Function.stream()
|> Stream.take(100)
|> Enum.to_list()

Summary

Functions

Creates a new function.

Deletes a function.

Gets a function by ID.

Lists all functions.

Returns a Stream that lazily paginates through all functions.

Types

t()

@type t() :: %Braintrust.Function{
  created_at: DateTime.t() | nil,
  deleted_at: DateTime.t() | nil,
  description: String.t() | nil,
  function_data: map() | nil,
  function_type: String.t() | nil,
  id: String.t(),
  metadata: map() | nil,
  name: String.t(),
  org_id: String.t() | nil,
  origin: map() | nil,
  project_id: String.t() | nil,
  slug: String.t() | nil,
  user_id: String.t() | nil
}

Functions

create(params, opts \\ [])

@spec create(
  map(),
  keyword()
) :: {:ok, t()} | {:error, Braintrust.Error.t()}

Creates a new function.

If a function with the same name/slug already exists within the project, returns the existing function unmodified (idempotent behavior).

Parameters

  • :project_id - Project ID (required)
  • :name - Function name (required)
  • :slug - Unique identifier for stable references (optional)
  • :description - Function description (optional)
  • :function_type - Type: "tool", "scorer", or "prompt" (optional)
  • :function_data - Function implementation data (optional)
  • :origin - Source tracking information (optional)
  • :metadata - Custom metadata map (optional)

Options

  • :api_key - Override API key for this request
  • :base_url - Override base URL for this request

Examples

# Create a code-based scorer
iex> {:ok, scorer} = Braintrust.Function.create(%{
...>   project_id: "proj_123",
...>   name: "relevance-scorer",
...>   slug: "relevance-scorer-v1",
...>   function_type: "scorer",
...>   function_data: %{
...>     type: "code",
...>     data: %{runtime: "node", code: "..."}
...>   }
...> })
iex> scorer.function_type
"scorer"

delete(function_id, opts \\ [])

@spec delete(
  String.t(),
  keyword()
) :: {:ok, t()} | {:error, Braintrust.Error.t()}

Deletes a function.

This is a soft delete - the function's deleted_at field will be set.

Options

  • :api_key - Override API key for this request
  • :base_url - Override base URL for this request

Examples

iex> {:ok, func} = Braintrust.Function.delete("func_123")
iex> func.deleted_at != nil
true

get(function_id, opts \\ [])

@spec get(
  String.t(),
  keyword()
) :: {:ok, t()} | {:error, Braintrust.Error.t()}

Gets a function by ID.

Options

  • :version - Specific version identifier to retrieve
  • :xact_id - Transaction ID for exact version
  • :api_key - Override API key for this request
  • :base_url - Override base URL for this request

Examples

iex> {:ok, func} = Braintrust.Function.get("func_123")
iex> func.name
"my-scorer"

# Get a specific version
iex> {:ok, func} = Braintrust.Function.get("func_123", version: "v2")

list(opts \\ [])

@spec list(keyword()) :: {:ok, [t()]} | {:error, Braintrust.Error.t()}

Lists all functions.

Returns all functions as a list. For large result sets, consider using stream/1 for memory-efficient lazy loading.

Options

  • :limit - Number of results per page (default: 100)
  • :starting_after - Cursor for pagination
  • :project_id - Filter by project ID
  • :function_name - Filter by function name
  • :function_type - Filter by type: "tool", "scorer", or "prompt"
  • :slug - Filter by function slug
  • :org_name - Filter by organization name
  • :ids - Filter by specific function IDs (list of strings)
  • :api_key - Override API key for this request
  • :base_url - Override base URL for this request

Examples

iex> {:ok, functions} = Braintrust.Function.list(limit: 10)
iex> is_list(functions)
true

stream(opts \\ [])

@spec stream(keyword()) :: Enumerable.t()

Returns a Stream that lazily paginates through all functions.

This is memory-efficient for large result sets as it only fetches pages as items are consumed.

Options

Same as list/1.

Examples

# Take first 50 functions
Braintrust.Function.stream(limit: 25)
|> Stream.take(50)
|> Enum.to_list()

# Process all functions without loading all into memory
Braintrust.Function.stream()
|> Stream.each(&process_function/1)
|> Stream.run()

update(function_id, params, opts \\ [])

@spec update(String.t(), map(), keyword()) ::
  {:ok, t()} | {:error, Braintrust.Error.t()}

Updates a function.

Uses PATCH semantics - only provided fields are updated. Updating a function may create a new version; previous versions remain accessible via version/xact_id.

Parameters

  • :name - New function name
  • :slug - New slug identifier
  • :description - New description
  • :function_type - New function type
  • :function_data - Updated implementation data
  • :metadata - Metadata to merge (deep merge for nested objects)

Options

  • :api_key - Override API key for this request
  • :base_url - Override base URL for this request

Examples

iex> {:ok, func} = Braintrust.Function.update("func_123", %{
...>   description: "Updated description"
...> })
iex> func.description
"Updated description"