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.
- {penguiflow-1.0.2 → penguiflow-1.0.3}/PKG-INFO +23 -2
- {penguiflow-1.0.2 → penguiflow-1.0.3}/README.md +22 -1
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/__init__.py +3 -1
- penguiflow-1.0.3/penguiflow/viz.py +76 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow.egg-info/PKG-INFO +23 -2
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow.egg-info/SOURCES.txt +2 -1
- {penguiflow-1.0.2 → penguiflow-1.0.3}/pyproject.toml +1 -1
- penguiflow-1.0.3/tests/test_viz.py +29 -0
- penguiflow-1.0.2/penguiflow/viz.py +0 -5
- {penguiflow-1.0.2 → penguiflow-1.0.3}/LICENSE +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/core.py +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/middlewares.py +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/node.py +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/patterns.py +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/registry.py +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow/types.py +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow.egg-info/dependency_links.txt +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow.egg-info/requires.txt +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/penguiflow.egg-info/top_level.txt +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/setup.cfg +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/tests/test_controller.py +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/tests/test_core.py +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/tests/test_patterns.py +0 -0
- {penguiflow-1.0.2 → penguiflow-1.0.3}/tests/test_registry.py +0 -0
- {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.
|
|
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(
|
|
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(
|
|
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.
|
|
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.
|
|
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(
|
|
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.
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|