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

Uploaded CPython 3.12macOS 11.0+ ARM64

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

Uploaded CPython 3.11macOS 11.0+ ARM64

gasp_py-0.4.2-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.2-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.2-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.2-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.2-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.2-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.2-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.2-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.2-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.2-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 3157326d68cb6286d9afa3361ac07519e0f71031b5369e95a0bc0f65e81fc4da
MD5 99a2b4e09462d2500be73f9d9af91f5c
BLAKE2b-256 d8a41ed322c4aea33a25c1340b3dad44d3b9bd4cf2f1462211cf64fe56c1d89c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d1092ef498337f007af6c573ab50178828a0bf524c4aac771ede78ba8b59d9f9
MD5 7b2aaba058ff8dfd5dcedb2a32be0d98
BLAKE2b-256 158864547d5aa52bf1eba2380f59716dc259e3cb3512410a194a2a5e61fc3912

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 962acf09d12ebe90b904341f071d9e3826bfdb5dcd50e036cf5b0b1b1ac77bee
MD5 243989cdc05b3c26d8438a01868d025a
BLAKE2b-256 364c1dba1b6816d2f144e8ff6edb72f90ac83f57317462147a5ee8eec8717d36

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 b44b3a9a60970017715cddac2cba7f59329638cdfc76bd6dd7566fc915f910a1
MD5 98bd38682933b4d941043fbd51259176
BLAKE2b-256 14df5ecc238196f0382b29c6bd8686bd5ee2aa301d5940ae983cc61b702b3cfe

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 009fab47eecca12f38b08db96dac94e615fb6459eb7e444681a37723d291607a
MD5 0cb7ac60e24c74047d73d84fd795652d
BLAKE2b-256 7d2ceda6282f05968a56a3f47af4a50ae2c31ed5bb6ecb06f70dfcf266957746

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b83eae502fa9777931320b96d16ebdc31f9853f0ed8325a512b8db1187cab667
MD5 b81831cdf5e85df801196fa13ab61045
BLAKE2b-256 166abaf380772826889949da6b724681bb0763fb0b731327cd378bb5a767a915

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 800e2cb87342dfba8baef4aa793dc770e231266fd7cf346ef8ccd564d6452c9a
MD5 ed881b67c94cebbb3a3f997b1c43458b
BLAKE2b-256 21254f0a60684db2b7b64f98177d4ce62a8f6fef5539d1687575c811d5ff1306

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a09940688acb55be3e554653db4574e33870c47034dbd0ade4dd4c9184f92fc1
MD5 083faa77e2f83ce6dd297a4dc0e23315
BLAKE2b-256 24cbcc9197ef1ac69fcd839fdf4a07d5880f64267655704d170dd8a1d1071bbc

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp310-cp310-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 4a7e0f44a2e9ebfbfaa47244d00dde0b73032ca49895f5f46266a208acb5b36c
MD5 f51f78bb96bbf9b5c0670b91ac9048af
BLAKE2b-256 1b8dce053fcf6979e03ec914cfecb40b8f20e7ad270bcbc6d0b010a4357677fd

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 b7f7d0d6f00c18aa664d5c8ace04ec30741e4c117468c5c42fcf8774d3aa4a72
MD5 138e4335ae42c62e714e8d924f5751f3
BLAKE2b-256 bfd2e9cd8d55e39939445b72c6d60514e97a06d6fc6a1d8109b618f26c088d1b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fb7b2145e157878d11968002ddb2180a835da755d5b60561ec31be805ddfea98
MD5 ee06d8ebb7b979c900a325e7fe27c101
BLAKE2b-256 a939fd8f4510771576520ae4c32d34734a44f7f06204f82653686ef608942e5d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp39-cp39-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 ed661cfab2f464420d1c744d3095552f00d0274b6a11bcd76fc676df1d51bf76
MD5 7c2b9200283e2407e177e9519ecc7882
BLAKE2b-256 67a78c1a0b27da07ec7ea1cc8f41871b136223aa4284ec6ee07e94eb5af40347

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp38-cp38-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 af88785b258ee46083d33f614f3b23a90b24c4801734c8ba4e875e834fe378de
MD5 b6509d8b348b3dee2d116694c1cec70a
BLAKE2b-256 1ecb9e74912a983bf824af4240a0e6326bc0a31a40d6a51238a32950d026fc4c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0d2ccc11efbbae8ac783fb926a527c2d290369d44934c48a2521a646502e4311
MD5 89d4b6794a0e673c8f2275acc2b24081
BLAKE2b-256 d331112bf2914b071f4c006eb498b1671d657ae66457751745f08aa8688473ac

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.2-cp38-cp38-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f798d8572c564cc5db06e4247d5664f7f57076d7f8542fecdee9de2baba8d9da
MD5 75d4616c8ddd688ecc6f7980d0c12580
BLAKE2b-256 b7c726fe4d868107d4343a3c578494876bbd6af2aca292a386d6d13c0fa81f63

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