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.
@@ -11,7 +11,7 @@ from langchain_agentx import create_loop_agent
11
11
  ```
12
12
  """
13
13
 
14
- __version__ = "2.3.8"
14
+ __version__ = "2.3.9"
15
15
 
16
16
  from .mcp.call import McpToolCaller
17
17
  from .mcp.client_manager import McpClientManager, McpConnectedClient
@@ -45,11 +45,23 @@ class LoopAbortSignal(Exception):
45
45
 
46
46
 
47
47
  def is_cancel_requested() -> bool:
48
- """当前 RunContext 是否已请求取消(无 context 则为 False)。"""
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
- return ctx is not None and bool(ctx.cancel_requested)
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
- async def cancel_tree(self, timeout: float = 10.0) -> None:
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
- register_spawned_task(task)
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langchain-agentx-python
3
- Version: 2.3.8
3
+ Version: 2.3.9
4
4
  Summary: LangChain/LangGraph-based agent utilities for CodeBaseX.
5
5
  Author-email: GoodMood2008 <GoodMood2008@users.noreply.github.com>
6
6
  License: Apache License
@@ -1,4 +1,4 @@
1
- langchain_agentx/__init__.py,sha256=gtvKFAWnCZTzCzgO9-k_SOm0i5QAt-QQKXfYx8noXtw,2014
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=cKlHxZh0u7-drCVqEiRtzkO270MHw6grJuZ1NpKoGfo,3250
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=dhNiLhvqD_QYacGMA0B5P3wWpSe3O6wU_XcVEzb86Z4,8303
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=iCEkPgLkaoEM4cB6o7KAqIaBpFuY5HtGGISMNm0tr4A,18954
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.8.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
841
- langchain_agentx_python-2.3.8.dist-info/METADATA,sha256=LQpK-C85dJ_lAdk9w7weRSeVJKKWJzEnBuDdytblGEY,23971
842
- langchain_agentx_python-2.3.8.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
843
- langchain_agentx_python-2.3.8.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
844
- langchain_agentx_python-2.3.8.dist-info/RECORD,,
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,,