İçeriğe geç
↑↓Gezin ↵Aç escKapat

Host API

Bu sayfayı connectHost metodlarını, sınırları ve hata kodlarını tam olarak bilmeniz gerektiğinde kullanın. Klasör düzeni, manifest ve kurulum için Eklenti oluşturma sayfasından başlayın.

import { connectHost, HostRequestError } from "@openchamber/sdk";
const host = connectHost();

connectHost, window yoksa HOST_UNAVAILABLE fırlatır. OpenChamber dışında, her çağrısı HOST_UNAVAILABLE ile reddedilen bir istemci döndürür. Sayfayı kapatırken dispose() çağırın; hâlâ süren çağrılar aynı kodla reddedilir.

OpenChamber’ın size gönderdikleri

onReady ilk anlık görüntüyle tetiklenir ve OpenChamber onu her yenilediğinde yeniden tetiklenir.

Bu, yalnızca bir kez çalışan bir bağlama callback’i değildir. Arayüzü ve abonelikleri bir kez oluşturun; sonraki çağrılarda alanları veya taslakları değiştirmeden temayı ve bağlamı güncelleyin. UI kit sayfasındaki korumalı örneğe bakın. onConnection gibi dinleyiciler mevcut değeri hemen iletir ve yeni görüntülerde aynı değeri tekrar iletebilir. Yeni istekten önce ilgili alanları karşılaştırın ve yerini yeni isteklerin aldığı eski yanıtları yok sayın.

AlanAnlamı
theme.modelight veya dark
theme.tokensuygulamanın renkleri (yüzeyler, metin, etkileşim durumları, primary, success/warning/error/info), font, mono ve radius. UI’ı bağlamadan önce bunu applyHostReady fonksiyonuna verin.
localeuygulamanın dil etiketi
directorygeçerli proje dizini veya null
session{ id, title, busy } veya null. Başlık yoksa oturum id’sine düşer. busy canlı durumdur. Oturumda varsa model ve agent (OpenCode ajanı) de gelir.
surfaceşeritte panel, iliştirme penceresinde dialog, tam ekranda page, Work Status panelinde status, Files içinde dosya düzenleyici olarak file, sohbetteki UI bloğunda block
itembu yüzeyin ne için açıldığı veya null: kullanıcının tıkladığı iliştirilmiş öğe (attach çağrısına verdiğiniz alanların aynısı, data dahil), tanımladığınız eylemlerden birinden gelen bir mesaj (kind: "message") veya oturum (kind: "session"). Bkz. Eylemler.
connectionentegrasyonunuz için { connected, account }
settingsintegration.settings içinde tanımladığınız alanların değerleri

Erişim token’ları burada da, request sonucunda da asla görünmez.

onDirectory, onSession, onSessionLifecycle, onConnection, onSettings ve onItem geç abone olduğunuzda en son değeri yeniden gönderir, sonra değiştikçe tetiklenmeye devam eder.

theme.tokens, primaryText, successText, warningText, errorText ve infoText alanlarını içerir. Bu zorunlu alanlar, host’un nötr arka planlar ve UI kit’in hafif renkli kontrolleri için hesapladığı metin renklerini taşır; düz renk dolguları için değildir. applyHostReady her durum güncellemesinde bunları uygular. CSS değişkenleri için UI kit sayfasına bakın.

Metodlar

