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.
- examples/__init__.py +0 -0
- examples/controller_multihop/__init__.py +0 -0
- examples/controller_multihop/flow.py +54 -0
- examples/fanout_join/__init__.py +0 -0
- examples/fanout_join/flow.py +54 -0
- examples/map_concurrent/__init__.py +0 -0
- examples/map_concurrent/flow.py +56 -0
- examples/metadata_propagation/flow.py +61 -0
- examples/mlflow_metrics/__init__.py +1 -0
- examples/mlflow_metrics/flow.py +120 -0
- examples/playbook_retrieval/__init__.py +0 -0
- examples/playbook_retrieval/flow.py +61 -0
- examples/quickstart/__init__.py +0 -0
- examples/quickstart/flow.py +74 -0
- examples/react_minimal/main.py +109 -0
- examples/react_parallel/main.py +121 -0
- examples/react_pause_resume/main.py +157 -0
- examples/react_replan/main.py +133 -0
- examples/reliability_middleware/__init__.py +0 -0
- examples/reliability_middleware/flow.py +67 -0
- examples/roadmap_status_updates/__init__.py +0 -0
- examples/roadmap_status_updates/flow.py +640 -0
- examples/roadmap_status_updates_subflows/__init__.py +0 -0
- examples/roadmap_status_updates_subflows/flow.py +814 -0
- examples/routing_policy/__init__.py +0 -0
- examples/routing_policy/flow.py +89 -0
- examples/routing_predicate/__init__.py +0 -0
- examples/routing_predicate/flow.py +51 -0
- examples/routing_union/__init__.py +0 -0
- examples/routing_union/flow.py +56 -0
- examples/status_roadmap_flow/__init__.py +0 -0
- examples/status_roadmap_flow/flow.py +458 -0
- examples/streaming_llm/__init__.py +3 -0
- examples/streaming_llm/flow.py +77 -0
- examples/testkit_demo/flow.py +34 -0
- examples/trace_cancel/flow.py +78 -0
- examples/traceable_errors/flow.py +51 -0
- examples/visualizer/flow.py +49 -0
- penguiflow/__init__.py +1 -1
- penguiflow/core.py +24 -1
- {penguiflow-2.2.2.dist-info → penguiflow-2.2.4.dist-info}/METADATA +4 -1
- penguiflow-2.2.4.dist-info/RECORD +68 -0
- {penguiflow-2.2.2.dist-info → penguiflow-2.2.4.dist-info}/top_level.txt +1 -0
- penguiflow-2.2.2.dist-info/RECORD +0 -30
- {penguiflow-2.2.2.dist-info → penguiflow-2.2.4.dist-info}/WHEEL +0 -0
- {penguiflow-2.2.2.dist-info → penguiflow-2.2.4.dist-info}/entry_points.txt +0 -0
- {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
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
|
-
|
|
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.
|
|
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,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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|