Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,34 @@ jobs:
- name: Smoke-test the LangChain example
run: python examples/langchain_policy_middleware_demo.py

pydantic-ai-contract:
name: Pydantic AI 2.22.0 contract
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.11"
cache: pip
cache-dependency-path: |
requirements-dev.lock
requirements-pydantic-ai.lock
pyproject.toml
- name: Install locked development and Pydantic AI contract dependencies
run: |
python -m pip install --require-hashes \
-r requirements-dev.lock \
-r requirements-pydantic-ai.lock
python -m pip install --no-build-isolation --no-deps -e .
- name: Test exact Pydantic AI agent contract
run: python -m pytest --no-cov integration_tests/test_pydantic_ai_sdk.py
- name: Smoke-test the Pydantic AI example
run: python examples/pydantic_ai_policy_toolset_demo.py

opentelemetry-contract:
name: OpenTelemetry 1.44.0 contract
runs-on: ubuntu-latest
Expand Down Expand Up @@ -534,7 +562,14 @@ jobs:
attest:
name: Attest distributions
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [test, openai-agents-contract, langchain-contract, opentelemetry-contract]
needs:
[
test,
openai-agents-contract,
langchain-contract,
pydantic-ai-contract,
opentelemetry-contract,
]
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ All notable product changes are recorded here.
- Optional exact-registry LangChain `1.3.14` sync/async tool middleware with final raw-argument
enforcement, native LangGraph interrupts, strict fingerprint-bound approval resume, generic
rejection results, a no-network real-agent example, and a dedicated hashed CI contract.
- Optional exact-registry Pydantic AI `2.22.0` wrapper toolset with native deferred approvals,
strict Samsarix evidence on resume, atomic single-use approval consumption, fresh current-policy
enforcement, a no-network real-agent example, adversarial tests, and a dedicated slim
hash-locked CI contract.

### Changed

Expand Down
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ tool inside the hash-verified dependency boundary.

Optional integrations have separate exact contract inputs and locks. Regenerate them with the same
universal Python 3.11 flags and run their dedicated integration tests and examples in environments
that install exactly one of `requirements-openai-agents.lock`, `requirements-langchain.lock`, or
`requirements-opentelemetry.lock` together with the development lock. Keep optional packages out
of the base development environment so the dependency-free import contract remains testable.
that install exactly one of `requirements-openai-agents.lock`, `requirements-langchain.lock`,
`requirements-pydantic-ai.lock`, or `requirements-opentelemetry.lock` together with the development
lock. Keep optional packages out of the base development environment so the dependency-free import
contract remains testable.

## Required checks

Expand Down
41 changes: 33 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ review?**
It is for Python developers who need a small policy-as-code boundary in front of tool calls,
workflows, or other consequential operations. Policies and inputs are JSON, decisions are
explainable, and the optional audit log excludes raw input by design. The package makes no
network calls and its core has no runtime dependencies. An optional OpenAI Agents SDK adapter is
isolated behind one install extra, an optional LangChain middleware protects exact tool registries
with fingerprint-bound review interrupts, and an optional OpenTelemetry API extra emits
metadata-only decision events into caller-owned traces. Other Samsarix repositories can embed the
core, but none is required; the package and its release lifecycle stand on their own.
network calls and its core has no runtime dependencies. Optional exact-version adapters protect
OpenAI Agents SDK function tools, LangChain tool registries, and Pydantic AI toolsets with
fingerprint-bound native review flows. An optional OpenTelemetry API extra emits metadata-only
decision events into caller-owned traces. Other Samsarix repositories can embed the core, but none
is required; the package and its release lifecycle stand on their own.

Within the Samsarix portfolio, this repository owns agent-action safety policy, human-review
outcomes, exact-call enforcement, privacy-minimized decision evidence, and the policy lifecycle.
Expand Down Expand Up @@ -604,6 +604,30 @@ the reviewer, so production checkpointers need sensitive-data controls and an au
surface. See the [LangChain middleware guide](docs/LANGCHAIN.md) for ordering, rejection, audit,
parallel-call, persistence, and unsupported-path boundaries.

## Pydantic AI integration

Install the slim optional runtime and run its deterministic no-network agent:

```bash
python -m pip install -e '.[pydantic-ai]'
python examples/pydantic_ai_policy_toolset_demo.py
```

