@vtxmacro/cli 2026.8.51 → 2026.8.53

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 +42 -18
  2. package/bin/vtx.js +1780 -185
  3. package/package.json +1 -1
package/bin/vtx.js CHANGED
@@ -5,11 +5,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __esm = (fn, res) => function __init() {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ var __esm = (fn, res, err) => function __init() {
9
+ if (err) throw err[0];
10
+ try {
11
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
+ } catch (e) {
13
+ throw err = [e], e;
14
+ }
10
15
  };
11
16
  var __commonJS = (cb, mod2) => function __require() {
12
- return mod2 || (0, cb[__getOwnPropNames(cb)[0]])((mod2 = { exports: {} }).exports, mod2), mod2.exports;
17
+ try {
18
+ return mod2 || (0, cb[__getOwnPropNames(cb)[0]])((mod2 = { exports: {} }).exports, mod2), mod2.exports;
19
+ } catch (e) {
20
+ throw mod2 = 0, e;
21
+ }
13
22
  };
14
23
  var __export = (target, all) => {
15
24
  for (var name in all)
@@ -38,7 +47,7 @@ var init_agent_cli_release = __esm({
38
47
  "agent-cli-release.json"() {
39
48
  agent_cli_release_default = {
40
49
  package_name: "@vtxmacro/cli",
41
- package_version: "2026.8.51",
50
+ package_version: "2026.8.53",
42
51
  codex_package_name: "@openai/codex",
43
52
  codex_version: "0.147.0",
44
53
  copilot_sdk_package_name: "@github/copilot-sdk",
@@ -16535,6 +16544,25 @@ async function syncInferenceDirectory(path, platform = process.platform) {
16535
16544
  await handle.close();
16536
16545
  }
16537
16546
  }
16547
+ async function replaceAtomicInferencePrivateFile(temporaryPath, destinationPath, options = {}) {
16548
+ const platform = options.platform ?? process.platform;
16549
+ const renameFile = options.renameFile ?? rename;
16550
+ const sleep4 = options.sleep ?? ((milliseconds) => new Promise((resolve6) => setTimeout(resolve6, milliseconds)));
16551
+ const maxAttempts = Math.max(1, options.maxAttempts ?? 40);
16552
+ const retryDelayMs = Math.max(0, options.retryDelayMs ?? 25);
16553
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
16554
+ try {
16555
+ await renameFile(temporaryPath, destinationPath);
16556
+ return;
16557
+ } catch (error48) {
16558
+ const code = String(error48.code ?? "");
16559
+ if (platform !== "win32" || !WINDOWS_PRIVATE_FILE_REPLACE_ERROR_CODES.has(code) || attempt === maxAttempts - 1) {
16560
+ throw error48;
16561
+ }
16562
+ await sleep4(retryDelayMs);
16563
+ }
16564
+ }
16565
+ }
16538
16566
  async function writeAtomicInferencePrivateFile(path, contents, dependencies = {}) {
16539
16567
  const platform = dependencies.platform ?? process.platform;
16540
16568
  const runner = dependencies.runner ?? runWindowsPrivateAcl;
@@ -16571,7 +16599,13 @@ async function writeAtomicInferencePrivateFile(path, contents, dependencies = {}
16571
16599
  }
16572
16600
  try {
16573
16601
  invalidateWindowsAclCache(path);
16574
- await rename(temporary, path);
16602
+ await replaceAtomicInferencePrivateFile(temporary, path, {
16603
+ platform,
16604
+ renameFile: dependencies.renameFile,
16605
+ sleep: dependencies.sleep,
16606
+ maxAttempts: dependencies.replaceMaxAttempts,
16607
+ retryDelayMs: dependencies.replaceRetryDelayMs
16608
+ });
16575
16609
  if (platform === "win32" && hardenedIdentity) {
16576
16610
  await rebindHardenedWindowsAclAfterRename(
16577
16611
  temporary,
@@ -16838,7 +16872,7 @@ async function acquireInferenceHostProcessLock(path, dependencies = {}) {
16838
16872
  }
16839
16873
  };
16840
16874
  }
16841
- 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;
16875
+ 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, WINDOWS_PRIVATE_FILE_REPLACE_ERROR_CODES;
16842
16876
  var init_config = __esm({
16843
16877
  "lib/inference-host/config.ts"() {
16844
16878
  "use strict";
@@ -17413,6 +17447,13 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
17413
17447
  credential_store_mode: config2.credentialStoreMode,
17414
17448
  credential_file_path: config2.credentialStoreMode === "file" ? resolve(config2.credentialFilePath) : null
17415
17449
  });
17450
+ WINDOWS_PRIVATE_FILE_REPLACE_ERROR_CODES = /* @__PURE__ */ new Set([
17451
+ "EACCES",
17452
+ "EBUSY",
17453
+ "EEXIST",
17454
+ "ENOTEMPTY",
17455
+ "EPERM"
17456
+ ]);
17416
17457
  }
17417
17458
  });
17418
17459
 
@@ -19654,32 +19695,60 @@ var init_agent_client = __esm({
19654
19695
  });
19655
19696
 
19656
19697
  // lib/inference-host/agent-state.ts
19657
- async function readCodexAgentRuntimeState(statePath) {
19698
+ async function readInferenceAgentRuntimeState(statePath) {
19658
19699
  const raw = await readInferencePrivateFile(
19659
- codexAgentRuntimeStatePath(statePath),
19660
- "Codex Agent runtime recovery state"
19700
+ inferenceAgentRuntimeStatePath(statePath),
19701
+ "Inference Agent runtime recovery state"
19661
19702
  );
19662
19703
  if (raw === null) return null;
19663
19704
  try {
19664
- return assertCodexAgentRuntimeState(JSON.parse(raw));
19705
+ return assertInferenceAgentRuntimeState(JSON.parse(raw));
19665
19706
  } catch (error48) {
19666
19707
  if (error48 instanceof SyntaxError) {
19667
- throw new Error("Codex Agent runtime recovery state is not valid JSON.");
19708
+ throw new Error("Inference Agent runtime recovery state is not valid JSON.");
19668
19709
  }
19669
19710
  throw error48;
19670
19711
  }
19671
19712
  }
19672
- async function writeCodexAgentRuntimeState(statePath, value) {
19713
+ async function writeInferenceAgentRuntimeState(statePath, value) {
19673
19714
  await writeAtomicInferencePrivateFile(
19674
- codexAgentRuntimeStatePath(statePath),
19675
- `${JSON.stringify(assertCodexAgentRuntimeState(value), null, 2)}
19715
+ inferenceAgentRuntimeStatePath(statePath),
19716
+ `${JSON.stringify(assertInferenceAgentRuntimeState(value), null, 2)}
19676
19717
  `
19677
19718
  );
19678
19719
  }
19679
- async function clearCodexAgentRuntimeState(statePath) {
19720
+ async function clearInferenceAgentRuntimeState(statePath) {
19680
19721
  await clearInferencePrivateFile(
19681
- codexAgentRuntimeStatePath(statePath),
19682
- "Codex Agent runtime recovery state"
19722
+ inferenceAgentRuntimeStatePath(statePath),
19723
+ "Inference Agent runtime recovery state"
19724
+ );
19725
+ }
19726
+ async function readInferenceForegroundAgentControlState(statePath) {
19727
+ const raw = await readInferencePrivateFile(
19728
+ foregroundAgentControlStatePath(statePath),
19729
+ "Foreground Agent control recovery state"
19730
+ );
19731
+ if (raw === null) return null;
19732
+ try {
19733
+ return assertForegroundAgentControlState(JSON.parse(raw));
19734
+ } catch (error48) {
19735
+ if (error48 instanceof SyntaxError) {
19736
+ throw new Error("Foreground Agent control recovery state is not valid JSON.");
19737
+ }
19738
+ throw error48;
19739
+ }
19740
+ }
19741
+ async function writeInferenceForegroundAgentControlState(statePath, value) {
19742
+ await writeAtomicInferencePrivateFile(
19743
+ foregroundAgentControlStatePath(statePath),
19744
+ `${JSON.stringify(assertForegroundAgentControlState(value), null, 2)}
19745
+ `
19746
+ );
19747
+ }
19748
+ async function clearInferenceForegroundAgentControlState(statePath) {
19749
+ await clearInferencePrivateFile(
19750
+ foregroundAgentControlStatePath(statePath),
19751
+ "Foreground Agent control recovery state"
19683
19752
  );
19684
19753
  }
19685
19754
  async function readInferenceAgentAttemptState(statePath) {
@@ -19738,7 +19807,7 @@ async function clearInferenceAgentNextState(statePath) {
19738
19807
  "Agent-driven inference next recovery state"
19739
19808
  );
19740
19809
  }
19741
- var inferenceAgentAttemptStatePath, inferenceAgentNextStatePath, codexAgentRuntimeStatePath, isIsoTimestamp, assertPlainObject, hasExactKeys, assertCodexAgentRuntimeState, assertNextState, assertAttemptState;
19810
+ var inferenceAgentAttemptStatePath, inferenceAgentNextStatePath, inferenceAgentRuntimeStatePath, isIsoTimestamp, assertPlainObject, hasExactKeys, assertInferenceAgentRuntimeState, readCodexAgentRuntimeState, clearCodexAgentRuntimeState, foregroundAgentControlStatePath, assertRuntimeAssignment, assertForegroundAgentControlState, assertNextState, assertAttemptState;
19742
19811
  var init_agent_state = __esm({
19743
19812
  "lib/inference-host/agent-state.ts"() {
19744
19813
  "use strict";
@@ -19746,18 +19815,20 @@ var init_agent_state = __esm({
19746
19815
  init_external_inference_contract();
19747
19816
  inferenceAgentAttemptStatePath = (statePath) => `${statePath}.agent-attempt.json`;
19748
19817
  inferenceAgentNextStatePath = (statePath) => `${statePath}.agent-next.json`;
19749
- codexAgentRuntimeStatePath = (statePath) => `${statePath}.codex-agent-runtime.json`;
19818
+ inferenceAgentRuntimeStatePath = (statePath) => `${statePath}.codex-agent-runtime.json`;
19750
19819
  isIsoTimestamp = (value) => typeof value === "string" && Number.isFinite(Date.parse(value));
19751
19820
  assertPlainObject = (value, message) => {
19752
19821
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(message);
19753
19822
  return value;
19754
19823
  };
19755
19824
  hasExactKeys = (record2, keys) => Object.keys(record2).sort().join("\0") === [...keys].sort().join("\0");
19756
- assertCodexAgentRuntimeState = (value) => {
19757
- const message = "Codex Agent runtime recovery state is invalid.";
19825
+ assertInferenceAgentRuntimeState = (value) => {
19826
+ const message = "Inference Agent runtime recovery state is invalid.";
19758
19827
  const state = assertPlainObject(value, message);
19828
+ const generic = state.schema_version === "vtx_inference_agent_runtime_v3";
19759
19829
  if (!hasExactKeys(state, [
19760
19830
  "schema_version",
19831
+ ...generic ? ["adapter_id"] : [],
19761
19832
  "host_id",
19762
19833
  "assignment",
19763
19834
  "thread",
@@ -19766,9 +19837,13 @@ var init_agent_state = __esm({
19766
19837
  "updated_at"
19767
19838
  ])) throw new Error(message);
19768
19839
  const assignment = assertPlainObject(state.assignment, message);
19769
- if (!["vtx_codex_agent_runtime_v1", "vtx_codex_agent_runtime_v2"].includes(
19840
+ if (![
19841
+ "vtx_codex_agent_runtime_v1",
19842
+ "vtx_codex_agent_runtime_v2",
19843
+ "vtx_inference_agent_runtime_v3"
19844
+ ].includes(
19770
19845
  String(state.schema_version)
19771
- ) || typeof state.host_id !== "string" || !state.host_id || !isIsoTimestamp(state.next_wake_at) || !isIsoTimestamp(state.updated_at) || !hasExactKeys(
19846
+ ) || generic && (typeof state.adapter_id !== "string" || !/^[a-z0-9][a-z0-9._-]{0,63}$/u.test(state.adapter_id)) || typeof state.host_id !== "string" || !state.host_id || !isIsoTimestamp(state.next_wake_at) || !isIsoTimestamp(state.updated_at) || !hasExactKeys(
19772
19847
  assignment,
19773
19848
  [
19774
19849
  "assignment_id",
@@ -19782,10 +19857,10 @@ var init_agent_state = __esm({
19782
19857
  "minimum_wake_seconds",
19783
19858
  "maximum_wake_seconds",
19784
19859
  "lease_expires_at",
19785
- ...state.schema_version === "vtx_codex_agent_runtime_v2" ? ["data_contract"] : []
19860
+ ...state.schema_version !== "vtx_codex_agent_runtime_v1" ? ["data_contract"] : []
19786
19861
  ]
19787
19862
  ) || typeof assignment.assignment_id !== "string" || !assignment.assignment_id || !Number.isSafeInteger(assignment.assignment_generation) || Number(assignment.assignment_generation) < 1 || typeof assignment.model_id !== "string" || !assignment.model_id || typeof assignment.reasoning_effort !== "string" || !assignment.reasoning_effort || !["trader", "assistant"].includes(String(assignment.bot_mode)) || !["server", "client"].includes(String(assignment.execution_mode)) || !Array.isArray(assignment.allowed_symbols) || assignment.allowed_symbols.some((symbol2) => typeof symbol2 !== "string" || !symbol2) || !assignment.output_schema || typeof assignment.output_schema !== "object" || Array.isArray(assignment.output_schema) || !Number.isSafeInteger(assignment.minimum_wake_seconds) || Number(assignment.minimum_wake_seconds) < 1 || !Number.isSafeInteger(assignment.maximum_wake_seconds) || Number(assignment.maximum_wake_seconds) < Number(assignment.minimum_wake_seconds) || !isIsoTimestamp(assignment.lease_expires_at)) throw new Error(message);
19788
- if (state.schema_version === "vtx_codex_agent_runtime_v2") {
19863
+ if (state.schema_version !== "vtx_codex_agent_runtime_v1") {
19789
19864
  if (!Array.isArray(assignment.data_contract) || assignment.data_contract.length === 0) {
19790
19865
  throw new Error(message);
19791
19866
  }
@@ -19824,6 +19899,76 @@ var init_agent_state = __esm({
19824
19899
  }
19825
19900
  return state;
19826
19901
  };
19902
+ readCodexAgentRuntimeState = readInferenceAgentRuntimeState;
19903
+ clearCodexAgentRuntimeState = clearInferenceAgentRuntimeState;
19904
+ foregroundAgentControlStatePath = (statePath) => `${statePath}.foreground-agent-control.json`;
19905
+ assertRuntimeAssignment = (value, message) => {
19906
+ const assignment = assertPlainObject(value, message);
19907
+ if (!hasExactKeys(assignment, [
19908
+ "assignment_id",
19909
+ "assignment_generation",
19910
+ "model_id",
19911
+ "reasoning_effort",
19912
+ "bot_mode",
19913
+ "execution_mode",
19914
+ "allowed_symbols",
19915
+ "output_schema",
19916
+ "data_contract",
19917
+ "minimum_wake_seconds",
19918
+ "maximum_wake_seconds",
19919
+ "lease_expires_at"
19920
+ ]) || typeof assignment.assignment_id !== "string" || !assignment.assignment_id || !Number.isSafeInteger(assignment.assignment_generation) || Number(assignment.assignment_generation) < 1 || typeof assignment.model_id !== "string" || !assignment.model_id || typeof assignment.reasoning_effort !== "string" || !assignment.reasoning_effort || !["trader", "assistant"].includes(String(assignment.bot_mode)) || !["server", "client"].includes(String(assignment.execution_mode)) || !Array.isArray(assignment.allowed_symbols) || assignment.allowed_symbols.some((symbol2) => typeof symbol2 !== "string" || !symbol2) || !assignment.output_schema || typeof assignment.output_schema !== "object" || Array.isArray(assignment.output_schema) || !Array.isArray(assignment.data_contract) || assignment.data_contract.length === 0 || !Number.isSafeInteger(assignment.minimum_wake_seconds) || Number(assignment.minimum_wake_seconds) < 1 || !Number.isSafeInteger(assignment.maximum_wake_seconds) || Number(assignment.maximum_wake_seconds) < Number(assignment.minimum_wake_seconds) || !isIsoTimestamp(assignment.lease_expires_at)) throw new Error(message);
19921
+ const ids = assignment.data_contract.map((value2) => {
19922
+ const descriptor = assertPlainObject(value2, message);
19923
+ if (!hasExactKeys(descriptor, [
19924
+ "id",
19925
+ "title",
19926
+ "description",
19927
+ "input_schema",
19928
+ "input_schema_sha256"
19929
+ ]) || typeof descriptor.id !== "string" || !descriptor.id || typeof descriptor.title !== "string" || !descriptor.title || typeof descriptor.description !== "string" || !descriptor.description || !descriptor.input_schema || typeof descriptor.input_schema !== "object" || Array.isArray(descriptor.input_schema) || typeof descriptor.input_schema_sha256 !== "string" || !/^[0-9a-f]{64}$/u.test(descriptor.input_schema_sha256)) throw new Error(message);
19930
+ return descriptor.id;
19931
+ });
19932
+ if (new Set(ids).size !== ids.length) throw new Error(message);
19933
+ return assignment;
19934
+ };
19935
+ assertForegroundAgentControlState = (value) => {
19936
+ const message = "Foreground Agent control recovery state is invalid.";
19937
+ const state = assertPlainObject(value, message);
19938
+ if (!hasExactKeys(state, [
19939
+ "schema_version",
19940
+ "host_id",
19941
+ "assignment",
19942
+ "pending_next",
19943
+ "pending_decision",
19944
+ "next_wake_at",
19945
+ "updated_at"
19946
+ ]) || state.schema_version !== "vtx_foreground_agent_control_v1" || typeof state.host_id !== "string" || !state.host_id || state.next_wake_at !== null && !isIsoTimestamp(state.next_wake_at) || !isIsoTimestamp(state.updated_at)) throw new Error(message);
19947
+ if (state.assignment !== null) assertRuntimeAssignment(state.assignment, message);
19948
+ if (state.pending_next !== null) {
19949
+ const pending = assertPlainObject(state.pending_next, message);
19950
+ if (!hasExactKeys(pending, ["operation_id", "requested_at"]) || typeof pending.operation_id !== "string" || !pending.operation_id || !isIsoTimestamp(pending.requested_at)) throw new Error(message);
19951
+ }
19952
+ if (state.pending_decision !== null) {
19953
+ if (state.assignment === null) throw new Error(message);
19954
+ const pending = assertPlainObject(state.pending_decision, message);
19955
+ if (!hasExactKeys(pending, [
19956
+ "request",
19957
+ "first_transmit_at",
19958
+ "last_status_check_at"
19959
+ ])) throw new Error(message);
19960
+ const request = assertPlainObject(pending.request, message);
19961
+ if (!hasExactKeys(request, [
19962
+ "assignment_id",
19963
+ "assignment_generation",
19964
+ "operation_id",
19965
+ "candidate",
19966
+ "observed_at",
19967
+ "provenance"
19968
+ ]) || request.assignment_id !== state.assignment.assignment_id || request.assignment_generation !== state.assignment.assignment_generation || typeof request.operation_id !== "string" || !request.operation_id || !request.candidate || typeof request.candidate !== "object" || Array.isArray(request.candidate) || !isIsoTimestamp(request.observed_at) || !request.provenance || typeof request.provenance !== "object" || Array.isArray(request.provenance) || pending.first_transmit_at !== null && !isIsoTimestamp(pending.first_transmit_at) || pending.last_status_check_at !== null && !isIsoTimestamp(pending.last_status_check_at)) throw new Error(message);
19969
+ }
19970
+ return state;
19971
+ };
19827
19972
  assertNextState = (value) => {
19828
19973
  if (!value || typeof value !== "object" || Array.isArray(value)) {
19829
19974
  throw new Error("Agent-driven inference next recovery state is invalid.");
@@ -23978,15 +24123,17 @@ $items = @(Get-CimInstance Win32_Process | Where-Object { $_.Name -in @('node.ex
23978
24123
  });
23979
24124
 
23980
24125
  // lib/inference-host/copilot-adapter.ts
24126
+ import { randomUUID } from "node:crypto";
23981
24127
  import { mkdtemp as mkdtemp2, rm as rm4 } from "node:fs/promises";
23982
24128
  import { createRequire as createRequire2 } from "node:module";
23983
24129
  import { tmpdir as tmpdir3 } from "node:os";
23984
24130
  import { join as join5 } from "node:path";
23985
24131
  import {
23986
24132
  CopilotClient,
23987
- RuntimeConnection
24133
+ RuntimeConnection,
24134
+ defineTool
23988
24135
  } from "@github/copilot-sdk";
23989
- var COPILOT_SDK_VERSION, MAX_RESULT_BYTES, resolveRuntimePackage, copilotRuntimePackageCandidates, resolvePinnedCopilotCliPath, createPrivateWorkspace, cleanCopilotEnvironment, defaultClient, modelCapabilities, requiredUsageInteger, optionalUsageInteger, CopilotSubscriptionAdapter;
24136
+ var COPILOT_SDK_VERSION, MAX_RESULT_BYTES, resolveRuntimePackage, copilotRuntimePackageCandidates, resolvePinnedCopilotCliPath, createPrivateWorkspace, cleanCopilotEnvironment, defaultClient, modelCapabilities, requiredUsageInteger, optionalUsageInteger, copilotAgentToolDefinitions, CopilotSubscriptionAdapter;
23990
24137
  var init_copilot_adapter = __esm({
23991
24138
  "lib/inference-host/copilot-adapter.ts"() {
23992
24139
  "use strict";
@@ -24082,9 +24229,66 @@ var init_copilot_adapter = __esm({
24082
24229
  }
24083
24230
  return Number(value);
24084
24231
  };
24232
+ copilotAgentToolDefinitions = (input, evidence) => {
24233
+ const execute = async (tool, argumentsValue) => {
24234
+ const argumentsRecord = argumentsValue && typeof argumentsValue === "object" && !Array.isArray(argumentsValue) ? argumentsValue : {};
24235
+ const callId = randomUUID();
24236
+ const result2 = await input.executeTool({
24237
+ callId,
24238
+ tool,
24239
+ arguments: argumentsRecord
24240
+ });
24241
+ evidence.push({ callId, tool, arguments: argumentsRecord, success: result2.success });
24242
+ return result2.success ? result2.value : { error: result2.value };
24243
+ };
24244
+ return [
24245
+ defineTool("vtx_get_data", {
24246
+ description: "Request assignment-scoped VTX data using one exact canonical capability schema.",
24247
+ parameters: {
24248
+ oneOf: input.dataContract.map((descriptor) => ({
24249
+ type: "object",
24250
+ additionalProperties: false,
24251
+ required: ["capability", "arguments"],
24252
+ description: descriptor.description,
24253
+ properties: {
24254
+ capability: { type: "string", const: descriptor.id, title: descriptor.title },
24255
+ arguments: descriptor.input_schema
24256
+ }
24257
+ }))
24258
+ },
24259
+ skipPermission: true,
24260
+ handler: async (args) => await execute("vtx_get_data", args)
24261
+ }),
24262
+ defineTool("vtx_submit_decision", {
24263
+ description: "Submit one VTX structured trading decision candidate.",
24264
+ parameters: {
24265
+ type: "object",
24266
+ additionalProperties: false,
24267
+ required: ["candidate"],
24268
+ properties: { candidate: input.decisionSchema }
24269
+ },
24270
+ skipPermission: true,
24271
+ handler: async (args) => await execute("vtx_submit_decision", args)
24272
+ }),
24273
+ defineTool("vtx_decision_status", {
24274
+ description: "Resolve the durable status of a previously attempted decision operation.",
24275
+ parameters: {
24276
+ type: "object",
24277
+ additionalProperties: false,
24278
+ required: ["operation_id"],
24279
+ properties: { operation_id: { type: "string", minLength: 1 } }
24280
+ },
24281
+ skipPermission: true,
24282
+ handler: async (args) => await execute("vtx_decision_status", args)
24283
+ })
24284
+ ];
24285
+ };
24085
24286
  CopilotSubscriptionAdapter = class {
24086
24287
  constructor(dependencies = {}) {
24087
24288
  this.inFlight = /* @__PURE__ */ new Map();
24289
+ this.agentConnection = null;
24290
+ this.agentWorkspaceCleanups = /* @__PURE__ */ new Map();
24291
+ this.closing = false;
24088
24292
  this.dependencies = dependencies;
24089
24293
  }
24090
24294
  async preflight(signal) {
@@ -24296,6 +24500,224 @@ ${input.outputSchemaJson}`
24296
24500
  await workspace.cleanup();
24297
24501
  }
24298
24502
  }
24503
+ async runTurn(input) {
24504
+ if (this.closing) {
24505
+ throw new CodexAppServerError({
24506
+ message: "Copilot Agent adapter is closing.",
24507
+ category: "transport",
24508
+ code: "transport_closed",
24509
+ retryable: true
24510
+ });
24511
+ }
24512
+ input.signal?.throwIfAborted();
24513
+ if (Date.now() >= input.deadlineAtMs || input.dataContract.length === 0) {
24514
+ throw new CodexAppServerError({
24515
+ message: "Copilot Agent turn input is invalid or expired.",
24516
+ category: Date.now() >= input.deadlineAtMs ? "timeout" : "schema",
24517
+ code: Date.now() >= input.deadlineAtMs ? "deadline_exceeded" : "invalid_agent_turn_input",
24518
+ retryable: false
24519
+ });
24520
+ }
24521
+ const startedAt = (this.dependencies.now ?? Date.now)();
24522
+ const ownedWorkspace = input.durableThread ? null : await (this.dependencies.createAgentWorkspace ?? this.dependencies.createWorkspace ?? createPrivateWorkspace)();
24523
+ const workspacePath = input.durableThread?.threadPath ?? ownedWorkspace.path;
24524
+ if (ownedWorkspace) this.agentWorkspaceCleanups.set(workspacePath, ownedWorkspace.cleanup);
24525
+ const client = (this.dependencies.createClient ?? defaultClient)(workspacePath);
24526
+ let session = null;
24527
+ let durableCheckpointed = input.durableThread !== null;
24528
+ let dispatchEntered = false;
24529
+ const toolEvidence = [];
24530
+ try {
24531
+ await client.start();
24532
+ const tools = copilotAgentToolDefinitions(input, toolEvidence);
24533
+ const sessionConfig = {
24534
+ clientName: "@vtxmacro/cli durable Copilot Agent host",
24535
+ model: input.requestedModel,
24536
+ ...input.requestedReasoningEffort === "none" ? {} : { reasoningEffort: input.requestedReasoningEffort },
24537
+ systemMessage: {
24538
+ mode: "replace",
24539
+ content: `${input.systemPrompt}
24540
+
24541
+ Return only one JSON value matching this JSON Schema exactly:
24542
+ ${JSON.stringify(input.outputSchema)}`
24543
+ },
24544
+ tools,
24545
+ availableTools: tools.map((tool) => tool.name),
24546
+ enableConfigDiscovery: false,
24547
+ streaming: true,
24548
+ workingDirectory: workspacePath,
24549
+ infiniteSessions: { enabled: true }
24550
+ };
24551
+ session = input.durableThread ? await client.resumeSession(input.durableThread.threadId, sessionConfig) : await client.createSession(sessionConfig);
24552
+ this.agentConnection = {
24553
+ client,
24554
+ session,
24555
+ workspacePath,
24556
+ cleanup: ownedWorkspace?.cleanup ?? null
24557
+ };
24558
+ const thread = {
24559
+ threadId: session.sessionId,
24560
+ threadPath: workspacePath,
24561
+ effectiveModel: input.requestedModel,
24562
+ effectiveReasoningEffort: input.requestedReasoningEffort
24563
+ };
24564
+ if (input.onThreadReady) {
24565
+ await input.onThreadReady(thread);
24566
+ durableCheckpointed = true;
24567
+ }
24568
+ const usageEvents = [];
24569
+ session.on((event) => {
24570
+ if (event.type === "assistant.usage" && !event.agentId) usageEvents.push(event);
24571
+ });
24572
+ const onAbort = () => {
24573
+ void session?.abort().catch(() => void 0);
24574
+ };
24575
+ input.signal?.addEventListener("abort", onAbort, { once: true });
24576
+ dispatchEntered = true;
24577
+ let response;
24578
+ try {
24579
+ response = await session.sendAndWait(
24580
+ { prompt: input.userPrompt },
24581
+ Math.max(1, input.deadlineAtMs - Date.now())
24582
+ );
24583
+ } finally {
24584
+ input.signal?.removeEventListener("abort", onAbort);
24585
+ }
24586
+ if (!response?.data.content || Buffer.byteLength(response.data.content, "utf8") > MAX_RESULT_BYTES) {
24587
+ throw new Error("copilot_agent_invalid_result");
24588
+ }
24589
+ const observedModels = /* @__PURE__ */ new Set();
24590
+ const observedEfforts = /* @__PURE__ */ new Set();
24591
+ let inputTokens = 0;
24592
+ let cachedInputTokens = 0;
24593
+ let outputTokens = 0;
24594
+ let reasoningOutputTokens = 0;
24595
+ let cacheWriteInputTokens = 0;
24596
+ let cacheWriteSupported = false;
24597
+ let timeToFirstTokenMs = null;
24598
+ let providerCallId = null;
24599
+ for (const event of usageEvents) {
24600
+ if (event.type !== "assistant.usage") continue;
24601
+ observedModels.add(event.data.model);
24602
+ if (event.data.reasoningEffort) observedEfforts.add(event.data.reasoningEffort);
24603
+ inputTokens += requiredUsageInteger(event.data.inputTokens, "input_tokens");
24604
+ cachedInputTokens += optionalUsageInteger(event.data.cacheReadTokens, "cache_read_tokens");
24605
+ outputTokens += requiredUsageInteger(event.data.outputTokens, "output_tokens");
24606
+ reasoningOutputTokens += optionalUsageInteger(event.data.reasoningTokens, "reasoning_tokens");
24607
+ if (event.data.cacheWriteTokens !== void 0) {
24608
+ cacheWriteSupported = true;
24609
+ cacheWriteInputTokens += optionalUsageInteger(event.data.cacheWriteTokens, "cache_write_tokens");
24610
+ }
24611
+ if (timeToFirstTokenMs === null && Number.isSafeInteger(event.data.timeToFirstTokenMs)) {
24612
+ timeToFirstTokenMs = Number(event.data.timeToFirstTokenMs);
24613
+ }
24614
+ providerCallId = event.data.providerCallId ?? event.data.apiCallId ?? providerCallId;
24615
+ }
24616
+ if (usageEvents.length === 0) throw new Error("copilot_agent_usage_receipt_missing");
24617
+ if (response.data.model) observedModels.add(response.data.model);
24618
+ if (observedModels.size !== 1 || !observedModels.has(input.requestedModel)) {
24619
+ throw new Error("copilot_agent_effective_model_mismatch");
24620
+ }
24621
+ const effectiveEffort = input.requestedReasoningEffort === "none" ? observedEfforts.size === 0 ? "none" : observedEfforts.size === 1 ? [...observedEfforts][0] : null : observedEfforts.size === 1 ? [...observedEfforts][0] : null;
24622
+ if (effectiveEffort !== input.requestedReasoningEffort) {
24623
+ throw new Error("copilot_agent_effective_effort_mismatch");
24624
+ }
24625
+ const usage = {
24626
+ inputTokens,
24627
+ cachedInputTokens: Math.min(cachedInputTokens, inputTokens),
24628
+ outputTokens,
24629
+ reasoningOutputTokens: Math.min(reasoningOutputTokens, outputTokens),
24630
+ totalTokens: inputTokens + outputTokens,
24631
+ cacheWriteInputTokens: cacheWriteSupported ? cacheWriteInputTokens : null,
24632
+ cacheWriteSupported
24633
+ };
24634
+ return {
24635
+ thread,
24636
+ turn: {
24637
+ text: response.data.content,
24638
+ reasoningContent: response.data.reasoningText ?? null,
24639
+ reasoningSummary: null,
24640
+ requestedModel: input.requestedModel,
24641
+ effectiveModel: input.requestedModel,
24642
+ requestedReasoningEffort: input.requestedReasoningEffort,
24643
+ effectiveReasoningEffort: effectiveEffort,
24644
+ adapterRequestId: providerCallId ?? response.data.requestId ?? response.data.messageId,
24645
+ adapterResponseId: response.data.serviceRequestId ?? response.data.messageId,
24646
+ usage,
24647
+ latencyMs: Math.max(0, (this.dependencies.now ?? Date.now)() - startedAt),
24648
+ timeToFirstTokenMs,
24649
+ terminalStatus: "completed",
24650
+ toolCalls: toolEvidence,
24651
+ webSearches: []
24652
+ }
24653
+ };
24654
+ } catch (error48) {
24655
+ if (error48 instanceof CodexAppServerError) throw error48;
24656
+ const cancelled = input.signal?.aborted === true;
24657
+ const deadline = Date.now() >= input.deadlineAtMs;
24658
+ if (dispatchEntered) await session?.abort().catch(() => void 0);
24659
+ if (session && !durableCheckpointed) {
24660
+ const abandonedSession = session;
24661
+ session = null;
24662
+ if (this.agentConnection?.session === abandonedSession) this.agentConnection = null;
24663
+ await abandonedSession.disconnect().catch(() => void 0);
24664
+ await client.deleteSession(abandonedSession.sessionId).catch(() => void 0);
24665
+ const cleanup = this.agentWorkspaceCleanups.get(workspacePath);
24666
+ if (cleanup) {
24667
+ await cleanup().catch(() => void 0);
24668
+ this.agentWorkspaceCleanups.delete(workspacePath);
24669
+ }
24670
+ }
24671
+ throw new CodexAppServerError({
24672
+ message: cancelled ? "Copilot Agent turn was cancelled." : deadline ? "Copilot Agent turn exceeded its deadline." : error48 instanceof Error ? error48.message : "Copilot Agent adapter failed.",
24673
+ category: cancelled ? "cancelled" : deadline ? "timeout" : "adapter",
24674
+ code: cancelled ? "cancelled" : deadline ? "deadline_exceeded" : "copilot_agent_adapter_failure",
24675
+ retryable: false,
24676
+ dispatchOutcome: dispatchEntered ? "confirmed_dispatched" : "not_dispatched",
24677
+ cause: error48
24678
+ });
24679
+ } finally {
24680
+ await session?.disconnect().catch(() => void 0);
24681
+ await client.stop().catch(async () => {
24682
+ await client.forceStop();
24683
+ });
24684
+ if (this.agentConnection?.session === session) this.agentConnection = null;
24685
+ }
24686
+ }
24687
+ async releaseThread(thread) {
24688
+ const active = this.agentConnection;
24689
+ if (active?.session.sessionId === thread.threadId) {
24690
+ await active.session.disconnect().catch(() => void 0);
24691
+ await active.client.stop().catch(async () => {
24692
+ await active.client.forceStop();
24693
+ });
24694
+ this.agentConnection = null;
24695
+ }
24696
+ const client = (this.dependencies.createClient ?? defaultClient)(thread.threadPath);
24697
+ await client.start();
24698
+ try {
24699
+ await client.deleteSession(thread.threadId);
24700
+ } finally {
24701
+ await client.stop().catch(async () => {
24702
+ await client.forceStop();
24703
+ });
24704
+ }
24705
+ const cleanup = this.agentWorkspaceCleanups.get(thread.threadPath);
24706
+ if (cleanup) {
24707
+ await cleanup();
24708
+ this.agentWorkspaceCleanups.delete(thread.threadPath);
24709
+ }
24710
+ }
24711
+ async close() {
24712
+ this.closing = true;
24713
+ const active = this.agentConnection;
24714
+ this.agentConnection = null;
24715
+ if (!active) return;
24716
+ await active.session.disconnect().catch(() => void 0);
24717
+ await active.client.stop().catch(async () => {
24718
+ await active.client.forceStop();
24719
+ });
24720
+ }
24299
24721
  };
24300
24722
  }
24301
24723
  });
@@ -30873,7 +31295,7 @@ var require_ajv = __commonJS({
30873
31295
  });
30874
31296
 
30875
31297
  // lib/inference-host/runner.ts
30876
- import { createHash as createHash6, randomUUID } from "node:crypto";
31298
+ import { createHash as createHash6, randomUUID as randomUUID2 } from "node:crypto";
30877
31299
  function createDefaultInferenceHostRunnerDependencies(options) {
30878
31300
  const fetchImpl = options.fetchImpl ?? fetch;
30879
31301
  return {
@@ -30908,7 +31330,7 @@ function createDefaultInferenceHostRunnerDependencies(options) {
30908
31330
  envelopePublicKey: options.envelopePublicKey
30909
31331
  };
30910
31332
  }
30911
- 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, settlesWithin, 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, createCodexAgentControlClient, CODEX_AGENT_SYSTEM_PROMPT, CODEX_AGENT_WAKE_SCHEMA, parseCodexAgentWake, CodexAgentRuntime;
31333
+ 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, settlesWithin, 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, createInferenceAgentControlClient, INFERENCE_AGENT_SYSTEM_PROMPT, INFERENCE_AGENT_WAKE_SCHEMA, parseInferenceAgentWake, InferenceAgentRuntime;
30912
31334
  var init_runner = __esm({
30913
31335
  "lib/inference-host/runner.ts"() {
30914
31336
  "use strict";
@@ -31292,7 +31714,7 @@ var init_runner = __esm({
31292
31714
  adapterId,
31293
31715
  options.structuredOutput ?? adapterId === "codex",
31294
31716
  options.sameAttemptRecovery ?? adapterId === "codex",
31295
- options.agentRuntime && adapterId === "codex" ? ["provider", "agent"] : ["provider"]
31717
+ options.agentRuntime ? ["provider", "agent"] : ["provider"]
31296
31718
  ),
31297
31719
  maxConcurrency: options.maxConcurrency === null || options.maxConcurrency === void 0 ? null : finitePositiveOption(options.maxConcurrency, 1, "Maximum concurrency"),
31298
31720
  advertisementTtlMs,
@@ -31747,10 +32169,11 @@ var init_runner = __esm({
31747
32169
  const agentRuntimeSettings = settings.agentRuntime;
31748
32170
  agentLoop = (async () => {
31749
32171
  while (!agentAbort.signal.aborted) {
31750
- const agentRuntime = new CodexAgentRuntime({
32172
+ const agentRuntime = new InferenceAgentRuntime({
32173
+ adapterId: settings.adapterId,
31751
32174
  hostId: localState.host_id,
31752
32175
  statePath: agentRuntimeSettings.statePath,
31753
- controlClient: createCodexAgentControlClient(mcp),
32176
+ controlClient: createInferenceAgentControlClient(mcp),
31754
32177
  adapter: agentRuntimeSettings.adapter
31755
32178
  });
31756
32179
  try {
@@ -33088,7 +33511,7 @@ var init_runner = __esm({
33088
33511
  }
33089
33512
  }
33090
33513
  };
33091
- createCodexAgentControlClient = (mcp) => ({
33514
+ createInferenceAgentControlClient = (mcp) => ({
33092
33515
  nextAssignment: async (request, options) => {
33093
33516
  const result2 = await mcp.callTool("inference.agent.assignment.next", {
33094
33517
  ...request,
@@ -33131,9 +33554,9 @@ var init_runner = __esm({
33131
33554
  await mcp.callTool("inference.agent.assignment.release", request, options);
33132
33555
  }
33133
33556
  });
33134
- CODEX_AGENT_SYSTEM_PROMPT = `You autonomously control one running VTX bot.
33557
+ INFERENCE_AGENT_SYSTEM_PROMPT = `You autonomously control one running VTX bot.
33135
33558
  VTX supplies no trading prompt or prepared market context. At your own cadence, request zero, some, or all assignment-scoped data with vtx_get_data and independently use web search when useful. Submit trading instructions only through vtx_submit_decision, using the assignment's exact decision schema. VTX remains responsible for validating and executing the same structured decision used by normal Server and Client modes. You have no shell, filesystem-write, app, plugin, browser-control, or subagent authority.`;
33136
- CODEX_AGENT_WAKE_SCHEMA = {
33559
+ INFERENCE_AGENT_WAKE_SCHEMA = {
33137
33560
  type: "object",
33138
33561
  additionalProperties: false,
33139
33562
  required: ["next_wake_seconds", "summary"],
@@ -33142,29 +33565,29 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33142
33565
  summary: { type: "string", minLength: 1, maxLength: 2e3 }
33143
33566
  }
33144
33567
  };
33145
- parseCodexAgentWake = (text, assignment) => {
33568
+ parseInferenceAgentWake = (text, assignment) => {
33146
33569
  let value;
33147
33570
  try {
33148
33571
  value = JSON.parse(text);
33149
33572
  } catch {
33150
33573
  throw new InferenceHostRunnerError(
33151
33574
  "invalid_agent_wake",
33152
- "Codex Agent returned invalid wake JSON."
33575
+ "Inference Agent returned invalid wake JSON."
33153
33576
  );
33154
33577
  }
33155
33578
  if (!value || typeof value !== "object" || Array.isArray(value)) {
33156
- throw new InferenceHostRunnerError("invalid_agent_wake", "Codex Agent wake is invalid.");
33579
+ throw new InferenceHostRunnerError("invalid_agent_wake", "Inference Agent wake is invalid.");
33157
33580
  }
33158
33581
  const seconds = value.next_wake_seconds;
33159
33582
  if (!Number.isSafeInteger(seconds) || Number(seconds) < 1) {
33160
- throw new InferenceHostRunnerError("invalid_agent_wake", "Codex Agent wake is invalid.");
33583
+ throw new InferenceHostRunnerError("invalid_agent_wake", "Inference Agent wake is invalid.");
33161
33584
  }
33162
33585
  return Math.max(
33163
33586
  assignment.minimum_wake_seconds,
33164
33587
  Math.min(assignment.maximum_wake_seconds, Number(seconds))
33165
33588
  );
33166
33589
  };
33167
- CodexAgentRuntime = class {
33590
+ InferenceAgentRuntime = class {
33168
33591
  constructor(options) {
33169
33592
  this.options = options;
33170
33593
  this.stopped = false;
@@ -33198,29 +33621,55 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33198
33621
  }
33199
33622
  async runOnce(signal) {
33200
33623
  const nowIso = () => new Date(this.now()).toISOString();
33201
- const recoveredState = await readCodexAgentRuntimeState(this.options.statePath);
33624
+ const recoveredState = await readInferenceAgentRuntimeState(this.options.statePath);
33202
33625
  if (recoveredState && recoveredState.host_id !== this.options.hostId) {
33203
33626
  throw new InferenceHostRunnerError(
33204
33627
  "agent_recovery_scope_mismatch",
33205
- "Codex Agent recovery state belongs to another host."
33628
+ "Inference Agent recovery state belongs to another host."
33206
33629
  );
33207
33630
  }
33208
33631
  let state;
33209
33632
  if (recoveredState?.schema_version === "vtx_codex_agent_runtime_v1") {
33633
+ if (this.options.adapterId !== "codex") {
33634
+ throw new InferenceHostRunnerError(
33635
+ "agent_recovery_adapter_mismatch",
33636
+ "Legacy Codex Agent recovery state cannot be opened by another adapter."
33637
+ );
33638
+ }
33210
33639
  state = await this.upgradeLegacyRuntimeState(recoveredState, signal);
33211
33640
  if (!state) return this.now() + (this.options.idlePollMs ?? 5e3);
33641
+ } else if (recoveredState?.schema_version === "vtx_codex_agent_runtime_v2") {
33642
+ if (this.options.adapterId !== "codex") {
33643
+ throw new InferenceHostRunnerError(
33644
+ "agent_recovery_adapter_mismatch",
33645
+ "Legacy Codex Agent recovery state cannot be opened by another adapter."
33646
+ );
33647
+ }
33648
+ state = {
33649
+ ...recoveredState,
33650
+ schema_version: "vtx_inference_agent_runtime_v3",
33651
+ adapter_id: "codex"
33652
+ };
33653
+ await writeInferenceAgentRuntimeState(this.options.statePath, state);
33212
33654
  } else {
33213
33655
  state = recoveredState ?? null;
33656
+ if (state && state.adapter_id !== this.options.adapterId) {
33657
+ throw new InferenceHostRunnerError(
33658
+ "agent_recovery_adapter_mismatch",
33659
+ "Inference Agent recovery state belongs to another adapter."
33660
+ );
33661
+ }
33214
33662
  }
33215
33663
  if (!state) {
33216
33664
  const assignment2 = await this.options.controlClient.nextAssignment({
33217
- operation_id: randomUUID(),
33665
+ operation_id: randomUUID2(),
33218
33666
  host_id: this.options.hostId,
33219
33667
  requested_at: nowIso()
33220
33668
  }, { signal });
33221
33669
  if (!assignment2) return this.now() + (this.options.idlePollMs ?? 5e3);
33222
33670
  state = {
33223
- schema_version: "vtx_codex_agent_runtime_v2",
33671
+ schema_version: "vtx_inference_agent_runtime_v3",
33672
+ adapter_id: this.options.adapterId,
33224
33673
  host_id: this.options.hostId,
33225
33674
  assignment: assignment2,
33226
33675
  thread: null,
@@ -33228,7 +33677,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33228
33677
  pending_decision: null,
33229
33678
  updated_at: nowIso()
33230
33679
  };
33231
- await writeCodexAgentRuntimeState(this.options.statePath, state);
33680
+ await writeInferenceAgentRuntimeState(this.options.statePath, state);
33232
33681
  } else {
33233
33682
  const persistedWakeAtMs = Date.parse(state.next_wake_at);
33234
33683
  if (persistedWakeAtMs > this.now()) {
@@ -33236,8 +33685,8 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33236
33685
  if (wakeOutcome !== "ready") {
33237
33686
  return this.now() + (this.options.idlePollMs ?? 5e3);
33238
33687
  }
33239
- const rereadState = await readCodexAgentRuntimeState(this.options.statePath);
33240
- if (rereadState?.schema_version !== "vtx_codex_agent_runtime_v2") {
33688
+ const rereadState = await readInferenceAgentRuntimeState(this.options.statePath);
33689
+ if (rereadState?.schema_version !== "vtx_inference_agent_runtime_v3" || rereadState.adapter_id !== this.options.adapterId) {
33241
33690
  return this.now() + (this.options.idlePollMs ?? 5e3);
33242
33691
  }
33243
33692
  state = rereadState;
@@ -33246,7 +33695,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33246
33695
  state = await this.resolvePendingDecision(state, signal);
33247
33696
  let assignment = state.assignment;
33248
33697
  const preTurnHeartbeat = await this.options.controlClient.heartbeat({
33249
- operation_id: randomUUID(),
33698
+ operation_id: randomUUID2(),
33250
33699
  host_id: this.options.hostId,
33251
33700
  assignment_id: assignment.assignment_id,
33252
33701
  assignment_generation: assignment.assignment_generation,
@@ -33261,7 +33710,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33261
33710
  lease_expires_at: preTurnHeartbeat.lease_expires_at
33262
33711
  };
33263
33712
  state = { ...state, assignment, updated_at: nowIso() };
33264
- await writeCodexAgentRuntimeState(this.options.statePath, state);
33713
+ await writeInferenceAgentRuntimeState(this.options.statePath, state);
33265
33714
  const turnAbort = new AbortController();
33266
33715
  const relayAbort = () => turnAbort.abort();
33267
33716
  signal?.addEventListener("abort", relayAbort, { once: true });
@@ -33271,7 +33720,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33271
33720
  const heartbeatTask = (async () => {
33272
33721
  while (!heartbeatStopped && !turnAbort.signal.aborted) {
33273
33722
  const heartbeat = await this.options.controlClient.heartbeat({
33274
- operation_id: randomUUID(),
33723
+ operation_id: randomUUID2(),
33275
33724
  host_id: this.options.hostId,
33276
33725
  assignment_id: assignment.assignment_id,
33277
33726
  assignment_generation: assignment.assignment_generation,
@@ -33295,7 +33744,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33295
33744
  const deadlineAtMs = this.now() + (this.options.turnTimeoutMs ?? 10 * 6e4);
33296
33745
  const result2 = await this.options.adapter.runTurn({
33297
33746
  durableThread: state.thread,
33298
- systemPrompt: CODEX_AGENT_SYSTEM_PROMPT,
33747
+ systemPrompt: INFERENCE_AGENT_SYSTEM_PROMPT,
33299
33748
  userPrompt: JSON.stringify({
33300
33749
  assignment_id: assignment.assignment_id,
33301
33750
  assignment_generation: assignment.assignment_generation,
@@ -33309,7 +33758,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33309
33758
  maximum: assignment.maximum_wake_seconds
33310
33759
  }
33311
33760
  }),
33312
- outputSchema: CODEX_AGENT_WAKE_SCHEMA,
33761
+ outputSchema: INFERENCE_AGENT_WAKE_SCHEMA,
33313
33762
  dataContract: assignment.data_contract,
33314
33763
  decisionSchema: assignment.output_schema,
33315
33764
  requestedModel: assignment.model_id,
@@ -33318,7 +33767,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33318
33767
  signal: turnAbort.signal,
33319
33768
  onThreadReady: async (thread) => {
33320
33769
  state = { ...state, thread, updated_at: nowIso() };
33321
- await writeCodexAgentRuntimeState(this.options.statePath, state);
33770
+ await writeInferenceAgentRuntimeState(this.options.statePath, state);
33322
33771
  },
33323
33772
  executeTool: async (call) => {
33324
33773
  if (call.tool === "vtx_get_data") {
@@ -33328,7 +33777,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33328
33777
  return { success: false, value: { error: "invalid_data_request" } };
33329
33778
  }
33330
33779
  const value = await this.options.controlClient.dataCall({
33331
- operation_id: randomUUID(),
33780
+ operation_id: randomUUID2(),
33332
33781
  host_id: this.options.hostId,
33333
33782
  assignment_id: assignment.assignment_id,
33334
33783
  assignment_generation: assignment.assignment_generation,
@@ -33352,12 +33801,12 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33352
33801
  return { success: false, value: { error: "decision_outcome_unresolved" } };
33353
33802
  }
33354
33803
  const pending = {
33355
- operation_id: randomUUID(),
33804
+ operation_id: randomUUID2(),
33356
33805
  candidate,
33357
33806
  observed_at: nowIso(),
33358
33807
  provenance: {
33359
- source: "codex_agent",
33360
- codex_thread_id: liveThread.threadId,
33808
+ source: "external_agent",
33809
+ agent_run_id: liveThread.threadId,
33361
33810
  requested_model: assignment.model_id,
33362
33811
  effective_model: liveThread.effectiveModel,
33363
33812
  requested_reasoning_effort: assignment.reasoning_effort,
@@ -33367,13 +33816,13 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33367
33816
  last_status_check_at: null
33368
33817
  };
33369
33818
  state = { ...state, pending_decision: pending, updated_at: nowIso() };
33370
- await writeCodexAgentRuntimeState(this.options.statePath, state);
33819
+ await writeInferenceAgentRuntimeState(this.options.statePath, state);
33371
33820
  state = {
33372
33821
  ...state,
33373
33822
  pending_decision: { ...pending, first_transmit_at: nowIso() },
33374
33823
  updated_at: nowIso()
33375
33824
  };
33376
- await writeCodexAgentRuntimeState(this.options.statePath, state);
33825
+ await writeInferenceAgentRuntimeState(this.options.statePath, state);
33377
33826
  let submitStatus;
33378
33827
  try {
33379
33828
  submitStatus = await this.options.controlClient.submitDecision({
@@ -33390,7 +33839,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33390
33839
  }
33391
33840
  if (submitStatus.status === "applied" || submitStatus.status === "not_applied") {
33392
33841
  state = { ...state, pending_decision: null, updated_at: nowIso() };
33393
- await writeCodexAgentRuntimeState(this.options.statePath, state);
33842
+ await writeInferenceAgentRuntimeState(this.options.statePath, state);
33394
33843
  }
33395
33844
  return {
33396
33845
  success: submitStatus.status === "applied",
@@ -33414,7 +33863,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33414
33863
  pending_decision: null,
33415
33864
  updated_at: nowIso()
33416
33865
  };
33417
- await writeCodexAgentRuntimeState(this.options.statePath, state);
33866
+ await writeInferenceAgentRuntimeState(this.options.statePath, state);
33418
33867
  }
33419
33868
  return {
33420
33869
  success: status.status === "applied" || status.status === "not_applied",
@@ -33422,11 +33871,11 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33422
33871
  };
33423
33872
  }
33424
33873
  });
33425
- const wakeSeconds = parseCodexAgentWake(result2.turn.text, assignment);
33874
+ const wakeSeconds = parseInferenceAgentWake(result2.turn.text, assignment);
33426
33875
  const nextWakeAtMs = this.now() + wakeSeconds * 1e3;
33427
33876
  const scheduledWakeAt = new Date(nextWakeAtMs).toISOString();
33428
33877
  const wakeHeartbeat = await this.options.controlClient.heartbeat({
33429
- operation_id: randomUUID(),
33878
+ operation_id: randomUUID2(),
33430
33879
  host_id: this.options.hostId,
33431
33880
  assignment_id: assignment.assignment_id,
33432
33881
  assignment_generation: assignment.assignment_generation,
@@ -33436,7 +33885,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33436
33885
  if (wakeHeartbeat.directive === "cancel") {
33437
33886
  if (state.pending_decision) return this.now() + (this.options.idlePollMs ?? 5e3);
33438
33887
  await this.options.adapter.releaseThread(result2.thread).catch(() => void 0);
33439
- await clearCodexAgentRuntimeState(this.options.statePath);
33888
+ await clearInferenceAgentRuntimeState(this.options.statePath);
33440
33889
  return this.now() + (this.options.idlePollMs ?? 5e3);
33441
33890
  }
33442
33891
  latestLeaseExpiry = wakeHeartbeat.lease_expires_at;
@@ -33447,7 +33896,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33447
33896
  next_wake_at: scheduledWakeAt,
33448
33897
  updated_at: nowIso()
33449
33898
  };
33450
- await writeCodexAgentRuntimeState(this.options.statePath, state);
33899
+ await writeInferenceAgentRuntimeState(this.options.statePath, state);
33451
33900
  return nextWakeAtMs;
33452
33901
  } catch (error48) {
33453
33902
  if (!cancelled) throw error48;
@@ -33466,7 +33915,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33466
33915
  if (state.thread) {
33467
33916
  await this.options.adapter.releaseThread(state.thread).catch(() => void 0);
33468
33917
  }
33469
- await clearCodexAgentRuntimeState(this.options.statePath);
33918
+ await clearInferenceAgentRuntimeState(this.options.statePath);
33470
33919
  return null;
33471
33920
  }
33472
33921
  async resolveLegacyPendingDecision(state, signal) {
@@ -33478,7 +33927,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33478
33927
  pending_decision: { ...pending, last_status_check_at: checkedAt },
33479
33928
  updated_at: checkedAt
33480
33929
  };
33481
- await writeCodexAgentRuntimeState(this.options.statePath, checking);
33930
+ await writeInferenceAgentRuntimeState(this.options.statePath, checking);
33482
33931
  const status = await this.options.controlClient.decisionStatus({
33483
33932
  host_id: this.options.hostId,
33484
33933
  assignment_id: state.assignment.assignment_id,
@@ -33491,7 +33940,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33491
33940
  pending_decision: null,
33492
33941
  updated_at: new Date(this.now()).toISOString()
33493
33942
  };
33494
- await writeCodexAgentRuntimeState(this.options.statePath, resolved);
33943
+ await writeInferenceAgentRuntimeState(this.options.statePath, resolved);
33495
33944
  return resolved;
33496
33945
  }
33497
33946
  async resolvePendingDecision(state, signal) {
@@ -33503,7 +33952,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33503
33952
  pending_decision: { ...pending, last_status_check_at: checkedAt },
33504
33953
  updated_at: checkedAt
33505
33954
  };
33506
- await writeCodexAgentRuntimeState(this.options.statePath, checking);
33955
+ await writeInferenceAgentRuntimeState(this.options.statePath, checking);
33507
33956
  const status = await this.options.controlClient.decisionStatus({
33508
33957
  host_id: this.options.hostId,
33509
33958
  assignment_id: state.assignment.assignment_id,
@@ -33516,7 +33965,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33516
33965
  pending_decision: null,
33517
33966
  updated_at: new Date(this.now()).toISOString()
33518
33967
  };
33519
- await writeCodexAgentRuntimeState(this.options.statePath, resolved);
33968
+ await writeInferenceAgentRuntimeState(this.options.statePath, resolved);
33520
33969
  return resolved;
33521
33970
  }
33522
33971
  async handleCancelledAssignment(state, signal) {
@@ -33532,7 +33981,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33532
33981
  if (current.thread) {
33533
33982
  await this.options.adapter.releaseThread(current.thread).catch(() => void 0);
33534
33983
  }
33535
- await clearCodexAgentRuntimeState(this.options.statePath);
33984
+ await clearInferenceAgentRuntimeState(this.options.statePath);
33536
33985
  }
33537
33986
  async waitUntilWake(nextWakeAtMs, signal) {
33538
33987
  const heartbeatIntervalMs = this.options.heartbeatIntervalMs ?? 3e3;
@@ -33540,11 +33989,11 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33540
33989
  await this.sleep(Math.min(heartbeatIntervalMs, nextWakeAtMs - this.now()), signal);
33541
33990
  if (this.stopped || signal?.aborted) return "stopped";
33542
33991
  if (this.now() >= nextWakeAtMs) return "ready";
33543
- const state = await readCodexAgentRuntimeState(this.options.statePath);
33544
- if (state?.schema_version !== "vtx_codex_agent_runtime_v2") return "cancelled";
33992
+ const state = await readInferenceAgentRuntimeState(this.options.statePath);
33993
+ if (state?.schema_version !== "vtx_inference_agent_runtime_v3" || state.adapter_id !== this.options.adapterId) return "cancelled";
33545
33994
  const requestedAt = new Date(this.now()).toISOString();
33546
33995
  const heartbeat = await this.options.controlClient.heartbeat({
33547
- operation_id: randomUUID(),
33996
+ operation_id: randomUUID2(),
33548
33997
  host_id: this.options.hostId,
33549
33998
  assignment_id: state.assignment.assignment_id,
33550
33999
  assignment_generation: state.assignment.assignment_generation,
@@ -33554,7 +34003,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33554
34003
  await this.handleCancelledAssignment(state, signal);
33555
34004
  return "cancelled";
33556
34005
  }
33557
- await writeCodexAgentRuntimeState(this.options.statePath, {
34006
+ await writeInferenceAgentRuntimeState(this.options.statePath, {
33558
34007
  ...state,
33559
34008
  assignment: {
33560
34009
  ...state.assignment,
@@ -33566,8 +34015,24 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33566
34015
  return this.stopped || signal?.aborted ? "stopped" : "ready";
33567
34016
  }
33568
34017
  async releaseForHostStop() {
33569
- let state = await readCodexAgentRuntimeState(this.options.statePath);
33570
- if (!state) return;
34018
+ const recovered = await readInferenceAgentRuntimeState(this.options.statePath);
34019
+ if (!recovered) return;
34020
+ let state;
34021
+ if (recovered.schema_version === "vtx_codex_agent_runtime_v1") {
34022
+ if (this.options.adapterId !== "codex") return;
34023
+ state = recovered;
34024
+ } else if (recovered.schema_version === "vtx_codex_agent_runtime_v2") {
34025
+ if (this.options.adapterId !== "codex") return;
34026
+ state = {
34027
+ ...recovered,
34028
+ schema_version: "vtx_inference_agent_runtime_v3",
34029
+ adapter_id: "codex"
34030
+ };
34031
+ await writeInferenceAgentRuntimeState(this.options.statePath, state);
34032
+ } else {
34033
+ if (recovered.adapter_id !== this.options.adapterId) return;
34034
+ state = recovered;
34035
+ }
33571
34036
  try {
33572
34037
  state = state.schema_version === "vtx_codex_agent_runtime_v1" ? await this.resolveLegacyPendingDecision(state) : await this.resolvePendingDecision(state);
33573
34038
  } catch {
@@ -33575,7 +34040,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33575
34040
  }
33576
34041
  if (state.pending_decision) return;
33577
34042
  await this.options.controlClient.releaseAssignment({
33578
- operation_id: randomUUID(),
34043
+ operation_id: randomUUID2(),
33579
34044
  host_id: this.options.hostId,
33580
34045
  assignment_id: state.assignment.assignment_id,
33581
34046
  assignment_generation: state.assignment.assignment_generation,
@@ -33583,7 +34048,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33583
34048
  requested_at: new Date(this.now()).toISOString()
33584
34049
  }, {});
33585
34050
  if (state.thread) await this.options.adapter.releaseThread(state.thread);
33586
- await clearCodexAgentRuntimeState(this.options.statePath);
34051
+ await clearInferenceAgentRuntimeState(this.options.statePath);
33587
34052
  }
33588
34053
  };
33589
34054
  }
@@ -33591,7 +34056,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
33591
34056
 
33592
34057
  // lib/inference-host/service.ts
33593
34058
  import { spawn as spawn6 } from "node:child_process";
33594
- import { randomUUID as randomUUID2 } from "node:crypto";
34059
+ import { randomUUID as randomUUID3 } from "node:crypto";
33595
34060
  import { createWriteStream, readFileSync } from "node:fs";
33596
34061
  import { access as access3, chmod as chmod3, mkdir as mkdir3, readFile as readFile5, rm as rm5, writeFile as writeFile2 } from "node:fs/promises";
33597
34062
  import { homedir as homedir2 } from "node:os";
@@ -34116,7 +34581,7 @@ WantedBy=default.target
34116
34581
  const previousRuntimeUpdatedAt = previousRuntime?.manifest_generation === manifest.generation ? Date.parse(previousRuntime.updated_at) : Number.NaN;
34117
34582
  const restoredManifest = preserveGeneration ? manifest : assertManifest({
34118
34583
  ...manifest,
34119
- generation: randomUUID2(),
34584
+ generation: randomUUID3(),
34120
34585
  installed_at: this.now().toISOString()
34121
34586
  });
34122
34587
  await writeAtomicInferencePrivateFile(
@@ -34402,7 +34867,7 @@ ${cleanup.stderr}`)) {
34402
34867
  ].sort((left, right) => left.instance_name.localeCompare(right.instance_name));
34403
34868
  const manifest = assertManifest({
34404
34869
  schema_version: "vtx_inference_service_v3",
34405
- generation: randomUUID2(),
34870
+ generation: randomUUID3(),
34406
34871
  installed_at: this.now().toISOString(),
34407
34872
  executable: this.executable,
34408
34873
  script: this.script,
@@ -34616,7 +35081,7 @@ ${result2.stderr}`)) {
34616
35081
  if (remaining.length === 0) return await this.uninstallUnlocked();
34617
35082
  return await this.replaceManifestUnlocked({
34618
35083
  ...manifest,
34619
- generation: randomUUID2(),
35084
+ generation: randomUUID3(),
34620
35085
  installed_at: this.now().toISOString(),
34621
35086
  workers: remaining
34622
35087
  }, await readInferenceHostServiceDesired(this.desiredPath()));
@@ -35006,7 +35471,7 @@ __export(cli_exports, {
35006
35471
  registerInferenceHostServiceControlInput: () => registerInferenceHostServiceControlInput,
35007
35472
  runInferenceHostCli: () => runInferenceHostCli
35008
35473
  });
35009
- import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypto";
35474
+ import { createHash as createHash7, randomUUID as randomUUID4 } from "node:crypto";
35010
35475
  import { spawn as spawn7 } from "node:child_process";
35011
35476
  import { lstat as lstat4, realpath as realpath4, rm as rm6 } from "node:fs/promises";
35012
35477
  import { hostname as osHostname } from "node:os";
@@ -35070,6 +35535,42 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
35070
35535
  async () => await agentFail(config2, parsed, dependencies, warnings)
35071
35536
  );
35072
35537
  }
35538
+ if (parsed.command === "agent-assignment-next") {
35539
+ return await withAgentCommandLock(
35540
+ config2,
35541
+ async () => await foregroundAssignmentNext(config2, parsed, dependencies, warnings)
35542
+ );
35543
+ }
35544
+ if (parsed.command === "agent-assignment-heartbeat") {
35545
+ return await withAgentCommandLock(
35546
+ config2,
35547
+ async () => await foregroundAssignmentHeartbeat(config2, parsed, dependencies, warnings)
35548
+ );
35549
+ }
35550
+ if (parsed.command === "agent-data-call") {
35551
+ return await withAgentCommandLock(
35552
+ config2,
35553
+ async () => await foregroundDataCall(config2, parsed, dependencies, warnings)
35554
+ );
35555
+ }
35556
+ if (parsed.command === "agent-decision-submit") {
35557
+ return await withAgentCommandLock(
35558
+ config2,
35559
+ async () => await foregroundDecisionSubmit(config2, parsed, dependencies, warnings)
35560
+ );
35561
+ }
35562
+ if (parsed.command === "agent-decision-status") {
35563
+ return await withAgentCommandLock(
35564
+ config2,
35565
+ async () => await foregroundDecisionStatus(config2, parsed, dependencies, warnings)
35566
+ );
35567
+ }
35568
+ if (parsed.command === "agent-assignment-release") {
35569
+ return await withAgentCommandLock(
35570
+ config2,
35571
+ async () => await foregroundAssignmentRelease(config2, parsed, dependencies, warnings)
35572
+ );
35573
+ }
35073
35574
  if (parsed.command === "service") {
35074
35575
  const mutationActions = /* @__PURE__ */ new Set(["install", "start", "stop", "recover", "uninstall"]);
35075
35576
  if (!parsed.serviceAction || !mutationActions.has(parsed.serviceAction)) {
@@ -35100,7 +35601,7 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
35100
35601
  return await cleanupLogin(config2, parsed, dependencies, warnings, true);
35101
35602
  }
35102
35603
  throw new Error(
35103
- "Usage: vtx inference-host <login|codex-login|run|agent-connect|agent-run|agent-next|agent-complete|agent-fail|service|status|doctor|logout|codex-logout|revoke> [--json]"
35604
+ "Usage: vtx inference-host <login|codex-login|run|agent-connect|agent-run|agent-next|agent-complete|agent-fail|agent-assignment-next|agent-assignment-heartbeat|agent-data-call|agent-decision-submit|agent-decision-status|agent-assignment-release|service|status|doctor|logout|codex-logout|revoke> [--json]"
35104
35605
  );
35105
35606
  } catch (error48) {
35106
35607
  return {
@@ -35111,7 +35612,7 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
35111
35612
  };
35112
35613
  }
35113
35614
  }
35114
- var INFERENCE_HOST_CLI_VERSION, runtimeReceiptPath, codexRecoveryPath, codexGuardianReceiptRoot, revocationCheckpointPath, foregroundHostLockPath, credentialLifecycleLockPath, serviceRecoveryCommandLockPath, AGENT_HEARTBEAT_INTERVAL_MS, AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS, retryableAgentHeartbeatError, assertRevocationCheckpoint, readRevocationCheckpoint, writeRevocationCheckpoint, clearRevocationCheckpoint, render, INFERENCE_HOST_HELP, parseHostConcurrency, parseInferenceHostArgs, resolveDurableServiceDisplayName, defaultOpenBrowser, registerInferenceHostServiceControlInput, defaultRegisterLifecycleSignalHandlers, lifecycleCancellation, configuredCredentialStore, restoreInferenceHostCredentialContext, recoverInferenceHostCredentialContextTransition, accountKeyForState, assertCredentialMatchesState2, revocationCheckpointForCredential, assertRevocationCheckpointMatchesLocalIdentity, fileExistsPrivately, inspectCodexAuthentication, clearLocalRuntimeArtifacts, assertDurableServiceUninstalled, assertLocalRuntimeArtifactsMayBeDiscarded, defaultRunForeground, preparePortableDurableAdapter, defaultRunPortableDurableAdapter, login, codexLogin, codexLogout, localStatus, doctor, cleanupLogin, runHost, defaultReadStdin, parseAgentStdin, agentOperationId, agentSession, agentConnect, agentRun, agentNext, agentComplete, agentFail, withAgentCommandLock, recoveryBackupPath, serviceRecoveryTransactionPath, readServiceRecoveryTransaction, assertResumableCodexRecoveryEvidence, recoverInstalledCodexService, serviceCommand, hasExplicitCredentialStoreConfiguration, credentialEnvironmentForIdentity, commandRequiresRetainedCredentialStore, commandUsesInstalledServiceCredentials, resolveInferenceHostCommandConfig;
35615
+ var INFERENCE_HOST_CLI_VERSION, runtimeReceiptPath, codexRecoveryPath, codexGuardianReceiptRoot, revocationCheckpointPath, foregroundHostLockPath, credentialLifecycleLockPath, serviceRecoveryCommandLockPath, AGENT_HEARTBEAT_INTERVAL_MS, AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS, retryableAgentHeartbeatError, assertRevocationCheckpoint, readRevocationCheckpoint, writeRevocationCheckpoint, clearRevocationCheckpoint, render, INFERENCE_HOST_HELP, parseHostConcurrency, parseInferenceHostArgs, resolveDurableServiceDisplayName, defaultOpenBrowser, registerInferenceHostServiceControlInput, defaultRegisterLifecycleSignalHandlers, lifecycleCancellation, configuredCredentialStore, restoreInferenceHostCredentialContext, recoverInferenceHostCredentialContextTransition, accountKeyForState, assertCredentialMatchesState2, revocationCheckpointForCredential, assertRevocationCheckpointMatchesLocalIdentity, fileExistsPrivately, inspectCodexAuthentication, clearLocalRuntimeArtifacts, assertDurableServiceUninstalled, assertLocalRuntimeArtifactsMayBeDiscarded, defaultRunForeground, preparePortableDurableAdapter, defaultRunPortableDurableAdapter, login, codexLogin, codexLogout, localStatus, doctor, cleanupLogin, runHost, defaultReadStdin, parseAgentStdin, parseOptionalAgentStdin, agentOperationId, agentSession, agentConnect, foregroundAgentControlState, requireForegroundAgentState, assignmentFromClaim, foregroundAssignmentNext, foregroundAssignmentHeartbeat, foregroundDataCall, foregroundDecisionStatusRequest, foregroundAssignmentLeaseEnded, handleForegroundCancelledAssignment, foregroundDecisionStatus, foregroundDecisionSubmit, foregroundAssignmentRelease, agentRun, agentNext, agentComplete, agentFail, withAgentCommandLock, recoveryBackupPath, serviceRecoveryTransactionPath, readServiceRecoveryTransaction, assertResumableCodexRecoveryEvidence, recoverInstalledCodexService, serviceCommand, hasExplicitCredentialStoreConfiguration, credentialEnvironmentForIdentity, commandRequiresRetainedCredentialStore, commandUsesInstalledServiceCredentials, resolveInferenceHostCommandConfig;
35115
35616
  var init_cli = __esm({
35116
35617
  "lib/inference-host/cli.ts"() {
35117
35618
  "use strict";
@@ -35211,6 +35712,12 @@ Commands:
35211
35712
  agent-next Claim the next exact VTX inference request
35212
35713
  agent-complete Submit one completed agent result from stdin
35213
35714
  agent-fail Submit one truthful agent failure from stdin
35715
+ agent-assignment-next Claim the assigned Main bot for Agent control
35716
+ agent-assignment-heartbeat Renew the current Agent assignment
35717
+ agent-data-call Request allowed assignment-scoped VTX data
35718
+ agent-decision-submit Submit the normal structured trading decision
35719
+ agent-decision-status Resolve an uncertain Agent decision submission
35720
+ agent-assignment-release Release the current Agent assignment
35214
35721
  service Install and control the durable background host
35215
35722
  status Inspect local host and credential state
35216
35723
  doctor Verify credentials, provider runtime, and private state
@@ -35525,6 +36032,7 @@ Durable service:
35525
36032
  );
35526
36033
  await clearInferenceAgentAttemptState(config2.statePath);
35527
36034
  await clearInferenceAgentNextState(config2.statePath);
36035
+ await clearInferenceForegroundAgentControlState(config2.statePath);
35528
36036
  await clearCodexAgentRuntimeState(config2.statePath);
35529
36037
  await clearInferenceHostLocalState(config2.statePath);
35530
36038
  };
@@ -35552,10 +36060,11 @@ Durable service:
35552
36060
  const revocationCheckpointPresent = await readRevocationCheckpoint(config2) !== null;
35553
36061
  const agentAttemptPresent = await readInferenceAgentAttemptState(config2.statePath) !== null;
35554
36062
  const agentNextRecoveryPresent = await readInferenceAgentNextState(config2.statePath) !== null;
36063
+ const foregroundAgentControlPresent = await readInferenceForegroundAgentControlState(config2.statePath) !== null;
35555
36064
  const codexAgentRuntimePresent = await readCodexAgentRuntimeState(config2.statePath) !== null;
35556
- if (pendingAttempts > 0 || codexRecoveryPresent || serviceRecoveryPresent || revocationCheckpointPresent || agentAttemptPresent || agentNextRecoveryPresent || codexAgentRuntimePresent) {
36065
+ if (pendingAttempts > 0 || codexRecoveryPresent || serviceRecoveryPresent || revocationCheckpointPresent || agentAttemptPresent || agentNextRecoveryPresent || foregroundAgentControlPresent || codexAgentRuntimePresent) {
35557
36066
  throw new Error(
35558
- "Inference host logout refused because attempt recovery is still pending (Codex, agent-driven, or revocation recovery). Rerun agent-next, complete or fail the active attempt, run the automated host to reconcile it, or resume revoke."
36067
+ "Inference host logout refused because attempt recovery is still pending (Codex, Provider, Agent-control, or revocation recovery). Reconcile or release the exact active operation before retrying logout, or resume revoke."
35559
36068
  );
35560
36069
  }
35561
36070
  };
@@ -35628,6 +36137,12 @@ Durable service:
35628
36137
  return { adapter, preflight: await adapter.preflight(signal) };
35629
36138
  };
35630
36139
  defaultRunPortableDurableAdapter = async (options) => {
36140
+ const agentAdapter = options.adapter;
36141
+ if (typeof agentAdapter.runTurn !== "function" || typeof agentAdapter.releaseThread !== "function" || typeof agentAdapter.close !== "function") {
36142
+ throw new Error(
36143
+ `${options.preflight.adapterId} does not implement the durable Agent-control contract.`
36144
+ );
36145
+ }
35631
36146
  const dependencies = createDefaultInferenceHostRunnerDependencies({
35632
36147
  apiUrl: options.config.apiUrl,
35633
36148
  statePath: options.config.statePath,
@@ -35663,6 +36178,10 @@ Durable service:
35663
36178
  maxConcurrency: options.maxConcurrency,
35664
36179
  once: options.once,
35665
36180
  emitDiagnosticEvent: options.emitDiagnosticEvent,
36181
+ agentRuntime: {
36182
+ statePath: options.config.statePath,
36183
+ adapter: agentAdapter
36184
+ },
35666
36185
  signal: options.signal
35667
36186
  }).run();
35668
36187
  };
@@ -35696,7 +36215,7 @@ Durable service:
35696
36215
  await writeInferenceHostCredentialContextTransition(config2, previousCredentialContext);
35697
36216
  await writeInferenceHostCredentialContext(config2);
35698
36217
  const keyPair = generateExternalInferenceEnvelopeKeyPair();
35699
- const hostId = randomUUID3();
36218
+ const hostId = randomUUID4();
35700
36219
  const beginLogin = dependencies.beginLogin ?? beginInferenceOAuthLogin;
35701
36220
  const loginStore = {
35702
36221
  kind: store.kind,
@@ -36376,7 +36895,27 @@ Waiting for approval...
36376
36895
  }
36377
36896
  return record2;
36378
36897
  };
36379
- agentOperationId = (kind) => `${kind}-${randomUUID3()}`;
36898
+ parseOptionalAgentStdin = async (dependencies, allowedKeys) => {
36899
+ if (!dependencies.readStdin && process.stdin.isTTY) return {};
36900
+ const raw = await (dependencies.readStdin ?? defaultReadStdin)();
36901
+ if (!raw.trim()) return {};
36902
+ let value;
36903
+ try {
36904
+ value = JSON.parse(raw);
36905
+ } catch {
36906
+ throw new Error("Agent-driven inference stdin must be one JSON object.");
36907
+ }
36908
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
36909
+ throw new Error("Agent-driven inference stdin must be one JSON object.");
36910
+ }
36911
+ const record2 = value;
36912
+ const unexpected = Object.keys(record2).filter((key) => !allowedKeys.includes(key));
36913
+ if (unexpected.length > 0) {
36914
+ throw new Error(`Unsupported agent-driven inference fields: ${unexpected.join(", ")}.`);
36915
+ }
36916
+ return record2;
36917
+ };
36918
+ agentOperationId = (kind) => `${kind}-${randomUUID4()}`;
36380
36919
  agentSession = async (config2, dependencies, warnings, signal) => {
36381
36920
  if (await readRevocationCheckpoint(config2)) {
36382
36921
  throw new Error("Inference host revocation recovery must finish first.");
@@ -36420,11 +36959,419 @@ Waiting for approval...
36420
36959
  reasoning_effort: result2.reasoning_effort,
36421
36960
  lanes: ["main", "review", "screener"],
36422
36961
  response_modes: ["provider_response", "decision_candidate"],
36962
+ control_modes: ["provider", "agent"],
36423
36963
  execution_modes: ["client", "server"],
36424
36964
  next_command: "vtx inference-host agent-next --wait-seconds 50 --json",
36965
+ agent_next_command: "vtx inference-host agent-assignment-next --wait-seconds 50 --json",
36425
36966
  keeper_command: "vtx inference-host agent-run"
36426
36967
  }, parsed.json),
36427
36968
  stderr: warnings.length > 0 ? `${warnings.join("\n")}
36969
+ ` : ""
36970
+ };
36971
+ };
36972
+ foregroundAgentControlState = (hostId, updatedAt) => ({
36973
+ schema_version: "vtx_foreground_agent_control_v1",
36974
+ host_id: hostId,
36975
+ assignment: null,
36976
+ pending_next: null,
36977
+ pending_decision: null,
36978
+ next_wake_at: null,
36979
+ updated_at: updatedAt
36980
+ });
36981
+ requireForegroundAgentState = async (config2, hostId) => {
36982
+ const state = await readInferenceForegroundAgentControlState(config2.statePath);
36983
+ if (!state?.assignment) {
36984
+ throw new Error("No active foreground Agent assignment. Run agent-assignment-next first.");
36985
+ }
36986
+ if (state.host_id !== hostId) {
36987
+ throw new Error("Foreground Agent assignment belongs to another inference host.");
36988
+ }
36989
+ return state;
36990
+ };
36991
+ assignmentFromClaim = (result2) => ({
36992
+ assignment_id: result2.assignment_id,
36993
+ assignment_generation: result2.assignment_generation,
36994
+ model_id: result2.model_id,
36995
+ reasoning_effort: result2.reasoning_effort,
36996
+ bot_mode: result2.bot_mode,
36997
+ execution_mode: result2.execution_mode,
36998
+ allowed_symbols: result2.allowed_symbols,
36999
+ data_contract: result2.data_contract,
37000
+ output_schema: result2.output_schema,
37001
+ minimum_wake_seconds: result2.minimum_wake_seconds,
37002
+ maximum_wake_seconds: result2.maximum_wake_seconds,
37003
+ lease_expires_at: result2.lease_expires_at
37004
+ });
37005
+ foregroundAssignmentNext = async (config2, parsed, dependencies, warnings) => {
37006
+ const session = await agentSession(config2, dependencies, warnings);
37007
+ const now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
37008
+ const sleep4 = dependencies.sleep ?? (async (milliseconds) => {
37009
+ await new Promise((resolve6) => setTimeout(resolve6, milliseconds));
37010
+ });
37011
+ const stopAt = now().getTime() + parsed.waitSeconds * 1e3;
37012
+ let state = await readInferenceForegroundAgentControlState(config2.statePath) ?? foregroundAgentControlState(session.localState.host_id, now().toISOString());
37013
+ if (state.host_id !== session.localState.host_id) {
37014
+ throw new Error("Foreground Agent recovery state belongs to another inference host.");
37015
+ }
37016
+ if (state.pending_decision) {
37017
+ throw new Error("Resolve the pending Agent decision before claiming another assignment.");
37018
+ }
37019
+ while (true) {
37020
+ if (!state.pending_next) {
37021
+ const requestedAt = now().toISOString();
37022
+ state = {
37023
+ ...state,
37024
+ pending_next: {
37025
+ operation_id: agentOperationId("agent-assignment-next"),
37026
+ requested_at: requestedAt
37027
+ },
37028
+ updated_at: requestedAt
37029
+ };
37030
+ await writeInferenceForegroundAgentControlState(config2.statePath, state);
37031
+ }
37032
+ const pending = state.pending_next;
37033
+ let result2;
37034
+ try {
37035
+ result2 = await session.client.callTool("inference.agent.assignment.next", {
37036
+ operation_id: pending.operation_id,
37037
+ host_id: session.localState.host_id,
37038
+ requested_at: pending.requested_at,
37039
+ contract_version: "agent_assignment_v2",
37040
+ ...state.assignment ? {
37041
+ assignment_id: state.assignment.assignment_id,
37042
+ assignment_generation: state.assignment.assignment_generation
37043
+ } : {}
37044
+ });
37045
+ } catch (error48) {
37046
+ if (error48 && typeof error48 === "object" && error48.definitivelyNotApplied === true) {
37047
+ state = { ...state, pending_next: null, updated_at: now().toISOString() };
37048
+ await writeInferenceForegroundAgentControlState(config2.statePath, state);
37049
+ }
37050
+ throw error48;
37051
+ }
37052
+ if (result2.claim_state === "claimed") {
37053
+ const assignment = assignmentFromClaim(result2);
37054
+ state = {
37055
+ ...state,
37056
+ assignment,
37057
+ pending_next: null,
37058
+ next_wake_at: null,
37059
+ updated_at: now().toISOString()
37060
+ };
37061
+ await writeInferenceForegroundAgentControlState(config2.statePath, state);
37062
+ return {
37063
+ exitCode: 0,
37064
+ stdout: render({
37065
+ ...result2,
37066
+ instructions: "VTX supplied no trading prompt or prepared context. Choose your own cadence; use agent-data-call zero or more times, submit the exact output_schema through agent-decision-submit, then record the next wake with agent-assignment-heartbeat. Keep agent-run open for liveness.",
37067
+ data_command: "vtx inference-host agent-data-call --json",
37068
+ decision_command: "vtx inference-host agent-decision-submit --json",
37069
+ decision_input: {
37070
+ candidate: "<object matching output_schema>",
37071
+ provenance: {
37072
+ source: "external_agent",
37073
+ agent_run_id: "<stable harness run id>",
37074
+ requested_model: result2.model_id,
37075
+ effective_model: "<actual model used>",
37076
+ requested_reasoning_effort: result2.reasoning_effort,
37077
+ effective_reasoning_effort: "<actual reasoning effort used>"
37078
+ }
37079
+ },
37080
+ heartbeat_command: "vtx inference-host agent-assignment-heartbeat --json",
37081
+ release_command: "vtx inference-host agent-assignment-release --json"
37082
+ }, parsed.json),
37083
+ stderr: warnings.length > 0 ? `${warnings.join("\n")}
37084
+ ` : ""
37085
+ };
37086
+ }
37087
+ state = { ...state, pending_next: null, updated_at: now().toISOString() };
37088
+ await writeInferenceForegroundAgentControlState(config2.statePath, state);
37089
+ const remaining = stopAt - now().getTime();
37090
+ if (remaining <= 0 || parsed.waitSeconds === 0) {
37091
+ return {
37092
+ exitCode: 0,
37093
+ stdout: render(result2, parsed.json),
37094
+ stderr: warnings.length > 0 ? `${warnings.join("\n")}
37095
+ ` : ""
37096
+ };
37097
+ }
37098
+ await sleep4(Math.min(remaining, Math.max(50, result2.retry_after_ms)));
37099
+ }
37100
+ };
37101
+ foregroundAssignmentHeartbeat = async (config2, parsed, dependencies, warnings) => {
37102
+ const session = await agentSession(config2, dependencies, warnings);
37103
+ const state = await requireForegroundAgentState(
37104
+ config2,
37105
+ session.localState.host_id
37106
+ );
37107
+ const input = await parseOptionalAgentStdin(dependencies, ["next_wake_at"]);
37108
+ const nextWakeAt = input.next_wake_at;
37109
+ if (nextWakeAt !== void 0 && (typeof nextWakeAt !== "string" || !Number.isFinite(Date.parse(nextWakeAt)))) {
37110
+ throw new Error("next_wake_at must be an ISO timestamp.");
37111
+ }
37112
+ const requestedAt = (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
37113
+ const result2 = await session.client.callTool("inference.agent.assignment.heartbeat", {
37114
+ operation_id: agentOperationId("agent-assignment-heartbeat"),
37115
+ host_id: session.localState.host_id,
37116
+ assignment_id: state.assignment.assignment_id,
37117
+ assignment_generation: state.assignment.assignment_generation,
37118
+ requested_at: requestedAt,
37119
+ ...nextWakeAt === void 0 ? {} : { next_wake_at: nextWakeAt }
37120
+ });
37121
+ if (result2.directive === "cancel") {
37122
+ await handleForegroundCancelledAssignment(config2, session, state, requestedAt);
37123
+ } else {
37124
+ await writeInferenceForegroundAgentControlState(config2.statePath, {
37125
+ ...state,
37126
+ assignment: { ...state.assignment, lease_expires_at: result2.lease_expires_at },
37127
+ next_wake_at: result2.next_wake_at ?? state.next_wake_at,
37128
+ updated_at: requestedAt
37129
+ });
37130
+ }
37131
+ return {
37132
+ exitCode: 0,
37133
+ stdout: render(result2, parsed.json),
37134
+ stderr: warnings.length > 0 ? `${warnings.join("\n")}
37135
+ ` : ""
37136
+ };
37137
+ };
37138
+ foregroundDataCall = async (config2, parsed, dependencies, warnings) => {
37139
+ const session = await agentSession(config2, dependencies, warnings);
37140
+ const state = await requireForegroundAgentState(config2, session.localState.host_id);
37141
+ const input = await parseAgentStdin(dependencies, ["capability", "arguments"]);
37142
+ const capability = typeof input.capability === "string" ? input.capability.trim() : "";
37143
+ if (!capability || !state.assignment.data_contract.some((item) => item.id === capability)) {
37144
+ throw new Error("Agent data capability is not allowed by the current assignment.");
37145
+ }
37146
+ if (!input.arguments || typeof input.arguments !== "object" || Array.isArray(input.arguments)) {
37147
+ throw new Error("Agent data arguments must be one JSON object.");
37148
+ }
37149
+ const result2 = await session.client.callTool("inference.agent.data.call", {
37150
+ operation_id: agentOperationId("agent-data-call"),
37151
+ host_id: session.localState.host_id,
37152
+ assignment_id: state.assignment.assignment_id,
37153
+ assignment_generation: state.assignment.assignment_generation,
37154
+ capability,
37155
+ arguments: input.arguments,
37156
+ requested_at: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
37157
+ });
37158
+ return {
37159
+ exitCode: 0,
37160
+ stdout: render(result2, parsed.json),
37161
+ stderr: warnings.length > 0 ? `${warnings.join("\n")}
37162
+ ` : ""
37163
+ };
37164
+ };
37165
+ foregroundDecisionStatusRequest = (hostId, state) => ({
37166
+ operation_id: state.pending_decision.request.operation_id,
37167
+ host_id: hostId,
37168
+ assignment_id: state.assignment.assignment_id,
37169
+ assignment_generation: state.assignment.assignment_generation
37170
+ });
37171
+ foregroundAssignmentLeaseEnded = (state, now) => Boolean(state.assignment) && Date.parse(state.assignment.lease_expires_at) <= now.getTime();
37172
+ handleForegroundCancelledAssignment = async (config2, session, state, requestedAt, signal) => {
37173
+ if (!state.pending_decision) {
37174
+ await clearInferenceForegroundAgentControlState(config2.statePath);
37175
+ return;
37176
+ }
37177
+ const cancelledState = {
37178
+ ...state,
37179
+ assignment: {
37180
+ ...state.assignment,
37181
+ lease_expires_at: requestedAt
37182
+ },
37183
+ pending_decision: {
37184
+ ...state.pending_decision,
37185
+ last_status_check_at: requestedAt
37186
+ },
37187
+ next_wake_at: null,
37188
+ updated_at: requestedAt
37189
+ };
37190
+ await writeInferenceForegroundAgentControlState(config2.statePath, cancelledState);
37191
+ try {
37192
+ await session.client.callTool(
37193
+ "inference.agent.decision.status",
37194
+ foregroundDecisionStatusRequest(session.localState.host_id, cancelledState),
37195
+ { signal }
37196
+ );
37197
+ } catch {
37198
+ return;
37199
+ }
37200
+ await clearInferenceForegroundAgentControlState(config2.statePath);
37201
+ };
37202
+ foregroundDecisionStatus = async (config2, parsed, dependencies, warnings) => {
37203
+ const session = await agentSession(config2, dependencies, warnings);
37204
+ let state = await requireForegroundAgentState(config2, session.localState.host_id);
37205
+ if (!state.pending_decision) {
37206
+ throw new Error("No uncertain foreground Agent decision requires status recovery.");
37207
+ }
37208
+ const checkedAt = (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
37209
+ state = {
37210
+ ...state,
37211
+ pending_decision: { ...state.pending_decision, last_status_check_at: checkedAt },
37212
+ updated_at: checkedAt
37213
+ };
37214
+ await writeInferenceForegroundAgentControlState(config2.statePath, state);
37215
+ const result2 = await session.client.callTool(
37216
+ "inference.agent.decision.status",
37217
+ foregroundDecisionStatusRequest(session.localState.host_id, state)
37218
+ );
37219
+ const assignmentLeaseEnded = foregroundAssignmentLeaseEnded(state, new Date(checkedAt));
37220
+ if (result2.found || assignmentLeaseEnded) {
37221
+ if (assignmentLeaseEnded) {
37222
+ await clearInferenceForegroundAgentControlState(config2.statePath);
37223
+ } else {
37224
+ await writeInferenceForegroundAgentControlState(config2.statePath, {
37225
+ ...state,
37226
+ pending_decision: null,
37227
+ updated_at: checkedAt
37228
+ });
37229
+ }
37230
+ }
37231
+ return {
37232
+ exitCode: 0,
37233
+ stdout: render(result2, parsed.json),
37234
+ stderr: warnings.length > 0 ? `${warnings.join("\n")}
37235
+ ` : ""
37236
+ };
37237
+ };
37238
+ foregroundDecisionSubmit = async (config2, parsed, dependencies, warnings) => {
37239
+ const session = await agentSession(config2, dependencies, warnings);
37240
+ const now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
37241
+ let state = await requireForegroundAgentState(config2, session.localState.host_id);
37242
+ if (!state.pending_decision) {
37243
+ const input = await parseAgentStdin(dependencies, ["candidate", "provenance"]);
37244
+ if (!input.candidate || typeof input.candidate !== "object" || Array.isArray(input.candidate)) {
37245
+ throw new Error("Agent decision candidate must be one JSON object.");
37246
+ }
37247
+ if (!input.provenance || typeof input.provenance !== "object" || Array.isArray(input.provenance)) {
37248
+ throw new Error("Agent decision provenance must be one JSON object.");
37249
+ }
37250
+ const observedAt = now().toISOString();
37251
+ state = {
37252
+ ...state,
37253
+ pending_decision: {
37254
+ request: {
37255
+ assignment_id: state.assignment.assignment_id,
37256
+ assignment_generation: state.assignment.assignment_generation,
37257
+ operation_id: agentOperationId("agent-decision-submit"),
37258
+ candidate: input.candidate,
37259
+ observed_at: observedAt,
37260
+ provenance: input.provenance
37261
+ },
37262
+ first_transmit_at: null,
37263
+ last_status_check_at: null
37264
+ },
37265
+ updated_at: observedAt
37266
+ };
37267
+ await writeInferenceForegroundAgentControlState(config2.statePath, state);
37268
+ } else {
37269
+ const checkedAt = now().toISOString();
37270
+ state = {
37271
+ ...state,
37272
+ pending_decision: { ...state.pending_decision, last_status_check_at: checkedAt },
37273
+ updated_at: checkedAt
37274
+ };
37275
+ await writeInferenceForegroundAgentControlState(config2.statePath, state);
37276
+ const status = await session.client.callTool(
37277
+ "inference.agent.decision.status",
37278
+ foregroundDecisionStatusRequest(session.localState.host_id, state)
37279
+ );
37280
+ if (status.found) {
37281
+ await writeInferenceForegroundAgentControlState(config2.statePath, {
37282
+ ...state,
37283
+ pending_decision: null,
37284
+ updated_at: checkedAt
37285
+ });
37286
+ return {
37287
+ exitCode: 0,
37288
+ stdout: render({ ...status, recovered: true }, parsed.json),
37289
+ stderr: warnings.length > 0 ? `${warnings.join("\n")}
37290
+ ` : ""
37291
+ };
37292
+ }
37293
+ }
37294
+ const transmittedAt = now().toISOString();
37295
+ state = {
37296
+ ...state,
37297
+ pending_decision: {
37298
+ ...state.pending_decision,
37299
+ first_transmit_at: state.pending_decision.first_transmit_at ?? transmittedAt
37300
+ },
37301
+ updated_at: transmittedAt
37302
+ };
37303
+ await writeInferenceForegroundAgentControlState(config2.statePath, state);
37304
+ try {
37305
+ const result2 = await session.client.callTool(
37306
+ "inference.agent.decision.submit",
37307
+ state.pending_decision.request
37308
+ );
37309
+ await writeInferenceForegroundAgentControlState(config2.statePath, {
37310
+ ...state,
37311
+ pending_decision: null,
37312
+ updated_at: now().toISOString()
37313
+ });
37314
+ return {
37315
+ exitCode: 0,
37316
+ stdout: render(result2, parsed.json),
37317
+ stderr: warnings.length > 0 ? `${warnings.join("\n")}
37318
+ ` : ""
37319
+ };
37320
+ } catch (error48) {
37321
+ const checkedAt = now().toISOString();
37322
+ state = {
37323
+ ...state,
37324
+ pending_decision: { ...state.pending_decision, last_status_check_at: checkedAt },
37325
+ updated_at: checkedAt
37326
+ };
37327
+ await writeInferenceForegroundAgentControlState(config2.statePath, state);
37328
+ try {
37329
+ const status = await session.client.callTool(
37330
+ "inference.agent.decision.status",
37331
+ foregroundDecisionStatusRequest(session.localState.host_id, state)
37332
+ );
37333
+ if (status.found) {
37334
+ await writeInferenceForegroundAgentControlState(config2.statePath, {
37335
+ ...state,
37336
+ pending_decision: null,
37337
+ updated_at: checkedAt
37338
+ });
37339
+ return {
37340
+ exitCode: 0,
37341
+ stdout: render({ ...status, recovered: true }, parsed.json),
37342
+ stderr: warnings.length > 0 ? `${warnings.join("\n")}
37343
+ ` : ""
37344
+ };
37345
+ }
37346
+ } catch {
37347
+ }
37348
+ throw error48;
37349
+ }
37350
+ };
37351
+ foregroundAssignmentRelease = async (config2, parsed, dependencies, warnings) => {
37352
+ const session = await agentSession(config2, dependencies, warnings);
37353
+ const state = await requireForegroundAgentState(config2, session.localState.host_id);
37354
+ if (state.pending_decision) {
37355
+ throw new Error("Resolve the pending Agent decision before releasing its assignment.");
37356
+ }
37357
+ const input = await parseOptionalAgentStdin(dependencies, ["reason_code"]);
37358
+ const reasonCode = input.reason_code === void 0 ? "agent_released" : input.reason_code;
37359
+ if (typeof reasonCode !== "string" || !/^[a-z0-9][a-z0-9._-]{0,95}$/u.test(reasonCode)) {
37360
+ throw new Error("reason_code must be a safe lowercase code.");
37361
+ }
37362
+ const result2 = await session.client.callTool("inference.agent.assignment.release", {
37363
+ operation_id: agentOperationId("agent-assignment-release"),
37364
+ host_id: session.localState.host_id,
37365
+ assignment_id: state.assignment.assignment_id,
37366
+ assignment_generation: state.assignment.assignment_generation,
37367
+ reason_code: reasonCode,
37368
+ requested_at: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
37369
+ });
37370
+ await clearInferenceForegroundAgentControlState(config2.statePath);
37371
+ return {
37372
+ exitCode: 0,
37373
+ stdout: render(result2, parsed.json),
37374
+ stderr: warnings.length > 0 ? `${warnings.join("\n")}
36428
37375
  ` : ""
36429
37376
  };
36430
37377
  };
@@ -36432,6 +37379,7 @@ Waiting for approval...
36432
37379
  const cancellation = lifecycleCancellation(dependencies);
36433
37380
  let keeperLock = null;
36434
37381
  let heartbeatCount = 0;
37382
+ let assignmentHeartbeatCount = 0;
36435
37383
  try {
36436
37384
  keeperLock = await acquireInferenceHostProcessLock(foregroundHostLockPath(config2));
36437
37385
  const store = configuredCredentialStore(config2, dependencies, (message) => {
@@ -36465,6 +37413,7 @@ Waiting for approval...
36465
37413
  }
36466
37414
  if (commandLock) {
36467
37415
  let heartbeatSuppressed = false;
37416
+ let assignmentHeartbeatComplete = true;
36468
37417
  try {
36469
37418
  const active = await readInferenceAgentAttemptState(config2.statePath);
36470
37419
  const pendingNext = await readInferenceAgentNextState(config2.statePath);
@@ -36524,10 +37473,65 @@ Waiting for approval...
36524
37473
  }
36525
37474
  }
36526
37475
  }
37476
+ const control = await readInferenceForegroundAgentControlState(config2.statePath);
37477
+ if (control && control.host_id !== session.localState.host_id) {
37478
+ throw new Error("Foreground Agent control state belongs to another inference host.");
37479
+ }
37480
+ if (control?.assignment) {
37481
+ assignmentHeartbeatComplete = false;
37482
+ try {
37483
+ const requestedAt = (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
37484
+ const result2 = await session.client.callTool(
37485
+ "inference.agent.assignment.heartbeat",
37486
+ {
37487
+ operation_id: agentOperationId("agent-assignment-heartbeat"),
37488
+ host_id: session.localState.host_id,
37489
+ assignment_id: control.assignment.assignment_id,
37490
+ assignment_generation: control.assignment.assignment_generation,
37491
+ requested_at: requestedAt
37492
+ },
37493
+ { signal: cancellation.signal }
37494
+ );
37495
+ assignmentHeartbeatComplete = true;
37496
+ assignmentHeartbeatCount += 1;
37497
+ if (result2.directive === "cancel") {
37498
+ await handleForegroundCancelledAssignment(
37499
+ config2,
37500
+ session,
37501
+ control,
37502
+ requestedAt,
37503
+ cancellation.signal
37504
+ );
37505
+ } else {
37506
+ await writeInferenceForegroundAgentControlState(config2.statePath, {
37507
+ ...control,
37508
+ assignment: {
37509
+ ...control.assignment,
37510
+ lease_expires_at: result2.lease_expires_at
37511
+ },
37512
+ updated_at: requestedAt
37513
+ });
37514
+ }
37515
+ } catch (error48) {
37516
+ if (cancellation.signal.aborted) break;
37517
+ if (!retryableAgentHeartbeatError(error48)) throw error48;
37518
+ consecutiveHeartbeatFailures += 1;
37519
+ retryDelayMs = Math.min(
37520
+ AGENT_HEARTBEAT_INTERVAL_MS * 2 ** Math.max(0, consecutiveHeartbeatFailures - 1),
37521
+ AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS
37522
+ );
37523
+ emitStderr(parsed.json ? `${JSON.stringify({
37524
+ status: "assignment_heartbeat_retry",
37525
+ retry_after_ms: retryDelayMs
37526
+ })}
37527
+ ` : `Foreground Agent assignment heartbeat was temporarily unavailable; retrying in ${retryDelayMs}ms.
37528
+ `);
37529
+ }
37530
+ }
36527
37531
  } finally {
36528
37532
  await commandLock.release();
36529
37533
  }
36530
- if (parsed.once && (heartbeatCount > 0 || heartbeatSuppressed)) break;
37534
+ if (parsed.once && (heartbeatCount > 0 || heartbeatSuppressed) && assignmentHeartbeatComplete) break;
36531
37535
  }
36532
37536
  if (parsed.once && !commandLock) break;
36533
37537
  await (dependencies.sleep ?? (async (milliseconds) => {
@@ -36536,7 +37540,11 @@ Waiting for approval...
36536
37540
  }
36537
37541
  return {
36538
37542
  exitCode: 0,
36539
- stdout: render({ status: "stopped", heartbeats: heartbeatCount }, parsed.json),
37543
+ stdout: render({
37544
+ status: "stopped",
37545
+ heartbeats: heartbeatCount,
37546
+ assignment_heartbeats: assignmentHeartbeatCount
37547
+ }, parsed.json),
36540
37548
  stderr: warnings.length > 0 ? `${warnings.join("\n")}
36541
37549
  ` : ""
36542
37550
  };
@@ -36924,7 +37932,7 @@ Waiting for approval...
36924
37932
  if (recoveryRaw === null && existingTransaction?.phase !== "reconciled") {
36925
37933
  throw new Error("Codex recovery evidence changed before service recovery began.");
36926
37934
  }
36927
- const transactionId = existingTransaction?.transaction_id ?? randomUUID3();
37935
+ const transactionId = existingTransaction?.transaction_id ?? randomUUID4();
36928
37936
  const backupPath = existingTransaction?.recovery_backup_path ?? recoveryBackupPath(config2, transactionId);
36929
37937
  if (!existingTransaction) {
36930
37938
  await writeAtomicInferencePrivateFile(backupPath, recoveryRaw);
@@ -37445,7 +38453,7 @@ var init_types = __esm({
37445
38453
  });
37446
38454
 
37447
38455
  // lib/agent-core/client.ts
37448
- import { randomUUID as randomUUID4 } from "node:crypto";
38456
+ import { randomUUID as randomUUID5 } from "node:crypto";
37449
38457
  function normalizeApiUrl(value) {
37450
38458
  const parsed = String(value || "").trim();
37451
38459
  if (!parsed) {
@@ -37707,7 +38715,7 @@ var init_client = __esm({
37707
38715
  return this.request("/trading/ai/runtime/decision", {
37708
38716
  method: "POST",
37709
38717
  profileId,
37710
- idempotencyKey: randomUUID4(),
38718
+ idempotencyKey: randomUUID5(),
37711
38719
  headers: { "x-client-runtime-lease": leaseToken },
37712
38720
  body: payload
37713
38721
  });
@@ -37716,7 +38724,7 @@ var init_client = __esm({
37716
38724
  return this.request("/trading/ai/runtime/trade-sync", {
37717
38725
  method: "POST",
37718
38726
  profileId,
37719
- idempotencyKey: randomUUID4(),
38727
+ idempotencyKey: randomUUID5(),
37720
38728
  headers: { "x-client-runtime-lease": leaseToken },
37721
38729
  body: payload
37722
38730
  });
@@ -37725,7 +38733,7 @@ var init_client = __esm({
37725
38733
  return this.request("/trading/ai/runtime/error", {
37726
38734
  method: "POST",
37727
38735
  profileId,
37728
- idempotencyKey: randomUUID4(),
38736
+ idempotencyKey: randomUUID5(),
37729
38737
  headers: { "x-client-runtime-lease": leaseToken },
37730
38738
  body: payload
37731
38739
  });
@@ -37737,7 +38745,7 @@ var init_client = __esm({
37737
38745
  return this.request("/trading/market-order", {
37738
38746
  method: "POST",
37739
38747
  profileId,
37740
- idempotencyKey: randomUUID4(),
38748
+ idempotencyKey: randomUUID5(),
37741
38749
  body: payload
37742
38750
  });
37743
38751
  }
@@ -37745,7 +38753,7 @@ var init_client = __esm({
37745
38753
  return this.request("/trading/limit-order", {
37746
38754
  method: "POST",
37747
38755
  profileId,
37748
- idempotencyKey: randomUUID4(),
38756
+ idempotencyKey: randomUUID5(),
37749
38757
  body: payload
37750
38758
  });
37751
38759
  }
@@ -37753,7 +38761,7 @@ var init_client = __esm({
37753
38761
  return this.request("/trading/cancel-order", {
37754
38762
  method: "POST",
37755
38763
  profileId,
37756
- idempotencyKey: randomUUID4(),
38764
+ idempotencyKey: randomUUID5(),
37757
38765
  body: payload
37758
38766
  });
37759
38767
  }
@@ -37772,7 +38780,7 @@ var init_client = __esm({
37772
38780
  return this.request("/trading/ai/start", {
37773
38781
  method: "POST",
37774
38782
  profileId,
37775
- idempotencyKey: randomUUID4(),
38783
+ idempotencyKey: randomUUID5(),
37776
38784
  body: payload
37777
38785
  });
37778
38786
  }
@@ -37780,7 +38788,7 @@ var init_client = __esm({
37780
38788
  return this.request("/trading/ai/stop", {
37781
38789
  method: "POST",
37782
38790
  profileId,
37783
- idempotencyKey: randomUUID4(),
38791
+ idempotencyKey: randomUUID5(),
37784
38792
  body: {}
37785
38793
  });
37786
38794
  }
@@ -37788,7 +38796,7 @@ var init_client = __esm({
37788
38796
  return this.request("/trading/ai/assistant/start", {
37789
38797
  method: "POST",
37790
38798
  profileId,
37791
- idempotencyKey: randomUUID4(),
38799
+ idempotencyKey: randomUUID5(),
37792
38800
  body: {}
37793
38801
  });
37794
38802
  }
@@ -37796,7 +38804,7 @@ var init_client = __esm({
37796
38804
  return this.request("/trading/ai/assistant/stop", {
37797
38805
  method: "POST",
37798
38806
  profileId,
37799
- idempotencyKey: randomUUID4(),
38807
+ idempotencyKey: randomUUID5(),
37800
38808
  body: {}
37801
38809
  });
37802
38810
  }
@@ -37804,7 +38812,7 @@ var init_client = __esm({
37804
38812
  return this.request("/trading/ai/runtime/session/start", {
37805
38813
  method: "POST",
37806
38814
  profileId,
37807
- idempotencyKey: randomUUID4(),
38815
+ idempotencyKey: randomUUID5(),
37808
38816
  body: payload
37809
38817
  });
37810
38818
  }
@@ -37815,7 +38823,7 @@ var init_client = __esm({
37815
38823
  return this.request("/trading/ai/runtime/session/stop", {
37816
38824
  method: "POST",
37817
38825
  profileId,
37818
- idempotencyKey: randomUUID4(),
38826
+ idempotencyKey: randomUUID5(),
37819
38827
  body: payload
37820
38828
  });
37821
38829
  }
@@ -37832,7 +38840,7 @@ var init_client = __esm({
37832
38840
  }).request("/trading/ai/runtime/session/stop", {
37833
38841
  method: "POST",
37834
38842
  profileId,
37835
- idempotencyKey: randomUUID4(),
38843
+ idempotencyKey: randomUUID5(),
37836
38844
  body: payload
37837
38845
  });
37838
38846
  }
@@ -37849,7 +38857,7 @@ import {
37849
38857
  unlinkSync,
37850
38858
  writeFileSync
37851
38859
  } from "node:fs";
37852
- import { randomUUID as randomUUID5 } from "node:crypto";
38860
+ import { randomUUID as randomUUID6 } from "node:crypto";
37853
38861
  import { dirname as dirname6 } from "node:path";
37854
38862
  var parseStoredValues, FileBackedProtectionStorage, clientRuntimeProtectionStatePath;
37855
38863
  var init_protection_storage = __esm({
@@ -37906,7 +38914,7 @@ var init_protection_storage = __esm({
37906
38914
  mkdirSync(dirname6(this.path), { recursive: true, mode: 448 });
37907
38915
  const serialized = `${JSON.stringify(values)}
37908
38916
  `;
37909
- const temporaryPath = `${this.path}.${process.pid}.${randomUUID5()}.tmp`;
38917
+ const temporaryPath = `${this.path}.${process.pid}.${randomUUID6()}.tmp`;
37910
38918
  try {
37911
38919
  writeFileSync(temporaryPath, serialized, {
37912
38920
  encoding: "utf8",
@@ -37933,7 +38941,7 @@ var init_protection_storage = __esm({
37933
38941
  });
37934
38942
 
37935
38943
  // lib/agent-core/headless-runtime.ts
37936
- import { randomUUID as randomUUID6 } from "node:crypto";
38944
+ import { randomUUID as randomUUID7 } from "node:crypto";
37937
38945
  import { setTimeout as sleep } from "node:timers/promises";
37938
38946
  function objectOrNull2(value) {
37939
38947
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -38031,8 +39039,8 @@ async function runAndReportLocalWorkCycle(options, state, leaseToken, context) {
38031
39039
  return Boolean(result2.decision || tradeSync || result2.afterDecision);
38032
39040
  }
38033
39041
  async function startHeadlessRuntime(options) {
38034
- const runtimeSessionId = randomUUID6();
38035
- const deviceId = String(options.deviceId || "").trim() || randomUUID6();
39042
+ const runtimeSessionId = randomUUID7();
39043
+ const deviceId = String(options.deviceId || "").trim() || randomUUID7();
38036
39044
  const startResponse = await options.client.startRuntime(options.profileId, {
38037
39045
  session_id: runtimeSessionId,
38038
39046
  device_id: deviceId,
@@ -38220,7 +39228,18 @@ var init_sort_utils = __esm({
38220
39228
  });
38221
39229
 
38222
39230
  // lib/runtime/hyperliquid-account-mode-contract.ts
38223
- var UNIFIED_MODE_ALIASES, normalizeAccountMode, extractAccountModeFromPayload, extractAccountModeCandidateFromPayload, isUnifiedAccountMode;
39231
+ function resolveExactHyperliquidAccountMode(userAbstraction, ...dexEvidence) {
39232
+ const mode = extractCanonicalHyperliquidAccountMode(userAbstraction);
39233
+ if (!mode) {
39234
+ throw new Error("Exact Hyperliquid userAbstraction response is invalid.");
39235
+ }
39236
+ if (mode !== "default" && mode !== "disabled") return mode;
39237
+ if (dexEvidence.length < 1) {
39238
+ throw new Error("Exact Hyperliquid userDexAbstraction response is unavailable.");
39239
+ }
39240
+ return parseExactDexAbstractionEnabled(dexEvidence[0]) ? "dexAbstraction" : mode;
39241
+ }
39242
+ var UNIFIED_MODE_ALIASES, CANONICAL_ACCOUNT_MODE_ALIASES, EXACT_MODE_KEYS, EXACT_MODE_BOOLEAN_KEYS, isExactTruthyFlag, normalizeCanonicalHyperliquidAccountMode, extractCanonicalHyperliquidAccountMode, parseExactDexAbstractionEnabled, normalizeAccountMode, extractAccountModeFromPayload, extractAccountModeCandidateFromPayload, isUnifiedAccountMode;
38224
39243
  var init_hyperliquid_account_mode_contract = __esm({
38225
39244
  "lib/runtime/hyperliquid-account-mode-contract.ts"() {
38226
39245
  "use strict";
@@ -38231,6 +39250,89 @@ var init_hyperliquid_account_mode_contract = __esm({
38231
39250
  "unified",
38232
39251
  "pm"
38233
39252
  ]);
39253
+ CANONICAL_ACCOUNT_MODE_ALIASES = /* @__PURE__ */ new Map([
39254
+ ["default", "default"],
39255
+ ["standard", "default"],
39256
+ ["classic", "default"],
39257
+ ["disabled", "disabled"],
39258
+ ["unifiedaccount", "unifiedAccount"],
39259
+ ["unified", "unifiedAccount"],
39260
+ ["portfoliomargin", "portfolioMargin"],
39261
+ ["pm", "portfolioMargin"],
39262
+ ["dexabstraction", "dexAbstraction"]
39263
+ ]);
39264
+ EXACT_MODE_KEYS = [
39265
+ "accountMode",
39266
+ "account_mode",
39267
+ "accountType",
39268
+ "account_type",
39269
+ "accountUnificationMode",
39270
+ "account_unification_mode",
39271
+ "abstractionMode",
39272
+ "abstraction_mode",
39273
+ "abstraction",
39274
+ "abstractionState",
39275
+ "dexAbstractionState",
39276
+ "marginMode",
39277
+ "state",
39278
+ "mode",
39279
+ "value"
39280
+ ];
39281
+ EXACT_MODE_BOOLEAN_KEYS = [
39282
+ ["unifiedAccount", ["isUnifiedAccount", "unifiedAccount", "isUnified", "unified", "is_unified_account"]],
39283
+ ["portfolioMargin", ["isPortfolioMargin", "portfolioMargin", "isPm", "pm", "is_portfolio_margin"]],
39284
+ ["dexAbstraction", ["isDexAbstraction", "dexAbstraction", "dexAbstractionEnabled", "is_dex_abstraction"]],
39285
+ ["default", ["isClassic", "classic", "isStandard", "standard"]]
39286
+ ];
39287
+ isExactTruthyFlag = (value) => value === true || value === 1 || typeof value === "string" && value.trim().toLowerCase() === "true";
39288
+ normalizeCanonicalHyperliquidAccountMode = (value) => {
39289
+ if (typeof value !== "string") return null;
39290
+ const key = value.trim().replace(/[_\s-]/g, "").toLowerCase();
39291
+ return CANONICAL_ACCOUNT_MODE_ALIASES.get(key) ?? null;
39292
+ };
39293
+ extractCanonicalHyperliquidAccountMode = (payload, depth = 0) => {
39294
+ if (depth > 6) return null;
39295
+ const direct = normalizeCanonicalHyperliquidAccountMode(payload);
39296
+ if (direct) return direct;
39297
+ if (Array.isArray(payload)) {
39298
+ for (const item of payload) {
39299
+ const mode = extractCanonicalHyperliquidAccountMode(item, depth + 1);
39300
+ if (mode) return mode;
39301
+ }
39302
+ return null;
39303
+ }
39304
+ if (!payload || typeof payload !== "object") return null;
39305
+ const source = payload;
39306
+ for (const key of EXACT_MODE_KEYS) {
39307
+ if (!(key in source)) continue;
39308
+ const mode = normalizeCanonicalHyperliquidAccountMode(source[key]);
39309
+ if (mode) return mode;
39310
+ }
39311
+ for (const [mode, keys] of EXACT_MODE_BOOLEAN_KEYS) {
39312
+ for (const key of keys) {
39313
+ if (isExactTruthyFlag(source[key])) return mode;
39314
+ }
39315
+ }
39316
+ for (const value of Object.values(source)) {
39317
+ const mode = extractCanonicalHyperliquidAccountMode(value, depth + 1);
39318
+ if (mode) return mode;
39319
+ }
39320
+ return null;
39321
+ };
39322
+ parseExactDexAbstractionEnabled = (payload) => {
39323
+ if (payload == null || payload === false) return false;
39324
+ if (payload === true) return true;
39325
+ if (typeof payload === "string") {
39326
+ const normalized = payload.trim().toLowerCase();
39327
+ if (normalized === "true") return true;
39328
+ if (normalized === "false") return false;
39329
+ }
39330
+ if (typeof payload === "number" && Number.isFinite(payload)) {
39331
+ if (payload === 1) return true;
39332
+ if (payload === 0) return false;
39333
+ }
39334
+ throw new Error("Exact Hyperliquid userDexAbstraction response is invalid.");
39335
+ };
38234
39336
  normalizeAccountMode = (mode) => String(mode ?? "").trim().toLowerCase().replace(/[_\s-]/g, "");
38235
39337
  extractAccountModeFromPayload = (payload) => {
38236
39338
  const candidate = extractAccountModeCandidateFromPayload(payload);
@@ -38455,6 +39557,229 @@ var init_hyperliquid_active_asset_contract = __esm({
38455
39557
  }
38456
39558
  });
38457
39559
 
39560
+ // lib/runtime/server-prompt-rescue-account-contract.ts
39561
+ var STABLE_SYMBOLS, toNumber2, firstNumber2, firstTruthy, spotContainers, extractCanonicalSpotMetrics, sumBalanceValueUsd, approximatelyEqual, balancesMirrorUnifiedAccountValue, computeEffectiveAccountValue, equityFormula, buildServerPromptRescueAccountSummary;
39562
+ var init_server_prompt_rescue_account_contract = __esm({
39563
+ "lib/runtime/server-prompt-rescue-account-contract.ts"() {
39564
+ "use strict";
39565
+ init_hyperliquid_account_mode_contract();
39566
+ STABLE_SYMBOLS = /* @__PURE__ */ new Set(["USDC", "USD", "USDT"]);
39567
+ toNumber2 = (value, fallback = 0) => {
39568
+ const numeric = Number(value);
39569
+ return Number.isFinite(numeric) ? numeric : fallback;
39570
+ };
39571
+ firstNumber2 = (values, fallback = 0) => {
39572
+ for (const value of values) {
39573
+ if (value == null || value === "") continue;
39574
+ const numeric = Number(value);
39575
+ if (Number.isFinite(numeric)) return numeric;
39576
+ }
39577
+ return fallback;
39578
+ };
39579
+ firstTruthy = (values, fallback) => {
39580
+ for (const value of values) {
39581
+ if (value) return value;
39582
+ }
39583
+ return fallback;
39584
+ };
39585
+ spotContainers = (spotResponse) => {
39586
+ if (!spotResponse || typeof spotResponse !== "object" || Array.isArray(spotResponse)) return [];
39587
+ const response = spotResponse;
39588
+ const containers = [response];
39589
+ for (const key of ["spotState", "userState", "clearinghouseState", "state", "data"]) {
39590
+ const child = response[key];
39591
+ if (child && typeof child === "object" && !Array.isArray(child)) containers.push(child);
39592
+ }
39593
+ return containers;
39594
+ };
39595
+ extractCanonicalSpotMetrics = (spotResponse) => {
39596
+ const response = spotResponse && typeof spotResponse === "object" && !Array.isArray(spotResponse) ? spotResponse : {};
39597
+ const containers = spotContainers(response);
39598
+ let accountValue = 0;
39599
+ let totalMarginUsed = 0;
39600
+ let withdrawable = 0;
39601
+ for (const container of containers) {
39602
+ const marginSummary = container.marginSummary && typeof container.marginSummary === "object" && !Array.isArray(container.marginSummary) ? container.marginSummary : {};
39603
+ accountValue = Math.max(accountValue, toNumber2(marginSummary.accountValue));
39604
+ totalMarginUsed = Math.max(totalMarginUsed, toNumber2(marginSummary.totalMarginUsed));
39605
+ withdrawable = Math.max(withdrawable, toNumber2(container.withdrawable));
39606
+ }
39607
+ if (accountValue <= 0) {
39608
+ for (const key of ["accountValue", "totalValue", "equity", "totalRawUsd", "usdValue", "usdcValue"]) {
39609
+ accountValue = Math.max(accountValue, toNumber2(response[key]));
39610
+ }
39611
+ }
39612
+ const balances = [];
39613
+ const listKeys = ["balances", "tokenBalances", "spotBalances", "assets"];
39614
+ for (const container of containers) {
39615
+ for (const listKey of listKeys) {
39616
+ const bucket = container[listKey];
39617
+ if (!Array.isArray(bucket)) continue;
39618
+ let stableTotal = 0;
39619
+ let anyTotal = 0;
39620
+ for (const rawEntry of bucket) {
39621
+ if (!rawEntry || typeof rawEntry !== "object" || Array.isArray(rawEntry)) continue;
39622
+ const entry = rawEntry;
39623
+ const coin = String(firstTruthy([
39624
+ entry.coin,
39625
+ entry.token,
39626
+ entry.asset,
39627
+ entry.symbol
39628
+ ], "")).trim().toUpperCase();
39629
+ if (!coin) continue;
39630
+ const total = toNumber2(firstTruthy([entry.total, entry.balance, entry.amount], "0"));
39631
+ const hold = toNumber2(firstTruthy([entry.hold, entry.locked], "0"));
39632
+ const available = Math.max(
39633
+ 0,
39634
+ toNumber2(firstTruthy([entry.available, entry.free, total - hold], "0"))
39635
+ );
39636
+ let valueUsd = toNumber2(firstTruthy([entry.usdValue, entry.usdcValue], "0"));
39637
+ if (valueUsd <= 0 && STABLE_SYMBOLS.has(coin)) {
39638
+ valueUsd = available > 0 ? available : total;
39639
+ }
39640
+ balances.push({ coin, total, hold, available, value_usd: valueUsd });
39641
+ const entryValue = valueUsd > 0 ? valueUsd : total;
39642
+ if (entryValue > 0) {
39643
+ anyTotal += entryValue;
39644
+ if (STABLE_SYMBOLS.has(coin)) stableTotal += entryValue;
39645
+ }
39646
+ }
39647
+ if (accountValue <= 0) {
39648
+ if (stableTotal > 0) accountValue = stableTotal;
39649
+ else if (anyTotal > 0) accountValue = anyTotal;
39650
+ }
39651
+ }
39652
+ if (balances.length > 0) break;
39653
+ }
39654
+ return { accountValue, totalMarginUsed, withdrawable, balances };
39655
+ };
39656
+ sumBalanceValueUsd = (balances) => balances.reduce((total, balance) => {
39657
+ let valueUsd = toNumber2(balance.value_usd);
39658
+ if (valueUsd <= 0 && STABLE_SYMBOLS.has(String(balance.coin || "").trim().toUpperCase())) {
39659
+ valueUsd = toNumber2(balance.total);
39660
+ }
39661
+ return total + Math.max(valueUsd, 0);
39662
+ }, 0);
39663
+ approximatelyEqual = (left, right, absoluteToleranceUsd, relativeTolerance) => {
39664
+ const reference = Math.max(Math.abs(left), Math.abs(right), 1);
39665
+ return Math.abs(left - right) <= Math.max(absoluteToleranceUsd, reference * relativeTolerance);
39666
+ };
39667
+ balancesMirrorUnifiedAccountValue = (input) => input.perpsEquity > 0 && input.spotEquity > 0 && input.balancesEquity > 0 && approximatelyEqual(
39668
+ input.perpsEquity,
39669
+ input.spotEquity,
39670
+ input.absoluteToleranceUsd,
39671
+ input.relativeTolerance
39672
+ ) && approximatelyEqual(
39673
+ input.spotEquity,
39674
+ input.balancesEquity,
39675
+ input.absoluteToleranceUsd,
39676
+ input.relativeTolerance
39677
+ );
39678
+ computeEffectiveAccountValue = (input) => {
39679
+ if (!input.unifiedLike) return input.perpsEquity;
39680
+ if (input.balancesEquity > 0) {
39681
+ if (input.mirrored) {
39682
+ return Math.max(input.perpsEquity, input.spotEquity, input.balancesEquity);
39683
+ }
39684
+ return Math.max(
39685
+ input.perpsEquity + input.balancesEquity,
39686
+ input.spotEquity,
39687
+ input.balancesEquity
39688
+ );
39689
+ }
39690
+ return Math.max(input.perpsEquity, input.spotEquity);
39691
+ };
39692
+ equityFormula = (input) => {
39693
+ if (!input.unifiedLike) return "perps_account_value";
39694
+ if (input.balancesEquity > 0) {
39695
+ if (input.mirrored) return "unified_mirrored_balances_equity";
39696
+ if (input.perpsEquity + input.balancesEquity >= Math.max(input.spotEquity, input.balancesEquity)) return "unified_perps_plus_balances";
39697
+ if (input.spotEquity >= input.balancesEquity) return "unified_spot_account_value";
39698
+ return "unified_balances_equity";
39699
+ }
39700
+ return input.perpsEquity >= input.spotEquity ? "unified_perps_account_value" : "unified_spot_account_value";
39701
+ };
39702
+ buildServerPromptRescueAccountSummary = (perpsResponse, spotResponse, accountMode, options = {}) => {
39703
+ const perps = perpsResponse && typeof perpsResponse === "object" && !Array.isArray(perpsResponse) ? perpsResponse : {};
39704
+ const marginSummary = perps.marginSummary && typeof perps.marginSummary === "object" && !Array.isArray(perps.marginSummary) ? perps.marginSummary : {};
39705
+ const crossMarginSummary = perps.crossMarginSummary && typeof perps.crossMarginSummary === "object" && !Array.isArray(perps.crossMarginSummary) ? perps.crossMarginSummary : {};
39706
+ const rawPerpsAccountValue = toNumber2(marginSummary.accountValue);
39707
+ const perpsAccountValue = Math.max(0, rawPerpsAccountValue);
39708
+ const crossMarginAccountValue = toNumber2(crossMarginSummary.accountValue);
39709
+ let totalMarginUsed = toNumber2(marginSummary.totalMarginUsed);
39710
+ let withdrawable = toNumber2(perps.withdrawable);
39711
+ const spot = accountMode === "disabled" ? { accountValue: 0, totalMarginUsed: 0, withdrawable: 0, balances: [] } : extractCanonicalSpotMetrics(spotResponse);
39712
+ const balances = spot.balances;
39713
+ const balancesEquity = sumBalanceValueUsd(balances);
39714
+ const unifiedLike = isUnifiedAccountMode(accountMode);
39715
+ if (unifiedLike) {
39716
+ totalMarginUsed = Math.max(totalMarginUsed, spot.totalMarginUsed);
39717
+ withdrawable = Math.max(withdrawable, spot.withdrawable);
39718
+ }
39719
+ const absoluteToleranceUsd = firstNumber2([
39720
+ options.mirroredAccountValueAbsoluteToleranceUsd,
39721
+ options.mirrored_account_value_absolute_tolerance_usd
39722
+ ]);
39723
+ const relativeTolerance = firstNumber2([
39724
+ options.mirroredAccountValueRelativeTolerance,
39725
+ options.mirrored_account_value_relative_tolerance
39726
+ ]);
39727
+ const mirrored = balancesMirrorUnifiedAccountValue({
39728
+ perpsEquity: perpsAccountValue,
39729
+ spotEquity: Math.max(spot.accountValue, 0),
39730
+ balancesEquity,
39731
+ absoluteToleranceUsd,
39732
+ relativeTolerance
39733
+ });
39734
+ const formulaInput = {
39735
+ perpsEquity: perpsAccountValue,
39736
+ spotEquity: Math.max(spot.accountValue, 0),
39737
+ balancesEquity,
39738
+ unifiedLike,
39739
+ mirrored
39740
+ };
39741
+ const accountValue = computeEffectiveAccountValue(formulaInput);
39742
+ const maintenanceMargin = toNumber2(perps.crossMaintenanceMarginUsed);
39743
+ const calculatedAvailable = accountValue - totalMarginUsed;
39744
+ const availableMargin = maintenanceMargin > 0 ? Math.max(
39745
+ calculatedAvailable,
39746
+ Math.max(0, accountValue - 4 * maintenanceMargin),
39747
+ withdrawable
39748
+ ) : Math.max(calculatedAvailable, withdrawable);
39749
+ let totalNotional = 0;
39750
+ let totalUnrealizedPnl = 0;
39751
+ const positions = Array.isArray(perps.assetPositions) ? perps.assetPositions : [];
39752
+ for (const entry of positions) {
39753
+ const position = entry && typeof entry === "object" && !Array.isArray(entry) ? entry.position : null;
39754
+ if (!position || typeof position !== "object" || Array.isArray(position)) continue;
39755
+ const size = toNumber2(position.szi);
39756
+ const unrealizedPnl = toNumber2(position.unrealizedPnl);
39757
+ totalUnrealizedPnl += unrealizedPnl;
39758
+ totalNotional += Math.abs(size * toNumber2(position.entryPx) + unrealizedPnl);
39759
+ }
39760
+ return {
39761
+ account_value: accountValue,
39762
+ total_margin_used: totalMarginUsed,
39763
+ available_margin: availableMargin,
39764
+ withdrawable,
39765
+ cross_margin_ratio: accountValue > 0 ? maintenanceMargin / accountValue : 0,
39766
+ maintenance_margin: maintenanceMargin,
39767
+ cross_account_leverage: accountValue > 0 ? totalNotional / accountValue : 0,
39768
+ total_unrealized_pnl: totalUnrealizedPnl,
39769
+ account_mode: accountMode,
39770
+ mode_source: "canonical",
39771
+ balances,
39772
+ raw_account_value: rawPerpsAccountValue,
39773
+ cross_margin_account_value: crossMarginAccountValue,
39774
+ spot_account_value: spot.accountValue,
39775
+ balances_equity: balancesEquity,
39776
+ equity_formula: equityFormula(formulaInput),
39777
+ balance_trust_classification: "trusted_canonical"
39778
+ };
39779
+ };
39780
+ }
39781
+ });
39782
+
38458
39783
  // lib/runtime/abort.ts
38459
39784
  var ABORT_MESSAGE_TOKENS, readAbortLikeMessage, isAbortLikeError;
38460
39785
  var init_abort = __esm({
@@ -39021,6 +40346,8 @@ var init_hyperliquid_account_state_adapter = __esm({
39021
40346
  init_sort_utils();
39022
40347
  init_hyperliquid_account_contract();
39023
40348
  init_hyperliquid_active_asset_contract();
40349
+ init_hyperliquid_account_mode_contract();
40350
+ init_server_prompt_rescue_account_contract();
39024
40351
  init_hyperliquid_market_symbol();
39025
40352
  init_network_debug();
39026
40353
  unsupportedUserActiveAssetCache = /* @__PURE__ */ new Set();
@@ -39136,13 +40463,15 @@ var init_hyperliquid_account_state_adapter = __esm({
39136
40463
  buildUserFillsStorageKey = (cacheKey) => {
39137
40464
  return `${USER_FILLS_CACHE_STORAGE_PREFIX}${cacheKey}`;
39138
40465
  };
39139
- buildAccountStateCacheKey = (apiUrl, walletAddress, symbol2, aggregatePerpDexs, dexNames, includeEffectiveTakerRate) => {
40466
+ buildAccountStateCacheKey = (apiUrl, walletAddress, symbol2, aggregatePerpDexs, dexNames, includeEffectiveTakerRate, includeExactAccountMode, includeActiveAssetData) => {
39140
40467
  return [
39141
40468
  apiUrl.replace(/\/$/, "").toLowerCase(),
39142
40469
  walletAddress.trim().toLowerCase(),
39143
40470
  normalizeHyperliquidMarketSymbol(symbol2),
39144
40471
  aggregatePerpDexs ? "aggregate" : "selected",
39145
40472
  includeEffectiveTakerRate ? "with-effective-taker-rate" : "without-effective-taker-rate",
40473
+ includeExactAccountMode ? "with-exact-account-mode" : "without-exact-account-mode",
40474
+ includeActiveAssetData ? "with-active-asset" : "without-active-asset",
39146
40475
  ...dexNames.map(normalizePerpDexName).sort()
39147
40476
  ].join("::");
39148
40477
  };
@@ -39352,7 +40681,8 @@ var init_hyperliquid_account_state_adapter = __esm({
39352
40681
  accountSummary: { ...result2.accountSummary },
39353
40682
  availableToTrade: { ...result2.availableToTrade },
39354
40683
  positions: result2.positions.map((position) => ({ ...position })),
39355
- ...result2.takerRate == null ? {} : { takerRate: result2.takerRate }
40684
+ ...result2.takerRate == null ? {} : { takerRate: result2.takerRate },
40685
+ ...result2.promptRescueEvidence == null ? {} : { promptRescueEvidence: { ...result2.promptRescueEvidence } }
39356
40686
  });
39357
40687
  readBrowserAccountStateCache = (cacheKey) => {
39358
40688
  const memoryEntry = browserAccountStateCache.get(cacheKey);
@@ -39382,7 +40712,8 @@ var init_hyperliquid_account_state_adapter = __esm({
39382
40712
  accountSummary: { ...result2.accountSummary || {} },
39383
40713
  availableToTrade: { ...result2.availableToTrade || {} },
39384
40714
  positions: Array.isArray(result2.positions) ? result2.positions.filter((position) => position !== null && typeof position === "object" && !Array.isArray(position)).map((position) => ({ ...position })) : [],
39385
- ...result2.takerRate == null ? {} : { takerRate: Number(result2.takerRate) }
40715
+ ...result2.takerRate == null ? {} : { takerRate: Number(result2.takerRate) },
40716
+ ...result2.promptRescueEvidence == null ? {} : { promptRescueEvidence: { ...result2.promptRescueEvidence } }
39386
40717
  }
39387
40718
  };
39388
40719
  if (entry.result.takerRate != null && (!Number.isFinite(entry.result.takerRate) || entry.result.takerRate < 0 || entry.result.takerRate >= 1)) {
@@ -39810,6 +41141,8 @@ var init_hyperliquid_account_state_adapter = __esm({
39810
41141
  const activeAssetRequestTypes = getBrowserActiveAssetTypeCandidates(apiUrl, walletAddress, symbol2);
39811
41142
  const aggregatePerpDexs = input.aggregatePerpDexs !== false;
39812
41143
  const includeEffectiveTakerRate = input.includeEffectiveTakerRate === true;
41144
+ const includeExactAccountMode = input.includeExactAccountMode === true;
41145
+ const includeActiveAssetData = input.includeActiveAssetData !== false;
39813
41146
  const dexNames = listPerpDexsForAccountState(input.config, dex, aggregatePerpDexs);
39814
41147
  const cacheKey = buildAccountStateCacheKey(
39815
41148
  apiUrl,
@@ -39817,7 +41150,9 @@ var init_hyperliquid_account_state_adapter = __esm({
39817
41150
  symbol2,
39818
41151
  aggregatePerpDexs,
39819
41152
  dexNames,
39820
- includeEffectiveTakerRate
41153
+ includeEffectiveTakerRate,
41154
+ includeExactAccountMode,
41155
+ includeActiveAssetData
39821
41156
  );
39822
41157
  const now = Date.now();
39823
41158
  const cached2 = readBrowserAccountStateCache(cacheKey);
@@ -39828,7 +41163,8 @@ var init_hyperliquid_account_state_adapter = __esm({
39828
41163
  "clearinghouseState",
39829
41164
  "spotClearinghouseState",
39830
41165
  ...includeEffectiveTakerRate ? ["userFees"] : [],
39831
- ...activeAssetRequestTypes
41166
+ ...includeExactAccountMode ? ["userAbstraction", "userDexAbstraction"] : [],
41167
+ ...includeActiveAssetData ? activeAssetRequestTypes : []
39832
41168
  ], now)) {
39833
41169
  return cloneBrowserAccountStateResult(cached2.result);
39834
41170
  }
@@ -39906,20 +41242,29 @@ var init_hyperliquid_account_state_adapter = __esm({
39906
41242
  return prefixHip3PositionCoins(response, dexName);
39907
41243
  })
39908
41244
  );
39909
- return aggregateClearinghouseResponses([defaultResponse, ...dexResponses]);
41245
+ return {
41246
+ payload: aggregateClearinghouseResponses([defaultResponse, ...dexResponses]),
41247
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString()
41248
+ };
39910
41249
  })();
39911
- const spotPromise = fetchHyperliquidInfoPayload(
39912
- apiUrl,
39913
- { type: "spotClearinghouseState", user: walletAddress },
39914
- input.signal
39915
- ).catch((error48) => {
39916
- recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
39917
- if (input.forceRefresh || input.includeEffectiveTakerRate === true) {
39918
- throw error48;
41250
+ const spotPromise = (async () => {
41251
+ let payload;
41252
+ try {
41253
+ payload = await fetchHyperliquidInfoPayload(
41254
+ apiUrl,
41255
+ { type: "spotClearinghouseState", user: walletAddress },
41256
+ input.signal
41257
+ );
41258
+ } catch (error48) {
41259
+ recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
41260
+ if (input.forceRefresh || input.includeEffectiveTakerRate === true) {
41261
+ throw error48;
41262
+ }
41263
+ payload = {};
39919
41264
  }
39920
- return {};
39921
- });
39922
- const activeAssetPromise = (async () => {
41265
+ return { payload, capturedAt: (/* @__PURE__ */ new Date()).toISOString() };
41266
+ })();
41267
+ const activeAssetPromise = input.includeActiveAssetData === false ? Promise.resolve(null) : (async () => {
39923
41268
  let lastError = null;
39924
41269
  for (const typeName of activeAssetRequestTypes) {
39925
41270
  try {
@@ -39939,17 +41284,50 @@ var init_hyperliquid_account_state_adapter = __esm({
39939
41284
  }
39940
41285
  throw lastError instanceof Error ? lastError : new Error("Failed to fetch browser active asset data.");
39941
41286
  })();
39942
- const userFeesPromise = input.includeEffectiveTakerRate === true ? fetchHyperliquidInfoPayload(
39943
- apiUrl,
39944
- { type: "userFees", user: walletAddress },
39945
- input.signal
39946
- ) : Promise.resolve(null);
39947
- const [perpsResponse, spotResponse, activeAssetResult, userFeesResponse] = await Promise.all([
41287
+ const userFeesPromise = input.includeEffectiveTakerRate === true ? (async () => ({
41288
+ payload: await fetchHyperliquidInfoPayload(
41289
+ apiUrl,
41290
+ { type: "userFees", user: walletAddress },
41291
+ input.signal
41292
+ ),
41293
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString()
41294
+ }))() : Promise.resolve(null);
41295
+ const exactAccountModePromise = input.includeExactAccountMode === true ? (async () => {
41296
+ const userAbstraction = await fetchHyperliquidInfoPayload(
41297
+ apiUrl,
41298
+ { type: "userAbstraction", user: walletAddress },
41299
+ input.signal
41300
+ );
41301
+ const preliminaryMode = extractCanonicalHyperliquidAccountMode(userAbstraction);
41302
+ if (!preliminaryMode) {
41303
+ throw new Error("Exact Hyperliquid userAbstraction response is invalid.");
41304
+ }
41305
+ let userDexAbstraction;
41306
+ if (preliminaryMode === "default" || preliminaryMode === "disabled") {
41307
+ userDexAbstraction = await fetchHyperliquidInfoPayload(
41308
+ apiUrl,
41309
+ { type: "userDexAbstraction", user: walletAddress },
41310
+ input.signal
41311
+ );
41312
+ }
41313
+ return {
41314
+ accountMode: resolveExactHyperliquidAccountMode(
41315
+ userAbstraction,
41316
+ userDexAbstraction
41317
+ ),
41318
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString()
41319
+ };
41320
+ })() : Promise.resolve(null);
41321
+ const [perpsResult, spotResult, activeAssetResult, userFeesResult, exactAccountMode] = await Promise.all([
39948
41322
  perpsPromise,
39949
41323
  spotPromise,
39950
41324
  activeAssetPromise,
39951
- userFeesPromise
41325
+ userFeesPromise,
41326
+ exactAccountModePromise
39952
41327
  ]);
41328
+ const perpsResponse = perpsResult.payload;
41329
+ const spotResponse = spotResult.payload;
41330
+ const userFeesResponse = userFeesResult?.payload ?? null;
39953
41331
  if (input.includeEffectiveTakerRate === true) {
39954
41332
  requirePromptSpotState(spotResponse);
39955
41333
  }
@@ -39969,20 +41347,32 @@ var init_hyperliquid_account_state_adapter = __esm({
39969
41347
  takerRate = parsedUserCrossRate;
39970
41348
  }
39971
41349
  const accountStateConfig = input.config.client_runtime_hyperliquid_account_state;
39972
- const normalizedSummary = buildAccountSummaryFromInfoResponses(perpsResponse, spotResponse, {
41350
+ const summaryPerpsResponse = exactAccountMode ? { ...perpsResponse, accountMode: exactAccountMode.accountMode } : perpsResponse;
41351
+ const accountSummaryOptions = {
39973
41352
  spotDominatesMinTotalUsd: accountStateConfig?.spot_dominates_min_total_usd,
39974
41353
  spotDominatesPerpsMultiplier: accountStateConfig?.spot_dominates_perps_multiplier,
39975
41354
  mirroredAccountValueAbsoluteToleranceUsd: accountStateConfig?.mirrored_account_value_absolute_tolerance_usd,
39976
41355
  mirroredAccountValueRelativeTolerance: accountStateConfig?.mirrored_account_value_relative_tolerance
39977
- });
41356
+ };
41357
+ const normalizedSummary = exactAccountMode ? buildServerPromptRescueAccountSummary(
41358
+ perpsResponse,
41359
+ spotResponse,
41360
+ exactAccountMode.accountMode,
41361
+ accountSummaryOptions
41362
+ ) : buildAccountSummaryFromInfoResponses(
41363
+ summaryPerpsResponse,
41364
+ spotResponse,
41365
+ accountSummaryOptions
41366
+ );
39978
41367
  const accountSummary = {
39979
41368
  ...normalizedSummary,
41369
+ ...exactAccountMode == null ? {} : { account_mode: exactAccountMode.accountMode, mode_source: "canonical" },
39980
41370
  address: walletAddress,
39981
41371
  dex: "all",
39982
41372
  market_type: "perp"
39983
41373
  };
39984
- const activeAssetPayload = activeAssetResult.payload;
39985
- const activeAssetType = activeAssetResult.type;
41374
+ const activeAssetPayload = activeAssetResult?.payload ?? null;
41375
+ const activeAssetType = activeAssetResult?.type ?? "promptAccountState";
39986
41376
  const normalizedActiveAsset = normalizeActiveAssetData(activeAssetPayload, symbol2);
39987
41377
  const markPrice = toPositiveFinite(normalizedActiveAsset.mark_price, toPositiveFinite(input.tickerPrice));
39988
41378
  const fallbackLeverage = toPositiveFinite(input.leverage, 1);
@@ -40000,7 +41390,17 @@ var init_hyperliquid_account_state_adapter = __esm({
40000
41390
  accountSummary,
40001
41391
  availableToTrade,
40002
41392
  positions: parseInfoPositions(perpsResponse),
40003
- ...takerRate == null ? {} : { takerRate }
41393
+ ...takerRate == null ? {} : { takerRate },
41394
+ ...exactAccountMode == null || userFeesResult == null ? {} : {
41395
+ promptRescueEvidence: {
41396
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
41397
+ perpsCapturedAt: perpsResult.capturedAt,
41398
+ spotCapturedAt: spotResult.capturedAt,
41399
+ feesCapturedAt: userFeesResult.capturedAt,
41400
+ accountModeCapturedAt: exactAccountMode.capturedAt,
41401
+ accountModeSource: "canonical"
41402
+ }
41403
+ }
40004
41404
  };
40005
41405
  };
40006
41406
  fetchBrowserUserFills = async (input) => {
@@ -51158,6 +52558,145 @@ var init_runtime_handoff = __esm({
51158
52558
  }
51159
52559
  });
51160
52560
 
52561
+ // lib/runtime/status-contract.ts
52562
+ var init_status_contract = __esm({
52563
+ "lib/runtime/status-contract.ts"() {
52564
+ "use strict";
52565
+ }
52566
+ });
52567
+
52568
+ // lib/runtime/error-surface-contract.ts
52569
+ var SENSITIVE_DB_TOKENS, SCHEMA_DISCLOSURE_TOKENS, SQL_STATEMENT_PATTERN, TRACEBACK_PATTERN, DB_SESSION_STATE_PATTERNS, isSensitiveRuntimeErrorDetail, EXECUTION_ERROR_DEFAULTS, isExecutionErrorReasonCode, RuntimeExecutionError, projectExecutionErrorContract;
52570
+ var init_error_surface_contract = __esm({
52571
+ "lib/runtime/error-surface-contract.ts"() {
52572
+ "use strict";
52573
+ init_status_contract();
52574
+ init_runtime_redaction();
52575
+ SENSITIVE_DB_TOKENS = [
52576
+ "sqlalchemy",
52577
+ "asyncpg",
52578
+ "psycopg",
52579
+ "dbapi",
52580
+ "programmingerror",
52581
+ "undefinedcolumnerror",
52582
+ "integrityerror",
52583
+ "statementerror",
52584
+ "queuepool",
52585
+ "postgresql",
52586
+ "sqlite"
52587
+ ];
52588
+ SCHEMA_DISCLOSURE_TOKENS = [
52589
+ " column ",
52590
+ " table ",
52591
+ " schema ",
52592
+ " relation ",
52593
+ " constraint "
52594
+ ];
52595
+ SQL_STATEMENT_PATTERN = /\b(select|insert|update|delete)\b[\s\S]{0,300}\bfrom\b/i;
52596
+ TRACEBACK_PATTERN = /traceback \(most recent call last\):/i;
52597
+ DB_SESSION_STATE_PATTERNS = [
52598
+ /\bthis session is in ['"]?\w+['"]? state\b/i,
52599
+ /\bno further sql can be emitted within this transaction\b/i,
52600
+ /\bcan(?:not|'t) reconnect until (?:the )?invalid transaction is rolled back\b/i,
52601
+ /\bthis session(?:'s)? transaction has been rolled back due to a previous exception\b/i,
52602
+ /\bthis transaction is (?:closed|inactive)\b/i,
52603
+ /\bthis session is provisioning a new connection; concurrent operations are not permitted\b/i,
52604
+ /\bthis session has been permanently closed\b/i,
52605
+ /\binvalid savepoint transaction\b/i
52606
+ ];
52607
+ isSensitiveRuntimeErrorDetail = (error48) => {
52608
+ const message = String(error48 || "").trim();
52609
+ if (!message) {
52610
+ return false;
52611
+ }
52612
+ const lowered = message.toLowerCase();
52613
+ if (TRACEBACK_PATTERN.test(lowered) || lowered.includes("[sql:")) {
52614
+ return true;
52615
+ }
52616
+ if (SENSITIVE_DB_TOKENS.some((token) => lowered.includes(token))) {
52617
+ return true;
52618
+ }
52619
+ if (DB_SESSION_STATE_PATTERNS.some((pattern) => pattern.test(message))) {
52620
+ return true;
52621
+ }
52622
+ return SQL_STATEMENT_PATTERN.test(lowered) && SCHEMA_DISCLOSURE_TOKENS.some((token) => ` ${lowered} `.includes(token));
52623
+ };
52624
+ EXECUTION_ERROR_DEFAULTS = {
52625
+ private_node_stale: ["preflight", "not_dispatched"],
52626
+ signer_validation_unavailable: ["preflight", "not_dispatched"],
52627
+ wallet_not_authorized: ["preflight", "not_dispatched"],
52628
+ credentials_missing: ["preflight", "not_dispatched"],
52629
+ local_safety_block: ["preflight", "not_dispatched"],
52630
+ redis_unavailable: ["coordination", "not_dispatched"],
52631
+ exchange_rejected: ["exchange_response", "confirmed_dispatched"],
52632
+ outcome_unknown: ["transport", "outcome_unknown"],
52633
+ internal_execution_error: ["execution", "unknown"]
52634
+ };
52635
+ isExecutionErrorReasonCode = (value) => Object.prototype.hasOwnProperty.call(EXECUTION_ERROR_DEFAULTS, value);
52636
+ RuntimeExecutionError = class extends Error {
52637
+ constructor(message, reasonCode) {
52638
+ super(message);
52639
+ this.name = "RuntimeExecutionError";
52640
+ this.reasonCode = reasonCode;
52641
+ this.executionStage = EXECUTION_ERROR_DEFAULTS[reasonCode][0];
52642
+ this.dispatchOutcome = EXECUTION_ERROR_DEFAULTS[reasonCode][1];
52643
+ }
52644
+ };
52645
+ projectExecutionErrorContract = (input) => {
52646
+ const {
52647
+ error: error48,
52648
+ symbol: symbol2 = null,
52649
+ reasonCode = null
52650
+ } = input;
52651
+ const typed = error48;
52652
+ const rawReason = String(reasonCode || typed?.reasonCode || "internal_execution_error").trim().toLowerCase();
52653
+ const resolvedReason = isExecutionErrorReasonCode(rawReason) ? rawReason : "internal_execution_error";
52654
+ const defaults = EXECUTION_ERROR_DEFAULTS[resolvedReason];
52655
+ const resolvedStage = defaults[0];
52656
+ const resolvedDispatch = defaults[1];
52657
+ const normalizedSymbol = String(symbol2 || "").trim();
52658
+ const orderLabel = normalizedSymbol ? `${normalizedSymbol} order` : "order";
52659
+ const rawMessage = sanitizeRuntimeDiagnosticValue(
52660
+ error48 instanceof Error ? error48.message : String(error48 || "").trim()
52661
+ );
52662
+ let message;
52663
+ if (resolvedReason === "private_node_stale") {
52664
+ message = `\u26A0\uFE0F The ${orderLabel} was not sent: Hyperliquid private account data was too stale to validate the signing key.`;
52665
+ } else if (resolvedReason === "signer_validation_unavailable") {
52666
+ message = `\u26A0\uFE0F The ${orderLabel} was not sent: Hyperliquid's private account service could not validate the signing key.`;
52667
+ } else if (resolvedReason === "wallet_not_authorized") {
52668
+ message = `\u26A0\uFE0F The ${orderLabel} was not sent: the signing key is not authorized for the configured wallet.`;
52669
+ } else if (resolvedReason === "credentials_missing") {
52670
+ message = `\u26A0\uFE0F The ${orderLabel} was not sent: a wallet address and authorized signing key are required for trading.`;
52671
+ } else if (resolvedReason === "local_safety_block") {
52672
+ const detail = isSensitiveRuntimeErrorDetail(rawMessage) ? "Local preflight validation failed." : rawMessage || "Local preflight validation failed.";
52673
+ const canonicalDetail = detail.replace(/^⚠️?\s*The (?:.+ )?order was not sent before exchange dispatch:\s*/i, "").trim() || "Local preflight validation failed.";
52674
+ message = `\u26A0\uFE0F The ${orderLabel} was not sent before exchange dispatch: ${canonicalDetail}`;
52675
+ } else if (resolvedReason === "redis_unavailable") {
52676
+ message = `\u26A0\uFE0F The ${orderLabel} was not sent because execution coordination was unavailable.`;
52677
+ } else if (resolvedReason === "exchange_rejected") {
52678
+ let detail = isSensitiveRuntimeErrorDetail(rawMessage) ? "The exchange did not provide safe rejection details." : rawMessage || "The exchange did not provide safe rejection details.";
52679
+ detail = detail.replace(/^⚠️?\s*Hyperliquid rejected the (?:.+ )?order:\s*/i, "").trim();
52680
+ detail = detail.replace(/^(?:Hyperliquid rejected order:|Order execution failed:|order execution failed:)\s*/, "");
52681
+ detail = detail.replace(/\s+asset=\d+\b\.?/g, "").trim() || "The exchange did not provide safe rejection details.";
52682
+ message = `\u26A0\uFE0F Hyperliquid rejected the ${orderLabel}: ${detail}`;
52683
+ } else if (resolvedReason === "outcome_unknown") {
52684
+ message = `\u26A0\uFE0F VTX could not confirm whether the ${orderLabel} was applied. Check open orders and the current position before retrying.`;
52685
+ } else {
52686
+ const detail = isSensitiveRuntimeErrorDetail(rawMessage) ? "VTX could not complete the exchange operation." : rawMessage || "VTX could not complete the exchange operation.";
52687
+ const canonicalDetail = detail.replace(/^⚠️?\s*VTX could not complete the (?:.+ )?order:\s*/i, "").trim() || "VTX could not complete the exchange operation.";
52688
+ message = `\u26A0\uFE0F VTX could not complete the ${orderLabel}: ${canonicalDetail}`;
52689
+ }
52690
+ return {
52691
+ reason_code: resolvedReason,
52692
+ execution_stage: resolvedStage,
52693
+ dispatch_outcome: resolvedDispatch,
52694
+ message
52695
+ };
52696
+ };
52697
+ }
52698
+ });
52699
+
51161
52700
  // lib/runtime/hyperliquid-client.ts
51162
52701
  var HyperliquidExchangeRejectionError, durableMutationAuthorityArgs, assertFreshPreparedExecutionContext, HYPERLIQUID_TERMINAL_ORDER_STATUSES, normalizeSymbol, HYPERLIQUID_NONCE_STORAGE_KEY, HYPERLIQUID_NONCE_LOCK_NAME, lastGeneratedNonce, readBrowserStoredHyperliquidNonce, writeBrowserStoredHyperliquidNonce, browserNonceCoordinator, allocateHyperliquidNonce, generateHyperliquidNonce, roundToSigFigs, normalizeDecimalString, toPlainDecimalString, roundDirectionalDecimalString, formatHyperliquidPerpPriceWire, formatHyperliquidTriggerPriceWire, countSignificantDigits, countDecimalPlaces, validateHyperliquidPerpPriceWire, validateHyperliquidSizeWire, formatSizeWire, inferApiUrl, inferIsTestnet, postHyperliquidInfo, toFiniteNumber, OPEN_ORDER_NUMERIC_STRING, OPEN_ORDER_ID_STRING, parseCanonicalOpenOrderId, parseOpenOrderFiniteNumber, parseOpenOrderPositiveNumber, parseOpenOrderPresentationNumber, readOpenOrderField, firstFiniteNumber2, parseFundingUsdcFromInfoPosition2, isExchangeIsolatedOnly, computeHip3AssetId, getPerpDexIndexMap, buildAssetInfosFromMetaResponse, requireWalletAddress2, assertPositiveInteger, assertPositiveNumber, normalizeOrderSide, normalizeHyperliquidClientOrderId, resolveAssets, findResolvedAsset, normalizeExecutionAssetMetadata, resolveHyperliquidAsset, resolveHyperliquidAssetIndex, fetchBrowserAvailableAssets, fetchBrowserAllMids, fetchBrowserSymbolMidPrice, fetchBrowserOpenOrders, parseCanonicalHyperliquidOrderStatusEvidence, fetchBrowserOrderStatusEvidence, fetchBrowserUserRole, fetchBrowserAccountState2, fetchBrowserPosition, buildHyperliquidOrderWire, buildHyperliquidTriggerOrderWire, signHyperliquidPayload, buildHyperliquidCancelPayload, buildHyperliquidUpdateLeveragePayload, buildHyperliquidMarketOrderPayload, buildHyperliquidTriggerOrderPayload, buildHyperliquidOrderBatchPayload, buildHyperliquidModifyOrderPayload, extractHyperliquidExchangeError, isDefinitiveHyperliquidExchangeResponse, extractDefinitiveHyperliquidOrderId, CANONICAL_POSITIVE_DECIMAL_PATTERN, extractCanonicalHyperliquidOrderStateAcknowledgement, extractCanonicalHyperliquidOrderStateAcknowledgements, extractCanonicalHyperliquidFilledOrderAcknowledgement, extractDefinitiveHyperliquidOrderMemberResults, buildHyperliquidOrderDiagnostics, loadClientExecutionReferenceEvidence, sha256Hex, extractSignedPayloadClientOrderId, extractSignedPayloadMutationCorrelation, assertDurableMutationMatchesSignedAction, submitHyperliquidExchangePayload;
51163
52702
  var init_hyperliquid_client = __esm({
@@ -51171,9 +52710,10 @@ var init_hyperliquid_client = __esm({
51171
52710
  init_runtime_redaction();
51172
52711
  init_exchange_mutation_fence();
51173
52712
  init_runtime_handoff();
51174
- HyperliquidExchangeRejectionError = class extends Error {
52713
+ init_error_surface_contract();
52714
+ HyperliquidExchangeRejectionError = class extends RuntimeExecutionError {
51175
52715
  constructor(message, orderDiagnostics, clientMutationId = null) {
51176
- super(message);
52716
+ super(message, "exchange_rejected");
51177
52717
  this.name = "HyperliquidExchangeRejectionError";
51178
52718
  this.orderDiagnostics = orderDiagnostics;
51179
52719
  this.clientMutationId = clientMutationId;
@@ -52871,8 +54411,9 @@ var init_hyperliquid_client = __esm({
52871
54411
  ...durableMutationAuthorityArgs(durableMutation)
52872
54412
  );
52873
54413
  if (beginResult.dispatch_authorized !== true) {
52874
- throw new Error(
52875
- "This exchange mutation was already recorded and will not be dispatched again. Durable reconciliation is required before retrying."
54414
+ throw new RuntimeExecutionError(
54415
+ "This exchange mutation was already recorded and will not be dispatched again. Durable reconciliation is required before retrying.",
54416
+ "local_safety_block"
52876
54417
  );
52877
54418
  }
52878
54419
  }
@@ -52895,8 +54436,9 @@ var init_hyperliquid_client = __esm({
52895
54436
  ...durableMutationAuthorityArgs(durableMutation)
52896
54437
  );
52897
54438
  } catch {
52898
- throw new Error(
52899
- "Exchange submission may have completed; durable reconciliation is pending."
54439
+ throw new RuntimeExecutionError(
54440
+ "Exchange submission may have completed; durable reconciliation is pending.",
54441
+ "outcome_unknown"
52900
54442
  );
52901
54443
  }
52902
54444
  };
@@ -52980,7 +54522,10 @@ var init_hyperliquid_client = __esm({
52980
54522
  assertFreshPreparedExecutionContext(input.preparedContext);
52981
54523
  } catch (preparedContextError) {
52982
54524
  await settleDurableMutation("rejected");
52983
- throw preparedContextError;
54525
+ throw new RuntimeExecutionError(
54526
+ preparedContextError instanceof Error ? preparedContextError.message : "Prepared exchange context expired before dispatch.",
54527
+ "local_safety_block"
54528
+ );
52984
54529
  }
52985
54530
  if (input.signal?.aborted) {
52986
54531
  await settleDurableMutation("rejected");
@@ -53012,8 +54557,9 @@ var init_hyperliquid_client = __esm({
53012
54557
  const payload = await response.json().catch(() => ({}));
53013
54558
  if (!response.ok) {
53014
54559
  await settleDurableMutation("transport_ambiguous");
53015
- throw new Error(
53016
- "Exchange submission may have completed; durable reconciliation is pending."
54560
+ throw new RuntimeExecutionError(
54561
+ "Exchange submission may have completed; durable reconciliation is pending.",
54562
+ "outcome_unknown"
53017
54563
  );
53018
54564
  }
53019
54565
  const exchangeError = extractHyperliquidExchangeError(payload);
@@ -53022,8 +54568,9 @@ var init_hyperliquid_client = __esm({
53022
54568
  exchangeError.partial ? "transport_ambiguous" : "rejected"
53023
54569
  );
53024
54570
  if (exchangeError.partial) {
53025
- throw new Error(
53026
- "Hyperliquid returned a partially applied exchange response; durable reconciliation is pending."
54571
+ throw new RuntimeExecutionError(
54572
+ "Hyperliquid returned a partially applied exchange response; durable reconciliation is pending.",
54573
+ "outcome_unknown"
53027
54574
  );
53028
54575
  }
53029
54576
  throw new HyperliquidExchangeRejectionError(
@@ -53037,8 +54584,9 @@ var init_hyperliquid_client = __esm({
53037
54584
  input.payload.action
53038
54585
  )) {
53039
54586
  await settleDurableMutation("transport_ambiguous");
53040
- throw new Error(
53041
- "Hyperliquid returned an incomplete exchange response; durable reconciliation is pending."
54587
+ throw new RuntimeExecutionError(
54588
+ "Hyperliquid returned an incomplete exchange response; durable reconciliation is pending.",
54589
+ "outcome_unknown"
53042
54590
  );
53043
54591
  }
53044
54592
  const exactExchangeOrderId = durableMutation?.operationKind === "order" ? extractDefinitiveHyperliquidOrderId(payload, input.payload.action) : null;
@@ -53060,12 +54608,14 @@ var init_hyperliquid_client = __esm({
53060
54608
  try {
53061
54609
  await settleDurableMutation("transport_ambiguous");
53062
54610
  } catch {
53063
- throw new Error(
53064
- "Exchange submission may have completed; durable reconciliation is pending."
54611
+ throw new RuntimeExecutionError(
54612
+ "Exchange submission may have completed; durable reconciliation is pending.",
54613
+ "outcome_unknown"
53065
54614
  );
53066
54615
  }
53067
- throw new Error(
53068
- "Exchange submission may have completed; durable reconciliation is pending."
54616
+ throw new RuntimeExecutionError(
54617
+ "Exchange submission may have completed; durable reconciliation is pending.",
54618
+ "outcome_unknown"
53069
54619
  );
53070
54620
  }
53071
54621
  throw error48;
@@ -53087,6 +54637,7 @@ var init_hyperliquid_signer_binding = __esm({
53087
54637
  "use strict";
53088
54638
  init_lib2();
53089
54639
  init_hyperliquid_client();
54640
+ init_error_surface_contract();
53090
54641
  normalizeAddress = (value, label) => {
53091
54642
  const normalized = String(value || "").trim().toLowerCase();
53092
54643
  if (!/^0x[0-9a-f]{40}$/.test(normalized)) {
@@ -53109,7 +54660,15 @@ var init_hyperliquid_signer_binding = __esm({
53109
54660
  return null;
53110
54661
  };
53111
54662
  assertBrowserHyperliquidSignerWalletBinding = async (input) => {
53112
- const walletAddress = normalizeAddress(input.walletAddress, "wallet address");
54663
+ let walletAddress;
54664
+ try {
54665
+ walletAddress = normalizeAddress(input.walletAddress, "wallet address");
54666
+ } catch {
54667
+ throw new RuntimeExecutionError(
54668
+ "A valid Hyperliquid wallet address is required for trading.",
54669
+ "credentials_missing"
54670
+ );
54671
+ }
53113
54672
  let signerAddress;
53114
54673
  try {
53115
54674
  signerAddress = normalizeAddress(
@@ -53117,13 +54676,25 @@ var init_hyperliquid_signer_binding = __esm({
53117
54676
  "signer address"
53118
54677
  );
53119
54678
  } catch {
53120
- throw new Error("Invalid Hyperliquid signing key.");
54679
+ throw new RuntimeExecutionError(
54680
+ "Invalid Hyperliquid signing key.",
54681
+ "credentials_missing"
54682
+ );
54683
+ }
54684
+ let roleResponse;
54685
+ try {
54686
+ roleResponse = await fetchBrowserUserRole({
54687
+ config: input.config ?? null,
54688
+ walletAddress: signerAddress,
54689
+ signal: input.signal
54690
+ });
54691
+ } catch (error48) {
54692
+ if (input.signal?.aborted) throw error48;
54693
+ throw new RuntimeExecutionError(
54694
+ "Hyperliquid's private account service could not validate the signing key.",
54695
+ "signer_validation_unavailable"
54696
+ );
53121
54697
  }
53122
- const roleResponse = await fetchBrowserUserRole({
53123
- config: input.config ?? null,
53124
- walletAddress: signerAddress,
53125
- signal: input.signal
53126
- });
53127
54698
  const signerRole = String(roleResponse.role || "").trim().toLowerCase();
53128
54699
  if (signerRole === "user" && signerAddress === walletAddress) {
53129
54700
  return {
@@ -53145,8 +54716,9 @@ var init_hyperliquid_signer_binding = __esm({
53145
54716
  };
53146
54717
  }
53147
54718
  }
53148
- throw new Error(
53149
- "The device Hyperliquid signing key is not authorized for this profile wallet. Stop the runtime and reconnect the wallet."
54719
+ throw new RuntimeExecutionError(
54720
+ "The device Hyperliquid signing key is not authorized for this profile wallet. Stop the runtime and reconnect the wallet.",
54721
+ "wallet_not_authorized"
53150
54722
  );
53151
54723
  };
53152
54724
  }
@@ -53881,6 +55453,7 @@ var init_browser_trading = __esm({
53881
55453
  "use strict";
53882
55454
  init_hyperliquid_client();
53883
55455
  init_hyperliquid_signer_binding();
55456
+ init_error_surface_contract();
53884
55457
  init_vault();
53885
55458
  resolveProfileId = (value) => {
53886
55459
  const profileId = String(value).trim();
@@ -53966,7 +55539,10 @@ var init_browser_trading = __esm({
53966
55539
  }
53967
55540
  }
53968
55541
  if (!signingKey) {
53969
- throw new Error("Missing required device-local Hyperliquid signing key for this profile. Configure it in System for this device.");
55542
+ throw new RuntimeExecutionError(
55543
+ "Missing required device-local Hyperliquid signing key for this profile. Configure it in System for this device.",
55544
+ "credentials_missing"
55545
+ );
53970
55546
  }
53971
55547
  return signingKey;
53972
55548
  };
@@ -53975,7 +55551,10 @@ var init_browser_trading = __esm({
53975
55551
  const signingKey = explicit || await loadSigningKey(resolveProfileId(input.profileId));
53976
55552
  const walletAddress = String(input.walletAddress || "").trim();
53977
55553
  if (!walletAddress) {
53978
- throw new Error("Missing wallet address for client Hyperliquid signing.");
55554
+ throw new RuntimeExecutionError(
55555
+ "Missing wallet address for client Hyperliquid signing.",
55556
+ "credentials_missing"
55557
+ );
53979
55558
  }
53980
55559
  await assertBrowserHyperliquidSignerWalletBinding({
53981
55560
  signingKey,
@@ -54484,6 +56063,7 @@ var init_runtime_execution = __esm({
54484
56063
  init_hyperliquid_market_symbol();
54485
56064
  init_network_debug();
54486
56065
  init_runtime_redaction();
56066
+ init_error_surface_contract();
54487
56067
  init_runtime_handoff();
54488
56068
  fetchClientRuntimeOpenOrders = async (request) => {
54489
56069
  const normalizedSymbol = normalizeHyperliquidMarketSymbol(
@@ -55961,6 +57541,7 @@ var init_runtime_execution = __esm({
55961
57541
  }
55962
57542
  }
55963
57543
  for (const candidate of candidates) {
57544
+ const rejectionProjection = error48 instanceof HyperliquidExchangeRejectionError ? projectExecutionErrorContract({ error: error48, symbol: symbol2 }) : null;
55964
57545
  reports.push({
55965
57546
  order_id: null,
55966
57547
  client_mutation_id: error48 instanceof HyperliquidExchangeRejectionError ? error48.clientMutationId ?? candidate.mutationId : candidate.mutationId,
@@ -55968,10 +57549,12 @@ var init_runtime_execution = __esm({
55968
57549
  action: candidate.kind === "sl" ? "AUTO_SL" : "AUTO_TP",
55969
57550
  status: error48 instanceof HyperliquidExchangeRejectionError ? "failed" : "blocked",
55970
57551
  execution_metadata: {
55971
- reason_code: error48 instanceof HyperliquidExchangeRejectionError ? "execution_error" : "protective_trigger_ack_unresolved",
55972
- error: getSanitizedRuntimeErrorMessage(error48) || "Protective trigger submission is unresolved.",
57552
+ reason_code: error48 instanceof HyperliquidExchangeRejectionError ? rejectionProjection?.reason_code : "protective_trigger_ack_unresolved",
57553
+ error: rejectionProjection?.message ?? getSanitizedRuntimeErrorMessage(error48) ?? "Protective trigger submission is unresolved.",
55973
57554
  ...error48 instanceof HyperliquidExchangeRejectionError ? {
55974
- execution_stage: "protective_trigger_order",
57555
+ execution_stage: rejectionProjection?.execution_stage,
57556
+ dispatch_outcome: rejectionProjection?.dispatch_outcome,
57557
+ operation_stage: "protective_trigger_order",
55975
57558
  entry_order_id: fill.orderId,
55976
57559
  order_diagnostics: error48.orderDiagnostics
55977
57560
  } : {}
@@ -59030,15 +60613,21 @@ var init_runtime_execution = __esm({
59030
60613
  execution_metadata: _toExecutionMetadata(marketOrderResponse)
59031
60614
  });
59032
60615
  const appendPostEntryProtectionFailure = (error48) => {
59033
- const message = getSanitizedRuntimeErrorMessage(error48) || "Unknown post-entry protection error.";
60616
+ const projection = projectExecutionErrorContract({
60617
+ error: error48,
60618
+ symbol: input.executionContext.symbol
60619
+ });
60620
+ const message = projection.message;
59034
60621
  executionReports.push({
59035
60622
  order_id: null,
59036
60623
  symbol: input.executionContext.symbol,
59037
60624
  action: "PROTECTIVE_RECONCILIATION",
59038
60625
  status: "failed",
59039
60626
  execution_metadata: {
59040
- reason_code: "execution_error",
59041
- execution_stage: "post_entry_protection",
60627
+ reason_code: projection.reason_code,
60628
+ execution_stage: projection.execution_stage,
60629
+ dispatch_outcome: projection.dispatch_outcome,
60630
+ operation_stage: "post_entry_protection",
59042
60631
  entry_order_id: _extractOrderId(marketOrderResponse),
59043
60632
  error: message
59044
60633
  }
@@ -59443,7 +61032,11 @@ var init_runtime_execution = __esm({
59443
61032
  );
59444
61033
  }
59445
61034
  } catch (triggerError) {
59446
- const message = getSanitizedRuntimeErrorMessage(triggerError) || "Unknown protective trigger order error.";
61035
+ const projection = projectExecutionErrorContract({
61036
+ error: triggerError,
61037
+ symbol: input.executionContext.symbol
61038
+ });
61039
+ const message = projection.message;
59447
61040
  const rejection = triggerError instanceof HyperliquidExchangeRejectionError ? triggerError : null;
59448
61041
  executionReports.push({
59449
61042
  order_id: null,
@@ -59454,8 +61047,10 @@ var init_runtime_execution = __esm({
59454
61047
  execution_metadata: {
59455
61048
  trigger_price: triggerInput.triggerPrice,
59456
61049
  is_take_profit: triggerInput.isTakeProfit,
59457
- reason_code: "execution_error",
59458
- execution_stage: "protective_trigger_order",
61050
+ reason_code: projection.reason_code,
61051
+ execution_stage: projection.execution_stage,
61052
+ dispatch_outcome: projection.dispatch_outcome,
61053
+ operation_stage: "protective_trigger_order",
59459
61054
  entry_order_id: _extractOrderId(marketOrderResponse),
59460
61055
  error: message,
59461
61056
  ...rejection ? { order_diagnostics: rejection.orderDiagnostics } : {}
@@ -59997,7 +61592,7 @@ var headless_local_worker_exports = {};
59997
61592
  __export(headless_local_worker_exports, {
59998
61593
  createHeadlessLocalWorker: () => createHeadlessLocalWorker
59999
61594
  });
60000
- import { randomUUID as randomUUID7 } from "node:crypto";
61595
+ import { randomUUID as randomUUID8 } from "node:crypto";
60001
61596
  function objectOrNull3(value) {
60002
61597
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
60003
61598
  }
@@ -60414,7 +62009,7 @@ function createHeadlessLocalWorker(options) {
60414
62009
  const statusMatch = errorText.match(/\b([45]\d{2})\b/);
60415
62010
  const statusCode = statusMatch ? Number(statusMatch[1]) : null;
60416
62011
  const failedInvocation = normalizeAiInvocationTelemetry({
60417
- client_invocation_id: randomUUID7(),
62012
+ client_invocation_id: randomUUID8(),
60418
62013
  use_case: "trader",
60419
62014
  role: "primary",
60420
62015
  attempt_index: 0,
@@ -60470,7 +62065,7 @@ function createHeadlessLocalWorker(options) {
60470
62065
  billable_cached_input_tokens: normalizedUsage.cached_input_tokens
60471
62066
  };
60472
62067
  const invocation = normalizeAiInvocationTelemetry({
60473
- client_invocation_id: randomUUID7(),
62068
+ client_invocation_id: randomUUID8(),
60474
62069
  use_case: "trader",
60475
62070
  role: "primary",
60476
62071
  attempt_index: 0,
@@ -60689,7 +62284,7 @@ var vtx_exports = {};
60689
62284
  __export(vtx_exports, {
60690
62285
  runVtxCli: () => runVtxCli
60691
62286
  });
60692
- import { randomUUID as randomUUID8 } from "node:crypto";
62287
+ import { randomUUID as randomUUID9 } from "node:crypto";
60693
62288
  import { spawn as spawn8 } from "node:child_process";
60694
62289
  function render2(value, json2) {
60695
62290
  if (json2) {
@@ -61103,8 +62698,8 @@ async function runVtxCli(argv2, env = process.env) {
61103
62698
  });
61104
62699
  return { exitCode: 0, stdout: render2(redactCliOutput(response2), json2), stderr: "" };
61105
62700
  }
61106
- const runtimeSessionId = randomUUID8();
61107
- const deviceId = config2.runtimeDeviceId ?? randomUUID8();
62701
+ const runtimeSessionId = randomUUID9();
62702
+ const deviceId = config2.runtimeDeviceId ?? randomUUID9();
61108
62703
  const response = await client.startRuntime(profileId, {
61109
62704
  session_id: runtimeSessionId,
61110
62705
  device_id: deviceId,