ÇağrıNe yapar
toast({ kind, message })uygulamada bildirim gösterir. kind değeri info, success veya error.
openUrl(url)kullanıcının tarayıcısında bir URL açar
openSurface(surfaceId)uygulamayı o ekrana geçirir
writeClipboard(text)metni kopyalar. 1 ile 32000 karakter arası.
compose({ text, mode? })metni göndermeden sohbet kutusuna koyar. mode değeri append (varsayılan) veya replace. Boşluklar kırpıldıktan sonra 1 ile 16000 karakter arası.
attach({ ... })sohbet kutusuna, GitHub ve Linear öğelerinin düştüğü yere bir etiket koyar. Aynı anda yalnızca bir etiket.
startSession({ ... })o öğe iliştirilmiş bir oturum oluşturur. { sessionId, sent } döndürür. sessions yeteneği gerekir.
prompt({ text, send? })geçerli oturuma yazar ya da oradan gönderir. { sent } döndürür. Göndermek için prompt yeteneği gerekir.
sessionLink({ ... })yeni oturum oluşturmadan bir öğeyi geçerli oturuma iliştirir
close()iliştirme penceresini kapatır. Şeritte hiçbir şey yapmaz.
oauthStart()sağlayıcının yetkilendirme sayfasını, host: { provider: "linear" } entegrasyonu için ise Linear’ınkini açar
oauthDisconnect()saklanan token’ı ya da Linear bağlantısını unutur
request({ method, path, query?, body? })entegrasyonunuzun apiOrigin adresini kullanıcının token’ı ekli olarak çağırır
serviceRequest({ method, path, query?, body? })eklentinizin yerel servisini çağırır (bkz. GUEST_SERVICES.md)
serviceStatus()stopped, starting, ready veya failed
readFile(path)metin dosyası okur. { content } döndürür.
writeFile(path, content)metin dosyasını atomik olarak yazar, üst klasörleri oluşturur. { written: true } döndürür.
listDir(path)klasörü listeler. { entries: [{ name, kind }] } döndürür, kind file, directory veya other olur.
stat(path){ kind, size, mtime }, kind file, directory, other veya missing olur.
generate({ prompt, system?, maxOutputTokens? })kullanıcının Small Model’inden tek seferlik metin. { text } döndürür. model yeteneği gerekir.
onResolve(handler)eğik çizgi komutlarınız için işleyiciyi kaydeder. { command, args } alır ve iliştirilecek bir öğe ya da null döndürür.
setBadge(count)şerit simgenizi bir noktayla işaretler ve sayıyı (0 ile 999 arası) ipucunda gösterir, null ile temizler
openCommit(sha)geçerli projenin o commit’inde Diff görünümünü açar. sha 7 ile 64 onaltılık karakterdir; commit’i OpenChamber kendisi okur.
setHeight(px)Work Status bölümünüzün yüksekliğini ayarlar. OpenChamber bunu 24 ile 320 piksel arasında tutar; daha uzun içerik sayfanızın içinde kayar. Başka yerlerde yok sayılır.
onFileOpen(listener)dosya düzenleyiciler: düzenlenecek dosyayı alır, { path, name, readOnly } ile birlikte encoding: "text" ve content ya da encoding: "binary" ve bytes. Ayrıca sayfanızda Cmd/Ctrl+S ile kaydetmeyi sağlar.
onFileSnapshot(handler)dosya düzenleyiciler: düzenlenmiş dosyanın tamamını { content, version } (ikili bir düzenleyicide { bytes, version }) olarak döndürür. OpenChamber bunu kaydetmek için ve kaynak görünümüne ya da tam ekrana geçmeden önce çağırır.
onFileSaved(listener)dosya düzenleyiciler: bu version değerine sahip anlık görüntü diske yazıldı. reportFileChange ile yanıt verin.
reportFileChange({ dirty, edited })dosya düzenleyiciler: OpenChamber’a kaydedilmemiş değişiklik olup olmadığını ve belgenin az önce değişip değişmediğini bildirir
requestFileSave()dosya düzenleyiciler: Cmd/Ctrl+S gibi hemen kaydeder
reportFileUnsupported()dosya düzenleyiciler: bu dosya burada açılamaz, onun yerine kaynağını gösterir

Üçü de aynı öğe alanlarını alır:

await host.attach({
providerId: "acme-hello",
id: "TICKET-1",
title: "Login is broken",
url: "https://example.com/TICKET-1",
});
await host.attach({
providerId: "acme-hello",
id: "!12",
title: "Fix login",
url: "https://example.com/merge_requests/12",
kind: "pull",
author: "ada",
branches: { head: "feature", base: "main" },
text: "Optional notes for the model",
});
await host.startSession({
providerId: "acme-hello",
id: "!12",
title: "Fix login",
url: "https://example.com/merge_requests/12",
kind: "pull",
worktree: true,
text: "Optional first message",
});

providerId panel id’nizdir; OpenChamber bunun üzerine zaten sizin id’nizi yazar. id öğe için kendi tanımlayıcınızdır. kind değeri issue (varsayılan) veya pull. text model için isteğe bağlı bağlamdır; boşluklar kırpıldıktan sonra 1 ile 16000 karakter arası. data size ait isteğe bağlı bir JSON’dur (durum, yorumlar, ne isterseniz); serileştirildiğinde en fazla 16000 karakter. OpenChamber bunu etiketle birlikte saklar ve kullanıcı etikete tıkladığında ctx.item içinde değiştirmeden geri verir; modele hiçbir zaman ulaşmaz.

startSession, etkin projeyi değiştirmeden projectId kabul eder. worktree verilmezse hedef dizin kullanılır; true otomatik adlı yeni worktree, { kind: "existing", directory } mevcut worktree, { kind: "new", name?, baseBranch? } ise adı ve temel dalı seçilen yeni worktree içindir. Ad, dal için de kullanılır. navigation varsayılanı "preserve" olur; "open" yeni sohbeti açar. İlk mesajın modeli, ajanı ve varyantı başlangıçta yakalanır.

