waldiez 0.1.7__py3-none-any.whl → 0.1.8__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/_version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Version information for Waldiez."""
2
2
 
3
- __version__ = "0.1.7"
3
+ __version__ = "0.1.8"
@@ -109,8 +109,7 @@ def get_chroma_db_args(
109
109
  f" embedding_function={embedding_function_arg},\n"
110
110
  )
111
111
  # The RAG example:
112
- # https://microsoft.github.io/autogen/docs/\
113
- # notebooks/agentchat_groupchat_RAG
112
+ # https://ag2ai.github.io/ag2/docs/notebooks/agentchat_groupchat_RAG/
114
113
  # raises `InvalidCollectionException`: Collection groupchat does not exist.
115
114
  # https://github.com/chroma-core/chroma/issues/861
116
115
  # https://github.com/microsoft/autogen/issues/3551#issuecomment-2366930994
@@ -14,7 +14,6 @@ from .helpers import escape_summary_args_quotes
14
14
 
15
15
 
16
16
  def get_nested_chat_trigger_agent_names(
17
- all_chats: List[WaldiezChat],
18
17
  nested_chat: WaldiezAgentNestedChat,
19
18
  agent_names: Dict[str, str],
20
19
  ) -> str:
@@ -22,8 +21,6 @@ def get_nested_chat_trigger_agent_names(
22
21
 
23
22
  Parameters
24
23
  ----------
25
- all_chats : List[WaldiezChat]
26
- All the chats in the flow.
27
24
  nested_chat : WaldiezAgentNestedChat
28
25
  The nested chat.
29
26
  agent_names : Dict[str, str]
@@ -34,14 +31,7 @@ def get_nested_chat_trigger_agent_names(
34
31
  str
35
32
  The trigger agent names.
36
33
  """
37
- trigger_agent_ids: List[str] = []
38
- for message in nested_chat.triggered_by:
39
- waldiez_chat = next(chat for chat in all_chats if chat.id == message.id)
40
- if message.is_reply:
41
- trigger_agent_ids.append(waldiez_chat.target)
42
- else:
43
- trigger_agent_ids.append(waldiez_chat.source)
44
- agents = [agent_names[agent_id] for agent_id in trigger_agent_ids]
34
+ agents = [agent_names[agent_id] for agent_id in nested_chat.triggered_by]
45
35
  trigger_string = f'{[", ".join(agents)]}'
46
36
  return trigger_string.replace("'", '"')
47
37
 
