waldiez 0.5.6__py3-none-any.whl → 0.5.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.

Files changed (116) hide show
  1. waldiez/_version.py +1 -1
  2. waldiez/cli.py +17 -2
  3. waldiez/exporter.py +1 -1
  4. waldiez/exporting/agent/code_execution.py +8 -1
  5. waldiez/exporting/agent/exporter.py +2 -1
  6. waldiez/exporting/agent/extras/captain_agent_extras.py +1 -0
  7. waldiez/exporting/agent/extras/doc_agent_extras.py +2 -3
  8. waldiez/exporting/agent/extras/group_manager_agent_extas.py +1 -0
  9. waldiez/exporting/agent/extras/handoffs/after_work.py +4 -4
  10. waldiez/exporting/agent/extras/handoffs/target.py +3 -0
  11. waldiez/exporting/agent/extras/rag/chroma_extras.py +0 -4
  12. waldiez/exporting/agent/extras/rag/mongo_extras.py +0 -1
  13. waldiez/exporting/agent/extras/rag/pgvector_extras.py +0 -2
  14. waldiez/exporting/agent/extras/rag/qdrant_extras.py +0 -3
  15. waldiez/exporting/agent/extras/rag/vector_db_extras.py +3 -2
  16. waldiez/exporting/agent/factory.py +11 -11
  17. waldiez/exporting/agent/processor.py +3 -2
  18. waldiez/exporting/chats/exporter.py +2 -2
  19. waldiez/exporting/chats/factory.py +5 -5
  20. waldiez/exporting/chats/processor.py +22 -1
  21. waldiez/exporting/chats/utils/common.py +45 -1
  22. waldiez/exporting/chats/utils/group.py +1 -1
  23. waldiez/exporting/chats/utils/sequential.py +3 -68
  24. waldiez/exporting/chats/utils/single.py +1 -38
  25. waldiez/exporting/core/context.py +39 -38
  26. waldiez/exporting/core/exporter.py +10 -10
  27. waldiez/exporting/core/exporters.py +36 -0
  28. waldiez/exporting/core/extras/base.py +2 -2
  29. waldiez/exporting/core/extras/chat_extras.py +4 -2
  30. waldiez/exporting/core/extras/path_resolver.py +6 -4
  31. waldiez/exporting/core/extras/serializer.py +1 -0
  32. waldiez/exporting/core/protocols.py +6 -0
  33. waldiez/exporting/core/result.py +8 -7
  34. waldiez/exporting/core/types.py +2 -2
  35. waldiez/exporting/core/utils/llm_config.py +2 -0
  36. waldiez/exporting/flow/execution_generator.py +54 -32
  37. waldiez/exporting/flow/factory.py +2 -2
  38. waldiez/exporting/flow/file_generator.py +8 -7
  39. waldiez/exporting/flow/merger.py +8 -7
  40. waldiez/exporting/flow/orchestrator.py +22 -8
  41. waldiez/exporting/flow/utils/__init__.py +2 -0
  42. waldiez/exporting/flow/utils/common.py +20 -11
  43. waldiez/exporting/flow/utils/importing.py +2 -1
  44. waldiez/exporting/flow/utils/logging.py +5 -2
  45. waldiez/exporting/models/exporter.py +2 -1
  46. waldiez/exporting/models/factory.py +6 -7
  47. waldiez/exporting/tools/exporter.py +7 -6
  48. waldiez/exporting/tools/factory.py +4 -5
  49. waldiez/exporting/tools/processor.py +9 -4
  50. waldiez/exporting/tools/registration.py +1 -0
  51. waldiez/io/_ws.py +2 -0
  52. waldiez/io/models/content/audio.py +1 -0
  53. waldiez/io/models/content/file.py +1 -0
  54. waldiez/io/models/content/image.py +1 -0
  55. waldiez/io/models/content/text.py +1 -0
  56. waldiez/io/models/content/video.py +1 -0
  57. waldiez/io/models/user_input.py +1 -0
  58. waldiez/io/models/user_response.py +1 -0
  59. waldiez/io/mqtt.py +6 -3
  60. waldiez/io/redis.py +7 -9
  61. waldiez/io/structured.py +8 -6
  62. waldiez/io/utils.py +11 -4
  63. waldiez/io/ws.py +4 -3
  64. waldiez/logger.py +11 -1
  65. waldiez/models/agents/agent/agent.py +1 -0
  66. waldiez/models/agents/agent/agent_data.py +2 -2
  67. waldiez/models/agents/agent/nested_chat.py +1 -4
  68. waldiez/models/agents/agent/termination_message.py +0 -7
  69. waldiez/models/agents/agent/update_system_message.py +2 -2
  70. waldiez/models/agents/doc_agent/doc_agent_data.py +33 -26
  71. waldiez/models/agents/doc_agent/rag_query_engine.py +1 -1
  72. waldiez/models/agents/extra_requirements.py +5 -5
  73. waldiez/models/agents/group_manager/group_manager.py +3 -7
  74. waldiez/models/agents/group_manager/speakers.py +0 -7
  75. waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +0 -2
  76. waldiez/models/agents/rag_user_proxy/rag_user_proxy_data.py +0 -2
  77. waldiez/models/agents/rag_user_proxy/retrieve_config.py +1 -17
  78. waldiez/models/agents/rag_user_proxy/vector_db_config.py +0 -5
  79. waldiez/models/chat/chat_data.py +0 -2
  80. waldiez/models/chat/chat_summary.py +5 -3
  81. waldiez/models/common/handoff.py +26 -18
  82. waldiez/models/common/naming.py +1 -0
  83. waldiez/models/flow/flow.py +9 -7
  84. waldiez/models/model/_llm.py +4 -2
  85. waldiez/models/model/extra_requirements.py +3 -3
  86. waldiez/models/model/model.py +5 -4
  87. waldiez/models/tool/extra_requirements.py +2 -2
  88. waldiez/models/tool/predefined/_google.py +7 -12
  89. waldiez/models/tool/predefined/_perplexity.py +13 -9
  90. waldiez/models/tool/predefined/_searxng.py +4 -1
  91. waldiez/models/tool/predefined/_tavily.py +0 -6
  92. waldiez/models/tool/predefined/_wikipedia.py +5 -1
  93. waldiez/models/tool/predefined/_youtube.py +0 -4
  94. waldiez/models/tool/tool.py +7 -7
  95. waldiez/models/tool/tool_data.py +39 -2
  96. waldiez/models/waldiez.py +29 -29
  97. waldiez/runner.py +18 -13
  98. waldiez/running/base_runner.py +96 -40
  99. waldiez/running/environment.py +2 -0
  100. waldiez/running/patch_io_stream.py +2 -0
  101. waldiez/running/post_run.py +3 -0
  102. waldiez/running/pre_run.py +1 -0
  103. waldiez/running/protocol.py +50 -48
  104. waldiez/running/run_results.py +2 -10
  105. waldiez/running/standard_runner.py +37 -13
  106. waldiez/running/timeline_processor.py +12 -1
  107. waldiez/running/utils.py +2 -0
  108. waldiez/utils/conflict_checker.py +1 -1
  109. waldiez/utils/version.py +1 -0
  110. {waldiez-0.5.6.dist-info → waldiez-0.5.8.dist-info}/METADATA +68 -65
  111. {waldiez-0.5.6.dist-info → waldiez-0.5.8.dist-info}/RECORD +115 -116
  112. waldiez/exporting/agent/extras/group/target.py +0 -178
  113. {waldiez-0.5.6.dist-info → waldiez-0.5.8.dist-info}/WHEEL +0 -0
  114. {waldiez-0.5.6.dist-info → waldiez-0.5.8.dist-info}/entry_points.txt +0 -0
  115. {waldiez-0.5.6.dist-info → waldiez-0.5.8.dist-info}/licenses/LICENSE +0 -0
  116. {waldiez-0.5.6.dist-info → waldiez-0.5.8.dist-info}/licenses/NOTICE.md +0 -0
