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

Uploaded CPython 3.12macOS 11.0+ ARM64

gasp_py-0.4.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.4.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.4.1-cp311-cp311-macosx_11_0_arm64.whl (1.0 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

gasp_py-0.4.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.4.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.4.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.4.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.4.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.4.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.4.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.4.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.4.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.4.1-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 876689f9dffbd7a9eeddb17608f4f01ba437376fefa66fbcf2d92be8aff6fa6c
MD5 e4e85c7679932d3782773eaa92639713
BLAKE2b-256 38667ee41bf59227159eb455c5745949b1d10358969a3f02f8c12afa3e57ff50

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4861c092d8c890b66ec56bbde85f9ac69a8babb58ee42c1af578eb7ece76d04a
MD5 e53db6203e7ec950e3fed376d09d9bcb
BLAKE2b-256 922724269a71085b42e66d166be11ad887002b7d38f09211e38b4c60ceebad7d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4138eefbe2f7a1b5cdf6fa04fff5c5179e1221ef5c3e519b707a466290b6707b
MD5 bad44d0efb2417215943ba596b370bcd
BLAKE2b-256 44028fff78e5dcb3cfe7e235b130d2e1230ff3d413201b7d03e4efe5c374abb6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 ed122d1008e077c41ec6046f8d958cd151a47380dc95c96902871449262acace
MD5 0ef5db6dc1d242ef71b12933f8e2ecbe
BLAKE2b-256 d2640cd673494de57a632356342af740e508b0d69a7f3bd2bd394a9ef360c35d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 37956ef62c38198debe232230375608f58e9cfae9fb42357c3b11bf65079e1dc
MD5 2a43d5f6d87fb88a0b9ac5e6ee3531b1
BLAKE2b-256 37f1555b2c5b6caa53dcd56b0fe125e1640937ada9d48af786c96417c7f1b60b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 713cb5cfafe2f54abad5885cae3c60f13ea06728d980326b30764ccc0b41301c
MD5 f1520f84c0196f01736f538762e9124d
BLAKE2b-256 12549aa3290c5b07f5a28a85e4d0e6b69c66a2832e54e3c624e47ce0ab5e59f0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 42db51b111514683777c52ad2ee45abb45a86e6ef05771c730d7dfa05a612fff
MD5 0ebf4e3e17b89a699d7c0483a12a3e16
BLAKE2b-256 77152c331f2d353ba9cfc02e9041df28079579ea1f57b981179d8d1bad8c2300

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 edcc9060099e40e378f3fcee2c814bc2cb0924f15e1e65dd152f2025e57a1987
MD5 dadad2254aa8b3a8c0f35d9ea3de8d28
BLAKE2b-256 53360b43142434a056700ed4cc24feb9b830ea5b81e1bbc96261fac13576769b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp310-cp310-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 912128a71134d1c4ce510d74d70b630dfc3ffc95aacbf260cf76e94df12b042a
MD5 07fb6c61214ff7178ea0c448d38180e2
BLAKE2b-256 09b22935cd219be868502ada95ee11064023dec8874d11df02776ff8ce5e9622

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 34a3ba0f7b32e496a8635c39db4e1dcff7493aeefc7e70255bf4e06f01c4f7d9
MD5 b2b9c15ba8d158c0b446d9670bb988e2
BLAKE2b-256 0ffdd087f510467ddb54fc4d729f874ed7f0a263c4b8e4b00204535d5bf75db4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 39edf91d607ed678b2014bbfd1715a0e33aee0cc8a1a08e5a4270299bc557c5c
MD5 2dea399fbb64f86249fd972fc6a21ef4
BLAKE2b-256 eb536c1126d6ad0ba4b4622e315e30ecf8b2cf88abafaecdae620ece76e47874

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp39-cp39-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 25b2a8783f490a1ed65b58a46c62426d9edc50019502572f89385e39ceed6c0c
MD5 f6abd1d1a9986b28f6405d807c35676f
BLAKE2b-256 c149e4f9b7e6ee40337a34754e6dc7758c41174f3b8b5fab47d3ad89e68fe3c6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp38-cp38-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 c2658ffad9389ee689e4bc028617b154f86624fe3ba523564d3937c5e070edbe
MD5 a8c05a883db3471697a4318bd03a86a5
BLAKE2b-256 8e5febfc933f20c0b38bcc9d0a527366df3359d064661c89a68902d193574a2e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 adf88e4d89970d79405c77f9f735c2e106b40aaf95a51807c79e005b943f1d2b
MD5 936f5d8848a21e79c14be955c25bc290
BLAKE2b-256 a8f45f4e2845110d5508d97815b6d96aa0ae01efda53479b25bf8b054080c62a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.4.1-cp38-cp38-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 2950ad6bc563615d899d024ffb005d02a1ade81e6877a903c9f66b998a443160
MD5 344658865804c480b7910f3cc89bece2
BLAKE2b-256 9f576c7691afb4a70bf3d581959df6ba81757d1749765be3fd4cacf6ae885832

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