Technical docs

Internal Chat

Overview

Support reference for the current internal chat UI.

Current chat modes

  • The current frontend chat peer modes are:
  • `aiTeammate`
  • `ally`
  • Sidebar `Chats` opens the shared chat surface. It is an action item, not navigation to a dedicated `/ai` page.
  • `Alt+C` toggles `Chats`.
  • Internal chat uses one shared session model for panel, floating, and minimized views.

What users can do

  • Start a new conversation, open history, rename a conversation, or delete it.
  • In the shared `Chats` surface, users first see a history screen across Ally and AI teammates, then open a conversation or start a fresh chat from a target chip.
  • The shared panel, floater, and Docs chat host use the same organization-level internal-chat history source.
  • History loads `20` conversations per page and automatically loads another page when the user reaches the list sentinel.
  • Entering at least `3` search characters automatically searches conversation titles and message content across the current user's Ally and AI teammate chats.
  • The target strip uses active teammates and includes the current user's personal Ally.
  • Conversation history rows can show a generated conversation icon when the backend provides a valid `conversation_icon_id`; otherwise they render text-only identity without that icon tile.
  • Send text, reply to a message, stop generation, and send attachments.
  • Use `Enter` to send from the current internal-chat composer.
  • Use `Shift+Enter` or `Alt+Enter` to insert a newline without sending.
  • Use `@` teammate mentions and `#` storage mentions when mention sources are available.
  • `@` mentions resolve from the teammate catalog for the current org. In AI-teammate chat, that list can also include Ally; the currently open teammate is excluded from the mention list. Personal Ally employees are excluded from the mention catalog.
  • `#` opens the `Files and folders` source and searches both entry types on demand. Results show the entry name and full storage path.
  • In AI teammate chat, `#` results are limited to that teammate's readable shared folders. In personal Ally chat, the search can span the organization's full Storage tree.
  • Selected storage mentions preserve whether the reference is a file or folder and are displayed as `#name` in message text.
  • Recall previously sent user messages with `ArrowUp` / `ArrowDown` when the composer is otherwise idle.
  • Leave feedback on assistant replies:
  • `Like`
  • `Dislike`
  • `Feedback` comment editor
  • Failed system-error assistant messages support comment-only feedback.
  • Use voice mode for Ally and AI teammate chat when that chat has realtime voice enabled.

Reasoning and display behavior

  • The composer shows a `Reasoning` control only when the resolved model supports reasoning.
  • User-facing reasoning selections are:
  • `Off`
  • `Low`
  • `Medium`
  • `High`
  • Reasoning preference is persisted in local storage and scoped by user, org, peer, entity, and conversation. A draft selection can carry forward into the first persisted conversation.
  • The reasoning selector is hidden while voice mode is active.
  • Assistant messages can persist a preface with reasoning, tool calls, and source cards, so those details survive reloads.
  • Message and reasoning text rendered through the shared AI Markdown component supports bare HTTP(S) URLs, inline-code URLs, explicit Markdown links, and angle-bracket autolinks.
  • When a bare HTTP(S) URL contains a malformed trailing backtick at a punctuation, symbol, whitespace, or end-of-text boundary, the renderer removes the backtick from the URL and keeps any following punctuation or prose outside the link. Explicit Markdown links, angle-bracket autolinks, and encoded backticks are not rewritten by this repair.
  • Same-origin links use in-app navigation. External links open in a new tab.
  • Chats that are already at the bottom stay pinned during streaming, thinking updates, and panel/viewport resize. If the user scrolls away, expanding a reasoning/tool section does not force them back to the bottom.

Mobile and onboarding behavior

  • On mobile, the internal-chat panel renders full width above the shared bottom nav instead of as a desktop-sized floating panel.
  • Tapping outside the mobile panel overlay closes it.
  • The onboarding URL flag `?onboarding=true` auto-opens Ally once the scoped chat state has restored.
  • Onboarding Ally bootstrap prefers the latest server conversation once per user/org scope, so users land in the current onboarding thread instead of a blank draft.
  • The onboarding floater is positioned bottom-right on desktop when the saved chat mode restores as a floating session.

REST endpoints the current UI uses

  • Cross-teammate history for the current user:
  • `GET /api/organizations/{orgId}/internal-chat/conversations?page=...&limit=...`
  • `GET /api/organizations/{orgId}/internal-chat/conversations/search?q=...&limit=...`
  • The list response includes `page`, `limit`, `total`, and `hasMore`. Rows include conversation title/icon/preview fields plus the associated AI employee identity.
  • List rows have a last message, belong to the current user through an active internal-chat participant, and exclude deleted conversations and deleted AI employees.
  • AI teammate chat:
  • `GET /api/organizations/{orgId}/employees/{employee_id}/messages`
  • `POST /api/organizations/{orgId}/employees/{employee_id}/messages`
  • `POST /api/organizations/{orgId}/employees/{employee_id}/conversations/new`
  • `POST /api/organizations/{orgId}/employees/{employee_id}/stop-generation`
  • `GET /api/organizations/{orgId}/employees/{employee_id}/conversations`
  • `GET /api/organizations/{orgId}/employees/{employee_id}/conversations/search`
  • `PATCH /api/organizations/{orgId}/employees/{employee_id}/conversations/{conversation_id}/title`
  • `DELETE /api/organizations/{orgId}/employees/{employee_id}/conversations/{conversation_id}`
  • Ally chat:
  • `GET /api/organizations/{orgId}/ally/messages`
  • `POST /api/organizations/{orgId}/ally/messages`
  • `POST /api/organizations/{orgId}/ally/conversations/new`
  • `POST /api/organizations/{orgId}/ally/stop-generation`
  • `GET /api/organizations/{orgId}/ally/conversations`
  • `GET /api/organizations/{orgId}/ally/conversations/search`
  • `PATCH /api/organizations/{orgId}/ally/conversations/{conversation_id}/title`
  • `DELETE /api/organizations/{orgId}/ally/conversations/{conversation_id}`
  • Capability bootstrap used by the current frontend:
  • `GET /api/init/internal-chat-capabilities`
  • Current response only exposes Ally model availability.

Feedback and realtime

  • Canonical internal-chat feedback endpoint:
  • `PUT /api/organizations/{orgId}/conversations/{conversation_id}/messages/{message_id}/feedback`
  • Feedback comments are capped at `500` characters.
  • Only the conversation owner can update feedback.
  • `429` feedback responses are surfaced as rate-limit failures, and `409` is used for messages that do not accept feedback.
  • Internal chat subscribes to:
  • `internal.message`
  • `internal.message_updated`
  • `voice_thinking_started`
  • `voice_thinking_ended`
  • `internal.message_updated` is the channel used to sync feedback edits and other message updates into the transcript.
  • Messages with status `in_progress` are not rendered in the transcript or conversation previews.

Attachments and voice

  • Shared chat input currently enforces:
  • max `10` attachments per message
  • max `10 MB` per attachment
  • max `30 MB` total attachments per message
  • `Too many attachments` toast when the file-count cap is exceeded
  • `File too large` toast when a file exceeds the per-file or total-size cap
  • drag/drop overlay text `Drop files here`, or `Attachment limit reached` when the cap is already hit
  • Shared chat input currently accepts:
  • images
  • PDF
  • SQLite database files (`.db3`)
  • plain text (`.txt`)
  • log files (`.log`)
  • Markdown (`.md`, `.markdown`)
  • CSV
  • XLSX
  • DOCX
  • XML
  • Message attachment URLs returned to authenticated internal chat clients use `/shared/attachments/{organizationId}/attachment/{attachmentId}` instead of direct object-storage URLs.
  • Spreadsheet chat attachments are prepared as workflow attachment context for CSV and XLSX when the backend can parse them.
  • File attachments included in AI prompt history use run-scoped shared URLs shaped `/shared/attachments/{organizationId}/run/{runId}/attachment/{attachmentId}`; the route returns `File not found` after the workflow run is finished.
  • `.txt` and `.log` attachments are normalized to `text/plain` before send.
  • `.md` and `.markdown` attachments are normalized to `text/markdown` before send.
  • Clipboard-pasted generic image names are rewritten to `screenshot-...`.
  • Realtime voice session creation currently uses:
  • `POST /chat/realtime/employee/create-session/{organization_id}/{employee_id}`
  • `POST /chat/realtime/ally/create-session/{organization_id}`
  • Voice session creation returns a `conversation_id` so the chat UI can bind the realtime session to the correct conversation.
  • Employee and Ally voice session creation require exactly one of:
  • `conversation_id`
  • `create_new_conversation`

Start building your AI team