Sonuç sessionId, directory, sent, linked ve isteğe bağlı worktree içerir. sent, sent, no-model, skipped veya failed olur; linked: false, öğenin kaydedilemediğini belirtir. Hazırlık veya oturum oluşturma hatasından sonra worktree kalırsa sessionId: null ve failure: "bootstrap-failed" | "session-create-failed" döner. Yeniden denemeden önce kontrol edin. En fazla 180 saniye bekler; zaman aşımı oluşturmanın geri alındığını kanıtlamaz.

sessionLink öğeyi şu an açık olan oturuma iliştirir. Proje veya oturum yoksa NO_SESSION hatasıdır.

İstemcinin herhangi bir şey gönderilmeden önce uyguladığı sınırlar:

AlanEn fazla karakter
id128
title200
url2000
text16000
data (serileştirilmiş)16000
author80
her dal adı200

prompt ve oturum yaşam döngüsü

await host.prompt({ text: "Fix the login" });
await host.prompt({ text: "Fix the login", send: true });
host.onSessionLifecycle((event) => {
document.body.dataset.phase = event.phase;
});

send olmadan prompt sohbet kutusundaki metnin yerine geçer. send: true ile mesajı kullanıcının seçtiği model ve ajanla gönderir. Eklenti bunları asla kendisi seçmez. Açık oturum yoksa NO_SESSION. Oturum meşgulken göndermek SESSION_BUSY; meşgulken kutuya yazmak çalışır. Sonuç, startSession ile aynı değerleri alan { sent } olur.

onSessionLifecycle oturumun ne yaptığını söyler. phase model çalışırken started, boşa geçtiğinde completed, beklenmeyen bir durumda failure olur. Geç eklenen bir dinleyici geçerli aşamayı hemen alır.

Projeler, worktree’ler ve canlı oturumlar

listProjects(), listWorktrees(projectId) ve listSessions(projectId) mevcut sessions iznini ve paylaşılan store verilerini kullanır. Her çağrıda Git taraması yapmaz ve konuşma içeriğini açmaz. Projeler kimlik, ad ve dizin; worktree kayıtları dal ve kullanılabilirlik içerir. Oturumlar tarihleri, üst oturumu, worktree ve yalnızca bu uzantının iliştirdiği öğeleri içerir. Bilinen arşiv oturumları da dahildir.

await onProjects(listener), await onWorktrees(projectId, listener) ve await onSessions(projectId, listener) aboneliği bitiren bir fonksiyon döndürür. Kayıt hatalarını yakalayın. Önce anlık görüntü, sonra değişiklikler gelir. Çerçeve başına en fazla 32 abonelik; dispose(), kapatma, duraklatma, kaldırma ve sunucu değiştirme bunları temizler. state, loading, ready veya error olur; oturumlarda dizin bazında coverage vardır. Hata mevcut verileri korur; tam boş listeyi yalnızca ready doğrular.

activity, unknown, idle, running, retrying, waiting-permission veya waiting-question olur. outcome, gözlemlenen completed, failed veya null değeridir; yalnızca bellekte en fazla 2.000 oturum için tutulur. Hata sonrası idle, sonraki çalışmaya kadar hatayı korur. Bu, görevin tamamlandığı anlamına gelmez. openSession(sessionId) sohbeti açıkça açar.

Kalıcı uzantı verisi

await host.storage.set("board", { columns: ["Todo", "Review"] });
const board = await host.storage.get("board");
const keys = await host.storage.keys();
await host.storage.delete("board");

Ek izin gerekmez. Depolama, bağlı sunucuda bu uzantıya aittir, yeniden yüklemelerde korunur ve kaldırma işleminde silinir. get, olmayan anahtar için undefined döndürür; kaydedilmiş JSON null değeri null kalır. Anahtarlar 1 ile 128 karakter arasındadır. Serileştirilmiş her JSON değeri en fazla 64 KiB UTF-8, toplam 2 MiB ve 2.000 anahtardır. Projeye özel veriler için anahtarda proje kimliği kullanın. Yazmalar sıralı ve atomiktir; hatalar mevcut veriyi korur.

request

const user = await host.request({ method: "GET", path: "/api/v2/user" });

path / ile başlar, şema ve host içermez; OpenChamber onu manifestinizdeki apiOrigin ile birleştirir ve Authorization başlığını ekler. Token entegrasyonları yapıştırılan token’ı olduğu gibi, manifest token.scheme: "bearer" ayarlıyorsa Bearer <token> olarak, "basic" ayarlıyorsa Basic base64(username:token) olarak gönderir. OAuth ve Linear entegrasyonları her zaman Bearer gönderir. Sonuç { status, body } olur. body metindir; JSON’ı kendiniz ayrıştırın.

Bir Linear entegrasyonu ayrıca GET /api/linear/issues/get çağırabilir; OpenChamber bunu kendi Linear rotasından yanıtlar.

20 saniye içinde yanıt gelmezse HOST_TIMEOUT.

try {
await host.request({ method: "GET", path: "/api/v2/user" });
} catch (error) {
if (error instanceof HostRequestError && error.code === "DISCONNECTED") {
await host.oauthStart();
}
}

serviceRequest

Manifest contributes.service tanımladığında OpenChamber o süreci başlatır ve sayfanız onunla aynı türden bir çağrıyla konuşur. Sayfa soketi asla kendisi açmaz.

const status = await host.serviceStatus();
const result = await host.serviceRequest({ method: "GET", path: "/containers" });

path için request ile aynı kurallar geçerlidir. Bir yerel servis tanımlamak, kullanıcının kurulumda onayladığı yeteneklere service ekler; o zamana kadar her serviceRequest NO_SERVICE olur. Tam sözleşme: paket dosyası GUEST_SERVICES.md.

Oturum olayları

Sayfanız bir oturumu yalnızca açıkken bilir. Servisiniz daha fazlasını bilebilir: contributes.service yanına contributes.sessionEvents tanımlayın, OpenChamber listelediğiniz olayları her projeden, bir pencere açık olsun ya da olmasın servise gönderir.

"service": { "entry": "service/main.js", "runtime": "host" },
"sessionEvents": { "events": ["turn-finished", "question-asked"], "content": true }

Olaylar şunlardır: turn-started, session-created, session-archived, session-deleted, turn-finished (ajan işini bitirdi ve hiçbir şey beklemiyor: çalışan alt ajan, açık izin ya da soru, hedef adımı yok), turn-failed, permission-asked ve question-asked. Kullanıcının durdurduğu bir tur hiçbir şey göndermez. Eklentiyi onaylamak aboneliğin kendisidir; iletişim kutusu olayları servis satırının altında listeler. content olmadan servis yalnızca tanımlayıcıları alır: oturum, proje dizini, kullanıcının oturuma iliştirdiği öğeler. "content": true ile manifest, kullanıcının ayrı bir satır olarak gördüğü bir yetenek de ister, Ajanın arka planda söylediklerini okuma, ve her olay ajanın son yanıtını, sorunun alanlarını ya da iznin ayrıntısını taşır.

Her olay servis bearer token’ı ile tek bir POST /session-events olarak gelir. readSessionEventRequest ile okuyun ve { "ok": true } yanıtlayın:

import { SESSION_EVENTS_PATH, readSessionEventRequest } from "@openchamber/sdk";
// inside your service's request handler, after the bearer check
if (url.pathname === SESSION_EVENTS_PATH) {
const request = readSessionEventRequest(body);
if (!request) return json(res, 400, { ok: false, error: "not a session event" });
const { event, content } = request;
if (event.type === "turn-finished" && event.project.directory === myProject) {
await postComment(event.linked, content?.type === "turn-finished" ? content.reply : "");
}
return json(res, 200, { ok: true });
}

Her projenin olayları gönderilir; event.project.directory değerini kendi ayarlarınızla karşılaştırın ve geri kalanına { "ok": true } yanıtlayın. Teslimat en fazla bir kez ve sıralıdır, aynı anda tek istek; başarısız bir yanıt olaylarınızı 30 saniye düşürür ve OpenChamber ya da servisiniz kapalıyken olanlar sonradan yeniden gönderilmez. Servisin bunun için panele ihtiyacı yoktur. session-events-log örneği her olayı bir dosyaya yazar.

OpenChamber’ı servisinizden çağırma

Bir servis, hiçbir pencere açık değilken de işlem yapabilir. createServiceHost, servisin OpenChamber’a dönüş yoludur:

import { createServiceHost } from '@openchamber/sdk';
const host = createServiceHost({ env: process.env });
const { sessionId } = await host.sessions.start({ prompt: 'Summarize the failed deploy', directory });
await host.sessions.send(sessionId, 'Now write the incident note');
await host.setInstructions(directory, 'Deploys run through the release branch.');
await host.emit('deploy-finished', { id: 42 });

sessions.start, sessions.send, sessions.retry, sessions.status ve sessions.stop için contributes.sessionControl gerekir; kullanıcı bunu ayrı bir satır olarak onaylar. sessions.lastReply için sessionControl: { content: true } gerekir. sessions.send ile gönderilen bir mesaj, sohbete yazılan bir mesaj gibi, ajanın o oturumda beklediği formu ya da sayfayı kapatır.

Ajanın isteklerini başka bir yere, örneğin bir sohbet uygulamasına taşımak için answers: true ekleyin. Kullanıcı bunu bir satır daha olarak onaylar ve servis artık herhangi bir oturumda kullanıcı adına yanıt verebilir: bir permission-asked olayı için sessions.answerPermission(sessionId, requestId, { decision: 'allow' }) (ya da ajanın okuyacağı bir message ile 'deny'), event.question.kind değeri form olan bir question-asked olayı için sessions.answerForm(sessionId, formId, values). Olayın içeriği formun alanlarını key değerleri ve seçenekleriyle listeler. Değerler yerine null göndermek formu yanıtsız kapatır. Bir izin yalnızca o tek isteği kapsar.

setInstructions için contributes.instructions gerekir; bu çağrı ajanların okuduklarına tek bir klasörde ya da null ile her yerde ekleme yapar.

emit, host.onServiceEvent üzerinden açık frame’lerinize ulaşır, böylece panelin yoklama yapması gerekmez. Hiçbir şey yeniden gönderilmez, bu yüzden sonradan açılan bir frame önce güncel durumu okur. readSettings, servise secret alanları dahil entegrasyonun ayarlarını verir; needsConfiguration ise eklentinin kartında bir mesaj gösterir.

Kimse istemeden çalışma

Bir servis ilk istekle başlar ve bir role sahip servis boşta kalınca durur. service.keepRunning: true, servisi OpenChamber ile birlikte başlatır ve durduğunda geri getirir. service.schedule servisi zamanlamaya göre uyandırır:

"service": {
"entry": "service/main.js",
"runtime": "host",
"keepRunning": true,
"schedule": [{ "id": "nightly", "cron": "0 3 * * *", "timezone": "Europe/Kyiv" }]
}

Bir çalıştırma tek bir POST /schedule isteğidir. readServiceScheduleRequest ile okuyun ve 200 yanıtlayın. OpenChamber kapalıyken kaçırılan bir çalıştırma kaybolur. Dış olaylara ihtiyaç duyan bir servis kendi bağlantısını tutar ya da yoklama yapar.

@ menüsündeki satırlar

contributes.mentions: { label }, sohbet kutusunun @ menüsüne bir bölüm ekler. Servisiniz POST /mentions/search isteğini 2 saniye içinde { items: [{ id, title, subtitle?, url? }] } ile, POST /mentions/resolve isteğini ise kullanıcının seçtiği satır için { text } ile yanıtlar. Metin mesajla birlikte ajana gider ve kullanıcı bir etiket görür. Yavaş bir servis satır eklemez ve dosyaları hiçbir zaman bekletmez; okunamayan bir satır etiket bırakmaz ve bunu bildirir.

Sohbetteki bloklar

contributes.blocks, ajanların bir UI bloğuna yazabileceği bileşenler ekler. Her birini panelinizle aynı korumalı alanda ve aynı izinlerle kendi sayfanız çizer.

"blocks": [{ "name": "JiraIssue", "description": "A Jira ticket", "args": ["key"], "entry": "blocks/issue.html" }]

Ajan JiraIssue("OPE-1") yazar, sayfanız da çağrıyı okur:

host.onBlock(({ args }) => draw(args.key));

Kök öğenizdeki bir ResizeObserver içinden host.setHeight(px) çağırın. Frame kutusunu dolgu olmadan doldurur, bu yüzden kendi dolgunuzu ekleyin. Eklenti başına en fazla 4 bileşen olabilir, çünkü her imza her oturumun okuduğu metindir.

Bir blok, bloktaki bir düğmenin yaptığı gibi ajana yanıt verebilir. Bir tıklamadan host.answerBlock(text) çağırın: ajan metni alır ve sonraki turuna başlar. Blok başına bir yanıt olur ve block.answered bunu yeniden yüklemeden sonra tutar, bu yüzden bloğu o zaman yanıtlanmış olarak çizin.

host.onBlock(({ args, answered }) => draw(args.key, answered));
button.onclick = () => host.answerBlock('Close this ticket');

Bunu yapan bir bileşende "answers": true ayarlayın. Açıklaması uyduğunda ajanlara yerleşik seçim yerine onunla sormaları söylenir ve yanıt bekleyen bir sayfa kendi Gönder düğmesini göstermez. Böyle bir bloğun altında OpenChamber, kendi formlarındaki not alanının aynısını sunar: ajan notu yanıtınızla birlikte okur ve tek başına bir not da yanıt sayılır.

