Query meeting notes endpoint (ChangeLog より) : hkob の雑記録 (503)

はじめに

hkob の雑記録の第503回目(連続76日目)は、最近サボっていた Developer Docs の ChangeLogs を紹介します。3つほど貯めているので、1日一つずつ紹介していきます。

ChangeLog の内容

5/11 に以下のように ChangeLog が更新されていました。

5/11 に更新された ChangeLog

新しい Query meeting notes エンドポイント(POST /v1/blocks/meeting_notes/query)は、Integration のユーザーに紐づく AI Meeting Notes を返す。filter / sort / limit は任意で指定できる。attendees エイリアスはサーバ側で正規化されるため、フィルタが往復(round-trip)しても整合する。

agent_id 親タイプ

エージェントに親子付け(parented)されたページおよびブロックは、拒否や書き換えではなく、parent{ "type": "agent_id", "agent_id": "..." } としてシリアライズするようになった。親タイプの一覧は Parent object を参照。

SDK 対応: @notionhq/clientv5.21.0 で、notion.blocks.meetingNotes.query()agent_id 親バリアントの型付きサポートが追加された。

API Reference の確認

せっかくなので、API Reference も確認してみます。部分ごとに引用し、コメントを追記していきます。

Overview

このエンドポイントは、meeting notesblock objectsobjectblocktypemeeting_notes)として一覧で返す。対象は、(ワークスペース内で)Integration に紐づくユーザーがそのブロックの attendee として含まれている meeting notes である。

レスポンスに含まれるもの:

  • results: meeting note blocks(meeting_notes ペイロードに title / status / children tab IDs(例: summary / notes / transcription)を含む。存在する場合は、カレンダー・録画に関するメタデータも含む)
  • has_more: 現在の filter / sort / limit に対して、このレスポンス以降にも追加の行があるか

フィールド選択: フィールドの部分取得パラメータはない。results[] の各要素は完全な block object である。必要なフィールド(例: meeting_notes、timestamp、people)をレスポンスから読み取る。返す meeting notes の絞り込みは filter を使う。利用可能なプロパティ名と演算子は、このエンドポイントの request body schema に定義される。

このエンドポイントはカーソルベースページネーションを使わないstart_cursornext_cursor は存在しない。結果セットの調整には filter / sort / limit(最大値は後述)を用いる。

Notion 内ではライブラリで Notion AI を一覧で確認できます。この仕組みはデータベースではないですが、Notion API からも検索し、一覧を取得できるようになりました。ただ、カーソルベースのページネーションには対応しないようなので、ある程度フィルタリングして抽出する必要がありそうです。

Request body

リクエストボディは JSON オブジェクトで、全フィールドが任意。

Field Description
filter 単一の property フィルタ、または filters 配列を持つ combinator"and" / "or")。詳細は Filtering を参照。
sort sort の順序付きリスト。各要素は propertydirectionascending / descending)を持つ。先に書いたものが優先。
limit 返す meeting notes の最大数。1〜50整数。省略時はサーバが 50 を用いる。

Default

{}

Sort and cap results

{
  "sort": [
    { "property": "last_edited_time", "direction": "descending" }
  ],
  "limit": 10
}

Request body に入れられるのは、filter, sort, limit の三つだけのようです。先ほど示したようにカーソル指定がないので、うまく filter で絞り込む必要があります。

Filtering

filter は次のいずれか:

  1. Property filter(単一条件)filter フィールド直下に、propertyfilter(operator と任意の value)を持つオブジェクトを置く。
  2. Combinatoroperator"and" または "or")と filters 配列を持つオブジェクト。filters の各要素は別の property filter、または(ネストは 1 階層まで)内側の filtersproperty フィルタのみからなる combinator(正確な形は API リファレンスの request schema を参照)。

テキスト/日付/person のフィルタにおけるプロパティ名、演算子、value 形状は request body schema に完全に定義される。無効なプロパティや不正なフィルタは 400 validation error となる。

フィルタは Property filter と Combinator で包まれた Property filter で構成されます。この下にサンプルが掲載されています。

Filter examples

以下 3 パターンは、単一 property filter、and combinator、or combinator をカバーする。より多くのプロパティや演算子は上記 schema を参照。サンプル文字列や UUID は適宜置換すること。

Simple property (title)

{
  "filter": {
    "property": "title",
    "filter": {
      "operator": "string_contains",
      "value": { "type": "exact", "value": "standup" }
    }
  }
}

Combinator: and

{
  "filter": {
    "operator": "and",
    "filters": [
      {
        "property": "title",
        "filter": {
          "operator": "string_contains",
          "value": { "type": "exact", "value": "planning" }
        }
      },
      {
        "property": "attendees",
        "filter": { "operator": "is_not_empty" }
      }
    ]
  }
}

Combinator: or, with sort and limit

{
  "filter": {
    "operator": "or",
    "filters": [
      {
        "property": "title",
        "filter": {
          "operator": "string_contains",
          "value": { "type": "exact", "value": "standup" }
        }
      },
      {
        "property": "title",
        "filter": {
          "operator": "string_contains",
          "value": { "type": "exact", "value": "sprint" }
        }
      }
    ]
  },
  "sort": [
    { "property": "last_edited_time", "direction": "descending" }
  ],
  "limit": 20
}

Query a data source の filter とは全く表現方法が異なりますね。このため、DataSource 用の Query の子クラスではなく、専用の QueryMeetingNotesFilter のようなクラスを一つ作成した方がよさそうです。

Sorting

各 sort 要素は propertydirectionascending / descending)を持つ。property は request body schema で定義されるものと同一の集合である。複数 sort がある場合、先に書いたものが優先される。

{
  "sort": [
    { "property": "last_edited_time", "direction": "descending" },
    { "property": "title", "direction": "ascending" }
  ]
}

これもプロパティごとに違いはなさそうなので、上記で作成したクラスで実装してもよさそうです。

Response shape

results の各要素は、meeting_notes オブジェクトと、通常の block メタデータを含む meeting note block である(詳細は本エンドポイントの response schema を参照)。

Integration capabilities

このエンドポイントは Integration の Read content 権限を要する。ワークスペース側に、Integration のユーザーに対する AI meeting notes が存在しない場合、呼び出しは validation error を返す。capabilities guide を参照。

results の各要素は meeting_notes の配列として取得されるようです。summary_block_id, notes_block_id, transcript_block_id という children が含まれているようです。この id からそれぞれのブロックが取得できそうです。

Errors

Integration のユーザーに AI meeting notes が存在しない場合、または filter / sort が不正な場合、HTTP 400 を返す。

リクエストが request limits を超えた場合、HTTP 400 または 429 を返す。

Note: Public API の各エンドポイントは複数のエラーコードを返し得る。詳細は Status codes ドキュメントの Error codes section を参照。

ユーザ用の AI meeting notes が存在しなかったり、filter / sort が不正な場合に 400 が返るようです。基本的にインテグレーションキーのユーザが会議に参加することはないので、PAT 認証を想定しているものと思います。meeting note の作成自体をインテグレーションキーで実行した場合は、参照できるのかもしれません。

ここから先はパラメータの詳細について書かれているので、省略します。

おわりに

ChangeLog のチェックをしばらくサボっていたので、溜まってしまっていました。紹介が終わった段階で、NotionRubyMapping のアップデートも進めていきます。先日の markdown のアップデートもすでに修正が入っていました。なるべく早めに対応します。

https://hkob.notion.site/hkob-16dd8e4e98ab807cbe3cf3cc94cdfe0f?pvs=4hkob.notion.site