Summary
GET /datamachine/v1/agents has two bugs in the non-admin code path that block multi-agent frontend chat.
Related: #993 (DB primitives), #972 (per-user toolsets)
Bug 1: Non-admin path omits agents the user OWNS
File: inc/Api/Agents.php lines 312-358
The non-admin branch only queries AgentAccess::get_agent_ids_for_user():
} else {
$access_repo = new AgentAccess();
$accessible_ids = $access_repo->get_agent_ids_for_user($user_id);
// ...loops through IDs...
}
If an owner's access grant is missing from agent_access (race condition, migration gap, manual DB edit), they won't see their own agent. The owner's relationship lives on datamachine_agents.owner_id, not in agent_access.
Fix
Merge owned agents with access-granted agents:
} else {
$access_repo = new AgentAccess();
$accessible_ids = $access_repo->get_agent_ids_for_user($user_id);
$owned_agents = $agents_repo->get_all_by_owner_id($user_id); // from #993
$owned_ids = array_column($owned_agents, 'agent_id');
$all_ids = array_unique(array_merge(array_map('intval', $owned_ids), $accessible_ids));
$all_agents = $agents_repo->get_agents_by_ids($all_ids); // from #993
// ...site_scope filter...
}
Bug 2: N+1 query pattern
The non-admin path calls get_agent_ids_for_user() (1 query), then get_agent() in a loop (N queries). For a user with access to 20 agents, that's 21 queries.
Fix
Use get_agents_by_ids() (batch method from #993) for a single query.
Enhancement: Add user_role to list response
shape_list_item() returns agent metadata but not the requesting user's role (viewer/operator/admin). The frontend needs this for UI decisions (show edit button, show config, etc.).
Needed
Enrich the response with the user's role from agent_access:
private static function shape_list_item(array $agent, ?string $user_role = null): array {
$item = [
'agent_id' => (int) $agent['agent_id'],
'agent_slug' => (string) $agent['agent_slug'],
'agent_name' => (string) $agent['agent_name'],
'owner_id' => (int) $agent['owner_id'],
'site_scope' => isset($agent['site_scope']) ? (int) $agent['site_scope'] : null,
'status' => (string) $agent['status'],
'created_at' => $agent['created_at'] ?? '',
'updated_at' => $agent['updated_at'] ?? '',
];
if ($user_role !== null) {
$item['user_role'] = $user_role;
}
return $item;
}
Checklist
Summary
GET /datamachine/v1/agentshas two bugs in the non-admin code path that block multi-agent frontend chat.Related: #993 (DB primitives), #972 (per-user toolsets)
Bug 1: Non-admin path omits agents the user OWNS
File:
inc/Api/Agents.phplines 312-358The non-admin branch only queries
AgentAccess::get_agent_ids_for_user():If an owner's access grant is missing from
agent_access(race condition, migration gap, manual DB edit), they won't see their own agent. The owner's relationship lives ondatamachine_agents.owner_id, not inagent_access.Fix
Merge owned agents with access-granted agents:
Bug 2: N+1 query pattern
The non-admin path calls
get_agent_ids_for_user()(1 query), thenget_agent()in a loop (N queries). For a user with access to 20 agents, that's 21 queries.Fix
Use
get_agents_by_ids()(batch method from #993) for a single query.Enhancement: Add
user_roleto list responseshape_list_item()returns agent metadata but not the requesting user's role (viewer/operator/admin). The frontend needs this for UI decisions (show edit button, show config, etc.).Needed
Enrich the response with the user's role from
agent_access:Checklist
handle_list()pathget_agent()loop with batchget_agents_by_ids()user_roleto list response shape