Most Cordis
Most Cordis osadza DeepSeek Harness (DSH) w backendzie Libre WebUI. DSH działa jako drzewo wtyczek w środowisku Cordis utrzymywanym przez Libre WebUI, więc możliwości są dostarczane jako usługi Cordis, a nie importowane moduły.
Most jest domyślnie wyłączony. Opisane tutaj działanie rozpoczyna się dopiero po włączeniu przez operatora; zobacz Konfigurację Cordis.
Dlaczego most zamiast bezpośredniej integracji
Bezpośredni import pakietów DSH do usług Libre WebUI byłby krótszy, ale gorszy: silnik stałby się zależnością czasu kompilacji. Zmiana adaptera modelu, pętli agenta lub usunięcie silnika wymagałoby modyfikacji i ponownego wdrożenia Libre WebUI.
Most odwraca tę zależność. Libre WebUI opiera się na jednym abstrakcyjnym kontrakcie, a dokument kompozycji Cordis określa jego implementację:
- Zmiana dostawcy bez przebudowy. Kompozycja jest plikiem YAML, więc wybór innego dostawcy to zmiana konfiguracji.
- Konfiguracja możliwości. Każda możliwość jest wierszem Loadera. Zmiany kompozycji operatora obowiązują przy następnym starcie hosta.
- Usunięcie bez pozostałości. Wszystkie usługi, odbiorniki i efekty silnika należą do głównego włókna. Jego zwolnienie wycofuje całość i pozwala zatrzymać silnik bez restartu Libre WebUI.
Warstwy
Konkretne zależności DSH pozostają w backend/src/cordis/dsh/. Trasy i usługi aplikacji korzystają z kontraktów mostu. Sterownik Work ma osobną kompozycję w pamięci i nigdy nie ładuje wtyczek systemu plików hosta.
Kontrakty
Kontrakt znajduje się w backend/src/cordis/contracts.ts. Celowo ogranicza się do danych potrzebnych API Libre WebUI, bez wewnętrznego słownictwa silnika.
| Kontrakt | Cel |
|---|---|
DshEngine.status() | Stan cyklu życia usług silnika (pending / ready / failed) |
DshEngine.modelConfiguration() | Domyślny model i dostawca działającej kompozycji |
DshEngine.listSessions() | Podsumowania sesji od najnowszej |
DshEngine.getSession(id) | Sesja z projekcją wiadomości |
DshEngine.createSession(opts) | Rezerwacja ID sesji i katalogu pracy |
DshEngine.updateSessionSettings(id, settings) | Zapis rzeczywistego modelu i natywnego trybu uprawnień plików podczas bezczynności |
DshEngine.decideApproval(id, approvalId, decision) | Rozstrzygnięcie oczekującego zatwierdzenia dla jego sesji |
DshEngine.deleteSession(id) | Zakończenie sesji i zwolnienie agenta |
DshEngine.listAgents() | Aktywni agenci, z oznaczeniem głównego i potomnych |
DshEngine.listTools() | Zarejestrowane narzędzia widoczne dla modelu |
DshEngine.sendMessage(id, txt) | Rozpoczęcie tury i zwrócenie uchwytu strumienia |
DshEngine.cancel(id) | Anulowanie aktywnej tury sesji |
Kontrakt jest publikowany jako usługa Cordis libreDshEngine. Odbiorca odczytuje ją przez ctx.get('libreDshEngine'), nie importując modułu mostu.
EngineStreamChunk przenosi text, reasoning, tool-call, tool-result, approval-request, approval-decision, error i done. Ramki na żywo trafiają do właściwego agenta i sesji; odpowiadająca im trwała wiadomość asystenta nie jest emitowana ponownie. sendMessage zwraca uchwyt, którego subscribe odtwarza już wysłaną treść. Dzięki temu szybki pierwszy token nie ginie między startem tury a podłączeniem odbiornika HTTP.
Przebieg jednej tury czatu
NDJSON zastępuje WebSocket, ponieważ tura jest pojedynczą sekwencją od serwera do klienta po żądaniu. Pozostawienie jej na POST eliminuje dodatkowy handshake, bilet i protokół ponownego łączenia oraz utrzymuje całą turę w jednym uwierzytelnionym żądaniu.
DONE i PENDING
Cordis aktywuje wtyczkę, gdy dostępne są zadeklarowane usługi; wiersz przechodzi więc także przez stany poprzedzające działanie. Pomylenie dwóch poniższych pojęć jest najczęstszą przyczyną milczącego silnika.
Stan wpisu Loadera. Wiersz przechodzi przez PENDING → LOADING → ACTIVE albo FAILED. Brak zadeklarowanych usług pozostawia go bezterminowo w oczekiwaniu zamiast kończyć błędem. Niepełna kompozycja może zatem wystartować i niczego nie obsługiwać.
Dostępność usługi. Host zgłasza każdą oczekiwaną usługę następująco:
| Stan | Znaczenie | Przyczyna |
|---|---|---|
pending | Niezarejestrowana w kontekście | Dostarczający wiersz nie został aktywowany albo jest wyłączony |
ready | Zarejestrowana i używalna | Dostarczający wiersz został aktywowany |
failed | Zadeklarowana, ale niedostępna | Zgłaszana z tekstem detail |
host.status() pokazuje dostępność i brakujące usługi wymagane; GET /api/cordis/health udostępnia te same dane. Pominięcie wymaganej usługi wywołuje błąd startu zamiast publikować silnik zwracający puste listy.
Łatwo pomylić dwa łańcuchy zależności:
dsh-toolsnie ruszy bezsystemPrompt.dsh-agent-loopczeka naagents,sessions,llm,tools,systemPromptisessionProjections.
Brak dowolnej z tych usług daje działający magazyn sesji, ale silnik nigdy nie odpowiada na wiadomość.
Konfiguracja dostawcy
Dostarczony wiersz libre-webui-llm-adapter obsługuje dostawców skonfigurowanych w Libre WebUI. Selektor na stronie Silnika wybiera model dla sesji bez zastępowania tego wiersza.
Zmiany wierszy kompozycji stosuje się przy kolejnym uruchomieniu hosta. Zrestartuj backend albo wyłącz i włącz Cordis, gdy przełącznik administratora nie jest zablokowany. Trwałe sesje pozostają w skonfigurowanym magazynie i wznawiają się przez bieżącą kompozycję.
Zaufany kod integracji może bezpośrednio używać API cyklu życia Loadera. Most nie udostępnia punktu końcowego wymiany adaptera ani automatycznie nie przywraca poprzedniego, jeśli zamiennik zawiedzie.
Wycofanie
Zwolnienie głównego włókna hosta usuwa wszystko, co zainstalował silnik. Ta relacja własności stanowi całą gwarancję:
- Usługi są rejestrowane przez wtyczki i wycofywane z ich włóknami.
- Subskrypcje
session/eventpowstają w konstruktorze mostu i należą do włókna jego wiersza. - Most śledzi uchwyty agentów i zwalnia je w swoim efekcie końcowym.
- Host zwalnia główny kontekst będący właścicielem wszystkich wierszy.
stopCordisHost() jest idempotentne i włączone w zamykanie backendu, dzięki czemu zegary i uchwyty plików są zwalniane, a nie pozostawiane do końca procesu.
Tożsamość i trwałość sesji
Strona Silnika rezerwuje nieprzezroczyste ID przy tworzeniu. Z włączoną trwałością nagłówek jest zapisywany natychmiast, więc restart przetrwa także pusta sesja. Most listuje zapisane i aktywne sesje, odczytuje logi przez walidowane API trwałego zapisu DSH i wznawia agenta pod tym samym ID dla kolejnej wiadomości. Nowe wiadomości używają konstruktora DSH z identyfikatorem.
Usunięcie sesji anuluje i zwalnia agenta przed usunięciem jej pliku. Lokalny adapter JSONL sprawdza ścieżki magazynu i sesji oraz odrzuca dowiązania symboliczne. Niestandardowe backendy bez obsługi usuwania zwracają błąd zamiast twierdzić, że dane zniknęły.
Anulowanie dociera do natywnego agenta, żądania modelu i narzędzi. Rozłączenie klienta anuluje turę; gotowe wiadomości pozostają czytelne. Odtwarzanie bufora strumienia jest ograniczone i zachowuje szybki wynik sprzed podłączenia odbiorcy.
Silnik hosta jest funkcją solo dla jednej repliki. Wdrożenia team nie mogą ładować lokalnego środowiska JSONL. Work w piaskownicy korzysta zamiast tego z istniejących repozytoriów SQL zadań, uruchomień, wiadomości, zatwierdzeń i zdarzeń.
Interfejs HTTP
| Metoda | Ścieżka | Cel |
|---|---|---|
GET | /api/cordis/health | Stan mostu; bez uwierzytelnienia |
GET | /api/cordis/sessions | Lista sesji |
POST | /api/cordis/sessions | Utworzenie sesji |
GET | /api/cordis/sessions/:id | Odczyt sesji z wiadomościami |
DELETE | /api/cordis/sessions/:id | Zakończenie sesji |
POST | /api/cordis/sessions/:id/messages | Wysłanie wiadomości i strumień NDJSON |
POST | /api/cordis/sessions/:id/cancel | Anulowanie aktywnej tury |
GET | /api/cordis/agents | Lista aktywnych agentów |
GET | /api/cordis/tools | Lista zarejestrowanych narzędzi |
Wszystkie trasy poza /health wymagają uwierzytelnionej sesji administratora. Gdy most nie może obsłużyć żądań, zwracają 503 z code równym CORDIS_DISABLED, CORDIS_STARTING lub CORDIS_UNAVAILABLE.

