langchain-agentx-python 2.1.0__py3-none-any.whl → 2.1.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.1.0"
14
+ __version__ = "2.1.1"
15
15
 
16
16
  from .loop import ( # noqa: F401
17
17
  create_loop_agent,
@@ -91,7 +91,7 @@ class SubagentContext:
91
91
  parent_tool_call_id: str | None = None # 触发本子 Agent 的 tool_call_id
92
92
  parent_conversation_session_id: str | None = None
93
93
  enable_trace: bool = True
94
- runnable_config: Any = None # 父 graph runnable_config,用于子 graph 事件自动冒泡到父 graph
94
+ runnable_config: Any = None # 父 runnable_config:仅供 tool_progress custom event 回调链;非子 raw 合并
95
95
  isolation: str = "none"
96
96
  worktree_dir: str | None = None
97
97
  workspace_root: str = ""
@@ -307,7 +307,8 @@ class SubagentOrchestrator:
307
307
  ) -> "AgentToolOutput":
308
308
  """异步执行子代理。
309
309
 
310
- 子 graph 事件通过 config 自动冒泡到父 graph,无需手动回调。
310
+ 子 graph 在独立 LoopStreamDriver 消费(Phase-4);progress 经 custom event 冒泡,
311
+ 裸子 on_tool_* 不并进父 astream。
311
312
  """
312
313
  from langchain_agentx.tools.agent.models import AgentToolOutput
313
314
 
@@ -595,7 +596,7 @@ class SubagentOrchestrator:
595
596
  ) -> Any:
596
597
  """异步启动子 agent。
597
598
 
598
- 子 graph 事件通过 config 自动冒泡到父 graph。
599
+ 子 graph Phase-4 独立 Driver 消费;progress 经 custom event 冒泡到父流。
599
600
  """
600
601
  owner_run_ctx = get_run_context()
