waldiez 0.6.0__py3-none-any.whl → 0.6.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.

Files changed (188) hide show
  1. waldiez/__init__.py +1 -1
  2. waldiez/_version.py +1 -1
  3. waldiez/cli.py +18 -7
  4. waldiez/cli_extras/jupyter.py +3 -0
  5. waldiez/cli_extras/runner.py +3 -1
  6. waldiez/cli_extras/studio.py +3 -1
  7. waldiez/exporter.py +9 -3
  8. waldiez/exporting/agent/exporter.py +9 -10
  9. waldiez/exporting/agent/extras/captain_agent_extras.py +6 -6
  10. waldiez/exporting/agent/extras/doc_agent_extras.py +6 -6
  11. waldiez/exporting/agent/extras/group_manager_agent_extas.py +34 -23
  12. waldiez/exporting/agent/extras/group_member_extras.py +6 -5
  13. waldiez/exporting/agent/extras/handoffs/after_work.py +1 -1
  14. waldiez/exporting/agent/extras/handoffs/available.py +1 -1
  15. waldiez/exporting/agent/extras/handoffs/condition.py +3 -2
  16. waldiez/exporting/agent/extras/handoffs/handoff.py +1 -1
  17. waldiez/exporting/agent/extras/handoffs/target.py +6 -4
  18. waldiez/exporting/agent/extras/rag/chroma_extras.py +27 -19
  19. waldiez/exporting/agent/extras/rag/mongo_extras.py +8 -8
  20. waldiez/exporting/agent/extras/rag/pgvector_extras.py +5 -5
  21. waldiez/exporting/agent/extras/rag/qdrant_extras.py +5 -4
  22. waldiez/exporting/agent/extras/rag/vector_db_extras.py +1 -1
  23. waldiez/exporting/agent/extras/rag_user_proxy_agent_extras.py +5 -7
  24. waldiez/exporting/agent/extras/reasoning_agent_extras.py +3 -5
  25. waldiez/exporting/chats/exporter.py +4 -4
  26. waldiez/exporting/chats/processor.py +1 -2
  27. waldiez/exporting/chats/utils/common.py +89 -48
  28. waldiez/exporting/chats/utils/group.py +9 -9
  29. waldiez/exporting/chats/utils/nested.py +7 -7
  30. waldiez/exporting/chats/utils/sequential.py +1 -1
  31. waldiez/exporting/chats/utils/single.py +2 -2
  32. waldiez/exporting/core/content.py +7 -7
  33. waldiez/exporting/core/context.py +5 -3
  34. waldiez/exporting/core/exporter.py +5 -3
  35. waldiez/exporting/core/exporters.py +2 -2
  36. waldiez/exporting/core/extras/agent_extras/captain_extras.py +2 -2
  37. waldiez/exporting/core/extras/agent_extras/group_manager_extras.py +2 -2
  38. waldiez/exporting/core/extras/agent_extras/rag_user_extras.py +2 -2
  39. waldiez/exporting/core/extras/agent_extras/standard_extras.py +3 -8
  40. waldiez/exporting/core/extras/base.py +7 -5
  41. waldiez/exporting/core/extras/flow_extras.py +4 -5
  42. waldiez/exporting/core/extras/model_extras.py +2 -2
  43. waldiez/exporting/core/extras/path_resolver.py +1 -2
  44. waldiez/exporting/core/extras/serializer.py +2 -2
  45. waldiez/exporting/core/protocols.py +6 -5
  46. waldiez/exporting/core/result.py +25 -28
  47. waldiez/exporting/core/types.py +10 -10
  48. waldiez/exporting/core/utils/llm_config.py +2 -2
  49. waldiez/exporting/core/validation.py +10 -11
  50. waldiez/exporting/flow/execution_generator.py +98 -10
  51. waldiez/exporting/flow/exporter.py +2 -2
  52. waldiez/exporting/flow/factory.py +2 -2
  53. waldiez/exporting/flow/file_generator.py +4 -2
  54. waldiez/exporting/flow/merger.py +5 -3
  55. waldiez/exporting/flow/orchestrator.py +72 -2
  56. waldiez/exporting/flow/utils/common.py +5 -5
  57. waldiez/exporting/flow/utils/importing.py +6 -7
  58. waldiez/exporting/flow/utils/linting.py +25 -9
  59. waldiez/exporting/flow/utils/logging.py +2 -2
  60. waldiez/exporting/models/exporter.py +8 -8
  61. waldiez/exporting/models/processor.py +5 -5
  62. waldiez/exporting/tools/exporter.py +2 -2
  63. waldiez/exporting/tools/processor.py +7 -4
  64. waldiez/io/__init__.py +8 -4
  65. waldiez/io/_ws.py +10 -6
  66. waldiez/io/models/constants.py +10 -10
  67. waldiez/io/models/content/audio.py +1 -0
  68. waldiez/io/models/content/base.py +20 -18
  69. waldiez/io/models/content/file.py +1 -0
  70. waldiez/io/models/content/image.py +1 -0
  71. waldiez/io/models/content/text.py +1 -0
  72. waldiez/io/models/content/video.py +1 -0
  73. waldiez/io/models/user_input.py +10 -5
  74. waldiez/io/models/user_response.py +17 -16
  75. waldiez/io/mqtt.py +18 -31
  76. waldiez/io/redis.py +18 -22
  77. waldiez/io/structured.py +52 -53
  78. waldiez/io/utils.py +3 -0
  79. waldiez/io/ws.py +5 -1
  80. waldiez/logger.py +16 -3
  81. waldiez/models/agents/__init__.py +3 -0
  82. waldiez/models/agents/agent/agent.py +23 -16
  83. waldiez/models/agents/agent/agent_data.py +25 -22
  84. waldiez/models/agents/agent/code_execution.py +9 -11
  85. waldiez/models/agents/agent/termination_message.py +10 -12
  86. waldiez/models/agents/agent/update_system_message.py +2 -4
  87. waldiez/models/agents/agents.py +8 -8
  88. waldiez/models/agents/assistant/assistant.py +6 -3
  89. waldiez/models/agents/assistant/assistant_data.py +2 -2
  90. waldiez/models/agents/captain/captain_agent.py +7 -4
  91. waldiez/models/agents/captain/captain_agent_data.py +5 -7
  92. waldiez/models/agents/doc_agent/doc_agent.py +7 -4
  93. waldiez/models/agents/doc_agent/doc_agent_data.py +9 -10
  94. waldiez/models/agents/doc_agent/rag_query_engine.py +10 -12
  95. waldiez/models/agents/extra_requirements.py +3 -3
  96. waldiez/models/agents/group_manager/group_manager.py +12 -7
  97. waldiez/models/agents/group_manager/group_manager_data.py +13 -12
  98. waldiez/models/agents/group_manager/speakers.py +17 -19
  99. waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +7 -4
  100. waldiez/models/agents/rag_user_proxy/rag_user_proxy_data.py +4 -1
  101. waldiez/models/agents/rag_user_proxy/retrieve_config.py +69 -63
  102. waldiez/models/agents/rag_user_proxy/vector_db_config.py +19 -19
  103. waldiez/models/agents/reasoning/reasoning_agent.py +7 -4
  104. waldiez/models/agents/reasoning/reasoning_agent_data.py +3 -2
  105. waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +8 -8
  106. waldiez/models/agents/user_proxy/user_proxy.py +6 -3
  107. waldiez/models/agents/user_proxy/user_proxy_data.py +1 -1
  108. waldiez/models/chat/chat.py +27 -20
  109. waldiez/models/chat/chat_data.py +22 -19
  110. waldiez/models/chat/chat_message.py +9 -9
  111. waldiez/models/chat/chat_nested.py +9 -9
  112. waldiez/models/chat/chat_summary.py +6 -6
  113. waldiez/models/common/__init__.py +2 -0
  114. waldiez/models/common/ag2_version.py +2 -0
  115. waldiez/models/common/dict_utils.py +8 -6
  116. waldiez/models/common/handoff.py +18 -17
  117. waldiez/models/common/method_utils.py +7 -7
  118. waldiez/models/common/naming.py +49 -0
  119. waldiez/models/flow/flow.py +11 -6
  120. waldiez/models/flow/flow_data.py +23 -17
  121. waldiez/models/flow/info.py +3 -3
  122. waldiez/models/flow/naming.py +2 -1
  123. waldiez/models/model/_aws.py +11 -13
  124. waldiez/models/model/_llm.py +5 -0
  125. waldiez/models/model/_price.py +2 -4
  126. waldiez/models/model/extra_requirements.py +1 -3
  127. waldiez/models/model/model.py +2 -2
  128. waldiez/models/model/model_data.py +21 -21
  129. waldiez/models/tool/extra_requirements.py +2 -4
  130. waldiez/models/tool/predefined/_duckduckgo.py +1 -0
  131. waldiez/models/tool/predefined/_email.py +1 -0
  132. waldiez/models/tool/predefined/_google.py +1 -0
  133. waldiez/models/tool/predefined/_perplexity.py +1 -0
  134. waldiez/models/tool/predefined/_searxng.py +1 -0
  135. waldiez/models/tool/predefined/_tavily.py +1 -0
  136. waldiez/models/tool/predefined/_wikipedia.py +1 -0
  137. waldiez/models/tool/predefined/_youtube.py +1 -0
  138. waldiez/models/tool/tool.py +8 -5
  139. waldiez/models/tool/tool_data.py +2 -2
  140. waldiez/models/waldiez.py +152 -4
  141. waldiez/runner.py +11 -5
  142. waldiez/running/async_utils.py +192 -0
  143. waldiez/running/base_runner.py +117 -264
  144. waldiez/running/dir_utils.py +52 -0
  145. waldiez/running/environment.py +10 -44
  146. waldiez/running/events_mixin.py +252 -0
  147. waldiez/running/exceptions.py +20 -0
  148. waldiez/running/gen_seq_diagram.py +18 -15
  149. waldiez/running/io_utils.py +216 -0
  150. waldiez/running/protocol.py +11 -5
  151. waldiez/running/requirements_mixin.py +65 -0
  152. waldiez/running/results_mixin.py +926 -0
  153. waldiez/running/standard_runner.py +22 -25
  154. waldiez/running/step_by_step/breakpoints_mixin.py +192 -60
  155. waldiez/running/step_by_step/command_handler.py +3 -0
  156. waldiez/running/step_by_step/events_processor.py +194 -14
  157. waldiez/running/step_by_step/step_by_step_models.py +110 -43
  158. waldiez/running/step_by_step/step_by_step_runner.py +107 -57
  159. waldiez/running/subprocess_runner/__base__.py +9 -1
  160. waldiez/running/subprocess_runner/_async_runner.py +5 -3
  161. waldiez/running/subprocess_runner/_sync_runner.py +6 -2
  162. waldiez/running/subprocess_runner/runner.py +39 -23
  163. waldiez/running/timeline_processor.py +1 -1
  164. waldiez/utils/__init__.py +2 -0
  165. waldiez/utils/conflict_checker.py +4 -4
  166. waldiez/utils/python_manager.py +415 -0
  167. waldiez/ws/_file_handler.py +18 -18
  168. waldiez/ws/_mock.py +2 -1
  169. waldiez/ws/cli.py +36 -12
  170. waldiez/ws/client_manager.py +35 -27
  171. waldiez/ws/errors.py +3 -0
  172. waldiez/ws/models.py +43 -52
  173. waldiez/ws/reloader.py +12 -4
  174. waldiez/ws/server.py +85 -55
  175. waldiez/ws/session_manager.py +8 -9
  176. waldiez/ws/session_stats.py +1 -1
  177. waldiez/ws/utils.py +4 -1
  178. {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/METADATA +82 -93
  179. waldiez-0.6.1.dist-info/RECORD +254 -0
  180. waldiez/running/post_run.py +0 -186
  181. waldiez/running/pre_run.py +0 -281
  182. waldiez/running/run_results.py +0 -14
  183. waldiez/running/utils.py +0 -625
  184. waldiez-0.6.0.dist-info/RECORD +0 -251
  185. {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/WHEEL +0 -0
  186. {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/entry_points.txt +0 -0
  187. {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/licenses/LICENSE +0 -0
  188. {waldiez-0.6.0.dist-info → waldiez-0.6.1.dist-info}/licenses/NOTICE.md +0 -0
waldiez/io/redis.py CHANGED
@@ -4,6 +4,8 @@
4
4
  # flake8: noqa: E501
5
5
  # pylint: disable=too-many-try-statements,broad-exception-caught
6
6
  # pylint: disable=line-too-long,duplicate-code
7
+ # pyright: reportMissingTypeStubs=false,reportUnknownArgumentType=false
8
+ # pyright: reportUnknownMemberType=false
7
9
 
8
10
  """A Redis I/O stream for handling print and input messages."""
9
11
 
@@ -12,16 +14,10 @@ import logging
12
14
  import time
13
15
  import traceback as tb
14
16
  import uuid
17
+ from collections.abc import Awaitable
15
18
  from pathlib import Path
16
19
  from types import TracebackType
17
- from typing import (
18
- TYPE_CHECKING,
19
- Any,
20
- Awaitable,
21
- Callable,
22
- Optional,
23
- Type,
24
- )
20
+ from typing import TYPE_CHECKING, Any, Callable
25
21
 
26
22
  try:
27
23
  import redis
@@ -60,10 +56,10 @@ class RedisIOStream(IOStream):
60
56
  redis: Redis
61
57
  task_id: str
62
58
  input_timeout: int
63
- on_input_request: Optional[Callable[[str, str, str], None]]
64
- on_input_received: Optional[Callable[[str, str], None]]
59
+ on_input_request: Callable[[str, str, str], None] | None
60
+ on_input_response: Callable[[str, str], None] | None
65
61
  max_stream_size: int
66
- output_stream: str
62
+ task_output_stream: str
67
63
  input_request_channel: str
68
64
  input_response_channel: str
69
65
 
@@ -73,8 +69,8 @@ class RedisIOStream(IOStream):
73
69
  task_id: str | None = None,
74
70
  input_timeout: int = 120,
75
71
  max_stream_size: int = 1000,
76
- on_input_request: Optional[Callable[[str, str, str], None]] = None,
77
- on_input_response: Optional[Callable[[str, str], None]] = None,
72
+ on_input_request: Callable[[str, str, str], None] | None = None,
73
+ on_input_response: Callable[[str, str], None] | None = None,
78
74
  redis_connection_kwargs: dict[str, Any] | None = None,
79
75
  uploads_root: Path | str | None = None,
80
76
  ) -> None:
@@ -127,7 +123,7 @@ class RedisIOStream(IOStream):
127
123
 
128
124
  def __exit__(
129
125
  self,
130
- exc_type: Type[Exception] | None,
126
+ exc_type: type[Exception] | None,
131
127
  exc_value: Exception | None,
132
128
  traceback: TracebackType | None,
133
129
  ) -> None:
@@ -165,7 +161,7 @@ class RedisIOStream(IOStream):
165
161
  """
166
162
  LOG.debug("Sending print message: %s", payload)
167
163
  RedisIOStream.try_do(
168
- self.redis.xadd, # pyright: ignore
164
+ self.redis.xadd,
169
165
  self.task_output_stream,
170
166
  payload,
171
167
  maxlen=self.max_stream_size,
@@ -182,7 +178,7 @@ class RedisIOStream(IOStream):
182
178
  """
183
179
  LOG.debug("Sending print message: %s", payload)
184
180
  RedisIOStream.try_do(
185
- self.redis.xadd, # pyright: ignore
181
+ self.redis.xadd,
186
182
  self.common_output_stream,
187
183
  payload,
188
184
  maxlen=self.max_stream_size,
@@ -414,7 +410,7 @@ class RedisIOStream(IOStream):
414
410
  )
415
411
 
416
412
  @staticmethod
417
- def _extract_message_data(data: Any) -> Optional[dict[str, Any]]:
413
+ def _extract_message_data(data: Any) -> dict[str, Any] | None:
418
414
  """Extract and parse the message data field."""
419
415
  message_data = data
420
416
 
@@ -431,7 +427,7 @@ class RedisIOStream(IOStream):
431
427
  LOG.error("Invalid message data format: %s", message_data)
432
428
  return None
433
429
 
434
- return message_data # pyright: ignore
430
+ return message_data # pyright: ignore[reportUnknownVariableType]
435
431
 
436
432
  @staticmethod
437
433
  def _message_has_required_fields(message_data: dict[str, Any]) -> bool:
@@ -445,7 +441,7 @@ class RedisIOStream(IOStream):
445
441
  @staticmethod
446
442
  def _process_nested_data(
447
443
  message_data: dict[str, Any],
448
- ) -> Optional[dict[str, Any]]:
444
+ ) -> dict[str, Any] | None:
449
445
  """Process nested JSON data if present."""
450
446
  # Create a copy to avoid modifying the original
451
447
  processed_data = message_data.copy()
@@ -467,7 +463,7 @@ class RedisIOStream(IOStream):
467
463
  @staticmethod
468
464
  def _create_user_response(
469
465
  message_data: dict[str, Any],
470
- ) -> Optional["UserResponse"]:
466
+ ) -> UserResponse | None:
471
467
  """Create UserResponse object from validated data."""
472
468
  try:
473
469
  return UserResponse.model_validate(message_data)
@@ -684,7 +680,7 @@ class RedisIOStream(IOStream):
684
680
  """
685
681
  for key in redis_client.scan_iter("task:*:output", count=100):
686
682
  RedisIOStream.try_do(
687
- redis_client.xtrim, # pyright: ignore
683
+ redis_client.xtrim,
688
684
  key,
689
685
  maxlen=maxlen,
690
686
  approximate=approximate,
@@ -760,7 +756,7 @@ class RedisIOStream(IOStream):
760
756
  ): # pragma: no branch
761
757
  before = await redis_client.xlen(key)
762
758
  await RedisIOStream.a_try_do(
763
- redis_client.xtrim, # pyright: ignore
759
+ redis_client.xtrim,
764
760
  key,
765
761
  maxlen=maxlen,
766
762
  approximate=approximate,
waldiez/io/structured.py CHANGED
@@ -1,12 +1,15 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
 
4
+ # pyright: reportMissingTypeStubs=false,reportUnknownVariableType=false
5
+ # pyright: reportUnknownArgumentType=false,reportArgumentType=false
6
+ # pyright: reportUnknownMemberType=false,reportAttributeAccessIssue=false
7
+ # pyright: reportPrivateImportUsage=false
8
+
4
9
  """Structured I/O stream for JSON-based communication over stdin/stdout."""
5
10
 
6
11
  import json
7
- import queue
8
12
  import sys
9
- import threading
10
13
  from getpass import getpass
11
14
  from pathlib import Path
12
15
  from typing import Any
@@ -63,14 +66,16 @@ class StructuredIOStream(IOStream):
63
66
  The data to print.
64
67
  kwargs : Any
65
68
  """
66
- sep = kwargs.get("sep", " ")
67
- end = kwargs.get("end", "\n")
68
- flush = kwargs.get("flush", True)
69
- payload_type = kwargs.get("type", "print")
69
+ sep = str(kwargs.get("sep", " "))
70
+ end = str(kwargs.get("end", "\n"))
71
+ flush = bool(kwargs.get("flush", True))
72
+ payload_type = str(kwargs.get("type", "print"))
70
73
  message = sep.join(map(str, args))
71
74
  if len(args) == 1 and isinstance(args[0], dict):
72
- message = args[0] # pyright: ignore
73
- payload_type = message.get("type", payload_type) # pyright: ignore
75
+ message = args[0] # type: ignore
76
+ payload_type_ = message.get("type", payload_type) # type: ignore
77
+ if isinstance(payload_type_, str):
78
+ payload_type = payload_type_
74
79
  is_dumped = True
75
80
  else:
76
81
  is_dumped, message = is_json_dumped(message)
@@ -83,27 +88,35 @@ class StructuredIOStream(IOStream):
83
88
  # "data": message,
84
89
  }
