Przejdź do głównej zawartości
Nawigacja Otwórz escZamknij

API hosta

Użyj tej strony, gdy potrzebujesz dokładnych metod connectHost, limitów i kodów błędów. Układ folderu, manifest i instalację opisuje Tworzenie rozszerzenia.

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

connectHost rzuca HOST_UNAVAILABLE, gdy nie ma window. Poza OpenChamber zwraca klienta, którego każde wywołanie jest odrzucane z HOST_UNAVAILABLE. Wywołaj dispose(), gdy zamykasz stronę; wywołania jeszcze w toku są odrzucane z tym samym kodem.

Co OpenChamber do Ciebie wysyła

onReady odpala się z pierwszą migawką i ponownie za każdym razem, gdy OpenChamber ją odświeża.

To nie jest jednorazowy callback montowania. Zamontuj UI i zarejestruj subskrypcje raz, a potem aktualizuj motyw i kontekst bez zastępowania pól ani szkiców. Przykład z ochroną przed ponownym montowaniem znajdziesz w UI kit. Listenery takie jak onConnection od razu przekazują bieżącą wartość i mogą ją powtórzyć z nową migawką. Porównuj istotne pola przed nowym żądaniem i ignoruj odpowiedzi zastąpionych żądań.

PoleCo to jest
theme.modelight lub dark
theme.tokenskolory aplikacji (powierzchnie, tekst, stany interakcji, primary, success/warning/error/info), font, mono i radius. Przekaż to do applyHostReady przed zamontowaniem UI.
localetag języka aplikacji
directorykatalog bieżącego projektu albo null
session{ id, title, busy } albo null. Tytuł wraca do id sesji, gdy go brak. busy to status na żywo. model i agent (agent OpenCode) pojawiają się, gdy sesja je ma.
surfacepanel na pasku bocznym, dialog w oknie dołączania, page na pełnym ekranie
itemto, dla czego otwarto tę powierzchnię, albo null: dołączony element, który użytkownik kliknął (te same pola, które przekazałeś do attach, łącznie z data), wiadomość (kind: "message") albo sesja (kind: "session") z jednej z zadeklarowanych przez Ciebie akcji. Zobacz Akcje.
connection{ connected, account } dla Twojej integracji
settingswartości pól zadeklarowanych w integration.settings

Tokeny dostępu nigdy nie pojawiają się tutaj ani w wyniku request.

onDirectory, onSession, onSessionLifecycle, onConnection, onSettings i onItem odtwarzają ostatnią wartość, gdy subskrybujesz późno, a potem odpalają się dalej przy każdej zmianie.

theme.tokens zawiera primaryText, successText, warningText, errorText i infoText. Te wymagane pola zawierają kolory tekstu obliczone przez hosta dla neutralnych teł i delikatnie zabarwionych kontrolek zestawu UI, nie dla pełnych kolorowych wypełnień. applyHostReady stosuje je przy każdym nowym stanie. Zmienne CSS opisuje zestaw UI.

Metody

WywołanieCo robi
toast({ kind, message })pokazuje toast w aplikacji. kind to info, success lub error.
openUrl(url)otwiera adres URL w przeglądarce użytkownika
openSurface(surfaceId)przełącza aplikację na ten ekran
writeClipboard(text)kopiuje tekst. Od 1 do 32000 znaków.
compose({ text, mode? })wstawia tekst do pola czatu bez wysyłania. mode to append (domyślnie) lub replace. Od 1 do 16000 znaków po przycięciu.
attach({ ... })umieszcza chip na polu czatu, w tym samym miejscu, gdzie trafiają elementy z GitHub i Linear. Tylko jeden chip naraz.
startSession({ ... })tworzy sesję z dołączonym elementem. Zwraca { sessionId, sent }. Wymaga uprawnienia sessions.
prompt({ text, send? })wpisuje tekst do bieżącej sesji albo go w niej wysyła. Zwraca { sent }. Wysyłanie wymaga uprawnienia prompt.
sessionLink({ ... })dołącza element do bieżącej sesji bez tworzenia nowej
close()zamyka okno dołączania. Na pasku bocznym nic nie robi.
oauthStart()otwiera stronę autoryzacji dostawcy albo stronę Linear dla integracji host: { provider: "linear" }
oauthDisconnect()zapomina zapisany token albo połączenie z Linear
request({ method, path, query?, body? })wywołuje apiOrigin Twojej integracji z dołączonym tokenem użytkownika
serviceRequest({ method, path, query?, body? })wywołuje usługę lokalną Twojego rozszerzenia (zobacz GUEST_SERVICES.md)
serviceStatus()stopped, starting, ready lub failed
readFile(path)czyta plik tekstowy. Zwraca { content }.
writeFile(path, content)zapisuje plik tekstowy atomowo, tworząc foldery nadrzędne. Zwraca { written: true }.
listDir(path)wypisuje zawartość folderu. Zwraca { entries: [{ name, kind }] }, kind to file, directory lub other.
stat(path){ kind, size, mtime }, kind to file, directory, other lub missing.
generate({ prompt, system?, maxOutputTokens? })jednorazowy tekst od Small Model użytkownika. Zwraca { text }. Wymaga uprawnienia model.
onResolve(handler)rejestruje obsługę Twoich poleceń z ukośnikiem. Dostaje { command, args } i zwraca element do dołączenia albo null.
setBadge(count)pokazuje liczbę (0 do 999) na Twojej ikonie na pasku bocznym, albo null, żeby ją usunąć

