Skip to main content

The Liminal SDK for Python

Project description

Liminal Python SDK

PyPI Version License

The Liminal SDK for Python provides a clean, straightforward, asyncio-based interface for interacting with the Liminal API.

Installation

pip install liminal-sdk-python

Python Versions

liminal is currently supported on:

  • Python 3.11
  • Python 3.12

Quickstart

Presuming the use of Microsoft Entra ID as your auth provider, instantiating a Liminal API object is easy:

import asyncio

from liminal import Client
from liminal.endpoints.auth import MicrosoftAuthProvider


async def main() -> None:
    """Create the aiohttp session and run the example."""
    logging.basicConfig(level=logging.DEBUG)

    # Create an auth provider to authenticate the user:
    microsoft_auth_provider = MicrosoftAuthProvider("<TENANT_ID>", "<CLIENT_ID>")

    # Create the liminal SDK instance:
    liminal = Client(microsoft_auth_provider, "<LIMINAL_API_SERVER_URL>")


asyncio.run(main())

You can see several examples of how to use this API object via the examples folder in this repo.

Initial Authentication

Liminal supports the concept of authenticating via various auth providers. Currently, the following auth providers are supported:

  • Microsoft Entra ID

Microsoft Entra ID

Liminal authenticates with Microsoft Entra ID via an OAuth 2.0 Device Authorization Grant. This flow requires you to start your app, retrieve a device code from the logs produced by this SDK, and provide that code to Microsoft via a web browser. Once you complete the login process, the SDK will be authenticated for use with your Liminal instance.

Finding your Entra ID Tenant and Client IDs

  • Log into your Azure portal.
  • Navigate to Microsoft Entra ID.
  • Click on App registrations.
  • Either create a new app registration or select an existing one.
  • In the Overview of the registration, look for the Application (client) ID and Directory (tenant) ID values.

Authenticating Against Entra ID

With a client ID and tenant ID, you can create a Liminal client object and authenticate it:

import asyncio

from liminal import Client
from liminal.endpoints.auth import MicrosoftAuthProvider


async def main() -> None:
    """Create the aiohttp session and run the example."""
    logging.basicConfig(level=logging.DEBUG)

    # Create an auth provider to authenticate the user:
    microsoft_auth_provider = MicrosoftAuthProvider("<TENANT_ID>", "<CLIENT_ID>")

    # Create the liminal SDK instance and authenticate it:
    liminal = Client(microsoft_auth_provider, "<LIMINAL_API_SERVER_URL>")
    await liminal.authenticate_from_auth_provider()


asyncio.run(main())

In your application logs, you will see a message that looks like this:

INFO:liminal:To sign in, use a web browser to open the page
https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.

Leaving your application running, open a browser at that URL and input the code as instructed. Once you successfully complete authentication via Entra ID, your Liminal client object will automatically authenticate with your Liminal API server.

Ongoing Authentication

After the initial authentication with your auth provider, the Liminal client object will internally store access and refresh tokens to ensure the ongoing ability to communicate with your Liminal API server. The client object will automatically handle using the stored refresh token to request new access tokens as appropriate.

Manually Interacting with the Refresh Token

The Liminal client object provides a add_refresh_token_callback method to manually interact with refresh tokens as they are generated. This is useful in situations where you want to retrieve that token and do something else with (store it in a database, for example). Every time a new refresh token is generated by the client object, the registered callbacks will be called.

Refresh token callbacks are methods that take a single str parameter (denoting the refresh token). These callbacks are not expected to return any value. Lastly, when calling add_refresh_token_callback, the returned method allows you to cancel the callback at any time.

import asyncio

from liminal import Client
from liminal.endpoints.auth import MicrosoftAuthProvider


async def main() -> None:
    """Create the aiohttp session and run the example."""
    logging.basicConfig(level=logging.DEBUG)

    # Create an auth provider to authenticate the user:
    microsoft_auth_provider = MicrosoftAuthProvider("<TENANT_ID>", "<CLIENT_ID>")

    # Create the liminal SDK instance and authenticate it:
    liminal = Client(microsoft_auth_provider, "<LIMINAL_API_SERVER_URL>")
    await liminal.authenticate_from_auth_provider()

    def do_something_with_refresh_token(refresh_token: str) -> None:
        """Do something with the refresh token."""
        pass

    # Register the refresh token callback:
    remove_callback = liminal.add_refresh_token_callback(
        do_something_with_refresh_token
    )

    # Later, if you want to remove the callback:
    remove_callback()


asyncio.run(main())

Getting Model Instances

Every LLM instance connected in the Liminal admin dashboard is referred to as a "model instance." The SDK provides several methods to interact with model instances:

import asyncio

from liminal import Client
from liminal.endpoints.auth import MicrosoftAuthProvider


async def main() -> None:
    # Assuming you have an authenticated `liminal` object:

    # Get all available model instances:
    model_instances = await liminal.llm.get_available_model_instances()
    # >>> [ModelInstance(...), ModelInstance(...)]

    # Get a specific model instance (if it exists):
    model_instance = await liminal.llm.get_model_instance("My Model")
    # >>> ModelInstance(...)


