waldiez 0.4.6__py3-none-any.whl → 0.4.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.
- waldiez/__init__.py +5 -5
- waldiez/_version.py +1 -1
- waldiez/cli.py +112 -73
- waldiez/exporter.py +61 -19
- waldiez/exporting/__init__.py +25 -6
- waldiez/exporting/agent/__init__.py +7 -3
- waldiez/exporting/agent/code_execution.py +114 -0
- waldiez/exporting/agent/exporter.py +354 -0
- waldiez/exporting/agent/extras/__init__.py +15 -0
- waldiez/exporting/agent/extras/captain_agent_extras.py +315 -0
- waldiez/exporting/agent/extras/group/target.py +178 -0
- waldiez/exporting/agent/extras/group_manager_agent_extas.py +500 -0
- waldiez/exporting/agent/extras/group_member_extras.py +181 -0
- waldiez/exporting/agent/extras/handoffs/__init__.py +19 -0
- waldiez/exporting/agent/extras/handoffs/after_work.py +78 -0
- waldiez/exporting/agent/extras/handoffs/available.py +74 -0
- waldiez/exporting/agent/extras/handoffs/condition.py +158 -0
- waldiez/exporting/agent/extras/handoffs/handoff.py +171 -0
- waldiez/exporting/agent/extras/handoffs/target.py +189 -0
- waldiez/exporting/agent/extras/rag/__init__.py +10 -0
- waldiez/exporting/agent/{utils/rag_user/chroma_utils.py → extras/rag/chroma_extras.py} +16 -15
- waldiez/exporting/agent/{utils/rag_user/mongo_utils.py → extras/rag/mongo_extras.py} +10 -10
- waldiez/exporting/agent/{utils/rag_user/pgvector_utils.py → extras/rag/pgvector_extras.py} +13 -13
- waldiez/exporting/agent/{utils/rag_user/qdrant_utils.py → extras/rag/qdrant_extras.py} +13 -13
- waldiez/exporting/agent/{utils/rag_user/vector_db.py → extras/rag/vector_db_extras.py} +59 -46
- waldiez/exporting/agent/extras/rag_user_proxy_agent_extras.py +245 -0
- waldiez/exporting/agent/extras/reasoning_agent_extras.py +88 -0
- waldiez/exporting/agent/factory.py +95 -0
- waldiez/exporting/agent/processor.py +150 -0
- waldiez/exporting/agent/system_message.py +36 -0
- waldiez/exporting/agent/termination.py +50 -0
- waldiez/exporting/chats/__init__.py +7 -3
- waldiez/exporting/chats/exporter.py +97 -0
- waldiez/exporting/chats/factory.py +65 -0
- waldiez/exporting/chats/processor.py +226 -0
- waldiez/exporting/chats/utils/__init__.py +6 -5
- waldiez/exporting/chats/utils/common.py +11 -45
- waldiez/exporting/chats/utils/group.py +55 -0
- waldiez/exporting/chats/utils/nested.py +37 -52
- waldiez/exporting/chats/utils/sequential.py +72 -61
- waldiez/exporting/chats/utils/{single_chat.py → single.py} +48 -50
- waldiez/exporting/core/__init__.py +196 -0
- waldiez/exporting/core/constants.py +17 -0
- waldiez/exporting/core/content.py +69 -0
- waldiez/exporting/core/context.py +244 -0
- waldiez/exporting/core/enums.py +89 -0
- waldiez/exporting/core/errors.py +19 -0
- waldiez/exporting/core/exporter.py +390 -0
- waldiez/exporting/core/exporters.py +67 -0
- waldiez/exporting/core/extras/__init__.py +39 -0
- waldiez/exporting/core/extras/agent_extras/__init__.py +27 -0
- waldiez/exporting/core/extras/agent_extras/captain_extras.py +57 -0
- waldiez/exporting/core/extras/agent_extras/group_manager_extras.py +102 -0
- waldiez/exporting/core/extras/agent_extras/rag_user_extras.py +53 -0
- waldiez/exporting/core/extras/agent_extras/reasoning_extras.py +68 -0
- waldiez/exporting/core/extras/agent_extras/standard_extras.py +263 -0
- waldiez/exporting/core/extras/base.py +241 -0
- waldiez/exporting/core/extras/chat_extras.py +118 -0
- waldiez/exporting/core/extras/flow_extras.py +70 -0
- waldiez/exporting/core/extras/model_extras.py +73 -0
- waldiez/exporting/core/extras/path_resolver.py +93 -0
- waldiez/exporting/core/extras/serializer.py +138 -0
- waldiez/exporting/core/extras/tool_extras.py +82 -0
- waldiez/exporting/core/protocols.py +259 -0
- waldiez/exporting/core/result.py +705 -0
- waldiez/exporting/core/types.py +329 -0
- waldiez/exporting/core/utils/__init__.py +11 -0
- waldiez/exporting/core/utils/comment.py +33 -0
- waldiez/exporting/core/utils/llm_config.py +117 -0
- waldiez/exporting/core/validation.py +96 -0
- waldiez/exporting/flow/__init__.py +6 -2
- waldiez/exporting/flow/execution_generator.py +193 -0
- waldiez/exporting/flow/exporter.py +107 -0
- waldiez/exporting/flow/factory.py +94 -0
- waldiez/exporting/flow/file_generator.py +214 -0
- waldiez/exporting/flow/merger.py +387 -0
- waldiez/exporting/flow/orchestrator.py +411 -0
- waldiez/exporting/flow/utils/__init__.py +9 -36
- waldiez/exporting/flow/utils/common.py +206 -0
- waldiez/exporting/flow/utils/importing.py +373 -0
- waldiez/exporting/flow/utils/linting.py +200 -0
- waldiez/exporting/flow/utils/{logging_utils.py → logging.py} +23 -9
- waldiez/exporting/models/__init__.py +3 -1
- waldiez/exporting/models/exporter.py +233 -0
- waldiez/exporting/models/factory.py +66 -0
- waldiez/exporting/models/processor.py +139 -0
- waldiez/exporting/tools/__init__.py +11 -0
- waldiez/exporting/tools/exporter.py +207 -0
- waldiez/exporting/tools/factory.py +57 -0
- waldiez/exporting/tools/processor.py +248 -0
- waldiez/exporting/tools/registration.py +133 -0
- waldiez/io/__init__.py +128 -0
- waldiez/io/_ws.py +199 -0
- waldiez/io/models/__init__.py +60 -0
- waldiez/io/models/base.py +66 -0
- waldiez/io/models/constants.py +78 -0
- waldiez/io/models/content/__init__.py +23 -0
- waldiez/io/models/content/audio.py +43 -0
- waldiez/io/models/content/base.py +45 -0
- waldiez/io/models/content/file.py +43 -0
- waldiez/io/models/content/image.py +96 -0
- waldiez/io/models/content/text.py +37 -0
- waldiez/io/models/content/video.py +43 -0
- waldiez/io/models/user_input.py +269 -0
- waldiez/io/models/user_response.py +215 -0
- waldiez/io/mqtt.py +681 -0
- waldiez/io/redis.py +782 -0
- waldiez/io/structured.py +419 -0
- waldiez/io/utils.py +184 -0
- waldiez/io/ws.py +298 -0
- waldiez/logger.py +481 -0
- waldiez/models/__init__.py +108 -51
- waldiez/models/agents/__init__.py +34 -70
- waldiez/models/agents/agent/__init__.py +10 -4
- waldiez/models/agents/agent/agent.py +466 -65
- waldiez/models/agents/agent/agent_data.py +119 -47
- waldiez/models/agents/agent/agent_type.py +13 -2
- waldiez/models/agents/agent/code_execution.py +12 -12
- waldiez/models/agents/agent/human_input_mode.py +8 -0
- waldiez/models/agents/agent/{linked_skill.py → linked_tool.py} +7 -7
- waldiez/models/agents/agent/nested_chat.py +35 -7
- waldiez/models/agents/agent/termination_message.py +30 -22
- waldiez/models/agents/{swarm_agent → agent}/update_system_message.py +22 -22
- waldiez/models/agents/agents.py +58 -63
- waldiez/models/agents/assistant/assistant.py +4 -4
- waldiez/models/agents/assistant/assistant_data.py +13 -1
- waldiez/models/agents/{captain_agent → captain}/captain_agent.py +5 -5
- waldiez/models/agents/{captain_agent → captain}/captain_agent_data.py +5 -5
- waldiez/models/agents/extra_requirements.py +11 -16
- waldiez/models/agents/group_manager/group_manager.py +103 -13
- waldiez/models/agents/group_manager/group_manager_data.py +36 -14
- waldiez/models/agents/group_manager/speakers.py +77 -24
- waldiez/models/agents/{rag_user → rag_user_proxy}/__init__.py +16 -16
- waldiez/models/agents/rag_user_proxy/rag_user_proxy.py +64 -0
- waldiez/models/agents/{rag_user/rag_user_data.py → rag_user_proxy/rag_user_proxy_data.py} +6 -5
- waldiez/models/agents/{rag_user → rag_user_proxy}/retrieve_config.py +182 -114
- waldiez/models/agents/{rag_user → rag_user_proxy}/vector_db_config.py +13 -13
- waldiez/models/agents/reasoning/reasoning_agent.py +6 -6
- waldiez/models/agents/reasoning/reasoning_agent_data.py +110 -63
- waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +38 -10
- waldiez/models/agents/user_proxy/user_proxy.py +11 -7
- waldiez/models/agents/user_proxy/user_proxy_data.py +2 -2
- waldiez/models/chat/__init__.py +2 -1
- waldiez/models/chat/chat.py +166 -87
- waldiez/models/chat/chat_data.py +99 -136
- waldiez/models/chat/chat_message.py +33 -23
- waldiez/models/chat/chat_nested.py +31 -30
- waldiez/models/chat/chat_summary.py +10 -8
- waldiez/models/common/__init__.py +52 -2
- waldiez/models/common/ag2_version.py +1 -1
- waldiez/models/common/base.py +38 -7
- waldiez/models/common/dict_utils.py +42 -17
- waldiez/models/common/handoff.py +459 -0
- waldiez/models/common/id_generator.py +19 -0
- waldiez/models/common/method_utils.py +130 -68
- waldiez/{exporting/base/utils → models/common}/naming.py +38 -61
- waldiez/models/common/waldiez_version.py +37 -0
- waldiez/models/flow/__init__.py +9 -2
- waldiez/models/flow/connection.py +18 -0
- waldiez/models/flow/flow.py +311 -215
- waldiez/models/flow/flow_data.py +207 -40
- waldiez/models/flow/info.py +85 -0
- waldiez/models/flow/naming.py +131 -0
- waldiez/models/model/__init__.py +7 -1
- waldiez/models/model/extra_requirements.py +3 -12
- waldiez/models/model/model.py +76 -21
- waldiez/models/model/model_data.py +108 -20
- waldiez/models/tool/__init__.py +16 -0
- waldiez/models/tool/extra_requirements.py +36 -0
- waldiez/models/{skill/skill.py → tool/tool.py} +88 -88
- waldiez/models/tool/tool_data.py +51 -0
- waldiez/models/tool/tool_type.py +8 -0
- waldiez/models/waldiez.py +97 -80
- waldiez/runner.py +114 -49
- waldiez/running/__init__.py +1 -1
- waldiez/running/environment.py +49 -68
- waldiez/running/gen_seq_diagram.py +16 -14
- waldiez/running/running.py +53 -34
- waldiez/utils/__init__.py +0 -4
- waldiez/utils/cli_extras/jupyter.py +5 -3
- waldiez/utils/cli_extras/runner.py +6 -4
- waldiez/utils/cli_extras/studio.py +6 -4
- waldiez/utils/conflict_checker.py +15 -9
- waldiez/utils/flaml_warnings.py +5 -5
- {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/METADATA +235 -91
- waldiez-0.4.8.dist-info/RECORD +200 -0
- waldiez/exporting/agent/agent_exporter.py +0 -297
- waldiez/exporting/agent/utils/__init__.py +0 -23
- waldiez/exporting/agent/utils/captain_agent.py +0 -263
- waldiez/exporting/agent/utils/code_execution.py +0 -65
- waldiez/exporting/agent/utils/group_manager.py +0 -220
- waldiez/exporting/agent/utils/rag_user/__init__.py +0 -7
- waldiez/exporting/agent/utils/rag_user/rag_user.py +0 -209
- waldiez/exporting/agent/utils/reasoning.py +0 -36
- waldiez/exporting/agent/utils/swarm_agent.py +0 -469
- waldiez/exporting/agent/utils/teachability.py +0 -41
- waldiez/exporting/agent/utils/termination_message.py +0 -44
- waldiez/exporting/base/__init__.py +0 -25
- waldiez/exporting/base/agent_position.py +0 -75
- waldiez/exporting/base/base_exporter.py +0 -118
- waldiez/exporting/base/export_position.py +0 -48
- waldiez/exporting/base/import_position.py +0 -23
- waldiez/exporting/base/mixin.py +0 -137
- waldiez/exporting/base/utils/__init__.py +0 -18
- waldiez/exporting/base/utils/comments.py +0 -96
- waldiez/exporting/base/utils/path_check.py +0 -68
- waldiez/exporting/base/utils/to_string.py +0 -84
- waldiez/exporting/chats/chats_exporter.py +0 -240
- waldiez/exporting/chats/utils/swarm.py +0 -210
- waldiez/exporting/flow/flow_exporter.py +0 -528
- waldiez/exporting/flow/utils/agent_utils.py +0 -204
- waldiez/exporting/flow/utils/chat_utils.py +0 -71
- waldiez/exporting/flow/utils/def_main.py +0 -77
- waldiez/exporting/flow/utils/flow_content.py +0 -202
- waldiez/exporting/flow/utils/flow_names.py +0 -116
- waldiez/exporting/flow/utils/importing_utils.py +0 -227
- waldiez/exporting/models/models_exporter.py +0 -199
- waldiez/exporting/models/utils.py +0 -174
- waldiez/exporting/skills/__init__.py +0 -9
- waldiez/exporting/skills/skills_exporter.py +0 -176
- waldiez/exporting/skills/utils.py +0 -369
- waldiez/models/agents/agent/teachability.py +0 -70
- waldiez/models/agents/rag_user/rag_user.py +0 -60
- waldiez/models/agents/swarm_agent/__init__.py +0 -50
- waldiez/models/agents/swarm_agent/after_work.py +0 -179
- waldiez/models/agents/swarm_agent/on_condition.py +0 -105
- waldiez/models/agents/swarm_agent/on_condition_available.py +0 -142
- waldiez/models/agents/swarm_agent/on_condition_target.py +0 -40
- waldiez/models/agents/swarm_agent/swarm_agent.py +0 -107
- waldiez/models/agents/swarm_agent/swarm_agent_data.py +0 -124
- waldiez/models/flow/utils.py +0 -232
- waldiez/models/skill/__init__.py +0 -16
- waldiez/models/skill/extra_requirements.py +0 -36
- waldiez/models/skill/skill_data.py +0 -53
- waldiez/models/skill/skill_type.py +0 -8
- waldiez/utils/pysqlite3_checker.py +0 -308
- waldiez/utils/rdps_checker.py +0 -122
- waldiez-0.4.6.dist-info/RECORD +0 -149
- /waldiez/models/agents/{captain_agent → captain}/__init__.py +0 -0
- /waldiez/models/agents/{captain_agent → captain}/captain_agent_lib_entry.py +0 -0
- {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/WHEEL +0 -0
- {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/entry_points.txt +0 -0
- {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/licenses/LICENSE +0 -0
- {waldiez-0.4.6.dist-info → waldiez-0.4.8.dist-info}/licenses/NOTICE.md +0 -0
waldiez/io/_ws.py
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
# flake8: noqa: E501
|
|
4
|
+
# pylint: disable=line-too-long
|
|
5
|
+
"""WebSocket IOStream implementation for AsyncIO."""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
from typing import Any, Protocol
|
|
9
|
+
|
|
10
|
+
HAS_WS_LIB = False
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from starlette.websockets import WebSocket # type: ignore[unused-ignore, unused-import, import-not-found, import-untyped] # noqa
|
|
14
|
+
|
|
15
|
+
HAS_WS_LIB = True # pyright: ignore
|
|
16
|
+
except ImportError:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
import websockets # type: ignore[unused-ignore, unused-import, import-not-found, import-untyped] # noqa
|
|
21
|
+
|
|
22
|
+
HAS_WS_LIB = True # pyright: ignore
|
|
23
|
+
except ImportError: # pragma: no cover
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class WebSocketConnection(Protocol):
|
|
28
|
+
"""Protocol for WebSocket connections."""
|
|
29
|
+
|
|
30
|
+
async def send_message(self, message: str) -> None:
|
|
31
|
+
"""Send a message over the WebSocket connection.
|
|
32
|
+
|
|
33
|
+
Parameters
|
|
34
|
+
----------
|
|
35
|
+
message : str
|
|
36
|
+
The message to send.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
async def receive_message(
|
|
40
|
+
self,
|
|
41
|
+
timeout: float = 120,
|
|
42
|
+
) -> str: # pyright: ignore
|
|
43
|
+
"""Receive a message from the WebSocket connection.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
timeout : float, optional
|
|
48
|
+
The timeout for receiving the message. Defaults to 120 seconds.
|
|
49
|
+
If the timeout is reached, an empty string is returned.
|
|
50
|
+
If an error occurs, an empty string is returned.
|
|
51
|
+
|
|
52
|
+
Returns
|
|
53
|
+
-------
|
|
54
|
+
str
|
|
55
|
+
The received message.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class WebSocketsAdapter:
|
|
60
|
+
"""Adapter for websockets library connections."""
|
|
61
|
+
|
|
62
|
+
def __init__(self, websocket: "websockets.ServerConnection"):
|
|
63
|
+
"""Initialize the adapter.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
websocket : ServerConnection
|
|
68
|
+
The websockets library connection.
|
|
69
|
+
"""
|
|
70
|
+
self.websocket = websocket
|
|
71
|
+
|
|
72
|
+
async def send_message(self, message: str) -> None:
|
|
73
|
+
"""Send a message using websockets library.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
message : str
|
|
78
|
+
The message to send.
|
|
79
|
+
"""
|
|
80
|
+
await self.websocket.send(message)
|
|
81
|
+
|
|
82
|
+
async def receive_message(self, timeout: float = 120) -> str:
|
|
83
|
+
"""Receive a message using websockets library.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
timeout : float, optional
|
|
88
|
+
The timeout for receiving the message. Defaults to 120 seconds.
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
str
|
|
93
|
+
The received message, decoded as a string.
|
|
94
|
+
"""
|
|
95
|
+
# pylint: disable=too-many-try-statements
|
|
96
|
+
try:
|
|
97
|
+
response = await asyncio.wait_for(
|
|
98
|
+
self.websocket.recv(), timeout=timeout
|
|
99
|
+
)
|
|
100
|
+
if isinstance(response, bytes):
|
|
101
|
+
return response.decode("utf-8")
|
|
102
|
+
return response if isinstance(response, str) else str(response)
|
|
103
|
+
except asyncio.TimeoutError:
|
|
104
|
+
return ""
|
|
105
|
+
except BaseException: # pylint: disable=broad-exception-caught
|
|
106
|
+
# Handle other exceptions that may occur during receive
|
|
107
|
+
return ""
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class StarletteAdapter:
|
|
111
|
+
"""Adapter for Starlette/FastAPI WebSocket connections."""
|
|
112
|
+
|
|
113
|
+
def __init__(self, websocket: "WebSocket"):
|
|
114
|
+
"""Initialize the adapter.
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
websocket : WebSocket
|
|
119
|
+
The Starlette/FastAPI WebSocket connection.
|
|
120
|
+
"""
|
|
121
|
+
self.websocket = websocket
|
|
122
|
+
|
|
123
|
+
async def send_message(self, message: str) -> None:
|
|
124
|
+
"""Send a message using Starlette WebSocket.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
message : str
|
|
129
|
+
The message to send.
|
|
130
|
+
"""
|
|
131
|
+
await self.websocket.send_text(message)
|
|
132
|
+
|
|
133
|
+
async def receive_message(self, timeout: float = 120) -> str:
|
|
134
|
+
"""Receive a message using Starlette WebSocket.
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
timeout : float, optional
|
|
139
|
+
The timeout for receiving the message. Defaults to 120 seconds.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
str
|
|
144
|
+
The received message, decoded as a string.
|
|
145
|
+
"""
|
|
146
|
+
try:
|
|
147
|
+
return await asyncio.wait_for(
|
|
148
|
+
self.websocket.receive_text(), timeout=timeout
|
|
149
|
+
)
|
|
150
|
+
except asyncio.TimeoutError:
|
|
151
|
+
return ""
|
|
152
|
+
except BaseException: # pylint: disable=broad-exception-caught
|
|
153
|
+
# Handle other exceptions that may occur during receive
|
|
154
|
+
return ""
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def create_websocket_adapter(websocket: Any) -> WebSocketConnection:
|
|
158
|
+
"""Create an appropriate adapter for the given WebSocket connection.
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
websocket : Any
|
|
163
|
+
The WebSocket connection (websockets or Starlette).
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
WebSocketConnection
|
|
168
|
+
An adapter that implements the WebSocketConnection protocol.
|
|
169
|
+
|
|
170
|
+
Raises
|
|
171
|
+
------
|
|
172
|
+
ValueError
|
|
173
|
+
If the WebSocket type is not supported.
|
|
174
|
+
"""
|
|
175
|
+
# Check for Starlette/FastAPI WebSocket
|
|
176
|
+
if hasattr(websocket, "send_text") and hasattr(websocket, "receive_text"):
|
|
177
|
+
return StarletteAdapter(websocket)
|
|
178
|
+
|
|
179
|
+
# Check for websockets library
|
|
180
|
+
if hasattr(websocket, "send") and hasattr(websocket, "recv"):
|
|
181
|
+
return WebSocketsAdapter(websocket)
|
|
182
|
+
|
|
183
|
+
raise ValueError(
|
|
184
|
+
"Unsupported WebSocket type. "
|
|
185
|
+
"Must be either websockets.ServerConnection "
|
|
186
|
+
"or starlette.websockets.WebSocket. "
|
|
187
|
+
f"Received: {type(websocket)}"
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def is_websocket_available() -> bool:
|
|
192
|
+
"""Check if any WebSocket library is available.
|
|
193
|
+
|
|
194
|
+
Returns
|
|
195
|
+
-------
|
|
196
|
+
bool
|
|
197
|
+
True if websockets or starlette is available, False otherwise.
|
|
198
|
+
"""
|
|
199
|
+
return HAS_WS_LIB
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
|
|
4
|
+
"""Models package for structured I/O."""
|
|
5
|
+
|
|
6
|
+
# Base models
|
|
7
|
+
from .base import PrintMessage, StructuredBase, UserInputRequest
|
|
8
|
+
|
|
9
|
+
# Constants and mappings
|
|
10
|
+
from .constants import (
|
|
11
|
+
CONTENT_MAPPING,
|
|
12
|
+
ContentMappingEntry,
|
|
13
|
+
ContentTypeKey,
|
|
14
|
+
MediaContent,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# Content models
|
|
18
|
+
from .content import (
|
|
19
|
+
AudioContent,
|
|
20
|
+
AudioMediaContent,
|
|
21
|
+
FileContent,
|
|
22
|
+
FileMediaContent,
|
|
23
|
+
ImageContent,
|
|
24
|
+
ImageMediaContent,
|
|
25
|
+
ImageUrlMediaContent,
|
|
26
|
+
TextMediaContent,
|
|
27
|
+
VideoContent,
|
|
28
|
+
VideoMediaContent,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# User models
|
|
32
|
+
from .user_input import UserInputData
|
|
33
|
+
from .user_response import UserResponse
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
# Base models
|
|
37
|
+
"StructuredBase",
|
|
38
|
+
"UserInputRequest",
|
|
39
|
+
"PrintMessage",
|
|
40
|
+
# Content base types
|
|
41
|
+
"ImageContent",
|
|
42
|
+
"VideoContent",
|
|
43
|
+
"AudioContent",
|
|
44
|
+
"FileContent",
|
|
45
|
+
"MediaContent",
|
|
46
|
+
# Content models
|
|
47
|
+
"TextMediaContent",
|
|
48
|
+
"ImageMediaContent",
|
|
49
|
+
"ImageUrlMediaContent",
|
|
50
|
+
"VideoMediaContent",
|
|
51
|
+
"AudioMediaContent",
|
|
52
|
+
"FileMediaContent",
|
|
53
|
+
# User models
|
|
54
|
+
"UserInputData",
|
|
55
|
+
"UserResponse",
|
|
56
|
+
# Constants
|
|
57
|
+
"ContentTypeKey",
|
|
58
|
+
"ContentMappingEntry",
|
|
59
|
+
"CONTENT_MAPPING",
|
|
60
|
+
]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
|
|
4
|
+
"""Base models for structured data."""
|
|
5
|
+
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
9
|
+
|
|
10
|
+
from ..utils import MessageType, gen_id, now
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class StructuredBase(BaseModel):
|
|
14
|
+
"""Base model for structured data."""
|
|
15
|
+
|
|
16
|
+
id: str = Field(default_factory=gen_id)
|
|
17
|
+
type: MessageType
|
|
18
|
+
timestamp: str = Field(default_factory=now)
|
|
19
|
+
model_config = ConfigDict(
|
|
20
|
+
extra="ignore",
|
|
21
|
+
arbitrary_types_allowed=True,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class UserInputRequest(StructuredBase):
|
|
26
|
+
"""User input prompt model."""
|
|
27
|
+
|
|
28
|
+
type: MessageType = "input_request"
|
|
29
|
+
request_id: str
|
|
30
|
+
prompt: str
|
|
31
|
+
password: bool = False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class PrintMessage(StructuredBase):
|
|
35
|
+
"""Model for print messages."""
|
|
36
|
+
|
|
37
|
+
type: MessageType = "print"
|
|
38
|
+
data: str
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def create(cls, *args: Any, **kwargs: Any) -> "PrintMessage":
|
|
42
|
+
"""Create a new print message.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
*args : Any
|
|
47
|
+
Positional arguments (not used).
|
|
48
|
+
**kwargs : Any
|
|
49
|
+
Keyword arguments
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
PrintMessage
|
|
54
|
+
A new print message instance with the provided data.
|
|
55
|
+
"""
|
|
56
|
+
message = " ".join(str(arg) for arg in args)
|
|
57
|
+
if "file" in kwargs:
|
|
58
|
+
file = kwargs.pop("file")
|
|
59
|
+
if hasattr(file, "getvalue"):
|
|
60
|
+
io_value = file.getvalue()
|
|
61
|
+
if isinstance(io_value, bytes):
|
|
62
|
+
io_value = io_value.decode("utf-8", errors="replace")
|
|
63
|
+
message += io_value
|
|
64
|
+
end = kwargs.get("end", "\n")
|
|
65
|
+
message += end
|
|
66
|
+
return cls(data=message)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
|
|
4
|
+
"""Constants and type mappings for content models."""
|
|
5
|
+
|
|
6
|
+
from typing import Type, TypedDict, Union
|
|
7
|
+
|
|
8
|
+
from typing_extensions import Literal
|
|
9
|
+
|
|
10
|
+
from .content.audio import AudioMediaContent
|
|
11
|
+
from .content.file import FileMediaContent
|
|
12
|
+
from .content.image import ImageMediaContent, ImageUrlMediaContent
|
|
13
|
+
from .content.text import TextMediaContent
|
|
14
|
+
from .content.video import VideoMediaContent
|
|
15
|
+
|
|
16
|
+
MediaContent = Union[
|
|
17
|
+
TextMediaContent,
|
|
18
|
+
ImageMediaContent,
|
|
19
|
+
ImageUrlMediaContent,
|
|
20
|
+
VideoMediaContent,
|
|
21
|
+
AudioMediaContent,
|
|
22
|
+
FileMediaContent,
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
ContentTypeKey = Literal["text", "image", "image_url", "video", "audio", "file"]
|
|
26
|
+
"""Possible content types for the mapping."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ContentMappingEntry(TypedDict):
|
|
30
|
+
"""TypedDict for content mapping entries.
|
|
31
|
+
|
|
32
|
+
Attributes
|
|
33
|
+
----------
|
|
34
|
+
fields: List[str]
|
|
35
|
+
List of possible field names for the content type
|
|
36
|
+
cls: Type[MediaContent]
|
|
37
|
+
The class to instantiate for this content type
|
|
38
|
+
required_field: str
|
|
39
|
+
The field name required by the class constructor
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
fields: list[str]
|
|
43
|
+
cls: Type[MediaContent]
|
|
44
|
+
required_field: str
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
CONTENT_MAPPING: dict[ContentTypeKey, ContentMappingEntry] = {
|
|
48
|
+
"text": {
|
|
49
|
+
"fields": ["text"],
|
|
50
|
+
"cls": TextMediaContent,
|
|
51
|
+
"required_field": "text",
|
|
52
|
+
},
|
|
53
|
+
"image": {
|
|
54
|
+
"fields": ["image"],
|
|
55
|
+
"cls": ImageMediaContent,
|
|
56
|
+
"required_field": "image",
|
|
57
|
+
},
|
|
58
|
+
"image_url": {
|
|
59
|
+
"fields": ["image_url", "url"],
|
|
60
|
+
"cls": ImageUrlMediaContent,
|
|
61
|
+
"required_field": "image_url",
|
|
62
|
+
},
|
|
63
|
+
"video": {
|
|
64
|
+
"fields": ["video"],
|
|
65
|
+
"cls": VideoMediaContent,
|
|
66
|
+
"required_field": "video",
|
|
67
|
+
},
|
|
68
|
+
"audio": {
|
|
69
|
+
"fields": ["audio"],
|
|
70
|
+
"cls": AudioMediaContent,
|
|
71
|
+
"required_field": "audio",
|
|
72
|
+
},
|
|
73
|
+
"file": {
|
|
74
|
+
"fields": ["file"],
|
|
75
|
+
"cls": FileMediaContent,
|
|
76
|
+
"required_field": "file",
|
|
77
|
+
},
|
|
78
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Content models for media types."""
|
|
4
|
+
|
|
5
|
+
from .audio import AudioMediaContent
|
|
6
|
+
from .base import AudioContent, FileContent, ImageContent, VideoContent
|
|
7
|
+
from .file import FileMediaContent
|
|
8
|
+
from .image import ImageMediaContent, ImageUrlMediaContent
|
|
9
|
+
from .text import TextMediaContent
|
|
10
|
+
from .video import VideoMediaContent
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"AudioMediaContent",
|
|
14
|
+
"AudioContent",
|
|
15
|
+
"VideoMediaContent",
|
|
16
|
+
"VideoContent",
|
|
17
|
+
"ImageMediaContent",
|
|
18
|
+
"ImageUrlMediaContent",
|
|
19
|
+
"ImageContent",
|
|
20
|
+
"FileMediaContent",
|
|
21
|
+
"FileContent",
|
|
22
|
+
"TextMediaContent",
|
|
23
|
+
]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
# pylint: disable=unused-argument
|
|
4
|
+
"""Audio media content models."""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Literal
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
from .base import AudioContent
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AudioMediaContent(BaseModel):
|
|
15
|
+
"""Audio media content."""
|
|
16
|
+
|
|
17
|
+
type: Literal["audio"] = "audio"
|
|
18
|
+
audio: AudioContent
|
|
19
|
+
|
|
20
|
+
def to_string(
|
|
21
|
+
self,
|
|
22
|
+
uploads_root: Path | None,
|
|
23
|
+
base_name: str | None = None,
|
|
24
|
+
) -> str:
|
|
25
|
+
"""Convert the content to a string.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
uploads_root : Path | None
|
|
30
|
+
The root directory for storing images, optional.
|
|
31
|
+
base_name : str | None
|
|
32
|
+
The base name for the image file, optional.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
str
|
|
37
|
+
The string representation of the content.
|
|
38
|
+
"""
|
|
39
|
+
if self.audio.url:
|
|
40
|
+
return f"<audio src='{self.audio.url}'></audio>"
|
|
41
|
+
if self.audio.file:
|
|
42
|
+
return f"<audio src='{self.audio.file}'></audio>"
|
|
43
|
+
return str(self.audio.file)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Base content models for media types."""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Optional
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ImageContent(BaseModel):
|
|
11
|
+
"""Image content model."""
|
|
12
|
+
|
|
13
|
+
url: Optional[str] = None
|
|
14
|
+
file: Optional[Any] = None # File type not directly mappable in Python
|
|
15
|
+
alt: Optional[str] = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class VideoContent(BaseModel):
|
|
19
|
+
"""Video content model."""
|
|
20
|
+
|
|
21
|
+
url: Optional[str] = None
|
|
22
|
+
file: Optional[Any] = None
|
|
23
|
+
duration: Optional[int] = None
|
|
24
|
+
thumbnailUrl: Optional[str] = None
|
|
25
|
+
mimeType: Optional[str] = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AudioContent(BaseModel):
|
|
29
|
+
"""Audio content model."""
|
|
30
|
+
|
|
31
|
+
url: Optional[str] = None
|
|
32
|
+
file: Optional[Any] = None
|
|
33
|
+
duration: Optional[int] = None
|
|
34
|
+
transcript: Optional[str] = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class FileContent(BaseModel):
|
|
38
|
+
"""File content model."""
|
|
39
|
+
|
|
40
|
+
url: Optional[str] = None
|
|
41
|
+
file: Optional[Any] = None
|
|
42
|
+
name: str
|
|
43
|
+
size: Optional[int] = None
|
|
44
|
+
type: Optional[str] = None
|
|
45
|
+
previewUrl: Optional[str] = None
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
# pylint: disable=unused-argument
|
|
4
|
+
"""File media content models."""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Literal
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
from .base import FileContent
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FileMediaContent(BaseModel):
|
|
15
|
+
"""File media content."""
|
|
16
|
+
|
|
17
|
+
type: Literal["file"] = "file"
|
|
18
|
+
file: FileContent
|
|
19
|
+
|
|
20
|
+
def to_string(
|
|
21
|
+
self,
|
|
22
|
+
uploads_root: Path | None,
|
|
23
|
+
base_name: str | None = None,
|
|
24
|
+
) -> str:
|
|
25
|
+
"""Convert the content to a string.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
uploads_root : Path | None
|
|
30
|
+
The root directory for storing images, optional.
|
|
31
|
+
base_name : str | None
|
|
32
|
+
The base name for the image file, optional.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
str
|
|
37
|
+
The string representation of the content.
|
|
38
|
+
"""
|
|
39
|
+
if self.file.url:
|
|
40
|
+
return f"<a href='{self.file.url}'>{self.file.name}</a>"
|
|
41
|
+
if self.file.file:
|
|
42
|
+
return f"<a href='{self.file.file}'>{self.file.name}</a>"
|
|
43
|
+
return str(self.file.file)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
# pylint: disable=unused-argument
|
|
4
|
+
"""Image media content models."""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
from typing_extensions import Literal
|
|
10
|
+
|
|
11
|
+
from ...utils import get_image
|
|
12
|
+
from .base import ImageContent
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ImageMediaContent(BaseModel):
|
|
16
|
+
"""Image media content."""
|
|
17
|
+
|
|
18
|
+
type: Literal["image"] = "image"
|
|
19
|
+
image: ImageContent
|
|
20
|
+
|
|
21
|
+
def to_string(
|
|
22
|
+
self,
|
|
23
|
+
uploads_root: Path | None,
|
|
24
|
+
base_name: str | None = None,
|
|
25
|
+
) -> str:
|
|
26
|
+
"""Convert the content to a string.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
uploads_root : Path | None
|
|
31
|
+
The root directory for storing images, optional.
|
|
32
|
+
base_name : str | None
|
|
33
|
+
The base name for the image file, optional.
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
str
|
|
38
|
+
The string representation of the content.
|
|
39
|
+
"""
|
|
40
|
+
if self.image.url:
|
|
41
|
+
image = get_image(
|
|
42
|
+
uploads_root=uploads_root,
|
|
43
|
+
image_data=self.image.url,
|
|
44
|
+
base_name=base_name,
|
|
45
|
+
)
|
|
46
|
+
return f"<img {image}>"
|
|
47
|
+
if self.image.file:
|
|
48
|
+
image = get_image(
|
|
49
|
+
uploads_root=uploads_root,
|
|
50
|
+
image_data=self.image.file,
|
|
51
|
+
base_name=base_name,
|
|
52
|
+
)
|
|
53
|
+
return f"<img {image}>"
|
|
54
|
+
return str(self.image.file)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class ImageUrlMediaContent(BaseModel):
|
|
58
|
+
"""Image URL media content."""
|
|
59
|
+
|
|
60
|
+
type: Literal["image_url"] = "image_url"
|
|
61
|
+
image_url: ImageContent
|
|
62
|
+
|
|
63
|
+
def to_string(
|
|
64
|
+
self,
|
|
65
|
+
uploads_root: Path | None,
|
|
66
|
+
base_name: str | None = None,
|
|
67
|
+
) -> str:
|
|
68
|
+
"""Convert the content to a string.
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
uploads_root : Path | None
|
|
73
|
+
The root directory for storing images, optional.
|
|
74
|
+
base_name : str | None
|
|
75
|
+
The base name for the image file, optional.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
str
|
|
80
|
+
The string representation of the content.
|
|
81
|
+
"""
|
|
82
|
+
if self.image_url.url:
|
|
83
|
+
image = get_image(
|
|
84
|
+
uploads_root=uploads_root,
|
|
85
|
+
image_data=self.image_url.url,
|
|
86
|
+
base_name=base_name,
|
|
87
|
+
)
|
|
88
|
+
return f"<img {image}>"
|
|
89
|
+
if self.image_url.file:
|
|
90
|
+
image = get_image(
|
|
91
|
+
uploads_root=uploads_root,
|
|
92
|
+
image_data=self.image_url.file,
|
|
93
|
+
base_name=base_name,
|
|
94
|
+
)
|
|
95
|
+
return f"<img {image}>"
|
|
96
|
+
return str(self.image_url.file)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
# pylint: disable=unused-argument
|
|
4
|
+
"""Text media content models."""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
from typing_extensions import Literal
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TextMediaContent(BaseModel):
|
|
13
|
+
"""Text media content."""
|
|
14
|
+
|
|
15
|
+
type: Literal["text"] = "text"
|
|
16
|
+
text: str
|
|
17
|
+
|
|
18
|
+
def to_string(
|
|
19
|
+
self,
|
|
20
|
+
uploads_root: Path | None = None,
|
|
21
|
+
base_name: str | None = None,
|
|
22
|
+
) -> str:
|
|
23
|
+
"""Convert the content to a string.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
uploads_root : Path | None
|
|
28
|
+
The root directory for storing images, optional.
|
|
29
|
+
base_name : str | None
|
|
30
|
+
The base name for the image file, optional.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
str
|
|
35
|
+
The string representation of the content.
|
|
36
|
+
"""
|
|
37
|
+
return self.text
|