Skip to main content

Serapeum OpenAI Provider

OpenAI integration for the Serapeum LLM framework

The serapeum-openai package provides complete OpenAI backend support for Serapeum, with two main classes covering both OpenAI APIs:

  • Completions: Chat Completions API for GPT-4o, GPT-4, GPT-3.5, and instruct models
  • Responses: Responses API for reasoning models (o3, o4-mini) with built-in tools and stateful conversations

Both classes implement the serapeum.core.llms.FunctionCallingLLM interface, making them compatible with all Serapeum orchestrators and tools.

Features

  • Chat & Completion: Sync/async support with streaming
  • Tool Calling: Function calling with automatic schema generation
  • Structured Outputs: Native JSON-schema support on compatible models, with automatic fallback to function-calling approach
  • Responses API: Built-in tools (file search, web search, code interpreter), reasoning-effort control, stateful conversations
  • Model Registry: YAML-based model metadata with automatic capability detection (context windows, JSON-schema support, function calling)
  • Retry Logic: OpenAI-specific exception classification with automatic retries for transient errors
  • Token Counting: Tiktoken integration for accurate token counting

Installation

From Source

cd libs/providers/openai
uv sync --active

From PyPI (when published)

pip install serapeum-openai

Prerequisites

You need an OpenAI API key. Set it as an environment variable:

export OPENAI_API_KEY="sk-..."

Or pass it directly when creating the LLM instance.

Quick Start

Chat Completions API

from serapeum.openai import Completions
from serapeum.core.llms import Message, MessageRole

llm = Completions(model="gpt-4o", temperature=0.7)

messages = [
    Message(role=MessageRole.USER, content="Explain quantum computing in one sentence.")
]
response = llm.chat(messages)
print(response.message.content)

Responses API

from serapeum.openai import Responses
from serapeum.core.llms import Message, MessageRole

llm = Responses(model="o3", reasoning_options={"effort": "medium"})

messages = [
    Message(role=MessageRole.USER, content="Solve this step by step: what is 2^10?")
]
response = llm.chat(messages)
print(response.message.content)

LLM Features

Streaming

from serapeum.openai import Completions
from serapeum.core.llms import Message, MessageRole

llm = Completions(model="gpt-4o")

messages = [Message(role=MessageRole.USER, content="Write a haiku about coding.")]

for chunk in llm.chat(messages, stream=True):
    print(chunk.delta, end="", flush=True)
print()

Async Operations

import asyncio
from serapeum.openai import Completions
from serapeum.core.llms import Message, MessageRole

llm = Completions(model="gpt-4o")

async def main():
    response = await llm.achat([
        Message(role=MessageRole.USER, content="Hello!")
    ])
    print(response.message.content)

    # Async streaming
    async for chunk in await llm.achat(
        [Message(role=MessageRole.USER, content="Count to 5.")],
        stream=True,
    ):
        print(chunk.delta, end="", flush=True)
    print()

asyncio.run(main())

Structured Outputs

Extract structured data using Pydantic models. On compatible models (GPT-4o and later), native JSON-schema mode is used automatically:

from pydantic import BaseModel, Field
from serapeum.openai import Completions
from serapeum.core.prompts import PromptTemplate


class Person(BaseModel):
    name: str = Field(description="Person's full name")
    age: int = Field(description="Person's age in years")
    occupation: str = Field(description="Person's job title")


llm = Completions(model="gpt-4o")

person = llm.parse(
    schema=Person,
    prompt=PromptTemplate("Extract person info from: {text}"),
    text="John Doe is a 32-year-old software engineer at Tech Corp.",
)

print(f"{person.name}, {person.age}, works as {person.occupation}")

Tool Calling

from serapeum.openai import Completions
from serapeum.core.tools import CallableTool
from serapeum.core.llms import Message, MessageRole


def get_weather(location: str, unit: str = "celsius") -> str:
    """Get current weather for a location."""
    return f"The weather in {location} is 22 {unit} and sunny."


llm = Completions(model="gpt-4o")

weather_tool = CallableTool.from_function(get_weather)
messages = [Message(role=MessageRole.USER, content="What's the weather in Paris?")]

response = llm.generate_tool_calls(
    tools=[weather_tool],
    chat_history=messages,
)

tool_calls = llm.get_tool_calls_from_response(
    response, error_on_no_tool_call=False
)
if tool_calls:
    for call in tool_calls:
        print(f"Tool: {call.tool_name}, Args: {call.tool_kwargs}")

Responses API with Built-in Tools

from serapeum.openai import Responses
from serapeum.core.llms import Message, MessageRole

llm = Responses(
    model="o3",
    reasoning_options={"effort": "medium"},
    built_in_tools=[{"type": "web_search_preview"}],
)

