agently 4.0.5.8__tar.gz → 4.0.6__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 (76) hide show
  1. {agently-4.0.5.8 → agently-4.0.6}/PKG-INFO +1 -1
  2. {agently-4.0.5.8 → agently-4.0.6}/agently/_default_settings.yaml +12 -0
  3. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/agent_extensions/KeyWaiterExtension.py +2 -1
  4. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/agent_extensions/ToolExtension.py +1 -1
  5. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/plugins/ModelRequester/OpenAICompatible.py +11 -1
  6. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/plugins/PromptGenerator/AgentlyPromptGenerator.py +105 -16
  7. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/plugins/ResponseParser/AgentlyResponseParser.py +43 -10
  8. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/tools/Search.py +87 -5
  9. {agently-4.0.5.8 → agently-4.0.6}/agently/core/Agent.py +24 -8
  10. {agently-4.0.5.8 → agently-4.0.6}/agently/core/ModelRequest.py +39 -27
  11. {agently-4.0.5.8 → agently-4.0.6}/agently/types/data/prompt.py +2 -0
  12. {agently-4.0.5.8 → agently-4.0.6}/agently/types/data/response.py +3 -1
  13. {agently-4.0.5.8 → agently-4.0.6}/agently/types/plugins/ResponseParser.py +16 -16
  14. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/FunctionShifter.py +60 -10
  15. {agently-4.0.5.8 → agently-4.0.6}/pyproject.toml +1 -1
  16. {agently-4.0.5.8 → agently-4.0.6}/LICENSE +0 -0
  17. {agently-4.0.5.8 → agently-4.0.6}/README.md +0 -0
  18. {agently-4.0.5.8 → agently-4.0.6}/agently/__init__.py +0 -0
  19. {agently-4.0.5.8 → agently-4.0.6}/agently/_default_init.py +0 -0
  20. {agently-4.0.5.8 → agently-4.0.6}/agently/base.py +0 -0
  21. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/agent_extensions/AutoFuncExtension.py +0 -0
  22. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/agent_extensions/ChatSessionExtension.py +0 -0
  23. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/agent_extensions/ConfigurePromptExtension.py +0 -0
  24. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/agent_extensions/__init__.py +0 -0
  25. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/hookers/ConsoleHooker.py +0 -0
  26. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/hookers/PureLoggerHooker.py +0 -0
  27. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/hookers/SystemMessageHooker.py +0 -0
  28. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/plugins/ToolManager/AgentlyToolManager.py +0 -0
  29. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/plugins/__init__.py +0 -0
  30. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/tools/Browse.py +0 -0
  31. {agently-4.0.5.8 → agently-4.0.6}/agently/builtins/tools/__init__.py +0 -0
  32. {agently-4.0.5.8 → agently-4.0.6}/agently/core/EventCenter.py +0 -0
  33. {agently-4.0.5.8 → agently-4.0.6}/agently/core/ExtensionHandlers.py +0 -0
  34. {agently-4.0.5.8 → agently-4.0.6}/agently/core/PluginManager.py +0 -0
  35. {agently-4.0.5.8 → agently-4.0.6}/agently/core/Prompt.py +0 -0
  36. {agently-4.0.5.8 → agently-4.0.6}/agently/core/Tool.py +0 -0
  37. {agently-4.0.5.8 → agently-4.0.6}/agently/core/TriggerFlow/BluePrint.py +0 -0
  38. {agently-4.0.5.8 → agently-4.0.6}/agently/core/TriggerFlow/Chunk.py +0 -0
  39. {agently-4.0.5.8 → agently-4.0.6}/agently/core/TriggerFlow/Execution.py +0 -0
  40. {agently-4.0.5.8 → agently-4.0.6}/agently/core/TriggerFlow/Process.py +0 -0
  41. {agently-4.0.5.8 → agently-4.0.6}/agently/core/TriggerFlow/TriggerFlow.py +0 -0
  42. {agently-4.0.5.8 → agently-4.0.6}/agently/core/TriggerFlow/__init__.py +0 -0
  43. {agently-4.0.5.8 → agently-4.0.6}/agently/core/TriggerFlow/process/BaseProcess.py +0 -0
  44. {agently-4.0.5.8 → agently-4.0.6}/agently/core/TriggerFlow/process/ForEachProcess.py +0 -0
  45. {agently-4.0.5.8 → agently-4.0.6}/agently/core/TriggerFlow/process/MatchCaseProcess.py +0 -0
  46. {agently-4.0.5.8 → agently-4.0.6}/agently/core/TriggerFlow/process/__init__.py +0 -0
  47. {agently-4.0.5.8 → agently-4.0.6}/agently/core/__init__.py +0 -0
  48. {agently-4.0.5.8 → agently-4.0.6}/agently/integrations/chromadb.py +0 -0
  49. {agently-4.0.5.8 → agently-4.0.6}/agently/types/__init__.py +0 -0
  50. {agently-4.0.5.8 → agently-4.0.6}/agently/types/data/__init__.py +0 -0
  51. {agently-4.0.5.8 → agently-4.0.6}/agently/types/data/event.py +0 -0
  52. {agently-4.0.5.8 → agently-4.0.6}/agently/types/data/request.py +0 -0
  53. {agently-4.0.5.8 → agently-4.0.6}/agently/types/data/serializable.py +0 -0
  54. {agently-4.0.5.8 → agently-4.0.6}/agently/types/data/tool.py +0 -0
  55. {agently-4.0.5.8 → agently-4.0.6}/agently/types/plugins/EventHooker.py +0 -0
  56. {agently-4.0.5.8 → agently-4.0.6}/agently/types/plugins/ModelRequester.py +0 -0
  57. {agently-4.0.5.8 → agently-4.0.6}/agently/types/plugins/PromptGenerator.py +0 -0
  58. {agently-4.0.5.8 → agently-4.0.6}/agently/types/plugins/ToolManager.py +0 -0
  59. {agently-4.0.5.8 → agently-4.0.6}/agently/types/plugins/__init__.py +0 -0
  60. {agently-4.0.5.8 → agently-4.0.6}/agently/types/plugins/base.py +0 -0
  61. {agently-4.0.5.8 → agently-4.0.6}/agently/types/trigger_flow/__init__.py +0 -0
  62. {agently-4.0.5.8 → agently-4.0.6}/agently/types/trigger_flow/trigger_flow.py +0 -0
  63. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/DataFormatter.py +0 -0
  64. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/DataLocator.py +0 -0
  65. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/DataPathBuilder.py +0 -0
  66. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/GeneratorConsumer.py +0 -0
  67. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/LazyImport.py +0 -0
  68. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/Logger.py +0 -0
  69. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/Messenger.py +0 -0
  70. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/RuntimeData.py +0 -0
  71. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/SerializableRuntimeData.py +0 -0
  72. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/Settings.py +0 -0
  73. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/Storage.py +0 -0
  74. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/StreamingJSONCompleter.py +0 -0
  75. {agently-4.0.5.8 → agently-4.0.6}/agently/utils/StreamingJSONParser.py +0 -0
  76. {agently-4.0.5.8 → agently-4.0.6}/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.8
