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:
- ✅ Load personal agents via
get_personal_agents(user_id) - ✅ Conditionally merge global agents if
merge_global_semantic_kernel_with_workspaceenabled - ❌ MISSING: Load group agents from user's active group
- ✅ Load personal actions via
get_personal_actions(user_id) - ✅ 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
semantic_kernel_loader.py(Lines ~1180-1280)- Changed import from
get_user_groupstorequire_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
- Changed import from
config.py- Updated VERSION to "0.237.008"
Code Changes
Before (Pseudocode)
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)
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:
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:
# 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 (fromfunctions_group.py)get_group_agents(group_id)- Returns all agents for a specific group (fromfunctions_group_agents.py)get_group_agent(group_id, agent_identifier)- Returns a specific agent from a group by ID or name (fromfunctions_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
Setup:
- User
f016493e-9395-4120-91b5-bac4276b6b6chas active groupcio6(ID:72254e24-4bc6-4680-bc2e-c56d5214d8e8) - Group has agent
cio6_servicenow_test_agentwith actioncio6_servicenow_query_incidents - Per-user semantic kernel mode enabled
- Global agent merging enabled
- User
User Action:
- User selects group agent
cio6_servicenow_test_agent - User submits message: "Show me all ServiceNow incidents"
- User selects group agent
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
- Personal agents still load correctly
- Global agents still merge correctly when enabled
- Group agents load from active group when one is selected
- No errors when user has no active group selected
- Agents properly marked with
is_groupandgroup_idflags - Agent selection finds group agents by name
- Security validation prevents users from accessing agents outside their active group
- Error handling prevents crashes if group loading fails
- 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:
- Logs an error with details about the mismatch
- Loads only core plugins (no sensitive group-specific plugins)
- Returns None for the agent, preventing unauthorized access
This security layer ensures that group agent access is strictly controlled through the active group mechanism.