Communication and Message Architecture
1. Core Principles
The communication architecture in VibeX is a critical component that enables the transparent, real-time feedback loop at the heart of the Vibe-X philosophy. It is designed to be robust, extensible, and streamable, drawing inspiration from modern standards like the Vercel AI SDK. The core principles are:
- Message-Oriented: The fundamental unit of communication is a
XMessage. All interactions, whether from a user, an agent, or a tool, are encapsulated in this structure. - Composable Parts: A
XMessageis composed of a list ofXMessagePartobjects. This allows for rich, multi-modal content and a clear separation of concerns (e.g., text, tool calls, and tool results all have their own part type). - Streaming First: The entire model is designed for real-time streaming. A message and its parts can be sent incrementally, allowing for responsive user interfaces and efficient data flow.
2. The Message and Part Schema
This section defines the core data structures for communication.
2.1. The XMessage Object
A XMessage represents a single entry in the conversation history. It contains a list of XMessagePart objects that make up its content.
import type { XMessagePart } from "@vibex/core";
interface XMessage {
id: string;
role: "system" | "user" | "assistant" | "tool" | "data";
parts: XMessagePart[];
metadata?: {
agentName?: string;
timestamp?: number;
[key: string]: unknown;
};
content?: string; // Optional for backward compatibility
}2.2. The Part Objects
These are the building blocks of a XMessage. Following the AI SDK pattern, we use a union type for all possible part types.
TextPart
The simplest part, containing a piece of text. During streaming, multiple TextPart objects can be sent to represent a continuous flow of text.
interface TextPart {
type: "text";
text: string;
}ToolCallPart
A structured request from an agent to call a specific tool with a given set of arguments.
interface ToolCallPart {
type: "tool-call";
toolCallId: string;
toolName: string;
args: Record<string, unknown>;
}ToolResultPart
The result of a tool execution. It is explicitly linked back to the originating call by its toolCallId.
interface ToolResultPart {
type: "tool-result";
toolCallId: string;
toolName: string;
result: unknown;
isError?: boolean;
}Extended Part Types
Beyond the core types, VibeX supports additional part types for richer agent interactions:
// For reasoning transparency
interface ReasoningPart {
type: "reasoning";
content: string;
}
// For file attachments
interface FilePart {
type: "file";
data: string | Uint8Array;
mimeType: string;
}
// For multi-step operations
interface StepStartPart {
type: "step-start";
stepId: string;
stepName?: string;
}
// VibeX-specific: Artifact references
interface ArtifactPart {
type: "artifact";
artifactId: string;
title: string;
version?: number;
preview?: string;
}
// VibeX-specific: Plan updates
interface PlanUpdatePart {
type: "plan-update";
planId: string;
action: "created" | "updated" | "completed" | "failed";
details?: Record<string, unknown>;
}3. Example Message Flows
3.1. Simple Text Conversation
User Message:
{
"role": "user",
"parts": [{ "type": "text", "text": "Hello, world!" }]
}Assistant Response (streamed):
// Stream Packet 1
{ "role": "assistant", "parts": [{ "type": "text", "text": "Hello" }] }
// Stream Packet 2
{ "role": "assistant", "parts": [{ "type": "text", "text": " there!" }] }3.2. Successful Tool Call Flow
This example shows the full lifecycle, from the agent requesting a tool to receiving the result.
1. Assistant requests a tool call:
The agent’s message contains both explanatory text and a ToolCallPart.
{
"role": "assistant",
"parts": [
{
"type": "text",
"text": "Sure, I can write that file for you. I will now call the tool."
},
{
"type": "tool-call",
"toolCallId": "tc_123",
"toolName": "write_file",
"args": { "path": "/hello.txt", "content": "Hello, world!" }
}
]
}2. The system provides the tool result:
A new message is created containing the ToolResultPart. This is sent back to the agent for its next reasoning step.
{
"role": "assistant",
"parts": [
{
"type": "tool-result",
"toolCallId": "tc_123",
"toolName": "write_file",
"result": {
"status": "success",
"message": "File written successfully."
},
"isError": false
}
]
}3. The agent generates its final response: After receiving the result, the agent formulates its final answer.
{
"role": "assistant",
"parts": [
{
"type": "text",
"text": "I have successfully written the file to `/hello.txt`."
}
]
}4. Streaming and Progressive Responses
To build a truly responsive UI, a client needs to be aware of the agent’s progress throughout its turn, not just at the end. This is especially important for multi-step operations like tool calls. VibeX achieves this by streaming a sequence of message updates for a single logical turn.
4.1. The Streaming Protocol
The client should not assume a single request will yield a single response. Instead, it should be prepared to receive multiple, distinct message objects over the same streaming connection. Each object provides a real-time snapshot of the agent’s activity.
5. Frontend State Management
The frontend maintains a streaming message state that progressively builds the UI using @vibex/react:
import { useXChat, type XChatMessage } from "@vibex/react";
function Chat({ spaceId }: { spaceId: string }) {
const {
messages,
input,
setInput,
append,
isLoading,
status,
} = useXChat({
spaceId,
});
// Messages are automatically updated as they stream
// Status provides granular loading states: "idle" | "streaming" | "awaiting-approval"
return (
<div>
{messages.map((msg) => (
<MessageRenderer key={msg.id} message={msg} />
))}
</div>
);
}
// Render message parts
function MessageRenderer({ message }: { message: XChatMessage }) {
return (
<div>
{message.parts.map((part, idx) => {
switch (part.type) {
case "text":
return <p key={idx}>{part.text}</p>;
case "tool-call":
return <ToolCallDisplay key={idx} toolCall={part} />;
case "tool-result":
return <ToolResultDisplay key={idx} result={part} />;
case "artifact":
return <ArtifactPreview key={idx} artifact={part} />;
default:
return null;
}
})}
</div>
);
}6. Benefits of This Architecture
- Progressive Rendering: UI updates smoothly as content streams
- Structured Data: Maintains proper message/part relationships
- Tool Transparency: Shows tool calls and results inline with text
- Error Recovery: Failed tool calls don’t break the message flow
- Multi-modal Support: Easily extends to images, files, and other content types
- Backward Compatible: The
contentfield provides plain text fallback - Type Safety: Full TypeScript types for all message structures
This architecture ensures that every piece of agent activity is captured, structured, and communicated in real-time, embodying the Vibe-X philosophy of transparency and user empowerment.