agently 4.0.5.3__tar.gz → 4.0.5.5__tar.gz

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.
Files changed (75) hide show
  1. {agently-4.0.5.3 → agently-4.0.5.5}/PKG-INFO +1 -1
  2. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/plugins/ModelRequester/OpenAICompatible.py +89 -26
  3. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/Agent.py +15 -1
  4. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/Prompt.py +1 -1
  5. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/data/prompt.py +2 -0
  6. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/DataFormatter.py +67 -9
  7. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/RuntimeData.py +1 -1
  8. {agently-4.0.5.3 → agently-4.0.5.5}/pyproject.toml +1 -1
  9. {agently-4.0.5.3 → agently-4.0.5.5}/LICENSE +0 -0
  10. {agently-4.0.5.3 → agently-4.0.5.5}/README.md +0 -0
  11. {agently-4.0.5.3 → agently-4.0.5.5}/agently/__init__.py +0 -0
  12. {agently-4.0.5.3 → agently-4.0.5.5}/agently/_default_init.py +0 -0
  13. {agently-4.0.5.3 → agently-4.0.5.5}/agently/_default_settings.yaml +0 -0
  14. {agently-4.0.5.3 → agently-4.0.5.5}/agently/base.py +0 -0
  15. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/agent_extensions/AutoFuncExtension.py +0 -0
  16. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/agent_extensions/ChatSessionExtension.py +0 -0
  17. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/agent_extensions/ConfigurePromptExtension.py +0 -0
  18. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/agent_extensions/KeyWaiterExtension.py +0 -0
  19. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/agent_extensions/ToolExtension.py +0 -0
  20. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/agent_extensions/__init__.py +0 -0
  21. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/hookers/ConsoleHooker.py +0 -0
  22. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/hookers/PureLoggerHooker.py +0 -0
  23. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/hookers/SystemMessageHooker.py +0 -0
  24. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/plugins/PromptGenerator/AgentlyPromptGenerator.py +0 -0
  25. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/plugins/ResponseParser/AgentlyResponseParser.py +0 -0
  26. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/plugins/ToolManager/AgentlyToolManager.py +0 -0
  27. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/plugins/__init__.py +0 -0
  28. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/tools/Browse.py +0 -0
  29. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/tools/Search.py +0 -0
  30. {agently-4.0.5.3 → agently-4.0.5.5}/agently/builtins/tools/__init__.py +0 -0
  31. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/EventCenter.py +0 -0
  32. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/ExtensionHandlers.py +0 -0
  33. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/ModelRequest.py +0 -0
  34. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/PluginManager.py +0 -0
  35. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/Tool.py +0 -0
  36. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/TriggerFlow/BluePrint.py +0 -0
  37. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/TriggerFlow/Chunk.py +0 -0
  38. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/TriggerFlow/Execution.py +0 -0
  39. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/TriggerFlow/Process.py +0 -0
  40. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/TriggerFlow/TriggerFlow.py +0 -0
  41. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/TriggerFlow/__init__.py +0 -0
  42. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/TriggerFlow/process/BaseProcess.py +0 -0
  43. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/TriggerFlow/process/ForEachProcess.py +0 -0
  44. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/TriggerFlow/process/MatchCaseProcess.py +0 -0
  45. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/TriggerFlow/process/__init__.py +0 -0
  46. {agently-4.0.5.3 → agently-4.0.5.5}/agently/core/__init__.py +0 -0
  47. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/__init__.py +0 -0
  48. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/data/__init__.py +0 -0
  49. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/data/event.py +0 -0
  50. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/data/request.py +0 -0
  51. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/data/response.py +0 -0
  52. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/data/serializable.py +0 -0
  53. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/data/tool.py +0 -0
  54. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/plugins/EventHooker.py +0 -0
  55. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/plugins/ModelRequester.py +0 -0
  56. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/plugins/PromptGenerator.py +0 -0
  57. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/plugins/ResponseParser.py +0 -0
  58. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/plugins/ToolManager.py +0 -0
  59. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/plugins/__init__.py +0 -0
  60. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/plugins/base.py +0 -0
  61. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/trigger_flow/__init__.py +0 -0
  62. {agently-4.0.5.3 → agently-4.0.5.5}/agently/types/trigger_flow/trigger_flow.py +0 -0
  63. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/DataLocator.py +0 -0
  64. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/DataPathBuilder.py +0 -0
  65. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/FunctionShifter.py +0 -0
  66. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/GeneratorConsumer.py +0 -0
  67. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/LazyImport.py +0 -0
  68. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/Logger.py +0 -0
  69. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/Messenger.py +0 -0
  70. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/SerializableRuntimeData.py +0 -0
  71. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/Settings.py +0 -0
  72. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/Storage.py +0 -0
  73. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/StreamingJSONCompleter.py +0 -0
  74. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/StreamingJSONParser.py +0 -0
  75. {agently-4.0.5.3 → agently-4.0.5.5}/agently/utils/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agently
