İçeriğe geç

Sohbet köprüsü

Sağlayıcı Tel değeri Taşıma Alan türü
Slack slack Socket Mode (giden WSS) slack

Tek sağlayıcı Slack’tir. ChatProvider tek değerli bir enum’dur ve cc_server tek bir eklenti kaydeder. Şema, her arama ve her benzersiz indeks provider üzerine anahtarlanmıştır; böylece kimlikler sağlayıcılar arasında geçmez ve yeni bir sağlayıcı eklemek yalnızca sunucuyu ilgilendiren bir değişikliktir.

Her çalışma alanı × sağlayıcı için bir sağlayıcı tarafı uygulama.

Komut adı uygulama başına belirlenir (varsayılan olarak cc, yani /cc). Bir yönetici bu adı değiştirebilir; köprü de o andan sonra en son hangi adla çağrıldıysa onu kullanır.

Komut Etkisi
/cc help (veya fiilsiz /cc) Botun neler yapabileceğini listeler
/cc link <code> Tek kullanımlık bir kodu kullanır ve gönderenin sohbet kimliğini bağlar
/cc ticket <title> Bağlı üyenin bildirdiği yerel bir bilet açar
/cc ticket <title> | <description> Aynısı; ilk | sonrasındaki her şey açıklama olur
Bilinmeyen fiil Bilinmeyen fiili ve yardım metnini bildirir

Bir ajana ulaşmanın yolları:

Hareket Davranış
Bir kanalda @bot … Bir Slack dizisi ve ona karşılık gelen bir Control Center alanı açar; ajan Slack dizisinde yanıtlar
Köprülenmiş bir Slack dizisinde yanıt Aynı Control Center alanını sürdürür — anma gerekmez
Bir kanalda düz ileti Yok sayılır (bota hitap etmiyor ve köprülenmiş bir Slack dizisinde değil)
Bota DM Her DM konuşması için bir Control Center alanı; ajan çalışırken bir Slack dizi başlığı ve “düşünüyor…” durumu ayarlar

Bağlantı iletişim kutusunu üreten ve gönderimi doğrulayan sağlayıcı tanımlayıcısı tarafından bildirilir.

Alan kimliği Etiket Zorunlu Önek Bulunduğu yer
botToken Bot kullanıcısı OAuth token’ı Evet xoxb- OAuth & Permissions
appToken Uygulama düzeyi token Evet xapp- Basic Information → App-Level Tokens, scope connections:write
configRefreshToken Uygulama yapılandırma yenileme token’ı Hayır xoxe App configuration tokens on api.slack.com/apps

configRefreshToken uygulama yönetimi kimlik bilgisidir: onsuz bağlantı çalışır ama bot Control Center’dan oluşturulamaz veya düzenlenemez. Her kullanımda rotasyona uğrar ve döndürülen değer anında saklanır.

Değerlerin başındaki ve sonundaki boşluklar kırpılır, bildirilmemiş anahtarlar atılır ve önek uyuşmazlığı istemcide ve sunucuda aynı cümleyle reddedilir. Zorunlu alanlar her bağlantıda dolu olmalıdır; boş bırakılan isteğe bağlı bir alan, zaten saklanmış olan değeri korur.

Bot token kapsamları:

app_mentions:read
assistant:write
channels:history
chat:write
commands
groups:history
im:history
users:read
users:read.email

Bot olay abonelikleri:

app_home_opened
app_mention
message.channels
message.groups
message.im

Control Center’ın uygulamayı oluştururken veya düzenlerken dayattığı yapısal ayarlar: Socket Mode etkin, istek URL’si yok, Messages sekmesi etkin ve yazılabilir, bot always_online, gerekli kapsamlar ve olaylar uygulamanın hâlihazırda sahip olduklarıyla birleştirilir (asla çıkarılmaz) ve File a ticket or link your Control Center account açıklamasını taşıyan tek bir slash komutu — dışa aktarılan bir manifestte Control Center’ın kendi komutunu tanımlayan işaret.

Durum Tel Anlamı
Bağlı değil disconnected Bu çalışma alanı × sağlayıcı için saklanmış kimlik bilgisi yok
Bağlanıyor… connecting Kimlik bilgileri saklandı, taşıma bağlanıyor veya yeniden bağlanıyor
Canlı connected Taşıma ayakta ve olay alıyor
Bağlantı hatası error Saklandı ama başarısız oluyor; sağlayıcının kendi hatası yanında gösterilir

Yeniden bağlanma, jitter eklenmiş ve 30 saniyeyle sınırlanmış üstel geri çekilmedir. Sağlayıcının başlattığı bir soket rotasyonu, geri çekilmeyi artırmadan hızla yeniden bağlanır. Reddedilen bir kimlik bilgisi (invalid_auth, not_authed, token_revoked, account_inactive, token_expired, invalid_app_id) veya eksik bir kapsam nihaidir: köprü, yeni kimlik bilgileri gelene kadar yeniden denemeyi bırakır.

Köprü en zengin yüzeye göre yazılmıştır ve yetenek başına kademeli olarak azalır.

Yetenek Slack Yokluğunda etkisi
streaming evet Yanıtın tamamı, sonunda bir kez gönderilir
streamingRequiresThread evet Dizi çapası olmayan bir yanıt hedefi, yanıtları bütün olarak gönderir
ephemeralMessages evet Kullanılabilir bir yanıt tanıtıcısı olmayan bir slash komutu yanıtı düşürülür (redler her zaman dizi içinde gönderilir)
threadStatus evet Geçici “düşünüyor…” satırı olmaz
threadTitle evet Sohbet dizisi varsayılan başlığını korur
slashCommands evet /cc yüzeyi olmaz
taskCards evet Yalnızca metin — yanıtın üstünde kart yok ve “View in Control Center” bağlantısı yok
maxMessageLength 39.000 Daha uzun yanıtlar, Control Center’a işaret eden bir ifadeyle kısaltılır
maxStreamChunkLength 3.800 Eklemeler bir paragraf, satır veya boşluk sınırından bölünür

Akış bildirmek, akış vaat etmek değildir: Slack’inki ücretli bir planda Agents & AI Apps özelliğini gerektirir. Çağrı anındaki bir ret (streaming_not_supported, feature_not_enabled, paid_only, …) bağlantının ömrü boyunca hatırlanır ve streamingAvailable: false olarak bildirilir. Slack’in görev kartları aynı çağrıya biner; bu yüzden kartın görüntüleme modunu reddeden bir Slack akışını korur ve yalnızca kartı kaybeder — bir kez, bağlantının ömrü boyunca.

Bir akışın ayrıca kime olduğunu, yani okuyucusunu adlandırması gerekir. Slack, bir akışı bir kanalda açmak için hem bir alıcı kullanıcı hem de o kullanıcının ekibini ister (DM istemez) ve aksi halde missing_recipient_user_id / missing_recipient_team_id ile reddeder — bu çağrı başına bir rettir; bu yüzden köprü denemeye devam eder ve bu sırada tur, tek bir gönderilmiş yanıt olarak ulaşır. Alıcı, soran kişidir ve gelen iletiden alınır (uygulamanın ekibi değil, kişinin kendi ekibi; böylece bir Slack Connect kanalı doğru çözümlenir). Sohbetten kimsenin başlatmadığı bir tur için — Control Center’da, zaten köprülenmiş bir konuşma üzerinde başlatılan iş — bu, bağlantıyı kuran üyedir; o kişi sohbet hesabının bağlantısını o sırada kaldırmışsa, o tur akış yerine bütün olarak gönderilir.

Ajan turu başına, her adım için bir satırı olan gruplanmış tek kart (task_display_mode: plan). Her satır id + title + status içeren bir task_update’tir; düşünce hazır olduğunda buna tek seferlik bir details eklenir. Aynı kimliğe sahip details ve output ayraç olmadan birleşir; bu yüzden details bir kez gönderilir ve output asla akış halinde gönderilmez. Planın başlığı istektir; yanıt ise markdown_text parçası taşıyan, sonradan gelen ayrı bir eklemedir.

Bölüm İçerik
Plan başlığı Ne istendiği
Kurulum satırı Working on it…, ardından Cloning …, ardından Starting the agent… — tek satır, başlığı değiştirilir
Düşünme satırı Thinking…, ajan akıl yürütmeye başladığında eklenir; düşünce bu satırın details değeridir ve akıl yürütme bittiğinde bir kez gönderilir
Araç satırları Her araç için bir satır (Bash which swift), yan yana durmaları için benzersiz kimlik
Durum O satır çalışırken devam ediyor; sonraki satır başladığında veya tur bittiğinde tamamlandı; başarısız, kesintiye uğramış ve tur sınırı için hata
Eylem çağrısı Tur bittiğinde sondaki satır olarak View in Control Center — iş hâlâ sürerken yoktur ve sunucunun erişilebilir genel URL’si yoksa da yoktur

Bir kartın asla taşımadığı şeyler: araç çıktısı, o izin listesinin dışında bir argüman veya veritabanından okunan herhangi bir şey. Akıl yürütme metni yalnızca Thinking… satırının ayrıntılarıdır (256 karakterle sınırlıdır), ileti gövdesi değildir. Yeni bir şey söylemeyecek bir kart yeniden gönderilmez. Bir anma akışı hemen açar, böylece Slack dizisi sessiz kalmaz; ardından hiç metin üretmeyen bir tur, ikinci bir ileti göndermek yerine aynı kartı kısa bir notla tamamlar. Akışı hiç açmamış bir alanda sözsüz geçen bir tur (kart yok ya da akış zaten reddedilmiş) yine de tamamlanmış kartı ve notu taşıyan tek bir ileti gönderir.

Akış halinde gönderilen ve gönderilen kartlar farklı yüklerdir:

Biçim Yapı Düz metin
Akış halinde plan_update artı id ile anahtarlanmış task_update parçaları Düz dize, parça başına 256 karakterle sınırlı
Gönderilen task_id ile anahtarlanmış task_card’ları saran bir plan bloğu Zengin metin

Hata işleme:

Durum Davranış
Sağlayıcı bir eklemede kartı reddeder Ekleme, kartsız olarak hemen yeniden denenir; düz metin yine canlı ulaşır ve kartlar bağlantının ömrü boyunca düşürülür
Sağlayıcı düz metni de reddeder Akış kapatılır ve yanıt bütün olarak gönderilir
Yanıtın bir kısmı ulaştıktan sonra akış kopar Akış kapatılır ve hiçbir şey yeniden gönderilmez

Yükün neden bu şekilde bölündüğü için bkz. Sohbet köprüleri.

Kart, bir anma kabul edildiğinde, klonlamadan ve ilk token’dan önce açılır; ardından gelen tur aynı kartı ve akışı devralır. Sonrasındaki anlatım, alan olay veri yolundaki SpaceProvisioningChanged olayından gelir — masaüstünün hazırlama şeridinin alan satırından okuduğu ilerlemenin aynısı.

Hazırlama durumu Anlatım
Anma kabul edildi Working on it…
repo adımı Cloning <repo>…
prCheckout adımı Checking out the pull request in <repo>…
script adımı Running the setup script for <repo>…
agent adımı Setting up <agent>…
provisioning, henüz adım yok Preparing the workspace…
ready Starting the agent…
Ajan akıl yürütüyor Thinking…
failed Workspace setup failed — details are in Control Center.
cancelled Workspace setup was stopped — details are in Control Center.

Kurulum anlatımı dört koşulun hepsini gerektirir:

Koşul
Sağlayıcı kartları görüntülüyor
Akış bu bağlantıda kullanılabilir
Alanda uçuşta bir sohbet isteği var
Orada bir turu zaten bildiren bir kart yok

İstek, bir tur başlayana veya kurulum başarısız olana kadar uçuşta kalır. Zaten açık bir kart yokken gelen bir ready olayı sıcak bir alandır ve sessiz bırakılır; sohbette kimsenin beklemediği bir hazırlama — uygulamada açılmış bir konuşma ya da açılışta devam ettirilen başıboş bir konuşma — hiç kart üretmez.

Sohbet ürünleri bir bağlantıda http(s) dışında hiçbir şey kabul etmez; bu yüzden bir eylem çağrısı masaüstünün şemasını doğrudan adlandıramaz.

Özellik Değer
Rota GET /open/workspaces/<workspaceId>/(spaces|tickets)/<id>
Köken Sunucunun genel URL’sinden türetilir (ws → http, wss → https); loopback korunur
Yanıt control-center://workspaces/<workspaceId>/(spaces|tickets)/<id> adresine giden ve elle basılacak bir düğme gösteren küçük, no-store bir HTML sayfası
Doğrulama Kimlikler [A-Za-z0-9_.-]{1,128} ile eşleşmelidir; başka her şey 404’tür
Erişim Herkese açık ve etkisiz — hiçbir veritabanı okumaz, dolayısıyla bir varlık sorgusu değildir; yetkilendirmeyi açtığı uygulama yapar
Alan Sınır Notlar
appName 1–35 karakter Varsayılanı Control Center · <workspace name>
botDisplayName 1–80 karakter Varsayılanı control-center
description ≤ 140 karakter
agentDescription ≤ 300 karakter Botla bir DM’in üstünde gösterilir
command ≤ 32 karakter Normalleştirilir: baştaki eğik çizgiler kaldırılır, küçük harfe çevrilir, [^a-z0-9_-] silinir, boşsa cc değerine düşer
agentEnabled — DM/ajan deneyiminin sunulup sunulmadığı

