langchain-agentx-python 1.2.7__py3-none-any.whl → 1.2.8__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/graph/graph_edges.py +2 -2
- langchain_agentx/loop/hook/__init__.py +7 -1
- langchain_agentx/loop/hook/async_hook_runner.py +37 -3
- langchain_agentx/loop/hook/graph_wiring.py +2 -2
- langchain_agentx/task_runtime/tasklist/store.py +9 -0
- {langchain_agentx_python-1.2.7.dist-info → langchain_agentx_python-1.2.8.dist-info}/METADATA +1 -1
- {langchain_agentx_python-1.2.7.dist-info → langchain_agentx_python-1.2.8.dist-info}/RECORD +11 -11
- {langchain_agentx_python-1.2.7.dist-info → langchain_agentx_python-1.2.8.dist-info}/LICENSE +0 -0
- {langchain_agentx_python-1.2.7.dist-info → langchain_agentx_python-1.2.8.dist-info}/WHEEL +0 -0
- {langchain_agentx_python-1.2.7.dist-info → langchain_agentx_python-1.2.8.dist-info}/top_level.txt +0 -0
langchain_agentx/__init__.py
CHANGED
|
@@ -32,7 +32,7 @@ from langchain_core.messages import AIMessage, AnyMessage, HumanMessage, ToolMes
|
|
|
32
32
|
from langgraph._internal._runnable import RunnableCallable
|
|
33
33
|
from langgraph.graph.state import StateGraph
|
|
34
34
|
from langgraph.prebuilt.tool_node import ToolNode
|
|
35
|
-
from ..hook.async_hook_runner import AsyncHookRunner
|
|
35
|
+
from ..hook.async_hook_runner import AsyncHookRunner, get_process_async_hook_runner
|
|
36
36
|
from ..hook.hook_projection import hook_result_to_event_dict
|
|
37
37
|
from ..hook.types import HookContext, HookEvent
|
|
38
38
|
|
|
@@ -96,7 +96,7 @@ def _execute_hook_common(
|
|
|
96
96
|
return None
|
|
97
97
|
hook_runner = state.get("_hook_runner")
|
|
98
98
|
if not isinstance(hook_runner, AsyncHookRunner):
|
|
99
|
-
hook_runner =
|
|
99
|
+
hook_runner = get_process_async_hook_runner()
|
|
100
100
|
ctx_kwargs: dict[str, Any] = {
|
|
101
101
|
"event": event,
|
|
102
102
|
"state": state,
|
|
@@ -12,7 +12,11 @@ loop.hook — Hook 子系统(P1/P2)。
|
|
|
12
12
|
Phase 1:新增 HookProgressPayloadBuilder 用于 progress 展示元数据构建。
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
-
from .async_hook_runner import
|
|
15
|
+
from .async_hook_runner import (
|
|
16
|
+
AsyncHookRunner,
|
|
17
|
+
get_process_async_hook_runner,
|
|
18
|
+
shutdown_process_async_hook_runner,
|
|
19
|
+
)
|
|
16
20
|
from .config import HookCandidate, HookCandidateDecision, HookSpec, HooksConfigSnapshot
|
|
17
21
|
from .engine import HookEngine
|
|
18
22
|
from .executors import AgentExecutor, CommandExecutor, HttpExecutor, PromptExecutor
|
|
@@ -40,6 +44,8 @@ from .types import (
|
|
|
40
44
|
__all__ = [
|
|
41
45
|
"AggregatedHookResult",
|
|
42
46
|
"AsyncHookRunner",
|
|
47
|
+
"get_process_async_hook_runner",
|
|
48
|
+
"shutdown_process_async_hook_runner",
|
|
43
49
|
"ATTACHMENT_HOOK_BLOCKING_ERROR",
|
|
44
50
|
"ATTACHMENT_HOOK_CANCELLED",
|
|
45
51
|
"ATTACHMENT_HOOK_NON_BLOCKING_ERROR",
|
|
@@ -8,12 +8,14 @@ async_hook_runner.py — Hook 同步入口的异步执行协作者。
|
|
|
8
8
|
HookGraphWiring 与 graph_edges 通过本协作者调用 HookEngine.execute()。
|
|
9
9
|
|
|
10
10
|
当前裁剪范围:
|
|
11
|
-
P1 仅实现线程桥接执行;不引入 nest_asyncio
|
|
11
|
+
P1 仅实现线程桥接执行;不引入 nest_asyncio,不修改外部 event loop。
|
|
12
|
+
进程级单例 ThreadPoolExecutor,atexit 显式 shutdown,禁止 fallback 裸 new。
|
|
12
13
|
"""
|
|
13
14
|
|
|
14
15
|
from __future__ import annotations
|
|
15
16
|
|
|
16
17
|
import asyncio
|
|
18
|
+
import atexit
|
|
17
19
|
from concurrent.futures import ThreadPoolExecutor
|
|
18
20
|
from threading import Lock
|
|
19
21
|
|
|
@@ -45,7 +47,10 @@ class AsyncHookRunner:
|
|
|
45
47
|
def _get_or_create_executor(self) -> ThreadPoolExecutor:
|
|
46
48
|
with self._executor_lock:
|
|
47
49
|
if self._executor is None:
|
|
48
|
-
self._executor = ThreadPoolExecutor(
|
|
50
|
+
self._executor = ThreadPoolExecutor(
|
|
51
|
+
max_workers=1,
|
|
52
|
+
thread_name_prefix="async-hook-runner",
|
|
53
|
+
)
|
|
49
54
|
return self._executor
|
|
50
55
|
|
|
51
56
|
def close(self) -> None:
|
|
@@ -59,4 +64,33 @@ class AsyncHookRunner:
|
|
|
59
64
|
return asyncio.run(hook_engine.execute(ctx))
|
|
60
65
|
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
_process_runner: AsyncHookRunner | None = None
|
|
68
|
+
_process_runner_lock = Lock()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def get_process_async_hook_runner() -> AsyncHookRunner:
|
|
72
|
+
"""进程级 Hook 桥接 runner(单例,避免 graph_edges fallback 泄漏线程池)。"""
|
|
73
|
+
global _process_runner
|
|
74
|
+
with _process_runner_lock:
|
|
75
|
+
if _process_runner is None:
|
|
76
|
+
_process_runner = AsyncHookRunner()
|
|
77
|
+
return _process_runner
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def shutdown_process_async_hook_runner() -> None:
|
|
81
|
+
"""关闭进程级 runner 线程池(测试 / 进程退出)。"""
|
|
82
|
+
global _process_runner
|
|
83
|
+
with _process_runner_lock:
|
|
84
|
+
if _process_runner is not None:
|
|
85
|
+
_process_runner.close()
|
|
86
|
+
_process_runner = None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
atexit.register(shutdown_process_async_hook_runner)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
__all__ = [
|
|
93
|
+
"AsyncHookRunner",
|
|
94
|
+
"get_process_async_hook_runner",
|
|
95
|
+
"shutdown_process_async_hook_runner",
|
|
96
|
+
]
|
|
@@ -17,7 +17,7 @@ from dataclasses import dataclass, field
|
|
|
17
17
|
from typing import Any
|
|
18
18
|
from uuid import uuid4
|
|
19
19
|
|
|
20
|
-
from .async_hook_runner import AsyncHookRunner
|
|
20
|
+
from .async_hook_runner import AsyncHookRunner, get_process_async_hook_runner
|
|
21
21
|
from .engine import HookEngine
|
|
22
22
|
from .hook_projection import derive_hook_outcome, hook_result_to_event_dict
|
|
23
23
|
from .types import AggregatedHookResult, HookContext, HookEvent
|
|
@@ -44,7 +44,7 @@ class HookGraphWiring:
|
|
|
44
44
|
workspace_cfg: Any | None = None
|
|
45
45
|
session_id: str | None = None
|
|
46
46
|
container_type: str = "interactive"
|
|
47
|
-
hook_runner: AsyncHookRunner = field(default_factory=
|
|
47
|
+
hook_runner: AsyncHookRunner = field(default_factory=get_process_async_hook_runner)
|
|
48
48
|
|
|
49
49
|
def loop_start_node(self, state: dict[str, Any], runtime: Any) -> dict[str, Any]:
|
|
50
50
|
run_id = state.get("_run_id")
|
|
@@ -29,6 +29,7 @@ task_runtime/tasklist/store.py — 任务存储核心
|
|
|
29
29
|
from __future__ import annotations
|
|
30
30
|
|
|
31
31
|
import asyncio
|
|
32
|
+
import atexit
|
|
32
33
|
import json
|
|
33
34
|
from collections.abc import Coroutine
|
|
34
35
|
from concurrent.futures import ThreadPoolExecutor
|
|
@@ -514,6 +515,14 @@ _T = TypeVar("_T")
|
|
|
514
515
|
_ASYNC_RUNNER = ThreadPoolExecutor(max_workers=1, thread_name_prefix="taskstore-sync")
|
|
515
516
|
|
|
516
517
|
|
|
518
|
+
def shutdown_taskstore_async_runner(*, wait: bool = True) -> None:
|
|
519
|
+
"""关闭 TaskStoreSync 桥接线程池(测试 / 进程退出)。"""
|
|
520
|
+
_ASYNC_RUNNER.shutdown(wait=wait)
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
atexit.register(shutdown_taskstore_async_runner)
|
|
524
|
+
|
|
525
|
+
|
|
517
526
|
def _run_async(coro_factory: Callable[[], Coroutine[Any, Any, _T]]) -> _T:
|
|
518
527
|
"""在同步上下文中执行协程;若已有 running loop 则在线程内 asyncio.run。"""
|
|
519
528
|
try:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
langchain_agentx/__init__.py,sha256=
|
|
1
|
+
langchain_agentx/__init__.py,sha256=b-u3BUFUQ27sY5qq7MGKGyTccmPP4VsDNwXrDWhXR24,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
|
|
@@ -66,14 +66,14 @@ langchain_agentx/loop/exit/withheld_error.py,sha256=LfX3j7Rgd9VoMzlz7GOs9TPuRe7R
|
|
|
66
66
|
langchain_agentx/loop/graph/__init__.py,sha256=9pUUqn7G87n3lV45iYIU24j0wcTHyCD--SSdtv3urh4,136
|
|
67
67
|
langchain_agentx/loop/graph/builtin_loop_control.py,sha256=jagBvSo8fj6Yjl95rkp5A0W8RgyVf4P-EXMmGweURl8,7184
|
|
68
68
|
langchain_agentx/loop/graph/factory.py,sha256=Pjc36mds2PYEo8rNSUawfUN8jiO0U6BO4AIDpCvNP3Q,91663
|
|
69
|
-
langchain_agentx/loop/graph/graph_edges.py,sha256=
|
|
69
|
+
langchain_agentx/loop/graph/graph_edges.py,sha256=A82WBrKfNCbx55xNz0If-oaPs1tr2R0inTnQFJSUu4E,43401
|
|
70
70
|
langchain_agentx/loop/graph/reactive_compact_node.py,sha256=AN31reohf25zRiqdPTmFCIQ1N6VwKn1oIkRkRuGAp4k,8725
|
|
71
71
|
langchain_agentx/loop/graph/runtime_tools_node.py,sha256=5iBPvHl2hOdfnRZrwtnoD4J_SzEuQKC6VQUJyPuthgA,5089
|
|
72
|
-
langchain_agentx/loop/hook/__init__.py,sha256=
|
|
73
|
-
langchain_agentx/loop/hook/async_hook_runner.py,sha256=
|
|
72
|
+
langchain_agentx/loop/hook/__init__.py,sha256=rOjc1cqWBxrcp651w_SQX50dWY7o28L2c-r8iVs-SWU,2167
|
|
73
|
+
langchain_agentx/loop/hook/async_hook_runner.py,sha256=SNyuYnQoowZzBTBHQb6o5L9wTG2Rl7qryeMtqFyEsxI,3195
|
|
74
74
|
langchain_agentx/loop/hook/config.py,sha256=f8XtGGHtyjuRvZNhkU8ohbhyqOHD7mHZn_w0rVXMX_o,9157
|
|
75
75
|
langchain_agentx/loop/hook/engine.py,sha256=s18KUN1QY0eC5T01mG8yO2lNxLg-GDa8ZhIXFjo1BSk,14865
|
|
76
|
-
langchain_agentx/loop/hook/graph_wiring.py,sha256=
|
|
76
|
+
langchain_agentx/loop/hook/graph_wiring.py,sha256=Bh40IsQzoYT_2ThdwFQB2uFiy8S6DZQ6NN8LBslcJJs,8057
|
|
77
77
|
langchain_agentx/loop/hook/hook_projection.py,sha256=B2PgU2YPx6Mnpdpcac6g_8SlkmR1bllNNPIn8jp2hyU,5966
|
|
78
78
|
langchain_agentx/loop/hook/progress_payload.py,sha256=bbNUEguw_cYbI3l0RJZ4VAtfgaRhD0jqwk3eE5AzgCE,4532
|
|
79
79
|
langchain_agentx/loop/hook/registry.py,sha256=X8k9NEzyBnasQyAWdJZmbLtX_OlV_KqUkFY4roYPLKo,11958
|
|
@@ -313,7 +313,7 @@ langchain_agentx/task_runtime/tasklist/notifier.py,sha256=ylFrvD220TJTpvxGzkSt3r
|
|
|
313
313
|
langchain_agentx/task_runtime/tasklist/path_resolver.py,sha256=mCo4I-dZiHpNVHHm6rT5ByFs9bfsfmtspejFKMo_Xq8,2604
|
|
314
314
|
langchain_agentx/task_runtime/tasklist/paths.py,sha256=pvrKiUK4kUa_mCWQz6_e4T2U6jXTOevBQRJmSfCquto,2284
|
|
315
315
|
langchain_agentx/task_runtime/tasklist/reader.py,sha256=PIc_GJ2uhp2dskX5Sb_jJxz_miZOkiHy-7nQrXd80E8,2295
|
|
316
|
-
langchain_agentx/task_runtime/tasklist/store.py,sha256=
|
|
316
|
+
langchain_agentx/task_runtime/tasklist/store.py,sha256=RShUySLEJlGbv1KY2zXTRVm57YCbtB6pXd09T8YDcyQ,20065
|
|
317
317
|
langchain_agentx/task_runtime/tasks/__init__.py,sha256=G_a_TVE5c3thIiETiOtKov5yMDAkob0dqzfwDsVsfPk,2041
|
|
318
318
|
langchain_agentx/task_runtime/tasks/ai_analysis/__init__.py,sha256=f_1U_gULXWWdrE9zCXNGfC2M-627X8p0K1Yj9CB_SHc,455
|
|
319
319
|
langchain_agentx/task_runtime/tasks/ai_analysis/base.py,sha256=bSIBCBlQyg_2sygKrZenUOmz4sLM7lpKrxEroMTf-9I,2702
|
|
@@ -667,8 +667,8 @@ langchain_agentx/workspace/root_grant_manager.py,sha256=W3gy8HTevbERbXqIgRcjzOXO
|
|
|
667
667
|
langchain_agentx/workspace/tool_boundary.py,sha256=UDwX6swpSLsx9HNkYuuRRiV5o7ZZG_Bru2Yn0c5kNX8,5724
|
|
668
668
|
langchain_agentx/workspace/validators.py,sha256=tQt-6TOcL8Fw7Ig5ebA9S7vGWh1rby920eFW6x8Tk9E,1439
|
|
669
669
|
langchain_agentx/workspace/view.py,sha256=Ip02CZNI-ZjF5k0OYT3q7RUR_auMEw83VJ6rQsaBcYU,4588
|
|
670
|
-
langchain_agentx_python-1.2.
|
|
671
|
-
langchain_agentx_python-1.2.
|
|
672
|
-
langchain_agentx_python-1.2.
|
|
673
|
-
langchain_agentx_python-1.2.
|
|
674
|
-
langchain_agentx_python-1.2.
|
|
670
|
+
langchain_agentx_python-1.2.8.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
671
|
+
langchain_agentx_python-1.2.8.dist-info/METADATA,sha256=GEO2zoN_6c-aydS3qR6yS6zRRIJB79FR_IX6YFePh3g,24846
|
|
672
|
+
langchain_agentx_python-1.2.8.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
|
|
673
|
+
langchain_agentx_python-1.2.8.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
|
|
674
|
+
langchain_agentx_python-1.2.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{langchain_agentx_python-1.2.7.dist-info → langchain_agentx_python-1.2.8.dist-info}/top_level.txt
RENAMED
|
File without changes
|