@vtxmacro/cli 2026.8.43 → 2026.8.45
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/bin/vtx.js +536 -104
- package/package.json +1 -1
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.45",
|
|
42
42
|
codex_package_name: "@openai/codex",
|
|
43
43
|
codex_version: "0.147.0",
|
|
44
44
|
copilot_sdk_package_name: "@github/copilot-sdk",
|
|
@@ -14379,7 +14379,7 @@ var init_zod = __esm({
|
|
|
14379
14379
|
});
|
|
14380
14380
|
|
|
14381
14381
|
// lib/external-inference-contract.ts
|
|
14382
|
-
var EXTERNAL_INFERENCE_CONTRACT_VERSION, EXTERNAL_INFERENCE_CONTROLLER_SCHEMA_VERSION, EXTERNAL_INFERENCE_ADVERTISEMENT_SCHEMA_VERSION, EXTERNAL_INFERENCE_ENVELOPE_SCHEMA_VERSION, EXTERNAL_INFERENCE_JOB_INPUT_SCHEMA_VERSION, LEGACY_EXTERNAL_INFERENCE_JOB_INPUT_SCHEMA_VERSION, EXTERNAL_INFERENCE_USAGE_SCHEMA_VERSION, EXTERNAL_INFERENCE_INPUT_HASH_DOMAIN, MAX_EXTERNAL_INFERENCE_STATUS_HOSTS, MAX_GENERATION, MAX_SAFE_INTEGER, MAX_PROMPT_BYTES, MAX_IMMUTABLE_JOB_INPUT_BYTES, MAX_CANDIDATE_PLAINTEXT_BYTES, MAX_CIPHERTEXT_CHARS, SHA256_INITIAL_STATE, SHA256_ROUND_CONSTANTS, rotateRight, sha256BytesHex, sha256Utf8Hex, computeImmutableJobInputSha256, identifierSchema, operationIdentifierSchema, sha256HexSchema, generationSchema, zeroBasedGenerationSchema, nonNegativeSafeIntegerSchema, positiveSafeIntegerSchema, sqlIntegerTokenCountSchema, timestampSchema, safeCodeSchema, externalInferenceAdapterIdSchema, reasoningEffortSchema, modelNameSchema, displayNameSchema, authenticatedAccountEmailSchema, protocolVersionSchema, base64UrlAlphabet, isCanonicalBase64Url, base64Url32BytesSchema, base64UrlNonceSchema, base64UrlCiphertextSchema, claimHandleSchema, boundedJsonTextSchema, boundedPromptTextSchema, laneSchema, botModeSchema, executionModeSchema, responseModeSchema, dispatchOutcomeSchema, responseOutcomeSchema, nativeModelControllerSchema, externalAgentModelControllerSchema, externalAgentUnboundControllerSchema, orderedFallbackHostIdsSchema, externalInferenceFallbackHostIdsSchema, liveModelControllerSchema, snapshotModelControllerSchema, modelIdentityMappingSchema, advertisedModelSchema, hostAdvertisementSchema, envelopeAadSchema, validateEnvelopeAad, commonEnvelopeShape, sealedKeyWrapEnvelopeSchema, sealedInputEnvelopeSchema, sealedCandidateEnvelopeSchema, sealedEnvelopeSchema, screenerCandidateRuntimeBindingSchema, screenerClientLeaseBindingSchema, screenerRuntimeBindingSchema, serverRuntimeBindingSchema, clientRuntimeBindingSchema, runtimeBindingSchema, immutableJobInputSchema, canonicalizeJsonValue, serializeImmutableJobInput, reportedTokenUsageSchema, unavailableTokenUsageSchema, tokenUsageSchema, agentConnectRequestSchema, agentNextRequestSchema, agentHeartbeatRequestSchema, emptyAgentNextResultSchema, claimedAgentNextResultSchema, agentNextResultSchema, agentCompleteRequestSchema, agentFailRequestSchema, requestedModelSelectionSchema, completedModelProvenanceSchema, attemptModelProvenanceSchema, providerWeeklyQuotaReadSchema, hostHeartbeatRequestSchema, jobClaimRequestSchema, emptyJobClaimSchema, claimedJobSchema, jobClaimResultSchema, attemptStartRequestSchema, jobHeartbeatRequestSchema, continueHeartbeatDirectiveSchema, cancelHeartbeatDirectiveSchema, jobHeartbeatResultSchema, adapterOutcomeEvidenceSchema, completionBaseShape, validateCompletion, providerResponseCompletionSchema, decisionCandidateCompletionSchema, jobCompleteRequestSchema, jobFailRequestSchema, jobCancelRequestSchema, jobCancellationReceiptSchema, jobDeliveryRequestSchema, deliveryBaseShape, validateDeliveryCandidate, providerResponseDeliverySchema, decisionCandidateDeliverySchema, jobDeliveryResultSchema, jobConsumptionRequestSchema, jobConsumptionReceiptSchema, jobStateSchema, jobStatusReadSchema, hostStatusReadSchema, controllerBindingStatusReadSchema, queueStatusReadSchema, outcomeStatusReadSchema, externalInferenceVolumeWindowReadSchema, externalInferenceFailureCountReadSchema, externalInferenceHostDiagnosticsReadSchema, externalInferenceProfileActivityReadSchema, externalInferenceStatusReadSchema, nativeResearchEvidenceSourceSchema, externalAgentResearchEvidenceSourceSchema, researchEvidenceSourceSchema, reportedResearchTokenUsageSchema, unavailableResearchTokenUsageSchema, researchTokenUsageSchema, externalInferenceProductLineageBaseShape, traderExternalInferenceProductLineageSchema, decisionChatExternalInferenceProductLineageSchema, screenerExternalInferenceProductLineageSchema, externalInferenceProductLineageSchema, normalProductLinkageSchema, evidenceMaterializationMarkerSchema, deliveredExternalAgentSourceIdentitySchema, deliveredRequestEvidenceSchema, researchEvidenceBaseShape, researchEvidenceBaseSchema, validateExactUtf8, validateResearchEvidence, providerResponseResearchEvidenceSchema, decisionCandidateResearchEvidenceSchema, researchEvidenceSchema;
|
|
14382
|
+
var EXTERNAL_INFERENCE_CONTRACT_VERSION, EXTERNAL_INFERENCE_CONTROLLER_SCHEMA_VERSION, EXTERNAL_INFERENCE_ADVERTISEMENT_SCHEMA_VERSION, EXTERNAL_INFERENCE_ENVELOPE_SCHEMA_VERSION, EXTERNAL_INFERENCE_JOB_INPUT_SCHEMA_VERSION, LEGACY_EXTERNAL_INFERENCE_JOB_INPUT_SCHEMA_VERSION, EXTERNAL_INFERENCE_USAGE_SCHEMA_VERSION, EXTERNAL_INFERENCE_INPUT_HASH_DOMAIN, MAX_EXTERNAL_INFERENCE_STATUS_HOSTS, MAX_GENERATION, MAX_SAFE_INTEGER, MAX_PROMPT_BYTES, MAX_IMMUTABLE_JOB_INPUT_BYTES, MAX_CANDIDATE_PLAINTEXT_BYTES, MAX_CIPHERTEXT_CHARS, SHA256_INITIAL_STATE, SHA256_ROUND_CONSTANTS, rotateRight, sha256BytesHex, sha256Utf8Hex, computeImmutableJobInputSha256, identifierSchema, operationIdentifierSchema, sha256HexSchema, generationSchema, zeroBasedGenerationSchema, nonNegativeSafeIntegerSchema, positiveSafeIntegerSchema, sqlIntegerTokenCountSchema, timestampSchema, safeCodeSchema, processExitCodeSchema, externalInferenceAdapterIdSchema, reasoningEffortSchema, modelNameSchema, displayNameSchema, authenticatedAccountEmailSchema, protocolVersionSchema, base64UrlAlphabet, isCanonicalBase64Url, base64Url32BytesSchema, base64UrlNonceSchema, base64UrlCiphertextSchema, claimHandleSchema, boundedJsonTextSchema, boundedPromptTextSchema, laneSchema, botModeSchema, executionModeSchema, responseModeSchema, dispatchOutcomeSchema, responseOutcomeSchema, nativeModelControllerSchema, externalAgentModelControllerSchema, externalAgentUnboundControllerSchema, orderedFallbackHostIdsSchema, externalInferenceFallbackHostIdsSchema, liveModelControllerSchema, snapshotModelControllerSchema, modelIdentityMappingSchema, advertisedModelSchema, hostAdvertisementSchema, envelopeAadSchema, validateEnvelopeAad, commonEnvelopeShape, sealedKeyWrapEnvelopeSchema, sealedInputEnvelopeSchema, sealedCandidateEnvelopeSchema, sealedEnvelopeSchema, screenerCandidateRuntimeBindingSchema, screenerClientLeaseBindingSchema, screenerRuntimeBindingSchema, serverRuntimeBindingSchema, clientRuntimeBindingSchema, runtimeBindingSchema, immutableJobInputSchema, canonicalizeJsonValue, serializeImmutableJobInput, reportedTokenUsageSchema, unavailableTokenUsageSchema, tokenUsageSchema, agentConnectRequestSchema, agentNextRequestSchema, agentHeartbeatRequestSchema, emptyAgentNextResultSchema, claimedAgentNextResultSchema, agentNextResultSchema, agentCompleteRequestSchema, agentFailRequestSchema, requestedModelSelectionSchema, completedModelProvenanceSchema, attemptModelProvenanceSchema, providerWeeklyQuotaReadSchema, hostHeartbeatRequestSchema, jobClaimRequestSchema, emptyJobClaimSchema, claimedJobSchema, jobClaimResultSchema, attemptStartRequestSchema, jobHeartbeatRequestSchema, continueHeartbeatDirectiveSchema, cancelHeartbeatDirectiveSchema, jobHeartbeatResultSchema, adapterOutcomeEvidenceSchema, completionBaseShape, validateCompletion, providerResponseCompletionSchema, decisionCandidateCompletionSchema, jobCompleteRequestSchema, codexProcessExitDiagnosticsSchema, jobFailRequestSchema, jobCancelRequestSchema, jobCancellationReceiptSchema, jobDeliveryRequestSchema, deliveryBaseShape, validateDeliveryCandidate, providerResponseDeliverySchema, decisionCandidateDeliverySchema, jobDeliveryResultSchema, jobConsumptionRequestSchema, jobConsumptionReceiptSchema, jobStateSchema, jobStatusReadSchema, hostStatusReadSchema, controllerBindingStatusReadSchema, queueStatusReadSchema, outcomeStatusReadSchema, externalInferenceVolumeWindowReadSchema, externalInferenceFailureCountReadSchema, externalInferenceHostDiagnosticsReadSchema, externalInferenceProfileActivityReadSchema, externalInferenceStatusReadSchema, nativeResearchEvidenceSourceSchema, externalAgentResearchEvidenceSourceSchema, researchEvidenceSourceSchema, reportedResearchTokenUsageSchema, unavailableResearchTokenUsageSchema, researchTokenUsageSchema, externalInferenceProductLineageBaseShape, traderExternalInferenceProductLineageSchema, decisionChatExternalInferenceProductLineageSchema, screenerExternalInferenceProductLineageSchema, externalInferenceProductLineageSchema, normalProductLinkageSchema, evidenceMaterializationMarkerSchema, deliveredExternalAgentSourceIdentitySchema, deliveredRequestEvidenceSchema, researchEvidenceBaseShape, researchEvidenceBaseSchema, validateExactUtf8, validateResearchEvidence, providerResponseResearchEvidenceSchema, decisionCandidateResearchEvidenceSchema, researchEvidenceSchema;
|
|
14383
14383
|
var init_external_inference_contract = __esm({
|
|
14384
14384
|
"lib/external-inference-contract.ts"() {
|
|
14385
14385
|
"use strict";
|
|
@@ -14582,6 +14582,7 @@ var init_external_inference_contract = __esm({
|
|
|
14582
14582
|
sqlIntegerTokenCountSchema = external_exports.number().int().min(0).max(2147483647);
|
|
14583
14583
|
timestampSchema = external_exports.iso.datetime({ offset: true });
|
|
14584
14584
|
safeCodeSchema = external_exports.string().min(1).max(96).regex(/^[a-z0-9][a-z0-9._-]{0,95}$/);
|
|
14585
|
+
processExitCodeSchema = external_exports.number().int().min(-(2 ** 31)).max(2 ** 31 - 1);
|
|
14585
14586
|
externalInferenceAdapterIdSchema = external_exports.string().min(1).max(64).regex(/^[a-z0-9][a-z0-9._-]{0,63}$/);
|
|
14586
14587
|
reasoningEffortSchema = external_exports.string().min(1).max(32).regex(/^[a-z][a-z0-9_-]{0,31}$/);
|
|
14587
14588
|
modelNameSchema = external_exports.string().min(1).max(256);
|
|
@@ -15435,6 +15436,55 @@ var init_external_inference_contract = __esm({
|
|
|
15435
15436
|
providerResponseCompletionSchema,
|
|
15436
15437
|
decisionCandidateCompletionSchema
|
|
15437
15438
|
]);
|
|
15439
|
+
codexProcessExitDiagnosticsSchema = external_exports.strictObject({
|
|
15440
|
+
schema_version: external_exports.literal("external_inference_process_exit_v1"),
|
|
15441
|
+
runtime: external_exports.literal("codex_app_server"),
|
|
15442
|
+
source: external_exports.enum(["child_receipt", "direct_process", "guardian_process"]),
|
|
15443
|
+
session_generation: generationSchema,
|
|
15444
|
+
expected_shutdown: external_exports.boolean(),
|
|
15445
|
+
exit_class: external_exports.enum(["zero", "nonzero", "signal", "unknown"]),
|
|
15446
|
+
exit_code: processExitCodeSchema.nullable(),
|
|
15447
|
+
signal: safeCodeSchema.nullable(),
|
|
15448
|
+
uptime_ms: nonNegativeSafeIntegerSchema,
|
|
15449
|
+
pending_request_count: nonNegativeSafeIntegerSchema.nullable(),
|
|
15450
|
+
active_thread_count: nonNegativeSafeIntegerSchema.nullable(),
|
|
15451
|
+
stderr_nonempty: external_exports.boolean().nullable(),
|
|
15452
|
+
stderr_bytes_observed: external_exports.number().int().min(0).max(65536).nullable(),
|
|
15453
|
+
stderr_truncated: external_exports.boolean().nullable(),
|
|
15454
|
+
stderr_class: external_exports.enum([
|
|
15455
|
+
"unknown",
|
|
15456
|
+
"none",
|
|
15457
|
+
"out_of_memory",
|
|
15458
|
+
"runtime_fatal",
|
|
15459
|
+
"memory_fault",
|
|
15460
|
+
"pipe_or_connection",
|
|
15461
|
+
"unclassified"
|
|
15462
|
+
])
|
|
15463
|
+
}).superRefine((value, context) => {
|
|
15464
|
+
const expectedExitClass = value.signal !== null ? "signal" : value.exit_code === null ? "unknown" : value.exit_code === 0 ? "zero" : "nonzero";
|
|
15465
|
+
if (value.exit_class !== expectedExitClass) {
|
|
15466
|
+
context.addIssue({ code: "custom", message: "process exit class does not match code and signal", path: ["exit_class"] });
|
|
15467
|
+
}
|
|
15468
|
+
if (value.signal !== null && value.exit_code !== null) {
|
|
15469
|
+
context.addIssue({ code: "custom", message: "signal exits cannot also report an exit code", path: ["exit_code"] });
|
|
15470
|
+
}
|
|
15471
|
+
if (value.stderr_class === "unknown") {
|
|
15472
|
+
if (value.stderr_nonempty !== null || value.stderr_bytes_observed !== null || value.stderr_truncated !== null) {
|
|
15473
|
+
context.addIssue({ code: "custom", message: "unknown stderr diagnostics must not infer observations", path: ["stderr_class"] });
|
|
15474
|
+
}
|
|
15475
|
+
} else if (value.stderr_nonempty === null || value.stderr_bytes_observed === null || value.stderr_truncated === null) {
|
|
15476
|
+
context.addIssue({ code: "custom", message: "observed stderr diagnostics must be complete", path: ["stderr_class"] });
|
|
15477
|
+
} else if (!value.stderr_nonempty) {
|
|
15478
|
+
if (value.stderr_bytes_observed !== 0 || value.stderr_truncated || value.stderr_class !== "none") {
|
|
15479
|
+
context.addIssue({ code: "custom", message: "empty stderr diagnostics are inconsistent", path: ["stderr_nonempty"] });
|
|
15480
|
+
}
|
|
15481
|
+
} else if (value.stderr_bytes_observed === 0 || value.stderr_class === "none") {
|
|
15482
|
+
context.addIssue({ code: "custom", message: "non-empty stderr diagnostics are inconsistent", path: ["stderr_nonempty"] });
|
|
15483
|
+
}
|
|
15484
|
+
if (value.stderr_truncated && value.stderr_bytes_observed !== 65536) {
|
|
15485
|
+
context.addIssue({ code: "custom", message: "truncated stderr diagnostics must report the observation cap", path: ["stderr_truncated"] });
|
|
15486
|
+
}
|
|
15487
|
+
});
|
|
15438
15488
|
jobFailRequestSchema = external_exports.strictObject({
|
|
15439
15489
|
schema_version: external_exports.literal("external_inference_job_fail_v1"),
|
|
15440
15490
|
contract_version: external_exports.literal(EXTERNAL_INFERENCE_CONTRACT_VERSION),
|
|
@@ -15457,6 +15507,7 @@ var init_external_inference_contract = __esm({
|
|
|
15457
15507
|
failure_category: safeCodeSchema,
|
|
15458
15508
|
failure_code: safeCodeSchema,
|
|
15459
15509
|
retryable: external_exports.boolean(),
|
|
15510
|
+
process_exit: codexProcessExitDiagnosticsSchema.nullable().optional(),
|
|
15460
15511
|
membership_disposition: external_exports.enum([
|
|
15461
15512
|
"retry_same_host",
|
|
15462
15513
|
"cascade_cooldown",
|
|
@@ -15473,6 +15524,13 @@ var init_external_inference_contract = __esm({
|
|
|
15473
15524
|
if (value.attempt_status !== expectedStatus) {
|
|
15474
15525
|
context.addIssue({ code: "custom", message: "attempt_status must match dispatch outcome", path: ["attempt_status"] });
|
|
15475
15526
|
}
|
|
15527
|
+
if (value.process_exit != null && (value.failure_category !== "transport" || value.failure_code !== "codex_process_closed" || value.process_exit.expected_shutdown)) {
|
|
15528
|
+
context.addIssue({
|
|
15529
|
+
code: "custom",
|
|
15530
|
+
message: "process exit diagnostics require an unexpected Codex process-close failure",
|
|
15531
|
+
path: ["process_exit"]
|
|
15532
|
+
});
|
|
15533
|
+
}
|
|
15476
15534
|
if (value.outcome.dispatch_outcome === "outcome_unknown" && value.membership_disposition !== void 0 && value.membership_disposition !== "quarantine_ambiguous") {
|
|
15477
15535
|
context.addIssue({ code: "custom", message: "outcome-unknown failures must be quarantined", path: ["membership_disposition"] });
|
|
15478
15536
|
}
|
|
@@ -16196,7 +16254,7 @@ import { spawn } from "node:child_process";
|
|
|
16196
16254
|
import { constants } from "node:fs";
|
|
16197
16255
|
import { lstat, mkdir, open, readFile, realpath, rename, rm } from "node:fs/promises";
|
|
16198
16256
|
import { homedir } from "node:os";
|
|
16199
|
-
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
16257
|
+
import { dirname, isAbsolute, join, relative, resolve, win32 as windowsPath } from "node:path";
|
|
16200
16258
|
function inferenceBaseDir(env) {
|
|
16201
16259
|
const configured = String(env.VTX_INFERENCE_HOST_HOME || "").trim();
|
|
16202
16260
|
return configured || join(homedir(), ".vtx", "inference-host");
|
|
@@ -16737,7 +16795,7 @@ async function acquireInferenceHostProcessLock(path, dependencies = {}) {
|
|
|
16737
16795
|
}
|
|
16738
16796
|
};
|
|
16739
16797
|
}
|
|
16740
|
-
var INFERENCE_CREDENTIAL_NAMESPACE, MAX_INFERENCE_PRIVATE_FILE_BYTES, WINDOWS_PRIVATE_ACL_BROKER_SCRIPT, windowsPrivateAclBrokerInvocation, WindowsPrivateAclBroker, defaultWindowsPrivateAclBroker, 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, inferenceHostCredentialContextPath, inferenceHostCredentialContextTransitionPath, credentialContextForConfig;
|
|
16798
|
+
var INFERENCE_CREDENTIAL_NAMESPACE, MAX_INFERENCE_PRIVATE_FILE_BYTES, WINDOWS_PRIVATE_ACL_BROKER_SCRIPT, WINDOWS_IDENTITY_COMMAND_TIMEOUT_MS, WINDOWS_PRIVATE_ACL_BROKER_STARTUP_TIMEOUT_MS, SMALL_IDENTITY_COMMAND_TIMEOUT_MS, windowsPowerShellEnvironment, windowsPrivateAclBrokerInvocation, WindowsPrivateAclBroker, defaultWindowsPrivateAclBroker, runWindowsPrivateAcl, windowsAclCache, windowsAclIdentity, aclCacheKey, secureWindowsPrivatePath, invalidateWindowsAclCache, rebindHardenedWindowsAclAfterRename, rebindHardenedWindowsDirectoryAfterOwnedMutation, isDefaultWindowsPrivatePath, secureExistingWindowsPath, linuxProcessIdentity, windowsProcessIdentityInvocation, windowsBootIdentityInvocation, windowsProcessIdentity, darwinProcessIdentity, runSmallIdentityCommand, cachedSystemBootIdentity, readInferenceSystemBootIdentity, defaultProcessIdentity, defaultCurrentProcessIdentity, processLockObservationCache, inferenceProcessIdentitiesMatch, DEFAULT_INFERENCE_HOST_INSTANCE, SAFE_INFERENCE_HOST_INSTANCE, requireNamedInstancePath, credentialStoreIdentity, inferenceHostCredentialContextPath, inferenceHostCredentialContextTransitionPath, credentialContextForConfig;
|
|
16741
16799
|
var init_config = __esm({
|
|
16742
16800
|
"lib/inference-host/config.ts"() {
|
|
16743
16801
|
"use strict";
|
|
@@ -16747,6 +16805,7 @@ var init_config = __esm({
|
|
|
16747
16805
|
$ProgressPreference='SilentlyContinue'
|
|
16748
16806
|
while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
16749
16807
|
$requestId=$null
|
|
16808
|
+
$failureStage='request_validation'
|
|
16750
16809
|
try {
|
|
16751
16810
|
if($line.Length -lt 2 -or $line.Length -gt 65536) { throw 'invalid request size' }
|
|
16752
16811
|
$request=$line | ConvertFrom-Json
|
|
@@ -16761,18 +16820,25 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
16761
16820
|
if($mode -ne 'harden' -and $mode -ne 'verify' -and $mode -ne 'verify-owner') { throw 'invalid ACL mode' }
|
|
16762
16821
|
$path=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String([string]$request.path_b64))
|
|
16763
16822
|
if([string]::IsNullOrWhiteSpace($path) -or $path.Length -gt 32767 -or $path.Contains([char]0)) { throw 'invalid path' }
|
|
16823
|
+
$failureStage='path_lookup'
|
|
16764
16824
|
if(-not (Test-Path -LiteralPath $path)) {
|
|
16765
16825
|
[Console]::Out.WriteLine((@{id=$requestId;status='missing'} | ConvertTo-Json -Compress))
|
|
16766
16826
|
continue
|
|
16767
16827
|
}
|
|
16768
|
-
$
|
|
16828
|
+
$failureStage='principal_resolution'
|
|
16829
|
+
$currentIdentity=[Security.Principal.WindowsIdentity]::GetCurrent()
|
|
16830
|
+
$current=$currentIdentity.User
|
|
16769
16831
|
$system=New-Object Security.Principal.SecurityIdentifier('S-1-5-18')
|
|
16770
16832
|
$admins=New-Object Security.Principal.SecurityIdentifier('S-1-5-32-544')
|
|
16833
|
+
$currentIsAdmin=(New-Object Security.Principal.WindowsPrincipal($currentIdentity)).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
16771
16834
|
$allowed=@($current.Value,$system.Value,$admins.Value)
|
|
16772
16835
|
if($mode -eq 'harden') {
|
|
16836
|
+
$failureStage='acl_read'
|
|
16773
16837
|
$acl=Get-Acl -LiteralPath $path
|
|
16838
|
+
$failureStage='owner_validation'
|
|
16774
16839
|
$existingOwner=(New-Object Security.Principal.NTAccount($acl.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value
|
|
16775
|
-
if($existingOwner -ne $current.Value) { throw 'private ACL owner is invalid' }
|
|
16840
|
+
if($existingOwner -ne $current.Value -and ($existingOwner -ne $admins.Value -or -not $currentIsAdmin)) { throw 'private ACL owner is invalid' }
|
|
16841
|
+
$failureStage='acl_mutation'
|
|
16776
16842
|
$acl.SetAccessRuleProtection($true,$false)
|
|
16777
16843
|
foreach($existingRule in @($acl.Access)) { [void]$acl.RemoveAccessRuleSpecific($existingRule) }
|
|
16778
16844
|
$inherit=if($kind -eq 'directory') {
|
|
@@ -16788,11 +16854,14 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
16788
16854
|
)
|
|
16789
16855
|
[void]$acl.AddAccessRule($rule)
|
|
16790
16856
|
}
|
|
16857
|
+
$failureStage='acl_write'
|
|
16791
16858
|
(Get-Item -LiteralPath $path).SetAccessControl($acl)
|
|
16792
16859
|
}
|
|
16860
|
+
$failureStage='acl_readback'
|
|
16793
16861
|
$actual=Get-Acl -LiteralPath $path
|
|
16862
|
+
$failureStage='acl_verification'
|
|
16794
16863
|
$owner=(New-Object Security.Principal.NTAccount($actual.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value
|
|
16795
|
-
if($owner -ne $current.Value) { throw 'private ACL owner is invalid' }
|
|
16864
|
+
if($owner -ne $current.Value -and ($owner -ne $admins.Value -or -not $currentIsAdmin)) { throw 'private ACL owner is invalid' }
|
|
16796
16865
|
if($mode -ne 'verify-owner') {
|
|
16797
16866
|
if(-not $actual.AreAccessRulesProtected) { throw 'private ACL inheritance is invalid' }
|
|
16798
16867
|
$userFull=$false
|
|
@@ -16807,9 +16876,28 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
16807
16876
|
}
|
|
16808
16877
|
[Console]::Out.WriteLine((@{id=$requestId;status='ok'} | ConvertTo-Json -Compress))
|
|
16809
16878
|
} catch {
|
|
16810
|
-
[Console]::Out.WriteLine((@{id=$requestId;status='error'} | ConvertTo-Json -Compress))
|
|
16879
|
+
[Console]::Out.WriteLine((@{id=$requestId;status='error';error_code=$failureStage} | ConvertTo-Json -Compress))
|
|
16811
16880
|
}
|
|
16812
16881
|
}`;
|
|
16882
|
+
WINDOWS_IDENTITY_COMMAND_TIMEOUT_MS = 15e3;
|
|
16883
|
+
WINDOWS_PRIVATE_ACL_BROKER_STARTUP_TIMEOUT_MS = 45e3;
|
|
16884
|
+
SMALL_IDENTITY_COMMAND_TIMEOUT_MS = 5e3;
|
|
16885
|
+
windowsPowerShellEnvironment = (extra = {}) => {
|
|
16886
|
+
const sanitizedExtra = { ...extra };
|
|
16887
|
+
delete sanitizedExtra.PSModulePath;
|
|
16888
|
+
const windowsRoot = process.env.SystemRoot ?? process.env.WINDIR;
|
|
16889
|
+
return {
|
|
16890
|
+
...sanitizedExtra,
|
|
16891
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
16892
|
+
SystemRoot: process.env.SystemRoot,
|
|
16893
|
+
WINDIR: process.env.WINDIR,
|
|
16894
|
+
ComSpec: process.env.ComSpec,
|
|
16895
|
+
PATHEXT: process.env.PATHEXT,
|
|
16896
|
+
PSModulePath: windowsRoot ? windowsPath.join(windowsRoot, "System32", "WindowsPowerShell", "v1.0", "Modules") : void 0,
|
|
16897
|
+
TEMP: process.env.TEMP,
|
|
16898
|
+
TMP: process.env.TMP
|
|
16899
|
+
};
|
|
16900
|
+
};
|
|
16813
16901
|
windowsPrivateAclBrokerInvocation = () => ({
|
|
16814
16902
|
args: [
|
|
16815
16903
|
"-NoLogo",
|
|
@@ -16818,16 +16906,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
16818
16906
|
"-EncodedCommand",
|
|
16819
16907
|
Buffer.from(WINDOWS_PRIVATE_ACL_BROKER_SCRIPT, "utf16le").toString("base64")
|
|
16820
16908
|
],
|
|
16821
|
-
env:
|
|
16822
|
-
NODE_ENV: process.env.NODE_ENV,
|
|
16823
|
-
SystemRoot: process.env.SystemRoot,
|
|
16824
|
-
WINDIR: process.env.WINDIR,
|
|
16825
|
-
ComSpec: process.env.ComSpec,
|
|
16826
|
-
PATHEXT: process.env.PATHEXT,
|
|
16827
|
-
PSModulePath: process.env.PSModulePath,
|
|
16828
|
-
TEMP: process.env.TEMP,
|
|
16829
|
-
TMP: process.env.TMP
|
|
16830
|
-
}
|
|
16909
|
+
env: windowsPowerShellEnvironment()
|
|
16831
16910
|
});
|
|
16832
16911
|
WindowsPrivateAclBroker = class {
|
|
16833
16912
|
constructor(dependencies = {}) {
|
|
@@ -16846,6 +16925,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
16846
16925
|
await operation;
|
|
16847
16926
|
};
|
|
16848
16927
|
this.requestTimeoutMs = dependencies.requestTimeoutMs ?? 15e3;
|
|
16928
|
+
this.startupRequestTimeoutMs = dependencies.startupRequestTimeoutMs ?? WINDOWS_PRIVATE_ACL_BROKER_STARTUP_TIMEOUT_MS;
|
|
16849
16929
|
this.idleShutdownMs = dependencies.idleShutdownMs ?? 3e4;
|
|
16850
16930
|
this.spawnProcess = dependencies.spawnProcess ?? (() => {
|
|
16851
16931
|
const invocation = windowsPrivateAclBrokerInvocation();
|
|
@@ -16896,7 +16976,19 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
16896
16976
|
let response;
|
|
16897
16977
|
try {
|
|
16898
16978
|
const parsed = JSON.parse(line);
|
|
16899
|
-
|
|
16979
|
+
const status = String(parsed.status);
|
|
16980
|
+
const expectedKeys = status === "error" ? "error_code\0id\0status" : "id\0status";
|
|
16981
|
+
if (Object.keys(parsed).sort().join("\0") !== expectedKeys || parsed.id !== pending.id || !["ok", "missing", "error"].includes(status) || status === "error" && ![
|
|
16982
|
+
"request_validation",
|
|
16983
|
+
"path_lookup",
|
|
16984
|
+
"principal_resolution",
|
|
16985
|
+
"acl_read",
|
|
16986
|
+
"owner_validation",
|
|
16987
|
+
"acl_mutation",
|
|
16988
|
+
"acl_write",
|
|
16989
|
+
"acl_readback",
|
|
16990
|
+
"acl_verification"
|
|
16991
|
+
].includes(String(parsed.error_code))) throw new Error("invalid response");
|
|
16900
16992
|
response = parsed;
|
|
16901
16993
|
} catch {
|
|
16902
16994
|
this.failChild(child, new Error("Windows private ACL broker returned malformed output."));
|
|
@@ -16911,12 +17003,16 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
16911
17003
|
error48.code = "ENOENT";
|
|
16912
17004
|
pending.reject(error48);
|
|
16913
17005
|
} else {
|
|
16914
|
-
pending.reject(new Error(
|
|
17006
|
+
pending.reject(new Error(
|
|
17007
|
+
`Windows private ACL ${pending.mode} failed (${response.error_code}).`
|
|
17008
|
+
));
|
|
16915
17009
|
}
|
|
16916
17010
|
this.scheduleIdleShutdown();
|
|
16917
17011
|
}
|
|
16918
17012
|
ensureChild() {
|
|
16919
|
-
if (this.child && this.child.exitCode === null && !this.child.killed)
|
|
17013
|
+
if (this.child && this.child.exitCode === null && !this.child.killed) {
|
|
17014
|
+
return { child: this.child, startedNow: false };
|
|
17015
|
+
}
|
|
16920
17016
|
const child = this.spawnProcess();
|
|
16921
17017
|
this.child = child;
|
|
16922
17018
|
this.outputBuffer = "";
|
|
@@ -16947,7 +17043,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
16947
17043
|
for (const stream of [child.stdin, child.stdout, child.stderr]) {
|
|
16948
17044
|
stream.unref?.();
|
|
16949
17045
|
}
|
|
16950
|
-
return child;
|
|
17046
|
+
return { child, startedNow: true };
|
|
16951
17047
|
}
|
|
16952
17048
|
async dispatch(path, kind, mode) {
|
|
16953
17049
|
if (this.idleTimer) {
|
|
@@ -16965,11 +17061,12 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
16965
17061
|
if (Buffer.byteLength(request, "utf8") > 65536) {
|
|
16966
17062
|
throw new Error("Windows private ACL broker request exceeds its input limit.");
|
|
16967
17063
|
}
|
|
16968
|
-
const child = this.ensureChild();
|
|
17064
|
+
const { child, startedNow } = this.ensureChild();
|
|
17065
|
+
const timeoutMs = startedNow ? this.startupRequestTimeoutMs : this.requestTimeoutMs;
|
|
16969
17066
|
await new Promise((resolvePromise, reject) => {
|
|
16970
17067
|
const timer = setTimeout(() => {
|
|
16971
17068
|
this.failChild(child, new Error("Windows private ACL broker request timed out."));
|
|
16972
|
-
},
|
|
17069
|
+
}, timeoutMs);
|
|
16973
17070
|
this.pending = { id: id2, mode, resolve: resolvePromise, reject, timer };
|
|
16974
17071
|
child.stdin.write(request, "utf8", (error48) => {
|
|
16975
17072
|
if (error48) {
|
|
@@ -17072,26 +17169,40 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
17072
17169
|
return null;
|
|
17073
17170
|
}
|
|
17074
17171
|
};
|
|
17172
|
+
windowsProcessIdentityInvocation = (pid) => {
|
|
17173
|
+
const script = `$ErrorActionPreference='Stop';$p=[Diagnostics.Process]::GetProcessById([int]$env:VTX_PROCESS_PID);[Console]::Out.Write($p.StartTime.ToUniversalTime().ToFileTimeUtc())`;
|
|
17174
|
+
return {
|
|
17175
|
+
args: [
|
|
17176
|
+
"-NoLogo",
|
|
17177
|
+
"-NoProfile",
|
|
17178
|
+
"-NonInteractive",
|
|
17179
|
+
"-EncodedCommand",
|
|
17180
|
+
Buffer.from(script, "utf16le").toString("base64")
|
|
17181
|
+
],
|
|
17182
|
+
env: windowsPowerShellEnvironment({ VTX_PROCESS_PID: String(pid) }),
|
|
17183
|
+
timeoutMs: WINDOWS_IDENTITY_COMMAND_TIMEOUT_MS
|
|
17184
|
+
};
|
|
17185
|
+
};
|
|
17186
|
+
windowsBootIdentityInvocation = () => {
|
|
17187
|
+
const script = `$ErrorActionPreference='Stop';$s=[System.Management.ManagementObjectSearcher]::new('SELECT LastBootUpTime FROM Win32_OperatingSystem');try{$c=$s.Get();$e=$c.GetEnumerator();if(-not $e.MoveNext()){throw 'boot identity unavailable'};$raw=[string]$e.Current['LastBootUpTime'];$v=[System.Management.ManagementDateTimeConverter]::ToDateTime($raw).ToUniversalTime().ToFileTimeUtc();[Console]::Out.Write($v)}finally{if($c){$c.Dispose()};$s.Dispose()}`;
|
|
17188
|
+
return {
|
|
17189
|
+
args: [
|
|
17190
|
+
"-NoLogo",
|
|
17191
|
+
"-NoProfile",
|
|
17192
|
+
"-NonInteractive",
|
|
17193
|
+
"-EncodedCommand",
|
|
17194
|
+
Buffer.from(script, "utf16le").toString("base64")
|
|
17195
|
+
],
|
|
17196
|
+
env: windowsPowerShellEnvironment(),
|
|
17197
|
+
timeoutMs: WINDOWS_IDENTITY_COMMAND_TIMEOUT_MS
|
|
17198
|
+
};
|
|
17199
|
+
};
|
|
17075
17200
|
windowsProcessIdentity = async (pid) => await new Promise((resolvePromise) => {
|
|
17076
|
-
const
|
|
17077
|
-
const child = spawn("powershell.exe", [
|
|
17078
|
-
"-NoLogo",
|
|
17079
|
-
"-NoProfile",
|
|
17080
|
-
"-NonInteractive",
|
|
17081
|
-
"-EncodedCommand",
|
|
17082
|
-
Buffer.from(script, "utf16le").toString("base64")
|
|
17083
|
-
], {
|
|
17201
|
+
const invocation = windowsProcessIdentityInvocation(pid);
|
|
17202
|
+
const child = spawn("powershell.exe", [...invocation.args], {
|
|
17084
17203
|
windowsHide: true,
|
|
17085
17204
|
stdio: ["ignore", "pipe", "ignore"],
|
|
17086
|
-
env:
|
|
17087
|
-
NODE_ENV: process.env.NODE_ENV,
|
|
17088
|
-
SystemRoot: process.env.SystemRoot,
|
|
17089
|
-
WINDIR: process.env.WINDIR,
|
|
17090
|
-
ComSpec: process.env.ComSpec,
|
|
17091
|
-
PATHEXT: process.env.PATHEXT,
|
|
17092
|
-
PSModulePath: process.env.PSModulePath,
|
|
17093
|
-
VTX_PROCESS_PID: String(pid)
|
|
17094
|
-
}
|
|
17205
|
+
env: invocation.env
|
|
17095
17206
|
});
|
|
17096
17207
|
const output3 = [];
|
|
17097
17208
|
let settled = false;
|
|
@@ -17104,7 +17215,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
17104
17215
|
const timer = setTimeout(() => {
|
|
17105
17216
|
child.kill("SIGKILL");
|
|
17106
17217
|
settle(null);
|
|
17107
|
-
},
|
|
17218
|
+
}, invocation.timeoutMs);
|
|
17108
17219
|
child.stdout.on("data", (chunk) => {
|
|
17109
17220
|
if (output3.reduce((total, item) => total + item.byteLength, 0) + Buffer.byteLength(chunk) > 1024) {
|
|
17110
17221
|
child.kill("SIGKILL");
|
|
@@ -17142,7 +17253,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
17142
17253
|
settle(code === 0 && Number.isFinite(started) ? `darwin:${Math.floor(started / 1e3)}` : null);
|
|
17143
17254
|
});
|
|
17144
17255
|
});
|
|
17145
|
-
runSmallIdentityCommand = async (command, args, env) => await new Promise((resolvePromise) => {
|
|
17256
|
+
runSmallIdentityCommand = async (command, args, env, timeoutMs = SMALL_IDENTITY_COMMAND_TIMEOUT_MS) => await new Promise((resolvePromise) => {
|
|
17146
17257
|
const child = spawn(command, [...args], {
|
|
17147
17258
|
windowsHide: true,
|
|
17148
17259
|
stdio: ["ignore", "pipe", "ignore"],
|
|
@@ -17160,7 +17271,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
17160
17271
|
const timer = setTimeout(() => {
|
|
17161
17272
|
child.kill("SIGKILL");
|
|
17162
17273
|
settle(null);
|
|
17163
|
-
},
|
|
17274
|
+
}, timeoutMs);
|
|
17164
17275
|
child.stdout.on("data", (chunk) => {
|
|
17165
17276
|
bytes3 += Buffer.byteLength(chunk);
|
|
17166
17277
|
if (bytes3 > 4096) {
|
|
@@ -17189,21 +17300,13 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
|
|
|
17189
17300
|
identity = null;
|
|
17190
17301
|
}
|
|
17191
17302
|
} else if (platform === "win32") {
|
|
17192
|
-
const
|
|
17193
|
-
identity = await runSmallIdentityCommand(
|
|
17194
|
-
"
|
|
17195
|
-
|
|
17196
|
-
|
|
17197
|
-
|
|
17198
|
-
|
|
17199
|
-
], {
|
|
17200
|
-
NODE_ENV: process.env.NODE_ENV,
|
|
17201
|
-
SystemRoot: process.env.SystemRoot,
|
|
17202
|
-
WINDIR: process.env.WINDIR,
|
|
17203
|
-
ComSpec: process.env.ComSpec,
|
|
17204
|
-
PATHEXT: process.env.PATHEXT,
|
|
17205
|
-
PSModulePath: process.env.PSModulePath
|
|
17206
|
-
});
|
|
17303
|
+
const invocation = windowsBootIdentityInvocation();
|
|
17304
|
+
identity = await runSmallIdentityCommand(
|
|
17305
|
+
"powershell.exe",
|
|
17306
|
+
invocation.args,
|
|
17307
|
+
invocation.env,
|
|
17308
|
+
invocation.timeoutMs
|
|
17309
|
+
);
|
|
17207
17310
|
} else if (platform === "darwin") {
|
|
17208
17311
|
identity = await runSmallIdentityCommand("sysctl", ["-n", "kern.boottime"], void 0);
|
|
17209
17312
|
}
|
|
@@ -19548,6 +19651,7 @@ var init_codex_app_server = __esm({
|
|
|
19548
19651
|
this.retryAtMs = options.retryAtMs ?? null;
|
|
19549
19652
|
this.usage = options.usage ?? null;
|
|
19550
19653
|
this.rateLimits = options.rateLimits ?? null;
|
|
19654
|
+
this.processExit = options.processExit ?? null;
|
|
19551
19655
|
}
|
|
19552
19656
|
};
|
|
19553
19657
|
objectOrNull = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -19852,7 +19956,7 @@ var init_codex_app_server = __esm({
|
|
|
19852
19956
|
};
|
|
19853
19957
|
GUARDIAN_SCRIPT = String.raw`
|
|
19854
19958
|
import { spawn } from 'node:child_process';
|
|
19855
|
-
import { chmod, open, rename, rm, writeFile } from 'node:fs/promises';
|
|
19959
|
+
import { chmod, open, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
19856
19960
|
import { dirname } from 'node:path';
|
|
19857
19961
|
const input = JSON.parse(Buffer.from(process.argv[1], 'base64url').toString('utf8'));
|
|
19858
19962
|
// The guardian owns the process boundary for every attempt. Apply a private
|
|
@@ -19882,7 +19986,7 @@ const replaceReceipt = async (temporary) => {
|
|
|
19882
19986
|
};
|
|
19883
19987
|
let receiptWriteSequence = 0;
|
|
19884
19988
|
let receiptWriteChain = Promise.resolve();
|
|
19885
|
-
const writeReceipt = (state, childPid) => {
|
|
19989
|
+
const writeReceipt = (state, childPid, termination = null) => {
|
|
19886
19990
|
const write = async () => {
|
|
19887
19991
|
const body = JSON.stringify({
|
|
19888
19992
|
schema_version: 'vtx_codex_guardian_v1',
|
|
@@ -19891,6 +19995,7 @@ const writeReceipt = (state, childPid) => {
|
|
|
19891
19995
|
guardian_pid: process.pid,
|
|
19892
19996
|
child_pid: childPid ?? null,
|
|
19893
19997
|
boot_identity: input.bootIdentity,
|
|
19998
|
+
termination,
|
|
19894
19999
|
updated_at: new Date().toISOString(),
|
|
19895
20000
|
}) + '\n';
|
|
19896
20001
|
receiptWriteSequence += 1;
|
|
@@ -19915,8 +20020,11 @@ const writeReceipt = (state, childPid) => {
|
|
|
19915
20020
|
};
|
|
19916
20021
|
let child = null;
|
|
19917
20022
|
let shuttingDown = false;
|
|
20023
|
+
let shutdownRequested = false;
|
|
20024
|
+
let childStartedAt = null;
|
|
19918
20025
|
let forceTimer = null;
|
|
19919
|
-
const
|
|
20026
|
+
const stopChild = (expected) => {
|
|
20027
|
+
if (expected) shutdownRequested = true;
|
|
19920
20028
|
if (shuttingDown) return;
|
|
19921
20029
|
shuttingDown = true;
|
|
19922
20030
|
if (!child) return;
|
|
@@ -19926,6 +20034,19 @@ const shutdown = () => {
|
|
|
19926
20034
|
}, input.shutdownGraceMs);
|
|
19927
20035
|
forceTimer.unref();
|
|
19928
20036
|
};
|
|
20037
|
+
let shutdownStarted = false;
|
|
20038
|
+
const shutdown = async () => {
|
|
20039
|
+
if (shutdownStarted) return;
|
|
20040
|
+
shutdownStarted = true;
|
|
20041
|
+
let expected = false;
|
|
20042
|
+
try {
|
|
20043
|
+
expected = (await readFile(input.shutdownIntentPath, 'utf8')) === input.processToken;
|
|
20044
|
+
await rm(input.shutdownIntentPath, { force: true });
|
|
20045
|
+
} catch {
|
|
20046
|
+
expected = false;
|
|
20047
|
+
}
|
|
20048
|
+
stopChild(expected);
|
|
20049
|
+
};
|
|
19929
20050
|
process.stdin.once('end', shutdown);
|
|
19930
20051
|
process.stdin.once('close', shutdown);
|
|
19931
20052
|
process.stdout.on('error', () => undefined);
|
|
@@ -19941,6 +20062,7 @@ child = spawn(input.binary, input.args, {
|
|
|
19941
20062
|
windowsHide: true,
|
|
19942
20063
|
detached: false,
|
|
19943
20064
|
});
|
|
20065
|
+
childStartedAt = Date.now();
|
|
19944
20066
|
child.stdin.on('error', () => undefined);
|
|
19945
20067
|
process.stdin.pipe(child.stdin, { end: false });
|
|
19946
20068
|
child.stdout.pipe(process.stdout);
|
|
@@ -19949,18 +20071,33 @@ child.once('spawn', async () => {
|
|
|
19949
20071
|
try {
|
|
19950
20072
|
await writeReceipt('running', child.pid ?? null);
|
|
19951
20073
|
} catch {
|
|
19952
|
-
|
|
20074
|
+
stopChild(false);
|
|
19953
20075
|
}
|
|
19954
20076
|
});
|
|
19955
|
-
child.once('error',
|
|
19956
|
-
child.once('close', async () => {
|
|
20077
|
+
child.once('error', () => stopChild(false));
|
|
20078
|
+
child.once('close', async (code, signal) => {
|
|
19957
20079
|
if (forceTimer) clearTimeout(forceTimer);
|
|
19958
20080
|
// A pending promise alone does not keep Node's event loop alive after the
|
|
19959
20081
|
// child and parent stdin have both closed. Hold one local handle until the
|
|
19960
20082
|
// serialized terminal tombstone is durably replaced.
|
|
19961
20083
|
const receiptKeepAlive = setInterval(() => undefined, 1_000);
|
|
19962
20084
|
try {
|
|
19963
|
-
|
|
20085
|
+
const normalizedSignal = typeof signal === 'string' && /^SIG[A-Z0-9]{1,28}$/.test(signal)
|
|
20086
|
+
? signal.toLowerCase()
|
|
20087
|
+
: null;
|
|
20088
|
+
const normalizedCode = normalizedSignal === null && Number.isInteger(code)
|
|
20089
|
+
&& code >= -(2 ** 31) && code <= (2 ** 31) - 1
|
|
20090
|
+
? code
|
|
20091
|
+
: null;
|
|
20092
|
+
await writeReceipt('terminated', child.pid ?? null, {
|
|
20093
|
+
exit_code: normalizedCode,
|
|
20094
|
+
signal: normalizedSignal,
|
|
20095
|
+
expected: shutdownRequested,
|
|
20096
|
+
uptime_ms: Math.min(
|
|
20097
|
+
Math.max(0, Date.now() - (childStartedAt ?? Date.now())),
|
|
20098
|
+
Number.MAX_SAFE_INTEGER,
|
|
20099
|
+
),
|
|
20100
|
+
});
|
|
19964
20101
|
} finally {
|
|
19965
20102
|
clearInterval(receiptKeepAlive);
|
|
19966
20103
|
process.exit(0);
|
|
@@ -20012,6 +20149,7 @@ child.once('close', async () => {
|
|
|
20012
20149
|
guardian_pid: null,
|
|
20013
20150
|
child_pid: null,
|
|
20014
20151
|
boot_identity: guardian.bootIdentity ?? null,
|
|
20152
|
+
termination: null,
|
|
20015
20153
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
20016
20154
|
})}
|
|
20017
20155
|
`;
|
|
@@ -20036,12 +20174,15 @@ child.once('close', async () => {
|
|
|
20036
20174
|
};
|
|
20037
20175
|
parseGuardianReceipt = (raw) => {
|
|
20038
20176
|
const value = JSON.parse(raw);
|
|
20039
|
-
|
|
20177
|
+
const rawTermination = value.termination;
|
|
20178
|
+
const termination = rawTermination === null || rawTermination === void 0 ? null : objectOrNull(rawTermination);
|
|
20179
|
+
if (value.schema_version !== "vtx_codex_guardian_v1" || typeof value.process_token !== "string" || !/^[0-9a-f]{64}$/u.test(value.process_token) || !["spawn_intent", "starting", "running", "terminated"].includes(String(value.state)) || value.guardian_pid !== null && !Number.isSafeInteger(value.guardian_pid) || value.state === "spawn_intent" && value.guardian_pid !== null || value.state !== "spawn_intent" && !Number.isSafeInteger(value.guardian_pid) || value.child_pid !== null && !Number.isSafeInteger(value.child_pid) || value.boot_identity !== null && value.boot_identity !== void 0 && typeof value.boot_identity !== "string" || typeof value.updated_at !== "string" || !Number.isFinite(Date.parse(value.updated_at)) || rawTermination !== null && rawTermination !== void 0 && termination === null || termination !== null && (value.state !== "terminated" || termination.exit_code !== null && (!Number.isInteger(termination.exit_code) || Number(termination.exit_code) < -(2 ** 31) || Number(termination.exit_code) > 2 ** 31 - 1) || termination.signal !== null && (typeof termination.signal !== "string" || !/^sig[a-z0-9]{1,28}$/u.test(termination.signal)) || termination.signal !== null && termination.exit_code !== null || typeof termination.expected !== "boolean" || !Number.isSafeInteger(termination.uptime_ms) || Number(termination.uptime_ms) < 0)) {
|
|
20040
20180
|
throw new Error("Codex guardian receipt is invalid.");
|
|
20041
20181
|
}
|
|
20042
20182
|
return {
|
|
20043
20183
|
...value,
|
|
20044
|
-
boot_identity: typeof value.boot_identity === "string" ? value.boot_identity : null
|
|
20184
|
+
boot_identity: typeof value.boot_identity === "string" ? value.boot_identity : null,
|
|
20185
|
+
termination
|
|
20045
20186
|
};
|
|
20046
20187
|
};
|
|
20047
20188
|
readCodexGuardianReceipt = async (path) => {
|
|
@@ -20085,6 +20226,7 @@ child.once('close', async () => {
|
|
|
20085
20226
|
args,
|
|
20086
20227
|
processToken: options.guardian.processToken,
|
|
20087
20228
|
receiptPath: options.guardian.receiptPath,
|
|
20229
|
+
shutdownIntentPath: `${options.guardian.receiptPath}.shutdown-intent`,
|
|
20088
20230
|
shutdownGraceMs: Math.max(25, options.guardian.shutdownGraceMs ?? 2e3),
|
|
20089
20231
|
bootIdentity: options.guardian.bootIdentity
|
|
20090
20232
|
}), "utf8").toString("base64url");
|
|
@@ -20106,13 +20248,33 @@ child.once('close', async () => {
|
|
|
20106
20248
|
this.nextRequestId = 1;
|
|
20107
20249
|
this.fatalError = null;
|
|
20108
20250
|
this.closed = false;
|
|
20251
|
+
this.processCloseObserved = false;
|
|
20252
|
+
this.shutdownRequested = false;
|
|
20253
|
+
this.stderrBytesObserved = 0;
|
|
20254
|
+
this.stderrNonempty = false;
|
|
20255
|
+
this.stderrTruncated = false;
|
|
20256
|
+
this.stderrTail = "";
|
|
20257
|
+
this.stderrClass = "none";
|
|
20109
20258
|
this.process = options.process;
|
|
20110
20259
|
this.codexHome = options.codexHome;
|
|
20111
|
-
this.
|
|
20260
|
+
this.sessionGeneration = options.sessionGeneration;
|
|
20261
|
+
this.startedAtMs = Date.now();
|
|
20262
|
+
this.guardian = options.guardian;
|
|
20263
|
+
this.onProcessExit = options.onProcessExit;
|
|
20264
|
+
this.process.stderr.on("data", (chunk) => this.observeStderr(chunk));
|
|
20112
20265
|
const lines = createInterface({ input: this.process.stdout, crlfDelay: Infinity });
|
|
20113
20266
|
lines.on("line", (line) => this.handleLine(line));
|
|
20114
|
-
this.process.once("error", () =>
|
|
20115
|
-
|
|
20267
|
+
this.process.once("error", () => {
|
|
20268
|
+
});
|
|
20269
|
+
this.process.once("close", (code, signal) => {
|
|
20270
|
+
void this.handleProcessClose(code, signal);
|
|
20271
|
+
});
|
|
20272
|
+
}
|
|
20273
|
+
static {
|
|
20274
|
+
this.STDERR_OBSERVATION_CAP_BYTES = 65536;
|
|
20275
|
+
}
|
|
20276
|
+
static {
|
|
20277
|
+
this.STDERR_CLASSIFICATION_TAIL_CHARS = 1024;
|
|
20116
20278
|
}
|
|
20117
20279
|
static async start(options) {
|
|
20118
20280
|
const spawnProcess = options.spawnProcess ?? defaultSpawn;
|
|
@@ -20173,7 +20335,13 @@ child.once('close', async () => {
|
|
|
20173
20335
|
});
|
|
20174
20336
|
}
|
|
20175
20337
|
}
|
|
20176
|
-
const session = new _CodexAppServerSession({
|
|
20338
|
+
const session = new _CodexAppServerSession({
|
|
20339
|
+
process: child,
|
|
20340
|
+
codexHome: options.codexHome,
|
|
20341
|
+
sessionGeneration: options.sessionGeneration ?? 1,
|
|
20342
|
+
guardian: guardian ?? null,
|
|
20343
|
+
onProcessExit: options.onProcessExit ?? null
|
|
20344
|
+
});
|
|
20177
20345
|
try {
|
|
20178
20346
|
const initialized = await session.request("initialize", {
|
|
20179
20347
|
clientInfo: {
|
|
@@ -20288,13 +20456,14 @@ child.once('close', async () => {
|
|
|
20288
20456
|
}
|
|
20289
20457
|
for (const listener of this.notificationListeners) listener({ method, params });
|
|
20290
20458
|
}
|
|
20291
|
-
failTransport(code) {
|
|
20459
|
+
failTransport(code, processExit = null) {
|
|
20292
20460
|
if (this.fatalError) return;
|
|
20293
20461
|
this.fatalError = new CodexAppServerError({
|
|
20294
20462
|
message: "Codex app-server transport became unavailable.",
|
|
20295
20463
|
category: "transport",
|
|
20296
20464
|
code,
|
|
20297
|
-
retryable: true
|
|
20465
|
+
retryable: true,
|
|
20466
|
+
processExit
|
|
20298
20467
|
});
|
|
20299
20468
|
for (const pending of this.pending.values()) {
|
|
20300
20469
|
if (pending.timer) clearTimeout(pending.timer);
|
|
@@ -20395,6 +20564,77 @@ child.once('close', async () => {
|
|
|
20395
20564
|
this.fatalListeners.add(listener);
|
|
20396
20565
|
return () => this.fatalListeners.delete(listener);
|
|
20397
20566
|
}
|
|
20567
|
+
observeStderr(chunk) {
|
|
20568
|
+
const bytes3 = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
|
|
20569
|
+
if (bytes3.length === 0) return;
|
|
20570
|
+
this.stderrNonempty = true;
|
|
20571
|
+
const remaining = Math.max(
|
|
20572
|
+
0,
|
|
20573
|
+
_CodexAppServerSession.STDERR_OBSERVATION_CAP_BYTES - this.stderrBytesObserved
|
|
20574
|
+
);
|
|
20575
|
+
if (remaining === 0) {
|
|
20576
|
+
this.stderrTruncated = true;
|
|
20577
|
+
return;
|
|
20578
|
+
}
|
|
20579
|
+
const observed = bytes3.subarray(0, remaining);
|
|
20580
|
+
this.stderrBytesObserved += observed.length;
|
|
20581
|
+
if (bytes3.length > remaining) this.stderrTruncated = true;
|
|
20582
|
+
this.stderrTail = `${this.stderrTail}${observed.toString("utf8")}`.slice(-_CodexAppServerSession.STDERR_CLASSIFICATION_TAIL_CHARS).toLowerCase();
|
|
20583
|
+
const classified = /heap out of memory|allocation failed|out of memory/u.test(this.stderrTail) ? "out_of_memory" : /fatal runtime error|fatal error|\bpanic(?:ked)?\b/u.test(this.stderrTail) ? "runtime_fatal" : /access violation|segmentation fault|\bsegfault\b/u.test(this.stderrTail) ? "memory_fault" : /broken pipe|econnreset|connection reset/u.test(this.stderrTail) ? "pipe_or_connection" : null;
|
|
20584
|
+
if (classified) this.stderrClass = classified;
|
|
20585
|
+
else if (this.stderrClass === "none") this.stderrClass = "unclassified";
|
|
20586
|
+
}
|
|
20587
|
+
async handleProcessClose(rawCode, rawSignal) {
|
|
20588
|
+
this.processCloseObserved = true;
|
|
20589
|
+
let termination = null;
|
|
20590
|
+
if (this.guardian) {
|
|
20591
|
+
try {
|
|
20592
|
+
const receipt = await readCodexGuardianReceipt(this.guardian.receiptPath);
|
|
20593
|
+
if (receipt?.process_token === this.guardian.processToken && receipt.state === "terminated") {
|
|
20594
|
+
termination = receipt.termination;
|
|
20595
|
+
}
|
|
20596
|
+
} catch {
|
|
20597
|
+
}
|
|
20598
|
+
}
|
|
20599
|
+
const diagnostics = this.processExitDiagnostics(rawCode, rawSignal, termination);
|
|
20600
|
+
if (this.guardian) {
|
|
20601
|
+
await rm2(`${this.guardian.receiptPath}.shutdown-intent`, { force: true }).catch(() => void 0);
|
|
20602
|
+
}
|
|
20603
|
+
try {
|
|
20604
|
+
this.onProcessExit?.(diagnostics);
|
|
20605
|
+
} catch {
|
|
20606
|
+
}
|
|
20607
|
+
this.failTransport("codex_process_closed", diagnostics);
|
|
20608
|
+
}
|
|
20609
|
+
processExitDiagnostics(rawCode, rawSignal, termination) {
|
|
20610
|
+
const source = termination ? "child_receipt" : this.guardian ? "guardian_process" : "direct_process";
|
|
20611
|
+
const reportedCode = termination?.exit_code ?? rawCode;
|
|
20612
|
+
const reportedSignal = termination?.signal ?? rawSignal;
|
|
20613
|
+
const signal = typeof reportedSignal === "string" && /^(?:SIG[A-Z0-9]{1,28}|sig[a-z0-9]{1,28})$/u.test(reportedSignal) ? reportedSignal.toLowerCase() : null;
|
|
20614
|
+
const exitCode = signal === null && typeof reportedCode === "number" && Number.isInteger(reportedCode) && reportedCode >= -(2 ** 31) && reportedCode <= 2 ** 31 - 1 ? reportedCode : null;
|
|
20615
|
+
const diagnostics = {
|
|
20616
|
+
schema_version: "external_inference_process_exit_v1",
|
|
20617
|
+
runtime: "codex_app_server",
|
|
20618
|
+
source,
|
|
20619
|
+
session_generation: this.sessionGeneration,
|
|
20620
|
+
expected_shutdown: termination?.expected ?? this.shutdownRequested,
|
|
20621
|
+
exit_class: signal !== null ? "signal" : exitCode === null ? "unknown" : exitCode === 0 ? "zero" : "nonzero",
|
|
20622
|
+
exit_code: exitCode,
|
|
20623
|
+
signal,
|
|
20624
|
+
uptime_ms: termination?.uptime_ms ?? Math.min(
|
|
20625
|
+
Math.max(0, Date.now() - this.startedAtMs),
|
|
20626
|
+
Number.MAX_SAFE_INTEGER
|
|
20627
|
+
),
|
|
20628
|
+
pending_request_count: this.pending.size,
|
|
20629
|
+
active_thread_count: this.threads.size,
|
|
20630
|
+
stderr_nonempty: this.stderrNonempty,
|
|
20631
|
+
stderr_bytes_observed: this.stderrBytesObserved,
|
|
20632
|
+
stderr_truncated: this.stderrTruncated,
|
|
20633
|
+
stderr_class: this.stderrNonempty ? this.stderrClass : "none"
|
|
20634
|
+
};
|
|
20635
|
+
this.stderrTail = "";
|
|
20636
|
+
return diagnostics;
|
|
20637
|
+
}
|
|
20398
20638
|
isUsable() {
|
|
20399
20639
|
return !this.closed && this.fatalError === null && this.process.exitCode === null;
|
|
20400
20640
|
}
|
|
@@ -20819,6 +21059,7 @@ child.once('close', async () => {
|
|
|
20819
21059
|
code: error48.code,
|
|
20820
21060
|
retryable: error48.retryable,
|
|
20821
21061
|
dispatchOutcome: requestWritten ? "outcome_unknown" : "not_dispatched",
|
|
21062
|
+
processExit: error48.processExit,
|
|
20822
21063
|
cause: error48
|
|
20823
21064
|
}));
|
|
20824
21065
|
});
|
|
@@ -21022,6 +21263,7 @@ child.once('close', async () => {
|
|
|
21022
21263
|
code: error48.code,
|
|
21023
21264
|
retryable: error48.retryable,
|
|
21024
21265
|
dispatchOutcome: "outcome_unknown",
|
|
21266
|
+
processExit: error48.processExit,
|
|
21025
21267
|
cause: error48
|
|
21026
21268
|
});
|
|
21027
21269
|
}
|
|
@@ -21274,6 +21516,20 @@ child.once('close', async () => {
|
|
|
21274
21516
|
async close() {
|
|
21275
21517
|
if (this.closed) return;
|
|
21276
21518
|
this.closed = true;
|
|
21519
|
+
if (this.processCloseObserved || this.process.exitCode !== null) {
|
|
21520
|
+
if (this.guardian) {
|
|
21521
|
+
await rm2(`${this.guardian.receiptPath}.shutdown-intent`, { force: true }).catch(() => void 0);
|
|
21522
|
+
}
|
|
21523
|
+
return;
|
|
21524
|
+
}
|
|
21525
|
+
this.shutdownRequested = true;
|
|
21526
|
+
if (this.guardian) {
|
|
21527
|
+
await writeFile(
|
|
21528
|
+
`${this.guardian.receiptPath}.shutdown-intent`,
|
|
21529
|
+
this.guardian.processToken,
|
|
21530
|
+
{ mode: 384 }
|
|
21531
|
+
).catch(() => void 0);
|
|
21532
|
+
}
|
|
21277
21533
|
this.process.stdin.end();
|
|
21278
21534
|
const exited = await new Promise((resolve6) => {
|
|
21279
21535
|
if (this.process.exitCode !== null) {
|
|
@@ -21482,11 +21738,12 @@ import {
|
|
|
21482
21738
|
import { createHash as createHash4, randomBytes as randomBytes3 } from "node:crypto";
|
|
21483
21739
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
21484
21740
|
import { isAbsolute as isAbsolute3, join as join4, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
21485
|
-
var MAX_PROMPT_BYTES2, CODEX_MODEL_NAME_PATTERN, CODEX_REASONING_EFFORT_PATTERN, codexRecoveryCheckpointProcessFingerprint, proveCodexSameBootQuiescence, tokenUsageReceiptSchema, turnResultReceiptSchema, terminalReceiptSchema, recoveryCheckpointSchema, recoveryFileSchema, FileCodexAttemptRecoveryStore, utf8Bytes, assertAttemptActive, tomlString, permissionConfig, ensureDedicatedCodexHome, createIsolatedCodexAttemptResources, createIsolatedCodexHostResources, validateAttemptInput, isStrictDescendant, assertRecoveryResourceScope, removeRecoveredThread, confirmGuardianTerminatedForRecovery, reconcileCodexAttemptRecovery, CodexSubscriptionAdapter;
|
|
21741
|
+
var MAX_PROMPT_BYTES2, CODEX_MODEL_NAME_PATTERN, CODEX_REASONING_EFFORT_PATTERN, codexRecoveryCheckpointProcessFingerprint, proveCodexSameBootQuiescence, tokenUsageReceiptSchema, turnResultReceiptSchema, terminalReceiptSchema, recoveryCheckpointSchema, recoveryFileSchema, FileCodexAttemptRecoveryStore, utf8Bytes, assertAttemptActive, tomlString, permissionConfig, ensureDedicatedCodexHome, createIsolatedCodexAttemptResources, createIsolatedCodexHostResources, validateAttemptInput, isStrictDescendant, assertRecoveryResourceScope, removeRecoveredThread, confirmGuardianTerminatedForRecovery, recoveredCodexProcessExit, reconcileCodexAttemptRecovery, CodexSubscriptionAdapter;
|
|
21486
21742
|
var init_codex_adapter = __esm({
|
|
21487
21743
|
"lib/inference-host/codex-adapter.ts"() {
|
|
21488
21744
|
"use strict";
|
|
21489
21745
|
init_zod();
|
|
21746
|
+
init_external_inference_contract();
|
|
21490
21747
|
init_codex_app_server();
|
|
21491
21748
|
init_codex_binary();
|
|
21492
21749
|
init_config();
|
|
@@ -21561,7 +21818,8 @@ var init_codex_adapter = __esm({
|
|
|
21561
21818
|
dispatchOutcome: external_exports.enum(["not_dispatched", "confirmed_dispatched", "outcome_unknown"]),
|
|
21562
21819
|
httpStatusCode: external_exports.number().int().min(100).max(599).nullable().optional(),
|
|
21563
21820
|
retryAtMs: external_exports.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).nullable().optional(),
|
|
21564
|
-
usage: tokenUsageReceiptSchema.nullable().optional()
|
|
21821
|
+
usage: tokenUsageReceiptSchema.nullable().optional(),
|
|
21822
|
+
processExit: codexProcessExitDiagnosticsSchema.nullable().optional()
|
|
21565
21823
|
})
|
|
21566
21824
|
})
|
|
21567
21825
|
]);
|
|
@@ -21577,6 +21835,7 @@ var init_codex_adapter = __esm({
|
|
|
21577
21835
|
processToken: external_exports.string().regex(/^[0-9a-f]{64}$/u).nullable(),
|
|
21578
21836
|
processReceiptPath: external_exports.string().min(1).max(4096).nullable(),
|
|
21579
21837
|
processState: external_exports.enum(["unmanaged", "spawn_intent", "running", "terminated"]),
|
|
21838
|
+
sessionGeneration: external_exports.number().int().positive().max(2147483647).nullable().optional(),
|
|
21580
21839
|
bootIdentity: external_exports.string().min(1).max(4096).nullable().optional(),
|
|
21581
21840
|
cleanupConfirmed: external_exports.boolean(),
|
|
21582
21841
|
adapterRequestId: external_exports.string().min(1).max(512).nullable(),
|
|
@@ -21971,6 +22230,30 @@ var init_codex_adapter = __esm({
|
|
|
21971
22230
|
throw error48;
|
|
21972
22231
|
}
|
|
21973
22232
|
};
|
|
22233
|
+
recoveredCodexProcessExit = (checkpoint, receipt) => {
|
|
22234
|
+
const termination = receipt?.termination;
|
|
22235
|
+
const sessionGeneration = checkpoint.sessionGeneration ?? null;
|
|
22236
|
+
if (!termination || termination.expected || sessionGeneration === null) return null;
|
|
22237
|
+
const signal = termination.signal;
|
|
22238
|
+
const exitCode = signal === null ? termination.exit_code : null;
|
|
22239
|
+
return {
|
|
22240
|
+
schema_version: "external_inference_process_exit_v1",
|
|
22241
|
+
runtime: "codex_app_server",
|
|
22242
|
+
source: "child_receipt",
|
|
22243
|
+
session_generation: sessionGeneration,
|
|
22244
|
+
expected_shutdown: false,
|
|
22245
|
+
exit_class: signal !== null ? "signal" : exitCode === null ? "unknown" : exitCode === 0 ? "zero" : "nonzero",
|
|
22246
|
+
exit_code: exitCode,
|
|
22247
|
+
signal,
|
|
22248
|
+
uptime_ms: termination.uptime_ms,
|
|
22249
|
+
pending_request_count: null,
|
|
22250
|
+
active_thread_count: null,
|
|
22251
|
+
stderr_nonempty: null,
|
|
22252
|
+
stderr_bytes_observed: null,
|
|
22253
|
+
stderr_truncated: null,
|
|
22254
|
+
stderr_class: "unknown"
|
|
22255
|
+
};
|
|
22256
|
+
};
|
|
21974
22257
|
reconcileCodexAttemptRecovery = async (options) => {
|
|
21975
22258
|
const attempts = await options.recoveryHooks.loadAll?.() ?? {};
|
|
21976
22259
|
const currentBootIdentity = options.bootIdentity ?? await readInferenceSystemBootIdentity();
|
|
@@ -22011,11 +22294,27 @@ var init_codex_adapter = __esm({
|
|
|
22011
22294
|
assertRecoveryResourceScope(checkpoint);
|
|
22012
22295
|
await removeRecoveredThread(checkpoint, options.codexHome);
|
|
22013
22296
|
await rm3(checkpoint.resourceRoot, { recursive: true, force: true });
|
|
22297
|
+
const recoveredProcessExit = recoveredCodexProcessExit(
|
|
22298
|
+
checkpoint,
|
|
22299
|
+
await readCodexGuardianReceipt(guardian.receiptPath)
|
|
22300
|
+
);
|
|
22301
|
+
const dispatchOutcome = crossedBoot ? "outcome_unknown" : checkpoint.dispatchOutcome;
|
|
22014
22302
|
await options.recoveryHooks.save({
|
|
22015
22303
|
...checkpoint,
|
|
22016
22304
|
processState: "terminated",
|
|
22017
22305
|
cleanupConfirmed: true,
|
|
22018
|
-
dispatchOutcome
|
|
22306
|
+
dispatchOutcome,
|
|
22307
|
+
terminal: checkpoint.terminal ?? (recoveredProcessExit ? {
|
|
22308
|
+
kind: "failed",
|
|
22309
|
+
error: {
|
|
22310
|
+
message: "Codex app-server transport became unavailable.",
|
|
22311
|
+
category: "transport",
|
|
22312
|
+
code: "codex_process_closed",
|
|
22313
|
+
retryable: true,
|
|
22314
|
+
dispatchOutcome,
|
|
22315
|
+
processExit: recoveredProcessExit
|
|
22316
|
+
}
|
|
22317
|
+
} : null)
|
|
22019
22318
|
});
|
|
22020
22319
|
reconciled += 1;
|
|
22021
22320
|
}
|
|
@@ -22029,8 +22328,15 @@ var init_codex_adapter = __esm({
|
|
|
22029
22328
|
this.durableSessionStart = null;
|
|
22030
22329
|
this.closing = false;
|
|
22031
22330
|
this.adapterClosePromise = null;
|
|
22331
|
+
this.sessionGeneration = 0;
|
|
22032
22332
|
this.dependencies = dependencies;
|
|
22033
22333
|
}
|
|
22334
|
+
emitDiagnostic(event) {
|
|
22335
|
+
try {
|
|
22336
|
+
this.dependencies.emitDiagnosticEvent?.(event);
|
|
22337
|
+
} catch {
|
|
22338
|
+
}
|
|
22339
|
+
}
|
|
22034
22340
|
async readAccountRateLimits(deadlineAtMs, signal) {
|
|
22035
22341
|
const codexHome = this.dependencies.codexHome;
|
|
22036
22342
|
if (!codexHome) {
|
|
@@ -22049,6 +22355,9 @@ var init_codex_adapter = __esm({
|
|
|
22049
22355
|
return await durableSession.session.readAccountRateLimits(deadlineAtMs, signal);
|
|
22050
22356
|
}
|
|
22051
22357
|
async startDurableSession(codexHome, deadlineAtMs) {
|
|
22358
|
+
this.sessionGeneration = Math.min(this.sessionGeneration + 1, 2147483647);
|
|
22359
|
+
const sessionGeneration = this.sessionGeneration;
|
|
22360
|
+
const activeAttemptIds = /* @__PURE__ */ new Set();
|
|
22052
22361
|
const binary = await (this.dependencies.resolveBinary ?? resolvePinnedCodexBinary)();
|
|
22053
22362
|
const guardianManaged = Boolean(
|
|
22054
22363
|
this.dependencies.recoveryHooks && !this.dependencies.spawnProcess
|
|
@@ -22063,10 +22372,26 @@ var init_codex_adapter = __esm({
|
|
|
22063
22372
|
codexHome,
|
|
22064
22373
|
deadlineAtMs,
|
|
22065
22374
|
spawnProcess: this.dependencies.spawnProcess,
|
|
22066
|
-
guardian: processToken && processReceiptPath ? { processToken, receiptPath: processReceiptPath, bootIdentity: bootIdentity ?? void 0 } : void 0
|
|
22375
|
+
guardian: processToken && processReceiptPath ? { processToken, receiptPath: processReceiptPath, bootIdentity: bootIdentity ?? void 0 } : void 0,
|
|
22376
|
+
sessionGeneration,
|
|
22377
|
+
onProcessExit: (diagnostics) => {
|
|
22378
|
+
this.emitDiagnostic({
|
|
22379
|
+
event: "codex_app_server_closed",
|
|
22380
|
+
process_exit: diagnostics,
|
|
22381
|
+
active_attempt_ids: [...activeAttemptIds].sort().slice(0, 64),
|
|
22382
|
+
active_attempt_ids_truncated: activeAttemptIds.size > 64
|
|
22383
|
+
});
|
|
22384
|
+
}
|
|
22385
|
+
});
|
|
22386
|
+
this.emitDiagnostic({
|
|
22387
|
+
event: "codex_app_server_session_started",
|
|
22388
|
+
session_generation: sessionGeneration,
|
|
22389
|
+
replacement: sessionGeneration > 1
|
|
22067
22390
|
});
|
|
22068
22391
|
return {
|
|
22069
22392
|
session,
|
|
22393
|
+
sessionGeneration,
|
|
22394
|
+
activeAttemptIds,
|
|
22070
22395
|
codexHome,
|
|
22071
22396
|
capabilityPreflight: null,
|
|
22072
22397
|
processToken,
|
|
@@ -22306,6 +22631,7 @@ var init_codex_adapter = __esm({
|
|
|
22306
22631
|
const receipt = await readCodexGuardianReceipt(checkpoint.processReceiptPath);
|
|
22307
22632
|
if (checkpoint.processState === "terminated" || receipt === null || receipt.state === "terminated") {
|
|
22308
22633
|
await rm3(checkpoint.processReceiptPath, { force: true });
|
|
22634
|
+
await rm3(`${checkpoint.processReceiptPath}.shutdown-intent`, { force: true });
|
|
22309
22635
|
}
|
|
22310
22636
|
}
|
|
22311
22637
|
}
|
|
@@ -22353,6 +22679,7 @@ var init_codex_adapter = __esm({
|
|
|
22353
22679
|
for (const session of sessions) {
|
|
22354
22680
|
if (session.processReceiptPath && unconfirmedReceiptPaths !== null && !unconfirmedReceiptPaths.has(resolve3(session.processReceiptPath))) {
|
|
22355
22681
|
await rm3(session.processReceiptPath, { force: true });
|
|
22682
|
+
await rm3(`${session.processReceiptPath}.shutdown-intent`, { force: true });
|
|
22356
22683
|
}
|
|
22357
22684
|
}
|
|
22358
22685
|
})();
|
|
@@ -22397,7 +22724,8 @@ var init_codex_adapter = __esm({
|
|
|
22397
22724
|
dispatchOutcome: recovered.dispatchOutcome,
|
|
22398
22725
|
httpStatusCode: recovered.httpStatusCode,
|
|
22399
22726
|
retryAtMs: recovered.retryAtMs,
|
|
22400
|
-
usage: recovered.usage
|
|
22727
|
+
usage: recovered.usage,
|
|
22728
|
+
processExit: recovered.processExit
|
|
22401
22729
|
});
|
|
22402
22730
|
}
|
|
22403
22731
|
throw new CodexAppServerError({
|
|
@@ -22430,6 +22758,7 @@ var init_codex_adapter = __esm({
|
|
|
22430
22758
|
input.deadlineAtMs,
|
|
22431
22759
|
input.signal
|
|
22432
22760
|
);
|
|
22761
|
+
sessionLease.activeAttemptIds.add(input.attemptId);
|
|
22433
22762
|
session = sessionLease.session;
|
|
22434
22763
|
baseCheckpoint = {
|
|
22435
22764
|
schemaVersion: "vtx_codex_attempt_recovery_v1",
|
|
@@ -22443,6 +22772,7 @@ var init_codex_adapter = __esm({
|
|
|
22443
22772
|
processToken: sessionLease.processToken,
|
|
22444
22773
|
processReceiptPath: sessionLease.processReceiptPath,
|
|
22445
22774
|
processState: sessionLease.processToken ? "running" : "unmanaged",
|
|
22775
|
+
sessionGeneration: sessionLease.sessionGeneration,
|
|
22446
22776
|
bootIdentity: sessionLease.bootIdentity,
|
|
22447
22777
|
cleanupConfirmed: false,
|
|
22448
22778
|
adapterRequestId: null,
|
|
@@ -22541,7 +22871,8 @@ var init_codex_adapter = __esm({
|
|
|
22541
22871
|
dispatchOutcome,
|
|
22542
22872
|
httpStatusCode: error48.httpStatusCode,
|
|
22543
22873
|
retryAtMs: error48.retryAtMs,
|
|
22544
|
-
usage: error48.usage
|
|
22874
|
+
usage: error48.usage,
|
|
22875
|
+
processExit: error48.processExit
|
|
22545
22876
|
}
|
|
22546
22877
|
}
|
|
22547
22878
|
};
|
|
@@ -22557,6 +22888,7 @@ var init_codex_adapter = __esm({
|
|
|
22557
22888
|
httpStatusCode: error48.httpStatusCode,
|
|
22558
22889
|
retryAtMs: error48.retryAtMs,
|
|
22559
22890
|
usage: error48.usage,
|
|
22891
|
+
processExit: error48.processExit,
|
|
22560
22892
|
cause: error48
|
|
22561
22893
|
});
|
|
22562
22894
|
}
|
|
@@ -22587,6 +22919,7 @@ var init_codex_adapter = __esm({
|
|
|
22587
22919
|
}
|
|
22588
22920
|
throw classified;
|
|
22589
22921
|
} finally {
|
|
22922
|
+
sessionLease?.activeAttemptIds.delete(input.attemptId);
|
|
22590
22923
|
const cleanup = async () => {
|
|
22591
22924
|
let cleanupError = sessionInvalidationError;
|
|
22592
22925
|
if (session && threadId) {
|
|
@@ -29717,7 +30050,7 @@ function createDefaultInferenceHostRunnerDependencies(options) {
|
|
|
29717
30050
|
envelopePublicKey: options.envelopePublicKey
|
|
29718
30051
|
};
|
|
29719
30052
|
}
|
|
29720
|
-
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_PROVIDER_RATE_LIMIT_REFRESH_MS, DEFAULT_ATTEMPT_HEARTBEAT_MS, DEFAULT_DRAIN_TIMEOUT_MS, DEFAULT_REMOTE_RETRY_LIMIT, MIN_SLEEP_MS, DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS, MIN_CLAIM_START_WINDOW_MS, UNBOUNDED_AVAILABLE_SLOTS, buildInferenceAdvertisedModels, summarizeInferenceHostRuntimeRecovery, FileInferenceHostRuntimeReceiptStore, InferenceHostRecoveryRequiredError, InferenceHostRunnerError, defaultSleep, abortError, defaultRegisterSignalHandlers, safeInteger, exactObjectKeys, validIso, validateAttemptReceipt, validateRuntimeReceipt, sha256, stableOperationId, buildAttemptStartRequest, isoAt, providerWeeklyQuotaFromRateLimits, finitePositiveOption, validateRunnerOptions, assertLocalCredentialIdentity, retryableRemoteError, remoteRetryAfterMs, controlPlaneFatal, defaultValidateOutput, objectRecord, positiveUtf8ByteLimit, assertCompilableOutputSchema, parseOutputContract, membershipFailureDisposition, safeFailureCode, exactJson2, runnerIdentityMismatch, assertAdvertisementResult, assertHostHeartbeatResult, assertClaimResult, assertStartResult, assertJobHeartbeatResult, assertTerminalResult, classifyFailure, ambiguousHeartbeatTransport, reportedTokenUsage, reportedUsage, InferenceHostRunner;
|
|
30053
|
+
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_PROVIDER_RATE_LIMIT_REFRESH_MS, DEFAULT_ATTEMPT_HEARTBEAT_MS, DEFAULT_DRAIN_TIMEOUT_MS, DEFAULT_REMOTE_RETRY_LIMIT, MIN_SLEEP_MS, MIN_HOST_HEARTBEAT_GAP_DIAGNOSTIC_MS, HOST_HEARTBEAT_GAP_DIAGNOSTIC_FACTOR, DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS, MIN_CLAIM_START_WINDOW_MS, MAX_ATTEMPT_START_RETRY_DELAY_MS, UNBOUNDED_AVAILABLE_SLOTS, buildInferenceAdvertisedModels, summarizeInferenceHostRuntimeRecovery, FileInferenceHostRuntimeReceiptStore, InferenceHostRecoveryRequiredError, InferenceHostRunnerError, defaultSleep, abortError, defaultRegisterSignalHandlers, safeInteger, exactObjectKeys, validIso, validateAttemptReceipt, validateRuntimeReceipt, sha256, stableOperationId, buildAttemptStartRequest, isoAt, providerWeeklyQuotaFromRateLimits, finitePositiveOption, validateRunnerOptions, assertLocalCredentialIdentity, retryableRemoteError, remoteRetryAfterMs, controlPlaneFatal, defaultValidateOutput, objectRecord, positiveUtf8ByteLimit, assertCompilableOutputSchema, parseOutputContract, membershipFailureDisposition, safeFailureCode, attemptStartRetryFallbackMs, exactJson2, runnerIdentityMismatch, assertAdvertisementResult, assertHostHeartbeatResult, assertClaimResult, assertStartResult, assertJobHeartbeatResult, assertTerminalResult, classifyFailure, ambiguousHeartbeatTransport, reportedTokenUsage, reportedUsage, InferenceHostRunner;
|
|
29721
30054
|
var init_runner = __esm({
|
|
29722
30055
|
"lib/inference-host/runner.ts"() {
|
|
29723
30056
|
"use strict";
|
|
@@ -29739,8 +30072,11 @@ var init_runner = __esm({
|
|
|
29739
30072
|
DEFAULT_DRAIN_TIMEOUT_MS = 3e4;
|
|
29740
30073
|
DEFAULT_REMOTE_RETRY_LIMIT = 3;
|
|
29741
30074
|
MIN_SLEEP_MS = 10;
|
|
30075
|
+
MIN_HOST_HEARTBEAT_GAP_DIAGNOSTIC_MS = 1e4;
|
|
30076
|
+
HOST_HEARTBEAT_GAP_DIAGNOSTIC_FACTOR = 3;
|
|
29742
30077
|
DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS = 5 * 60 * 1e3;
|
|
29743
30078
|
MIN_CLAIM_START_WINDOW_MS = 5e3;
|
|
30079
|
+
MAX_ATTEMPT_START_RETRY_DELAY_MS = 15e3;
|
|
29744
30080
|
UNBOUNDED_AVAILABLE_SLOTS = Number.MAX_SAFE_INTEGER;
|
|
29745
30081
|
buildInferenceAdvertisedModels = (capabilities, adapterRuntimeVersion, adapter = "codex", structuredOutput = true, sameAttemptRecovery = adapter === "codex") => {
|
|
29746
30082
|
const visible = capabilities.filter((capability) => !capability.hidden);
|
|
@@ -30276,6 +30612,10 @@ var init_runner = __esm({
|
|
|
30276
30612
|
const normalized = value.trim().toLowerCase().replace(/[^a-z0-9._-]+/gu, "_").slice(0, 96);
|
|
30277
30613
|
return /^[a-z0-9]/u.test(normalized) ? normalized : fallback;
|
|
30278
30614
|
};
|
|
30615
|
+
attemptStartRetryFallbackMs = (retryCount) => Math.min(
|
|
30616
|
+
1e3 * 2 ** Math.min(Math.max(0, retryCount - 1), 4),
|
|
30617
|
+
MAX_ATTEMPT_START_RETRY_DELAY_MS
|
|
30618
|
+
);
|
|
30279
30619
|
exactJson2 = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
30280
30620
|
runnerIdentityMismatch = (operation) => {
|
|
30281
30621
|
throw new InferenceHostRunnerError(
|
|
@@ -30729,6 +31069,26 @@ var init_runner = __esm({
|
|
|
30729
31069
|
}
|
|
30730
31070
|
};
|
|
30731
31071
|
await hostHeartbeat("healthy");
|
|
31072
|
+
let lastHostHeartbeatSucceededAt = now();
|
|
31073
|
+
let hostHeartbeatGapOpen = false;
|
|
31074
|
+
const hostHeartbeatGapThresholdMs = Math.max(
|
|
31075
|
+
MIN_HOST_HEARTBEAT_GAP_DIAGNOSTIC_MS,
|
|
31076
|
+
settings.hostHeartbeatMs * HOST_HEARTBEAT_GAP_DIAGNOSTIC_FACTOR
|
|
31077
|
+
);
|
|
31078
|
+
const observeHostHeartbeatGap = (observedAt) => {
|
|
31079
|
+
const gapMs = Math.max(0, observedAt - lastHostHeartbeatSucceededAt);
|
|
31080
|
+
if (gapMs >= hostHeartbeatGapThresholdMs && !hostHeartbeatGapOpen) {
|
|
31081
|
+
hostHeartbeatGapOpen = true;
|
|
31082
|
+
emitDiagnostic("host_heartbeat_gap_detected", {
|
|
31083
|
+
gap_ms: gapMs,
|
|
31084
|
+
configured_interval_ms: settings.hostHeartbeatMs,
|
|
31085
|
+
diagnostic_threshold_ms: hostHeartbeatGapThresholdMs,
|
|
31086
|
+
active_attempts: active.size,
|
|
31087
|
+
host_heartbeat_sequence: receipt.host_heartbeat_sequence
|
|
31088
|
+
});
|
|
31089
|
+
}
|
|
31090
|
+
return gapMs;
|
|
31091
|
+
};
|
|
30732
31092
|
let nextHostHeartbeatAt = now() + settings.hostHeartbeatMs;
|
|
30733
31093
|
let nextAdvertisementAttemptAt = 0;
|
|
30734
31094
|
let nextProviderRateLimitRefreshAt = now() + settings.providerRateLimitRefreshMs;
|
|
@@ -30736,6 +31096,7 @@ var init_runner = __esm({
|
|
|
30736
31096
|
let pendingClaimPromotions = 0;
|
|
30737
31097
|
let onceClaimed = false;
|
|
30738
31098
|
const recoveryQueue = [];
|
|
31099
|
+
const attemptStartRetryCounts = /* @__PURE__ */ new Map();
|
|
30739
31100
|
const launchClaim = (claim, recovery, claimRequest) => {
|
|
30740
31101
|
if (!recovery) {
|
|
30741
31102
|
claimed += 1;
|
|
@@ -30748,6 +31109,10 @@ var init_runner = __esm({
|
|
|
30748
31109
|
claim.attempt_index,
|
|
30749
31110
|
claim.input_sha256
|
|
30750
31111
|
]);
|
|
31112
|
+
const nextStartRetryCount = Math.min(
|
|
31113
|
+
(attemptStartRetryCounts.get(attemptId) ?? 0) + 1,
|
|
31114
|
+
Number.MAX_SAFE_INTEGER
|
|
31115
|
+
);
|
|
30751
31116
|
const controller = new AbortController();
|
|
30752
31117
|
attemptControllers.set(attemptId, controller);
|
|
30753
31118
|
let claimPromotionSettled = claimRequest === void 0;
|
|
@@ -30812,13 +31177,27 @@ var init_runner = __esm({
|
|
|
30812
31177
|
active_attempts: active.size
|
|
30813
31178
|
});
|
|
30814
31179
|
},
|
|
31180
|
+
startRetryCount: nextStartRetryCount,
|
|
31181
|
+
onAttemptStartRetry: (observation) => {
|
|
31182
|
+
attemptStartRetryCounts.set(attemptId, observation.retry_count);
|
|
31183
|
+
emitDiagnostic("attempt_start_retry_scheduled", {
|
|
31184
|
+
...observation,
|
|
31185
|
+
job_id: claim.job_id,
|
|
31186
|
+
attempt_id: attemptId,
|
|
31187
|
+
active_attempts: active.size
|
|
31188
|
+
});
|
|
31189
|
+
},
|
|
30815
31190
|
resumeReceipt: recovery,
|
|
30816
31191
|
claimRequest,
|
|
30817
31192
|
onClaimPersisted: settleClaimPromotion
|
|
30818
31193
|
}).then((outcome) => {
|
|
30819
|
-
if (outcome === "completed")
|
|
30820
|
-
|
|
30821
|
-
|
|
31194
|
+
if (outcome === "completed") {
|
|
31195
|
+
attemptStartRetryCounts.delete(attemptId);
|
|
31196
|
+
completed += 1;
|
|
31197
|
+
} else if (outcome === "failed") {
|
|
31198
|
+
attemptStartRetryCounts.delete(attemptId);
|
|
31199
|
+
failed += 1;
|
|
31200
|
+
} else {
|
|
30822
31201
|
const recovery2 = receipt.attempts[attemptId];
|
|
30823
31202
|
if (recovery2?.phase !== "claimed") {
|
|
30824
31203
|
throw new InferenceHostRecoveryRequiredError(
|
|
@@ -30828,6 +31207,7 @@ var init_runner = __esm({
|
|
|
30828
31207
|
retryRecovery = recovery2;
|
|
30829
31208
|
}
|
|
30830
31209
|
}).catch((error48) => {
|
|
31210
|
+
attemptStartRetryCounts.delete(attemptId);
|
|
30831
31211
|
failed += 1;
|
|
30832
31212
|
const recovery2 = receipt.attempts[attemptId];
|
|
30833
31213
|
if (recovery2?.phase === "terminal_pending") {
|
|
@@ -30840,22 +31220,19 @@ var init_runner = __esm({
|
|
|
30840
31220
|
attemptControllers.delete(attemptId);
|
|
30841
31221
|
if (retryRecovery) {
|
|
30842
31222
|
recoveryQueue.push(retryRecovery);
|
|
30843
|
-
emitDiagnostic("attempt_start_retry_scheduled", {
|
|
30844
|
-
job_id: claim.job_id,
|
|
30845
|
-
attempt_id: attemptId,
|
|
30846
|
-
active_attempts: active.size
|
|
30847
|
-
});
|
|
30848
31223
|
}
|
|
30849
31224
|
});
|
|
30850
31225
|
active.set(attemptId, promise2);
|
|
30851
|
-
|
|
30852
|
-
|
|
30853
|
-
|
|
30854
|
-
|
|
30855
|
-
|
|
30856
|
-
|
|
30857
|
-
|
|
30858
|
-
|
|
31226
|
+
if (!recovery) {
|
|
31227
|
+
emitDiagnostic("attempt_started", {
|
|
31228
|
+
job_id: claim.job_id,
|
|
31229
|
+
attempt_id: attemptId,
|
|
31230
|
+
attempt_index: claim.attempt_index,
|
|
31231
|
+
requested_model: claim.requested_model,
|
|
31232
|
+
requested_reasoning_effort: claim.requested_reasoning_effort,
|
|
31233
|
+
active_attempts: active.size
|
|
31234
|
+
});
|
|
31235
|
+
}
|
|
30859
31236
|
return attemptId;
|
|
30860
31237
|
};
|
|
30861
31238
|
const removeRecoveredAttempt = async (attemptId) => {
|
|
@@ -30978,6 +31355,7 @@ var init_runner = __esm({
|
|
|
30978
31355
|
}
|
|
30979
31356
|
}
|
|
30980
31357
|
if (currentTime >= nextHostHeartbeatAt) {
|
|
31358
|
+
observeHostHeartbeatGap(currentTime);
|
|
30981
31359
|
try {
|
|
30982
31360
|
const refreshPendingAcrossExpiry = receipt.pending_advertisement !== null && expiresAt <= currentTime && nextAdvertisementAttemptAt > currentTime;
|
|
30983
31361
|
await hostHeartbeat(
|
|
@@ -30986,6 +31364,19 @@ var init_runner = __esm({
|
|
|
30986
31364
|
false,
|
|
30987
31365
|
refreshPendingAcrossExpiry
|
|
30988
31366
|
);
|
|
31367
|
+
const heartbeatSucceededAt = now();
|
|
31368
|
+
const gapMs = observeHostHeartbeatGap(heartbeatSucceededAt);
|
|
31369
|
+
if (hostHeartbeatGapOpen) {
|
|
31370
|
+
emitDiagnostic("host_heartbeat_gap_recovered", {
|
|
31371
|
+
gap_ms: gapMs,
|
|
31372
|
+
configured_interval_ms: settings.hostHeartbeatMs,
|
|
31373
|
+
diagnostic_threshold_ms: hostHeartbeatGapThresholdMs,
|
|
31374
|
+
active_attempts: active.size,
|
|
31375
|
+
host_heartbeat_sequence: receipt.host_heartbeat_sequence
|
|
31376
|
+
});
|
|
31377
|
+
hostHeartbeatGapOpen = false;
|
|
31378
|
+
}
|
|
31379
|
+
lastHostHeartbeatSucceededAt = heartbeatSucceededAt;
|
|
30989
31380
|
} catch (error48) {
|
|
30990
31381
|
if (controlPlaneFatal(error48)) {
|
|
30991
31382
|
requestDrain("authority_lost");
|
|
@@ -31262,10 +31653,28 @@ var init_runner = __esm({
|
|
|
31262
31653
|
MIN_SLEEP_MS,
|
|
31263
31654
|
attemptDeadlineAtMs - now() - MIN_CLAIM_START_WINDOW_MS
|
|
31264
31655
|
);
|
|
31265
|
-
|
|
31266
|
-
Math.
|
|
31267
|
-
|
|
31656
|
+
const retryCount = Math.min(
|
|
31657
|
+
Math.max(1, options.startRetryCount),
|
|
31658
|
+
Number.MAX_SAFE_INTEGER
|
|
31268
31659
|
);
|
|
31660
|
+
const retryDelayMs = Math.min(
|
|
31661
|
+
remoteRetryAfterMs(error48, attemptStartRetryFallbackMs(retryCount)),
|
|
31662
|
+
remainingMs
|
|
31663
|
+
);
|
|
31664
|
+
const rawErrorCode = error48 && typeof error48 === "object" && "code" in error48 ? String(error48.code) : "start_acknowledgement_failed";
|
|
31665
|
+
options.onAttemptStartRetry?.({
|
|
31666
|
+
failure_stage: "job_start_acknowledgement",
|
|
31667
|
+
error_code: safeFailureCode(rawErrorCode, "start_acknowledgement_failed"),
|
|
31668
|
+
http_status_code: error48 instanceof ExternalInferenceMcpError ? error48.httpStatusCode : null,
|
|
31669
|
+
retryable: retryableRemoteError(error48),
|
|
31670
|
+
definitively_not_applied: Boolean(
|
|
31671
|
+
error48 && typeof error48 === "object" && "definitivelyNotApplied" in error48 && error48.definitivelyNotApplied === true
|
|
31672
|
+
),
|
|
31673
|
+
retry_after_ms: error48 instanceof ExternalInferenceMcpError ? error48.retryAfterMs : null,
|
|
31674
|
+
retry_count: retryCount,
|
|
31675
|
+
next_delay_ms: retryDelayMs
|
|
31676
|
+
});
|
|
31677
|
+
await options.sleep(retryDelayMs, signal);
|
|
31269
31678
|
return "retry_claimed";
|
|
31270
31679
|
}
|
|
31271
31680
|
assertStartResult(startRequest, startResult);
|
|
@@ -31527,6 +31936,7 @@ var init_runner = __esm({
|
|
|
31527
31936
|
});
|
|
31528
31937
|
}
|
|
31529
31938
|
const classified = classifyFailure(heartbeatFailure ?? error48, adapterResult);
|
|
31939
|
+
const processExit = heartbeatFailure === void 0 && error48 instanceof CodexAppServerError && error48.code === "codex_process_closed" && error48.processExit?.expected_shutdown === false ? error48.processExit : null;
|
|
31530
31940
|
const heartbeatAmbiguous = ambiguousHeartbeatTransport(heartbeatFailure);
|
|
31531
31941
|
const failure = heartbeatAmbiguous ? {
|
|
31532
31942
|
...classified,
|
|
@@ -31580,6 +31990,7 @@ var init_runner = __esm({
|
|
|
31580
31990
|
failure_category: failure.category,
|
|
31581
31991
|
failure_code: failure.code,
|
|
31582
31992
|
retryable: failure.retryable,
|
|
31993
|
+
...processExit ? { process_exit: processExit } : {},
|
|
31583
31994
|
membership_disposition: membershipFailureDisposition({
|
|
31584
31995
|
...failure,
|
|
31585
31996
|
dispatchOutcome
|
|
@@ -31614,6 +32025,7 @@ var init_runner = __esm({
|
|
|
31614
32025
|
failure_category: failureRequest.failure_category,
|
|
31615
32026
|
failure_code: failureRequest.failure_code,
|
|
31616
32027
|
retryable: failureRequest.retryable,
|
|
32028
|
+
process_exit: failureRequest.process_exit ?? null,
|
|
31617
32029
|
dispatch_outcome: failureRequest.outcome.dispatch_outcome,
|
|
31618
32030
|
response_outcome: failureRequest.outcome.response_outcome,
|
|
31619
32031
|
latency_ms: adapterResult?.latencyMs ?? null,
|
|
@@ -32983,8 +33395,8 @@ ${result2.stderr}`)) {
|
|
|
32983
33395
|
return !nextWorker || !sameWorker(record2.worker, nextWorker);
|
|
32984
33396
|
});
|
|
32985
33397
|
for (const record2 of retiring) {
|
|
32986
|
-
await updateRecord(record2, "draining");
|
|
32987
33398
|
record2.controller.abort();
|
|
33399
|
+
await updateRecord(record2, "draining");
|
|
32988
33400
|
}
|
|
32989
33401
|
const settled = await Promise.allSettled(retiring.map((record2) => record2.promise));
|
|
32990
33402
|
const failedDrain = settled.find(
|
|
@@ -33018,8 +33430,8 @@ ${result2.stderr}`)) {
|
|
|
33018
33430
|
const drainWorkers = async () => {
|
|
33019
33431
|
const draining = [...workers.values()];
|
|
33020
33432
|
for (const record2 of draining) {
|
|
33021
|
-
await updateRecord(record2, "draining");
|
|
33022
33433
|
record2.controller.abort();
|
|
33434
|
+
await updateRecord(record2, "draining");
|
|
33023
33435
|
}
|
|
33024
33436
|
const settled = await Promise.allSettled(draining.map((record2) => record2.promise));
|
|
33025
33437
|
const failedDrain = settled.find(
|
|
@@ -33607,6 +34019,17 @@ Durable service:
|
|
|
33607
34019
|
}
|
|
33608
34020
|
};
|
|
33609
34021
|
defaultRunForeground = async (options) => {
|
|
34022
|
+
const localState = await readInferenceHostLocalState(options.config.statePath);
|
|
34023
|
+
const emitCodexDiagnostic = (event) => {
|
|
34024
|
+
options.emitDiagnosticEvent?.({
|
|
34025
|
+
...event,
|
|
34026
|
+
schema_version: "vtx_inference_host_diagnostic_v1",
|
|
34027
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
34028
|
+
instance_name: options.config.instanceName,
|
|
34029
|
+
host_id: localState?.host_id ?? null,
|
|
34030
|
+
display_name: options.displayName
|
|
34031
|
+
});
|
|
34032
|
+
};
|
|
33610
34033
|
const adapter = new CodexSubscriptionAdapter({
|
|
33611
34034
|
resolveBinary: async () => options.verifiedBinary,
|
|
33612
34035
|
createAttemptResources: options.hostResources.createAttemptResources,
|
|
@@ -33614,7 +34037,8 @@ Durable service:
|
|
|
33614
34037
|
guardianReceiptRoot: codexGuardianReceiptRoot(options.config),
|
|
33615
34038
|
recoveryHooks: new FileCodexAttemptRecoveryStore(
|
|
33616
34039
|
codexRecoveryPath(options.config)
|
|
33617
|
-
)
|
|
34040
|
+
),
|
|
34041
|
+
emitDiagnosticEvent: emitCodexDiagnostic
|
|
33618
34042
|
});
|
|
33619
34043
|
const dependencies = createDefaultInferenceHostRunnerDependencies({
|
|
33620
34044
|
apiUrl: options.config.apiUrl,
|
|
@@ -34291,7 +34715,15 @@ Waiting for approval...
|
|
|
34291
34715
|
const emitDiagnosticEvent = parsed.json ? (event) => (dependencies.emitStdout ?? ((text) => {
|
|
34292
34716
|
process.stdout.write(text);
|
|
34293
34717
|
}))(`${JSON.stringify(event)}
|
|
34294
|
-
`) :
|
|
34718
|
+
`) : adapterId === "codex" ? (event) => {
|
|
34719
|
+
if (!["codex_app_server_closed", "codex_app_server_session_started"].includes(
|
|
34720
|
+
String(event.event ?? "")
|
|
34721
|
+
)) return;
|
|
34722
|
+
(dependencies.emitStderr ?? ((text) => {
|
|
34723
|
+
process.stderr.write(text);
|
|
34724
|
+
}))(`[VTX inference-host] ${JSON.stringify(event)}
|
|
34725
|
+
`);
|
|
34726
|
+
} : void 0;
|
|
34295
34727
|
if (adapterId !== "codex") {
|
|
34296
34728
|
const prepared = await (dependencies.prepareDurableAdapter ?? preparePortableDurableAdapter)(
|
|
34297
34729
|
adapterId,
|