Most czatu
Dostawcy
Dział zatytułowany „Dostawcy”| Dostawca | Wartość protokołu | Transport | Rodzaj przestrzeni |
|---|---|---|---|
| Slack | slack |
Socket Mode (wychodzący WSS) | slack |
Slack to jedyny dostawca. ChatProvider to jednowartościowy enum, a cc_server rejestruje jedną wtyczkę. Schemat, każde wyszukiwanie i każdy indeks unikalny są kluczowane przez provider, więc identyfikatory nigdy nie przechodzą między dostawcami, a dodanie kolejnego to zmiana wyłącznie po stronie serwera.
Jedna aplikacja po stronie dostawcy na obszar roboczy × dostawcę.
Polecenia czatu
Dział zatytułowany „Polecenia czatu”Nazwa polecenia jest właściwa dla aplikacji (cc domyślnie, czyli /cc). Administrator może ją zmienić; most używa wtedy tej nazwy, pod którą polecenie wywołano ostatnio.
| Polecenie | Efekt |
|---|---|
/cc help (lub /cc bez czasownika) |
Wyświetla, co potrafi bot |
/cc link <code> |
Realizuje jednorazowy kod i łączy tożsamość czatu nadawcy |
/cc ticket <title> |
Zakłada lokalne zgłoszenie przekazane przez połączonego członka |
/cc ticket <title> | <description> |
To samo, z wszystkim po pierwszym | jako opisem |
| Nieznany czasownik | Zgłasza nieznany czasownik wraz z tekstem pomocy |
Sposoby dotarcia do agenta:
| Działanie | Zachowanie |
|---|---|
@bot … na kanale |
Otwiera wątek Slacka i pasującą przestrzeń Control Center; agent odpowiada w wątku Slacka |
| Odpowiedź w połączonym wątku Slacka | Kontynuuje tę samą przestrzeń Control Center — wzmianka nie jest potrzebna |
| Zwykła wiadomość na kanale | Ignorowana (nie jest skierowana do bota i nie należy do połączonego wątku Slacka) |
| Wiadomość prywatna do bota | Jedna przestrzeń Control Center na rozmowę prywatną; ustawia tytuł wątku Slacka i status „is thinking…“, gdy agent pracuje |
Pola danych uwierzytelniających (Slack)
Dział zatytułowany „Pola danych uwierzytelniających (Slack)”Deklarowane przez deskryptor dostawcy, który generuje okno połączenia i waliduje zgłoszenie.
| Identyfikator pola | Etykieta | Wymagane | Prefiks | Gdzie się znajduje |
|---|---|---|---|---|
botToken |
Bot user OAuth token | Tak | xoxb- |
OAuth & Permissions |
appToken |
App-level token | Tak | xapp- |
Basic Information → App-Level Tokens, scope connections:write |
configRefreshToken |
App configuration refresh token | Nie | xoxe |
App configuration tokens on api.slack.com/apps |
configRefreshToken to dane uwierzytelniające do zarządzania aplikacją: bez nich połączenie działa, ale bota nie można utworzyć ani edytować z Control Center. Jest rotowany przy każdym użyciu, a nowa wartość jest zapisywana natychmiast.
Wartości są przycinane z białych znaków, niezadeklarowane klucze są odrzucane, a niezgodny prefiks jest odrzucany tym samym komunikatem po stronie klienta i serwera. Pola wymagane muszą być podane przy każdym połączeniu; pole opcjonalne pozostawione puste zachowuje to, co już zapisano.
Wymagania aplikacji Slack
Dział zatytułowany „Wymagania aplikacji Slack”Zakresy tokenu bota:
app_mentions:readassistant:writechannels:historychat:writecommandsgroups:historyim:historyusers:readusers:read.emailSubskrypcje zdarzeń bota:
app_home_openedapp_mentionmessage.channelsmessage.groupsmessage.imUstawienia strukturalne, które Control Center wymusza, gdy tworzy lub edytuje aplikację: włączony Socket Mode, brak adresu URL żądań, zakładka Messages włączona i zapisywalna, bot always_online, wymagane zakresy i zdarzenia scalone z tym, co aplikacja już ma (nigdy nie odejmowane) oraz jedno polecenie slash niosące opis File a ticket or link your Control Center account — znacznik, który identyfikuje własne polecenie Control Center w wyeksportowanym manifeście.
Stany połączenia
Dział zatytułowany „Stany połączenia”| Stan | Wartość protokołu | Znaczenie |
|---|---|---|
| Nie połączono | disconnected |
Brak zapisanych danych uwierzytelniających dla tej pary obszar roboczy × dostawca |
| Łączenie… | connecting |
Dane uwierzytelniające zapisane, transport się łączy lub łączy ponownie |
| Na żywo | connected |
Transport działa i odbiera zdarzenia |
| Błąd połączenia | error |
Zapisane, ale kończy się niepowodzeniem; obok pokazywany jest błąd samego dostawcy |
Ponowne połączenie to wykładniczy backoff z jitterem, ograniczony do 30 sekund. Zainicjowana przez dostawcę rotacja gniazda łączy ponownie bez zwłoki i bez zwiększania backoffu. Odrzucone dane uwierzytelniające (invalid_auth, not_authed, token_revoked, account_inactive, token_expired, invalid_app_id) lub brakujący zakres są ostateczne: most przestaje ponawiać próby, dopóki nie pojawią się nowe dane uwierzytelniające.
Możliwości dostawcy (Slack)
Dział zatytułowany „Możliwości dostawcy (Slack)”Most jest pisany pod najbogatszą powierzchnię i traci możliwości pojedynczo.
| Możliwość | Slack | Efekt, gdy jej brak |
|---|---|---|
streaming |
tak | Cała odpowiedź jest publikowana raz, na końcu |
streamingRequiresThread |
tak | Cel odpowiedzi bez kotwicy wątku publikuje całe odpowiedzi |
ephemeralMessages |
tak | Odpowiedź na polecenie slash bez użytecznego uchwytu odpowiedzi jest porzucana (odmowy zawsze trafiają do wątku) |
threadStatus |
tak | Brak przemijającego wiersza „is thinking…” |
threadTitle |
tak | Wątek czatu zachowuje domyślny tytuł |
slashCommands |
tak | Brak powierzchni /cc |
taskCards |
tak | Tylko tekst — żadnej karty nad odpowiedzią ani linku „View in Control Center” |
maxMessageLength |
39,000 | Dłuższe odpowiedzi są obcinane ze wskazaniem na Control Center |
maxStreamChunkLength |
3,800 | Dołączane fragmenty są dzielone na granicy akapitu, wiersza lub spacji |
Zgłoszenie strumieniowania to jeszcze nie obietnica: strumieniowanie Slacka wymaga funkcji Agents & AI Apps w płatnym planie. Odmowa w chwili wywołania (streaming_not_supported, feature_not_enabled, paid_only, …) jest zapamiętywana na cały czas życia połączenia i pokazywana jako streamingAvailable: false. Karty zadań Slacka korzystają z tego samego wywołania, więc Slack, który odrzuca tryb wyświetlania karty, zachowuje swój strumień i traci tylko kartę — raz, na cały czas życia połączenia.
Strumień musi też wskazać czytelnika, dla którego jest przeznaczony. Slack wymaga zarówno użytkownika będącego odbiorcą, jak i jego zespołu, aby otworzyć strumień na kanale (wiadomość prywatna tego nie wystarcza) i w przeciwnym razie odmawia z missing_recipient_user_id / missing_recipient_team_id — to odmowa dotycząca pojedynczego wywołania, więc most próbuje dalej, a tura dociera tymczasem jako jedna opublikowana odpowiedź. Odbiorcą jest ten, kto zapytał, wzięty z wiadomości przychodzącej (jego zespół, a nie zespół aplikacji, dzięki czemu kanał Slack Connect jest rozwiązywany poprawnie). W przypadku tury, której nikt nie rozpoczął z czatu — pracy uruchomionej w Control Center na już połączonej rozmowie — jest to członek, którego połączenie utworzyło most; jeśli od tego czasu odłączył on swoje konto czatu, ta tura jest publikowana w całości, a nie strumieniowana.
Karty zadania
Dział zatytułowany „Karty zadania”Jedna zgrupowana karta na turę agenta (task_display_mode: plan), z wierszem na każdy krok. Każdy wiersz to task_update złożony z id + title + status, plus jednorazowe details, gdy myśl jest gotowa. details i output o tym samym identyfikatorze są łączone bez separatora, więc details są wysyłane raz, a output nigdy nie jest strumieniowany. Tytuł planu to żądanie; odpowiedź to osobne, późniejsze dołączenie niosące fragment markdown_text.
| Część | Zawartość |
|---|---|
| Tytuł planu | To, o co poproszono |
| Wiersz konfiguracji | Working on it…, potem Cloning …, potem Starting the agent… — jeden wiersz, tytuł jest zastępowany |
| Wiersz rozumowania | Thinking…, dodawany, gdy agent zaczyna rozumować; myśl to details tego wiersza, wysyłane raz po zakończeniu rozumowania |
| Wiersze narzędzi | Po jednym na narzędzie (Bash which swift), unikalny identyfikator, dzięki czemu stoją obok siebie |
| Status | W toku, gdy ten wiersz działa; ukończony, gdy zaczyna się następny wiersz albo tura się kończy; błąd w przypadku niepowodzenia, przerwania i limitu tur |
| Wezwanie do działania | View in Control Center jako końcowy wiersz po zakończeniu tury — nieobecne, gdy praca wciąż trwa, i nieobecne, gdy serwer nie ma osiągalnego publicznego adresu URL |
Czego karta nigdy nie niesie: danych wyjściowych narzędzi, argumentu spoza tej listy dozwolonych ani niczego odczytanego z bazy danych. Proza rozumowania to wyłącznie details wiersza Thinking… (ograniczone do 256 znaków), a nie treść wiadomości. Karta, która nie powiedziałaby nic nowego, nie jest wysyłana ponownie. Wzmianka otwiera strumień natychmiast, aby wątek Slacka nie milczał; tura, która potem nie wygenerowała żadnego tekstu, kończy tę samą kartę krótką notatką, zamiast publikować drugą wiadomość. Tura bez słów na przestrzeni, która nigdy nie otworzyła strumienia (brak kart albo strumieniowanie już odrzucone), i tak publikuje jedną wiadomość niosącą ukończoną kartę i notatkę.
Karty strumieniowane i publikowane to różne ładunki:
| Forma | Kształt | Proza |
|---|---|---|
| Strumieniowana | plan_update plus fragmenty task_update kluczowane przez id |
Zwykły ciąg, ograniczony do 256 znaków na fragment |
| Publikowana | Blok plan opakowujący task_card kluczowane przez task_id |
Tekst sformatowany |
Obsługa niepowodzeń:
| Sytuacja | Zachowanie |
|---|---|
| Dostawca odrzuca kartę przy dołączaniu | Dołączenie jest natychmiast ponawiane bez niej; proza wciąż dociera na żywo, a karty są porzucane na cały czas życia połączenia |
| Dostawca odrzuca również prozę | Strumień jest zamykany, a odpowiedź publikowana w całości |
| Strumień urywa się po dotarciu części odpowiedzi | Strumień jest zamykany i nic nie jest publikowane ponownie |
Dlaczego ładunek jest dzielony w ten sposób, wyjaśnia sekcja Mosty czatu.
Konfiguracja, zanim pojawi się tura
Dział zatytułowany „Konfiguracja, zanim pojawi się tura”Karta otwiera się, gdy wzmianka zostanie przyjęta, przed klonowaniem i przed pierwszym tokenem; następująca tura przejmuje tę samą kartę i strumień. Narracja po tym pochodzi ze zdarzenia SpaceProvisioningChanged w magistrali zdarzeń domenowych — ten sam postęp, który baner konfiguracji w aplikacji desktopowej odczytuje z wiersza przestrzeni.
| Stan konfiguracji | Narracja |
|---|---|
| Wzmianka przyjęta | Working on it… |
Krok repo |
Cloning <repo>… |
Krok prCheckout |
Checking out the pull request in <repo>… |
Krok script |
Running the setup script for <repo>… |
Krok agent |
Setting up <agent>… |
provisioning, jeszcze bez kroku |
Preparing the workspace… |
ready |
Starting the agent… |
| Agent rozumuje | Thinking… |
failed |
Workspace setup failed — details are in Control Center. |
cancelled |
Workspace setup was stopped — details are in Control Center. |
Narracja konfiguracji wymaga wszystkich czterech warunków:
| Warunek |
|---|
| Dostawca renderuje karty |
| Strumieniowanie jest dostępne na tym połączeniu |
| Przestrzeń ma żądanie czatu w toku |
| Żadna karta nie raportuje już tam tury |
Żądanie pozostaje w toku, dopóki nie zacznie się tura albo nie zawiedzie konfiguracja. Zdarzenie ready bez już otwartej karty oznacza ciepłą przestrzeń i pozostaje ciche, a konfiguracja, na którą nikt w czacie nie czeka — rozmowa otwarta w aplikacji, osierocona rozmowa wznowiona przy starcie — nie tworzy żadnej karty.
Strona przekierowania /open
Dział zatytułowany „Strona przekierowania /open”Produkty czatowe przyjmują w linku http(s) i nic więcej, więc wezwanie do działania nie może wprost nazwać schematu aplikacji desktopowej.
| Właściwość | Wartość |
|---|---|
| Trasa | GET /open/workspaces/<workspaceId>/(spaces|tickets)/<id> |
| Pochodzenie | Wyprowadzane z publicznego adresu URL serwera (ws → http, wss → https); pętla zwrotna jest zachowywana |
| Odpowiedź | Niewielka strona HTML bez buforowania, która przechodzi do control-center://workspaces/<workspaceId>/(spaces|tickets)/<id> i pokazuje ręczny przycisk |
| Walidacja | Identyfikatory muszą pasować do [A-Za-z0-9_.-]{1,128}; wszystko inne to 404 |
| Dostęp | Publiczny i bierny — nie czyta żadnej bazy danych, więc nie jest wyrocznią istnienia; autoryzację wykonuje aplikacja, którą otwiera |
Pola profilu bota
Dział zatytułowany „Pola profilu bota”| Pole | Limit | Uwagi |
|---|---|---|
appName |
1–35 znaków | Domyślnie Control Center · <workspace name> |
botDisplayName |
1–80 znaków | Domyślnie control-center |
description |
≤ 140 znaków | |
agentDescription |
≤ 300 znaków | Pokazywane nad wiadomością prywatną z botem |
command |
≤ 32 znaków | Normalizowana: wiodące ukośniki usuwane, zamiana na małe litery, [^a-z0-9_-] usuwane, pusta wartość wraca do cc |
agentEnabled |
— | Czy doświadczenie wiadomości prywatnych i agenta jest udostępniane |
Puste pole oznacza „nie zmieniaj”, a nie „wyczyść”. Limity należą do Slacka i są najostrzejsze spośród modelowanych produktów.
Kody połączenia
Dział zatytułowany „Kody połączenia”| Właściwość | Wartość |
|---|---|
| Długość | 6 znaków |
| Alfabet | 23456789ABCDEFGHJKLMNPQRSTVWXYZ (bez 0/O, 1/I, U) |
| Czas życia | 15 minut |
| Użycia | Jedno |
| Przechowywanie | W pamięci — restart serwera unieważnia niewykorzystane kody |
| Zakres | Jeden obszar roboczy i jeden dostawca; wygenerowanie nowego kodu unieważnia poprzedni kod członka |
Realizacja kodu jest dopasowywana bez rozróżniania wielkości liter. Nieznane, wygasłe kody oraz kody z obcego obszaru roboczego lub od złego dostawcy zawodzą celowo w identyczny sposób.
Metody połączenia
Dział zatytułowany „Metody połączenia”| Metoda | Wartość protokołu | Sposób |
|---|---|---|
| Code | code |
Członek zrealizował /cc link <code> |
email |
Zweryfikowany adres e-mail dostawcy pasował do użytkownika, który jest już członkiem obszaru roboczego |
Operacje RPC
Dział zatytułowany „Operacje RPC”Wszystkie są ograniczone do obszaru roboczego. Serwer jest bezstanowy, więc każde wywołanie niesie własny workspace_id w argumentach; dyspozytor odrzuca operację ograniczoną do obszaru roboczego, która go pomija, jeszcze przed otwarciem jakiejkolwiek bazy danych. Dane uwierzytelniające podróżują wyłącznie do środka — odczyty statusu nigdy ich nie zwracają.
| Operacja | Rodzaj | Minimalna rola | Klasy akcji |
|---|---|---|---|
chat.providers |
read | guest |
— |
chat.status |
read | guest |
— |
chat.connect |
mutate | admin |
secretAccess, networkEgress |
chat.disconnect |
destructive | admin |
secretAccess |
chat.listUserLinks |
read | guest |
— |
chat.beginUserLink |
mutate | member |
— |
chat.unlinkUser |
mutate | member dla siebie, admin dla każdego innego |
— |
chat.createApp |
mutate | admin |
secretAccess, networkEgress |
chat.setupLink |
read | admin |
— |
chat.botProfile |
read | admin |
networkEgress |
chat.updateBotProfile |
mutate | admin |
networkEgress |
Operacje odczytu dziedziczą próg guest ze swojego rodzaju; mutacje bez jawnego progu wymagają member.
chat.setupLink składa adres URL tworzenia aplikacji u dostawcy z profilu bota. Nie deklaruje żadnej klasy akcji, bo nie czyta żadnego sekretu i niczego nie wywołuje — jedyne wywołanie wykonuje przeglądarka użytkownika.
Powierzchnię dopełnia jedno reaktywne zapytanie:
| Zapytanie | Rodzaj | Emituje |
|---|---|---|
chat.watchUserLinks |
watch | Listę członków, wysyłaną ponownie za każdym razem, gdy połączenie powstanie lub zostanie usunięte |
Istnieje, ponieważ połączenie następuje po drugiej stronie: członek wpisuje jednorazowy kod do bota, więc żadna odpowiedź klienta nie może przenieść odpowiedzi z powrotem. Lista w ustawieniach i otwarte okno „Połącz moje konto” śledzą je oba, a okno przechodzi do potwierdzenia w chwili, gdy dotrze połączenie samego członka.
chat.beginUserLink zawsze generuje kod dla tożsamości samego wywołującego. chat.updateBotProfile zwraca remaining_step tylko wtedy, gdy pozostaje krok (zwykle ponowna instalacja); jego brak oznacza, że zmiana już działa.
chat.providers zwraca jeden wpis na każdego oferowanego dostawcę — deskryptor, a gdy istnieje, także status połączenia. Wszystko, co renderuje interfejs ustawień, pochodzi z tego ładunku — dlatego dodanie dostawcy to zmiana wyłącznie po stronie serwera.
Przechowywanie
Dział zatytułowany „Przechowywanie”| Co | Gdzie |
|---|---|
| Dane uwierzytelniające połączenia | <dataDir>/<workspaceId>/chat_credentials/<provider>.json |
| Niedokończona konfiguracja z przewodnikiem | <dataDir>/<workspaceId>/chat_credentials/<provider>_setup.json |
| Starsze pliki Slacka | <dataDir>/<workspaceId>/slack_credentials.json oraz slack_app_setup.json, odczytane raz i zmigrowane na miejscu |
Dane uwierzytelniające leżą obok bazy danych obszaru roboczego, a nie w niej: usunięcie obszaru roboczego zabiera ze sobą jego tokeny czatu, a workspace.export lub kopia zapasowa kopiuje workspace.db — obszar roboczy przekazany komuś innemu nie nosi więc aktywnych tokenów bota. Zapisy są atomowe (plik tymczasowy plus zmiana nazwy) i ograniczone do samego właściciela.
Tabele bazy danych
Dział zatytułowany „Tabele bazy danych”Obie leżą w bazie danych obszaru roboczego, która zawiera skondensowaną bazę odniesienia v1 — odczyt między obszarami roboczymi się więc nie skompiluje.
chat_space_links — jedna rozmowa zewnętrzna ↔ jedna przestrzeń Control Center:
| Kolumna | Uwagi |
|---|---|
id |
UUID v4 |
workspace_id |
Zakres obszaru roboczego |
provider |
ChatProvider.wire |
external_team_id |
Zespół Slacka T…, pusty dla dostawców bez tego pojęcia |
external_channel_id |
Kanał Slacka C…, grupa G…, wiadomość prywatna D… |
external_thread_id |
Kotwica wątku Slacka albo null, gdy cała rozmowa jest kotwicą (wiadomości prywatne do bota) |
cc_space_id |
REFERENCES spaces(id) ON DELETE CASCADE |
created_by_user_id, created_at, last_activity_at |
Unikalny dla (workspace_id, provider, external_channel_id, external_thread_id), z indeksem częściowym wymuszającym to samo dla pustych identyfikatorów wątku (SQLite traktuje NULL-e jako odrębne).
chat_user_links — jeden członek zewnętrzny ↔ jeden użytkownik Control Center:
| Kolumna | Uwagi |
|---|---|
id |
UUID v4 |
workspace_id |
Zakres obszaru roboczego |
provider |
ChatProvider.wire |
external_team_id, external_user_id |
Członek Slacka U… |
user_id |
Użytkownik Control Center (globalny, więc bez klucza obcego) |
method |
code lub email |
linked_at |
Unikalny dla (workspace_id, provider, external_team_id, external_user_id) i dla (workspace_id, provider, user_id) — przypisanie jednowartościowe w obu kierunkach, przy czym jedna osoba może być połączona z kilkoma dostawcami.
Połączenie to ustalenie tożsamości, nie nadanie dostępu: członkostwo jest sprawdzane od nowa przy każdym zdarzeniu przychodzącym, więc połączenie należące do członka, który został w międzyczasie usunięty, kończy się odmową.
Rodzaj przestrzeni i metadane wiadomości
Dział zatytułowany „Rodzaj przestrzeni i metadane wiadomości”Połączona przestrzeń jest tworzona z SpaceKind dostawcy (slack). Zachowuje się jak zwykła przestrzeń dla ludzi — powiadamia i grupuje się jak topic — a isExternalChat to sprawdzenie, przez które przechodzi każde zachowanie (odbicie, plakietki, retencja).
Każda wiadomość, którą most wnosi, nosi stempel metadata['chat']:
{ "chat": { "provider": "slack", "teamId": "T024BE7LD", "channelId": "C0G9QF9GW", "threadId": "1700000000.000100", "messageId": "1700000000.000200", "userId": "U024BE7LH", "userLabel": "sam" }}Stempel jest także zabezpieczeniem przed echem: odbicie wychodzące pomija każdą wiadomość, która go niesie, co powstrzymuje wiadomość przychodzącą z czatu przed natychmiastowym opublikowaniem z powrotem.
Zachowanie przekazywania
Dział zatytułowany „Zachowanie przekazywania”| Zachowanie | Szczegóły |
|---|---|
| Co jest przekazywane na zewnątrz | Wyłącznie tekst agenta plus wiersz statusu karty zadania. Proza rozumowania i dane wyjściowe narzędzi zostają w Control Center |
| Tempo strumieniowania | Ograniczane do jednego wysłania na sekundę w trakcie tury; karta i tekst, który ją objaśnia, podróżują w tym samym wywołaniu |
| Wiadomości pisane przez ludzi w Control Center | Odbijane do połączonego wątku, z nazwą wyświetlaną autora jako prefiksem |
| Puste tury | Raportowane jako krótka notatka (uruchomienie nie powiodło się, zostało przerwane albo zatrzymane na limicie tur), a nie cisza |
| Deduplikacja | Kluczowana identyfikatorem zdarzenia samego dostawcy; zapamiętywane jest ostatnie 512 |
| Agent pierwszego kontaktu | Nowa połączona rozmowa budzi agenta CEO obszaru roboczego, w przeciwnym razie jego pierwszego agenta, a w ostateczności nikogo |
| Nazywanie przestrzeni | #channel · <request> dla wątku kanału Slacka, Slack DM · <request> dla wiadomości prywatnej, tytuły ograniczone do 48 znaków |
| Izolacja awarii | Jedno złe zdarzenie nigdy nie przewraca mostu; połączenie obsługuje dalej każdą inną rozmowę |
Zobacz też
Dział zatytułowany „Zobacz też”- Skonfiguruj integrację Slack
- Połącz konto Slack
- Dostosuj bota czatu
- Mosty czatu
- Guardraile o klasach akcji, które deklarują operacje