langchain-agentx-python 2.2.4__py3-none-any.whl → 2.2.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.
@@ -11,7 +11,7 @@ from langchain_agentx import create_loop_agent
11
11
  ```
12
12
  """
13
13
 
14
- __version__ = "2.2.4"
14
+ __version__ = "2.2.6"
15
15
 
16
16
  from .loop import ( # noqa: F401
17
17
  create_loop_agent,
@@ -176,6 +176,12 @@ class RuntimeTool(ABC):
176
176
  is_concurrency_safe: bool = False
177
177
  """是否支持并发执行。"""
178
178
 
179
+ requires_user_interaction: bool = False
180
+ """
181
+ 对齐 CC ``Tool.requiresUserInteraction()``。
182
+ True 时 bypassPermissions / auto allow 不得吞掉上游 ask(如 AskUser gather)。
183
+ """
184
+
179
185
  never_truncate: bool = False
180
186
  """
181
187
  禁止 ToolOutputManager 截断输出。
@@ -272,6 +278,15 @@ class RuntimeTool(ABC):
272
278
  _ = data, ctx
273
279
  return self.is_concurrency_safe
274
280
 
281
+ def requires_user_interaction_for(
282
+ self,
283
+ data: dict[str, Any],
284
+ ctx: ToolExecutionContext,
285
+ ) -> bool:
286
+ """该次调用是否强制用户交互;默认读取类属性(对齐 CC requiresUserInteraction)。"""
287
+ _ = data, ctx
288
+ return bool(self.requires_user_interaction)
289
+
275
290
  def resolve_capabilities(
276
291
  self,
277
292
  data: dict[str, Any],
@@ -4,12 +4,13 @@ inner_permission_chain.py — CC inner 段 1–5(hasPermissionsToUseToolInner
4
4
  职责:
5
5
  在 PermissionOrchestrator 内编排 global deny/ask → L1 → mode 短路 → path policy
6
6
  → acceptEdits 快路径 → passthrough→ask。
7
+ RUI(requires_user_interaction)上游 ask 对齐 CC step 1e,不被 bypass 吞掉。
7
8
 
8
9
  链路位置:
9
10
  permission_orchestrator._evaluate_inner / _aevaluate_inner
10
11
 
11
12
  当前裁剪范围:
12
- 段 6(auto / L3)不在此模块;auto_mode hook 仍由 aauthorize outer 暂存至 Phase 4。
13
+ 段 6(auto / L3)不在此模块。
13
14
  """
14
15
 
15
16
  from __future__ import annotations
@@ -64,6 +65,9 @@ class InnerPermissionChain:
64
65
  seg12 = self._segment_1_2_global(tool_name, data, ctx, tool_flags)
65
66
  if seg12 is not None:
66
67
  if seg12.behavior == "ask":
68
+ # CC step 1e:RUI + ask 不被 bypassPermissions 吞掉
69
+ if tool.requires_user_interaction_for(data, ctx):
70
+ return seg12
67
71
  seg4 = self._segment_4_mode_shortcircuit(tool, data, ctx, tool_flags)
68
72
  if seg4 is not None:
69
73
  return seg4
@@ -72,6 +76,10 @@ class InnerPermissionChain:
72
76
  l1 = tool.run_l1_permission_check(data, ctx)
73
77
  if l1.outcome != "continue":
74
78
  if l1.outcome == "ask":
79
+ if l1.decision is None:
80
+ raise ValueError(f"L1 outcome={l1.outcome!r} requires decision")
81
+ if tool.requires_user_interaction_for(data, ctx):
82
+ return l1.decision
75
83
  seg4 = self._segment_4_mode_shortcircuit(tool, data, ctx, tool_flags)
76
84
  if seg4 is not None:
77
85
  return seg4
@@ -4,6 +4,7 @@ outer_permission_resolver.py — 段 6 outer 裁决(GAP-3)
4
4
  职责:
5
5
  inner 产出 ask 后:auto 分类器消化 / headless fail-close deny;非 ask 原样返回。
6
6
  classifier 熔断到顶:CLI → ask;headless → ClassifierDenialLimitAbort。
7
+ RUI 工具的 ask 不被 auto allow 吞掉(对齐 CC requiresUserInteraction)。
7
8
 
8
9
  链路位置:
9
10
  PermissionOrchestrator._resolve_outer
@@ -61,6 +62,8 @@ class OuterPermissionResolver:
61
62
  tool_flags = ctx.tool_flags if hasattr(ctx, "tool_flags") else {}
62
63
  mode = str(tool_flags.get("permission_mode", "default"))
63
64
 
65
+ inner_ask = decision
66
+
64
67
  if mode == "auto":
65
68
  auto_decision = await self._run_auto_mode_hook(tool, data, ctx)
66
69
  if auto_decision is not None:
@@ -70,12 +73,18 @@ class OuterPermissionResolver:
70
73
  ctx,
71
74
  headless=headless,
72
75
  )
73
- if auto_decision.behavior in ("allow", "deny", "ask"):
76
+ if (
77
+ auto_decision.behavior == "allow"
78
+ and tool.requires_user_interaction_for(data, ctx)
79
+ ):
80
+ # CC:忽略 auto allow,保留 ask;继续走下方 headless / 透传
81
+ pass
82
+ elif auto_decision.behavior in ("allow", "deny", "ask"):
74
83
  return auto_decision
75
84
 
76
85
  if headless:
77
- return self._headless_deny(decision)
78
- return decision
86
+ return self._headless_deny(inner_ask)
87
+ return inner_ask
79
88
 
80
89
  @staticmethod
81
90
  async def _run_auto_mode_hook(
@@ -84,6 +84,7 @@ class AskUserQuestionTool(RuntimeTool):
84
84
  is_read_only: bool = True
85
85
  is_destructive: bool = False
86
86
  is_concurrency_safe: bool = True
87
+ requires_user_interaction: bool = True
87
88
  never_truncate: bool = False
88
89
  dedupe_identical_calls: bool = False
89
90
  max_result_size_chars: int = 100_000
@@ -183,6 +183,8 @@ class ExitPlanModeRuntimeTool(_PlanModeRuntimeToolBase):
183
183
  description: str = EXIT_PLAN_MODE_DESCRIPTION
184
184
  input_model = ExitPlanModeInput
185
185
  output_model = ExitPlanModeOutput
186
+ # 对齐 CC ExitPlanMode.requiresUserInteraction:bypass/auto 不得静默放行确认
187
+ requires_user_interaction: bool = True
186
188
 
187
189
  def prompt_for_model(self, ctx: ToolPromptContext) -> str:
188
190
  _ = ctx
@@ -65,7 +65,7 @@ from .execution import (
65
65
  )
66
66
  from .memory_drain_registry import MemoryDrainRegistry
67
67
  from .memory_session_policy import collect_agent_nodes, validate_loop_session_ids
68
- from .state import WorkflowState
68
+ from .state import WorkflowState, project_workflow_node_update
69
69
 
70
70
  # Lazy import for event_adapter(避免循环依赖)
71
71
  # 实际使用时通过 _get_event_adapter() 延迟导入
@@ -453,21 +453,22 @@ class BaseWorkflow(ABC):
453
453
 
454
454
  与 run() 的区别:
455
455
  - run(): 返回完整 WorkflowState(用于顶层调用)
456
- - as_node(): 返回完整 WorkflowState(作为其他 Workflow 的节点)
456
+ - as_node(): 返回相对父 state 的 channel delta(供 LangGraph reducer 合并)
457
457
 
458
458
  实现原理:
459
- - 直接调用 run() 返回完整 state
459
+ - 调用 run() 得到子图终态
460
+ - 经 project_workflow_node_update 将 messages / item_results 投影为增量
460
461
  - 传递 parent_workflow 构建层级关系
461
462
  - 使用 outer_semaphore 控制并发(如果提供)
462
- - LangGraph 的 reducer 会自动处理合并
463
463
 
464
464
  并发控制(问题 19):
465
465
  - 如果 outer_workflow 提供 semaphore,子 workflow 的执行会被限流
466
466
  - 这解决了 DeepSearch 场景下 45 个 sub-workflow 同时启动的问题
467
467
 
468
- 注意(问题 18 - as_node() diff 算法硬 bug):
469
- - ✅ 新设计(正确):直接返回完整 state,让 LangGraph reducer 处理合并
470
- - ❌ 旧设计(错误):手算 diff,硬编码字段名,假设 reducer 是 list append
468
+ 注意(聚合通道契约 · 2026-09-04):
469
+ - 节点必须返回 delta,禁止把父 state 全量回写进 messages / item_results
470
+ - 手写节点请用 delta_messages / delta_item_results
471
+ - as_node 已自动投影,避免嵌套子图 2^N 膨胀
471
472
  """
472
473
  async def node_fn(state: dict) -> dict:
473
474
  # 入口即快照父 _active_run_config,避免 run() 内 set/restore 与父并发时读漂移。
@@ -475,16 +476,18 @@ class BaseWorkflow(ABC):
475
476
  # === 并发控制(问题 19)===
476
477
  if outer_semaphore is not None:
477
478
  async with outer_semaphore:
478
- return await self.run(
479
+ result = await self.run(
479
480
  state,
480
481
  parent_workflow=parent_workflow,
481
482
  run_config=inherited_run_config,
482
483
  )
483
- return await self.run(
484
- state,
485
- parent_workflow=parent_workflow,
486
- run_config=inherited_run_config,
487
- )
484
+ else:
485
+ result = await self.run(
486
+ state,
487
+ parent_workflow=parent_workflow,
488
+ run_config=inherited_run_config,
489
+ )
490
+ return project_workflow_node_update(state, result)
488
491
 
489
492
  return node_fn
490
493
 
@@ -93,16 +93,22 @@ class AgentNode:
93
93
  ctx: WorkflowNodeContext,
94
94
  invocation: LoopInvocation,
95
95
  ) -> dict[str, Any]:
96
- del state, ctx
97
- return {
98
- "messages": graph_result.get("messages", []),
99
- "item_results": [
96
+ from .state import delta_item_results, project_workflow_node_update
97
+
98
+ del ctx
99
+ update = project_workflow_node_update(
100
+ {"messages": state.get("messages", [])},
101
+ {"messages": graph_result.get("messages", [])},
102
+ )
103
+ update.update(
104
+ delta_item_results(
100
105
  {
101
106
  "node": self.name,
102
107
  "session_id": invocation.session_id,
103
108
  }
104
- ],
105
- }
109
+ )
110
+ )
111
+ return update
106
112
 
107
113
  def map_error(
108
114
  self,
@@ -110,16 +116,16 @@ class AgentNode:
110
116
  exc: Exception,
111
117
  ctx: WorkflowNodeContext,
112
118
  ) -> dict[str, Any]:
113
- return {
114
- "messages": state.get("messages", []),
115
- "item_results": [
116
- {
117
- "node": self.name,
118
- "session_id": ctx.loop_session_id,
119
- "error": str(exc),
120
- }
121
- ],
122
- }
119
+ from .state import delta_item_results
120
+
121
+ del state
122
+ return delta_item_results(
123
+ {
124
+ "node": self.name,
125
+ "session_id": ctx.loop_session_id,
126
+ "error": str(exc),
127
+ }
128
+ )
123
129
 
124
130
  def _resolve_graph_factory(
125
131
  self,
@@ -1,10 +1,11 @@
1
1
  """
2
- state.py — Workflow 状态定义
2
+ state.py — Workflow 状态定义与聚合通道契约
3
3
 
4
4
  职责:
5
5
  - 定义 WorkflowState 基类(TypedDict + Annotated reducer)
6
- - 规范 Workflow 状态字段命名与 reducer 使用
7
- - 提供文档模式定义,不强制继承
6
+ - item_results 按身份键幂等合并(防 2^N 全量回写 OOM)
7
+ - 提供 delta_messages / delta_item_results 增量构造接口(防误用)
8
+ - as_node 用 project_workflow_node_update 将终态投影为 delta
8
9
 
9
10
  链路位置:
10
11
  - 被 BaseWorkflow 和所有特殊 Workflow 使用
@@ -13,44 +14,268 @@ state.py — Workflow 状态定义
13
14
  当前裁剪范围:
14
15
  - 仅包含基础字段(messages, item_results, workflow_id 等)
15
16
  - 业务特定字段由具体 Workflow 自行扩展
16
-
17
- 设计说明(问题 10):
18
- - WorkflowState 使用 TypedDict,这是 LangGraph 的最佳实践
19
- - TypedDict + Annotated reducer 是 LangGraph 官方推荐的状态定义方式
20
- - 不要使用普通 dict(没有类型检查和 reducer 支持)
21
- - 不要使用 dataclass(LangGraph StateGraph 不直接支持)
17
+ - 通道预算上限(P2)未做
22
18
  """
23
19
 
24
20
  from __future__ import annotations
25
21
 
26
- from typing import Annotated, TypedDict
27
- from operator import add
22
+ import logging
23
+ import os
24
+ from typing import Annotated, Any, Hashable, Mapping, Sequence, TypedDict
28
25
 
29
26
  from langgraph.graph.message import add_messages
30
27
  from langchain_core.messages import AnyMessage
31
28
 
29
+ logger = logging.getLogger(__name__)
30
+
31
+ _STRICT_DELTA_ENV = "LANGCHAIN_AGENTX_WORKFLOW_STRICT_DELTA"
32
+
33
+ # 显式主键优先;其次 task(编排任务);再 node/repo/session 等复合键
34
+ _EXPLICIT_IDENTITY_KEYS: tuple[str, ...] = ("result_id", "item_key", "id")
35
+ _COMPOSITE_IDENTITY_KEYS: tuple[str, ...] = (
36
+ "node",
37
+ "repo_id",
38
+ "repo",
39
+ "session_id",
40
+ "from",
41
+ )
42
+
43
+
44
+ def item_result_identity(item: Any) -> Hashable | None:
45
+ """提取 item_results 条目的合并身份;无身份则返回 None(走 append)。"""
46
+ if not isinstance(item, dict):
47
+ try:
48
+ hash(item)
49
+ except TypeError:
50
+ return None
51
+ return ("value", item)
52
+
53
+ for key in _EXPLICIT_IDENTITY_KEYS:
54
+ value = item.get(key)
55
+ if value is not None:
56
+ return (key, value)
57
+
58
+ task = item.get("task")
59
+ if task is not None:
60
+ return ("task", task)
61
+
62
+ parts = tuple(
63
+ (key, item[key])
64
+ for key in _COMPOSITE_IDENTITY_KEYS
65
+ if item.get(key) is not None
66
+ )
67
+ if parts:
68
+ return ("composite", parts)
69
+ return None
70
+
71
+
72
+ def _looks_like_full_rewrite(left: Sequence[Any], right: Sequence[Any]) -> bool:
73
+ """检测典型反模式:提交值 = 旧列表前缀 + 增量(state.get(...) + [...])。"""
74
+ if not left or len(right) <= len(left):
75
+ return False
76
+ return list(right[: len(left)]) == list(left)
77
+
78
+
79
+ def _maybe_raise_or_warn_full_rewrite(left: list[Any], right: list[Any]) -> None:
80
+ if not _looks_like_full_rewrite(left, right):
81
+ return
82
+ message = (
83
+ "item_results full-rewrite antipattern detected: "
84
+ f"submitted len={len(right)} looks like prior len={len(left)} + suffix. "
85
+ "Return delta only via delta_item_results(...); "
86
+ "do not submit state.get('item_results', []) + [...]."
87
+ )
88
+ if os.environ.get(_STRICT_DELTA_ENV, "").strip() in {"1", "true", "TRUE", "yes", "YES"}:
89
+ raise ValueError(message)
90
+ logger.warning(message)
91
+
92
+
93
+ class ItemResultsMerge:
94
+ """item_results 通道归约器:按身份键幂等合并,并检测全量回写。"""
95
+
96
+ def __call__(
97
+ self,
98
+ left: list[Any] | None,
99
+ right: list[Any] | None,
100
+ ) -> list[Any]:
101
+ return self.merge(left, right)
102
+
103
+ def merge(
104
+ self,
105
+ left: list[Any] | None,
106
+ right: list[Any] | None,
107
+ ) -> list[Any]:
108
+ left_list = list(left or [])
109
+ right_list = list(right or [])
110
+ if not right_list:
111
+ return left_list
112
+ if not left_list:
113
+ return list(right_list)
114
+
115
+ _maybe_raise_or_warn_full_rewrite(left_list, right_list)
116
+
117
+ keyed: dict[Hashable, int] = {}
118
+ merged: list[Any] = []
119
+ for item in left_list:
120
+ identity = item_result_identity(item)
121
+ if identity is None:
122
+ merged.append(item)
123
+ continue
124
+ if identity in keyed:
125
+ merged[keyed[identity]] = item
126
+ else:
127
+ keyed[identity] = len(merged)
128
+ merged.append(item)
129
+
130
+ for item in right_list:
131
+ identity = item_result_identity(item)
132
+ if identity is None:
133
+ merged.append(item)
134
+ continue
135
+ if identity in keyed:
136
+ merged[keyed[identity]] = item
137
+ else:
138
+ keyed[identity] = len(merged)
139
+ merged.append(item)
140
+ return merged
141
+
142
+
143
+ merge_item_results = ItemResultsMerge()
144
+
145
+
146
+ def _normalize_varargs(items: tuple[Any, ...]) -> list[Any]:
147
+ if len(items) == 1 and isinstance(items[0], list):
148
+ return list(items[0])
149
+ return list(items)
150
+
151
+
152
+ def delta_messages(*messages: Any) -> dict[str, list[Any]]:
153
+ """构造 messages 通道增量(节点应 return 本 dict 或其展开)。
154
+
155
+ 只接收本次新增消息,禁止传入 state['messages'] 全量历史。
156
+ """
157
+ return {"messages": _normalize_varargs(messages)}
158
+
159
+
160
+ def delta_item_results(*items: Any) -> dict[str, list[Any]]:
161
+ """构造 item_results 通道增量(节点应 return 本 dict 或其展开)。
162
+
163
+ 只接收本次新增/更新条目;条目宜带身份键(result_id / item_key / task / node+…)。
164
+ 禁止传入 state.get('item_results', []) + [...] 全量历史。
165
+ """
166
+ return {"item_results": _normalize_varargs(items)}
167
+
168
+
169
+ def _message_identity(message: Any) -> Hashable | None:
170
+ msg_id = getattr(message, "id", None)
171
+ if msg_id is not None:
172
+ return ("id", msg_id)
173
+ return None
174
+
175
+
176
+ def _messages_delta(before: Sequence[Any] | None, after: Sequence[Any] | None) -> list[Any]:
177
+ before_list = list(before or [])
178
+ after_list = list(after or [])
179
+ if not after_list:
180
+ return []
181
+ seen: set[Hashable] = set()
182
+ for message in before_list:
183
+ identity = _message_identity(message)
184
+ if identity is not None:
185
+ seen.add(identity)
186
+ delta: list[Any] = []
187
+ for message in after_list:
188
+ identity = _message_identity(message)
189
+ if identity is None:
190
+ # 无 id:仅当不在 before 相等集合中时纳入(弱 diff)
191
+ if message not in before_list:
192
+ delta.append(message)
193
+ continue
194
+ if identity not in seen:
195
+ seen.add(identity)
196
+ delta.append(message)
197
+ return delta
198
+
199
+
200
+ def _item_results_delta(
201
+ before: Sequence[Any] | None,
202
+ after: Sequence[Any] | None,
203
+ ) -> list[Any]:
204
+ before_list = list(before or [])
205
+ after_list = list(after or [])
206
+ if not after_list:
207
+ return []
208
+
209
+ before_by_key: dict[Hashable, Any] = {}
210
+ before_unkeyed: list[Any] = []
211
+ for item in before_list:
212
+ identity = item_result_identity(item)
213
+ if identity is None:
214
+ before_unkeyed.append(item)
215
+ else:
216
+ before_by_key[identity] = item
217
+
218
+ delta: list[Any] = []
219
+ after_unkeyed: list[Any] = []
220
+ for item in after_list:
221
+ identity = item_result_identity(item)
222
+ if identity is None:
223
+ after_unkeyed.append(item)
224
+ continue
225
+ prior = before_by_key.get(identity)
226
+ if prior is None or prior != item:
227
+ delta.append(item)
228
+
229
+ remaining_unkeyed = list(before_unkeyed)
230
+ for item in after_unkeyed:
231
+ if item in remaining_unkeyed:
232
+ remaining_unkeyed.remove(item)
233
+ else:
234
+ delta.append(item)
235
+ return delta
236
+
237
+
238
+ def project_workflow_node_update(
239
+ before: Mapping[str, Any],
240
+ after: Mapping[str, Any],
241
+ ) -> dict[str, Any]:
242
+ """将子 workflow 终态投影为父图节点应提交的 channel delta。
243
+
244
+ 聚合通道(messages / item_results)只提交相对 before 的增量;
245
+ 其它字段在值变化时原样写入(last-write-wins)。
246
+ """
247
+ update: dict[str, Any] = {}
248
+ for key, value in after.items():
249
+ if key == "messages":
250
+ delta = _messages_delta(before.get("messages"), value)
251
+ if delta:
252
+ update["messages"] = delta
253
+ continue
254
+ if key == "item_results":
255
+ delta = _item_results_delta(before.get("item_results"), value)
256
+ if delta:
257
+ update["item_results"] = delta
258
+ continue
259
+ if before.get(key) != value:
260
+ update[key] = value
261
+ return update
262
+
32
263
 
33
264
  class WorkflowState(TypedDict, total=False):
34
265
  """Workflow 状态 schema,支持并发写入。
35
266
 
36
267
  字段说明:
37
- - messages: 消息列表(所有节点都会追加消息,使用 reducer)
38
- - item_results: 并行任务结果列表(聚合所有 item 的输出,使用 reducer)
39
- - workflow_id: 当前 Workflow ID(单写,由 BaseWorkflow 设置)
40
- - task_key: 当前任务标识符(单写,Phase 2+)
41
- - current_step: 当前步骤(单写,用于顺序 Workflow)
42
- - error: 错误信息(单写,用于错误处理)
43
-
44
- 使用方式:
45
- - 基础类型:WorkflowState(本定义)
46
- - 扩展类型:class MyState(WorkflowState, total=False) 添加业务字段
268
+ - messages: 消息列表(add_messages 按 id 幂等合并)
269
+ - item_results: 并行/叶节点产出(merge_item_results 按身份键幂等合并)
270
+ - workflow_id / task_key / current_step / orchestration_round / error: 单写字段
271
+
272
+ 节点写入约定:
273
+ - 使用 delta_messages / delta_item_results 构造增量,禁止 {**state} 全量回写聚合通道
47
274
  """
48
275
 
49
- # === 并发聚合字段(使用 reducer)===
50
276
  messages: Annotated[list[AnyMessage], add_messages]
51
- item_results: Annotated[list[dict], add]
277
+ item_results: Annotated[list[dict], merge_item_results]
52
278
 
53
- # === 单写字段(无需 reducer)===
54
279
  workflow_id: str
55
280
  task_key: str | None
56
281
  current_step: str | None
@@ -58,4 +283,12 @@ class WorkflowState(TypedDict, total=False):
58
283
  error: str | None
59
284
 
60
285
 
61
- __all__ = ["WorkflowState"]
286
+ __all__ = [
287
+ "WorkflowState",
288
+ "ItemResultsMerge",
289
+ "merge_item_results",
290
+ "item_result_identity",
291
+ "delta_messages",
292
+ "delta_item_results",
293
+ "project_workflow_node_update",
294
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langchain-agentx-python
3
- Version: 2.2.4
3
+ Version: 2.2.6
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=rYu7Sa7AIXQVmlKCoRc4uqxp7Lb37UIESLvYcrsemdA,1614
1
+ langchain_agentx/__init__.py,sha256=w5E568-acwfUArEGRc1Fs10Ni10VOEs-jLn4UGZVjeE,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
@@ -393,7 +393,7 @@ langchain_agentx/tool_runtime/__init__.py,sha256=C4ZrS6UWSL65ErfNWMvBuZBnht6ZuGb
393
393
  langchain_agentx/tool_runtime/accept_edits_fast_path.py,sha256=UMCOF9Ws7hx3pcYvL-Kq7vzIAGvOGdEfx69ccUDXT-k,2281
394
394
  langchain_agentx/tool_runtime/adapter.py,sha256=rM-Y2zSZ--N-TIvx1HtI1J7ralPU0w4jJuX3bBvIVxM,33847
395
395
  langchain_agentx/tool_runtime/agent_home_bypass.py,sha256=na9xQPgJ02qA3YiJ1F8jN0Uv4uBDPzqRk3lfPPE089g,8010
396
- langchain_agentx/tool_runtime/base.py,sha256=Ez9W42DsaiZcWDDO8UfRKv3E7_Z6WBcABkwdAi6qTK8,21390
396
+ langchain_agentx/tool_runtime/base.py,sha256=asjZ0Rsxchh51OQbt5-h61xoWgC-i5sUbH0e_uSf-X0,21922
397
397
  langchain_agentx/tool_runtime/cancel_projection.py,sha256=81_Bvg8ZiuPdl1usePt7ykXFuO6Sg7UXogYQBX6aysQ,2788
398
398
  langchain_agentx/tool_runtime/capabilities.py,sha256=KHwu5KLqrpPKLOTwHhnvIIs9MTmQYeuS2hAFmI_Nsy8,3837
399
399
  langchain_agentx/tool_runtime/classifier_denial_bridge.py,sha256=Wv40rYc5U3Mn7G3H7sUWrcG78HyLKnrRXvv7Yv9wI5U,2743
@@ -404,14 +404,14 @@ langchain_agentx/tool_runtime/denial_tracking_bridge.py,sha256=qssnZ_tzCIrDeJvtx
404
404
  langchain_agentx/tool_runtime/errors.py,sha256=Ed1FMjBdPfr0WG-YwLIm_7jokl9k_DjHFNiewZTeQfg,8883
405
405
  langchain_agentx/tool_runtime/failure_event_emitter.py,sha256=C7c4Gc7Vo_R6_ah2Xxa2eso7l9Iuz_KTgRV0j0B08rA,10467
406
406
  langchain_agentx/tool_runtime/identical_call_cache.py,sha256=v8WWuTHWR5ThujcMO4Ty28mZS_w-JN24267fZ4PHWK8,3865
407
- langchain_agentx/tool_runtime/inner_permission_chain.py,sha256=zNjrEeeqIZDs_wZzmrfWqFXxCPxgSesEz2VFr1f37S0,16639
407
+ langchain_agentx/tool_runtime/inner_permission_chain.py,sha256=k0uf-Tvr4NitX9xsSvGki2iuwBn0IZZ0t_rQf49CbnE,17075
408
408
  langchain_agentx/tool_runtime/limits.py,sha256=imE1IetmyKQM82INR0VkP3qZNM4bjUJuf1CG5BkY0uw,356
409
409
  langchain_agentx/tool_runtime/loader.py,sha256=ZeT-xIB6TDkehqyYWx1gkvI0aKx9_xKDKJhqyIvlAvw,9397
410
410
  langchain_agentx/tool_runtime/loop_loader.py,sha256=C_4T9XxlDmKaTzGv4MO6mJuR-rd6uueb1ZWwEKvvFaE,9087
411
411
  langchain_agentx/tool_runtime/loop_runtime_context.py,sha256=HBZMdtKD7MpU8o7JmURFZGPTfxr2aFFlFF2nBZR_n8s,3613
412
412
  langchain_agentx/tool_runtime/messages.py,sha256=Fp-ZiLAbOQAQa8uIv-owE8PXtWyhpYSXxtzy3PVbKSw,3631
413
413
  langchain_agentx/tool_runtime/models.py,sha256=cO9EgLKPXiktHl_xXtBwLQrCo6mj4tbT4WoPmuFLE0w,20345
414
- langchain_agentx/tool_runtime/outer_permission_resolver.py,sha256=X3rocXXLvnXCUMufG-mBr1Mk0So7FxLd5nrZo9OE5kg,3763
414
+ langchain_agentx/tool_runtime/outer_permission_resolver.py,sha256=t6vq1f6K0EYZFAlEBV-Ic2hoGB3miVZWqvrZOQv-Z0A,4169
415
415
  langchain_agentx/tool_runtime/override.py,sha256=D8TRftoeWzqlTuWCGUxNkFY7XzWx_d5oxI_ltNibqPA,10258
416
416
  langchain_agentx/tool_runtime/path_safety.py,sha256=dUrl2SObKmRDwdm9k8veO_Eh0iXw0LPLAMZJGxeKnTE,8548
417
417
  langchain_agentx/tool_runtime/permission_context.py,sha256=ReVV2kjVWAPTsPaYXxRB-dICqualEvi2zzwF8NX_Wkk,6229
@@ -524,7 +524,7 @@ langchain_agentx/tools/ask_user_question/constants.py,sha256=vK5QraZBBVj7woW1TF0
524
524
  langchain_agentx/tools/ask_user_question/html_preview.py,sha256=OwNpsH9qm8iJ-TTbzkMFvG49T4-oNJXJXH4OZ8r55wc,3913
525
525
  langchain_agentx/tools/ask_user_question/models.py,sha256=uLc2UK_v8iMFEL1Zk0mUOBYdcg2HfbaLdH68o8kr7GE,3376
526
526
  langchain_agentx/tools/ask_user_question/prompt.py,sha256=0RdVuUeNzQBzPeVrLcbiBqh1uizFgUANvaKOZpVy_qg,2803
527
- langchain_agentx/tools/ask_user_question/tool.py,sha256=-f41ZDny0gi3HLniZ4IoBJJ9bKOQR6GB5D6CE9MpVbI,13362
527
+ langchain_agentx/tools/ask_user_question/tool.py,sha256=KGIjeLD9J_3RR-C3fGpOsuqjULmuobohG0F2ie8i8UI,13405
528
528
  langchain_agentx/tools/ask_user_question/validators.py,sha256=gUYuuKJNrExWGvhFlmhqqSU8ax7s4EhXMvTEjapHeiY,5974
529
529
  langchain_agentx/tools/bash/__init__.py,sha256=molPHFDylE2wWG_aQx7fb0ciAx3wWpdXzIixTZV5ne4,214
530
530
  langchain_agentx/tools/bash/ast_security.py,sha256=6DFd_TwT986dbGkKT3UnDIZioBdmi8mbJcYSI-XEtdM,22444
@@ -591,7 +591,7 @@ langchain_agentx/tools/plan_mode/__init__.py,sha256=wO5FX24xEB0Dx9h6bysBt1ql3wn0
591
591
  langchain_agentx/tools/plan_mode/constants.py,sha256=vBjcx9JTSOhU9jfCJ4RKnCxVQPn0HzHapouKxRf2Zns,293
592
592
  langchain_agentx/tools/plan_mode/models.py,sha256=kRHPJetlB9X5nAq7-bWm1WcC68YsAj17UxY7fR6TpZ4,1204
593
593
  langchain_agentx/tools/plan_mode/prompt.py,sha256=69o04P598fYs70EaHmpx6_XTk6fgxj06njn5Qq51YF0,3935
594
- langchain_agentx/tools/plan_mode/tool.py,sha256=SBp3MZoPEsLiDOu6qXYDIxZwkG0z8OpLDSqIW2aT3iM,8717
594
+ langchain_agentx/tools/plan_mode/tool.py,sha256=IDOPKUn2cdvO43Evsu5Ns0U6x1T3aji8IOtqdBDDyYU,8852
595
595
  langchain_agentx/tools/read/__init__.py,sha256=82jaYnSYVxREh7HR3tiPAoNLQGmdCsWlkFXHyUg9-ME,217
596
596
  langchain_agentx/tools/read/backend.py,sha256=YqKJ5jzMIrND3WC582jDvVA2mh2rKZ12LK9Vt-j3bz0,14524
597
597
  langchain_agentx/tools/read/limits.py,sha256=JrCEv1UCzBYevf0rDgGOFFfOAHCo04LjLOCj5m1rmbc,2843
@@ -696,7 +696,7 @@ langchain_agentx/utils/permissions/filesystem.py,sha256=79vRSRPnPadHlDOOYvvbuJaJ
696
696
  langchain_agentx/utils/settings/__init__.py,sha256=UXzHZmrBJsO8ZpDmHfclHXpS7rfpmqRoXEnmTFbtVpE,172
697
697
  langchain_agentx/utils/settings/managed_path.py,sha256=MVcw4F9bTrhKqTLom8ZiiqSqCREMbGcAK9Lt8hkD67M,1155
698
698
  langchain_agentx/workflow/__init__.py,sha256=wgjJM2wW0DbFHjsNbq2bKYgFs3BIPFRuQbH8Ry5kfys,4324
699
- langchain_agentx/workflow/base.py,sha256=rzZTH0ciepTglXfhDMkhl1uiJV4d_bXkOgpHlmu-N0w,33409
699
+ langchain_agentx/workflow/base.py,sha256=g4U7hO4fNRBiwh8Y3yLiU8Rgo1AgahaXV1L7lPob32c,33600
700
700
  langchain_agentx/workflow/batch.py,sha256=rdE9xbQ2-SI3-6yNTsKoSylDoTD5B0djLSKwqy1BdZ8,5474
701
701
  langchain_agentx/workflow/catalog_registry.py,sha256=tYUny5FkHwQU-RRUxOdxaJhiRV_9VRXU636Yn_Gzt-g,2109
702
702
  langchain_agentx/workflow/dag.py,sha256=Y1IR1IwnM79Xuev6HZnOvAE3Q23MRnA9lu4vg2Cie48,4469
@@ -706,7 +706,7 @@ langchain_agentx/workflow/execution.py,sha256=iCEkPgLkaoEM4cB6o7KAqIaBpFuY5HtGGI
706
706
  langchain_agentx/workflow/loop_factory.py,sha256=hCShf_gDnesW2A9JspaUY3upp3NCIguII_wRiXnSIUM,3954
707
707
  langchain_agentx/workflow/memory_drain_registry.py,sha256=Xm_ytbB-BbRIu3-h-KhptsCsmmueOiNZePUuG1hk8zk,1681
708
708
  langchain_agentx/workflow/memory_session_policy.py,sha256=2FI0ZbAA6MnxJexnLYLadQpiqipPQwVnUrTWgl55A74,3333
709
- langchain_agentx/workflow/node.py,sha256=0lFVxCKzCsrN61wBkZpniWwLVXPEwvedmCnqtljIvL8,4891
709
+ langchain_agentx/workflow/node.py,sha256=03DtGBYkpFIv_XWMwLQsgWgS0aK4eHxvMfCI5DiBEmE,5069
710
710
  langchain_agentx/workflow/node_adapter.py,sha256=3ZjXhN-Yqg2JzYpRsvnhOvw8-gvGdzmFYkDG2AFndX4,5330
711
711
  langchain_agentx/workflow/projection_isolation.py,sha256=kx6cM8ZtZAFA2VZ8yBIgVaIQE5o4ZfvSoY3mcxSe3hk,634
712
712
  langchain_agentx/workflow/r8_event_stream_benchmark.py,sha256=VdDOWoK3yoGjYyVpAIN3qoQrChz6Ot8sxDw7Uh8RdhU,6562
@@ -716,7 +716,7 @@ langchain_agentx/workflow/run_session.py,sha256=LuFY52uvYfOBGD_Yi878pO5N2bVWJnVG
716
716
  langchain_agentx/workflow/runtime.py,sha256=DdL66SlcvTyU9KxA-JAS4dFxWuJXlYGQdtmBmZfk3dc,3267
717
717
  langchain_agentx/workflow/runtime_scope_path.py,sha256=k1PLnHK-xFEui6birSCWPZeKKV4_oXIip3mst_xDICo,2687
718
718
  langchain_agentx/workflow/runtime_scope_registry.py,sha256=WgyWAWTuM6xZl6ik2pAZCWBwToeTOaSu94kYqJKY2jU,2945
719
- langchain_agentx/workflow/state.py,sha256=zdtf2x547iAyLKBza2Ye0ROOkeSLoWEkNMUVbLfb1g4,2105
719
+ langchain_agentx/workflow/state.py,sha256=PCSqwlJIP2rMg-TFhDFK2KzWXTC2dEn1q7eVCK1z4SY,9155
720
720
  langchain_agentx/workflow/structure_collector.py,sha256=w2ryitiR9t48DrYGBbR4zlSBOaa7dtrD0XqR23BbSHk,13574
721
721
  langchain_agentx/workflow/structure_errors.py,sha256=yYulfRRc70RU2rKjyJYEIhIspCH5taRa72kAwl3nOAA,941
722
722
  langchain_agentx/workflow/structure_validation.py,sha256=resy8jK_V1mKd_BQykwmpbesg6Yl2QbLavEUEQB2O_w,17698
@@ -761,8 +761,8 @@ langchain_agentx/workspace/root_grant_manager.py,sha256=W3gy8HTevbERbXqIgRcjzOXO
761
761
  langchain_agentx/workspace/tool_boundary.py,sha256=UDwX6swpSLsx9HNkYuuRRiV5o7ZZG_Bru2Yn0c5kNX8,5724
762
762
  langchain_agentx/workspace/validators.py,sha256=tQt-6TOcL8Fw7Ig5ebA9S7vGWh1rby920eFW6x8Tk9E,1439
763
763
  langchain_agentx/workspace/view.py,sha256=PGasqTaqhlD03SXXazHuw4RHfV681AIdlsYqL70pEjc,4774
764
- langchain_agentx_python-2.2.4.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
765
- langchain_agentx_python-2.2.4.dist-info/METADATA,sha256=X5bLG_gFcxVwOPDJ6PWzNl-HYGukdx7N2B-TNv6ECsc,24250
766
- langchain_agentx_python-2.2.4.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
767
- langchain_agentx_python-2.2.4.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
768
- langchain_agentx_python-2.2.4.dist-info/RECORD,,
764
+ langchain_agentx_python-2.2.6.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
765
+ langchain_agentx_python-2.2.6.dist-info/METADATA,sha256=aFUHiJcRrYfmX1zz5EcopI4JNyrKygDP2OeT6HlaEPg,24250
766
+ langchain_agentx_python-2.2.6.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
767
+ langchain_agentx_python-2.2.6.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
768
+ langchain_agentx_python-2.2.6.dist-info/RECORD,,