VS Code のチャット履歴を、実データだけで判定しないようにする#

前回、AI とのやりとりをあとから記事化するために、 export_sessions.py で Copilot Chat のセッションを書き出す仕組みを作った。

ただ、実際に使ってみると、すぐに次の疑問が出てきた。

  • --list の一覧が、VS Code のチャット履歴一覧と合っていない

  • GitHub Copilot のチャットと CODEX のチャットで、記録のされ方が違うように見える

  • CODEX 側のやりとりも、直近ログとして同じ流れで取り出せるのか

VS Code の画面では、チャット履歴の一覧にアイコンが付くものと付かないものがあり、 上部の「チャット / CODEX」の切り替えでも表示内容が変わる。

最初は、見た目の印象から 「アイコンが付いているものが CODEX なのではないか」 と考えた。

この疑問の根っこにあったのは、かなり素朴な違和感だった。

GUI 上では CODEX のセッション履歴が確かに見えている。 タブを切り替えれば CODEX 側の履歴として確認できる。 それなのに、自分で作ったスクリプトから見ると、 その履歴がうまく一致しない。

もし画面には存在しているのに、スクリプトからは見つけられないのだとしたら、 それは単なる「データがない」では済まない。 自分が見ている保存場所、読んでいる形式、判定している条件のどこかが、 VS Code の実際の扱いとずれているはずである。

ここで少し立ち止まる必要があった。

手元の保存データだけを見て判定ロジックを作ると、 自分がたまたま使った範囲に最適化されたスクリプトになってしまう。 それでは、別のモードや別の状態のセッションを取りこぼすかもしれない。

今回は、その違和感と不安をきっかけに、 export_sessions.py の方針を「実データ観測」から「仕様を優先し、実データで補う」方向へ立て直した。

最初に見えた問題#

既存の export_sessions.py は、 主に次の場所を見ていた。

Code/User/workspaceStorage/<workspace-id>/GitHub.copilot-chat/transcripts/

この配下の .jsonl を読めば、 Copilot Chat の本文を取り出すことはできる。

しかし、VS Code のチャット履歴一覧に近い情報を出そうとすると、 transcripts だけでは足りなかった。

一覧表示には、セッションのタイトル、作成日時、状態、種類などが関係する。 それらは transcripts だけで完結しているとは限らず、 workspaceStorage 配下の chatSessions 側にも手掛かりがある。

つまり、目的によって見るべきデータ源が違っていた。

  • 本文を取り出すには transcripts が重要

  • VS Code の一覧に近づけるには chatSessions も重要

  • セッション ID で両方を統合する必要がある

この時点で、 --list が VS Code の一覧とずれる理由はかなり見えてきた。

実データだけで判断しようとして不安になった#

最初の実装案では、手元の chatSessions を見て、 mode.kindmode.id の値から CODEX らしさを判定しようとしていた。

たとえば、観測できたデータでは mode.kindagent になっていた。 また、mode.idagentPlan.agent.md のような値が入っていた。

ここだけを見ると、 「mode.kind=agent なら CODEX かもしれない」 という判定を書きたくなる。

しかし、これは危ない。

手元にあるデータは、あくまで自分がその日に試した操作の結果である。 Ask、Plan、Agent のすべての組み合わせを網羅しているわけではないし、 VS Code や拡張機能の内部実装がどういう意図でその値を保存しているかも、 実データだけでは分からない。

この段階で、 「実装できそう」よりも 「この根拠で判定してよいのか」 を優先して考える必要が出てきた。

仕様起点で見直す#

そこで、VS Code 本体や関連拡張の公開情報を確認し、 どこまでが仕様として頼れる情報で、 どこからが手元データによる補完なのかを分けて考えることにした。

特に確認したかったのは、 VS Code のセッション履歴一覧で表示される「左側のアイコン」が何を意味しているのかである。

調べた結果、少なくとも次のように考えるのがよさそうだった。

  • 左側のアイコンは、単純に「CODEX かどうか」だけを示すものではない

  • 進行中、要入力、失敗、未読などの状態アイコンが優先される場合がある

  • 状態アイコンでない場合に、セッション種別やプロバイダー由来のアイコンが出る

  • CODEX 判定の主根拠は、model 名よりも sessionTypeproviderType 側に寄せるべき

つまり、 「アイコンが付いているから CODEX」 という判定は雑すぎる。

一方で、 「CODEX 判定は、VS Code のアイコン表示に近い根拠へ寄せるべき」 という方向性は正しい。

この違いが大事だった。

判定の優先順位を決める#

最終的に、export_sessions.py のセッション種別判定は、 次の優先順位で考えることにした。

  1. sessionType または providerType が CODEX 系かどうか

  2. セッション resource の scheme が CODEX 系かどうか

  3. mode 情報から CODEX らしさを補助的に見る

  4. 最後の補助として model 名を見る

この順番にした理由は単純である。

VS Code の UI がセッション種別として扱っている情報に近いものを優先し、 mode や model 名のような情報は補助に回したかった。

