Skip to content

Message Roles

AIDK supports five message roles, each with specific semantics for how they're handled by models and rendered in context.

Role Overview

RoleSourcePurposePersisted?
userHuman/clientUser messages to the modelYes
assistantModel outputModel-generated responsesYes
systemDeveloperInstructions, role definitionYes
toolTool executorTool execution resultsYes
eventApplicationUser actions, state changesYes

User Messages

Messages from the human user or client application.

tsx
<Message role="user">
  What's the weather like today?
</Message>

// Or with content blocks
<Message role="user" content={[
  { type: 'text', text: 'Analyze this image:' },
  { type: 'image', source: { type: 'url', url: 'https://...' } }
]} />

Characteristics:

  • Always visible to the model
  • Typically the conversation driver
  • Can contain text, images, audio, documents

Assistant Messages

Messages generated by the AI model.

tsx
<Message role="assistant">
  The weather today is sunny with a high of 72°F.
</Message>

// With tool calls
<Message role="assistant" content={[
  { type: 'text', text: 'Let me check that for you.' },
  { type: 'tool_use', id: 'call_123', name: 'get_weather', input: { city: 'SF' } }
]} />

Characteristics:

  • Generated by model, not authored by you
  • May contain tool calls (tool_use blocks)
  • Accumulated in timeline after each tick

System Messages

Instructions and behavioral configuration for the model.

tsx
<System>
  You are a helpful customer support agent for TechCorp.
  Always be professional and concise.
</System>

// Or explicit Message
<Message role="system">
  Respond only in JSON format.
</Message>

Characteristics:

  • Typically at the start of the conversation
  • Sets the model's behavior and constraints
  • Multiple system messages are consolidated
  • Content from <Section> components becomes system message content

Tool Messages

Results from tool/function executions.

tsx
<Message role="tool" content={[
  {
    type: 'tool_result',
    toolUseId: 'call_123',
    content: [{ type: 'text', text: '{"temp": 72, "condition": "sunny"}' }]
  }
]} />

Characteristics:

  • Always paired with a tool_use in an assistant message
  • Contains tool_result content blocks
  • toolUseId must match the corresponding tool_use.id
  • Automatically generated by the engine after tool execution

Event Messages

Application events like user actions, state changes, or system notifications.

tsx
<Message role="event" content={[
  { type: 'user_action', action: 'clicked_button', target: 'submit' }
]} />

// Using the Event component
<Event>
  <UserAction action="uploaded_file" target="document.pdf" />
</Event>

Characteristics:

  • Represents application-level events, not conversational turns
  • Contains event-specific content blocks (user_action, etc.)
  • Transformed for models that don't natively support events

Event Content Blocks

tsx
// User action
{ type: 'user_action', action: 'clicked', target: 'buy_button' }

// State change
{ type: 'state_change', key: 'cart.items', from: 2, to: 3 }

// System event
{ type: 'system_event', event: 'session_timeout', data: { reason: 'inactivity' } }

Model Handling

Different models handle roles differently:

Standard Roles

Most models natively support user, assistant, system, and tool:

tsx
// These map directly to model APIs
<Message role="user">Hello</Message>       // → user message
<Message role="assistant">Hi!</Message>    // → assistant message
<Message role="system">Be helpful</Message> // → system message
<Message role="tool">...</Message>          // → tool result

Event Role Transformation

The event role isn't natively supported by most models. AIDK transforms it:

tsx
// Your code
<Event>
  <UserAction action="clicked" target="help_button" />
</Event>

// Transformed for model (example)
// Becomes a user message with event delimiters:
// <event type="user_action">
//   User clicked: help_button
// </event>

The exact transformation is configurable via messageTransformation in model options.

Role Mapping Configuration

Different providers support different roles. AIDK's MessageTransformationConfig controls how non-standard roles are mapped:

typescript
messageTransformation: {
  roleMapping: {
    /**
     * Role for event messages:
     * - 'user': Most compatible (default)
     * - 'developer': Use developer role (Claude, newer OpenAI)
     * - 'system': Treat as system context
     */
    event: 'user' | 'developer' | 'system',

    /**
     * Role for ephemeral content (Grounding, Ephemeral):
     * - 'user': Most compatible (default)
     * - 'developer': Use developer role (Claude, newer OpenAI)
     * - 'system': Treat as system context
     */
    ephemeral: 'user' | 'developer' | 'system',
  },
}

Provider-Specific Defaults

ProviderEvent RoleEphemeral RoleNotes
Anthropic ClaudedeveloperdeveloperNative developer role support
OpenAI GPT-4+developerdeveloperNewer models support developer role
OpenAI GPT-3.5useruserUse user role fallback
Google GeminiuseruserUse user role

Configuring Role Mapping

Per-model configuration:

typescript
const model = createLanguageModel({
  metadata: {
    id: 'claude-3',
    capabilities: [{
      messageTransformation: {
        roleMapping: {
          event: 'developer',
          ephemeral: 'developer',
        },
      },
    }],
  },
  // ...
});

Dynamic configuration based on provider:

typescript
messageTransformation: (modelId: string, provider?: string) => ({
  roleMapping: {
    event: provider === 'anthropic' ? 'developer' : 'user',
    ephemeral: provider === 'anthropic' ? 'developer' : 'user',
  },
})

Per-request override:

typescript
const result = await model.generate.call({
  messages: [...],
  messageTransformation: {
    roleMapping: { event: 'user' },  // Override for this request
  },
});

JSX Components for Messages

Message Component

tsx
import { Message } from 'aidk';

// String content
<Message role="user">Hello!</Message>

// Content blocks
<Message
  role="assistant"
  content={[{ type: 'text', text: 'Hi there!' }]}
/>

// With metadata
<Message
  role="user"
  id="msg-123"
  metadata={{ source: 'web' }}
>
  Hello!
</Message>

Role-Specific Components

tsx
import { User, Assistant, System, Event } from 'aidk';

// Shorthand components
<User>Hello!</User>
<Assistant>Hi there!</Assistant>
<System>You are helpful.</System>
<Event><UserAction action="clicked" target="button" /></Event>

Timeline Component

tsx
<Timeline>
  <System>You are a helpful assistant.</System>
  <User>What's 2+2?</User>
  <Assistant>2+2 equals 4.</Assistant>
  <User>Thanks!</User>
</Timeline>

Content Block Types

Messages contain content blocks. Common types:

Block TypeUsed InPurpose
textAll rolesPlain text content
imageuser, assistantImage content
audiouser, assistantAudio content
documentuserPDF, documents
tool_useassistantTool call request
tool_resulttoolTool execution result
user_actioneventUser interaction
state_changeeventState update
system_eventeventSystem notification
tsx
interface ContentBlock {
  type: 'text' | 'image' | 'audio' | 'tool_use' | 'tool_result' | ...;
  // Type-specific fields
}

Best Practices

1. Use Semantic Components

tsx
// Good: Semantic intent clear
<System>You are a helpful assistant.</System>
<User>{userInput}</User>

// Less good: Generic message
<Message role="system">You are a helpful assistant.</Message>

2. Don't Manually Create Assistant Messages

tsx
// Bad: Creating assistant messages yourself
<Assistant>I'll help you with that.</Assistant>

// Good: Let the model generate responses
// Assistant messages come from model output

3. Use Events for Non-Conversational Actions

tsx
// Good: Event for UI action
<Event>
  <UserAction action="selected_product" target={productId} />
</Event>

// Less good: User message for non-conversational action
<User>I selected product {productId}</User>

4. Consolidate System Instructions

tsx
// Good: Single system message with sections
<System>
  <Section id="role">You are a customer support agent.</Section>
  <Section id="rules">Never promise refunds.</Section>
</System>

// Less good: Multiple system messages
<System>You are a customer support agent.</System>
<System>Never promise refunds.</System>

Released under the MIT License.