3
- Version: 4.0.5.3
3
+ Version: 4.0.5.5
4
4
  Summary:
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -84,6 +84,8 @@ class OpenAICompatible(ModelRequester):
84
84
  "$mappings": {
85
85
  "path_mappings": {
86
86
  "OpenAICompatible": "plugins.ModelRequester.OpenAICompatible",
87
+ "OpenAI": "plugins.ModelRequester.OpenAICompatible",
88
+ "OAIClient": "plugins.ModelRequester.OpenAICompatible",
87
89
  },
88
90
  },
89
91
  "model_type": "chat",
@@ -98,6 +100,7 @@ class OpenAICompatible(ModelRequester):
98
100
  "proxy": None,
99
101
  "request_options": {},
100
102
  "base_url": "https://api.openai.com/v1",
103
+ "full_url": None,
101
104
  "path_mapping": {
102
105
  "chat": "/chat/completions",
103
106
  "completions": "/completions",
@@ -200,17 +203,17 @@ class OpenAICompatible(ModelRequester):
200
203
  agently_request_dict["data"] = request_data
201
204
 
202
205
  # headers
203
- headers = DataFormatter.to_str_key_dict(
206
+ headers: dict[str, str] = DataFormatter.to_str_key_dict(
204
207
  self.plugin_settings.get("headers"),
205
208
  value_format="str",
206
- default={},
209
+ default_value={},
207
210
  )
208
211
  headers.update({"Connection": "close"})
209
212
  ## set
210
213
  agently_request_dict["headers"] = headers
211
214
 
212
215
  # client options
213
- client_options = DataFormatter.to_str_key_dict(self.plugin_settings.get("client_options"))
216
+ client_options = DataFormatter.to_str_key_dict(self.plugin_settings.get("client_options"), default_value={})
214
217
  ## proxy
215
218
  proxy = self.plugin_settings.get("proxy", None)
216
219
  if proxy:
@@ -225,7 +228,8 @@ class OpenAICompatible(ModelRequester):
225
228
  "write": 30.0,
226
229
  "pool": 30.0,
227
230
  },
228
- )
231
+ ),
232
+ default_value={},
229
233
  )
230
234
  timeout = Timeout(**timeout_configs)
231
235
  client_options.update({"timeout": timeout})
@@ -236,7 +240,16 @@ class OpenAICompatible(ModelRequester):
236
240
  request_options = DataFormatter.to_str_key_dict(
237
241
  self.plugin_settings.get("request_options"),
238
242
  value_format="serializable",
243
+ default_value={},
239
244
  )
245
+ request_options_in_prompt = self.prompt.get("options", {})
246
+ if request_options_in_prompt:
247
+ request_options.update(request_options_in_prompt)
248
+ request_options = DataFormatter.to_str_key_dict(
249
+ request_options,
250
+ value_format="serializable",
251
+ default_value={},
252
+ )
240
253
  ## !: ensure model
