Persist completed run elapsed time

This commit is contained in:
wuyang6
2026-06-12 19:48:45 +08:00
parent aac6383fe6
commit 4a268902bf
2 changed files with 61 additions and 27 deletions
+58 -24
View File
@@ -3799,34 +3799,68 @@ def _annotate_last_assistant_elapsed(
session_id: str, session_id: str,
elapsed_ms: int, elapsed_ms: int,
) -> None: ) -> None:
path = _session_json_path(directory, session_id)
try: try:
data = json.loads(path.read_text(encoding='utf-8')) stored = load_agent_session(session_id, directory=directory)
except (OSError, json.JSONDecodeError): except (
FileNotFoundError,
OSError,
json.JSONDecodeError,
KeyError,
TypeError,
ValueError,
):
return return
messages = data.get('messages')
display_messages = data.get('display_messages') messages, messages_changed = _annotate_last_assistant_in_messages(
if not isinstance(display_messages, list): stored.messages,
display_messages = messages elapsed_ms,
if not isinstance(messages, list) and not isinstance(display_messages, list): )
display_messages: tuple[dict[str, Any], ...] = ()
display_changed = False
if stored.display_messages:
display_messages, display_changed = _annotate_last_assistant_in_messages(
stored.display_messages,
elapsed_ms,
)
if not messages_changed and not display_changed:
return return
for message_list in (messages, display_messages):
if not isinstance(message_list, list): save_agent_session(
replace(
stored,
messages=messages if messages_changed else stored.messages,
display_messages=(
display_messages
if display_changed
else stored.display_messages
),
),
directory=directory,
)
def _annotate_last_assistant_in_messages(
messages: tuple[dict[str, Any], ...] | tuple[Any, ...],
elapsed_ms: int,
) -> tuple[tuple[dict[str, Any], ...], bool]:
updated = [dict(message) for message in messages if isinstance(message, dict)]
for index in range(len(updated) - 1, -1, -1):
message = updated[index]
if message.get('role') != 'assistant':
continue continue
for message in reversed(message_list): metadata = message.get('metadata')
if not isinstance(message, dict) or message.get('role') != 'assistant': if not isinstance(metadata, dict):
continue metadata = {}
metadata = message.get('metadata') else:
if not isinstance(metadata, dict): metadata = dict(metadata)
metadata = {} if metadata.get('elapsed_ms') == elapsed_ms:
message['metadata'] = metadata return tuple(updated), False
metadata['elapsed_ms'] = elapsed_ms metadata['elapsed_ms'] = elapsed_ms
break message['metadata'] = metadata
try: updated[index] = message
path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding='utf-8') return tuple(updated), True
except OSError: return tuple(updated), False
return
return
def _read_session_title(directory: Path, session_id: str | None) -> str | None: def _read_session_title(directory: Path, session_id: str | None) -> str | None:
@@ -148,7 +148,7 @@ export function ThreadListSidebar({
<SidebarMenu> <SidebarMenu>
<SidebarMenuItem> <SidebarMenuItem>
<SidebarMenuButton size="lg"> <SidebarMenuButton size="lg">
<div className="aui-sidebar-header-icon-wrapper flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> <div className="aui-sidebar-header-icon-wrapper flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-accent text-sidebar-foreground">
<BotIcon className="aui-sidebar-header-icon size-4" /> <BotIcon className="aui-sidebar-header-icon size-4" />
</div> </div>
<div className="aui-sidebar-header-heading mr-6 flex flex-col gap-0.5 leading-none"> <div className="aui-sidebar-header-heading mr-6 flex flex-col gap-0.5 leading-none">
@@ -647,7 +647,7 @@ function AccountMenu({
{compact ? ( {compact ? (
<button <button
type="button" type="button"
className="flex size-8 items-center justify-center rounded-full bg-sidebar-primary text-sidebar-primary-foreground transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground" className="flex size-8 items-center justify-center rounded-full bg-sidebar-accent text-sidebar-foreground transition-colors hover:bg-sidebar-accent/80 hover:text-sidebar-accent-foreground"
aria-label="账号与统计" aria-label="账号与统计"
title={account.username} title={account.username}
> >
@@ -660,7 +660,7 @@ function AccountMenu({
type="button" type="button"
className="flex w-full items-center gap-2 rounded-lg px-2 py-2 text-left transition-colors hover:bg-sidebar-accent" className="flex w-full items-center gap-2 rounded-lg px-2 py-2 text-left transition-colors hover:bg-sidebar-accent"
> >
<div className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> <div className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-sidebar-accent text-sidebar-foreground">
<UserIcon className="size-4" /> <UserIcon className="size-4" />
</div> </div>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">