Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
0a1b5ee
add crude keyvault base impl
nadoylemsft Sep 30, 2025
be8d0d7
upd actions for MAG
nadoylemsft Sep 30, 2025
6bb5fd0
add settings to fix
nadoylemsft Sep 30, 2025
ab28c4f
upd secret naming convention
nadoylemsft Sep 30, 2025
46945e7
upd auth types to include conn string/basic(un/pw)
nadoylemsft Oct 1, 2025
0662053
fix method name
nadoylemsft Oct 1, 2025
09f7433
add get agent helper
nadoylemsft Oct 2, 2025
e24da04
add ui trigger word and get agent helper
nadoylemsft Oct 2, 2025
e46afa2
upd function imports
nadoylemsft Oct 2, 2025
bf5e85a
upd agents call
nadoylemsft Oct 2, 2025
8aeea1a
add desc of plugins
nadoylemsft Oct 2, 2025
a4054ab
fix for admin modal loading
nadoylemsft Oct 3, 2025
5cce7bf
upd default agent handling
nadoylemsft Oct 6, 2025
5a56bdc
rmv unneeded file
nadoylemsft Oct 6, 2025
db6372e
rmv extra imp statements
nadoylemsft Oct 6, 2025
d0aff17
add new cosmos container script
nadoylemsft Oct 6, 2025
427f01d
upd instructions for consistency of code
nadoylemsft Oct 9, 2025
33ba357
adds safe calls for akv functions
nadoylemsft Oct 9, 2025
07e31c7
adds akv to personal agents
nadoylemsft Oct 9, 2025
91f3a86
fix for user agents boot issue
nadoylemsft Oct 10, 2025
2a23b84
fix global set
nadoylemsft Oct 10, 2025
570ec56
upd azure function plugin to super init
nadoylemsft Oct 10, 2025
def744b
upd to clean imports
nadoylemsft Oct 10, 2025
3b0b743
add keyvault to global actions loading
nadoylemsft Oct 10, 2025
a037caa
add plugin loading docs
nadoylemsft Oct 10, 2025
74c200c
rmv secret leak via logging
nadoylemsft Oct 10, 2025
509bc63
rmv displaying of token in logs
nadoylemsft Oct 10, 2025
0bb4a6b
fix not loading global actions for personal agents
nadoylemsft Oct 10, 2025
186a6e1
rmv unsupported characters from logging
nadoylemsft Oct 10, 2025
f11381c
fix chat links in dark mode
nadoylemsft Oct 10, 2025
b2d6613
chg order of css for links in dark mode
nadoylemsft Oct 10, 2025
967f9cb
fix chat color
nadoylemsft Oct 10, 2025
bf201f1
add default plugin print logging
nadoylemsft Oct 10, 2025
39d944e
rmv default check for nonsql plugins
nadoylemsft Oct 14, 2025
7114bac
upd requirements
nadoylemsft Oct 14, 2025
3d64e25
add keyvault and dynamic addsetting ui
nadoylemsft Oct 14, 2025
eeef42b
fix for agents/plugins with invalid akv chars
nadoylemsft Oct 15, 2025
7a0976f
add imp to appins logging
nadoylemsft Oct 15, 2025
f64702e
add security tab UI + key vault UI
nadoylemsft Oct 15, 2025
298b342
add keyvault settings
nadoylemsft Oct 15, 2025
048decf
fix for copilot findings.
nadoylemsft Oct 15, 2025
3a369b2
fix for resaving plugin without changing secret
nadoylemsft Oct 16, 2025
9cb063f
init azure billing plugin
nadoylemsft Oct 15, 2025
75a74cd
add app settings cache
nadoylemsft Oct 16, 2025
edd4a6d
upd to azure billing plugin
nadoylemsft Oct 17, 2025
8d58857
upd to msgraph plugin
nadoylemsft Oct 17, 2025
29d01b9
init community customizations
nadoylemsft Oct 24, 2025
0ba3e3e
add module
nadoylemsft Oct 24, 2025
5337b7a
add key vault config modal
nadoylemsft Oct 27, 2025
10e95c3
add logging and functions to math
nadoylemsft Nov 3, 2025
0bee627
rmv extra telemetry, add appcache
nadoylemsft Nov 4, 2025
ee80672
upd billing plugin
nadoylemsft Nov 4, 2025
c7dec1b
add/upd key vault, admin settings, agents, max tokens
nadoylemsft Nov 4, 2025
15507e1
Remove abp for pr
nadoylemsft Nov 11, 2025
841a70b
disable static logging for development
nadoylemsft Nov 11, 2025
73ac08c
rmv dup import
nadoylemsft Nov 11, 2025
825555a
add note on pass
nadoylemsft Nov 11, 2025
a4d6725
added notes
nadoylemsft Nov 11, 2025
2abfccf
rmv dup decl
nadoylemsft Nov 11, 2025
900c9f5
add semicolon
nadoylemsft Nov 11, 2025
8f37e54
rmv unused variable add agent name to log
nadoylemsft Nov 11, 2025
41c3a83
add actions migration back in
nadoylemsft Nov 11, 2025
b287aac
add notes and copilot fixes
nadoylemsft Nov 11, 2025
26b174e
add group agents/actions
nadoylemsft Nov 13, 2025
8241ae9
add branch for testing/rmv old branch
nadoylemsft Nov 13, 2025
1abd608
bug fixes, group agent modifications, rmv client validation
nadoylemsft Nov 19, 2025
4b90765
rmv ajv
nadoylemsft Nov 19, 2025
1c4dd0e
Merge branch 'Development' into feature/group-agents-actions
nadoylemsft Nov 19, 2025
993b61d
upd from copilot
nadoylemsft Nov 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions .github/workflows/docker_image_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,6 @@ jobs:
login-server: ${{ secrets.ACR_LOGIN_SERVER }}

- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install Ajv
run: npm install ajv@^8.0.0 ajv-cli@^5.0.0
- name: Install Ajv
run: npm install ajv@^8.0.0 ajv-formats
- name: Generate standalone JSON schema validators
run: node scripts/generate-validators.mjs
- name: Build the Docker image
run:
docker build . --file application/single_app/Dockerfile --tag ${{ secrets.ACR_LOGIN_SERVER }}/simple-chat:$(date +'%Y-%m-%d')_$GITHUB_RUN_NUMBER;
Expand Down
8 changes: 0 additions & 8 deletions .github/workflows/docker_image_publish_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ jobs:
login-server: ${{ secrets.ACR_LOGIN_SERVER }}

- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install Ajv
run: npm install ajv@^8.0.0 ajv-formats
- name: Generate standalone JSON schema validators
run: node scripts/generate-validators.mjs
- name: Build the Docker image
run:
docker build . --file application/single_app/Dockerfile --tag ${{ secrets.ACR_LOGIN_SERVER }}/simple-chat-dev:$(date +'%Y-%m-%d')_$GITHUB_RUN_NUMBER;
Expand Down
10 changes: 1 addition & 9 deletions .github/workflows/docker_image_publish_nadoyle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
push:
branches:
- nadoyle
- keyvaultForSecrets
- feature/group-agents-actions

workflow_dispatch:

Expand All @@ -27,14 +27,6 @@ jobs:
login-server: ${{ secrets.ACR_LOGIN_SERVER_NADOYLE }}

- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install Ajv
run: npm install ajv@^8.0.0 ajv-formats
- name: Generate standalone JSON schema validators
run: node scripts/generate-validators.mjs
- name: Build the Docker image
run:
docker build . --file application/single_app/Dockerfile --tag ${{ secrets.ACR_LOGIN_SERVER_NADOYLE }}/simple-chat-dev:$(date +'%Y-%m-%d')_$GITHUB_RUN_NUMBER;
Expand Down
4 changes: 2 additions & 2 deletions application/single_app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def configure_sessions(settings):
@app.before_first_request
def before_first_request():
print("Initializing application...")
settings = get_settings()
settings = get_settings(use_cosmos=True)
app_settings_cache.configure_app_cache(settings, get_redis_cache_infrastructure_endpoint(settings.get('redis_url', '').strip().split('.')[0]))
app_settings_cache.update_settings_cache(settings)
print(f"DEBUG:Application settings: {settings}")
Expand Down Expand Up @@ -456,7 +456,7 @@ def list_semantic_kernel_plugins():
register_route_external_health(app)

