asz.view
asz.view is one conversation, rebuilt from its Session Flow and its Session Data, as one document:
everything a viewer renders, and nothing a viewer must compute. Every talk is a tree of runs and
steps with the text the referenced records carry, and the streams, the segments, the relations,
the rounds and the files sit beside them, each verified. The evidence is inside it once, so a
viewer never opens a .sd file; the ref on a node is a citation, not a pointer to fetch.
It is never a file. asz view builds it in memory from the .sf rounds and the .sd files, once
per fold, and serves it as one response at /api/c/{id}/view. A server that holds the same files,
such as the SkyWalking OAP, builds the same document and answers a conversation query with it.
Package pkg/sessionview defines and owns the shape. Every reader shares it, and a change to it is
a change to the version: a 1.x adds keys and never removes or renames one; a 2.0 may do either.
The document is JSON. Keys are snake_case, as in the two source formats, and are written in the
order this page lists them. Times are unix milliseconds, read from the .sd record a node
references; a view is read and never digested, so it carries no RFC 3339 strings. The same head
round over the same files gives the same document, so one built by asz view and one built by
another server compare equal as documents.
Top level
{"format":"asz.view","version":"1.0",
"conversation":"0438c73b-…","sessions":["0438c73b-…"],
"head":{"round":4,"digest":"2e77…"},"parser":"v1","policy":"v1+idle=10m0s",
"summary":{"title":"Check otel-rules support for meter mal","state":"verified","problems":[],
"talks":357,"steps":16121,"streams":132,"segments":50,"rounds":4,"unresolved":0,
"from":1786033245531,"to":1786502191749,
"kinds":{"llm.call":4656,"tool":5606,…},"relation_types":{"in_segment":346,…},"quality":{"exact_unique":338,…}},
"rounds":[{"round":1,"digest":"6d2d…","previous":null,"from_seq":1,"through_seq":5,"input_digest":"…",
"from_time":1786033245531,"through_time":1786322168715,"verified":true}, …],
"files":[{"file":"0438c73b-…/streams/main/transcript-…-000002.sd","format":"sd","kind":"transcript",
"seq":2,"round":null,"stream":"main","run":null,"lines":1017,"bytes":2097000,"digest":"9a39…",
"from_time":1786033290556,"through_time":1786036000000}, …,
{"file":"_conversations/0438c73b-…/rounds/r000001-6d2d93b21f79.sf","format":"sf","kind":"round",
"seq":null,"round":1,"stream":null,"run":null,"lines":3575,"bytes":1026788,"digest":"f3fe…",
"from_time":1786033245531,"through_time":1786322168715}],
"streams":[{"id":"stream/main","name":"main","role":"main","label":"","parent":"","records":10728,
"steps":7310,"talk":"talk/main/95a1…","named_by":"","opened_by":[]}, …],
"segments":[{"id":"segment/at_2_7","state":"candidate","committable":true,"talks":24,"from":1786033290556,"to":1786039329174}, …],
"talks":[{"id":"talk/main/95a1…","kind":"talk","parent":"epoch/main/0","stream":"main","at":1786033290556,
"ref":{"seq":2,"row":7},"attrs":{"loops":1,"runs":1,"trigger":"external"},
"label":"for meter mal, …","reply":"## Short answer…","runs":1,"steps":132,"tools":51,
"from":1786033290556,"to":1786033717089,"segment":"segment/at_2_7",
"children":[…],"edges":[{"type":"in_segment","other":"segment/at_2_7","dir":"out","quality":"exact_unique","via":"activity window"}]}, …],
"relations":[{"id":"rel/starts/…","type":"starts","from":"tool/toolu_…","to":"stream/a1…","quality":"exact_unique",
"via":"parent tool result","evidence":[{"seq":1,"row":12}]}, …],
"unresolved":[]}
| Key | Value |
|---|---|
format, version |
asz.view, 1.0. A reader that does not know the version stops here. |
conversation, sessions |
the conversation id, and the sessions that contributed to it, from the fold’s session nodes; one session, equal to the conversation id, for the Claude Code adapter |
head |
round and digest of the newest round the document was folded to |
parser, policy |
from the head round’s header |
summary |
title; state, one of verified, incomplete when a round or a file is missing, mismatch when a digest failed; problems, one line each, empty when verified; the counts talks, steps, streams, segments, rounds, unresolved; from and to, when the session began and its last activity, from the session node; and kinds, relation_types and quality, the fold sized by node kind, by relation type and by how well each relation is known |
rounds |
one per round, in order: round, digest, previous (null on round 1), from_seq, through_seq, input_digest, from_time, through_time (the record time range of the files the round consumed, null when none carries a time), verified |
files |
one per .sd file, then one per round: file (its path on the wire), format (sd or sf), kind, seq or round, stream or run, lines, bytes, digest, from_time, through_time. Absent values are null. Together with rounds, this is exactly what a rebuild needs. |
streams |
one per execution stream: id, name, role (main or child), label, parent, records, steps, talk, named_by, and opened_by, every step the assembler could tie to the start of the stream as {step, stream, talk, quality}; several means it did not choose, and neither does a view |
segments |
one per activity window: id, state, committable, talks, from, to |
talks |
one tree per talk, in time order. See the node below |
relations |
one per relation of the fold: id, type, from, to, quality, via, evidence |
unresolved |
one per reference the assembler could not resolve, open or since resolved: id, kind, ref, reason, state |
Verification is content, not an error. A gap in the chain or a failed digest is written into
summary.state and summary.problems, each round says whether it verified, and the rest of the
document holds whatever could still be folded. A viewer shows the problem; it never gets an error
instead of a document.
A node in talks
{"id":"tool/toolu_01KH…","kind":"tool","parent":"call/msg_011C…","stream":"main","at":1786033295667,
"ref":{"seq":2,"row":13,"block":0},"refs":[{"seq":2,"row":13,"block":0},{"seq":2,"row":14,"block":0}],
"attrs":{"name":"Bash","result":"available","result_join":"exact_unique","timing":"unavailable"},
"text":"{\"command\":\"ls …\"}","state":"available","bytes":145,"flags":["finished"],
"name":"Bash","result":"…","result_state":"available","result_bytes":2048,
"request_to_result_ms":1312,"request_to_result_join":"exact_unique",
"edges":[{"type":"starts","other":"stream/a1…","dir":"out","quality":"exact_unique","via":"parent tool result"}],
"children":[…]}
| Key | Value |
|---|---|
id, kind, parent, stream, attrs |
the node as the fold holds it; kind is one of the node kinds of Session Flow |
at |
when its record happened, from the record; 0 when nothing observed it |
ref, refs |
the record it stands on and every record it covers, as {seq, row, block}, kept so a viewer can show the evidence |
text, state, bytes |
the part the node stands on: its readable text, clipped to 2,000 bytes, whether the content is available, and its full size. For a data part the text is the data as compact JSON. A reader wanting the whole record reads it by address. |
usage, flags, dropped |
what else the referenced record says, copied once: on an llm.call, the token counts in, out, cache_read, cache_write from the one record usage_at names, never a sum over fragments; the record’s flags; and its dropped list, so a viewer can say what was left out and why |
| a talk adds | label, reply (the first 2,000 bytes of its last assistant message), runs, steps, tools, from, to, child, segment |
| a tool or agent call adds | name, failed, result, result_state, result_bytes, request_to_result_ms and request_to_result_join, the time from the request record to the result record where the assembler joined them exactly |
a turn.duration step adds |
duration_ms, duration_measured_by |
children |
containment, in record order: a talk holds runs, a run holds steps, a call holds what it produced |
edges |
every relation touching the node, in both directions, as {type, other, dir, quality, via}, so a viewer draws cross-stream flow without searching relations |
Keys a node has no value for are absent, not null. Nothing in a document is inferred beyond what
the fold and the records say. Where the fold says unavailable, the document says it too.
Reading it
asz view serves the document at /api/c/{id}/view and builds it once per fold, so a second reader
pays nothing until a new round arrives. The largest conversation measured, 357 talks and 16,121
steps, is 19 MB as one document and was built in 0.7 s.