Wewnętrzne elementy Plugin
To jest szczegółowe odniesienie do architektury. Praktyczne przewodniki znajdziesz tutaj:
- Zainstaluj i używaj pluginów — przewodnik użytkownika
- Pierwsze kroki — samouczek tworzenia pierwszego pluginu
- Pluginy kanałów — zbuduj kanał wiadomości
- Pluginy dostawców — zbuduj dostawcę modeli
- Przegląd SDK — mapa importów i API rejestracji
Publiczny model możliwości
Możliwości to publiczny model natywnych pluginów w OpenClaw. Każdy natywny plugin OpenClaw rejestruje się względem co najmniej jednego typu możliwości:| Możliwość | Metoda rejestracji | Przykładowe pluginy |
|---|---|---|
| Wnioskowanie tekstowe | api.registerProvider(...) | openai, anthropic |
| Backend wnioskowania CLI | api.registerCliBackend(...) | openai, anthropic |
| Mowa | api.registerSpeechProvider(...) | elevenlabs, microsoft |
| Transkrypcja w czasie rzeczywistym | api.registerRealtimeTranscriptionProvider(...) | openai |
| Głos w czasie rzeczywistym | api.registerRealtimeVoiceProvider(...) | openai |
| Rozumienie mediów | api.registerMediaUnderstandingProvider(...) | openai, google |
| Generowanie obrazów | api.registerImageGenerationProvider(...) | openai, google, fal, minimax |
| Generowanie muzyki | api.registerMusicGenerationProvider(...) | google, minimax |
| Generowanie wideo | api.registerVideoGenerationProvider(...) | qwen |
| Pobieranie z sieci | api.registerWebFetchProvider(...) | firecrawl |
| Wyszukiwanie w sieci | api.registerWebSearchProvider(...) | google |
| Kanał / wiadomości | api.registerChannel(...) | msteams, matrix |
Stan kompatybilności zewnętrznej
Model możliwości jest już wdrożony w core i używany dziś przez pluginy bundled/natywne, ale zgodność zewnętrznych pluginów nadal wymaga wyższego progu niż „jest eksportowane, więc jest zamrożone”. Aktualne wytyczne:- istniejące zewnętrzne pluginy: zachowaj działanie integracji opartych na hookach; traktuj to jako bazowy poziom kompatybilności
- nowe pluginy bundled/natywne: preferuj jawną rejestrację możliwości zamiast zależnych od dostawcy wejść w implementację lub nowych projektów tylko z hookami
- zewnętrzne pluginy przyjmujące rejestrację możliwości: dozwolone, ale traktuj pomocnicze powierzchnie specyficzne dla możliwości jako ewoluujące, chyba że dokumentacja wyraźnie oznacza dany kontrakt jako stabilny
- API rejestracji możliwości to zamierzony kierunek
- legacy hooki pozostają najbezpieczniejszą ścieżką bez naruszania zgodności dla zewnętrznych pluginów w trakcie przejścia
- eksportowane podścieżki pomocnicze nie są równorzędne; preferuj wąski, udokumentowany kontrakt, a nie przypadkowe eksporty pomocnicze
Kształty pluginów
OpenClaw klasyfikuje każdy załadowany plugin do określonego kształtu na podstawie jego rzeczywistego zachowania rejestracyjnego (a nie tylko statycznych metadanych):- plain-capability — rejestruje dokładnie jeden typ możliwości (na przykład
plugin tylko dostawcy, taki jak
mistral) - hybrid-capability — rejestruje wiele typów możliwości (na przykład
openaiobsługuje wnioskowanie tekstowe, mowę, rozumienie mediów i generowanie obrazów) - hook-only — rejestruje tylko hooki (typowane lub własne), bez możliwości, narzędzi, poleceń ani usług
- non-capability — rejestruje narzędzia, polecenia, usługi lub trasy, ale bez możliwości
openclaw plugins inspect <id>, aby zobaczyć kształt pluginu i podział
możliwości. Szczegóły znajdziesz w dokumentacji CLI.
Legacy hooki
Hookbefore_agent_start pozostaje obsługiwany jako ścieżka kompatybilności dla
pluginów tylko z hookami. Nadal zależą od niego starsze pluginy używane w praktyce.
Kierunek:
- utrzymać jego działanie
- dokumentować go jako legacy
- dla pracy z nadpisywaniem modelu/dostawcy preferować
before_model_resolve - dla modyfikacji promptów preferować
before_prompt_build - usunąć dopiero wtedy, gdy realne użycie spadnie, a pokrycie fixture potwierdzi bezpieczeństwo migracji
Sygnały kompatybilności
Po uruchomieniuopenclaw doctor lub openclaw plugins inspect <id> możesz zobaczyć
jedną z tych etykiet:
| Sygnał | Znaczenie |
|---|---|
| config valid | Konfiguracja poprawnie się parsuje, a pluginy są rozwiązywane |
| compatibility advisory | Plugin używa wspieranego, ale starszego wzorca (np. hook-only) |
| legacy warning | Plugin używa before_agent_start, które jest przestarzałe |
| hard error | Konfiguracja jest nieprawidłowa lub nie udało się załadować pluginu |
hook-only, ani before_agent_start nie spowodują dziś uszkodzenia pluginu —
hook-only ma charakter doradczy, a before_agent_start wywołuje jedynie ostrzeżenie. Te
sygnały pojawiają się również w openclaw status --all i openclaw plugins doctor.
Przegląd architektury
System pluginów OpenClaw ma cztery warstwy:- Manifest + wykrywanie
OpenClaw znajduje kandydackie pluginy w skonfigurowanych ścieżkach, katalogach głównych workspace,
globalnych katalogach rozszerzeń i bundled extensions. Wykrywanie najpierw odczytuje natywne
manifesty
openclaw.plugin.jsonoraz obsługiwane manifesty pakietów. - Włączanie + walidacja Core decyduje, czy wykryty plugin jest włączony, wyłączony, zablokowany czy wybrany do ekskluzywnego slotu, takiego jak pamięć.
- Ładowanie środowiska uruchomieniowego Natywne pluginy OpenClaw są ładowane w procesie przez jiti i rejestrują możliwości w centralnym rejestrze. Zgodne pakiety są normalizowane do rekordów rejestru bez importowania kodu środowiska uruchomieniowego.
- Konsumpcja powierzchni Pozostała część OpenClaw odczytuje rejestr, aby udostępniać narzędzia, kanały, konfigurację dostawców, hooki, trasy HTTP, polecenia CLI i usługi.
- metadane na etapie parsowania pochodzą z
registerCli(..., { descriptors: [...] }) - rzeczywisty moduł CLI pluginu może pozostać lazy i zarejestrować się przy pierwszym wywołaniu
- wykrywanie + walidacja konfiguracji powinny działać na podstawie metadanych manifestu/schematu bez wykonywania kodu pluginu
- natywne zachowanie środowiska uruchomieniowego pochodzi ze ścieżki modułu pluginu
register(api)
Pluginy kanałów i współdzielone narzędzie wiadomości
Pluginy kanałów nie muszą rejestrować osobnego narzędzia send/edit/react dla zwykłych działań czatu. OpenClaw utrzymuje jedno współdzielone narzędziemessage w core, a
pluginy kanałów odpowiadają za specyficzne dla kanału wykrywanie i wykonanie za nim.
Obecna granica wygląda tak:
- core odpowiada za host współdzielonego narzędzia
message, połączenie z promptami, prowadzenie sesji/wątków i dyspozycję wykonania - pluginy kanałów odpowiadają za wykrywanie działań w danym zakresie, wykrywanie możliwości oraz wszelkie fragmenty schematu specyficzne dla kanału
- pluginy kanałów odpowiadają za gramatykę rozmów sesji specyficzną dla dostawcy, na przykład sposób, w jaki identyfikatory konwersacji kodują identyfikatory wątków lub dziedziczą po konwersacjach nadrzędnych
- pluginy kanałów wykonują końcowe działanie przez swój adapter działań
ChannelMessageActionAdapter.describeMessageTool(...). To zunifikowane wywołanie wykrywania
pozwala pluginowi zwrócić widoczne działania, możliwości i wkłady do schematu
razem, aby te elementy nie rozjeżdżały się między sobą.
Gdy parametr narzędzia wiadomości specyficzny dla kanału zawiera źródło mediów, takie jak
lokalna ścieżka lub zdalny URL mediów, plugin powinien również zwrócić
mediaSourceParams z describeMessageTool(...). Core używa tej jawnej
listy, aby stosować normalizację ścieżek sandbox i wskazówki dotyczące wychodzącego dostępu do mediów
bez hardkodowania nazw parametrów należących do pluginu.
Preferuj tam mapy ograniczone do działań, a nie jedną płaską listę dla całego kanału, aby
parametr mediów przeznaczony tylko dla profilu nie był normalizowany przy niezwiązanych działaniach, takich jak
send.
Core przekazuje zakres środowiska uruchomieniowego do tego kroku wykrywania. Ważne pola obejmują:
accountIdcurrentChannelIdcurrentThreadTscurrentMessageIdsessionKeysessionIdagentId- zaufane przychodzące
requesterSenderId
message w core.
Właśnie dlatego zmiany routingu embedded-runner nadal należą do pracy nad pluginami: runner
odpowiada za przekazywanie bieżącej tożsamości czatu/sesji do granicy wykrywania pluginu, aby
współdzielone narzędzie message ujawniało właściwą powierzchnię należącą do kanału dla
bieżącego kroku.
W przypadku narzędzi pomocniczych wykonania należących do kanału, bundled pluginy powinny utrzymywać
środowisko uruchomieniowe wykonania wewnątrz własnych modułów rozszerzeń. Core nie odpowiada już za
środowiska uruchomieniowe działań wiadomości Discord, Slack, Telegram czy WhatsApp pod src/agents/tools.
Nie publikujemy osobnych podścieżek plugin-sdk/*-action-runtime, a bundled
pluginy powinny importować swój lokalny kod środowiska uruchomieniowego bezpośrednio z modułów
należących do ich rozszerzeń.
Ta sama granica dotyczy ogólnie ścieżek SDK nazwanych według dostawców: core nie powinien
importować wygodnych barrelów specyficznych dla kanałów takich jak Slack, Discord, Signal,
WhatsApp lub podobnych rozszerzeń. Jeśli core potrzebuje jakiegoś zachowania, powinien albo
zużyć własny barrel api.ts / runtime-api.ts danego bundled pluginu, albo wynieść tę potrzebę
do wąskiej, ogólnej możliwości we współdzielonym SDK.
Konkretnie dla ankiet istnieją dwie ścieżki wykonania:
outbound.sendPollto współdzielona baza dla kanałów pasujących do wspólnego modelu ankietactions.handleAction("poll")to preferowana ścieżka dla semantyki ankiet specyficznej dla kanału lub dodatkowych parametrów ankiet
Model własności możliwości
OpenClaw traktuje natywny plugin jako granicę własności dla firmy lub funkcji, a nie jako zbiór przypadkowo powiązanych integracji. Oznacza to, że:- plugin firmowy powinien zwykle obsługiwać wszystkie powierzchnie OpenClaw skierowane do tej firmy
- plugin funkcjonalny powinien zwykle obsługiwać pełną powierzchnię funkcji, którą wprowadza
- kanały powinny korzystać ze współdzielonych możliwości core zamiast doraźnie ponownie implementować zachowanie dostawców
- bundled plugin
openaiodpowiada za zachowanie dostawcy modeli OpenAI oraz za zachowanie OpenAI dotyczące mowy + głosu w czasie rzeczywistym + rozumienia mediów + generowania obrazów - bundled plugin
elevenlabsodpowiada za zachowanie ElevenLabs dotyczące mowy - bundled plugin
microsoftodpowiada za zachowanie Microsoft dotyczące mowy - bundled plugin
googleodpowiada za zachowanie dostawcy modeli Google oraz za zachowanie Google dotyczące rozumienia mediów + generowania obrazów + wyszukiwania w sieci - bundled plugin
firecrawlodpowiada za zachowanie Firecrawl dotyczące pobierania z sieci - bundled pluginy
minimax,mistral,moonshotizaiodpowiadają za swoje backendy rozumienia mediów - bundled plugin
qwenodpowiada za zachowanie dostawcy tekstowego Qwen oraz za rozumienie mediów i generowanie wideo - plugin
voice-calljest pluginem funkcjonalnym: odpowiada za transport połączeń, narzędzia, CLI, trasy i mostkowanie strumienia mediów Twilio, ale korzysta ze współdzielonych możliwości mowy oraz transkrypcji w czasie rzeczywistym i głosu w czasie rzeczywistym zamiast bezpośrednio importować pluginy dostawców
- OpenAI znajduje się w jednym pluginie, nawet jeśli obejmuje modele tekstowe, mowę, obrazy i przyszłe wideo
- inny dostawca może zrobić to samo dla własnego obszaru funkcjonalnego
- kanały nie muszą wiedzieć, który plugin dostawcy jest właścicielem dostawcy; korzystają ze współdzielonego kontraktu możliwości udostępnianego przez core
- plugin = granica własności
- możliwość = kontrakt core, który wiele pluginów może implementować lub wykorzystywać
- zdefiniowanie brakującej możliwości w core
- udostępnienie jej przez API/runtime pluginów w sposób typowany
- podłączenie kanałów/funkcji do tej możliwości
- pozwolenie pluginom dostawców na rejestrowanie implementacji
Warstwowanie możliwości
Używaj tego modelu mentalnego przy podejmowaniu decyzji, gdzie powinien znajdować się kod:- warstwa możliwości core: współdzielona orkiestracja, polityka, fallback, reguły scalania konfiguracji, semantyka dostarczania i typowane kontrakty
- warstwa pluginów dostawców: API specyficzne dla dostawcy, autoryzacja, katalogi modeli, synteza mowy, generowanie obrazów, przyszłe backendy wideo, endpointy użycia
- warstwa pluginów kanałów/funkcji: integracje Slack/Discord/voice-call itd., które wykorzystują możliwości core i prezentują je na określonej powierzchni
- core odpowiada za politykę TTS w czasie odpowiedzi, kolejność fallbacków, preferencje i dostarczanie przez kanały
openai,elevenlabsimicrosoftodpowiadają za implementacje syntezyvoice-callwykorzystuje pomocnik środowiska uruchomieniowego TTS dla telefonii
Przykład pluginu firmy z wieloma możliwościami
Plugin firmy powinien z zewnątrz sprawiać wrażenie spójnego. Jeśli OpenClaw ma współdzielone kontrakty dla modeli, mowy, transkrypcji w czasie rzeczywistym, głosu w czasie rzeczywistym, rozumienia mediów, generowania obrazów, generowania wideo, pobierania z sieci i wyszukiwania w sieci, dostawca może obsługiwać wszystkie swoje powierzchnie w jednym miejscu:- jeden plugin jest właścicielem powierzchni dostawcy
- core nadal jest właścicielem kontraktów możliwości
- kanały i pluginy funkcjonalne wykorzystują helpery
api.runtime.*, a nie kod dostawcy - testy kontraktowe mogą sprawdzać, że plugin zarejestrował możliwości, do których przyznaje się jako właściciel
Przykład możliwości: rozumienie wideo
OpenClaw już teraz traktuje rozumienie obrazów/audio/wideo jako jedną współdzieloną możliwość. Obowiązuje tu ten sam model własności:- core definiuje kontrakt rozumienia mediów
- pluginy dostawców rejestrują
describeImage,transcribeAudioidescribeVideo, jeśli dotyczy - kanały i pluginy funkcjonalne wykorzystują współdzielone zachowanie core zamiast podłączać się bezpośrednio do kodu dostawcy
api.registerVideoGenerationProvider(...) względem niego.
Potrzebujesz konkretnej listy kontrolnej wdrożenia? Zobacz
Capability Cookbook.
Kontrakty i egzekwowanie
Powierzchnia API pluginów jest celowo typowana i scentralizowana wOpenClawPluginApi. Ten kontrakt definiuje obsługiwane punkty rejestracji oraz
pomocniki środowiska uruchomieniowego, na których plugin może polegać.
Dlaczego to ma znaczenie:
- autorzy pluginów otrzymują jeden stabilny wewnętrzny standard
- core może odrzucać duplikaty własności, na przykład gdy dwa pluginy rejestrują ten sam identyfikator dostawcy
- uruchamianie może pokazywać użyteczne diagnostyki dla nieprawidłowej rejestracji
- testy kontraktowe mogą wymuszać własność bundled pluginów i zapobiegać cichemu dryfowi
- egzekwowanie rejestracji w czasie działania Rejestr pluginów waliduje rejestracje podczas ładowania pluginów. Przykłady: zduplikowane identyfikatory dostawców, zduplikowane identyfikatory dostawców mowy i nieprawidłowe rejestracje powodują diagnostyki pluginów zamiast niezdefiniowanego zachowania.
- testy kontraktowe Bundled pluginy są przechwytywane w rejestrach kontraktowych podczas uruchamiania testów, dzięki czemu OpenClaw może jawnie sprawdzać własność. Dziś jest to używane dla dostawców modeli, dostawców mowy, dostawców wyszukiwania w sieci oraz własności rejestracji bundled pluginów.
Co należy do kontraktu
Dobre kontrakty pluginów są:- typowane
- małe
- specyficzne dla możliwości
- należące do core
- wielokrotnego użytku przez wiele pluginów
- możliwe do wykorzystania przez kanały/funkcje bez wiedzy o dostawcy
- polityka specyficzna dla dostawcy ukryta w core
- jednorazowe furtki dla pluginów, które omijają rejestr
- kod kanału sięgający bezpośrednio do implementacji dostawcy
- doraźne obiekty środowiska uruchomieniowego, które nie są częścią
OpenClawPluginApianiapi.runtime
Model wykonania
Natywne pluginy OpenClaw działają w procesie razem z Gateway. Nie są sandboxowane. Załadowany natywny plugin ma tę samą granicę zaufania na poziomie procesu co kod core. Konsekwencje:- natywny plugin może rejestrować narzędzia, handlery sieciowe, hooki i usługi
- błąd natywnego pluginu może spowodować awarię lub destabilizację gateway
- złośliwy natywny plugin jest równoważny dowolnemu wykonaniu kodu wewnątrz procesu OpenClaw
@openclaw/<id> lub zatwierdzony typowany sufiks, taki jak
-provider, -plugin, -speech, -sandbox lub -media-understanding, gdy
pakiet celowo udostępnia węższą rolę pluginu.
Ważna uwaga dotycząca zaufania:
plugins.allowufa identyfikatorom pluginów, a nie pochodzeniu źródła.- Plugin workspace z tym samym identyfikatorem co bundled plugin celowo przesłania bundled kopię, gdy taki plugin workspace jest włączony/znajduje się na allowliście.
- To normalne i przydatne dla lokalnego programowania, testowania poprawek i hotfixów.
Granica eksportu
OpenClaw eksportuje możliwości, a nie wygodne implementacje. Zachowaj publiczną rejestrację możliwości. Ogranicz eksporty helperów spoza kontraktu:- podścieżki pomocnicze specyficzne dla bundled pluginów
- podścieżki infrastruktury runtime, które nie są przeznaczone jako publiczne API
- helpery wygody specyficzne dla dostawców
- helpery konfiguracji/onboardingu, które są szczegółami implementacji
plugin-sdk/feishu, plugin-sdk/feishu-setup, plugin-sdk/zalo,
plugin-sdk/zalo-setup oraz kilka ścieżek plugin-sdk/matrix*. Traktuj je jako
zastrzeżone eksporty będące szczegółami implementacji, a nie jako zalecany wzorzec SDK dla
nowych pluginów zewnętrznych.
Potok ładowania
Podczas uruchamiania OpenClaw wykonuje w przybliżeniu następujące kroki:- wykrywa katalogi główne kandydackich pluginów
- odczytuje natywne lub zgodne manifesty pakietów i metadane pakietów
- odrzuca niebezpiecznych kandydatów
- normalizuje konfigurację pluginów (
plugins.enabled,allow,deny,entries,slots,load.paths) - decyduje o włączeniu dla każdego kandydata
- ładuje włączone natywne moduły przez jiti
- wywołuje natywne hooki
register(api)(lubactivate(api)— starszy alias) i zbiera rejestracje do rejestru pluginów - udostępnia rejestr powierzchniom poleceń/runtime
activate to starszy alias dla register — loader rozwiązuje, który z nich jest obecny (def.register ?? def.activate) i wywołuje go w tym samym miejscu. Wszystkie bundled pluginy używają register; dla nowych pluginów preferuj register.Zachowanie manifest-first
Manifest jest źródłem prawdy dla płaszczyzny sterowania. OpenClaw używa go do:- identyfikacji pluginu
- wykrywania zadeklarowanych kanałów/Skills/schematu konfiguracji lub możliwości pakietu
- walidacji
plugins.entries.<id>.config - uzupełniania etykiet/placeholderów w Control UI
- wyświetlania metadanych instalacji/katalogu
- zachowania tanich deskryptorów aktywacji i konfiguracji bez ładowania runtime pluginu
activation i setup pozostają w płaszczyźnie sterowania.
Są to wyłącznie deskryptory metadanych dla planowania aktywacji i wykrywania konfiguracji;
nie zastępują rejestracji runtime, register(...) ani setupEntry.
Pierwsi konsumenci aktywacji na żywo używają teraz wskazówek manifestu dotyczących poleceń, kanałów i dostawców,
aby zawężać ładowanie pluginów przed szerszą materializacją rejestru:
- ładowanie CLI zawęża się do pluginów, które są właścicielami żądanej głównej komendy
- rozwiązywanie konfiguracji kanałów/pluginów zawęża się do pluginów, które są właścicielami żądanego identyfikatora kanału
- jawne rozwiązywanie konfiguracji/runtime dostawców zawęża się do pluginów, które są właścicielami żądanego identyfikatora dostawcy
setup.providers i
setup.cliBackends, aby zawężać kandydackie pluginy, zanim nastąpi powrót do
setup-api dla pluginów, które nadal potrzebują hooków runtime w czasie konfiguracji. Jeśli więcej niż
jeden wykryty plugin zgłasza ten sam znormalizowany identyfikator dostawcy konfiguracji lub backendu CLI,
wyszukiwanie konfiguracji odrzuca niejednoznacznego właściciela zamiast polegać na kolejności wykrywania.
Co loader przechowuje w pamięci podręcznej
OpenClaw utrzymuje krótkotrwałe pamięci podręczne w procesie dla:- wyników wykrywania
- danych rejestru manifestów
- załadowanych rejestrów pluginów
- Ustaw
OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1lubOPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1, aby wyłączyć te pamięci podręczne. - Dostosuj okna pamięci podręcznej za pomocą
OPENCLAW_PLUGIN_DISCOVERY_CACHE_MSiOPENCLAW_PLUGIN_MANIFEST_CACHE_MS.
Model rejestru
Załadowane pluginy nie modyfikują bezpośrednio przypadkowych globalnych elementów core. Rejestrują się w centralnym rejestrze pluginów. Rejestr śledzi:- rekordy pluginów (tożsamość, źródło, pochodzenie, status, diagnostyka)
- narzędzia
- legacy hooki i hooki typowane
- kanały
- dostawców
- handlery RPC Gateway
- trasy HTTP
- rejestratory CLI
- usługi działające w tle
- polecenia należące do pluginów
- moduł pluginu -> rejestracja w rejestrze
- runtime core -> konsumpcja rejestru
Callbacki powiązania konwersacji
Pluginy, które wiążą konwersację, mogą reagować, gdy zatwierdzenie zostanie rozstrzygnięte. Użyjapi.onConversationBindingResolved(...), aby otrzymać callback po zatwierdzeniu lub odrzuceniu
żądania powiązania:
status:"approved"lub"denied"decision:"allow-once","allow-always"lub"deny"binding: rozstrzygnięte powiązanie dla zatwierdzonych żądańrequest: podsumowanie oryginalnego żądania, wskazówka odłączenia, identyfikator nadawcy oraz metadane konwersacji
Hooki środowiska uruchomieniowego dostawcy
Pluginy dostawców mają teraz dwie warstwy:- metadane manifestu:
providerAuthEnvVarsdla taniego wyszukiwania uwierzytelniania dostawcy przez env przed załadowaniem runtime,providerAuthAliasesdla wariantów dostawcy współdzielących uwierzytelnianie,channelEnvVarsdla taniego wyszukiwania env/konfiguracji kanału przed załadowaniem runtime orazproviderAuthChoicesdla tanich etykiet onboardingu/wyboru uwierzytelniania i metadanych flag CLI przed załadowaniem runtime - hooki czasu konfiguracji:
catalog/ starszediscoveryorazapplyConfigDefaults - hooki runtime:
normalizeModelId,normalizeTransport,normalizeConfig,applyNativeStreamingUsageCompat,resolveConfigApiKey,resolveSyntheticAuth,resolveExternalAuthProfiles,shouldDeferSyntheticProfileAuth,resolveDynamicModel,prepareDynamicModel,normalizeResolvedModel,contributeResolvedModelCompat,capabilities,normalizeToolSchemas,inspectToolSchemas,resolveReasoningOutputMode,prepareExtraParams,createStreamFn,wrapStreamFn,resolveTransportTurnState,resolveWebSocketSessionPolicy,formatApiKey,refreshOAuth,buildAuthDoctorHint,matchesContextOverflowError,classifyFailoverReason,isCacheTtlEligible,buildMissingAuthMessage,suppressBuiltInModel,augmentModelCatalog,isBinaryThinking,supportsXHighThinking,resolveDefaultThinkingLevel,isModernModelRef,prepareRuntimeAuth,resolveUsageAuth,fetchUsageSnapshot,createEmbeddingProvider,buildReplayPolicy,sanitizeReplayHistory,validateReplayTurns,onModelSelected
providerAuthEnvVars, gdy dostawca ma poświadczenia oparte na env,
które ogólne ścieżki auth/status/wyboru modelu powinny widzieć bez ładowania runtime pluginu. Użyj manifestu
providerAuthAliases, gdy jeden identyfikator dostawcy ma ponownie używać zmiennych env innego
identyfikatora dostawcy, profili auth, auth opartego na konfiguracji i opcji onboardingu klucza API. Użyj manifestu
providerAuthChoices, gdy powierzchnie CLI onboardingu/wyboru auth powinny znać identyfikator opcji dostawcy,
etykiety grup i proste połączenie auth z użyciem jednej flagi bez ładowania runtime dostawcy. Zachowaj runtime dostawcy
envVars dla wskazówek skierowanych do operatora, takich jak etykiety onboardingu lub zmienne konfiguracji
client-id/client-secret dla OAuth.
Użyj manifestu channelEnvVars, gdy kanał ma auth lub konfigurację sterowaną przez env, które
ogólny fallback shell-env, kontrole config/status lub prompty konfiguracji powinny widzieć
bez ładowania runtime kanału.
Kolejność hooków i sposób użycia
W przypadku pluginów modeli/dostawców OpenClaw wywołuje hooki mniej więcej w tej kolejności. Kolumna „Kiedy używać” to szybki przewodnik decyzyjny.| # | Hook | Co robi | Kiedy używać |
|---|---|---|---|
| 1 | catalog | Publikuje konfigurację dostawcy do models.providers podczas generowania models.json | Dostawca jest właścicielem katalogu lub domyślnych wartości base URL |
| 2 | applyConfigDefaults | Stosuje globalne domyślne wartości konfiguracji należące do dostawcy podczas materializacji konfiguracji | Wartości domyślne zależą od trybu auth, env lub semantyki rodziny modeli dostawcy |
| — | (built-in model lookup) | OpenClaw najpierw próbuje zwykłej ścieżki rejestru/katalogu | (to nie jest hook pluginu) |
| 3 | normalizeModelId | Normalizuje starsze aliasy identyfikatorów modeli lub aliasy wersji preview przed wyszukaniem | Dostawca jest właścicielem czyszczenia aliasów przed rozstrzygnięciem kanonicznego modelu |
| 4 | normalizeTransport | Normalizuje api / baseUrl rodziny dostawców przed ogólnym składaniem modelu | Dostawca odpowiada za czyszczenie transportu dla niestandardowych identyfikatorów dostawców w tej samej rodzinie transportu |
| 5 | normalizeConfig | Normalizuje models.providers.<id> przed rozstrzygnięciem runtime/dostawcy | Dostawca potrzebuje czyszczenia konfiguracji, które powinno znajdować się razem z pluginem; bundled helpery rodziny Google pełnią też rolę zabezpieczenia dla obsługiwanych wpisów konfiguracji Google |
| 6 | applyNativeStreamingUsageCompat | Stosuje zgodnościowe przekształcenia użycia natywnego streamingu do dostawców konfiguracji | Dostawca potrzebuje poprawek metadanych użycia natywnego streamingu zależnych od endpointu |
| 7 | resolveConfigApiKey | Rozstrzyga auth typu env-marker dla dostawców konfiguracji przed załadowaniem auth runtime | Dostawca ma własne rozstrzyganie klucza API env-marker; amazon-bedrock ma tu również wbudowany resolver env-marker AWS |
| 8 | resolveSyntheticAuth | Udostępnia auth lokalne/self-hosted lub oparte na konfiguracji bez utrwalania jawnego tekstu | Dostawca może działać z syntetycznym/lokalnym znacznikiem poświadczeń |
| 9 | resolveExternalAuthProfiles | Nakłada zewnętrzne profile auth należące do dostawcy; domyślne persistence to runtime-only dla poświadczeń należących do CLI/aplikacji | Dostawca ponownie używa zewnętrznych poświadczeń auth bez utrwalania skopiowanych tokenów odświeżania |
| 10 | shouldDeferSyntheticProfileAuth | Obniża priorytet zapisanych syntetycznych placeholderów profili względem auth opartego na env/konfiguracji | Dostawca przechowuje syntetyczne profile-placeholdery, które nie powinny mieć pierwszeństwa |
| 11 | resolveDynamicModel | Synchroniczny fallback dla należących do dostawcy identyfikatorów modeli, których nie ma jeszcze w lokalnym rejestrze | Dostawca akceptuje dowolne identyfikatory modeli z upstreamu |
| 12 | prepareDynamicModel | Asynchroniczne rozgrzanie, po czym resolveDynamicModel uruchamia się ponownie | Dostawca potrzebuje metadanych sieciowych przed rozstrzygnięciem nieznanych identyfikatorów |
| 13 | normalizeResolvedModel | Końcowe przepisanie przed użyciem rozstrzygniętego modelu przez embedded runner | Dostawca potrzebuje przekształceń transportu, ale nadal używa transportu core |
| 14 | contributeResolvedModelCompat | Dodaje flagi zgodności dla modeli dostawcy działających za innym zgodnym transportem | Dostawca rozpoznaje własne modele na transportach proxy bez przejmowania własności dostawcy |
| 15 | capabilities | Metadane transkryptu/narzędzi należące do dostawcy, używane przez współdzieloną logikę core | Dostawca potrzebuje niuansów związanych z transkryptem/rodziną dostawców |
| 16 | normalizeToolSchemas | Normalizuje schematy narzędzi, zanim zobaczy je embedded runner | Dostawca potrzebuje czyszczenia schematów na poziomie rodziny transportu |
| 17 | inspectToolSchemas | Udostępnia diagnostykę schematów należącą do dostawcy po normalizacji | Dostawca chce ostrzeżeń o słowach kluczowych bez uczenia core reguł specyficznych dla dostawcy |
| 18 | resolveReasoningOutputMode | Wybiera kontrakt wyjścia rozumowania: natywny lub otagowany | Dostawca potrzebuje otagowanego rozumowania/końcowego wyjścia zamiast natywnych pól |
| 19 | prepareExtraParams | Normalizacja parametrów żądania przed ogólnymi wrapperami opcji streamu | Dostawca potrzebuje domyślnych parametrów żądania lub czyszczenia parametrów dla konkretnego dostawcy |
| 20 | createStreamFn | Całkowicie zastępuje zwykłą ścieżkę streamu niestandardowym transportem | Dostawca potrzebuje własnego protokołu przewodowego, a nie tylko wrappera |
| 21 | wrapStreamFn | Wrapper streamu po zastosowaniu wrapperów ogólnych | Dostawca potrzebuje wrapperów zgodności dla nagłówków/treści/modelu żądania bez własnego transportu |
| 22 | resolveTransportTurnState | Dołącza natywne nagłówki transportu na turę lub metadane | Dostawca chce, aby ogólne transporty wysyłały natywną tożsamość tury dostawcy |
| 23 | resolveWebSocketSessionPolicy | Dołącza natywne nagłówki WebSocket lub politykę cooldown sesji | Dostawca chce, aby ogólne transporty WS dostrajały nagłówki sesji lub politykę fallback |
| 24 | formatApiKey | Formater profilu auth: zapisany profil staje się ciągiem apiKey w runtime | Dostawca przechowuje dodatkowe metadane auth i potrzebuje niestandardowego kształtu tokenu w runtime |
| 25 | refreshOAuth | Nadpisanie odświeżania OAuth dla niestandardowych endpointów odświeżania lub polityki błędów odświeżania | Dostawca nie pasuje do współdzielonych mechanizmów odświeżania pi-ai |
| 26 | buildAuthDoctorHint | Wskazówka naprawcza dołączana po nieudanym odświeżeniu OAuth | Dostawca potrzebuje własnych wskazówek naprawy auth po błędzie odświeżania |
| 27 | matchesContextOverflowError | Matcher przepełnienia okna kontekstu należący do dostawcy | Dostawca ma surowe błędy przepełnienia, których nie wykryją ogólne heurystyki |
| 28 | classifyFailoverReason | Klasyfikacja przyczyny failover należąca do dostawcy | Dostawca może mapować surowe błędy API/transportu na rate-limit/przeciążenie itd. |
| 29 | isCacheTtlEligible | Polityka prompt-cache dla dostawców proxy/backhaul | Dostawca potrzebuje bramkowania TTL cache specyficznego dla proxy |
| 30 | buildMissingAuthMessage | Zastępstwo dla ogólnego komunikatu odzyskiwania po brakującym auth | Dostawca potrzebuje własnej wskazówki odzyskiwania po brakującym auth |
| 31 | suppressBuiltInModel | Tłumienie nieaktualnych modeli z upstreamu plus opcjonalna wskazówka błędu dla użytkownika | Dostawca musi ukryć nieaktualne wiersze upstreamu lub zastąpić je wskazówką od dostawcy |
| 32 | augmentModelCatalog | Syntetyczne/końcowe wiersze katalogu dodawane po wykryciu | Dostawca potrzebuje syntetycznych wierszy forward-compat w models list i selektorach |
| 33 | isBinaryThinking | Przełącznik rozumowania włącz/wyłącz dla dostawców binary-thinking | Dostawca udostępnia tylko binarne włączanie/wyłączanie rozumowania |
| 34 | supportsXHighThinking | Obsługa rozumowania xhigh dla wybranych modeli | Dostawca chce xhigh tylko dla części modeli |
| 35 | resolveDefaultThinkingLevel | Domyślny poziom /think dla konkretnej rodziny modeli | Dostawca odpowiada za domyślną politykę /think dla rodziny modeli |
| 36 | isModernModelRef | Matcher nowoczesnych modeli dla filtrów profili live i wyboru smoke | Dostawca odpowiada za dopasowywanie preferowanych modeli live/smoke |
| 37 | prepareRuntimeAuth | Wymienia skonfigurowane poświadczenie na rzeczywisty token/klucz runtime tuż przed wnioskowaniem | Dostawca potrzebuje wymiany tokenu lub krótkotrwałego poświadczenia żądania |
| 38 | resolveUsageAuth | Rozstrzyga poświadczenia użycia/rozliczeń dla /usage i powiązanych powierzchni statusu | Dostawca potrzebuje niestandardowego parsowania tokenu użycia/limitu lub innego poświadczenia użycia |
| 39 | fetchUsageSnapshot | Pobiera i normalizuje snapshoty użycia/limitów specyficzne dla dostawcy po rozstrzygnięciu auth | Dostawca potrzebuje endpointu użycia specyficznego dla dostawcy lub parsera ładunku |
| 40 | createEmbeddingProvider | Buduje adapter embeddingów należący do dostawcy dla pamięci/wyszukiwania | Zachowanie embeddingów pamięci należy do pluginu dostawcy |
| 41 | buildReplayPolicy | Zwraca politykę replay kontrolującą obsługę transkryptu dla dostawcy | Dostawca potrzebuje własnej polityki transkryptu (na przykład usuwania bloków rozumowania) |
| 42 | sanitizeReplayHistory | Przepisuje historię replay po ogólnym czyszczeniu transkryptu | Dostawca potrzebuje przekształceń replay specyficznych dla dostawcy wykraczających poza współdzielone helpery Compaction |
| 43 | validateReplayTurns | Końcowa walidacja lub przekształcanie tur replay przed embedded runnerem | Transport dostawcy potrzebuje bardziej rygorystycznej walidacji tur po ogólnej sanityzacji |
| 44 | onModelSelected | Uruchamia skutki uboczne po wyborze modelu należące do dostawcy | Dostawca potrzebuje telemetrii lub stanu należącego do dostawcy, gdy model staje się aktywny |
normalizeModelId, normalizeTransport i normalizeConfig najpierw sprawdzają
dopasowany plugin dostawcy, a następnie przechodzą do innych pluginów dostawców obsługujących hooki,
dopóki któryś rzeczywiście nie zmieni identyfikatora modelu albo transportu/konfiguracji. Dzięki temu
shimy aliasów/zgodności dostawców nadal działają bez wymagania, aby wywołujący wiedział, który
bundled plugin jest właścicielem przepisania. Jeśli żaden hook dostawcy nie przepisze obsługiwanego
wpisu konfiguracji z rodziny Google, bundled normalizator konfiguracji Google nadal zastosuje
to czyszczenie zgodności.
Jeśli dostawca potrzebuje w pełni niestandardowego protokołu przewodowego lub własnego wykonawcy żądań,
jest to inna klasa rozszerzenia. Te hooki służą do zachowań dostawcy, które nadal działają
w zwykłej pętli wnioskowania OpenClaw.
Przykład dostawcy
Wbudowane przykłady
- Anthropic używa
resolveDynamicModel,capabilities,buildAuthDoctorHint,resolveUsageAuth,fetchUsageSnapshot,isCacheTtlEligible,resolveDefaultThinkingLevel,applyConfigDefaults,isModernModelRefiwrapStreamFn, ponieważ odpowiada za zgodność forward-compat Claude 4.6, wskazówki dotyczące rodziny dostawców, wskazówki naprawy auth, integrację endpointu użycia, kwalifikowalność prompt-cache, domyślne wartości konfiguracji zależne od auth, domyślną/adaptacyjną politykę rozumowania Claude oraz kształtowanie streamu specyficzne dla Anthropic dla nagłówków beta,/fast/serviceTiericontext1m. - Helpery streamu Anthropic specyficzne dla Claude pozostają na razie we własnej
publicznej powierzchni
api.ts/contract-api.tsbundled pluginu. Ta powierzchnia pakietu eksportujewrapAnthropicProviderStream,resolveAnthropicBetas,resolveAnthropicFastMode,resolveAnthropicServiceTieroraz niższopoziomowe konstruktory wrapperów Anthropic zamiast rozszerzać ogólne SDK o reguły nagłówków beta jednego dostawcy. - OpenAI używa
resolveDynamicModel,normalizeResolvedModelicapabilities, a takżebuildMissingAuthMessage,suppressBuiltInModel,augmentModelCatalog,supportsXHighThinkingiisModernModelRef, ponieważ odpowiada za zgodność forward-compat GPT-5.4, bezpośrednią normalizację OpenAIopenai-completions->openai-responses, wskazówki auth świadome Codex, tłumienie Spark, syntetyczne wiersze listy OpenAI oraz politykę rozumowania / modeli live GPT-5; rodzina streamówopenai-responses-defaultsodpowiada za współdzielone natywne wrappery OpenAI Responses dla nagłówków atrybucji,/fast/serviceTier, szczegółowości tekstu, natywnego wyszukiwania w sieci Codex, kształtowania ładunku reasoning-compat oraz zarządzania kontekstem Responses. - OpenRouter używa
catalog, a takżeresolveDynamicModeliprepareDynamicModel, ponieważ dostawca działa jako pass-through i może udostępniać nowe identyfikatory modeli przed aktualizacją statycznego katalogu OpenClaw; używa takżecapabilities,wrapStreamFniisCacheTtlEligible, aby utrzymać nagłówki żądań specyficzne dla dostawcy, metadane routingu, poprawki rozumowania i politykę prompt-cache poza core. Jego polityka replay pochodzi z rodzinypassthrough-gemini, podczas gdy rodzina streamówopenrouter-thinkingodpowiada za wstrzykiwanie rozumowania proxy oraz pomijanie nieobsługiwanych modeli /auto. - GitHub Copilot używa
catalog,auth,resolveDynamicModelicapabilities, a takżeprepareRuntimeAuthifetchUsageSnapshot, ponieważ potrzebuje logowania urządzenia należącego do dostawcy, zachowania fallback modeli, niuansów transkryptu Claude, wymiany tokenu GitHub -> token Copilot oraz endpointu użycia należącego do dostawcy. - OpenAI Codex używa
catalog,resolveDynamicModel,normalizeResolvedModel,refreshOAuthiaugmentModelCatalog, a takżeprepareExtraParams,resolveUsageAuthifetchUsageSnapshot, ponieważ nadal działa na transportach core OpenAI, ale odpowiada za własną normalizację transportu/base URL, politykę fallback odświeżania OAuth, domyślny wybór transportu, syntetyczne wiersze katalogu Codex oraz integrację endpointu użycia ChatGPT; współdzieli tę samą rodzinę streamówopenai-responses-defaultsco bezpośrednie OpenAI. - Google AI Studio i Gemini CLI OAuth używają
resolveDynamicModel,buildReplayPolicy,sanitizeReplayHistory,resolveReasoningOutputMode,wrapStreamFniisModernModelRef, ponieważ rodzina replaygoogle-geminiodpowiada za fallback zgodności forward-compat Gemini 3.1, natywną walidację replay Gemini, sanityzację bootstrap replay, tryb wyjścia rozumowania z tagami oraz dopasowywanie nowoczesnych modeli, podczas gdy rodzina streamówgoogle-thinkingodpowiada za normalizację ładunku rozumowania Gemini; Gemini CLI OAuth używa równieżformatApiKey,resolveUsageAuthifetchUsageSnapshotdo formatowania tokenu, parsowania tokenu i połączenia endpointu limitów. - Anthropic Vertex używa
buildReplayPolicyprzez rodzinę replayanthropic-by-model, dzięki czemu czyszczenie replay specyficzne dla Claude pozostaje ograniczone do identyfikatorów Claude, a nie do każdego transportuanthropic-messages. - Amazon Bedrock używa
buildReplayPolicy,matchesContextOverflowError,classifyFailoverReasoniresolveDefaultThinkingLevel, ponieważ odpowiada za klasyfikację błędów throttle/not-ready/context-overflow specyficznych dla Bedrock dla ruchu Anthropic-on-Bedrock; jego polityka replay nadal współdzieli tę samą ochronę tylko dla Claudeanthropic-by-model. - OpenRouter, Kilocode, Opencode i Opencode Go używają
buildReplayPolicyprzez rodzinę replaypassthrough-gemini, ponieważ przekazują modele Gemini przez transporty zgodne z OpenAI i potrzebują sanityzacji sygnatur myśli Gemini bez natywnej walidacji replay Gemini ani przekształceń bootstrap. - MiniMax używa
buildReplayPolicyprzez rodzinę replayhybrid-anthropic-openai, ponieważ jeden dostawca odpowiada zarówno za semantykę wiadomości Anthropic, jak i zgodność z OpenAI; zachowuje usuwanie bloków rozumowania tylko dla Claude po stronie Anthropic, jednocześnie nadpisując tryb wyjścia rozumowania z powrotem na natywny, a rodzina streamówminimax-fast-modeodpowiada za przepisania modeli trybu fast na współdzielonej ścieżce streamu. - Moonshot używa
catalogorazwrapStreamFn, ponieważ nadal korzysta ze współdzielonego transportu OpenAI, ale potrzebuje normalizacji ładunku rozumowania należącej do dostawcy; rodzina streamówmoonshot-thinkingmapuje konfigurację oraz stan/thinkna swój natywny binarny ładunek rozumowania. - Kilocode używa
catalog,capabilities,wrapStreamFniisCacheTtlEligible, ponieważ potrzebuje nagłówków żądań należących do dostawcy, normalizacji ładunku rozumowania, wskazówek transkryptu Gemini oraz bramkowania cache-TTL Anthropic; rodzina streamówkilocode-thinkingutrzymuje wstrzykiwanie rozumowania Kilo na współdzielonej ścieżce streamu proxy, jednocześnie pomijająckilo/autoi inne identyfikatory modeli proxy, które nie obsługują jawnych ładunków rozumowania. - Z.AI używa
resolveDynamicModel,prepareExtraParams,wrapStreamFn,isCacheTtlEligible,isBinaryThinking,isModernModelRef,resolveUsageAuthifetchUsageSnapshot, ponieważ odpowiada za fallback GLM-5, domyślne wartościtool_stream, UX binary thinking, dopasowywanie nowoczesnych modeli oraz zarówno auth użycia, jak i pobieranie limitów; rodzina streamówtool-stream-default-onutrzymuje wrappertool_streamdomyślnie włączony poza ręcznie pisanym kodem specyficznym dla dostawcy. - xAI używa
normalizeResolvedModel,normalizeTransport,contributeResolvedModelCompat,prepareExtraParams,wrapStreamFn,resolveSyntheticAuth,resolveDynamicModeliisModernModelRef, ponieważ odpowiada za normalizację natywnego transportu xAI Responses, przepisania aliasów trybu fast Grok, domyślnetool_stream, czyszczenie strict-tool / ładunku rozumowania, ponowne użycie auth fallback dla narzędzi należących do pluginu, rozstrzyganie modeli Grok zgodne z forward-compat oraz poprawki zgodności należące do dostawcy, takie jak profil schematu narzędzi xAI, nieobsługiwane słowa kluczowe schematu, natywneweb_searchi dekodowanie argumentów wywołań narzędzi z encji HTML. - Mistral, OpenCode Zen i OpenCode Go używają tylko
capabilities, aby utrzymać niuanse transkryptu/narzędzi poza core. - Bundled dostawcy tylko katalogowi, tacy jak
byteplus,cloudflare-ai-gateway,huggingface,kimi-coding,nvidia,qianfan,synthetic,together,venice,vercel-ai-gatewayivolcengine, używają tylkocatalog. - Qwen używa
catalogdla swojego dostawcy tekstowego oraz współdzielonych rejestracji rozumienia mediów i generowania wideo dla swoich powierzchni multimodalnych. - MiniMax i Xiaomi używają
catalogoraz hooków użycia, ponieważ ich zachowanie/usagenależy do pluginu, mimo że wnioskowanie nadal działa przez współdzielone transporty.
Narzędzia pomocnicze środowiska uruchomieniowego
Pluginy mogą uzyskiwać dostęp do wybranych helperów core przezapi.runtime. Dla TTS:
textToSpeechzwraca zwykły ładunek wyjściowy TTS z core dla powierzchni plików/notatek głosowych.- Używa konfiguracji core
messages.ttsi wyboru dostawcy. - Zwraca bufor dźwięku PCM + częstotliwość próbkowania. Pluginy muszą przeprowadzić resampling/kodowanie dla dostawców.
listVoicesjest opcjonalne dla każdego dostawcy. Używaj go dla selektorów głosów lub przepływów konfiguracji należących do dostawcy.- Listy głosów mogą zawierać bogatsze metadane, takie jak locale, płeć i tagi osobowości dla selektorów świadomych dostawcy.
- OpenAI i ElevenLabs obsługują dziś telefonię. Microsoft nie.
api.registerSpeechProvider(...).
- Zachowaj politykę TTS, fallback i dostarczanie odpowiedzi w core.
- Używaj dostawców mowy dla zachowania syntezy należącego do dostawcy.
- Starsze wejście Microsoft
edgejest normalizowane do identyfikatora dostawcymicrosoft. - Preferowany model własności jest zorientowany na firmę: jeden plugin dostawcy może obsługiwać tekst, mowę, obrazy i przyszłych dostawców mediów, gdy OpenClaw dodaje te kontrakty możliwości.
- Zachowaj orkiestrację, fallback, konfigurację i podłączenie kanałów w core.
- Zachowaj zachowanie dostawcy w pluginie dostawcy.
- Rozszerzanie addytywne powinno pozostać typowane: nowe opcjonalne metody, nowe opcjonalne pola wyników, nowe opcjonalne możliwości.
- Generowanie wideo już stosuje ten sam wzorzec:
- core jest właścicielem kontraktu możliwości i helpera runtime
- pluginy dostawców rejestrują
api.registerVideoGenerationProvider(...) - pluginy funkcjonalne/kanałowe wykorzystują
api.runtime.videoGeneration.*
api.runtime.mediaUnderstanding.*to preferowana współdzielona powierzchnia dla rozumienia obrazów/audio/wideo.- Używa konfiguracji audio rozumienia mediów z core (
tools.media.audio) oraz kolejności fallback dostawców. - Zwraca
{ text: undefined }, gdy nie powstanie wynik transkrypcji (na przykład w przypadku pominiętego/nieobsługiwanego wejścia). api.runtime.stt.transcribeAudioFile(...)pozostaje aliasem zgodności.
api.runtime.subagent:
providerimodelto opcjonalne nadpisania dla pojedynczego przebiegu, a nie trwałe zmiany sesji.- OpenClaw honoruje te pola nadpisania tylko dla zaufanych wywołujących.
- W przypadku przebiegów fallback należących do pluginu operatorzy muszą wyrazić zgodę przez
plugins.entries.<id>.subagent.allowModelOverride: true. - Użyj
plugins.entries.<id>.subagent.allowedModels, aby ograniczyć zaufane pluginy do określonych kanonicznych celówprovider/model, lub"*"aby jawnie dopuścić dowolny cel. - Niezaufane przebiegi subagenta pluginów nadal działają, ale żądania nadpisania są odrzucane zamiast po cichu przechodzić do fallback.
api.registerWebSearchProvider(...).
Uwagi:
- Zachowaj wybór dostawcy, rozstrzyganie poświadczeń i współdzieloną semantykę żądań w core.
- Używaj dostawców wyszukiwania w sieci dla transportów wyszukiwania specyficznych dla dostawcy.
api.runtime.webSearch.*to preferowana współdzielona powierzchnia dla pluginów funkcjonalnych/kanałowych, które potrzebują zachowania wyszukiwania bez zależności od wrappera narzędzia agenta.
api.runtime.imageGeneration
generate(...): generuje obraz przy użyciu skonfigurowanego łańcucha dostawców generowania obrazów.listProviders(...): wyświetla dostępnych dostawców generowania obrazów i ich możliwości.
Trasy HTTP Gateway
Pluginy mogą udostępniać endpointy HTTP za pomocąapi.registerHttpRoute(...).
path: ścieżka trasy pod serwerem HTTP gateway.auth: wymagane. Użyj"gateway", aby wymagać zwykłego auth gateway, lub"plugin"dla auth zarządzanego przez plugin / weryfikacji Webhook.match: opcjonalne."exact"(domyślnie) lub"prefix".replaceExisting: opcjonalne. Pozwala temu samemu pluginowi zastąpić własną istniejącą rejestrację trasy.handler: zwróćtrue, gdy trasa obsłużyła żądanie.
api.registerHttpHandler(...)zostało usunięte i spowoduje błąd ładowania pluginu. Zamiast tego użyjapi.registerHttpRoute(...).- Trasy pluginów muszą jawnie deklarować
auth. - Konflikty dokładnych
path + matchsą odrzucane, chyba że ustawionoreplaceExisting: true, a jeden plugin nie może zastąpić trasy innego pluginu. - Nakładające się trasy z różnymi poziomami
authsą odrzucane. Łańcuchy przejściaexact/prefixutrzymuj tylko na tym samym poziomieauth. - Trasy
auth: "plugin"nie otrzymują automatycznie zakresów runtime operatora. Służą do webhooków / weryfikacji podpisów zarządzanych przez plugin, a nie do uprzywilejowanych wywołań helperów Gateway. - Trasy
auth: "gateway"działają wewnątrz zakresu runtime żądania Gateway, ale ten zakres jest celowo konserwatywny:- auth bearer oparty na współdzielonym sekrecie (
gateway.auth.mode = "token"/"password") utrzymuje zakresy runtime tras pluginów przypięte dooperator.write, nawet jeśli wywołujący wysyłax-openclaw-scopes - zaufane tryby HTTP przekazujące tożsamość (na przykład
trusted-proxylubgateway.auth.mode = "none"na prywatnym ingressie) honorująx-openclaw-scopestylko wtedy, gdy nagłówek jest jawnie obecny - jeśli
x-openclaw-scopesjest nieobecny w takich żądaniach tras pluginów z przekazywaną tożsamością, zakres runtime wraca dooperator.write
- auth bearer oparty na współdzielonym sekrecie (
- Praktyczna zasada: nie zakładaj, że trasa pluginu z auth gateway jest niejawnie powierzchnią administracyjną. Jeśli twoja trasa potrzebuje zachowania tylko dla administratora, wymagaj trybu auth przekazującego tożsamość i udokumentuj jawny kontrakt nagłówka
x-openclaw-scopes.
Ścieżki importu Plugin SDK
Podczas tworzenia pluginów używaj podścieżek SDK zamiast monolitycznego importuopenclaw/plugin-sdk:
openclaw/plugin-sdk/plugin-entrydla prymitywów rejestracji pluginów.openclaw/plugin-sdk/coredla ogólnego współdzielonego kontraktu skierowanego do pluginów.openclaw/plugin-sdk/config-schemadla eksportu głównego schematu Zodopenclaw.json(OpenClawSchema).- Stabilne prymitywy kanałów, takie jak
openclaw/plugin-sdk/channel-setup,openclaw/plugin-sdk/setup-runtime,openclaw/plugin-sdk/setup-adapter-runtime,openclaw/plugin-sdk/setup-tools,openclaw/plugin-sdk/channel-pairing,openclaw/plugin-sdk/channel-contract,openclaw/plugin-sdk/channel-feedback,openclaw/plugin-sdk/channel-inbound,openclaw/plugin-sdk/channel-lifecycle,openclaw/plugin-sdk/channel-reply-pipeline,openclaw/plugin-sdk/command-auth,openclaw/plugin-sdk/secret-inputiopenclaw/plugin-sdk/webhook-ingressdla współdzielonego podłączenia konfiguracji/auth/odpowiedzi/Webhook.channel-inboundjest wspólnym miejscem dla debounce, dopasowywania wzmianek, helperów polityki wzmianek przychodzących, formatowania kopert przychodzących oraz helperów kontekstu kopert przychodzących.channel-setupto wąska ścieżka konfiguracji opcjonalnej instalacji.setup-runtimeto bezpieczna dla runtime powierzchnia konfiguracji używana przezsetupEntry/ odroczone uruchamianie, w tym bezpieczne importowo adaptery łatek konfiguracji.setup-adapter-runtimeto świadoma env ścieżka adaptera konfiguracji konta.setup-toolsto mała ścieżka helperów CLI/archiwów/dokumentacji (formatCliCommand,detectBinary,extractArchive,resolveBrewExecutable,formatDocsLink,CONFIG_DIR). - Podścieżki domenowe, takie jak
openclaw/plugin-sdk/channel-config-helpers,openclaw/plugin-sdk/allow-from,openclaw/plugin-sdk/channel-config-schema,openclaw/plugin-sdk/telegram-command-config,openclaw/plugin-sdk/channel-policy,openclaw/plugin-sdk/approval-gateway-runtime,openclaw/plugin-sdk/approval-handler-adapter-runtime,openclaw/plugin-sdk/approval-handler-runtime,openclaw/plugin-sdk/approval-runtime,openclaw/plugin-sdk/config-runtime,openclaw/plugin-sdk/infra-runtime,openclaw/plugin-sdk/agent-runtime,openclaw/plugin-sdk/lazy-runtime,openclaw/plugin-sdk/reply-history,openclaw/plugin-sdk/routing,openclaw/plugin-sdk/status-helpers,openclaw/plugin-sdk/text-runtime,openclaw/plugin-sdk/runtime-storeiopenclaw/plugin-sdk/directory-runtimedla współdzielonych helperów runtime/konfiguracji.telegram-command-configto wąska publiczna ścieżka dla normalizacji/walidacji niestandardowych poleceń Telegram i pozostaje dostępna nawet wtedy, gdy bundled powierzchnia kontraktu Telegram jest tymczasowo niedostępna.text-runtimeto współdzielona ścieżka tekstu/Markdown/logowania, obejmująca usuwanie tekstu widocznego dla asystenta, helpery renderowania/dzielenia Markdown, helpery redakcji, helpery tagów dyrektyw oraz bezpieczne narzędzia tekstowe. - Powierzchnie kanałów specyficzne dla zatwierdzeń powinny preferować jeden kontrakt
approvalCapabilityw pluginie. Core odczytuje wtedy auth zatwierdzeń, dostarczanie, renderowanie, natywne routowanie i leniwe zachowanie natywnego handlera przez tę jedną możliwość zamiast mieszać zachowanie zatwierdzeń z niezwiązanymi polami pluginu. openclaw/plugin-sdk/channel-runtimejest przestarzałe i pozostaje jedynie jako shima zgodności dla starszych pluginów. Nowy kod powinien importować węższe prymitywy ogólne, a kod repo nie powinien dodawać nowych importów tej shimy.- Wewnętrzne elementy bundled extensions pozostają prywatne. Zewnętrzne pluginy powinny używać tylko podścieżek
openclaw/plugin-sdk/*. Kod core/testów OpenClaw może używać publicznych punktów wejścia repo pod katalogiem głównym pakietu pluginu, takich jakindex.js,api.js,runtime-api.js,setup-entry.jsoraz wąsko ukierunkowane pliki, takie jaklogin-qr-api.js. Nigdy nie importujsrc/*pakietu pluginu z core ani z innego rozszerzenia. - Podział punktów wejścia repo:
<plugin-package-root>/api.jsto barrel helperów/typów,<plugin-package-root>/runtime-api.jsto barrel tylko runtime,<plugin-package-root>/index.jsto punkt wejścia bundled pluginu, a<plugin-package-root>/setup-entry.jsto punkt wejścia pluginu konfiguracji. - Aktualne przykłady bundled dostawców:
- Anthropic używa
api.js/contract-api.jsdla helperów streamu Claude, takich jakwrapAnthropicProviderStream, helpery nagłówków beta i parsowanieservice_tier. - OpenAI używa
api.jsdla konstruktorów dostawców, helperów modeli domyślnych i konstruktorów dostawców realtime. - OpenRouter używa
api.jsdla swojego konstruktora dostawcy oraz helperów onboardingu/konfiguracji, podczas gdyregister.runtime.jsmoże nadal ponownie eksportować ogólne helperyplugin-sdk/provider-streamdo użytku lokalnego w repo.
- Anthropic używa
- Publiczne punkty wejścia ładowane przez fasadę preferują aktywny snapshot konfiguracji runtime, gdy taki istnieje, a następnie wracają do rozstrzygniętego pliku konfiguracji na dysku, gdy OpenClaw nie udostępnia jeszcze snapshotu runtime.
- Ogólne współdzielone prymitywy pozostają preferowanym publicznym kontraktem SDK. Nadal istnieje mały
zastrzeżony zestaw zgodności helperów oznaczonych marką bundled kanałów. Traktuj je jako
powierzchnie utrzymaniowe/zgodnościowe dla bundled, a nie nowe cele importu dla podmiotów trzecich; nowe kontrakty międzykanałowe powinny nadal trafiać do
ogólnych podścieżek
plugin-sdk/*albo lokalnych barrelów pluginuapi.js/runtime-api.js.
- Unikaj głównego barrelu
openclaw/plugin-sdkw nowym kodzie. - Najpierw preferuj wąskie, stabilne prymitywy. Nowsze podścieżki setup/pairing/reply/
feedback/contract/inbound/threading/command/secret-input/webhook/infra/
allowlist/status/message-tool są zamierzonym kontraktem dla nowych prac nad
bundled i zewnętrznymi pluginami.
Parsowanie/dopasowywanie celów należy do
openclaw/plugin-sdk/channel-targets. Bramki działań wiadomości i helpery identyfikatorów wiadomości reakcji należą doopenclaw/plugin-sdk/channel-actions. - Barrele helperów specyficznych dla bundled extensions nie są domyślnie stabilne. Jeśli
helper jest potrzebny tylko bundled extension, trzymaj go za lokalną
warstwą
api.jslubruntime-api.jstego rozszerzenia zamiast promować go doopenclaw/plugin-sdk/<extension>. - Nowe współdzielone ścieżki helperów powinny być ogólne, a nie oznaczone marką kanału. Wspólne parsowanie
celów należy do
openclaw/plugin-sdk/channel-targets; elementy wewnętrzne specyficzne dla kanału pozostają za lokalną warstwąapi.jslubruntime-api.jsnależącego pluginu. - Podścieżki specyficzne dla możliwości, takie jak
image-generation,media-understandingispeech, istnieją, ponieważ bundled/natywne pluginy używają ich już dziś. Ich obecność sama w sobie nie oznacza, że każdy eksportowany helper jest długoterminowym zamrożonym kontraktem zewnętrznym.
Schematy narzędzia wiadomości
Pluginy powinny być właścicielami wkładów do schematudescribeMessageTool(...) specyficznych dla kanału.
Pola specyficzne dla dostawcy trzymaj w pluginie, a nie we współdzielonym core.
Dla współdzielonych przenośnych fragmentów schematu używaj ponownie ogólnych helperów eksportowanych przez
openclaw/plugin-sdk/channel-actions:
createMessageToolButtonsSchema()dla ładunków w stylu siatki przyciskówcreateMessageToolCardSchema()dla strukturalnych ładunków kart
Rozstrzyganie celów kanału
Pluginy kanałów powinny być właścicielami semantyki celów specyficznych dla kanału. Zachowaj współdzielony host outbound jako ogólny i używaj powierzchni adaptera wiadomości dla reguł dostawcy:messaging.inferTargetChatType({ to })decyduje, czy znormalizowany cel powinien być traktowany jakodirect,groupczychannelprzed wyszukaniem w katalogu.messaging.targetResolver.looksLikeId(raw, normalized)mówi core, czy dane wejście powinno pominąć bezpośrednio do rozstrzygania podobnego do identyfikatora zamiast wyszukiwania w katalogu.messaging.targetResolver.resolveTarget(...)to fallback pluginu, gdy core potrzebuje końcowego rozstrzygnięcia należącego do dostawcy po normalizacji lub po braku trafienia w katalogu.messaging.resolveOutboundSessionRoute(...)odpowiada za konstruowanie trasy sesji specyficzne dla dostawcy po rozstrzygnięciu celu.
- Używaj
inferTargetChatTypedla decyzji kategorialnych, które powinny zapadać przed wyszukiwaniem peerów/grup. - Używaj
looksLikeIddo sprawdzeń typu „traktuj to jako jawny/natywny identyfikator celu”. - Używaj
resolveTargetdla fallbacku normalizacji specyficznego dla dostawcy, a nie dla szerokiego wyszukiwania w katalogu. - Natywne identyfikatory dostawcy, takie jak identyfikatory czatów, identyfikatory wątków, JID-y, handle i
identyfikatory pokoi, przechowuj wewnątrz wartości
targetlub parametrów specyficznych dla dostawcy, a nie w ogólnych polach SDK.
Katalogi oparte na konfiguracji
Pluginy, które wyprowadzają wpisy katalogu z konfiguracji, powinny trzymać tę logikę w pluginie i wykorzystywać współdzielone helpery zopenclaw/plugin-sdk/directory-runtime.
Używaj tego, gdy kanał potrzebuje peerów/grup opartych na konfiguracji, takich jak:
- peery DM sterowane allowlistą
- skonfigurowane mapy kanałów/grup
- statyczne fallbacki katalogów ograniczone do konta
directory-runtime obsługują tylko ogólne operacje:
- filtrowanie zapytań
- stosowanie limitów
- deduplikację/helpery normalizacji
- budowanie
ChannelDirectoryEntry[]
Katalogi dostawców
Pluginy dostawców mogą definiować katalogi modeli do wnioskowania za pomocąregisterProvider({ catalog: { run(...) { ... } } }).
catalog.run(...) zwraca ten sam kształt, który OpenClaw zapisuje do
models.providers:
{ provider }dla jednego wpisu dostawcy{ providers }dla wielu wpisów dostawców
catalog, gdy plugin jest właścicielem identyfikatorów modeli specyficznych dla dostawcy, domyślnych
wartości base URL lub metadanych modeli zależnych od auth.
catalog.order kontroluje, kiedy katalog pluginu jest scalany względem
wbudowanych niejawnych dostawców OpenClaw:
simple: dostawcy używający zwykłego klucza API lub envprofile: dostawcy pojawiający się, gdy istnieją profile authpaired: dostawcy syntetyzujący wiele powiązanych wpisów dostawcówlate: ostatni przebieg, po innych niejawnych dostawcach
discoverynadal działa jako starszy alias- jeśli zarejestrowano zarówno
catalog, jak idiscovery, OpenClaw używacatalog
Kanałowa inspekcja tylko do odczytu
Jeśli twój plugin rejestruje kanał, preferuj implementacjęplugin.config.inspectAccount(cfg, accountId) obok resolveAccount(...).
Dlaczego:
resolveAccount(...)to ścieżka runtime. Może zakładać, że poświadczenia są w pełni zmaterializowane i może szybko zakończyć się błędem, gdy brakuje wymaganych sekretów.- Ścieżki poleceń tylko do odczytu, takie jak
openclaw status,openclaw status --all,openclaw channels status,openclaw channels resolveoraz przepływy naprawy doctor/config, nie powinny wymagać materializacji poświadczeń runtime tylko po to, by opisać konfigurację.
inspectAccount(...):
- Zwracaj tylko opisowy stan konta.
- Zachowuj
enablediconfigured. - Dołączaj pola źródła/statusu poświadczeń, gdy ma to znaczenie, takie jak:
tokenSource,tokenStatusbotTokenSource,botTokenStatusappTokenSource,appTokenStatussigningSecretSource,signingSecretStatus
- Nie musisz zwracać surowych wartości tokenów tylko po to, by raportować dostępność
tylko do odczytu. Zwrócenie
tokenStatus: "available"(oraz odpowiadającego mu pola źródła) wystarcza dla poleceń typu status. - Używaj
configured_unavailable, gdy poświadczenie jest skonfigurowane przez SecretRef, ale niedostępne w bieżącej ścieżce polecenia.
Package packi
Katalog pluginu może zawieraćpackage.json z openclaw.extensions:
name/<fileBase>.
Jeśli twój plugin importuje zależności npm, zainstaluj je w tym katalogu, aby
node_modules było dostępne (npm install / pnpm install).
Barierka bezpieczeństwa: każdy wpis openclaw.extensions musi pozostać wewnątrz katalogu pluginu
po rozstrzygnięciu symlinków. Wpisy wychodzące poza katalog pakietu są
odrzucane.
Uwaga dotycząca bezpieczeństwa: openclaw plugins install instaluje zależności pluginów za pomocą
npm install --omit=dev --ignore-scripts (bez skryptów cyklu życia, bez zależności deweloperskich w runtime). Utrzymuj drzewa zależności pluginów jako „czyste JS/TS” i unikaj pakietów wymagających kompilacji przez postinstall.
Opcjonalnie: openclaw.setupEntry może wskazywać lekki moduł tylko do konfiguracji.
Gdy OpenClaw potrzebuje powierzchni konfiguracji dla wyłączonego pluginu kanału albo
gdy plugin kanału jest włączony, ale nadal nieskonfigurowany, ładuje setupEntry
zamiast pełnego punktu wejścia pluginu. Dzięki temu uruchamianie i konfiguracja są lżejsze,
gdy główny punkt wejścia pluginu podłącza również narzędzia, hooki lub inny kod tylko runtime.
Opcjonalnie: openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen
może włączyć plugin kanału do tej samej ścieżki setupEntry w fazie
uruchamiania gateway przed listen, nawet gdy kanał jest już skonfigurowany.
Używaj tego tylko wtedy, gdy setupEntry w pełni pokrywa powierzchnię uruchamiania, która musi istnieć
zanim gateway zacznie nasłuchiwać. W praktyce oznacza to, że punkt wejścia konfiguracji
musi rejestrować każdą możliwość należącą do kanału, od której zależy uruchamianie, taką jak:
- sama rejestracja kanału
- wszelkie trasy HTTP, które muszą być dostępne zanim gateway zacznie nasłuchiwać
- wszelkie metody Gateway, narzędzia lub usługi, które muszą istnieć w tym samym oknie czasowym
singleAccountKeysToMovenamedAccountPromotionKeysresolveSingleAccountPromotionTarget(...)
channels.<id>.accounts.* bez ładowania pełnego punktu wejścia pluginu.
Matrix jest obecnym bundled przykładem: przenosi tylko klucze auth/bootstrap do
nazwanego promowanego konta, gdy nazwane konta już istnieją, i może zachować
skonfigurowany niekanoniczny klucz konta domyślnego zamiast zawsze tworzyć
accounts.default.
Te adaptery łatek konfiguracji utrzymują leniwe wykrywanie powierzchni kontraktowej bundled. Czas
importu pozostaje lekki; powierzchnia promocji jest ładowana tylko przy pierwszym użyciu zamiast
ponownie wchodzić w uruchamianie bundled kanału podczas importu modułu.
Gdy te powierzchnie uruchamiania zawierają metody RPC Gateway, utrzymuj je pod
prefiksem specyficznym dla pluginu. Przestrzenie nazw administratora core (config.*,
exec.approvals.*, wizard.*, update.*) pozostają zastrzeżone i zawsze rozstrzygają się
do operator.admin, nawet jeśli plugin żąda węższego zakresu.
Przykład:
Metadane katalogu kanałów
Pluginy kanałów mogą reklamować metadane konfiguracji/wykrywania przezopenclaw.channel oraz
wskazówki instalacji przez openclaw.install. Dzięki temu dane katalogu core pozostają wolne od danych.
Przykład:
openclaw.channel poza minimalnym przykładem:
detailLabel: etykieta dodatkowa dla bogatszych powierzchni katalogu/statusudocsLabel: nadpisuje tekst linku do dokumentacjipreferOver: identyfikatory pluginów/kanałów o niższym priorytecie, które ten wpis katalogu powinien wyprzedzaćselectionDocsPrefix,selectionDocsOmitLabel,selectionExtras: kontrolki tekstu dla powierzchni wyborumarkdownCapable: oznacza kanał jako obsługujący Markdown dla decyzji o formatowaniu outboundexposure.configured: ukrywa kanał z powierzchni listowania skonfigurowanych kanałów, gdy ustawionofalseexposure.setup: ukrywa kanał z interaktywnych selektorów konfiguracji/ustawiania, gdy ustawionofalseexposure.docs: oznacza kanał jako wewnętrzny/prywatny dla powierzchni nawigacji dokumentacjishowConfigured/showInSetup: starsze aliasy nadal akceptowane dla kompatybilności; preferujexposurequickstartAllowFrom: włącza kanał do standardowego przepływuallowFromszybkiego startuforceAccountBinding: wymaga jawnego powiązania konta nawet wtedy, gdy istnieje tylko jedno kontopreferSessionLookupForAnnounceTarget: preferuje wyszukiwanie sesji przy rozstrzyganiu celów ogłoszeń
~/.openclaw/mpm/plugins.json~/.openclaw/mpm/catalog.json~/.openclaw/plugins/catalog.json
OPENCLAW_PLUGIN_CATALOG_PATHS (albo OPENCLAW_MPM_CATALOG_PATHS) na
jeden lub więcej plików JSON (rozdzielanych przecinkami/średnikami/PATH). Każdy plik powinien
zawierać { "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }. Parser akceptuje również "packages" lub "plugins" jako starsze aliasy klucza "entries".
Pluginy silnika kontekstu
Pluginy silnika kontekstu są właścicielami orkiestracji kontekstu sesji dla ingestu, składania i Compaction. Rejestruj je z pluginu przezapi.registerContextEngine(id, factory), a następnie wybierz aktywny silnik za pomocą
plugins.slots.contextEngine.
Użyj tego, gdy plugin musi zastąpić lub rozszerzyć domyślny
potok kontekstu, zamiast jedynie dodawać wyszukiwanie pamięci lub hooki.
compact()
zaimplementowane i jawnie deleguj je dalej:
Dodawanie nowej możliwości
Gdy plugin potrzebuje zachowania, które nie pasuje do obecnego API, nie omijaj systemu pluginów przez prywatne sięgnięcie do środka. Dodaj brakującą możliwość. Zalecana sekwencja:- zdefiniuj kontrakt core Zdecyduj, jakim współdzielonym zachowaniem powinien zarządzać core: polityką, fallbackiem, scalaniem konfiguracji, cyklem życia, semantyką skierowaną do kanałów i kształtem helpera runtime.
- dodaj typowane powierzchnie rejestracji/runtime pluginów
Rozszerz
OpenClawPluginApii/lubapi.runtimeo najmniejszą użyteczną typowaną powierzchnię możliwości. - podłącz konsumentów core + kanałów/funkcji Kanały i pluginy funkcjonalne powinny korzystać z nowej możliwości przez core, a nie przez bezpośredni import implementacji dostawcy.
- zarejestruj implementacje dostawców Pluginy dostawców następnie rejestrują swoje backendy względem tej możliwości.
- dodaj pokrycie kontraktowe Dodaj testy, aby własność i kształt rejestracji pozostawały jawne w czasie.
Lista kontrolna możliwości
Gdy dodajesz nową możliwość, implementacja powinna zwykle dotykać tych powierzchni jednocześnie:- typy kontraktów core w
src/<capability>/types.ts - helper runtime/runner core w
src/<capability>/runtime.ts - powierzchnia rejestracji API pluginów w
src/plugins/types.ts - podłączenie rejestru pluginów w
src/plugins/registry.ts - udostępnienie runtime pluginów w
src/plugins/runtime/*, gdy pluginy funkcjonalne/kanałowe muszą z niej korzystać - helpery przechwytywania/testów w
src/test-utils/plugin-registration.ts - asercje własności/kontraktów w
src/plugins/contracts/registry.ts - dokumentacja operatora/pluginów w
docs/
Szablon możliwości
Minimalny wzorzec:- core jest właścicielem kontraktu możliwości + orkiestracji
- pluginy dostawców są właścicielami implementacji dostawców
- pluginy funkcjonalne/kanałowe korzystają z helperów runtime
- testy kontraktowe utrzymują jawną własność