langchain-agentx-python 2.2.1__py3-none-any.whl → 2.2.2__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/observability/events/agent_event_projector.py +36 -19
- langchain_agentx/observability/events/compact_event_gate.py +152 -0
- {langchain_agentx_python-2.2.1.dist-info → langchain_agentx_python-2.2.2.dist-info}/METADATA +1 -1
- {langchain_agentx_python-2.2.1.dist-info → langchain_agentx_python-2.2.2.dist-info}/RECORD +8 -7
- {langchain_agentx_python-2.2.1.dist-info → langchain_agentx_python-2.2.2.dist-info}/LICENSE +0 -0
- {langchain_agentx_python-2.2.1.dist-info → langchain_agentx_python-2.2.2.dist-info}/WHEEL +0 -0
- {langchain_agentx_python-2.2.1.dist-info → langchain_agentx_python-2.2.2.dist-info}/top_level.txt +0 -0
langchain_agentx/__init__.py
CHANGED
|
@@ -51,6 +51,12 @@ from langchain_agentx.observability.events.agent_defaults import DEFAULT_AGENT_T
|
|
|
51
51
|
from langchain_agentx.observability.events.subagent_window_text_guard import (
|
|
52
52
|
SubagentWindowTextGuard,
|
|
53
53
|
)
|
|
54
|
+
from langchain_agentx.observability.events.compact_event_gate import (
|
|
55
|
+
beneficial_light_stage_names,
|
|
56
|
+
extract_compaction_meta_from_chain_end_data,
|
|
57
|
+
is_user_visible_compact,
|
|
58
|
+
light_only_with_benefit,
|
|
59
|
+
)
|
|
54
60
|
from langchain_agentx.observability.events.tool_call_id_resolver import (
|
|
55
61
|
ToolCallIdResolver,
|
|
56
62
|
)
|
|
@@ -121,8 +127,7 @@ class LangchainAgentEventType(Enum):
|
|
|
121
127
|
FINISH_STEP = "finish-step"
|
|
122
128
|
HOOK_PROGRESS = "hook-progress"
|
|
123
129
|
HOOK_FINISHED = "hook-finished"
|
|
124
|
-
|
|
125
|
-
COMPACT_END = "compact-end"
|
|
130
|
+
COMPACT_BOUNDARY = "compact-boundary"
|
|
126
131
|
MEMORY_SAVED = "memory-saved"
|
|
127
132
|
SUBAGENT_START = "subagent-start"
|
|
128
133
|
SUBAGENT_END = "subagent-end"
|
|
@@ -396,12 +401,7 @@ class AgentEventProjector:
|
|
|
396
401
|
step_index=self.state.step_index or None,
|
|
397
402
|
)
|
|
398
403
|
|
|
399
|
-
|
|
400
|
-
yield self._event(
|
|
401
|
-
event_type=LangchainAgentEventType.COMPACT_START,
|
|
402
|
-
data={},
|
|
403
|
-
step_index=self.state.step_index or None,
|
|
404
|
-
)
|
|
404
|
+
# D-CMP-EVT:不在 start 发 compact(CC 无 start/end;事后单边界)
|
|
405
405
|
|
|
406
406
|
def _build_loop_observation_payload(self) -> Dict[str, Any]:
|
|
407
407
|
snap = self.state.last_loop_snapshot or {}
|
|
@@ -752,7 +752,6 @@ class AgentEventProjector:
|
|
|
752
752
|
result["tokens_freed"] = meta.get("tokens_freed_sum")
|
|
753
753
|
|
|
754
754
|
stages = meta.get("stages")
|
|
755
|
-
autocompact_found = False
|
|
756
755
|
microcompact_found = False
|
|
757
756
|
|
|
758
757
|
if isinstance(stages, list):
|
|
@@ -761,7 +760,6 @@ class AgentEventProjector:
|
|
|
761
760
|
name = s.get("name")
|
|
762
761
|
extra = s.get("extra") or {}
|
|
763
762
|
if name == "autocompact":
|
|
764
|
-
autocompact_found = True
|
|
765
763
|
result["autocompact_mode"] = extra.get("autocompact_mode")
|
|
766
764
|
result["folded_messages"] = extra.get("folded_messages")
|
|
767
765
|
result["messages_summarized"] = extra.get("folded_messages")
|
|
@@ -782,10 +780,12 @@ class AgentEventProjector:
|
|
|
782
780
|
break
|
|
783
781
|
|
|
784
782
|
if "compact_type" not in result:
|
|
785
|
-
|
|
783
|
+
mode = result.get("autocompact_mode")
|
|
784
|
+
if isinstance(mode, str) and mode:
|
|
786
785
|
result["compact_type"] = "autocompact"
|
|
787
|
-
|
|
786
|
+
elif microcompact_found:
|
|
788
787
|
result["compact_type"] = "microcompact"
|
|
788
|
+
# 不再用「stages 出现过 autocompact 名」回落为 autocompact(假阳性)
|
|
789
789
|
|
|
790
790
|
if "summary" not in result:
|
|
791
791
|
messages = output.get("messages")
|
|
@@ -848,13 +848,30 @@ class AgentEventProjector:
|
|
|
848
848
|
step_index=self.state.step_index or None,
|
|
849
849
|
)
|
|
850
850
|
|
|
851
|
-
if self.
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
851
|
+
if self._is_compact_node(name):
|
|
852
|
+
meta = extract_compaction_meta_from_chain_end_data(data)
|
|
853
|
+
if is_user_visible_compact(meta):
|
|
854
|
+
if self.enable_compact_events:
|
|
855
|
+
compact_data = self._extract_compact_summary(data)
|
|
856
|
+
if "trigger" not in compact_data:
|
|
857
|
+
compact_data["trigger"] = "auto"
|
|
858
|
+
yield self._event(
|
|
859
|
+
event_type=LangchainAgentEventType.COMPACT_BOUNDARY,
|
|
860
|
+
data=compact_data,
|
|
861
|
+
step_index=self.state.step_index or None,
|
|
862
|
+
)
|
|
863
|
+
elif light_only_with_benefit(meta):
|
|
864
|
+
# D-CMP-EVT-7:对齐 CC logForDebugging;不受 enable_compact_events 关闭影响
|
|
865
|
+
freed = None
|
|
866
|
+
if isinstance(meta, dict):
|
|
867
|
+
freed = meta.get("tokens_freed_sum")
|
|
868
|
+
stages = beneficial_light_stage_names(meta)
|
|
869
|
+
logger.debug(
|
|
870
|
+
"compact light-only: tokens_freed_sum=%s stages=%s "
|
|
871
|
+
"(no public compact-boundary; align CC logForDebugging)",
|
|
872
|
+
freed,
|
|
873
|
+
stages or None,
|
|
874
|
+
)
|
|
858
875
|
|
|
859
876
|
if name == self.state.graph_name:
|
|
860
877
|
if self.enable_reasoning_events and self.state.is_reasoning_active:
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""
|
|
2
|
+
compact_event_gate.py — compact 公共事件门闩(对齐 CC compact_boundary)
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
- 从 compaction_pipeline_meta 判定是否用户可见真压缩 / light-only 有收益
|
|
6
|
+
- 供 agent_event_projector 发射 compact-boundary 或 logger.debug
|
|
7
|
+
|
|
8
|
+
链路位置:
|
|
9
|
+
- Layer 3: observability/events 投影门闩(不改 L0 压缩流水线)
|
|
10
|
+
|
|
11
|
+
当前裁剪范围:
|
|
12
|
+
- 仅 meta 谓词;不创建 SSE 以外的事件类型
|
|
13
|
+
- session_memory applied 仅识别显式标记(字段可后续扩展)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Any, Optional
|
|
19
|
+
|
|
20
|
+
from langchain_agentx.loop.exit.query_source import QuerySource
|
|
21
|
+
|
|
22
|
+
# 实际折叠上下文的 autocompact_mode(不含仅 skipped)
|
|
23
|
+
APPLIED_AUTOCOMPACT_MODES: frozenset[str] = frozenset(
|
|
24
|
+
{
|
|
25
|
+
"llm",
|
|
26
|
+
"prune",
|
|
27
|
+
"prune_blocked_llm",
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
_LIGHT_STAGE_NAMES: frozenset[str] = frozenset(
|
|
32
|
+
{
|
|
33
|
+
"tool_result_budget",
|
|
34
|
+
"snip",
|
|
35
|
+
"microcompact",
|
|
36
|
+
"collapse",
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _as_dict(meta: Any) -> Optional[dict[str, Any]]:
|
|
42
|
+
return meta if isinstance(meta, dict) else None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _stage_extra(stage: dict[str, Any]) -> dict[str, Any]:
|
|
46
|
+
extra = stage.get("extra")
|
|
47
|
+
return extra if isinstance(extra, dict) else {}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _positive_number(value: Any) -> bool:
|
|
51
|
+
if value is None:
|
|
52
|
+
return False
|
|
53
|
+
try:
|
|
54
|
+
return float(value) > 0
|
|
55
|
+
except (TypeError, ValueError):
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def is_user_visible_compact(meta: Any) -> bool:
|
|
60
|
+
"""真压缩已应用 → 应对齐 CC 发一条 compact-boundary。
|
|
61
|
+
|
|
62
|
+
禁止用 tokens_freed_sum / stages 仅出现 autocompact 名 / compact_type 回落判定。
|
|
63
|
+
"""
|
|
64
|
+
m = _as_dict(meta)
|
|
65
|
+
if m is None:
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
# Session / 手动:L0 现网键(factory session_memory 路径无 stages[])
|
|
69
|
+
if m.get("session_memory_compact_applied") is True:
|
|
70
|
+
return True
|
|
71
|
+
if m.get("manual_compact_applied") is True:
|
|
72
|
+
return True
|
|
73
|
+
if m.get("session_memory_compaction") == "applied":
|
|
74
|
+
return True
|
|
75
|
+
if m.get("autocompact_mode") == QuerySource.SESSION_MEMORY:
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
stages = m.get("stages")
|
|
79
|
+
if not isinstance(stages, list):
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
for stage in stages:
|
|
83
|
+
if not isinstance(stage, dict):
|
|
84
|
+
continue
|
|
85
|
+
name = stage.get("name")
|
|
86
|
+
extra = _stage_extra(stage)
|
|
87
|
+
if name == "autocompact":
|
|
88
|
+
mode = extra.get("autocompact_mode")
|
|
89
|
+
if isinstance(mode, str) and mode in APPLIED_AUTOCOMPACT_MODES:
|
|
90
|
+
return True
|
|
91
|
+
if name == QuerySource.SESSION_MEMORY and extra.get("applied") is True:
|
|
92
|
+
return True
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def light_only_with_benefit(meta: Any) -> bool:
|
|
97
|
+
"""非用户可见,但有轻量 stage(或 sum)释放 token → 应对齐 CC logForDebugging。"""
|
|
98
|
+
if is_user_visible_compact(meta):
|
|
99
|
+
return False
|
|
100
|
+
m = _as_dict(meta)
|
|
101
|
+
if m is None:
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
stages = m.get("stages")
|
|
105
|
+
if isinstance(stages, list):
|
|
106
|
+
for stage in stages:
|
|
107
|
+
if not isinstance(stage, dict):
|
|
108
|
+
continue
|
|
109
|
+
if _positive_number(stage.get("tokens_freed")):
|
|
110
|
+
return True
|
|
111
|
+
# micro 规范化标记但 tokens 估计可能为 0:仍视为有 light 动作时可记
|
|
112
|
+
name = stage.get("name")
|
|
113
|
+
extra = _stage_extra(stage)
|
|
114
|
+
if name == "microcompact" and extra.get("microcompact_normalized"):
|
|
115
|
+
return True
|
|
116
|
+
|
|
117
|
+
return _positive_number(m.get("tokens_freed_sum"))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def beneficial_light_stage_names(meta: Any) -> list[str]:
|
|
121
|
+
"""有收益的轻量 stage 名(供 debug 文案)。"""
|
|
122
|
+
m = _as_dict(meta)
|
|
123
|
+
if m is None:
|
|
124
|
+
return []
|
|
125
|
+
names: list[str] = []
|
|
126
|
+
stages = m.get("stages")
|
|
127
|
+
if not isinstance(stages, list):
|
|
128
|
+
return names
|
|
129
|
+
for stage in stages:
|
|
130
|
+
if not isinstance(stage, dict):
|
|
131
|
+
continue
|
|
132
|
+
name = stage.get("name")
|
|
133
|
+
if not isinstance(name, str):
|
|
134
|
+
continue
|
|
135
|
+
extra = _stage_extra(stage)
|
|
136
|
+
freed = _positive_number(stage.get("tokens_freed"))
|
|
137
|
+
micro = name == "microcompact" and bool(extra.get("microcompact_normalized"))
|
|
138
|
+
if freed or micro:
|
|
139
|
+
if name in _LIGHT_STAGE_NAMES or freed or micro:
|
|
140
|
+
names.append(name)
|
|
141
|
+
return names
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def extract_compaction_meta_from_chain_end_data(data: Any) -> Optional[dict[str, Any]]:
|
|
145
|
+
"""从 on_chain_end data 取出 compaction_pipeline_meta。"""
|
|
146
|
+
if not isinstance(data, dict):
|
|
147
|
+
return None
|
|
148
|
+
output = data.get("output")
|
|
149
|
+
if not isinstance(output, dict):
|
|
150
|
+
return None
|
|
151
|
+
meta = output.get("compaction_pipeline_meta")
|
|
152
|
+
return meta if isinstance(meta, dict) else None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
langchain_agentx/__init__.py,sha256=
|
|
1
|
+
langchain_agentx/__init__.py,sha256=CeiwdY0JNT9SJDHhM5_WnrLFW0CaC3PjbVuO98Owi1o,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
|
|
@@ -217,8 +217,9 @@ langchain_agentx/observability/evaluation/checkers/tool_behavior.py,sha256=o1nH8
|
|
|
217
217
|
langchain_agentx/observability/events/__init__.py,sha256=Zr9Iguf9XsJQLsCJy13YFdBtXHPEnI9aSWXWmA2MisA,1497
|
|
218
218
|
langchain_agentx/observability/events/accumulated_text_scope.py,sha256=M4OvuQTgReF8SFrOmr-M5vyOJpzfvxj_DKD5bVpGb70,3169
|
|
219
219
|
langchain_agentx/observability/events/agent_defaults.py,sha256=gmX0P__lux5xbCb8dtAlVCb3wZ7avaqFleoW4Q5anw4,1187
|
|
220
|
-
langchain_agentx/observability/events/agent_event_projector.py,sha256=
|
|
220
|
+
langchain_agentx/observability/events/agent_event_projector.py,sha256=Rktmy2D3qizCejAChbuOiAa06Tnup2Z6cVNATfrrxkU,63995
|
|
221
221
|
langchain_agentx/observability/events/api_retry_projection.py,sha256=XGb09sNOi6k1ZGW4YqMLBE8GDxNwNMprk62jV9TS9dQ,2433
|
|
222
|
+
langchain_agentx/observability/events/compact_event_gate.py,sha256=50RJemwB1lnQn_NFWOFSgU418ZUR8dbd_v0538PT7zM,4751
|
|
222
223
|
langchain_agentx/observability/events/factory.py,sha256=gqMATIK9tBQzaPWSPhCCSPuCq-WF562ZDTnFUaMm9Qc,1570
|
|
223
224
|
langchain_agentx/observability/events/finish_event_payload_composer.py,sha256=v7MyLNSZ_gR5u5WFxPJu_0MYNDvC9s9gI2iNNt9Vbr4,13189
|
|
224
225
|
langchain_agentx/observability/events/finish_outcome.py,sha256=igoueAwduzuuGDwg6u9AbBB-T2UBiqbUfNoxWCBYc_g,10401
|
|
@@ -759,8 +760,8 @@ langchain_agentx/workspace/root_grant_manager.py,sha256=W3gy8HTevbERbXqIgRcjzOXO
|
|
|
759
760
|
langchain_agentx/workspace/tool_boundary.py,sha256=UDwX6swpSLsx9HNkYuuRRiV5o7ZZG_Bru2Yn0c5kNX8,5724
|
|
760
761
|
langchain_agentx/workspace/validators.py,sha256=tQt-6TOcL8Fw7Ig5ebA9S7vGWh1rby920eFW6x8Tk9E,1439
|
|
761
762
|
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.
|
|
763
|
+
langchain_agentx_python-2.2.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
764
|
+
langchain_agentx_python-2.2.2.dist-info/METADATA,sha256=YHgIChmc4fVyfDcUNs9faXXrRAdOrZ8CF3db6Wnw-JY,24250
|
|
765
|
+
langchain_agentx_python-2.2.2.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
|
|
766
|
+
langchain_agentx_python-2.2.2.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
|
|
767
|
+
langchain_agentx_python-2.2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{langchain_agentx_python-2.2.1.dist-info → langchain_agentx_python-2.2.2.dist-info}/top_level.txt
RENAMED
|
File without changes
|