import type { TRPCContext } from "../../trpc.js"; import type { ToolContext, ToolDef, ToolExecutor } from "./shared.js"; type ConfigReadmodelsDeps = { createManagementLevelCaller: (ctx: TRPCContext) => { listGroups: () => Promise; }>>; }; createUtilizationCategoryCaller: (ctx: TRPCContext) => { list: () => Promise>; getById: (params: { id: string }) => Promise<{ _count: { projects: number }; }>; }; createCalculationRuleCaller: (ctx: TRPCContext) => { list: () => Promise>; }; createEffortRuleCaller: (ctx: TRPCContext) => { list: () => Promise; }>>; }; createExperienceMultiplierCaller: (ctx: TRPCContext) => { list: () => Promise; }>>; }; createScopedCallerContext: (ctx: ToolContext) => TRPCContext; }; export const configReadmodelToolDefinitions: ToolDef[] = [ { type: "function", function: { name: "list_management_levels", description: "List management level groups and their levels with target percentages.", parameters: { type: "object", properties: {} }, }, }, { type: "function", function: { name: "list_utilization_categories", description: "List utilization categories (cost classification for projects).", parameters: { type: "object", properties: {} }, }, }, { type: "function", function: { name: "list_calculation_rules", description: "List calculation rules for cost attribution and chargeability.", parameters: { type: "object", properties: {} }, }, }, { type: "function", function: { name: "list_effort_rules", description: "List effort estimation rules with their formulas and conditions.", parameters: { type: "object", properties: {} }, }, }, { type: "function", function: { name: "list_experience_multipliers", description: "List experience multipliers that adjust effort estimates based on seniority.", parameters: { type: "object", properties: {} }, }, }, ]; export function createConfigReadmodelExecutors( deps: ConfigReadmodelsDeps, ): Record { return { async list_management_levels(_params: Record, ctx: ToolContext) { const caller = deps.createManagementLevelCaller(deps.createScopedCallerContext(ctx)); const groups = await caller.listGroups(); return groups.map((group) => ({ id: group.id, name: group.name, target: group.targetPercentage ? `${group.targetPercentage}%` : null, levels: group.levels.map((level) => ({ id: level.id, name: level.name })), })); }, async list_utilization_categories(_params: Record, ctx: ToolContext) { const caller = deps.createUtilizationCategoryCaller(deps.createScopedCallerContext(ctx)); const categories = await caller.list(); const categoriesWithCounts = await Promise.all( categories.map(async (category) => ({ category, projectCount: (await caller.getById({ id: category.id }))._count.projects, })), ); return categoriesWithCounts.map(({ category, projectCount }) => ({ id: category.id, code: category.code, name: category.name, description: category.description, projectCount, })); }, async list_calculation_rules(_params: Record, ctx: ToolContext) { const caller = deps.createCalculationRuleCaller(deps.createScopedCallerContext(ctx)); const rules = await caller.list(); return rules.map((rule) => ({ id: rule.id, name: rule.name, description: rule.description, isActive: rule.isActive, triggerType: rule.triggerType, orderType: rule.orderType, costEffect: rule.costEffect, costReductionPercent: rule.costReductionPercent, chargeabilityEffect: rule.chargeabilityEffect, priority: rule.priority, project: rule.project ? { id: rule.project.id, name: rule.project.name, shortCode: rule.project.shortCode, } : null, })); }, async list_effort_rules(_params: Record, ctx: ToolContext) { const caller = deps.createEffortRuleCaller(deps.createScopedCallerContext(ctx)); const ruleSets = await caller.list(); return ruleSets.flatMap((ruleSet) => ruleSet.rules.map((rule) => ({ id: rule.id, description: rule.description, scopeType: rule.scopeType, discipline: rule.discipline, chapter: rule.chapter, unitMode: rule.unitMode, hoursPerUnit: rule.hoursPerUnit, sortOrder: rule.sortOrder, ruleSet: { name: ruleSet.name, isDefault: ruleSet.isDefault, }, }))); }, async list_experience_multipliers(_params: Record, ctx: ToolContext) { const caller = deps.createExperienceMultiplierCaller(deps.createScopedCallerContext(ctx)); const multiplierSets = await caller.list(); return multiplierSets.flatMap((multiplierSet) => multiplierSet.rules.map((rule) => ({ id: rule.id, description: rule.description, chapter: rule.chapter, location: rule.location, level: rule.level, costMultiplier: rule.costMultiplier, billMultiplier: rule.billMultiplier, shoringRatio: rule.shoringRatio, additionalEffortRatio: rule.additionalEffortRatio, sortOrder: rule.sortOrder, multiplierSet: { name: multiplierSet.name, isDefault: multiplierSet.isDefault, }, }))); }, }; }