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
30 changes: 29 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,34 @@ jobs:
- name: Smoke-test the OpenAI Agents example
run: python examples/openai_agents_guardrail_demo.py

langchain-contract:
name: LangChain 1.3.14 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-langchain.lock
pyproject.toml
- name: Install locked development and LangChain contract dependencies
run: |
python -m pip install --require-hashes \
-r requirements-dev.lock \
-r requirements-langchain.lock
python -m pip install --no-build-isolation --no-deps -e .
- name: Test exact LangChain agent contract
run: python -m pytest --no-cov integration_tests/test_langchain_sdk.py
- name: Smoke-test the LangChain example
run: python examples/langchain_policy_middleware_demo.py

opentelemetry-contract:
name: OpenTelemetry 1.44.0 contract
runs-on: ubuntu-latest
Expand Down Expand Up @@ -506,7 +534,7 @@ jobs:
attest:
name: Attest distributions
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [test, openai-agents-contract, opentelemetry-contract]
needs: [test, openai-agents-contract, langchain-contract, opentelemetry-contract]
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ All notable product changes are recorded here.
- An optional OpenTelemetry decision-event sink with a stable privacy-minimized `samsarix.*`
attribute contract, exact `opentelemetry-api/sdk==1.44.0` integration lane, no-network example,
and bounded ordered `CompositeAuditSink` fan-out for durable storage plus trace correlation.
- 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.

### Changed

Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ 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 `requirements-openai-agents.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`, 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
40 changes: 32 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ It is for Python developers who need a small policy-as-code boundary in front of
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, 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.
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.

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 @@ -580,6 +581,29 @@ remains dependency-free. Hosted/built-in tools, MCP-hosted tools, handoffs, name
[OpenAI Agents SDK integration guide](docs/OPENAI_AGENTS.md) for the supported boundary, approval
semantics, Pydantic-coercion caveat, and production checklist.

## LangChain integration

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

```bash
python -m pip install -e '.[langchain]'
python examples/langchain_policy_middleware_demo.py
```

`create_langchain_tool_policy(bound_catalog)` returns a policy object whose `validate_tools`
method requires an exact real `BaseTool` registry and whose middleware enforces both sync and async
tool calls. Put `tool_policy.middleware` last in LangChain's middleware list so it sees the final
raw arguments after other middleware transformations. Unknown tools, mismatched resolved tools,
denies, malformed inputs, and framework-shape errors never call the handler.

A policy `review` outcome uses LangGraph's native interrupt/checkpoint flow. The interrupt carries
the exact call fingerprint; the strict resume response must echo it and add `approved: true` before
the current policy, actor, context, name, capabilities, and arguments are re-enforced. Mutation or
replay against another call fails closed. The interrupt intentionally contains tool arguments for
the reviewer, so production checkpointers need sensitive-data controls and an authenticated review
surface. See the [LangChain middleware guide](docs/LANGCHAIN.md) for ordering, rejection, audit,
parallel-call, persistence, and unsupported-path boundaries.

## Downstream adoption

Samsarix Agent Framework is the first verified downstream consumer. Its optional policy registry
Expand All @@ -588,11 +612,11 @@ 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 a public, reproducible OpenAI Agents SDK adapter and exact-version
contract test. The consumer repository remains private as of 2026-08-01, so neither item 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).
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,
compatibility, rollback, support level, and evidence limits are recorded in
[adoption and compatibility evidence](docs/ADOPTION.md).

## Decision semantics

Expand Down
22 changes: 16 additions & 6 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 and
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 both optional-integration lanes are green.
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 @@ -45,7 +45,17 @@ Nothing in this repository currently uploads to PyPI, creates a GitHub release,
python examples/openai_agents_guardrail_demo.py
```

5. In a second fresh virtual environment, validate only the OpenTelemetry optional contract:
5. In a second fresh virtual environment, validate only the LangChain optional contract:

```bash
python -m pip install --require-hashes \
-r requirements-dev.lock \
-r requirements-langchain.lock
python -m pytest --no-cov integration_tests/test_langchain_sdk.py
python examples/langchain_policy_middleware_demo.py
```

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

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

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

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

7. Install the downloaded wheel with `--no-deps` in a new virtual environment and run
8. 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.
8. Record the commit, CI run, distribution SHA-256 digests, attestation verification, and rollback
9. Record the commit, CI run, distribution SHA-256 digests, attestation verification, and rollback
ref in the release notes.

## Registry publication prerequisites
Expand Down
10 changes: 8 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ adoption remain separate evidence-based decisions.
- [x] Add one public, reproducible OpenAI Agents SDK `FunctionTool` adapter with native approval
routing, exact-version dependency locking, a real SDK contract test, and explicit unsupported
execution paths.
- [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] 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 @@ -76,8 +79,11 @@ 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 and OpenTelemetry adapters are reproducible integration evidence, not external
adopter case studies.
The public OpenAI, LangChain, 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
application-owned.
- Installed-wheel smoke coverage, retained CI distributions, and GitHub build-provenance
attestations exist. PyPI project ownership, Trusted Publishing, protected release approval, and
durable registry publication evidence are not yet configured.
Expand Down
8 changes: 8 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ rather than per-call reviewer evidence. Durable runs must persist the adapter's
fingerprint alongside protected SDK state; the bounded in-memory default fails closed after
reconstruction.

When using the optional LangChain adapter, put Samsarix last in the middleware list so no inner
middleware can change arguments after authorization. Protect LangGraph thread IDs, checkpointer
state, and reviewer endpoints; review interrupts intentionally persist proposed tool arguments.
Authenticate and authorize reviewers, preserve the exact approval binding, enforce expiry and
one-time resume, and treat direct `BaseTool` calls or side effects performed by middleware itself as
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.

`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
36 changes: 29 additions & 7 deletions docs/ADOPTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,35 @@ deployment. It is intentionally specific enough for maintainers to reproduce and

