penguiflow 2.2.2__py3-none-any.whl → 2.2.4__py3-none-any.whl

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 (47) hide show
  1. examples/__init__.py +0 -0
  2. examples/controller_multihop/__init__.py +0 -0
  3. examples/controller_multihop/flow.py +54 -0
  4. examples/fanout_join/__init__.py +0 -0
  5. examples/fanout_join/flow.py +54 -0
  6. examples/map_concurrent/__init__.py +0 -0
  7. examples/map_concurrent/flow.py +56 -0
  8. examples/metadata_propagation/flow.py +61 -0
  9. examples/mlflow_metrics/__init__.py +1 -0
  10. examples/mlflow_metrics/flow.py +120 -0
  11. examples/playbook_retrieval/__init__.py +0 -0
  12. examples/playbook_retrieval/flow.py +61 -0
  13. examples/quickstart/__init__.py +0 -0
  14. examples/quickstart/flow.py +74 -0
  15. examples/react_minimal/main.py +109 -0
  16. examples/react_parallel/main.py +121 -0
  17. examples/react_pause_resume/main.py +157 -0
  18. examples/react_replan/main.py +133 -0
  19. examples/reliability_middleware/__init__.py +0 -0
  20. examples/reliability_middleware/flow.py +67 -0
  21. examples/roadmap_status_updates/__init__.py +0 -0
  22. examples/roadmap_status_updates/flow.py +640 -0
  23. examples/roadmap_status_updates_subflows/__init__.py +0 -0
  24. examples/roadmap_status_updates_subflows/flow.py +814 -0
  25. examples/routing_policy/__init__.py +0 -0
  26. examples/routing_policy/flow.py +89 -0
  27. examples/routing_predicate/__init__.py +0 -0
  28. examples/routing_predicate/flow.py +51 -0
  29. examples/routing_union/__init__.py +0 -0
  30. examples/routing_union/flow.py +56 -0
  31. examples/status_roadmap_flow/__init__.py +0 -0
  32. examples/status_roadmap_flow/flow.py +458 -0
  33. examples/streaming_llm/__init__.py +3 -0
  34. examples/streaming_llm/flow.py +77 -0
  35. examples/testkit_demo/flow.py +34 -0
  36. examples/trace_cancel/flow.py +78 -0
  37. examples/traceable_errors/flow.py +51 -0
  38. examples/visualizer/flow.py +49 -0
  39. penguiflow/__init__.py +1 -1
  40. penguiflow/core.py +24 -1
  41. {penguiflow-2.2.2.dist-info → penguiflow-2.2.4.dist-info}/METADATA +4 -1
  42. penguiflow-2.2.4.dist-info/RECORD +68 -0
  43. {penguiflow-2.2.2.dist-info → penguiflow-2.2.4.dist-info}/top_level.txt +1 -0
  44. penguiflow-2.2.2.dist-info/RECORD +0 -30
  45. {penguiflow-2.2.2.dist-info → penguiflow-2.2.4.dist-info}/WHEEL +0 -0
  46. {penguiflow-2.2.2.dist-info → penguiflow-2.2.4.dist-info}/entry_points.txt +0 -0
  47. {penguiflow-2.2.2.dist-info → penguiflow-2.2.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,77 @@
1
+ """Mock LLM streaming example."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from collections import defaultdict
7
+
8
+ from penguiflow import (
9
+ Headers,
10
+ Message,
11
+ Node,
12
+ NodePolicy,
13
+ StreamChunk,
14
+ chunk_to_ws_json,
15
+ create,
16
+ format_sse_event,
17
+ )
18
+
19
+
20
+ async def mock_llm(message: Message, ctx) -> None:
21
+ """Emit streaming tokens for an incoming prompt."""
22
+
23
+ prompt = str(message.payload)
24
+ tokens = prompt.split()
25
+
26
+ for idx, token in enumerate(tokens):
27
+ await asyncio.sleep(0.05)
28
+ done = idx == len(tokens) - 1
29
+ text = token + (" " if not done else "")
30
+ await ctx.emit_chunk(
31
+ parent=message,
32
+ text=text,
33
+ done=done,
34
+ meta={"token_index": idx},
35
+ )
36
+
37
+
38
+ BUFFERS: defaultdict[str, list[str]] = defaultdict(list)
39
+
40
+
41
+ async def sse_sink(message: Message, _ctx) -> str | None:
42
+ """Print Server-Sent Events payloads and return final text when complete."""
43
+
44
+ chunk = message.payload
45
+ assert isinstance(chunk, StreamChunk)
46
+
47
+ buffer = BUFFERS[chunk.stream_id]
48
+ buffer.append(chunk.text)
49
+
50
+ print(format_sse_event(chunk), end="")
51
+ if chunk.done:
52
+ final_text = "".join(BUFFERS.pop(chunk.stream_id))
53
+ print(chunk_to_ws_json(chunk))
54
+ return final_text
55
+ return None
56
+
57
+
58
+ async def main() -> None:
59
+ llm_node = Node(mock_llm, name="mock_llm", policy=NodePolicy(validate="none"))
60
+ sink_node = Node(sse_sink, name="sse_sink", policy=NodePolicy(validate="none"))
61
+ flow = create(llm_node.to(sink_node))
62
+ flow.run()
63
+
64
+ message = Message(
65
+ payload="Penguins huddle to stay warm",
66
+ headers=Headers(tenant="demo"),
67
+ )
68
+
69
+ await flow.emit(message)
70
+ final_text = await flow.fetch()
71
+ print(f"final: {final_text}")
72
+
73
+ await flow.stop()
74
+
75
+
76
+ if __name__ == "__main__": # pragma: no cover
77
+ asyncio.run(main())
@@ -0,0 +1,34 @@
1
+ import asyncio
2
+
3
+ from penguiflow import FinalAnswer, Headers, Message, Node, NodePolicy, create, testkit
4
+
5
+
6
+ async def enrich(message: Message, _ctx) -> Message:
7
+ enriched = message.payload + " ⛸️"
8
+ return message.model_copy(update={"payload": enriched})
9
+
10
+
11
+ async def finalize(message: Message, _ctx) -> Message:
12
+ answer = FinalAnswer(text=message.payload.upper())
13
+ return message.model_copy(update={"payload": answer})
14
+
15
+
16
+ async def main() -> None:
17
+ enrich_node = Node(enrich, name="enrich", policy=NodePolicy(validate="none"))
18
+ final_node = Node(finalize, name="final", policy=NodePolicy(validate="none"))
19
+ flow = create(enrich_node.to(final_node), final_node.to())
20
+
21
+ message = Message(payload="hello penguins", headers=Headers(tenant="demo"))
22
+
23
+ result = await testkit.run_one(flow, message)
24
+ testkit.assert_node_sequence(message.trace_id, ["enrich", "final"])
25
+
26
+ final_answer = result.payload
27
+ if isinstance(final_answer, FinalAnswer):
28
+ print(f"Final answer: {final_answer.text}")
29
+ else:
30
+ print(f"Unexpected payload: {result}")
31
+
32
+
33
+ if __name__ == "__main__":
34
+ asyncio.run(main())
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from typing import Any
5
+
6
+ from penguiflow import Headers, Message, Node, NodePolicy, create
7
+
8
+ _started = asyncio.Event()
9
+
10
+
11
+ def build_cancel_playbook() -> tuple[Any, Any]:
12
+ async def sub_worker(message: Message, _ctx) -> Message:
13
+ print(f"subflow: started for trace {message.trace_id}")
14
+ _started.set()
15
+ try:
16
+ await asyncio.sleep(1.0)
17
+ except asyncio.CancelledError:
18
+ print(f"subflow: received cancellation for trace {message.trace_id}")
19
+ raise
20
+ return message
21
+
22
+ node = Node(sub_worker, name="sub", policy=NodePolicy(validate="none"))
23
+ return create(node.to()), None
24
+
25
+
26
+ async def controller(message: Message, ctx) -> Message:
27
+ await ctx.call_playbook(build_cancel_playbook, message)
28
+ return message
29
+
30
+
31
+ async def sink(message: Message, _ctx) -> str:
32
+ return str(message.payload)
33
+
34
+
35
+ async def _metrics_printer(event: str, payload: dict[str, object]) -> None:
36
+ if event.startswith("trace_cancel"):
37
+ pending = payload["trace_pending"]
38
+ inflight = payload["trace_inflight"]
39
+ q_in = payload["q_depth_in"]
40
+ q_out = payload["q_depth_out"]
41
+ print(
42
+ f"{event} pending={pending} inflight={inflight} "
43
+ f"q_in={q_in} q_out={q_out}"
44
+ )
45
+
46
+
47
+ async def main() -> None:
48
+ controller_node = Node(
49
+ controller,
50
+ name="controller",
51
+ policy=NodePolicy(validate="none"),
52
+ )
53
+ sink_node = Node(
54
+ sink,
55
+ name="sink",
56
+ policy=NodePolicy(validate="none"),
57
+ )
58
+
59
+ flow = create(controller_node.to(sink_node))
60
+ flow.add_middleware(_metrics_printer)
61
+ flow.run()
62
+
63
+ cancel_msg = Message(payload="cancel-me", headers=Headers(tenant="demo"))
64
+ safe_msg = Message(payload="safe", headers=Headers(tenant="demo"))
65
+
66
+ await flow.emit(cancel_msg)
67
+ await _started.wait()
68
+ await flow.cancel(cancel_msg.trace_id)
69
+
70
+ await flow.emit(safe_msg)
71
+ safe_result = await flow.fetch()
72
+ print(f"safe result: {safe_result}")
73
+
74
+ await flow.stop()
75
+
76
+
77
+ if __name__ == "__main__": # pragma: no cover
78
+ asyncio.run(main())
@@ -0,0 +1,51 @@
1
+ """Example showcasing FlowError emission to the Rookery."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+
7
+ from penguiflow import (
8
+ FlowError,
9
+ Headers,
10
+ Message,
11
+ Node,
12
+ NodePolicy,
13
+ create,
14
+ )
15
+
16
+
17
+ async def flaky_node(message: Message, _ctx) -> Message:
18
+ raise RuntimeError("external service unavailable")
19
+
20
+
21
+ async def main() -> None:
22
+ node = Node(
23
+ flaky_node,
24
+ name="flaky", # keep a readable name for error payloads
25
+ policy=NodePolicy(validate="none", max_retries=1, timeout_s=0.05),
26
+ )
27
+
28
+ flow = create(node.to(), emit_errors_to_rookery=True)
29
+ flow.run()
30
+
31
+ message = Message(payload="trigger", headers=Headers(tenant="demo"))
32
+
33
+ await flow.emit(message)
34
+ result = await flow.fetch()
35
+
36
+ if isinstance(result, FlowError):
37
+ payload = result.to_payload()
38
+ print(
39
+ "flow error captured:",
40
+ payload["code"],
41
+ payload.get("message"),
42
+ "trace=", payload.get("trace_id"),
43
+ )
44
+ else: # pragma: no cover - defensive
45
+ print("unexpected result:", result)
46
+
47
+ await flow.stop()
48
+
49
+
50
+ if __name__ == "__main__": # pragma: no cover
51
+ asyncio.run(main())
@@ -0,0 +1,49 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from penguiflow import Node, NodePolicy, create, flow_to_dot, flow_to_mermaid
6
+
7
+
8
+ async def controller(message: str, ctx) -> str:
9
+ """Simple controller that loops until it receives STOP."""
10
+
11
+ if message == "STOP":
12
+ return message
13
+ return message
14
+
15
+
16
+ async def summarize(message: str, ctx) -> str:
17
+ """Pretend to summarize the accumulated working memory."""
18
+
19
+ return f"summary:{message}"
20
+
21
+
22
+ def build_flow_diagrams() -> None:
23
+ controller_node = Node(
24
+ controller,
25
+ name="controller",
26
+ allow_cycle=True,
27
+ policy=NodePolicy(validate="none"),
28
+ )
29
+ summarize_node = Node(
30
+ summarize,
31
+ name="summarize",
32
+ policy=NodePolicy(validate="none"),
33
+ )
34
+
35
+ flow = create(controller_node.to(controller_node, summarize_node))
36
+
37
+ mermaid = flow_to_mermaid(flow, direction="LR")
38
+ dot = flow_to_dot(flow, rankdir="LR")
39
+
40
+ base = Path(__file__).parent
41
+ (base / "diagram.md").write_text(f"```mermaid\n{mermaid}\n```\n", encoding="utf-8")
42
+ (base / "diagram.dot").write_text(f"{dot}\n", encoding="utf-8")
43
+
44
+ print("Mermaid diagram written to diagram.md")
45
+ print("DOT diagram written to diagram.dot")
46
+
47
+
48
+ if __name__ == "__main__": # pragma: no cover - manual example
49
+ build_flow_diagrams()
penguiflow/__init__.py CHANGED
@@ -105,4 +105,4 @@ __all__ = [
105
105
  "TrajectoryStep",
106
106
  ]
107
107
 
108
- __version__ = "2.2.2"
108
+ __version__ = "2.2.4"
penguiflow/core.py CHANGED
@@ -14,6 +14,7 @@ from collections import deque
14
14
  from collections.abc import Awaitable, Callable, Mapping, Sequence
15
15
  from contextlib import suppress
16
16
  from dataclasses import dataclass
17
+ from types import TracebackType
17
18
  from typing import Any, cast
18
19
 
19
20
  from .bus import BusEnvelope, MessageBus
@@ -27,6 +28,14 @@ from .types import WM, FinalAnswer, Message, StreamChunk
27
28
 
28
29
  logger = logging.getLogger("penguiflow.core")
29
30
 
31
+ ExcInfo = tuple[type[BaseException], BaseException, TracebackType | None]
32
+
33
+
34
+ def _capture_exc_info(exc: BaseException | None) -> ExcInfo | None:
35
+ if exc is None:
36
+ return None
37
+ return (type(exc), exc, exc.__traceback__)
38
+
30
39
  BUDGET_EXCEEDED_TEXT = "Hop budget exhausted"
31
40
  DEADLINE_EXCEEDED_TEXT = "Deadline exceeded"
32
41
  TOKEN_BUDGET_EXCEEDED_TEXT = "Token budget exhausted"
@@ -750,6 +759,7 @@ class PenguiFlow:
750
759
  raise
751
760
  except TimeoutError as exc:
752
761
  latency = (time.perf_counter() - start) * 1000
762
+ exc_info = _capture_exc_info(exc)
753
763
  await self._emit_event(
754
764
  event="node_timeout",
755
765
  node=node,
@@ -759,6 +769,7 @@ class PenguiFlow:
759
769
  latency_ms=latency,
760
770
  level=logging.WARNING,
761
771
  extra={"exception": repr(exc)},
772
+ exc_info=exc_info,
762
773
  )
763
774
  if attempt >= node.policy.max_retries:
764
775
  timeout_message: str | None = None
@@ -783,6 +794,7 @@ class PenguiFlow:
783
794
  flow_error=flow_error,
784
795
  latency=latency,
785
796
  attempt=attempt,
797
+ exc_info=exc_info,
786
798
  )
