waldiez 0.5.7__py3-none-any.whl → 0.5.9__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/_version.py CHANGED
@@ -5,4 +5,4 @@
5
5
  This file is automatically generated by Hatchling.
6
6
  Do not edit this file directly.
7
7
  """
8
- __version__ = VERSION = "0.5.7"
8
+ __version__ = VERSION = "0.5.9"
waldiez/cli.py CHANGED
@@ -100,6 +100,19 @@ def run(
100
100
  False,
101
101
  help="Override the output file if it already exists.",
102
102
  ),
103
+ env_file: Optional[Path] = typer.Option( # noqa: B008
104
+ None,
105
+ "--env-file",
106
+ "-e",
107
+ help=(
108
+ "Path to a .env file containing additional environment variables. "
109
+ "These variables will be set before running the flow."
110
+ ),
111
+ file_okay=True,
112
+ dir_okay=False,
113
+ readable=True,
114
+ resolve_path=True,
115
+ ),
103
116
  ) -> None:
104
117
  """Run a Waldiez flow."""
105
118
  os.environ["AUTOGEN_USE_DOCKER"] = "0"
@@ -126,6 +139,7 @@ def run(
126
139
  structured, # structured_io
127
140
  False, # skip_mmd
128
141
  False, # skip_timeline
142
+ env_file,
129
143
  )
130
144
  else:
131
145
  runner.run(
@@ -134,6 +148,7 @@ def run(
134
148
  structured_io=structured,
135
149
  skip_mmd=False,
136
150
  skip_timeline=False,
151
+ dot_env=env_file,
137
152
  )
138
153
 
139
154
 
@@ -157,7 +172,7 @@ def convert(
157
172
  "Path to the output file. "
158
173
  "The file extension determines the output format: "
159
174
  "`.py` for Python script, `.ipynb` for Jupyter notebook."
160
- " If not provided, the output will be saved in the same directory as the input file."
175
+ " If not provided, the output (.py) will be saved in the same directory as the input file."
161
176
  " If the file already exists, it will not be overwritten unless --force is used."
162
177
  ),
163
178
  file_okay=True,
@@ -1,5 +1,7 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ # pylint: disable=line-too-long
4
+ # flake8: noqa: E501
3
5
  """Common utilities for exporting chats."""
4
6
 
5
7
  import json
@@ -99,14 +101,56 @@ def get_event_handler_string(
99
101
  f"{tab} should_continue = False\n"
100
102
  f"{tab} if not should_continue:\n"
101
103
  f"{tab} break\n"
104
+ )
105
+ content += get_result_dicts_string(tab, is_async)
106
+ content += (
102
107
  f"{tab}else:\n"
103
108
  f"{tab} if not isinstance(results, list):\n"
104
109
  f"{tab} results = [results]\n"
105
- f"{tab} for result in results:\n"
110
+ f"{tab} for index, result in enumerate(results):\n"
106
111
  )
107
112
  if is_async:
108
113
  content += f"{tab} await result.process()\n"
109
114
  else:
110
115
  content += f"{tab} result.process()\n"
116
+ content += get_result_dicts_string(tab, is_async)
111
117
 
112
118
  return content
119
+
120
+
121
+ def get_result_dicts_string(tab: str, is_async: bool) -> str:
122
+ """Get the result dicts string.
123
+
124
+ Parameters
125
+ ----------
126
+ tab : str
127
+ The space string to use for indentation.
128
+ is_async : bool
129
+ Whether the function is asynchronous.
130
+
131
+ Returns
132
+ -------
133
+ str
134
+ The result dicts string.
135
+ """
136
+ space = f"{tab} "
137
+ flow_content = f"{space}result_dict = {{\n"
138
+ flow_content += f"{space} 'index': index,\n"
139
+ if is_async:
140
+ flow_content += f"{space} 'messages': await result.messages,\n"
141
+ flow_content += f"{space} 'summary': await result.summary,\n"
142
+ flow_content += f"{space} 'cost': (await result.cost).model_dump(mode='json', fallback=str) if await result.cost else None,\n"
143
+ flow_content += f"{space} 'context_variables': (await result.context_variables).model_dump(mode='json', fallback=str) if await result.context_variables else None,\n"
144
+ flow_content += (
145
+ f"{space} 'last_speaker': await result.last_speaker,\n"
146
+ )
147
+ else:
148
+ flow_content += f"{space} 'messages': result.messages,\n"
149
+ flow_content += f"{space} 'summary': result.summary,\n"
150
+ flow_content += f"{space} 'cost': result.cost.model_dump(mode='json', fallback=str) if result.cost else None,\n"
151
+ flow_content += f"{space} 'context_variables': result.context_variables.model_dump(mode='json', fallback=str) if result.context_variables else None,\n"
152
+ flow_content += f"{space} 'last_speaker': result.last_speaker,\n"
153
+ flow_content += f"{space} 'uuid': str(result.uuid),\n"
154
+ flow_content += f"{space}}}\n"
155
+ flow_content += f"{space}result_dicts.append(result_dict)\n"
156
+ return flow_content
@@ -43,7 +43,7 @@ def export_group_chats(
43
43
  tab = " " * tabs
44
44
  run_group_chat = "run_group_chat"
45
45
  if is_async:
46
- run_group_chat = "a_run_group_chat"
46
+ run_group_chat = "await a_run_group_chat"
47
47
  manager_name = agent_names[manager.id]
48
48
  pattern_name = f"{manager_name}_pattern"
49
49
  content = f"{tab}results = {run_group_chat}(" + "\n"
@@ -115,11 +115,14 @@ class ExecutionGenerator:
115
115
  "Callable[[BaseEvent], Coroutine[None, None, bool]]"
116
116
  "] = None"
117
117
  )
118
- return_type_hint = (
119
- "AsyncRunResponseProtocol" if is_async else "RunResponseProtocol"
120
- )
118
+ return_type_hint = "list[dict[str, Any]]"
121
119
  flow_content += f"def main({on_event_arg}) -> {return_type_hint}:\n"
122
- flow_content += f" {main_doc_string(is_async=is_async)}\n"
120
+ flow_content += f" {main_doc_string()}\n"
121
+ if not is_async:
122
+ flow_content += " results: list[RunResponseProtocol] | RunResponseProtocol = []\n"
123
+ else:
124
+ flow_content += " results: list[AsyncRunResponseProtocol] | AsyncRunResponseProtocol = []\n"
125
+ flow_content += " result_dicts: list[dict[str, Any]] = []\n"
123
126
  space = " "
124
127
  if cache_seed is not None:
125
128
  flow_content += (
@@ -138,7 +141,7 @@ class ExecutionGenerator:
138
141
  flow_content += after_run + "\n"
139
142
  if cache_seed is not None:
140
143
  space = space[4:]
141
- flow_content += f"{space}return results\n"
144
+ flow_content += f"{space}return result_dicts\n"
142
145
  return flow_content
143
146
 
144
147
  @staticmethod
@@ -163,42 +166,19 @@ class ExecutionGenerator:
163
166
  if is_async:
164
167
  return "# %%\nawait main()\n"
165
168
  return "# %%\nmain()\n"
169
+ return_type_hint = "list[dict[str, Any]]"
166
170
  if is_async:
167
171
  content += "async def call_main() -> None:\n"
168
- return_type_hint = "list[AsyncRunResponseProtocol]"
169
172
  else:
170
173
  content += "def call_main() -> None:\n"
171
- return_type_hint = "list[RunResponseProtocol]"
172
174
  content += f'{tab}"""Run the main function and print the results."""\n'
173
175
  content += f"{tab}results: {return_type_hint} = "
174
176
  if is_async:
175
177
  content += "await "
176
178
  content += "main()\n"
177
- content += f"{tab}results_dicts: list[dict[str, Any]] = []\n"
178
- content += f"{tab}for result in results:\n"
179
- if is_async:
180
- content += f"{tab}{tab}result_summary = await result.summary\n"
181
- content += f"{tab}{tab}result_messages = await result.messages\n"
182
- content += f"{tab}{tab}result_cost = await result.cost\n"
183
- else:
184
- content += f"{tab}{tab}result_summary = result.summary\n"
185
- content += f"{tab}{tab}result_messages = result.messages\n"
186
- content += f"{tab}{tab}result_cost = result.cost\n"
187
- content += f"{tab}{tab}cost: dict[str, Any] | None = None\n"
188
- content += f"{tab}{tab}if result_cost:\n"
189
- content += f'{tab}{tab}{tab}cost = result_cost.model_dump(mode="json", fallback=str)\n'
190
- content += f"{tab}{tab}results_dicts.append(\n"
191
- content += f"{tab}{tab}{tab}{{\n"
192
- content += f"{tab}{tab}{tab}{tab}'summary': result_summary,\n"
193
- content += f"{tab}{tab}{tab}{tab}'messages': result_messages,\n"
194
- content += f"{tab}{tab}{tab}{tab}'cost': cost,\n"
195
- content += f"{tab}{tab}{tab}}}\n"
196
- content += f"{tab}{tab})\n"
197
- content += "\n"
198
- content += f"{tab}results_dict = {{\n"
199
- content += f"{tab}{tab}'results': results_dicts,\n"
200
- content += f"{tab}}}\n"
201
- content += f"{tab}print(json.dumps(results_dict, indent=2))\n"
179
+ content += (
180
+ f"{tab}print(json.dumps(results, indent=2, ensure_ascii=False))\n"
181
+ )
202
182
  return content
203
183
 
204
184
  @staticmethod
@@ -226,3 +206,45 @@ class ExecutionGenerator:
226
206
  else:
227
207
  content += " call_main()\n"
228
208
  return content
209
+
210
+
211
+ def get_result_dicts_string(space: str, is_async: bool) -> str:
212
+ """Get the result dicts string.
213
+
214
+ Parameters
215
+ ----------
216
+ space : str
217
+ The space string to use for indentation.
218
+ is_async : bool
219
+ Whether the function is asynchronous.
220
+
221
+ Returns
222
+ -------
223
+ str
224
+ The result dicts string.
225
+ """
226
+ flow_content = f"{space}for index, result in enumerate(results):\n"
227
+ if not is_async:
228
+ flow_content += f"{space} result_dict = {{\n"
229
+ flow_content += f"{space} 'index': index,\n"
230
+ flow_content += f"{space} 'messages': result.messages,\n"
231
+ flow_content += f"{space} 'summary': result.summary,\n"
232
+ flow_content += f"{space} 'cost': result.cost.model_dump(mode='json', fallback=str) if result.cost else None,\n"
233
+ flow_content += f"{space} 'context_variables': result.context_variables.model_dump(mode='json', fallback=str) if result.context_variables else None,\n"
234
+ flow_content += f"{space} 'last_speaker': result.last_speaker,\n"
235
+ flow_content += f"{space} 'uuid': str(result.uuid),\n"
236
+ flow_content += f"{space} }}\n"
237
+ else:
238
+ flow_content += f"{space} result_dict = {{\n"
239
+ flow_content += f"{space} 'index': index,\n"
240
+ flow_content += f"{space} 'messages': await result.messages,\n"
241
+ flow_content += f"{space} 'summary': await result.summary,\n"
242
+ flow_content += f"{space} 'cost': (await result.cost).model_dump(mode='json', fallback=str) if await result.cost else None,\n"
243
+ flow_content += f"{space} 'context_variables': (await result.context_variables).model_dump(mode='json', fallback=str) if await result.context_variables else None,\n"
244
+ flow_content += (
245
+ f"{space} 'last_speaker': await result.last_speaker,\n"
246
+ )
247
+ flow_content += f"{space} 'uuid': str(result.uuid),\n"
248
+ flow_content += f"{space} }}\n"
249
+ flow_content += f"{space} result_dicts.append(result_dict)\n"
250
+ return flow_content
@@ -102,29 +102,21 @@ Tags: {", ".join(tags)}
102
102
  """'''
103
103
 
104
104
 
105
- def main_doc_string(is_async: bool) -> str:
105
+ def main_doc_string() -> str:
106
106
  """Generate the docstring for the main function.
107
107
 
108
- Parameters
109
- ----------
110
- is_async : bool
111
- Whether the main function is asynchronous.
112
-
113
108
  Returns
114
109
  -------
115
110
  str
116
111
  The docstring for the main function.
117
112
  """
118
- return_type_hint = (
119
- "AsyncRunResponseProtocol" if is_async else "RunResponseProtocol"
120
- )
113
+ return_type_hint = "list[dict[str, Any]]"
121
114
  return f'''"""Start chatting.
122
115
 
123
116
  Returns
124
117
  -------
125
118
  {return_type_hint}
126
- The result of the chat session, which can be a single ChatResult,
127
- a list of ChatResults, or a dictionary mapping integers to ChatResults.
119
+ The result of the chat session.
128
120
 
129
121
  Raises
130
122
  ------
@@ -193,6 +185,7 @@ def get_common_env_var_setup() -> str:
193
185
  """
