fix(webui): keep context-engine guidance model-facing - #2825
LumenYoung wants to merge 1 commit into
Conversation
SummaryReading the diff at (1) Wrap the compressor input with a synthetic system anchor ( Code referenceThe split helper at def _split_model_context_for_display(messages):
model_context = list(messages or [])
display_messages = list(model_context)
if display_messages and isinstance(display_messages[0], dict) and display_messages[0].get("role") == "system":
display_messages = display_messages[1:]
return display_messages, model_contextThe compression call-site change at s.messages = compressed # display: no leading system guidance
s.context_messages = compressed_context # model context: keeps system guidanceThe LCM-only fallback at def _ensure_lcm_retrieval_policy_model_context(messages, context_engine=None):
engine_name = str(context_engine or "").lower()
if engine_name != "lcm" and not _looks_like_lcm_model_context(model_context):
return model_context
if _context_has_lcm_retrieval_policy(model_context):
return model_context
...Diagnosis / RecommendationThe architectural premise is right: WebUI's
Test planplus a manual round-trip with a real LCM-enabled session: trigger manual compression via the WebUI, confirm Strong shape, layering concerns above worth addressing before merge. |
Deferred to a future iteration — concerns from review need a pass before mergeThanks @LumenYoung — the architectural premise (WebUI's Concerns to address before mergeFollowing the review's per-claim analysis:
What works as-is
Path forwardTwo viable next steps:
My read: (1) is the cleaner path because the engine-name plumbing question genuinely needs your judgment about how the LCM plugin should expose its policy text — that's a contract design call, not a mechanical fix. Applying |
f76d976 to
c887529
Compare
|
Thanks @LumenYoung — you've identified a real gap: WebUI keeps its system prompt separate from Closing this implementation, though, because the detection mechanism is too brittle to maintain. The durable fix belongs on the context-engine contract side: the engine should emit its model-facing guidance through a stable, structured signal (e.g. a dedicated Closing with thanks for the clear write-up of the underlying split — if you (or anyone) want to pursue the structured-signal version, that'd be very welcome. Crediting your analysis here for whoever picks it up. |
Summary
This PR makes WebUI preserve context-engine guidance as model-facing context after manual compression, without rendering that guidance in the visible transcript.
The motivating case is LCM/retrieval-backed compression: WebUI can successfully persist compacted summaries such as
[Recent Summary ...], but because WebUI keeps its system prompt separate fromconversation_history, context engines that attach guidance to a leading system message may not have a stable model-facing place to put retrieval instructions. The next model turn can then see compacted summaries without the policy that tells it to recover exact details through retrieval tools.Why this happens
WebUI has a split that the CLI/core path does not expose in the same way:
messages: user-visible transcriptcontext_messages: model-facing active contextsystem_message: passed separately torun_conversation(...)The manual compression path previously compressed only the transcript messages and then wrote the returned list to both display and model context. That works for plain summarization, but it loses the context-engine contract for engines that need to return model-facing guidance, especially when the guidance is attached to a leading system message.
For retrieval-backed summaries, this is risky: summaries are useful routing/index hints, not a complete source of exact historical facts. The model should be reminded to use retrieval before relying on compacted history.
Fix
context_messages: preserves leading system guidance for the modelmessages: strips leading system guidance so it is not rendered as a visible transcript turnTests
tests/test_sprint46.py::test_lcm_policy_helper_injects_model_facing_policy_for_summary_contexttests/test_sprint46.py::test_lcm_policy_helper_is_idempotent_and_avoids_non_lcm_contexttests/test_sprint46.py::test_session_compress_keeps_engine_system_guidance_model_facing_onlytests/test_sprint46.py::test_session_compress_roundtripLocal focused run: