wizardflow 0.3.0__tar.gz → 0.4.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.
- {wizardflow-0.3.0 → wizardflow-0.4.0}/PKG-INFO +18 -7
- {wizardflow-0.3.0 → wizardflow-0.4.0}/README.md +17 -6
- {wizardflow-0.3.0 → wizardflow-0.4.0}/examples/multibranch.html +28 -11
- {wizardflow-0.3.0 → wizardflow-0.4.0}/examples/multibranch.md +21 -11
- {wizardflow-0.3.0 → wizardflow-0.4.0}/examples/multibranch.py +23 -2
- {wizardflow-0.3.0 → wizardflow-0.4.0}/examples/quickstart.html +20 -6
- {wizardflow-0.3.0 → wizardflow-0.4.0}/examples/quickstart.md +12 -6
- {wizardflow-0.3.0 → wizardflow-0.4.0}/examples/quickstart.py +17 -2
- {wizardflow-0.3.0 → wizardflow-0.4.0}/pyproject.toml +1 -1
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/__init__.py +6 -2
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_render.py +9 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/404.html +7 -25
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/__next.__PAGE__.txt +2 -2
- wizardflow-0.4.0/src/wizardflow/_ui/__next._full.txt +23 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/__next._head.txt +1 -1
- wizardflow-0.4.0/src/wizardflow/_ui/__next._index.txt +7 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/__next._tree.txt +1 -1
- wizardflow-0.3.0/src/wizardflow/_ui/_next/static/chunks/0ux_7aev0a2kt.js → wizardflow-0.4.0/src/wizardflow/_ui/_next/static/chunks/07ur0v9hb4ida.js +3 -3
- wizardflow-0.3.0/src/wizardflow/_ui/_next/static/chunks/0u1x9l49cgb30.js → wizardflow-0.4.0/src/wizardflow/_ui/_next/static/chunks/1_way7swvumpv.js +1 -1
- wizardflow-0.4.0/src/wizardflow/_ui/_next/static/chunks/221oy04d3f6t2.js +7 -0
- wizardflow-0.4.0/src/wizardflow/_ui/_next/static/chunks/35wrz4n1txs_o.js +265 -0
- wizardflow-0.4.0/src/wizardflow/_ui/_not-found/__next._full.txt +18 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_not-found/__next._head.txt +1 -1
- wizardflow-0.4.0/src/wizardflow/_ui/_not-found/__next._index.txt +7 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_not-found/__next._not-found/__PAGE__.txt +1 -1
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_not-found/__next._not-found.txt +1 -1
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_not-found/__next._tree.txt +1 -1
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_not-found.html +7 -25
- wizardflow-0.4.0/src/wizardflow/_ui/_not-found.txt +18 -0
- wizardflow-0.4.0/src/wizardflow/_ui/index.html +7 -0
- wizardflow-0.4.0/src/wizardflow/_ui/index.txt +23 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/sitemap.xml +1 -1
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/client.py +20 -7
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/html.py +9 -1
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/markdown.py +6 -1
- {wizardflow-0.3.0 → wizardflow-0.4.0}/tests/test_html.py +23 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/tests/test_markdown.py +21 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/tests/test_reader.py +10 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/tests/test_trace.py +37 -0
- wizardflow-0.3.0/src/wizardflow/_ui/__next._full.txt +0 -22
- wizardflow-0.3.0/src/wizardflow/_ui/__next._index.txt +0 -6
- wizardflow-0.3.0/src/wizardflow/_ui/_next/static/chunks/142r2alz4_x6t.js +0 -1
- wizardflow-0.3.0/src/wizardflow/_ui/_next/static/chunks/2q_qu9w0vej6s.js +0 -115
- wizardflow-0.3.0/src/wizardflow/_ui/_not-found/__next._full.txt +0 -17
- wizardflow-0.3.0/src/wizardflow/_ui/_not-found/__next._index.txt +0 -6
- wizardflow-0.3.0/src/wizardflow/_ui/_not-found.txt +0 -17
- wizardflow-0.3.0/src/wizardflow/_ui/index.html +0 -25
- wizardflow-0.3.0/src/wizardflow/_ui/index.txt +0 -22
- {wizardflow-0.3.0 → wizardflow-0.4.0}/.gitignore +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/CONTRIBUTING.md +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/LICENSE +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/assets/demo.gif +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/examples/data_types.py +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/scripts/build_ui.py +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/05-c3ty_6dwfk.js +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/09s72r58ijxwx.js +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/0cz1d0mv5g_q7.js +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/14mrh2-p_w84d.js +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/18clj6xsyhc_j.css +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/2-j1b74l3lxxu.css +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/27jktro2p5rq9.js +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/2gj5bmeov-r8f.js +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/310vm2bl3xxpt.js +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/3lt2ss7dftc2n.css +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/3n7dm2ojtyzwn.js +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/chunks/turbopack-2fblmukzx7kws.js +0 -0
- {wizardflow-0.3.0/src/wizardflow/_ui/_next/static/AJjiS0WLQjNzSyuZBS0Ff → wizardflow-0.4.0/src/wizardflow/_ui/_next/static/hZT2Q8C4grDYd_BRHVtw0}/_buildManifest.js +0 -0
- {wizardflow-0.3.0/src/wizardflow/_ui/_next/static/AJjiS0WLQjNzSyuZBS0Ff → wizardflow-0.4.0/src/wizardflow/_ui/_next/static/hZT2Q8C4grDYd_BRHVtw0}/_clientMiddlewareManifest.js +0 -0
- {wizardflow-0.3.0/src/wizardflow/_ui/_next/static/AJjiS0WLQjNzSyuZBS0Ff → wizardflow-0.4.0/src/wizardflow/_ui/_next/static/hZT2Q8C4grDYd_BRHVtw0}/_ssgManifest.js +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/4fa387ec64143e14-s.2tuy5pz7dlieh.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/53b9e256198e5412-s.390ncx5urfkfu.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/5ce348bf30bf5439-s.31988l_ccedte.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/6306c77e7c8268e4-s.2dbetqa9o8jxf.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/7178b3e590c64307-s.21jp631_3pja2.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/797e433ab948586e-s.p.0r6juujl39pe6.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/7d817b4c03b0c5f1-s.1uyisp29ctx0d.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/8a480f0b521d4e75-s.1qq4vpdcun5oj.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/bbc41e54d2fcbd21-s.1rgnod-3esatf.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/caa3a2e1cccd8315-s.p.0wgildi0cnwt9.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/fef07dbb0973bf53-s.3p2_lha1f2xer.woff2 +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/_next/static/media/icon.09qublg69ek7b.svg +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/icon.svg +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/opengraph-image +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/_ui/robots.txt +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/cli.py +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/constants.py +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/py.typed +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/src/wizardflow/reader.py +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/tests/conftest.py +0 -0
- {wizardflow-0.3.0 → wizardflow-0.4.0}/tests/test_cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wizardflow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.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
|
|
@@ -57,6 +57,10 @@ runtime dependencies**, no daemon, no setup.
|
|
|
57
57
|
|
|
58
58
|

