langchain-agentx-python 2.2.9__py3-none-any.whl → 2.3.0__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.9"
14
+ __version__ = "2.3.0"
15
15
 
16
16
  from .loop import ( # noqa: F401
17
17
  create_loop_agent,
@@ -209,12 +209,13 @@ class InnerPermissionChain:
209
209
  command = data.get("command")
210
210
  if not isinstance(command, str) or not command.strip():
211
211
  return None
212
- deny_result = matcher.match_deny(tool_name, command)
213
- if deny_result is not None:
214
- return deny_result
215
- ask_result = matcher.match_ask(tool_name, command)
216
- if ask_result is not None:
217
- return ask_result
212
+ from langchain_agentx.tools.bash.bash_registry_content import (
213
+ evaluate_bash_inner_content_rules,
214
+ )
215
+
216
+ content_decision = evaluate_bash_inner_content_rules(command, registry)
217
+ if content_decision is not None:
218
+ return content_decision
218
219
  return None
219
220
 
220
221
  path = self._engine._extract_path(data)
@@ -127,6 +127,15 @@ def _content_rule_matches_target(
127
127
  target=target,
128
128
  rule_content=rule_content,
129
129
  )
130
+ if tool_name == "Skill":
131
+ from langchain_agentx.tools.skill.registry_permission import (
132
+ skill_rule_content_matches,
133
+ )
134
+
135
+ return skill_rule_content_matches(
136
+ skill_name=target,
137
+ rule_content=rule_content,
138
+ )
130
139
  return fnmatch.fnmatch(target, rule_content)
131
140
 
132
141
 
@@ -0,0 +1,106 @@
1
+ """
2
+ tools/bash/bash_registry_content.py — Bash cliArg 内容 deny/ask(compound 段级 · Phase D)
3
+
4
+ 职责:
5
+ Inner 段 1 对 Bash 按 AST permission_segments 评估内容级 deny/ask(对齐 CC compound 子命令优先 deny)。
6
+
7
+ 链路位置:
8
+ InnerPermissionChain._segment_1_2_global(Bash 分支)。
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from langchain_agentx.tool_runtime.models import AuthorizationDecision
14
+ from langchain_agentx.tool_runtime.permission_rule_matcher import (
15
+ RegistryPermissionMatcher,
16
+ _decision_from_legacy_glob,
17
+ _decision_from_rule,
18
+ )
19
+ from langchain_agentx.tool_runtime.permission_rules import (
20
+ PermissionRuleBehavior,
21
+ PermissionRuleRegistry,
22
+ )
23
+ from langchain_agentx.tools.bash.shell_rule_matching import match_shell_permission_rule
24
+
25
+
26
+ def bash_permission_segments(command: str) -> list[str]:
27
+ from langchain_agentx.tools.bash.ast_security import BashAstAnalyzer
28
+
29
+ analysis = BashAstAnalyzer().analyze(command)
30
+ segments = [s.strip() for s in analysis.permission_segments if s and s.strip()]
31
+ return segments or [command.strip()]
32
+
33
+
34
+ def _segment_content_decision(
35
+ segment: str,
36
+ registry: PermissionRuleRegistry,
37
+ behavior: PermissionRuleBehavior,
38
+ ) -> AuthorizationDecision | None:
39
+ matcher = RegistryPermissionMatcher(registry)
40
+ if behavior is PermissionRuleBehavior.DENY:
41
+ direct = matcher.match_deny("Bash", segment)
42
+ else:
43
+ direct = matcher.match_ask("Bash", segment)
44
+ if direct is not None:
45
+ return direct
46
+
47
+ legacy = registry.find_legacy_glob_match(segment, behavior)
48
+ if legacy is not None:
49
+ return _decision_from_legacy_glob(legacy, behavior=behavior.value)
50
+
51
+ for rule in registry.iter_rules(behavior):
52
+ if rule.tool_name != "Bash" or not rule.rule_content:
53
+ continue
54
+ if match_shell_permission_rule(rule.rule_content, segment, match_mode="prefix"):
55
+ return _decision_from_rule(rule, behavior=behavior.value)
56
+ return None
57
+
58
+
59
+ def evaluate_bash_inner_content_rules(
60
+ command: str,
61
+ registry: PermissionRuleRegistry,
62
+ ) -> AuthorizationDecision | None:
63
+ """CC compound:段级 deny 优先 → full deny/ask → 段级 ask。"""
64
+ cmd = command.strip()
65
+ if not cmd:
66
+ return None
67
+
68
+ matcher = RegistryPermissionMatcher(registry)
69
+ full_deny = matcher.match_deny("Bash", cmd)
70
+ if full_deny is not None:
71
+ return full_deny
72
+
73
+ segments = bash_permission_segments(cmd)
74
+ if len(segments) > 1:
75
+ for segment in segments:
76
+ seg_deny = _segment_content_decision(
77
+ segment, registry, PermissionRuleBehavior.DENY
78
+ )
79
+ if seg_deny is not None:
80
+ return seg_deny
81
+
82
+ full_ask = matcher.match_ask("Bash", cmd)
83
+ if full_ask is not None:
84
+ return full_ask
85
+
86
+ if len(segments) > 1:
87
+ first_ask: AuthorizationDecision | None = None
88
+ for segment in segments:
89
+ seg_ask = _segment_content_decision(
90
+ segment, registry, PermissionRuleBehavior.ASK
91
+ )
92
+ if seg_ask is not None and first_ask is None:
93
+ first_ask = seg_ask
94
+ if first_ask is not None:
95
+ return first_ask
96
+
97
+ if len(segments) == 1:
98
+ return _segment_content_decision(
99
+ segments[0], registry, PermissionRuleBehavior.DENY
100
+ ) or _segment_content_decision(
101
+ segments[0], registry, PermissionRuleBehavior.ASK
102
+ )
103
+ return None
104
+
105
+
106
+ __all__ = ["bash_permission_segments", "evaluate_bash_inner_content_rules"]
@@ -10,9 +10,10 @@ tools/bash/command_allow_rules.py — Bash 内容级 allow 匹配(slash comman
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
- import fnmatch
14
13
  from typing import TYPE_CHECKING
15
14
 
15
+ from langchain_agentx.tools.bash.shell_rule_matching import match_shell_permission_rule
16
+
16
17
  from langchain_agentx.tool_runtime.models import AuthorizationDecision, ToolExecutionContext
17
18
  from langchain_agentx.tool_runtime.permission_context import get_command_bash_allow_rules
18
19
  from langchain_agentx.tool_runtime.permission_rule_matcher import RegistryPermissionMatcher
@@ -28,22 +29,17 @@ if TYPE_CHECKING:
28
29
 
29
30
 
30
31
  def bash_command_matches_allow_rule(command: str, rule_content: str) -> bool:
31
- """CC prefix:* 与简单 fnmatch 子集。"""
32
+ """CC shellRuleMatching(prefix / wildcard / exact)。"""
32
33
  cmd = command.strip()
33
34
  pattern = rule_content.strip()
34
35
  if not cmd or not pattern:
35
36
  return False
36
-
37
- if pattern.endswith(":*"):
38
- prefix = pattern[:-2].rstrip()
39
- if not prefix:
40
- return False
41
- return cmd == prefix or cmd.startswith(f"{prefix} ")
42
-
43
- if "*" in pattern or "?" in pattern or "[" in pattern:
44
- return fnmatch.fnmatch(cmd, pattern)
45
-
46
- return cmd == pattern or cmd.startswith(f"{pattern} ")
37
+ return match_shell_permission_rule(
38
+ pattern,
39
+ cmd,
40
+ match_mode="prefix",
41
+ is_compound=False,
42
+ )
47
43
 
48
44
 
49
45
  def try_command_allow_decision(
@@ -99,6 +95,51 @@ def try_registry_bash_content_allow_decision(
99
95
  return matcher.match_allow("Bash", command.strip())
100
96
 
101
97
 
98
+ def registry_has_cliarg_bash_allow(registry: PermissionRuleRegistry) -> bool:
99
+ for rule in registry.iter_rules(PermissionRuleBehavior.ALLOW):
100
+ if rule.source_name == "cliArg" and rule.tool_name == "Bash":
101
+ return True
102
+ return False
103
+
104
+
105
+ def promote_unscoped_bash_passthrough_to_ask(
106
+ decision: AuthorizationDecision,
107
+ *,
108
+ command: str,
109
+ ctx: ToolExecutionContext,
110
+ policy_engine: DefaultPolicyEngine | None,
111
+ ) -> AuthorizationDecision:
112
+ """无 cliArg Bash allow 时,write_roots 静默 allow → ask(对齐 CC passthrough)。"""
113
+ if policy_engine is None or decision.behavior != "allow":
114
+ return decision
115
+ if _READ_ONLY_CLASSIFIER.classify(
116
+ command.strip(),
117
+ shell_ops_already_resolved=True,
118
+ ).is_read_only:
119
+ return decision
120
+ if decision.policy_id != "write_roots":
121
+ return decision
122
+ registry = build_permission_rule_registry(
123
+ policy_config=policy_engine._config,
124
+ session_store=ctx.session_store,
125
+ workspace_root=ctx.workspace_root,
126
+ agent_home_segment=ctx.agent_home_segment,
127
+ )
128
+ if registry_has_cliarg_bash_allow(registry):
129
+ return decision
130
+ if cliarg_bash_has_content_allow_without_bare_tool(registry):
131
+ return decision
132
+ return AuthorizationDecision(
133
+ behavior="ask",
134
+ message=decision.message,
135
+ policy_id="bash_passthrough",
136
+ ask_prompt=(
137
+ decision.ask_prompt
138
+ or f"Allow Bash command?\n{command.strip()}"
139
+ ),
140
+ )
141
+
142
+
102
143
  def promote_unmatched_cliarg_content_only_allow_to_ask(
103
144
  decision: AuthorizationDecision,
104
145
  *,
@@ -0,0 +1,143 @@
1
+ """
2
+ tools/bash/shell_rule_matching.py — CC shellRuleMatching.ts 对齐(Phase D)
3
+
4
+ 职责:
5
+ prefix :*、wildcard(含 \\* / \\\\ 转义)、``git *`` 尾 wildcard 可选参数语义。
6
+
7
+ 链路位置:
8
+ command_allow_rules.bash_command_matches_permission_rule。
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import re
14
+ from dataclasses import dataclass
15
+ from typing import Literal
16
+
17
+ _ESCAPED_STAR = "\x00ESCAPED_STAR\x00"
18
+ _ESCAPED_BACKSLASH = "\x00ESCAPED_BACKSLASH\x00"
19
+
20
+
21
+ def permission_rule_extract_prefix(permission_rule: str) -> str | None:
22
+ m = re.match(r"^(.+):\*$", permission_rule.strip())
23
+ return m.group(1) if m else None
24
+
25
+
26
+ def has_wildcards(pattern: str) -> bool:
27
+ text = pattern.strip()
28
+ if text.endswith(":*"):
29
+ return False
30
+ i = 0
31
+ while i < len(text):
32
+ if text[i] == "*":
33
+ backslashes = 0
34
+ j = i - 1
35
+ while j >= 0 and text[j] == "\\":
36
+ backslashes += 1
37
+ j -= 1
38
+ if backslashes % 2 == 0:
39
+ return True
40
+ i += 1
41
+ return False
42
+
43
+
44
+ def match_wildcard_pattern(
45
+ pattern: str,
46
+ command: str,
47
+ *,
48
+ case_insensitive: bool = False,
49
+ ) -> bool:
50
+ """对齐 CC ``matchWildcardPattern``(含 trailing `` *`` → optional args)。"""
51
+ trimmed = pattern.strip()
52
+ processed = ""
53
+ i = 0
54
+ while i < len(trimmed):
55
+ ch = trimmed[i]
56
+ if ch == "\\" and i + 1 < len(trimmed):
57
+ nxt = trimmed[i + 1]
58
+ if nxt == "*":
59
+ processed += _ESCAPED_STAR
60
+ i += 2
61
+ continue
62
+ if nxt == "\\":
63
+ processed += _ESCAPED_BACKSLASH
64
+ i += 2
65
+ continue
66
+ processed += ch
67
+ i += 1
68
+
69
+ escaped = re.sub(r"[.+?^${}()|\[\]\\'\"]", r"\\\g<0>", processed)
70
+ with_wildcards = escaped.replace("*", ".*")
71
+ regex_body = with_wildcards.replace(_ESCAPED_STAR, r"\*").replace(
72
+ _ESCAPED_BACKSLASH, r"\\"
73
+ )
74
+
75
+ unescaped_stars = processed.count("*")
76
+ if regex_body.endswith(" .*") and unescaped_stars == 1:
77
+ regex_body = regex_body[:-3] + "( .*)?"
78
+
79
+ flags = re.DOTALL
80
+ if case_insensitive:
81
+ flags |= re.IGNORECASE
82
+ return re.fullmatch(f"^{regex_body}$", command, flags=flags) is not None
83
+
84
+
85
+ @dataclass(frozen=True)
86
+ class ShellPermissionRule:
87
+ kind: Literal["exact", "prefix", "wildcard"]
88
+ value: str
89
+
90
+
91
+ def parse_permission_rule(rule_content: str) -> ShellPermissionRule:
92
+ text = rule_content.strip()
93
+ prefix = permission_rule_extract_prefix(text)
94
+ if prefix is not None:
95
+ return ShellPermissionRule(kind="prefix", value=prefix)
96
+ if has_wildcards(text):
97
+ return ShellPermissionRule(kind="wildcard", value=text)
98
+ return ShellPermissionRule(kind="exact", value=text)
99
+
100
+
101
+ def match_shell_permission_rule(
102
+ rule_content: str,
103
+ command: str,
104
+ *,
105
+ match_mode: Literal["exact", "prefix"] = "prefix",
106
+ is_compound: bool = False,
107
+ ) -> bool:
108
+ """单条 Bash 内容规则对单段 command 的匹配(CC ``bashPermissionRule`` 分支)。"""
109
+ cmd = command.strip()
110
+ if not cmd:
111
+ return False
112
+ parsed = parse_permission_rule(rule_content)
113
+
114
+ if parsed.kind == "exact":
115
+ return parsed.value == cmd
116
+
117
+ if parsed.kind == "prefix":
118
+ if match_mode == "exact":
119
+ return parsed.value == cmd
120
+ if is_compound:
121
+ return False
122
+ prefix = parsed.value
123
+ if cmd == prefix:
124
+ return True
125
+ if cmd.startswith(prefix + " "):
126
+ return True
127
+ xargs_prefix = "xargs " + prefix
128
+ if cmd == xargs_prefix or cmd.startswith(xargs_prefix + " "):
129
+ return True
130
+ return False
131
+
132
+ if match_mode == "exact":
133
+ return False
134
+ if is_compound:
135
+ return False
136
+ return match_wildcard_pattern(parsed.value, cmd)
137
+
138
+
139
+ __all__ = [
140
+ "match_shell_permission_rule",
141
+ "match_wildcard_pattern",
142
+ "parse_permission_rule",
143
+ ]
@@ -1034,7 +1034,17 @@ class BashRuntimeTool(RuntimeTool):
1034
1034
  return decision
1035
1035
 
1036
1036
  final = self._authorize_sed_segment(command=command, ctx=ctx, cwd=cwd) or decision
1037
- return promote_unmatched_cliarg_content_only_allow_to_ask(
1037
+ final = promote_unmatched_cliarg_content_only_allow_to_ask(
1038
+ final,
1039
+ command=command,
1040
+ ctx=ctx,
1041
+ policy_engine=self._policy,
1042
+ )
1043
+ from langchain_agentx.tools.bash.command_allow_rules import (
1044
+ promote_unscoped_bash_passthrough_to_ask,
1045
+ )
1046
+
1047
+ return promote_unscoped_bash_passthrough_to_ask(
1038
1048
  final,
1039
1049
  command=command,
1040
1050
  ctx=ctx,
@@ -0,0 +1,99 @@
1
+ """
2
+ tools/skill/registry_permission.py — Skill 内容级 deny/allow(CC SkillTool.checkPermissions · Phase D)
3
+
4
+ 职责:
5
+ Skill(name) / Skill(prefix:*) 与 registry 规则匹配。
6
+
7
+ 链路位置:
8
+ SkillRuntimeTool.run_l1_permission_check(frontmatter 约束之前)。
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import TYPE_CHECKING, Any
14
+
15
+ from langchain_agentx.tool_runtime.models import AuthorizationDecision
16
+ from langchain_agentx.tool_runtime.permission_decision import (
17
+ attach_decision_reason,
18
+ make_other_decision_reason,
19
+ )
20
+ from langchain_agentx.tool_runtime.permission_rule_matcher import RegistryPermissionMatcher
21
+ from langchain_agentx.tool_runtime.permission_rules import build_permission_rule_registry
22
+ from langchain_agentx.tools.bash.shell_rule_matching import match_shell_permission_rule
23
+
24
+ if TYPE_CHECKING:
25
+ from langchain_agentx.tool_runtime.models import ToolExecutionContext
26
+
27
+
28
+ def skill_permission_rule_content(skill_name: str) -> str:
29
+ text = skill_name.strip()
30
+ if text.startswith("/"):
31
+ text = text[1:]
32
+ return text
33
+
34
+
35
+ def skill_rule_content_matches(*, skill_name: str, rule_content: str) -> bool:
36
+ """对齐 CC ``ruleMatches``:精确或 ``prefix:*``。"""
37
+ command_name = skill_permission_rule_content(skill_name)
38
+ normalized_rule = rule_content.strip()
39
+ if normalized_rule.startswith("/"):
40
+ normalized_rule = normalized_rule[1:]
41
+ if normalized_rule == command_name:
42
+ return True
43
+ if normalized_rule.endswith(":*"):
44
+ prefix = normalized_rule[:-2]
45
+ return command_name.startswith(prefix)
46
+ return match_shell_permission_rule(
47
+ normalized_rule, command_name, match_mode="prefix"
48
+ )
49
+
50
+
51
+ def evaluate_skill_registry_permission(
52
+ skill_name: str,
53
+ ctx: ToolExecutionContext,
54
+ policy_engine: Any,
55
+ ) -> AuthorizationDecision | None:
56
+ if policy_engine is None:
57
+ return None
58
+ registry = build_permission_rule_registry(
59
+ policy_config=policy_engine._config,
60
+ session_store=ctx.session_store,
61
+ workspace_root=ctx.workspace_root,
62
+ agent_home_segment=ctx.agent_home_segment,
63
+ )
64
+ target = skill_permission_rule_content(skill_name)
65
+ matcher = RegistryPermissionMatcher(registry)
66
+ for match_fn in (matcher.match_deny, matcher.match_ask, matcher.match_allow):
67
+ matched = match_fn("Skill", target)
68
+ if matched is not None:
69
+ return matched
70
+ return None
71
+
72
+
73
+ def skill_default_ask_decision(skill_name: str) -> AuthorizationDecision:
74
+ target = skill_permission_rule_content(skill_name)
75
+ suggestions = (
76
+ {
77
+ "type": "addRules",
78
+ "destination": "localSettings",
79
+ "behavior": "allow",
80
+ "rules": [{"toolName": "Skill", "ruleContent": target}],
81
+ },
82
+ )
83
+ decision = AuthorizationDecision(
84
+ behavior="ask",
85
+ ask_prompt=f"Allow skill {target}?",
86
+ policy_id="skill_default",
87
+ metadata={"suggestions": suggestions},
88
+ )
89
+ return attach_decision_reason(
90
+ decision,
91
+ make_other_decision_reason("Skill default permission prompt"),
92
+ )
93
+
94
+
95
+ __all__ = [
96
+ "evaluate_skill_registry_permission",
97
+ "skill_default_ask_decision",
98
+ "skill_rule_content_matches",
99
+ ]
@@ -187,6 +187,24 @@ class SkillRuntimeTool(RuntimeTool):
187
187
  ),
188
188
  )
189
189
 
190
+ from langchain_agentx.tools.skill.registry_permission import (
191
+ evaluate_skill_registry_permission,
192
+ )
193
+
194
+ registry_decision = evaluate_skill_registry_permission(
195
+ inp.skill_name,
196
+ ctx,
197
+ self._policy,
198
+ )
199
+ if registry_decision is not None:
200
+ if registry_decision.behavior == "allow":
201
+ pass
202
+ else:
203
+ return L1PermissionResult(
204
+ outcome=registry_decision.behavior,
205
+ decision=registry_decision,
206
+ )
207
+
190
208
  local = self._constraint_evaluator.evaluate(cmd.frontmatter)
191
209
  if local.behavior != "allow":
192
210
  return L1PermissionResult(outcome=local.behavior, decision=local)
@@ -40,8 +40,32 @@ def webfetch_permission_rule_content(url: str) -> str:
40
40
 
41
41
 
42
42
  def webfetch_rule_content_matches(*, target: str, rule_content: str) -> bool:
43
- """WebFetch 内容规则:target 与 rule 均为 ``domain:host`` 或 ``input:…``。"""
44
- return target.strip().lower() == rule_content.strip().lower()
43
+ """WebFetch 内容规则:``domain:host`` 精确或 ``domain:*.example.com`` wildcard(Phase D)。"""
44
+ t = target.strip().lower()
45
+ r = rule_content.strip().lower()
46
+ if t == r:
47
+ return True
48
+ if not r.startswith("domain:") or not t.startswith("domain:"):
49
+ return False
50
+ host_pattern = r[len("domain:") :]
51
+ host_target = t[len("domain:") :]
52
+ if "*" not in host_pattern and "?" not in host_pattern:
53
+ return False
54
+ from langchain_agentx.tools.bash.shell_rule_matching import match_wildcard_pattern
55
+
56
+ return match_wildcard_pattern(host_pattern, host_target)
57
+
58
+
59
+ def webfetch_allow_suggestions(rule_content: str) -> tuple[dict[str, object], ...]:
60
+ """对齐 CC WebFetchTool ``buildSuggestions``(L3 ``metadata.suggestions``)。"""
61
+ return (
62
+ {
63
+ "type": "addRules",
64
+ "destination": "localSettings",
65
+ "behavior": "allow",
66
+ "rules": [{"toolName": "WebFetch", "ruleContent": rule_content}],
67
+ },
68
+ )
45
69
 
46
70
 
47
71
  def evaluate_webfetch_registry_permission(
@@ -60,6 +84,16 @@ def evaluate_webfetch_registry_permission(
60
84
  for match_fn in (matcher.match_deny, matcher.match_ask, matcher.match_allow):
61
85
  matched = match_fn("WebFetch", target)
62
86
  if matched is not None:
87
+ if matched.behavior == "ask":
88
+ meta = dict(matched.metadata or {})
89
+ meta.setdefault("suggestions", webfetch_allow_suggestions(target))
90
+ return AuthorizationDecision(
91
+ behavior=matched.behavior,
92
+ message=matched.message,
93
+ policy_id=matched.policy_id,
94
+ ask_prompt=matched.ask_prompt,
95
+ metadata=meta,
96
+ )
63
97
  return matched
64
98
  decision = AuthorizationDecision(
65
99
  behavior="ask",
@@ -67,6 +101,7 @@ def evaluate_webfetch_registry_permission(
67
101
  "Claude requested permissions to use WebFetch, but you haven't granted it yet."
68
102
  ),
69
103
  policy_id="webfetch_default",
104
+ metadata={"suggestions": webfetch_allow_suggestions(target)},
70
105
  )
71
106
  return attach_decision_reason(
72
107
  decision,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langchain-agentx-python
3
- Version: 2.2.9
3
+ Version: 2.3.0
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=sLs2vKbNQCEmhW-uC3NdfDAK1zHUjcNzPxy1y2UPlqg,1614
1
+ langchain_agentx/__init__.py,sha256=8oCd_P48WoQZB9jQROU6rc2POQ3qA6K1LHWG1xtaSPo,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
@@ -404,7 +404,7 @@ 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=SSr45DuwiuKxoyb3r7DdrRu7YUFzKIWBCmTYhBKFO68,17594
407
+ langchain_agentx/tool_runtime/inner_permission_chain.py,sha256=50wYXRu7Hi-rvDiI2QxSLC4uBAsJwG3Vp-v3AutLY4E,17629
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
@@ -419,7 +419,7 @@ langchain_agentx/tool_runtime/permission_context.py,sha256=ReVV2kjVWAPTsPaYXxRB-
419
419
  langchain_agentx/tool_runtime/permission_decision.py,sha256=-dWuC60MV6PYgHHOsSxr6Qad8Mm3qgMuh6nkzM87LO4,10280
420
420
  langchain_agentx/tool_runtime/permission_orchestrator.py,sha256=nwx76k74aAFgo63tfkoi6zUJTj9-10tnQzj03VYqFuw,4637
421
421
  langchain_agentx/tool_runtime/permission_rule_matcher.py,sha256=z4VesjyvvEry-L2U1VsrJB3SR6wtaG8OOuhvftsvj9U,4725
422
- langchain_agentx/tool_runtime/permission_rules.py,sha256=Aw4qTckMCpQDZpGeAHkRS4fON3ixWU9B5B9W6D2OlMg,19435
422
+ langchain_agentx/tool_runtime/permission_rules.py,sha256=2N66xdR9khrzRY_1OCKsv05oAwWyf45e546NUwC_7hg,19709
423
423
  langchain_agentx/tool_runtime/permission_settings_loader.py,sha256=Xu6dso0ghh4pb7Puf8nj20nXxjGeQvL4kIGycavwG_o,5624
424
424
  langchain_agentx/tool_runtime/permission_settings_sync.py,sha256=g6TvjWwa7D0kw5rDznPsoMv7xylESPOyWA2vZW4HDm0,4590
425
425
  langchain_agentx/tool_runtime/permission_snapshot.py,sha256=xFoi9fIcZjSw_zrIoyglneM-vJsDOLCEjiVoazr5Ack,1947
@@ -532,9 +532,10 @@ langchain_agentx/tools/bash/ast_security.py,sha256=6DFd_TwT986dbGkKT3UnDIZioBdmi
532
532
  langchain_agentx/tools/bash/auto_mode_adapter.py,sha256=7-yb_kGmpytBYkD2Hn5YWPIceo_YN4PatEKj8O7HKsM,4243
533
533
  langchain_agentx/tools/bash/backend.py,sha256=E0DMBAENZLUSLvuEh6RubNJ6iCVnx1d2VGsQzVuLA5k,65361
534
534
  langchain_agentx/tools/bash/bash_hardening.py,sha256=KEYKRC7kS_to4mzXuChvCmOIIb4dSUkOb9K1MBDtWDc,29296
535
+ langchain_agentx/tools/bash/bash_registry_content.py,sha256=YHE3PwuLBeFrEux4xNaDZjJpYtUSMFPLYr6A7g-fFxk,3569
535
536
  langchain_agentx/tools/bash/bash_runtime_contract.py,sha256=s8vrvMl7405KLGw2hPFbzlzWohm5JX3c9cImMBgqh8I,1511
536
537
  langchain_agentx/tools/bash/boundary_check.py,sha256=k9Bv-baIAUDE3-c_Brw3VSXXYMv_g3lTM0mabIadnwc,8822
537
- langchain_agentx/tools/bash/command_allow_rules.py,sha256=-1m-yzTCEBHnomeliejUs-CR9yBr9SqtczKoLZIZKsc,5950
538
+ langchain_agentx/tools/bash/command_allow_rules.py,sha256=RYW1M9QpJa2HuvOeU9dnmoiNhmExKA1Sgv5jPWDd_Ag,7357
538
539
  langchain_agentx/tools/bash/cwd_reporter.py,sha256=mASbKWLb4MiX4zLKY3w1ocIdfhmwj5KRgX4OW_PcAns,2642
539
540
  langchain_agentx/tools/bash/events.py,sha256=xDpPA3zhne2cnlYTmiiPTsV423-h-Nw-VKDR_rlnbGE,6065
540
541
  langchain_agentx/tools/bash/l1_decision_reason.py,sha256=MOL9HBBpJEgypuTiYdNojQBl8eIsTwRge5CtGeYRJKI,5365
@@ -557,8 +558,9 @@ langchain_agentx/tools/bash/semantic_matrix.py,sha256=stvsudu8mGjS1JJCawMAUKabt-
557
558
  langchain_agentx/tools/bash/semantics.py,sha256=pkf4URTulAOVL7m04Rq9JJF7z0J2mTEsGWrjyoY9r6o,5769
558
559
  langchain_agentx/tools/bash/shell_locator.py,sha256=AUnCZS8gmZurCs8rL4y0MMOS9UZimfg5rQ5At38mZKU,6296
559
560
  langchain_agentx/tools/bash/shell_quoting.py,sha256=K4JLVGwU8VpdQzfQB1o3xsq4HoCKHew1pry8hHChcoA,4498
561
+ langchain_agentx/tools/bash/shell_rule_matching.py,sha256=uYEKg2C5M1r0eh3L4b5NCML1Gj2UBdIXeL_u2A6_RyM,3981
560
562
  langchain_agentx/tools/bash/task_runtime.py,sha256=hikVC9YugtvpLf4nDaPlX_GFem1YQvDRwN0ShRflUYU,3568
561
- langchain_agentx/tools/bash/tool.py,sha256=xhuFynhBg4Vcar3WjLoJptlYPoqRnkFiV_lQRi0l6T0,46387
563
+ langchain_agentx/tools/bash/tool.py,sha256=O8wDLMsPM9ryx_BfKo_SaGtlyRb7UyUxDAmOEgUgIek,46699
562
564
  langchain_agentx/tools/bash/windows_shell_quoting.py,sha256=0RzLnTKyFrJ536QzqPZvSyUcQWN794XRlAq2RdHeKHo,1615
563
565
  langchain_agentx/tools/edit/__init__.py,sha256=PiiOHUODUzTRQxxPdE7ZMTjd3vfdzm9LEcn1lpVtg8o,203
564
566
  langchain_agentx/tools/edit/backend.py,sha256=JrikYafZDGMQ2JjXRxbnv1VSHVGRUdLmZN__nnqkM9o,3159
@@ -618,9 +620,10 @@ langchain_agentx/tools/skill/paths_matcher.py,sha256=J4SOBThray_72mrYiQUfJ5Icu6T
618
620
  langchain_agentx/tools/skill/plugin_loader.py,sha256=qT0VcIWkKFmRGGH8-e_f4y1XIpjY71TVbnZwnu2M9_M,1191
619
621
  langchain_agentx/tools/skill/policy.py,sha256=SFlW627gyo_-wyIppAqoytBmrLPlSGw-mbR00gjOJQY,1541
620
622
  langchain_agentx/tools/skill/prompt.py,sha256=tvSqvCGroVdloveiWIYxIPQmpESqzPAs5ZJztvHBdOI,1782
623
+ langchain_agentx/tools/skill/registry_permission.py,sha256=ns_S6IBOdacrZcgHzCOj9rjlPOIecavF5hW-pHmalcY,3258
621
624
  langchain_agentx/tools/skill/repository_factory.py,sha256=7zDoPDZgxoR03CkmKdx9b0aUXwaH8E5LtBYQPGF26rA,1222
622
625
  langchain_agentx/tools/skill/source_paths.py,sha256=7qhErxCyDTBiGZc41i_EqMZi6aueCdY4kvMJ03g6z4s,2996
623
- langchain_agentx/tools/skill/tool.py,sha256=LJvXAjnEONIF0-Z2hBksEuj6qV5coId8AP99ov01pWM,19135
626
+ langchain_agentx/tools/skill/tool.py,sha256=vhiwjeyST9BhsMZmKk8-Vej3JId0AxTPrQ5ebFvguG4,19711
624
627
  langchain_agentx/tools/skill/bundled/__init__.py,sha256=gaCH_mROpv0lIgLjin1VIFu-8hbP2nY1PHoF7vZt2Ns,4516
625
628
  langchain_agentx/tools/skill/bundled/prompts.py,sha256=gcaTnNRlWfHNPgO3EfZxU9vMYbOapMrAduvgaVc-_Fc,4838
626
629
  langchain_agentx/tools/skill/bundled/registry.py,sha256=oxvvFeeUzM-qVPtayVaQp5tfRiMazyln2-rCM86AYa8,6274
@@ -650,7 +653,7 @@ langchain_agentx/tools/webfetch/loader.py,sha256=QCATTqBvQHXiMVuAbGQGQeymVevDfWw
650
653
  langchain_agentx/tools/webfetch/models.py,sha256=e_k3FS_9JLekKsq1auRioLDhUFz4YNUlX3MrvnW5BE0,2561
651
654
  langchain_agentx/tools/webfetch/preapproved.py,sha256=8SjbOZdZla208oml8pzixkA-vvZ9c0kofCQ-3XQCoeQ,4312
652
655
  langchain_agentx/tools/webfetch/prompt.py,sha256=lpiAV9ftjs-M1BS6R5_L_uNAcOPJ5bJ9H-ZE2eq_5OY,3771
653
- langchain_agentx/tools/webfetch/registry_permission.py,sha256=5jSg_c2TuAqNGMA1_C_pSNRufN2fuOaqTOEcitjaQf8,2535
656
+ langchain_agentx/tools/webfetch/registry_permission.py,sha256=lkJx0XhY6XOeYgM3uAsFiFEtWawE5mZMl8IyuQchYSo,3924
654
657
  langchain_agentx/tools/webfetch/summary.py,sha256=wk-5C39VoEIj9OyZtw6DOs6GYtdvPVECb80uGgVwI7w,1038
655
658
  langchain_agentx/tools/webfetch/tool.py,sha256=4qT0nH2DwC8iPEWzmnZjns8lnynXS7muc-2xCgVlbZY,9199
656
659
  langchain_agentx/tools/websearch/__init__.py,sha256=gOVwLv3X9iLUpnN5lhyLeEiovw-JDmzdqxGg7ufkIMY,950
@@ -763,8 +766,8 @@ langchain_agentx/workspace/root_grant_manager.py,sha256=W3gy8HTevbERbXqIgRcjzOXO
763
766
  langchain_agentx/workspace/tool_boundary.py,sha256=UDwX6swpSLsx9HNkYuuRRiV5o7ZZG_Bru2Yn0c5kNX8,5724
764
767
  langchain_agentx/workspace/validators.py,sha256=tQt-6TOcL8Fw7Ig5ebA9S7vGWh1rby920eFW6x8Tk9E,1439
765
768
  langchain_agentx/workspace/view.py,sha256=PGasqTaqhlD03SXXazHuw4RHfV681AIdlsYqL70pEjc,4774
766
- langchain_agentx_python-2.2.9.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
767
- langchain_agentx_python-2.2.9.dist-info/METADATA,sha256=MWx8nrJ8lXDQorwBf7tximEwOMScMgBTbNOqshUd2v0,24250
768
- langchain_agentx_python-2.2.9.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
769
- langchain_agentx_python-2.2.9.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
770
- langchain_agentx_python-2.2.9.dist-info/RECORD,,
769
+ langchain_agentx_python-2.3.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
770
+ langchain_agentx_python-2.3.0.dist-info/METADATA,sha256=PGoShL7qCuKn4cToEl22oCzy1TD3bu1o7uYqnN9rpOk,24250
771
+ langchain_agentx_python-2.3.0.dist-info/WHEEL,sha256=51RkbunBAw4BWsgaQWTpPhg4Diwp3c9P5iaLk67Hdtg,92
772
+ langchain_agentx_python-2.3.0.dist-info/top_level.txt,sha256=Ge284pniNt8xea0OLk2o9o32GqVpDhOYk20fwE-0xxA,17
773
+ langchain_agentx_python-2.3.0.dist-info/RECORD,,