agent-alignment-protocol 0.3.0__tar.gz → 0.4.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.
Files changed (25) hide show
  1. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/PKG-INFO +3 -3
  2. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/README.md +2 -2
  3. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/pyproject.toml +1 -1
  4. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/__init__.py +1 -1
  5. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/tracing.py +19 -5
  6. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/verification/api.py +51 -0
  7. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/.gitignore +0 -0
  8. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/LICENSE +0 -0
  9. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/schemas/alignment-card.schema.json +0 -0
  10. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/schemas/ap-trace.schema.json +0 -0
  11. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/schemas/value-coherence.schema.json +0 -0
  12. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/cli/__init__.py +0 -0
  13. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/cli/main.py +0 -0
  14. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/compliance.py +0 -0
  15. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/py.typed +0 -0
  16. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/schemas/__init__.py +0 -0
  17. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/schemas/alignment_card.py +0 -0
  18. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/schemas/ap_trace.py +0 -0
  19. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/schemas/value_coherence.py +0 -0
  20. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/verification/__init__.py +0 -0
  21. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/verification/constants.py +0 -0
  22. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/verification/divergence.py +0 -0
  23. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/verification/features.py +0 -0
  24. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/verification/models.py +0 -0
  25. {agent_alignment_protocol-0.3.0 → agent_alignment_protocol-0.4.0}/src/aap/verification/ssm.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-alignment-protocol
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Agent Alignment Protocol - The missing alignment layer for the agent protocol stack
5
5
  Project-URL: Homepage, https://github.com/mnemom/aap
6
6
  Project-URL: Documentation, https://github.com/mnemom/aap#readme
