mcpField
C
conversation-history-brief

conversation-history-brief

github.com/hubspotマーケティング・グロース28194 回インストール今日更新
リポジトリ

conversation-history-brief について

conversation-history-briefは、HubSpot Conversationsの受信トレイのスレッドから顧客向けブリーフを作成するスキルです。CRMや営業の業務向けに、全ページの取得、チャネル種別の解決、履歴の要約方法を案内します。

主な機能

  1. 01受信トレイとチャネルの列挙
  2. 02コンタクトに関連するスレッドの検索
  3. 03全件取得のためのページ処理
  4. 04メッセージの取得と要約
  5. 05構造化された顧客ブリーフの生成

活用シーン

  1. 01通話前のコンタクトブリーフ作成
  2. 02コンタクトの受信トレイ履歴の確認
  3. 03受信トレイのスレッドとCRM活動履歴の統合

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/hubspot/agent-cli-skills --skill conversation-history-brief

インストール後、Claude Code で/conversation-history-briefを入力して読み込まれたか確認します。

詳細

hub-cli PR #251 の conversations コマンドグループが必要です。hubspot conversations --help が正式な情報源です。また、CRM のアクティビティ履歴(通話、メール、メモ)については communication-history/SKILL.md も参照してください。このスキルは Conversations 受信トレイの範囲のみを扱います。

スレッドがコンタクトにどのように関連付けられるか

conversations threads list は --associated-contact-id を受け付けます。さらに --inbox-id も指定する必要があります。受信トレイを知らなければ、ポータル全体のコンタクトスレッド検索は存在しません。すべての受信トレイをカバーするには、まずそれらを列挙し(ステップ 1)、その後で受信トレイごとにクエリを実行します。

ページング: --format jsonl で結果セット全体を収集しないこと

すべての conversations の list コマンドはデフォルトで --limit 100 となり、次のページ用のカーソルを返します。--format jsonl はデータ行のみを出力します — カーソルは --format json でのみ、.meta.next に現れます。 したがって、--format jsonl をファイルにパイプすると、最初の 100 行で暗黙的に切り捨てられます。また、--limit を増やしても修正にはなりません。エンドポイントがページサイズに上限を設けているためです。

すべての行を確認する必要があるものには、このヘルパーを使用してください:

# conv_page <output-file> <conversations list args...>
# Pages a conversations list endpoint to exhaustion, writing one JSON object
# per line to <output-file>.
conv_page() {
  out=$1; shift
  after=""
  : > "$out"
  while :; do
    if [ -n "$after" ]; then
      page=$(hubspot "$@" --format json --after "$after") || return 1
    else
      page=$(hubspot "$@" --format json) || return 1
    fi
    printf '%s' "$page" | jq -c '.data[]' >> "$out"
    after=$(printf '%s' "$page" | jq -r '.meta.next // empty')
    [ -n "$after" ] || break
  done
}

最初のページを対話的にざっと見るだけなら、素の --format jsonl でも問題ありません。

1. 受信トレイを列挙する

conv_page /tmp/inboxes.jsonl conversations inboxes list
# {"id":"123","name":"Support Inbox","createdAt":"...","updatedAt":"..."}
# {"id":"124","name":"Sales Chat","createdAt":"...","updatedAt":"..."}

2. コンタクトのすべてのスレッドを検索する

受信トレイ ID をループし、コンタクトに関連付けられたスレッドを収集します:

CONTACT_ID=73235
: > /tmp/contact_threads.jsonl   # truncate output file

while IFS= read -r inbox; do
  inbox_id=$(echo "$inbox" | jq -r '.id')
  conv_page /tmp/inbox_threads.jsonl conversations threads list \
    --inbox-id "$inbox_id" \
    --associated-contact-id "$CONTACT_ID"
  cat /tmp/inbox_threads.jsonl >> /tmp/contact_threads.jsonl
done < /tmp/inboxes.jsonl

echo "Total threads found: $(wc -l < /tmp/contact_threads.jsonl)"

スレッドの出力形状:

{"id":"111","status":"OPEN","createdAt":"2026-07-28T10:02:00Z","latestMessageTimestamp":"2026-07-30T14:22:00Z","assignedTo":"A-78901","inboxId":"123","originalChannelId":"1000","originalChannelAccountId":"148662","associatedContactId":"73235","spam":false,"archived":false}

スレッドには存在しないと想定しがちな 2 つのフィールドがあります:

  • channelType はありません。 スレッドは発信元チャネルを originalChannelId に ID のみで記載します。conversations channels list と結合して人間が読めるタイプに解決してください。これは {"id":"1000","name":"Support Email","type":"EMAIL","inboxId":"123"} を返します(以下のステップ 3)。
  • subject は保証されません。 信頼できるフィールドは status(OPEN/CLOSED)、タイムスタンプ、assignedTo、およびチャネル ID です。subject は常に // "(no subject)" のフォールバックを経由して読み取ってください。

3. チャネル ID をチャネルタイプに解決する

: > /tmp/channels.jsonl
while IFS= read -r inbox; do
  inbox_id=$(echo "$inbox" | jq -r '.id')
  conv_page /tmp/inbox_channels.jsonl conversations channels list --inbox-id "$inbox_id"
  cat /tmp/inbox_channels.jsonl >> /tmp/channels.jsonl
done < /tmp/inboxes.jsonl

