Skip to main content

GASP (Gee Another Schema Parser) - A validator for WAIL (Widely Applicable Interface Language) schemas and JSON

Project description

GASP (Gee Another Schema Parser)

GASP is a high-performance Rust-based parser and validator for WAIL (Widely Applicable Interface Language) schemas and JSON responses. It's specifically designed to work with Large Language Models (LLMs) by providing robust error recovery for common LLM response quirks.

What is WAIL?

WAIL (Widely Applicable Interface Language) is a schema language designed for:

  1. Generating type-validated LLM prompts
  2. Validating JSON responses from LLMs
  3. Providing clear error messages for schema violations

Why

In our expereince the ergonomics around tool calling kind of suck right now and in the lowest common denominator settings are down right painful.

If you're using OpenRouter (which is great) they choose not to support some platform specific features (understandable) like the "ANY" parameter from Anthropic so you wind up with super verbose output, the occasional no tool call, missing params even when specified in "required" and so we decided to implement this prompt creator and schema validator because what are tool calls other than type interfaces.

Honestly, BAML is a really sick tool and more feature complete than this, with like people actually paid to work on it, and outside of the minimal needs we have that this was created for you should go use them.

However, they require you to use their code gen'd inference clients for sending messages to the LLM. That let's them do some really powerful things like validation mid streaming, but you have to be all in on them.

GASP and WAIL let you separate out prompt creation, inference and prompt validation from one another so you can apply GASP to whatever client floats your boat with the trade off that we aren't intending to make this work for every streaming format under the sun (at least I'm not, feel free to contribute!) so it's only applicable to fully generated outputs.

I didn't need all that especially because I along with my friend and co-founder have written Asimov a framework for building Agents that includes all of our own inference machinery I'm not looking to give up.

Anyway both Asimov and now GASP/WAIL are built for supporting Bismuth a programming agent that can help businesses find and patch bugs on your Github PRs before you ever know about them.

Features

  • Robust Error Recovery: Handles common LLM response issues like trailing commas, unquoted identifiers, and malformed JSON
  • Type Validation: Strong type checking for both schema definitions and JSON responses
  • High Performance: Written in Rust with Python bindings for optimal speed
  • Developer Friendly: Clear error messages (except for syntax errors see below) and intuitive schema syntax
  • LLM-Optimized: Specifically designed to work with the quirks and inconsistencies of LLM outputs

Anti-Features

  • Non existant syntax error messages - I will get around to this soon but right now this is just as likely to segfault or die in rust with a cryptic error message as it is to tell you what you're doing is wrong.

Caveats

  • Output parsing is assumed to be sequential - That is we assume output happens in the same order as the template variable binding so like if binding1 doesn't correspond to output1 things will be wacky.

Installation

pip install gasp-py

Usage

from gasp_py import WAILGenerator

# Create a validator with your WAIL schema
generator = WAILGenerator(r'''
    # Define your schema here
    object Response {
        name: String,
        age: Number,
        interests: Array<String>
    }

    # Define your template function
    template GenerateResponse(desc: String) -> Response {
        prompt """
        Based on {{desc}} generate a response that returns {{return_type}}      
        """
    }

    # Define your main block which can handle variable assignments
    main {
        let template = Response(desc: "A really responsy response")

        prompt {
            We're showing off examples and example of of a prompt generated by WAIL looks like this:

            {{template}}
        }
    }
''')

# Get the prompt to send to the LLM
(prompt, warnings, errors) = generator.get_prompt()

# Parse and validate JSON responses
generator.parse_llm_output("""
{
    name: "Alice",
    "age": 25,
    "interests": [coding, 'AI', "music"]
}
""")

# Note the ability to handle malformed JSON

Error Recovery

GASP includes built-in error recovery for common LLM response issues:

  • Trailing commas in arrays and objects
  • Unquoted identifiers in object keys
  • Missing quotes around strings
  • Inconsistent whitespace and formatting

License

Apache License, Version 2.0 - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Complete Example

Here's a complete example showing how to use GASP in Python:

from gasp import WAILGenerator
import json

