# 2367 Group Agent Loading Fix B0f74e16

> Group Agent Loading Fix

- Skill: `tools-only/2367-group-agent-loading-fix-b0f74e16` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/2367-group-agent-loading-fix-b0f74e16`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/2367-group-agent-loading-fix-b0f74e16/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-22
- Page: https://skillmd.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.
