# Text Stream WebSocket

The text-stream WebSocket provides a real-time bidirectional channel for text-based agent conversations. After connecting, the server pushes typed JSON frames representing session lifecycle events, agent messages, and (optionally) tool call activity.

## Connection

Connect to the text-stream WebSocket endpoint for your workspace and service. The connection accepts optional query parameters:

| Parameter         | Type    | Required | Description                                                                                              |
| ----------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------- |
| `conversation_id` | string  | No       | Resume an existing conversation. If omitted, a new conversation is created.                              |
| `tool_events`     | boolean | No       | When `true`, the server emits `tool_call_started` and `tool_call_completed` frames. Defaults to `false`. |

## Frame Format

Every frame is a JSON object with a `type` field that identifies the frame variant. All fields are at the top level of the object - there is no nested `data` envelope.

```json
{"type": "message", "role": "agent", "text": "Hello, how can I help?"}
```

This flat format differs from the voice observer WebSocket, which nests payload fields inside a `data` object. If you integrate with both endpoints, handle the envelope difference explicitly.

## Frame Types

### Lifecycle Frames

These frames are always emitted.

#### `session_started`

First frame after the WebSocket handshake completes.

| Field             | Type   | Description                                                             |
| ----------------- | ------ | ----------------------------------------------------------------------- |
| `type`            | string | `"session_started"`                                                     |
| `session_id`      | string | Server-assigned session identifier                                      |
| `conversation_id` | string | The conversation ID (newly created or the one supplied via query param) |

#### `session_ended`

Graceful end of conversation.

| Field    | Type   | Description                                                                        |
| -------- | ------ | ---------------------------------------------------------------------------------- |
| `type`   | string | `"session_ended"`                                                                  |
| `reason` | string | Completion reason: `stopped`, `completed`, `escalated`, `disconnected`, or `other` |

#### `error`

Recoverable error mid-session. The connection may remain open. Terminal errors close the WebSocket with a status code.

| Field     | Type   | Description                      |
| --------- | ------ | -------------------------------- |
| `type`    | string | `"error"`                        |
| `message` | string | Human-readable error description |

#### `ping`

Keepalive frame. Reset your dead-socket watchdog and otherwise ignore it.

| Field  | Type   | Description |
| ------ | ------ | ----------- |
| `type` | string | `"ping"`    |

#### `typing`

Indicates the agent is preparing a response. Pure UX hint with no additional payload.

| Field  | Type   | Description |
| ------ | ------ | ----------- |
| `type` | string | `"typing"`  |

#### `response_complete`

Marks the end of an agent turn. The next user message can be sent after receiving this frame.

| Field       | Type    | Description                                                                                 |
| ----------- | ------- | ------------------------------------------------------------------------------------------- |
| `type`      | string  | `"response_complete"`                                                                       |
| `duplicate` | boolean | `true` if the server suppressed a repeated response (idempotent send). Defaults to `false`. |

#### `message`

Final consolidated agent message for a turn.

| Field  | Type   | Description                                     |
| ------ | ------ | ----------------------------------------------- |
| `type` | string | `"message"`                                     |
| `role` | string | The message author. Currently always `"agent"`. |
| `text` | string | The agent's response text                       |

### Tool Call Frames

These frames are only emitted when the `tool_events=true` query parameter is set. Both frames arrive after the tool has already executed - they are post-hoc summaries, not real-time progress events.

#### `tool_call_started`

| Field       | Type                    | Description                                                              |
| ----------- | ----------------------- | ------------------------------------------------------------------------ |
| `type`      | string                  | `"tool_call_started"`                                                    |
| `tool_name` | string                  | Name of the tool that was invoked                                        |
| `call_id`   | string                  | Unique identifier for this tool call                                     |
| `input`     | object, string, or null | The input passed to the tool. Format depends on the tool's input schema. |

#### `tool_call_completed`

| Field       | Type    | Description                                                                          |
| ----------- | ------- | ------------------------------------------------------------------------------------ |
| `type`      | string  | `"tool_call_completed"`                                                              |
| `tool_name` | string  | Name of the tool that was invoked                                                    |
| `call_id`   | string  | Unique identifier for this tool call (matches the corresponding `tool_call_started`) |
| `result`    | string  | The tool's stringified output                                                        |
| `succeeded` | boolean | Whether the tool returned successfully. Defaults to `true`.                          |

## Forward Compatibility

The server may add new frame types in future releases. Consumers that encounter an unknown `type` value should drop the frame and continue processing. Treating unknown types as errors will cause unnecessary failures when new frame variants are introduced.

## Example Session

```
<- {"type": "session_started", "session_id": "ss_abc123", "conversation_id": "conv_def456"}
-> {"text": "Hi, I need to reschedule my appointment"}
<- {"type": "typing"}
<- {"type": "message", "role": "agent", "text": "I can help with that. What date works for you?"}
<- {"type": "response_complete", "duplicate": false}
-> {"text": "Next Tuesday"}
<- {"type": "typing"}
<- {"type": "tool_call_started", "tool_name": "check_availability", "call_id": "tc_789", "input": {"date": "2026-07-15"}}
<- {"type": "tool_call_completed", "tool_name": "check_availability", "call_id": "tc_789", "result": "{\"slots\": [\"9:00 AM\", \"2:00 PM\"]}", "succeeded": true}
<- {"type": "message", "role": "agent", "text": "I have openings at 9:00 AM and 2:00 PM next Tuesday. Which works better?"}
<- {"type": "response_complete", "duplicate": false}
-> {"text": "9 AM please"}
<- {"type": "typing"}
<- {"type": "message", "role": "agent", "text": "Done - you are rescheduled for Tuesday at 9:00 AM."}
<- {"type": "response_complete", "duplicate": false}
<- {"type": "session_ended", "reason": "completed"}
```

(`<-` = server to client, `->` = client to server)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.amigo.ai/developer-guide/platform-api/platform-api/text-stream-websocket.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
