strathon 1.2.2__tar.gz → 1.2.3__tar.gz

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.
Files changed (66) hide show
  1. {strathon-1.2.2/src/strathon.egg-info → strathon-1.2.3}/PKG-INFO +3 -3
  2. {strathon-1.2.2 → strathon-1.2.3}/pyproject.toml +3 -3
  3. strathon-1.2.3/src/strathon/_version.py +1 -0
  4. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/client.py +1 -1
  5. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/config.py +1 -1
  6. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/heartbeat.py +1 -1
  7. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/openai_agents.py +1 -2
  8. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/policy/approval.py +1 -0
  9. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/policy/enforcer.py +15 -0
  10. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/policy/steer.py +0 -2
  11. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/policy/types.py +4 -3
  12. {strathon-1.2.2 → strathon-1.2.3/src/strathon.egg-info}/PKG-INFO +3 -3
  13. {strathon-1.2.2 → strathon-1.2.3}/src/strathon.egg-info/requires.txt +2 -2
  14. {strathon-1.2.2 → strathon-1.2.3}/tests/test_smoke.py +1 -1
  15. strathon-1.2.2/src/strathon/_version.py +0 -1
  16. {strathon-1.2.2 → strathon-1.2.3}/LICENSE +0 -0
  17. {strathon-1.2.2 → strathon-1.2.3}/NOTICE +0 -0
  18. {strathon-1.2.2 → strathon-1.2.3}/README.md +0 -0
  19. {strathon-1.2.2 → strathon-1.2.3}/setup.cfg +0 -0
  20. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/__init__.py +0 -0
  21. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/exceptions.py +0 -0
  22. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/exporter/__init__.py +0 -0
  23. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/exporter/otlp.py +0 -0
  24. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/__init__.py +0 -0
  25. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/anthropic.py +0 -0
  26. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/autogen.py +0 -0
  27. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/claude_agent.py +0 -0
  28. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/crewai.py +0 -0
  29. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/google_adk.py +0 -0
  30. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/langchain.py +0 -0
  31. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/langgraph.py +0 -0
  32. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/openai.py +0 -0
  33. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/instrumentation/pydantic_ai.py +0 -0
  34. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/intervention/__init__.py +0 -0
  35. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/intervention/hooks.py +0 -0
  36. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/policy/__init__.py +0 -0
  37. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/policy/expression.py +0 -0
  38. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/policy/halt_enforcer.py +0 -0
  39. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/policy/throttle.py +0 -0
  40. {strathon-1.2.2 → strathon-1.2.3}/src/strathon/py.typed +0 -0
  41. {strathon-1.2.2 → strathon-1.2.3}/src/strathon.egg-info/SOURCES.txt +0 -0
  42. {strathon-1.2.2 → strathon-1.2.3}/src/strathon.egg-info/dependency_links.txt +0 -0
  43. {strathon-1.2.2 → strathon-1.2.3}/src/strathon.egg-info/top_level.txt +0 -0
  44. {strathon-1.2.2 → strathon-1.2.3}/tests/test_allow_list_mode.py +0 -0
  45. {strathon-1.2.2 → strathon-1.2.3}/tests/test_approval_sdk.py +0 -0
  46. {strathon-1.2.2 → strathon-1.2.3}/tests/test_crewai.py +0 -0
  47. {strathon-1.2.2 → strathon-1.2.3}/tests/test_crewai_intervention.py +0 -0
  48. {strathon-1.2.2 → strathon-1.2.3}/tests/test_enforcement_matrix.py +0 -0
  49. {strathon-1.2.2 → strathon-1.2.3}/tests/test_fail_closed.py +0 -0
  50. {strathon-1.2.2 → strathon-1.2.3}/tests/test_framework_upgrades.py +0 -0
  51. {strathon-1.2.2 → strathon-1.2.3}/tests/test_google_adk.py +0 -0
  52. {strathon-1.2.2 → strathon-1.2.3}/tests/test_halt_enforcer.py +0 -0
  53. {strathon-1.2.2 → strathon-1.2.3}/tests/test_instrumentation_hooks.py +0 -0
  54. {strathon-1.2.2 → strathon-1.2.3}/tests/test_instrumentation_stubs.py +0 -0
  55. {strathon-1.2.2 → strathon-1.2.3}/tests/test_langgraph.py +0 -0
  56. {strathon-1.2.2 → strathon-1.2.3}/tests/test_openai_agents.py +0 -0
  57. {strathon-1.2.2 → strathon-1.2.3}/tests/test_openai_agents_intervention.py +0 -0
  58. {strathon-1.2.2 → strathon-1.2.3}/tests/test_openai_agents_steer.py +0 -0
  59. {strathon-1.2.2 → strathon-1.2.3}/tests/test_policy_enforcer.py +0 -0
  60. {strathon-1.2.2 → strathon-1.2.3}/tests/test_policy_expression.py +0 -0
  61. {strathon-1.2.2 → strathon-1.2.3}/tests/test_policy_integration.py +0 -0
  62. {strathon-1.2.2 → strathon-1.2.3}/tests/test_policy_time.py +0 -0
  63. {strathon-1.2.2 → strathon-1.2.3}/tests/test_pydantic_ai.py +0 -0
  64. {strathon-1.2.2 → strathon-1.2.3}/tests/test_steer.py +0 -0
  65. {strathon-1.2.2 → strathon-1.2.3}/tests/test_steer_halt.py +0 -0
  66. {strathon-1.2.2 → strathon-1.2.3}/tests/test_throttle.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: strathon