model 名に codex が含まれるかどうかだけで判定すると、 将来モデル名が変わったときに壊れやすい。 また、model 名は「どのプロバイダーのセッションか」という UI 上の分類とは、 必ずしも同じ意味ではない。

実データは無視しないが、主役にはしない。 仕様や UI の考え方を先に置き、 実データはそれを検証したり、保存形式に合わせて補正したりするために使う。

実装で直したこと#

今回の作業では、export_sessions.py を次の方向で更新した。

  • chatSessions の JSONL 解析を追加する

  • transcriptschatSessions をセッション ID で統合する

  • --typeall / chat / codex を選べるようにする

  • --recent N で直近 N 件を扱えるようにする

  • CODEX 判定を provider / sessionType 優先にする

  • chatSessionskind=0 初期スナップショットを正しく読む

  • creationDate が epoch ミリ秒の場合に日時へ正規化する

たとえば、利用イメージは次のようになる。

rye run python export_sessions.py --list --recent 5
rye run python export_sessions.py --list --type codex --recent 5
rye run python export_sessions.py --latest

これで、 VS Code の一覧に近い情報を出すための土台と、 本文ログを書き出すための土台を分けて考えられるようになった。

ただし、今回の時点では、 手元の保存データに CODEX 判定へ使える providerTypesessionType のシグナルが十分に残っておらず、 --type codex は 0 件だった。

ここで AI は、 判定ロジックと保存データの限界が切り分けられた状態だと整理していた。

ただ、自分としてはまだ納得できていない。

なぜなら、VS Code の GUI 上では CODEX の履歴を確認できているからである。 画面に表示できているということは、 どこかにはその一覧を構成する情報があるはずだ。 スクリプトで --type codex が 0 件になるなら、 「CODEX の履歴がない」のではなく、 「自分のスクリプトが GUI と同じ根拠にまだ到達できていない」 と見るほうが自然である。

そのため、今回の結果は完了ではなく途中経過である。 少なくとも、自分にとっては 「いったん限界が分かった」 というより、 「GUI と保存データの対応関係をまだ取り切れていない」 という感覚のほうが強い。

この違和感を残しておくことも、今回の記事では大事にしたい。 同じように VS Code のチャット履歴や CODEX セッションの保存場所を調べる人は、 おそらく同じところで引っかかるからである。

わかったこと#

今回いちばん大きかった学びは、 「動く判定」と「根拠のある判定」は違うということだった。

手元の JSONL を見れば、 その日に保存されたデータに対して動くロジックは作れる。 しかし、それだけでは、 VS Code の UI が何を根拠に一覧を構成しているのか、 拡張機能がどの情報をセッション種別として扱っているのかまでは分からない。

特に、今回のように 「画面上の表示に近い一覧を作りたい」 という目的では、 保存ファイルの形だけでなく、 UI がどの概念を表示しているのかを見る必要がある。

また、状態アイコンと種別アイコンが混ざる点も重要だった。

左側に何かアイコンがあるからといって、 それが常に CODEX という意味になるわけではない。 状態を示すアイコンかもしれないし、 プロバイダー種別を示すアイコンかもしれない。

こういうところを雑に扱うと、 後から一覧とフィルタの意味がずれてしまう。

次に確認したいこと#

次にやるなら、 CODEX セッションを開いた直後に export_sessions.py を再実行し、 そのセッションにどの識別子が保存されるかを確認したい。

加えて、GUI の「チャット / CODEX」切り替えが、 内部的にどのデータ源や provider 情報に結びついているのかを、 もう少し直接追いかけたい。 画面上の一覧に出ている以上、 VS Code 本体または拡張機能のどこかに、 その一覧を構成する入口があるはずである。

特に見たいのは次のような情報である。

  • sessionTypeproviderType が保存されるか

  • resource の scheme に CODEX 系の情報が出るか

  • Ask、Plan、Agent の違いが保存形式にどう出るか

  • VS Code の一覧表示と --list の順序、タイトル、日時がどこまで一致するか

  • GUI の CODEX タブに出る履歴と、ローカル保存ファイルの対応関係をどう取れるか

ここまで確認できれば、 --type codex の精度をもう一段上げられるはずである。

おわりに#

AI とのやりとりをログとして残す仕組みは、 単に JSONL を読めば終わりではなかった。

本文を取り出したいのか、 VS Code の一覧に近づけたいのか、 GitHub Copilot と CODEX を分けたいのか。 目的によって、見るべきデータも、頼るべき根拠も変わる。

今回は、実データを見て一気に実装しようとしたところで、 「それは仕様理解として十分なのか」 と立ち止まれたのがよかった。

そして同時に、 「AI が一応の整理をしたとしても、人間側の納得感が追いついていないなら、 そこにはまだ記事にする価値のある問いが残っている」 とも感じた。

GUI では見えている。 しかし、スクリプトではまだ取れない。

このずれをどう埋めるかが、次の調査テーマである。

手元の観測を大切にしつつ、 それだけに引っ張られない。

個人用の小さなスクリプトでも、 こういう順番で考えると、あとから育てやすい道具になる。

記事情報

著者:

mtakagishi

公開日:

2026-05-30