@@ -46,7 +46,7 @@ Description-Content-Type: text/markdown
46
46
  [![PyPI](https://img.shields.io/pypi/v/agent-alignment-protocol.svg)](https://pypi.org/project/agent-alignment-protocol/)
47
47
  [![npm](https://img.shields.io/npm/v/@mnemom/agent-alignment-protocol.svg)](https://www.npmjs.com/package/@mnemom/agent-alignment-protocol)
48
48
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
49
- [![Spec](https://img.shields.io/badge/spec-v0.1.0-green.svg)](https://docs.mnemom.ai/protocols/aap/specification)
49
+ [![Spec](https://img.shields.io/badge/spec-v0.4.0-green.svg)](https://docs.mnemom.ai/protocols/aap/specification)
50
50
 
51
51
  **A transparency protocol for autonomous agents.**
52
52
 
@@ -334,7 +334,7 @@ No server required — runs entirely client-side via WebAssembly.
334
334
 
335
335
  ## Status
336
336
 
337
- **Current Version**: 0.1.8
337
+ **Current Version**: 0.4.0
338
338
 
339
339
  | Component | Status |
340
340
  |-----------|--------|
@@ -6,7 +6,7 @@
6
6
  [![PyPI](https://img.shields.io/pypi/v/agent-alignment-protocol.svg)](https://pypi.org/project/agent-alignment-protocol/)
7
7
  [![npm](https://img.shields.io/npm/v/@mnemom/agent-alignment-protocol.svg)](https://www.npmjs.com/package/@mnemom/agent-alignment-protocol)
8
8
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
9
- [![Spec](https://img.shields.io/badge/spec-v0.1.0-green.svg)](https://docs.mnemom.ai/protocols/aap/specification)
9
+ [![Spec](https://img.shields.io/badge/spec-v0.4.0-green.svg)](https://docs.mnemom.ai/protocols/aap/specification)
10
10
 
11
11
  **A transparency protocol for autonomous agents.**
12
12
 
@@ -294,7 +294,7 @@ No server required — runs entirely client-side via WebAssembly.
294
294
 
295
295
  ## Status
296
296
 
297
- **Current Version**: 0.1.8
297
+ **Current Version**: 0.4.0
298
298
 
299
299
  | Component | Status |
300
300
  |-----------|--------|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "agent-alignment-protocol"
7
- version = "0.3.0"
7
+ version = "0.4.0"
8
8
  description = "Agent Alignment Protocol - The missing alignment layer for the agent protocol stack"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -36,7 +36,7 @@ Quick Start:
36
36
  See docs/SPEC.md for the full protocol specification.
37
37
  """
38
38
 
39
- __version__ = "0.3.0"
39
+ __version__ = "0.4.0"
40
40
 
41
41
  # EU AI Act compliance presets
42
42
  from aap.compliance import (
@@ -142,8 +142,15 @@ class TraceConfig:
142
142
  session_id: str | None = None
143
143
  """Session ID to include in trace context."""
144
144
 
145
- include_args: bool = True
146
- """Include function arguments in action.parameters."""
145
+ include_args: bool = False
146
+ """Include function arguments in action.parameters.
147
+
148
+ WARNING: When set to True, all function arguments are serialized into the
149
+ trace output. This may inadvertently leak sensitive data (PII, credentials,
150
+ API keys, etc.) into trace files. Only enable this when you are certain that
151
+ function arguments do not contain sensitive information, or when traces are
152
+ stored in a secure, access-controlled location.
153
+ """
147
154
 
148
155
  include_return_repr: bool = False
149
156
  """Include repr of return value in trace (may leak data)."""
@@ -345,14 +352,19 @@ def _write_trace(trace: dict[str, Any], config: TraceConfig) -> Path | None:
345
352
  return None
346
353
 
347
354
  # Write to file
355
+ import os
348
356
  output_dir = Path(config.output_dir)
349
357
  output_dir.mkdir(parents=True, exist_ok=True)
358
+ # Ensure restrictive directory permissions (umask may weaken mode= arg)
359
+ os.chmod(output_dir, 0o700)
350
360
 
351
361
  filename = f"{trace['trace_id']}.json"
352
362
  filepath = output_dir / filename
353
363
 
354
364
  with open(filepath, "w") as f:
355
365
  json.dump(trace, f, indent=2, default=str)
366
+ # Restrict file permissions to owner-only read/write
367
+ os.chmod(filepath, 0o600)
356
368
 
357
369
  return filepath
358
370
 
@@ -403,7 +415,7 @@ def trace_decision(
403
415
  default_values: list[str] | None = None,
404
416
  agent_id: str = "",
405
417
  session_id: str | None = None,
406
- include_args: bool = True,
418
+ include_args: bool = False,
407
419
  include_return_repr: bool = False,
408
420
  ) -> Callable[[Callable[P, R]], Callable[P, R]]:
409
421
  ...
@@ -421,7 +433,7 @@ def trace_decision(
421
433
  default_values: list[str] | None = None,
422
434
  agent_id: str = "",
423
435
  session_id: str | None = None,
424
- include_args: bool = True,
436
+ include_args: bool = False,
425
437
  include_return_repr: bool = False,
426
438
  ) -> Callable[P, R] | Callable[[Callable[P, R]], Callable[P, R]]:
427
439
  """Decorator that generates AP-Traces for function calls.
@@ -444,7 +456,9 @@ def trace_decision(
444
456
  default_values: Default values_applied if not provided by function.
445
457
  agent_id: Agent ID for traces (auto-generated if empty).
446
458
  session_id: Session ID to include in trace context.
447
- include_args: Include function arguments in action.parameters (default: True).
459
+ include_args: Include function arguments in action.parameters (default: False).
460
+ WARNING: When True, all function arguments are serialized into trace
461
+ output, which may leak sensitive data (PII, credentials, API keys).
448
462
  include_return_repr: Include repr of return value (default: False).
449
463
 
450
464
  Returns:
@@ -90,6 +90,13 @@ def verify_trace(
90
90
  ) -> VerificationResult:
91
91
  """Verify a single AP-Trace against an Alignment Card.
92
92
 
93
+ IMPORTANT: This function provides STRUCTURAL verification only — it checks that
94
+ a trace conforms to the declarations in an alignment card. It does NOT provide
95
+ cryptographic integrity verification. Traces are not signed or hash-chained in
96
+ the current version. A malicious agent can produce structurally valid traces for
97
+ arbitrary behavior. For integrity guarantees, use AIP (Agent Integrity Protocol)
98
+ in conjunction with AAP.
99
+
93
100
  Performs the verification algorithm specified in SPEC Section 7.3:
94
101
  1. Autonomy compliance - action category matches autonomy envelope
95
102
  2. Escalation compliance - required escalations were performed
@@ -103,6 +110,26 @@ def verify_trace(
103
110
  Returns:
104
111
  VerificationResult with violations and warnings
105
112
  """
113
+ # Validate required fields
114
+ if not isinstance(trace, dict):
115
+ raise TypeError("trace must be a dictionary")
116
+ if not isinstance(card, dict):
117
+ raise TypeError("card must be a dictionary")
118
+ if "action" not in trace:
119
+ raise ValueError("trace must contain 'action' field")
120
+ if "decision" not in trace or "values_applied" not in trace.get("decision", {}):
121
+ raise ValueError("trace must contain 'decision.values_applied' field")
122
+
123
+ # Warn if tamper_evidence is declared but not cryptographically enforced
124
+ tamper_evidence = (card.get("audit") or {}).get("commitment", {}).get("tamper_evidence")
125
+ if tamper_evidence in ("signed", "merkle"):
126
+ import warnings as _warnings
127
+ _warnings.warn(
128
+ f'[AAP] Warning: tamper_evidence mode "{tamper_evidence}" is declared '
129
+ "but NOT cryptographically enforced in this version.",
130
+ stacklevel=2,
131
+ )
132
+
106
133
  start_time = time.time()
107
134
  violations: list[Violation] = []
108
135
  warnings: list[Warning] = []
@@ -271,6 +298,12 @@ def check_coherence(
271
298
  Returns:
272
299
  CoherenceResult with compatibility assessment
273
300
  """
301
+ # Validate required fields
302
+ if not isinstance(my_card, dict):
303
+ raise TypeError("my_card must be a dictionary")
304
+ if not isinstance(their_card, dict):
305
+ raise TypeError("their_card must be a dictionary")
306
+
274
307
  my_values = set(my_card.get("values", {}).get("declared", []))
275
308
  their_values = set(their_card.get("values", {}).get("declared", []))
276
309
 
@@ -590,6 +623,12 @@ def detect_drift(
590
623
  Returns:
591
624
  List of DriftAlert objects for detected drift events
592
625
  """
626
+ # Validate required fields
627
+ if not isinstance(card, dict):
628
+ raise TypeError("card must be a dictionary")
629
+ if not isinstance(traces, list):
630
+ raise TypeError("traces must be a list")
631
+
593
632
  # Delegate to DivergenceDetector (Braid-extracted implementation)
594
633
  from aap.verification.divergence import DivergenceDetector
595
634
 
@@ -643,6 +682,11 @@ def _evaluate_condition(condition: str, trace: dict[str, Any]) -> bool:
643
682
 
644
683
  # Look for field in trace context (handle explicit None)
645
684
  actual = (trace.get("context") or {}).get(field)
685
+ # Check context.metadata (match TypeScript behavior)
686
+ if actual is None:
687
+ metadata = (trace.get("context") or {}).get("metadata", {})
688
+ if isinstance(metadata, dict):
689
+ actual = metadata.get(field)
646
690
  if actual is None:
647
691
  actual = (trace.get("action") or {}).get("parameters", {}).get(field)
648
692
  if actual is None:
@@ -670,6 +714,13 @@ def _evaluate_condition(condition: str, trace: dict[str, Any]) -> bool:
670
714
  if re.match(r'^\w+$', condition):
671
715
  return bool((trace.get("context") or {}).get(condition))
672
716
 
717
+ import logging
718
+ logging.getLogger("aap").warning(
719
+ '[AAP] Condition could not be parsed: "%s". Supported patterns: '
720
+ '"field == value", "field > number", "field_name" (boolean). '
721
+ "This trigger will not fire.",
722
+ condition,
723
+ )
673
724
  return False
674
725
 
675
726