Conversation Creation + Management
This guide covers the complete lifecycle of conversations in the Amigo platform, from creation and interaction to monitoring agent actions and system integration.
Conversation Lifecycle Overview
Creation: Initialize a new conversation with a service
Interaction: Exchange messages between user and agent
Monitoring: Track agent actions and dynamic behaviors
Integration: Connect with external systems based on conversation events
Termination: End conversations automatically or manually
Creating a New Conversation
To initiate a new conversation with a user:
Equivalent TypeScript / Node 18+ example (re‑uses the parseNdjsonStream
helper defined later in this document):
It will include several event types as denoted by the type
field:
ConversationCreatedEvent
conversation-created
Provides the conversation_id
and confirms successful creation
ErrorEvent
error
Indicates an internal error occurred. When this happens, none of the messages/artifacts in this interaction persist, and the entire API call is rolled back.
NewMessageEvent
new-message
Contains message chunks (text or voice based on parameters).
InteractionCompleteEvent
interaction-complete
Signals successful stream completion.
CurrentAgentActionEvent
current-agent-action
Only emitted if the emit_current_agent_action_event
query parameter is set to True
. Describes the action the agent's taking to produce the response.
Understanding the agent's actions:
You can use the CurrentAgentActionEvent
to understand the agent's actions as it's generating the response. The event follows the schema below:
You can use the below endpoint to retrieve dynamic behavior set versions:
You can use the below endpoint to compute metrics:
Important Conversation Management Rules
A user cannot have multiple active conversations for the same service
The
conversation_id
must be stored and used for all subsequent interactionsThe conversation object should be persisted for at least the duration of the active session
Interacting with a Conversation
After creating a conversation, you can send user messages:
Request Format
The request body must use
multipart/form-data
formatInclude a single form field named
recorded_message
containing UTF-8 encoded textThe body can be sent as a stream to reduce latency, as processing begins as soon as chunks are received
The response takes the form of a body stream:
Response Stream Events
UserMessageAvailableEvent
user-message-available
First event in response, includes the user message if sent as text.
ErrorEvent
error
Indicates an internal error occurred. When this happens, none of the messages/artifacts in this interaction persist, and the entire API call is rolled back.
InteractionCompleteEvent
interaction-complete
Signals the interaction is complete.
EndSessionEvent
end-session
Optional event if conversation automatically ends.
CurrentAgentActionEvent
current-agent-action
Only emitted if the emit_current_agent_action_event
query parameter is set to True
. Describes the action the agent's taking to produce the response.
How to Consume the application/x‑ndjson
Stream
application/x‑ndjson
Stream/conversation/{conversation_id}/interact
returns an ND‑JSON stream (one JSON object per line, ‑separated).
The server keeps the underlying HTTP/2 connection open after the last event of a turn so that you can immediately begin the next turn without paying the cost of a new TLS/TCP handshake. Do not wait for the socket to close—instead, decide in your client logic when you are done processing a turn.
The final event of every successful turn is always:
interaction-complete
– the agent finished speaking/thinking for this user turn.
If the conversation is over (for example the agent decides to end‑session) you will also receive:
end-session
Once you have seen one of those events you can safely stop listening, cancel the stream, or start the next request on the same connection.
Below is a minimal Node 18+ example (TypeScript/JavaScript) that shows the correct pattern. The helper parseNdjsonStream()
is reproduced in full below so you can copy‑paste without pulling in any external dependencies.
Adding a Hard Timeout (Optional)
If you want to guarantee that your UI never waits more than N seconds for a turn to complete, wrap the fetch in an AbortController
:
If the controller aborts, fetch()
rejects with DOMException: AbortError
; show an appropriate error to the user and offer a retry.
Tips & Gotchas
Always set
Accept: application/x-ndjson
when you expect a text response stream. • If you setresponse_format=voice
, useAccept: audio/mpeg
(MP3) orAccept: audio/wav
accordingly.The connection staying open is not a timeout. It is normal HTTP/2 behaviour. Abort the request yourself (e.g. via
AbortController
) if you want a hard upper bound.If you plan to send the next user message immediately, you can keep the connection open and reuse it – simply start another
/interact
request.
Voice‑Note (≠ Voice‑to‑Voice) Interactions
Amigo currently supports voice notes: you send audio, the agent responds with synthesised audio.
It is not a full duplex "voice‑to‑voice" phone call. Treat each /interact
turn as an async voice note exchange:
Encode the user's recording as a WAV or FLAC fragment.
POST it as the
recorded_message
form field withrequest_format=voice
.Set
response_format=voice
and choose anAccept
header: •audio/mpeg
→ MP3, most efficient for mobile play‑back. •audio/wav
→ uncompressed PCM, lowest latency for small clips.Parse the ND‑JSON events exactly as for text—
new-message
contains base‑64 audio chunks—and play them back in order.
Example (browser / React Native):
Because each request/response represents one voice note, you can easily build push‑to‑talk or walkie‑talkie style UX while re‑using the same streaming infrastructure described above.
Quick‑Start Checklist (Keep This Handy!)
🟢 Before You Hit Send
Have you set all three required headers? •
Authorization: Bearer <JWT>
•Accept: application/x-ndjson
(oraudio/*
) •Content‑Type
handled automatically byFormData
, do not hard‑codemultipart/form-data; boundary=...
yourself.Is the query‑string correct?
request_format=text|voice
andresponse_format=text|voice
must match the formats you actually send/expect.Are you waiting for
interaction-complete
, not for the socket to close? An open HTTP/2 connection ≠ timeout.Did you remember that one user = one active conversation per service? Handle the "already started" error by resuming or finishing the existing conversation.
🟡 Troubleshooting
• error
event received
Log the full event. 2. Fix the request. 3. Retry the entire turn—the server has already rolled it back.
• HTTP 415 / 406 → Your Accept
or Content‑Type
is wrong.
• Stream seems silent → Are you parsing per‑line? The first bytes might be small; buffer until you hit .
🛑 Never
• Never assume the transport will close on success. • Never create a new conversation when one is still active—finish or resume instead.
Common Integration Patterns (Straight from amigo‑examples)
1. Fire‑and‑forget Notification
You only care about the agent's final reply; intermediate new-message
chunks are ignored.
2. Real‑time "Type‑as‑you‑stream" UI
3. Server‑Side Relay (Backend collects, then pushes to client)
Useful when the browser environment cannot (yet) consume streaming fetches—your backend remains the only component that needs the Amigo secret.
4. Finishing Idle Conversations Automatically
Keeps your database clean and avoids users hitting the "already in a conversation" error weeks later.
Conversation Lifecycle Management
Understanding Conversation States
Started: Conversation is active and can receive interactions
Finished: Conversation has ended and cannot receive further interactions
Automatic vs. Manual Finish
A conversation can finish in two ways:
Automatically: When the service determines the conversation should finish (based on user intent, service completion, etc.)
Manually: When explicitly ended via the finish conversation API (e.g. due to timeout or user action)
Finishing a Conversation
To manually finish a conversation:
Important: This endpoint should only be called:
On started, non-finished conversations
After previous conversation API calls have completed
When the conversation hasn't automatically finished during interaction
When a conversation finishes, post-conversation analysis is initiated asynchronously (memory generation, user model updates, etc.).
Managing "Dangling" Conversations
Conversations never time out automatically. You have several options for handling inactive conversations:
Timeout Approach: Track user's last interaction time and call the finish endpoint after a defined period
Caution: This may terminate conversations users intend to continue
Resume Option (Recommended): When a user returns, offer options to:
Resume the existing conversation
Start a new conversation (which requires ending the current one)
Error Handling: If your application attempts to create a new conversation while one is active:
Catch the error response
Prompt the user to either resume or end the existing conversation
The Amigo system prevents users from having multiple ongoing conversations of the same service type, ensuring conversation integrity.
Last updated
Was this helpful?