added URL property to agents (link to agent) and fixed redirect base paths
This commit is contained in:
parent
cebc1cf649
commit
d160b1bc90
5 changed files with 53 additions and 23 deletions
11
config.py
11
config.py
|
|
@ -13,7 +13,16 @@ def get_base_path() -> str:
|
|||
return BASE_PATH
|
||||
|
||||
def get_full_url(path: str) -> str:
|
||||
"""Get full URL with base path prefix"""
|
||||
"""
|
||||
DEPRECATED: Use get_app_url() from main.py instead for consistency.
|
||||
Get full URL with base path prefix.
|
||||
"""
|
||||
import warnings
|
||||
warnings.warn(
|
||||
"get_full_url() is deprecated. Use get_app_url() from main.py instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2
|
||||
)
|
||||
path = path.lstrip("/") # Remove leading slash
|
||||
if BASE_PATH:
|
||||
return f"{BASE_PATH}/{path}"
|
||||
|
|
|
|||
3
crud.py
3
crud.py
|
|
@ -337,7 +337,8 @@ def _agent_data_differs(existing_agent: dict, new_agent_data: dict) -> bool:
|
|||
comparable_fields = [
|
||||
"agent_description", "agent_purpose", "agent_version", "agent_status",
|
||||
"agent_location", "agent_department", "agent_contact_person",
|
||||
"agent_tags", "agent_userbase", "agent_capabilities", "agent_metadata"
|
||||
"agent_tags", "agent_userbase", "agent_capabilities", "agent_metadata",
|
||||
"url"
|
||||
]
|
||||
|
||||
for field in comparable_fields:
|
||||
|
|
|
|||
39
main.py
39
main.py
|
|
@ -214,6 +214,7 @@ def create_agent_response(agent: dict) -> models.AiAgentResponse:
|
|||
agent_metadata=sanitize_metadata(agent.get("agent_metadata")) if agent.get("agent_metadata") else None,
|
||||
agent_userbase=agent.get("agent_userbase"),
|
||||
agent_capabilities=agent.get("agent_capabilities"),
|
||||
url=agent.get("url"),
|
||||
quality_audit_status=agent.get("quality_audit_status", False),
|
||||
quality_audit_updated_by=agent.get("quality_audit_updated_by"),
|
||||
quality_audit_updated_at=agent.get("quality_audit_updated_at"),
|
||||
|
|
@ -272,6 +273,7 @@ def map_agent_collector_to_internal(collector_data: models.AgentCollectorCreate)
|
|||
"agent_contact_person": collector_data.contact_person,
|
||||
"agent_tags": collector_data.tags,
|
||||
"agent_metadata": collector_data.metadata,
|
||||
"url": collector_data.url,
|
||||
# Usage tracking fields (new)
|
||||
"usage_timeline": usage_timeline,
|
||||
"conversation_count": collector_data.conversation_count,
|
||||
|
|
@ -547,7 +549,7 @@ async def azure_token_exchange(request: Request):
|
|||
async def agent_register_page(request: Request):
|
||||
current_user = await get_current_user_optional(request)
|
||||
if not current_user:
|
||||
return RedirectResponse(url=config.get_full_url("login"), status_code=303)
|
||||
return RedirectResponse(url=get_app_url("login"), status_code=303)
|
||||
return templates.TemplateResponse("agent_register.html", get_template_context(request, current_user))
|
||||
|
||||
@app.post("/agent-register", response_class=HTMLResponse)
|
||||
|
|
@ -572,7 +574,7 @@ async def agent_register_form(
|
|||
# Get user from cookie - require authentication
|
||||
current_user = await get_current_user_optional(request)
|
||||
if not current_user:
|
||||
return RedirectResponse(url=config.get_full_url("login"), status_code=303)
|
||||
return RedirectResponse(url=get_app_url("login"), status_code=303)
|
||||
|
||||
user_id = str(current_user["_id"])
|
||||
|
||||
|
|
@ -652,7 +654,7 @@ async def agent_register_form(
|
|||
async def dashboard(request: Request):
|
||||
current_user = await get_current_user_optional(request)
|
||||
if not current_user:
|
||||
return RedirectResponse(url=config.get_full_url("login"), status_code=303)
|
||||
return RedirectResponse(url=get_app_url("login"), status_code=303)
|
||||
return templates.TemplateResponse("admin/dashboard.html", get_template_context(request, current_user))
|
||||
|
||||
@app.get("/user-management", response_class=HTMLResponse)
|
||||
|
|
@ -664,8 +666,8 @@ async def logout(request: Request):
|
|||
"""Logout user and clear all session data"""
|
||||
# Clear MSAL session data if present
|
||||
request.session.clear()
|
||||
|
||||
response = RedirectResponse(url=config.get_full_url(""), status_code=303)
|
||||
|
||||
response = RedirectResponse(url=get_app_url(""), status_code=303)
|
||||
response.delete_cookie(key="access_token")
|
||||
return response
|
||||
|
||||
|
|
@ -673,14 +675,14 @@ async def logout(request: Request):
|
|||
async def profile_page(request: Request):
|
||||
current_user = await get_current_user_optional(request)
|
||||
if not current_user:
|
||||
return RedirectResponse(url=config.get_full_url("login"), status_code=303)
|
||||
return RedirectResponse(url=get_app_url("login"), status_code=303)
|
||||
return templates.TemplateResponse("profile.html", get_template_context(request, current_user))
|
||||
|
||||
@app.get("/agent-management", response_class=HTMLResponse)
|
||||
@app.get("/agent-management", response_class=HTMLResponse)
|
||||
async def agent_management_page(request: Request, view: Optional[str] = Query(None), success: Optional[str] = Query(None), error: Optional[str] = Query(None)):
|
||||
current_user = await get_current_user_optional(request)
|
||||
if not current_user:
|
||||
return RedirectResponse(url=config.get_full_url("login"), status_code=303)
|
||||
return RedirectResponse(url=get_app_url("login"), status_code=303)
|
||||
|
||||
# Default to "all" view for regular users, "my" view can be specified via query param
|
||||
if view == "my":
|
||||
|
|
@ -712,7 +714,7 @@ async def agent_management_page(request: Request, view: Optional[str] = Query(No
|
|||
async def admin_dashboard(request: Request):
|
||||
current_user = await get_current_user_optional(request)
|
||||
if not current_user or not current_user.get("is_admin"):
|
||||
return RedirectResponse(url=config.get_full_url("login"), status_code=303)
|
||||
return RedirectResponse(url=get_app_url("login"), status_code=303)
|
||||
|
||||
# Get statistics
|
||||
all_users = await crud.get_all_users()
|
||||
|
|
@ -745,8 +747,8 @@ async def admin_dashboard(request: Request):
|
|||
async def search_page(request: Request, q: Optional[str] = Query(None)):
|
||||
current_user = await get_current_user_optional(request)
|
||||
if not current_user:
|
||||
return RedirectResponse(url=config.get_full_url("login"), status_code=303)
|
||||
|
||||
return RedirectResponse(url=get_app_url("login"), status_code=303)
|
||||
|
||||
search_results = {"agents": [], "users": []}
|
||||
if q:
|
||||
# Search agents using proper search function
|
||||
|
|
@ -773,8 +775,8 @@ async def search_page(request: Request, q: Optional[str] = Query(None)):
|
|||
async def edit_agent_form(request: Request, agent_id: str):
|
||||
current_user = await get_current_user_optional(request)
|
||||
if not current_user:
|
||||
return RedirectResponse(url=config.get_full_url("login"), status_code=303)
|
||||
|
||||
return RedirectResponse(url=get_app_url("login"), status_code=303)
|
||||
|
||||
agent = await crud.get_agent_by_id(agent_id)
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail="Agent not found")
|
||||
|
|
@ -793,8 +795,8 @@ async def edit_agent_form(request: Request, agent_id: str):
|
|||
async def delete_agent_form(request: Request, agent_id: str):
|
||||
current_user = await get_current_user_optional(request)
|
||||
if not current_user:
|
||||
return RedirectResponse(url=config.get_full_url("login"), status_code=303)
|
||||
|
||||
return RedirectResponse(url=get_app_url("login"), status_code=303)
|
||||
|
||||
# Check permission and delete
|
||||
user_id = str(current_user["_id"]) if not current_user.get("is_admin") else None
|
||||
deleted = await crud.delete_agent(agent_id, user_id)
|
||||
|
|
@ -994,12 +996,14 @@ async def create_agent_collector(
|
|||
if existing_agent:
|
||||
# Agent exists - log usage AND update agent document with new usage data
|
||||
internal_data = map_agent_collector_to_internal(agent)
|
||||
print(f"🔗 URL DEBUG: Agent '{agent.name}' - URL in internal_data: {internal_data.get('url')}")
|
||||
|
||||
# Create usage record for fallback purposes (existing system)
|
||||
await crud.create_agent_usage_record(agent.name, internal_data)
|
||||
|
||||
# Update agent document with new usage data (replace strategy)
|
||||
update_fields = {
|
||||
"url": internal_data.get("url"),
|
||||
"usage_timeline": internal_data.get("usage_timeline"),
|
||||
"conversation_count": internal_data.get("conversation_count"),
|
||||
"unique_users": internal_data.get("unique_users"),
|
||||
|
|
@ -1011,13 +1015,16 @@ async def create_agent_collector(
|
|||
|
||||
# Only update non-None usage fields
|
||||
update_fields = {k: v for k, v in update_fields.items() if k == "updated_at" or v is not None}
|
||||
print(f"🔗 URL DEBUG: Agent '{agent.name}' - update_fields after filter: {update_fields}")
|
||||
print(f"🔗 URL DEBUG: Agent '{agent.name}' - URL in update_fields: {update_fields.get('url')}")
|
||||
|
||||
if len(update_fields) > 1: # More than just updated_at
|
||||
from database import agents_collection
|
||||
await agents_collection.update_one(
|
||||
result = await agents_collection.update_one(
|
||||
{"agent_name": agent.name},
|
||||
{"$set": update_fields}
|
||||
)
|
||||
print(f"🔗 URL DEBUG: Agent '{agent.name}' - Update executed: matched={result.matched_count}, modified={result.modified_count}")
|
||||
|
||||
return models.AgentUsageTrackingResponse(
|
||||
status="usage_logged",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ class AiAgent(BaseModel):
|
|||
agent_metadata: dict[str, str] | None = Field(default=None, title="Metadata associated with the agent")
|
||||
agent_userbase: list[str] | None = Field(default=None, title="Userbase associated with the agent")
|
||||
agent_capabilities: list[str] | None = Field(default=None, title="Capabilities of the agent")
|
||||
url: str | None = Field(default=None, title="Direct link to create a conversation with this agent")
|
||||
quality_audit_status: bool | None = Field(default=False, title="Quality audit status")
|
||||
quality_audit_updated_by: str | None = Field(default=None, title="Admin user ID who updated quality audit")
|
||||
quality_audit_updated_at: str | None = Field(default=None, title="Quality audit last update timestamp")
|
||||
|
|
@ -74,6 +75,7 @@ class AiAgentCreate(BaseModel):
|
|||
agent_metadata: Optional[dict[str, str]] = None
|
||||
agent_userbase: Optional[list[str]] = None
|
||||
agent_capabilities: Optional[list[str]] = None
|
||||
url: Optional[str] = None
|
||||
quality_audit_status: Optional[bool] = False
|
||||
quality_audit_updated_by: Optional[str] = None
|
||||
quality_audit_updated_at: Optional[str] = None
|
||||
|
|
@ -98,6 +100,7 @@ class AiAgentResponse(BaseModel):
|
|||
agent_metadata: Optional[dict[str, str]] = None
|
||||
agent_userbase: Optional[list[str]] = None
|
||||
agent_capabilities: Optional[list[str]] = None
|
||||
url: Optional[str] = None
|
||||
quality_audit_status: Optional[bool] = None
|
||||
quality_audit_updated_by: Optional[str] = None
|
||||
quality_audit_updated_at: Optional[str] = None
|
||||
|
|
@ -131,6 +134,7 @@ class AgentCollectorCreate(BaseModel):
|
|||
contact_person: Optional[str] = None
|
||||
tags: Optional[list[str]] = None
|
||||
metadata: Optional[dict] = None
|
||||
url: Optional[str] = None
|
||||
|
||||
# Usage tracking fields (new)
|
||||
usage_timeline: Optional[List[UsageTimelineEntry]] = None
|
||||
|
|
|
|||
|
|
@ -425,6 +425,7 @@ let currentView = '{{ current_view }}';
|
|||
let currentUserId = '{{ current_user._id|string }}';
|
||||
let currentUserEmail = '{{ current_user.email }}';
|
||||
let currentUserIsAdmin = {{ 'true' if current_user.is_admin else 'false' }};
|
||||
const basePath = '{{ base_path }}';
|
||||
|
||||
// Helper function to check if current user can edit an agent
|
||||
function canUserEditAgent(agent) {
|
||||
|
|
@ -571,9 +572,9 @@ function switchToView(view) {
|
|||
|
||||
displayAgents(agents);
|
||||
updateAgentCounts();
|
||||
|
||||
|
||||
// Update URL without page reload
|
||||
const newUrl = view === 'my' ? '/agent-management?view=my' : '/agent-management';
|
||||
const newUrl = view === 'my' ? `${basePath}/agent-management?view=my` : `${basePath}/agent-management`;
|
||||
window.history.pushState({view: view}, '', newUrl);
|
||||
}
|
||||
|
||||
|
|
@ -607,7 +608,7 @@ function displayAgents(agentsToShow) {
|
|||
<div>
|
||||
<h6 class="mb-1 fw-bold">${agent.agent_name}</h6>
|
||||
<p class="text-muted mb-2 small">${agent.agent_description || 'No description'}</p>
|
||||
<div class="d-flex gap-2 align-items-center flex-wrap">
|
||||
<div class="d-flex gap-2 align-items-center flex-wrap mb-1">
|
||||
<span class="agent-status status-${agent.agent_status || 'Development'}">
|
||||
${agent.agent_status || 'Development'}
|
||||
</span>
|
||||
|
|
@ -616,7 +617,13 @@ function displayAgents(agentsToShow) {
|
|||
${agent.quality_audit_status && agent.risk_factor ? getRiskFactorBadge(agent.risk_factor) : ''}
|
||||
${agent.total_messages ? `<span class="badge bg-info text-white" title="Total Messages"><i class="fas fa-comments me-1"></i>${agent.total_messages.toLocaleString()}</span>` : ''}
|
||||
${agent.unique_users ? `<span class="badge bg-primary" title="Unique Users"><i class="fas fa-users me-1"></i>${agent.unique_users}</span>` : ''}
|
||||
${agent.url ? `<a href="${agent.url}" target="_blank" class="btn btn-sm btn-success" onclick="event.stopPropagation();" title="Start a conversation with this agent"><i class="fas fa-external-link-alt me-1"></i>Open Agent</a>` : ''}
|
||||
</div>
|
||||
${agent.agent_tags && agent.agent_tags.length > 0 ? `
|
||||
<div class="d-flex gap-1 flex-wrap">
|
||||
${agent.agent_tags.map(tag => `<span class="badge bg-secondary" style="font-size: 0.7rem;"><i class="fas fa-tag me-1"></i>${tag}</span>`).join('')}
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<small class="text-muted">${formatDate(agent.agent_created_at)}</small>
|
||||
|
|
@ -675,6 +682,7 @@ async function showAgentDetails(agentId) {
|
|||
|
||||
const agent = await response.json();
|
||||
console.log('DEBUG: Fresh agent data loaded:', agent);
|
||||
console.log('DEBUG: Agent URL field:', agent.url);
|
||||
console.log('DEBUG: Quality Audit Details:', {
|
||||
status: agent.quality_audit_status,
|
||||
updated_by: agent.quality_audit_updated_by,
|
||||
|
|
@ -691,9 +699,10 @@ async function showAgentDetails(agentId) {
|
|||
<tr><td><strong>Status:</strong></td><td><span class="agent-status status-${agent.agent_status || 'Development'}">${agent.agent_status || 'Development'}</span></td></tr>
|
||||
<tr><td><strong>Version:</strong></td><td>${agent.agent_version || 'N/A'}</td></tr>
|
||||
<tr><td><strong>Purpose:</strong></td><td>${agent.agent_purpose || 'N/A'}</td></tr>
|
||||
${agent.url ? `<tr><td><strong>Agent Link:</strong></td><td><a href="${agent.url}" target="_blank" class="btn btn-sm btn-success"><i class="fas fa-external-link-alt me-1"></i>Open Agent</a></td></tr>` : ''}
|
||||
<tr><td><strong>Quality Audit:</strong></td><td>
|
||||
${agent.quality_audit_status ?
|
||||
'<span class="badge bg-success"><i class="fas fa-certificate me-1"></i>Audited</span>' :
|
||||
${agent.quality_audit_status ?
|
||||
'<span class="badge bg-success"><i class="fas fa-certificate me-1"></i>Audited</span>' :
|
||||
'<span class="badge bg-secondary">Not Audited</span>'
|
||||
}
|
||||
${agent.quality_audit_status && agent.risk_factor ? getRiskFactorBadge(agent.risk_factor) : ''}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue