Skip to content

feat: add canonical conversation session read-state ability #448

Description

@chubes4

Problem

Generic conversation-session clients can create, list, get, title, and delete principal-owned sessions through agents/* abilities, but cannot persist read state. The canonical session row exposes last_read_at, while WP_Agent_Conversation_Store explicitly excludes read-state mutation and no canonical ability owns it.

This leaves frontend adapters with two bad options: call a product-specific ability/store directly, violating layer purity, or return a successful mark-read response without persisting anything.

Evidence

  • src/Transcripts/register-agents-conversation-session-abilities.php registers list/get/create/update-title/delete only.
  • src/Transcripts/class-wp-agent-conversation-store.php documents last_read_at in the canonical row but says read-state is outside the transcript store contract.
  • The built-in CPT store persists _agents_api_last_read_at but exposes no generic mutation path.
  • fix: preserve workspace across chat session lifecycle frontend-agent-chat#123 needs workspace- and principal-scoped read-state behavior across the same lifecycle as the existing session abilities.

Required contract

  • Add an optional generic read-state capability for stores that own it, rather than forcing it into every transcript store.
  • Add a canonical ability such as agents/mark-conversation-session-read scoped by the existing workspace and resolved principal/session owner semantics.
  • Verify ownership and workspace exactly as get/update-title/delete do.
  • Return a truthful result including whether state was persisted and the canonical last_read_at; unsupported stores must fail explicitly rather than report success.
  • Keep storage and UI policy out of the substrate.

Tests

  • Create sessions with the same owner in two workspaces and prove marking one read cannot mutate or resolve the other workspace's session.
  • Cover user and non-user principal owners through a principal-aware store.
  • Cover unsupported stores with an explicit error.
  • Confirm a subsequent get/list reflects the updated last_read_at and unread projection when the store supplies one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions