tracely-ai 0.1.0__py3-none-any.whl

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,266 @@
1
+ Metadata-Version: 2.4
2
+ Name: tracely-ai
3
+ Version: 0.1.0
4
+ Summary: Tracely Python SDK: automatic + manual agent tracing, exported to Tracely over OTLP.
5
+ Project-URL: Homepage, https://github.com/Jwuthri/Tracely
6
+ Project-URL: Documentation, https://github.com/Jwuthri/Tracely/blob/master/sdk/README.md
7
+ Project-URL: Source, https://github.com/Jwuthri/Tracely
8
+ Project-URL: Issues, https://github.com/Jwuthri/Tracely/issues
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,evals,llm,observability,opentelemetry,tracing
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: System :: Monitoring
16
+ Requires-Python: >=3.10
17
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.25
18
+ Requires-Dist: opentelemetry-sdk>=1.25
19
+ Provides-Extra: all
20
+ Requires-Dist: anthropic; extra == 'all'
21
+ Requires-Dist: claude-agent-sdk; extra == 'all'
22
+ Requires-Dist: crewai; extra == 'all'
23
+ Requires-Dist: google-adk; extra == 'all'
24
+ Requires-Dist: google-genai>=0.3; extra == 'all'
25
+ Requires-Dist: langchain-openrouter>=0.1.0; extra == 'all'
26
+ Requires-Dist: litellm>=1.40; extra == 'all'
27
+ Requires-Dist: llama-index; extra == 'all'
28
+ Requires-Dist: mistralai>=1.0; extra == 'all'
29
+ Requires-Dist: openai-agents; extra == 'all'
30
+ Requires-Dist: openinference-instrumentation-anthropic>=0.1.0; extra == 'all'
31
+ Requires-Dist: openinference-instrumentation-bedrock>=0.1.0; extra == 'all'
32
+ Requires-Dist: openinference-instrumentation-claude-agent-sdk>=0.1.0; extra == 'all'
33
+ Requires-Dist: openinference-instrumentation-crewai>=0.1.0; extra == 'all'
34
+ Requires-Dist: openinference-instrumentation-google-adk>=0.1.0; extra == 'all'
35
+ Requires-Dist: openinference-instrumentation-google-genai>=0.1.0; extra == 'all'
36
+ Requires-Dist: openinference-instrumentation-groq>=0.1.0; extra == 'all'
37
+ Requires-Dist: openinference-instrumentation-langchain>=0.1.0; extra == 'all'
38
+ Requires-Dist: openinference-instrumentation-llama-index>=0.1.0; extra == 'all'
39
+ Requires-Dist: openinference-instrumentation-mistralai>=0.1.0; extra == 'all'
40
+ Requires-Dist: openinference-instrumentation-openai-agents>=0.1.0; extra == 'all'
41
+ Requires-Dist: openinference-instrumentation-openai>=0.1.0; extra == 'all'
42
+ Provides-Extra: anthropic
43
+ Requires-Dist: anthropic; extra == 'anthropic'
44
+ Requires-Dist: openinference-instrumentation-anthropic>=0.1.0; extra == 'anthropic'
45
+ Provides-Extra: bedrock
46
+ Requires-Dist: openinference-instrumentation-bedrock>=0.1.0; extra == 'bedrock'
47
+ Provides-Extra: claude-agent-sdk
48
+ Requires-Dist: claude-agent-sdk; extra == 'claude-agent-sdk'
49
+ Requires-Dist: openinference-instrumentation-claude-agent-sdk>=0.1.0; extra == 'claude-agent-sdk'
50
+ Provides-Extra: crewai
51
+ Requires-Dist: crewai; extra == 'crewai'
52
+ Requires-Dist: openinference-instrumentation-crewai>=0.1.0; extra == 'crewai'
53
+ Provides-Extra: google
54
+ Requires-Dist: google-genai>=0.3; extra == 'google'
55
+ Requires-Dist: openinference-instrumentation-google-genai>=0.1.0; extra == 'google'
56
+ Provides-Extra: google-adk
57
+ Requires-Dist: google-adk; extra == 'google-adk'
58
+ Requires-Dist: openinference-instrumentation-google-adk>=0.1.0; extra == 'google-adk'
59
+ Provides-Extra: google-genai
60
+ Requires-Dist: google-genai>=0.3; extra == 'google-genai'
61
+ Provides-Extra: groq
62
+ Requires-Dist: openinference-instrumentation-groq>=0.1.0; extra == 'groq'
63
+ Provides-Extra: langchain
64
+ Requires-Dist: openinference-instrumentation-langchain>=0.1.0; extra == 'langchain'
65
+ Provides-Extra: litellm
66
+ Requires-Dist: litellm>=1.40; extra == 'litellm'
67
+ Provides-Extra: llama-index
68
+ Requires-Dist: llama-index; extra == 'llama-index'
69
+ Requires-Dist: openinference-instrumentation-llama-index>=0.1.0; extra == 'llama-index'
70
+ Provides-Extra: mistral
71
+ Requires-Dist: mistralai>=1.0; extra == 'mistral'
72
+ Requires-Dist: openinference-instrumentation-mistralai>=0.1.0; extra == 'mistral'
73
+ Provides-Extra: mistral-sdk
74
+ Requires-Dist: mistralai>=1.0; extra == 'mistral-sdk'
75
+ Provides-Extra: openai
76
+ Requires-Dist: openinference-instrumentation-openai>=0.1.0; extra == 'openai'
77
+ Provides-Extra: openai-agents
78
+ Requires-Dist: openai-agents; extra == 'openai-agents'
79
+ Requires-Dist: openinference-instrumentation-openai-agents>=0.1.0; extra == 'openai-agents'
80
+ Provides-Extra: openllmetry
81
+ Requires-Dist: opentelemetry-instrumentation-anthropic>=0.30b0; extra == 'openllmetry'
82
+ Requires-Dist: opentelemetry-instrumentation-openai-v2>=2.0b0; extra == 'openllmetry'
83
+ Provides-Extra: openrouter
84
+ Requires-Dist: langchain-openrouter>=0.1.0; extra == 'openrouter'
85
+ Provides-Extra: openrouter-openai
86
+ Requires-Dist: openai>=1.0; extra == 'openrouter-openai'
87
+ Provides-Extra: xai
88
+ Requires-Dist: openai>=1.0; extra == 'xai'
89
+ Description-Content-Type: text/markdown
90
+
91
+ # `tracely-ai` — instrument agents + the CI gate CLI
92
+
93
+ Two things in one small package:
94
+
95
+ 1. an **instrumentation SDK** — `tracely.init()` activates the OpenAI/Anthropic/LangChain/LiteLLM auto-instrumentors so your existing code is traced with **zero span code** (the default path); a custom `SpanProcessor` stamps the active `tracely.trace()` run context onto every span — including the zero-touch provider spans. Manual context managers remain the escape hatch. Everything emits standard `gen_ai.*` / OpenInference attributes **plus** Tracely's first-class `tracely.*` hints, so the backend can populate its agent-semantic columns; and
96
+ 2. the **`tracely` CLI** — `tracely gate` and `tracely replay`, which run an agent's promoted regression suite in CI and gate the PR (exit 0/1 + GitHub status/comment).
97
+
98
+ The core depends only on `opentelemetry-sdk` + the OTLP HTTP exporter (Python ≥ 3.10); a provider extra adds that provider's auto-instrumentor.
99
+
100
+ ```bash
101
+ pip install "tracely-ai[openai]" # provider extras: [openai] [anthropic] [langchain] [litellm] [all]
102
+ # or: pip install tracely-ai # core only (manual API + CLI)
103
+ # import name is `tracely_sdk`; the CLI is `tracely` (entry point tracely_sdk.cli:main)
104
+ ```
105
+
106
+ > Already using OpenTelemetry / OpenInference / LangGraph instrumentation? You don't need the instrumentation half — point your existing OTLP exporter at `POST {endpoint}/v1/traces` with `Authorization: Bearer <ingest-key>` and set the `tracely.*` attributes below. This SDK is just the ergonomic path. The **CLI**, however, is how you wire Tracely into CI.
107
+
108
+ ---
109
+
110
+ ## 1. Instrument an agent
111
+
112
+ ### Automatic (the default — zero span code)
113
+
114
+ `init()` activates the auto-instrumentors; `trace()` attaches the run context; `@observe` adds
115
+ function-level spans. No manual span code.
116
+
117
+ ```python
118
+ import tracely_sdk as tracely
119
+ from openai import OpenAI
120
+
121
+ tracely.init(endpoint="http://localhost:8000", api_key="tracely_dev_key",
122
+ service_name="support-agent", env="prod", instrument="auto")
123
+
124
+ with tracely.trace(agent="support-agent", conversation="conv-1", user="u_42"):
125
+ OpenAI().chat.completions.create(model="gpt-4o", messages=[...]) # GENERATION span, captured
126
+
127
+ @tracely.observe(as_type="agent") # args→input, return→output, auto-nested
128
+ def plan(goal): ...
129
+ ```
130
+
131
+ `instrument` is `"auto"` (every importable provider SDK), an explicit list (`["openai",
132
+ "anthropic"]`), or `False`. The `tracely.trace()` hints flow onto **every** span inside it — including
133
+ the provider spans the instrumentor creates — via a custom `SpanProcessor`. Streaming token usage
134
+ needs `stream_options={"include_usage": True}`.
135
+
136
+ **Also covered:** LangChain/LangGraph (`[langchain]` — graphs nest, node names become steps), LiteLLM
137
+ (`instrument=["litellm"]` — 100+ providers via one callback), and a non-patching drop-in
138
+ (`from tracely_sdk.openai import OpenAI` / `wrap_openai`). Under `"auto"`, when the LangChain
139
+ instrumentor is present it owns LLM spans and the provider instrumentors are skipped to avoid
140
+ duplicate spans (override with an explicit list). Full guide: the docs [Automatic instrumentation](https://github.com/Jwuthri/Tracely/blob/master/docs/pages/automatic.mdx) page.
141
+
142
+ ### Manual / custom spans (the escape hatch)
143
+
144
+ For anything the auto path doesn't cover. Each `with` block is a span; nesting builds the tree.
145
+
146
+ ```python
147
+ import tracely_sdk as tracely
148
+
149
+ tracely.init(endpoint="http://localhost:8000", api_key="tracely_dev_key",
150
+ service_name="support-agent", env="prod")
151
+
152
+ with tracely.agent("support-agent", version="v3", conversation="conv-1", turn=0) as a: # AGENT span = run root
153
+ tracely.set_io(a, input=user_msg, output=answer) # what the agent received / returned
154
+ with tracely.thinking(agent="support-agent") as th: # THINKING span (reasoning)
155
+ tracely.set_io(th, output=reasoning); tracely.set_usage(th, thinking_tokens=120)
156
+ with tracely.llm("gpt-4o", agent="support-agent") as g: # GENERATION span
157
+ tracely.set_io(g, input=messages, output=completion)
158
+ tracely.set_usage(g, input_tokens=812, output_tokens=96)
159
+ with tracely.tool("get_order", agent="support-agent") as t: # TOOL span
160
+ try:
161
+ result = get_order(order_id)
162
+ tracely.set_io(t, input={"order_id": order_id}, output=result)
163
+ except Exception as e:
164
+ tracely.error(t, str(e)) # level=ERROR → the failure signal
165
+
166
+ tracely.flush() # force-flush the exporter (call before the process exits)
167
+ ```
168
+
169
+ ### Span context managers — one per observation type
170
+ | Call | Span type | Sets |
171
+ |---|---|---|
172
+ | `agent(slug, *, version, run_id, role, conversation, turn, user, trace_name, handoff_from, edge="delegate")` | `AGENT` (run root) | `tracely.agent.id`/`.version`/`.run_id`/`.role`, `tracely.conversation.id` + `session.id`, `tracely.turn.index`, `tracely.env`; `user`→`tracely.user.id`, `trace_name`→`tracely.trace.name`; `handoff_from`→ a handoff edge (`caller`→this agent, `edge.type`). |
173
+ | `llm(model, *, agent, temperature, top_p, max_tokens, frequency_penalty, presence_penalty, seed, tool_calls, metadata)` | `GENERATION` | `gen_ai.request.model` + the sampling params as `gen_ai.request.*`; `tool_calls`→`tracely.tool_calls` (tools the model **requested**); `metadata`→`tracely.metadata.*`. |
174
+ | `tool(name, *, agent)` | `TOOL` | `gen_ai.operation.name=execute_tool`, `gen_ai.tool.name`. |
175
+ | `thinking(name="thinking", *, agent, model)` | `THINKING` | reasoning emitted as its own span; optional `model`. |
176
+ | `retriever(name="retrieve", *, agent)` | `RETRIEVER` | a retrieval step — query in `set_io(input=)`, hits in `set_io(output=)`. |
177
+ | `embedding(model, *, agent)` | `EMBEDDING` | `gen_ai.request.model`; record tokens with `set_usage(input_tokens=)`. |
178
+ | `guardrail(name="guardrail", *, agent)` | `GUARDRAIL` | a safety/policy check — verdict in `set_io(output={"action": "allow"\|"block"})`. |
179
+ | `chain(name, *, agent)` | `CHAIN` | a grouping span (e.g. a RAG pipeline) — nest other spans inside it. |
180
+ | `turn(turn_id, *, index)` / `step(name, *, step_id)` | marker / generic | `tracely.turn.*` / `tracely.step.*`. |
181
+
182
+ ### Annotating spans
183
+ - `set_io(span, *, input=None, output=None)` → `tracely.input` / `tracely.output` (objects are JSON-encoded; message content is a `{role, content:[blocks]}` object or a content-block list).
184
+ - `set_usage(span, *, input_tokens=None, output_tokens=None, thinking_tokens=None)` → `gen_ai.usage.input_tokens` / `output_tokens` / `reasoning_tokens`.
185
+ - `set_metadata(span, **kv)` → `tracely.metadata.<key>` — arbitrary tags (e.g. prompt version, tenant), surfaced in the span's Metadata and searchable.
186
+ - `error(span, message="")` → marks the span `StatusCode.ERROR` (→ `level=ERROR` in Tracely) — this is *the* failure-detection signal.
187
+ - `flush()` → force-flush the OTLP exporter.
188
+
189
+ ### What Tracely reads
190
+ Standard `gen_ai.*` / OpenInference attributes, plus first-class hints that become **indexed columns** on the span row: `tracely.agent.id`/`.version`/`.role`, `tracely.user.id`, `tracely.trace.name`, `tracely.conversation.id`, `tracely.turn.id`/`.index`, `tracely.step.id`/`.name`, `tracely.observation.type`, `tracely.tool_calls`, `tracely.handoff.*` + `tracely.edge.type`, the `gen_ai.request.*` sampling params, and `tracely.env` (`prod|staging|ci|dev` — the gating axis). Agent slug + version are auto-registered into the Postgres registry on ingest.
191
+
192
+ ### Declaring a conversation's agent catalog
193
+ Pass `agents=[{name, description, tools:[...]}]` to `tracely.trace(...)` (or call `set_agents([...])`) to declare the agents/tools a conversation uses — emitted once as `tracely.agents`. The backend stores this per conversation; the UI's **Conversation Agents** panel renders it (with per-tool run counts) and the LLM judge can read it as `@LIST_AGENT`. Without it, Tracely still derives the agent view from the spans.
194
+
195
+ ---
196
+
197
+ ## 2. Hermetic replay (`call_tool` / `call_llm` / `fixtures`)
198
+
199
+ These let the **same agent code** run live in production and deterministically offline in CI. Wrap each external call:
200
+
201
+ ```python
202
+ def run(user_input: str):
203
+ with tracely.agent("support-agent"):
204
+ # In prod: calls the real fn and records the output. In replay: serves the recorded output.
205
+ order = tracely.call_tool("get_order", lambda: get_order(order_id), args={"order_id": order_id})
206
+ answer = tracely.call_llm("gpt-4o", lambda: chat(messages), input=messages, usage=(812, 96))
207
+ return answer
208
+ ```
209
+
210
+ - **Production (`--live` or no fixtures active):** `call_tool`/`call_llm` invoke your `fn`, record the output (and any error) on the span, and return it.
211
+ - **CI replay:** `tracely replay` activates the case's recorded **fixture bundle** via `with tracely.fixtures(bundle): ...`; `call_tool`/`call_llm` then **serve the recorded outputs in order** (or by `args` match) and never call your `fn`. A call that errored in production is reproduced on the span **and raised as `tracely.ToolError`**, so the agent's own `try/except` runs exactly as it would live — and the gate sees the same failure condition.
212
+
213
+ **Auto-instrument / drop-in code replays too** (no manual seam required): inside a `fixtures()` block Tracely class-patches the provider's create-method, so code that calls the SDK directly — `client.chat.completions.create(...)` under `instrument="auto"` or the `tracely_sdk.openai` drop-in — is served the recorded completion (reconstructed into a provider-shaped response) and never hits the network. Covered today: **OpenAI `chat.completions`** and **Anthropic `messages`**; other providers fall back to live in replay until added. The manual `call_llm` seam remains the way to get provider-agnostic hermetic replay everywhere.
214
+
215
+ This is what makes replay deterministic, offline, and free (no API keys, no cost). See [regression-testing design](https://github.com/Jwuthri/Tracely/blob/master/design/part2-tracely/05-regression-testing.md).
216
+
217
+ ---
218
+
219
+ ## 3. The CI gate CLI
220
+
221
+ ```bash
222
+ tracely gate <agent> [--env ci] [--api …] [--key …] [--pr N] [--sha …] [--github]
223
+ tracely replay <agent> (--entrypoint module:func | --cmd "…") [--live] [--github]
224
+ ```
225
+
226
+ - **`tracely gate <agent>`** — gate a PR against **pre-emitted** `env=ci` traces (your CI already ran the agent and emitted traces); cases are matched to candidates by `input_digest`.
227
+ - **`tracely replay <agent>`** — re-run the agent **on each promoted case's recorded input** (fetched from `GET /api/gate/suite`), then gate. `--entrypoint module:func` calls a Python function per case; `--cmd "…"` runs a shell command per case (gets `TRACELY_INPUT`) that emits its own trace. Hermetic by default; `--live` makes real tool/LLM calls.
228
+
229
+ Both **exit 0 (PASS) / 1 (FAIL)** and, inside GitHub Actions (or with `--github`), post a **commit status + PR comment** with per-case results and soft warnings (latency/token deltas vs the last green gate). `--dry-run` prints the GitHub calls instead of sending; `--no-github` never touches GitHub. Config via flags or env (`TRACELY_API`, `TRACELY_KEY`, `TRACELY_AGENT`, `TRACELY_GATE_ENV`, `TRACELY_WEB_URL`, `GITHUB_TOKEN`). A reusable composite action lives at `.github/actions/tracely-gate/`.
230
+
231
+ ---
232
+
233
+ ## Examples (`sdk/examples/` + `sdk/example.py`)
234
+
235
+ [`examples/README.md`](examples/README.md) is the full index — **one runnable file per way of
236
+ tracing**, all the same fake-DB **two-agent conversation** (a Support Agent that hands the pricing
237
+ turn off to a Billing Agent, declaring its catalog via `tracely.trace(agents=...)`): each frontier
238
+ provider (OpenAI, Anthropic, Gemini, Mistral, Bedrock) + OpenRouter, each harness (LangChain
239
+ `create_agent`, LangGraph, LiteLLM, LlamaIndex, CrewAI), each first-party agent SDK (OpenAI Agents,
240
+ Claude Agent SDK, Google ADK), and each approach (`@observe`+`trace`, the `wrap_openai`/`wrap_anthropic`
241
+ drop-ins, manual spans). Highlights:
242
+
243
+ | File | Shows |
244
+ |---|---|
245
+ | `../example.py` | the minimal demo trace (agent → llm → failing tool). `make sdk-example`. |
246
+ | `examples/auto_openai.py` · `auto_anthropic.py` · `auto_gemini.py` · … | **automatic** provider tracing — zero span code (one file per frontier provider + OpenRouter). |
247
+ | `examples/auto_langchain.py` (`create_agent`) · `auto_langgraph.py` · `auto_litellm.py` · … | **automatic** harness tracing (one file per framework, current APIs). |
248
+ | `examples/auto_openai_agents.py` · `auto_claude_agent.py` · `auto_google_adk.py` | **automatic** first-party agent-SDK tracing (OpenAI Agents / Claude Agent SDK / Google ADK). |
249
+ | `examples/auto_agent.py` | **automatic** `@observe` + `trace()` agent → thinking/gen/tool tree. `make auto-agent`. |
250
+ | `examples/dropin_openai.py` · `dropin_anthropic.py` | non-patching `wrap_openai` / `wrap_anthropic` drop-ins. |
251
+ | `examples/manual_spans.py` | the manual escape-hatch API as a full agent (no provider/key needed). |
252
+ | `examples/weather_agent.py` / `weather_agent_cli.py` | a real agent wired with `call_tool`/`call_llm` for `tracely replay --entrypoint` / `--cmd`. |
253
+ | `examples/seed_conversations.py` | rich demo data using **every** SDK helper — single/multi-turn, multi-agent + handoffs, RAG (guardrail→embed→retrieve→chain), thinking, multimodal, structured output, multi-model. `make seed-demo`. |
254
+ | `examples/seed_multiturn.py` | one multi-turn conversation (manual API, no key) — the showcase for the **rolling summary** + **declared agents** (`@LIST_AGENT`). |
255
+ | `examples/seed_regression.py` | promote a failing trace → run red→green CI gates (fills Cases + Gates). `make seed-regression`. |
256
+ | `examples/seed_multicall.py` / `seed_handler.py` | repeated-call + handler examples for fixture replay. |
257
+
258
+ ---
259
+
260
+ ## Key decisions (and why)
261
+
262
+ 1. **Thin wrapper, not a framework.** It only sets attributes on OTel spans — anyone already on OpenTelemetry/OpenInference can skip it and just emit the `tracely.*` hints. No lock-in.
263
+ 2. **First-class `tracely.*` hints.** Agent/conversation/turn/step/env are emitted as semantic attributes so they become indexed columns server-side — the basis for agent-level evals and PR gating.
264
+ 3. **`THINKING` is a span type, not a field.** Reasoning is its own observation, so it renders distinctly and carries its own token usage.
265
+ 4. **Record-replay in the SDK.** `call_tool`/`call_llm` are the seam that makes "the recorded run is the test" real: the same code path records in prod and replays in CI, reproducing recorded errors via `ToolError` so error-handling behaviour is gated faithfully.
266
+ 5. **The CLI is the CI contract.** `gate`/`replay` exit 0/1 and speak GitHub — so wiring Tracely into a pipeline is one step, with the hard gate being fail-to-pass and everything else advisory.
@@ -0,0 +1,14 @@
1
+ tracely_sdk/__init__.py,sha256=QzwgnAQO3FvEj5y9qwHqvr7cqWxFiHD6I8pzCsxWuEw,56991
2
+ tracely_sdk/_wrap.py,sha256=9f5C5DXpos2bGbJWziADw63SH4RqCnphlpk4YFRf-K0,2749
3
+ tracely_sdk/anthropic.py,sha256=xBONmBrnfJ3AYlE06UavOdAHIm3IgHxvvcN01Y5vhc4,3930
4
+ tracely_sdk/cli.py,sha256=g5PaVuQV9fTkFXpaKwcvjY288F4sEkohZKgVfIPvLiI,19356
5
+ tracely_sdk/google.py,sha256=bWRabPN7DHRKZ_pyc9VPPDaopvVGRvlnEryu85LOZXw,5439
6
+ tracely_sdk/mistral.py,sha256=S8pOHS9AKtArqI6ONPuviAk6OPS1ocqqGEk-unqpxCE,4298
7
+ tracely_sdk/openai.py,sha256=s_wS2B_WU5Dx-Zl-SE3PNxFXnk5QilXihdQj945QjFs,3512
8
+ tracely_sdk/openrouter.py,sha256=4xo4iNOFisxd8SPW_IE3NnkIB7wyo5f3ujTRHngnkAU,1563
9
+ tracely_sdk/xai.py,sha256=VsL3mGjtE96dSRXxKpjh2uGIXGDTaPqZXEcFztkBMck,1615
10
+ tracely_ai-0.1.0.dist-info/METADATA,sha256=o5h6l8vkN78W9NX3X3gYhIlLIm3d619W84vobkIhmRM,19505
11
+ tracely_ai-0.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
12
+ tracely_ai-0.1.0.dist-info/entry_points.txt,sha256=Z-jn1oOh44vxm9LFN5G1_2EO3nA5r3Wmwq_WndyFWh8,49
13
+ tracely_ai-0.1.0.dist-info/licenses/LICENSE,sha256=NLFizOHjAtQ1Zka2_TNs3fe5qxIU8i9UbD5gGkqdk1U,1072
14
+ tracely_ai-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ tracely = tracely_sdk.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Julien Wuthrich
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.