mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-10-26 10:45:22 +00:00
feat(pi-permission-system): AutoReview 改为跟随主模型的对话式工具调用审查
AutoReview: - 审查器回到 Codex Guardian 风格的对话式审查,默认跟随会话当前主模型 (每次审查实时读取 ctx.model);provider/model 必须同时设置才固定审查 模型,只设其一视为配置错误并转人工。 - 结论只通过 approve / reject 两个工具给出,参数仅 reason;不强制 toolChoice,正文文本(即使是合法 JSON)一律忽略。 - approve 自动放行;reject 转人工并在弹窗显示理由(标注模型生成)。 超时、Provider 错误、截断、未调用工具、多次调用、参数无效等异常同样 转人工,并附固定的系统说明;用户按 Esc 中止时直接拒绝。 - 模型调用改为 modelRegistry.streamSimple(...).result():Pi 1.3.0 面向 扩展的 ModelRegistry 没有 completeSimple,原写法在真实环境中每次都会 转人工。 - 对话记录保留可信度标注;工具结果在有更短的 pi-compaction 摘要时替换 为摘要;token 估算改为非 ASCII 字符按 1 token 计;预算可配置。 - 同一条用户消息内完全相同的请求只缓存 approve 结论。 - 默认 reasoning low、总超时 30 秒、最多 2 次尝试、maxOutputTokens 4000。 删除: - 未发布过的 TypeSafe Jev 分类器实现、DenialCircuitBreaker。 - 整个 annotator 机制(model-explanation、注册表、registerAnnotator、 provider-timeout);annotators 配置键保留为已弃用并忽略,避免旧配置 被拒绝。 测试: - 新增 reviewer / transcript / 弹窗说明 / 默认配置测试;清理重复、恒真 或只测实现细节的旧测试。 - 使用 deepseek-v4.1-flash 实测 5 个场景各 5 次,25 次结论全部符合预期。 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent
dec48dab6d
commit
7e6a8faae1
@@ -66,37 +66,64 @@ There is no separate `external_directory` decision. A path outside the current w
|
||||
> **Note:** Trailing commas are not supported. If parsing fails, ordinary policy fails safely to `ask`.
|
||||
## Built-in AutoReview
|
||||
|
||||
`autoReview.enabled` controls the built-in authorizer named `auto-review`. It only receives requests that ordinary policy resolved to `ask`; it cannot bypass a hard deny. Add `"auto-review"` to `authorizerChain` to make it the primary case-by-case authority. An `allow` or `deny` verdict is final for that request. `defer` continues to the next authorizer and ultimately the human permission dialog.
|
||||
`autoReview.enabled` controls the built-in authorizer named `auto-review`. It only receives requests that ordinary policy resolved to `ask`; it cannot bypass a hard deny. Add `"auto-review"` to `authorizerChain` to make it the primary case-by-case authority. An `allow` verdict is final for that request, and so is a `deny`. `defer` continues to the next authorizer and ultimately the human permission dialog.
|
||||
|
||||
The reviewer uses only trusted direct-user transcript evidence and recognized structured answers. Assistant, tool, compaction, and cancelled-answer content cannot authorize an operation. Model lookup, authentication, timeout, malformed output, or internal errors all return `defer`.
|
||||
### The reviewer is a conversational model, deciding through tool calls
|
||||
|
||||
The review model comes entirely from configuration. There is no default provider/model pair and no synthesized stand-in, so automatic review stays inactive until both `autoReview.provider` and `autoReview.model` name a model your Pi registry actually publishes:
|
||||
AutoReview makes one independent model call per ask: a fixed review system prompt, a single user message containing the rendered transcript and a bounded JSON description of the planned action, and exactly two tools — `approve` and `reject`. The verdict is whichever of those tools the model calls, and the call must carry a non-empty `reason`. Everything else is a failure, not a verdict:
|
||||
|
||||
- a reply with **no tool call at all** — even one whose text happens to be valid JSON — counts as *no verdict*, because the verdict protocol is the tool call, not prose
|
||||
- **two or more tool calls**, an unknown tool name, or a missing `reason` count as an *invalid response*
|
||||
- a truncated response (`length` stop reason) counts as *truncated*
|
||||
|
||||
None of those is retried: the same request produced them. Provider errors are retried while attempts and the timeout budget remain.
|
||||
|
||||
### A rejection defers — it never denies
|
||||
|
||||
`approve` maps to `allow`. `reject` maps to `defer`, and the model's `reason` is shown in the human permission prompt, labelled as model-generated. Every failure — timeout, provider error, malformed reply, missing model — also maps to `defer` with a fixed system-authored note. A model refusal or a broken review therefore always costs a human glance, never a silent denial. Pressing Esc during a review aborts it and denies the operation outright, so no human dialog pops up after the user already said no.
|
||||
|
||||
An `allow` is cached for the rest of the current user message: the same action asked again under the same trusted conversation point skips the model call. A new user message invalidates the cache, and rejects are never cached.
|
||||
|
||||
### Context budgets
|
||||
|
||||
The reviewer sees a bounded rendering of the session transcript: trusted user turns and structured user-interaction answers are kept preferentially, and the most recent untrusted entries fill the remaining budget under `maxUntrustedEntries`. Token counts are estimated conservatively — ASCII counts a quarter token per character, every non-ASCII codepoint a full token — because the `length / 4` heuristic under-counts CJK by roughly 2–4x. When the companion `pi-compaction` extension is loaded, already-summarized tool results are substituted with their summaries when strictly shorter, so the budget buys more context.
|
||||
|
||||
| Key | Default | Ceiling for |
|
||||
| --- | --- | --- |
|
||||
| `autoReview.transcript.messageTokens` | `10000` | message-kind transcript entries |
|
||||
| `autoReview.transcript.toolTokens` | `10000` | tool-result transcript entries |
|
||||
| `autoReview.transcript.maxUntrustedEntries` | `40` | untrusted entries retained |
|
||||
|
||||
Any single entry is additionally capped at a fixed 2000 estimated tokens for messages and 1000 for tool results, regardless of the budgets above.
|
||||
|
||||
### Configuration
|
||||
|
||||
By default AutoReview follows the session's **current** model — the same model the operator is chatting with — so a mid-session model switch applies to the very next ask. Set `autoReview.provider` and `autoReview.model` **together** to pin a fixed reviewer; set neither to follow the session. Setting exactly one is a misconfiguration: the reviewer warns once at `session_start` and defers every ask.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"authorizerChain": ["auto-review"],
|
||||
"autoReview": {
|
||||
"enabled": true,
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-flash",
|
||||
"reasoning": "off"
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Key | Default | Description |
|
||||
| ---------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `autoReview.enabled` | `true` | Registers the `auto-review` authorizer. It decides nothing until named in `authorizerChain`. |
|
||||
| `autoReview.provider` | — | Pi provider id of the review model. No default; when absent the reviewer defers every ask. |
|
||||
| `autoReview.model` | — | Model id within that provider. No default; when absent the reviewer defers every ask. |
|
||||
| `autoReview.reasoning` | — | Thinking level for a reasoning-capable review model. No default; omit to send no reasoning option. |
|
||||
| `autoReview.timeoutMs` | `90000` | Total retry budget for one review call. |
|
||||
| `autoReview.includeBaselinePolicy` | `true` | Include the built-in Codex Guardian–style policy text. |
|
||||
| `autoReview.additionalPolicy` | — | Operator policy appended to the baseline. Required when `includeBaselinePolicy` is `false`. |
|
||||
| Key | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `autoReview.enabled` | `true` | Registers the `auto-review` authorizer. It decides nothing until named in `authorizerChain`. |
|
||||
| `autoReview.provider` | — | Provider id of a pinned review model. Must be set together with `autoReview.model`; leave both unset to follow the session's current model. |
|
||||
| `autoReview.model` | — | Model id of a pinned review model. Must be set together with `autoReview.provider`. |
|
||||
| `autoReview.reasoning` | `"low"` | Reasoning level for reasoning-capable review models. `off` disables it; non-reasoning models always receive no reasoning option. |
|
||||
| `autoReview.timeoutMs` | `30000` | Total budget for one review call, across all attempts (max 300000). |
|
||||
| `autoReview.maxAttempts` | `2` | Attempts including the first (1–5). A malformed or truncated response is not retried: the same request produced it. |
|
||||
| `autoReview.maxOutputTokens` | `4000` | Output budget for a single review call (256–32000). |
|
||||
| `autoReview.transcript.*` | see above | Transcript rendering budgets. |
|
||||
| `annotators` | — | **Deprecated and ignored.** The annotator mechanism was removed. Still accepted so a deployed config keeps loading; remove it. |
|
||||
|
||||
When either `provider` or `model` is missing and `auto-review` is named in `authorizerChain`, the extension notifies once at `session_start` that automatic review cannot run and every ask will reach the human prompt. An unknown provider or an unpublished model id also defers, with the reason recorded in the permission review log.
|
||||
When `auto-review` is named in `authorizerChain` and a pinned `provider`/`model` pair cannot be resolved, the extension notifies once at `session_start` that automatic review cannot run. Follow-the-session-model mode warns about nothing: absence of a session model is the session's business.
|
||||
|
||||
Each `allow` / `deny` is written to the permission review log; the extension keeps no aggregate history, runs no background analysis agent, and never edits either policy file.
|
||||
Each review outcome is written to the permission review log — the resolved model, the outcome, the model's reason or the failure category, attempts, usage, and transcript statistics. The extension keeps no aggregate history, runs no background analysis agent, and never edits either policy file.
|
||||
|
||||
## Runtime Knobs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user