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
@@ -41,6 +41,7 @@ def get_valid_python_variable_name(
41
41
  # \W matches any non-word character, but in Python's re module,
42
42
  # \w includes Unicode letters by default, so we need to be more explicit
43
43
  # to replace Unicode letters with underscores for valid Python identifiers
44
+ # noinspection RegExpSimplifiable
44
45
  possible = re.sub(r"[^\w]", "_", possible) # Replace non-word chars
45
46
  possible = re.sub(r"[^\x00-\x7F]", "_", possible) # Replace non-ASCII chars
46
47
 
@@ -4,7 +4,6 @@
4
4
  """Waldiez flow model."""
5
5
 
6
6
  from functools import cached_property
7
- from typing import Optional
8
7
 
9
8
  from pydantic import Field, model_validator
10
9
  from typing_extensions import Annotated, Literal, Self
@@ -133,7 +132,7 @@ class WaldiezFlow(WaldiezBase):
133
132
  description="The date and time when the flow was last updated.",
134
133
  ),
135
134
  ]
136
- _ordered_flow: Optional[list[WaldiezAgentConnection]] = None
135
+ _ordered_flow: list[WaldiezAgentConnection] | None = None
137
136
  _single_agent_mode: bool = False
138
137
  _is_group_chat: bool = False
139
138
 
@@ -160,7 +159,7 @@ class WaldiezFlow(WaldiezBase):
160
159
  return self._is_group_chat
161
160
 
162
161
  @property
163
- def cache_seed(self) -> Optional[int]:
162
+ def cache_seed(self) -> int | None:
164
163
  """Check if the flow has caching disabled.
165
164
 
166
165
  Returns
@@ -351,6 +350,7 @@ class WaldiezFlow(WaldiezBase):
351
350
  ) -> list[WaldiezAgentConnection]:
352
351
  """Get the ordered flow."""
353
352
  if self._is_group_chat:
353
+ # noinspection PyTypeChecker
354
354
  return self._get_group_chat_flow()
355
355
  # in the chats, there is the 'order' field, we use this,
356
356
  # we only keep the ones with order >=0
@@ -408,7 +408,7 @@ class WaldiezFlow(WaldiezBase):
408
408
 
409
409
  Returns
410
410
  -------
411
- list[tuple[WaldiezChat, WaldiezAgent, WaldiezAgent]]
411
+ list[WaldiezAgentConnection]
412
412
  The ordered flow for group chat.
413
413
  """
414
414
  # in a group chat there is no "order", the group manager
@@ -427,8 +427,8 @@ class WaldiezFlow(WaldiezBase):
427
427
  # )
428
428
  # in the second case, the chat would be:
429
429
  # user.run(manager, ...)
430
- user_agent: Optional[WaldiezAgent] = None
431
- to_root_manager: Optional[WaldiezChat] = None
430
+ user_agent: WaldiezAgent | None = None
431
+ to_root_manager: WaldiezChat | None = None
432
432
  root_manager: WaldiezGroupManager = self.get_root_group_manager()
433
433
  for chat in self.data.chats:
434
434
  if chat.target == root_manager.id:
@@ -438,7 +438,9 @@ class WaldiezFlow(WaldiezBase):
438
438
  user_agent = source
439
439
  to_root_manager = chat
440
440
  break
441
- if not to_root_manager or not user_agent:
441
+ if not to_root_manager:
442
+ return []
443
+ if not user_agent:
442
444
  return []