`create_pydantic_ai_tool_policy(bound_catalog, toolset)` returns a policy object whose `toolset`
wraps Pydantic AI's public execution seam. Every run step must expose the complete exact catalog
as real `ToolsetTool` objects, and each call must resolve to the snapshotted object. Allow delegates
once, deny never delegates, and review becomes native `DeferredToolRequests` metadata bound to the
exact call fingerprint.

After authenticating the reviewer, use `tool_policy.build_results(requests, decisions)` to create
resume evidence. A plain Pydantic AI boolean approval is not enough: resume requires Samsarix
metadata, fresh actor/context providers, and current-policy re-enforcement. Pydantic AI performs
schema validation before the wrapper, so this adapter authorizes validated JSON-native arguments;
custom argument validators must have no side effects. Approved results are first-write recorded
and atomically consumed; durable reconstruction supplies an application-owned approval store. See the
[Pydantic AI toolset guide](docs/PYDANTIC_AI.md) for multi-call resolution, persistence, sensitive
metadata, and unsupported-path boundaries.

## Downstream adoption

Samsarix Agent Framework is the first verified downstream consumer. Its optional policy registry
Expand All @@ -612,9 +636,10 @@ capabilities outside model arguments, re-reads authentication/approval facts for
blocks execution on every non-allow outcome or gate failure. The consumer contract runs on Python
3.11-3.14 while the framework's dependency-free core retains Python 3.10 support.

The repository also carries public, reproducible OpenAI Agents SDK and LangChain adapters with
exact-version contract tests. The consumer repository remains private as of 2026-08-01, so none of
these items is a public third-party case study or production deployment. Exact commits,
The repository also carries public, reproducible OpenAI Agents SDK, LangChain, and Pydantic AI
adapters with exact-version contract tests. The consumer repository remains private as of
2026-08-01, so none of these items is a public third-party case study or production deployment.
Exact commits,
compatibility, rollback, support level, and evidence limits are recorded in
[adoption and compatibility evidence](docs/ADOPTION.md).

Expand Down
24 changes: 17 additions & 7 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ attested artifact, publishing a release, and claiming adopter evidence are disti
The Python 3.11 CI job builds the wheel and source distribution once, validates both files, installs
the wheel into a clean virtual environment, and uploads the exact files as
`python-distributions-<commit>` for 14 days. The same workflow exercises the source package across
Python 3.11-3.14. Dedicated hash-locked lanes exercise the exact OpenAI Agents SDK, LangChain, and
OpenTelemetry API/SDK contracts plus their no-network examples; release candidates are valid only
when the complete matrix and all optional-integration lanes are green.
Python 3.11-3.14. Dedicated hash-locked lanes exercise the exact OpenAI Agents SDK, LangChain,
Pydantic AI, and OpenTelemetry API/SDK contracts plus their no-network examples; release candidates
are valid only when the complete matrix and all optional-integration lanes are green.

