wizardflow 0.6.7__tar.gz → 0.7.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 (124) hide show
  1. {wizardflow-0.6.7 → wizardflow-0.7.0}/.gitignore +1 -0
  2. wizardflow-0.7.0/PKG-INFO +230 -0
  3. wizardflow-0.7.0/README.md +183 -0
  4. wizardflow-0.7.0/docs/cli.md +118 -0
  5. wizardflow-0.7.0/docs/jsonl-file-format.md +184 -0
  6. wizardflow-0.7.0/docs/opentelemetry.md +302 -0
  7. wizardflow-0.7.0/docs/recording.md +258 -0
  8. {wizardflow-0.6.7 → wizardflow-0.7.0}/pyproject.toml +1 -1
  9. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/__init__.py +77 -3
  10. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/404.html +3 -3
  11. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/__next.__PAGE__.txt +3 -3
  12. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/__next._full.txt +6 -6
  13. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/__next._head.txt +1 -1
  14. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/__next._index.txt +3 -3
  15. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/__next._tree.txt +2 -2
  16. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/0h4fa6bya_8s_.js → wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/0d1yav018wi6n.js +1 -1
  17. wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/0fizjutis9uvx.js +120 -0
  18. wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/14a18doinx71t.css +1 -0
  19. wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/1diz-5jfxjm5x.js +1 -0
  20. wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/1por0fhggxwcm.js +19 -0
  21. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/3lt2ss7dftc2n.css → wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/24c18qa28ilul.css +1 -1
  22. wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/2dclsx_n3obic.js +1 -0
  23. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/3kdn4z1bubx6o.js → wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/2l6srvxdnb-io.js +1 -1
  24. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/18s31mhvm3v37.js → wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/32c7h_m2amh5m.js +1 -1
  25. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/17lpwh4vr7yy-.js → wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/352yh6c3r6-0k.js +1 -1
  26. wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/3fxdmyfsnxue6.js +131 -0
  27. wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/3q-c23s8gv3du.js +1 -0
  28. wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/3rdqn8rx95pw7.js +1 -0
  29. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/35s_hwnpcd3sa.js → wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/414c1-tn-1aef.js +4 -4
  30. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/38u-dtit1x5gj.js → wizardflow-0.7.0/src/wizardflow/_ui/_next/static/chunks/43x_68q2b6gcs.js +2 -2
  31. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_not-found/__next._full.txt +4 -4
  32. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_not-found/__next._head.txt +1 -1
  33. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_not-found/__next._index.txt +3 -3
  34. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_not-found/__next._not-found/__PAGE__.txt +1 -1
  35. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_not-found/__next._not-found.txt +1 -1
  36. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_not-found/__next._tree.txt +1 -1
  37. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_not-found.html +3 -3
  38. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_not-found.txt +4 -4
  39. wizardflow-0.7.0/src/wizardflow/_ui/index.html +7 -0
  40. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/index.txt +6 -6
  41. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/sitemap.xml +1 -1
  42. wizardflow-0.7.0/src/wizardflow/_ui/why-wizardflow/__next._full.txt +37 -0
  43. wizardflow-0.7.0/src/wizardflow/_ui/why-wizardflow/__next._head.txt +6 -0
  44. wizardflow-0.7.0/src/wizardflow/_ui/why-wizardflow/__next._index.txt +7 -0
  45. wizardflow-0.7.0/src/wizardflow/_ui/why-wizardflow/__next._tree.txt +5 -0
  46. wizardflow-0.7.0/src/wizardflow/_ui/why-wizardflow/__next.why-wizardflow/__PAGE__.txt +20 -0
  47. wizardflow-0.7.0/src/wizardflow/_ui/why-wizardflow/__next.why-wizardflow.txt +5 -0
  48. wizardflow-0.7.0/src/wizardflow/_ui/why-wizardflow.html +7 -0
  49. wizardflow-0.7.0/src/wizardflow/_ui/why-wizardflow.txt +37 -0
  50. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/cli.py +108 -2
  51. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/client.py +597 -36
  52. wizardflow-0.7.0/src/wizardflow/otel.py +339 -0
  53. wizardflow-0.7.0/src/wizardflow/otel_file_exporter.py +141 -0
  54. wizardflow-0.7.0/src/wizardflow/otel_mapping.py +382 -0
  55. wizardflow-0.7.0/src/wizardflow/reader.py +272 -0
  56. {wizardflow-0.6.7 → wizardflow-0.7.0}/tests/test_cli.py +38 -0
  57. wizardflow-0.7.0/tests/test_otel.py +415 -0
  58. wizardflow-0.7.0/tests/test_otel_file_exporter.py +78 -0
  59. {wizardflow-0.6.7 → wizardflow-0.7.0}/tests/test_reader.py +92 -1
  60. {wizardflow-0.6.7 → wizardflow-0.7.0}/tests/test_trace.py +435 -0
  61. wizardflow-0.6.7/PKG-INFO +0 -552
  62. wizardflow-0.6.7/README.md +0 -505
  63. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/04v6b5cii8amb.js +0 -121
  64. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/07ut259iis1nt.js +0 -19
  65. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/0rcl5uhziw0rb.js +0 -1
  66. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/0xty7ppkvnn_9.js +0 -1
  67. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/1p2cfk2pfta65.js +0 -1
  68. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/2bn76zw72neic.js +0 -122
  69. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/2ovr9w8tatmai.js +0 -1
  70. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/3-4_ix1hbk5bi.js +0 -1
  71. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/33lom4053xb3g.js +0 -1
  72. wizardflow-0.6.7/src/wizardflow/_ui/_next/static/chunks/43u-gbx_f5fl7.js +0 -1
  73. wizardflow-0.6.7/src/wizardflow/_ui/index.html +0 -7
  74. wizardflow-0.6.7/src/wizardflow/reader.py +0 -134
  75. {wizardflow-0.6.7 → wizardflow-0.7.0}/CONTRIBUTING.md +0 -0
  76. {wizardflow-0.6.7 → wizardflow-0.7.0}/LICENSE +0 -0
  77. {wizardflow-0.6.7 → wizardflow-0.7.0}/assets/demo.gif +0 -0
  78. {wizardflow-0.6.7 → wizardflow-0.7.0}/examples/data_types.py +0 -0
  79. {wizardflow-0.6.7 → wizardflow-0.7.0}/examples/multibranch.html +0 -0
  80. {wizardflow-0.6.7 → wizardflow-0.7.0}/examples/multibranch.md +0 -0
  81. {wizardflow-0.6.7 → wizardflow-0.7.0}/examples/multibranch.py +0 -0
  82. {wizardflow-0.6.7 → wizardflow-0.7.0}/examples/quickstart.html +0 -0
  83. {wizardflow-0.6.7 → wizardflow-0.7.0}/examples/quickstart.md +0 -0
  84. {wizardflow-0.6.7 → wizardflow-0.7.0}/examples/quickstart.py +0 -0
  85. {wizardflow-0.6.7 → wizardflow-0.7.0}/scripts/build_ui.py +0 -0
  86. {wizardflow-0.6.7 → wizardflow-0.7.0}/scripts/live_trace_demo.py +0 -0
  87. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_render.py +0 -0
  88. {wizardflow-0.6.7/src/wizardflow/_ui/_next/static/Turmu90w9F5mwvKyfszeR → wizardflow-0.7.0/src/wizardflow/_ui/_next/static/H81QsKAgLXQMK2H6vyBjb}/_buildManifest.js +0 -0
  89. {wizardflow-0.6.7/src/wizardflow/_ui/_next/static/Turmu90w9F5mwvKyfszeR → wizardflow-0.7.0/src/wizardflow/_ui/_next/static/H81QsKAgLXQMK2H6vyBjb}/_clientMiddlewareManifest.js +0 -0
  90. {wizardflow-0.6.7/src/wizardflow/_ui/_next/static/Turmu90w9F5mwvKyfszeR → wizardflow-0.7.0/src/wizardflow/_ui/_next/static/H81QsKAgLXQMK2H6vyBjb}/_ssgManifest.js +0 -0
  91. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/05-c3ty_6dwfk.js +0 -0
  92. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/09s72r58ijxwx.js +0 -0
  93. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/0cz1d0mv5g_q7.js +0 -0
  94. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/14mrh2-p_w84d.js +0 -0
  95. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/18clj6xsyhc_j.css +0 -0
  96. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/1_way7swvumpv.js +0 -0
  97. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/2-j1b74l3lxxu.css +0 -0
  98. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/27jktro2p5rq9.js +0 -0
  99. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/2gj5bmeov-r8f.js +0 -0
  100. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/310vm2bl3xxpt.js +0 -0
  101. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/3n7dm2ojtyzwn.js +0 -0
  102. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/chunks/turbopack-2fblmukzx7kws.js +0 -0
  103. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/4fa387ec64143e14-s.2tuy5pz7dlieh.woff2 +0 -0
  104. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/53b9e256198e5412-s.390ncx5urfkfu.woff2 +0 -0
  105. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/5ce348bf30bf5439-s.31988l_ccedte.woff2 +0 -0
  106. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/6306c77e7c8268e4-s.2dbetqa9o8jxf.woff2 +0 -0
  107. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/7178b3e590c64307-s.21jp631_3pja2.woff2 +0 -0
  108. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/797e433ab948586e-s.p.0r6juujl39pe6.woff2 +0 -0
  109. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/7d817b4c03b0c5f1-s.1uyisp29ctx0d.woff2 +0 -0
  110. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/8a480f0b521d4e75-s.1qq4vpdcun5oj.woff2 +0 -0
  111. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/bbc41e54d2fcbd21-s.1rgnod-3esatf.woff2 +0 -0
  112. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/caa3a2e1cccd8315-s.p.0wgildi0cnwt9.woff2 +0 -0
  113. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/fef07dbb0973bf53-s.3p2_lha1f2xer.woff2 +0 -0
  114. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/_next/static/media/icon.09qublg69ek7b.svg +0 -0
  115. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/icon.svg +0 -0
  116. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/opengraph-image +0 -0
  117. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/_ui/robots.txt +0 -0
  118. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/constants.py +0 -0
  119. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/html.py +0 -0
  120. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/markdown.py +0 -0
  121. {wizardflow-0.6.7 → wizardflow-0.7.0}/src/wizardflow/py.typed +0 -0
  122. {wizardflow-0.6.7 → wizardflow-0.7.0}/tests/conftest.py +0 -0
  123. {wizardflow-0.6.7 → wizardflow-0.7.0}/tests/test_html.py +0 -0
  124. {wizardflow-0.6.7 → wizardflow-0.7.0}/tests/test_markdown.py +0 -0
@@ -5,6 +5,7 @@ __pycache__/
5
5
  build/
6
6
  dist/
7
7
  .pytest_cache/
8
+ .test-tmp/
8
9
  .venv/
9
10
  venv/
10
11
  # uv resolves this in CI (uv run / uv build); a zero-dependency library doesn't
@@ -0,0 +1,230 @@
1
+ Metadata-Version: 2.5
2
+ Name: wizardflow
3
+ Version: 0.7.0
4
+ Summary: Python SDK for recording agent flows into the WizardFlow / AgentTrace file format.
5
+ Project-URL: Homepage, https://getwizardflow.com
6
+ Project-URL: Documentation, https://getwizardflow.com
7
+ Author: Leon Koch
8
+ License: MIT License
9
+
10
+ Copyright (c) 2026 Leon Koch
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+ License-File: LICENSE
30
+ Keywords: agents,langgraph,llm,observability,tracing
31
+ Classifier: Development Status :: 3 - Alpha
32
+ Classifier: Intended Audience :: Developers
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Operating System :: OS Independent
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.9
37
+ Classifier: Programming Language :: Python :: 3.10
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Programming Language :: Python :: 3.13
41
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
42
+ Classifier: Typing :: Typed
43
+ Requires-Python: >=3.9
44
+ Provides-Extra: dev
45
+ Requires-Dist: pytest>=7; extra == 'dev'
46
+ Description-Content-Type: text/markdown
47
+
48
+ # WizardFlow Python SDK
49
+
50
+ **A lightweight recorder for Python agents.** WizardFlow turns an agent run
51
+ into a portable WizardFlow JSONL file that you can replay as an interactive
52
+ graph, inspect with ordinary tools, or attach to a bug report.
53
+
54
+ Drop the file into [getwizardflow.com](https://getwizardflow.com) and it is
55
+ processed entirely in the browser—nothing is uploaded. You can also replay it
56
+ locally with `wizardflow ui`.
57
+
58
+ ![WizardFlow replaying an agent run](https://raw.githubusercontent.com/lkleonk/wizardflow/main/sdk/python/assets/demo.gif)
59
+
60
+ â–¶ **[Watch this run replay](https://getwizardflow.com/?example=doctor-consultation)**
61
+
62
+ ## Why WizardFlow?
63
+
64
+ - **The trace is a file.** Commit, diff, grep, archive, or share it without an
65
+ observability account.
66
+ - **Replay it anywhere.** Use the bundled local viewer or the fully client-side
67
+ hosted viewer.
68
+ - **Zero runtime dependencies.** The base SDK is pure Python and requires no
69
+ daemon or framework.
70
+ - **Explicit by design.** Your code chooses which node executions and values
71
+ enter the trace.
72
+ - **OpenTelemetry is optional.** The same node executions can also be projected
73
+ to OTLP-compatible observability backends.
74
+
75
+ ## Install
76
+
77
+ ```bash
78
+ pip install wizardflow
79
+ ```
80
+
81
+ ## Quickstart
82
+
83
+ ```python
84
+ import uuid
85
+
86
+ import wizardflow
87
+
88
+ trace = wizardflow.init(
89
+ output_dir="traces",
90
+ file_prefix="run",
91
+ nodes=["generator"],
92
+ )
93
+
94
+ message_id = str(uuid.uuid4())
95
+ input_value = ...
96
+
97
+ with trace.node(message_id, "generator") as node:
98
+ node.log_input(input_value)
99
+ output_value = ...
100
+ node.log_output(output_value)
101
+
102
+ trace_path = trace.end_message(message_id)
103
+ print(trace_path)
104
+ ```
105
+
106
+ `trace.node(...)` records the node's execution interval. `log_input()` and
107
+ `log_output()` preserve their JSON-compatible values in the trace, and
108
+ `end_message()` appends the completed message to JSONL. There is no separate
109
+ `save()` call.
110
+
111
+ Drop `trace_path` into [getwizardflow.com](https://getwizardflow.com), or open
112
+ it locally:
113
+
114
+ ```bash
115
+ wizardflow ui traces/run__<timestamp>.jsonl
116
+ ```
117
+
118
+ The module-level style remains available for applications that use one default
119
+ trace:
120
+
121
+ ```python
122
+ wizardflow.init(nodes=["generator"])
123
+
124
+ with wizardflow.node("msg-1", "generator") as node:
125
+ node.log_input(input_value)
126
+ node.log_output(output_value)
127
+
128
+ wizardflow.end_message("msg-1")
129
+ ```
130
+
131
+ ## Optional OpenTelemetry export
132
+
133
+ Install the optional OTel packages directly:
134
+
135
+ ```bash
136
+ pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
137
+ ```
138
+
139
+ Then enable OTLP trace export while retaining JSONL as the portable source of
140
+ truth:
141
+
142
+ ```python
143
+ trace = wizardflow.init(
144
+ nodes=["generator"],
145
+ name="my-agent",
146
+ otel=True,
147
+ otel_endpoint="http://localhost:4318/v1/traces",
148
+ otel_trace_scope="message",
149
+ )
150
+
151
+ with trace.node("msg-1", "generator", kind="llm") as node:
152
+ node.log_input(input_value)
153
+ node.log_output(output_value)
154
+
155
+ trace.end_message("msg-1")
156
+ trace.close_otel()
157
+ ```
158
+
159
+ Generic logs can optionally choose an exact application-owned span attribute
160
+ without changing their JSONL/UI label:
161
+
162
+ ```python
163
+ node.log("quality", 0.92, otel_attribute="app.response.quality")
164
+ ```
165
+
166
+ Content export is privacy-conscious and disabled by default. See the
167
+ [OpenTelemetry guide](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/opentelemetry.md)
168
+ for provider ownership, GenAI mappings, content controls, graph events, and
169
+ independent JSONL/OTel lifecycles. Existing artifacts can be exported later:
170
+
171
+ ```bash
172
+ wizardflow otel export run.jsonl --endpoint http://localhost:4318/v1/traces
173
+ ```
174
+
175
+ ## LangGraph topology
176
+
177
+ WizardFlow can read nodes and edges from a compiled LangGraph application
178
+ without importing LangGraph itself:
179
+
180
+ ```python
181
+ trace = wizardflow.init_from_langgraph(
182
+ compiled_app,
183
+ output_dir="traces",
184
+ file_prefix="run",
185
+ )
186
+ ```
187
+
188
+ Runtime recording then uses the same `trace.node(...)` API. Extraction is
189
+ duck-typed through `app.get_graph()`.
190
+
191
+ ## Documentation
192
+
193
+ - **[Recording agent runs](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/recording.md)**
194
+ — messages, node scopes, semantic records, generic logs, kinds, output
195
+ selection, multiple clients, and reinitialization.
196
+ - **[OpenTelemetry export](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/opentelemetry.md)**
197
+ — OTLP setup, provider ownership, GenAI mappings, privacy controls, graph
198
+ events, offline JSONL export, and cleanup.
199
+ - **[WizardFlow JSONL format](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/jsonl-file-format.md)**
200
+ — record shapes, semantic fields, compatibility, and rotation.
201
+ - **[CLI and local viewer](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/cli.md)**
202
+ — live local replay and Markdown, HTML, and JSON export.
203
+
204
+ ## CLI at a glance
205
+
206
+ ```bash
207
+ wizardflow ui run.jsonl # interactive local replay
208
+ wizardflow ui --latest traces/ # newest trace in a directory
209
+ wizardflow md run.jsonl -o run.md # Markdown export
210
+ wizardflow html run.jsonl -o run.html
211
+ wizardflow json run.jsonl -o run.json
212
+ ```
213
+
214
+ All commands read both WizardFlow JSONL and the single-document JSON form. See
215
+ the [CLI guide](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/cli.md)
216
+ for flags, live-trace behavior, and rotated-part navigation.
217
+
218
+ ## Examples
219
+
220
+ Runnable examples live in
221
+ [`examples/`](https://github.com/lkleonk/wizardflow/tree/main/sdk/python/examples):
222
+
223
+ - `quickstart.py` records a small linear flow.
224
+ - `multibranch.py` records two messages that take different graph branches.
225
+
226
+ ## Development
227
+
228
+ See
229
+ [CONTRIBUTING.md](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/CONTRIBUTING.md)
230
+ for local tests and maintainer workflows.
@@ -0,0 +1,183 @@
1
+ # WizardFlow Python SDK
2
+
3
+ **A lightweight recorder for Python agents.** WizardFlow turns an agent run
4
+ into a portable WizardFlow JSONL file that you can replay as an interactive
5
+ graph, inspect with ordinary tools, or attach to a bug report.
6
+
7
+ Drop the file into [getwizardflow.com](https://getwizardflow.com) and it is
8
+ processed entirely in the browser—nothing is uploaded. You can also replay it
9
+ locally with `wizardflow ui`.
10
+
11
+ ![WizardFlow replaying an agent run](https://raw.githubusercontent.com/lkleonk/wizardflow/main/sdk/python/assets/demo.gif)
12
+
13
+ â–¶ **[Watch this run replay](https://getwizardflow.com/?example=doctor-consultation)**
14
+
15
+ ## Why WizardFlow?
16
+
17
+ - **The trace is a file.** Commit, diff, grep, archive, or share it without an
18
+ observability account.
19
+ - **Replay it anywhere.** Use the bundled local viewer or the fully client-side
20
+ hosted viewer.
21
+ - **Zero runtime dependencies.** The base SDK is pure Python and requires no
22
+ daemon or framework.
23
+ - **Explicit by design.** Your code chooses which node executions and values
24
+ enter the trace.
25
+ - **OpenTelemetry is optional.** The same node executions can also be projected
26
+ to OTLP-compatible observability backends.
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ pip install wizardflow
32
+ ```
33
+
34
+ ## Quickstart
35
+
36
+ ```python
37
+ import uuid
38
+
39
+ import wizardflow
40
+
41
+ trace = wizardflow.init(
42
+ output_dir="traces",
43
+ file_prefix="run",
44
+ nodes=["generator"],
45
+ )
46
+
47
+ message_id = str(uuid.uuid4())
48
+ input_value = ...
49
+
50
+ with trace.node(message_id, "generator") as node:
51
+ node.log_input(input_value)
52
+ output_value = ...
53
+ node.log_output(output_value)
54
+
55
+ trace_path = trace.end_message(message_id)
56
+ print(trace_path)
57
+ ```
58
+
59
+ `trace.node(...)` records the node's execution interval. `log_input()` and
60
+ `log_output()` preserve their JSON-compatible values in the trace, and
61
+ `end_message()` appends the completed message to JSONL. There is no separate
62
+ `save()` call.
63
+
64
+ Drop `trace_path` into [getwizardflow.com](https://getwizardflow.com), or open
65
+ it locally:
66
+
67
+ ```bash
68
+ wizardflow ui traces/run__<timestamp>.jsonl
69
+ ```
70
+
71
+ The module-level style remains available for applications that use one default
72
+ trace:
73
+
74
+ ```python
75
+ wizardflow.init(nodes=["generator"])
76
+
77
+ with wizardflow.node("msg-1", "generator") as node:
78
+ node.log_input(input_value)
79
+ node.log_output(output_value)
80
+
81
+ wizardflow.end_message("msg-1")
82
+ ```
83
+
84
+ ## Optional OpenTelemetry export
85
+
86
+ Install the optional OTel packages directly:
87
+
88
+ ```bash
89
+ pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
90
+ ```
91
+
92
+ Then enable OTLP trace export while retaining JSONL as the portable source of
93
+ truth:
94
+
95
+ ```python
96
+ trace = wizardflow.init(
97
+ nodes=["generator"],
98
+ name="my-agent",
99
+ otel=True,
100
+ otel_endpoint="http://localhost:4318/v1/traces",
101
+ otel_trace_scope="message",
102
+ )
103
+
104
+ with trace.node("msg-1", "generator", kind="llm") as node:
105
+ node.log_input(input_value)
106
+ node.log_output(output_value)
107
+
108
+ trace.end_message("msg-1")
109
+ trace.close_otel()
110
+ ```
111
+
112
+ Generic logs can optionally choose an exact application-owned span attribute
113
+ without changing their JSONL/UI label:
114
+
115
+ ```python
116
+ node.log("quality", 0.92, otel_attribute="app.response.quality")
117
+ ```
118
+
119
+ Content export is privacy-conscious and disabled by default. See the
120
+ [OpenTelemetry guide](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/opentelemetry.md)
121
+ for provider ownership, GenAI mappings, content controls, graph events, and
122
+ independent JSONL/OTel lifecycles. Existing artifacts can be exported later:
123
+
124
+ ```bash
125
+ wizardflow otel export run.jsonl --endpoint http://localhost:4318/v1/traces
126
+ ```
127
+
128
+ ## LangGraph topology
129
+
130
+ WizardFlow can read nodes and edges from a compiled LangGraph application
131
+ without importing LangGraph itself:
132
+
133
+ ```python
134
+ trace = wizardflow.init_from_langgraph(
135
+ compiled_app,
136
+ output_dir="traces",
137
+ file_prefix="run",
138
+ )
139
+ ```
140
+
141
+ Runtime recording then uses the same `trace.node(...)` API. Extraction is
142
+ duck-typed through `app.get_graph()`.
143
+
144
+ ## Documentation
145
+
146
+ - **[Recording agent runs](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/recording.md)**
147
+ — messages, node scopes, semantic records, generic logs, kinds, output
148
+ selection, multiple clients, and reinitialization.
149
+ - **[OpenTelemetry export](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/opentelemetry.md)**
150
+ — OTLP setup, provider ownership, GenAI mappings, privacy controls, graph
151
+ events, offline JSONL export, and cleanup.
152
+ - **[WizardFlow JSONL format](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/jsonl-file-format.md)**
153
+ — record shapes, semantic fields, compatibility, and rotation.
154
+ - **[CLI and local viewer](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/cli.md)**
155
+ — live local replay and Markdown, HTML, and JSON export.
156
+
157
+ ## CLI at a glance
158
+
159
+ ```bash
160
+ wizardflow ui run.jsonl # interactive local replay
161
+ wizardflow ui --latest traces/ # newest trace in a directory
162
+ wizardflow md run.jsonl -o run.md # Markdown export
163
+ wizardflow html run.jsonl -o run.html
164
+ wizardflow json run.jsonl -o run.json
165
+ ```
166
+
167
+ All commands read both WizardFlow JSONL and the single-document JSON form. See
168
+ the [CLI guide](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/docs/cli.md)
169
+ for flags, live-trace behavior, and rotated-part navigation.
170
+
171
+ ## Examples
172
+
173
+ Runnable examples live in
174
+ [`examples/`](https://github.com/lkleonk/wizardflow/tree/main/sdk/python/examples):
175
+
176
+ - `quickstart.py` records a small linear flow.
177
+ - `multibranch.py` records two messages that take different graph branches.
178
+
179
+ ## Development
180
+
181
+ See
182
+ [CONTRIBUTING.md](https://github.com/lkleonk/wizardflow/blob/main/sdk/python/CONTRIBUTING.md)
183
+ for local tests and maintainer workflows.
@@ -0,0 +1,118 @@
1
+ # CLI and local viewer
2
+
3
+ The `wizardflow` command reads both WizardFlow JSONL parts and the legacy
4
+ single-document JSON representation.
5
+
6
+ ## Selecting a trace
7
+
8
+ Every subcommand accepts a trace as a positional argument or through `--path`:
9
+
10
+ ```bash
11
+ wizardflow ui run.jsonl
12
+ wizardflow ui --path run.jsonl
13
+ ```
14
+
15
+ Use `--latest` to select the most recently modified `.jsonl` or `.json` file in
16
+ a directory:
17
+
18
+ ```bash
19
+ wizardflow ui --latest
20
+ wizardflow ui --latest traces/
21
+ ```
22
+
23
+ ## Local interactive viewer
24
+
25
+ ```bash
26
+ wizardflow ui run.jsonl [--host 127.0.0.1] [--port 0] [--no-open]
27
+ ```
28
+
29
+ This starts a standard-library HTTP server and serves the static WizardFlow UI
30
+ bundled in the package.
31
+
32
+ | Option | Default | Meaning |
33
+ | --- | --- | --- |
34
+ | `--latest` | off | Treat the path as a directory and choose its newest trace |
35
+ | `--host` | `127.0.0.1` | Interface to bind |
36
+ | `--port` | `0` | Port to bind; zero asks the OS for a free port |
37
+ | `--no-open` | off | Print the URL instead of opening a browser |
38
+
39
+ The viewer follows a growing active part using ETag revalidation. Polling pauses
40
+ while the tab is hidden and stops when the part gains `nextPart`, because a
41
+ sealed part no longer grows. Part navigation loads neighboring files rather
42
+ than stitching the entire rotation chain into one timeline.
43
+
44
+ ## Markdown export
45
+
46
+ ```bash
47
+ wizardflow md run.jsonl
48
+ wizardflow md run.jsonl -o run.md
49
+ wizardflow md run.jsonl --no-mermaid
50
+ ```
51
+
52
+ Markdown output includes metadata, an optional Mermaid graph, messages, steps,
53
+ and payloads.
54
+
55
+ | Option | Meaning |
56
+ | --- | --- |
57
+ | `-o`, `--output` | Write to a file instead of stdout |
58
+ | `--mermaid` | Include the graph diagram; enabled by default |
59
+ | `--no-mermaid` | Omit the graph diagram |
60
+
61
+ ## HTML export
62
+
63
+ ```bash
64
+ wizardflow html run.jsonl
65
+ wizardflow html run.jsonl -o run.html
66
+ ```
67
+
68
+ This produces one self-contained document with inline CSS, no JavaScript, and
69
+ no external assets. It renders messages and payloads; use Markdown when a graph
70
+ diagram is required.
71
+
72
+ ## Assemble JSONL into JSON
73
+
74
+ ```bash
75
+ wizardflow json run.jsonl
76
+ wizardflow json run.jsonl -o run.json
77
+ ```
78
+
79
+ This assembles the selected part's header and message records into one
80
+ pretty-printed WizardFlow trace. A seal's `nextPart` is folded into metadata. It
81
+ does not combine an entire rotation chain.
82
+
83
+ ## Export JSONL to OpenTelemetry
84
+
85
+ ```bash
86
+ wizardflow otel export run.jsonl --endpoint http://localhost:4318/v1/traces
87
+ wizardflow otel export run.jsonl --trace-scope message
88
+ ```
89
+
90
+ This projects an existing artifact through OTLP/HTTP using the same semantic
91
+ mapping as live export. It creates fresh OTel trace IDs and never modifies the
92
+ source file. By default it discovers and exports the complete rotated
93
+ part-chain and creates one `wizardflow.run` trace; `--trace-scope message`
94
+ creates one `wizardflow.message` trace per message.
95
+
96
+ | Option | Default | Meaning |
97
+ | --- | --- | --- |
98
+ | `--endpoint` | OTel environment | OTLP/HTTP traces endpoint |
99
+ | `--trace-scope` | `recording` | `recording` or `message` trace boundaries |
100
+ | `--include-content` | off | Export bounded input, output, and structured log content |
101
+ | `--content-max-bytes` | `16_384` | Maximum bytes for each exported content value |
102
+ | `--export-graph` | off | Add the WizardFlow graph event to each root |
103
+ | `--graph-max-bytes` | `65_536` | Maximum full graph-event content size |
104
+ | `--current-part-only` | off | Export only the named rotation part |
105
+
106
+ When `--endpoint` is omitted, the command reads
107
+ `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`, then `OTEL_EXPORTER_OTLP_ENDPOINT`.
108
+ See [opentelemetry.md](opentelemetry.md) for installation, privacy, and mapping
109
+ details.
110
+
111
+ ## Live traces and rotated parts
112
+
113
+ `end_message()` appends one durable line, so `wizardflow ui` can show messages
114
+ while the process is still recording. When the active part rotates, its seal
115
+ points to the next filename. The local server resolves only plain sibling part
116
+ names from the trace directory; UI assets always take precedence.
117
+
118
+ See [jsonl-file-format.md](jsonl-file-format.md) for the record and rotation schema.