graphsight-langgraph 0.1.0__tar.gz → 0.1.2__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.
- graphsight_langgraph-0.1.2/PKG-INFO +252 -0
- graphsight_langgraph-0.1.2/README.md +225 -0
- graphsight_langgraph-0.1.2/graphsight_langgraph.egg-info/PKG-INFO +252 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/pyproject.toml +2 -2
- graphsight_langgraph-0.1.0/PKG-INFO +0 -232
- graphsight_langgraph-0.1.0/README.md +0 -205
- graphsight_langgraph-0.1.0/graphsight_langgraph.egg-info/PKG-INFO +0 -232
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/LICENSE +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/graphsight_langgraph/__init__.py +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/graphsight_langgraph/github_ingest.py +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/graphsight_langgraph/mapper.py +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/graphsight_langgraph/schema.py +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/graphsight_langgraph/tracer.py +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/graphsight_langgraph.egg-info/SOURCES.txt +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/graphsight_langgraph.egg-info/dependency_links.txt +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/graphsight_langgraph.egg-info/entry_points.txt +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/graphsight_langgraph.egg-info/requires.txt +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/graphsight_langgraph.egg-info/top_level.txt +0 -0
- {graphsight_langgraph-0.1.0 → graphsight_langgraph-0.1.2}/setup.cfg +0 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: graphsight-langgraph
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: X-ray for LangGraph retrieval: one callback handler captures every retriever call, score, and relational path — rendered as an interactive graph.
|
|
5
|
+
Author: Arush Karnatak
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/Kcodess2807/graphsight
|
|
8
|
+
Project-URL: Documentation, https://github.com/Kcodess2807/graphsight/tree/main/graphsight-langgraph
|
|
9
|
+
Keywords: langgraph,langchain,tracing,observability,rag,retrieval,agents
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: langchain-core>=0.3
|
|
24
|
+
Provides-Extra: example
|
|
25
|
+
Requires-Dist: langgraph>=0.2; extra == "example"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# graphsight-langgraph
|
|
29
|
+
|
|
30
|
+
[](https://pypi.org/project/graphsight-langgraph/)
|
|
31
|
+
[](https://pypi.org/project/graphsight-langgraph/)
|
|
32
|
+
[](https://github.com/Kcodess2807/graphsight/blob/main/graphsight-langgraph/LICENSE)
|
|
33
|
+
|
|
34
|
+
**See exactly why your LangGraph agent picked the context it picked.**
|
|
35
|
+
|
|
36
|
+
Retrieval in an agent is a black box: documents go in, an answer comes out,
|
|
37
|
+
and when the answer is wrong you're left guessing which context misled it.
|
|
38
|
+
This package opens the box. One callback handler records a
|
|
39
|
+
[LangGraph](https://github.com/langchain-ai/langgraph) run — every node,
|
|
40
|
+
every retriever call, per-document scores, and (for graph-aware retrievers)
|
|
41
|
+
the relational paths between retrieved entities — and one command renders it
|
|
42
|
+
as an interactive graph in your browser.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
your LangGraph agent ──▶ LangGraphTracer ──▶ AgentTrace (v0.1) ──▶ graphsight viewer
|
|
46
|
+
(callbacks) neutral JSON interactive graph
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Only dependency: `langchain-core`. No engine, no backend, no account —
|
|
50
|
+
nothing leaves your machine.
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install graphsight-langgraph # the tracer
|
|
56
|
+
pip install "graphsight-langgraph[example]" # + langgraph, for the GitHub CLI
|
|
57
|
+
pip install graphsight # the local viewer (recommended)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Compatibility
|
|
61
|
+
|
|
62
|
+
| | |
|
|
63
|
+
|---|---|
|
|
64
|
+
| Python | ≥ 3.10 |
|
|
65
|
+
| `langchain-core` | ≥ 0.3 (verified against 1.5.0) |
|
|
66
|
+
| `langgraph` | any recent version; only needed for the `[example]` extra |
|
|
67
|
+
| Sync (`invoke` / `stream`) | verified |
|
|
68
|
+
| Async (`ainvoke` / `astream`) | same callback events; not yet covered by the verification run |
|
|
69
|
+
|
|
70
|
+
## Quickstart: trace a GitHub repo in 60 seconds
|
|
71
|
+
|
|
72
|
+
No setup, no API keys — public repositories don't need a token:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
graphsight-github-trace langchain-ai/langgraph "who fixed the recent streaming bugs?"
|
|
76
|
+
graphsight graphsight_out/trace_state.json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Your browser opens on a live graph of that repository's recent activity:
|
|
80
|
+
the PRs that matched the question, the people who authored them, the issues
|
|
81
|
+
they resolve — every node clickable, scores shown, execution timeline
|
|
82
|
+
included.
|
|
83
|
+
|
|
84
|
+
### `graphsight-github-trace` reference
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
graphsight-github-trace REPO [QUESTION] [options]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
| Argument | Default | Description |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| `REPO` | — | `owner/name`, e.g. `langchain-ai/langgraph`. |
|
|
93
|
+
| `QUESTION` | *"What changed recently in \<repo\>, and who drove it?"* | The question the traced retrieval answers. |
|
|
94
|
+
| `--token` | `$GITHUB_TOKEN` | GitHub token. Required for private repositories; raises the rate limit on public ones. |
|
|
95
|
+
| `--prs` | `25` | Recent pull requests to fetch. |
|
|
96
|
+
| `--issues` | `25` | Recent issues to fetch. |
|
|
97
|
+
| `--top` | `10` | Items the retrieval keeps. |
|
|
98
|
+
| `--out` | `graphsight_out/` | Output directory for `agent_trace.json` and `trace_state.json`. |
|
|
99
|
+
|
|
100
|
+
Method note: the CLI builds a corpus with relational edges
|
|
101
|
+
(`person AUTHORED pr`, `pr RESOLVES issue`, `pr TOUCHES repo`) and ranks by
|
|
102
|
+
**lexical overlap with 1-hop graph expansion** — deliberately simple, and
|
|
103
|
+
reported as such. The scores you see are exactly the scores computed;
|
|
104
|
+
nothing is presented as semantic similarity.
|
|
105
|
+
|
|
106
|
+
## Tracing your own agent
|
|
107
|
+
|
|
108
|
+
The complete integration:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from graphsight_langgraph import LangGraphTracer, to_tracestate
|
|
112
|
+
|
|
113
|
+
tracer = LangGraphTracer()
|
|
114
|
+
result = graph.invoke(inputs, config={"callbacks": [tracer]})
|
|
115
|
+
|
|
116
|
+
trace = tracer.finish(query="why is checkout failing?", answer=result["answer"])
|
|
117
|
+
to_tracestate(trace) # viewer-ready dict — json.dump it, then: graphsight trace.json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Configuration propagation (read this once)
|
|
121
|
+
|
|
122
|
+
LangChain only propagates callbacks into runnables that receive the run's
|
|
123
|
+
config. Inside a LangGraph node, pass the node's config through to
|
|
124
|
+
sub-runnables, or the tracer will record the node but not what happened
|
|
125
|
+
inside it:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
def retrieve(state, config): # 1. accept config
|
|
129
|
+
docs = retriever.invoke(state["q"], config=config) # 2. pass it through
|
|
130
|
+
return {"docs": docs}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Symptom if you skip this:** the trace shows node spans but zero
|
|
134
|
+
retrievals.
|
|
135
|
+
|
|
136
|
+
### API reference
|
|
137
|
+
|
|
138
|
+
| Name | Description |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `LangGraphTracer()` | `BaseCallbackHandler` subclass. Pass via `config={"callbacks": [tracer]}` to `invoke` / `stream`. Reusable within a single run; create a fresh instance per run. |
|
|
141
|
+
| `tracer.finish(query=None, answer=None) -> AgentTrace` | Assembles the trace after the run: closes dangling spans, computes total latency. `query` falls back to the first retriever query seen. |
|
|
142
|
+
| `to_tracestate(trace) -> dict` | Maps an `AgentTrace` to the viewer's JSON contract. Serialize with `json.dump`. |
|
|
143
|
+
| `trace.to_dict() -> dict` | The framework-neutral `AgentTrace` (schema v0.1) for your own tooling. |
|
|
144
|
+
| `AgentTrace`, `Span`, `Retrieval`, `RetrievedItem`, `TraceEdge` | Plain dataclasses defining the schema; importable for custom emitters. |
|
|
145
|
+
|
|
146
|
+
## What gets captured
|
|
147
|
+
|
|
148
|
+
| Source in the run | Captured as |
|
|
149
|
+
|---|---|
|
|
150
|
+
| Each LangGraph node execution | `Span(kind="node")` with monotonic-clock timing |
|
|
151
|
+
| Framework internals (`RunnableSequence`, `ChannelWrite`, `__start__`, …) | filtered out — one span per user node |
|
|
152
|
+
| `on_retriever_end` documents | one `RetrievedItem` per doc: id, label, kind, score, content, source |
|
|
153
|
+
| `Document.metadata` score keys (`score`, `relevance_score`, `similarity`, `_score`, `vector_score`) | item scores |
|
|
154
|
+
| `Document.metadata["edges"]` | relational edges, deduplicated per retrieval |
|
|
155
|
+
| LLM / tool calls | plain spans in the execution timeline |
|
|
156
|
+
| Edges present in a retrieval | `arm = "graph"`, else `"vector"` — detected automatically |
|
|
157
|
+
|
|
158
|
+
### Making your retriever graph-aware
|
|
159
|
+
|
|
160
|
+
The tracer reads two optional metadata conventions from the `Document`
|
|
161
|
+
objects your retriever returns:
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
Document(
|
|
165
|
+
page_content="PR #4821 'fix: idempotent refund path' merged by Priya N. ...",
|
|
166
|
+
metadata={
|
|
167
|
+
"id": "pr_4821", # stable node id (falls back to a content hash)
|
|
168
|
+
"label": "PR #4821", # display name
|
|
169
|
+
"kind": "pull_request", # normalized to a viewer entity type, see below
|
|
170
|
+
"score": 0.94, # any recognized score key
|
|
171
|
+
"source": "https://github.com/acme/platform/pull/4821",
|
|
172
|
+
"edges": [ # optional — enables the relational view
|
|
173
|
+
{"source": "pr_4821", "target": "svc_checkout",
|
|
174
|
+
"relation": "TOUCHES", "weight": 0.9},
|
|
175
|
+
],
|
|
176
|
+
},
|
|
177
|
+
)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`kind` values are normalized (`pull_request → PR`, `service → Service`,
|
|
181
|
+
`person`/`author` → `Person`, `ticket`/`issue`/`jira` → `Ticket`,
|
|
182
|
+
`repo → Repo`, `library → Library`, `team → Team`, `tool → Tool`; anything
|
|
183
|
+
else renders as `Document`).
|
|
184
|
+
|
|
185
|
+
### Degradation behavior
|
|
186
|
+
|
|
187
|
+
- **No edges in metadata** → a flat scored-retrieval view instead of
|
|
188
|
+
relational path highlighting. Still useful; not graph-aware.
|
|
189
|
+
- **No recognized score keys** → scores stay `None`; no score chips render.
|
|
190
|
+
Nothing is ever fabricated.
|
|
191
|
+
- The emitted `confidence.rationale` states that scores came from your
|
|
192
|
+
retriever and were not recomputed — an imported trace never masquerades
|
|
193
|
+
as an engine-computed one.
|
|
194
|
+
|
|
195
|
+
## Schema (v0.1)
|
|
196
|
+
|
|
197
|
+
`AgentTrace` is the stable contract. Future adapters (LlamaIndex, raw
|
|
198
|
+
OpenTelemetry) emit the same shape and render in the same viewer.
|
|
199
|
+
|
|
200
|
+
```jsonc
|
|
201
|
+
{
|
|
202
|
+
"schema_version": "0.1",
|
|
203
|
+
"framework": "langgraph",
|
|
204
|
+
"query": "…",
|
|
205
|
+
"spans": [
|
|
206
|
+
{ "id": "…", "name": "retrieve", "kind": "node", // node | retriever | llm | tool
|
|
207
|
+
"parent_id": null, "start_ms": 0.0, "end_ms": 0.3, "status": "ok" }
|
|
208
|
+
],
|
|
209
|
+
"retrievals": [
|
|
210
|
+
{
|
|
211
|
+
"span_id": "…", "query": "…",
|
|
212
|
+
"arm": "graph", // "vector" | "graph", auto-detected
|
|
213
|
+
"items": [
|
|
214
|
+
{ "id": "pr_4821", "label": "PR #4821", "kind": "pull_request",
|
|
215
|
+
"score": 0.94, "vector_score": null, "graph_score": null,
|
|
216
|
+
"content": "…", "source_uri": "https://…", "metadata": {} }
|
|
217
|
+
],
|
|
218
|
+
"edges": [ // optional — the relational view
|
|
219
|
+
{ "source": "pr_4821", "target": "svc_checkout", "relation": "TOUCHES", "weight": 0.9 }
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
],
|
|
223
|
+
"answer": "…",
|
|
224
|
+
"latency_ms": 3.9
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Troubleshooting
|
|
229
|
+
|
|
230
|
+
| Symptom | Cause / fix |
|
|
231
|
+
|---|---|
|
|
232
|
+
| Node spans but no retrievals | Config not propagated into the node's sub-runnables — see [Configuration propagation](#configuration-propagation-read-this-once). |
|
|
233
|
+
| Items without scores | Your retriever doesn't write a recognized score key to `Document.metadata` — add one (`score` is simplest). |
|
|
234
|
+
| Flat graph, no edges | Your retriever doesn't emit `metadata["edges"]` — see [Making your retriever graph-aware](#making-your-retriever-graph-aware). |
|
|
235
|
+
| `GitHub API 403` from the CLI | Rate limit (60 requests/hour unauthenticated) — pass `--token` or set `GITHUB_TOKEN`. |
|
|
236
|
+
| Garbled output on Windows consoles | Fixed in ≥ 0.1.1; upgrade. |
|
|
237
|
+
|
|
238
|
+
## Roadmap
|
|
239
|
+
|
|
240
|
+
In order: a **LlamaIndex adapter** emitting the same `AgentTrace`, then a
|
|
241
|
+
raw **OpenTelemetry span** ingestor. The schema is the contract; adapters
|
|
242
|
+
stay thin.
|
|
243
|
+
|
|
244
|
+
## Links
|
|
245
|
+
|
|
246
|
+
- Source & issue tracker: [github.com/Kcodess2807/graphsight](https://github.com/Kcodess2807/graphsight)
|
|
247
|
+
- The viewer: [graphsight on PyPI](https://pypi.org/project/graphsight/)
|
|
248
|
+
- Beta test script: [BETA.md](https://github.com/Kcodess2807/graphsight/blob/main/BETA.md)
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
MIT © Arush Karnatak
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# graphsight-langgraph
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/graphsight-langgraph/)
|
|
4
|
+
[](https://pypi.org/project/graphsight-langgraph/)
|
|
5
|
+
[](https://github.com/Kcodess2807/graphsight/blob/main/graphsight-langgraph/LICENSE)
|
|
6
|
+
|
|
7
|
+
**See exactly why your LangGraph agent picked the context it picked.**
|
|
8
|
+
|
|
9
|
+
Retrieval in an agent is a black box: documents go in, an answer comes out,
|
|
10
|
+
and when the answer is wrong you're left guessing which context misled it.
|
|
11
|
+
This package opens the box. One callback handler records a
|
|
12
|
+
[LangGraph](https://github.com/langchain-ai/langgraph) run — every node,
|
|
13
|
+
every retriever call, per-document scores, and (for graph-aware retrievers)
|
|
14
|
+
the relational paths between retrieved entities — and one command renders it
|
|
15
|
+
as an interactive graph in your browser.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
your LangGraph agent ──▶ LangGraphTracer ──▶ AgentTrace (v0.1) ──▶ graphsight viewer
|
|
19
|
+
(callbacks) neutral JSON interactive graph
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Only dependency: `langchain-core`. No engine, no backend, no account —
|
|
23
|
+
nothing leaves your machine.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install graphsight-langgraph # the tracer
|
|
29
|
+
pip install "graphsight-langgraph[example]" # + langgraph, for the GitHub CLI
|
|
30
|
+
pip install graphsight # the local viewer (recommended)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Compatibility
|
|
34
|
+
|
|
35
|
+
| | |
|
|
36
|
+
|---|---|
|
|
37
|
+
| Python | ≥ 3.10 |
|
|
38
|
+
| `langchain-core` | ≥ 0.3 (verified against 1.5.0) |
|
|
39
|
+
| `langgraph` | any recent version; only needed for the `[example]` extra |
|
|
40
|
+
| Sync (`invoke` / `stream`) | verified |
|
|
41
|
+
| Async (`ainvoke` / `astream`) | same callback events; not yet covered by the verification run |
|
|
42
|
+
|
|
43
|
+
## Quickstart: trace a GitHub repo in 60 seconds
|
|
44
|
+
|
|
45
|
+
No setup, no API keys — public repositories don't need a token:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
graphsight-github-trace langchain-ai/langgraph "who fixed the recent streaming bugs?"
|
|
49
|
+
graphsight graphsight_out/trace_state.json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Your browser opens on a live graph of that repository's recent activity:
|
|
53
|
+
the PRs that matched the question, the people who authored them, the issues
|
|
54
|
+
they resolve — every node clickable, scores shown, execution timeline
|
|
55
|
+
included.
|
|
56
|
+
|
|
57
|
+
### `graphsight-github-trace` reference
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
graphsight-github-trace REPO [QUESTION] [options]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
| Argument | Default | Description |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `REPO` | — | `owner/name`, e.g. `langchain-ai/langgraph`. |
|
|
66
|
+
| `QUESTION` | *"What changed recently in \<repo\>, and who drove it?"* | The question the traced retrieval answers. |
|
|
67
|
+
| `--token` | `$GITHUB_TOKEN` | GitHub token. Required for private repositories; raises the rate limit on public ones. |
|
|
68
|
+
| `--prs` | `25` | Recent pull requests to fetch. |
|
|
69
|
+
| `--issues` | `25` | Recent issues to fetch. |
|
|
70
|
+
| `--top` | `10` | Items the retrieval keeps. |
|
|
71
|
+
| `--out` | `graphsight_out/` | Output directory for `agent_trace.json` and `trace_state.json`. |
|
|
72
|
+
|
|
73
|
+
Method note: the CLI builds a corpus with relational edges
|
|
74
|
+
(`person AUTHORED pr`, `pr RESOLVES issue`, `pr TOUCHES repo`) and ranks by
|
|
75
|
+
**lexical overlap with 1-hop graph expansion** — deliberately simple, and
|
|
76
|
+
reported as such. The scores you see are exactly the scores computed;
|
|
77
|
+
nothing is presented as semantic similarity.
|
|
78
|
+
|
|
79
|
+
## Tracing your own agent
|
|
80
|
+
|
|
81
|
+
The complete integration:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from graphsight_langgraph import LangGraphTracer, to_tracestate
|
|
85
|
+
|
|
86
|
+
tracer = LangGraphTracer()
|
|
87
|
+
result = graph.invoke(inputs, config={"callbacks": [tracer]})
|
|
88
|
+
|
|
89
|
+
trace = tracer.finish(query="why is checkout failing?", answer=result["answer"])
|
|
90
|
+
to_tracestate(trace) # viewer-ready dict — json.dump it, then: graphsight trace.json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Configuration propagation (read this once)
|
|
94
|
+
|
|
95
|
+
LangChain only propagates callbacks into runnables that receive the run's
|
|
96
|
+
config. Inside a LangGraph node, pass the node's config through to
|
|
97
|
+
sub-runnables, or the tracer will record the node but not what happened
|
|
98
|
+
inside it:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
def retrieve(state, config): # 1. accept config
|
|
102
|
+
docs = retriever.invoke(state["q"], config=config) # 2. pass it through
|
|
103
|
+
return {"docs": docs}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Symptom if you skip this:** the trace shows node spans but zero
|
|
107
|
+
retrievals.
|
|
108
|
+
|
|
109
|
+
### API reference
|
|
110
|
+
|
|
111
|
+
| Name | Description |
|
|
112
|
+
|---|---|
|
|
113
|
+
| `LangGraphTracer()` | `BaseCallbackHandler` subclass. Pass via `config={"callbacks": [tracer]}` to `invoke` / `stream`. Reusable within a single run; create a fresh instance per run. |
|
|
114
|
+
| `tracer.finish(query=None, answer=None) -> AgentTrace` | Assembles the trace after the run: closes dangling spans, computes total latency. `query` falls back to the first retriever query seen. |
|
|
115
|
+
| `to_tracestate(trace) -> dict` | Maps an `AgentTrace` to the viewer's JSON contract. Serialize with `json.dump`. |
|
|
116
|
+
| `trace.to_dict() -> dict` | The framework-neutral `AgentTrace` (schema v0.1) for your own tooling. |
|
|
117
|
+
| `AgentTrace`, `Span`, `Retrieval`, `RetrievedItem`, `TraceEdge` | Plain dataclasses defining the schema; importable for custom emitters. |
|
|
118
|
+
|
|
119
|
+
## What gets captured
|
|
120
|
+
|
|
121
|
+
| Source in the run | Captured as |
|
|
122
|
+
|---|---|
|
|
123
|
+
| Each LangGraph node execution | `Span(kind="node")` with monotonic-clock timing |
|
|
124
|
+
| Framework internals (`RunnableSequence`, `ChannelWrite`, `__start__`, …) | filtered out — one span per user node |
|
|
125
|
+
| `on_retriever_end` documents | one `RetrievedItem` per doc: id, label, kind, score, content, source |
|
|
126
|
+
| `Document.metadata` score keys (`score`, `relevance_score`, `similarity`, `_score`, `vector_score`) | item scores |
|
|
127
|
+
| `Document.metadata["edges"]` | relational edges, deduplicated per retrieval |
|
|
128
|
+
| LLM / tool calls | plain spans in the execution timeline |
|
|
129
|
+
| Edges present in a retrieval | `arm = "graph"`, else `"vector"` — detected automatically |
|
|
130
|
+
|
|
131
|
+
### Making your retriever graph-aware
|
|
132
|
+
|
|
133
|
+
The tracer reads two optional metadata conventions from the `Document`
|
|
134
|
+
objects your retriever returns:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
Document(
|
|
138
|
+
page_content="PR #4821 'fix: idempotent refund path' merged by Priya N. ...",
|
|
139
|
+
metadata={
|
|
140
|
+
"id": "pr_4821", # stable node id (falls back to a content hash)
|
|
141
|
+
"label": "PR #4821", # display name
|
|
142
|
+
"kind": "pull_request", # normalized to a viewer entity type, see below
|
|
143
|
+
"score": 0.94, # any recognized score key
|
|
144
|
+
"source": "https://github.com/acme/platform/pull/4821",
|
|
145
|
+
"edges": [ # optional — enables the relational view
|
|
146
|
+
{"source": "pr_4821", "target": "svc_checkout",
|
|
147
|
+
"relation": "TOUCHES", "weight": 0.9},
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`kind` values are normalized (`pull_request → PR`, `service → Service`,
|
|
154
|
+
`person`/`author` → `Person`, `ticket`/`issue`/`jira` → `Ticket`,
|
|
155
|
+
`repo → Repo`, `library → Library`, `team → Team`, `tool → Tool`; anything
|
|
156
|
+
else renders as `Document`).
|
|
157
|
+
|
|
158
|
+
### Degradation behavior
|
|
159
|
+
|
|
160
|
+
- **No edges in metadata** → a flat scored-retrieval view instead of
|
|
161
|
+
relational path highlighting. Still useful; not graph-aware.
|
|
162
|
+
- **No recognized score keys** → scores stay `None`; no score chips render.
|
|
163
|
+
Nothing is ever fabricated.
|
|
164
|
+
- The emitted `confidence.rationale` states that scores came from your
|
|
165
|
+
retriever and were not recomputed — an imported trace never masquerades
|
|
166
|
+
as an engine-computed one.
|
|
167
|
+
|
|
168
|
+
## Schema (v0.1)
|
|
169
|
+
|
|
170
|
+
`AgentTrace` is the stable contract. Future adapters (LlamaIndex, raw
|
|
171
|
+
OpenTelemetry) emit the same shape and render in the same viewer.
|
|
172
|
+
|
|
173
|
+
```jsonc
|
|
174
|
+
{
|
|
175
|
+
"schema_version": "0.1",
|
|
176
|
+
"framework": "langgraph",
|
|
177
|
+
"query": "…",
|
|
178
|
+
"spans": [
|
|
179
|
+
{ "id": "…", "name": "retrieve", "kind": "node", // node | retriever | llm | tool
|
|
180
|
+
"parent_id": null, "start_ms": 0.0, "end_ms": 0.3, "status": "ok" }
|
|
181
|
+
],
|
|
182
|
+
"retrievals": [
|
|
183
|
+
{
|
|
184
|
+
"span_id": "…", "query": "…",
|
|
185
|
+
"arm": "graph", // "vector" | "graph", auto-detected
|
|
186
|
+
"items": [
|
|
187
|
+
{ "id": "pr_4821", "label": "PR #4821", "kind": "pull_request",
|
|
188
|
+
"score": 0.94, "vector_score": null, "graph_score": null,
|
|
189
|
+
"content": "…", "source_uri": "https://…", "metadata": {} }
|
|
190
|
+
],
|
|
191
|
+
"edges": [ // optional — the relational view
|
|
192
|
+
{ "source": "pr_4821", "target": "svc_checkout", "relation": "TOUCHES", "weight": 0.9 }
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
],
|
|
196
|
+
"answer": "…",
|
|
197
|
+
"latency_ms": 3.9
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Troubleshooting
|
|
202
|
+
|
|
203
|
+
| Symptom | Cause / fix |
|
|
204
|
+
|---|---|
|
|
205
|
+
| Node spans but no retrievals | Config not propagated into the node's sub-runnables — see [Configuration propagation](#configuration-propagation-read-this-once). |
|
|
206
|
+
| Items without scores | Your retriever doesn't write a recognized score key to `Document.metadata` — add one (`score` is simplest). |
|
|
207
|
+
| Flat graph, no edges | Your retriever doesn't emit `metadata["edges"]` — see [Making your retriever graph-aware](#making-your-retriever-graph-aware). |
|
|
208
|
+
| `GitHub API 403` from the CLI | Rate limit (60 requests/hour unauthenticated) — pass `--token` or set `GITHUB_TOKEN`. |
|
|
209
|
+
| Garbled output on Windows consoles | Fixed in ≥ 0.1.1; upgrade. |
|
|
210
|
+
|
|
211
|
+
## Roadmap
|
|
212
|
+
|
|
213
|
+
In order: a **LlamaIndex adapter** emitting the same `AgentTrace`, then a
|
|
214
|
+
raw **OpenTelemetry span** ingestor. The schema is the contract; adapters
|
|
215
|
+
stay thin.
|
|
216
|
+
|
|
217
|
+
## Links
|
|
218
|
+
|
|
219
|
+
- Source & issue tracker: [github.com/Kcodess2807/graphsight](https://github.com/Kcodess2807/graphsight)
|
|
220
|
+
- The viewer: [graphsight on PyPI](https://pypi.org/project/graphsight/)
|
|
221
|
+
- Beta test script: [BETA.md](https://github.com/Kcodess2807/graphsight/blob/main/BETA.md)
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT © Arush Karnatak
|