Skip to main content
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

type
'assistant'
Message type identifier.
uuid
string
Unique identifier for this message.
session_id
string
Session identifier.
message.id
string
API message ID.
message.model
string
Model used to generate this response (e.g., 'gpt-4', 'qwen-max').
message.content
ContentBlock[]
Array of content blocks. See Content Blocks below.
message.stop_reason
string | null
Reason why generation stopped:
  • 'end_turn': Normal completion
  • 'max_tokens': Token limit reached
  • 'stop_sequence': Stop sequence encountered
message.usage
Usage
Token usage information:
{
  input_tokens: number;
  output_tokens: number;
  cache_creation_input_tokens?: number;
  cache_read_input_tokens?: number;
}
parent_tool_use_id
string | null
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

is_error
boolean
Whether the query completed with an error.
subtype
string
Result subtype:
  • 'success': Query completed successfully
  • 'error_max_turns': Exceeded maximum turns
  • 'error_during_execution': Error during execution
duration_ms
number
Total duration of the query in milliseconds.
duration_api_ms
number
Time spent in API calls in milliseconds.
num_turns
number
Number of conversation turns executed.
result
string
Result message (only present when is_error is false).
usage
ExtendedUsage
Extended usage information including web search requests and cache metrics.
modelUsage
Record<string, ModelUsage>
Per-model usage breakdown.
permission_denials
CLIPermissionDenial[]
Array of tools that were denied permission during execution.
error
object
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

message_start
MessageStartStreamEvent
Signals the start of a new message:
{
  type: 'message_start';
  message: {
    id: string;
    role: 'assistant';
    model: string;
  };
}
content_block_start
ContentBlockStartEvent
Signals the start of a new content block:
{
  type: 'content_block_start';
  index: number;
  content_block: ContentBlock;
}
content_block_delta
ContentBlockDeltaEvent
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 }
content_block_stop
ContentBlockStopEvent
Signals completion of a content block:
{
  type: 'content_block_stop';
  index: number;
}
message_stop
MessageStopStreamEvent
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.

ToolUseBlock

interface ToolUseBlock {
  type: 'tool_use';
  id: string;
  name: string;
  input: unknown;
  annotations?: Annotation[];
}
Represents a tool being invoked.

ToolResultBlock

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