omnius 1.0.695 → 1.0.697
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/py-embed.js +4215 -2598
- package/dist/index.js +41242 -35198
- package/dist/library.js +8063 -6080
- package/dist/python-cuda-runtime.js +512 -0
- package/dist/update-worker.js +4250 -2633
- package/docs/DISCOVERY.json +802 -1
- package/docs/DISCOVERY.md +22 -1
- package/docs/guides/long-horizon-feature-workflow.md +42 -0
- package/docs/research/aiwg-long-horizon-feature-workflow.md +94 -0
- package/docs/work-orders/long-horizon-feature-delivery/WO-01-native-research-feature-workflow.md +122 -0
- package/docs/work-orders/runtime-health-remediation/TOOL-QUALITY-2026-09-05.md +84 -0
- package/docs/work-orders/runtime-health-remediation/TRACKER.md +48 -1
- package/docs/work-orders/runtime-health-remediation/WO-30-structured-tool-invocation.md +65 -0
- package/docs/work-orders/runtime-health-remediation/WO-31-complete-runtime-policy.md +62 -0
- package/docs/work-orders/runtime-health-remediation/WO-32-evidence-dependent-steering.md +55 -0
- package/docs/work-orders/runtime-health-remediation/WO-33-file-mutation-transactions.md +55 -0
- package/docs/work-orders/runtime-health-remediation/WO-34-shell-authority-and-results.md +46 -0
- package/docs/work-orders/runtime-health-remediation/WO-35-search-and-exploration-isolation.md +56 -0
- package/docs/work-orders/runtime-health-remediation/WO-36-media-evidence-integrity.md +44 -0
- package/docs/work-orders/runtime-health-remediation/WO-37-browser-and-process-lifecycle.md +86 -0
- package/docs/work-orders/runtime-health-remediation/WO-37-point-localization-cancellation.md +24 -0
- package/docs/work-orders/runtime-health-remediation/WO-38-tool-contract-preservation.md +83 -0
- package/docs/work-orders/runtime-health-remediation/WO-39-telegram-working-indicator.md +76 -0
- package/docs/work-orders/runtime-health-remediation/WO-40-web-content-and-crawl-receipts.md +44 -0
- package/docs/work-orders/runtime-health-remediation/WO-41-completion-evidence-consistency.md +45 -0
- package/docs/work-orders/runtime-health-remediation/WO-42-media-execution-and-configuration.md +79 -0
- package/docs/work-orders/runtime-health-remediation/WO-43-telegram-router-progress-boundary.md +71 -0
- package/docs/work-orders/runtime-health-remediation/WO-44-evidence-backed-terminal-results.md +56 -0
- package/docs/work-orders/runtime-health-remediation/WO-45-native-ollama-tool-contract.md +33 -0
- package/npm-shrinkwrap.json +5 -5
- package/package.json +1 -1
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
import { createRequire as __omnius_createRequire } from "node:module"; import { fileURLToPath as __omnius_fileURLToPath } from "node:url"; import { dirname as __omnius_dirname } from "node:path"; const require = __omnius_createRequire(import.meta.url); const __filename = __omnius_fileURLToPath(import.meta.url); const __dirname = __omnius_dirname(__filename);
|
|
2
|
+
|
|
3
|
+
// packages/execution/src/python-cuda-runtime.ts
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { arch, homedir, platform as platform2 } from "node:os";
|
|
7
|
+
import { dirname, join as join2 } from "node:path";
|
|
8
|
+
|
|
9
|
+
// packages/execution/src/jetson-monitor.ts
|
|
10
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
11
|
+
import { platform } from "node:os";
|
|
12
|
+
var _isJetsonHost = null;
|
|
13
|
+
function isJetsonHost() {
|
|
14
|
+
if (_isJetsonHost !== null) return _isJetsonHost;
|
|
15
|
+
if (platform() !== "linux") {
|
|
16
|
+
_isJetsonHost = false;
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
if (existsSync("/etc/nv_tegra_release") || existsSync("/sys/module/tegra_fuse")) {
|
|
20
|
+
_isJetsonHost = true;
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const model = readFileSync("/proc/device-tree/model", "utf8").replace(/\0/g, " ");
|
|
25
|
+
_isJetsonHost = /\b(nvidia|jetson|orin|tegra)\b/i.test(model);
|
|
26
|
+
} catch {
|
|
27
|
+
_isJetsonHost = false;
|
|
28
|
+
}
|
|
29
|
+
return _isJetsonHost;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// packages/execution/src/venv-paths.ts
|
|
33
|
+
import { join } from "node:path";
|
|
34
|
+
var isWin = process.platform === "win32";
|
|
35
|
+
function venvPython(venvDir) {
|
|
36
|
+
return isWin ? join(venvDir, "Scripts", "python.exe") : join(venvDir, "bin", "python");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// packages/execution/src/python-cuda-runtime.ts
|
|
40
|
+
function managedVenvUsesSystemSitePackages(venvDir) {
|
|
41
|
+
try {
|
|
42
|
+
const value = readFileSync2(join2(venvDir, "pyvenv.cfg"), "utf8");
|
|
43
|
+
const match = value.match(/^include-system-site-packages\s*=\s*(true|false)\s*$/mi);
|
|
44
|
+
if (!match) return void 0;
|
|
45
|
+
return match[1]?.toLowerCase() === "true";
|
|
46
|
+
} catch {
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function run(command, args, timeout, env) {
|
|
51
|
+
const result = spawnSync(command, args, {
|
|
52
|
+
encoding: "utf8",
|
|
53
|
+
env,
|
|
54
|
+
timeout,
|
|
55
|
+
maxBuffer: 16 * 1024 * 1024
|
|
56
|
+
});
|
|
57
|
+
const output = `${result.stdout ?? ""}
|
|
58
|
+
${result.stderr ?? ""}`.trim();
|
|
59
|
+
return {
|
|
60
|
+
ok: !result.error && result.status === 0,
|
|
61
|
+
output: result.error ? `${output}
|
|
62
|
+
${result.error.message}`.trim() : output
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function isNvidiaArmCudaHost() {
|
|
66
|
+
if (platform2() !== "linux" || !["arm64", "arm"].includes(arch())) return false;
|
|
67
|
+
return isJetsonHost() || existsSync2("/usr/local/cuda/targets/aarch64-linux") || Boolean(process.env["JETSON_L4T_VERSION"]);
|
|
68
|
+
}
|
|
69
|
+
function probeCudaTorchSync(python, env = process.env) {
|
|
70
|
+
const code = [
|
|
71
|
+
"import json,torch",
|
|
72
|
+
"assert torch.cuda.is_available(), f'CUDA unavailable (torch={torch.__version__}, torch_cuda={torch.version.cuda})'",
|
|
73
|
+
"p=torch.cuda.get_device_properties(0)",
|
|
74
|
+
"free,total=torch.cuda.mem_get_info(0)",
|
|
75
|
+
"major,minor=torch.cuda.get_device_capability(0)",
|
|
76
|
+
"print(json.dumps({'torch':torch.__version__,'torchCuda':torch.version.cuda,'torchFile':torch.__file__,'device':p.name,'major':major,'minor':minor,'total':total,'free':free}))"
|
|
77
|
+
].join(";");
|
|
78
|
+
const result = run(python, ["-c", code], 6e4, env);
|
|
79
|
+
if (!result.ok) return { ok: false, python, output: result.output };
|
|
80
|
+
try {
|
|
81
|
+
const line = result.output.split(/\r?\n/).slice().reverse().find((value) => value.trim().startsWith("{"));
|
|
82
|
+
const parsed = JSON.parse(line || "{}");
|
|
83
|
+
return {
|
|
84
|
+
ok: true,
|
|
85
|
+
python,
|
|
86
|
+
output: result.output,
|
|
87
|
+
torchVersion: parsed.torch,
|
|
88
|
+
torchCudaVersion: parsed.torchCuda,
|
|
89
|
+
deviceName: parsed.device,
|
|
90
|
+
computeCapability: Number(`${parsed.major ?? 0}.${parsed.minor ?? 0}`),
|
|
91
|
+
totalMemoryBytes: Number(parsed.total ?? 0),
|
|
92
|
+
freeMemoryBytes: Number(parsed.free ?? 0),
|
|
93
|
+
torchModulePath: parsed.torchFile
|
|
94
|
+
};
|
|
95
|
+
} catch {
|
|
96
|
+
return { ok: false, python, output: `Invalid CUDA Torch probe output: ${result.output}` };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function resolveVendorCudaPythonSync(preferredPython = "python3", env = process.env) {
|
|
100
|
+
const candidates = [
|
|
101
|
+
env["OMNIUS_JETPACK_PYTHON"]?.trim(),
|
|
102
|
+
env["OMNIUS_CUDA_PYTHON"]?.trim(),
|
|
103
|
+
preferredPython.trim()
|
|
104
|
+
];
|
|
105
|
+
const userHome = homedir();
|
|
106
|
+
candidates.push(
|
|
107
|
+
join2(userHome, ".venv", "bin", "python"),
|
|
108
|
+
join2(userHome, ".venv", "bin", "python3")
|
|
109
|
+
);
|
|
110
|
+
for (const parent of ["Documents", "Projects", "projects", "workspace"]) {
|
|
111
|
+
const root = join2(userHome, parent);
|
|
112
|
+
try {
|
|
113
|
+
for (const entry of readdirSync(root, { withFileTypes: true }).slice(0, 256)) {
|
|
114
|
+
if (!entry.isDirectory()) continue;
|
|
115
|
+
candidates.push(
|
|
116
|
+
join2(root, entry.name, ".venv", "bin", "python"),
|
|
117
|
+
join2(root, entry.name, ".venv", "bin", "python3"),
|
|
118
|
+
join2(root, entry.name, "venv", "bin", "python"),
|
|
119
|
+
join2(root, entry.name, "venv", "bin", "python3")
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
} catch {
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const nestedRoots = ["Documents", "Projects", "projects", "workspace", "Work", "src"].map((name) => join2(userHome, name));
|
|
126
|
+
const pending = nestedRoots.map((root) => ({ root, depth: 0 }));
|
|
127
|
+
const skipped = /* @__PURE__ */ new Set([".git", ".cache", ".npm", ".pnpm-store", "node_modules", "dist", "build", "models", "runtimes"]);
|
|
128
|
+
let inspected = 0;
|
|
129
|
+
while (pending.length > 0 && inspected < 768) {
|
|
130
|
+
const current = pending.shift();
|
|
131
|
+
inspected++;
|
|
132
|
+
try {
|
|
133
|
+
const entries = readdirSync(current.root, { withFileTypes: true }).slice(0, 256);
|
|
134
|
+
for (const entry of entries) {
|
|
135
|
+
if (!entry.isDirectory() || skipped.has(entry.name)) continue;
|
|
136
|
+
const child = join2(current.root, entry.name);
|
|
137
|
+
if (entry.name === ".venv" || entry.name === "venv") {
|
|
138
|
+
candidates.push(join2(child, "bin", "python"), join2(child, "bin", "python3"));
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (entry.name.startsWith(".") || current.depth >= 4) continue;
|
|
142
|
+
pending.push({ root: child, depth: current.depth + 1 });
|
|
143
|
+
}
|
|
144
|
+
} catch {
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
candidates.push(
|
|
148
|
+
"/usr/bin/python3",
|
|
149
|
+
"/usr/local/bin/python3",
|
|
150
|
+
"python3"
|
|
151
|
+
);
|
|
152
|
+
const availableCandidates = candidates.filter((candidate) => {
|
|
153
|
+
if (!candidate) return false;
|
|
154
|
+
return !candidate.includes("/") || existsSync2(candidate);
|
|
155
|
+
});
|
|
156
|
+
const seen = /* @__PURE__ */ new Set();
|
|
157
|
+
let firstFailure = null;
|
|
158
|
+
for (const candidate of availableCandidates) {
|
|
159
|
+
if (seen.has(candidate)) continue;
|
|
160
|
+
seen.add(candidate);
|
|
161
|
+
const probe = probeCudaTorchSync(candidate, env);
|
|
162
|
+
if (probe.ok) return probe;
|
|
163
|
+
firstFailure ??= probe;
|
|
164
|
+
}
|
|
165
|
+
return firstFailure ?? {
|
|
166
|
+
ok: false,
|
|
167
|
+
python: preferredPython,
|
|
168
|
+
output: "No Python interpreter candidate exposed CUDA-enabled vendor Torch"
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function readFirst(paths) {
|
|
172
|
+
for (const path of paths) {
|
|
173
|
+
try {
|
|
174
|
+
const value = readFileSync2(path, "utf8").replace(/\0/g, " ").trim();
|
|
175
|
+
if (value) return value;
|
|
176
|
+
} catch {
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return void 0;
|
|
180
|
+
}
|
|
181
|
+
function detectCudaToolkitVersion(env) {
|
|
182
|
+
const versionJson = readFirst(["/usr/local/cuda/version.json"]);
|
|
183
|
+
if (versionJson) {
|
|
184
|
+
try {
|
|
185
|
+
const parsed = JSON.parse(versionJson);
|
|
186
|
+
const version = parsed.cuda?.version ?? parsed.version;
|
|
187
|
+
if (version) return String(version);
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const versionText = readFirst(["/usr/local/cuda/version.txt"]);
|
|
192
|
+
const textMatch = versionText?.match(/CUDA\s+Version\s+([0-9.]+)/i);
|
|
193
|
+
if (textMatch?.[1]) return textMatch[1];
|
|
194
|
+
for (const nvccPath of ["/usr/local/cuda-12.2/bin/nvcc", "/usr/local/cuda/bin/nvcc", "nvcc"]) {
|
|
195
|
+
const nvcc = run(nvccPath, ["--version"], 15e3, env);
|
|
196
|
+
const match = nvcc.output.match(/release\s+([0-9.]+)/i)?.[1];
|
|
197
|
+
if (match) return match;
|
|
198
|
+
}
|
|
199
|
+
return void 0;
|
|
200
|
+
}
|
|
201
|
+
function classifyNvidiaArmEnvironmentSync(preferredPython = "python3", env = process.env) {
|
|
202
|
+
const nvidiaArm = isNvidiaArmCudaHost();
|
|
203
|
+
const reasons = [];
|
|
204
|
+
const boardModel = readFirst(["/proc/device-tree/model"]);
|
|
205
|
+
const family = /orin/i.test(boardModel ?? "") ? "orin" : /thor/i.test(boardModel ?? "") ? "thor" : /xavier/i.test(boardModel ?? "") ? "xavier" : "unknown";
|
|
206
|
+
const l4tText = readFirst(["/etc/nv_tegra_release"]);
|
|
207
|
+
const l4tMatch = l4tText?.match(/R(\d+).*REVISION:\s*([0-9.]+)/i);
|
|
208
|
+
const l4tRelease = l4tMatch ? `${l4tMatch[1]}.${l4tMatch[2]}` : void 0;
|
|
209
|
+
const l4tMajor = Number(l4tMatch?.[1] ?? 0);
|
|
210
|
+
const l4tRevision = Number(l4tMatch?.[2] ?? 0);
|
|
211
|
+
const jetPackMajor = l4tMajor >= 38 ? 7 : l4tMajor >= 36 ? 6 : l4tMajor >= 34 ? 5 : l4tMajor === 32 ? 4 : void 0;
|
|
212
|
+
const jetPackPackage = run(
|
|
213
|
+
"dpkg-query",
|
|
214
|
+
["-W", "-f=${Version}", "nvidia-jetpack"],
|
|
215
|
+
15e3,
|
|
216
|
+
env
|
|
217
|
+
);
|
|
218
|
+
const jetPackVersion = jetPackPackage.ok ? jetPackPackage.output.match(/\d+\.\d+(?:\.\d+)?/)?.[0] : void 0;
|
|
219
|
+
const jetPackFamily = l4tMajor >= 38 ? "7.x" : l4tMajor >= 36 ? l4tRevision >= 4 ? "6.2+" : "6.0/6.1" : l4tMajor === 35 ? "5.x" : l4tMajor === 32 ? "4.x" : void 0;
|
|
220
|
+
const cudaToolkitVersion = detectCudaToolkitVersion(env);
|
|
221
|
+
const vendor = resolveVendorCudaPythonSync(preferredPython, env);
|
|
222
|
+
const pythonInfo = run(
|
|
223
|
+
vendor.python || preferredPython,
|
|
224
|
+
["-c", "import sys;print(f'{sys.version_info.major}.{sys.version_info.minor} cp{sys.version_info.major}{sys.version_info.minor}')"],
|
|
225
|
+
3e4,
|
|
226
|
+
env
|
|
227
|
+
);
|
|
228
|
+
const pythonTokens = pythonInfo.ok ? pythonInfo.output.trim().split(/\s+/).slice(-2) : [];
|
|
229
|
+
const pythonVersion = pythonTokens[0];
|
|
230
|
+
const pythonAbi = pythonTokens[1];
|
|
231
|
+
const managedTorchProviders = [];
|
|
232
|
+
const cudaIndexMatch = cudaToolkitVersion?.match(/^(\d+)\.(\d+)/);
|
|
233
|
+
if (nvidiaArm && jetPackMajor && cudaIndexMatch) {
|
|
234
|
+
const cudaIndexTag = `cu${cudaIndexMatch[1]}${cudaIndexMatch[2]}`;
|
|
235
|
+
if (jetPackMajor >= 6) {
|
|
236
|
+
managedTorchProviders.push({
|
|
237
|
+
id: "jetson-ai-lab-index",
|
|
238
|
+
mode: "index",
|
|
239
|
+
location: `https://pypi.jetson-ai-lab.io/jp${jetPackMajor}/${cudaIndexTag}`
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (jetPackVersion) {
|
|
243
|
+
managedTorchProviders.push({
|
|
244
|
+
id: "nvidia-jetpack-index",
|
|
245
|
+
mode: "find-links",
|
|
246
|
+
location: `https://developer.download.nvidia.com/compute/redist/jp/v${jetPackVersion.replace(/\D/g, "")}/pytorch/`
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const yuyiCompatible = nvidiaArm && !vendor.ok && family === "orin" && l4tMajor === 36 && l4tRevision >= 4 && cudaToolkitVersion?.startsWith("12.6") === true && pythonVersion === "3.10" && (vendor.computeCapability === 8.7 || !vendor.ok && family === "orin");
|
|
251
|
+
if (yuyiCompatible) {
|
|
252
|
+
managedTorchProviders.unshift({
|
|
253
|
+
id: "yuyirobotlab-orin-cu126-vllm-0.19.0",
|
|
254
|
+
mode: "wheel",
|
|
255
|
+
location: "https://github.com/YuyiRobotLab/vllm-orin-release/releases/download/v0.19.0-orin/torch-2.10.0-cp310-cp310-linux_aarch64.whl"
|
|
256
|
+
});
|
|
257
|
+
reasons.push("Exact Orin SM 8.7 / L4T 36.4+ / CUDA 12.6 / CPython 3.10 provider match");
|
|
258
|
+
}
|
|
259
|
+
if (vendor.ok) {
|
|
260
|
+
reasons.push("No exact binary provider matches every hardware/runtime dimension");
|
|
261
|
+
reasons.push("CUDA-enabled vendor Torch is available for a source build");
|
|
262
|
+
return {
|
|
263
|
+
nvidiaArm,
|
|
264
|
+
family,
|
|
265
|
+
boardModel,
|
|
266
|
+
l4tRelease,
|
|
267
|
+
jetPackMajor,
|
|
268
|
+
jetPackVersion,
|
|
269
|
+
jetPackFamily,
|
|
270
|
+
cudaToolkitVersion,
|
|
271
|
+
pythonVersion,
|
|
272
|
+
pythonAbi,
|
|
273
|
+
computeCapability: vendor.computeCapability,
|
|
274
|
+
vendorPython: vendor.python,
|
|
275
|
+
vendorTorchVersion: vendor.torchVersion,
|
|
276
|
+
vendorTorchCudaVersion: vendor.torchCudaVersion,
|
|
277
|
+
recommendedStrategy: "source-existing-torch",
|
|
278
|
+
managedTorchProviders,
|
|
279
|
+
reasons
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
if (managedTorchProviders.length > 0) {
|
|
283
|
+
reasons.push("No CUDA-enabled vendor Torch interpreter was found");
|
|
284
|
+
reasons.push(`Managed CUDA Torch providers: ${managedTorchProviders.map((provider) => provider.id).join(", ")}`);
|
|
285
|
+
return {
|
|
286
|
+
nvidiaArm,
|
|
287
|
+
family,
|
|
288
|
+
boardModel,
|
|
289
|
+
l4tRelease,
|
|
290
|
+
jetPackMajor,
|
|
291
|
+
jetPackVersion,
|
|
292
|
+
jetPackFamily,
|
|
293
|
+
cudaToolkitVersion,
|
|
294
|
+
pythonVersion,
|
|
295
|
+
pythonAbi,
|
|
296
|
+
computeCapability: family === "orin" ? 8.7 : vendor.computeCapability,
|
|
297
|
+
vendorPython: vendor.python,
|
|
298
|
+
recommendedStrategy: "managed-torch",
|
|
299
|
+
matchedProvider: managedTorchProviders[0]?.id,
|
|
300
|
+
managedTorchProviders,
|
|
301
|
+
reasons
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
reasons.push("No CUDA-enabled vendor Torch interpreter was found");
|
|
305
|
+
return {
|
|
306
|
+
nvidiaArm,
|
|
307
|
+
family,
|
|
308
|
+
boardModel,
|
|
309
|
+
l4tRelease,
|
|
310
|
+
jetPackMajor,
|
|
311
|
+
jetPackVersion,
|
|
312
|
+
jetPackFamily,
|
|
313
|
+
cudaToolkitVersion,
|
|
314
|
+
pythonVersion,
|
|
315
|
+
pythonAbi,
|
|
316
|
+
recommendedStrategy: "unsupported",
|
|
317
|
+
reasons
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function ensureCudaPythonVenvSync(options) {
|
|
321
|
+
const env = { ...process.env, ...options.env };
|
|
322
|
+
const preferredPython = options.bootstrapPython?.trim() || "python3";
|
|
323
|
+
const managedPython = venvPython(options.venvDir);
|
|
324
|
+
const nvidiaArm = isNvidiaArmCudaHost();
|
|
325
|
+
const requireHost = options.requireHostCudaTorch ?? nvidiaArm;
|
|
326
|
+
const label = options.label?.trim() || "managed CUDA Python runtime";
|
|
327
|
+
const host = nvidiaArm ? resolveVendorCudaPythonSync(preferredPython, env) : probeCudaTorchSync(preferredPython, env);
|
|
328
|
+
const classification = nvidiaArm ? classifyNvidiaArmEnvironmentSync(preferredPython, env) : void 0;
|
|
329
|
+
const managedProviders = classification?.managedTorchProviders ?? [];
|
|
330
|
+
const allowManagedTorchInstall = options.allowManagedTorchInstall ?? true;
|
|
331
|
+
const includeSystemSitePackages = options.includeSystemSitePackages ?? true;
|
|
332
|
+
const bootstrapPython = host.ok ? host.python : preferredPython;
|
|
333
|
+
if (requireHost && !host.ok && (!allowManagedTorchInstall || managedProviders.length === 0)) {
|
|
334
|
+
throw new Error(
|
|
335
|
+
`${label} requires compatible CUDA Torch, but no vendor installation or environment-matched provider was found: ${host.output}`
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
let repaired = false;
|
|
339
|
+
if (existsSync2(managedPython)) {
|
|
340
|
+
const current = probeCudaTorchSync(managedPython, env);
|
|
341
|
+
const isolationMismatch = managedVenvUsesSystemSitePackages(options.venvDir) !== includeSystemSitePackages;
|
|
342
|
+
if ((options.repairIncompatibleVenv ?? true) && (isolationMismatch || host.ok && !current.ok)) {
|
|
343
|
+
rmSync(options.venvDir, { recursive: true, force: true });
|
|
344
|
+
repaired = true;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
if (!existsSync2(managedPython)) {
|
|
348
|
+
mkdirSync(dirname(options.venvDir), { recursive: true });
|
|
349
|
+
const created = run(
|
|
350
|
+
bootstrapPython,
|
|
351
|
+
[
|
|
352
|
+
"-m",
|
|
353
|
+
"venv",
|
|
354
|
+
...includeSystemSitePackages ? ["--system-site-packages"] : [],
|
|
355
|
+
options.venvDir
|
|
356
|
+
],
|
|
357
|
+
12e4,
|
|
358
|
+
env
|
|
359
|
+
);
|
|
360
|
+
if (!created.ok) throw new Error(`Failed to create ${label}: ${created.output}`);
|
|
361
|
+
if (managedVenvUsesSystemSitePackages(options.venvDir) !== includeSystemSitePackages) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
`${label} venv did not retain include-system-site-packages=${includeSystemSitePackages}; refusing an ambiguous Python dependency boundary`
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
let managed = probeCudaTorchSync(managedPython, env);
|
|
368
|
+
if (!managed.ok && host.ok && host.torchModulePath) {
|
|
369
|
+
const siteProbe = run(
|
|
370
|
+
managedPython,
|
|
371
|
+
["-c", "import json,site;print(json.dumps(site.getsitepackages()))"],
|
|
372
|
+
3e4,
|
|
373
|
+
env
|
|
374
|
+
);
|
|
375
|
+
try {
|
|
376
|
+
const line = siteProbe.output.split(/\r?\n/).slice().reverse().find((value) => value.trim().startsWith("["));
|
|
377
|
+
const managedSites = JSON.parse(line || "[]");
|
|
378
|
+
const managedSite = managedSites[0];
|
|
379
|
+
if (managedSite) {
|
|
380
|
+
const vendorSite = dirname(dirname(host.torchModulePath));
|
|
381
|
+
writeFileSync(join2(managedSite, "omnius-vendor-torch.pth"), `${vendorSite}
|
|
382
|
+
`, "utf8");
|
|
383
|
+
managed = probeCudaTorchSync(managedPython, env);
|
|
384
|
+
}
|
|
385
|
+
} catch {
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
let torchProvider;
|
|
389
|
+
if (!managed.ok && allowManagedTorchInstall && managedProviders.length > 0) {
|
|
390
|
+
const providerEnv = { ...env };
|
|
391
|
+
delete providerEnv["PIP_CONSTRAINT"];
|
|
392
|
+
const failures = [];
|
|
393
|
+
for (const provider of managedProviders) {
|
|
394
|
+
const providerArgs = provider.mode === "wheel" ? ["-m", "pip", "install", "--disable-pip-version-check", "--no-deps", "--force-reinstall", provider.location] : provider.mode === "index" ? ["-m", "pip", "install", "--disable-pip-version-check", "--upgrade", "--force-reinstall", "--index-url", provider.location, "torch"] : ["-m", "pip", "install", "--disable-pip-version-check", "--upgrade", "--force-reinstall", "--no-index", "--find-links", provider.location, "--no-deps", "torch"];
|
|
395
|
+
const installed = run(managedPython, providerArgs, 12e5, providerEnv);
|
|
396
|
+
if (!installed.ok) {
|
|
397
|
+
failures.push(`${provider.id}: ${installed.output}`);
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
const candidate = probeCudaTorchSync(managedPython, providerEnv);
|
|
401
|
+
if (!candidate.ok) {
|
|
402
|
+
failures.push(`${provider.id}: installed Torch failed CUDA validation: ${candidate.output}`);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
managed = candidate;
|
|
406
|
+
torchProvider = provider.id;
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
if (!managed.ok && requireHost) {
|
|
410
|
+
throw new Error(
|
|
411
|
+
`${label} could not install CUDA Torch for ${classification?.jetPackFamily ?? "detected JetPack"} / CUDA ${classification?.cudaToolkitVersion ?? "unknown"} / ${classification?.pythonAbi ?? "unknown ABI"}: ${failures.join("; ")}`
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const companions = [...new Set(options.cudaCompanionPackages ?? [])].filter((name) => name.trim() && name.trim().toLowerCase() !== "torch");
|
|
416
|
+
if (managed.ok && nvidiaArm && companions.length > 0) {
|
|
417
|
+
const companionImports = companions.map((name) => name.replace(/-/g, "_"));
|
|
418
|
+
const importProbe = () => run(
|
|
419
|
+
managedPython,
|
|
420
|
+
["-c", `import ${companionImports.join(",")}`],
|
|
421
|
+
6e4,
|
|
422
|
+
env
|
|
423
|
+
);
|
|
424
|
+
if (!importProbe().ok) {
|
|
425
|
+
const failures = [];
|
|
426
|
+
for (const provider of managedProviders.filter((candidate) => candidate.mode !== "wheel")) {
|
|
427
|
+
const providerArgs = provider.mode === "index" ? ["-m", "pip", "install", "--disable-pip-version-check", "--no-deps", "--upgrade", "--index-url", provider.location, ...companions] : ["-m", "pip", "install", "--disable-pip-version-check", "--no-deps", "--upgrade", "--no-index", "--find-links", provider.location, ...companions];
|
|
428
|
+
const installed = run(managedPython, providerArgs, 12e5, env);
|
|
429
|
+
if (installed.ok && importProbe().ok) break;
|
|
430
|
+
failures.push(`${provider.id}: ${installed.output}`);
|
|
431
|
+
}
|
|
432
|
+
const verified = importProbe();
|
|
433
|
+
if (!verified.ok && requireHost) {
|
|
434
|
+
throw new Error(
|
|
435
|
+
`${label} could not resolve CUDA companion packages (${companions.join(", ")}) for ${classification?.jetPackFamily ?? "detected JetPack"}: ${failures.join("; ") || verified.output}`
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (requireHost && !managed.ok) {
|
|
441
|
+
throw new Error(`${label} cannot inherit CUDA Torch from ${bootstrapPython}: ${managed.output}`);
|
|
442
|
+
}
|
|
443
|
+
const pipEnv = { ...env };
|
|
444
|
+
const protectedTorch = managed.ok ? managed : host;
|
|
445
|
+
if (protectedTorch.ok && protectedTorch.torchVersion) {
|
|
446
|
+
const constraintPath = join2(options.venvDir, "omnius-cuda-constraints.txt");
|
|
447
|
+
writeFileSync(
|
|
448
|
+
constraintPath,
|
|
449
|
+
`torch===${protectedTorch.torchVersion}
|
|
450
|
+
# Omnius protects environment-matched CUDA Torch from pip replacement.
|
|
451
|
+
`,
|
|
452
|
+
"utf8"
|
|
453
|
+
);
|
|
454
|
+
writeFileSync(
|
|
455
|
+
join2(options.venvDir, process.platform === "win32" ? "pip.ini" : "pip.conf"),
|
|
456
|
+
`[global]
|
|
457
|
+
constraint = ${constraintPath}
|
|
458
|
+
`,
|
|
459
|
+
"utf8"
|
|
460
|
+
);
|
|
461
|
+
pipEnv["PIP_CONSTRAINT"] = constraintPath;
|
|
462
|
+
}
|
|
463
|
+
return {
|
|
464
|
+
venvDir: options.venvDir,
|
|
465
|
+
python: managedPython,
|
|
466
|
+
bootstrapPython,
|
|
467
|
+
nvidiaArm,
|
|
468
|
+
repaired,
|
|
469
|
+
host,
|
|
470
|
+
managed,
|
|
471
|
+
pipEnv,
|
|
472
|
+
torchProvider
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
var CUDA_RUNTIME_PACKAGES = /* @__PURE__ */ new Set([
|
|
476
|
+
"torch",
|
|
477
|
+
"torchvision",
|
|
478
|
+
"torchaudio",
|
|
479
|
+
"triton",
|
|
480
|
+
"vllm",
|
|
481
|
+
"vllm-omni",
|
|
482
|
+
"xformers",
|
|
483
|
+
"flash-attn"
|
|
484
|
+
]);
|
|
485
|
+
function packageName(spec) {
|
|
486
|
+
return spec.trim().match(/^([a-zA-Z0-9_.-]+)/)?.[1]?.toLowerCase().replace(/_/g, "-") ?? "";
|
|
487
|
+
}
|
|
488
|
+
function cudaSafePipInstallArgs(specs, options = {}) {
|
|
489
|
+
if (isNvidiaArmCudaHost() && !options.noDeps && specs.some((spec) => CUDA_RUNTIME_PACKAGES.has(packageName(spec)))) {
|
|
490
|
+
throw new Error(
|
|
491
|
+
"NVIDIA ARM CUDA packages must use --no-deps or a source build bound to vendor Torch"
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
return [
|
|
495
|
+
"-m",
|
|
496
|
+
"pip",
|
|
497
|
+
"install",
|
|
498
|
+
"--disable-pip-version-check",
|
|
499
|
+
...options.upgrade ? ["--upgrade"] : [],
|
|
500
|
+
...options.noDeps ? ["--no-deps"] : [],
|
|
501
|
+
...specs
|
|
502
|
+
];
|
|
503
|
+
}
|
|
504
|
+
export {
|
|
505
|
+
classifyNvidiaArmEnvironmentSync,
|
|
506
|
+
cudaSafePipInstallArgs,
|
|
507
|
+
ensureCudaPythonVenvSync,
|
|
508
|
+
isNvidiaArmCudaHost,
|
|
509
|
+
managedVenvUsesSystemSitePackages,
|
|
510
|
+
probeCudaTorchSync,
|
|
511
|
+
resolveVendorCudaPythonSync
|
|
512
|
+
};
|