import type { GpuDevice } from "@aicommander/protocol"; /** * Deciding whether a `gpuIndex` a caller sent can name a card ON THIS MACHINE. * * Pure validation against the device list supplied by JobManager.setKnownGpus. * Disk access stays in the job store; hardware probing stays in gpu.ts, driven * by connection.ts. * * Two bounds, deliberately different in kind: * - JOB_MAX_GPU_INDEX is a NAMESPACE bound (0..4095 = the `gpu-.lock` names * we may ever create). It says nothing about hardware, and it is what made * `gpuIndex: 7` on a one-card box a perfectly acceptable request that then * ran with CUDA_VISIBLE_DEVICES=7, found no card, and either died hours later * or silently fell back to CPU. * - the known device list is a HARDWARE bound, and it is only consulted when we * actually have one. `probeGpuState()` is what tells those two apart, and it * is deliberately STINGY with confidence: ONLY a clean `nvidia-smi` run that * reported zero devices yields a CONFIDENT empty list. An absent binary (it * may simply be off the service's minimal PATH), a wedged driver, a * `nvidia-smi` that would not fork on a loaded box, or output that parsed * only in part are all "we could not tell". So an unknown list * (`null` here) must stay PERMISSIVE: * refusing a legitimate training run because the probe hiccuped would be a * worse bug than the one this fixes. */ /** What `JobManager` knows about this machine's cards; `null` = we do not know. */ export type KnownGpus = readonly GpuDevice[] | null; /** Either the value to use, or the sentence to refuse the request with. */ export type GpuIndexDecision = { gpuIndex: number | null; } | { invalid: string; }; /** * A gpuIndex from the wire. Anything that is not a plausible device index cannot * name a card on ANY machine, so it comes back as an `invalid_request` refusal — * never as a silently dropped field, which would start an unreserved GPU job and * cause the exact OOM collision the lock exists to prevent. * * The hardware check answers the same class of question — "retrying this exact * request fails identically" — so it is the same `invalid_request` refusal, not * a machine error. And it is worded like the `gpu_busy` message it sits next to: * name the culprit, then give the concrete ways out, because the caller is an * agent that has to pick one without asking anybody. * * Returns either the normalized value or the refusal text; wrapping the number * keeps `null` (no GPU asked for) distinguishable from a refusal without another * sentinel. */ export declare function decideGpuIndex(value: unknown, known: KnownGpus): GpuIndexDecision; /** * The card list as a caller-facing phrase: `[0] RTX 5080, [1] RTX 4090`. * * Names are re-sanitised here even though gpu.ts already did it at the probe: * this string is authored INTO a refusal an LLM reads, and the payload-safety * invariant does not get to assume the value took the path we expect. */ export declare function describeGpus(known: readonly GpuDevice[]): string;