sondera-harness 0.6.3__tar.gz → 0.7.0__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.
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/PKG-INFO +7 -10
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/README.md +6 -9
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/pyproject.toml +1 -1
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/adk/plugin.py +6 -5
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/langgraph/middleware.py +6 -5
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/strands/harness.py +5 -4
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/types.py +0 -36
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera_harness.egg-info/PKG-INFO +7 -10
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/LICENSE +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/setup.cfg +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/__main__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/adk/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/adk/analyze.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/cli.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/exceptions.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/harness/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/harness/abc.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/harness/cedar/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/harness/cedar/harness.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/harness/cedar/schema.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/harness/sondera/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/harness/sondera/_grpc.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/harness/sondera/harness.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/langgraph/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/langgraph/analyze.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/langgraph/exceptions.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/langgraph/graph.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/any_pb2.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/any_pb2.pyi +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/any_pb2_grpc.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/duration_pb2.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/duration_pb2.pyi +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/duration_pb2_grpc.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/empty_pb2.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/empty_pb2.pyi +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/empty_pb2_grpc.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/struct_pb2.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/struct_pb2.pyi +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/struct_pb2_grpc.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/timestamp_pb2.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/timestamp_pb2.pyi +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/timestamp_pb2_grpc.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/wrappers_pb2.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/wrappers_pb2.pyi +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/wrappers_pb2_grpc.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/core/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/core/v1/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/core/v1/primitives_pb2.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/core/v1/primitives_pb2.pyi +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/core/v1/primitives_pb2_grpc.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/harness/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/harness/v1/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/harness/v1/harness_pb2.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/harness/v1/harness_pb2.pyi +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/harness/v1/harness_pb2_grpc.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/py.typed +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/settings.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/strands/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/strands/analyze.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/app.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/app.tcss +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/screens/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/screens/adjudication.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/screens/agent.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/screens/trajectory.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/__init__.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/agent_card.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/agent_list.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/recent_adjudications.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/recent_trajectories.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/summary.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/tool_card.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/violation_panel.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/violations_list.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/violations_summary.py +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera_harness.egg-info/SOURCES.txt +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera_harness.egg-info/dependency_links.txt +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera_harness.egg-info/entry_points.txt +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera_harness.egg-info/requires.txt +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera_harness.egg-info/top_level.txt +0 -0
- {sondera_harness-0.6.3 → sondera_harness-0.7.0}/tests/test_harness.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sondera-harness
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Sondera Harness SDK for Python - Agent governance and policy enforcement
|
|
5
5
|
Author-email: Sondera AI <sdk@sondera.ai>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -47,11 +47,6 @@ Requires-Dist: strands-agents>=1.21.0; extra == "all"
|
|
|
47
47
|
Dynamic: license-file
|
|
48
48
|
|
|
49
49
|
<div align="center">
|
|
50
|
-
<picture>
|
|
51
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/sondera-ai/harness-sdk-python/main/assets/sondera-logo-dark.svg">
|
|
52
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/sondera-ai/harness-sdk-python/main/assets/sondera-logo-light.svg">
|
|
53
|
-
<img alt="Sondera" src="https://raw.githubusercontent.com/sondera-ai/harness-sdk-python/main/assets/sondera-logo-light.svg" height="60">
|
|
54
|
-
</picture>
|
|
55
50
|
|
|
56
51
|
<h1>Sondera Harness</h1>
|
|
57
52
|
|
|
@@ -66,7 +61,7 @@ Dynamic: license-file
|
|
|
66
61
|
·
|
|
67
62
|
<a href="https://github.com/sondera-ai/sondera-harness-python/tree/main/examples">Examples</a>
|
|
68
63
|
·
|
|
69
|
-
<a href="https://
|
|
64
|
+
<a href="https://join.slack.com/t/sonderacommunity/shared_invite/zt-3onw10qhj-5UNQ7EMuAbPk0nTwh_sNcw">Slack</a>
|
|
70
65
|
</p>
|
|
71
66
|
|
|
72
67
|
<p>
|
|
@@ -94,12 +89,16 @@ This policy stops your agent from running `rm -rf`, every time.
|
|
|
94
89
|
|
|
95
90
|
## Quickstart
|
|
96
91
|
|
|
92
|
+
> **Try it now:** [](https://colab.research.google.com/github/sondera-ai/sondera-harness-python/blob/main/docs/src/notebooks/quickstart.ipynb) - no install required.
|
|
93
|
+
|
|
97
94
|
### 1. Install
|
|
98
95
|
|
|
99
96
|
```bash
|
|
100
97
|
uv add "sondera-harness[langgraph]" # or: pip install "sondera-harness[langgraph]"
|
|
101
98
|
```
|
|
102
99
|
|
|
100
|
+
Works with [LangChain/LangGraph](https://docs.sondera.ai/integrations/langgraph/), [Google ADK](https://docs.sondera.ai/integrations/adk/), [Strands](https://docs.sondera.ai/integrations/strands/), and [custom agents](https://docs.sondera.ai/integrations/custom/).
|
|
101
|
+
|
|
103
102
|
### 2. Add to Your Agent (LangGraph)
|
|
104
103
|
|
|
105
104
|
```python
|
|
@@ -132,8 +131,6 @@ agent = create_agent(
|
|
|
132
131
|
)
|
|
133
132
|
```
|
|
134
133
|
|
|
135
|
-
Also supports [Google ADK](https://docs.sondera.ai/integrations/adk/), [Strands](https://docs.sondera.ai/integrations/strands/), and [custom integrations](https://docs.sondera.ai/integrations/custom/).
|
|
136
|
-
|
|
137
134
|
> [!NOTE]
|
|
138
135
|
> This example uses Sondera Platform ([free account](https://sondera.ai)), which also enables the TUI below. For local-only development, see [CedarPolicyHarness](https://docs.sondera.ai/integrations/custom/).
|
|
139
136
|
|
|
@@ -163,7 +160,7 @@ uv run sondera # or: sondera (if installed via pip)
|
|
|
163
160
|
|
|
164
161
|
## Community
|
|
165
162
|
|
|
166
|
-
- [
|
|
163
|
+
- [Slack](https://join.slack.com/t/sonderacommunity/shared_invite/zt-3onw10qhj-5UNQ7EMuAbPk0nTwh_sNcw) for questions and feedback
|
|
167
164
|
- [GitHub Issues](https://github.com/sondera-ai/sondera-harness-python/issues) for bugs
|
|
168
165
|
- [Contributing](CONTRIBUTING.md) for development setup
|
|
169
166
|
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<picture>
|
|
3
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/sondera-ai/harness-sdk-python/main/assets/sondera-logo-dark.svg">
|
|
4
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/sondera-ai/harness-sdk-python/main/assets/sondera-logo-light.svg">
|
|
5
|
-
<img alt="Sondera" src="https://raw.githubusercontent.com/sondera-ai/harness-sdk-python/main/assets/sondera-logo-light.svg" height="60">
|
|
6
|
-
</picture>
|
|
7
2
|
|
|
8
3
|
<h1>Sondera Harness</h1>
|
|
9
4
|
|
|
@@ -18,7 +13,7 @@
|
|
|
18
13
|
·
|
|
19
14
|
<a href="https://github.com/sondera-ai/sondera-harness-python/tree/main/examples">Examples</a>
|
|
20
15
|
·
|
|
21
|
-
<a href="https://
|
|
16
|
+
<a href="https://join.slack.com/t/sonderacommunity/shared_invite/zt-3onw10qhj-5UNQ7EMuAbPk0nTwh_sNcw">Slack</a>
|
|
22
17
|
</p>
|
|
23
18
|
|
|
24
19
|
<p>
|
|
@@ -46,12 +41,16 @@ This policy stops your agent from running `rm -rf`, every time.
|
|
|
46
41
|
|
|
47
42
|
## Quickstart
|
|
48
43
|
|
|
44
|
+
> **Try it now:** [](https://colab.research.google.com/github/sondera-ai/sondera-harness-python/blob/main/docs/src/notebooks/quickstart.ipynb) - no install required.
|
|
45
|
+
|
|
49
46
|
### 1. Install
|
|
50
47
|
|
|
51
48
|
```bash
|
|
52
49
|
uv add "sondera-harness[langgraph]" # or: pip install "sondera-harness[langgraph]"
|
|
53
50
|
```
|
|
54
51
|
|
|
52
|
+
Works with [LangChain/LangGraph](https://docs.sondera.ai/integrations/langgraph/), [Google ADK](https://docs.sondera.ai/integrations/adk/), [Strands](https://docs.sondera.ai/integrations/strands/), and [custom agents](https://docs.sondera.ai/integrations/custom/).
|
|
53
|
+
|
|
55
54
|
### 2. Add to Your Agent (LangGraph)
|
|
56
55
|
|
|
57
56
|
```python
|
|
@@ -84,8 +83,6 @@ agent = create_agent(
|
|
|
84
83
|
)
|
|
85
84
|
```
|
|
86
85
|
|
|
87
|
-
Also supports [Google ADK](https://docs.sondera.ai/integrations/adk/), [Strands](https://docs.sondera.ai/integrations/strands/), and [custom integrations](https://docs.sondera.ai/integrations/custom/).
|
|
88
|
-
|
|
89
86
|
> [!NOTE]
|
|
90
87
|
> This example uses Sondera Platform ([free account](https://sondera.ai)), which also enables the TUI below. For local-only development, see [CedarPolicyHarness](https://docs.sondera.ai/integrations/custom/).
|
|
91
88
|
|
|
@@ -115,7 +112,7 @@ uv run sondera # or: sondera (if installed via pip)
|
|
|
115
112
|
|
|
116
113
|
## Community
|
|
117
114
|
|
|
118
|
-
- [
|
|
115
|
+
- [Slack](https://join.slack.com/t/sonderacommunity/shared_invite/zt-3onw10qhj-5UNQ7EMuAbPk0nTwh_sNcw) for questions and feedback
|
|
119
116
|
- [GitHub Issues](https://github.com/sondera-ai/sondera-harness-python/issues) for bugs
|
|
120
117
|
- [Contributing](CONTRIBUTING.md) for development setup
|
|
121
118
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sondera-harness"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.7.0"
|
|
8
8
|
description = "Sondera Harness SDK for Python - Agent governance and policy enforcement"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12,<3.15"
|
|
@@ -23,6 +23,7 @@ from google.genai import types as genai_types
|
|
|
23
23
|
from sondera.adk.analyze import format
|
|
24
24
|
from sondera.harness import Harness
|
|
25
25
|
from sondera.types import (
|
|
26
|
+
Decision,
|
|
26
27
|
PromptContent,
|
|
27
28
|
Role,
|
|
28
29
|
Stage,
|
|
@@ -135,7 +136,7 @@ class SonderaHarnessPlugin(BasePlugin):
|
|
|
135
136
|
f"[SonderaHarness] User message adjudication for trajectory {self._harness.trajectory_id}"
|
|
136
137
|
)
|
|
137
138
|
|
|
138
|
-
if adjudication.
|
|
139
|
+
if adjudication.decision == Decision.DENY:
|
|
139
140
|
return genai_types.Content(
|
|
140
141
|
parts=[genai_types.Part(text=adjudication.reason)]
|
|
141
142
|
)
|
|
@@ -212,7 +213,7 @@ class SonderaHarnessPlugin(BasePlugin):
|
|
|
212
213
|
f"[SonderaHarness] Before model adjudication for trajectory {self._harness.trajectory_id}"
|
|
213
214
|
)
|
|
214
215
|
|
|
215
|
-
if adjudication.
|
|
216
|
+
if adjudication.decision == Decision.DENY:
|
|
216
217
|
return LlmResponse(
|
|
217
218
|
content=genai_types.Content(
|
|
218
219
|
parts=[genai_types.Part(text=adjudication.reason)]
|
|
@@ -254,7 +255,7 @@ class SonderaHarnessPlugin(BasePlugin):
|
|
|
254
255
|
f"[SonderaHarness] After model adjudication for trajectory {self._harness.trajectory_id}"
|
|
255
256
|
)
|
|
256
257
|
|
|
257
|
-
if adjudication.
|
|
258
|
+
if adjudication.decision == Decision.DENY:
|
|
258
259
|
return LlmResponse(
|
|
259
260
|
content=genai_types.Content(
|
|
260
261
|
parts=[genai_types.Part(text=adjudication.reason)]
|
|
@@ -296,7 +297,7 @@ class SonderaHarnessPlugin(BasePlugin):
|
|
|
296
297
|
f"[SonderaHarness] Before tool adjudication for trajectory {self._harness.trajectory_id}"
|
|
297
298
|
)
|
|
298
299
|
|
|
299
|
-
if adjudication.
|
|
300
|
+
if adjudication.decision == Decision.DENY:
|
|
300
301
|
return {"error": f"Tool blocked: {adjudication.reason}"}
|
|
301
302
|
return None
|
|
302
303
|
|
|
@@ -332,7 +333,7 @@ class SonderaHarnessPlugin(BasePlugin):
|
|
|
332
333
|
f"[SonderaHarness] After tool adjudication for trajectory {self._harness.trajectory_id}"
|
|
333
334
|
)
|
|
334
335
|
|
|
335
|
-
if adjudication.
|
|
336
|
+
if adjudication.decision == Decision.DENY:
|
|
336
337
|
return {"error": f"Tool result blocked: {adjudication.reason}"}
|
|
337
338
|
return None
|
|
338
339
|
|
|
@@ -28,6 +28,7 @@ except ImportError:
|
|
|
28
28
|
|
|
29
29
|
from sondera.harness import Harness
|
|
30
30
|
from sondera.types import (
|
|
31
|
+
Decision,
|
|
31
32
|
PromptContent,
|
|
32
33
|
Role,
|
|
33
34
|
Stage,
|
|
@@ -173,7 +174,7 @@ class SonderaHarnessMiddleware(AgentMiddleware[State]):
|
|
|
173
174
|
f"[SonderaHarness] Before Agent Adjudication for trajectory {self._harness.trajectory_id}"
|
|
174
175
|
)
|
|
175
176
|
|
|
176
|
-
if adjudication.
|
|
177
|
+
if adjudication.decision == Decision.DENY:
|
|
177
178
|
self._log.warning(
|
|
178
179
|
f"[SonderaHarness] Policy violation detected (strategy={self._strategy.value}): "
|
|
179
180
|
f"{adjudication.reason}"
|
|
@@ -226,7 +227,7 @@ class SonderaHarnessMiddleware(AgentMiddleware[State]):
|
|
|
226
227
|
PromptContent(text=_message_to_text(request.messages[-1])),
|
|
227
228
|
)
|
|
228
229
|
|
|
229
|
-
if pre_adjudication.
|
|
230
|
+
if pre_adjudication.decision == Decision.DENY:
|
|
230
231
|
_LOGGER.warning(
|
|
231
232
|
f"[SonderaHarness] Pre-model policy violation (strategy={self._strategy.value}): "
|
|
232
233
|
f"{pre_adjudication.reason}"
|
|
@@ -259,7 +260,7 @@ class SonderaHarnessMiddleware(AgentMiddleware[State]):
|
|
|
259
260
|
self._log.info(
|
|
260
261
|
f"[SonderaHarness] Post-model Adjudication for trajectory {self._harness.trajectory_id}"
|
|
261
262
|
)
|
|
262
|
-
if post_adjudication.
|
|
263
|
+
if post_adjudication.decision == Decision.DENY:
|
|
263
264
|
self._log.warning(
|
|
264
265
|
f"[SonderaHarness] Post-model policy violation (strategy={self._strategy.value}): "
|
|
265
266
|
f"{post_adjudication.reason}"
|
|
@@ -324,7 +325,7 @@ class SonderaHarnessMiddleware(AgentMiddleware[State]):
|
|
|
324
325
|
f"[SonderaHarness] Before Tool Adjudication for trajectory {self._harness.trajectory_id}"
|
|
325
326
|
)
|
|
326
327
|
|
|
327
|
-
if pre_adjudication.
|
|
328
|
+
if pre_adjudication.decision == Decision.DENY:
|
|
328
329
|
self._log.warning(
|
|
329
330
|
f"[SonderaHarness] Pre-tool policy violation for {tool_name} "
|
|
330
331
|
f"(strategy={self._strategy.value}): {pre_adjudication.reason}"
|
|
@@ -367,7 +368,7 @@ class SonderaHarnessMiddleware(AgentMiddleware[State]):
|
|
|
367
368
|
f"[SonderaHarness] After Tool Adjudication for trajectory {self._harness.trajectory_id}"
|
|
368
369
|
)
|
|
369
370
|
|
|
370
|
-
if post_adjudication.
|
|
371
|
+
if post_adjudication.decision == Decision.DENY:
|
|
371
372
|
self._log.warning(
|
|
372
373
|
f"[SonderaHarness] Post-tool policy violation for {tool_name} "
|
|
373
374
|
f"(strategy={self._strategy.value}): {post_adjudication.reason}"
|
|
@@ -16,6 +16,7 @@ from strands.hooks.events import (
|
|
|
16
16
|
from sondera.harness import Harness
|
|
17
17
|
from sondera.strands.analyze import format_strands_agent
|
|
18
18
|
from sondera.types import (
|
|
19
|
+
Decision,
|
|
19
20
|
PromptContent,
|
|
20
21
|
Role,
|
|
21
22
|
Stage,
|
|
@@ -163,7 +164,7 @@ class SonderaHarnessHook(HookProvider):
|
|
|
163
164
|
f"[SonderaHarness] Before model adjudication for trajectory {self._harness.trajectory_id}"
|
|
164
165
|
)
|
|
165
166
|
|
|
166
|
-
if adjudication.
|
|
167
|
+
if adjudication.decision == Decision.DENY:
|
|
167
168
|
self._log.warning(
|
|
168
169
|
f"[SonderaHarness] Model call blocked: {adjudication.reason}"
|
|
169
170
|
)
|
|
@@ -192,7 +193,7 @@ class SonderaHarnessHook(HookProvider):
|
|
|
192
193
|
f"[SonderaHarness] After model adjudication for trajectory {self._harness.trajectory_id}"
|
|
193
194
|
)
|
|
194
195
|
|
|
195
|
-
if adjudication.
|
|
196
|
+
if adjudication.decision == Decision.DENY:
|
|
196
197
|
self._log.warning(
|
|
197
198
|
f"[SonderaHarness] Model response blocked: {adjudication.reason}"
|
|
198
199
|
)
|
|
@@ -231,7 +232,7 @@ class SonderaHarnessHook(HookProvider):
|
|
|
231
232
|
f"[SonderaHarness] Before tool adjudication for trajectory {self._harness.trajectory_id}"
|
|
232
233
|
)
|
|
233
234
|
|
|
234
|
-
if adjudication.
|
|
235
|
+
if adjudication.decision == Decision.DENY:
|
|
235
236
|
# Cancel the tool call using Strands' cancel_tool mechanism
|
|
236
237
|
event.cancel_tool = f"Tool blocked by policy: {adjudication.reason}"
|
|
237
238
|
self._log.warning(
|
|
@@ -262,7 +263,7 @@ class SonderaHarnessHook(HookProvider):
|
|
|
262
263
|
f"[SonderaHarness] After tool adjudication for trajectory {self._harness.trajectory_id}"
|
|
263
264
|
)
|
|
264
265
|
|
|
265
|
-
if adjudication.
|
|
266
|
+
if adjudication.decision == Decision.DENY:
|
|
266
267
|
# Modify the result to indicate policy violation
|
|
267
268
|
event.result = {
|
|
268
269
|
"content": [
|
|
@@ -258,21 +258,6 @@ class Adjudication(Model):
|
|
|
258
258
|
annotations: list[PolicyAnnotation] = Field(default_factory=list)
|
|
259
259
|
"""Annotations from policy evaluations."""
|
|
260
260
|
|
|
261
|
-
@property
|
|
262
|
-
def is_denied(self) -> bool:
|
|
263
|
-
"""Check if is denied."""
|
|
264
|
-
return self.decision == Decision.DENY
|
|
265
|
-
|
|
266
|
-
@property
|
|
267
|
-
def is_allowed(self) -> bool:
|
|
268
|
-
"""Check if allowed."""
|
|
269
|
-
return self.decision == Decision.ALLOW
|
|
270
|
-
|
|
271
|
-
@property
|
|
272
|
-
def is_escalated(self) -> bool:
|
|
273
|
-
"""Check if result requires escalation."""
|
|
274
|
-
return self.decision == Decision.ESCALATE
|
|
275
|
-
|
|
276
261
|
|
|
277
262
|
class AdjudicatedStep(Model):
|
|
278
263
|
"""Result of the adjudicated input."""
|
|
@@ -286,27 +271,6 @@ class AdjudicatedStep(Model):
|
|
|
286
271
|
guardrails: GuardrailContext | None = None
|
|
287
272
|
"""Guardrail check results for this step."""
|
|
288
273
|
|
|
289
|
-
@property
|
|
290
|
-
def is_denied(self) -> bool:
|
|
291
|
-
"""Check if result is denied."""
|
|
292
|
-
return (
|
|
293
|
-
self.adjudication.decision == Decision.DENY
|
|
294
|
-
and self.mode == PolicyEngineMode.GOVERN
|
|
295
|
-
)
|
|
296
|
-
|
|
297
|
-
@property
|
|
298
|
-
def is_allowed(self) -> bool:
|
|
299
|
-
"""Check if result is allowed."""
|
|
300
|
-
return self.adjudication.decision == Decision.ALLOW
|
|
301
|
-
|
|
302
|
-
@property
|
|
303
|
-
def is_escalated(self) -> bool:
|
|
304
|
-
"""Check if result requires escalation."""
|
|
305
|
-
return (
|
|
306
|
-
self.adjudication.decision == Decision.ESCALATE
|
|
307
|
-
and self.mode == PolicyEngineMode.GOVERN
|
|
308
|
-
)
|
|
309
|
-
|
|
310
274
|
@property
|
|
311
275
|
def message(self) -> str:
|
|
312
276
|
"""Get the adjudication reason in a friendly format."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sondera-harness
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Sondera Harness SDK for Python - Agent governance and policy enforcement
|
|
5
5
|
Author-email: Sondera AI <sdk@sondera.ai>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -47,11 +47,6 @@ Requires-Dist: strands-agents>=1.21.0; extra == "all"
|
|
|
47
47
|
Dynamic: license-file
|
|
48
48
|
|
|
49
49
|
<div align="center">
|
|
50
|
-
<picture>
|
|
51
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/sondera-ai/harness-sdk-python/main/assets/sondera-logo-dark.svg">
|
|
52
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/sondera-ai/harness-sdk-python/main/assets/sondera-logo-light.svg">
|
|
53
|
-
<img alt="Sondera" src="https://raw.githubusercontent.com/sondera-ai/harness-sdk-python/main/assets/sondera-logo-light.svg" height="60">
|
|
54
|
-
</picture>
|
|
55
50
|
|
|
56
51
|
<h1>Sondera Harness</h1>
|
|
57
52
|
|
|
@@ -66,7 +61,7 @@ Dynamic: license-file
|
|
|
66
61
|
·
|
|
67
62
|
<a href="https://github.com/sondera-ai/sondera-harness-python/tree/main/examples">Examples</a>
|
|
68
63
|
·
|
|
69
|
-
<a href="https://
|
|
64
|
+
<a href="https://join.slack.com/t/sonderacommunity/shared_invite/zt-3onw10qhj-5UNQ7EMuAbPk0nTwh_sNcw">Slack</a>
|
|
70
65
|
</p>
|
|
71
66
|
|
|
72
67
|
<p>
|
|
@@ -94,12 +89,16 @@ This policy stops your agent from running `rm -rf`, every time.
|
|
|
94
89
|
|
|
95
90
|
## Quickstart
|
|
96
91
|
|
|
92
|
+
> **Try it now:** [](https://colab.research.google.com/github/sondera-ai/sondera-harness-python/blob/main/docs/src/notebooks/quickstart.ipynb) - no install required.
|
|
93
|
+
|
|
97
94
|
### 1. Install
|
|
98
95
|
|
|
99
96
|
```bash
|
|
100
97
|
uv add "sondera-harness[langgraph]" # or: pip install "sondera-harness[langgraph]"
|
|
101
98
|
```
|
|
102
99
|
|
|
100
|
+
Works with [LangChain/LangGraph](https://docs.sondera.ai/integrations/langgraph/), [Google ADK](https://docs.sondera.ai/integrations/adk/), [Strands](https://docs.sondera.ai/integrations/strands/), and [custom agents](https://docs.sondera.ai/integrations/custom/).
|
|
101
|
+
|
|
103
102
|
### 2. Add to Your Agent (LangGraph)
|
|
104
103
|
|
|
105
104
|
```python
|
|
@@ -132,8 +131,6 @@ agent = create_agent(
|
|
|
132
131
|
)
|
|
133
132
|
```
|
|
134
133
|
|
|
135
|
-
Also supports [Google ADK](https://docs.sondera.ai/integrations/adk/), [Strands](https://docs.sondera.ai/integrations/strands/), and [custom integrations](https://docs.sondera.ai/integrations/custom/).
|
|
136
|
-
|
|
137
134
|
> [!NOTE]
|
|
138
135
|
> This example uses Sondera Platform ([free account](https://sondera.ai)), which also enables the TUI below. For local-only development, see [CedarPolicyHarness](https://docs.sondera.ai/integrations/custom/).
|
|
139
136
|
|
|
@@ -163,7 +160,7 @@ uv run sondera # or: sondera (if installed via pip)
|
|
|
163
160
|
|
|
164
161
|
## Community
|
|
165
162
|
|
|
166
|
-
- [
|
|
163
|
+
- [Slack](https://join.slack.com/t/sonderacommunity/shared_invite/zt-3onw10qhj-5UNQ7EMuAbPk0nTwh_sNcw) for questions and feedback
|
|
167
164
|
- [GitHub Issues](https://github.com/sondera-ai/sondera-harness-python/issues) for bugs
|
|
168
165
|
- [Contributing](CONTRIBUTING.md) for development setup
|
|
169
166
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/any_pb2.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/any_pb2.pyi
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/any_pb2_grpc.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/duration_pb2.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/duration_pb2.pyi
RENAMED
|
File without changes
|
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/empty_pb2.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/empty_pb2.pyi
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/empty_pb2_grpc.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/struct_pb2.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/struct_pb2.pyi
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/struct_pb2_grpc.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/timestamp_pb2.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/timestamp_pb2.pyi
RENAMED
|
File without changes
|
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/wrappers_pb2.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/google/protobuf/wrappers_pb2.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/core/v1/__init__.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/core/v1/primitives_pb2.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/core/v1/primitives_pb2.pyi
RENAMED
|
File without changes
|
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/harness/__init__.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/harness/v1/__init__.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/harness/v1/harness_pb2.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/proto/sondera/harness/v1/harness_pb2.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/recent_adjudications.py
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/recent_trajectories.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera/tui/widgets/violations_summary.py
RENAMED
|
File without changes
|
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera_harness.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{sondera_harness-0.6.3 → sondera_harness-0.7.0}/src/sondera_harness.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|