Sarek AI Accountability TypeScript SDK
TypeScript SDK for accountable AI. Wraps your AI client, logs every call as a signed entry, and anchors a proof per decision. ESM, Node.js 18 or later.
npm install @sarek/ai-accountabilityAiLogger.init()
Creates a logger instance. Loads or creates the agent identity (a P-256 key pair on disk) and ensures the local directory structure exists.
Signature
class AiLogger {
static init(options?: AiLoggerOptions): Promise<AiLogger>
}Parameters
| Name | Type | Default | Description |
|---|---|---|---|
options.name | string | 'default' | Agent name. One identity and log file per name. |
options.role | string | 'unspecified' | The agent’s role, recorded in every entry. |
options.ledgerUrl | string | see below | Core Service endpoint. |
options.onLog | (entry: LogEntry, proof: AiLoggerProof) => void | Called immediately after signing. | |
options.onStamped | (proof: AiLoggerProof) => void | Called when the proof is anchored (~10 s later). |
URL precedence: explicit ledgerUrl, then ai-accountability/config.json
(created automatically, default http://localhost:3000), then the built-in
fallback.
Returns
Promise<AiLogger>.
Example
import { AiLogger } from '@sarek/ai-accountability'
const sarek = await AiLogger.init({
name: 'claims-triage',
role: 'insurance-claims',
onLog: (entry, proof) => auditDb.insert(entry),
onStamped: proof => auditDb.attachProof(proof.logId, proof.txHash)
})monitor()
Wraps an AI client in a Proxy and returns the wrapper. The original client
is never mutated. Provider detection is duck-typed from the client object, so
no provider SDK becomes a dependency.
Signature
monitor(client: unknown, options?: MonitorOptions): unknownParameters
| Name | Type | Description |
|---|---|---|
client | unknown | The AI client to wrap. |
options.provider | string | Required only for clients that cannot be distinguished automatically. |
Returns
A wrapped client with the same API as the original. Each response carries the
proof at response.aiLogger.
Supported providers
| Provider | Detection |
|---|---|
| OpenAI, Anthropic, Gemini, Azure OpenAI, Ollama (native), AWS Bedrock (Converse), Mistral, Cohere (V2) | Automatic |
| Groq, Together AI, OpenRouter | Automatic with the official SDK; hint when using an OpenAI client against their endpoint |
| Perplexity, Fireworks | Hint: { provider: 'perplexity' } / { provider: 'fireworks' } (no official TypeScript SDK) |
| xAI (Grok) | Hint: { provider: 'xai' } (wire-identical to OpenAI) |
Example
Auto-detected
import OpenAI from 'openai'
import Anthropic from '@anthropic-ai/sdk'
const openai = sarek.monitor(new OpenAI())
const anthropic = sarek.monitor(new Anthropic())Errors
Throws if the client cannot be recognized and no provider hint is given.
close()
Waits for all in-flight anchoring to finish. Call it before process exit so no proofs are lost. Safe to call more than once.
Signature
close(): Promise<void>Example
await sarek.close()The log flow
- Input and output are hashed separately with SHA3-256. Objects are serialized canonically (compact JSON, keys sorted at every level), so the same call produces the same hashes in TypeScript and Python.
- The entry is signed with the agent’s P-256 key.
onLog(entry, proof)fires immediately. The AI response is already on its way back to your code.- The combined hash is anchored asynchronously (~10 s). Failures are logged and never thrown into your application.
- The proof file is written, the log line is updated with
txHashandblockNumber, andonStamped(proof)fires.
LogEntry
One entry per AI call, appended to ai-accountability/logs/<agent>.jsonl.
| Field | Type | Description |
|---|---|---|
logId | string | UUID, unique per call |
timestamp | string | ISO 8601 |
provider | string | One of the 14 supported providers |
model | string | Model identifier from the response |
inputHash | string | SHA3-256 of the input, never the raw prompt |
outputHash | string | SHA3-256 of the output, never the raw completion |
predictionId | string | Provider response id, or a generated UUID |
inputTokens | number | From the provider’s usage block |
outputTokens | number | From the provider’s usage block |
totalTokens | number | Summed when the provider does not return it |
latencyMs | number | Wall-clock latency of the call |
finishReason | string | null | Why the model stopped |
statusCode | number | Always 200; failed calls are not logged |
systemFingerprint | string | null | Exact model version where the provider exposes it |
environment | string | null | From process.env.NODE_ENV |
sdkVersion | string | SDK version that wrote the entry |
agentId | string | The agent name |
role | string | The agent role |
signature | string | ECDSA P-256 over inputHash + outputHash |
txHash | string | Filled in after anchoring |
blockNumber | number | Filled in after anchoring |
citations | string[] | null | Perplexity only: source URIs, null otherwise |
AiLoggerProof
Attached to every response as response.aiLogger and passed to both
callbacks.
interface AiLoggerProof {
logId: string
agentId: string
role: string
inputHash: string
outputHash: string
ldgp: string // base64-encoded proof file
txHash: string
blockNumber: number
proofPath: string // path to the .ldgp file on disk
}CLI
The package installs a sarek binary for working with local logs.
| Command | Description |
|---|---|
sarek list [--agent <name>] | List log entries, with anchoring status and txHash |
sarek verify --logId <id> | Show the entry and check that its proof file exists locally. Full cryptographic verification runs through the Core Service, see Verification. |
sarek get log --logId <id> | Extract entry plus proof to ai-accountability/extracted/<logId>/, a portable evidence package |
sarek get report [--agent <name>] | Generate a six-page PDF report and anchor it |
sarek clear [--agent <name>] | Delete local logs, proofs and reports |
Local files
ai-accountability/
config.json created automatically
.gitignore created automatically, protects private keys
agents/
<name>/
identity.json
private.key P-256 private key (chmod 600)
logs/
<name>.jsonl one line per AI call
proofs/
<name>/
log-<logId>.ldgp one proof per call
reports/ written by `sarek get report`
extracted/ written by `sarek get log`