# {"1000":"EMAIL","1001":"LIVE_CHAT"}
jq -s 'map({key: (.id|tostring), value: .type}) | from_entries' \
  /tmp/channels.jsonl > /tmp/channel_types.json

以下のステップでスレッドにラベルを付けるために使用するヘルパー:

CHANNEL_TYPES=$(cat /tmp/channel_types.json)

4. 各スレッドのメッセージを取得する

messages list は他のすべての list エンドポイントと同様にページングするため、最初の 100 件を取得するのではなくページングしてください:

: > /tmp/all_messages.jsonl

while IFS= read -r thread; do
  tid=$(echo "$thread" | jq -r '.id')
  conv_page /tmp/thread_messages.jsonl conversations messages list --thread-id "$tid"
  jq -c --argjson thread "$thread" --argjson types "$CHANNEL_TYPES" \
    '. + {
       _threadId: $thread.id,
       _subject: ($thread.subject // "(no subject)"),
       _channelType: ($types[($thread.originalChannelId | tostring)] // "UNKNOWN")
     }' /tmp/thread_messages.jsonl \
  >> /tmp/all_messages.jsonl
done < /tmp/contact_threads.jsonl

メッセージの出力形状:

{"id":"222","type":"MESSAGE","text":"Hello, I have a billing question.","sender":{"actorId":"A-456","name":"Jane Doe"},"createdAt":"2026-07-30T14:20:00Z"}

単一のメッセージを完全な詳細で取得するには:

hubspot conversations messages get --thread-id 111 --message-id 222 --format jsonl

5. アカウントブリーフ用のコンパクトなタイムライン

最新のアクティビティ順に並べた、人間が読めるスレッドサマリーを生成します。-s に注意してください: ファイルは JSONL であるため、slurp しないと sort_by に一度に 1 つのオブジェクトが渡され、タイムラインを出力する代わりに jq が Cannot index string with string で終了コード 5 で終了します。

echo "=== Conversation History for Contact $CONTACT_ID ==="
jq -sr --argjson types "$CHANNEL_TYPES" \
  'sort_by(.latestMessageTimestamp) | reverse[] |
   "\(.latestMessageTimestamp[0:10])  \($types[(.originalChannelId | tostring)] // "?")  [\(.status)]  \(.subject // "(no subject)")"' \
  /tmp/contact_threads.jsonl

主要なメッセージの抜粋(スレッドごとの最初のメッセージ):

echo ""
echo "=== First message per thread ==="
while IFS= read -r thread; do
  tid=$(echo "$thread" | jq -r '.id')
  subject=$(echo "$thread" | jq -r '.subject // "(no subject)"')
  first_msg=$(hubspot conversations messages list --thread-id "$tid" --limit 1 --format jsonl \
    | jq -r '.text // .richText // "(no text)" | .[0:200]')
  echo "[$tid] $subject: $first_msg"
done < /tmp/contact_threads.jsonl

6. 構造化されたアカウントブリーフのセクション

より大きなアカウントブリーフに埋め込むのに適した JSON ブロックを出力します:

jq -n \
  --argjson threads "$(jq -s '.' /tmp/contact_threads.jsonl)" \
  --argjson types "$CHANNEL_TYPES" \
  --arg contact_id "$CONTACT_ID" \
  '{
    conversations: {
      contact_id: $contact_id,
      total_threads: ($threads | length),
      open_threads: ($threads | map(select(.status=="OPEN")) | length),
      channels: ($threads | map($types[(.originalChannelId | tostring)] // "UNKNOWN") | unique),
      latest_activity: ($threads | sort_by(.latestMessageTimestamp) | last | .latestMessageTimestamp),
      threads: ($threads | map({
        id: .id,
        subject: (.subject // "(no subject)"),
        status: .status,
        channel: ($types[(.originalChannelId | tostring)] // "UNKNOWN"),
        last_activity: .latestMessageTimestamp,
        assigned_to: (.assignedTo // null)
      }))
    }
  }'

CRM アクティビティ履歴との組み合わせ

通話前の完全なブリーフを作成するには、このスキルを communication-history/SKILL.md と組み合わせてください:

CONTACT_ID=73235

echo "=== CRM Activity (calls, emails, notes) ==="
hubspot activities list --contact $CONTACT_ID --limit 10 \
| jq -r '"\(.timestamp[0:10])  \(.type)  \(.title)"'

echo ""
echo "=== Conversations Inbox Threads ==="
# ... run the thread loop from step 2 above ...

既知の制約

  • threads list には --inbox-id が必要です — 全体像を把握するにはすべての受信トレイをループする必要があります。
  • 日付範囲のサーバーサイドフィルターはありません — latestMessageTimestamp を使用して jq でクライアントサイドでフィルタリングしてください。
  • すべての list コマンドは 100 行でページングし、カーソル(.meta.next)を公開するのは --format json のみです。完全である必要があるものには conv_page を使用してください。素の --format jsonl のリダイレクトは暗黙的に切り捨てられます。
  • スレッドは channelType を持ちません — originalChannelId を conversations channels list と結合してタイプを取得してください。スレッドは会話の途中でチャネルを切り替えることもあるため、originalChannelId はスレッドが開始した場所を表すのであり、使用したすべてのチャネルを表すわけではありません。
  • subject はスレッドの保証されたフィールドではありません。常に // "(no subject)" のフォールバックを使用してください。
  • text と richText: 一部のメッセージタイプは text ではなく richText にフォーマットされたコンテンツを含みます。抜粋を抽出する際は両方のフィールドを確認してください。

コメント