Boş bir kutu “dokunma” anlamına gelir, “temizle” değil. Sınırlar Slack’inkilerdir; modellenen ürünler arasında en dar olanlar bunlardır.

Özellik Değer
Uzunluk 6 karakter
Alfabe 23456789ABCDEFGHJKLMNPQRSTVWXYZ (0/O, 1/I, U yok)
Ömür 15 dakika
Kullanım Bir kez
Depolama Bellekte — sunucu yeniden başlatıldığında bekleyen kodlar geçersiz olur
Kapsam Bir çalışma alanı ve bir sağlayıcı; yeni bir kod üretmek üyenin önceki kodunu geçersiz kılar

Kod kullanımı, büyük/küçük harf ayrımı gözetilmeden eşleştirilir. Bilinmeyen, süresi geçmiş, başka bir çalışma alanına ait ve yanlış sağlayıcıya ait kodların tümü bilinçli olarak aynı şekilde başarısız olur.

Yöntem Tel Nasıl
Kod code Üye /cc link <code> komutunu kullandı
E-posta email Sağlayıcının doğrulanmış e-postası, zaten çalışma alanı üyesi olan bir kullanıcıyla eşleşti

Tümü çalışma alanı kapsamlıdır. Sunucu durumsuzdur; bu yüzden her çağrı kendi workspace_id değerini argümanlarda taşır ve dağıtıcı, workspace_id değerini atlayan çalışma alanı kapsamlı bir işlemi herhangi bir veritabanı açılmadan önce reddeder. Kimlik bilgileri yalnızca içeri girer — durum okumaları onları asla geri döndürmez.

İşlem Tür En düşük rol Eylem sınıfları
chat.providers okuma guest —
chat.status okuma guest —
chat.connect değişiklik admin secretAccess, networkEgress
chat.disconnect yıkıcı admin secretAccess
chat.listUserLinks okuma guest —
chat.beginUserLink değişiklik member —
chat.unlinkUser değişiklik kendiniz için member, başkası için admin —
chat.createApp değişiklik admin secretAccess, networkEgress
chat.setupLink okuma admin —
chat.botProfile okuma admin networkEgress
chat.updateBotProfile değişiklik admin networkEgress

Okuma işlemleri guest tabanını türlerinden devralır; açık bir tabanı olmayan değişiklikler member gerektirir.

chat.setupLink, bot profilinden bir sağlayıcı uygulama oluşturma URL’si oluşturur. Hiçbir sır okumadığı ve hiçbir yere bağlanmadığı için bir eylem sınıfı bildirmez — tek çağrıyı kullanıcının kendi tarayıcısı yapar.

Yüzeyi tek bir reaktif sorgu tamamlar:

Sorgu Tür Yaydığı
chat.watchUserLinks izleme Kadro; bir bağlantı kurulduğunda veya kaldırıldığında yeniden gönderilir

Bu sorgu, bağlama işi diğer tarafta gerçekleştiği için vardır: üye tek kullanımlık kodu bota yazar, dolayısıyla hiçbir istemci yanıtı cevabı geri taşıyamaz. Ayarlardaki kadro ve açık “hesabımı bağla” iletişim kutusu bunu izler; üyenin kendi bağlantısı geldiği anda iletişim kutusu bir onaya döner.

chat.beginUserLink her zaman çağıranın kendi kimliği için bir kod üretir. chat.updateBotProfile, yalnızca geriye bir adım kaldığında (tipik olarak bir yeniden yükleme) bir remaining_step döndürür; bunun yokluğu, düzenlemenin etkin olduğu anlamına gelir.

chat.providers, sunulan her sağlayıcı için bir girdi döndürür — tanımlayıcı ve varsa bağlantı durumu. Ayarlar arayüzünün görüntülediği her şey bu yükten gelir; bir sağlayıcı eklemenin yalnızca sunucuyu ilgilendiren bir değişiklik olmasının nedeni budur.

Ne Nerede
Bağlantı kimlik bilgileri <dataDir>/<workspaceId>/chat_credentials/<provider>.json
Yarım kalmış rehberli kurulum <dataDir>/<workspaceId>/chat_credentials/<provider>_setup.json
Eski Slack dosyaları <dataDir>/<workspaceId>/slack_credentials.json ve slack_app_setup.json; bir kez okunur ve yerinde taşınır

