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,199 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ # pylint: disable=unused-argument,no-self-use
4
+ """Command handler for step-by-step execution."""
5
+
6
+ from typing import TYPE_CHECKING, Any, Union
7
+
8
+ if TYPE_CHECKING:
9
+ from autogen.events.base_event import BaseEvent # type: ignore
10
+ from autogen.messages.base_message import BaseMessage # type: ignore
11
+
12
+ # noinspection PyUnusedImports
13
+ from .step_by_step_runner import WaldiezStepByStepRunner
14
+
15
+
16
+ # pylint: disable=too-few-public-methods
17
+ class EventProcessor:
18
+ """Processes events for the step-by-step runner."""
19
+
20
+ def __init__(self, runner: "WaldiezStepByStepRunner"):
21
+ self.runner = runner
22
+
23
+ def process_event(
24
+ self, event: Union["BaseEvent", "BaseMessage"]
25
+ ) -> dict[str, Any]:
26
+ """Shared logic for both sync and async event processing.
27
+
28
+ Parameters
29
+ ----------
30
+ event : BaseEvent | BaseMessage
31
+ The event to process.
32
+
33
+ Returns
34
+ -------
35
+ dict[str, Any]
36
+ The result of processing the event.
37
+ """
38
+ self.runner.event_plus_one()
39
+ self.runner.current_event = event
40
+
41
+ if self.runner.is_stop_requested():
42
+ return {"action": "stop", "reason": "stop_requested"}
43
+
44
+ event_info = self._create_event_info(event)
45
+ self._update_participant_info(event_info)
46
+ self._manage_event_history(event_info)
47
+ self._check_for_input_request(event_info)
48
+
49
+ should_break = self.runner.should_break_on_event(
50
+ event, self.runner.step_mode
51
+ )
52
+
53
+ return {
54
+ "action": "continue",
55
+ "should_break": should_break,
56
+ "event_info": event_info,
57
+ }
58
+
59
+ def _create_event_info(
60
+ self, event: Union["BaseEvent", "BaseMessage"]
61
+ ) -> dict[str, Any]:
62
+ """Create event info dictionary from event object.
63
+
64
+ Parameters
65
+ ----------
66
+ event : BaseEvent | BaseMessage
67
+ The event to convert to info dict.
68
+
69
+ Returns
70
+ -------
71
+ dict[str, Any]
72
+ Event information dictionary.
73
+ """
74
+ event_info = event.model_dump(
75
+ mode="json", exclude_none=True, fallback=str
76
+ )
77
+ event_info["count"] = self.runner.event_count
78
+ event_info["sender"] = getattr(event, "sender", self.runner.last_sender)
79
+ event_info["recipient"] = getattr(
80
+ event, "recipient", self.runner.last_recipient
81
+ )
82
+ return event_info
83
+
84
+ def _update_participant_info(self, event_info: dict[str, Any]) -> None:
85
+ """Update sender and recipient information in event_info.
86
+
87
+ Parameters
88
+ ----------
89
+ event_info : dict[str, Any]
90
+ Event information dictionary to update.
91
+ """
92
+ if not event_info["sender"] or not event_info["recipient"]:
93
+ self._extract_participants_from_content(event_info)
94
+
95
+ self._handle_group_chat_speaker(event_info)
96
+ self._extract_participants_from_direct_content(event_info)
97
+
98
+ # Update last known participants
99
+ self.runner.last_sender = event_info["sender"]
100
+ self.runner.last_recipient = event_info["recipient"]
101
+
102
+ def _extract_participants_from_content(
103
+ self, event_info: dict[str, Any]
104
+ ) -> None:
105
+ """Extract sender/recipient from nested content structure.
106
+
107
+ Parameters
108
+ ----------
109
+ event_info : dict[str, Any]
110
+ Event information dictionary to update.
111
+ """
112
+ content = event_info.get("content", {})
113
+ if (
114
+ isinstance(content, dict)
115
+ and "chat_info" in content
116
+ and isinstance(content["chat_info"], dict)
117
+ ):
118
+ content = content.get("chat_info", {}) # pyright: ignore
119
+
120
+ if not event_info["sender"] and "sender" in content:
121
+ event_info["sender"] = content["sender"]
122
+ if not event_info["recipient"] and "recipient" in content:
123
+ event_info["recipient"] = content["recipient"]
124
+
125
+ def _handle_group_chat_speaker(self, event_info: dict[str, Any]) -> None:
126
+ """Handle speaker information for group chat events.
127
+
128
+ Parameters
129
+ ----------
130
+ event_info : dict[str, Any]
131
+ Event information dictionary to update.
132
+ """
133
+ if (
134
+ event_info.get("type") == "group_chat_run_chat"
135
+ and "content" in event_info
136
+ and isinstance(event_info["content"], dict)
137
+ ):
138
+ content = event_info.get("content", {})
139
+ speaker = content.get("speaker")
140
+ if isinstance(speaker, str) and speaker:
141
+ event_info["sender"] = speaker
142
+
143
+ def _extract_participants_from_direct_content(
144
+ self, event_info: dict[str, Any]
145
+ ) -> None:
146
+ """Extract sender/recipient directly from content dictionary.
147
+
148
+ Parameters
149
+ ----------
150
+ event_info : dict[str, Any]
151
+ Event information dictionary to update.
152
+ """
153
+ if "content" in event_info and isinstance(event_info["content"], dict):
154
+ content = event_info.get("content", {})
155
+
156
+ sender = content.get("sender", "")
157
+ if isinstance(sender, str) and sender:
158
+ event_info["sender"] = sender
159
+
160
+ recipient = content.get("recipient", "")
161
+ if isinstance(recipient, str) and recipient:
162
+ event_info["recipient"] = recipient
163
+
164
+ def _manage_event_history(self, event_info: dict[str, Any]) -> None:
165
+ """Add event to history and manage history size limits.
166
+
167
+ Parameters
168
+ ----------
169
+ event_info : dict[str, Any]
170
+ Event information to add to history.
171
+ """
172
+ self.runner.add_to_history(event_info)
173
+ self._trim_history_if_needed()
174
+
175
+ def _trim_history_if_needed(self) -> None:
176
+ """Remove oldest events from history if over size limit."""
177
+ current_history = self.runner.event_history
178
+ if len(current_history) > self.runner.max_event_history:
179
+ excess = len(current_history) - self.runner.max_event_history
180
+ for _ in range(excess):
181
+ self.runner.pop_event()
182
+
183
+ def _check_for_input_request(self, event_info: dict[str, Any]) -> None:
184
+ """Swap participant names if we have an input request."""
185
+ if (
186
+ event_info["type"] in ("input_request", "debug_input_request")
187
+ and "sender" in event_info
188
+ and "recipient" in event_info
189
+ ):
190
+ # swap them,
191
+ # before:
192
+ # "recipient" is the user (the one received the input request),
193
+ # make her the "sender" (the one typing...)
194
+ sender = event_info["sender"]
195
+ recipient = event_info["recipient"]
196
+ event_info["sender"] = recipient
197
+ event_info["recipient"] = sender
198
+ self.runner.last_sender = recipient
199
+ self.runner.last_recipient = sender