Wszystkie trzy przyjmują te same pola elementu:

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 to id Twojego panelu; OpenChamber i tak nadpisuje je Twoim id. id to Twój własny identyfikator elementu. kind to issue (domyślnie) lub pull. text to opcjonalny kontekst dla modelu, od 1 do 16000 znaków po przycięciu. data to opcjonalny JSON na Twój użytek (status, komentarze, cokolwiek), do 16000 znaków po serializacji. OpenChamber zapisuje go razem z chipem i oddaje bez zmian w ctx.item, gdy użytkownik kliknie chip; nigdy nie trafia do modelu.

startSession przyjmuje projectId bez przełączania bieżącego projektu. Pominięte worktree oznacza katalog docelowy, true tworzy worktree z wygenerowaną nazwą, { kind: "existing", directory } wskazuje istniejące, a { kind: "new", name?, baseBranch? } nowe. Nazwa dotyczy też gałęzi. navigation domyślnie wynosi "preserve"; "open" otwiera nowy czat. Model, agent i wariant pierwszej wiadomości są ustalane na początku.

Wynik zawiera sessionId, directory, sent, linked i opcjonalne worktree. sent to sent, no-model, skipped lub failed; linked: false oznacza błąd zapisu elementu. Worktree pozostawione po błędzie przygotowania lub tworzenia sesji zwraca sessionId: null i failure: "bootstrap-failed" | "session-create-failed". Sprawdź wynik przed ponowieniem. Limit oczekiwania wynosi 180 sekund; timeout nie potwierdza wycofania operacji.

sessionLink dołącza element do sesji otwartej w tej chwili. Brak projektu lub brak sesji to błąd NO_SESSION.

Limity, które klient stosuje, zanim cokolwiek wyśle:

PoleMaks. znaków
id128
title200
url2000
text16000
data (po serializacji)16000
author80
każda nazwa gałęzi200

prompt i cykl życia sesji

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;
});

Bez send prompt zastępuje tekst w polu czatu. Z send: true wysyła wiadomość z modelem i agentem wybranymi przez użytkownika. Rozszerzenie nigdy ich nie wybiera. Brak otwartej sesji to NO_SESSION. Wysyłanie, gdy sesja jest zajęta, to SESSION_BUSY; wpisywanie do pola działa także wtedy. Wynik to { sent } z tymi samymi wartościami co w startSession.

onSessionLifecycle mówi, co robi sesja. phase to started, gdy model pracuje, completed, gdy sesja przechodzi w bezczynność, i failure przy nieoczekiwanym statusie. Późny nasłuchiwacz od razu dostaje bieżącą fazę.

Projekty, stany na żywo i pamięć

listProjects(), listWorktrees(projectId) i listSessions(projectId) używają istniejącego uprawnienia sessions i wspólnych store. Nie wykonują skanu Git przy każdym wywołaniu ani nie udostępniają rozmów. Projekty zawierają ID, nazwę i katalog, worktree także gałąź i dostępność. Sesje zawierają daty, rodzica, worktree i tylko elementy dołączone przez to rozszerzenie. Znane sesje archiwalne są uwzględnione.

await onProjects(listener), await onWorktrees(projectId, listener) i await onSessions(projectId, listener) zwracają funkcję anulowania subskrypcji. Obsłuż błędy rejestracji. Najpierw dostajesz migawkę, potem zmiany. Maksymalnie 32 subskrypcje na ramkę; dispose(), zamknięcie, wstrzymanie, usunięcie i zmiana serwera zwalniają je. state to loading, ready lub error, a sesje mają coverage dla katalogów. Błąd zachowuje dane; tylko ready potwierdza pełną pustą listę.

