fix(gateway): expand @ references before the reply pointer so quoted text stays literal
Follow-up to the truncation removal: with the full reply text in the prepared message, a `@file:`/`@url:` reference inside the *quoted* message reached the context-reference expander and read a local file on the replier's behalf (the old 500-char slice hid this for long quotes; short quotes were already exposed on main). Expansion now runs on the new message text only; the reply pointer is prepended afterwards.
This commit is contained in:
@@ -1618,10 +1618,13 @@ class GatewayInboundMixin:
|
||||
message_text = await self._enrich_inbound_voice(event, source, message_text, audio_paths)
|
||||
message_text = self._prepend_inbound_media_file_notes(message_text, audio_file_paths, video_paths)
|
||||
message_text = self._prepend_inbound_document_notes(event, message_text)
|
||||
message_text = self._prepend_inbound_reply_context(event, source, message_text)
|
||||
if "@" in message_text:
|
||||
return await self._expand_inbound_context_references(source, session_key, message_text)
|
||||
return message_text
|
||||
message_text = await self._expand_inbound_context_references(source, session_key, message_text)
|
||||
if message_text is None:
|
||||
return None
|
||||
# After expansion: the quoted reply is someone else's text and stays literal — an
|
||||
# ``@file:`` inside it must never read a local file on the replier's behalf.
|
||||
return self._prepend_inbound_reply_context(event, source, message_text)
|
||||
|
||||
async def _prepare_profile_scoped_inbound_message_text(
|
||||
self, *, event: MessageEvent, source: SessionSource, history: List[Dict[str, Any]],
|
||||
|
||||
@@ -86,6 +86,33 @@ async def test_telegram_long_reply_reaches_prompt_without_losing_later_items():
|
||||
assert history == [{"role": "user", "content": "Previous request"}]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_quoted_reply_references_stay_literal_while_typed_ones_expand(tmp_path, monkeypatch):
|
||||
"""The replied-to author's ``@file:`` is quoted text, not the replier's request: no local read.
|
||||
The same reference typed in the new message still expands (positive control)."""
|
||||
import threading
|
||||
|
||||
payload = tmp_path / "notes.txt"
|
||||
payload.write_text("LOCAL-FILE-MARKER", encoding="utf-8")
|
||||
monkeypatch.setenv("TERMINAL_CWD", str(tmp_path))
|
||||
runner = _make_runner()
|
||||
runner._session_model_overrides, runner._last_resolved_model = {}, {}
|
||||
runner._agent_cache, runner._agent_cache_lock = {}, threading.Lock()
|
||||
runner._resolve_session_agent_runtime = lambda **kw: ("openai/gpt-4.1-mini", {"base_url": None, "api_key": ""})
|
||||
source = _source()
|
||||
|
||||
quoted = ("x " * 300) + f"\nsee @file:{payload.name} for details"
|
||||
quoted_ref = MessageEvent(text="what does this say?", source=source, reply_to_message_id="7", reply_to_text=quoted)
|
||||
result = await runner._prepare_inbound_message_text(event=quoted_ref, source=source, history=[])
|
||||
assert quoted in result
|
||||
assert "LOCAL-FILE-MARKER" not in result
|
||||
|
||||
typed_ref = MessageEvent(text=f"read @file:{payload.name}", source=source, reply_to_message_id="7", reply_to_text="short")
|
||||
result = await runner._prepare_inbound_message_text(event=typed_ref, source=source, history=[])
|
||||
assert result.startswith('[Replying to: "short"]')
|
||||
assert "LOCAL-FILE-MARKER" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_reply_prefix_still_injected_when_text_in_history():
|
||||
"""Regression test: the pointer must survive even when the quoted text
|
||||
|
||||
Reference in New Issue
Block a user