Strona to frontend/src/pages/CordisPage.tsx, dostępna pod /cordis z paska bocznego. Wyświetla sesje i narzędzia, tworzy sesje i dodaje strumieniowaną turę do rozmowy. Gdy most jest wyłączony lub nie startuje, pokazuje przyczynę zamiast pustej listy; inaczej „brak sesji” wyglądałby jak „brak silnika”.
Klient przeglądarkowy to frontend/src/utils/api/cordisApi.ts. Używa wyłącznie tego interfejsu, nie importuje typów backendu ani pakietów @deepseek-ai/*, więc silnik można zastąpić bez zmiany frontendu. Turę odbiera się przez sendMessage(sessionId, text, { onChunk }); klient sam analizuje JSON rozdzielany nowymi liniami i obsługuje fragmenty podzielone między odczyty sieci.
Sterowanie czatem Silnika
Strona wyświetla Markdown, tabele i kod z kolorowaniem składni, z kopiowaniem odpowiedzi i kodu. Prompty systemowe oraz wstrzyknięty kontekst środowiska są w zwiniętej sekcji Kontekst sesji, a nie jako wiadomości użytkownika. Ujawnione rozumowanie i aktywność narzędzi mają oddzielne sekcje; wyniki po odświeżeniu nadal pasują do właściwej operacji.
Wybierz rzeczywisty model dostawcy. Selektor używa lokalnych modeli i wtyczek dostępnych zalogowanemu administratorowi, z tożsamością dostawcy. Persony i agenci Czatu nie są ID modeli i nie wstrzykują swoich instrukcji do rozmowy Silnika. Starsze błędne nagłówki modeli person są pomijane jako wskazówki domyślne bez zmiany zapisanego logu.
Każda sesja ma Tylko odczyt lub Zapis w obszarze roboczym, wymuszane przez politykę plików DSH i kanoniczną granicę obszaru mostu. Kompozytor pokazuje zakres. Ustawienia są zapisywane jako natywne zdarzenia i przeżywają restart; zmiany podczas tury są odrzucane.
Natywne żądanie rozszerzenia uprawnień pojawia się jako karta Pozwól raz / Odmów przy operacji. Zgoda dotyczy tylko tego żądania i nie zmienia stałego trybu. Nieaktualne lub anulowane żądania nie mogą zostać zatwierdzone, a Czat bez interfejsu odrzuca pytania, których nie może wyświetlić. Most nie oferuje nieograniczonego dostępu do hosta.
Dodatkowe punkty końcowe administratora:
| Metoda | Ścieżka | Cel |
|---|---|---|
GET | /api/cordis/models | Dostępne modele dostawców i bieżący domyślny rzeczywisty model |
PATCH | /api/cordis/sessions/:id/settings | Ustawienie modelu lub trybu uprawnień sesji |
POST | /api/cordis/sessions/:id/approvals/:approvalId | Rozstrzygnięcie żądania przez allowed-once lub rejected |
Używanie silnika w Czacie
Włącz Dostęp i zasady → Modele agentów CLI i Silnik Cordis. Administratorzy mogą wtedy wybrać DeepSeek Harness w Czacie. Każde żądanie otrzymuje nową sesję tymczasową z dostarczonym transkryptem. Zwykła baza Czatu pozostaje źródłem prawdy: niezależne rozmowy, odgałęzienia i ponowienia nie współdzielą ukrytej historii silnika. Log tymczasowy jest usuwany po zakończeniu lub anulowaniu i nie pojawia się na stronie Silnika.
Standardowa kompozycja dostawców dodaje też wpisy DeepSeek Harness · model (dostawca) w grupie Agenci. Zapisane ID opakowują tę samą kwalifikowaną trasę co strona Silnika: dsh:lwui:ollama:<model> lub dsh:lwui:plugin:<plugin>:<model>, z kodowaniem procentowym składników. Opcjonalne lokalne połączenie natywnego DSH dodaje dsh:native:<provider>:<model> z aktualnego katalogu instancji, używając jej konfiguracji i danych uwierzytelniających.
Zainstaluj osobny pakiet Apache-2.0 z libre-webui/dsh-native-provider albo przygotuj pakiet z dystrybucji Libre WebUI. Oba używają nazwy @libre-webui/dsh-native-provider i zachowują klucze u natywnego DSH. Wymagane są ten sam host Unix i konto systemowe oraz prywatne gniazdo Unix; połączenie nie izoluje aplikacji dzielących to konto. Udostępnia tylko inferencję, bez natywnych sesji agentów i wykonania narzędzi. Instalację, restarty profili, aktualizacje i usuwanie opisuje przewodnik konfiguracji. Brak połączenia lub modelu kończy się błędem bez zmiany dostawcy. Natywne wywołania pojawiają się też w Użycie dostawców z modelem, zgłoszonymi tokenami, opóźnieniem i wynikiem.
Profil bazowy dsh zachowuje domyślny model działającej kompozycji. Kompozycje z własnym adapterem udostępniają ten profil bez reklamowania nieobsługiwanych zastąpień dostawców Libre WebUI.
Tytuły i podsumowania rozumowania rozwiązują wybór DSH do dostawcy i wysyłają bezpośrednie żądanie tekstowe bez narzędzi lub sesji agenta. Profil bazowy odczytuje domyślne wartości działającego silnika, także nadpisania w wierszu mostu, zamiast zgadywać z katalogu. Własne adaptery wymagają jawnego modelu zadań Ollama lub wtyczki. Niedostępny dostawca daje zwykły błąd albo lokalny podgląd tytułu, a nie żądanie do innego dostawcy.
Żądanie korzysta z ustawień i danych uwierzytelniających zalogowanego administratora. Dane innych administratorów nie są wybierane domyślnie. Skonfigurowany obszar Cordis pozostaje domyślny; Czat nie zastępuje go katalogiem domowym użytkownika serwera.
Work w piaskownicy
Po włączeniu Cordis Work udostępnia osobny wybór Silnik z Libre WebUI i DeepSeek Harness. Selektor zachowuje nazwy modeli i dostawców. Dla dostawców LWUI wybór DSH zapisuje się jako dsh:<model>; natywne wybory zapisują providerType: dsh, dokładne ID dostawcy i surowe ID modelu. Zwykłe kontrole dostępu i obsługi narzędzi nadal obowiązują; natywne dane wymagają dodatkowo aktywnego administratora.
Każde uruchomienie tworzy izolowaną pętlę agenta DSH w pamięci. Adapter otrzymuje bieżący transkrypt Work, metadane dostawcy, obrazy i schematy narzędzi. Ciała narzędzi tylko czekają na wyniki Work; nie mogą czytać plików hosta ani uruchamiać jego procesów.
Work sprawdza argumenty, żąda zatwierdzeń, wykonuje narzędzia w środowisku obszaru, zapisuje wyniki i stan odtwarzania dostawcy w SQL, wymusza budżety i publikuje zdarzenia. Odmowa daje zwykły wynik odmowy. Anulowanie zwalnia DSH i korzysta z istniejącego sprzątania kontenera Work. Po odzyskaniu workera nowy sterownik dostaje zapisany kontekst bez powtarzania zakończonych skutków narzędzi.
Integracja nie wymaga kompozycji hosta ani magazynu JSONL. Podlega zasadom Work dla Docker/Kubernetes i wdrożeń, w tym współdzielonej trwałości trybu team.
Granica bezpieczeństwa
Strona Silnika i agent Czatu na hoście są tylko dla administratorów. Sesje stanowią wspólną konsolę administracyjną, łącznie z promptami systemowymi, a nie obszary poszczególnych użytkowników. Zwykłe konta nie mogą ich odczytywać, tworzyć, modyfikować ani anulować przez API.
Dostarczone narzędzia plikowe ograniczają odczyt i zapis do skonfigurowanego obszaru przez ścieżki kanoniczne, w tym rozwiązywanie dowiązań. Nadpisane katalogi sesji muszą pozostać wewnątrz obszaru. Nadal obowiązują natywna polityka modyfikacji DSH i jednorazowe zgody Silnika. Wtyczki kompozycji instalowane przez operatora są zaufanym kodem serwera i mogą rozszerzać możliwości. Zatwierdzenia Silnika są niezależne od zatwierdzeń Work i wykonania w kontenerach.
Sterownik DSH Work jest osobny: nie ładuje wtyczek plików, powłoki ani trwałego zapisu hosta i działa wyłącznie przez autoryzację i piaskownicę Work. Zdalni dostawcy pozostają opcjonalni i korzystają z trasy skonfigurowanej dla wybranego konta.