Kimlik bilgileri, çalışma alanının veritabanının içinde değil yanında durur: bir çalışma alanını silmek sohbet token’larını da onunla götürür ve workspace.export veya bir yedek workspace.db dosyasını kopyalar — böylece başkasına verilen bir çalışma alanı canlı bot token’ları taşımaz. Yazmalar atomiktir (geçici dosya artı yeniden adlandırma) ve yalnızca sahibinin erişimine sıkılaştırılır.

İkisi de çalışma alanı veritabanında yaşar; bu veritabanı sıkıştırılmış bir v1 temeli taşır — bu yüzden çalışma alanları arası bir okuma derlenmez.

chat_space_links — bir harici konuşma ↔ bir Control Center alanı:

Sütun Notlar
id UUID v4
workspace_id Çalışma alanı kapsamı
provider ChatProvider.wire
external_team_id Slack ekibi T…, bu kavramı olmayan sağlayıcılarda boş
external_channel_id Slack kanalı C…, grup G…, DM D…
external_thread_id Slack dizi çapası veya konuşmanın tamamı çapa olduğunda (bot DM’leri) null
cc_space_id REFERENCES spaces(id) ON DELETE CASCADE
created_by_user_id, created_at, last_activity_at

(workspace_id, provider, external_channel_id, external_thread_id) üzerinde benzersizdir; null dizi kimlikleri için de aynısını uygulayan kısmi bir indeks vardır (SQLite NULL’ları birbirinden farklı sayar).

chat_user_links — bir harici üye ↔ bir Control Center kullanıcısı:

Sütun Notlar
id UUID v4
workspace_id Çalışma alanı kapsamı
provider ChatProvider.wire
external_team_id, external_user_id Slack üyesi U…
user_id Control Center kullanıcısı (genel, bu yüzden yabancı anahtar yok)
method code veya email
linked_at

(workspace_id, provider, external_team_id, external_user_id) ve (workspace_id, provider, user_id) üzerinde benzersizdir — aynı kişi birden çok sağlayıcıda bağlı olabilirken her iki yönde de tek değerli atıf sağlar.

Bir bağlantı, kimlik çözümlemesidir, bir erişim izni değildir: üyelik her gelen olayda yeniden denetlenir; böylece sonradan çıkarılmış bir üyeye ait bağlantı bir redde çözümlenir.

Köprülenmiş bir alan, sağlayıcının SpaceKind değeriyle (slack) oluşturulur. Sıradan, insana yönelik bir alan gibi davranır — topic gibi bildirilir ve bölümlere ayrılır — ve her davranışın (aynalama, rozetleme, saklama) içinden geçtiği denetim isExternalChat’tir.

Köprünün içeri getirdiği her ileti bir metadata['chat'] damgası taşır:

{
"chat": {
"provider": "slack",
"teamId": "T024BE7LD",
"channelId": "C0G9QF9GW",
"threadId": "1700000000.000100",
"messageId": "1700000000.000200",
"userId": "U024BE7LH",
"userLabel": "sam"
}
}

Damga aynı zamanda yankı korumasıdır: dışa dönük aynalama, onu taşıyan her iletiyi atlar; sohbetten gelen bir iletinin doğrudan geri gönderilmesini engelleyen şey budur.

Davranış Ayrıntı
Dışarı aktarılan Yalnızca ajan metni ve görev kartının durum satırı. Akıl yürütme metni ve araç çıktısı Control Center’da kalır
Akış temposu Bir tur sürerken saniyede bir boşaltmaya kısılır; kart ve açıkladığı metin aynı çağrıda gider
Control Center’da yazılan insan iletileri Yazarın görünen adı öne eklenerek bağlı diziye yansıtılır
Boş turlar Sessizlik yerine kısa bir not olarak bildirilir (çalıştırma başarısız oldu, kesintiye uğradı veya tur sınırında durdu)
Yinelenenleri ayıklama Sağlayıcının kendi olay kimliğine göre anahtarlanır; son 512 tanesi hatırlanır
Ön kapı ajanı Yeni köprülenmiş bir konuşma, çalışma alanının CEO ajanını uyandırır; o yoksa ilk ajanını, o da yoksa kimseyi
Alan adlandırma Bir Slack kanal dizisi için #channel · <request>, bir DM için Slack DM · <request>; başlıklar 48 karakterle sınırlıdır
Hata yalıtımı Tek bir hatalı olay köprüyü asla düşürmez; bağlantı diğer tüm konuşmalara hizmet etmeye devam eder