85
90
  if isinstance(message, dict):
86
- payload.update(message) # pyright: ignore
91
+ payload.update(message)
92
+ end = ""
87
93
  else:
88
94
  payload["data"] = message
89
95
  if "type" not in payload:
90
96
  payload["type"] = payload_type
91
97
  else:
92
- print_message = PrintMessage(data=message) # pyright: ignore
98
+ print_message = PrintMessage(data=message)
93
99
  payload = print_message.model_dump(mode="json", fallback=str)
94
100
  payload["type"] = payload_type
95
101
  dumped = json.dumps(payload, default=str, ensure_ascii=False) + end
96
- if kwargs.get("file") and kwargs["file"] in [
102
+ file = kwargs.get("file", None)
103
+ if file and file in [
97
104
  sys.stderr,
98
105
  sys.__stderr__,
99
106
  sys.stdout,
100
107
  sys.__stdout__,
101
108
  ]:
102
- print(dumped, file=kwargs["file"], flush=flush)
109
+ print(dumped, file=file, flush=flush)
103
110
  else:
104
111
  print(dumped, flush=flush)
105
112
 
106
- def input(self, prompt: str = "", *, password: bool = False) -> str:
113
+ def input(
114
+ self,
115
+ prompt: str = "",
116
+ *,
117
+ password: bool = False,
118
+ request_id: str | None = None,
119
+ ) -> str:
107
120
  """Structured input from stdin.
108
121
 
109
122
  Parameters
@@ -112,13 +125,15 @@ class StructuredIOStream(IOStream):
112
125
  The prompt to display. Defaults to "".
113
126
  password : bool, optional
114
127
  Whether to read a password. Defaults to False.
128
+ request_id : str, optional
129
+ The request id. If not provided, a new will be generated.
115
130
 
116
131
  Returns
117
132
  -------
118
133
  str
119
134
  The line read from the input stream.
120
135
  """
121
- request_id = gen_id()
136
+ input_request_id = request_id or gen_id()
122
137
  prompt = prompt or ">"
123
138
  if not prompt or prompt in [">", "> "]: # pragma: no cover
124
139
  # if the prompt is just ">" or "> ",
@@ -129,15 +144,17 @@ class StructuredIOStream(IOStream):
129
144
  input_type = "debug"
130
145
  self._send_input_request(
131
146
  prompt,
132
- request_id,
147
+ input_request_id,
133
148
  password,
134
149
  input_type=input_type,
135
150
  )
136
- user_input_raw = self._read_user_input(prompt, password, request_id)
137
- response = self._handle_user_input(user_input_raw, request_id)
151
+ user_input_raw = self._read_user_input(
152
+ prompt, password, input_request_id
153
+ )
154
+ response = self._handle_user_input(user_input_raw, input_request_id)
138
155
  user_response = response.to_string(
139
156
  uploads_root=self.uploads_root,
140
- base_name=request_id,
157
+ base_name=input_request_id,
141
158
  )
142
159
  return user_response
143
160
 
@@ -163,11 +180,8 @@ class StructuredIOStream(IOStream):
163
180
  content_block["content"] = try_parse_maybe_serialized(
164
181
  inner_content
165
182
  )
166
- print(
167
- json.dumps(message_dump, default=str),
168
- flush=True,
169
- file=sys.stdout,
170
- )
183
+ message_dump["timestamp"] = now()
184
+ print(json.dumps(message_dump, default=str), flush=True)
171
185
 
172
186
  # noinspection PyMethodMayBeStatic
173
187
  # pylint: disable=no-self-use
@@ -197,33 +211,15 @@ class StructuredIOStream(IOStream):
197
211
  password: bool,
198
212
  request_id: str,
199
213
  ) -> str:
