Risk Assessment

Updated

Every transaction action block returned by the Chaos AI SDK includes risk metadata: a risk level (low, medium, high, critical), a list of warnings, and a list of blockers. This recipe shows how to build a complete risk-checking gate before executing transactions.

[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop

Full Example

risk-assessment.ts
import {
  Chaos,
  WALLET_MODEL,
  hasRisks,
  hasBlockers,
  getAllWarnings,
  getAllBlockers,
  getHighestRiskLevel,
  extractTransactionBlocks,
} from '@chaoslabs/ai-sdk';
import type { RiskLevel, ChatCreateResponse } from '@chaoslabs/ai-sdk';
 
const chaos = new Chaos({ apiKey: process.env.CHAOS_API_KEY! });
 
const response = await chaos.chat.responses.create({
  model: WALLET_MODEL,
  input: [
    {
      type: 'message',
      role: 'user',
      content: 'Swap 100 ETH for USDC on Ethereum',
    },
  ],
  metadata: {
    user_id: 'user-123',
    session_id: 'session-risk-demo',
    wallets: [{ address: '0xYourWallet', chain: 'ethereum' }],
  },
});
 
// ─── Risk Gate ──────────────────────────────────────────────────────────────
 
function assessRisk(response: ChatCreateResponse): 'proceed' | 'confirm' | 'block' {
  // Step 1: Check for hard blockers
  if (hasBlockers(response)) {
    const blockers = getAllBlockers(response);
    console.error('BLOCKED - Cannot proceed:');
    for (const blocker of blockers) {
      console.error(`  [${blocker.severity}] ${blocker.message}`);
    }
    return 'block';
  }
 
  // Step 2: Check for elevated risks
  if (hasRisks(response)) {
    const level = getHighestRiskLevel(response);
    const warnings = getAllWarnings(response);
 
    console.warn(`Risk level: ${level}`);
    for (const warning of warnings) {
      console.warn(`  [${warning.severity}] ${warning.message}`);
    }
 
    return 'confirm'; // Require user confirmation
  }
 
  // Step 3: No significant risks
  console.log('No risks detected');
  return 'proceed';
}
 
const decision = assessRisk(response);
 
switch (decision) {
  case 'proceed':
    console.log('Safe to execute transactions');
    break;
  case 'confirm':
    console.log('Requires user confirmation before executing');
    break;
  case 'block':
    console.log('Transaction should not be executed');
    break;
}

Risk Utilities Reference

hasRisks(response)

Returns true if any action block has a risk level above low.

has-risks.ts
import { hasRisks } from '@chaoslabs/ai-sdk';
 
if (hasRisks(response)) {
  // At least one action block has medium, high, or critical risk
  console.warn('Risks detected');
}

hasBlockers(response)

Returns true if any action block has high/critical risk level or non-empty blockers array.

has-blockers.ts
import { hasBlockers } from '@chaoslabs/ai-sdk';
 
if (hasBlockers(response)) {
  // At least one action block has blockers or high/critical risk
  console.error('Transaction is blocked');
}

getAllWarnings(response)

Collects all RiskInfoItem objects from the risks.warnings array of every action block.

get-warnings.ts
import { getAllWarnings } from '@chaoslabs/ai-sdk';
 
const warnings = getAllWarnings(response);
// RiskInfoItem[] — fields are optional: severity?, message?, title?, impact?
for (const w of warnings) {
  console.warn(`[${w.severity ?? 'warn'}] ${w.message ?? w.title ?? 'Unknown warning'}`);
}

getAllBlockers(response)

Collects all RiskInfoItem objects from the risks.blockers array of every action block.

get-blockers.ts
import { getAllBlockers } from '@chaoslabs/ai-sdk';
 
const blockers = getAllBlockers(response);
// RiskInfoItem[] — fields are optional: severity?, message?, title?, impact?
for (const b of blockers) {
  console.error(`[${b.severity ?? 'block'}] ${b.message ?? b.title ?? 'Unknown blocker'}`);
}

getHighestRiskLevel(response)

Returns the highest risk level across all action blocks, or undefined if no action blocks have a risk level set. Risk levels are ordered: low < medium < high < critical.

highest-risk.ts
import { getHighestRiskLevel } from '@chaoslabs/ai-sdk';
import type { RiskLevel } from '@chaoslabs/ai-sdk';
 
const level: RiskLevel | undefined = getHighestRiskLevel(response);
 
switch (level) {
  case 'low':
    console.log('Low risk - safe to proceed');
    break;
  case 'medium':
    console.warn('Medium risk - review warnings');
    break;
  case 'high':
    console.error('High risk - manual review required');
    break;
  case 'critical':
    console.error('Critical risk - do not execute');
    break;
  case undefined:
    console.log('No risk level set');
    break;
}

Per-Block Risk Inspection

For more granular control, inspect each action block's risks object directly.

per-block-risk.ts
import { extractTransactionBlocks } from '@chaoslabs/ai-sdk';
 
for (const block of extractTransactionBlocks(response)) {
  console.log(`\nAction block (${block.primitives.length} primitive(s))`);
  console.log(`  Risk level: ${block.risks.level}`);
 
  if (block.risks.warnings?.length) {
    console.log('  Warnings:');
    for (const w of block.risks.warnings) {
      console.log(`    - [${w.severity}] ${w.message}`);
    }
  }
 
  if (block.risks.blockers?.length) {
    console.log('  Blockers:');
    for (const b of block.risks.blockers) {
      console.log(`    - [${b.severity}] ${b.message}`);
    }
  }
}

Practical Pattern: Risk-Gated Execution

Combine risk assessment with transaction extraction for a production-ready execution gate.

risk-gate.ts
import {
  Chaos,
  WALLET_MODEL,
  hasBlockers,
  hasRisks,
  getHighestRiskLevel,
  getAllWarnings,
  extractTransactionBlocks,
} from '@chaoslabs/ai-sdk';
import type { ActionBlock } from '@chaoslabs/ai-sdk';
 
async function executeWithRiskGate(
  chaos: Chaos,
  query: string,
  walletAddress: string
): Promise<{ executed: boolean; reason: string; blocks: ActionBlock[] }> {
  const response = await chaos.chat.responses.create({
    model: WALLET_MODEL,
    input: [{ type: 'message', role: 'user', content: query }],
    metadata: {
      user_id: 'user-123',
      session_id: `session-${Date.now()}`,
      wallets: [{ address: walletAddress, chain: 'ethereum' }],
    },
  });
 
  const txBlocks = extractTransactionBlocks(response);
  if (txBlocks.length === 0) {
    return { executed: false, reason: 'No transactions returned', blocks: [] };
  }
 
  if (hasBlockers(response)) {
    return { executed: false, reason: 'Transaction blocked by risk engine', blocks: txBlocks };
  }
 
  if (hasRisks(response)) {
    const level = getHighestRiskLevel(response);
    const warnings = getAllWarnings(response);
    console.warn(`Proceeding with ${level} risk and ${warnings.length} warning(s)`);
  }
 
  // Forward txBlocks to wallet for signing...
  return { executed: true, reason: 'Transactions ready for signing', blocks: txBlocks };
}
[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop
Was this helpful?