feat(channels): REST adapter for agents/list-conversation-sessions - #559
Merged
Merged
Conversation
Adds a generic sessions REST route symmetric to the chat adapter, so a client that needs to scope session lists no longer has to depend on a specific chat client's route and filter for this half of the surface. - GET /agents-api/v1/sessions dispatches the canonical agents/list-conversation-sessions ability. - apply_filters( 'agents_frontend_chat_rest_session_list_input', $input, $request ) lets hosts scope by workspace, agent, context, or session owner once, against the substrate. Named for symmetry with agents_frontend_chat_rest_input. - A non-array filter return is rejected as a 400 WP_Error, never a fatal, matching the chat adapter's contract. Input is cached per-request via SplObjectStorage. - The permission callback defers entirely to the canonical agents_conversation_sessions_permission() decision; the transport-level agents_frontend_chat_rest_session_list_permission filter can only narrow that decision (AND), never widen it, so the route adapts authorization instead of expanding it. - REST args are derived from the ability's own list input schema so the route's contract cannot drift from the ability it adapts. - Wired into agents-api.php bootstrap alongside the existing chat REST route; new smoke test added to composer.json's smoke script. Closes #558
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #558
What
Adds a generic sessions REST adapter symmetric to the existing chat adapter:
GET /agents-api/v1/sessionsdispatches the canonicalagents/list-conversation-sessionsability (src/Transcripts/register-agents-conversation-session-abilities.php).apply_filters( 'agents_frontend_chat_rest_session_list_input', $input, $request )— a host can now scope session lists (by workspace, agent, context, or session owner) once, against the substrate, instead of shipping a client-specific route and filter for this half of the surface.400 WP_Error, never a fatal. Input is cached per-request viaSplObjectStorage, mirroringagents_frontend_chat_rest_input.agents_conversation_sessions_permission()decision (current-user capability or resolved session owner). A transport-levelagents_frontend_chat_rest_session_list_permissionfilter can only narrow that decision ($allowed && (bool) apply_filters(...)), never widen it — the route adapts authorization, it does not expand it.agents_conversation_sessions_list_input_schema(), so the route's argument contract cannot drift from the ability it adapts.agents-api.phpbootstrap right after the existing chat REST route.Why this asymmetry mattered
agents/list-conversation-sessionsalready existed as an ability, but the only registered REST routes were/chatand the JSON-RPC chat route. A client that wanted a session list had to ship its own route and its own filter —Automattic/frontend-agent-chatdoes exactly that withfrontend_agent_chat_session_list_input, andAutomattic/intelligencedepends on that client-specific filter today for wiki-brain session scoping (Automattic/intelligence#1066). That breaks the moment a different client is used: a consumer that needs both chat and session scoping ends up depending on a client for one and the substrate for the other. This closes that gap so the dependency points one way, at the substrate.Filter name decision
Kept
agents_frontend_chat_rest_session_list_input— symmetric withagents_frontend_chat_rest_input(sameagents_frontend_chat_rest_*prefix family as the existing REST adapter's permission filter) rather than inventing a new prefix. Same reasoning foragents_frontend_chat_rest_session_list_permission, added alongside it as the narrowing-only transport permission seam, matchingagents_frontend_chat_rest_permissionon the chat route.Design notes
workspaceobject (workspace_type+workspace_id), but also has a flat-params fallback inagents_conversation_sessions_workspace(). The REST route exposes flatworkspace_type/workspace_idquery args (simpler for GET) and assembles the nestedworkspaceobject internally — filter authors can still override with a fullworkspaceobject since the ability checksisset( $input['workspace'] )first.session_owneris exposed as a REST arg mirroring the ability's own owner schema. It is safe to expose because the ability binds any asserted owner to the authenticated principal's own owner and fails closed on mismatch (agents_conversation_session_owner_from_input()) — the route does not widen what a caller can address.agents_frontend_chat_rest_schema_property()helper from the chat route file (sameAgentsAPI\AI\Channelsnamespace) rather than duplicating it.agents_conversation_sessions_int_value()from the ability's own file forlimit/offsetcoercion instead of a raw(int)cast on amixedREST param (PHPStan correctly flagged the raw cast; this is also the same coercion the ability applies internally).Validation
Ran the repo's actual CI commands (
.github/workflows/ci.ymlrunscomposer phpstanandcomposer smoke):Exit code 0 for the full
composer testrun (every one of the ~140 smoke files in thesmokescript, including the new one). No@phpstan-ignorecomments, no baseline entries, no type casts added to silence anything — the one PHPStan finding during development (cast.inton(int) $mixed) was fixed by reusing the ability's own coercion helper, not suppressed.AI-generated by Extra Chill Bot (Claude Sonnet) via Kimaki minion; reviewed by nobody yet.