3
+ Version: 4.0.6
4
4
  Summary:
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -22,6 +22,18 @@ prompt:
22
22
  assistant: assistant
23
23
  user: user
24
24
  _: assistant
25
+ prompt_title_mapping:
26
+ system: "SYSTEM"
27
+ developer: "DEVELOPER DIRECTIONS"
28
+ chat_history: "CHAT HISTORY"
29
+ info: "INFO"
30
+ tools: "TOOLS"
31
+ action_results: "ACTION RESULTS"
32
+ instruct: "INSTRUCT"
33
+ examples: "EXAMPLES"
34
+ input: "INPUT"
35
+ output: "OUTPUT"
36
+ output_requirement: "OUTPUT REQUIREMENT"
25
37
  response:
26
38
  streaming_parse: False
27
39
  streaming_parse_path_style: dot
@@ -19,6 +19,7 @@ from typing import Any, Callable
19
19
  from agently.core import BaseAgent
20
20
  from agently.utils import FunctionShifter, GeneratorConsumer
21
21
 
22
+
22
23
  class KeyWaiterExtension(BaseAgent):
23
24
  def __init__(self, *args, **kwargs):
24
25
  super().__init__(*args, **kwargs)
@@ -48,7 +49,7 @@ class KeyWaiterExtension(BaseAgent):
48
49
 
49
50
  def __get_consumer(self):
50
51
  response = self.get_response()
51
- return GeneratorConsumer(response.get_async_generator(content="instant"))
52
+ return GeneratorConsumer(response.get_async_generator(type="instant"))
52
53
 
53
54
  async def async_get_key_result(
54
55
  self,
@@ -119,7 +119,7 @@ class ToolExtension(BaseAgent):
119
119
  },
120
120
  )
121
121
  tool_judgement_response = tool_judgement_request.get_response()
