PartyFlow

Reference: Message Format#

Полное описание структурированных данных, которые отправитель (бот, incoming webhook) вкладывает в сообщение, чтобы канал отрендерил его rich — с цветной полоской, грид-полями, кнопками, attachments, вложениями.

Эта страница — reference для отправителя. Как оно потом рендерится в UI — забота клиента PartyFlow, и её можно игнорировать: достаточно отдать валидный JSON по схеме ниже, всё остальное сделает платформа.


Где это используется#

Структурированный payload бывает двух типов: sender-provided rich metadata (attachments, blocks, buttons, files) и PartyFlow-generated metadata для Agent Runs.

Контекст Как попадает в сообщение
Incoming webhook Поля верхнего уровня JSON-тела запроса (attachments, blocks, buttons, files). См. reference/http-webhook-endpoint.md.
Bot response В ответах бота на button.click / modal.submit — поле update_message.metadata_json или send_message.metadata_json (JSON-строка). См. reference/interactive-components.md.
Agent Run PartyFlow генерирует bot_metadata_json.kind="agent_run" для долгих AI-ответов, созданных через Bot REST API.

Для incoming webhooks и bot responses формат sender-provided rich metadata идентичный: endpoint автоматически детектит Slack или Pachca формат по набору полей. Agent Run metadata не отправляется ботом напрямую и не проходит через Slack/Pachca autodetect.

Файлы, загруженные через Bot REST Bot Files API, не являются частью metadata_json: они передаются отдельным top-level полем attachments: [{ "file_id": "..." }] в Bot REST API. Не смешивайте это поле со Slack legacy metadata_json.attachments.


Верхнеуровневая структура#

type BotMetadata = {
  attachments?: SlackAttachment[];  // Slack legacy
  blocks?: SlackBlock[];            // Slack Block Kit
  buttons?: PachcaButton[];         // Pachca URL-кнопки
  files?: PachcaFile[];             // Pachca вложения
  severity?: "critical" | "warning" | "info";  // влияет на push-policy
  kind?: "agent_run";               // server-generated Agent Run status
  agent_run?: AgentRunMetadata;     // только когда kind === "agent_run"
};

Правило автодетекта формата:

  • attachments или blocks → Slack format.
  • buttons или files → Pachca format.
  • Форматы не смешиваются в одном сообщении.
  • kind="agent_run" → отдельный server-generated формат для долгих AI-ответов; он не смешивается с Slack/Pachca rich blocks.
  • Если ни одно из полей не передано, а в text есть контент — шлётся как обычное текстовое сообщение.

severity (опциональное)#

Указывает приоритет сообщения. Если поле опущено — трактуется как warning (default).

Значение Использовать для Что делает PartyFlow
critical P0/P1 incident, outage, alarming event Красный бейдж в UI. Push пробивает quiet hours и DND получателя (но уважает явно заглушённые им каналы).
warning Обычные alerts, CI уведомления Бейдж не показывается. Push работает по стандартным правилам DND получателя.
info Success-сообщения, FYI, completions Серый бейдж. Push не триггерится для этого сообщения.

Синонимы — endpoint приводит к трём внутренним значениям:

Прислали Станет
error, fatal, emergency, alert, critical critical
warn, warning warning
debug, notice, info info
что-то другое warning (fallback)

Поле взаимодействует с push-policy — см. reference/http-webhook-endpoint.md § Push policy. Само по себе severity только вешает бейдж и влияет на поведение push, не на рендер контента.


Agent Run metadata#

Для долгих AI-ответов бот может создать Agent Run. PartyFlow сразу отправит placeholder-сообщение, а затем будет обновлять его metadata безопасными статусами. Бот не передаёт status_text напрямую: текст статуса выбирается по разрешённому сервером списку.

interface AgentRunEnvelope {
  version: 1;
  kind: "agent_run";
  agent_run: AgentRunMetadata;
}
 
interface AgentRunMetadata {
  run_id: string;
  widget_id?: string;
  status:
    | "accepted"
    | "queued"
    | "gathering_context"
    | "using_tool"
    | "waiting_tool"
    | "waiting_user"
    | "finalizing"
    | "completed"
    | "failed"
    | "cancelled"
    | "expired";
  status_text: string;
  sequence: number;
  is_terminal: boolean;
  trigger_message_id: string | null;
  updated_at: string;
  completed_at: string | null;
  error_code: string;
}

widget_id появляется, когда Agent Run связан с Execution Widget. Полное состояние widget читайте через Bot REST API; не кладите task state в metadata_json. Для изменения task используйте PATCH /api/v1/bot/execution_tasks/{widget_id} или terminal update связанного Agent Run.

Status status_text
accepted Запрос принят
queued В очереди
gathering_context Ищу контекст
using_tool Использую инструмент
waiting_tool Жду ответ инструмента
waiting_user Жду ответа пользователя
finalizing Готовлю финальный ответ
completed Готово
failed Не удалось выполнить
cancelled Остановлено
expired Остановлено по тайм-ауту

