Files
CapaKraken/packages/api/src/router/assistant-tool-policy.ts
T

295 lines
8.4 KiB
TypeScript

import { PermissionKey, SystemRole } from "@capakraken/shared";
import { ADVANCED_ASSISTANT_TOOLS, TOOL_DEFINITIONS } from "./assistant-tools.js";
import type { ToolDef } from "./assistant-tools/shared.js";
const TOOL_PERMISSION_MAP: Record<string, string> = {
update_resource: "manageResources",
create_resource: "manageResources",
deactivate_resource: "manageResources",
create_role: PermissionKey.MANAGE_ROLES,
update_role: PermissionKey.MANAGE_ROLES,
delete_role: PermissionKey.MANAGE_ROLES,
update_project: "manageProjects",
create_project: "manageProjects",
delete_project: "manageProjects",
create_estimate: "manageProjects",
clone_estimate: "manageProjects",
update_estimate_draft: "manageProjects",
submit_estimate_version: "manageProjects",
approve_estimate_version: "manageProjects",
create_estimate_revision: "manageProjects",
create_estimate_export: "manageProjects",
generate_estimate_weekly_phasing: "manageProjects",
update_estimate_commercial_terms: "manageProjects",
generate_project_cover: "manageProjects",
remove_project_cover: "manageProjects",
import_csv_data: PermissionKey.IMPORT_DATA,
create_allocation: "manageAllocations",
cancel_allocation: "manageAllocations",
update_allocation_status: "manageAllocations",
update_timeline_allocation_inline: "manageAllocations",
apply_timeline_project_shift: "manageAllocations",
quick_assign_timeline_resource: "manageAllocations",
batch_quick_assign_timeline_resources: "manageAllocations",
batch_shift_timeline_allocations: "manageAllocations",
create_demand: "manageAllocations",
fill_demand: "manageAllocations",
create_estimate_planning_handoff: "manageAllocations",
execute_task_action: "manageAllocations",
};
const COST_TOOLS = new Set([
"get_budget_status",
"get_chargeability",
"get_chargeability_report",
"get_resource_computation_graph",
"get_project_computation_graph",
"resolve_rate",
"list_rate_cards",
"get_estimate_detail",
"get_estimate_version_snapshot",
"find_best_project_resource",
"get_staffing_suggestions",
]);
const PLANNING_READ_TOOLS = new Set([
"list_allocations",
"list_demands",
"list_blueprints",
"get_blueprint",
"list_clients",
"list_roles",
"list_management_levels",
"list_utilization_categories",
"check_resource_availability",
"get_staffing_suggestions",
"find_capacity",
"find_best_project_resource",
]);
const RESOURCE_OVERVIEW_TOOLS = new Set([
"search_resources",
"get_country",
"list_org_units",
]);
const CONTROLLER_ONLY_TOOLS = new Set([
"search_by_skill",
"search_projects",
"get_project",
"search_estimates",
"get_timeline_entries_view",
"get_timeline_holiday_overlays",
"get_project_timeline_context",
"preview_project_shift",
"get_statistics",
"get_dashboard_detail",
"get_skill_gaps",
"get_project_health",
"get_budget_forecast",
"query_change_history",
"get_entity_timeline",
"export_resources_csv",
"export_projects_csv",
"list_audit_log_entries",
"get_audit_log_entry",
"get_audit_log_timeline",
"get_audit_activity_summary",
"get_chargeability_report",
"get_resource_computation_graph",
"get_project_computation_graph",
"get_estimate_detail",
"list_estimate_versions",
"get_estimate_version_snapshot",
"get_estimate_weekly_phasing",
"get_estimate_commercial_terms",
]);
const MANAGER_ONLY_TOOLS = new Set([
"import_csv_data",
"list_assignable_users",
"create_notification",
"update_timeline_allocation_inline",
"apply_timeline_project_shift",
"quick_assign_timeline_resource",
"batch_quick_assign_timeline_resources",
"batch_shift_timeline_allocations",
"create_estimate",
"clone_estimate",
"update_estimate_draft",
"submit_estimate_version",
"approve_estimate_version",
"create_estimate_revision",
"create_estimate_export",
"create_estimate_planning_handoff",
"generate_estimate_weekly_phasing",
"update_estimate_commercial_terms",
"create_task_for_user",
"assign_task",
"send_broadcast",
"list_broadcasts",
"get_broadcast_detail",
"approve_vacation",
"reject_vacation",
"get_pending_vacation_approvals",
"get_entitlement_summary",
"set_entitlement",
"create_role",
"update_role",
"delete_role",
"create_client",
"update_client",
]);
const ADMIN_ONLY_TOOLS = new Set([
"list_users",
"get_active_user_count",
"create_user",
"set_user_password",
"update_user_role",
"update_user_name",
"link_user_resource",
"auto_link_users_by_email",
"set_user_permissions",
"reset_user_permissions",
"get_effective_user_permissions",
"disable_user_totp",
"list_dispo_import_batches",
"get_dispo_import_batch",
"stage_dispo_import_batch",
"validate_dispo_import_batch",
"cancel_dispo_import_batch",
"list_dispo_staged_resources",
"list_dispo_staged_projects",
"list_dispo_staged_assignments",
"list_dispo_staged_vacations",
"list_dispo_staged_unresolved_records",
"resolve_dispo_staged_record",
"commit_dispo_import_batch",
"get_system_settings",
"update_system_settings",
"clear_stored_runtime_secrets",
"get_ai_configured",
"test_ai_connection",
"test_smtp_connection",
"test_gemini_connection",
"list_system_role_configs",
"update_system_role_config",
"list_webhooks",
"get_webhook",
"create_webhook",
"update_webhook",
"delete_webhook",
"test_webhook",
"create_org_unit",
"update_org_unit",
"create_country",
"update_country",
"create_metro_city",
"update_metro_city",
"delete_metro_city",
"list_holiday_calendars",
"get_holiday_calendar",
"create_holiday_calendar",
"update_holiday_calendar",
"delete_holiday_calendar",
"create_holiday_calendar_entry",
"update_holiday_calendar_entry",
"delete_holiday_calendar_entry",
]);
function hasLegacyToolAccess(
toolName: string,
permissions: Set<PermissionKey>,
userRole: string,
hasResourceOverviewAccess: boolean,
hasControllerAccess: boolean,
hasManagerAccess: boolean,
) {
const requiredPerm = TOOL_PERMISSION_MAP[toolName];
if (requiredPerm && !permissions.has(requiredPerm as PermissionKey)) {
return false;
}
if (ADMIN_ONLY_TOOLS.has(toolName) && userRole !== SystemRole.ADMIN) {
return false;
}
if (MANAGER_ONLY_TOOLS.has(toolName) && !hasManagerAccess) {
return false;
}
if (RESOURCE_OVERVIEW_TOOLS.has(toolName) && !hasResourceOverviewAccess) {
return false;
}
if (CONTROLLER_ONLY_TOOLS.has(toolName) && !hasControllerAccess) {
return false;
}
if (PLANNING_READ_TOOLS.has(toolName) && !permissions.has(PermissionKey.VIEW_PLANNING)) {
return false;
}
if (COST_TOOLS.has(toolName) && !permissions.has(PermissionKey.VIEW_COSTS)) {
return false;
}
if (ADVANCED_ASSISTANT_TOOLS.has(toolName) && !permissions.has(PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS)) {
return false;
}
return true;
}
function hasToolAccess(
tool: ToolDef,
permissions: Set<PermissionKey>,
userRole: string,
hasResourceOverviewAccess: boolean,
): boolean {
if (!tool.access) {
const hasControllerAccess = userRole === SystemRole.ADMIN
|| userRole === SystemRole.MANAGER
|| userRole === SystemRole.CONTROLLER;
const hasManagerAccess = userRole === SystemRole.ADMIN
|| userRole === SystemRole.MANAGER;
return hasLegacyToolAccess(
tool.function.name,
permissions,
userRole,
hasResourceOverviewAccess,
hasControllerAccess,
hasManagerAccess,
);
}
if (tool.access.requiredPermissions?.some((permission) => !permissions.has(permission))) {
return false;
}
if (tool.access.allowedSystemRoles && !tool.access.allowedSystemRoles.includes(userRole as SystemRole)) {
return false;
}
if (tool.access.requiresResourceOverview && !hasResourceOverviewAccess) {
return false;
}
if (tool.access.requiresPlanningRead && !permissions.has(PermissionKey.VIEW_PLANNING)) {
return false;
}
if (tool.access.requiresCostView && !permissions.has(PermissionKey.VIEW_COSTS)) {
return false;
}
if (tool.access.requiresAdvancedAssistant && !permissions.has(PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS)) {
return false;
}
return true;
}
export function getAvailableAssistantTools(
permissions: Set<PermissionKey>,
userRole: string,
): ToolDef[] {
const hasResourceOverviewAccess = permissions.has(PermissionKey.VIEW_ALL_RESOURCES)
|| permissions.has(PermissionKey.MANAGE_RESOURCES);
return TOOL_DEFINITIONS.filter((tool) => (
hasToolAccess(tool, permissions, userRole, hasResourceOverviewAccess)
));
}