|
|
59
59
|
|
|
60
|
+
▶ **[Watch this exact run live](https://getwizardflow.com/?example=university-consultant)** —
|
|
61
|
+
the flow from the GIF, replaying in your browser right now. No install, and
|
|
62
|
+
nothing is uploaded.
|
|
63
|
+
|
|
60
64
|
The file it produces is JSON Lines with a small, documented schema: line 1 is a
|
|
61
65
|
`header` record carrying the `graph { nodes, edges }`, then one `message`
|
|
62
66
|
record per line (`steps[] → payloads[] { label, value }`). Every line is plain
|
|
@@ -150,7 +154,11 @@ wizardflow.end_message("msg-2") # writes msg-2
|
|
|
150
154
|
|
|
151
155
|
Pass the **string `id`**, never a handle object — safe to hand to a callback or
|
|
152
156
|
across threads. A message is created on first reference and finalized by
|
|
153
|
-
`end_message`; `end_message(id, title="...")` optionally gives it a human title
|
|
157
|
+
`end_message`; `end_message(id, title="...")` optionally gives it a human title,
|
|
158
|
+
and `end_message(id, meta={...})` attaches flat metadata about the message as a
|
|
159
|
+
whole (outcome, latency, user id, …) — the viewer shows it on the message's
|
|
160
|
+
timeline chip. Keep meta values short scalars; large structured data belongs in
|
|
161
|
+
`log()` payloads.
|
|
154
162
|
|
|
155
163
|
### Choosing message ids
|
|
156
164
|
|
|
@@ -169,8 +177,9 @@ Do **not** use a session id, user id, or thread id as the message id. Those
|
|
|
169
177
|
identify a *conversation*, and a conversation contains many messages — after
|
|
170
178
|
the first `end_message(session_id)`, every further `log(session_id, ...)` in
|
|
171
179
|
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
|
-
|
|
180
|
+
session visible in the trace, put it in `init(meta=...)` or in the message's
|
|
181
|
+
meta (`end_message(msg_id, meta={"session": session_id})`) — never in the id.
|
|
182
|
+
Ids are opaque:
|
|
174
183
|
the viewer only displays and groups by them, so encoding meaning into them
|
|
175
184
|
buys nothing. Hardcoded ids like `"msg-1"` are fine for demo scripts; `uuid4`
|
|
176
185
|
is the right default for real applications.
|
|
@@ -302,9 +311,11 @@ metadata never fails extraction (the edge is just emitted plain). Call it
|
|
|
302
311
|
**message id**, the second is the node. With `label`/`content` it records a
|
|
303
312
|
payload; bare `log(id, "node")` records a visit with no payloads. The message
|
|
304
313
|
is created on first reference; this only accumulates in memory.
|
|
305
|
-
- `end_message(id, title=None)` — finalize a message and append it
|
|
306
|
-
trace; returns the current trace path. The **only** call that touches
|
|
307
|
-
Optional `title` sets the message's human title
|
|
314
|
+
- `end_message(id, title=None, meta=None)` — finalize a message and append it
|
|
315
|
+
to the trace; returns the current trace path. The **only** call that touches
|
|
316
|
+
disk. Optional `title` sets the message's human title; optional `meta` (a
|
|
317
|
+
flat dict of short scalars) attaches message-level metadata shown on the
|
|
318
|
+
message's chip in the viewer. Idempotent.
|
|
308
319
|
- `reinit(name=None, description=None, meta=None)` — start a **new trace
|
|
309
320
|
file** (fresh timestamped name), keeping the graph and output configuration.
|
|
310
321
|
Use it at natural boundaries of a long-lived process — a new user session, a
|
|
@@ -10,6 +10,10 @@ runtime dependencies**, no daemon, no setup.
|
|
|
10
10
|
|
|
11
11
|

