ガイド
モバイルアプリで使う
はい。ウィジェットは、普通の HTTP API の上に載った薄いクライアントです。API のどこにもブラウザの前提はありません — cookie も、リダイレクトも、JSON が入って JSON が出ます。iOS でも Android でも、同じエージェント、同じプラン、同じ枠で話せます。別に買うモバイル製品も、入れる SDK もありません。
変わるのは、アプリが自分の身元をどう証明するかです。誰にも解かれるバイナリをリリースする前に、ここは正しくしておく価値があります。
入り口は 2 つ。どれを選ぶか
アプリにすでにバックエンドがあるなら、それを使ってください。サーバーがサイトのシークレットを持ち、短命な署名トークンを発行します。アプリはあなたのサーバーにトークンを求め、それを私たちに送ります。シークレットはアプリの中に同梱されることはなく、トークンは数分で切れます。どのユーザーに会話を与えるかはあなたが決められます。選べるなら、これが選ぶべき道です。
アプリにバックエンドがなければ、代わりに公開のサイトキーを載せられます — ウェブサイトのウィジェットが使うのと同じキーです。それが何を意味するか理解してください: キーはどんなアプリのバイナリからも抽出でき、ウェブサイトと違い、照合できるドメインがありません。これはポータルで意図的にオンにする必要があります — サイトの Setup タブの Also used from a mobile app です。オンにするまで、ブラウザの Origin がないリクエストは拒否されます。
その場合、すぐ下の Require each app install to register もチェックしてください。すると、アプリは初回実行時に /v1/install を 1 回呼び、返ってきた ID を保持し、以後すべてのリクエストに送ります。リクエストは登録済みインストールごとにレート制限されるため、抽出されたキーが、1 つの呼び出し元にボットの共有枠への制限なしの道を与えることはありません。コストは、インストールごとに呼び出し 1 回増えるだけです。
リクエストの順序
ベース URL は https://kavilo.cloud です。すべてのリクエストで、認証情報をヘッダーとして送ります — Authorization: Bearer <token> か X-Kavilo-Key: kw_pub_…。
POST /v1/install— 上記の設定にチェックした場合、初回実行時に 1 回。返ってくるinstallIdを保持し、以後はX-Kavilo-Installとして送ります。POST /v1/session— 開始または再開。{"conversationId": "…"}を送ります。初回は空です。保持すべき ID、Greeting、カーソル、それまでの履歴が返ります。POST /v1/message— 1 ターンを送信します。即座に202が返り、返信はあなたが読んでいる方のトランスポートに届きます。POST /v1/poll— 返信を受け取る 2 通りのうちの 1 つ。カーソルを送り、新しいものを受け取ります。空で応答するまで最大 25 秒待つので、これをループすると busy wait ではなく long-poll になります。GET /v1/stream— ポーリングの代替: 同じフレームを server-sent events として受け取ります。POST /v1/end— 訪問者が終了したことを示します。文字起こしを送り、会話を閉じます。
poll と stream は、同じカーソルで同じバッファを読みます。会話の途中で切り替えても、何も失いません。スマートフォンでは、通常、poll のほうが簡単です。ネットワークが変わっても特別な処理なしで耐え、ユーザーが読みながらソケットを開きっぱなしにしません。
返信を読み取る
各フレームには seq、kind、通常は text があります。token フレームは届くたびに追加してください。ターンは final で終わります。そこには完全な答えが含まれるので — それを正として採用し、蓄積してきたものを置き換えてください。再接続で返信を 2 回表示しっぱなしになるのを防ぐためです。ターンは error でも終わります。終わり方はこの 2 つだけです。待ち続けるべき "done" フレームは存在しません。
メッセージ 1 通が返信 1 通を意味するわけではありません。エージェントがまだ回答中に、訪問者が 2 通目を送ると、同じターンに組み込まれます。メッセージごとに返信 1 通を数え切るまでブロックするアプリは、いずれハングします。代わりに final まで読み続けてください。
バックグラウンドへ送られたとき
15 分間静かになった会話は閉じられ、その文字起こしが送信されます — ウェブでも同じルールです。タブを閉じた訪問者と、お茶を淹れにいった訪問者は、見分けがつかないのですから。睡眠に入るスマートフォンなら、その線を簡単に越えます。
だからフォアグラウンドに戻ったら、保存した ID で /v1/session をもう一度呼び出してください。会話が開いていれば続きを、閉じられていれば新しいものが返ります。どちらの場合も、応答が再描画用の履歴を渡してくれます。その呼び出しは、エラー処理ではなく、画面を読み込む方法だと思ってみてください。
まだないもの
添付ファイルです。チャット API にはアップロードエンドポイントがありません。アプリでもウェブでもありません。だから訪問者は、壊れた部分の写真を送ることができません。それがあなたのアプリの用途なら、教えてください — 実際に必要とする人が現れると、優先順位が上がります。
ここから始める
リファレンスクライアントを頼めば、Swift と Kotlin の両方で、一連の全シーケンスを送ります — 各 100 行程度で、信用するより読むほうが早い、そんな短さです。hello@kavilo.cloud まで書き、どのプラットフォームを使っているかを教えてください。