fix session display replay consistency

This commit is contained in:
wuyang6
2026-06-30 14:40:20 +08:00
parent 84ff22fc65
commit 0007d99763
4 changed files with 291 additions and 19 deletions
+56 -5
View File
@@ -724,7 +724,11 @@ class LocalCodingAgent:
if stored_resume_state is not None:
starting_usage = usage_from_payload(stored_resume_state.usage)
starting_cost_usd = stored_resume_state.total_cost_usd
starting_tool_calls = stored_resume_state.tool_calls
starting_tool_calls = self._sanitize_persisted_tool_call_count(
stored_resume_state.tool_calls,
stored_resume_state.messages,
stored_resume_state.display_messages,
)
starting_session_turns = stored_resume_state.turns
budget_state = (
stored_resume_state.budget_state
@@ -1830,6 +1834,7 @@ class LocalCodingAgent:
)
return turn, ()
request_messages = session.to_openai_messages()
assistant_index = session.start_assistant(
message_id=f'assistant_{len(session.messages)}'
)
@@ -1837,7 +1842,7 @@ class LocalCodingAgent:
finish_reason: str | None = None
events: list[StreamEvent] = []
for event in self.client.stream(
session.to_openai_messages(),
request_messages,
tool_specs,
output_schema=self.runtime_config.output_schema,
):
@@ -4416,14 +4421,22 @@ class LocalCodingAgent:
previous = None
if previous is not None:
previous_turns = previous.turns
previous_tool_calls = previous.tool_calls
previous_tool_calls = self._sanitize_persisted_tool_call_count(
previous.tool_calls,
previous.messages,
previous.display_messages,
)
if isinstance(previous.budget_state, dict):
previous_budget_state = dict(previous.budget_state)
total_tool_calls = self._merge_tool_call_count(
previous_tool_calls,
result.tool_calls,
)
budget_state = {
'model_calls': int(previous_budget_state.get('model_calls', 0))
+ max(result.turns, 0),
'session_turns': previous_turns + result.turns,
'tool_calls': previous_tool_calls + result.tool_calls,
'tool_calls': total_tool_calls,
'delegated_tasks': sum(
1 for entry in result.file_history if entry.get('action') in ('delegate_agent', 'Agent')
),
@@ -4438,7 +4451,7 @@ class LocalCodingAgent:
messages=session.model_transcript(),
display_messages=session.display_transcript(),
turns=previous_turns + result.turns,
tool_calls=previous_tool_calls + result.tool_calls,
tool_calls=total_tool_calls,
usage=result.usage.to_dict(),
total_cost_usd=result.total_cost_usd,
file_history=result.file_history,
@@ -4463,6 +4476,44 @@ class LocalCodingAgent:
transcript=session.transcript(),
)
@staticmethod
def _merge_tool_call_count(previous_tool_calls: int, result_tool_calls: int) -> int:
previous = max(0, int(previous_tool_calls or 0))
current = max(0, int(result_tool_calls or 0))
# Resumed runs initialize the runtime counter from persisted state, so
# result.tool_calls is usually already session-cumulative. Do not add it
# to the previous total again.
if current >= previous:
return current
# Some early-return paths still return a per-run delta.
return previous + current
@staticmethod
def _sanitize_persisted_tool_call_count(
persisted_tool_calls: int,
model_messages: tuple[dict[str, object], ...],
display_messages: tuple[dict[str, object], ...],
) -> int:
persisted = max(0, int(persisted_tool_calls or 0))
counted = max(
LocalCodingAgent._count_assistant_tool_calls(model_messages),
LocalCodingAgent._count_assistant_tool_calls(display_messages),
)
if counted and persisted > counted * 100:
return counted
return persisted
@staticmethod
def _count_assistant_tool_calls(messages: tuple[dict[str, object], ...]) -> int:
total = 0
for message in messages:
if not isinstance(message, dict) or message.get('role') != 'assistant':
continue
tool_calls = message.get('tool_calls')
if isinstance(tool_calls, (list, tuple)):
total += len(tool_calls)
return total
def _inject_runtime_guidance(
self,
session: AgentSessionState,