waldiez 0.3.11__py3-none-any.whl → 0.4.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 (66) hide show
  1. waldiez/_version.py +1 -1
  2. waldiez/cli.py +1 -3
  3. waldiez/exporting/agent/agent_exporter.py +26 -15
  4. waldiez/exporting/agent/utils/__init__.py +2 -4
  5. waldiez/exporting/agent/utils/captain_agent.py +250 -0
  6. waldiez/exporting/agent/utils/swarm_agent.py +12 -7
  7. waldiez/exporting/base/utils/comments.py +1 -0
  8. waldiez/exporting/chats/utils/swarm.py +1 -1
  9. waldiez/exporting/flow/flow_exporter.py +5 -6
  10. waldiez/exporting/flow/utils/__init__.py +3 -6
  11. waldiez/exporting/flow/utils/def_main.py +5 -4
  12. waldiez/exporting/flow/utils/flow_content.py +38 -0
  13. waldiez/exporting/flow/utils/importing_utils.py +64 -29
  14. waldiez/exporting/skills/skills_exporter.py +13 -6
  15. waldiez/exporting/skills/utils.py +92 -6
  16. waldiez/models/__init__.py +6 -0
  17. waldiez/models/agents/__init__.py +14 -0
  18. waldiez/models/agents/agent/__init__.py +2 -1
  19. waldiez/models/agents/agent/agent.py +71 -11
  20. waldiez/models/agents/agent/agent_type.py +11 -0
  21. waldiez/models/agents/agents.py +11 -1
  22. waldiez/models/agents/captain_agent/__init__.py +15 -0
  23. waldiez/models/agents/captain_agent/captain_agent.py +45 -0
  24. waldiez/models/agents/captain_agent/captain_agent_data.py +62 -0
  25. waldiez/models/agents/captain_agent/captain_agent_lib_entry.py +38 -0
  26. waldiez/models/agents/extra_requirements.py +88 -0
  27. waldiez/models/agents/group_manager/speakers.py +3 -0
  28. waldiez/models/agents/rag_user/retrieve_config.py +3 -0
  29. waldiez/models/agents/reasoning/reasoning_agent_reason_config.py +1 -0
  30. waldiez/models/agents/swarm_agent/after_work.py +13 -11
  31. waldiez/models/agents/swarm_agent/on_condition.py +3 -2
  32. waldiez/models/agents/swarm_agent/on_condition_available.py +1 -0
  33. waldiez/models/agents/swarm_agent/swarm_agent_data.py +3 -3
  34. waldiez/models/agents/swarm_agent/update_system_message.py +1 -0
  35. waldiez/models/chat/chat_message.py +1 -0
  36. waldiez/models/chat/chat_summary.py +1 -0
  37. waldiez/models/common/__init__.py +4 -0
  38. waldiez/models/common/ag2_version.py +30 -0
  39. waldiez/models/common/base.py +1 -1
  40. waldiez/models/common/date_utils.py +2 -0
  41. waldiez/models/common/dict_utils.py +2 -0
  42. waldiez/models/common/method_utils.py +98 -0
  43. waldiez/models/flow/__init__.py +2 -0
  44. waldiez/models/flow/utils.py +61 -1
  45. waldiez/models/model/__init__.py +2 -0
  46. waldiez/models/model/extra_requirements.py +57 -0
  47. waldiez/models/model/model.py +5 -2
  48. waldiez/models/model/model_data.py +3 -1
  49. waldiez/models/skill/__init__.py +4 -0
  50. waldiez/models/skill/extra_requirements.py +39 -0
  51. waldiez/models/skill/skill.py +157 -13
  52. waldiez/models/skill/skill_data.py +14 -0
  53. waldiez/models/skill/skill_type.py +8 -0
  54. waldiez/models/waldiez.py +47 -76
  55. waldiez/runner.py +19 -7
  56. waldiez/running/environment.py +30 -1
  57. waldiez/running/running.py +0 -6
  58. waldiez/utils/pysqlite3_checker.py +18 -5
  59. {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/METADATA +42 -30
  60. {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/RECORD +64 -55
  61. waldiez/exporting/agent/utils/agent_class_name.py +0 -36
  62. waldiez/exporting/agent/utils/agent_imports.py +0 -55
  63. {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/WHEEL +0 -0
  64. {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/entry_points.txt +0 -0
  65. {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/licenses/LICENSE +0 -0
  66. {waldiez-0.3.11.dist-info → waldiez-0.4.0.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,38 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Waldiez captain agent lib entry."""
4
+
5
+ from pydantic import Field
6
+ from typing_extensions import Annotated
7
+
8
+ from ...common import WaldiezBase
9
+
10
+
11
+ class WaldiezCaptainAgentLibEntry(WaldiezBase):
12
+ """Captain agent lib entry."""
13
+
14
+ name: Annotated[
15
+ str,
16
+ Field(
17
+ ...,
18
+ title="Name",
19
+ description="The name of the agent",
20
+ ),
21
+ ]
22
+ description: Annotated[
23
+ str,
24
+ Field(
25
+ ...,
26
+ title="Description",
27
+ description="The description of the agent",
28
+ ),
29
+ ]
30
+ system_message: Annotated[
31
+ str,
32
+ Field(
33
+ ...,
34
+ title="System message",
35
+ description="The system message",
36
+ alias="systemMessage",
37
+ ),
38
+ ]
@@ -0,0 +1,88 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Extra requirements for agents."""
4
+
5
+ # pylint: disable=line-too-long
6
+ import platform
7
+ from typing import Iterator, List, Set
8
+
9
+ from .agent import WaldiezAgent
10
+ from .rag_user import WaldiezRagUser
11
+
12
+
13
+ def get_retrievechat_extra_requirements(
14
+ agents: Iterator[WaldiezAgent],
15
+ ) -> Set[str]:
16
+ """Get the retrievechat extra requirements.
17
+
18
+ Parameters
19
+ ----------
20
+ agents : List[WaldiezAgent]
21
+ The flow agents.
22
+
23
+ Returns
24
+ -------
25
+ Set[str]
26
+ The retrievechat extra requirements.
27
+ """
28
+ # https://github.com/ag2ai/ag2/blob/main/pyproject.toml
29
+ # with chromadb relaxed
30
+ # to avoid conflicts with other extras and (later) allow py3.13
31
+ rag_requirements: Set[str] = {
32
+ "protobuf==4.25.3",
33
+ "chromadb>=0.5.23",
34
+ "sentence_transformers",
35
+ "pypdf",
36
+ "ipython",
37
+ "beautifulsoup4",
38
+ "markdownify",
39
+ }
40
+ for agent in agents:
41
+ if agent.agent_type == "rag_user" and isinstance(agent, WaldiezRagUser):
42
+ # if not chroma, get the relevant db requirements
43
+ db_type = agent.data.retrieve_config.vector_db
44
+ if db_type == "pgvector":
45
+ rag_requirements.update(
46
+ [
47
+ "pgvector>=0.2.5",
48
+ "psycopg[binary]>=3.2.4",
49
+ ]
50
+ )
51
+ elif db_type == "mongodb":
52
+ rag_requirements.add("pymongo>=4.11")
53
+ elif db_type == "qdrant":
54
+ rag_requirements.update(["qdrant_client[fastembed]"])
55
+ return rag_requirements
56
+
57
+
58
+ def get_captain_agent_extra_requirements() -> List[str]:
59
+ """Get the captain agent extra requirements.
60
+
61
+ Returns
62
+ -------
63
+ List[str]
64
+ The captain agent extra requirements.
65
+ """
66
+ # https://github.com/ag2ai/ag2/blob/main/autogen/agentchat/contrib/captainagent/tools/requirements.txt # noqa: E501
67
+ tool_requirements = [
68
+ "markdownify",
69
+ "arxiv",
70
+ "pymupdf",
71
+ "wikipedia-api",
72
+ "easyocr",
73
+ "python-pptx",
74
+ "openai-whisper",
75
+ "pandas",
76
+ "scipy",
77
+ # "sentence-transformers", also in agent_requirements
78
+ ]
79
+ agent_requirements = [
80
+ "chromadb",
81
+ "sentence-transformers",
82
+ "huggingface-hub",
83
+ ]
84
+ if platform.system() == "Linux":
85
+ agent_requirements.append("pysqlite3-binary")
86
+ # on windows and OSX, installing pysqlite3-binary seem to fail in some cases
87
+ # we can handle/install if needed in waldiez.utils.pysqlite3_checker
88
+ return tool_requirements + agent_requirements
@@ -16,8 +16,11 @@ WaldiezGroupManagerSpeakersSelectionMethod = Literal[
16
16
  "round_robin",
17
17
  "custom",
18
18
  ]
19
+ """Possible methods for the speaker selection."""
19
20
  WaldiezGroupManagerSpeakersSelectionMode = Literal["repeat", "transition"]
21
+ """Possible selection modes: repeat, transition."""
20
22
  WaldiezGroupManagerSpeakersTransitionsType = Literal["allowed", "disallowed"]
23
+ """Possible transitions types: allowed, disallowed."""
21
24
 
22
25
  CUSTOM_SPEAKER_SELECTION = "custom_speaker_selection"
23
26
  CUSTOM_SPEAKER_SELECTION_ARGS = ["last_speaker", "groupchat"]
@@ -13,8 +13,11 @@ from ...common import WaldiezBase, check_function, generate_function
13
13
  from .vector_db_config import WaldiezRagUserVectorDbConfig
14
14
 
15
15
  WaldiezRagUserTask = Literal["code", "qa", "default"]
16
+ """Possible tasks for the retrieve chat."""
16
17
  WaldiezRagUserVectorDb = Literal["chroma", "pgvector", "mongodb", "qdrant"]
18
+ """Possible vector dbs for the retrieve chat."""
17
19
  WaldiezRagUserChunkMode = Literal["multi_lines", "one_line"]
20
+ """Possible chunk modes for the retrieve chat."""
18
21
  WaldiezRagUserModels: Dict[WaldiezRagUserVectorDb, str] = {
19
22
  "chroma": "all-MiniLM-L6-v2",
20
23
  "mongodb": "all-MiniLM-L6-v2",
@@ -8,6 +8,7 @@ from typing_extensions import Annotated, Literal
8
8
  from ...common import WaldiezBase
9
9
 
10
10
  ReasoningConfigMethod = Literal["beam_search", "mcts", "lats", "dfs"]
11
+ """Possible reasoning methods."""
11
12
 
12
13
 
13
14
  class WaldiezReasoningAgentReasonConfig(WaldiezBase):
@@ -17,16 +17,18 @@ from typing_extensions import Annotated, Literal, Self
17
17
  from ...common import WaldiezBase, check_function, generate_function
18
18
 
19
19
  WaldiezSwarmAfterWorkRecipientType = Literal["agent", "option", "callable"]
20
+ """The possible AfterWork recipient types."""
20
21
  WaldiezSwarmAfterWorkOption = Literal[
21
22
  "TERMINATE", "REVERT_TO_USER", "STAY", "SWARM_MANAGER"
22
23
  ]
24
+ """The possible AfterWork options."""
23
25
 
24
26
 
25
27
  CUSTOM_AFTER_WORK = "custom_after_work"
26
28
  CUSTOM_AFTER_WORK_ARGS = ["last_speaker", "messages", "groupchat"]
27
29
  CUSTOM_AFTER_WORK_TYPES = (
28
- ["SwarmAgent", "List[Dict[str, Any]]", "GroupChat"],
29
- "Union[AfterWorkOption, SwarmAgent, str]",
30
+ ["ConversableAgent", "List[Dict[str, Any]]", "GroupChat"],
31
+ "Union[AfterWorkOption, ConversableAgent, str]",
30
32
  )
31
33
 
32
34
 
@@ -45,15 +47,15 @@ class WaldiezSwarmAfterWork(WaldiezBase):
45
47
  recipient_type : WaldiezSwarmAfterWorkRecipientType
46
48
  The type of recipient.
47
49
  Can be 'agent', 'option', or 'callable'.
48
- If 'agent', the recipient is a SwarmAgent.
50
+ If 'agent', the recipient is a Swarm Agent.
49
51
  If 'option', the recipient is an AfterWorkOption :
50
52
  ('TERMINATE', 'REVERT_TO_USER', 'STAY', 'SWARM_MANAGER').
51
53
  If 'callable', it should have the signature:
52
54
  def custom_after_work(
53
- last_speaker: SwarmAgent,
55
+ last_speaker: ConversableAgent,
54
56
  messages: List[dict],
55
57
  groupchat: GroupChat,
56
- ) -> Union[AfterWorkOption, SwarmAgent, str]:
58
+ ) -> Union[AfterWorkOption, ConversableAgent, str]:
57
59
 
58
60
  """
59
61
 
@@ -79,15 +81,15 @@ class WaldiezSwarmAfterWork(WaldiezBase):
79
81
  description=(
80
82
  "The type of recipient. "
81
83
  "Can be 'agent', 'option', or 'callable'. "
82
- "If 'agent', the recipient is a SwarmAgent. "
84
+ "If 'agent', the recipient is a Swarm Agent. "
83
85
  "If 'option', the recipient is an AfterWorkOption :"
84
86
  " ('TERMINATE', 'REVERT_TO_USER', 'STAY', 'SWARM_MANAGER'). "
85
87
  "If 'callable', it should have the signature: "
86
88
  "def custom_after_work("
87
- " last_speaker: SwarmAgent,"
89
+ " last_speaker: ConversableAgent,"
88
90
  " messages: List[Dict[str, Any]],"
89
91
  " groupchat: GroupChat,"
90
- ") -> Union[AfterWorkOption, SwarmAgent, str]:"
92
+ ") -> Union[AfterWorkOption, ConversableAgent, str]:"
91
93
  ),
92
94
  ),
93
95
  ]
@@ -117,13 +119,13 @@ class WaldiezSwarmAfterWork(WaldiezBase):
117
119
  The recipient string and the function content if applicable.
118
120
  """
119
121
  if self.recipient_type == "option":
120
- return f"AFTER_WORK(AfterWorkOption.{self.recipient})", ""
122
+ return f"AfterWork(AfterWorkOption.{self.recipient})", ""
121
123
  if self.recipient_type == "agent":
122
124
  # the the recipient is passed as the agent name
123
125
  # (and not its id), care should be taken to ensure
124
126
  # the all the agents in the flow have unique names
125
127
  agent_instance = agent_names.get(self.recipient, self.recipient)
126
- return f"AFTER_WORK({agent_instance})", ""
128
+ return f"AfterWork({agent_instance})", ""
127
129
 
128
130
  function_name = CUSTOM_AFTER_WORK
129
131
  if name_prefix:
@@ -131,7 +133,7 @@ class WaldiezSwarmAfterWork(WaldiezBase):
131
133
  if name_suffix:
132
134
  function_name = f"{function_name}_{name_suffix}"
133
135
  return (
134
- f"AFTER_WORK({function_name})",
136
+ f"AfterWork({function_name})",
135
137
  generate_function(
136
138
  function_name=function_name,
137
139
  function_args=CUSTOM_AFTER_WORK_ARGS,
@@ -12,6 +12,7 @@ from .on_condition_available import WaldiezSwarmOnConditionAvailable
12
12
  from .on_condition_target import WaldiezSwarmOnConditionTarget
13
13
 
14
14
  WaldiezSwarmOnConditionTargetType = Literal["agent", "nested_chat"]
15
+ """Possible types for the target of the OnCondition."""
15
16
 
16
17
 
17
18
  class WaldiezSwarmOnCondition(WaldiezBase):
@@ -30,7 +31,7 @@ class WaldiezSwarmOnCondition(WaldiezBase):
30
31
  The condition for transitioning to the target agent
31
32
 
32
33
  available: str, optional
33
- Optional condition to determine if this ON_CONDITION is available.
34
+ Optional condition to determine if this OnCondition is available.
34
35
  Can be a Callable or a string. If a string, it will look up the
35
36
  value of the context variable with that name, which should be a bool.
36
37
 
@@ -73,7 +74,7 @@ class WaldiezSwarmOnCondition(WaldiezBase):
73
74
  default_factory=WaldiezSwarmOnConditionAvailable,
74
75
  title="Available",
75
76
  description=(
76
- "Optional condition to determine if this ON_CONDITION "
77
+ "Optional condition to determine if this OnCondition "
77
78
  "is available."
78
79
  ),
79
80
  ),
@@ -12,6 +12,7 @@ from ...common import WaldiezBase, check_function, generate_function
12
12
  WaldiezSwarmOnConditionAvailableCheckType = Literal[
13
13
  "string", "callable", "none"
14
14
  ]
15
+ """Possible types for the `available` check."""
15
16
 
16
17
  CUSTOM_ON_CONDITION_AVAILABLE = "custom_on_condition_available"
17
18
  CUSTOM_ON_CONDITION_AVAILABLE_ARGS = ["agent", "message"]
@@ -29,7 +29,7 @@ class WaldiezSwarmAgentData(WaldiezAgentData):
29
29
  A list of functions (skill ids) to register with the agent.
30
30
 
31
31
  update_agent_state_before_reply : List[str]
32
- A list of functions, including `UPDATE_SYSTEM_MESSAGE`,
32
+ A list of functions, including `UpdateSystemMessage`,
33
33
  called to update the agent's state before it replies. Each function
34
34
  is called when the agent is selected and before it speaks.
35
35
 
@@ -67,10 +67,10 @@ class WaldiezSwarmAgentData(WaldiezAgentData):
67
67
  title="Update Agent State Before Reply",
68
68
  alias="updateAgentStateBeforeReply",
69
69
  description=(
70
- "A list of functions, including UPDATE_SYSTEM_MESSAGEs,"
70
+ "A list of functions, including UpdateSystemMessage,"
71
71
  "called to update the agent's state before it replies. "
72
72
  " Each function is called when the agent is selected "
73
- "and before it speaks. If not an UPDATE_SYSTEM_MESSAGE, "
73
+ "and before it speaks. If not an UpdateSystemMessage, "
74
74
  "it should be a skill id."
75
75
  ),
76
76
  default_factory=list,
@@ -10,6 +10,7 @@ from typing_extensions import Annotated, Literal, Self
10
10
  from ...common import WaldiezBase, check_function, generate_function
11
11
 
12
12
  WaldiezSwarmUpdateFunctionType = Literal["string", "callable"]
13
+ """Possible types for the update function."""
13
14
 
14
15
  CUSTOM_UPDATE_SYSTEM_MESSAGE = "custom_update_system_message"
15
16
  CUSTOM_UPDATE_SYSTEM_MESSAGE_ARGS = ["agent", "messages"]
@@ -12,6 +12,7 @@ from ..common import WaldiezBase, check_function, update_dict
12
12
  WaldiezChatMessageType = Literal[
13
13
  "string", "method", "rag_message_generator", "none"
14
14
  ]
15
+ """Possible types for the message."""
15
16
 
16
17
  CALLABLE_MESSAGE = "callable_message"
17
18
  CALLABLE_MESSAGE_ARGS = ["sender", "recipient", "context"]
@@ -20,6 +20,7 @@ WaldiezChatSummaryMethod = Literal[
20
20
  "reflection_with_llm",
21
21
  "last_msg",
22
22
  ]
23
+ """Possible methods for the LLM summary."""
23
24
 
24
25
 
25
26
  class WaldiezChatSummary(WaldiezBase):
@@ -2,11 +2,13 @@
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
  """Common utils for all models."""
4
4
 
5
+ from .ag2_version import get_autogen_version
5
6
  from .base import WaldiezBase
6
7
  from .date_utils import now
7
8
  from .dict_utils import update_dict
8
9
  from .method_utils import (
9
10
  check_function,
11
+ gather_code_imports,
10
12
  generate_function,
11
13
  get_function,
12
14
  parse_code_string,
@@ -16,6 +18,8 @@ __all__ = [
16
18
  "WaldiezBase",
17
19
  "now",
18
20
  "check_function",
21
+ "gather_code_imports",
22
+ "get_autogen_version",
19
23
  "get_function",
20
24
  "generate_function",
21
25
  "parse_code_string",
@@ -0,0 +1,30 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """Get the autogen version."""
4
+
5
+ import warnings
6
+ from functools import cache
7
+
8
+
9
+ @cache
10
+ def get_autogen_version() -> str:
11
+ """Get the autogen version.
12
+
13
+ Returns
14
+ -------
15
+ str
16
+ The autogen version.
17
+
18
+ Raises
19
+ ------
20
+ ValueError
21
+ If pyautogen is not installed.
22
+ """
23
+ # pylint: disable=import-outside-toplevel
24
+ with warnings.catch_warnings():
25
+ warnings.simplefilter("ignore")
26
+ try:
27
+ from autogen.version import __version__ as ag2 # type: ignore
28
+ except ImportError as error: # pragma: no cover
29
+ raise ValueError("pyautogen is not installed.") from error
30
+ return ag2
@@ -65,6 +65,6 @@ class WaldiezBase(BaseModel):
65
65
  by_alias = True
66
66
  return super().model_dump_json(by_alias=by_alias, **kwargs)
67
67
 
68
- def __hash__(self) -> int:
68
+ def __hash__(self) -> int: # pragma: no cover
69
69
  """Return the hash of the object."""
70
70
  return id(self)
@@ -1,3 +1,5 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
1
3
  """Date utilities."""
2
4
 
3
5
  from datetime import datetime, timezone
@@ -1,3 +1,5 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
1
3
  """Dictionary related utilities."""
2
4
 
3
5
  from typing import Any, Dict
@@ -3,6 +3,10 @@
3
3
  """Function related utilities."""
4
4
 
5
5
  import ast
6
+ import importlib.util
7
+ import sys
8
+ import sysconfig
9
+ from pathlib import Path
6
10
  from typing import List, Optional, Tuple
7
11
 
8
12
  import parso
@@ -12,6 +16,35 @@ import parso.tree
12
16
  MAX_VAR_NAME_LENGTH = 64
13
17
 
14
18
 
19
+ def is_standard_library(module_name: str) -> bool:
20
+ """Check if the module is part of the standard library.
21
+
22
+ Parameters
23
+ ----------
24
+ module_name : str
25
+ The module name.
26
+
27
+ Returns
28
+ -------
29
+ bool
30
+ True if the module is part of the standard library.
31
+ """
32
+ if module_name in sys.builtin_module_names:
33
+ return True
34
+ try:
35
+ spec = importlib.util.find_spec(module_name)
36
+ except BaseException: # pylint: disable=broad-except
37
+ return False
38
+ if spec is None or not spec.origin:
39
+ return False
40
+ if "site-packages" in spec.origin:
41
+ return False
42
+ if spec.origin.startswith(sys.prefix) or spec.origin == "frozen":
43
+ return True
44
+ stdlib_path = str(Path(sysconfig.get_path("stdlib")).resolve())
45
+ return spec.origin.startswith(stdlib_path)
46
+
47
+
15
48
  def parse_code_string(
16
49
  code_string: str,
17
50
  ) -> Tuple[Optional[str], Optional[ast.Module]]:
@@ -38,6 +71,71 @@ def parse_code_string(
38
71
  return None, tree
39
72
 
40
73
 
74
+ def gather_code_imports(
75
+ code_string: str,
76
+ is_interop: bool,
77
+ ) -> Tuple[List[str], List[str]]:
78
+ """Gather the imports from the code string.
79
+
80
+ Parameters
81
+ ----------
82
+ code_string : str
83
+ The code string.
84
+ is_interop : bool
85
+ If True, make sure the interoperability import is present.
86
+
87
+ Returns
88
+ -------
89
+ Tuple[List[str], List[str]]
90
+ The standard library imports and the third party imports.
91
+ """
92
+ standard_lib_imports: List[str] = []
93
+ third_party_imports: List[str] = []
94
+ tree = parso.parse(code_string) # type: ignore
95
+ for node in tree.iter_imports():
96
+ if node.type == "import_name":
97
+ full_import_statement = node.get_code().strip()
98
+ module_name = (
99
+ node.get_code().replace("import", "").strip().split(" ")[0]
100
+ )
101
+ if not module_name:
102
+ continue
103
+ if is_standard_library(module_name):
104
+ standard_lib_imports.append(full_import_statement)
105
+ else:
106
+ third_party_imports.append(full_import_statement)
107
+ elif node.type == "import_from":
108
+ full_import_statement = node.get_code().strip()
109
+ module_name = (
110
+ node.get_code().replace("from", "").strip().split(" ")[0]
111
+ )
112
+ if not module_name:
113
+ continue
114
+ if is_standard_library(module_name):
115
+ standard_lib_imports.append(full_import_statement)
116
+ else:
117
+ third_party_imports.append(full_import_statement)
118
+ if is_interop and (
119
+ "from autogen.interop import Interoperability"
120
+ not in third_party_imports
121
+ ):
122
+ third_party_imports.append(
123
+ "from autogen.interop import Interoperability"
124
+ )
125
+ # sorted_standard_lib_imports = # first import x, then from a import b
126
+ sorted_standard_lib_imports = sorted(
127
+ [stmt for stmt in standard_lib_imports if stmt.startswith("import ")]
128
+ ) + sorted(
129
+ [stmt for stmt in standard_lib_imports if stmt.startswith("from ")]
130
+ )
131
+ sorted_third_party_imports = sorted(
132
+ [stmt for stmt in third_party_imports if stmt.startswith("import ")]
133
+ ) + sorted(
134
+ [stmt for stmt in third_party_imports if stmt.startswith("from ")]
135
+ )
136
+ return sorted_standard_lib_imports, sorted_third_party_imports
137
+
138
+
41
139
  def check_function(
42
140
  code_string: str,
43
141
  function_name: str,
@@ -4,8 +4,10 @@
4
4
 
5
5
  from .flow import WaldiezFlow
6
6
  from .flow_data import WaldiezFlowData
7
+ from .utils import get_flow_data
7
8
 
8
9
  __all__ = [
10
+ "get_flow_data",
9
11
  "WaldiezFlow",
10
12
  "WaldiezFlowData",
11
13
  ]
@@ -4,7 +4,7 @@
4
4
 
5
5
  import uuid
6
6
  from datetime import datetime, timezone
7
- from typing import List
7
+ from typing import Any, Dict, List, Optional
8
8
 
9
9
  from ..agents import (
10
10
  WaldiezAgent,
@@ -170,3 +170,63 @@ def merge_nested_chat_messages(
170
170
  chat_ids_added.append(chat.id)
171
171
  nested_chat.messages.sort(key=lambda x: chat_ids_added.index(x.id))
172
172
  return [nested_chat]
173
+
174
+
175
+ def get_flow_data(
176
+ data: Dict[str, Any],
177
+ flow_id: Optional[str] = None,
178
+ name: Optional[str] = None,
179
+ description: Optional[str] = None,
180
+ tags: Optional[List[str]] = None,
181
+ requirements: Optional[List[str]] = None,
182
+ ) -> Dict[str, Any]:
183
+ """Get the flow from the passed data dict.
184
+
185
+ Parameters
186
+ ----------
187
+ data : Dict[str, Any]
188
+ The data dict.
189
+ flow_id : Optional[str], optional
190
+ The flow ID, by default None.
191
+ name : Optional[str], optional
192
+ The flow name, by default None.
193
+ description : Optional[str], optional
194
+ The flow description, by default None.
195
+ tags : Optional[List[str]], optional
196
+ The flow tags, by default None.
197
+ requirements : Optional[List[str]], optional
198
+ The flow requirements, by default None.
199
+
200
+ Returns
201
+ -------
202
+ Dict[str, Any]
203
+ The flow data.
204
+
205
+ Raises
206
+ ------
207
+ ValueError
208
+ If the flow type is not "flow".
209
+ """
210
+ item_type = data.get("type", "flow")
211
+ if item_type != "flow":
212
+ # empty flow (from exported model/skill ?)
213
+ raise ValueError(f"Invalid flow type: {item_type}")
214
+ from_args = {
215
+ "id": flow_id,
216
+ "name": name,
217
+ "description": description,
218
+ "tags": tags,
219
+ "requirements": requirements,
220
+ }
221
+ for key, value in from_args.items():
222
+ if value:
223
+ data[key] = value
224
+ if "name" not in data:
225
+ data["name"] = "Waldiez Flow"
226
+ if "description" not in data:
227
+ data["description"] = "Waldiez Flow description"
228
+ if "tags" not in data:
229
+ data["tags"] = []
230
+ if "requirements" not in data:
231
+ data["requirements"] = []
232
+ return data
@@ -2,10 +2,12 @@
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
  """Waldiez model."""
4
4
 
5
+ from .extra_requirements import get_models_extra_requirements
5
6
  from .model import DEFAULT_BASE_URLS, WaldiezModel
6
7
  from .model_data import WaldiezModelAPIType, WaldiezModelData, WaldiezModelPrice
7
8
 
8
9
  __all__ = [
10
+ "get_models_extra_requirements",
9
11
  "DEFAULT_BASE_URLS",
10
12
  "WaldiezModel",
11
13
  "WaldiezModelData",