787
799
  return
788
800
  attempt += 1
@@ -801,6 +813,7 @@ class PenguiFlow:
801
813
  continue
802
814
  except Exception as exc: # noqa: BLE001
803
815
  latency = (time.perf_counter() - start) * 1000
816
+ exc_info = _capture_exc_info(exc)
804
817
  await self._emit_event(
805
818
  event="node_error",
806
819
  node=node,
@@ -810,6 +823,7 @@ class PenguiFlow:
810
823
  latency_ms=latency,
811
824
  level=logging.ERROR,
812
825
  extra={"exception": repr(exc)},
826
+ exc_info=exc_info,
813
827
  )
814
828
  if attempt >= node.policy.max_retries:
815
829
  flow_error = self._create_flow_error(
@@ -830,6 +844,7 @@ class PenguiFlow:
830
844
  flow_error=flow_error,
831
845
  latency=latency,
832
846
  attempt=attempt,
847
+ exc_info=exc_info,
833
848
  )
834
849
  return
835
850
  attempt += 1
@@ -890,6 +905,7 @@ class PenguiFlow:
890
905
  flow_error: FlowError,
891
906
  latency: float | None,
892
907
  attempt: int,
908
+ exc_info: ExcInfo | None,
893
909
  ) -> None:
894
910
  original = flow_error.unwrap()
