Block Parsing

Updated

Chaos AI responses contain structured blocks: tables, charts, transaction actions, markdown, interactive elements, info alerts, code snippets, and forms. This recipe shows how to extract and handle each block type using the SDK's type guards and extraction functions.

Block Types Overview

The SDK defines 10 block types:

TypeDiscriminantType GuardExtraction Function
TabletableisTableBlockextractTableBlocks
Pie Chartpie_chartisPieChartBlockextractChartBlocks
Bar Chartbar_chartisBarChartBlockextractChartBlocks
Timeseriestimeseries_chartisTimeseriesChartBlockextractChartBlocks
ActionactionisTransactionActionBlockextractTransactionBlocks
MarkdownmarkdownisMarkdownBlockextractMarkdownBlocks
InteractiveinteractiveisInteractiveBlockextractInteractiveBlocks
AlertalertisInfoBlockextractInfoBlocks
CodecodeisCodeBlockextractCodeBlocks
FormformisFormBlockextractFormBlocks

Extracting All Blocks

Use extractBlocks to get every block from a response, regardless of type.

all-blocks.ts
import { extractBlocks, countBlocksByType, hasBlocks, hasBlockType } from '@chaoslabs/ai-sdk';
import type { ChatCreateResponse } from '@chaoslabs/ai-sdk';
 
function summarizeResponse(response: ChatCreateResponse) {
  if (!hasBlocks(response)) {
    console.log('Response contains no blocks');
    return;
  }
 
  const blocks = extractBlocks(response);
  console.log(`Total blocks: ${blocks.length}`);
 
  // Get counts per type
  const counts = countBlocksByType(response);
  for (const [type, count] of Object.entries(counts)) {
    if (count > 0) {
      console.log(`  ${type}: ${count}`);
    }
  }
 
  // Check for specific block types
  if (hasBlockType(response, 'action')) {
    console.log('Response contains transactions');
  }
  if (hasBlockType(response, 'table')) {
    console.log('Response contains tables');
  }
}

Type Guard Pattern

Iterate over all blocks and use type guards to handle each type with full type narrowing.

type-guard-pattern.ts
import {
  extractBlocks,
  isTableBlock,
  isChartBlock,
  isTransactionActionBlock,
  isMarkdownBlock,
  isInteractiveBlock,
  isInfoBlock,
  isCodeBlock,
  isFormBlock,
  isPieChartBlock,
  isBarChartBlock,
  isTimeseriesChartBlock,
} from '@chaoslabs/ai-sdk';
import type { ChatCreateResponse } from '@chaoslabs/ai-sdk';
 
function processBlocks(response: ChatCreateResponse) {
  for (const block of extractBlocks(response)) {
    if (isTableBlock(block)) {
      // block is TableBlock
      console.log('Table:', block.title);
      console.log('  Headers:', block.tableHeaders);
      console.log('  Rows:', block.tableRows.length);
 
    } else if (isTransactionActionBlock(block)) {
      // block is ActionBlock
      console.log('Action primitives:', block.primitives.map((p) => p.type));
      console.log('  Risk level:', block.risks.level);
 
    } else if (isChartBlock(block)) {
      // block is PieChartBlock | BarChartBlock | TimeseriesChartBlock
      console.log('Chart:', block.title, `(${block.type})`);
 
      if (isPieChartBlock(block)) {
        console.log('  Pie series:', block.series.length);
      } else if (isBarChartBlock(block)) {
        console.log('  Bar series:', block.series.length);
      } else if (isTimeseriesChartBlock(block)) {
        console.log('  Timeseries data points:', block.series.length);
      }
 
    } else if (isMarkdownBlock(block)) {
      // block is MarkdownBlock
      console.log('Markdown:', block.content.slice(0, 100) + '...');
 
    } else if (isInteractiveBlock(block)) {
      // block is InteractiveBlock
      console.log('Interactive:', block.title);
 
    } else if (isInfoBlock(block)) {
      // block is AlertBlock
      console.log('Alert:', block.severity, block.content);
 
    } else if (isCodeBlock(block)) {
      // block is CodeBlock
      console.log('Code:', block.language, block.content.slice(0, 50) + '...');
 
    } else if (isFormBlock(block)) {
      // block is FormBlock
      console.log('Form:', block.title);
    }
  }
}

Typed Extraction Functions

Each extraction function returns an array of the specific block type, already narrowed.

extraction-functions.ts
import {
  extractTableBlocks,
  extractChartBlocks,
  extractTransactionBlocks,
  extractMarkdownBlocks,
  extractInteractiveBlocks,
  extractInfoBlocks,
  extractCodeBlocks,
  extractFormBlocks,
} from '@chaoslabs/ai-sdk';
import type { ChatCreateResponse } from '@chaoslabs/ai-sdk';
 
function extractAll(response: ChatCreateResponse) {
  const tables       = extractTableBlocks(response);       // TableBlock[]
  const charts       = extractChartBlocks(response);       // ChartBlock[]
  const transactions = extractTransactionBlocks(response); // ActionBlock[]
  const markdown     = extractMarkdownBlocks(response);    // MarkdownBlock[]
  const interactive  = extractInteractiveBlocks(response);  // InteractiveBlock[]
  const alerts       = extractInfoBlocks(response);        // AlertBlock[]
  const code         = extractCodeBlocks(response);        // CodeBlock[]
  const forms        = extractFormBlocks(response);        // FormBlock[]
 
  return { tables, charts, transactions, markdown, interactive, alerts, code, forms };
}

Searching Blocks by Title

Use findTableByTitle and findChartByTitle to locate specific blocks by their title (case-insensitive substring match).

search-by-title.ts
import {
  findTableByTitle,
  findChartByTitle,
  tableToObjects,
} from '@chaoslabs/ai-sdk';
 
// Find a table containing 'positions' in its title
const positionsTable = findTableByTitle(response, 'positions');
if (positionsTable) {
  const rows = tableToObjects(positionsTable);
  console.log('Positions:', rows);
}
 
// Find a chart containing 'allocation' in its title
const chart = findChartByTitle(response, 'allocation');
if (chart) {
  console.log('Chart type:', chart.type);
}

Streaming Block Detection

Use isBlockMessage during streaming to detect block messages as they arrive.

streaming-blocks.ts
import {
  Chaos,
  WALLET_MODEL,
  isBlockMessage,
  isTableBlock,
  isChartBlock,
} 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: 'Show me top DeFi protocols by TVL' },
  ],
  metadata: { user_id: 'user-123', session_id: 'session-blocks' },
  onStreamEvent: (message) => {
    if (isBlockMessage(message)) {
      const block = message.data.block;
      if (isTableBlock(block)) {
        console.log('[stream] Table received:', block.title);
      } else if (isChartBlock(block)) {
        console.log('[stream] Chart received:', block.title);
      }
    }
  },
});
[@portabletext/react] Unknown block type "callout", specify a component for it in the `components.types` prop
Was this helpful?