For pushes to `main`, a separate least-privilege job waits for the complete matrix, downloads those
already-verified files, and creates GitHub build-provenance attestations. The attestation links each
Expand Down Expand Up @@ -55,7 +55,17 @@ Nothing in this repository currently uploads to PyPI, creates a GitHub release,
python examples/langchain_policy_middleware_demo.py
```

6. In a third fresh virtual environment, validate only the OpenTelemetry optional contract:
6. In a third fresh virtual environment, validate only the Pydantic AI optional contract:

```bash
python -m pip install --require-hashes \
-r requirements-dev.lock \
-r requirements-pydantic-ai.lock
python -m pytest --no-cov integration_tests/test_pydantic_ai_sdk.py
python examples/pydantic_ai_policy_toolset_demo.py
```

7. In a fourth fresh virtual environment, validate only the OpenTelemetry optional contract:

```bash
python -m pip install --require-hashes \
Expand All @@ -65,7 +75,7 @@ Nothing in this repository currently uploads to PyPI, creates a GitHub release,
python examples/opentelemetry_decision_event_demo.py
```

7. Download the exact CI distributions for the commit, then verify their provenance:
8. Download the exact CI distributions for the commit, then verify their provenance:

```bash
gh run download RUN_ID \
Expand All @@ -77,9 +87,9 @@ Nothing in this repository currently uploads to PyPI, creates a GitHub release,
--repo Deathcharge/samsarix-agent-ethics
```

8. Install the downloaded wheel with `--no-deps` in a new virtual environment and run
9. Install the downloaded wheel with `--no-deps` in a new virtual environment and run
`samsarix-ethics --version`, schema export, policy validation, and one allow/deny walkthrough.
9. Record the commit, CI run, distribution SHA-256 digests, attestation verification, and rollback
10. Record the commit, CI run, distribution SHA-256 digests, attestation verification, and rollback
ref in the release notes.

## Registry publication prerequisites
Expand Down
6 changes: 5 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ adoption remain separate evidence-based decisions.
- [x] Add exact-registry LangChain sync/async middleware with final-argument enforcement, native
LangGraph review interrupts, fingerprint-bound resume, exact-version locking, and a real
no-network agent contract.
- [x] Add an exact-registry Pydantic AI wrapper toolset with native deferred review,
fingerprint-bound Samsarix resume evidence, exact slim-version locking, and a real no-network
agent contract.
- [x] Expose one immutable metadata-only audit record to a caller-supplied sink while preserving
the existing JSONL API and fail-closed behavior.
- [x] Correlate metadata-only decisions with a caller-owned OpenTelemetry trace through an optional
Expand Down Expand Up @@ -79,7 +82,8 @@ Current hardening backlog:

- No published package/release, public third-party adopter, or production deployment evidence.
- The first verified consumer is a private Samsarix repository; its evidence is maintainer-visible.
The public OpenAI, LangChain, and OpenTelemetry adapters are reproducible integration evidence,
The public OpenAI, LangChain, Pydantic AI, and OpenTelemetry adapters are reproducible
integration evidence,
not external adopter case studies.
- LangChain review checkpoints intentionally contain proposed tool arguments. Reviewer identity,
checkpoint confidentiality, expiry, one-time resume, and multi-call transactionality remain
Expand Down
12 changes: 12 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ one-time resume, and treat direct `BaseTool` calls or side effects performed by
outside this adapter. Parallel tool nodes are not a transaction and may produce partial side
effects. A rejected interrupt returns a generic tool error but is not an authorization audit record.

When using the optional Pydantic AI adapter, register only `tool_policy.toolset` for the protected
tools and require the complete run-step registry to remain equal to the trusted catalog. Pydantic
schema and custom argument validators run before the wrapper; validators must not perform side
effects, and policy sees their validated JSON-native result rather than the model's original
spelling. A native Pydantic approval boolean is not Samsarix authorization: approved resume must
carry adapter-built exact-call evidence and still pass current-policy enforcement. Protect
message/deferred state and conversation IDs, authenticate reviewers, enforce expiry and atomic
one-time consumption, and treat other toolsets, direct calls, provider tools, and pre-delegation
side effects as outside this adapter. Parallel calls remain non-transactional.
The default first-write/consume store blocks result replay only inside one live adapter instance;
durable reconstruction requires an application-owned implementation stored with workflow state.

`ToolGate` invokes only the explicit callback supplied by the embedding application and only after
an allow decision; it is not a sandbox. The package makes no network requests, executes no policy
code, loads no plugins, and stores no raw evaluation input in its built-in audit record.
Expand Down
34 changes: 26 additions & 8 deletions docs/ADOPTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ deployment. It is intentionally specific enough for maintainers to reproduce and
## Public runtime contract

The repository includes optional exact-version adapters for strict top-level OpenAI Agents SDK
`FunctionTool` objects and exact LangChain `BaseTool` registries. Dedicated CI jobs install hashed
dependency graphs for `openai-agents==0.18.3` and `langchain==1.3.14`, exercise real framework
types, and run no-network examples. The OpenAI contract verifies guardrail execution, callback
compatibility, and fail-closed handling before schema coercion. The LangChain contract verifies a
real checkpointed interrupt/resume and proves that a final Samsarix middleware sees an earlier
middleware's argument transformation before allowing execution. The [OpenAI guide](OPENAI_AGENTS.md)
and [LangChain guide](LANGCHAIN.md) make this evidence reproducible from a public checkout. These
are maintained compatibility contracts, not evidence of a third-party adopter, live model call,
`FunctionTool` objects, exact LangChain `BaseTool` registries, and exact Pydantic AI `ToolsetTool`
registries. Dedicated CI jobs install hashed dependency graphs for `openai-agents==0.18.3`,
`langchain==1.3.14`, and `pydantic-ai-slim==2.22.0`, exercise real framework types, and run
no-network examples. The OpenAI contract verifies guardrail execution and fail-closed handling
before schema coercion. The LangChain contract verifies a real checkpointed interrupt/resume and
final middleware ordering. The Pydantic AI contract verifies native deferred approval/rejection,
requires Samsarix evidence beyond a native boolean, and detects registry drift. The
[OpenAI guide](OPENAI_AGENTS.md), [LangChain guide](LANGCHAIN.md), and
[Pydantic AI guide](PYDANTIC_AI.md) make this reproducible from a public checkout. These are
maintained compatibility contracts, not evidence of a third-party adopter, live model call,
production traffic, or hosted deployment.

## Implemented gap: exact-registry LangChain enforcement
Expand All @@ -35,6 +37,22 @@ and calls made outside the protected agent bypass this boundary. Parallel tool c
transaction and may still produce partial side effects. This is exact public runtime evidence, not
an adopter or production claim.

## Implemented gap: native Pydantic AI deferred authorization

Pydantic AI exposes `WrapperToolset.call_tool` as the public tool-execution wrapping seam and
`DeferredToolRequests`/`DeferredToolResults` as its pause-and-resume contract. Its documentation
also states that approval is not itself an authorization boundary. Samsarix therefore exact-matches
the full run-step registry, raises native `ApprovalRequired` for policy review, and requires
adapter-built fingerprint evidence in metadata before accepting a native approved resume. Current
policy and fresh application facts remain authoritative.

Pydantic schema and custom argument validation precedes the wrapper, so the boundary protects
validated arguments and requires side-effect-free validators. Other toolsets, direct calls, and
provider-side tools bypass the wrapper. Conversation and deferred state may retain proposed
arguments, while reviewer authentication, decision expiry, one-time consumption, and durable
storage remain application-owned. This is exact public runtime evidence, not adopter or production
evidence.

## Samsarix Agent Framework

Samsarix Agent Framework is the first consumer-owned integration. Its optional
Expand Down
23 changes: 22 additions & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,27 @@ strict `ToolCallApproval` dictionary matching the current call fingerprint befor
enforcement. Rejection returns a generic error `ToolMessage` without invoking the tool. The adapter
contract version is `LANGCHAIN_ADAPTER_VERSION = 1`. See [LANGCHAIN.md](LANGCHAIN.md).

### `create_pydantic_ai_tool_policy(bindings, toolset, *, actor_provider=None, context_provider=None, approval_store=None)`

Creates an optional `PydanticAIToolPolicy` for one exact `BoundToolCatalog` and one real Pydantic
AI `AbstractToolset`. Construction imports Pydantic AI only when called. `toolset` returns a public
`WrapperToolset` subclass suitable for `Agent(toolsets=[...])`; every run step must expose an exact
catalog-matching dictionary of real `ToolsetTool` objects, and execution must resolve to the
snapshotted object.

Providers are synchronous callbacks from `RunContext.deps` to fresh application-owned JSON facts.
`approval_store` implements `PydanticAIApprovalStore.remember(...)` and atomic `.consume(...)`.
The bounded thread-safe process-local default retains at most
`MAX_PENDING_PYDANTIC_AI_APPROVALS` (4,096) pending calls and fails closed after reconstruction;
durable workflows supply protected application-owned state.
Allow delegates once after audited enforcement. Deny raises the typed gate error. Review raises
native `ApprovalRequired` with `PYDANTIC_AI_REVIEW_METADATA_KEY` metadata.
`build_results(requests, decisions)` validates selected deferred calls and creates either
fingerprint-bound `PYDANTIC_AI_APPROVAL_METADATA_KEY` evidence or a generic `ToolDenied` result.
A native boolean approval without this evidence fails closed, and approved resume re-enforces the
current call and policy. The adapter contract version is `PYDANTIC_AI_ADAPTER_VERSION = 1`. See
[PYDANTIC_AI.md](PYDANTIC_AI.md).

### `BoundToolCatalog`

The immutable mapping returned by `ToolGate.bind_catalog(...)`. It exposes `gate`, `catalog`,
Expand Down Expand Up @@ -716,7 +737,7 @@ records. See [AUDIT_CHAINS.md](AUDIT_CHAINS.md) for the format and complete thre
`PolicyValidationError`, `PolicyDeploymentValidationError`, `PolicyActivationError`,
`PolicyCompositionError`, `PolicyTestValidationError`, `InputValidationError`, `EvaluationError`,
`AuditLogError`, `AuditChainError`, `OpenAIAgentsIntegrationError`, `LangChainIntegrationError`,
and the tool-call enforcement errors derive from
`PydanticAIIntegrationError`, and the tool-call enforcement errors derive from
`SamsarixEthicsError`. `AuditChainError` also derives from `AuditLogError`, preserving fail-closed
gate handling. The base
class and specialized errors are exported from `samsarix_ethics` and defined in
Expand Down
Loading