fix(gateway): a /branch child row carries the parent's system prompt
The gateway /branch copies the parent transcript byte-for-byte but created
the child row without a system prompt, so the branch's first turn rebuilt
the prompt (re-probing the workspace) and lost the warm prefix cache, and
logged the null-prompt warning on every branch. 2ec12952 fixed the CLI and
TUI branch writers; the gateway is the third. Read the parent row's prompt
and pass it to create_session.
(cherry picked from commit 4103a7c66c3b86659ee2cdbd7eef37d735aff237)
This commit is contained in:
@@ -1039,6 +1039,14 @@ class GatewaySessionCommandsMixin:
|
||||
# ``_branched_from`` keeps the branch visible in /resume and /sessions after the parent is
|
||||
# reopened and re-ended. ALL routing columns go in at CREATE time: a crash before
|
||||
# switch_session() records the peer would otherwise leave the branch unroutable.
|
||||
# The child sends the parent's exact system prompt: a row without one makes the branch's
|
||||
# first turn rebuild (re-probing the workspace) and forfeits the warm cache the copied
|
||||
# transcript buys.
|
||||
parent_prompt = None
|
||||
try:
|
||||
parent_prompt = ((await self._session_db.get_session(parent_session_id)) or {}).get("system_prompt")
|
||||
except Exception:
|
||||
logger.debug("branch: parent system prompt read failed for %s", parent_session_id, exc_info=True)
|
||||
try:
|
||||
await self._session_db.create_session(
|
||||
session_id=new_session_id,
|
||||
@@ -1048,7 +1056,7 @@ class GatewaySessionCommandsMixin:
|
||||
parent_session_id=parent_session_id, user_id=dest_source.user_id,
|
||||
session_key=dest_key, chat_id=dest_source.chat_id, chat_type=dest_source.chat_type,
|
||||
thread_id=dest_source.thread_id, origin_json=_branch_origin_json,
|
||||
display_name=current_entry.display_name)
|
||||
display_name=current_entry.display_name, system_prompt=parent_prompt or None)
|
||||
except Exception as e:
|
||||
logger.error("Failed to create branch session: %s", e)
|
||||
return t("gateway.branch.create_failed", error=e)
|
||||
|
||||
@@ -153,3 +153,32 @@ class TestBranchRoutingColumns:
|
||||
|
||||
_ = real_switch_session # silence unused
|
||||
|
||||
|
||||
class TestBranchSystemPrompt:
|
||||
@pytest.mark.asyncio
|
||||
async def test_branched_session_carries_parent_system_prompt(self, store):
|
||||
"""The branch copies the parent transcript byte-for-byte so its first
|
||||
turn can hit the warm prefix cache, but create_session() at branch
|
||||
time dropped the system prompt: the child row's system_prompt column
|
||||
was None even though the parent row held one. Mirrors the CLI/TUI fix
|
||||
in 2ec12952 for the third branch-creation site (the gateway)."""
|
||||
source = _make_source()
|
||||
parent_entry = store.get_or_create_session(source)
|
||||
store._db.update_system_prompt(parent_entry.session_id, "PARENT PROMPT")
|
||||
store._db.append_message(parent_entry.session_id, role="user", content="hello")
|
||||
store._db.append_message(parent_entry.session_id, role="assistant", content="world")
|
||||
|
||||
runner = _make_branch_runner(store)
|
||||
await runner._handle_branch_command(_make_event("/branch"))
|
||||
|
||||
new_entry = store.get_or_create_session(source)
|
||||
assert new_entry.session_id != parent_entry.session_id
|
||||
|
||||
row = store._db.get_session(new_entry.session_id)
|
||||
assert row is not None
|
||||
assert row["system_prompt"] == "PARENT PROMPT", (
|
||||
"branched session lost the parent's system prompt — its first "
|
||||
"turn will re-probe the workspace and forfeit the warm cache "
|
||||
"the copied transcript buys"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user