コンテンツにスキップ

チャットチャネルでの承認と回答

AI 社員が高リスクの操作(現時点ではコンピューター操作の高リスクステップ)を行うとき、応答中の会話で人に判断を求めることがあります。各リクエストには完全な ID があります。同じ bot アカウント、同じ会話またはスレッドで、ID を付けて返信してください。

確認 <完全なリクエスト UUID> approve <完全なリクエスト UUID>
取消 <完全なリクエスト UUID> deny <完全なリクエスト UUID>
回答 <完全なリクエスト UUID> <回答> answer <完全なリクエスト UUID> <回答>

最初の語がこの 6 つの動詞のどれかで、2 番目の語が完全なリクエスト UUID であるメッセージだけが判断として扱われます。それ以外は通常の会話で、これまでどおり社員に渡されます。

  • 「確認」だけ(たとえば社員が「送信しますか」と聞いた後の返事)、“approve the Q3 budget”、“deny it”:そのままモデルに届き、bot が自分でエラーを返すことはありません。
  • 古い判断カードに動詞だけで返信する方法(「同意」「拒絕」「取消」、approve、deny。ウォッチ向けのテキスト返信)は、そのカード本来の処理でこれまでどおり動きます。
  • 「是」、yes、A/B だけ、または不完全な ID では、どのリクエストも判断されません。

完全な ID を含むコマンドの小さな打ち間違いは、社員に渡さずに判断として扱います。語と語の間の複数の空白や全角空白、ID の直後や文末の閉じ句読点(確認 <ID>。、approve <ID>.、確認 <ID>!)です。ID は大文字やハイフンなしでもかまいません。動詞は最初の語で、上の表とまったく同じ表記である必要があります(Approve、確認:<ID>、簡体字の「确认」は判断になりません)。

リクエストには 2 種類あります。質問は回答を集めるもので(回答/answer)、回答はデータとして保存されるだけで操作を許可しません。承認(確認/取消、approve/deny)は 1 つの操作を許可または拒否します。確認 <質問 ID> と 回答 <承認 ID> はどちらも拒否されます。

次のすべてを満たす必要があります。

  1. そのターンを起こした本人。 リクエストは bot のプラットフォームアカウント、会話またはスレッド、ターンを起こしたメッセージの送信者に結び付けられます。同じグループの別のメンバー、別の会話にいる同じ人、同じデプロイの別の bot、表示名では判断できません。Telegram の匿名管理者、「チャンネルとして投稿」するメンバー、リンクされたチャンネルからの自動転送は共通の仮の送信者 ID を使うため、これらのメッセージはリクエストを作らず、判断もできません。転送されたメッセージも判断になりません。他人の「確認 」を転送しても、転送した人が同意したことにはなりません。
  2. ダッシュボードのユーザーがいるデプロイでは、検証済みの Admin または Manager。 users.db にユーザーが 1 人でもいれば、その人は Active な Admin または Manager アカウントに結び付いた検証済みのチャネル ID を持っている必要があります。Employee、未連携、未検証の連携は拒否されます。ターンを起こした本人ではない Manager はチャネルで代わりに判断できないため、ダッシュボードを使ってください。
  3. ひとり運用のデプロイ。 ダッシュボードのユーザーがまったくいない場合に限り、ターンを起こした本人が自分のリクエストを判断できます。
  4. チャネルのアクセス設定も適用されます。 判断の時点で許可リスト、ブロックリスト、ペアリング、チャンネルとサーバー(guild)の設定を読み直し、それらで拒否される送信者は判断できません。allowed_users がありペアリングがオフの場合、送信者と会話の両方がリストに必要です。ペアリングがオンの場合は、どちらか一方が通れば十分です。通常のメッセージにも同じ規則が適用されます。

質問への回答は 1 と 4 が条件です。回答できるのはターンを起こした本人だけで、チャネルのアクセス設定も適用されますが、Admin や Manager のロールは不要です。

送信者が結び付けられた本人だと bot が確認できる前に拒否される判断(ID が存在しない、別のアカウント/会話/人のリクエスト、チャネル設定で拒否される送信者)には、常に同じ一文が返ります。そのため、どの ID が存在するかを探る手段にはなりません。入力したコマンドでもボタンでも、アクセス確認はリクエストの照会より先に行います。

