wizardflow 0.2.0__tar.gz → 0.3.0__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.
Files changed (89) hide show
  1. {wizardflow-0.2.0 → wizardflow-0.3.0}/PKG-INFO +120 -16
  2. {wizardflow-0.2.0 → wizardflow-0.3.0}/README.md +119 -15
  3. {wizardflow-0.2.0 → wizardflow-0.3.0}/pyproject.toml +1 -1
  4. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/__init__.py +20 -0
  5. wizardflow-0.3.0/src/wizardflow/_ui/404.html +25 -0
  6. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/__next.__PAGE__.txt +3 -3
  7. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/__next._full.txt +4 -4
  8. wizardflow-0.3.0/src/wizardflow/_ui/__next._head.txt +6 -0
  9. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/__next._index.txt +1 -1
  10. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/__next._tree.txt +2 -2
  11. wizardflow-0.3.0/src/wizardflow/_ui/_next/static/chunks/2q_qu9w0vej6s.js +115 -0
  12. wizardflow-0.2.0/src/wizardflow/_ui/_next/static/chunks/0mz_v1wicwnmn.css → wizardflow-0.3.0/src/wizardflow/_ui/_next/static/chunks/3lt2ss7dftc2n.css +1 -1
  13. wizardflow-0.3.0/src/wizardflow/_ui/_next/static/media/icon.09qublg69ek7b.svg +34 -0
  14. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_not-found/__next._full.txt +2 -2
  15. wizardflow-0.3.0/src/wizardflow/_ui/_not-found/__next._head.txt +6 -0
  16. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_not-found/__next._index.txt +1 -1
  17. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_not-found/__next._not-found/__PAGE__.txt +1 -1
  18. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_not-found/__next._not-found.txt +1 -1
  19. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_not-found/__next._tree.txt +1 -1
  20. wizardflow-0.3.0/src/wizardflow/_ui/_not-found.html +25 -0
  21. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_not-found.txt +2 -2
  22. wizardflow-0.3.0/src/wizardflow/_ui/icon.svg +34 -0
  23. wizardflow-0.3.0/src/wizardflow/_ui/index.html +25 -0
  24. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/index.txt +4 -4
  25. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/sitemap.xml +1 -1
  26. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/client.py +123 -12
  27. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/html.py +25 -0
  28. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/markdown.py +23 -3
  29. {wizardflow-0.2.0 → wizardflow-0.3.0}/tests/test_html.py +17 -0
  30. {wizardflow-0.2.0 → wizardflow-0.3.0}/tests/test_markdown.py +27 -0
  31. {wizardflow-0.2.0 → wizardflow-0.3.0}/tests/test_trace.py +250 -0
  32. wizardflow-0.2.0/src/wizardflow/_ui/404.html +0 -25
  33. wizardflow-0.2.0/src/wizardflow/_ui/__next._head.txt +0 -6
  34. wizardflow-0.2.0/src/wizardflow/_ui/_next/static/chunks/4158u-399exxn.js +0 -115
  35. wizardflow-0.2.0/src/wizardflow/_ui/_next/static/media/icon.3okpzkln1vq00.svg +0 -19
  36. wizardflow-0.2.0/src/wizardflow/_ui/_not-found/__next._head.txt +0 -6
  37. wizardflow-0.2.0/src/wizardflow/_ui/_not-found.html +0 -25
  38. wizardflow-0.2.0/src/wizardflow/_ui/icon.svg +0 -19
  39. wizardflow-0.2.0/src/wizardflow/_ui/index.html +0 -25
  40. {wizardflow-0.2.0 → wizardflow-0.3.0}/.gitignore +0 -0
  41. {wizardflow-0.2.0 → wizardflow-0.3.0}/CONTRIBUTING.md +0 -0
  42. {wizardflow-0.2.0 → wizardflow-0.3.0}/LICENSE +0 -0
  43. {wizardflow-0.2.0 → wizardflow-0.3.0}/assets/demo.gif +0 -0
  44. {wizardflow-0.2.0 → wizardflow-0.3.0}/examples/data_types.py +0 -0
  45. {wizardflow-0.2.0 → wizardflow-0.3.0}/examples/multibranch.html +0 -0
  46. {wizardflow-0.2.0 → wizardflow-0.3.0}/examples/multibranch.md +0 -0
  47. {wizardflow-0.2.0 → wizardflow-0.3.0}/examples/multibranch.py +0 -0
  48. {wizardflow-0.2.0 → wizardflow-0.3.0}/examples/quickstart.html +0 -0
  49. {wizardflow-0.2.0 → wizardflow-0.3.0}/examples/quickstart.md +0 -0
  50. {wizardflow-0.2.0 → wizardflow-0.3.0}/examples/quickstart.py +0 -0
  51. {wizardflow-0.2.0 → wizardflow-0.3.0}/scripts/build_ui.py +0 -0
  52. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_render.py +0 -0
  53. {wizardflow-0.2.0/src/wizardflow/_ui/_next/static/F7xCRRyix77IKo6qy-ltF → wizardflow-0.3.0/src/wizardflow/_ui/_next/static/AJjiS0WLQjNzSyuZBS0Ff}/_buildManifest.js +0 -0
  54. {wizardflow-0.2.0/src/wizardflow/_ui/_next/static/F7xCRRyix77IKo6qy-ltF → wizardflow-0.3.0/src/wizardflow/_ui/_next/static/AJjiS0WLQjNzSyuZBS0Ff}/_clientMiddlewareManifest.js +0 -0
  55. {wizardflow-0.2.0/src/wizardflow/_ui/_next/static/F7xCRRyix77IKo6qy-ltF → wizardflow-0.3.0/src/wizardflow/_ui/_next/static/AJjiS0WLQjNzSyuZBS0Ff}/_ssgManifest.js +0 -0
  56. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/05-c3ty_6dwfk.js +0 -0
  57. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/09s72r58ijxwx.js +0 -0
  58. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/0cz1d0mv5g_q7.js +0 -0
  59. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/0u1x9l49cgb30.js +0 -0
  60. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/0ux_7aev0a2kt.js +0 -0
  61. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/142r2alz4_x6t.js +0 -0
  62. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/14mrh2-p_w84d.js +0 -0
  63. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/18clj6xsyhc_j.css +0 -0
  64. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/2-j1b74l3lxxu.css +0 -0
  65. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/27jktro2p5rq9.js +0 -0
  66. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/2gj5bmeov-r8f.js +0 -0
  67. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/310vm2bl3xxpt.js +0 -0
  68. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/3n7dm2ojtyzwn.js +0 -0
  69. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/chunks/turbopack-2fblmukzx7kws.js +0 -0
  70. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/4fa387ec64143e14-s.2tuy5pz7dlieh.woff2 +0 -0
  71. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/53b9e256198e5412-s.390ncx5urfkfu.woff2 +0 -0
  72. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/5ce348bf30bf5439-s.31988l_ccedte.woff2 +0 -0
  73. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/6306c77e7c8268e4-s.2dbetqa9o8jxf.woff2 +0 -0
  74. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/7178b3e590c64307-s.21jp631_3pja2.woff2 +0 -0
  75. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/797e433ab948586e-s.p.0r6juujl39pe6.woff2 +0 -0
  76. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/7d817b4c03b0c5f1-s.1uyisp29ctx0d.woff2 +0 -0
  77. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/8a480f0b521d4e75-s.1qq4vpdcun5oj.woff2 +0 -0
  78. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/bbc41e54d2fcbd21-s.1rgnod-3esatf.woff2 +0 -0
  79. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/caa3a2e1cccd8315-s.p.0wgildi0cnwt9.woff2 +0 -0
  80. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/_next/static/media/fef07dbb0973bf53-s.3p2_lha1f2xer.woff2 +0 -0
  81. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/opengraph-image +0 -0
  82. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/_ui/robots.txt +0 -0
  83. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/cli.py +0 -0
  84. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/constants.py +0 -0
  85. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/py.typed +0 -0
  86. {wizardflow-0.2.0 → wizardflow-0.3.0}/src/wizardflow/reader.py +0 -0
  87. {wizardflow-0.2.0 → wizardflow-0.3.0}/tests/conftest.py +0 -0
  88. {wizardflow-0.2.0 → wizardflow-0.3.0}/tests/test_cli.py +0 -0
  89. {wizardflow-0.2.0 → wizardflow-0.3.0}/tests/test_reader.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wizardflow
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Python SDK for recording agent flows into the WizardFlow / AgentTrace file format.
5
5
  Project-URL: Homepage, https://getwizardflow.com
6
6
  Project-URL: Documentation, https://getwizardflow.com
@@ -98,6 +98,8 @@ No runtime dependencies. Developing the SDK itself? See
98
98
  ## Quickstart
99
99
 
100
100
  ```python
101
+ import uuid
102
+
101
103
  import wizardflow
102
104
 
103
105
  wizardflow.init(
@@ -110,10 +112,11 @@ wizardflow.init(
110
112
 
111
113
  # Every log names its message in the first argument:
112
114
  # log(message_id, node, payload_label, payload_value)
113
- wizardflow.log("msg-1", "router", "llm_input", prompt) # same node, two payloads ->
114
- wizardflow.log("msg-1", "router", "llm_output", output) # folded into one step
115
- wizardflow.log("msg-1", "tool_node") # visited, no payloads
116
- wizardflow.end_message("msg-1") # -> writes the trace
115
+ msg_id = str(uuid.uuid4()) # one fresh id per message
116
+ wizardflow.log(msg_id, "router", "llm_input", prompt) # same node, two payloads ->
117
+ wizardflow.log(msg_id, "router", "llm_output", output) # folded into one step
118
+ wizardflow.log(msg_id, "tool_node") # visited, no payloads
119
+ wizardflow.end_message(msg_id) # -> writes the trace
117
120
  ```
