langchain-agentx-python 2.3.7__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.7"
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
  ]
@@ -127,6 +127,11 @@ class SubagentContext:
127
127
  inherit_hooks: bool | frozenset[HookEvent] | None = True
128
128
  """True/None → DEFAULT_SUBAGENT_INHERITED_EVENTS;False → 不继承;frozenset → 自定义事件集。"""
129
129
 
130
+ progress_host_kind: str | None = None
131
+ """Skill fork:``skill_progress`` 时 runner 只冒泡 CC 同构 skill progress,不发 subagent 双通道。"""
132
+ skill_prompt: str = ""
133
+ """Skill fork:↔ CC ``onProgress`` ``data.prompt``(skill 正文)。"""
134
+
130
135
 
131
136
  @dataclass
132
137
  class SubagentResult:
@@ -25,7 +25,7 @@ from langchain_agentx.loop.runtime.subagent_execution_paths import (
25
25
  resolve_subagent_effective_cwd,
26
26
  resolve_subagent_workspace_root,
27
27
  )
28
- from langchain_agentx.loop.subagent.context import create_subagent_context
28
+ from langchain_agentx.loop.subagent.context import SubagentContext, create_subagent_context
29
29
  from langchain_agentx.loop.subagent.hooks_pipeline import (
30
30
  _apply_agent_frontmatter_hooks as _pipeline_apply_agent_hooks,
31
31
  _apply_skill_fork_hooks as _pipeline_apply_skill_hooks,
@@ -54,6 +54,23 @@ from langchain_agentx.observability.logging import ObservabilityLoggerAdapter, b
54
54
  from langchain_agentx.workspace import resolve_agent_state_config
55
55
  from langchain_agentx.loop.config.thinking_config import ThinkingConfig
56
56
 
57
+
58
+ def _apply_skill_fork_progress_host(
59
+ subagent_ctx: SubagentContext,
60
+ *,
61
+ skill_hook_frontmatter: dict[str, Any] | None,
62
+ skill_prompt: str,
63
+ ) -> None:
64
+ """Skill fork:注入 CC 同构 skill_progress 冒泡上下文(Phase A · L8/L9)。"""
65
+ if skill_hook_frontmatter is None:
66
+ return
67
+ from langchain_agentx.tools.skill.fork import is_fork_execution_context
68
+
69
+ if is_fork_execution_context(skill_hook_frontmatter):
70
+ subagent_ctx.progress_host_kind = "skill_progress"
71
+ subagent_ctx.skill_prompt = skill_prompt or ""
72
+
73
+
57
74
  if TYPE_CHECKING:
58
75
  from langchain_agentx.loop.runtime import AgentLoopConfig
59
76
  from langchain_agentx.tool_runtime.models import ToolExecutionContext
@@ -344,6 +361,11 @@ class SubagentOrchestrator:
344
361
  is_builtin_subagent=getattr(subagent_config, "is_builtin", False),
345
362
  inherit_hooks=True if inherit_hooks is None else inherit_hooks,
346
363
  )
364
+ _apply_skill_fork_progress_host(
365
+ subagent_ctx,
366
+ skill_hook_frontmatter=skill_hook_frontmatter,
367
+ skill_prompt=inp.prompt or "",
368
+ )
347
369
  subagent_ctx.mcp_child_session = mcp_child
348
370
  scope = propagate_subagent_tool_scope(
349
371
  parent_ctx=ctx,
@@ -564,6 +586,11 @@ class SubagentOrchestrator:
564
586
  is_builtin_subagent=getattr(subagent_config, "is_builtin", False),
565
587
  inherit_hooks=True if inherit_hooks is None else inherit_hooks,
566
588
  )
589
+ _apply_skill_fork_progress_host(
590
+ subagent_ctx,
591
+ skill_hook_frontmatter=skill_hook_frontmatter,
592
+ skill_prompt=inp.prompt or "",
593
+ )
567
594
  subagent_ctx.mcp_child_session = mcp_child
