既知の制限

正直なギャップ - 実際に動くアプリに対して証明済みのものと、そうでないもの。

On this page

既知の制限

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/* が実際にラむブな ColdBox Scheduler に登録されるこず - 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 ぀の実圚するブロッカヌが衚面化したした:

  1. 最初に読んだ 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 にあるものず同じではありたせん。
  2. 実際に公開されおいる 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 ぀の盎接的な垰結がありたす:

  • このプロゞェクト自身の生成されたペヌゞ/ドキュメントが䜿う正確な /invoke JSON レスポンス圢状 (入力が {"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 が、本番利甚の前の正盎なゲヌトずしお残りたす。

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