waldiez 0.2.2__py3-none-any.whl → 0.3.1__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 waldiez might be problematic. Click here for more details.
- waldiez/__init__.py +2 -0
- waldiez/__main__.py +2 -0
- waldiez/_version.py +3 -1
- waldiez/cli.py +13 -3
- waldiez/cli_extras.py +4 -3
- waldiez/conflict_checker.py +4 -3
- waldiez/exporter.py +28 -105
- waldiez/exporting/__init__.py +8 -9
- waldiez/exporting/agent/__init__.py +7 -0
- waldiez/exporting/agent/agent_exporter.py +279 -0
- waldiez/exporting/agent/utils/__init__.py +23 -0
- waldiez/exporting/agent/utils/agent_class_name.py +34 -0
- waldiez/exporting/agent/utils/agent_imports.py +50 -0
- waldiez/exporting/{agents → agent/utils}/code_execution.py +9 -11
- waldiez/exporting/{agents → agent/utils}/group_manager.py +47 -35
- waldiez/exporting/{agents → agent/utils}/rag_user/__init__.py +2 -0
- waldiez/exporting/{agents → agent/utils}/rag_user/chroma_utils.py +22 -17
- waldiez/exporting/{agents → agent/utils}/rag_user/mongo_utils.py +14 -10
- waldiez/exporting/{agents → agent/utils}/rag_user/pgvector_utils.py +12 -8
- waldiez/exporting/{agents → agent/utils}/rag_user/qdrant_utils.py +11 -8
- waldiez/exporting/{agents → agent/utils}/rag_user/rag_user.py +78 -55
- waldiez/exporting/{agents → agent/utils}/rag_user/vector_db.py +10 -8
- waldiez/exporting/agent/utils/swarm_agent.py +463 -0
- waldiez/exporting/{agents → agent/utils}/teachability.py +10 -6
- waldiez/exporting/{agents → agent/utils}/termination_message.py +7 -8
- waldiez/exporting/base/__init__.py +25 -0
- waldiez/exporting/base/agent_position.py +75 -0
- waldiez/exporting/base/base_exporter.py +118 -0
- waldiez/exporting/base/export_position.py +48 -0
- waldiez/exporting/base/import_position.py +23 -0
- waldiez/exporting/base/mixin.py +134 -0
- waldiez/exporting/base/utils/__init__.py +18 -0
- waldiez/exporting/{utils → base/utils}/comments.py +12 -55
- waldiez/exporting/{utils → base/utils}/naming.py +14 -4
- waldiez/exporting/base/utils/path_check.py +68 -0
- waldiez/exporting/{utils/object_string.py → base/utils/to_string.py} +21 -20
- waldiez/exporting/chats/__init__.py +5 -12
- waldiez/exporting/chats/chats_exporter.py +240 -0
- waldiez/exporting/chats/utils/__init__.py +15 -0
- waldiez/exporting/chats/utils/common.py +81 -0
- waldiez/exporting/chats/{nested.py → utils/nested.py} +125 -86
- waldiez/exporting/chats/utils/sequential.py +244 -0
- waldiez/exporting/chats/utils/single_chat.py +313 -0
- waldiez/exporting/chats/utils/swarm.py +207 -0
- waldiez/exporting/flow/__init__.py +5 -3
- waldiez/exporting/flow/flow_exporter.py +503 -0
- waldiez/exporting/flow/utils/__init__.py +47 -0
- waldiez/exporting/flow/utils/agent_utils.py +204 -0
- waldiez/exporting/flow/utils/chat_utils.py +71 -0
- waldiez/exporting/flow/utils/def_main.py +62 -0
- waldiez/exporting/flow/utils/flow_content.py +112 -0
- waldiez/exporting/flow/utils/flow_names.py +115 -0
- waldiez/exporting/flow/utils/importing_utils.py +182 -0
- waldiez/exporting/{utils → flow/utils}/logging_utils.py +34 -31
- waldiez/exporting/models/__init__.py +7 -242
- waldiez/exporting/models/models_exporter.py +192 -0
- waldiez/exporting/models/utils.py +166 -0
- waldiez/exporting/skills/__init__.py +7 -161
- waldiez/exporting/skills/skills_exporter.py +169 -0
- waldiez/exporting/skills/utils.py +281 -0
- waldiez/models/__init__.py +25 -7
- waldiez/models/agents/__init__.py +70 -0
- waldiez/models/agents/agent/__init__.py +11 -1
- waldiez/models/agents/agent/agent.py +9 -4
- waldiez/models/agents/agent/agent_data.py +3 -1
- waldiez/models/agents/agent/code_execution.py +2 -0
- waldiez/models/agents/agent/linked_skill.py +2 -0
- waldiez/models/agents/agent/nested_chat.py +2 -0
- waldiez/models/agents/agent/teachability.py +2 -0
- waldiez/models/agents/agent/termination_message.py +49 -13
- waldiez/models/agents/agents.py +15 -3
- waldiez/models/agents/assistant/__init__.py +2 -0
- waldiez/models/agents/assistant/assistant.py +2 -0
- waldiez/models/agents/assistant/assistant_data.py +2 -0
- waldiez/models/agents/group_manager/__init__.py +9 -1
- waldiez/models/agents/group_manager/group_manager.py +2 -0
- waldiez/models/agents/group_manager/group_manager_data.py +2 -0
- waldiez/models/agents/group_manager/speakers.py +49 -13
- waldiez/models/agents/rag_user/__init__.py +21 -4
- waldiez/models/agents/rag_user/rag_user.py +3 -1
- waldiez/models/agents/rag_user/rag_user_data.py +2 -0
- waldiez/models/agents/rag_user/retrieve_config.py +268 -17
- waldiez/models/agents/rag_user/vector_db_config.py +5 -3
- waldiez/models/agents/swarm_agent/__init__.py +49 -0
- waldiez/models/agents/swarm_agent/after_work.py +178 -0
- waldiez/models/agents/swarm_agent/on_condition.py +103 -0
- waldiez/models/agents/swarm_agent/on_condition_available.py +140 -0
- waldiez/models/agents/swarm_agent/on_condition_target.py +40 -0
- waldiez/models/agents/swarm_agent/swarm_agent.py +107 -0
- waldiez/models/agents/swarm_agent/swarm_agent_data.py +125 -0
- waldiez/models/agents/swarm_agent/update_system_message.py +144 -0
- waldiez/models/agents/user_proxy/__init__.py +2 -0
- waldiez/models/agents/user_proxy/user_proxy.py +2 -0
- waldiez/models/agents/user_proxy/user_proxy_data.py +2 -0
- waldiez/models/chat/__init__.py +21 -3
- waldiez/models/chat/chat.py +241 -7
- waldiez/models/chat/chat_data.py +192 -48
- waldiez/models/chat/chat_message.py +153 -144
- waldiez/models/chat/chat_nested.py +33 -53
- waldiez/models/chat/chat_summary.py +2 -0
- waldiez/models/common/__init__.py +6 -6
- waldiez/models/common/base.py +4 -1
- waldiez/models/common/method_utils.py +163 -83
- waldiez/models/flow/__init__.py +2 -0
- waldiez/models/flow/flow.py +176 -40
- waldiez/models/flow/flow_data.py +63 -2
- waldiez/models/flow/utils.py +172 -0
- waldiez/models/model/__init__.py +2 -0
- waldiez/models/model/model.py +30 -9
- waldiez/models/model/model_data.py +3 -1
- waldiez/models/skill/__init__.py +4 -1
- waldiez/models/skill/skill.py +30 -2
- waldiez/models/skill/skill_data.py +2 -0
- waldiez/models/waldiez.py +28 -4
- waldiez/runner.py +142 -228
- waldiez/running/__init__.py +33 -0
- waldiez/running/environment.py +83 -0
- waldiez/running/gen_seq_diagram.py +185 -0
- waldiez/running/running.py +300 -0
- {waldiez-0.2.2.dist-info → waldiez-0.3.1.dist-info}/METADATA +35 -28
- waldiez-0.3.1.dist-info/RECORD +125 -0
- waldiez-0.3.1.dist-info/licenses/LICENSE +201 -0
- waldiez/exporting/agents/__init__.py +0 -5
- waldiez/exporting/agents/agent.py +0 -236
- waldiez/exporting/agents/agent_skills.py +0 -67
- waldiez/exporting/agents/llm_config.py +0 -53
- waldiez/exporting/chats/chats.py +0 -46
- waldiez/exporting/chats/helpers.py +0 -420
- waldiez/exporting/flow/def_main.py +0 -32
- waldiez/exporting/flow/flow.py +0 -189
- waldiez/exporting/utils/__init__.py +0 -36
- waldiez/exporting/utils/importing.py +0 -265
- waldiez/exporting/utils/method_utils.py +0 -35
- waldiez/exporting/utils/path_check.py +0 -51
- waldiez-0.2.2.dist-info/RECORD +0 -92
- waldiez-0.2.2.dist-info/licenses/LICENSE +0 -21
- {waldiez-0.2.2.dist-info → waldiez-0.3.1.dist-info}/WHEEL +0 -0
- {waldiez-0.2.2.dist-info → waldiez-0.3.1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Generate a Mermaid sequence diagram from a file containing event data."""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Dict, Set, Union
|
|
9
|
+
|
|
10
|
+
import pandas as pd
|
|
11
|
+
|
|
12
|
+
MAX_LEN = 100
|
|
13
|
+
SEQ_TXT = """
|
|
14
|
+
%%{init: {'sequence': {'actorSpacing': 10, 'width': 150}}}%%
|
|
15
|
+
sequenceDiagram
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def escape_mermaid_text(text: str) -> str:
|
|
20
|
+
"""Replace newline characters with <br/> for Mermaid compatibility.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
text : str
|
|
25
|
+
The text to escape.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
str
|
|
30
|
+
The escaped text with newline characters replaced by <br/>.
|
|
31
|
+
"""
|
|
32
|
+
if len(text) > MAX_LEN:
|
|
33
|
+
limited_text = text[:MAX_LEN] + "..."
|
|
34
|
+
else:
|
|
35
|
+
limited_text = text
|
|
36
|
+
output = limited_text.replace("\n", "<br/>")
|
|
37
|
+
output = re.sub(r"<br/>\s*<br/>", "<br/><br/>", output)
|
|
38
|
+
return output
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_json_state(json_state: Any) -> Dict[str, Any]:
|
|
42
|
+
"""Get the JSON state of the event.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
json_state : Union[str, dict]
|
|
47
|
+
The JSON state of the event.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
dict
|
|
52
|
+
The JSON state of the event.
|
|
53
|
+
"""
|
|
54
|
+
if isinstance(json_state, dict):
|
|
55
|
+
return json_state
|
|
56
|
+
if isinstance(json_state, str):
|
|
57
|
+
try:
|
|
58
|
+
return json.loads(json_state)
|
|
59
|
+
except json.JSONDecodeError:
|
|
60
|
+
return {}
|
|
61
|
+
return {}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# pylint: disable=too-many-locals
|
|
65
|
+
def process_events(df_events: pd.DataFrame) -> str:
|
|
66
|
+
"""Process the events DataFrame and generate a Mermaid sequence diagram.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
df_events : pd.DataFrame
|
|
71
|
+
The DataFrame containing the events data.
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
str
|
|
75
|
+
The Mermaid sequence diagram text.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
# Set to store participants (senders and recipients)
|
|
79
|
+
participants: Set[str] = set()
|
|
80
|
+
recipient: str
|
|
81
|
+
|
|
82
|
+
# Initialize the sequence diagram text
|
|
83
|
+
seq_text = SEQ_TXT
|
|
84
|
+
|
|
85
|
+
# Loop through each event in the DataFrame
|
|
86
|
+
for i in range(len(df_events["json_state"])):
|
|
87
|
+
# Parse the JSON state of the event
|
|
88
|
+
df_j = get_json_state(df_events["json_state"][i])
|
|
89
|
+
# Skip events that are not relevant (e.g., replies or missing messages)
|
|
90
|
+
if ("message" in df_j.keys()) and (
|
|
91
|
+
df_events["event_name"][i] != "reply_func_executed"
|
|
92
|
+
):
|
|
93
|
+
sender = df_j["sender"]
|
|
94
|
+
recipient = df_events["source_name"][i]
|
|
95
|
+
|
|
96
|
+
# Extract message content if available
|
|
97
|
+
if (
|
|
98
|
+
isinstance(df_j["message"], dict)
|
|
99
|
+
and "content" in df_j["message"]
|
|
100
|
+
):
|
|
101
|
+
message = "Content: " + str(df_j["message"]["content"])
|
|
102
|
+
else:
|
|
103
|
+
message = str(df_j["message"])
|
|
104
|
+
|
|
105
|
+
# Escape the message for Mermaid compatibility and
|
|
106
|
+
# truncate long messages
|
|
107
|
+
message = escape_mermaid_text(message)
|
|
108
|
+
|
|
109
|
+
# Add sender and recipient to participants set
|
|
110
|
+
participants.add(recipient)
|
|
111
|
+
participants.add(sender)
|
|
112
|
+
|
|
113
|
+
# Split message into main message and context
|
|
114
|
+
# if "Content" is present
|
|
115
|
+
if "Content: " in message:
|
|
116
|
+
message_parts = message.split("Content: ")
|
|
117
|
+
main_message = message_parts[0].strip()
|
|
118
|
+
context = "Content: " + message_parts[1].strip()
|
|
119
|
+
seq_text += f" {sender}->>{recipient}: {main_message}\n"
|
|
120
|
+
seq_text += f" note over {recipient}: {context}\n"
|
|
121
|
+
else:
|
|
122
|
+
seq_text += f" {sender}->>{recipient}: {message}\n"
|
|
123
|
+
|
|
124
|
+
# Add participants to the Mermaid diagram
|
|
125
|
+
participants_text = ""
|
|
126
|
+
for participant in participants:
|
|
127
|
+
participant_title = participant.replace("_", " ").title()
|
|
128
|
+
participants_text += (
|
|
129
|
+
f" participant {participant} as {participant_title}" + "\n"
|
|
130
|
+
)
|
|
131
|
+
# Prepend the participants to the sequence diagram text
|
|
132
|
+
mermaid_text = SEQ_TXT + participants_text + seq_text[len(SEQ_TXT) :]
|
|
133
|
+
return mermaid_text
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def save_diagram(mermaid_text: str, output_path: Union[str, Path]) -> None:
|
|
137
|
+
"""Save the Mermaid diagram to a .mmd file.
|
|
138
|
+
|
|
139
|
+
Parameters
|
|
140
|
+
----------
|
|
141
|
+
mermaid_text : str
|
|
142
|
+
The Mermaid sequence diagram text.
|
|
143
|
+
output_path : Union[str, Path]
|
|
144
|
+
The path to save the Mermaid diagram.
|
|
145
|
+
"""
|
|
146
|
+
with open(output_path, "w", encoding="utf-8", newline="\n") as file:
|
|
147
|
+
file.write(mermaid_text)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def generate_sequence_diagram(
|
|
151
|
+
file_path: Union[str, Path], output_path: Union[str, Path]
|
|
152
|
+
) -> None:
|
|
153
|
+
"""Main function to generate the Mermaid diagram.
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
file_path : Union[str, Path]
|
|
158
|
+
The path to the JSON or CSV file containing the events data.
|
|
159
|
+
output_path : Union[str, Path]
|
|
160
|
+
The path to save the Mermaid diagram.
|
|
161
|
+
|
|
162
|
+
Raises
|
|
163
|
+
------
|
|
164
|
+
FileNotFoundError
|
|
165
|
+
If the input file is not found.
|
|
166
|
+
ValueError
|
|
167
|
+
If the input file is not a JSON or CSV file.
|
|
168
|
+
"""
|
|
169
|
+
if isinstance(file_path, str):
|
|
170
|
+
file_path = Path(file_path)
|
|
171
|
+
if not file_path.exists():
|
|
172
|
+
raise FileNotFoundError(f"File not found: {file_path}")
|
|
173
|
+
if file_path.suffix not in [".json", ".csv"]:
|
|
174
|
+
raise ValueError("Input file must be a JSON or CSV file.")
|
|
175
|
+
is_csv = file_path.suffix == ".csv"
|
|
176
|
+
if is_csv:
|
|
177
|
+
df_events = pd.read_csv(file_path)
|
|
178
|
+
else:
|
|
179
|
+
df_events = pd.read_json(file_path)
|
|
180
|
+
|
|
181
|
+
# Generate the Mermaid sequence diagram text
|
|
182
|
+
mermaid_text = process_events(df_events)
|
|
183
|
+
|
|
184
|
+
# Save the Mermaid diagram to a file
|
|
185
|
+
save_diagram(mermaid_text, output_path)
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Utilities for running code."""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import datetime
|
|
7
|
+
import io
|
|
8
|
+
import os
|
|
9
|
+
import shutil
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
12
|
+
import tempfile
|
|
13
|
+
from contextlib import asynccontextmanager, contextmanager
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import (
|
|
16
|
+
AsyncIterator,
|
|
17
|
+
Callable,
|
|
18
|
+
Iterator,
|
|
19
|
+
Optional,
|
|
20
|
+
Set,
|
|
21
|
+
Tuple,
|
|
22
|
+
Union,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from .environment import in_virtualenv
|
|
26
|
+
from .gen_seq_diagram import generate_sequence_diagram
|
|
27
|
+
|
|
28
|
+
# pylint: disable=import-outside-toplevel
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@contextmanager
|
|
32
|
+
def chdir(to: Union[str, Path]) -> Iterator[None]:
|
|
33
|
+
"""Change the current working directory in a context.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
to : Union[str, Path]
|
|
38
|
+
The directory to change to.
|
|
39
|
+
|
|
40
|
+
Yields
|
|
41
|
+
------
|
|
42
|
+
Iterator[None]
|
|
43
|
+
The context manager.
|
|
44
|
+
"""
|
|
45
|
+
old_cwd = str(os.getcwd())
|
|
46
|
+
os.chdir(to)
|
|
47
|
+
try:
|
|
48
|
+
yield
|
|
49
|
+
finally:
|
|
50
|
+
os.chdir(old_cwd)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@asynccontextmanager
|
|
54
|
+
async def a_chdir(to: Union[str, Path]) -> AsyncIterator[None]:
|
|
55
|
+
"""Asynchronously change the current working directory in a context.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
to : Union[str, Path]
|
|
60
|
+
The directory to change to.
|
|
61
|
+
|
|
62
|
+
Yields
|
|
63
|
+
------
|
|
64
|
+
AsyncIterator[None]
|
|
65
|
+
The async context manager.
|
|
66
|
+
"""
|
|
67
|
+
old_cwd = str(os.getcwd())
|
|
68
|
+
os.chdir(to)
|
|
69
|
+
try:
|
|
70
|
+
yield
|
|
71
|
+
finally:
|
|
72
|
+
os.chdir(old_cwd)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def before_run(
|
|
76
|
+
output_path: Optional[Union[str, Path]],
|
|
77
|
+
uploads_root: Optional[Union[str, Path]],
|
|
78
|
+
) -> str:
|
|
79
|
+
"""Actions to perform before running the flow.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
output_path : Optional[Union[str, Path]]
|
|
84
|
+
The output path.
|
|
85
|
+
uploads_root : Optional[Union[str, Path]]
|
|
86
|
+
The runtime uploads root.
|
|
87
|
+
|
|
88
|
+
Returns
|
|
89
|
+
-------
|
|
90
|
+
str
|
|
91
|
+
The file name.
|
|
92
|
+
"""
|
|
93
|
+
printer = get_printer()
|
|
94
|
+
printer(
|
|
95
|
+
"Requirements installed.\n"
|
|
96
|
+
"NOTE: If new packages were added and you are using Jupyter, "
|
|
97
|
+
"you might need to restart the kernel."
|
|
98
|
+
)
|
|
99
|
+
if not uploads_root:
|
|
100
|
+
uploads_root = Path(tempfile.mkdtemp())
|
|
101
|
+
else:
|
|
102
|
+
uploads_root = Path(uploads_root)
|
|
103
|
+
if not uploads_root.exists():
|
|
104
|
+
uploads_root.mkdir(parents=True)
|
|
105
|
+
file_name = "waldiez_flow.py" if not output_path else Path(output_path).name
|
|
106
|
+
if file_name.endswith((".json", ".waldiez")):
|
|
107
|
+
file_name = file_name.replace(".json", ".py").replace(".waldiez", ".py")
|
|
108
|
+
if not file_name.endswith(".py"):
|
|
109
|
+
file_name += ".py"
|
|
110
|
+
return file_name
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def install_requirements(
|
|
114
|
+
extra_requirements: Set[str], printer: Callable[..., None]
|
|
115
|
+
) -> None:
|
|
116
|
+
"""Install the requirements.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
extra_requirements : Set[str]
|
|
121
|
+
The extra requirements.
|
|
122
|
+
printer : Callable[..., None]
|
|
123
|
+
The printer function.
|
|
124
|
+
"""
|
|
125
|
+
requirements_string = ", ".join(extra_requirements)
|
|
126
|
+
printer(f"Installing requirements: {requirements_string}")
|
|
127
|
+
pip_install = [sys.executable, "-m", "pip", "install"]
|
|
128
|
+
if not in_virtualenv():
|
|
129
|
+
pip_install.append("--user")
|
|
130
|
+
pip_install.extend(extra_requirements)
|
|
131
|
+
with subprocess.Popen(
|
|
132
|
+
pip_install,
|
|
133
|
+
stdout=subprocess.PIPE,
|
|
134
|
+
stderr=subprocess.PIPE,
|
|
135
|
+
) as proc:
|
|
136
|
+
if proc.stdout:
|
|
137
|
+
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
|
|
138
|
+
printer(line.strip())
|
|
139
|
+
if proc.stderr:
|
|
140
|
+
for line in io.TextIOWrapper(proc.stderr, encoding="utf-8"):
|
|
141
|
+
printer(line.strip())
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
async def a_install_requirements(
|
|
145
|
+
extra_requirements: Set[str], printer: Callable[..., None]
|
|
146
|
+
) -> None:
|
|
147
|
+
"""Install the requirements asynchronously.
|
|
148
|
+
|
|
149
|
+
Parameters
|
|
150
|
+
----------
|
|
151
|
+
extra_requirements : Set[str]
|
|
152
|
+
The extra requirements.
|
|
153
|
+
printer : Callable[..., None]
|
|
154
|
+
The printer function.
|
|
155
|
+
"""
|
|
156
|
+
requirements_string = ", ".join(extra_requirements)
|
|
157
|
+
printer(f"Installing requirements: {requirements_string}")
|
|
158
|
+
pip_install = [sys.executable, "-m", "pip", "install"]
|
|
159
|
+
if not in_virtualenv():
|
|
160
|
+
pip_install.append("--user")
|
|
161
|
+
pip_install.extend(extra_requirements)
|
|
162
|
+
proc = await asyncio.create_subprocess_exec(
|
|
163
|
+
*pip_install,
|
|
164
|
+
stdout=asyncio.subprocess.PIPE,
|
|
165
|
+
stderr=asyncio.subprocess.PIPE,
|
|
166
|
+
)
|
|
167
|
+
if proc.stdout:
|
|
168
|
+
async for line in proc.stdout:
|
|
169
|
+
printer(line.decode().strip())
|
|
170
|
+
if proc.stderr:
|
|
171
|
+
async for line in proc.stderr:
|
|
172
|
+
printer(line.decode().strip())
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def after_run(
|
|
176
|
+
temp_dir: Path,
|
|
177
|
+
output_path: Optional[Union[str, Path]],
|
|
178
|
+
printer: Callable[..., None],
|
|
179
|
+
flow_name: str,
|
|
180
|
+
skip_mmd: bool = False,
|
|
181
|
+
) -> None:
|
|
182
|
+
"""Actions to perform after running the flow.
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
temp_dir : Path
|
|
187
|
+
The temporary directory.
|
|
188
|
+
output_path : Optional[Union[str, Path]]
|
|
189
|
+
The output path.
|
|
190
|
+
printer : Callable[..., None]
|
|
191
|
+
The printer function.
|
|
192
|
+
flow_name : str
|
|
193
|
+
The flow name.
|
|
194
|
+
skip_mmd : bool, optional
|
|
195
|
+
Whether to skip the mermaid sequence diagram generation,
|
|
196
|
+
by default False
|
|
197
|
+
"""
|
|
198
|
+
if isinstance(output_path, str):
|
|
199
|
+
output_path = Path(output_path)
|
|
200
|
+
output_dir = output_path.parent if output_path else Path.cwd()
|
|
201
|
+
if output_dir.is_file():
|
|
202
|
+
output_dir = output_dir.parent
|
|
203
|
+
if skip_mmd is False:
|
|
204
|
+
events_csv_path = temp_dir / "logs" / "events.csv"
|
|
205
|
+
if events_csv_path.exists():
|
|
206
|
+
printer("Generating mermaid sequence diagram...")
|
|
207
|
+
mmd_path = temp_dir / f"{flow_name}.mmd"
|
|
208
|
+
generate_sequence_diagram(events_csv_path, mmd_path)
|
|
209
|
+
shutil.copyfile(mmd_path, output_dir / f"{flow_name}.mmd")
|
|
210
|
+
if output_path:
|
|
211
|
+
destination_dir = output_path.parent
|
|
212
|
+
destination_dir = (
|
|
213
|
+
destination_dir
|
|
214
|
+
/ "waldiez_out"
|
|
215
|
+
/ datetime.datetime.now().strftime("%Y%m%d%H%M%S")
|
|
216
|
+
)
|
|
217
|
+
destination_dir.mkdir(parents=True, exist_ok=True)
|
|
218
|
+
# copy the contents of the temp dir to the destination dir
|
|
219
|
+
printer(f"Copying the results to {destination_dir}")
|
|
220
|
+
for item in temp_dir.iterdir():
|
|
221
|
+
# skip cache files
|
|
222
|
+
if (
|
|
223
|
+
item.name.startswith("__pycache__")
|
|
224
|
+
or item.name.endswith(".pyc")
|
|
225
|
+
or item.name.endswith(".pyo")
|
|
226
|
+
or item.name.endswith(".pyd")
|
|
227
|
+
or item.name == ".cache"
|
|
228
|
+
):
|
|
229
|
+
continue
|
|
230
|
+
if item.is_file():
|
|
231
|
+
shutil.copy(item, destination_dir)
|
|
232
|
+
else:
|
|
233
|
+
shutil.copytree(item, destination_dir / item.name)
|
|
234
|
+
shutil.rmtree(temp_dir)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def get_printer() -> Callable[..., None]:
|
|
238
|
+
"""Get the printer function.
|
|
239
|
+
|
|
240
|
+
Returns
|
|
241
|
+
-------
|
|
242
|
+
Callable[..., None]
|
|
243
|
+
The printer function.
|
|
244
|
+
"""
|
|
245
|
+
from autogen.io import IOStream # type: ignore
|
|
246
|
+
|
|
247
|
+
printer = IOStream.get_default().print
|
|
248
|
+
|
|
249
|
+
def safe_printer(*args: object, **kwargs: object) -> None:
|
|
250
|
+
try:
|
|
251
|
+
printer(*args, **kwargs)
|
|
252
|
+
except UnicodeEncodeError:
|
|
253
|
+
# pylint: disable=too-many-try-statements
|
|
254
|
+
try:
|
|
255
|
+
msg, flush = get_what_to_print(*args, **kwargs)
|
|
256
|
+
printer(msg, end="", flush=flush)
|
|
257
|
+
except UnicodeEncodeError:
|
|
258
|
+
sys.stdout = io.TextIOWrapper(
|
|
259
|
+
sys.stdout.buffer, encoding="utf-8"
|
|
260
|
+
)
|
|
261
|
+
sys.stderr = io.TextIOWrapper(
|
|
262
|
+
sys.stderr.buffer, encoding="utf-8"
|
|
263
|
+
)
|
|
264
|
+
try:
|
|
265
|
+
printer(*args, **kwargs)
|
|
266
|
+
except UnicodeEncodeError:
|
|
267
|
+
sys.stderr.write(
|
|
268
|
+
"Could not print the message due to encoding issues.\n"
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
return safe_printer
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def get_what_to_print(*args: object, **kwargs: object) -> Tuple[str, bool]:
|
|
275
|
+
"""Get what to print.
|
|
276
|
+
|
|
277
|
+
Parameters
|
|
278
|
+
----------
|
|
279
|
+
args : object
|
|
280
|
+
The arguments.
|
|
281
|
+
kwargs : object
|
|
282
|
+
The keyword arguments.
|
|
283
|
+
|
|
284
|
+
Returns
|
|
285
|
+
-------
|
|
286
|
+
Tuple[str, bool]
|
|
287
|
+
The message and whether to flush.
|
|
288
|
+
"""
|
|
289
|
+
sep = kwargs.get("sep", " ")
|
|
290
|
+
if not isinstance(sep, str):
|
|
291
|
+
sep = " "
|
|
292
|
+
end = kwargs.get("end", "\n")
|
|
293
|
+
if not isinstance(end, str):
|
|
294
|
+
end = "\n"
|
|
295
|
+
flush = kwargs.get("flush", False)
|
|
296
|
+
if not isinstance(flush, bool):
|
|
297
|
+
flush = False
|
|
298
|
+
msg = sep.join(str(arg) for arg in args) + end
|
|
299
|
+
utf8_msg = msg.encode("utf-8", errors="replace").decode("utf-8")
|
|
300
|
+
return utf8_msg, flush
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: waldiez
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: waldiez
|
|
5
5
|
Project-URL: homepage, https://waldiez.github.io/waldiez/python
|
|
6
6
|
Project-URL: repository, https://github.com/waldiez/python.git
|
|
@@ -9,7 +9,7 @@ License-File: LICENSE
|
|
|
9
9
|
Classifier: Development Status :: 3 - Alpha
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: Intended Audience :: Science/Research
|
|
12
|
-
Classifier: License :: OSI Approved ::
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Programming Language :: Python
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -17,43 +17,48 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
19
|
Requires-Python: <3.13,>=3.10
|
|
20
|
+
Requires-Dist: asyncer==0.0.8
|
|
21
|
+
Requires-Dist: httpx<0.28.0,>=0.27.0
|
|
20
22
|
Requires-Dist: jupytext
|
|
21
|
-
Requires-Dist:
|
|
22
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: pandas>=2
|
|
24
|
+
Requires-Dist: parso==0.8.4
|
|
25
|
+
Requires-Dist: pyautogen==0.7.1
|
|
26
|
+
Requires-Dist: pydantic<3,>=2.6.1
|
|
23
27
|
Requires-Dist: typer<0.13,>=0.9
|
|
24
28
|
Provides-Extra: ag2-extras
|
|
25
|
-
Requires-Dist: autogen[captainagent]==0.
|
|
29
|
+
Requires-Dist: autogen[captainagent]==0.7.1; (platform_system == 'Linux') and extra == 'ag2-extras'
|
|
26
30
|
Requires-Dist: pgvector>=0.3.6; extra == 'ag2-extras'
|
|
27
31
|
Requires-Dist: psycopg[binary]>=3.2.3; extra == 'ag2-extras'
|
|
28
|
-
Requires-Dist: pyautogen[anthropic]==0.
|
|
29
|
-
Requires-Dist: pyautogen[bedrock]==0.
|
|
30
|
-
Requires-Dist: pyautogen[gemini]==0.
|
|
31
|
-
Requires-Dist: pyautogen[groq]==0.
|
|
32
|
-
Requires-Dist: pyautogen[lmm]==0.
|
|
33
|
-
Requires-Dist: pyautogen[mistral]==0.
|
|
34
|
-
Requires-Dist: pyautogen[neo4j]==0.
|
|
35
|
-
Requires-Dist: pyautogen[retrievechat-mongodb]==0.
|
|
36
|
-
Requires-Dist: pyautogen[retrievechat-pgvector]==0.
|
|
37
|
-
Requires-Dist: pyautogen[retrievechat-qdrant]==0.
|
|
38
|
-
Requires-Dist: pyautogen[retrievechat]==0.
|
|
39
|
-
Requires-Dist: pyautogen[together]==0.
|
|
40
|
-
Requires-Dist: pyautogen[websurfer]==0.
|
|
32
|
+
Requires-Dist: pyautogen[anthropic]==0.7.1; extra == 'ag2-extras'
|
|
33
|
+
Requires-Dist: pyautogen[bedrock]==0.7.1; extra == 'ag2-extras'
|
|
34
|
+
Requires-Dist: pyautogen[gemini]==0.7.1; extra == 'ag2-extras'
|
|
35
|
+
Requires-Dist: pyautogen[groq]==0.7.1; extra == 'ag2-extras'
|
|
36
|
+
Requires-Dist: pyautogen[lmm]==0.7.1; extra == 'ag2-extras'
|
|
37
|
+
Requires-Dist: pyautogen[mistral]==0.7.1; extra == 'ag2-extras'
|
|
38
|
+
Requires-Dist: pyautogen[neo4j]==0.7.1; extra == 'ag2-extras'
|
|
39
|
+
Requires-Dist: pyautogen[retrievechat-mongodb]==0.7.1; extra == 'ag2-extras'
|
|
40
|
+
Requires-Dist: pyautogen[retrievechat-pgvector]==0.7.1; extra == 'ag2-extras'
|
|
41
|
+
Requires-Dist: pyautogen[retrievechat-qdrant]==0.7.1; (python_version < '3.13') and extra == 'ag2-extras'
|
|
42
|
+
Requires-Dist: pyautogen[retrievechat]==0.7.1; extra == 'ag2-extras'
|
|
43
|
+
Requires-Dist: pyautogen[together]==0.7.1; extra == 'ag2-extras'
|
|
44
|
+
Requires-Dist: pyautogen[websurfer]==0.7.1; extra == 'ag2-extras'
|
|
41
45
|
Requires-Dist: pymongo==4.10.1; extra == 'ag2-extras'
|
|
42
46
|
Requires-Dist: qdrant-client[fastembed]; (python_version >= '3.13') and extra == 'ag2-extras'
|
|
43
47
|
Provides-Extra: dev
|
|
44
48
|
Requires-Dist: autoflake==2.3.1; extra == 'dev'
|
|
45
|
-
Requires-Dist: bandit==1.8.
|
|
49
|
+
Requires-Dist: bandit==1.8.2; extra == 'dev'
|
|
46
50
|
Requires-Dist: black[jupyter]==24.10.0; extra == 'dev'
|
|
47
51
|
Requires-Dist: flake8==7.1.1; extra == 'dev'
|
|
48
52
|
Requires-Dist: isort==5.13.2; extra == 'dev'
|
|
49
|
-
Requires-Dist: mypy==1.14.
|
|
50
|
-
Requires-Dist:
|
|
53
|
+
Requires-Dist: mypy==1.14.1; extra == 'dev'
|
|
54
|
+
Requires-Dist: pandas-stubs; extra == 'dev'
|
|
55
|
+
Requires-Dist: pre-commit==4.1.0; extra == 'dev'
|
|
51
56
|
Requires-Dist: pydocstyle==6.3.0; extra == 'dev'
|
|
52
57
|
Requires-Dist: pylint==3.3.3; extra == 'dev'
|
|
53
58
|
Requires-Dist: python-dotenv==1.0.1; extra == 'dev'
|
|
54
|
-
Requires-Dist: ruff==0.
|
|
59
|
+
Requires-Dist: ruff==0.9.2; extra == 'dev'
|
|
55
60
|
Requires-Dist: toml; (python_version <= '3.10') and extra == 'dev'
|
|
56
|
-
Requires-Dist: types-pyyaml==6.0.12.
|
|
61
|
+
Requires-Dist: types-pyyaml==6.0.12.20241230; extra == 'dev'
|
|
57
62
|
Requires-Dist: types-toml==0.10.8.20240310; extra == 'dev'
|
|
58
63
|
Requires-Dist: yamllint==1.35.1; extra == 'dev'
|
|
59
64
|
Provides-Extra: docs
|
|
@@ -61,17 +66,18 @@ Requires-Dist: mdx-include==1.4.2; extra == 'docs'
|
|
|
61
66
|
Requires-Dist: mdx-truly-sane-lists==1.3; extra == 'docs'
|
|
62
67
|
Requires-Dist: mkdocs-jupyter==0.25.1; extra == 'docs'
|
|
63
68
|
Requires-Dist: mkdocs-macros-plugin==1.3.7; extra == 'docs'
|
|
64
|
-
Requires-Dist: mkdocs-material==9.5.
|
|
69
|
+
Requires-Dist: mkdocs-material==9.5.50; extra == 'docs'
|
|
65
70
|
Requires-Dist: mkdocs-minify-html-plugin==0.2.3; extra == 'docs'
|
|
66
71
|
Requires-Dist: mkdocs==1.6.1; extra == 'docs'
|
|
67
|
-
Requires-Dist: mkdocstrings-python==1.
|
|
72
|
+
Requires-Dist: mkdocstrings-python==1.13.0; extra == 'docs'
|
|
68
73
|
Requires-Dist: mkdocstrings[crystal,python]==0.27.0; extra == 'docs'
|
|
69
74
|
Provides-Extra: jupyter
|
|
70
75
|
Requires-Dist: jupyterlab>=4.3.0; extra == 'jupyter'
|
|
71
|
-
Requires-Dist: waldiez-jupyter==0.
|
|
76
|
+
Requires-Dist: waldiez-jupyter==0.3.1; extra == 'jupyter'
|
|
72
77
|
Provides-Extra: studio
|
|
73
|
-
Requires-Dist: waldiez-studio==0.
|
|
78
|
+
Requires-Dist: waldiez-studio==0.3.1; extra == 'studio'
|
|
74
79
|
Provides-Extra: test
|
|
80
|
+
Requires-Dist: pytest-asyncio==0.25.2; extra == 'test'
|
|
75
81
|
Requires-Dist: pytest-cov==6.0.0; extra == 'test'
|
|
76
82
|
Requires-Dist: pytest-html==4.1.1; extra == 'test'
|
|
77
83
|
Requires-Dist: pytest-sugar==1.0.0; extra == 'test'
|
|
@@ -202,6 +208,7 @@ runner.run(output_path=output_path)
|
|
|
202
208
|
- [juptytext](https://github.com/mwouts/jupytext)
|
|
203
209
|
- [pydantic](https://github.com/pydantic/pydantic)
|
|
204
210
|
- [typer](https://github.com/fastapi/typer)
|
|
211
|
+
- [asyncer](https://github.com/fastapi/asyncer)
|
|
205
212
|
|
|
206
213
|
## Known Conflicts
|
|
207
214
|
|
|
@@ -219,4 +226,4 @@ runner.run(output_path=output_path)
|
|
|
219
226
|
|
|
220
227
|
## License
|
|
221
228
|
|
|
222
|
-
This project is licensed under the
|
|
229
|
+
This project is licensed under the [Apache License, Version 2.0 (Apache-2.0)](https://github.com/waldiez/python/blob/main/LICENSE).
|