UniLM.jl

A unified Julia interface for large language models.

CI codecov Aqua QA Stable Dev

What is UniLM.jl?

UniLM.jl provides a Julian, type-safe interface to LLM providers via the OpenAI-compatible API standard — covering the Chat Completions API, the Responses API, Image Generation, Embeddings, and MCP. Works with OpenAI, Azure, Gemini, Mistral, DeepSeek, Ollama, vLLM, LM Studio, and any OpenAI-compatible provider.

Key Features

  • 🗣️ Chat Completions — stateful conversations with automatic history management
  • 🔮 Responses API — OpenAI's newer API with built-in tools, multi-turn chaining, and reasoning
  • 🖼️ Image Generation — create images from text prompts with gpt-image-1.5
  • 🔧 Tool/Function Calling — first-class support for function tools in both APIs, with automated tool_loop
  • 🔌 MCP (Model Context Protocol) — connect to MCP servers or build your own, with seamless tool loop integration
  • 📊 Embeddings — text embedding generation
  • 🌊 Streaming — real-time token streaming with do-block syntax
  • 📐 Structured Output — JSON Schema–constrained generation
  • ☁️ Multi-Backend — OpenAI, Azure, Gemini, DeepSeek, Ollama, Mistral, vLLM, LM Studio
  • Type Safety — invalid states are unrepresentable; tested with JET.jl and Aqua.jl

Two APIs, One Package

FeatureChat CompletionsResponses API
Stateful conversationsChat + push!previous_response_id
System promptMessage(Val(:system), ...)instructions kwarg
Tool callingGPTTool / GPTToolCallFunctionTool / function_tool
Web searchWebSearchTool
File searchFileSearchTool
Streamingstream=true + callbackdo-block syntax
Structured outputResponseFormatTextConfig / json_schema_format
Reasoning (O-series)Reasoning
Automated tool looptool_loop!tool_loop
MCP integrationmcp_tools bridgeMCPTool / mcp_tool

Installation

using Pkg
Pkg.add(url="https://github.com/algunion/UniLM.jl")

Or in the Pkg REPL:

pkg> add https://github.com/algunion/UniLM.jl

Quick Example

Building requests — these construct objects locally without calling the API:

using UniLM
using JSON

# Chat Completions request
chat = Chat(model="gpt-5.2")
push!(chat, Message(Val(:system), "You are a Julia expert."))
push!(chat, Message(Val(:user), "Explain multiple dispatch in one sentence."))
println("Chat has ", length(chat), " messages, model: ", chat.model)
println("Request body preview:")
println(JSON.json(chat))
Chat has 2 messages, model: gpt-5.2
Request body preview:
{"messages":[{"role":"system","content":"You are a Julia expert."},{"role":"user","content":"Explain multiple dispatch in one sentence."}],"model":"gpt-5.2"}
# Responses API request
r = Respond(input="What makes Julia special?")
println("Respond model: ", r.model)
println(JSON.json(r))
Respond model: gpt-5.2
{"model":"gpt-5.2","input":"What makes Julia special?"}
# Image Generation request
ig = ImageGeneration(prompt="A watercolor Julia logo", quality="high")
println("Image model: ", ig.model)
println(JSON.json(ig))
Image model:
{"quality":"high","prompt":"A watercolor Julia logo","model":"gpt-image-1.5"}

With a valid API key, actual API calls return structured results:

Responses API (recommended for new code):

result = respond("Explain Julia's multiple dispatch in 2-3 sentences.")
if result isa ResponseSuccess
    println(output_text(result))
else
    println("Request failed — ", output_text(result))
end
Julia’s multiple dispatch means a function can have many method definitions, and Julia chooses which one to run based on the types of *all* arguments, not just the first. This lets you write generic code while still getting specialized, efficient behavior for different combinations of input types.

Chat Completions:

chat = Chat(model="gpt-4o-mini")
push!(chat, Message(Val(:system), "You are a concise Julia programming tutor."))
push!(chat, Message(Val(:user), "What is multiple dispatch? Answer in 2-3 sentences."))
result = chatrequest!(chat)
if result isa LLMSuccess
    println(result.message.content)
else
    println("Request failed — see result for details")
end
Multiple dispatch is a programming paradigm where the method that gets executed is determined by the types of all arguments passed to a function, rather than just the first one, as in single dispatch. This allows for more flexible and expressive code, enabling developers to define different function behaviors based on combinations of argument types. Julia is known for its built-in support for multiple dispatch, making it a key feature of the language.

Image Generation:

result = generate_image(
    "A watercolor painting of a friendly robot reading a Julia programming book",
    size="1024x1024", quality="medium"
)
println("Success: ", result isa ImageSuccess)
if result isa ImageSuccess
    save_image(image_data(result)[1], joinpath(@__DIR__, "assets", "generated_robot.png"))
    println("Saved to assets/generated_robot.png")
else
    println("Image generation failed — see result for details")
end
Success: true
Saved to assets/generated_robot.png

Generated robot reading Julia

Next Steps