@thyn-ai/sqai 0.1.2 → 0.1.3

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/index.cjs CHANGED
@@ -173,11 +173,15 @@ function fromAlgentaError(error) {
173
173
  }
174
174
 
175
175
  // src/env.ts
176
+ var DEFAULT_BUILD_SERVICE_URL = "https://sqai-buildservice.fly.dev";
176
177
  function readEnv(env = process.env) {
177
178
  const apiKey = (env.SQAI_API_KEY ?? "").trim() || void 0;
178
179
  const engineUrl = (env.SQAI_ENGINE_URL ?? "").trim() || void 0;
179
180
  const autoInstall = (env.SQAI_RUNTIME_AUTO_INSTALL ?? "").trim() !== "0";
180
- return { apiKey, engineUrl, autoInstall };
181
+ const modulesRaw = (env.SQAI_RUNTIME_MODULES ?? "").split(",").map((m) => m.trim()).filter((m) => m.length > 0);
182
+ const runtimeModules = modulesRaw.length > 0 ? modulesRaw : void 0;
183
+ const buildServiceUrl = (env.SQAI_BUILD_SERVICE_URL ?? "").trim() || DEFAULT_BUILD_SERVICE_URL;
184
+ return { apiKey, engineUrl, autoInstall, runtimeModules, buildServiceUrl };
181
185
  }
182
186
  function inferMode(explicit, resolved) {
183
187
  if (explicit) {
@@ -1029,7 +1033,7 @@ async function removeQuietly(path) {
1029
1033
  } catch {
1030
1034
  }
1031
1035
  }
1032
- var RuntimeProvisioner = class {
1036
+ var RuntimeProvisioner = class _RuntimeProvisioner {
1033
1037
  options;
1034
1038
  trustRoot;
1035
1039
  runtime = null;
@@ -1089,8 +1093,110 @@ var RuntimeProvisioner = class {
1089
1093
  cacheDir() {
1090
1094
  return this.options.cacheDir ?? runtimeCacheDir();
1091
1095
  }
1096
+ /** Normalized module filter (sorted, unique, non-empty) or null for the default bundle. */
1097
+ filterModules() {
1098
+ const mods = (this.options.runtimeModules ?? []).map((m) => m.trim()).filter((m) => m.length > 0);
1099
+ if (mods.length === 0) {
1100
+ return null;
1101
+ }
1102
+ return Array.from(new Set(mods)).sort();
1103
+ }
1104
+ /** Ask the build service to compile + sign a bundle for exactly these modules. */
1105
+ async resolveFilteredBundle(modules, platformKey) {
1106
+ if (this.options.resolveFilteredBundle) {
1107
+ return this.options.resolveFilteredBundle(modules, platformKey);
1108
+ }
1109
+ const base = this.options.buildServiceUrl;
1110
+ if (!base) {
1111
+ throw new SqaiError(
1112
+ "runtime_provision_failed",
1113
+ "runtimeModules was set but no build service is configured. Set SQAI_BUILD_SERVICE_URL to a build-on-provision endpoint, or omit runtimeModules to use the default bundle.",
1114
+ { details: { reason: "no_build_service", modules } }
1115
+ );
1116
+ }
1117
+ let response;
1118
+ try {
1119
+ response = await fetch(`${base.replace(/\/$/, "")}/v1/runtime/build`, {
1120
+ method: "POST",
1121
+ headers: { "content-type": "application/json" },
1122
+ body: JSON.stringify({ modules, platform: platformKey })
1123
+ });
1124
+ } catch (error) {
1125
+ const message = error instanceof Error ? error.message : String(error);
1126
+ throw new SqaiError(
1127
+ "runtime_provision_failed",
1128
+ `Build service request failed: ${message}`,
1129
+ { retryable: true, details: { reason: "build_service_unreachable", modules } }
1130
+ );
1131
+ }
1132
+ if (!response.ok) {
1133
+ throw new SqaiError(
1134
+ "runtime_provision_failed",
1135
+ `Build service returned HTTP ${response.status} for the requested filter.`,
1136
+ { retryable: response.status >= 500, details: { reason: "build_failed", modules } }
1137
+ );
1138
+ }
1139
+ const body = await response.json();
1140
+ return {
1141
+ url: body.url,
1142
+ sha256: body.sha256,
1143
+ version: body.version ?? this.options.contract.runtime_bundle.version,
1144
+ cacheKey: body.cache_key
1145
+ };
1146
+ }
1147
+ /**
1148
+ * The filter's cache key, computed IDENTICALLY to the build service
1149
+ * (sha256("mods|platform|version")[:20], mods = sorted+unique, comma-joined).
1150
+ * Lets the reuse fast-path find an already-running filtered daemon without a
1151
+ * build-service round-trip. The build service's returned key is authoritative
1152
+ * for install; this only has to match for the reuse optimization to hit.
1153
+ */
1154
+ localCacheKey(modules, platformKey) {
1155
+ const canonical = modules.join(",");
1156
+ const version = this.options.contract.runtime_bundle.version;
1157
+ return (0, import_node_crypto5.createHash)("sha256").update(`${canonical}|${platformKey}|${version}`).digest("hex").slice(0, 20);
1158
+ }
1159
+ /**
1160
+ * Deterministic per-filter daemon endpoint so a filtered runtime never collides
1161
+ * with the default (or another filter's) daemon on the shared default socket.
1162
+ */
1163
+ filterEndpoint(cacheKey) {
1164
+ const seed = parseInt(cacheKey.slice(0, 6), 16) || 0;
1165
+ const port = 50100 + seed % 800;
1166
+ return { sock: (0, import_node_path2.join)(this.cacheDir(), `${cacheKey}.sock`), tcp: `127.0.0.1:${port}` };
1167
+ }
1168
+ static DAEMON_ENDPOINT_ENV = [
1169
+ "ALGENTA_DAEMON_SOCK",
1170
+ "ALGENTA_DAEMON_TCP",
1171
+ "ALGENTA_MOJO_SOCK",
1172
+ "ALGENTA_RUNTIME_DIR"
1173
+ ];
1174
+ /** Point the about-to-be-spawned daemon at a filter-specific socket/port/dir. */
1175
+ applyDaemonEndpointEnv(endpoint, installDir) {
1176
+ const saved = {};
1177
+ for (const key of _RuntimeProvisioner.DAEMON_ENDPOINT_ENV) {
1178
+ saved[key] = process.env[key];
1179
+ }
1180
+ process.env.ALGENTA_DAEMON_SOCK = endpoint.sock;
1181
+ process.env.ALGENTA_DAEMON_TCP = endpoint.tcp;
1182
+ process.env.ALGENTA_MOJO_SOCK = `${endpoint.sock}.worker`;
1183
+ process.env.ALGENTA_RUNTIME_DIR = (0, import_node_path2.join)(installDir, ".runtime");
1184
+ return saved;
1185
+ }
1186
+ restoreEnv(saved) {
1187
+ for (const [key, value] of Object.entries(saved)) {
1188
+ if (value === void 0) {
1189
+ delete process.env[key];
1190
+ } else {
1191
+ process.env[key] = value;
1192
+ }
1193
+ }
1194
+ }
1092
1195
  async doEnsure() {
1093
- const runtime = this.newRuntime();
1196
+ const platformKey = currentPlatformKey();
1197
+ const filter = this.filterModules();
1198
+ const probeEndpoint = filter ? this.filterEndpoint(this.localCacheKey(filter, platformKey)) : void 0;
1199
+ const runtime = this.newRuntime(probeEndpoint ? { tcpAddress: probeEndpoint.tcp } : void 0);
1094
1200
  try {
1095
1201
  const health = await runtime.health();
1096
1202
  if (health.runtime_available) {
@@ -1099,40 +1205,54 @@ var RuntimeProvisioner = class {
1099
1205
  }
1100
1206
  } catch {
1101
1207
  }
1102
- const platformKey = currentPlatformKey();
1103
- const bundle = this.options.contract.runtime_bundle;
1104
- const platformBundle = bundle.platforms[platformKey];
1105
- if (!platformBundle) {
1106
- const supported = Object.keys(bundle.platforms);
1107
- throw new SqaiError(
1108
- "unsupported_platform",
1109
- supported.length === 0 ? "No managed runtime bundle is published yet for any platform. Start a local Algenta runtime daemon, or set SQAI_ENGINE_URL / SQAI_API_KEY to use a hosted engine." : `No managed runtime bundle is published for '${platformKey}'.`,
1110
- { details: { platform: platformKey, supported } }
1111
- );
1208
+ let version;
1209
+ let installKey;
1210
+ let platformBundle;
1211
+ let endpoint;
1212
+ if (filter) {
1213
+ const resolved = await this.resolveFilteredBundle(filter, platformKey);
1214
+ version = resolved.version;
1215
+ installKey = `filtered-${resolved.cacheKey}`;
1216
+ platformBundle = { url: resolved.url, sha256: resolved.sha256 };
1217
+ endpoint = this.filterEndpoint(resolved.cacheKey);
1218
+ } else {
1219
+ const bundle = this.options.contract.runtime_bundle;
1220
+ const pinned = bundle.platforms[platformKey];
1221
+ if (!pinned) {
1222
+ const supported = Object.keys(bundle.platforms);
1223
+ throw new SqaiError(
1224
+ "unsupported_platform",
1225
+ supported.length === 0 ? "No managed runtime bundle is published yet for any platform. Start a local Algenta runtime daemon, or set SQAI_ENGINE_URL / SQAI_API_KEY to use a hosted engine." : `No managed runtime bundle is published for '${platformKey}'.`,
1226
+ { details: { platform: platformKey, supported } }
1227
+ );
1228
+ }
1229
+ version = bundle.version;
1230
+ installKey = version;
1231
+ platformBundle = pinned;
1112
1232
  }
1113
1233
  if (!this.options.autoInstall) {
1114
1234
  throw new SqaiError(
1115
1235
  "runtime_provision_failed",
1116
1236
  "Automatic runtime installation is disabled (SQAI_RUNTIME_AUTO_INSTALL=0). Install manually with `sqai runtime install` or `sqai runtime install --from-file`.",
1117
- { details: { platform: platformKey, version: bundle.version } }
1237
+ { details: { platform: platformKey, version } }
1118
1238
  );
1119
1239
  }
1120
- if (compareRuntimeVersions(bundle.version, this.trustRoot.minAcceptedRuntimeVersion) < 0) {
1240
+ if (compareRuntimeVersions(version, this.trustRoot.minAcceptedRuntimeVersion) < 0) {
1121
1241
  throw new SqaiError(
1122
1242
  "runtime_provision_failed",
1123
- `Managed runtime ${bundle.version} is below the minimum accepted runtime version ${this.trustRoot.minAcceptedRuntimeVersion} (rollback protection).`,
1243
+ `Managed runtime ${version} is below the minimum accepted runtime version ${this.trustRoot.minAcceptedRuntimeVersion} (rollback protection).`,
1124
1244
  {
1125
1245
  details: {
1126
1246
  reason: "rollback_protected",
1127
1247
  platform: platformKey,
1128
- version: bundle.version,
1248
+ version,
1129
1249
  min_accepted_version: this.trustRoot.minAcceptedRuntimeVersion
1130
1250
  }
1131
1251
  }
1132
1252
  );
1133
1253
  }
1134
- const installed = await this.ensureInstalled(platformKey, bundle.version, platformBundle);
1135
- return this.spawnInstalled(platformKey, installed);
1254
+ const installed = await this.ensureInstalled(platformKey, version, platformBundle, installKey);
1255
+ return this.spawnInstalled(platformKey, installed, endpoint);
1136
1256
  }
1137
1257
  provisionError(reason, message, platformKey, version, extra = {}, retryable = false) {
1138
1258
  return new SqaiError("runtime_provision_failed", message, {
@@ -1174,8 +1294,8 @@ var RuntimeProvisioner = class {
1174
1294
  };
1175
1295
  }
1176
1296
  /** Verify an existing install if present; returns null when absent/invalid. */
1177
- async verifiedInstallOrNull(platformKey, version, removeOnFailure) {
1178
- const installDir = (0, import_node_path2.join)(this.cacheDir(), version);
1297
+ async verifiedInstallOrNull(platformKey, version, removeOnFailure, installKey = version) {
1298
+ const installDir = (0, import_node_path2.join)(this.cacheDir(), installKey);
1179
1299
  try {
1180
1300
  await import_node_fs2.promises.access((0, import_node_path2.join)(installDir, MANIFEST_NAME));
1181
1301
  } catch {
@@ -1226,15 +1346,15 @@ var RuntimeProvisioner = class {
1226
1346
  return true;
1227
1347
  }
1228
1348
  }
1229
- /** Serialize installers on `<cacheDir>/<version>.lock`; returns the verified install. */
1230
- async ensureInstalled(platformKey, version, platformBundle) {
1349
+ /** Serialize installers on `<cacheDir>/<installKey>.lock`; returns the verified install. */
1350
+ async ensureInstalled(platformKey, version, platformBundle, installKey = version) {
1231
1351
  const cacheDir = this.cacheDir();
1232
1352
  await import_node_fs2.promises.mkdir(cacheDir, { recursive: true });
1233
- const existing = await this.verifiedInstallOrNull(platformKey, version, true);
1353
+ const existing = await this.verifiedInstallOrNull(platformKey, version, true, installKey);
1234
1354
  if (existing) {
1235
1355
  return existing;
1236
1356
  }
1237
- const lockPath = (0, import_node_path2.join)(cacheDir, `${version}.lock`);
1357
+ const lockPath = (0, import_node_path2.join)(cacheDir, `${installKey}.lock`);
1238
1358
  const waitTimeoutMs = this.options.lockWaitTimeoutMs ?? LOCK_WAIT_TIMEOUT_MS;
1239
1359
  const pollIntervalMs = this.options.lockPollIntervalMs ?? LOCK_POLL_INTERVAL_MS;
1240
1360
  const deadline = Date.now() + waitTimeoutMs;
@@ -1246,12 +1366,12 @@ var RuntimeProvisioner = class {
1246
1366
  await removeQuietly(lockPath);
1247
1367
  continue;
1248
1368
  }
1249
- const finished = await this.verifiedInstallOrNull(platformKey, version, false);
1369
+ const finished = await this.verifiedInstallOrNull(platformKey, version, false, installKey);
1250
1370
  if (finished) {
1251
1371
  return finished;
1252
1372
  }
1253
1373
  if (Date.now() >= deadline) {
1254
- const lastChance = await this.verifiedInstallOrNull(platformKey, version, false);
1374
+ const lastChance = await this.verifiedInstallOrNull(platformKey, version, false, installKey);
1255
1375
  if (lastChance) {
1256
1376
  return lastChance;
1257
1377
  }
@@ -1260,29 +1380,29 @@ var RuntimeProvisioner = class {
1260
1380
  `Another installer holds the runtime install lock for ${version} and did not finish within ${Math.round(waitTimeoutMs / 1e3)}s. Retry, or remove the stale lock from the runtime cache directory.`,
1261
1381
  platformKey,
1262
1382
  version,
1263
- { lock_file: `${version}.lock` },
1383
+ { lock_file: `${installKey}.lock` },
1264
1384
  true
1265
1385
  );
1266
1386
  }
1267
1387
  await sleep(pollIntervalMs);
1268
1388
  }
1269
1389
  try {
1270
- const raced = await this.verifiedInstallOrNull(platformKey, version, false);
1390
+ const raced = await this.verifiedInstallOrNull(platformKey, version, false, installKey);
1271
1391
  if (raced) {
1272
1392
  return raced;
1273
1393
  }
1274
- return await this.downloadVerifyExtract(platformKey, version, platformBundle);
1394
+ return await this.downloadVerifyExtract(platformKey, version, platformBundle, installKey);
1275
1395
  } finally {
1276
1396
  await removeQuietly(lockPath);
1277
1397
  }
1278
1398
  }
1279
1399
  /** Holder-of-the-lock path: download → verify → extract → atomic rename. */
1280
- async downloadVerifyExtract(platformKey, version, platformBundle) {
1400
+ async downloadVerifyExtract(platformKey, version, platformBundle, installKey = version) {
1281
1401
  const cacheDir = this.cacheDir();
1282
1402
  const token = (0, import_node_crypto5.randomBytes)(6).toString("hex");
1283
1403
  const tarballPath = (0, import_node_path2.join)(cacheDir, `tmp-${token}.tgz`);
1284
1404
  const extractDir = (0, import_node_path2.join)(cacheDir, `tmp-${token}`);
1285
- const installDir = (0, import_node_path2.join)(cacheDir, version);
1405
+ const installDir = (0, import_node_path2.join)(cacheDir, installKey);
1286
1406
  const url = resolveBundleUrl(platformBundle.url, version, platformKey);
1287
1407
  try {
1288
1408
  const download = this.options.downloadBundle ?? defaultDownloadBundle;
@@ -1329,7 +1449,7 @@ var RuntimeProvisioner = class {
1329
1449
  try {
1330
1450
  await import_node_fs2.promises.rename(extractDir, installDir);
1331
1451
  } catch (error) {
1332
- const raced = await this.verifiedInstallOrNull(platformKey, version, false);
1452
+ const raced = await this.verifiedInstallOrNull(platformKey, version, false, installKey);
1333
1453
  if (raced) {
1334
1454
  return raced;
1335
1455
  }
@@ -1348,7 +1468,7 @@ var RuntimeProvisioner = class {
1348
1468
  }
1349
1469
  }
1350
1470
  /** Spawn the installed bundle's daemon through MojoRuntime autoStart. */
1351
- async spawnInstalled(platformKey, installed) {
1471
+ async spawnInstalled(platformKey, installed, endpoint) {
1352
1472
  const version = installed.manifest.runtime_bundle_version;
1353
1473
  let entryRelative;
1354
1474
  try {
@@ -1361,7 +1481,10 @@ var RuntimeProvisioner = class {
1361
1481
  "start",
1362
1482
  "--foreground"
1363
1483
  ];
1364
- const managed = this.newRuntime({ autoStart: true, daemonCommand });
1484
+ const managed = this.newRuntime(
1485
+ endpoint ? { autoStart: true, daemonCommand, tcpAddress: endpoint.tcp } : { autoStart: true, daemonCommand }
1486
+ );
1487
+ const savedEnv = endpoint ? this.applyDaemonEndpointEnv(endpoint, installed.installDir) : null;
1365
1488
  try {
1366
1489
  const health = await managed.health();
1367
1490
  if (!health.runtime_available) {
@@ -1385,6 +1508,10 @@ var RuntimeProvisioner = class {
1385
1508
  version,
1386
1509
  { daemon_entry: entryRelative }
1387
1510
  );
1511
+ } finally {
1512
+ if (savedEnv) {
1513
+ this.restoreEnv(savedEnv);
1514
+ }
1388
1515
  }
1389
1516
  try {
1390
1517
  await import_node_fs2.promises.writeFile(
@@ -1651,7 +1778,9 @@ var SQAI = class {
1651
1778
  this.resultStore = new ResultStore(config.resultStore);
1652
1779
  this.provisioner = new RuntimeProvisioner({
1653
1780
  contract: this.contractIndex.contract,
1654
- autoInstall: env.autoInstall
1781
+ autoInstall: env.autoInstall,
1782
+ runtimeModules: config.runtimeModules ?? env.runtimeModules,
1783
+ buildServiceUrl: config.buildServiceUrl ?? env.buildServiceUrl
1655
1784
  });
1656
1785
  if (config.runtime) {
1657
1786
  this.rawRuntime = config.runtime;