601
602
  handle = self._register_background_agent(
@@ -226,7 +226,7 @@ async def _emit_progress(
226
226
  """发射子 Agent teaser lane 到父 graph(CC 对齐:仅 tool_use / tool_result)。
227
227
 
228
228
  同步 dispatch 优先:并行线程池 / _run_coroutine_sync 子线程内 adispatch 无法触达父回调链。
229
- graph 的 config 通过 ctx.runnable_config 传递(在 _collect_subagent_events 中合并)。
229
+ 父 config ctx.runnable_config 仅服务 custom event 派发(Phase-4 不合并父 callbacks)。
230
230
  """
231
231
  if event.type not in ("tool_use", "tool_result"):
232
232
  return
@@ -219,6 +219,10 @@ class AgentEventProjector:
219
219
  self.enable_subagent_events: bool = config.get("enable_subagent_events", True)
220
220
  self.synthesize_tool_call: bool = config.get("synthesize_tool_call", True)
221
221
  self.enable_tool_input_start: bool = config.get("enable_tool_input_start", False)
222
+ # Doc-34 F5:活跃子窗内抑制非 Agent 主台 tool-*(默认 on;关则恢复旧投影)
223
+ self.suppress_subagent_child_main_tier_tools: bool = bool(
224
+ config.get("suppress_subagent_child_main_tier_tools", True)
225
+ )
222
226
  self.filter_unparented_subgraph_events: bool = config.get(
223
227
  "filter_unparented_subgraph_events", False
224
228
  )
@@ -528,9 +532,17 @@ class AgentEventProjector:
528
532
  self._sync_accumulated_answer_mirror()
529
533
 
530
534
  def _should_suppress_main_tier_text_stream(self) -> bool:
531
- """D28 SDK-1:子 Agent 窗口内不 emit 父 main-tier TEXT_* / REASONING_*。"""
535
+ """Doc-33:子 Agent 窗口内不 emit 父 main-tier TEXT_* / REASONING_*。"""
532
536
  return self.state.subagent_window_text_guard.should_suppress_main_tier_stream
533
537
 
538
+ def _should_suppress_main_tier_child_tool_events(self, tool_name: str) -> bool:
539
+ """Doc-34 F2/F3/F5:flag on 且非 Agent 且 open_runs>0 → 抑制主台 tool-*。"""
540
+ if not self.suppress_subagent_child_main_tier_tools:
541
+ return False
542
+ if self._is_agent_tool(tool_name):
543
+ return False
544
+ return self.state.subagent_window_text_guard.should_suppress_main_tier_tool_events
545
+
534
546
  def _on_subagent_start_boundary(self) -> None:
535
547
  self.state.subagent_window_text_guard.on_subagent_start()
536
548
 
@@ -888,6 +900,7 @@ class AgentEventProjector:
888
900
  messages=messages if isinstance(messages, list) else None,
889
901
  )
890
902
  self._closeout_saw_finish_emitted = True
903
+ self.state.subagent_window_text_guard.warn_if_unbalanced_at_finish(logger)
891
904
  yield self._event(
892
905
  event_type=LangchainAgentEventType.FINISH,
893
906
  data=finish_data,
@@ -1113,6 +1126,16 @@ class AgentEventProjector:
1113
1126
 
1114
1127
  self.state.current_tool = name
1115
1128
 
1129
+ # Doc-34 F2:非 Agent 且窗开 → 在任何 TOOL_INPUT_* / TOOL_CALL 之前 return
1130
+ if self._should_suppress_main_tier_child_tool_events(name):
1131
+ self.state.subagent_window_text_guard.note_suppressed_child_tool_start()
1132
+ logger.debug(
1133
+ "Doc-34: suppress main-tier tool_start name=%s open_runs=%s",
1134
+ name,
1135
+ self.state.subagent_window_text_guard.open_runs,
1136
+ )
1137
+ return
1138
+
1116
1139
  if self.enable_tool_input_start:
1117
1140
  yield self._event(
1118
1141
  event_type=LangchainAgentEventType.TOOL_INPUT_START,
@@ -1192,6 +1215,11 @@ class AgentEventProjector:
1192
1215
  data = event.get("data", {}) or {}
1193
1216
  tool_call_id = ToolCallIdResolver.resolve_from_langgraph_tool_event(event)
1194
1217
 
1218
+ # Doc-34 F2:窗内非 Agent 对称抑制 RESULT/ERROR(不碰 Agent end → on_subagent_end)
1219
+ if self._should_suppress_main_tier_child_tool_events(name):
1220
+ self.state.current_tool = None
1221
+ return
1222
+
1195
1223
  output = data.get("output")
1196
1224
 
1197
1225
  event_type, event_data = self._classify_tool_end_event(
@@ -1,14 +1,17 @@
1
1
  """
2
- subagent_window_text_guard.py — D28 SDK-1 子 Agent 窗口 main-tier 流抑制
2
+ subagent_window_text_guard.py — 子 Agent 窗口 main-tier 抑制闸门
3
3
 
4
- 职责:跟踪 open subagent 计数;窗口内禁止父 adapter emit TEXT_* / REASONING_*,
5
- Agent 正文仅经 SUBAGENT_TRANSCRIPT / subagent-tool-* progress 冒泡。
6
- 链路位置:AgentEventProjector._handle_model_stream / _handle_model_end
7
- 当前裁剪范围:SUBAGENT_START/END 计数;不新增 subagent-text-delta 事件类型
4
+ 职责:跟踪 open subagent 计数(open_runs SSOT);
5
+ Doc-33:窗内抑制 TEXT_* / REASONING_*;
6
+ Doc-34:窗内抑制非 Agent 主台 tool-*(分属性 API,共用 open_runs);
7
+ Phase 2:非平衡 END / finish 扫尾轻诊断 + 抑制计数。
8
+ 链路位置:AgentEventProjector model_stream / tool_start/_end / FINISH
9
+ 当前裁剪范围:不引入 Registry 独窗;不做 D3 漏网 B 改写
8
10
  """
9
11
 
10
12
  from __future__ import annotations
11
13
 
14
+ import logging
12
15
  from dataclasses import dataclass
13
16
  from typing import TYPE_CHECKING
14
17
 
@@ -18,9 +21,11 @@ if TYPE_CHECKING:
18
21
 
19
22
  @dataclass
20
23
  class SubagentWindowTextGuard:
21
- """D28:子 Agent 运行窗口内抑制父 main-tier 流式正文。"""
24
+ """ Agent 运行窗口:text / tool 分属性抑制,共用 open_runs。"""
22
25
 
23
26
  open_runs: int = 0
27
+ suppressed_child_tool_starts: int = 0
28
+ unbalanced_end_count: int = 0
24
29
 
25
30
  def on_subagent_start(self) -> None:
26
31
  self.open_runs += 1
@@ -28,11 +33,45 @@ class SubagentWindowTextGuard:
28
33
  def on_subagent_end(self) -> None:
29
34
  if self.open_runs > 0:
30
35
  self.open_runs -= 1
36
+ return
37
+ self.unbalanced_end_count += 1
38
+
39
+ def note_suppressed_child_tool_start(self) -> None:
40
+ """Doc-34:窗内抑制了一次主台子工具 on_tool_start(B 抵达但被闸)。"""
41
+ self.suppressed_child_tool_starts += 1
31
42
 
32
43
  @property
33
44
  def should_suppress_main_tier_stream(self) -> bool:
45
+ """Doc-33:窗内抑制 main-tier TEXT_* / REASONING_*。"""
46
+ return self.open_runs > 0
47
+
48
+ @property
49
+ def should_suppress_main_tier_tool_events(self) -> bool:
50
+ """Doc-34(F3):窗内抑制非 Agent 主台 tool-*;与 stream 分属性、共用 open_runs。"""
34
51
  return self.open_runs > 0
35
52
 
53
+ def warn_if_unbalanced_at_finish(self, log: logging.Logger | None = None) -> None:
54
+ """FINISH 扫尾:缺 END 导致 open_runs 僵死,或多余 END。"""
55
+ active = log or logging.getLogger(__name__)
56
+ if self.open_runs > 0:
57
+ active.warning(
58
+ "SubagentWindowTextGuard: open_runs=%s at FINISH "
59
+ "(missing SUBAGENT_END; parent tools may stay suppressed)",
60
+ self.open_runs,
61
+ )
62
+ if self.unbalanced_end_count > 0:
63
+ active.warning(
64
+ "SubagentWindowTextGuard: unbalanced SUBAGENT_END count=%s "
65
+ "(END without matching START)",
66
+ self.unbalanced_end_count,
67
+ )
68
+ if self.suppressed_child_tool_starts > 0:
69
+ active.debug(
70
+ "SubagentWindowTextGuard: suppressed_child_tool_starts=%s "
71
+ "(Doc-34 B path reached projector but was gated)",
72
+ self.suppressed_child_tool_starts,
73
+ )
74
+
36
75
  def reset_active_stream_flags(self, state: EventAdapterState) -> None:
37
76
  """抑制 emit 时清理由半开 stream 留下的 active 标志(不补发 END)。"""
38
77
  state.is_reasoning_active = False
@@ -285,8 +285,8 @@ class AgentRuntimeTool(RuntimeTool):
285
285
  async def ainvoke(self, data: dict[str, Any], ctx: ToolExecutionContext) -> AgentToolOutput:
286
286
  """异步执行子 Agent。
287
287
 
288
- 子 graph 事件通过 config 自动冒泡到父 graphrunner.py 合并父 runnable_config),
289
- 无需手动 bubble
288
+ 子 graph 在独立 LoopStreamDriver 内消费 astream_eventsPhase-4 源头隔离);
289
+ tool_progress / transcript 经 custom event 冒泡到父流,裸 on_tool_* 不并进父 astream
290
290
 
291
291
  CC 对照:AgentTool.tsx call() 中 onProgress → createProgressMessage → stream.enqueue
292
292
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langchain-agentx-python
3
- Version: 2.1.0
3
+ Version: 2.1.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=CgHyU18uWVbXjHg_5d0L50y28LboDeAoFspC7YP5mk0,1678
1
+ langchain_agentx/__init__.py,sha256=HR2GxgZ6DS54PYkZLAbryBGZGrh2SOYkxP73uKeSEsI,1678
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
@@ -141,19 +141,19 @@ langchain_agentx/loop/subagent/active_run_registry.py,sha256=KurhAMDTBnRkdxNidaM
141
141
  langchain_agentx/loop/subagent/async_runner.py,sha256=y8Ke8nMi2XwdsrTKHCdOtIdr9hc-B1iGTAgMoVceapk,8692
142
142
  langchain_agentx/loop/subagent/boundary_snapshot.py,sha256=9cQuqN29nJDRnHnx9c8b09KRmODE2zv15Z06QyjVJps,10008
143
143
  langchain_agentx/loop/subagent/cache_safe_params.py,sha256=-qcgdazEYRy6s4ILQuttpxraE3gsxq17Ro7LYBnuv3E,4460
144
- langchain_agentx/loop/subagent/context.py,sha256=3ho_iZwHu3Ydz-4ZXJWCUeEuLe53VXAk8goBfdv0uiY,22290
144
+ langchain_agentx/loop/subagent/context.py,sha256=skkSPvnshEN4Lh5kWoD7zjUtCOKcjdb4Ho1eM1apXFo,22297
145
145
  langchain_agentx/loop/subagent/display_projector.py,sha256=AKsGWS1c9reH0kuD5u4oQ24KsBgyt7X10iZM3ere6Fs,3504
146
146
  langchain_agentx/loop/subagent/fork_boilerplate.py,sha256=2Uh3cwegL7V-DvtLIxjX7ik5uW5mXfY2NBzP-biREso,5005
147
147
  langchain_agentx/loop/subagent/fork_ports.py,sha256=hZATCvlYOxNVZtR3PoOVbI1GkA0KhHEyux6lUIjG5_4,1323
148
148
  langchain_agentx/loop/subagent/fork_worktree_notice.py,sha256=WKAJVxvRMJfbzRe_07Mgrm_zQIQCYx4RwsUnWSSOnkg,1389
149
149
  langchain_agentx/loop/subagent/forked_runner.py,sha256=ZEwkNlbwp1-PlJB5COHMKUu_w8EnSMLRc8s0umZ4NuM,6667
150
150
  langchain_agentx/loop/subagent/graph.py,sha256=EbwEE9A1-pDdLADsGdWuNQwl-cw7j1_Xia5lW7Wb-kQ,5215
151
- langchain_agentx/loop/subagent/orchestrator.py,sha256=Eyy9SA1AuX_uafWYMEVK-n6qPpSkuOJqvMwfzQGpOj4,30969
151
+ langchain_agentx/loop/subagent/orchestrator.py,sha256=LZcwnR5YnXGq_qC-ueOkV3Tv061RUomUcCcqip882GQ,31062
152
152
  langchain_agentx/loop/subagent/progress.py,sha256=_4YCDnVDH8sBiwXhCQVB8OHaUQwsCOGdUTP_Z_yOdsU,6522
153
153
  langchain_agentx/loop/subagent/progress_dispatcher.py,sha256=e1Kd16WRUOAJSeAjupukrlxHoyCR_JO84SHqntMCzdQ,3831
154
154
  langchain_agentx/loop/subagent/prompt.py,sha256=p7RgzibNfEJdfX8nBnZGEwQLa3_EgOn4E56T9MBRIEc,1722
155
155
  langchain_agentx/loop/subagent/reasoning_extractor.py,sha256=KrCQtBdKzsjAEfA7H5COuXzBhuGGonT2Su8IEKYlUpA,1334
156
- langchain_agentx/loop/subagent/runner.py,sha256=rjWtFKf2NgtLQax8nhlKQhlFVQuJeP8JvtuuhkJLbyM,29323
156
+ langchain_agentx/loop/subagent/runner.py,sha256=40jIJsTJcJTOFbMELB283YSPQIBCs_zXyABznpBOE0U,29325
157
157
  langchain_agentx/loop/subagent/subagent_termination_classifier.py,sha256=ULArQeAibgy6ETSf4vRR0L6X1rsDM7-ZuLzRWQ_pmeY,3158
158
158
  langchain_agentx/loop/subagent/transcript.py,sha256=-S0VjZcvqlJQGkVGu8VDMTYwTwOePdjDHfjYi3uu7BY,7187
159
159
  langchain_agentx/loop/subagent/transcript_message_builder.py,sha256=gcDdbVOospJ9f0b-eM_0Y1uc4yTstaraWZdejokDyDQ,2081
@@ -217,7 +217,7 @@ langchain_agentx/observability/evaluation/checkers/tool_behavior.py,sha256=o1nH8
217
217
  langchain_agentx/observability/events/__init__.py,sha256=9IfY3IcALgQjxdsircWrwTCFuSwr8MTKBDstC8CXPHY,1051
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=RN1bS9-A-XI_AZYguraVtfcQ4OvEvDxnAWhn0NKySIU,60600
220
+ langchain_agentx/observability/events/agent_event_projector.py,sha256=0xm_lWv5wtlhI05aL08yPSwTuA_Gj4cDXB00ni5bihI,62075
221
221
  langchain_agentx/observability/events/api_retry_projection.py,sha256=XGb09sNOi6k1ZGW4YqMLBE8GDxNwNMprk62jV9TS9dQ,2433
222
222
  langchain_agentx/observability/events/factory.py,sha256=gqMATIK9tBQzaPWSPhCCSPuCq-WF562ZDTnFUaMm9Qc,1570
223
223
  langchain_agentx/observability/events/finish_event_payload_composer.py,sha256=W4jLFy6868GX122qljjeLJowsG7g26o4eKVbHEa7DJc,11481
@@ -225,7 +225,7 @@ langchain_agentx/observability/events/finish_outcome.py,sha256=I1-1RKQYMRXA5Kw0w
225
225
  langchain_agentx/observability/events/langchain_agentx_event_adapter.py,sha256=plPZpoqYwDFR_XgdjH5NMQnl_oO6-rixBNl4sGJ0XRw,7519
226
226
  langchain_agentx/observability/events/model_end_text_backfill.py,sha256=7RBnxWLi1Oe-Bw9WTYqN-B6IdytFlY-Jso1STtQr6rE,5157
227
227
  langchain_agentx/observability/events/subagent_event_mapper.py,sha256=9M9cKzMz7_OXOod0JKtLb-FtUhAKiAVikKGRF6h6Ttk,6860
228
- langchain_agentx/observability/events/subagent_window_text_guard.py,sha256=yOlhWFKOij98Rdn6knBIk2FUQpSGaBbob7d4U49tEmM,1372
228
+ langchain_agentx/observability/events/subagent_window_text_guard.py,sha256=myo4SSV2TKZjpyrCoe-g5beNGmZnYZefa8nqW76q0Xc,3101
229
229
  langchain_agentx/observability/events/tool_call_id_resolver.py,sha256=Mun8jNb91tbV7hvIUkFG9g6NJGHVMW0kHS7Zt6N2gUA,4530
230
230
  langchain_agentx/observability/events/tool_outcome_resolver.py,sha256=YqF9Io9-0xdIdz7iYQuJkY-PiUXLC0zR26Eb9n35L9g,4357
231
231
  langchain_agentx/observability/events/workflow_aware_event_adapter.py,sha256=GlKN4vQcnXUSC9vcBWbrg4B6Td3aglzcOr4zDUfsXXw,7490
@@ -501,7 +501,7 @@ langchain_agentx/tools/agent/models.py,sha256=jPxah6JgPt0UlZVyrAQxQeZmVUDOBV7xyl
501
501
  langchain_agentx/tools/agent/prompt.py,sha256=QQA40AfA5sEIl_LG7kn7UlUKFBOzsHSs_M8c5n-p7YU,8093
502
502
  langchain_agentx/tools/agent/prompt_scope.py,sha256=xQup3hosuN0B6TFq7jYV5SE6gzZNwR6BOQ552dfef5I,2677
503
503
  langchain_agentx/tools/agent/scope.py,sha256=6F2ZJgSvt-gFeciyKIQxaIiW5PBW9zUeTj3P0uxqrrg,6324
504
- langchain_agentx/tools/agent/tool.py,sha256=FfL8sfxgFryDLvs-q83tOQJugBFhRu-TQQSZTnvOXiI,16705
504
+ langchain_agentx/tools/agent/tool.py,sha256=kRKnS-xCUtLyAWhkizlDsQo5cXjH5f4QNF7O8EDXXws,16778
505
505
  langchain_agentx/tools/agent/built_in/__init__.py,sha256=4YUHj8nUcUOvJW9p158W_t_RBoQt8Uh7eTt0idnCTE4,657
506
506
  langchain_agentx/tools/agent/built_in/agentx_guide.py,sha256=Wz4791lK_URpAGtKWceEMvJlD_cu79KfmNQka5yXeUs,2719
507
507
  langchain_agentx/tools/agent/built_in/explore.py,sha256=H5757yjmudceFVaMN0O4YDH267DKfFPMSxGR83waNkk,3504
@@ -752,8 +752,8 @@ langchain_agentx/workspace/root_grant_manager.py,sha256=W3gy8HTevbERbXqIgRcjzOXO
752
752
  langchain_agentx/workspace/tool_boundary.py,sha256=UDwX6swpSLsx9HNkYuuRRiV5o7ZZG_Bru2Yn0c5kNX8,5724
753
753
  langchain_agentx/workspace/validators.py,sha256=tQt-6TOcL8Fw7Ig5ebA9S7vGWh1rby920eFW6x8Tk9E,1439
754
754
  langchain_agentx/workspace/view.py,sha256=PGasqTaqhlD03SXXazHuw4RHfV681AIdlsYqL70pEjc,4774
755
- langchain_agentx_python-2.1.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
756
- langchain_agentx_python-2.1.0.dist-info/METADATA,sha256=TdLyMypNyg3psJwPdU3votemXhPzWi1HQkEH7qm03Ww,24844
757
- langchain_agentx_python-2.1.0.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
758
- langchain_agentx_python-2.1.0.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
759
- langchain_agentx_python-2.1.0.dist-info/RECORD,,
755
+ langchain_agentx_python-2.1.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
756
+ langchain_agentx_python-2.1.1.dist-info/METADATA,sha256=2NbkPmSmd1eLI1GDFHMWqUIDLyh9t0c7DKJvxlHDwcA,24844
757
+ langchain_agentx_python-2.1.1.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
758
+ langchain_agentx_python-2.1.1.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
759
+ langchain_agentx_python-2.1.1.dist-info/RECORD,,