refactor(api): extract assistant country read slice
This commit is contained in:
@@ -85,6 +85,10 @@ import {
|
||||
countryMetroAdminToolDefinitions,
|
||||
createCountryMetroAdminExecutors,
|
||||
} from "./assistant-tools/country-metro-admin.js";
|
||||
import {
|
||||
countryReadmodelToolDefinitions,
|
||||
createCountryReadmodelExecutors,
|
||||
} from "./assistant-tools/country-readmodels.js";
|
||||
import {
|
||||
createUserSelfServiceExecutors,
|
||||
userSelfServiceToolDefinitions,
|
||||
@@ -431,7 +435,6 @@ const LEGACY_MONOLITHIC_TOOL_ACCESS: Partial<Record<string, ToolAccessRequiremen
|
||||
get_pending_vacation_approvals: { allowedSystemRoles: [...MANAGER_ASSISTANT_ROLES] },
|
||||
get_entitlement_summary: { allowedSystemRoles: [...MANAGER_ASSISTANT_ROLES] },
|
||||
set_entitlement: { allowedSystemRoles: [...MANAGER_ASSISTANT_ROLES] },
|
||||
get_country: { requiresResourceOverview: true },
|
||||
delete_project: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
|
||||
generate_project_cover: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
|
||||
remove_project_cover: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
|
||||
@@ -2161,34 +2164,7 @@ export const TOOL_DEFINITIONS: ToolDef[] = withToolAccess([
|
||||
...clientMutationToolDefinitions,
|
||||
|
||||
// ── ADMIN / CONFIG READ TOOLS ──
|
||||
{
|
||||
type: "function",
|
||||
function: {
|
||||
name: "list_countries",
|
||||
description: "List countries including working hours, schedule rules, active flag, and metro cities.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
includeInactive: { type: "boolean", description: "Include inactive countries. Default: false." },
|
||||
search: { type: "string", description: "Optional country code or name search." },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "function",
|
||||
function: {
|
||||
name: "get_country",
|
||||
description: "Get one country with schedule rules, active flag, metro cities, and resource count. Accepts ID, code, or name.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
identifier: { type: "string", description: "Country ID, code, or name." },
|
||||
},
|
||||
required: ["identifier"],
|
||||
},
|
||||
},
|
||||
},
|
||||
...countryReadmodelToolDefinitions,
|
||||
...countryMetroAdminToolDefinitions,
|
||||
...configReadmodelToolDefinitions,
|
||||
...userAdminToolDefinitions,
|
||||
@@ -2627,40 +2603,12 @@ const executors = {
|
||||
|
||||
// ── ADMIN / CONFIG ──
|
||||
|
||||
async list_countries(params: { includeInactive?: boolean; search?: string }, ctx: ToolContext) {
|
||||
const caller = createCountryCaller(createScopedCallerContext(ctx));
|
||||
const countries = await caller.list(
|
||||
params.includeInactive
|
||||
? undefined
|
||||
: { isActive: true },
|
||||
);
|
||||
const normalizedSearch = params.search?.trim().toLowerCase();
|
||||
const filteredCountries = normalizedSearch
|
||||
? countries.filter((country) =>
|
||||
country.code.toLowerCase().includes(normalizedSearch)
|
||||
|| country.name.toLowerCase().includes(normalizedSearch))
|
||||
: countries;
|
||||
|
||||
return {
|
||||
count: filteredCountries.length,
|
||||
countries: filteredCountries.map(formatCountry),
|
||||
};
|
||||
},
|
||||
|
||||
async get_country(params: { identifier: string }, ctx: ToolContext) {
|
||||
const caller = createCountryCaller(createScopedCallerContext(ctx));
|
||||
let country;
|
||||
try {
|
||||
country = await caller.getByIdentifier({ identifier: params.identifier });
|
||||
} catch (error) {
|
||||
const mapped = toAssistantCountryNotFoundError(error);
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return formatCountry(country);
|
||||
},
|
||||
...createCountryReadmodelExecutors({
|
||||
createCountryCaller,
|
||||
createScopedCallerContext,
|
||||
formatCountry,
|
||||
toAssistantCountryNotFoundError,
|
||||
}),
|
||||
...createCountryMetroAdminExecutors({
|
||||
createCountryCaller,
|
||||
createScopedCallerContext,
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import type { Prisma } from "@capakraken/db";
|
||||
import type { TRPCContext } from "../../trpc.js";
|
||||
import { withToolAccess, type ToolContext, type ToolDef, type ToolExecutor } from "./shared.js";
|
||||
|
||||
type AssistantToolErrorResult = { error: string };
|
||||
|
||||
type CountryRecord = {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
dailyWorkingHours: number;
|
||||
scheduleRules?: Prisma.JsonValue | null;
|
||||
isActive?: boolean | null;
|
||||
metroCities?: Array<{ id: string; name: string }> | null;
|
||||
_count?: { resources?: number | null } | null;
|
||||
};
|
||||
|
||||
type CountryReadmodelsDeps = {
|
||||
createCountryCaller: (ctx: TRPCContext) => {
|
||||
list: (params?: { isActive: boolean }) => Promise<CountryRecord[]>;
|
||||
getByIdentifier: (params: { identifier: string }) => Promise<CountryRecord>;
|
||||
};
|
||||
createScopedCallerContext: (ctx: ToolContext) => TRPCContext;
|
||||
formatCountry: (country: CountryRecord) => unknown;
|
||||
toAssistantCountryNotFoundError: (
|
||||
error: unknown,
|
||||
) => AssistantToolErrorResult | null;
|
||||
};
|
||||
|
||||
export const countryReadmodelToolDefinitions: ToolDef[] = withToolAccess([
|
||||
{
|
||||
type: "function",
|
||||
function: {
|
||||
name: "list_countries",
|
||||
description: "List countries including working hours, schedule rules, active flag, and metro cities.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
includeInactive: { type: "boolean", description: "Include inactive countries. Default: false." },
|
||||
search: { type: "string", description: "Optional country code or name search." },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "function",
|
||||
function: {
|
||||
name: "get_country",
|
||||
description: "Get one country with schedule rules, active flag, metro cities, and resource count. Accepts ID, code, or name.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
identifier: { type: "string", description: "Country ID, code, or name." },
|
||||
},
|
||||
required: ["identifier"],
|
||||
},
|
||||
},
|
||||
},
|
||||
], {
|
||||
get_country: {
|
||||
requiresResourceOverview: true,
|
||||
},
|
||||
});
|
||||
|
||||
export function createCountryReadmodelExecutors(
|
||||
deps: CountryReadmodelsDeps,
|
||||
): Record<string, ToolExecutor> {
|
||||
return {
|
||||
async list_countries(
|
||||
params: { includeInactive?: boolean; search?: string },
|
||||
ctx: ToolContext,
|
||||
) {
|
||||
const caller = deps.createCountryCaller(deps.createScopedCallerContext(ctx));
|
||||
const countries = await caller.list(
|
||||
params.includeInactive
|
||||
? undefined
|
||||
: { isActive: true },
|
||||
);
|
||||
const normalizedSearch = params.search?.trim().toLowerCase();
|
||||
const filteredCountries = normalizedSearch
|
||||
? countries.filter((country) =>
|
||||
country.code.toLowerCase().includes(normalizedSearch)
|
||||
|| country.name.toLowerCase().includes(normalizedSearch))
|
||||
: countries;
|
||||
|
||||
return {
|
||||
count: filteredCountries.length,
|
||||
countries: filteredCountries.map(deps.formatCountry),
|
||||
};
|
||||
},
|
||||
|
||||
async get_country(
|
||||
params: { identifier: string },
|
||||
ctx: ToolContext,
|
||||
) {
|
||||
const caller = deps.createCountryCaller(deps.createScopedCallerContext(ctx));
|
||||
let country;
|
||||
try {
|
||||
country = await caller.getByIdentifier({ identifier: params.identifier });
|
||||
} catch (error) {
|
||||
const mapped = deps.toAssistantCountryNotFoundError(error);
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
return deps.formatCountry(country);
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user