sondera-harness 0.6.3__py3-none-any.whl → 0.7.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.
sondera/adk/plugin.py CHANGED
@@ -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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
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.is_denied:
266
+ if adjudication.decision == Decision.DENY:
266
267
  # Modify the result to indicate policy violation
267
268
  event.result = {
268
269
  "content": [
sondera/types.py CHANGED
@@ -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.6.3
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://discord.gg/8zMbcnDnZs">Discord</a>
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:** [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](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
- - [Discord](https://discord.gg/8zMbcnDnZs) for questions and feedback
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
 
@@ -4,10 +4,10 @@ sondera/cli.py,sha256=owchF-eA6kttYGTSsLl0B7XJMmn9O2n2LFjpfYQvznQ,494
4
4
  sondera/exceptions.py,sha256=vtuToFc5tSlzAyVYvayyOatKBcoenisDA1RN2yk9aSI,3584
5
5
  sondera/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  sondera/settings.py,sha256=bLB98vT75aXKh5ihYnCd0dTk1AdfUUaGuPkyzhcldE0,459
7
- sondera/types.py,sha256=t4TbVcieoPgGr9wje0jz0eFmXPmfOvdqsKds8aKgMDI,10428
7
+ sondera/types.py,sha256=4dnAqwUCYPsS6Tm6QchRsIQmuAyTcGnDnV2txewtg2I,9402
8
8
  sondera/adk/__init__.py,sha256=weoilnJyr8JNBv2HK6s3hhW-6rOBGBcNwwkKk1oHVFE,77
9
9
  sondera/adk/analyze.py,sha256=IurwCWPZlNbMkIwi3TGWUu4k-w_VmKCkAnVFbfipbxY,7974
10
- sondera/adk/plugin.py,sha256=ioxJCRaAC5Rt73h_Y6G3LgHSkz28K1hVi8nZGyCdAgc,13047
10
+ sondera/adk/plugin.py,sha256=U6bhPCawBOJBE802ECFEyVVUNn5qouMHnM-awDrfkLQ,13141
11
11
  sondera/harness/__init__.py,sha256=gK0rFEyixD9X67pFyWKQpcq_oZ6pep6up8K0Y-zvXUc,221
12
12
  sondera/harness/abc.py,sha256=hL77Rlzy1B-DjFexhskGm_9j5Sue-TaWdlSnjr-Al70,3548
13
13
  sondera/harness/cedar/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -20,7 +20,7 @@ sondera/langgraph/__init__.py,sha256=F2eNoPp944tvGbf9a4etNh3-o49WOPrcs9EFVT0OYYw
20
20
  sondera/langgraph/analyze.py,sha256=1n-1yKr7-kfdFNSBe9JozZ08oJeYvPqKkFttcQ4MXHI,20514
21
21
  sondera/langgraph/exceptions.py,sha256=BRdh1gpELb3_WZ9Bh_UUwZsIOcIPrpQCD-7LnnAGeV4,501
22
22
  sondera/langgraph/graph.py,sha256=hIF5q_Fbq4E16CDqDksLrCETTEORgKiqPlpqIB5F-Rc,6898
23
- sondera/langgraph/middleware.py,sha256=q29nATkKlBiPs0bWuDpABkWccgYIBB6voLUnbQi1x0c,16816
23
+ sondera/langgraph/middleware.py,sha256=J3bUmW1Aor6q2DImqPSmrmX2yxDKfcFs9v35XEi66Cs,16910
24
24
  sondera/proto/google/protobuf/any_pb2.py,sha256=W6duyvBgx7RvePFCrJSxWagU7ddj1W9l8CsjarJJPOs,1703
25
25
  sondera/proto/google/protobuf/any_pb2.pyi,sha256=SSPWnvAxd1bX9FYZmLrZVmQ-29GsAE5bmgBcJlMaVfw,587
26
26
  sondera/proto/google/protobuf/any_pb2_grpc.py,sha256=OVxvViTmAZH370lIhyTfRI29xiCur_xZyAI4VJY1qJg,899
@@ -52,7 +52,7 @@ sondera/proto/sondera/harness/v1/harness_pb2.pyi,sha256=NiQNpGD9ICD41I9w11yJJwec
52
52
  sondera/proto/sondera/harness/v1/harness_pb2_grpc.py,sha256=h5y_HwqqzzpjaqQuaUt5ICy-2B2UJ-jea0gYfXsB6Ig,21845
53
53
  sondera/strands/__init__.py,sha256=Tg0l3ERb_uusENXZv9mtZz5tJ-TLK7K8zG2KsKHmUn4,124
54
54
  sondera/strands/analyze.py,sha256=yT9_DGieoMIxy5DGma9EdeAl2FVnkFQkdqK8waTphB8,8007
55
- sondera/strands/harness.py,sha256=CazoBF-grM2D2Ipj68QdYW4BmWw9fdLVy3_ntcylXvs,13100
55
+ sondera/strands/harness.py,sha256=helyy9AaaO7dVas2UcC0SfTWiylsaNXl_j7PZx0LVmY,13178
56
56
  sondera/tui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
57
  sondera/tui/app.py,sha256=I6Pcyatr5pPqjYwmBZrdTSFY11oR9sWmG90gVbN9pqo,11521
58
58
  sondera/tui/app.tcss,sha256=AE239R11BCuhKj8ZxvMYXduZw_-H11I7UkTDh72qdME,6562
@@ -70,9 +70,9 @@ sondera/tui/widgets/tool_card.py,sha256=3yNQcc_umcan4V1S5GiEKd7l4YA_atibwn3HF0n6
70
70
  sondera/tui/widgets/violation_panel.py,sha256=fowe4KWb13NXLX0_RAxEPdRqYeyGzlImpRs4_L9y1zI,2933
71
71
  sondera/tui/widgets/violations_list.py,sha256=86qICAsQOC6kjQLs64WxK7u59vEJ8kvfiToLVlzFyHM,2866
72
72
  sondera/tui/widgets/violations_summary.py,sha256=e2LwqlB1aS8sZ2gEC5clk7siA16NSgePU1mpv8T1iTc,4473
73
- sondera_harness-0.6.3.dist-info/licenses/LICENSE,sha256=DmSfauhgrslTxZOcDAmcYqsqsKBkMqVh3PYdjPghNbU,1070
74
- sondera_harness-0.6.3.dist-info/METADATA,sha256=cWb8iOVxQLKyIRcNq8902znCu6oqPr8IRhU6Yvm64lg,6419
75
- sondera_harness-0.6.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
76
- sondera_harness-0.6.3.dist-info/entry_points.txt,sha256=5cLgW0-GzEwNnQjXIhGT21iFprQb1lftBaFJjC4IrgE,78
77
- sondera_harness-0.6.3.dist-info/top_level.txt,sha256=BR0X8Gq9CCpwbQg5evpQfy5zwp9fTuGnlJhXSNqQ_hA,8
78
- sondera_harness-0.6.3.dist-info/RECORD,,
73
+ sondera_harness-0.7.0.dist-info/licenses/LICENSE,sha256=DmSfauhgrslTxZOcDAmcYqsqsKBkMqVh3PYdjPghNbU,1070
74
+ sondera_harness-0.7.0.dist-info/METADATA,sha256=mHC8kmhaMjapN72zLii3afE304_Bd-_LLHvwZEl77K0,6361
75
+ sondera_harness-0.7.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
76
+ sondera_harness-0.7.0.dist-info/entry_points.txt,sha256=5cLgW0-GzEwNnQjXIhGT21iFprQb1lftBaFJjC4IrgE,78
77
+ sondera_harness-0.7.0.dist-info/top_level.txt,sha256=BR0X8Gq9CCpwbQg5evpQfy5zwp9fTuGnlJhXSNqQ_hA,8
78
+ sondera_harness-0.7.0.dist-info/RECORD,,