@@ -228,7 +218,7 @@ def export_nested_chat(
228
218
  use_suffix = len(agent.data.nested_chats) > 1
229
219
  for index, entry in enumerate(agent.data.nested_chats):
230
220
  trigger_names = get_nested_chat_trigger_agent_names(
231
- all_chats=all_chats, nested_chat=entry, agent_names=agent_names
221
+ nested_chat=entry, agent_names=agent_names
232
222
  )
233
223
  chat_queue, extra_methods = get_nested_chat_queue(
234
224
  nested_chat=entry,
@@ -14,6 +14,7 @@ get_sqlite_to_csv_call_string
14
14
 
15
15
 
16
16
  # Check issue:
17
+ # Also check if in ag2 this still applies
17
18
  # https://github.com/microsoft/autogen/issues/2286
18
19
  # we cannot log new agents if they have code_execution enabled
19
20
  # we get `Path` is not JSON serializable (on code_executor)
waldiez/io/__init__.py CHANGED
@@ -5,100 +5,48 @@ It is meant to be used when we want to use custom
5
5
  is used to trigger a UI element that requires user input.
6
6
  and sends back the user's input to the websocket. In the same
7
7
  way, we can use it to forward what is meant to be printed.
8
-
9
-
10
- We use:
11
-
12
- - one tcp server to handle messaging between the clients
13
- - one tcp client (provider) to set and forward the user's input
14
- that we got elsewhere (e.g. from a websocket connection)
15
- - one tcp client (consumer) to ask and get the input from the provider
16
8
  """
17
9
 
18
- import socket
19
- from contextlib import closing
10
+ import threading
20
11
  from typing import Any, Callable, Optional
21
12
 
22
13
  from autogen.io import IOStream # type: ignore[import-untyped]
23
14
 
24
- from .stream import TCPConsumer, TCPProvider, TCPServer
25
-
26
15
 
27
16
  class WaldiezIOStream(IOStream):
28
- """Custom IOStream class to handle the `print` and `input` functions."""
17
+ """Custom IOStream class to handle `print` and `input` functions."""
29
18
 
30
19
  def __init__(
31
20
  self,
32
- port: int = 0,
33
- input_timeout: float = 60,
21
+ input_timeout: float = 60.0,
34
22
  print_function: Optional[Callable[..., None]] = None,
35
23
  on_prompt_input: Optional[Callable[[str], None]] = None,
36
24
  ) -> None:
37
- """Initialize the IOStream.
25
+ """
26
+ Initialize the IOStream.
38
27
 
39
28
  Parameters
40
29
  ----------
41
- port : int, optional
42
- The port to use, by default 0 (auto-assign).
43
30
  input_timeout : float, optional
44
- The input timeout, by default 60.
31
+ The input timeout in seconds, by default 60.0.
45
32
  print_function : Optional[Callable[..., None]], optional
46
- The print function to use, by default None.
33
+ The function to handle print operations, by default None.
47
34
  on_prompt_input : Optional[Callable[[str], None]], optional
48
- The function to call for getting an input, by default None.
35
+ The function to call for processing input prompts, by default None.
36
+
37
+ Notes
38
+ -----
39
+ - on_prompt_input: It does not return a string (like 'input' does).
40
+ Instead, it is meant to be used to forward the prompt somewhere else
41
+ (e.g., a websocket). When we get the input, we can call
42
+ `waldiez_io_stream.set_input(input_data)` with the input data.
49
43
  """
50
- self._print_function = print_function
51
- if port == 0:
52
- port = get_available_port()
53
- self._port = port
54
- self._input_timeout = input_timeout
55
- self._server = TCPServer(port)
56
- self._server.start()
57
- self._provider = TCPProvider("localhost", port, response=None)
58
- self._on_prompt_input = on_prompt_input
59
-
60
- @property
61
- def print_function(self) -> Optional[Callable[..., None]]:
62
- """Get the print function."""
63
- return self._print_function
64
-
65
- def open(self) -> None:
66
- """Start the server."""
67
- if not self._server.is_running():
68
- self._server.start()
69
-
70
- def close(self) -> None:
71
- """Stop the server and the provider."""
72
- # pylint: disable=broad-except
73
- if self._server.is_running():
74
- try:
75
- self._server.stop()
76
- except BaseException: # pragma: no cover
77
- pass
78
- try:
79
- self._provider.stop()
80
- except BaseException: # pragma: no cover
81
- pass
82
-
83
- def __del__(self) -> None: # pragma: no cover
84
- """Delete the instance."""
85
- self.close()
86
-
87
- def forward_input(self, input_data: str) -> None:
88
- """Forward the user's input to the provider.
89
-
90
- When we have the input data
91
- e.g. from 'input(..)' or from a websocket connection,
92
- we can forward it to the provider (the tcp client)
93
- to make it available to the consumer (the other tcp client).
94
- Parameters
95
- ----------
96
- input_data : str
97
- The input data to forward.
98
- """
99
- if not self._provider.is_running():
100
- self._provider.start()
101
- self._provider.set_response(input_data)
44
+ self.input_timeout = input_timeout # Timeout for input
45
+ self.print_function = print_function # Custom print handler
46
+ self._on_prompt_input = on_prompt_input # Custom input prompt handler
47
+ self.current_input: Optional[str] = None # Store the current input
48
+ self._input_event = threading.Event() # Event to signal input readiness
49
+ self.allow_input = True # Flag to allow or block input setting
102
50
 
103
51
  def print(
104
52
  self,
@@ -107,7 +55,8 @@ class WaldiezIOStream(IOStream):
107
55
  end: str = "\n",
108
56
  flush: bool = False,
109
57
  ) -> None:
110
- """Mock the print function.
58
+ """
59
+ Mock the `print` function.
111
60
 
112
61
  Parameters
113
62
  ----------
@@ -116,66 +65,78 @@ class WaldiezIOStream(IOStream):
116
65
  sep : str, optional
117
66
  The separator, by default " ".
118
67
  end : str, optional
119
- The end, by default a new line.
68
+ The ending string, by default a new line.
120
69
  flush : bool, optional
121
- Whether to flush, by default False.
70
+ Whether to flush the output, by default False.
122
71
  """
123
72
  print_function: Callable[..., None] = self.print_function or print
124
73
  print_function(*objects, sep=sep, end=end, flush=flush)
125
74
 
126
75
  def input(self, prompt: str = "", *, password: bool = False) -> str:
127
- """Mock the input function.
76
+ """
77
+ Mock the `input` function with optional timeout handling.
128
78
 
129
79
  Parameters
130
80
  ----------
131
81
  prompt : str, optional
132
82
  The prompt to show, by default "".
133
- password : bool, optional (not used)
134
- Whether to show the input as password, by default False.
83
+ password : bool, optional
84
+ Whether to hide the input as password (not used), by default False.
135
85
 
136
86
  Returns
137
87
  -------
138
88
  str
139
- The user's input.
89
+ The user's input or '\n' if timeout occurs.
140
90
  """
141
91
  _prompt = prompt or "Your input:"
142
- if _prompt in (">", "> "):
92
+ if _prompt in (">", "> "): # pragma: no cover
143
93
  _prompt = "Your input:"
144
94
  if prompt:
145
95
  if self._on_prompt_input:
146
96
  self._on_prompt_input(_prompt)
147
97
  self.print(_prompt, end="")
148
- if not self._provider.is_running():
149
- self._provider.start()
150
- # wait for the provider to start
151
- self._provider.wait(timeout=self._input_timeout)
152
- if not self._provider.is_running(): # pragma: no cover
153
- self.print(
154
- "WARNING: Provider is not running. Was an input expected?"
98
+
99
+ # Only reset if no input is currently set
100
+ # e.g. handle the case when we call set_input(..) before input(..)
101
+ already_set = self._input_event.is_set()
102
+ if not self._input_event.is_set():
103
+ self.current_input = None # Reset previous input
104
+ self._input_event.clear() # Clear the event before waiting
105
+
106
+ # Wait for input or timeout
107
+ if not self._input_event.wait(self.input_timeout):
108
+ # Timeout occurred, return what we have so far
109
+ to_return = (
110
+ self.current_input if self.current_input is not None else "\n"
155
111
  )
156
- return "\n"
157
- consumer = TCPConsumer(
158
- "localhost", self._port, timeout=self._input_timeout
112
+ self.current_input = None
113
+ self._input_event.clear()
114
+ # if we had already set the input, return it
115
+ return to_return if already_set else "\n"
116
+
117
+ # Input is ready, return it
118
+ to_return = (
119
+ self.current_input if self.current_input is not None else "\n"
159
120
  )
160
- consumer.start()
161
- # send the prompt and wait for the response
162
- consumer.send_prompt(_prompt)
163
- response = consumer.get_response()
164
- consumer.stop()
165
- self._provider.stop()
166
- # return the response or a line break (i.e. no input)
167
- return response or "\n"
168
-
169
-
170
- def get_available_port() -> int:
171
- """Get an available port.
172
-
173
- Returns
174
- -------
175
- int
176
- Available port.
177
- """
178
- with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as soc:
179
- soc.bind(("", 0))
180
- soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
181
- return soc.getsockname()[1]
121
+ self.current_input = None
122
+ self._input_event.clear() # Clear the event after waiting
123
+ return to_return
124
+
125
+ def set_input(self, value: str) -> None:
126
+ """
127
+ Set the input value and signal that input is ready.
128
+
129
+ Parameters
130
+ ----------
131
+ value : str
132
+ The value to set as input.
133
+ """
134
+ if self.allow_input: # Respect the allow_input flag
135
+ self.current_input = value
136
+ self._input_event.set() # Signal that input is ready
137
+
138
+ def reset_state(self) -> None:
139
+ """Reset the IOStream state for testing."""
140
+ self.current_input = None
141
+ self._input_event.clear()
142
+ self.allow_input = True # Re-enable input setting
@@ -40,22 +40,18 @@ class WaldiezAgentNestedChat(WaldiezBase):
40
40
 
41
41
  Attributes
42
42
  ----------
43
- triggered_by : List[WaldiezAgentNestedChatMessage]
44
- A list of chats (id and is_reply) to determine
45
- the triggering of the nested chat.
43
+ triggered_by : List[str]
44
+ A list of agent ids that trigger the nested chat.
46
45
  messages : List[WaldiezAgentNestedChatMessage]
47
46
  The list of messages (chat ids and 'is_reply'z)
48
47
  to include the in the nested chat registration.
49
48
  """
50
49
 
51
50
  triggered_by: Annotated[
52
- List[WaldiezAgentNestedChatMessage],
51
+ List[str],
53
52
  Field(
54
53
  title="Triggered By",
55
- description=(
56
- "A list of chats (id and is_reply) to determine"
57
- "the triggering of the nested chat."
58
- ),
54
+ description=("A list of agent ids that trigger the nested chat."),
59
55
  alias="triggeredBy",
60
56
  default_factory=list,
61
57
  ),
waldiez/models/waldiez.py CHANGED
@@ -205,18 +205,16 @@ class Waldiez:
205
205
  requirements_list = filter(
206
206
  lambda requirement: not (
207
207
  requirement.startswith("pyautogen")
208
- or requirement.startswith("autogen-agentchat")
208
+ or requirement.startswith("ag2")
209
209
  ),
210
210
  self.flow.requirements,
211
211
  )
212
212
  requirements = set(requirements_list)
213
213
  if self.has_rag_agents:
214
- requirements.add(
215
- f"autogen-agentchat[retrievechat]=={autogen_version}"
216
- )
214
+ requirements.add(f"ag2[retrievechat]=={autogen_version}")
217
215
  else:
218
- requirements.add(f"autogen-agentchat=={autogen_version}")
219
- # ref: https://github.com/microsoft/autogen/blob/main/setup.py
216
+ requirements.add(f"ag2=={autogen_version}")
217
+ # ref: https://github.com/ag2ai/ag2/blob/main/setup.py
220
218
  models_with_additional_requirements = [
221
219
  "together",
222
220
  "gemini",
@@ -229,8 +227,7 @@ class Waldiez:
229
227
  for model in self.models:
230
228
  if model.data.api_type in models_with_additional_requirements:
231
229
  requirements.add(
232
- f"autogen-agentchat[{model.data.api_type}]=="
233
- f"{autogen_version}"
230
+ f"ag2[{model.data.api_type}]==" f"{autogen_version}"
234
231
  )
235
232
  return list(requirements)
236
233
 
@@ -1,11 +1,10 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: waldiez
3
- Version: 0.1.7
3
+ Version: 0.1.8
4
4
  Summary: waldiez
5
- Project-URL: homepage, https://waldiez.github.io/py/
6
- Project-URL: repository, https://github.com/waldiez/py.git
5
+ Project-URL: homepage, https://waldiez.github.io/waldiez/
6
+ Project-URL: repository, https://github.com/waldiez/waldiez.git
7
7
  Author-email: Panagiotis Kasnesis <pkasnesis@thingenious.io>, Lazaros Toumanidis <laztoum@protonmail.com>
8
- License-File: LICENSE
9
8
  Classifier: Development Status :: 3 - Alpha
10
9
  Classifier: Intended Audience :: Developers
11
10
  Classifier: Intended Audience :: Science/Research
@@ -17,28 +16,26 @@ Classifier: Programming Language :: Python :: 3.10
17
16
  Classifier: Programming Language :: Python :: 3.11
18
17
  Classifier: Programming Language :: Python :: 3.12
19
18
  Requires-Python: <3.13,>=3.10
20
- Requires-Dist: autogen-agentchat==0.2.37
19
+ Requires-Dist: ag2==0.3.2
21
20
  Requires-Dist: jupytext
22
- Requires-Dist: twisted==24.10.0
23
- Provides-Extra: autogen-extras
24
- Requires-Dist: autogen-agentchat[anthropic]==0.2.37; extra == 'autogen-extras'
25
- Requires-Dist: autogen-agentchat[bedrock]==0.2.37; extra == 'autogen-extras'
26
- Requires-Dist: autogen-agentchat[gemini]==0.2.37; extra == 'autogen-extras'
27
- Requires-Dist: autogen-agentchat[groq]==0.2.37; extra == 'autogen-extras'
28
- Requires-Dist: autogen-agentchat[mistral]==0.2.37; extra == 'autogen-extras'
29
- Requires-Dist: autogen-agentchat[retrievechat-couchbase]==0.2.37; extra == 'autogen-extras'
30
- Requires-Dist: autogen-agentchat[retrievechat-mongodb]==0.2.37; extra == 'autogen-extras'
31
- Requires-Dist: autogen-agentchat[retrievechat-pgvector]==0.2.37; extra == 'autogen-extras'
32
- Requires-Dist: autogen-agentchat[retrievechat-qdrant]==0.2.37; extra == 'autogen-extras'
33
- Requires-Dist: autogen-agentchat[retrievechat]==0.2.37; extra == 'autogen-extras'
34
- Requires-Dist: autogen-agentchat[together]==0.2.37; extra == 'autogen-extras'
35
- Requires-Dist: autogen-agentchat[websurfer]==0.2.37; extra == 'autogen-extras'
36
- Requires-Dist: chromadb==0.5.17; extra == 'autogen-extras'
37
- Requires-Dist: fastembed==0.4.1; extra == 'autogen-extras'
38
- Requires-Dist: pgvector==0.3.6; extra == 'autogen-extras'
39
- Requires-Dist: psycopg[binary]>=3.2.3; extra == 'autogen-extras'
40
- Requires-Dist: pymongo==4.10.1; extra == 'autogen-extras'
41
- Requires-Dist: qdrant-client==1.12.1; extra == 'autogen-extras'
21
+ Provides-Extra: ag2-extras
22
+ Requires-Dist: ag2[anthropic]==0.3.2; extra == 'ag2-extras'
23
+ Requires-Dist: ag2[bedrock]==0.3.2; extra == 'ag2-extras'
24
+ Requires-Dist: ag2[gemini]==0.3.2; extra == 'ag2-extras'
25
+ Requires-Dist: ag2[groq]==0.3.2; extra == 'ag2-extras'
26
+ Requires-Dist: ag2[mistral]==0.3.2; extra == 'ag2-extras'
27
+ Requires-Dist: ag2[retrievechat-mongodb]==0.3.2; extra == 'ag2-extras'
28
+ Requires-Dist: ag2[retrievechat-pgvector]==0.3.2; extra == 'ag2-extras'
29
+ Requires-Dist: ag2[retrievechat-qdrant]==0.3.2; extra == 'ag2-extras'
30
+ Requires-Dist: ag2[retrievechat]==0.3.2; extra == 'ag2-extras'
31
+ Requires-Dist: ag2[together]==0.3.2; extra == 'ag2-extras'
32
+ Requires-Dist: ag2[websurfer]==0.3.2; extra == 'ag2-extras'
33
+ Requires-Dist: chromadb==0.5.3; extra == 'ag2-extras'
34
+ Requires-Dist: fastembed==0.4.2; extra == 'ag2-extras'
35
+ Requires-Dist: pgvector>=0.2.5; extra == 'ag2-extras'
36
+ Requires-Dist: psycopg[binary]>=3.1.18; extra == 'ag2-extras'
37
+ Requires-Dist: pymongo==4.10.1; extra == 'ag2-extras'
38
+ Requires-Dist: qdrant-client==1.12.1; extra == 'ag2-extras'
42
39
  Provides-Extra: dev
43
40
  Requires-Dist: autoflake==2.3.1; extra == 'dev'
44
41
  Requires-Dist: bandit==1.7.10; extra == 'dev'
@@ -50,7 +47,7 @@ Requires-Dist: pre-commit==4.0.1; extra == 'dev'
50
47
  Requires-Dist: pydocstyle==6.3.0; extra == 'dev'
51
48
  Requires-Dist: pylint==3.3.1; extra == 'dev'
52
49
  Requires-Dist: python-dotenv==1.0.1; extra == 'dev'
53
- Requires-Dist: ruff==0.7.2; extra == 'dev'
50
+ Requires-Dist: ruff==0.7.4; extra == 'dev'
54
51
  Requires-Dist: types-pyyaml==6.0.12; extra == 'dev'
55
52
  Requires-Dist: yamllint==1.35.1; extra == 'dev'
56
53
  Provides-Extra: docs
@@ -58,11 +55,11 @@ Requires-Dist: mdx-include==1.4.2; extra == 'docs'
58
55
  Requires-Dist: mdx-truly-sane-lists==1.3; extra == 'docs'
59
56
  Requires-Dist: mkdocs-jupyter==0.25.1; extra == 'docs'
60
57
  Requires-Dist: mkdocs-macros-plugin==1.3.7; extra == 'docs'
61
- Requires-Dist: mkdocs-material==9.5.43; extra == 'docs'
58
+ Requires-Dist: mkdocs-material==9.5.44; extra == 'docs'
62
59
  Requires-Dist: mkdocs-minify-html-plugin==0.2.3; extra == 'docs'
63
60
  Requires-Dist: mkdocs==1.6.1; extra == 'docs'
64
61
  Requires-Dist: mkdocstrings-python==1.12.2; extra == 'docs'
65
- Requires-Dist: mkdocstrings[crystal,python]==0.26.2; extra == 'docs'
62
+ Requires-Dist: mkdocstrings[crystal,python]==0.27.0; extra == 'docs'
66
63
  Provides-Extra: test
67
64
  Requires-Dist: pytest-cov==6.0.0; extra == 'test'
68
65
  Requires-Dist: pytest-html==4.1.1; extra == 'test'
@@ -74,20 +71,20 @@ Description-Content-Type: text/markdown
74
71
 
75
72
  # Waldiez
76
73
 
77
- ![CI Build](https://github.com/waldiez/py/actions/workflows/main.yaml/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/waldiez/py/badge.svg)](https://coveralls.io/github/waldiez/py) [![PyPI version](https://badge.fury.io/py/waldiez.svg)](https://badge.fury.io/py/waldiez)
74
+ ![CI Build](https://github.com/waldiez/waldiez/actions/workflows/main.yaml/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/waldiez/waldiez/badge.svg)](https://coveralls.io/github/waldiez/waldiez) [![PyPI version](https://badge.fury.io/waldiez/waldiez.svg)](https://badge.fury.io/py/waldiez)
78
75
 
79
76
  Translate a Waldiez flow:
80
77
 
81
- ![Flow](https://raw.githubusercontent.com/waldiez/py/refs/heads/main/docs/flow.png)
78
+ ![Flow](https://raw.githubusercontent.com/waldiez/waldiez/refs/heads/main/docs/static/images/overview.webp)
82
79
 
83
- To a python script or a jupyter notebook with the corresponding [autogen](https://github.com/microsoft/autogen/) agents and chats.
80
+ To a python script or a jupyter notebook with the corresponding [ag2](https://github.com/ag2ai/ag2/) agents and chats.
84
81
 
85
82
  ## Features
86
83
 
87
84
  - Export .waldiez flows to .py or .ipynb
88
85
  - Run a .waldiez flow
89
86
  - Include a `logs` folder with the logs of the flow in csv format
90
- - Provide a custom [IOSStream](https://autogen-ai.github.io/autogen/docs/reference/io/base#iostream) to handle input and output.
87
+ - Provide a custom [IOSStream](https://ag2ai.github.io/ag2/docs/reference/io/base#iostream) to handle input and output.
91
88
 
92
89
  ## Installation
93
90
 
@@ -100,7 +97,7 @@ python -m pip install waldiez
100
97
  From the repository:
101
98
 
102
99
  ```bash
103
- python -m pip install git+https://github.com/waldiez/py.git
100
+ python -m pip install git+https://github.com/waldiez/waldiez.git
104
101
  ```
105
102
 
106
103
  ## Usage
@@ -119,13 +116,13 @@ waldiez /path/to/a/flow.waldiez --output /path/to/an/output/flow[.py] [--force]
119
116
  ```shell
120
117
  CONTAINER_COMMAND=docker # or podman
121
118
  # pull the image
122
- $CONTAINER_COMMAND pull waldiez/py
119
+ $CONTAINER_COMMAND pull waldiez/waldiez
123
120
  # Export a Waldiez flow to a python script or a jupyter notebook
124
121
  $CONTAINER_COMMAND run \
125
122
  --rm \
126
123
  -v /path/to/a/flow.waldiez:/flow.waldiez \
127
124
  -v /path/to/an/output:/output \
128
- waldiez/py --export /flow.waldiez --output /output/flow[.py|.ipynb]
125
+ waldiez/waldiez --export /flow.waldiez --output /output/flow[.py|.ipynb]
129
126
 
130
127
  # with selinux and/or podman, you might get permission (or file not found) errors, so you can try:
131
128
  $CONTAINER_COMMAND run \
@@ -134,12 +131,12 @@ $CONTAINER_COMMAND run \
134
131
  -v /path/to/an/output:/output \
135
132
  --userns=keep-id \
136
133
  --security-opt label=disable \
137
- waldiez/py --export /flow.waldiez --output /output/flow[.py|.ipynb]
134
+ waldiez/waldiez --export /flow.waldiez --output /output/flow[.py|.ipynb]
138
135
  ```
139
136
 
140
137
  ```shell
141
138
  # Export and run the script
142
- $CONTAINER_COMMAND run --rm -v /path/to/a/flow.waldiez:/flow.waldiez -v /path/to/an/output:/output waldiez/py /flow.waldiez --output /output/output[.py]
139
+ $CONTAINER_COMMAND run --rm -v /path/to/a/flow.waldiez:/flow.waldiez -v /path/to/an/output:/output waldiez/waldiez /flow.waldiez --output /output/output[.py]
143
140
  ```
144
141
 
145
142
  ### As a library
@@ -170,40 +167,75 @@ runner.run(output_path=output_path)
170
167
 
171
168
  ```python
172
169
  # Run the flow with a custom IOStream
170
+ # In case the standard 'input' and 'print' functions cannot be used
171
+ import time
172
+ import threading
173
+
174
+ from typing import Any
175
+
173
176
  from waldiez import WaldiezRunner
174
177
  from waldiez.io import WaldiezIOStream
175
178
 
176
179
  flow_path = "/path/to/a/flow.waldiez"
177
180
  output_path = "/path/to/an/output.py"
178
181
 
179
- def print_function(*values, **args) -> None:
180
- """A custom print function."""
181
- print(values)
182
182
 
183
- def on_prompt_input(prompt: str) -> str:
184
- """A custom input function."""
185
- return input(prompt)
183
+ def custom_print_function(*args: Any, sep: str = " ", **kwargs: Any) -> None:
184
+ """Custom print function."""
185
+ print(*args, sep=sep, **kwargs)
186
+
187
+
188
+ # Custom input handler
189
+ class InputProcessorWrapper:
190
+ """Wrapper input processor.
191
+
192
+ To manage the interaction between the custom input processor and IOStream.
193
+ """
194
+
195
+ def __init__(self):
196
+ self.stream = None # Placeholder for the WaldiezIOStream instance
197
+ self.lock = threading.Lock() # Ensure thread-safe operations
198
+
199
+ def custom_input_processor(self, prompt: str) -> None:
200
+ """Simulate external input and send it back to the IOStream."""
201
+ def external_input_simulation():
202
+ with self.lock: # Ensure thread-safe access
203
+ time.sleep(2) # Simulate delay for network input
204
+ if self.stream:
205
+ self.stream.set_input("Simulated external input")
206
+ else:
207
+ raise RuntimeError("Stream reference not set!")
186
208
 
187
- io_stream = WaldiezIOStream(
188
- print_function=print_function,
189
- on_prompt_input=on_prompt_input,
209
+ threading.Thread(target=external_input_simulation, daemon=True).start()
210
+
211
+ def set_stream(self, stream: "WaldiezIOStream"):
212
+ """Set the WaldiezIOStream instance."""
213
+ with self.lock: # Ensure thread-safe setting of the stream
214
+ self.stream = stream
215
+
216
+ processor_wrapper = InputProcessorWrapper()
217
+
218
+ stream = WaldiezIOStream(
190
219
  input_timeout=30,
220
+ print_function=
221
+ on_prompt_input=processor_wrapper.custom_input_processor,
191
222
  )
223
+
224
+ # Link the processor wrapper to the WaldiezIOStream instance
225
+ processor_wrapper.set_stream(custom_stream)
226
+
192
227
  with WaldiezIOStream.set_default(io_stream):
193
228
  runner = WaldiezRunner.load(flow_path)
194
229
  runner.run(stream=io_stream, output_path=output_path)
195
230
 
196
- io_stream.close()
197
-
198
231
  ```
199
232
 
200
233
  ### Tools
201
234
 
202
- - [autogen](https://github.com/microsoft/autogen/)
235
+ - [ag2 (formerly AutoGen)](https://github.com/ag2ai/ag2)
203
236
  - [juptytext](https://github.com/mwouts/jupytext)
204
- - [twisted](https://github.com/twisted/twisted)
205
237
  - [pydantic](https://github.com/pydantic/pydantic)
206
238
 
207
239
  ## License
208
240
 
209
- This project is licensed under the MIT License - see the [LICENSE](https://github.com/waldiez/py/blob/main/LICENSE) file for details.
241
+ This project is licensed under the MIT License - see the [LICENSE](https://github.com/waldiez/waldiez/blob/main/LICENSE) file for details.