194
186
  content = """
195
187
  # Common environment variable setup for Waldiez flows
188
+ load_dotenv(override=True)
196
189
  os.environ["AUTOGEN_USE_DOCKER"] = "0"
197
190
  os.environ["ANONYMIZED_TELEMETRY"] = "False"
198
191
  """
@@ -100,7 +100,8 @@ def sort_imports(
100
100
  third_party_imports.append(import_string)
101
101
  elif position == ImportPosition.LOCAL: # pragma: no branch
102
102
  local_imports.append(import_string)
103
-
103
+ if "from dotenv import load_dotenv" not in third_party_imports:
104
+ third_party_imports.append("from dotenv import load_dotenv")
104
105
  autogen_imports = clean_and_group_autogen_imports(autogen_imports)
105
106
  third_party_imports = ensure_np_import(third_party_imports)
106
107
  sorted_builtins = get_sorted_imports(builtin_imports)
@@ -186,7 +186,8 @@ class ModelsExporter(Exporter[ModelExtras]):
186
186
  for_notebook=self.config.for_notebook,
187
187
  )
188
188
  loader_script = f'''{comment}# NOTE:
189
- # This section assumes that a file named "{self.flow_name}_api_keys"
189
+ # This section assumes that a file named:
190
+ # "{self.flow_name}_api_keys.py"
190
191
  # exists in the same directory as this file.
191
192
  # This file contains the API keys for the models used in this flow.
192
193
  # It should be .gitignored and not shared publicly.
@@ -176,7 +176,8 @@ class ToolsExporter(Exporter[ToolExtras]):
176
176
  for_notebook=self.config.for_notebook,
177
177
  )
178
178
  loader_script = f'''{comment}# NOTE:
179
- # This section assumes that a file named "{self.flow_name}_{tool_name}_secrets"
179
+ # This section assumes that a file named:
180
+ # "{self.flow_name}_{tool_name}_secrets.py"
180
181
  # exists in the same directory as this file.
181
182
  # This file contains the secrets for the tool used in this flow.
182
183
  # It should be .gitignored and not shared publicly.
@@ -192,7 +192,12 @@ ag2_{tool_name} = ag2_{tool_name}_interop.convert_tool(
192
192
  )
193
193
  f.write("import os\n\n")
194
194
  for key, value in tool.secrets.items():
195
- f.write(f'os.environ["{key}"] = "{value}"\n')
195
+ # f.write(f'os.environ["{key}"] = "{value}"\n')
196
+ # check first if the key already exists in os.environ
197
+ f.write(
198
+ f'os.environ["{key}"] = '
199
+ f'os.environ.get("{key}", "{value}")\n'
200
+ )
196
201
  except Exception as exc: # pragma: no cover
197
202
  raise ExporterContentError(
198
203
  f"Failed to write secrets file for tool '{tool_name}': {exc}"
@@ -338,11 +338,11 @@ def set_bedrock_aws_config(
338
338
  value = getattr(aws_config, param, "") if aws_config else ""
339
339
 
340
340
  # If not found, try environment variable
341
- if not value: # pragma: no cover
341
+ if not value or value == "REPLACE_ME": # pragma: no cover
342
342
  value = os.environ.get(env_var, "")
343
343
 
344
344
  # Add to extra_args if value exists
345
- if value: # pragma: no branch
345
+ if value and value != "REPLACE_ME": # pragma: no branch
346
346
  extra_args[config_key] = value
347
347
 
348
348
  # Update llm_config with extra_args
@@ -16,10 +16,9 @@ class GoogleSearchToolImpl(PredefinedTool):
16
16
 
17
17
  required_secrets: list[str] = [
18
18
  "GOOGLE_SEARCH_API_KEY",
19
+ "GOOGLE_SEARCH_ENGINE_ID",
19
20
  ]
20
- required_kwargs: dict[str, type] = {
21
- "google_search_engine_id": str,
22
- }
21
+ required_kwargs: dict[str, type] = {}
23
22
  _kwargs: dict[str, Any] = {}
24
23
 
25
24
  @property
@@ -138,25 +137,15 @@ class GoogleSearchToolImpl(PredefinedTool):
138
137
  str
139
138
  The content for the tool.
140
139
  """
141
- os.environ["GOOGLE_SEARCH_API_KEY"] = secrets.get(
142
- "GOOGLE_SEARCH_API_KEY", ""
143
- )
144
- google_search_engine_id = self.google_search_engine_id
145
- if not google_search_engine_id:
146
- google_search_engine_id = secrets.get("GOOGLE_SEARCH_ENGINE_ID", "")
147
140
  content = f'''
148
141
  def {self.name}(
149
142
  query: str,
150
- search_api_key: str,
151
- search_engine_id: str,
152
143
  num_results: int = 10,
153
144
  ) -> list[dict[str, Any]]:
154
145
  """Perform a Google search and return formatted results.
155
146
 
156
147
  Args:
157
148
  query: The search query string.
158
- search_api_key: The API key for the Google Search API.
159
- search_engine_id: The search engine ID for the Google Search API.
160
149
  num_results: The maximum number of results to return. Defaults to 10.
161
150
  Returns:
162
151
  A list of dictionaries of the search results.
@@ -164,14 +153,17 @@ def {self.name}(
164
153
  google_search_api_key = os.environ.get("GOOGLE_SEARCH_API_KEY", "")
165
154
  if not google_search_api_key:
166
155
  raise ValueError("GOOGLE_SEARCH_API_KEY is required for Google search tool.")
156
+ google_search_engine_id = os.environ.get("GOOGLE_SEARCH_ENGINE_ID", "")
157
+ if not google_search_engine_id:
158
+ raise ValueError("Google Search Engine ID is required for Google search tool.")
167
159
  {self.name}_tool = GoogleSearchTool(
168
160
  search_api_key=google_search_api_key,
169
- search_engine_id="{google_search_engine_id}",
161
+ search_engine_id=google_search_engine_id,
170
162
  )
171
163
  return {self.name}_tool(
172
164
  query=query,
173
- search_api_key=search_api_key,
174
- search_engine_id=search_engine_id,
165
+ search_api_key=google_search_api_key,
166
+ search_engine_id=google_search_engine_id,
175
167
  num_results=num_results
176
168
  )
177
169
  '''
@@ -4,7 +4,6 @@
4
4
  # flake8: noqa: E501
5
5
  """Predefined Perplexity AI search tool for Waldiez."""
6
6
 
7
- import os
8
7
  from typing import Any
9
8
 
10
9
  from ._config import PredefinedToolConfig
@@ -120,21 +119,23 @@ class PerplexitySearchToolImpl(PredefinedTool):
120
119
  str
121
120
  Content retrieved by the tool.
122
121
  """
123
- os.environ["PERPLEXITY_API_KEY"] = secrets.get("PERPLEXITY_API_KEY", "")
122
+ model = self.kwargs["model"]
123
+ max_tokens = self.kwargs["max_tokens"]
124
+ search_domain_filter = self.kwargs["search_domain_filter"]
124
125
  content = f'''
125
126
  def {self.name}(
126
127
  query: str,
127
- model: str = "{self.kwargs["model"]}",
128
- max_tokens: int = {self.kwargs["max_tokens"]},
129
- search_domain_filter: Optional[list[str]] = {self.kwargs["search_domain_filter"]},
128
+ model: str = "{model}",
129
+ max_tokens: int = {max_tokens},
130
+ search_domain_filter: Optional[list[str]] = {search_domain_filter},
130
131
  ) -> "SearchResponse":
131
132
  """Perform a Perplexity AI search and return formatted results.
132
133
 
133
134
  Args:
134
135
  query: The search query string.
135
- model: The model to use for the search. Defaults to "{self.kwargs["model"]}".
136
- max_tokens: The maximum number of tokens to return. Defaults to {self.kwargs["max_tokens"]}.
137
- search_domain_filter: List of domain filters for the search. Defaults to {self.kwargs["search_domain_filter"]}.
136
+ model: The model to use for the search. Defaults to "{model}".
137
+ max_tokens: The maximum number of tokens to return. Defaults to {max_tokens}.
138
+ search_domain_filter: List of domain filters for the search. Defaults to {search_domain_filter}.
138
139
  Returns:
139
140
  A list of dictionaries of the search results.
140
141
  """
@@ -4,7 +4,6 @@
4
4
  # flake8: noqa: E501
5
5
  """Predefined Tavily search tool for Waldiez."""
6
6
 
7
- import os
8
7
  from typing import Any
9
8
 
10
9
  from ._config import PredefinedToolConfig
@@ -98,13 +97,9 @@ class TavilySearchToolImpl(PredefinedTool):
98
97
  str
99
98
  The content for the tool.
100
99
  """
101
- os.environ["TAVILY_API_KEY"] = secrets.get(
102
- "TAVILY_API_KEY", os.environ.get("TAVILY_API_KEY", "")
103
- )
104
100
  content = f'''
105
101
  def {self.name}(
106
102
  query: str,
107
- tavily_api_key: str = os.environ.get("TAVILY_API_KEY", ""),
108
103
  search_depth: str = "basic",
109
104
  topic: str = "general",
110
105
  include_answer: str = "basic",
@@ -116,7 +111,6 @@ def {self.name}(
116
111
 
117
112
  Args:
118
113
  query: The search query string.
119
- tavily_api_key: The API key for Tavily (injected dependency).
120
114
  search_depth: The depth of the search ('basic' or 'advanced'). Defaults to "basic".
121
115
  include_answer: Whether to include an AI-generated answer ('basic' or 'advanced'). Defaults to "basic".
122
116
  include_raw_content: Whether to include raw content in the results. Defaults to False.
@@ -4,7 +4,6 @@
4
4
  # flake8: noqa: E501
5
5
  """Predefined YouTube search tool for Waldiez."""
6
6
 
7
- import os
8
7
  from typing import Any
9
8
 
10
9
  from ._config import PredefinedToolConfig
@@ -101,11 +100,9 @@ class YouTubeSearchToolImpl(PredefinedTool):
101
100
  str
102
101
  The content for the tool.
103
102
  """
104
- os.environ["YOUTUBE_API_KEY"] = secrets.get("YOUTUBE_API_KEY", "")
105
103
  content = f'''
106
104
  def {self.name}(
107
105
  query: str,
108
- youtube_api_key: str = os.environ.get("YOUTUBE_API_KEY", ""),
109
106
  max_results: int = 5,
110
107
  include_video_details: bool = True,
111
108
  ) -> list[dict[str, Any]]:
@@ -113,7 +110,6 @@ def {self.name}(
113
110
 
114
111
  Args:
115
112
  query: The search query string.
116
- youtube_api_key: The API key for the YouTube Data API.
117
113
  max_results: The maximum number of results to return. Defaults to 5.
118
114
  include_video_details: Whether to include detailed video information. Defaults to True.
119
115
 
waldiez/runner.py CHANGED
@@ -14,7 +14,7 @@ variables specified in the waldiez file are set.
14
14
  """
15
15
 
16
16
  from pathlib import Path
17
- from typing import TYPE_CHECKING, Any, Union
17
+ from typing import Any
18
18
 
19
19
  from typing_extensions import Literal
20
20
 
@@ -24,12 +24,6 @@ from .running import (
24
24
  WaldiezStandardRunner,
25
25
  )
26
26
 
27
- if TYPE_CHECKING:
28
- from autogen.io.run_response import ( # type: ignore[import-untyped]
29
- AsyncRunResponseProtocol,
30
- RunResponseProtocol,
31
- )
32
-
33
27
 
34
28
  def create_runner(
35
29
  waldiez: Waldiez,
@@ -38,6 +32,7 @@ def create_runner(
38
32
  output_path: str | Path | None = None,
39
33
  uploads_root: str | Path | None = None,
40
34
  structured_io: bool = False,
35
+ dot_env: str | Path | None = None,
41
36
  **kwargs: Any,
42
37
  ) -> WaldiezBaseRunner:
43
38
  """Create a Waldiez runner of the specified type.
@@ -54,6 +49,8 @@ def create_runner(
54
49
  Uploads root directory, by default None
55
50
  structured_io : bool, optional
56
51
  Use structured I/O, by default False
52
+ dot_env : str | Path | None, optional
53
+ Path to a .env file for environment variables, by default None
57
54
  **kwargs
58
55
  Additional arguments for specific runner types
59
56
 
@@ -84,6 +81,7 @@ def create_runner(
84
81
  output_path=output_path,
85
82
  uploads_root=uploads_root,
86
83
  structured_io=structured_io,
84
+ dot_env=dot_env,
87
85
  **kwargs,
88
86
  )
89
87
 
@@ -101,6 +99,7 @@ class WaldiezRunner(WaldiezBaseRunner):
101
99
  output_path: str | Path | None = None,
102
100
  uploads_root: str | Path | None = None,
103
101
  structured_io: bool = False,
102
+ dot_env: str | Path | None = None,
104
103
  **kwargs: Any,
105
104
  ):
106
105
  """Create a runner instance.
@@ -117,9 +116,10 @@ class WaldiezRunner(WaldiezBaseRunner):
117
116
  Uploads root directory, by default None
118
117
  structured_io : bool, optional
119
118
  Use structured I/O, by default False
119
+ dot_env : str | Path | None, optional
120
+ Path to a .env file for environment variables, by default None
120
121
  **kwargs
121
122
  Additional arguments for specific runner types
122
-
123
123
  """
124
124
  self._runner = create_runner(
125
125
  waldiez=waldiez,
@@ -127,6 +127,7 @@ class WaldiezRunner(WaldiezBaseRunner):
127
127
  output_path=output_path,
128
128
  uploads_root=uploads_root,
129
129
  structured_io=structured_io,
130
+ dot_env=dot_env,
130
131
  **kwargs,
131
132
  )
132
133
 
@@ -165,10 +166,7 @@ class WaldiezRunner(WaldiezBaseRunner):
165
166
  skip_mmd: bool,
166
167
  skip_timeline: bool,
167
168
  **kwargs: Any,
168
- ) -> Union[
169
- list["RunResponseProtocol"],
170
- list["AsyncRunResponseProtocol"],
171
- ]:
169
+ ) -> list[dict[str, Any]]:
172
170
  return self._runner._run(
173
171
  temp_dir=temp_dir,
174
172
  output_file=output_file,
@@ -205,14 +203,16 @@ class WaldiezRunner(WaldiezBaseRunner):
205
203
  uploads_root: Path | None,
206
204
  skip_mmd: bool,
207
205
  skip_timeline: bool,
206
+ dot_env: str | Path | None = None,
208
207
  **kwargs: Any,
209
- ) -> Union[list["RunResponseProtocol"], list["AsyncRunResponseProtocol"]]:
208
+ ) -> list[dict[str, Any]]:
210
209
  return await self._runner._a_run(
211
210
  temp_dir=temp_dir,
212
211
  output_file=output_file,
213
212
  uploads_root=uploads_root,
214
213
  skip_mmd=skip_mmd,
215
214
  skip_timeline=skip_timeline,
215
+ dot_env=dot_env,
216
216
  **kwargs,
217
217
  )
218
218
 
@@ -246,6 +246,7 @@ class WaldiezRunner(WaldiezBaseRunner):
246
246
  output_path: str | Path | None = None,
247
247
  uploads_root: str | Path | None = None,
248
248
  structured_io: bool = False,
249
+ dot_env: str | Path | None = None,
249
250
  **kwargs: Any,
250
251
  ) -> "WaldiezRunner":
251
252
  """Load a waldiez flow and create a runner.
@@ -268,6 +269,8 @@ class WaldiezRunner(WaldiezBaseRunner):
268
269
  Uploads root directory, by default None
269
270
  structured_io : bool, optional
270
271
  Use structured I/O, by default False
272
+ dot_env : str | Path | None, optional
273
+ Path to a .env file for environment variables, by default None
271
274
  **kwargs
272
275
  Additional arguments for specific runner types
273
276
 
@@ -295,5 +298,6 @@ class WaldiezRunner(WaldiezBaseRunner):
295
298
  output_path=output_path,
296
299
  uploads_root=uploads_root,
297
300
  structured_io=structured_io,
301
+ dot_env=dot_env,
298
302
  **kwargs,
299
303
  )