Skip to content

Releases: Cogensec/agentegrity

v0.7.0: Decision provenance + three new Python adapters

08 Jun 19:46
34d149f

Choose a tag to compare

v0.7.0: Decision provenance + three new Python adapters

Captures why the agent decided, not just what the evaluator concluded. Every decision boundary (tool call, final output, subagent dispatch) now appends a signed, hash-chained DecisionRecord to the same AttestationChain that holds the evaluator's attestations, captured before the action executes. A downstream verifier can prove the rationale was bound at decision time and not retrofitted.

Three new Python framework adapters complete the v0.7 family (now eight): AWS Bedrock Agents (with real enforcement on the Strands surface), Agno (Agent + Team, real enforcement via StopAgentRun), AutoGen (OpenTelemetry SpanProcessor over GenAI semconv spans). CrewAI is patched for the 1.x event-bus relocation.

Decision provenance

New module agentegrity.core.decision with:

  • DecisionRecord (signed, hash-chained, lives in the same chain as AttestationRecord)
  • CaptureTier (Minimal / Partial / Full)
  • DecisionInput, RejectedAlternative
  • build_decision_record(...) helper

New _BaseAdapter / IntegrityMonitor API:

  • Optional signing_key= constructor argument signs every record
  • record_decision(...) for explicit capture (the adapter calls it automatically at the three boundaries; IntegrityMonitor exposes it for the @guard path)

New AttestationChain methods:

  • to_json() / from_json() round-trip
  • verify_chain_detailed() -> (ok, broken_idx, broken_kind) (verify_chain() -> bool unchanged)
  • verify_decision_links() validates each attestation's decision-type Evidence still points at unaltered decisions

New ChainedRecord Protocol both record kinds satisfy structurally; the chain is heterogeneous without dispatch.

New CLI verb:

python -m agentegrity verify-decisions chain.json

Loads a serialized chain, runs verify_chain() + verify_decision_links(), prints a per-record table (kind / boundary / tier / signed / verified), exits non-zero on any failure.

Honest framing

  • Capture tier today is C (Minimal) on every shipped adapter. The schema supports Tier B (Partial: reasoning chain) and Tier A (Full: rejected alternatives), but no adapter populates those fields in production. Tier B/A unlock as adapter-specific deliberation surfaces are wired (Claude reasoning streams, OpenAI Responses reasoning content).
  • Capture fails open. On exception, the framework logs a warning AND emits a structured capture_failure FrameworkEvent so monitoring can see the gap. An adversary who can trigger a capture exception still leaves a chain gap; fail-closed would crash agents on transient bugs.
  • subagent_start is a lifecycle attestation, not a decision. The candidate_action.type is subagent_dispatch_observed and boundary_category is lifecycle_attestation, because the parent's decision to delegate already happened earlier (often at its own pre_tool_use).