if __name__ == '__main__':
settings = get_settings()
settings = get_settings(use_cosmos=True)
app_settings_cache.configure_app_cache(settings, get_redis_cache_infrastructure_endpoint(settings.get('redis_url', '').strip().split('.')[0]))
app_settings_cache.update_settings_cache(settings)
initialize_clients(settings)
Expand Down
3 changes: 1 addition & 2 deletions application/single_app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@
EXECUTOR_TYPE = 'thread'
EXECUTOR_MAX_WORKERS = 30
SESSION_TYPE = 'filesystem'
VERSION = "0.233.153"

VERSION = "0.233.166"


SECRET_KEY = os.getenv('SECRET_KEY', 'dev-secret-key-change-in-production')
Expand Down
3 changes: 1 addition & 2 deletions application/single_app/functions_appinsights.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ def log_event(
try:
try:
cache = app_settings_cache.get_settings_cache() or None
except Exception as e:
print(f"[Log] Could not retrieve settings cache: {e}")
except Exception:
cache = None

# Get logger - use Azure Monitor logger if configured, otherwise standard logger
Expand Down
39 changes: 35 additions & 4 deletions application/single_app/functions_conversation_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def collect_conversation_metadata(user_message, conversation_id, user_id, active
document_scope=None, selected_document_id=None, model_deployment=None,
hybrid_search_enabled=False,
image_gen_enabled=False, selected_documents=None,
selected_agent=None, search_results=None, web_search_results=None,
selected_agent=None, selected_agent_details=None, search_results=None, web_search_results=None,
conversation_item=None, additional_participants=None):
"""
Collect comprehensive metadata for a conversation based on the user's interaction.
Expand All @@ -65,6 +65,7 @@ def collect_conversation_metadata(user_message, conversation_id, user_id, active
search_results: Results from hybrid search
conversation_item: Existing conversation item to update
additional_participants: List of additional user IDs to include as participants
selected_agent_details: Detailed agent metadata (is_group, group_id, group_name)

Returns:
dict: Updated conversation metadata
Expand All @@ -86,6 +87,25 @@ def collect_conversation_metadata(user_message, conversation_id, user_id, active
if 'strict' not in conversation_item:
conversation_item['strict'] = False

# Prepare agent-derived group context (used when agent is a group and no documents were used)
agent_primary_context = None
agent_primary_context_active = False
if selected_agent_details and selected_agent_details.get('is_group'):
group_id = selected_agent_details.get('group_id')
group_name = selected_agent_details.get('group_name')

if group_id:
if not group_name:
group_info = find_group_by_id(group_id)
if group_info:
group_name = group_info.get('name')
agent_primary_context = {
"type": "primary",
"scope": "group",
"id": group_id,
"name": group_name or "Unknown Group"
}

# Process documents from search results first to determine primary context
document_map = {} # Map of document_id -> {scope, chunks, classification}
workspace_used = None # Track the first workspace used (becomes primary context)
Expand Down Expand Up @@ -144,19 +164,30 @@ def collect_conversation_metadata(user_message, conversation_id, user_id, active
"id": scope_id,
"name": context_name
}
# If no documents were used, we don't set a primary context yet
# This allows us to track conversations that only use model knowledge
# If no documents were used, fall back to agent-based primary context
if not primary_context and agent_primary_context:
primary_context = agent_primary_context
agent_primary_context_active = True

# Update or add primary context only if we don't already have one
existing_primary = next((ctx for ctx in conversation_item['context'] if ctx.get('type') == 'primary'), None)
if primary_context:
if existing_primary:
# Primary context already exists - check if this is the same workspace
# Primary context already exists - determine how to handle the new context
if (existing_primary.get('scope') == primary_context.get('scope') and
existing_primary.get('id') == primary_context.get('id')):
# Same workspace - update existing primary context (e.g., refresh name)
existing_primary.update(primary_context)
debug_print(f"Updated existing primary context: {existing_primary}")
elif agent_primary_context_active:
# Promote the group agent context to become the new primary context
existing_primary.update({
"scope": primary_context.get('scope'),
"id": primary_context.get('id'),
"name": primary_context.get('name')
})
debug_print(f"Replaced existing primary context with agent group context: {existing_primary}")
primary_context = None
Comment thread
Bionic711 marked this conversation as resolved.
else:
# Different workspace - this should become a secondary context
debug_print(f"Primary context already exists ({existing_primary.get('scope')}:{existing_primary.get('id')}), "f"treating new workspace ({primary_context.get('scope')}:{primary_context.get('id')}) as secondary")
Expand Down
10 changes: 10 additions & 0 deletions application/single_app/functions_global_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ def ensure_default_global_agent_exists():
"azure_agent_apim_gpt_api_version": "",
"enable_agent_gpt_apim": False,
"is_global": True,
"is_group": False,
"agent_type": "local",
"instructions": (
"You are a highly capable research assistant. Your role is to help the user investigate academic, technical, and real-world topics by finding relevant information, summarizing key points, identifying knowledge gaps, and suggesting credible sources for further study.\n\n"
"You must always:\n- Think step-by-step and work methodically.\n- Distinguish between fact, inference, and opinion.\n- Clearly state your assumptions when making inferences.\n- Cite authoritative sources when possible (e.g., peer-reviewed journals, academic publishers, government agencies).\n- Avoid speculation unless explicitly asked for.\n- When asked to summarize, preserve the intent, nuance, and technical accuracy of the original content.\n- When generating questions, aim for depth and clarity to guide rigorous inquiry.\n- Present answers in a clear, structured format using bullet points, tables, or headings when appropriate.\n\n"
Expand Down Expand Up @@ -105,6 +107,9 @@ def get_global_agents():
for agent in agents:
if agent.get('max_completion_tokens') is None:
agent['max_completion_tokens'] = -1
agent.setdefault('is_global', True)
agent.setdefault('is_group', False)
agent.setdefault('agent_type', 'local')
return agents
except Exception as e:
log_event(
Expand Down Expand Up @@ -135,6 +140,9 @@ def get_global_agent(agent_id):
agent = keyvault_agent_get_helper(agent, agent_id, scope="global")
if agent.get('max_completion_tokens') is None:
agent['max_completion_tokens'] = -1
agent.setdefault('is_global', True)
agent.setdefault('is_group', False)
agent.setdefault('agent_type', 'local')
print(f"Found global agent: {agent_id}")
return agent
except Exception as e:
Expand Down Expand Up @@ -165,6 +173,8 @@ def save_global_agent(agent_data):
agent_data['id'] = str(uuid.uuid4())
# Add metadata
agent_data['is_global'] = True
agent_data['is_group'] = False
agent_data.setdefault('agent_type', 'local')
agent_data['created_at'] = datetime.utcnow().isoformat()
agent_data['updated_at'] = datetime.utcnow().isoformat()
log_event(
Expand Down
27 changes: 27 additions & 0 deletions application/single_app/functions_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from config import *
from functions_authentication import *
from functions_settings import *
from typing import Iterable


def create_group(name, description):
Expand Down Expand Up @@ -128,6 +129,32 @@ def get_user_role_in_group(group_doc, user_id):
return None


def require_active_group(user_id: str) -> str:
"""Return the active group id for a user or raise ValueError if missing."""
settings = get_user_settings(user_id)
active_group_id = settings.get("settings", {}).get("activeGroupOid")
if not active_group_id:
raise ValueError("No active group selected")
return active_group_id


def assert_group_role(user_id: str, group_id: str, allowed_roles: Iterable[str] = ("Owner", "Admin")) -> str:
"""Ensure the user holds one of the allowed roles for the group."""
group_doc = find_group_by_id(group_id)
if not group_doc:
raise LookupError("Group not found")

role = get_user_role_in_group(group_doc, user_id)
if not role:
raise PermissionError("User is not a member of this group")

allowed = {r.lower() for r in allowed_roles}
if role.lower() not in allowed:
raise PermissionError("Insufficient permissions for this group")

return role


def map_group_list_for_frontend(groups, current_user_id):
"""
Utility to produce a simplified list of group data
Expand Down
Loading