Skip to content

Ask AI

Ask anything about Destesi — setup, products, APIs.

Powered by Claude. Answers may be wrong — always verify against the docs.

Reference

The real surface area of the Chat service: its HTTP endpoints, the streaming event shapes, the models and tools it exposes, and the configuration operators use to run it.

Every product endpoint is gated by your single sign-on session. After you sign in at account.destesi.io and open Chat, the service redeems a one-time token and sets a host-only chat_session cookie. Each request validates that cookie against Accounts; an invalid or missing session returns 401.

Endpoint Method Purpose
/healthz GET Liveness — returns ok.
/readyz GET Readiness — 200 when an AI provider is wired, 503 degraded otherwise.
/v1/sso/callback GET SSO callback; redeems the exchange token and sets chat_session.
/v1/auth/me GET The current user (id, email, name).
/v1/auth/logout POST Clears the session cookie. Idempotent.
/v1/me/products GET Your launcher entitlements (proxied from Accounts).
/v1/chat POST The main agentic chat stream.
/v1/chat/approvals/{tool_use_id} POST Approve or cancel a paused tool, resuming the stream.
/v1/models GET The list of selectable models.

Server-side conversation storage. Every route re-checks that the conversation belongs to the calling (workspace, user) pair and answers 404 for anything else, so a conversation id from another workspace is indistinguishable from one that doesn’t exist. If no store is configured, all four return 503 persistence_disabled.

Endpoint Method Purpose
/v1/conversations GET List your conversations, newest first. limit (default 30, max 100) and a before cursor.
/v1/conversations/{id}/messages GET One page of messages. limit (default 30, max 100) and a before cursor; pages ascend within themselves.
/v1/conversations/{id} PATCH Rename a conversation.
/v1/conversations/{id} DELETE Delete a conversation and its messages.
Endpoint Method Purpose
/v1/uploads POST Upload a file from the composer (up to 50 MiB) and register it in Drive, returning a drive_file_id you can attach.
/v1/attachments/{drive_file_id}/content GET Fetch an attachment’s content for display in the conversation.

The primary endpoint. It always runs the agentic loop and streams the reply back as newline-delimited JSON (Content-Type: application/x-ndjson) — one JSON object per line.

{
"model": "global.anthropic.claude-haiku-4-5-20251001-v1:0",
"conversation_id": "conv_abc",
"client_id": "msg_local_42",
"messages": [
{ "role": "user", "content": "Generate an image of a robot mascot." }
],
"attachments": [
{ "drive_file_id": "file_abc", "name": "spec.md" }
]
}
  • messages (required) — the conversation so far. Each message has a role (user, assistant, or system) and content. content is either a JSON string (plain text) or a JSON array of content blocks (for replaying prior tool calls and results). An empty messages array returns 400 missing_messages.
  • attachments (optional) — Drive files to fold into the conversation as context. Each needs a drive_file_id; name is echoed back for display.
  • model (optional) — overrides the default model for this request.
  • conversation_id (optional) — the conversation this turn belongs to. Supply it to append to an existing thread; omit it and a new conversation is created and announced in the stream. A conversation id that isn’t yours is rejected with 404 before the stream opens.
  • client_id (optional) — your own idempotency key for this user message. A retried POST carrying the same client_id updates the same stored row instead of duplicating it.

Each line is one event, keyed by type:

{"type":"conversation","id":"conv_abc","title":"New chat"} // emitted only when this turn CREATED a conversation
{"type":"attachments","items":[ ... ]} // per-attachment status (ok | truncated | attached | skipped)
{"type":"text","delta":"..."} // a chunk of the assistant's reply
{"type":"tool_call","tool":"generate_image","input":{ ... }} // the model invoked a tool
{"type":"tool_result","tool":"generate_image","result":{ ... }}// the tool's output
{"type":"tool_result","tool":"...","error":"..."} // a tool failed
{"type":"tool_approval_needed","tool_use_id":"...","tool":"gmail_send_email","input":{ ... },"editable_fields":[ ... ],"expires_at":"..."}
{"type":"done","reply":"..."} // terminal — full assistant text
{"type":"done","paused_for_approval":true,"tool_use_id":"..."} // terminal — waiting on an approval