def create_person_prompt():
    """Define the WAIL schema for person generation."""
    return r'''
    # Define our Person type
    object Person {
        name: String
        age: Number
        interests: String[]
    }

    # Define a template for generating a person from a description
    template GetPersonFromDescription(description: String) -> Person {
        prompt: """
        Given this description of a person: "{{description}}"

        Create a Person object with their name, age, and interests.
        Return in this format: 
        {{return_type}}
        """
    }

    main {
        # This is a comment
        let person_prompt = GetPersonFromDescription(
            description: "Alice is a 25-year-old software engineer who loves coding, AI, and hiking."
        );

        # This is the prompt we'll send to the LLM
        prompt {
            This is an example of a prompt generated by WAIL:
            {{person_prompt}}
        }
    }
    '''

def main():
    # Initialize our validator with the schema
    generator = WAILGenerator()
    generator.load_wail(create_person_prompt())

    warnings, errors = generator.validate_wail()

    print("Validation Results:")
    print("\nWarnings:")
    print(warnings)
    print("\nErrors:")
    print(errors)

    # Get the generated prompt - this is what you'd send to your LLM
    (prompt, warnings, errors) = generator.get_prompt()
    print("Generated Prompt:")
    print(prompt)
    print("Warnings:")
    print(warnings)
    print("Errors:")
    print(errors)

    # In a real application, you would send this prompt to your LLM
    # Here we'll simulate an LLM response with some typical quirks
    llm_response = """
    {
        'name': 'Alice',
        'age': 25,
        'interests': [
            "coding",
            'AI',
            hiking,
        ]
    }
    """

    try:
        # Validate the LLM's response and get the parsed JSON as a Python dict
        result = generator.parse_llm_output(llm_response)
        print("✓ Response validation successful!")

        result = result["person_prompt"]
        

        # Work with the validated data
        print("\nParsed Person:")
        print(f"Name: {result['name']}")
        print(f"Age: {result['age']}")
        print(f"Interests: {', '.join(result['interests'])}")
        
        # # You can also convert it to standard JSON
        # print("\nAs standard JSON:")
        # print(json.dumps(result, indent=2))
        
    except Exception as e:
        print(f"❌ Validation error: {e}")

if __name__ == "__main__":
    main() 

This example demonstrates:

  1. Creating a WAIL schema with proper Python string formatting
  2. Defining object types and templates in WAIL
  3. Generating a type-aware prompt for your LLM
  4. Handling common LLM response quirks automatically
  5. Validating and parsing the response
  6. Working with the validated data in Python

When run, this script will output:

Validation Results:
Warnings:
[]
Errors:
[]
Generated Prompt:

This is an example of a prompt generated by WAIL:

Given this description of a person: "Alice is a 25-year-old software engineer who loves coding, AI, and hiking."

Create a Person object with their name, age, and interests.
Return in this format: 

{
  name: string
  age: number
  interests: String[]>
}


Warnings:
[]
Errors:
[]
✓ Response validation successful!

Parsed Person:
Name: Alice
Age: 25
Interests: coding, AI, hiking

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

gasp_py-0.4.0-cp312-cp312-musllinux_1_2_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

gasp_py-0.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

