mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-24 13:32:22 +02:00
103 lines
3.7 KiB
Python
103 lines
3.7 KiB
Python
"""Pure session-construction for resume + duplicate, lifted out of agent_manager.
|
|
These BUILD an AgentSession and return it; the caller owns the in-memory store write
|
|
and the UI notify (store-before-notify is load-bearing, a client must never be told
|
|
about a session it can't yet fetch)."""
|
|
|
|
from datetime import datetime
|
|
from typing import Dict, List, Optional
|
|
from uuid import uuid4
|
|
|
|
from typeguard import typechecked
|
|
|
|
from backend.apps.agents.core.models import AgentSession, Message, MessageBranch
|
|
from backend.apps.agents.manager.session.apply_context_window import apply_context_window
|
|
from backend.apps.agents.manager.session.session_store import load_session_data
|
|
|
|
|
|
@typechecked
|
|
def load_session_for_resume(session_id: str) -> AgentSession:
|
|
"""Build a live AgentSession from its on-disk JSON snapshot. The disk copy stays put
|
|
(the history list reads from disk; deleting on resume would erase it). Raises if absent."""
|
|
data = load_session_data(session_id)
|
|
if data is None:
|
|
raise ValueError(f"Session {session_id} not found in history")
|
|
session = AgentSession(**data)
|
|
apply_context_window(session)
|
|
session.closed_at = None
|
|
return session
|
|
|
|
|
|
@typechecked
|
|
def build_duplicate_session(
|
|
source: Optional[AgentSession],
|
|
session_id: str,
|
|
dashboard_id: Optional[str],
|
|
up_to_message_id: Optional[str],
|
|
) -> AgentSession:
|
|
"""Build an independent copy of a session with the same chat history but fresh ids
|
|
(so branching the copy can't disturb the original). Raises if the source can't be found."""
|
|
if not source:
|
|
data = load_session_data(session_id)
|
|
if data is None:
|
|
raise ValueError(f"Session {session_id} not found")
|
|
source = AgentSession(**data)
|
|
apply_context_window(source)
|
|
|
|
source_messages = list(source.messages)
|
|
if up_to_message_id:
|
|
cut_idx = next(
|
|
(i for i, m in enumerate(source_messages) if m.id == up_to_message_id),
|
|
None,
|
|
)
|
|
if cut_idx is not None:
|
|
source_messages = source_messages[: cut_idx + 1]
|
|
|
|
old_to_new_msg: Dict[str, str] = {}
|
|
new_messages: List[Message] = []
|
|
for msg in source_messages:
|
|
new_id = uuid4().hex
|
|
old_to_new_msg[msg.id] = new_id
|
|
new_messages.append(Message(
|
|
id=new_id,
|
|
role=msg.role,
|
|
content=msg.content,
|
|
timestamp=msg.timestamp,
|
|
branch_id=msg.branch_id,
|
|
parent_id=old_to_new_msg.get(msg.parent_id) if msg.parent_id else None,
|
|
context_paths=msg.context_paths,
|
|
attached_skills=msg.attached_skills,
|
|
forced_tools=msg.forced_tools,
|
|
images=msg.images,
|
|
))
|
|
|
|
new_branches: Dict[str, MessageBranch] = {}
|
|
for bid, branch in source.branches.items():
|
|
new_branches[bid] = MessageBranch(
|
|
id=bid,
|
|
parent_branch_id=branch.parent_branch_id,
|
|
fork_point_message_id=old_to_new_msg.get(branch.fork_point_message_id) if branch.fork_point_message_id else None,
|
|
created_at=branch.created_at,
|
|
)
|
|
|
|
new_session = AgentSession(
|
|
id=uuid4().hex,
|
|
name=f"{source.name} (copy)",
|
|
status="stopped",
|
|
model=source.model,
|
|
mode=source.mode,
|
|
system_prompt=source.system_prompt,
|
|
allowed_tools=list(source.allowed_tools),
|
|
max_turns=source.max_turns,
|
|
cwd=source.cwd,
|
|
created_at=datetime.now(),
|
|
messages=new_messages,
|
|
branches=new_branches,
|
|
active_branch_id=source.active_branch_id,
|
|
tool_group_meta=dict(source.tool_group_meta),
|
|
dashboard_id=dashboard_id or source.dashboard_id,
|
|
sdk_session_id=source.sdk_session_id,
|
|
needs_fork=True,
|
|
)
|
|
apply_context_window(new_session)
|
|
return new_session
|