895
911
  exception_repr = repr(original) if original is not None else flow_error.message
@@ -906,6 +922,7 @@ class PenguiFlow:
906
922
  latency_ms=latency,
907
923
  level=logging.ERROR,
908
924
  extra=extra,
925
+ exc_info=exc_info,
909
926
  )
910
927
  if self._emit_errors_to_rookery and flow_error.trace_id is not None:
911
928
  await self._emit_to_rookery(flow_error, source=context.owner)
@@ -1365,6 +1382,7 @@ class PenguiFlow:
1365
1382
  latency_ms: float | None,
1366
1383
  level: int,
1367
1384
  extra: dict[str, Any] | None = None,
1385
+ exc_info: ExcInfo | None = None,
1368
1386
  ) -> None:
1369
1387
  node_name = getattr(node, "name", None)
1370
1388
  node_id = getattr(node, "node_id", node_name)
@@ -1398,7 +1416,12 @@ class PenguiFlow:
1398
1416
  extra=extra or {},
1399
1417
  )
1400
1418
 
1401
- logger.log(level, event, extra=event_obj.to_payload())
1419
+ payload = event_obj.to_payload()
1420
+ log_kwargs: dict[str, Any] = {"extra": payload}
1421
+ if exc_info is not None:
1422
+ log_kwargs["exc_info"] = exc_info
1423
+
1424
+ logger.log(level, event, **log_kwargs)
1402
1425
 
