langchain-agentx-python 2.2.0__py3-none-any.whl → 2.2.1__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.2.0"
14
+ __version__ = "2.2.1"
15
15
 
16
16
  from .loop import ( # noqa: F401
17
17
  create_loop_agent,
@@ -3,8 +3,8 @@ scope_resolver.py — Workflow event adapter active scope 解析
3
3
 
4
4
  职责:
5
5
  - 根据 WorkflowStack.build_path() 从 flat scopes[path] registry 解析当前 active scope
6
- - public orphan path miss hard-fail
7
- - internal 尾段 path miss 时 warn + registered ancestor 回退(A00 P-LOSSY / P-EXEC
6
+ - miss 时按 D-SCOPE-A′ 降级到最近非 root / 非 workflow_root 已注册祖先
7
+ - 无非 root 祖先时 hard-fail(禁 blanket root
8
8
 
9
9
  链路位置:
10
10
  - Layer 3: Workflow 事件适配器
@@ -14,18 +14,18 @@ scope_resolver.py — Workflow event adapter active scope 解析
14
14
  - 仅 dict lookup,不扫描 workflow 实例或 graph
15
15
  - scope key 与 WorkflowStack.build_path() / RuntimeScopePath.key() 一致
16
16
  - legacy config 无 scopes 时由 root 字段合成仅含 root 的 registry
17
- - 禁止 blanket root 兜底;无 registered 祖先时仍 raise
17
+ - 禁止把 root degrade 目标;与 SessionRouter 共享 nearest_degrade_ancestor
18
18
  """
19
19
 
20
20
  from __future__ import annotations
21
21
 
22
22
  import logging
23
+ from collections.abc import Callable
23
24
  from typing import Any
24
25
 
25
26
  from langchain_agentx.workflow.runtime_scope_registry import resolve_effective_scopes
26
27
  from langchain_agentx.workflow.structure_errors import WorkflowScopeResolutionError
27
28
 
28
- from .depth_resolver import LANGGRAPH_INTERNAL_LOOP_NODE_NAMES
29
29
  from .stack import WorkflowStack
30
30
 
31
31
  logger = logging.getLogger(__name__)
@@ -34,9 +34,30 @@ _SCOPE_METADATA_FIELDS = frozenset(
34
34
  {"workflow_id", "scope_key", "scope_kind", "scope_origin", "graph_key"}
35
35
  )
36
36
 
37
+ ScopeLookup = Callable[[str], dict[str, Any] | None]
37
38
 
38
- def _path_tail_segment(scope_key: str) -> str:
39
- return scope_key.rsplit(">", 1)[-1]
39
+
40
+ def nearest_degrade_ancestor(
41
+ path: str,
42
+ *,
43
+ root_scope: str,
44
+ lookup: ScopeLookup,
45
+ ) -> dict[str, Any] | None:
46
+ """沿 '>' 前缀向上;跳过 root_scope / workflow_root(D-SCOPE-A′ · 禁 blanket root)。"""
47
+ if ">" not in path:
48
+ return None
49
+ parts = path.split(">")
50
+ for depth in range(len(parts) - 1, 0, -1):
51
+ prefix = ">".join(parts[:depth])
52
+ if prefix == root_scope:
53
+ continue
54
+ entry = lookup(prefix)
55
+ if entry is None:
56
+ continue
57
+ if entry.get("scope_kind") == "workflow_root":
58
+ continue
59
+ return entry
60
+ return None
40
61
 
41
62
 
42
63
  class WorkflowScopeResolver:
@@ -51,6 +72,12 @@ class WorkflowScopeResolver:
51
72
  root_scope=self._root_scope,
52
73
  )
53
74
  self._scope_misses: list[str] = []
75
+ self._degrade_warned_paths: set[str] = set()
76
+
77
+ @property
78
+ def root_scope(self) -> str:
79
+ """开流 root_scope(SessionRouter 祖先 walk 唯一来源)。"""
80
+ return self._root_scope
54
81
 
55
82
  @property
56
83
  def scope_misses(self) -> tuple[str, ...]:
@@ -81,16 +108,13 @@ class WorkflowScopeResolver:
81
108
 
82
109
  self._record_scope_miss(scope_key)
83
110
 
84
- if not self._is_internal_path_miss(scope_key):
85
- raise self._build_scope_resolution_error(scope_key)
86
-
87
- ancestor = self._nearest_registered_ancestor_entry()
111
+ ancestor = nearest_degrade_ancestor(
112
+ scope_key,
113
+ root_scope=self._root_scope,
114
+ lookup=self.scope_entry_at,
115
+ )
88
116
  if ancestor is not None:
89
- logger.warning(
90
- "workflow scope miss degraded to ancestor: path=%r ancestor=%r",
91
- scope_key,
92
- ancestor.get("scope_key"),
93
- )
117
+ self._warn_degraded_once(scope_key, ancestor)
94
118
  return ancestor
95
119
 
96
120
  raise self._build_scope_resolution_error(scope_key)
@@ -103,22 +127,15 @@ class WorkflowScopeResolver:
103
127
  if key not in _SCOPE_METADATA_FIELDS
104
128
  }
105
129
 
106
- def _is_internal_path_miss(self, scope_key: str) -> bool:
107
- """miss path 末段为 internal loop 节点 → 视为 internal 误抬,可降级。"""
108
- if ">" not in scope_key:
109
- return False
110
- return _path_tail_segment(scope_key) in LANGGRAPH_INTERNAL_LOOP_NODE_NAMES
111
-
112
- def _nearest_registered_ancestor_entry(self) -> dict[str, Any] | None:
113
- """沿 build_path() 的 '>' 分段前缀向上 walk,返回首个 scope_entry_at 命中。"""
114
- scope_key = self.current_scope_key()
115
- parts = scope_key.split(">")
116
- for depth in range(len(parts) - 1, 0, -1):
117
- prefix = ">".join(parts[:depth])
118
- entry = self.scope_entry_at(prefix)
119
- if entry is not None:
120
- return entry
121
- return None
130
+ def _warn_degraded_once(self, scope_key: str, ancestor: dict[str, Any]) -> None:
131
+ if scope_key in self._degrade_warned_paths:
132
+ return
133
+ self._degrade_warned_paths.add(scope_key)
134
+ logger.warning(
135
+ "workflow scope miss degraded to ancestor: path=%r ancestor=%r",
136
+ scope_key,
137
+ ancestor.get("scope_key"),
138
+ )
122
139
 
123
140
  def _build_scope_resolution_error(self, scope_key: str) -> WorkflowScopeResolutionError:
124
141
  detail_parts = [
@@ -144,4 +161,8 @@ class WorkflowScopeResolver:
144
161
  )
145
162
 
146
163
 
147
- __all__ = ["WorkflowScopeResolver", "WorkflowScopeResolutionError"]
164
+ __all__ = [
165
+ "WorkflowScopeResolver",
166
+ "WorkflowScopeResolutionError",
167
+ "nearest_degrade_ancestor",
168
+ ]
@@ -13,6 +13,7 @@ session_router.py — Workflow 结构/agent 事件 session_id 路由
13
13
  当前裁剪范围:
14
14
  - 结构容器事件仍走 stack/path;agent/loop 事件优先无状态 resolve_loop_session_id_for_event
15
15
  - aggregate 使用 aggregate_key 作为 task_key,无 special case
16
+ - D-SCOPE-A-SESSION:ns path 精确 miss 时与 ScopeResolver 同 walk(排除 root)
16
17
  """
17
18
 
18
19
  from __future__ import annotations
@@ -20,7 +21,7 @@ from __future__ import annotations
20
21
  from typing import Any
21
22
 
22
23
  from .depth_resolver import DepthResolver
23
- from .scope_resolver import WorkflowScopeResolver
24
+ from .scope_resolver import WorkflowScopeResolver, nearest_degrade_ancestor
24
25
  from .stack import WorkflowStack
25
26
  from .types import WorkflowEvent, WorkflowEventType
26
27
 
@@ -130,6 +131,12 @@ class WorkflowSessionRouter:
130
131
  scope_path = self._scope_path_from_raw_event(raw_event)
131
132
  if scope_path:
132
133
  entry = self._scope_resolver.scope_entry_at(scope_path)
134
+ if entry is None:
135
+ entry = nearest_degrade_ancestor(
136
+ scope_path,
137
+ root_scope=self._scope_resolver.root_scope,
138
+ lookup=self._scope_resolver.scope_entry_at,
139
+ )
133
140
  if entry is not None:
134
141
  return self._loop_session_from_scope_entry(
135
142
  entry,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langchain-agentx-python
3
- Version: 2.2.0
3
+ Version: 2.2.1
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=_jWRBw5rNM52V1JxowuR91v-mVr2N_1x-Adhgz-4XrU,1614
1
+ langchain_agentx/__init__.py,sha256=MJpPR7tuUrTR76iSfQUpDD67ydVKB93o5UEY78FBs28,1614
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
@@ -724,8 +724,8 @@ langchain_agentx/workflow/validation.py,sha256=3I2jrSgOLAufe3kIzftE_Tfq0ZS-74bIx
724
724
  langchain_agentx/workflow/event_adapter/__init__.py,sha256=PkG6dP5mAjukYOFEtNFVDn00q_zPmS506dapZxpDgG8,1736
725
725
  langchain_agentx/workflow/event_adapter/adapter.py,sha256=eoOgcSos_cu12BRg3a4P0lQvarwr9jCcgt3OrC68A58,25188
726
726
  langchain_agentx/workflow/event_adapter/depth_resolver.py,sha256=1xI44dNk9cPotmk1Up14s0QV12WpkRPAQPYnVDY3ZlQ,3991
727
- langchain_agentx/workflow/event_adapter/scope_resolver.py,sha256=8KzflPIy0Y7PgX8xjgvEQD6_zzYEDL0oqxquhuA3wHA,5510
728
- langchain_agentx/workflow/event_adapter/session_router.py,sha256=0ih5_VxVb1_CWeUvz_qQIT14Mo0Oq7KZ22x1W__8hys,8915
727
+ langchain_agentx/workflow/event_adapter/scope_resolver.py,sha256=J4duUIdMfNB87zq_0q2sGBgokg0t0UIaxlBGRYJEv7w,5813
728
+ langchain_agentx/workflow/event_adapter/session_router.py,sha256=v2MZieOXDpcioeskSFswnXGKtT_Aw0M0sY9W3oCFmUY,9292
729
729
  langchain_agentx/workflow/event_adapter/stack.py,sha256=VCpJekxlGOg0CU2Unxcq7-TeyAHUajPyakKoGnUlT7g,4396
730
730
  langchain_agentx/workflow/event_adapter/structure_lifecycle_guard.py,sha256=0inUI-fw-xgWQHuGVVoWRM3a_gpys9JgvOxG5P4bTdw,6658
731
731
  langchain_agentx/workflow/event_adapter/structure_utils.py,sha256=y2gS-Tj9FajAqP8kgygaxrosVIRYNjhEtpnp-OIccB8,2820
@@ -759,8 +759,8 @@ langchain_agentx/workspace/root_grant_manager.py,sha256=W3gy8HTevbERbXqIgRcjzOXO
759
759
  langchain_agentx/workspace/tool_boundary.py,sha256=UDwX6swpSLsx9HNkYuuRRiV5o7ZZG_Bru2Yn0c5kNX8,5724
760
760
  langchain_agentx/workspace/validators.py,sha256=tQt-6TOcL8Fw7Ig5ebA9S7vGWh1rby920eFW6x8Tk9E,1439
761
761
  langchain_agentx/workspace/view.py,sha256=PGasqTaqhlD03SXXazHuw4RHfV681AIdlsYqL70pEjc,4774
762
- langchain_agentx_python-2.2.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
763
- langchain_agentx_python-2.2.0.dist-info/METADATA,sha256=nn2x47UdjwxReSgREvpk012hKVMAXtw303b9JRhUdAM,24250
764
- langchain_agentx_python-2.2.0.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
765
- langchain_agentx_python-2.2.0.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
766
- langchain_agentx_python-2.2.0.dist-info/RECORD,,
762
+ langchain_agentx_python-2.2.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
763
+ langchain_agentx_python-2.2.1.dist-info/METADATA,sha256=UfgeVWTPqOZJ3Nps3E7gtcupQdCo0YhTRY8uLS3uUiM,24250
764
+ langchain_agentx_python-2.2.1.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
765
+ langchain_agentx_python-2.2.1.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
766
+ langchain_agentx_python-2.2.1.dist-info/RECORD,,