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.3.3-cp312-cp312-musllinux_1_2_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

gasp_py-0.3.3-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.3.3-cp312-cp312-macosx_11_0_arm64.whl (983.5 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

gasp_py-0.3.3-cp311-cp311-musllinux_1_2_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

gasp_py-0.3.3-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.3.3-cp311-cp311-macosx_11_0_arm64.whl (984.7 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

gasp_py-0.3.3-cp310-cp310-musllinux_1_2_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ x86-64

gasp_py-0.3.3-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.3.3-cp310-cp310-macosx_10_12_x86_64.whl (1.0 MB view details)

Uploaded CPython 3.10macOS 10.12+ x86-64

gasp_py-0.3.3-cp39-cp39-musllinux_1_2_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ x86-64

gasp_py-0.3.3-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.3.3-cp39-cp39-macosx_10_12_x86_64.whl (1.0 MB view details)

Uploaded CPython 3.9macOS 10.12+ x86-64

gasp_py-0.3.3-cp38-cp38-musllinux_1_2_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.8musllinux: musl 1.2+ x86-64

gasp_py-0.3.3-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.3.3-cp38-cp38-macosx_10_12_x86_64.whl (1.0 MB view details)

Uploaded CPython 3.8macOS 10.12+ x86-64

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 5d960e879756de34d3e9a75a47daca5a48c72ec4d9817cd838e89a5d411f1ce5
MD5 d69cf8420f984f17f14060ad59cc6484
BLAKE2b-256 3151afebfb81cdb1e8d211ec6c682e1068378cf845b407876ccd425db05858b2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7a14d189b1751204d0b6a72160fb17947edc869cfa3329a972eeb0f2653750aa
MD5 4392516c579e403e74c0af24dd63e71a
BLAKE2b-256 26fbe5bd0705639f4177308f65c455ddec07cd7c7fe50210a917cfb249f9f291

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 46169ffa2b0e7963205319f658d71e9ab342d12726855a59881d98ee4e609069
MD5 e5782aa8f5ee14484d1f3e2149a529ac
BLAKE2b-256 cbe155766e368ff549e601c434316fdc2f2b3ed4e17cdd8fb921562468624c33

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 683dfb68c4b22f6e8f2f196028608a399de52874c78681faadc9d5a56c38919b
MD5 55b079556838b079adcef6ee0b32b018
BLAKE2b-256 fd2e509d09fcbc515b7f81ac03023af4c353638834d4e79d1cfe81e00ce227fd

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5dcaf5098f01de23d9f796fd13121b494f2ae8b966cc603a3f349d78ad22bc33
MD5 eadd36b2e290ed5530ebce32f6ad8c89
BLAKE2b-256 7694db79bafa77af339f6a333ee813d2da7e7ad6520fff30112d1851ae0cadbf

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 81b4e0025821ec165f7f9c505f1305d0fa043266519aab0301f99bf31fa963ee
MD5 cb11415d9ea10e9b10e54135857e4030
BLAKE2b-256 563543c762aed232c5936cd1efb92d0bbb893380822a9c34af8c70251c3a9b4d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 316da419af2c97b3fefe0479b91945522e36c68f10411f5aabee025f78a14bde
MD5 665d0fd87a2f72f4cb10d48dfa7a776e
BLAKE2b-256 477c4836625d1e74d7b65bf12e44bddf39b04256a16c86b79d3491eb40da3e20

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 bdcb444eef03439486b9243948c77578e777fd4b163df20f843f5a5c50cfe419
MD5 a78548f455a79f6e25a6c51773b5a613
BLAKE2b-256 c05228392f889b3997776fecb02469c2ef3dfb50a15877e31726ffe76e4027dd

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp310-cp310-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 1eddd2b0fa7c0cae036b6874eab5ac6e38d85341b3ee9cf53b2c0b9dbe201ead
MD5 f87a399a77c3d5847af61eb4ce135636
BLAKE2b-256 496c64532c608cebd92de458b0441fb85d76e853a1409096a83049a077c6e63d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 eddf69d9f732b26be0c25a78288fde6ddf552ed9084a17cb6395daee47f5f69b
MD5 407ed433ea9edcb8c902cdefc3a44cf2
BLAKE2b-256 045af042bf7793e1a531c0fe77808f98a659930b6a4d77b22e37b0eeba1271e2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f4fe699f02fbe20c94b4f121ad6f5074b934a7d16182e184b5a334107e6f1192
MD5 684a56f646b7a8854a15fb59fbb9eaff
BLAKE2b-256 20ba2fbaf89477375e9f587a2092a87e9df6cc052c894c2cd8681e48d129d4db

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp39-cp39-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 a4e6093215a3ac40f8fd3926f803bd5dd1d6fa0f72ddad57773bdf135081afe8
MD5 412c940d0071af8efdca9140ca9c88ad
BLAKE2b-256 d12496fc55b3f672ec82a2b51936cdbdbe835f03d1285b099e1858fe64ef8614

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp38-cp38-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 5ef693aef87efdfd286c75768c894d5c161f96ff3c4bcd025a0562a1909dc28d
MD5 4c129f461cf65bd88c23ac216e2d2973
BLAKE2b-256 2cd7a60877bfb0cf3c0cfbba45032f773e099a520f27d8654972b8d7dcff8f6c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 21cdb62bdbc61d325e129b62f5c64d07b966a955b64bab8204b03c1df4220b49
MD5 a6c74cd66182dff4c5d07fda1a01f141
BLAKE2b-256 e387cf2478b3c5f1702d124b1defc5b05584750f7bf15b1366197853aa1c06d7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.3-cp38-cp38-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 2ca8da5d116dc17d662c7b06c8d76639916fa8fd52d7f9b08030ec4125d55bff
MD5 c0e845d1e9465f5e562c6063bcb507a8
BLAKE2b-256 44e887a4abc2fdcc9b6133a5e50f2ee657b9346d13a436aa582e05d366569e56

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