複数のVS CodeでCodexを動かしていると、ある処理が「実行中」なのか「人間の確認待ち」なのかを、離れた場所からでも知りたくなります。ESP32でLEDを光らせること自体より難しかったのは、どのCodexの状態を、どのLEDに表示してよいかの判定でした。
ロコリス研究所では、Codexの状態を集めるTask Monitorと、Wi-Fiでその状態を読むESP32の表示機を接続しました。七つの作業位置A~GをLED 1~7に対応させ、8個目はTask Monitorとの接続・監視状態に使っています。この記事では、状態の割当をサーバー側で確定し、曖昧な場合は表示しないようにした実装と、ブレッドボード上の実機で確認した結果をまとめます。
状態と作業位置は、別々の場所から来る
A~Gは、Task Monitorで既に使っている、WorkとVS Codeを対応付けるための位置ラベルです。ラベルの設定方法と保存方法はTask Monitorの技術構成で説明しました。ここでは、その位置へCodexの状態をどう結び付け、LEDに渡したかを扱います。
Task Monitorは、Codexのローカル記録から実行状態と人間の承認状態を読み取ります。VS Codeの拡張機能は、人間が位置を設定した各ウィンドウのworkspaceをTask Monitorへ定期的に知らせます。
表示機に必要なのは「承認待ちのCodexがある」という情報だけではありません。そのCodexが、作業位置Bとして設定したVS Codeと同じRepositoryの仕事かまで分からなければ、BのLEDを黄色にはできません。
当初はSessionカードにもA~Gを手動で設定する方式を試しました。しかし、VS CodeとSessionの両方に位置を持たせると、同じ関係を二度設定することになります。位置の設定はVS Codeだけに残し、Sessionとの関連付けをTask Monitor側で行う形に変えました。
表示名ではなくRepository IDで結合する
workspaceの末尾のフォルダー名やカードに表示した名前が同じでも、同一Repositoryとは限りません。逆に、Repository内のサブフォルダーを開いたVS Codeと、そのRepositoryのルートに紐づくCodexを、文字列の完全一致だけで結ぶこともできません。
そこでTask Monitorは、CodexのworkspaceとVS Codeのworkspaceを、それぞれRepository Registryのrepository_idへ解決してから照合します。Repositoryのルートより深いパスは、登録されたルートのうち一致する部分が最も長いRepositoryへ解決します。たとえば親Repositoryの中に別のRepositoryが登録されていれば、子の中のパスは子を選びます。一方、同じルートパスが異なる二つのrepository_idで登録されていれば、最長一致でも候補が二つ残るため、どちらにも確定しません。VS Code側のfile: URIもWindowsのパスへ変換してから照合します。
VS Codeで複数フォルダーを開いている場合は、すべてのフォルダーを解決します。異なるRepositoryを含む、解決できないフォルダーがあるなど、対応を一意に決められなければSessionをその位置へ結合しません。同じRepositoryを複数ウィンドウで開き、AとBのように異なる位置へ設定した場合も、どちらかを推測して選びません。
この判断はLEDならではです。画面には名称や補足情報を並べられますが、光だけを見る人には、黄色になった理由が誤った結合だったのかどうか分かりません。不確かな作業へ承認待ちを表示するより、その対応を表示しない方が安全だと判断しました。
七つの作業位置の状態をAPI側で確定する
Task MonitorはGET /api/sessionsのslot_statesで、A~Gを固定順に返します。各位置の判定では、対象となるCodexの処理が複数ある場合の優先順位を次のようにしました。
| 優先順位 | APIの状態 | LED 1~7 | 意味 |
|---|---|---|---|
| 1 | ERROR |
赤 | 未確認のエラーがある |
| 2 | REVIEW_REQUIRED |
黄 | 人間による結果の確認が残っている |
| 3 | RUNNING |
緑 | Codexが実行中 |
| 4 | CONNECTED |
青 | VS Codeは接続中で、上記の対象はない |
| 5 | DISCONNECTED |
消灯 | 接続中のVS Codeがない |
たとえば同じRepositoryの作業に実行中と承認待ちが重なれば、黄を優先します。「待機中のWork」という別の手動表示は、Codexの承認待ちとは異なるため、黄色判定には使いません。
実装では、オンラインのVS Codeに設定された位置をRepositoryごとに集め、位置が一つに定まったRepositoryだけをCodexの状態と結合します。次はTask Monitor側の処理から、位置の競合判定と赤・黄・緑の優先順位を抜粋したものです。表の青は接続中のVS Codeに対象となる処理がない場合、消灯は接続中のVS Codeもない場合に、それぞれ後続の処理で判定します。
slots_by_repository = {
repository_id: next(iter(slots))
for repository_id, slots in repository_slots.items()
if len(slots) == 1
}
priorities = {'RUNNING': 1, 'REVIEW_REQUIRED': 2, 'ERROR': 3}
ここでlen(slots) == 1を満たさないRepositoryには、Codexの状態を割り当てません。複数ウィンドウで同じ位置を選んでいる場合は一つに定まりますが、位置が競合する場合は除外されます。対象となる処理も、内部・テスト用Session、確認済みエラー、承認済みの処理などを除いて選びます。
逆に、異なるRepositoryを同じ位置Bへ設定することは許します。各Repositoryの位置がBに一意に定まれば、双方のCodexの状態をBへ集約し、表の優先順位で一色にします。たとえば一方が実行中で、もう一方が承認待ちなら、BのLEDは黄です。len(slots) == 1は「一つのRepositoryに複数の位置がないか」を調べる条件であり、「一つの位置にRepositoryが一つだけ」という制限ではありません。
ESP32は確定した状態を読む
ESP32はWi-Fi経由でTask Monitorへ接続し、GET /api/sessionsを5秒間隔で取得します。使用したのはPlatformIOのesp32dev環境、Arduino framework、Adafruit NeoPixel、ArduinoJson 7.4.3です。LEDのデータ出力はGPIO18、LEDは8個、輝度設定は16/255としました。
ESP32側では、slot_statesのslotとstateを読み、LED 1~7へ反映します。vscode_instancesに含まれる表示名や位置、待機中のWorkから、Sessionとの結合をやり直しません。結合の判断をTask MonitorとESP32の二か所へ分散させないためです。
また、受け取った状態が正しい形かを確認します。A~Gの7件がそろい、位置が重複せず、状態が既知の値であることが条件です。欠損、重複、未知の状態、通信失敗があればLED 1~7を消灯し、以前の方法による推測表示へは戻しません。OLEDには取得できていないことをTM DOWNで示します。
LED 8は作業位置とは別の全体表示です。実装上はAPI取得失敗で赤、監視停止で黄、API接続が正常で監視中なら青になります。ESP32から承認操作は行わず、LAN経由では状態を読み取るだけです。
テストと実機で確かめた範囲
Task Monitor側のテストでは、Repositoryのルートとサブフォルダーの解決、最長一致、曖昧なルート、別Repositoryを含む複数フォルダー、同じRepositoryで位置が競合する場合などを確認しました。位置の自動関連付けに関するテスト8件と、その時点の全回帰テスト204件が成功したという記録が残っています。
ブレッドボード上の試作機では、VS Code側でTask MonitorのRepositoryをBに割り当てて確認しました。Sessionカード側にA~Gを設定する操作はしていません。
| 人間が確認した場面 | BのLED |
|---|---|
| 同じRepositoryのCodexが実行中 | 緑 |
| 処理が終わり、人間の承認待ちになった | 黄 |
| Task Monitorの画面で人間が承認した後 | 約5秒以内に青 |
ESP32を操作して色を切り替えたわけではありません。Wi-Fi接続とAPI取得、OLEDのWIFI OK・TM OK・MON ON、監視中のLED 8が青になることも確認しました。
ブレッドボード上の試作機の写真と、表示機を作った背景はNoteの記事に載せています。
一方、赤のエラー表示、API切断時や監視停止時のLED 8、Wi-Fi切断後の再接続は、コードとテスト上の扱いは定めていますが、今回の実機確認結果には含めません。電池での稼働と長時間運転も未確認です。使用した8連LED基板の正確なIC型番と信号条件も未確定で、今回の個体でESP32の3.3Vデータ信号による制御に成功したことを、別個体の動作保証とは扱っていません。
表示機へ渡す前に、割当の根拠を確定する
ESP32の仕事は、受け取った状態をLEDへ表示するところまでです。どのVS CodeとCodexを同じ仕事として扱うか、複数の処理のうちどれを優先するかは、Task Monitorが判断します。対応を確定できない場合に推測して光らせないことも、その判断に含めました。
実機では、Bの緑、黄、青への自動追従まで確認できました。七つの作業位置を少ない光で表すために必要だったのは、LEDの色数よりも、その光がどの作業を指しているかを確実に決めることでした。