Add runtime service links for lab endpoints

This commit is contained in:
2026-04-23 18:11:16 -06:00
parent 431e667c5e
commit ea55178f9c
10 changed files with 509 additions and 46 deletions
+120 -6
View File
@@ -2,31 +2,56 @@ export const COURSEWARE_RUNTIME_CONFIG_PATH = "/courseware-runtime.json";
export const LAB1_DEFAULT_NETRON_URL = "http://127.0.0.1:8338";
export const LAB2_DEFAULT_OLLAMA_URL = "http://127.0.0.1:11434";
export const LAB2_DEFAULT_OLLAMA_MODELS = [
{
label: "Gemma 4 E2B Q2",
value: "cajina/gemma4_e2b-q2_k_xl:v01",
},
{
label: "Gemma 4 E2B Q4",
value: "batiai/gemma4-e2b:q4",
},
{
label: "Gemma 4 E2B Q8",
value: "bjoernb/gemma4-e2b-fast:latest",
label: "Gemma 4 E2B Q6",
value: "batiai/gemma4-e2b:q6",
},
] as const;
export const LAB3_DEFAULT_TERMINAL_PATH = "/wetty";
export const COURSEWARE_SERVICE_IDS = [
"open-webui",
"promptfoo",
"chunkviz",
"embedding-atlas",
"unsloth",
"ssh",
] as const;
export type CoursewareRuntimeModelOption = {
label: string;
value: string;
};
export type CoursewareServiceId = (typeof COURSEWARE_SERVICE_IDS)[number];
export type CoursewareRuntimeServices = Partial<
Record<CoursewareServiceId, string>
>;
export type ResolvedCoursewareRuntimeServices = Record<
CoursewareServiceId,
string
>;
export const COURSEWARE_SERVICE_DEFAULTS: ResolvedCoursewareRuntimeServices = {
"chunkviz": "http://127.0.0.1:3000",
"embedding-atlas": "http://127.0.0.1:5055",
"open-webui": "http://127.0.0.1:8080",
"promptfoo": "http://127.0.0.1:15500",
"ssh": "ssh://127.0.0.1:22",
"unsloth": "http://127.0.0.1:8888",
};
export type CoursewareRuntimeConfig = {
lab1NetronUrl?: string;
lab2OllamaModels?: CoursewareRuntimeModelOption[];
lab2OllamaUrl?: string;
lab3TerminalUrl?: string;
services?: CoursewareRuntimeServices;
};
export type ResolvedCoursewareRuntimeConfig = {
@@ -34,6 +59,7 @@ export type ResolvedCoursewareRuntimeConfig = {
lab2OllamaModels: CoursewareRuntimeModelOption[];
lab2OllamaUrl: string;
lab3TerminalUrl: string;
services: ResolvedCoursewareRuntimeServices;
};
const loopbackHosts = new Set(["127.0.0.1", "localhost", "::1"]);
@@ -61,6 +87,93 @@ function getCurrentHostname() {
return hostname || undefined;
}
export function isCoursewareServiceId(
value: string,
): value is CoursewareServiceId {
return (COURSEWARE_SERVICE_IDS as readonly string[]).includes(value);
}
export function getCoursewareServiceBaseUrl(
serviceId: CoursewareServiceId,
envValue?: string,
currentHostname = getCurrentHostname(),
) {
const trimmedValue = envValue?.trim();
const baseUrl = trimmedValue || COURSEWARE_SERVICE_DEFAULTS[serviceId];
return rewriteLoopbackHost(baseUrl, currentHostname);
}
export function getCoursewareServices(
envValue?: CoursewareRuntimeServices,
currentHostname = getCurrentHostname(),
): ResolvedCoursewareRuntimeServices {
const services = {} as ResolvedCoursewareRuntimeServices;
for (const serviceId of COURSEWARE_SERVICE_IDS) {
services[serviceId] = getCoursewareServiceBaseUrl(
serviceId,
envValue?.[serviceId],
currentHostname,
);
}
return services;
}
function appendUrlPath(urlValue: string, pathSuffix: string) {
const trimmedSuffix = pathSuffix.trim();
if (!trimmedSuffix) {
return urlValue;
}
try {
const url = new URL(urlValue);
const normalizedSuffix = trimmedSuffix.startsWith("/")
? trimmedSuffix
: `/${trimmedSuffix}`;
const basePath = url.pathname === "/" ? "" : url.pathname.replace(/\/$/, "");
url.pathname = `${basePath}${normalizedSuffix}`;
return url.toString();
} catch {
return urlValue;
}
}
export function resolveCoursewareServiceBaseUrl(
runtimeConfig: Pick<ResolvedCoursewareRuntimeConfig, "services">,
serviceId: CoursewareServiceId,
) {
return runtimeConfig.services[serviceId];
}
export function resolveCoursewareServiceUrl(
runtimeConfig: Pick<ResolvedCoursewareRuntimeConfig, "services">,
serviceId: CoursewareServiceId,
pathSuffix?: string,
) {
const baseUrl = resolveCoursewareServiceBaseUrl(runtimeConfig, serviceId);
if (!pathSuffix?.trim()) {
return baseUrl;
}
return appendUrlPath(baseUrl, pathSuffix);
}
export function resolveCoursewareServiceAddress(
runtimeConfig: Pick<ResolvedCoursewareRuntimeConfig, "services">,
serviceId: CoursewareServiceId,
) {
const baseUrl = resolveCoursewareServiceBaseUrl(runtimeConfig, serviceId);
try {
const url = new URL(baseUrl);
return url.port ? `${url.hostname}:${url.port}` : url.hostname;
} catch {
return baseUrl;
}
}
export function getLab1NetronUrl(
envValue?: string,
currentHostname = getCurrentHostname(),
@@ -145,6 +258,7 @@ export function normalizeCoursewareRuntimeConfig(
config?.lab3TerminalUrl,
currentHostname,
),
services: getCoursewareServices(config?.services, currentHostname),
};
}