GNL
Dokümanlar menüsü
Studio@gnldev/studio

Studio — inspector & yönetim düzlemi

Journal'ı gözlemleyen web UI + JSON API: run timeline/state/diff/trace/cost, canlı Playground, onaylar, metrikler, threads, organizasyonlar ve bütçe yönetimi.

Ne işe yarar / ne zaman kullanılır#

Studio, @gnldev/durable journal'ının üstüne oturan bir teftiş + yönetim düzlemi: run'ların timeline'ını, adım adım materyalize durumunu (state/diff), OTel-benzeri trace'i ve maliyeti gösterir; tarayıcıdan agent çalıştırıp (Playground) askıdaki tool onaylarını inceler/onaylar; thread'leri (memory), workflow'ları, organizasyonları ve bütçeleri yönetir. "Bu run neden askıya alındı", "hangi model adımı ne kadar tuttu", "prod'a almadan önce agent'ı tarayıcıdan deneyeyim" gibi ihtiyaçlarda — kendi backend'inizde bu görünürlüğü sıfırdan yazmak yerine — kullanılır. Çoğu görünüm (Playground, Memory, Workflows, Scorers, Kullanıcılar, Organizasyonlar) opsiyoneldir: yalnız ilgili opsiyon verilirse açılır, yoksa sessizce gizlenir (GET /capabilities UI'ın hangi görünümleri göstereceğini buradan keşfeder).

Kurulum / import#

Çekirdek export'lar @gnldev/studio kökünden gelir; Playground'un araç şemasını JSON Schema'ya çevirmek için ayrı bir alt-export gerekir (ai paketine bağımlılığı studio çekirdeğinden izole tutar):

import { createStudioApp, createStudioRunner } from '@gnldev/studio';
import { aiToolSchema } from '@gnldev/studio/ai';

Adım adım kullanım#

