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.
- langchain_agentx/__init__.py +1 -1
- langchain_agentx/workflow/event_adapter/scope_resolver.py +53 -32
- langchain_agentx/workflow/event_adapter/session_router.py +8 -1
- {langchain_agentx_python-2.2.0.dist-info → langchain_agentx_python-2.2.1.dist-info}/METADATA +1 -1
- {langchain_agentx_python-2.2.0.dist-info → langchain_agentx_python-2.2.1.dist-info}/RECORD +8 -8
- {langchain_agentx_python-2.2.0.dist-info → langchain_agentx_python-2.2.1.dist-info}/LICENSE +0 -0
- {langchain_agentx_python-2.2.0.dist-info → langchain_agentx_python-2.2.1.dist-info}/WHEEL +0 -0
- {langchain_agentx_python-2.2.0.dist-info → langchain_agentx_python-2.2.1.dist-info}/top_level.txt +0 -0
langchain_agentx/__init__.py
CHANGED
|
@@ -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
|
-
-
|
|
7
|
-
-
|
|
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
|
-
-
|
|
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
|
-
|
|
39
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
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
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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__ = [
|
|
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,4 +1,4 @@
|
|
|
1
|
-
langchain_agentx/__init__.py,sha256=
|
|
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=
|
|
728
|
-
langchain_agentx/workflow/event_adapter/session_router.py,sha256=
|
|
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.
|
|
763
|
-
langchain_agentx_python-2.2.
|
|
764
|
-
langchain_agentx_python-2.2.
|
|
765
|
-
langchain_agentx_python-2.2.
|
|
766
|
-
langchain_agentx_python-2.2.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
{langchain_agentx_python-2.2.0.dist-info → langchain_agentx_python-2.2.1.dist-info}/top_level.txt
RENAMED
|
File without changes
|