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.
@@ -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)
@@ -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