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 ãªãŒããŒã䜿ããŸããäž¡æ¹ãšãããã§ã¯å¿
èŠã ããã§ãã
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 /stream | SSE ã¿ãŒã³ (ãã®ããŒãžã䜿ããã®) |
POST /batch | inputs[] é
åãå®è¡ |
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() ãæ¡çšããŠããã®ãšåãå¥çŽãªã®ã§ãäžæ¹åãã«æžãããã¯ã©ã€ã¢ã³ãã¯ããäžæ¹ã«å¯ŸããŠãåäœããŸãã
忢ã¯ãåã«ãã§ãããäžæããã®ã§ã¯ãªã /cancel ãçµç±ããå¿
èŠããããŸãã HTTP ãªã¯ãšã¹ããäžæããŠãããã©ãŠã¶ãèãã®ããããã ãã§ã - ãµãŒããŒã¯ããŒã«ãåŒã³åºããããŒã¯ã³ãæ¶è²»ããªããã¿ãŒã³ã®å®è¡ãç¶ããŸãããã®ããããŒãžã¯ãã¹ãŠã®ã¿ãŒã³ã« threadId ãæ·»ããŠéããäžæããåã«ããã /cancel ã« POST ããagent.cancelRun() ããã®ã©ã³ã®æ¬¡ã®ãã§ãã¯ãã€ã³ãã«ã·ã°ãã«ãéããããã«ããŸãã
/clear ãš /compact ã¯ã©ã¡ããã¹ã³ãŒãã«æ³šææ·±ãã§ãã/clear ã¯ãåŒæ°ãåãããã¹ãŠã®èšªåè
ã®å±¥æŽãæ¶ããŠããŸã AiAgent.clearMemory() ã§ã¯ãªããåã¡ã¢ãªèªèº«ã® clear( userId, conversationId ) ãçµç±ããŸãã/compact ãåãçç±ã§ summarize( config, userId, conversationId ) ãçµç±ããŸããå§çž®ã¯ããã®äŒè©±ã®å€ãã¡ãã»ãŒãžã AI ãæžããèŠçŽã«çœ®ãæããçŽè¿ã®ããã€ãã¯ä¿æããåŒã³åºãå
ã® (userId, conversationId) ãã¢ä»¥å€ã«ã¯äžåè§ŠããŸããã
/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 ã¯ãã©ã®ã¿ã¡åœè£ å¯èœã§ãã
ãªãŒãã³ãª 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"
ããã·ã¥åã§ãããæå·åã§ã¯ãããŸããã æå·åã¯å¯éã§ãããçãŸããããŒã¿ããŒã¹ãã¡ã€ã«ã¯ã»ãŒåžžã«ãããã埩å·ã§ããäœããšäžç·ã«æã¡åºãããŸã - ãã®ããå¯éãªæ¹åŒã¯ã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 ã¯ã»ãã·ã§ã³ãããµãŒããŒåŽã§åãããããªã¯ãšã¹ãããã£ããã¯æ±ºããŠåããããŸãã: äœããæ¿èªããã®ã誰ããšããã®ã¯ããŸãã«åŒã³åºãå
ãèªåèªèº«ã«ã€ããŠäž»åŒµãã¹ãã§ã¯ãªãé¡ã®ããšã§ãã
äžæäžã®ã©ã³ã¯ããããéå§ããã»ãã·ã§ã³ã«å±ããäž¡æ¹ã®ã«ãŒããããã匷å¶ããŸãã 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 / Compact | Clear ã¯ãã®äŒè©±ã空ã«ããŸãã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-sqlite | JDBC ãã©ã€ãã§ããããããªããŠã 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.datasource | ColdBox ã®ããŒã¿ãœãŒã¹å | 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 ãæããŸãã
ããã§ã® 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 ãåå©çšããç¬éã«ã¢ãã«ã®ã³ã³ããã¹ãã«ãŸã 座ã£ããŸãŸãäŒè©±ãèŠããªããªã£ãŠããŸããŸãã
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 | ãã¶ã€ã³ããŒã¯ã³ - äžèšåç § |
themeFile | CSS ãªãŒããŒã©ã€ããžã®ãã¹ããããžã§ã¯ãã«ãŒãããã®çžå¯Ÿãã¹ãããã©ã«ã㯠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)" }
}
16 é²ã«ã©ãŒã¯ããã·ã¥ãå
é ã«ä»ãããã®ãŸãŸæžããŠãã ããã BoxLang ã¯ã·ã³ã°ã«ã¯ã©ãŒããšããã«ã¯ã©ãŒãã®äž¡æ¹ã®æååã§ # ããæååè£éãéå§ããããã.bx ã® config å
ã®ãªãã©ã«ãª 16 é²ã«ã©ãŒã¯ãããã·ã¥ãäºéã«ããªãéãããŒã¹ãšã©ãŒã«ãªããŸã - 誰ãèŠããŠããªãèœãšã穎ã§ãããžã§ãã¬ãŒã¿ãããªãã«ä»£ãã£ãŠãããä»ãçŽãã®ã§ã"0f766e" ã¯ãã®ãŸãŸåããŸããrgb()ãhsl()ãè²åã«ã¯ã©ã¡ãã«ããŠãç¹å¥ãªå¯Ÿå¿ã¯äžèŠã§ãã
ããŒã¯ã³ãã«ããŒããªãéšå - ã«ã¹ã¿ã ãã©ã³ããã¬ã€ã¢ãŠããèŠçŽ ããšã®ã«ãŒã« - ã«ã€ããŠã¯ããããžã§ã¯ãã« resources/webui/theme.css ã眮ããŠãã ãããããã¯ããŒãžã® <style> ã«æåŸã«ã€ã³ã©ã€ã³åãããã®ã§ãåºè·æã®ããã©ã«ããš theme ããŒã¯ã³ã®äž¡æ¹ã«åã¡ãŸãããããŠå®éã® .css ãã¡ã€ã«ãªã®ã§ãæ®éã® #rrggbb ã® 16 é²è¡šèšãããã§ã¯æ£åžžã«åäœããŸãã(ãã®ãã¡ã€ã«å
ã®ãªãã©ã«ãª </style ã¯ããŒãžã®ã¹ã¿ã€ã«ãããã¯ãæ©æã«çµäºãããŠããŸãããããã«ãã倱æãããŸãã)
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 å
¬éãæã€ãããžã§ã¯ãã¯ããã®ããæ¬¡ãåŸãŸãã
- çæããã
Application.bxã§ã®ã»ãã·ã§ã³ç®¡çã®æå¹å -this.sessionManagement = trueãthis.setClientCookies = trueã60 åã®sessionTimeoutãCookie ã¯ããã§ã®åºç€ã§ã: Cookie ããªããã°ã»ãã·ã§ã³ id ããããŸããã - èªèº«ã®
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ããã¯ãã«ãã©ããªçµã¿åããã§ã - ã¹ã³ãŒãã¯ä¿ãããŸãã
ãªã 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 ãã¢ã³ã«ãŒã«å€æãããããšã¯æ±ºããŠãããŸããã
ã³ã³ããŒã¶ãŒã¯ textarea ã§ã â Enter ã§éä¿¡ãShift+Enter ã§æ¹è¡ã远å ããçŽ 6 è¡åãŸã§ã¹ã¯ããŒã«ãªãã§äŒžã³ãŸããé²è¡äžã®ã¿ãŒã³ã¯ Stop (AbortController) ã§æ¢ãããããã§ã«ã¹ããªãŒãã³ã°ããããã®ã¯ç Žæ£ããããã®ãŸãŸä¿æãããŸãããã©ã³ã¹ã¯ãªããã¯ããã§ã«äžçªäžã«ããå Žåã«ã®ã¿èªåã¹ã¯ããŒã«ããã®ã§ãã¹ããªãŒãã³ã°ã®éäžã§äœããèªã¿è¿ãããã«äžã«ã¹ã¯ããŒã«ããŠããäžã«åŒãæ»ãããããšã¯ãããŸããã
What is not here yet
ãã®ããŒãžã¯ãããèªèº«ã® API ã«å¯ŸããŠã¯å®å šã§ã - å¿ èŠãªã«ãŒãã¯ãã¹ãŠååšããå®è¡ãããŠããŸãã以äžããã®ã®ã£ããã§ãã
| è¶³ããªããã® | ã¡ã¢ |
|---|---|
| æ·»ä»ãã¡ã€ã« / ç»åå ¥å | ã³ã³ããŒã¶ãŒã¯ããã¹ãã®ã¿ã§ããbx-ai èªäœã¯ç»åãæ±ããã®ã§ãããã¯èœåã®ã®ã£ããã§ã¯ãªã UI ã®ã®ã£ããã§ã |
| ãªãã©ã€ / åçæ | 倱æããã¿ãŒã³ã¯æåã§åéããå¿ èŠããããŸã |
| ç·šéããŠåé | ãã§ã«éä¿¡æžã¿ã®ã¡ãã»ãŒãžãç·šéããããšã¯ã§ããŸãã |
| ããŒã¯ã³ / ã³ã¹ã衚瀺 | ãããã€ããŒã¯ãããè¿ããŸããã䜿çšéã衚瀺ãããã®ã¯äœããããŸãã |
å®éã® ColdBox ã®èµ·åã«å¯ŸããŠäœãæ€èšŒæžã¿ã§äœãæªæ€èšŒã (ãã©ãŠã¶ãé§åããã®ã§ã¯ãªããžã§ãã¬ãŒã¿ã¬ãã«ã®ã¢ãµãŒã·ã§ã³ã ãã§ã«ããŒãããŠãããã®ããŒãžã®éšåãå«ã) ã«ã€ããŠã¯ãæ¢ç¥ã®å¶é ãåç §ããŠãã ããã