Skip to documentation
Documentation navigation

Documentation navigation

Documentation / guides

Traverse content safely

Traverse sealed messages and recursively inspect nested blocks without panics.

developer

The Conversation and Block interfaces are sealed, which makes explicit type switches the safe traversal pattern. Recursion is required for ToolResultBlock.Content, where images and other blocks may be nested inside a tool result.

Message traversal

func messageBlocks(m content.Conversation) []content.Block {
	switch typed := m.(type) {
	case *content.SystemMessage:
		return typed.Blocks
	case *content.UserMessage:
		return typed.Blocks
	case *content.AIMessage:
		return typed.Blocks
	case *content.ToolResultMessage:
		return typed.Blocks
	default:
		return nil
	}
}

The inference request validator uses this exhaustive enumeration to find image blocks. It also recursively descends into ToolResultBlock.Content; a shallow top-level scan would incorrectly admit an image nested in a tool result for a model that cannot process images.

Block traversal

func hasText(blocks []content.Block) bool {
	for _, block := range blocks {
		switch typed := block.(type) {
		case *content.TextBlock:
			if typed != nil && typed.Text != "" {
				return true
			}
		case *content.ToolResultBlock:
			if typed != nil && hasText(typed.Content) {
				return true
			}
		}
	}
	return false
}

Always guard typed pointers before dereferencing. A typed-nil payload can inhabit an interface and is rejected by MarshalBlock; traversal code should fail closed or skip it explicitly rather than panic.

Proof

Related: Conversation, ImageBlock, Feature validation.

← back to documentation