200
- input_queue: queue.Queue[str] = queue.Queue()
201
-
202
- def read_input() -> None:
203
- """Read user input from stdin."""
204
- try:
205
- user_input = (
206
- getpass(prompt).strip()
207
- if password
208
- else input(prompt).strip()
209
- )
210
- input_queue.put(user_input)
211
- except EOFError:
212
- input_queue.put("")
213
-
214
- input_thread = threading.Thread(target=read_input, daemon=True)
215
- input_thread.start()
216
-
217
214
  try:
218
- return input_queue.get(timeout=self.timeout)
219
- except queue.Empty:
220
- self._send_timeout_message(request_id)
215
+ return (
216
+ getpass(prompt).strip() if password else input(prompt).strip()
217
+ )
218
+ except EOFError:
221
219
  return ""
222
220
  except BaseException as e:
223
221
  self._send_error_message(request_id, str(e))
224
222
  return ""
225
- finally:
226
- input_thread.join(timeout=1)
227
223
 
228
224
  def _send_timeout_message(self, request_id: str) -> None:
229
225
  timeout_payload = {
@@ -330,7 +326,10 @@ class StructuredIOStream(IOStream):
330
326
  response_type = "input_response"
331
327
  else:
332
328
  response_type = _response_type
333
- if user_input.get("request_id") == request_id:
329
+ if (
330
+ user_input.get("request_id") == request_id
331
+ or response_type == "debug_input_response"
332
+ ):
334
333
  # We have a valid response to our request
335
334
  data = user_input.get("data")
336
335
  if not data:
@@ -345,7 +344,7 @@ class StructuredIOStream(IOStream):
345
344
  )
