Files
Nexus/packages/api/src/router/assistant-tools/country-readmodels.ts
T
Hartmut b41c1d2501
CI / Architecture Guardrails (push) Successful in 2m38s
CI / Assistant Split Regression (push) Successful in 3m33s
CI / Typecheck (push) Successful in 3m51s
CI / Lint (push) Successful in 5m2s
CI / E2E Tests (push) Has been cancelled
CI / Fresh-Linux Docker Deploy (push) Has been cancelled
CI / Release Images (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
rename(phase 1): CapaKraken → Nexus across code, UI, docs, CI (#61)
rename(phase 1): CapaKraken → Nexus across code, UI, docs, CI (#61)

Co-authored-by: Hartmut Nörenberg <hn@hartmut-noerenberg.com>
Co-committed-by: Hartmut Nörenberg <hn@hartmut-noerenberg.com>
2026-05-21 16:28:40 +02:00

110 lines
3.5 KiB
TypeScript

import type { Prisma } from "@nexus/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);
},
};
}