Add your description here
Project description
Typus (typus-dsl)
Strict typing for loose models.
Typus is a Python library for Grammar Constrained Decoding (GCD).
Large Language Models (LLMs) are powerful but chaotic. They hallucinate invalid syntax, invent non-existent functions, and break JSON formatting. Typus solves this by generating strict Context-Free Grammars (CFGs) that constrain the LLM's token generation process.
Instead of writing complex EBNF strings by hand, you use a Pythonic Interface to define your constraints—from simple regex patterns to entire semantic domains.
🌟 Why Typus?
- 🚫 No More Hallucinations: Force the LLM to output exactly what you need (valid JSON, SQL, Python, or CSV).
- 🐍 Python-First: Define grammars using standard Python operators (
|,+) and types (dataclasses,int,str). - 🧩 Universal: Define your grammar once and compile it for any target:
- Llama.cpp / GGUF: Compiles to GBNF.
- Validators: Compiles to Regex.
- Parsers: Compiles to Lark (EBNF).
- 🧠 Cognitive Control: Use Templates to force "Chain of Thought" reasoning before actions.
📦 Installation
pip install typus-dsl
# or with uv
uv add typus-dsl
🏗 The Stack: From Low-Level to High-Level
Typus offers three layers of abstraction depending on your needs.
1. The Grammar DSL (Low Level)
For when you need pixel-perfect control over every character.
Use standard Python operators to define rules.
from typus import Grammar
g = Grammar()
# Define primitives
g.digit = g.regex(r"[0-9]")
g.number = g.digit + g.maybe("." + g.some(g.digit))
# Define structure
g.coordinate = "(" + g.number + ", " + g.number + ")"
g.root = "Point: " + g.coordinate
2. Templates (Mid Level)
For when you want to structure the LLM's thought process.
Mix static prompts with dynamic grammar constraints using Python f-string syntax.
# Force the model to think before it answers
g.root = g.template(
"Thought: {thought}\nAction: {action}",
thought=g.some(g.regex(r"[^\n]+"), sep="\n"),
action="SEARCH" | "CALCULATE"
)
3. The Domain Engine (High Level)
For when you want to project a "Problem Domain" into a target language.
Define your types and functions in Python, and Typus generates the grammar that enforces them in JSON, SQL, HTML, or Python.
# Define the domain once
@dataclass
class User: ...
# Generate a JSON Schema grammar
Json().build(Domain(User))
# Generate a SQL Query grammar
SQLQuery().build(Domain(User))
⚡ Use Cases & Examples
Use Case 1: Semantic Versioning (Regex Validation)
Ensure the model generates valid SemVer strings like v1.0.2 or v2.10.0-rc1.
from typus import Grammar
g = Grammar()
g.digits = g.regex(r"(0|[1-9][0-9]*)")
g.version = g.digits + "." + g.digits + "." + g.digits
g.tag = g.maybe("-" + g.regex(r"[0-9a-z-]+"))
g.root = "v" + g.version + g.tag
print(g.compile("gbnf"))
Use Case 2: Structured Reasoning (Templates)
Force an Agent to provide a reasoning trace before emitting a final JSON answer. This prevents "blind" answering.
from typus import Grammar
g = Grammar()
g.thought = g.some(g.regex(r"[^\n]+"), sep="\n")
g.json_blob = g.regex(r"\{.*\}") # Simplified JSON regex
# The template constrains the structure
g.root = g.template(
"Reasoning:\n{steps}\n\nFinal Answer:\n{result}",
steps=g.thought,
result=g.json_blob
)
Use Case 3: Type-Safe JSON Generation (Domain + JSON)
Define your data schema using Pydantic or Dataclasses, and get a grammar that guarantees the output matches that schema.
from dataclasses import dataclass
from typing import List
from typus.languages import Json
@dataclass
class Product:
id: int
name: str
tags: List[str]
# Generate a strict GBNF grammar for this schema
# The LLM cannot miss a comma, quote, or bracket.
g = Json().build(Product)
print(g.compile("gbnf"))
Use Case 4: Safe SQL Querying (Domain + SQL)
Expose a specific set of "Allowed Queries" to the LLM. The grammar ensures the model can only generate valid SELECT statements for your specific table columns, preventing SQL Injection and hallucinations.
from typus import Grammar, Domain
from typus.languages import SQLQuery
# 1. Define the Schema
@dataclass
class Users:
name: str
age: int
# 2. Define allowed access patterns
def get_users_by_name(name: str) -> Users: ...
def get_users_by_age(min_age: int) -> Users: ...
# 3. Build the Grammar
# The LLM can generate: "SELECT name, age FROM Users WHERE name = '...'"
# It CANNOT generate: "DROP TABLE Users"
g = SQLQuery().build(
Domain(Users, entrypoints=[get_users_by_name, get_users_by_age])
)
🔧 Supported Backends
Typus is compiler-agnostic. You build the AST once, and export it to:
| Backend | Command | Use Case |
|---|---|---|
| GBNF | g.compile("gbnf") |
Llama.cpp, llama-python, local GGUF models. |
| Regex | g.compile("regex", max_depth=3) |
Guidance, Outlines, Standard API validators. Supports bounded recursion. |
| Lark | g.compile("lark") |
Python Parsing. Use Typus to parse the string the LLM just generated. |
| JSON Schema | (Via Json language) |
OpenAI / Anthropic structured output APIs. |
🛣 Roadmap
- v0.1: Core DSL (
Sequence,Choice,Regex), GBNF Compiler. - v0.2: Templates (
g.template), Regex Compiler with unrolling. - v0.3: Lark Compiler (Round-trip parsing).
- v0.4: The Domain Engine (
typus.domainreflection). - v0.5: Language Strategies (
Json,SQLQuery,Markdown,Python).
📄 License
MIT License. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file typus_dsl-0.3.2.tar.gz.
File metadata
- Download URL: typus_dsl-0.3.2.tar.gz
- Upload date:
- Size: 28.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e16ae13092d576534fd071003e16fec4d2933723e5a91eabad63c297304d075a
|
|
| MD5 |
02dea061a5cebfbf7cfbfdee0cf29c70
|
|
| BLAKE2b-256 |
71755da06060300c6ede80aee97034693c2216121f015e0cb92462ba0895ce20
|
File details
Details for the file typus_dsl-0.3.2-py3-none-any.whl.
File metadata
- Download URL: typus_dsl-0.3.2-py3-none-any.whl
- Upload date:
- Size: 10.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49266139527d9836ee19a2169c33a50e71cebbff44ebe5192356384164e24278
|
|
| MD5 |
ba99492c9224a83f0f37302d7827b016
|
|
| BLAKE2b-256 |
3be2ed19b17f1fc0358a1c936809a7fcb85198868861a2e5b28fd12f5afbf47b
|