Starflow ✨

Package Version Hex Docs

Starflow is a Gleam library for building stateful chains of LLM interactions. It provides a simple, type-safe way to create flows that transform state into prompts, interact with language models, and parse responses back into state.

This library currently only supports Claude’s send_message API

Installation

gleam add starflow

Quick Start

Here’s a simple example that asks Claude to tell a joke:

import gleam/io
import gleam/result
import gleam/string
import envoy

import starflow
import starflow/api_key
import starflow/model
import starflow/providers
import starflow/state

pub fn main() {
  let result = {
    // Setup API key and model
    use env_api_key <- result.try(
      envoy.get("ANTHROPIC_API_KEY")
      |> result.replace_error("api key not set!"),
    )
    let api_key = api_key.new(providers.Anthropic, env_api_key)
    let model = model.new(api_key)

    // Define prompt transformer
    let prompt = fn(state) {
      [state.TextContent("Tell me a joke.")]
    }

    // Create and execute flow
    let flow =
      starflow.new(model)
      |> starflow.with_prompt(prompt)

    let state = state.new(Nil)
    starflow.invoke(state, flow)
  }

  case result {
    Ok(state) -> io.println(string.inspect(state))
    Error(err) -> io.println_error(err)
  }
}

Key Features

State Management

Transformers

Provider Support

Examples

See the test directory for examples!

Common Patterns

Simple Question-Answer

let flow =
  starflow.new(model)
  |> starflow.with_prompt(fn(question) {
    [state.TextContent(question)]
  })

starflow.invoke(state.new("What is 2+2?"), flow)

Stateful Interactions

// Define custom state type
pub type GameState {
  GameState(target: Int, guesses: List(Int))
}

// Create game flow
let game_flow =
  starflow.new(model)
  |> starflow.with_prompt(fn(state: GameState) {
    [state.TextContent("Guess a number between 1 and " <> int.to_string(state.target))]
  })
  |> starflow.with_parser(fn(state, resp) {
    // Parse response and update game state
    let guess = parse_number(resp)
    state.State(..state, any: GameState(..state.any, guesses: [guess, ..state.any.guesses]))
  })

Response Parsing

let flow =
  starflow.new(model)
  |> starflow.with_parser(fn(state, resp) {
    case resp.content {
      [state.TextContent(text)] -> {
        // Process response text
        state.State(..state, any: process_text(text))
      }
      _ -> state
    }
  })

Development

gleam run   # Run the project

Coming Soon

Documentation

For detailed documentation visit hexdocs.pm/starflow.

Search Document