toon-python

repository·main·Indexed 20 days ago

https://github.com/toon-format/toon-python

A Python implementation of TOON (Token-Oriented Object Notation), a compact, human-readable serialization format designed to reduce token usage by 30-60% compared to JSON when passing structured data to Large Language Models. It features YAML-like indentation, CSV-like tabular arrays, and integration with Pydantic via ToonPydanticModel for structured LLM interactions. The library includes utilities for encoding, decoding, token counting via tiktoken, and measuring token savings.

Tokens
12.7K
Snippets
54
Records
62
Agent score
70%

What's inside toon-python

  1. Understand TOON primitive types

    main

    TOON supports the following primitive types:

    • Numbers:
      • Integers (e.g., 42, -17).
      • Floats (e.g., 3.14).
      • Note: Encoders must use decimal form, not scientific notation. Non-finite values (Infinity, NaN) are encoded as null.
      • Large integers (>2^53-1) should be quoted for compatibility (e.g., "9007199254740993").
    • Booleans: Represented as lowercase true and false.
    • Null: Represented as lowercase null.
    true
    false
    null
    42
    3.14
  2. Best practices for token efficiency in TOON

    main

    To maximize the 30-60% token reduction offered by TOON, follow these structural guidelines:

    1. Prefer Tabular Format: Use [N,]{fields}: instead of lists of objects. It is significantly more efficient.
    2. Minimize Nesting: Deeply nested structures increase token overhead; flatten data where possible.
    3. Use Compact Keys: Use short, descriptive keys (e.g., id instead of user_identification_number).
    4. Be Consistent: Do not mix JSON and TOON in the same conversation context.
  3. Version Numbering Convention

    main

    The project follows Semantic Versioning:

    • MAJOR (X.0.0): Incompatible API changes.
    • MINOR (0.X.0): New functionality, backward compatible.
    • PATCH (0.0.X): Bug fixes, backward compatible.

    Current Roadmap Examples:

    • 0.9.x: Serializer, spec compliance, PyPI publishing.
    • 1.0.0-rc.x: Production readiness candidates.
    • 1.0.0: Official stable release.
  4. How TOON objects are structured

    main

    TOON (Token-Oriented Object Notation) uses an indentation-based structure similar to YAML for representing objects. Objects consist of key: value pairs.

    Simple Objects

    Represented as direct key-value pairs:

    name: Alice
    age: 30
    active: true

    Nested Objects

    Nesting is achieved through indentation (default is 2 spaces):

    user:
      name: Alice
      settings:
        theme: dark

    Object Keys

    Keys follow identifier rules. If a key contains spaces, leading/trailing whitespace, structural characters (like :, [, {, -), or is a reserved keyword/numeric-looking string, it must be quoted.

    name: Alice
    age: 30
    active: true
    
    user:
      name: Alice
      settings:
        theme: dark
    
    "with space": 4
    "123": 3
  5. How TOON arrays work

    main

    All TOON arrays must include a length indicator [N] for validation. There are three primary array formats depending on the data type:

    1. Primitive Arrays

    Used for arrays of simple values (numbers, strings, booleans). They use an inline comma-separated format. The comma delimiter is hidden in the header.

    [5]: 1,2,3,4,5
    [3]: alpha,beta,gamma

    2. Tabular Arrays

    Used for uniform arrays where every object has the same keys and all values are primitives. This uses a CSV-like format for maximum efficiency.

    • All objects must have identical keys.
    • All values must be primitives (no nesting).
    • The header includes the keys: [N,]{key1,key2}.
    [3,]{id,name,age}:
      1,Alice,30
      2,Bob,25
      3,Charlie,35

    3. List Arrays

    Used for non-uniform or nested arrays (where elements might be different types or contain objects/arrays). These use a - marker for each element.

    [3]:
      - name: Alice
      - 42
      - hello

    4. Nested and Empty Arrays

    • Nested: Arrays within arrays use the list format or primitive format recursively.
    • Empty: Represented by [0]:.
    matrix[2]:
      - [3]: 1,2,3
      - [3]: 4,5,6
    
    items[0]:
    [3,]{id,name,age}:
      1,Alice,30
      2,Bob,25
      3,Charlie,35
  6. Best practices for LLM integration with TOON

    main

    To maximize the efficiency and reliability of using TOON with Large Language Models, follow these patterns:

    • Explicit Prompting: Clearly instruct the model to use the TOON format.
    • Few-Shot Examples: Provide concrete examples of the desired TOON structure within your prompt.
    • Tabular Arrays: For maximum token efficiency (reducing costs by 30-60%), instruct the model to use tabular arrays for uniform objects.
    • Error Recovery: Always wrap your decode() calls in error handling to manage potential model hallucinations or syntax errors gracefully.
    • Consistency: Maintain the use of TOON throughout the entire conversation context.
  7. Commit, Tag, and Release toon_format

    main

    Once the build is verified, follow these steps to trigger the automated publishing process:

    1. Commit version changes to pyproject.toml and src/toon_format/__init__.py.
    2. Create and push a Git tag (e.g., vX.Y.Z).
    3. Publish to PyPI:
      • Go to GitHub Releases.
      • Create a new release using the tag you just pushed.
      • Add release notes and click "Publish release".
      • The GitHub Action will automatically build and publish the package to PyPI.
    # Commit version changes
    git add pyproject.toml src/toon_format/__init__.py
    git commit -m "Bump version to X.Y.Z"
    
    # Create and push tag
    git tag -a vX.Y.Z -m "Release version X.Y.Z"
    git push origin main
    git push origin vX.Y.Z
  8. Prepare and Build the toon_format Package

    main

    Before releasing, you must update the version number in two locations: pyproject.toml (line 3) and src/toon_format/__init__.py (line 28).

    Follow these steps to prepare the build:

    1. Run local quality checks:

      • Tests: uv run pytest
      • Linting: uv run ruff check .
      • Type checking: uv run mypy src/toon_format
    2. Build the package: Clean previous artifacts, build the distribution, and verify the contents.

    3. Verify installation: Install the built .whl file into a fresh virtual environment to ensure it works as expected.

    # Clean previous builds
    rm -rf dist/ build/ *.egg-info
    
    # Build the package
    python -m build
    
    # Verify the package contents
    python -m zipfile -l dist/toon_format-X.Y.Z-py3-none-any.whl
    
    # Test installation in a clean environment
    python -m venv test_env
    test_env/bin/pip install dist/toon_format-X.Y.Z-py3-none-any.whl
    test_env/bin/python -c "import toon_format; print(toon_format.__version__)"
    rm -rf test_env
  9. Validate LLM responses with length markers

    main

    You can use lengthMarker during encoding to provide explicit validation hints to the LLM. By setting lengthMarker to a character like #, the encoded TOON string will include markers (e.g., items[#3]: a,b,c) that tell the model exactly how many items are expected in an array.

    Prompting Tip: Tell the model: "Array lengths are prefixed with #. Ensure your response matches these counts exactly."

    from toon_format import encode
    
    data = {"items": ["a", "b", "c"]}
    toon = encode(data, {"lengthMarker": "#"})
    # Output: items[#3]: a,b,c
  10. Handle TOON decoding errors gracefully

    main

    When decoding LLM-generated strings, always wrap the decode() call in a try-except block to catch ToonDecodeError. This is critical because LLMs may occasionally produce invalid syntax or incorrect array lengths.

    from toon_format import decode, ToonDecodeError
    
    def safe_decode(toon_str):
        try:
            return decode(toon_str)
        except ToonDecodeError as e:
            print(f"TOON decode error: {e}")
            # Fall back to asking model to regenerate or use default
            return None
  11. Prompting LLMs to use TOON format

    main

    To ensure an LLM responds in TOON (Token-Oriented Object Notation), provide explicit format instructions in your system or user prompt. It is recommended to define the syntax rules and provide a structural example.

    Recommended Prompting Rules:

    • Use key: value for objects.
    • Use indentation for nesting.
    • Use [N] to indicate array lengths.
    • Use tabular format [N,]{fields}: for uniform arrays.
    • Always wrap the response in ```toon code blocks to help the model distinguish the format from natural language.
    Respond using TOON format (Token-Oriented Object Notation):
    - Use `key: value` for objects
    - Use indentation for nesting
    - Use `[N]` to indicate array lengths
    - Use tabular format `[N,]{fields}:` for uniform arrays
    
    Example:
    users[2,]{id,name}:
      1,Alice
      2,Bob
  12. Integrate TOON with Pydantic

    main

    Using the toon_format.pydantic.ToonPydanticModel, you can use TOON for structured LLM interactions. This provides a schema that is 50-60% smaller than standard JSON schema.

    Workflow:

    1. Define a model: Inherit from ToonPydanticModel.
    2. Generate Schema: Use User.schema_to_toon() to get a compact TOON representation of your schema for LLM system prompts.
    3. Parse Output: Use User.model_validate_toon(toon_output) to convert LLM-generated TOON strings into validated Pydantic objects.
    4. Serialize: Use user.model_dump_toon() to convert a model instance back to a TOON string.
    from toon_format.pydantic import ToonPydanticModel
    
    class User(ToonPydanticModel):
        name: str
        age: int
        email: str | None = None
    
    # 1. Schema for LLM
    schema_toon = User.schema_to_toon()
    
    # 2. Parse LLM output
    toon_output = "name:Ansar,age:25,email:ansar@example.com"
    user = User.model_validate_toon(toon_output)
    
    # 3. Serialize instance
    toon_str = user.model_dump_toon()