If no suite tools are configured for the workspace, the stream is simply a series of text events followed by done — there are no tool_call or tool_result events.

The conversation frame arrives first when the turn created a new conversation; echo that id back as conversation_id on every subsequent turn in the thread. When you already sent a conversation_id, no conversation frame is emitted.

When an action requires approval (sending email, posting to GitHub), /v1/chat ends with done carrying paused_for_approval: true and a tool_use_id. To resume, POST your decision:

{ "decision": "approve", "input": { "subject": "Edited subject", "body": "Edited body" } }
  • decision"approve" or "cancel".
  • input (optional) — the edited values for the tool’s editable_fields. Omit to approve the draft as-is.

The response is another NDJSON stream carrying the tool result and the assistant’s follow-up. A pending approval is durable (stored, so it survives a reload or a service restart), single-use, and has a 30-minute TTL; a resume for an expired or already-resumed approval returns 404.

The tools Chat exposes are determined per-workspace by which products and connections are wired: a family whose dependency is unwired is omitted from the registry entirely, so the model never sees it and never promises it. With everything wired the registry is 47 tools.

The agentic loop is bounded — the model gets a limited number of tool-call rounds before it must produce a final answer.

Tool What it does Requires approval
generate_image Generate an image (512 / 768 / 1024 px). No
generate_audio Synthesize speech with a Text-to-Speech voice. No
elevenlabs_list_voices List the voices in your connected ElevenLabs account. No
elevenlabs_generate_audio Synthesize speech with an ElevenLabs voice. No
Tool What it does Requires approval
gmail_search Search the inbox (Gmail query syntax). No
gmail_read_email Read a message by ID. No
gmail_send_email Compose and send an email. Yes
Tool What it does Requires approval
github_list_repos List accessible repositories. No
github_read_path Read a file or list a directory. No
github_search_code Search code across accessible repos. No
github_search_issues Search issues and pull requests. No
github_get_issue Read an issue or PR with comments. No
github_get_pr_diff Get a pull request’s unified diff. No
github_create_comment Comment on an issue or PR. Yes
github_create_issue Open a new issue. Yes
github_edit_issue Edit, close, or reopen an issue. Yes
Tool What it does Requires approval
slack_list_channels List channels the connected account can see. No
slack_read_channel Read recent messages in a channel. No
slack_send_message Post a message to a channel. Yes
Tool What it does Requires approval
linear_search_issues Search issues. No
linear_get_issue Read one issue. No
linear_create_issue Create an issue. Yes
linear_update_issue Update an issue. Yes
Tool What it does Requires approval
drive_list_files List files in your Drive library. No
drive_read_file Read a Drive file’s text content. No
drive_get_download_url Mint a short-lived download URL for a Drive file. No
Tool What it does Requires approval
snap_list_branches List Snap branches. No
snap_branch_status Read one Snap branch’s status. No
review_status Read the code-review status of a pull request. No

Both Snap tools are read-only; Chat never mutates a Snap branch.

Tool What it does Requires approval
whatsapp_list_conversations List customer conversations. No
whatsapp_read_conversation Read one conversation. No
Tool What it does Requires approval
capture_app Screenshot a live, already-running web app plus its on-screen regions. No
compose_promo Assemble captured frames into a re-renderable promo composition. No
render_promo Render a composed promo to MP4. No
prepare_promo_preview / teardown_promo_preview Stand up and tear down a preview environment to film. No
prepare_promo_render / teardown_promo_render Stand up and tear down the render sandbox. No
produce_promo Produce a narrated promo of a connected repo or live URL, end to end. No
Tool What it does Requires approval
list_connections List the third-party apps this workspace has connected. No
connect_read Make a read-only call against a connected app’s API. No
connect_write Make a mutating call against a connected app’s API. Yes
request_connection Return a sign-in link so you can connect a provider. No
check_connection Check whether a provider is connected yet. No

