feat: diagnose workspace connector bindings

This commit is contained in:
2026-08-03 22:52:29 +02:00
parent e2d1117614
commit ff795d1c91
4 changed files with 656 additions and 1 deletions
+12
View File
@@ -23,9 +23,12 @@ export interface AppConfig {
* pay the probe; the local dev launcher (run-stack.sh) opts in via THT_DWH_PRECHECK.
*/
dwhPrecheck: boolean;
workspaceDiagnosticTimeoutMs: number;
workspaceRegistry: WorkspaceRegistryConfig;
}
export const MAX_WORKSPACE_DIAGNOSTIC_TIMEOUT_MS = 10_000;
function requiredRegistryValue(value: string, label: string): string {
if (value.length === 0 || value.trim() !== value || value.includes("\0")) {
throw new Error(`workspace registry ${label} configuration is invalid`);
@@ -77,6 +80,14 @@ function positiveImportLimit(value: string | undefined, fallback: number): numbe
return limit;
}
function diagnosticTimeout(value: string | undefined): number {
const timeout = Number(value ?? 5_000);
if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > MAX_WORKSPACE_DIAGNOSTIC_TIMEOUT_MS) {
throw new Error("workspace diagnostic timeout configuration is invalid");
}
return timeout;
}
export function loadConfig(env: Record<string, string | undefined>): AppConfig {
const authMode = env.AUTH_MODE ?? "none";
if (!(["none", "mock", "upstream"] as const).includes(authMode as AppConfig["authMode"])) {
@@ -192,6 +203,7 @@ export function loadConfig(env: Record<string, string | undefined>): AppConfig {
secretFiles,
modelApiKeyFile,
dwhPrecheck: env.THT_DWH_PRECHECK === "true" || env.THT_DWH_PRECHECK === "1",
workspaceDiagnosticTimeoutMs: diagnosticTimeout(env.THT_WORKSPACE_DIAGNOSTIC_TIMEOUT_MS),
workspaceRegistry,
};
}
+408
View File
@@ -0,0 +1,408 @@
import { randomUUID } from "node:crypto";
import { MAX_WORKSPACE_DIAGNOSTIC_TIMEOUT_MS } from "../config.js";
import { buildInstallationContract } from "./contracts.js";
import type { RuntimeBindings } from "./runtime-renderer.js";
import { validateCanonicalWorkspace, type CanonicalWorkspace } from "./schema.js";
import type { WorkspaceErrorCode } from "./types.js";
export interface Diagnostic {
level: "error" | "warning" | "info";
code: WorkspaceErrorCode | "binding_ok";
field?: string;
message: string;
}
export interface WorkspaceDiagnostics {
activatable: boolean;
diagnostics: Diagnostic[];
}
type ConnectorRole = "dwh" | "vector";
interface DiagnosticResource {
database?: string;
schema?: string;
collection?: string;
}
export interface ConnectorDiagnosticRequest {
role: ConnectorRole;
transport: "postgres_direct" | "pgvector_direct" | "rest_api" | "ssh_tunnel";
host?: string;
port?: number;
baseUrl?: string;
user?: string;
credentialFile: string;
tlsCaFile?: string;
resource: DiagnosticResource;
timeoutMs: number;
signal: AbortSignal;
}
export interface ConnectorDiagnosticResult {
resolved: boolean;
tlsVerified: boolean;
authenticated: boolean;
resource: DiagnosticResource;
}
export interface SshTunnelRequest {
sshHost: string;
sshPort: number;
sshUser: string;
privateKeyFile: string;
knownHostsFile: string;
targetHost: string;
targetPort: number;
localHost: "127.0.0.1";
localPort: 0;
timeoutMs: number;
signal: AbortSignal;
}
export interface LoopbackTunnel {
host: "127.0.0.1";
port: number;
}
export interface VectorDiagnosticRequest {
collection: string;
timeoutMs: number;
signal: AbortSignal;
}
export interface VectorDiagnosticResult {
collection?: string;
dimensions?: number;
distance?: "cosine" | "l2" | "inner_product";
}
export interface EmbeddingDiagnosticRequest {
baseUrl: string;
credentialFile?: string;
tlsCaFile?: string;
model: string;
timeoutMs: number;
signal: AbortSignal;
}
export interface EmbeddingDiagnosticResult {
available: boolean;
dimensions?: number;
}
export interface WriteDiagnosticRecordRequest {
collection: string;
id: string;
dimensions: number;
timeoutMs: number;
signal: AbortSignal;
}
/**
* Adapters own protocol-specific I/O. They receive only binding file paths, never secret
* contents, and return metadata only; response bodies must stay inside the adapter.
*/
export interface DiagnosticAdapters {
probeConnector(request: ConnectorDiagnosticRequest): Promise<ConnectorDiagnosticResult>;
withSshTunnel<T>(
request: SshTunnelRequest,
probe: (tunnel: LoopbackTunnel) => Promise<T>,
): Promise<T>;
inspectVector(request: VectorDiagnosticRequest): Promise<VectorDiagnosticResult>;
probeEmbedding(request: EmbeddingDiagnosticRequest): Promise<EmbeddingDiagnosticResult>;
writeDiagnosticRecord(request: WriteDiagnosticRecordRequest): Promise<void>;
removeDiagnosticRecord(request: WriteDiagnosticRecordRequest): Promise<void>;
}
export const DEFAULT_WORKSPACE_DIAGNOSTIC_TIMEOUT_MS = 5_000;
function unavailableAdapters(): DiagnosticAdapters {
const unavailable = async (): Promise<never> => {
throw new Error("diagnostic adapter unavailable");
};
return {
probeConnector: unavailable,
withSshTunnel: unavailable,
inspectVector: unavailable,
probeEmbedding: unavailable,
writeDiagnosticRecord: unavailable,
removeDiagnosticRecord: unavailable,
};
}
function boundedTimeout(value: number | undefined, fallback: number): number {
const selected = value ?? fallback;
return Math.min(Math.max(1, selected), fallback, MAX_WORKSPACE_DIAGNOSTIC_TIMEOUT_MS);
}
async function withTimeout<T>(timeoutMs: number, operation: (signal: AbortSignal) => Promise<T>): Promise<T> {
const controller = new AbortController();
let timer: NodeJS.Timeout | undefined;
try {
return await new Promise<T>((resolve, reject) => {
timer = setTimeout(() => {
controller.abort();
reject(new Error("diagnostic timed out"));
}, timeoutMs);
void operation(controller.signal).then(resolve, reject);
});
} finally {
if (timer !== undefined) clearTimeout(timer);
controller.abort();
}
}
function sameResource(expected: DiagnosticResource, actual: DiagnosticResource): boolean {
return Object.entries(expected).every(([key, value]) => actual[key as keyof DiagnosticResource] === value);
}
function hasRequiredConnectorChecks(result: ConnectorDiagnosticResult, resource: DiagnosticResource): boolean {
return result.resolved && result.tlsVerified && result.authenticated && sameResource(resource, result.resource);
}
function diagnosticError(code: WorkspaceErrorCode, field?: string): Diagnostic {
return {
level: "error",
code,
...(field ? { field } : {}),
message: code === "binding_missing"
? "Installation binding is missing or invalid."
: code === "semantic_index_incompatible"
? "Semantic index metadata is incompatible with this workspace."
: "Connector diagnostic failed.",
};
}
function bindingName(
workspace: CanonicalWorkspace,
role: "DWH" | "VECTOR" | "EMBEDDING",
suffix: string,
): string {
const entry = buildInstallationContract(workspace).variables.find((variable) => (
variable.role === role && variable.suffix === suffix
));
if (!entry) throw new Error(`workspace contract is missing ${role}_${suffix}`);
return entry.name;
}
function numericBinding(binding: Record<string, string>, name: string): number | undefined {
const value = Number(binding[name]);
return Number.isInteger(value) && value > 0 && value <= 65_535 ? value : undefined;
}
function diagnosticsForMissingBindings(
workspace: CanonicalWorkspace,
bindings: RuntimeBindings,
): Diagnostic[] {
const missing = new Set([
...bindings.dwh.missing,
...bindings.vector.missing,
...bindings.embedding.missing,
]);
const knownHosts = [
bindings.dwh.transport === "ssh_tunnel" ? bindingName(workspace, "DWH", "SSH_KNOWN_HOSTS_FILE") : undefined,
bindings.vector.transport === "ssh_tunnel" ? bindingName(workspace, "VECTOR", "SSH_KNOWN_HOSTS_FILE") : undefined,
].filter((field): field is string => field !== undefined);
const ordered = [...new Set([...knownHosts.filter((field) => missing.has(field)), ...[...missing].sort()])];
return ordered.map((field) => diagnosticError("binding_missing", field));
}
function connectorRequest(
workspace: CanonicalWorkspace,
role: ConnectorRole,
bindings: RuntimeBindings,
timeoutMs: number,
): ConnectorDiagnosticRequest | SshTunnelRequest | undefined {
const binding = role === "dwh" ? bindings.dwh : bindings.vector;
const contractRole = role === "dwh" ? "DWH" : "VECTOR";
const values = binding.values;
const resource: DiagnosticResource = role === "dwh"
? { database: workspace.dwh.database, schema: workspace.dwh.schema }
: { collection: workspace.semantic_index.vector_store.collection };
const field = (suffix: string) => bindingName(workspace, contractRole, suffix);
const credentialFile = values[field(binding.transport === "rest_api" ? "API_KEY_FILE" : "PASSWORD_FILE")];
if (credentialFile === undefined) return undefined;
if (binding.transport === "rest_api") {
const baseUrl = values[field("BASE_URL")];
if (baseUrl === undefined) return undefined;
return {
role,
transport: "rest_api",
baseUrl,
credentialFile,
tlsCaFile: values[field("TLS_CA_FILE")],
resource,
timeoutMs,
signal: new AbortController().signal,
};
}
if (binding.transport === "ssh_tunnel") {
const sshHost = values[field("SSH_HOST")];
const sshPort = numericBinding(values, field("SSH_PORT"));
const sshUser = values[field("SSH_USER")];
const privateKeyFile = values[field("SSH_PRIVATE_KEY_FILE")];
const knownHostsFile = values[field("SSH_KNOWN_HOSTS_FILE")];
const targetHost = values[field("SSH_TARGET_HOST")];
const targetPort = numericBinding(values, field("SSH_TARGET_PORT"));
if (!sshHost || !sshPort || !sshUser || !privateKeyFile || !knownHostsFile || !targetHost || !targetPort) return undefined;
return {
sshHost, sshPort, sshUser, privateKeyFile, knownHostsFile, targetHost, targetPort,
localHost: "127.0.0.1", localPort: 0, timeoutMs, signal: new AbortController().signal,
};
}
const host = values[field("HOST")];
const port = numericBinding(values, field("PORT"));
const user = values[field("USER")];
if (!host || !port || !user) return undefined;
return {
role,
transport: binding.transport,
host,
port,
user,
credentialFile,
tlsCaFile: values[field("TLS_CA_FILE")],
resource,
timeoutMs,
signal: new AbortController().signal,
};
}
function tunnelProbeRequest(
workspace: CanonicalWorkspace,
role: ConnectorRole,
bindings: RuntimeBindings,
timeoutMs: number,
tunnel: LoopbackTunnel,
signal: AbortSignal,
): ConnectorDiagnosticRequest {
const binding = role === "dwh" ? bindings.dwh : bindings.vector;
const contractRole = role === "dwh" ? "DWH" : "VECTOR";
const password = binding.values[bindingName(workspace, contractRole, "PASSWORD_FILE")];
const user = binding.values[bindingName(workspace, contractRole, "USER")];
if (!password || !user) throw new Error("missing SSH connector credentials");
return {
role,
transport: "ssh_tunnel",
host: tunnel.host,
port: tunnel.port,
user,
credentialFile: password,
tlsCaFile: binding.values[bindingName(workspace, contractRole, "TLS_CA_FILE")],
resource: role === "dwh"
? { database: workspace.dwh.database, schema: workspace.dwh.schema }
: { collection: workspace.semantic_index.vector_store.collection },
timeoutMs,
signal,
};
}
export function createWorkspaceDiagnoser(
adapters: DiagnosticAdapters,
options: { timeoutMs?: number } = {},
) {
const fallbackTimeout = boundedTimeout(options.timeoutMs, DEFAULT_WORKSPACE_DIAGNOSTIC_TIMEOUT_MS);
return async function diagnoseWorkspace(
workspace: CanonicalWorkspace,
bindings: RuntimeBindings,
options: { writeProbe: boolean },
): Promise<WorkspaceDiagnostics> {
const canonical = validateCanonicalWorkspace(workspace);
const diagnostics = diagnosticsForMissingBindings(canonical, bindings);
if (diagnostics.length > 0) return { activatable: false, diagnostics };
const dwhTimeout = boundedTimeout(canonical.dwh.timeout_ms, fallbackTimeout);
const vectorTimeout = boundedTimeout(canonical.semantic_index.vector_store.timeout_ms, fallbackTimeout);
const embeddingTimeout = boundedTimeout(canonical.semantic_index.embedding.timeout_ms, fallbackTimeout);
for (const role of ["dwh", "vector"] as const) {
const timeoutMs = role === "dwh" ? dwhTimeout : vectorTimeout;
const request = connectorRequest(canonical, role, bindings, timeoutMs);
if (!request) {
diagnostics.push(diagnosticError("binding_missing"));
continue;
}
try {
const result = "sshHost" in request
? await withTimeout(timeoutMs, (signal) => adapters.withSshTunnel(
{ ...request, signal },
(tunnel) => adapters.probeConnector(tunnelProbeRequest(
canonical, role, bindings, timeoutMs, tunnel, signal,
)),
))
: await withTimeout(timeoutMs, (signal) => adapters.probeConnector({ ...request, signal }));
const resource = role === "dwh"
? { database: canonical.dwh.database, schema: canonical.dwh.schema }
: { collection: canonical.semantic_index.vector_store.collection };
if (!hasRequiredConnectorChecks(result, resource)) diagnostics.push(diagnosticError("connector_unavailable"));
else diagnostics.push({ level: "info", code: "binding_ok", message: `${role === "dwh" ? "DWH" : "Vector"} binding diagnostic passed.` });
} catch {
diagnostics.push(diagnosticError("connector_unavailable"));
}
}
if (!diagnostics.some((diagnostic) => diagnostic.level === "error")) {
try {
const vector = await withTimeout(vectorTimeout, (signal) => adapters.inspectVector({
collection: canonical.semantic_index.vector_store.collection,
timeoutMs: vectorTimeout,
signal,
}));
const expected = canonical.semantic_index.vector_store;
if (
vector.collection !== expected.collection
|| vector.dimensions !== expected.dimensions
|| vector.distance !== expected.distance
) diagnostics.push(diagnosticError("semantic_index_incompatible"));
} catch {
diagnostics.push(diagnosticError("connector_unavailable"));
}
}
if (!diagnostics.some((diagnostic) => diagnostic.level === "error")) {
try {
const embedding = await withTimeout(embeddingTimeout, (signal) => adapters.probeEmbedding({
baseUrl: bindings.embedding.values[bindingName(canonical, "EMBEDDING", "BASE_URL")] ?? "",
credentialFile: bindings.embedding.values[bindingName(canonical, "EMBEDDING", "API_KEY_FILE")],
tlsCaFile: bindings.embedding.values[bindingName(canonical, "EMBEDDING", "TLS_CA_FILE")],
model: canonical.semantic_index.embedding.model,
timeoutMs: embeddingTimeout,
signal,
}));
if (!embedding.available || embedding.dimensions !== canonical.semantic_index.embedding.dimensions) {
diagnostics.push(diagnosticError("semantic_index_incompatible"));
}
} catch {
diagnostics.push(diagnosticError("connector_unavailable"));
}
}
if (options.writeProbe && !diagnostics.some((diagnostic) => diagnostic.level === "error")) {
const request: WriteDiagnosticRecordRequest = {
collection: canonical.semantic_index.vector_store.collection,
id: `diagnostic:${randomUUID()}`,
dimensions: canonical.semantic_index.vector_store.dimensions,
timeoutMs: vectorTimeout,
signal: new AbortController().signal,
};
try {
await withTimeout(vectorTimeout, (signal) => adapters.writeDiagnosticRecord({ ...request, signal }));
await withTimeout(vectorTimeout, (signal) => adapters.removeDiagnosticRecord({ ...request, signal }));
} catch {
diagnostics.push(diagnosticError("connector_unavailable"));
}
}
return {
activatable: !diagnostics.some((diagnostic) => diagnostic.level === "error"),
diagnostics,
};
};
}
export const diagnoseWorkspace = createWorkspaceDiagnoser(unavailableAdapters());
+235
View File
@@ -0,0 +1,235 @@
import { expect, test, vi } from "vitest";
import {
createWorkspaceDiagnoser,
type DiagnosticAdapters,
} from "../src/workspaces/diagnostics.js";
import type { RuntimeBindings } from "../src/workspaces/runtime-renderer.js";
import { parseWorkspaceYaml } from "../src/workspaces/schema.js";
const workspace = parseWorkspaceYaml(`workspace:
schema_version: 1
id: psd-clinical
name: Policlinico San Donato
language: it
dwh:
engine: postgres
database: warehouse
schema: datawarehouse
timeout_ms: 8000
supported_transports: [postgres_direct, rest_api, ssh_tunnel]
semantic_index:
vector_store:
engine: pgvector
collection: clinical_documents
dimensions: 768
distance: cosine
timeout_ms: 8000
supported_transports: [pgvector_direct, rest_api, ssh_tunnel]
embedding:
provider: ollama_compatible
model: nomic-embed-text-v2-moe
dimensions: 768
timeout_ms: 8000
llm_policy:
allowed: [zai/glm-5.2]
`);
const bindings: RuntimeBindings = {
dwh: {
transport: "postgres_direct",
missing: [],
values: {
THT_WS_PSD_CLINICAL_DWH_HOST: "dwh.example.test",
THT_WS_PSD_CLINICAL_DWH_PORT: "5432",
THT_WS_PSD_CLINICAL_DWH_USER: "reader",
THT_WS_PSD_CLINICAL_DWH_PASSWORD_FILE: "/run/secrets/dwh-password",
THT_WS_PSD_CLINICAL_DWH_TLS_CA_FILE: "/run/secrets/dwh-ca",
},
},
vector: {
transport: "pgvector_direct",
missing: [],
values: {
THT_WS_PSD_CLINICAL_VECTOR_HOST: "vector.example.test",
THT_WS_PSD_CLINICAL_VECTOR_PORT: "5432",
THT_WS_PSD_CLINICAL_VECTOR_USER: "vector-reader",
THT_WS_PSD_CLINICAL_VECTOR_PASSWORD_FILE: "/run/secrets/vector-password",
THT_WS_PSD_CLINICAL_VECTOR_TLS_CA_FILE: "/run/secrets/vector-ca",
},
},
embedding: {
transport: "rest_api",
missing: [],
values: {
THT_WS_PSD_CLINICAL_EMBEDDING_BASE_URL: "https://embedding.example.test",
THT_WS_PSD_CLINICAL_EMBEDDING_API_KEY_FILE: "/run/secrets/embedding-key",
THT_WS_PSD_CLINICAL_EMBEDDING_TLS_CA_FILE: "/run/secrets/embedding-ca",
},
},
};
function successfulAdapters(overrides: Partial<DiagnosticAdapters> = {}): DiagnosticAdapters {
return {
probeConnector: vi.fn(async (request) => ({
resolved: true,
tlsVerified: true,
authenticated: true,
resource: request.resource,
})),
withSshTunnel: vi.fn(async (_request, probe) => probe({ host: "127.0.0.1", port: 45678 })),
inspectVector: vi.fn(async () => ({
collection: "clinical_documents",
dimensions: 768,
distance: "cosine",
})),
probeEmbedding: vi.fn(async () => ({ available: true, dimensions: 768 })),
writeDiagnosticRecord: vi.fn(async () => undefined),
removeDiagnosticRecord: vi.fn(async () => undefined),
...overrides,
};
}
function diagnose(adapters = successfulAdapters()) {
return createWorkspaceDiagnoser(adapters, { timeoutMs: 5000 });
}
test("reports the missing vector collection dimensions as semantic-index incompatibility", async () => {
const result = await diagnose(successfulAdapters({
inspectVector: vi.fn(async () => ({
collection: "clinical_documents",
dimensions: undefined,
distance: "cosine",
})),
}))(workspace, bindings, { writeProbe: false });
expect(result.diagnostics).toContainEqual(expect.objectContaining({
code: "semantic_index_incompatible",
}));
expect(result.activatable).toBe(false);
});
test("refuses an SSH tunnel when known-hosts is missing", async () => {
const sshBindingsWithoutKnownHosts: RuntimeBindings = {
...bindings,
dwh: {
transport: "ssh_tunnel",
missing: ["THT_WS_PSD_CLINICAL_DWH_SSH_KNOWN_HOSTS_FILE"],
values: {
THT_WS_PSD_CLINICAL_DWH_USER: "reader",
THT_WS_PSD_CLINICAL_DWH_PASSWORD_FILE: "/run/secrets/dwh-password",
THT_WS_PSD_CLINICAL_DWH_SSH_HOST: "bastion.example.test",
THT_WS_PSD_CLINICAL_DWH_SSH_PORT: "22",
THT_WS_PSD_CLINICAL_DWH_SSH_USER: "tunnel",
THT_WS_PSD_CLINICAL_DWH_SSH_PRIVATE_KEY_FILE: "/run/secrets/ssh-key",
THT_WS_PSD_CLINICAL_DWH_SSH_TARGET_HOST: "dwh.internal",
THT_WS_PSD_CLINICAL_DWH_SSH_TARGET_PORT: "5432",
},
},
};
const adapters = successfulAdapters();
const result = await diagnose(adapters)(workspace, sshBindingsWithoutKnownHosts, { writeProbe: false });
expect(result.activatable).toBe(false);
expect(result.diagnostics[0]).toMatchObject({
code: "binding_missing",
field: expect.stringContaining("SSH_KNOWN_HOSTS_FILE"),
});
expect(adapters.withSshTunnel).not.toHaveBeenCalled();
});
test("checks direct and REST resolution, TLS, authentication, and resource metadata without exposing failures", async () => {
const adapters = successfulAdapters({
probeConnector: vi.fn(async (request) => ({
resolved: true,
tlsVerified: true,
authenticated: true,
resource: request.role === "dwh"
? { database: "warehouse", schema: "wrong_schema" }
: request.resource,
})),
});
const restBindings: RuntimeBindings = {
...bindings,
dwh: {
transport: "rest_api",
missing: [],
values: {
THT_WS_PSD_CLINICAL_DWH_BASE_URL: "https://dwh.example.test",
THT_WS_PSD_CLINICAL_DWH_API_KEY_FILE: "/run/secrets/dwh-api-key",
THT_WS_PSD_CLINICAL_DWH_TLS_CA_FILE: "/run/secrets/dwh-ca",
},
},
};
const result = await diagnose(adapters)(workspace, restBindings, { writeProbe: false });
expect(adapters.probeConnector).toHaveBeenCalledWith(expect.objectContaining({
transport: "rest_api",
timeoutMs: 5000,
tlsCaFile: "/run/secrets/dwh-ca",
credentialFile: "/run/secrets/dwh-api-key",
resource: { database: "warehouse", schema: "datawarehouse" },
}));
expect(result).toMatchObject({ activatable: false });
expect(JSON.stringify(result)).not.toContain("wrong_schema");
expect(JSON.stringify(result)).not.toContain("/run/secrets/dwh-api-key");
});
test("uses a loopback-only SSH tunnel for the bounded connector probe", async () => {
const adapters = successfulAdapters();
const sshBindings: RuntimeBindings = {
...bindings,
dwh: {
transport: "ssh_tunnel",
missing: [],
values: {
THT_WS_PSD_CLINICAL_DWH_USER: "reader",
THT_WS_PSD_CLINICAL_DWH_PASSWORD_FILE: "/run/secrets/dwh-password",
THT_WS_PSD_CLINICAL_DWH_TLS_CA_FILE: "/run/secrets/dwh-ca",
THT_WS_PSD_CLINICAL_DWH_SSH_HOST: "bastion.example.test",
THT_WS_PSD_CLINICAL_DWH_SSH_PORT: "22",
THT_WS_PSD_CLINICAL_DWH_SSH_USER: "tunnel",
THT_WS_PSD_CLINICAL_DWH_SSH_PRIVATE_KEY_FILE: "/run/secrets/ssh-key",
THT_WS_PSD_CLINICAL_DWH_SSH_KNOWN_HOSTS_FILE: "/run/secrets/known-hosts",
THT_WS_PSD_CLINICAL_DWH_SSH_TARGET_HOST: "dwh.internal",
THT_WS_PSD_CLINICAL_DWH_SSH_TARGET_PORT: "5432",
},
},
};
const result = await diagnose(adapters)(workspace, sshBindings, { writeProbe: false });
expect(result.activatable).toBe(true);
expect(adapters.withSshTunnel).toHaveBeenCalledWith(expect.objectContaining({
localHost: "127.0.0.1",
localPort: 0,
knownHostsFile: "/run/secrets/known-hosts",
timeoutMs: 5000,
}), expect.any(Function));
expect(adapters.probeConnector).toHaveBeenCalledWith(expect.objectContaining({
host: "127.0.0.1",
port: 45678,
}));
});
test("requires a matching embedding model vector and removes its unique write probe", async () => {
const adapters = successfulAdapters();
const result = await diagnose(adapters)(workspace, bindings, { writeProbe: true });
expect(result.activatable).toBe(true);
expect(adapters.probeEmbedding).toHaveBeenCalledWith(expect.objectContaining({
model: "nomic-embed-text-v2-moe",
timeoutMs: 5000,
}));
expect(adapters.writeDiagnosticRecord).toHaveBeenCalledWith(expect.objectContaining({
collection: "clinical_documents",
id: expect.stringMatching(/^diagnostic:/),
dimensions: 768,
}));
expect(adapters.removeDiagnosticRecord).toHaveBeenCalledWith(expect.objectContaining({
collection: "clinical_documents",
id: expect.stringMatching(/^diagnostic:/),
}));
});
+1 -1
View File
@@ -17,7 +17,7 @@ ARG PI_VERSION
# Runtime tools
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates ripgrep fd-find tini \
curl ca-certificates ripgrep fd-find tini git openssh-client \
&& rm -rf /var/lib/apt/lists/* \
&& ln -s /usr/bin/fdfind /usr/local/bin/fd