refactor(api): extract assistant country read slice
This commit is contained in:
@@ -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