decision-os-sdk
v0.2.0
Published
Official TypeScript/JavaScript SDK for Decision OS — AI decision governance platform
Maintainers
Readme
decision-os-sdk
Official TypeScript SDK for Decision OS — the AI governance control plane.
Log decisions, capture runtime snapshots, and enforce policies across your AI agents with a single lightweight dependency.
Installation
npm install decision-os-sdkNo peer dependencies. Works in Node.js 18+, Edge Runtime, and Bun.
Quickstart
import { DecisionOS } from "decision-os-sdk";
const dos = new DecisionOS({
apiKey: process.env.DECISION_OS_API_KEY!,
agentId: "your-agent-id", // bind once, reuse across calls
baseUrl: "https://decisionos.com", // your Decision OS instance
});
// Log a decision with inline policy evaluation
const { decision_id, policy_eval } = await dos.logDecision({
context: "Route this support ticket to the right team",
options: [
{ key: "engineering", label: "Engineering" },
{ key: "billing", label: "Billing" },
{ key: "security", label: "Security" },
],
constraints: ["SLA < 4h", "Tier: enterprise"],
chosen: "engineering",
confidence: 0.91,
run_policy_eval: true, // evaluate against the agent's active policy
});
console.log(decision_id); // "d_..." — immutable ledger entry
console.log(policy_eval); // { ok: true, diff: {...} }Configuration
const dos = new DecisionOS({
apiKey: string; // required — Bearer token from Settings → API Keys
baseUrl?: string; // default: "https://decisionos.com"
agentId?: string; // bind a default agent_id (overridable per call)
timeoutMs?: number; // default: 8000 (8 seconds)
retries?: number; // default: 2 (exponential backoff on 5xx / 429)
userAgent?: string; // optional x-client header for tracing
});Methods
logDecision(input)
Writes a decision to the immutable Decision OS ledger. Returns a decision_id that anchors all downstream records (snapshots, outcomes, replays).
const response = await dos.logDecision(input: LogDecisionInput);Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| context | string | ✅ | The decision prompt, question, or situation |
| chosen | string | ✅ | The key of the option the agent selected |
| agent_id | string | if not in config | ID of the governed agent |
| decision_type | string | — | Default: "action_selection" |
| options | DecisionOption[] | — | All considered options with labels and probabilities |
| constraints | string[] | — | Constraints that were active at decision time |
| assumptions | DecisionAssumption[] | — | Assumptions the agent operated under |
| confidence | number | — | Agent confidence 0–1 |
| policy_version_id | string | — | Pin to a specific policy version |
| runner | string | — | Runner identifier (e.g. "gpt_runner") |
| model | string | — | Model used (e.g. "gpt-4o") |
| prompt_version | string | — | Prompt version string |
| parameters | Record<string, unknown> | — | Runner parameters (temperature, top_p, etc.) |
| trace_id | string | — | OTel / LangSmith trace ID |
| run_id | string | — | Run or thread ID |
| span_id | string | — | Span ID for distributed tracing |
| parent_span_id | string | — | Parent span ID |
| request_id | string | — | Idempotency key — duplicate calls return the original |
| run_policy_eval | boolean | — | Run inline policy evaluation and return the diff |
Response
type LogDecisionResponse = {
decision_id: string; // immutable ledger ID
status: "draft" | "committed" | string;
policy_eval?: { // present if run_policy_eval: true
ok: boolean;
replay_id?: string;
policy_version_id?: string;
diff?: Record<string, unknown>;
error?: string;
};
};Full example
const { decision_id, policy_eval } = await dos.logDecision({
context: "Should we approve this loan application? Credit score: 720, DTI: 38%",
options: [
{ key: "approve", label: "Approve", probability: 0.72 },
{ key: "decline", label: "Decline", probability: 0.18 },
{ key: "manual_review", label: "Send to underwriting", probability: 0.10 },
],
constraints: ["Regulatory: ECOA", "Max DTI: 43%"],
assumptions: [
{ text: "Credit score is current", confidence: 0.99 },
{ text: "Income is verified", confidence: 0.95 },
{ text: "No adverse employment events", confidence: 0.87 },
],
chosen: "approve",
confidence: 0.72,
runner: "lending_runner_v2",
model: "gpt-4o",
prompt_version: "lending-v3.1",
trace_id: opentelemetrySpan.traceId,
run_id: workflowRunId,
request_id: transactionId, // idempotency — safe to retry
run_policy_eval: true,
});
if (policy_eval && !policy_eval.ok) {
// Active policy flagged this decision — alert or escalate
await sendAlert(decision_id, policy_eval.error);
}captureSnapshot(input)
Attaches runtime evidence to an existing decision: model telemetry, tool call traces, timing data, and evaluation results. Use this immediately after the agent produces its output.
const response = await dos.captureSnapshot(input: CaptureSnapshotInput);Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| decision_id | string | ✅ | The decision_id from logDecision |
| snapshot | Record<string, unknown> | ✅ | Freeform runtime state to preserve |
| agent_id | string | if not in config | ID of the governed agent |
| event_id | string | — | Source event ID for the snapshot |
| policy_version_id | string | — | Policy version active at capture time |
| schema_version | string | — | Snapshot schema version string |
| captured_at | string | — | ISO 8601 timestamp (defaults to now) |
| trace_id | string | — | OTel trace ID |
| run_id | string | — | Run or thread ID |
| span_id | string | — | Span ID |
| parent_span_id | string | — | Parent span ID |
| request_id | string | — | Idempotency key |
| tool_calls | Record<string, unknown> | — | Tool call records (inputs, outputs, errors) |
| model_usage | Record<string, unknown> | — | Token counts: { input_tokens, output_tokens, total_tokens } |
| timings | Record<string, unknown> | — | Latency data: { latency_ms, first_token_ms } |
| eval | Record<string, unknown> | — | Evaluation results (rubric scores, pass/fail) |
| eval_score | number | — | Scalar evaluation score 0–1 |
| eval_pass | boolean | — | Whether the evaluation passed |
Response
type CaptureSnapshotResponse = {
snapshot_id: string;
};Full example
const { snapshot_id } = await dos.captureSnapshot({
decision_id: decision_id, // from logDecision
snapshot: {
input: userMessage,
output: agentResponse,
state: graphState,
},
tool_calls: {
search: { query: "loan regulations DTI", results_count: 14, latency_ms: 340 },
},
model_usage: {
input_tokens: 1842,
output_tokens: 287,
total_tokens: 2129,
},
timings: {
latency_ms: 1240,
first_token_ms: 380,
},
eval: evalResult,
eval_score: 0.94,
eval_pass: true,
trace_id: opentelemetrySpan.traceId,
run_id: workflowRunId,
});logOutcome(input)
Closes the governance loop by recording what actually happened after a decision was made. The outcome is appended to the workspace outcome chain with a tamper-evident hash linking it to the original decision.
const outcome = await dos.logOutcome({
decision_id: decision_id, // from logDecision
status: "success", // "success" | "partial" | "fail" | "unknown"
notes: "Resolved in 2h by engineering team",
actual: { resolution_type: "human_override", override_by: "agent_supervisor" },
});
console.log(outcome.outcome_id); // immutable outcome ledger ID
console.log(outcome.chain_index); // position in the outcome chain
console.log(outcome.content_hash); // SHA-256 hash for this outcomeParameters
| Field | Type | Required | Description |
|---|---|---|---|
| decision_id | string | ✅ | The decision_id from logDecision |
| status | string | ✅ | "success" | "partial" | "fail" | "unknown" |
| notes | string \| null | — | Human-readable outcome summary |
| actual | Record<string, unknown> \| null | — | Structured outcome data |
verifyChain(options?)
Cryptographically verifies the workspace decision and outcome chains by recomputing SHA-256 hashes and confirming prev_hash links. Returns a verification report for compliance attestation.
const report = await dos.verifyChain({ lastN: 100 });
if (!report.ok) {
console.error("Chain integrity failure:", report.decisions.error_details);
}
console.log(`Verified ${report.decisions.checked} decisions — ${report.decisions.errors} errors`);
console.log(`Verified ${report.outcomes.checked} outcomes — ${report.outcomes.errors} errors`);Parameters
| Field | Type | Description |
|---|---|---|
| lastN | number | Verify the N most recent records in each chain. Default: 50 |
Error handling
The SDK throws DecisionOSApiError for non-retriable API errors (4xx). Transient errors (5xx, 429, timeouts) are retried automatically up to retries times with exponential backoff.
import { DecisionOS } from "decision-os-sdk";
try {
const result = await dos.logDecision({ ... });
} catch (err) {
if (err instanceof Error) {
// err.message includes the HTTP status and API error text
// e.g. "DecisionOS: API error 401 Unauthorized - invalid api key"
console.error(err.message);
}
}Network timeouts abort after timeoutMs (default 8s) and are retried.
TypeScript types
import type {
DecisionOSConfig,
LogDecisionInput,
LogDecisionResponse,
CaptureSnapshotInput,
CaptureSnapshotResponse,
DecisionOption,
DecisionAssumption,
} from "decision-os-sdk";Integration examples
LangGraph (TypeScript)
import { StateGraph, END } from "@langchain/langgraph";
import { DecisionOS } from "decision-os-sdk";
const dos = new DecisionOS({
apiKey: process.env.DECISION_OS_API_KEY!,
agentId: "fraud-review-agent",
baseUrl: "https://decisionos.com",
});
async function reviewNode(state: { summary: string; runId: string }) {
const verdict = await runFraudModel(state.summary);
const { decision_id } = await dos.logDecision({
context: state.summary,
options: [{ key: "approve" }, { key: "decline" }, { key: "review" }],
chosen: verdict.action,
confidence: verdict.confidence,
run_id: state.runId,
run_policy_eval: true,
});
return { ...state, decisionId: decision_id };
}
const graph = new StateGraph({ channels: stateSchema })
.addNode("review", reviewNode)
.addEdge("review", END);Full guide: LangGraph + Decision OS integration
OpenAI Assistants API + Chat Completions
Use the built-in integration helpers for zero-boilerplate logging. They automatically extract model, usage, latency, and thread metadata.
import { DecisionOS } from "decision-os-sdk";
import { logAssistantRun, logChatCompletion } from "decision-os-sdk/integrations/openai";
import OpenAI from "openai";
const dos = new DecisionOS({
apiKey: process.env.DECISION_OS_API_KEY!,
agentId: "support-router",
});
const openai = new OpenAI();
// ── Assistants API ─────────────────────────────────────────────────────────
const run = await openai.beta.threads.runs.poll(thread.id, run.id);
await logAssistantRun(dos, run, {
decisionContext: "Classify and route support ticket #8820",
chosen: lastAssistantMessage,
// model, usage, latency, thread_id extracted automatically
});
// ── Chat Completions ───────────────────────────────────────────────────────
const completion = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: prompt }],
});
await logChatCompletion(dos, completion, {
decisionContext: "Route support ticket",
chosen: completion.choices[0].message.content ?? "unknown",
// model, usage extracted automatically; snapshot captured fire-and-forget
});REST API (any language)
curl -X POST https://decisionos.com/api/public/v1/decisions \
-H "Authorization: Bearer dos_live_..." \
-H "Content-Type: application/json" \
-d '{
"agentId": "your-agent-id",
"context": "Classify this document",
"chosenOptionKey": "contract",
"confidence": 0.94,
"options": [
{ "key": "contract" },
{ "key": "invoice" },
{ "key": "other" }
],
"runPolicyEval": true
}'Resources
License
MIT