En basit kurulum: kendi Hono/Node app'inize bir yola createStudioApp mount edin. Bu, hem JSON API'yi (/api/*) hem de derlenmiş React arayüzünü (@gnldev/studio-ui) tek app'te birleştirir — apiBase, arayüzün fetch edeceği API önekini söyler (mount ettiğiniz yolla aynı olmalı):

const gnl = createGnl(config);

app.route('/studio', createStudioApp({
  reader: toJournal(storage.runs),
  apiBase: '/studio',
  gnl: createStudioRunner(gnl, config, { toJsonSchema: aiToolSchema }),
  auth,
  org: {},
  budgets: { default: { tokenLimit: 100 } },
  users: userStore,
}));

reader zorunludur ve journal'ı gösterir (toJournal(storage.runs) ile mevcut storage'ınızdan türetilir). gnl verilmezse Playground/Tools/Workflows görünümleri gizlenir — verildiğinde createStudioRunner createGnl instance'ınızı ve config'inizi alıp tarayıcıdan çalıştırılabilir bir koşucuya sarar (agent listesi, tool şemaları, model adı gibi hassas olmayan metadata dışarı sızar; model objesinin kendisi asla sızmaz). auth verilmezse tüm uçlar serbesttir; verilirse (ücretsiz roleAuth veya paralı @gnldev/auth-ee) okuma/yazma uçları kapı(gate)lenir. org: {} çok-organizasyonlu okuma teftişini açar (varsayılan çözücü x-gnl-org header'ıdır); budgets Organizasyonlar panelinde düzenlenebilen varsayılan/organizasyon-bazlı limitleri; users ise Studio'nun "Kullanıcılar" görünümünü açar.

Yalnız JSON API'ye (UI olmadan, kendi arayüzünüzü kuracaksanız) ya da yalnız statik/ayrı servis edilen HTML UI'a ihtiyacınız varsa aynı seçenekleri iki ayrı fonksiyona bölebilirsiniz:

app.route('/studio/api', createStudioApi({ reader, gnl, auth }));  // JSON only
app.route('/studio', createStudioAdmin({ apiBase: '/studio' }));    // HTML UI only (it points at a remote API)

Mount ettikten sonra REST uçları doğrudan da kullanılabilir — ör. bir run'ın maliyeti veya trace'i:

Studio REST
GET /studio/api/runs/:id/state?step=3   → the materialized state at step 3 (reconstructState)
GET /studio/api/runs/:id/cost           → getRunCost(reader, id)
GET /studio/api/runs/:id/trace          → waterfall span'leri (maliyet dahil)
GET /studio/api/approvals               → pending tool approvals across ALL suspended runs (inbox)

Dead-letter — parkta ne var, ve geri koymak#

events verdiğinizde Dead-letter görünümü açılır; yanında GET /dead-events/topics, GET /dead-events ve POST /dead-events/release gelir. queue ile aynı kendi-store'unu-sar deseni: StudioEvents host'un sağladığı bir köprüdür, yani Studio @gnldev/events'e bağımlı değildir ve kendi store'unuz üzerinde de aynı şekilde çalışır.

Her şey üçlü ile adreslenir: (topic, consumer, id). Bir konu dallanır, yani tek bir olayın tüketici başına bir karantina kaydı olur — tek başına id bunların birkaçını birden gösterir. Yarım bir üçlü bu yüzden sessizce ıskalayan bir arama değil, 400'dür.

wire your own store
import { listDeadEvents, retryDeadEvent } from '@gnldev/events';

createStudioApp({
  reader: toJournal(storage.runs),
  events: {
    orgScoped: true,   // the host declaring it honours the ctx.orgId it is handed
    topics:     ()                       => listTopics(storage.work),
    listDead:   (topic, consumer, ctx)   => listDeadEvents(storage.work, topic, consumer),
    release:    (topic, consumer, id)    => retryDeadEvent(storage.work, topic, consumer, id),
  },
});

Üç şey yüzeyin sonradan eklenmiş parçası değil, kendisidir. Olay gövdesi, çağıran hem istemedikçe hem de payloads:read taşımadıkça verilmez; işleyicinin hata metni aynı izinle tutulur ve istemeye gerek yoktur, çünkü varsayılan cevapta gelir. Tarama pahalıdır — bütün bir konu kaydını okur — bu yüzden dağıtım genelinde aynı anda bir tane koşar, kalanlar sıraya girer ve Retry-After sabit bir sayı değil, bu dağıtımın kendi tamamlanmış taramalarından ölçülür.

Serbest bırakma etkisiz-tekrarlanabilirdir: zaten bırakılmış bir olayı geri vermek 409 değil, belgelenmiş bir işlemdir. Yalnızca teslim edilmiş olay nihaidir. Her bırakma denetim kaydına event.release olarak yazılır.

API referansı#

fncreateStudioApp

Admin HTML UI + JSON API (/api/*) tek app'te — en kolay geriye uyumlu kurulum.

fncreateStudioApi

Yalnız JSON API (UI yok); kendi mount/auth/programatik akışınıza gömmek için.

fncreateStudioAdmin

Yalnız HTML UI; apiBase ile yerel veya uzakta çalışan bir Studio API'ye bakar.

fncreateStudioRunner

createGnl instance'ından Playground/Tools/Workflows koşucusu türetir (StudioAgentRunner).

fnaiToolSchema

@gnldev/studio/ai alt-export'u — zod şemasını JSON Schema'ya çevirir (Tools görünümü formu için).

typedeadEventScan

Dead-letter taramasını ayarlar: timeoutMs (host'un taraması ne kadar sürebilir), queueWaitMs ve queueDepth (kaç çağıran bekleyebilir), maxAbandonedScans (cevap vermeyen bir store'a yeni okuma açmayı durdurur).

typeStudioApiOptions

createStudioApi/Runner girdisi: reader (zorunlu) + resume/chat/gnl/memory/workflows/scorers/datasets/mcp/queue/events/deadEventScan/cache/vectors/users/auth/org/budgets/retention/evalGate/alerts (hepsi opsiyonel).

typeStudioAppOptions

StudioApiOptions + apiBase (admin HTML'in fetch edeceği API öneki).

Not
Her görünüm opt-in'dir: GET /capabilities yalnız verilen opsiyonlara göre true döner (ör. gnl yoksa playground: false). UI, giriş ekranından önce bu uçla kendini uyarlar; siz de kendi entegrasyonunuzda hangi yüzeylerin açık olduğunu buradan doğrulayabilirsiniz.
Dikkat
users (Kullanıcılar görünümü + /users uçları) paralı bir sözleşmedir — implementasyonu (createJournalUserStore) @gnldev/auth-ee'de yaşar; ücretsiz katmanda bu opsiyonu vermezseniz görünüm sessizce gizlenir. Aynı şekilde Organizasyonlar/Bütçe yönetimi yalnız çok-organizasyonluluk açıkken (org verildiğinde veya auth sağlayıcısı multiOrganization bildirdiğinde) görünür.
İlişkili
Yönetilen agent sürümleri için agent-versioning, promote öncesi suite kapısı için eval-gate, organizasyon limitleri için budget-quota, paralı kullanıcı yönetimi için user-store ve denetim kaydı için audit-log sayfalarına bakın.