@@ -17,6 +17,7 @@ from .execution_generator import ExecutionGenerator
17
17
  from .utils.common import generate_header
18
18
 
19
19
 
20
+ # noinspection PyProtocol
20
21
  class FileGenerator(ContentGenerator):
21
22
  """Generate the complete flow notebook content."""
22
23
 
@@ -34,7 +35,7 @@ class FileGenerator(ContentGenerator):
34
35
  self.context = context
35
36
  self.config = context.get_config()
36
37
 
37
- # pylint: disable=too-many-locals
38
+ # pylint: disable=too-many-locals,unused-argument
38
39
  def generate(
39
40
  self,
40
41
  merged_result: ExportResult,
@@ -42,26 +43,26 @@ class FileGenerator(ContentGenerator):
42
43
  after_run: str,
43
44
  skip_logging: bool,
44
45
  **kwargs: Any,
45
- ) -> str:
46
- """Generate the complete flow notebook content.
46
+ ) -> str: # pyright: ignore
47
+ """Generate content based on provided parameters.
47
48
 
48
49
  Parameters
49
50
  ----------
50
51
  merged_result : ExportResult
51
52
  The merged export result containing all content.
52
53
  is_async : bool
53
- Whether to generate async conten
54
+ Whether to generate async content.
54
55
  after_run : str
