> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/QwenLM/qwen-code/llms.txt
> Use this file to discover all available pages before exploring further.

# Message Types

> Understanding SDK message types and type guards

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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
import { isSDKAssistantMessage } from '@qwen-code/sdk';

if (isSDKAssistantMessage(message)) {
  // TypeScript knows message is SDKAssistantMessage
  console.log(message.message.model);
}
```

### Example Usage

```typescript theme={null}
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

<ResponseField name="type" type="'assistant'">
  Message type identifier.
</ResponseField>

<ResponseField name="uuid" type="string">
  Unique identifier for this message.
</ResponseField>

<ResponseField name="session_id" type="string">
  Session identifier.
</ResponseField>

<ResponseField name="message.id" type="string">
  API message ID.
</ResponseField>

<ResponseField name="message.model" type="string">
  Model used to generate this response (e.g., `'gpt-4'`, `'qwen-max'`).
</ResponseField>

<ResponseField name="message.content" type="ContentBlock[]">
  Array of content blocks. See [Content Blocks](#content-blocks) below.
</ResponseField>

<ResponseField name="message.stop_reason" type="string | null">
  Reason why generation stopped:

  * `'end_turn'`: Normal completion
  * `'max_tokens'`: Token limit reached
  * `'stop_sequence'`: Stop sequence encountered
</ResponseField>

<ResponseField name="message.usage" type="Usage">
  Token usage information:

  ```typescript theme={null}
  {
    input_tokens: number;
    output_tokens: number;
    cache_creation_input_tokens?: number;
    cache_read_input_tokens?: number;
  }
  ```
</ResponseField>

<ResponseField name="parent_tool_use_id" type="string | null">
  ID of the parent tool use, if this is a response to a tool invocation.
</ResponseField>

## SDKResultMessage

Indicates query completion with success or error information.

### Type Definition

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

<ResponseField name="is_error" type="boolean">
  Whether the query completed with an error.
</ResponseField>

<ResponseField name="subtype" type="string">
  Result subtype:

  * `'success'`: Query completed successfully
  * `'error_max_turns'`: Exceeded maximum turns
  * `'error_during_execution'`: Error during execution
</ResponseField>

<ResponseField name="duration_ms" type="number">
  Total duration of the query in milliseconds.
</ResponseField>

<ResponseField name="duration_api_ms" type="number">
  Time spent in API calls in milliseconds.
</ResponseField>

<ResponseField name="num_turns" type="number">
  Number of conversation turns executed.
</ResponseField>

<ResponseField name="result" type="string">
  Result message (only present when `is_error` is false).
</ResponseField>

<ResponseField name="usage" type="ExtendedUsage">
  Extended usage information including web search requests and cache metrics.
</ResponseField>

<ResponseField name="modelUsage" type="Record<string, ModelUsage>">
  Per-model usage breakdown.
</ResponseField>

<ResponseField name="permission_denials" type="CLIPermissionDenial[]">
  Array of tools that were denied permission during execution.
</ResponseField>

<ResponseField name="error" type="object">
  Error information (only present when `is_error` is true):

  ```typescript theme={null}
  {
    type?: string;
    message: string;
  }
  ```
</ResponseField>

## SDKSystemMessage

Provides session information and configuration.

### Type Definition

```typescript theme={null}
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

```typescript theme={null}
import { isSDKSystemMessage } from '@qwen-code/sdk';

if (isSDKSystemMessage(message)) {
  console.log('Session info:', message);
}
```

### Example Usage

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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:

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
import { isSDKPartialAssistantMessage } from '@qwen-code/sdk';

if (isSDKPartialAssistantMessage(message)) {
  // Handle streaming event
}
```

### Example Usage

```typescript theme={null}
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

<ResponseField name="message_start" type="MessageStartStreamEvent">
  Signals the start of a new message:

  ```typescript theme={null}
  {
    type: 'message_start';
    message: {
      id: string;
      role: 'assistant';
      model: string;
    };
  }
  ```
</ResponseField>

<ResponseField name="content_block_start" type="ContentBlockStartEvent">
  Signals the start of a new content block:

  ```typescript theme={null}
  {
    type: 'content_block_start';
    index: number;
    content_block: ContentBlock;
  }
  ```
</ResponseField>

<ResponseField name="content_block_delta" type="ContentBlockDeltaEvent">
  Incremental update to a content block:

  ```typescript theme={null}
  {
    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 }`
</ResponseField>

<ResponseField name="content_block_stop" type="ContentBlockStopEvent">
  Signals completion of a content block:

  ```typescript theme={null}
  {
    type: 'content_block_stop';
    index: number;
  }
  ```
</ResponseField>

<ResponseField name="message_stop" type="MessageStopStreamEvent">
  Signals completion of the entire message:

  ```typescript theme={null}
  {
    type: 'message_stop';
  }
  ```
</ResponseField>

## Content Blocks

Content blocks represent different types of content in messages:

### TextBlock

```typescript theme={null}
interface TextBlock {
  type: 'text';
  text: string;
  annotations?: Annotation[];
}
```

Plain text content from the assistant.

### ThinkingBlock

```typescript theme={null}
interface ThinkingBlock {
  type: 'thinking';
  thinking: string;
  signature?: string;
  annotations?: Annotation[];
}
```

Internal reasoning/thinking process of the AI.

### ToolUseBlock

```typescript theme={null}
interface ToolUseBlock {
  type: 'tool_use';
  id: string;
  name: string;
  input: unknown;
  annotations?: Annotation[];
}
```

Represents a tool being invoked.

### ToolResultBlock

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

* [query() Function](/sdk/api/query) - Create query sessions
* [Query Instance Methods](/sdk/api/query-instance) - Methods for controlling queries
* [Examples](/sdk/examples/single-turn) - Practical usage examples
