Summary
The canonical agents/chat input schema promotes a session_owner concept for transcripts that aren't owned by a logged-in user — agents_chat_session_owner_schema() documents it as:
Opaque, isolating owner for persisted conversation sessions. Use for anonymous browser or external-channel chats when no logged-in user owns the transcript. … such as user:<id>, browser:<opaque id>, or a channel-specific conversation key.
But the WP_Agent_Conversation_Store interface only offers a user-centric creation method:
// src/Transcripts/class-wp-agent-conversation-store.php:63
public function create_session( WP_Agent_Workspace_Scope $workspace, int $user_id, string $agent_slug = '', array $metadata = array(), string $context = 'chat' ): string;
The owner-based creation that matches session_owner exists only on the concrete CPT implementation, not in the interface:
// src/Transcripts/class-wp-agent-cpt-conversation-store.php:193
public function create_session_for_owner( WP_Agent_Workspace_Scope $workspace, array $owner, string $agent_slug = '', array $metadata = array(), string $context = 'chat' ): string;
Impact
A consumer coding against the contract (resolving the store via apply_filters( 'wp_agent_conversation_store', null ) and treating it as a WP_Agent_Conversation_Store) cannot portably create an anonymous / browser-owned session — the only interface method requires an int $user_id. To use the very session_owner vocabulary the chat schema defines, you have to either bind to the concrete WP_Agent_Cpt_Conversation_Store (defeating the interface) or fall back to user_id = 0, which conflates "guest" with "no owner."
Concretely: an anonymous public chat surface (e.g. a served site, a support widget) has no user_id, and session_owner: { type: "browser", key: "<opaque>" } is exactly the intended model — but it's unreachable through the contract.
Proposal
Promote owner-based creation to the WP_Agent_Conversation_Store interface so the contract matches the canonical session_owner vocabulary. Either:
- add
create_session_for_owner( WP_Agent_Workspace_Scope $workspace, array $owner, … ): string to the interface, or
- make
create_session accept an owner (e.g. int|array $user_or_owner, or an optional ?array $owner that supersedes $user_id).
The CPT store already implements it; this is mostly about lifting it into the contract (+ a default/adapter for stores that only know user_id).
Secondary observation
The agents/chat dispatcher (src/Channels/register-agents-chat-ability.php) doesn't write to the registered conversation store — persistence is entirely consumer-wired. That may be intentional (consumers own materialization policy), but it's worth a doc note, since both the store and the canonical session_owner shape exist and a newcomer reasonably expects the chat path to use them.
Context
Surfaced while building an example consumer (an "agent-served site" on agents-api + wp-ai-client): https://github.com/lezama/agent-served-site — its Session_Store resolves the store via the filter and uses create_session/get_session/update_session, and had to settle for user_id instead of a browser owner for anonymous visitors. Related: #324 (per-agent register_chat_handler routing).
🤖 Generated with Claude Code
Summary
The canonical
agents/chatinput schema promotes asession_ownerconcept for transcripts that aren't owned by a logged-in user —agents_chat_session_owner_schema()documents it as:But the
WP_Agent_Conversation_Storeinterface only offers a user-centric creation method:The owner-based creation that matches
session_ownerexists only on the concrete CPT implementation, not in the interface:Impact
A consumer coding against the contract (resolving the store via
apply_filters( 'wp_agent_conversation_store', null )and treating it as aWP_Agent_Conversation_Store) cannot portably create an anonymous / browser-owned session — the only interface method requires anint $user_id. To use the verysession_ownervocabulary the chat schema defines, you have to either bind to the concreteWP_Agent_Cpt_Conversation_Store(defeating the interface) or fall back touser_id = 0, which conflates "guest" with "no owner."Concretely: an anonymous public chat surface (e.g. a served site, a support widget) has no
user_id, andsession_owner: { type: "browser", key: "<opaque>" }is exactly the intended model — but it's unreachable through the contract.Proposal
Promote owner-based creation to the
WP_Agent_Conversation_Storeinterface so the contract matches the canonicalsession_ownervocabulary. Either:create_session_for_owner( WP_Agent_Workspace_Scope $workspace, array $owner, … ): stringto the interface, orcreate_sessionaccept an owner (e.g.int|array $user_or_owner, or an optional?array $ownerthat supersedes$user_id).The CPT store already implements it; this is mostly about lifting it into the contract (+ a default/adapter for stores that only know
user_id).Secondary observation
The
agents/chatdispatcher (src/Channels/register-agents-chat-ability.php) doesn't write to the registered conversation store — persistence is entirely consumer-wired. That may be intentional (consumers own materialization policy), but it's worth a doc note, since both the store and the canonicalsession_ownershape exist and a newcomer reasonably expects the chat path to use them.Context
Surfaced while building an example consumer (an "agent-served site" on agents-api + wp-ai-client): https://github.com/lezama/agent-served-site — its
Session_Storeresolves the store via the filter and usescreate_session/get_session/update_session, and had to settle foruser_idinstead of a browser owner for anonymous visitors. Related: #324 (per-agentregister_chat_handlerrouting).🤖 Generated with Claude Code