Add your description here
Project description
Typus (typus-dsl)
Strict typing for loose models.
Typus is a Python library for defining Context-Free Grammars (CFGs) programmatically and compiling them into generation constraints for Large Language Models (LLMs).
It solves the Backend Fragmentation problem. Define your grammar once in Python, and compile it to GBNF (for Llama.cpp), JSON Schema, or Regex.
🚀 Features
- 🐍 Pythonic DSL: Define grammars using standard Python operators (
+,|) and attribute access (g.rule). - 📝 Structured Templates: Use standard Python format strings (
"Reason: {thought}") to define rigid prompt structures. - 🛡️ Type-Safe Core: A robust AST (
Symbol,Terminal,Sequence) that prevents invalid states by construction. - ⚡ Regex Support: First-class support for Regular Expressions using
g.regex(). - 🏗️ High-Level Builders: Helpers like
maybe(),some(), andany()that handle recursion automatically. - 🏷️ Deterministic Naming: Rules generated by helpers use stable, readable names (e.g.,
some_item) or explicit names you provide. - ⚙️ GBNF Backend: Out-of-the-box support for
llama.cppgrammars. - 🔌 Plugin Architecture: Easily register custom backends without modifying the core.
📦 Installation
pip install typus-dsl
# or with uv
uv add typus-dsl
⚡ Quick Start
1. Basic: Semantic Versioning (SemVer)
Define a grammar to validate version strings like v1.0.2 or v2.10.0-rc1.
from typus import Grammar
g = Grammar()
# 1. Define atomic components with Regex
# "0" or "1-9" followed by digits (no leading zeros allowed)
g.digits = g.regex(r"(0|[1-9][0-9]*)")
# 2. Structure the version core: X.Y.Z
g.version_core = g.digits + "." + g.digits + "." + g.digits
# 3. Handle optional pre-release tag (e.g. "-alpha", "-rc1")
# maybe(x) -> x | ε
g.prerelease = g.maybe("-" + g.regex(r"[0-9A-Za-z-]+"))
# 4. Assemble the root rule
g.root = "v" + g.version_core + g.prerelease
print(g.compile("gbnf"))
2. Intermediate: Reasoning & Action (Templates)
Force the LLM to follow a strict "Chain of Thought" structure using g.template().
from typus import Grammar
g = Grammar()
# 1. Define the dynamic components
g.thought = g.some(g.regex(r"[^\n]+"), sep="\n") # One or more lines of text
g.action = "SEARCH" | "CALCULATE" | "FINISH"
g.query = '"' + g.regex(r"[^\"]+") + '"'
# 2. Use a Template to structure the interaction
# This mixes static text prompts with grammar rules ({thought}, {action}, {query})
g.root = g.template(
"Thought: {thought}\n"
"Action: {action}({query})",
thought=g.thought,
action=g.action,
query=g.query
)
print(g.compile("gbnf"))
Output (GBNF):
root ::= "Thought: " some_regex_sep_newline "\nAction: " action "(" query ")"
thought ::= some_regex_sep_newline
some_regex_sep_newline ::= [^\n]+ | [^\n]+ "\n" some_regex_sep_newline
action ::= ( "SEARCH" | "CALCULATE" | "FINISH" )
query ::= "\"" [^"]+ "\""
3. Advanced: Structured Function Calling
Define a grammar for an Agent tool call, like search_tool(query="foo", limit=5).
This demonstrates recursion, lists, and explicit naming.
from typus import Grammar
g = Grammar()
# 1. Define primitives
g.identifier = g.regex(r"[a-zA-Z_][a-zA-Z0-9_]*")
g.string_lit = '"' + g.regex(r'[^"]*') + '"'
g.number_lit = g.regex(r"[0-9]+")
# 2. Define a generic "Value" (String or Number)
g.value = g.string_lit | g.number_lit
# 3. Define a named argument: name=value
g.arg = g.identifier + "=" + g.value
# 4. Define the Argument List
# any(x, sep) -> (x (sep x)*)?
# We explicitly name the recursive rule "args" for cleaner GBNF.
g.arg_list = g.any(g.arg, sep=", ", name="args")
# 5. Root: name(args)
g.root = g.identifier + "(" + g.arg_list + ")"
print(g.compile("gbnf"))
Output (GBNF):
root ::= [a-zA-Z_][a-zA-Z0-9_]* "(" ( args | "" ) ")"
identifier ::= [a-zA-Z_][a-zA-Z0-9_]*
value ::= ( string-lit | number-lit )
string-lit ::= "\"" [^"]* "\""
number-lit ::= [0-9]+
arg ::= identifier "=" value
args ::= arg | arg ", " args
🏗 Architecture
Typus follows a strict Layered Architecture to ensure security and flexibility.
Layer 1: The Core (typus.core)
The atomic units of the grammar. These are pure data structures.
- Terminal: A string literal or regex.
- Sequence (
+):A + B. Optimized to flatten automatically ((A+B)+C->A+B+C). - Choice (
|):A | B. - Epsilon: The empty string ($\epsilon$).
- NonTerminal: A reference to another rule (allowing recursion).
Layer 2: The Engine (typus.grammar)
The Grammar class manages the state. It handles:
- Lazy Evaluation: You can use
g.my_rulebefore defining it. - Recursion Management: Generates stable recursive rules for
some()andany(). - Template Parsing: Converts Python format strings into grammar sequences.
- Backend Dispatch: Delegates compilation to registered visitors.
Layer 3: The Backends (typus.backends)
Typus is agnostic to the output format.
- GBNF: Included by default. Handles escaping and rule naming conventions.
- (Planned) JSON Schema: For OpenAI/Anthropic structured outputs.
- (Planned) Lark: For validation and parsing.
🛣 Roadmap
- v0.1: Core AST, Operators, GBNF Backend.
- v0.2: Regex support (
g.regex("[0-9]+")) & Templates. - v0.3: JSON Schema Backend.
- v0.4:
typus.domain(Python Type Reflection). - v0.5:
typus.languages(Python, HTML, SQL Generators).
📄 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.1.tar.gz.
File metadata
- Download URL: typus_dsl-0.3.1.tar.gz
- Upload date:
- Size: 28.2 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 |
549c2047eb30fba24861f2e9c03e0196d08888950a6332364ac5b842986d9bc6
|
|
| MD5 |
0f540d2bc842a3ff23e79ea7ddc4d263
|
|
| BLAKE2b-256 |
bc7df7f637bf3daa8a52890a26673c9d5b748f4f5b8d2f41a398b2741d8d1755
|
File details
Details for the file typus_dsl-0.3.1-py3-none-any.whl.
File metadata
- Download URL: typus_dsl-0.3.1-py3-none-any.whl
- Upload date:
- Size: 10.1 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 |
ce66fa15f3f94e214345cd40c0fd46e9e7c7166ee0ae424dee522429d8c81a66
|
|
| MD5 |
5a5163223078205362b09eace52dccec
|
|
| BLAKE2b-256 |
94b2b59ce089056648c60828bdad108c17ea98a03e274c6aa0cc2cf5aac09cee
|