568
595
  scope = propagate_subagent_tool_scope(
569
596
  parent_ctx=ctx,
@@ -8,6 +8,8 @@ CC 对照:src/agent/subagent/progress.ts onProgress 回调参数类型
8
8
 
9
9
  # transcript lane 在 tool_progress custom event 上的 phase 值(与 adapter mapper 冻结一致)
10
10
  SUBAGENT_TRANSCRIPT_PHASE = "transcript_message"
11
+ # Skill fork CC 对齐:Typed Tool Progress(↔ CC data.type === 'skill_progress')
12
+ SKILL_PROGRESS_PHASE = "skill_progress"
11
13
 
12
14
  from dataclasses import dataclass, field
13
15
  from typing import Any, Literal
@@ -14,6 +14,7 @@ from typing import Any
14
14
 
15
15
  from langchain_agentx.loop.subagent.context import SubagentContext
16
16
  from langchain_agentx.loop.subagent.progress import (
17
+ SKILL_PROGRESS_PHASE,
17
18
  SUBAGENT_TRANSCRIPT_PHASE,
18
19
  SubagentProgressEvent,
19
20
  )
@@ -46,6 +47,31 @@ class SubagentProgressDispatcher:
46
47
  event_data["tool_input"] = dict(event.tool_call_detail.tool_input)
47
48
  return event_data
48
49
 
50
+ @staticmethod
51
+ def build_skill_progress_payload(
52
+ ctx: SubagentContext,
53
+ *,
54
+ message_kind: str,
55
+ message: dict[str, Any],
56
+ step: int,
57
+ tool_name: str,
58
+ agent_id: str,
59
+ ) -> dict[str, Any]:
60
+ return {
61
+ "tool_call_id": ctx.parent_tool_call_id,
62
+ "agent_id": agent_id,
63
+ "phase": SKILL_PROGRESS_PHASE,
64
+ "step": step,
65
+ "tool_name": tool_name,
66
+ "message_kind": message_kind,
67
+ "message": dict(message),
68
+ "prompt": str(getattr(ctx, "skill_prompt", "") or ""),
69
+ "data": {
70
+ "subagent_type": ctx.subagent_type,
71
+ "type": "skill_progress",
72
+ },
73
+ }
74
+
49
75
  @staticmethod
50
76
  def build_transcript_payload(
51
77
  ctx: SubagentContext,
@@ -265,6 +265,35 @@ async def _emit_progress(
265
265
  await SubagentProgressDispatcher.dispatch_async(parent_config, payload)
266
266
 
267
267
 
268
+ def _uses_skill_progress_host(ctx: SubagentContext) -> bool:
269
+ return getattr(ctx, "progress_host_kind", None) == "skill_progress"
270
+
271
+
272
+ async def _emit_skill_progress(
273
+ ctx: SubagentContext,
274
+ *,
275
+ message_kind: str,
276
+ message: dict[str, Any],
277
+ step: int,
278
+ tool_name: str,
279
+ ) -> None:
280
+ """Skill fork:单帧 CC 同构 skill_progress(L9 · 不发 subagent 双通道)。"""
281
+ parent_config = getattr(ctx, "runnable_config", None)
282
+ if parent_config is None:
283
+ return
284
+ payload = SubagentProgressDispatcher.build_skill_progress_payload(
285
+ ctx,
286
+ message_kind=message_kind,
287
+ message=message,
288
+ step=step,
289
+ tool_name=tool_name,
290
+ agent_id=ctx.agent_id,
291
+ )
292
+ if SubagentProgressDispatcher.dispatch_sync(parent_config, payload):
293
+ return
294
+ await SubagentProgressDispatcher.dispatch_async(parent_config, payload)
295
+
296
+
268
297
  async def _emit_transcript_progress(
269
298
  ctx: SubagentContext,
270
299
  event: SubagentProgressEvent,
@@ -322,6 +351,21 @@ async def _handle_tool_start_event(
322
351
  if not tool_call_id:
323
352
  tool_call_id = f"{SYNTHETIC_TRANSCRIPT_TOOL_ID_PREFIX}{ctx.agent_id}:{next_step}"
324
353
 
354
+ message_kind, normalized = SubagentTranscriptMessageBuilder.build_tool_use(
355
+ tool_name=tool_name,
356
+ tool_input=tool_input if isinstance(tool_input, dict) else None,
357
+ tool_call_id=tool_call_id,
358
+ )
359
+ if _uses_skill_progress_host(ctx):
360
+ await _emit_skill_progress(
361
+ ctx,
362
+ message_kind=message_kind,
363
+ message=normalized,
364
+ step=next_step,
365
+ tool_name=tool_name,
366
+ )
367
+ return next_step, tool_name
368
+
325
369
  await _emit_progress(
326
370
  ctx,
327
371
  SubagentProgressEvent(
@@ -335,12 +379,6 @@ async def _handle_tool_start_event(
335
379
  trace=trace,
336
380
  ),
337
381
  )
338
-
339
- message_kind, normalized = SubagentTranscriptMessageBuilder.build_tool_use(
340
- tool_name=tool_name,
341
- tool_input=tool_input if isinstance(tool_input, dict) else None,
342
- tool_call_id=tool_call_id,
343
- )
344
382
  await _emit_transcript_progress(
345
383
  ctx,
346
384
  SubagentProgressEvent(
@@ -419,6 +457,23 @@ async def _handle_tool_end_event(
419
457
  synthetic=synthetic,
420
458
  )
421
459
  transcript.append(msg_dict)
460
+
461
+ message_kind, normalized = SubagentTranscriptMessageBuilder.build_tool_result(
462
+ tool_name=tool_name,
463
+ content=transcript_text,
464
+ tool_call_id=tool_call_id,
465
+ synthetic=synthetic,
466
+ )
467
+ if _uses_skill_progress_host(ctx):
468
+ await _emit_skill_progress(
469
+ ctx,
470
+ message_kind=message_kind,
471
+ message=normalized,
472
+ step=step,
473
+ tool_name=tool_name,
474
+ )
475
+ return
476
+
422
477
  await _emit_progress(
423
478
  ctx,
424
479
  SubagentProgressEvent(
@@ -430,13 +485,6 @@ async def _handle_tool_end_event(
430
485
  summary=summary[:200] if summary else "",
431
486
  ),
432
487
  )
433
-
434
- message_kind, normalized = SubagentTranscriptMessageBuilder.build_tool_result(
435
- tool_name=tool_name,
436
- content=transcript_text,
437
- tool_call_id=tool_call_id,
438
- synthetic=synthetic,
439
- )
440
488
  await _emit_transcript_progress(
441
489
  ctx,
442
490
  SubagentProgressEvent(
@@ -38,6 +38,9 @@ from langchain_agentx.observability.events.model_end_text_backfill import (
38
38
  BackfillKind,
39
39
  ModelEndTextBackfillPolicy,
40
40
  )
41
+ from langchain_agentx.observability.events.skill_progress_event_mapper import (
42
+ SkillProgressEventMapper,
43
+ )
41
44
  from langchain_agentx.observability.events.subagent_event_mapper import (
42
45
  SubagentBoundaryPayloadBuilder,
43
46
  SubagentProgressEventMapper,
@@ -136,6 +139,7 @@ class LangchainAgentEventType(Enum):
136
139
  SUBAGENT_TOOL_RESULT = "subagent-tool-result"
137
140
  SUBAGENT_TRANSCRIPT_MESSAGE = "subagent-transcript-message"
138
141
  SUBAGENT_MODEL_STEP = "subagent-model-step"
142
+ SKILL_PROGRESS = "skill-progress"
139
143
  ERROR = "error"
140
144
  API_RETRY = "api-retry"
141
145
  ASSISTANT_TURN_SUPERSEDED = "assistant-turn-superseded"
@@ -1553,6 +1557,16 @@ class AgentEventProjector:
1553
1557
  if not isinstance(data, dict):
1554
1558
  return
1555
1559
 
1560
+ skill_mapped = SkillProgressEventMapper.map_custom_tool_progress(data)
1561
+ if skill_mapped is not None:
1562
+ yield self._event(
1563
+ event_type=skill_mapped.event_type,
1564
+ data=skill_mapped.data,
1565
+ step_index=self.state.step_index,
1566
+ tool_name=skill_mapped.tool_name,
1567
+ )
1568
+ return
1569
+
1556
1570
  if self.enable_subagent_events:
1557
1571
  mapped = SubagentProgressEventMapper.map_custom_tool_progress(data)
1558
1572
  if mapped is not None:
@@ -0,0 +1,87 @@
1
+ """
2
+ skill_progress_event_mapper.py — Skill fork tool_progress → skill-progress SSE
3
+
4
+ 职责:将 custom event ``tool_progress``(phase skill_progress)映射为 LangchainAgentEventType.SKILL_PROGRESS。
5
+ 链路位置:AgentEventProjector._handle_custom_event,优先于 SubagentProgressEventMapper。
6
+ 当前裁剪范围:仅 Skill fork progress;不含 Agent agent_progress(另轨 subagent-*)。
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from dataclasses import dataclass
12
+ from typing import Any, TYPE_CHECKING
13
+
14
+ # 与 loop.subagent.progress.SKILL_PROGRESS_PHASE 同值;此处不 import loop,避免 observability↔loop 循环依赖
15
+ _SKILL_PROGRESS_PHASE = "skill_progress"
16
+
17
+ if TYPE_CHECKING:
18
+ from langchain_agentx.observability.events.langchain_agentx_event_adapter import (
19
+ LangchainAgentEventType,
20
+ )
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class MappedSkillProgress:
25
+ event_type: "LangchainAgentEventType"
26
+ data: dict[str, Any]
27
+ tool_name: str | None
28
+
29
+
30
+ class SkillProgressEventMapper:
31
+ """Skill fork progress → ``skill-progress`` 公共协议。"""
32
+
33
+ @classmethod
34
+ def is_skill_progress_payload(cls, data: dict[str, Any]) -> bool:
35
+ if not isinstance(data, dict):
36
+ return False
37
+ phase = data.get("phase")
38
+ return isinstance(phase, str) and phase == _SKILL_PROGRESS_PHASE
39
+
40
+ @classmethod
41
+ def map_custom_tool_progress(
42
+ cls,
43
+ data: dict[str, Any],
44
+ ) -> MappedSkillProgress | None:
45
+ from langchain_agentx.observability.events.langchain_agentx_event_adapter import (
46
+ LangchainAgentEventType,
47
+ )
48
+
49
+ if not cls.is_skill_progress_payload(data):
50
+ return None
51
+
52
+ message = data.get("message")
53
+ if not isinstance(message, dict):
54
+ return None
55
+
56
+ message_kind = data.get("message_kind")
57
+ if message_kind not in ("assistant", "user"):
58
+ return None
59
+
60
+ agent_id = data.get("agent_id")
61
+ if not isinstance(agent_id, str) or not agent_id.strip():
62
+ return None
63
+
64
+ step_raw = data.get("step", 0)
65
+ step = int(step_raw) if isinstance(step_raw, (int, float)) else 0
66
+
67
+ event_data: dict[str, Any] = {
68
+ "tool_call_id": str(data.get("tool_call_id") or ""),
69
+ "agent_id": agent_id,
70
+ "type": "skill_progress",
71
+ "prompt": str(data.get("prompt") or ""),
72
+ "message_kind": message_kind,
73
+ "message": dict(message),
74
+ "step": step,
75
+ }
76
+ tool_name = str(data.get("tool_name") or "")
77
+ if tool_name:
78
+ event_data["tool_name"] = tool_name
79
+
80
+ return MappedSkillProgress(
81
+ event_type=LangchainAgentEventType.SKILL_PROGRESS,
82
+ data=event_data,
83
+ tool_name=tool_name or None,
84
+ )
85
+
86
+
87
+ __all__ = ["MappedSkillProgress", "SkillProgressEventMapper"]
@@ -12,6 +12,8 @@ from __future__ import annotations
12
12
  from dataclasses import dataclass
13
13
  from typing import Any, TYPE_CHECKING
14
14
 
15
+ _SKILL_PROGRESS_PHASE = "skill_progress"
16
+
15
17
  if TYPE_CHECKING:
16
18
  from langchain_agentx.observability.events.langchain_agentx_event_adapter import (
17
19
  LangchainAgentEventType,
@@ -21,7 +23,11 @@ _SUBAGENT_TRANSCRIPT_PHASE = "transcript_message"
21
23
 
22
24
  _SUBAGENT_TEASER_PHASES = frozenset({"tool_use", "tool_result"})
23
25
  _SUBAGENT_DROP_PHASES = frozenset({"model_step"})
24
- _SUBAGENT_KNOWN_PHASES = _SUBAGENT_TEASER_PHASES | _SUBAGENT_DROP_PHASES | {_SUBAGENT_TRANSCRIPT_PHASE}
26
+ _SUBAGENT_KNOWN_PHASES = (
27
+ _SUBAGENT_TEASER_PHASES
28
+ | _SUBAGENT_DROP_PHASES
29
+ | {_SUBAGENT_TRANSCRIPT_PHASE, _SKILL_PROGRESS_PHASE}
30
+ )
25
31
 
26
32
 
27
33
  @dataclass(frozen=True)
@@ -109,6 +115,9 @@ class SubagentProgressEventMapper:
109
115
  if not isinstance(phase, str):
110
116
  return None
111
117
 
118
+ if phase == _SKILL_PROGRESS_PHASE:
119
+ return None
120
+
112
121
  if phase == _SUBAGENT_TRANSCRIPT_PHASE:
113
122
  return cls._map_transcript(data, LangchainAgentEventType)
114
123
 
@@ -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.7
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=zQXChDyx78k93u07LSKkHsuhqm9jmU0_873Vc4IXRcI,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
@@ -146,7 +146,7 @@ langchain_agentx/loop/subagent/active_run_registry.py,sha256=KurhAMDTBnRkdxNidaM
146
146
  langchain_agentx/loop/subagent/async_runner.py,sha256=gGx8UMZbsnxUMPzc_7-XkWgd1EiuRcFAoOVUfjhFltE,13740
147
147
  langchain_agentx/loop/subagent/boundary_snapshot.py,sha256=9cQuqN29nJDRnHnx9c8b09KRmODE2zv15Z06QyjVJps,10008
148
148
  langchain_agentx/loop/subagent/cache_safe_params.py,sha256=-qcgdazEYRy6s4ILQuttpxraE3gsxq17Ro7LYBnuv3E,4460
149
- langchain_agentx/loop/subagent/context.py,sha256=oupi8suTfCINUiWwDhfRbFFzRE-w26SXi8Hfz22xR2U,23729
149
+ langchain_agentx/loop/subagent/context.py,sha256=tR2QQfNBKci0_rOm6e_p5wNXlo1gZntHpgkFfIuTLHE,24000
150
150
  langchain_agentx/loop/subagent/display_projector.py,sha256=AKsGWS1c9reH0kuD5u4oQ24KsBgyt7X10iZM3ere6Fs,3504
151
151
  langchain_agentx/loop/subagent/fork_boilerplate.py,sha256=2Uh3cwegL7V-DvtLIxjX7ik5uW5mXfY2NBzP-biREso,5005
152
152
  langchain_agentx/loop/subagent/fork_ports.py,sha256=hZATCvlYOxNVZtR3PoOVbI1GkA0KhHEyux6lUIjG5_4,1323
@@ -157,13 +157,13 @@ langchain_agentx/loop/subagent/hook_attachment_messages.py,sha256=em3VXaUfURou_Y
157
157
  langchain_agentx/loop/subagent/hooks_compose.py,sha256=enPKRsAbqjB5HqACE-YFzM8K3Job7azi4wpqI1kmgl8,2515
158
158
  langchain_agentx/loop/subagent/hooks_pipeline.py,sha256=4OweLS52TRbcaUO56YpE-qX71ZPCjPRS0j9KzIcx5ls,6399
159
159
  langchain_agentx/loop/subagent/mcp_child_servers.py,sha256=UJ9FtIZroYvP6KfNLUnHKbb7bqg2qSmo15MkzHcVKME,4395
160
- langchain_agentx/loop/subagent/orchestrator.py,sha256=XdGHFihgDc5O3U27fAf8jOin4oGNXexuqgDMeuBdrzM,40804
160
+ langchain_agentx/loop/subagent/orchestrator.py,sha256=35gaY6gzdlCxEogyYiTRos5KtSpsSOADJBZIHazsQbc,41785
161
161
  langchain_agentx/loop/subagent/parent_hook_snapshot.py,sha256=cwBC2eXvx1evc6QPpI42zq-iKThpObyoyWmkDNj9E7Q,2095
162
- langchain_agentx/loop/subagent/progress.py,sha256=_4YCDnVDH8sBiwXhCQVB8OHaUQwsCOGdUTP_Z_yOdsU,6522
163
- langchain_agentx/loop/subagent/progress_dispatcher.py,sha256=e1Kd16WRUOAJSeAjupukrlxHoyCR_JO84SHqntMCzdQ,3831
162
+ langchain_agentx/loop/subagent/progress.py,sha256=nef3VVT9QmB2ZWCDAO86cmtVwCJIR8lXMr6jczQKqOY,6650
163
+ langchain_agentx/loop/subagent/progress_dispatcher.py,sha256=KD5EdfoGplIaT8xvt5vgfXgSLPbvn9KqvY85wLpOX7A,4603
164
164
  langchain_agentx/loop/subagent/prompt.py,sha256=p7RgzibNfEJdfX8nBnZGEwQLa3_EgOn4E56T9MBRIEc,1722
165
165
  langchain_agentx/loop/subagent/reasoning_extractor.py,sha256=KrCQtBdKzsjAEfA7H5COuXzBhuGGonT2Su8IEKYlUpA,1334
166
- langchain_agentx/loop/subagent/runner.py,sha256=ms200D_0oM9Scqr1OmDd_va6ORAl_OB57RCqEeC9HtA,33736
166
+ langchain_agentx/loop/subagent/runner.py,sha256=GCYWWMZtkJRH8L1sJAwrVwe0yOqO-6kBT-6p5J1w_s0,35142
167
167
  langchain_agentx/loop/subagent/subagent_start_hooks.py,sha256=HIyW7_ta9JNxiyrgL8scNpZzcJrAyld4qaRehYx36GY,1359
168
168
  langchain_agentx/loop/subagent/subagent_termination_classifier.py,sha256=ULArQeAibgy6ETSf4vRR0L6X1rsDM7-ZuLzRWQ_pmeY,3158
169
169
  langchain_agentx/loop/subagent/transcript.py,sha256=-S0VjZcvqlJQGkVGu8VDMTYwTwOePdjDHfjYi3uu7BY,7187
@@ -264,7 +264,7 @@ langchain_agentx/observability/evaluation/checkers/tool_behavior.py,sha256=o1nH8
264
264
  langchain_agentx/observability/events/__init__.py,sha256=mORGJjMvJ6ob5tOqFOyyGhDLjK4gB-Q2HN0l-GPmamk,1624
265
265
  langchain_agentx/observability/events/accumulated_text_scope.py,sha256=M4OvuQTgReF8SFrOmr-M5vyOJpzfvxj_DKD5bVpGb70,3169
266
266
  langchain_agentx/observability/events/agent_defaults.py,sha256=gmX0P__lux5xbCb8dtAlVCb3wZ7avaqFleoW4Q5anw4,1187
267
- langchain_agentx/observability/events/agent_event_projector.py,sha256=Vsyd3XRFuN4ZoblCpOm1rZEUmEo1yu8DX9OyCXgsiPg,64726
267
+ langchain_agentx/observability/events/agent_event_projector.py,sha256=aWh3BsJyTmzcNdRlFXrvnLoCzNoJy9DX7mmFxvNcJYI,65285
268
268
  langchain_agentx/observability/events/api_retry_projection.py,sha256=XGb09sNOi6k1ZGW4YqMLBE8GDxNwNMprk62jV9TS9dQ,2433
269
269
  langchain_agentx/observability/events/compact_event_gate.py,sha256=50RJemwB1lnQn_NFWOFSgU418ZUR8dbd_v0538PT7zM,4751
270
270
  langchain_agentx/observability/events/factory.py,sha256=gqMATIK9tBQzaPWSPhCCSPuCq-WF562ZDTnFUaMm9Qc,1570
@@ -274,7 +274,8 @@ langchain_agentx/observability/events/langchain_agentx_event_adapter.py,sha256=u
274
274
  langchain_agentx/observability/events/mcp_event_sink.py,sha256=4gOS2_JfIGwr3bUWCH47H7uaztLypkfQ7Ews71Jbwn0,1989
275
275
  langchain_agentx/observability/events/model_end_text_backfill.py,sha256=7RBnxWLi1Oe-Bw9WTYqN-B6IdytFlY-Jso1STtQr6rE,5157
276
276
  langchain_agentx/observability/events/oob_event_sink.py,sha256=ijE2AI8gfoMPRPXDwQszNWi_aCKwODywpG884blo08E,5670
277
- langchain_agentx/observability/events/subagent_event_mapper.py,sha256=9M9cKzMz7_OXOod0JKtLb-FtUhAKiAVikKGRF6h6Ttk,6860
277
+ langchain_agentx/observability/events/skill_progress_event_mapper.py,sha256=3-TZcwOT57oSTxRu7GpUGbq_2wI6TimipTbM9dsaZmU,2878
278
+ langchain_agentx/observability/events/subagent_event_mapper.py,sha256=DihmbR3YZsb_xlNmbIbL5LsftEWNlbM5FHLqXcq7R0k,7009
278
279
  langchain_agentx/observability/events/subagent_window_text_guard.py,sha256=myo4SSV2TKZjpyrCoe-g5beNGmZnYZefa8nqW76q0Xc,3101
279
280
  langchain_agentx/observability/events/tool_call_id_resolver.py,sha256=Mun8jNb91tbV7hvIUkFG9g6NJGHVMW0kHS7Zt6N2gUA,4530
280
281
  langchain_agentx/observability/events/tool_outcome_resolver.py,sha256=YqF9Io9-0xdIdz7iYQuJkY-PiUXLC0zR26Eb9n35L9g,4357
@@ -777,7 +778,7 @@ langchain_agentx/workflow/catalog_registry.py,sha256=tYUny5FkHwQU-RRUxOdxaJhiRV_
777
778
  langchain_agentx/workflow/dag.py,sha256=Y1IR1IwnM79Xuev6HZnOvAE3Q23MRnA9lu4vg2Cie48,4469
778
779
  langchain_agentx/workflow/display_enricher.py,sha256=2HJ4xJI8H4hwBoWHAi6D_LwE-dcbZD_pafnS7DMDYZ4,6147
779
780
  langchain_agentx/workflow/display_resolver.py,sha256=hEaljqprjubG82zeqLOEeQ32AMAxaZwvwaLq3v-yt3c,10119
780
- langchain_agentx/workflow/execution.py,sha256=iCEkPgLkaoEM4cB6o7KAqIaBpFuY5HtGGISMNm0tr4A,18954
781
+ langchain_agentx/workflow/execution.py,sha256=1exCcD1zxZ8vSx4js6ygnJ4xXAnK1UwT8rpIAYAfxxc,19155
781
782
  langchain_agentx/workflow/loop_factory.py,sha256=hCShf_gDnesW2A9JspaUY3upp3NCIguII_wRiXnSIUM,3954
782
783
  langchain_agentx/workflow/memory_drain_registry.py,sha256=Xm_ytbB-BbRIu3-h-KhptsCsmmueOiNZePUuG1hk8zk,1681
783
784
  langchain_agentx/workflow/memory_session_policy.py,sha256=2FI0ZbAA6MnxJexnLYLadQpiqipPQwVnUrTWgl55A74,3333
@@ -836,8 +837,8 @@ langchain_agentx/workspace/root_grant_manager.py,sha256=W3gy8HTevbERbXqIgRcjzOXO
836
837
  langchain_agentx/workspace/tool_boundary.py,sha256=UDwX6swpSLsx9HNkYuuRRiV5o7ZZG_Bru2Yn0c5kNX8,5724
837
838
  langchain_agentx/workspace/validators.py,sha256=tQt-6TOcL8Fw7Ig5ebA9S7vGWh1rby920eFW6x8Tk9E,1439
838
839
  langchain_agentx/workspace/view.py,sha256=PGasqTaqhlD03SXXazHuw4RHfV681AIdlsYqL70pEjc,4774
839
- langchain_agentx_python-2.3.7.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
840
- langchain_agentx_python-2.3.7.dist-info/METADATA,sha256=p1SyevO1IsExSYN-OZOIgFId_BsYNhQG7feoPqOu7W4,23971
841
- langchain_agentx_python-2.3.7.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
842
- langchain_agentx_python-2.3.7.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
843
- langchain_agentx_python-2.3.7.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,,