122
- tool_judgement_result = tool_judgement_response.get_async_generator(content="instant")
122
+ tool_judgement_result = tool_judgement_response.get_async_generator(type="instant")
123
123
  async for instant in tool_judgement_result:
124
124
  if instant.path == "use_tool" and instant.is_complete:
125
125
  if instant.value is False:
@@ -46,6 +46,7 @@ class ContentMapping(TypedDict):
46
46
  id: str | None
47
47
  role: str | None
48
48
  delta: str | None
49
+ tool_calls: str | None
49
50
  done: str | None
50
51
  usage: str | None
51
52
  finish_reason: str | None
@@ -114,11 +115,11 @@ class OpenAICompatible(ModelRequester):
114
115
  "id": "id",
115
116
  "role": "choices[0].delta.role",
116
117
  "delta": "choices[0].delta.content",
118
+ "tool_calls": "choices[0].delta.tool_calls",
117
119
  "done": None,
118
120
  "usage": "usage",
119
121
  "finish_reason": "choices[0].finish_reason",
120
122
  "extra_delta": {
121
- "tool_calls": "choices[0].delta.tool_calls",
122
123
  "function_call": "choices[0].delta.function_call",
123
124
  },
124
125
  "extra_done": None,
@@ -508,6 +509,7 @@ class OpenAICompatible(ModelRequester):
508
509
  id_mapping = content_mapping["id"]
509
510
  role_mapping = content_mapping["role"]
510
511
  delta_mapping = content_mapping["delta"]
512
+ tool_calls_mapping = content_mapping["tool_calls"]
511
513
  done_mapping = content_mapping["done"]
512
514
  usage_mapping = content_mapping["usage"]
513
515
  finish_reason_mapping = content_mapping["finish_reason"]
@@ -551,6 +553,14 @@ class OpenAICompatible(ModelRequester):
551
553
  if delta:
552
554
  content_buffer += str(delta)
553
555
  yield "delta", delta
556
+ if tool_calls_mapping:
557
+ tool_calls = DataLocator.locate_path_in_dict(
558
+ loaded_message,
559
+ tool_calls_mapping,
560
+ style=content_mapping_style,
561
+ )
562
+ if tool_calls:
563
+ yield "tool_calls", tool_calls
554
564
  if extra_delta_mapping:
555
565
  for extra_key, extra_path in extra_delta_mapping.items():