346
345
  if isinstance(data, list):
347
346
  return self._handle_list_response(
348
- data, # pyright: ignore
347
+ data,
349
348
  request_id=request_id,
350
349
  response_type=response_type,
351
350
  )
@@ -365,7 +364,7 @@ class StructuredIOStream(IOStream):
365
364
  type=response_type,
366
365
  data=self._format_multimedia_response(
367
366
  request_id=request_id,
368
- data=data, # pyright: ignore
367
+ data=data,
369
368
  ),
370
369
  request_id=request_id,
371
370
  )
@@ -391,7 +390,7 @@ class StructuredIOStream(IOStream):
391
390
  request_id: str,
392
391
  response_type: MessageType,
393
392
  ) -> UserResponse:
394
- if len(data) == 0: # pyright: ignore
393
+ if len(data) == 0:
395
394
  # Empty list, return empty response
396
395
  return UserResponse(
397
396
  type=response_type,
@@ -400,7 +399,7 @@ class StructuredIOStream(IOStream):
400
399
  )
401
400
 
402
401
  input_data: list[UserInputData] = []
403
- for entry in data: # pyright: ignore
402
+ for entry in data:
404
403
  # pylint: disable=broad-exception-caught
405
404
  try:
406
405
  content = UserInputData.model_validate(entry)
