-
Notifications
You must be signed in to change notification settings - Fork 5
refactor: datamachine/list-agents — scope-aware defaults, per-user access resolution #996
Description
Summary
Refactor the existing datamachine/list-agents ability from admin-only to scope-aware with smart defaults. One primitive that serves all callers — no need for a separate list-accessible-agents ability.
Replaces: #995 (closed)
Related: #993 (batch DB methods), #994 (REST endpoint fixes), #972 (per-user toolsets)
Blocked by: #993 (get_all_by_owner_id(), get_agents_by_ids())
Current Behavior
// datamachine/list-agents — admin-only, returns everything
// Permission: PermissionHelper::can_manage()
// Returns: all agents scoped to current site + network-wideThe REST endpoint GET /datamachine/v1/agents bypasses this ability entirely and does its own access-scoped DB queries for non-admin users. Business logic is split between two places.
Proposed Behavior
Default (no params) = list agents the calling user can access. Admin can escalate.
Parameters
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
scope |
string | no | 'mine' |
'mine' = user's accessible agents. 'all' = all agents on site (admin-only). |
user_id |
int | no | acting user | Whose accessible agents to list. Admin can query for any user. Non-admin forced to self. |
site_id |
int | no | current blog | Filter by site_scope (matches exact + NULL/network-wide) |
status |
string | no | 'active' |
Filter by agent status. 'any' to skip. |
include_role |
bool | no | false |
Include the user's access role per agent in response |
Permission Model
| Caller | scope |
user_id |
Result |
|---|---|---|---|
Any user with can('chat') |
mine (default) |
self (default) | Agents they own + have grants to |
| Admin | mine (default) |
self (default) | Same — their own accessible agents |
| Admin | all |
— | All agents on site (current behavior) |
| Admin | mine |
other user's ID | That user's accessible agents |
| Non-admin | all |
— | Permission denied |
| Non-admin | mine |
other user's ID | Permission denied (forced to self) |
Base permission: can('chat') (down from can_manage())
Escalation: scope=all or user_id != self requires can_manage()
Resolution Logic (scope=mine)
// 1. Agents the user OWNS
$owned = $agents_repo->get_all_by_owner_id($user_id);
// 2. Agents the user has ACCESS GRANTS to
$granted_ids = $access_repo->get_agent_ids_for_user($user_id);
$extra_ids = array_diff($granted_ids, array_column($owned, 'agent_id'));
$granted = $agents_repo->get_agents_by_ids($extra_ids);
// 3. Merge + dedupe
$all = array_merge($owned, $granted);
// 4. Filter by site_scope (match exact site OR network-wide NULL)
// 5. Filter by status
// 6. Final gate: PermissionHelper::can_access_agent() per agent
// 7. Shape responseResolution Logic (scope=all)
// Current behavior, unchanged
$all = $agents_repo->get_all(['site_id' => $site_id]);
// Filter by status
// Shape responseReturn Shape
[
'success' => true,
'agents' => [
[
'agent_id' => 5,
'agent_slug' => 'roadie',
'agent_name' => 'Roadie',
'owner_id' => 1,
'site_scope' => null,
'status' => 'active',
'description' => 'Your AI assistant.', // from agent_config.description
'is_owner' => true, // whether acting user owns this agent
'user_role' => 'admin', // only when include_role=true
],
],
]What Changes After This Ships
- REST
GET /agentsrefactored to call this ability — no more inline DB queries in the controller - Frontend chat plugin calls
wp_get_ability('datamachine/list-agents')->execute()with no params — gets the user's accessible agents automatically - CLI gets natural behavior:
wp datamachine agents list= your agents,wp datamachine agents list --scope=all= all (admin) - Chat tools can list a user's agents through the same primitive
- Agent-to-agent workflows can query accessible agents for any user (admin context)
CLI Mapping
# Default: my accessible agents
wp datamachine agents list
# Admin: all agents on site
wp datamachine agents list --scope=all
# Admin: another user's agents
wp datamachine agents list --user_id=5
# With role info
wp datamachine agents list --include_roleBackward Compatibility
The ability currently returns all agents for admins. After this change:
- Admin calling with no params gets their own accessible agents (behavior change)
- Admin calling with
--scope=allgets the old behavior - Any existing code that calls the ability is admin-only code (non-admins couldn't use it before), so the admin caller just needs to add
scope=allif they want the old behavior - REST endpoint refactored at the same time, so the transition is atomic
Checklist
- Lower base permission from
can_manage()tocan('chat') - Add
scopeparameter (default'mine') - Add
user_idparameter (default acting user, admin-only escalation) - Add
site_id,status,include_roleparameters - Implement
scope=mineresolution: owned + access-granted, merged, deduped, filtered - Keep
scope=allas current behavior (admin-only gate) - Extract
descriptionfromagent_configJSON - Add
is_ownerboolean to response shape - Optional
user_roleenrichment from access table - Refactor
Api/Agents.php::handle_list()to delegate to this ability - Update CLI
agents listcommand for new params - Uses
get_all_by_owner_id()+get_agents_by_ids()from feat: Multi-agent database primitives — batch queries + session agent info #993