acceldata-aio-tracer 0.1.0.dev1__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 (23) hide show
  1. acceldata_aio_tracer-0.1.0.dev1/PKG-INFO +301 -0
  2. acceldata_aio_tracer-0.1.0.dev1/README.md +286 -0
  3. acceldata_aio_tracer-0.1.0.dev1/pyproject.toml +20 -0
  4. acceldata_aio_tracer-0.1.0.dev1/setup.py +34 -0
  5. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/__init__.py +91 -0
  6. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/_opik_bridge.py +107 -0
  7. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/auth.py +38 -0
  8. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/client.py +166 -0
  9. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/__init__.py +0 -0
  10. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/adk.py +11 -0
  11. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/aisuite.py +3 -0
  12. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/anthropic.py +3 -0
  13. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/bedrock.py +3 -0
  14. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/crewai.py +3 -0
  15. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/dspy.py +3 -0
  16. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/genai.py +3 -0
  17. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/guardrails.py +3 -0
  18. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/harbor.py +3 -0
  19. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/haystack.py +3 -0
  20. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/langchain.py +19 -0
  21. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/litellm.py +3 -0
  22. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/llama_index.py +3 -0
  23. acceldata_aio_tracer-0.1.0.dev1/src/acceldata_aio_tracer/integrations/openai.py +3 -0