241
254
  request_options.update(
242
255
  {
@@ -245,18 +258,22 @@ class OpenAICompatible(ModelRequester):
245
258
  DataFormatter.to_str_key_dict(
246
259
  self.plugin_settings.get("default_model"),
247
260
  value_format="serializable",
248
- default={self.model_type: self.plugin_settings.get("default_model")},
261
+ default_key=self.model_type,
249
262
  )[self.model_type],
250
263
  )
251
264
  }
252
265
  )
253
266
  ## !: ensure stream
254
- is_stream = self.plugin_settings.get("stream", True)
267
+ is_stream = self.plugin_settings.get("stream")
268
+ if is_stream is None:
269
+ is_stream = True
255
270
  request_options.update({"stream": is_stream})
256
271
  ## set
257
272
  agently_request_dict["request_options"] = request_options
258
273
 
259
274
  # request url
275
+ ## get full url
276
+ full_url = self.plugin_settings.get("full_url")
260
277
  ## get base url
261
278
  base_url = str(self.plugin_settings.get("base_url"))
262
279
  base_url = base_url[:-1] if base_url[-1] == "/" else base_url
@@ -264,10 +281,14 @@ class OpenAICompatible(ModelRequester):
264
281
  path_mapping = DataFormatter.to_str_key_dict(
265
282
  self.plugin_settings.get("path_mapping"),
266
283
  value_format="str",
284
+ default_value={},
267
285
  )
268
286
  path_mapping = {k: v if v[0] == "/" else f"/{ v }" for k, v in path_mapping.items()}
269
287
  ## set
270
- request_url = f"{ base_url }{ path_mapping[self.model_type] }"
288
+ if isinstance(full_url, str):
289
+ request_url = full_url
290
+ else:
291
+ request_url = f"{ base_url }{ path_mapping[self.model_type] }"
271
292
  agently_request_dict["request_url"] = request_url
272
293
 
273
294
  return AgentlyRequestData(**agently_request_dict)
@@ -309,16 +330,31 @@ class OpenAICompatible(ModelRequester):
309
330
  auth = DataFormatter.to_str_key_dict(
310
331
  self.plugin_settings.get("auth", "None"),
311
332
  value_format="serializable",
312
- default={"api_key": self.plugin_settings.get("auth", "None")},
333
+ default_key="api_key",
313
334
  )
314
- headers_with_auth = {**request_data.headers, "Authorization": f"Bearer { auth['api_key'] }"}
335
+ api_key = self.plugin_settings.get("api_key", None)
336
+ if api_key is not None and auth["api_key"] == "None":
337
+ auth["api_key"] = str(api_key)
338
+ if "api_key" in auth:
339
+ headers_with_auth = {**request_data.headers, "Authorization": f"Bearer { auth['api_key'] }"}
340
+ elif "headers" in auth and isinstance(auth["headers"], dict):
341
+ headers_with_auth = {**request_data.headers, **auth["headers"]}
342
+ elif "body" in auth and isinstance(auth["body"], dict):
343
+ headers_with_auth = request_data.headers.copy()
344
+ request_data.data.update(**auth["body"])
345
+ else:
346
+ headers_with_auth = request_data.headers.copy()
315
347
 
316
348
  # request
317
349
  # stream request
318
350
  if self.model_type in ("chat", "completions") and request_data.stream:
319
351
  async with AsyncClient(**request_data.client_options) as client:
320
352
  client.headers.update(headers_with_auth)
321
- full_request_data = DataFormatter.to_str_key_dict(request_data.data, value_format="serializable")
353
+ full_request_data = DataFormatter.to_str_key_dict(
354
+ request_data.data,
355
+ value_format="serializable",
356
+ default_value={},
357
+ )
322
358
  full_request_data.update(request_data.request_options)
