agent-tracegraph 0.2.0__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_tracegraph-0.3.1/CHANGELOG.md +329 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/PKG-INFO +52 -18
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/README.md +50 -16
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/contracts/phoenix-runtime.json +1 -1
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/pyproject.toml +14 -2
- agent_tracegraph-0.3.1/src/tracegraph/_atomic_write.py +41 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/adapters/langgraph_checkpoint.py +150 -44
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/adapters/otlp_spans.py +189 -68
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/adapters/phoenix_export.py +51 -43
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/analysis/ahu.py +13 -11
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/analysis/diagnose.py +118 -94
- agent_tracegraph-0.3.1/src/tracegraph/analysis/memo.py +193 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/analysis/patterns.py +15 -6
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/artifact.py +45 -37
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/cli.py +98 -90
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/model.py +13 -2
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/normalize.py +134 -40
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/review_candidates.py +6 -19
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/store/in_memory.py +22 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/store/ladybug.py +16 -3
- agent_tracegraph-0.2.0/CHANGELOG.md +0 -117
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/.gitignore +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/LICENSE +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/SECURITY.md +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/contracts/analysis-report.schema.json +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/contracts/review-candidates.schema.json +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/__init__.py +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/adapters/__init__.py +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/adapters/base.py +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/analysis/__init__.py +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/analysis/explain.py +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/input_validation.py +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/py.typed +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/sqlite_snapshot.py +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/store/__init__.py +0 -0
- {agent_tracegraph-0.2.0 → agent_tracegraph-0.3.1}/src/tracegraph/store/base.py +0 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Tracegraph are documented here.
|
|
4
|
+
|
|
5
|
+
The **artifact** schema version and the **report**/**review-candidate** JSON schemas are
|
|
6
|
+
separate contracts from this version number; changes to any of them are called out
|
|
7
|
+
explicitly.
|
|
8
|
+
|
|
9
|
+
## 0.3.1 - 2026-10-13
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **An unreadable cost no longer understates the run's total.** The importers dropped a
|
|
14
|
+
`llm.cost.total` that was not a finite non-negative decimal (`"abc"`, `-1`, a boolean), so
|
|
15
|
+
`analyze` summed the remaining costs and printed a total that was knowably too low, with no
|
|
16
|
+
warning. The documented rule that a single unparseable cost withholds the whole total only
|
|
17
|
+
applied to artifacts built by hand. An unreadable total cost is now stored as the fixed
|
|
18
|
+
marker `"unreadable"`, never the producer's value, and the report withholds `total_cost`
|
|
19
|
+
and its delta with the existing note.
|
|
20
|
+
- Token counts, prompt and completion costs, cost currencies and Phoenix evaluation scores
|
|
21
|
+
that cannot be read were dropped without a trace. They are still reported as unavailable,
|
|
22
|
+
and `ingest-otlp`, `ingest-phoenix`, `analyze` and `phoenix diagnose` now say so on stderr,
|
|
23
|
+
naming the kind of value and how many spans (for scores, evaluations) carried it, never
|
|
24
|
+
the value itself. A boolean score still reads as `1.0` or `0.0`, as before.
|
|
25
|
+
- An OTLP `intValue` sent as a fractional JSON number was truncated before validation:
|
|
26
|
+
`1.5` became `1` and `-0.5` became `0`, so an invalid token count looked valid. It is now
|
|
27
|
+
validated as sent.
|
|
28
|
+
- **A checkpoint history LangGraph could not have written is a usage error, not a
|
|
29
|
+
traceback or a different trace.** About half of 64 one-field mutations of a real history
|
|
30
|
+
(a non-object `metadata` or `channel_values`, a numeric `checkpoint_ns`, a boolean `v`, an
|
|
31
|
+
unhashable parent checkpoint id, ...) crashed `ingest` with a traceback, and several were
|
|
32
|
+
read silently as something else: a malformed parent config or `metadata.parents` dropped
|
|
33
|
+
the declared parent and made the checkpoint a root, and `metadata.step` of `true` or `1.5`
|
|
34
|
+
was read as step 1. Each checkpoint is now checked against the types LangGraph declares
|
|
35
|
+
for the fields tracegraph reads, strictly, and rejected with a message naming the field.
|
|
36
|
+
A config `checkpoint_id` that disagrees with the checkpoint's own id is rejected too.
|
|
37
|
+
- A checkpoint row the saver cannot decode (an unknown serialization type, metadata nested
|
|
38
|
+
past the recursion limit, a non-string metadata column) crashed `ingest` and `discover`
|
|
39
|
+
with a traceback, except that `discover` reported an unknown serialization type as "does
|
|
40
|
+
not support listing all threads". Both now report the history as undecodable.
|
|
41
|
+
- Pending writes that are not a `(task id, channel, value)` triple were skipped without a
|
|
42
|
+
word, and any 3-character string was unpacked as one (`"abc"` became task `a`). They are
|
|
43
|
+
still ignored, but `ingest` now says how many on stderr, since one could have carried a
|
|
44
|
+
task failure.
|
|
45
|
+
|
|
46
|
+
### Compatibility notes for imports
|
|
47
|
+
|
|
48
|
+
- An artifact imported from a span with an unreadable total cost now carries
|
|
49
|
+
`"total_cost": "unreadable"` instead of no cost, and its reports withhold the run's
|
|
50
|
+
total cost. No schema change: 0.3.0 reads such an artifact and withholds the same way.
|
|
51
|
+
- Because `intValue` is no longer truncated, `llm.cost.total = {"intValue": 1.5}` is stored as
|
|
52
|
+
`"1.5"` instead of `"1"`, and a `toolgraph.graph_generation` of `{"intValue": 1.5}` is
|
|
53
|
+
rejected like any other invalid generation instead of being read as `1`.
|
|
54
|
+
- The committed Phoenix fixture carries an unreadable `llm.cost.prompt`; reading it now prints
|
|
55
|
+
one stderr disclosure. Every committed fixture's artifact, report, memo, candidate file and
|
|
56
|
+
CLI stdout is unchanged.
|
|
57
|
+
- LangGraph histories that `ingest` used to accept with a malformed field listed above are
|
|
58
|
+
now refused. Histories written by LangGraph's own savers are unaffected: the checks cover
|
|
59
|
+
only fields tracegraph reads (`counters_since_delta_snapshot`, which savers return as
|
|
60
|
+
lists although it is declared as tuples, is not checked), a missing `updated_channels`
|
|
61
|
+
and a legacy `pending_sends` are accepted, and an unknown `metadata.source` string still
|
|
62
|
+
reads as a loop. The committed LangGraph fixture is byte-identical.
|
|
63
|
+
|
|
64
|
+
## 0.3.0 - 2026-10-13
|
|
65
|
+
|
|
66
|
+
### Fixed
|
|
67
|
+
|
|
68
|
+
- An artifact whose content was not canonical (for example a stored trace status that
|
|
69
|
+
disagreed with its steps) was stamped `schema_version` 4 even when it carried no edge
|
|
70
|
+
origins. Version 4 is now stamped only when the file's TREE_PARENT edges are the
|
|
71
|
+
origin-priority projection of its causal edges and that differs from the temporal one; the
|
|
72
|
+
rest of the trace does not affect the stamp. **Digest impact:** canonical artifacts are
|
|
73
|
+
unchanged, but re-serializing a non-canonical trace (one `validate` rejects) whose tree is
|
|
74
|
+
not the origin-priority one, such as a trace with its derived edges missing, now writes
|
|
75
|
+
version 2 or 3 instead of 4. Any digest computed from that re-serialization changes,
|
|
76
|
+
including the `artifact_digest` that `analyze` reports for such a trace.
|
|
77
|
+
- Loading now rejects an envelope that understates its content: a `schema_version` 2 file
|
|
78
|
+
holding an origin-priority projection or derived task steps. Every reader that trusts the
|
|
79
|
+
envelope would have read such a file under the wrong rules, and a re-save rewrote it as a
|
|
80
|
+
different file. An envelope may still overstate what its content needs.
|
|
81
|
+
- `schema_version` must be an integer. `true`, `1.0`, `2.0` and `4.0` were accepted because
|
|
82
|
+
they compare equal, and `true` was migrated as a version 1 file.
|
|
83
|
+
- Evidence floats (`duration_ms`, evaluation `score`) must be finite, and the writer refuses
|
|
84
|
+
to emit `NaN`/`Infinity`, which are not JSON.
|
|
85
|
+
- `--backend ladybug` crashed with a raw traceback on a step `seq` outside the INT64 range
|
|
86
|
+
the backend stores. It now exits with a usage error naming the limit.
|
|
87
|
+
- `InMemoryStore.upsert_edges` accepted a `CAUSED_BY`/`TREE_PARENT` edge whose endpoint was
|
|
88
|
+
not a stored step, or a `BELONGS_TO` edge pointing at another trace; the failure surfaced
|
|
89
|
+
later as a `KeyError` from `ancestors`. It now raises `ValueError` and inserts nothing from
|
|
90
|
+
that batch, matching the LadybugDB store. `WROTE`/`READ` channel edges are unchecked as
|
|
91
|
+
before, and node upsert still replaces by ID.
|
|
92
|
+
- OTLP and Phoenix imports crashed with a raw traceback on a timestamp of `Infinity`, `NaN`
|
|
93
|
+
or a number beyond the representable date range, on a `spanId`/`parentSpanId` given as a
|
|
94
|
+
list, and on Phoenix `annotations` that were not an array. A timestamp that cannot be read
|
|
95
|
+
— including garbage text, which was silently dropped before — is now reported as
|
|
96
|
+
unavailable and disclosed on stderr by `ingest-otlp`, `ingest-phoenix`, `analyze` and
|
|
97
|
+
`phoenix diagnose`. Malformed ids and annotations are rejected with a usage error.
|
|
98
|
+
- An OTLP `status.code` of `true` was read as OK because `true == 1`, and `false` as UNSET
|
|
99
|
+
because `false == 0`; both are now rejected, for OTLP and Phoenix imports alike.
|
|
100
|
+
- LangGraph: two derived task steps could receive the same id (checkpoint `A` with task
|
|
101
|
+
`x#task:y`, checkpoint `A#task:x` with task `y`); the second silently replaced the first
|
|
102
|
+
and gained a second cause it never had. The collision is now rejected like a collision
|
|
103
|
+
with a checkpoint.
|
|
104
|
+
- LangGraph: a failed task that no candidate node reproduces is still reported unnamed, and
|
|
105
|
+
the read now says so on stderr. An unnamed failure is also what a change in LangGraph's
|
|
106
|
+
task-id algorithm would look like, so it is no longer silent.
|
|
107
|
+
|
|
108
|
+
- `diff` and `validate` printed producer text through Rich markup: a step named
|
|
109
|
+
`tool[bold]` showed as `tool`, and an invalid edge naming `ghost[red]X[/red]` showed as
|
|
110
|
+
`ghostX`. Both now print the text literally, as `inspect`, `explain` and `query` already
|
|
111
|
+
did. Output paths are printed literally too: an `--out` path containing `[/]` used to
|
|
112
|
+
raise a markup error after the file had been written, so the command exited 1 for work
|
|
113
|
+
it had completed.
|
|
114
|
+
- `diff --structure` paired any two leftover subtrees because every label is empty under
|
|
115
|
+
that option, then reported them under an empty path (`only in B under > : subtree ·`).
|
|
116
|
+
An empty label is no longer treated as evidence of correspondence, and the reported
|
|
117
|
+
subtrees now show step names so they can be found, while the comparison still ignores
|
|
118
|
+
them. The identical/not-identical verdict and exit code are unchanged.
|
|
119
|
+
- `explain` and `query --explain` labeled a nameless step by its `source`, which for
|
|
120
|
+
OTLP and Phoenix spans is always `loop` and for LangGraph is checkpoint metadata
|
|
121
|
+
(`input`, `loop`), not what the step was. They now use the step kind, like every other
|
|
122
|
+
view.
|
|
123
|
+
- `export-incident-memo` wrote `links_preserved` as `true`/`false`/`null` in its front
|
|
124
|
+
matter but as `True`/`False`/`None` in its summary. Both now use the front-matter form.
|
|
125
|
+
- The Phoenix CLI version-floor message is derived from the floor constant instead of
|
|
126
|
+
repeating it.
|
|
127
|
+
|
|
128
|
+
- `analyze --baseline` published token deltas, and cost deltas, from totals that covered
|
|
129
|
+
only some steps on one side: with tokens on 3 of 3 steps in the baseline and 1 of 3 in
|
|
130
|
+
the current run it reported `-200`, although the silent steps could have used any amount.
|
|
131
|
+
Like the duration delta, these deltas are now withheld with a note unless every step on
|
|
132
|
+
both sides reports the metric. In traces where only model calls carry token counts this
|
|
133
|
+
withholds the token delta. A cost total or delta withheld because steps or runs report
|
|
134
|
+
different or unknown currencies is now disclosed too; before, `analyze` printed
|
|
135
|
+
`cost=unavailable` with no reason.
|
|
136
|
+
|
|
137
|
+
- Writing an artifact or an analysis report left a hidden temporary file behind when the
|
|
138
|
+
write or fsync failed, because the temporary name was recorded only after writing. All
|
|
139
|
+
four output writers now share one helper that removes it on every failure.
|
|
140
|
+
|
|
141
|
+
### Compatibility notes for imports
|
|
142
|
+
|
|
143
|
+
These change what an input that imported successfully before now produces or whether it
|
|
144
|
+
imports at all. No committed fixture is affected.
|
|
145
|
+
|
|
146
|
+
- An OTLP token count given as a boolean (`true`, or `{"intValue": true}`) was stored as `1`;
|
|
147
|
+
it is now unavailable, matching how an unusable cost is already treated. A non-finite
|
|
148
|
+
token count is unavailable too instead of crashing the import. An `intValue` holding a
|
|
149
|
+
boolean is no longer converted to `0`/`1` for any attribute.
|
|
150
|
+
- Raw OTLP input could inject evaluation summaries through the private
|
|
151
|
+
`_tracegraph_evaluations` span key, bypassing the length limit the Phoenix importer
|
|
152
|
+
applies. Only the Phoenix importer reads that key now.
|
|
153
|
+
- An empty-string `traceId` or `spanId` is rejected. A `parentSpanId` of `0`, `false` or
|
|
154
|
+
`[]` used to be read as "no parent", which made a span with a malformed declared parent a
|
|
155
|
+
root; it is now rejected. A missing, `null` or empty-string `parentSpanId` still marks a
|
|
156
|
+
root span.
|
|
157
|
+
- A Phoenix evaluation score too large to represent crashed the import; it is now
|
|
158
|
+
unavailable, like a non-finite score.
|
|
159
|
+
- When several spans carry the `graph.node.parent_id` a span declares (a loop), the importer
|
|
160
|
+
picks the nearest execution that started earlier. A span with a missing or unreadable
|
|
161
|
+
start time sorted as time 0 and could win that choice, so a timestamp nobody recorded
|
|
162
|
+
decided a causal edge. Such spans no longer take part: the choice is treated as
|
|
163
|
+
ambiguous, and the span falls back to its declared `parentSpanId`, or the import is
|
|
164
|
+
rejected if it has none.
|
|
165
|
+
- The CLA workflow refused every pull request from the maintainer's own commit-author
|
|
166
|
+
account, which is not the account that owns the repository. Both are allowlisted now.
|
|
167
|
+
- The release documentation asked for a personal access token with *read* access to pull
|
|
168
|
+
requests. Posting the CLA comment failed with that configuration and succeeded after
|
|
169
|
+
raising it to write; the cause remains unconfirmed, since GitHub documents either Issues
|
|
170
|
+
write or Pull requests write as sufficient. The documentation now asks for write on
|
|
171
|
+
Contents, Issues and Pull requests alike and records the observation rather than
|
|
172
|
+
inferring a rule.
|
|
173
|
+
- It also did not say that a Trusted Publisher's "Environment name" is the GitHub
|
|
174
|
+
environment rather than the index, which failed the first 0.2.0 rehearsal.
|
|
175
|
+
|
|
176
|
+
### Dependencies
|
|
177
|
+
|
|
178
|
+
- The optional `[cypher]` extra now accepts LadybugDB `>=0.18,<0.22` (was `<0.19`), and the
|
|
179
|
+
lockfile moves to 0.21.2. The full test suite and every fixture's output are unchanged
|
|
180
|
+
on 0.21.2.
|
|
181
|
+
- CI now tests against Phoenix CLI 1.18.8 (was 1.8.1). The runtime floor stays 1.0.4: this
|
|
182
|
+
pin is what CI proves, not what tracegraph requires.
|
|
183
|
+
|
|
184
|
+
### Added
|
|
185
|
+
|
|
186
|
+
- `tracegraph export-incident-memo <artifact> -o memo.md` writes a Markdown post-mortem
|
|
187
|
+
intended for long-term memory stores. Its output is a strict allowlist: the run id appears
|
|
188
|
+
only as a truncated SHA-256 `run_digest`, steps appear as `step_<n>_<kind>` aliases, and
|
|
189
|
+
no step name, error message, evaluation label or payload is written. Edges that only show
|
|
190
|
+
containment or have no recorded origin are rendered as "preceded by", never "caused by".
|
|
191
|
+
The memo carries the SHA-256 of the exact artifact bytes it was built from.
|
|
192
|
+
|
|
193
|
+
### Changed
|
|
194
|
+
|
|
195
|
+
- **Artifact schema version 4.** When a step has several causes, its single TREE_PARENT is
|
|
196
|
+
now chosen by edge origin first — a declared graph or checkpoint parent over span
|
|
197
|
+
containment, over a span link, over an unknown origin — and only then by time. An artifact
|
|
198
|
+
whose tree differs from the purely temporal choice is stamped version 4; every other
|
|
199
|
+
artifact serializes as version 2 or 3, byte for byte as before. **Readers from 0.2.0 and
|
|
200
|
+
older refuse version 4 files** with an explicit unsupported-version error. This build reads
|
|
201
|
+
both projections, and the LadybugDB store re-emits a legacy file unchanged. The derived
|
|
202
|
+
tree feeds `inspect`, `diff`, and `analyze --baseline`, where it decides both the topology
|
|
203
|
+
changes and how steps are matched between the two runs: a step whose tree parent moved
|
|
204
|
+
can now appear as one removed and one added behavior change, and its logical step key
|
|
205
|
+
changes. Raw causal queries (`explain`, `query`) are unaffected.
|
|
206
|
+
- Phoenix timestamps without a timezone are now read as UTC rather than in the local
|
|
207
|
+
timezone of the machine running the import. **Digest impact:** artifacts built from such
|
|
208
|
+
exports now hash the same on every machine, and differ from any artifact previously built
|
|
209
|
+
where the local timezone applied a nonzero offset to those timestamps. Timestamps that
|
|
210
|
+
carry a `Z` or an offset are unchanged.
|
|
211
|
+
- **Phoenix artifacts no longer carry free-text annotation names or labels.** The Phoenix
|
|
212
|
+
import is documented as body-free and already kept only identifier-shaped span names, but
|
|
213
|
+
annotation names and labels were kept as free text (whitespace-collapsed, cut to 200
|
|
214
|
+
characters), so an evaluator's note such as `user said: my password is hunter2` reached
|
|
215
|
+
the artifact. They now pass the same identifier filter as span names: an evaluation whose
|
|
216
|
+
name fails it is dropped, and a label that fails it becomes `null` while the score is
|
|
217
|
+
kept. **Artifact content change:** a re-import of a Phoenix export with such annotations
|
|
218
|
+
produces different bytes and digests. Identifier-shaped text, which can still be personal
|
|
219
|
+
data such as an e-mail address, is kept.
|
|
220
|
+
|
|
221
|
+
## 0.2.0 - 2026-09-12
|
|
222
|
+
|
|
223
|
+
First published release. `0.1.0` was tagged but never uploaded.
|
|
224
|
+
|
|
225
|
+
### Fixed
|
|
226
|
+
|
|
227
|
+
- **A LangGraph node that raised an exception was reported as a successful run**
|
|
228
|
+
(`status=ok`, `error_count=0`). LangGraph does not route such a failure through a state
|
|
229
|
+
channel: it records it in the checkpoint's pending writes and writes no further checkpoint,
|
|
230
|
+
so reading channel values alone could not see it and no `--error-channel` value recovered
|
|
231
|
+
it. Each failed task now becomes its own step, hanging off the checkpoint that scheduled it
|
|
232
|
+
rather than marking that checkpoint — which is named after the node that *produced* it, so
|
|
233
|
+
marking it reported the wrong node.
|
|
234
|
+
- A task cancelled because a *sibling* failed is no longer counted as a second failure.
|
|
235
|
+
LangGraph records sibling cancellation through the same `__error__` channel as a genuine
|
|
236
|
+
fault; those tasks are reported as `unset` with no message, so one fault stays one failure
|
|
237
|
+
and a healthy node is never a primary candidate.
|
|
238
|
+
|
|
239
|
+
### Security
|
|
240
|
+
|
|
241
|
+
- **Reading a checkpoint database no longer executes what it contains.** LangGraph's
|
|
242
|
+
deserializer revives stored objects by importing a module and calling a name, both taken
|
|
243
|
+
from the payload, and by default an unrecognized target is logged and then called — so a
|
|
244
|
+
crafted checkpoint naming `os.system` or `subprocess.run` ran on the machine doing the
|
|
245
|
+
analysis (both verified against the pinned dependency). `tracegraph ingest` now passes a
|
|
246
|
+
serializer with an empty allowlist.
|
|
247
|
+
|
|
248
|
+
**Behaviour change:** objects outside the framework's registered types no longer revive
|
|
249
|
+
through `ingest`; they come back as their raw arguments. If you were relying on a custom
|
|
250
|
+
class being reconstructed from checkpoint state, it will now surface as plain data.
|
|
251
|
+
Constructing `LangGraphCheckpointAdapter` yourself is unaffected — the serializer is
|
|
252
|
+
whichever one your saver carries.
|
|
253
|
+
|
|
254
|
+
### Added
|
|
255
|
+
|
|
256
|
+
- The failing node's name, recovered by recomputing LangGraph's task id from checkpoint data.
|
|
257
|
+
The match is self-verifying, so a task nothing identifies keeps no name rather than
|
|
258
|
+
borrowing a neighbour's.
|
|
259
|
+
- `StepSource.TASK`, marking a step derived from pending writes rather than from a checkpoint.
|
|
260
|
+
- `RawTrace.ingest_warnings`, printed by `ingest` to stderr — disclosures about the *read*
|
|
261
|
+
(for example `Send` packets that could not be decoded), which are not part of the run and so
|
|
262
|
+
never enter the artifact.
|
|
263
|
+
- First public release metadata: Apache-2.0 `LICENSE`, `CLA.md`, `CODE_OF_CONDUCT.md`,
|
|
264
|
+
`CONTRIBUTING.md`, `SECURITY.md`, and PyPI classifiers, keywords, authors and project URLs.
|
|
265
|
+
- `tracegraph --version` (`-V`), which prints the bare version and nothing else. There was no
|
|
266
|
+
way to ask an installed build what it was.
|
|
267
|
+
- An sdist allowlist. Previously the source distribution shipped everything git tracked —
|
|
268
|
+
tests, docs, CI workflows, the lockfile and the checkpoint fixtures.
|
|
269
|
+
- A tag-triggered release workflow publishing through PyPI Trusted Publishing: `test-v*`
|
|
270
|
+
rehearses against TestPyPI, `v*` publishes to PyPI. Only the publishing job holds an OIDC
|
|
271
|
+
token, and it checks out nothing, installs nothing, and uploads only files whose digests
|
|
272
|
+
match what the build job recorded. Before any of that, the build refuses a tag whose
|
|
273
|
+
commit is not on the default branch, has no green `tests` run of its own, disagrees with
|
|
274
|
+
the packaged version, or has no dated changelog entry.
|
|
275
|
+
- `scripts/verify_artifacts.py`, which checks that the built distributions are exactly the
|
|
276
|
+
two files that will be uploaded and that the source distribution carries only what the
|
|
277
|
+
packaging allowlist intends. It also refuses tests, docs, CI configuration and the
|
|
278
|
+
lockfile outright, so widening that allowlist cannot quietly start shipping them, and
|
|
279
|
+
refuses any archive member whose path does not go where it reads — a `..` segment is
|
|
280
|
+
what would let a member satisfy both lists and still land somewhere else, or outside
|
|
281
|
+
the archive entirely, when someone extracts it.
|
|
282
|
+
- `scripts/require_ci_success.py`, the release gate described above.
|
|
283
|
+
- A [release runbook](docs/releasing.md) and a
|
|
284
|
+
[public release checklist](docs/public-release-checklist.md).
|
|
285
|
+
- The installed-wheel CI jobs now pin the version they expect and run the artifact
|
|
286
|
+
verifier, so the release checks are exercised on every pull request rather than first at
|
|
287
|
+
tag time.
|
|
288
|
+
|
|
289
|
+
### Changed
|
|
290
|
+
|
|
291
|
+
- **The distribution is now `agent-tracegraph`.** The plain `tracegraph` name on PyPI belongs
|
|
292
|
+
to an unrelated project. The import package, the console script, the schema `kind`
|
|
293
|
+
constants and the `TRACEGRAPH_*` environment variables are **unchanged** — only the name
|
|
294
|
+
you install differs. Installing from source or from a checkout is unaffected.
|
|
295
|
+
- The build backend version is pinned (`hatchling==1.32.0`), so a release rehearsal and the
|
|
296
|
+
production tag cannot run *different backend versions* against the same commit. This is
|
|
297
|
+
drift control, not reproducibility: hatchling's own dependencies still float. The uv
|
|
298
|
+
version used to build is pinned in the same way.
|
|
299
|
+
- `twine check` is a gate again, pinned to `twine@7.0.0`. It was disabled because twine 6
|
|
300
|
+
rejected the `Metadata-Version: 2.5` this backend emits; twine 7 accepts it.
|
|
301
|
+
- **Artifact schema version 3**, stamped *by content*: an artifact carrying derived task steps
|
|
302
|
+
declares 3 so an older reader refuses it by name instead of failing on an enum, while
|
|
303
|
+
artifacts without them still serialize as version 2 byte for byte. The envelope is inside
|
|
304
|
+
the digest `export-review-candidates` binds to, so a blanket bump would have invalidated
|
|
305
|
+
digests already published for unchanged artifacts.
|
|
306
|
+
- The LangGraph capture disclosure in every report now names both the error channel and task
|
|
307
|
+
pending writes. It remains unconditional: an artifact ingested by an older build, or one
|
|
308
|
+
using an unrecognized checkpoint layout, carries no derived step and is indistinguishable
|
|
309
|
+
from a genuinely clean run.
|
|
310
|
+
- `xxhash` is now a direct runtime dependency (LangGraph hashes task ids with it, but
|
|
311
|
+
`langgraph` itself is only a development dependency here).
|
|
312
|
+
- `langgraph-checkpoint>=4.1` is now declared directly rather than left transitive, because
|
|
313
|
+
ingestion calls its serializer API. `allowed_msgpack_modules` does not exist before 4.1
|
|
314
|
+
(4.0.0 raises `TypeError`), so the floor is what makes the hardening above guaranteed
|
|
315
|
+
rather than incidental.
|
|
316
|
+
|
|
317
|
+
### Known limitations
|
|
318
|
+
|
|
319
|
+
- Tasks that were *scheduled but never committed* — a run paused by `interrupt()`, stopped by
|
|
320
|
+
the recursion limit, or killed — are not reported. Trace `status` still means "did a step
|
|
321
|
+
error", so such a run reports `ok`.
|
|
322
|
+
- Only the latest persisted error survives per task, so repeated attempts are not
|
|
323
|
+
reconstructed.
|
|
324
|
+
- `Send` packets can only be named where `langgraph.types` is importable; an ordinary install
|
|
325
|
+
has only the `langgraph.checkpoint` half of that namespace, and the gap is disclosed.
|
|
326
|
+
|
|
327
|
+
## 0.1.0 - 2026-05-30
|
|
328
|
+
|
|
329
|
+
Tagged but never published. Initial read-path causal-graph analysis of LangGraph agent traces.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agent-tracegraph
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Time-travel debugging and causal RCA for LangGraph agent traces, on a causal graph.
|
|
5
5
|
Project-URL: Homepage, https://github.com/memtomem/tracegraph
|
|
6
6
|
Project-URL: Repository, https://github.com/memtomem/tracegraph
|
|
@@ -26,7 +26,7 @@ Requires-Dist: rich>=13
|
|
|
26
26
|
Requires-Dist: typer>=0.12
|
|
27
27
|
Requires-Dist: xxhash>=3
|
|
28
28
|
Provides-Extra: cypher
|
|
29
|
-
Requires-Dist: ladybug<0.
|
|
29
|
+
Requires-Dist: ladybug<0.22,>=0.18; extra == 'cypher'
|
|
30
30
|
Description-Content-Type: text/markdown
|
|
31
31
|
|
|
32
32
|
# tracegraph
|
|
@@ -110,6 +110,9 @@ tracegraph query tool-failure --backend ladybug A.json B.json # use the option
|
|
|
110
110
|
|
|
111
111
|
# export versioned, body-free governance evidence (an empty match set is a valid report)
|
|
112
112
|
tracegraph export-review-candidates tool-retry-failure *.json -o candidates.json
|
|
113
|
+
|
|
114
|
+
# export an allowlisted incident post-mortem (Markdown) for a long-term memory store
|
|
115
|
+
tracegraph export-incident-memo A.json -o incident.md
|
|
113
116
|
```
|
|
114
117
|
|
|
115
118
|
Frequently-used options, beyond `--out` / `--json-out`:
|
|
@@ -273,17 +276,27 @@ result, blast radius, preflight result, or graph state.
|
|
|
273
276
|
|
|
274
277
|
## Status
|
|
275
278
|
|
|
276
|
-
|
|
279
|
+
Alpha (`0.x`): the artifact, report and review-candidate formats are versioned contracts,
|
|
280
|
+
and any change to them is called out in the [changelog](CHANGELOG.md).
|
|
277
281
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
282
|
+
| Area | What exists |
|
|
283
|
+
|---|---|
|
|
284
|
+
| Sources | LangGraph checkpoint savers (including subgraph namespaces and native task failures), OTLP/OpenInference span exports, Phoenix CLI exports |
|
|
285
|
+
| Commands | `ingest`, `ingest-otlp`, `ingest-phoenix`, `inspect`, `validate`, `explain`, `diff`, `analyze`, `presets`, `query`, `export-review-candidates`, `export-incident-memo`, `phoenix doctor`, `phoenix diagnose` |
|
|
286
|
+
| Patterns | Versioned presets matched over the raw causal graph; the governance-eligible `tool-retry-failure@v2` requires an explicit producer retry marker, and repetition-only heuristics are query-only |
|
|
287
|
+
| Backends | Pure-Python in-memory store (default); optional LadybugDB/Cypher accelerator (`[cypher]`), whose results must equal the pure-Python matcher's |
|
|
288
|
+
| Ecosystem | SyncMill run correlation (`syncmill.run_id`), Toolgraph preflight evidence as non-causal metadata, a weekly Phoenix + SyncMill end-to-end workflow (Phoenix CLI and server pinned; SyncMill tracks its default branch) |
|
|
289
|
+
|
|
290
|
+
Known limits:
|
|
291
|
+
|
|
292
|
+
- A LangGraph task that was scheduled but left no result and no recorded error (a run
|
|
293
|
+
paused by `interrupt()`, stopped by the recursion limit, or killed) is not reported, so
|
|
294
|
+
such a run reads `ok` unless some other step recorded an error.
|
|
295
|
+
- Phoenix exports carry no span links, so their artifacts are parent-only; additional fan-in
|
|
296
|
+
causes may be missing.
|
|
297
|
+
- Report privacy (`safe-v1`) applies to reports; OTLP and LangGraph artifacts keep the
|
|
298
|
+
producer's names and error messages.
|
|
299
|
+
- CI covers Python 3.12 on Linux.
|
|
287
300
|
|
|
288
301
|
Caveat for the checkpoint adapter: it is a **checkpoint-level** view (one node per
|
|
289
302
|
super-step), and node names/kinds are best-effort metadata. Phoenix/OTLP adapters are
|
|
@@ -328,14 +341,30 @@ with deterministic SHA-256 aliases, and disclose in `warnings` when an alias act
|
|
|
328
341
|
the report. Trace/step identifiers remain; this is not anonymization.
|
|
329
342
|
Raw artifact names and bytes are not rewritten for report privacy or matching, so the
|
|
330
343
|
artifact — unlike the report — can still carry whatever the producer put in a span name or
|
|
331
|
-
error message
|
|
344
|
+
error message. Phoenix ingestion is the exception: it filters at the source, keeping span
|
|
345
|
+
names and annotation names and labels only when they are identifier-shaped, and dropping
|
|
346
|
+
status messages. Identifier-shaped is not the same as anonymous: an e-mail address passes.
|
|
332
347
|
`export-review-candidates` output is not passed through the report redactor: its `tool_key`
|
|
333
|
-
is the raw endpoint span name.
|
|
348
|
+
is the raw endpoint span name. `export-incident-memo` goes further than `safe-v1`: it writes
|
|
349
|
+
no step names, error messages or evaluation labels at all. Steps appear as kind-based
|
|
350
|
+
aliases and the run id as a truncated digest; the rest is structural metadata such as trace
|
|
351
|
+
status, causal fidelity, step and error counts, preset pattern ids and versions, edge
|
|
352
|
+
origins, fidelity disclosures, and the digest of the exact artifact bytes. Logical
|
|
334
353
|
comparison keys are JSON-encoded typed paths; consumers should treat them as opaque strings.
|
|
335
354
|
Containment and unknown edges preserve all error investigation candidates, deeper first.
|
|
336
355
|
Explicit causal ancestry supplies context, not proof that an exception propagated.
|
|
337
356
|
Explicit OTLP OK takes precedence over handled exception events on new ingestion; old
|
|
338
357
|
artifacts are not reinterpreted.
|
|
358
|
+
A span whose status is UNSET and that carries no exception event (one with a message or
|
|
359
|
+
type makes it `error` in both importers) is read differently by source. `ingest-otlp`
|
|
360
|
+
records it as `ok`, because UNSET is OpenTelemetry's default status and producers such as
|
|
361
|
+
SyncMill leave successful spans unset. Phoenix ingestion keeps it as `unset`. Trace status
|
|
362
|
+
is the same either way, but step statuses differ wherever they are shown, and a preset that
|
|
363
|
+
requires an `ok` step does not match an unset one: a SyncMill run where an agent attempt
|
|
364
|
+
left UNSET directly causes a failing `gate:` tool reports `gate-failure-after-success`
|
|
365
|
+
through `ingest-otlp` and not through Phoenix. Compare a run with a baseline from the same
|
|
366
|
+
source; mixing them can report a step whose status differs only by source as a behavior
|
|
367
|
+
change (`ok` to `unset`, or the reverse).
|
|
339
368
|
|
|
340
369
|
LangGraph ingestion reads both the configured error state channel and native task failures
|
|
341
370
|
from checkpoint pending writes. A node that raises becomes a derived `task` step under the
|
|
@@ -346,9 +375,11 @@ borrowing a neighbour's name. When one task raises, LangGraph
|
|
|
346
375
|
cancels its siblings and records that through the same channel; a cancelled task is reported
|
|
347
376
|
as an `unset` step with no message, because it was torn down rather than at fault. Only the
|
|
348
377
|
latest persisted error survives per task, so repeated attempts are not reconstructed, and
|
|
349
|
-
`Send` packets are nameable only where `langgraph.types` is importable — an ordinary install
|
|
350
|
-
|
|
351
|
-
|
|
378
|
+
`Send` packets are nameable only where `langgraph.types` is importable — an ordinary install
|
|
379
|
+
discloses them instead. An artifact whose derived tree relies on EdgeOrigin precedence declares
|
|
380
|
+
artifact `schema_version` 4; otherwise, an artifact carrying derived task steps declares
|
|
381
|
+
`schema_version` 3, and artifacts without them still serialize as version 2, byte for byte.
|
|
382
|
+
Missing observed errors still do not
|
|
352
383
|
prove success: an artifact ingested by an older build, or one using an unrecognized checkpoint
|
|
353
384
|
layout, carries no derived step and looks exactly like a clean run, which is why the capture
|
|
354
385
|
disclosure is unconditional. Link preservation
|
|
@@ -356,7 +387,10 @@ means valid in-trace links only. Structural diff compares the derived tree and d
|
|
|
356
387
|
lossy step counts. Metrics sum available span observations: partial coverage and producer
|
|
357
388
|
aggregation can undercount or double count. Coverage gaps are disclosed rather than absorbed
|
|
358
389
|
— a wall duration derived from a subset of steps says so, one whose end precedes its start is
|
|
359
|
-
withheld, and a single unparseable cost withholds the whole total instead of understating it.
|
|
390
|
+
withheld, and a single unparseable cost withholds the whole total instead of understating it.
|
|
391
|
+
An OTLP or Phoenix import records an unreadable total cost as `unreadable` for that reason, and
|
|
392
|
+
reports token counts, other costs, currencies and evaluation scores it cannot read as
|
|
393
|
+
unavailable, disclosing each on stderr; the producer's value is never kept. File input has a size limit, but stdin/Phoenix
|
|
360
394
|
subprocess output and query materialization are not streaming memory guarantees.
|
|
361
395
|
|
|
362
396
|
Both stores isolate returned mutable objects. InMemory node upsert replaces by ID;
|
|
@@ -79,6 +79,9 @@ tracegraph query tool-failure --backend ladybug A.json B.json # use the option
|
|
|
79
79
|
|
|
80
80
|
# export versioned, body-free governance evidence (an empty match set is a valid report)
|
|
81
81
|
tracegraph export-review-candidates tool-retry-failure *.json -o candidates.json
|
|
82
|
+
|
|
83
|
+
# export an allowlisted incident post-mortem (Markdown) for a long-term memory store
|
|
84
|
+
tracegraph export-incident-memo A.json -o incident.md
|
|
82
85
|
```
|
|
83
86
|
|
|
84
87
|
Frequently-used options, beyond `--out` / `--json-out`:
|
|
@@ -242,17 +245,27 @@ result, blast radius, preflight result, or graph state.
|
|
|
242
245
|
|
|
243
246
|
## Status
|
|
244
247
|
|
|
245
|
-
|
|
248
|
+
Alpha (`0.x`): the artifact, report and review-candidate formats are versioned contracts,
|
|
249
|
+
and any change to them is called out in the [changelog](CHANGELOG.md).
|
|
246
250
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
251
|
+
| Area | What exists |
|
|
252
|
+
|---|---|
|
|
253
|
+
| Sources | LangGraph checkpoint savers (including subgraph namespaces and native task failures), OTLP/OpenInference span exports, Phoenix CLI exports |
|
|
254
|
+
| Commands | `ingest`, `ingest-otlp`, `ingest-phoenix`, `inspect`, `validate`, `explain`, `diff`, `analyze`, `presets`, `query`, `export-review-candidates`, `export-incident-memo`, `phoenix doctor`, `phoenix diagnose` |
|
|
255
|
+
| Patterns | Versioned presets matched over the raw causal graph; the governance-eligible `tool-retry-failure@v2` requires an explicit producer retry marker, and repetition-only heuristics are query-only |
|
|
256
|
+
| Backends | Pure-Python in-memory store (default); optional LadybugDB/Cypher accelerator (`[cypher]`), whose results must equal the pure-Python matcher's |
|
|
257
|
+
| Ecosystem | SyncMill run correlation (`syncmill.run_id`), Toolgraph preflight evidence as non-causal metadata, a weekly Phoenix + SyncMill end-to-end workflow (Phoenix CLI and server pinned; SyncMill tracks its default branch) |
|
|
258
|
+
|
|
259
|
+
Known limits:
|
|
260
|
+
|
|
261
|
+
- A LangGraph task that was scheduled but left no result and no recorded error (a run
|
|
262
|
+
paused by `interrupt()`, stopped by the recursion limit, or killed) is not reported, so
|
|
263
|
+
such a run reads `ok` unless some other step recorded an error.
|
|
264
|
+
- Phoenix exports carry no span links, so their artifacts are parent-only; additional fan-in
|
|
265
|
+
causes may be missing.
|
|
266
|
+
- Report privacy (`safe-v1`) applies to reports; OTLP and LangGraph artifacts keep the
|
|
267
|
+
producer's names and error messages.
|
|
268
|
+
- CI covers Python 3.12 on Linux.
|
|
256
269
|
|
|
257
270
|
Caveat for the checkpoint adapter: it is a **checkpoint-level** view (one node per
|
|
258
271
|
super-step), and node names/kinds are best-effort metadata. Phoenix/OTLP adapters are
|
|
@@ -297,14 +310,30 @@ with deterministic SHA-256 aliases, and disclose in `warnings` when an alias act
|
|
|
297
310
|
the report. Trace/step identifiers remain; this is not anonymization.
|
|
298
311
|
Raw artifact names and bytes are not rewritten for report privacy or matching, so the
|
|
299
312
|
artifact — unlike the report — can still carry whatever the producer put in a span name or
|
|
300
|
-
error message
|
|
313
|
+
error message. Phoenix ingestion is the exception: it filters at the source, keeping span
|
|
314
|
+
names and annotation names and labels only when they are identifier-shaped, and dropping
|
|
315
|
+
status messages. Identifier-shaped is not the same as anonymous: an e-mail address passes.
|
|
301
316
|
`export-review-candidates` output is not passed through the report redactor: its `tool_key`
|
|
302
|
-
is the raw endpoint span name.
|
|
317
|
+
is the raw endpoint span name. `export-incident-memo` goes further than `safe-v1`: it writes
|
|
318
|
+
no step names, error messages or evaluation labels at all. Steps appear as kind-based
|
|
319
|
+
aliases and the run id as a truncated digest; the rest is structural metadata such as trace
|
|
320
|
+
status, causal fidelity, step and error counts, preset pattern ids and versions, edge
|
|
321
|
+
origins, fidelity disclosures, and the digest of the exact artifact bytes. Logical
|
|
303
322
|
comparison keys are JSON-encoded typed paths; consumers should treat them as opaque strings.
|
|
304
323
|
Containment and unknown edges preserve all error investigation candidates, deeper first.
|
|
305
324
|
Explicit causal ancestry supplies context, not proof that an exception propagated.
|
|
306
325
|
Explicit OTLP OK takes precedence over handled exception events on new ingestion; old
|
|
307
326
|
artifacts are not reinterpreted.
|
|
327
|
+
A span whose status is UNSET and that carries no exception event (one with a message or
|
|
328
|
+
type makes it `error` in both importers) is read differently by source. `ingest-otlp`
|
|
329
|
+
records it as `ok`, because UNSET is OpenTelemetry's default status and producers such as
|
|
330
|
+
SyncMill leave successful spans unset. Phoenix ingestion keeps it as `unset`. Trace status
|
|
331
|
+
is the same either way, but step statuses differ wherever they are shown, and a preset that
|
|
332
|
+
requires an `ok` step does not match an unset one: a SyncMill run where an agent attempt
|
|
333
|
+
left UNSET directly causes a failing `gate:` tool reports `gate-failure-after-success`
|
|
334
|
+
through `ingest-otlp` and not through Phoenix. Compare a run with a baseline from the same
|
|
335
|
+
source; mixing them can report a step whose status differs only by source as a behavior
|
|
336
|
+
change (`ok` to `unset`, or the reverse).
|
|
308
337
|
|
|
309
338
|
LangGraph ingestion reads both the configured error state channel and native task failures
|
|
310
339
|
from checkpoint pending writes. A node that raises becomes a derived `task` step under the
|
|
@@ -315,9 +344,11 @@ borrowing a neighbour's name. When one task raises, LangGraph
|
|
|
315
344
|
cancels its siblings and records that through the same channel; a cancelled task is reported
|
|
316
345
|
as an `unset` step with no message, because it was torn down rather than at fault. Only the
|
|
317
346
|
latest persisted error survives per task, so repeated attempts are not reconstructed, and
|
|
318
|
-
`Send` packets are nameable only where `langgraph.types` is importable — an ordinary install
|
|
319
|
-
|
|
320
|
-
|
|
347
|
+
`Send` packets are nameable only where `langgraph.types` is importable — an ordinary install
|
|
348
|
+
discloses them instead. An artifact whose derived tree relies on EdgeOrigin precedence declares
|
|
349
|
+
artifact `schema_version` 4; otherwise, an artifact carrying derived task steps declares
|
|
350
|
+
`schema_version` 3, and artifacts without them still serialize as version 2, byte for byte.
|
|
351
|
+
Missing observed errors still do not
|
|
321
352
|
prove success: an artifact ingested by an older build, or one using an unrecognized checkpoint
|
|
322
353
|
layout, carries no derived step and looks exactly like a clean run, which is why the capture
|
|
323
354
|
disclosure is unconditional. Link preservation
|
|
@@ -325,7 +356,10 @@ means valid in-trace links only. Structural diff compares the derived tree and d
|
|
|
325
356
|
lossy step counts. Metrics sum available span observations: partial coverage and producer
|
|
326
357
|
aggregation can undercount or double count. Coverage gaps are disclosed rather than absorbed
|
|
327
358
|
— a wall duration derived from a subset of steps says so, one whose end precedes its start is
|
|
328
|
-
withheld, and a single unparseable cost withholds the whole total instead of understating it.
|
|
359
|
+
withheld, and a single unparseable cost withholds the whole total instead of understating it.
|
|
360
|
+
An OTLP or Phoenix import records an unreadable total cost as `unreadable` for that reason, and
|
|
361
|
+
reports token counts, other costs, currencies and evaluation scores it cannot read as
|
|
362
|
+
unavailable, disclosing each on stderr; the producer's value is never kept. File input has a size limit, but stdin/Phoenix
|
|
329
363
|
subprocess output and query materialization are not streaming memory guarantees.
|
|
330
364
|
|
|
331
365
|
Both stores isolate returned mutable objects. InMemory node upsert replaces by ID;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# the schema `kind` constants and the TRACEGRAPH_* environment variables — those are package
|
|
5
5
|
# identity, not distribution identity, and renaming them would break published contracts.
|
|
6
6
|
name = "agent-tracegraph"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.1"
|
|
8
8
|
description = "Time-travel debugging and causal RCA for LangGraph agent traces, on a causal graph."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -58,7 +58,7 @@ tracegraph = "tracegraph.cli:main"
|
|
|
58
58
|
# LadybugDB is the actively maintained successor to the archived Kùzu project. The JSON
|
|
59
59
|
# artifact remains authoritative, so an accelerator cache is rebuilt across DB versions.
|
|
60
60
|
[project.optional-dependencies]
|
|
61
|
-
cypher = ["ladybug>=0.18,<0.
|
|
61
|
+
cypher = ["ladybug>=0.18,<0.22"]
|
|
62
62
|
|
|
63
63
|
[dependency-groups]
|
|
64
64
|
dev = [
|
|
@@ -70,6 +70,9 @@ dev = [
|
|
|
70
70
|
# a dependency bump there would turn that test red for a reason nothing in it names.
|
|
71
71
|
"pyyaml>=6",
|
|
72
72
|
]
|
|
73
|
+
# Kept out of `dev` so the default environment stays what the test jobs prove; CI's lint
|
|
74
|
+
# job installs it explicitly. Pinned: a new mypy release is a new set of rules.
|
|
75
|
+
typing = ["mypy==1.18.2"]
|
|
73
76
|
|
|
74
77
|
[build-system]
|
|
75
78
|
# Pinned exactly. A release rehearsal and the production tag are two builds on two days, and
|
|
@@ -115,6 +118,15 @@ src = ["src", "tests"]
|
|
|
115
118
|
select = ["F", "E4", "E7", "E9", "B"]
|
|
116
119
|
ignore = ["B008"] # typer declares option defaults in the signature by design
|
|
117
120
|
|
|
121
|
+
[tool.mypy]
|
|
122
|
+
# The wheel ships py.typed, so its annotations are a contract. Not `strict`: the goal is
|
|
123
|
+
# that what is annotated is checked and correct, not that every helper gains a signature.
|
|
124
|
+
python_version = "3.12"
|
|
125
|
+
files = ["src/tracegraph"]
|
|
126
|
+
check_untyped_defs = true
|
|
127
|
+
warn_unused_ignores = true
|
|
128
|
+
warn_redundant_casts = true
|
|
129
|
+
|
|
118
130
|
[tool.pytest.ini_options]
|
|
119
131
|
testpaths = ["tests"]
|
|
120
132
|
pythonpath = ["examples"]
|