@@ -0,0 +1,301 @@
1
+ Metadata-Version: 2.1
2
+ Name: acceldata-aio-tracer
3
+ Version: 0.1.0.dev1
4
+ Summary: Acceldata LLM observability SDK
5
+ License: Apache-2.0
6
+ Author: Acceldata
7
+ Requires-Python: >=3.10,<4.0
8
+ Classifier: License :: OSI Approved :: Apache Software License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Requires-Dist: httpx
13
+ Requires-Dist: opik (==1.11.3)
14
+ Description-Content-Type: text/markdown
15
+
16
+ # acceldata-aio-tracer
17
+
18
+ LLM observability SDK by Acceldata, built on top of [Opik](https://github.com/comet-ml/opik). It:
19
+
20
+ - Adds Acceldata `accessKey` / `secretKey` authentication to every Opik HTTP call via an httpx auth hook.
21
+ - Re-exports the full Opik public API under the `acceldata_aio_tracer` namespace.
22
+ - Mirrors all Opik integrations under `acceldata_aio_tracer.integrations.<framework>` so customer code never imports from `opik` directly.
23
+
24
+ ## Index
25
+
26
+ - [Installation](#installation)
27
+ - [Quick start](#quick-start)
28
+ - [Configuration](#configuration)
29
+ - [Signature stability](#signature-stability)
30
+ - [Programmatic (`configure`)](#programmatic-configure)
31
+ - [Explicit client (`AcceldataTracer`)](#explicit-client-acceldatatracer)
32
+ - [Environment variables](#environment-variables)
33
+ - [Auto-init from env](#auto-init-from-env)
34
+ - [Authentication](#authentication)
35
+ - [Integrations](#integrations)
36
+ - [Decorator-style integrations](#decorator-style-integrations)
37
+ - [Callback / handler-style integrations](#callback--handler-style-integrations)
38
+ - [Integration reference](#integration-reference)
39
+ - [Adding a new integration](#adding-a-new-integration)
40
+ - [Debugging](#debugging)
41
+ - [License](#license)
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install acceldata-aio-tracer
47
+ ```
48
+
49
+ Requires Python 3.10+. A pinned `opik` version is pulled transitively — do not install `opik` separately at a different version.
50
+
51
+ ## Quick start
52
+
53
+ ```python
54
+ import acceldata_aio_tracer as aio
55
+
56
+ aio.configure(
57
+ url="https://acme.acceldata.local:5443/aio",
58
+ access_key="...",
59
+ secret_key="...",
60
+ project_name="default",
61
+ )
62
+
63
+ @aio.track
64
+ def summarize(text: str) -> str:
65
+ # call an LLM, return the summary
66
+ ...
67
+
68
+ summarize("hello world") # traced and sent to Acceldata
69
+ ```
70
+
71
+ `aio.track` is the standard Opik `@track` decorator re-exported under the wrapper namespace. All other top-level Opik APIs (`opik.Opik`, `opik.flush`, etc.) are also available as `aio.Opik`, `aio.flush`, and so on.
72
+
73
+ ## Configuration
74
+
75
+ There are two configuration entry points; pick based on usage style.
76
+
77
+ ### Signature stability
78
+
79
+ Both `configure()` and `AcceldataTracer()` follow the same shape — three required positional-or-keyword args followed by keyword-only options:
80
+
81
+ ```python
82
+ def configure(
83
+ url: str, # required, stable public name
84
+ access_key: str, # required, stable public name
85
+ secret_key: str, # required, stable public name
86
+ *, # everything below is keyword-only
87
+ project_name: Optional[str] = None, # may evolve across releases
88
+ debug: bool = False, # may evolve across releases
89
+ check_tls_certificate: bool = True, # may evolve across releases
90
+ ) -> None: ...
91
+ ```
92
+
93
+ What this means in practice:
94
+
95
+ - **`url`, `access_key`, `secret_key` are required and will not be renamed.** Pass them positionally or by name — both forms are supported indefinitely.
96
+
97
+ ```python
98
+ # Both calls are equivalent:
99
+ aio.configure("https://acme.acceldata.local:5443/aio", "ak", "sk")
100
+ aio.configure(url="https://acme.acceldata.local:5443/aio", access_key="ak", secret_key="sk")
101
+ ```
102
+
103
+ - **All other options are keyword-only.** New options may be added, deprecated, or removed across releases without breaking existing call sites. Always pass them by name (`debug=True`, not `True`).
104
+ - **No partial calls.** All three required args must be supplied on every call. To change only a kwarg later (e.g. project name), either call `configure()` again with the full triple, or set the underlying env var directly (`os.environ["OPIK_PROJECT_NAME"] = "..."`).
105
+
106
+ ### Programmatic (`configure`)
107
+
108
+ Use this for workflows that rely on `@track` decorators or framework integrations — anything that creates the Opik client lazily.
109
+
110
+ ```python
111
+ import acceldata_aio_tracer as aio
112
+
113
+ aio.configure(
114
+ url="https://acme.acceldata.local:5443/aio",
115
+ access_key="...",
116
+ secret_key="...",
117
+ project_name="default", # optional
118
+ debug=False, # optional, see Debugging
119
+ check_tls_certificate=True, # set False only for self-signed dev gateways
120
+ )
121
+ ```
122
+
123
+ `configure()` sets the env vars Opik reads natively (`OPIK_URL_OVERRIDE`, `OPIK_ACCESS_KEY`, `OPIK_SECRET_KEY`, `OPIK_PROJECT_NAME`) and registers the Acceldata auth hook so every subsequent Opik client carries the auth headers.
124
+
125
+ ### Explicit client (`AcceldataTracer`)
126
+
127
+ Use this when you want a directly-constructed client (e.g. for non-decorator usage or to hold a per-request client).
128
+
129
+ ```python
130
+ from acceldata_aio_tracer import AcceldataTracer
131
+
132
+ client = AcceldataTracer(
133
+ url="https://acme.acceldata.local:5443/aio",
134
+ access_key="...",
135
+ secret_key="...",
136
+ )
137
+ # `client` is a fully-configured `opik.Opik` instance.
138
+ ```
139
+
140
+ Calling `AcceldataTracer(...)` also registers the auth hook globally, so any other Opik client created later in the process (including those used by integrations) inherits the auth.
141
+
142
+ ### Environment variables
143
+
144
+ | Variable | Purpose |
145
+ |---|---|
146
+ | `ACCELDATA_AIO_URL` | Acceldata gateway URL, e.g. `https://acme.acceldata.local:5443/aio` |
147
+ | `ACCELDATA_AIO_ACCESS_KEY` | Acceldata access key |
148
+ | `ACCELDATA_AIO_SECRET_KEY` | Acceldata secret key |
149
+ | `ACCELDATA_AIO_PROJECT_NAME` | Default project name for traces |
150
+ | `ACCELDATA_AIO_CHECK_TLS_CERTIFICATE` | `false` disables TLS verify on outbound Opik calls (dev / self-signed gateways only) |
151
+ | `ACCELDATA_AIO_DEBUG` | `true` / `1` / `yes` / `on` (case-insensitive) installs the HTTP debug interceptor at import time. Off by default. Wrapper-specific — no upstream fallback. |
152
+
153
+ The wrapper also respects the upstream Opik names (`OPIK_URL_OVERRIDE`, `OPIK_ACCESS_KEY`, `OPIK_SECRET_KEY`, `OPIK_PROJECT_NAME`, `OPIK_CHECK_TLS_CERTIFICATE`) as a fallback. If both an `ACCELDATA_AIO_*` and its `OPIK_*` counterpart are set, the `OPIK_*` value wins — useful as an escape hatch for migration, power-user overrides, or ops scripts that already reference Opik names.
154
+
155
+ At import time the wrapper prints a one-line summary to `stderr` listing which logical setting was picked from which env var name (names only, never values):
156
+
157
+ ```
158
+ [acceldata_aio_tracer] env init: URL<-ACCELDATA_AIO_URL, ACCESS_KEY<-ACCELDATA_AIO_ACCESS_KEY, SECRET_KEY<-ACCELDATA_AIO_SECRET_KEY
159
+ ```
160
+
161
+ ### Auto-init from env
162
+
163
+ If both `ACCELDATA_AIO_ACCESS_KEY` and `ACCELDATA_AIO_SECRET_KEY` (or their `OPIK_*` fallbacks) are present when the package is imported, the Acceldata auth hook is registered automatically — no `configure()` call needed.
164
+
165
+ ```bash
166
+ export ACCELDATA_AIO_URL="https://acme.acceldata.local:5443/aio"
167
+ export ACCELDATA_AIO_ACCESS_KEY="..."
168
+ export ACCELDATA_AIO_SECRET_KEY="..."
169
+ ```
170
+
171
+ ```python
172
+ import acceldata_aio_tracer # auth hook registered, env-init summary printed to stderr
173
+ ```
174
+
175
+ ## Authentication
176
+
177
+ Acceldata uses `accessKey` and `secretKey` HTTP headers instead of bearer tokens. The auth hook attaches these headers to every Opik HTTP request and removes any pre-existing `Authorization` header to avoid conflicts:
178
+
179
+ ```
180
+ accessKey: <ACCESS_KEY>
181
+ secretKey: <SECRET_KEY>
182
+ ```
183
+
184
+ The hook is installed once per process and applies to every `httpx.Client` Opik creates afterward.
185
+
186
+ ## Integrations
187
+
188
+ Every Opik integration is mirrored under `acceldata_aio_tracer.integrations.<framework>`. Two usage styles exist depending on the framework — pick based on the [reference table](#integration-reference) below.
189
+
190
+ ### Decorator-style integrations
191
+
192
+ Wrap an SDK client with `track_<framework>(...)`. Tracing is automatic from that point on.
193
+
194
+ ```python
195
+ from openai import OpenAI
196
+ from acceldata_aio_tracer.integrations.openai import track_openai
197
+
198
+ client = track_openai(OpenAI())
199
+ client.chat.completions.create(
200
+ model="gpt-4o-mini",
201
+ messages=[{"role": "user", "content": "hi"}],
202
+ ) # automatically traced
203
+ ```
204
+
205
+ The same shape applies to Anthropic, AWS Bedrock, Google GenAI, AISuite, LiteLLM, CrewAI, Guardrails AI, and Harbor — substitute the framework name in both the import and the function call.
206
+
207
+ ### Callback / handler-style integrations
208
+
209
+ Instantiate a tracer / callback / connector and pass it to the framework's callback machinery.
210
+
211
+ ```python
212
+ # LangChain / LangGraph
213
+ from acceldata_aio_tracer.integrations.langchain import LangChainTracer
214
+
215
+ tracer = LangChainTracer()
216
+ chain.invoke({"input": "..."}, config={"callbacks": [tracer]})
217
+ ```
218
+
219
+ ```python
220
+ # Google ADK
221
+ from acceldata_aio_tracer.integrations.adk import ADKTracer, track_adk_agent_recursive
222
+
223
+ tracer = ADKTracer()
224
+ track_adk_agent_recursive(my_agent, tracer)
225
+ ```
226
+
227
+ ```python
228
+ # DSPy
229
+ import dspy
230
+ from acceldata_aio_tracer.integrations.dspy import DSPyCallback
231
+
232
+ dspy.configure(callbacks=[DSPyCallback()])
233
+ ```
234
+
235
+ ```python
236
+ # Haystack
237
+ from acceldata_aio_tracer.integrations.haystack import HaystackConnector
238
+
239
+ pipeline.add_component("opik", HaystackConnector())
240
+ ```
241
+
242
+ ```python
243
+ # LlamaIndex
244
+ from llama_index.core.callbacks import CallbackManager
245
+ from acceldata_aio_tracer.integrations.llama_index import LlamaIndexCallbackHandler
246
+
247
+ manager = CallbackManager([LlamaIndexCallbackHandler()])
248
+ ```
249
+
250
+ ### Integration reference
251
+
252
+ 15 Opik integrations exist; 14 are mirrored here. Sagemaker is intentionally not exposed (upstream is an internal AWS auth helper with no public API).
253
+
254
+ | Integration | Import path | Exported names | Style | Renamed from upstream |
255
+ |---|---|---|---|---|
256
+ | LangChain / LangGraph | `acceldata_aio_tracer.integrations.langchain` | `LangChainTracer`, `track_langgraph`, `extract_current_langgraph_span_data`, `LANGGRAPH_INTERRUPT_OUTPUT_KEY`, `LANGGRAPH_RESUME_INPUT_KEY`, `LANGGRAPH_INTERRUPT_METADATA_KEY`, `LANGGRAPH_PARENT_COMMAND_METADATA_KEY` | Callback | `OpikTracer` -> `LangChainTracer` |
257
+ | Google ADK | `acceldata_aio_tracer.integrations.adk` | `ADKTracer`, `track_adk_agent_recursive`, `build_mermaid_graph_definition` | Callback | `OpikTracer` -> `ADKTracer` |
258
+ | DSPy | `acceldata_aio_tracer.integrations.dspy` | `DSPyCallback` | Callback | `OpikCallback` -> `DSPyCallback` |
259
+ | Haystack | `acceldata_aio_tracer.integrations.haystack` | `HaystackConnector` | Component | `OpikConnector` -> `HaystackConnector` |
260
+ | LlamaIndex | `acceldata_aio_tracer.integrations.llama_index` | `LlamaIndexCallbackHandler` | Callback | (already framework-named) |
261
+ | OpenAI | `acceldata_aio_tracer.integrations.openai` | `track_openai` | Decorator | (no rename) |
262
+ | Anthropic | `acceldata_aio_tracer.integrations.anthropic` | `track_anthropic` | Decorator | (no rename) |
263
+ | AWS Bedrock | `acceldata_aio_tracer.integrations.bedrock` | `track_bedrock` | Decorator | (no rename) |
264
+ | Google GenAI | `acceldata_aio_tracer.integrations.genai` | `track_genai` | Decorator | (no rename) |
265
+ | AISuite | `acceldata_aio_tracer.integrations.aisuite` | `track_aisuite` | Decorator | (no rename) |
266
+ | LiteLLM | `acceldata_aio_tracer.integrations.litellm` | `track_completion` | Decorator | (no rename) |
267
+ | CrewAI | `acceldata_aio_tracer.integrations.crewai` | `track_crewai` | Decorator | (no rename) |
268
+ | Guardrails AI | `acceldata_aio_tracer.integrations.guardrails` | `track_guardrails` | Decorator | (no rename) |
269
+ | Harbor | `acceldata_aio_tracer.integrations.harbor` | `track_harbor`, `reset_harbor_tracking` | Decorator | (no rename) |
270
+
271
+ For per-integration usage details (model versions, async patterns, edge cases, advanced config), refer to the [Opik documentation](https://www.comet.com/docs/opik/) — wrapper imports are drop-in equivalents.
272
+
273
+ ## Adding a new integration
274
+
275
+ When upstream Opik (`opik.integrations.<name>`) ships a new integration, mirror it here:
276
+
277
+ 1. Inspect the upstream `__init__.py` for the public exports.
278
+ 2. Create `src/acceldata_aio_tracer/integrations/<name>.py`:
279
+ - **Decorator-style** (`track_<name>` function): `from opik.integrations.<name> import track_<name>` + `__all__ = ("track_<name>",)`.
280
+ - **Class-style with Opik prefix** (`OpikTracer`, `OpikCallback`, `OpikConnector`): rename to a framework-named class. E.g. `from opik.integrations.<name> import OpikTracer as <Framework>Tracer`.
281
+ - **Class-style with framework prefix** (already framework-named): pass-through re-export.
282
+ 3. Add a row to the [Integration reference](#integration-reference) table above.
283
+ 4. Smoke-test: `python -c "from acceldata_aio_tracer.integrations.<name> import *"`.
284
+
285
+ The wrapper does not auto-mirror — every new upstream integration needs an explicit file.
286
+
287
+ ## Debugging
288
+
289
+ To trace every Opik HTTP call (including a copy-paste `curl` reproducer for any 4xx/5xx response), enable debug mode:
290
+
291
+ ```python
292
+ aio.configure(url=..., access_key=..., secret_key=..., debug=True)
293
+ # or
294
+ client = AcceldataTracer(url=..., access_key=..., secret_key=..., debug=True)
295
+ ```
296
+
297
+ On a failed request, the request body is dumped to `/tmp/acceldata-aio-tracer-last-failed-request.bin` and a replay-ready `curl` command is printed to the `acceldata_aio_tracer.http_trace` logger.
298
+
299
+ ## License
300
+
301
+ Apache-2.0. This SDK is a thin wrapper around [Opik](https://github.com/comet-ml/opik), which is also Apache-2.0 licensed.
@@ -0,0 +1,286 @@
1
+ # acceldata-aio-tracer
2
+
3
+ LLM observability SDK by Acceldata, built on top of [Opik](https://github.com/comet-ml/opik). It:
4
+
5
+ - Adds Acceldata `accessKey` / `secretKey` authentication to every Opik HTTP call via an httpx auth hook.
6
+ - Re-exports the full Opik public API under the `acceldata_aio_tracer` namespace.
7
+ - Mirrors all Opik integrations under `acceldata_aio_tracer.integrations.<framework>` so customer code never imports from `opik` directly.
8
+
9
+ ## Index
10
+
11
+ - [Installation](#installation)
12
+ - [Quick start](#quick-start)
13
+ - [Configuration](#configuration)
14
+ - [Signature stability](#signature-stability)
15
+ - [Programmatic (`configure`)](#programmatic-configure)
16
+ - [Explicit client (`AcceldataTracer`)](#explicit-client-acceldatatracer)
17
+ - [Environment variables](#environment-variables)
18
+ - [Auto-init from env](#auto-init-from-env)
19
+ - [Authentication](#authentication)
20
+ - [Integrations](#integrations)
21
+ - [Decorator-style integrations](#decorator-style-integrations)
22
+ - [Callback / handler-style integrations](#callback--handler-style-integrations)
23
+ - [Integration reference](#integration-reference)
24
+ - [Adding a new integration](#adding-a-new-integration)
25
+ - [Debugging](#debugging)
26
+ - [License](#license)
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ pip install acceldata-aio-tracer
32
+ ```
33
+
34
+ Requires Python 3.10+. A pinned `opik` version is pulled transitively — do not install `opik` separately at a different version.
35
+
36
+ ## Quick start
37
+
38
+ ```python
39
+ import acceldata_aio_tracer as aio
40
+
41
+ aio.configure(
42
+ url="https://acme.acceldata.local:5443/aio",
43
+ access_key="...",
44
+ secret_key="...",
45
+ project_name="default",
46
+ )
47
+
48
+ @aio.track
49
+ def summarize(text: str) -> str:
50
+ # call an LLM, return the summary
51
+ ...
52
+
53
+ summarize("hello world") # traced and sent to Acceldata
54
+ ```
55
+
56
+ `aio.track` is the standard Opik `@track` decorator re-exported under the wrapper namespace. All other top-level Opik APIs (`opik.Opik`, `opik.flush`, etc.) are also available as `aio.Opik`, `aio.flush`, and so on.
57
+
58
+ ## Configuration
59
+
60
+ There are two configuration entry points; pick based on usage style.
61
+
62
+ ### Signature stability
63
+
64
+ Both `configure()` and `AcceldataTracer()` follow the same shape — three required positional-or-keyword args followed by keyword-only options:
65
+
66
+ ```python
67
+ def configure(
68
+ url: str, # required, stable public name
69
+ access_key: str, # required, stable public name
70
+ secret_key: str, # required, stable public name
71
+ *, # everything below is keyword-only
72
+ project_name: Optional[str] = None, # may evolve across releases
73
+ debug: bool = False, # may evolve across releases
74
+ check_tls_certificate: bool = True, # may evolve across releases
75
+ ) -> None: ...
76
+ ```
77
+
78
+ What this means in practice:
79
+
80
+ - **`url`, `access_key`, `secret_key` are required and will not be renamed.** Pass them positionally or by name — both forms are supported indefinitely.
81
+
82
+ ```python
83
+ # Both calls are equivalent:
84
+ aio.configure("https://acme.acceldata.local:5443/aio", "ak", "sk")
85
+ aio.configure(url="https://acme.acceldata.local:5443/aio", access_key="ak", secret_key="sk")
86
+ ```
87
+
88
+ - **All other options are keyword-only.** New options may be added, deprecated, or removed across releases without breaking existing call sites. Always pass them by name (`debug=True`, not `True`).
89
+ - **No partial calls.** All three required args must be supplied on every call. To change only a kwarg later (e.g. project name), either call `configure()` again with the full triple, or set the underlying env var directly (`os.environ["OPIK_PROJECT_NAME"] = "..."`).
90
+
91
+ ### Programmatic (`configure`)
92
+
93
+ Use this for workflows that rely on `@track` decorators or framework integrations — anything that creates the Opik client lazily.
94
+
95
+ ```python
96
+ import acceldata_aio_tracer as aio
97
+
98
+ aio.configure(
99
+ url="https://acme.acceldata.local:5443/aio",
100
+ access_key="...",
101
+ secret_key="...",
102
+ project_name="default", # optional
103
+ debug=False, # optional, see Debugging
104
+ check_tls_certificate=True, # set False only for self-signed dev gateways
105
+ )
106
+ ```
107
+
108
+ `configure()` sets the env vars Opik reads natively (`OPIK_URL_OVERRIDE`, `OPIK_ACCESS_KEY`, `OPIK_SECRET_KEY`, `OPIK_PROJECT_NAME`) and registers the Acceldata auth hook so every subsequent Opik client carries the auth headers.
109
+
110
+ ### Explicit client (`AcceldataTracer`)
111
+
112
+ Use this when you want a directly-constructed client (e.g. for non-decorator usage or to hold a per-request client).
113
+
114
+ ```python
115
+ from acceldata_aio_tracer import AcceldataTracer
116
+
117
+ client = AcceldataTracer(
118
+ url="https://acme.acceldata.local:5443/aio",
119
+ access_key="...",
120
+ secret_key="...",
121
+ )
122
+ # `client` is a fully-configured `opik.Opik` instance.
123
+ ```
124
+
125
+ Calling `AcceldataTracer(...)` also registers the auth hook globally, so any other Opik client created later in the process (including those used by integrations) inherits the auth.
126
+
127
+ ### Environment variables
128
+
129
+ | Variable | Purpose |
130
+ |---|---|
131
+ | `ACCELDATA_AIO_URL` | Acceldata gateway URL, e.g. `https://acme.acceldata.local:5443/aio` |
132
+ | `ACCELDATA_AIO_ACCESS_KEY` | Acceldata access key |
133
+ | `ACCELDATA_AIO_SECRET_KEY` | Acceldata secret key |
134
+ | `ACCELDATA_AIO_PROJECT_NAME` | Default project name for traces |
135
+ | `ACCELDATA_AIO_CHECK_TLS_CERTIFICATE` | `false` disables TLS verify on outbound Opik calls (dev / self-signed gateways only) |
136
+ | `ACCELDATA_AIO_DEBUG` | `true` / `1` / `yes` / `on` (case-insensitive) installs the HTTP debug interceptor at import time. Off by default. Wrapper-specific — no upstream fallback. |
137
+
138
+ The wrapper also respects the upstream Opik names (`OPIK_URL_OVERRIDE`, `OPIK_ACCESS_KEY`, `OPIK_SECRET_KEY`, `OPIK_PROJECT_NAME`, `OPIK_CHECK_TLS_CERTIFICATE`) as a fallback. If both an `ACCELDATA_AIO_*` and its `OPIK_*` counterpart are set, the `OPIK_*` value wins — useful as an escape hatch for migration, power-user overrides, or ops scripts that already reference Opik names.
139
+
140
+ At import time the wrapper prints a one-line summary to `stderr` listing which logical setting was picked from which env var name (names only, never values):
141
+
142
+ ```
143
+ [acceldata_aio_tracer] env init: URL<-ACCELDATA_AIO_URL, ACCESS_KEY<-ACCELDATA_AIO_ACCESS_KEY, SECRET_KEY<-ACCELDATA_AIO_SECRET_KEY
144
+ ```
145
+
146
+ ### Auto-init from env
147
+
148
+ If both `ACCELDATA_AIO_ACCESS_KEY` and `ACCELDATA_AIO_SECRET_KEY` (or their `OPIK_*` fallbacks) are present when the package is imported, the Acceldata auth hook is registered automatically — no `configure()` call needed.
149
+
150
+ ```bash
151
+ export ACCELDATA_AIO_URL="https://acme.acceldata.local:5443/aio"
152
+ export ACCELDATA_AIO_ACCESS_KEY="..."
153
+ export ACCELDATA_AIO_SECRET_KEY="..."
154
+ ```
155
+
156
+ ```python
157
+ import acceldata_aio_tracer # auth hook registered, env-init summary printed to stderr
158
+ ```
159
+
160
+ ## Authentication
161
+
162
+ Acceldata uses `accessKey` and `secretKey` HTTP headers instead of bearer tokens. The auth hook attaches these headers to every Opik HTTP request and removes any pre-existing `Authorization` header to avoid conflicts:
163
+
164
+ ```
165
+ accessKey: <ACCESS_KEY>
166
+ secretKey: <SECRET_KEY>
167
+ ```
168
+
169
+ The hook is installed once per process and applies to every `httpx.Client` Opik creates afterward.
170
+
171
+ ## Integrations
172
+
173
+ Every Opik integration is mirrored under `acceldata_aio_tracer.integrations.<framework>`. Two usage styles exist depending on the framework — pick based on the [reference table](#integration-reference) below.
174
+
175
+ ### Decorator-style integrations
176
+
177
+ Wrap an SDK client with `track_<framework>(...)`. Tracing is automatic from that point on.
178
+
179
+ ```python
180
+ from openai import OpenAI
181
+ from acceldata_aio_tracer.integrations.openai import track_openai
182
+
183
+ client = track_openai(OpenAI())
184
+ client.chat.completions.create(
185
+ model="gpt-4o-mini",
186
+ messages=[{"role": "user", "content": "hi"}],
187
+ ) # automatically traced
188
+ ```
189
+
190
+ The same shape applies to Anthropic, AWS Bedrock, Google GenAI, AISuite, LiteLLM, CrewAI, Guardrails AI, and Harbor — substitute the framework name in both the import and the function call.
191
+
192
+ ### Callback / handler-style integrations
193
+
194
+ Instantiate a tracer / callback / connector and pass it to the framework's callback machinery.
195
+
196
+ ```python
197
+ # LangChain / LangGraph
198
+ from acceldata_aio_tracer.integrations.langchain import LangChainTracer
199
+
200
+ tracer = LangChainTracer()
201
+ chain.invoke({"input": "..."}, config={"callbacks": [tracer]})
202
+ ```
203
+
204
+ ```python
205
+ # Google ADK
206
+ from acceldata_aio_tracer.integrations.adk import ADKTracer, track_adk_agent_recursive
207
+
208
+ tracer = ADKTracer()
209
+ track_adk_agent_recursive(my_agent, tracer)
210
+ ```
211
+
212
+ ```python
213
+ # DSPy
214
+ import dspy
215
+ from acceldata_aio_tracer.integrations.dspy import DSPyCallback
216
+
217
+ dspy.configure(callbacks=[DSPyCallback()])
218
+ ```
219
+
220
+ ```python
221
+ # Haystack
222
+ from acceldata_aio_tracer.integrations.haystack import HaystackConnector
223
+
224
+ pipeline.add_component("opik", HaystackConnector())
225
+ ```
226
+
227
+ ```python
228
+ # LlamaIndex
229
+ from llama_index.core.callbacks import CallbackManager
230
+ from acceldata_aio_tracer.integrations.llama_index import LlamaIndexCallbackHandler
231
+
232
+ manager = CallbackManager([LlamaIndexCallbackHandler()])
233
+ ```
234
+
235
+ ### Integration reference
236
+
237
+ 15 Opik integrations exist; 14 are mirrored here. Sagemaker is intentionally not exposed (upstream is an internal AWS auth helper with no public API).
238
+
239
+ | Integration | Import path | Exported names | Style | Renamed from upstream |
240
+ |---|---|---|---|---|
241
+ | LangChain / LangGraph | `acceldata_aio_tracer.integrations.langchain` | `LangChainTracer`, `track_langgraph`, `extract_current_langgraph_span_data`, `LANGGRAPH_INTERRUPT_OUTPUT_KEY`, `LANGGRAPH_RESUME_INPUT_KEY`, `LANGGRAPH_INTERRUPT_METADATA_KEY`, `LANGGRAPH_PARENT_COMMAND_METADATA_KEY` | Callback | `OpikTracer` -> `LangChainTracer` |
242
+ | Google ADK | `acceldata_aio_tracer.integrations.adk` | `ADKTracer`, `track_adk_agent_recursive`, `build_mermaid_graph_definition` | Callback | `OpikTracer` -> `ADKTracer` |
243
+ | DSPy | `acceldata_aio_tracer.integrations.dspy` | `DSPyCallback` | Callback | `OpikCallback` -> `DSPyCallback` |
244
+ | Haystack | `acceldata_aio_tracer.integrations.haystack` | `HaystackConnector` | Component | `OpikConnector` -> `HaystackConnector` |
245
+ | LlamaIndex | `acceldata_aio_tracer.integrations.llama_index` | `LlamaIndexCallbackHandler` | Callback | (already framework-named) |
246
+ | OpenAI | `acceldata_aio_tracer.integrations.openai` | `track_openai` | Decorator | (no rename) |
247
+ | Anthropic | `acceldata_aio_tracer.integrations.anthropic` | `track_anthropic` | Decorator | (no rename) |
248
+ | AWS Bedrock | `acceldata_aio_tracer.integrations.bedrock` | `track_bedrock` | Decorator | (no rename) |
249
+ | Google GenAI | `acceldata_aio_tracer.integrations.genai` | `track_genai` | Decorator | (no rename) |
250
+ | AISuite | `acceldata_aio_tracer.integrations.aisuite` | `track_aisuite` | Decorator | (no rename) |
251
+ | LiteLLM | `acceldata_aio_tracer.integrations.litellm` | `track_completion` | Decorator | (no rename) |
252
+ | CrewAI | `acceldata_aio_tracer.integrations.crewai` | `track_crewai` | Decorator | (no rename) |
253
+ | Guardrails AI | `acceldata_aio_tracer.integrations.guardrails` | `track_guardrails` | Decorator | (no rename) |
254
+ | Harbor | `acceldata_aio_tracer.integrations.harbor` | `track_harbor`, `reset_harbor_tracking` | Decorator | (no rename) |
255
+
256
+ For per-integration usage details (model versions, async patterns, edge cases, advanced config), refer to the [Opik documentation](https://www.comet.com/docs/opik/) — wrapper imports are drop-in equivalents.
257
+
258
+ ## Adding a new integration
259
+
260
+ When upstream Opik (`opik.integrations.<name>`) ships a new integration, mirror it here:
261
+
262
+ 1. Inspect the upstream `__init__.py` for the public exports.
263
+ 2. Create `src/acceldata_aio_tracer/integrations/<name>.py`:
264
+ - **Decorator-style** (`track_<name>` function): `from opik.integrations.<name> import track_<name>` + `__all__ = ("track_<name>",)`.
265
+ - **Class-style with Opik prefix** (`OpikTracer`, `OpikCallback`, `OpikConnector`): rename to a framework-named class. E.g. `from opik.integrations.<name> import OpikTracer as <Framework>Tracer`.
266
+ - **Class-style with framework prefix** (already framework-named): pass-through re-export.
267
+ 3. Add a row to the [Integration reference](#integration-reference) table above.
268
+ 4. Smoke-test: `python -c "from acceldata_aio_tracer.integrations.<name> import *"`.
269
+
270
+ The wrapper does not auto-mirror — every new upstream integration needs an explicit file.
271
+
272
+ ## Debugging
273
+
274
+ To trace every Opik HTTP call (including a copy-paste `curl` reproducer for any 4xx/5xx response), enable debug mode:
275
+
276
+ ```python
277
+ aio.configure(url=..., access_key=..., secret_key=..., debug=True)
278
+ # or
279
+ client = AcceldataTracer(url=..., access_key=..., secret_key=..., debug=True)
280
+ ```
281
+
282
+ On a failed request, the request body is dumped to `/tmp/acceldata-aio-tracer-last-failed-request.bin` and a replay-ready `curl` command is printed to the `acceldata_aio_tracer.http_trace` logger.
283
+
284
+ ## License
285
+
286
+ Apache-2.0. This SDK is a thin wrapper around [Opik](https://github.com/comet-ml/opik), which is also Apache-2.0 licensed.
@@ -0,0 +1,20 @@
1
+ [tool.poetry]
2
+ name = "acceldata-aio-tracer"
3
+ version = "0.1.0.dev1"
4
+ description = "Acceldata LLM observability SDK"
5
+ authors = ["Acceldata"]
6
+ license = "Apache-2.0"
7
+ readme = "README.md"
8
+ packages = [{ include = "acceldata_aio_tracer", from = "src" }]
9
+
10
+ [tool.poetry.dependencies]
11
+ python = "^3.10"
12
+ opik = "1.11.3"
13
+ httpx = "*"
14
+
15
+ [tool.poetry.group.dev.dependencies]
16
+ pytest = "^8.0.0"
17
+
18
+ [build-system]
19
+ requires = ["poetry-core"]
20
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,34 @@
1
+ # -*- coding: utf-8 -*-
2
+ from setuptools import setup
3
+
4
+ package_dir = \
5
+ {'': 'src'}
6
+
7
+ packages = \
8
+ ['acceldata_aio_tracer', 'acceldata_aio_tracer.integrations']
9
+
10
+ package_data = \
11
+ {'': ['*']}
12
+
13
+ install_requires = \
14
+ ['httpx', 'opik==1.11.3']
15
+
16
+ setup_kwargs = {
17
+ 'name': 'acceldata-aio-tracer',
18
+ 'version': '0.1.0.dev1',
19
+ 'description': 'Acceldata LLM observability SDK',
20
+ 'long_description': '# acceldata-aio-tracer\n\nLLM observability SDK by Acceldata, built on top of [Opik](https://github.com/comet-ml/opik). It:\n\n- Adds Acceldata `accessKey` / `secretKey` authentication to every Opik HTTP call via an httpx auth hook.\n- Re-exports the full Opik public API under the `acceldata_aio_tracer` namespace.\n- Mirrors all Opik integrations under `acceldata_aio_tracer.integrations.<framework>` so customer code never imports from `opik` directly.\n\n## Index\n\n- [Installation](#installation)\n- [Quick start](#quick-start)\n- [Configuration](#configuration)\n - [Signature stability](#signature-stability)\n - [Programmatic (`configure`)](#programmatic-configure)\n - [Explicit client (`AcceldataTracer`)](#explicit-client-acceldatatracer)\n - [Environment variables](#environment-variables)\n - [Auto-init from env](#auto-init-from-env)\n- [Authentication](#authentication)\n- [Integrations](#integrations)\n - [Decorator-style integrations](#decorator-style-integrations)\n - [Callback / handler-style integrations](#callback--handler-style-integrations)\n - [Integration reference](#integration-reference)\n- [Adding a new integration](#adding-a-new-integration)\n- [Debugging](#debugging)\n- [License](#license)\n\n## Installation\n\n```bash\npip install acceldata-aio-tracer\n```\n\nRequires Python 3.10+. A pinned `opik` version is pulled transitively — do not install `opik` separately at a different version.\n\n## Quick start\n\n```python\nimport acceldata_aio_tracer as aio\n\naio.configure(\n url="https://acme.acceldata.local:5443/aio",\n access_key="...",\n secret_key="...",\n project_name="default",\n)\n\n@aio.track\ndef summarize(text: str) -> str:\n # call an LLM, return the summary\n ...\n\nsummarize("hello world") # traced and sent to Acceldata\n```\n\n`aio.track` is the standard Opik `@track` decorator re-exported under the wrapper namespace. All other top-level Opik APIs (`opik.Opik`, `opik.flush`, etc.) are also available as `aio.Opik`, `aio.flush`, and so on.\n\n## Configuration\n\nThere are two configuration entry points; pick based on usage style.\n\n### Signature stability\n\nBoth `configure()` and `AcceldataTracer()` follow the same shape — three required positional-or-keyword args followed by keyword-only options:\n\n```python\ndef configure(\n url: str, # required, stable public name\n access_key: str, # required, stable public name\n secret_key: str, # required, stable public name\n *, # everything below is keyword-only\n project_name: Optional[str] = None, # may evolve across releases\n debug: bool = False, # may evolve across releases\n check_tls_certificate: bool = True, # may evolve across releases\n) -> None: ...\n```\n\nWhat this means in practice:\n\n- **`url`, `access_key`, `secret_key` are required and will not be renamed.** Pass them positionally or by name — both forms are supported indefinitely.\n\n```python\n# Both calls are equivalent:\naio.configure("https://acme.acceldata.local:5443/aio", "ak", "sk")\naio.configure(url="https://acme.acceldata.local:5443/aio", access_key="ak", secret_key="sk")\n```\n\n- **All other options are keyword-only.** New options may be added, deprecated, or removed across releases without breaking existing call sites. Always pass them by name (`debug=True`, not `True`).\n- **No partial calls.** All three required args must be supplied on every call. To change only a kwarg later (e.g. project name), either call `configure()` again with the full triple, or set the underlying env var directly (`os.environ["OPIK_PROJECT_NAME"] = "..."`).\n\n### Programmatic (`configure`)\n\nUse this for workflows that rely on `@track` decorators or framework integrations — anything that creates the Opik client lazily.\n\n```python\nimport acceldata_aio_tracer as aio\n\naio.configure(\n url="https://acme.acceldata.local:5443/aio",\n access_key="...",\n secret_key="...",\n project_name="default", # optional\n debug=False, # optional, see Debugging\n check_tls_certificate=True, # set False only for self-signed dev gateways\n)\n```\n\n`configure()` sets the env vars Opik reads natively (`OPIK_URL_OVERRIDE`, `OPIK_ACCESS_KEY`, `OPIK_SECRET_KEY`, `OPIK_PROJECT_NAME`) and registers the Acceldata auth hook so every subsequent Opik client carries the auth headers.\n\n### Explicit client (`AcceldataTracer`)\n\nUse this when you want a directly-constructed client (e.g. for non-decorator usage or to hold a per-request client).\n\n```python\nfrom acceldata_aio_tracer import AcceldataTracer\n\nclient = AcceldataTracer(\n url="https://acme.acceldata.local:5443/aio",\n access_key="...",\n secret_key="...",\n)\n# `client` is a fully-configured `opik.Opik` instance.\n```\n\nCalling `AcceldataTracer(...)` also registers the auth hook globally, so any other Opik client created later in the process (including those used by integrations) inherits the auth.\n\n### Environment variables\n\n| Variable | Purpose |\n|---|---|\n| `ACCELDATA_AIO_URL` | Acceldata gateway URL, e.g. `https://acme.acceldata.local:5443/aio` |\n| `ACCELDATA_AIO_ACCESS_KEY` | Acceldata access key |\n| `ACCELDATA_AIO_SECRET_KEY` | Acceldata secret key |\n| `ACCELDATA_AIO_PROJECT_NAME` | Default project name for traces |\n| `ACCELDATA_AIO_CHECK_TLS_CERTIFICATE` | `false` disables TLS verify on outbound Opik calls (dev / self-signed gateways only) |\n| `ACCELDATA_AIO_DEBUG` | `true` / `1` / `yes` / `on` (case-insensitive) installs the HTTP debug interceptor at import time. Off by default. Wrapper-specific — no upstream fallback. |\n\nThe wrapper also respects the upstream Opik names (`OPIK_URL_OVERRIDE`, `OPIK_ACCESS_KEY`, `OPIK_SECRET_KEY`, `OPIK_PROJECT_NAME`, `OPIK_CHECK_TLS_CERTIFICATE`) as a fallback. If both an `ACCELDATA_AIO_*` and its `OPIK_*` counterpart are set, the `OPIK_*` value wins — useful as an escape hatch for migration, power-user overrides, or ops scripts that already reference Opik names.\n\nAt import time the wrapper prints a one-line summary to `stderr` listing which logical setting was picked from which env var name (names only, never values):\n\n```\n[acceldata_aio_tracer] env init: URL<-ACCELDATA_AIO_URL, ACCESS_KEY<-ACCELDATA_AIO_ACCESS_KEY, SECRET_KEY<-ACCELDATA_AIO_SECRET_KEY\n```\n\n### Auto-init from env\n\nIf both `ACCELDATA_AIO_ACCESS_KEY` and `ACCELDATA_AIO_SECRET_KEY` (or their `OPIK_*` fallbacks) are present when the package is imported, the Acceldata auth hook is registered automatically — no `configure()` call needed.\n\n```bash\nexport ACCELDATA_AIO_URL="https://acme.acceldata.local:5443/aio"\nexport ACCELDATA_AIO_ACCESS_KEY="..."\nexport ACCELDATA_AIO_SECRET_KEY="..."\n```\n\n```python\nimport acceldata_aio_tracer # auth hook registered, env-init summary printed to stderr\n```\n\n## Authentication\n\nAcceldata uses `accessKey` and `secretKey` HTTP headers instead of bearer tokens. The auth hook attaches these headers to every Opik HTTP request and removes any pre-existing `Authorization` header to avoid conflicts:\n\n```\naccessKey: <ACCESS_KEY>\nsecretKey: <SECRET_KEY>\n```\n\nThe hook is installed once per process and applies to every `httpx.Client` Opik creates afterward.\n\n## Integrations\n\nEvery Opik integration is mirrored under `acceldata_aio_tracer.integrations.<framework>`. Two usage styles exist depending on the framework — pick based on the [reference table](#integration-reference) below.\n\n### Decorator-style integrations\n\nWrap an SDK client with `track_<framework>(...)`. Tracing is automatic from that point on.\n\n```python\nfrom openai import OpenAI\nfrom acceldata_aio_tracer.integrations.openai import track_openai\n\nclient = track_openai(OpenAI())\nclient.chat.completions.create(\n model="gpt-4o-mini",\n messages=[{"role": "user", "content": "hi"}],\n) # automatically traced\n```\n\nThe same shape applies to Anthropic, AWS Bedrock, Google GenAI, AISuite, LiteLLM, CrewAI, Guardrails AI, and Harbor — substitute the framework name in both the import and the function call.\n\n### Callback / handler-style integrations\n\nInstantiate a tracer / callback / connector and pass it to the framework\'s callback machinery.\n\n```python\n# LangChain / LangGraph\nfrom acceldata_aio_tracer.integrations.langchain import LangChainTracer\n\ntracer = LangChainTracer()\nchain.invoke({"input": "..."}, config={"callbacks": [tracer]})\n```\n\n```python\n# Google ADK\nfrom acceldata_aio_tracer.integrations.adk import ADKTracer, track_adk_agent_recursive\n\ntracer = ADKTracer()\ntrack_adk_agent_recursive(my_agent, tracer)\n```\n\n```python\n# DSPy\nimport dspy\nfrom acceldata_aio_tracer.integrations.dspy import DSPyCallback\n\ndspy.configure(callbacks=[DSPyCallback()])\n```\n\n```python\n# Haystack\nfrom acceldata_aio_tracer.integrations.haystack import HaystackConnector\n\npipeline.add_component("opik", HaystackConnector())\n```\n\n```python\n# LlamaIndex\nfrom llama_index.core.callbacks import CallbackManager\nfrom acceldata_aio_tracer.integrations.llama_index import LlamaIndexCallbackHandler\n\nmanager = CallbackManager([LlamaIndexCallbackHandler()])\n```\n\n### Integration reference\n\n15 Opik integrations exist; 14 are mirrored here. Sagemaker is intentionally not exposed (upstream is an internal AWS auth helper with no public API).\n\n| Integration | Import path | Exported names | Style | Renamed from upstream |\n|---|---|---|---|---|\n| LangChain / LangGraph | `acceldata_aio_tracer.integrations.langchain` | `LangChainTracer`, `track_langgraph`, `extract_current_langgraph_span_data`, `LANGGRAPH_INTERRUPT_OUTPUT_KEY`, `LANGGRAPH_RESUME_INPUT_KEY`, `LANGGRAPH_INTERRUPT_METADATA_KEY`, `LANGGRAPH_PARENT_COMMAND_METADATA_KEY` | Callback | `OpikTracer` -> `LangChainTracer` |\n| Google ADK | `acceldata_aio_tracer.integrations.adk` | `ADKTracer`, `track_adk_agent_recursive`, `build_mermaid_graph_definition` | Callback | `OpikTracer` -> `ADKTracer` |\n| DSPy | `acceldata_aio_tracer.integrations.dspy` | `DSPyCallback` | Callback | `OpikCallback` -> `DSPyCallback` |\n| Haystack | `acceldata_aio_tracer.integrations.haystack` | `HaystackConnector` | Component | `OpikConnector` -> `HaystackConnector` |\n| LlamaIndex | `acceldata_aio_tracer.integrations.llama_index` | `LlamaIndexCallbackHandler` | Callback | (already framework-named) |\n| OpenAI | `acceldata_aio_tracer.integrations.openai` | `track_openai` | Decorator | (no rename) |\n| Anthropic | `acceldata_aio_tracer.integrations.anthropic` | `track_anthropic` | Decorator | (no rename) |\n| AWS Bedrock | `acceldata_aio_tracer.integrations.bedrock` | `track_bedrock` | Decorator | (no rename) |\n| Google GenAI | `acceldata_aio_tracer.integrations.genai` | `track_genai` | Decorator | (no rename) |\n| AISuite | `acceldata_aio_tracer.integrations.aisuite` | `track_aisuite` | Decorator | (no rename) |\n| LiteLLM | `acceldata_aio_tracer.integrations.litellm` | `track_completion` | Decorator | (no rename) |\n| CrewAI | `acceldata_aio_tracer.integrations.crewai` | `track_crewai` | Decorator | (no rename) |\n| Guardrails AI | `acceldata_aio_tracer.integrations.guardrails` | `track_guardrails` | Decorator | (no rename) |\n| Harbor | `acceldata_aio_tracer.integrations.harbor` | `track_harbor`, `reset_harbor_tracking` | Decorator | (no rename) |\n\nFor per-integration usage details (model versions, async patterns, edge cases, advanced config), refer to the [Opik documentation](https://www.comet.com/docs/opik/) — wrapper imports are drop-in equivalents.\n\n## Adding a new integration\n\nWhen upstream Opik (`opik.integrations.<name>`) ships a new integration, mirror it here:\n\n1. Inspect the upstream `__init__.py` for the public exports.\n2. Create `src/acceldata_aio_tracer/integrations/<name>.py`:\n - **Decorator-style** (`track_<name>` function): `from opik.integrations.<name> import track_<name>` + `__all__ = ("track_<name>",)`.\n - **Class-style with Opik prefix** (`OpikTracer`, `OpikCallback`, `OpikConnector`): rename to a framework-named class. E.g. `from opik.integrations.<name> import OpikTracer as <Framework>Tracer`.\n - **Class-style with framework prefix** (already framework-named): pass-through re-export.\n3. Add a row to the [Integration reference](#integration-reference) table above.\n4. Smoke-test: `python -c "from acceldata_aio_tracer.integrations.<name> import *"`.\n\nThe wrapper does not auto-mirror — every new upstream integration needs an explicit file.\n\n## Debugging\n\nTo trace every Opik HTTP call (including a copy-paste `curl` reproducer for any 4xx/5xx response), enable debug mode:\n\n```python\naio.configure(url=..., access_key=..., secret_key=..., debug=True)\n# or\nclient = AcceldataTracer(url=..., access_key=..., secret_key=..., debug=True)\n```\n\nOn a failed request, the request body is dumped to `/tmp/acceldata-aio-tracer-last-failed-request.bin` and a replay-ready `curl` command is printed to the `acceldata_aio_tracer.http_trace` logger.\n\n## License\n\nApache-2.0. This SDK is a thin wrapper around [Opik](https://github.com/comet-ml/opik), which is also Apache-2.0 licensed.',
21
+ 'author': 'Acceldata',
22
+ 'author_email': 'None',
23
+ 'maintainer': 'None',
24
+ 'maintainer_email': 'None',
25
+ 'url': 'None',
26
+ 'package_dir': package_dir,
27
+ 'packages': packages,
28
+ 'package_data': package_data,
29
+ 'install_requires': install_requires,
30
+ 'python_requires': '>=3.10,<4.0',
31
+ }
32
+
33
+
34
+ setup(**setup_kwargs)
@@ -0,0 +1,91 @@
1
+ from typing import Optional
2
+
3
+ import opik as _opik
4
+ from opik import * # noqa: F401, F403
5
+
6
+ from . import _opik_bridge
7
+ from .auth import (
8
+ AcceldataAuth,
9
+ setup_acceldata_auth,
10
+ setup_acceldata_auth_hook,
11
+ )
12
+ from .client import AcceldataTracer
13
+
14
+
15
+ def configure(
16
+ url: str,
17
+ access_key: str,
18
+ secret_key: str,
19
+ *,
20
+ project_name: Optional[str] = None,
21
+ debug: bool = False,
22
+ check_tls_certificate: bool = True,
23
+ ) -> None:
24
+ """Acceldata equivalent of opik.configure().
25
+
26
+ Registers the Acceldata auth hook so every subsequent Opik client
27
+ carries accessKey/secretKey headers, applies the URL/project settings,
28
+ and optionally installs an HTTP debug interceptor.
29
+
30
+ The first three parameters (``url``, ``access_key``, ``secret_key``) are
31
+ the SDK's stable public surface and may be passed positionally or by
32
+ name. All other options are keyword-only so future flags can be added,
33
+ deprecated, or removed without breaking customer call sites.
34
+
35
+ Each argument has a matching ``ACCELDATA_AIO_*`` env variable that can
36
+ be used instead of an explicit call. If both are present the explicit
37
+ argument wins; if neither, ``configure()`` cannot be skipped. Upstream
38
+ ``OPIK_*`` names are accepted as a fallback (see README "Environment
39
+ variables").
40
+
41
+ Args:
42
+ url: Acceldata gateway URL, e.g.
43
+ ``https://acme.acceldata.local:5443/aio``.
44
+ Env: ``ACCELDATA_AIO_URL`` (fallback: ``OPIK_URL_OVERRIDE``).
45
+ access_key: Acceldata API access key.
46
+ Env: ``ACCELDATA_AIO_ACCESS_KEY``
47
+ (fallback: ``OPIK_ACCESS_KEY``).
48
+ secret_key: Acceldata API secret key.
49
+ Env: ``ACCELDATA_AIO_SECRET_KEY``
50
+ (fallback: ``OPIK_SECRET_KEY``).
51
+ project_name: Default project name for traces.
52
+ Env: ``ACCELDATA_AIO_PROJECT_NAME``
53
+ (fallback: ``OPIK_PROJECT_NAME``).
54
+ debug: When True, install an httpx interceptor that logs every Opik
55
+ HTTP call and, on >=400 responses, dumps the request body to
56
+ disk and prints a copy-paste curl for replay. Off by default.
57
+ Env: ``ACCELDATA_AIO_DEBUG`` accepts ``1`` / ``true`` / ``yes``
58
+ / ``on`` (case-insensitive) to enable. Wrapper-specific — has
59
+ no upstream ``OPIK_*`` fallback.
60
+ check_tls_certificate: When False, disables TLS certificate
61
+ verification for outbound HTTP calls. Use only for local dev
62
+ against self-signed gateways. Default True.
63
+ Env: ``ACCELDATA_AIO_CHECK_TLS_CERTIFICATE``
64
+ (fallback: ``OPIK_CHECK_TLS_CERTIFICATE``).
65
+ """
66
+ _opik_bridge.apply_configure(
67
+ url=url,
68
+ access_key=access_key,
69
+ secret_key=secret_key,
70
+ project_name=project_name,
71
+ debug=debug,
72
+ check_tls_certificate=check_tls_certificate,
73
+ )
74
+
75
+
76
+ # Bootstrap ACCELDATA_AIO_* env vars and auto-register the auth hook at
77
+ # import time. All upstream-naming details live in _opik_bridge so this
78
+ # module stays free of OPIK_* references.
79
+ _opik_bridge.bootstrap_from_env()
80
+
81
+
82
+ __all__ = (
83
+ "AcceldataTracer",
84
+ "AcceldataAuth",
85
+ "configure",
86
+ "setup_acceldata_auth",
87
+ "setup_acceldata_auth_hook",
88
+ *_opik.__all__,
89
+ )
90
+
91
+ del _opik
@@ -0,0 +1,107 @@
1
+ """Bridge between the Acceldata-branded API surface and upstream Opik internals.
2
+
3
+ Everything in this module knows about the OPIK_* env-var names and the
4
+ upstream Opik configuration keys. Nothing outside this module should
5
+ reference them — that keeps the public package surface (__init__.py,
6
+ configure(), etc.) brand-clean.
7
+ """
8
+
9
+ import os
10
+ import sys
11
+ from typing import Optional
12
+
13
+ from .auth import setup_acceldata_auth_hook
14
+ from .client import _install_http_debug_interceptor
15
+
16
+
17
+ # Customer-facing AIO env var name -> upstream Opik env var name.
18
+ # Upstream names are an internal implementation detail and never exposed
19
+ # in the public API.
20
+ _ALIASES = (
21
+ ("URL", "ACCELDATA_AIO_URL", "OPIK_URL_OVERRIDE"),
22
+ ("ACCESS_KEY", "ACCELDATA_AIO_ACCESS_KEY", "OPIK_ACCESS_KEY"),
23
+ ("SECRET_KEY", "ACCELDATA_AIO_SECRET_KEY", "OPIK_SECRET_KEY"),
24
+ ("PROJECT_NAME", "ACCELDATA_AIO_PROJECT_NAME", "OPIK_PROJECT_NAME"),
25
+ ("CHECK_TLS_CERTIFICATE", "ACCELDATA_AIO_CHECK_TLS_CERTIFICATE", "OPIK_CHECK_TLS_CERTIFICATE"),
26
+ )
27
+
28
+
29
+ def _parse_truthy(value: str) -> bool:
30
+ """True for common truthy string representations: 1, true, yes, on (case-insensitive)."""
31
+ return value.strip().lower() in ("1", "true", "yes", "on")
32
+
33
+
34
+ def bootstrap_from_env() -> None:
35
+ """Translate ACCELDATA_AIO_* env vars to the upstream names Opik reads
36
+ natively, then auto-register the auth hook if creds are present and
37
+ install the HTTP debug interceptor if ``ACCELDATA_AIO_DEBUG`` is truthy.
38
+
39
+ An explicit upstream value (e.g. OPIK_URL_OVERRIDE) wins over its
40
+ ACCELDATA_AIO_* counterpart — escape hatch for migration, ops scripts,
41
+ or power-user overrides.
42
+
43
+ Prints a one-line stderr summary naming which env var fed each setting
44
+ (names only, never values).
45
+ """
46
+ picked = []
47
+ for label, aio_name, upstream_name in _ALIASES:
48
+ if os.environ.get(upstream_name) is not None:
49
+ picked.append((label, upstream_name))
50
+ elif os.environ.get(aio_name) is not None:
51
+ os.environ[upstream_name] = os.environ[aio_name]
52
+ picked.append((label, aio_name))
53
+
54
+ debug_raw = os.environ.get("ACCELDATA_AIO_DEBUG")
55
+ debug_enabled = debug_raw is not None and _parse_truthy(debug_raw)
56
+ if debug_enabled:
57
+ picked.append(("DEBUG", "ACCELDATA_AIO_DEBUG"))
58
+
59
+ if picked:
60
+ summary = ", ".join(f"{label}<-{source}" for label, source in picked)
61
+ print(f"[acceldata_aio_tracer] env init: {summary}", file=sys.stderr)
62
+ else:
63
+ print(
64
+ "[acceldata_aio_tracer] env init: no ACCELDATA_AIO_* or upstream "
65
+ "env vars detected; call configure() to set explicitly",
66
+ file=sys.stderr,
67
+ )
68
+
69
+ access_key = os.environ.get("OPIK_ACCESS_KEY")
70
+ secret_key = os.environ.get("OPIK_SECRET_KEY")
71
+ if access_key and secret_key:
72
+ setup_acceldata_auth_hook(access_key, secret_key)
73
+
74
+ if debug_enabled:
75
+ url = os.environ.get("OPIK_URL_OVERRIDE")
76
+ if url:
77
+ _install_http_debug_interceptor(url)
78
+ else:
79
+ print(
80
+ "[acceldata_aio_tracer] env init: ACCELDATA_AIO_DEBUG is truthy "
81
+ "but no URL configured; debug interceptor not installed",
82
+ file=sys.stderr,
83
+ )
84
+
85
+
86
+ def apply_configure(
87
+ *,
88
+ url: str,
89
+ access_key: str,
90
+ secret_key: str,
91
+ project_name: Optional[str],
92
+ debug: bool,
93
+ check_tls_certificate: bool,
94
+ ) -> None:
95
+ """Apply the side effects of a configure() call: write upstream env vars,
96
+ register the Acceldata auth hook, optionally install the HTTP debug
97
+ interceptor.
98
+ """
99
+ os.environ["OPIK_URL_OVERRIDE"] = url
100
+ os.environ["OPIK_ACCESS_KEY"] = access_key
101
+ os.environ["OPIK_SECRET_KEY"] = secret_key
102
+ if project_name is not None:
103
+ os.environ["OPIK_PROJECT_NAME"] = project_name
104
+ setup_acceldata_auth_hook(access_key, secret_key)
105
+ os.environ["OPIK_CHECK_TLS_CERTIFICATE"] = "true" if check_tls_certificate else "false"
106
+ if debug:
107
+ _install_http_debug_interceptor(url)
@@ -0,0 +1,38 @@
1
+ import os
2
+
3
+ import httpx
4
+ import opik.hooks
5
+
6
+
7
+ class AcceldataAuth(httpx.Auth):
8
+ def __init__(self, access_key: str, secret_key: str) -> None:
9
+ self.access_key = access_key
10
+ self.secret_key = secret_key
11
+
12
+ def auth_flow(self, request): # type: ignore
13
+ request.headers.pop("authorization", None)
14
+ request.headers["accessKey"] = self.access_key
15
+ request.headers["secretKey"] = self.secret_key
16
+ yield request
17
+
18
+
19
+ def setup_acceldata_auth_hook(access_key: str, secret_key: str) -> None:
20
+ def acceldata_auth_client_hook(client: httpx.Client) -> None:
21
+ client.auth = AcceldataAuth(access_key, secret_key)
22
+
23
+ opik.hooks.add_httpx_client_hook(
24
+ opik.hooks.HttpxClientHook(
25
+ client_modifier=acceldata_auth_client_hook,
26
+ client_init_arguments=None,
27
+ )
28
+ )
29
+
30
+
31
+ def setup_acceldata_auth(url: str, access_key: str, secret_key: str) -> None:
32
+ """Boot-time setup for users of @opik.track and Opik integrations.
33
+
34
+ Call once before any tracked function runs. Subsequent Opik clients
35
+ (including the cached one used by @track) will pick up the auth.
36
+ """
37
+ os.environ.setdefault("OPIK_URL_OVERRIDE", url)
38
+ setup_acceldata_auth_hook(access_key, secret_key)
@@ -0,0 +1,166 @@
1
+ import logging
2
+ import os
3
+ import shlex
4
+ from typing import Any
5
+ from urllib.parse import urlparse
6
+
7
+ from opik import Opik
8
+
9
+ from .auth import setup_acceldata_auth_hook
10
+
11
+
12
+ _DEBUG_REQ_DUMP_PATH = "/tmp/acceldata-aio-tracer-last-failed-request.bin"
13
+ _debug_installed = False
14
+
15
+
16
+ def _install_http_debug_interceptor(opik_url: str) -> None:
17
+ """Patch httpx.Client.send and httpx.AsyncClient.send to log every Opik
18
+ HTTP call. On responses with status >= 400, dumps the request body to
19
+ `_DEBUG_REQ_DUMP_PATH` and prints a copy-paste curl that replays the
20
+ request. Idempotent — safe to call multiple times.
21
+ """
22
+ global _debug_installed
23
+ if _debug_installed:
24
+ return
25
+
26
+ import httpx
27
+
28
+ logger = logging.getLogger("acceldata_aio_tracer.http_trace")
29
+ logger.setLevel(logging.DEBUG)
30
+ if not logger.handlers:
31
+ h = logging.StreamHandler()
32
+ h.setFormatter(logging.Formatter(
33
+ "%(asctime)s %(levelname)-5s acceldata_aio_tracer.http_trace: %(message)s"
34
+ ))
35
+ logger.addHandler(h)
36
+ logger.propagate = False
37
+
38
+ target_host = urlparse(opik_url).netloc
39
+
40
+ def is_opik_url(url) -> bool:
41
+ try:
42
+ return urlparse(str(url)).netloc == target_host
43
+ except Exception:
44
+ return False
45
+
46
+ def fmt_body(body) -> str:
47
+ if body is None:
48
+ return "<none>"
49
+ if isinstance(body, (bytes, bytearray)):
50
+ try:
51
+ return body.decode("utf-8", errors="replace")[:4000]
52
+ except Exception:
53
+ return f"<{len(body)} bytes>"
54
+ return str(body)[:4000]
55
+
56
+ def decode_resp(resp_body) -> str:
57
+ if isinstance(resp_body, (bytes, bytearray)):
58
+ return resp_body.decode("utf-8", errors="replace")
59
+ return str(resp_body)
60
+
61
+ def build_replay_curl(method: str, url: str, headers: dict, body_path) -> str:
62
+ parts = ["curl -v --insecure -X", method, shlex.quote(str(url))]
63
+ for k, v in headers.items():
64
+ if k.lower() in ("host", "content-length"):
65
+ continue
66
+ parts += ["-H", shlex.quote(f"{k}: {v}")]
67
+ if body_path:
68
+ parts += ["--data-binary", f"@{body_path}"]
69
+ return " \\\n ".join(parts)
70
+
71
+ def dump_request_body(request) -> str:
72
+ if not request.content:
73
+ return ""
74
+ try:
75
+ with open(_DEBUG_REQ_DUMP_PATH, "wb") as f:
76
+ f.write(request.content)
77
+ return _DEBUG_REQ_DUMP_PATH
78
+ except Exception as write_err:
79
+ logger.warning(f"failed to dump request body: {write_err}")
80
+ return ""
81
+
82
+ def log_failure(request, response, resp_body, async_marker: str = "") -> None:
83
+ body_path = dump_request_body(request)
84
+ decoded = decode_resp(resp_body)[:8000]
85
+ curl = build_replay_curl(
86
+ request.method, str(request.url), dict(request.headers), body_path
87
+ )
88
+ logger.error(
89
+ f"<<< {async_marker}{response.status_code} {request.method} {request.url}\n"
90
+ f" error_body={decoded}\n"
91
+ f" request_body_dumped_to={body_path or '<none>'}\n"
92
+ f" REPLAY (paste into shell):\n{curl}"
93
+ )
94
+
95
+ orig_send = httpx.Client.send
96
+
97
+ def patched_send(self, request, *args, **kwargs):
98
+ log_this = is_opik_url(request.url)
99
+ if log_this:
100
+ logger.debug(
101
+ f">>> {request.method} {request.url}\n"
102
+ f" headers={dict(request.headers)}\n"
103
+ f" body={fmt_body(request.content)}"
104
+ )
105
+ response = orig_send(self, request, *args, **kwargs)
106
+ if log_this:
107
+ try:
108
+ resp_body = response.read()
109
+ except Exception as read_err:
110
+ resp_body = f"<read failed: {read_err}>".encode()
111
+ if response.status_code >= 400:
112
+ log_failure(request, response, resp_body)
113
+ else:
114
+ logger.debug(
115
+ f"<<< {response.status_code} {request.method} {request.url}\n"
116
+ f" body={fmt_body(resp_body)}"
117
+ )
118
+ return response
119
+
120
+ httpx.Client.send = patched_send
121
+
122
+ orig_async_send = httpx.AsyncClient.send
123
+
124
+ async def patched_async_send(self, request, *args, **kwargs):
125
+ log_this = is_opik_url(request.url)
126
+ if log_this:
127
+ logger.debug(
128
+ f">>> [async] {request.method} {request.url}\n"
129
+ f" headers={dict(request.headers)}\n"
130
+ f" body={fmt_body(request.content)}"
131
+ )
132
+ response = await orig_async_send(self, request, *args, **kwargs)
133
+ if log_this:
134
+ try:
135
+ resp_body = await response.aread()
136
+ except Exception as read_err:
137
+ resp_body = f"<read failed: {read_err}>".encode()
138
+ if response.status_code >= 400:
139
+ log_failure(request, response, resp_body, async_marker="[async] ")
140
+ else:
141
+ logger.debug(
142
+ f"<<< [async] {response.status_code} {request.method} {request.url}\n"
143
+ f" body={fmt_body(resp_body)}"
144
+ )
145
+ return response
146
+
147
+ httpx.AsyncClient.send = patched_async_send
148
+
149
+ _debug_installed = True
150
+ logger.info(f"http debug interceptor installed for host={target_host}")
151
+
152
+
153
+ def AcceldataTracer(
154
+ url: str,
155
+ access_key: str,
156
+ secret_key: str,
157
+ *,
158
+ debug: bool = False,
159
+ check_tls_certificate: bool = True,
160
+ **kwargs: Any,
161
+ ) -> Opik:
162
+ setup_acceldata_auth_hook(access_key, secret_key)
163
+ os.environ["OPIK_CHECK_TLS_CERTIFICATE"] = "true" if check_tls_certificate else "false"
164
+ if debug:
165
+ _install_http_debug_interceptor(url)
166
+ return Opik(host=url, **kwargs)
@@ -0,0 +1,11 @@
1
+ from opik.integrations.adk import (
2
+ OpikTracer as ADKTracer,
3
+ build_mermaid_graph_definition,
4
+ track_adk_agent_recursive,
5
+ )
6
+
7
+ __all__ = (
8
+ "ADKTracer",
9
+ "track_adk_agent_recursive",
10
+ "build_mermaid_graph_definition",
11
+ )
@@ -0,0 +1,3 @@
1
+ from opik.integrations.aisuite import track_aisuite
2
+
3
+ __all__ = ("track_aisuite",)
@@ -0,0 +1,3 @@
1
+ from opik.integrations.anthropic import track_anthropic
2
+
3
+ __all__ = ("track_anthropic",)
@@ -0,0 +1,3 @@
1
+ from opik.integrations.bedrock import track_bedrock
2
+
3
+ __all__ = ("track_bedrock",)
@@ -0,0 +1,3 @@
1
+ from opik.integrations.crewai import track_crewai
2
+
3
+ __all__ = ("track_crewai",)
@@ -0,0 +1,3 @@
1
+ from opik.integrations.dspy import OpikCallback as DSPyCallback
2
+
3
+ __all__ = ("DSPyCallback",)
@@ -0,0 +1,3 @@
1
+ from opik.integrations.genai import track_genai
2
+
3
+ __all__ = ("track_genai",)
@@ -0,0 +1,3 @@
1
+ from opik.integrations.guardrails import track_guardrails
2
+
3
+ __all__ = ("track_guardrails",)
@@ -0,0 +1,3 @@
1
+ from opik.integrations.harbor import reset_harbor_tracking, track_harbor
2
+
3
+ __all__ = ("track_harbor", "reset_harbor_tracking")
@@ -0,0 +1,3 @@
1
+ from opik.integrations.haystack import OpikConnector as HaystackConnector
2
+
3
+ __all__ = ("HaystackConnector",)
@@ -0,0 +1,19 @@
1
+ from opik.integrations.langchain import (
2
+ LANGGRAPH_INTERRUPT_METADATA_KEY,
3
+ LANGGRAPH_INTERRUPT_OUTPUT_KEY,
4
+ LANGGRAPH_PARENT_COMMAND_METADATA_KEY,
5
+ LANGGRAPH_RESUME_INPUT_KEY,
6
+ OpikTracer as LangChainTracer,
7
+ extract_current_langgraph_span_data,
8
+ track_langgraph,
9
+ )
10
+
11
+ __all__ = (
12
+ "LangChainTracer",
13
+ "track_langgraph",
14
+ "extract_current_langgraph_span_data",
15
+ "LANGGRAPH_INTERRUPT_OUTPUT_KEY",
16
+ "LANGGRAPH_RESUME_INPUT_KEY",
17
+ "LANGGRAPH_INTERRUPT_METADATA_KEY",
18
+ "LANGGRAPH_PARENT_COMMAND_METADATA_KEY",
19
+ )
@@ -0,0 +1,3 @@
1
+ from opik.integrations.litellm import track_completion
2
+
3
+ __all__ = ("track_completion",)
@@ -0,0 +1,3 @@
1
+ from opik.integrations.llama_index import LlamaIndexCallbackHandler
2
+
3
+ __all__ = ("LlamaIndexCallbackHandler",)
@@ -0,0 +1,3 @@
1
+ from opik.integrations.openai import track_openai
2
+
3
+ __all__ = ("track_openai",)