323
359
  try:
324
360
  async for sse in await self._aiter_sse_with_retry(
@@ -331,22 +367,34 @@ class OpenAICompatible(ModelRequester):
331
367
  json=full_request_data,
332
368
  headers=headers_with_auth,
333
369
  )
334
- content_type = response.headers.get("Content-Type", "")
335
- if content_type.startswith("application/json"):
336
- try:
337
- error_json = response.json()
338
- except Exception:
339
- error_json = await response.aread()
340
- error_json = json.loads(error_json.decode())
341
- error = error_json["error"]
342
- error_title = f"{ error['code'] if 'code' in error else 'unknown_code' } - { error['type'] if 'type' in error else 'unknown_type' }"
343
- error_detail = error["message"] if "message" in error else ""
344
- yield "error", error_detail
345
- else:
370
+ # Raise status code >= 400
371
+ if response.status_code >= 400:
372
+ e = RequestError(
373
+ f"Status Code: { response.status_code }\n" f"Request Data: {full_request_data}"
374
+ )
346
375
  self._messenger.error(
347
- "Error: SSE Error\n" f"Detail: {e}\n" f"Request Data: {full_request_data}", status="FAILED"
376
+ e,
377
+ status="FAILED",
348
378
  )
349
379
  yield "error", e
380
+ else:
381
+ content_type = response.headers.get("Content-Type", "")
382
+ if content_type.startswith("application/json"):
383
+ try:
384
+ error_json = response.json()
385
+ except Exception:
386
+ error_json = await response.aread()
387
+ error_json = json.loads(error_json.decode())
388
+ error = error_json["error"]
389
+ error_title = f"{ error['code'] if 'code' in error else 'unknown_code' } - { error['type'] if 'type' in error else 'unknown_type' }"
390
+ error_detail = error["message"] if "message" in error else ""
391
+ yield "error", error_detail
392
+ else:
393
+ self._messenger.error(
394
+ "Error: SSE Error\n" f"Detail: {e}\n" f"Request Data: {full_request_data}",
395
+ status="FAILED",
396
+ )
397
+ yield "error", e
350
398
  except HTTPStatusError as e:
