Metadata-Version: 2.5
Name: truthlocks-openai
Version: 1.1.0
Summary: Truthlocks MAIP wrapper for OpenAI — auto-generate cryptographic receipts for every API call
Project-URL: Homepage, https://truthlocks.com
Project-URL: Documentation, https://docs.truthlocks.com/sdk/openai
Project-URL: Repository, https://github.com/truthlocks/maip
Author-email: Truthlocks Inc <support@truthlocks.com>
License-Expression: Apache-2.0
Keywords: ai-provenance,machine-identity,maip,openai,receipts,truthlocks
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.9
Requires-Dist: maip-ai-connectors[openai]<2,>=1.1.0
Description-Content-Type: text/markdown

# Truthlocks for OpenAI

Capture structured evidence about OpenAI operations in your Python application.
Inspect input/output hashes and execution metadata alongside the original result.

**Package:** `truthlocks-openai` · **Python:** 3.9+ · **License:** Apache-2.0

[Developer documentation](https://docs.truthlocks.com) · [Truthlocks Console](https://console.truthlocks.com)

## Install

```sh
python -m pip install truthlocks-openai
```

This package re-exports the OpenAI integration from `maip-ai-connectors` and installs
its corresponding optional dependencies. Keep compatible versions of the integration
and your provider/framework in your application's lockfile.

## Run a complete local example

This example creates local receipt data without calling a paid model or submitting
anything to Truthlocks. It deliberately sets `auto_receipt=False`.

```python
from types import SimpleNamespace
from truthlocks_openai import MAIPOpenAIWrapper
from maip_ai_connectors.config import MAIPConfig

# A local stand-in demonstrates the return contract without paid API calls.
class DemoCompletions:
    def create(self, **kwargs):
        message = SimpleNamespace(content="Hello", tool_calls=[])
        return SimpleNamespace(choices=[SimpleNamespace(message=message)],
                               usage=SimpleNamespace(prompt_tokens=1, completion_tokens=1))

client = SimpleNamespace(chat=SimpleNamespace(completions=DemoCompletions()))
wrapper = MAIPOpenAIWrapper(client=client, config=MAIPConfig(auto_receipt=False))
response, receipt = wrapper.chat_completions_create(
    model="demo-model", messages=[{"role": "user", "content": "Hello"}]
)
print(response.choices[0].message.content)
print(receipt.payload_hash)
```

## Connect your application

Replace `client` with your authenticated `openai.OpenAI` client and `demo-model` with a model available to your account. Calls through these two wrapper methods return `(provider_response, local_receipt)`. Responses API, moderation, streaming and async provider clients are not implemented by this wrapper.

Provider credentials belong to the underlying provider client. A Truthlocks key does
not authenticate a model provider, and provider charges are separate.

## Understand the result

`payload_hash` is a hash of locally constructed receipt data. It is **not** a server
receipt ID, a signature, proof of transparency-log inclusion, or confirmation that
Truthlocks accepted the event. The local receipt has no `receipt_id` property.
Export its structured fields with `receipt.model_dump()` or `receipt.model_dump_json()`.
Hashing application-supplied data does not independently establish that an AI provider
performed an operation or that the output is correct.

## API and configuration

| Item | Purpose |
| --- | --- |
| `MAIPOpenAIWrapper` | Public integration classes exported by this package. |
| `chat_completions_create() and embeddings_create()` | Supported entry points; see the example for the relevant class. |
| `MAIPConfig(auto_receipt=False)` | Collect local evidence without background HTTP submission. |
| `agent_id` | Registered agent in the authenticated workspace, used for signing. |
| `tenant_id` | Workspace metadata in the payload; it does not grant access. |

## Hosted receipt submission


## Submit and verify hosted evidence (1.1.0+)

Register a machine identity in your workspace before submission. Set `MAIP_AGENT_ID`
to its identifier and `MAIP_API_KEY` to a workspace API key with access to machine
identities and receipts. Provider keys are separate. A `tl_test_` key selects the
sandbox host unless `MAIP_API_URL` overrides it; production defaults to
`https://api.truthlocks.com/v1`. Do not use a tenant header as authentication.

This example submits the local `receipt` created above only when credentials are set:

```python
import asyncio
import os
from maip_ai_connectors.client import MAIPClient
from maip_ai_connectors.config import MAIPConfig

async def submit_and_verify(local_receipt):
    config = MAIPConfig(agent_id=os.environ["MAIP_AGENT_ID"],
                        api_key=os.environ["MAIP_API_KEY"])
    async with MAIPClient(config) as client:
        stored = await client.create_receipt(local_receipt)
        check = await client.verify_receipt(stored.receipt_id)
        if not check.valid or not check.signature_verified:
            raise RuntimeError(check.reason or check.verdict)
        print(stored.receipt_id, check.verdict)

if os.environ.get("MAIP_API_KEY") and os.environ.get("MAIP_AGENT_ID"):
    asyncio.run(submit_and_verify(receipt))
```

The server stores integration metadata in a signed MAIP action receipt. Its
`receipt_id` differs from the local `payload_hash`. Verification checks the signature
and current lifecycle state; it does **not** establish transparency-log inclusion.
Old receipts whose signing key was lost return `UNVERIFIABLE`.

For automatic hooks, enable `auto_receipt=True`. In synchronous code delivery is
confirmed before the hook returns. In asynchronous code, call `await wrapper.flush()`
and `await wrapper.aclose()` before shutdown; inspect `get_submitted_receipts()` for
server responses. These lifecycle methods apply to AI wrappers/callbacks; data
clients use their async context manager or `create_receipt_sync()` instead.
Read retries are bounded; writes are never automatically replayed. After a timeout,
check the agent's receipts before retrying. Listing returns up to the latest 100
receipts for one agent, with integration filters applied to that page.

## Troubleshooting

| Symptom | Check |
| --- | --- |
| Import fails | Install this package in the Python environment running your app, including its optional framework dependencies. |
| Provider authentication fails | Configure credentials on the underlying provider client. |
| No local receipts | Execute a supported wrapper method or invoke an attached callback; construction alone records nothing. |
| `receipt_id` is missing | The returned object is local evidence; use `payload_hash` to inspect its digest. |
| No receipt arrives in Console | Local mode does not submit; configure a registered agent and await confirmed delivery. |

No fixed latency, automatic compliance certification, or universal event coverage is
promised. Measure overhead in your application and inspect the fields you retain.
For support, include the package version and a sanitized reproduction; exclude keys,
raw customer content and authentication tokens.
