agently 4.0.6.11__tar.gz → 4.0.7.1__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.
- {agently-4.0.6.11 → agently-4.0.7.1}/PKG-INFO +1 -1
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/_default_settings.yaml +2 -1
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/base.py +17 -1
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/plugins/PromptGenerator/AgentlyPromptGenerator.py +21 -5
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/tools/Search.py +1 -1
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/ModelRequest.py +9 -1
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/TriggerFlow/BluePrint.py +2 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/TriggerFlow/Execution.py +28 -11
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/TriggerFlow/TriggerFlow.py +22 -7
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/TriggerFlow/process/BaseProcess.py +16 -2
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/TriggerFlow/process/ForEachProcess.py +29 -23
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/DataFormatter.py +8 -2
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/DataLocator.py +108 -31
- {agently-4.0.6.11 → agently-4.0.7.1}/pyproject.toml +1 -1
- {agently-4.0.6.11 → agently-4.0.7.1}/LICENSE +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/README.md +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/_default_init.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/agent_extensions/AutoFuncExtension.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/agent_extensions/ChatSessionExtension.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/agent_extensions/ConfigurePromptExtension.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/agent_extensions/KeyWaiterExtension.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/agent_extensions/ToolExtension.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/agent_extensions/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/hookers/ConsoleHooker.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/hookers/PureLoggerHooker.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/hookers/SystemMessageHooker.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/plugins/ModelRequester/OpenAICompatible.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/plugins/ResponseParser/AgentlyResponseParser.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/plugins/ToolManager/AgentlyToolManager.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/plugins/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/tools/Browse.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/tools/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/Agent.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/EventCenter.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/ExtensionHandlers.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/PluginManager.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/Prompt.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/Tool.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/TriggerFlow/Chunk.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/TriggerFlow/Process.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/TriggerFlow/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/TriggerFlow/process/MatchCaseProcess.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/TriggerFlow/process/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/core/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/integrations/chromadb.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/data/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/data/event.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/data/prompt.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/data/request.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/data/response.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/data/serializable.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/data/tool.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/plugins/EventHooker.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/plugins/ModelRequester.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/plugins/PromptGenerator.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/plugins/ResponseParser.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/plugins/ToolManager.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/plugins/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/plugins/base.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/trigger_flow/__init__.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/types/trigger_flow/trigger_flow.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/DataPathBuilder.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/FunctionShifter.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/GeneratorConsumer.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/LazyImport.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/Logger.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/Messenger.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/PythonSandbox.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/RuntimeData.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/SerializableRuntimeData.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/Settings.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/Storage.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/StreamingJSONCompleter.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/StreamingJSONParser.py +0 -0
- {agently-4.0.6.11 → agently-4.0.7.1}/agently/utils/__init__.py +0 -0
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
import logging
|
|
15
16
|
from typing import Any, Literal, Type, TYPE_CHECKING, TypeVar, Generic, cast
|
|
16
17
|
|
|
17
18
|
from agently.utils import Settings, create_logger, FunctionShifter, DataFormatter
|
|
@@ -37,6 +38,10 @@ _hook_default_event_handlers(event_center)
|
|
|
37
38
|
async_system_message = event_center.async_system_message
|
|
38
39
|
system_message = event_center.system_message
|
|
39
40
|
logger = create_logger()
|
|
41
|
+
httpx_level_name = settings.get("runtime.httpx_log_level", "WARNING")
|
|
42
|
+
httpx_level = getattr(logging, str(httpx_level_name).upper(), logging.WARNING)
|
|
43
|
+
logging.getLogger("httpx").setLevel(httpx_level)
|
|
44
|
+
logging.getLogger("httpcore").setLevel(httpx_level)
|
|
40
45
|
tool = Tool(plugin_manager, settings)
|
|
41
46
|
_agently_messenger = event_center.create_messenger("Agently")
|
|
42
47
|
|
|
@@ -70,11 +75,13 @@ settings.update_mappings(
|
|
|
70
75
|
"runtime.show_model_logs": True,
|
|
71
76
|
"runtime.show_tool_logs": True,
|
|
72
77
|
"runtime.show_trigger_flow_logs": True,
|
|
78
|
+
"runtime.httpx_log_level": "INFO",
|
|
73
79
|
},
|
|
74
80
|
False: {
|
|
75
81
|
"runtime.show_model_logs": False,
|
|
76
82
|
"runtime.show_tool_logs": False,
|
|
77
83
|
"runtime.show_trigger_flow_logs": False,
|
|
84
|
+
"runtime.httpx_log_level": "WARNING",
|
|
78
85
|
},
|
|
79
86
|
}
|
|
80
87
|
}
|
|
@@ -117,7 +124,16 @@ class AgentlyMain(Generic[A]):
|
|
|
117
124
|
self.tool = tool
|
|
118
125
|
self.AgentType = AgentType
|
|
119
126
|
|
|
120
|
-
|
|
127
|
+
def set_settings(key: str, value: "SerializableValue", *, auto_load_env: bool = False):
|
|
128
|
+
self.settings.set_settings(key, value, auto_load_env=auto_load_env)
|
|
129
|
+
if key in ("runtime.httpx_log_level", "debug"):
|
|
130
|
+
level_name = self.settings.get("runtime.httpx_log_level", "WARNING")
|
|
131
|
+
level = getattr(logging, str(level_name).upper(), logging.WARNING)
|
|
132
|
+
logging.getLogger("httpx").setLevel(level)
|
|
133
|
+
logging.getLogger("httpcore").setLevel(level)
|
|
134
|
+
return self
|
|
135
|
+
|
|
136
|
+
self.set_settings = set_settings
|
|
121
137
|
|
|
122
138
|
def set_debug_console(self, debug_console_status: Literal["ON", "OFF"]):
|
|
123
139
|
match debug_console_status:
|
|
@@ -589,13 +589,29 @@ class AgentlyPromptGenerator(PromptGenerator):
|
|
|
589
589
|
fields = {}
|
|
590
590
|
validators = {}
|
|
591
591
|
|
|
592
|
-
def ensure_list_and_cast(v: Any, target_type:
|
|
592
|
+
def ensure_list_and_cast(v: Any, target_type: Any):
|
|
593
593
|
if not isinstance(v, list):
|
|
594
594
|
v = [v]
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
595
|
+
casted = []
|
|
596
|
+
for item in v:
|
|
597
|
+
if target_type is Any or not isinstance(target_type, type):
|
|
598
|
+
casted.append(item)
|
|
599
|
+
continue
|
|
600
|
+
target_type = cast(type, target_type)
|
|
601
|
+
if isinstance(item, target_type):
|
|
602
|
+
casted.append(item)
|
|
603
|
+
continue
|
|
604
|
+
if isinstance(item, Mapping):
|
|
605
|
+
model_validate = getattr(target_type, "model_validate", None)
|
|
606
|
+
if callable(model_validate):
|
|
607
|
+
casted.append(model_validate(item))
|
|
608
|
+
continue
|
|
609
|
+
parse_obj = getattr(target_type, "parse_obj", None)
|
|
610
|
+
if callable(parse_obj):
|
|
611
|
+
casted.append(parse_obj(item))
|
|
612
|
+
continue
|
|
613
|
+
casted.append(target_type(item))
|
|
614
|
+
return casted
|
|
599
615
|
|
|
600
616
|
if isinstance(schema, Mapping):
|
|
601
617
|
for field_name, field_type_schema in schema.items():
|
|
@@ -153,6 +153,11 @@ class ModelResponseResult:
|
|
|
153
153
|
return await self._response_parser.async_get_data(type=type)
|
|
154
154
|
return await self._response_parser.async_get_data(type=type)
|
|
155
155
|
|
|
156
|
+
@overload
|
|
157
|
+
async def async_get_data_object(
|
|
158
|
+
self,
|
|
159
|
+
) -> "BaseModel | None": ...
|
|
160
|
+
|
|
156
161
|
@overload
|
|
157
162
|
async def async_get_data_object(
|
|
158
163
|
self,
|
|
@@ -432,6 +437,9 @@ class ModelRequest:
|
|
|
432
437
|
self.get_data = FunctionShifter.syncify(self.async_get_data)
|
|
433
438
|
self.get_data_object = FunctionShifter.syncify(self.async_get_data_object)
|
|
434
439
|
|
|
440
|
+
self.start = self.get_data
|
|
441
|
+
self.async_start = self.async_get_data
|
|
442
|
+
|
|
435
443
|
def set_prompt(
|
|
436
444
|
self,
|
|
437
445
|
key: "PromptStandardSlot | str",
|
|
@@ -464,7 +472,7 @@ class ModelRequest:
|
|
|
464
472
|
prompt: Any,
|
|
465
473
|
mappings: dict[str, Any] | None = None,
|
|
466
474
|
):
|
|
467
|
-
self.prompt.set("system", ["YOU MUST REACT AND RESPOND AS {system.
|
|
475
|
+
self.prompt.set("system", ["YOU MUST REACT AND RESPOND AS {system.your_role}!"])
|
|
468
476
|
self.prompt.set("system.your_role", prompt, mappings)
|
|
469
477
|
return self
|
|
470
478
|
|
|
@@ -132,6 +132,7 @@ class TriggerFlowBluePrint:
|
|
|
132
132
|
*,
|
|
133
133
|
execution_id: str | None = None,
|
|
134
134
|
skip_exceptions: bool = False,
|
|
135
|
+
concurrency: int | None = None,
|
|
135
136
|
):
|
|
136
137
|
handlers_snapshot: TriggerFlowAllHandlers = {
|
|
137
138
|
"event": {k: v.copy() for k, v in self._handlers["event"].items()},
|
|
@@ -143,6 +144,7 @@ class TriggerFlowBluePrint:
|
|
|
143
144
|
trigger_flow=trigger_flow,
|
|
144
145
|
id=execution_id,
|
|
145
146
|
skip_exceptions=skip_exceptions,
|
|
147
|
+
concurrency=concurrency,
|
|
146
148
|
)
|
|
147
149
|
|
|
148
150
|
def copy(self, *, name: str | None = None):
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import uuid
|
|
17
17
|
import asyncio
|
|
18
18
|
import warnings
|
|
19
|
+
from contextvars import ContextVar
|
|
19
20
|
|
|
20
21
|
from typing import Any, Literal, TYPE_CHECKING
|
|
21
22
|
|
|
@@ -37,6 +38,7 @@ class TriggerFlowExecution:
|
|
|
37
38
|
trigger_flow: "TriggerFlow",
|
|
38
39
|
id: str | None = None,
|
|
39
40
|
skip_exceptions: bool = False,
|
|
41
|
+
concurrency: int | None = None,
|
|
40
42
|
):
|
|
41
43
|
# Basic Attributions
|
|
42
44
|
self.id = id if id is not None else uuid.uuid4().hex
|
|
@@ -45,6 +47,11 @@ class TriggerFlowExecution:
|
|
|
45
47
|
self._runtime_data = RuntimeData()
|
|
46
48
|
self._system_runtime_data = RuntimeData()
|
|
47
49
|
self._skip_exceptions = skip_exceptions
|
|
50
|
+
self._concurrency_semaphore = asyncio.Semaphore(concurrency) if concurrency and concurrency > 0 else None
|
|
51
|
+
self._concurrency_depth = ContextVar(
|
|
52
|
+
f"trigger_flow_execution_concurrency_depth_{ self.id }",
|
|
53
|
+
default=0,
|
|
54
|
+
)
|
|
48
55
|
|
|
49
56
|
# Settings
|
|
50
57
|
self.settings = Settings(
|
|
@@ -126,19 +133,29 @@ class TriggerFlowExecution:
|
|
|
126
133
|
},
|
|
127
134
|
self.settings,
|
|
128
135
|
)
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
136
|
+
async def run_handler(handler_func):
|
|
137
|
+
if self._concurrency_semaphore is None:
|
|
138
|
+
return await handler_func
|
|
139
|
+
depth = self._concurrency_depth.get()
|
|
140
|
+
token = self._concurrency_depth.set(depth + 1)
|
|
141
|
+
try:
|
|
142
|
+
if depth > 0:
|
|
143
|
+
return await handler_func
|
|
144
|
+
async with self._concurrency_semaphore:
|
|
145
|
+
return await handler_func
|
|
146
|
+
finally:
|
|
147
|
+
self._concurrency_depth.reset(token)
|
|
148
|
+
|
|
149
|
+
handler_task = FunctionShifter.asyncify(handler)(
|
|
150
|
+
TriggerFlowEventData(
|
|
151
|
+
trigger_event=trigger_event,
|
|
152
|
+
trigger_type=trigger_type,
|
|
153
|
+
value=value,
|
|
154
|
+
execution=self,
|
|
155
|
+
_layer_marks=_layer_marks,
|
|
140
156
|
)
|
|
141
157
|
)
|
|
158
|
+
tasks.append(asyncio.ensure_future(run_handler(handler_task)))
|
|
142
159
|
|
|
143
160
|
if tasks:
|
|
144
161
|
await asyncio.gather(*tasks, return_exceptions=self._skip_exceptions)
|
|
@@ -99,13 +99,19 @@ class TriggerFlow:
|
|
|
99
99
|
self._blue_print.chunks[handler_or_name.__name__] = chunk
|
|
100
100
|
return chunk
|
|
101
101
|
|
|
102
|
-
def create_execution(
|
|
102
|
+
def create_execution(
|
|
103
|
+
self,
|
|
104
|
+
*,
|
|
105
|
+
skip_exceptions: bool | None = None,
|
|
106
|
+
concurrency: int | None = None,
|
|
107
|
+
):
|
|
103
108
|
execution_id = uuid.uuid4().hex
|
|
104
109
|
skip_exceptions = skip_exceptions if skip_exceptions is not None else self._skip_exceptions
|
|
105
110
|
execution = self._blue_print.create_execution(
|
|
106
111
|
self,
|
|
107
112
|
execution_id=execution_id,
|
|
108
113
|
skip_exceptions=skip_exceptions,
|
|
114
|
+
concurrency=concurrency,
|
|
109
115
|
)
|
|
110
116
|
self._executions[execution_id] = execution
|
|
111
117
|
return execution
|
|
@@ -118,8 +124,14 @@ class TriggerFlow:
|
|
|
118
124
|
if execution.id in self._executions:
|
|
119
125
|
del self._executions[execution.id]
|
|
120
126
|
|
|
121
|
-
async def async_start_execution(
|
|
122
|
-
|
|
127
|
+
async def async_start_execution(
|
|
128
|
+
self,
|
|
129
|
+
initial_value: Any,
|
|
130
|
+
*,
|
|
131
|
+
wait_for_result: bool = False,
|
|
132
|
+
concurrency: int | None = None,
|
|
133
|
+
):
|
|
134
|
+
execution = self.create_execution(concurrency=concurrency)
|
|
123
135
|
await execution.async_start(initial_value, wait_for_result=wait_for_result)
|
|
124
136
|
return execution
|
|
125
137
|
|
|
@@ -192,8 +204,9 @@ class TriggerFlow:
|
|
|
192
204
|
*,
|
|
193
205
|
wait_for_result: bool = True,
|
|
194
206
|
timeout: int | None = 10,
|
|
207
|
+
concurrency: int | None = None,
|
|
195
208
|
):
|
|
196
|
-
execution = await self.async_start_execution(initial_value)
|
|
209
|
+
execution = await self.async_start_execution(initial_value, concurrency=concurrency)
|
|
197
210
|
if wait_for_result:
|
|
198
211
|
return await execution.async_get_result(timeout=timeout)
|
|
199
212
|
|
|
@@ -202,8 +215,9 @@ class TriggerFlow:
|
|
|
202
215
|
initial_value: Any = None,
|
|
203
216
|
*,
|
|
204
217
|
timeout: int | None = 10,
|
|
218
|
+
concurrency: int | None = None,
|
|
205
219
|
):
|
|
206
|
-
execution = self.create_execution()
|
|
220
|
+
execution = self.create_execution(concurrency=concurrency)
|
|
207
221
|
return execution.get_async_runtime_stream(
|
|
208
222
|
initial_value,
|
|
209
223
|
timeout=timeout,
|
|
@@ -213,9 +227,10 @@ class TriggerFlow:
|
|
|
213
227
|
self,
|
|
214
228
|
initial_value: Any = None,
|
|
215
229
|
*,
|
|
216
|
-
timeout:
|
|
230
|
+
timeout: float | None = 10.0,
|
|
231
|
+
concurrency: int | None = None,
|
|
217
232
|
):
|
|
218
|
-
execution = self.create_execution()
|
|
233
|
+
execution = self.create_execution(concurrency=concurrency)
|
|
219
234
|
return execution.get_runtime_stream(
|
|
220
235
|
initial_value,
|
|
221
236
|
timeout=timeout,
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
import uuid
|
|
17
|
-
from asyncio import Event
|
|
17
|
+
from asyncio import Event, Semaphore
|
|
18
18
|
from threading import Lock
|
|
19
19
|
|
|
20
20
|
from typing import Callable, Any, Literal, TYPE_CHECKING, overload, cast
|
|
@@ -266,11 +266,13 @@ class TriggerFlowBaseProcess:
|
|
|
266
266
|
self,
|
|
267
267
|
*chunks: "TriggerFlowChunk | TriggerFlowHandler | tuple[str, TriggerFlowHandler]",
|
|
268
268
|
side_branch: bool = False,
|
|
269
|
+
concurrency: int | None = None,
|
|
269
270
|
):
|
|
270
271
|
batch_trigger = f"Batch-{ uuid.uuid4().hex }"
|
|
271
272
|
results = {}
|
|
272
273
|
triggers_to_wait = {}
|
|
273
274
|
trigger_to_chunk_name = {}
|
|
275
|
+
semaphore = Semaphore(concurrency) if concurrency and concurrency > 0 else None
|
|
274
276
|
|
|
275
277
|
async def wait_all_chunks(data: "TriggerFlowEventData"):
|
|
276
278
|
if data.event in triggers_to_wait:
|
|
@@ -292,13 +294,25 @@ class TriggerFlowBaseProcess:
|
|
|
292
294
|
chunk = self._flow_chunk(chunk_name)(chunk_func)
|
|
293
295
|
else:
|
|
294
296
|
chunk = self._flow_chunk(chunk.__name__)(chunk) if callable(chunk) else chunk
|
|
297
|
+
typed_chunk = cast(TriggerFlowChunk, chunk)
|
|
295
298
|
triggers_to_wait[chunk.trigger] = False
|
|
296
299
|
trigger_to_chunk_name[chunk.trigger] = chunk.name
|
|
297
300
|
results[chunk.name] = None
|
|
301
|
+
|
|
302
|
+
if semaphore is None:
|
|
303
|
+
handler = typed_chunk.async_call
|
|
304
|
+
else:
|
|
305
|
+
def make_handler(bound_chunk: TriggerFlowChunk):
|
|
306
|
+
async def handler(data: "TriggerFlowEventData"):
|
|
307
|
+
async with semaphore:
|
|
308
|
+
return await bound_chunk.async_call(data)
|
|
309
|
+
return handler
|
|
310
|
+
handler = make_handler(typed_chunk)
|
|
311
|
+
|
|
298
312
|
self._blue_print.add_handler(
|
|
299
313
|
self.trigger_type,
|
|
300
314
|
self.trigger_event,
|
|
301
|
-
|
|
315
|
+
handler,
|
|
302
316
|
)
|
|
303
317
|
self._blue_print.add_event_handler(chunk.trigger, wait_all_chunks)
|
|
304
318
|
|
|
@@ -22,7 +22,7 @@ from agently.utils import RuntimeDataNamespace
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class TriggerFlowForEachProcess(TriggerFlowBaseProcess):
|
|
25
|
-
def for_each(self):
|
|
25
|
+
def for_each(self, *, concurrency: int | None = None):
|
|
26
26
|
for_each_id = uuid.uuid4().hex
|
|
27
27
|
for_each_block_data = TriggerFlowBlockData(
|
|
28
28
|
outer_block=self._block_data,
|
|
@@ -31,6 +31,7 @@ class TriggerFlowForEachProcess(TriggerFlowBaseProcess):
|
|
|
31
31
|
},
|
|
32
32
|
)
|
|
33
33
|
send_item_trigger = f"ForEach-{ for_each_id }-Send"
|
|
34
|
+
semaphore = asyncio.Semaphore(concurrency) if concurrency and concurrency > 0 else None
|
|
34
35
|
|
|
35
36
|
async def send_items(data: "TriggerFlowEventData"):
|
|
36
37
|
data.layer_in()
|
|
@@ -38,33 +39,38 @@ class TriggerFlowForEachProcess(TriggerFlowBaseProcess):
|
|
|
38
39
|
assert for_each_instance_id is not None
|
|
39
40
|
|
|
40
41
|
send_tasks = []
|
|
41
|
-
|
|
42
|
-
items = list(data.value)
|
|
43
|
-
for item in items:
|
|
44
|
-
data.layer_in()
|
|
45
|
-
item_id = data.layer_mark
|
|
46
|
-
assert item_id is not None
|
|
47
|
-
data._system_runtime_data.set(f"for_each_results.{ for_each_instance_id }.{ item_id }", EMPTY)
|
|
48
|
-
send_tasks.append(
|
|
49
|
-
data.async_emit(
|
|
50
|
-
send_item_trigger,
|
|
51
|
-
item,
|
|
52
|
-
data._layer_marks.copy(),
|
|
53
|
-
)
|
|
54
|
-
)
|
|
55
|
-
data.layer_out()
|
|
56
|
-
await asyncio.gather(*send_tasks)
|
|
57
|
-
else:
|
|
42
|
+
def prepare_item(item):
|
|
58
43
|
data.layer_in()
|
|
59
44
|
item_id = data.layer_mark
|
|
60
45
|
assert item_id is not None
|
|
46
|
+
layer_marks = data._layer_marks.copy()
|
|
61
47
|
data._system_runtime_data.set(f"for_each_results.{ for_each_instance_id }.{ item_id }", EMPTY)
|
|
62
|
-
await data.async_emit(
|
|
63
|
-
send_item_trigger,
|
|
64
|
-
data.value,
|
|
65
|
-
data._layer_marks.copy(),
|
|
66
|
-
)
|
|
67
48
|
data.layer_out()
|
|
49
|
+
return item_id, layer_marks, item
|
|
50
|
+
|
|
51
|
+
async def emit_item(item, layer_marks):
|
|
52
|
+
if semaphore is None:
|
|
53
|
+
await data.async_emit(
|
|
54
|
+
send_item_trigger,
|
|
55
|
+
item,
|
|
56
|
+
layer_marks,
|
|
57
|
+
)
|
|
58
|
+
else:
|
|
59
|
+
async with semaphore:
|
|
60
|
+
await data.async_emit(
|
|
61
|
+
send_item_trigger,
|
|
62
|
+
item,
|
|
63
|
+
layer_marks,
|
|
64
|
+
)
|
|
65
|
+
if not isinstance(data.value, str) and isinstance(data.value, Sequence):
|
|
66
|
+
items = list(data.value)
|
|
67
|
+
for item in items:
|
|
68
|
+
_, layer_marks, item_value = prepare_item(item)
|
|
69
|
+
send_tasks.append(emit_item(item_value, layer_marks))
|
|
70
|
+
await asyncio.gather(*send_tasks)
|
|
71
|
+
else:
|
|
72
|
+
_, layer_marks, item_value = prepare_item(data.value)
|
|
73
|
+
await emit_item(item_value, layer_marks)
|
|
68
74
|
|
|
69
75
|
self.to(send_items)
|
|
70
76
|
|
|
@@ -56,15 +56,21 @@ class DataFormatter:
|
|
|
56
56
|
if issubclass(value, BaseModel):
|
|
57
57
|
extracted_value = {}
|
|
58
58
|
for name, field in value.model_fields.items():
|
|
59
|
+
annotation = field.annotation
|
|
60
|
+
if hasattr(field, "rebuild_annotation"):
|
|
61
|
+
try:
|
|
62
|
+
annotation = field.rebuild_annotation()
|
|
63
|
+
except Exception:
|
|
64
|
+
annotation = field.annotation
|
|
59
65
|
extracted_value.update(
|
|
60
66
|
{
|
|
61
67
|
name: (
|
|
62
68
|
(
|
|
63
|
-
DataFormatter.sanitize(
|
|
69
|
+
DataFormatter.sanitize(annotation, remain_type=remain_type),
|
|
64
70
|
field.description,
|
|
65
71
|
)
|
|
66
72
|
if field.description
|
|
67
|
-
else (DataFormatter.sanitize(
|
|
73
|
+
else (DataFormatter.sanitize(annotation, remain_type=remain_type),)
|
|
68
74
|
)
|
|
69
75
|
}
|
|
70
76
|
)
|
|
@@ -21,6 +21,101 @@ if TYPE_CHECKING:
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class DataLocator:
|
|
24
|
+
@staticmethod
|
|
25
|
+
def _locate_path_parts(
|
|
26
|
+
result: Any,
|
|
27
|
+
path_parts: list[str],
|
|
28
|
+
*,
|
|
29
|
+
style: Literal["dot", "slash"],
|
|
30
|
+
default: Any,
|
|
31
|
+
):
|
|
32
|
+
if not path_parts:
|
|
33
|
+
return result
|
|
34
|
+
path_part = path_parts[0]
|
|
35
|
+
remaining = path_parts[1:]
|
|
36
|
+
if style == "dot":
|
|
37
|
+
if "[" in path_part:
|
|
38
|
+
path_key_and_index = path_part.split("[")
|
|
39
|
+
path_key = path_key_and_index[0]
|
|
40
|
+
path_index = path_key_and_index[1][:-1]
|
|
41
|
+
if isinstance(result, Mapping):
|
|
42
|
+
result = result.get(path_key, default)
|
|
43
|
+
else:
|
|
44
|
+
return default
|
|
45
|
+
if path_index in ("*", ""):
|
|
46
|
+
if not isinstance(result, str) and isinstance(result, Sequence):
|
|
47
|
+
values = []
|
|
48
|
+
for item in result:
|
|
49
|
+
value = DataLocator._locate_path_parts(
|
|
50
|
+
item,
|
|
51
|
+
remaining,
|
|
52
|
+
style=style,
|
|
53
|
+
default=default,
|
|
54
|
+
)
|
|
55
|
+
if value is default:
|
|
56
|
+
return default
|
|
57
|
+
values.append(value)
|
|
58
|
+
return values
|
|
59
|
+
return default
|
|
60
|
+
try:
|
|
61
|
+
index = int(path_index)
|
|
62
|
+
except Exception:
|
|
63
|
+
return default
|
|
64
|
+
if not isinstance(result, str) and isinstance(result, Sequence):
|
|
65
|
+
try:
|
|
66
|
+
return DataLocator._locate_path_parts(
|
|
67
|
+
result[index],
|
|
68
|
+
remaining,
|
|
69
|
+
style=style,
|
|
70
|
+
default=default,
|
|
71
|
+
)
|
|
72
|
+
except Exception:
|
|
73
|
+
return default
|
|
74
|
+
return default
|
|
75
|
+
else:
|
|
76
|
+
if isinstance(result, Mapping):
|
|
77
|
+
return DataLocator._locate_path_parts(
|
|
78
|
+
result.get(path_part, default),
|
|
79
|
+
remaining,
|
|
80
|
+
style=style,
|
|
81
|
+
default=default,
|
|
82
|
+
)
|
|
83
|
+
return default
|
|
84
|
+
else:
|
|
85
|
+
if path_part == "*":
|
|
86
|
+
if not isinstance(result, str) and isinstance(result, Sequence):
|
|
87
|
+
values = []
|
|
88
|
+
for item in result:
|
|
89
|
+
value = DataLocator._locate_path_parts(
|
|
90
|
+
item,
|
|
91
|
+
remaining,
|
|
92
|
+
style=style,
|
|
93
|
+
default=default,
|
|
94
|
+
)
|
|
95
|
+
if value is default:
|
|
96
|
+
return default
|
|
97
|
+
values.append(value)
|
|
98
|
+
return values
|
|
99
|
+
return default
|
|
100
|
+
if isinstance(result, Mapping):
|
|
101
|
+
return DataLocator._locate_path_parts(
|
|
102
|
+
result.get(path_part, default),
|
|
103
|
+
remaining,
|
|
104
|
+
style=style,
|
|
105
|
+
default=default,
|
|
106
|
+
)
|
|
107
|
+
if not isinstance(result, str) and isinstance(result, Sequence):
|
|
108
|
+
try:
|
|
109
|
+
return DataLocator._locate_path_parts(
|
|
110
|
+
result[int(path_part)],
|
|
111
|
+
remaining,
|
|
112
|
+
style=style,
|
|
113
|
+
default=default,
|
|
114
|
+
)
|
|
115
|
+
except Exception:
|
|
116
|
+
return default
|
|
117
|
+
return default
|
|
118
|
+
|
|
24
119
|
@staticmethod
|
|
25
120
|
def locate_path_in_dict(
|
|
26
121
|
original_dict: dict,
|
|
@@ -34,42 +129,24 @@ class DataLocator:
|
|
|
34
129
|
match style:
|
|
35
130
|
case "dot":
|
|
36
131
|
try:
|
|
37
|
-
result = original_dict
|
|
38
132
|
path_parts = path.split(".")
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
result = result[path_key]
|
|
46
|
-
else:
|
|
47
|
-
return default
|
|
48
|
-
if not isinstance(result, str) and isinstance(result, Sequence):
|
|
49
|
-
result = result[path_index]
|
|
50
|
-
else:
|
|
51
|
-
return default
|
|
52
|
-
else:
|
|
53
|
-
if isinstance(result, Mapping):
|
|
54
|
-
result = result[path_part]
|
|
55
|
-
else:
|
|
56
|
-
return default
|
|
57
|
-
return result
|
|
133
|
+
return DataLocator._locate_path_parts(
|
|
134
|
+
original_dict,
|
|
135
|
+
path_parts,
|
|
136
|
+
style="dot",
|
|
137
|
+
default=default,
|
|
138
|
+
)
|
|
58
139
|
except Exception:
|
|
59
140
|
return default
|
|
60
141
|
case "slash":
|
|
61
|
-
result = original_dict
|
|
62
|
-
path_parts = path.split("/")
|
|
63
142
|
try:
|
|
64
|
-
for
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return default
|
|
72
|
-
return result
|
|
143
|
+
path_parts = [part for part in path.split("/") if part]
|
|
144
|
+
return DataLocator._locate_path_parts(
|
|
145
|
+
original_dict,
|
|
146
|
+
path_parts,
|
|
147
|
+
style="slash",
|
|
148
|
+
default=default,
|
|
149
|
+
)
|
|
73
150
|
except Exception:
|
|
74
151
|
return default
|
|
75
152
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/agent_extensions/ChatSessionExtension.py
RENAMED
|
File without changes
|
{agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/agent_extensions/ConfigurePromptExtension.py
RENAMED
|
File without changes
|
{agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/agent_extensions/KeyWaiterExtension.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/plugins/ModelRequester/OpenAICompatible.py
RENAMED
|
File without changes
|
|
File without changes
|
{agently-4.0.6.11 → agently-4.0.7.1}/agently/builtins/plugins/ToolManager/AgentlyToolManager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|