55
56
  Additional content to add after the main flow execution.
56
57
  skip_logging : bool
57
58
  Whether to skip logging setup.
58
59
  **kwargs : Any
59
- Additional keyword arguments for the generator.
60
+ Parameters to influence content generation.
60
61
 
61
62
  Returns
62
63
  -------
63
64
  str
64
- The complete flow notebook content.
65
+ The generated content.
65
66
 
66
67
  Raises
67
68
  ------
@@ -214,7 +215,7 @@ class FileGenerator(ContentGenerator):
214
215
  tags=self.config.tags,
215
216
  for_notebook=self.config.for_notebook,
216
217
  )
217
- header_string = "\n".join(content.content for content in from_result)
218
+ header_string = "\n".join(item.content for item in from_result)
218
219
  while not header_string.endswith("\n\n"):
219
220
  header_string += "\n"
220
221
  return header_string
@@ -4,7 +4,6 @@
4
4
  """Content merger for combining multiple export results."""
5
5
 
6
6
  from dataclasses import dataclass, field
7
- from typing import Optional, Union
8
7
 
9
8
  from ..core import (
10
9
  ContentOrder,
@@ -34,12 +33,12 @@ class MergeStatistics:
34
33
  class ContentMerger:
35
34
  """Intelligently merges multiple ExportResult objects."""
36
35
 
37
- def __init__(self, context: Optional[ExporterContext] = None):
36
+ def __init__(self, context: ExporterContext | None = None):
38
37
  """Initialize the content merger.
39
38
 
40
39
  Parameters
41
40
  ----------
42
- context : Optional[ExporterContext], optional
41
+ context : ExporterContext | None, optional
43
42
  The exporter context, by default None
44
43
  """
45
44
  self.context = context or ExporterContext()
@@ -245,12 +244,13 @@ class ContentMerger:
245
244
  )
246
245
 
247
246
  # pylint: disable=no-self-use
248
- def _get_order_value(self, order: Union[int, ContentOrder]) -> int:
247
+ # noinspection PyMethodMayBeStatic
248
+ def _get_order_value(self, order: int | ContentOrder) -> int:
249
249
  """Get numeric value from order for sorting.
250
250
 
251
251
  Parameters
252
252
  ----------
253
- order : Union[int, ContentOrder]
253
+ order : int | ContentOrder
254
254
  The order value
255
255
 
256
256
  Returns
@@ -352,7 +352,8 @@ class ContentMerger:
352
352
  warnings=all_warnings,
353
353
  )
354
354
 
355
- def _merge_main_content(self, results: list[ExportResult]) -> Optional[str]:
355
+ # noinspection PyMethodMayBeStatic
356
+ def _merge_main_content(self, results: list[ExportResult]) -> str | None:
356
357
  """Merge main content from results.
357
358
 
358
359
  For flow exports, main content is typically empty since all content
@@ -365,7 +366,7 @@ class ContentMerger:
365
366
 
366
367
  Returns
367
368
  -------
368
- Optional[str]
369
+ str | None
369
370
  The merged main content, or None