@@ -435,8 +434,8 @@ class StructuredIOStream(IOStream):
435
434
  # Create a log message
436
435
  got_id: str | None = None
437
436
  if isinstance(response, dict):
438
- got_id = response.get("request_id") # pyright: ignore
439
- response_str = str(response) # pyright: ignore
437
+ got_id = response.get("request_id")
438
+ response_str = str(response)
440
439
  message = response_str[:100] + (
441
440
  "..." if len(response_str) > 100 else ""
442
441
  )
@@ -481,7 +480,7 @@ class StructuredIOStream(IOStream):
481
480
  result: list[str] = []
482
481
  if "content" in data and isinstance(data["content"], dict):
483
482
  return self._format_multimedia_response(
484
- data=data["content"], # pyright: ignore
483
+ data=data["content"],
485
484
  request_id=request_id,
486
485
  )
487
486
 
waldiez/io/utils.py CHANGED
@@ -1,6 +1,8 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
 
4
+ # pyright: reportMissingTypeStubs=false,reportDeprecated=false
5
+
4
6
  """Utility functions for the waldiez.io package."""
5
7
 
6
8
  import ast
@@ -15,6 +17,7 @@ from autogen.events import BaseEvent # type: ignore
15
17
  from autogen.messages import BaseMessage # type: ignore