1403
1426
  if self._state_store is not None:
1404
1427
  stored_event = StoredEvent.from_flow_event(event_obj)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: penguiflow
3
- Version: 2.2.2
3
+ Version: 2.2.4
4
4
  Summary: Async agent orchestration primitives.
5
5
  Author: PenguiFlow Team
6
6
  License: MIT License
@@ -687,9 +687,12 @@ pytest -q
687
687
  * `examples/streaming_llm/`: mock LLM emitting streaming chunks to an SSE sink.
688
688
  * `examples/metadata_propagation/`: attaching and consuming `Message.meta` context.
689
689
  * `examples/visualizer/`: exports Mermaid + DOT diagrams with loop/subflow annotations.
690
+ * `examples/roadmap_status_updates/`: roadmap-aware agent scaffold that streams status updates and final chunks.
691
+ * `examples/status_roadmap_flow/`: roadmap-driven websocket status updates with FlowResponse scaffolding.
690
692
  * `examples/react_minimal/`: JSON-only ReactPlanner loop with a stubbed LLM.
691
693
  * `examples/react_pause_resume/`: Phase B planner features with pause/resume and developer hints.
692
694
 
695
+
693
696
  ---
694
697
 
695
698
  ## 🤝 Contributing
@@ -0,0 +1,68 @@
1
+ examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ examples/controller_multihop/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ examples/controller_multihop/flow.py,sha256=OWDt62vriJQLbT903xwMSzLodpKu3yNKrsOcTHhRJ54,1335
4
+ examples/fanout_join/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ examples/fanout_join/flow.py,sha256=vYV_8BymsEngYXOqr2CESHF6bSZyNE889-LFbIksNp4,1426
6
+ examples/map_concurrent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ examples/map_concurrent/flow.py,sha256=VwY17FJip1ECLjTjW4ngjvrIGpRQwsYUGd8trjbizUY,1736
8
+ examples/metadata_propagation/flow.py,sha256=j7Jq-5sxSPrwdOgZkQWTeHy40JZjovhqBxY_R_RGmXY,1561
9
+ examples/mlflow_metrics/__init__.py,sha256=wtVt6xOTCKbE-FZWzCFgGdvSVQCU7kgPEw_cC-1g0F8,36
10
+ examples/mlflow_metrics/flow.py,sha256=lXErUrktpoZtg1tySblCIJsBPXn4Q2Z_xwlyp8bgo4s,4108
11
+ examples/playbook_retrieval/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ examples/playbook_retrieval/flow.py,sha256=QvPsQjZc7syg5hsvIpYmicqQ_MFvC3KQByPeRL4THmw,1922
13
+ examples/quickstart/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ examples/quickstart/flow.py,sha256=MRwH8r2jTyUeV69dsZpXf_LKVcRltGlkX6ZSRDslMc4,1833
15
+ examples/react_minimal/main.py,sha256=DI7tkIuo8aRq0f_ztp-w6jYSxPa5_DL2lsSxLE6-AzY,2875
16
+ examples/react_parallel/main.py,sha256=PEiZ7eVCvFFPwTxFxNGJY_5zn-AUsyiEMGZNtFSCz40,3449
17
+ examples/react_pause_resume/main.py,sha256=n-mZWEn5r9PhWbUiq9vizwW8WjvFDi1Xts7h7Fw_5Lg,4758
18
+ examples/react_replan/main.py,sha256=PYffkxojH5hbqUfZH2yW-PQD_VQKsCvyG3SChU2-tFE,3656
19
+ examples/reliability_middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ examples/reliability_middleware/flow.py,sha256=3NaLLuVaWz5HLqP8BLdygqqLqavgCRAAeMiSWyBuS90,1522
21
+ examples/roadmap_status_updates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ examples/roadmap_status_updates/flow.py,sha256=aPDq8HRPe1LkJeHntlszbf_AUNLujOLCttjXtg5DOoc,19261
23
+ examples/roadmap_status_updates_subflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ examples/roadmap_status_updates_subflows/flow.py,sha256=jMgHt39PyYm5eii4F7qC6qpYtk9RCBh5sL45-giteD4,25698
25
+ examples/routing_policy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
+ examples/routing_policy/flow.py,sha256=k8zGTDEQ5NPsVL6k1vMUiVKO2YmZaXJeHPS-bd8fq5o,2041
27
+ examples/routing_predicate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ examples/routing_predicate/flow.py,sha256=WtZzhuLqWdjTtkEiBiOGcuHm6VLsNE-9wnjAiNgwUlA,1275
29
+ examples/routing_union/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ examples/routing_union/flow.py,sha256=ynvhYSKqNhr8adf9jJdhW-BwWBJK4Xl3eF73hcPtRJI,1296
31
+ examples/status_roadmap_flow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ examples/status_roadmap_flow/flow.py,sha256=-fVx6DRZin_SuWf2820nQGbFt-6srBZ8iUv1-9aSbFA,14063
33
+ examples/streaming_llm/__init__.py,sha256=l4PbJZqC1LE9iaCqA2Rzt5LNpThEa7ThWngH3diFVCw,51
34
+ examples/streaming_llm/flow.py,sha256=W85Pb91-M6_Q4Tjo9Cg1U42tqFQ6EZmW-qNt1kKXOrM,1872
35
+ examples/testkit_demo/flow.py,sha256=k39Okl6EFO9b1XaQtrbstrpZhWJdNspEQpmT1bRqd1w,1134
36
+ examples/trace_cancel/flow.py,sha256=UlNpX7nI46BTtUx7-ckkN_ls65qqRVQMHNG0hGe1A8w,2144
37
+ examples/traceable_errors/flow.py,sha256=GqRE8OP13bq1xOdn846V5slENXFR94_waD0uZ3NrhA8,1186
38
+ examples/visualizer/flow.py,sha256=KXjmB71GKwk0-Wq51yI2lL3YJ0DkQxL8y5auzJlIoSw,1326
39
+ penguiflow/__init__.py,sha256=OhDLbTttbiiHElY02YjvMdOvdFeXbGZr4Rng4HL54Gc,2435
40
+ penguiflow/admin.py,sha256=093xFkE4bM_2ZhLrzhrEUKtmKHi_yVfMPyaGfwi1rcA,5382
41
+ penguiflow/bus.py,sha256=mb29509_n97A6zwC-6EDpYorfAWFSpwqsMu_WeZhLE8,732
42
+ penguiflow/catalog.py,sha256=z-Drf6PbEkvd65PcBvsVJZBBnM9GwT8ctcMdiIoQ5HY,4673
43
+ penguiflow/core.py,sha256=NJrXfu1YbZyzGaXsSIbwFl8LBslAzntU3LiFgvEqz3s,54755
44
+ penguiflow/debug.py,sha256=KPdpWbascsi1ghu-2HPqRORPM2iqkuV6qWyPc0mAalY,945
45
+ penguiflow/errors.py,sha256=mXpCqZ3zdvz7J7Dck_kcw2BGTIm9yrJAjxp_L8KMY7o,3419
46
+ penguiflow/metrics.py,sha256=KsxH9tUqrYfs3EyccLcM0-haYySAByq7RMnK7q61eRA,3989
47
+ penguiflow/middlewares.py,sha256=cB4SrRciNcKHyLanaMVsfMElt3El0LNCj_3dyik07x4,2864
48
+ penguiflow/node.py,sha256=0NOs3rU6t1tHNNwwJopqzM2ufGcp82JpzhckynWBRqs,3563
49
+ penguiflow/patterns.py,sha256=qtzRSNRKxV5_qEPXhffd15PuCZs0YnoGF80nNUsrcxw,5512
50
+ penguiflow/policies.py,sha256=3w8ionnpTyuA0ZCc3jPpB011L7_i1qlbiO6escY024s,4385
51
+ penguiflow/registry.py,sha256=1nR3J1A6jzuevH8EMn83vCkSnnNKgE28CCO6fXMA3wE,2001
52
+ penguiflow/remote.py,sha256=0-2aW48P8OB8KLEC_7_F_RHtzVJk3huyAMBGdXjmWeA,16426
53
+ penguiflow/state.py,sha256=fBY5d_48hR4XHWVG08FraaQ7u4IVPJwooewfVLmzu1Q,1773
54
+ penguiflow/streaming.py,sha256=RKMm4VfaDA2ceEM_pB2Cuhmpwtdcjj7og-kjXQQDcbc,3863
55
+ penguiflow/testkit.py,sha256=pIFYpu1RfJnW2mbGvUkPhMpL-xDAw0E959oTMxLkLh8,11806
56
+ penguiflow/types.py,sha256=Fl56-b7OwIEUbPMDD1CY09nbOG_tmBw3FUhioojeG5M,1503
57
+ penguiflow/viz.py,sha256=KbBb9kKoL223vj0NgJV_jo5ny-0RTc2gcSBACm0jG8w,5508
58
+ penguiflow/planner/__init__.py,sha256=y-dCNIQmkqEgzrnVqQSU6i2tB0dwqjb7LgG2lhtLJJ8,459
59
+ penguiflow/planner/prompts.py,sha256=R9LveYlp6JbSIBcZiRjTZYu-eKk3fgrKZH0Jf3pNVvM,7551
60
+ penguiflow/planner/react.py,sha256=WP0WvoDShKf5k0jHLiFtUT4ns5YAgWW348C1YEdkSXo,50321
61
+ penguiflow-2.2.4.dist-info/licenses/LICENSE,sha256=JSvodvLXxSct_kI9IBsZOBpVKoESQTB_AGbkClwZ7HI,1065
62
+ penguiflow_a2a/__init__.py,sha256=JuK_ov06yS2H97D2OVXhgX8LcgdOqE3EujUPaDKaduc,342
63
+ penguiflow_a2a/server.py,sha256=VMBO-oGjB6Z9mtRBU0z7ZFGprDUC_kihZJukh3budbs,25932
64
+ penguiflow-2.2.4.dist-info/METADATA,sha256=cnpv2G4qTgOOB_p3ITVkjFBjcDsGuR8nDXx2ae_ZxFE,28150
65
+ penguiflow-2.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
66
+ penguiflow-2.2.4.dist-info/entry_points.txt,sha256=F2KxANLEVGRbpWLmcHcvYrTVLWbKWdmk3VOe98a7t9I,59
67
+ penguiflow-2.2.4.dist-info/top_level.txt,sha256=3vpgBt9ye3flT7bZ2cM0D5_eGk0xt_k8x5X9SizoW_g,35
68
+ penguiflow-2.2.4.dist-info/RECORD,,
@@ -1,2 +1,3 @@
1
+ examples
1
2
  penguiflow
