1278 lines
49 KiB
Markdown
1278 lines
49 KiB
Markdown
# 汎用Hook機構とAuto Prompterの実現可能性調査
|
||
|
||
調査日: 2026-07-24
|
||
対象: MAESTRO(gitea-agent-orchestrator)
|
||
注記: 本調査ではコード変更を行っていない。
|
||
|
||
## 1. 結論
|
||
|
||
**縮小して実装すべきである。**
|
||
|
||
推奨範囲は次のとおり。
|
||
|
||
- 観測は、既存 `EventLogger` を拡張した非同期・fail-openのイベント通知とする。
|
||
- 制御は、初期段階ではツール実行前だけに同期的な `PolicyGate` を追加する。
|
||
- Auto Prompterは、決定的条件で候補を絞った後、必要な場合だけ小型LLMが登録済みルールIDを三値判定する。
|
||
- 承認機構はHookへ移さず、独立した承認サービスへ一般化してHookから呼び出す。
|
||
- Completeでは、初期段階は観測と軽量な最終確認だけを行う。
|
||
- Piece/Movementは、初期段階では観測対象とscope情報に限定し、遷移制御へ介入しない。
|
||
|
||
全面的な汎用Hook化、既存権限処理の置換、生成ストリーム途中の判定、Piece/Movement遷移制御は推奨しない。
|
||
|
||
最終判断は以下である。
|
||
|
||
> **ツール実行前Hookだけ実装し、既存承認機構を中心に拡張する。観測Hookと監査ログは既存EventLogger上へ追加する。**
|
||
|
||
製品方針は [Auto Prompter ワークスペース機能 設計方針](./auto-prompter-workspace-design.md) を正とする。一般ユーザーがワークスペース単位で設定できる機能として提供するが、公開は段階化する。初期段階では常時適用ルール、テンプレート、決定的条件、shadow判定を中心とし、自由記述の自然言語条件を使う制御actionは評価基準を満たした後に有効化する。
|
||
|
||
EU AI Actの透明性、監査、人間監督、provenance、保持方針は [EU AI Act透明性対応 設計付録](./auto-prompter-eu-ai-act-transparency-design.md) を参照する。法的義務と自主的統制を分け、hidden chain-of-thoughtの保存や一律5年保持を前提にしない。
|
||
|
||
---
|
||
|
||
## 2. 現在の関連機能と処理フロー
|
||
|
||
### 2.1 エージェントのメインループ
|
||
|
||
中心は `src/engine/agent-loop.ts` の `executeMovement()` である。
|
||
|
||
1. Movement用プロンプトとツールを準備
|
||
2. iterationごとに途中指示を取り込む
|
||
3. LLMをストリーミング実行
|
||
4. tool callを通常ツール、`transition`、`complete` に分類
|
||
5. 通常ツールを実行
|
||
6. 待機・承認状態を確認
|
||
7. `complete` またはMovement遷移を処理
|
||
|
||
### 2.2 LLM呼び出し前後
|
||
|
||
LLM呼び出し前:
|
||
|
||
- キャンセル確認
|
||
- 途中指示の取り込み
|
||
- watchdog
|
||
- コンテキスト超過検査・圧縮
|
||
- LLM呼び出し開始イベント
|
||
|
||
LLM呼び出し後:
|
||
|
||
- SSEのテキスト・tool call集約
|
||
- エラー回復
|
||
- usage更新
|
||
- tool call分類
|
||
- tool dispatch
|
||
- `complete` / `transition` 処理
|
||
|
||
主な実装:
|
||
|
||
- `src/engine/agent-loop/llm-iteration.ts`
|
||
- `src/engine/llm-stream.ts`
|
||
- `src/llm/openai-compat.ts`
|
||
|
||
### 2.3 ストリーミング応答
|
||
|
||
`OpenAICompatClient.chat()` がOpenAI互換SSEを読み、`consumeLlmStream()` が以下を集約する。
|
||
|
||
- テキスト
|
||
- tool call
|
||
- tool引数delta
|
||
- usage
|
||
- reasoning文字数
|
||
- backend情報
|
||
- retry/error
|
||
|
||
現状ではテキストchunkがUI callbackへ即時送信される。生成途中のAuto Prompter判定には、ストリーム保留、abort、再生成、部分表示の整合処理が必要となるため、初期実装では扱わない方が安全である。
|
||
|
||
### 2.4 動作途中の追加プロンプト
|
||
|
||
iteration間で `checkInterjections()` がユーザーコメントを取得し、次の形式で `messages` に追加する。
|
||
|
||
```text
|
||
[interjection] ユーザーの追加指示
|
||
```
|
||
|
||
Auto Prompterの追加指示にも同じmessage injection方式を再利用できる。DBコメントを経由させる必要はなく、message injection部分を内部サービスとして抽出するのが適切である。
|
||
|
||
### 2.5 ツール実行
|
||
|
||
```text
|
||
dispatchRegularToolCalls
|
||
└─ executeRegularToolCallCached
|
||
├─ tool_callイベント
|
||
├─ キャッシュ判定
|
||
└─ executeRegularToolCall
|
||
├─ Movement内の許可判定
|
||
├─ 引数JSON parse
|
||
└─ executeTool
|
||
└─ 各ツールモジュールへルーティング
|
||
```
|
||
|
||
主な実装:
|
||
|
||
- `src/engine/agent-loop/tool-dispatcher.ts`
|
||
- `src/engine/agent-loop/tool-execution.ts`
|
||
- `src/engine/tools/index.ts`
|
||
|
||
許可外ツールは `isAllowedRegularTool()` で拒否され、エラーのtool resultとしてモデルへ返される。拒否記録はベストエフォートで、記録失敗によってツール処理を壊さない。
|
||
|
||
### 2.6 許可申請と承認
|
||
|
||
現在は `RequestTool` 専用フローである。
|
||
|
||
```text
|
||
RequestTool
|
||
→ tool_requestsへpending保存
|
||
→ pendingToolApprovalを設定
|
||
→ MovementをWAITING_HUMAN_TOOL_REQUESTで終了
|
||
→ UIに承認カード
|
||
→ approve/deny API
|
||
→ approveならlocal_tasks.granted_toolsへツール名追加
|
||
→ parked jobを再開
|
||
→ 同じMovementを最初から再実行
|
||
```
|
||
|
||
主な実装:
|
||
|
||
- `src/engine/tools/tool-request.ts`
|
||
- `src/engine/agent-loop/pending-states.ts`
|
||
- `src/bridge/local-tasks-tool-requests-api.ts`
|
||
- `src/db/repositories/tool-requests.ts`
|
||
- `ui/src/components/chat/ToolRequestApproval.tsx`
|
||
|
||
現在の承認単位は「タスク中のツール名」であり、引数、操作内容、Movement、期限、回数は承認対象へ固定されない。
|
||
|
||
### 2.7 PieceとMovement
|
||
|
||
`src/engine/piece-runner.ts` の `runPiece()` がMovementループを所有する。
|
||
|
||
- Piece定義の検証
|
||
- Movement選択
|
||
- 再訪問回数制限
|
||
- Movement開始通知
|
||
- `executeMovement()`
|
||
- Movement結果の保存
|
||
- `COMPLETE` / `ABORT` / `ASK` / 各種待機状態の変換
|
||
- 次Movementの選択
|
||
- Piece完了通知
|
||
|
||
### 2.8 CompleteとMovement遷移
|
||
|
||
- `complete`: JSON引数を検証し、成功・中断・ユーザー入力待ちへ変換
|
||
- `transition`: 現在Movementの `rules` に含まれる遷移先だけ受理
|
||
- 不正なtool callにはtool resultで理由を返し、再試行
|
||
- pending subtaskがある成功Completeは自動待機へ変換
|
||
|
||
実装は `src/engine/agent-loop/terminal-control.ts` にある。
|
||
|
||
### 2.9 会話・状態・イベント
|
||
|
||
- 会話履歴: `Conversation`。メモリ上のmessagesとJSONL transcript
|
||
- タスク状態: Repository/SQLite
|
||
- 実行中状態: `ToolContext`、`ExecuteMovementOptions`
|
||
- 監査・診断: `EventLogger` による `logs/events.jsonl`
|
||
- UI通知: callback → reporter → SSE/DB comment
|
||
- ログ: 通常logger、activity log、event log
|
||
|
||
`EventLogger` は構造化イベント、run ID、連番、相関ID、Movement scope、マスキング、サイズ制限、書き込み失敗時のNoop化を既に備える。
|
||
|
||
現状、一般的なmiddleware/pluginバスはない。`EventLogger` は観測イベントバスに最も近いが、購読型ではなくファイル出力型である。
|
||
|
||
---
|
||
|
||
## 3. Hook追加候補地点
|
||
|
||
| タイミング | 分類 | 理由 |
|
||
|---|---|---|
|
||
| ツール実行前 | 初期実装に必要 | 副作用前に確実に保留・拒否・承認できる |
|
||
| ツール拒否時 | 初期実装に必要 | 既存ブロック結果と監査を統合しやすい |
|
||
| ツール実行後 | 初期実装に必要 | 結果監査。観測専用・非ブロッキング |
|
||
| Complete受理前 | 初期実装に必要 | 最終確認用。ただし最初は軽量 |
|
||
| エラー発生時 | 初期実装に必要 | 観測イベントのみ |
|
||
| Movement開始前 | 将来追加すると有用 | Movement別ルール選択、固定指示 |
|
||
| Movement完了前 | 将来追加すると有用 | 遷移前確認。ただし回帰リスクあり |
|
||
| Movement遷移後 | 将来追加すると有用 | 監査のみなら低リスク |
|
||
| Piece開始前 | 将来追加すると有用 | 監査・ルールスナップショット |
|
||
| LLM呼び出し前 | 将来追加すると有用 | コンテキスト検査や固定指示 |
|
||
| LLM応答後 | 将来追加すると有用 | テキスト品質検査。ただし再生成設計が必要 |
|
||
| 許可申請時 | 将来追加すると有用 | 承認理由の監査・ポリシー拒否 |
|
||
| ユーザー承認・拒否時 | 将来追加すると有用 | 承認監査、再申請制御 |
|
||
| Movement遷移前の制御 | 複雑化が大きい | Piece中核と競合しやすい |
|
||
| Piece完了前の制御 | 複雑化が大きい | Completeと二重の終了判定になる |
|
||
| 生成stream途中 | 複雑化が大きい | 保留、abort、再生成、部分表示整合が必要 |
|
||
| LLM tokenごとのHook | 複雑化が大きい | 現行OpenAI互換APIでは実用的でない |
|
||
|
||
初期Hook名は次で十分である。
|
||
|
||
```text
|
||
tool.before
|
||
tool.after
|
||
tool.denied
|
||
completion.before_accept
|
||
runtime.error
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 推奨するHookアーキテクチャ
|
||
|
||
### 4.1 観測と制御のハイブリッド
|
||
|
||
```text
|
||
┌─ Auto Prompter
|
||
処理地点 ── PolicyGate ─┼─ Approval Service
|
||
│ 同期・制御 └─ Security Policy
|
||
│
|
||
└──── EventSink ────── Audit / Trace / Notification
|
||
非同期・観測
|
||
```
|
||
|
||
### 4.2 制御用インターフェース
|
||
|
||
```ts
|
||
type GateDecision =
|
||
| { kind: "allow" }
|
||
| {
|
||
kind: "redirect";
|
||
messages: RegisteredPrompt[];
|
||
consumeOriginalAction: true;
|
||
}
|
||
| {
|
||
kind: "require_approval";
|
||
request: ApprovalRequest;
|
||
consumeOriginalAction: true;
|
||
}
|
||
| {
|
||
kind: "deny";
|
||
reasonCode: string;
|
||
modelMessage: string;
|
||
}
|
||
| {
|
||
kind: "stop";
|
||
reasonCode: string;
|
||
};
|
||
|
||
interface PolicyGate {
|
||
evaluate(
|
||
point: ControlPoint,
|
||
context: Readonly<PolicyContext>,
|
||
): Promise<GateDecision>;
|
||
}
|
||
```
|
||
|
||
Hookが本体状態を直接変更せず、返却値だけで制御する構成とする。
|
||
|
||
### 4.3 観測用インターフェース
|
||
|
||
```ts
|
||
interface EventSink {
|
||
publish(event: HookObservation): void;
|
||
}
|
||
```
|
||
|
||
観測Hookは原則として以下を守る。
|
||
|
||
- awaitしない
|
||
- 失敗しても本体を止めない
|
||
- 本体状態を変更しない
|
||
- timeoutを短くする
|
||
- 管理者通知はqueueへ送る
|
||
|
||
観測、助言、制御、承認を単一の自由度が高いHook型へ統合しない。
|
||
|
||
| 種類 | 実装 |
|
||
|---|---|
|
||
| 観測 | `EventSink` |
|
||
| 助言 | `GateDecision.redirect` |
|
||
| 拒否・停止 | `PolicyGate` |
|
||
| 承認 | `ApprovalService`をPolicyGateから呼ぶ |
|
||
|
||
---
|
||
|
||
## 5. Auto Prompterの責任範囲
|
||
|
||
Auto Prompterが行うのは、登録済みルールの選択までとする。
|
||
|
||
行わせない処理:
|
||
|
||
- 新しいポリシー文の自由生成
|
||
- 停止理由の自由生成
|
||
- ツール引数の書き換え
|
||
- 直接的な権限付与
|
||
- Piece/Movement遷移先の生成
|
||
- 管理者通知文の自由生成
|
||
- ルール自体の自動変更
|
||
|
||
```text
|
||
ルール候補の決定的フィルタ
|
||
→ 必要な候補だけ意味判定
|
||
→ rule ID + 三値結果
|
||
→ MAESTROが登録済みactionを実行
|
||
```
|
||
|
||
```ts
|
||
type AutoPrompterAction =
|
||
| "inject_instruction"
|
||
| "deny_current_tool"
|
||
| "request_approval"
|
||
| "stop_task"
|
||
| "audit_only"
|
||
| "notify_admin";
|
||
```
|
||
|
||
`notify_admin` 単独で利用者制限を実行してはならない。
|
||
|
||
---
|
||
|
||
## 6. 判定モデルの構成
|
||
|
||
### 6.1 入力
|
||
|
||
会話全文は原則として渡さない。
|
||
|
||
```json
|
||
{
|
||
"rules": [
|
||
{
|
||
"id": "rule-12",
|
||
"condition": "元に戻すことが難しい削除を行おうとしている"
|
||
}
|
||
],
|
||
"current": {
|
||
"piece": "coding",
|
||
"movement": "implement",
|
||
"hook_point": "tool.before",
|
||
"tool": {
|
||
"name": "Bash",
|
||
"category": "command_execution",
|
||
"arguments_summary": "rm ...",
|
||
"arguments": "必要な範囲に限定した文字列"
|
||
}
|
||
},
|
||
"context": {
|
||
"latest_user_message": "...",
|
||
"recent_messages": ["最大数件"],
|
||
"previous_rule_fires": [
|
||
{"rule_id": "rule-12", "count": 0}
|
||
],
|
||
"approval_state": "none"
|
||
}
|
||
}
|
||
```
|
||
|
||
| 情報 | 方針 |
|
||
|---|---|
|
||
| 会話全文 | 原則渡さない |
|
||
| 最新ユーザー入力 | 渡す |
|
||
| 直近会話 | 必要時のみ2~4 turn |
|
||
| Piece/Movement | 渡す |
|
||
| ツール名・カテゴリ | 必須 |
|
||
| ツール引数 | 対象キーのみ。秘密値を除去 |
|
||
| ツール結果 | `tool.after` ルールだけ |
|
||
| 過去発火 | rule ID、回数、直近fingerprintのみ |
|
||
| ユーザー権限 | 決定的フィルタ側で使用 |
|
||
| 登録済み指示本文 | Judgeへ渡さない方が安全 |
|
||
|
||
Judge入力は外部送信境界として扱う。監査保存時と同じfield allowlistを先に適用し、その後で秘密値をマスクする。会話は必要箇所の要約または最大2~4 turnへ制限し、条件文、tool引数、Web取得内容は命令ではなく非信頼データとして構造的に分離する。Judge用endpoint、model、timeout、最大並列数は本体LLMと独立して設定し、設定値はJob開始時に固定する。
|
||
|
||
### 6.2 出力
|
||
|
||
```json
|
||
{
|
||
"decisions": [
|
||
{
|
||
"rule_id": "rule-12",
|
||
"result": "match",
|
||
"confidence": 0.91
|
||
},
|
||
{
|
||
"rule_id": "rule-18",
|
||
"result": "unknown",
|
||
"confidence": 0.42
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
結果は `match | no_match | unknown` に限定し、説明文は要求しない。
|
||
|
||
確信度は監査・shadow評価には使えるが、安全保証には利用しない。
|
||
|
||
- `match`: 登録actionを実行
|
||
- `no_match`: 通常処理
|
||
- `unknown`:
|
||
- `audit_only` / 追加指示では発火しない
|
||
- 重大な削除・外部送信では決定的安全規則または承認へフォールバック
|
||
- タスク停止は発火しない
|
||
|
||
複数ルールは、Hook pointとカテゴリで候補を絞り、最大10件程度を一括判定する。毎ルール個別呼び出しは避ける。
|
||
|
||
### 6.3 小型LLMを使わない条件
|
||
|
||
- tool名・カテゴリ
|
||
- Piece/Movement
|
||
- ユーザー権限
|
||
- 発火回数
|
||
- 既存承認状態
|
||
- 既知のファイル削除
|
||
- `chmod`、`chown`、`rm` 等の操作
|
||
- 外部通信ツール
|
||
- 言語文字比率
|
||
- 許可外ツール
|
||
- 同一入力fingerprint
|
||
- タスク/Piece/Movement scope
|
||
|
||
### 6.4 Judge失敗時の扱い
|
||
|
||
| ルール種別 | timeout・schema不正・`unknown`時 |
|
||
|---|---|
|
||
| 常時適用 | Judgeを使用しない |
|
||
| スタイル・説明改善 | 発火させず監査だけ残す |
|
||
| `audit_only` | 判定失敗イベントだけ残し、本体処理を継続する |
|
||
| 危険操作 | Judgeへ委ねず、決定的規則または既存安全境界で処理する |
|
||
| 承認候補 | 決定的条件が成立していれば承認へ、安全性に無関係な意味条件だけなら発火しない |
|
||
| `stop_task` | Judge失敗だけでは停止しない |
|
||
|
||
Judgeの出力schemaにはversionを持たせ、未対応version、未知のrule ID、重複IDを不正応答として扱う。
|
||
|
||
---
|
||
|
||
## 7. ツール実行前ゲート
|
||
|
||
実現可能である。最適な論理順序は、引数parseと基本許可判定の後、キャッシュ判定より前である。
|
||
|
||
現行の `executeRegularToolCallCached()` はcache routingを行った後で `executeRegularToolCall()` 内の許可判定と引数parseへ進む。このため、既存関数へ単純にHookを追加するだけではcache hitがPolicyGateを迂回する。機能ON時だけ、parse・基本許可判定・PolicyGateをcache routingより前へ移すpreflight経路が必要である。機能OFF時はpreflight、clone、normalize、serializeを行わず、現在のdispatcherへ直接短絡する。
|
||
|
||
```text
|
||
tool call受信
|
||
→ JSON parse
|
||
→ 基本許可判定
|
||
→ ToolPolicyContext構築
|
||
→ PolicyGate.evaluate(tool.before)
|
||
├─ allow
|
||
├─ redirect
|
||
├─ require_approval
|
||
├─ deny
|
||
└─ stop
|
||
→ allowの場合だけcache/executeTool
|
||
```
|
||
|
||
preflightのparse結果は `valid | invalid` として保持する。不正JSONをPolicyGate独自の入力エラーへ置き換えず、tool名・カテゴリだけで成立する決定的規則を除いて意味判定を行わない。Policyで保留されなければ、既存tool validationへ渡して従来と同じエラーtool resultを生成する。これにより機能ON時も入力検証の責任とエラー形式を変えない。
|
||
|
||
### 7.1 batch事前評価
|
||
|
||
`dispatchRegularToolCalls()` は `Read`、`Glob`、`Grep`、`WebSearch`、`WebFetch`、`ReadImage` を並列実行できる。特に外部通信を含むbatchでは、各callを実行しながら個別にPolicyGateへ掛けると、1件を保留した時点で兄弟callが実行済みになる。
|
||
|
||
初期実装では、iteration内のregular tool callを副作用前に一括preflightする。競合解決は、各call内のrule競合とiteration全体のbatch集約を分離する。
|
||
|
||
```text
|
||
全regular tool callをparse・基本許可判定
|
||
→ callごとにrule actionを解決
|
||
stop > deny > require_approval > redirect > audit_only / allow
|
||
→ iteration全体へbatch集約
|
||
stopが1件以上
|
||
└─ regular・complete・transitionを含む全callを実行せず結果を記録してABORT
|
||
require_approvalまたはredirectが1件以上
|
||
└─ regular・complete・transitionを含む全callを実行せず結果を記録して保留
|
||
denyだけが含まれる
|
||
└─ deny対象は実行せず、残りは実行して全callへtool resultを作る
|
||
全件allow / audit_only
|
||
└─ 既存の並列・逐次dispatcherへ渡す
|
||
```
|
||
|
||
`require_approval` または `redirect` でiterationを保留する場合、同じassistant messageへco-emitされたComplete/transitionも受理しない。全tool call IDへ合成tool resultを記録してから、承認待ちまたは次iterationへ進む。`stop` は同様に全tool resultを記録した後、hard-terminal abort reason `policy_stopped` を持つABORTへ変換する。denyだけの場合はdeny対象へ合成resultを作り、残りは既存dispatcherへ渡す。InteractiveBrowse等が待機へ入った場合を含め、以後の記録・再開は既存挙動を維持する。
|
||
|
||
preflight後に実行しないcallについては、grounding reservationをreleaseまたは非引用の結果でfulfillし、未解決の出典予約を残さない。初期実装では安全側へ寄せ、制御状態を変えるdecisionが含まれるiterationを部分実行しない。将来、tool間の独立性を証明できる場合だけ、カテゴリ別の部分実行を検討する。
|
||
|
||
### 7.2 追加指示とmessage順序
|
||
|
||
元のtool callを実行せず、対応するtool resultを作る。
|
||
|
||
```text
|
||
実行は保留されました。
|
||
登録済みルール rule-12 により、次の確認を行ってから新しいtool callを作成してください:
|
||
「削除対象と復元方法を確認してください」
|
||
```
|
||
|
||
定型指示をuser messageとして追加し、次iterationへ戻す。元のtool callは消費済みとし、LLMが改めて新しい引数で呼び直す。
|
||
|
||
providerのtool call対応関係を壊さないため、同一iterationでは次の順序を必須とする。
|
||
|
||
```text
|
||
assistant: tool calls
|
||
tool: call Aの実結果または合成結果
|
||
tool: call Bの実結果または合成結果
|
||
tool: call Cの実結果または合成結果
|
||
user: 統合済みの登録指示
|
||
```
|
||
|
||
追加指示は全tool resultの後に1件だけ追記する。複数のredirectは優先順位順に重複除去して統合する。既存の途中コメント取得処理を直接呼ばず、Conversationへ規定位置で追加する `InstructionInjector` を共通サービスとして利用する。
|
||
|
||
### 7.3 承認対象の固定
|
||
|
||
```ts
|
||
approvalFingerprint = SHA-256(
|
||
canonicalJson({
|
||
taskId,
|
||
piece,
|
||
movement,
|
||
toolName,
|
||
normalizedArguments,
|
||
policyRuleId,
|
||
policyRuleVersion,
|
||
})
|
||
);
|
||
```
|
||
|
||
承認後は同じfingerprintの操作だけを許可する。`once` と再利用可能scopeは別のrecord型として扱う。
|
||
|
||
- `once`: `approvalRequestId` とランダムnonceを持ち、`approved` から `consumed` へのCASをtool実行直前に1回だけ成功させる。同じfingerprintでも別のcallへ再利用しない。
|
||
- `task_argument`: task内で同じfingerprintへ再利用できる。初期実装には含めない。
|
||
|
||
`once` は実行の試行を承認するscopeとし、toolが失敗しても消費済みへ戻さない。再試行には新しい承認を要求する。再開後に再生成されたcallは、request ID、nonce、fingerprintがすべて一致する場合だけ消費できる。
|
||
request IDとnonceはモデルのtool引数へ追加しない。parked jobのPolicy resume contextへ固定し、task、Piece、Movement、rule、fingerprintが一致する唯一の未消費approved recordをサーバー側で選ぶ。候補が0件または複数件ならCASを行わず再承認とする。
|
||
|
||
|
||
`jobId` は監査相関には保存するが、操作fingerprintには含めない。Continueや再開でJobが変わっても同じ操作を識別できるが、承認を再利用できるのは明示的な再利用scopeだけである。`once` はrequest IDとnonceのCASを別途要求する。
|
||
|
||
現在のようにMovement全体を再実行すると異なる引数が生成される可能性がある。安全性が高いのは承認済みtool callの保存・直接実行だが、変更範囲が大きい。初期実装では再生成されたtool callのfingerprint照合が現実的である。
|
||
|
||
fingerprint不一致では元の承認を流用しない。同じMovementでの承認要求回数に上限を設け、上限到達後は決定的に拒否して理由を返す。再生成、Job再開、auto-parkをまたいで上限がリセットされないよう、発火回数、承認要求回数、拒否済みfingerprint、直近状態fingerprintをDBへ保存する。メモリ上の `PolicyState` は同一実行内のキャッシュに限定する。
|
||
|
||
### 7.4 Complete受理前ゲート
|
||
|
||
現行の終端処理では、native winner選択、control tool result記録、pending子タスクのauto-park、Movement result生成が連続する。Hook追加時はpending確認を分岐前へ移すが、auto-park経路でも既存control tool result記録を必ず維持する。初期実装の `completion.before_accept` は、本当に終端可能なCompleteだけへ適用する。
|
||
|
||
```text
|
||
native winner選択
|
||
→ pending子タスク等を確認
|
||
├─ pendingあり: 既存control tool resultsを記録
|
||
│ → 既存WAIT_SUBTASKSへauto-parkし、Hookは発火しない
|
||
└─ pendingなし: completion.before_accept
|
||
├─ allow: 既存control tool resultsを記録してMovement result生成
|
||
└─ deny / redirect: 全control callへ `Error:` tool resultを記録
|
||
→ 統合済み指示を追記
|
||
→ 次のLLM iterationで再推論
|
||
```
|
||
|
||
Complete発火回数はtask+Movement+rule単位でDBへ保存し、resume後も原則1回の上限を維持する。初期実装は決定的確認だけとし、Judgeによる完了可否判定は行わない。
|
||
|
||
---
|
||
|
||
## 8. 既存ユーザー承認機構との統合
|
||
|
||
承認機構本体はHookへ移行せず、`ApprovalService` として独立させ、既存 `RequestTool` とHookの両方から利用する。
|
||
|
||
```text
|
||
RequestTool ───┐
|
||
├─ ApprovalService
|
||
PolicyGate ────┘
|
||
```
|
||
|
||
```ts
|
||
type ApprovalScope =
|
||
| { kind: "once"; approvalRequestId: string; nonce: string; fingerprint: string; consumedAt?: string }
|
||
| { kind: "task_tool"; taskId: string; toolName: string }
|
||
| { kind: "task_argument"; taskId: string; fingerprint: string }
|
||
| { kind: "movement"; taskId: string; movement: string; toolName: string }
|
||
| { kind: "persistent_tool"; spaceId: string; toolName: string };
|
||
```
|
||
|
||
初期実装は以下だけでよい。
|
||
|
||
- Policy承認は今回だけ
|
||
- このタスク中、このツール
|
||
- 拒否
|
||
|
||
PolicyGateからの引数単位承認では、既存の `addGrantedTool(taskId, toolName)` に相当するtask+tool名の権限追加を行わない。Policy承認は専用approval recordへ保存し、fingerprint一致時だけPolicyGateがallowする。既存 `RequestTool` の「このタスク中、このツール」承認は互換経路として維持し、Policy承認とは混在させない。
|
||
|
||
評価は二段階に分ける。
|
||
|
||
```text
|
||
管理者拒否 / workspace tool policy / 既存基本許可
|
||
→ 通過したcallだけPolicyGate
|
||
→ 拒否済みfingerprint / one-shot承認 / rule actionを評価
|
||
→ allow時も各tool内のsandbox / SSRF / path検証を必ず実行
|
||
```
|
||
|
||
Policy承認は、workspace tool policyと基本許可を通過済みのcallに対する追加ゲートだけを解除する。未許可toolをPolicy承認によって許可せず、後段のsandbox、SSRF、path検証を迂回しない。
|
||
|
||
同一fingerprintの拒否後は再申請しない。引数が変われば別fingerprintとし、タスク単位の承認要求上限を設ける。
|
||
|
||
競合するPolicy actionの優先順位は次に固定する。
|
||
|
||
```text
|
||
stop
|
||
> deny
|
||
> require_approval
|
||
> redirect
|
||
> audit_only / allow
|
||
```
|
||
|
||
このPolicy action優先順位はcall内のAuto Prompter rule競合だけに適用する。既存安全境界は前段で評価し、PolicyGateによって緩和しない。
|
||
|
||
### 8.1 Job単位のPolicy Snapshot
|
||
|
||
Jobのclaim・workspace準備時に次をsnapshotし、そのJobの間は変更しない。
|
||
|
||
- `available`、workspace `enabled`
|
||
- 有効ruleのID、version、条件、action、scope、発火上限
|
||
- 常時適用する登録済み指示
|
||
- Judge model、endpoint、timeout、判定schema version
|
||
|
||
初回claim時にsnapshotをJob ID単位のDB recordへ永続化し、再claim・waiting_humanからのresumeでは現在のworkspace設定を読み直さず、必ず既存snapshotを復元する。常時ルールと条件付きルールは同じsnapshotを参照し、Job途中の設定変更・無効化は次のJobから反映する。
|
||
|
||
Policy approvalへparkする際は、approvalRequestId、nonce、fingerprint、snapshot IDをJobのPolicy resume contextへCASで紐付ける。resume時はこのcontextと既存snapshotを同一transaction境界で取得し、one-shot消費後にcontextを消費済みへ更新する。Job終端時はsnapshot/contextを完了状態にし、監査保持期間に従って削除する。
|
||
|
||
監査イベントにはsnapshot ID/versionを記録する。tool callごとの設定DB取得は行わない。機能OFFのJobではsnapshot/contextを作成しない。
|
||
|
||
---
|
||
|
||
## 9. 監査ログ
|
||
|
||
既存 `EventLogger` を基盤として利用する。
|
||
|
||
推奨イベント:
|
||
|
||
```text
|
||
policy_evaluation
|
||
policy_rule_matched
|
||
policy_instruction_injected
|
||
policy_tool_denied
|
||
approval_requested
|
||
approval_decided
|
||
approval_fingerprint_mismatch
|
||
policy_task_stopped
|
||
policy_notification_queued
|
||
```
|
||
|
||
記録候補:
|
||
|
||
- user ID
|
||
- task/job/run ID
|
||
- Piece/Movement
|
||
- Hook point
|
||
- tool名・カテゴリ
|
||
- 安全な引数要約
|
||
- rule ID・rule version
|
||
- 三値結果
|
||
- Judge model ID/version
|
||
- confidence
|
||
- action
|
||
- approval request ID
|
||
- 承認・拒否
|
||
- 実際の実行有無
|
||
- tool resultの成功/失敗
|
||
- timestamp
|
||
- 通知queue ID
|
||
|
||
保存しないもの:
|
||
|
||
- 生の認証情報
|
||
- 完全な会話全文
|
||
- 生のAuthorization header
|
||
- 必要性のない完全なtool引数
|
||
- Webページ全文
|
||
- 「悪意ある利用者」等の人物評価ラベル
|
||
|
||
Auto Prompter側でfield allowlistとマスキングを行い、その後で既存 `EventLogger` のマスキングとサイズ制限を適用する。
|
||
|
||
```text
|
||
記録
|
||
→ UI内の警告
|
||
→ 追加承認
|
||
→ 管理者通知
|
||
→ 管理者ポリシーによる制限
|
||
```
|
||
|
||
意味判定1回だけで利用者を制限してはならない。
|
||
|
||
---
|
||
|
||
## 10. PieceとMovementへ適用できる範囲
|
||
|
||
### 薄いHookだけで可能
|
||
|
||
- Piece開始・終了の観測
|
||
- Movement開始・終了の観測
|
||
- Piece/Movement情報の監査付与
|
||
- Movement別ルール候補の切り替え
|
||
- Movement開始時の固定指示
|
||
- 現在Movementとtoolカテゴリの整合性判定
|
||
- 遷移後イベント
|
||
|
||
### 状態遷移変更が必要
|
||
|
||
- Movement完了を保留
|
||
- 遷移前に承認待ちへ駐車
|
||
- 特定条件まで遷移禁止
|
||
- Piece完了前の再検証
|
||
- Hook判断による別Movementへの移動
|
||
|
||
### 後回しにすべきもの
|
||
|
||
- Auto PrompterによるMovement遷移先変更
|
||
- HookによるMovementスキップ
|
||
- HookによるPiece差し替え
|
||
- 複数Hookの投票で遷移決定
|
||
- Piece完了とCompleteの二重validator
|
||
|
||
初期段階ではPiece/Movementは観測対象とscope情報に留める。
|
||
|
||
---
|
||
|
||
## 11. 既存機能の置き換え・統合候補
|
||
|
||
| 対象 | 現在 | 移行案 | 効果 | リスク | 推奨 |
|
||
|---|---|---|---|---|---|
|
||
| ツール許可判定 | `isAllowedRegularTool` | 既存判定後にPolicyGate | 引数単位制御 | 二重権限体系 | そのまま残す |
|
||
| 許可外ブロック | `tool-execution.ts` | `tool.denied`を発行 | 監査統一 | 制御移行で迂回リスク | 一部だけ共通化 |
|
||
| RequestTool | 専用tool | ApprovalService利用 | 承認ロジック共通化 | 既存挙動回帰 | 共通サービスを呼ぶ |
|
||
| ユーザー承認要求 | tool request専用 | ApprovalService | 引数単位承認可能 | schema/API変更 | 共通サービス化 |
|
||
| 承認結果 | APIでtool overlay追加 | scope別decision | 柔軟な承認 | 複雑化 | 一部共通化 |
|
||
| 途中プロンプト | interjection直書き | `InstructionInjector` | Auto Prompterと再利用 | message順序 | 共通サービス化 |
|
||
| Complete検証 | terminal-control | `completion.before_accept`追加 | 登録ルール確認 | 完了不能ループ | 既存を残し薄く追加 |
|
||
| Movement遷移検証 | rules照合 | 観測eventのみ | 監査 | 中核回帰 | 置き換えない |
|
||
| エラー処理 | 各層 | `runtime.error`発行 | 観測統一 | Hookで回復すると不透明 | 購読側へ一部追加 |
|
||
| ロギング | logger/EventLogger | policy event追加 | 診断向上 | 個人情報 | 購読側へ追加 |
|
||
| イベント通知 | callbacks/EventLogger | EventSink adapter | 統一 | 二重イベント | 一部共通化 |
|
||
| 再試行制御 | loop-safety等 | Auto Prompter発火上限だけ追加 | 無限ループ防止 | 汎用化は複雑 | 既存を残す |
|
||
| コスト制限 | runtime側 | 観測のみ | 可視化 | Hook遅延 | 置き換えない |
|
||
| タイムアウト | AbortController/client | 観測のみ | 診断 | 安全境界弱体化 | 置き換えない方が安全 |
|
||
| ツール回数制限 | tool loop tracker | rule上限と別管理 | 明確 | 二重カウンタ | 置き換えない |
|
||
| デバッグ観測 | EventLogger | policy event追加 | 追跡容易 | イベント量 | 購読側へ移行可能 |
|
||
| セキュリティチェック | 各tool/SSRF等 | PolicyGateは追加層 | 意味的判定追加 | Hookを信頼しすぎる | 既存を残す |
|
||
|
||
Hook導入の効果は既存処理の大量削減ではなく、追加ポリシーの安全な挿入位置と共通監査形式の提供である。
|
||
|
||
---
|
||
|
||
## 12. UIとUX
|
||
|
||
### 基本画面
|
||
|
||
1. ルール名
|
||
2. いつ確認するか
|
||
3. 対象
|
||
4. どのような場合か
|
||
5. そのとき何をするか
|
||
|
||
| 内部用語 | UI表示 |
|
||
|---|---|
|
||
| `tool.before` | ツールを実行する前 |
|
||
| `completion.before_accept` | 作業を完了する前 |
|
||
| `inject_instruction` | 確認事項を伝えて、もう一度考えさせる |
|
||
| `deny_current_tool` | 今回の操作を実行しない |
|
||
| `request_approval` | 実行前に確認を求める |
|
||
| `stop_task` | タスクを停止する |
|
||
| `audit_only` | 履歴へ記録する |
|
||
| `notify_admin` | 管理者へ知らせる |
|
||
|
||
### 一般ユーザー向け対象カテゴリ
|
||
|
||
- コマンド実行
|
||
- ファイルの変更
|
||
- データの削除
|
||
- インターネット検索
|
||
- 外部サービスへの送信
|
||
- Git操作・GitHub操作
|
||
- ブラウザ操作
|
||
- SSH・外部マシン操作
|
||
- すべてのツール
|
||
|
||
個別tool名指定、優先度、最大発火回数、クールダウン、Piece/Movement限定、confidence閾値、`unknown`時の扱い、管理者通知、rule version、shadow modeは詳細設定へ隠す。
|
||
|
||
利用者に見えない指示挿入を避け、適用時には次のような通知を出す。
|
||
|
||
```text
|
||
自動ルール「削除前の確認」が適用されました。
|
||
今回の操作は実行せず、復元方法を確認するようエージェントへ伝えました。
|
||
```
|
||
|
||
承認カードには、操作内容、対象、承認理由、承認scope、引数変更時は再承認になることを表示する。
|
||
|
||
---
|
||
|
||
## 13. 変更が必要なファイル、クラス、関数
|
||
|
||
### 初期実装で変更
|
||
|
||
- `src/engine/agent-loop/tool-execution.ts`
|
||
- `executeRegularToolCallCached()`
|
||
- tool実行前ゲート
|
||
- redirect/deny/approval結果のtool result化
|
||
- `src/engine/agent-loop/tool-dispatcher.ts`
|
||
- iteration全callのbatch preflight
|
||
- Policyで実行しないcallの合成結果とgrounding reservation解放
|
||
- `src/engine/agent-loop.ts`
|
||
- 定型指示のmessage追加
|
||
- PolicyStateの保持
|
||
- Complete前の軽量ゲート
|
||
- `src/engine/agent-loop/movement-setup.ts` / `src/engine/agent-loop/prompt.ts`
|
||
- Job snapshotの常時指示をstatic preambleへ安定順序で合成
|
||
- `src/engine/agent-loop/types.ts`
|
||
- PolicyService、state、callback型
|
||
- `src/engine/tools/core.ts`
|
||
- ToolContextへpolicy/approval context追加
|
||
- `src/engine/piece-runner.ts`
|
||
- task scopeのPolicyStateをMovement間で共有
|
||
- Piece/Movement情報をcontextへ設定
|
||
- `src/engine/agent-loop/pending-states.ts`
|
||
- Policy approval専用のwaiting result
|
||
- `src/worker.ts`
|
||
- Policy waitReasonの永続化と完了結果の処理
|
||
- `policy_stopped` をhard-terminal abort reasonへ追加しretryを禁止
|
||
- `src/db/repositories/jobs.ts`
|
||
- Policy resume contextとsnapshot IDのCAS紐付け・専用resume
|
||
- `src/db/repositories/approval-requests.ts`
|
||
- one-shot承認の `approved → consumed` CASと発火状態永続化
|
||
- `src/db/repositories/policy-run-snapshots.ts`
|
||
- 初回claim時のsnapshot作成、再claim時の復元、終端時の完了・保持期限処理
|
||
- `src/progress/event-log.ts`
|
||
- policy eventのpayload規約
|
||
- `src/engine/tools/tool-request.ts`
|
||
- ApprovalService呼び出しへ段階移行
|
||
- `src/bridge/local-tasks-tool-requests-api.ts`
|
||
- 汎用approval APIへ互換委譲
|
||
- `src/bridge/policy-approval-requests-api.ts`
|
||
- Policy専用approve/denyとresume API
|
||
- `ui/src/components/chat/ToolRequestApproval.tsx`
|
||
- 汎用承認カードへの段階移行
|
||
- `ui/src/components/chat/ChatComposer.tsx` / `ChatComposerPanel.tsx`
|
||
- Policy waitReasonの入力ロックと承認カード配置
|
||
- DB schema / migration / Repository facade
|
||
- policy rule、approval request、発火状態tableの作成と公開method追加
|
||
- Bridge route registration
|
||
- Policy rule・approval APIを既存routerへmount
|
||
- Workspace設定取得・更新API
|
||
- master enabledをJob claim snapshotへ同梱し、rule取得をON時だけ実行
|
||
- ワークスペースSettings親画面
|
||
- Auto Prompter設定route・navigation・権限表示を追加
|
||
- feature flag / config schema / normalization
|
||
- `available`、Phase availability、Judge設定のvalidationと既定値
|
||
|
||
### 新規候補
|
||
|
||
```text
|
||
src/engine/policy/
|
||
policy-gate.ts
|
||
policy-context.ts
|
||
policy-state.ts
|
||
auto-prompter.ts
|
||
deterministic-matcher.ts
|
||
semantic-rule-judge.ts
|
||
rule-conflict-resolver.ts
|
||
instruction-injector.ts
|
||
approval-service.ts
|
||
approval-fingerprint.ts
|
||
policy-audit.ts
|
||
|
||
src/db/repositories/
|
||
policy-rules.ts
|
||
approval-requests.ts
|
||
|
||
src/bridge/
|
||
policy-rules-api.ts
|
||
policy-approval-requests-api.ts
|
||
|
||
ui/src/components/settings/
|
||
AutoPrompterRulesForm.tsx
|
||
|
||
ui/src/components/chat/
|
||
PolicyApprovalCard.tsx
|
||
PolicyActionNotice.tsx
|
||
```
|
||
|
||
実装時にはアプリ内ヘルプと更新履歴も同じPRで更新する必要がある。
|
||
|
||
---
|
||
|
||
## 14. 初期実装の最小範囲
|
||
|
||
ここでいう初期実装は、Phase 0~4を順に通過した最初のGA範囲を指す。各Phaseは個別に検証・feature flag配信し、前Phaseの受入条件を満たすまで次の制御機能を有効化しない。
|
||
|
||
### 含める
|
||
|
||
- `tool.before` 制御点
|
||
- `tool.after` 観測イベント
|
||
- `tool.denied` 観測イベント
|
||
- `completion.before_accept` の決定的確認
|
||
- ルールCRUD
|
||
- toolカテゴリ・Piece・Movement・回数による決定的絞り込み
|
||
- 小型LLMによる三値・rule ID判定のshadow評価
|
||
- 登録済み定型指示の追加
|
||
- 今回のtool call拒否
|
||
- 既存承認フローへの接続
|
||
- ruleごとの最大発火回数
|
||
- 同一fingerprintの重複防止
|
||
- 基本監査イベント
|
||
- shadow mode
|
||
|
||
### 除外
|
||
|
||
- 自由記述の自然言語条件による拒否、停止、承認の本番制御
|
||
- Judge結果だけに依存する安全上の許可・拒否
|
||
- delegate子エージェント内からの独立したユーザー承認待ち
|
||
- Piece/Movement遷移の制御
|
||
- LLM呼び出し前後の汎用middleware
|
||
- 生成stream途中の判定
|
||
- 管理者自動通知
|
||
- 不正利用者の自動制限
|
||
- 複雑なrule依存関係
|
||
- plugin marketplace
|
||
- Judgeによる採点
|
||
- 全既存機能のHook化
|
||
- 恒久承認
|
||
- 承認済みtool callの直接再実行
|
||
|
||
---
|
||
|
||
## 15. 将来拡張
|
||
|
||
- Movement開始時の固定指示
|
||
- LLM応答後の言語・読みやすさ確認
|
||
- 引数単位の承認
|
||
- 管理者通知queue
|
||
- task/space/organization scopeのルール
|
||
- rule versioningと公開テンプレート
|
||
- offline replay評価
|
||
- 複数Judgeの比較
|
||
- 管理者ポリシーと個人ルールの階層化
|
||
- 観測subscriber plugin
|
||
- Complete reviewer
|
||
- Piece開始・終了監査
|
||
- ルール推奨機能。ただし自動有効化はしない
|
||
|
||
---
|
||
|
||
## 16. アーキテクチャ案の比較
|
||
|
||
| 観点 | 案1 直接Hook | 案2 Event Bus | 案3 Middleware | 案4 承認中心 | 案5 ハイブリッド |
|
||
|---|---|---|---|---|---|
|
||
| 現行コードとの相性 | 良 | 観測のみ良 | 部分的 | ツールだけ良 | 最良 |
|
||
| 変更範囲 | 小 | 中 | 大 | 小~中 | 中 |
|
||
| 実装難易度 | 低 | 中 | 高 | 中 | 中 |
|
||
| オーバーヘッド | 小 | 小 | 中 | 小 | 小~中 |
|
||
| 順序制御 | 呼び出し順 | 不透明になりやすい | 明示可能 | 限定的 | 明示可能 |
|
||
| 非同期観測 | 弱い | 強い | 中 | 弱い | 強い |
|
||
| 制御 | 強い | 不向き | 強い | ツール承認のみ | 強い |
|
||
| デバッグ | 容易 | 因果追跡が必要 | chain追跡が必要 | 容易 | 相関IDで可能 |
|
||
| エラー隔離 | 個別 | 良 | 設計依存 | 良 | 良 |
|
||
| テスト | 容易 | 中 | 高コスト | 容易 | 中 |
|
||
| 承認統合 | 中 | 不向き | 良 | 最良 | 最良 |
|
||
| Piece/Movement | 追加しやすい | 観測向き | 包装可能 | 弱い | 段階導入可能 |
|
||
| plugin化 | 弱い | 強い | 強い | 弱い | 将来可能 |
|
||
| 既存置換 | 少ない | 観測を統合 | 多い | 承認のみ | 必要部分だけ |
|
||
| 過剰抽象化 | 低 | 中 | 高 | 低 | 中 |
|
||
|
||
案5を採用し、制御点は明示的な直接呼び出し、制御ロジックは `PolicyGate`、承認は `ApprovalService`、観測は `EventLogger` adapter、Auto PrompterはPolicyGateの一 evaluatorとする。
|
||
|
||
---
|
||
|
||
## 17. セキュリティとプライバシー
|
||
|
||
主なリスク:
|
||
|
||
- 自然言語条件にprompt injectionが含まれる
|
||
- tool引数やWeb本文がJudgeを操作する
|
||
- ルールの定型指示がMovement指示と矛盾する
|
||
- Auto Prompterが権限判定を上書きする
|
||
- Judge失敗で危険操作がfail-openになる
|
||
- 管理者が会話全文を監査できる
|
||
- tool引数にcredentialが含まれる
|
||
- 通知先へ機密情報が流れる
|
||
- 誤検知が利用者評価に利用される
|
||
|
||
対策:
|
||
|
||
- ルール条件、tool引数、会話を明確にdataとして区切る
|
||
- Judgeに自由文やactionを生成させない
|
||
- 登録済みrule ID以外を拒否
|
||
- tool引数はfield allowlistとマスキング
|
||
- 重大操作はLLM判定ではなく決定的ルール
|
||
- 既存SSRF・sandbox・tool policyを残す
|
||
- 個人評価ではなく「この操作の判定」として記録
|
||
- 監査閲覧権限をtask/space scopeへ制限
|
||
- 保持期間を設定可能にする
|
||
- 通知は安全な要約のみ
|
||
- 管理者拒否を最優先
|
||
- Judge timeout時の扱いをaction種別ごとに固定
|
||
|
||
---
|
||
|
||
## 18. パフォーマンス
|
||
|
||
各tool実行前に小型LLMを必ず呼ぶ構成は避ける。
|
||
|
||
```text
|
||
ruleなし → 0コスト
|
||
対象Hookなし → 0コスト
|
||
カテゴリ不一致 → 0コスト
|
||
決定的条件で確定 → LLMなし
|
||
意味判定候補あり → 一括Judge
|
||
```
|
||
|
||
対策:
|
||
|
||
- rule候補上限
|
||
- rule definitionのtoken budget
|
||
- Judge専用worker/role
|
||
- 同一fingerprint cache
|
||
- 並列tool callは一括判定
|
||
- 観測イベントを同期通知しない
|
||
- 通知queue
|
||
- Judge timeoutを短くする
|
||
- モデルversionを固定し、変更時はshadow評価
|
||
|
||
目標値例:
|
||
|
||
- 決定的判定: 5ms未満
|
||
- Judge判定P95: 1秒未満
|
||
- 通常toolの追加遅延: 50ms未満
|
||
- Judge対象率: 全tool callの10%未満
|
||
|
||
---
|
||
|
||
## 19. テスト計画
|
||
|
||
### Unit
|
||
|
||
- rule scope filter
|
||
- 三値schema検証
|
||
- 未登録rule ID拒否
|
||
- fingerprint canonicalization
|
||
- 発火回数
|
||
- cooldown
|
||
- 同一状態dedupe
|
||
- conflict resolver
|
||
- secret masking
|
||
- GateDecisionごとの処理
|
||
- Hook失敗時のfail policy
|
||
|
||
### ツール実行前
|
||
|
||
- allowなら1回だけ実行
|
||
- redirect/deny/approvalなら実行されない
|
||
- 元tool callへtool resultが返る
|
||
- 追加指示後に元callが自動実行されない
|
||
- 並列batchの一部だけ拒否
|
||
- redirect/approval/stopを含むbatchは兄弟callを部分実行しない
|
||
- regularとco-emitされたComplete/transitionへ全件tool resultを返す
|
||
- stopは `policy_stopped` のhard-terminal ABORTとなり、retry 0回でpending子タスクを既存経路で取り消す
|
||
- 不正JSONは既存tool validationと同じエラーになる
|
||
- cache hit前にもpolicyが適用される
|
||
- 承認後のfingerprint不一致を拒否
|
||
|
||
### 承認
|
||
|
||
- 一回承認
|
||
- one-shotのCAS消費は並行実行でも1回だけ成功
|
||
- 消費済みone-shotは同じfingerprintでも再利用不可
|
||
- tool失敗後の再試行には新しい承認が必要
|
||
- タスク中承認
|
||
- 拒否
|
||
- 二重決定
|
||
- concurrent approval
|
||
- 他ユーザーによる決定拒否
|
||
- 管理者拒否優先
|
||
- 拒否後の再申請抑止
|
||
- 再開後のMovement整合
|
||
- 承認待ち中にruleを編集・無効化しても、再開Jobは永続化済み旧snapshotを使用
|
||
- resume context候補が0件・複数件ならone-shotを消費せず再承認
|
||
|
||
### Auto Prompter
|
||
|
||
- 日本語条件
|
||
- 曖昧条件
|
||
- `unknown`
|
||
- tool引数・Web本文内のprompt injection
|
||
- 存在しないrule ID
|
||
- Judge timeout
|
||
- 不正JSON
|
||
- モデル変更差分
|
||
|
||
### Piece/Movement回帰
|
||
|
||
- Hook無効時の既存挙動一致
|
||
- transition
|
||
- Complete
|
||
- ASK
|
||
- subtask/browser/tool approval wait
|
||
- loop guard
|
||
- conversation replay
|
||
- KV prefix安定性
|
||
|
||
### プライバシー
|
||
|
||
- API key
|
||
- Bearer token
|
||
- password
|
||
- URL query secret
|
||
- shell環境変数
|
||
- PIIを含む会話
|
||
- audit APIの権限
|
||
|
||
---
|
||
|
||
## 20. 段階的な実装ロードマップ
|
||
|
||
### Phase 0: Shadow観測
|
||
|
||
- `tool.before` contextを構築
|
||
- 既存動作は変えない
|
||
- 決定的matcherとJudge結果を監査
|
||
- Job snapshot、batch preflight、OFF短絡の互換性を検証
|
||
- 誤検知・遅延を測定
|
||
|
||
### Phase 1: Audit + 常時ルール
|
||
|
||
- rule CRUD
|
||
- EventLogger統合
|
||
- 発火制御
|
||
- UIへ「記録のみ」ルール
|
||
- 常時適用ルールをstatic preambleへ一度だけ合成
|
||
- 一般ユーザー向けテンプレートとON/OFF設定
|
||
- 管理者通知なし
|
||
|
||
### Phase 2: 追加指示・拒否
|
||
|
||
- `redirect`
|
||
- 決定的条件だけを制御actionへ使用
|
||
- 追加権限を持つユーザーが作成した決定的ルールに限り `stop_task`
|
||
- `deny`
|
||
- 元tool callを消費
|
||
- 無限ループ防止
|
||
- rule actionの透明表示
|
||
|
||
### Phase 3: 既存承認統合
|
||
|
||
- ApprovalService抽出
|
||
- 一回承認
|
||
- fingerprint
|
||
- 既存RequestTool互換adapter
|
||
- 汎用承認カード
|
||
|
||
### Phase 4: Complete前の軽量確認
|
||
|
||
- 決定的条件中心
|
||
- 発火はMovement当たり原則1回
|
||
- 上限超過時は停止または通常Complete
|
||
|
||
### Phase 5: 評価後の拡張判断
|
||
|
||
- Movement開始Hook
|
||
- 引数単位承認
|
||
- 管理者通知
|
||
- Complete Reviewer
|
||
- 自然言語Judgeの品質基準を満たした場合だけ制御actionへ段階適用
|
||
- 一般ユーザーの自由記述条件はこの評価後に公開判断
|
||
- 公開テンプレート
|
||
|
||
---
|
||
|
||
## 21. 敵対的レビュー
|
||
|
||
### 21.1 Auto Prompterは本当に必要か
|
||
|
||
多くのユースケースは以下で代替できる。
|
||
|
||
- Movementプロンプトの改善
|
||
- toolカテゴリごとの固定ポリシー
|
||
- Bash等への決定的検査
|
||
- 既存承認の引数単位拡張
|
||
- Complete前Reviewer
|
||
- 管理者定義テンプレート
|
||
|
||
Auto Prompterを導入すると、同じ入力でも登録rule、Judge model、model version、発火履歴によって挙動が変わる。Pieceだけを見ても実行理由を説明できなくなり、再現性と予測可能性が低下する。
|
||
|
||
### 21.2 自然言語条件は不安定
|
||
|
||
- 「危険」「難しい」「大きく外れた」等の基準が曖昧
|
||
- 条件文に例外が書かれない
|
||
- 条件同士が重複する
|
||
- Judge model変更で結果が変わる
|
||
- 日本語の否定・二重否定を誤る
|
||
- tool引数中の文字列と実際の操作を区別できない
|
||
- prompt injectionの新しい攻撃面になる
|
||
|
||
一般ユーザーに自然言語ruleを自由入力させると、サポート不能な挙動が増える可能性がある。
|
||
|
||
### 21.3 Hook基盤はコードを簡潔にしない
|
||
|
||
既存処理はすでに、権限、tool dispatch、RequestTool、wait state、Piece mapping、Complete validation、EventLogger、retry/watchdogという意味のある専用境界を持つ。
|
||
|
||
これらをHookへ移してもコード総量は減らず、処理の追跡先が増える。汎用middleware chainへ移すと、Hookの順番とstate変更を理解しなければ本体を追えなくなる。
|
||
|
||
### 21.4 承認疲れ
|
||
|
||
誤検知が多いと、利用者は承認内容を読まず機械的に許可するようになる。安全性向上のための承認が形骸化する可能性がある。
|
||
|
||
### 21.5 監査ログが新しいリスクになる
|
||
|
||
判定精度改善のため会話や引数を多く記録すると、監査基盤自体が機密情報の集積点になる。既存の正規表現マスキングだけでは任意のcredential、URL query、ファイル本文、個人情報、独自token形式を完全には防げない。
|
||
|
||
「不正利用の可能性」というラベルは、誤検知時に利用者へ不利益を与える危険がある。
|
||
|
||
### 21.6 Piece/Movementへの介入は危険
|
||
|
||
Movementには既に目的、tool集合、遷移rules、再訪問制限、Complete、ASK、wait/resumeがある。別の条件遷移系を追加すると、完了不能、同じMovementへの反復、追加指示と元promptの矛盾が起こり得る。
|
||
|
||
### 21.7 パフォーマンス
|
||
|
||
tool利用の多いタスクでは、Judge呼び出しがLLM本体より多くなる可能性がある。小型モデルでもGPU queueを消費し、通常ジョブと競合する。
|
||
|
||
### 21.8 より単純な代替案
|
||
|
||
1. 既存toolカテゴリへ危険度metadataを追加
|
||
2. Bash・削除・外部送信を決定的に検査
|
||
3. 既存承認を一回限り・引数fingerprint対応へ拡張
|
||
4. Complete前に固定Reviewerを1回実行
|
||
5. EventLoggerへ承認・拒否イベントを追加
|
||
6. Movement別の管理者定型指示だけ許可
|
||
7. 自然言語条件はshadow modeに限定
|
||
|
||
この代替案の方が再現性、説明可能性、性能、保守性で優れる可能性がある。
|
||
|
||
### 21.9 中止・縮小基準
|
||
|
||
以下のいずれかがPoCで確認された場合、自然言語Auto Prompterは中止する。
|
||
|
||
- 対象ruleのprecisionが90%未満
|
||
- 危険操作のrecallが決定的ルールを上回らない
|
||
- Judge P95が1秒を超える
|
||
- 全tool callの20%以上でJudgeが必要
|
||
- `unknown` が10%以上
|
||
- 承認要求の拒否・無視率が高い
|
||
- model変更で発火率が大きく変化
|
||
- 自然言語ruleの問い合わせが運用負担になる
|
||
- 監査に必要な情報量がプライバシー要件を超える
|
||
- Hook無効時でも既存挙動と一致しない
|
||
|
||
この場合は「固定ルール+既存承認拡張+監査ログ」に縮小する。
|
||
|
||
---
|
||
|
||
## 22. 最終判断
|
||
|
||
### 採用
|
||
|
||
- **ツール実行前Hookだけ実装**
|
||
- **既存承認機構を中心に拡張**
|
||
- **観測Hookと監査ログは既存EventLogger上に実装**
|
||
- **Auto Prompterはワークスペース設定として一般ユーザーへ提供**
|
||
- **自然言語Judgeは最初はshadow modeとし、決定的ルールと常時ルールを先行公開**
|
||
- **決定的条件を優先し、意味判定は限定的に使用**
|
||
|
||
### 不採用・延期
|
||
|
||
- 全面Hook化
|
||
- 権限・sandbox・timeout・retryのHookへの移行
|
||
- Piece/Movement遷移制御
|
||
- 生成stream途中の判定
|
||
- 品質基準を満たす前の、一般ユーザーへの自由な自然言語rule制御action公開
|
||
- Auto Prompterによる自動利用者制限
|
||
- 汎用plugin基盤
|
||
- 既存承認機構のHook内部への全面移行
|
||
|
||
Hook導入によって既存コードが大幅に簡潔になる見込みはない。価値があるのは、**ツール副作用直前に追加ポリシーを安全に適用できる明示的な境界と、既存EventLoggerへ統一された監査情報を残せること**である。
|
||
|
||
Auto Prompter自体は、そのHook基盤上の任意機能として扱い、Hook基盤の中心概念にしない設計が妥当である。
|