Message Parts
All message parts extend BasePart which provides a stable id: string. The ChatMessagePart union is the discriminated union of every part type below, keyed on the type field.
Part Types
| Type String | Interface | Key Fields | Description |
|---|---|---|---|
text | TextPart | text | Final assembled plain text. |
text-delta | TextDeltaPart | delta | Streaming text fragment. Accumulated into a TextPart on completion. |
markdown | MarkdownPart | markdown | Markdown-formatted content. |
citation | CitationPart | title, url, snippet? | Source citation with a link. |
suggestion-chips | SuggestionChipPart | chips[], payloadVersion? | Tappable suggestion chips. Each chip has label and optional value. |
product-carousel | ProductCarouselPart | products[], payloadVersion? | Horizontal product carousel. |
order-summary | OrderSummaryPart | orderId, items[], subtotal, total, payloadVersion? | Order summary with line items and totals. |
custom | CustomPayloadPart | payloadType, data, payloadVersion? | Arbitrary payload for app-specific rendering. |
tool-call | ToolCallPart | toolCallId, toolName, input, status, output?, error? | Agent-initiated tool invocation and its lifecycle. |
tool-result | ToolResultPart | toolCallId, toolName, output, error? | Result returned from a tool execution. |
file | FilePart | attachmentId?, fileName, mimeType, sizeBytes, url?, uploadStatus?, uploadProgress?, lifecycleStatus?, preview?, scanStatus? | Attached file with upload lifecycle metadata. File bytes are never stored in the part. |
agent-transfer | AgentTransferPart | status, targetAgent?, reason?, queuePosition?, estimatedWaitTime? | Live-agent handoff status. |
diagnostic | DiagnosticPart | category, message, details?, timestamp | Internal diagnostic event surfaced as a part. |
end-session | EndSessionPart | reason, message? | Session termination marker. |
error | ErrorPart | code, message, userMessage?, developerHint?, docsUrl?, retryable? | Structured error surfaced inline in the message stream. |
audio-input | AudioInputPart | mimeType, status, durationMs?, sampleRate?, channels?, url?, retained? | User-captured audio. status flows `capturing → completed |
audio-output | AudioOutputPart | mimeType, status, durationMs?, sampleRate?, url?, retained?, playedUpToMs? | Model-generated audio. status flows `streaming → completed |
transcript | TranscriptPart | role, text, interim, confidence?, language?, audioRefId? | STT output. Interim transcripts are replaced in place when finalized. |
audio-cue | AudioCuePart | cue, responseId?, metadata? | Side-channel voice signal (end-of-turn, barge-in, speech-started, silence-threshold-hit, session-ready, session-ended). |
vision | VisionPart | kind, mimeType, url?, data?, width?, height?, altText?, caption?, sizeBytes? | First-class image input or output. `kind: 'input' |
memory-approval | MemoryApprovalPart | operation, entryId?, payload, status | Long-term memory write awaiting user approval (save/update/delete). |
memory-recall-result | MemoryRecallResultPart | query?, entries[] | Result of a memory.recall tool call. |
sentiment-signal | SentimentSignalPart | category, score, confidence, polarity, source, latencyMs, attributedMessageId? | Sentiment classification, default sr-only renderer. |
intent-signal | IntentSignalPart | intent, score, confidence, source, latencyMs, attributedMessageId? | Inferred intent classification, default sr-only renderer. |
computer-use-surface | ComputerUseSurfacePart | sessionId, state, streamUrl?, actionLog[], error? | Sandboxed browser action stream. Default renderer is <ComputerUseSurface>. |
a2ui-surface | A2UISurfacePart | surfaceId, state, components, dataModel? | Agent-to-UI generative surface. |
ToolCallPart Status Values
| Status | Meaning |
|---|---|
requested | Server requested the tool call. |
awaiting_approval | Waiting for user/host approval. |
pending_supervisor | Waiting for a supervisor approval workflow. |
async_pending | Accepted for asynchronous server-side completion. |
approved | Approved, ready to execute. |
denied | User or policy denied the call. |
executing | Handler is running. |
completed | Execution succeeded. |
failed | Execution threw an error. |
timed_out | Execution exceeded timeoutMs. |
duplicate | Server replay protection detected a repeated idempotency key. |
Server actions may also attach idempotencyKey, duplicateDisposition, and
approvalPolicy to ToolCallPart so the UI can explain replay and approval
state without inspecting raw tool input.
FilePart Upload Status Values
uploadStatus is the coarse, backwards-compatible status. New attachment UIs should prefer lifecycleStatus when present.
| Status | Meaning |
|---|---|
pending | File selected, upload not started. |
uploading | Upload in progress (uploadProgress updates). |
completed | Upload succeeded, url is populated. |
failed | Upload failed. |
FilePart Lifecycle Values
| Lifecycle | Meaning |
|---|---|
selected | The user selected a file and the SDK created an attachment id. |
validating | MIME type, size, count, and customer policy checks are running. |
rejected | Validation failed before upload. |
queued | Validation passed and upload is queued. |
uploading | Bytes are being sent to the mock adapter, proxy route, or custom adapter. |
uploaded | Upload completed; scan or ready-to-send processing may still follow. |
scan_pending | A proxy scan hook is pending. The reference proxy uses a metadata-only fake hook by default. |
scan_failed | The scan hook rejected the attachment. |
ready_to_send | The SDK staged a typed file part for the next user turn. |
sent | The file part was included in a user message. |
failed | Upload failed after validation. Retry may be available. |
removed | The attachment was removed and will not be sent. |
preview contains safe metadata only: { kind, fileName, mimeType, sizeBytes }. It does not contain file contents, text snippets, HTML, base64, or object URLs. Host apps can render their own local previews, but debug bundles and message parts should stay metadata-only.
EndSessionPart Reason Values
| Reason | Meaning |
|---|---|
completed | Natural conversation end. |
timeout | Session timed out. |
error | Session ended due to an error. |
user_ended | User explicitly ended the session. |
agent_ended | Agent ended the session. |
handoff_completed | Handoff to a live agent completed. |
AudioInputPart Status Values
| Status | Meaning |
|---|---|
capturing | Mic is open and recording. |
completed | Capture finished, audio sent to provider. |
cancelled | Capture cancelled (push-to-talk released without speaking, etc.). |
failed | Capture failed (device error, permission revoked mid-session). |
AudioOutputPart Status Values
| Status | Meaning |
|---|---|
streaming | Provider is emitting audio frames. |
completed | Playback finished naturally. |
interrupted | Barge-in interrupted playback; playedUpToMs records the offset. |
AudioCuePart Cue Values
| Cue | Meaning |
|---|---|
session-ready | VoiceSession is open and listening. |
session-ended | VoiceSession is closing. |
speech-started | Provider VAD detected user speech (drives barge-in). |
silence-threshold-hit | VAD detected end of user speech. |
end-of-turn | Turn boundary (either explicit pushToTalk('release') or provider-detected). |
barge-in | Emitted by the SDK after the arbiter has interrupted an in-flight assistant turn. |
VisionPart Kind Values
| Kind | Meaning |
|---|---|
input | User-uploaded image attached to a user turn. |
output | Model-generated image returned in an assistant turn. |
Type Guards
Every part type has a corresponding type guard exported from gecx-chat:
import { isTextPart, isToolCallPart, isSuggestionChipsPart } from 'gecx-chat';
for (const part of message.parts) {
if (isTextPart(part)) { /* part is TextPart */ }
if (isToolCallPart(part)) { /* part is ToolCallPart */ }
}
Base set: isTextPart, isTextDeltaPart, isMarkdownPart, isCitationPart, isSuggestionChipsPart, isProductCarouselPart, isOrderSummaryPart, isCustomPayloadPart, isToolCallPart, isToolResultPart, isFilePart, isAgentTransferPart, isDiagnosticPart, isEndSessionPart, isErrorPart, isA2UISurfacePart.
Voice and multimodal: isAudioInputPart, isAudioOutputPart, isTranscriptPart, isAudioCuePart, isVisionPart.
Memory: isMemoryApprovalPart, isMemoryRecallResultPart.
Signals: isSentimentSignalPart, isIntentSignalPart, and a combined isSignalPart that matches either.
Computer-use: isComputerUseSurfacePart.
Builders
Factory functions for constructing parts without hand-rolling the shape:
import { textPart, chipsPart, toolCallPart } from 'gecx-chat';
const text = textPart('Hello');
const chips = chipsPart([{ label: 'Yes' }, { label: 'No' }]);
Available builders: textPart, markdownPart, citationPart, chipsPart, toolCallPart, toolResultPart, productCarouselPart, orderSummaryPart, errorPart, diagnosticPart, agentTransferPart, endSessionPart, filePart, customPart, plus voice builders (audioInputPart, audioOutputPart, transcriptPart, audioCuePart, visionPart), signal builders (sentimentSignalPart, intentSignalPart), and memoryApprovalPart / memoryRecallResultPart.
ChatMessage
The envelope that wraps an array of parts:
| Field | Type | Description |
|---|---|---|
id | string | Unique message identifier. |
role | 'user' | 'agent' | Message author. |
status | 'pending' | 'streaming' | 'completed' | 'error' | Current message lifecycle state. |
createdAt | string | ISO 8601 timestamp. |
sessionId | string | Owning session identifier. |
turnIndex | number | Zero-based turn index in the conversation. |
responseId | string? | Transport response identifier (agent messages). |
parts | ChatMessagePart[] | Ordered array of message parts. |
metadata | Record<string, unknown>? | Arbitrary metadata. |
rawResponse | { events: TransportEvent[] }? | Raw transport events (when preserveRawResponses is enabled). |
docs/reference/message-parts.md