443
445
  return [
444
446
  {
@@ -104,8 +104,8 @@ def get_llm_imports(model: "WaldiezModel") -> set[str]:
104
104
 
105
105
  Returns
106
106
  -------
107
- str
108
- The LLM import statements for the model.
107
+ set[str]
108
+ A set of import statements needed for the model's LLM.
109
109
 
110
110
  Raises
111
111
  ------
@@ -358,6 +358,7 @@ def do_cohere_llm(model: "WaldiezModel") -> tuple[str, str]:
358
358
  return arg, before
359
359
 
360
360
 
361
+ # noinspection DuplicatedCode
361
362
  def do_deepseek_llm(model: "WaldiezModel") -> tuple[str, str]:
362
363
  """Get the DeepSeek LLM argument and any content before it.
363
364
 
@@ -394,6 +395,7 @@ def do_google_llm(model: "WaldiezModel") -> tuple[str, str]:
394
395
  return arg, before
395
396
 
396
397
 
398
+ # noinspection DuplicatedCode
397
399
  def do_groq_llm(model: "WaldiezModel") -> tuple[str, str]:
398
400
  """Get the Groq LLM argument and any content before it.
399
401
 
@@ -2,14 +2,14 @@
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
  """Waldiez model extra requirements."""
4
4
 
5
- from typing import Iterator, Set
5
+ from typing import Set
6
6
 
7
7
  from .model import WaldiezModel
8
8
 
9
9
 
10
10
  def get_models_extra_requirements(
11
- models: Iterator[WaldiezModel], autogen_version: str
12
- ) -> Set[str]:
11
+ models: list[WaldiezModel], autogen_version: str
12
+ ) -> set[str]:
13
13
  """Get the models extra requirements.
14
14
 
15
15
  Parameters
@@ -272,6 +272,7 @@ class WaldiezModel(WaldiezBase):
272
272
  return get_llm_arg(self)
273
273
 
274
274
 
275
+ # noinspection PyTypeChecker
275
276
  def set_default_base_url(
276
277
  llm_config: dict[str, Any], api_type: WaldiezModelAPIType
277
278
  ) -> dict[str, Any]:
@@ -303,7 +304,7 @@ def set_default_base_url(
303
304
 
304
305
  def set_bedrock_aws_config(
305
306
  llm_config: dict[str, Any],
306
- aws_config: Optional[WaldiezModelAWS],
307
+ aws_config: WaldiezModelAWS | None,
307
308
  ) -> dict[str, Any]:
308
309
  """Set the AWS config for Bedrock.
309
310
 
@@ -311,7 +312,7 @@ def set_bedrock_aws_config(
311
312
  ----------
312
313
  llm_config : dict[str, Any]
313
314
  The llm config dictionary.
314
- aws_config : Optional[WaldiezModelAWS]
315
+ aws_config : WaldiezModelAWS | None
315
316
  The passed aws config if any.
316
317
 
317
318
  Returns
@@ -337,11 +338,11 @@ def set_bedrock_aws_config(
337
338
  value = getattr(aws_config, param, "") if aws_config else ""
338
339
 
339
340
  # If not found, try environment variable
340
- if not value: # pragma: no cover
341
+ if not value or value == "REPLACE_ME": # pragma: no cover
341
342
  value = os.environ.get(env_var, "")
342
343
 
343
344
  # Add to extra_args if value exists
344
- if value: # pragma: no branch
345
+ if value and value != "REPLACE_ME": # pragma: no branch
345
346
  extra_args[config_key] = value
346
347
 
347
348
  # Update llm_config with extra_args
@@ -2,14 +2,14 @@
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
  """Waldiez tool extra requirements."""
4
4
 
5
- from typing import Iterator, Set
5
+ from typing import Set
6
6
 
7
7
  from .predefined import get_predefined_tool_requirements
8
8
  from .tool import WaldiezTool
9
9
 
10
10
 
11
11
  def get_tools_extra_requirements(
12
- tools: Iterator[WaldiezTool],
12
+ tools: list[WaldiezTool],
13
13
  autogen_version: str,
14
14
  ) -> Set[str]:
15
15
  """Get the tools extra requirements.
@@ -106,10 +106,12 @@ class GoogleSearchToolImpl(PredefinedTool):
106
106
  if name not in kwargs:
107
107
  missing.append(name)
108
108
  elif not isinstance(kwargs[name], type_of):
109
+ # pylint: disable=broad-exception-caught
110
+ # noinspection PyBroadException
109
111
  try:
110
112
  kwargs[name] = type_of(kwargs[name])
111
113
  self._kwargs[name] = kwargs[name]
112
- except Exception: # pylint: disable=broad-except
114
+ except Exception:
113
115
  invalid.append(name)
114
116
  else:
115
117
  if name in self._kwargs:
@@ -136,25 +138,15 @@ class GoogleSearchToolImpl(PredefinedTool):
136
138
  str
137
139
  The content for the tool.
138
140
  """
139
- os.environ["GOOGLE_SEARCH_API_KEY"] = secrets.get(
140
- "GOOGLE_SEARCH_API_KEY", ""
141
- )
142
- google_search_engine_id = self.google_search_engine_id
143
- if not google_search_engine_id:
144
- google_search_engine_id = secrets.get("GOOGLE_SEARCH_ENGINE_ID", "")
145
141
  content = f'''
146
142
  def {self.name}(
147
143
  query: str,
148
- search_api_key: str,
149
- search_engine_id: str,
150
144
  num_results: int = 10,
151
145
  ) -> list[dict[str, Any]]:
152
146
  """Perform a Google search and return formatted results.
153
147
 
154
148
  Args:
155
149
  query: The search query string.
156
- search_api_key: The API key for the Google Search API.
157
- search_engine_id: The search engine ID for the Google Search API.
158
150
  num_results: The maximum number of results to return. Defaults to 10.
159
151
  Returns:
160
152
  A list of dictionaries of the search results.
@@ -162,9 +154,12 @@ def {self.name}(
162
154
  google_search_api_key = os.environ.get("GOOGLE_SEARCH_API_KEY", "")
163
155
  if not google_search_api_key:
164
156
  raise ValueError("GOOGLE_SEARCH_API_KEY is required for Google search tool.")
157
+ google_search_engine_id = os.environ.get("GOOGLE_SEARCH_ENGINE_ID", "")
158
+ if not google_search_engine_id:
159
+ raise ValueError("Google Search Engine ID is required for Google search tool.")
165
160
  {self.name}_tool = GoogleSearchTool(
166
161
  search_api_key=google_search_api_key,
167
- search_engine_id="{google_search_engine_id}",
162
+ search_engine_id=google_search_engine_id,
168
163
  )
169
164
  return {self.name}_tool(
170
165
  query=query,
@@ -4,7 +4,6 @@
4
4
  # flake8: noqa: E501
5
5
  """Predefined Perplexity AI search tool for Waldiez."""
6
6
 
7
- import os
8
7
  from typing import Any
9
8
 
10
9
  from ._config import PredefinedToolConfig
@@ -77,6 +76,7 @@ class PerplexitySearchToolImpl(PredefinedTool):
77
76
  missing_secrets.append("PERPLEXITY_API_KEY")
78
77
  return missing_secrets
79
78
 
79
+ # noinspection DuplicatedCode
80
80
  def validate_kwargs(self, kwargs: dict[str, Any]) -> list[str]:
81
81
  """Validate keyword arguments and return list of missing required ones.
82
82
 
@@ -93,11 +93,13 @@ class PerplexitySearchToolImpl(PredefinedTool):
93
93
  for key, value in self.kwargs.items():
94
94
  if key in kwargs: # pragma: no branch
95
95
  type_of = self.kwarg_types.get(key, str)
96
+ # pylint: disable=broad-exception-caught
97
+ # noinspection PyBroadException
96
98
  try:
97
99
  casted = type_of(value)
98
100
  if key in self.kwargs: # pragma: no branch
99
101
  self.kwargs[key] = casted
100
- except Exception: # pylint: disable=broad-except
102
+ except Exception:
101
103
  pass
102
104
  return []
103
105
 
@@ -117,21 +119,23 @@ class PerplexitySearchToolImpl(PredefinedTool):
117
119
  str
118
120
  Content retrieved by the tool.
119
121
  """
120
- os.environ["PERPLEXITY_API_KEY"] = secrets.get("PERPLEXITY_API_KEY", "")
122
+ model = self.kwargs["model"]
123
+ max_tokens = self.kwargs["max_tokens"]
124
+ search_domain_filter = self.kwargs["search_domain_filter"]
121
125
  content = f'''
122
126
  def {self.name}(
123
127
  query: str,
124
- model: str = "{self.kwargs["model"]}",
125
- max_tokens: int = {self.kwargs["max_tokens"]},
126
- search_domain_filter: Optional[list[str]] = {self.kwargs["search_domain_filter"]},
128
+ model: str = "{model}",
129
+ max_tokens: int = {max_tokens},
130
+ search_domain_filter: Optional[list[str]] = {search_domain_filter},
127
131
  ) -> "SearchResponse":
128
132
  """Perform a Perplexity AI search and return formatted results.
129
133
 
130
134
  Args:
131
135
  query: The search query string.
132
- model: The model to use for the search. Defaults to "{self.kwargs["model"]}".
133
- max_tokens: The maximum number of tokens to return. Defaults to {self.kwargs["max_tokens"]}.
134
- search_domain_filter: List of domain filters for the search. Defaults to {self.kwargs["search_domain_filter"]}.
136
+ model: The model to use for the search. Defaults to "{model}".
137
+ max_tokens: The maximum number of tokens to return. Defaults to {max_tokens}.
138
+ search_domain_filter: List of domain filters for the search. Defaults to {search_domain_filter}.
135
139
  Returns:
136
140
  A list of dictionaries of the search results.
137
141
  """
@@ -68,6 +68,7 @@ class SearxNGSearchToolImpl(PredefinedTool):
68
68
  """
69
69
  return [] # No secrets required for this tool.
70
70
 
71
+ # noinspection DuplicatedCode
71
72
  def validate_kwargs(self, kwargs: dict[str, Any]) -> list[str]:
72
73
  """Validate keyword arguments and return list of missing required ones.
73
74
 
@@ -84,11 +85,13 @@ class SearxNGSearchToolImpl(PredefinedTool):
84
85
  for key, value in self.kwargs.items():
85
86
  if key in kwargs: # pragma: no branch
86
87
  type_of = self.kwarg_types.get(key, str)
88
+ # pylint: disable=broad-exception-caught
89
+ # noinspection PyBroadException
87
90
  try:
88
91
  casted = type_of(value)
89
92
  if key in self.kwargs: # pragma: no branch
90
93
  self.kwargs[key] = casted
91
- except Exception: # pylint: disable=broad-except
94
+ except Exception:
92
95
  pass
93
96
  return []
94
97
 
@@ -4,7 +4,6 @@
4
4
  # flake8: noqa: E501
5
5
  """Predefined Tavily search tool for Waldiez."""
6
6
 
7
- import os
8
7
  from typing import Any
9
8
 
10
9
  from ._config import PredefinedToolConfig
@@ -98,13 +97,9 @@ class TavilySearchToolImpl(PredefinedTool):
98
97
  str
99
98
  The content for the tool.
100
99
  """
101
- os.environ["TAVILY_API_KEY"] = secrets.get(
102
- "TAVILY_API_KEY", os.environ.get("TAVILY_API_KEY", "")
103
- )
104
100
  content = f'''
105
101
  def {self.name}(
106
102
  query: str,
107
- tavily_api_key: str = os.environ.get("TAVILY_API_KEY", ""),
108
103
  search_depth: str = "basic",
109
104
  topic: str = "general",
110
105
  include_answer: str = "basic",
@@ -116,7 +111,6 @@ def {self.name}(
116
111
 
117
112
  Args:
118
113
  query: The search query string.
119
- tavily_api_key: The API key for Tavily (injected dependency).
120
114
  search_depth: The depth of the search ('basic' or 'advanced'). Defaults to "basic".
121
115
  include_answer: Whether to include an AI-generated answer ('basic' or 'advanced'). Defaults to "basic".
122
116
  include_raw_content: Whether to include raw content in the results. Defaults to False.
@@ -73,6 +73,7 @@ class WikipediaSearchToolImpl(PredefinedTool):
73
73
  """
74
74
  return []
75
75
 
76
+ # noinspection DuplicatedCode
76
77
  def validate_kwargs(self, kwargs: dict[str, Any]) -> list[str]:
77
78
  """Validate keyword arguments and return list of missing required ones.
78
79
 
@@ -89,14 +90,17 @@ class WikipediaSearchToolImpl(PredefinedTool):
89
90
  for key, value in self.kwargs.items():
90
91
  if key in kwargs:
91
92
  type_of = self.kwargs_types.get(key, str)
93
+ # pylint: disable=broad-exception-caught
94
+ # noinspection PyBroadException
92
95
  try:
93
96
  casted = type_of(value)
94
97
  if key in self.kwargs:
95
98
  self.kwargs[key] = casted
96
- except Exception: # pylint: disable=broad-except
99
+ except Exception:
97
100
  pass
98
101
  return []
99
102
 
103
+ # pylint: disable=unused-argument
100
104
  def get_content(
101
105
  self,
102
106
  secrets: dict[str, str],
@@ -4,7 +4,6 @@
4
4
  # flake8: noqa: E501
5
5
  """Predefined YouTube search tool for Waldiez."""
6
6
 
7
- import os
8
7
  from typing import Any
9
8
 
10
9
  from ._config import PredefinedToolConfig
@@ -101,11 +100,9 @@ class YouTubeSearchToolImpl(PredefinedTool):
101
100
  str
102
101
  The content for the tool.
103
102
  """
104
- os.environ["YOUTUBE_API_KEY"] = secrets.get("YOUTUBE_API_KEY", "")
105
103
  content = f'''
106
104
  def {self.name}(
107
105
  query: str,
108
- youtube_api_key: str = os.environ.get("YOUTUBE_API_KEY", ""),
109
106
  max_results: int = 5,
110
107
  include_video_details: bool = True,
111
108
  ) -> list[dict[str, Any]]:
@@ -113,7 +110,6 @@ def {self.name}(
113
110
 
114
111
  Args:
115
112
  query: The search query string.
116
- youtube_api_key: The API key for the YouTube Data API.
117
113
  max_results: The maximum number of results to return. Defaults to 5.
118
114
  include_video_details: Whether to include detailed video information. Defaults to True.
119
115
 
@@ -5,7 +5,7 @@
5
5
  import json
6
6
  import re
7
7
  from pathlib import Path
8
- from typing import Any, Union
8
+ from typing import Any
9
9
 
10
10
  from pydantic import Field, model_validator
11
11
  from typing_extensions import Annotated, Literal, Self
@@ -44,9 +44,9 @@ class WaldiezTool(WaldiezBase):
44
44
  The tags of the tool.
45
45
  requirements : list[str]
46
46
  The requirements of the tool.
47
- created_at : str
47
+ created_at : str, optional
48
48
  The date and time when the tool was created.
49
- updated_at : str
49
+ updated_at : str, optional
50
50
  The date and time when the tool was last updated.
51
51
  data : WaldiezToolData
52
52
  The data of the tool. See `WaldiezToolData`.
@@ -81,7 +81,7 @@ class WaldiezTool(WaldiezBase):
81
81
  description="The tags of the tool.",
82
82
  default_factory=list,
83
83
  ),
84
- ]
84
+ ] = []
85
85
  requirements: Annotated[
86
86
  list[str],
87
87
  Field(
@@ -89,7 +89,7 @@ class WaldiezTool(WaldiezBase):
89
89
  description="The requirements of the tool.",
90
90
  default_factory=list,
91
91
  ),
92
- ]
92
+ ] = []
93
93
  data: Annotated[
94
94
  WaldiezToolData,
95
95
  Field(..., title="Data", description="The data of the tool."),
@@ -112,12 +112,12 @@ class WaldiezTool(WaldiezBase):
112
112
  ]
113
113
 
114
114
  @staticmethod
115
- def load(data_or_path: Union[str, Path, dict[str, Any]]) -> "WaldiezTool":
115
+ def load(data_or_path: str | Path | dict[str, Any]) -> "WaldiezTool":
116
116
  """Load a tool from a read-only file.
117
117
 
118
118
  Parameters
119
119
  ----------
120
- data_or_path : Union[str, Path, dict[str, Any]]
120
+ data_or_path : str | Path | dict[str, Any]
121
121
  The path to the read-only file or the loaded data.
122
122
 
123
123
  Returns
@@ -4,8 +4,8 @@
4
4
 
5
5
  from typing import Any
6
6
 
7
- from pydantic import Field
8
- from typing_extensions import Annotated
7
+ from pydantic import Field, SerializationInfo, model_serializer, model_validator
8
+ from typing_extensions import Annotated, Self
9
9
 
10
10
  from ..common import WaldiezBase
11
11
  from .tool_type import WaldiezToolType
@@ -61,3 +61,40 @@ class WaldiezToolData(WaldiezBase):
61
61
  ),
62
62
  ),
63
63
  ] = {}
64
+
65
+ _raw_content: str = ""
66
+
67
+ @model_validator(mode="after")
68
+ def validate_tool_data(self) -> Self:
69
+ """Validate the tool data.
70
+
71
+ Returns
72
+ -------
73
+ Self
74
+ The validated tool data.
75
+ """
76
+ self._raw_content = self.content
77
+
78
+ return self
79
+
80
+ @model_serializer(mode="plain", when_used="always")
81
+ def serialize_tool_data(self, info: SerializationInfo) -> dict[str, Any]:
82
+ """Serialize the tool data.
83
+
84
+ Parameters
85
+ ----------
86
+ info : SerializationInfo
87
+ The serialization information.
88
+
89
+ Returns
90
+ -------
91
+ dict[str, Any]
92
+ The serialized tool data.
93
+ """
94
+ tool_type_key = "toolType" if info.by_alias else "tool_type"
95
+ return {
96
+ tool_type_key: self.tool_type,
97
+ "content": self._raw_content,
98
+ "secrets": self.secrets,
99
+ "kwargs": self.kwargs,
100
+ }
waldiez/models/waldiez.py CHANGED
@@ -11,7 +11,7 @@ definitions and their optional additional tools to be used.
11
11
  import json
12
12
  from dataclasses import dataclass
13
13
  from pathlib import Path
14
- from typing import Any, Iterator, Optional
14
+ from typing import Any, Iterator
15
15
 
16
16
  from .agents import (
17
17
  WaldiezAgent,
@@ -43,11 +43,11 @@ class Waldiez:
43
43
  def from_dict(
44
44
  cls,
45
45
  data: dict[str, Any],
46
- flow_id: Optional[str] = None,
47
- name: Optional[str] = None,
48
- description: Optional[str] = None,
49
- tags: Optional[list[str]] = None,
50
- requirements: Optional[list[str]] = None,
46
+ flow_id: str | None = None,
47
+ name: str | None = None,
48
+ description: str | None = None,
49
+ tags: list[str] | None = None,
50
+ requirements: list[str] | None = None,
51
51
  ) -> "Waldiez":
52
52
  """Create a Waldiez from dict.
53
53
 
@@ -55,15 +55,15 @@ class Waldiez:
55
55
  ----------
56
56
  data : dict[str, Any]
57
57
  The data.
58
- flow_id : Optional[str], optional
58
+ flow_id : str | None, optional
59
59
  The flow id, by default None (retrieved from data or generated).
60
- name : Optional[str], optional
60
+ name: str | None, optional
61
61
  The name, by default None (retrieved from data).
62
- description : Optional[str], optional
62
+ description : str | None, optional
63
63
  The description, by default None (retrieved from data).
64
- tags : Optional[list[str]], optional
64
+ tags: list[str] | None, optional
65
65
  The tags, by default None (retrieved from data).
66
- requirements : Optional[list[str]], optional
66
+ requirements: list[str] | None, optional
67
67
  The requirements, by default None (retrieved from data).
68
68
 
69
69
  Returns
@@ -86,10 +86,10 @@ class Waldiez:
86
86
  def load(
87
87
  cls,
88
88
  waldiez_file: str | Path,
89
- name: Optional[str] = None,
90
- description: Optional[str] = None,
91
- tags: Optional[list[str]] = None,
92
- requirements: Optional[list[str]] = None,
89
+ name: str | None = None,
90
+ description: str | None = None,
91
+ tags: list[str] | None = None,
92
+ requirements: list[str] | None = None,
93
93
  ) -> "Waldiez":
94
94
  """Load a Waldiez from a file.
95
95
 
@@ -97,14 +97,14 @@ class Waldiez:
97
97
  ----------
98
98
  waldiez_file : Union[str, Path]
99
99
  The Waldiez file.
100
- name : Optional[str], optional
101
- The name, by default None.
102
- description : Optional[str], optional
103
- The description, by default None.
104
- tags : Optional[list[str]], optional
105
- The tags, by default None.
106
- requirements : Optional[list[str]], optional
107
- The requirements, by default None.
100
+ name: str | None, optional
101
+ The name, by default None (retrieved from data).
102
+ description : str | None, optional
103
+ The description, by default None (retrieved from data).
104
+ tags: list[str] | None, optional
105
+ The tags, by default None (retrieved from data).
106
+ requirements: list[str] | None, optional
107
+ The requirements, by default None (retrieved from data).
108
108
 
109
109
  Returns
110
110
  -------
@@ -133,7 +133,7 @@ class Waldiez:
133
133
  )
134
134
 
135
135
  def model_dump_json(
136
- self, by_alias: bool = True, indent: Optional[int] = None
136
+ self, by_alias: bool = True, indent: int | None = None
137
137
  ) -> str:
138
138
  """Get the model dump json.
139
139
 
@@ -143,7 +143,7 @@ class Waldiez:
143
143
  ----------
144
144
  by_alias : bool, optional
145
145
  Use alias (toCamel), by default True.
146
- indent : Optional[int], optional
146
+ indent : int | None, optional
147
147
  The indent, by default None.
148
148
 
149
149
  Returns
@@ -250,7 +250,7 @@ class Waldiez:
250
250
  return self.flow.is_async
251
251
 
252
252
  @property
253
- def cache_seed(self) -> Optional[int]:
253
+ def cache_seed(self) -> int | None:
254
254
  """Get the cache seed."""
255
255
  return self.flow.cache_seed
256
256
 
@@ -275,7 +275,7 @@ class Waldiez:
275
275
  requirements = set(requirements_list)
276
276
  requirements.add(f"ag2[openai]=={autogen_version}")
277
277
  if self.has_rag_agents: # pragma: no branch
278
- rag_extras = get_retrievechat_extra_requirements(self.agents)
278
+ rag_extras = get_retrievechat_extra_requirements(list(self.agents))
279
279
  requirements.update(rag_extras)
280
280
  if self.has_multimodal_agents: # pragma: no branch
281
281
  requirements.add(f"ag2[lmm]=={autogen_version}")
@@ -291,13 +291,13 @@ class Waldiez:
291
291
  )
292
292
  requirements.update(
293
293
  get_models_extra_requirements(
294
- self.models,
294
+ list(self.models),
295
295
  autogen_version=autogen_version,
296
296
  )
297
297
  )
298
298
  requirements.update(
299
299
  get_tools_extra_requirements(
300
- self.tools,
300
+ list(self.tools),
301
301
  autogen_version=autogen_version,
302
302
  )
303
303
  )