3
- Version: 1.2.2
3
+ Version: 1.2.3
4
4
  Summary: Open-source AI agent firewall. Blocks dangerous agent tool calls before they execute, with in-process CEL enforcement at the tool-call boundary.
5
5
  Author-email: Strathon <hello@getstrathon.com>
6
6
  License-Expression: Apache-2.0
@@ -39,7 +39,7 @@ Requires-Dist: openai-agents>=0.17.5; extra == "openai-agents"
39
39
  Provides-Extra: anthropic
40
40
  Requires-Dist: anthropic>=0.40.0; extra == "anthropic"
41
41
  Provides-Extra: claude-agent
42
- Requires-Dist: claude-agent-sdk>=0.1.0; extra == "claude-agent"
42
+ Requires-Dist: claude-agent-sdk>=0.1.81; extra == "claude-agent"
43
43
  Requires-Dist: anthropic>=0.40.0; extra == "claude-agent"
44
44
  Provides-Extra: langchain
45
45
  Requires-Dist: langchain-core>=0.3.0; extra == "langchain"
@@ -59,7 +59,7 @@ Provides-Extra: all
59
59
  Requires-Dist: openai>=1.0.0; extra == "all"
60
60
  Requires-Dist: openai-agents>=0.17.5; extra == "all"
61
61
  Requires-Dist: anthropic>=0.40.0; extra == "all"
62
- Requires-Dist: claude-agent-sdk>=0.1.0; extra == "all"
62
+ Requires-Dist: claude-agent-sdk>=0.1.81; extra == "all"
63
63
  Requires-Dist: langchain-core>=0.3.0; extra == "all"
64
64
  Requires-Dist: crewai>=1.14.7; extra == "all"
65
65
  Requires-Dist: autogen-agentchat>=0.7.0; extra == "all"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "strathon"
