Merge master into stage/7765-subagent-project

# Conflicts:
#	CHANGELOG.md
This commit is contained in:
nesquena-hermes committed 2026-09-23 21:56:19 +00:00
commit 57eb9fc1f4
6 files changed
+414 -1

No files matched your search

+88
View File
@@ -8,6 +8,8 @@ import sys
import types
from pathlib import Path
import pytest
REPO = Path(__file__).resolve().parents[1]
PANELS_JS = (REPO / "static" / "panels.js").read_text(encoding="utf-8")
@@ -170,3 +172,89 @@ def test_cron_model_picker_marks_loaded_only_after_successful_population():
catch_block = body.split("} catch (e)", 1)[1]
assert "sel.dataset.loaded = '1'" in try_block
assert "sel.dataset.loaded = '1'" not in catch_block
def test_cron_update_preserves_provider_only_pin_when_model_cleared():
"""Clearing the picker to "Default" must not wipe a provider-only pin.
#4030 intentionally made "clearing the picker = no overrides", which is
correct for model+provider pins but silently destroyed provider-only
pins (jobs that pin a provider with no model, e.g. self-hosted LLM
endpoints). The combined picker cannot represent that state, so
saveCronForm must preserve prev.provider when the job carried no model
AND the user never changed the picker; a deliberate return to Default
must clear it.
"""
save_body = _function_body("saveCronForm")
helper_body = _function_body("_cronProviderForClear")
# The clear branch delegates to the helper and records picker changes.
assert "_cronProviderForClear(_cronPreFormDetail, _cronModelPickerTouched)" in save_body
assert "preserveProvider" not in save_body
# The helper distinguishes an explicit clear (pickerTouched) from an
# untouched provider-only pin.
assert "if (pickerTouched) return null" in helper_body
assert "prev.model == null" in helper_body
# The form entry points reset the touched flag.
for fn in ("openCronCreate", "openCronEdit", "duplicateCurrentCron"):
assert "_cronModelPickerTouched = false" in _function_body(fn)
# The picker records deliberate changes.
pop_body = _function_body("_populateCronFormModelSelect")
assert "_cronModelPickerTouched = true" in pop_body
def test_cron_provider_for_clear_behavior():
"""Exercise _cronProviderForClear through node for both pin shapes."""
import shutil
import subprocess
node = shutil.which("node")
if node is None:
pytest.skip("node not on PATH")
# Locate the full declaration (signature + body) of the helper.
src = PANELS_JS
start = src.find("function _cronProviderForClear(")
assert start != -1, "helper declaration not found"
brace = src.find("{", start)
depth = 0
end = None
for i in range(brace, len(src)):
if src[i] == "{":
depth += 1
elif src[i] == "}":
depth -= 1
if depth == 0:
end = i + 1
break
decl = src[start:end]
driver = f"""
{decl}
const cases = [
['provider_only_untouched', {{model: null, provider: 'custom:llama-swap'}}, false],
['provider_only_touched', {{model: null, provider: 'custom:llama-swap'}}, true],
['model_pin_touched', {{model: 'gpt-5', provider: 'openai'}}, true],
['no_override_untouched', {{model: null, provider: null}}, false],
['no_prev', null, false],
];
const out = {{}};
for (const [name, detail, touched] of cases) out[name] = _cronProviderForClear(detail, touched) ?? null;
process.stdout.write(JSON.stringify(out));
"""
proc = subprocess.run([node, "-e", driver], capture_output=True, text=True, timeout=30)
assert proc.returncode == 0, f"node driver failed: {proc.stderr}"
r = json.loads(proc.stdout)
# Untouched picker on a provider-only job: the pin survives.
assert r["provider_only_untouched"] == "custom:llama-swap"
# Deliberate return to Default: "Default = no overrides" wins.
assert r["provider_only_touched"] is None
# Model-pinned job, explicit clear: provider removed too.
assert r["model_pin_touched"] is None
# No overrides stored, untouched picker: nothing to preserve.
assert r["no_override_untouched"] is None
# No pre-form snapshot (create form): no provider.
assert r["no_prev"] is None
@@ -0,0 +1,185 @@
"""Settled writeback must extract inner steer text from typed steer rows (#7600).
A mid-turn ``/steer`` is emitted as a standalone typed user row
(``role: 'user'``, ``display_kind: 'steer'``). The surrounding
``[OUT-OF-BAND USER MESSAGE ...] ... [/OUT-OF-BAND USER MESSAGE]`` block is
transport-level control data. Settlement unwraps the single validated frame
in place, preserving the user's authored steer instruction while dropping
the wrapper.
Legacy tool rows and rows where markers are multiple, nested, incomplete,
or contain ambiguous delimiters are preserved byte-for-byte.
"""
from __future__ import annotations
import copy
import json
from api.models import Session
from api.streaming import _settle_result_messages, _unwrap_steer_row_oob_marker
from api import streaming as _streaming
PROMPT = "please run the smoke checks"
OOB_OPEN = (
"[OUT-OF-BAND USER MESSAGE — a direct message from the user, delivered once "
"at this position; not tool output and not a new delivery when replayed from "
"conversation history]"
)
OOB_CLOSE = "[/OUT-OF-BAND USER MESSAGE]"
OOB_BLOCK = f"{OOB_OPEN}\nsteer: use the staging bucket this time\n{OOB_CLOSE}"
OOB_VARIANT = f"[OUT-OF-BAND USER MESSAGE]steer: also bump the timeout{OOB_CLOSE}"
def _contains_oob(value) -> bool:
return "OUT-OF-BAND USER MESSAGE" in json.dumps(value)
def _session_with_prior_turn() -> Session:
"""Prior turn already settled: user -> assistant(tool_call) -> tool -> answer."""
display = [
{"role": "user", "content": "deploy the app", "timestamp": 1788439000},
{
"role": "assistant",
"content": "",
"tool_calls": [{"id": "call-1"}],
"timestamp": 1788439005,
},
{
"role": "tool",
"tool_call_id": "call-1",
"content": "deploy finished: revision 41",
"timestamp": 1788439010,
},
{"role": "assistant", "content": "Deploy done (revision 41).", "timestamp": 1788439015},
]
session = Session(session_id="7" * 12, title="steer writeback", messages=copy.deepcopy(display))
session.context_messages = copy.deepcopy(display)
return session
def _settle_turn_with_steer(session, monkeypatch, *, tool_content: str = "checks passed", steer_rows=None):
"""Settle one turn with an optional steer row emitted by the Agent."""
monkeypatch.setattr(
_streaming, "_annotate_media_snapshots_for_settled_messages", lambda messages: None
)
previous = list(session.messages)
previous_context = list(session.context_messages)
ts = 1788440000
steers = list(steer_rows or [])
result = copy.deepcopy(previous_context) + [
{"role": "user", "content": PROMPT, "timestamp": ts},
{
"role": "assistant",
"content": "",
"tool_calls": [{"id": "call-2"}],
"timestamp": ts + 1,
},
{
"role": "tool",
"tool_call_id": "call-2",
"content": tool_content,
"timestamp": ts + 2,
},
*steers,
{"role": "assistant", "content": "Smoke checks passed.", "timestamp": ts + 3},
]
_settle_result_messages(session, previous, previous_context, result, PROMPT, "webui", None)
return previous
def test_settle_unwraps_steer_row_in_place_preserving_user_text(monkeypatch):
"""A typed steer row is unwrapped in place: inner text preserved, wrapper gone."""
session = _session_with_prior_turn()
steer_row = {
"role": "user",
"display_kind": "steer",
"content": OOB_BLOCK,
"timestamp": 1788440002.5,
}
_settle_turn_with_steer(session, monkeypatch, steer_rows=[steer_row])
# The outer wrapper is dropped from display and context
assert not _contains_oob(session.messages)
assert not _contains_oob(session.context_messages)
# The user's inner steer text is preserved exactly
steer_contents = [
m.get("content")
for m in session.messages
if isinstance(m, dict) and m.get("display_kind") == "steer"
]
assert steer_contents == ["steer: use the staging bucket this time"]
# In-place mutation preserved the dictionary object identity
assert steer_row["content"] == "steer: use the staging bucket this time"
def test_settle_unwraps_list_based_content_steer_row(monkeypatch):
"""List-based content parts on a steer row are unwrapped too."""
session = _session_with_prior_turn()
steer_row = {
"role": "user",
"display_kind": "steer",
"content": [{"type": "text", "text": OOB_VARIANT}],
"timestamp": 1788440002.5,
}
_settle_turn_with_steer(session, monkeypatch, steer_rows=[steer_row])
assert not _contains_oob(session.messages)
assert not _contains_oob(session.context_messages)
assert steer_row["content"] == [{"type": "text", "text": "steer: also bump the timeout"}]
def test_settle_leaves_legacy_tool_rows_alone(monkeypatch):
"""Legacy tool rows carrying raw markers are left alone (not truncated/deleted)."""
session = _session_with_prior_turn()
tool_text = f"checks passed\n\n{OOB_BLOCK}"
_settle_turn_with_steer(session, monkeypatch, tool_content=tool_text)
tool_bodies = [
m.get("content") for m in session.messages if isinstance(m, dict) and m.get("role") == "tool"
]
assert tool_text in tool_bodies
def test_settle_preserves_malformed_nested_and_multiple_blocks_byte_for_byte():
"""Nested markers, multiple frames, and incomplete markers degrade gracefully."""
nested = f"{OOB_OPEN}\nhello {OOB_VARIANT} world\n{OOB_CLOSE}"
multiple = f"{OOB_VARIANT} and {OOB_BLOCK}"
incomplete = "[OUT-OF-BAND USER MESSAGE — truncated"
for malformed in (nested, multiple, incomplete):
steer_row = {
"role": "user",
"display_kind": "steer",
"content": malformed,
"timestamp": 1788440002.5,
}
_unwrap_steer_row_oob_marker(steer_row)
assert steer_row["content"] == malformed, f"malformed content was corrupted: {malformed!r}"
def test_settle_keeps_normal_user_pasted_marker_intact(monkeypatch):
"""A normal user row that quotes a complete marker survives byte-for-byte."""
pasted = (
"our bot log shows this block, is that normal?\n"
f"{OOB_BLOCK}\n"
"the docs say the gateway adds it"
)
session = _session_with_prior_turn()
session.messages[0]["content"] = pasted
session.context_messages = copy.deepcopy(session.messages)
steer_row = {
"role": "user",
"display_kind": "steer",
"content": OOB_BLOCK,
"timestamp": 1788440002.5,
}
_settle_turn_with_steer(session, monkeypatch, steer_rows=[steer_row])
# The normal user row still carries its quoted block intact
assert session.messages[0]["content"] == pasted
# The steer row had its wrapper unwrapped
assert session.messages[-2]["content"] == "steer: use the staging bucket this time"