crystil 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crystil-0.8.0/CONTRIBUTE.md +138 -0
- crystil-0.8.0/MANIFEST.in +14 -0
- crystil-0.8.0/PKG-INFO +49 -0
- crystil-0.8.0/README.md +29 -0
- crystil-0.8.0/crystil/__init__.py +102 -0
- crystil-0.8.0/crystil/_base.py +443 -0
- crystil-0.8.0/crystil/_clients.py +788 -0
- crystil-0.8.0/crystil/_config.py +19 -0
- crystil-0.8.0/crystil/_constants.py +16 -0
- crystil-0.8.0/crystil/_errors.py +2 -0
- crystil-0.8.0/crystil/_invoke.py +190 -0
- crystil-0.8.0/crystil/_iterable.py +59 -0
- crystil-0.8.0/crystil/_iterator.py +82 -0
- crystil-0.8.0/crystil/_network.py +133 -0
- crystil-0.8.0/crystil/_providers.py +74 -0
- crystil-0.8.0/crystil/_sentinel.py +32 -0
- crystil-0.8.0/crystil/_streaming.py +55 -0
- crystil-0.8.0/crystil/_utils.py +55 -0
- crystil-0.8.0/crystil/api/_invocation.py +39 -0
- crystil-0.8.0/crystil/api/_workflow.py +26 -0
- crystil-0.8.0/crystil.egg-info/PKG-INFO +49 -0
- crystil-0.8.0/crystil.egg-info/SOURCES.txt +25 -0
- crystil-0.8.0/crystil.egg-info/dependency_links.txt +1 -0
- crystil-0.8.0/crystil.egg-info/requires.txt +5 -0
- crystil-0.8.0/crystil.egg-info/top_level.txt +3 -0
- crystil-0.8.0/pyproject.toml +77 -0
- crystil-0.8.0/setup.cfg +4 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Python SDK
|
|
2
|
+
|
|
3
|
+
The Python SDK allows customers who have a Python solution to integrate with Crystil. Below are steps to get the SDK working on your local environment. Since we are a Python shop, this is the 1st SDK that gets updated, and this is the SDK we use to test with most.
|
|
4
|
+
|
|
5
|
+
## Supports
|
|
6
|
+
|
|
7
|
+
Currently the Python SDK supports the following LLM Clients:
|
|
8
|
+
|
|
9
|
+
- Anthropic version 0.76.0 - Official version from Anthropic
|
|
10
|
+
- Google GenAI - Official version from Google
|
|
11
|
+
- Groq version 1.2.0 - Runs many open source LLMs
|
|
12
|
+
- LangChain version 0.3.27 - Works with LangChain framework that works with many LLMs
|
|
13
|
+
- Open AI version 2.15.0 - Official version from Open AI
|
|
14
|
+
- Pydantic version 0.8.1 - Works with Pydantic framework that works with many LLMs
|
|
15
|
+
|
|
16
|
+
## Prerequisites
|
|
17
|
+
|
|
18
|
+
### Install UV
|
|
19
|
+
|
|
20
|
+
The Python SDK uses UV as the package/project manager, so if you don't already have this installed, install it.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
brew install uv
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Install Python SDK
|
|
27
|
+
|
|
28
|
+
Get the source code:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
cd ~/src/payloop
|
|
32
|
+
git clone git@github.com:CrystilAI/python-sdk.git
|
|
33
|
+
cd ~/src/payloop/python-sdk
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Install dependencies and create venv:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
uv sync
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Tests
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
uv run pytest
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
To run integration tests, you need to add the following keys/credentials to the environment. Note you can just set a subset of these keys if you just want to test some of the integrations.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
cp .env.example .env
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- **ANTHROPIC_API_KEY** - Valid Anthropic LLM key used for Anthropic tests.
|
|
55
|
+
- **AWS_ACCESS_KEY_ID** - The AWS access key used for LangChain Bedrock tests.
|
|
56
|
+
- **AWS_SECRET_ACCESS_KEY** - The AWS secret access key used for LangChain Bedrock tests.
|
|
57
|
+
- **AWS_DEFAULT_REGION** - The AWS default region used for LangChain Bedrock tests. Currently it is `us-east-1`.
|
|
58
|
+
- **GOOGLE_APPLICATION_CREDENTIALS** - Local path to your Google credentials file. This is used for LangChain Google and Vertex tests.
|
|
59
|
+
- **GOOGLE_API_KEY** - Google API Key used for Google tests.
|
|
60
|
+
- **GROQ_API_KEY** - Groq API Key used for Groq tests.
|
|
61
|
+
- **OPENAI_API_KEY** - Valid OpenAI LLM key used for OpenAI tests.
|
|
62
|
+
- **OPENROUTER_API_KEY** - Valid Open Router AI key used to test Pydantic AI.
|
|
63
|
+
- **CRYSTIL_API_KEY** - Crystil API key. Log into desired environment (production, staging, or local) and get the production API key there.
|
|
64
|
+
|
|
65
|
+
Run integration tests:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uv run pytest --integration
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## GitHub Actions Workflows
|
|
72
|
+
|
|
73
|
+
Shortly after Python SDK `0.6.0` was released, we added GitHub Actions workflows for running both unit tests and integration tests.
|
|
74
|
+
|
|
75
|
+
In the GitHub free plan, you have limits on GitHub Actions usage:
|
|
76
|
+
https://docs.github.com/en/billing/concepts/product-billing/github-actions#free-use-of-github-actions
|
|
77
|
+
|
|
78
|
+
As of this writing, the free plan has 2,000 minutes available per month and 10 GB of cache storage.
|
|
79
|
+
|
|
80
|
+
Unit and integration test runs will be counted against the minutes available.
|
|
81
|
+
|
|
82
|
+
If the Crystil GitHub account starts running low on available minutes (at 80% usage), an email will be sent to GitHub account administrators.
|
|
83
|
+
|
|
84
|
+
### Unit test suite runs
|
|
85
|
+
|
|
86
|
+
Unit tests will run upon:
|
|
87
|
+
|
|
88
|
+
- Every push to a branch that has a PR opened
|
|
89
|
+
- Every push to `main`
|
|
90
|
+
|
|
91
|
+
This "Run Unit Tests" workflow is defined in this file:
|
|
92
|
+
https://github.com/CrystilAI/backend/blob/main/.github/workflows/run-tests.yml
|
|
93
|
+
|
|
94
|
+
Upon these events, any pytest tests NOT marked with `@pytest.mark.integration` will be run.
|
|
95
|
+
|
|
96
|
+
Any tests marked with `@pytest.mark.integration` will ONLY run as part of the integration test suite.
|
|
97
|
+
|
|
98
|
+
Unit tests will NOT run for any branch whose PR title has `[WIP]` present. This allows us to not run the tests on a branch that's actively in development, which allows us to save on GitHub Actions minutes usage.
|
|
99
|
+
|
|
100
|
+
The unit tests are run against Python versions 3.9, 3.10, 3.11, 3.12, and 3.13.
|
|
101
|
+
|
|
102
|
+
As of this writing, some Python packages that we depend on have not been updated for Python 3.14. Python 3.14 was released in October 2025. Apparently it's common for Python packages to not be updated until 6-12 months after releases.
|
|
103
|
+
|
|
104
|
+
#### Viewing unit test suite runs in GitHub UI
|
|
105
|
+
|
|
106
|
+
The GitHub Actions page for the Python SDK can be found at:
|
|
107
|
+
https://github.com/CrystilAI/python-sdk/actions
|
|
108
|
+
|
|
109
|
+
### Integration test suite runs
|
|
110
|
+
|
|
111
|
+
The integration test suite is run against the Crystil staging environment. It will perform real LLM SDK calls, which will be sent along to the staging Collector.
|
|
112
|
+
|
|
113
|
+
The "Run Integration Tests" workflow is defined in this file:
|
|
114
|
+
https://github.com/CrystilAI/python-sdk/blob/main/.github/workflows/run-integration-tests.yaml
|
|
115
|
+
|
|
116
|
+
> **The integration test suite will run only when manually requested by a user!**
|
|
117
|
+
|
|
118
|
+
This was a deliberate choice because the integration test suite:
|
|
119
|
+
|
|
120
|
+
- Takes longer to run
|
|
121
|
+
- Performs LLM requests
|
|
122
|
+
- Sends Crystil collector requests to the staging environment
|
|
123
|
+
|
|
124
|
+
Because performing LLM requests incurs a cost, we only want to run integration tests when the developer has specifically requested to run them.
|
|
125
|
+
|
|
126
|
+
#### Running integration tests
|
|
127
|
+
|
|
128
|
+
You should generally run the integration tests at these points in time:
|
|
129
|
+
|
|
130
|
+
- Before merging a branch of Python SDK changes to `main` — this ensures that your Python SDK changes are working with the current branch running in staging
|
|
131
|
+
- If you have made `backend` repository changes that may impact SDK usage, and deployed them to the staging environment — you can run the integration tests from the `main` branch of Python SDK against staging
|
|
132
|
+
|
|
133
|
+
1. To run the integration tests, visit [the Actions page](https://github.com/CrystilAI/python-sdk/actions).
|
|
134
|
+
2. Click "Run Integration Tests"
|
|
135
|
+
3. Click "Run workflow" button
|
|
136
|
+
4. Select branch to run from (`main` or branch for your outstanding PR)
|
|
137
|
+
5. See updated Actions list
|
|
138
|
+
6. Monitor progress via the topmost "Run Integration Tests" workflow
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
prune tests
|
|
2
|
+
prune .claude
|
|
3
|
+
prune .github
|
|
4
|
+
prune bin
|
|
5
|
+
exclude CLAUDE.md
|
|
6
|
+
exclude CLAUDE.local.md
|
|
7
|
+
exclude .pre-commit-config.yaml
|
|
8
|
+
exclude .python-version
|
|
9
|
+
exclude .env
|
|
10
|
+
exclude .env.example
|
|
11
|
+
exclude .gitignore
|
|
12
|
+
exclude uv.lock
|
|
13
|
+
global-exclude __pycache__
|
|
14
|
+
global-exclude *.py[cod]
|
crystil-0.8.0/PKG-INFO
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: crystil
|
|
3
|
+
Version: 0.8.0
|
|
4
|
+
Summary: Crystil Python SDK
|
|
5
|
+
Author-email: Crystil <noc@crystil.com>
|
|
6
|
+
Project-URL: Homepage, https://crystil.com/
|
|
7
|
+
Project-URL: Documentation, https://developers.crystil.com/
|
|
8
|
+
Project-URL: Repository, https://github.com/CrystilAI/
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: botocore
|
|
16
|
+
Requires-Dist: grpcio
|
|
17
|
+
Requires-Dist: protobuf
|
|
18
|
+
Requires-Dist: requests
|
|
19
|
+
Requires-Dist: urllib3
|
|
20
|
+
|
|
21
|
+
# Welcome to Crystil!
|
|
22
|
+
|
|
23
|
+
### Cost Visibility for AI Agents
|
|
24
|
+
|
|
25
|
+
Crystil is a lightweight infrastructure layer that gives AI teams real-time visibility into the true costs of deploying agents - across tasks, workflows, and customers. Most teams today can’t see what it actually costs to deploy their agents, making it nearly impossible to manage gross margins or price with confidence.
|
|
26
|
+
|
|
27
|
+
With just a single line of code, Crystil delivers:
|
|
28
|
+
- Cost tracking across OpenAI, Anthropic, Gemini, Groq, and more in one place
|
|
29
|
+
- Breakdowns by task, agent, and customer in real time
|
|
30
|
+
- Confidence to deploy the right pricing model (cost-plus, token-based, outcome-based, etc.) while preserving gross margins
|
|
31
|
+
|
|
32
|
+
Watch a short demo video: [Crystil Walkthrough Video](https://www.youtube.com/watch?v=Z-GkSl_7imY)
|
|
33
|
+
|
|
34
|
+
By surfacing exactly what’s driving cost and value, Crystil becomes the source of truth for agent economics - helping founders and operators scale their agents with confidence.
|
|
35
|
+
|
|
36
|
+
Sign up here: [crystil.com](https://crystil.com/)
|
|
37
|
+
|
|
38
|
+
# Installation
|
|
39
|
+
|
|
40
|
+
pip install crystil
|
|
41
|
+
|
|
42
|
+
# Documentation
|
|
43
|
+
|
|
44
|
+
Our SDK reference provides documentation for:
|
|
45
|
+
- Understanding how Crystil works
|
|
46
|
+
- Demonstrating how to integrate Crystil into your product
|
|
47
|
+
- Code samples to illustrate our SDK and API
|
|
48
|
+
|
|
49
|
+
Check it out here: [developers.crystil.com](https://developers.crystil.com)
|
crystil-0.8.0/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Welcome to Crystil!
|
|
2
|
+
|
|
3
|
+
### Cost Visibility for AI Agents
|
|
4
|
+
|
|
5
|
+
Crystil is a lightweight infrastructure layer that gives AI teams real-time visibility into the true costs of deploying agents - across tasks, workflows, and customers. Most teams today can’t see what it actually costs to deploy their agents, making it nearly impossible to manage gross margins or price with confidence.
|
|
6
|
+
|
|
7
|
+
With just a single line of code, Crystil delivers:
|
|
8
|
+
- Cost tracking across OpenAI, Anthropic, Gemini, Groq, and more in one place
|
|
9
|
+
- Breakdowns by task, agent, and customer in real time
|
|
10
|
+
- Confidence to deploy the right pricing model (cost-plus, token-based, outcome-based, etc.) while preserving gross margins
|
|
11
|
+
|
|
12
|
+
Watch a short demo video: [Crystil Walkthrough Video](https://www.youtube.com/watch?v=Z-GkSl_7imY)
|
|
13
|
+
|
|
14
|
+
By surfacing exactly what’s driving cost and value, Crystil becomes the source of truth for agent economics - helping founders and operators scale their agents with confidence.
|
|
15
|
+
|
|
16
|
+
Sign up here: [crystil.com](https://crystil.com/)
|
|
17
|
+
|
|
18
|
+
# Installation
|
|
19
|
+
|
|
20
|
+
pip install crystil
|
|
21
|
+
|
|
22
|
+
# Documentation
|
|
23
|
+
|
|
24
|
+
Our SDK reference provides documentation for:
|
|
25
|
+
- Understanding how Crystil works
|
|
26
|
+
- Demonstrating how to integrate Crystil into your product
|
|
27
|
+
- Code samples to illustrate our SDK and API
|
|
28
|
+
|
|
29
|
+
Check it out here: [developers.crystil.com](https://developers.crystil.com)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
___ _ _ _
|
|
3
|
+
/ __|_ _ _ _ __| |_(_) |
|
|
4
|
+
| (__| '_| || (_-< _| | |
|
|
5
|
+
\___|_| \_, /__/\__|_|_|AI
|
|
6
|
+
|__/ 07312025 / optimus codex
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
from uuid import uuid4
|
|
11
|
+
|
|
12
|
+
from crystil._config import Config
|
|
13
|
+
from crystil._errors import CrystilRequestInterceptedError
|
|
14
|
+
from crystil._providers import Anthropic as LlmProviderAnthropic
|
|
15
|
+
from crystil._providers import Google as LlmProviderGoogle
|
|
16
|
+
from crystil._providers import Groq as LlmProviderGroq
|
|
17
|
+
from crystil._providers import LangChain as LlmProviderLangChain
|
|
18
|
+
from crystil._providers import OpenAi as LlmProviderOpenAi
|
|
19
|
+
from crystil._providers import PydanticAi as LlmProviderPydanticAi
|
|
20
|
+
from crystil._sentinel import Sentinel
|
|
21
|
+
from crystil.api._workflow import Workflow, Workflows
|
|
22
|
+
|
|
23
|
+
__all__ = ["Crystil", "CrystilRequestInterceptedError"]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Crystil:
|
|
27
|
+
def __init__(self, api_key=None):
|
|
28
|
+
if api_key is None:
|
|
29
|
+
api_key = os.environ.get("CRYSTIL_API_KEY", None)
|
|
30
|
+
|
|
31
|
+
if api_key is None:
|
|
32
|
+
raise RuntimeError(
|
|
33
|
+
"API key is missing. Either set the CRYSTIL_API_KEY environment "
|
|
34
|
+
+ "variable or set the api_key parameter when instantiating Crystil."
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
self.config = Config()
|
|
38
|
+
self.config.api_key = api_key
|
|
39
|
+
self.config.tx_uuid = uuid4()
|
|
40
|
+
self.sentinel = Sentinel(self.config)
|
|
41
|
+
|
|
42
|
+
self.anthropic = LlmProviderAnthropic(self)
|
|
43
|
+
self.google = LlmProviderGoogle(self)
|
|
44
|
+
self.groq = LlmProviderGroq(self)
|
|
45
|
+
self.langchain = LlmProviderLangChain(self)
|
|
46
|
+
self.openai = LlmProviderOpenAi(self)
|
|
47
|
+
self.pydantic_ai = LlmProviderPydanticAi(self)
|
|
48
|
+
|
|
49
|
+
self.workflow = Workflow(self.config)
|
|
50
|
+
self.workflows = Workflows(self.config)
|
|
51
|
+
|
|
52
|
+
def attribution(
|
|
53
|
+
self,
|
|
54
|
+
parent_id=None,
|
|
55
|
+
parent_name=None,
|
|
56
|
+
subsidiary_id=None,
|
|
57
|
+
subsidiary_name=None,
|
|
58
|
+
# -- Deprecated parameters! They are here for backwards compatibility only.
|
|
59
|
+
parent_uuid=None,
|
|
60
|
+
subsidiary_uuid=None,
|
|
61
|
+
):
|
|
62
|
+
if parent_id is None:
|
|
63
|
+
raise RuntimeError("a string parent_id is required")
|
|
64
|
+
|
|
65
|
+
parent_id = str(parent_id)
|
|
66
|
+
|
|
67
|
+
if len(parent_id) > 100:
|
|
68
|
+
raise RuntimeError("parent_id cannot be greater than 100 characters")
|
|
69
|
+
|
|
70
|
+
if parent_name is not None and len(parent_name) > 100:
|
|
71
|
+
raise RuntimeError("parent_name cannot be greater than 100 characters")
|
|
72
|
+
|
|
73
|
+
if subsidiary_name is not None and subsidiary_id is None:
|
|
74
|
+
raise RuntimeError(
|
|
75
|
+
"a string subsidiary_id is required if a subsidiary_name is provided"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
if subsidiary_id is not None:
|
|
79
|
+
subsidiary_id = str(subsidiary_id)
|
|
80
|
+
|
|
81
|
+
if len(subsidiary_id) > 100:
|
|
82
|
+
raise RuntimeError(
|
|
83
|
+
"subsidiary_id cannot be greater than 100 characters"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if subsidiary_name is not None and len(subsidiary_name) > 100:
|
|
87
|
+
raise RuntimeError("subsidiary_name cannot be greater than 100 characters")
|
|
88
|
+
|
|
89
|
+
subsidiary = None
|
|
90
|
+
if subsidiary_id is not None:
|
|
91
|
+
subsidiary = {"id": subsidiary_id, "name": subsidiary_name}
|
|
92
|
+
|
|
93
|
+
self.config.attribution = {
|
|
94
|
+
"parent": {"id": parent_id, "name": parent_name},
|
|
95
|
+
"subsidiary": subsidiary,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return self
|
|
99
|
+
|
|
100
|
+
def new_transaction(self):
|
|
101
|
+
self.config.tx_uuid = uuid4()
|
|
102
|
+
return self
|