Argümanları bir model yazar, bu yüzden bir web sayfasındaki ya da bir bilet metnindeki yazı onları yönlendirebilir. Argümanları güvenilmez sayın ve kullanıcı tıklayana kadar yan etkisi olan hiçbir şey yapmayın.

Bildirim kanalları

Bir servis, kullanıcının bildirimlerini masaüstü ve telefonun yanında iletebilir: provides: ["notifications"] tanımlayın ve kanalı contributes.notifications içinde tarif edin.

"service": { "entry": "service/main.js", "runtime": "host", "provides": ["notifications"] },
"notifications": {
"label": "Slack",
"instances": { "kind": "fixed", "origin": "https://slack.com" },
"token": { "header": "authorization", "scheme": "bearer", "scopes": ["chat:write"] }
}

OpenChamber bu tarife göre Ayarlar → Entegrasyonlar’da kanal için bir hesap kartı çizer ve hesabı saklar: kullanıcı hesabı orada bağlar, token OpenChamber’da kalır ve servisiniz onu hiç görmez. Bir hesap bağlandıktan sonra OpenChamber’ın telefona göndereceği her bildirim, kullanıcının kendi bildirim anahtarlarından geçtikten sonra servisinize de gider; kullanıcı her zaman bildirilmeyi seçmediyse yalnızca hiçbir pencere görünür değilken. Eklentiyi duraklatmak bunu durdurur.

OpenChamber üç çağrıyı POST /notifications adresine iletir: auth.probe (bu sunucu ilettiğiniz bir sunucu mu), auth.verify (bu token kime ait) ve notify (bir bildirim). Her birini readNotificationsProviderRequest ile okuyun ve kanalın sunucusuna yalnızca giden yardımcı üzerinden ulaşın; yardımcı isteğinizi çağrının tanıtıcısıyla OpenChamber’a gönderir, OpenChamber token’ı ekler ve isteği hesabın sunucusuyla sınırlı tutar.

import { NOTIFICATIONS_PROVIDER_PATH, createNotificationsOutbound, readNotificationsProviderRequest } from "@openchamber/sdk";
const outbound = createNotificationsOutbound({ env: process.env });
// inside your service's request handler, after the bearer check
if (url.pathname === NOTIFICATIONS_PROVIDER_PATH) {
const request = readNotificationsProviderRequest(body);
if (!request) return json(res, 400, { ok: false, error: { message: "not a notifications call" } });
if (request.method === "notify") {
const { notification } = request.input as { notification: GuestNotification };
const answer = await outbound.request(request.session.handle, {
method: "POST", path: "/api/chat.postMessage",
headers: { "content-type": "application/json" },
body: JSON.stringify({ channel: "#agents", text: `${notification.title}: ${notification.body}` }),
});
return json(res, 200, answer.status === 200 ? { ok: true, data: { delivered: true } } : { ok: false, error: { message: `Slack answered ${answer.status}`, status: answer.status } });
}
// auth.probe → { ok: true, data: { supported: true } }; auth.verify → { ok: true, data: { account: { id, login } } }
}

Bir projenin hangi odaya ya da kanala gideceği eklentinizin kendi seçimidir: bildirim directory ve sessionName taşır. Kurumsal modda, telefonda olduğu gibi yalnızca genel başlığı taşır. notification-webhook örneği, karşısında deneyebileceğiniz bir alıcıyla birlikte eksiksiz bir kanaldır.

İzleyiciler

Bir servis, Linear’ın yanında bir iş öğesi izleyicisi olabilir: provides: ["tracker"] tanımlayın ve izleyiciyi contributes.tracker içinde tarif edin. OpenChamber bunu, servis daha hiç çalışmadan yalnızca manifestten yola çıkarak izleyicilerin göründüğü her yerde Linear’ın yanında listeler.

"service": { "entry": "service/main.js", "runtime": "host", "provides": ["tracker"] },
"tracker": {
"wire": 1,
"label": "YouTrack",
"instances": { "kind": "user", "label": "Server address", "placeholder": "https://youtrack.example.com" },
"auth": { "token": { "header": "authorization", "scheme": "bearer", "createPath": "/users/me?tab=account-security" } },
"capabilities": { "stateUpdate": true, "labels": true, "priority": true, "projectMapping": true, "sessionComments": true },
"stateFilters": ["open", "all", "todo", "in-progress", "done"],
"identifier": "key-number",
"urls": { "item": ["/issue/{id}", "/{segments+}/issue/{id}"] }
}

