fix(agent): tools-available note on dropped-tools continuation; keep legacy stub recognized (#74990)
The dropped-tools partial-stream continuation now also states the cut was a transport interruption and tools remain available. The pre-rewording network-stub text stays in the compressor's synthetic-turn set so crash-persisted nudges from older sessions are not mistaken for user turns.
This commit is contained in:
@@ -4192,13 +4192,15 @@ Write only the summary body. Do not include any preamble or prefix."""
|
||||
from agent.conversation_loop import (
|
||||
_CODEX_ACK_CONTINUATION_NUDGE, _CODEX_INCOMPLETE_NUDGE, _DEGENERATE_FINAL_NUDGE,
|
||||
_DROPPED_TOOLCALL_NUDGE_CONTENT, _EMPTY_TOOL_RESPONSE_NUDGE, _LENGTH_CONTINUATION_DROPPED_TOOLS_PREFIX,
|
||||
_LENGTH_CONTINUATION_NETWORK_STUB, _LENGTH_CONTINUATION_OUTPUT_LIMIT,
|
||||
_LEGACY_LENGTH_CONTINUATION_NETWORK_STUB, _LENGTH_CONTINUATION_NETWORK_STUB,
|
||||
_LENGTH_CONTINUATION_OUTPUT_LIMIT,
|
||||
)
|
||||
return text in {
|
||||
COMPRESSION_CONTINUATION_USER_CONTENT, _LEGACY_COMPRESSION_CONTINUATION_USER_CONTENT,
|
||||
MAX_ITERATIONS_SUMMARY_REQUEST, _CODEX_INCOMPLETE_NUDGE, _CODEX_ACK_CONTINUATION_NUDGE,
|
||||
_DEGENERATE_FINAL_NUDGE, _DROPPED_TOOLCALL_NUDGE_CONTENT, _EMPTY_TOOL_RESPONSE_NUDGE,
|
||||
_LENGTH_CONTINUATION_NETWORK_STUB, _LENGTH_CONTINUATION_OUTPUT_LIMIT,
|
||||
_LENGTH_CONTINUATION_NETWORK_STUB, _LEGACY_LENGTH_CONTINUATION_NETWORK_STUB,
|
||||
_LENGTH_CONTINUATION_OUTPUT_LIMIT,
|
||||
} or text.startswith((
|
||||
_BACKGROUND_PROCESS_NOTIFICATION_PREFIX, TODO_INJECTION_HEADER + "\n", _LENGTH_CONTINUATION_DROPPED_TOOLS_PREFIX,
|
||||
))
|
||||
|
||||
@@ -892,6 +892,11 @@ _LENGTH_CONTINUATION_OUTPUT_LIMIT = (
|
||||
"[System: Your previous response was truncated by the output length limit. Continue exactly "
|
||||
"where you left off. Do not restart or repeat prior text. Finish the answer directly.]"
|
||||
)
|
||||
# Pre-#74990 wording; kept so crash-persisted nudges from older sessions are still recognized.
|
||||
_LEGACY_LENGTH_CONTINUATION_NETWORK_STUB = (
|
||||
"[System: The previous response was cut off by a network error mid-stream. Continue exactly "
|
||||
"where you left off. Do not restart or repeat prior text. Finish the answer directly.]"
|
||||
)
|
||||
# The dropped-tools variant interpolates tool names; matched by prefix.
|
||||
_LENGTH_CONTINUATION_DROPPED_TOOLS_PREFIX = "[System: Your previous tool call "
|
||||
|
||||
@@ -904,7 +909,8 @@ def _get_continuation_prompt(is_partial_stub: bool, dropped_tools: Optional[List
|
||||
"the stream timed out before it could be delivered. Do NOT retry the same tool call "
|
||||
"with the same large content. Instead, break the content into multiple smaller tool "
|
||||
"calls (e.g. use multiple patch calls or write smaller files). Each tool call's "
|
||||
"arguments must be under ~8K tokens to avoid stream timeouts.]"
|
||||
"arguments must be under ~8K tokens to avoid stream timeouts. The cut was a transport "
|
||||
"interruption, not a capability change — your tools remain fully available.]"
|
||||
)
|
||||
return _LENGTH_CONTINUATION_NETWORK_STUB if is_partial_stub else _LENGTH_CONTINUATION_OUTPUT_LIMIT
|
||||
|
||||
|
||||
18
tests/agent/test_partial_stream_continuation_prompt.py
Normal file
18
tests/agent/test_partial_stream_continuation_prompt.py
Normal file
@@ -0,0 +1,18 @@
|
||||
"""After a mid-stream transport cut the continuation must keep tools on the table (#74990)."""
|
||||
import pytest
|
||||
|
||||
from agent import conversation_loop as cl
|
||||
from agent.context_compressor import ContextCompressor
|
||||
|
||||
|
||||
@pytest.mark.parametrize("dropped", [None, ["write_file"]])
|
||||
def test_partial_stub_continuation_says_tools_remain_available(dropped):
|
||||
prompt = cl._get_continuation_prompt(True, dropped).lower()
|
||||
assert "tools" in prompt and "available" in prompt
|
||||
assert "finish the answer directly" not in prompt
|
||||
|
||||
|
||||
@pytest.mark.parametrize("dropped", [None, ["write_file"]])
|
||||
def test_new_and_legacy_stub_nudges_are_recognized_as_synthetic(dropped):
|
||||
for text in (cl._get_continuation_prompt(True, dropped), cl._LEGACY_LENGTH_CONTINUATION_NETWORK_STUB):
|
||||
assert ContextCompressor._is_synthetic_compression_user_turn({"role": "user", "content": text})
|
||||
Reference in New Issue
Block a user