diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a165e22b..4ac6fcd00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Fixed +- **The agent no longer tells you a stored credential is "wrong" when it's just masked.** Secrets are redacted (`***`, `sk-abc…xyz1`) before the model sees them, but nothing told the model that masking was intentional — so it sometimes read a masked API key or password and reported it as a typo or a placeholder. The WebUI progress-guidance prompt now explains that redacted credential fields are deliberate masking, so the agent stops flagging correctly-stored secrets as errors. Thanks @mvanhorn. (#5927, #5871) + - **Stale "unread" dot no longer lingers on a session after you open it.** Visiting a session now clears its sidebar unread indicator across the paths that previously left it stuck — the same-session reselect, the metadata-arrival ack, and the post-message-load re-sync — while a completion that lands in a genuinely hidden/background tab correctly stays unread. It also stops a phantom unread/streaming indicator from appearing when you switch from a busy session to an idle one (the idle session's streaming flags are now reset from its own metadata before the sidebar repaint, instead of inheriting the previous session's busy state). Thanks @neaucode-bot. (#5917, #4946) - **Plugin-provided model providers route correctly when set as the default.** A model from a plugin-only provider (e.g. a `@plugin:model` route) was surfaced in the catalog but, when that plugin provider was also the configured default, the request dropped the `@plugin:` routing hint and went to the wrong backend. Provider-hint resolution now applies plugin routing before the configured-provider bare-passthrough. Thanks @alexfoxtm. (#5909, #5461) diff --git a/api/streaming.py b/api/streaming.py index cbdaf895c..6e8a2ea0b 100644 --- a/api/streaming.py +++ b/api/streaming.py @@ -636,6 +636,7 @@ WebUI progress guidance: - Each update should say what you are about to check, what you just confirmed, or why the next tool call is needed. - Keep updates concise, factual, and in the user's language. One or two short sentences are enough. - Do not reveal hidden reasoning, chain-of-thought, private scratchpads, secrets, raw logs, or long tool output. +- Password, API-key, token, and secret fields are automatically redacted by the system. Treat masked values as intentional redaction, not placeholder text or user input errors, and do not tell the user a stored credential is wrong based on a masked value alone. - Final visible assistant replies must be clear, user-facing, and in the user's language, not private planning notes. - Do not include terse planning fragments or scratchpad shorthand in visible assistant text. Avoid fragments like "Need script", "Need check logs", "Need inspect email", or "maybe invite"; either omit them or rewrite them as clear user-facing progress. - For direct answers or very short tasks, skip progress updates and answer normally. diff --git a/tests/test_issue5871_redaction_awareness_prompt.py b/tests/test_issue5871_redaction_awareness_prompt.py new file mode 100644 index 000000000..abbc868ba --- /dev/null +++ b/tests/test_issue5871_redaction_awareness_prompt.py @@ -0,0 +1,47 @@ +"""Product-semantics coverage for WebUI credential-masking guidance (#5871).""" + +import re + +from api.streaming import _WEBUI_PROGRESS_PROMPT, _webui_ephemeral_system_prompt + + +def _redaction_guidance() -> str: + return next( + line for line in _WEBUI_PROGRESS_PROMPT.splitlines() + if "automatically redacted" in line + ) + + +def test_progress_prompt_explains_intentional_credential_redaction(): + guidance = _redaction_guidance() + + assert "Password, API-key, token, and secret fields" in guidance + assert "intentional redaction" in guidance + assert "not placeholder text or user input errors" in guidance + assert "do not tell the user a stored credential is wrong" in guidance + assert "masked value alone" in guidance + + +def test_redaction_guidance_flows_into_ephemeral_system_prompt(): + prompt = _webui_ephemeral_system_prompt( + "Use a concise tone.", + surface_context={"source": "webui"}, + ) + + assert _redaction_guidance() in prompt + + +def test_progress_prompt_retains_secret_leak_prevention_guidance(): + assert ( + "Do not reveal hidden reasoning, chain-of-thought, private scratchpads, " + "secrets, raw logs, or long tool output." + ) in _WEBUI_PROGRESS_PROMPT + + +def test_redaction_guidance_does_not_teach_concrete_key_or_mask_formats(): + guidance = _redaction_guidance() + + assert "***" not in guidance + assert "..." not in guidance + assert not re.search(r"\b(?:sk-|ghp_|github_pat_|xox[baprs]-|AKIA)\S+", guidance) + assert not re.search(r"\b[A-Za-z0-9_-]{24,}\b", guidance)