Bu rehberde: Panelin canlı güncellemelerini (kutuların yeşile dönmesi, ajan adımlarının akması, yeni mesajlar) kendi aracınızda nasıl dinleyeceğinizi öğrenirsiniz. Bu rehber yazılımcılar içindir.
⏱ 12 dakika
Kısaca
SSE (Server-Sent Events), sunucunun tarayıcıya veya programınıza canlı olay "akıtmasıdır". Panel bunu kullanır: bir çalıştırmayı izlerken kutuların sırayla yeşile dönmesi SSE sayesindedir. Sunucudan sunucuya kalıcı entegrasyon için giden webhook'lar daha uygundur.


Genel bilgi
Server-Sent Events (SSE), OrqLabs'un canlı güncellemeleri tarayıcıya ve istemcilere ittiği mekanizmadır: iş akışı çalıştırmasında node'ların yeşile dönmesi, ajan adımlarının akması, Gelen Kutusu'nda yeni mesajın belirmesi. Panel bunları kullanır; siz de kendi araçlarınızda kullanabilirsiniz. Sunucudan sunucuya kalıcı entegrasyon için giden webhook'lar daha uygundur.
Üç akış
| Akış | Uç nokta | İçerik |
|---|---|---|
| Çalıştırma | GET /orgs/:orgId/runs/:runId/events | ExecutionEvent – önce kayıtlı olaylar tekrar oynatılır (replay), sonra canlı |
| Ajan çalıştırması | GET /orgs/:orgId/agent-runs/:id/events | { type: "step", step: AgentStep } ve { type: "done", run } |
| Organizasyon | GET /orgs/:orgId/events | Bildirimler, onay istekleri, konuşma mesajları, run durumları, ajan adımları (özet) |
Yanıt Content-Type: text/event-stream; bağlantı açık kalır, her 25 saniyede bir yorum satırı (: ping) ile canlı tutulur.
Zarf biçimi
event: node.finished
id: 42
data: {"type":"node.finished","runId":"run_01J…","nodeId":"n2","at":"2026-09-26T09:14:05.020Z","itemCount":3,"durationMs":41230}
event: notification
id: 43
data: {"id":"ntf_…","title":"Onay bekliyor","body":"Approve LINKEDIN post","link":"/app/acme/approvals","createdAt":"…"}
event alanı olay türüdür (ExecutionEvent.type, notification, conversation.message, approval.requested, agent.step, run.status); data JSON'dur; id artan sıra numarasıdır ve yeniden bağlanmada kullanılır.
Çalıştırma akışı (ExecutionEvent)
| type | Alanlar | Anlamı |
|---|---|---|
run.started | runId, workflowId, at | Run başladı |
node.started | runId, nodeId, at, attempt | Node çalışmaya başladı (attempt > 1 yeniden deneme) |
node.finished | runId, nodeId, at, itemCount, durationMs | Node bitti |
node.failed | runId, nodeId, at, error, willRetry | Node hata verdi; willRetry true ise yeniden denenecek |
node.waiting | runId, nodeId, at, until? | Onay/bekleme; run WAITING |
run.finished | runId, at, status, costUsd | Run bitti (SUCCEEDED/FAILED/CANCELED) |
log | runId, nodeId?, at, level, message | Node logları (data.code console.log, uyarılar) |
Bağlandığınızda o ana kadar kaydedilmiş olaylar sırayla gönderilir (replay), ardından canlı olaylar gelir; biten bir run için replay sonrasında run.finished ile akış kapanır. Node çıktıları (item'lar) SSE ile gönderilmez; GET /orgs/:orgId/runs/:runId ile alın.
Ajan çalıştırması akışı
event: step
data: {"type":"step","step":{"index":3,"type":"tool_call","at":"…","name":"web_search","input":{"query":"Türkiye kahve pazarı 2026"}}}
event: step
data: {"type":"step","step":{"index":4,"type":"tool_result","at":"…","name":"web_search","output":"[10 sonuç]","durationMs":812}}
event: done
data: {"type":"done","run":{"id":"ar_…","status":"succeeded","summary":"…","usage":{"inputTokens":48210,"outputTokens":3120,"costUsd":0.13}}}
AgentStep.type: thinking, message, tool_call, tool_result, error, handoff. Uzun output değerleri kısaltılır; tam adımlar GET /agent-runs/:id. done sonrasında akış kapanır.
Organizasyon akışı
| event | data | Kaynak |
|---|---|---|
notification | Notification nesnesi | Onay isteği, devir, yayın hatası, rapor, bütçe |
approval.requested | { approvalId, title, runId, nodeId, expiresAt } | utility.approval, ajan onayları |
conversation.message | { conversationId, channel, message: { id, direction, sender, text, at } } | Gelen ve giden mesajlar |
run.status | { runId, workflowId, status, costUsd? } | Run durum değişimleri (özet) |
agent.step | { agentRunId, type, index, name? } | Ajan adımı (özet; ayrıntı için ajan akışı) |
| Platform olayları | PlatformEventEnvelope | lead.qualified, post.published gibi olaylar da bu akışa düşer (organizasyon üyeleri için) |
Bu akış Redis org:<orgId> kanalından beslenir; panel tek bağlantı açar ve tüm sayfaları günceller.
Kimlik doğrulama
- Tarayıcıda
EventSourceözel başlık gönderemez. Bu yüzden SSE uç noktaları JWT'yi?access_token=<accessToken>sorgu parametresiyle de kabul eder; panel bu yöntemi kullanır. Token URL'de göründüğü için yalnızca HTTPS üzerinden ve kısa ömürlü (15 dk) access token ile kullanın; erişim loglarında sorgu dizesini maskeleyin. - Sunucu tarafında (
fetch,curl,eventsourcepaketi) normal başlık kullanın:Authorization: Bearer <accessToken>veyaX-Api-Key: af_live_...(API anahtarı içinworkflows:read/conversations:readkapsamı). - Access token 15 dakikada dolar; SSE bağlantısı açıkken sunucu kapatmaz, ancak yeniden bağlanmada yeni token gerekir.
Yeniden bağlanma ve Last-Event-ID
- Tarayıcı
EventSourcebağlantı kopunca otomatik yeniden bağlanır. Sunucu her bağlantıda önce kayıtlı geçmişi yeniden oynatır (çalıştırma akışındaNodeRunsatırları, ajan akışında kaydedilmiş adımlar), sonra canlı olaylara geçer; bu yüzden kopma sırasında kaçan olaylar kaybolmaz, ancak aynı olayı ikinci kez görebilirsiniz — istemcidenodeId/step.indexile idempotent güncelleyin.Last-Event-IDbaşlığı kullanılmaz. - Çalıştırma bittikten sonra açılan bir bağlantı geçmişi gönderir ve akışı kapatır (
done). - Sunucu tarafı zaman aşımı yoktur; yük dengeleyici/proxy'de SSE için
proxy_read_timeout/idle timeout değerini yükseltin (Nginx:proxy_buffering off; proxy_read_timeout 3600s;).
Tarayıcı örneği
// accessToken: /auth/login veya /auth/refresh yanıtındaki kısa ömürlü JWT
const es = new EventSource(`${API}/orgs/${orgId}/runs/${runId}/events?access_token=${encodeURIComponent(accessToken)}`);
es.addEventListener("node.started", (e) => mark(JSON.parse(e.data).nodeId, "running"));
es.addEventListener("node.finished", (e) => mark(JSON.parse(e.data).nodeId, "ok"));
es.addEventListener("node.failed", (e) => { const d = JSON.parse(e.data); mark(d.nodeId, d.willRetry ? "retry" : "failed"); });
es.addEventListener("node.waiting", (e) => mark(JSON.parse(e.data).nodeId, "waiting"));
es.addEventListener("run.finished", (e) => { const d = JSON.parse(e.data); showCost(d.costUsd); es.close(); });
es.onerror = () => console.warn("SSE bağlantısı koptu; otomatik yeniden bağlanıyor");
Node.js örneği
// npm i eventsource
import EventSource from "eventsource";
const es = new EventSource(`${API}/orgs/${ORG}/agent-runs/${AR_ID}/events`, {
headers: { "X-Api-Key": process.env.ORQLABS_API_KEY },
});
es.addEventListener("step", (e) => {
const { step } = JSON.parse(e.data);
if (step.type === "tool_call") console.log(`→ ${step.name}`, step.input);
if (step.type === "message") console.log(step.text);
});
es.addEventListener("done", (e) => {
const { run } = JSON.parse(e.data);
console.log(run.status, run.summary, run.usage.costUsd);
es.close();
});
fetch ile ham akış okumak isterseniz text/event-stream gövdesini satır satır ayrıştırın (event:, id:, data: alanları, boş satır ayırıcı).
Redis kanalları (mimari not)
Worker olayları Redis pub/sub'a yayınlar; API SSE uç noktaları abone olur:
| Kanal | İçerik |
|---|---|
run:<runId> | ExecutionEvent JSON |
agentrun:<agentRunId> | `{ type: "step" |
org:<organizationId> | { event, data } – bildirim, onay, konuşma, platform olayları |
Birden fazla API kopyası varsa hepsi aynı Redis'e abone olur; istemci hangi kopyaya bağlanırsa olayı alır. Çalıştırma olayları ayrıca veritabanına yazılır (replay için); organizasyon akışı yalnızca canlıdır (geçmiş için bildirimler ve API).
Sorun giderme
| Belirti | Neden | Çözüm |
|---|---|---|
| 401 | Bilet süresi doldu / başlık yok | Yeni bilet; sunucu tarafında başlık |
| Bağlantı 60 sn sonra kopuyor | Proxy idle timeout | Nginx/ALB timeout artırın; ping 25 sn |
| Olaylar gecikmeli geliyor | proxy_buffering açık | Kapatın |
| Replay çok uzun | Uzun run, çok log olayı | ?since=<id> parametresi ile son olaylardan başlayın |
event: reset | Tampon aşıldı | Durumu GET /runs/:id ile yenileyin |
| Hiç olay yok | Run başka organizasyonda / yanlış id | 404 kontrolü; GET /runs/:id |
Sık sorulan sorular
Bağlantı koparsa olayları kaçırır mıyım? Hayır. Yeniden bağlandığınızda kayıtlı geçmiş yeniden gönderilir; aynı olayı iki kez görebilirsiniz.
Tarayıcıda API anahtarı kullanabilir miyim? Hayır. Tarayıcıda kısa ömürlü kullanıcı oturumu kullanın; API anahtarı yalnızca sunucuda.
Bağlantı 60 saniyede kopuyor. Ters vekil sunucunuzun (Nginx vb.) zaman aşımını artırın ve tamponlamayı kapatın.