asyncio.run(main())

Managing Threads

Threads are conversations with an LLM instance:

import asyncio

from liminal import Client
from liminal.endpoints.auth import MicrosoftAuthProvider


async def main() -> None:
    # Assuming you have an authenticated `liminal` object:

    # Get all available threads:
    threads = await liminal.thread.get_available()
    # >>> [Thread(...), Thread(...)]

    # Get a specific thread by ID:
    thread = await liminal.thread.get_by_id(123)
    # >>> Thread(...)

    # Some operations require a model instance:
    model_instance = await liminal.llm.get_model_instance("My Model")

    # Create a new thread:
    thread = await liminal.thread.create(model_instance.id, "New Thread")
    # >>> Thread(...)

    # Get the "de-identified" (containing sensitive data) context history for a thread:
    thread = await liminal.thread.get_deidentified_context_history(model_instance.id)
    # >>> [DeidentifiedToken(...), DeidentifiedToken(...), DeidentifiedToken(...)]


asyncio.run(main())

Submitting Prompts

Submitting prompts is easy:

import asyncio

from liminal import Client
from liminal.endpoints.auth import MicrosoftAuthProvider


async def main() -> None:
    # Assuming you have an authenticated `liminal` object:

    # Prompt operations require a thread:
    thread = await liminal.thread.get_by_id(123)
    # >>> Thread(...)

    # Analayze a prompt for sensitive info:
    findings = await liminal.prompt.analyze(thread.id)
    # >>> AnalyzeResponse(...)

    # Cleanse input text by applying the policies defined in the Liminal admin
    # dashboard. You can optionally provide existing analysis finidings; if not
    # provided, analyze is # called automatically):
    cleansed = await liminal.prompt.cleanse(
        thread.id, "Here is a sensitive prompt", findings=findings
    )
    # >>> CleanseResponse(...)

    # Submit a prompt to an LLM, cleansing it in the process (once again, providing optional
    # findings):
    response = await liminal.prompt.submit(
        thread.id, "Here is a sensitive prompt", findings=findings
    )
    # >>> ProcessResponse(...)

    # Rehydrate a response with sensitive data:
    hydrated = await liminal.prompt.hydrate(
        thread.id, "Here is a response to rehdyrate"
    )
    # >>> HydrateResponse(...)


asyncio.run(main())

Running Examples

You can see examples of how to use this SDK via the examples folder in this repo. Each example follows a similar "call" format by asking for inputs via environment variables; for example:

LIMINAL_API_SERVER_URL=https://api.DOMAIN.liminal.ai \
CLIENT_ID=xxxxxxxxxxxxxxxx \
TENANT_ID=xxxxxxxxxxxxxxxx \
MODEL_INSTANCE_NAME=model-instance-name \
python3 examples/quickstart_with_microsoft.py

Contributing

Thanks to all of our contributors so far!

  1. Check for open features/bugs or initiate a discussion on one.
  2. Fork the repository.
  3. (optional, but highly recommended) Create a virtual environment: python3 -m venv .venv
  4. (optional, but highly recommended) Enter the virtual environment: source ./.venv/bin/activate
  5. Install the dev environment: script/setup
  6. Code your new feature or bug fix on a new branch.
  7. Write tests that cover your new functionality.
  8. Run tests and ensure 100% code coverage: poetry run pytest --cov liminal tests
  9. Update README.md with any new documentation.
  10. Submit a pull request!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

liminal_sdk_python-2024.3.3.tar.gz (20.4 kB view details)

Uploaded Source

Built Distribution

liminal_sdk_python-2024.3.3-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file liminal_sdk_python-2024.3.3.tar.gz.

File metadata

  • Download URL: liminal_sdk_python-2024.3.3.tar.gz
  • Upload date:
  • Size: 20.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.2 CPython/3.11.8 Linux/6.5.0-1016-azure

File hashes

Hashes for liminal_sdk_python-2024.3.3.tar.gz
Algorithm Hash digest
SHA256 8e32e9b9489a7b948909e23e1b13136bad806814daf38e977299e486dee16c98
MD5 34aae47273f28f7f3d2d646f590c04be
BLAKE2b-256 26f86637ec190362cbd0ab5c57ed2b543b48fd840abb18c018f010b2f0100bc1

See more details on using hashes here.

File details

Details for the file liminal_sdk_python-2024.3.3-py3-none-any.whl.

File metadata

File hashes

Hashes for liminal_sdk_python-2024.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 df602893ad4e08d1d83795b7d1635d7db12c05905e349bc249c54b06fd3bb0cf
MD5 28722dccf03ccac5c1d3f3873fd0f4bd
BLAKE2b-256 20950d8dbec354c20d6b8f64151a0fd82dfbbdd3e6d3aed63baea09a0c00bdac

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page