Skip to main content

Unified Python interface for LLMs across local and cloud backends.

Project description

polyrt

Unified Python interface for LLMs across local and cloud backends.

polyrt is a typed adapter library that exposes a single small surface — generate, stream, and their async variants — backed by Anthropic's Claude, OpenAI's GPT models, and local Apple-Silicon models via MLX. It does not route, it does not orchestrate, it does not run a server: it gives you one consistent function call shape and one consistent return type, regardless of which backend you point it at.

PyPI Python License

Install

Backend Install
Claude (Anthropic) pip install polyrt[anthropic]
OpenAI pip install polyrt[openai]
MLX (Apple Silicon) pip install polyrt[mlx]
All of the above pip install polyrt[all]

Python 3.11+ required.

Quickstart

Sync

"""Synchronous one-shot generation."""

import polyrt

result = polyrt.generate(
    "claude",
    model="claude-haiku-4-5",
    messages=[{"role": "user", "content": "Say hello in one word."}],
    max_tokens=20,
)
print(result.text)
print(f"Tokens: {result.usage.input_tokens} in, {result.usage.output_tokens} out")

Async streaming

"""Async streaming generation."""

import asyncio

import polyrt


async def main() -> None:
    async for event in polyrt.astream(
        "openai",
        model="gpt-4.1-mini",
        messages=[{"role": "user", "content": "Count to five."}],
        max_tokens=40,
    ):
        if event.type == "token":
            print(event.delta, end="", flush=True)
        elif event.type == "done" and event.usage is not None:
            print(f"\n\n[{event.usage.total_tokens} tokens]")


asyncio.run(main())

Structured output

"""Schema-constrained structured output."""

from pydantic import BaseModel

import polyrt


class City(BaseModel):
    name: str
    country: str
    population: int


result = polyrt.generate(
    "claude",
    model="claude-haiku-4-5",
    messages=[{"role": "user", "content": "Pick a notable city and return its data."}],
    schema=City,
)
assert isinstance(result.parsed, City)
print(f"{result.parsed.name}, {result.parsed.country} — pop {result.parsed.population:,}")

Backends

Backend Capabilities Extra
claude schema, tools, vision, streaming polyrt[anthropic]
openai schema, tools, vision, streaming polyrt[openai]
mlx streaming (schema/tools/vision come in v0.2) polyrt[mlx]

Schema enforcement

When you pass schema=SomeModel, polyrt asks the backend to constrain its output to that Pydantic model and parses the result for you. The strategy differs by backend:

  • Claude — passes the schema as a single tool with tool_choice forced to that tool, then parses the tool's input payload.
  • OpenAI — uses Structured Outputs (response_format with type=json_schema, strict=true) so the model is constrained at decode time.
  • MLX — not yet supported in v0.1; raises NotSupportedError. v0.2 will add support via outlines or lm-format-enforcer.

Response.parsed is your validated Pydantic instance when it works, None otherwise.

What polyrt is not

  • Not a router that picks a backend for you
  • Not an agent framework
  • Not a model server or proxy
  • Not a fine-tuning toolkit
  • Not a prompt template engine

It is a typed adapter. If you want one of the things above, this is the layer you would build it on top of.

Adding a backend

  1. Subclass Backend (or duck-type the protocol) and implement the seven methods.
  2. Call polyrt.registry.register("<name>", YourFactory) at module import time.
  3. Either ship inside polyrt/backends/<name>.py, or expose your factory as a polyrt.backends entry point so users get it via pip install.

See docs/backends.md for the full contract.

License

Apache 2.0. See LICENSE.

Acknowledgments

Project details


Download files

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

Source Distribution

polyrt-0.1.0.tar.gz (25.7 kB view details)

Uploaded Source

Built Distribution

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

polyrt-0.1.0-py3-none-any.whl (23.9 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for polyrt-0.1.0.tar.gz
Algorithm Hash digest
SHA256 24e5a252e1dfc7876ae63f1d39de9450da7ca3a614eeb797346240506ec9bdeb
MD5 84c1a8a5fcd2cc8286e438c90043d431
BLAKE2b-256 4227ef71cf5b8c6ec40bcc224799f7d4ba533772e8027598db3ad18fa722e7f9

See more details on using hashes here.

File details

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

File metadata

  • Download URL: polyrt-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 23.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for polyrt-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 07cace5092cf9811b678f6ea76c52eb79095b67188217c2a003782680e30b1ee
MD5 4cd3f1ef045cf8864ae78c2d78aef60b
BLAKE2b-256 5014e8849dd3f6cc43945d043b065d5799e0b08477a0a5b8cc98b95d1cbe9d67

See more details on using hashes here.

Supported by

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