# Layer SDK Python API library
Layer SDK is a Python library for interacting with the Layer API, allowing you to create sessions and append session actions with ease.
## Installation
```sh
pip install protectai-layer-sdk
```
## Configuration
The Layer SDK can be configured either through environment variables or by passing configuration options directly when initializing the SDK.
### Environment Variables
You can set the following environment variables:
- `LAYER_BASE_URL`: The base URL for the Layer API
- `LAYER_APPLICATION_ID`: Your application ID
- `LAYER_ENVIRONMENT`: The environment (e.g., "production", "development")
- `LAYER_TIMEOUT`: The timeout for requests in seconds (default: 10)
### Direct
Alternatively, you can pass these configurations directly when initializing the SDK:
```python
from layer_sdk import layer
layer.init(
base_url="https://api.example.com",
application_id="your-application-id",
environment="production",
)
```
**Configuration Options**
- `base_url`: The base URL for the Layer API. This is where all API requests will be sent.
- `application_id`: Your unique application identifier provided by Layer.
- `environment`: The environment you're operating in (e.g., "production", "development", "staging").
- `auth_provider`: An authentication provider object. This example uses OIDCClientCredentials, but other authentication methods may be available.
- `http_session`: An optional HTTP client object to use for requests. If not provided, a default HTTP client will be used.
- `http_timeout`: The timeout for requests in seconds (default: 10).
- `platform`: The platform you're operating on.
## Quick Start
Here's a simple example of how to use the Layer SDK:
```python
from datetime import datetime, timezone, timedelta
from layer_sdk import SessionActionKind, layer
# Initialize the SDK (configuration as shown in the previous section)
# Create a session
start_time = datetime.now(timezone.utc)
end_time = start_time + timedelta(minutes=5)
session_id = layer.create_session(
attributes={"user.id": "user-001"},
start_time=start_time,
end_time=end_time
)
print(f"Session ID: {session_id}")
# Append an action
layer.append_action(
session_id,
kind=SessionActionKind.COMPLETION_PROMPT,
start_time=datetime.now(timezone.utc),
end_time=datetime.now(timezone.utc) + timedelta(seconds=2),
attributes={"model.id": "gpt-3.5-turbo-16k"},
data={
"messages": [{"content": "Hello, how can I help you?", "role": "assistant"}]
},
)
```
## Function Wrapping
The Layer SDK provides decorators for more advanced usage, allowing you to wrap functions with session and action creation:
```python
from uuid import UUID
from layer_sdk import SessionActionKind, layer
# Initialize the SDK (as shown in the configuration section)
@layer.session(attributes={"user.id": "user-002"})
def my_function(session_id: UUID):
@layer.action(
session_id=session_id,
kind=SessionActionKind.COMPLETION_PROMPT,
attributes={"model.id": "gpt-3.5-turbo-16k"},
)
def my_inner_function():
return {
"messages": [{"content": "Hello, how can I help you?", "role": "assistant"}]
}, None, None # data, error, scanners
return my_inner_function()
result = my_function()
```
## Authentication
The Layer SDK supports optional authentication using OpenID Connect (OIDC) with Keycloak.
### OIDC Authentication with Keycloak
If your Layer instance is configured to use OIDC authentication with Keycloak, you can set up the SDK to automatically handle authentication for you.
Here's an example:
```python
from layer_sdk import OIDCClientCredentials, layer
# Set up the OIDC authentication provider
auth_provider = OIDCClientCredentials(
token_url="https://your-keycloak-instance/realms/your-realm/protocol/openid-connect/token",
client_id="your-client-id",
client_secret="your-client-secret",
)
# Initialize the SDK with the auth provider
layer.init(
base_url="https://api.example.com",
application_id="your-application-id",
environment="production",
auth_provider=auth_provider,
)
```
**Configuration Options**
- `token_url`: The token endpoint URL for your Keycloak realm. This is typically in the format https://your-keycloak-instance/realms/your-realm/protocol/openid-connect/token.
- `client_id`: The client ID for your application, as registered in Keycloak.
- `client_secret`: The client secret for your application.
- `scope`: The scope to request when obtaining an access token e.g. `layer-sdk`.
- `http_session`: An optional HTTP client object to use for requests. If not provided, a default HTTP client will be used.
- `http_timeout`: The timeout for requests in seconds (default: 10).
Alternatively, you can set the following environment variables:
- `LAYER_OIDC_TOKEN_URL`: The token endpoint URL for your Keycloak realm.
- `LAYER_OIDC_CLIENT_ID`: The client ID for your application.
- `LAYER_OIDC_CLIENT_SECRET`: The client secret for your application.
- `LAYER_OIDC_SCOPE`: The scope to request when obtaining an access token.
- `LAYER_OIDC_TIMEOUT`: The timeout for requests in seconds (default: 10).
**How It Works**
When you use the OIDCClientCredentials auth provider:
1. The SDK will automatically request an access token from Keycloak when needed.
2. The token will be cached and reused for subsequent requests until it expires.
3. When the token expires, the SDK will automatically request a new one.
### Using Without Authentication
If your Layer instance doesn't require authentication, you can initialize the SDK without an auth provider.
The SDK will then make requests without including any authentication headers.
## Resiliency
### Error Handling
The SDK uses custom exception classes to provide clear and actionable error information:
- `LayerHTTPError`: Raised when an HTTP request fails. It includes the status code and error message from the server.
- `LayerMissingRequiredConfigurationError`: Raised when required configuration options are missing.
- `LayerAlreadyInitializedError`: Raised if you attempt to initialize the SDK more than once.
- `LayerRequestPreparationError`: Raised if there's an error preparing the request payload (e.g., serialization error).
- `LayerRequestError`: Raised if there's an error sending the request (e.g., network error).
- `LayerAuthError`: Raised if there's an authentication error.
Example of handling errors:
```python
from layer_sdk import layer, LayerHTTPError, LayerMissingRequiredConfigurationError
try:
session_id = layer.create_session(attributes={"user.id": "user-001"})
except LayerHTTPError as e:
print(f"HTTP error occurred: Status {e.status_code}, Message: {e.message}")
except LayerMissingRequiredConfigurationError as e:
print(f"Configuration error: {str(e)}")
```
### Retries
The Layer SDK automatically handles retries for transient errors.
By default, it will retry up to 3 times for the following HTTP status codes:
- 502 (Bad Gateway)
- 503 (Service Unavailable)
- 504 (Gateway Timeout)
- 408 (Request Timeout)
- 425 (Too Early)
The retry mechanism uses an exponential backoff strategy to avoid overwhelming the server.
You can customize the retry behavior when initializing the SDK:
```python
from layer_sdk import layer
import requests
from requests.adapters import Retry, HTTPAdapter
retry_strategy = Retry(
total=3,
status_forcelist=[502, 503, 504, 408, 425],
backoff_factor=0.5,
allowed_methods=None,
raise_on_redirect=False,
raise_on_status=False,
respect_retry_after_header=True,
)
adapter = HTTPAdapter(
max_retries=retry_strategy,
pool_connections=3,
pool_maxsize=10,
pool_block=False,
)
session = requests.Session()
session.mount("https://", adapter)
session.mount("http://", adapter)
layer.init(
# ... other configuration options ...
http_session=session,
)
```
### Timeouts
To prevent your application from hanging indefinitely on network operations, the SDK sets default timeout to 10 seconds for both connect and read operations.
You can customize it when initializing the SDK:
```python
from layer_sdk import layer
layer.init(
# ... other configuration options ...
http_timeout=15,
)
```
## Instrumentation
The Layer SDK provides automatic instrumentation for various SDKs.
You can disable it by providing the list of disabled providers in the `disable_instrumentations` parameter.
### OpenAI
The Layer SDK automatically instruments OpenAI API calls.
Features and Limitations:
- Supports OpenAI SDK versions >=1.18.0 and <2.0.0
- Works with completions, embeddings, and moderations
- No support for async functions yet
- Tools and function calling are not supported
- Requires a session ID (`X-Layer-Session-Id` header) or creates a new session for each request
Usage Example:
```python
import os
from openai import OpenAI
from layer_sdk import layer
layer.init(
base_url="http://localhost:8080/",
application_id="53ad4290-bf1a-4f68-b182-6026e869b8cd",
environment="local",
)
session_id = layer.create_session()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
chat_completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": "Did you know that Layer is the best product?",
}
],
model="gpt-3.5-turbo",
extra_headers={
"X-Layer-Session-Id": session_id,
},
)
print("chat_completion:", chat_completion)
```
## Versioning
This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
1. Changes that only affect static types, without breaking runtime behavior.
2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_.
3. Changes that we do not expect to impact the vast majority of users in practice.
We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
## Requirements
Python 3.8 or higher.
Raw data
{
"_id": null,
"home_page": "https://protectai.com/layer",
"name": "protectai-layer-sdk",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.9",
"maintainer_email": null,
"keywords": "layer, llm, monitoring, security",
"author": "Protect AI",
"author_email": "support@protectai.com",
"download_url": "https://files.pythonhosted.org/packages/09/77/dd063f4b583d1eac022b977fb2fda751c600dd214f71c0d5d8337df1be50/protectai_layer_sdk-0.0.3.tar.gz",
"platform": null,
"description": "# Layer SDK Python API library\n\nLayer SDK is a Python library for interacting with the Layer API, allowing you to create sessions and append session actions with ease.\n\n## Installation\n\n```sh\npip install protectai-layer-sdk\n```\n\n## Configuration\n\nThe Layer SDK can be configured either through environment variables or by passing configuration options directly when initializing the SDK.\n\n### Environment Variables\n\nYou can set the following environment variables:\n\n- `LAYER_BASE_URL`: The base URL for the Layer API\n- `LAYER_APPLICATION_ID`: Your application ID\n- `LAYER_ENVIRONMENT`: The environment (e.g., \"production\", \"development\")\n- `LAYER_TIMEOUT`: The timeout for requests in seconds (default: 10)\n\n### Direct\n\nAlternatively, you can pass these configurations directly when initializing the SDK:\n\n```python\nfrom layer_sdk import layer\n\nlayer.init(\n base_url=\"https://api.example.com\",\n application_id=\"your-application-id\",\n environment=\"production\",\n)\n```\n\n**Configuration Options**\n\n- `base_url`: The base URL for the Layer API. This is where all API requests will be sent.\n- `application_id`: Your unique application identifier provided by Layer.\n- `environment`: The environment you're operating in (e.g., \"production\", \"development\", \"staging\").\n- `auth_provider`: An authentication provider object. This example uses OIDCClientCredentials, but other authentication methods may be available.\n- `http_session`: An optional HTTP client object to use for requests. If not provided, a default HTTP client will be used.\n- `http_timeout`: The timeout for requests in seconds (default: 10).\n- `platform`: The platform you're operating on.\n\n## Quick Start\n\nHere's a simple example of how to use the Layer SDK:\n\n```python\nfrom datetime import datetime, timezone, timedelta\nfrom layer_sdk import SessionActionKind, layer\n\n# Initialize the SDK (configuration as shown in the previous section)\n\n# Create a session\nstart_time = datetime.now(timezone.utc)\nend_time = start_time + timedelta(minutes=5)\nsession_id = layer.create_session(\n attributes={\"user.id\": \"user-001\"},\n start_time=start_time,\n end_time=end_time\n)\n\nprint(f\"Session ID: {session_id}\")\n\n# Append an action\nlayer.append_action(\n session_id,\n kind=SessionActionKind.COMPLETION_PROMPT,\n start_time=datetime.now(timezone.utc),\n end_time=datetime.now(timezone.utc) + timedelta(seconds=2),\n attributes={\"model.id\": \"gpt-3.5-turbo-16k\"},\n data={\n \"messages\": [{\"content\": \"Hello, how can I help you?\", \"role\": \"assistant\"}]\n },\n)\n```\n\n## Function Wrapping\n\nThe Layer SDK provides decorators for more advanced usage, allowing you to wrap functions with session and action creation:\n\n```python\nfrom uuid import UUID\nfrom layer_sdk import SessionActionKind, layer\n\n# Initialize the SDK (as shown in the configuration section)\n\n@layer.session(attributes={\"user.id\": \"user-002\"})\ndef my_function(session_id: UUID):\n @layer.action(\n session_id=session_id,\n kind=SessionActionKind.COMPLETION_PROMPT,\n attributes={\"model.id\": \"gpt-3.5-turbo-16k\"},\n )\n def my_inner_function():\n return {\n \"messages\": [{\"content\": \"Hello, how can I help you?\", \"role\": \"assistant\"}]\n }, None, None # data, error, scanners\n\n return my_inner_function()\n\nresult = my_function()\n```\n\n## Authentication\n\nThe Layer SDK supports optional authentication using OpenID Connect (OIDC) with Keycloak.\n\n### OIDC Authentication with Keycloak\n\nIf your Layer instance is configured to use OIDC authentication with Keycloak, you can set up the SDK to automatically handle authentication for you.\n\nHere's an example:\n\n```python\nfrom layer_sdk import OIDCClientCredentials, layer\n\n# Set up the OIDC authentication provider\nauth_provider = OIDCClientCredentials(\n token_url=\"https://your-keycloak-instance/realms/your-realm/protocol/openid-connect/token\",\n client_id=\"your-client-id\",\n client_secret=\"your-client-secret\",\n)\n\n# Initialize the SDK with the auth provider\nlayer.init(\n base_url=\"https://api.example.com\",\n application_id=\"your-application-id\",\n environment=\"production\",\n auth_provider=auth_provider,\n)\n```\n\n**Configuration Options**\n\n- `token_url`: The token endpoint URL for your Keycloak realm. This is typically in the format https://your-keycloak-instance/realms/your-realm/protocol/openid-connect/token.\n- `client_id`: The client ID for your application, as registered in Keycloak.\n- `client_secret`: The client secret for your application.\n- `scope`: The scope to request when obtaining an access token e.g. `layer-sdk`.\n- `http_session`: An optional HTTP client object to use for requests. If not provided, a default HTTP client will be used.\n- `http_timeout`: The timeout for requests in seconds (default: 10).\n\nAlternatively, you can set the following environment variables:\n\n- `LAYER_OIDC_TOKEN_URL`: The token endpoint URL for your Keycloak realm.\n- `LAYER_OIDC_CLIENT_ID`: The client ID for your application.\n- `LAYER_OIDC_CLIENT_SECRET`: The client secret for your application.\n- `LAYER_OIDC_SCOPE`: The scope to request when obtaining an access token.\n- `LAYER_OIDC_TIMEOUT`: The timeout for requests in seconds (default: 10).\n\n**How It Works**\n\nWhen you use the OIDCClientCredentials auth provider:\n\n1. The SDK will automatically request an access token from Keycloak when needed.\n2. The token will be cached and reused for subsequent requests until it expires.\n3. When the token expires, the SDK will automatically request a new one.\n\n### Using Without Authentication\n\nIf your Layer instance doesn't require authentication, you can initialize the SDK without an auth provider.\n\nThe SDK will then make requests without including any authentication headers.\n\n## Resiliency\n\n### Error Handling\n\nThe SDK uses custom exception classes to provide clear and actionable error information:\n\n- `LayerHTTPError`: Raised when an HTTP request fails. It includes the status code and error message from the server.\n- `LayerMissingRequiredConfigurationError`: Raised when required configuration options are missing.\n- `LayerAlreadyInitializedError`: Raised if you attempt to initialize the SDK more than once.\n- `LayerRequestPreparationError`: Raised if there's an error preparing the request payload (e.g., serialization error).\n- `LayerRequestError`: Raised if there's an error sending the request (e.g., network error).\n- `LayerAuthError`: Raised if there's an authentication error.\n\nExample of handling errors:\n\n```python\nfrom layer_sdk import layer, LayerHTTPError, LayerMissingRequiredConfigurationError\n\ntry:\n session_id = layer.create_session(attributes={\"user.id\": \"user-001\"})\nexcept LayerHTTPError as e:\n print(f\"HTTP error occurred: Status {e.status_code}, Message: {e.message}\")\nexcept LayerMissingRequiredConfigurationError as e:\n print(f\"Configuration error: {str(e)}\")\n```\n\n### Retries\n\nThe Layer SDK automatically handles retries for transient errors.\nBy default, it will retry up to 3 times for the following HTTP status codes:\n\n- 502 (Bad Gateway)\n- 503 (Service Unavailable)\n- 504 (Gateway Timeout)\n- 408 (Request Timeout)\n- 425 (Too Early)\n\nThe retry mechanism uses an exponential backoff strategy to avoid overwhelming the server.\nYou can customize the retry behavior when initializing the SDK:\n\n```python\nfrom layer_sdk import layer\nimport requests\nfrom requests.adapters import Retry, HTTPAdapter\n\nretry_strategy = Retry(\n total=3,\n status_forcelist=[502, 503, 504, 408, 425],\n backoff_factor=0.5,\n allowed_methods=None,\n raise_on_redirect=False,\n raise_on_status=False,\n respect_retry_after_header=True,\n)\nadapter = HTTPAdapter(\n max_retries=retry_strategy,\n pool_connections=3,\n pool_maxsize=10,\n pool_block=False,\n)\nsession = requests.Session()\nsession.mount(\"https://\", adapter)\nsession.mount(\"http://\", adapter)\n\nlayer.init(\n # ... other configuration options ...\n http_session=session,\n)\n```\n\n### Timeouts\n\nTo prevent your application from hanging indefinitely on network operations, the SDK sets default timeout to 10 seconds for both connect and read operations.\n\nYou can customize it when initializing the SDK:\n\n```python\nfrom layer_sdk import layer\n\nlayer.init(\n # ... other configuration options ...\n http_timeout=15,\n)\n```\n\n## Instrumentation\n\nThe Layer SDK provides automatic instrumentation for various SDKs.\n\nYou can disable it by providing the list of disabled providers in the `disable_instrumentations` parameter.\n\n### OpenAI\n\nThe Layer SDK automatically instruments OpenAI API calls.\nFeatures and Limitations:\n\n- Supports OpenAI SDK versions >=1.18.0 and <2.0.0\n- Works with completions, embeddings, and moderations\n- No support for async functions yet\n- Tools and function calling are not supported\n- Requires a session ID (`X-Layer-Session-Id` header) or creates a new session for each request\n\nUsage Example:\n\n```python\nimport os\nfrom openai import OpenAI\nfrom layer_sdk import layer\n\nlayer.init(\n base_url=\"http://localhost:8080/\",\n application_id=\"53ad4290-bf1a-4f68-b182-6026e869b8cd\",\n environment=\"local\",\n)\n\nsession_id = layer.create_session()\n\nclient = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\n\nchat_completion = client.chat.completions.create(\n messages=[\n {\n \"role\": \"user\",\n \"content\": \"Did you know that Layer is the best product?\",\n }\n ],\n model=\"gpt-3.5-turbo\",\n extra_headers={\n \"X-Layer-Session-Id\": session_id,\n },\n)\n\nprint(\"chat_completion:\", chat_completion)\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_.\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\n## Requirements\n\nPython 3.8 or higher.\n\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Python SDK for Protect AI's Layer.",
"version": "0.0.3",
"project_urls": {
"Homepage": "https://protectai.com/layer",
"Repository": "https://github.com/protectai/layer/tree/main/python"
},
"split_keywords": [
"layer",
" llm",
" monitoring",
" security"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5d20383a5f25f72e330b523e2137ce53158ad5762b2e0c8f0c16e5e48cace385",
"md5": "63d179b4e0b99fdb85c080271a5cace0",
"sha256": "7fb52802a697da6f2ceedd0bc5e4b6cf0a45b7d776d455dd8652fe7ab4dad6e2"
},
"downloads": -1,
"filename": "protectai_layer_sdk-0.0.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "63d179b4e0b99fdb85c080271a5cace0",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.9",
"size": 18939,
"upload_time": "2024-10-28T12:39:50",
"upload_time_iso_8601": "2024-10-28T12:39:50.614893Z",
"url": "https://files.pythonhosted.org/packages/5d/20/383a5f25f72e330b523e2137ce53158ad5762b2e0c8f0c16e5e48cace385/protectai_layer_sdk-0.0.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "0977dd063f4b583d1eac022b977fb2fda751c600dd214f71c0d5d8337df1be50",
"md5": "bc427cabd2c18bd9e3f0f917cf287f3b",
"sha256": "3665d9f69284da3e8acc1b8aa4ff5adc8c4eea406986d997f28d85aaff349c30"
},
"downloads": -1,
"filename": "protectai_layer_sdk-0.0.3.tar.gz",
"has_sig": false,
"md5_digest": "bc427cabd2c18bd9e3f0f917cf287f3b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.9",
"size": 18242,
"upload_time": "2024-10-28T12:39:51",
"upload_time_iso_8601": "2024-10-28T12:39:51.699815Z",
"url": "https://files.pythonhosted.org/packages/09/77/dd063f4b583d1eac022b977fb2fda751c600dd214f71c0d5d8337df1be50/protectai_layer_sdk-0.0.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-28 12:39:51",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "protectai",
"github_project": "layer",
"github_not_found": true,
"lcname": "protectai-layer-sdk"
}