メインコンテンツまでスキップ

Cordis ブリッジ

Cordis ブリッジは DeepSeek Harness(DSH)エンジンを Libre WebUI のバックエンドに組み込みます。DSH は Libre WebUI がホストする Cordis ランタイム内のプラグインツリーとして動作し、その機能は直接インポートするモジュールではなく Cordis サービスとして提供されます。

ブリッジは既定で無効です。運用者が有効にするまでは、このページに記載した処理は実行されません。Cordis の設定を参照してください。

直接統合せずブリッジを使う理由

Libre WebUI のサービスから DSH パッケージを直接インポートすればコードは短くなりますが、エンジンがコンパイル時の依存関係になります。モデルアダプターやエージェントループの交換、エンジンの削除にも、Libre WebUI の変更と再デプロイが必要になります。

ブリッジでは依存関係を逆転させます。Libre WebUI は単一の抽象インターフェイスに依存し、その実装を Cordis の構成ドキュメントで選びます。

  • 再ビルドせず接続先を変更。 構成は YAML ファイルなので、別のプロバイダーへの切り替えは設定変更で済みます。
  • 機能を構成。 各機能は Loader の 1 行に対応します。運用者が管理する構成の変更は、次回のホスト起動時に反映されます。
  • 残さず削除。 エンジンが登録するサービス、リスナー、エフェクトはすべてルートファイバーに属します。そのファイバーを破棄すると全体が元に戻るため、Libre WebUI を再起動せずにエンジンを停止できます。

レイヤー

DSH 固有の依存関係は backend/src/cordis/dsh/ 内に限定されます。ルートとアプリケーションサービスはブリッジのインターフェイスを使用します。Work ドライバーには独立したメモリ内構成があり、ホストのファイルシステムプラグインをマウントしません。

インターフェイス

インターフェイスは backend/src/cordis/contracts.ts にあります。エンジン固有の用語を使わず、Libre WebUI API に必要なデータだけを表すよう、意図的に範囲を絞っています。