В public_text, error_code и metadata нельзя помещать raw reasoning, prompt'ы, token'ы, секреты, tool payloads, stack traces, приватные идентификаторы файлов или постоянные download URLs.


Порядок рендера#

Клиент PartyFlow рисует rich-контент в этом порядке (сверху вниз):

┌──────────────────────────────────────────┐
│ [BOT badge] Display name     12:34       │
├──────────────────────────────────────────┤
│ msg.text (только если blocks отсутствуют)│
├──────────────────────────────────────────┤
│ blocks[]: header / section / divider / … │
├──────────────────────────────────────────┤
│ ┃ attachments[]: color-bar + content     │
├──────────────────────────────────────────┤
│ [Button 1] [Button 2]                    │
├──────────────────────────────────────────┤
│ 📎 file.pdf (200 KB)                    │
└──────────────────────────────────────────┘

Важное правило Slack-совместимости: если вы прислали и blocks, и text — в UI показывается blocks, text скрывается. Поле text в таком случае используется только для push-уведомлений, предпросмотров в листинге каналов и полнотекстового поиска. Всегда заполняйте text понятным plain-fallback'ом — это ровно то, что увидит пользователь в push-notification.


Slack Attachments#

Используют: Grafana Alerting, GitLab CI, Sentry, Jenkins, Prometheus Alertmanager.

interface SlackAttachment {
  color?: string;          // "#36a64f" | "good" | "warning" | "danger"
  title?: string;
  title_link?: string;     // URL — title становится ссылкой
  pretext?: string;        // текст ДО attachment (без цветной полоски)
  text?: string;           // основной текст (Slack mrkdwn)
  fallback?: string;       // plain-fallback для push
  fields?: SlackField[];   // key-value grid
  author_name?: string;
  author_icon?: string;    // 16x16
  author_link?: string;
  footer?: string;
  footer_icon?: string;    // 16x16
  ts?: number;             // Unix timestamp → рендерится как дата
  image_url?: string;      // большое изображение
  thumb_url?: string;      // миниатюра справа (~75x75)
}
 
interface SlackField {
  title: string;     // bold label
  value: string;     // значение (Slack mrkdwn допустим)
  short?: boolean;   // true = 2 колонки, false = full width
}

Color aliases: "good"#2EB67D, "warning"#ECB22E, "danger"#E01E5A.

Пример: Grafana alert#

{
  "text": "🔥 High CPU on prod-web-01",
  "severity": "critical",
  "attachments": [
    {
      "color": "danger",
      "title": "[FIRING:1] High CPU Usage",
      "title_link": "https://grafana.example.com/alerting/abc123/view",
      "text": "CPU usage on *prod-web-01* exceeded 90% for 5 minutes.",
      "fields": [
        {"title": "Status",    "value": "Firing",          "short": true},
        {"title": "Severity",  "value": "critical",        "short": true},
        {"title": "Instance",  "value": "prod-web-01:9090","short": true},
        {"title": "Dashboard", "value": "<https://grafana.example.com/d/abc|Infrastructure>", "short": true}
      ],
      "footer": "Grafana Alerting",
      "footer_icon": "https://grafana.example.com/public/img/grafana_icon.svg",
      "ts": 1744721696
    }
  ]
}

Грейд вниз: если ваш Grafana контакт-поинт шлёт только text без attachments — отрисуется как plain-текст, severity всё равно применяется.


Slack Blocks (Block Kit)#

Используют: PagerDuty, GitHub Actions, новые версии Grafana.

type SlackBlock = HeaderBlock | SectionBlock | DividerBlock | ContextBlock | ImageBlock;
 
interface HeaderBlock {
  type: "header";
  text: { type: "plain_text"; text: string };
}
 
interface SectionBlock {
  type: "section";
  text?: TextElement;                // основной текст
  fields?: TextElement[];            // grid, max 10 элементов
  accessory?: { type: "image"; image_url: string; alt_text: string };
}
 
interface DividerBlock {
  type: "divider";
}
 
interface ContextBlock {
  type: "context";
  elements: (TextElement | { type: "image"; image_url: string; alt_text: string })[];
}
 
interface ImageBlock {
  type: "image";
  image_url: string;
  alt_text: string;
  title?: { type: "plain_text"; text: string };
}
 
type TextElement =
  | { type: "plain_text"; text: string }
  | { type: "mrkdwn"; text: string };

Неизвестный type → клиент молча пропустит блок (forward compatibility: мы не ломаем ренедер, когда появится новый тип).

Лимиты: до 50 блоков на сообщение, до 10 fields внутри section, до 10 elements внутри context, plain_text.text до 3000 символов, mrkdwn.text до 3000 символов.

Пример: PagerDuty incident#

