> ## Documentation Index
> Fetch the complete documentation index at: https://docs.plungeai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Conversation — chat, followup, continue (and the ⏸ HITL loop)

> Three distinct conversation surfaces — pick by what the user is doing:


<!-- sources-of-truth: orchestration/mcp-gateway/tools.ts, orchestration/mcp-gateway/conversation.ts, orchestration/mcp-gateway/chat.ts, orchestration/mcp-gateway/server.ts | last-synced: 2026-09-24 -->
Three distinct conversation surfaces — pick by what the user is doing:

| Surface | Anchored to | Use when |
|---|---|---|
| `plungeai_chat` | A standing conversation (its own `conversation_id`) | Open-ended chat with the platform assistant, across days. |
| `plungeai_followup` | A COMPLETED execution (`execution_id`) | "Ask more about that run" — the run's result is the context. |
| `plungeai_continue` | A PAUSED execution (`execution_id`) | The run stopped with a ⏸ block — a question or a pending approval. |

The execution id doubles as the conversation session id: every follow-up and
continue turn on a run lands in that run's conversation thread, which
`plungeai_get_result` and `plungeai_executions {action: "conversation"}`
render in full (Studio shows the same thread).

---

## The ⏸ HITL loop (read this first)

A conversational or gated agent stops in one of two states, appended to the
run's result and surfaced by `plungeai_get_workflow_status` as
`structuredContent.continuation`:

```
⏸ AWAITING USER APPROVAL: <action summary> (<price>)
Ask the user to confirm, then call plungeai_continue with execution_id "<id>"
and approve: true (or message: "<their words>").
```

```
⏸ AWAITING USER: <question>
Relay this to the user, then call plungeai_continue with execution_id "<id>"
and message: "<their answer>".
```

In the status tool's machine mirror these map to `continuation.status:
"needs_approval"` and `"question"` respectively.

**The protocol, exactly:**

1. Relay the block to the user VERBATIM (it is theirs, not yours) and ask
   them to decide ("Approve this action? yes/no").
2. Wait for their words.
3. `plungeai_continue {execution_id, approve: true}` ONLY for an explicit
   yes. Anything else — an answer, a denial, a change of course — goes as
   `message: "<their words>"`.
4. The reply either ends with another ⏸ block (loop again) or with
   `✅ Conversation resolved (no further input needed)`.

Approval fences are trust fences: never approve on your own, never rephrase
the pending action, never "retry" around a pause. Async runs surface pending
approvals via `plungeai_get_workflow_status` and `plungeai_get_result` — the
same protocol applies from there.

---

## plungeai_continue

**Purpose:** resume a paused conversation — answer the agent's question or
deliver the user's approval decision.

**Parameters**

| Param | Type | Notes |
|---|---|---|
| `execution_id` | string, required | The id from the ⏸ block. |
| `message` | string | The user's words: an answer, a "no", a modification. |
| `approve` | boolean | `true` only after the user explicitly confirmed. |

One of `message` / `approve: true` is required.

**Example (approval):** `{"user_request": "yes, book it", "execution_id": "d3ad...", "approve": true}`
**Example (answer):** `{"user_request": "the London office, not Paris", "execution_id": "d3ad...", "message": "The London office, not Paris"}`

**Returns:** the agent's next turn (an approved action executes during this
call — it can legitimately take ~30s), then either a fresh ⏸ block or
`✅ Conversation resolved`. Both turns are saved to the run's thread.

**Failures & fixes**

- "Provide `message` or `approve: true`" → you sent neither.
- "Execution not found" → wrong/foreign id; take it from the ⏸ block itself.
- "No conversation session for this execution (expired or not a
  conversational agent)" → the pause window lapsed or the run never paused;
  use `plungeai_followup` for a finished run.
- "This run isn't paused — it already completed. Use plungeai_followup..."
  → exactly that; `continue` is only for pending sessions. (A late
  `approve: true` on an already-consumed approval is safe — it answers that
  nothing is awaiting approval rather than re-running the action.)
- "Agent continuation failed" → the engine failed OR the reply just didn't
  land within the ~30s poll while the action may still have executed.
  Retrying `approve: true` once is safe (the approval token is idempotent —
  the action never runs twice). For a `message`, check `plungeai_get_result`
  first — if the turn landed, a retry would send the message again as a
  second turn. Then surface to the user.

---

## plungeai_followup

**Purpose:** ask a follow-up about a COMPLETED execution. Session-first: if
the run's agent left a session, the SAME agent continues with its own
context. Otherwise a research fallback answers using the run's stored result
as prior context (and is instructed to web-verify any new factual claim —
never to invent).

**Parameters:** `execution_id` (required), `prompt` (required — the user's
follow-up, ≤65536).

**Example:** `{"user_request": "what about their European competitors?", "execution_id": "d3ad...", "prompt": "What about their European competitors?"}`

**Returns:** the answer (relay verbatim), possibly ending in a ⏸ block if the
continued agent paused again. The turn is appended to the run's conversation
thread — a later `plungeai_get_result` on the same id shows the whole
dialogue.

**Failures & fixes:** "Execution not found" → wrong/foreign id. "Failed to
retrieve follow-up response" → transient; retry once. If the stored result
has expired the fallback researches from scratch — the answer may lack the
original run's specifics; say so if it matters.

---

## plungeai_chat

**Purpose:** persistent chat with the PlungeAI assistant — a conversational
agent with web search and registry lookup. Conversations persist and appear
identically in Studio's Think tab and the CLI.

**Actions**

| Action | Requires | Notes |
|---|---|---|
| `send` | `message` | Streams a reply. Omit `conversation_id` to auto-create a conversation (titled from the first message); pass it to continue one. The reply ends with `(conversation: <id>)` — reuse that id for every subsequent turn. |
| `new` | — | Explicitly create a conversation first (optional `message` seeds the title); returns the id. |
| `list_sessions` | — | Table of the user's conversations (Title, ID, Messages). |
| `history` | `conversation_id` | The full transcript, rendered. |

**Example:** `{"user_request": "what can this platform do?", "action": "send", "message": "What can this platform do?"}`

**Returns:** the assistant's markdown + the conversation-id footer. Relay
both — the footer is how the user (and you) come back to the thread.

**Failures & fixes:** "message is required for send." / "conversation_id is
required for history." → supply it. "Conversation not found" → wrong or
foreign id; `list_sessions` to find the real one. Avoid firing two `send`
calls into the same conversation concurrently — turns are persisted
one-writer-at-a-time and a racing turn can be lost.

---

## Choosing among the three (quick rules)

- ⏸ block on screen → `plungeai_continue`. Nothing else resumes a pause.
- "Ask more about that run/report" → `plungeai_followup` with that run's id.
- Free-standing conversation, no run in sight → `plungeai_chat`.
- `continue` on a finished run redirects you to `followup`; `followup` on a
  paused run continues the pending session (it is session-first) — but the
  approval decision itself must still travel via `continue`.
