**Fix Title:** Group Agents Not Loading in Per-User Semantic Kernel Mode
**Issue Description:** Group agents were not being loaded when per-user semantic kernel mode was enabled, causing group agents to fall back to global agents and resulting in zero plugins/actions available.
**Root Cause:** The `load_user_semantic_kernel()` function only loaded personal agents and global agents (when merge enabled), but completely omitted group agents from the user's active group.
**Fixed/Implemented in
Installs into .claude/skills of the current project.
Are you the author of 2367 Group Agent Loading Fix B0f74e16?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tools-only-2367-group-agent-loading-fix-b0f74e16)
# Group Agent Loading Fix
## Header Information
**Fix Title:** Group Agents Not Loading in Per-User Semantic Kernel Mode
**Issue Description:** Group agents were not being loaded when per-user semantic kernel mode was enabled, causing group agents to fall back to global agents and resulting in zero plugins/actions available.
**Root Cause:** The `load_user_semantic_kernel()` function only loaded personal agents and global agents (when merge enabled), but completely omitted group agents from the user's active group.
**Fixed/Implemented in version:** **0.237.008** (matches `config.py` `app.config['VERSION']`)
**Date:** January 31, 2026
## Problem Statement
### Symptoms
When a user selected a group agent in per-user semantic kernel mode:
- The agent selection would fall back to the global "researcher" agent
- Plugin count would be zero (`plugin_count: 0, plugins: []`)
- Agent would ask clarifying questions instead of executing available actions
- No group agents appeared in the available agents list
- Group actions (plugins) were not accessible even though they existed in the database
### Impact
- **Severity:** High - Group agents completely non-functional in per-user kernel mode
- **Affected Users:** All users with per-user semantic kernel enabled who are members of groups
- **Workaround:** None - only global agents worked
### Evidence from Logs
```
[SK Loader] User settings found 1 agents for user 'f016493e-9395-4120-91b5-bac4276b6b6c'
[SK Loader] Found 2 global agents to merge
[SK Loader] After merging: 3 total agents
[DEBUG] [INFO]: [SK Loader] Merged agents: [('researcher', True), ('servicenow_test_agent', True), ('researcher', False)]
[DEBUG] [INFO]: [SK Loader] Looking for agent named 'cio6_servicenow_test_agent' with is_global=False
[DEBUG] [INFO]: [SK Loader] User NO agent found matching user-selected agent: cio6_servicenow_test_agent
[SK Loader] User f016493e-9395-4120-91b5-bac4276b6b6c No agent found matching user-selected agent: cio6_servicenow_test_agent
```
Notice: Only 3 agents loaded (2 global + 1 personal), **zero group agents** despite user being member of group "cio6".
## Root Cause Analysis
### Architectural Gap
The `load_user_semantic_kernel()` function in `semantic_kernel_loader.py` had the following loading sequence:
1. ✅ Load personal agents via `get_personal_agents(user_id)`
2. ✅ Conditionally merge global agents if `merge_global_semantic_kernel_with_workspace` enabled
3. ❌ **MISSING:** Load group agents from user's active group
4. ✅ Load personal actions via `get_personal_actions(user_id)`
5. ✅ Conditionally merge global actions if merge enabled
### Why It Was Missed
The code did not load group agents from the user's active group in per-user semantic kernel mode. This meant:
- Group agents were never available for selection
- Users in groups could not use group-level agent configurations
- The system would fall back to global or personal agents even when a group agent was requested
**Note:** Group actions (plugins) are loaded separately by the agent itself based on the selected agent's configuration, not in the `load_user_semantic_kernel()` function. This fix specifically addresses group agent loading.
## Technical Details
### Files Modified
1. **`semantic_kernel_loader.py`** (Lines ~1180-1280)
- Changed import from `get_user_groups` to `require_active_group`
- Added group agent loading from active group only
- Added security validation to ensure selected group agents match the user's active group
- Simplified error handling for cases where no active group is selected
2. **`config.py`**
- Updated VERSION to "0.237.008"
### Code Changes
#### Before (Pseudocode)
```python
agents_cfg = get_personal_agents(user_id)
# Mark personal agents
for agent in agents_cfg:
agent['is_global'] = False
# No group agent loading at all
# Merge global agents if enabled
if merge_global:
# Add global agents
# Load personal actions only
plugin_manifests = get_personal_actions(user_id)
# No group action loading at all
```
#### After (Pseudocode)
```python
agents_cfg = get_personal_agents(user_id)
# Mark personal agents
for agent in agents_cfg:
agent['is_global'] = False
# Load group agents from active group only
try:
active_group_id = require_active_group(user_id)
group_agents = get_group_agents(active_group_id)
for group_agent in group_agents:
group_agent['is_global'] = False
group_agent['is_group'] = True
group_agent['group_id'] = active_group_id
agents_cfg.append(group_agent)
except ValueError:
# No active group - normal case
pass
# Security check: If a group agent is selected, validate it matches active group
if selected_agent_is_group:
resolved_group_id = selected_agent_data.get('group_id')
active_group_id = require_active_group(user_id)
if resolved_group_id != active_group_id:
# Reject - security violation
load_core_plugins_only(kernel, settings)
return kernel, None
# Merge global agents if enabled (unchanged)
if merge_global:
# Add global agents
# Load personal actions
plugin_manifests = get_personal_actions(user_id)
```
### Key Implementation Details
**Group Agent Loading:**
```python
from functions_group import require_active_group
from functions_group_agents import get_group_agents
# Load group agents for user's active group (if any)
try:
active_group_id = require_active_group(user_id)
group_agents = get_group_agents(active_group_id)
if group_agents:
print(f"[SK Loader] Found {len(group_agents)} group agents for active group '{active_group_id}'")
# Badge group agents with group metadata
for group_agent in group_agents:
group_agent['is_global'] = False
group_agent['is_group'] = True
agents_cfg.extend(group_agents)
print(f"[SK Loader] After merging group agents: {len(agents_cfg)} total agents")
else:
print(f"[SK Loader] No group agents found for active group '{active_group_id}'")
except ValueError:
# No active group set - this is fine, just means no group agents available
print(f"[SK Loader] User '{user_id}' has no active group - skipping group agent loading")
```
**Security Validation for Selected Group Agents:**
```python
# Append selected group agent (if any) to the candidate list so downstream selection logic can resolve it
selected_agent_data = selected_agent if isinstance(selected_agent, dict) else {}
selected_agent_is_group = selected_agent_data.get('is_group', False)
if selected_agent_is_group:
resolved_group_id = selected_agent_data.get('group_id')
active_group_id = None
# Group agent MUST have a group_id
if not resolved_group_id:
log_event(
"[SK Loader] Group agent selected but no group_id provided in selection data.",
level=logging.ERROR
)
load_core_plugins_only(kernel, settings)
return kernel, None
try:
active_group_id = require_active_group(user_id)
if resolved_group_id != active_group_id:
debug_print(
f"[SK Loader] Selected group agent references group {resolved_group_id}, active group is {active_group_id}."
)
log_event(
"[SK Loader] Group agent selected from the non-active group.",
level=logging.ERROR
)
load_core_plugins_only(kernel, settings)
return kernel, None
except ValueError as err:
debug_print(f"[SK Loader] No active group available while loading group agent: {err}")
log_event(
"[SK Loader] Group agent selected but no active group in settings.",
level=logging.ERROR
)
load_core_plugins_only(kernel, settings)
return kernel, None
```
### Functions Used
- **`require_active_group(user_id)`** - Returns the active group ID or raises ValueError if none selected (from `functions_group.py`)
- **`get_group_agents(group_id)`** - Returns all agents for a specific group (from `functions_group_agents.py`)
- **`get_group_agent(group_id, agent_identifier)`** - Returns a specific agent from a group by ID or name (from `functions_group_agents.py`)
### Error Handling and Security
- Group agent loading wrapped in try-except with ValueError handling for no active group (normal case)
- Security validation ensures selected group agents match the user's active group
- If a user attempts to select a group agent from a non-active group, the system loads core plugins only and returns None
- All errors logged with descriptive messages for debugging
- System gracefully degrades to personal + global agents if group loading fails
## Validation
### Test Scenario
1. **Setup:**
- User `f016493e-9395-4120-91b5-bac4276b6b6c` has active group `cio6` (ID: `72254e24-4bc6-4680-bc2e-c56d5214d8e8`)
- Group has agent `cio6_servicenow_test_agent` with action `cio6_servicenow_query_incidents`
- Per-user semantic kernel mode enabled
- Global agent merging enabled
2. **User Action:**
- User selects group agent `cio6_servicenow_test_agent`
- User submits message: "Show me all ServiceNow incidents"
### Before Fix - Failure Behavior
```
[SK Loader] User settings found 1 agents for user 'f016493e-9395-4120-91b5-bac4276b6b6c'
[SK Loader] After merging: 3 total agents # Only personal + global
[SK Loader] Looking for agent named 'cio6_servicenow_test_agent' with is_global=False
[SK Loader] User NO agent found matching user-selected agent: cio6_servicenow_test_agent
[SK Loader] selected_agent fallback to first agent: researcher # ❌ Wrong agent
[Enhanced Agent Citations] Extracted 0 detailed plugin invocations # ❌ No actions
{'agent': 'researcher', 'plugin_count': 0} # ❌ Zero plugins
```
**Result:** Agent asks clarifying questions instead of querying ServiceNow.
### After Fix - Success Behavior
```
[SK Loader] User settings found 1 agents for user 'f016493e-9395-4120-91b5-bac4276b6b6c'
[SK Loader] Found 1 group agents for active group '72254e24-4bc6-4680-bc2e-c56d5214d8e8' # ✅ Group agent loaded
[SK Loader] After merging group agents: 2 total agents # ✅ Personal + Group
[SK Loader] After merging: 4 total agents # ✅ Includes global agents
[SK Loader] Merged agents: [('researcher', True), ('servicenow_test_agent', True), ('researcher', False), ('cio6_servicenow_test_agent', False)] # ✅ Group agent present
[SK Loader] User f016493e-9395-4120-91b5-bac4276b6b6c Found EXACT match for agent: cio6_servicenow_test_agent (is_global=False) # ✅ Agent found
[SK Loader] Plugin cio6_servicenow_query_incidents: SUCCESS # ✅ Plugin loaded
```
**Result:** Correct group agent selected with its actions available for execution.
### Verification Checklist
- [x] Personal agents still load correctly
- [x] Global agents still merge correctly when enabled
- [x] Group agents load from active group when one is selected
- [x] No errors when user has no active group selected
- [x] Agents properly marked with `is_group` and `group_id` flags
- [x] Agent selection finds group agents by name
- [x] Security validation prevents users from accessing agents outside their active group
- [x] Error handling prevents crashes if group loading fails
- [x] Logging provides visibility into group loading process
## Security Enhancement
This fix includes a critical security validation that was added as part of the implementation:
**Security Check:** When a user selects a group agent, the system now validates that the agent's `group_id` matches the user's currently active group. This prevents users from potentially accessing group agents from groups they are members of but have not set as active, ensuring proper access control.
**Implementation:** If a mismatch is detected between the selected agent's group and the user's active group, the system:
1. Logs an error with details about the mismatch
2. Loads only core plugins (no sensitive group-specific plugins)
3. Returns None for the agent, preventing unauthorized access
This security layer ensures that group agent access is strictly controlled through the active group mechanism.