contexttrace 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,183 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import logging
5
+ import time
6
+ from typing import Any, Optional, Protocol
7
+
8
+ import httpx
9
+
10
+ from contexttrace.errors import ContextTraceHTTPError
11
+
12
+ logger = logging.getLogger("contexttrace")
13
+
14
+
15
+ class Transport(Protocol):
16
+ def post(self, path: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
17
+ ...
18
+
19
+ def get(self, path: str) -> dict[str, Any]:
20
+ ...
21
+
22
+
23
+ class HttpTransport:
24
+ def __init__(
25
+ self,
26
+ *,
27
+ base_url: str,
28
+ api_key: str,
29
+ timeout: float = 30.0,
30
+ retries: int = 2,
31
+ debug: bool = False,
32
+ client: Optional[httpx.Client] = None,
33
+ ) -> None:
34
+ self.retries = max(0, retries)
35
+ self.debug = debug
36
+ self._client = client or httpx.Client(
37
+ base_url=base_url.rstrip("/"),
38
+ timeout=timeout,
39
+ headers={
40
+ "Authorization": f"Bearer {api_key}",
41
+ "User-Agent": "contexttrace-python/0.1.0",
42
+ },
43
+ )
44
+
45
+ def post(self, path: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
46
+ return self._request("POST", path, json=payload or {})
47
+
48
+ def get(self, path: str) -> dict[str, Any]:
49
+ return self._request("GET", path)
50
+
51
+ def _request(self, method: str, path: str, **kwargs: Any) -> dict[str, Any]:
52
+ last_error: Optional[BaseException] = None
53
+ attempts = self.retries + 1
54
+
55
+ for attempt in range(attempts):
56
+ try:
57
+ if self.debug:
58
+ logger.debug("%s %s", method, path)
59
+ response = self._client.request(method, path, **kwargs)
60
+ if response.status_code >= 500 and attempt < attempts - 1:
61
+ last_error = _http_error(response)
62
+ _sleep_before_retry(attempt)
63
+ continue
64
+ return _json_or_raise(response)
65
+ except (httpx.TimeoutException, httpx.NetworkError, httpx.TransportError) as exc:
66
+ last_error = exc
67
+ if attempt >= attempts - 1:
68
+ break
69
+ _sleep_before_retry(attempt)
70
+
71
+ raise ContextTraceHTTPError(
72
+ "ContextTrace API request failed after %s attempt(s): %s %s: %s"
73
+ % (attempts, method, path, last_error)
74
+ )
75
+
76
+ def close(self) -> None:
77
+ self._client.close()
78
+
79
+
80
+ class AsyncTransport(Protocol):
81
+ async def post(self, path: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
82
+ ...
83
+
84
+ async def get(self, path: str) -> dict[str, Any]:
85
+ ...
86
+
87
+
88
+ class AsyncHttpTransport:
89
+ def __init__(
90
+ self,
91
+ *,
92
+ base_url: str,
93
+ api_key: str,
94
+ timeout: float = 30.0,
95
+ retries: int = 2,
96
+ debug: bool = False,
97
+ client: Optional[httpx.AsyncClient] = None,
98
+ ) -> None:
99
+ self.retries = max(0, retries)
100
+ self.debug = debug
101
+ self._client = client or httpx.AsyncClient(
102
+ base_url=base_url.rstrip("/"),
103
+ timeout=timeout,
104
+ headers={
105
+ "Authorization": f"Bearer {api_key}",
106
+ "User-Agent": "contexttrace-python/0.1.0",
107
+ },
108
+ )
109
+
110
+ async def post(self, path: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
111
+ return await self._request("POST", path, json=payload or {})
112
+
113
+ async def get(self, path: str) -> dict[str, Any]:
114
+ return await self._request("GET", path)
115
+
116
+ async def _request(self, method: str, path: str, **kwargs: Any) -> dict[str, Any]:
117
+ last_error: Optional[BaseException] = None
118
+ attempts = self.retries + 1
119
+
120
+ for attempt in range(attempts):
121
+ try:
122
+ if self.debug:
123
+ logger.debug("%s %s", method, path)
124
+ response = await self._client.request(method, path, **kwargs)
125
+ if response.status_code >= 500 and attempt < attempts - 1:
126
+ last_error = _http_error(response)
127
+ await _async_sleep_before_retry(attempt)
128
+ continue
129
+ return _json_or_raise(response)
130
+ except (httpx.TimeoutException, httpx.NetworkError, httpx.TransportError) as exc:
131
+ last_error = exc
132
+ if attempt >= attempts - 1:
133
+ break
134
+ await _async_sleep_before_retry(attempt)
135
+
136
+ raise ContextTraceHTTPError(
137
+ "ContextTrace API request failed after %s attempt(s): %s %s: %s"
138
+ % (attempts, method, path, last_error)
139
+ )
140
+
141
+ async def close(self) -> None:
142
+ await self._client.aclose()
143
+
144
+
145
+ def _json_or_raise(response: httpx.Response) -> dict[str, Any]:
146
+ try:
147
+ response.raise_for_status()
148
+ except httpx.HTTPStatusError as exc:
149
+ raise _http_error(response) from exc
150
+
151
+ try:
152
+ data = response.json()
153
+ except ValueError as exc:
154
+ raise ContextTraceHTTPError(
155
+ "ContextTrace API returned invalid JSON for %s %s."
156
+ % (response.request.method, response.request.url)
157
+ ) from exc
158
+
159
+ if not isinstance(data, dict):
160
+ raise ContextTraceHTTPError("ContextTrace API returned a non-object JSON response.")
161
+ return data
162
+
163
+
164
+ def _http_error(response: httpx.Response) -> ContextTraceHTTPError:
165
+ detail = response.text
166
+ try:
167
+ body = response.json()
168
+ if isinstance(body, dict):
169
+ detail = str(body.get("detail") or body.get("error") or body)
170
+ except ValueError:
171
+ pass
172
+ return ContextTraceHTTPError(
173
+ "ContextTrace API request failed with HTTP %s for %s %s: %s"
174
+ % (response.status_code, response.request.method, response.request.url, detail)
175
+ )
176
+
177
+
178
+ def _sleep_before_retry(attempt: int) -> None:
179
+ time.sleep(min(0.5, 0.1 * (2 ** attempt)))
180
+
181
+
182
+ async def _async_sleep_before_retry(attempt: int) -> None:
183
+ await asyncio.sleep(min(0.5, 0.1 * (2 ** attempt)))
contexttrace/viewer.py ADDED
@@ -0,0 +1,148 @@
1
+ from __future__ import annotations
2
+
3
+ from html import escape
4
+ from pathlib import Path
5
+ from typing import Any, Callable
6
+ from wsgiref.simple_server import make_server
7
+
8
+ from contexttrace.report import ReportGenerator
9
+ from contexttrace.storage import SQLiteTraceStore
10
+
11
+
12
+ def create_viewer_app(storage_path: str = ".contexttrace/contexttrace.db") -> Callable:
13
+ store = SQLiteTraceStore(storage_path)
14
+
15
+ def app(environ: dict[str, Any], start_response: Callable) -> list[bytes]:
16
+ path = environ.get("PATH_INFO") or "/"
17
+ try:
18
+ status = "200 OK"
19
+ body = _route(path, store)
20
+ except Exception as exc:
21
+ status = "500 Internal Server Error"
22
+ body = _page("ContextTrace Viewer Error", "<p>%s</p>" % escape(str(exc)))
23
+ start_response(status, [("Content-Type", "text/html; charset=utf-8")])
24
+ return [body.encode("utf-8")]
25
+
26
+ return app
27
+
28
+
29
+ def serve_viewer(
30
+ *,
31
+ storage_path: str = ".contexttrace/contexttrace.db",
32
+ host: str = "127.0.0.1",
33
+ port: int = 8765,
34
+ ) -> None:
35
+ app = create_viewer_app(storage_path)
36
+ with make_server(host, port, app) as server:
37
+ print("ContextTrace local viewer: http://%s:%s" % (host, port))
38
+ server.serve_forever()
39
+
40
+
41
+ def _route(path: str, store: SQLiteTraceStore) -> str:
42
+ if path == "/":
43
+ status = store.trace_count()
44
+ last_eval = store.last_eval_run()
45
+ return _page(
46
+ "ContextTrace Local Viewer",
47
+ """
48
+ <section class="hero">
49
+ <h1>ContextTrace Local Viewer</h1>
50
+ <p>Inspect local RAG and agent traces stored in SQLite.</p>
51
+ <div class="metrics">
52
+ <div><dt>Traces</dt><dd>{trace_count}</dd></div>
53
+ <div><dt>Last Eval Run</dt><dd>{last_eval}</dd></div>
54
+ </div>
55
+ </section>
56
+ """.format(
57
+ trace_count=status,
58
+ last_eval=escape(str((last_eval or {}).get("id") or "None")),
59
+ ),
60
+ )
61
+ if path == "/traces":
62
+ rows = []
63
+ for trace in store.list_traces(limit=100):
64
+ failure = ((trace.get("evaluation") or {}).get("failure") or {}).get("failure_type") or "not_evaluated"
65
+ score = ((trace.get("evaluation") or {}).get("scores") or {}).get("citation_support", "")
66
+ rows.append(
67
+ "<tr><td><a href=\"/traces/{id}\">{id}</a></td><td>{query}</td><td>{failure}</td><td>{score}</td><td>{created}</td></tr>".format(
68
+ id=escape(str(trace.get("id"))),
69
+ query=escape(str(trace.get("query") or "")[:140]),
70
+ failure=escape(str(failure)),
71
+ score=escape(str(score)),
72
+ created=escape(str(trace.get("created_at") or "")),
73
+ )
74
+ )
75
+ return _page(
76
+ "Traces",
77
+ "<h1>Traces</h1><table><thead><tr><th>Trace ID</th><th>Query</th><th>Failure</th><th>Citation Support</th><th>Created</th></tr></thead><tbody>%s</tbody></table>"
78
+ % ("\n".join(rows) or "<tr><td colspan=\"5\">No traces found.</td></tr>"),
79
+ )
80
+ if path.startswith("/traces/"):
81
+ trace_id = path.rsplit("/", 1)[-1]
82
+ trace = store.get_trace(trace_id)
83
+ return ReportGenerator().render(trace)
84
+ if path == "/eval-runs":
85
+ rows = []
86
+ for run in store.list_eval_runs(limit=100):
87
+ summary = run.get("summary") or {}
88
+ rows.append(
89
+ "<tr><td>{id}</td><td>{dataset}</td><td>{endpoint}</td><td>{score}</td><td>{created}</td></tr>".format(
90
+ id=escape(str(run.get("id"))),
91
+ dataset=escape(str(run.get("dataset") or "")),
92
+ endpoint=escape(str(run.get("endpoint") or "")),
93
+ score=escape(str(summary.get("reliability_score", ""))),
94
+ created=escape(str(run.get("created_at") or "")),
95
+ )
96
+ )
97
+ return _page(
98
+ "Eval Runs",
99
+ "<h1>Eval Runs</h1><table><thead><tr><th>ID</th><th>Dataset</th><th>Endpoint</th><th>Reliability</th><th>Created</th></tr></thead><tbody>%s</tbody></table>"
100
+ % ("\n".join(rows) or "<tr><td colspan=\"5\">No eval runs found.</td></tr>"),
101
+ )
102
+ if path == "/reports":
103
+ report_dir = Path(".contexttrace") / "reports"
104
+ items = []
105
+ for report in sorted(report_dir.glob("*.html")) if report_dir.exists() else []:
106
+ items.append("<li>%s</li>" % escape(str(report)))
107
+ return _page("Reports", "<h1>Reports</h1><ul>%s</ul>" % ("\n".join(items) or "<li>No reports found.</li>"))
108
+ return _page("Not Found", "<h1>Not Found</h1><p>No local viewer page exists for this path.</p>")
109
+
110
+
111
+ def _page(title: str, body: str) -> str:
112
+ return """<!doctype html>
113
+ <html lang="en">
114
+ <head>
115
+ <meta charset="utf-8">
116
+ <meta name="viewport" content="width=device-width, initial-scale=1">
117
+ <title>{title}</title>
118
+ <style>
119
+ :root {{ --bg: #f7f8fa; --panel: #fff; --text: #1f2933; --muted: #697386; --line: #d8dee8; --accent: #2458d3; }}
120
+ * {{ box-sizing: border-box; }}
121
+ body {{ margin: 0; background: var(--bg); color: var(--text); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }}
122
+ main {{ max-width: 1120px; margin: 0 auto; padding: 32px 20px 56px; }}
123
+ nav {{ display: flex; gap: 16px; margin-bottom: 22px; }}
124
+ nav a {{ color: var(--accent); text-decoration: none; font-weight: 700; }}
125
+ h1 {{ margin-top: 0; }}
126
+ section, table {{ background: var(--panel); border: 1px solid var(--line); border-radius: 8px; }}
127
+ section {{ padding: 20px; }}
128
+ table {{ width: 100%; border-collapse: collapse; overflow: hidden; }}
129
+ th, td {{ border-bottom: 1px solid var(--line); padding: 10px; text-align: left; vertical-align: top; }}
130
+ th {{ color: var(--muted); font-size: 12px; text-transform: uppercase; }}
131
+ .metrics {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-top: 16px; }}
132
+ .metrics div {{ border: 1px solid var(--line); border-radius: 8px; padding: 12px; background: #fbfcfe; }}
133
+ dt {{ color: var(--muted); font-size: 12px; font-weight: 700; text-transform: uppercase; }}
134
+ dd {{ margin: 4px 0 0; font-size: 20px; }}
135
+ </style>
136
+ </head>
137
+ <body>
138
+ <main>
139
+ <nav>
140
+ <a href="/">Overview</a>
141
+ <a href="/traces">Traces</a>
142
+ <a href="/eval-runs">Eval Runs</a>
143
+ <a href="/reports">Reports</a>
144
+ </nav>
145
+ {body}
146
+ </main>
147
+ </body>
148
+ </html>""".format(title=escape(title), body=body)
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.1
2
+ Name: contexttrace
3
+ Version: 0.1.0
4
+ Summary: Local-first SDK and CLI for RAG and agent reliability tracing, citation checks, and failure diagnosis.
5
+ Author: ContextTrace contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/samarth1412/Context-Trace
8
+ Project-URL: Documentation, https://github.com/samarth1412/Context-Trace/tree/main/docs
9
+ Project-URL: Repository, https://github.com/samarth1412/Context-Trace
10
+ Project-URL: Issues, https://github.com/samarth1412/Context-Trace/issues
11
+ Project-URL: Changelog, https://github.com/samarth1412/Context-Trace/blob/main/CHANGELOG.md
12
+ Keywords: rag,llm,retrieval-augmented-generation,citations,evaluation,observability,agents,cli,sqlite
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.8
26
+ Description-Content-Type: text/markdown
27
+ Requires-Dist: click>=8.1
28
+ Requires-Dist: httpx>=0.27
29
+ Requires-Dist: typing-extensions>=4.9
30
+ Provides-Extra: all
31
+ Requires-Dist: fastapi>=0.110; extra == "all"
32
+ Requires-Dist: langchain-core>=0.2; extra == "all"
33
+ Requires-Dist: langgraph>=0.2; extra == "all"
34
+ Requires-Dist: llama-index-core>=0.10; extra == "all"
35
+ Requires-Dist: opentelemetry-api>=1.24; extra == "all"
36
+ Provides-Extra: fastapi
37
+ Requires-Dist: fastapi>=0.110; extra == "fastapi"
38
+ Provides-Extra: integrations
39
+ Requires-Dist: fastapi>=0.110; extra == "integrations"
40
+ Requires-Dist: langchain-core>=0.2; extra == "integrations"
41
+ Requires-Dist: langgraph>=0.2; extra == "integrations"
42
+ Requires-Dist: llama-index-core>=0.10; extra == "integrations"
43
+ Requires-Dist: opentelemetry-api>=1.24; extra == "integrations"
44
+ Provides-Extra: langchain
45
+ Requires-Dist: langchain-core>=0.2; extra == "langchain"
46
+ Provides-Extra: langgraph
47
+ Requires-Dist: langgraph>=0.2; extra == "langgraph"
48
+ Provides-Extra: llamaindex
49
+ Requires-Dist: llama-index-core>=0.10; extra == "llamaindex"
50
+ Provides-Extra: local
51
+ Provides-Extra: opentelemetry
52
+ Requires-Dist: opentelemetry-api>=1.24; extra == "opentelemetry"
53
+ Provides-Extra: otel
54
+ Requires-Dist: opentelemetry-api>=1.24; extra == "otel"
55
+ Provides-Extra: test
56
+ Requires-Dist: pytest>=8.0; extra == "test"
57
+
58
+ # ContextTrace
59
+
60
+ **Debug RAG failures before users find them.**
61
+
62
+ ContextTrace is a local-first Python SDK and CLI for evaluating existing RAG and AI agent systems. It records retrieved chunks, selected context, answer claims, citations, token usage, latency, and agent events, then writes local traces and HTML reports without requiring a hosted dashboard.
63
+
64
+ ## Install
65
+
66
+ ```bash
67
+ pip install contexttrace
68
+ contexttrace --version
69
+ contexttrace init
70
+ ```
71
+
72
+ Optional integrations:
73
+
74
+ ```bash
75
+ pip install "contexttrace[langchain]"
76
+ pip install "contexttrace[llamaindex]"
77
+ pip install "contexttrace[fastapi]"
78
+ pip install "contexttrace[langgraph]"
79
+ pip install "contexttrace[otel]"
80
+ pip install "contexttrace[all]"
81
+ ```
82
+
83
+ ## Quickstart
84
+
85
+ ```bash
86
+ contexttrace init
87
+ contexttrace demo --dataset refund_policy
88
+ contexttrace report --last
89
+ contexttrace doctor
90
+ ```
91
+
92
+ By default, traces are stored locally in:
93
+
94
+ ```text
95
+ .contexttrace/contexttrace.db
96
+ ```
97
+
98
+ ## SDK Example
99
+
100
+ ```python
101
+ from contexttrace import ContextTrace
102
+
103
+ ct = ContextTrace(project="support-rag")
104
+
105
+ with ct.trace(query="What is the refund policy?") as trace:
106
+ chunks = retriever.search("What is the refund policy?")
107
+ trace.log_retrieval(chunks)
108
+ trace.log_context(chunks[:5])
109
+
110
+ answer = llm.generate("What is the refund policy?", chunks[:5])
111
+ trace.log_answer(answer, usage={"total_tokens": 1200})
112
+ trace.log_citations([
113
+ {"claim": "Refunds are available within 30 days.", "source_chunk_id": "chunk_12"}
114
+ ])
115
+
116
+ result = trace.evaluate()
117
+ print(result["failure"]["failure_type"])
118
+ ```
119
+
120
+ ## BYO RAG Endpoint
121
+
122
+ Evaluate a running local or hosted RAG API without adding SDK code:
123
+
124
+ ```bash
125
+ contexttrace eval \
126
+ --dataset evals/questions.json \
127
+ --endpoint http://localhost:8000/query \
128
+ --method POST \
129
+ --input-key question \
130
+ --answer-path $.answer \
131
+ --contexts-path $.contexts \
132
+ --citations-path $.citations \
133
+ --fail-on "failure_rate>0.25"
134
+ ```
135
+
136
+ ## What It Catches
137
+
138
+ - `retrieval_miss`
139
+ - `citation_mismatch`
140
+ - `unsupported_answer`
141
+ - `contradicted_answer`
142
+ - `conflicting_sources`
143
+ - `should_have_abstained`
144
+ - agent failures such as `stale_memory_used` and `tool_error`
145
+
146
+ ## Privacy
147
+
148
+ Local mode is the default. ContextTrace makes no network calls unless you configure an LLM judge provider or evaluate a RAG endpoint you provide.
149
+
150
+ ## Links
151
+
152
+ - Repository: https://github.com/samarth1412/Context-Trace
153
+ - Documentation: https://github.com/samarth1412/Context-Trace/tree/main/docs
154
+ - Issues: https://github.com/samarth1412/Context-Trace/issues
@@ -0,0 +1,31 @@
1
+ contexttrace/__init__.py,sha256=PYE5v4eQyRQj85tm4r1QU4vD50Ha_sMy2y_Vq0oP5V0,1347
2
+ contexttrace/_version.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
3
+ contexttrace/cli.py,sha256=HwPlpP89ZlMjVdU-tjIFD_Z4cwgxOWtG-Xgn389P_sI,19751
4
+ contexttrace/client.py,sha256=i-fFRG3ESXgfIIy2_wmmQpgWK1F8VmVDx8K5KpDdQdk,34333
5
+ contexttrace/config.py,sha256=inyY1xhYB8Py9T5COmI6Rj_WcLLR6ItP1Hs7T2XtjTk,7401
6
+ contexttrace/demo.py,sha256=COxHRNnyYySgujBrBrwe-z1ti19VZzubkDNrhm79358,11445
7
+ contexttrace/demo_data.py,sha256=cJjprUipIqjorF_JAscOqONpqeSqdEUFx4WlLqcFmAc,14069
8
+ contexttrace/endpoint_eval.py,sha256=0WZLYnTs03GXiJoHOnXyj_ATeYpkLPtZTYaeU_Mb4Qs,12242
9
+ contexttrace/errors.py,sha256=WsqJGLoP02pjheLTZEDL1R9N52vA3A0_QhlJBOGDr-A,393
10
+ contexttrace/evaluator.py,sha256=bQhHvnysDZuwBGmU1GfPLB9ae7_Gaquh3aFP3Zc9HCU,14414
11
+ contexttrace/local.py,sha256=k6_6gvbzQEg_ZETkTC4gzN1vXitYSFus7d8GtNj3A58,12723
12
+ contexttrace/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
13
+ contexttrace/regression.py,sha256=mexwqdv8H-HUNqyoOUT6oBQWiApDKtNvRjNn9N0i77E,4494
14
+ contexttrace/reliability.py,sha256=MYxgwNOsHhErnjTDJkAYsAhNPjgFqcvLbE5pkannxYw,11130
15
+ contexttrace/report.py,sha256=AwUIweDMy1WINaxSYOM2bj-LkVwlHo23NlunuqLBF7A,17667
16
+ contexttrace/thresholds.py,sha256=J6yrMD3dPRtqx7JKnLFYqvchd4paiyXBPm5KhfLKs1Q,1572
17
+ contexttrace/transport.py,sha256=ra4GIgSjM5gPkS_VGHQXFmgeP-JswYHO9JSJqMNnhgc,5938
18
+ contexttrace/viewer.py,sha256=GERrf61SMvVNZ8wt-RDOMHiqJU5uqvX0OJshAEEMO2U,6599
19
+ contexttrace/integrations/__init__.py,sha256=EhuHHsPlRfxzMm3L_1BSV1VJj7BCf0KmVE8MG8xbbEM,645
20
+ contexttrace/integrations/fastapi.py,sha256=uDL2NfTGHbw8Dq58Ubx83mKqpDmsANOUeTYquX3cDeA,11417
21
+ contexttrace/integrations/langchain.py,sha256=w3FoqlrvBojpOfIcTAXSkX7ZaWPaJ-lqM1o6S0csh0M,15584
22
+ contexttrace/integrations/langgraph.py,sha256=9RkqTwmf0dIIbEIe_JsYTFCa7hKATj_kBLjBKWyezbw,6775
23
+ contexttrace/integrations/llamaindex.py,sha256=J3bEUDZmCBKJ6skWsHO-o9vVYu_2tKzRJNUohalPv_U,14446
24
+ contexttrace/integrations/opentelemetry.py,sha256=9hlMvnFiz3XykFWb3kw3oH5fLesV8t7yXw_UFAAbF1E,4179
25
+ contexttrace/storage/__init__.py,sha256=VcZgNDrQXc9SWt37nJ6F2LYOyMQryXYBWpedLQkK2vQ,95
26
+ contexttrace/storage/sqlite_store.py,sha256=hg117peJvWoCPe4pQ_8zMohq6otIF0Zowa80WvFjcnk,23807
27
+ contexttrace-0.1.0.dist-info/METADATA,sha256=P-fJL8KKplGOYuv6F3r77xihSlplWWAlTMU-KOAm80I,5291
28
+ contexttrace-0.1.0.dist-info/WHEEL,sha256=BNRMDyzLkkcmlv0J8ppDQkk2VED33SesJDynr9ED1gc,91
29
+ contexttrace-0.1.0.dist-info/entry_points.txt,sha256=RJDO0pz-10mTUe9HZwgtBSRWsyz4JtSNvzvt0T0_T5k,55
30
+ contexttrace-0.1.0.dist-info/top_level.txt,sha256=r1Az9kxVpsJuPfnrMOPOp2U_6ceBO4CQt6C5tTnGaLM,13
31
+ contexttrace-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.3.4)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ contexttrace = contexttrace.cli:main
@@ -0,0 +1 @@
1
+ contexttrace