Web チャット UI

完全なブラウザチャットクライアント - サイドバー、ストリーミング、承認、SQLite ストア。

On this page

Web チャット UI

exposes: "webui" を持぀ gateways/*.bx ゚ントリは、゚ヌゞェント向けの完党なブラりザチャットクラむアント - 䌚話サむドバヌ、掚論ずツヌル呌び出しを䌎うストリヌミング、human-in-the-loop 承認、蚪問者ごずのテヌマ、そしおその背埌にある実際の SQLite ストア - を出荷したす。

これは公開が宣蚀される堎所であるずいう理由で gateways/ の䞋にありたすが、それ自䜓が独立したサブシステムであり、それゆえに独自のペヌゞを持っおいたす。

// gateways/chat.bx
class {
	function configure() {
		return {
			exposes     : "webui",
			path        : "/chat",
			apiKeyEnvVar: "CHAT_UI_API_KEY"   // optional - see Securing the API
		};
	}
}

これは静的な <path>/index.html (盎接配信され、ルヌトは䞍芁です) ず、生成された handlers/ChatUi.bx ず models/ChatDb.bx に支えられた <path>/api 配䞋の専甚 API を生成したす。

この UI は䟝存関係のない玠の HTML/CSS/JS です - Bootstrap、AlpineJS、Vite のビルドステップは䞀切ありたせん - そしお BX Agents 自䜓の䞭にあらかじめビルドされおバンドルされおいたす: bxAgents build が npm install/npm run build を実行するこずは決しおなく、生成されたプロゞェクトは Node や npm をむンストヌルする必芁が䞀切ありたせん。ペヌゞが必芁ずするものはすべお、生成された単䞀の index.html にむンラむン化されおいたす。

その制玄はビルドに぀いおのものであり、スコヌプに぀いおのものではありたせん。このペヌゞは完党なクラむアントです: 䌚話サむドバヌ、掚論ずツヌル呌び出しを䌎うストリヌミング、承認、圧瞮 (compaction)、サヌバヌ偎のテヌマです。実際にただ足りおいないものは What is not here yet に䞀芧がありたす。

このペヌゞは、生成された自身の <path>/api ルヌトず、POST <path>/api/stream (Accept: text/event-stream) を介しお通信したす。POST もカスタムヘッダヌの蚭定もできないブラりザの EventSource ではなく、fetch() + 手動の ReadableStream リヌダヌを䜿いたす。䞡方ずもここでは必芁だからです。

Warning

toAi() は各 bx-ai チャンクをそのたた転送したす - ラップしたせん。 ColdBox の AI Routing ドキュメント はストリヌムを data: {"token":"..."} 行ずしお瀺しおいたすが、その゜ヌス自䜓 (Router.cfc、toAi() のストリヌムサブルヌト) は emitter.send( chunk, "chunk" ) を行いたす - ぀たり、すべおのフレヌムが完党に正芏化された bx-ai ゚ンベロヌプを運びたす。

event: chunk
data: {"object":"chat.completion.chunk","choices":[{"delta":{"role":"assistant","content":"Ray","reasoning":"...","tool_calls":[...]}}]}

event: done
data: [DONE]

token ずいうキヌはどこにもありたせん。そのドキュメントペヌゞに沿っお曞かれたクラむアント - このUIの最初のバヌゞョンも含む - は undefined を読み取り、䜕もレンダリングしたせん。代わりに choices[0].delta.content を読んでください。

゚ンベロヌプ党䜓が届くため、掚論ずツヌル呌び出しはすでに配線の䞊に茉っおおり、远加の゚ンドポむントは䞍芁です: delta.reasoning (bx-ai によっおすべおのプロバむダヌにわたっお正芏化されおいたす) は折りたたたれた「Thinking」ストリップずしお描画され、delta.tool_calls は折りたたたれた呌び出しごずのチップずしお描画されたす。ツヌル呌び出しの匕数は index でキヌ付けされた郚分的な JSON フラグメントずしおストリヌミングされるため、ペヌゞは単䞀のどのチャンクが完党な呌び出しを保持しおいるずも仮定せず、むンデックスごずに蓄積しおいきたす。

ストリヌミングタヌンの実際の様子

sequenceDiagram
    autonumber
    participant B as browser (generated index.html)
    participant H as handlers/ChatUi.bx
    participant A as the agent
    participant D as models/ChatDb.bx (SQLite)

    B->>H: POST /chat/api/stream, Accept: text/event-stream
    H->>D: resolve the conversation for this session
    H->>A: agent.stream( ... )
    H-->>B: event: thread - the threadId, sent BEFORE the first chunk
    loop for every chunk bx-ai emits
        A-->>H: a full normalized bx-ai envelope
        H-->>B: event: chunk - choices[0].delta.content / .reasoning / .tool_calls
    end
    H->>D: persist the turn
    H-->>B: event: done - [DONE]

thread むベントが最初に送られるのは、レスポンスヘッダヌはボディが届き始める前には読めないためで、ペヌゞはタヌンの途䞭で POST /cancel できるように、その threadId を必芁ずしたす。

生成される API

webui ゚ントリは、生成された handlers/ChatUi.bx によっお配信される 20 個のアクションを <path>/api の䞋にマりントしたす。

ルヌト目的
POST /invoke同期の 1 タヌン
POST /streamSSE タヌン (このペヌゞが䜿うもの)
POST /batchinputs[] 配列を実行
POST /cancel進行䞭のランを停止 - { threadId, reason? }
POST /steer実行䞭のタヌンにメッセヌゞをスプラむス - { threadId, input }
POST /clearこの蚪問者の䌚話をクリア
POST /compactこの蚪問者の叀いメッセヌゞを芁玄し、最近のものは保持 - 任意の { keepRecent }
GET /historyこの蚪問者の保存枈みメッセヌゞ。トランスクリプトの再氎和甚
POST /resume保留䞭の承認に答え、継続をストリヌミング - { threadId, decision, editedData?, reason? }
GET /pending䞭断䞭のランが䜕を埅っおいるか - ?threadId=
GET /tools゚ヌゞェントの登録枈みツヌル
GET /health生存確認
GET /info゚ヌゞェント名、モデル、メモリ/ツヌル数、機胜フラグ
GET /conversationsこの蚪問者の䌚話。最新のアクティビティ順
POST /conversations/create䌚話を開始 - 任意の { title }、発行された conversationId を返す
POST /conversations/rename{ conversationId, title }
POST /conversations/delete{ conversationId } - むンデックス行ずその゚ヌゞェントのメッセヌゞの䞡方を削陀
GET /preferencesこの蚪問者の保存枈み蚭定、{ key: value } ずしお
POST /preferences/set{ key, value }
POST /preferences/delete{ key }

すべお、userId ずしお ColdBox の getUserSessionIdentifier() によっおスコヌプされおいたす。最初の 3 ぀は toAi() の圢ずワむダヌフォヌマットを正確に保っおいたす。

threadId はサヌバヌ暩嚁です: 䞎えられればリク゚ストから取埗され、そうでなければ発行され、垞に゚コヌバックされたす - /invoke ず /batch では X-Thread-Id レスポンスヘッダヌずしお、/stream では最初のチャンクより前に送られる thread SSE むベントずしお (ヘッダヌはボディが届き始める前には読めないためです)。これは ColdBox 8.1 自身の toAi() が採甚しおいるのず同じ契玄なので、䞀方向けに曞かれたクラむアントはもう䞀方に察しおも動䜜したす。

Warning

停止は、単にフェッチを䞭断するのではなく /cancel を経由する必芁がありたす。 HTTP リク゚ストを䞭断しおも、ブラりザが聞くのをやめるだけです - サヌバヌはツヌルを呌び出し、トヌクンを消費しながらタヌンの実行を続けたす。そのためペヌゞはすべおのタヌンに threadId を添えお送り、䞭断する前にそれを /cancel に POST し、agent.cancelRun() がそのランの次のチェックポむントにシグナルを送れるようにしたす。

/clear ず /compact はどちらもスコヌプに泚意深いです。/clear は、匕数を取らずすべおの蚪問者の履歎を消しおしたう AiAgent.clearMemory() ではなく、各メモリ自身の clear( userId, conversationId ) を経由したす。/compact も同じ理由で summarize( config, userId, conversationId ) を経由したす。圧瞮は、この䌚話の叀いメッセヌゞを AI が曞いた芁玄に眮き換え、盎近のいく぀かは保持し、呌び出し元の (userId, conversationId) ペア以倖には䞀切觊れたせん。

Info

/compact には芁玄モデルが必芁で、それを持っおいるかどうかを報告したす。 summarize() は、メモリに summaryProvider ず summaryModel の䞡方が蚭定されおいない限り、たた䌚話がすでに keepRecent 以䞋の堎合も、サむレントな無操䜜になりたす。どちらも゚ラヌではないため、/compact は { compacted, before, after } を返しお呌び出し元自身に確認させ、/info の capabilities.compact は、そもそも芁玄モデルが蚭定されおいるかどうかを報告したす - そのため、ペヌゞは䜕もしないボタンを、壊れおいるように芋せる代わりに隠すこずができたす。

リク゚ストから取られるのは keepRecent だけです。summarize() は model/provider のオヌバヌラむドも尊重したすが、ここでそれを受け付けおしたうず、どの蚪問者でもあなたの認蚌情報で奜きなプロバむダヌずモデルに芁玄呌び出しを向けられおしたいたす - それはメモリ自身の config が決めるこずです。

// Agent.bx - what makes /compact functional
memory: {
	type            : "cache",
	summaryProvider : "openai",
	summaryModel    : "gpt-4o-mini",
	summaryThreshold: 10
}

ナヌザヌずサむンむン

デフォルトでは Web UI にはアカりントもゲヌトもありたせん — オヌプンで、すべおの蚪問者は匿名です。それがれロ儀匏な bxAgents serve の䜓隓であり、これはデプロむの姿勢ではありたせん。webui ゚ントリで users を宣蚀するず、cbauth ず、他のすべおが䜿うのず同じ SQLite ストアに支えられた、本物のサむンむンゲヌトが有効になりたす。

アカりントなしでは、UI は 1 ぀の共有ワヌクスペヌスです

意図的に、蚪問者ごずのアむデンティティは存圚したせん。アカりントのない Web UI ぞのすべおの蚪問者は、同じ䌚話、蚭定、゚ヌゞェントメモリを読み曞きしたす — そのペヌゞに到達できる人は誰でも、その䞭のすべおを芋るこずができたす。

これは芋萜ずしではなく、アカりントなしで実行するこずの芁点そのものです - オヌプンな UI は 1 ぀の共有ツヌル (ラップトップ、信頌できる瀟内マシン) であり、マルチテナントサヌビスではありたせん。ブラりザごずに独自のスラむスを持たせおも、誰も求めおいないブラりザごずのコピヌに 1 ぀のワヌクスペヌスを断片化させるだけであり、その断片化を行う任意のクラむアント偎 ID は、どのみち停装可胜です。

Warning

オヌプンな UI には蚪問者間のプラむバシヌがありたせん。 その URL に到達できる人は誰でも、その䞭のすべおの䌚話を芋るこずができ、そのどれでも続けたり削陀したりできたす。もしそれが望むずころでないなら - 芋るべき人以䞊の人がそのペヌゞに到達できるあらゆる堎所で - users を宣蚀しおください。

// gateways/chatUi.bx
users : [
    { username: "ada",   passwordEnvVar: "ACME_ADA_PASSWORD", displayName: "Ada Lovelace" },
    { username: "grace", passwordHash: "pbkdf2$210000$...",   displayName: "Grace Hopper" }
]

パスワヌドは config に決しお曞き蟌たれたせん

アカりントは、パスワヌドを保持する環境倉数の名前 (passwordEnvVar) を指定するか、すでにハッシュ化された倀 (passwordHash) を持ちたす。リテラルな password キヌは、譊告ではなくビルド゚ラヌです — サむレントに無芖しおしたうず、実際には䜕もコミットしおいないのにパスワヌドを蚭定したず信じ蟌んでしたいたす。

passwordHash は、それが逆算䞍胜であるからこそコミットしおも安党です。アプリが䜿うのず同じハッシャヌで生成しおください。

bxAgents hash-password --password="correct horse battery staple"
Danger

ハッシュ化であり、暗号化ではありたせん。 暗号化は可逆であり、盗たれたデヌタベヌスファむルはほが垞に、それを埩号できる䜕かず䞀緒に持ち出されたす - そのため可逆な方匏は、1 ぀のファむル挏掩を、他の堎所で䜿い回されたものも含む党ナヌザヌのパスワヌド挏掩に倉えおしたいたす。ここでのパスワヌドは、ナヌザヌごずのランダムな゜ルト付きの PBKDF2-HMAC-SHA256 を経由し、デヌタベヌスから埩元するこずは決しおできたせん。(BoxLang には bcrypt や argon2 の BIF は出荷されおいたせん。PBKDF2 は䟝存関係を远加せずに䜿える最匷のプリミティブです。)

反埩回数は各ハッシュの内郚に保存されるため (pbkdf2$<iterations>$<salt>$<digest>)、すでに保存されおいるものを無効化せずに埌から匕き䞊げるこずができたす。

サむンむンが倉えるもの

ナヌザヌスコヌプのものはすべお、実際のアカりントに再キヌされたす。生成された handlers/ChatUi.bx は、1 ぀のメ゜ッド (resolveUserId()) で cbauth から盎接アむデンティティを解決し、゚ヌゞェントメモリ、䌚話むンデックス、蚭定、保留䞭のラン所有暩はすべおその戻り倀をキヌにしたす。

これは意図的に ColdBox の identifierProvider 蚭定ではなく cbauth を読み取りたす: coldbox config 構造䜓の䞭で宣蚀されたクロヌゞャは決しお configSettings に届かない (文曞化されおいるリテラルな圢ず、埌からの代入の䞡方で、実際の起動で確認枈みです) ため、その蚭定に頌っおいたものは䜕であれ、サむレントにセッション id を代わりに受け取っおいたした。

実務䞊の違いは: 䌚話ず蚭定はブラりザやデバむスをたたいでその人に぀いおいき、Cookie をクリアしおも新しい「ナヌザヌ」が䜜られるこずはもうありたせん。

users なしusers あり
アむデンティティ1 ぀の共有ワヌクスペヌスサむンむンしおいるアカりント
䌚話が芋えるのはUI に到達できる誰でもその所有者のみ
ブラりザ/デバむスをたたいでその人に぀いおいくn/a — 䜕も個人単䜍ではないはい
サむンむンなしで到達可胜すべおログむンフォヌムのみ

ラむフサむクル

アカりントは、すべおの起動のたびに、この順序で config から調敎されたす: スキヌマむンタヌセプタヌがマむグレヌションを行い、シヌダヌがアカりントを曞き蟌み、その埌ログむンゲヌトが匷制を開始したす。

  • 远加 config にナヌザヌを远加するず䜜成されたす。
  • 倉曎 パスワヌドを倉曎するず曎新されたす。シヌダヌは、蚭定されたパスワヌドが保存されおいるものず䞀臎しなくなった堎合にのみ再ハッシュするため、倉曎のないパスワヌドには 1 回の怜蚌コストしかかかりたせん。
  • 削陀 config から削陀するず、削陀ではなくアカりントを無効化したす。圌らの䌚話は圌らの id を参照しおいるため、行を削陀するずアクセスを取り消す代わりにその履歎を孀立させおしたいたす。圌らはもうサむンむンできたせんが、デヌタはそのたた残り、アカりントが埩元されれば戻っおきたす。
  • 倉数が未蚭定の passwordEnvVar を持぀アカりントは、そのアカりントを完党にスキップし、webui-auth に譊告をログしたす。これは意図的にクロヌズ (安党偎) に倱敗したす - 空のパスワヌドでアカりントを䜜成しおしたうこずは、存圚しないこずよりもずっず悪いこずだからです。

これではないもの

これは固定された、オペレヌタヌが甚意したアカりントの䞀芧であり、ナヌザヌ管理システムではありたせん。セルフ登録も、パスワヌドリセットも、ロヌルや暩限も、ナヌザヌごずのレヌト制限や支出䞊限もありたせん。連合アむデンティティが必芁な堎合は、生成されたハンドラの resolveUserId() を線集しお、あなた自身の認蚌枈みプリンシパルを返すようにしおください - Web UI の残りの郚分は、その id がどこから来たのか䞀切知りたせんし、気にもしたせん。

Human-in-the-loop

゚ヌゞェントが承認のために䞀時停止するず、ストリヌムは詳现を運ばない middleware_stop チャンクを発行したす。そのためペヌゞは GET /pending?threadId= に䜕がリク゚ストされおいるかを尋ね、Approve / Reject でレンダリングし、POST /resume 経由で答えたす - これは同じタヌンの継続をストリヌミングするので、その結果は新しいタヌンを始めるのではなく、䌚話の䞭に収たりたす。

decidedBy はセッションからサヌバヌ偎で埋められ、リク゚ストボディからは決しお埋められたせん: 䜕かを承認したのが誰かずいうのは、たさに呌び出し元が自分自身に぀いお䞻匵すべきではない類のこずです。

Warning

䞭断䞭のランは、それを開始したセッションに属し、䞡方のルヌトがそれを匷制したす。 decidedBy をサヌバヌ偎で導出するこずは、呌び出し元が誰が決定したかに぀いお嘘を぀くこずを止めるだけです - それ単䜓では誰のランを決定しおいるかに぀いおは䜕も察凊したせん。他のすべおのアクションず異なり、/pending ず /resume は䌚話ではなく threadId によっおアドレスされるため、所有暩チェックがなければ、他人の threadId を持぀蚪問者が、その人の保留䞭のツヌル呌び出しずその匕数を読み取り、その人に代わっお承認・拒吊できおしたいたす。

所有者には远加の蚘垳は䞍芁です: ハンドラはセッション由来の userId をラン options に刻み蟌み、゚ヌゞェントはその䞭断状態ず䞀緒にその options をチェックポむントしたす - そのため、保存された状態はすでに自分が誰のものかを知っおいたす。呌び出し元が所有者でない堎合、/pending はあたかも䜕も保留しおいないかのように答えるので、これを䜿っお threadId が存圚するかどうかを探るこずはできたせん。/resume は 403 で拒吊したす。

履歎ず再読み蟌み

トランスクリプトは DOM の䞭に存圚し、䌚話ぱヌゞェントのメモリの䞭に存圚したす。再氎和がなければ、リロヌドは空の画面を衚瀺するのに、゚ヌゞェントはすべおを芚えたたたです - そのためペヌゞは空癜に芋えたのに、ナヌザヌには芋えおいないメッセヌゞに぀いおのフォロヌアップに答えおしたうこずになりたす。そのためペヌゞはロヌド時に GET <path>/api/history を呌び出し、保存されたメッセヌゞ (マヌクダりンも含めお) を再生し、䌚話が空か、フェッチが倱敗した堎合はりェルカムメッセヌゞにフォヌルバックしたす。

New は新しい conversationId を開始したす。䜕も削陀したせん - 以前の䌚話は自身の id のもずでサヌバヌ䞊に残り、サむドバヌに衚瀺されたす。それこそが䌚話テヌブルの存圚意矩です。

ペヌゞが行うこず

出荷されるペヌゞは、デモ甚のシェルではなく実際のチャットクラむアントです。たず GET /info を読み取り、サヌバヌが実際に報告する内容に自分自身を合わせるので、あるコントロヌルは、その機胜が実圚する堎所にのみ珟れたす。

領域振る舞い
䌚話サむドバヌこの蚪問者の䌚話を最新順に、メッセヌゞ数ずずもに䞀芧衚瀺したす。切り替え、名前倉曎 (✎)、削陀 (×)、たたは新芏開始。タむトルは textContent を通じおレンダリングされたす — タむトルはナヌザヌが最初に入力したものが䜕であれそのたたなので、マヌクアップずしお解釈されるこずは決しおありたせん
ストリヌミング䞭に操瞊するコンポヌザヌはタヌンの間ずっず生きたたたです。Send は Steer になり、メッセヌゞは新しいタヌンを始めるのではなく、すでに進行䞭のランに継ぎ足されたす
Stopフェッチを䞭断する前に /cancel を POST するので、サヌバヌは実際にトヌクンの消費をやめ、その埌すでにストリヌミングされたものはそのたた保持したす
Clear / CompactClear はこの䌚話を空にしたす。Compact は芁玄モデルが蚭定されおいる堎合にのみ珟れ、実際に䜕をしたか (Compacted 12 messages down to 3、たたは Nothing to compact yet) を報告したす
掚論 + ツヌル呌び出し同じ゚ンベロヌプの delta.reasoning ず delta.tool_calls から䟛絊される、折りたたみ匏の開瀺
承認human-in-the-loop の䞀時停止は GET /pending から Approve/Reject カヌドをレンダリングし、/resume 経由で答えられ、同じタヌンの継続をストリヌミングしたす
テヌマpreferences にサヌバヌ偎で保存されるので、ブラりザではなくアむデンティティに぀いおいきたす。localStorage はロヌカルコピヌを保持するので、倱敗したリク゚ストがあっおも遞択は生き残りたす
モデル/info のモデル名がヘッダヌに収たるので、䜕が答えたのか垞に明確です

埩旧はその響き以䞊に重芁です。 最埌に開いた䌚話は localStorage に蚘憶されたすが、䌚話自䜓はサヌバヌ䞊に存圚したす。その id がもう存圚しない堎合 (別のタブで削陀された、あるいは新しいストアである) — ペヌゞは、アクティブな行のない空の画面に再氎和する代わりに、残っおいる䞭で最新の䌚話にフォヌルバックしたす。

狭い画面には、抌し぀ぶされたものではなく本物のレむアりトが甚意されたす: 40rem 未満では、サむドバヌはトランスクリプトの幅を奪うのではなく、その䞊にオヌバヌレむされ、prefers-reduced-motion は尊重されたす。

SQLite ストア

すべおの webui プロゞェクトは SQLite デヌタベヌスを埗たす。これは任意ではなく、オフにするフラグもありたせん。

その理由は奜みではなく、実際のギャップです: bx-ai の IAiMemory には列挙 API がありたせん。 これは (userId, conversationId) ごずのバケットです — 1 ぀を読み曞き・クリアできたすが、その䞭の䜕も「このナヌザヌはどの䌚話を持っおいるか」には答えたせん。䌚話䞀芧、ナヌザヌごずの蚭定、その他のリレヌショナルなものはすべお、メモリの内郚ではなく、それに䞊ぶ実際のストレヌゞが必芁です。

郚品それが䜕か
bx-sqliteJDBC ドラむバです。これがなくおも webui アプリは起動したすが、すべおのク゚リが未知のドラむバで倱敗したす
qb読み曞き甚の QueryBuilder、テヌブル甚の SchemaBuilder。手曞きの SQL はどこにもありたせん
models/ChatDb.bx生成されたす。スキヌマを所有し、ク゚リビルダヌを配垃したす
interceptors/WebUiSchema.bx生成されたす。起動時に ChatDb を構築するので、マむグレヌションはその時点で走り、デヌタベヌスに最初に觊れたリク゚ストで走るわけではありたせん

デヌタ゜ヌスは Application.bx に登録され、グラマヌは config/ColdBox.bx に固定されたす。

// Application.bx (generated)
this.datasources[ "bxagents" ] = {
	"driver"  : "sqlite",
	"database": expandPath( "./data/chat.db" )
}
this.datasource = "bxagents"   // NOT this.defaultDatasource - see below

// config/ColdBox.bx (generated)
qb : {
	defaultGrammar : "SQLiteGrammar@qb",
	defaultOptions : { datasource : "bxagents" }
}

どちらも、゚ントリごずに䞊曞きするのは任意です。

キヌ䜕をするかデフォルト
database.datasourceColdBox のデヌタ゜ヌス名bxagents
database.pathデヌタベヌスファむル、アプリルヌトからの盞察パス./data/chat.db

絶察パスの database.path はビルドを倱敗させたす: これは生成されたアプリの内郚で expandPath() によっお解決されるため、絶察パスはサむレントにアプリディレクトリの倖に脱出し、パッケヌゞ化された .bxa デプロむを壊したす。

スキヌマはバヌゞョン管理され、前方向専甚です。 ChatDb.migrate() は適甚したものを bxagents_schema_version テヌブルに蚘録し、新しいものだけを適甚するので、既存のストアに察しお起動するのは無操䜜です。v1 は conversations ず preferences を䜜成したす。新しい applyV<n>() を远加し SCHEMA_VERSION を䞊げるこずで進化させおください — 出荷枈みのマむグレヌションを線集するこずでは決しお行わないでください。SQLite はカラムを倉曎したり削陀したりできないからで、qb の SQLiteGrammar はそうであるかのように装う代わりに UnsupportedOperation を投げたす。

Warning

ここでの 2 ぀のこずは盎感に反しおおり、どちらも実際の ColdBox の起動に察しお、ドキュメントを読んで確立されたのではなく、苊劎しお確立されたした。

デフォルトデヌタ゜ヌスの蚭定は this.datasource であり、this.defaultDatasource ではありたせん。 登録キヌは耇数圢 (this.datasources[ "name" ]) であるため、単数圢のデフォルトはそれに䞀臎するように読めたすが — BoxLang は this.defaultDatasource をサむレントに受け入れ、䜕もしたせん。それが生み出す倱敗は、たさにあなたが遞択しようずしおいるそのデヌタ゜ヌスの名前を挙げたす (No default datasource defined in the application or globally or in the query options. Registered datasources are: [bxagents])。これは、蚭定のスペルミスずいうより、遞択メカニズムが壊れおいるように読めたす。

すべおの qb ビルダヌにデヌタ゜ヌスの名前を指定しおください。moduleSettings.qb.defaultOptions に頌らないでください。 qb の ModuleConfig.cfc は QueryBuilder@qb を onLoad() の䞭で .initArg( name = "defaultOptions", value = settings.defaultOptions ) ずしおマッピングするため、その蚭定はあなたをカバヌしおいるように芋えたす。それは実際の起動では届きたせんでした - デヌタ゜ヌスは登録されおいたのに、ビルダヌは空の options を持ったたたでした。そのため ChatDb.query() は、配垃するすべおのビルダヌに察しお .mergeDefaultOptions( { datasource : static.DATASOURCE } ) を呌び出したす。SchemaBuilder@qb は defaultOptions を䞀切受け取らない (qb はこれを grammar だけでマッピングしたす) ので、すべおのスキヌマ呌び出しは自分自身で options: { datasource: ... } を枡したす。

moduleSettings.qb ブロックはそれでも生成されたす - アプリ内の他のあらゆる qb の利甚にずっお正しいものだからです - しかし、生成されたストアはそれに䟝存しおいたせん。

ChatDb を extend する堎合は、远加するものすべおにデヌタ゜ヌスの名前を指定しおください。

もう䞀぀、倉わらないもの: デヌタ゜ヌスは名前付きデヌタ゜ヌスである必芁があり、むンラむン構造䜓では決しおありたせん - qb 自身の appendSqlComments() はその匕数を string ずしお型付けしおいるため、構造䜓は SQL が䞀切実行される前に䟋倖を投げたす。

グラマヌだけが SQLite 固有の郚分です。それ以倖はすべお qb を経由するので、これを埌で Postgres や MySQL に向けるのは曞き盎しではなく、グラマヌずデヌタ゜ヌスの倉曎で枈みたす。

䌚話ず蚭定

これらは SQLite ストアが存圚する理由そのものであり、どちらも他のすべおず同じ、サヌバヌ由来の userId でスコヌプされおいたす。

䌚話。 /invoke、/stream、/batch を通るすべおのタヌンは、それ自身をむンデックスに蚘録したす: その行は初回利甚時に䜜成され、updatedAt が動き、最初のナヌザヌメッセヌゞがタむトルになりたす (1 行に折りたたたれ、60 文字に切り詰められたす) - すでに蚭定されおいる堎合を陀きたす。そのため、名前倉曎が次のタヌンによっおサむレントに元に戻されるこずはありたせん。messageCount は衚瀺甚のカりンタヌで、タヌンごずに 2 ず぀増えたす。途䞭で終わったタヌンは 1 だけ倚く残すこずがあり、/clear はこれをリセットしたす。実際に䜕が話されたかに぀いおの暩嚁であり続けるのは、゚ヌゞェント自身のメモリです。

/conversations/delete は、むンデックス行ずその䌚話に察する゚ヌゞェントのメッセヌゞの䞡方を削陀したす。行だけを萜ずすず、誰かがその id を再利甚した瞬間にモデルのコンテキストにただ座ったたた、䌚話が芋えなくなっおしたいたす。

Warning

touchConversation() が qb の upsert ではない理由。 upsert は䞻キヌだけを察象にするため、他の蚪問者の conversationId を掚枬した呌び出し元が、その行に自分自身の userId を曞き蟌み、䌚話を乗っ取っおしたうこずになりたす。このストアはたず読み取り、その行が他人のものである堎合は拒吊したす。setPreference() は upsert を行い、安党です — そのタヌゲットは (userId, prefKey) の耇合キヌであり、呌び出し元自身のアむデンティティがそのマッチ察象の䞀郚だからです。

蚭定。 localStorage ではなくサヌバヌ偎なので、ブラりザではなくアむデンティティに぀いおいきたす。identifierProvider を実際の認蚌枈みプリンシパルに向ければ、生成されたコヌドを䞀切倉曎するこずなく、蚪問者の蚭定はデバむスをたたいでその人に぀いおいきたす。

ブランディングずテヌマ

以䞋のキヌはすべお任意です - この゚ントリは exposes ず path だけでも動䜜したす。

キヌ䜕をするか
titleブラりザのタむトルずヘッダヌの芋出し
subtitle芋出しの䞋の小さな行
icon絵文字 (むンラむン SVG のファビコンずヘッダヌの䞡方にレンダリングされたす) たたは画像 URL/パス (/logo.svg、https:// 、data:image/
)
welcome最初のタヌンの前に衚瀺される空状態のメッセヌゞ
placeholderコンポヌザヌ入力のプレヌスホルダヌ
footerコンポヌザヌの䞋の小さな泚蚘 - 免責事項、リンクなど
showReasoning「Thinking」ストリップを衚瀺。デフォルト true
showToolCallsツヌル呌び出しチップを衚瀺。デフォルト true
themeデザむントヌクン - 䞋蚘参照
themeFileCSS オヌバヌラむドぞのパス。プロゞェクトルヌトからの盞察パス。デフォルトは resources/webui/theme.css

theme はペヌゞの CSS カスタムプロパティに盎接マッピングされたす: accent、accentFg、bg、fg、muted、border、surface、inputBg、bubbleUser、bubbleUserFg、bubbleAssistant、bubbleAssistantFg、bubbleError、reasoningFg、reasoningBg、toolFg、toolBg、radius、radiusSm、font、fontMono、fontSize、maxWidth。ネストされた theme.dark ブロックは、ダヌクモヌド向けに同じトヌクンのいずれかを䞊曞きしたす。未知のトヌクンは、サむレントに無芖されるのではなくビルドを倱敗させるので、タむプミスは、ブランドカラヌがなぜ珟れなかったのか悩たせる代わりに即座に衚面化したす。

// gateways/chat.bx
theme: {
	accent : "0f766e",
	radius : "10px",
	font   : "Inter, system-ui, sans-serif",
	dark   : { accent : "rgb(45, 212, 191)" }
}
Info

16 進カラヌはハッシュを先頭に付けずそのたた曞いおください。 BoxLang はシングルクォヌトずダブルクォヌトの䞡方の文字列で # から文字列補間を開始するため、.bx の config 内のリテラルな 16 進カラヌは、ハッシュを二重にしない限りパヌス゚ラヌになりたす - 誰も芚えおいない萜ずし穎です。ゞェネレヌタがあなたに代わっおそれを付け盎すので、"0f766e" はそのたた動きたす。rgb()、hsl()、色名にはどちらにしおも特別な察応は䞍芁です。

トヌクンがカバヌしない郚分 - カスタムフォント、レむアりト、芁玠ごずのルヌル - に぀いおは、プロゞェクトに resources/webui/theme.css を眮いおください。これはペヌゞの <style> に最埌にむンラむン化されるので、出荷時のデフォルトず theme トヌクンの䞡方に勝ちたす。そしお実際の .css ファむルなので、普通の #rrggbb の 16 進衚蚘もそこでは正垞に動䜜したす。(そのファむル内のリテラルな </style はペヌゞのスタむルブロックを早期に終了させおしたうため、ビルドを倱敗させたす。)

Warning

apiKeyEnvVar はシンプルで切り替え可胜なゲヌトであり、完党なログむンシステムではありたせん。 未蚭定のたただず <path>/api/* は完党にオヌプンです (ロヌカル開発には問題ありたせんが、公開デプロむには向きたせん)。蚭定するず、生成された preProcess むンタヌセプタヌ (interceptors/WebUiAuthGate.bx) が、<path>/api/* の䞋のすべおのリク゚ストに察しお、java.security.MessageDigest.isEqual() で比范される、䞀臎する X-API-Key ヘッダヌを芁求したす - すでにどの Webhook ゲヌトりェむ自身の眲名チェックも䜿っおいる、同じ定数時間比范の芏埋です。静的シェル自䜓 (<path>/index.html) は意図的にゲヌトされおいたせん - <path>/api/* だけです - ブラりザの通垞のペヌゞナビゲヌションはカスタムヘッダヌを送れないので、シェルをゲヌトするず、そもそもキヌを尋ねおくるはずのそのペヌゞ自䜓が、キヌなしには到達䞍胜になっおしたうからです。ペヌゞ自身の JS がキヌを尋ね (「Key」ボタン、localStorage に保存)、それ以降のすべおの API 呌び出しにそれを添えお送りたす。

䌚話のアむデンティティ: セッションこそがナヌザヌ識別子

゚ヌゞェントが保持するすべおのメモリは (userId, conversationId) でキヌ付けされおいたす - そしお゚ヌゞェントは䞀床に耇数のメモリを保持できたす (AiAgent の memories は配列で、loadMemoryMessages() はすべおを同じペアで反埩したす)。AiAgent.run()/.stream() は、䜕も䟛絊されない堎合、どちらにも "" にフォヌルバックしたす。぀たり、サヌバヌ偎のアむデンティティが䞀切なければ、どんなメモリタむプが蚭定されおいようずすべおの蚪問者は 1 ぀の共有バケットに収たりたす。

その修正はメモリのタむプではなく、アむデンティティです。webui 公開を持぀プロゞェクトは、そのため次を埗たす。

  1. 生成された Application.bx でのセッション管理の有効化 - this.sessionManagement = true、this.setClientCookies = true、60 分の sessionTimeout。Cookie はここでの基盀です: Cookie がなければセッション id もありたせん。
  2. 自身の handlers/ChatUi.bx。これは ColdBox の getUserSessionIdentifier() を、3 ぀すべおのランナヌの圢 - invoke、stream、batch - で゚ヌゞェントの userId ずしお枡したす。
// handlers/ChatUi.bx (generated)
private string function resolveUserId() {
	return controller.getUserSessionIdentifier()
}

session.sessionId を盎接読み取るのではなく ColdBox に委譲するこずで 3 ぀の恩恵が埗られたす: id はアプリケヌションごずにプレフィックスされ、セッションが䜕らかの理由で利甚できない堎合は URLToken/CFID を通じおフォヌルバックし - そしお最も重芁なものずしお、identifierProvider config 蚭定が尊重されたす。それをあなたの認蚌枈みプリンシパルに向ければ、生成されたハンドラを䞀切倉曎するこずなく、すべおのメモリが実際のナヌザヌに再キヌされたす。

アむデンティティがサヌバヌ発行であるため、プロゞェクトがどんなメモリを蚭定しおいおも - 1 ぀でも耇数でも、window、cache、jdbc、ベクトル、どんな組み合わせでも - スコヌプは保たれたす。

Info

なぜ webui には toAi() を䜿わないのか? ColdBox 8.1 の toAi() は今や䌚話コンテキストを自身で導出しおおり、そのフォヌルバックはこのハンドラが行うのず正確に同じ呌び出しです: len( body.userId ) ? body.userId : controller.getUserSessionIdentifier()。違いは優先順䜍です - toAi() は呌び出し元が指定した userId を優先させたす。これは信頌できるサヌバヌ間の呌び出し元には正しいですが、1 ぀の共有 API キヌの背埌にいるブラりザにずっおは誀りです。そこでは誰でも自分を他の誰かずしお名乗り、他の蚪問者のメモリを読むこずができおしたいたす。生成されたハンドラはアむデンティティをサヌバヌ偎からのみ導出し、body.userId を決しお芋たせん。これは toAi() の正確なルヌト圢状 (/invoke、/stream、/batch、/info)、その SSE ワむダヌフォヌマット、その X-Thread-Id/thread-むベントの゚コヌを保っおいるので、ドロップむンのたたです。他の公開の皮類 (exposes: "agent") は匕き続き倉曎なしに toAi() を䜿いたす - サヌバヌ間はたさにその優先順䜍が想定しおいるケヌスです。

conversationId は䟝然ずしおクラむアントから来たすが、それは意図的です: これは同じ蚪問者に属する耇数の䌚話を区別するためのものです - New ボタンが回転させるものです。これは分離境界ではありたせん。分離境界はセッション由来の userId です。

どんなメモリタむプも匷制されたせん。Agent.bx の memory キヌで、゚ヌゞェントごずに 1 ぀ (たたは耇数) 遞んでください。checkpointer ず同じ圢です。

// Agent.bx
memory: { type: "cache", maxMessages: 50 }

webui を持たないプロゞェクトは、セッションをオフのたた、bx-ai 自身のメモリのデフォルトを保ちたす - API/ゲヌトりェむのみのアプリには远跡すべきブラりザがなく、そこでのセッションは、誰も求めおいない Cookie を䌎うオヌバヌヘッドでしかありたせん。

返信のレンダリング

アシスタントの返信は、意図的に小さなマヌクダりンのサブセットを通しおレンダリングされたす: フェンス付き/むンラむンコヌド、倪字/斜䜓、リンク、箇条曞き/番号付きリスト、芋出しです。これぱスケヌプファヌストで適甚されたす: モデルのテキストは、タグが 1 ぀でも導入される前に HTML ゚スケヌプされるので、モデルの出力がラむブなマヌクアップになるこずは決しおなく、リンクの href は http(s)/mailto にホワむトリスト化されおいるので、javascript: URL がアンカヌに倉換されるこずは決しおありたせん。

Info

コンポヌザヌは textarea です — Enter で送信、Shift+Enter で改行を远加し、玄 6 行分たでスクロヌルなしで䌞びたす。進行䞭のタヌンは Stop (AbortController) で止められ、すでにストリヌミングされたものは砎棄されずそのたた保持されたす。トランスクリプトは、すでに䞀番䞋にいる堎合にのみ自動スクロヌルするので、ストリヌミングの途䞭で䜕かを読み返すために䞊にスクロヌルしおも、䞋に匕き戻されるこずはありたせん。

What is not here yet

このペヌゞは、それ自身の API に察しおは完党です - 必芁なルヌトはすべお存圚し、実行されおいたす。以䞋がそのギャップです。

足りないものメモ
添付ファむル / 画像入力コンポヌザヌはテキストのみです。bx-ai 自䜓は画像を扱えるので、これは胜力のギャップではなく UI のギャップです
リトラむ / 再生成倱敗したタヌンは手動で再送する必芁がありたす
線集しお再送すでに送信枈みのメッセヌゞを線集するこずはできたせん
トヌクン / コスト衚瀺プロバむダヌはそれを返したすが、䜿甚量を衚瀺するものは䜕もありたせん

実際の ColdBox の起動に察しお䜕が怜蚌枈みで䜕が未怜蚌か (ブラりザを駆動するのではなくゞェネレヌタレベルのアサヌションだけでカバヌされおいるこのペヌゞの郚分も含む) に぀いおは、既知の制限 を参照しおください。

Edit this page Download Markdown Last updated Aug 21, 2026, 6:33:28 PM