Kullanıcı, Uzantı hesapları altındaki izleyici kartında hesap bağlar: bir token ya da auth.oauth tanımladığınızda tarayıcıda oturum açma (OpenChamber oturum açmayı kullanıcının girdiği client id ile yürütür ve token’ları saklar). Servisiniz hiçbir zaman bir kimlik bilgisi görmez. urls.item, bir öğenin adresi için şablonlardır; {id} tanımlayıcının yerini tutar (sorguda taşındığında ?name={id} olarak da). OpenChamber bunları derler, böylece yapıştırılan bağlantılar bağlı öğelere dönüşür. identifier anahtarın neye benzediğini söyler: key-number (PROJ-42), number ya da short-code.

OpenChamber dokuz çağrıyı POST /tracker adresine iletir: auth.probe ve auth.verify, okuma çağrıları items.list, items.get, items.liveSummaries, states.list ve containers.list, yazma çağrıları items.updateState ve comments.create. Her birini readTrackerProviderRequest ile okuyun, yansız öğe biçimlerinde yanıtlayın ve izleyicinin sunucusuna yalnızca giden yardımcı üzerinden ulaşın; yardımcı isteğinizi çağrının tanıtıcısıyla OpenChamber’a gönderir, OpenChamber kimlik bilgisini ekler ve isteği hesabın sunucusuyla sınırlı tutar. Bir okumanın tanıtıcısı yalnızca GET gönderir.

import { TRACKER_PROVIDER_PATH, createTrackerOutbound, readTrackerProviderRequest } from "@openchamber/sdk";
const outbound = createTrackerOutbound({ env: process.env });
// inside your service's request handler, after the bearer check
if (url.pathname === TRACKER_PROVIDER_PATH) {
const request = readTrackerProviderRequest(body);
if (!request) return json(res, 400, { ok: false, error: { message: "not a tracker call" } });
if (request.method === "items.get") {
const answer = await outbound.request(request.session.handle, { method: "GET", path: `/api/issues/${encodeURIComponent(String(request.input.id))}` });
if (answer.status === 404) return json(res, 200, { ok: true, data: { item: null } });
if (answer.status !== 200) return json(res, 200, { ok: false, error: { message: `YouTrack answered ${answer.status}`, status: answer.status } });
return json(res, 200, { ok: true, data: { item: toTrackerItem(JSON.parse(answer.body)) } });
}
}

Kullanıcı oturum yorumlarını açtığında OpenChamber, comments.create çağrısını “session started”, “completed” ya da “failed” ile ve oturuma bir bağlantıyla, her biri için bir kez yapar; yorum başka bir şey taşımaz. tracker-provider örneği, karşısında deneyebileceğiniz sahte bir sunucuyla birlikte eksiksiz bir izleyicidir.

Kullanım sağlayıcıları

Bir servis, yerleşik sağlayıcıların yanında kullanımı bildirebilir: provides: ["quota"] tanımlayın ve kimlik bilgilerine ihtiyaç duyduğu OpenCode sağlayıcılarını contributes.quota.providers içinde listeleyin. OpenChamber sağlayıcıya ext-<panel.id> adını verir, kartını uzantının adı ve simgesiyle çizer ve yerleşik bir sağlayıcıya sorduğu gibi sorar.

"service": { "entry": "service/main.js", "runtime": "host", "provides": ["quota"] },
"quota": { "providers": ["openrouter"] }

Onay iletişim kutusu bu sağlayıcıları listeler; listeyi değiştiren bir sürüm yeniden sorar. Her yenilemede OpenChamber POST /quota adresine tek bir çağrı, usage.read, gönderir; input.credentials içinde, listelenen sağlayıcılardan OpenCode’un kimlik bilgisi sakladığı her biri için o kimlik bilgisi (bir API anahtarı ya da bir tarayıcı girişinin token’ları) bulunur ve depodan başka hiçbir şey bulunmaz. OpenCode’un kimlik bilgisi saklamadığı listelenmiş bir sağlayıcı yapılandırılmamış olarak gösterilir ve servis çağrılmaz; anahtarı uzantının kendi ayarlarında duran bir sağlayıcı için boş listeye izin verilir.

Gövdeyi readQuotaProviderRequest ile okuyun ve yerleşik bir sağlayıcının hesapladığı sonucu { ok: true, data } ile yanıtlayın: ok, configured, error, planLabel ve pencere adına göre usage.windows, her biri usedPercent, windowSeconds, resetAt (epoch milisaniye) ve isteğe bağlı valueLabel ya da value ile; ayrıca model başına pencereler için usage.models. Kalan payı, sıfırlamaya geri sayımı ve biçimlendirilmiş metinleri OpenChamber türetir, böylece kart yerleşik bir sağlayıcınınkiyle eşleşir.

import { QUOTA_PROVIDER_PATH, readQuotaProviderRequest } from "@openchamber/sdk";
// inside your service's request handler, after the bearer check
if (url.pathname === QUOTA_PROVIDER_PATH) {
const request = readQuotaProviderRequest(body);
if (!request) return json(res, 400, { ok: false, error: { message: "not a usage call" } });
const credential = request.input.credentials.openrouter;
const bearer = credential.type === "api" ? credential.key : credential.access;
const answer = await fetch("https://openrouter.ai/api/v1/key", { headers: { authorization: `Bearer ${bearer}` } });
if (answer.status === 401) return json(res, 200, { ok: true, data: { ok: false, configured: true, error: "OpenRouter refused the key.", usage: null } });
return json(res, 200, { ok: true, data: toUsage(await answer.json()) });
}

Servis 20 sn içinde yanıt verir ve on dakika çağrı almazsa durur; Kullanım sayfası açıkken her üç dakikada bir yenilenir. quota-provider örneği, denemek için sahte bir kullanım API’siyle birlikte eksiksiz bir sağlayıcıdır.

Dosyalar

Göreli bir yol açık projenin içindedir ve files yeteneği gerektirir. / veya ~/ ile başlayan bir yol, tanımlanmış bir contributes.filesystem deseniyle eşleşmeli ve filesystem yeteneği gerektirir. Kurallar için bkz. Eklenti oluşturma.

const { content } = await host.readFile("package.json");
await host.writeFile("notes/today.md", "# Today\n");
const { entries } = await host.listDir("src");
const info = await host.stat("~/.config/opencode/opencode.json");

Sınırlar: yol en fazla 1024 karakter, içerik en fazla 2,000,000 karakter, listeleme en fazla 2000 kayıt. İçerik sınırını aşmak FILE_TOO_LARGE olur.

generate

const { text } = await host.generate({ prompt: notes, system: "Summarize in one sentence." });

prompt kırpıldıktan sonra 1 ila 64.000 karakter, system en fazla 8.000, maxOutputTokens 1 ila 4.000 olabilir. Hiçbir şey bir oturuma girmez ve geçmiş tutulmaz; eklenti asla modeli seçmez. Çağrı en fazla 90 saniye bekler. Kullanılabilir bir Small Model yoksa NO_MODEL; model hatası MODEL_FAILED olur. Bkz. Metin üretme.

Hata kodları

Başarısız çağrılar HostRequestError fırlatır. code şunlardan biridir; message daha fazlasını söyler.

KodNe zaman
HOST_UNAVAILABLEwindow yok, OpenChamber içinde değil veya dispose() çalıştı
HOST_TIMEOUT20 saniye boyunca yanıt yok
HOST_REJECTEDOpenChamber reddetti veya bu SDK’nın tanımadığı bir kodla yanıtladı
DISCONNECTEDentegrasyonunuz için token veya Linear bağlantısı yok
BAD_PATHpath hatalı biçimlendirilmiş ya da izin verilen kaynağın dışına çıkmaya çalıştı
NO_INTEGRATIONmanifestte integration yok
NO_SESSIONaçık oturum yokken prompt veya sessionLink
SESSION_BUSYoturum meşgulken prompt({ send: true })
DISABLEDkullanıcı eklentiyi Ayarlar → Uzantılar içinde duraklattı
NO_SERVICEyerel servis tanımlanmamış, onaylanmamış veya çalışmıyor
NOT_GRANTEDkullanıcı bu çağrının gerektirdiği yeteneği onaylamadı
SERVICE_FAILEDyerel servis çöktü veya hiç hazır olmadı
NO_DIRECTORYaçık proje yokken göreli bir dosya yolu kullanıldı ya da açık proje yokken openCommit çağrıldı
NOT_FOUNDvar olmayan bir dosyada readFile ya da projede olmayan bir commit için openCommit
FILE_TOO_LARGEokuma veya yazmada dosya içeriği sınırın üzerinde
DENIEDişletim sistemi dosya işlemini reddetti
NO_MODELkullanılabilir Small Model olmadan generate
MODEL_FAILEDSmall Model bir hata döndürdü
UNSUPPORTEDbu OpenChamber çağrıyı yapamaz, örneğin Diff görünümü olmayan yerde openCommit

İlgili sayfalar

  • Eklenti oluşturma: klasör, manifest, kurulum ve yetenekler
  • UI kiti: düğmeler, alanlar, listeler ve diğer yapı taşları