Working with Responses
Every call to the Chaos AI API returns a ChatCreateResponse. This guide covers how to inspect the response status, extract text and structured blocks, and evaluate risk information attached to transaction proposals.
ChatCreateResponse Structure
The response object has the following shape:
| Field | Type | Description |
|---|---|---|
id | string | Unique response identifier |
kind | "response" | Always "response" |
model | string | Model used for the response |
status | "completed" | "failed" | Whether the request succeeded |
messages | ChaosSDKMessage[] | Array of response messages (text, blocks, status, etc.) |
error | ResponseError | Error details when status is "failed" |
The messages array contains different message types identified by their type field:
"text"-- Free-form text content"block"-- Structured data (tables, charts, transactions, forms, etc.)"status"-- Agent processing status updates"follow_up_suggestions"-- Suggested follow-up questions"input"-- User disambiguation requests
Extracting Text
extractText() collects all text messages from a response and joins them into a single string. This is the simplest way to get the conversational reply.
import { Chaos, WALLET_MODEL, extractText } 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: 'What is the current price of ETH?' }],
metadata: { user_id: 'user-123', session_id: 'session-abc' },
});
if (response.status === 'completed') {
const text = extractText(response);
console.log(text);
} else {
console.error('Request failed:', response.error);
}Extracting Blocks
extractBlocks() returns all Block objects from the response. Blocks are structured data -- tables, charts, transaction proposals, markdown, forms, interactive elements, and more.
import { Chaos, WALLET_MODEL, extractBlocks } 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 my portfolio breakdown.' }],
metadata: { user_id: 'user-123', session_id: 'session-abc' },
});
const blocks = extractBlocks(response);
for (const block of blocks) {
console.log(`Block type: ${block.type}`);
}
// Possible block types:
// "table" | "pie_chart" | "bar_chart" | "timeseries_chart" |
// "action" | "markdown" | "interactive" | "alert" | "code" | "form"Typed Block Extractors
The SDK provides specialized extractors that filter blocks by type and return properly typed arrays. Each returns only the matching block type, so you get full TypeScript inference.
Table Blocks
extractTableBlocks() returns TableBlock[]. Each table has tableHeaders (column names) and tableRows (2D data array). Use the companion utilities to convert tables to objects or query specific columns.
import {
Chaos,
WALLET_MODEL,
extractTableBlocks,
tableToObjects,
getTableColumn,
findTableRow,
getTableDimensions,
findTableByTitle,
} 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 my Aave positions.' }],
metadata: { user_id: 'user-123', session_id: 'session-abc' },
});
// Get all table blocks
const tables = extractTableBlocks(response);
if (tables.length > 0) {
const table = tables[0];
// Dimensions
const dims = getTableDimensions(table);
console.log(`${dims.rows} rows x ${dims.columns} columns`);
// Convert to array of objects
interface Position { Asset: string; Balance: string; APY: string }
const rows = tableToObjects<Position>(table);
for (const row of rows) {
console.log(`${row.Asset}: ${row.Balance} (${row.APY})`);
}
// Extract a single column
const assets = getTableColumn(table, 'Asset');
console.log('Assets:', assets);
// Find a specific row
const ethRow = findTableRow(table, 'Asset', 'ETH');
console.log('ETH row:', ethRow);
}
// Search by title
const supplyTable = findTableByTitle(response, 'supply');
if (supplyTable) {
console.log('Found supply table with', supplyTable.tableRows.length, 'rows');
}Chart Blocks
extractChartBlocks() returns a ChartBlock[] union of PieChartBlock | BarChartBlock | TimeseriesChartBlock. Use the chart utility functions or subtype guards to work with specific chart types.
import {
Chaos,
WALLET_MODEL,
extractChartBlocks,
getChartData,
getChartPercentages,
getChartTotal,
findChartByTitle,
isPieChartBlock,
isBarChartBlock,
isTimeseriesChartBlock,
} 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 my portfolio allocation.' }],
metadata: { user_id: 'user-123', session_id: 'session-abc' },
});
const charts = extractChartBlocks(response);
for (const chart of charts) {
if (isPieChartBlock(chart)) {
// Pie chart utilities
const data = getChartData(chart);
const percentages = getChartPercentages(chart);
const total = getChartTotal(chart);
console.log(`Total: $${total}`);
for (const segment of percentages) {
console.log(` ${segment.label}: ${segment.percentage.toFixed(1)}%`);
}
} else if (isBarChartBlock(chart)) {
console.log('Bar chart:', chart.title);
} else if (isTimeseriesChartBlock(chart)) {
console.log('Timeseries chart:', chart.title);
}
}
// Search by title
const allocationChart = findChartByTitle(response, 'allocation');
if (allocationChart) {
console.log('Found allocation chart');
}Transaction Action Blocks
extractTransactionBlocks() returns ActionBlock[]. These represent proposed DeFi transactions with primitives (the specific operations), risk assessments, and optional transaction sequences.
import {
Chaos,
WALLET_MODEL,
extractTransactionBlocks,
extractPrimitives,
extractPrimitivesByType,
getPrimitiveTypes,
findTransactionsByPrimitive,
} 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: 'Deposit 1 ETH into Aave on Ethereum.' }],
metadata: {
user_id: 'user-123',
session_id: 'session-abc',
wallets: [{ address: '0xABC...', chain: 'ethereum' }],
},
});
// Get all transaction blocks
const txBlocks = extractTransactionBlocks(response);
for (const block of txBlocks) {
console.log('Needs confirmation:', block.needs_confirmation);
console.log('Notes:', block.notes);
console.log('Risk level:', block.risks.level);
console.log('Primitives:', block.primitives.length);
}
// Extract all primitives across all transaction blocks
const primitives = extractPrimitives(response);
for (const p of primitives) {
console.log(`${p.type}: ${JSON.stringify(p.params)}`);
}
// Get unique primitive types
const types = getPrimitiveTypes(response);
console.log('Primitive types used:', types);
// Filter by specific type
const deposits = extractPrimitivesByType(response, 'lending_deposit');
console.log(`Found ${deposits.length} deposit primitive(s)`);
// Find transaction blocks containing a specific primitive
const depositBlocks = findTransactionsByPrimitive(response, 'lending_deposit');
console.log(`Found ${depositBlocks.length} block(s) with deposit primitives`);Risk Assessment
Transaction action blocks include a risks object with a severity level and arrays of warnings and blockers. The SDK provides functions to inspect risk information across all transaction blocks in a response.
Checking for Risks
hasRisks() returns true if any transaction block has a risk level above "low". hasBlockers() returns true if any block has "high" or "critical" risk level, or contains blockers.
import { Chaos, WALLET_MODEL, hasRisks, hasBlockers, extractText } 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.' }],
metadata: {
user_id: 'user-123',
session_id: 'session-abc',
wallets: [{ address: '0xABC...', chain: 'ethereum' }],
},
});
if (hasBlockers(response)) {
console.log('BLOCKED: This transaction has critical risks. Do not proceed.');
} else if (hasRisks(response)) {
console.log('WARNING: This transaction has elevated risks. Review before proceeding.');
} else {
console.log('Low risk. Safe to proceed.');
}
console.log(extractText(response));Inspecting Warnings and Blockers
getAllWarnings() and getAllBlockers() aggregate RiskInfoItem objects from all transaction blocks. Each item has optional title, message, severity, and impact fields.
import {
Chaos,
WALLET_MODEL,
getAllWarnings,
getAllBlockers,
getHighestRiskLevel,
} 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: 'Borrow 50000 USDC against my ETH on Aave.' }],
metadata: {
user_id: 'user-123',
session_id: 'session-abc',
wallets: [{ address: '0xABC...', chain: 'ethereum' }],
},
});
// Overall risk level across all transactions
const riskLevel = getHighestRiskLevel(response);
console.log('Highest risk level:', riskLevel); // "low" | "medium" | "high" | "critical" | undefined
// Inspect warnings
const warnings = getAllWarnings(response);
for (const w of warnings) {
console.log(`[WARNING] ${w.title}: ${w.message}`);
}
// Inspect blockers
const blockers = getAllBlockers(response);
for (const b of blockers) {
console.log(`[BLOCKER] ${b.title}: ${b.message}`);
}Block Statistics
The SDK provides utility functions to summarize the block composition of a response.
import {
Chaos,
WALLET_MODEL,
countBlocksByType,
hasBlocks,
hasBlockType,
} 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: 'Analyze my full portfolio.' }],
metadata: { user_id: 'user-123', session_id: 'session-abc' },
});
// Check if response contains any blocks
if (hasBlocks(response)) {
// Check for specific block types
if (hasBlockType(response, 'table')) {
console.log('Response includes table data');
}
if (hasBlockType(response, 'pie_chart')) {
console.log('Response includes pie charts');
}
// Get counts for all block types
const counts = countBlocksByType(response);
console.log('Block counts:', counts);
// { table: 2, pie_chart: 1, bar_chart: 0, timeseries_chart: 1,
// action: 0, markdown: 1, interactive: 0, alert: 0, code: 0, form: 0 }
}Complete Example: Response Lifecycle
Here is an end-to-end example showing the full lifecycle of inspecting a response -- from status checking through text extraction, block processing, and risk evaluation.
import {
Chaos,
WALLET_MODEL,
extractText,
extractBlocks,
extractTableBlocks,
extractChartBlocks,
extractTransactionBlocks,
tableToObjects,
hasRisks,
hasBlockers,
getAllWarnings,
getAllBlockers,
getHighestRiskLevel,
countBlocksByType,
} from '@chaoslabs/ai-sdk';
async function analyzeResponse() {
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: 'Deposit 5 ETH into Aave and show my updated positions.',
},
],
metadata: {
user_id: 'user-123',
session_id: 'session-abc',
wallets: [{ address: '0xABC...', chain: 'ethereum' }],
},
});
// Step 1: Check status
if (response.status === 'failed') {
console.error('Request failed:', response.error);
return;
}
console.log(`Response ${response.id} (model: ${response.model})`);
// Step 2: Extract and display text
const text = extractText(response);
if (text) {
console.log('\n--- AI Response ---');
console.log(text);
}
// Step 3: Summarize blocks
const counts = countBlocksByType(response);
console.log('\n--- Block Summary ---');
for (const [type, count] of Object.entries(counts)) {
if (count > 0) console.log(` ${type}: ${count}`);
}
// Step 4: Process tables
const tables = extractTableBlocks(response);
for (const table of tables) {
console.log(`\nTable: ${table.title ?? '(untitled)'}`);
const rows = tableToObjects(table);
console.table(rows);
}
// Step 5: Process charts
const charts = extractChartBlocks(response);
for (const chart of charts) {
console.log(`\nChart: ${chart.title ?? '(untitled)'} [${chart.type}]`);
}
// Step 6: Evaluate transaction risks
const txBlocks = extractTransactionBlocks(response);
if (txBlocks.length > 0) {
console.log(`\n--- Transactions (${txBlocks.length}) ---`);
console.log('Highest risk:', getHighestRiskLevel(response) ?? 'none');
if (hasBlockers(response)) {
console.log('\nBLOCKERS:');
for (const b of getAllBlockers(response)) {
console.log(` - ${b.title}: ${b.message}`);
}
} else if (hasRisks(response)) {
console.log('\nWARNINGS:');
for (const w of getAllWarnings(response)) {
console.log(` - ${w.title}: ${w.message}`);
}
} else {
console.log('Risk assessment: LOW -- safe to proceed');
}
}
}
analyzeResponse().catch(console.error);Quick Reference
| Function | Returns | Description |
|---|---|---|
extractText(response) | string | All text content joined by newlines |
extractBlocks(response) | Block[] | All blocks of any type |
extractTableBlocks(response) | TableBlock[] | Table blocks only |
extractChartBlocks(response) | ChartBlock[] | Pie, bar, and timeseries chart blocks |
extractTransactionBlocks(response) | ActionBlock[] | Transaction action blocks |
extractMarkdownBlocks(response) | MarkdownBlock[] | Markdown blocks |
extractInteractiveBlocks(response) | InteractiveBlock[] | Interactive blocks |
extractInfoBlocks(response) | AlertBlock[] | Alert/info blocks |
extractCodeBlocks(response) | CodeBlock[] | Code blocks |
extractFormBlocks(response) | FormBlock[] | Form blocks |
hasRisks(response) | boolean | Any transaction with risk above "low" |
hasBlockers(response) | boolean | Any transaction with high/critical risk or blockers |
getAllWarnings(response) | RiskInfoItem[] | All warnings across transactions |
getAllBlockers(response) | RiskInfoItem[] | All blockers across transactions |
getHighestRiskLevel(response) | RiskLevel | undefined | Highest risk: "low" | "medium" | "high" | "critical" |
countBlocksByType(response) | BlockTypeCounts | Count of each block type |
hasBlocks(response) | boolean | Whether the response contains any blocks |
hasBlockType(response, type) | boolean | Whether the response contains a specific block type |