refactor(api): extract assistant self-service slice

This commit is contained in:
2026-03-30 21:31:06 +02:00
parent 72394747f9
commit 7d3c6d978e
3 changed files with 322 additions and 261 deletions
+10 -260
View File
@@ -95,6 +95,10 @@ import {
countryMetroAdminToolDefinitions,
createCountryMetroAdminExecutors,
} from "./assistant-tools/country-metro-admin.js";
import {
createUserSelfServiceExecutors,
userSelfServiceToolDefinitions,
} from "./assistant-tools/user-self-service.js";
import type { ToolContext, ToolDef, ToolExecutor } from "./assistant-tools/shared.js";
import { getCommentToolEntityDescription, getCommentToolScopeSentence } from "../lib/comment-entity-registry.js";
@@ -2794,152 +2798,7 @@ export const TOOL_DEFINITIONS: ToolDef[] = [
},
},
},
{
type: "function",
function: {
name: "list_assignable_users",
description: "List lightweight users available for assignment workflows. Manager or admin role required.",
parameters: { type: "object", properties: {} },
},
},
{
type: "function",
function: {
name: "get_current_user",
description: "Get the authenticated user's own profile, role, and permission overrides.",
parameters: { type: "object", properties: {} },
},
},
{
type: "function",
function: {
name: "get_dashboard_layout",
description: "Get the authenticated user's saved dashboard widget layout and last update timestamp.",
parameters: { type: "object", properties: {} },
},
},
{
type: "function",
function: {
name: "save_dashboard_layout",
description: "Save the authenticated user's dashboard layout. Always confirm first.",
parameters: {
type: "object",
properties: {
layout: {
type: "array",
description: "Dashboard layout items as stored by the user router.",
items: { type: "object" },
},
},
required: ["layout"],
},
},
},
{
type: "function",
function: {
name: "get_favorite_project_ids",
description: "Get the authenticated user's favorite project IDs.",
parameters: { type: "object", properties: {} },
},
},
{
type: "function",
function: {
name: "toggle_favorite_project",
description: "Add or remove a project from the authenticated user's favorites. Always confirm first.",
parameters: {
type: "object",
properties: {
projectId: { type: "string", description: "Project ID." },
},
required: ["projectId"],
},
},
},
{
type: "function",
function: {
name: "get_column_preferences",
description: "Get the authenticated user's saved table column preferences for all supported views.",
parameters: { type: "object", properties: {} },
},
},
{
type: "function",
function: {
name: "set_column_preferences",
description: "Update the authenticated user's table column preferences for one view. Always confirm first.",
parameters: {
type: "object",
properties: {
view: {
type: "string",
enum: ["resources", "projects", "allocations", "vacations", "roles", "users", "blueprints"],
description: "View key to update.",
},
visible: {
type: "array",
items: { type: "string" },
description: "Visible column IDs.",
},
sort: {
type: ["object", "null"],
properties: {
field: { type: "string" },
dir: { type: "string", enum: ["asc", "desc"] },
},
description: "Sort state. Use null to clear it.",
},
rowOrder: {
type: ["array", "null"],
items: { type: "string" },
description: "Optional row order. Use null to clear it.",
},
},
required: ["view"],
},
},
},
{
type: "function",
function: {
name: "generate_totp_secret",
description: "Generate a new MFA TOTP secret and provisioning URI for the authenticated user. Always confirm first. The secret is sensitive.",
parameters: { type: "object", properties: {} },
},
},
{
type: "function",
function: {
name: "verify_and_enable_totp",
description: "Verify a 6-digit MFA TOTP token and enable MFA for the authenticated user. Always confirm first.",
parameters: {
type: "object",
properties: {
token: { type: "string", description: "6-digit TOTP token." },
},
required: ["token"],
},
},
},
{
type: "function",
function: {
name: "get_mfa_status",
description: "Get the authenticated user's MFA status.",
parameters: { type: "object", properties: {} },
},
},
{
type: "function",
function: {
name: "get_active_user_count",
description: "Get the number of users active in the last five minutes. Admin role required.",
parameters: { type: "object", properties: {} },
},
},
...userSelfServiceToolDefinitions,
{
type: "function",
function: {
@@ -5482,120 +5341,11 @@ const executors = {
const users = await caller.list();
return users.slice(0, Math.min(params.limit ?? 50, 100));
},
async list_assignable_users(_params: Record<string, never>, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
return caller.listAssignable();
},
async get_current_user(_params: Record<string, never>, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
return caller.me();
},
async get_dashboard_layout(_params: Record<string, never>, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
return caller.getDashboardLayout();
},
async save_dashboard_layout(params: { layout: unknown[] }, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
const result = await caller.saveDashboardLayout({ layout: params.layout });
return {
__action: "invalidate",
scope: ["dashboard"],
success: true,
...result,
message: "Saved dashboard layout.",
};
},
async get_favorite_project_ids(_params: Record<string, never>, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
return caller.getFavoriteProjectIds();
},
async toggle_favorite_project(params: { projectId: string }, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
const result = await caller.toggleFavoriteProject({ projectId: params.projectId });
return {
__action: "invalidate",
scope: ["project"],
success: true,
...result,
message: result.added ? "Added project to favorites." : "Removed project from favorites.",
};
},
async get_column_preferences(_params: Record<string, never>, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
return caller.getColumnPreferences();
},
async set_column_preferences(params: {
view: "resources" | "projects" | "allocations" | "vacations" | "roles" | "users" | "blueprints";
visible?: string[];
sort?: { field: string; dir: "asc" | "desc" } | null;
rowOrder?: string[] | null;
}, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
const result = await caller.setColumnPreferences({
view: params.view,
...(params.visible !== undefined ? { visible: params.visible } : {}),
...(params.sort !== undefined ? { sort: params.sort } : {}),
...(params.rowOrder !== undefined ? { rowOrder: params.rowOrder } : {}),
});
return {
__action: "invalidate",
scope: ["user"],
success: true,
...result,
message: `Updated column preferences for ${params.view}.`,
};
},
async generate_totp_secret(_params: Record<string, never>, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
const result = await caller.generateTotpSecret();
return {
__action: "invalidate",
scope: ["user"],
success: true,
...result,
message: "Generated a new MFA TOTP secret.",
};
},
async verify_and_enable_totp(params: { token: string }, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
let result;
try {
result = await caller.verifyAndEnableTotp({ token: params.token });
} catch (error) {
const mapped = toAssistantTotpEnableError(error);
if (mapped) {
return mapped;
}
throw error;
}
return {
__action: "invalidate",
scope: ["user"],
success: true,
...result,
message: "Enabled MFA TOTP.",
};
},
async get_mfa_status(_params: Record<string, never>, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
return caller.getMfaStatus();
},
async get_active_user_count(_params: Record<string, never>, ctx: ToolContext) {
const caller = createUserCaller(createScopedCallerContext(ctx));
return caller.activeCount();
},
...createUserSelfServiceExecutors({
createUserCaller,
createScopedCallerContext,
toAssistantTotpEnableError,
}),
async create_user(params: {
email: string;