messages = [
    Message(role=MessageRole.USER, content="What happened in tech news today?")
]
response = llm.chat(messages)
print(response.message.content)

Configuration

Completions (Chat Completions API)

from serapeum.openai import Completions

llm = Completions(
    model="gpt-4o",                       # Required: model name
    temperature=0.7,                       # Sampling temperature (0.0-2.0)
    max_tokens=1024,                       # Max tokens to generate
    logprobs=None,                         # Return log probabilities (None/True/False)
    top_logprobs=0,                        # Number of top logprobs per token (0-20)
    strict=False,                          # Strict JSON-schema mode
    reasoning_effort=None,                 # For O1 models: "low"/"medium"/"high"/etc.
    modalities=None,                       # Output modalities, e.g. ["text", "audio"]
    audio_config=None,                     # Audio output config (voice, format, etc.)
    api_key="sk-...",                      # API key (or OPENAI_API_KEY env)
    api_base=None,                         # Custom API base URL
    timeout=60.0,                          # Request timeout in seconds
    default_headers=None,                  # Additional HTTP headers
    additional_kwargs={},                  # Extra API parameters
)

Responses (Responses API)

from serapeum.openai import Responses

llm = Responses(
    model="o3",                            # Required: model name
    temperature=0.1,                       # Sampling temperature (omitted when reasoning_options set)
    top_p=1.0,                             # Nucleus sampling (omitted when reasoning_options set)
    max_output_tokens=None,                # Max output tokens
    reasoning_options={"effort": "medium"},# Reasoning effort control for O1 models
    include=None,                          # Additional output fields, e.g. ["reasoning.encrypted_content"]
    instructions=None,                     # System-level instructions
    built_in_tools=None,                   # Built-in tools list
    store=False,                           # Store responses server-side
    track_previous_responses=False,        # Stateful conversation tracking (forces store=True)
    truncation="disabled",                 # Input truncation strategy
    user=None,                             # End-user identifier for abuse monitoring
    call_metadata=None,                    # Metadata forwarded in the "metadata" field
    strict=False,                          # Strict JSON-schema mode
    context_window=None,                   # Manual context-window override in tokens
    api_key="sk-...",                      # API key (or OPENAI_API_KEY env)
    api_base=None,                         # Custom API base URL
    timeout=60.0,                          # Request timeout
)

Package Layout

src/serapeum/openai/
├── __init__.py              # Lazy imports (Completions, Responses)
├── llm/
│   ├── chat_completions.py  # Completions class (Chat Completions API)
│   ├── responses.py         # Responses class (Responses API)
│   └── base/
│       ├── client.py        # SDK client lifecycle and credentials
│       ├── model.py         # Model metadata and tokenizer
│       └── structured.py    # Native JSON-schema structured output
├── data/
│   ├── models.py            # Model query functions and constants
│   └── models.yaml          # Model registry (context windows, capabilities)
├── parsers/
│   ├── chat_parsers.py      # Chat completion response parsers
│   ├── formatters.py        # Message format converters
│   └── response_parsers.py  # Responses API output parsers
├── retry.py                 # OpenAI-specific retry logic
└── utils.py                 # Credential resolution, constants

Testing

# All tests (from repo root)
python -m pytest libs/providers/openai/tests

# Skip end-to-end tests (don't require API key)
python -m pytest libs/providers/openai/tests -m "not e2e"

# Only unit tests
python -m pytest libs/providers/openai/tests -m unit

Note: End-to-end tests require a valid OPENAI_API_KEY environment variable.

Links

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

serapeum_openai-0.1.0.tar.gz (65.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

serapeum_openai-0.1.0-py3-none-any.whl (72.6 kB view details)

Uploaded Python 3

File details

Details for the file serapeum_openai-0.1.0.tar.gz.

File metadata

  • Download URL: serapeum_openai-0.1.0.tar.gz
  • Upload date:
  • Size: 65.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for serapeum_openai-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1e993600d8381ef4517b7357a96be4b2ed09fc2229d7e0ed4b9827645783ce6f
MD5 fd86ff9838af0c8cde70f4dda961be99
BLAKE2b-256 d91324205ea9bfcb3531147e9a34856217c14c2174347e994d402ca2feaed3f7

See more details on using hashes here.

File details

Details for the file serapeum_openai-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for serapeum_openai-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8f79ccdd9258b2f11872f1b4546f7d320a53d3575b80d18b70570de70a36d0fb
MD5 34eb1eafe3fa4f082963f2c85f8d6221
BLAKE2b-256 ecbfec043c12bee4d7378d4f6565b5a2f4198e2258dc04c5e8dc689e73921380

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page