The SDK emits different message types as the query progresses. Each message type provides specific information about the session state, AI responses, and execution results.
Message Type Overview
import {
isSDKUserMessage,
isSDKAssistantMessage,
isSDKSystemMessage,
isSDKResultMessage,
isSDKPartialAssistantMessage,
} from '@qwen-code/sdk';
for await (const message of result) {
if (isSDKAssistantMessage(message)) {
// Handle assistant message
} else if (isSDKResultMessage(message)) {
// Handle result message
} else if (isSDKSystemMessage(message)) {
// Handle system message
}
}
SDKAssistantMessage
Contains responses from the AI assistant.
Type Definition
interface SDKAssistantMessage {
type: 'assistant';
uuid: string;
session_id: string;
message: APIAssistantMessage;
parent_tool_use_id: string | null;
}
interface APIAssistantMessage {
id: string;
type: 'message';
role: 'assistant';
model: string;
content: ContentBlock[];
stop_reason?: string | null;
usage: Usage;
}
Type Guard
import { isSDKAssistantMessage } from '@qwen-code/sdk';
if (isSDKAssistantMessage(message)) {
// TypeScript knows message is SDKAssistantMessage
console.log(message.message.model);
}
Example Usage
for await (const message of result) {
if (isSDKAssistantMessage(message)) {
console.log('Model:', message.message.model);
console.log('Stop reason:', message.message.stop_reason);
// Process content blocks
for (const block of message.message.content) {
if (block.type === 'text') {
console.log('Text:', block.text);
} else if (block.type === 'thinking') {
console.log('Thinking:', block.thinking);
} else if (block.type === 'tool_use') {
console.log(`Tool: ${block.name}(${JSON.stringify(block.input)})`);
}
}
}
}
Fields
Unique identifier for this message.
Model used to generate this response (e.g., 'gpt-4', 'qwen-max').
Reason why generation stopped:
'end_turn': Normal completion
'max_tokens': Token limit reached
'stop_sequence': Stop sequence encountered
Token usage information:{
input_tokens: number;
output_tokens: number;
cache_creation_input_tokens?: number;
cache_read_input_tokens?: number;
}
ID of the parent tool use, if this is a response to a tool invocation.
SDKResultMessage
Indicates query completion with success or error information.
Type Definition
type SDKResultMessage = SDKResultMessageSuccess | SDKResultMessageError;
interface SDKResultMessageSuccess {
type: 'result';
subtype: 'success';
uuid: string;
session_id: string;
is_error: false;
duration_ms: number;
duration_api_ms: number;
num_turns: number;
result: string;
usage: ExtendedUsage;
modelUsage?: Record<string, ModelUsage>;
permission_denials: CLIPermissionDenial[];
}
interface SDKResultMessageError {
type: 'result';
subtype: 'error_max_turns' | 'error_during_execution';
uuid: string;
session_id: string;
is_error: true;
duration_ms: number;
duration_api_ms: number;
num_turns: number;
usage: ExtendedUsage;
modelUsage?: Record<string, ModelUsage>;
permission_denials: CLIPermissionDenial[];
error?: {
type?: string;
message: string;
};
}
Type Guard
import { isSDKResultMessage } from '@qwen-code/sdk';
if (isSDKResultMessage(message)) {
if (message.is_error) {
console.error('Error:', message.error);
} else {
console.log('Success:', message.result);
}
}
Example Usage
for await (const message of result) {
if (isSDKResultMessage(message)) {
console.log(`Completed in ${message.duration_ms}ms`);
console.log(`API time: ${message.duration_api_ms}ms`);
console.log(`Turns: ${message.num_turns}`);
console.log(`Total tokens: ${message.usage.input_tokens + message.usage.output_tokens}`);
if (message.is_error) {
console.error('Error type:', message.subtype);
console.error('Error message:', message.error?.message);
} else {
console.log('Result:', message.result);
}
if (message.permission_denials.length > 0) {
console.log('Permission denials:', message.permission_denials);
}
}
}
Fields
Whether the query completed with an error.
Result subtype:
'success': Query completed successfully
'error_max_turns': Exceeded maximum turns
'error_during_execution': Error during execution
Total duration of the query in milliseconds.
Time spent in API calls in milliseconds.
Number of conversation turns executed.
Result message (only present when is_error is false).
Extended usage information including web search requests and cache metrics.
modelUsage
Record<string, ModelUsage>
Per-model usage breakdown.
Array of tools that were denied permission during execution.
Error information (only present when is_error is true):{
type?: string;
message: string;
}
SDKSystemMessage
Provides session information and configuration.
Type Definition
interface SDKSystemMessage {
type: 'system';
subtype: string;
uuid: string;
session_id: string;
data?: unknown;
cwd?: string;
tools?: string[];
mcp_servers?: Array<{ name: string; status: string }>;
model?: string;
permission_mode?: string;
slash_commands?: string[];
qwen_code_version?: string;
output_style?: string;
agents?: string[];
skills?: string[];
capabilities?: Record<string, unknown>;
}
Type Guard
import { isSDKSystemMessage } from '@qwen-code/sdk';
if (isSDKSystemMessage(message)) {
console.log('Session info:', message);
}
Example Usage
for await (const message of result) {
if (isSDKSystemMessage(message)) {
console.log('Session ID:', message.session_id);
console.log('Working directory:', message.cwd);
console.log('Model:', message.model);
console.log('Permission mode:', message.permission_mode);
console.log('Available tools:', message.tools);
console.log('MCP servers:', message.mcp_servers);
console.log('Qwen Code version:', message.qwen_code_version);
}
}
SDKUserMessage
Represents a user message sent to the AI.
Type Definition
interface SDKUserMessage {
type: 'user';
uuid?: string;
session_id: string;
message: APIUserMessage;
parent_tool_use_id: string | null;
options?: Record<string, unknown>;
}
interface APIUserMessage {
role: 'user';
content: string | ContentBlock[];
}
Type Guard
import { isSDKUserMessage } from '@qwen-code/sdk';
if (isSDKUserMessage(message)) {
console.log('User message:', message.message.content);
}
Example Usage
You typically create these messages when using multi-turn conversations:
const userMessage: SDKUserMessage = {
type: 'user',
session_id: 'my-session',
message: {
role: 'user',
content: 'Create a hello.txt file',
},
parent_tool_use_id: null,
};
SDKPartialAssistantMessage
Streaming events emitted during message generation (when includePartialMessages: true).
Type Definition
interface SDKPartialAssistantMessage {
type: 'stream_event';
uuid: string;
session_id: string;
event: StreamEvent;
parent_tool_use_id: string | null;
}
type StreamEvent =
| MessageStartStreamEvent
| ContentBlockStartEvent
| ContentBlockDeltaEvent
| ContentBlockStopEvent
| MessageStopStreamEvent;
Type Guard
import { isSDKPartialAssistantMessage } from '@qwen-code/sdk';
if (isSDKPartialAssistantMessage(message)) {
// Handle streaming event
}
Example Usage
import { query, isSDKPartialAssistantMessage } from '@qwen-code/sdk';
const result = query({
prompt: 'Explain async/await',
options: { includePartialMessages: true },
});
for await (const message of result) {
if (isSDKPartialAssistantMessage(message)) {
const event = message.event;
if (event.type === 'message_start') {
console.log('Message started:', event.message.model);
} else if (event.type === 'content_block_start') {
console.log('Block started:', event.content_block.type);
} else if (event.type === 'content_block_delta') {
if (event.delta.type === 'text_delta') {
process.stdout.write(event.delta.text);
} else if (event.delta.type === 'thinking_delta') {
process.stdout.write(`[Thinking: ${event.delta.thinking}]`);
}
} else if (event.type === 'content_block_stop') {
console.log('\nBlock stopped at index:', event.index);
} else if (event.type === 'message_stop') {
console.log('Message complete');
}
}
}
Stream Event Types
Signals the start of a new message:{
type: 'message_start';
message: {
id: string;
role: 'assistant';
model: string;
};
}
Signals the start of a new content block:{
type: 'content_block_start';
index: number;
content_block: ContentBlock;
}
Incremental update to a content block:{
type: 'content_block_delta';
index: number;
delta: ContentBlockDelta;
}
Delta types:
{ type: 'text_delta', text: string }
{ type: 'thinking_delta', thinking: string }
{ type: 'input_json_delta', partial_json: string }
Signals completion of a content block:{
type: 'content_block_stop';
index: number;
}
Signals completion of the entire message:{
type: 'message_stop';
}
Content Blocks
Content blocks represent different types of content in messages:
TextBlock
interface TextBlock {
type: 'text';
text: string;
annotations?: Annotation[];
}
Plain text content from the assistant.
ThinkingBlock
interface ThinkingBlock {
type: 'thinking';
thinking: string;
signature?: string;
annotations?: Annotation[];
}
Internal reasoning/thinking process of the AI.
interface ToolUseBlock {
type: 'tool_use';
id: string;
name: string;
input: unknown;
annotations?: Annotation[];
}
Represents a tool being invoked.
interface ToolResultBlock {
type: 'tool_result';
tool_use_id: string;
content?: string | ContentBlock[];
is_error?: boolean;
annotations?: Annotation[];
}
Result from a tool execution.
Type Guards for Content Blocks
import {
isTextBlock,
isThinkingBlock,
isToolUseBlock,
isToolResultBlock,
} from '@qwen-code/sdk';
for (const block of message.message.content) {
if (isTextBlock(block)) {
console.log(block.text);
} else if (isThinkingBlock(block)) {
console.log('[Thinking]:', block.thinking);
} else if (isToolUseBlock(block)) {
console.log(`Tool: ${block.name}`);
} else if (isToolResultBlock(block)) {
console.log(`Result: ${block.content}`);
}
}
Complete Example
import {
query,
isSDKAssistantMessage,
isSDKResultMessage,
isSDKSystemMessage,
isSDKPartialAssistantMessage,
isTextBlock,
isThinkingBlock,
isToolUseBlock,
} from '@qwen-code/sdk';
const result = query({
prompt: 'List files in the current directory',
options: {
includePartialMessages: true,
},
});
for await (const message of result) {
if (isSDKSystemMessage(message)) {
console.log('Session started:', message.session_id);
console.log('Model:', message.model);
} else if (isSDKPartialAssistantMessage(message)) {
if (message.event.type === 'content_block_delta') {
if (message.event.delta.type === 'text_delta') {
process.stdout.write(message.event.delta.text);
}
}
} else if (isSDKAssistantMessage(message)) {
console.log('\n--- Complete Message ---');
for (const block of message.message.content) {
if (isTextBlock(block)) {
console.log('Text:', block.text);
} else if (isThinkingBlock(block)) {
console.log('Thinking:', block.thinking);
} else if (isToolUseBlock(block)) {
console.log(`Tool: ${block.name}(${JSON.stringify(block.input)})`);
}
}
} else if (isSDKResultMessage(message)) {
console.log('\n--- Result ---');
console.log('Duration:', message.duration_ms, 'ms');
console.log('Tokens:', message.usage.input_tokens + message.usage.output_tokens);
if (message.is_error) {
console.error('Error:', message.error?.message);
} else {
console.log('Success:', message.result);
}
}
}
See Also