basalt_sdk 1.1.1__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.
Files changed (91) hide show
  1. basalt_sdk-1.1.1/.gitignore +20 -0
  2. basalt_sdk-1.1.1/PKG-INFO +560 -0
  3. basalt_sdk-1.1.1/README.md +468 -0
  4. basalt_sdk-1.1.1/basalt/__init__.py +40 -0
  5. basalt_sdk-1.1.1/basalt/_internal/__init__.py +6 -0
  6. basalt_sdk-1.1.1/basalt/_internal/base_client.py +121 -0
  7. basalt_sdk-1.1.1/basalt/_internal/http.py +404 -0
  8. basalt_sdk-1.1.1/basalt/_version.py +1 -0
  9. basalt_sdk-1.1.1/basalt/client.py +164 -0
  10. basalt_sdk-1.1.1/basalt/config.py +15 -0
  11. basalt_sdk-1.1.1/basalt/datasets/__init__.py +25 -0
  12. basalt_sdk-1.1.1/basalt/datasets/client.py +387 -0
  13. basalt_sdk-1.1.1/basalt/datasets/file_upload.py +501 -0
  14. basalt_sdk-1.1.1/basalt/datasets/models.py +159 -0
  15. basalt_sdk-1.1.1/basalt/experiments/__init__.py +13 -0
  16. basalt_sdk-1.1.1/basalt/experiments/client.py +147 -0
  17. basalt_sdk-1.1.1/basalt/experiments/models.py +62 -0
  18. basalt_sdk-1.1.1/basalt/observability/__init__.py +75 -0
  19. basalt_sdk-1.1.1/basalt/observability/api.py +1176 -0
  20. basalt_sdk-1.1.1/basalt/observability/config.py +227 -0
  21. basalt_sdk-1.1.1/basalt/observability/context_managers.py +921 -0
  22. basalt_sdk-1.1.1/basalt/observability/decorators.py +98 -0
  23. basalt_sdk-1.1.1/basalt/observability/evaluators.py +118 -0
  24. basalt_sdk-1.1.1/basalt/observability/instrumentation.py +519 -0
  25. basalt_sdk-1.1.1/basalt/observability/processors.py +428 -0
  26. basalt_sdk-1.1.1/basalt/observability/request_tracing.py +131 -0
  27. basalt_sdk-1.1.1/basalt/observability/resilient_exporters.py +72 -0
  28. basalt_sdk-1.1.1/basalt/observability/semconv.py +645 -0
  29. basalt_sdk-1.1.1/basalt/observability/spans.py +71 -0
  30. basalt_sdk-1.1.1/basalt/observability/trace.py +165 -0
  31. basalt_sdk-1.1.1/basalt/observability/trace_context.py +222 -0
  32. basalt_sdk-1.1.1/basalt/observability/types.py +27 -0
  33. basalt_sdk-1.1.1/basalt/observability/utils.py +409 -0
  34. basalt_sdk-1.1.1/basalt/prompts/__init__.py +49 -0
  35. basalt_sdk-1.1.1/basalt/prompts/client.py +694 -0
  36. basalt_sdk-1.1.1/basalt/prompts/models.py +662 -0
  37. basalt_sdk-1.1.1/basalt/types/__init__.py +43 -0
  38. basalt_sdk-1.1.1/basalt/types/cache.py +16 -0
  39. basalt_sdk-1.1.1/basalt/types/common.py +13 -0
  40. basalt_sdk-1.1.1/basalt/types/exceptions.py +67 -0
  41. basalt_sdk-1.1.1/basalt/utils/__init__.py +0 -0
  42. basalt_sdk-1.1.1/basalt/utils/memcache.py +48 -0
  43. basalt_sdk-1.1.1/docs/01-introduction.md +236 -0
  44. basalt_sdk-1.1.1/docs/02-getting-started.md +169 -0
  45. basalt_sdk-1.1.1/docs/03-prompts.md +772 -0
  46. basalt_sdk-1.1.1/docs/04-datasets.md +417 -0
  47. basalt_sdk-1.1.1/docs/05-observability.md +274 -0
  48. basalt_sdk-1.1.1/docs/06-advanced-tracing.md +85 -0
  49. basalt_sdk-1.1.1/docs/06-manual-tracing.md +488 -0
  50. basalt_sdk-1.1.1/docs/07-llm-tracing.md +55 -0
  51. basalt_sdk-1.1.1/docs/08-async-observability.md +156 -0
  52. basalt_sdk-1.1.1/docs/09-auto-instrumentation.md +236 -0
  53. basalt_sdk-1.1.1/docs/10-evaluators.md +539 -0
  54. basalt_sdk-1.1.1/docs/11-experiments.md +125 -0
  55. basalt_sdk-1.1.1/docs/12-user-org-tracking.md +223 -0
  56. basalt_sdk-1.1.1/docs/13-trace-context.md +577 -0
  57. basalt_sdk-1.1.1/pyproject.toml +215 -0
  58. basalt_sdk-1.1.1/tests/__init__.py +0 -0
  59. basalt_sdk-1.1.1/tests/conftest.py +44 -0
  60. basalt_sdk-1.1.1/tests/datasets/__init__.py +1 -0
  61. basalt_sdk-1.1.1/tests/datasets/test_client.py +370 -0
  62. basalt_sdk-1.1.1/tests/datasets/test_file_upload.py +627 -0
  63. basalt_sdk-1.1.1/tests/experiments/__init__.py +1 -0
  64. basalt_sdk-1.1.1/tests/experiments/test_client.py +301 -0
  65. basalt_sdk-1.1.1/tests/internal/__init__.py +1 -0
  66. basalt_sdk-1.1.1/tests/internal/test_http.py +414 -0
  67. basalt_sdk-1.1.1/tests/observability/__init__.py +1 -0
  68. basalt_sdk-1.1.1/tests/observability/test_api.py +541 -0
  69. basalt_sdk-1.1.1/tests/observability/test_config.py +35 -0
  70. basalt_sdk-1.1.1/tests/observability/test_context_managers.py +574 -0
  71. basalt_sdk-1.1.1/tests/observability/test_decorators.py +70 -0
  72. basalt_sdk-1.1.1/tests/observability/test_evaluators.py +86 -0
  73. basalt_sdk-1.1.1/tests/observability/test_instrumentation.py +266 -0
  74. basalt_sdk-1.1.1/tests/observability/test_multi_exporters.py +298 -0
  75. basalt_sdk-1.1.1/tests/observability/test_processors.py +316 -0
  76. basalt_sdk-1.1.1/tests/observability/test_request_tracing.py +76 -0
  77. basalt_sdk-1.1.1/tests/observability/test_resilient_exporters.py +149 -0
  78. basalt_sdk-1.1.1/tests/observability/test_should_evaluate_propagation.py +454 -0
  79. basalt_sdk-1.1.1/tests/observability/test_trace.py +419 -0
  80. basalt_sdk-1.1.1/tests/observability/utils.py +35 -0
  81. basalt_sdk-1.1.1/tests/otel/__init__.py +3 -0
  82. basalt_sdk-1.1.1/tests/otel/conftest.py +45 -0
  83. basalt_sdk-1.1.1/tests/otel/example_otlp_export.py +151 -0
  84. basalt_sdk-1.1.1/tests/otel/generate_sample_otlp_json.py +127 -0
  85. basalt_sdk-1.1.1/tests/otel/otlp_utils.py +177 -0
  86. basalt_sdk-1.1.1/tests/otel/test_llm_instrumentation.py +791 -0
  87. basalt_sdk-1.1.1/tests/prompts/__init__.py +0 -0
  88. basalt_sdk-1.1.1/tests/prompts/test_client.py +937 -0
  89. basalt_sdk-1.1.1/tests/prompts/test_context_manager.py +233 -0
  90. basalt_sdk-1.1.1/tests/test_client_telemetry.py +48 -0
  91. basalt_sdk-1.1.1/tests/test_observe_decorators.py +87 -0