370
371
  """
371
372
  main_contents: list[str] = []
@@ -22,6 +22,7 @@ from .merger import ContentMerger
22
22
  from .utils import (
23
23
  generate_header,
24
24
  get_after_run_content,
25
+ get_common_env_var_setup,
25
26
  get_np_no_nep50_handle,
26
27
  get_sqlite_out,
27
28
  get_start_logging,
@@ -31,6 +32,7 @@ from .utils import (
31
32
 
32
33
 
33
34
  # pylint: disable=no-self-use,too-many-instance-attributes
35
+ # noinspection PyMethodMayBeStatic
34
36
  class ExportOrchestrator:
35
37
  """Coordinates the export process."""
36
38
 
@@ -168,10 +170,15 @@ class ExportOrchestrator:
168
170
  position=ExportPosition.TOP, # befoe everything
169
171
  order=ContentOrder.EARLY_SETUP,
170
172
  )
173
+ merged_result.add_content(
174
+ get_common_env_var_setup(),
175
+ position=ExportPosition.IMPORTS, # after imports (need os)
176
+ order=ContentOrder.CLEANUP,
177
+ )
171
178
  merged_result.add_content(
172
179
  get_np_no_nep50_handle(),
173
180
  position=ExportPosition.IMPORTS, # after imports (need np)
174
- order=ContentOrder.CLEANUP,
181
+ order=ContentOrder.CLEANUP.value + 1,
175
182
  )
176
183
  if not self.should_skip_logging():
177
184
  merged_result.add_content(
@@ -180,7 +187,7 @@ class ExportOrchestrator:
180
187
  for_notebook=self.config.for_notebook,
181
188
  ),
182
189
  position=ExportPosition.IMPORTS, # after imports, before models
183
- order=ContentOrder.CLEANUP.value + 1, # after imports
190
+ order=ContentOrder.CLEANUP.value + 2, # after imports and np
184
191
  skip_strip=True, # keep newlines
185
192
  )
186
193
  # merged_result.add_content
@@ -266,6 +273,7 @@ class ExportOrchestrator:
266
273
  def _get_chats_exporter(self) -> ChatsExporter:
267
274
  """Get or create chats exporter."""
268
275
  if self._chats_exporter is None:
276
+ # noinspection PyTypeChecker
269
277
  self._chats_exporter = create_chats_exporter(
270
278
  waldiez=self.waldiez,
271
279
  all_agents=self.agents,
@@ -325,6 +333,7 @@ class ExportOrchestrator:
325
333
  agent_arguments: dict[str, list[str]],
326
334
  ) -> AgentExporter:
327
335
  """Create an exporter for a specific agent."""
336
+ # noinspection PyTypeChecker
328
337
  return create_agent_exporter(
329
338
  agent=agent,
330
339
  agent_names=self.agent_names,
@@ -343,6 +352,7 @@ class ExportOrchestrator:
343
352
  ),
344
353
  )
345
354
 
355
+ # noinspection PyMethodMayBeStatic
346
356
  def _extract_agent_arguments_from_result(
347
357
  self, result: ExportResult
348
358
  ) -> dict[str, list[str]]:
@@ -416,14 +426,18 @@ class ExportOrchestrator:
416
426
  def should_skip_logging(self) -> bool:
417
427
  """Determine if logging should be skipped.
418
428
 
429
+ In case there is any compatibility issue with logging
430
+ we can skip logging entirely (until handled/fixed).
431
+
432
+ e.g:
433
+ return self.waldiez.has_doc_agents
434
+ or:
435
+ if self.waldiez.flow.is_group_chat:
436
+ return any(tool.is_predefined for tool in self.waldiez.tools)
437
+
419
438
  Returns
420
439
  -------
421
440
  bool
422
441
  True if logging should be skipped, False otherwise.