|
|
12
12
|
|
|
13
|
+
▶ **[Watch this exact run live](https://getwizardflow.com/?example=university-consultant)** —
|
|
14
|
+
the flow from the GIF, replaying in your browser right now. No install, and
|
|
15
|
+
nothing is uploaded.
|
|
16
|
+
|
|
13
17
|
The file it produces is JSON Lines with a small, documented schema: line 1 is a
|
|
14
18
|
`header` record carrying the `graph { nodes, edges }`, then one `message`
|
|
15
19
|
record per line (`steps[] → payloads[] { label, value }`). Every line is plain
|
|
@@ -103,7 +107,11 @@ wizardflow.end_message("msg-2") # writes msg-2
|
|
|
103
107
|
|
|
104
108
|
Pass the **string `id`**, never a handle object — safe to hand to a callback or
|
|
105
109
|
across threads. A message is created on first reference and finalized by
|
|
106
|
-
`end_message`; `end_message(id, title="...")` optionally gives it a human title
|
|
110
|
+
`end_message`; `end_message(id, title="...")` optionally gives it a human title,
|
|
111
|
+
and `end_message(id, meta={...})` attaches flat metadata about the message as a
|
|
112
|
+
whole (outcome, latency, user id, …) — the viewer shows it on the message's
|
|
113
|
+
timeline chip. Keep meta values short scalars; large structured data belongs in
|
|
114
|
+
`log()` payloads.
|
|
107
115
|
|
|
108
116
|
### Choosing message ids
|
|
109
117
|
|
|
@@ -122,8 +130,9 @@ Do **not** use a session id, user id, or thread id as the message id. Those
|
|
|
122
130
|
identify a *conversation*, and a conversation contains many messages — after
|
|
123
131
|
the first `end_message(session_id)`, every further `log(session_id, ...)` in
|
|
124
132
|
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
|
-
|
|
133
|
+
session visible in the trace, put it in `init(meta=...)` or in the message's
|
|
134
|
+
meta (`end_message(msg_id, meta={"session": session_id})`) — never in the id.
|
|
135
|
+
Ids are opaque:
|
|
127
136
|
the viewer only displays and groups by them, so encoding meaning into them
|
|
128
137
|
buys nothing. Hardcoded ids like `"msg-1"` are fine for demo scripts; `uuid4`
|
|
129
138
|
is the right default for real applications.
|
|
@@ -255,9 +264,11 @@ metadata never fails extraction (the edge is just emitted plain). Call it
|
|
|
255
264
|
**message id**, the second is the node. With `label`/`content` it records a
|
|
256
265
|
payload; bare `log(id, "node")` records a visit with no payloads. The message
|
|
257
266
|
is created on first reference; this only accumulates in memory.
|
|
258
|
-
- `end_message(id, title=None)` — finalize a message and append it
|
|
259
|
-
trace; returns the current trace path. The **only** call that touches
|
|
260
|
-
Optional `title` sets the message's human title
|
|
267
|
+
- `end_message(id, title=None, meta=None)` — finalize a message and append it
|
|
268
|
+
to the trace; returns the current trace path. The **only** call that touches
|
|
269
|
+
disk. Optional `title` sets the message's human title; optional `meta` (a
|
|
270
|
+
flat dict of short scalars) attaches message-level metadata shown on the
|
|
271
|
+
message's chip in the viewer. Idempotent.
|
|
261
272
|
- `reinit(name=None, description=None, meta=None)` — start a **new trace
|
|
262
273
|
file** (fresh timestamped name), keeping the graph and output configuration.
|
|
263
274
|
Use it at natural boundaries of a long-lived process — a new user session, a
|
|
@@ -18,6 +18,10 @@ blockquote {
|
|
|
18
18
|
color: #8a8a8a; font-style: italic;
|
|
19
19
|
}
|
|
20
20
|
table.meta { border-collapse: collapse; font-size: .85rem; margin-bottom: 2rem; }
|
|
21
|
+
section.nodes { margin: -1rem 0 2rem; }
|
|
22
|
+
section.nodes h2 { font-size: 1.05rem; margin: 0 0 .2rem; }
|
|
23
|
+
section.nodes ul { margin: 0; padding-left: 1.2rem; font-size: .9rem; }
|
|
24
|
+
section.nodes li { margin: .15rem 0; }
|
|
21
25
|
table.meta th, table.meta td {
|
|
22
26
|
border: 1px solid #8884; padding: .25rem .6rem; text-align: left;
|
|
23
27
|
}
|
|
@@ -27,6 +31,7 @@ section.message {
|
|
|
27
31
|
padding: .25rem 1rem 1rem; margin-bottom: 1.5rem;
|
|
28
32
|
}
|
|
29
33
|
section.message > h2 { font-size: 1.15rem; margin: .8rem 0 .4rem; }
|
|
34
|
+
section.message > p.msg-meta { font-size: .85rem; color: #8a8a8a; margin: -.2rem 0 .6rem; }
|
|
30
35
|
section.step { padding: .9rem 0; }
|
|
31
36
|
section.step:first-of-type { padding-top: .2rem; }
|
|
32
37
|
/* Divider between consecutive nodes in a message. */
|
|
@@ -57,48 +62,60 @@ pre code { background: none; padding: 0; }
|
|
|
57
62
|
<table class="meta">
|
|
58
63
|
<tr><th>version</th><td>0.2</td></tr>
|
|
59
64
|
</table>
|
|
65
|
+
<section class="nodes">
|
|
66
|
+
<h2>Nodes</h2>
|
|
67
|
+
<ul>
|
|
68
|
+
<li><span class="label">router</span> — Classifies the request and picks a branch: planner or retriever.</li>
|
|
69
|
+
<li><span class="label">planner</span> — Decomposes a tool-using request into concrete tool calls.</li>
|
|
70
|
+
<li><span class="label">retriever</span> — Fetches the most relevant documents for the query.</li>
|
|
71
|
+
<li><span class="label">tool_node</span> — Runs the planned tool calls against external APIs.</li>
|
|
72
|
+
<li><span class="label">generator</span> — Writes the answer from the tool result or retrieved docs.</li>
|
|
73
|
+
</ul>
|
|
74
|
+
</section>
|
|
60
75
|
<section class="message">
|
|
61
76
|
<h2>Weather in Berlin</h2>
|
|
77
|
+
<p class="msg-meta"><span class="label">branch</span>: planner · <span class="label">outcome</span>: answered · <span class="label">latency_ms</span>: 10210</p>
|
|
62
78
|
<section class="step">
|
|
63
|
-
<h3>user_input <span class="time">·
|
|
79
|
+
<h3>user_input <span class="time">· 13:14:05</span></h3>
|
|
64
80
|
<p class="scalar"><span class="label">Input</span> <code>What's the weather in Berlin?</code></p>
|
|
65
81
|
</section>
|
|
66
82
|
<section class="step">
|
|
67
|
-
<h3>router <span class="time">·
|
|
83
|
+
<h3>router <span class="time">· 13:14:05</span></h3>
|
|
68
84
|
<p class="scalar"><span class="label">llm_input</span> <code>Pick a route for the request...</code></p>
|
|
69
85
|
<p class="scalar"><span class="label">llm_output</span> <code>{"route": "planner", "confidence": 0.92}</code></p>
|
|
70
86
|
</section>
|
|
71
87
|
<section class="step">
|
|
72
|
-
<h3>planner <span class="time">·
|
|
88
|
+
<h3>planner <span class="time">· 13:14:05</span></h3>
|
|
73
89
|
<p class="scalar"><span class="label">llm_input</span> <code>Decompose into tool calls...</code></p>
|
|
74
90
|
<p class="scalar"><span class="label">llm_output</span> <code>{"plan": ["weather_api(city='Berlin')"]}</code></p>
|
|
75
91
|
</section>
|
|
76
92
|
<section class="step">
|
|
77
|
-
<h3>tool_node <span class="time">·
|
|
93
|
+
<h3>tool_node <span class="time">· 13:14:05</span></h3>
|
|
78
94
|
</section>
|
|
79
95
|
<section class="step">
|
|
80
|
-
<h3>generator <span class="time">·
|
|
96
|
+
<h3>generator <span class="time">· 13:14:05</span></h3>
|
|
81
97
|
<p class="scalar"><span class="label">llm_input</span> <code>Answer using the tool result...</code></p>
|
|
82
98
|
<p class="scalar"><span class="label">llm_output</span> <code>It's 19C and partly cloudy in Berlin.</code></p>
|
|
83
99
|
</section>
|
|
84
100
|
<section class="step">
|
|
85
|
-
<h3>final_response <span class="time">·
|
|
101
|
+
<h3>final_response <span class="time">· 13:14:05</span></h3>
|
|
86
102
|
<p class="scalar"><span class="label">Output</span> <code>It's 19C and partly cloudy in Berlin.</code></p>
|
|
87
103
|
</section>
|
|
88
104
|
</section>
|
|
89
105
|
<section class="message">
|
|
90
106
|
<h2>Summarize research paper</h2>
|
|
107
|
+
<p class="msg-meta"><span class="label">branch</span>: retriever · <span class="label">outcome</span>: answered · <span class="label">docs_used</span>: 2 · <span class="label">latency_ms</span>: 7130</p>
|
|
91
108
|
<section class="step">
|
|
92
|
-
<h3>user_input <span class="time">·
|
|
109
|
+
<h3>user_input <span class="time">· 13:14:05</span></h3>
|
|
93
110
|
<p class="scalar"><span class="label">Input</span> <code>Summarize the attached research paper.</code></p>
|
|
94
111
|
</section>
|
|
95
112
|
<section class="step">
|
|
96
|
-
<h3>router <span class="time">·
|
|
113
|
+
<h3>router <span class="time">· 13:14:05</span></h3>
|
|
97
114
|
<p class="scalar"><span class="label">llm_input</span> <code>Pick a route for the request...</code></p>
|
|
98
115
|
<p class="scalar"><span class="label">llm_output</span> <code>{"route": "retriever", "confidence": 0.88}</code></p>
|
|
99
116
|
</section>
|
|
100
117
|
<section class="step">
|
|
101
|
-
<h3>retriever <span class="time">·
|
|
118
|
+
<h3>retriever <span class="time">· 13:14:05</span></h3>
|
|
102
119
|
<div class="payload"><span class="label">Input</span><pre><code>{
|
|
103
120
|
"topK": 4,
|
|
104
121
|
"namespace": "papers"
|
|
@@ -115,12 +132,12 @@ pre code { background: none; padding: 0; }
|
|
|
115
132
|
]</code></pre></div>
|
|
116
133
|
</section>
|
|
117
134
|
<section class="step">
|
|
118
|
-
<h3>generator <span class="time">·
|
|
135
|
+
<h3>generator <span class="time">· 13:14:05</span></h3>
|
|
119
136
|
<p class="scalar"><span class="label">llm_input</span> <code>Summarize the retrieved documents...</code></p>
|
|
120
137
|
<p class="scalar"><span class="label">llm_output</span> <code>The paper proposes a sparse attention variant with near-linear cost.</code></p>
|
|
121
138
|
</section>
|
|
122
139
|
<section class="step">
|
|
123
|
-
<h3>final_response <span class="time">·
|
|
140
|
+
<h3>final_response <span class="time">· 13:14:05</span></h3>
|
|
124
141
|
<p class="scalar"><span class="label">Output</span> <code>The paper proposes a sparse attention variant with near-linear cost.</code></p>
|
|
125
142
|
</section>
|
|
126
143
|
</section>
|
|
@@ -26,49 +26,59 @@ flowchart TD
|
|
|
26
26
|
n5 --> n6
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
- **router** — Classifies the request and picks a branch: planner or retriever.
|
|
30
|
+
- **planner** — Decomposes a tool-using request into concrete tool calls.
|
|
31
|
+
- **retriever** — Fetches the most relevant documents for the query.
|
|
32
|
+
- **tool_node** — Runs the planned tool calls against external APIs.
|
|
33
|
+
- **generator** — Writes the answer from the tool result or retrieved docs.
|
|
34
|
+
|
|
29
35
|
## Weather in Berlin
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
**branch**: planner · **outcome**: answered · **latency_ms**: 10210
|
|
38
|
+
|
|
39
|
+
### user_input · 13:14:05
|
|
32
40
|
|
|
33
41
|
**Input**: `What's the weather in Berlin?`
|
|
34
42
|
|
|
35
|
-
### router ·
|
|
43
|
+
### router · 13:14:05
|
|
36
44
|
|
|
37
45
|
**llm_input**: `Pick a route for the request...`
|
|
38
46
|
|
|
39
47
|
**llm_output**: `{"route": "planner", "confidence": 0.92}`
|
|
40
48
|
|
|
41
|
-
### planner ·
|
|
49
|
+
### planner · 13:14:05
|
|
42
50
|
|
|
43
51
|
**llm_input**: `Decompose into tool calls...`
|
|
44
52
|
|
|
45
53
|
**llm_output**: `{"plan": ["weather_api(city='Berlin')"]}`
|
|
46
54
|
|
|
47
|
-
### tool_node ·
|
|
55
|
+
### tool_node · 13:14:05
|
|
48
56
|
|
|
49
|
-
### generator ·
|
|
57
|
+
### generator · 13:14:05
|
|
50
58
|
|
|
51
59
|
**llm_input**: `Answer using the tool result...`
|
|
52
60
|
|
|
53
61
|
**llm_output**: `It's 19C and partly cloudy in Berlin.`
|
|
54
62
|
|
|
55
|
-
### final_response ·
|
|
63
|
+
### final_response · 13:14:05
|
|
56
64
|
|
|
57
65
|
**Output**: `It's 19C and partly cloudy in Berlin.`
|
|
58
66
|
|
|
59
67
|
## Summarize research paper
|
|
60
68
|
|
|
61
|
-
|
|
69
|
+
**branch**: retriever · **outcome**: answered · **docs_used**: 2 · **latency_ms**: 7130
|
|
70
|
+
|
|
71
|
+
### user_input · 13:14:05
|
|
62
72
|
|
|
63
73
|
**Input**: `Summarize the attached research paper.`
|
|
64
74
|
|
|
65
|
-
### router ·
|
|
75
|
+
### router · 13:14:05
|
|
66
76
|
|
|
67
77
|
**llm_input**: `Pick a route for the request...`
|
|
68
78
|
|
|
69
79
|
**llm_output**: `{"route": "retriever", "confidence": 0.88}`
|
|
70
80
|
|
|
71
|
-
### retriever ·
|
|
81
|
+
### retriever · 13:14:05
|
|
72
82
|
|
|
73
83
|
**Input**
|
|
74
84
|
|
|
@@ -94,12 +104,12 @@ flowchart TD
|
|
|
94
104
|
]
|
|
95
105
|
```
|
|
96
106
|
|
|
97
|
-
### generator ·
|
|
107
|
+
### generator · 13:14:05
|
|
98
108
|
|
|
99
109
|
**llm_input**: `Summarize the retrieved documents...`
|
|
100
110
|
|
|
101
111
|
**llm_output**: `The paper proposes a sparse attention variant with near-linear cost.`
|
|
102
112
|
|
|
103
|
-
### final_response ·
|
|
113
|
+
### final_response · 13:14:05
|
|
104
114
|
|
|
105
115
|
**Output**: `The paper proposes a sparse attention variant with near-linear cost.`
|
|
@@ -43,6 +43,16 @@ wiz = wizardflow.init(
|
|
|
43
43
|
("retriever", "generator"), # branches rejoin
|
|
44
44
|
("generator", "final_response"),
|
|
45
45
|
],
|
|
46
|
+
# Optional one-line description per node (keyed by id), shown behind an
|
|
47
|
+
# info icon in the viewer when the node is selected. Plumbing nodes
|
|
48
|
+
# (user_input, final_response) are intentionally left out.
|
|
49
|
+
node_descriptions={
|
|
50
|
+
"router": "Classifies the request and picks a branch: planner or retriever.",
|
|
51
|
+
"planner": "Decomposes a tool-using request into concrete tool calls.",
|
|
52
|
+
"retriever": "Fetches the most relevant documents for the query.",
|
|
53
|
+
"tool_node": "Runs the planned tool calls against external APIs.",
|
|
54
|
+
"generator": "Writes the answer from the tool result or retrieved docs.",
|
|
55
|
+
},
|
|
46
56
|
)
|
|
47
57
|
|
|
48
58
|
# msg-1 — takes the planner / tool branch.
|
|
@@ -55,7 +65,14 @@ wizardflow.log("msg-1", "tool_node") # ran the tool, logged no payload
|
|
|
55
65
|
wizardflow.log("msg-1", "generator", "llm_input", "Answer using the tool result...")
|
|
56
66
|
wizardflow.log("msg-1", "generator", "llm_output", "It's 19C and partly cloudy in Berlin.")
|
|
57
67
|
wizardflow.log("msg-1", "final_response", "Output", "It's 19C and partly cloudy in Berlin.")
|
|
58
|
-
|
|
68
|
+
# Optional meta: flat facts about the message as a whole (short scalars only),
|
|
69
|
+
# shown on the message's chip in the viewer. Here it records which branch ran
|
|
70
|
+
# and how the run turned out.
|
|
71
|
+
wizardflow.end_message(
|
|
72
|
+
"msg-1",
|
|
73
|
+
title="Weather in Berlin",
|
|
74
|
+
meta={"branch": "planner", "outcome": "answered", "latency_ms": 10210},
|
|
75
|
+
)
|
|
59
76
|
|
|
60
77
|
# msg-2 — takes the retriever branch (skips planner/tool entirely).
|
|
61
78
|
wizardflow.log("msg-2", "user_input", "Input", "Summarize the attached research paper.")
|
|
@@ -71,6 +88,10 @@ wizardflow.log("msg-2", "generator", "llm_output",
|
|
|
71
88
|
"The paper proposes a sparse attention variant with near-linear cost.")
|
|
72
89
|
wizardflow.log("msg-2", "final_response", "Output",
|
|
73
90
|
"The paper proposes a sparse attention variant with near-linear cost.")
|
|
74
|
-
wizardflow.end_message(
|
|
91
|
+
wizardflow.end_message(
|
|
92
|
+
"msg-2",
|
|
93
|
+
title="Summarize research paper",
|
|
94
|
+
meta={"branch": "retriever", "outcome": "answered", "docs_used": 2, "latency_ms": 7130},
|
|
95
|
+
)
|
|
75
96
|
|
|
76
97
|
print(f"wrote {wiz.current_path}")
|
|
@@ -18,6 +18,10 @@ blockquote {
|
|
|
18
18
|
color: #8a8a8a; font-style: italic;
|
|
19
19
|
}
|
|
20
20
|
table.meta { border-collapse: collapse; font-size: .85rem; margin-bottom: 2rem; }
|
|
21
|
+
section.nodes { margin: -1rem 0 2rem; }
|
|
22
|
+
section.nodes h2 { font-size: 1.05rem; margin: 0 0 .2rem; }
|
|
23
|
+
section.nodes ul { margin: 0; padding-left: 1.2rem; font-size: .9rem; }
|
|
24
|
+
section.nodes li { margin: .15rem 0; }
|
|
21
25
|
table.meta th, table.meta td {
|
|
22
26
|
border: 1px solid #8884; padding: .25rem .6rem; text-align: left;
|
|
23
27
|
}
|
|
@@ -27,6 +31,7 @@ section.message {
|
|
|
27
31
|
padding: .25rem 1rem 1rem; margin-bottom: 1.5rem;
|
|
28
32
|
}
|
|
29
33
|
section.message > h2 { font-size: 1.15rem; margin: .8rem 0 .4rem; }
|
|
34
|
+
section.message > p.msg-meta { font-size: .85rem; color: #8a8a8a; margin: -.2rem 0 .6rem; }
|
|
30
35
|
section.step { padding: .9rem 0; }
|
|
31
36
|
section.step:first-of-type { padding-top: .2rem; }
|
|
32
37
|
/* Divider between consecutive nodes in a message. */
|
|
@@ -57,33 +62,42 @@ pre code { background: none; padding: 0; }
|
|
|
57
62
|
<table class="meta">
|
|
58
63
|
<tr><th>version</th><td>0.2</td></tr>
|
|
59
64
|
</table>
|
|
65
|
+
<section class="nodes">
|
|
66
|
+
<h2>Nodes</h2>
|
|
67
|
+
<ul>
|
|
68
|
+
<li><span class="label">router</span> — Classifies the request and picks the next node.</li>
|
|
69
|
+
<li><span class="label">planner</span> — Decomposes the request into concrete tool calls.</li>
|
|
70
|
+
<li><span class="label">tool_node</span> — Runs the planned tool calls against external APIs.</li>
|
|
71
|
+
</ul>
|
|
72
|
+
</section>
|
|
60
73
|
<section class="message">
|
|
61
74
|
<h2>msg-1</h2>
|
|
62
75
|
<section class="step">
|
|
63
|
-
<h3>user_input <span class="time">·
|
|
76
|
+
<h3>user_input <span class="time">· 13:13:58</span></h3>
|
|
64
77
|
<p class="scalar"><span class="label">Input</span> <code>What's the weather in Berlin?</code></p>
|
|
65
78
|
</section>
|
|
66
79
|
<section class="step">
|
|
67
|
-
<h3>router <span class="time">·
|
|
80
|
+
<h3>router <span class="time">· 13:13:58</span></h3>
|
|
68
81
|
<p class="scalar"><span class="label">llm_input</span> <code>Route this request...</code></p>
|
|
69
82
|
<p class="scalar"><span class="label">llm_output</span> <code>{"route": "planner"}</code></p>
|
|
70
83
|
</section>
|
|
71
84
|
<section class="step">
|
|
72
|
-
<h3>tool_node <span class="time">·
|
|
85
|
+
<h3>tool_node <span class="time">· 13:13:58</span></h3>
|
|
73
86
|
</section>
|
|
74
87
|
<section class="step">
|
|
75
|
-
<h3>final_response <span class="time">·
|
|
88
|
+
<h3>final_response <span class="time">· 13:13:58</span></h3>
|
|
76
89
|
<p class="scalar"><span class="label">Output</span> <code>It's 19C and partly cloudy in Berlin.</code></p>
|
|
77
90
|
</section>
|
|
78
91
|
</section>
|
|
79
92
|
<section class="message">
|
|
80
93
|
<h2>Summarize the paper</h2>
|
|
94
|
+
<p class="msg-meta"><span class="label">outcome</span>: answered · <span class="label">latency_ms</span>: 320</p>
|
|
81
95
|
<section class="step">
|
|
82
|
-
<h3>user_input <span class="time">·
|
|
96
|
+
<h3>user_input <span class="time">· 13:13:58</span></h3>
|
|
83
97
|
<p class="scalar"><span class="label">Input</span> <code>Summarize the paper.</code></p>
|
|
84
98
|
</section>
|
|
85
99
|
<section class="step">
|
|
86
|
-
<h3>router <span class="time">·
|
|
100
|
+
<h3>router <span class="time">· 13:13:58</span></h3>
|
|
87
101
|
<p class="scalar"><span class="label">llm_output</span> <code>{"route": "planner"}</code></p>
|
|
88
102
|
</section>
|
|
89
103
|
</section>
|
|
@@ -21,30 +21,36 @@ flowchart TD
|
|
|
21
21
|
n3 --> n4
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
- **router** — Classifies the request and picks the next node.
|
|
25
|
+
- **planner** — Decomposes the request into concrete tool calls.
|
|
26
|
+
- **tool_node** — Runs the planned tool calls against external APIs.
|
|
27
|
+
|
|
24
28
|
## msg-1
|
|
25
29
|
|
|
26
|
-
### user_input ·
|
|
30
|
+
### user_input · 13:13:58
|
|
27
31
|
|
|
28
32
|
**Input**: `What's the weather in Berlin?`
|
|
29
33
|
|
|
30
|
-
### router ·
|
|
34
|
+
### router · 13:13:58
|
|
31
35
|
|
|
32
36
|
**llm_input**: `Route this request...`
|
|
33
37
|
|
|
34
38
|
**llm_output**: `{"route": "planner"}`
|
|
35
39
|
|
|
36
|
-
### tool_node ·
|
|
40
|
+
### tool_node · 13:13:58
|
|
37
41
|
|
|
38
|
-
### final_response ·
|
|
42
|
+
### final_response · 13:13:58
|
|
39
43
|
|
|
40
44
|
**Output**: `It's 19C and partly cloudy in Berlin.`
|
|
41
45
|
|
|
42
46
|
## Summarize the paper
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
**outcome**: answered · **latency_ms**: 320
|
|
49
|
+
|
|
50
|
+
### user_input · 13:13:58
|
|
45
51
|
|
|
46
52
|
**Input**: `Summarize the paper.`
|
|
47
53
|
|
|
48
|
-
### router ·
|
|
54
|
+
### router · 13:13:58
|
|
49
55
|
|
|
50
56
|
**llm_output**: `{"route": "planner"}`
|
|
@@ -26,6 +26,15 @@ wiz = wizardflow.init(
|
|
|
26
26
|
("planner", "tool_node"),
|
|
27
27
|
("tool_node", "final_response"),
|
|
28
28
|
],
|
|
29
|
+
# Optional: a one-line description per node, keyed by node id. It shows
|
|
30
|
+
# behind an info icon in the viewer when the node is selected. Plumbing
|
|
31
|
+
# nodes (user_input, final_response) are left out on purpose — not every
|
|
32
|
+
# node needs one.
|
|
33
|
+
node_descriptions={
|
|
34
|
+
"router": "Classifies the request and picks the next node.",
|
|
35
|
+
"planner": "Decomposes the request into concrete tool calls.",
|
|
36
|
+
"tool_node": "Runs the planned tool calls against external APIs.",
|
|
37
|
+
},
|
|
29
38
|
)
|
|
30
39
|
|
|
31
40
|
# Message 1 — each log names its message ("msg-1") in the first argument.
|
|
@@ -36,10 +45,16 @@ wizardflow.log("msg-1", "tool_node") # visited, no payloads
|
|
|
36
45
|
wizardflow.log("msg-1", "final_response", "Output", "It's 19C and partly cloudy in Berlin.")
|
|
37
46
|
wizardflow.end_message("msg-1") # <- writes the file; msg-1 is now persisted
|
|
38
47
|
|
|
39
|
-
# Message 2 — same shape; an optional title gives the message a human title
|
|
48
|
+
# Message 2 — same shape; an optional title gives the message a human title,
|
|
49
|
+
# and optional meta attaches flat facts about the message as a whole (shown on
|
|
50
|
+
# the message's chip in the viewer). Keep meta values short scalars.
|
|
40
51
|
wizardflow.log("msg-2", "user_input", "Input", "Summarize the paper.")
|
|
41
52
|
wizardflow.log("msg-2", "router", "llm_output", '{"route": "planner"}')
|
|
42
|
-
wizardflow.end_message(
|
|
53
|
+
wizardflow.end_message(
|
|
54
|
+
"msg-2",
|
|
55
|
+
title="Summarize the paper",
|
|
56
|
+
meta={"outcome": "answered", "latency_ms": 320},
|
|
57
|
+
)
|
|
43
58
|
# -> the part file now contains msg-1 and msg-2
|
|
44
59
|
|
|
45
60
|
print(f"wrote {wiz.current_path}")
|
|
@@ -155,8 +155,12 @@ def log(
|
|
|
155
155
|
get_default().log(id, node, label, content)
|
|
156
156
|
|
|
157
157
|
|
|
158
|
-
def end_message(
|
|
159
|
-
|
|
158
|
+
def end_message(
|
|
159
|
+
id: str,
|
|
160
|
+
title: Optional[str] = None,
|
|
161
|
+
meta: Optional[Dict[str, Any]] = None,
|
|
162
|
+
) -> str:
|
|
163
|
+
return get_default().end_message(id, title=title, meta=meta)
|
|
160
164
|
|
|
161
165
|
|
|
162
166
|
def to_dict() -> Dict[str, Any]:
|
|
@@ -18,6 +18,15 @@ def short_time(timestamp: Any) -> str:
|
|
|
18
18
|
return clock.split(".", 1)[0] if "." in clock else clock
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
def meta_text(value: Any) -> str:
|
|
22
|
+
"""Render a meta value for display. Meta values are short scalars by
|
|
23
|
+
contract; an out-of-contract dict/list still renders readably as compact
|
|
24
|
+
JSON instead of its Python repr."""
|
|
25
|
+
if isinstance(value, (dict, list)):
|
|
26
|
+
return json.dumps(value, ensure_ascii=False)
|
|
27
|
+
return str(value)
|
|
28
|
+
|
|
29
|
+
|
|
21
30
|
def classify_value(value: Any) -> Tuple[str, str]:
|
|
22
31
|
"""Classify a payload value for rendering, returning ``(kind, text)``.
|
|
23
32
|
|