Text Chat
Send text messages and render streaming responses from an Estuary character.
Sending a Message
Call Send Text on a character's UEstuaryCharacterComponent. It returns a message_id you can use to correlate the streaming response.
FString MessageId = CharacterComponent->SendText(TEXT("Tell me about the ocean."));
In Blueprint: drag from the Character Component, call Send Text, and store the returned Message Id if you want to correlate or interrupt later.
The message must be non-empty for the server to respond.
Receiving Streaming Responses
Responses stream back in chunks. Bind On Bot Response and accumulate the text until bIsFinal is true.
void AMyActor::BeginPlay()
{
Super::BeginPlay();
CharacterComponent->OnBotResponse.AddDynamic(this, &AMyActor::HandleResponse);
}
void AMyActor::HandleResponse(const FEstuaryBotResponse& Response)
{
// Append each delta chunk to build the full reply
AccumulatedText += Response.Text;
if (Response.bIsFinal)
{
UE_LOG(LogTemp, Log, TEXT("Character said: %s"), *AccumulatedText);
AccumulatedText.Reset();
}
}
Bot response fields
| Field | Type | Description |
|---|---|---|
Text | string | The delta text for this chunk. Concatenate across chunks. |
MessageId | string | Matches the message_id returned by SendText. |
ChunkIndex | int | 0-based chunk counter (-1 when not provided). |
bIsFinal | bool | true on the final chunk — no more chunks for this message follow. |
bIsInterjection | bool | true for a backchannel/interjection rather than a direct answer. |
:::tip Streaming UI
Update your on-screen text on every chunk for a live "typing" effect, and treat bIsFinal as the cue to commit the message to your chat history and re-enable the input field.
:::
Text-Only Mode
By default the server also generates spoken audio (bot_voice). To get text without TTS audio — for a silent chat UI — there are two ways:
- Say Line with
bTextOnly = true(for scripted lines, below). - For user turns, the text-only flag lives on the lower-level
FEstuaryUserTextpayload; if you don't attach an audio player component, audio chunks are simply ignored.
Scripted Lines (Say Line)
Say Line makes the character speak a prewritten line via TTS, skipping the LLM entirely. Use it for greetings, tutorials, or any moment you want exact words.
CharacterComponent->SayLine(TEXT("Welcome to the demo!"), /*bTextOnly=*/false);
Differences from SendText:
- The server auto-interrupts any in-flight response first.
- The server mints its own
message_id—SayLinereturns nothing. The reply still arrives throughOnBotResponse/OnBotVoicewith that server-generated ID. - The line is saved to conversation history as something the character naturally said.
Set bTextOnly = true to get only the text back with no spoken audio.
Interrupting a Response
Call Interrupt to abort the response that is currently streaming. The component targets its most recent message automatically.
CharacterComponent->Interrupt();
After interrupting:
OnBotResponsechunks for the interrupted message stop arriving.- The server sends an acknowledgement, firing On Interrupt Acked with a
Reason.
Interrupt is a no-op if there is no active turn.
void AMyActor::HandleInterruptAck(const FEstuaryInterruptPayload& Payload)
{
UE_LOG(LogTemp, Log, TEXT("Interrupted: %s"), *Payload.Reason);
}
Updating Preferences
Adjust session-level behavior flags with Update Preferences. Changes apply to subsequent responses in the same session.
FEstuaryPreferences Prefs;
Prefs.bEnableVisionAcknowledgment = true; // bot verbally acknowledges what it sees
CharacterComponent->UpdatePreferences(Prefs);
For preference keys not yet exposed as explicit fields, use the ExtraPreferences map as a forward-compatible key/value bag.
Memory Updates
After a conversation ends, the server may extract long-term memories in the background and push them to the client. Bind On Memory Updated on the subsystem:
Estuary->OnMemoryUpdated.AddDynamic(this, &AMyActor::HandleMemory);
void AMyActor::HandleMemory(const FEstuaryMemoryUpdated& Update)
{
UE_LOG(LogTemp, Log, TEXT("%d new memories extracted"), Update.MemoriesExtracted);
for (const FEstuaryMemoryData& Mem : Update.NewMemories)
{
UE_LOG(LogTemp, Log, TEXT(" [%s] %s"), *Mem.MemoryType, *Mem.Content);
}
}
See Data Models for the full memory schema.
Multi-Character Scenes
You can place several AEstuaryCharacter actors with different Character IDs. Each registers independently with the subsystem and receives only its own response stream — there is no cross-talk. The active conversation is with the character ID used in Connect; the others coexist without interfering.
Next Steps
- Voice Connection — Add speech input and TTS output
- Vision — Let the character see and describe images
- API Reference: Character Components