@@ -0,0 +1,20 @@
1
+ basalt*.egg-info/
2
+ build/
3
+ dist/
4
+ __pycache__/
5
+ test.py
6
+ .DS_Store
7
+ .idea/
8
+ venv/
9
+ .github/instructions/*.md
10
+ .copilot-tracking
11
+ .env*
12
+ requirements*
13
+ .serena
14
+ .hatch/
15
+ *.pyc
16
+ .pytest_cache/
17
+ .ruff_cache/
18
+ coverage.xml
19
+ .coverage
20
+ htmlcov/
@@ -0,0 +1,560 @@
1
+ Metadata-Version: 2.4
2
+ Name: basalt_sdk
3
+ Version: 1.1.1
4
+ Summary: Basalt SDK for python
5
+ Project-URL: Homepage, https://github.com/basalt-ai/basalt-python
6
+ Author-email: Basalt <support@getbasalt.ai>
7
+ License-Expression: MIT
8
+ Keywords: ai,basalt,python,sdk
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Requires-Python: >=3.10
12
+ Requires-Dist: black>=26.1.0
13
+ Requires-Dist: httpx>=0.28.1
14
+ Requires-Dist: jinja2>=3.1.6
15
+ Requires-Dist: opentelemetry-api~=1.39.1
16
+ Requires-Dist: opentelemetry-exporter-otlp~=1.39.1
17
+ Requires-Dist: opentelemetry-instrumentation-httpx~=0.59b0
18
+ Requires-Dist: opentelemetry-instrumentation~=0.59b0
19
+ Requires-Dist: opentelemetry-sdk~=1.39.1
20
+ Requires-Dist: opentelemetry-semantic-conventions~=0.59b0
21
+ Requires-Dist: typing-extensions>=4.10.0
22
+ Requires-Dist: wrapt~=1.17.3
23
+ Provides-Extra: all
24
+ Requires-Dist: opentelemetry-instrumentation-anthropic~=0.51.0; extra == 'all'
25
+ Requires-Dist: opentelemetry-instrumentation-bedrock~=0.51.0; extra == 'all'
26
+ Requires-Dist: opentelemetry-instrumentation-chromadb~=0.51.0; extra == 'all'
27
+ Requires-Dist: opentelemetry-instrumentation-google-generativeai~=0.51.0; extra == 'all'
28
+ Requires-Dist: opentelemetry-instrumentation-langchain~=0.51.0; extra == 'all'
29
+ Requires-Dist: opentelemetry-instrumentation-llamaindex~=0.51.0; extra == 'all'
30
+ Requires-Dist: opentelemetry-instrumentation-mistralai~=0.51.0; extra == 'all'
31
+ Requires-Dist: opentelemetry-instrumentation-openai~=0.51.0; extra == 'all'
32
+ Requires-Dist: opentelemetry-instrumentation-pinecone~=0.51.0; extra == 'all'
33
+ Requires-Dist: opentelemetry-instrumentation-qdrant~=0.51.0; extra == 'all'
34
+ Requires-Dist: opentelemetry-instrumentation-vertexai~=0.51.0; extra == 'all'
35
+ Provides-Extra: anthropic
36
+ Requires-Dist: opentelemetry-instrumentation-anthropic~=0.51.0; extra == 'anthropic'
37
+ Provides-Extra: bedrock
38
+ Requires-Dist: opentelemetry-instrumentation-bedrock~=0.51.0; extra == 'bedrock'
39
+ Provides-Extra: chromadb
40
+ Requires-Dist: opentelemetry-instrumentation-chromadb~=0.51.0; extra == 'chromadb'
41
+ Provides-Extra: dev
42
+ Requires-Dist: anthropic; extra == 'dev'
43
+ Requires-Dist: coverage; extra == 'dev'
44
+ Requires-Dist: google-genai; extra == 'dev'
45
+ Requires-Dist: mistralai; extra == 'dev'
46
+ Requires-Dist: openai; extra == 'dev'
47
+ Requires-Dist: opentelemetry-instrumentation-anthropic; extra == 'dev'
48
+ Requires-Dist: opentelemetry-instrumentation-google-genai; extra == 'dev'
49
+ Requires-Dist: opentelemetry-instrumentation-google-generativeai; extra == 'dev'
50
+ Requires-Dist: opentelemetry-instrumentation-openai; extra == 'dev'
51
+ Requires-Dist: opentelemetry-instrumentation-vertexai; extra == 'dev'
52
+ Requires-Dist: parameterized; extra == 'dev'
53
+ Requires-Dist: pytest; extra == 'dev'
54
+ Requires-Dist: pytest-asyncio; extra == 'dev'
55
+ Requires-Dist: pytest-cov; extra == 'dev'
56
+ Requires-Dist: requests; extra == 'dev'
57
+ Requires-Dist: ruff; extra == 'dev'
58
+ Requires-Dist: setuptools; extra == 'dev'
59
+ Requires-Dist: twine; extra == 'dev'
60
+ Requires-Dist: wheel; extra == 'dev'
61
+ Provides-Extra: framework-all
62
+ Requires-Dist: opentelemetry-instrumentation-langchain~=0.51.0; extra == 'framework-all'
63
+ Requires-Dist: opentelemetry-instrumentation-llamaindex~=0.51.0; extra == 'framework-all'
64
+ Provides-Extra: google-generativeai
65
+ Requires-Dist: opentelemetry-instrumentation-google-generativeai~=0.51.0; extra == 'google-generativeai'
66
+ Provides-Extra: langchain
67
+ Requires-Dist: opentelemetry-instrumentation-langchain~=0.51.0; extra == 'langchain'
68
+ Provides-Extra: llamaindex
69
+ Requires-Dist: opentelemetry-instrumentation-llamaindex~=0.51.0; extra == 'llamaindex'
70
+ Provides-Extra: llm-all
71
+ Requires-Dist: opentelemetry-instrumentation-anthropic~=0.51.0; extra == 'llm-all'
72
+ Requires-Dist: opentelemetry-instrumentation-bedrock~=0.51.0; extra == 'llm-all'
73
+ Requires-Dist: opentelemetry-instrumentation-google-generativeai~=0.51.0; extra == 'llm-all'
74
+ Requires-Dist: opentelemetry-instrumentation-mistralai~=0.51.0; extra == 'llm-all'
75
+ Requires-Dist: opentelemetry-instrumentation-openai~=0.51.0; extra == 'llm-all'
76
+ Requires-Dist: opentelemetry-instrumentation-vertexai~=0.51.0; extra == 'llm-all'
77
+ Provides-Extra: mistralai
78
+ Requires-Dist: opentelemetry-instrumentation-mistralai~=0.51.0; extra == 'mistralai'
79
+ Provides-Extra: openai
80
+ Requires-Dist: opentelemetry-instrumentation-openai~=0.51.0; extra == 'openai'
81
+ Provides-Extra: pinecone
82
+ Requires-Dist: opentelemetry-instrumentation-pinecone~=0.51.0; extra == 'pinecone'
83
+ Provides-Extra: qdrant
84
+ Requires-Dist: opentelemetry-instrumentation-qdrant~=0.51.0; extra == 'qdrant'
85
+ Provides-Extra: vector-all
86
+ Requires-Dist: opentelemetry-instrumentation-chromadb~=0.51.0; extra == 'vector-all'
87
+ Requires-Dist: opentelemetry-instrumentation-pinecone~=0.51.0; extra == 'vector-all'
88
+ Requires-Dist: opentelemetry-instrumentation-qdrant~=0.51.0; extra == 'vector-all'
89
+ Provides-Extra: vertex-ai
90
+ Requires-Dist: opentelemetry-instrumentation-vertexai~=0.51.0; extra == 'vertex-ai'
91
+ Description-Content-Type: text/markdown
92
+
93
+ # Basalt SDK
94
+
95
+ Basalt is a powerful tool for managing AI prompts, monitoring AI applications, and their release workflows. This SDK is the official Python package for interacting with your Basalt prompts and monitoring your AI applications.
96
+
97
+ ## Installation
98
+
99
+ Install the Basalt SDK via pip:
100
+
101
+ ```bash
102
+ pip install basalt-sdk
103
+ ```
104
+
105
+ ### Optional Instrumentation Dependencies
106
+
107
+ The SDK includes optional OpenTelemetry instrumentation packages for various LLM providers, vector databases, and frameworks. You can install only the instrumentations you need:
108
+
109
+ #### LLM Provider Instrumentations
110
+
111
+ ```bash
112
+ # Individual providers (10 available)
113
+ pip install basalt-sdk[openai]
114
+ pip install basalt-sdk[anthropic]
115
+ pip install basalt-sdk[google-generativeai] # Google Gemini
116
+ pip install basalt-sdk[bedrock]
117
+ pip install basalt-sdk[vertex-ai]
118
+ pip install basalt-sdk[ollama]
119
+ ...
120
+
121
+ # Multiple providers
122
+ pip install basalt-sdk[openai,anthropic]
123
+
124
+ # All LLM providers (10 providers)
125
+ pip install basalt-sdk[llm-all]
126
+ ```
127
+
128
+ **Note:** The NEW Google GenAI SDK instrumentation is not yet available on PyPI. Use `google-generativeai` for Gemini for now.
129
+
130
+ #### Vector Database Instrumentations
131
+
132
+ ```bash
133
+ # Individual vector databases
134
+ pip install basalt-sdk[chromadb]
135
+ pip install basalt-sdk[pinecone]
136
+ pip install basalt-sdk[qdrant]
137
+
138
+ # All vector databases
139
+ pip install basalt-sdk[vector-all]
140
+ ```
141
+
142
+ #### Framework Instrumentations
143
+
144
+ ```bash
145
+ # Individual frameworks
146
+ pip install basalt-sdk[langchain]
147
+ pip install basalt-sdk[llamaindex]
148
+
149
+ # All frameworks
150
+ pip install basalt-sdk[framework-all]
151
+ ```
152
+
153
+ #### Install Everything
154
+
155
+ ```bash
156
+ # Install all available instrumentations
157
+ pip install basalt-sdk[all]
158
+ ```
159
+
160
+ **Note:** These instrumentation packages are automatically activated when you enable telemetry in the Basalt SDK. They provide automatic tracing for your LLM provider calls, vector database operations, and framework usage.
161
+
162
+ ## Usage
163
+
164
+ ### Importing and Initializing the SDK
165
+
166
+ To get started, import the `Basalt` class and initialize it with your API key. Telemetry is enabled by default via OpenTelemetry, but can be configured or disabled:
167
+
168
+ ```python
169
+ from basalt import Basalt, TelemetryConfig
170
+
171
+ # Basic initialization with API key
172
+ basalt = Basalt(api_key="my-dev-api-key")
173
+
174
+ # Disable all telemetry
175
+ basalt = Basalt(api_key="my-dev-api-key", enable_telemetry=False)
176
+
177
+ # Advanced telemetry configuration
178
+ telemetry = TelemetryConfig(
179
+ service_name="my-app",
180
+ environment="staging",
181
+ enabled_providers=["openai", "anthropic"], # Optional: selective instrumentation
182
+ )
183
+ basalt = Basalt(api_key="my-dev-api-key", telemetry_config=telemetry)
184
+
185
+ # Or use client-level parameters (simpler)
186
+ basalt = Basalt(
187
+ api_key="my-dev-api-key",
188
+ enabled_instruments=["openai", "anthropic"]
189
+ )
190
+
191
+ # Configure global metadata when constructing the client
192
+ basalt = Basalt(
193
+ api_key="my-dev-api-key",
194
+ observability_metadata={"env": "staging"},
195
+ )
196
+
197
+ # Don't forget to shutdown the client when done
198
+ # This flushes any pending telemetry data
199
+ basalt.shutdown()
200
+ ```
201
+
202
+ See `examples/telemetry_example.py` for a more complete walkthrough covering decorators, context managers, and custom exporters.
203
+
204
+ ### Telemetry & Observability
205
+
206
+ The SDK includes comprehensive OpenTelemetry integration for observability:
207
+
208
+ - `TelemetryConfig` centralizes all observability options including:
209
+ - Service name/version and deployment environment
210
+ - Custom exporter configuration
211
+ - Lightweight tracing wrappers for Basalt API calls (bring your own HTTP instrumentation if you need transport-level spans)
212
+ - LLM provider instrumentation with fine-grained control over which providers to instrument
213
+ - Quick disable via `enable_telemetry=False` bypasses all instrumentation without touching application code.
214
+ - Built-in decorators and context managers simplify manual span creation:
215
+ - **Root Spans**: `@start_observe` - Creates trace entry point with identity and experiment tracking
216
+ - **Nested Spans**: `@observe` with `kind` parameter - For generation, retrieval, tool, event, function spans
217
+
218
+ ```python
219
+ from basalt.observability import observe, start_observe
220
+
221
+
222
+ # Root span with identity tracking
223
+ @start_observe(
224
+ feature_slug="dataset-processing",
225
+ name="process_workflow",
226
+ identity={
227
+ "organization": {"id": "123", "name": "ACME"},
228
+ "user": {"id": "456", "name": "John Doe"}
229
+ },
230
+ metadata={"environment": "production"}
231
+ )
232
+ def process_dataset(slug: str, user_id: str) -> str:
233
+ # Identity automatically propagates to child spans
234
+ observe.set_input({"slug": slug})
235
+ result = f"processed:{slug}"
236
+ observe.set_output({"result": result})
237
+ return result
238
+
239
+
240
+ # Nested LLM span
241
+ @observe(kind="generation", name="llm.generate")
242
+ def generate_summary(model: str, prompt: str) -> dict:
243
+ # Your LLM call here
244
+ return {"choices": [{"message": {"content": "Summary"}}]}
245
+
246
+
247
+ ```
248
+
249
+
250
+
251
+ **Supported environment variables:**
252
+
253
+ | Variable | Description |
254
+ | --- | --- |
255
+ | `BASALT_API_KEY` | API key for authentication (can also be passed to `Basalt()` constructor). |
256
+ | `BASALT_TELEMETRY_ENABLED` | Master switch to enable/disable telemetry (default: `true`). |
257
+ | `BASALT_SERVICE_NAME` | Overrides the OTEL `service.name`. |
258
+ | `BASALT_ENVIRONMENT` | Sets `deployment.environment`. |
259
+ | `BASALT_OTEL_EXPORTER_OTLP_ENDPOINT` | Custom OTLP HTTP endpoint for traces. Overrides the default Basalt OTEL collector endpoint. |
260
+ | `BASALT_BUILD` | SDK build mode - set to `development` for local OTEL collector testing (default: `production`). |
261
+ | `TRACELOOP_TRACE_CONTENT` | Controls whether prompts/completions are logged. **Note:** Set automatically by `TelemetryConfig.trace_content` - you typically don't need to set this manually. |
262
+ | `BASALT_ENABLED_INSTRUMENTS` | Comma-separated list of instruments to enable (e.g., `openai,anthropic`). |
263
+ | `BASALT_DISABLED_INSTRUMENTS` | Comma-separated list of instruments to disable (e.g., `langchain,llamaindex`). |
264
+
265
+ **Default OTLP Exporter:**
266
+
267
+ By default, the SDK automatically sends traces to Basalt's OTEL collector:
268
+ - **Production**: `https://otel.getbasalt.ai/v1/traces`
269
+ - **Development**: `http://localhost:4318/v1/traces` (when `BASALT_BUILD=development`)
270
+
271
+ You can override this by:
272
+ 1. Providing a custom `exporter` in `TelemetryConfig`
273
+ 2. Setting the `BASALT_OTEL_EXPORTER_OTLP_ENDPOINT` environment variable
274
+ 3. Disabling telemetry with `enable_telemetry=False`
275
+
276
+ ## Prompt SDK
277
+
278
+ The Prompt SDK allows you to interact with your Basalt prompts using an exception-based API for clear error handling.
279
+
280
+ For a complete working example, check out:
281
+ - [Prompt API Example](./examples/prompt_api_example.py) - Detailed examples with error handling
282
+ - [Prompt SDK Demo Notebook](./examples/prompt_sdk_demo.ipynb) - Interactive notebook
283
+
284
+ ### Available Methods
285
+
286
+ #### Prompts
287
+ Your Basalt instance exposes a `prompts` property for interacting with your Basalt prompts:
288
+
289
+ - **List Prompts**
290
+
291
+ Retrieve all available prompts.
292
+
293
+ **Example Usage:**
294
+
295
+ ```python
296
+ from basalt import Basalt
297
+ from basalt.types.exceptions import BasaltAPIError, UnauthorizedError
298
+
299
+ basalt = Basalt(api_key="your-api-key")
300
+
301
+ try:
302
+ prompts = basalt.prompts.list_sync()
303
+ for prompt in prompts:
304
+ print(f"{prompt.slug} - {prompt.name}")
305
+ except UnauthorizedError:
306
+ print("Invalid API key")
307
+ except BasaltAPIError as e:
308
+ print(f"API error: {e}")
309
+ ```
310
+
311
+ - **Get a Prompt**
312
+
313
+ Retrieve a specific prompt using a slug, and optional filters `tag` and `version`. Without tag or version, the production version of your prompt is selected by default.
314
+
315
+ **Example Usage:**
316
+
317
+ ```python
318
+ from basalt import Basalt
319
+ from basalt.types.exceptions import NotFoundError, BasaltAPIError
320
+
321
+ basalt = Basalt(api_key="your-api-key")
322
+
323
+ try:
324
+ # Get the production version
325
+ prompt = basalt.prompts.get_sync('prompt-slug')
326
+ print(prompt.text)
327
+
328
+ # With optional tag or version parameters
329
+ prompt = basalt.prompts.get_sync(slug='prompt-slug', tag='latest')
330
+ prompt = basalt.prompts.get_sync(slug='prompt-slug', version='1.0.0')
331
+
332
+ # If your prompt has variables, pass them when fetching
333
+ prompt = basalt.prompts.get_sync(
334
+ slug='prompt-slug',
335
+ variables={'name': 'John Doe', 'role': 'engineer'}
336
+ )
337
+
338
+ # Use the prompt with your AI provider of choice
339
+ # Example: OpenAI
340
+ import openai
341
+ client = openai.OpenAI()
342
+
343
+ response = client.chat.completions.create(
344
+ model='gpt-4',
345
+ messages=[{'role': 'user', 'content': prompt.text}]
346
+ )
347
+ print(response.choices[0].message.content)
348
+
349
+ except NotFoundError:
350
+ print('Prompt not found')
351
+ except BasaltAPIError as e:
352
+ print(f'API error: {e}')
353
+ finally:
354
+ basalt.shutdown()
355
+ ```
356
+
357
+ - **Context Managers for Observability** (Recommended)
358
+
359
+ Use prompts as context managers to automatically nest LLM calls under a prompt span for better trace organization and observability:
360
+
361
+ **Sync Example:**
362
+
363
+ ```python
364
+ from basalt import Basalt
365
+ import openai
366
+
367
+ basalt = Basalt(api_key="your-api-key")
368
+ client = openai.OpenAI()
369
+
370
+ # Use context manager for automatic span nesting
371
+ with basalt.prompts.get_sync('summary-prompt', tag='production') as prompt:
372
+ response = client.chat.completions.create(
373
+ model=prompt.model.model,
374
+ messages=[{'role': 'user', 'content': prompt.text}]
375
+ )
376
+ print(response.choices[0].message.content)
377
+
378
+ basalt.shutdown()
379
+ ```
380
+
381
+ **Async Example:**
382
+
383
+ ```python
384
+ import asyncio
385
+ from basalt import Basalt
386
+ import openai
387
+
388
+ async def generate():
389
+ basalt = Basalt(api_key="your-api-key")
390
+ client = openai.AsyncOpenAI()
391
+
392
+ async with await basalt.prompts.get('summary-prompt', tag='production') as prompt:
393
+ response = await client.chat.completions.create(
394
+ model=prompt.model.model,
395
+ messages=[{'role': 'user', 'content': prompt.text}]
396
+ )
397
+ print(response.choices[0].message.content)
398
+
399
+ basalt.shutdown()
400
+
401
+ asyncio.run(generate())
402
+ ```
403
+
404
+ See the [Prompts guide](./docs/03-prompts.md#observability-with-context-managers) for complete details.
405
+
406
+ - **Describe a Prompt**
407
+
408
+ Get metadata about a prompt including available versions and tags.
409
+
410
+ **Example Usage:**
411
+
412
+ ```python
413
+ try:
414
+ description = basalt.prompts.describe_sync('prompt-slug')
415
+ print(f"Available versions: {description.available_versions}")
416
+ print(f"Available tags: {description.available_tags}")
417
+ except NotFoundError:
418
+ print('Prompt not found')
419
+ ```
420
+
421
+ - **Async Operations**
422
+
423
+ All methods have async variants using `_async` suffix:
424
+
425
+ ```python
426
+ import asyncio
427
+
428
+ async def fetch_prompts():
429
+ basalt = Basalt(api_key="your-api-key")
430
+
431
+ try:
432
+ # List prompts asynchronously
433
+ prompts = await basalt.prompts.list_async()
434
+
435
+ # Get a specific prompt asynchronously
436
+ prompt = await basalt.prompts.get_async('prompt-slug')
437
+
438
+ # Describe a prompt asynchronously
439
+ description = await basalt.prompts.describe_async('prompt-slug')
440
+
441
+ finally:
442
+ basalt.shutdown()
443
+
444
+ asyncio.run(fetch_prompts())
445
+ ```
446
+
447
+ ## Dataset SDK
448
+
449
+ The Dataset SDK allows you to interact with your Basalt datasets using an exception-based API for clear error handling.
450
+
451
+ For a complete working example, check out:
452
+ - [Dataset API Example](./examples/dataset_api_example.py) - Detailed examples with error handling
453
+ - [Dataset SDK Demo Notebook](./examples/dataset_sdk_demo.ipynb) - Interactive notebook
454
+
455
+ ### Available Methods
456
+
457
+ #### Datasets
458
+ Your Basalt instance exposes a `datasets` property for interacting with your Basalt datasets:
459
+
460
+ - **List Datasets**
461
+
462
+ Retrieve all available datasets.
463
+
464
+ **Example Usage:**
465
+
466
+ ```python
467
+ from basalt import Basalt
468
+ from basalt.types.exceptions import BasaltAPIError
469
+
470
+ basalt = Basalt(api_key="your-api-key")
471
+
472
+ try:
473
+ datasets = basalt.datasets.list_sync()
474
+ for dataset in datasets:
475
+ print(f"{dataset.slug} - {dataset.name}")
476
+ print(f"Columns: {dataset.columns}")
477
+ except BasaltAPIError as e:
478
+ print(f"API error: {e}")
479
+ ```
480
+
481
+ - **Get a Dataset**
482
+
483
+ Retrieve a specific dataset by slug.
484
+
485
+ **Example Usage:**
486
+
487
+ ```python
488
+ from basalt.types.exceptions import NotFoundError
489
+
490
+ try:
491
+ dataset = basalt.datasets.get_sync('dataset-slug')
492
+ print(f"Dataset: {dataset.name}")
493
+ print(f"Rows: {len(dataset.rows)}")
494
+
495
+ # Access dataset rows
496
+ for row in dataset.rows:
497
+ print(row)
498
+
499
+ except NotFoundError:
500
+ print('Dataset not found')
501
+ ```
502
+
503
+ - **Async Operations**
504
+
505
+ All methods have async variants using `_async` suffix:
506
+
507
+ ```python
508
+ import asyncio
509
+
510
+ async def fetch_datasets():
511
+ basalt = Basalt(api_key="your-api-key")
512
+
513
+ try:
514
+ # List datasets asynchronously
515
+ datasets = await basalt.datasets.list_async()
516
+
517
+ # Get a specific dataset asynchronously
518
+ dataset = await basalt.datasets.get_async('dataset-slug')
519
+
520
+ finally:
521
+ basalt.shutdown()
522
+
523
+ asyncio.run(fetch_datasets())
524
+ ```
525
+
526
+ ## Error Handling
527
+
528
+ The SDK uses exception-based error handling for clarity and pythonic patterns:
529
+
530
+ ```python
531
+ from basalt import Basalt
532
+ from basalt.types.exceptions import (
533
+ BasaltAPIError, # Base exception for all API errors
534
+ NotFoundError, # Resource not found (404)
535
+ UnauthorizedError, # Authentication failed (401)
536
+ NetworkError, # Network/connection errors
537
+ )
538
+
539
+ basalt = Basalt(api_key="your-api-key")
540
+
541
+ try:
542
+ prompt = basalt.prompts.get_sync('my-prompt')
543
+ # Use the prompt
544
+ except NotFoundError:
545
+ print("Prompt doesn't exist")
546
+ except UnauthorizedError:
547
+ print("Check your API key")
548
+ except NetworkError:
549
+ print("Network connection failed")
550
+ except BasaltAPIError as e:
551
+ print(f"Other API error: {e}")
552
+ finally:
553
+ basalt.shutdown()
554
+ ```
555
+
556
+
557
+
558
+ ## License
559
+
560
+ MIT