423
442
  """
424
- return self.waldiez.has_doc_agents
425
- # if not self.waldiez.tools:
426
- # return False
427
- # if self.waldiez.flow.is_group_chat:
428
- # return any(tool.is_predefined for tool in self.waldiez.tools)
429
- # return False
443
+ return False
@@ -5,6 +5,7 @@
5
5
  from .common import (
6
6
  generate_header,
7
7
  get_after_run_content,
8
+ get_common_env_var_setup,
8
9
  get_np_no_nep50_handle,
9
10
  )
10
11
  from .importing import get_sorted_imports, get_the_imports_string
@@ -12,6 +13,7 @@ from .logging import get_sqlite_out, get_start_logging, get_stop_logging
12
13
 
13
14
  __all__ = [
14
15
  "generate_header",
16
+ "get_common_env_var_setup",
15
17
  "get_np_no_nep50_handle",
16
18
  "get_after_run_content",
17
19
  "get_the_imports_string",
@@ -102,29 +102,21 @@ Tags: {", ".join(tags)}
102
102
  """'''
103
103
 
104
104
 
105
- def main_doc_string(is_async: bool) -> str:
105
+ def main_doc_string() -> str:
106
106
  """Generate the docstring for the main function.
107
107
 
108
- Parameters
109
- ----------
110
- is_async : bool
111
- Whether the main function is asynchronous.
112
-
113
108
  Returns
114
109
  -------
115
110
  str
116
111
  The docstring for the main function.
117
112
  """
118
- return_type_hint = (
119
- "AsyncRunResponseProtocol" if is_async else "RunResponseProtocol"
120
- )
113
+ return_type_hint = "list[dict[str, Any]]"
121
114
  return f'''"""Start chatting.
122
115
 
123
116
  Returns
124
117
  -------
125
118
  {return_type_hint}
126
- The result of the chat session, which can be a single ChatResult,
127
- a list of ChatResults, or a dictionary mapping integers to ChatResults.
119
+ The result of the chat session.
128
120
 
129
121
  Raises
130
122
  ------
@@ -183,6 +175,23 @@ def get_after_run_content(
183
175
  return content
184
176
 
185
177
 
178
+ def get_common_env_var_setup() -> str:
179
+ """Get common environment variable setup for Waldiez flows.
180
+
181
+ Returns
182
+ -------
183
+ str
184
+ The content to set up common environment variables.
185
+ """
186
+ content = """
187
+ # Common environment variable setup for Waldiez flows
188
+ load_dotenv(override=True)
189
+ os.environ["AUTOGEN_USE_DOCKER"] = "0"
190
+ os.environ["ANONYMIZED_TELEMETRY"] = "False"
191
+ """
192
+ return content
193
+
194
+
186
195
  def get_np_no_nep50_handle() -> str:
187
196
  """Handle the "module numpy has no attribute _no_pep50_warning" error.
188
197
 
@@ -100,7 +100,8 @@ def sort_imports(
100
100
  third_party_imports.append(import_string)
101
101
  elif position == ImportPosition.LOCAL: # pragma: no branch
102
102
  local_imports.append(import_string)
103
-
103
+ if "from dotenv import load_dotenv" not in third_party_imports:
104
+ third_party_imports.append("from dotenv import load_dotenv")
104
105
  autogen_imports = clean_and_group_autogen_imports(autogen_imports)
105
106
  third_party_imports = ensure_np_import(third_party_imports)
106
107
  sorted_builtins = get_sorted_imports(builtin_imports)
@@ -49,7 +49,7 @@ def get_start_logging(is_async: bool, for_notebook: bool) -> str:
49
49
  "Start logging.",
50
50
  for_notebook=for_notebook,
51
51
  )
52
- if is_async is False:
52
+ if not is_async:
53
53
  return f'''
54
54
  {tab}{comment}
55
55
  {tab}def start_logging() -> None:
@@ -83,6 +83,7 @@ def get_start_logging(is_async: bool, for_notebook: bool) -> str:
83
83
 
84
84
 
85
85
  # pylint: disable=differing-param-doc,differing-type-doc
86
+ # noinspection PyUnresolvedReferences
86
87
  def get_sync_sqlite_out() -> str:
87
88
  r"""Get the sqlite to csv and json conversion code string.
88
89
 
@@ -165,6 +166,7 @@ def get_sync_sqlite_out() -> str:
165
166
 
166
167
 
167
168
  # pylint: disable=differing-param-doc,differing-type-doc,line-too-long
169
+ # noinspection PyUnresolvedReferences
168
170
  def get_async_sqlite_out() -> str:
169
171
  r"""Get the sqlite to csv and json conversion code string.
170
172
 
@@ -325,6 +327,7 @@ def get_sqlite_out_call(tabs: int, is_async: bool) -> str:
325
327
  return content
326
328
 
327
329
 
330
+ # noinspection PyUnresolvedReferences
328
331
  def get_stop_logging(is_async: bool, tabs: int = 0) -> str:
329
332
  r"""Get the function to stop logging and gather logs.
330
333
 
@@ -343,7 +346,7 @@ def get_stop_logging(is_async: bool, tabs: int = 0) -> str:
343
346
  Example
344
347
  -------
345
348
  ```python
346
- >>> get_logging_stop_string()
349
+ >>> get_stop_logging()
347
350
  def stop_logging() -> None:
348
351
  \"\"\"Stop logging.\"\"\"
349
352
  runtime_logging.stop()
@@ -186,7 +186,8 @@ class ModelsExporter(Exporter[ModelExtras]):
186
186
  for_notebook=self.config.for_notebook,
187
187
  )
188
188
  loader_script = f'''{comment}# NOTE:
189
- # This section assumes that a file named "{self.flow_name}_api_keys"
189
+ # This section assumes that a file named:
190
+ # "{self.flow_name}_api_keys.py"
190
191
  # exists in the same directory as this file.
191
192
  # This file contains the API keys for the models used in this flow.
192
193
  # It should be .gitignored and not shared publicly.
@@ -3,7 +3,6 @@
3
3
  """Factory function for creating a ModelsExporter instance."""
4
4
 
5
5
  from pathlib import Path
6
- from typing import Optional, Union
7
6
 
8
7
  from waldiez.models import WaldiezAgent, WaldiezModel
9
8
 
@@ -19,9 +18,9 @@ def create_models_exporter(
19
18
  models: list[WaldiezModel],
20
19
  model_names: dict[str, str],
21
20
  for_notebook: bool = False,
22
- cache_seed: Optional[int] = None,
23
- output_dir: Optional[Union[str, Path]] = None,
24
- context: Optional[ExporterContext] = None,
21
+ cache_seed: int | None = None,
22
+ output_dir: str | Path | None = None,
23
+ context: ExporterContext | None = None,
25
24
  ) -> ModelsExporter:
26
25
  """Create a models exporter.
27
26
 
@@ -39,11 +38,11 @@ def create_models_exporter(
39
38
  Mapping of model IDs to names.
40
39
  for_notebook : bool, optional
41
40
  Whether the export is for a notebook, by default False
42
- cache_seed : Optional[int], optional
41
+ cache_seed : int | None, optional
43
42
  The cache seed if any, by default None
44
- output_dir : Optional[Union[str, Path]], optional
43
+ output_dir : str | Path | None, optional
45
44
  Output directory for generated files, by default None
46
- context : Optional[ExporterContext], optional
45
+ context : ExporterContext | None, optional
47
46
  Exporter context with dependencies, by default None
48
47
 
49
48
  Returns
@@ -4,7 +4,7 @@
4
4
  """Tools exporter."""
5
5
 
6
6
  from pathlib import Path
7
- from typing import Any, Optional, Union
7
+ from typing import Any, Optional
8
8
 
9
9
  from waldiez.models import WaldiezAgent, WaldiezTool
10
10
 
@@ -32,8 +32,8 @@ class ToolsExporter(Exporter[ToolExtras]):
32
32
  agent_names: dict[str, str],
33
33
  tools: list[WaldiezTool],
34
34
  tool_names: dict[str, str],
35
- output_dir: Optional[Union[str, Path]] = None,
36
- context: Optional[ExporterContext] = None,
35
+ output_dir: str | Path | None = None,
36
+ context: ExporterContext | None = None,
37
37
  **kwargs: Any,
38
38
  ):
39
39
  """Initialize the tools exporter.
@@ -50,9 +50,9 @@ class ToolsExporter(Exporter[ToolExtras]):
50
50
  The tools to export.
51
51
  tool_names : dict[str, str]
52
52
  Mapping of tool IDs to names.
53
- output_dir : Optional[Union[str, Path]], optional
53
+ output_dir : str | Path | None
54
54
  Output directory for generated files, by default None
55
- context : Optional[ExporterContext], optional
55
+ context : ExporterContext | None
56
56
  Exporter context with dependencies, by default None
57
57
  **kwargs
58
58
  Additional keyword arguments.
@@ -176,7 +176,8 @@ class ToolsExporter(Exporter[ToolExtras]):
176
176
  for_notebook=self.config.for_notebook,
177
177
  )
