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) Co-authored-by: Hartmut Nörenberg <hn@hartmut-noerenberg.com> Co-committed-by: Hartmut Nörenberg <hn@hartmut-noerenberg.com>
110 lines
3.5 KiB
TypeScript
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);
|
|
},
|
|
};
|
|
}
|