activity to unknown, idle, running, retrying, waiting-permission lub waiting-question. outcome to zaobserwowane completed, failed lub null, przechowywane wyłącznie w pamięci dla maksymalnie 2 000 sesji. Idle po błędzie zachowuje błąd do następnego uruchomienia. Nie oznacza to ukończenia zadania. openSession(sessionId) jawnie otwiera czat.

host.storage.get(key), set(key, value), delete(key) i keys() zapisują własny JSON na połączonym serwerze bez dodatkowego uprawnienia. Brak klucza daje undefined, zapisane null pozostaje null. Klucze mają od 1 do 128 znaków, wartość do 64 KiB UTF-8, całość do 2 MiB i 2 000 kluczy. Dla danych projektu umieść jego ID w kluczu. Zapisy są serializowane i atomowe, a błędy zachowują poprzednie dane. Usunięcie rozszerzenia usuwa pamięć.

request

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

path zaczyna się od / i nie ma schematu ani hosta; OpenChamber łączy go z apiOrigin z Twojego manifestu i dodaje nagłówek Authorization. Integracje tokenowe wysyłają wklejony token bez zmian, jako Bearer <token>, gdy manifest ustawia token.scheme: "bearer", albo jako Basic base64(username:token), gdy ustawia "basic". Integracje OAuth i Linear zawsze wysyłają Bearer. Wynik to { status, body }. Treść jest tekstem; JSON parsujesz samodzielnie.

Integracja Linear może też wywołać GET /api/linear/issues/get, na które OpenChamber odpowiada z własnej trasy Linear.

Brak odpowiedzi w ciągu 20 sekund to 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

Gdy manifest deklaruje contributes.service, OpenChamber uruchamia ten proces, a Twoja strona rozmawia z nim przez ten sam rodzaj wywołania. Strona nigdy sama nie otwiera socketu.

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

path podlega tym samym zasadom co w request. Zadeklarowanie usługi lokalnej dodaje service do uprawnień, które użytkownik zatwierdza przy instalacji; do tego czasu każde serviceRequest to NO_SERVICE. Pełny kontrakt: plik GUEST_SERVICES.md w pakiecie.

Pliki

Ścieżka względna leży w otwartym projekcie i wymaga uprawnienia files. Ścieżka zaczynająca się od / lub ~/ musi pasować do zadeklarowanego wzorca contributes.filesystem i wymaga uprawnienia filesystem. Zasady opisuje Tworzenie rozszerzenia.

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");

Limity: ścieżka do 1024 znaków, treść do 2 000 000 znaków, listing do 2000 wpisów. Przekroczenie limitu treści to FILE_TOO_LARGE.

generate

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

prompt ma od 1 do 64 000 znaków po przycięciu, system do 8000, maxOutputTokens od 1 do 4000. Nic nie trafia do sesji i historia nie jest zapisywana; rozszerzenie nigdy nie wybiera modelu. Wywołanie czeka maksymalnie 90 sekund. Brak dostępnego Small Model to NO_MODEL; błąd modelu to MODEL_FAILED. Zobacz Generowanie tekstu.

Kody błędów

Nieudane wywołania rzucają HostRequestError. code to jeden z poniższych; message mówi więcej.

KodKiedy
HOST_UNAVAILABLEbrak window, poza OpenChamber albo po wywołaniu dispose()
HOST_TIMEOUTbrak odpowiedzi przez 20 sekund
HOST_REJECTEDOpenChamber odmówił albo odpowiedział kodem, którego to SDK nie zna
DISCONNECTEDbrak tokena lub połączenia z Linear dla Twojej integracji
BAD_PATHpath był źle sformułowany albo próbował wyjść poza dozwolony origin
NO_INTEGRATIONmanifest nie ma integration
NO_SESSIONprompt lub sessionLink bez otwartej sesji
SESSION_BUSYprompt({ send: true }), gdy sesja była zajęta
DISABLEDużytkownik wstrzymał rozszerzenie w Ustawienia → Rozszerzenia
NO_SERVICEusługa lokalna niezadeklarowana, niezatwierdzona albo nieuruchomiona
NOT_GRANTEDużytkownik nie zatwierdził uprawnienia, którego wymaga to wywołanie
SERVICE_FAILEDusługa lokalna padła albo nigdy nie osiągnęła gotowości
NO_DIRECTORYwzględna ścieżka pliku użyta bez otwartego projektu
NOT_FOUNDreadFile na pliku, który nie istnieje
FILE_TOO_LARGEtreść pliku ponad limit, przy odczycie lub zapisie
DENIEDsystem operacyjny odmówił operacji na pliku
NO_MODELgenerate bez dostępnego Small Model
MODEL_FAILEDSmall Model zwrócił błąd

Zobacz też