118
121
 
119
122
  There is **no `save()`** and no autosave: `log()` only accumulates in memory,
@@ -149,6 +152,82 @@ Pass the **string `id`**, never a handle object — safe to hand to a callback o
149
152
  across threads. A message is created on first reference and finalized by
150
153
  `end_message`; `end_message(id, title="...")` optionally gives it a human title.
151
154
 
155
+ ### Choosing message ids
156
+
157
+ A message is **one unit of work** — one user turn, one run through the graph.
158
+ Its id only has to be unique within the run, and it **cannot be reused** once
159
+ `end_message` has been called on it. The simplest safe choice is a fresh UUID
160
+ per message:
161
+
162
+ ```python
163
+ import uuid
164
+
165
+ msg_id = str(uuid.uuid4())
166
+ ```
167
+
168
+ Do **not** use a session id, user id, or thread id as the message id. Those
169
+ identify a *conversation*, and a conversation contains many messages — after
170
+ the first `end_message(session_id)`, every further `log(session_id, ...)` in
171
+ that session raises, because that "message" has already ended. If you want the
172
+ session visible in the trace, put it in `init(meta=...)` or in the message
173
+ title (`end_message(msg_id, title=...)`) — never in the id. Ids are opaque:
174
+ the viewer only displays and groups by them, so encoding meaning into them
175
+ buys nothing. Hardcoded ids like `"msg-1"` are fine for demo scripts; `uuid4`
176
+ is the right default for real applications.
177
+
178
+ ## One flow, or several at once
179
+
180
+ `init()` installs the client it returns as the module default. With a single
181
+ flow — the common case — **ignore the return value** and call
182
+ `wizardflow.log(...)` / `wizardflow.end_message(...)` directly: they work from
183
+ any module, with no handle to thread through your code.
184
+
185
+ Running several agent flows side by side (say, a doctor flow and a patient
186
+ flow) means several traces, and each needs its own instance. Keep the returned
187
+ client per flow and log through it — and name it **`tracer`**, not `client`,
188
+ since `client` in an agent codebase is almost always the LLM client:
189
+
190
+ ```python
191
+ doctor_tracer = wizardflow.init(file_prefix="doctor", nodes=[...], edges=[...])
192
+ patient_tracer = wizardflow.init(file_prefix="patient", nodes=[...], edges=[...])
193
+
194
+ doctor_tracer.log(doc_msg, "diagnose", "llm_input", prompt)
195
+ patient_tracer.log(pat_msg, "intake", "llm_input", prompt)
196
+ ```
197
+
198
+ With more than one tracer, don't mix in the bare module-level calls:
199
+ `wizardflow.log(...)` always targets the most recently initialized tracer.
200
+
201
+ ## Node descriptions, labels & colors
202
+
203
+ Nodes can carry a short human description of what they do. In the viewer it
204
+ stays out of the way: when a node is selected, a small info icon appears next
205
+ to its name in the inspector — click it to read the description. Nodes without
206
+ one show no icon, and `wizardflow md` / `wizardflow html` list the described
207
+ nodes under the graph.
208
+
209
+ ```python
210
+ wizardflow.init(
211
+ nodes=["router", "retriever", "generator"],
212
+ edges=[("router", "retriever"), ("retriever", "generator")],
213
+ node_descriptions={
214
+ "router": "Chooses the next step.",
215
+ "retriever": "Fetches relevant documents.",
216
+ "generator": "Writes the final answer.",
217
+ },
218
+ )
219
+ ```
220
+
221
+ Two sibling kwargs work the same way: `node_labels` maps ids to the display
222
+ name the viewer shows instead of the raw id (especially useful with
223
+ `init_from_langgraph`, where the extracted ids are your function names), and
224
+ `node_colors` sets accent colors. All three are validated against the declared
225
+ nodes: an unknown id raises a `WizardFlowError` at `init()` time so typos fail
226
+ fast; with `silent=True` it is logged as a warning on the `wizardflow` logger
227
+ and skipped instead. All three also work on `init_from_langgraph`, where they
228
+ attach to the extracted node ids — `log()` always targets the **id**, never
229
+ the label.
230
+
152
231
  ## LangGraph: automatic topology
153
232
 
154
233
  Instead of listing `nodes`/`edges` by hand, read them straight from a compiled
