fix session display replay consistency
This commit is contained in:
+56
-5
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user