penguiflow 1.0.2__tar.gz → 1.0.3__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.

Potentially problematic release.


This version of penguiflow might be problematic. Click here for more details.

Files changed (25) hide show
  1. {penguiflow-1.0.2 → penguiflow-1.0.3}/PKG-INFO +23 -2
  2. {penguiflow-1.0.2 → penguiflow-1.0.3}/README.md +22 -1
  3. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/__init__.py +3 -1
  4. penguiflow-1.0.3/penguiflow/viz.py +76 -0
  5. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow.egg-info/PKG-INFO +23 -2
  6. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow.egg-info/SOURCES.txt +2 -1
  7. {penguiflow-1.0.2 → penguiflow-1.0.3}/pyproject.toml +1 -1
  8. penguiflow-1.0.3/tests/test_viz.py +29 -0
  9. penguiflow-1.0.2/penguiflow/viz.py +0 -5
  10. {penguiflow-1.0.2 → penguiflow-1.0.3}/LICENSE +0 -0
  11. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/core.py +0 -0
  12. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/middlewares.py +0 -0
  13. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/node.py +0 -0
  14. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/patterns.py +0 -0
  15. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/registry.py +0 -0
  16. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/types.py +0 -0
  17. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow.egg-info/dependency_links.txt +0 -0
  18. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow.egg-info/requires.txt +0 -0
  19. {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow.egg-info/top_level.txt +0 -0
  20. {penguiflow-1.0.2 → penguiflow-1.0.3}/setup.cfg +0 -0
  21. {penguiflow-1.0.2 → penguiflow-1.0.3}/tests/test_controller.py +0 -0
  22. {penguiflow-1.0.2 → penguiflow-1.0.3}/tests/test_core.py +0 -0
  23. {penguiflow-1.0.2 → penguiflow-1.0.3}/tests/test_patterns.py +0 -0
  24. {penguiflow-1.0.2 → penguiflow-1.0.3}/tests/test_registry.py +0 -0
  25. {penguiflow-1.0.2 → penguiflow-1.0.3}/tests/test_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: penguiflow
3
- Version: 1.0.2
3
+ Version: 1.0.3
4
4
  Summary: Async agent orchestration primitives.
5
5
  Author: PenguiFlow Team
6
6
  License: MIT License
@@ -99,7 +99,7 @@ from penguiflow.node import Node
99
99
  class QueryOut(BaseModel):
100
100
  topic: str
101
101
 
102
- async def triage(m: QueryIn) -> QueryOut:
102
+ async def triage(msg: QueryIn, ctx) -> QueryOut:
103
103
  return QueryOut(topic="metrics")
104
104
 
105
105
  triage_node = Node(triage, name="triage")
@@ -328,6 +328,19 @@ flow focused on high-level orchestration logic.
328
328
 
329
329
  ---
330
330
 
331
+ ### Visualization
332
+
333
+ Need a quick view of the flow topology? Call `flow_to_mermaid(flow)` to render the graph
334
+ as a Mermaid diagram ready for Markdown or docs tools:
335
+
336
+ ```python
337
+ from penguiflow import flow_to_mermaid
338
+
339
+ print(flow_to_mermaid(flow, direction="LR"))
340
+ ```
341
+
342
+ ---
343
+
331
344
  ## 🛡️ Reliability & Observability
332
345
 
333
346
  * **NodePolicy**: set validation scope plus per-node timeout, retries, and backoff curves.
@@ -346,6 +359,14 @@ flow focused on high-level orchestration logic.
346
359
 
347
360
  ---
348
361
 
362
+ ## 📊 Benchmarks
363
+
364
+ Lightweight benchmarks live under `benchmarks/`. Run them via `uv run python benchmarks/<name>.py`
365
+ to capture baselines for fan-out throughput, retry/timeout overhead, and controller
366
+ playbook latency. Copy them into product repos to watch for regressions over time.
367
+
368
+ ---
369
+
349
370
  ## 🔮 Roadmap
350
371
 
351
372
  * **v1 (current)**: safe core runtime, type-safety, retries, timeouts, routing, controller loops, playbooks via examples.
@@ -60,7 +60,7 @@ from penguiflow.node import Node
60
60
  class QueryOut(BaseModel):
61
61
  topic: str
62
62
 
63
- async def triage(m: QueryIn) -> QueryOut:
63
+ async def triage(msg: QueryIn, ctx) -> QueryOut:
64
64
  return QueryOut(topic="metrics")
65
65
 
66
66
  triage_node = Node(triage, name="triage")
@@ -289,6 +289,19 @@ flow focused on high-level orchestration logic.
289
289
 
290
290
  ---
291
291
 
292
+ ### Visualization
293
+
294
+ Need a quick view of the flow topology? Call `flow_to_mermaid(flow)` to render the graph
295
+ as a Mermaid diagram ready for Markdown or docs tools:
296
+
297
+ ```python
298
+ from penguiflow import flow_to_mermaid
299
+
300
+ print(flow_to_mermaid(flow, direction="LR"))
301
+ ```
302
+
303
+ ---
304
+
292
305
  ## 🛡️ Reliability & Observability
293
306
 
294
307
  * **NodePolicy**: set validation scope plus per-node timeout, retries, and backoff curves.
@@ -307,6 +320,14 @@ flow focused on high-level orchestration logic.
307
320
 
308
321
  ---
309
322
 
323
+ ## 📊 Benchmarks
324
+
325
+ Lightweight benchmarks live under `benchmarks/`. Run them via `uv run python benchmarks/<name>.py`
326
+ to capture baselines for fan-out throughput, retry/timeout overhead, and controller
327
+ playbook latency. Copy them into product repos to watch for regressions over time.
328
+
329
+ ---
330
+
310
331
  ## 🔮 Roadmap
311
332
 
312
333
  * **v1 (current)**: safe core runtime, type-safety, retries, timeouts, routing, controller loops, playbooks via examples.
@@ -15,6 +15,7 @@ from .node import Node, NodePolicy
15
15
  from .patterns import join_k, map_concurrent, predicate_router, union_router
16
16
  from .registry import ModelRegistry
17
17
  from .types import WM, FinalAnswer, Headers, Message, PlanStep, Thought
18
+ from .viz import flow_to_mermaid
18
19
 
19
20
  __all__ = [
20
21
  "__version__",
@@ -37,7 +38,8 @@ __all__ = [
37
38
  "join_k",
38
39
  "predicate_router",
39
40
  "union_router",
41
+ "flow_to_mermaid",
40
42
  "create",
41
43
  ]
42
44
 
43
- __version__ = "1.0.2"
45
+ __version__ = "1.0.3"
@@ -0,0 +1,76 @@
1
+ """Visualization helpers for PenguiFlow graphs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from typing import TYPE_CHECKING
7
+
8
+ from .core import Endpoint
9
+ from .node import Node
10
+
11
+ if TYPE_CHECKING: # pragma: no cover - type checking only
12
+ from .core import PenguiFlow
13
+
14
+ __all__ = ["flow_to_mermaid"]
15
+
16
+
17
+ def flow_to_mermaid(flow: PenguiFlow, *, direction: str = "TD") -> str:
18
+ """Render the flow graph as a Mermaid diagram string.
19
+
20
+ Parameters
21
+ ----------
22
+ flow:
23
+ The `PenguiFlow` instance to visualize.
24
+ direction:
25
+ Mermaid graph direction ("TD", "LR", etc.). Defaults to top-down.
26
+ """
27
+
28
+ lines: list[str] = [f"graph {direction}"]
29
+ nodes: set[object] = set()
30
+
31
+ for floe in flow._floes: # noqa: SLF001 - visualization accesses internals by design
32
+ if floe.source is not None:
33
+ nodes.add(floe.source)
34
+ if floe.target is not None:
35
+ nodes.add(floe.target)
36
+
37
+ id_lookup: dict[object, str] = {}
38
+ used_ids: set[str] = set()
39
+
40
+ for entity in nodes:
41
+ label = _display_label(entity)
42
+ node_id = _unique_id(label, used_ids)
43
+ used_ids.add(node_id)
44
+ id_lookup[entity] = node_id
45
+ lines.append(f" {node_id}[\"{label}\"]")
46
+
47
+ for floe in flow._floes: # noqa: SLF001
48
+ source = floe.source
49
+ target = floe.target
50
+ if source is None or target is None:
51
+ continue
52
+ src_id = id_lookup.get(source)
53
+ tgt_id = id_lookup.get(target)
54
+ if src_id is None or tgt_id is None:
55
+ continue
56
+ lines.append(f" {src_id} --> {tgt_id}")
57
+
58
+ return "\n".join(lines)
59
+
60
+
61
+ def _display_label(entity: object) -> str:
62
+ if isinstance(entity, Node):
63
+ return entity.name or entity.node_id
64
+ if isinstance(entity, Endpoint):
65
+ return entity.name
66
+ return str(entity)
67
+
68
+
69
+ def _unique_id(label: str, used: set[str]) -> str:
70
+ base = re.sub(r"[^0-9A-Za-z_]", "_", label) or "node"
71
+ candidate = base
72
+ index = 1
73
+ while candidate in used:
74
+ index += 1
75
+ candidate = f"{base}_{index}"
76
+ return candidate
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: penguiflow
3
- Version: 1.0.2
3
+ Version: 1.0.3
4
4
  Summary: Async agent orchestration primitives.
5
5
  Author: PenguiFlow Team
6
6
  License: MIT License
@@ -99,7 +99,7 @@ from penguiflow.node import Node
99
99
  class QueryOut(BaseModel):
100
100
  topic: str
101
101
 
102
- async def triage(m: QueryIn) -> QueryOut:
102
+ async def triage(msg: QueryIn, ctx) -> QueryOut:
103
103
  return QueryOut(topic="metrics")
104
104
 
105
105
  triage_node = Node(triage, name="triage")
@@ -328,6 +328,19 @@ flow focused on high-level orchestration logic.
328
328
 
329
329
  ---
330
330
 
331
+ ### Visualization
332
+
333
+ Need a quick view of the flow topology? Call `flow_to_mermaid(flow)` to render the graph
334
+ as a Mermaid diagram ready for Markdown or docs tools:
335
+
336
+ ```python
337
+ from penguiflow import flow_to_mermaid
338
+
339
+ print(flow_to_mermaid(flow, direction="LR"))
340
+ ```
341
+
342
+ ---
343
+
331
344
  ## 🛡️ Reliability & Observability
332
345
 
333
346
  * **NodePolicy**: set validation scope plus per-node timeout, retries, and backoff curves.
@@ -346,6 +359,14 @@ flow focused on high-level orchestration logic.
346
359
 
347
360
  ---
348
361
 
362
+ ## 📊 Benchmarks
363
+
364
+ Lightweight benchmarks live under `benchmarks/`. Run them via `uv run python benchmarks/<name>.py`
365
+ to capture baselines for fan-out throughput, retry/timeout overhead, and controller
366
+ playbook latency. Copy them into product repos to watch for regressions over time.
367
+
368
+ ---
369
+
349
370
  ## 🔮 Roadmap
350
371
 
351
372
  * **v1 (current)**: safe core runtime, type-safety, retries, timeouts, routing, controller loops, playbooks via examples.
@@ -18,4 +18,5 @@ tests/test_controller.py
18
18
  tests/test_core.py
19
19
  tests/test_patterns.py
20
20
  tests/test_registry.py
21
- tests/test_types.py
21
+ tests/test_types.py
22
+ tests/test_viz.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "penguiflow"
7
- version = "1.0.2"
7
+ version = "1.0.3"
8
8
  description = "Async agent orchestration primitives."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -0,0 +1,29 @@
1
+ """Tests for visualization helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import pytest
6
+
7
+ from penguiflow import Node, NodePolicy, create
8
+ from penguiflow.viz import flow_to_mermaid
9
+
10
+
11
+ @pytest.mark.asyncio
12
+ async def test_flow_to_mermaid_renders_edges() -> None:
13
+ async def fan(msg: str, ctx) -> str:
14
+ return msg
15
+
16
+ async def sink(msg: str, ctx) -> str:
17
+ return msg
18
+
19
+ fan_node = Node(fan, name="fan", policy=NodePolicy(validate="none"))
20
+ sink_node = Node(sink, name="sink", policy=NodePolicy(validate="none"))
21
+
22
+ flow = create(fan_node.to(sink_node))
23
+
24
+ mermaid = flow_to_mermaid(flow)
25
+
26
+ assert mermaid.startswith("graph TD")
27
+ assert "fan" in mermaid
28
+ assert "sink" in mermaid
29
+ assert "-->" in mermaid
@@ -1,5 +0,0 @@
1
- """Visualization helpers for PenguiFlow graphs."""
2
-
3
- from __future__ import annotations
4
-
5
- __all__: list[str] = []
File without changes
File without changes