351
399
  self._messenger.error(
352
400
  "Error: HTTP Status Error\n"
@@ -373,15 +421,29 @@ class OpenAICompatible(ModelRequester):
373
421
  else:
374
422
  async with AsyncClient(**request_data.client_options) as client:
375
423
  client.headers.update(headers_with_auth)
376
- full_request_data = DataFormatter.to_str_key_dict(request_data.data, value_format="serializable")
424
+ full_request_data = DataFormatter.to_str_key_dict(
425
+ request_data.data,
426
+ value_format="serializable",
427
+ default_value={},
428
+ )
377
429
  full_request_data.update(request_data.request_options)
378
430
  try:
379
431
  response = await client.post(
380
432
  request_data.request_url,
381
433
  json=full_request_data,
382
434
  )
383
- yield "message", response.content.decode()
384
- yield "message", "[DONE]"
435
+ if response.status_code >= 400:
436
+ e = RequestError(
437
+ f"Status Code: { response.status_code }\n" f"Request Data: {full_request_data}"
438
+ )
439
+ self._messenger.error(
440
+ e,
441
+ status="FAILED",
442
+ )
443
+ yield "error", e
444
+ else:
445
+ yield "message", response.content.decode()
446
+ yield "message", "[DONE]"
385
447
  except HTTPStatusError as e:
386
448
  self._messenger.error(
387
449
  "Error: HTTP Status Error\n"
@@ -450,6 +512,7 @@ class OpenAICompatible(ModelRequester):
450
512
  loaded_message,
451
513
  role_mapping,
452
514
  style=content_mapping_style,
515
+ default="assistant",
453
516
  )
454
517
  if role:
455
518
  meta.update({"role": role})
@@ -110,7 +110,7 @@ class BaseAgent:
110
110
 
111
111
  def reset_chat_history(self):
112
112
  if "chat_history" in self.prompt:
113
- del self.prompt["chat_history"]
113
+ self.prompt.set("chat_history", [])
114
114
  return self
115
115
 
116
116
  def set_chat_history(self, chat_history: "list[dict[str, Any] | ChatMessage]"):
@@ -121,6 +121,8 @@ class BaseAgent:
121
121
  return self
122
122
 
123
123
  def add_chat_history(self, chat_history: "list[dict[str, Any] | ChatMessage] | dict[str, Any] | ChatMessage"):
124
+ if not isinstance(chat_history, list):
125
+ chat_history = [chat_history]
124
126
  self.prompt.set("chat_history", chat_history)
125
127
  return self
126
128
 
@@ -252,3 +254,15 @@ class BaseAgent:
252
254
  else:
253
255
  self.request.prompt.set("output", prompt, mappings)
254
256
  return self
257
+
258
+ def options(
259
+ self,
260
+ options: dict[str, Any],
261
+ *,
262
+ always: bool = False,
263
+ ):
264
+ if always:
265
+ self.prompt.set("options", options)
266
+ else:
267
+ self.request.prompt.set("options", options)
268
+ return self
@@ -191,5 +191,5 @@ class Prompt(RuntimeData):
191
191
  else:
192
192
  super().append(key, value)
193
193
 
194
- def get(self, key: "PromptStandardSlot | None" = None, default: Any | None = None, inherit: bool = True):
194
+ def get(self, key: "PromptStandardSlot | None" = None, default: T = None, inherit: bool = True) -> Any | T:
195
195
  return super().get(key, default=default, inherit=inherit)
@@ -122,6 +122,7 @@ PromptStandardSlot = Literal[
122
122
  "attachment",
123
123
  "output",
124
124
  "output_format",
125
+ "options",
125
126
  ]
126
127
 
127
128
 
@@ -144,6 +145,7 @@ class PromptModel(BaseModel):
144
145
  attachment: Annotated[list[ChatMessageContent], PlainValidator(validate_attachment)] = []
145
146
  output: Any = None
146
147
  output_format: OutputFormat | Any = None
148
+ options: dict[str, Any] = {}
147
149
 
148
150
  model_config = ConfigDict(extra="allow")
149
151
 
@@ -23,12 +23,15 @@ from typing import (
23
23
  get_args,
24
24
  overload,
25
25
  TYPE_CHECKING,
26
+ TypeVar,
26
27
  )
27
28
  from pydantic import BaseModel
28
29
 
29
30
  if TYPE_CHECKING:
30
31
  from agently.types.data import SerializableValue, KwargsType
31
32
 
33
+ T = TypeVar("T")
34
+
32
35
 
33
36
  class DataFormatter:
34
37
  @staticmethod
@@ -101,9 +104,10 @@ class DataFormatter:
101
104
  value: Any,
102
105
  *,
103
106
  value_format: None = None,
104
- default: dict[str, Any] | None = None,
107
+ default_key: str,
108
+ default_value: T = None,
105
109
  inconvertible_warning: bool = False,
106
- ) -> dict[str, Any]: ...
110
+ ) -> dict[str, Any | T]: ...
107
111
 
108
112
  @overload
109
113
  @staticmethod
@@ -111,9 +115,10 @@ class DataFormatter:
111
115
  value: Any,
112
116
  *,
113
117
  value_format: Literal["serializable"],
114
- default: dict[str, "SerializableValue"] | None = None,
118
+ default_key: str,
119
+ default_value: T = None,
115
120
  inconvertible_warning: bool = False,
116
- ) -> dict[str, "SerializableValue"]: ...
121
+ ) -> dict[str, "SerializableValue" | T]: ...
117
122
 
118
123
  @overload
119
124
  @staticmethod
