既知の制限
正直なギャップ - 実際に動くアプリに対して証明済みのものと、そうでないもの。
On this page
- テストは mock プロバイダーに対してのみ実行される
- Real ColdBox integration testing
- toAi() の最初のリクエストのレースコンディション
- 3 つの統合チェック - 元々の計画とは別の経路で解決された
- 実際の OS プロセスの CLI テスト - そしてそれが見つけた実際のバグ
- テストフレームワークの構築中に見つかった実際の、根本的なバグ: エージェントが自身のツールを一度も受け取っていなかった
- serve の miniserver 検索は PATH のみ
- スコープ付き BoxLang ランタイムホームは serve / invoke --server には無条件に届くが、インプロセスの動詞には BoxLang のインストールが .env をロードする場合にのみ届く
- new の box install 便宜ステップは自動テストで演習されていない
- chat には本物の TTY が必要
- 修正済み: chat とデフォルト ( --server なし) の invoke は、クラスベースの Agent.bx に対してかつて失敗していた
- box.json の executable インストールのスモークテストはない
- schedules/Scheduler.bx はビルド時に検証されない
- test 動詞の構築中に見つかった実際のバグ: boxlang-miniserver がクラスパスにあると「現在の BoxLang jar」の解決が曖昧になる
- deploy の ssh / docker / digitalocean ターゲットは実際のプロセスによる自動テストで演習されていない
- deploy の ftp / sftp ターゲット: 実際の接続処理は証明済みだが、実際の成功するアップロードは証明されていない
- build は、生成の途中でクラッシュした場合に部分的に書き込まれた .build/app をロールバックしない
- testBx で観測された、間欠的な StackOverflowError (このプロジェクト自身のコードとは無関係)
- Push-style gateways (Telegram) are tested against a mocked API/scheduler seam only - no live platform integration runs in CI
- WhatsApp Personal (非公式の個人アカウントブリッジ) - 調査済み、未構築
- GatewaySession はプロジェクト全体で 1 つ、かつルートエージェント専用 (v1)
- 修正済み: GatewaySessionBootstrap.bx は誤った aiGatewayRegistry() キーでゲートウェイを検索していた (4 つすべての push 型ゲートウェイにわたって壊れた状態で出荷されており、WhatsApp の調査の過程で発見された)
- ./gradlew downloadModules が、 GatewayGenerator の aiGatewayRegistry() コード生成に一時的に遅れた bx-ai のスナップショットを取得することがある
- v1 の Web チャット UI ( exposes: "webui" ) - 実物であることと、ドキュメントに照らしてしか確認できず、ライブなサーバーに対してではなかったこと
- Web UI の SQLite ストア - ライブラリレベルでは検証済み、実際の ColdBox の起動を通してではない
- 実際の HTTP を通した Web UI: 統合ランナーのプローブによって証明されている
- Web UI 自身のフロントエンド: 実際のブラウザで駆動されたが、モック API に対して
æ¢ç¥ã®å¶é
BX Agents ã¯çŸåšã掻çºã«éçºãé²ããããŠããŸãããã®ããŒãžã¯ãæ£çŽãªã®ã£ãã - å®éã«åãã¢ããªã«å¯ŸããŠæ€èšŒæžã¿ã®éšåãbx-ai ã® "mock" ãããã€ããŒã«å¯ŸããŠãããŸã å®è¡ãããŠããªãéšåããããŠãã®ãããžã§ã¯ããééããå®éã® upstream ã®ç - ãèšé²ããŠããŸãã
ãã¹ã㯠mock ãããã€ããŒã«å¯ŸããŠã®ã¿å®è¡ããã
ãã¹ãŠã®é«éã¬ãŒã³ã®ã¹ãã㯠(ãã«ããã€ãã©ã€ã³ããžã§ãã¬ãŒã¿ãCLI åè©) ãš ColdBox çµ±åã¹ã€ãŒã ã¯ãbx-ai ã«çµã¿èŸŒãŸãã "mock" ãããã€ããŒãæŒç¿ããŸã - LLM ãžã®å®éã®ãããã¯ãŒã¯åŒã³åºãã¯æ±ºããŠè¡ããŸãããããã¯æå³çã§ã (é«éã§ãç¡æã§ã決å®ç㪠CI)ãããããããã¯å®éã®ãããã€ã㌠(OpenAIãAnthropic ãªã©) ãå®éã«ãšã³ãããŒãšã³ãã§æ£ããã©ãŠã³ãããªããããããšã蚌æããèªåãã¹ããçŸæç¹ã§ã¯ååšããªãããšãæå³ããŸããæ¬çªã§ããã«äŸåããåã«ãå®éã®ãããã€ããŒãšäœ¿ãæšãŠã® API ããŒã«å¯ŸããŠãå°ãªããšãäžåºŠã¯æåã§ chat/serve ãå®è¡ããŠãã ããã
Real ColdBox integration testing
./gradlew testColdBoxIntegration ã¯ãçæãããã¢ããªèªèº«ã® Application.bx/Bootstrap ã«å¯ŸããŠå®éã® boxlang-miniserver ããã»ã¹ãèµ·åããtoAi() ç»é²æžã¿ã«ãŒããéããŠæ¬ç©ã® HTTP ãªã¯ãšã¹ããè¡ããŸããããã¯ã¹ã€ãŒãã®äžã§æã匷åãªèšŒæãã€ã³ãã§ãããéçºäžã« ColdBoxAppGenerator.bx ã® 3 ã€ã®å®éã®ãã° (WireBox ã® Binder ã® extends ã®æ¬ èœãBootstrap ã³ã³ã¹ãã©ã¯ã¿ã®åŒæ°é åºã®èª€ããBinder ã«ååšããªãçŽ ã® getInstance() åŒã³åºã) ãæãŸããŸããã
toAi() ã®æåã®ãªã¯ãšã¹ãã®ã¬ãŒã¹ã³ã³ãã£ã·ã§ã³
æ°ããèµ·åããã¢ããªã® toAi() ã«ãŒããžã®æ¬åœã«æåã®HTTP ãªã¯ãšã¹ãã¯ããFunction [getInstance] not foundããšããäžæçãªå€±æãããããšããããŸã - ããã¯ãRouter èªèº«ã® getInstance ããªã²ãŒãäžã§ã®ãæ¬ç©ã® ColdBox/WireBox ã®é
延泚å
¥ã®ã¬ãŒã¹ã³ã³ãã£ã·ã§ã³ã§ãããBX Agents ã®ãã°ã§ã¯ãããŸãããä»ã®äœã (ãã«ã¹ãã§ãã¯ãchat ã»ãã·ã§ã³ãå¥ã®ã«ãŒã) ããã§ã« GeneratedAgent ã·ã³ã°ã«ãã³ãäžåºŠæ§ç¯ãããã WireBox ã«åŒ·å¶ããåŸã®ããã以éã®ãã¹ãŠã®ãªã¯ãšã¹ãã§ã¯ç¢ºå®ã«æåããŸããè² è·ã®ãããç¶æ³ã§æ°ãããããã€ããã toAi() ã«ãŒãã«äŸåããåã«ããŠã©ãŒã ã¢ãããªã¯ãšã¹ããéã£ãŠãã ããã
3 ã€ã®çµ±åãã§ã㯠- å ã ã®èšç»ãšã¯å¥ã®çµè·¯ã§è§£æ±ºããã
tests/specs/integration/RuntimeStartupSmokeSpec.bx ã«ã¯äŸç¶ãšã㊠3 ã€ã® xit() ãæ®ã£ãŠããŸãããã®ãã¡ã€ã«ã¯ CLI ã©ã³ã㌠(runTests.bxs/testBx) çµç±ã§å®è¡ãããBoxLang ã® CLI ã¢ãŒã㯠cgi ã¹ã³ãŒããäžåäžããªãããã§ã - ããã¯ãèµ·åæã«ã«ãŒã¿ãŒãããŒãããããã ãã§ã ColdBox ã® RoutingService ãå¿
èŠãšãããã®ã§ããããã¯æ§é çãªäºå®ã§ãããã®ã£ããã§ã¯ãããŸããããã® 3 ã€ã®ãã§ãã¯ã¯ãã¹ãŠãå®éã«ã¯å¥ã®å Žæã§æ¬ç©ãšããŠèšŒæãããŠããŸããtests/specs/integration/coldbox/ColdBoxRuntimeSpec.bx (å®éã® boxlang-miniserver ããã»ã¹ã«ãã£ãŠé
ä¿¡ããããæ¬ç©ã® HTTP ãªã¯ãšã¹ãã®å
éšã§å®è¡ãããŸã) ã§ã:
- å®éã® ColdBox ã§ã«ãŒãã£ã³ã°ããã HTTP ãªã¯ãšã¹ãããçæããããšãŒãžã§ã³ãã«ãšã³ãããŒãšã³ãã§å°éããããš -
ColdBoxRuntimeSpec.bxãšrunColdBoxIntegrationTests.bxsèªèº«ã®POST /api/chat/invokeã¢ãµãŒã·ã§ã³ã«ãã£ãŠèšŒæãããŠããŸãã schedules/*ãå®éã«ã©ã€ã㪠ColdBoxSchedulerã«ç»é²ãããããš -SchedulerService.getSchedulers()["appScheduler@coldbox"].hasTask(...)ããå®éã® cron çºç«ãåŸ ã€ããšãªã (ãµããŒããããæãç²ãç²åºŠã¯ 1 åã§ãããã¿ã¹ã¯ããã§ã«ã©ã€ãã§ç»é²æžã¿ã§ããããšã確èªãããåŸã«ããããªè¿œå ã®èšŒæã®ããã«æ¯åã® CI å®è¡ã«è² è·ããããããšã«ãªããŸã)ãå®éã®èµ·åã«å¯ŸããŠèšŒæããŠããŸããchatãšserveããã HTTP ã«ãŒããæ±ºããŠé£ãéããªãããš - å ã ã®æžãæ¹ (chatã¯èšèšäžãWireBox ãäžåèµ·åããªãã®ã§ãWireBox ã®ã·ã³ã°ã«ãã³ãªããžã§ã¯ããå ±æããããšã¯æ±ºããŠã§ããŸãã) ãããå®éã«éèŠãªããšãžãšä¿®æ£ãããŸãã: WireBox ã®å€åŽã§GeneratedAgentFactoryãã€ã³ã¹ã¿ã³ã¹åãããšãWireBox èªèº«ã®ã·ã³ã°ã«ãã³ãšæ¯ãèãçã«ç䟡ãªãšãŒãžã§ã³ããçæãããããšããããšã§ãã
å®éã® OS ããã»ã¹ã® CLI ãã¹ã - ãããŠãããèŠã€ããå®éã®ãã°
ModuleCliProcessTest.java ã¯ãå®éã«ã€ã³ã¹ããŒã«å¯èœãªã¢ãžã¥ãŒã«æ§é (build/modules/bxagents) ã®ã³ããŒã«å¯ŸããŠãå®éã® modulesDirectory ãæã圢ã§ãæ¬ç©ã® java -jar <boxlang-jar> module:bxagents <verb> ... åããã»ã¹ãèµ·åããŸã - å®éã® BoxLang ã€ã³ã¹ããŒã«ããã®ã¢ãžã¥ãŒã«ãããŒãããã®ãšãŸãã«åãæ¹æ³ã§ããä»ã®ãã¹ãŠã® CLI ã¹ããã¯ã¯ä»£ããã« ModuleConfig.main()/ååè©ã® run() ãã€ã³ããã»ã¹ã§åŒã³åºããŠãããããã¯ããé«éã§ãããå®éã«ã€ã³ã¹ããŒã«ãããåŸã«æ¬åœã«ã¢ãžã¥ãŒã«ã解決ãããããšãäžå蚌æããŸããã
ãã®ã®ã£ããã¯å®éã®ãã®ã§ãã: ãã®ãã¹ãã¯ãå®éã«ã€ã³ã¹ããŒã«ãããã¢ãžã¥ãŒã«ããã»ã¹ãéããŠå®è¡ãããç¬éã«ããã¹ãŠã® CLI åè©ããclass not locatedãã§å€±æããããšãæãŸããŸãããå
éšã®çžäºåç
§ãããã®ãªããžããªèªèº«ã®éçº/ãã¹ãçš boxlang.json (æã§å®£èšããã /bxagents ãããã³ã°) ã®ãããã§ã®ã¿è§£æ±ºããããçŽ ã® bxagents.models.... ãšãããããåºåãã®ãã¹ã䜿ã£ãŠããããã§ã - å®éã«ã€ã³ã¹ããŒã«ãããã¢ãžã¥ãŒã«ã¯ããã®ãããã³ã°ã決ããŠåŸãããŸããããã¹ãŠã®ãã¹ããããã¯ã©ã¹ã®å
éšåç
§ããClass@bxagents ãšããã¢ãžã¥ãŒã«çžå¯Ÿã®ãµãã£ãã¯ã¹åœ¢åŒã«åãæ¿ããããšã§ä¿®æ£ãããŸãã (ModuleConfig.bx èªäœã¯ãã¢ãžã¥ãŒã«ã®ã«ãŒãã«åº§ã£ãŠããããã¬ãŒã³ãªçžå¯Ÿãã¹ãåé¡ãªã解決ããã®ã§ã倿Žã¯äžèŠã§ãã) - å®å
šãªèª¬æã¯ BuildPipeline.bx ã® init() ã® docblock ãåç
§ããŠãã ãããbuild.gradle ã®ã¢ãžã¥ãŒã«æ§é ã®åºåå
㯠build/module ãã build/modules/bxagents ã«ç§»åããŸãã (modulesDirectory ã®çºèŠããããèŠã€ããããã«ã¯ããã©ã«ãåãã¢ãžã¥ãŒã«åãšäžèŽããå¿
èŠããããŸã)ãéçº/ãã¹ãçšã® boxlang.json ãä»ããããå®éã®ã¢ãžã¥ãŒã«ãšããŠããŒãããã®ã§ãæ¢åã®ã¹ã€ãŒãå
šäœã¯ãåãªã䟿å®çãªãããã³ã°ã§ã¯ãªããæ¬çªãšåã解決ãã¹ãæŒç¿ããŸãã
ãã¹ããã¬ãŒã ã¯ãŒã¯ã®æ§ç¯äžã«èŠã€ãã£ãå®éã®ãæ ¹æ¬çãªãã°: ãšãŒãžã§ã³ããèªèº«ã®ããŒã«ãäžåºŠãåãåã£ãŠããªãã£ã
BaseAgentSpec ã® toHaveCalledTool ãããã£ãŒ (M15) ã®æ§ç¯äžã«ãæ·±å»ãªããããŸã§çºèŠãããŠããªãã£ããã°ã衚é¢åããŸãã: ColdBoxAppGenerator ãçæãã aiAgent() åŒã³åºãã«ã¯ãtools: åŒæ°ããŸã£ããæž¡ãããŠããŸããã§ãã (å®éã® bx-ai ãœãŒã¹ã«ç
§ãããŠç¢ºèªæžã¿ã§ã - AiAgent.bx ã¯å
éšã§ aiToolRegistry() ãäžååç
§ããŸãã)ããããžã§ã¯ãã® tools/ ã¯ãã«ãã«ã³ããŒãããMCP é
ç·ã®ããã«åå解決å¯èœã«ã¯ãªã£ãŠããŸããããBX Agents ããããŸã§ã«ãã«ãããã©ã®ãšãŒãžã§ã³ãã - å®éã«é
ä¿¡ãããã¢ããªãchatããã¹ãã¹ããã¯ã®ã©ã®ã³ã³ããã¹ãã§ãã£ãŠã - èªèº«ã®å®£èšãããããŒã«ãå®éã«ã¯äžåºŠãåãåã£ãŠããŸããã§ããã ããã¯ãæ¢åã®ã©ã®ãã¹ããå®éã®ããŒã«åŒã³åºããã¢ãµãŒãããããšããªãã空ã§ãªãå¿çã ããã¢ãµãŒãããŠãããããæ€åºãããã«ããŸããã
ColdBoxAppGenerator.renderAgentFactory() ã§ä¿®æ£ãããŸãã: çæããããã¹ãŠã® GeneratedAgentFactory.bx ã¯ãæ°ãã ToolRegistryLoader.bx ãçµç±ããŠèªèº«ã® tools/ ãã£ã¬ã¯ããªãããŒãããããã«ãªããŸãã (çææã«åã蟌ãŸãã絶察ãã¹ã䜿ããããŒããããã³ã³ããã¹ãã§æå¹ãªã/ããããã³ã°ãäœãã«äŸåããçžå¯Ÿãã¹ã¯äœ¿ããŸãã - aiToolRegistry().scan("tools") èªèº«ã®çžå¯Ÿãã¹è§£æ±ºããchat ã®ãã㪠DynamicClassLoader ã«ãã£ãŠããŒããããã³ã³ããã¹ãããåŒã³åºãããéã«ãµã€ã¬ã³ãã«å€±æããããšã確èªããŸãã)ããã®åŸããã¹ãŠã® aiAgent() åŒã³åºãã« tools: aiToolRegistry().getAll() ãæž¡ããŸãã
3 ã€ç®ã®ãããã¬ãã«ã¹ã¯ãªããã®èœãšã穎ããCI ã§èŠåŽããŠèŠã€ãããŸãã: var 㯠.bxs ã¹ã¯ãªããã®ãããã¬ãã«ã§ã¯äœ¿çšã§ããŸããã var 㯠local ã¹ã³ãŒãã«å®£èšããŸãããããã¯é¢æ°ã®å
éšã«ããååšããªãããããããã¬ãã«ã® var x = ... ã¯å®è¡æã« Scope [local] is not available in this context ãæããŸã - ããŒã¹æã§ã¯ãªãã®ã§ãã¬ãã¥ãŒãçãå»¶ã³ãããã«å°éããã³ãŒããã¹ã§ã®ã¿çºç«ããŸãããã㯠runColdBoxIntegrationTests.bxs ã§ 1 ååã® CI ãµã€ã¯ã«ãæ¶è²»ããŸãããåé¡ã®è¡ã¯å€±æèšºæçšã®åå²ã®å
éšã«ãã£ããããä»ã®äœãããã§ã«ãããããªã£ãããŸãã«ãã®ãšãã«ã¯ã©ãã·ã¥ããæ¬åœã®å€±æãèªåèªèº«ã®ãã®ã§çœ®ãæããŠããŸããŸããã2 ã€ã®ã«ãŒã«ãããããå°ãããŸã: .bxs ã®é¢æ°ã®å€ã§ var ãæžããªãããšããããŠèšºæåºåãèªèº«ã® try/catch ã§å
ã¿ãããã説æããããšããŠãã倱æãé ããªãããã«ããããšã§ãã
ããã©ã«ãããŒã¿ãœãŒã¹ã®ããã® Application èšå®ã¯ this.datasource ã§ãããthis.defaultDatasource ã§ã¯ãããŸãããè€æ°åœ¢ã®ç»é²ããŒã¯æ¬åœã« this.datasources[ "name" ] = { ... } ã§ãããããthis.defaultDatasource ã¯èª°ããæã䌞ã°ããŠããŸãååã§ã - ãã㊠BoxLang ã¯ããããµã€ã¬ã³ãã«åãå
¥ããäœãããŸãããå®éã«ã©ã³ã¿ã€ã ã«å¯ŸããŠçŽæ¥æ€èšŒããããã®ã§ãæšæž¬ã§ã¯ãããŸãã: this.defaultDatasource = "testds" ãèšå®ããç¶æ
ã§ã修食åãªãã® queryExecute() ã¯äŸç¶ãšã㊠No default datasource defined in the application or globally or in the query options. Registered datasources are: [testds] ã§å€±æããŸãã1 è¡ã this.datasource = "testds" ã«å€ãããšãããŒã¿ãœãŒã¹ã解決ãããåŒã³åºãã¯å®éã®ãã©ã€ãã®é¢å¿äºã«é²ã¿ãŸããæžããèšå®ãç¡èŠãããããšã«ã€ããŠã®èŠåããã³ãããšã©ãŒã®äžã«ã¯ãªããã¡ãã»ãŒãžã¯éžæããããšããŠããç»é²æžã¿ããŒã¿ãœãŒã¹ã®ååãæããŠããã®ã§ãéžæã¡ã«ããºã ãã®ãã®ãå£ããŠããããã«èªããŠããŸããŸãã
qb ã® moduleSettings.qb.defaultOptions ã¯ãå®éã® ColdBox ã®èµ·åã§ã¯ QueryBuilder ã«å±ããŠããŸããã§ããã çæããã config/ColdBox.bx 㯠moduleSettings.qb.defaultOptions = { datasource : "<name>" } ãèšå®ããqb èªèº«ã® ModuleConfig.cfc 㯠onLoad() ã®å
éšã§ .initArg( name = "defaultOptions", value = settings.defaultOptions ) ã«ãã£ãŠ QueryBuilder@qb ããããã³ã°ããŸã - ããã¯æ£ããèªããŸãããçæããã ChatDb.query() ãå
ã
ããŒã¿ãœãŒã¹ãäžåæå®ããŠããªãã£ãçç±ã§ããããŸããããã¯æ©èœããŸããã§ãã: ãã¹ãŠã®ã¯ãšãªã No default datasource defined in the application or globally or in the query options. Registered datasources are: [<name>] ã§å€±æããŸãããã€ãŸãããŒã¿ãœãŒã¹ã¯ç»é²æžã¿ã ã£ãã®ã«ããã«ããŒã¯ç©ºã® options ãæã£ããŸãŸã§ããããã®ã¢ãžã¥ãŒã«èšå®ããªãå±ããªãã£ãã®ãã¯åŸ¹åºè¿œæ±ãããŸããã§ãã - ãããã©ãã§ããããªã£ãã®ã¯ããã®ãã©ãã³ã°ã«äŸåããããããæç€ºçã«ããŒã¿ãœãŒã¹ãæå®ããã»ããè¯ãããã§ããChatDb.query() ã¯ä»ãããã¹ãŠã®ãã«ããŒã«å¯Ÿã㊠.mergeDefaultOptions( { datasource : static.DATASOURCE } ) ãåŒã³åºããŸããSchemaBuilder ã«å¯Ÿã㊠schemaOptions() ããã§ã«è¡ããªããã°ãªããªãã£ãããšãåæ ããŠããŸã (qb 㯠SchemaBuilder ã« defaultOptions ãäžåæž¡ããŸãã)ãçæãããã³ãŒãã«æ°ãã qb ã®åŒã³åºããã¹ã远å ããå Žåã¯ãããã«ããŒã¿ãœãŒã¹ãæå®ããŠãã ãããã¢ãžã¥ãŒã«èšå®ãããªããã«ããŒããŠããããšæ³å®ããªãã§ãã ããã
çæãããã¢ããªã¯ä»ã this.datasources ã ãã§ãªããthis.defaultDatasource ã宣èšããŸãã ããŒã¿ãœãŒã¹ã 1 ã€ãããªãå Žåãååãæå®ããã«ã¯ãšãªãå®è¡ãããã® - ColdBox èªäœãå¥ã®ã¢ãžã¥ãŒã«ããããžã§ã¯ãèªèº«ã®ã³ãŒã - ã¯ã倱æããã®ã§ã¯ãªãããã«å°éããã¹ãã§ãã以åã¯çæãããããŒã¿ãœãŒã¹ãããã¯ã«å¯ŸããŠäœãã¢ãµãŒããããŠãããããããããã©ã«ããªãã§åºè·ãããçç±ã§ããColdBoxAppGeneratorSpec ã¯ä»ããWeb UI ããã®ã±ãŒã¹ãš Web UI ãªãã®ã±ãŒã¹ (ã©ã¡ãã®è¡ãçŸããªãã¹ãã±ãŒã¹) ã®äž¡æ¹ãã«ããŒããŠããŸãã
çæããã models/ChatDb.bx ã¯ã³ã³ãã€ã«ã§ãããã©ã®ãŠãããã¹ããã¯ãããã«æ°ã¥ããŸããã§ããã WebUiGenerator ã¯ãBoxLang ã®æååãªãã©ã«ãã BoxLang ãœãŒã¹ãçµã¿ç«ãŠãŸãããªãã©ã«ãªããã«ã¯ã©ãŒãã¯äºéåãããã¯ã©ãŒããšããŠæžãããã®ã§ã空æååãªãã©ã«ã«ã¯ 4 ã€ã®ã¯ã©ãŒãæåãå¿
èŠã§ãèªç¶ã«èŠãã 2 ã€ãæžããšãè¡ã®æ®ãã飲ã¿èŸŒãã§ããŸã 1 ã€ã®äœåãªã¯ã©ãŒããéããŠããŸããŸãã空æååãžã® elvis æŒç®å (?: "") ãéã¶ 2 è¡ã®ãã³ãã¬ãŒãã ?: " ãåºåããŠããŸããçæããããã¹ãŠã® Web UI ãããžã§ã¯ãããããŒã¹ã«å€±æãã ChatDb.bx ãåºè·ããŠããŸããããã¹ãŠã® WebUiGeneratorSpec ã®ã±ãŒã¹ã¯çæãããããã¹ãã®éšåæååãã¢ãµãŒãããŠãããããã¯ãã¹ãŠäŸç¶ãšããŠäžèŽããŠããŸãããå®éã® ColdBox ã®èµ·åã ãããããã³ã³ãã€ã«ããããšããŠããããã®ãã¹èªäœãäžèšã®ããŒãã¹ãã°ã«ãã£ãŠäœãµã€ã¯ã«ãå£ããŠãããããå®éã®ãã°ã¯ãããã®èåŸã«é ãããŸãŸã§ãããçæããããœãŒã¹ã®ãã¹ãŠã®è¡ãããã«ã¯ã©ãŒããå¶æ°åæã€ããšãã¢ãµãŒããã WebUiGeneratorSpec ã®ã±ãŒã¹ãä»ãååšããŸã - ããã¯ãããŸããŸééã£ãŠãã 2 è¡ã ãã§ãªãããã®ã¯ã©ã¹å
šäœãæãŸããäžå€æ¡ä»¶ã§ããããããã®ããåºãæèš: èªèº«ã®åºåã«å¯ŸããŠã°ã¬ããããã ãã®ãžã§ãã¬ãŒã¿ã¹ããã¯ã¯ãåºåãæå¹ãªã³ãŒãã§ããããšããã¹ãããŠããŸããã
GET /chat/api/health ã¯ãããã蚌æããŠããããã«èŠããããããã£ãšå°ãªãããšãã蚌æããŠããŸããã çæããã health() ã¢ã¯ã·ã§ã³ã¯ãªãã©ã«ãª { status: "ok", success: true } ãã¬ã³ããªã³ã°ãããã以å€ã«ã¯äœã«ãè§ŠããŸãã - ã€ãŸã 200 㯠ColdBox ãèµ·åããã«ãŒãã£ã³ã°ãçæããã ChatUi ãã³ãã©ã«å°éããããšã蚌æããã ãã§ãWireBoxãChatDbãSQLite ã«ã€ããŠã¯äœãèªããŸãããrunColdBoxIntegrationTests.bxs ã®ã³ã¡ã³ãã¯ãã€ãŠãColdBox routing -> ChatUi -> WireBox -> ChatDbããæŒç¿ããŠãããšäž»åŒµããŠããŸããããããã¯èª€ãã§ãããå®éã«èª€ã£ãå®å¿æãäžããŠããŸãã: ãã CI å®è¡ã§ã¯ãmodels/ChatDb.bx ããŸã£ããã³ã³ãã€ã«ã§ããªãç¶æ
ã®ãŸãŸãã°ãªãŒã³ãªãããŒããè¿ã£ãŠããŸããããã®å Žã§ä¿®æ£ãããŸãããã¹ãã¢ã®ã«ãã¬ããžãšããŠæ±ãã¹ãã¯ããããŒãã§ã¯ãªãçµ±åã¹ããã¯ã§ãã
TestBox ã® JSONReporter ã¯ãã©ã€ããªãã¬ãŒã ã¯ãŒã¯ã®ã·ã³ã°ã«ãã³ã«è§Šããã¹ããã¯ã«ã€ããŠã¯å ±åã§ããŸããã ColdBox ã®çµ±åã¹ããã¯ã¯å®éã® controller/WireBox/qb ãªããžã§ã¯ãã解決ãããããã®ãªããžã§ã¯ãåç
§ã TestBox ã®çµæã¡ã¡ã³ãã«æ®ããŸããJSONReporter ã¯ãã®ã¡ã¡ã³ãããŸãããšã·ãªã¢ã©ã€ãºãããããBoxLang ã¯ã©ã€ããªãªããžã§ã¯ãã«å¯ŸããŠãªãã¬ã¯ã·ã§ã³ãè¡ã (StructUtil.objectToStruct -> DynamicInteropService.getMethodNames)ããããã®åŸªç°åç
§ã JVM ã StackOverflowError ãæãããŸã§ãã©ã£ãŠããŸããŸãããããçºç«ããæã«ã¯ãã§ã«ã¹ããã¯èªäœã¯ã°ãªãŒã³ã§å®è¡ãçµããŠããŠããŸãã«ãããæ··ä¹±ãæããŸãã: åæ Œããã¹ã€ãŒãã倱æããå®è¡ãšããŠå ±åãããã®ã§ãããã®ãã tests/runner-coldbox.bxm ã¯èªèº«ã®ã¬ããŒããçµã¿ç«ãŠãŸãããã¹ãŠã®å€ã toScalar() ãã«ããŒã«éããŠãªããžã§ã¯ããã·ãªã¢ã©ã€ã¶ã«äžåå±ããªãããã«ããã¬ããŒããæ§ç¯ãããåã«é²æããŒã«ãŒã«åæ Œ/倱æã®ã«ãŠã³ããèšé²ããŸã - ãã®ãããã·ãªã¢ã©ã€ãºã®å€±æãäºåºŠãšãã¹ãã®å€±æãšèª€èªãããããšã¯ãããŸããã
BoxLang ã® time ãã¹ã¯ã§ã¯ãnn ã¯åã§ã¯ãªã NANOSECONDS (ããç§) ã§ã - mm ã䜿ã£ãŠãã ããã dateTimeFormat( now(), "HH:nn:ss" ) 㯠02:777491298:32 ã®ãããªã¿ã€ã ã¹ã¿ã³ãããµã€ã¬ã³ãã«çæãã誀ã£ãæžåŒã§ã¯ãªãç Žæããåºåã®ããã«èªããŸãã(éã®èœãšã穎ã date ãã¹ã¯ã«ãããããšã«æ³šæããŠãã ãããããã§ã¯ mm ãæã§ã: yyyy-mm-dd ã¯æ¥ã§ã¯ãªãåãçæããŸãã)
ãµãŒããŒåŽã§ã¢ã€ãã³ãã£ãã£ãå°åºããããšã¯ãããã«å¯ŸããŠèªå¯ããããšãšåãã§ã¯ãããŸããã çæããã handlers/ChatUi.bx ã¯ããã¹ãŠã®ã¢ã¯ã·ã§ã³ã§ãªã¯ãšã¹ãããã£ããã§ã¯ãªãã»ãã·ã§ã³ãã userId ãå°åºããããšã«æ°ãé
ã£ãŠããŸããããããã§ã 2 ã€ã®ã¢ã¯ã·ã§ã³ã«ã¯èªå¯ã®ç©ŽããããŸãããåŒã³åºãå
ã§ã¯ãªã threadId ã«ãã£ãŠã¢ãã¬ã¹ãããŠããããã§ãã/pending ãš /resume 㯠id ã«ãã£ãŠãã§ãã¯ãã€ã³ããããŒãããããã«å¯ŸããŠåäœããŠããŸããã/resume ã¯ã»ãã·ã§ã³ãã decidedBy ãå°åºããããŠããŸããããããã¯ã¹ã³ãŒããã§ãã¯ã®ããã«èªããäžæ¹ã§ãå®éã«çµ±å¶ããŠããã®ã¯æ±ºå®ã«ä»ããããã©ãã«ã ãã§ãããã©ã®ã©ã³ã決å®ãããããšããŠãããã§ã¯ãããŸããã§ãããä»äººã® threadId ãæã€èšªåè
ã¯ããã®ä¿çäžã®ããŒã«åŒã³åºããèªã¿ã代ããã«æ¿èªã»æåŠã§ããŠããŸããŸããäž¡æ¹ãšãä»ããåŒã³åºãå
ãããšãŒãžã§ã³ããã©ã³ options ã«ãã§ãã¯ãã€ã³ããã userId ãšæ¯èŒããŸãããããèŠããŠãã䟡å€ã®ããäžè¬çãªã«ãŒã«ã§ã: ããã«ãŒããåŒã³åºãå
ã§ã¯ãªãäžéæãª id ã§ããŒä»ããããŠããå ŽåããµãŒããŒåŽã§ã¢ã€ãã³ãã£ãã£ãå°åºããããšã¯å±æ§ã®èšé²ã«ã¯ãªããŸãããã¢ã¯ã»ã¹å¶åŸ¡ã«ã¯ãªããŸãã - ãã® 2 ã€ã¯å¥ã
ã«èããå¿
èŠããããåã颿°å
ã«ãµãŒããŒç±æ¥ã®å€ã座ã£ãŠãããšãäž¡æ¹ãå
ŒããŠãããšç°¡åã«èª€èªãããŠããŸããŸãã
ProjectValidator ã®ãã¹ãã§ãã¯ã¯ãå
é ã®ã»ãã¬ãŒã¿ã ãã§ãªã .. ãèæ
®ããå¿
èŠããããŸãã database.path ã¯ãçæããã Application.bx ã®äžã§ expandPath() åŒã³åºãã«ãã®ãŸãŸå·®ã蟌ãŸããããã絶察ãã¹ã§ãããã©ããããã§ãã¯ãããŠããŸããã - ../../var/lib/chat.db ã¯ããã®ãã§ãã¯ããããã«ééããªããããŸã£ããåãããã«ã¢ããªãã£ã¬ã¯ããªãè±åºããŸããä»ã§ã¯äž¡æ¹ã®ã»ãã¬ãŒã¿ã«ã€ããŠæåŠããã..hidden ã a..b ã®ãããªæ£åœãªååã¯äŸç¶ãšããŠééããããããã¹ã»ã°ã¡ã³ãå
šäœãããããããŠããŸããçæããããã¹ãå®ãå°æ¥ã®ã©ã®ããªããŒã¿ãããã®äž¡æ¹ã®ååããã§ãã¯ããå¿
èŠããããŸãã
ãã¹ãã¹ã€ãŒããããŒã«ã«ã§å®è¡ããã«ã¯ãCI ãšãŸã£ããåãããã« bx-ai ããœãŒã¹ãããªãŒããŒã¬ã€ããå¿
èŠããããŸãã ./gradlew downloadModules ã¯å
¬éæžã¿ã® bx-ai ã¹ãããã·ã§ãããååŸããŸãããããã¯èªèº«ã® development ãã©ã³ãã«é
ããŠããŸã - ããã¯ãã³ããªã³ã°ãããã³ã㌠(src/test/resources/modules/bxai ã®äž) ãäžæžããããã®åŸã¹ã€ãŒã㯠Method 'isRunning' not found ãš The method aiGatewayRegistry does not exist ãšãã 2 ã€ã®ãupstream ã«ã¯ååšãããå
¬éãã«ãã«ã¯ååšããªã API ã«é¢ãããšã©ãŒã§ãçŽ 40 åã®ã¹ããã¯ã§å€±æããŸããããã¯åŸéã§ã¯ãªããåŸéã ãšèª€è§£ãããããã®ã§ããtestBx ãå®è¡ããåã«ããªãã«ãããŠãªãŒããŒã¬ã€ããŠãã ãã: ( cd <bx-ai checkout> && ./gradlew createModuleStructure ) ã®åŸ cp -R <bx-ai>/build/module/. src/test/resources/modules/bxai/ãtests/coldbox/ãtests/testbox/ãtests/qb/ 㯠(tests/ ã§å®è¡ãã) box install ããæ¥ãŠããããã® 3 ã€ã¯ãã¹ãŠ gitignore ãããŠããŸãã
chr() 㯠BoxLang ã«ã¯ååšããŸãã - ãã® BIF 㯠char() ã§ãã ããã¯ã³ã³ããã¹ãäŸåã§ã¯ãããŸããã以å㯠ModuleConfig.bx ã®ã³ã¡ã³ããããã®ã¢ãžã¥ãŒã« CLI å®è¡ã³ã³ããã¹ãã§ã®ã¿ãå©çšã§ããªããšäž»åŒµããŠããŸããã (çŸåšã¯ä¿®æ£æžã¿ã§ã)ãå®éã«ã©ã³ã¿ã€ã ã«å¯ŸããŠçŽæ¥æ€èšŒãããŠããŸã: char( 10 ) ã¯æ¹è¡ãè¿ããŸãããchr( 10 ) ã¯ãã¬ãŒã³ãª CLI ã¹ã¯ãªããã§ããé
ä¿¡ããããã³ãã¬ãŒãå
ã§ãåãããã« Function [chr] not found ãæããŸãããããç¥ã£ãŠãã䟡å€ãããã®ã¯ããã®å€±æãã©ã³ã¿ã€ã ã®ãã®ã ããã§ã - chr() ã¯ããŒã¹ã¯éããã¬ãã¥ãŒãçãå»¶ã³ãããã«å°éããæåã®ã³ãŒããã¹ã§æããããŸããããã¯ããã§äœåãã® CI ãµã€ã¯ã«ãæ¶è²»ããŸãã: tests/runner-coldbox.bxm ã¯ãã®æåã®é²æããŒã«ãŒã§ chr( 10 ) ãåŒã³åºããŠããããããã¹ãŠã®ãªã¯ãšã¹ãããšã³ããªã§ 500 ãè¿ããäžèšã®å詊è¡ã«ãŒããããã®ãã¬ãŒã³ãª 1 è¡ã®ãšã©ãŒãäžéæãªãHTTP 408ãå¿çãªããã«å€ããŠããŸããŸããã
åã CI ããŒãã¹ããã® 4 ã€ç®ã®æèšã§ãæãå€ãã®ãµã€ã¯ã«ãæ¶è²»ãããã®ã§ã: å詊è¡ãäžæžãããŠããŸãèšè£
ã¯ãäœãèšé²ããŸããã tests/runner-coldbox.bxm ã¯ãèªèº«ã®é²æãã¡ã€ã«ãåãè©°ãã (fileWrite( progressFile, "" )) ããšããå§ãŸããrunColdBoxIntegrationTests.bxs ã¯ãæéãŸã§ 1 ç§ããšã«ã©ã³ããŒãªã¯ãšã¹ããå詊è¡ããŠããŸããããã®ããããã¹ãŠã®å詊è¡ãããã³ã°ããæåã®è©Šè¡ãæžããããŒã«ãŒãæ¶ãå»ãã倱æèšºæã¯å¿ å®ã«ç©ºã®ãã¡ã€ã«ã衚瀺ããŸãã - ããã¯ãããŒãžã¯ã©ãã«ãå°éããªãã£ãããšèªããŸãããå®éã¯ã蚌æ ãåé€ããããã§ãããããã«æªãããšã«ãå詊è¡ã¯èšºæãšã¯ç¬ç«ããŠç©æ¥µçã«æå®³ã§ãã: ã©ã³ããŒããŒãžã¯å®äŸ¡ã§ãåªçã§ããªã (TestBox ãèµ·åãããã¹ãŠã®çµ±åã¹ããã¯ãå®è¡ããŸã)ããã®ããå詊è¡ã¯ããããäžæ¡ãã®ã¹ã¬ãããããªã MiniServer ã®ã¯ãŒã«ãŒããŒã«ã«äžŠè¡ãããã«ãã¹ãå®è¡ãç©ã¿éããŠããŸããŸãã - ããã¯ãã³ã°ããå埩ããæ¹æ³ã§ã¯ãªãããã³ã°ãåŒãèµ·ããæ¹æ³ã§ããäž¡æ¹ãšãä¿®æ£ãããŠããŸã: ãªãŒã±ã¹ãã¬ãŒã¿ãŒã¯ããŒã«ãŒãã¡ã€ã«ãäžåºŠã ãã¯ãªã¢ããæ£ç¢ºã« 1 åã ããªã¯ãšã¹ããè¡ããŸã (ããã«å
ç«ã€ãã«ã¹ãããŒãããã§ã«ãµãŒããŒãèµ·åããŠããããšã蚌æããŠããã®ã§ãå詊è¡ãåŸ
ã€ã¹ããã®ã¯äœããããŸãã)ããããŠãã®ããŒãžã¯è¿œèšã®ã¿ãè¡ããåè¡ã«ãªã¯ãšã¹ãããšã® UUID ãã¿ã°ä»ãããã®ã§ãéè€ãã詊è¡ãèå¥å¯èœãªãŸãŸæ®ããŸããäžè¬çãªã«ãŒã«: 鲿ãã°ã¯è¿œèšå°çšã§ããããããèšè£
ããŠãããã®ããé·çãããªããã°ãªããŸããããããŠãé«äŸ¡ãããã¯ã¹ããŒããã«ãªãã®ã¯ã決ããŠå詊è¡ã«ãŒãã®èåŸã«çœ®ãããã¹ãã§ã¯ãããŸããã
ããã蚺æããŠããæäžã«èŠã€ãã£ããå¥ã®é¢é£ãã BoxLang ã®èœãšã穎: request ã¯äºçŽãããçµã¿èŸŒã¿ã¹ã³ãŒãåã§ãã request ãšããååã®ããŒã«ã«/ã«ãŒã倿°ã¯ãããããµã€ã¬ã³ãã«ã·ã£ããŠããããšããããŸã - for ( var request in someArray ) { request.someKey } ã¯æ£ããåæ°ã ãå埩ããŸãããããã®å
éšã§ã®ãã¹ãŠã® request.someKey ã¢ã¯ã»ã¹ã¯ãã«ãŒã倿°ã®ä»£ããã«ããšã©ãŒããªã空ã®çµã¿èŸŒã¿ã¹ã³ãŒãããµã€ã¬ã³ãã«èªã¿åã£ãŠããŸãããBaseAgentSpec.bx ã®ãããã£ãŒã§ recordedRequest ã«ãªããŒã ããããšã§ä¿®æ£ãããŸãã - ãã®ãããžã§ã¯ãã§ãrequest ãšããæå³ã®éãååã§ã«ãŒãããå°æ¥ã®ã©ã㪠BoxLang ã³ãŒãã§ãèŠããŠãã䟡å€ããããŸãã
serve ã® miniserver æ€çŽ¢ã¯ PATH ã®ã¿
serve 㯠boxlang-miniserver ã PATH äžã§ã®ã¿æ¢ããŸã (MiniServerLauncher.findExecutable())ãèšå®ããããã¹ããã³ãã«ããããã€ããªãžã®ãã©ãŒã«ããã¯ã¯ãããŸãã - ã€ã³ã¹ããŒã«ãããŠããã PATH ã«ãªããã°ãserve ã¯æç¢ºã§å¯ŸåŠå¯èœãªãšã©ãŒã§å€±æããŸããããããæãå¥ã®æ¹æ³ã¯ãããŸãããinvoke --server ã¯å
éšã§ serve ãåå©çšããã®ã§ããã®åã PATH ã®ã¿ã®æ€çŽ¢ãåŒãç¶ããŸã - ãã® InvokeSpec.bx èªèº«ã®å®éã® HTTP ã©ãŠã³ãããªããçšãã¹ãã¯ããŸã MiniServerLauncher.findExecutable() ããã§ãã¯ããPATH ã«å®éã®ãã€ããªããªããã°ã倱æã§ã¯ãªãã¹ãããããŸãããã㯠RuntimeStartupSmokeSpec.bx ããã§ã«èªèº«ã® jar ååšãã§ãã¯ã§äœ¿ã£ãŠããã®ãšåãæ
£çšã§ããæ¬çªã§ãã®å®éã® HTTP ãã¹ã«äŸåããåã«ãboxlang-miniserver ãã€ã³ã¹ããŒã«ããããã·ã³ã§ãå°ãªããšãäžåºŠã¯æåã§ bxAgents invoke --message=... --server ãå®è¡ããŠãã ãã - ãã®ããŒãžã®ä»ã®ç®æã§ãã§ã«äœ¿ãããŠããã®ãšåããæ£çŽãªæ çµã¿ã§ãããã®ã¹ã€ãŒããããããç°å¢ã§èªåã§éããããšãã§ããªãã®ã£ããã«ã€ããŠã§ãã
ã¹ã³ãŒãä»ã BoxLang ã©ã³ã¿ã€ã ããŒã 㯠serve/invoke --server ã«ã¯ç¡æ¡ä»¶ã«å±ãããã€ã³ããã»ã¹ã®åè©ã«ã¯ BoxLang ã®ã€ã³ã¹ããŒã«ã .env ãããŒãããå Žåã«ã®ã¿å±ã
serve 㯠miniserver èªèº«ã® BoxLang ã©ã³ã¿ã€ã ããŒã ããserverHome çµç±ã§ .build/runtime ã«ã¹ã³ãŒãããŸã (ããã¯å®åšãããç¢ºèªæžã¿ã® MiniServerConfig ãã£ãŒã«ãã§ã - boxlang-web èªèº«ã® MiniServer CLI ãã«ãããã¹ã: -s, --serverHome <PATH> BoxLang server home directory (default: ~/.boxlang))ããã®ãããåãããžã§ã¯ãã®ã³ã³ãã€ã«æžã¿ã¯ã©ã¹ãã£ãã·ã¥ãšããããã config ãªãŒããŒã©ã€ãã¯ãã°ããŒãã«ã«å
±æããã ~/.boxlang ã§ã¯ãªããããžã§ã¯ãããšã«åé¢ãããŸããinvoke --server ã¯å
éšã§ serve ãåå©çšããããããããç¶æ¿ããŸãããã®éšåã¯ç¡æ¡ä»¶ã§ã - ç§ãã¡ããã®ããã»ã¹ã®èµ·å config ãèªåèªèº«ã§æžããŠããããã§ãã
chatãbuildãtestããããŠããã©ã«ã (ã€ã³ããã»ã¹) ã® invoke ã¯éããŸã: ãããã¯ãã§ã«èµ·åããŠãã bxAgents ããã»ã¹ã®å
éšã§å®è¡ããããã®èªèº«ã® BoxLang ã©ã³ã¿ã€ã - ãããŠãã®ããŒã - ã¯ãModuleConfig.bx èªèº«ã® main() ãå«ããç§ãã¡ã® BoxLang ã³ãŒããäœã§ããå®è¡ãããæ©äŒãåŸããããåã«è§£æ±ºãããŠããŸã (ãã®ã³ãŒããè§£éããã«ã¯ããšã³ãžã³èªäœããŸãååšããªããã°ãªããªãããã§ã)ãBoxRuntime 㯠JVM å
šäœã§ 1 ã€ã®ã·ã³ã°ã«ãã³ã§ããã®ããŒã ã¯æåã®åæåæã«åºå®ãããããããã§ã«å®è¡äžã®ãã®ããã»ã¹ã®å
éšããåè©ã¯ã©ã¹ãäœãããŠãããããé¡ã£ãŠå€æŽããããšã¯ã§ããŸããã
ããã«å¯Ÿããæ¬åœã®ã¬ããŒã¯å®éã«ååšããŸã: BoxRunner (BoxLang èªèº«ã®ã³ã¢ CLI ãšã³ããªãã€ã³ãã§ãããminiserver ã ãã§ã¯ãããŸãã) ã¯ãBoxRuntime ãåæåãããåã«ãæ£çæ£éã® BOXLANG_HOME ç°å¢å€æ°ãèªã¿åããŸã - ããã¯ããã¥ã¡ã³ãã ãã§ãªããå®éã®ã©ã³ã¿ã€ã jar ã«å¯ŸããŠçŽæ¥ç¢ºèªæžã¿ã§ã: å®éã® OS ç°å¢å€æ°ãšã㊠BOXLANG_HOME=<path> ãèšå®ããŠãããå®è¡ãããš (çžå¯Ÿãã¹ã¯çµ¶å¯Ÿãã¹ãšåãããã« CWD ã«å¯ŸããŠè§£æ±ºãããŸã)ã~/.boxlang ã®ä»£ããã«ãã®ãã¹ã«ãæ¯åãå®å
šãªããŒã æ§é ãçšæãããŸããnew ã¯ããŸãã«ãã®çç±ã§ (ortus-boxlang/bx-ai-intro èªèº«ã® .env/BOXLANG_HOME ã³ã³ãã³ã·ã§ã³ãåæ ããŠ)ãserve ã䜿ãã®ãšåããã¹ã§ãã BOXLANG_HOME=.build/runtime ã宣èšãã .env ãããããžã§ã¯ãã«ãŒã (ã€ãŸããã€ã³ããã»ã¹ã®åè©ã®ããã«ãŠãŒã¶ãŒãå®éã« bxAgents <verb> ãå®è¡ãããã£ã¬ã¯ããªã§ãããCWD ããŒã¹ã® .env ããŒããŒããããèŠã€ããã¹ãæ£ããå Žæã§ã) ã«ã¹ãã£ãã©ãŒã«ãããŸãã
確èªã§ããããšããããŠã§ããªãã£ãããšã boxlang-miniserver (serve ãèµ·åãããã®) ã«ã¯ãå®éã«çµã¿èŸŒãŸãã .env ã®èªåããŒãããããŸã - ãã㯠ortus.boxlang.web.MiniServer ãå®éã«ãã³ã³ãã€ã«ãããã®åŸå®éã«å®è¡ããããšã§ç¢ºèªæžã¿ã§ã: envFile ãèšå®ãããŠããªãå Žåã.env ã¯ãµãŒããŒã®webRoot (ãããžã§ã¯ãã«ãŒãã§ã¯ãããŸãã) ããã®çžå¯Ÿãã¹ã§è§£æ±ºãããèŠã€ããã° Java ã® Properties ãšããŠããŒããããåããŒã¯ System.setProperty() çµç±ã§é©çšãããŸã - ãã®æ¹æ³ã§ããŒããããå®éã®å€ã¯ãgetSystemSetting() ãéã㊠BoxLang ã³ãŒãããèŠããŸããçã®ã³ã¢ã©ã³ã¿ã€ã jar (BoxRunnerãchat/build/test/ããã©ã«ãã® invoke ã䜿ããã®) ã«ã¯ãããã«çžåœããããžãã¯ãã©ãã«ããããŸãã (jar å
ã®ãã¹ãŠã®ã¯ã©ã¹ã .env ã§ã°ã¬ããããŠç¢ºèªæžã¿ã§ã) - ãã®ããããããã®åè©ã¯ãå®éã«ã€ã³ã¹ããŒã«ãããŠãã boxlang CLI (ãã®çã® jar ã§ã¯ãªããBVM ãæäŸãããã€ãã£ãã©ã³ãã£ãŒ) ã JVM ãèµ·åããåã«èªèº«ã§ .env ã®ããŒããè¡ã£ãŠããå Žåã«ã®ã¿ .env ãæŸããŸããortus-boxlang/bx-ai-intro ãé Œã£ãŠããã®ããã®æ¹æ³ã§ããããã¯ãã£ãšããããããã®ãããžã§ã¯ãã®å®äžçã§ã®äœ¿ããæ¹ãšäžèŽããŠããŸããããã®ãµã³ãããã¯ã¹ã«ã¯çŽæ¥æ€èšŒããããã®å®éã®ãã€ããªããããŸããã
.env ã®ããŒããè¡ãããå Žåã§ããã1 ã€ã®å
·äœçã§ç¢ºèªæžã¿ã®èœãšã穎ããããŸã: BOXLANG_HOME ããèªäœã¯ãå®éã® OS ç°å¢å€æ°ã§ãªãéã广ãæã¡ãŸãã - JVM ã®ã·ã¹ãã ããããã£ã§ãã-D ãã©ã°ã§ããããŸãããå®éã® jar ã«å¯Ÿã㊠2 åãçŽæ¥æ€èšŒãããŠããŸã: (1) .env ã BOXLANG_HOME=customhome ã宣èšããŠãã webRoot ã«å¯Ÿã㊠boxlang-miniserver ãå®è¡ãããšããã®ãã¡ã€ã«ã¯ããŒããããŸãã (èªèº«ã® "Loaded environment variables from:" ãšãããã°è¡ãšãgetSystemSetting() ãä»ã® .env ã®å€ãæ£ããè¿ãããšã«ãã£ãŠç¢ºèªæžã¿ã§ã)ãããã§ããµãŒããŒã¯ Logs Directory: /root/.boxlang/logs ãšããããã©ã«ãã®ããŒã ããã°ã«åºããŸãããcustomhome ã§ã¯ãããŸããã(2) BoxRunner ã -DBOXLANG_HOME=<path> (JVM ã®ã·ã¹ãã ããããã£ã§ã.env ã¯é¢äžããŸãã) ã§çŽæ¥èµ·åããŠãã解決ãããããŒã ã«ã¯äœã®å¹æããããŸããã§ãããgetSystemSetting( "BOXLANG_HOME" ) 㯠BoxLang ã³ãŒãããåãã§ãã®ãã©ã°ã®å€ãè¿ãã«ããããããã§ããã€ãŸã BOXLANG_HOME ã®è§£æ±ºã¯ãå
·äœçã«ã¯æ¬ç©ã® OS ç°å¢å€æ°ã ããèªã¿ãŸã - ã»ãšãã©ã®èšå®ãšã¯ç°ãªããgetSystemSetting() ãããã«å¯ŸããŠå€ãè¿ãããšã¯ãã©ã³ã¿ã€ã ããŒã ãå®éã«ç§»åããããšãæå³ããŸãããããªãã® boxlang CLI ã® .env ããŒããŒããMiniServer ã®å
éšãšåãæ¹æ³ (JVM ããã§ã«èµ·åããåŸã® System.setProperty) ã§åäœããJVM ãèµ·åããåã«æ¬ç©ã® env 倿°ããšã¯ã¹ããŒãããŠããªãå Žåã.env ã®äžã® BOXLANG_HOME ã¯ã.env èªäœã¯æ£åžžã«ããŒããããã«ãããããããã©ã³ã¿ã€ã ããŒã ã«ã¯å±ããŸãã - ãã以å€ã®ãã¹ãŠã¯ãã®ãŸãŸæ©èœããŸããããªãã®ã€ã³ã¹ããŒã«ãããããŸã£ããæäŸããªãå Žåã¯ãã³ãã³ããå®è¡ããåã«èªåèªèº«ã§ããã source ããŠãã ãã (äŸãã° set -a; source .env; set +a)ãããããã° serve ããã§ã«ç¡æ¡ä»¶ã«åŸãŠããåé¢ãåŸãããŸãã
new ã® box install 䟿å®ã¹ãããã¯èªåãã¹ãã§æŒç¿ãããŠããªã
new ã¯ããã©ã«ãã§ãã¹ãã£ãã©ãŒã«ãããã tests/ ãã©ã«ãã®å
éšã§ box install ãå®è¡ãããããbxAgents test 㯠(CLI ãªãã¡ã¬ã³ã¹ åç
§) ããã«åäœããŸããããã¯å®éã®ãããã¯ãŒã¯æäœã§ã (CommandBox 㯠testbox ã ForgeBox ã«å¯ŸããŠè§£æ±ºããŸã) - ãã®éçºãµã³ãããã¯ã¹ã§ã¯å
·äœçã«çŽ 25 ç§ããããèšŒææžãšã©ãŒã§å€±æããããšã確èªãããŠããŸããããã¯ããã®ãããžã§ã¯ãèªèº«ã®ããŒã«ã®ä»ã®ç®æã§ãã§ã«ææãããŠãããForgeBox ã«å°éäžèœãšããåãå¶çŽã§ããNewSpec.bx ã¯é«éã§æ±ºå®ç㪠--skipInstall ãã¹ã®ã¿ãæŒç¿ããŸã (OS ããã»ã¹ã® ModuleCliProcessTest.java/ã€ã³ããã»ã¹ã® ModuleConfigCliSpec.bx ã«ãã new ã®åŒã³åºãããåãçç±ã§ --skipInstall ãæž¡ããŸã) - ããã©ã«ãã®ã€ã³ã¹ããŒã«è©Šè¡ãã¹èªäœã¯ãæåãã¹ãã«ãã£ãŠã®ã¿æ€èšŒãããŠãããCI ã§ã¯ãããŸããã
chat ã«ã¯æ¬ç©ã® TTY ãå¿
èŠ
chat 㯠BoxLang èªèº«ã® MiniConsole ã䜿çšããŸãããã㯠raw ã¿ãŒããã«ã¢ãŒããã»ããã¢ããããããã« stty ãã·ã§ã«ã¢ãŠãããŸã - æ¬ç©ã®å¯Ÿè©±ã¿ãŒããã«ã«å¯ŸããŠã®ã¿å®è¡ã§ããŸãããã€ãããªãã€ã¬ã¯ãããããã¯é察話ããã»ã¹ (CI ãžã§ããã¹ã¯ãªãã) ããã¯åäœããŸãããé察話ã®ãã©ãŒã«ããã¯ã¢ãŒãã¯ãããŸããã
ä¿®æ£æžã¿: chat ãšããã©ã«ã (--server ãªã) ã® invoke ã¯ãã¯ã©ã¹ããŒã¹ã® Agent.bx ã«å¯ŸããŠãã€ãŠå€±æããŠãã
以åã¯ãchat ãšããã©ã«ãã® invoke ã®äž¡æ¹ãããšãŒãžã§ã³ãã«å°éããåã« The requested class [agent.classes.agentClass] has not been located in any class resolver. ãæããŠããŸãããæ ¹æ¬åå : ã©ã¡ãã®åè©ããçæããã GeneratedAgentFactory.bx ããColdBox ã³ã³ãããäžåä»ããã« DynamicClassLoader.instantiate() (絶察ãã¹ã«å¯Ÿããçã® RunnableLoader åŒã³åºã) çµç±ã§ã€ã³ããã»ã¹ã«ããŒãããŠããŸããããçæããããã¡ã¯ããªã¯ãã¯ã©ã¹ããŒã¹ã® Agent.bx ãçžå¯Ÿçãªãããåºåããã¹ã®æ€çŽ¢ new "agent.classes.agentClass"() ã§ã€ã³ã¹ã¿ã³ã¹åããŠãããããã¯ã¢ããªã®ã«ãŒãã解決å¯èœã«ãããããã³ã°ãç»é²ãããŠããå Žåã«ã®ã¿è§£æ±ºããããã®ã§ãå®éã® ColdBox ã®èµ·åã®å€åŽã§ã¯äœããããç»é²ããŠããŸããã§ããã
DynamicClassLoader.instantiate() ã®çŽåã«ã¹ã¯ãªããã®éäžã§ãããã³ã°ãç»é²ããããš (Configuration.registerMapping( "/", appDir )) ãããããä¿®æ£ããŸãã - ã¹ã¿ã³ãã¢ãã³ã® .bxs ã¹ã¯ãªããã§æäœæ¥ã§åãæé ãåçŸããããšã§çµéšçã«ç¢ºèªãããŠããŸããäžèšã§ãã§ã« TestRunnerLauncher ã® TestBox çºèŠã«ã€ããŠææžåãããŠãããåãçš®é¡ã®å¶éã§ã: ã¹ã¯ãªããã®éäžã§ Configuration.registerMapping() ã«ãã£ãŠç»é²ããããããã³ã°ã¯ããã®åãããã»ã¹å
ã§è¡ãããã¯ã©ã¹èªèº«ã®çžå¯Ÿãã¹æ€çŽ¢ã«ã¯ç¢ºå®ã«ã¯äŒæããŸããã
ä¿®æ£: ColdBoxAppGenerator.copyAgentClass() ã¯ä»ã (ãããåºåãã®ã³ã³ããŒãã³ããã¹ã§ã¯ãªã) ã³ããŒãããã¯ã©ã¹èªèº«ã®çµ¶å¯Ÿãã¡ã€ã«ãã¹ãè¿ããrenderClassBasedAgentStatement() ã¯ãçžå¯Ÿç㪠new "..."() ã§ã¯ãªããchat/invoke ããã§ã« GeneratedAgentFactory.bx èªäœãããŒãããã®ã«äœ¿ã£ãŠããã®ãšãŸã£ããåãããªããã£ãã§ãã DynamicClassLoader.instantiate( absolutePath, context ) çµç±ã§ãããã€ã³ã¹ã¿ã³ã¹åããŸããããã¯ãããã³ã°è§£æ±ºãå®å
šã«åé¿ããã®ã§ãå®éã® ColdBox ã³ã³ãããèµ·åããŠãããã©ããã«ããããããä»ã§ã¯åãããã«åäœããŸããexamples/class-based-agent/ ã«å¯ŸããŠç¢ºèªæžã¿ã§ã: chatãããã©ã«ãã® invokeãinvoke --serverãserve ã¯ãã¹ãŠãä»ã§ã¯åããšãŒãžã§ã³ããæ£ãããã«ãããŠå®è¡ããŸãã
box.json ã® executable ã€ã³ã¹ããŒã«ã®ã¹ã¢ãŒã¯ãã¹ãã¯ãªã
box.json 㯠"boxlang": { "executable": "bxAgents" } ã宣èšããŠããã®ã§ãå®éã®ã¢ãžã¥ãŒã«ã€ã³ã¹ããŒã«ã¯ãã€ãã£ã㪠bxAgents ã³ãã³ããçæããŸã (ã€ã³ã¹ããŒã« åç
§)ããã®é
ç·èªäœã¯èªåãã¹ãã§æŒç¿ãããŠããŸãã - ãã㯠BoxLang ã®ã¢ãžã¥ãŒã«ã€ã³ã¹ããŒã©ãŒèªèº«ãææžåããŠãããå®è¡ãã¡ã€ã«ã©ãããŒãçæããæåã«äŸåããŠããããœãŒã¹ãèªãã§ç¢ºèªããããã®ã§ãã£ãŠããã®ãªããžããªèªèº«ã® CI ã§ã®ã€ã³ã¹ããŒã«&å®è¡ãã¹ãã«ãããã®ã§ã¯ãããŸããã
schedules/Scheduler.bx ã¯ãã«ãæã«æ€èšŒãããªã
ããã¯å®éã®ææžãã® ColdBox ã³ãŒãããã®ãŸãŸéãããŠãããã (schedules/ åç
§)ãbuild ã¯ããã€ãŠ { cron, action } config ããã§ãã¯ãããŠãããããªæå³ã®ãããã§ãã¯ãè¡ãããšãã§ããŸãã - æ§æãšã©ãŒãgetInstance( "..." ) åŒã³åºãã®ã¿ã€ããã¹ããããã¯ååšããªããšãŒãžã§ã³ãåã®åç
§ã¯ããã¹ãŠ build ãã¯ãªãŒã³ã«ééããçæãããã¢ããªãå®éã«èµ·åãããšã (serve) ã«ã®ã¿è¡šé¢åããŸãããã®ãããžã§ã¯ããäžèº«ãææããŠããªãä»ã®ããããå®éã® BoxLang ã¯ã©ã¹ãšåãã§ããbuild ã¯ãããã«é£æ¥ããããçã 1 ã€ã®ééãã¯ãã£ããããŸã: 2 ã€ã®ãšãŒãžã§ã³ã (ã«ãŒããŸãã¯ã©ããªæ·±ãã®ãµããšãŒãžã§ã³ãã§ã) ãåã name ã宣èšããŠããããšã§ã - ããã¯ãã®ãããžã§ã¯ããèªèº«ã§çæãã config/WireBox.bx ã®ãã€ã³ãã£ã³ã°è¡çªãªã®ã§ãçæããä»ã®ãã¹ãŠãšåãããã«æ€èšŒæã«ãã§ãã¯ãããŸãã
test åè©ã®æ§ç¯äžã«èŠã€ãã£ãå®éã®ãã°: boxlang-miniserver ãã¯ã©ã¹ãã¹ã«ãããšãçŸåšã® BoxLang jarãã®è§£æ±ºãææ§ã«ãªã
TestRunnerService.bx ã¯ããããžã§ã¯ãã® tests/specs ãå®è¡ããããã«æ°ããåããã»ã¹ãèµ·åããã©ã® jar ã§ãããèµ·åããããç¥ãå¿
èŠããããŸããæåã®å®è£
ã¯ããã®ã¯ã©ã¹ãããŒãããã jar ã¯ã©ããããšããæšæºçãªããªã㯠(BoxRuntime.class.getProtectionDomain().getCodeSource().getLocation()) ã䜿ã£ãŠããŸãã - ããã¯åé¢ããæåãã¹ãã§ã¯æ©èœããŸããããserve/MiniServerLauncher é¢é£ã®ã¹ããã¯ã®ããã« boxlang-miniserver-*.jar ãã¯ã©ã¹ãã¹ã«å¿
èŠãšããããã®ãããžã§ã¯ãèªèº«ã®å®å
šãª testBx ã¹ã€ãŒãã®äžéšãšããŠå®è¡ãããšãäºæž¬äžèœã«å€±æããŸãããçŽæ¥èª¿æ»ããŠç¢ºèªãããŸãã: boxlang-miniserver-*.jar ã¯ãortus.boxlang.runtime.BoxRuntime èªèº«ã®ã³ããŒããã³ãã«ãããã¡ãã jar ã§ã - äž¡æ¹ã® jar ãã¯ã©ã¹ãã¹ã«ãããšãã¯ã©ã¹ããŒããŒã¯ BoxRuntime.class ããæ¬ç©ã®ã©ã³ã¿ã€ã jar ã§ã¯ãªã miniserver jar ã«è§£æ±ºããŠããŸãããšããããBoxRunner.main ã®ä»£ããã« MiniServer.main (BoxLang ã¹ã¯ãªããããã¹ãã¬ããŒããäžåçæãããåã« --bx-config ãæåŠããŠå³åº§ã«çµäºã³ãŒã 1 ã§çµäºããŸã) ããµã€ã¬ã³ãã«èµ·åããŠããŸããŸãããã㯠tests/specs/cli/TestSpec.bx ã®å®éã®ããã»ã¹ã®ã±ãŒã¹ã exitCode=1 ãšç©ºã®ã¬ããŒãã§å€±æãããšãã圢ã§è¡šé¢åããŸããããããã¯åé¢ããç¶æ
ã§ã¯ãªãããã«ã¹ã€ãŒããéããŠå®è¡ããå Žåã«ã®ã¿åçŸããããããèŠéããããããŠããŸããã
java.class.path ãã jar ã解決ããããã«ä¿®æ£ãããŸãã - miniserver ãå«ãŸãªã boxlang-*.jar ãšã³ããªãæ¢ãããã®ãããªãšã³ããªãèŠã€ãããªãå Žåã«ã®ã¿ãå€ã codeSource ã®ããªãã¯ã«ãã©ãŒã«ããã¯ããŸãã
deploy ã® ssh/docker/digitalocean ã¿ãŒã²ããã¯å®éã®ããã»ã¹ã«ããèªåãã¹ãã§æŒç¿ãããŠããªã
SshTargetSpec.bx/DockerTargetSpec.bx ã¯ãå®éã®ãã€ããªãäžååŒã³åºããã«ãåã¿ãŒã²ãããæ§ç¯ããæ£ç¢ºãª scp/ssh/docker ã³ãã³ã (å®éã® ProcessBuilder åŒæ°é
å) ãã¢ãµãŒãããŸã - ãã®ã¹ã€ãŒãã®ä»ã®ç®æã§ãCI ã§ PATH ã«ãªããããããªããã€ããªãå¿
èŠãªãã®ã«å¯ŸããŠäœ¿ãããŠããã®ãšåãããã£ããã£ããã ãã§å®è¡ããªããã¢ãããŒãã§ã (MiniServerLauncherTest ã® assumeTrue ã«ããã¹ããããåç
§)ãlocal ã®ã³ããŒããžãã¯ã¯æ¬åœã«æŒç¿ãããŠããŸã (LocalTargetSpec.bx)ããã®ãªãã¡ã¯ã¿ãªã³ã°ãä¿®æ£ããå®éã®æœåšãã°ã«å¯Ÿããååž°ãã¹ããå«ã¿ãŸã: å
ã
ã® Deploy.bx ã¯ãææ°ãã® .bxa ããã¡ã€ã«åã®åå¥ãœãŒãã§éžãã§ããããããžã§ã¯ãã 2 æ¡ã®ããŒãžã§ã³ã«éãããš (v9.0.0 㯠v10.0.0 ã®åŸã«ãœãŒããããŸã) ãµã€ã¬ã³ãã«èª€ã£ãŠéžãã§ããŸãã - å®éã®ãã¡ã€ã«æŽæ°æå»ã§ãœãŒãããããšã§ä¿®æ£ãããŸãã (DistArtifactLocator)ã
DigitalOceanTargetSpec.bx ãåæ§ã«ãçŽç²ãª buildAppSpec()/findExistingAppId() ã®ããžãã¯ã®ã¿ããŠããããã¹ãããŠããŸã - å®éã® GET/POST /v2/apps åŒã³åºã㯠CI ã§ã¯äžåæŒç¿ãããŠããŸãããã©ã€ã㪠DigitalOcean ã¢ã«ãŠã³ããš API ããŒã¯ã³ãå¿
èŠã ããã§ããã©ã¡ããäžæ¹ã«æ¬çªã§äŸåããåã«ãå®éã®äœ¿ãæšãŠ VM ã«å¯ŸããŠå°ãªããšãäžåºŠã¯æåã§ deploy --name=<ssh-entry> ããå®éã® DO ã¢ã«ãŠã³ãã«å¯ŸããŠäœ¿ãæšãŠã®ã¢ããªã§ deploy --name=<digitalocean-entry> ãå®è¡ããŠãã ãã - äžèšã®ã¢ãã¯ãããã€ããŒã®ã¿ã®ãã¹ãã®ã®ã£ããã§ãã§ã«äœ¿ãããŠããã®ãšåããæ£çŽãªæ çµã¿ã§ãã
deploy ã® ftp/sftp ã¿ãŒã²ãã: å®éã®æ¥ç¶åŠçã¯èšŒææžã¿ã ããå®éã®æåããã¢ããããŒãã¯èšŒæãããŠããªã
å€éšãã€ããªãã·ã§ã«ã¢ãŠããã (ãã®ããã³ãã³ãæ§ç¯ã ããå®ãµãŒããŒãªãã§ãã¹ãã§ãã) ssh/docker ãšã¯ç°ãªããftp/sftp ã¯å®éã® bx-ftp ã¢ãžã¥ãŒã«ã® bx:ftp ã³ã³ããŒãã³ããã€ã³ããã»ã¹ã§åŒã³åºããŸã - ãã³ãã³ãããã£ããã£ããŠå®è¡ããªãããšããéžæè¢ã¯ãããŸãããBaseFtpTargetSpec.bx ã¯ä»£ããã«ãäœã listen ããŠããªãããŒãã§ 127.0.0.1 ã«å¯ŸããŠæ¬ç©ã®æ¥ç¶è©Šè¡ãè¡ããå®éã®æ¥ç¶æåŠãšã©ãŒãææãããæç¢ºãª BxAgents.DeployFailed ãšããŠåéåºãããããšãã¢ãµãŒãããŸã (bx-ftp èªèº«ã®ãœãŒã¹ã«ããããã¹ãŠã®ã¢ã¯ã·ã§ã³ã¯ãœãã㪠succeeded: false ãè¿ãã®ã§ã¯ãªã倱ææã«äŸå€ãæããããšã確èªãããŠããŸã)ãããã¯å®éã®æ¥ç¶/ãšã©ãŒã©ãã/ã¯ãªãŒã³ã¢ããã®ãã¹ããšã³ãããŒãšã³ãã§èšŒæããŠããŸããã蚌æã§ããªãã®ã¯å®éã®æåããã¢ããããŒãã§ãã
ãã®ã®ã£ããã¯å
·äœçã«ããã®éçºãµã³ãããã¯ã¹ã«ã¯çã® TCP ã®éä¿¡æ¥ç¶ããŸã£ãããªãããã§ã - ããã®ã¯ãã®ç°å¢ã®ãããã·ãçµç±ãã HTTPS ã®ã¿ã§ã (çŽæ¥ç¢ºèªæžã¿ã§ã: curl ftp://test.rebex.net ãšãå
¬é FTP ãã¹ããžã®çã® /dev/tcp æ¥ç¶ã®äž¡æ¹ããã³ã°ããŠã¿ã€ã ã¢ãŠãããdocker info ã¯åããŠããããŒã¢ã³ããªãããšã瀺ããŠãããããbx-ftp èªèº«ã«ãã³ãã«ããã Docker ã® FTP/SFTP ãã¹ããµãŒããŒãããã§ã¯èµ·åã§ããŸããã§ãã)ãããã¯ãµã³ãããã¯ã¹ã®å¶çŽã§ãããã³ãŒãã®å¶éã§ã¯ãããŸãã - ã©ã¡ããäžæ¹ã«æ¬çªã§äŸåããåã«ãå®éã«å°éå¯èœãªãµãŒã㌠(ãããã¯ãDocker/ãããã¯ãŒã¯ã¢ã¯ã»ã¹ã®ãããã·ã³ããã® bx-ftp èªèº«ã® docker-compose up ãã¹ããµãŒããŒ) ã«å¯ŸããŠãå°ãªããšãäžåºŠã¯æåã§ deploy --name=<ftp-entry> ãš deploy --name=<sftp-entry> ãå®è¡ããŠãã ãã - äžèšã® ssh/digitalocean ã§ãã§ã«äœ¿ãããŠããã®ãšåããæ£çŽãªæ çµã¿ã§ãã
build ã¯ãçæã®éäžã§ã¯ã©ãã·ã¥ããå Žåã«éšåçã«æžã蟌ãŸãã .build/app ãããŒã«ããã¯ããªã
BuildPipeline.build() ã¯ãäºåã« .build/app ãåé€ããŠåäœæãããã®åŸãã§ãŒãº 5 ã®ãžã§ãã¬ãŒã¿ãé çªã«å®è¡ããŸãããã§ãŒãº 3 (ProjectValidator) ããã§ãã¯ã§ããå
¥åã¯ãã¹ãŠããããèµ·ããåã«ãã§ãã¯ããããããå®éã®çæéäžã®ã¯ã©ãã·ã¥ã¯å®éã«ã¯çšã§ããã¯ãã§ã - ããããããããã§ãçºçããå Žå (äŸãã°ãããŒãã«å€±æãã models//schedules//mcp/ ãšã³ããªããããã¯ç°å¢/ãã¡ã€ã«ã·ã¹ãã ã®åé¡)ã.build/app ã¯ã以åã®å
容ã«åŸ©å
ããããã¯ãªãŒã³ã¢ããããããããã®ã§ã¯ãªããéšåçã«æžã蟌ãŸããç¶æ
ã§ãã£ã¹ã¯ã«æ®ããŸãããã®åŸã®æåãã build ã¯ããããããã«äžæžãããã®ã§ãããã¯åºçãããã®ã§ã¯ãããŸãããã倱æãããã«ããšæ¬¡ã®ãã«ãã®éã« .build/app ãæ€æ»ãããã® (CI ã¹ããããæåã® package ã®å詊è¡) ã¯ãå£ããåçæã®ã¢ããªãèŠãããšããããŸããããŒã«ããã¯/äžæãã£ã¬ã¯ããªçµç±ã®å
¥ãæ¿ãã¹ãããã¯ãŸã ãããŸããã
testBx ã§èŠ³æž¬ãããã鿬 ç㪠StackOverflowError (ãã®ãããžã§ã¯ãèªèº«ã®ã³ãŒããšã¯ç¡é¢ä¿)
ãã®ãã€ã«ã¹ããŒã³ã®èª¿æ»äžã./gradlew testBx 㯠(æ¯åã§ã¯ãªã) ææãBoxLang ãšã³ãžã³èªèº«ã®æ±çšãªããžã§ã¯ã JSON ã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ (DynamicObjectSerializer/BoxStructSerializer ãäºãã亀äºã«åŒã³åããã¹ã¿ãã¯ãå°œãããŸã§ç¶ããŸã - -Xss16m ã§ãäŸç¶ãšããŠçºçããããšã確èªãããŠããã®ã§ãåã«æ·±ãã ãã®æéãªæ§é ã§ã¯ãªããæ¬ç©ã®åŸªç°ã§ã) ã®å
éšã§ StackOverflowError ãåºã㊠JVM å
šäœãã¯ã©ãã·ã¥ãããŸãããgit stash (ãã®ã»ãã·ã§ã³ã®å€æŽãäžåé©çšããªãç¶æ
ã§ãdevelopment ã«ããåãã³ãããã«å¯ŸããŠãã¯ã©ãã·ã¥ã¯åäžã«åçŸããŸãã) ãšãtests/specs/** ãåå¥ã«ãçµã¿åãããŠãããã¹ãŠã®ãµããã£ã¬ã¯ããªã«äºåæ¢çŽ¢ãè¡ãããšã§ (ãã¹ãŠã®ãµãã»ãããããã«ã¯ãã¹ãŠã®ã1 ã€ãé€ããµãã»ãããããã¯ãªãŒã³ã«å®è¡ã§ããŸãã) åé¢ã詊ã¿ãŸããããåäžã®å®å
šãªå®è¡ã ããææãããåçŸããã¯ã©ãã·ã¥ã®çŽåŸã«åäžã®å®å
šãªã¹ã€ãŒããåå®è¡ãããšãæã«ã¯ã¯ãªãŒã³ã«åæ ŒããããšããããŸããããã¯ã(ExampleScheduler èªèº«ã®ã©ã€ããªããã¯ã°ã©ãŠã³ãã® everySecond() ã¿ã¹ã¯ãããã®æç¹ã§å®è¡äžã®ã©ã®ã¹ããã¯ãšã䞊è¡ããŠèªèº«ã®ã¹ã¬ããããŒã«ããåºåããŠããããšãšçžäºäœçšããŠããå¯èœæ§ããã) ã¿ã€ãã³ã°äŸåã®ã¬ãŒã¹ã³ã³ãã£ã·ã§ã³ã瀺åããŠãããã©ãã 1 ã€ã®ã¹ããã¯ããã®ãããžã§ã¯ãèªèº«ã®çæã³ãŒãã®ãã°ã§ã¯ãããŸãããtestBx ãä»ã«èª¬æã®ã€ããªã StackOverflowError ã§å€±æããå Žåã¯ãæ¬åœã®åŸéã ãšæ±ºãã€ããåã«å詊è¡ããŠãã ãã - çŸæç¹ã§ã¯ãªã³ããã³ãã§åçŸå¯èœã§ã¯ãªããããããã«å¯Ÿããèªåååž°ãã¹ãã¯ååšããããããåäžã®æ ¹æ¬åå ãŸã§ããã«è¿œæ±ããããšã¯ä»åã®ã¹ã³ãŒãå€ã§ããã
Push-style gateways (Telegram) are tested against a mocked API/scheduler seam only - no live platform integration runs in CI
TelegramGatewaySpec.bx 㯠TelegramGateway èªèº«ã®ããžã㯠(åä¿¡ã®æ£èŠåã4096 æåäžéã§ã®éä¿¡ãã£ã³ãã³ã°ãHITL ã€ã³ã©ã€ã³ããŒããŒãã®æ§ç¯ãã¹ã±ãžã¥ãŒã©ã¿ã¹ã¯ã®ç»é²/åé€) ããæ³šå
¥å¯èœãª apiCaller/setScheduler() ãã¹ãã·ãŒã ã ãã«å¯ŸããŠæŒç¿ããŸã - å®éã® Telegram Bot API åŒã³åºãããå®éã® ColdBox ã¹ã±ãžã¥ãŒã©ã®èµ·åãäžåºŠããããŸãããããã¯ã²ãŒããŠã§ã€èªèº«ã®ã³ãŒããæ£ããããšã蚌æããŸãããå®éã« Telegram ã®å® API ãã©ã€ããªå®è¡äžã®ã¹ã±ãžã¥ãŒã©ã«å¯ŸããŠãšã³ãããŒãšã³ãã§åäœããããšã蚌æãããã®ã§ã¯ãããŸãããæ¬çªã§ããã«äŸåããåã«ãå®éã® botTokenEnvVar ã«çŽä»ãã Telegram ããããæã€ãããžã§ã¯ãã«å¯ŸããŠãå°ãªããšãäžåºŠã¯æåã§ bxAgents serve ãå®è¡ããŠãã ãã - ãã®ãã¡ã€ã«ã®ä»ã®ç®æã§ãã§ã«äœ¿ãããŠãããã¢ãã¯ãããã€ããŒã®ã¿/ã©ã€ãæ¥ç¶ãªãã®ãã¹ãã®ã£ãããšåãæ£çŽãªæ çµã¿ã§ããåãæ³šæäºé
ã¯ãåãæ¹æ³ã§æ§ç¯ããããããããå°æ¥ã® push åã²ãŒããŠã§ã€ (SlackãDiscordãEmailãWhatsApp) ã«ãåœãŠã¯ãŸããŸãã
SlackGatewaySpec.bx ã¯åãã®ã£ããããããã«äžæ®µæ·±ãæ±ããŠããŸã: SlackGateway ã®æ°žç¶ç㪠websocket æ¥ç¶ã¯ã泚å
¥å¯èœãª setSocketOpener() ã·ãŒã (å®éã® java.net.http.WebSocket ã®ä»£ãããšãªããã§ã€ã¯ãªããžã§ã¯ã) ãéããŠãã¹ããããŠãããããã¹ããã¯å
ã®ãã¹ãŠã®ãã¬ãŒã åŠç/忥ç¶ããžãã¯ã®ã¢ãµãŒã·ã§ã³ã¯ãå®éã®ãããã¯ãŒã¯ I/O ããŒãã§å®è¡ãããŸããå®éã« (ã¢ãã¯ã§ã¯ãªã) çŽæ¥æ€èšŒãããããš: ã¹ã¿ã³ãã¢ãã³ã®ã¹ã¢ãŒã¯ãã¹ãããå®éã® SlackSocketListener(gateway) (ãã㯠implements="java:java.net.java.net.http.WebSocket$Listener" ãçŽæ¥æã¡ãŸã - BoxLang ã¯ãããæ¬ç©ã® JVM å®è£
ãšããŠã³ã³ãã€ã«ãããããã·ã¯äžèŠã§ã) ãã€ã³ã¹ã¿ã³ã¹åããå®éã® HttpClient.newWebSocketBuilder().buildAsync(...) ãå°éäžèœãªã¢ãã¬ã¹ã«å¯ŸããŠåŒã³åºããBoxLang ãã Java ãžã®çžäºéçšèªäœããããã¯ãŒã¯å¢çãŸã§æ£ããæ©èœããããšã確èªããŸãã (ãã£ã¹ã/çžäºéçšãšã©ãŒã§ã¯ãªãããã¬ãŒã³ãª java.net.ConnectException ã§å€±æããŸãã) - ããããããã®ã©ã®ãã¹ãããSlack ã®å®éã®ãµãŒããŒã«å¯ŸããŠæ¬ç©ã® Socket Mode ãã³ãã·ã§ã€ã¯ãå®äºãããããšã¯äžåºŠããããŸãããæ¬çªã§ããã«äŸåããåã«ãå®éã® botTokenEnvVar/appTokenEnvVar ã«çŽä»ãã Slack ã¢ããªã®èªèšŒæ
å ±ãæã€ãããžã§ã¯ãã«å¯ŸããŠãå°ãªããšãäžåºŠã¯æåã§ bxAgents serve ãå®è¡ããŠãã ããã
DiscordGatewaySpec.bx ã¯ããŸã£ããåãçç±ã§ãåäžã®ã®ã£ãããæ±ããŠããŸã: DiscordGateway ã®ãã¬ãŒã åŠç/ããŒãããŒã/忥ç¶ããžãã¯ã¯ã泚å
¥å¯èœãª setApiCaller()/setSocketOpener() ã·ãŒã ã«å¯ŸããŠã®ã¿æŒç¿ãããŠãããå®éã®ãããã¯ãŒã¯ I/O ã¯ãŒãã§ããåãã¹ã¿ã³ãã¢ãã³ã®ã¹ã¢ãŒã¯ãã¹ãã®èŠåŸãããã«ãé©çšãããŸãã - å®éã® HttpClient.newWebSocketBuilder().buildAsync(...) åŒã³åºããå°éäžèœãªã¢ãã¬ã¹ã«å¯ŸããŠé§åãã gateway.onConnect() ã¯ããã£ã¹ã/çžäºéçšãšã©ãŒã§ã¯ãªããã¬ãŒã³ãª java.net.ConnectException ã§å€±æããçžäºéçšãã§ãŒã³ãæ©èœããããšã確èªããŠããŸããæ€èšŒãããªãã£ãããš: Discord ã®å®éã®ãµãŒããŒã«å¯Ÿããå®éã® Gateway ãã³ãã·ã§ã€ã¯ (Hello â Identify â READY)ãDiscord èªèº«ã®èš±å®¹ç¯å²äžã§ã®å®éã®ããŒãããŒãã®ã¿ã€ãã³ã°ããã㊠Discord Developer Portal ã§å®éã®ãããã«å¯Ÿã㊠MESSAGE_CONTENT ãæå¹å/æ¿èªãããåŸã®ãããã©ã«ãã® intents ã®å€ (GUILDS+GUILD_MESSAGES+DIRECT_MESSAGES+MESSAGE_CONTENT = 37377) ãå®éã«ã¡ãã»ãŒãžã³ã³ãã³ããåä¿¡ããã®ã«ååã§ãããã©ããã§ããæ¬çªã§ããã«äŸåããåã«ãå®éã® botTokenEnvVar ã«çŽä»ãã Discord ããã (MESSAGE_CONTENT ãæå¹åæžã¿) ãæã€ãããžã§ã¯ãã«å¯ŸããŠãå°ãªããšãäžåºŠã¯æåã§ bxAgents serve ãå®è¡ããŠãã ããã
EmailGatewaySpec.bx ã¯ããã倧ããªããŒãžã§ã³ã®åãã®ã£ãããæ±ããŠããŸããåä¿¡ IMAP ã¯ã泚å
¥å¯èœãª setImapPoller() ã·ãŒã (çŒ¶è©°ã®æ£èŠåæžã¿ã¡ãã»ãŒãžæ§é äœãå®éã®ã¡ãŒã«ããã¯ã¹ãªã) ãéããŠå®å
šã«ãã¹ããããŠãããéä¿¡ãæ³šå
¥å¯èœãª setMailService() ã·ãŒã (MailService@cbmailservices ã®ä»£ãããšãªã FakeMailService/FakeMail) ãéããŠå®å
šã«ãã¹ããããŠããŸã - ãããã®ã¹ããã¯ã§ã¯ EmailGateway ã¯å®éã® WireBox ãäžåééããŸãããå®éã® ColdBox ã®èµ·åãååšããªãããã§ããä»åã®ã»ãã·ã§ã³ã§ (ã¢ãã¯ã§ã¯ãªããæ³å®ã§ããªã) å®éã«çŽæ¥æ€èšŒãããããš: fetchInboundMessages() ãäŸåããå®éã® jakarta.mail API è¡šé¢ (Session.getDefaultInstance()ãFlags/Flags.Flag/FlagTermãStore.getStore("imaps")ãFolder.READ_WRITEãMimeMultipartãInternetAddress) ããå®éã® jakarta.mail-api/Angus Mail ã® jar (ãããã¯ãã®ãªããžããªèªèº«ã®ãã¹ãã¯ã©ã¹ãã¹ã«ãã³ããªã³ã°ãããŠããªããããããã®ããã«ã¹ã¿ã³ãã¢ãã³ã§ããŠã³ããŒããããŸãã) ã«å¯ŸããŠç¢ºèªãã䜿ãããŠãããã¹ãŠã®ã¯ã©ã¹/ã¡ãœããåãå®éã«ååšã解決ãããããšã確èªããŸãããå°éäžèœãªã¢ãã¬ã¹ã«å¯Ÿããå®éã® Store.connect() ãã(ãã€ãã¹ããããã«ããŒã§ã¯ãªã) EmailGateway.pollInbox() èªäœãéããŠé§åãããšãçžäºéçš/ãã£ã¹ããšã©ãŒã§ã¯ãªãããã¬ãŒã³ãªæ¥ç¶ã¿ã€ã ã¢ãŠããšã©ãŒã§å€±æããçžäºéçšãã§ãŒã³ãå®éã®ãããã¯ãŒã¯å¢çã«æ£ããå°éããããšã確èªããŸãããSlack/Discord ã® websocket ã¹ã¢ãŒã¯ãã¹ããšåãèŠåŸã§ããæç€ºçã«æ€èšŒãããªãã£ãããšããããŠãã£ãããã©ãããã©ãŒã ã®ã²ãŒããŠã§ã€ãããå³å¯ã«å€§ããªã®ã£ããã§ããããš: å®éã®ã¡ãŒã«ããã¯ã¹ã«å¯Ÿããå®éã® IMAP ãã³ãã·ã§ã€ã¯ã¯ãªãããã®ãªããžããªã«ããã®ãã¹ãããŒãã¹ã«ããå®éã® cbmailservices/bx-mail ã¢ãžã¥ãŒã«ãã€ã³ã¹ããŒã«ãããŠããŸãã (bx-ai/TestBox ã®ããã«ã¯ãã³ããªã³ã°ãããŠããŸãã - åãã¯ãŒã¯ã¢ã©ãŠã³ããå¥ã®ã¢ãžã¥ãŒã«ã«é©çšãããŠããäžèšã®ã¹ãããã·ã§ããé
å»¶ã®ãšã³ããªãåç
§ããŠãã ãã)ããã®ãã WireBox ã®è§£æ±ºãã¹ (MailService@cbmailservices ãå®éã«ååšããããšãBXMail ã® bx:mail åŒã³åºããå®éã«éä¿¡ããããš) ã¯ãã¢ãã¯ã§ãå®ç©ã§ãããã®ã³ãŒãããŒã¹ã§äžåºŠãæŒç¿ãããŠããŸãããæ¬çªã§ãã®ã²ãŒããŠã§ã€ã«äŸåããåã«ãå®éã® IMAP èªèšŒæ
å ±ãšå®éã«ã€ã³ã¹ããŒã«ããã cbmailservices/bx-mail (box install ãæåããmoduleSettings.cbmailservices ã解決ããããšã確èª) ãæã€ãããžã§ã¯ãã«å¯ŸããŠãå°ãªããšãäžåºŠã¯æåã§ bxAgents serve ãå®è¡ããŠãã ãã - ããã¯ããããŸã§ã«åºè·ããã 4 ã€ã® push åã²ãŒããŠã§ã€ã®äžã§æãæ€èšŒãèããã®ã§ãã
WhatsAppCloudGatewaySpec.bx ã¯ãã¢ãã¯ã§ã¯ãªããã²ãŒããŠã§ã€èªèº«ã®ããžãã¯ãæ¬ç©ãšããŠååã«ã«ããŒããŠããŸã: çœ²åæ€èšŒãã¹ã¯ãå®éã«èšç®ããã HMAC-SHA256 眲å (javax.crypto.Mac/SecretKeySpecãBoxLang ã®èšç®ãä¿¡é Œããåã«ãä»åã®ã»ãã·ã§ã³ã§ openssl dgst -hmac ãš Python èªèº«ã® hmac ã¢ãžã¥ãŒã«ã®äž¡æ¹ã«å¯ŸããŠç¬ç«ããŠã¯ãã¹ãã§ãã¯ãããŸãã - å®éã®åç
§ãã¯ãã«ã®äžäžèŽãæãŸããŸãããããã㯠BoxLang ã®ãã°ã§ã¯ãªããæã§ã³ããŒããæåŸ
å€ã®ã¿ã€ããã¹ã§ãã£ãããšã倿ããŸããããããããã¯ã¯ãã¹æ€èšŒã ããæãŸãããããã®ã§ã) ã§æŒç¿ãããŠãããverify ãã³ãã·ã§ã€ã¯ãwebhook ã®ãã£ã¹ããã/éè€æé€ãéä¿¡ãã€ã³ã¿ã©ã¯ãã£ããªãã¿ã³/ãªã¹ãã®ã¬ã³ããªã³ã°ã¯ãã¹ãŠãéä¿¡ã® Graph API HTTP åŒã³åºãã ããã¹ã¿ãåããã (setApiCaller()) ç¶æ
ã§ãã²ãŒããŠã§ã€ã®å®éã®å
¬éã¡ãœãããéããŠé§åãããŠããŸããæ€èšŒãããªãã£ãããš: çæããã handlers/WhatsAppCloud.bx èªèº«ã® ColdBox ãªã¯ãšã¹ãã³ã³ããã¹ãåŒã³åºã (event.getHTTPContent()/event.getHTTPHeader()/event.renderData()ãGET ãã³ãã·ã§ã€ã¯çšã® rc ã® URL ã¹ã³ãŒãã«ããŒãžããããããåºåãããŒã®ã¯ãšãªãã©ã¡ãŒã¿ã¢ã¯ã»ã¹) ããå®éã® ColdBox ã®èµ·åã«å¯ŸããŠè¡ãããšã§ã - ãããã¯ææžåãããæšæºç㪠ColdBox REST ãã³ãã©ã®ã€ãã£ãªã ã§ã (ColdBox èªèº«ã® "Building REST APIs" ã¬ã·ãããã¥ã¡ã³ãã«ç
§ãããŠç¢ºèªæžã¿ã§ãæšæž¬ã§ã¯ãããŸãã)ããã®ãã¡ã€ã«ã®ä»ã®ç®æã§èª€ãã ã£ãããšã倿ããææžåãããŠããªã aiGatewayRegistry() ã®ããŒã®æ³å®ããã¯ãæå³ã®ãã圢ã§ããä¿¡é Œã§ããåºçºç¹ã§ããããææžåãããŠãããããšã¯ããã®çæãããã³ã³ããã¹ãã§åäœãããšèšŒæãããŠãããããšãšã¯éããŸãããã®ãããžã§ã¯ãèªèº«ã®å®éã® runColdBoxIntegrationTests.bxs/miniserver ããŒãã¹ãæ¡åŒµããŠãããã«ããŒããã«ã¯ãå¥éèµ·åããã miniserver ãµãããã»ã¹ã«ãã§ã€ã¯ã®ç°å¢å€æ°ãæž¡ã (ãã®ããã®æ¢åã®ä»çµã¿ã¯ãããŸãã) ããä»ã®åæ ŒããŠãããã¹ããäŸåããŠããå
±æã® e2e-coldbox-route ãã£ã¯ã¹ãã£ã§å®éã® config é¢é£ã®èµ·å倱æã®ãªã¹ã¯ãåããã®ãããããå¿
èŠã§ãããã¬ãžã¹ããªããŒã®ãã°ããããå®éã«ééã£ãŠãã確床ãäœãããã®ã®ã£ããã®ããã«ãã®ççºååŸãåããããèŠéãããŸãããæ¬çªã§ãã®ã«ãŒãã«äŸåããåã«ãå®éã« bxAgents serve ãè¡ãã/webhooks/whatsapp-cloud ã«å¯Ÿããæ¬ç©ã® Meta Webhook ãã¹ã (ããã㯠curl) ãå°ãªããšãäžåºŠã¯è¡ã£ãŠãã ãããå®éã® Graph API åŒã³åºããäžåºŠãè¡ãããŠããŸãã - deliver()/requestHumanInteraction() ã® HTTP ã¬ã€ã€ãŒã¯ apiCaller ãã¹ãã·ãŒã ãéããŠã®ã¿æŒç¿ãããŠããŸãã
TeamsGatewaySpec.bx ã¯ãã¢ãã¯ã§ã¯ãªããã²ãŒããŠã§ã€èªèº«ã®ããžãã¯ãæ¬ç©ãšããŠååã«ã«ããŒããŠããŸã: JWT ã®æ€èšŒã¯ãå®éã«çæããã 2048 ãããã® RSA éµã㢠(java.security.KeyPairGenerator) ãšãã¹ããã¯å
ã«ãã¹ãŠçµã¿èŸŒãŸããæçœ²åã®ãã¹ã JWT (äºåèšç®ããããã£ã¯ã¹ãã£ãªãããã¹ãæã®å€éš openssl äŸåãªã) ã«å¯ŸããŠæŒç¿ãããŠãããæå¹ãªçœ²åã¯åçãããã£ã¹ããããããäžæ¹ã§ãæ¹ããããã眲åã誀ã£ã audã誀ã£ã issãæéåãã® exp ã¯ãããããç¬ç«ã㊠401 ã§æåŠãããããšã確èªãããŠããŸããinvoke ã¢ã¯ãã£ãã㣠(Adaptive Card ãã¿ã³ã¯ãªãã¯) ãã¹ãã¡ãã»ãŒãžãã£ã¹ããããå人ã¹ã³ãŒãã®ã¿ã®ãã£ã«ã¿ãªã³ã°ãreplyToId ã«ããã¹ã¬ããã£ã³ã°ããã£ã³ãã³ã°ãAdaptive Card ã®ã¬ã³ããªã³ã°ã¯ãéä¿¡ã® Connector REST åŒã³åºãã ããã¹ã¿ãå (setApiCaller()) ãããJWKS/OAuth2 ããŒã¯ã³ã®ååŸãã¹ã¿ãåããã (setJwksFetcher()/setTokenFetcher()) ç¶æ
ã§ããã¹ãŠã²ãŒããŠã§ã€ã®å®éã®å
¬éã¡ãœãããéããŠé§åãããŠããŸããæ€èšŒãããªãã£ãããš: çæããã handlers/Teams.bx èªèº«ã® ColdBox ãªã¯ãšã¹ãã³ã³ããã¹ãåŒã³åºãããå®éã® ColdBox ã®èµ·åã«å¯ŸããŠè¡ãããš (WhatsApp Cloud èªèº«ã®ãã³ãã©ãšåãã«ããŽãªã®ã®ã£ããã§ãåãçç±ã§èŠéãããŠããŸã - äžèšã®ãã®ãšã³ããªãåç
§)ãå®éã® OAuth2 ããŒã¯ã³ååŸã Connector REST åŒã³åºãããMicrosoft ã®å®éã®ãšã³ããã€ã³ãã«å¯ŸããŠè¡ãããããšã¯äžåºŠããããŸããããããŠãã€ã³ã¹ã¿ã³ã¹ã®çåæéäž JWKS ããã£ãã·ã¥ããããšãããã¬ãŒããªã (docs/conventions/gateways.md ã® Teams ã»ã¯ã·ã§ã³åç
§) ã¯ãå®éã®éµããŒããŒã·ã§ã³ã®ã·ããªãªãäžåºŠãæŒç¿ãããŠããªãããšãæå³ããŸããæ¬çªã§ãã®ã²ãŒããŠã§ã€ã«äŸåããåã«ãå®éã« bxAgents serve ãè¡ããå®éã® Teams ã¢ããªç»é² (Azure/Bot Framework ããŒã¿ã«ããã® App ID/ãã¹ã¯ãŒã) ãšå®éã® Teams ã¯ã©ã€ã¢ã³ãããã® DM éä¿¡ããå°ãªããšãäžåºŠã¯è¡ã£ãŠãã ããã
TwilioGatewaySpec.bx ã¯ãã¢ãã¯ã§ã¯ãªããã²ãŒããŠã§ã€èªèº«ã®ããžãã¯ãæ¬ç©ãšããŠååã«ã«ããŒããŠããŸã: X-Twilio-Signature ã® HMAC-SHA1/base64 æ€èšŒãã¹ã¯ãã¹ããã¯å
ã§ã€ã³ã©ã€ã³ã«çµã¿ç«ãŠãããå®éã«èšç®ããã眲åã§æŒç¿ãããŠãããBoxLang ã®å®è£
ãä¿¡é Œããåã«ãä»åã®ã»ãã·ã§ã³ã§ Python èªèº«ã® hmac/hashlib ã¢ãžã¥ãŒã«ã«å¯ŸããŠç¬ç«ããŠã¯ãã¹ãã§ãã¯ãããŸãã (WhatsApp Cloud èªèº«ã® HMAC-SHA256 ã¯ãã¹ãã§ãã¯ãšåãèŠåŸã§ã) - æ¢ç¥ã®èªèšŒããŒã¯ã³/URL/ãã©ã¡ãŒã¿ã®çµã¿åããã«å¯Ÿããå®éã®åç
§çœ²åã Python ã§èšç®ãããBoxLang ã®åºåãšæ£ç¢ºã«äžèŽããããšã確èªãããŠããŸãããã©ãŒã ããã£ã®ããŒã¹ (ãªãã©ã«ãª + ã %2B ããŒã»ã³ããšã³ã³ãŒãã£ã³ã°ãéããŠæ£ããåŸåŸ©ããããšãå«ã)ããããã·/ãã³ãã«ãããã€çšã® publicUrl ãªãŒããŒã©ã€ããTwiML ã®å³æç¢ºèªå¿çãšéåæ REST è¿ä¿¡ã®ãã¥ã¢ã«ãã¹ã¢ãã«ãéä¿¡ãã£ã³ãã³ã°ããããŠé»è©±çªå·ããŒã® HITL è¿ä¿¡ã®çŽä»ãã¯ãéä¿¡ã® Messages API HTTP åŒã³åºãã ããã¹ã¿ãåããã (setApiCaller()) ç¶æ
ã§ããã¹ãŠã²ãŒããŠã§ã€ã®å®éã®å
¬éã¡ãœãããéããŠé§åãããŠããŸããæ€èšŒãããªãã£ãããš: çæããã handlers/Twilio.bx èªèº«ã® event.getUrl() åŒã³åºãããå®éã® ColdBox ã®èµ·åã«å¯ŸããŠè¡ãããš (WhatsApp Cloud/Teams èªèº«ã®ãã³ãã©ãšåãã«ããŽãªã®ã®ã£ããã§ãåãçç±ã§èŠéãããŠããŸã) - event.getUrl() ã¯ææžåããã ColdBox ã® Routable/Request Context ã¡ãœããã§ã (ColdBox ã®ããã¥ã¡ã³ã MCP çµç±ã§ç¢ºèªæžã¿ã§ãæšæž¬ã§ã¯ãããŸãã) ãããææžåãããŠãããããšã¯ããã®çæãããã³ã³ããã¹ãã§èšŒæãããŠãããããšã§ã¯ãããŸãããå®éã® Twilio Messages API åŒã³åºããäžåºŠãè¡ãããŠããŸãããæ¬çªã§ãã®ã«ãŒãã«äŸåããåã«ãå®éã« bxAgents serve ãè¡ããå®éã® Twilio é»è©±çªå·ã® Webhook ãã¹ããå°ãªããšãäžåºŠã¯è¡ã£ãŠãã ãã - ãããŠãé»è©±çªå·ããŒã® HITL çŽä»ã (docs/conventions/gateways.md ã® Twilio ã»ã¯ã·ã§ã³åç
§) ã«ã¯ãå®éã®ãææžåãããå¶éãããããšã«æ³šæããŠãã ãã: åãé»è©±çªå·ãžã® 2 åç®ã® HITL ãªã¯ãšã¹ãããæåã®ãã®ããŸã çããããŠããªãç¶æ
ã§æ¥ããšãæåã® pendingApprovals ãšã³ããªãäžæžãããŠããŸãããµã€ã¬ã³ãã«ãããå€ç«ãããŠããŸããŸããåä¿¡ SMS ã«å¯Ÿããã¢ããŒãªã¹ã/ã¬ãŒãå¶éãæ§ç¯ãããŠããŸãã - èªèº«ã® allowFrom config ããå¿
é ãã§ãããšææžåã¯ããŠãã (ãã³ãŒãäžã§ã¯åŒ·å¶ããŠããªã) Eve ãšã¯ç°ãªãããã®ç§»æ€çã«ã¯ãããšåçã®ã²ãŒãããŸã£ãããããŸãããã©ããªé»è©±çªå·ã§ããããã€ããã Twilio çªå·ã«ã¡ãã»ãŒãžãéã£ãŠãšãŒãžã§ã³ãã«å°éã§ããŸãã
GitHubGatewaySpec.bx ã¯ãã¢ãã¯ã§ã¯ãªããã²ãŒããŠã§ã€èªèº«ã®ããžãã¯ãæ¬ç©ãšããŠååã«ã«ããŒããŠããããã®ã²ãŒããŠã§ã€ã®ã³ã¢ããžãã¯ã¯ããã«ãéçºäžã« (æä¹
çãªã¹ããã¯ã ãã§ãªã) ã¹ã¿ã³ãã¢ãã³ã®å®éã® BoxLang ã«ããã¹ã¢ãŒã¯ãã¹ããéããŠé§åãããŸãã - ããããæ¬ç©ã®ãã°ããã¹ãã¹ã€ãŒãã«äžåºŠãå±ãåã«æãŸã£ãçµç·¯ã§ã: ã¡ã³ã·ã§ã³æœåºãã«ããŒã®éšåæååããžãã¯ã¯ã@mention ãã³ã¡ã³ãã®æ¬åœã«å
é ã«ããå Žå (éåžžã«ããããã±ãŒã¹ã§ã) ã«ã¯åžžã« left( body, 0 ) ãåŒã³åºããŠãããBoxLang ã® left() ã¯ãŒãæåæ°ã«å¯ŸããŠç©ºæååãè¿ã代ããã« "Count cannot be zero" ãæããŸã - å®éã®ã³ã¡ã³ãæ¬æã§ãããããªã¬ãŒããããšã§ç¢ºèªãããleft()/mid() ããŒãé·ã蚱容ãããšæ³å®ããã®ã§ã¯ãªãããŒãé·ã®ã±ãŒã¹ãæç€ºçã«åå²ãããããšã§ä¿®æ£ãããŸãããX-Hub-Signature-256 ã®æ€èšŒã@mention ã®æ£èŠè¡šçŸå
èªã¿ã²ãŒã (mybot ãšããååã®ãããã @mybot2 ã§ã¯çºç«ããªãããšããå°çšã®ã¹ã¢ãŒã¯ãã¹ãã§ç¢ºèªæžã¿)ããããã«ãŒãã®ã¬ãŒããé
ä¿¡ ID ã®éè€æé€ãissue ãšã¬ãã¥ãŒã¹ã¬ããã®äŒè©±ã¢ã€ãã³ãã£ãã£ãdeliver()ããã㊠@mention ããè¿ä¿¡ãžã® HITL çŽä»ãã¯ãéä¿¡ã® GitHub REST åŒã³åºãã ããã¹ã¿ãåããã (setApiCaller()) ç¶æ
ã§ããã¹ãŠã²ãŒããŠã§ã€ã®å®éã®å
¬éã¡ãœãããéããŠé§åãããŠããŸããæ€èšŒãããªãã£ãããš: çæããã handlers/GitHub.bx ãå®éã® ColdBox ã®èµ·åã«å¯ŸããŠè¡ãããš (ãã®ãããžã§ã¯ãã®ä»ã®ãã¹ãŠã® Webhook ã²ãŒããŠã§ã€èªèº«ã®ãã³ãã©ãšåãã«ããŽãªã®ã®ã£ããã§ãåãçç±ã§èŠéãããŠããŸã)ãå®éã® GitHub API åŒã³åºãã¯äžåºŠãè¡ãããŠããããå®éã® GitHub App/PAT ãå®éã®ãªããžããªã«å¯ŸããŠäœ¿ãããããšããããŸãã - æ¬çªã§ãã®ã²ãŒããŠã§ã€ã«äŸåããåã«ãå®éã« bxAgents serve ãè¡ãããã¹ããªããžããªã«å¯ŸããŠèšå®ãããå®éã® GitHub Webhook ããå°ãªããšãäžåºŠã¯è¡ã£ãŠãã ããã
SignalGatewaySpec.bx ã¯ãã¢ãã¯ã§ã¯ãªããã²ãŒããŠã§ã€èªèº«ã®ããžãã¯ãæ¬ç©ãšããŠååã«ã«ããŒããŠããŸã: handleSseEvent() ã® JSON-RPC/SSE ããŒã¹ (空è¡/äžæ£ãª JSON ã®åŠçãã°ã«ãŒãã¡ãã»ãŒãžã®ãã£ã«ã¿ãªã³ã°ãåŒçšã¹ã¬ããã£ã³ã°ã衚瀺åããªãå Žåã® sourceUuid ãã©ãŒã«ããã¯)ãdeliver() ã®éä¿¡ã®åœ¢ãšãã£ã³ãã³ã°ããã㊠HITL 決å®ã®çŽä»ã/ãããã³ã°ã¯ããã¹ãŠéä¿¡ã® rpcCaller/connector ã® I/O åŒã³åºãã ããã¹ã¿ãåãããç¶æ
ã§ãã²ãŒããŠã§ã€ã®å®éã®å
¬éã¡ãœãããéããŠé§åãããŠããŸãããã®ãããžã§ã¯ãã®ä»ã®ãã¹ãŠã®ã²ãŒããŠã§ã€ãšåãã·ãŒã ãã¹ãã®èŠåŸã§ããéçºäžã« 2 ã€ã® BoxLang ã¬ãã«ã®çºèŠããããã©ã¡ãã解決æžã¿ã§ãã²ãŒããŠã§ã€åºæã®ãã°ãšããããäžè¬çãªå°é·ãšããŠèšé²ãã䟡å€ããããŸã: (1) ããŒã«ã«å€æ°ã request ãšåä»ããã¹ã¿ã³ãã¢ãã³ã®ã¹ã¢ãŒã¯ãã¹ãã¹ã¯ãªãããããã¬ãŒã³ãªå€æ°ãäœã代ããã«ããµã€ã¬ã³ãã« BoxLang èªèº«ã®äºçŽæžã¿ request ã¹ã³ãŒããšçžäºäœçšããŠãããæ¬ç©ã® Java çžäºéçšã®å¶éã®ããã«èŠãã (ããã倿°åãå€ãããšãŸã£ããæ¶ãã) ãmethod not foundã/ãargument type mismatchããšããçŽãããããšã©ãŒã HttpClient.send() ããåºããŠããŸãã - SignalGateway.bx èªäœã«ã¯äžåºŠããã°ã¯ãããŸããã§ããã(2) ã¹ã¿ã³ãã¢ãã³ã® .bxs ã¹ã¢ãŒã¯ãã¹ãã¹ã¯ãªããã® (颿°ã®å
éšã§ã¯ãªã) ãããã¬ãã«ã«çŽæ¥çœ®ããã try/catch ã java.lang.VerifyError: Inconsistent stackmap frames ãããªã¬ãŒããŸããããã㯠BoxLang ã®ãããã¬ãã«ã¹ã¯ãªããã³ã³ãã€ã©ã®æ¬ç©ã®ãã€ãã³ãŒãæ€èšŒã®å¶éã§ãã¹ã¿ãã¯ãã¬ãŒã¹ã蟿ã£ãŠãã¹ãã¹ã¯ãªããèªèº«ã®çæãããã¯ã©ã¹ã§ããããšã倿ããSignalGateway.bx ã®ãã®ã§ã¯ãããŸããã§ãã - try/catch ãååä»ãã®é¢æ°ã®å
éšã«ã©ããããããšã§ä¿®æ£ãããŸãããæ€èšŒãããªãã£ãããšããããŠãããŸã§ã«åºè·ããããã¹ãŠã® push åã²ãŒããŠã§ã€ã®äžã§æå€§ã®ã®ã£ããã§ããããš: ãã®ç°å¢ã«ã¯å®éã® signal-cli ããŒã¢ã³ãäžåºŠãå©çšå¯èœã§ãªãã£ããããéåæ SSE æ¥ç¶ã®ã©ã€ããµã€ã¯ã«å
šäœ - HttpClient.sendAsync()+BodyHandlers.ofLines() ã«ããã¹ããªãŒã ã®ãªãŒãã³ãæ¬åœã«äžå®å®ãªæ¥ç¶ã«å¯Ÿããææ°ããã¯ãªãã®åæ¥ç¶ã«ãŒãã30 ç§/120 ç§ã®ã¢ã€ãã«ãŠã©ããããã°ã匷å¶ãã忥ç¶ããããŠã©ã€ã㪠JSON-RPC ã®ã©ãŠã³ãããªãã - ã¯ãäžåºŠããšã³ãããŒãšã³ãã§æŒç¿ãããŠããããçžäºéçšã®ãã©ãã³ã°ã¬ãã«ã§ã¹ã¢ãŒã¯ãã¹ããããŠããã ãã§ã (ã¹ã¿ã³ãã¢ãã³ã®ãã¹ããå°éäžèœãªã¢ãã¬ã¹ã«å¯ŸããŠå®éã® java.net.ConnectException ã«å°éãããã§ãŒã³ãå¥å
šã§ããããšã蚌æããŠããŸãããã©ã€ããªããŒã¢ã³ã«å¯ŸããŠåäœããããšã®èšŒæã§ã¯ãããŸãã)ãæ¬çªã§ãã®ã²ãŒããŠã§ã€ã«äŸåããåã«ãå®éã«çšŒåããŠãã signal-cli ããŒã¢ã³ãšå®éã«ãªã³ã¯ããã Signal ã¢ã«ãŠã³ããæã€ãããžã§ã¯ãã«å¯ŸããŠãå°ãªããšãäžåºŠã¯æåã§ bxAgents serve ãå®è¡ããŠãã ãã - ããã¯ãã®ã³ãŒãããŒã¹ã«ãããŠæ¬åœã«æ°ãã転éã¢ãŒããã¯ãã£ã§ãã (Telegram/Slack/Discord/Email/Signal ã®äžã§å¯äžã® SSE ããŒã¹ã®ã²ãŒããŠã§ã€ã§ã)ããã§ã«èšŒæãããŠãã転é圢ã®äžã®åãªãæ°ãããã©ãããã©ãŒã ã§ã¯ãããŸããã
WhatsApp Personal (éå ¬åŒã®å人ã¢ã«ãŠã³ãããªããž) - èª¿æ»æžã¿ãæªæ§ç¯
å
ã
ã®èšç» (Hermes Agent èªèº«ã®ã¢ãŒããã¯ãã£ã«åããããã®) ã¯ã@whiskeysockets/baileys (Hermes èªäœã䜿ãããã«ãããã€ã¹ WhatsApp Web ãããã³ã«ã¯ã©ã€ã¢ã³ãã§ãMIT ã©ã€ã»ã³ã¹ã§ãããã®å®å
šãª bridge.js ã¯èŠçŽã§ã¯ãªããä»åã®ã»ãã·ã§ã³ã§ Hermes ã®å®éã®ãœãŒã¹ããçŽæ¥èªã¿èŸŒãŸããŸãã) ãå®è¡ãã Node.js ãµãããã»ã¹ãèµ·åããããšã§æ§ç¯ããã WhatsAppPersonalGateway ãæ±ããŠããŸããããã®ã¢ãããŒãã¯ããµãããã»ã¹ããªããžããããã€ãã£ã㪠BoxLang/JVM ã®çµ±åãåªå
ãããã€ãã£ã㪠Java ã©ã€ãã©ãªã䜿ãã®ã¯ããããªãŒãã³ãœãŒã¹ã§ GPL ã§ã LGPL ã§ããªãå Žåã«éããšããçŽæ¥ã®æç€ºãåããã»ãã·ã§ã³ã®éäžã§èŠéãããŸããã
ãã®èª¿æ»ã§èŠã€ãã£ãã®ã Cobalt (com.github.auties00:cobaltãæ§ WhatsappWeb4j) ã§ã - ããã¯å®åšãããMIT ã©ã€ã»ã³ã¹ã®ã掻çºã«ã¡ã³ããã³ã¹ãããŠãã (900 以äžã®ã¹ã¿ãŒ) WhatsApp ã®ãã«ãããã€ã¹ããªã³ã¯ã¯ã©ã€ã¢ã³ãããããã³ã«ã® Java å®è£
ã§ãææžåãããæµæ¢ãª API (WhatsAppClient.builder().linkedApi().webClient()...ãaddNewMessageListener()ãsendMessage()) ãæã¡ãåäžæœè±¡ã¡ãœããã®ãªã¹ããŒã«å¯Ÿã㊠BoxLang èªèº«ãææžåããŠãã Java-SAM 匷å¶ãããããã«å€æã§ããŸã (BoxLang ã®ããã¥ã¡ã³ã MCP çµç±ã§ç¢ºèªæžã¿ã§ãåäžæœè±¡ã¡ãœããã®ãªã¹ããŒã« createDynamicProxy() ã¯äžèŠã§ã)ãæ€èšŒäžã«ãæšæž¬ã§ã¯ãªãå®éã« 2 ã€ã®å®åšãããããã«ãŒã衚é¢åããŸãã:
- æåã«èªãã pom.xml (Cobalt ã®
masterãã©ã³ããé²è¡äžã®ãã«ãã¢ãžã¥ãŒã«ã®æžãçŽã) 㯠Java 25 ãèŠæ±ããŸã - ãã㯠BoxLang èªèº«ãææžåããŠããããŒã¹ã©ã€ã³ (Java 21 以äžãBoxLang ã®ããã¥ã¡ã³ã MCP çµç±ã§ç¢ºèªããããã®ãããžã§ã¯ãèªèº«ã®21.0.10ã® JDK ãšäžèŽããŠããŸã) ãã 2 ã¡ãžã£ãŒããŒãžã§ã³å ã§ããå®éã« Maven Central ã«å ¬éãããŠããã¢ãŒãã£ãã¡ã¯ã (cobalt:0.0.10ã<dependency>ã仿¥å®éã«è§£æ±ºãããã®ã§ãæªãªãªãŒã¹ã®æžãçŽãã§ã¯ãããŸãã) ã«å¯ŸããŠåãã§ãã¯ãããšã<java.version>21</java.version>ã瀺ãããŸãã - ã€ãŸã Java 25 ã®çºèŠã¯ãééã£ããã©ã³ããèªãã ããšã«ãã誀èŠå ±ã§ãããæ¬ç©ã®ãããã«ãŒã§ã¯ãããŸããã§ãããæ³šæç¹ãšããŠèšé²ãã䟡å€ããããŸã: GitHub ãªããžããªã®ããã©ã«ããã©ã³ãã®pom.xmlã¯ãå¿ ããã Maven Central ã«ãããã®ãšåãã§ã¯ãããŸããã - å®éã«å
¬éãããŠãã
cobalt:0.0.10ã¯ãcom.aspose:aspose-wordsãããŒããªã³ã³ãã€ã«æäŸåãšããŠåŒã蟌ã¿ãŸã (Word ææžãããªã³ã¯ãã¬ãã¥ãŒã®ãµã ãã€ã«ãçæããããã«å éšã§äœ¿ãããŠããŸã) - Aspose.Words for Java ã¯åçš/ãããã©ã€ãšã¿ãªãªã©ã€ã»ã³ã¹ã§ããããªãŒãã³ãœãŒã¹ã§ã¯ãããŸããããã®ãããããããã³ãã«ãããšãCobalt èªäœãããããæºããããã«éžã°ããã®ãšåãã©ã€ã»ã³ã¹å¶çŽã«éåããããšã«ãªããŸããå®å šãªäŸåé¢ä¿ã°ã©ã (çŽ 15 åã® jar: zxingãqr-terminalãcurve25519ãprotobuf-baseãããŒãžã§ã³ã«ãã£ãŠ jackson ã fastjson2ãlibphonenumberãdd-plistãapk-parserãlink-previewãjaffreeãez-vcardãslf4jããã㊠Aspose) ã¯ãã¹ãŠæåã§ããŠã³ããŒããããã®ã¢ãžã¥ãŒã«ã®libs/ãã©ã«ãã«ãã³ãã«ããå¿ èŠããããŸã - BoxLang ã®ã¢ãžã¥ãŒã«ã«ã¯ãç¬èªã® Maven 颚ã®äŸåé¢ä¿è§£æ±ºããããŸãã (BoxLang ã®ããã¥ã¡ã³ã MCP çµç±ã§ç¢ºèªæžã¿ã§ã: ãµãŒãããŒãã£ã® jar ã¯ã¢ãžã¥ãŒã«ã®libs/ãã©ã«ãã«çŽæ¥ãã³ãã«ãããã¢ãžã¥ãŒã«ããšã®ã¯ã©ã¹ããŒããŒã«ãã£ãŠããŒããããŸã - äŸåé¢ä¿ã°ã©ããèªåçã«è§£æ±ºããjavaLibrariesããŒã¯box.jsonã«ã¯ãããŸãã)ã
Aspose ã«ããã©ã€ã»ã³ã¹æ±æãšãçµæãå®éã«ããŒããããããšãæ€èšŒããäŸåé¢ä¿è§£æ±ºããŒã«ãäžåãªãäžã§ã®æäœæ¥ã«ãããã¡ãã jar çµã¿ç«ãŠã®æéãèæ
®ããWhatsApp Personal ã¯ãå®éã®ã²ãŒããŠã§ã€ãšããŠããã¹ã¿ããšããŠãåºè·ããããã¹ã³ãŒãå€ãšãããŸãããProjectValidator ã® validGatewayTypes ãš GatewayGenerator ã® TYPE_CLASS_MAP ã«ã¯ whatsapp-personal ãšã³ããªãå«ãŸããŠããŸãã - type: "whatsapp-personal" ã宣èšããããšãããããžã§ã¯ãã¯ã誀解ãæãåç«¯ã«æ§ç¯ãããã¹ã¿ãã§ã¯ãªããä»ã®ããããæªãµããŒãã¿ã€ããšåããunknown gateway typeãæ€èšŒãšã©ãŒã«ãªããŸãããããèŠçŽãã®ã¯ãCobalt ããã€ã Aspose ãžã®äŸåãèœãšããå Žå (ããã¯çãæ©èœã§ã - Word ææžã®ãªã³ã¯ãã¬ãã¥ãŒã®ãµã ãã€ã«åã§ãããã¡ãã»ãŒãžã³ã°ã®ã³ã¢ã§ã¯ãããŸãã)ããããã¯å°æ¥ã®ã»ãã·ã§ã³ãã(ä»åã¯ã¢ãŒããã¯ãã£ã®å¥œã¿ã§åŽäžããããæè¡çãªãããã«ãŒã§ã¯ãªã) Node/Baileys ãµãããã»ã¹ããªããžã¢ãããŒãããã¯ãéžã¶ãšå€æããå Žåã«ã¯ã劥åœã§ãã
GatewaySession ã¯ãããžã§ã¯ãå
šäœã§ 1 ã€ããã€ã«ãŒããšãŒãžã§ã³ãå°çš (v1)
å°ãªããšã 1 ã€ã® push åã²ãŒããŠã§ã€ãšã³ããªãæã€ãããžã§ã¯ãã¯ãæ£ç¢ºã« 1 ã€ã®çæããã GatewaySession ãåŸãŸããããã¯ãã¹ãŠã® push åã²ãŒããŠã§ã€ããŸãšããåžžã«ãããžã§ã¯ãã®ã«ãŒããšãŒãžã§ã³ãã«æçžãããŸã - exposes: "agent" ã® HTTP å
¬éãåžžã«ã«ãŒããšãŒãžã§ã³ãã®ã¿ã§ãããšããæ¢åã®åäŸãšäžèŽããŠããŸã (gateways/ åç
§)ããµããšãŒãžã§ã³ããæã€ãããžã§ã¯ãã¯ããŸã ç°ãªãã²ãŒããŠã§ã€ãç°ãªããµããšãŒãžã§ã³ãã«ã«ãŒãã£ã³ã°ããããšã¯ã§ããŸãã (äŸãã°ãTelegram 㯠SupportBot ãšè©±ããSlack 㯠ResearchBot ãšè©±ãã)ãå°æ¥çãªããšãŒãžã§ã³ãããšã®ããŒãã® GatewaySession ã«æ¶è²»ããããã²ãŒããŠã§ã€ããšã® targetAgent: "SubagentName" ã㌠(ãããžã§ã¯ãå
šäœã§ 1 ã€ã®ã»ãã·ã§ã³ã®ä»£ããã«) ã¯ãèªç¶ãªæ¡åŒµãã€ã³ãã§ããããŸã æ§ç¯ãããŠããŸããã
ä¿®æ£æžã¿: GatewaySessionBootstrap.bx ã¯èª€ã£ã aiGatewayRegistry() ããŒã§ã²ãŒããŠã§ã€ãæ€çŽ¢ããŠãã (4 ã€ãã¹ãŠã® push åã²ãŒããŠã§ã€ã«ããã£ãŠå£ããç¶æ
ã§åºè·ãããŠãããWhatsApp ã®èª¿æ»ã®éçšã§çºèŠããã)
å®éã«ã以ååºè·ãããŠãããã°ã§ã: çæãããã€ã³ã¿ãŒã»ãã¿ãŒã® aiGatewayRegistry().get(...) åŒã³åºãã¯ãçºèŠããã gateways/* ãšã³ããªèªèº«ã®ãã¡ã€ã«å (äŸãã° gateways/telegramChannel.bx ããã® "telegramChannel") ã䜿ã£ãŠããŸããããbx-ai ã®å®éã® GatewayRegistry.register() ã¯åžžã«ã²ãŒããŠã§ã€ã¯ã©ã¹èªèº«ã®åºå®ããã getName() (äŸãã° TelegramGateway.init() ã§äžåºŠã ãèšå®ããã "telegram") ã§ããŒä»ãããŸã - åŒã³åºãå
ãæå®ãããã®ã¯äžå䜿ãããŸãããbx-ai ã®ãœãŒã¹ãçŽæ¥èªãããšãšãçµéšçã« (å®éã®ã²ãŒããŠã§ã€ãç»é²ãããã®çºèŠããããšã³ããªåã§ .get() ãåŒã³åºããš "No item found in registry" ãæããããããšã確èªããŠ) äž¡æ¹ã§ç¢ºèªæžã¿ã§ããããã¯ã€ãŸããGatewaySession ã®æ§ç¯ããpush åã²ãŒããŠã§ã€ãæã€ãã¹ãŠã®çæãããžã§ã¯ãã«ã€ããŠãColdBox ã®èµ·åæ (afterConfigurationLoad) ã«æããŠããŸãããšãæå³ããŠããŸãã - TelegramãSlackãDiscordãEmail ã¯ãã¹ãŠãã®ãã°ãšãšãã«åºè·ãããŠãããããã¯æ¢åã®ãã¹ãã«ãã¬ããžãçæããããã¡ã€ã«ã®çã®æååå
容ã«å¯ŸããŠã ãã¢ãµãŒãããã©ã€ããªã¬ãžã¹ããªã«å¯ŸããŠã¯äžåºŠãã¢ãµãŒãããŠããªãã£ããããæ€åºãããã«ããŸããã
GatewayGenerator.generate() ã§ä¿®æ£ãããŸãã: ãã®ã€ã³ã¿ãŒã»ãã¿ãŒã¯ä»ãããããã®ã²ãŒããŠã§ã€ã TYPE æåå (ãããŸã§ã«æ§ç¯ããããã¹ãŠã® push åã²ãŒããŠã§ã€ã«ãããŠãåžžã«ç»é²ãããååãšåäžã§ã) ã§ãéè€æé€ããªããæ€çŽ¢ããŸããGatewayGeneratorSpec.bx ã¯æä¹
çãªååž°ãã¹ããåŸãŸãããããã¯æ¬ç©ã®ã²ãŒããŠã§ã€ã€ã³ã¹ã¿ã³ã¹ãç»é²ãããžã§ãã¬ãŒã¿ãã¡ããã©åºåããããŒããã©ã€ã㪠aiGatewayRegistry() çµç±ã§ããã解決ããããšã蚌æããŸã - ããã¯ãæåã«ãããæ€åºãããã«åºè·ãããããšãèš±ããŠããŸã£ãããŸãã«ãã®ã®ã£ãããå¡ããã®ã§ãã
ãã®ä¿®æ£ã衚é¢åããããå®éã®æä¹
çãªåž°çµ (æ°ããæåã§ã¯ãªããæ£ããå°éå¯èœã«ãªã£ãã ãã§ã): ã¬ãžã¹ããªã¯ãšã³ããªã§ã¯ãªãã¿ã€ãã§ããŒä»ããããŠãããããåã push åã¿ã€ãã® gateways/* ãšã³ããªã 2 ã€ãããšããããžã§ã¯ãå
šäœã§åãã¬ãžã¹ããªã¹ãããã«è¡çªããŸã - äŸãã° type: "telegram" ã® 2 ã€ã®ãšã³ã㪠(ç°ãªã 2 ã€ã®ãããããŒã¯ã³) ã¯ã2 ã€ç®ã®ç»é²ããµã€ã¬ã³ãã«æåã®ãã®ãäžæžãããGatewaySession ã¯ãã®ãã¡ã®äžæ¹ããäžåºŠãèŠãããšããããŸããã仿¥æç¹ã§ã¯ããšã³ããªããšã®ãšã€ãªã¢ã¹/ç»é²åã®ãªãŒããŒã©ã€ãã¯ãããŸããããããžã§ã¯ãããã push åã¿ã€ãããšã« 1 ã€ã³ã¹ã¿ã³ã¹ããšããã®ãå®éã® v1 ã®äžéã§ã - ãã®ä¿®æ£ããããå¯èŠåãããŸã§ã¯ããã®ããã«ã¯ææžåãããŠããŸããã§ããã
./gradlew downloadModules ããGatewayGenerator ã® aiGatewayRegistry() ã³ãŒãçæã«äžæçã«é
ãã bx-ai ã®ã¹ãããã·ã§ãããååŸããããšããã
bx-ai 㯠development ãã©ã³ãã§ gatewayRegistry() ã aiGatewayRegistry() ã«ãªããŒã ããŸãã (çŽæ¥ç¢ºèªæžã¿ã§ã - bifs/gatewayRegistry.bx ã¯å®å
šã«åé€ãããåŸæ¹äºæã®ãšã€ãªã¢ã¹ã¯ãããŸãã)ãGatewayGenerator ã¯ããã«äžèŽããããæŽæ°ãããŸãããbx-ai ããŸã ãªãªãŒã¹ãã«ããããŠããªãããããã®ãããžã§ã¯ãèªèº«ã®æ¹éã¯ããããåé¿çã§èŠãé ãã®ã§ã¯ãªãããã®ãŸãŸè¿œåŸããããšã ã£ãããã§ããèœãšã穎: downloadModules ã¯ãåºå®ããããç¶ç¶çã«åå
¬éãããã¹ãããã·ã§ããã¢ãŒãã£ãã¡ã¯ã (bx-ai@3.4.0-snapshot) ã downloads.ortussolutions.com ããååŸããŸããããã®å
¬éæžã¿ã® zip 㯠bx-ai èªèº«ã® git development HEAD ã«ããçšåºŠé
ããããšããããŸã (ä»åã®ã»ãã·ã§ã³ã§çŽæ¥ç¢ºèªæžã¿ã§ã: ãã® upstream ã®ãªããŒã ãçå°ããçŽåŸãããŠã³ããŒãå¯èœãªã¹ãããã·ã§ããã«ã¯ãŸã å€ã gatewayRegistry.bx ãæ®ã£ãŠããŸãã)ããã®æ¹åããåã®ã¹ãããã·ã§ãããæ°ãã downloadModules ãååŸããŠããŸããšããã£ãã«ã¢ããã¿ã® gateways/* ãšã³ããªãæã€ãããžã§ã¯ãã¯ãçæãããã³ãŒããä»ãæ°ããååãåŒã³åºããŠããã«ãããããããååŸãããã¢ãžã¥ãŒã«ããŸã å€ããã®ããæã£ãŠããªããããFunction 'aiGatewayRegistry' not found ã§èµ·åã«å€±æããŸãããã㯠BX Agents åŽããä¿®æ£ã§ãããã®ã§ã¯ãããŸãã - ForgeBox ã bx-ai ã®çŸåšã® development ããã¹ãããã·ã§ãããåå
¬éããã°ãèªç¶ã«è§£æ±ºããŸãããã®ãããžã§ã¯ãèªèº«ã®çæã³ãŒããããããã¯å€ããªã£ãŠãããããããªãããŠã³ããŒãæžã¿ã® zip ã«é Œãã®ã§ã¯ãªãããã® git ãœãŒã¹ (ortus-boxlang/bx-ai) ããçŽæ¥ããŒã«ã«ãªã¢ãžã¥ãŒã«æ§é ãæ§ç¯ããããšã§ãbx-ai ã®æ¬åœã® HEAD ã«å¯ŸããŠæ£ããããšãæ€èšŒãããŠããŸãã
push åã²ãŒããŠã§ã€/GatewaySession ã®äœæ¥ãæ§ç¯ããŠããæäžã«ãåãé
å»¶ãç¬ç«ããŠå確èªããŸãã: ããŠã³ããŒãããã bx-ai@3.4.0-snapshot ã¯ããã®æç¹ã§ãŸã GatewaySession.bx ãæã£ãŠããããaiGatewaySession()/aiGatewayRegistry() BIF ããªããonMessage()/onError() ãäžåæããªã BaseGateway.bx/IGateway.bx ã§ãã - ãã®åããªããŒã ãããã£ãšåã®ã¹ãããã·ã§ããã§ããtestBx ã¯ãã®ç¶æ
ã§ãsrc/test/resources/modules/bxai ã® bifs//models//public//ModuleConfig.bx ããbx-ai èªèº«ã® git ãœãŒã¹ããã®æ°ããã³ããŒã«çœ®ãæããããšã§å®è¡ãããŸãã (libs//box.json ã¯ãã®ãŸãŸã§ã)ãäžèšãšåãã¯ãŒã¯ã¢ã©ãŠã³ãã§ãããã㯠build/serve ã®ãšã³ããŠãŒã¶ãŒãèªåã§è¡ãå¿
èŠã®ããããšã§ã¯ãªããForgeBox ã远ãã€ããŸã§ã®ããã®ã»ãã·ã§ã³èªèº«ã® CI ãªãã®æ€èšŒã®ããã«å¿
èŠã ã£ããã®ã§ãã
CI ã¯ä»ãããããèªåçã«åé¿ããŸããããããå¿
èŠããã£ãããã§ãã ãã®ã¹ã€ãŒãã®æåã®å®éã® GitHub Actions å®è¡ãããã®é
å»¶ãèŠãç®ã ãã®ãã®ã§ã¯ãªãããšã蚌æããŸãã: å
¬éãããŠãã bx-ai@3.4.0-snapshot ã¯äŸç¶ãšã㊠bifs/gatewayRegistry.bx ãåºè·ããŠãã (upstream ã§ã¯ãšãã®æã« aiGatewayRegistry ã«ãªããŒã ãããŠããŸã)ããããŠãã®ã¢ãžã¥ãŒã«ã® 9 ã€ãã¹ãŠã® push åã²ãŒããŠã§ã€ã extend ããŠãããmodels/gateway/BaseGateway.bx ãäžåå«ãã§ããŸãããããã«å¯ŸããŠãã¹ããããšããã®ã¢ãžã¥ãŒã«èªèº«ã®ã³ãŒããšã¯ç¡é¢ä¿ãªçç±ã§ 41 åã®ã¹ããã¯ã倱æããŸã (The method aiGatewayRegistry does not existãç¶ããŠååšããªãããŒã¹ã¯ã©ã¹ããã«ã¹ã±ãŒããããã¹ãŠã®ã²ãŒããŠã§ã€ã¹ããã¯ã§ã)ããã®ãã .github/workflows/tests.yml 㯠bx-ai ã® development ãã©ã³ããã¯ããŒã³ãããã® createModuleStructure ãå®è¡ãããã®çµæã downloadModules ãååŸãããã®ã®äžã«ãªãŒããŒã¬ã€ããŸã - äžèšã®æåã¯ãŒã¯ã¢ã©ãŠã³ããèªååãããã®ã§ããbx-ftp ãš bx-sqlite ã¯å®å®çãªãªãŒã¹ã§ãããäŸç¶ãšã㊠downloadModules ãããã®ãŸãŸååŸãããŸããå
¬éãããã¹ãããã·ã§ããã远ãã€ãããããã®ãªãŒããŒã¬ã€ã¹ããããåé€ããŠãã ããããããŸã§ã¯ãCI ã¯ãã³çããããã¢ãŒãã£ãã¡ã¯ãã§ã¯ãªã bx-ai ã®ãã©ã³ã HEAD ã«å¯ŸããŠãã¹ãããŠãããããupstream ã®ç Žå£ãããã§ã¯ bx-agents ã®å€±æãšããŠè¡šé¢åããããšã«æ³šæããŠãã ããã
Slash /compact ã®é
ç·äžã«ã3 åç®ãšããŠããã«ééããŸãã: bx-ai 㯠development (ã³ããã f9ac7bd) ã§ IAiMemory.summarize() ã userId/conversationId ã«ãã£ãŠã¹ã³ãŒãããŸããããæ°ãã downloadModules ã¯äŸç¶ãšããŠãå€ãåäžåŒæ°ã® summarize( struct config = {} ) ãæã€ã¹ãããã·ã§ãããååŸããŸãããåãã¯ãŒã¯ã¢ã©ãŠã³ã - ã¢ãžã¥ãŒã«ã¯ bx-ai èªèº«ã® git ãœãŒã¹ãã (ãã®ãªããžããªã§ ./gradlew createModuleStructure ãå®è¡ããsrc/test/resources/modules/bxai ã«äžæžãã³ããŒããŠ) åæ§ç¯ãããã¹ã³ãŒããããæåã¯ãã®ãã«ãã«å¯ŸããŠçŽæ¥æ€èšŒãããŸããã以åã® 2 åãšã¯ç°ãªããããã¯ãšã³ããŠãŒã¶ãŒãå®éã«ééãããã©ã³ã¿ã€ã äžã®åž°çµãæã¡ãŸã: /compact 㯠mem.summarize( config, userId, conversationId ) ãåŒã³åºããŸããããã® ã³ãããããåã® bx-ai ã§ã¯ã远å ã®åŒæ°ã¯åã«ç¡èŠããããããå§çž®ã¯åŒã³åºãå
ã®äŒè©±ã§ã¯ãªãããã®ã¡ã¢ãªã€ã³ã¹ã¿ã³ã¹ã®ããã©ã«ãã¹ã³ãŒããèŠçŽããŠããŸããŸãããã®ãããçæãããã¢ããªã¯ /compact ã«éã£ãŠã¯ f9ac7bd 以éã® bx-ai ãå¿
èŠãšããŸããä»ã®ãã¹ãŠã®ã«ãŒãã«ã¯åœ±é¿ããŸããããã®ãªããžããªèªèº«ã®ãã¹ãã¹ã€ãŒãã¯ãå€ãã¹ãããã·ã§ããã§ãäœäžã€åŸéããŸãããWeb UI ã®ã¹ããã¯ã¯å®è¡ããã®ã§ã¯ãªããçæããããœãŒã¹ããã¹ãã«å¯ŸããŠã¢ãµãŒãããŠããããã§ãã
v1 ã® Web ãã£ãã UI (exposes: "webui") - å®ç©ã§ããããšãšãããã¥ã¡ã³ãã«ç
§ãããŠãã確èªã§ãããã©ã€ããªãµãŒããŒã«å¯ŸããŠã§ã¯ãªãã£ãããš
WebUiGeneratorSpec.bx ãš BuildPipelineSpec.bx ã®ãšã³ãããŒãšã³ããã¹ãã¯ã©ã¡ãããå®éã®ãã£ã¯ã¹ãã£ã«å¯ŸããŠå®éã® WebUiGenerator/BuildPipeline ã¯ã©ã¹ãé§åããŸã: éç㪠<path>/index.html ã·ã§ã«ãæ£ããæžã蟌ãŸããæ£ãããã³ãã¬ãŒãåãããŠããããš (__API_BASE__/__APP_TITLE__ ã®ãã¬ãŒã¹ãã«ããŒã眮æãããåºåã«äžåæ®ããªãããš) ã確èªãããŠãããä»»æã® interceptors/WebUiAuthGate.bx 㯠apiKeyEnvVar ãèšå®ãããŠããå Žåã«ã®ã¿çæããã<path>/api/* ã ããã²ãŒãããçŽ ã® <path> ã·ã§ã«èªäœã¯æ±ºããŠã²ãŒããããconfig/ColdBox.bx ã® interceptors:[...] ãªã¹ãã«æ£ããç»é²ãããããšããå®éã® BuildPipeline ãéããŠãšã³ãããŒãšã³ãã§ç¢ºèªãããŠããŸããçæãããã€ã³ã¿ãŒã»ãã¿ãŒã¯ãä»åã®ã»ãã·ã§ã³ã§ã¹ã¿ã³ãã¢ãã³ã®ã¹ã¢ãŒã¯ãã¹ã (ãã«ããã€ãã©ã€ã³èªäœã䜿ãã®ãšåã DynamicClassLoader ããªããã£ãã§ããŒããããŸãã) ãéããŠãæ£ããã³ã³ãã€ã«ã»ã€ã³ã¹ã¿ã³ã¹åãããããšã確èªãããŠããŸãã
æ€èšŒãããªãã£ãããš - ãããŠãã®éçºç°å¢ã§ã¯ã§ããªãã£ãããš: å®éã® bxAgents serve + å®éã®ãã©ãŠã¶ãã¹ãã«ãããããŒãžãå®éã«ããŒããããè¿ä¿¡ãã¹ããªãŒãã³ã°ãããX-API-Key ã²ãŒããå®éã«æ¬ç©ã® HTTP çµç±ã§ãªã¯ãšã¹ããæåŠ/åçããããšã§ãããã®ãããžã§ã¯ãèªèº«ã® runColdBoxIntegrationTests.bxs/tests/coldbox ããŒãã¹ (http-gateway-agent ã® toAi() ã® /invoke ã«ãŒãããšã³ãããŒãšã³ãã§åäœããããšã蚌æããã®ãšåããã®) ã¯ãtests/ ã®å
éšã§å®éã« box install ãè¡ãããšã§ tests/coldbox ãååšããããšãå¿
èŠãšããŸãããCommandBox ãš ForgeBox ã®ãããã¯ãŒã¯ã¢ã¯ã»ã¹ã¯ã©ã¡ãããã®ã»ãã·ã§ã³ã®ãµã³ãããã¯ã¹ã§ã¯å©çšã§ããªãã£ããããWeb UI ã«å¯Ÿã㊠(ãããã¯ä»ã®äœãã«ã€ããŠãå確èªããããã«) ãã®ã»ãã·ã§ã³ã§ãã®ããŒãã¹ãæŒç¿ããããšã¯ã§ããŸããã§ãããããã«ã¯ 2 ã€ã®çŽæ¥çãªåž°çµããããŸã:
- ãã®ãããžã§ã¯ãèªèº«ã®çæãããããŒãž/ããã¥ã¡ã³ããäœ¿ãæ£ç¢ºãª
/invokeJSON ã¬ã¹ãã³ã¹åœ¢ç¶ (å ¥åã{"input": "..."}ãã¬ã¹ãã³ã¹ã«"success": trueãå«ã) ã¯ãrunColdBoxIntegrationTests.bxsèªèº«ã®ãã§ã«åæ ŒããŠããæ¢åã®ã¢ãµãŒã·ã§ã³ (å®å šãªåœ¢ã®ã¢ãµãŒã·ã§ã³ã§ã¯ãªããéšåæååãã§ãã¯) çµç±ã§ã®ã¿çµéšçã«ç¢ºèªãããŠããããã®ã»ãã·ã§ã³ã§åæ€èšŒããããã®ã§ã¯ãããŸããã - Web UI èªèº«ã® JS ãããŒã¹ãã
/streamã® SSE ã¯ã€ã€ãŒãã©ãŒããã (data: {"token":"..."}è¡ã§ãdata: [DONE]ã§çµç«¯ãããŸã) ã¯ãColdBox èªèº«ã®å ¬åŒãªãAI Routingãããã¥ã¡ã³ãããçŽæ¥åããããã®ã§ããããã®ã»ãã·ã§ã³ã§ã©ã€ããªãµãŒããŒã«å¯ŸããŠç¬ç«ããŠå確èªããããã®ã§ã¯ãããŸãã - ãã®ãããžã§ã¯ãã®ããã¥ã¡ã³ãã«ããä»ã®ã»ãšãã©ãã¹ãŠã®ã¯ã€ã€ãŒãã©ãŒãããã®äž»åŒµããå¯èœãªéãå®éã«åãã³ãŒãã«ç §ãããŠã¯ãã¹ãã§ãã¯ãããŠãã (ãã®ãã¡ã€ã«ã®ä»ã®ç®æã«ãã HMAC-SHA256/SHA1 ã®çœ²åæ¹åŒã®ç¬ç«ãã Python/openssl ã®ã¯ãã¹ãã§ãã¯ãªã©ãåç §) ã®ãšã¯ç°ãªããŸãã
æ¬çªã§ãã®æ©èœã«äŸåããåã«ãå®éã« bxAgents serve + å®éã®ãã©ãŠã¶ãã¹ã (ã¡ãã»ãŒãžãéä¿¡ãããè¿ä¿¡ãã¹ããªãŒãã³ã°ãããX-API-Key ã²ãŒããããŒãæ¬ ãããªã¯ãšã¹ããå®éã« 401 ã§æåŠããããš) ãå°ãªããšãäžåºŠã¯è¡ã£ãŠãã ãã - ãã®ãã¡ã€ã«ã®ä»ã®ç®æã§ãçæããããããã Webhook ãã³ãã©èªèº«ã®ãå®éã®èµ·åã«å¯ŸããŠæªæ€èšŒãšããã®ã£ããã«ã€ããŠãã§ã«äžããããŠããã®ãšåãæšæºçãªå©èšã§ãã
Web UI ã® SQLite ã¹ã㢠- ã©ã€ãã©ãªã¬ãã«ã§ã¯æ€èšŒæžã¿ãå®éã® ColdBox ã®èµ·åãéããŠã§ã¯ãªã
models/ChatDb.bx ã®èåŸã«ãã qb + bx-sqlite ã®ã¹ã¿ãã¯ã¯ãããã¥ã¡ã³ãããæšæž¬ãããã®ã§ã¯ãªããä»åã®ã»ãã·ã§ã³ã§å®éã® jar ã«å¯ŸããŠçŽæ¥æ€èšŒãããŠããŸã: qb 13.1.0 ã® .cfc ãœãŒã¹ã¯ bx-compat-cfml ãªãã§ BoxLang 1.16 äžã§ãã€ãã£ãã«ã³ã³ãã€ã«ã»å®è¡ãããŸããSQLiteGrammar + SchemaBuilder ã¯æ¬åœã« v1 ã®ããŒãã«ãšã€ã³ããã¯ã¹ãå®éã® SQLite ãã¡ã€ã«ã«å¯ŸããŠäœæããŸãã2 åç®ã®ãã€ã°ã¬ãŒã·ã§ã³ãã¹ã¯ã¯ãªãŒã³ãªç¡æäœã§ããQueryBuilder ã¯æ¿å
¥ããã£ã«ã¿æžã¿/ãœãŒãæžã¿ã®èªã¿åããåé€ãåŸåŸ©ãããŸãããã㊠preferences ã®è€åäž»ããŒã¯ãæ¬åœã« (userId, prefKey) ã®éè€ãæåŠããŸãããã®éçšã§ãæ³å®ã§ã¯ãªãå®éã« 2 ã€ã®å¶çŽãèŠã€ãããŸãã - qb ã¯ååä»ãã®ããŒã¿ãœãŒã¹ãå¿
èŠãšããŸã (èªèº«ã® appendSqlComments() ã¯ãã®åŒæ°ã string ãšããŠåä»ãããŠãããããã€ã³ã©ã€ã³æ§é äœã¯ SQL ãäžåå®è¡ãããåã«äŸå€ãæããŸã)ããã㊠SchemaBuilder@qb ã¯ãã® grammar åŒæ°ã®ã¿ã§ãããã³ã°ãããmoduleSettings.qb.defaultOptions ãäžååãåããŸãã - ãããŠçæãããã³ãŒãã¯ããã®äž¡æ¹ã«æ²¿ã£ã圢ã«ãªã£ãŠããŸãã
æ€èšŒãããªãã£ãããšãWeb UI ã®ä»ã®éšåãšåãçç±ã§ã: ããã¯å®éã® ColdBox ã®èµ·åã®å
éšã§äžåºŠãå®è¡ãããŠããŸãããtests/coldbox ã«ã¯å®éã® box install ãå¿
èŠã§ãããCommandBox/ForgeBox ã®ãããã¯ãŒã¯ã¢ã¯ã»ã¹ã¯ãã®ã»ãã·ã§ã³ã®ãµã³ãããã¯ã¹ã§ã¯å©çšã§ããŸããã§ããããã®ãããã€ã°ã¬ãŒã·ã§ã³ããžãã¯ã¯èšŒææžã¿ã§ããã3 ã€ã®é
ç·äžã®æ³å®ã¯ãšã³ãããŒãšã³ãã§ã¯æŒç¿ãããŠããŸãã: getInstance( "ChatDb" ) ãçæãããã¢ããªèªèº«ã® WireBox ãéããŠè§£æ±ºãããããšãSchemaBuilder@qb/QueryBuilder@qb ã qb ãå®éã® ColdBox ã¢ãžã¥ãŒã«ãšããŠã€ã³ã¹ããŒã«ãããéã«è§£æ±ºãããããš (qb 㯠box.json ã®äŸåé¢ä¿ã§ãããããã§ã¯ãã³ããªã³ã°ãããŠããŸãã - cbmailservices ããã§ã«æ±ããŠããã®ãšåãæ£çŽãªã®ã£ããã§ã)ããããŠçæããã Application.bx ã®äžã® this.datasources ãæåŸ
éãã«æŸãããããšã§ããæ¬çªã§ãã®ã¹ãã¢ã«äŸåããåã«ãqb ãš bx-sqlite ãå®éã«ã€ã³ã¹ããŒã«ããã webui ãããžã§ã¯ãã«å¯ŸããŠäžåºŠ bxAgents serve ãè¡ã£ãŠãã ããããããã®ãããããæ¬ ããŠããå Žåã®å€±æã¢ãŒãã¯ããµã€ã¬ã³ãã§ã¯ãªããèµ·åæã«å€§ããçŸããŸã (解決ã§ããªã WireBox ãããã³ã°ããæªç¥ã® JDBC ãã©ã€ãã§ã)ã
å®éã® HTTP ãéãã Web UI: çµ±åã©ã³ããŒã®ãããŒãã«ãã£ãŠèšŒæãããŠãã
runColdBoxIntegrationTests.bxs ã¯ãå®éã® boxlang-miniserver ã«ãã£ãŠèµ·åãããçææžã¿ãã£ã¯ã¹ãã£ã¢ããªã«å¯ŸããŠãå€éšãã GET /chat/api/health ããã§ãããã200 ã§ãªããã°ãã«ãã倱æãããŸããCI ã§ã¯æ¬¡ãè¿ããŸã:
+ App probe GET /chat/api/health -> status=200
body: {"success":true,"status":"ok"}
ãã®åäžã®ãªã¯ãšã¹ãããWeb UI ã®ãµãŒããŒåŽã«ã€ããŠã®ãšã³ãããŒãšã³ãã®èšŒæã§ã: ColdBox ã®ã«ãŒãã£ã³ã°ãçæããã handlers/ChatUi.bx ã«å°éããããšãWireBox ããã³ãã©ãš ChatDb ã解決ããããšãthis.datasources ã bx-sqlite ã«äœ¿çšå¯èœãª SQLite ãã¡ã€ã«ãäžããããšããã㊠qb ãå®éã«æå¹åããã ColdBox ã¢ãžã¥ãŒã«ã§ããããš - ãããã®ã©ãäžã€ãšããŠããœãŒã¹ããã¹ãã®ã¢ãµãŒã·ã§ã³ã ãã§ã¯ç¢ºç«ã§ããŸãããWebUiRuntimeSpec.bx ã¯ããã®åãèµ·åã®å
éšã§ WireBox ããå®éã®ãªããžã§ã¯ããèªã¿åºãããšã§ãã¹ãã¢ã®æå (ãã€ã°ã¬ãŒã·ã§ã³ãã¹ã³ãŒããããäŒè©±ã® CRUDãã¯ãã¹ãŠãŒã¶ãŒã¬ãŒããèšå®ã®ã¢ãããµãŒã) ãã«ããŒããŸãã
äŸç¶ãšããŠã«ããŒãããŠããªããã®: ä»ã® webui ã®ã«ãŒã矀ãå®éã® HTTP çµç±ã§ã§ããå€éšãããã§ãããããã®ã¯ /health ã ãã§ããWebUiRuntimeSpec ããä»ã®ã«ãŒããé§åããããšã¯ãæ§é äžäžå¯èœã§ãããã®ã¹ããã¯ã¯ã©ã³ããŒèªäœãå æããŠããã®ãšåãåäžã® miniserver ã«ãã£ãŠé
ä¿¡ããããªã¯ãšã¹ãã®å
éšã§å®è¡ããããããã«ãŒãããã¯åŒã³åºãã¯ã¯ãŒã«ãŒããŒã«ã奪ãåã£ãŠããŸãããã§ããæ®ããã«ããŒããã«ã¯ã2 ã€ç®ã®ãµãŒããŒããã»ã¹ãããã倧ã㪠miniserver ã¹ã¬ããããŒã«ã®ã©ã¡ãããå¿
èŠã§ãããã¯åœè£
ããã®ã§ã¯ãªãèªç¶ãªæ¬¡ã®ã¹ãããã§ãã
ãã®æ®µèœã¯ãã€ãŠããã®æ¯æžã®èšŒæ ãšã㊠runner-coldbox.bxm never responded: HTTP 408 ãåŒçšããŠããŸããããã®åž°å±ã¯èª€ãã§ããããããæ° CI ãµã€ã¯ã«ã«ããã£ãŠãã®ãããžã§ã¯ãã誀å°ããçµç·¯ãšããŠèšé²ãã䟡å€ããããŸã: 408 ã¯ã«ãŒãããã¯åŒã³åºããšã¯äžåé¢ä¿ãããŸããã§ãããã©ã³ããŒããŒãžã¯ååšããªã BIF ã§ãã chr( 10 ) ãåŒã³åºããŠããããããã¹ãŠã®ãªã¯ãšã¹ãã®ãšã³ããªã§ 500 ãè¿ããŠããããªãŒã±ã¹ãã¬ãŒã¿ãŒã®å詊è¡ã«ãŒããæçµçãªã¿ã€ã ã¢ãŠããå ±åãããŸã§ããã® 500 ã 90 ç§éããã€ã¶ãç¶ããŠããŸãããäž¡æ¹ãšãä¿®æ£ãããŠããŸããäžèšã®ã«ãŒãããã¯æ¯æžã®æžå¿µèªäœã¯ããã®ã¹ããã¯ã®å
éšããããå€ãã®ã«ãŒããé§åããªããå®åšããæ§é çãªçç±ã§ãããããã¯ããã§å®éã«å€±æã芳枬ããããã®ãšãããããæ ¹æ ã®ããäºæ³ã®ãŸãŸã§ãã
Web UI èªèº«ã®ããã³ããšã³ã: å®éã®ãã©ãŠã¶ã§é§åãããããã¢ã㯠API ã«å¯ŸããŠ
åºè·ãããããŒãžã® JavaScript ã¯ãä»åã®ã»ãã·ã§ã³ã§ãåã«ãœãŒã¹ããã¹ããšããŠã¢ãµãŒããããã ãã§ãªããå®éã«æŒç¿ãããŸãã: çæããã index.html ã¯ãããã¬ã¹ Chromium ã«ããŒãããããã¹ãŠã® <path>/api/* ã«ãŒããååãçŸå®çãªãã€ããŒãã§å¿çããç¶æ
ã§ããšã³ãããŒãšã³ãã§é§åãããŸããããã®æ¹æ³ã§ç¢ºèªãããåäœ: GET /conversations ããã®äŒè©±ãµã€ãããŒã®ã¬ã³ããªã³ã°ãšãèªèº«ã®ã«ãŒããéããåãæ¿ã/åå倿Ž/åé€ãGET /info ã«ããããŒã«ããŒã®åœ¢æ (capabilities.compact ã true ã®å Žåã«ã®ã¿ Compact ãçŸããã¢ãã«åãããããŒã«åãŸãããš)ã/history ã«ãããã©ã³ã¹ã¯ãªããã®åæ°Žåãbx-ai ã®ãšã³ãããŒãããã³ã³ãã³ããæšè«ãããŒã«åŒã³åºãããããæµãå®éã® SSE ã¿ãŒã³ãããŒã¯ããŠã³ã®ã¬ã³ããªã³ã°ããã㊠New chat ããµãŒããŒåŽã§äŒè©±ãäœæãããããéãããšãJavaScript ãšã©ãŒã¯ãŒãã眮æãããªã __TOKEN__ ãã¬ãŒã¹ãã«ããŒããŒããçãç»é¢ã®ã¬ã€ã¢ãŠã㯠390px ã§ã¹ã¯ãªãŒã³ã·ã§ãããããŸããã
ããã蚌æããªããã®: ãã® API 㯠Playwright ã«ããã¢ãã¯ã§ãããå®éã® SQLite ã¹ãã¢ã«å¯ŸããŠå®éã® ColdBox èµ·åã®äžã§åããçæããã handlers/ChatUi.bx ã§ã¯ãããŸããããªã¯ãšã¹ããšã¬ã¹ãã³ã¹ã®åœ¢ã¯ãçæããããã³ãã©èªèº«ã®ãœãŒã¹ããåãããŠãããããäž¡è
ã®ããªããã¯ããã«ãã£ãŠã¯æãŸããããŸãããäžèšã®æ¢ç¥ã®å¶éã®ãšã³ããªã§ã¹ãã¢ã«ã€ããŠè¿°ã¹ãããŠããããšã¯ãã¹ãŠãããã«ãåœãŠã¯ãŸããŸã - qb ãš bx-sqlite ãå®éã«ã€ã³ã¹ããŒã«ããã webui ãããžã§ã¯ãã«å¯ŸããäžåºŠã®æå bxAgents serve ããæ¬çªå©çšã®åã®æ£çŽãªã²ãŒããšããŠæ®ããŸãã