インターフェイス用途
DshEngine.status()各エンジンサービスのライフサイクル状態(pending / ready / failed
DshEngine.modelConfiguration()実行中の構成のモデルとプロバイダーの既定値
DshEngine.listSessions()新しい順のセッション概要
DshEngine.getSession(id)セッションと投影されたメッセージの取得
DshEngine.createSession(opts)セッション ID と作業ディレクトリの予約
DshEngine.updateSessionSettings(id, settings)アイドル時に実モデルの選択とネイティブのファイル権限モードを保存
DshEngine.decideApproval(id, approvalId, decision)所属セッションの保留中のネイティブツール承認を 1 件処理
DshEngine.deleteSession(id)セッションを終了しエージェントを破棄
DshEngine.listAgents()実行中のエージェントをルートまたは子として一覧表示
DshEngine.listTools()エンジンがモデル向けに登録したツール
DshEngine.sendMessage(id, txt)ターンを開始しストリームハンドルを返す
DshEngine.cancel(id)セッションで実行中のターンをキャンセル

このインターフェイスは Cordis サービス libreDshEngine として公開されます。利用側は ctx.get('libreDshEngine') で取得し、ブリッジのモジュールを直接インポートしません。

EngineStreamChunktextreasoningtool-calltool-resultapproval-requestapproval-decisionerrordone を運びます。ライブフレームは所属するエージェントとセッションに振り分けられ、対応する永続化済みアシスタントメッセージを二重送信しません。sendMessage が返すハンドルの subscribe は送信済みデータを再生するため、ターン開始から HTTP ハンドラーのリスナー登録までの間に最初のトークンが生成されても失われません。

シーケンス:チャットの 1 ターン

ターンはリクエストに続くサーバーからクライアントへの単一シーケンスなので、NDJSON を使用します。POST 内で処理すれば、追加のハンドシェイク、チケット、再接続プロトコルが不要で、ターン全体を 1 件の認証済みリクエスト内に保てます。

DONE と PENDING

Cordis は宣言したサービスが利用可能になってからプラグインを有効化するため、行にはまだ実行されていない状態があります。次の 2 つの概念を区別してください。混同すると、エンジンが応答しない原因になります。

Loader のエントリー状態。 Loader は各行を PENDING → LOADING → ACTIVE、または FAILED として追跡します。宣言したサービスが不足している行は失敗せず、無期限に待機します。そのため、不完全な構成ではエンジンが起動しても何も提供しない状態になります。

サービスの利用可能性。 ホストは想定する各サービスを次の状態で報告します。

状態意味原因
pendingコンテキストに未登録提供元の行が未有効化、または無効
ready登録済みで利用可能提供元の行が有効化済み
failed宣言済みだが利用不可detail 文字列で理由を報告

host.status() は想定するすべてのサービスと利用可能性を列挙し、不足する必須サービスを示します。GET /api/cordis/health も同じ情報を返します。必須サービスが欠けた構成では、空のリストを返すエンジンを公開するのではなく、起動時に例外を送出します。

次の 2 つの依存チェーンは特に間違えやすいものです。

  • dsh-toolssystemPrompt がなければ起動できません。
  • dsh-agent-loopagentssessionsllmtoolssystemPromptsessionProjections がすべて揃うまで起動できません。

どれかが欠けると、セッションストアは動いていてもメッセージには一切応答しない構成になります。

プロバイダー設定

同梱の libre-webui-llm-adapter 行は、Libre WebUI で設定したモデルプロバイダーを提供します。エンジンページのモデル選択では、この行を置き換えずにセッション用のプロバイダーモデルを選べます。

構成内のプラグイン行を変更した場合、次回のホスト起動時に反映されます。バックエンドを再起動するか、管理者の切り替えがロックされていなければ Cordis を無効化して再び有効化してください。保存済みセッションは設定されたストアに残り、現在の構成で再開されます。

信頼された統合コードは Cordis Loader のライフサイクル API を直接利用できます。ブリッジにはアダプター交換エンドポイントはなく、交換に失敗しても前のアダプターを自動復元しません。

ロールバック

ホストのルートファイバーを破棄すると、エンジンが登録したすべてのものが削除されます。この単一の所有関係が保証を成り立たせています。

  • サービスはプラグインが登録し、ファイバーとともに撤回されます。
  • session/event の購読はブリッジ自身のコンストラクター内で登録され、ブリッジ行のファイバーに属します。
  • エージェントのハンドルはブリッジが追跡し、後処理のエフェクトで破棄します。
  • ホストは、全行を所有するルートコンテキストを破棄します。

stopCordisHost() は冪等で、バックエンドのシャットダウン処理に組み込まれています。エンジンのタイマーやファイルハンドルは、プロセス終了任せにせず解放されます。

セッションの識別と永続化

エンジンページは作成時に不透明なセッション ID を予約します。永続化が有効ならヘッダーを直ちに保存するため、空のセッションでも再起動後に残ります。ブリッジは保存済みと実行中の両方のセッションを一覧表示し、DSH の検証済み永続化 API でログを読み、続きのターンでは同じ ID のエージェントを再開します。新しいユーザーメッセージは DSH の識別子付きメッセージコンストラクターで作成します。

セッションを削除すると、先にエージェントをキャンセルして破棄し、その後で保存ファイルを削除します。ローカル JSONL 削除アダプターはストアとセッションのパスを検証し、シンボリックリンクを拒否します。削除非対応のカスタム永続化バックエンドは、削除したと装わずエラーを返します。

キャンセルはネイティブエージェント、モデルリクエスト、ツール処理に伝わります。クライアントの切断はそのターンをキャンセルしますが、完了済みメッセージは引き続き読めます。ストリーム再生のバッファーには上限があり、読み取り側が接続する前の素早い応答を保持します。

ホストエンジンは単一レプリカの solo 機能です。team デプロイではローカル JSONL ランタイムをマウントできません。サンドボックス化された Work は、既存の SQL ベースのタスク、実行、メッセージ、承認、イベントのリポジトリを使用します。

HTTP インターフェイス

メソッドパス用途
GET/api/cordis/healthブリッジ状態。認証不要
GET/api/cordis/sessionsセッション一覧
POST/api/cordis/sessionsセッション作成
GET/api/cordis/sessions/:idセッションとメッセージの読み取り
DELETE/api/cordis/sessions/:idセッション終了
POST/api/cordis/sessions/:id/messagesメッセージ送信と NDJSON ストリーム
POST/api/cordis/sessions/:id/cancel実行中のターンをキャンセル
GET/api/cordis/agents実行中のエージェント一覧
GET/api/cordis/tools登録済みツール一覧

/health 以外のすべてのルートには認証済みの管理者セッションが必要です。ブリッジが処理できない間は 503 を返し、codeCORDIS_DISABLEDCORDIS_STARTINGCORDIS_UNAVAILABLE のいずれかを設定します。

セッション一覧、登録済みツール、ストリーミングされたチャット履歴を表示する Libre WebUI の Cordis エンジンページ。

ページは frontend/src/pages/CordisPage.tsx に実装され、サイドバーから /cordis にアクセスできます。セッションと登録済みツールの一覧、セッション作成、会話へのターンのストリーミングを提供します。ブリッジが無効または起動不能なら空の一覧ではなく理由を表示し、「セッションがない」と「エンジンがない」を区別できます。

ブラウザークライアントは frontend/src/utils/api/cordisApi.ts です。このインターフェイスだけを使い、バックエンドの型や @deepseek-ai/* パッケージをインポートしないため、フロントエンドを変えずにエンジンを交換できます。sendMessage(sessionId, text, { onChunk }) でターンを受信し、改行区切りの JSON を自身で解析して、ネットワーク読み取りで分割されたチャンクも扱います。

エンジンのチャット操作

エンジンページは Markdown、表、構文ハイライト付きコードブロックを表示し、返信やコードをコピーできます。システムプロンプトと注入されたランタイムコンテキストは、折りたたまれたセッションのコンテキストにまとめられ、ユーザーが書いたメッセージとして表示されません。公開された推論とツールの動作は別々に展開でき、再読み込み後もツール結果は正しい操作に対応付けられます。

入力欄で実際のプロバイダーモデルを選んでください。選択肢には、サインインした管理者が利用できるローカルモデルとプラグインモデルが、プロバイダーの識別情報とともに表示されます。Chat のペルソナやエージェント選択はモデル ID ではなく、その指示がエンジンの会話に注入されることもありません。過去に失敗したペルソナモデルのヘッダーは、既定モデルの手掛かりとして無視され、保存済みログは変更されません。

各セッションには読み取り専用またはワークスペースへの書き込み設定があります。DSH のファイルシステムポリシーとブリッジの正規化されたワークスペース境界がこれを強制し、入力欄には対象範囲を表示します。設定はネイティブセッションのイベントとして保存され、再起動後も残ります。ターン実行中の変更は拒否されます。

ネイティブの権限昇格リクエストは、操作に付随する一度許可する / 拒否カードとして表示されます。承認はそのリクエストだけに適用され、継続的な権限モードは変わりません。期限切れやキャンセル済みのリクエストは承認できず、画面を持たない Chat 呼び出しは提示できない質問を拒否します。ブリッジは無制限のホストアクセスを提供しません。

追加の管理者エンドポイントは次のとおりです。

メソッドパス用途
GET/api/cordis/models利用可能なプロバイダーモデルと現在の実モデルの既定値
PATCH/api/cordis/sessions/:id/settingsこのセッションのモデルまたは権限モードを設定
POST/api/cordis/sessions/:id/approvals/:approvalId保留中の 1 件を allowed-once または rejected で処理

Chat でエンジンを使う

アクセスとポリシー → エージェントCLIモデルCordis エンジンを両方有効にすると、管理者は Chat で DeepSeek Harness を選べます。各リクエストには、その Chat リクエストが提供した履歴を含む新しい一時エンジンセッションが割り当てられます。通常の Chat データベースが引き続き正規の状態を保持し、無関係な会話、分岐、再試行が見えないエンジン履歴を共有することはありません。一時ログは完了またはキャンセル後に削除され、エンジンページには表示されません。

標準のプロバイダー構成では、エージェントグループに DeepSeek Harness · モデル(プロバイダー)も表示されます。保存 ID はエンジンページと同じ限定付きルートを包む dsh:lwui:ollama:<model> または dsh:lwui:plugin:<plugin>:<model> で、各プロバイダー要素はパーセントエンコードされます。任意のローカルなネイティブ DSH 接続を設定すると、接続先のライブカタログから dsh:native:<provider>:<model> が追加され、そのプロバイダー設定と認証情報を再利用します。Apache-2.0 の独立パッケージを libre-webui/dsh-native-provider からインストールするか、Libre WebUI 配布物からバンドルを準備してください。どちらも @libre-webui/dsh-native-provider という名前を使い、キーはネイティブ DSH に保持します。同一 Unix ホスト、同一 OS アカウントのプライベート Unix ソケットを使用するため、同じアカウントを共有するアプリ同士は隔離できません。提供するのはモデル推論だけで、ネイティブのエージェントセッションやツール実行は含みません。インストール、プロファイルの再起動、更新、削除は設定ガイドを参照してください。接続や選択モデルが利用できなければ、別のプロバイダーに切り替えず失敗します。ネイティブ呼び出しはプロバイダー使用状況にも記録され、選択モデル、報告されたトークン数、遅延、結果を確認できます。基本の dsh プロファイルは実行中の構成の既定モデルを維持します。カスタムアダプター構成は基本プロファイルを公開し、未対応の Libre WebUI プロバイダー上書きを選択肢として示しません。

タイトルと推論要約は DSH の選択を基になるプロバイダーへ解決し、ツールやエージェントセッションを使わず直接テキストを要求します。基本プロファイルへの要求は、現在のカタログから推測せず、ブリッジ行の上書きを含む実行中エンジンの既定値を読みます。カスタムアダプターでは、これらの機能向けに Ollama またはプラグインのタスクモデルを明示的に設定する必要があります。選択先が利用できない場合は通常の失敗またはローカルのタイトルプレビューとなり、別のプロバイダーへの要求は行いません。

リクエストは認証済み管理者のプロバイダー設定と認証情報を使い、別の管理者の認証情報を暗黙に選びません。既定の作業領域は設定済みの Cordis ワークスペースです。Chat がサーバーユーザーのホームディレクトリに置き換えることはありません。

サンドボックス化された Work

Cordis が有効な場合、Work には Libre WebUIDeepSeek Harness を選べる独立したエンジン操作があります。モデル選択は通常のモデル名とプロバイダー識別情報を維持します。LWUI のプロバイダーを使う DSH 選択は内部的に dsh:<model> として保存されます。ネイティブ DSH 選択は providerType: dsh、正確なプロバイダー ID、元のモデル ID を保存します。通常のツール機能とアクセス検証に加え、ネイティブ認証情報の利用には有効な管理者であることが必要です。

各実行は隔離されたメモリ内 DSH エージェントループを作成します。モデルアダプターは現在の Work 履歴、プロバイダーメタデータ、画像、ツールスキーマを受け取ります。ツール本体は Work が返す結果を待つだけで、ホストのファイルを読んだりプロセスを起動したりできません。

引数の検証、承認要求、ワークスペースランタイム内のツール実行、結果とプロバイダー再生状態の SQL 記録、予算の強制、イベント発行は引き続き Work が担当します。拒否されたツールは通常の拒否結果を返します。キャンセルは DSH を破棄し、Work の既存のコンテナー清掃処理に従います。ワーカー復旧後は新しい DSH ドライバーが復元済み Work コンテキストを受け取り、完了したツールの副作用を繰り返しません。

Work 統合にはホストエンジンの構成や JSONL セッションストアは不要です。team モードの共有永続化要件を含め、Work の既存の Docker/Kubernetes ランタイムとデプロイルールに従います。

セキュリティ境界

エンジンページとホスト側の Chat エージェントは管理者専用です。システムプロンプトを含むエンジンセッションは共有の管理者コンソールであり、ユーザーごとのワークスペースではありません。一般アカウントは API 経由で読み取り、作成、変更、キャンセルを行えません。

同梱のホストファイルシステムツールは、シンボリックリンクの解決を含む正規化されたファイルシステムの対象に基づいて、読み書きを設定済みワークスペース内に制限します。セッションの作業ディレクトリの上書きもその範囲内でなければなりません。DSH のネイティブ変更ポリシーとエンジンの一度限りの承認は引き続き適用されます。運用者が導入する構成プラグインは信頼されたサーバーコードであり、追加機能を与えられます。エンジンの承認は Work の承認やコンテナー実行とは別です。

Work の DSH ドライバーは独立しており、ホストのファイルシステム、シェル、永続化プラグインをマウントせず、既存の Work の認可とサンドボックス経由でのみ実行できます。リモートモデルプロバイダーは引き続き明示的な有効化が必要で、選択したアカウントに設定されたプロバイダールートを使用します。