{
  "text": "[P1] DB connection pool exhausted",
  "severity": "critical",
  "blocks": [
    {
      "type": "header",
      "text": {"type": "plain_text", "text": "Incident: DB Connection Pool Exhausted"}
    },
    {
      "type": "section",
      "fields": [
        {"type": "mrkdwn", "text": "*Service:*\nPayment API"},
        {"type": "mrkdwn", "text": "*Severity:*\nP1 - Critical"},
        {"type": "mrkdwn", "text": "*Started:*\n2026-04-19 12:34 UTC"},
        {"type": "mrkdwn", "text": "*On-call:*\n<@user-42>"}
      ]
    },
    {"type": "divider"},
    {
      "type": "context",
      "elements": [
        {"type": "image", "image_url": "https://pagerduty.com/icon.png", "alt_text": "PagerDuty"},
        {"type": "mrkdwn", "text": "PagerDuty | <https://pd.example.com/incidents/P123|View incident>"}
      ]
    }
  ]
}

Interactive blocks (actions)#

Используется ботами для кнопок, select menus и модалок. Только для бот-сообщений — incoming webhooks и Slack/Pachca mainline форматы их не используют.

interface ActionsBlock {
  type: "actions";
  elements: (ButtonElement | SelectElement)[];
}
 
interface ButtonElement {
  type: "button";
  action_id: string;               // ^[a-z0-9_-]{1,64}$, unique в рамках сообщения
  text: string;                    // до 75 символов
  style?: "primary" | "danger";    // иначе neutral
  data?: string;                   // до 2000 chars, произвольный payload
  visibility_user_ids?: string[];  // 1..100, кому показывать кнопку
  confirm?: {                      // второй клик для подтверждения
    title: string;                 // до 75
    text: string;                  // до 300
    confirm_label?: string;
    cancel_label?: string;
  };
}
 
interface SelectElement {
  type: "select";
  action_id: string;
  placeholder?: string;            // до 100
  options: Array<{
    value: string;                 // до 150, уникален
    label: string;                 // до 75
  }>;                              // до 25 опций
}

Полный справочник поведения (лимиты, signed tokens, визуальные стили, click-response flow) — reference/interactive-components.md. Эта страница описывает только schema отправки.


Pachca Buttons#

URL-кнопки в payload входящего webhook'а от Pachca-совместимых источников:

interface PachcaButton {
  text: string;   // label кнопки
  url?: string;   // → кнопка-ссылка в новое окно
  data?: string;  // есть без url → НЕ рендерится в MVP
}

Пример#

{
  "message": {
    "content": "Pipeline finished. Approve deploy?",
    "buttons": [
      {"text": "Approve", "url": "https://ci.example.com/deploy/42/approve"},
      {"text": "View Logs", "url": "https://ci.example.com/deploy/42/logs"},
      {"text": "Rollback", "url": "https://ci.example.com/deploy/42/rollback"}
    ]
  }
}

Кнопки с только data (без url) пока не рендерятся — механизм click-callback для Pachca-формата не подключён. Если нужна интерактивная кнопка, используйте Slack Interactive Components через бота (см. выше).


Pachca Files#

Вложения:

interface PachcaFile {
  name: string;          // отображаемое имя
  url: string;           // HTTPS URL
  size?: number;         // bytes → рендер как "200 KB" / "1.4 MB"
}

Пример#

{
  "message": {
    "content": "Build artifacts ready",
    "files": [
      {"name": "build.log", "url": "https://ci.example.com/artifacts/42/build.log", "size": 204800},
      {"name": "coverage.html", "url": "https://ci.example.com/artifacts/42/coverage.html", "size": 1048576}
    ]
  }
}

Файлы отображаются ссылками; PartyFlow не копирует их к себе — клиент скачивает по URL напрямую. URL должен быть доступен получателю (без auth, либо с кросс-site токеном в URL).


Обработка mrkdwn#

Slack-формат использует mrkdwn (свой диалект Markdown). PartyFlow автоматически конвертирует его в стандартный Markdown только в поле верхнего уровня text входящего webhook'а. Внутри blocks и attachments текст передаётся как есть — клиент обрабатывает сам.

Что конвертируется на верхнем уровне text:

Slack mrkdwn Markdown
*bold* **bold**
_italic_ *italic*
~strike~ ~~strike~~
<url|label> [label](url)
<url> url
&amp; &lt; &gt; & < >

Если вы шлёте сложное форматирование через blocks — просто используйте Slack mrkdwn синтаксис (*bold*, _italic_, <url|label>). Клиент PartyFlow его сам отрендерит по тем же правилам.


Сводка: кто что шлёт#

Ориентировочный матрикс — какой инструмент какой формат использует «из коробки».

Инструмент Формат Типовые поля
Grafana Alerting Slack attachments color, title, title_link, fields, footer, ts
GitLab CI/CD Slack attachments color, title, title_link, fields, author_name
Sentry Slack attachments color, title, title_link, text, fields
Jenkins Slack attachments color, title, title_link, fields
PagerDuty Slack Block Kit header, section с fields, divider, context
GitHub Actions Block Kit + attachments blocks для заголовка, attachments для details
Prometheus Alertmanager Slack attachments color, title, text, несколько fields
Pachca-боты Pachca buttons / files URL-кнопки, файловые ссылки
Custom боты (ваши) любой из форматов зависит от сценария

Для отладки: все эти источники успешно тестируются на reference/http-webhook-endpoint.md — endpoint определит формат и применит соответствующий рендерер.


Связанное#