langchain-agentx-python 2.3.8__py3-none-any.whl → 2.3.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.
- langchain_agentx/__init__.py +1 -1
- langchain_agentx/loop/loop_abort.py +14 -2
- langchain_agentx/loop/run_context.py +58 -2
- langchain_agentx/workflow/execution.py +3 -1
- {langchain_agentx_python-2.3.8.dist-info → langchain_agentx_python-2.3.9.dist-info}/METADATA +1 -1
- {langchain_agentx_python-2.3.8.dist-info → langchain_agentx_python-2.3.9.dist-info}/RECORD +9 -9
- {langchain_agentx_python-2.3.8.dist-info → langchain_agentx_python-2.3.9.dist-info}/LICENSE +0 -0
- {langchain_agentx_python-2.3.8.dist-info → langchain_agentx_python-2.3.9.dist-info}/WHEEL +0 -0
- {langchain_agentx_python-2.3.8.dist-info → langchain_agentx_python-2.3.9.dist-info}/top_level.txt +0 -0
langchain_agentx/__init__.py
CHANGED
|
@@ -45,11 +45,23 @@ class LoopAbortSignal(Exception):
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def is_cancel_requested() -> bool:
|
|
48
|
-
"""
|
|
48
|
+
"""当前或祖先 RunContext 是否已请求取消(无 context 则为 False)。
|
|
49
|
+
|
|
50
|
+
祖先链:nested Parallelization ctx 下 leaf 可读到 L0 ``cancel_requested``。
|
|
51
|
+
"""
|
|
49
52
|
from .run_context import get_run_context
|
|
50
53
|
|
|
51
54
|
ctx = get_run_context()
|
|
52
|
-
|
|
55
|
+
seen: set[int] = set()
|
|
56
|
+
while ctx is not None:
|
|
57
|
+
ident = id(ctx)
|
|
58
|
+
if ident in seen:
|
|
59
|
+
break
|
|
60
|
+
seen.add(ident)
|
|
61
|
+
if bool(ctx.cancel_requested):
|
|
62
|
+
return True
|
|
63
|
+
ctx = ctx.parent
|
|
64
|
+
return False
|
|
53
65
|
|
|
54
66
|
|
|
55
67
|
def abort_signal_for_phase(
|
|
@@ -12,6 +12,7 @@ run_context.py — Workflow/Agent 结构化并发上下文(parent → child ca
|
|
|
12
12
|
asyncio 为主;thread 仅 bounded join(无法强制中断 LLM);anyio/trio 不保证 context 传播。
|
|
13
13
|
P1:reset 失败时在仍可见 owner 的 derived logical context 内 force-clear;
|
|
14
14
|
宿主 detached ingest 用 create_task_with_copied_context / run_context_scope。
|
|
15
|
+
nested Parallelization:child_contexts + 递归 cancel_tree;W4 可用 use_cancel_authority。
|
|
15
16
|
"""
|
|
16
17
|
|
|
17
18
|
from __future__ import annotations
|
|
@@ -41,6 +42,10 @@ class RunContext:
|
|
|
41
42
|
root_task: asyncio.Task
|
|
42
43
|
child_tasks: set[asyncio.Task] = field(default_factory=set)
|
|
43
44
|
child_threads: set[threading.Thread] = field(default_factory=set)
|
|
45
|
+
# nested Parallelization/Chaining 再 install 时登记;cancel_tree 先深取消其 child_tasks。
|
|
46
|
+
# 用 list:RunContext 含 set/Task 不可哈希,不能放 set。
|
|
47
|
+
child_contexts: list["RunContext"] = field(default_factory=list, repr=False)
|
|
48
|
+
parent: Optional["RunContext"] = field(default=None, repr=False, compare=False)
|
|
44
49
|
cancel_requested: bool = False
|
|
45
50
|
# D-EVT-6:宿主在 cancel_tree / killAll 时写入;finish 投影读取;缺省 unknown。
|
|
46
51
|
# 取值:escape | workflow_stop | kill_agents | unknown;禁止从「是否有后台」猜测。
|
|
@@ -52,10 +57,42 @@ class RunContext:
|
|
|
52
57
|
def register_child_thread(self, thread: threading.Thread) -> None:
|
|
53
58
|
self.child_threads.add(thread)
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
def register_child_context(self, child: "RunContext") -> None:
|
|
61
|
+
"""登记 nested RunContext(install_run_context(parent=…))。"""
|
|
62
|
+
if all(existing is not child for existing in self.child_contexts):
|
|
63
|
+
self.child_contexts.append(child)
|
|
64
|
+
child.parent = self
|
|
65
|
+
|
|
66
|
+
def cancel_authority(self) -> "RunContext":
|
|
67
|
+
"""取消权威:最外层 RunContext(宿主 Stop / cancel_tree 目标)。"""
|
|
68
|
+
node: RunContext = self
|
|
69
|
+
seen: set[int] = set()
|
|
70
|
+
while node.parent is not None:
|
|
71
|
+
ident = id(node)
|
|
72
|
+
if ident in seen:
|
|
73
|
+
break
|
|
74
|
+
seen.add(ident)
|
|
75
|
+
node = node.parent
|
|
76
|
+
return node
|
|
77
|
+
|
|
78
|
+
def _mark_cancel_requested(self, *, source: str | None) -> None:
|
|
79
|
+
"""本层 + 全部 nested 写入 cancel_requested(协作闸可立即看到)。"""
|
|
56
80
|
self.cancel_requested = True
|
|
81
|
+
if source is not None and self.cancel_source is None:
|
|
82
|
+
self.cancel_source = source
|
|
83
|
+
for nested in list(self.child_contexts):
|
|
84
|
+
nested._mark_cancel_requested(source=source or self.cancel_source)
|
|
85
|
+
|
|
86
|
+
async def cancel_tree(self, timeout: float = 10.0) -> None:
|
|
87
|
+
"""取消本层 child_tasks,并递归 nested child_contexts(W4 / leaf producer)。"""
|
|
88
|
+
self._mark_cancel_requested(source=self.cancel_source)
|
|
57
89
|
deadline = time.monotonic() + timeout
|
|
58
90
|
|
|
91
|
+
# 深取消:先砍 nested 内 W4 producer,再 cancel 本层(含 nested.root_task)。
|
|
92
|
+
for nested in list(self.child_contexts):
|
|
93
|
+
remaining = max(0.0, deadline - time.monotonic())
|
|
94
|
+
await nested.cancel_tree(timeout=remaining)
|
|
95
|
+
|
|
59
96
|
for child in list(self.child_tasks):
|
|
60
97
|
child.cancel()
|
|
61
98
|
if self.child_tasks:
|
|
@@ -128,6 +165,7 @@ def install_run_context(
|
|
|
128
165
|
ctx = RunContext(root_task=current)
|
|
129
166
|
if parent is not None:
|
|
130
167
|
parent.register_child(ctx.root_task)
|
|
168
|
+
parent.register_child_context(ctx)
|
|
131
169
|
token = _current_run_context.set(ctx)
|
|
132
170
|
return ctx, token
|
|
133
171
|
|
|
@@ -205,15 +243,32 @@ async def drive_async_iterator_in_current_task(
|
|
|
205
243
|
yield item
|
|
206
244
|
|
|
207
245
|
|
|
246
|
+
def resolve_cancel_authority(
|
|
247
|
+
ctx: RunContext | None = None,
|
|
248
|
+
) -> RunContext | None:
|
|
249
|
+
"""解析取消权威 ctx;缺省取当前 ContextVar 的 outermost。"""
|
|
250
|
+
current = ctx if ctx is not None else get_run_context()
|
|
251
|
+
if current is None:
|
|
252
|
+
return None
|
|
253
|
+
return current.cancel_authority()
|
|
254
|
+
|
|
255
|
+
|
|
208
256
|
def register_spawned_task(
|
|
209
257
|
task: asyncio.Task,
|
|
210
258
|
*,
|
|
211
259
|
owner: RunContext | None = None,
|
|
260
|
+
use_cancel_authority: bool = False,
|
|
212
261
|
) -> None:
|
|
213
|
-
"""将 spawn 出的 asyncio task 注册到 RunContext(无 context 时 no-op)。
|
|
262
|
+
"""将 spawn 出的 asyncio task 注册到 RunContext(无 context 时 no-op)。
|
|
263
|
+
|
|
264
|
+
``use_cancel_authority=True``:挂到 outermost(Workflow W4),避免仅挂在
|
|
265
|
+
nested Parallelization ctx 上导致 L0 ``cancel_tree`` 砍不到 producer。
|
|
266
|
+
"""
|
|
214
267
|
ctx = owner if owner is not None else get_run_context()
|
|
215
268
|
if ctx is None:
|
|
216
269
|
return
|
|
270
|
+
if use_cancel_authority:
|
|
271
|
+
ctx = ctx.cancel_authority()
|
|
217
272
|
try:
|
|
218
273
|
owner_loop = ctx.root_task.get_loop()
|
|
219
274
|
task_loop = task.get_loop()
|
|
@@ -249,5 +304,6 @@ __all__ = [
|
|
|
249
304
|
"register_spawned_task",
|
|
250
305
|
"register_spawned_thread",
|
|
251
306
|
"reset_run_context",
|
|
307
|
+
"resolve_cancel_authority",
|
|
252
308
|
"run_context_scope",
|
|
253
309
|
]
|
|
@@ -445,7 +445,9 @@ class WorkflowAgentLoopExecutor:
|
|
|
445
445
|
await queue.put(None)
|
|
446
446
|
|
|
447
447
|
task = asyncio.create_task(_producer())
|
|
448
|
-
|
|
448
|
+
# W4:挂到 cancel authority(outermost),避免 Parallelization nested
|
|
449
|
+
# install 后 L0.cancel_tree 只看见 nested.root、砍不到 leaf producer。
|
|
450
|
+
register_spawned_task(task, use_cancel_authority=True)
|
|
449
451
|
try:
|
|
450
452
|
while True:
|
|
451
453
|
event = await queue.get()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
langchain_agentx/__init__.py,sha256=
|
|
1
|
+
langchain_agentx/__init__.py,sha256=P6NRAff0z_tvGxr7Vw8SjC7iBM818Lx6SXrGH9p_dvE,2014
|
|
2
2
|
langchain_agentx/command/__init__.py,sha256=Ej260S5uFQcmEtGZQG_NH7BYjHoStrpBLtGUsBTxyZk,631
|
|
3
3
|
langchain_agentx/command/allowed_tools.py,sha256=TVA0VM8rm98H-QbLK_GRiX5RhEAZFxKawliMi4kk96A,3359
|
|
4
4
|
langchain_agentx/command/context.py,sha256=DIGOGPBw5UGDBm0WNNJlKx1h_9rCRmcdROv4DT61Qug,731
|
|
@@ -28,9 +28,9 @@ langchain_agentx/health/models.py,sha256=lHwdvn0w-qs-c8mI6I3nlnoCk8--y7gADj7C9u7
|
|
|
28
28
|
langchain_agentx/health/preflight.py,sha256=wGysAnhT-jR1LfyjdaX9diO573Zzt5Z1M3vxDbpdcK0,5612
|
|
29
29
|
langchain_agentx/loop/__init__.py,sha256=JoFPFrlllvGCYFEk2RUuqq9AfUIdLVSNbrRdTRy6g_I,1428
|
|
30
30
|
langchain_agentx/loop/benchmark_frozen_config.py,sha256=YI4IaDVMBOEucF36F2oNv5mw1TqMG_rm_LJSpKAnFWM,13942
|
|
31
|
-
langchain_agentx/loop/loop_abort.py,sha256=
|
|
31
|
+
langchain_agentx/loop/loop_abort.py,sha256=wFlvCLjE9Avs83_8hqmUq0DlP58LSjtxOge-g1K4oPQ,3547
|
|
32
32
|
langchain_agentx/loop/message_contract.py,sha256=Twl83TneU2PRdxgGRBxs6S9_ovRT6cb5WeCUzd6oJnE,2196
|
|
33
|
-
langchain_agentx/loop/run_context.py,sha256=
|
|
33
|
+
langchain_agentx/loop/run_context.py,sha256=CRzbzuQziFmjvTTgZ6ctKLGyvzsuqq_oDr9zhLOhFik,10940
|
|
34
34
|
langchain_agentx/loop/config/__init__.py,sha256=0pf3Mml7LZpQ1C3_AtROFQClrBQegaGCG4YCTfSr9v8,1137
|
|
35
35
|
langchain_agentx/loop/config/agent_config.py,sha256=tOnAHFor6dkle3FvUOVx0YsmiYVTH11UrWSyTmOLV0c,3100
|
|
36
36
|
langchain_agentx/loop/config/compaction_config.py,sha256=MmXqY47-9nPDhdXvnU92Xp0XeaZ605ErQwX9d2emEkM,1176
|
|
@@ -778,7 +778,7 @@ langchain_agentx/workflow/catalog_registry.py,sha256=tYUny5FkHwQU-RRUxOdxaJhiRV_
|
|
|
778
778
|
langchain_agentx/workflow/dag.py,sha256=Y1IR1IwnM79Xuev6HZnOvAE3Q23MRnA9lu4vg2Cie48,4469
|
|
779
779
|
langchain_agentx/workflow/display_enricher.py,sha256=2HJ4xJI8H4hwBoWHAi6D_LwE-dcbZD_pafnS7DMDYZ4,6147
|
|
780
780
|
langchain_agentx/workflow/display_resolver.py,sha256=hEaljqprjubG82zeqLOEeQ32AMAxaZwvwaLq3v-yt3c,10119
|
|
781
|
-
langchain_agentx/workflow/execution.py,sha256=
|
|
781
|
+
langchain_agentx/workflow/execution.py,sha256=1exCcD1zxZ8vSx4js6ygnJ4xXAnK1UwT8rpIAYAfxxc,19155
|
|
782
782
|
langchain_agentx/workflow/loop_factory.py,sha256=hCShf_gDnesW2A9JspaUY3upp3NCIguII_wRiXnSIUM,3954
|
|
783
783
|
langchain_agentx/workflow/memory_drain_registry.py,sha256=Xm_ytbB-BbRIu3-h-KhptsCsmmueOiNZePUuG1hk8zk,1681
|
|
784
784
|
langchain_agentx/workflow/memory_session_policy.py,sha256=2FI0ZbAA6MnxJexnLYLadQpiqipPQwVnUrTWgl55A74,3333
|
|
@@ -837,8 +837,8 @@ langchain_agentx/workspace/root_grant_manager.py,sha256=W3gy8HTevbERbXqIgRcjzOXO
|
|
|
837
837
|
langchain_agentx/workspace/tool_boundary.py,sha256=UDwX6swpSLsx9HNkYuuRRiV5o7ZZG_Bru2Yn0c5kNX8,5724
|
|
838
838
|
langchain_agentx/workspace/validators.py,sha256=tQt-6TOcL8Fw7Ig5ebA9S7vGWh1rby920eFW6x8Tk9E,1439
|
|
839
839
|
langchain_agentx/workspace/view.py,sha256=PGasqTaqhlD03SXXazHuw4RHfV681AIdlsYqL70pEjc,4774
|
|
840
|
-
langchain_agentx_python-2.3.
|
|
841
|
-
langchain_agentx_python-2.3.
|
|
842
|
-
langchain_agentx_python-2.3.
|
|
843
|
-
langchain_agentx_python-2.3.
|
|
844
|
-
langchain_agentx_python-2.3.
|
|
840
|
+
langchain_agentx_python-2.3.9.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
841
|
+
langchain_agentx_python-2.3.9.dist-info/METADATA,sha256=pwTUN5gZ5zW2jrl7nwOYxD53dZUKhEEkZu19bdqS7Ew,23971
|
|
842
|
+
langchain_agentx_python-2.3.9.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
|
|
843
|
+
langchain_agentx_python-2.3.9.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
|
|
844
|
+
langchain_agentx_python-2.3.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{langchain_agentx_python-2.3.8.dist-info → langchain_agentx_python-2.3.9.dist-info}/top_level.txt
RENAMED
|
File without changes
|