waldiez 0.1.7__py3-none-any.whl → 0.1.9__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.9"
@@ -32,9 +32,9 @@ def _get_chroma_client_string(agent: WaldiezRagUser) -> Tuple[str, str]:
32
32
  # SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes
33
33
  # in position 2-3: truncated \UXXXXXXXX escape
34
34
  local_path = Path(agent.retrieve_config.db_config.local_storage_path)
35
- client_str += f'PersistentClient(path=r"{local_path}")'
35
+ client_str += f'PersistentClient(path=r"{local_path}", settings=Settings(anonymized_telemetry=False))'
36
36
  else:
37
- client_str += "Client()"
37
+ client_str += "Client(Settings(anonymized_telemetry=False))"
38
38
  return client_str, to_import
39
39
 
40
40
 
@@ -97,11 +97,11 @@ def get_chroma_db_args(
97
97
  - The custom embedding function.
98
98
  - Any additional content to be used before the `kwargs` string.
99
99
  """
100
- client_str, to_import_client = _get_chroma_client_string(agent)
100
+ client_str, client_to_import = _get_chroma_client_string(agent)
101
101
  embedding_function_arg, to_import_embedding, embedding_function_body = (
102
102
  _get_chroma_embedding_function_string(agent, agent_name)
103
103
  )
104
- to_import = {to_import_client}
104
+ to_import = {client_to_import, "from chromadb.config import Settings"}
105
105
  if to_import_embedding:
106
106
  to_import.add(to_import_embedding)
107
107
  kwarg_string = (
@@ -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)
@@ -2,11 +2,12 @@
2
2
 
3
3
  import os
4
4
  from pathlib import Path
5
+ from typing import Optional
5
6
 
6
7
  # pylint: disable=broad-except
7
8
 
8
9
 
9
- def _is_local_path(string: str) -> bool:
10
+ def _check_local_path(string: str) -> Optional[Path]:
10
11
  """Check if a string is a local path.
11
12
 
12
13
  Parameters
@@ -21,9 +22,11 @@ def _is_local_path(string: str) -> bool:
21
22
  """
22
23
  try:
23
24
  path = Path(string).resolve()
24
- return path.exists()
25
25
  except Exception: # pragma: no cover
26
- return False
26
+ return None
27
+ if path.exists():
28
+ return path
29
+ return None
27
30
 
28
31
 
29
32
  def get_path_string(string: str) -> str:
@@ -41,8 +44,8 @@ def get_path_string(string: str) -> str:
41
44
  """
42
45
  # On windows, we get paths like "C:\path\to\file"
43
46
  # if so, let's try to avoid invalid escape sequences
44
- if not _is_local_path(string):
47
+ if not _check_local_path(string):
45
48
  return string
46
49
  if os.name == "nt": # pragma: no cover
47
50
  return f"r'{string}'"
48
- return f"'{string}'"
51
+ return f"{Path(string).resolve()}"
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