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.2-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.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.3.2-cp312-cp312-macosx_11_0_arm64.whl (972.7 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

gasp_py-0.3.2-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.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.3.2-cp311-cp311-macosx_11_0_arm64.whl (972.6 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 23a6a6afb21c7b41454e0ec67a211dc6d11e08de2a0e2f073ec7f93a151db551
MD5 f851c7da3765187bb0fffea64069081d
BLAKE2b-256 babe2143d05e01e2af862cbe5dd13263e01df73d19bf3a3e4552dba9f2d71890

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5630b117e8efb6ec48ca7e52d921bc4b0c38062e629816400672337339e85b4a
MD5 517cb5d36c4f0a9b42560e7a207109c7
BLAKE2b-256 54f4ed40b3b63640357354261dc6710e66c9042fc1d3f3640d0d92178de03f9f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3bf71933809c839d6e2eb921bac1bb9135bdc353d28dbfaaacfbf77ff5ce5f40
MD5 2c7b8659d31392d55ff6c219864fd799
BLAKE2b-256 146e1338b348136d21467b8eb43b175d93f85272a6a71e395a1cb6363237372a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 33987d73e2ce6a09a42be520d09824615c9eb582225602edf38d86452012afb1
MD5 c05171899db3717d12099b7db27ebab5
BLAKE2b-256 b8152c4489b2f2942a47617c3f10929eed88a998876cc33a1588fa00501344ba

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 32e25ea966f9d4ce3b3b6b510fe8435b3893060ef387a0b239941f7055eddfec
MD5 b519ca67a2413cb7f3db786d4db60a9e
BLAKE2b-256 c36649d937fc44c3f7e166d44d69a7adb33e36e787d47480a9ad2cc89a1c0f20

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 55e4e1f2d449ad932f76275e711522f134d93ef6f6e70148e023ba4435c6f73f
MD5 2cb9fec7dbacc54086134e12a92692cc
BLAKE2b-256 83211564acd529f5bd866e025794017249f22e09a0fad213355d2a53acd4c385

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 625311fcb5e69e4784684b1fa940ca16824e547eb01eff88bdb0b5c6f4c6273d
MD5 399795b23f3f641cfeca9287a2dff309
BLAKE2b-256 3a2e26e50e8fbb1019bdb21af626862c81f241322ccb2eefd04bd61c6f49c6da

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9b3b9340893be15332ca0786b242ede77054e523729fcab6ef967d03f243a716
MD5 868b45640182b6244f810644a444e1fc
BLAKE2b-256 91be6369867032a5af047344f77002cda7e1a48236e25c670eee88e8339e0a68

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp310-cp310-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 c118319c4504deadf9fa03ae6fd0260f46ad04fd98fdbde2c978518d63011f53
MD5 01225763de01beb24b0122cf547f854f
BLAKE2b-256 ea8ced38e0437234c56e1cd14e8551f2e5671dfd94f81dfa98c8eb3ac06af0d1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 d17c110214d1ea6d468eef800806efcab328209223e1feb062017ac18e1252b0
MD5 999a40b63c797d04917b096720fe224e
BLAKE2b-256 d7ab9fdae36155824dd31e17f5f9f5be96d0934081b2bc5a3fd0494291afe2a1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5c66f360747e12a6fd88845dfc2301faf54f05c1d07f49d2407371d96b13a356
MD5 64c20ee0a4d39214bad3d102ec12bdc2
BLAKE2b-256 08a4952e695886bd049adec929225db179415095909fe05233339bf848effd4c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp39-cp39-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 e0ff5c02b9ae6781d11a337eceff55ba0a7a2cd603f2c47f58bf90c3a539420c
MD5 8d37fb1721a9c65dafb4498566157a80
BLAKE2b-256 968d87c03975b8f1c86e94af90a15c34450555b5741128b93fff3114baa0d0c2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp38-cp38-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 0f482549ac98896562fb5791048e77b6a2bc8a47ee90de6f87892c508c2ea8d0
MD5 817062041dde3b952e511b0a456941f6
BLAKE2b-256 17a79f658be5d1550901fe620898f4d36505ce19f477b11f10b63285df07767e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 990ee90e599ed8b2a92db04a77fbed571d5ec643c876723a5aa04f67ba133321
MD5 70f91760c1ac363315e55b702d708db9
BLAKE2b-256 532e476bd48ee69ab0398d9625a1a6b0ea4d10533fec02dd91340652df9f2bba

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for gasp_py-0.3.2-cp38-cp38-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 8cccde1ead6891fa7b38504e68457ea424fbe8d038e9a310274d9782014ebd73
MD5 bd062717ac535230fb11c61c8db56101
BLAKE2b-256 7f76d373e27f2bbf2c5eec7a83d7a4dc6d25f744b0328c69f7493d56050e195d

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