langchain-agentx-python 2.4.4__py3-none-any.whl → 2.4.6__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/loop/hook/registry.py +54 -2
- langchain_agentx/loop/subagent/context.py +10 -5
- langchain_agentx/tool_runtime/session_store.py +11 -3
- {langchain_agentx_python-2.4.4.dist-info → langchain_agentx_python-2.4.6.dist-info}/METADATA +1 -1
- {langchain_agentx_python-2.4.4.dist-info → langchain_agentx_python-2.4.6.dist-info}/RECORD +9 -9
- {langchain_agentx_python-2.4.4.dist-info → langchain_agentx_python-2.4.6.dist-info}/LICENSE +0 -0
- {langchain_agentx_python-2.4.4.dist-info → langchain_agentx_python-2.4.6.dist-info}/WHEEL +0 -0
- {langchain_agentx_python-2.4.4.dist-info → langchain_agentx_python-2.4.6.dist-info}/top_level.txt +0 -0
langchain_agentx/__init__.py
CHANGED
|
@@ -18,6 +18,7 @@ registry.py — HookRegistry 用户侧入口。
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
20
|
import copy
|
|
21
|
+
import types
|
|
21
22
|
from dataclasses import replace
|
|
22
23
|
from typing import Any, Callable
|
|
23
24
|
from uuid import uuid4
|
|
@@ -25,6 +26,51 @@ from uuid import uuid4
|
|
|
25
26
|
from .config import HookSpec, HooksConfigSnapshot
|
|
26
27
|
from .types import HookEvent
|
|
27
28
|
|
|
29
|
+
# fresh_state 克隆时,同一父实例上的多个 bound method 共用一个克隆 self
|
|
30
|
+
_CallableSelfCloneMap = dict[int, Any]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _clone_hook_callable(
|
|
34
|
+
fn: Any,
|
|
35
|
+
*,
|
|
36
|
+
self_clones: _CallableSelfCloneMap,
|
|
37
|
+
) -> Any:
|
|
38
|
+
"""克隆 hook 回调;bound method 按 ``id(__self__)`` 去重,再绑到同一克隆实例。"""
|
|
39
|
+
self_obj = getattr(fn, "__self__", None)
|
|
40
|
+
func = getattr(fn, "__func__", None)
|
|
41
|
+
if self_obj is None or func is None or isinstance(self_obj, type):
|
|
42
|
+
# 普通函数 / 静态 / 类方法:保持 deepcopy 语义(通常仍是同一对象)
|
|
43
|
+
try:
|
|
44
|
+
return copy.deepcopy(fn)
|
|
45
|
+
except Exception:
|
|
46
|
+
return fn
|
|
47
|
+
|
|
48
|
+
key = id(self_obj)
|
|
49
|
+
if key not in self_clones:
|
|
50
|
+
self_clones[key] = copy.deepcopy(self_obj)
|
|
51
|
+
cloned_self = self_clones[key]
|
|
52
|
+
name = getattr(func, "__name__", None)
|
|
53
|
+
if isinstance(name, str) and name and hasattr(cloned_self, name):
|
|
54
|
+
rebound = getattr(cloned_self, name)
|
|
55
|
+
if callable(rebound) and getattr(rebound, "__self__", None) is cloned_self:
|
|
56
|
+
return rebound
|
|
57
|
+
return types.MethodType(func, cloned_self)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _clone_hook_config_fresh(
|
|
61
|
+
config: dict[str, Any],
|
|
62
|
+
*,
|
|
63
|
+
self_clones: _CallableSelfCloneMap,
|
|
64
|
+
) -> dict[str, Any]:
|
|
65
|
+
"""逐键深拷;``fn``/``callback`` 走 bound-method 去重克隆。"""
|
|
66
|
+
cloned: dict[str, Any] = {}
|
|
67
|
+
for key, value in config.items():
|
|
68
|
+
if key in ("fn", "callback") and callable(value):
|
|
69
|
+
cloned[key] = _clone_hook_callable(value, self_clones=self_clones)
|
|
70
|
+
else:
|
|
71
|
+
cloned[key] = copy.deepcopy(value)
|
|
72
|
+
return cloned
|
|
73
|
+
|
|
28
74
|
|
|
29
75
|
# ── 任务完成 Hook 类型定义 ────────────────────────────────────────
|
|
30
76
|
|
|
@@ -326,13 +372,19 @@ class HookRegistry:
|
|
|
326
372
|
*,
|
|
327
373
|
fresh_state: bool = True,
|
|
328
374
|
) -> HookRegistry:
|
|
329
|
-
"""过滤 clone 父 registry specs 到子 loop(LOCK-2
|
|
375
|
+
"""过滤 clone 父 registry specs 到子 loop(LOCK-2)。
|
|
376
|
+
|
|
377
|
+
``fresh_state=True``:可变 config 深拷,且同一父实例上的 bound method
|
|
378
|
+
(PRE/POST/…)共用**一份**克隆 ``__self__``——子会话相对父隔离,
|
|
379
|
+
子会话内跨事件状态机仍共享(见 bug hook-fork-bound-method-deepcopy-splits-state)。
|
|
380
|
+
"""
|
|
330
381
|
child = HookRegistry()
|
|
382
|
+
self_clones: _CallableSelfCloneMap = {}
|
|
331
383
|
for spec in self._specs:
|
|
332
384
|
if spec.event not in inherited_events:
|
|
333
385
|
continue
|
|
334
386
|
if fresh_state:
|
|
335
|
-
config =
|
|
387
|
+
config = _clone_hook_config_fresh(spec.config, self_clones=self_clones)
|
|
336
388
|
else:
|
|
337
389
|
config = dict(spec.config)
|
|
338
390
|
cloned = replace(
|
|
@@ -19,7 +19,8 @@ Fork 路径区分(对齐 CC):
|
|
|
19
19
|
``path_prep`` 与遗留 ``cwd``/worktree 自建二选一(编排层须传 ``path_prep``);
|
|
20
20
|
fork + worktree 时可选注入 CC 等价 ``buildWorktreeNotice`` user 消息(见 ``fork_worktree_notice``);
|
|
21
21
|
create_subagent_context 在 fork_from_parent=True 时注入 fork-boilerplate 行为规范;
|
|
22
|
-
P0-1:
|
|
22
|
+
P0-1: 子代理隔离 session_store(clone + inherit_grants);读缓存仅在
|
|
23
|
+
fork_from_parent=True 时继承(对齐 CC forkContextMessages ⟺ cloneFileStateCache)。
|
|
23
24
|
"""
|
|
24
25
|
|
|
25
26
|
import os
|
|
@@ -287,11 +288,15 @@ def create_subagent_context(
|
|
|
287
288
|
|
|
288
289
|
parent_store = getattr(parent_ctx, "session_store", None)
|
|
289
290
|
session_store: Any = parent_store
|
|
290
|
-
# P0-1
|
|
291
|
-
#
|
|
292
|
-
#
|
|
291
|
+
# P0-1:子代理隔离 session_store(cwd / 权限缓存不共享);grant 快照可继承。
|
|
292
|
+
# 读缓存绑定消息历史(对齐 CC runAgent.ts):仅 fork_from_parent=True 时
|
|
293
|
+
# clone _file_read_state;plain / Skill fork 空缓存,避免 file_unchanged 误判。
|
|
293
294
|
if isinstance(parent_store, AgentSessionStore):
|
|
294
|
-
session_store = parent_store.clone(
|
|
295
|
+
session_store = parent_store.clone(
|
|
296
|
+
file_state_only=True,
|
|
297
|
+
inherit_grants=True,
|
|
298
|
+
inherit_file_reads=fork_from_parent,
|
|
299
|
+
)
|
|
295
300
|
|
|
296
301
|
# 写入 cwd 到子会话 session_store.cwd_override(runtime state SSOT)
|
|
297
302
|
# 这确保后续 LangChainAdapter.build_tool_execution_context() 和
|
|
@@ -390,11 +390,19 @@ class AgentSessionStore:
|
|
|
390
390
|
*,
|
|
391
391
|
file_state_only: bool = True,
|
|
392
392
|
inherit_grants: bool = False,
|
|
393
|
+
inherit_file_reads: bool = True,
|
|
393
394
|
) -> AgentSessionStore:
|
|
395
|
+
"""克隆会话存储。
|
|
396
|
+
|
|
397
|
+
``inherit_file_reads`` 对齐 CC ``forkContextMessages !== undefined``
|
|
398
|
+
→ ``cloneFileStateCache``;plain / Skill fork 须传 ``False``(空读缓存),
|
|
399
|
+
避免 Read dedup 返回 ``file_unchanged`` 而子会话无父消息历史。
|
|
400
|
+
"""
|
|
394
401
|
new = AgentSessionStore(session_id=str(uuid.uuid4()))
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
402
|
+
if inherit_file_reads:
|
|
403
|
+
new._file_read_state = {
|
|
404
|
+
k: copy.deepcopy(v) for k, v in self._file_read_state.items()
|
|
405
|
+
}
|
|
398
406
|
if inherit_grants:
|
|
399
407
|
new._granted_roots = copy.deepcopy(self._granted_roots)
|
|
400
408
|
new.enable_dynamic_root_grant = self.enable_dynamic_root_grant
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
langchain_agentx/__init__.py,sha256=
|
|
1
|
+
langchain_agentx/__init__.py,sha256=fth2HJEGBE2s3P92UlQiNbql2glzWE_f5uddTh6FkP4,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
|
|
@@ -83,7 +83,7 @@ langchain_agentx/loop/hook/engine.py,sha256=s18KUN1QY0eC5T01mG8yO2lNxLg-GDa8ZhIX
|
|
|
83
83
|
langchain_agentx/loop/hook/graph_wiring.py,sha256=EvntU0VsqX-VIp9yQnKI3Qnz2-Scd-5-GviHh7xoZ1s,8769
|
|
84
84
|
langchain_agentx/loop/hook/hook_projection.py,sha256=B2PgU2YPx6Mnpdpcac6g_8SlkmR1bllNNPIn8jp2hyU,5966
|
|
85
85
|
langchain_agentx/loop/hook/progress_payload.py,sha256=bbNUEguw_cYbI3l0RJZ4VAtfgaRhD0jqwk3eE5AzgCE,4532
|
|
86
|
-
langchain_agentx/loop/hook/registry.py,sha256=
|
|
86
|
+
langchain_agentx/loop/hook/registry.py,sha256=tRuVbwUsO7ELwmigJNkgcxczF1toOy27tavUhzczyoI,15348
|
|
87
87
|
langchain_agentx/loop/hook/trust.py,sha256=4RlzQkleRO3xU1N4dZ5mPHgejDn_Xar2jOhwkLWKn4A,1236
|
|
88
88
|
langchain_agentx/loop/hook/types.py,sha256=tkI5R5KwsUNBczJ9we3dRa7gbqNmOar6k4BQyXGqiGs,5510
|
|
89
89
|
langchain_agentx/loop/hook/executors/__init__.py,sha256=rzRQ0_8-G1IUqNFMEVxAq7YTvvq2zTlZGENRabeU4_c,258
|
|
@@ -146,7 +146,7 @@ langchain_agentx/loop/subagent/active_run_registry.py,sha256=KurhAMDTBnRkdxNidaM
|
|
|
146
146
|
langchain_agentx/loop/subagent/async_runner.py,sha256=ZJu6DztRmg0SNEapEuPyQbsk8SprXiMKWDWDHb9L7yQ,14124
|
|
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=
|
|
149
|
+
langchain_agentx/loop/subagent/context.py,sha256=YAAR_g7BA_PXL5LGxxO1xWMn5pvVU3VOYSmxdxNPbbg,25243
|
|
150
150
|
langchain_agentx/loop/subagent/definition_permission.py,sha256=_Y30FA0EDTgqpqjw5luIiwbpABLo17myC3aY4NWbGIw,2188
|
|
151
151
|
langchain_agentx/loop/subagent/display_projector.py,sha256=AKsGWS1c9reH0kuD5u4oQ24KsBgyt7X10iZM3ere6Fs,3504
|
|
152
152
|
langchain_agentx/loop/subagent/fork_boilerplate.py,sha256=2Uh3cwegL7V-DvtLIxjX7ik5uW5mXfY2NBzP-biREso,5005
|
|
@@ -489,7 +489,7 @@ langchain_agentx/tool_runtime/read_ignore_patterns.py,sha256=l4kNulVDaOdQxcs4FeC
|
|
|
489
489
|
langchain_agentx/tool_runtime/read_permission.py,sha256=rwH7NEtL57aUKXVjSf6hMOOvEWOayNFyvI_SNoNCHPA,9284
|
|
490
490
|
langchain_agentx/tool_runtime/registry.py,sha256=cvdMRz5cyAqLjM0MWWp6wu1DgqtZeMoiR2vgyAVHlb8,3358
|
|
491
491
|
langchain_agentx/tool_runtime/session_hints.py,sha256=TyoNdSw5GsE5AvYDPHJKsrto9YXZtbAdihI8YKHdRxA,3004
|
|
492
|
-
langchain_agentx/tool_runtime/session_store.py,sha256=
|
|
492
|
+
langchain_agentx/tool_runtime/session_store.py,sha256=47asao4mHf75BijGg2OrJhexCUk2k8w3GpMUGYirNxM,17625
|
|
493
493
|
langchain_agentx/tool_runtime/shell_error.py,sha256=gi2i0sc4qHcUiLD5B2yk-wIvyVaOpLFKyf4ZnnKmAuE,2198
|
|
494
494
|
langchain_agentx/tool_runtime/smoke_test_runtime.py,sha256=vOdoYdFwsWjq8k7rHD7hkgtgM5noGr9a6Wn1hHZ7354,11846
|
|
495
495
|
langchain_agentx/tool_runtime/state_bridge.py,sha256=8F7jG8Uk4EVJaAB8rwKpNmbWrNZtIHYJO5RFBiwSRhs,6011
|
|
@@ -839,8 +839,8 @@ langchain_agentx/workspace/root_grant_manager.py,sha256=W3gy8HTevbERbXqIgRcjzOXO
|
|
|
839
839
|
langchain_agentx/workspace/tool_boundary.py,sha256=UDwX6swpSLsx9HNkYuuRRiV5o7ZZG_Bru2Yn0c5kNX8,5724
|
|
840
840
|
langchain_agentx/workspace/validators.py,sha256=tQt-6TOcL8Fw7Ig5ebA9S7vGWh1rby920eFW6x8Tk9E,1439
|
|
841
841
|
langchain_agentx/workspace/view.py,sha256=PGasqTaqhlD03SXXazHuw4RHfV681AIdlsYqL70pEjc,4774
|
|
842
|
-
langchain_agentx_python-2.4.
|
|
843
|
-
langchain_agentx_python-2.4.
|
|
844
|
-
langchain_agentx_python-2.4.
|
|
845
|
-
langchain_agentx_python-2.4.
|
|
846
|
-
langchain_agentx_python-2.4.
|
|
842
|
+
langchain_agentx_python-2.4.6.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
843
|
+
langchain_agentx_python-2.4.6.dist-info/METADATA,sha256=hlPQGo7vha4ZBFMEIgNs77O8oCYLtYQ-kymif47LSTs,23971
|
|
844
|
+
langchain_agentx_python-2.4.6.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
|
|
845
|
+
langchain_agentx_python-2.4.6.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
|
|
846
|
+
langchain_agentx_python-2.4.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{langchain_agentx_python-2.4.4.dist-info → langchain_agentx_python-2.4.6.dist-info}/top_level.txt
RENAMED
|
File without changes
|