waldiez 0.5.9__py3-none-any.whl → 0.6.0__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 (109) hide show
  1. waldiez/_version.py +1 -1
  2. waldiez/cli.py +113 -24
  3. waldiez/exporting/agent/exporter.py +9 -6
  4. waldiez/exporting/agent/extras/captain_agent_extras.py +44 -7
  5. waldiez/exporting/agent/extras/group_manager_agent_extas.py +6 -1
  6. waldiez/exporting/agent/extras/handoffs/after_work.py +1 -0
  7. waldiez/exporting/agent/extras/handoffs/available.py +1 -0
  8. waldiez/exporting/agent/extras/handoffs/condition.py +3 -1
  9. waldiez/exporting/agent/extras/handoffs/handoff.py +1 -0
  10. waldiez/exporting/agent/extras/handoffs/target.py +1 -0
  11. waldiez/exporting/agent/termination.py +1 -0
  12. waldiez/exporting/chats/utils/common.py +25 -23
  13. waldiez/exporting/core/__init__.py +0 -2
  14. waldiez/exporting/core/constants.py +3 -1
  15. waldiez/exporting/core/context.py +13 -13
  16. waldiez/exporting/core/extras/serializer.py +12 -10
  17. waldiez/exporting/core/protocols.py +0 -141
  18. waldiez/exporting/core/result.py +5 -5
  19. waldiez/exporting/core/types.py +1 -0
  20. waldiez/exporting/core/utils/llm_config.py +2 -2
  21. waldiez/exporting/flow/execution_generator.py +1 -0
  22. waldiez/exporting/flow/merger.py +2 -2
  23. waldiez/exporting/flow/orchestrator.py +1 -0
  24. waldiez/exporting/flow/utils/common.py +3 -3
  25. waldiez/exporting/flow/utils/importing.py +1 -0
  26. waldiez/exporting/flow/utils/logging.py +7 -80
  27. waldiez/exporting/tools/exporter.py +5 -0
  28. waldiez/exporting/tools/factory.py +4 -0
  29. waldiez/exporting/tools/processor.py +5 -1
  30. waldiez/io/__init__.py +3 -1
  31. waldiez/io/_ws.py +15 -5
  32. waldiez/io/models/content/image.py +1 -0
  33. waldiez/io/models/user_input.py +4 -4
  34. waldiez/io/models/user_response.py +1 -0
  35. waldiez/io/mqtt.py +1 -1
  36. waldiez/io/structured.py +98 -45
  37. waldiez/io/utils.py +17 -11
  38. waldiez/io/ws.py +10 -12
  39. waldiez/logger.py +180 -63
  40. waldiez/models/agents/agent/agent.py +2 -1
  41. waldiez/models/agents/agent/update_system_message.py +0 -2
  42. waldiez/models/agents/doc_agent/doc_agent.py +8 -1
  43. waldiez/models/chat/chat.py +1 -0
  44. waldiez/models/chat/chat_data.py +0 -2
  45. waldiez/models/common/base.py +2 -0
  46. waldiez/models/common/dict_utils.py +169 -40
  47. waldiez/models/common/handoff.py +2 -0
  48. waldiez/models/common/method_utils.py +2 -0
  49. waldiez/models/flow/flow.py +6 -6
  50. waldiez/models/flow/info.py +5 -1
  51. waldiez/models/model/_llm.py +31 -14
  52. waldiez/models/model/model.py +4 -1
  53. waldiez/models/model/model_data.py +18 -5
  54. waldiez/models/tool/predefined/_config.py +5 -1
  55. waldiez/models/tool/predefined/_duckduckgo.py +4 -0
  56. waldiez/models/tool/predefined/_email.py +477 -0
  57. waldiez/models/tool/predefined/_google.py +4 -1
  58. waldiez/models/tool/predefined/_perplexity.py +4 -1
  59. waldiez/models/tool/predefined/_searxng.py +4 -1
  60. waldiez/models/tool/predefined/_tavily.py +4 -1
  61. waldiez/models/tool/predefined/_wikipedia.py +5 -2
  62. waldiez/models/tool/predefined/_youtube.py +4 -1
  63. waldiez/models/tool/predefined/protocol.py +3 -0
  64. waldiez/models/tool/tool.py +22 -4
  65. waldiez/models/waldiez.py +12 -0
  66. waldiez/runner.py +37 -54
  67. waldiez/running/__init__.py +6 -0
  68. waldiez/running/base_runner.py +381 -363
  69. waldiez/running/environment.py +1 -0
  70. waldiez/running/exceptions.py +9 -0
  71. waldiez/running/post_run.py +10 -4
  72. waldiez/running/pre_run.py +199 -66
  73. waldiez/running/protocol.py +21 -101
  74. waldiez/running/run_results.py +1 -1
  75. waldiez/running/standard_runner.py +83 -276
  76. waldiez/running/step_by_step/__init__.py +46 -0
  77. waldiez/running/step_by_step/breakpoints_mixin.py +512 -0
  78. waldiez/running/step_by_step/command_handler.py +151 -0
  79. waldiez/running/step_by_step/events_processor.py +199 -0
  80. waldiez/running/step_by_step/step_by_step_models.py +541 -0
  81. waldiez/running/step_by_step/step_by_step_runner.py +750 -0
  82. waldiez/running/subprocess_runner/__base__.py +279 -0
  83. waldiez/running/subprocess_runner/__init__.py +16 -0
  84. waldiez/running/subprocess_runner/_async_runner.py +362 -0
  85. waldiez/running/subprocess_runner/_sync_runner.py +456 -0
  86. waldiez/running/subprocess_runner/runner.py +570 -0
  87. waldiez/running/timeline_processor.py +1 -1
  88. waldiez/running/utils.py +492 -3
  89. waldiez/utils/version.py +2 -6
  90. waldiez/ws/__init__.py +71 -0
  91. waldiez/ws/__main__.py +15 -0
  92. waldiez/ws/_file_handler.py +199 -0
  93. waldiez/ws/_mock.py +74 -0
  94. waldiez/ws/cli.py +235 -0
  95. waldiez/ws/client_manager.py +851 -0
  96. waldiez/ws/errors.py +416 -0
  97. waldiez/ws/models.py +988 -0
  98. waldiez/ws/reloader.py +363 -0
  99. waldiez/ws/server.py +508 -0
  100. waldiez/ws/session_manager.py +393 -0
  101. waldiez/ws/session_stats.py +83 -0
  102. waldiez/ws/utils.py +410 -0
  103. {waldiez-0.5.9.dist-info → waldiez-0.6.0.dist-info}/METADATA +105 -96
  104. {waldiez-0.5.9.dist-info → waldiez-0.6.0.dist-info}/RECORD +108 -83
  105. waldiez/running/patch_io_stream.py +0 -210
  106. {waldiez-0.5.9.dist-info → waldiez-0.6.0.dist-info}/WHEEL +0 -0
  107. {waldiez-0.5.9.dist-info → waldiez-0.6.0.dist-info}/entry_points.txt +0 -0
  108. {waldiez-0.5.9.dist-info → waldiez-0.6.0.dist-info}/licenses/LICENSE +0 -0
  109. {waldiez-0.5.9.dist-info → waldiez-0.6.0.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,477 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ # pylint: disable=line-too-long
4
+ # flake8: noqa: E501
5
+ """Predefined send email tool."""
6
+
7
+ from copy import deepcopy
8
+ from typing import Any
9
+
10
+ from ._config import PredefinedToolConfig
11
+ from .protocol import PredefinedTool
12
+
13
+
14
+ # noinspection PyBroadException,TryExceptPass
15
+ class SendEmailToolImpl(PredefinedTool):
16
+ """Predefined tool for sending emails."""
17
+
18
+ required_secrets: list[str] = [
19
+ "SMTP_HOST",
20
+ "SMTP_PORT",
21
+ "SMTP_USERNAME",
22
+ "SMTP_PASSWORD",
23
+ ]
24
+ required_kwargs: dict[str, type] = {}
25
+
26
+ DEFAULT_KWARGS: dict[str, Any] = {
27
+ "is_async": False, # controls whether the exported tool function is async or sync
28
+ "subject": "",
29
+ "body_text": "",
30
+ "body_html": "",
31
+ "to": [],
32
+ "attachments": [],
33
+ "cc": [],
34
+ "bcc": [],
35
+ "reply_to": [],
36
+ "sender": "",
37
+ "use_ssl": False,
38
+ "use_starttls": True,
39
+ "timeout": 30.0,
40
+ }
41
+
42
+ kwarg_types: dict[str, type] = {
43
+ "is_async": bool,
44
+ "subject": str,
45
+ "body_text": str,
46
+ "body_html": str,
47
+ "to": list,
48
+ "attachments": list,
49
+ "cc": list,
50
+ "bcc": list,
51
+ "reply_to": list,
52
+ "sender": str,
53
+ "use_ssl": bool,
54
+ "use_starttls": bool,
55
+ "timeout": float,
56
+ }
57
+
58
+ def __init__(self) -> None:
59
+ self._kwargs: dict[str, Any] = deepcopy(self.DEFAULT_KWARGS)
60
+
61
+ @property
62
+ def name(self) -> str:
63
+ return "send_email"
64
+
65
+ @property
66
+ def description(self) -> str:
67
+ return "A tool for sending emails with support for attachments, HTML/text content, and various SMTP configurations."
68
+
69
+ @property
70
+ def kwargs(self) -> dict[str, Any]:
71
+ """
72
+ Get the keyword arguments for the tool.
73
+
74
+ Returns
75
+ -------
76
+ dict[str, Any]
77
+ The keyword arguments for the tool.
78
+ """
79
+ return dict(self._kwargs)
80
+
81
+ @property
82
+ def tags(self) -> list[str]:
83
+ return ["email", "communication", "smtp"]
84
+
85
+ @property
86
+ def requirements(self) -> list[str]:
87
+ return []
88
+
89
+ @property
90
+ def tool_imports(self) -> list[str]:
91
+ return [
92
+ "import asyncio",
93
+ "import smtplib",
94
+ "import ssl",
95
+ "from email.message import EmailMessage",
96
+ "from email.utils import formatdate, make_msgid",
97
+ "from pathlib import Path",
98
+ ]
99
+
100
+ def validate_secrets(self, secrets: dict[str, str]) -> list[str]:
101
+ """
102
+ Validate the provided secrets against the tool's requirements.
103
+
104
+ Parameters
105
+ ----------
106
+ secrets: dict[str, str]
107
+ The secrets to validate.
108
+
109
+ Returns
110
+ -------
111
+ list[str]
112
+ A list of validation error messages, if any.
113
+ """
114
+ problems: list[str] = []
115
+ for key in self.required_secrets:
116
+ val = secrets.get(key)
117
+ if val is None or str(val).strip() == "":
118
+ problems.append(key)
119
+ # pylint: disable=broad-exception-caught
120
+ try:
121
+ port = int(secrets.get("SMTP_PORT", ""))
122
+ if not 1 <= port <= 65535:
123
+ problems.append("SMTP_PORT (invalid port range)")
124
+ except Exception:
125
+ problems.append("SMTP_PORT (not a valid integer)")
126
+ return problems
127
+
128
+ def validate_kwargs(self, kwargs: dict[str, Any]) -> list[str]:
129
+ """
130
+ Validate the provided keyword arguments against the tool's requirements.
131
+
132
+ Parameters
133
+ ----------
134
+ kwargs: dict[str, Any]
135
+ The keyword arguments to validate.
136
+
137
+ Returns
138
+ -------
139
+ list[str]
140
+ A list of validation error messages, if any.
141
+ """
142
+ updated = dict(self._kwargs)
143
+ # noinspection DuplicatedCode
144
+ for key, value in kwargs.items():
145
+ if key in self.kwarg_types:
146
+ typ = self.kwarg_types[key]
147
+ # pylint: disable=broad-exception-caught
148
+ try:
149
+ if typ is list and isinstance(value, str):
150
+ updated[key] = [
151
+ s.strip() for s in value.split(",") if s.strip()
152
+ ]
153
+ else:
154
+ updated[key] = typ(value)
155
+ except Exception:
156
+ pass
157
+ self._kwargs = updated
158
+ return []
159
+
160
+ def _get_effective_kwargs(
161
+ self,
162
+ runtime_kwargs: dict[str, Any] | None = None,
163
+ ) -> dict[str, Any]:
164
+ """Get effective keyword arguments."""
165
+ effective = dict(self._kwargs)
166
+ # noinspection DuplicatedCode
167
+ if runtime_kwargs:
168
+ # cast only known keys, same rules as validate_kwargs
169
+ for k, v in runtime_kwargs.items():
170
+ if k in self.kwarg_types:
171
+ typ = self.kwarg_types[k]
172
+ # pylint: disable=broad-exception-caught
173
+ try:
174
+ if typ is list and isinstance(v, str):
175
+ effective[k] = [
176
+ s.strip() for s in v.split(",") if s.strip()
177
+ ]
178
+ else:
179
+ effective[k] = typ(v)
180
+ except Exception:
181
+ pass
182
+ return effective
183
+
184
+ def get_content(
185
+ self,
186
+ secrets: dict[str, str],
187
+ runtime_kwargs: dict[str, Any] | None = None,
188
+ ) -> str:
189
+ """
190
+ Generate the email content based on the provided secrets and tool kwargs.
191
+
192
+ Parameters
193
+ ----------
194
+ secrets: dict[str, str]
195
+ The secrets required for SMTP authentication and configuration.
196
+ runtime_kwargs: dict[str, Any] | None, optional
197
+ Runtime keyword arguments to customize the content generation.
198
+
199
+ Returns
200
+ -------
201
+ str
202
+ The generated email content.
203
+ """
204
+ smtp_host = secrets.get("SMTP_HOST", "smtp.gmail.com")
205
+ try:
206
+ smtp_port = int(secrets.get("SMTP_PORT", "587"))
207
+ except (ValueError, TypeError):
208
+ smtp_port = 587
209
+ smtp_user = secrets.get("SMTP_USERNAME", "")
210
+ smtp_pass = secrets.get("SMTP_PASSWORD", "")
211
+
212
+ effective_kwargs = self._get_effective_kwargs(runtime_kwargs)
213
+
214
+ is_async = effective_kwargs.get("is_async", False)
215
+ use_ssl = effective_kwargs.get("use_ssl", False)
216
+ use_starttls = effective_kwargs.get("use_starttls", True)
217
+ timeout = effective_kwargs.get("timeout", 30.0)
218
+
219
+ base = f"""
220
+ def _collect_rcpts(to, cc, bcc):
221
+ rcpts = []
222
+ for part in (to, cc, bcc):
223
+ if not part:
224
+ continue
225
+ if isinstance(part, str):
226
+ rcpts.extend([s.strip() for s in part.split(",") if s.strip()])
227
+ else:
228
+ rcpts.extend(part)
229
+ seen, out = set(), []
230
+ for r in rcpts:
231
+ if r not in seen:
232
+ seen.add(r)
233
+ out.append(r)
234
+ return out
235
+
236
+
237
+ def _split_emails(value) -> list[str]:
238
+ if not value:
239
+ return []
240
+ if isinstance(value, str):
241
+ return [s.strip() for s in value.split(",") if s.strip()]
242
+ return list(value)
243
+
244
+ def _build_message(
245
+ subject: str,
246
+ sender: str,
247
+ recipients: str | list[str],
248
+ body_text: str | None = None,
249
+ body_html: str | None = None,
250
+ attachments: list | None = None,
251
+ cc: list[str] | None = None,
252
+ reply_to: list[str] | None = None,
253
+ ) -> EmailMessage:
254
+ recipients = _split_emails(recipients)
255
+ cc = _split_emails(cc)
256
+ reply_to = _split_emails(reply_to)
257
+ attachments = attachments or []
258
+
259
+ if not (body_text or body_html):
260
+ raise ValueError("Provide at least one of body_text or body_html.")
261
+
262
+ msg = EmailMessage()
263
+ msg["Subject"] = subject
264
+ msg["From"] = sender
265
+ msg["To"] = ", ".join(recipients)
266
+ msg["Date"] = formatdate(localtime=True)
267
+ msg["Message-ID"] = make_msgid()
268
+ if cc:
269
+ msg["Cc"] = ", ".join(cc)
270
+ if reply_to:
271
+ msg["Reply-To"] = ", ".join(reply_to)
272
+
273
+ if body_html and body_text:
274
+ msg.set_content(body_text)
275
+ msg.add_alternative(body_html, subtype="html")
276
+ elif body_html:
277
+ msg.add_alternative(body_html, subtype="html")
278
+ else:
279
+ msg.set_content(body_text or "")
280
+
281
+ for item in attachments:
282
+ if isinstance(item, Path):
283
+ data = item.read_bytes()
284
+ filename = item.name
285
+ mime = "application/octet-stream"
286
+ else:
287
+ filename, data, mime = item
288
+ maintype, _, subtype = mime.partition("/")
289
+ msg.add_attachment(data, maintype=maintype, subtype=subtype, filename=filename)
290
+
291
+ return msg
292
+
293
+
294
+ def _send_email_sync(
295
+ subject: str,
296
+ to: str | list[str],
297
+ body_text: str | None = None,
298
+ body_html: str | None = None,
299
+ attachments: list | None = None,
300
+ cc: list[str] | None = None,
301
+ bcc: list[str] | None = None,
302
+ reply_to: list[str] | None = None,
303
+ sender: str | None = None,
304
+ use_ssl: bool = {use_ssl},
305
+ use_starttls: bool = {use_starttls},
306
+ timeout: float = {timeout},
307
+ ) -> dict:
308
+ smtp_host = "{smtp_host}"
309
+ smtp_port = {smtp_port}
310
+ username = "{smtp_user}"
311
+ password = "{smtp_pass}"
312
+ sender = sender or username
313
+
314
+ context = ssl.create_default_context()
315
+ msg = _build_message(
316
+ subject=subject,
317
+ sender=sender,
318
+ recipients=to,
319
+ body_text=body_text,
320
+ body_html=body_html,
321
+ attachments=attachments,
322
+ cc=cc,
323
+ reply_to=reply_to,
324
+ )
325
+ rcpts = _collect_rcpts(to, cc, bcc)
326
+ if not rcpts:
327
+ raise ValueError("No recipients provided (to/cc/bcc are all empty).")
328
+ if use_ssl:
329
+ with smtplib.SMTP_SSL(smtp_host, smtp_port, context=context, timeout=timeout) as server:
330
+ if username and password:
331
+ server.login(username, password)
332
+ return server.send_message(msg, to_addrs=rcpts)
333
+ else:
334
+ with smtplib.SMTP(smtp_host, smtp_port, timeout=timeout) as server:
335
+ server.ehlo()
336
+ if use_starttls:
337
+ server.starttls(context=context)
338
+ server.ehlo()
339
+ if username and password:
340
+ server.login(username, password)
341
+ return server.send_message(msg, to_addrs=rcpts)
342
+
343
+
344
+ async def _send_email_async(
345
+ subject: str,
346
+ to: str | list[str],
347
+ body_text: str | None = None,
348
+ body_html: str | None = None,
349
+ attachments: list | None = None,
350
+ cc: list[str] | None = None,
351
+ bcc: list[str] | None = None,
352
+ reply_to: list[str] | None = None,
353
+ sender: str | None = None,
354
+ use_ssl: bool = {use_ssl},
355
+ use_starttls: bool = {use_starttls},
356
+ timeout: float = {timeout},
357
+ ) -> dict:
358
+ return await asyncio.to_thread(
359
+ _send_email_sync,
360
+ subject=subject,
361
+ to=to,
362
+ body_text=body_text,
363
+ body_html=body_html,
364
+ attachments=attachments,
365
+ cc=cc,
366
+ bcc=bcc,
367
+ reply_to=reply_to,
368
+ sender=sender,
369
+ use_ssl=use_ssl,
370
+ use_starttls=use_starttls,
371
+ timeout=timeout,
372
+ )
373
+ """
374
+
375
+ # exported callable is chosen by config: async or sync
376
+ if is_async:
377
+ exported = f'''
378
+ async def {self.name}(
379
+ subject: str,
380
+ to: str | list[str],
381
+ body_text: str | None = None,
382
+ body_html: str | None = None,
383
+ attachments: list | None = None,
384
+ cc: list[str] | None = None,
385
+ bcc: list[str] | None = None,
386
+ reply_to: list[str] | None = None,
387
+ sender: str | None = None,
388
+ ) -> dict:
389
+ """Send email asynchronously.
390
+
391
+ At least one recipient must be specified.
392
+ At least one of `body_text` or `body_html` must be provided.
393
+
394
+ Args:
395
+ subject: The email subject.
396
+ to: The recipient email address(es).
397
+ body_text: The plain text body of the email.
398
+ body_html: The HTML body of the email.
399
+ attachments: Any file attachments to include.
400
+ cc: The CC email address(es).
401
+ bcc: The BCC email address(es).
402
+ reply_to: The reply-to email address(es).
403
+ sender: The sender email address.
404
+
405
+ Returns:
406
+ A dictionary containing the result of the email sending operation.
407
+ """
408
+ return await _send_email_async(
409
+ subject=subject,
410
+ to=to,
411
+ body_text=body_text,
412
+ body_html=body_html,
413
+ attachments=attachments,
414
+ cc=cc,
415
+ bcc=bcc,
416
+ reply_to=reply_to,
417
+ sender=sender,
418
+ )
419
+ '''
420
+ else:
421
+ exported = f'''
422
+ def {self.name}(
423
+ subject: str,
424
+ to: str | list[str],
425
+ body_text: str | None = None,
426
+ body_html: str | None = None,
427
+ attachments: list | None = None,
428
+ cc: list[str] | None = None,
429
+ bcc: list[str] | None = None,
430
+ reply_to: list[str] | None = None,
431
+ sender: str | None = None,
432
+ ) -> dict:
433
+ """Send email synchronously.
434
+
435
+ At least one recipient must be specified.
436
+ At least one of `body_text` or `body_html` must be provided.
437
+
438
+ Args:
439
+ subject: The email subject.
440
+ to: The recipient email address(es).
441
+ body_text: The plain text body of the email.
442
+ body_html: The HTML body of the email.
443
+ attachments: Any file attachments to include.
444
+ cc: The CC email address(es).
445
+ bcc: The BCC email address(es).
446
+ reply_to: The reply-to email address(es).
447
+ sender: The sender email address.
448
+
449
+ Returns:
450
+ A dictionary containing the result of the email sending operation.
451
+ """
452
+ return _send_email_sync(
453
+ subject=subject,
454
+ to=to,
455
+ body_text=body_text,
456
+ body_html=body_html,
457
+ attachments=attachments,
458
+ cc=cc,
459
+ bcc=bcc,
460
+ reply_to=reply_to,
461
+ sender=sender,
462
+ )
463
+ '''
464
+
465
+ return base + exported
466
+
467
+
468
+ SendEmailTool = SendEmailToolImpl()
469
+ SendEmailConfig = PredefinedToolConfig(
470
+ name=SendEmailTool.name,
471
+ description=SendEmailTool.description,
472
+ tags=SendEmailTool.tags,
473
+ requirements=SendEmailTool.requirements,
474
+ required_secrets=SendEmailTool.required_secrets,
475
+ required_kwargs=SendEmailTool.required_kwargs,
476
+ implementation=SendEmailTool,
477
+ )
@@ -39,7 +39,7 @@ class GoogleSearchToolImpl(PredefinedTool):
39
39
  @property
40
40
  def requirements(self) -> list[str]:
41
41
  """Python requirements for the tool."""
42
- return ["ag2[google-search,gemini,openai]"]
42
+ return ["ag2[google-search,gemini]"]
43
43
 
44
44
  @property
45
45
  def tags(self) -> list[str]:
@@ -124,6 +124,7 @@ class GoogleSearchToolImpl(PredefinedTool):
124
124
  def get_content(
125
125
  self,
126
126
  secrets: dict[str, str],
127
+ runtime_kwargs: dict[str, Any] | None = None,
127
128
  ) -> str:
128
129
  """Get content for the tool.
129
130
 
@@ -131,6 +132,8 @@ class GoogleSearchToolImpl(PredefinedTool):
131
132
  ----------
132
133
  secrets : dict[str, str]
133
134
  Dictionary of secrets/environment variables.
135
+ runtime_kwargs : dict[str, Any] | None, optional
136
+ Runtime keyword arguments to customize the content generation.
134
137
 
135
138
  Returns
136
139
  -------
@@ -94,7 +94,7 @@ class PerplexitySearchToolImpl(PredefinedTool):
94
94
  if key in kwargs: # pragma: no branch
95
95
  type_of = self.kwarg_types.get(key, str)
96
96
  # pylint: disable=broad-exception-caught
97
- # noinspection PyBroadException
97
+ # noinspection PyBroadException,TryExceptPass
98
98
  try:
99
99
  casted = type_of(value)
100
100
  if key in self.kwargs: # pragma: no branch
@@ -106,6 +106,7 @@ class PerplexitySearchToolImpl(PredefinedTool):
106
106
  def get_content(
107
107
  self,
108
108
  secrets: dict[str, str],
109
+ runtime_kwargs: dict[str, Any] | None = None,
109
110
  ) -> str:
110
111
  """Get content for the tool.
111
112
 
@@ -113,6 +114,8 @@ class PerplexitySearchToolImpl(PredefinedTool):
113
114
  ----------
114
115
  secrets : dict[str, str]
115
116
  Dictionary of secrets/environment variables.
117
+ runtime_kwargs : dict[str, Any] | None, optional
118
+ Runtime keyword arguments to customize the content generation.
116
119
 
117
120
  Returns
118
121
  -------
@@ -86,7 +86,7 @@ class SearxNGSearchToolImpl(PredefinedTool):
86
86
  if key in kwargs: # pragma: no branch
87
87
  type_of = self.kwarg_types.get(key, str)
88
88
  # pylint: disable=broad-exception-caught
89
- # noinspection PyBroadException
89
+ # noinspection PyBroadException,TryExceptPass
90
90
  try:
91
91
  casted = type_of(value)
92
92
  if key in self.kwargs: # pragma: no branch
@@ -98,6 +98,7 @@ class SearxNGSearchToolImpl(PredefinedTool):
98
98
  def get_content(
99
99
  self,
100
100
  secrets: dict[str, str],
101
+ runtime_kwargs: dict[str, Any] | None = None,
101
102
  ) -> str:
102
103
  """Get content for the tool.
103
104
 
@@ -105,6 +106,8 @@ class SearxNGSearchToolImpl(PredefinedTool):
105
106
  ----------
106
107
  secrets : dict[str, str]
107
108
  Dictionary of secrets/environment variables.
109
+ runtime_kwargs : dict[str, Any] | None, optional
110
+ Runtime keyword arguments to customize the content generation.
108
111
 
109
112
  Returns
110
113
  -------
@@ -34,7 +34,7 @@ class TavilySearchToolImpl(PredefinedTool):
34
34
  @property
35
35
  def requirements(self) -> list[str]:
36
36
  """Python requirements for the tool."""
37
- return ["ag2[tavily, openai]"]
37
+ return ["ag2[tavily]"]
38
38
 
39
39
  @property
40
40
  def tags(self) -> list[str]:
@@ -84,6 +84,7 @@ class TavilySearchToolImpl(PredefinedTool):
84
84
  def get_content(
85
85
  self,
86
86
  secrets: dict[str, str],
87
+ runtime_kwargs: dict[str, Any] | None = None,
87
88
  ) -> str:
88
89
  """Get content for the tool.
89
90
 
@@ -91,6 +92,8 @@ class TavilySearchToolImpl(PredefinedTool):
91
92
  ----------
92
93
  secrets : dict[str, str]
93
94
  Dictionary of secrets/environment variables.
95
+ runtime_kwargs : dict[str, Any] | None, optional
96
+ Runtime keyword arguments to customize the content generation.
94
97
 
95
98
  Returns
96
99
  -------
@@ -43,7 +43,7 @@ class WikipediaSearchToolImpl(PredefinedTool):
43
43
  @property
44
44
  def requirements(self) -> list[str]:
45
45
  """Python requirements for the tool."""
46
- return ["ag2[wikipedia, openai]"]
46
+ return ["ag2[wikipedia]"]
47
47
 
48
48
  @property
49
49
  def tags(self) -> list[str]:
@@ -91,7 +91,7 @@ class WikipediaSearchToolImpl(PredefinedTool):
91
91
  if key in kwargs:
92
92
  type_of = self.kwargs_types.get(key, str)
93
93
  # pylint: disable=broad-exception-caught
94
- # noinspection PyBroadException
94
+ # noinspection PyBroadException,TryExceptPass
95
95
  try:
96
96
  casted = type_of(value)
97
97
  if key in self.kwargs:
@@ -104,6 +104,7 @@ class WikipediaSearchToolImpl(PredefinedTool):
104
104
  def get_content(
105
105
  self,
106
106
  secrets: dict[str, str],
107
+ runtime_kwargs: dict[str, Any] | None = None,
107
108
  ) -> str:
108
109
  """Get the content of the tool.
109
110
 
@@ -111,6 +112,8 @@ class WikipediaSearchToolImpl(PredefinedTool):
111
112
  ----------
112
113
  secrets : dict[str, str]
113
114
  Dictionary of secrets/environment variables.
115
+ runtime_kwargs : dict[str, Any] | None, optional
116
+ Runtime keyword arguments to customize the content generation.
114
117
 
115
118
  Returns
116
119
  -------
@@ -36,7 +36,7 @@ class YouTubeSearchToolImpl(PredefinedTool):
36
36
  @property
37
37
  def requirements(self) -> list[str]:
38
38
  """Python requirements for the tool."""
39
- return ["ag2[google-search, openai]"]
39
+ return ["ag2[google-search]"]
40
40
 
41
41
  @property
42
42
  def tags(self) -> list[str]:
@@ -87,6 +87,7 @@ class YouTubeSearchToolImpl(PredefinedTool):
87
87
  def get_content(
88
88
  self,
89
89
  secrets: dict[str, str],
90
+ runtime_kwargs: dict[str, Any] | None = None,
90
91
  ) -> str:
91
92
  """Get content for the tool.
92
93
 
@@ -94,6 +95,8 @@ class YouTubeSearchToolImpl(PredefinedTool):
94
95
  ----------
95
96
  secrets : dict[str, str]
96
97
  Dictionary of secrets/environment variables.
98
+ runtime_kwargs : dict[str, Any] | None, optional
99
+ Runtime keyword arguments to customize the content generation.
97
100
 
98
101
  Returns
99
102
  -------
@@ -37,6 +37,7 @@ class PredefinedTool(Protocol):
37
37
  def get_content(
38
38
  self,
39
39
  secrets: dict[str, str],
40
+ runtime_kwargs: dict[str, Any] | None = None,
40
41
  ) -> str:
41
42
  """Get the content of the tool.
42
43
 
@@ -44,6 +45,8 @@ class PredefinedTool(Protocol):
44
45
  ----------
45
46
  secrets : dict[str, str]
46
47
  Dictionary of secrets/environment variables.
48
+ runtime_kwargs : dict[str, Any] | None, optional
49
+ Runtime keyword arguments to customize the content generation.
47
50
 
48
51
  Returns
49
52
  -------