connect_read and connect_write take a provider id and a relative path — never a full URL — and Connect injects the credential server-side. Chat never sees the token.

Tool What it does Requires approval
list_connected_actions Browse Connect’s typed action catalog for this workspace. No
run_connected_action Run a read-only catalog action. No
run_connected_write_action Run a catalog action that changes something. Yes

GET /v1/models returns the selectable models. The current set (Anthropic Claude models, served via AWS Bedrock):

{
"models": [
"global.anthropic.claude-haiku-4-5-20251001-v1:0",
"global.anthropic.claude-sonnet-4-6",
"global.anthropic.claude-opus-4-5-20251101-v1:0"
]
}

The default is the Haiku profile. Pass any of these — including the global. prefix, which is part of the id — as the model field on /v1/chat.

generate_audio draws on the Text-to-Speech catalog. Voice names, engines, and the languages each one covers are documented once, in Text-to-Speech — Chat does not maintain a second copy that would drift out of date. The default language is auto (detected from your text).

Attachments come either from your Drive library or from POST /v1/uploads (50 MiB per file). What happens next depends on the type:

  • Text extracted: text/*, application/json, application/xml. Up to ~50 KiB per attachment (beyond that the attachment is reported as truncated) and ~200 KiB per request across all files.
  • Presence block only: images, video, audio, and PDF. The file’s name, MIME type, drive_file_id, and a short-lived download link are given to the model — enough for it to acknowledge the file and pass it to a tool — but the bytes are not inlined as text. These are reported as attached, not skipped.
  • skipped: only when the file could not be fetched at all, or an unrecognised type was hit.

Attachments replay across turns: once attached to a conversation, later turns in that conversation still carry the file, so you don’t re-attach it to ask a follow-up.

Self-hosting Chat? It’s a Go service backed by Postgres for conversation history and pending approvals. Configuration is environment-driven; a capability is enabled only when every variable it needs is set — otherwise the matching tool is omitted from the registry and the model never sees it. Every request is scoped to the caller’s workspace.

Variable Purpose Default
CHAT_ADDR HTTP listen address. :9102
IDENTITY_API_URL Accounts service base URL (server-to-server). http://localhost:9091
CHAT_WEB_URL Default redirect target after SSO. http://localhost:4329
CHAT_WEB_URL_ALLOWLIST Allowed ?web= origins (comma-separated).
CHAT_CORS_ALLOWED_ORIGINS CORS origins for the API (comma-separated).
CHAT_DATABASE_URL Postgres DSN for conversation history and durable approvals. Unset → history routes 503 persistence_disabled, chat still streams, and approvals fall back to in-memory (they will not survive a restart).

Chat needs at least one provider, or /v1/chat returns 503 agent_not_configured. When both are set, the direct Anthropic provider is used.

Variable Purpose Default
AWS_REGION Bedrock region (credentials come from the standard AWS chain).
CHAT_BEDROCK_MODEL_ID Bedrock inference profile. global.anthropic.claude-haiku-4-5-20251001-v1:0
ANTHROPIC_API_KEY Enables the direct Anthropic provider when set.
CHAT_ANTHROPIC_MODEL_ID Model ID for the direct provider. claude-haiku-4-5-20251001

Each capability is gated independently. If its variables are unset, the corresponding tool is simply not offered.

Variable Enables
SUITE_TOOL_SECRET Suite tool dispatch overall. Unset → text-only chat.
IMAGEGEN_API_URL generate_image.
TTS_API_URL generate_audio.
DRIVE_API_URL Drive attachments, the drive_* read tools, and auto-save of generated artifacts.
CONNECT_API_URL + CONNECT_CONTROLLER_SECRET Everything credential-backed: Gmail, GitHub, Slack, Linear, ElevenLabs, WhatsApp, the Connect bridge, and the Connect action catalog. Credentials are fetched from Connect at call time.
STUDIO_API_URL + SUITE_TOOL_SECRET compose_promo / render_promo.
RENDER_WORKER_URL + RENDER_WORKER_SECRET capture_app.