178
178
  loader_script = f'''{comment}# NOTE:
179
- # This section assumes that a file named "{self.flow_name}_{tool_name}_secrets"
179
+ # This section assumes that a file named:
180
+ # "{self.flow_name}_{tool_name}_secrets.py"
180
181
  # exists in the same directory as this file.
181
182
  # This file contains the secrets for the tool used in this flow.
182
183
  # It should be .gitignored and not shared publicly.
@@ -3,7 +3,6 @@
3
3
  """Factory function for creating a ToolsExporter instance."""
4
4
 
5
5
  from pathlib import Path
6
- from typing import Optional, Union
7
6
 
8
7
  from waldiez.models import WaldiezAgent, WaldiezTool
9
8
 
@@ -17,8 +16,8 @@ def create_tools_exporter(
17
16
  agent_names: dict[str, str],
18
17
  tools: list[WaldiezTool],
19
18
  tool_names: dict[str, str],
20
- output_dir: Optional[Union[str, Path]] = None,
21
- context: Optional[ExporterContext] = None,
19
+ output_dir: str | Path | None = None,
20
+ context: ExporterContext | None = None,
22
21
  ) -> ToolsExporter:
23
22
  """Create a tools exporter.
24
23
 
@@ -34,9 +33,9 @@ def create_tools_exporter(
34
33
  The tools to export.
35
34
  tool_names : dict[str, str]
36
35
  Mapping of tool IDs to names.
37
- output_dir : Optional[Union[str, Path]], optional
36
+ output_dir : str | Path | None, optional
38
37
  Output directory for generated files, by default None
39
- context : Optional[ExporterContext], optional
38
+ context : ExporterContext | None, optional
40
39
  Exporter context with dependencies, by default None
41
40
 
42
41
  Returns
@@ -5,7 +5,6 @@
5
5
 
6
6
  from dataclasses import dataclass, field
7
7
  from pathlib import Path
8
- from typing import Optional
9
8
 
10
9
  from waldiez.models import WaldiezTool
11
10
 
@@ -34,7 +33,7 @@ class ToolProcessor:
34
33
  flow_name: str,
35
34
  tools: list[WaldiezTool],
36
35
  tool_names: dict[str, str],
37
- output_dir: Optional[Path] = None,
36
+ output_dir: Path | None = None,
38
37
  ):
39
38
  """Initialize the tool processor.
40
39
 
@@ -46,7 +45,7 @@ class ToolProcessor:
46
45
  The tools to process.
47
46
  tool_names : dict[str, str]
48
47
  Mapping of tool IDs to names.
49
- output_dir : Optional[Path], optional
48
+ output_dir : Path | None, optional
50
49
  Output directory for generated files, by default None
51
50
  """
52
51
  self.flow_name = flow_name
@@ -193,7 +192,12 @@ ag2_{tool_name} = ag2_{tool_name}_interop.convert_tool(
193
192
  )
194
193
  f.write("import os\n\n")
195
194
  for key, value in tool.secrets.items():
196
- f.write(f'os.environ["{key}"] = "{value}"\n')
195
+ # f.write(f'os.environ["{key}"] = "{value}"\n')
196
+ # check first if the key already exists in os.environ
197
+ f.write(
198
+ f'os.environ["{key}"] = '
199
+ f'os.environ.get("{key}", "{value}")\n'
200
+ )
197
201
  except Exception as exc: # pragma: no cover
198
202
  raise ExporterContentError(
199
203
  f"Failed to write secrets file for tool '{tool_name}': {exc}"
@@ -217,6 +221,7 @@ ag2_{tool_name} = ag2_{tool_name}_interop.convert_tool(
217
221
  )
218
222
 
219
223
  # pylint: disable=no-self-use
224
+ # noinspection PyMethodMayBeStatic
220
225
  def _sort_imports(self, imports: list[str]) -> list[str]:
221
226
  """Sort imports: 'import' statements first, then 'from' statements.
222
227
 
@@ -99,6 +99,7 @@ class ToolRegistrationProcessor:
99
99
  return "\n".join(registrations) if registrations else ""
100
100
 
101
101
  # pylint: disable=no-self-use
102
+ # noinspection PyMethodMayBeStatic
102
103
  def _create_registration(
103
104
  self,
104
105
  caller_name: str,
waldiez/io/_ws.py CHANGED
@@ -93,6 +93,7 @@ class WebSocketsAdapter:
93
93
  The received message, decoded as a string.
94
94
  """
95
95
  # pylint: disable=too-many-try-statements
96
+ # noinspection PyBroadException
96
97
  try:
97
98
  response = await asyncio.wait_for(
98
99
  self.websocket.recv(), timeout=timeout
@@ -143,6 +144,7 @@ class StarletteAdapter:
143
144
  str
144
145
  The received message, decoded as a string.
145
146
  """
147
+ # noinspection PyBroadException
146
148
  try:
147
149
  return await asyncio.wait_for(
148
150
  self.websocket.receive_text(), timeout=timeout
@@ -11,6 +11,7 @@ from pydantic import BaseModel
11
11
  from .base import AudioContent
12
12
 
13
13
 
14
+ # noinspection PyUnusedLocal
14
15
  class AudioMediaContent(BaseModel):
15
16
  """Audio media content."""
16
17
 
@@ -11,6 +11,7 @@ from pydantic import BaseModel
11
11
  from .base import FileContent
12
12
 
13
13
 
14
+ # noinspection PyUnusedLocal
14
15
  class FileMediaContent(BaseModel):
15
16
  """File media content."""
16
17
 
@@ -12,6 +12,7 @@ from ...utils import get_image
12
12
  from .base import ImageContent
13
13
 
14
14
 
15
+ # noinspection DuplicatedCode
15
16
  class ImageMediaContent(BaseModel):
16
17
  """Image media content."""
17
18
 
@@ -9,6 +9,7 @@ from pydantic import BaseModel
9
9
  from typing_extensions import Literal
10
10
 
11
11
 
12
+ # noinspection PyUnusedLocal
12
13
  class TextMediaContent(BaseModel):
13
14
  """Text media content."""
14
15
 
@@ -11,6 +11,7 @@ from typing_extensions import Literal
11
11
  from .base import VideoContent
12
12
 
13
13
 
14
+ # noinspection PyUnusedLocal
14
15
  class VideoMediaContent(BaseModel):
15
16
  """Video media content."""
16
17
 
@@ -186,6 +186,7 @@ class UserInputData(BaseModel):
186
186
 
187
187
  return None # pragma: no cover
188
188
 
189
+ # noinspection PyNestedDecorators
189
190
  @field_validator("content", mode="before")
190
191
  @classmethod
191
192
  def validate_content(cls, v: Any) -> MediaContent: # noqa: C901,D102
@@ -21,6 +21,7 @@ class UserResponse(StructuredBase):
21
21
  type: MessageType = "input_response"
22
22
  data: UserInputData | list[UserInputData] | str
23
23
 
24
+ # noinspection PyNestedDecorators
24
25
  @field_validator("data", mode="before")
25
26
  @classmethod
26
27
  def validate_data(
waldiez/io/mqtt.py CHANGED
@@ -33,6 +33,7 @@ except ImportError as error: # pragma: no cover
33
33
  "MQTT client not installed. Please install paho-mqtt with `pip install paho-mqtt`."
34
34
  ) from error
35
35
 
36
+ from autogen.events import BaseEvent # type: ignore
36
37
  from autogen.io import IOStream # type: ignore
37
38
  from autogen.messages import BaseMessage # type: ignore
38
39
 
@@ -54,6 +55,7 @@ MQTT_MAX_RECONNECT_COUNT = 12
54
55
  MQTT_MAX_RECONNECT_DELAY = 60
55
56
 
56
57
 
58
+ # noinspection PyUnusedLocal,PyBroadException
57
59
  class MqttIOStream(IOStream):
58
60
  """MQTT I/O stream."""
59
61
 
@@ -299,6 +301,7 @@ class MqttIOStream(IOStream):
299
301
  reconnect_count += 1
300
302
  LOG.info("Reconnect failed after %s attempts.", reconnect_count)
301
303
 
304
+ # noinspection PyUnresolvedReferences
302
305
  def _on_message(
303
306
  self, client: mqtt.Client, userdata: Any, msg: mqtt.MQTTMessage
304
307
  ) -> None:
@@ -476,13 +479,13 @@ class MqttIOStream(IOStream):
476
479
  )
477
480
  self._print(payload)
478
481
 
479
- def send(self, message: BaseMessage) -> None:
482
+ def send(self, message: BaseEvent | BaseMessage) -> None:
480
483
  """Send a structured message to MQTT.
481
484
 
482
485
  Parameters
483
486
  ----------
484
- message : BaseMessage
485
- The message to send.
487
+ message : BaseEvent | BaseMessage
488
+ The message or event to send.
486
489
  """
487
490
  try:
488
491
  message_dump = message.model_dump(mode="json")