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.5.1-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.5.1-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.5.1-cp312-cp312-macosx_11_0_arm64.whl (1.0 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

gasp_py-0.5.1-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.5.1-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.5.1-cp311-cp311-macosx_11_0_arm64.whl (1.0 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

gasp_py-0.5.1-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.5.1-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.5.1-cp310-cp310-macosx_10_12_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.10macOS 10.12+ x86-64

gasp_py-0.5.1-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.5.1-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.5.1-cp39-cp39-macosx_10_12_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.9macOS 10.12+ x86-64

gasp_py-0.5.1-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.5.1-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.5.1-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.5.1-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 f8571f5a273c4835344a63bec1b4b35351a628c9758504916f8b169c7de01ad5
MD5 99e5fe0604a05a617f1e6696bedc0175
BLAKE2b-256 53dd04d04d8cb9d88815f552906b513ae04a22b1572c0ce55fbb29b5a38f1474

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1d0500a820587a47c774c04837a44d51e59764ce5739545be7cd9643ed369ee1
MD5 a153595939a1222c0b2a7b4fe8d1bcd4
BLAKE2b-256 1371ab5b20583ee0d307a736ab08c67aed9b2bf34e4ec482c7fd9995f23adec1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a3bdfbb03409aeb18c0409af42a859436a48fb351d2d1eb96fb610100c61a7fb
MD5 eaad3323dedf05b21c66c25a09a6774c
BLAKE2b-256 bae4c85dbeb2fec368ac5f3d1ffe06c6ab8101b1f7f503961b02cbf9ab2d9a10

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 ad917800e0c0a4188a98322df2a3aa27b297979eb92b4eae8e20e2e9a97070ef
MD5 569d6891ff1010945602374fcc3a9076
BLAKE2b-256 d84b7cb0705968e645ae6daa87efd9afd79fd1cabda678ab4624af3c056dea8a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9bec0cd8a3dd877b3f2b9cdafcf522b32dad1eed3555507b1aad6096d7b7f095
MD5 9c6369c520d98d29a5007c5a1266bc3d
BLAKE2b-256 9d5ab4ac48c64ab33976fb6024f7b9a3a9875d79cb3a74f2a339938a5c1aeb64

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 68f2ad314639bc7dce1af58f0b3902f55c64e3316c6f6a7f9250caf1642f497c
MD5 9f13a92eb678566ca6d8b543dda0f558
BLAKE2b-256 c6e7b2a60a6a7193973eac4c9cd34dd092d08a8c19eca4e4c4c9a98e8b9bd828

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 ce9e00aed83a50d88d22d70ff7defc96dda5e0fc28bde4bdd5865bcdbf19852b
MD5 3ef333e45a03c77779aef7c8d883810f
BLAKE2b-256 17d1602aea66f619f7222a9d224c4f3bc50328b74fb7354d9f80d029a44acdc1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b0d4830fe6f97debbc9ae06742a824afe1ec07a2301fb293ca05da74360b0eeb
MD5 dd55b487054067c227132531666743da
BLAKE2b-256 b35c54db9d3ec32d059de87c13f620b614f3fdd33225e37420737cd292ef13cd

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp310-cp310-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 c6c7e576e6ca3b88e396de15df97d1eb3eee7e674e4ea5f05a288c643c84c764
MD5 74d3bcf23a826810d99e40ed0ed8c178
BLAKE2b-256 98602364fcad64a01840768ae2801e0a43a8dc10c63f166a2f0aa82e54cc9dcd

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 ec348b8705c123fc7f973b2cf1d647dc6d27cd10114ba8aa7ddf39043a017b9b
MD5 276d6de6153bcb9990c922ea5e6bc0d6
BLAKE2b-256 674caaadf823dec2eb94db527603249b9aa1455bac34c0ddfcca85c2296970d0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 de51b5b76f5036c57d42b3964e06183f9c8823a27b695541799ba5ea039894a3
MD5 6aeae71d087066e6fd47e64a0912ed76
BLAKE2b-256 57d4b56917b28674dfd51c8926acdcfeb86c50a45003dce5e07912708234ca1b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp39-cp39-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 10fff400aa32ca75d3fb20a280a8734c39cc4e8e31077bbc03b94e5197ee624e
MD5 34620f3f5c45b216346dfd9f9831a488
BLAKE2b-256 303de865482c36667772530d23421a077dfc334af8764a0a9a296099d24712ed

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp38-cp38-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 463caaaae589f376ca6d79f92b89ca1964b4d108f5583c3a197ca01515c27203
MD5 c46e2f5127f92d7d75beb3cbd9370b1f
BLAKE2b-256 7cefd86c3881bb2c47817662e2682a18cf7fc56019e77339e4054efc2910f8be

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 61601fe9a25a82d14547afc97635e733829980aa1923642febfab9dc25ab970d
MD5 68cafbd2cbd9d97e720df39642eaa304
BLAKE2b-256 2b573d94dbd89aaf8427246cfbb84615fda1b88dc5a65b3bcf6d62f85d244a14

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.5.1-cp38-cp38-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 19dfdad629086f558385ac43157c58362322f55fbbc9c1ac061a6e3ced1666ee
MD5 8ed1f18c573fb38ef45e0a0985baabb8
BLAKE2b-256 897856ad591282098e491e63c680dc3c9db011b91912732b96cf767332c497cb

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