"""Message commands: list, get.""" from __future__ import annotations import hashlib from typing import Optional import typer from honcho_cli.commands.workspace import _handle_error from honcho_cli.output import print_result, status from honcho_cli.validation import validate_resource_id from honcho_cli.common import add_common_options app = typer.Typer(help="Message operations.") add_common_options(app) @app.command("list") def list_messages( session_id: Optional[str] = typer.Argument(None, help="Session ID (uses default if omitted)"), last: int = typer.Option(20, "--last", help="Number of recent messages"), reverse: bool = typer.Option(False, "--reverse", help="Reverse order"), brief: bool = typer.Option(False, "--brief", help="Show only IDs, peer, token count, and created_at (no content)"), workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Override workspace ID"), session: Optional[str] = typer.Option(None, "--session", "-s", help="Override session ID"), json_output: bool = typer.Option(False, "--json", help="Force JSON output"), ) -> None: """List messages in a session.""" from honcho_cli.commands.session import _get_session_id from honcho_cli.common import handle_cmd_flags from honcho_cli.main import get_client handle_cmd_flags(json_output=json_output, workspace=workspace, session=session) sid = _get_session_id(session_id) client, config = get_client() sess = client.session(sid) try: msgs = list(sess.messages()) if not reverse: msgs = msgs[-last:] else: msgs = msgs[:last] # Detect duplicate content content_hashes: dict[str, list[str]] = {} for m in msgs: h = hashlib.md5(m.content.encode()).hexdigest() content_hashes.setdefault(h, []).append(m.id) dupes = {h: ids for h, ids in content_hashes.items() if len(ids) > 1} if dupes: dupe_count = sum(len(ids) - 1 for ids in dupes.values()) status(f"Warning: {dupe_count} duplicate message(s) detected (identical content, different IDs)") if brief: items = [ { "id": m.id, "peer_id": m.peer_id, "token_count": m.token_count, "created_at": str(m.created_at), } for m in msgs ] print_result(items, columns=["id", "peer_id", "token_count", "created_at"], title="Messages") else: items = [ { "id": m.id, "peer_id": m.peer_id, "content": m.content, "token_count": m.token_count, "metadata": m.metadata, "created_at": str(m.created_at), } for m in msgs ] print_result(items, columns=["id", "peer_id", "content", "created_at"], title="Messages") except Exception as e: _handle_error(e, "message", "list") @app.command("get") def get_message( message_id: str = typer.Argument(help="Message ID"), session_id: Optional[str] = typer.Option(None, "--session", "-s", help="Session ID"), workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Override workspace ID"), json_output: bool = typer.Option(False, "--json", help="Force JSON output"), ) -> None: """Get a single message by ID.""" from honcho_cli.commands.session import _get_session_id from honcho_cli.common import handle_cmd_flags from honcho_cli.main import get_client handle_cmd_flags(json_output=json_output, workspace=workspace) validate_resource_id(message_id, "message") sid = _get_session_id(session_id) client, config = get_client() try: # Use raw HTTP to get a single message sess = client.session(sid) msgs = list(sess.messages()) msg = next((m for m in msgs if m.id == message_id), None) if msg is None: from honcho_cli.output import print_error print_error("MESSAGE_NOT_FOUND", f"Message '{message_id}' not found in session '{sid}'", {"message_id": message_id, "session_id": sid}) raise typer.Exit(1) print_result({ "id": msg.id, "peer_id": msg.peer_id, "content": msg.content, "token_count": msg.token_count, "metadata": msg.metadata, "created_at": str(msg.created_at), }) except SystemExit: raise except Exception as e: _handle_error(e, "message", message_id)