Structure webber into three independent subprojects: - webber-api/: FastAPI backend server with all agent code - webber-cli/: Standalone CLI client (renamed from cli/ to webber_cli/) - webber-sandbox/: Test project for functional testing Key changes: - Each subproject has its own .venv (Python 3.12+) - Added sandbox.sh for managing test project templates - Created sandbox-templates/ with calculator-cli and empty starter - Updated CI/CD for prefixed tags (api/v*, cli/v*) - Added comprehensive AGENTS.md with operational instructions - Added gitignore filtering to glob and grep tools - Created pyproject.toml for each subproject Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
61 lines
1.7 KiB
Python
61 lines
1.7 KiB
Python
"""
|
|
Session state management.
|
|
"""
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime
|
|
from typing import Literal
|
|
|
|
|
|
@dataclass
|
|
class Message:
|
|
"""Single message in conversation history."""
|
|
role: Literal["user", "assistant", "system"]
|
|
content: str
|
|
timestamp: datetime = field(default_factory=datetime.now)
|
|
|
|
def __str__(self) -> str:
|
|
return f"[{self.role}] {self.content[:50]}..."
|
|
|
|
|
|
@dataclass
|
|
class SessionState:
|
|
"""
|
|
Persistent state for a CLI session.
|
|
|
|
Tracks conversation history and context.
|
|
"""
|
|
working_dir: str
|
|
messages: list[Message] = field(default_factory=list)
|
|
started_at: datetime = field(default_factory=datetime.now)
|
|
|
|
# Token tracking (for future context management)
|
|
estimated_tokens: int = 0
|
|
max_tokens: int = 128000
|
|
|
|
def add_message(self, role: Literal["user", "assistant", "system"], content: str) -> None:
|
|
"""Add a message to history."""
|
|
self.messages.append(Message(role=role, content=content))
|
|
# Rough token estimate (4 chars per token)
|
|
self.estimated_tokens += len(content) // 4
|
|
|
|
def get_history(self, limit: int | None = None) -> list[Message]:
|
|
"""Get recent message history."""
|
|
if limit:
|
|
return self.messages[-limit:]
|
|
return self.messages
|
|
|
|
def clear_history(self) -> None:
|
|
"""Clear message history."""
|
|
self.messages.clear()
|
|
self.estimated_tokens = 0
|
|
|
|
@property
|
|
def message_count(self) -> int:
|
|
"""Number of messages in history."""
|
|
return len(self.messages)
|
|
|
|
@property
|
|
def is_near_limit(self) -> bool:
|
|
"""Check if approaching token limit."""
|
|
return self.estimated_tokens > (self.max_tokens * 0.8)
|