コンテンツにスキップ

Telegram ミニアプリ承認詳細カード

アクションの完全な説明・シミュレーションされた結果・残り時間まで確認し、Telegram の中でそのまま承認・拒否できる。


高リスクなアクションに人間の同意が必要になると、DuDuClaw は承認・拒否の2つのボタンが付いたカードを Telegram にプッシュします。ボタン自体は十分ですが、判断に必要な情報——アクションの完全な説明、シミュレーションされた結果、自動拒否までの残り時間——はカードには載り切りません。これまでこれらはダッシュボードでしか見られず、「スマホで決める」は「ブラウザに切り替え、ログインし、該当の1件を探す」作業になっていました。

この機能は、その3つを Telegram の中に持ち込みます。カードに3つ目のボタン「🔎 查看詳情」(詳細を見る)が追加され、タップすると会話の上に小さな画面が展開されます。内容を確認したら、その場で承認または拒否——一連の流れは Telegram から一歩も出ません。

これは試作(spike)機能で、デフォルトはオフです。 対象はこの承認詳細カード1枚のみ:まず「チャネルの中にインターフェースを入れる」という道が成立するかを検証し、その後にタスク・支出・ステータスなど他の画面へ広げるかどうかを判断します。


高リスクアクションが人間の同意を待つ
|
v
bot との1対1チャットにカードをプッシュ
[承認] [拒否] [🔎 詳細を見る]
| 3つ目のボタンをタップ
v
会話の上に Mini App が展開
| Telegram が署名済み initData を添付
v
Gateway が HMAC を再計算して検証
| 一致 --> 詳細が POST で届く
v
完全な説明+シミュレーション結果
+毎秒更新のカウントダウン
| 承認 / 拒否
v
画面は自動で閉じ、チャットのカードは
その場で1行の結果に畳まれる
  • どの種類の決定か:カードと同じ行のラベル(「⚠️ 高風險動作需要你同意」——高リスクなアクションにあなたの同意が必要です)。
  • 誰が何をしようとしているか:AI 従業員の名前と、アクションの平易な説明(「高リスクツールを実行」「新しいスキル/ツールをインストール」…)。
  • 内容:チャットの吹き出しのように切り詰められない、完全な説明。
  • 承認したら次に何が起こるか:システムが事前にシミュレーションした1〜3ステップの結果。シミュレーション結果のない承認ではこのセクション自体が表示されず、でっち上げることはありません。
  • 残り時間:毎秒更新されるカウントダウン。残りが3分の1を切ると赤に変わります。期限までに応答がなければ一律で自動拒否です。
  • 2つの大きなボタン:このアクションを承認する/拒否する。送信に成功すると画面は自動で閉じ、会話に戻ります。

画面の配色は Telegram のテーマに追従します(ダークモード・ライトモード・カスタムテーマすべてに適用)。ダークなチャットに白い長方形が突き刺さることはありません。


有効化の条件(3つすべて必須)

Section titled “有効化の条件(3つすべて必須)”
条件 設定方法 満たさない場合
機能スイッチ config.toml[miniapp] enabled = true エンドポイントは 404 を返し、カードは従来の2ボタンのまま
公開 URL が https config.toml[dashboard] public_url = "https://あなたのドメイン" 詳細ボタンは付かない(Telegram は Mini App に https を必須としている)
カードが 1対1のプライベートチャット に届く プッシュ先で決まる 詳細ボタンは付かない(Telegram は web_app ボタンをプライベートチャットのみに許可)
~/.duduclaw/config.toml
[miniapp]
enabled = true
[dashboard]
public_url = "https://ai.example.com"

変更後は gateway を再起動してください。3つの条件のどれか1つでも満たさなければ、カードはこの機能を有効化する前とまったく同じです——ボタンが欠けることも、メッセージが届かなくなることもありません。

http://localhost:18789 のようなローカルアドレスは、有効なダッシュボードの場所ではあっても、有効な Mini App の場所ではありません。公開 https ドメインを持たないデプロイ(ほとんどのローカルインストールがこれに該当)は何もする必要がなく、この機能は沈黙したままです。


Telegram が Mini App を開くとき、ユーザー id と開いた時刻を含む署名済みの initData が添付されます。署名鍵の素材はあなた自身の bot token です。DuDuClaw は公式ドキュメントどおりに再計算します:

data_check_string = hash 以外のすべてのフィールドをアルファベット順に並べ、\n で連結
secret_key = HMAC_SHA256(<bot_token>, "WebAppData")
hash = hex(HMAC_SHA256(data_check_string, secret_key))

算出した値は Telegram が添付した hash と定数時間で比較します。一致しなければ何も返しません——この承認が存在するかどうかすら明かさず、簡略版を返すこともありません。

署名の他に、さらに3つの関門があります:

  1. auth_date が1時間を超えていれば期限切れ(画面を開いたまま放置した場合は会話から開き直す)。タイムスタンプがあり得ないほど未来を指す場合も同様に拒否。
  2. user フィールドに数値 id が含まれていなければ拒否。
  3. エンドポイントには IP ごと・分ごとのリクエスト上限がある。

URL 上の ?id=<番号>資格情報ではありません。番号を知っていても誰にも内容は見えません——ページ自体はデータを持たず、データは署名検証済みの POST を通じてのみ取得できます。

第二の権限体系はありません。 Mini App が識別する Telegram ユーザー id は、カードのボタンを押したときに報告される id と同一なので、送信された決定はボタンとまったく同じ経路を通ります:

  • ダッシュボードで検証済みのバインディングを持ち、役割が管理者/スーパーバイザーの人は決定できる;
  • 一般従業員アカウントは不可(受信者本人であっても不可——職務分離のため);
  • チャネルアカウントを誰もバインドしていないデプロイでは、「カードが届いたアカウント本人」だけが決定できる。

詳細の閲覧にも同じ判定が適用され、緩い読み取り専用ルールはありません:決定できない人は内容も見られません。

bot token は HMAC の鍵素材としてのみ使われ、ログに書かれず、レスポンスに含まれず、ページにも入りません。ページ自体にバックエンドの詳細は一切なく、エラーメッセージはすべて「会話から開き直してください」のような人間向けの文言です。


  • グループにはこのボタンが付きません。 Telegram は web_app ボタンをユーザーと bot のプライベートチャットのみに許可しています。グループにプッシュされたカードは従来の承認/拒否の2ボタンのまま——これは意図的です:無理に付けるとメッセージ全体が送信できなくなります。
  • https は必須。 Telegram の規定であり、本プロジェクトの選択ではありません。
  • 承認カード1枚のみ。 タスク・支出・ステータスのカードは、これまでどおり既存のボタンとダッシュボードのディープリンクを使います。
  • Telegram のみ。 LINE LIFF・Teams Dialog・Feishu Web App には同等の能力がありますが、今回は実装していません。Slack・WhatsApp・Google Chat・Discord には同等の仕組みがなく、今後も「カードボタン+ネイティブフォーム」の路線のみです。
  • ページは telegram.org からプラットフォーム SDK を取得します。 これは Telegram.WebAppinitData・テーマパラメータ・ウィンドウを閉じる)を得る唯一のサポートされた方法です。SDK が取得できなくてもページは壊れません——URL フラグメント(tgWebAppData)から同じデータを読み、自動クローズだけが失われます。それ以外にページに外部リソースはありません:CSS・JS はすべてインラインで、CDN もフォントも画像もありません。

ローカルマシンには公開 https がなく webview が開けないため、以下は公開デプロイのある環境で実行してください:

  1. [miniapp] enabled = true と https の [dashboard] public_url を設定し、gateway を再起動する。
  2. ブラウザで https://あなたのドメイン/miniapp/approval?id=test を開く——「請從對話中開啟」(会話から開いてください)が表示されるはずです。ページが生きていて、身元なしにはデータを渡さない証拠です。
  3. 人間の承認が必要なアクションをトリガーし、bot とのプライベートチャットにカードを届かせる。
  4. カードに3つ目のボタン「🔎 查看詳情」が現れるはずです。開くと完全な内容とカウントダウンが見えます。
  5. 画面内で承認または拒否 → チャット内の元のカードがその場で1行の結果に畳まれます(ボタンを押したときと同じ挙動)。
  6. ネガティブテスト:同じ URL を決定権限のない人に渡す。開くと「您沒有查看這筆決定的權限」(この決定を閲覧する権限がありません)だけが表示されるはずです。