@@ -180,8 +259,8 @@ wizardflow.init_from_langgraph(
180
259
  ```
181
260
 
182
261
  By default, a color key that does not match an extracted node id raises a
183
- `WizardFlowError` so typos fail fast. With `silent=True`, unknown color keys are
184
- ignored.
262
+ `WizardFlowError` so typos fail fast. With `silent=True`, unknown color keys
263
+ are skipped and logged as a warning instead.
185
264
 
186
265
  It extracts node ids (keeping `__start__` / `__end__`) and directed edges, and
187
266
  marks runtime branches with `"conditional": true` (deterministic and parallel
@@ -202,23 +281,23 @@ A non-LangGraph object raises `LangGraphExtractionError`; missing conditional
202
281
  metadata never fails extraction (the edge is just emitted plain). Call it
203
282
  **after `compile()`**, when the topology actually exists.
204
283
 
205
- ## API (v0.2)
284
+ ## API
206
285
 
207
- > **Breaking change in 0.2:** traces are now JSON Lines (`.jsonl`), written by
208
- > appending — the old single-document `.json` format is gone from the SDK
209
- > (writer *and* CLI readers). The web UI at getwizardflow.com still opens old
210
- > `.json` traces.
211
-
212
- - `init(output_dir=, file_prefix="wizardflow", name=, description=, nodes=, edges=, meta=, silent=False, max_bytes=16_000_000, max_messages=2_000) -> Client`
286
+ - `init(output_dir=, file_prefix="wizardflow", name=, description=, nodes=, edges=, node_labels=, node_colors=, node_descriptions=, meta=, silent=False, max_bytes=16_000_000, max_messages=2_000) -> Client`
213
287
  - `description` lands in `meta.description` (matches the schema field).
214
288
  - `nodes=` enables fast-fail: `log()` to an undeclared node raises
215
289
  `UnknownNodeError` immediately (unless silenced).
290
+ - `node_labels` / `node_colors` / `node_descriptions` map declared node ids
291
+ to a display name / CSS color / short description; an unknown id raises
292
+ unless silenced (then it's logged as a warning and skipped).
216
293
  - `output_dir` is optional; omitted, traces are written in cwd.
217
294
  - `file_prefix` is optional; omitted, filenames start with `wizardflow`.
218
295
  - `max_bytes` / `max_messages` cap each part file before rotation (see below).
219
- - `init_from_langgraph(app, output_dir=, file_prefix="wizardflow", name=, description=, meta=, node_colors=, silent=False, max_bytes=..., max_messages=...) -> Client`
296
+ - `init_from_langgraph(app, output_dir=, file_prefix="wizardflow", name=, description=, meta=, node_labels=, node_colors=, node_descriptions=, silent=False, max_bytes=..., max_messages=...) -> Client`
220
297
  - same as `init`, but `nodes`/`edges` come from `app.get_graph()`.
221
- - `node_colors` maps extracted node ids to CSS colors such as `"#A78BFA"`.
298
+ - `node_labels` renames extracted ids for display (they're your function
299
+ names); `node_colors` maps them to CSS colors such as `"#A78BFA"`;
300
+ `node_descriptions` to short descriptions.
222
301
  - `log(id, node, label=None, content=None)` — the first positional is the
223
302
  **message id**, the second is the node. With `label`/`content` it records a
224
303
  payload; bare `log(id, "node")` records a visit with no payloads. The message
@@ -226,6 +305,13 @@ metadata never fails extraction (the edge is just emitted plain). Call it
226
305
  - `end_message(id, title=None)` — finalize a message and append it to the
227
306
  trace; returns the current trace path. The **only** call that touches disk.
228
307
  Optional `title` sets the message's human title. Idempotent.
308
+ - `reinit(name=None, description=None, meta=None)` — start a **new trace
309
+ file** (fresh timestamped name), keeping the graph and output configuration.
310
+ Use it at natural boundaries of a long-lived process — a new user session, a
311
+ new day. The old file is left as-is (**no seal**: it's a finished run, not a
312
+ rotated part). Open messages carry over and are written wherever they end;
313
+ completed message ids become reusable. `name`/`description`/`meta` replace
314
+ the current values when given. Returns the new trace path.
229
315
  - `Client.current_path` — the trace file currently being written.
230
316
  - `to_dict()` / `to_json()` — inspect the active part (completed messages),
231
317
  assembled into one `AgentTraceFile` object.
@@ -251,6 +337,10 @@ unparseable final line (a crash mid-append leaves a torn tail; everything
251
337
  before it is intact). Only **completed** messages are written; an in-progress
252
338
  message lives in memory until it ends.
253
339
 
340
+ > Early SDK versions (0.1) wrote a trace as one single-document `.json` file
341
+ > instead. Newer versions write JSONL only, but every reader — the CLI
342
+ > subcommands and the web UI at getwizardflow.com — still opens both formats.
343
+
254
344
  ### How saving works
255
345
 
256
346
  `end_message` **appends one line** to the active part — O(1) no matter how
@@ -312,6 +402,20 @@ Consecutive `log()` calls to the **same** node within a message fold into a
312
402
  single step with multiple payloads (e.g. a router step carrying both
313
403
  `llm_input` and `llm_output`). A `log()` to a different node starts a new step.
314
404
 
405
+ ## What to log (conventions)
406
+
407
+ Payload labels are free-form strings — the schema reserves none of them. These
408
+ conventions just keep traces consistent and readable:
409
+
410
+ - **LLM-backed nodes** — log the exact prompt as `llm_input` and the raw
411
+ completion as `llm_output`. When a run goes wrong, the trace then shows
412
+ precisely what the model saw and what it said — most of what you need to
413
+ debug an agent — and step folding merges the pair into one step.
414
+ - **Everything else** — log the node's real domain data under honest labels: a
415
+ retriever logs its `query` and `results`, a tool node `tool_input` and
416
+ `tool_output`, a deterministic router its `decision`. Don't force
417
+ `llm_input`/`llm_output` onto nodes that never call a model.
418
+
315
419
  ## Examples
316
420
 
317
421
  Fuller runnable examples live in
@@ -51,6 +51,8 @@ No runtime dependencies. Developing the SDK itself? See
51
51
  ## Quickstart
52
52
 
53
53
  ```python
54
+ import uuid
55
+
54
56
  import wizardflow
55
57
 
56
58
  wizardflow.init(
@@ -63,10 +65,11 @@ wizardflow.init(
63
65
 
64
66
  # Every log names its message in the first argument:
65
67
  # log(message_id, node, payload_label, payload_value)
66
- wizardflow.log("msg-1", "router", "llm_input", prompt) # same node, two payloads ->
67
- wizardflow.log("msg-1", "router", "llm_output", output) # folded into one step
68
- wizardflow.log("msg-1", "tool_node") # visited, no payloads
69
- wizardflow.end_message("msg-1") # -> writes the trace
68
+ msg_id = str(uuid.uuid4()) # one fresh id per message
69
+ wizardflow.log(msg_id, "router", "llm_input", prompt) # same node, two payloads ->
70
+ wizardflow.log(msg_id, "router", "llm_output", output) # folded into one step
71
+ wizardflow.log(msg_id, "tool_node") # visited, no payloads
72
+ wizardflow.end_message(msg_id) # -> writes the trace
70
73
  ```
71
74
 
72
75
  There is **no `save()`** and no autosave: `log()` only accumulates in memory,
@@ -102,6 +105,82 @@ Pass the **string `id`**, never a handle object — safe to hand to a callback o
102
105
  across threads. A message is created on first reference and finalized by
103
106
  `end_message`; `end_message(id, title="...")` optionally gives it a human title.
104
107
 
108
+ ### Choosing message ids
109
+
110
+ A message is **one unit of work** — one user turn, one run through the graph.
111
+ Its id only has to be unique within the run, and it **cannot be reused** once
112
+ `end_message` has been called on it. The simplest safe choice is a fresh UUID
113
+ per message:
114
+
115
+ ```python
116
+ import uuid
117
+
118
+ msg_id = str(uuid.uuid4())
119
+ ```
120
+
121
+ Do **not** use a session id, user id, or thread id as the message id. Those
122
+ identify a *conversation*, and a conversation contains many messages — after
123
+ the first `end_message(session_id)`, every further `log(session_id, ...)` in
124
+ that session raises, because that "message" has already ended. If you want the
125
+ session visible in the trace, put it in `init(meta=...)` or in the message
126
+ title (`end_message(msg_id, title=...)`) — never in the id. Ids are opaque:
127
+ the viewer only displays and groups by them, so encoding meaning into them
128
+ buys nothing. Hardcoded ids like `"msg-1"` are fine for demo scripts; `uuid4`
129
+ is the right default for real applications.
130
+
131
+ ## One flow, or several at once
132
+
133
+ `init()` installs the client it returns as the module default. With a single
134
+ flow — the common case — **ignore the return value** and call
135
+ `wizardflow.log(...)` / `wizardflow.end_message(...)` directly: they work from
136
+ any module, with no handle to thread through your code.
137
+
138
+ Running several agent flows side by side (say, a doctor flow and a patient
139
+ flow) means several traces, and each needs its own instance. Keep the returned
140
+ client per flow and log through it — and name it **`tracer`**, not `client`,
141
+ since `client` in an agent codebase is almost always the LLM client:
142
+
143
+ ```python
144
+ doctor_tracer = wizardflow.init(file_prefix="doctor", nodes=[...], edges=[...])
145
+ patient_tracer = wizardflow.init(file_prefix="patient", nodes=[...], edges=[...])
146
+
147
+ doctor_tracer.log(doc_msg, "diagnose", "llm_input", prompt)
148
+ patient_tracer.log(pat_msg, "intake", "llm_input", prompt)
149
+ ```
150
+
151
+ With more than one tracer, don't mix in the bare module-level calls:
152
+ `wizardflow.log(...)` always targets the most recently initialized tracer.
153
+
154
+ ## Node descriptions, labels & colors
155
+
156
+ Nodes can carry a short human description of what they do. In the viewer it
157
+ stays out of the way: when a node is selected, a small info icon appears next
158
+ to its name in the inspector — click it to read the description. Nodes without
159
+ one show no icon, and `wizardflow md` / `wizardflow html` list the described
160
+ nodes under the graph.
161
+
162
+ ```python
163
+ wizardflow.init(
164
+ nodes=["router", "retriever", "generator"],
165
+ edges=[("router", "retriever"), ("retriever", "generator")],
166
+ node_descriptions={
167
+ "router": "Chooses the next step.",
168
+ "retriever": "Fetches relevant documents.",
169
+ "generator": "Writes the final answer.",
170
+ },
171
+ )
172
+ ```
173
+
174
+ Two sibling kwargs work the same way: `node_labels` maps ids to the display
175
+ name the viewer shows instead of the raw id (especially useful with
176
+ `init_from_langgraph`, where the extracted ids are your function names), and
177
+ `node_colors` sets accent colors. All three are validated against the declared
178
+ nodes: an unknown id raises a `WizardFlowError` at `init()` time so typos fail
179
+ fast; with `silent=True` it is logged as a warning on the `wizardflow` logger
180
+ and skipped instead. All three also work on `init_from_langgraph`, where they
181
+ attach to the extracted node ids — `log()` always targets the **id**, never
182
+ the label.
183
+
105
184
  ## LangGraph: automatic topology
106
185
 
107
186
  Instead of listing `nodes`/`edges` by hand, read them straight from a compiled
@@ -133,8 +212,8 @@ wizardflow.init_from_langgraph(
133
212
  ```
134
213
 
135
214
  By default, a color key that does not match an extracted node id raises a
136
- `WizardFlowError` so typos fail fast. With `silent=True`, unknown color keys are
137
- ignored.
215
+ `WizardFlowError` so typos fail fast. With `silent=True`, unknown color keys
216
+ are skipped and logged as a warning instead.
138
217
 
139
218
  It extracts node ids (keeping `__start__` / `__end__`) and directed edges, and
140
219
  marks runtime branches with `"conditional": true` (deterministic and parallel
@@ -155,23 +234,23 @@ A non-LangGraph object raises `LangGraphExtractionError`; missing conditional
155
234
  metadata never fails extraction (the edge is just emitted plain). Call it
156
235
  **after `compile()`**, when the topology actually exists.
157
236
 
158
- ## API (v0.2)
237
+ ## API
159
238
 
160
- > **Breaking change in 0.2:** traces are now JSON Lines (`.jsonl`), written by
161
- > appending — the old single-document `.json` format is gone from the SDK
162
- > (writer *and* CLI readers). The web UI at getwizardflow.com still opens old
163
- > `.json` traces.
164
-
165
- - `init(output_dir=, file_prefix="wizardflow", name=, description=, nodes=, edges=, meta=, silent=False, max_bytes=16_000_000, max_messages=2_000) -> Client`
239
+ - `init(output_dir=, file_prefix="wizardflow", name=, description=, nodes=, edges=, node_labels=, node_colors=, node_descriptions=, meta=, silent=False, max_bytes=16_000_000, max_messages=2_000) -> Client`
166
240
  - `description` lands in `meta.description` (matches the schema field).
167
241
  - `nodes=` enables fast-fail: `log()` to an undeclared node raises
168
242
  `UnknownNodeError` immediately (unless silenced).
243
+ - `node_labels` / `node_colors` / `node_descriptions` map declared node ids
244
+ to a display name / CSS color / short description; an unknown id raises
245
+ unless silenced (then it's logged as a warning and skipped).
169
246
  - `output_dir` is optional; omitted, traces are written in cwd.
170
247
  - `file_prefix` is optional; omitted, filenames start with `wizardflow`.
171
248
  - `max_bytes` / `max_messages` cap each part file before rotation (see below).
172
- - `init_from_langgraph(app, output_dir=, file_prefix="wizardflow", name=, description=, meta=, node_colors=, silent=False, max_bytes=..., max_messages=...) -> Client`
249
+ - `init_from_langgraph(app, output_dir=, file_prefix="wizardflow", name=, description=, meta=, node_labels=, node_colors=, node_descriptions=, silent=False, max_bytes=..., max_messages=...) -> Client`
173
250
  - same as `init`, but `nodes`/`edges` come from `app.get_graph()`.
174
- - `node_colors` maps extracted node ids to CSS colors such as `"#A78BFA"`.
251
+ - `node_labels` renames extracted ids for display (they're your function
252
+ names); `node_colors` maps them to CSS colors such as `"#A78BFA"`;
253
+ `node_descriptions` to short descriptions.
175
254
  - `log(id, node, label=None, content=None)` — the first positional is the
176
255
  **message id**, the second is the node. With `label`/`content` it records a
177
256
  payload; bare `log(id, "node")` records a visit with no payloads. The message
@@ -179,6 +258,13 @@ metadata never fails extraction (the edge is just emitted plain). Call it
179
258
  - `end_message(id, title=None)` — finalize a message and append it to the
180
259
  trace; returns the current trace path. The **only** call that touches disk.
181
260
  Optional `title` sets the message's human title. Idempotent.
261
+ - `reinit(name=None, description=None, meta=None)` — start a **new trace
262
+ file** (fresh timestamped name), keeping the graph and output configuration.
263
+ Use it at natural boundaries of a long-lived process — a new user session, a
264
+ new day. The old file is left as-is (**no seal**: it's a finished run, not a
265
+ rotated part). Open messages carry over and are written wherever they end;
266
+ completed message ids become reusable. `name`/`description`/`meta` replace
267
+ the current values when given. Returns the new trace path.
182
268
  - `Client.current_path` — the trace file currently being written.
183
269
  - `to_dict()` / `to_json()` — inspect the active part (completed messages),
184
270
  assembled into one `AgentTraceFile` object.
@@ -204,6 +290,10 @@ unparseable final line (a crash mid-append leaves a torn tail; everything
204
290
  before it is intact). Only **completed** messages are written; an in-progress
205
291
  message lives in memory until it ends.
206
292
 
293
+ > Early SDK versions (0.1) wrote a trace as one single-document `.json` file
294
+ > instead. Newer versions write JSONL only, but every reader — the CLI
295
+ > subcommands and the web UI at getwizardflow.com — still opens both formats.
296
+
207
297
  ### How saving works
208
298
 
209
299
  `end_message` **appends one line** to the active part — O(1) no matter how
@@ -265,6 +355,20 @@ Consecutive `log()` calls to the **same** node within a message fold into a
265
355
  single step with multiple payloads (e.g. a router step carrying both
266
356
  `llm_input` and `llm_output`). A `log()` to a different node starts a new step.
267
357
 
358
+ ## What to log (conventions)
359
+
360
+ Payload labels are free-form strings — the schema reserves none of them. These
361
+ conventions just keep traces consistent and readable:
362
+
363
+ - **LLM-backed nodes** — log the exact prompt as `llm_input` and the raw
364
+ completion as `llm_output`. When a run goes wrong, the trace then shows
365
+ precisely what the model saw and what it said — most of what you need to
366
+ debug an agent — and step folding merges the pair into one step.
367
+ - **Everything else** — log the node's real domain data under honest labels: a
368
+ retriever logs its `query` and `results`, a tool node `tool_input` and
369
+ `tool_output`, a deterministic router its `decision`. Don't force
370
+ `llm_input`/`llm_output` onto nodes that never call a model.
371
+
268
372
  ## Examples
269
373
 
270
374
  Fuller runnable examples live in
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "wizardflow"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Python SDK for recording agent flows into the WizardFlow / AgentTrace file format."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -42,6 +42,7 @@ logging.getLogger(Logging.LOGGER_NAME).addHandler(logging.NullHandler())
42
42
  __all__ = [
43
43
  "init",
44
44
  "init_from_langgraph",
45
+ "reinit",
45
46
  "log",
46
47
  "end_message",
47
48
  "to_dict",
@@ -63,6 +64,9 @@ def init(
63
64
  description: Optional[str] = None,
64
65
  nodes: Optional[Iterable[NodeSpec]] = None,
65
66
  edges: Optional[Iterable[EdgeSpec]] = None,
67
+ node_labels: Optional[Mapping[str, str]] = None,
68
+ node_colors: Optional[Mapping[str, str]] = None,
69
+ node_descriptions: Optional[Mapping[str, str]] = None,
66
70
  meta: Optional[Dict[str, Any]] = None,
67
71
  silent: bool = False,
68
72
  max_bytes: int = Rotation.DEFAULT_MAX_BYTES,
@@ -77,6 +81,9 @@ def init(
77
81
  description=description,
78
82
  nodes=nodes,
79
83
  edges=edges,
84
+ node_labels=node_labels,
85
+ node_colors=node_colors,
86
+ node_descriptions=node_descriptions,
80
87
  meta=meta,
81
88
  silent=silent,
82
89
  max_bytes=max_bytes,
@@ -92,7 +99,9 @@ def init_from_langgraph(
92
99
  name: Optional[str] = None,
93
100
  description: Optional[str] = None,
94
101
  meta: Optional[Dict[str, Any]] = None,
102
+ node_labels: Optional[Mapping[str, str]] = None,
95
103
  node_colors: Optional[Mapping[str, str]] = None,
104
+ node_descriptions: Optional[Mapping[str, str]] = None,
96
105
  silent: bool = False,
97
106
  max_bytes: int = Rotation.DEFAULT_MAX_BYTES,
98
107
  max_messages: int = Rotation.DEFAULT_MAX_MESSAGES,
@@ -110,7 +119,9 @@ def init_from_langgraph(
110
119
  name=name,
111
120
  description=description,
112
121
  meta=meta,
122
+ node_labels=node_labels,
113
123
  node_colors=node_colors,
124
+ node_descriptions=node_descriptions,
114
125
  silent=silent,
115
126
  max_bytes=max_bytes,
116
127
  max_messages=max_messages,
@@ -126,6 +137,15 @@ def get_default() -> Client:
126
137
 
127
138
  # --- module-level delegation to the default client ------------------------
128
139
 
140
+ def reinit(
141
+ name: Optional[str] = None,
142
+ description: Optional[str] = None,
143
+ meta: Optional[Dict[str, Any]] = None,
144
+ ) -> str:
145
+ """Start a new trace file on the default client (see :meth:`Client.reinit`)."""
146
+ return get_default().reinit(name=name, description=description, meta=meta)
147
+
148
+
129
149
  def log(
130
150
  id: str,
131
151
  node: str,
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html><html lang="en" class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/18clj6xsyhc_j.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/310vm2bl3xxpt.js"/><script src="/_next/static/chunks/09s72r58ijxwx.js" async=""></script><script src="/_next/static/chunks/3n7dm2ojtyzwn.js" async=""></script><script src="/_next/static/chunks/2gj5bmeov-r8f.js" async=""></script><script src="/_next/static/chunks/27jktro2p5rq9.js" async=""></script><script src="/_next/static/chunks/turbopack-2fblmukzx7kws.js" async=""></script><script src="/_next/static/chunks/142r2alz4_x6t.js" async=""></script><script src="/_next/static/chunks/0ux_7aev0a2kt.js" async=""></script><script src="/_next/static/chunks/05-c3ty_6dwfk.js" async=""></script><script src="/_next/static/chunks/14mrh2-p_w84d.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>WizardFlow — Replay and inspect agent flows</title><meta name="description" content="WizardFlow is a browser-based viewer for agent runs. Upload a trace file to replay an agent flow step by step — message timeline, ordered node execution, live graph activity, and full payload inspection. Everything runs locally; no data leaves your browser."/><meta name="application-name" content="WizardFlow"/><link rel="author" href="https://github.com/lkleonk"/><meta name="author" content="Leon Koch"/><meta name="keywords" content="agent flow,LLM agent,agent visualization,agent debugging,agent observability,LangGraph,agent trace viewer,flow replay,node graph,payload inspection"/><meta name="creator" content="Leon Koch"/><meta name="robots" content="index, follow"/><meta name="googlebot" content="index, follow, max-video-preview:-1, max-image-preview:large, max-snippet:-1"/><link rel="canonical" href="https://getwizardflow.com"/><meta property="og:title" content="WizardFlow — Replay and inspect agent flows"/><meta property="og:description" content="WizardFlow is a browser-based viewer for agent runs. Upload a trace file to replay an agent flow step by step — message timeline, ordered node execution, live graph activity, and full payload inspection. Everything runs locally; no data leaves your browser."/><meta property="og:url" content="https://getwizardflow.com"/><meta property="og:site_name" content="WizardFlow"/><meta property="og:locale" content="en_US"/><meta property="og:image" content="https://getwizardflow.com/opengraph-image?c0f3b66bb21d844d"/><meta property="og:image:type" content="image/png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="WizardFlow — Replay and inspect agent flows"/><meta property="og:type" content="website"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:title" content="WizardFlow — Replay and inspect agent flows"/><meta name="twitter:description" content="WizardFlow is a browser-based viewer for agent runs. Upload a trace file to replay an agent flow step by step — message timeline, ordered node execution, live graph activity, and full payload inspection. Everything runs locally; no data leaves your browser."/><meta name="twitter:image" content="https://getwizardflow.com/opengraph-image?c0f3b66bb21d844d"/><meta name="twitter:image:alt" content="WizardFlow — Replay and inspect agent flows"/><meta name="twitter:image:type" content="image/png"/><meta name="twitter:image:width" content="1200"/><meta name="twitter:image:height" content="630"/><link rel="icon" href="/icon.svg?icon.09qublg69ek7b.svg" sizes="any" type="image/svg+xml"/><script src="/_next/static/chunks/0cz1d0mv5g_q7.js" noModule=""></script><style data-emotion="mui-global 11d272x">html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;box-sizing:border-box;-webkit-text-size-adjust:100%;}*,*::before,*::after{box-sizing:inherit;}strong,b{font-weight:700;}body{margin:0;color:var(--mui-palette-text-primary);font-family:var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;font-weight:400;font-size:0.9285714285714286rem;line-height:1.5;background-color:var(--mui-palette-background-default);}@media print{body{background-color:var(--mui-palette-common-white);}}body::backdrop{background-color:var(--mui-palette-background-default);}</style><style data-emotion="mui-global kfimoy">:root{--mui-spacing:8px;--mui-shape-borderRadius:8px;--mui-shadows-0:none;--mui-shadows-1:0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12);--mui-shadows-2:0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12);--mui-shadows-3:0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12);--mui-shadows-4:0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);--mui-shadows-5:0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12);--mui-shadows-6:0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12);--mui-shadows-7:0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12);--mui-shadows-8:0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12);--mui-shadows-9:0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12);--mui-shadows-10:0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12);--mui-shadows-11:0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12);--mui-shadows-12:0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12);--mui-shadows-13:0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12);--mui-shadows-14:0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12);--mui-shadows-15:0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12);--mui-shadows-16:0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12);--mui-shadows-17:0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12);--mui-shadows-18:0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12);--mui-shadows-19:0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12);--mui-shadows-20:0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12);--mui-shadows-21:0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12);--mui-shadows-22:0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12);--mui-shadows-23:0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12);--mui-shadows-24:0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12);--mui-zIndex-mobileStepper:1000;--mui-zIndex-fab:1050;--mui-zIndex-speedDial:1050;--mui-zIndex-appBar:1100;--mui-zIndex-drawer:1200;--mui-zIndex-modal:1300;--mui-zIndex-snackbar:1400;--mui-zIndex-tooltip:1500;--mui-font-h1:300 5.571428571428571rem/1.167 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-h2:300 3.482142857142857rem/1.2 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-h3:400 2.7857142857142856rem/1.167 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-h4:400 1.9732142857142858rem/1.235 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-h5:400 1.3928571428571428rem/1.334 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-h6:500 1.1607142857142858rem/1.6 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-subtitle1:400 0.9285714285714286rem/1.75 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-subtitle2:500 0.8125rem/1.57 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-body1:400 0.9285714285714286rem/1.5 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-body2:400 0.8125rem/1.43 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-button:500 0.8125rem/1.75 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-caption:400 0.6964285714285714rem/1.66 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-overline:400 0.6964285714285714rem/2.66 var(--font-geist-sans),system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mui-font-inherit:inherit inherit/inherit inherit;}[data-mui-color-scheme="dark"]{--mui-overlays-0:none;--mui-overlays-1:linear-gradient(rgba(255 255 255 / 0.051), rgba(255 255 255 / 0.051));--mui-overlays-2:linear-gradient(rgba(255 255 255 / 0.069), rgba(255 255 255 / 0.069));--mui-overlays-3:linear-gradient(rgba(255 255 255 / 0.082), rgba(255 255 255 / 0.082));--mui-overlays-4:linear-gradient(rgba(255 255 255 / 0.092), rgba(255 255 255 / 0.092));--mui-overlays-5:linear-gradient(rgba(255 255 255 / 0.101), rgba(255 255 255 / 0.101));--mui-overlays-6:linear-gradient(rgba(255 255 255 / 0.108), rgba(255 255 255 / 0.108));--mui-overlays-7:linear-gradient(rgba(255 255 255 / 0.114), rgba(255 255 255 / 0.114));--mui-overlays-8:linear-gradient(rgba(255 255 255 / 0.119), rgba(255 255 255 / 0.119));--mui-overlays-9:linear-gradient(rgba(255 255 255 / 0.124), rgba(255 255 255 / 0.124));--mui-overlays-10:linear-gradient(rgba(255 255 255 / 0.128), rgba(255 255 255 / 0.128));--mui-overlays-11:linear-gradient(rgba(255 255 255 / 0.132), rgba(255 255 255 / 0.132));--mui-overlays-12:linear-gradient(rgba(255 255 255 / 0.135), rgba(255 255 255 / 0.135));--mui-overlays-13:linear-gradient(rgba(255 255 255 / 0.139), rgba(255 255 255 / 0.139));--mui-overlays-14:linear-gradient(rgba(255 255 255 / 0.142), rgba(255 255 255 / 0.142));--mui-overlays-15:linear-gradient(rgba(255 255 255 / 0.145), rgba(255 255 255 / 0.145));--mui-overlays-16:linear-gradient(rgba(255 255 255 / 0.147), rgba(255 255 255 / 0.147));--mui-overlays-17:linear-gradient(rgba(255 255 255 / 0.15), rgba(255 255 255 / 0.15));--mui-overlays-18:linear-gradient(rgba(255 255 255 / 0.152), rgba(255 255 255 / 0.152));--mui-overlays-19:linear-gradient(rgba(255 255 255 / 0.155), rgba(255 255 255 / 0.155));--mui-overlays-20:linear-gradient(rgba(255 255 255 / 0.157), rgba(255 255 255 / 0.157));--mui-overlays-21:linear-gradient(rgba(255 255 255 / 0.159), rgba(255 255 255 / 0.159));--mui-overlays-22:linear-gradient(rgba(255 255 255 / 0.161), rgba(255 255 255 / 0.161));--mui-overlays-23:linear-gradient(rgba(255 255 255 / 0.163), rgba(255 255 255 / 0.163));--mui-overlays-24:linear-gradient(rgba(255 255 255 / 0.165), rgba(255 255 255 / 0.165));--mui-palette-AppBar-darkBg:var(--mui-palette-background-paper, #15181D);--mui-palette-AppBar-darkColor:var(--mui-palette-text-primary, #E6E8EB);}:root,[data-mui-color-scheme="dark"]{-webkit-print-color-scheme:dark;color-scheme:dark;--mui-palette-background-default:#0B0D10;--mui-palette-background-paper:#15181D;--mui-palette-background-defaultChannel:11 13 16;--mui-palette-background-paperChannel:21 24 29;--mui-palette-primary-main:#60A5FA;--mui-palette-primary-light:rgb(127, 183, 251);--mui-palette-primary-dark:rgb(67, 115, 175);--mui-palette-primary-contrastText:rgba(0, 0, 0, 0.87);--mui-palette-primary-mainChannel:96 165 250;--mui-palette-primary-lightChannel:127 183 251;--mui-palette-primary-darkChannel:67 115 175;--mui-palette-primary-contrastTextChannel:0 0 0;--mui-palette-divider:rgba(255, 255, 255, 0.08);--mui-palette-text-primary:#E6E8EB;--mui-palette-text-secondary:#9AA1AB;--mui-palette-text-disabled:rgba(255, 255, 255, 0.5);--mui-palette-text-icon:rgba(255, 255, 255, 0.5);--mui-palette-text-primaryChannel:230 232 235;--mui-palette-text-secondaryChannel:154 161 171;--mui-palette-common-black:#000;--mui-palette-common-white:#fff;--mui-palette-common-background:#000;--mui-palette-common-onBackground:#fff;--mui-palette-common-backgroundChannel:0 0 0;--mui-palette-common-onBackgroundChannel:255 255 255;--mui-palette-secondary-main:#ce93d8;--mui-palette-secondary-light:#f3e5f5;--mui-palette-secondary-dark:#ab47bc;--mui-palette-secondary-contrastText:rgba(0, 0, 0, 0.87);--mui-palette-secondary-mainChannel:206 147 216;--mui-palette-secondary-lightChannel:243 229 245;--mui-palette-secondary-darkChannel:171 71 188;--mui-palette-secondary-contrastTextChannel:0 0 0;--mui-palette-error-main:#f44336;--mui-palette-error-light:#e57373;--mui-palette-error-dark:#d32f2f;--mui-palette-error-contrastText:#fff;--mui-palette-error-mainChannel:244 67 54;--mui-palette-error-lightChannel:229 115 115;--mui-palette-error-darkChannel:211 47 47;--mui-palette-error-contrastTextChannel:255 255 255;--mui-palette-warning-main:#ffa726;--mui-palette-warning-light:#ffb74d;--mui-palette-warning-dark:#f57c00;--mui-palette-warning-contrastText:rgba(0, 0, 0, 0.87);--mui-palette-warning-mainChannel:255 167 38;--mui-palette-warning-lightChannel:255 183 77;--mui-palette-warning-darkChannel:245 124 0;--mui-palette-warning-contrastTextChannel:0 0 0;--mui-palette-info-main:#29b6f6;--mui-palette-info-light:#4fc3f7;--mui-palette-info-dark:#0288d1;--mui-palette-info-contrastText:rgba(0, 0, 0, 0.87);--mui-palette-info-mainChannel:41 182 246;--mui-palette-info-lightChannel:79 195 247;--mui-palette-info-darkChannel:2 136 209;--mui-palette-info-contrastTextChannel:0 0 0;--mui-palette-success-main:#66bb6a;--mui-palette-success-light:#81c784;--mui-palette-success-dark:#388e3c;--mui-palette-success-contrastText:rgba(0, 0, 0, 0.87);--mui-palette-success-mainChannel:102 187 106;--mui-palette-success-lightChannel:129 199 132;--mui-palette-success-darkChannel:56 142 60;--mui-palette-success-contrastTextChannel:0 0 0;--mui-palette-grey-50:#fafafa;--mui-palette-grey-100:#f5f5f5;--mui-palette-grey-200:#eeeeee;--mui-palette-grey-300:#e0e0e0;--mui-palette-grey-400:#bdbdbd;--mui-palette-grey-500:#9e9e9e;--mui-palette-grey-600:#757575;--mui-palette-grey-700:#616161;--mui-palette-grey-800:#424242;--mui-palette-grey-900:#212121;--mui-palette-grey-A100:#f5f5f5;--mui-palette-grey-A200:#eeeeee;--mui-palette-grey-A400:#bdbdbd;--mui-palette-grey-A700:#616161;--mui-palette-action-active:#fff;--mui-palette-action-hover:rgba(255, 255, 255, 0.08);--mui-palette-action-hoverOpacity:0.08;--mui-palette-action-selected:rgba(255, 255, 255, 0.16);--mui-palette-action-selectedOpacity:0.16;--mui-palette-action-disabled:rgba(255, 255, 255, 0.3);--mui-palette-action-disabledBackground:rgba(255, 255, 255, 0.12);--mui-palette-action-disabledOpacity:0.38;--mui-palette-action-focus:rgba(255, 255, 255, 0.12);--mui-palette-action-focusOpacity:0.12;--mui-palette-action-activatedOpacity:0.24;--mui-palette-action-activeChannel:255 255 255;--mui-palette-action-selectedChannel:255 255 255;--mui-palette-Alert-errorColor:rgb(244, 199, 199);--mui-palette-Alert-infoColor:rgb(184, 231, 251);--mui-palette-Alert-successColor:rgb(204, 232, 205);--mui-palette-Alert-warningColor:rgb(255, 226, 183);--mui-palette-Alert-errorFilledBg:var(--mui-palette-error-dark, #d32f2f);--mui-palette-Alert-infoFilledBg:var(--mui-palette-info-dark, #0288d1);--mui-palette-Alert-successFilledBg:var(--mui-palette-success-dark, #388e3c);--mui-palette-Alert-warningFilledBg:var(--mui-palette-warning-dark, #f57c00);--mui-palette-Alert-errorFilledColor:#fff;--mui-palette-Alert-infoFilledColor:#fff;--mui-palette-Alert-successFilledColor:#fff;--mui-palette-Alert-warningFilledColor:rgba(0, 0, 0, 0.87);--mui-palette-Alert-errorStandardBg:rgb(22, 11, 11);--mui-palette-Alert-infoStandardBg:rgb(7, 19, 24);--mui-palette-Alert-successStandardBg:rgb(12, 19, 13);--mui-palette-Alert-warningStandardBg:rgb(25, 18, 7);--mui-palette-Alert-errorIconColor:var(--mui-palette-error-main, #f44336);--mui-palette-Alert-infoIconColor:var(--mui-palette-info-main, #29b6f6);--mui-palette-Alert-successIconColor:var(--mui-palette-success-main, #66bb6a);--mui-palette-Alert-warningIconColor:var(--mui-palette-warning-main, #ffa726);--mui-palette-AppBar-defaultBg:var(--mui-palette-grey-900, #212121);--mui-palette-Avatar-defaultBg:var(--mui-palette-grey-600, #757575);--mui-palette-Button-inheritContainedBg:var(--mui-palette-grey-800, #424242);--mui-palette-Button-inheritContainedHoverBg:var(--mui-palette-grey-700, #616161);--mui-palette-Chip-defaultBorder:var(--mui-palette-grey-700, #616161);--mui-palette-Chip-defaultAvatarColor:var(--mui-palette-grey-300, #e0e0e0);--mui-palette-Chip-defaultIconColor:var(--mui-palette-grey-300, #e0e0e0);--mui-palette-FilledInput-bg:rgba(255, 255, 255, 0.09);--mui-palette-FilledInput-hoverBg:rgba(255, 255, 255, 0.13);--mui-palette-FilledInput-disabledBg:rgba(255, 255, 255, 0.12);--mui-palette-LinearProgress-primaryBg:rgb(48, 82, 125);--mui-palette-LinearProgress-secondaryBg:rgb(103, 73, 108);--mui-palette-LinearProgress-errorBg:rgb(122, 33, 27);--mui-palette-LinearProgress-infoBg:rgb(20, 91, 123);--mui-palette-LinearProgress-successBg:rgb(51, 93, 53);--mui-palette-LinearProgress-warningBg:rgb(127, 83, 19);--mui-palette-Skeleton-bg:rgba(var(--mui-palette-text-primaryChannel, undefined) / 0.13);--mui-palette-Slider-primaryTrack:rgb(48, 82, 125);--mui-palette-Slider-secondaryTrack:rgb(103, 73, 108);--mui-palette-Slider-errorTrack:rgb(122, 33, 27);--mui-palette-Slider-infoTrack:rgb(20, 91, 123);--mui-palette-Slider-successTrack:rgb(51, 93, 53);--mui-palette-Slider-warningTrack:rgb(127, 83, 19);--mui-palette-SnackbarContent-bg:rgb(250, 250, 250);--mui-palette-SnackbarContent-color:rgba(0, 0, 0, 0.87);--mui-palette-SpeedDialAction-fabHoverBg:rgb(56, 58, 62);--mui-palette-StepConnector-border:var(--mui-palette-grey-600, #757575);--mui-palette-StepContent-border:var(--mui-palette-grey-600, #757575);--mui-palette-Switch-defaultColor:var(--mui-palette-grey-300, #e0e0e0);--mui-palette-Switch-defaultDisabledColor:var(--mui-palette-grey-600, #757575);--mui-palette-Switch-primaryDisabledColor:rgb(43, 74, 112);--mui-palette-Switch-secondaryDisabledColor:rgb(92, 66, 97);--mui-palette-Switch-errorDisabledColor:rgb(109, 30, 24);--mui-palette-Switch-infoDisabledColor:rgb(18, 81, 110);--mui-palette-Switch-successDisabledColor:rgb(45, 84, 47);--mui-palette-Switch-warningDisabledColor:rgb(114, 75, 17);--mui-palette-TableCell-border:rgba(81, 81, 81, 1);--mui-palette-Tooltip-bg:rgba(97, 97, 97, 0.92);--mui-palette-dividerChannel:255 255 255;--mui-opacity-inputPlaceholder:0.5;--mui-opacity-inputUnderline:0.7;--mui-opacity-switchTrackDisabled:0.2;--mui-opacity-switchTrack:0.3;}[data-mui-color-scheme="light"]{-webkit-print-color-scheme:light;color-scheme:light;--mui-palette-common-black:#000;--mui-palette-common-white:#fff;--mui-palette-common-background:#fff;--mui-palette-common-onBackground:#000;--mui-palette-common-backgroundChannel:255 255 255;--mui-palette-common-onBackgroundChannel:0 0 0;--mui-palette-primary-main:#2563EB;--mui-palette-primary-light:rgb(80, 130, 239);--mui-palette-primary-dark:rgb(25, 69, 164);--mui-palette-primary-contrastText:#fff;--mui-palette-primary-mainChannel:37 99 235;--mui-palette-primary-lightChannel:80 130 239;--mui-palette-primary-darkChannel:25 69 164;--mui-palette-primary-contrastTextChannel:255 255 255;--mui-palette-secondary-main:#9c27b0;--mui-palette-secondary-light:#ba68c8;--mui-palette-secondary-dark:#7b1fa2;--mui-palette-secondary-contrastText:#fff;--mui-palette-secondary-mainChannel:156 39 176;--mui-palette-secondary-lightChannel:186 104 200;--mui-palette-secondary-darkChannel:123 31 162;--mui-palette-secondary-contrastTextChannel:255 255 255;--mui-palette-error-main:#d32f2f;--mui-palette-error-light:#ef5350;--mui-palette-error-dark:#c62828;--mui-palette-error-contrastText:#fff;--mui-palette-error-mainChannel:211 47 47;--mui-palette-error-lightChannel:239 83 80;--mui-palette-error-darkChannel:198 40 40;--mui-palette-error-contrastTextChannel:255 255 255;--mui-palette-warning-main:#ed6c02;--mui-palette-warning-light:#ff9800;--mui-palette-warning-dark:#e65100;--mui-palette-warning-contrastText:#fff;--mui-palette-warning-mainChannel:237 108 2;--mui-palette-warning-lightChannel:255 152 0;--mui-palette-warning-darkChannel:230 81 0;--mui-palette-warning-contrastTextChannel:255 255 255;--mui-palette-info-main:#0288d1;--mui-palette-info-light:#03a9f4;--mui-palette-info-dark:#01579b;--mui-palette-info-contrastText:#fff;--mui-palette-info-mainChannel:2 136 209;--mui-palette-info-lightChannel:3 169 244;--mui-palette-info-darkChannel:1 87 155;--mui-palette-info-contrastTextChannel:255 255 255;--mui-palette-success-main:#2e7d32;--mui-palette-success-light:#4caf50;--mui-palette-success-dark:#1b5e20;--mui-palette-success-contrastText:#fff;--mui-palette-success-mainChannel:46 125 50;--mui-palette-success-lightChannel:76 175 80;--mui-palette-success-darkChannel:27 94 32;--mui-palette-success-contrastTextChannel:255 255 255;--mui-palette-grey-50:#fafafa;--mui-palette-grey-100:#f5f5f5;--mui-palette-grey-200:#eeeeee;--mui-palette-grey-300:#e0e0e0;--mui-palette-grey-400:#bdbdbd;--mui-palette-grey-500:#9e9e9e;--mui-palette-grey-600:#757575;--mui-palette-grey-700:#616161;--mui-palette-grey-800:#424242;--mui-palette-grey-900:#212121;--mui-palette-grey-A100:#f5f5f5;--mui-palette-grey-A200:#eeeeee;--mui-palette-grey-A400:#bdbdbd;--mui-palette-grey-A700:#616161;--mui-palette-text-primary:#1A1D21;--mui-palette-text-secondary:#5B636E;--mui-palette-text-disabled:rgba(0, 0, 0, 0.38);--mui-palette-text-primaryChannel:26 29 33;--mui-palette-text-secondaryChannel:91 99 110;--mui-palette-divider:rgba(0, 0, 0, 0.10);--mui-palette-background-paper:#FFFFFF;--mui-palette-background-default:#F6F7F9;--mui-palette-background-defaultChannel:246 247 249;--mui-palette-background-paperChannel:255 255 255;--mui-palette-action-active:rgba(0, 0, 0, 0.54);--mui-palette-action-hover:rgba(0, 0, 0, 0.04);--mui-palette-action-hoverOpacity:0.04;--mui-palette-action-selected:rgba(0, 0, 0, 0.08);--mui-palette-action-selectedOpacity:0.08;--mui-palette-action-disabled:rgba(0, 0, 0, 0.26);--mui-palette-action-disabledBackground:rgba(0, 0, 0, 0.12);--mui-palette-action-disabledOpacity:0.38;--mui-palette-action-focus:rgba(0, 0, 0, 0.12);--mui-palette-action-focusOpacity:0.12;--mui-palette-action-activatedOpacity:0.12;--mui-palette-action-activeChannel:0 0 0;--mui-palette-action-selectedChannel:0 0 0;--mui-palette-Alert-errorColor:rgb(95, 33, 32);--mui-palette-Alert-infoColor:rgb(1, 67, 97);--mui-palette-Alert-successColor:rgb(30, 70, 32);--mui-palette-Alert-warningColor:rgb(102, 60, 0);--mui-palette-Alert-errorFilledBg:var(--mui-palette-error-main, #d32f2f);--mui-palette-Alert-infoFilledBg:var(--mui-palette-info-main, #0288d1);--mui-palette-Alert-successFilledBg:var(--mui-palette-success-main, #2e7d32);--mui-palette-Alert-warningFilledBg:var(--mui-palette-warning-main, #ed6c02);--mui-palette-Alert-errorFilledColor:#fff;--mui-palette-Alert-infoFilledColor:#fff;--mui-palette-Alert-successFilledColor:#fff;--mui-palette-Alert-warningFilledColor:#fff;--mui-palette-Alert-errorStandardBg:rgb(253, 237, 237);--mui-palette-Alert-infoStandardBg:rgb(229, 246, 253);--mui-palette-Alert-successStandardBg:rgb(237, 247, 237);--mui-palette-Alert-warningStandardBg:rgb(255, 244, 229);--mui-palette-Alert-errorIconColor:var(--mui-palette-error-main, #d32f2f);--mui-palette-Alert-infoIconColor:var(--mui-palette-info-main, #0288d1);--mui-palette-Alert-successIconColor:var(--mui-palette-success-main, #2e7d32);--mui-palette-Alert-warningIconColor:var(--mui-palette-warning-main, #ed6c02);--mui-palette-AppBar-defaultBg:var(--mui-palette-grey-100, #f5f5f5);--mui-palette-Avatar-defaultBg:var(--mui-palette-grey-400, #bdbdbd);--mui-palette-Button-inheritContainedBg:var(--mui-palette-grey-300, #e0e0e0);--mui-palette-Button-inheritContainedHoverBg:var(--mui-palette-grey-A100, #f5f5f5);--mui-palette-Chip-defaultBorder:var(--mui-palette-grey-400, #bdbdbd);--mui-palette-Chip-defaultAvatarColor:var(--mui-palette-grey-700, #616161);--mui-palette-Chip-defaultIconColor:var(--mui-palette-grey-700, #616161);--mui-palette-FilledInput-bg:rgba(0, 0, 0, 0.06);--mui-palette-FilledInput-hoverBg:rgba(0, 0, 0, 0.09);--mui-palette-FilledInput-disabledBg:rgba(0, 0, 0, 0.12);--mui-palette-LinearProgress-primaryBg:rgb(172, 195, 247);--mui-palette-LinearProgress-secondaryBg:rgb(217, 172, 224);--mui-palette-LinearProgress-errorBg:rgb(238, 175, 175);--mui-palette-LinearProgress-infoBg:rgb(158, 209, 237);--mui-palette-LinearProgress-successBg:rgb(175, 205, 177);--mui-palette-LinearProgress-warningBg:rgb(248, 199, 158);--mui-palette-Skeleton-bg:rgba(var(--mui-palette-text-primaryChannel, undefined) / 0.11);--mui-palette-Slider-primaryTrack:rgb(172, 195, 247);--mui-palette-Slider-secondaryTrack:rgb(217, 172, 224);--mui-palette-Slider-errorTrack:rgb(238, 175, 175);--mui-palette-Slider-infoTrack:rgb(158, 209, 237);--mui-palette-Slider-successTrack:rgb(175, 205, 177);--mui-palette-Slider-warningTrack:rgb(248, 199, 158);--mui-palette-SnackbarContent-bg:rgb(49, 49, 49);--mui-palette-SnackbarContent-color:#fff;--mui-palette-SpeedDialAction-fabHoverBg:rgb(216, 216, 216);--mui-palette-StepConnector-border:var(--mui-palette-grey-400, #bdbdbd);--mui-palette-StepContent-border:var(--mui-palette-grey-400, #bdbdbd);--mui-palette-Switch-defaultColor:var(--mui-palette-common-white, #fff);--mui-palette-Switch-defaultDisabledColor:var(--mui-palette-grey-100, #f5f5f5);--mui-palette-Switch-primaryDisabledColor:rgb(172, 195, 247);--mui-palette-Switch-secondaryDisabledColor:rgb(217, 172, 224);--mui-palette-Switch-errorDisabledColor:rgb(238, 175, 175);--mui-palette-Switch-infoDisabledColor:rgb(158, 209, 237);--mui-palette-Switch-successDisabledColor:rgb(175, 205, 177);--mui-palette-Switch-warningDisabledColor:rgb(248, 199, 158);--mui-palette-TableCell-border:rgba(224, 224, 224, 1);--mui-palette-Tooltip-bg:rgba(97, 97, 97, 0.92);--mui-palette-dividerChannel:0 0 0;--mui-opacity-inputPlaceholder:0.42;--mui-opacity-inputUnderline:0.42;--mui-opacity-switchTrackDisabled:0.12;--mui-opacity-switchTrack:0.38;}</style></head><body><div hidden=""><!--$--><!--/$--></div><script>(function() {
2
+ try {
3
+ let colorScheme = '';
4
+ const mode = localStorage.getItem('mui-mode') || 'dark';
5
+ const dark = localStorage.getItem('mui-color-scheme-dark') || 'dark';
6
+ const light = localStorage.getItem('mui-color-scheme-light') || 'light';
7
+ if (mode === 'system') {
8
+ // handle system mode
9
+ const mql = window.matchMedia('(prefers-color-scheme: dark)');
10
+ if (mql.matches) {
11
+ colorScheme = dark
12
+ } else {
13
+ colorScheme = light
14
+ }
15
+ }
16
+ if (mode === 'light') {
17
+ colorScheme = light;
18
+ }
19
+ if (mode === 'dark') {
20
+ colorScheme = dark;
21
+ }
22
+ if (colorScheme) {
23
+ document.documentElement.setAttribute('data-mui-color-scheme', colorScheme);
24
+ }
25
+ } catch(e){}})();</script><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/310vm2bl3xxpt.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[44636,[\"/_next/static/chunks/142r2alz4_x6t.js\",\"/_next/static/chunks/0ux_7aev0a2kt.js\"],\"default\"]\n3:I[39756,[\"/_next/static/chunks/05-c3ty_6dwfk.js\",\"/_next/static/chunks/14mrh2-p_w84d.js\"],\"default\"]\n4:I[37457,[\"/_next/static/chunks/05-c3ty_6dwfk.js\",\"/_next/static/chunks/14mrh2-p_w84d.js\"],\"default\"]\n5:I[97367,[\"/_next/static/chunks/05-c3ty_6dwfk.js\",\"/_next/static/chunks/14mrh2-p_w84d.js\"],\"OutletBoundary\"]\n6:\"$Sreact.suspense\"\n9:I[97367,[\"/_next/static/chunks/05-c3ty_6dwfk.js\",\"/_next/static/chunks/14mrh2-p_w84d.js\"],\"ViewportBoundary\"]\nb:I[97367,[\"/_next/static/chunks/05-c3ty_6dwfk.js\",\"/_next/static/chunks/14mrh2-p_w84d.js\"],\"MetadataBoundary\"]\nd:I[68027,[\"/_next/static/chunks/142r2alz4_x6t.js\",\"/_next/static/chunks/0ux_7aev0a2kt.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/18clj6xsyhc_j.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"_not-found\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",16],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/18clj6xsyhc_j.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/142r2alz4_x6t.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0ux_7aev0a2kt.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"suppressHydrationWarning\":true,\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable\",\"children\":[\"$\",\"body\",null,{\"children\":[[[\"$\",\"script\",\"mui-color-scheme-init\",{\"suppressHydrationWarning\":true,\"nonce\":\"$undefined\",\"dangerouslySetInnerHTML\":{\"__html\":\"(function() {\\ntry {\\n let colorScheme = '';\\n const mode = localStorage.getItem('mui-mode') || 'dark';\\n const dark = localStorage.getItem('mui-color-scheme-dark') || 'dark';\\n const light = localStorage.getItem('mui-color-scheme-light') || 'light';\\n if (mode === 'system') {\\n // handle system mode\\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\\n if (mql.matches) {\\n colorScheme = dark\\n } else {\\n colorScheme = light\\n }\\n }\\n if (mode === 'light') {\\n colorScheme = light;\\n }\\n if (mode === 'dark') {\\n colorScheme = dark;\\n }\\n if (colorScheme) {\\n document.documentElement.setAttribute('data-mui-color-scheme', colorScheme);\\n }\\n} catch(e){}})();\"}}]],[\"$\",\"$L2\",null,{\"children\":[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:1:props:children:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L5\",null,{\"children\":[\"$\",\"$6\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@7\"}]}]]}],{},null,false,null]},null,false,\"$@8\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[\"$\",\"$L9\",null,{\"children\":\"$La\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Lb\",null,{\"children\":[\"$\",\"$6\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lc\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/18clj6xsyhc_j.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"AJjiS0WLQjNzSyuZBS0Ff\"}\n"])</script><script>self.__next_f.push([1,"e:[]\n8:\"$We\"\n"])</script><script>self.__next_f.push([1,"a:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"f:I[27201,[\"/_next/static/chunks/05-c3ty_6dwfk.js\",\"/_next/static/chunks/14mrh2-p_w84d.js\"],\"IconMark\"]\n7:null\n"])</script><script>self.__next_f.push([1,"c:[[\"$\",\"title\",\"0\",{\"children\":\"WizardFlow — Replay and inspect agent flows\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"WizardFlow is a browser-based viewer for agent runs. Upload a trace file to replay an agent flow step by step — message timeline, ordered node execution, live graph activity, and full payload inspection. Everything runs locally; no data leaves your browser.\"}],[\"$\",\"meta\",\"2\",{\"name\":\"application-name\",\"content\":\"WizardFlow\"}],[\"$\",\"link\",\"3\",{\"rel\":\"author\",\"href\":\"https://github.com/lkleonk\"}],[\"$\",\"meta\",\"4\",{\"name\":\"author\",\"content\":\"Leon Koch\"}],[\"$\",\"meta\",\"5\",{\"name\":\"keywords\",\"content\":\"agent flow,LLM agent,agent visualization,agent debugging,agent observability,LangGraph,agent trace viewer,flow replay,node graph,payload inspection\"}],[\"$\",\"meta\",\"6\",{\"name\":\"creator\",\"content\":\"Leon Koch\"}],[\"$\",\"meta\",\"7\",{\"name\":\"robots\",\"content\":\"index, follow\"}],[\"$\",\"meta\",\"8\",{\"name\":\"googlebot\",\"content\":\"index, follow, max-video-preview:-1, max-image-preview:large, max-snippet:-1\"}],[\"$\",\"link\",\"9\",{\"rel\":\"canonical\",\"href\":\"https://getwizardflow.com\"}],[\"$\",\"meta\",\"10\",{\"property\":\"og:title\",\"content\":\"WizardFlow — Replay and inspect agent flows\"}],[\"$\",\"meta\",\"11\",{\"property\":\"og:description\",\"content\":\"WizardFlow is a browser-based viewer for agent runs. Upload a trace file to replay an agent flow step by step — message timeline, ordered node execution, live graph activity, and full payload inspection. Everything runs locally; no data leaves your browser.\"}],[\"$\",\"meta\",\"12\",{\"property\":\"og:url\",\"content\":\"https://getwizardflow.com\"}],[\"$\",\"meta\",\"13\",{\"property\":\"og:site_name\",\"content\":\"WizardFlow\"}],[\"$\",\"meta\",\"14\",{\"property\":\"og:locale\",\"content\":\"en_US\"}],[\"$\",\"meta\",\"15\",{\"property\":\"og:image\",\"content\":\"https://getwizardflow.com/opengraph-image?c0f3b66bb21d844d\"}],[\"$\",\"meta\",\"16\",{\"property\":\"og:image:type\",\"content\":\"image/png\"}],[\"$\",\"meta\",\"17\",{\"property\":\"og:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"18\",{\"property\":\"og:image:height\",\"content\":\"630\"}],[\"$\",\"meta\",\"19\",{\"property\":\"og:image:alt\",\"content\":\"WizardFlow — Replay and inspect agent flows\"}],[\"$\",\"meta\",\"20\",{\"property\":\"og:type\",\"content\":\"website\"}],[\"$\",\"meta\",\"21\",{\"name\":\"twitter:card\",\"content\":\"summary_large_image\"}],[\"$\",\"meta\",\"22\",{\"name\":\"twitter:title\",\"content\":\"WizardFlow — Replay and inspect agent flows\"}],[\"$\",\"meta\",\"23\",{\"name\":\"twitter:description\",\"content\":\"WizardFlow is a browser-based viewer for agent runs. Upload a trace file to replay an agent flow step by step — message timeline, ordered node execution, live graph activity, and full payload inspection. Everything runs locally; no data leaves your browser.\"}],[\"$\",\"meta\",\"24\",{\"name\":\"twitter:image\",\"content\":\"https://getwizardflow.com/opengraph-image?c0f3b66bb21d844d\"}],[\"$\",\"meta\",\"25\",{\"name\":\"twitter:image:alt\",\"content\":\"WizardFlow — Replay and inspect agent flows\"}],[\"$\",\"meta\",\"26\",{\"name\":\"twitter:image:type\",\"content\":\"image/png\"}],[\"$\",\"meta\",\"27\",{\"name\":\"twitter:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"28\",{\"name\":\"twitter:image:height\",\"content\":\"630\"}],[\"$\",\"link\",\"29\",{\"rel\":\"icon\",\"href\":\"/icon.svg?icon.09qublg69ek7b.svg\",\"sizes\":\"any\",\"type\":\"image/svg+xml\"}],[\"$\",\"$Lf\",\"30\",{}]]\n"])</script></body></html>
@@ -1,10 +1,10 @@
1
1
  1:"$Sreact.fragment"
2
2
  2:I[47257,["/_next/static/chunks/05-c3ty_6dwfk.js","/_next/static/chunks/14mrh2-p_w84d.js"],"ClientPageRoot"]
3
- 3:I[52683,["/_next/static/chunks/142r2alz4_x6t.js","/_next/static/chunks/0ux_7aev0a2kt.js","/_next/static/chunks/4158u-399exxn.js"],"default"]
3
+ 3:I[52683,["/_next/static/chunks/142r2alz4_x6t.js","/_next/static/chunks/0ux_7aev0a2kt.js","/_next/static/chunks/2q_qu9w0vej6s.js"],"default"]
4
4
  6:I[97367,["/_next/static/chunks/05-c3ty_6dwfk.js","/_next/static/chunks/14mrh2-p_w84d.js"],"OutletBoundary"]
5
5
  7:"$Sreact.suspense"
6
- :HL["/_next/static/chunks/0mz_v1wicwnmn.css","style"]
7
- 0:{"rsc":["$","$1","c",{"children":[["$","$L2",null,{"Component":"$3","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@4","$@5"]}}],[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0mz_v1wicwnmn.css","precedence":"next"}],["$","script","script-0",{"src":"/_next/static/chunks/4158u-399exxn.js","async":true}]],["$","$L6",null,{"children":["$","$7",null,{"name":"Next.MetadataOutlet","children":"$@8"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"F7xCRRyix77IKo6qy-ltF"}
6
+ :HL["/_next/static/chunks/3lt2ss7dftc2n.css","style"]
7
+ 0:{"rsc":["$","$1","c",{"children":[["$","$L2",null,{"Component":"$3","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@4","$@5"]}}],[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/3lt2ss7dftc2n.css","precedence":"next"}],["$","script","script-0",{"src":"/_next/static/chunks/2q_qu9w0vej6s.js","async":true}]],["$","$L6",null,{"children":["$","$7",null,{"name":"Next.MetadataOutlet","children":"$@8"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"AJjiS0WLQjNzSyuZBS0Ff"}
8
8
  4:{}
9
9
  5:"$0:rsc:props:children:0:props:serverProvidedParams:params"
10
10
  8:null