2
3
  penguiflow_a2a
@@ -1,30 +0,0 @@
1
- penguiflow/__init__.py,sha256=DX6MR_htAwn0VSZpMQiT3bqqNVcnJvin5fMvgvGMQ8Q,2435
2
- penguiflow/admin.py,sha256=093xFkE4bM_2ZhLrzhrEUKtmKHi_yVfMPyaGfwi1rcA,5382
3
- penguiflow/bus.py,sha256=mb29509_n97A6zwC-6EDpYorfAWFSpwqsMu_WeZhLE8,732
4
- penguiflow/catalog.py,sha256=z-Drf6PbEkvd65PcBvsVJZBBnM9GwT8ctcMdiIoQ5HY,4673
5
- penguiflow/core.py,sha256=7w3fbyfQspt0aRt5nfDcr2kzPzX7Tf7O83v-U64DfHI,53960
6
- penguiflow/debug.py,sha256=KPdpWbascsi1ghu-2HPqRORPM2iqkuV6qWyPc0mAalY,945
7
- penguiflow/errors.py,sha256=mXpCqZ3zdvz7J7Dck_kcw2BGTIm9yrJAjxp_L8KMY7o,3419
8
- penguiflow/metrics.py,sha256=KsxH9tUqrYfs3EyccLcM0-haYySAByq7RMnK7q61eRA,3989
9
- penguiflow/middlewares.py,sha256=cB4SrRciNcKHyLanaMVsfMElt3El0LNCj_3dyik07x4,2864
10
- penguiflow/node.py,sha256=0NOs3rU6t1tHNNwwJopqzM2ufGcp82JpzhckynWBRqs,3563
11
- penguiflow/patterns.py,sha256=qtzRSNRKxV5_qEPXhffd15PuCZs0YnoGF80nNUsrcxw,5512
12
- penguiflow/policies.py,sha256=3w8ionnpTyuA0ZCc3jPpB011L7_i1qlbiO6escY024s,4385
13
- penguiflow/registry.py,sha256=1nR3J1A6jzuevH8EMn83vCkSnnNKgE28CCO6fXMA3wE,2001
14
- penguiflow/remote.py,sha256=0-2aW48P8OB8KLEC_7_F_RHtzVJk3huyAMBGdXjmWeA,16426
15
- penguiflow/state.py,sha256=fBY5d_48hR4XHWVG08FraaQ7u4IVPJwooewfVLmzu1Q,1773
16
- penguiflow/streaming.py,sha256=RKMm4VfaDA2ceEM_pB2Cuhmpwtdcjj7og-kjXQQDcbc,3863
17
- penguiflow/testkit.py,sha256=pIFYpu1RfJnW2mbGvUkPhMpL-xDAw0E959oTMxLkLh8,11806
18
- penguiflow/types.py,sha256=Fl56-b7OwIEUbPMDD1CY09nbOG_tmBw3FUhioojeG5M,1503
19
- penguiflow/viz.py,sha256=KbBb9kKoL223vj0NgJV_jo5ny-0RTc2gcSBACm0jG8w,5508
20
- penguiflow/planner/__init__.py,sha256=y-dCNIQmkqEgzrnVqQSU6i2tB0dwqjb7LgG2lhtLJJ8,459
21
- penguiflow/planner/prompts.py,sha256=R9LveYlp6JbSIBcZiRjTZYu-eKk3fgrKZH0Jf3pNVvM,7551
22
- penguiflow/planner/react.py,sha256=WP0WvoDShKf5k0jHLiFtUT4ns5YAgWW348C1YEdkSXo,50321
23
- penguiflow-2.2.2.dist-info/licenses/LICENSE,sha256=JSvodvLXxSct_kI9IBsZOBpVKoESQTB_AGbkClwZ7HI,1065
24
- penguiflow_a2a/__init__.py,sha256=JuK_ov06yS2H97D2OVXhgX8LcgdOqE3EujUPaDKaduc,342
25
- penguiflow_a2a/server.py,sha256=VMBO-oGjB6Z9mtRBU0z7ZFGprDUC_kihZJukh3budbs,25932
26
- penguiflow-2.2.2.dist-info/METADATA,sha256=bVu1DkWE8uXM3y2tcoFpiyjA7CBsEYlpDnirDXQNtUo,27930
27
- penguiflow-2.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
- penguiflow-2.2.2.dist-info/entry_points.txt,sha256=F2KxANLEVGRbpWLmcHcvYrTVLWbKWdmk3VOe98a7t9I,59
29
- penguiflow-2.2.2.dist-info/top_level.txt,sha256=K-fTwLA14n0u_LDxDBCV7FmeBnJffhTOtUbTtOymQns,26
30
- penguiflow-2.2.2.dist-info/RECORD,,