16
18
 
17
19
  DEBUG_INPUT_PROMPT = (
20
+ # cspell: disable-next-line
18
21
  "[Step] (c)ontinue, (r)un, (q)uit, (i)nfo, (h)elp, (st)ats: "
19
22
  )
20
23
  START_CHAT_PROMPT = "Enter your message to start the conversation: "
waldiez/io/ws.py CHANGED
@@ -1,6 +1,9 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+
3
4
  # pylint: disable=too-many-try-statements
5
+ # pyright: reportMissingTypeStubs=false,reportReturnType=false
6
+
4
7
  """WebSocket IOStream implementation for AsyncIO."""
5
8
 
6
9
  import asyncio
@@ -30,12 +33,13 @@ from .utils import (
30
33
  LOG = logging.getLogger(__name__)
31
34
 
32
35
  if not is_websocket_available(): # pragma: no cover
33
- raise ImportError(
36
+ _msg = ( # pylint: disable=invalid-name
34
37
  "WebSocket support requires "
35
38
  "either the 'websockets' or 'starlette' package. "
36
39
  "Please install one of them with "
37
40
  "`pip install websockets` or `pip install starlette`."
38
41
  )
42
+ raise ImportError(_msg)
39
43
 
40
44
 
41
45
  class AsyncWebsocketsIOStream(IOStream):
waldiez/logger.py CHANGED
@@ -3,6 +3,8 @@
3
3
  # pylint: disable=broad-exception-caught,too-many-try-statements
4
4
  """Waldiez logger."""
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  import inspect
7
9
  import logging
8
10
  import os
@@ -10,13 +12,15 @@ import re
10
12
  import string
11
13
  import threading
12
14
  import traceback
15
+ from collections.abc import Mapping
13
16
  from datetime import datetime
14
17
  from enum import IntEnum
15
18
  from pathlib import Path
16
19
  from types import TracebackType
17
- from typing import Any, Callable, Mapping, Optional
20
+ from typing import Any, Callable
18
21
 
19
22
  import click
23
+ from typing_extensions import override
20
24
 
21
25
  HERE = Path(__file__).parent
22
26
 
@@ -41,7 +45,7 @@ class WaldiezLogger(logging.Logger):
41
45
  - logger.info("User {user} has {count} items", user="john", count=5)
42
46
  """
43
47
 
44
- _instance: Optional["WaldiezLogger"] = None
48
+ _instance: WaldiezLogger | None = None
45
49
  _lock: threading.Lock = threading.Lock()
46
50
 
47
51
  _INTERNAL_METHODS = {
@@ -179,6 +183,7 @@ class WaldiezLogger(logging.Logger):
179
183
  return self._level_map.get(level.upper(), LogLevel.INFO)
180
184
 
181
185
  # pylint: disable=unused-argument
186
+ @override
182
187
  def log(
183
188
  self,
184
189
  level: int,
@@ -249,6 +254,7 @@ class WaldiezLogger(logging.Logger):
249
254
  level_int = self._get_level_number(level)
250
255
  self.log(level_int, msg, *args, **kwargs)
251
256
 
257
+ @override
252
258
  def debug(self, msg: Any, *args: Any, **kwargs: Any) -> None:
253
259
  """Log a debug message.
254
260
 
@@ -263,6 +269,7 @@ class WaldiezLogger(logging.Logger):
263
269
  """
264
270
  self.do_log(msg, *args, level="debug", **kwargs)
265
271
 
272
+ @override
266
273
  def info(self, msg: Any, *args: Any, **kwargs: Any) -> None:
267
274
  """Log an informational message.
268
275
 
@@ -291,6 +298,7 @@ class WaldiezLogger(logging.Logger):
291
298
  """
292
299
  self.do_log(msg, *args, level="success", **kwargs)
293
300
 
301
+ @override
294
302
  def warning(self, msg: Any, *args: Any, **kwargs: Any) -> None:
295
303
  """Log a warning message.
296
304
 
@@ -305,6 +313,7 @@ class WaldiezLogger(logging.Logger):
305
313
  """
306
314
  self.do_log(msg, *args, level="warning", **kwargs)
307
315
 
316
+ @override
308
317
  def error(self, msg: Any, *args: Any, **kwargs: Any) -> None:
309
318
  """Log an error message.
310
319
 
@@ -319,6 +328,7 @@ class WaldiezLogger(logging.Logger):
319
328
  """
320
329
  self.do_log(msg, *args, level="error", **kwargs)
321
330
 
331
+ @override
322
332
  def critical(self, msg: Any, *args: Any, **kwargs: Any) -> None:
323
333
  """Log a critical error message.
324
334
 
@@ -333,6 +343,7 @@ class WaldiezLogger(logging.Logger):
333
343
  """
334
344
  self.do_log(msg, *args, level="critical", **kwargs)
335
345
 
346
+ @override
336
347
  def exception(self, msg: Any, *args: Any, **kwargs: Any) -> None:
337
348
  """Log an exception message.
338
349
 
@@ -354,6 +365,7 @@ class WaldiezLogger(logging.Logger):
354
365
  if tb and "NoneType: None" not in tb: # pragma: no branch
355
366
  click.echo(click.style(tb, fg="red", dim=True))
356
367
 
368
+ @override
357
369
  def setLevel(self, level: int | str) -> None:
358
370
  """
359
371
  Set the logging level.
@@ -388,10 +400,11 @@ class WaldiezLogger(logging.Logger):
388
400
  self._level = level_upper
389
401
  super().setLevel(self._level_map[level_upper].value)
390
402
  else:
391
- raise ValueError(
403
+ msg = (
392
404
  f"Invalid log level: {level}. "
393
405
  f"Valid levels are: {list(self._level_map.keys())}"
394
406
  )
407
+ raise ValueError(msg)
395
408
 
396
409
  def get_level(self) -> str:
397
410
  """Get the current logging level.
@@ -1,5 +1,8 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+
4
+ # pyright: reportImportCycles=false
5
+
3
6
  """Agent models."""
4
7
 
5
8
  from .agent import (
@@ -1,6 +1,8 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+
3
4
  # pylint: disable=too-many-public-methods
5
+ # pyright: reportArgumentType=false
4
6
  """Base agent class to be inherited by all agents."""
5
7
 
6
8
  import warnings
@@ -71,7 +73,7 @@ class WaldiezAgent(WaldiezBase):
71
73
  title="Type",
72
74
  description="The type of the 'node' in a graph.",
73
75
  ),
74
- ] = "agent"
76
+ ]
75
77
  agent_type: Annotated[
76
78
  WaldiezAgentType,
77
79
  Field(
@@ -93,7 +95,7 @@ class WaldiezAgent(WaldiezBase):
93
95
  title="Description",
94
96
  description="The description of the agent",
95
97
  ),
96
- ] = "Agent's description"
98
+ ]
97
99
  tags: Annotated[
98
100
  list[str],
99
101
  Field(
@@ -101,7 +103,7 @@ class WaldiezAgent(WaldiezBase):
101
103
  description="Tags of the agent",
102
104
  default_factory=list,
103
105
  ),
104
- ] = []
106
+ ]
105
107
  requirements: Annotated[
106
108
  list[str],
107
109
  Field(
@@ -109,7 +111,7 @@ class WaldiezAgent(WaldiezBase):
109
111
  description="Python requirements for the agent",
110
112
  default_factory=list,
111
113
  ),
112
- ] = []
114
+ ]
113
115
  created_at: Annotated[
114
116
  str,
115
117
  Field(
@@ -131,7 +133,7 @@ class WaldiezAgent(WaldiezBase):
131
133
  Field(
132
134
  title="Data",
133
135
  description="The data (properties) of the agent",
134
- default_factory=WaldiezAgentData, # pyright: ignore
136
+ default_factory=WaldiezAgentData,
135
137
  ),
136
138
  ]
137
139
 
@@ -139,7 +141,7 @@ class WaldiezAgent(WaldiezBase):
139
141
  list[WaldiezHandoff],
140
142
  Field(
141
143
  init=False, # this is not a field in the constructor
142
- default_factory=list[WaldiezHandoff],
144
+ default_factory=list,
143
145
  title="Handoffs",
144
146
  description=(
145
147
  "A list of handoffs (target ids) to register. "
@@ -148,10 +150,10 @@ class WaldiezAgent(WaldiezBase):
148
150
  ),
149
151
  ] = []
150
152
 
151
- _checked_nested_chats: Annotated[bool, Field(init=False, default=False)] = (
153
+ _checked_nested_chats: Annotated[bool, Field(default=False, init=False)] = (
152
154
  False
153
155
  )
154
- _checked_handoffs: Annotated[bool, Field(init=False, default=False)] = False
156
+ _checked_handoffs: Annotated[bool, Field(default=False, init=False)] = False
155
157
 
156
158
  @property
157
159
  def args_to_skip(self) -> list[str]:
@@ -190,10 +192,11 @@ class WaldiezAgent(WaldiezBase):
190
192
  If handoffs have not been gathered yet.
191
193
  """
192
194
  if not self._checked_handoffs:
193
- raise RuntimeError(
195
+ msg = (
194
196
  "Handoffs have not been gathered yet. "
195
197
  "Call gather_handoffs() first."
196
198
  )
199
+ raise RuntimeError(msg)
197
200
  return self._handoffs
198
201
 
199
202
  @field_validator("agent_type")
@@ -392,7 +395,7 @@ class WaldiezAgent(WaldiezBase):
392
395
  return class_name # pragma: no cover
393
396
 
394
397
  @property
395
- def ag2_imports(self) -> set[str]:
398
+ def ag2_imports(self) -> set[str]: # pylint: disable=too-complex
396
399
  """Return the AG2 imports of the agent.
397
400
 
398
401
  Returns
@@ -413,25 +416,28 @@ class WaldiezAgent(WaldiezBase):
413
416
  case "UserProxyAgent":
414
417
  imports.add("from autogen import UserProxyAgent")
415
418
  case "RetrieveUserProxyAgent":
416
- imports.add(
419
+ _imp = (
417
420
  "from autogen.agentchat.contrib.retrieve_user_proxy_agent "
418
421
  "import RetrieveUserProxyAgent"
419
422
  )
423
+ imports.add(_imp)
420
424
  case "MultimodalConversableAgent":
421
- imports.add(
425
+ _imp = (
422
426
  "from "
423
427
  "autogen.agentchat.contrib.multimodal_conversable_agent "
424
428
  "import MultimodalConversableAgent"
425
429
  )
430
+ imports.add(_imp)
426
431
  case "ReasoningAgent":
427
432
  imports.add(
428
433
  "from autogen.agents.experimental import ReasoningAgent"
429
434
  )
430
435
  case "CaptainAgent":
431
- imports.add(
436
+ _imp = (
432
437
  "from autogen.agentchat.contrib.captainagent "
433
438
  "import CaptainAgent"
434
439
  )
440
+ imports.add(_imp)
435
441
  case "GroupChatManager": # pragma: no branch
436
442
  imports.add("from autogen import GroupChat")
437
443
  imports.add("from autogen.agentchat import GroupChatManager")
@@ -443,10 +449,11 @@ class WaldiezAgent(WaldiezBase):
443
449
  case "ConversableAgent":
444
450
  imports.add("from autogen import ConversableAgent")
445
451
  case _: # pragma: no cover
446
- raise ValueError(
452
+ msg = (
447
453
  f"Unknown agent class: {agent_class}. "
448
454
  "Please implement the imports for this class."
449
455
  )
456
+ raise ValueError(msg)
450
457
  return imports
451
458
 
452
459
  def validate_linked_tools(
@@ -678,8 +685,8 @@ class WaldiezAgent(WaldiezBase):
678
685
  nested_chat = WaldiezAgentNestedChat(
679
686
  triggered_by=triggered_by,
680
687
  messages=messages,
681
- condition=chat_with_condition.condition, # pyright: ignore
682
- available=chat_with_condition.available, # pyright: ignore
688
+ condition=chat_with_condition.condition,
689
+ available=chat_with_condition.available,
683
690
  )
684
691
  self.data.nested_chats.append(nested_chat)
685
692