[eric] release: 1.7.9 ships with a story, and two log assertions stop reading the root logger

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018foyDoK19jjbYdudfzQVkZ
This commit is contained in:
ciregenz
2026-08-24 01:04:59 -07:00
co-authored by Claude Opus 5
parent 3e0e1f67c6
commit f8d67fdfd1
3 changed files with 63 additions and 9 deletions
+22
View File
@@ -21,6 +21,28 @@ P_RELEASES: List[ReleaseNote] = [
# Only lines that are true of the built app belong here. This one file feeds the in-app card, the
# GitHub body AND the Help agent's context, so a line written for a planned feature becomes the
# agent confidently describing something that does not exist.
ReleaseNote(
version="1.7.9",
headline="Agents keep going when the connection does not, and the fn key finally works.",
highlights=[
"Press fn to dictate on any Mac. It asks for permission the first time you use it rather than at install, and it recovers without a relaunch if you grant it later.",
"Drop files straight onto a chat. Anything the app cannot take now says so instead of silently doing nothing.",
"The transcript follows a running agent until you scroll away, and re-pins itself the moment you scroll back.",
"Agents can move, tile, collapse and close their own cards, so a busy canvas tidies itself.",
],
fixes=[
"A dropped connection no longer costs you the conversation. The agent reconnects and carries on from where it was.",
"Pressing Stop stops it. A background watchdog can no longer restart a chat you just ended.",
"Chats stopped disconnecting mid task. A slow web page was being mistaken for a jammed tool and shot, roughly ten times a week per install.",
"An agent that runs out of things to say gets asked once for its answer instead of leaving you looking at a Done label with nothing under it.",
"Signing in on a fresh install works. The hand off back from your browser was landing on the wrong port.",
"An expired provider login renews itself mid run instead of stopping the turn and asking you to reconnect.",
"A browser agent can no longer report a task complete when the page never changed.",
"Turning a schedule on or off tells you the truth. A failed save used to leave the switch showing the wrong state.",
"Card resizing ends when you let go, even over an embedded browser.",
"Dictation goes to the chat you were typing in, not a brand new one.",
],
),
ReleaseNote(
version="1.7.8",
headline="A stuck chat unsticks itself, and agents can finally upload files.",
+37 -6
View File
@@ -19,6 +19,38 @@ from backend.apps.agents.core.error_classify import (
)
TURN_RUNNER = "backend/apps/agents/manager/run/TurnRunner.py"
class p_capture:
"""Capture a specific logger directly.
`caplog` reads the ROOT logger, so it goes blind the moment any other test in the run sets
propagate=False on ours: these two assertions passed alone and failed in the full suite while
the line was plainly there in captured stderr. A logging assertion must not depend on what
3,000 other tests did to the logging tree.
"""
def __init__(self, name):
import logging
self.logger = logging.getLogger(name)
self.records = []
self.handler = logging.Handler()
self.handler.emit = lambda r: self.records.append(r)
def __enter__(self):
import logging
self.prev = self.logger.level
self.logger.setLevel(logging.WARNING)
self.logger.addHandler(self.handler)
return self
def __exit__(self, *a):
self.logger.removeHandler(self.handler)
self.logger.setLevel(self.prev)
@property
def text(self):
return "\n".join(r.getMessage() for r in self.records)
# Where each fault is raised. A fault this build knows but wires nowhere is the exact shape of a
# guard that never fires, so the map is the test, not a convenience.
WIRED_IN = {
@@ -109,18 +141,17 @@ def test_every_known_fault_is_wired_somewhere():
assert p_block(kind).strip(), f"{kind} has an empty branch"
def test_arming_is_announced_and_a_typo_is_named(monkeypatch, caplog):
def test_arming_is_announced_and_a_typo_is_named(monkeypatch):
# The harness built to kill row-6 silence had it: unknown_faults() existed and NOTHING called it,
# so a mistyped name armed nothing while the drill exercised the untouched happy path.
monkeypatch.setenv("OSW_FAULT", "policy_block,plicy_blok")
with caplog.at_level("WARNING"):
with p_capture("backend.apps.agents.core.fault_injection") as cap:
announce()
assert "policy_block" in caplog.text and "plicy_blok" in caplog.text
caplog.clear()
assert "policy_block" in cap.text and "plicy_blok" in cap.text
monkeypatch.delenv("OSW_FAULT")
with caplog.at_level("WARNING"):
with p_capture("backend.apps.agents.core.fault_injection") as cap2:
announce()
assert caplog.text == "", "a shipped build must say nothing at all"
assert cap2.text == "", "a shipped build must say nothing at all"
def test_the_boot_path_actually_announces():
+4 -3
View File
@@ -118,12 +118,13 @@ def test_the_hook_shapes_the_pristine_response_not_the_flattened_one():
assert i_capture < i_use
def test_the_off_switch_is_declared_and_announces_itself(monkeypatch, caplog):
def test_the_off_switch_is_declared_and_announces_itself(monkeypatch):
from backend.apps.agents.manager.streaming import tool_output_shaper as mod
from backend.tests.test_fault_injection import p_capture
class S:
id = "s1"
monkeypatch.setenv("OSW_TOOL_SHAPING", "off")
with caplog.at_level("WARNING"):
with p_capture("backend.apps.agents.manager.streaming.tool_output_shaper") as cap:
assert mod.shape_for_model(S(), "s1", {"stdout": p_big()}, "m1", "Bash") is None
assert "OFF" in caplog.text, "a guard that stops guarding must say which sessions it stopped protecting"
assert "OFF" in cap.text, "a guard that stops guarding must say which sessions it stopped protecting"