## Public runtime contract

The repository now includes an optional adapter for strict top-level OpenAI Agents SDK
`FunctionTool` objects. Its dedicated CI job installs the hashed dependency graph for
`openai-agents==0.18.3` and verifies real SDK types, guardrail execution, callback compatibility,
and fail-closed handling of a value that Pydantic would otherwise coerce after the guardrail. The
no-network example and [integration guide](OPENAI_AGENTS.md) make this evidence reproducible from a
public checkout. It is a maintained compatibility contract, not evidence of a third-party adopter,
live model call, production traffic, or hosted deployment.
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,
production traffic, or hosted deployment.

## Implemented gap: exact-registry LangChain enforcement

LangChain documents `wrap_tool_call` as the middleware hook surrounding every tool call, with the
first middleware outermost, and LangGraph interrupts as checkpointed pause/resume primitives.
Samsarix therefore accepts only a complete set of real `BaseTool` objects whose names exactly
match a trusted `BoundToolCatalog`, and its middleware must be listed last so it authorizes the
final raw argument mapping after outer transformations. Allow and deny paths re-use the ordinary
gate; review emits one native interrupt whose response is bound to the exact tool-call ID,
normalized arguments, trusted catalog metadata, and actor. Resume re-evaluates the current policy
and trusted facts before invoking the framework handler once.

The interrupt payload necessarily persists proposed tool arguments in the application's LangGraph
checkpointer. The application therefore owns checkpointer encryption/access/retention, reviewer
authentication, CSRF protection, expiry, atomic one-time resume, and thread-ID authorization.
Direct `BaseTool.invoke`, server-side tools, middleware that executes before calling its handler,
and calls made outside the protected agent bypass this boundary. Parallel tool calls are not a
transaction and may still produce partial side effects. This is exact public runtime evidence, not
an adopter or production claim.

## Samsarix Agent Framework

Expand Down
22 changes: 21 additions & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,25 @@ input guardrails and approval logic, and appends Samsarix enforcement. It raises
`OPENAI_AGENTS_ADAPTER_VERSION`. See [OPENAI_AGENTS.md](OPENAI_AGENTS.md) for the exact execution
boundary and approval workflow.

### `create_langchain_tool_policy(bindings, *, actor_provider=None, context_provider=None)`

Creates an optional `LangChainToolPolicy` for one exact `BoundToolCatalog`. Construction imports
LangChain only when called. `validate_tools(tools)` requires real `BaseTool` instances whose names
exactly match the catalog. `middleware` is the sync/async `AgentMiddleware` instance and must be
last in LangChain's middleware list so it sees the final request after outer transformations.

The providers are synchronous callbacks from `request.runtime.context` to current application-
owned JSON facts. `explain(request)` performs an unaudited policy explanation and
`approval_for(request, approved=...)` creates unsigned exact-call evidence for a caller-owned
review system; neither method authenticates a reviewer or authorizes execution.

Allow invokes the original handler once after an audited enforcement. Deny raises the ordinary
typed gate error. Review calls LangGraph `interrupt()` with
`LANGCHAIN_REVIEW_INTERRUPT_TYPE = "samsarix.tool_call.review"`; an approved resume must be a
strict `ToolCallApproval` dictionary matching the current call fingerprint before final
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).

### `BoundToolCatalog`

The immutable mapping returned by `ToolGate.bind_catalog(...)`. It exposes `gate`, `catalog`,
Expand Down Expand Up @@ -696,7 +715,8 @@ records. See [AUDIT_CHAINS.md](AUDIT_CHAINS.md) for the format and complete thre

`PolicyValidationError`, `PolicyDeploymentValidationError`, `PolicyActivationError`,
`PolicyCompositionError`, `PolicyTestValidationError`, `InputValidationError`, `EvaluationError`,
`AuditLogError`, `AuditChainError`, and the tool-call enforcement errors derive from
`AuditLogError`, `AuditChainError`, `OpenAIAgentsIntegrationError`, `LangChainIntegrationError`,
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
3 changes: 3 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ untrusted action JSON ─> bounded parser ─> context object ──────
trusted tool catalog + complete local registry names ─> exact match ─> immutable gate bindings
locked policy deployment + fingerprinted catalog ─> ToolGateDeployment ─> verified bindings
verified bindings + final callback objects ─> ToolDispatcher ─> authorized sequential dispatch
verified bindings + exact LangChain BaseTools ─> final middleware ─> allow / interrupt / block

validated policy + optional contract/lock ─> PolicyRuntime generation N ─> live gates
validated complete candidate ─> compare-and-swap atomic activation ──────┘
Expand Down Expand Up @@ -65,6 +66,8 @@ the legacy `helix-unified` repository.
sync/async callback enforcement.
- `openai_agents.py`: optional strict `FunctionTool` protection and native approval-flow routing
without importing the SDK at core package import time.
- `langchain.py`: optional exact-registry sync/async middleware, final-argument enforcement, and
fingerprint-bound LangGraph interrupt resume without importing LangChain at core package import.
- `cli.py`: non-interactive commands, rendering, stderr discipline, and exit codes.
- `__init__.py`: deliberate public Python API.

Expand Down
Loading