@vtxmacro/cli 2026.8.29 → 2026.8.31
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/README.md +16 -0
- package/bin/vtx.js +438 -205
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -71,6 +71,22 @@ vtx inference-host codex-logout
|
|
|
71
71
|
vtx inference-host revoke
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
To connect another Codex subscription to the same VTX account, repeat the
|
|
75
|
+
login and service-install commands with a stable local name such as
|
|
76
|
+
`--instance codex-2`. Each named instance has an isolated VTX grant, Codex
|
|
77
|
+
home, credential file, runtime state, recovery state, and worker; one per-user
|
|
78
|
+
OS supervisor runs all installed instances. Use `service status --json` to
|
|
79
|
+
inspect the installed workers. The installer rejects duplicate authenticated
|
|
80
|
+
ChatGPT emails and fails closed when it cannot prove multiple subscriptions are
|
|
81
|
+
distinct. Use `service uninstall --instance <name>` to remove one worker;
|
|
82
|
+
unqualified `service uninstall` removes the whole supervisor. The legacy
|
|
83
|
+
unqualified host commands continue to target `default`.
|
|
84
|
+
|
|
85
|
+
Automated hosts use three concurrent slots per subscription by default. Set a
|
|
86
|
+
bounded value from 1 through 8 with `--max-concurrency`. Slots share the live
|
|
87
|
+
subscription rate-limit gate and cooldown; this does not guarantee capacity
|
|
88
|
+
beyond the authenticated account's current entitlement.
|
|
89
|
+
|
|
74
90
|
This durable host uses a separate least-privilege `insights:inference`
|
|
75
91
|
OAuth grant. It also keeps its ChatGPT subscription login in a dedicated private
|
|
76
92
|
Codex home. Neither credential is copied from or widens the ordinary CLI or Codex
|
package/bin/vtx.js
CHANGED
|
@@ -38,7 +38,7 @@ var init_agent_cli_release = __esm({
|
|
|
38
38
|
"agent-cli-release.json"() {
|
|
39
39
|
agent_cli_release_default = {
|
|
40
40
|
package_name: "@vtxmacro/cli",
|
|
41
|
-
package_version: "2026.8.
|
|
41
|
+
package_version: "2026.8.31",
|
|
42
42
|
codex_package_name: "@openai/codex",
|
|
43
43
|
codex_version: "0.147.0",
|
|
44
44
|
platforms: {
|
|
@@ -16084,13 +16084,26 @@ import { spawn } from "node:child_process";
|
|
|
16084
16084
|
import { constants } from "node:fs";
|
|
16085
16085
|
import { lstat, mkdir, open, readFile, realpath, rename, rm } from "node:fs/promises";
|
|
16086
16086
|
import { homedir } from "node:os";
|
|
16087
|
-
import { dirname, join, relative, resolve } from "node:path";
|
|
16087
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
16088
16088
|
function inferenceBaseDir(env) {
|
|
16089
16089
|
const configured = String(env.VTX_INFERENCE_HOST_HOME || "").trim();
|
|
16090
16090
|
return configured || join(homedir(), ".vtx", "inference-host");
|
|
16091
16091
|
}
|
|
16092
|
+
function normalizeInferenceHostInstanceName(raw) {
|
|
16093
|
+
const value = raw.trim().toLowerCase();
|
|
16094
|
+
if (!SAFE_INFERENCE_HOST_INSTANCE.test(value)) {
|
|
16095
|
+
throw new Error(
|
|
16096
|
+
"Inference host instance must be 1-48 lowercase letters, numbers, or hyphens, and cannot start or end with a hyphen."
|
|
16097
|
+
);
|
|
16098
|
+
}
|
|
16099
|
+
return value;
|
|
16100
|
+
}
|
|
16092
16101
|
function resolveInferenceHostConfig(env = process.env) {
|
|
16093
16102
|
const baseDir = inferenceBaseDir(env);
|
|
16103
|
+
const instanceName = normalizeInferenceHostInstanceName(
|
|
16104
|
+
String(env.VTX_INFERENCE_HOST_INSTANCE || DEFAULT_INFERENCE_HOST_INSTANCE)
|
|
16105
|
+
);
|
|
16106
|
+
const instanceDir = instanceName === DEFAULT_INFERENCE_HOST_INSTANCE ? baseDir : join(baseDir, "instances", instanceName);
|
|
16094
16107
|
const rawMode = String(env.VTX_INFERENCE_HOST_CREDENTIAL_STORE || "os").trim().toLowerCase();
|
|
16095
16108
|
if (rawMode !== "os" && rawMode !== "file") {
|
|
16096
16109
|
throw new Error("VTX_INFERENCE_HOST_CREDENTIAL_STORE must be os or file.");
|
|
@@ -16103,15 +16116,36 @@ function resolveInferenceHostConfig(env = process.env) {
|
|
|
16103
16116
|
"VTX_INFERENCE_HOST_CREDENTIAL_FILE requires explicit file credential-store mode."
|
|
16104
16117
|
);
|
|
16105
16118
|
}
|
|
16106
|
-
const credentialFilePath = rawMode === "file" ?
|
|
16119
|
+
const credentialFilePath = rawMode === "file" ? requireNamedInstancePath(
|
|
16120
|
+
instanceName,
|
|
16121
|
+
instanceDir,
|
|
16122
|
+
explicitCredentialPath,
|
|
16123
|
+
"VTX_INFERENCE_HOST_CREDENTIAL_FILE"
|
|
16124
|
+
) || join(instanceDir, "credentials.json") : null;
|
|
16125
|
+
const explicitStatePath = requireNamedInstancePath(
|
|
16126
|
+
instanceName,
|
|
16127
|
+
instanceDir,
|
|
16128
|
+
String(env.VTX_INFERENCE_HOST_STATE_PATH || "").trim(),
|
|
16129
|
+
"VTX_INFERENCE_HOST_STATE_PATH"
|
|
16130
|
+
);
|
|
16131
|
+
const explicitLockPath = requireNamedInstancePath(
|
|
16132
|
+
instanceName,
|
|
16133
|
+
instanceDir,
|
|
16134
|
+
String(env.VTX_INFERENCE_HOST_LOCK_PATH || "").trim(),
|
|
16135
|
+
"VTX_INFERENCE_HOST_LOCK_PATH"
|
|
16136
|
+
);
|
|
16107
16137
|
return {
|
|
16108
16138
|
apiUrl: String(env.VTX_API_URL || "https://api.vtxmacro.com").replace(/\/+$/, ""),
|
|
16139
|
+
baseDir,
|
|
16140
|
+
instanceName,
|
|
16109
16141
|
credentialStoreMode: rawMode,
|
|
16110
16142
|
credentialFilePath,
|
|
16111
16143
|
credentialStoreIdentity: credentialStoreIdentity(rawMode, credentialFilePath, env),
|
|
16112
|
-
codexHomePath: join(
|
|
16113
|
-
statePath:
|
|
16114
|
-
processLockPath:
|
|
16144
|
+
codexHomePath: join(instanceDir, "codex-home"),
|
|
16145
|
+
statePath: explicitStatePath || join(instanceDir, "state.json"),
|
|
16146
|
+
processLockPath: explicitLockPath || join(instanceDir, "host.lock"),
|
|
16147
|
+
supervisorStatePath: join(baseDir, "state.json"),
|
|
16148
|
+
supervisorProcessLockPath: join(baseDir, "host.lock")
|
|
16115
16149
|
};
|
|
16116
16150
|
}
|
|
16117
16151
|
function assertLocalState(value) {
|
|
@@ -16488,12 +16522,14 @@ async function acquireInferenceHostProcessLock(path, dependencies = {}) {
|
|
|
16488
16522
|
}
|
|
16489
16523
|
};
|
|
16490
16524
|
}
|
|
16491
|
-
var INFERENCE_CREDENTIAL_NAMESPACE, MAX_INFERENCE_PRIVATE_FILE_BYTES, WINDOWS_PRIVATE_ACL_SCRIPT, windowsPrivateAclInvocation, runWindowsPrivateAcl, windowsAclCache, windowsAclIdentity, aclCacheKey, secureWindowsPrivatePath, invalidateWindowsAclCache, rebindHardenedWindowsAclAfterRename, rebindHardenedWindowsDirectoryAfterOwnedMutation, isDefaultWindowsPrivatePath, secureExistingWindowsPath, linuxProcessIdentity, windowsProcessIdentity, darwinProcessIdentity, runSmallIdentityCommand, cachedSystemBootIdentity, readInferenceSystemBootIdentity, defaultProcessIdentity, defaultCurrentProcessIdentity, processLockObservationCache, inferenceProcessIdentitiesMatch, credentialStoreIdentity;
|
|
16525
|
+
var INFERENCE_CREDENTIAL_NAMESPACE, MAX_INFERENCE_PRIVATE_FILE_BYTES, DEFAULT_CODEX_HOST_CONCURRENCY, MAX_CODEX_HOST_CONCURRENCY, WINDOWS_PRIVATE_ACL_SCRIPT, windowsPrivateAclInvocation, runWindowsPrivateAcl, windowsAclCache, windowsAclIdentity, aclCacheKey, secureWindowsPrivatePath, invalidateWindowsAclCache, rebindHardenedWindowsAclAfterRename, rebindHardenedWindowsDirectoryAfterOwnedMutation, isDefaultWindowsPrivatePath, secureExistingWindowsPath, linuxProcessIdentity, windowsProcessIdentity, darwinProcessIdentity, runSmallIdentityCommand, cachedSystemBootIdentity, readInferenceSystemBootIdentity, defaultProcessIdentity, defaultCurrentProcessIdentity, processLockObservationCache, inferenceProcessIdentitiesMatch, DEFAULT_INFERENCE_HOST_INSTANCE, SAFE_INFERENCE_HOST_INSTANCE, requireNamedInstancePath, credentialStoreIdentity;
|
|
16492
16526
|
var init_config = __esm({
|
|
16493
16527
|
"lib/inference-host/config.ts"() {
|
|
16494
16528
|
"use strict";
|
|
16495
16529
|
INFERENCE_CREDENTIAL_NAMESPACE = "vtxmacro-insights-inference";
|
|
16496
16530
|
MAX_INFERENCE_PRIVATE_FILE_BYTES = 16 * 1024 * 1024;
|
|
16531
|
+
DEFAULT_CODEX_HOST_CONCURRENCY = 3;
|
|
16532
|
+
MAX_CODEX_HOST_CONCURRENCY = 8;
|
|
16497
16533
|
WINDOWS_PRIVATE_ACL_SCRIPT = `$ErrorActionPreference='Stop'
|
|
16498
16534
|
$path=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($env:VTX_PRIVATE_PATH_B64))
|
|
16499
16535
|
$kind=$env:VTX_PRIVATE_PATH_KIND
|
|
@@ -16845,6 +16881,16 @@ if(-not $userFull) { throw 'private ACL does not grant the current user full con
|
|
|
16845
16881
|
};
|
|
16846
16882
|
processLockObservationCache = /* @__PURE__ */ new Map();
|
|
16847
16883
|
inferenceProcessIdentitiesMatch = (stored, observed) => stored === observed;
|
|
16884
|
+
DEFAULT_INFERENCE_HOST_INSTANCE = "default";
|
|
16885
|
+
SAFE_INFERENCE_HOST_INSTANCE = /^[a-z0-9](?:[a-z0-9-]{0,46}[a-z0-9])?$/u;
|
|
16886
|
+
requireNamedInstancePath = (instanceName, instanceDir, rawPath, label) => {
|
|
16887
|
+
if (!rawPath || instanceName === DEFAULT_INFERENCE_HOST_INSTANCE) return rawPath;
|
|
16888
|
+
const relativePath = relative(resolve(instanceDir), resolve(rawPath));
|
|
16889
|
+
if (relativePath === ".." || relativePath.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute(relativePath)) {
|
|
16890
|
+
throw new Error(`${label} for a named instance must stay inside its isolated instance directory.`);
|
|
16891
|
+
}
|
|
16892
|
+
return rawPath;
|
|
16893
|
+
};
|
|
16848
16894
|
credentialStoreIdentity = (mode, filePath, env) => {
|
|
16849
16895
|
if (mode === "file") {
|
|
16850
16896
|
if (!filePath) throw new Error("Inference credential fallback path is unavailable.");
|
|
@@ -19029,7 +19075,7 @@ var init_agent_state = __esm({
|
|
|
19029
19075
|
import { spawn as spawn3 } from "node:child_process";
|
|
19030
19076
|
import { chmod, lstat as lstat2, open as open2, readFile as readFile2, rename as rename2, rm as rm2, writeFile } from "node:fs/promises";
|
|
19031
19077
|
import { tmpdir } from "node:os";
|
|
19032
|
-
import { dirname as dirname2, isAbsolute, join as join2, resolve as resolve2, sep } from "node:path";
|
|
19078
|
+
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, resolve as resolve2, sep } from "node:path";
|
|
19033
19079
|
import { createInterface } from "node:readline";
|
|
19034
19080
|
async function loginCodexSubscription(options) {
|
|
19035
19081
|
const session = await CodexAppServerSession.start(options);
|
|
@@ -19101,12 +19147,13 @@ async function logoutCodexSubscription(options) {
|
|
|
19101
19147
|
await session.close();
|
|
19102
19148
|
}
|
|
19103
19149
|
}
|
|
19104
|
-
var CODEX_INFERENCE_PERMISSION_PROFILE, CODEX_REASONING_SUMMARY_MAX_UTF8_BYTES, CODEX_ACCOUNT_PLAN_TYPES, CodexAppServerError, objectOrNull, finiteToken, tokenUsageFromBreakdown, usageFromNotification, validPlanType, nonnegativeSafeIntegerOrNull, nonnegativeFiniteNumberOrNull, parseRateLimitWindow, RATE_LIMIT_REACHED_TYPES, DEFAULT_CODEX_QUOTA_COOLDOWN_MS, MAX_CODEX_QUOTA_COOLDOWN_MS, CODEX_TRANSIENT_RATE_LIMIT_COOLDOWN_MS, parseRateLimitSnapshot, codexRateLimitRetryAtMs, codexAccountRateLimitReached, forbiddenMethod, forbiddenTerminalItem, classifyCodexTurnFailure, scrubbedCodexEnvironment, killWindowsProcessTree, appServerArgs, GUARDIAN_SCRIPT, WINDOWS_RECEIPT_REPLACE_ERROR_CODES, replaceCodexGuardianReceiptFile, writeCodexGuardianSpawnIntent, parseGuardianReceipt, readCodexGuardianReceipt, waitForCodexGuardianState, defaultSpawn, CodexAppServerSession;
|
|
19150
|
+
var CODEX_INFERENCE_PERMISSION_PROFILE, CODEX_REASONING_CONTENT_MAX_UTF8_BYTES, CODEX_REASONING_SUMMARY_MAX_UTF8_BYTES, CODEX_ACCOUNT_PLAN_TYPES, CodexAppServerError, objectOrNull, finiteToken, tokenUsageFromBreakdown, usageFromNotification, validPlanType, nonnegativeSafeIntegerOrNull, nonnegativeFiniteNumberOrNull, parseRateLimitWindow, RATE_LIMIT_REACHED_TYPES, DEFAULT_CODEX_QUOTA_COOLDOWN_MS, MAX_CODEX_QUOTA_COOLDOWN_MS, CODEX_TRANSIENT_RATE_LIMIT_COOLDOWN_MS, parseRateLimitSnapshot, codexRateLimitRetryAtMs, codexAccountRateLimitReached, forbiddenMethod, forbiddenTerminalItem, classifyCodexTurnFailure, scrubbedCodexEnvironment, killWindowsProcessTree, appServerArgs, GUARDIAN_SCRIPT, WINDOWS_RECEIPT_REPLACE_ERROR_CODES, replaceCodexGuardianReceiptFile, writeCodexGuardianSpawnIntent, parseGuardianReceipt, readCodexGuardianReceipt, waitForCodexGuardianState, defaultSpawn, CodexAppServerSession;
|
|
19105
19151
|
var init_codex_app_server = __esm({
|
|
19106
19152
|
"lib/inference-host/codex-app-server.ts"() {
|
|
19107
19153
|
"use strict";
|
|
19108
19154
|
init_config();
|
|
19109
19155
|
CODEX_INFERENCE_PERMISSION_PROFILE = "vtx_inference_readonly";
|
|
19156
|
+
CODEX_REASONING_CONTENT_MAX_UTF8_BYTES = 32768;
|
|
19110
19157
|
CODEX_REASONING_SUMMARY_MAX_UTF8_BYTES = 32768;
|
|
19111
19158
|
CODEX_ACCOUNT_PLAN_TYPES = [
|
|
19112
19159
|
"free",
|
|
@@ -19725,7 +19772,10 @@ child.once('close', async () => {
|
|
|
19725
19772
|
title: "VTX External Inference Host",
|
|
19726
19773
|
version: "external_inference.v1"
|
|
19727
19774
|
},
|
|
19728
|
-
capabilities: {
|
|
19775
|
+
capabilities: {
|
|
19776
|
+
experimentalApi: true,
|
|
19777
|
+
optOutNotificationMethods: ["thread/started"]
|
|
19778
|
+
}
|
|
19729
19779
|
}, {
|
|
19730
19780
|
timeoutMs: Math.max(1, options.deadlineAtMs - Date.now()),
|
|
19731
19781
|
signal: options.signal
|
|
@@ -20259,8 +20309,8 @@ child.once('close', async () => {
|
|
|
20259
20309
|
developerInstructions: options.systemPrompt,
|
|
20260
20310
|
config: {
|
|
20261
20311
|
model_reasoning_effort: options.requestedReasoningEffort,
|
|
20262
|
-
model_reasoning_summary: "
|
|
20263
|
-
show_raw_agent_reasoning:
|
|
20312
|
+
model_reasoning_summary: "none",
|
|
20313
|
+
show_raw_agent_reasoning: true,
|
|
20264
20314
|
hide_agent_reasoning: false,
|
|
20265
20315
|
web_search: "disabled",
|
|
20266
20316
|
features: {
|
|
@@ -20296,7 +20346,7 @@ child.once('close', async () => {
|
|
|
20296
20346
|
const resolvedHome = resolve2(this.codexHome);
|
|
20297
20347
|
const resolvedThreadPath = resolve2(threadPath);
|
|
20298
20348
|
const resolvedSessionsRoot = join2(resolvedHome, "sessions");
|
|
20299
|
-
if (!threadId || !threadPath || !
|
|
20349
|
+
if (!threadId || !threadPath || !isAbsolute2(threadPath) || !resolvedThreadPath.startsWith(`${resolvedSessionsRoot}${sep}`) || !resolvedThreadPath.endsWith(".jsonl") || thread?.ephemeral !== false || thread?.modelProvider !== "openai" || !Array.isArray(thread?.turns) || thread.turns.length !== 0 || result2.model !== options.requestedModel || result2.modelProvider !== "openai" || result2.serviceTier !== "default" || result2.reasoningEffort !== options.requestedReasoningEffort || String(result2.cwd || "") !== options.workspacePath || !Array.isArray(result2.runtimeWorkspaceRoots) || result2.runtimeWorkspaceRoots.length !== 0 || !Array.isArray(result2.instructionSources) || result2.instructionSources.length !== 0 || result2.approvalPolicy !== "never" || result2.approvalsReviewer !== "user" || sandbox?.type !== "readOnly" || sandbox.networkAccess !== false || permission?.id !== CODEX_INFERENCE_PERMISSION_PROFILE || permission.extends !== null) {
|
|
20300
20350
|
throw new CodexAppServerError({
|
|
20301
20351
|
message: "Codex thread isolation or effective settings were invalid.",
|
|
20302
20352
|
category: "adapter",
|
|
@@ -20332,7 +20382,7 @@ child.once('close', async () => {
|
|
|
20332
20382
|
let terminal = null;
|
|
20333
20383
|
let completedReasoningObserved = false;
|
|
20334
20384
|
let completedReasoningSequence = 0;
|
|
20335
|
-
const
|
|
20385
|
+
const completedReasoningContent = /* @__PURE__ */ new Map();
|
|
20336
20386
|
let terminalResolve;
|
|
20337
20387
|
let terminalReject;
|
|
20338
20388
|
const terminalPromise = new Promise((resolve6, reject) => {
|
|
@@ -20352,6 +20402,19 @@ child.once('close', async () => {
|
|
|
20352
20402
|
});
|
|
20353
20403
|
const startedAt = Date.now();
|
|
20354
20404
|
const unsubscribe = this.subscribe(({ method, params }) => {
|
|
20405
|
+
if (method === "thread/started") {
|
|
20406
|
+
const startedThread = objectOrNull(params.thread);
|
|
20407
|
+
if (!String(startedThread?.id || "")) {
|
|
20408
|
+
terminalReject(new CodexAppServerError({
|
|
20409
|
+
message: "Codex returned an invalid thread lifecycle notification.",
|
|
20410
|
+
category: "adapter",
|
|
20411
|
+
code: "invalid_thread_started_notification",
|
|
20412
|
+
retryable: false,
|
|
20413
|
+
dispatchOutcome: requestWritten ? turnId ? "confirmed_dispatched" : "outcome_unknown" : "not_dispatched"
|
|
20414
|
+
}));
|
|
20415
|
+
}
|
|
20416
|
+
return;
|
|
20417
|
+
}
|
|
20355
20418
|
const eventThreadId = String(params.threadId || "");
|
|
20356
20419
|
const scopedMethod = method.startsWith("thread/") || method.startsWith("turn/") || method.startsWith("item/") || method.startsWith("rawResponse") || method === "model/rerouted";
|
|
20357
20420
|
if (scopedMethod && !eventThreadId) {
|
|
@@ -20400,7 +20463,7 @@ child.once('close', async () => {
|
|
|
20400
20463
|
if (method === "thread/settings/updated") {
|
|
20401
20464
|
const settings = objectOrNull(params.threadSettings);
|
|
20402
20465
|
const permission = objectOrNull(settings?.activePermissionProfile);
|
|
20403
|
-
if (!settings || settings.model !== request.requestedModel || settings.modelProvider !== "openai" || settings.effort !== request.requestedReasoningEffort || settings.summary !== "
|
|
20466
|
+
if (!settings || settings.model !== request.requestedModel || settings.modelProvider !== "openai" || settings.effort !== request.requestedReasoningEffort || settings.summary !== "none" || String(settings.cwd || "") !== request.workspacePath || settings.approvalPolicy !== "never" || permission?.id !== CODEX_INFERENCE_PERMISSION_PROFILE || permission.extends !== null) {
|
|
20404
20467
|
terminalReject(new CodexAppServerError({
|
|
20405
20468
|
message: "Codex effective turn settings changed after dispatch.",
|
|
20406
20469
|
category: "adapter",
|
|
@@ -20456,9 +20519,9 @@ child.once('close', async () => {
|
|
|
20456
20519
|
completedReasoningObserved = true;
|
|
20457
20520
|
const itemId = String(item.id || params.itemId || "").trim();
|
|
20458
20521
|
const itemKey = itemId ? `id:${itemId}` : `sequence:${completedReasoningSequence++}`;
|
|
20459
|
-
|
|
20522
|
+
completedReasoningContent.set(
|
|
20460
20523
|
itemKey,
|
|
20461
|
-
Array.isArray(item.
|
|
20524
|
+
Array.isArray(item.content) ? item.content : []
|
|
20462
20525
|
);
|
|
20463
20526
|
}
|
|
20464
20527
|
}
|
|
@@ -20500,7 +20563,7 @@ child.once('close', async () => {
|
|
|
20500
20563
|
model: request.requestedModel,
|
|
20501
20564
|
serviceTier: "default",
|
|
20502
20565
|
effort: request.requestedReasoningEffort,
|
|
20503
|
-
summary: "
|
|
20566
|
+
summary: "none",
|
|
20504
20567
|
outputSchema: request.outputSchema
|
|
20505
20568
|
}, {
|
|
20506
20569
|
timeoutMs: remaining(),
|
|
@@ -20689,10 +20752,10 @@ child.once('close', async () => {
|
|
|
20689
20752
|
const fallbackMessages = items.filter((item) => item?.type === "agentMessage" && item.phase == null);
|
|
20690
20753
|
const answerItem = finalMessages.at(-1) ?? fallbackMessages.at(-1);
|
|
20691
20754
|
const text = typeof answerItem?.text === "string" ? answerItem.text : "";
|
|
20692
|
-
const
|
|
20693
|
-
const
|
|
20694
|
-
const
|
|
20695
|
-
const
|
|
20755
|
+
const reasoningContentSections = completedReasoningObserved ? [...completedReasoningContent.values()] : items.flatMap((item) => item?.type === "reasoning" && Array.isArray(item.content) ? [item.content] : []);
|
|
20756
|
+
const reasoningContentParts = reasoningContentSections.flatMap((content) => content.filter((part) => typeof part === "string" && part.trim().length > 0));
|
|
20757
|
+
const reasoningContentCandidate = reasoningContentParts.length > 0 ? reasoningContentParts.join("\n\n") : null;
|
|
20758
|
+
const reasoningContent = reasoningContentCandidate !== null && Buffer.byteLength(reasoningContentCandidate, "utf8") <= CODEX_REASONING_CONTENT_MAX_UTF8_BYTES ? reasoningContentCandidate : null;
|
|
20696
20759
|
const usage = threadUsage ?? rawResponseUsage;
|
|
20697
20760
|
const responseIdentity = adapterResponseId ?? turnId;
|
|
20698
20761
|
if (!text || !usage || !responseIdentity) {
|
|
@@ -20706,7 +20769,8 @@ child.once('close', async () => {
|
|
|
20706
20769
|
}
|
|
20707
20770
|
return {
|
|
20708
20771
|
text,
|
|
20709
|
-
|
|
20772
|
+
reasoningContent,
|
|
20773
|
+
reasoningSummary: null,
|
|
20710
20774
|
requestedModel: request.requestedModel,
|
|
20711
20775
|
effectiveModel: request.thread.effectiveModel,
|
|
20712
20776
|
requestedReasoningEffort: request.requestedReasoningEffort,
|
|
@@ -20990,7 +21054,7 @@ import {
|
|
|
20990
21054
|
} from "node:fs/promises";
|
|
20991
21055
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
20992
21056
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
20993
|
-
import { isAbsolute as
|
|
21057
|
+
import { isAbsolute as isAbsolute3, join as join4, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
20994
21058
|
var MAX_PROMPT_BYTES2, CODEX_MODEL_NAME_PATTERN, CODEX_REASONING_EFFORT_PATTERN, tokenUsageReceiptSchema, turnResultReceiptSchema, terminalReceiptSchema, recoveryCheckpointSchema, recoveryFileSchema, FileCodexAttemptRecoveryStore, utf8Bytes, assertAttemptActive, tomlString, permissionConfig, ensureDedicatedCodexHome, createIsolatedCodexAttemptResources, createIsolatedCodexHostResources, validateAttemptInput, isStrictDescendant, assertRecoveryResourceScope, removeRecoveredThread, confirmGuardianTerminatedForRecovery, reconcileCodexAttemptRecovery, CodexSubscriptionAdapter;
|
|
20995
21059
|
var init_codex_adapter = __esm({
|
|
20996
21060
|
"lib/inference-host/codex-adapter.ts"() {
|
|
@@ -21013,6 +21077,7 @@ var init_codex_adapter = __esm({
|
|
|
21013
21077
|
});
|
|
21014
21078
|
turnResultReceiptSchema = external_exports.strictObject({
|
|
21015
21079
|
text: external_exports.string().min(1).max(MAX_PROMPT_BYTES2),
|
|
21080
|
+
reasoningContent: external_exports.string().min(1).max(CODEX_REASONING_CONTENT_MAX_UTF8_BYTES).nullable().optional().transform((value) => value ?? null),
|
|
21016
21081
|
reasoningSummary: external_exports.string().min(1).max(CODEX_REASONING_SUMMARY_MAX_UTF8_BYTES).nullable().optional().transform((value) => value ?? null),
|
|
21017
21082
|
requestedModel: external_exports.string().regex(CODEX_MODEL_NAME_PATTERN),
|
|
21018
21083
|
effectiveModel: external_exports.string().regex(CODEX_MODEL_NAME_PATTERN),
|
|
@@ -21025,7 +21090,7 @@ var init_codex_adapter = __esm({
|
|
|
21025
21090
|
timeToFirstTokenMs: external_exports.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).nullable(),
|
|
21026
21091
|
terminalStatus: external_exports.literal("completed")
|
|
21027
21092
|
}).superRefine((value, context) => {
|
|
21028
|
-
if (value.reasoningSummary != null && utf8Bytes(value.reasoningSummary) > CODEX_REASONING_SUMMARY_MAX_UTF8_BYTES || value.usage.cachedInputTokens > value.usage.inputTokens || value.usage.reasoningOutputTokens > value.usage.outputTokens || value.usage.totalTokens !== value.usage.inputTokens + value.usage.outputTokens || value.effectiveModel !== value.requestedModel || value.effectiveReasoningEffort !== value.requestedReasoningEffort) {
|
|
21093
|
+
if (value.reasoningContent != null && utf8Bytes(value.reasoningContent) > CODEX_REASONING_CONTENT_MAX_UTF8_BYTES || value.reasoningSummary != null && utf8Bytes(value.reasoningSummary) > CODEX_REASONING_SUMMARY_MAX_UTF8_BYTES || value.usage.cachedInputTokens > value.usage.inputTokens || value.usage.reasoningOutputTokens > value.usage.outputTokens || value.usage.totalTokens !== value.usage.inputTokens + value.usage.outputTokens || value.effectiveModel !== value.requestedModel || value.effectiveReasoningEffort !== value.requestedReasoningEffort) {
|
|
21029
21094
|
context.addIssue({ code: "custom", message: "Invalid Codex recovery usage or identity." });
|
|
21030
21095
|
}
|
|
21031
21096
|
});
|
|
@@ -21320,7 +21385,7 @@ var init_codex_adapter = __esm({
|
|
|
21320
21385
|
const parentPath = resolve3(parent);
|
|
21321
21386
|
const candidatePath = resolve3(candidate);
|
|
21322
21387
|
const scoped = relative2(parentPath, candidatePath);
|
|
21323
|
-
return scoped.length > 0 && !scoped.startsWith(`..${sep2}`) && scoped !== ".." && !
|
|
21388
|
+
return scoped.length > 0 && !scoped.startsWith(`..${sep2}`) && scoped !== ".." && !isAbsolute3(scoped);
|
|
21324
21389
|
};
|
|
21325
21390
|
assertRecoveryResourceScope = (checkpoint) => {
|
|
21326
21391
|
const temporaryRoot = resolve3(tmpdir2());
|
|
@@ -21410,7 +21475,7 @@ var init_codex_adapter = __esm({
|
|
|
21410
21475
|
}
|
|
21411
21476
|
}
|
|
21412
21477
|
if (checkpoint.threadPath !== null) {
|
|
21413
|
-
if (!
|
|
21478
|
+
if (!isAbsolute3(checkpoint.threadPath) || !isStrictDescendant(
|
|
21414
21479
|
checkpoint.threadPath,
|
|
21415
21480
|
sessionsRoot
|
|
21416
21481
|
) || !checkpoint.threadPath.endsWith(".jsonl")) {
|
|
@@ -28989,11 +29054,20 @@ var init_runner = __esm({
|
|
|
28989
29054
|
options.codexModelCapabilities,
|
|
28990
29055
|
options.adapterRuntimeVersion
|
|
28991
29056
|
),
|
|
28992
|
-
maxConcurrency:
|
|
28993
|
-
|
|
28994
|
-
|
|
28995
|
-
|
|
28996
|
-
|
|
29057
|
+
maxConcurrency: (() => {
|
|
29058
|
+
const value = finitePositiveOption(
|
|
29059
|
+
options.maxConcurrency,
|
|
29060
|
+
DEFAULT_MAX_CONCURRENCY,
|
|
29061
|
+
"Maximum concurrency"
|
|
29062
|
+
);
|
|
29063
|
+
if (value > MAX_CODEX_HOST_CONCURRENCY) {
|
|
29064
|
+
throw new InferenceHostRunnerError(
|
|
29065
|
+
"invalid_configuration",
|
|
29066
|
+
`Maximum concurrency must not exceed ${MAX_CODEX_HOST_CONCURRENCY}.`
|
|
29067
|
+
);
|
|
29068
|
+
}
|
|
29069
|
+
return value;
|
|
29070
|
+
})(),
|
|
28997
29071
|
advertisementTtlMs,
|
|
28998
29072
|
advertisementRefreshLeadMs,
|
|
28999
29073
|
hostHeartbeatMs: finitePositiveOption(
|
|
@@ -29107,6 +29181,8 @@ var init_runner = __esm({
|
|
|
29107
29181
|
providerResponseSchemaVersion: null,
|
|
29108
29182
|
providerResponseMaxUtf8Bytes: null,
|
|
29109
29183
|
providerResponseTextMaxUtf8Bytes: null,
|
|
29184
|
+
providerReasoningContentMaxUtf8Bytes: null,
|
|
29185
|
+
providerReasoningContentSupported: false,
|
|
29110
29186
|
providerReasoningSummaryMaxUtf8Bytes: null,
|
|
29111
29187
|
providerReasoningSummarySupported: false
|
|
29112
29188
|
};
|
|
@@ -29116,6 +29192,7 @@ var init_runner = __esm({
|
|
|
29116
29192
|
const properties = objectRecord(outputSchema.properties);
|
|
29117
29193
|
const schemaVersionProperty = objectRecord(properties?.schema_version);
|
|
29118
29194
|
const responseTextProperty = objectRecord(properties?.response_text);
|
|
29195
|
+
const reasoningContentProperty = objectRecord(properties?.reasoning_content);
|
|
29119
29196
|
const reasoningSummaryProperty = objectRecord(properties?.reasoning_summary);
|
|
29120
29197
|
const schemaVersion = schemaVersionProperty?.const;
|
|
29121
29198
|
const requiredFields = outputSchema.required;
|
|
@@ -29125,18 +29202,22 @@ var init_runner = __esm({
|
|
|
29125
29202
|
"finish_reason",
|
|
29126
29203
|
"refusal_status"
|
|
29127
29204
|
];
|
|
29205
|
+
const providerReasoningContentSupported = reasoningContentProperty !== null;
|
|
29128
29206
|
const providerReasoningSummarySupported = reasoningSummaryProperty !== null;
|
|
29129
|
-
const expectedFields = providerReasoningSummarySupported ? [...baseExpectedFields, "reasoning_summary"] : baseExpectedFields;
|
|
29207
|
+
const expectedFields = providerReasoningContentSupported ? [...baseExpectedFields, "reasoning_content"] : providerReasoningSummarySupported ? [...baseExpectedFields, "reasoning_summary"] : baseExpectedFields;
|
|
29130
29208
|
const responseMaxUtf8Bytes = positiveUtf8ByteLimit(
|
|
29131
29209
|
outputSchema["x-vtx-max-utf8-bytes"]
|
|
29132
29210
|
);
|
|
29133
29211
|
const responseTextMaxUtf8Bytes = positiveUtf8ByteLimit(
|
|
29134
29212
|
responseTextProperty?.["x-vtx-max-utf8-bytes"]
|
|
29135
29213
|
);
|
|
29214
|
+
const reasoningContentMaxUtf8Bytes = positiveUtf8ByteLimit(
|
|
29215
|
+
reasoningContentProperty?.["x-vtx-max-utf8-bytes"]
|
|
29216
|
+
);
|
|
29136
29217
|
const reasoningSummaryMaxUtf8Bytes = positiveUtf8ByteLimit(
|
|
29137
29218
|
reasoningSummaryProperty?.["x-vtx-max-utf8-bytes"]
|
|
29138
29219
|
);
|
|
29139
|
-
if (outputSchema.type !== "object" || outputSchema.additionalProperties !== false || !Array.isArray(requiredFields) || !requiredFields.every((field) => typeof field === "string") || [...requiredFields].sort().join("\0") !== expectedFields.sort().join("\0") || properties === null || !exactObjectKeys(properties, expectedFields) || adapterSchema === null || typeof schemaVersion !== "string" || schemaVersion !== jobInput.output_schema_version || responseTextMaxUtf8Bytes === null || providerReasoningSummarySupported && reasoningSummaryMaxUtf8Bytes === null || responseMaxUtf8Bytes === null) {
|
|
29220
|
+
if (outputSchema.type !== "object" || outputSchema.additionalProperties !== false || !Array.isArray(requiredFields) || !requiredFields.every((field) => typeof field === "string") || [...requiredFields].sort().join("\0") !== expectedFields.sort().join("\0") || properties === null || !exactObjectKeys(properties, expectedFields) || adapterSchema === null || typeof schemaVersion !== "string" || schemaVersion !== jobInput.output_schema_version || responseTextMaxUtf8Bytes === null || providerReasoningContentSupported && reasoningContentMaxUtf8Bytes === null || providerReasoningSummarySupported && reasoningSummaryMaxUtf8Bytes === null || providerReasoningContentSupported && providerReasoningSummarySupported || responseMaxUtf8Bytes === null) {
|
|
29140
29221
|
throw new InferenceHostRunnerError(
|
|
29141
29222
|
"invalid_output_schema",
|
|
29142
29223
|
"The provider-response output schema does not match the canonical envelope structure."
|
|
@@ -29151,6 +29232,8 @@ var init_runner = __esm({
|
|
|
29151
29232
|
providerResponseSchemaVersion: schemaVersion,
|
|
29152
29233
|
providerResponseMaxUtf8Bytes: responseMaxUtf8Bytes,
|
|
29153
29234
|
providerResponseTextMaxUtf8Bytes: responseTextMaxUtf8Bytes,
|
|
29235
|
+
providerReasoningContentMaxUtf8Bytes: reasoningContentMaxUtf8Bytes,
|
|
29236
|
+
providerReasoningContentSupported,
|
|
29154
29237
|
providerReasoningSummaryMaxUtf8Bytes: reasoningSummaryMaxUtf8Bytes,
|
|
29155
29238
|
providerReasoningSummarySupported
|
|
29156
29239
|
};
|
|
@@ -30085,6 +30168,12 @@ var init_runner = __esm({
|
|
|
30085
30168
|
"Codex response text exceeds the immutable provider-response UTF-8 byte limit."
|
|
30086
30169
|
);
|
|
30087
30170
|
}
|
|
30171
|
+
if (outputContract.providerReasoningContentSupported && outputContract.providerReasoningContentMaxUtf8Bytes !== null && adapterResult.reasoningContent !== null && Buffer.byteLength(adapterResult.reasoningContent, "utf8") > outputContract.providerReasoningContentMaxUtf8Bytes) {
|
|
30172
|
+
throw new InferenceHostRunnerError(
|
|
30173
|
+
"output_schema_reasoning_content_too_large",
|
|
30174
|
+
"Codex reasoning content exceeds the immutable provider-response UTF-8 byte limit."
|
|
30175
|
+
);
|
|
30176
|
+
}
|
|
30088
30177
|
if (outputContract.providerReasoningSummarySupported && outputContract.providerReasoningSummaryMaxUtf8Bytes !== null && adapterResult.reasoningSummary !== null && Buffer.byteLength(adapterResult.reasoningSummary, "utf8") > outputContract.providerReasoningSummaryMaxUtf8Bytes) {
|
|
30089
30178
|
throw new InferenceHostRunnerError(
|
|
30090
30179
|
"output_schema_reasoning_summary_too_large",
|
|
@@ -30096,6 +30185,7 @@ var init_runner = __esm({
|
|
|
30096
30185
|
response_text: adapterResult.text,
|
|
30097
30186
|
finish_reason: finishReason,
|
|
30098
30187
|
refusal_status: refusalStatus,
|
|
30188
|
+
...outputContract.providerReasoningContentSupported ? { reasoning_content: adapterResult.reasoningContent } : {},
|
|
30099
30189
|
...outputContract.providerReasoningSummarySupported ? { reasoning_summary: adapterResult.reasoningSummary } : {}
|
|
30100
30190
|
};
|
|
30101
30191
|
validateOutput(outputContract.providerResponseSchema, providerResponse);
|
|
@@ -30316,7 +30406,7 @@ import { createWriteStream, readFileSync } from "node:fs";
|
|
|
30316
30406
|
import { access as access3, chmod as chmod3, mkdir as mkdir3, readFile as readFile5, rm as rm4, writeFile as writeFile2 } from "node:fs/promises";
|
|
30317
30407
|
import { homedir as homedir2 } from "node:os";
|
|
30318
30408
|
import { dirname as dirname4, join as join5, resolve as resolve4 } from "node:path";
|
|
30319
|
-
var SERVICE_NAME, SYSTEMD_UNIT, LAUNCHD_LABEL, SERVICE_COOPERATIVE_STOP_SECONDS, isWindowsSubsystemForLinux, inferenceHostServiceManifestPath, inferenceHostServiceDesiredPath, inferenceHostServiceLogPath, xmlEscape, plistEscape, systemdQuote, defaultRunCommand, managerName, assertManifest, assertDesiredState, readInferenceHostServiceManifest, readInferenceHostServiceDesired, readDesiredAcrossAtomicReplacement, writeDesired, runtimeEnvironment, serviceArguments, windowsOwnedCommandLine, vbScriptString, windowsServiceLauncher, windowsTaskXml, systemdUnit, launchAgentPlist, InferenceHostServiceManager, appendServiceLog, spawnServiceChild, runInferenceHostServiceSupervisor;
|
|
30409
|
+
var SERVICE_NAME, SYSTEMD_UNIT, LAUNCHD_LABEL, SERVICE_COOPERATIVE_STOP_SECONDS, isWindowsSubsystemForLinux, inferenceHostServiceManifestPath, inferenceHostServiceDesiredPath, inferenceHostServiceLogPath, xmlEscape, plistEscape, systemdQuote, defaultRunCommand, managerName, assertRuntimeEnvironment, assertServicePath, assertWorker, assertManifest, assertDesiredState, readInferenceHostServiceManifest, readInferenceHostServiceDesired, readDesiredAcrossAtomicReplacement, writeDesired, runtimeEnvironment, serviceArguments, windowsOwnedCommandLine, vbScriptString, windowsServiceLauncher, windowsTaskXml, systemdUnit, launchAgentPlist, InferenceHostServiceManager, appendServiceLog, spawnServiceChild, runInferenceHostServiceSupervisor;
|
|
30320
30410
|
var init_service = __esm({
|
|
30321
30411
|
"lib/inference-host/service.ts"() {
|
|
30322
30412
|
"use strict";
|
|
@@ -30334,9 +30424,9 @@ var init_service = __esm({
|
|
|
30334
30424
|
}
|
|
30335
30425
|
})())
|
|
30336
30426
|
);
|
|
30337
|
-
inferenceHostServiceManifestPath = (config2) => `${config2.
|
|
30338
|
-
inferenceHostServiceDesiredPath = (config2) => `${config2.
|
|
30339
|
-
inferenceHostServiceLogPath = (config2) => `${config2.
|
|
30427
|
+
inferenceHostServiceManifestPath = (config2) => `${config2.supervisorStatePath}.service.json`;
|
|
30428
|
+
inferenceHostServiceDesiredPath = (config2) => `${config2.supervisorStatePath}.service-desired.json`;
|
|
30429
|
+
inferenceHostServiceLogPath = (config2) => `${config2.supervisorStatePath}.service.log`;
|
|
30340
30430
|
xmlEscape = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30341
30431
|
plistEscape = xmlEscape;
|
|
30342
30432
|
systemdQuote = (value) => `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("%", "%%")}"`;
|
|
@@ -30366,29 +30456,79 @@ var init_service = __esm({
|
|
|
30366
30456
|
if (platform === "linux") return "systemd-user";
|
|
30367
30457
|
throw new Error(`Inference-host background service is unsupported on ${platform}.`);
|
|
30368
30458
|
};
|
|
30459
|
+
assertRuntimeEnvironment = (value) => {
|
|
30460
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
30461
|
+
throw new Error("Inference-host service runtime environment is invalid.");
|
|
30462
|
+
}
|
|
30463
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
30464
|
+
if (!key.startsWith("VTX_") || typeof entry !== "string") {
|
|
30465
|
+
throw new Error("Inference-host service runtime environment is invalid.");
|
|
30466
|
+
}
|
|
30467
|
+
}
|
|
30468
|
+
return value;
|
|
30469
|
+
};
|
|
30470
|
+
assertServicePath = (value) => {
|
|
30471
|
+
if (typeof value !== "string" || !value || /[\r\n\0]/u.test(value)) {
|
|
30472
|
+
throw new Error("Inference-host service manifest paths contain control characters.");
|
|
30473
|
+
}
|
|
30474
|
+
return value;
|
|
30475
|
+
};
|
|
30476
|
+
assertWorker = (value) => {
|
|
30477
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
30478
|
+
throw new Error("Inference-host service worker is invalid.");
|
|
30479
|
+
}
|
|
30480
|
+
const record2 = value;
|
|
30481
|
+
if (typeof record2.instance_name !== "string" || !/^[a-z0-9](?:[a-z0-9-]{0,46}[a-z0-9])?$/u.test(record2.instance_name) || record2.adapter !== "codex" || typeof record2.display_name !== "string" || !record2.display_name || !Number.isSafeInteger(record2.max_concurrency) || Number(record2.max_concurrency) < 1 || Number(record2.max_concurrency) > MAX_CODEX_HOST_CONCURRENCY || record2.authenticated_account_email !== null && typeof record2.authenticated_account_email !== "string" || record2.authenticated_account_plan !== null && typeof record2.authenticated_account_plan !== "string") {
|
|
30482
|
+
throw new Error("Inference-host service worker is invalid.");
|
|
30483
|
+
}
|
|
30484
|
+
return {
|
|
30485
|
+
instance_name: record2.instance_name,
|
|
30486
|
+
adapter: "codex",
|
|
30487
|
+
display_name: record2.display_name,
|
|
30488
|
+
max_concurrency: Number(record2.max_concurrency),
|
|
30489
|
+
authenticated_account_email: record2.authenticated_account_email,
|
|
30490
|
+
authenticated_account_plan: record2.authenticated_account_plan,
|
|
30491
|
+
runtime_environment: assertRuntimeEnvironment(record2.runtime_environment)
|
|
30492
|
+
};
|
|
30493
|
+
};
|
|
30369
30494
|
assertManifest = (value) => {
|
|
30370
30495
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
30371
30496
|
throw new Error("Inference-host service manifest is invalid.");
|
|
30372
30497
|
}
|
|
30373
30498
|
const record2 = value;
|
|
30374
|
-
if (record2.schema_version
|
|
30499
|
+
if (record2.schema_version === "vtx_inference_service_v1") {
|
|
30500
|
+
const legacy = record2;
|
|
30501
|
+
if (legacy.adapter !== "codex" || typeof legacy.installed_at !== "string" || !Number.isFinite(Date.parse(legacy.installed_at)) || typeof legacy.executable !== "string" || !legacy.executable || typeof legacy.script !== "string" || !legacy.script || typeof legacy.display_name !== "string" || !legacy.display_name || typeof legacy.log_path !== "string" || !legacy.log_path) throw new Error("Inference-host service manifest is invalid.");
|
|
30502
|
+
const runtime_environment = assertRuntimeEnvironment(legacy.runtime_environment);
|
|
30503
|
+
const worker = assertWorker({
|
|
30504
|
+
instance_name: "default",
|
|
30505
|
+
adapter: "codex",
|
|
30506
|
+
display_name: legacy.display_name,
|
|
30507
|
+
max_concurrency: Number(runtime_environment.VTX_INFERENCE_HOST_MAX_CONCURRENCY || 1),
|
|
30508
|
+
authenticated_account_email: null,
|
|
30509
|
+
authenticated_account_plan: null,
|
|
30510
|
+
runtime_environment
|
|
30511
|
+
});
|
|
30512
|
+
return {
|
|
30513
|
+
schema_version: "vtx_inference_service_v2",
|
|
30514
|
+
installed_at: legacy.installed_at,
|
|
30515
|
+
executable: assertServicePath(legacy.executable),
|
|
30516
|
+
script: assertServicePath(legacy.script),
|
|
30517
|
+
log_path: assertServicePath(legacy.log_path),
|
|
30518
|
+
workers: [worker]
|
|
30519
|
+
};
|
|
30520
|
+
}
|
|
30521
|
+
if (record2.schema_version !== "vtx_inference_service_v2" || typeof record2.installed_at !== "string" || !Number.isFinite(Date.parse(record2.installed_at)) || typeof record2.executable !== "string" || !record2.executable || typeof record2.script !== "string" || !record2.script || typeof record2.log_path !== "string" || !record2.log_path || !Array.isArray(record2.workers) || record2.workers.length < 1) {
|
|
30375
30522
|
throw new Error("Inference-host service manifest is invalid.");
|
|
30376
30523
|
}
|
|
30377
|
-
|
|
30378
|
-
|
|
30379
|
-
|
|
30380
|
-
|
|
30381
|
-
|
|
30382
|
-
|
|
30383
|
-
throw new Error("Inference-host service manifest paths contain control characters.");
|
|
30384
|
-
}
|
|
30524
|
+
assertServicePath(record2.executable);
|
|
30525
|
+
assertServicePath(record2.script);
|
|
30526
|
+
assertServicePath(record2.log_path);
|
|
30527
|
+
const workers = record2.workers.map(assertWorker);
|
|
30528
|
+
if (new Set(workers.map((worker) => worker.instance_name)).size !== workers.length) {
|
|
30529
|
+
throw new Error("Inference-host service worker names must be unique.");
|
|
30385
30530
|
}
|
|
30386
|
-
|
|
30387
|
-
if (!key.startsWith("VTX_") || typeof entry !== "string") {
|
|
30388
|
-
throw new Error("Inference-host service runtime environment is invalid.");
|
|
30389
|
-
}
|
|
30390
|
-
}
|
|
30391
|
-
return record2;
|
|
30531
|
+
return { ...record2, workers };
|
|
30392
30532
|
};
|
|
30393
30533
|
assertDesiredState = (value) => {
|
|
30394
30534
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -30440,13 +30580,15 @@ var init_service = __esm({
|
|
|
30440
30580
|
}, null, 2)}
|
|
30441
30581
|
`);
|
|
30442
30582
|
};
|
|
30443
|
-
runtimeEnvironment = (config2) => {
|
|
30583
|
+
runtimeEnvironment = (config2, maxConcurrency) => {
|
|
30444
30584
|
const result2 = {
|
|
30445
30585
|
VTX_API_URL: config2.apiUrl,
|
|
30446
|
-
VTX_INFERENCE_HOST_HOME:
|
|
30586
|
+
VTX_INFERENCE_HOST_HOME: config2.baseDir,
|
|
30587
|
+
VTX_INFERENCE_HOST_INSTANCE: config2.instanceName,
|
|
30447
30588
|
VTX_INFERENCE_HOST_CREDENTIAL_STORE: config2.credentialStoreMode,
|
|
30448
30589
|
VTX_INFERENCE_HOST_STATE_PATH: config2.statePath,
|
|
30449
|
-
VTX_INFERENCE_HOST_LOCK_PATH: config2.processLockPath
|
|
30590
|
+
VTX_INFERENCE_HOST_LOCK_PATH: config2.processLockPath,
|
|
30591
|
+
VTX_INFERENCE_HOST_MAX_CONCURRENCY: String(maxConcurrency)
|
|
30450
30592
|
};
|
|
30451
30593
|
if (config2.credentialFilePath) {
|
|
30452
30594
|
result2.VTX_INFERENCE_HOST_CREDENTIAL_FILE = config2.credentialFilePath;
|
|
@@ -30562,7 +30704,7 @@ WantedBy=default.target
|
|
|
30562
30704
|
return inferenceHostServiceLogPath(this.config);
|
|
30563
30705
|
}
|
|
30564
30706
|
controlLockPath() {
|
|
30565
|
-
return `${this.config.
|
|
30707
|
+
return `${this.config.supervisorProcessLockPath}.service-control`;
|
|
30566
30708
|
}
|
|
30567
30709
|
async withControlLock(operation) {
|
|
30568
30710
|
let lock2 = null;
|
|
@@ -30598,12 +30740,12 @@ WantedBy=default.target
|
|
|
30598
30740
|
];
|
|
30599
30741
|
}
|
|
30600
30742
|
definitionPath() {
|
|
30601
|
-
if (this.platform === "win32") return `${this.config.
|
|
30743
|
+
if (this.platform === "win32") return `${this.config.supervisorStatePath}.service-task.xml`;
|
|
30602
30744
|
if (this.platform === "darwin") return join5(this.home, "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
30603
30745
|
return join5(this.home, ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
30604
30746
|
}
|
|
30605
30747
|
windowsLauncherPath() {
|
|
30606
|
-
return `${this.config.
|
|
30748
|
+
return `${this.config.supervisorStatePath}.service-launcher.vbs`;
|
|
30607
30749
|
}
|
|
30608
30750
|
async managerCommand(action) {
|
|
30609
30751
|
const definition = this.definitionPath();
|
|
@@ -30646,37 +30788,19 @@ WantedBy=default.target
|
|
|
30646
30788
|
}
|
|
30647
30789
|
throw new Error("Background service did not reach an active state within 10 seconds.");
|
|
30648
30790
|
}
|
|
30649
|
-
async
|
|
30650
|
-
|
|
30651
|
-
|
|
30652
|
-
async installUnlocked(options) {
|
|
30653
|
-
if (await readInferenceHostServiceManifest(this.manifestPath())) {
|
|
30654
|
-
await this.uninstallUnlocked();
|
|
30655
|
-
}
|
|
30656
|
-
await access3(this.executable);
|
|
30657
|
-
await access3(this.script);
|
|
30658
|
-
const manifest = assertManifest({
|
|
30659
|
-
schema_version: "vtx_inference_service_v1",
|
|
30660
|
-
installed_at: this.now().toISOString(),
|
|
30661
|
-
adapter: options.adapter,
|
|
30662
|
-
executable: this.executable,
|
|
30663
|
-
script: this.script,
|
|
30664
|
-
display_name: options.displayName,
|
|
30665
|
-
log_path: this.logPath(),
|
|
30666
|
-
runtime_environment: runtimeEnvironment(this.config)
|
|
30667
|
-
});
|
|
30668
|
-
const args = serviceArguments(this.script, this.manifestPath());
|
|
30669
|
-
const definition = this.platform === "win32" ? windowsTaskXml(this.windowsLauncherPath(), this.windowsDirectory, this.username) : this.platform === "darwin" ? launchAgentPlist(this.executable, args, this.logPath()) : systemdUnit(this.executable, args);
|
|
30791
|
+
async registerManifestUnlocked(manifest, desiredRunning) {
|
|
30792
|
+
const args = serviceArguments(manifest.script, this.manifestPath());
|
|
30793
|
+
const definition = this.platform === "win32" ? windowsTaskXml(this.windowsLauncherPath(), this.windowsDirectory, this.username) : this.platform === "darwin" ? launchAgentPlist(manifest.executable, args, manifest.log_path) : systemdUnit(manifest.executable, args);
|
|
30670
30794
|
let managerInstallAttempted = false;
|
|
30671
30795
|
try {
|
|
30672
30796
|
await writeAtomicInferencePrivateFile(this.manifestPath(), `${JSON.stringify(manifest, null, 2)}
|
|
30673
30797
|
`);
|
|
30674
|
-
await writeDesired(this.desiredPath(),
|
|
30798
|
+
await writeDesired(this.desiredPath(), desiredRunning, this.now());
|
|
30675
30799
|
await mkdir3(dirname4(this.definitionPath()), { recursive: true, mode: 448 });
|
|
30676
30800
|
if (this.platform === "win32") {
|
|
30677
30801
|
await writeAtomicInferencePrivateFile(
|
|
30678
30802
|
this.windowsLauncherPath(),
|
|
30679
|
-
windowsServiceLauncher(
|
|
30803
|
+
windowsServiceLauncher(manifest.executable, args)
|
|
30680
30804
|
);
|
|
30681
30805
|
await writeFile2(this.definitionPath(), `\uFEFF${definition}`, {
|
|
30682
30806
|
encoding: "utf16le",
|
|
@@ -30693,7 +30817,7 @@ WantedBy=default.target
|
|
|
30693
30817
|
managerInstallAttempted = true;
|
|
30694
30818
|
const installed = await this.managerCommand("install");
|
|
30695
30819
|
if (installed.exitCode !== 0) throw new Error(`Background service installation failed: ${installed.stderr.trim()}`);
|
|
30696
|
-
if (
|
|
30820
|
+
if (desiredRunning) {
|
|
30697
30821
|
const started = await this.managerCommand("start");
|
|
30698
30822
|
if (started.exitCode !== 0 && !/already running|in progress/iu.test(`${started.stdout}
|
|
30699
30823
|
${started.stderr}`)) {
|
|
@@ -30701,6 +30825,7 @@ ${started.stderr}`)) {
|
|
|
30701
30825
|
}
|
|
30702
30826
|
await this.waitForManagerActive();
|
|
30703
30827
|
}
|
|
30828
|
+
return await this.status();
|
|
30704
30829
|
} catch (error48) {
|
|
30705
30830
|
await writeDesired(this.desiredPath(), false, this.now()).catch(() => void 0);
|
|
30706
30831
|
if (managerInstallAttempted) {
|
|
@@ -30728,7 +30853,83 @@ ${cleanup.stderr}`)) {
|
|
|
30728
30853
|
}
|
|
30729
30854
|
throw error48;
|
|
30730
30855
|
}
|
|
30731
|
-
|
|
30856
|
+
}
|
|
30857
|
+
async replaceManifestUnlocked(next, desiredRunning) {
|
|
30858
|
+
const previous = await readInferenceHostServiceManifest(this.manifestPath());
|
|
30859
|
+
const previousDesired = previous ? await readInferenceHostServiceDesired(this.desiredPath()) : false;
|
|
30860
|
+
if (previous) await this.uninstallUnlocked();
|
|
30861
|
+
try {
|
|
30862
|
+
return await this.registerManifestUnlocked(next, desiredRunning);
|
|
30863
|
+
} catch (error48) {
|
|
30864
|
+
if (!previous) throw error48;
|
|
30865
|
+
try {
|
|
30866
|
+
await this.registerManifestUnlocked(previous, previousDesired);
|
|
30867
|
+
} catch (rollbackError) {
|
|
30868
|
+
throw new Error(
|
|
30869
|
+
"Inference-host service reconfiguration failed and the previous supervisor could not be restored.",
|
|
30870
|
+
{ cause: new AggregateError([error48, rollbackError]) }
|
|
30871
|
+
);
|
|
30872
|
+
}
|
|
30873
|
+
throw new Error(
|
|
30874
|
+
"Inference-host service reconfiguration failed; the previous supervisor was restored.",
|
|
30875
|
+
{ cause: error48 }
|
|
30876
|
+
);
|
|
30877
|
+
}
|
|
30878
|
+
}
|
|
30879
|
+
async install(options) {
|
|
30880
|
+
return await this.withControlLock(async () => await this.installUnlocked(options));
|
|
30881
|
+
}
|
|
30882
|
+
async installUnlocked(options) {
|
|
30883
|
+
const existing = await readInferenceHostServiceManifest(this.manifestPath());
|
|
30884
|
+
const normalizedEmail = options.authenticatedAccountEmail?.trim().toLowerCase() || null;
|
|
30885
|
+
const otherWorkers = existing?.workers.filter(
|
|
30886
|
+
(worker) => worker.instance_name !== this.config.instanceName
|
|
30887
|
+
) ?? [];
|
|
30888
|
+
if (otherWorkers.length > 0 && (!normalizedEmail || otherWorkers.some((worker) => !worker.authenticated_account_email))) {
|
|
30889
|
+
throw new Error(
|
|
30890
|
+
"Cannot prove that every installed instance uses a distinct ChatGPT subscription. Reinstall instances with live account identity before adding another."
|
|
30891
|
+
);
|
|
30892
|
+
}
|
|
30893
|
+
if (normalizedEmail && otherWorkers.some((worker) => worker.authenticated_account_email?.trim().toLowerCase() === normalizedEmail)) {
|
|
30894
|
+
throw new Error(
|
|
30895
|
+
"This ChatGPT subscription is already installed under another inference-host instance."
|
|
30896
|
+
);
|
|
30897
|
+
}
|
|
30898
|
+
if (this.config.credentialFilePath && otherWorkers.some((worker) => {
|
|
30899
|
+
const otherPath = worker.runtime_environment.VTX_INFERENCE_HOST_CREDENTIAL_FILE;
|
|
30900
|
+
return otherPath && resolve4(otherPath) === resolve4(this.config.credentialFilePath);
|
|
30901
|
+
})) {
|
|
30902
|
+
throw new Error(
|
|
30903
|
+
"Each inference-host instance must use a different private credential file."
|
|
30904
|
+
);
|
|
30905
|
+
}
|
|
30906
|
+
await access3(this.executable);
|
|
30907
|
+
await access3(this.script);
|
|
30908
|
+
const maxConcurrency = options.maxConcurrency ?? 1;
|
|
30909
|
+
const workers = [
|
|
30910
|
+
...existing?.workers.filter((worker) => worker.instance_name !== this.config.instanceName) ?? [],
|
|
30911
|
+
{
|
|
30912
|
+
instance_name: this.config.instanceName,
|
|
30913
|
+
adapter: options.adapter,
|
|
30914
|
+
display_name: options.displayName,
|
|
30915
|
+
max_concurrency: maxConcurrency,
|
|
30916
|
+
authenticated_account_email: normalizedEmail,
|
|
30917
|
+
authenticated_account_plan: options.authenticatedAccountPlan ?? null,
|
|
30918
|
+
runtime_environment: runtimeEnvironment(this.config, maxConcurrency)
|
|
30919
|
+
}
|
|
30920
|
+
].sort((left, right) => left.instance_name.localeCompare(right.instance_name));
|
|
30921
|
+
const manifest = assertManifest({
|
|
30922
|
+
schema_version: "vtx_inference_service_v2",
|
|
30923
|
+
installed_at: this.now().toISOString(),
|
|
30924
|
+
executable: this.executable,
|
|
30925
|
+
script: this.script,
|
|
30926
|
+
log_path: this.logPath(),
|
|
30927
|
+
workers
|
|
30928
|
+
});
|
|
30929
|
+
return await this.replaceManifestUnlocked(
|
|
30930
|
+
manifest,
|
|
30931
|
+
options.startImmediately !== false
|
|
30932
|
+
);
|
|
30732
30933
|
}
|
|
30733
30934
|
async start() {
|
|
30734
30935
|
return await this.withControlLock(async () => await this.startUnlocked());
|
|
@@ -30755,11 +30956,12 @@ ${result2.stderr}`)) {
|
|
|
30755
30956
|
return await this.withControlLock(async () => await this.stopUnlocked());
|
|
30756
30957
|
}
|
|
30757
30958
|
async stopUnlocked() {
|
|
30758
|
-
|
|
30959
|
+
const manifest = await readInferenceHostServiceManifest(this.manifestPath());
|
|
30960
|
+
if (!manifest) {
|
|
30759
30961
|
throw new Error("Inference-host service is not installed.");
|
|
30760
30962
|
}
|
|
30761
30963
|
await writeDesired(this.desiredPath(), false, this.now());
|
|
30762
|
-
const serviceLockPath = `${this.config.
|
|
30964
|
+
const serviceLockPath = `${this.config.supervisorProcessLockPath}.service`;
|
|
30763
30965
|
let serviceReleased = false;
|
|
30764
30966
|
for (let attempt = 0; attempt < this.stopWaitAttempts; attempt += 1) {
|
|
30765
30967
|
try {
|
|
@@ -30777,7 +30979,7 @@ ${result2.stderr}`)) {
|
|
|
30777
30979
|
}
|
|
30778
30980
|
if (!serviceReleased) {
|
|
30779
30981
|
throw new Error(
|
|
30780
|
-
`Inference-host
|
|
30982
|
+
`Inference-host workers did not stop cooperatively within ${SERVICE_COOPERATIVE_STOP_SECONDS} seconds; refusing forced termination while cleanup may be pending.`
|
|
30781
30983
|
);
|
|
30782
30984
|
}
|
|
30783
30985
|
const result2 = await this.managerCommand("stop");
|
|
@@ -30803,8 +31005,15 @@ ${result2.stderr}`)) {
|
|
|
30803
31005
|
manager_active: managerActive,
|
|
30804
31006
|
manager: managerName(this.platform),
|
|
30805
31007
|
manager_state: result2.exitCode === 0 ? output3 || "installed" : "not-installed",
|
|
30806
|
-
adapter: manifest
|
|
30807
|
-
log_path: manifest?.log_path ?? this.logPath()
|
|
31008
|
+
adapter: manifest ? "codex" : null,
|
|
31009
|
+
log_path: manifest?.log_path ?? this.logPath(),
|
|
31010
|
+
workers: manifest?.workers.map((worker) => ({
|
|
31011
|
+
instance_name: worker.instance_name,
|
|
31012
|
+
display_name: worker.display_name,
|
|
31013
|
+
max_concurrency: worker.max_concurrency,
|
|
31014
|
+
authenticated_account_email: worker.authenticated_account_email,
|
|
31015
|
+
authenticated_account_plan: worker.authenticated_account_plan
|
|
31016
|
+
})) ?? []
|
|
30808
31017
|
};
|
|
30809
31018
|
}
|
|
30810
31019
|
async logs(lines = 100) {
|
|
@@ -30819,6 +31028,24 @@ ${result2.stderr}`)) {
|
|
|
30819
31028
|
throw error48;
|
|
30820
31029
|
}
|
|
30821
31030
|
}
|
|
31031
|
+
async uninstallInstance(instanceName) {
|
|
31032
|
+
return await this.withControlLock(async () => {
|
|
31033
|
+
const manifest = await readInferenceHostServiceManifest(this.manifestPath());
|
|
31034
|
+
if (!manifest) throw new Error("Inference-host service is not installed.");
|
|
31035
|
+
if (!manifest.workers.some((worker) => worker.instance_name === instanceName)) {
|
|
31036
|
+
throw new Error(`Inference-host instance ${instanceName} is not installed.`);
|
|
31037
|
+
}
|
|
31038
|
+
const remaining = manifest.workers.filter(
|
|
31039
|
+
(worker) => worker.instance_name !== instanceName
|
|
31040
|
+
);
|
|
31041
|
+
if (remaining.length === 0) return await this.uninstallUnlocked();
|
|
31042
|
+
return await this.replaceManifestUnlocked({
|
|
31043
|
+
...manifest,
|
|
31044
|
+
installed_at: this.now().toISOString(),
|
|
31045
|
+
workers: remaining
|
|
31046
|
+
}, await readInferenceHostServiceDesired(this.desiredPath()));
|
|
31047
|
+
});
|
|
31048
|
+
}
|
|
30822
31049
|
async uninstall() {
|
|
30823
31050
|
return await this.withControlLock(async () => await this.uninstallUnlocked());
|
|
30824
31051
|
}
|
|
@@ -30848,7 +31075,8 @@ ${result2.stderr}`)) {
|
|
|
30848
31075
|
manager: managerName(this.platform),
|
|
30849
31076
|
manager_state: "not-installed",
|
|
30850
31077
|
adapter: null,
|
|
30851
|
-
log_path: manifest.log_path
|
|
31078
|
+
log_path: manifest.log_path,
|
|
31079
|
+
workers: []
|
|
30852
31080
|
};
|
|
30853
31081
|
}
|
|
30854
31082
|
};
|
|
@@ -30861,21 +31089,21 @@ ${result2.stderr}`)) {
|
|
|
30861
31089
|
`, resolvePromise);
|
|
30862
31090
|
});
|
|
30863
31091
|
};
|
|
30864
|
-
spawnServiceChild = async (manifest, signal) => {
|
|
31092
|
+
spawnServiceChild = async (manifest, worker, signal) => {
|
|
30865
31093
|
const args = [
|
|
30866
31094
|
manifest.script,
|
|
30867
31095
|
"inference-host",
|
|
30868
31096
|
"run",
|
|
30869
31097
|
"--json",
|
|
30870
31098
|
"--display-name",
|
|
30871
|
-
|
|
31099
|
+
worker.display_name
|
|
30872
31100
|
];
|
|
30873
31101
|
const startedAt = Date.now();
|
|
30874
31102
|
const log = createWriteStream(manifest.log_path, { flags: "a", mode: 384 });
|
|
30875
31103
|
return await new Promise((resolvePromise, reject) => {
|
|
30876
31104
|
let stdout = "";
|
|
30877
31105
|
const child = spawn5(manifest.executable, args, {
|
|
30878
|
-
env: { ...process.env, ...
|
|
31106
|
+
env: { ...process.env, ...worker.runtime_environment },
|
|
30879
31107
|
windowsHide: true,
|
|
30880
31108
|
stdio: ["ignore", "pipe", "pipe"]
|
|
30881
31109
|
});
|
|
@@ -30919,64 +31147,72 @@ ${result2.stderr}`)) {
|
|
|
30919
31147
|
runInferenceHostServiceSupervisor = async (manifestPath, options = {}) => {
|
|
30920
31148
|
const manifest = await readInferenceHostServiceManifest(manifestPath);
|
|
30921
31149
|
if (!manifest) throw new Error("Inference-host service manifest is missing.");
|
|
30922
|
-
const desiredPath =
|
|
31150
|
+
const desiredPath = manifestPath.replace(/\.service\.json$/u, ".service-desired.json");
|
|
30923
31151
|
const signal = options.signal ?? new AbortController().signal;
|
|
30924
31152
|
const sleep4 = options.sleep ?? (async (milliseconds) => {
|
|
30925
31153
|
await new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds));
|
|
30926
31154
|
});
|
|
30927
31155
|
const launch = options.runWorker ?? options.spawnChild ?? spawnServiceChild;
|
|
30928
|
-
|
|
30929
|
-
|
|
30930
|
-
|
|
30931
|
-
|
|
30932
|
-
|
|
30933
|
-
|
|
30934
|
-
|
|
30935
|
-
let workerComplete = false;
|
|
30936
|
-
let monitorError = null;
|
|
30937
|
-
const desiredMonitor = (async () => {
|
|
30938
|
-
while (!workerComplete && !workerController.signal.aborted) {
|
|
30939
|
-
await sleep4(500);
|
|
30940
|
-
if (!await readDesiredAcrossAtomicReplacement(desiredPath)) {
|
|
30941
|
-
workerController.abort();
|
|
30942
|
-
break;
|
|
30943
|
-
}
|
|
30944
|
-
}
|
|
30945
|
-
})().catch((error48) => {
|
|
30946
|
-
monitorError = error48;
|
|
30947
|
-
workerController.abort();
|
|
30948
|
-
});
|
|
30949
|
-
let result2;
|
|
31156
|
+
await appendServiceLog(manifest.log_path, "service_supervisor_started", {
|
|
31157
|
+
adapter: "codex",
|
|
31158
|
+
instances: manifest.workers.map((worker) => worker.instance_name)
|
|
31159
|
+
});
|
|
31160
|
+
const superviseWorker = async (worker) => {
|
|
31161
|
+
let failures = 0;
|
|
31162
|
+
while (!signal.aborted && await readDesiredAcrossAtomicReplacement(desiredPath)) {
|
|
30950
31163
|
try {
|
|
30951
|
-
|
|
30952
|
-
|
|
30953
|
-
|
|
30954
|
-
|
|
30955
|
-
|
|
30956
|
-
|
|
30957
|
-
|
|
30958
|
-
|
|
30959
|
-
|
|
30960
|
-
|
|
30961
|
-
|
|
30962
|
-
|
|
30963
|
-
|
|
30964
|
-
|
|
30965
|
-
|
|
30966
|
-
|
|
30967
|
-
|
|
30968
|
-
|
|
30969
|
-
|
|
30970
|
-
|
|
30971
|
-
|
|
30972
|
-
|
|
30973
|
-
|
|
30974
|
-
|
|
30975
|
-
|
|
30976
|
-
|
|
30977
|
-
|
|
31164
|
+
const workerController = new AbortController();
|
|
31165
|
+
const forwardAbort = () => workerController.abort();
|
|
31166
|
+
signal.addEventListener("abort", forwardAbort, { once: true });
|
|
31167
|
+
let workerComplete = false;
|
|
31168
|
+
let monitorError = null;
|
|
31169
|
+
const desiredMonitor = (async () => {
|
|
31170
|
+
while (!workerComplete && !workerController.signal.aborted) {
|
|
31171
|
+
await sleep4(500);
|
|
31172
|
+
if (!await readDesiredAcrossAtomicReplacement(desiredPath)) {
|
|
31173
|
+
workerController.abort();
|
|
31174
|
+
break;
|
|
31175
|
+
}
|
|
31176
|
+
}
|
|
31177
|
+
})().catch((error48) => {
|
|
31178
|
+
monitorError = error48;
|
|
31179
|
+
workerController.abort();
|
|
31180
|
+
});
|
|
31181
|
+
let result2;
|
|
31182
|
+
try {
|
|
31183
|
+
result2 = await launch(manifest, worker, workerController.signal);
|
|
31184
|
+
} finally {
|
|
31185
|
+
workerComplete = true;
|
|
31186
|
+
workerController.abort();
|
|
31187
|
+
signal.removeEventListener("abort", forwardAbort);
|
|
31188
|
+
await desiredMonitor;
|
|
31189
|
+
}
|
|
31190
|
+
if (monitorError) throw monitorError;
|
|
31191
|
+
if (signal.aborted || !await readDesiredAcrossAtomicReplacement(desiredPath)) break;
|
|
31192
|
+
failures = result2.uptimeMs >= 6e4 ? 0 : failures + 1;
|
|
31193
|
+
const retryAfterMs = Math.min(1e3 * 2 ** Math.min(failures, 5), 3e4);
|
|
31194
|
+
await appendServiceLog(manifest.log_path, "worker_exited", {
|
|
31195
|
+
instance_name: worker.instance_name,
|
|
31196
|
+
exit_code: result2.exitCode,
|
|
31197
|
+
uptime_ms: result2.uptimeMs,
|
|
31198
|
+
drain_reason: result2.drainReason ?? null,
|
|
31199
|
+
retry_after_ms: retryAfterMs
|
|
31200
|
+
});
|
|
31201
|
+
await sleep4(retryAfterMs);
|
|
31202
|
+
} catch (error48) {
|
|
31203
|
+
if (signal.aborted) break;
|
|
31204
|
+
failures += 1;
|
|
31205
|
+
const retryAfterMs = Math.min(1e3 * 2 ** Math.min(failures, 5), 3e4);
|
|
31206
|
+
await appendServiceLog(manifest.log_path, "worker_launch_failed", {
|
|
31207
|
+
instance_name: worker.instance_name,
|
|
31208
|
+
error: error48 instanceof Error ? error48.message : "unknown",
|
|
31209
|
+
retry_after_ms: retryAfterMs
|
|
31210
|
+
});
|
|
31211
|
+
await sleep4(retryAfterMs);
|
|
31212
|
+
}
|
|
30978
31213
|
}
|
|
30979
|
-
}
|
|
31214
|
+
};
|
|
31215
|
+
await Promise.all(manifest.workers.map(superviseWorker));
|
|
30980
31216
|
await appendServiceLog(manifest.log_path, "service_supervisor_stopped");
|
|
30981
31217
|
};
|
|
30982
31218
|
}
|
|
@@ -31066,7 +31302,7 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
|
|
|
31066
31302
|
};
|
|
31067
31303
|
}
|
|
31068
31304
|
}
|
|
31069
|
-
var INFERENCE_HOST_CLI_VERSION, runtimeReceiptPath, codexRecoveryPath, codexGuardianReceiptRoot, revocationCheckpointPath, foregroundHostLockPath, AGENT_HEARTBEAT_INTERVAL_MS, AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS, retryableAgentHeartbeatError, assertRevocationCheckpoint, readRevocationCheckpoint, writeRevocationCheckpoint, clearRevocationCheckpoint, render, INFERENCE_HOST_HELP,
|
|
31305
|
+
var INFERENCE_HOST_CLI_VERSION, runtimeReceiptPath, codexRecoveryPath, codexGuardianReceiptRoot, revocationCheckpointPath, foregroundHostLockPath, AGENT_HEARTBEAT_INTERVAL_MS, AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS, retryableAgentHeartbeatError, assertRevocationCheckpoint, readRevocationCheckpoint, writeRevocationCheckpoint, clearRevocationCheckpoint, render, INFERENCE_HOST_HELP, parseHostConcurrency, parseInferenceHostArgs, defaultOpenBrowser, defaultRegisterLifecycleSignalHandlers, lifecycleCancellation, configuredCredentialStore, accountKeyForState, assertCredentialMatchesState2, revocationCheckpointForCredential, assertRevocationCheckpointMatchesLocalIdentity, fileExistsPrivately, inspectCodexAuthentication, clearLocalRuntimeArtifacts, assertDurableServiceUninstalled, assertLocalRuntimeArtifactsMayBeDiscarded, defaultRunForeground, login, codexLogin, codexLogout, localStatus, doctor, cleanupLogin, runHost, defaultReadStdin, parseAgentStdin, agentOperationId, agentSession, agentConnect, agentRun, agentNext, agentComplete, agentFail, withAgentCommandLock, serviceCommand, hasExplicitCredentialStoreConfiguration, commandUsesInstalledServiceCredentials, resolveInferenceHostCommandConfig;
|
|
31070
31306
|
var init_cli = __esm({
|
|
31071
31307
|
"lib/inference-host/cli.ts"() {
|
|
31072
31308
|
"use strict";
|
|
@@ -31170,6 +31406,8 @@ Commands:
|
|
|
31170
31406
|
|
|
31171
31407
|
Common options:
|
|
31172
31408
|
--json Emit machine-readable JSON
|
|
31409
|
+
--instance NAME Target an isolated local subscription instance (default: default)
|
|
31410
|
+
--max-concurrency N Automated Codex slots for this subscription (1-8; default: 3)
|
|
31173
31411
|
--help, -h Show this help
|
|
31174
31412
|
|
|
31175
31413
|
If the OS credential store cannot retain the VTX grant, set
|
|
@@ -31177,23 +31415,31 @@ VTX_INFERENCE_HOST_CREDENTIAL_STORE=file before login to use the supported
|
|
|
31177
31415
|
private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
31178
31416
|
|
|
31179
31417
|
Durable service:
|
|
31180
|
-
vtx inference-host
|
|
31418
|
+
vtx inference-host login --instance codex-1
|
|
31419
|
+
vtx inference-host codex-login --instance codex-1
|
|
31420
|
+
vtx inference-host service install --instance codex-1
|
|
31421
|
+
vtx inference-host login --instance codex-2
|
|
31422
|
+
vtx inference-host codex-login --instance codex-2
|
|
31423
|
+
vtx inference-host service install --instance codex-2
|
|
31424
|
+
vtx inference-host service uninstall --instance codex-2
|
|
31181
31425
|
vtx inference-host service <start|stop|status|logs|uninstall>
|
|
31182
31426
|
`;
|
|
31183
|
-
|
|
31427
|
+
parseHostConcurrency = (raw, label) => {
|
|
31184
31428
|
const value = Number(raw);
|
|
31185
|
-
if (value
|
|
31186
|
-
throw new Error(`${label} must be
|
|
31429
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > MAX_CODEX_HOST_CONCURRENCY) {
|
|
31430
|
+
throw new Error(`${label} must be an integer from 1 through ${MAX_CODEX_HOST_CONCURRENCY}.`);
|
|
31187
31431
|
}
|
|
31188
31432
|
return value;
|
|
31189
31433
|
};
|
|
31190
31434
|
parseInferenceHostArgs = (argv2, env) => {
|
|
31191
31435
|
let json2 = String(env.VTX_OUTPUT_JSON || "").trim().toLowerCase() === "true";
|
|
31192
31436
|
let once = false;
|
|
31193
|
-
let maxConcurrency =
|
|
31194
|
-
String(env.VTX_INFERENCE_HOST_MAX_CONCURRENCY ||
|
|
31437
|
+
let maxConcurrency = parseHostConcurrency(
|
|
31438
|
+
String(env.VTX_INFERENCE_HOST_MAX_CONCURRENCY || DEFAULT_CODEX_HOST_CONCURRENCY),
|
|
31195
31439
|
"VTX_INFERENCE_HOST_MAX_CONCURRENCY"
|
|
31196
31440
|
);
|
|
31441
|
+
let instanceName = String(env.VTX_INFERENCE_HOST_INSTANCE || "default").trim();
|
|
31442
|
+
let instanceExplicit = Boolean(String(env.VTX_INFERENCE_HOST_INSTANCE || "").trim());
|
|
31197
31443
|
let displayName = String(env.VTX_INFERENCE_HOST_DISPLAY_NAME || "").trim() || "Codex subscription host";
|
|
31198
31444
|
let displayNameExplicit = Boolean(String(env.VTX_INFERENCE_HOST_DISPLAY_NAME || "").trim());
|
|
31199
31445
|
let adapter = null;
|
|
@@ -31217,7 +31463,7 @@ Durable service:
|
|
|
31217
31463
|
if (argument === "--max-concurrency") {
|
|
31218
31464
|
const raw = argv2[index + 1];
|
|
31219
31465
|
if (!raw) throw new Error("--max-concurrency requires a value.");
|
|
31220
|
-
maxConcurrency =
|
|
31466
|
+
maxConcurrency = parseHostConcurrency(raw, "--max-concurrency");
|
|
31221
31467
|
index += 1;
|
|
31222
31468
|
continue;
|
|
31223
31469
|
}
|
|
@@ -31229,7 +31475,7 @@ Durable service:
|
|
|
31229
31475
|
index += 1;
|
|
31230
31476
|
continue;
|
|
31231
31477
|
}
|
|
31232
|
-
if (["--adapter", "--model", "--model-label", "--effort", "--wait-seconds", "--lines", "--service-manifest"].includes(argument)) {
|
|
31478
|
+
if (["--adapter", "--model", "--model-label", "--effort", "--wait-seconds", "--lines", "--service-manifest", "--instance"].includes(argument)) {
|
|
31233
31479
|
const raw = argv2[index + 1];
|
|
31234
31480
|
if (!raw?.trim()) throw new Error(`${argument} requires a value.`);
|
|
31235
31481
|
if (argument === "--adapter") adapter = raw.trim();
|
|
@@ -31249,6 +31495,10 @@ Durable service:
|
|
|
31249
31495
|
}
|
|
31250
31496
|
}
|
|
31251
31497
|
if (argument === "--service-manifest") serviceManifestPath = resolve5(raw.trim());
|
|
31498
|
+
if (argument === "--instance") {
|
|
31499
|
+
instanceName = raw.trim();
|
|
31500
|
+
instanceExplicit = true;
|
|
31501
|
+
}
|
|
31252
31502
|
index += 1;
|
|
31253
31503
|
continue;
|
|
31254
31504
|
}
|
|
@@ -31276,6 +31526,8 @@ Durable service:
|
|
|
31276
31526
|
json: json2,
|
|
31277
31527
|
once,
|
|
31278
31528
|
maxConcurrency,
|
|
31529
|
+
instanceName,
|
|
31530
|
+
instanceExplicit,
|
|
31279
31531
|
displayName,
|
|
31280
31532
|
adapter,
|
|
31281
31533
|
modelId,
|
|
@@ -31387,9 +31639,10 @@ Durable service:
|
|
|
31387
31639
|
await clearInferenceHostLocalState(config2.statePath);
|
|
31388
31640
|
};
|
|
31389
31641
|
assertDurableServiceUninstalled = async (config2) => {
|
|
31390
|
-
|
|
31642
|
+
const manifest = await readInferenceHostServiceManifest(`${config2.supervisorStatePath}.service.json`);
|
|
31643
|
+
if (manifest?.workers.some((worker) => worker.instance_name === config2.instanceName)) {
|
|
31391
31644
|
throw new Error(
|
|
31392
|
-
|
|
31645
|
+
`Uninstall the durable inference-host service before changing credentials for instance ${config2.instanceName}.`
|
|
31393
31646
|
);
|
|
31394
31647
|
}
|
|
31395
31648
|
};
|
|
@@ -32417,55 +32670,19 @@ Waiting for approval...
|
|
|
32417
32670
|
if (!parsed.serviceManifestPath) throw new Error("Internal service manifest path is required.");
|
|
32418
32671
|
const serviceManifest = await readInferenceHostServiceManifest(parsed.serviceManifestPath);
|
|
32419
32672
|
if (!serviceManifest) throw new Error("Inference-host service manifest is missing.");
|
|
32420
|
-
const
|
|
32673
|
+
const supervisorConfig = resolveInferenceHostConfig({
|
|
32421
32674
|
...env,
|
|
32422
|
-
...serviceManifest.runtime_environment
|
|
32675
|
+
...serviceManifest.workers[0].runtime_environment
|
|
32423
32676
|
});
|
|
32424
32677
|
const serviceLock = await acquireInferenceHostProcessLock(
|
|
32425
|
-
`${
|
|
32678
|
+
`${supervisorConfig.supervisorProcessLockPath}.service`
|
|
32426
32679
|
);
|
|
32427
32680
|
const cancellation = lifecycleCancellation(dependencies);
|
|
32428
32681
|
try {
|
|
32429
32682
|
await (dependencies.runServiceSupervisor ?? runInferenceHostServiceSupervisor)(
|
|
32430
32683
|
parsed.serviceManifestPath,
|
|
32431
32684
|
{
|
|
32432
|
-
signal: cancellation.signal
|
|
32433
|
-
runWorker: async (manifest, signal) => {
|
|
32434
|
-
const startedAt = Date.now();
|
|
32435
|
-
const serviceEnv = { ...env, ...manifest.runtime_environment };
|
|
32436
|
-
const serviceConfig2 = resolveInferenceHostConfig(serviceEnv);
|
|
32437
|
-
const unregister = (abort) => {
|
|
32438
|
-
const onAbort = () => abort("SIGTERM");
|
|
32439
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
32440
|
-
return () => signal.removeEventListener("abort", onAbort);
|
|
32441
|
-
};
|
|
32442
|
-
const result2 = await runHost(serviceConfig2, {
|
|
32443
|
-
...parsed,
|
|
32444
|
-
command: "run",
|
|
32445
|
-
serviceAction: null,
|
|
32446
|
-
serviceManifestPath: null,
|
|
32447
|
-
displayName: manifest.display_name,
|
|
32448
|
-
once: false
|
|
32449
|
-
}, serviceEnv, {
|
|
32450
|
-
...dependencies,
|
|
32451
|
-
registerLifecycleSignalHandlers: unregister
|
|
32452
|
-
}, warnings);
|
|
32453
|
-
let drainReason = null;
|
|
32454
|
-
try {
|
|
32455
|
-
const summary = JSON.parse(result2.stdout);
|
|
32456
|
-
if (summary && typeof summary === "object" && !Array.isArray(summary) && typeof summary.drain_reason === "string" && /^[a-z0-9_]{1,96}$/u.test(
|
|
32457
|
-
summary.drain_reason
|
|
32458
|
-
)) {
|
|
32459
|
-
drainReason = summary.drain_reason;
|
|
32460
|
-
}
|
|
32461
|
-
} catch {
|
|
32462
|
-
}
|
|
32463
|
-
return {
|
|
32464
|
-
exitCode: result2.exitCode,
|
|
32465
|
-
uptimeMs: Date.now() - startedAt,
|
|
32466
|
-
drainReason
|
|
32467
|
-
};
|
|
32468
|
-
}
|
|
32685
|
+
signal: cancellation.signal
|
|
32469
32686
|
}
|
|
32470
32687
|
);
|
|
32471
32688
|
return { exitCode: 0, stdout: "", stderr: "" };
|
|
@@ -32499,12 +32716,18 @@ Waiting for approval...
|
|
|
32499
32716
|
throw new Error("Run vtx inference-host codex-login before installing the automated Codex service.");
|
|
32500
32717
|
}
|
|
32501
32718
|
const binary = await (dependencies.resolveBinary ?? resolvePinnedCodexBinary)(env);
|
|
32502
|
-
await (dependencies.preflightCodex ?? preflightCodexSubscription)({
|
|
32719
|
+
const preflight = await (dependencies.preflightCodex ?? preflightCodexSubscription)({
|
|
32503
32720
|
binary,
|
|
32504
32721
|
codexHome: config2.codexHomePath,
|
|
32505
32722
|
deadlineAtMs: Date.now() + 3e4
|
|
32506
32723
|
});
|
|
32507
|
-
const status = await manager.install({
|
|
32724
|
+
const status = await manager.install({
|
|
32725
|
+
adapter: "codex",
|
|
32726
|
+
displayName: parsed.displayName,
|
|
32727
|
+
maxConcurrency: parsed.maxConcurrency,
|
|
32728
|
+
authenticatedAccountEmail: preflight?.authenticated_account_email ?? null,
|
|
32729
|
+
authenticatedAccountPlan: preflight?.authenticated_account_plan ?? null
|
|
32730
|
+
});
|
|
32508
32731
|
return {
|
|
32509
32732
|
exitCode: 0,
|
|
32510
32733
|
stdout: render({ status: "service_installed", ...status }, parsed.json),
|
|
@@ -32530,7 +32753,8 @@ Waiting for approval...
|
|
|
32530
32753
|
return { exitCode: lifecycleMatches ? 0 : 1, stdout: render(status, parsed.json), stderr: "" };
|
|
32531
32754
|
}
|
|
32532
32755
|
if (action === "uninstall") {
|
|
32533
|
-
|
|
32756
|
+
const status = parsed.instanceExplicit ? await manager.uninstallInstance(config2.instanceName) : await manager.uninstall();
|
|
32757
|
+
return { exitCode: 0, stdout: render({ status: "service_uninstalled", ...status }, parsed.json), stderr: "" };
|
|
32534
32758
|
}
|
|
32535
32759
|
throw new Error("Usage: vtx inference-host service <install|start|stop|status|logs|uninstall>.");
|
|
32536
32760
|
};
|
|
@@ -32539,16 +32763,20 @@ Waiting for approval...
|
|
|
32539
32763
|
);
|
|
32540
32764
|
commandUsesInstalledServiceCredentials = (parsed) => parsed.command === "status" || parsed.command === "doctor" || parsed.command === "service" && parsed.serviceAction === "install";
|
|
32541
32765
|
resolveInferenceHostCommandConfig = async (parsed, env) => {
|
|
32542
|
-
const
|
|
32766
|
+
const selectedEnv = {
|
|
32767
|
+
...env,
|
|
32768
|
+
VTX_INFERENCE_HOST_INSTANCE: parsed.instanceName
|
|
32769
|
+
};
|
|
32770
|
+
const baseConfig = resolveInferenceHostConfig(selectedEnv);
|
|
32543
32771
|
if (!commandUsesInstalledServiceCredentials(parsed) || hasExplicitCredentialStoreConfiguration(env)) {
|
|
32544
32772
|
return baseConfig;
|
|
32545
32773
|
}
|
|
32546
|
-
const manifestPath = `${baseConfig.
|
|
32774
|
+
const manifestPath = `${baseConfig.supervisorStatePath}.service.json`;
|
|
32547
32775
|
const manifest = await readInferenceHostServiceManifest(manifestPath);
|
|
32548
32776
|
if (!manifest) return baseConfig;
|
|
32549
32777
|
const installedConfig = resolveInferenceHostConfig({
|
|
32550
|
-
...
|
|
32551
|
-
...manifest.runtime_environment
|
|
32778
|
+
...selectedEnv,
|
|
32779
|
+
...manifest.workers.find((worker) => worker.instance_name === baseConfig.instanceName)?.runtime_environment
|
|
32552
32780
|
});
|
|
32553
32781
|
if (resolve5(installedConfig.statePath) !== resolve5(baseConfig.statePath)) {
|
|
32554
32782
|
throw new Error(
|
|
@@ -49975,7 +50203,11 @@ function buildHeadlessExchangeConfig(input) {
|
|
|
49975
50203
|
user_fills_ttl_seconds: readCacheNumberField("user_fills_ttl_seconds"),
|
|
49976
50204
|
stale_if_429_max_age_seconds: readCacheNumberField("stale_if_429_max_age_seconds")
|
|
49977
50205
|
},
|
|
49978
|
-
client_runtime_hyperliquid_case_sensitive_symbols: Array.isArray(input.client_runtime_hyperliquid_case_sensitive_symbols) ? input.client_runtime_hyperliquid_case_sensitive_symbols : null
|
|
50206
|
+
client_runtime_hyperliquid_case_sensitive_symbols: Array.isArray(input.client_runtime_hyperliquid_case_sensitive_symbols) ? input.client_runtime_hyperliquid_case_sensitive_symbols : null,
|
|
50207
|
+
client_runtime_hyperliquid_perp_dexs: input.client_runtime_hyperliquid_perp_dexs ? {
|
|
50208
|
+
enabled: input.client_runtime_hyperliquid_perp_dexs.enabled === true,
|
|
50209
|
+
allowed_dexes: Array.isArray(input.client_runtime_hyperliquid_perp_dexs.allowed_dexes) ? input.client_runtime_hyperliquid_perp_dexs.allowed_dexes.map((dex) => String(dex).trim()).filter(Boolean) : []
|
|
50210
|
+
} : void 0
|
|
49979
50211
|
};
|
|
49980
50212
|
}
|
|
49981
50213
|
async function fetchLocalHyperliquidSnapshot(input) {
|
|
@@ -49991,7 +50223,7 @@ async function fetchLocalHyperliquidSnapshot(input) {
|
|
|
49991
50223
|
symbol: input.symbol,
|
|
49992
50224
|
tickerPrice: 0,
|
|
49993
50225
|
leverage,
|
|
49994
|
-
aggregatePerpDexs:
|
|
50226
|
+
aggregatePerpDexs: true
|
|
49995
50227
|
});
|
|
49996
50228
|
const clientExchangeSnapshot = buildClientExchangeSnapshot({
|
|
49997
50229
|
walletAddress,
|
|
@@ -51022,7 +51254,8 @@ var INFERENCE_HOST_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
|
51022
51254
|
"--effort",
|
|
51023
51255
|
"--wait-seconds",
|
|
51024
51256
|
"--lines",
|
|
51025
|
-
"--service-manifest"
|
|
51257
|
+
"--service-manifest",
|
|
51258
|
+
"--instance"
|
|
51026
51259
|
]);
|
|
51027
51260
|
var isInferenceHostCliInvocation = (argv2) => {
|
|
51028
51261
|
for (let index = 0; index < argv2.length; index += 1) {
|