@@ -121,18 +126,64 @@ class DataFormatter:
121
126
  value: Any,
122
127
  *,
123
128
  value_format: Literal["str"],
124
- default: dict[str, str] | None = None,
129
+ default_key: str,
130
+ default_value: T = None,
125
131
  inconvertible_warning: bool = False,
126
- ) -> dict[str, str]: ...
132
+ ) -> dict[str, str | T]: ...
133
+
134
+ @overload
135
+ @staticmethod
136
+ def to_str_key_dict(
137
+ value: Any,
138
+ *,
139
+ value_format: None = None,
140
+ default_key: None,
141
+ default_value: T = None,
142
+ inconvertible_warning: bool = False,
143
+ ) -> dict[str, Any] | T: ...
144
+
145
+ @overload
146
+ @staticmethod
147
+ def to_str_key_dict(
148
+ value: Any,
149
+ *,
150
+ value_format: Literal["serializable"],
151
+ default_key: None,
152
+ default_value: T = None,
153
+ inconvertible_warning: bool = False,
154
+ ) -> dict[str, "SerializableValue"] | T: ...
155
+
156
+ @overload
157
+ @staticmethod
158
+ def to_str_key_dict(
159
+ value: Any,
160
+ *,
161
+ value_format: Literal["str"],
162
+ default_key: None,
163
+ default_value: T = None,
164
+ inconvertible_warning: bool = False,
165
+ ) -> dict[str, str | T] | T: ...
166
+
167
+ @overload
168
+ @staticmethod
169
+ def to_str_key_dict(
170
+ value: Any,
171
+ *,
172
+ value_format: Literal['serializable', 'str'] | None = None,
173
+ default_key: str | None = None,
174
+ default_value: T = None,
175
+ inconvertible_warning: bool = False,
176
+ ) -> dict[str, Any] | T: ...
127
177
 
128
178
  @staticmethod
129
179
  def to_str_key_dict(
130
180
  value: Any,
131
181
  *,
132
182
  value_format: Literal["serializable", "str"] | None = None,
133
- default: dict[str, Any] | None = None,
183
+ default_key: str | None = None,
184
+ default_value: T = None,
134
185
  inconvertible_warning: bool = False,
135
- ):
186
+ ) -> dict[str, Any] | T:
136
187
  if isinstance(value, Mapping):
137
188
  if value_format is None:
138
189
  return {str(DataFormatter.sanitize(k)): v for k, v in value.items()}
@@ -147,7 +198,14 @@ class DataFormatter:
147
198
  f"Value: { value }\n"
148
199
  "Tips: You can provide parameter 'default_key' to allow DataFormatter.to_str_key_dict() convert non-dictionary value to a dictionary { default_key: value } automatically."
149
200
  )
150
- return default if default is not None else {}
201
+ # restructure value to {default_key: value}
202
+ if default_key is not None:
203
+ return DataFormatter.to_str_key_dict(
204
+ {default_key: value},
205
+ value_format=value_format,
206
+ default_value=default_value,
207
+ )
208
+ return default_value
151
209
 
152
210
  @staticmethod
153
211
  def to_str(value: Any) -> str:
@@ -392,7 +392,7 @@ class RuntimeData:
392
392
  case "yaml":
393
393
  return yaml.safe_dump(serializable_data)
394
394
  case "toml":
395
- return toml.dumps(DataFormatter.to_str_key_dict(serializable_data))
395
+ return toml.dumps(DataFormatter.to_str_key_dict(serializable_data, default_key="data"))
396
396
 
397
397
  def __delitem__(self, key: Any):
398
398
  if isinstance(key, str) and "." in key:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agently"
3
- version = "4.0.5.3"
3
+ version = "4.0.5.5"
4
4
  description = ""
5
5
  authors = [
6
6
  {name = "Agently Team",email = "developer@agently.tech"},
File without changes
File without changes
File without changes
File without changes