同じグループに DuDuClaw の bot が複数いる場合、判断コマンドを受け取った bot はそれぞれ 1 回ずつ返信します(リクエストが自分のものでない bot は同じ拒否文を返します)。これは意図的です。他の bot のリクエストのときだけ黙ると、その沈黙自体がどの ID が存在するかを漏らしてしまいます。

リクエストに結び付けられるもの

Section titled “リクエストに結び付けられるもの”

承認は、依頼した社員、bot アカウント、人、会話またはスレッド、正確な操作のダイジェスト、ポリシー、有効期限に結び付きます。タスクがある場合はタスクの契約とその revision にも結び付き、契約の変更、一時停止、再開の後は再承認が必要です。同じ ID と内容でタスクを作り直しても古い承認は復活しません。期限切れ、取り消し、不明な形式、破損した結び付けはすべて拒否されます。古いリクエストは従来の処理のままで、新しい再開権限は得ません。

高リスクの確認は、社員が応答中の信頼済みチャネル入口が作成し、その入口の実際のアカウントとスレッドで送ります。Telegram は getMe で検証した bot ID、Slack は auth.test と bots.info の team・user・app ID を使い各イベントと照合し、Discord は接続中の application ID、LINE は署名検証済みの destination と source を使います。認証情報はメモリにだけ置き、承認データベースには書かず、グローバル bot にも切り替えません。

承認後、実行前に、ゲートウェイは社員の権限、実行許可、タスクの取り消し、期限、停止と一時停止を再確認し、画面とフォーカス中のウィンドウを観察し直します。変化があればリクエストは無効になり、観察と承認をやり直す必要があります。チャンネルを許可リストから外しても承認済みの操作は取り消されません。止めるにはリクエストの取り消し、セッションの停止、許可の取り消しを使ってください。入力文字はダイジェストと文字数だけを保存します。ゲートウェイの再起動後、古い画面の承認は restart_requires_reobserve になり、古い座標は再生されません。

~/.duduclaw/threat_level は運用者の緊急停止スイッチです。ファイルが無ければ GREEN です。GREEN、YELLOW、RED は大文字小文字を問わず、前後の空白と先頭の UTF-8 BOM は無視します。ファイルはあるのに読めない、空、内容が分からない場合は 50 ミリ秒間隔でさらに 2 回読み直し(echo GREEN > threat_level は一瞬ファイルを空にします)、それでも不明なら RED として扱います。この隙間を避けるため、一時ファイルに書いてから名前を変える方法で書き込んでください。

Telegram のポーリングと Slack の Socket Mode は、完全な ID の判断を受信側で、会話キューに入る前に処理します。そのため自分の確認を待っているコンピューター操作がそれを塞ぐことはありません(Telegram グループの @bot 確認 <ID> も同様。取り除くのはメッセージの先頭にあるこの bot へのメンションだけで、大文字小文字は問いません)。LINE は判断イベントを独立した永続 worker に回します。Discord では判断メッセージと判断ボタンが専用の小さな処理枠を持ち、通常の返信用の 10 枠とは別です。この枠を得られるのはチャネルのアクセス確認を通った送信者だけで、判断メッセージは添付ファイルをダウンロードしないため、偽の判断を連投しても枠を占有できません。通常のメッセージの添付ファイルのダウンロードは 30 秒で打ち切ります。通常の作業は会話ごとに上限付きで並び、キューが満杯のときは受け付けなかったことを bot が伝えます。

Discord のボタンはプラットフォームが検証したチャンネル ID、種類、guild を使います。guild のメッセージごとに bot はまず現在のチャンネルの ID、guild、種類を照会し、照会に失敗したり食い違ったりした場合はそのメッセージを処理しません。DM はプラットフォームの DM 情報を使います。

次の入口ではこの確認を作れず、結び付けられたリクエストも判断できません。ここから始まった高リスクのコンピューター操作は拒否されます。

  • WhatsApp、Feishu、Microsoft Teams、Google Chat、WeCom、DingTalk、WebChat
  • Telegram Mini App
  • Slack と Discord のスラッシュコマンド
  • スケジュール(cron)、リマインダー、委任された作業

これらの既存のカードボタンとテキスト返信は、従来から扱っている古い種類のリクエストをこれまでどおり判断します。これらの入口で「確認 」と入力しても結び付けられたリクエストには影響せず、メッセージは通常どおり社員に渡されます。

結び付けられたリクエストには、ボタン付きの古い形式のリマインダーカードは送られません。判断できるのは、そのリクエスト自身の会話での完全な ID による返信か、ダッシュボードだけです。

ダッシュボードでのみ判断できる種類

Section titled “ダッシュボードでのみ判断できる種類”

ゲートウェイ内蔵の「ダッシュボードのみ」リストが基準で、現在は次のとおりです。

  • ナレッジレビュー(保留された記憶の主張)
  • duduclaw ops channel-ingress で申請された LINE 受信箱の操作
  • ワークフローの有効化
  • 結果が不明な操作の照合(approvals.resolve_uncertain、Admin のみ)

これらにチャネルで返信しても効果はありません。

Slack には users:read スコープが必要

Section titled “Slack には users:read スコープが必要”

Slack の判断は bot 自身の検証済みアカウントに結び付きます。その検証には bots.info が必要で、bots.info には bot token の users:read スコープが必要です。これが無いとアカウントを検証できず、その bot でのすべての判断とコンピューター操作の確認が拒否されます(fail closed)。このときゲートウェイは次のことを行います。

  • その bot に送られた判断に、Slack では判断できないのでダッシュボードを使うよう伝える一文を返す
  • bot ごと、ゲートウェイのプロセスごとに最初の失敗で Activity Feed を 1 件(slack_decision_identity_unavailable)書く
  • その bot を <home>/state/slack_decision_identity.json に記録し、duduclaw doctor の「Slack 決定身分」行に表示する

users:read を追加し、アプリをワークスペースに再インストールして、ゲートウェイの再接続を待ってください。接続に成功すると doctor のこの行は消えます。

承認は実行ではありません。操作台帳は prepared、executing、succeeded/failed/uncertain を順に記録します。実行時はリースと増加する fence を持ち、受領記録なしでプロセスが終わった操作は uncertain になり、自動で再送されません。

Admin は approvals.operations で台帳をページ単位で見る(before_rowid、limit 1–500)か、operation_id で 1 件を確認できます。approvals.resolve_uncertain は操作 ID、現在の fence、成功か失敗か、実際の受領記録、理由を受け取り、状態を確定させるだけで再実行はしません。ダッシュボードでの判断は別の管理権限で、チャネルのユーザーに代わって質問に答えることはできません。approvals.list は結び付けの詳細と回答を、そのリクエストを判断できる人にだけ、現在のロールで判断して返します。

Unix では approvals.db を 0600 で作成し、既存ファイルと WAL/SHM の権限も絞ります。データベースや sidecar がシンボリックリンクの場合は拒否します。このバージョンには台帳の自動削除ジョブはありません。

操作の run_id はサーバーが作成します。永続受信は受け付けたイベントの run ID(run_origin_kind=ingress)、その他の信頼済み入口はコンピューター操作のセッション ID(computer_session)を使います。

  • 最後の画面確認から入力までの間に、人や OS がデスクトップを変えることはあります。ゲートウェイは承認、監査、台帳の書き込みの後に観察し直し、既知の古い画面と取り消された権限を拒否しますが、外部のデスクトップを原子的に止めることはできません。
  • 実際の Telegram supergroup では未検証:フォーラムではない supergroup での返信に message_thread_id が付くかどうか。付く場合、返信として送った確認がその返信スレッドの外で起きたリクエストと一致せず、拒否されます(誤って承認されることはありません)。通常のメッセージとして確認を送ってください。
  • Slack のロール照合はチャンネルとユーザー ID だけを使い、ワークスペースを含みません。リクエスト自体は bot の team と app に結び付いているため、影響するのは複数の Slack ワークスペースを使うデプロイでどのダッシュボードロールが参照されるかだけです。

英語版:durable-channel-decisions.md、繁体字中国語版:zh-TW/durable-channel-decisions.md。