pig
A Gleam library for building and orchestrating AI agents on the BEAM.
pig combines a provider-neutral agent loop with OTP isolation, typed tools,
skills, hooks, durable conversation history, and structured telemetry.
Installation
gleam add pig
Basic usage
import pig
import pig/openai
import pig_protocol/message
pub fn main() {
let provider = openai.provider("your-api-key", "gpt-4o-mini")
let config =
pig.new(provider)
|> pig.with_model("gpt-4o-mini")
|> pig.with_system_prompt("You are a helpful assistant.")
let assert Ok(agent) = pig.start(config)
let assert Ok(message.Assistant(content:, ..)) =
pig.run(agent, "Explain OTP in one sentence.")
echo content
pig.stop(agent)
}
pig/openai supports OpenAI-compatible endpoints through
provider_with_base_url, so the same runtime can be used with compatible local
or hosted providers.
Thinking levels
Why this previously appeared supported
Pig already had a Thinking field on assistant messages and Responses requests
included reasoning.encrypted_content. Both are response/history features:
neither selected how much reasoning the model should perform. There was no
request configuration for reasoning_effort or reasoning.effort, so users
were correct that thinking levels could not be set.
Configuration
Inference settings belong to the agent, not to an individual run. Configure them while building the agent:
import pig_protocol/thinking
let provider = openai.provider("your-api-key", "gpt-5")
let config =
pig.new(provider)
|> pig.with_thinking_level(thinking.Medium)
Available levels are Off, Minimal, Low, Medium, High, XHigh, and
Max. The setting is included in every inference request. Use
pig.set_thinking_level(agent, level) to change it durably mid-session, or
pig.reset_inference_settings(agent) to restore provider-default behavior; session
restoration reapplies the saved setting. Off is explicit: it asks the
provider not to use reasoning, while the unset/default setting uses the
provider's default. Runtime-only agents update their in-memory settings and
history; configure a SessionStore to make setting and conversation changes
durable across restarts.
A provider default is still useful when demonstrating a provider outside an agent or when an agent has no explicit setting:
let provider =
openai.provider("your-api-key", "gpt-5")
|> openai.with_default_thinking_level(thinking.Medium)
Use responses_provider for OpenAI's Responses API. It uses the same
one-argument Provider(InferenceRequest) interface. Responses requests send
reasoning.effort; enabled levels also request an automatic provider-generated
reasoning summary. System messages are mapped to Responses instructions.
Pig does not maintain a model capability catalog, clamp levels, or promise that
a model supports a selected level; unsupported values are reported by the
provider. Setting changes and inference start/stop events are observable through
Pig's normal events and session persistence.
Tools
A tool combines a JSON Schema definition with a handler. The agent executes tool calls and feeds their results back to the provider automatically.
import gleam/dynamic/decode
import gleam/json
import jscheam/schema
import pig/tool
import pig_protocol/tool_definition
fn add_tool() -> tool.Tool {
tool.Tool(
definition: tool_definition.ToolDefinition(
name: "add",
description: "Add two integers.",
parameters: schema.object([
schema.prop("a", schema.integer()),
schema.prop("b", schema.integer()),
]),
),
handler: fn(context, arguments) {
// Context is library-owned and identifies this invocation.
let _ = tool.call_id(context)
let _ = tool.tool_name(context)
let decoder = {
use a <- decode.field("a", decode.int)
use b <- decode.field("b", decode.int)
decode.success(a + b)
}
case decode.run(arguments, decoder) {
Ok(total) -> Ok(json.int(total))
Error(_) -> Error(tool.ToolError("Expected integer fields a and b"))
}
},
)
}
Register it while building the configuration:
let config =
pig.new(provider)
|> pig.with_tool(add_tool())
Timeouts and continued runs
Fresh runs use a 120-second default collector deadline. When a deadline is reached, Pig actively cancels in-flight provider and tool work before returning. The OpenAI HTTP timeout is configured on the provider/transport separately; it is not a generic provider idle cap. Explicit and non-panicking variants are available:
pig.run_with_timeout(agent, "Hello", 30_000)
pig.try_run_with_timeout(agent, "Hello", 30_000)
pig.try_run_continue_with_timeout(agent, 30_000)
The try_* functions return an outer Error(Nil) when the runtime is unavailable
or the collector deadline is reached; provider and run errors remain in the inner
result. A timeout actively cancels in-flight provider or tool work before
returning.
Continued runs resume from preloaded history without adding another user message, supporting checkpoint-and-resume workflows.
Features
- Provider-neutral runtime — providers implement one typed function.
- OTP agent isolation — each running agent owns its state in an actor.
- Parallel tool execution — independent tool calls run concurrently.
- Skills and hooks — compose reusable capabilities and lifecycle policy.
- Durable history with
SessionStore— preload and continue checkpointed conversations. - Observability — structured
:telemetry, terminal output, and JSONL sessions. - Workspace tools — optional SQLite-backed key/value and virtual-file storage.
- Supervision — child specifications for OTP supervision trees.
Shared messages, errors, stop reasons, and provider codecs live in
pig_protocol.
Examples
The examples directory includes:
- code review agents
- a knowledge notebook
- URL summarization
- scale testing
- a client/server chat application
Each example is a standalone Gleam project.
Development
From this package directory:
gleam test
gleam build --warnings-as-errors
From the repository root, run all package tests with:
mise run test
Live integration tests are disabled by default and require provider credentials:
mise run test-integration
License
Apache-2.0