Full spec: [spec/properties/decision-provenance.md](https://github.com/Cogensec/agentegrity/blob/v0.7.0/spec/properties/decision-provenance.md).

New adapters

AWS Bedrock Agents

pip install agentegrity[bedrock-agents]

One adapter, two surfaces:

  • instrument_strands(agent) registers typed HookProvider hooks on a Strands Agent (BeforeInvocationEventuser_prompt_submit, BeforeToolCallEventpre_tool_use, AfterToolCallEventpost_tool_use, AfterInvocationEventstop). Under enforce=True, blocked tool calls actually fire event.cancel_tool to deny the tool. First adapter in the v0.7 batch where enforcement is real, not just recorded.
  • wrap_client(boto3_client) patches bedrock-agent-runtime.invoke_agent to force enableTrace=True and stream-map TracePart variants (action group / collaborator / failure) onto canonical events. Observation-only on this surface because traces arrive post-hoc; the wrapper iterator runs in a generator's finally block so a caller bailing out mid-iteration still fires stop.

Agno (2.x)

pip install agentegrity[agno]

Hooks into pre_hooks / post_hooks / tool_hooks on both Agent and Team. instrument_team() marks listed members for subagent_* emission while the leader emits the top-level prompt/stop pair; all members share one adapter so the chain is unified.

Real enforcement: the tool_hook evaluates pre_tool_use synchronously and raises StopAgentRun (an AgentRunException subclass, the only family FunctionCall.execute() re-raises to halt) before the tool runs. InputCheckError would be wrong here because it extends Exception directly and gets swallowed into a status="failure" result.

Agno 2.x re-propagates agent.tool_hooks onto every tool at run setup, so tools added after instrument() are captured automatically.

AutoGen

pip install agentegrity[autogen]

OpenTelemetry SpanProcessor consuming AutoGen's GenAI semconv spans (invoke_agent, execute_tool). Maps root invoke_agentuser_prompt_submit / stop, nested → subagent_start / subagent_stop, execute_toolpre_tool_use / post_tool_use (or post_tool_use_failure on ERROR status).

Observation-only: OTel spans observe post-hoc, so enforce=True records block decisions in the chain but cannot prevent tool calls. Emits a UserWarning on construction if both are set.

Other improvements

  • Synchronous evaluation core. The eight _handle_* event handlers are now plain def; dispatch goes through a synchronous _evaluate_sync that completes before the hook returns. Unlocks real enforcement on sync hook surfaces (see Agno). on_event stays async for protocol compatibility.
  • Adapter factory consolidated. AgentegrityClient.create_adapter(name, profile, *, enforce=False, api_key=None) replaces the five per-framework methods. Adding an adapter is now one line in _ADAPTER_REGISTRY. Migrate call sites from client.create_claude_adapter(profile=p) to client.create_adapter("claude", profile=p). The high-level zero-config entry points (agentegrity.claude.hooks(), agentegrity.crewai.instrument(), etc.) are unaffected.
  • [all] extra is self-referential. Register a new optional framework once under [project.optional-dependencies]; it flows into [all] automatically.
  • Google ADK warns on enforce=True to match the AutoGen / boto3 observation-only pattern. ADK's before_* callbacks expose no veto mechanism.
  • Evidence is now part of the public API (from agentegrity import Evidence) since downstream verifiers building decision-link evidence need it.

Breaking changes

1. AttestationRecord canonical payload now includes record_kind

Required so the heterogeneous chain can distinguish attestation records from decision records under signature (otherwise a tamperer could flip a decision into an attestation post-signing).

2. Evidence.content_hash is now real SHA-256

Was str(hash(str(r.to_dict()))) using Python's process-salted string hash, non-deterministic across processes and non-portable, which silently broke any cross-process tamper-evident verification. The three triplicated record-build paths (adapter base, monitor, SDK client) now share one build_attestation_record() helper.

Impact

Chains serialized pre-v0.7 fail verify_chain() after upgrade, signed or not. The in-memory recomputed content_hash (now over the new canonical bytes) doesn't match the stored chain_previous references in subsequent records. Loading still works; verification doesn't.

No rescue migration script. Two options:

  • Re-build the chain from a fresh root with the new code (recommended)
  • Pin to v0.6 for legacy verification: pip install agentegrity==0.6.0

3. CrewAI adapter requires crewai ≥ 1.0

crewai 1.0 relocated event classes from crewai.utilities.events to crewai.events. The adapter now imports from the new path. The previous "requires crewai" tests passed for the wrong reason (matching the legacy path's ModuleNotFoundError); they're replaced with a fake-bus integration test that drives every registered handler. crewai 0.x is no longer supported.

Install

pip install agentegrity==0.7.0
# with specific adapter extras
pip install "agentegrity[claude,langchain,bedrock-agents,agno,autogen]"
# everything (dev included)
pip install "agentegrity[all,dev]"

TypeScript packages (all bumped to 0.7.0 in parity):

npm i @agentegrity/client@0.7.0
npm i @agentegrity/claude-sdk@0.7.0
# ... langchain, openai-agents, crewai, google-adk, vercel-ai

Repository note

The repo has been renamed from cogensec/agentegrity-framework to cogensec/agentegrity. Old URLs redirect via GitHub for now; update bookmarks and git remotes at your convenience:

git remote set-url origin https://github.com/Cogensec/agentegrity.git

Verification

$ python -m agentegrity
agentegrity 0.7.0
...

$ python -m agentegrity verify-decisions chain.json
agentegrity 0.7.0 — verify-decisions chain.json
  records:        5
  chain valid:    yes
  decision links: yes

  idx  kind          boundary/score          tier      signed  verified
    0  attestation   attestation             -         yes     yes
    1  attestation   attestation             -         yes     yes
    2  decision      pre_tool_use            minimal   yes     yes
    3  attestation   attestation             -         yes     yes
    4  decision      stop                    minimal   yes     yes

Quality gates

  • 480 tests pass (+66 from v0.6.0 baseline of 414)
  • mypy clean across 39 source files
  • ruff clean
  • Cross-adapter conformance: 11 invariants × 8 adapters + 1 team-aware test

Full changelog

See [[CHANGELOG.md](...

Read more

v0.6.0 — Detection depth, recovery round-trip, conformance, benchmark

06 May 13:19
a65103d

Choose a tag to compare

The release that closes Phase 2 of the dev plan. Full notes in CHANGELOG.md; headline below.

Highlights

  • 4-layer default pipeline. RecoveryLayer is now a first-class default alongside Adversarial / Cortical / Governance.
  • AdversarialLayer. 21-pattern regex taxonomy across six attack families (prompt_injection, jailbreak, role_confusion, system_prompt_extraction, data_exfiltration, prompt_obfuscation). Scans direct input + memory_reads + tool_outputs + retrieved_documents + peer_messages.
  • CorticalLayer. Jensen-Shannon distance drift with Laplace smoothing and a min_drift_samples guard.
  • RecoveryLayer. Checkpoint Protocol with InMemory / File / Sqlite reference backends + tested snapshot() / restore_to() tamper-recover round trip.
  • BaselineStore Protocol. Behavioural baselines persist across process restarts via InMemory / File / Sqlite backends.
  • Cross-adapter conformance suite. 9 invariants × 5 adapters + a registry-stability sentinel test.
  • Detection benchmark harness. pytest -m benchmark; synthetic suite always runs; PINT / AgentDojo / InjecAgent loaders skip when their AGENTEGRITY_BENCH_* env var is unset. Real InjecAgent numbers (TPR=0.000) published in STATUS.md as the honest baseline that the next-release LLM classifier should improve.
  • Branch coverage gates. Python ≥ 85% (currently 86.71%), TypeScript ≥ 80% lines / ≥ 70% functions (currently 89.99% / 83.40%).
  • Nightly detection benchmark workflow.

Migration notes

  • PropertyWeights default recovery_integrity bumped from 0.0 to 0.15. Callers passing three keyword args (adversarial_coherence / environmental_portability / verifiable_assurance) without recovery_integrity will now hit the sum-to-1.0 validator. Either add recovery_integrity=0.0 or drop the explicit weights= argument and adopt the new default.
  • Cortical drift scores now come from Jensen-Shannon distance, not forward KL. Numeric values differ. Tuned drift_tolerance thresholds should be revalidated.

Stats

  • 313 unit tests + 5 benchmark tests + 2 benchmark skips.
  • ruff clean, mypy --strict clean across 29 source files.
  • Python branch coverage 86.71%; TS line coverage 89.99%, function coverage 83.40%.
  • 17 commits since v0.5.3 — see the merged PR for the full list.

Released by @requie.