Persist resume prompts before execution

This commit is contained in:
wuyang6
2026-05-14 14:48:21 +08:00
parent ed935b633f
commit 3c200db621
+83 -11
View File
@@ -1630,6 +1630,29 @@ def create_app(state: AgentState) -> FastAPI:
account_key = state._account_key(account_id)
snapshot = state.run_manager.snapshot_latest(account_key, safe_id)
stored_snapshot = state.run_state_store.snapshot_latest(account_key, safe_id)
if (
snapshot is not None
and stored_snapshot is not None
and stored_snapshot.get('status') in ACTIVE_RUN_STATUSES
and snapshot.get('run_id') == stored_snapshot.get('run_id')
and snapshot.get('status') not in ACTIVE_RUN_STATUSES
):
state.run_state_store.finish(
str(stored_snapshot.get('run_id') or ''),
status=str(snapshot.get('status') or 'interrupted'),
elapsed_ms=(
int(snapshot['elapsed_ms'])
if isinstance(snapshot.get('elapsed_ms'), (int, float))
else None
),
stage=str(snapshot.get('current_stage') or ''),
error=(
str(snapshot.get('error'))
if snapshot.get('error') is not None
else None
),
)
stored_snapshot = state.run_state_store.snapshot_latest(account_key, safe_id)
if snapshot is not None:
return _merge_run_snapshot(snapshot, stored_snapshot) or snapshot
if stored_snapshot is not None:
@@ -1735,14 +1758,12 @@ def create_app(state: AgentState) -> FastAPI:
session_directory,
requested_session_id,
)
fallback_title = None
if request.resume_session_id is None:
fallback_title = _save_in_progress_session(
directory=session_directory,
agent=agent,
session_id=requested_session_id,
prompt=prompt,
)
fallback_title = _save_in_progress_session(
directory=session_directory,
agent=agent,
session_id=requested_session_id,
prompt=prompt,
)
if run_lock.locked():
queued_event = {
'type': 'run_queued',
@@ -2137,6 +2158,9 @@ def _sanitize_stored_session_for_resume(
stored: StoredAgentSession,
) -> StoredAgentSession:
trimmed, changed = _trim_incomplete_message_tail(stored.messages)
if trimmed and _is_pending_user_message(trimmed[-1]):
trimmed = trimmed[:-1]
changed = True
messages = _without_run_status_messages(trimmed)
if len(messages) != len(trimmed):
changed = True
@@ -2186,6 +2210,16 @@ def _is_incomplete_session_message(message: dict[str, Any]) -> bool:
return False
def _is_pending_user_message(message: dict[str, Any]) -> bool:
metadata = message.get('metadata')
return (
message.get('role') == 'user'
and isinstance(metadata, dict)
and metadata.get('placeholder') is True
and metadata.get('status') == 'running'
)
def _assistant_has_trailing_tool_call(message: dict[str, Any]) -> bool:
if message.get('role') != 'assistant':
return False
@@ -2359,11 +2393,49 @@ def _save_in_progress_session(
safe_id = _safe_session_id(session_id)
if safe_id is None or not prompt:
return None
if _session_json_path(directory, safe_id).exists():
initial_title = _derive_initial_session_title(prompt)
pending_metadata = {'status': 'running', 'placeholder': True}
session_path = _session_json_path(directory, safe_id)
if session_path.exists():
# 续聊也要先落盘用户消息。否则前端流断开或刷新时,用户刚发的内容只
# 存在于浏览器内存里,会出现“消息丢了但后端状态还在”的错觉。
try:
stored = load_agent_session(safe_id, directory=directory)
except (FileNotFoundError, OSError, json.JSONDecodeError):
return None
messages = list(stored.messages)
if messages and _is_pending_user_message(dict(messages[-1])):
messages.pop()
messages.append(
{
'role': 'user',
'content': prompt,
'state': 'final',
'metadata': pending_metadata,
'message_id': f'user_pending_{int(time.time() * 1000)}',
}
)
budget_state = (
dict(stored.budget_state)
if isinstance(stored.budget_state, dict)
else {}
)
budget_state['status'] = 'running'
try:
save_agent_session(
replace(
stored,
messages=tuple(messages),
budget_state=budget_state,
),
directory=directory,
)
except OSError:
return None
return None
# 新会话的第一轮执行可能很久。先写一个运行中占位,避免刷新页面后找不到会话。
initial_title = _derive_initial_session_title(prompt)
scratchpad_directory = (
agent.runtime_config.scratchpad_root / safe_id / 'scratchpad'
).resolve()
@@ -2372,7 +2444,7 @@ def _save_in_progress_session(
session = agent.build_session(None, scratchpad_directory=scratchpad_directory)
session.append_user(
prompt,
metadata={'status': 'running', 'placeholder': True},
metadata=pending_metadata,
message_id='user_pending_0',
)
stored = StoredAgentSession(