Repository navigation
Conversation
|
Thanks for this, and for listing the open questions. Before going into the code, we want to talk about the direction, because it has changed on our side since we wrote #146. #146 asks for a "safety net" preset in bypass mode and a "fewer prompts" preset in the default and accept-edits modes. You built what it says. We have since changed our minds, so this is about where we want to go now, not a mistake on your part. Where we want to go
What we would like your view on We have some ideas for the settings, but you know this code better now, so we would rather hear how you would do it.
|
Update: model-assisted Auto permission mode (
|
|
Thanks for the update and for taking the direction on board. The branch now conflicts with
Could you merge We'll review once CI is green. |
|
Implemented the requested #146 update and resolved the
GitHub now reports the PR as |
|
CI annotation follow-up: the single Server tests error belonged to the superseded 58e8f6a run, where the PowerShell deny test exceeded the CI timeout. Commit 42c782e fixed that test and the latest run remains green. Commit e60011a also upgrades actions/checkout and actions/cache from v4 to v5, removing the three Node.js 20 deprecation warnings. Latest run 43140782736: Server tests 2656 passed, 2 skipped, 0 failed; Desktop tests, Desktop typecheck, and GitGuardian also passed. The only remaining annotations are three GitHub notices about the future ubuntu-latest migration; there are now 0 errors and 0 warnings. |
GoDiao
left a comment
There was a problem hiding this comment.
Thanks for rebuilding this around Auto mode and for resolving the conflicts. The overall shape is what we asked for: Auto is its own mode, deny rules run before the model, every failure falls back to asking, the other four modes never call the model, and #235's secret reads stay with the user. Lint and the touched tests pass on our side too (235 server/CLI tests in random order, 311 desktop tests), and business-flow fails the same 14 tests under --randomize on main, so that is not from this PR.
We reviewed it along the seven dimensions in AGENTS.md. Below are the changes we need, sorted by tier.
Must fix
1. An explicit ask rule can be approved by the model.
In hasPermissionsToUseTool (src/utils/permissions/permissions.ts, the mode === 'auto' branch), only a safetyCheck with classifierApprovable: false and tools with requiresUserInteraction skip the model. A user's own ask rule (step 1b for a whole tool, step 1f for content rules such as Bash(git push:*)) returns ask with decisionReason.type === 'rule' and goes to the model like any other ask. With Bash(git push:*) set to ask and Auto selected, a decision of allow runs git push origin main without a prompt, while bypass mode still asks for it. The settings text (settings.permissions.rulesDescription) also says these rules take precedence over the guardrail.
Please return early for ask rules as well, and add a test that fails without it.
2. The CLI reads providers.json and the decision provider's key itself.
readDecisionProvider in permissionGuardrail.ts reads providers.json from disk on every decision, imports normalizeProvidersIndex from src/server/, and requestAskProbability sends the key from the CLI process. On main the CLI never reads providers.json: the sidecar resolves the active provider and passes its settings to the CLI as environment variables when it starts the CLI (buildProviderManagedEnv in providerRuntimeEnv.ts). Here the file format is now read in two places, and a read error is swallowed, so Auto quietly falls back to asking with only "Decision provider or model is unavailable".
Please follow the main pattern: when Auto uses a decision provider, have the sidecar put the provider's endpoint, API format, model and key into the CLI environment alongside the variables it already sets, and have the CLI read only those. Then the import from src/server/ and the file read go away. A change to the Auto settings can take effect when the CLI restarts, as a provider change does today.
Should fix
3. Long input can hide the tool call from the decision model.
renderInput joins the user request, the tool call and the working directory, and clipMiddle keeps the first 70% and last 30% of 1500 characters. When the user's message is long, the tool call in the middle is cut entirely, and the model still returns a score. Please fall back to ask when the tool call itself does not fit, and if anything is shortened, shorten only the user request.
4. Protected paths can be approved by the model, and always_asks is lost.
Writes to Claude config files and other sensitive files return safetyCheck with classifierApprovable: true (filesystem.ts), so in Auto the model can approve edits to .claude/settings.json or hooks. These paths still ask in bypass mode. When the model answers ask, { ...result, decisionReason } replaces the safetyCheck reason, so structuredIO.ts no longer sets always_asks and the dialog offers "Always allow" for a protected path. Please keep every safetyCheck with the user in Auto, and keep the original reason when the model answers ask.
5. Background agents get a prompt instead of a denial.
The Auto branch returns directly, both in the early returns and after a model ask, so it never reaches the shouldAvoidPermissionPrompts block further down (permission hooks, then deny). In Auto, a background agent that reads .env or gets a model ask sends a permission request instead of being denied. Please let these cases fall through to that block.
6. Switching to Auto is not reported to the server.
print.ts still has newMode === (feature('TRANSCRIPT_CLASSIFIER') && 'auto') in the permission-mode listener. The flag is off in our builds, so a switch to Auto never emits system/status and never calls savePermissionMode. The server's effective mode stays on the old mode, and a resumed session goes back to it. Please compare with 'auto' directly and add a test.
7. The settings page names a different model than the one Auto uses.
With no fastModel, the runtime uses the session's selected model (fastModel ?? selectedModel in buildProviderManagedEnv, as on main), but the Auto settings show fastModel ?? models[0]. If the session runs on a model other than the first, the page and the privacy confirmation name the wrong one. Please show the model the runtime uses, from one place.
8. Decision provider requests skip the network settings.
discoverDecisionModels uses a bare fetch with no timeout, and testDecisionProviderConfig and the CLI request do not use the manual proxy. The provider code already has this in fetchUpstreamModels / fetchWithTimeout with getProxyFetchOptions (src/server/upstream/client.ts). Please reuse that, so "Fetch models" and "Test" work for users behind a proxy.
9. Desktop.
DecisionProviderSettingsSectioncallsuseDecisionProviderStore()without a selector. Please read each field with its own selector, as the rest of the PR does.DecisionProviderFormModalrepeats the model list (add, remove, merge with discovered models) and the connectivity line fromProviderFormModal. Please move the shared parts into one component or hook that both forms use.
10. The rule-denied card.
We're fine with keeping it in this PR, with two fixes:
- The description always points to
.claude/settings.local.json, but a deny rule can also come from the user or policy settings. Please word it so it holds for any source, or name the actual source. - It recognises a denial by matching the English message text (
/Permission to use .+ has been denied\./). Please use something structured that travels with the result instead, so the card doesn't silently disappear when the message changes.
11. Tests and errors.
- Removing the two early returns in the Auto branch (the non-approvable
safetyCheckandrequiresUserInteraction) leaves all 14 guardrail tests passing. ReplacingevaluateFastModel(...)withreturn nullleaves those andprovider-runtime-envpassing. Please add tests that fail in both cases: a non-approvable safety check and an interactive tool never reach the model; and the fast-model path returns allow, falls back to ask whensideQuerythrows, and makes no call when it is not configured. - The four
catch {}blocks and the!response.okbranch inpermissionGuardrail.tsdrop the cause. Please log the provider, model and error (logForDebuggingorlogError).
Notes
- PR description: it still describes the first version (
safetyNet/fewerPromptspresets, enabling the guardrail, a default decision provider, the bypass question). Please rewrite it to match the current code. - Design doc:
docs/features/permission-guardrail/tech-design.mdsays the Auto settings include a link to provider configuration; there is none. Please add the link or drop the sentence. - Leftovers:
normalizeSavedDecisionProviderrepairs concatenated model IDs and stripsactiveDecisionProviderId. That data only came from earlier commits of this branch, which were never released, so this code can go.DEFAULT_AUTO_PERMISSION_SETTINGSinsrc/types/permissionGuardrail.tsis not used.- The i18n key
settings.decisionProviders.modelsPlaceholderis not used.
yoloClassifier.tsand theTRANSCRIPT_CLASSIFIERflag: leave them as they are in this PR. We'll remove them separately.
Thanks again. This is a big piece of work, and it's close.
Summary
askon missing credentials, timeouts, provider errors, or malformed outputdenyrules and bypass-immune checks ahead of all decision-model calls/permissionsto permission settings and document the project rule file and cross-platform shell namesValidation status
The only provider/model combination validated end to end is the hosted OpenAI Decisions API with
gpt-6-luna. Manual acceptance covered provider discovery and connection testing, safety-net allow/ask behavior, invalid-key fallback, Bash and PowerShell explicit-deny precedence in bypass mode, bypass-immune writes, and transcript-marker persistence after a full DreamCoder restart.Jev, d1-ultra, Claude, Ollama, and the other decision models have not been validated end to end in DreamCoder. Their presets and protocol adapters are implementation support, not a deployment-validation claim. Thresholds and AUROC values must not be transferred between models.
How to deploy Jev
Jev is a hosted OpenRouter Decisions model, not a local deployment. It requires an OpenRouter API key; an OpenAI API key cannot call it.
https://openrouter.ai/api/alphaand API format OpenRouter Decisions.typesafe/jev-1.14.safetyNetor observation-only behavior. Do not allow Jev to turnaskintoallowuntil it has a model-specific calibrated threshold.Use the generated dev run to select the threshold with the scoring workflow documented in
experiments/system1-guardrail/eval/README.md. Freeze that threshold before running the test split, and report the test split once. This Jev deployment path is documented but still needs real-key end-to-end verification.Safety boundaries
askasktoallowRequest for feedback
providerIdandmodelId, or should deployment and behavior be combined into one permission-specific workflow?.claude/settings.local.json, including separateBash(...)andPowerShell(...)rules, or continue documenting manual JSON editing until rule ownership and merging semantics are settled?fewerPrompts? The current implementation supports both presets, but automaticasktoallowremains disabled until a model is calibrated.Testing
bun test --randomize --seed=1for the permission guardrail, structured I/O, transcript history, and WebSocket test files: 67 passedcd desktop && bun run lint: passedgpt-6-lunaPart of #146