gasp_py-0.4.0-cp312-cp312-macosx_11_0_arm64.whl (1.0 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

gasp_py-0.4.0-cp311-cp311-musllinux_1_2_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

gasp_py-0.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

gasp_py-0.4.0-cp311-cp311-macosx_11_0_arm64.whl (1.0 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

gasp_py-0.4.0-cp310-cp310-musllinux_1_2_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ x86-64

gasp_py-0.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

gasp_py-0.4.0-cp310-cp310-macosx_10_12_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.10macOS 10.12+ x86-64

gasp_py-0.4.0-cp39-cp39-musllinux_1_2_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ x86-64

gasp_py-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

gasp_py-0.4.0-cp39-cp39-macosx_10_12_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.9macOS 10.12+ x86-64

gasp_py-0.4.0-cp38-cp38-musllinux_1_2_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.8musllinux: musl 1.2+ x86-64

gasp_py-0.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

gasp_py-0.4.0-cp38-cp38-macosx_10_12_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.8macOS 10.12+ x86-64

File details

Details for the file gasp_py-0.4.0-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 767d9a2a44464f690172a66985d9a0526b5fb26332a94d3b376ff819c5ca09fe
MD5 a94ff784ccdca57b46947671fb83e98b
BLAKE2b-256 6cd6f7fa63e61982f6ee460ac7a547faf1622abb7337758f3343398e481fe2a1

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 00eec53aa58f3be516c2bab90101b4ad1bb283c4a1b70ad289997fc32ca50ccf
MD5 0dfdf36fa6e275f15b35ecbb4c446fe0
BLAKE2b-256 1c8b1594151aaae5f14549f259fa4f618b0ba7226c8580249a3f4673a0c31381

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 39c3440f30efbb0687f91bb6726265ff762576b66ae6edc99f3b8280841fa6b9
MD5 97dc1a031c3cf8bb8f98c3cb65254031
BLAKE2b-256 7f5b079d8502f3556108d471236f2057c7a412e27b8486c2ce14a2da82804263

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 76695c6e59d7cada5e705e1de5f4fb65bb27c1bdd2d636cc20806af55241b3d8
MD5 4d9edea05887beb195b4bc96e5f53084
BLAKE2b-256 aec6d95f203f742e9f97eb9e2df76199efaee6093f3bbae957f2fe3add856c09

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ca75210a64bf3a287efa2c65e9ad62ad82682d79d9c5046f6fae47cad5b57e42
MD5 82f053c9e7dfe076bbcc9ea4f83e3b55
BLAKE2b-256 6e02c59e362fe0b6d5f2727baf44fbb955d14d1d556025bf41a28262dc35d606

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6204bd59b165d05e4013b5b60e9f314f786a0ee8ded850e6c612ea0cd26d3eb3
MD5 99285eb9cbbab925a3e112b8cbf6beee
BLAKE2b-256 c9398ef2383c3ad2db0949177b6e471c791c99cda3ac437c1e90a3e491d98f7c

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp310-cp310-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 a862c057f41df3ae158861fd02f2fcf7abdb56b397aaff93f7ee443941e0e63f
MD5 072db80a3edf096f09b2c5a85943662f
BLAKE2b-256 09a06a025b96fb9906a2a4189c1309cb839c93514bfd36ae7b9e493ab40e3173

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ecb7565a441c279c2984e6b66b3c9c5922088701dd2e06b8266fd9b078270f68
MD5 1cfe5bb4756d110385ec75df72d3714a
BLAKE2b-256 10ec15c34dde3fd08eca621c2316362f4a25459c3db7f4144dd25919372ea45d

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp310-cp310-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp310-cp310-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 378b3cb632a09d2af414ae259896140f8b2351e66d55d928151c55178c16db10
MD5 36fd6f0e5fdb85ca5fea68f94be3b28c
BLAKE2b-256 2fb3a43a66e4ce73e5c7296bcc83d95e71daf3d74841a49cb92d5bc4f8e037c8

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp39-cp39-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 c1922537bb1bae5fd974ad268f27e49edd56e9dbf724cca47339f70dc05b3073
MD5 eb95a233a11e426865b7479d0a5f81e0
BLAKE2b-256 3dc161d60c8a9d02a581252e49f8ae8bc0cb3a174ff57b516468dfc45a8b0978

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b3abf223ce200a6129863fa5f87fed9ca75d6384a9e377c3e4880512630bc4b1
MD5 91ad6942565d781be84e719fd0326320
BLAKE2b-256 8ad2a33273220e752ec95a321366f1da891748f9da3f231ddfcf2aa89fb81564

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp39-cp39-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp39-cp39-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 e50c7d929f78d9d263994b60c879cbcc3bb3cd0512bd770ec770cfec64d8c869
MD5 18e986f9ac2cd2a0363443ce9b3bacc7
BLAKE2b-256 b6a47f0a11bc439e14808bdf9f690d75aae44d435480b7348f8db4c1ebebae60

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp38-cp38-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp38-cp38-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 92dc675d4069e0f31ec13bb81eda06893f6e2eaa1a991a48c3fad89daa98f544
MD5 521413eaf7d049de079d21e201614e7f
BLAKE2b-256 42de6ce243ab5b02915d47e074ecd9a17d3b55462036620235295d5835315be6

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c079c4fd157875058842e36286b47d0b84818459e54cac64c830f82023aaa00f
MD5 9ea7e92ce7c0a5d22c8ae75b00773ccb
BLAKE2b-256 8b9c5fc69ade6a52baa5899b60d1d8f81ff910f0f467e386eb97d49334e2b223

See more details on using hashes here.

File details

Details for the file gasp_py-0.4.0-cp38-cp38-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.0-cp38-cp38-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 463fad788b3c918020df89c872c260887e84ed2a3579c82d4cffcd9997ea7a90
MD5 e74c43b9d9398783c07a0a70b70ce560
BLAKE2b-256 eae806d594a0331c4be454e6501e3cc8cf22a4851ce70ff685a411a0ceaa013f

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