556
566
  extra_value = DataLocator.locate_path_in_dict(
@@ -135,7 +135,7 @@ class AgentlyPromptGenerator(PromptGenerator):
135
135
  def _generate_yaml_prompt_list(self, title: str, prompt_part: Any) -> list[str]:
136
136
  sanitized_part = DataFormatter.sanitize(prompt_part)
137
137
  return [
138
- f"[{ title.upper() }]:",
138
+ f"[{ title }]:",
139
139
  (
140
140
  str(sanitized_part)
141
141
  if isinstance(sanitized_part, (str, int, float, bool)) or sanitized_part is None
@@ -145,10 +145,11 @@ class AgentlyPromptGenerator(PromptGenerator):
145
145
  ]
146
146
 
147
147
  def _generate_main_prompt(self, prompt_object: PromptModel):
148
+ prompt_title_mapping = cast(dict[str, str], self.settings.get("prompt.prompt_title_mapping", {}))
148
149
  prompt_text_list = []
149
150
  # tools
150
151
  if prompt_object.tools and isinstance(prompt_object.tools, list):
151
- prompt_text_list.append("[TOOLS]:")
152
+ prompt_text_list.append(f"[{ prompt_title_mapping.get('tools', 'TOOLS') }]:")
152
153
  for tool_info in prompt_object.tools:
153
154
  if isinstance(tool_info, dict):
154
155
  prompt_text_list.append("[")
@@ -163,11 +164,21 @@ class AgentlyPromptGenerator(PromptGenerator):
163
164
 
164
165
  # action_results
165
166
  if prompt_object.action_results:
166
- prompt_text_list.extend(self._generate_yaml_prompt_list("ACTION RESULTS", prompt_object.action_results))
167
+ prompt_text_list.extend(
168
+ self._generate_yaml_prompt_list(
169
+ str(
170
+ prompt_title_mapping.get(
171
+ 'action_results',
172
+ 'ACTION RESULTS',
173
+ )
174
+ ),
175
+ prompt_object.action_results,
176
+ )
177
+ )
167
178
 
168
179
  # info
169
180
  if prompt_object.info:
170
- prompt_text_list.append("[INFO]:")
181
+ prompt_text_list.append(f"[{ prompt_title_mapping.get('info', 'INFO') }]:")
171
182
  if isinstance(prompt_object.info, Mapping):
172
183
  for title, content in prompt_object.info.items():
173
184
  prompt_text_list.append(f"- { title }: { DataFormatter.sanitize(content) }")
@@ -186,11 +197,45 @@ class AgentlyPromptGenerator(PromptGenerator):
186
197
 
187
198
  # instruct
188
199
  if prompt_object.instruct:
189
- prompt_text_list.extend(self._generate_yaml_prompt_list("INSTRUCT", prompt_object.instruct))
200
+ prompt_text_list.extend(
201
+ self._generate_yaml_prompt_list(
202
+ str(
203
+ prompt_title_mapping.get(
204
+ 'instruct',
205
+ 'INSTRUCT',
206
+ )
207
+ ),
208
+ prompt_object.instruct,
209
+ )
210
+ )
211
+
212
+ # examples
213
+ if prompt_object.examples:
214
+ prompt_text_list.extend(
215
+ self._generate_yaml_prompt_list(
216
+ str(
217
+ prompt_title_mapping.get(
218
+ 'examples',
219
+ 'EXAMPLES',
220
+ )
221
+ ),
222
+ prompt_object.examples,
223
+ )
224
+ )
190
225
 
191
226
  # input
192
227
  if prompt_object.input:
193
- prompt_text_list.extend(self._generate_yaml_prompt_list("INPUT", prompt_object.input))
228
+ prompt_text_list.extend(
229
+ self._generate_yaml_prompt_list(
230
+ str(
231
+ prompt_title_mapping.get(
232
+ 'input',
233
+ 'INPUT',
234
+ )
235
+ ),
236
+ prompt_object.input,
237
+ )
238
+ )
194
239
 
195
240
  # output
196
241
  if prompt_object.output:
@@ -200,7 +245,7 @@ class AgentlyPromptGenerator(PromptGenerator):
200
245
  final_output_dict.update(prompt_object.output)
201
246
  prompt_text_list.extend(
202
247
  [
203
- "[OUTPUT REQUIREMENT]:",
248
+ f"[{ prompt_title_mapping.get('output_requirement', 'OUTPUT REQUIREMENT') }]:",
204
249
  "Data Format: JSON",
205
250
  "Data Structure:",
206
251
  self._generate_json_output_prompt(DataFormatter.sanitize(final_output_dict)),
@@ -210,14 +255,16 @@ class AgentlyPromptGenerator(PromptGenerator):
210
255
  case "markdown":
211
256
  prompt_text_list.extend(
212
257
  [
213
- "[OUTPUT REQUIREMENT]:",
258
+ f"[{ prompt_title_mapping.get('output_requirement', 'OUTPUT REQUIREMENT') }]:",
214
259
  "Data Format: markdown text",
215
260
  ]
216
261
  )
217
262
  case "text":
218
263
  pass
219
264
 
220
- prompt_text_list.append("[OUTPUT]:")
265
+ prompt_text_list.append(
266
+ f"[{ prompt_title_mapping.get('output', 'OUTPUT') }]:",
267
+ )
221
268
  return prompt_text_list
222
269
 
223
270
  def _generate_yaml_prompt_message(
@@ -253,22 +300,47 @@ class AgentlyPromptGenerator(PromptGenerator):
253
300
  prompt_text_list = []
254
301
 
255
302
  merged_role_mapping = cast(dict[str, str], self.settings.get("prompt.role_mapping", {}))
303
+ prompt_title_mapping = cast(dict[str, str], self.settings.get("prompt.prompt_title_mapping", {}))
256
304
  if not isinstance(merged_role_mapping, dict):
257
305
  merged_role_mapping = {}
258
306
 
259
307
  if isinstance(role_mapping, dict):
260
308
  merged_role_mapping.update(role_mapping)
261
309
 
310
+ prompt_text_list.append(
311
+ f"{ (merged_role_mapping['user'] if 'user' in merged_role_mapping else 'user').upper() }:"
312
+ )
313
+
262
314
  # system & developer
263
315
  if prompt_object.system:
264
- prompt_text_list.extend(self._generate_yaml_prompt_list("SYSTEM", prompt_object.system))
316
+ prompt_text_list.extend(
317
+ self._generate_yaml_prompt_list(
318
+ str(
319
+ prompt_title_mapping.get(
320
+ 'system',
321
+ 'SYSTEM',
322
+ )
323
+ ),
324
+ prompt_object.system,
325
+ )
326
+ )
265
327
 
266
328
  if prompt_object.developer:
267
- prompt_text_list.extend(self._generate_yaml_prompt_list("DEVELOPER DIRECTIONS", prompt_object.developer))
329
+ prompt_text_list.extend(
330
+ self._generate_yaml_prompt_list(
331
+ str(
332
+ prompt_title_mapping.get(
333
+ 'developer',
334
+ 'DEVELOPER DIRECTIONS',
335
+ )
336
+ ),
337
+ prompt_object.developer,
338
+ )
339
+ )
268
340
 
269
341
  # chat_history
270
342
  if prompt_object.chat_history:
271
- chat_history_lines = ["[CHAT HISTORY]:"]
343
+ chat_history_lines = [f"[{ prompt_title_mapping.get('chat_history', 'CHAT HISTORY') }]:"]
272
344
  content_adapter = TypeAdapter(ChatMessageContent)
273
345
  for message in prompt_object.chat_history:
274
346
  role = (
@@ -296,7 +368,7 @@ class AgentlyPromptGenerator(PromptGenerator):
296
368
 
297
369
  prompt_text_list.extend(self._generate_main_prompt(prompt_object))
298
370
  prompt_text_list.append(
299
- f"[{ merged_role_mapping['assistant'] if 'assistant' in merged_role_mapping else 'assistant' }]:"
371
+ f"{ (merged_role_mapping['assistant'] if 'assistant' in merged_role_mapping else 'assistant').upper() }:"
300
372
  )
301
373
 
302
374
  return "\n".join(prompt_text_list)
@@ -314,6 +386,8 @@ class AgentlyPromptGenerator(PromptGenerator):
314
386
  prompt_messages = []
315
387
 
316
388
  merged_role_mapping = cast(dict[str, str], self.settings.get("prompt.role_mapping", {}))
389
+ prompt_title_mapping = cast(dict[str, str], self.settings.get("prompt.prompt_title_mapping", {}))
390
+
317
391
  if not isinstance(merged_role_mapping, dict):
318
392
  merged_role_mapping = {}
319
393
 
@@ -324,7 +398,12 @@ class AgentlyPromptGenerator(PromptGenerator):
324
398
  if prompt_object.system:
325
399
  prompt_messages.append(
326
400
  self._generate_yaml_prompt_message(
327
- "system",
401
+ str(
402
+ prompt_title_mapping.get(
403
+ 'system',
404
+ 'SYSTEM',
405
+ )
406
+ ),
328
407
  prompt_object.system,
329
408
  role_mapping=merged_role_mapping,
330
409
  )
@@ -333,7 +412,12 @@ class AgentlyPromptGenerator(PromptGenerator):
333
412
  if prompt_object.developer:
334
413
  prompt_messages.append(
335
414
  self._generate_yaml_prompt_message(
336
- "developer",
415
+ str(
416
+ prompt_title_mapping.get(
417
+ 'developer',
418
+ 'DEVELOPER DIRECTIONS',
419
+ )
420
+ ),
337
421
  prompt_object.developer,
338
422
  role_mapping=merged_role_mapping,
339
423
  )
@@ -376,7 +460,12 @@ class AgentlyPromptGenerator(PromptGenerator):
376
460
  0,
377
461
  {
378
462
  "role": "user",
379
- "content": [{"type": "text", "text": "[Chat History]"}],
463
+ "content": [
464
+ {
465
+ "type": "text",
466
+ "text": f"[{ prompt_title_mapping.get('chat_history', 'CHAT HISTORY') }]",
467
+ }
468
+ ],
380
469
  },
381
470
  )
382
471
  if chat_history[-1]["role"] != "assistant":
@@ -22,6 +22,7 @@ from pydantic import BaseModel
22
22
  import json5
23
23
 
24
24
  from agently.types.plugins import ResponseParser
25
+ from agently.types.data import StreamingData
25
26
  from agently.utils import (
26
27
  DataPathBuilder,
27
28
  RuntimeDataNamespace,
@@ -86,8 +87,8 @@ class AgentlyResponseParser(ResponseParser):
86
87
 
87
88
  self.get_meta = FunctionShifter.syncify(self.async_get_meta)
88
89
  self.get_text = FunctionShifter.syncify(self.async_get_text)
89
- self.get_result = FunctionShifter.syncify(self.async_get_result)
90
- self.get_result_object = FunctionShifter.syncify(self.async_get_result_object)
90
+ self.get_data = FunctionShifter.syncify(self.async_get_data)
91
+ self.get_data_object = FunctionShifter.syncify(self.async_get_data_object)
91
92
 
92
93
  @staticmethod
93
94
  def _on_register():
@@ -241,14 +242,20 @@ class AgentlyResponseParser(ResponseParser):
241
242
  await cast(GeneratorConsumer, self._response_consumer).get_result()
242
243
  return self.full_result_data["meta"]
243
244
 
244
- async def async_get_result(
245
+ async def async_get_data(
245
246
  self,
246
247
  *,
247
- content: Literal['original', 'parsed', "all"] = "parsed",
248
+ type: Literal['original', 'parsed', "all"] | None = "parsed",
249
+ content: Literal['original', 'parsed', "all"] | None = "parsed",
248
250
  ) -> Any:
249
251
  await self._ensure_consumer()
250
252
  await cast(GeneratorConsumer, self._response_consumer).get_result()
251
- match content:
253
+ if type is None and content is not None:
254
+ warnings.warn(
255
+ f"Parameter `content` in method .async_get_data() is deprecated and will be removed in future version, please use parameter `type` instead."
256
+ )
257
+ type = content
258
+ match type:
252
259
  case "original":
253
260
  return self.full_result_data["original_done"].copy()
254
261
  case "parsed":
@@ -257,7 +264,7 @@ class AgentlyResponseParser(ResponseParser):
257
264
  case "all":
258
265
  return self.full_result_data.copy()
259
266
 
260
- async def async_get_result_object(self) -> BaseModel | None:
267
+ async def async_get_data_object(self) -> BaseModel | None:
261
268
  if self._prompt_object.output_format != "json":
262
269
  raise TypeError(
263
270
  "Error: Cannot build an output model for a non-structure output.\n"
@@ -275,23 +282,36 @@ class AgentlyResponseParser(ResponseParser):
275
282
 
276
283
  async def get_async_generator(
277
284
  self,
278
- content: Literal['all', 'delta', 'original', 'instant', 'streaming_parse'] | None = "delta",
285
+ type: Literal['all', 'delta', 'typed_delta', 'original', 'instant', 'streaming_parse'] | None = "delta",
286
+ content: Literal['all', 'delta', 'typed_delta', 'original', 'instant', 'streaming_parse'] | None = "delta",
279
287
  ) -> AsyncGenerator:
280
288
  await self._ensure_consumer()
281
289
  parsed_generator = cast(GeneratorConsumer, self._response_consumer).get_async_generator()
282
290
  _streaming_parse_path_style = self.settings.get("response.streaming_parse_path_style", "dot")
291
+ if type is None and content is not None:
292
+ warnings.warn(
293
+ f"Parameter `content` in method .get_async_generator() is deprecated and will be removed in future version, please use parameter `type` instead."
294
+ )
295
+ type = content
283
296
  async for event, data in parsed_generator:
284
- match content:
297
+ match type:
285
298
  case "all":
286
299
  yield event, data
287
300
  case "delta":
288
301
  if event == "delta":
289
302
  yield data
303
+ case "typed_delta":
304
+ if event == "delta":
305
+ yield "delta", data
306
+ elif event == "tool_calls":
307
+ yield "tool_calls", data
290
308
  case "instant" | "streaming_parse":
291
309
  if self._streaming_json_parser is not None:
292
310
  streaming_parsed = None
293
311
  if event == "delta":
294
312
  streaming_parsed = self._streaming_json_parser.parse_chunk(data)
313
+ elif event == "tool_calls":
314
+ yield StreamingData(path="$tool_calls", value=data)
295
315
  elif event == "done":
296
316
  streaming_parsed = self._streaming_json_parser.finalize()
297
317
  if streaming_parsed:
@@ -305,23 +325,36 @@ class AgentlyResponseParser(ResponseParser):
305
325
 
306
326
  def get_generator(
307
327
  self,
308
- content: Literal['all', 'delta', 'original', 'instant', 'streaming_parse'] | None = "delta",
328
+ type: Literal['all', 'delta', 'typed_delta', 'original', 'instant', 'streaming_parse'] | None = "delta",
329
+ content: Literal['all', 'delta', 'typed_delta', 'original', 'instant', 'streaming_parse'] | None = "delta",
309
330
  ) -> Generator:
310
331
  asyncio.run(self._ensure_consumer())
311
332
  parsed_generator = cast(GeneratorConsumer, self._response_consumer).get_generator()
312
333
  _streaming_parse_path_style = self.settings.get("response.streaming_parse_path_style", "dot")
334
+ if type is None and content is not None:
335
+ warnings.warn(
336
+ f"Parameter `content` in method .get_generator() is deprecated and will be removed in future version, please use parameter `type` instead."
337
+ )
338
+ type = content
313
339
  for event, data in parsed_generator:
314
- match content:
340
+ match type:
315
341
  case "all":
316
342
  yield event, data
317
343
  case "delta":
318
344
  if event == "delta":
319
345
  yield data
346
+ case "typed_delta":
347
+ if event == "delta":
348
+ yield "delta", data
349
+ elif event == "tool_calls":
350
+ yield "tool_calls", data
320
351
  case "instant" | "streaming_parse":
321
352
  if self._streaming_json_parser is not None:
322
353
  streaming_parsed = None
323
354
  if event == "delta":
324
355
  streaming_parsed = self._streaming_json_parser.parse_chunk(data)
356
+ elif event == "tool_calls":
357
+ yield StreamingData(path="$tool_calls", value=data)
325
358
  elif event == "done":
326
359
  streaming_parsed = self._streaming_json_parser.finalize()
327
360
  if streaming_parsed:
@@ -13,15 +13,16 @@
13
13
  # limitations under the License.
14
14
 
15
15
 
16
- from typing import Literal
16
+ from typing import Any, Literal
17
17
 
18
- from agently.utils import LazyImport
18
+ from agently.utils import LazyImport, FunctionShifter
19
19
 
20
20
 
21
21
  class Search:
22
22
 
23
23
  def __init__(
24
24
  self,
25
+ *,
25
26
  proxy: str | None = None,
26
27
  timeout: int | None = None,
27
28
  backend: (
@@ -31,6 +32,76 @@ class Search:
31
32
  Literal["auto", "bing", "duckduckgo", "yahoo", "google", "mullvad_google", "yandex", "wikipedia"] | None
32
33
  ) = None,
33
34
  news_backend: Literal["auto", "bing", "duckduckgo", "yahoo"] | None = None,
35
+ region: Literal[
36
+ "xa-ar",
37
+ "xa-en",
38
+ "ar-es",
39
+ "au-en",
40
+ "at-de",
41
+ "be-fr",
42
+ "be-nl",
43
+ "br-pt",
44
+ "bg-bg",
45
+ "ca-en",
46
+ "ca-fr",
47
+ "ct-ca",
48
+ "cl-es",
49
+ "cn-zh",
50
+ "co-es",
51
+ "hr-hr",
52
+ "cz-cs",
53
+ "dk-da",
54
+ "ee-et",
55
+ "fi-fi",
56
+ "fr-fr",
57
+ "de-de",
58
+ "gr-el",
59
+ "hk-tzh",
60
+ "hu-hu",
61
+ "in-en",
62
+ "id-id",
63
+ "id-en",
64
+ "ie-en",
65
+ "il-he",
66
+ "it-it",
67
+ "jp-jp",
68
+ "kr-kr",
69
+ "lv-lv",
70
+ "lt-lt",
71
+ "xl-es",
72
+ "my-ms",
73
+ "my-en",
74
+ "mx-es",
75
+ "nl-nl",
76
+ "nz-en",
77
+ "no-no",
78
+ "pe-es",
79
+ "ph-en",
80
+ "ph-tl",
81
+ "pl-pl",
82
+ "pt-pt",
83
+ "ro-ro",
84
+ "ru-ru",
85
+ "sg-en",
86
+ "sk-sk",
87
+ "sl-sl",
88
+ "za-en",
89
+ "es-es",
90
+ "se-sv",
91
+ "ch-de",
92
+ "ch-fr",
93
+ "ch-it",
94
+ "tw-tzh",
95
+ "th-th",
96
+ "tr-tr",
97
+ "ua-uk",
98
+ "uk-en",
99
+ "us-en",
100
+ "ue-es",
101
+ "ve-es",
102
+ "vn-vi",
103
+ ] = "us-en",
104
+ options: dict[str, Any] | None = None,
34
105
  ):
35
106
  LazyImport.import_package("ddgs")
36
107
  from ddgs import DDGS
@@ -42,6 +113,8 @@ class Search:
42
113
  "search": search_backend if search_backend is not None else backend,
43
114
  "news": news_backend if news_backend is not None else backend,
44
115
  }
116
+ self.region = region
117
+ self._extra_options = options or {}
45
118
 
46
119
  async def search(
47
120
  self,
@@ -60,11 +133,14 @@ class Search:
60
133
  Returns:
61
134
  List of dictionaries with search results.
62
135
  """
63
- return self.ddgs.text(
136
+ search_text = FunctionShifter.auto_options_func(self.ddgs.text)
137
+ return search_text(
64
138
  query=query,
65
139
  timelimit=timelimit,
66
140
  max_results=max_results,
67
141
  backend=self.backends.get("search", "auto"),
142
+ region=self.region,
143
+ **self._extra_options,
68
144
  )
69
145
 
70
146
  async def search_news(
@@ -84,11 +160,14 @@ class Search:
84
160
  Returns:
85
161
  List of dictionaries with news search results.
86
162
  """
87
- return self.ddgs.news(
163
+ search_news = FunctionShifter.auto_options_func(self.ddgs.news)
164
+ return search_news(
88
165
  query=query,
89
166
  timelimit=timelimit,
90
167
  max_results=max_results,
91
168
  backend=self.backends.get("news", "auto"),
169
+ region=self.region,
170
+ **self._extra_options,
92
171
  )
93
172
 
94
173
  async def search_wikipedia(
@@ -108,11 +187,14 @@ class Search:
108
187
  Returns:
109
188
  List of dictionaries with search results.
110
189
  """
111
- return self.ddgs.text(
190
+ search_wikipedia = FunctionShifter.auto_options_func(self.ddgs.text)
191
+ return search_wikipedia(
112
192
  query=query,
113
193
  timelimit=timelimit,
114
194
  max_results=max_results,
115
195
  backend="wikipedia",
196
+ region=self.region,
197
+ **self._extra_options,
116
198
  )
117
199
 
118
200
  async def search_arxiv(
@@ -40,7 +40,7 @@ class BaseAgent:
40
40
  name=f"Agent-{ self.name }-Settings",
41
41
  parent=parent_settings,
42
42
  )
43
- self.prompt = Prompt(
43
+ self.agent_prompt = Prompt(
44
44
  name=f"Agent-{ self.name }-Prompt",
45
45
  plugin_manager=self.plugin_manager,
46
46
  parent_settings=self.settings,
@@ -58,24 +58,27 @@ class BaseAgent:
58
58
  agent_name=self.name,
59
59
  plugin_manager=self.plugin_manager,
60
60
  parent_settings=self.settings,
61
- parent_prompt=self.prompt,
61
+ parent_prompt=self.agent_prompt,
62
62
  parent_extension_handlers=self.extension_handlers,
63
63
  )
64
+ self.request_prompt = self.request.prompt
65
+ self.prompt = self.request_prompt
64
66
 
65
67
  self.get_response = self.request.get_response
68
+ self.get_result = self.request.get_result
66
69
  self.get_meta = self.request.get_meta
67
70
  self.async_get_meta = self.request.async_get_meta
68
71
  self.get_text = self.request.get_text
69
72
  self.async_get_text = self.request.async_get_text
70
- self.get_result = self.request.get_result
71
- self.async_get_result = self.request.async_get_result
72
- self.get_result_object = self.request.get_result_object
73
- self.async_get_result_object = self.request.async_get_result_object
73
+ self.get_data = self.request.get_data
74
+ self.async_get_data = self.request.async_get_data
75
+ self.get_data_object = self.request.get_data_object
76
+ self.async_get_data_object = self.request.async_get_data_object
74
77
  self.get_generator = self.request.get_generator
75
78
  self.get_async_generator = self.request.get_async_generator
76
79
 
77
- self.start = self.get_result
78
- self.async_start = self.async_get_result
80
+ self.start = self.get_data
81
+ self.async_start = self.async_get_data
79
82
 
80
83
  # Basic Methods
81
84
  def set_settings(self, key: str, value: "SerializableValue"):
@@ -237,6 +240,19 @@ class BaseAgent:
237
240
  self.request.prompt.set("instruct", prompt, mappings)
238
241
  return self
239
242
 
243
+ def examples(
244
+ self,
245
+ prompt: Any,
246
+ mappings: dict[str, Any] | None = None,
247
+ *,
248
+ always: bool = False,
249
+ ):
250
+ if always:
251
+ self.prompt.set("examples", prompt, mappings)
252
+ else:
253
+ self.request.prompt.set("examples", prompt, mappings)
254
+ return self
255
+
240
256
  def output(
241
257
  self,
242
258
  prompt: (