7
- version = "1.2.2"
7
+ version = "1.2.3"
8
8
  description = "Open-source AI agent firewall. Blocks dangerous agent tool calls before they execute, with in-process CEL enforcement at the tool-call boundary."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -40,7 +40,7 @@ dependencies = [
40
40
  openai = ["openai>=1.0.0"]
41
41
  openai-agents = ["openai-agents>=0.17.5"]
42
42
  anthropic = ["anthropic>=0.40.0"]
43
- claude-agent = ["claude-agent-sdk>=0.1.0", "anthropic>=0.40.0"]
43
+ claude-agent = ["claude-agent-sdk>=0.1.81", "anthropic>=0.40.0"]
44
44
  langchain = ["langchain-core>=0.3.0"]
45
45
  langgraph = ["langchain-core>=0.3.0"]
46
46
  crewai = ["crewai>=1.14.7"]
@@ -52,7 +52,7 @@ all = [
52
52
  "openai>=1.0.0",
53
53
  "openai-agents>=0.17.5",
54
54
  "anthropic>=0.40.0",
55
- "claude-agent-sdk>=0.1.0",
55
+ "claude-agent-sdk>=0.1.81",
56
56
  "langchain-core>=0.3.0",
57
57
  "crewai>=1.14.7",
58
58
  "autogen-agentchat>=0.7.0",
@@ -0,0 +1 @@
1
+ __version__ = "1.2.3"
@@ -138,7 +138,7 @@ class Client:
138
138
  trace.set_tracer_provider(self._tracer_provider)
139
139
 
140
140
  # Named tracer for instrumentations and manual span emission
141
- self._tracer = self._tracer_provider.get_tracer("strathon", "1.2.2")
141
+ self._tracer = self._tracer_provider.get_tracer("strathon", "1.2.3")
142
142
 
143
143
  # Runtime intervention: optional policy enforcer
144
144
  self._policy_enforcer = None
@@ -33,7 +33,7 @@ class Config:
33
33
  # HTTP request timeout to Strathon receiver
34
34
  http_timeout_seconds: float = 10.0
35
35
 
36
- # Retry behaviour on export failure
36
+ # Retry behavior on export failure
37
37
  max_retries: int = 3
38
38
  retry_backoff_seconds: float = 1.0
39
39
 
@@ -28,7 +28,7 @@ if TYPE_CHECKING:
28
28
 
29
29
  logger = logging.getLogger("strathon.heartbeat")
30
30
 
31
- _VERSION = "1.2.2"
31
+ _VERSION = "1.2.3"
32
32
 
33
33
 
34
34
  def compute_code_hash() -> str:
@@ -840,8 +840,7 @@ def _build_strathon_guardrail_function(client):
840
840
  # The guardrail is async, so we do REAL interactive approval:
841
841
  # wait for the operator off the event loop. Approved -> allow the
842
842
  # tool to run; denied/expired/timed out -> raise_exception so the
843
- # tool body never runs. Previously require_approval fell through to
844
- # allow() here (a silent-allow gap).
843
+ # tool body never runs.
845
844
  from strathon.policy import await_for_approval
846
845
  try:
847
846
  await await_for_approval(
@@ -57,6 +57,7 @@ def request_approval(
57
57
  "tool_name": attrs.get("gen_ai.tool.name") or attrs.get("strathon.tool.name"),
58
58
  "tool_args": attrs.get("strathon.tool.args"),
59
59
  "timeout_seconds": decision.timeout_seconds or 300,
60
+ "approvers_required": decision.approvers_required or 1,
60
61
  }).encode("utf-8")
61
62
 
62
63
  api_key = getattr(client, "_api_key", None)
@@ -281,6 +281,20 @@ class PolicyEnforcer:
281
281
  timeout = int(raw_timeout)
282
282
  if timeout <= 0:
283
283
  timeout = 300
284
+ # approvers_required (the N in N-of-M). Same fail-safe posture:
285
+ # an invalid value must never raise out of check_policy, so it
286
+ # falls back to 1 (single sign-off) rather than disabling the
287
+ # policy. The receiver enforces the threshold and dedupes
288
+ # distinct approvers.
289
+ raw_approvers = (policy.action_config or {}).get(
290
+ "approvers_required", 1
291
+ )
292
+ if isinstance(raw_approvers, bool) or not isinstance(
293
+ raw_approvers, int
294
+ ):
295
+ approvers_required = 1
296
+ else:
297
+ approvers_required = raw_approvers if raw_approvers >= 1 else 1
284
298
  return PolicyDecision(
285
299
  action="require_approval",
286
300
  policy_id=policy.id,
@@ -290,6 +304,7 @@ class PolicyEnforcer:
290
304
  or f"Tool call requires approval per policy '{policy.name}'"
291
305
  ),
292
306
  timeout_seconds=timeout,
307
+ approvers_required=approvers_required,
293
308
  )
294
309
  # steer
295
310
  replacement = (
@@ -709,8 +709,6 @@ def _install_class_patch(cls: Type[Any]) -> None:
709
709
  # Route through the async dispatcher so this surface enforces the
710
710
  # full action set — halt check, block, throttle, steer, AND real
711
711
  # interactive require_approval — identically to the sync path.
712
- # Previously this hand-rolled only block/throttle/steer and ran the
713
- # body for approval/halt (a silent-allow gap).
714
712
  return await dispatch_policy_decision_async(
715
713
  client,
716
714
  span_name=span_name,
@@ -27,9 +27,9 @@ class Policy:
27
27
  priority: int = 0
28
28
  description: Optional[str] = None
29
29
  # Shadow policies are evaluated and recorded server-side but must never
30
- # enforce. The SDK previously dropped this field on parse, which made a
31
- # shadow block policy block for real in-process the inverse of the
32
- # documented "test without enforcing" contract.
30
+ # enforce in-process. This field is carried through parse so a shadow
31
+ # block policy stays observe-only instead of blocking for real, honoring
32
+ # the "test without enforcing" contract.
33
33
  shadow: bool = False
34
34
 
35
35
  def to_dict(self) -> Dict[str, Any]:
@@ -92,6 +92,7 @@ class PolicyDecision:
92
92
  retry_after_seconds: Optional[float] = None
93
93
  approval_id: Optional[str] = None
94
94
  timeout_seconds: Optional[int] = None
95
+ approvers_required: Optional[int] = None
95
96
 
96
97
  @property
97
98
  def is_allow(self) -> bool:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: strathon
3
- Version: 1.2.2
3
+ Version: 1.2.3
4
4
  Summary: Open-source AI agent firewall. Blocks dangerous agent tool calls before they execute, with in-process CEL enforcement at the tool-call boundary.
5
5
  Author-email: Strathon <hello@getstrathon.com>
6
6
  License-Expression: Apache-2.0
@@ -39,7 +39,7 @@ Requires-Dist: openai-agents>=0.17.5; extra == "openai-agents"
39
39
  Provides-Extra: anthropic
40
40
  Requires-Dist: anthropic>=0.40.0; extra == "anthropic"
41
41
  Provides-Extra: claude-agent
42
- Requires-Dist: claude-agent-sdk>=0.1.0; extra == "claude-agent"
42
+ Requires-Dist: claude-agent-sdk>=0.1.81; extra == "claude-agent"
43
43
  Requires-Dist: anthropic>=0.40.0; extra == "claude-agent"
44
44
  Provides-Extra: langchain
45
45
  Requires-Dist: langchain-core>=0.3.0; extra == "langchain"
@@ -59,7 +59,7 @@ Provides-Extra: all
59
59
  Requires-Dist: openai>=1.0.0; extra == "all"
60
60
  Requires-Dist: openai-agents>=0.17.5; extra == "all"
61
61
  Requires-Dist: anthropic>=0.40.0; extra == "all"
62
- Requires-Dist: claude-agent-sdk>=0.1.0; extra == "all"
62
+ Requires-Dist: claude-agent-sdk>=0.1.81; extra == "all"
63
63
  Requires-Dist: langchain-core>=0.3.0; extra == "all"
64
64
  Requires-Dist: crewai>=1.14.7; extra == "all"
65
65
  Requires-Dist: autogen-agentchat>=0.7.0; extra == "all"
@@ -9,7 +9,7 @@ cel-python>=0.5.0
9
9
  openai>=1.0.0
10
10
  openai-agents>=0.17.5
11
11
  anthropic>=0.40.0
12
- claude-agent-sdk>=0.1.0
12
+ claude-agent-sdk>=0.1.81
13
13
  langchain-core>=0.3.0
14
14
  crewai>=1.14.7
15
15
  autogen-agentchat>=0.7.0
@@ -23,7 +23,7 @@ anthropic>=0.40.0
23
23
  autogen-agentchat>=0.7.0
24
24
 
25
25
  [claude-agent]
26
- claude-agent-sdk>=0.1.0
26
+ claude-agent-sdk>=0.1.81
27
27
  anthropic>=0.40.0
28
28
 
29
29
  [crewai]
@@ -24,7 +24,7 @@ def make_client(**kwargs):
24
24
 
25
25
 
26
26
  def test_version():
27
- assert __version__ == "1.2.2"
27
+ assert __version__ == "1.2.3"
28
28
 
29
29
 
30
30
  def test_client_requires_api_key():
@@ -1 +0,0 @@
1
- __version__ = "1.2.2"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes