@vtxmacro/cli 2026.8.24 → 2026.8.26

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.
Files changed (3) hide show
  1. package/README.md +7 -6
  2. package/bin/vtx.js +79 -44
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -51,12 +51,13 @@ credential.
51
51
 
52
52
  Before the first Codex login, enable **Device code authorization for Codex** in
53
53
  ChatGPT Security settings. Only enter a device code from a login you initiated,
54
- and never share it. The automated host advertises `gpt-5.6-sol` with
55
- `medium`, `high`, and `xhigh` reasoning effort. Before starting a Trader,
56
- confirm that the VTX AI page shows the intended authenticated ChatGPT email and
57
- plan. The host reads the live Codex account window: a reached limit pauses new
58
- dispatch until its reported reset, while a transient throttle uses a short
59
- bounded cooldown.
54
+ and never share it. The automated host reads the authenticated Codex model
55
+ picker and advertises every visible model with that model's exact display name,
56
+ default effort, and supported reasoning efforts. Hidden Codex entries are not
57
+ exposed. Before starting a Trader, confirm that the VTX AI page shows the
58
+ intended authenticated ChatGPT email and plan. The host reads the live Codex
59
+ account window: a reached limit pauses new dispatch until its reported reset,
60
+ while a transient throttle uses a short bounded cooldown.
60
61
 
61
62
  ```bash
62
63
  vtx inference-host login
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.24",
41
+ package_version: "2026.8.26",
42
42
  codex_package_name: "@openai/codex",
43
43
  codex_version: "0.147.0",
44
44
  platforms: {
@@ -19074,10 +19074,20 @@ async function preflightCodexSubscription(options) {
19074
19074
  });
19075
19075
  }
19076
19076
  const rateLimits = await session.readAccountRateLimits(options.deadlineAtMs, options.signal);
19077
+ const modelCapabilities = await session.readModelCapabilities(options.deadlineAtMs, options.signal);
19078
+ if (modelCapabilities.length === 0) {
19079
+ throw new CodexAppServerError({
19080
+ message: "Codex did not return any visible models with supported reasoning efforts.",
19081
+ category: "model",
19082
+ code: "model_catalog_empty",
19083
+ retryable: false
19084
+ });
19085
+ }
19077
19086
  return {
19078
19087
  authenticated_account_email: account.authenticatedChatGptAccount.email,
19079
19088
  authenticated_account_plan: account.authenticatedChatGptAccount.planType,
19080
- rate_limits: rateLimits
19089
+ rate_limits: rateLimits,
19090
+ model_capabilities: modelCapabilities
19081
19091
  };
19082
19092
  } finally {
19083
19093
  await session.close();
@@ -20144,7 +20154,7 @@ child.once('close', async () => {
20144
20154
  });
20145
20155
  }
20146
20156
  const result2 = await this.request("model/list", {
20147
- includeHidden: true,
20157
+ includeHidden: false,
20148
20158
  ...cursor ? { cursor } : {}
20149
20159
  }, {
20150
20160
  timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
@@ -20154,17 +20164,24 @@ child.once('close', async () => {
20154
20164
  for (const raw of data) {
20155
20165
  const candidate = objectOrNull(raw);
20156
20166
  if (!candidate) continue;
20157
- const id2 = typeof candidate.id === "string" && candidate.id.trim() ? candidate.id.trim() : null;
20158
- const model = typeof candidate.model === "string" && candidate.model.trim() ? candidate.model.trim() : null;
20159
- if (!id2 && !model) continue;
20167
+ const id2 = typeof candidate.id === "string" ? candidate.id.trim() : "";
20168
+ const model = typeof candidate.model === "string" ? candidate.model.trim() : "";
20169
+ const displayName = typeof candidate.displayName === "string" ? candidate.displayName.trim() : "";
20170
+ const hidden = candidate.hidden === true;
20160
20171
  const supportedReasoningEfforts = Array.isArray(candidate.supportedReasoningEfforts) ? candidate.supportedReasoningEfforts.flatMap((item) => {
20161
20172
  const reasoningEffort = objectOrNull(item)?.reasoningEffort;
20162
20173
  return typeof reasoningEffort === "string" && reasoningEffort.trim() ? [reasoningEffort.trim()] : [];
20163
20174
  }) : [];
20175
+ const defaultReasoningEffort = typeof candidate.defaultReasoningEffort === "string" ? candidate.defaultReasoningEffort.trim() : "";
20176
+ if (!id2 || !model || !displayName || hidden || supportedReasoningEfforts.length === 0 || new Set(supportedReasoningEfforts).size !== supportedReasoningEfforts.length || !supportedReasoningEfforts.includes(defaultReasoningEffort)) continue;
20164
20177
  capabilities.push(Object.freeze({
20165
20178
  id: id2,
20166
20179
  model,
20167
- supportedReasoningEfforts: Object.freeze(supportedReasoningEfforts)
20180
+ displayName,
20181
+ hidden,
20182
+ supportedReasoningEfforts: Object.freeze(supportedReasoningEfforts),
20183
+ defaultReasoningEffort,
20184
+ isDefault: candidate.isDefault === true
20168
20185
  }));
20169
20186
  }
20170
20187
  cursor = typeof result2.nextCursor === "string" && result2.nextCursor ? result2.nextCursor : null;
@@ -20952,7 +20969,7 @@ import {
20952
20969
  import { randomBytes as randomBytes3 } from "node:crypto";
20953
20970
  import { tmpdir as tmpdir2 } from "node:os";
20954
20971
  import { isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
20955
- var INITIAL_CODEX_INFERENCE_MODEL, SUPPORTED_CODEX_REASONING_EFFORTS, MAX_PROMPT_BYTES2, tokenUsageReceiptSchema, turnResultReceiptSchema, terminalReceiptSchema, recoveryCheckpointSchema, recoveryFileSchema, FileCodexAttemptRecoveryStore, utf8Bytes, assertAttemptActive, tomlString, permissionConfig, ensureDedicatedCodexHome, createIsolatedCodexAttemptResources, createIsolatedCodexHostResources, validateAttemptInput, isStrictDescendant, assertRecoveryResourceScope, removeRecoveredThread, confirmGuardianTerminatedForRecovery, reconcileCodexAttemptRecovery, CodexSubscriptionAdapter;
20972
+ 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;
20956
20973
  var init_codex_adapter = __esm({
20957
20974
  "lib/inference-host/codex-adapter.ts"() {
20958
20975
  "use strict";
@@ -20960,9 +20977,9 @@ var init_codex_adapter = __esm({
20960
20977
  init_codex_app_server();
20961
20978
  init_codex_binary();
20962
20979
  init_config();
20963
- INITIAL_CODEX_INFERENCE_MODEL = "gpt-5.6-sol";
20964
- SUPPORTED_CODEX_REASONING_EFFORTS = ["medium", "high", "xhigh"];
20965
20980
  MAX_PROMPT_BYTES2 = 3e5;
20981
+ CODEX_MODEL_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$/u;
20982
+ CODEX_REASONING_EFFORT_PATTERN = /^[a-z][a-z0-9_-]{0,31}$/u;
20966
20983
  tokenUsageReceiptSchema = external_exports.strictObject({
20967
20984
  inputTokens: external_exports.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
20968
20985
  cachedInputTokens: external_exports.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
@@ -20974,10 +20991,10 @@ var init_codex_adapter = __esm({
20974
20991
  });
20975
20992
  turnResultReceiptSchema = external_exports.strictObject({
20976
20993
  text: external_exports.string().min(1).max(MAX_PROMPT_BYTES2),
20977
- requestedModel: external_exports.literal(INITIAL_CODEX_INFERENCE_MODEL),
20978
- effectiveModel: external_exports.literal(INITIAL_CODEX_INFERENCE_MODEL),
20979
- requestedReasoningEffort: external_exports.enum(SUPPORTED_CODEX_REASONING_EFFORTS),
20980
- effectiveReasoningEffort: external_exports.enum(SUPPORTED_CODEX_REASONING_EFFORTS),
20994
+ requestedModel: external_exports.string().regex(CODEX_MODEL_NAME_PATTERN),
20995
+ effectiveModel: external_exports.string().regex(CODEX_MODEL_NAME_PATTERN),
20996
+ requestedReasoningEffort: external_exports.string().regex(CODEX_REASONING_EFFORT_PATTERN),
20997
+ effectiveReasoningEffort: external_exports.string().regex(CODEX_REASONING_EFFORT_PATTERN),
20981
20998
  adapterRequestId: external_exports.string().min(1).max(512),
20982
20999
  adapterResponseId: external_exports.string().min(1).max(512),
20983
21000
  usage: tokenUsageReceiptSchema,
@@ -20985,7 +21002,7 @@ var init_codex_adapter = __esm({
20985
21002
  timeToFirstTokenMs: external_exports.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).nullable(),
20986
21003
  terminalStatus: external_exports.literal("completed")
20987
21004
  }).superRefine((value, context) => {
20988
- if (value.usage.cachedInputTokens > value.usage.inputTokens || value.usage.reasoningOutputTokens > value.usage.outputTokens || value.usage.totalTokens !== value.usage.inputTokens + value.usage.outputTokens || value.effectiveReasoningEffort !== value.requestedReasoningEffort) {
21005
+ if (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) {
20989
21006
  context.addIssue({ code: "custom", message: "Invalid Codex recovery usage or identity." });
20990
21007
  }
20991
21008
  });
@@ -21208,9 +21225,9 @@ var init_codex_adapter = __esm({
21208
21225
  retryable: false
21209
21226
  });
21210
21227
  }
21211
- if (input.requestedModel !== INITIAL_CODEX_INFERENCE_MODEL || !SUPPORTED_CODEX_REASONING_EFFORTS.includes(input.requestedReasoningEffort)) {
21228
+ if (!CODEX_MODEL_NAME_PATTERN.test(input.requestedModel) || !CODEX_REASONING_EFFORT_PATTERN.test(input.requestedReasoningEffort)) {
21212
21229
  throw new CodexAppServerError({
21213
- message: "Codex model selection is not admitted by the pinned adapter.",
21230
+ message: "Codex model selection is not a valid catalog identity.",
21214
21231
  category: "model",
21215
21232
  code: "model_selection_not_admitted",
21216
21233
  retryable: false
@@ -28637,7 +28654,7 @@ function createDefaultInferenceHostRunnerDependencies(options) {
28637
28654
  envelopePublicKey: options.envelopePublicKey
28638
28655
  };
28639
28656
  }
28640
- var import_ajv, RUNTIME_RECEIPT_SCHEMA_VERSION, ATTEMPT_RECEIPT_SCHEMA_VERSION, DEFAULT_ADVERTISEMENT_TTL_MS, DEFAULT_ADVERTISEMENT_REFRESH_LEAD_MS, DEFAULT_HOST_HEARTBEAT_MS, DEFAULT_ATTEMPT_HEARTBEAT_MS, DEFAULT_DRAIN_TIMEOUT_MS, DEFAULT_REMOTE_RETRY_LIMIT, DEFAULT_MAX_CONCURRENCY, MIN_SLEEP_MS, DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS, MIN_CLAIM_START_WINDOW_MS, CODEX_INFERENCE_ADVERTISED_MODEL, FileInferenceHostRuntimeReceiptStore, InferenceHostRecoveryRequiredError, InferenceHostRunnerError, defaultSleep, abortError, defaultRegisterSignalHandlers, safeInteger, exactObjectKeys, validIso, validateAttemptReceipt, validateRuntimeReceipt, sha256, stableOperationId, buildAttemptStartRequest, isoAt, finitePositiveOption, validateRunnerOptions, assertLocalCredentialIdentity, retryableRemoteError, remoteRetryAfterMs, controlPlaneFatal, defaultValidateOutput, objectRecord, positiveUtf8ByteLimit, assertCompilableOutputSchema, parseOutputContract, safeFailureCode, exactJson2, runnerIdentityMismatch, assertAdvertisementResult, assertHostHeartbeatResult, assertClaimResult, assertStartResult, assertJobHeartbeatResult, assertTerminalResult, classifyFailure, ambiguousHeartbeatTransport, reportedTokenUsage, reportedUsage, InferenceHostRunner;
28657
+ var import_ajv, RUNTIME_RECEIPT_SCHEMA_VERSION, ATTEMPT_RECEIPT_SCHEMA_VERSION, DEFAULT_ADVERTISEMENT_TTL_MS, DEFAULT_ADVERTISEMENT_REFRESH_LEAD_MS, DEFAULT_HOST_HEARTBEAT_MS, DEFAULT_ATTEMPT_HEARTBEAT_MS, DEFAULT_DRAIN_TIMEOUT_MS, DEFAULT_REMOTE_RETRY_LIMIT, DEFAULT_MAX_CONCURRENCY, MIN_SLEEP_MS, DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS, MIN_CLAIM_START_WINDOW_MS, buildCodexInferenceAdvertisedModels, FileInferenceHostRuntimeReceiptStore, InferenceHostRecoveryRequiredError, InferenceHostRunnerError, defaultSleep, abortError, defaultRegisterSignalHandlers, safeInteger, exactObjectKeys, validIso, validateAttemptReceipt, validateRuntimeReceipt, sha256, stableOperationId, buildAttemptStartRequest, isoAt, finitePositiveOption, validateRunnerOptions, assertLocalCredentialIdentity, retryableRemoteError, remoteRetryAfterMs, controlPlaneFatal, defaultValidateOutput, objectRecord, positiveUtf8ByteLimit, assertCompilableOutputSchema, parseOutputContract, safeFailureCode, exactJson2, runnerIdentityMismatch, assertAdvertisementResult, assertHostHeartbeatResult, assertClaimResult, assertStartResult, assertJobHeartbeatResult, assertTerminalResult, classifyFailure, ambiguousHeartbeatTransport, reportedTokenUsage, reportedUsage, InferenceHostRunner;
28641
28658
  var init_runner = __esm({
28642
28659
  "lib/inference-host/runner.ts"() {
28643
28660
  "use strict";
@@ -28645,7 +28662,6 @@ var init_runner = __esm({
28645
28662
  init_external_inference_contract();
28646
28663
  init_config();
28647
28664
  init_credential_store();
28648
- init_codex_adapter();
28649
28665
  init_codex_app_server();
28650
28666
  init_crypto();
28651
28667
  init_mcp_client();
@@ -28662,21 +28678,38 @@ var init_runner = __esm({
28662
28678
  MIN_SLEEP_MS = 10;
28663
28679
  DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS = 5 * 60 * 1e3;
28664
28680
  MIN_CLAIM_START_WINDOW_MS = 5e3;
28665
- CODEX_INFERENCE_ADVERTISED_MODEL = Object.freeze({
28666
- model_id: INITIAL_CODEX_INFERENCE_MODEL,
28667
- label: "Codex GPT-5.6 Sol",
28668
- adapter: "codex",
28669
- supported_lanes: ["main", "review", "screener"],
28670
- supported_reasoning_efforts: [...SUPPORTED_CODEX_REASONING_EFFORTS],
28671
- default_reasoning_effort: "medium",
28672
- supported_response_modes: ["provider_response", "decision_candidate"],
28673
- allowed_model_identities: [{
28674
- requested_model: INITIAL_CODEX_INFERENCE_MODEL,
28675
- effective_models: [INITIAL_CODEX_INFERENCE_MODEL]
28676
- }],
28677
- structured_output: true,
28678
- same_attempt_recovery: true
28679
- });
28681
+ buildCodexInferenceAdvertisedModels = (capabilities, adapterRuntimeVersion) => {
28682
+ const visible = capabilities.filter((capability) => !capability.hidden);
28683
+ if (visible.length === 0 || visible.length > 64) {
28684
+ throw new InferenceHostRunnerError(
28685
+ "invalid_configuration",
28686
+ visible.length === 0 ? "Codex did not return any visible models that VTX can advertise." : "Codex returned more models than the VTX advertisement contract can represent."
28687
+ );
28688
+ }
28689
+ const models = visible.map((capability) => ({
28690
+ model_id: capability.model,
28691
+ label: capability.displayName,
28692
+ adapter: "codex",
28693
+ supported_lanes: ["main", "review", "screener"],
28694
+ supported_reasoning_efforts: [...capability.supportedReasoningEfforts],
28695
+ default_reasoning_effort: capability.defaultReasoningEffort,
28696
+ supported_response_modes: ["provider_response", "decision_candidate"],
28697
+ allowed_model_identities: [{
28698
+ requested_model: capability.model,
28699
+ effective_models: [capability.model]
28700
+ }],
28701
+ structured_output: true,
28702
+ same_attempt_recovery: true,
28703
+ adapter_runtime_version: adapterRuntimeVersion
28704
+ }));
28705
+ if (new Set(models.map((model) => model.model_id)).size !== models.length) {
28706
+ throw new InferenceHostRunnerError(
28707
+ "invalid_configuration",
28708
+ "Codex returned duplicate runtime model identities."
28709
+ );
28710
+ }
28711
+ return models;
28712
+ };
28680
28713
  FileInferenceHostRuntimeReceiptStore = class {
28681
28714
  constructor(path) {
28682
28715
  this.path = path;
@@ -28919,6 +28952,10 @@ var init_runner = __esm({
28919
28952
  );
28920
28953
  }
28921
28954
  return {
28955
+ advertisedModels: buildCodexInferenceAdvertisedModels(
28956
+ options.codexModelCapabilities,
28957
+ options.adapterRuntimeVersion
28958
+ ),
28922
28959
  maxConcurrency: finitePositiveOption(
28923
28960
  options.maxConcurrency,
28924
28961
  DEFAULT_MAX_CONCURRENCY,
@@ -29390,12 +29427,7 @@ var init_runner = __esm({
29390
29427
  health,
29391
29428
  advertised_at: isoAt(advertisedAt),
29392
29429
  expires_at: isoAt(advertisedAt + settings.advertisementTtlMs),
29393
- models: [{
29394
- ...CODEX_INFERENCE_ADVERTISED_MODEL,
29395
- supported_lanes: [...CODEX_INFERENCE_ADVERTISED_MODEL.supported_lanes],
29396
- supported_response_modes: [...CODEX_INFERENCE_ADVERTISED_MODEL.supported_response_modes],
29397
- adapter_runtime_version: this.options.adapterRuntimeVersion
29398
- }]
29430
+ models: settings.advertisedModels
29399
29431
  });
29400
29432
  receipt = {
29401
29433
  ...receipt,
@@ -29976,7 +30008,7 @@ var init_runner = __esm({
29976
30008
  systemPrompt: jobInput.system_prompt,
29977
30009
  userPrompt: jobInput.user_prompt,
29978
30010
  outputSchemaJson: outputContract.adapterSchemaJson,
29979
- requestedModel: INITIAL_CODEX_INFERENCE_MODEL,
30011
+ requestedModel: jobInput.requested_model,
29980
30012
  requestedReasoningEffort: jobInput.requested_reasoning_effort,
29981
30013
  deadlineAtMs: Date.parse(jobInput.deadline_at),
29982
30014
  signal: attemptAbort.signal
@@ -30203,9 +30235,10 @@ var init_runner = __esm({
30203
30235
  }
30204
30236
  }
30205
30237
  validateImmutableSelection(jobInput) {
30206
- if (jobInput.requested_model !== INITIAL_CODEX_INFERENCE_MODEL || !SUPPORTED_CODEX_REASONING_EFFORTS.includes(
30207
- jobInput.requested_reasoning_effort
30208
- ) || jobInput.controller.model_id !== INITIAL_CODEX_INFERENCE_MODEL || jobInput.controller.reasoning_effort !== jobInput.requested_reasoning_effort) {
30238
+ const advertisedModel = this.options.codexModelCapabilities.find(
30239
+ (candidate) => !candidate.hidden && candidate.model === jobInput.requested_model
30240
+ );
30241
+ if (!advertisedModel || !advertisedModel.supportedReasoningEfforts.includes(jobInput.requested_reasoning_effort) || jobInput.controller.model_id !== jobInput.requested_model || jobInput.controller.reasoning_effort !== jobInput.requested_reasoning_effort) {
30209
30242
  throw new InferenceHostRunnerError(
30210
30243
  "unsupported_model_selection",
30211
30244
  "The claimed model or reasoning effort was not advertised by this host."
@@ -31361,6 +31394,7 @@ Durable service:
31361
31394
  authenticatedAccountEmail: options.authenticatedAccountEmail,
31362
31395
  authenticatedAccountPlan: options.authenticatedAccountPlan,
31363
31396
  codexRateLimits: options.codexRateLimits,
31397
+ codexModelCapabilities: options.codexModelCapabilities,
31364
31398
  protocolVersion: EXTERNAL_INFERENCE_CONTRACT_VERSION,
31365
31399
  adapterRuntimeVersion: INFERENCE_HOST_CLI_VERSION,
31366
31400
  maxConcurrency: options.maxConcurrency,
@@ -31861,6 +31895,7 @@ Waiting for approval...
31861
31895
  authenticatedAccountEmail: preflight?.authenticated_account_email ?? null,
31862
31896
  authenticatedAccountPlan: preflight?.authenticated_account_plan ?? null,
31863
31897
  codexRateLimits: preflight?.rate_limits ?? null,
31898
+ codexModelCapabilities: preflight?.model_capabilities ?? [],
31864
31899
  maxConcurrency: parsed.maxConcurrency,
31865
31900
  once: parsed.once,
31866
31901
  env,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtxmacro/cli",
3
- "version": "2026.8.24",
3
+ "version": "2026.8.26",
4
4
  "description": "VTX Macro CLI, MCP server, and durable subscription inference host.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",