@vtxmacro/cli 2026.10.31 → 2026.10.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/vtx.js CHANGED
@@ -113,7 +113,7 @@ var init_routing = __esm({
113
113
  var agent_cli_release_default;
114
114
  var init_agent_cli_release = __esm({
115
115
  "agent-cli-release.json"() {
116
- agent_cli_release_default = { package_name: "@vtxmacro/cli", package_version: "2026.10.31", codex_package_name: "@openai/codex", codex_version: "0.155.0", copilot_sdk_package_name: "@github/copilot-sdk", copilot_sdk_version: "1.0.0-beta.8", copilot_cli_package_name: "@github/copilot", copilot_cli_version: "1.0.80", deepseek_harness_version: "0.1.1-rc.2", deepseek_harness_packages: ["@deepseek-ai/dsh-agent", "@deepseek-ai/dsh-agent-instructions", "@deepseek-ai/dsh-agent-loop", "@deepseek-ai/dsh-agent-spine-demo", "@deepseek-ai/dsh-anonymous-user-id", "@deepseek-ai/dsh-atomic-write", "@deepseek-ai/dsh-attachment", "@deepseek-ai/dsh-brand", "@deepseek-ai/dsh-code-runtime", "@deepseek-ai/dsh-credentials", "@deepseek-ai/dsh-fs", "@deepseek-ai/dsh-goal", "@deepseek-ai/dsh-goal-round-driver", "@deepseek-ai/dsh-home-paths", "@deepseek-ai/dsh-invariants", "@deepseek-ai/dsh-jobs", "@deepseek-ai/dsh-jobs-local", "@deepseek-ai/dsh-launch-environment", "@deepseek-ai/dsh-llm", "@deepseek-ai/dsh-llm-deepseek", "@deepseek-ai/dsh-llm-retry", "@deepseek-ai/dsh-output-retention", "@deepseek-ai/dsh-sandbox", "@deepseek-ai/dsh-sandbox-policy", "@deepseek-ai/dsh-scope", "@deepseek-ai/dsh-session", "@deepseek-ai/dsh-session-checkpoint-policy", "@deepseek-ai/dsh-session-persistence", "@deepseek-ai/dsh-session-persistence-jsonl", "@deepseek-ai/dsh-session-projection", "@deepseek-ai/dsh-session-title", "@deepseek-ai/dsh-settings", "@deepseek-ai/dsh-shell", "@deepseek-ai/dsh-shell-env", "@deepseek-ai/dsh-skill", "@deepseek-ai/dsh-skill-filesystem", "@deepseek-ai/dsh-subprocess", "@deepseek-ai/dsh-system-prompt", "@deepseek-ai/dsh-timeout", "@deepseek-ai/dsh-tool-bash", "@deepseek-ai/dsh-tool-goal", "@deepseek-ai/dsh-tool-jobs", "@deepseek-ai/dsh-tool-skill", "@deepseek-ai/dsh-tools", "@deepseek-ai/dsh-typert-protocol", "@deepseek-ai/dsh-user-approval"], deepseek_cordis_package_name: "@deepseek-ai/cordis", deepseek_cordis_version: "4.0.1", deepseek_support_packages: { "@deepseek-ai/cordis-plugin-timer": "1.1.3" }, platforms: { "linux-x64": { package_name: "@openai/codex-linux-x64", target: "x86_64-unknown-linux-musl", binary_name: "codex", sha256: "660e159a49e823ac8e5986cb238f73158ce4b957d40d9292f8de90862644b501" }, "win32-x64": { package_name: "@openai/codex-win32-x64", target: "x86_64-pc-windows-msvc", binary_name: "codex.exe", sha256: "e4c11374bd9de8ad5c3b7617fd4654bb7839901edb0863f9930666863c7a021b" } }, pi_coding_agent_package_name: "@earendil-works/pi-coding-agent", pi_ai_package_name: "@earendil-works/pi-ai", pi_version: "0.85.1", pi_support_packages: ["@earendil-works/pi-agent-core", "@earendil-works/pi-telemetry", "@earendil-works/pi-tui", "@earendil-works/chord"], grok_version: "1.0.30", grok_platforms: { "linux-x64": { package_name: "@xai-official/grok-linux-x64", binary_name: "grok", sha256: "504dd6546ab991b75d36698242875ce461489cd1f8cd84285873cb55bd5c7d54" }, "win32-x64": { package_name: "@xai-official/grok-win32-x64", binary_name: "grok.exe", sha256: "48736d1a4342a801ea26d0ecde4c516b653f791399065adaa55973f83abd8867" } } };
116
+ agent_cli_release_default = { package_name: "@vtxmacro/cli", package_version: "2026.10.33", codex_package_name: "@openai/codex", codex_version: "0.155.0", copilot_sdk_package_name: "@github/copilot-sdk", copilot_sdk_version: "1.0.0-beta.8", copilot_cli_package_name: "@github/copilot", copilot_cli_version: "1.0.80", deepseek_harness_version: "0.1.1-rc.2", deepseek_harness_packages: ["@deepseek-ai/dsh-agent", "@deepseek-ai/dsh-agent-instructions", "@deepseek-ai/dsh-agent-loop", "@deepseek-ai/dsh-agent-spine-demo", "@deepseek-ai/dsh-anonymous-user-id", "@deepseek-ai/dsh-atomic-write", "@deepseek-ai/dsh-attachment", "@deepseek-ai/dsh-brand", "@deepseek-ai/dsh-code-runtime", "@deepseek-ai/dsh-credentials", "@deepseek-ai/dsh-fs", "@deepseek-ai/dsh-goal", "@deepseek-ai/dsh-goal-round-driver", "@deepseek-ai/dsh-home-paths", "@deepseek-ai/dsh-invariants", "@deepseek-ai/dsh-jobs", "@deepseek-ai/dsh-jobs-local", "@deepseek-ai/dsh-launch-environment", "@deepseek-ai/dsh-llm", "@deepseek-ai/dsh-llm-deepseek", "@deepseek-ai/dsh-llm-retry", "@deepseek-ai/dsh-output-retention", "@deepseek-ai/dsh-sandbox", "@deepseek-ai/dsh-sandbox-policy", "@deepseek-ai/dsh-scope", "@deepseek-ai/dsh-session", "@deepseek-ai/dsh-session-checkpoint-policy", "@deepseek-ai/dsh-session-persistence", "@deepseek-ai/dsh-session-persistence-jsonl", "@deepseek-ai/dsh-session-projection", "@deepseek-ai/dsh-session-title", "@deepseek-ai/dsh-settings", "@deepseek-ai/dsh-shell", "@deepseek-ai/dsh-shell-env", "@deepseek-ai/dsh-skill", "@deepseek-ai/dsh-skill-filesystem", "@deepseek-ai/dsh-subprocess", "@deepseek-ai/dsh-system-prompt", "@deepseek-ai/dsh-timeout", "@deepseek-ai/dsh-tool-bash", "@deepseek-ai/dsh-tool-goal", "@deepseek-ai/dsh-tool-jobs", "@deepseek-ai/dsh-tool-skill", "@deepseek-ai/dsh-tools", "@deepseek-ai/dsh-typert-protocol", "@deepseek-ai/dsh-user-approval"], deepseek_cordis_package_name: "@deepseek-ai/cordis", deepseek_cordis_version: "4.0.1", deepseek_support_packages: { "@deepseek-ai/cordis-plugin-timer": "1.1.3" }, platforms: { "linux-x64": { package_name: "@openai/codex-linux-x64", target: "x86_64-unknown-linux-musl", binary_name: "codex", sha256: "660e159a49e823ac8e5986cb238f73158ce4b957d40d9292f8de90862644b501" }, "win32-x64": { package_name: "@openai/codex-win32-x64", target: "x86_64-pc-windows-msvc", binary_name: "codex.exe", sha256: "e4c11374bd9de8ad5c3b7617fd4654bb7839901edb0863f9930666863c7a021b" } }, pi_coding_agent_package_name: "@earendil-works/pi-coding-agent", pi_ai_package_name: "@earendil-works/pi-ai", pi_version: "0.85.1", pi_support_packages: ["@earendil-works/pi-agent-core", "@earendil-works/pi-telemetry", "@earendil-works/pi-tui", "@earendil-works/chord"], grok_version: "1.0.30", grok_platforms: { "linux-x64": { package_name: "@xai-official/grok-linux-x64", binary_name: "grok", sha256: "504dd6546ab991b75d36698242875ce461489cd1f8cd84285873cb55bd5c7d54" }, "win32-x64": { package_name: "@xai-official/grok-win32-x64", binary_name: "grok.exe", sha256: "48736d1a4342a801ea26d0ecde4c516b653f791399065adaa55973f83abd8867" } } };
117
117
  }
118
118
  });
119
119
 
@@ -1195,6 +1195,7 @@ var init_runtime_policy_generated = __esm({
1195
1195
  runtime: {
1196
1196
  assignment_page_default_limit: 20,
1197
1197
  client_candidate_owner_lease_grace_ms: 6e4,
1198
+ bot_switch_max_retries: 2,
1198
1199
  client_server_heartbeats_per_owner_lease: 2,
1199
1200
  client_server_heartbeat_min_ms: 5e3,
1200
1201
  client_server_heartbeat_max_ms: 3e4
@@ -1472,7 +1473,7 @@ var init_runtime_policy_generated = __esm({
1472
1473
  });
1473
1474
 
1474
1475
  // lib/constants.ts
1475
- var MS_PER_SECOND, SECONDS_PER_MINUTE, MINUTES_PER_HOUR, HOURS_PER_DAY, DAYS_PER_WEEK, MS_PER_MINUTE, SECONDS_PER_HOUR, SECONDS_PER_DAY, SECONDS_PER_WEEK, MINUTES_PER_DAY, MINUTES_PER_WEEK, MS_PER_HOUR, MS_PER_DAY, READ_STAMP_TIE_MS, READ_STAMP_STEP_BACK_MS, CLOCK_FIELD_DIGITS, BACKOFF_GROWTH_FACTOR, BYTES_PER_KIB, BYTES_PER_MIB, BITS_PER_BYTE, BYTE_MASK, OWNER_ONLY_FILE_MODE, OWNER_ONLY_DIRECTORY_MODE, GROUP_OTHER_PERMISSION_BITS, DECIMAL_RADIX, HEX_RADIX, BASE36_RADIX, BYTE_HEX_DIGITS, UINT32_HEX_DIGITS, RANDOM_FRACTION_PREFIX_LENGTH, PERCENT_SCALE, MIDPOINT_DIVISOR, SQUARE_EXPONENT, FNV1A_32_OFFSET_BASIS, FNV1A_32_PRIME, JSON_INDENT_SPACES, INT32_MIN, INT32_MAX, SET_TIMEOUT_MAX_DELAY_MS, POSITION_SIZE_EPSILON, CANDLE_TIMEFRAME_SECONDS, HTTP_STATUS, HTTP_STATUS_MIN, HTTP_STATUS_MAX, HTTP_CLIENT_ERROR_MIN, HTTP_SERVER_ERROR_MIN, PROMPT_RESCUE_ASKS_PER_CYCLE_BUILD, USD_DISPLAY_DECIMALS, AI_COST_ESTIMATE_PERIOD_DAYS, SECONDS_PER_AI_COST_ESTIMATE_PERIOD, DATE_FIELD_DIGITS, EXTERNAL_INFERENCE_LIMITS, NODE_ARGV_COMMAND_ARGS_START, EXIT_CODE_TEMPFAIL, SHA256_INITIAL_STATE, SHA256_ROUND_CONSTANTS, SHA256, UINT64_HIGH_WORD_DIVISOR, CANONICAL_BASE64URL, INFERENCE_ENVELOPE_CRYPTO, EXTERNAL_INFERENCE_SCHEMA_BOUNDS, JSON_RPC_ERROR_CODES, INFERENCE_MCP_SCHEMA_PROBE_MAX_DEPTH, INFERENCE_HOST_PROCESS_LOCK_RECORD_SCHEMA_VERSION, INFERENCE_HOST_RECLAIM_GUARD_CREATE_PASSES, LINUX_PROC_STAT_COMM_TERMINATOR_CHARS, INFERENCE_HOST_RANDOM_BYTES, INFERENCE_OAUTH_TOKEN_MAX_LENGTH, INFERENCE_CREDENTIAL_WINDOWS_NOT_FOUND_EXIT_CODE, MACOS_SECURITY_ITEM_NOT_FOUND_EXIT_CODE, INFERENCE_CREDENTIAL_LABEL_ACCOUNT_KEY_CHARS, INFERENCE_HOST_STABLE_OPERATION_ID_HASH_CHARS, INFERENCE_HOST_DRAIN_PRIORITY, INFERENCE_JOB_CLAIM_SCHEMA_VERSION, INFERENCE_HOST_WINDOWS_TASK_IDENTITY_MAX_CHARS, INFERENCE_HOST_OWNER_ONLY_EXECUTABLE_MODE, WINDOWS_TASKKILL_PROCESS_NOT_FOUND_EXIT_CODE, INFERENCE_HOST_CLI_MAX_SERVICE_POSITIONALS, INFERENCE_HOST_CLI_MAX_COMMAND_POSITIONALS, INFERENCE_HOST_DISPLAY_NAME_MAX_CHARS, INFERENCE_HOST_REVOCATION_CHECKPOINT_MAX_CHARS, INFERENCE_HOST_MODEL_ID_MAX_CHARS, CODEX_RECOVERY_RECEIPT_MAX_CHARS, CODEX_HOSTED_ATTEMPT_PATH_SEGMENTS, CODEX_GUARDIAN_PROCESS_TOKEN_BYTES, CODEX_RATE_LIMIT_EXHAUSTED_PERCENT, INFERENCE_HOST_PROXY_TOKEN_BYTES, GROK_TOOL_SERVER_TOKEN_BYTES, GROK_NATIVE_SESSION_GROUP_NAME_MAX_CHARS, GROK_POLICY_TRANSPORT_MAX_BYTES, EXO_POLICY_MAX_TOOL_ROUNDS, EXO_POLICY_MAX_MODELS, EXO_POLICY_MODEL_NAME_MAX_CHARS, EXO_RUNTIME_VERSION_COMMIT_CHARS, PI_QUALIFIED_MODEL_ID_MAX_CHARS, PI_STRUCTURED_OUTPUT_MAX_DEPTH, PI_STRUCTURED_OUTPUT_MAX_PROPERTIES, INFERENCE_HOST_API_KEY_MIN_CHARS, INFERENCE_HOST_API_KEY_MAX_BYTES, INFERENCE_HOST_API_KEY_IDENTITY_HEX_CHARS, DEEPSEEK_HARNESS_NODE_LTS_MAJOR, DEEPSEEK_HARNESS_NODE_LTS_MIN_MINOR, DEEPSEEK_HARNESS_NODE_CURRENT_MAJOR, PROMPT_FIXED_DIGITS, PROMPT_SIGNIFICANT_DIGITS, PROMPT_NUMBER_MAX_DIGITS, PROMPT_RELATIVE_VOLUME_DIGITS, BINARY_RADIX, PROMPT_PRICE_INTEGER_THRESHOLD, PROMPT_MARGIN_UTILIZATION_DECIMALS, PROMPT_SYMBOL_MAX_CHARS, PROMPT_PARTIAL_UNIT_ROUND_UP_FRACTION, HALF_UP_ROUNDING_OFFSET, PROMPT_ENTRY_PRICE_MATCH_ABS_TOLERANCE, PROMPT_ENTRY_PRICE_MATCH_REL_TOLERANCE, DECISION_OUTPUT_EXAMPLE_TRADABILITY, INDICATOR_RSI_PERIOD, INDICATOR_ATR_PERIOD, INDICATOR_MACD_FAST_PERIOD, INDICATOR_MACD_SLOW_PERIOD, INDICATOR_MACD_SIGNAL_PERIOD, INDICATOR_BOLLINGER_PERIOD, INDICATOR_BOLLINGER_STD_DEV, INDICATOR_OSCILLATOR_MAX, EMA_SMOOTHING_NUMERATOR, PROMPT_EMA_PERIODS, JSON_UNICODE_ESCAPE_PREFIX_LENGTH, JSON_UNICODE_ESCAPE_HEX_DIGITS, JSON_CONTROL_CHARACTER_MAX, RUNTIME_DEBUG_SNIPPET_CHARS, RUNTIME_DEBUG_PROMPT_SNIPPET_CHARS, RUNTIME_DEBUG_TOKEN_PREFIX_CHARS, RUNTIME_DEBUG_USD_DECIMALS, REVIEW_FAILURE_DETAIL_MAX_CHARS, RUNTIME_LATENCY_SECONDS_DECIMALS, AI_SCHEDULE_CLOCK_PARTS, ESTIMATED_CHARS_PER_TOKEN, PROVIDER_ERROR_RAW_TEXT_MAX_CHARS, AI_CALL_COST_DECIMALS, PROVIDER_DIAGNOSTIC_LIMITS, AI_INVOCATION_CONTRACT_VERSION, AI_INVOCATION_TELEMETRY_LIMITS, PROVIDER_USAGE_DETAIL_LIMITS, HYPERLIQUID_EXCHANGE_SPECIFICATION, HYPERLIQUID_TPSL_BATCH_MIN_ORDERS, HYPERLIQUID_USER_FILLS_PROVIDER_PAGE_CAP, HYPERLIQUID_ROW_WEIGHTED_INFO_REQUESTS, HYPERLIQUID_INFO_ROWS_PER_EXTRA_WEIGHT, HYPERLIQUID_META_AND_ASSET_CTXS_PARTS, HYPERLIQUID_SIDE_PAIR_LENGTH, HYPERLIQUID_SIGNED_SIZE_MATCH_EXTRA_DECIMALS, HYPERLIQUID_OPEN_ORDERS_MAX_NESTING_DEPTH, ACCOUNT_PAYLOAD_MODE_SEARCH_MAX_DEPTH, HYPERLIQUID_ACCOUNT_ROUNDING_DECIMALS, HYPERLIQUID_UNREALIZED_PNL_ZERO_TOLERANCE, HYPERLIQUID_MAX_DEPLOYER_FEE_SCALE, HYPERLIQUID_DEPLOYER_FEE_SCALE_MULTIPLIER, HYPERLIQUID_GROWTH_MODE_FEE_FACTOR, HYPERLIQUID_ALIGNED_QUOTE_NON_DEPLOYER_FEE_FACTOR, HYPERLIQUID_CLOSE_SIZE_RELATIVE_TOLERANCE, HYPERLIQUID_POSITION_SIZE_MATCH_ABS_TOLERANCE, HYPERLIQUID_POSITION_SIZE_MATCH_RELATIVE_TOLERANCE, HYPERLIQUID_LOT_FLOOR_NOISE_DECIMALS, HYPERLIQUID_RECOVERY_BACKOFF_MAX_EXPONENT, HYPERLIQUID_RECOVERY_CONCURRENCY_GROWTH_FACTOR, UUID_BYTES, UUID_HEX_GROUP_ENDS, MSGPACK, CLIENT_RUNTIME_DEFAULT_RETRY_SECONDS, CLIENT_RUNTIME_PROVIDER_ATTEMPT_SUMMARY_MAX_CHARS, CLIENT_RUNTIME_HL_REQUEST_TYPE_MAX_CHARS, CLIENT_RUNTIME_DRAWDOWN_DEBUG_DECIMALS, CLIENT_PROTECTIVE_GROUP_VERSION, CLIENT_PROTECTIVE_TPSL_PAIR_LEGS, CLIENT_PROTECTIVE_FILL_MATCH_ABS_TOLERANCE, CLIENT_PROTECTIVE_FILL_MATCH_REL_TOLERANCE, CLIENT_CLOSE_FILL_EPSILON_ULPS, COPY_TRADING_SIZE_EPSILON, COPY_TRADING_RELATIVE_SIZE_TOLERANCE, COPY_TRADING_NOTIONAL_CAP_TOLERANCE_USD, CLIENT_ACCOUNT_PNL_NONZERO_MIN_USD, RUNTIME_PORTFOLIO_PERIOD_ENTRY_LENGTH, CLIENT_EXCHANGE_RECONCILIATION_MAX_DELAY_MS, RFC1918_172_BLOCK_SECOND_OCTET, AGENT_CLI_TAKEOVER_REQUIRED_EXIT_CODE, EXIT_CODE_INTERRUPTED, EXIT_CODE_SIGNAL_BASE, BYOK_PROVIDER_DISPLAY_ORDER_STEP, TOKENS_PER_MILLION, RENDER_DEBUG_ID_RANDOM_CHARS;
1476
+ var MS_PER_SECOND, SECONDS_PER_MINUTE, MINUTES_PER_HOUR, HOURS_PER_DAY, DAYS_PER_WEEK, MS_PER_MINUTE, SECONDS_PER_HOUR, SECONDS_PER_DAY, SECONDS_PER_WEEK, MINUTES_PER_DAY, MINUTES_PER_WEEK, MS_PER_HOUR, MS_PER_DAY, READ_STAMP_TIE_MS, READ_STAMP_STEP_BACK_MS, CLOCK_FIELD_DIGITS, BACKOFF_GROWTH_FACTOR, BYTES_PER_KIB, BYTES_PER_MIB, BITS_PER_BYTE, BYTE_MASK, OWNER_ONLY_FILE_MODE, OWNER_ONLY_DIRECTORY_MODE, GROUP_OTHER_PERMISSION_BITS, DECIMAL_RADIX, HEX_RADIX, BASE36_RADIX, BYTE_HEX_DIGITS, UINT32_HEX_DIGITS, RANDOM_FRACTION_PREFIX_LENGTH, PERCENT_SCALE, MIDPOINT_DIVISOR, SQUARE_EXPONENT, FNV1A_32_OFFSET_BASIS, FNV1A_32_PRIME, JSON_INDENT_SPACES, INT32_MIN, INT32_MAX, SET_TIMEOUT_MAX_DELAY_MS, POSITION_SIZE_EPSILON, CANDLE_TIMEFRAME_SECONDS, HTTP_STATUS, HTTP_STATUS_MIN, HTTP_STATUS_MAX, HTTP_CLIENT_ERROR_MIN, HTTP_SERVER_ERROR_MIN, PROMPT_RESCUE_ASKS_PER_CYCLE_BUILD, USD_DISPLAY_DECIMALS, AI_COST_ESTIMATE_PERIOD_DAYS, SECONDS_PER_AI_COST_ESTIMATE_PERIOD, DATE_FIELD_DIGITS, EXTERNAL_INFERENCE_LIMITS, NODE_ARGV_COMMAND_ARGS_START, EXIT_CODE_TEMPFAIL, SHA256_INITIAL_STATE, SHA256_ROUND_CONSTANTS, SHA256, UINT64_HIGH_WORD_DIVISOR, CANONICAL_BASE64URL, INFERENCE_ENVELOPE_CRYPTO, EXTERNAL_INFERENCE_SCHEMA_BOUNDS, JSON_RPC_ERROR_CODES, INFERENCE_MCP_SCHEMA_PROBE_MAX_DEPTH, INFERENCE_HOST_PROCESS_LOCK_RECORD_SCHEMA_VERSION, NATIVE_PROTECTION_RECORD_WITH_LOTS_VERSION, INFERENCE_HOST_RECLAIM_GUARD_CREATE_PASSES, LINUX_PROC_STAT_COMM_TERMINATOR_CHARS, INFERENCE_HOST_RANDOM_BYTES, INFERENCE_OAUTH_TOKEN_MAX_LENGTH, INFERENCE_CREDENTIAL_WINDOWS_NOT_FOUND_EXIT_CODE, MACOS_SECURITY_ITEM_NOT_FOUND_EXIT_CODE, INFERENCE_CREDENTIAL_LABEL_ACCOUNT_KEY_CHARS, INFERENCE_HOST_STABLE_OPERATION_ID_HASH_CHARS, INFERENCE_HOST_DRAIN_PRIORITY, INFERENCE_JOB_CLAIM_SCHEMA_VERSION, INFERENCE_HOST_WINDOWS_TASK_IDENTITY_MAX_CHARS, INFERENCE_HOST_OWNER_ONLY_EXECUTABLE_MODE, WINDOWS_TASKKILL_PROCESS_NOT_FOUND_EXIT_CODE, INFERENCE_HOST_CLI_MAX_SERVICE_POSITIONALS, INFERENCE_HOST_CLI_MAX_COMMAND_POSITIONALS, INFERENCE_HOST_DISPLAY_NAME_MAX_CHARS, INFERENCE_HOST_REVOCATION_CHECKPOINT_MAX_CHARS, INFERENCE_HOST_MODEL_ID_MAX_CHARS, CODEX_RECOVERY_RECEIPT_MAX_CHARS, CODEX_HOSTED_ATTEMPT_PATH_SEGMENTS, CODEX_GUARDIAN_PROCESS_TOKEN_BYTES, CODEX_RATE_LIMIT_EXHAUSTED_PERCENT, INFERENCE_HOST_PROXY_TOKEN_BYTES, GROK_TOOL_SERVER_TOKEN_BYTES, GROK_NATIVE_SESSION_GROUP_NAME_MAX_CHARS, GROK_POLICY_TRANSPORT_MAX_BYTES, EXO_POLICY_MAX_TOOL_ROUNDS, EXO_POLICY_MAX_MODELS, EXO_POLICY_MODEL_NAME_MAX_CHARS, EXO_RUNTIME_VERSION_COMMIT_CHARS, PI_QUALIFIED_MODEL_ID_MAX_CHARS, PI_STRUCTURED_OUTPUT_MAX_DEPTH, PI_STRUCTURED_OUTPUT_MAX_PROPERTIES, INFERENCE_HOST_API_KEY_MIN_CHARS, INFERENCE_HOST_API_KEY_MAX_BYTES, INFERENCE_HOST_API_KEY_IDENTITY_HEX_CHARS, DEEPSEEK_HARNESS_NODE_LTS_MAJOR, DEEPSEEK_HARNESS_NODE_LTS_MIN_MINOR, DEEPSEEK_HARNESS_NODE_CURRENT_MAJOR, PROMPT_FIXED_DIGITS, PROMPT_SIGNIFICANT_DIGITS, PROMPT_NUMBER_MAX_DIGITS, PROMPT_RELATIVE_VOLUME_DIGITS, BINARY_RADIX, PROMPT_PRICE_INTEGER_THRESHOLD, PROMPT_MARGIN_UTILIZATION_DECIMALS, PROMPT_SYMBOL_MAX_CHARS, PROMPT_PARTIAL_UNIT_ROUND_UP_FRACTION, HALF_UP_ROUNDING_OFFSET, PROMPT_ENTRY_PRICE_MATCH_ABS_TOLERANCE, PROMPT_ENTRY_PRICE_MATCH_REL_TOLERANCE, DECISION_OUTPUT_EXAMPLE_TRADABILITY, INDICATOR_RSI_PERIOD, INDICATOR_ATR_PERIOD, INDICATOR_MACD_FAST_PERIOD, INDICATOR_MACD_SLOW_PERIOD, INDICATOR_MACD_SIGNAL_PERIOD, INDICATOR_BOLLINGER_PERIOD, INDICATOR_BOLLINGER_STD_DEV, INDICATOR_OSCILLATOR_MAX, EMA_SMOOTHING_NUMERATOR, PROMPT_EMA_PERIODS, JSON_UNICODE_ESCAPE_PREFIX_LENGTH, JSON_UNICODE_ESCAPE_HEX_DIGITS, JSON_CONTROL_CHARACTER_MAX, RUNTIME_DEBUG_SNIPPET_CHARS, RUNTIME_DEBUG_PROMPT_SNIPPET_CHARS, RUNTIME_DEBUG_TOKEN_PREFIX_CHARS, RUNTIME_DEBUG_USD_DECIMALS, REVIEW_FAILURE_DETAIL_MAX_CHARS, RUNTIME_LATENCY_SECONDS_DECIMALS, AI_SCHEDULE_CLOCK_PARTS, ESTIMATED_CHARS_PER_TOKEN, PROVIDER_ERROR_RAW_TEXT_MAX_CHARS, AI_CALL_COST_DECIMALS, PROVIDER_DIAGNOSTIC_LIMITS, AI_INVOCATION_CONTRACT_VERSION, AI_INVOCATION_TELEMETRY_LIMITS, PROVIDER_USAGE_DETAIL_LIMITS, HYPERLIQUID_EXCHANGE_SPECIFICATION, HYPERLIQUID_TPSL_BATCH_MIN_ORDERS, HYPERLIQUID_USER_FILLS_PROVIDER_PAGE_CAP, HYPERLIQUID_ROW_WEIGHTED_INFO_REQUESTS, HYPERLIQUID_INFO_ROWS_PER_EXTRA_WEIGHT, HYPERLIQUID_META_AND_ASSET_CTXS_PARTS, HYPERLIQUID_SIDE_PAIR_LENGTH, HYPERLIQUID_SIGNED_SIZE_MATCH_EXTRA_DECIMALS, HYPERLIQUID_OPEN_ORDERS_MAX_NESTING_DEPTH, ACCOUNT_PAYLOAD_MODE_SEARCH_MAX_DEPTH, HYPERLIQUID_ACCOUNT_ROUNDING_DECIMALS, HYPERLIQUID_UNREALIZED_PNL_ZERO_TOLERANCE, HYPERLIQUID_MAX_DEPLOYER_FEE_SCALE, HYPERLIQUID_DEPLOYER_FEE_SCALE_MULTIPLIER, HYPERLIQUID_GROWTH_MODE_FEE_FACTOR, HYPERLIQUID_ALIGNED_QUOTE_NON_DEPLOYER_FEE_FACTOR, HYPERLIQUID_CLOSE_SIZE_RELATIVE_TOLERANCE, HYPERLIQUID_POSITION_SIZE_MATCH_ABS_TOLERANCE, HYPERLIQUID_POSITION_SIZE_MATCH_RELATIVE_TOLERANCE, HYPERLIQUID_LOT_FLOOR_NOISE_DECIMALS, HYPERLIQUID_RECOVERY_BACKOFF_MAX_EXPONENT, HYPERLIQUID_RECOVERY_CONCURRENCY_GROWTH_FACTOR, UUID_BYTES, UUID_HEX_GROUP_ENDS, MSGPACK, CLIENT_RUNTIME_DEFAULT_RETRY_SECONDS, CLIENT_RUNTIME_PROVIDER_ATTEMPT_SUMMARY_MAX_CHARS, CLIENT_RUNTIME_HL_REQUEST_TYPE_MAX_CHARS, CLIENT_RUNTIME_DRAWDOWN_DEBUG_DECIMALS, CLIENT_PROTECTIVE_GROUP_VERSION, CLIENT_PROTECTIVE_TPSL_PAIR_LEGS, CLIENT_PROTECTIVE_FILL_MATCH_ABS_TOLERANCE, CLIENT_PROTECTIVE_FILL_MATCH_REL_TOLERANCE, CLIENT_CLOSE_FILL_EPSILON_ULPS, COPY_TRADING_SIZE_EPSILON, COPY_TRADING_RELATIVE_SIZE_TOLERANCE, COPY_TRADING_NOTIONAL_CAP_TOLERANCE_USD, CLIENT_ACCOUNT_PNL_NONZERO_MIN_USD, RUNTIME_PORTFOLIO_PERIOD_ENTRY_LENGTH, CLIENT_EXCHANGE_RECONCILIATION_MAX_DELAY_MS, RFC1918_172_BLOCK_SECOND_OCTET, AGENT_CLI_TAKEOVER_REQUIRED_EXIT_CODE, EXIT_CODE_INTERRUPTED, EXIT_CODE_SIGNAL_BASE, BYOK_PROVIDER_DISPLAY_ORDER_STEP, TOKENS_PER_MILLION, RENDER_DEBUG_ID_RANDOM_CHARS;
1476
1477
  var init_constants = __esm({
1477
1478
  "lib/constants.ts"() {
1478
1479
  "use strict";
@@ -1772,6 +1773,7 @@ var init_constants = __esm({
1772
1773
  };
1773
1774
  INFERENCE_MCP_SCHEMA_PROBE_MAX_DEPTH = 4;
1774
1775
  INFERENCE_HOST_PROCESS_LOCK_RECORD_SCHEMA_VERSION = 2;
1776
+ NATIVE_PROTECTION_RECORD_WITH_LOTS_VERSION = 2;
1775
1777
  INFERENCE_HOST_RECLAIM_GUARD_CREATE_PASSES = 2;
1776
1778
  LINUX_PROC_STAT_COMM_TERMINATOR_CHARS = 2;
1777
1779
  INFERENCE_HOST_RANDOM_BYTES = {
@@ -21025,6 +21027,7 @@ var init_runtime_policy_generated2 = __esm({
21025
21027
  runtime: {
21026
21028
  assignment_page_default_limit: 20,
21027
21029
  client_candidate_owner_lease_grace_ms: 6e4,
21030
+ bot_switch_max_retries: 2,
21028
21031
  client_server_heartbeats_per_owner_lease: 2,
21029
21032
  client_server_heartbeat_min_ms: 5e3,
21030
21033
  client_server_heartbeat_max_ms: 3e4
@@ -21860,8 +21863,8 @@ var init_external_inference_contract = __esm({
21860
21863
  if (value.runtime_binding.binding_kind !== value.execution_mode && !(value.runtime_binding.binding_kind === "historical_chat" && value.execution_mode === "server" && value.use_case === "decision_chat")) {
21861
21864
  context.addIssue({ code: "custom", message: "runtime binding must match execution_mode", path: ["runtime_binding", "binding_kind"] });
21862
21865
  }
21863
- if (value.lane === "screener" && value.runtime_binding.bot_mode !== "trader") {
21864
- context.addIssue({ code: "custom", message: "screener jobs require a confirmed trader binding", path: ["runtime_binding", "bot_mode"] });
21866
+ if (value.lane === "screener" && !["trader", "assistant"].includes(value.runtime_binding.bot_mode)) {
21867
+ context.addIssue({ code: "custom", message: "screener jobs require a confirmed bot binding", path: ["runtime_binding", "bot_mode"] });
21865
21868
  }
21866
21869
  if (value.controller.host_id !== value.host_id) {
21867
21870
  context.addIssue({ code: "custom", message: "controller host_id must match job host_id", path: ["controller", "host_id"] });
@@ -57836,6 +57839,7 @@ async function getLLMConfig(cookie, profileId, signal) {
57836
57839
  method: "GET",
57837
57840
  headers,
57838
57841
  credentials: "include",
57842
+ cache: "no-store",
57839
57843
  signal: requestSignal
57840
57844
  });
57841
57845
  if (held && response.status === HTTP_STATUS.NOT_MODIFIED) return JSON.parse(held.text);
@@ -57960,6 +57964,17 @@ var init_account_summary = __esm({
57960
57964
  }
57961
57965
  });
57962
57966
 
57967
+ // lib/api/mobile-notifications.ts
57968
+ var init_mobile_notifications = __esm({
57969
+ "lib/api/mobile-notifications.ts"() {
57970
+ "use strict";
57971
+ init_define_VTX_EXO_POLICY();
57972
+ init_define_VTX_GROK_POLICY();
57973
+ init_define_VTX_PI_MODEL_POLICY();
57974
+ init_shared();
57975
+ }
57976
+ });
57977
+
57963
57978
  // lib/runtime/hyperliquid-account-mode-contract.ts
57964
57979
  function resolveExactHyperliquidAccountMode(userAbstraction, ...dexEvidence) {
57965
57980
  const mode = extractCanonicalHyperliquidAccountMode(userAbstraction);
@@ -59393,9 +59408,15 @@ var init_runtime_error_reason_rules = __esm({
59393
59408
  { contains: "hyperliquid fresh public read returned non-json" },
59394
59409
  { contains: "hyperliquid public freshness bracket moved backwards" }
59395
59410
  ] } },
59396
- { reason_code: "behavior_state_unavailable", when: { all: [
59397
- { contains: "critical behavior context could not be constructed" },
59398
- { contains: "next scheduled cycle" }
59411
+ { reason_code: "behavior_state_unavailable", when: { any: [
59412
+ { all: [
59413
+ { contains: "your prompt on the ai page contains something vtx can't use" },
59414
+ { contains: "next scheduled cycle" }
59415
+ ] },
59416
+ { all: [
59417
+ { contains: "critical behavior context could not be constructed" },
59418
+ { contains: "next scheduled cycle" }
59419
+ ] }
59399
59420
  ] } },
59400
59421
  { reason_code: "hyperliquid_wallet_not_authorized", when: { any: [
59401
59422
  { contains: "hyperliquid api wallet is not authorized" },
@@ -59514,6 +59535,8 @@ var init_runtime_error_reason_rules = __esm({
59514
59535
  model_unavailable: { transient: false, severity: "ERROR" },
59515
59536
  outcome_unknown: { transient: true, severity: "ERROR" },
59516
59537
  private_node_stale: { transient: true, severity: "ERROR" },
59538
+ protective_order_not_placed: { transient: false, severity: "WARN" },
59539
+ protective_order_unmanaged: { transient: false, severity: "WARN" },
59517
59540
  provider_network_failure: { transient: true, severity: "ERROR" },
59518
59541
  provider_not_configured: { transient: false, severity: "ERROR" },
59519
59542
  provider_unavailable: { transient: true, severity: "ERROR" },
@@ -59869,9 +59892,12 @@ var init_error_surface_contract = __esm({
59869
59892
  const detailLower = normalizedDetail.toLowerCase();
59870
59893
  const classificationBasis = detailLower || lowered;
59871
59894
  const pausePrefix = runtimePausePrefix(Boolean(isAssistantActive));
59872
- if (classificationBasis.includes("critical behavior state is unavailable for this trading cycle")) {
59895
+ if (classificationBasis.includes("behavior memory is unavailable for this trading cycle")) {
59873
59896
  return `${pausePrefix}: Critical behavior context could not be constructed for this cycle. The cycle was skipped safely; VTX will retry at the next scheduled cycle.`;
59874
59897
  }
59898
+ if (classificationBasis.includes("critical behavior state is unavailable for this trading cycle")) {
59899
+ return `${pausePrefix}: Your prompt on the AI page contains something VTX can't use, for example a <behavior_state> line in the System Prompt that doesn't start with "- ". Fix the prompt; VTX skipped this cycle and will retry at the next scheduled cycle.`;
59900
+ }
59875
59901
  if (classificationBasis.includes(
59876
59902
  "client runtime decision persistence deadline exceeded after the ai run completed"
59877
59903
  )) {
@@ -68468,12 +68494,12 @@ function getKzgLibrary(kzg) {
68468
68494
  return { blobToKzgCommitment, computeBlobKzgProof };
68469
68495
  }
68470
68496
  function getVersionedHash(version3, hash5) {
68471
- let versioned = version3.toString(16);
68472
- while (versioned.length < 2) {
68473
- versioned = "0" + versioned;
68497
+ let versioned2 = version3.toString(16);
68498
+ while (versioned2.length < 2) {
68499
+ versioned2 = "0" + versioned2;
68474
68500
  }
68475
- versioned += sha2563(hash5).substring(4);
68476
- return "0x" + versioned;
68501
+ versioned2 += sha2563(hash5).substring(4);
68502
+ return "0x" + versioned2;
68477
68503
  }
68478
68504
  function handleAddress(value) {
68479
68505
  if (value === "0x") {
@@ -90550,7 +90576,7 @@ var init_hyperliquid_signer = __esm({
90550
90576
  });
90551
90577
 
90552
90578
  // lib/runtime/hyperliquid-client.ts
90553
- var HyperliquidExchangeRejectionError, durableMutationAuthorityArgs, assertFreshPreparedExecutionContext, normalizeSymbol, HYPERLIQUID_NONCE_STORAGE_KEY, HYPERLIQUID_NONCE_LOCK_NAME, lastGeneratedNonce, readBrowserStoredHyperliquidNonce, writeBrowserStoredHyperliquidNonce, browserNonceCoordinator, allocateHyperliquidNonce, hostNonceAllocator, allocateActionNonce, generateHyperliquidNonce, normalizeDecimalString, HYPERLIQUID_PRICE_SIGNIFICANT_FIGURES, HYPERLIQUID_INTEGER_PRICE_MINIMUM, shortestDecimalParts, formatHyperliquidPerpPriceGrid, formatHyperliquidTriggerPriceWire, hyperliquidOrderPriceRounding, formatHyperliquidOrderPriceWire, countSignificantDigits, countDecimalPlaces, validateHyperliquidPerpPriceWire, validateHyperliquidSizeWire, formatSizeWire, inferApiUrl, inferIsTestnet, postHyperliquidInfoRead, postHyperliquidInfo, fetchBrowserHyperliquidInfoPayload, fetchBrowserHyperliquidInfoRead, fetchBrowserHyperliquidInfoText, coerceMarketMaxLeverage, toFiniteNumber, OPEN_ORDER_NUMERIC_STRING, OPEN_ORDER_ID_STRING, parseCanonicalOpenOrderId, parseOpenOrderFiniteNumber, parseOpenOrderNonNegativeNumber, NATIVE_FIRED_TRIGGER_CONDITION, parseOpenOrderPositiveNumber, parseOpenOrderPresentationNumber, readOpenOrderField, firstFiniteNumber, parseFundingUsdcFromInfoPosition, isExchangeIsolatedOnly, resolveLeverageTarget, computeHip3AssetId, getPerpDexIndexMap, buildAssetInfosFromMetaResponse, requireWalletAddress, assertPositiveInteger, assertPositiveNumber, normalizeOrderSide, normalizeHyperliquidClientOrderId, resolveAssets, findResolvedAsset, normalizeExecutionAssetMetadata, resolveHyperliquidAsset, resolveHyperliquidAssetIndex, decimalUnits, quantizeHyperliquidOrderSizeValue, hyperliquidSignedSizeMatchesRequestedSize, finitePositive, readDevicePrivateExecutionContext, quantizeHyperliquidOrderSize, fetchBrowserAvailableAssets, fetchBrowserAllMids, fetchBrowserSymbolMidPrice, fetchBrowserOpenOrders, parseCanonicalHyperliquidOrderStatusEvidence, fetchBrowserOrderStatusEvidence, fetchBrowserUserRole, fetchBrowserAccountState, fetchBrowserPosition, buildHyperliquidOrderWire, buildHyperliquidTriggerOrderWire, signHyperliquidPayload, signHyperliquidPreparedAction, buildHyperliquidCancelPayload, buildHyperliquidUpdateLeveragePayload, buildHyperliquidMarketOrderPayload, buildHyperliquidLimitOrderPayload, buildHyperliquidTriggerOrderPayload, buildHyperliquidOrderBatchPayload, buildHyperliquidModifyOrderPayload, extractHyperliquidExchangeError, acknowledgementLookupPacing, lookupUntilListed, resolveHyperliquidTriggerAcknowledgements, resolveHyperliquidModifyAcknowledgement, isDefinitiveHyperliquidExchangeResponse, extractDefinitiveHyperliquidOrderId, CANONICAL_POSITIVE_DECIMAL_PATTERN, extractCanonicalHyperliquidOrderStateAcknowledgement, extractCanonicalHyperliquidOrderStateAcknowledgements, extractCanonicalHyperliquidFilledOrderAcknowledgement, extractDefinitiveHyperliquidOrderMemberResults, buildHyperliquidOrderDiagnostics, loadClientExecutionReferenceEvidence, sha256Hex, extractSignedPayloadClientOrderId, extractSignedPayloadMutationCorrelation, assertDurableMutationMatchesSignedAction, exchangeRejectionReason, exchangeActionPriority, submitHyperliquidExchangePayload;
90579
+ var HyperliquidExchangeRejectionError, durableMutationAuthorityArgs, assertFreshPreparedExecutionContext, normalizeSymbol, HYPERLIQUID_NONCE_STORAGE_KEY, HYPERLIQUID_NONCE_LOCK_NAME, lastGeneratedNonce, readBrowserStoredHyperliquidNonce, writeBrowserStoredHyperliquidNonce, browserNonceCoordinator, allocateHyperliquidNonce, hostNonceAllocator, allocateActionNonce, generateHyperliquidNonce, normalizeDecimalString, HYPERLIQUID_PRICE_SIGNIFICANT_FIGURES, HYPERLIQUID_INTEGER_PRICE_MINIMUM, shortestDecimalParts, formatHyperliquidPerpPriceGrid, formatHyperliquidTriggerPriceWire, hyperliquidOrderPriceRounding, formatHyperliquidOrderPriceWire, countSignificantDigits, countDecimalPlaces, validateHyperliquidPerpPriceWire, validateHyperliquidSizeWire, formatSizeWire, inferApiUrl, inferIsTestnet, postHyperliquidInfoRead, postHyperliquidInfo, fetchBrowserHyperliquidInfoPayload, fetchBrowserHyperliquidInfoRead, fetchBrowserHyperliquidInfoText, coerceMarketMaxLeverage, toFiniteNumber, OPEN_ORDER_NUMERIC_STRING, OPEN_ORDER_ID_STRING, parseCanonicalOpenOrderId, parseOpenOrderFiniteNumber, parseOpenOrderNonNegativeNumber, NATIVE_FIRED_TRIGGER_CONDITION, parseOpenOrderPositiveNumber, parseOpenOrderPresentationNumber, readOpenOrderField, firstFiniteNumber, parseFundingUsdcFromInfoPosition, isExchangeIsolatedOnly, resolveLeverageTarget, computeHip3AssetId, getPerpDexIndexMap, buildAssetInfosFromMetaResponse, requireWalletAddress, assertPositiveInteger, assertPositiveNumber, normalizeOrderSide, normalizeHyperliquidClientOrderId, resolveAssets, findResolvedAsset, normalizeExecutionAssetMetadata, resolveHyperliquidAsset, resolveHyperliquidAssetIndex, decimalUnits, quantizeHyperliquidOrderSizeValue, hyperliquidSignedSizeMatchesRequestedSize, finitePositive, readDevicePrivateExecutionContext, quantizeHyperliquidOrderSize, fetchBrowserAvailableAssets, fetchBrowserAllMids, fetchBrowserSymbolMidPrice, fetchBrowserOpenOrders, parseCanonicalHyperliquidOrderStatusEvidence, fetchBrowserOrderStatusEvidence, fetchBrowserUserRole, fetchBrowserAccountState, fetchBrowserPosition, buildHyperliquidOrderWire, buildHyperliquidTriggerOrderWire, signHyperliquidPayload, signHyperliquidPreparedAction, buildHyperliquidCancelPayload, buildHyperliquidUpdateLeveragePayload, buildHyperliquidMarketOrderPayload, buildHyperliquidLimitOrderPayload, buildHyperliquidTriggerOrderPayload, buildHyperliquidOrderBatchPayload, buildHyperliquidModifyOrderPayload, TRAILING_PCT_PATTERN, buildHyperliquidTrailingStopPayload, extractHyperliquidExchangeError, acknowledgementLookupPacing, lookupUntilListed, resolveHyperliquidTriggerAcknowledgements, readHyperliquidTrailingStopAcknowledgement, resolveHyperliquidModifyAcknowledgement, isDefinitiveHyperliquidExchangeResponse, extractDefinitiveHyperliquidOrderId, CANONICAL_POSITIVE_DECIMAL_PATTERN, extractCanonicalHyperliquidOrderStateAcknowledgement, extractCanonicalHyperliquidOrderStateAcknowledgements, extractCanonicalHyperliquidFilledOrderAcknowledgement, extractDefinitiveHyperliquidOrderMemberResults, buildHyperliquidOrderDiagnostics, loadClientExecutionReferenceEvidence, sha256Hex, extractSignedPayloadClientOrderId, extractSignedPayloadMutationCorrelation, assertDurableMutationMatchesSignedAction, exchangeRejectionReason, exchangeActionPriority, submitHyperliquidExchangePayload;
90554
90580
  var init_hyperliquid_client = __esm({
90555
90581
  "lib/runtime/hyperliquid-client.ts"() {
90556
90582
  "use strict";
@@ -91645,7 +91671,12 @@ var init_hyperliquid_client = __esm({
91645
91671
  };
91646
91672
  fetchBrowserAccountState = async (input) => {
91647
91673
  const user = requireWalletAddress(input.walletAddress);
91648
- const payload = await postHyperliquidInfo(input, { type: "clearinghouseState", user }, "hyperliquid.clearinghouseState");
91674
+ const dex = String(input.dex ?? "").trim().toLowerCase();
91675
+ const payload = await postHyperliquidInfo(
91676
+ input,
91677
+ { type: "clearinghouseState", user, ...dex ? { dex } : {} },
91678
+ "hyperliquid.clearinghouseState"
91679
+ );
91649
91680
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
91650
91681
  throw new Error("Malformed Hyperliquid clearinghouseState response.");
91651
91682
  }
@@ -91663,8 +91694,10 @@ var init_hyperliquid_client = __esm({
91663
91694
  const positions = Array.isArray(state2.assetPositions) ? state2.assetPositions.map((entry) => {
91664
91695
  const assetPosition = entry;
91665
91696
  const position = assetPosition.position || {};
91697
+ const coin = String(position.coin || assetPosition.coin || "");
91666
91698
  return {
91667
- symbol: String(position.coin || assetPosition.coin || ""),
91699
+ // A HIP-3 DEX may name its coins without the DEX.
91700
+ symbol: dex && coin && !coin.includes(":") ? `${dex}:${coin}` : coin,
91668
91701
  size: toFiniteNumber(position.szi, 0),
91669
91702
  entry_price: position.entryPx == null ? null : toFiniteNumber(position.entryPx, 0),
91670
91703
  unrealized_pnl: position.unrealizedPnl == null ? null : toFiniteNumber(position.unrealizedPnl, 0),
@@ -91694,7 +91727,7 @@ var init_hyperliquid_client = __esm({
91694
91727
  };
91695
91728
  fetchBrowserPosition = async (input) => {
91696
91729
  const symbol2 = normalizeSymbol(input.symbol);
91697
- const accountState = await fetchBrowserAccountState(input);
91730
+ const accountState = await fetchBrowserAccountState({ ...input, dex: getHyperliquidMarketDex(symbol2) });
91698
91731
  return accountState.positions.find((position) => normalizeSymbol(position.symbol) === symbol2) ?? null;
91699
91732
  };
91700
91733
  buildHyperliquidOrderWire = async (input, tif, price, priceKind) => {
@@ -92029,6 +92062,52 @@ var init_hyperliquid_client = __esm({
92029
92062
  order
92030
92063
  });
92031
92064
  };
92065
+ TRAILING_PCT_PATTERN = /^\d+(\.\d+)?%$/;
92066
+ buildHyperliquidTrailingStopPayload = async (input) => {
92067
+ input = { ...input, publicRequestPriority: "trading_reduce" };
92068
+ assertPositiveNumber(input.size, "Hyperliquid trailing stop size");
92069
+ const { asset_index: assetIndex, sz_decimals: sizeDecimals } = await resolveHyperliquidAsset(input);
92070
+ const side = normalizeOrderSide(input.side);
92071
+ const roundedSize = quantizeHyperliquidOrderSizeValue(input.size, sizeDecimals, "nearest");
92072
+ assertPositiveNumber(roundedSize, "Hyperliquid trailing stop size");
92073
+ const sizeWire = formatSizeWire(roundedSize, sizeDecimals);
92074
+ const sizeValidation = validateHyperliquidSizeWire(sizeWire, sizeDecimals);
92075
+ if (!sizeValidation.valid) {
92076
+ throw new Error(`Invalid Hyperliquid trailing stop size wire: ${sizeValidation.reason}.`);
92077
+ }
92078
+ let retracement;
92079
+ if ("pct" in input.retracement) {
92080
+ const pct = input.retracement.pct.trim();
92081
+ const decimals = pct.includes(".") ? pct.slice(pct.indexOf(".") + 1, -1).length : 0;
92082
+ if (!TRAILING_PCT_PATTERN.test(pct) || !(Number(pct.slice(0, -1)) > 0) || decimals > HYPERLIQUID_EXCHANGE_SPECIFICATION.trailing_retracement_pct_max_decimals) {
92083
+ throw new Error(
92084
+ `Hyperliquid trailing stop percent must be positive with at most ${HYPERLIQUID_EXCHANGE_SPECIFICATION.trailing_retracement_pct_max_decimals} decimals.`
92085
+ );
92086
+ }
92087
+ retracement = { pct };
92088
+ } else {
92089
+ const px = input.retracement.px.trim();
92090
+ const pxValidation = validateHyperliquidPerpPriceWire(px, sizeDecimals);
92091
+ if (!(Number(px) > 0) || !pxValidation.valid) {
92092
+ throw new Error("Hyperliquid trailing stop distance must be a positive price on the market grid.");
92093
+ }
92094
+ retracement = { px };
92095
+ }
92096
+ let activationPx = null;
92097
+ if (input.activationPrice != null) {
92098
+ assertPositiveNumber(input.activationPrice, "Hyperliquid trailing stop activation price");
92099
+ activationPx = formatHyperliquidTriggerPriceWire(input.activationPrice, sizeDecimals);
92100
+ }
92101
+ return signHyperliquidPayload(input, {
92102
+ type: "trailingStop",
92103
+ asset: assetIndex,
92104
+ isBuy: side === "buy",
92105
+ sz: sizeWire,
92106
+ reduceOnly: true,
92107
+ retracement,
92108
+ activationPx
92109
+ });
92110
+ };
92032
92111
  extractHyperliquidExchangeError = (payload) => {
92033
92112
  if (!payload || typeof payload !== "object") {
92034
92113
  return null;
@@ -92107,6 +92186,19 @@ var init_hyperliquid_client = __esm({
92107
92186
  }
92108
92187
  return { ...root, response: { ...response, data: { ...data4, statuses: resolved } } };
92109
92188
  };
92189
+ readHyperliquidTrailingStopAcknowledgement = (payload) => {
92190
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) return { outcome: "unknown" };
92191
+ const record5 = payload;
92192
+ const body = record5.response;
92193
+ if (record5.status === "err" && typeof body === "string" && body.trim()) return { outcome: "refused", reason: body };
92194
+ if (record5.status !== "ok" || !body || typeof body !== "object") return { outcome: "unknown" };
92195
+ const answer = body;
92196
+ const orderId = answer.data?.oid;
92197
+ if (answer.type === "trailingStop" && typeof orderId === "number" && Number.isSafeInteger(orderId) && orderId > 0) {
92198
+ return { outcome: "placed", order_id: orderId };
92199
+ }
92200
+ return { outcome: "unknown" };
92201
+ };
92110
92202
  resolveHyperliquidModifyAcknowledgement = async (payload, action, lookup, pacing = acknowledgementLookupPacing()) => {
92111
92203
  if (action.type !== "modify" || payload == null || typeof payload !== "object" || Array.isArray(payload)) {
92112
92204
  return payload;
@@ -92149,6 +92241,9 @@ var init_hyperliquid_client = __esm({
92149
92241
  if (action.type === "updateLeverage") {
92150
92242
  return exchangeResponse.type === "default";
92151
92243
  }
92244
+ if (action.type === "trailingStop") {
92245
+ return readHyperliquidTrailingStopAcknowledgement(payload).outcome === "placed";
92246
+ }
92152
92247
  const actionItems = action.type === "order" ? action.orders : action.type === "modify" ? [action.order] : action.type === "cancel" || action.type === "cancelByCloid" ? action.cancels : null;
92153
92248
  const expectedCount = Array.isArray(actionItems) ? actionItems.length : 0;
92154
92249
  const data4 = exchangeResponse.data && typeof exchangeResponse.data === "object" && !Array.isArray(exchangeResponse.data) ? exchangeResponse.data : null;
@@ -92564,6 +92659,13 @@ var init_hyperliquid_client = __esm({
92564
92659
  }
92565
92660
  return signedAssetId2;
92566
92661
  }
92662
+ if (durableMutation.operationKind === "trailing_stop") {
92663
+ const signedAssetId2 = Number(action.asset);
92664
+ if (action.type !== "trailingStop" || !Number.isInteger(signedAssetId2) || signedAssetId2 < 0 || action.reduceOnly !== true) {
92665
+ throw new Error("Durable trailing stop authority requires exactly one signed reduce-only trailingStop.");
92666
+ }
92667
+ return signedAssetId2;
92668
+ }
92567
92669
  const signedAssetId = Number(action.asset);
92568
92670
  if (action.type !== "updateLeverage" || !Number.isInteger(signedAssetId) || signedAssetId < 0 || !Number.isInteger(Number(action.leverage)) || Number(action.leverage) <= 0 || typeof action.isCross !== "boolean") {
92569
92671
  throw new Error(
@@ -92585,6 +92687,7 @@ var init_hyperliquid_client = __esm({
92585
92687
  };
92586
92688
  exchangeActionPriority = (action, requested) => {
92587
92689
  if (action.type === "cancel" || action.type === "cancelByCloid") return requested === "trading_reduce" ? "trading_reduce" : "trading_execute";
92690
+ if (action.type === "trailingStop") return action.reduceOnly === true ? "trading_reduce" : "trading_execute";
92588
92691
  const orders = action.type === "order" && Array.isArray(action.orders) ? action.orders : action.type === "modify" ? [action.order] : [];
92589
92692
  return orders.length > 0 && orders.every((order) => order && typeof order === "object" && order.r === true) ? "trading_reduce" : "trading_execute";
92590
92693
  };
@@ -92653,7 +92756,8 @@ var init_hyperliquid_client = __esm({
92653
92756
  clientOrderIds: durableMutation.clientOrderIds ?? null,
92654
92757
  ...durableMutation.protection ? { protection: durableMutation.protection } : {},
92655
92758
  ...durableMutation.protectiveActionId ? { protectiveActionId: durableMutation.protectiveActionId } : {},
92656
- ...durableMutation.protection || durableMutation.protectiveActionId ? { signedPayload: serializedPayload } : {},
92759
+ // A trailing stop has no CLOID: the server binds the lot it signs.
92760
+ ...durableMutation.protection || durableMutation.protectiveActionId || durableMutation.operationKind === "trailing_stop" ? { signedPayload: serializedPayload } : {},
92657
92761
  attemptEvidence: diagnostics.first_order ? {
92658
92762
  requestedExchangeSize: diagnostics.first_order.size,
92659
92763
  submittedLimitPrice: diagnostics.first_order.price,
@@ -92904,7 +93008,7 @@ var init_hyperliquid_client = __esm({
92904
93008
  })
92905
93009
  );
92906
93010
  }
92907
- const exchangeError = extractHyperliquidExchangeError(payload);
93011
+ const exchangeError = durableMutation?.operationKind === "trailing_stop" && readHyperliquidTrailingStopAcknowledgement(payload).outcome !== "refused" ? null : extractHyperliquidExchangeError(payload);
92908
93012
  if (exchangeError) {
92909
93013
  emitHyperliquidExchangeRejection(String(exchangeError.message ?? ""));
92910
93014
  await settleDurableMutation(
@@ -92944,7 +93048,8 @@ var init_hyperliquid_client = __esm({
92944
93048
  "outcome_unknown"
92945
93049
  );
92946
93050
  }
92947
- const exactExchangeOrderId = durableMutation?.operationKind === "order" ? extractDefinitiveHyperliquidOrderId(payload, input.payload.action) : null;
93051
+ const trailingAcknowledgement = durableMutation?.operationKind === "trailing_stop" ? readHyperliquidTrailingStopAcknowledgement(payload) : null;
93052
+ const exactExchangeOrderId = durableMutation?.operationKind === "order" ? extractDefinitiveHyperliquidOrderId(payload, input.payload.action) : trailingAcknowledgement?.outcome === "placed" ? String(trailingAcknowledgement.order_id) : null;
92948
93053
  const extractedOrderMemberResults = durableMutation?.operationKind === "order" ? extractDefinitiveHyperliquidOrderMemberResults(
92949
93054
  payload,
92950
93055
  input.payload.action
@@ -93042,12 +93147,21 @@ var init_exchange_mutation_evidence = __esm({
93042
93147
  { type: "activeAssetData", user: wallet, coin },
93043
93148
  "hyperliquid.activeAssetData"
93044
93149
  ) : null;
93150
+ const dex = input.required.open_orders_dex;
93151
+ const openOrders = dex == null ? void 0 : await fetchBrowserHyperliquidInfoPayload(
93152
+ readInput,
93153
+ { type: "frontendOpenOrders", user: wallet, ...dex ? { dex } : {} },
93154
+ "hyperliquid.frontendOpenOrders"
93155
+ );
93156
+ const historicalOrders = input.required.historical_orders === true ? await fetchBrowserHyperliquidInfoPayload(readInput, { type: "historicalOrders", user: wallet }, "hyperliquid.historicalOrders") : void 0;
93045
93157
  return {
93046
93158
  evidence: {
93047
93159
  wallet_address: wallet,
93048
93160
  observed_at: observedAt,
93049
93161
  order_statuses: orderStatuses,
93050
- active_asset_data: activeAssetData
93162
+ active_asset_data: activeAssetData,
93163
+ ...openOrders === void 0 ? {} : { open_orders: openOrders },
93164
+ ...historicalOrders === void 0 ? {} : { historical_orders: historicalOrders }
93051
93165
  },
93052
93166
  startedAtMonotonicMs
93053
93167
  };
@@ -94623,6 +94737,7 @@ var init_api2 = __esm({
94623
94737
  init_updates();
94624
94738
  init_profile_emoji();
94625
94739
  init_account_summary();
94740
+ init_mobile_notifications();
94626
94741
  init_server_runtime_lease();
94627
94742
  clientRuntimeSecretHeaders = (profileId) => {
94628
94743
  const headers = getProfileHeaders({}, profileId);
@@ -94706,9 +94821,8 @@ var init_api2 = __esm({
94706
94821
  if ("invocations" in payload) {
94707
94822
  body.invocations = payload.invocations ?? [];
94708
94823
  }
94709
- if (payload.stopReason !== void 0) {
94710
- body.stop_reason = payload.stopReason ?? null;
94711
- }
94824
+ if (payload.stopReason !== void 0) body.stop_reason = payload.stopReason ?? null;
94825
+ if (payload.modeSwitch) body.mode_switch = true;
94712
94826
  if (payload.authoritativeIntent !== void 0) {
94713
94827
  body.authoritative_intent = payload.authoritativeIntent;
94714
94828
  }
@@ -96333,7 +96447,7 @@ var init_vault = __esm({
96333
96447
  });
96334
96448
 
96335
96449
  // lib/runtime/browser-trading.ts
96336
- var resolveProfileId, requirePositiveNumber, assertFreshPreparedContext, throwIfAborted, UUID_PATTERN, createExchangeMutationIdentity, requireClientExchangeExpiresAfterSeconds, loadSigningKey, priorityOf, resolveSigningKey, requireWalletAddress2, resolveEstimatedPrice, executeClientLeverageUpdate, executeClientMarketOrder, resolveClientProtectiveSigningKey, executeClientPreparedProtectiveAction, executeClientLimitOrder, executeClientTriggerOrder, executeClientOrderBatch, executeClientModifyOrder, executeClientCancelOrder, executeClientClosePosition;
96450
+ var resolveProfileId, requirePositiveNumber, assertFreshPreparedContext, throwIfAborted, UUID_PATTERN, createExchangeMutationIdentity, requireClientExchangeExpiresAfterSeconds, loadSigningKey, priorityOf, resolveSigningKey, requireWalletAddress2, resolveEstimatedPrice, executeClientLeverageUpdate, executeClientMarketOrder, resolveClientProtectiveSigningKey, executeClientPreparedProtectiveAction, executeClientLimitOrder, executeClientTriggerOrder, executeClientOrderBatch, executeClientModifyOrder, executeClientCancelOrder, executeClientTrailingStop, executeClientClosePosition;
96337
96451
  var init_browser_trading = __esm({
96338
96452
  "lib/runtime/browser-trading.ts"() {
96339
96453
  "use strict";
@@ -96794,6 +96908,41 @@ var init_browser_trading = __esm({
96794
96908
  }
96795
96909
  });
96796
96910
  };
96911
+ executeClientTrailingStop = async (input) => {
96912
+ input = { ...input, publicRequestPriority: "trading_reduce" };
96913
+ throwIfAborted(input.signal);
96914
+ const signingKey = await resolveSigningKey(input);
96915
+ throwIfAborted(input.signal);
96916
+ const mutation = createExchangeMutationIdentity(false, input);
96917
+ const payload = await buildHyperliquidTrailingStopPayload({
96918
+ config: input.config ?? null,
96919
+ publicRequestPriority: priorityOf(input),
96920
+ signingKey,
96921
+ symbol: input.symbol,
96922
+ side: input.side,
96923
+ size: input.size,
96924
+ retracement: input.retracement,
96925
+ expiresAfterSeconds: requireClientExchangeExpiresAfterSeconds(input.config)
96926
+ });
96927
+ return submitHyperliquidExchangePayload({
96928
+ config: input.config ?? null,
96929
+ publicRequestPriority: priorityOf(input),
96930
+ payload,
96931
+ signal: input.signal,
96932
+ mutationScope: resolveProfileId(input.profileId),
96933
+ durableMutation: {
96934
+ profileId: input.profileId,
96935
+ requiredRuntimeSessionId: input.runtimeSessionId,
96936
+ runtimeLeaseToken: input.runtimeLeaseToken,
96937
+ runtimeDeviceId: input.runtimeDeviceId,
96938
+ schedulerInstanceId: input.schedulerInstanceId,
96939
+ mutationId: mutation.mutationId,
96940
+ operationKind: "trailing_stop",
96941
+ symbol: input.symbol,
96942
+ onExchangeOrderDispatched: input.onExchangeOrderDispatched
96943
+ }
96944
+ });
96945
+ };
96797
96946
  executeClientClosePosition = async (input) => {
96798
96947
  input = { ...input, publicRequestPriority: "trading_reduce" };
96799
96948
  throwIfAborted(input.signal);
@@ -98560,7 +98709,7 @@ var init_protective_evidence = __esm({
98560
98709
  });
98561
98710
 
98562
98711
  // lib/runtime/protective-actions.ts
98563
- var DECIMAL, CLOID, fail2, exactKeys, nonNegativeInteger, decimalString, POSITION_ORDER_SIZE, orderSizeString, canonicalTriggerOrder, canonicalProtectiveWireAction, assertProtectiveActionLocallySafe, authorityArgs2, errorCode2, foreignClaimExpiresAtMs, drainLocks, refusedUntil, drainClientProtectiveActions, drainOnce;
98712
+ var DECIMAL, PERCENT, CLOID, fail2, exactKeys, nonNegativeInteger, decimalString, POSITION_ORDER_SIZE, orderSizeString, canonicalTriggerOrder, canonicalProtectiveWireAction, assertProtectiveActionLocallySafe, authorityArgs2, errorCode2, foreignClaimExpiresAtMs, drainLocks, refusedUntil, drainClientProtectiveActions, drainOnce;
98564
98713
  var init_protective_actions = __esm({
98565
98714
  "lib/runtime/protective-actions.ts"() {
98566
98715
  "use strict";
@@ -98577,6 +98726,7 @@ var init_protective_actions = __esm({
98577
98726
  init_error_surface_contract();
98578
98727
  init_protective_evidence();
98579
98728
  DECIMAL = /^(?:0|[1-9]\d*)(?:\.\d+)?$/;
98729
+ PERCENT = /^(?:0|[1-9]\d*)(?:\.\d+)?%$/;
98580
98730
  CLOID = /^0x[0-9a-f]{32}$/;
98581
98731
  fail2 = (message) => {
98582
98732
  throw new RuntimeExecutionError(
@@ -98655,9 +98805,48 @@ var init_protective_actions = __esm({
98655
98805
  if (oid <= 0) fail2("cancel target is invalid.");
98656
98806
  return { type: "cancel", cancels: [{ a: nonNegativeInteger(cancel.a, "asset"), o: oid }] };
98657
98807
  }
98808
+ if (kind === "trailingStop") {
98809
+ const action = exactKeys(wire, ["type", "asset", "isBuy", "sz", "reduceOnly", "retracement", "activationPx"], "action");
98810
+ if (action.reduceOnly !== true) fail2("a trailing stop must be reduce-only.");
98811
+ if (typeof action.isBuy !== "boolean") fail2("trailing stop side is invalid.");
98812
+ if (action.activationPx !== null) fail2("a trailing stop is active at once.");
98813
+ const distance = action.retracement;
98814
+ let retracement;
98815
+ if (distance && typeof distance === "object" && "pct" in distance) {
98816
+ const pct = exactKeys(distance, ["pct"], "retracement").pct;
98817
+ const decimals = typeof pct === "string" && pct.includes(".") ? pct.slice(pct.indexOf(".") + 1, -1).length : 0;
98818
+ if (typeof pct !== "string" || !PERCENT.test(pct) || !(Number(pct.slice(0, -1)) > 0) || decimals > HYPERLIQUID_EXCHANGE_SPECIFICATION.trailing_retracement_pct_max_decimals) {
98819
+ fail2("trailing stop percent is invalid.");
98820
+ }
98821
+ retracement = { pct };
98822
+ } else {
98823
+ retracement = { px: decimalString(exactKeys(distance, ["px"], "retracement").px, "trailing stop distance") };
98824
+ }
98825
+ return {
98826
+ type: "trailingStop",
98827
+ asset: nonNegativeInteger(action.asset, "asset"),
98828
+ isBuy: action.isBuy,
98829
+ sz: decimalString(action.sz, "trailing stop size"),
98830
+ reduceOnly: true,
98831
+ retracement,
98832
+ activationPx: null
98833
+ };
98834
+ }
98658
98835
  return fail2("unsupported action type.");
98659
98836
  };
98660
98837
  assertProtectiveActionLocallySafe = (action, canonical, livePositionSize) => {
98838
+ if (canonical.type === "trailingStop" !== (action.operation_kind === "trailing_stop")) {
98839
+ fail2("operation kind does not match the action.");
98840
+ }
98841
+ if (canonical.type === "trailingStop") {
98842
+ if (action.action_kind !== "place" || action.client_order_ids.length > 0) fail2("trailing stop metadata does not match.");
98843
+ if (canonical.asset !== action.exchange_asset_id) fail2("asset does not match the symbol.");
98844
+ if (livePositionSize == null || !Number.isFinite(livePositionSize) || livePositionSize === 0) {
98845
+ fail2("the live position is flat or unknown.");
98846
+ }
98847
+ if (canonical.isBuy !== livePositionSize < 0) fail2("the trailing stop would not close the live position.");
98848
+ return;
98849
+ }
98661
98850
  const assets = canonical.type === "cancel" ? canonical.cancels.map((cancel) => cancel.a) : canonical.type === "modify" ? [canonical.order.a] : canonical.orders.map((order) => order.a);
98662
98851
  if (assets.some((asset) => asset !== action.exchange_asset_id)) fail2("asset does not match the symbol.");
98663
98852
  if (canonical.type === "cancel") {
@@ -99567,7 +99756,7 @@ var init_protective_trigger_price = __esm({
99567
99756
  });
99568
99757
 
99569
99758
  // lib/runtime/protective-stop-replacement.ts
99570
- var STOP_REPLACED, STOP_REPLACEMENT_EXHAUSTED, STOP_REPLACEMENT_REJECTED, STOP_REPLACEMENT_NOT_LANDED, STOP_CLEANUP_IN_FLIGHT, TERMINAL_WITHOUT_FILL, CANCELLED_BY_USER, POSITION_FLAT_AFTER_TERMINAL, CAPACITY_ALREADY_ALLOCATED, TRIGGER_INVALID, STOP_EXECUTION_REJECTED, STOP_TRIGGER_CROSSED, permanentStopRejectionStatuses, protectiveStopRejectionIsPermanent, POSITION_ENDED_ORDER_STATUSES, finiteOrNull, floorToLot, positiveSafeInteger, decimalOrNull, positionTolerance, chainFillChronology, protectivePositionEpisodeEnded, decideProtectiveStopReplacement;
99759
+ var STOP_REPLACED, STOP_REPLACEMENT_EXHAUSTED, STOP_REPLACEMENT_REJECTED, STOP_REPLACEMENT_NOT_LANDED, STOP_CLEANUP_IN_FLIGHT, TERMINAL_WITHOUT_FILL, CANCELLED_BY_USER, POSITION_FLAT_AFTER_TERMINAL, CAPACITY_ALREADY_ALLOCATED, TRIGGER_INVALID, STOP_EXECUTION_REJECTED, STOP_TRIGGER_CROSSED, permanentStopRejectionStatuses, protectiveStopRejectionIsPermanent, POSITION_ENDED_ORDER_STATUSES, finiteOrNull, floorToLot, positiveSafeInteger, decimalOrNull, positionTolerance, chainFillChronology, marketFillChain, noExposureOnSide, protectivePositionEpisodeEnded, decideProtectiveStopReplacement;
99571
99760
  var init_protective_stop_replacement = __esm({
99572
99761
  "lib/runtime/protective-stop-replacement.ts"() {
99573
99762
  "use strict";
@@ -99644,16 +99833,13 @@ var init_protective_stop_replacement = __esm({
99644
99833
  }
99645
99834
  return ordered;
99646
99835
  };
99647
- protectivePositionEpisodeEnded = (input) => {
99648
- if (!POSITION_ENDED_ORDER_STATUSES.has(String(input.orderStatus ?? ""))) return false;
99649
- const statusMs = positiveSafeInteger(input.statusTimestampMs);
99650
- if (statusMs == null || !Array.isArray(input.fills)) return false;
99651
- const market = normalizeHyperliquidMarketSymbol(input.symbol);
99652
- const sign = input.isLong ? 1 : -1;
99836
+ marketFillChain = (fills, symbol2) => {
99837
+ if (!Array.isArray(fills)) return null;
99838
+ const market = normalizeHyperliquidMarketSymbol(symbol2);
99653
99839
  const rows = [];
99654
99840
  const seen = /* @__PURE__ */ new Set();
99655
- for (const fill of input.fills) {
99656
- if (fill == null || typeof fill !== "object" || Array.isArray(fill)) return false;
99841
+ for (const fill of fills) {
99842
+ if (fill == null || typeof fill !== "object" || Array.isArray(fill)) return null;
99657
99843
  const record5 = fill;
99658
99844
  if (normalizeHyperliquidMarketSymbol(String(record5.coin ?? "")) !== market) continue;
99659
99845
  const tradeId = positiveSafeInteger(record5.tid);
@@ -99661,12 +99847,26 @@ var init_protective_stop_replacement = __esm({
99661
99847
  const size = decimalOrNull(record5.sz);
99662
99848
  const start = decimalOrNull(record5.startPosition);
99663
99849
  if (tradeId == null || seen.has(tradeId) || time3 == null || record5.side !== "B" && record5.side !== "A" || size == null || size <= 0 || start == null) {
99664
- return false;
99850
+ return null;
99665
99851
  }
99666
99852
  seen.add(tradeId);
99667
- rows.push({ time: time3, tradeId, start, end: start + (record5.side === "B" ? size : -size) });
99853
+ rows.push({
99854
+ time: time3,
99855
+ tradeId,
99856
+ start,
99857
+ end: start + (record5.side === "B" ? size : -size),
99858
+ orderId: String(record5.oid ?? "").trim()
99859
+ });
99668
99860
  }
99669
- const chained = chainFillChronology(rows);
99861
+ return chainFillChronology(rows);
99862
+ };
99863
+ noExposureOnSide = (position, isLong) => (isLong ? 1 : -1) * position <= positionTolerance(position, 0);
99864
+ protectivePositionEpisodeEnded = (input) => {
99865
+ if (!POSITION_ENDED_ORDER_STATUSES.has(String(input.orderStatus ?? ""))) return false;
99866
+ const statusMs = positiveSafeInteger(input.statusTimestampMs);
99867
+ if (statusMs == null) return false;
99868
+ const sign = input.isLong ? 1 : -1;
99869
+ const chained = marketFillChain(input.fills, input.symbol);
99670
99870
  if (chained == null) return false;
99671
99871
  const before = chained.filter((row) => row.time <= statusMs);
99672
99872
  const after = chained.filter((row) => row.time > statusMs);
@@ -99819,7 +100019,7 @@ var init_protective_entry_cover = __esm({
99819
100019
  });
99820
100020
 
99821
100021
  // lib/runtime/native-position-protection.ts
99822
- var nativeProtectionSettings, memberSetting, KINDS, formatTriggerOrNull, nativePositionTriggerPrice, nativeEntryRequest, HALF_UP_DIGIT, roundDecimalHalfUp, nativeTrailingRetracement, nativeAfterFillActions, classifyNativeOrderEnd, isOpenInDirection, nativePlacementGate, nativeStrayOrderDecision, FIRED_TRIGGER_CONDITION, closingSide, DECIMAL_PATTERN, decimalUnits2, fractionDigits, nativePlaceCover, nativeRearmDecision, nativeLostStopCrossed, explainAbsentProtectiveOrder, readServerNativeProtectionState;
100022
+ var nativeProtectionSettings, memberSetting, KINDS, formatTriggerOrNull, nativePositionTriggerPrice, nativeEntryRequest, HALF_UP_DIGIT, roundDecimalHalfUp, nativeTrailingRetracement, nativeAfterFillActions, classifyNativeOrderEnd, isOpenInDirection, nativePlacementGate, nativeStrayOrderDecision, FIRED_TRIGGER_CONDITION, TRAILING_ORDER_TYPE, closingSide, DECIMAL_PATTERN, decimalUnits2, fractionDigits, nativePlaceCover, positiveOrderId, nativeRearmDecision, nativeLostStopCrossed, readListedProtectiveRow, explainAbsentProtectiveOrder, readServerNativeProtectionState, nativeFillOpenedPosition, nativePositionEndedSince, flatReadEndsPosition;
99823
100023
  var init_native_position_protection = __esm({
99824
100024
  "lib/runtime/native-position-protection.ts"() {
99825
100025
  "use strict";
@@ -99966,6 +100166,7 @@ var init_native_position_protection = __esm({
99966
100166
  return input.positionStateMs > input.placedMs ? "cancel" : "need_reads";
99967
100167
  };
99968
100168
  FIRED_TRIGGER_CONDITION = "Triggered";
100169
+ TRAILING_ORDER_TYPE = "trailing stop market";
99969
100170
  closingSide = (isLong) => isLong ? "a" : "b";
99970
100171
  DECIMAL_PATTERN = /^-?\d+(\.\d+)?$/;
99971
100172
  decimalUnits2 = (value, scale) => {
@@ -99979,6 +100180,7 @@ var init_native_position_protection = __esm({
99979
100180
  nativePlaceCover = (input) => {
99980
100181
  const market = normalizeHyperliquidMarketSymbol(input.symbol);
99981
100182
  const own = new Set(input.ownClientOrderIds.map((value) => String(value).trim().toLowerCase()).filter(Boolean));
100183
+ const ownTrailing = new Set((input.ownTrailingOrderIds ?? []).map(positiveOrderId).filter((id2) => id2 != null));
99982
100184
  const positionText = String(input.positionSize).replace(/^-/, "");
99983
100185
  const sized = [];
99984
100186
  for (const row of input.rows) {
@@ -99986,7 +100188,9 @@ var init_native_position_protection = __esm({
99986
100188
  if (row.reduceOnly !== true || row.isTrigger !== true) continue;
99987
100189
  if (String(row.triggerCondition ?? "").trim() === FIRED_TRIGGER_CONDITION) continue;
99988
100190
  if (String(row.side ?? "").trim().toLowerCase() !== closingSide(input.isLong)) continue;
99989
- const orderType = String(row.orderType ?? "").toLowerCase();
100191
+ const orderType = String(row.orderType ?? "").trim().toLowerCase();
100192
+ const rowOrderId = positiveOrderId(row.oid);
100193
+ if (orderType === TRAILING_ORDER_TYPE && rowOrderId != null && ownTrailing.has(rowOrderId)) continue;
99990
100194
  const rowKind = orderType.includes("take profit") ? "tp" : orderType.includes("stop") ? "sl" : null;
99991
100195
  if (rowKind !== input.kind) continue;
99992
100196
  if (own.has(String(row.cloid ?? "").trim().toLowerCase())) {
@@ -100004,6 +100208,13 @@ var init_native_position_protection = __esm({
100004
100208
  const covered = sized.reduce((total, size) => total + decimalUnits2(size, scale), BigInt(0));
100005
100209
  return position > BigInt(0) && covered >= position ? { decision: "covered" } : { decision: "place" };
100006
100210
  };
100211
+ positiveOrderId = (value) => {
100212
+ if (typeof value === "boolean") return null;
100213
+ const text = String(value ?? "").trim();
100214
+ if (!/^\d+$/.test(text)) return null;
100215
+ const orderId = Number(text);
100216
+ return orderId > 0 && Number.isSafeInteger(orderId) ? orderId : null;
100217
+ };
100007
100218
  nativeRearmDecision = (input) => {
100008
100219
  if (!isOpenInDirection(input.position, input.isLong)) return "retire";
100009
100220
  if (input.endedMs == null || !(input.positionStateMs > input.endedMs)) return "need_reads";
@@ -100013,6 +100224,7 @@ var init_native_position_protection = __esm({
100013
100224
  if (input.mark == null || !Number.isFinite(input.mark)) return false;
100014
100225
  return input.isLong ? input.mark <= input.trigger : input.mark >= input.trigger;
100015
100226
  };
100227
+ readListedProtectiveRow = (row) => String(row.triggerCondition ?? "").trim() === FIRED_TRIGGER_CONDITION ? "not_resting_status_read_decides" : "resting";
100016
100228
  explainAbsentProtectiveOrder = (input) => {
100017
100229
  if (isOpenInDirection(input.position, input.isLong)) return "status_read";
100018
100230
  return input.positionStateMs > input.lastSeenRestingMs ? "ended_with_position" : "need_reads";
@@ -100027,17 +100239,69 @@ var init_native_position_protection = __esm({
100027
100239
  if (typeof record5.enabled !== "boolean" || legacy == null || native == null) return null;
100028
100240
  return { enabled: record5.enabled, legacySymbols: new Set(legacy), nativeSymbols: new Set(native) };
100029
100241
  };
100242
+ nativeFillOpenedPosition = (input) => {
100243
+ if (!input.complete || !Array.isArray(input.fills)) return "unknown";
100244
+ const market = normalizeHyperliquidMarketSymbol(input.symbol);
100245
+ const moves = [];
100246
+ const decimal = (value) => {
100247
+ const text = typeof value === "number" && Number.isFinite(value) ? String(value) : typeof value === "string" ? value.trim() : "";
100248
+ return DECIMAL_PATTERN.test(text) ? Number(text) : null;
100249
+ };
100250
+ for (const fill of input.fills) {
100251
+ if (fill == null || typeof fill !== "object" || Array.isArray(fill)) continue;
100252
+ const record5 = fill;
100253
+ if (String(record5.oid ?? "").trim() !== input.orderId.trim()) continue;
100254
+ if (normalizeHyperliquidMarketSymbol(String(record5.coin ?? "")) !== market) continue;
100255
+ const start = decimal(record5.startPosition);
100256
+ const size = decimal(record5.sz);
100257
+ if (start == null || size == null || size <= 0 || record5.side !== "B" && record5.side !== "A") return "unknown";
100258
+ moves.push({ start, end: start + (record5.side === "B" ? size : -size) });
100259
+ }
100260
+ if (moves.length === 0) return "unknown";
100261
+ if (moves.some(({ start, end }) => noExposureOnSide(start, input.isLong) && !noExposureOnSide(end, input.isLong))) {
100262
+ return "opened";
100263
+ }
100264
+ if (moves.every(({ start }) => !noExposureOnSide(start, input.isLong))) return "joined";
100265
+ if (moves.every(({ end }) => noExposureOnSide(end, input.isLong))) return "other_side";
100266
+ return "unknown";
100267
+ };
100268
+ nativePositionEndedSince = (input) => {
100269
+ let answer = "unknown";
100270
+ const chain = input.complete ? marketFillChain(input.fills, input.symbol) : null;
100271
+ if (chain != null) {
100272
+ let last = -1;
100273
+ chain.forEach((row, index) => {
100274
+ if (row.orderId === input.orderId.trim()) last = index;
100275
+ });
100276
+ if (last >= 0) {
100277
+ answer = chain.slice(last).some((row) => noExposureOnSide(row.end, input.isLong)) ? "ended" : "open";
100278
+ }
100279
+ }
100280
+ if (answer === "unknown" && input.flatRead != null && flatReadEndsPosition(input.flatRead, input.isLong)) return "ended";
100281
+ return answer;
100282
+ };
100283
+ flatReadEndsPosition = (read, isLong) => {
100284
+ if (read.pageComplete !== true || read.newestFillMs === void 0) return false;
100285
+ const text = String(read.position ?? "").trim();
100286
+ if (!DECIMAL_PATTERN.test(text) || !Number.isSafeInteger(read.stateMs)) return false;
100287
+ if (!noExposureOnSide(Number(text), isLong)) return false;
100288
+ if (read.newestFillMs == null) return true;
100289
+ return Number.isSafeInteger(read.newestFillMs) && read.newestFillMs < read.stateMs;
100290
+ };
100030
100291
  }
100031
100292
  });
100032
100293
 
100033
100294
  // lib/runtime/native-protection-device.ts
100034
- var NATIVE_PROTECTION_RECORD_VERSION, nativeProtectionStorage, resolveStorage, setNativeProtectionStorage, recordKey, isMember, readNativeProtectionRecord, writeNativeProtectionRecord, NativeOrderNotSentError, withDispatchBoundary, attempt, notSentRestores, errorText, actionOf, isOpenInDirection2, coverRows, restingOrderIdAt, definitivelyRefused, planNativeOpen, recordEntryChildren, observeMembers, UNKNOWN_ORDER_RESPONSE, resolveUnknownOrderIds, settleNativeProtectionAfterFill, reconcileNativeProtection;
100295
+ var NATIVE_PROTECTION_RECORD_VERSION, nativeProtectionStorage, resolveStorage, setNativeProtectionStorage, recordKey, isMember, isRetracement, isLot, isStandbyAdd, readNativeProtectionRecord, versioned, writeNativeProtectionRecord, NO_FILLS, nativeFillsPageFromUserFills, fillsReader, flatReadOf, orderFillTimes, namedOrderId, NativeOrderNotSentError, withDispatchBoundary, attempt, notSentRestores, errorText, actionOf, isOpenInDirection2, coverRows, restingOrderIdAt, definitivelyRefused, TRAILING_LOT_FIRED, TRAILING_LOT_POSITION_ENDED, TRAILING_LOT_OTHER_SIDE, lotFillLeftPosition, lotOfAdd, ORDER_ID_PATTERN, lotFillOrderId, lotPositionSince, ownLotOrderIds, lotRetracement, lotReport, sendTrailingLot, planNativeFillLot, planNativeStandbyAdd, nameNativeStandbyAdd, dropNativeStandbyAdd, dropNativePendingLot, planNativePendingLot, planNativeOpen, recordEntryChildren, observeMembers, UNKNOWN_ORDER_RESPONSE, resolveUnknownOrderIds, plannedPair, resolveStandbyAdds, settleNativeProtectionAfterFill, reconcileNativeProtection;
100035
100296
  var init_native_protection_device = __esm({
100036
100297
  "lib/runtime/native-protection-device.ts"() {
100037
100298
  "use strict";
100038
100299
  init_define_VTX_EXO_POLICY();
100039
100300
  init_define_VTX_GROK_POLICY();
100040
100301
  init_define_VTX_PI_MODEL_POLICY();
100302
+ init_constants();
100303
+ init_hyperliquid_market_symbol();
100304
+ init_hyperliquid_order_status();
100041
100305
  init_order_identity();
100042
100306
  init_native_position_protection();
100043
100307
  NATIVE_PROTECTION_RECORD_VERSION = 1;
@@ -100058,7 +100322,23 @@ var init_native_protection_device = __esm({
100058
100322
  isMember = (value) => {
100059
100323
  if (!value || typeof value !== "object") return false;
100060
100324
  const member = value;
100061
- return (member.kind === "sl" || member.kind === "tp") && typeof member.clientOrderId === "string" && (member.orderId === null || typeof member.orderId === "number" && Number.isSafeInteger(member.orderId)) && typeof member.trigger === "string" && (member.placedAtMs === null || typeof member.placedAtMs === "number") && typeof member.sentAtMs === "number" && typeof member.replacedOnce === "boolean" && (member.pendingModify === void 0 || typeof member.pendingModify === "object" && member.pendingModify !== null && typeof member.pendingModify.clientOrderId === "string" && typeof member.pendingModify.trigger === "string" && typeof member.pendingModify.sentAtMs === "number");
100325
+ return (member.kind === "sl" || member.kind === "tp") && typeof member.clientOrderId === "string" && (member.orderId === null || typeof member.orderId === "number" && Number.isSafeInteger(member.orderId)) && typeof member.trigger === "string" && (member.placedAtMs === null || typeof member.placedAtMs === "number") && typeof member.sentAtMs === "number" && typeof member.replacedOnce === "boolean" && (member.plannedAfterMs === void 0 || typeof member.plannedAfterMs === "number") && (member.pendingModify === void 0 || typeof member.pendingModify === "object" && member.pendingModify !== null && typeof member.pendingModify.clientOrderId === "string" && typeof member.pendingModify.trigger === "string" && typeof member.pendingModify.sentAtMs === "number");
100326
+ };
100327
+ isRetracement = (value) => {
100328
+ if (!value || typeof value !== "object") return false;
100329
+ const keys = Object.keys(value);
100330
+ const record5 = value;
100331
+ return keys.length === 1 && (typeof record5.pct === "string" || typeof record5.px === "string");
100332
+ };
100333
+ isLot = (value) => {
100334
+ if (!value || typeof value !== "object") return false;
100335
+ const lot = value;
100336
+ return (lot.mutationId === null || typeof lot.mutationId === "string") && typeof lot.fillKey === "string" && (lot.fillOrderId === void 0 || typeof lot.fillOrderId === "string") && typeof lot.fillEventMs === "number" && typeof lot.size === "string" && isRetracement(lot.retracement) && (lot.orderId === null || typeof lot.orderId === "number" && Number.isSafeInteger(lot.orderId)) && (lot.placedAtMs === null || typeof lot.placedAtMs === "number") && typeof lot.sentAtMs === "number" && typeof lot.replacedOnce === "boolean" && (lot.userCancelledOrderId === void 0 || typeof lot.userCancelledOrderId === "number") && (lot.fillEventFromDevice === void 0 || typeof lot.fillEventFromDevice === "boolean") && (lot.retiredReason === void 0 || typeof lot.retiredReason === "string");
100337
+ };
100338
+ isStandbyAdd = (value) => {
100339
+ if (!value || typeof value !== "object") return false;
100340
+ const add = value;
100341
+ return typeof add.clientOrderId === "string" && (add.orderId === null || typeof add.orderId === "string") && typeof add.sentAtMs === "number";
100062
100342
  };
100063
100343
  readNativeProtectionRecord = (profileId, symbol2) => {
100064
100344
  const storage3 = resolveStorage();
@@ -100066,22 +100346,83 @@ var init_native_protection_device = __esm({
100066
100346
  const raw = storage3.getItem(recordKey(profileId, symbol2));
100067
100347
  if (raw == null) return null;
100068
100348
  const parsed = JSON.parse(raw);
100069
- if (parsed?.version !== NATIVE_PROTECTION_RECORD_VERSION || parsed.profileId !== profileId || parsed.symbol !== symbol2 || typeof parsed.walletAddress !== "string" || typeof parsed.isLong !== "boolean" || parsed.phase !== "entry_pending" && parsed.phase !== "active" || typeof parsed.entryMutationId !== "string" || typeof parsed.entryClientOrderId !== "string" || typeof parsed.createdAtMs !== "number" || !Array.isArray(parsed.members) || !parsed.members.every(isMember)) {
100349
+ if (parsed?.version !== NATIVE_PROTECTION_RECORD_VERSION && parsed?.version !== NATIVE_PROTECTION_RECORD_WITH_LOTS_VERSION || parsed.profileId !== profileId || parsed.symbol !== symbol2 || typeof parsed.walletAddress !== "string" || typeof parsed.isLong !== "boolean" || parsed.phase !== "entry_pending" && parsed.phase !== "active" || typeof parsed.entryMutationId !== "string" || typeof parsed.entryClientOrderId !== "string" || typeof parsed.createdAtMs !== "number" || !Array.isArray(parsed.members) || !parsed.members.every(isMember) || parsed.lots !== void 0 && (parsed.version !== NATIVE_PROTECTION_RECORD_WITH_LOTS_VERSION || !Array.isArray(parsed.lots) || !parsed.lots.every(isLot)) || parsed.standby !== void 0 && (!Array.isArray(parsed.standby) || !parsed.standby.every(isStandbyAdd)) || parsed.positionOrderId !== void 0 && typeof parsed.positionOrderId !== "string") {
100070
100350
  throw new Error("Stored native protection record is invalid.");
100071
100351
  }
100072
100352
  return parsed;
100073
100353
  };
100354
+ versioned = (record5) => {
100355
+ const { lots, ...rest } = record5;
100356
+ return lots && lots.length > 0 ? { ...rest, version: NATIVE_PROTECTION_RECORD_WITH_LOTS_VERSION, lots } : { ...rest, version: NATIVE_PROTECTION_RECORD_VERSION };
100357
+ };
100074
100358
  writeNativeProtectionRecord = (profileId, symbol2, record5) => {
100075
100359
  const storage3 = resolveStorage();
100076
100360
  if (!storage3) return false;
100077
100361
  try {
100078
100362
  if (record5 == null) storage3.removeItem(recordKey(profileId, symbol2));
100079
- else storage3.setItem(recordKey(profileId, symbol2), JSON.stringify(record5));
100363
+ else storage3.setItem(recordKey(profileId, symbol2), JSON.stringify(versioned(record5)));
100080
100364
  return true;
100081
100365
  } catch {
100082
100366
  return false;
100083
100367
  }
100084
100368
  };
100369
+ NO_FILLS = { fills: [], complete: false, coversFromMs: null };
100370
+ nativeFillsPageFromUserFills = (rawFills, evidence) => {
100371
+ const live = evidence.source === "live";
100372
+ if (evidence.providerRowCount < evidence.providerPageCap) return { fills: [...rawFills], complete: live, coversFromMs: null };
100373
+ const oldest = evidence.oldestFillTimeMs;
100374
+ if (oldest == null) return NO_FILLS;
100375
+ return {
100376
+ fills: rawFills.filter((fill) => Number(fill?.time) > oldest),
100377
+ complete: live,
100378
+ coversFromMs: oldest + 1
100379
+ };
100380
+ };
100381
+ fillsReader = (io) => {
100382
+ let read = null;
100383
+ return () => {
100384
+ read ??= io.readFills().catch((error48) => {
100385
+ if (io.endsPass?.(error48)) throw error48;
100386
+ return NO_FILLS;
100387
+ });
100388
+ return read;
100389
+ };
100390
+ };
100391
+ flatReadOf = (position, page, symbol2) => {
100392
+ const stateMs = position.stateTimeMs;
100393
+ if (!page.complete || stateMs == null || !Number.isSafeInteger(stateMs)) return null;
100394
+ const market = normalizeHyperliquidMarketSymbol(symbol2);
100395
+ let newest = null;
100396
+ for (const fill of page.fills) {
100397
+ if (fill == null || typeof fill !== "object" || Array.isArray(fill)) continue;
100398
+ const row = fill;
100399
+ if (normalizeHyperliquidMarketSymbol(String(row.coin ?? "")) !== market) continue;
100400
+ const time3 = Number(row.time);
100401
+ if (!Number.isSafeInteger(time3)) return null;
100402
+ newest = newest == null ? time3 : Math.max(newest, time3);
100403
+ }
100404
+ return {
100405
+ position: String(position.size),
100406
+ stateMs,
100407
+ newestFillMs: newest,
100408
+ pageComplete: page.coversFromMs == null || page.coversFromMs < stateMs
100409
+ };
100410
+ };
100411
+ orderFillTimes = (page, orderId, symbol2) => {
100412
+ const market = normalizeHyperliquidMarketSymbol(symbol2);
100413
+ return page.fills.flatMap((fill) => {
100414
+ if (fill == null || typeof fill !== "object" || Array.isArray(fill)) return [];
100415
+ const row = fill;
100416
+ if (String(row.oid ?? "").trim() !== orderId.trim()) return [];
100417
+ if (normalizeHyperliquidMarketSymbol(String(row.coin ?? "")) !== market) return [];
100418
+ const time3 = Number(row.time);
100419
+ return [Number.isSafeInteger(time3) && time3 > 0 ? time3 : Number.NaN];
100420
+ });
100421
+ };
100422
+ namedOrderId = (evidence) => {
100423
+ const orderId = Number(evidence.orderId);
100424
+ return evidence.responseValid && evidence.orderMatches && Number.isSafeInteger(orderId) && orderId > 0 ? String(orderId) : null;
100425
+ };
100085
100426
  NativeOrderNotSentError = class extends Error {
100086
100427
  constructor(cause) {
100087
100428
  super(cause instanceof Error ? cause.message : "The exchange call failed before dispatch.");
@@ -100146,8 +100487,147 @@ var init_native_protection_device = __esm({
100146
100487
  const statuses = root?.response?.data?.statuses;
100147
100488
  return Array.isArray(statuses) && statuses.length > 0 && statuses.every((status) => Boolean(status && typeof status === "object" && "error" in status));
100148
100489
  };
100490
+ TRAILING_LOT_FIRED = "protective_trailing_lot_fired";
100491
+ TRAILING_LOT_POSITION_ENDED = "protective_trailing_lot_position_ended";
100492
+ TRAILING_LOT_OTHER_SIDE = "protective_trailing_lot_other_side";
100493
+ lotFillLeftPosition = (lot) => lot.retiredReason === TRAILING_LOT_FIRED || lot.retiredReason === TRAILING_LOT_POSITION_ENDED || lot.retiredReason === TRAILING_LOT_OTHER_SIDE;
100494
+ lotOfAdd = (lot, add) => lot.fillKey === add.clientOrderId || add.orderId != null && (lot.fillKey === add.orderId || lot.fillOrderId === add.orderId);
100495
+ ORDER_ID_PATTERN = /^\d+$/;
100496
+ lotFillOrderId = (lot) => lot.fillOrderId ?? (ORDER_ID_PATTERN.test(lot.fillKey) ? lot.fillKey : null);
100497
+ lotPositionSince = async (lot, record5, fills) => {
100498
+ const orderId = lotFillOrderId(lot);
100499
+ if (orderId == null) return "unknown";
100500
+ const page = await fills();
100501
+ return nativePositionEndedSince({
100502
+ fills: page.fills,
100503
+ complete: page.complete,
100504
+ orderId,
100505
+ isLong: record5.isLong,
100506
+ symbol: record5.symbol
100507
+ });
100508
+ };
100509
+ ownLotOrderIds = (record5) => (record5.lots ?? []).flatMap((lot) => lot.orderId == null ? [] : [lot.orderId]);
100510
+ lotRetracement = (settings, size, sizeDecimals) => {
100511
+ const stopLoss = settings.stopLoss;
100512
+ if (!stopLoss?.trailing || !(Number(size) > 0)) return null;
100513
+ return nativeTrailingRetracement({ mode: stopLoss.mode, value: stopLoss.value, lotSize: Number(size), sizeDecimals });
100514
+ };
100515
+ lotReport = (symbol2, lot, status, metadata) => ({
100516
+ order_id: lot.orderId == null ? null : String(lot.orderId),
100517
+ symbol: symbol2,
100518
+ action: "AUTO_SL",
100519
+ status,
100520
+ execution_metadata: { trailing_lot: true, protected_size: lot.size, retracement: lot.retracement, ...metadata }
100521
+ });
100522
+ sendTrailingLot = async (args) => {
100523
+ const { io } = args;
100524
+ if (!io.placeTrailingLot) return { lot: args.lot, report: null };
100525
+ const mutationId = io.newMutationId();
100526
+ const journaled = {
100527
+ ...args.lot,
100528
+ mutationId,
100529
+ orderId: null,
100530
+ placedAtMs: null,
100531
+ sentAtMs: io.nowMs()
100532
+ };
100533
+ if (!args.journal(journaled)) {
100534
+ return {
100535
+ lot: args.lot,
100536
+ report: lotReport(args.symbol, args.lot, "failed", { reason_code: "protective_lifecycle_persistence_failed" })
100537
+ };
100538
+ }
100539
+ const place = io.placeTrailingLot;
100540
+ const outcome = await notSentRestores(
100541
+ () => attempt(io, () => place({ mutationId, size: journaled.size, retracement: journaled.retracement })),
100542
+ () => args.journal(args.lot)
100543
+ );
100544
+ if (!outcome.ok && outcome.error instanceof NativeOrderNotSentError) {
100545
+ args.journal(args.lot);
100546
+ return {
100547
+ lot: args.lot,
100548
+ report: lotReport(args.symbol, args.lot, "failed", { reason_code: "protective_place_not_sent", error: errorText(outcome.error) })
100549
+ };
100550
+ }
100551
+ if (!outcome.ok && outcome.refused) {
100552
+ const retired = { ...journaled, retiredReason: "protective_place_rejected" };
100553
+ return {
100554
+ lot: retired,
100555
+ report: lotReport(args.symbol, retired, "failed", { reason_code: "protective_place_rejected", error: errorText(outcome.error) })
100556
+ };
100557
+ }
100558
+ const orderId = outcome.ok ? outcome.response?.orderId ?? null : null;
100559
+ const placed = { ...journaled, orderId };
100560
+ return {
100561
+ lot: placed,
100562
+ report: lotReport(args.symbol, placed, "executed", {
100563
+ ...args.reasonCode ? { reason_code: args.reasonCode } : {},
100564
+ ...args.lot.orderId != null ? { replaced_order_id: String(args.lot.orderId) } : {}
100565
+ })
100566
+ };
100567
+ };
100568
+ planNativeFillLot = (record5, input) => {
100569
+ const fillKey = input.fillKey.trim();
100570
+ const retracement = lotRetracement(input.settings, input.fillSize, input.sizeDecimals);
100571
+ if (!fillKey || retracement == null) return record5;
100572
+ const lots = [...record5.lots ?? []];
100573
+ if (lots.some((lot) => lot.fillKey === fillKey)) return record5;
100574
+ const planned = {
100575
+ mutationId: null,
100576
+ fillKey,
100577
+ fillEventMs: input.nowMs,
100578
+ size: input.fillSize,
100579
+ retracement,
100580
+ orderId: null,
100581
+ placedAtMs: null,
100582
+ sentAtMs: input.nowMs,
100583
+ replacedOnce: false,
100584
+ fillEventFromDevice: true
100585
+ };
100586
+ const pendingIndex = input.pendingKey ? lots.findIndex((lot) => lot.fillKey === input.pendingKey && lot.mutationId == null && lot.size === "") : -1;
100587
+ if (pendingIndex >= 0) lots[pendingIndex] = planned;
100588
+ else lots.push(planned);
100589
+ return { ...record5, lots };
100590
+ };
100591
+ planNativeStandbyAdd = (record5, input) => {
100592
+ if (!input.clientOrderId || (record5.standby ?? []).some((add) => add.clientOrderId === input.clientOrderId)) return record5;
100593
+ return {
100594
+ ...record5,
100595
+ standby: [...record5.standby ?? [], { clientOrderId: input.clientOrderId, orderId: null, sentAtMs: input.nowMs }]
100596
+ };
100597
+ };
100598
+ nameNativeStandbyAdd = (record5, clientOrderId, orderId) => (record5.standby ?? []).some((add) => add.clientOrderId === clientOrderId && add.orderId !== orderId) ? {
100599
+ ...record5,
100600
+ standby: (record5.standby ?? []).map((add) => add.clientOrderId === clientOrderId ? { ...add, orderId } : add)
100601
+ } : record5;
100602
+ dropNativeStandbyAdd = (record5, clientOrderId) => {
100603
+ const standby = (record5.standby ?? []).filter((add) => add.clientOrderId !== clientOrderId);
100604
+ const { standby: _dropped, ...rest } = record5;
100605
+ return standby.length > 0 ? { ...rest, standby } : rest;
100606
+ };
100607
+ dropNativePendingLot = (record5, key) => versioned({
100608
+ ...record5,
100609
+ lots: (record5.lots ?? []).filter((lot) => !(lot.fillKey === key && lot.mutationId == null && lot.size === ""))
100610
+ });
100611
+ planNativePendingLot = (record5, input) => {
100612
+ const retracement = lotRetracement(input.settings, String(input.sizeHint), input.sizeDecimals);
100613
+ if (retracement == null || !input.key || (record5.lots ?? []).some((lot) => lot.fillKey === input.key)) return record5;
100614
+ return versioned({
100615
+ ...record5,
100616
+ lots: [...record5.lots ?? [], {
100617
+ mutationId: null,
100618
+ fillKey: input.key,
100619
+ fillEventMs: input.nowMs,
100620
+ fillEventFromDevice: true,
100621
+ size: "",
100622
+ retracement,
100623
+ orderId: null,
100624
+ placedAtMs: null,
100625
+ sentAtMs: input.nowMs,
100626
+ replacedOnce: false
100627
+ }]
100628
+ });
100629
+ };
100149
100630
  planNativeOpen = (input) => {
100150
- if (input.settings.stopLoss?.trailing) return null;
100151
100631
  const request = nativeEntryRequest({
100152
100632
  settings: input.settings,
100153
100633
  isLong: input.isLong,
@@ -100173,7 +100653,9 @@ var init_native_protection_device = __esm({
100173
100653
  triggerPrice: Number(member.trigger),
100174
100654
  clientOrderId: member.clientOrderId
100175
100655
  })),
100176
- record: {
100656
+ // Trailing mode: the open's lot is journaled with the entry, sized once
100657
+ // its fill is known (or from the position it opened), so no settle can lose it.
100658
+ record: planNativePendingLot({
100177
100659
  version: NATIVE_PROTECTION_RECORD_VERSION,
100178
100660
  profileId: input.profileId,
100179
100661
  symbol: input.symbol,
@@ -100184,7 +100666,13 @@ var init_native_protection_device = __esm({
100184
100666
  entryClientOrderId: input.entryClientOrderId,
100185
100667
  createdAtMs: input.nowMs,
100186
100668
  members
100187
- }
100669
+ }, {
100670
+ settings: input.settings,
100671
+ sizeDecimals: input.sizeDecimals,
100672
+ key: input.entryClientOrderId,
100673
+ sizeHint: input.entrySize,
100674
+ nowMs: input.nowMs
100675
+ })
100188
100676
  };
100189
100677
  };
100190
100678
  recordEntryChildren = (record5, entryResponse) => ({
@@ -100226,7 +100714,7 @@ var init_native_protection_device = __esm({
100226
100714
  }
100227
100715
  continue;
100228
100716
  }
100229
- if (member.orderId != null || member.retiredReason) {
100717
+ if (member.orderId != null || member.retiredReason || member.plannedAfterMs != null) {
100230
100718
  members.push(member);
100231
100719
  continue;
100232
100720
  }
@@ -100239,6 +100727,109 @@ var init_native_protection_device = __esm({
100239
100727
  }
100240
100728
  return { ...record5, members };
100241
100729
  };
100730
+ plannedPair = (settings, afterMs, io) => ["sl", "tp"].filter((kind) => (kind === "sl" ? settings.stopLoss : settings.takeProfit) != null).map((kind) => ({
100731
+ kind,
100732
+ clientOrderId: clientOrderIdForMutation(io.newMutationId()),
100733
+ orderId: null,
100734
+ trigger: "",
100735
+ placedAtMs: null,
100736
+ sentAtMs: io.nowMs(),
100737
+ replacedOnce: false,
100738
+ plannedAfterMs: afterMs
100739
+ }));
100740
+ resolveStandbyAdds = async (args) => {
100741
+ const { io } = args;
100742
+ let record5 = args.record;
100743
+ const standby = record5.standby ?? [];
100744
+ if (standby.length === 0) return { record: record5, addFillMs: null, undecided: false };
100745
+ const left = [];
100746
+ let addFillMs = null;
100747
+ for (const add of standby) {
100748
+ if (left.length > 0) {
100749
+ left.push(add);
100750
+ continue;
100751
+ }
100752
+ let orderId = add.orderId;
100753
+ let endedUnfilledAtMs = null;
100754
+ if (orderId == null) {
100755
+ const evidence = await io.readOrderStatus(add.clientOrderId);
100756
+ orderId = namedOrderId(evidence);
100757
+ if (orderId == null) {
100758
+ if (!(evidence.responseStatus === UNKNOWN_ORDER_RESPONSE && io.nowMs() > io.neverLandsAfterMs(add.sentAtMs))) {
100759
+ left.push(add);
100760
+ }
100761
+ continue;
100762
+ }
100763
+ if (classifyHyperliquidOrderStatus(evidence.orderStatus) === "terminal_unfilled") {
100764
+ endedUnfilledAtMs = evidence.orderTimestampMs ?? null;
100765
+ }
100766
+ }
100767
+ const page = await args.fills();
100768
+ const times = orderFillTimes(page, orderId, record5.symbol);
100769
+ const verdict = nativeFillOpenedPosition({
100770
+ fills: page.fills,
100771
+ complete: page.complete,
100772
+ orderId,
100773
+ isLong: record5.isLong,
100774
+ symbol: record5.symbol
100775
+ });
100776
+ const fillMs = times.length > 0 && times.every(Number.isFinite) ? Math.max(...times) : null;
100777
+ if (verdict === "other_side") {
100778
+ const lots = record5.lots ?? [];
100779
+ if (lots.some((lot) => lotOfAdd(lot, { clientOrderId: add.clientOrderId, orderId }))) {
100780
+ record5 = {
100781
+ ...record5,
100782
+ lots: lots.map((lot) => lotOfAdd(lot, { clientOrderId: add.clientOrderId, orderId }) && !lot.retiredReason ? { ...lot, retiredReason: TRAILING_LOT_OTHER_SIDE } : lot)
100783
+ };
100784
+ }
100785
+ continue;
100786
+ }
100787
+ if (verdict === "unknown" || fillMs == null) {
100788
+ const neverFilled = endedUnfilledAtMs != null && page.complete && times.length === 0 && (page.coversFromMs == null || page.coversFromMs <= endedUnfilledAtMs);
100789
+ if (neverFilled) continue;
100790
+ let pageAccountsForAdd = times.length > 0;
100791
+ if (!pageAccountsForAdd && page.coversFromMs != null) {
100792
+ const evidence = await io.readOrderStatus(orderId);
100793
+ const endedMs = evidence.statusTimestampMs;
100794
+ pageAccountsForAdd = evidence.responseValid && evidence.terminal && endedMs != null && endedMs < page.coversFromMs;
100795
+ }
100796
+ const positionEnded = nativePositionEndedSince({
100797
+ fills: page.fills,
100798
+ complete: page.complete,
100799
+ orderId,
100800
+ isLong: record5.isLong,
100801
+ symbol: record5.symbol,
100802
+ flatRead: pageAccountsForAdd ? flatReadOf(args.position, page, record5.symbol) : null
100803
+ }) === "ended";
100804
+ if (!positionEnded) left.push(add);
100805
+ continue;
100806
+ }
100807
+ const stateMs = args.position.stateTimeMs;
100808
+ if (stateMs == null || !(stateMs > fillMs)) {
100809
+ left.push(add);
100810
+ continue;
100811
+ }
100812
+ record5 = { ...record5, positionOrderId: orderId };
100813
+ addFillMs = fillMs;
100814
+ if (verdict === "opened") {
100815
+ const resting = record5.members.filter((member) => member.orderId != null && !member.retiredReason && args.page.some((order) => order.oid === member.orderId));
100816
+ const planned = plannedPair(args.settings, fillMs, io);
100817
+ record5 = {
100818
+ ...record5,
100819
+ members: [
100820
+ ...planned.map((member) => {
100821
+ const kept = resting.find((entry) => entry.kind === member.kind);
100822
+ return kept ? { ...kept, replacedOnce: false } : member;
100823
+ }),
100824
+ // A kind the settings no longer enable stays tracked while it rests.
100825
+ ...resting.filter((entry) => !planned.some((member) => member.kind === entry.kind))
100826
+ ]
100827
+ };
100828
+ }
100829
+ }
100830
+ const { standby: _decided, ...rest } = record5;
100831
+ return { record: left.length > 0 ? { ...rest, standby: left } : rest, addFillMs, undecided: left.length > 0 };
100832
+ };
100242
100833
  settleNativeProtectionAfterFill = async (input) => {
100243
100834
  const { io } = input;
100244
100835
  const reports = [];
@@ -100247,6 +100838,17 @@ var init_native_protection_device = __esm({
100247
100838
  const page = await io.readOpenOrders();
100248
100839
  const position = await io.readPosition();
100249
100840
  const symbol2 = record5.symbol;
100841
+ const fills = fillsReader(io);
100842
+ const settlingAdds = (record5.standby ?? []).length > 0;
100843
+ const boundary = await resolveStandbyAdds({ record: record5, settings: input.settings, io, fills, position, page });
100844
+ record5 = boundary.record;
100845
+ if (boundary.undecided) {
100846
+ return { record: record5, reports };
100847
+ }
100848
+ const entryOrderId = String(input.entryOrderId ?? "").trim();
100849
+ if (record5.positionOrderId == null && boundary.addFillMs == null && !settlingAdds && ORDER_ID_PATTERN.test(entryOrderId)) {
100850
+ record5 = { ...record5, positionOrderId: entryOrderId };
100851
+ }
100250
100852
  if (!isOpenInDirection2(position.size, record5.isLong)) {
100251
100853
  reports.push({
100252
100854
  order_id: input.entryOrderId,
@@ -100285,7 +100887,10 @@ var init_native_protection_device = __esm({
100285
100887
  });
100286
100888
  let eventMs = Math.max(
100287
100889
  0,
100288
- ...observations.map((entry) => entry.row?.timestamp ?? entry.member.placedAtMs ?? 0)
100890
+ ...observations.map((entry) => entry.row?.timestamp ?? entry.member.placedAtMs ?? 0),
100891
+ // An add's own fill, and the fill a planned pair answers: Hyperliquid's times.
100892
+ boundary.addFillMs ?? 0,
100893
+ ...record5.members.map((member) => member.plannedAfterMs ?? 0)
100289
100894
  );
100290
100895
  if (eventMs <= 0 && input.entryOrderId) {
100291
100896
  const entryStatus = await io.readOrderStatus(input.entryOrderId);
@@ -100365,7 +100970,7 @@ var init_native_protection_device = __esm({
100365
100970
  });
100366
100971
  continue;
100367
100972
  }
100368
- if (existing != null && existing.orderId == null && !unknownClientOrderIds.has(existing.clientOrderId)) {
100973
+ if (existing != null && existing.orderId == null && existing.plannedAfterMs == null && !unknownClientOrderIds.has(existing.clientOrderId)) {
100369
100974
  continue;
100370
100975
  }
100371
100976
  if (gate !== "place") {
@@ -100386,7 +100991,8 @@ var init_native_protection_device = __esm({
100386
100991
  symbol: symbol2,
100387
100992
  positionSize: String(position.size),
100388
100993
  ownClientOrderIds: [],
100389
- rows: coverRows(page)
100994
+ rows: coverRows(page),
100995
+ ownTrailingOrderIds: ownLotOrderIds(record5)
100390
100996
  });
100391
100997
  if (cover.decision !== "place") {
100392
100998
  continue;
@@ -100424,7 +101030,7 @@ var init_native_protection_device = __esm({
100424
101030
  () => io.persist({ ...record5, phase: "active", members: before })
100425
101031
  );
100426
101032
  if (!outcome.ok && outcome.refused) {
100427
- members.splice(0, members.length, ...before);
101033
+ if (outcome.error instanceof NativeOrderNotSentError) members.splice(0, members.length, ...before);
100428
101034
  reports.push({
100429
101035
  order_id: null,
100430
101036
  symbol: symbol2,
@@ -100433,6 +101039,8 @@ var init_native_protection_device = __esm({
100433
101039
  execution_metadata: {
100434
101040
  reason_code: outcome.error instanceof NativeOrderNotSentError ? "protective_place_not_sent" : "protective_place_rejected",
100435
101041
  trigger_price: step.trigger,
101042
+ // The fill this stop protects: its warning is shown once per stop.
101043
+ entry_order_id: input.entryOrderId,
100436
101044
  error: errorText(outcome.error)
100437
101045
  }
100438
101046
  });
@@ -100456,6 +101064,59 @@ var init_native_protection_device = __esm({
100456
101064
  }
100457
101065
  });
100458
101066
  }
101067
+ const lots = [...record5.lots ?? []];
101068
+ const fillKey = String(input.entryOrderId ?? "").trim();
101069
+ let lotIndex = fillKey ? lots.findIndex((lot) => lot.fillKey === fillKey) : -1;
101070
+ const fillLotSize = Number(input.fillSize) > 0 ? input.fillSize : record5.phase === "entry_pending" ? String(Math.abs(position.size)) : "0";
101071
+ const fillRetracement = lotRetracement(input.settings, fillLotSize, input.sizeDecimals);
101072
+ if (lotIndex < 0 && fillKey && fillRetracement) {
101073
+ lots.push({
101074
+ mutationId: null,
101075
+ fillKey,
101076
+ fillEventMs: eventMs,
101077
+ size: fillLotSize,
101078
+ retracement: fillRetracement,
101079
+ orderId: null,
101080
+ placedAtMs: null,
101081
+ sentAtMs: io.nowMs(),
101082
+ replacedOnce: false
101083
+ });
101084
+ lotIndex = lots.length - 1;
101085
+ }
101086
+ const journaledLot = lotIndex >= 0 ? lots[lotIndex] : null;
101087
+ if (journaledLot && journaledLot.mutationId == null && !journaledLot.retiredReason && journaledLot.userCancelledOrderId == null && io.placeTrailingLot) {
101088
+ const size = journaledLot.size || fillLotSize;
101089
+ const retracement = lotRetracement(input.settings, size, input.sizeDecimals);
101090
+ if (retracement) {
101091
+ const { fillEventFromDevice: _deviceTime, ...withoutDeviceTime } = journaledLot;
101092
+ let planned = eventMs > 0 ? { ...withoutDeviceTime, size, retracement, fillEventMs: eventMs } : { ...journaledLot, size, retracement };
101093
+ if (gate === "place" && lotFillOrderId(planned) == null) {
101094
+ const named = namedOrderId(await io.readOrderStatus(planned.fillKey));
101095
+ if (named != null) planned = { ...planned, fillOrderId: named };
101096
+ }
101097
+ const since = gate === "place" ? await lotPositionSince(planned, record5, fills) : "unknown";
101098
+ if (since === "ended") {
101099
+ lots[lotIndex] = { ...planned, retiredReason: TRAILING_LOT_POSITION_ENDED };
101100
+ } else if (since === "open") {
101101
+ const index = lotIndex;
101102
+ const sent = await sendTrailingLot({
101103
+ io,
101104
+ symbol: symbol2,
101105
+ lot: planned,
101106
+ journal: (lot) => io.persist({
101107
+ ...record5,
101108
+ phase: "active",
101109
+ members,
101110
+ lots: [...lots.slice(0, index), lot, ...lots.slice(index + 1)]
101111
+ })
101112
+ });
101113
+ lots[index] = sent.lot;
101114
+ if (sent.report) reports.push(sent.report);
101115
+ } else {
101116
+ lots[lotIndex] = planned;
101117
+ }
101118
+ }
101119
+ }
100459
101120
  for (const entry of observations) {
100460
101121
  if (!entry.row || reports.some((report) => report.order_id === String(entry.row?.oid))) continue;
100461
101122
  reports.push({
@@ -100470,7 +101131,7 @@ var init_native_protection_device = __esm({
100470
101131
  }
100471
101132
  });
100472
101133
  }
100473
- record5 = { ...record5, phase: "active", members };
101134
+ record5 = { ...record5, phase: "active", members, ...lots.length > 0 ? { lots } : {} };
100474
101135
  return { record: record5, reports };
100475
101136
  };
100476
101137
  reconcileNativeProtection = async (input) => {
@@ -100482,6 +101143,28 @@ var init_native_protection_device = __esm({
100482
101143
  const position = await io.readPosition();
100483
101144
  const symbol2 = record5.symbol;
100484
101145
  const stateMs = position.stateTimeMs ?? Number.NEGATIVE_INFINITY;
101146
+ const fills = fillsReader(io);
101147
+ const undecidedAdds = (record5.standby ?? []).length > 0;
101148
+ let membersPositionEnded = null;
101149
+ const membersEnded = () => {
101150
+ membersPositionEnded ??= (async () => {
101151
+ let anchor = record5.positionOrderId ?? null;
101152
+ if (anchor == null) {
101153
+ anchor = namedOrderId(await io.readOrderStatus(record5.entryClientOrderId));
101154
+ if (anchor != null) record5 = { ...record5, positionOrderId: anchor };
101155
+ }
101156
+ const fillsPage = await fills();
101157
+ return nativePositionEndedSince({
101158
+ fills: fillsPage.fills,
101159
+ complete: fillsPage.complete,
101160
+ orderId: anchor ?? "",
101161
+ isLong: record5.isLong,
101162
+ symbol: symbol2,
101163
+ flatRead: flatReadOf(position, fillsPage, symbol2)
101164
+ });
101165
+ })();
101166
+ return membersPositionEnded;
101167
+ };
100485
101168
  const observations = observeMembers(record5, page).map((entry) => ({
100486
101169
  ...entry,
100487
101170
  member: entry.row ? { ...entry.member, placedAtMs: entry.row.timestamp || entry.member.placedAtMs } : entry.member
@@ -100516,7 +101199,8 @@ var init_native_protection_device = __esm({
100516
101199
  symbol: symbol2,
100517
101200
  positionSize: String(position.size),
100518
101201
  ownClientOrderIds: [],
100519
- rows: coverRows(page)
101202
+ rows: coverRows(page),
101203
+ ownTrailingOrderIds: ownLotOrderIds(record5)
100520
101204
  });
100521
101205
  if (cover.decision !== "place") return args.member;
100522
101206
  const clientOrderId = clientOrderIdForMutation(io.newMutationId());
@@ -100606,7 +101290,8 @@ var init_native_protection_device = __esm({
100606
101290
  trigger_price: args.trigger,
100607
101291
  position_tpsl: true,
100608
101292
  protected_size: Math.abs(position.size),
100609
- ...refused ? { error: errorText(outcome.error) } : {}
101293
+ // A refused replacement or re-arm is not placed again: left to a person.
101294
+ ...refused ? { error: errorText(outcome.error), manual_intervention: true } : {}
100610
101295
  }
100611
101296
  });
100612
101297
  return placed;
@@ -100651,6 +101336,33 @@ var init_native_protection_device = __esm({
100651
101336
  members.push(member);
100652
101337
  continue;
100653
101338
  }
101339
+ if (member.plannedAfterMs != null) {
101340
+ if (!kindEnabled(member)) continue;
101341
+ const plannedGate = nativePlacementGate({
101342
+ eventMs: member.plannedAfterMs,
101343
+ position: position.size,
101344
+ positionStateMs: stateMs,
101345
+ isLong: record5.isLong
101346
+ });
101347
+ if (plannedGate === "not_required") continue;
101348
+ const plannedTrigger = currentTrigger(member);
101349
+ if (plannedGate === "need_reads" || plannedTrigger == null) {
101350
+ anyResting = true;
101351
+ members.push(member);
101352
+ continue;
101353
+ }
101354
+ const placed = await placeMember({
101355
+ member,
101356
+ trigger: plannedTrigger,
101357
+ replacedOnce: false,
101358
+ eventMs: member.plannedAfterMs,
101359
+ reasonCode: "protective_native_position_opened_by_add",
101360
+ observationIndex
101361
+ });
101362
+ members.push(placed);
101363
+ if (!placed.retiredReason) anyResting = true;
101364
+ continue;
101365
+ }
100654
101366
  if (member.orderId == null) {
100655
101367
  if (io.nowMs() <= io.neverLandsAfterMs(member.sentAtMs) || !unknownClientOrderIds.has(member.clientOrderId)) {
100656
101368
  anyResting = true;
@@ -100694,10 +101406,9 @@ var init_native_protection_device = __esm({
100694
101406
  });
100695
101407
  explained = end2 === "resting" || end2 === "pending" || end2 === "unknown" ? "status_read" : "ended_with_position";
100696
101408
  }
100697
- if (explained !== "ended_with_position") {
100698
- anyResting = true;
100699
- members.push(member);
100700
- }
101409
+ if (explained === "ended_with_position" && await membersEnded() === "ended") continue;
101410
+ anyResting = true;
101411
+ members.push(member);
100701
101412
  continue;
100702
101413
  }
100703
101414
  const evidence = await io.readOrderStatus(member.orderId);
@@ -100719,7 +101430,7 @@ var init_native_protection_device = __esm({
100719
101430
  });
100720
101431
  if (rearm === "retire" || !kindEnabled(member)) continue;
100721
101432
  const rearmTrigger = currentTrigger(member);
100722
- if (rearm === "need_reads" || rearmTrigger == null) {
101433
+ if (rearm === "need_reads" || rearmTrigger == null || undecidedAdds) {
100723
101434
  members.push(member);
100724
101435
  continue;
100725
101436
  }
@@ -100792,10 +101503,235 @@ var init_native_protection_device = __esm({
100792
101503
  members.push(replacement);
100793
101504
  if (replacement !== member && !replacement.retiredReason) anyResting = true;
100794
101505
  }
100795
- if (!positionOpen && !anyResting) {
101506
+ const lots = [];
101507
+ const storedLots = record5.lots ?? [];
101508
+ const isUnsized = (lot) => lot.mutationId == null && lot.size === "";
101509
+ const priorLots = [...storedLots.filter((lot) => !isUnsized(lot)), ...storedLots.filter(isUnsized)];
101510
+ const journalLot = (index, lot) => io.persist({
101511
+ ...record5,
101512
+ members,
101513
+ lots: [...lots, lot, ...priorLots.slice(index + 1)]
101514
+ });
101515
+ for (const [index, prior] of priorLots.entries()) {
101516
+ let lot = prior;
101517
+ const restingRow = lot.orderId == null ? null : page.find((order) => order.oid === lot.orderId) ?? null;
101518
+ const otherSideUnnamed = lot.retiredReason === TRAILING_LOT_OTHER_SIDE && lot.mutationId != null && lot.orderId == null;
101519
+ if ((lot.retiredReason || lot.userCancelledOrderId != null) && !otherSideUnnamed && !(restingRow && readListedProtectiveRow({ triggerCondition: restingRow.trigger_condition }) === "resting")) {
101520
+ lots.push(lot);
101521
+ continue;
101522
+ }
101523
+ if (lot.mutationId == null) {
101524
+ if (lot.fillEventFromDevice) {
101525
+ const entryStatus = await io.readOrderStatus(lot.fillKey);
101526
+ if (entryStatus.responseValid && entryStatus.orderMatches && entryStatus.statusTimestampMs != null) {
101527
+ const { fillEventFromDevice: _deviceTime, ...exchangeTimed } = lot;
101528
+ const named = lotFillOrderId(lot) == null ? namedOrderId(entryStatus) : null;
101529
+ lot = { ...exchangeTimed, fillEventMs: entryStatus.statusTimestampMs, ...named != null ? { fillOrderId: named } : {} };
101530
+ } else if (entryStatus.responseStatus === UNKNOWN_ORDER_RESPONSE && io.nowMs() > io.neverLandsAfterMs(lot.sentAtMs)) {
101531
+ continue;
101532
+ } else {
101533
+ anyResting = true;
101534
+ lots.push(lot);
101535
+ continue;
101536
+ }
101537
+ }
101538
+ const gate = nativePlacementGate({
101539
+ eventMs: lot.fillEventMs,
101540
+ position: position.size,
101541
+ positionStateMs: stateMs,
101542
+ isLong: record5.isLong
101543
+ });
101544
+ if (gate === "not_required") continue;
101545
+ if (gate !== "place") {
101546
+ anyResting = true;
101547
+ lots.push(lot);
101548
+ continue;
101549
+ }
101550
+ if (lotFillOrderId(lot) == null) {
101551
+ const named = namedOrderId(await io.readOrderStatus(lot.fillKey));
101552
+ if (named != null) lot = { ...lot, fillOrderId: named };
101553
+ }
101554
+ if ((record5.standby ?? []).some((add) => lotOfAdd(lot, add))) {
101555
+ anyResting = true;
101556
+ lots.push(lot);
101557
+ continue;
101558
+ }
101559
+ const since = await lotPositionSince(lot, record5, fills);
101560
+ if (since === "ended") {
101561
+ lots.push({ ...lot, retiredReason: TRAILING_LOT_POSITION_ENDED });
101562
+ continue;
101563
+ }
101564
+ if (since !== "open") {
101565
+ anyResting = true;
101566
+ lots.push(lot);
101567
+ continue;
101568
+ }
101569
+ if (!lot.size) {
101570
+ const others = [...lots, ...priorLots.slice(index + 1)];
101571
+ const covered = others.reduce((total, other) => other.size && !lotFillLeftPosition(other) ? total + Number(other.size) : total, 0);
101572
+ const uncovered = Number((Math.abs(position.size) - covered).toFixed(input.sizeDecimals));
101573
+ if (!(uncovered > 0)) continue;
101574
+ lot = { ...lot, size: String(uncovered) };
101575
+ }
101576
+ const retracement2 = lotRetracement(input.settings, lot.size, input.sizeDecimals);
101577
+ if (retracement2 == null) {
101578
+ lots.push(lot);
101579
+ continue;
101580
+ }
101581
+ const sent2 = await sendTrailingLot({ io, symbol: symbol2, lot: { ...lot, retracement: retracement2 }, journal: (next) => journalLot(index, next) });
101582
+ lots.push(sent2.lot);
101583
+ if (sent2.report) reports.push(sent2.report);
101584
+ if (!sent2.lot.retiredReason) anyResting = true;
101585
+ continue;
101586
+ }
101587
+ if (lot.orderId == null) {
101588
+ let answer = null;
101589
+ try {
101590
+ answer = io.readLotMutation ? await io.readLotMutation(lot.mutationId) : null;
101591
+ } catch (error48) {
101592
+ if (io.endsPass?.(error48)) throw error48;
101593
+ }
101594
+ const orderId = Number(answer?.exchange_order_id);
101595
+ const named = answer != null && (answer.status === "settled" && answer.outcome_code === "success" || answer.status === "reconciled" && answer.outcome_code === "exchange_effect_observed") && Number.isSafeInteger(orderId) && orderId > 0;
101596
+ if (named) {
101597
+ lot = { ...lot, orderId };
101598
+ } else if (lot.retiredReason && (answer?.status === "settled" && answer.outcome_code === "rejected" || answer?.status === "reconciled" && answer.outcome_code === "exchange_expired_unconfirmed" || answer?.status === "absent" && io.nowMs() > io.neverLandsAfterMs(lot.sentAtMs))) {
101599
+ lots.push({ ...lot, mutationId: null });
101600
+ continue;
101601
+ } else if (answer?.status === "settled" && answer.outcome_code === "rejected") {
101602
+ lots.push({ ...lot, retiredReason: "protective_place_rejected" });
101603
+ continue;
101604
+ } else if (answer?.status === "reconciled" && answer.outcome_code === "exchange_expired_unconfirmed" || answer?.status === "absent" && io.nowMs() > io.neverLandsAfterMs(lot.sentAtMs)) {
101605
+ if (!positionOpen) continue;
101606
+ const since = await lotPositionSince(lot, record5, fills);
101607
+ if (since === "ended") {
101608
+ lots.push({ ...lot, retiredReason: TRAILING_LOT_POSITION_ENDED });
101609
+ continue;
101610
+ }
101611
+ if (since !== "open") {
101612
+ anyResting = true;
101613
+ lots.push(lot);
101614
+ continue;
101615
+ }
101616
+ const sent2 = await sendTrailingLot({ io, symbol: symbol2, lot: { ...lot, mutationId: null }, journal: (next) => journalLot(index, next) });
101617
+ lots.push(sent2.lot);
101618
+ if (sent2.report) reports.push(sent2.report);
101619
+ if (!sent2.lot.retiredReason) anyResting = true;
101620
+ continue;
101621
+ } else {
101622
+ anyResting = true;
101623
+ lots.push(lot);
101624
+ continue;
101625
+ }
101626
+ }
101627
+ const lotOrderId = lot.orderId;
101628
+ const row = lot === prior ? restingRow : page.find((order) => order.oid === lotOrderId) ?? null;
101629
+ if (row && readListedProtectiveRow({ triggerCondition: row.trigger_condition }) === "resting") {
101630
+ lot = { ...lot, placedAtMs: row.timestamp || lot.placedAtMs };
101631
+ const stray = lot.retiredReason === TRAILING_LOT_OTHER_SIDE ? "cancel" : nativeStrayOrderDecision({
101632
+ placedMs: lot.placedAtMs ?? Number.POSITIVE_INFINITY,
101633
+ position: position.size,
101634
+ positionStateMs: stateMs,
101635
+ isLong: record5.isLong
101636
+ });
101637
+ if (stray === "cancel") {
101638
+ const outcome = await attempt(io, () => io.cancelOrder(lotOrderId));
101639
+ reports.push(lotReport(symbol2, lot, outcome.ok ? "executed" : "failed", {
101640
+ reason_code: outcome.ok ? "protective_native_stray_cancelled" : "protective_native_stray_cancel_failed",
101641
+ live_position_size: position.size,
101642
+ ...outcome.ok ? {} : { error: errorText(outcome.error) }
101643
+ }));
101644
+ if (!outcome.ok) {
101645
+ anyResting = true;
101646
+ lots.push(lot);
101647
+ }
101648
+ continue;
101649
+ }
101650
+ anyResting = true;
101651
+ lots.push(lot);
101652
+ continue;
101653
+ }
101654
+ if (lot.retiredReason || lot.userCancelledOrderId != null) {
101655
+ lots.push(lot);
101656
+ continue;
101657
+ }
101658
+ if (!positionOpen) {
101659
+ const explained = lot.placedAtMs != null ? explainAbsentProtectiveOrder({
101660
+ lastSeenRestingMs: lot.placedAtMs,
101661
+ position: position.size,
101662
+ positionStateMs: stateMs,
101663
+ isLong: record5.isLong
101664
+ }) : "status_read";
101665
+ if (explained === "ended_with_position") continue;
101666
+ const evidence2 = await io.readOrderStatus(lotOrderId);
101667
+ const end2 = classifyNativeOrderEnd({
101668
+ orderStatus: evidence2.responseValid ? String(evidence2.orderStatus ?? "") : "",
101669
+ replacedByOwnModify: false,
101670
+ userCancelledThroughVtx: false
101671
+ });
101672
+ if (end2 === "resting" || end2 === "pending" || end2 === "unknown") {
101673
+ anyResting = true;
101674
+ lots.push(lot);
101675
+ }
101676
+ continue;
101677
+ }
101678
+ const evidence = await io.readOrderStatus(lotOrderId);
101679
+ const end = classifyNativeOrderEnd({
101680
+ orderStatus: evidence.responseValid ? String(evidence.orderStatus ?? "") : "",
101681
+ replacedByOwnModify: false,
101682
+ userCancelledThroughVtx: false
101683
+ });
101684
+ if (end === "resting" || end === "pending" || end === "unknown" || end === "superseded" || end === "user_cancelled") {
101685
+ anyResting = true;
101686
+ lots.push(lot);
101687
+ continue;
101688
+ }
101689
+ if (end === "fired" || end === "ended_with_position") {
101690
+ lots.push({ ...lot, retiredReason: TRAILING_LOT_FIRED });
101691
+ continue;
101692
+ }
101693
+ if (end === "lost_permanent" || lot.replacedOnce) {
101694
+ const reason = end === "lost_permanent" ? "protective_stop_execution_rejected" : "protective_replacement_lost";
101695
+ lots.push({ ...lot, retiredReason: reason });
101696
+ reports.push(lotReport(symbol2, lot, "failed", { reason_code: reason, order_status: evidence.orderStatus, manual_intervention: true }));
101697
+ continue;
101698
+ }
101699
+ const lostGate = nativePlacementGate({
101700
+ eventMs: evidence.statusTimestampMs ?? Number.POSITIVE_INFINITY,
101701
+ position: position.size,
101702
+ positionStateMs: stateMs,
101703
+ isLong: record5.isLong
101704
+ });
101705
+ const retracement = lotRetracement(input.settings, lot.size, input.sizeDecimals);
101706
+ if (lostGate !== "place" || retracement == null) {
101707
+ lots.push(lot);
101708
+ continue;
101709
+ }
101710
+ const lostSince = await lotPositionSince(lot, record5, fills);
101711
+ if (lostSince === "ended") {
101712
+ lots.push({ ...lot, retiredReason: TRAILING_LOT_POSITION_ENDED });
101713
+ continue;
101714
+ }
101715
+ if (lostSince !== "open") {
101716
+ lots.push(lot);
101717
+ continue;
101718
+ }
101719
+ const sent = await sendTrailingLot({
101720
+ io,
101721
+ symbol: symbol2,
101722
+ lot: { ...lot, retracement, replacedOnce: true },
101723
+ journal: (next) => journalLot(index, next),
101724
+ reasonCode: "protective_stop_replaced"
101725
+ });
101726
+ lots.push(sent.lot);
101727
+ if (sent.report) reports.push(sent.report);
101728
+ if (!sent.lot.retiredReason) anyResting = true;
101729
+ }
101730
+ if (!positionOpen && !anyResting && !undecidedAdds) {
100796
101731
  return { record: null, reports };
100797
101732
  }
100798
- record5 = { ...record5, members };
101733
+ const { lots: _priorLots, ...withoutLots } = record5;
101734
+ record5 = { ...withoutLots, members, ...lots.length > 0 ? { lots } : {} };
100799
101735
  return { record: record5, reports };
100800
101736
  };
100801
101737
  }
@@ -104500,6 +105436,37 @@ var init_runtime_execution = __esm({
104500
105436
  publicRequestPriority: "trading_reduce",
104501
105437
  orderId
104502
105438
  })),
105439
+ placeTrailingLot: async ({ mutationId, size, retracement }) => {
105440
+ const response = await fenced((onExchangeOrderDispatched) => executeClientTrailingStop({
105441
+ ...common,
105442
+ onExchangeOrderDispatched,
105443
+ mutationId,
105444
+ side: exitSide,
105445
+ size: Number(size),
105446
+ retracement
105447
+ }));
105448
+ const answer = readHyperliquidTrailingStopAcknowledgement(response);
105449
+ return { orderId: answer.outcome === "placed" ? answer.order_id : null };
105450
+ },
105451
+ readLotMutation: async (mutationId) => {
105452
+ const mutation = await getClientRuntimeExchangeMutation(request.profileId, mutationId, request.signal);
105453
+ if (mutation == null) return { status: "absent" };
105454
+ if (mutation.operation_kind !== "trailing_stop") throw new Error("The ledger names another action for this trailing lot.");
105455
+ return { status: mutation.status, outcome_code: mutation.outcome_code, exchange_order_id: mutation.exchange_order_id };
105456
+ },
105457
+ // The device's own fills read (Client Mode: every Hyperliquid read comes
105458
+ // from the device), fresh, as the per-entry lane's episode rule reads it.
105459
+ readFills: async () => {
105460
+ const { rawFills, evidence } = await fetchBrowserUserFills({
105461
+ publicRequestPriority: "trading_reduce",
105462
+ config: request.config ?? {},
105463
+ walletAddress,
105464
+ symbols: [symbol2],
105465
+ forceRefresh: true,
105466
+ signal: request.signal
105467
+ });
105468
+ return nativeFillsPageFromUserFills(rawFills, evidence);
105469
+ },
104503
105470
  isDefinitiveRefusal: (error48) => error48 instanceof HyperliquidExchangeRejectionError || error48 instanceof NativeOrderNotSentError,
104504
105471
  neverLandsAfterMs: (sentAtMs) => clientOrderNeverLandsAfterMs(request.config, { kind: "absent", ageStartMs: sentAtMs }),
104505
105472
  newMutationId: () => createRuntimeId().toLowerCase(),
@@ -104533,17 +105500,29 @@ var init_runtime_execution = __esm({
104533
105500
  if (read.record.walletAddress !== wallet) return [nativeStorageReport(symbol2, "protective_wallet_mismatch")];
104534
105501
  try {
104535
105502
  const io = nativeProtectionIo(request, read.record.isLong);
104536
- if (read.record.phase === "entry_pending") {
105503
+ const standby = read.record.standby ?? [];
105504
+ if (read.record.phase === "entry_pending" || standby.length > 0) {
104537
105505
  const settled = await settleNativeProtectionAfterFill({
104538
105506
  record: read.record,
104539
105507
  settings: nativeSettingsOf(request.executionContext),
104540
105508
  sizeDecimals: request.executionContext.sizeDecimals,
104541
105509
  fillSize: "0",
104542
- entryOrderId: read.record.entryClientOrderId,
105510
+ entryOrderId: read.record.phase === "entry_pending" ? read.record.entryClientOrderId : standby[0].orderId ?? standby[0].clientOrderId,
104543
105511
  io
104544
105512
  });
104545
105513
  const reports2 = [...settled.reports];
104546
- if (!writeNativeProtectionRecord(profileId, symbol2, settled.record)) {
105514
+ let record5 = settled.record;
105515
+ if (record5 != null && record5.phase !== "entry_pending" && (record5.standby ?? []).length > 0) {
105516
+ const kept = await reconcileNativeProtection({
105517
+ record: record5,
105518
+ settings: nativeSettingsOf(request.executionContext),
105519
+ sizeDecimals: request.executionContext.sizeDecimals,
105520
+ io
105521
+ });
105522
+ reports2.push(...kept.reports);
105523
+ record5 = kept.record;
105524
+ }
105525
+ if (!writeNativeProtectionRecord(profileId, symbol2, record5)) {
104547
105526
  reports2.push(nativeStorageReport(symbol2, "protective_lifecycle_persistence_failed"));
104548
105527
  }
104549
105528
  return reports2;
@@ -107877,6 +108856,7 @@ var init_runtime_execution = __esm({
107877
108856
  if (entryMutationId) entryClientOrderId = clientOrderIdForMutation(entryMutationId);
107878
108857
  let nativeOpen = null;
107879
108858
  let nativeAddRecord = null;
108859
+ let nativePendingLotKey = null;
107880
108860
  const nativeProfileId = String(input.profileId).trim();
107881
108861
  const nativeBlocked = (reasonCode, message) => ({
107882
108862
  // A flip whose close already filled reports that close as executed.
@@ -107915,7 +108895,23 @@ var init_runtime_execution = __esm({
107915
108895
  }
107916
108896
  if (classified.intent === "add") {
107917
108897
  if (existingNative.kind === "record" && existingNative.record.isLong === (classified.side === "buy")) {
107918
- nativeAddRecord = existingNative.record;
108898
+ entryMutationId ??= createRuntimeId().toLowerCase();
108899
+ entryClientOrderId = clientOrderIdForMutation(entryMutationId);
108900
+ nativePendingLotKey = entryClientOrderId;
108901
+ const journaledAt = Date.now();
108902
+ nativeAddRecord = planNativeStandbyAdd(planNativePendingLot(existingNative.record, {
108903
+ settings: nativeSettingsOf(input.executionContext),
108904
+ sizeDecimals: input.executionContext.sizeDecimals,
108905
+ key: entryClientOrderId,
108906
+ sizeHint: sizeAsset,
108907
+ nowMs: journaledAt
108908
+ }), { clientOrderId: entryClientOrderId, nowMs: journaledAt });
108909
+ if (nativeAddRecord !== existingNative.record && !writeNativeProtectionRecord(nativeProfileId, input.executionContext.symbol, nativeAddRecord)) {
108910
+ return nativeBlocked(
108911
+ "protective_lifecycle_persistence_failed",
108912
+ "Blocked new exposure because its position protection could not be stored."
108913
+ );
108914
+ }
107919
108915
  }
107920
108916
  } else if (existingNative.kind === "record") {
107921
108917
  return nativeBlocked(
@@ -108090,6 +109086,16 @@ var init_runtime_execution = __esm({
108090
109086
  if (nativeOpen != null && (!entryDispatchBoundaryPassed || isDefinitiveEntryRejection(entryDispatchError, entryMutationId))) {
108091
109087
  writeNativeProtectionRecord(nativeProfileId, input.executionContext.symbol, null);
108092
109088
  }
109089
+ if (nativePendingLotKey != null && nativeOpen == null && (!entryDispatchBoundaryPassed || isDefinitiveEntryRejection(entryDispatchError, entryMutationId))) {
109090
+ const stored = readNativeRecord(nativeProfileId, input.executionContext.symbol);
109091
+ if (stored.kind === "record") {
109092
+ writeNativeProtectionRecord(
109093
+ nativeProfileId,
109094
+ input.executionContext.symbol,
109095
+ dropNativeStandbyAdd(dropNativePendingLot(stored.record, nativePendingLotKey), nativePendingLotKey)
109096
+ );
109097
+ }
109098
+ }
108093
109099
  const handoffVeto = isClientRuntimeWindowHandoffBeforePlanDispatch(entryDispatchError);
108094
109100
  const handoffBeforeDispatch = handoffVeto || !entryDispatchBoundaryPassed && input.shouldCancelBeforeExchangeOrderDispatch?.() === true;
108095
109101
  const hasCommittedReports = executionReports.some((report) => report.status === "executed" && String(report.order_id || "").trim().length > 0);
@@ -108212,7 +109218,20 @@ var init_runtime_execution = __esm({
108212
109218
  const symbol2 = input.executionContext.symbol;
108213
109219
  let record5 = nativeOpen != null ? recordEntryChildren(nativeOpen.record, marketOrderResponse) : nativeAddRecord;
108214
109220
  let keepNativeJournal = false;
108215
- if (nativeOpen != null && !writeNativeProtectionRecord(nativeProfileId, symbol2, record5)) {
109221
+ if (confirmedMarketFill?.orderId) {
109222
+ if (nativeOpen == null && nativePendingLotKey != null) {
109223
+ record5 = nameNativeStandbyAdd(record5, nativePendingLotKey, String(confirmedMarketFill.orderId));
109224
+ }
109225
+ record5 = planNativeFillLot(record5, {
109226
+ settings: nativeSettingsOf(input.executionContext),
109227
+ sizeDecimals: input.executionContext.sizeDecimals,
109228
+ fillKey: String(confirmedMarketFill.orderId),
109229
+ fillSize: String(confirmedMarketFill.filledSize),
109230
+ nowMs: Date.now(),
109231
+ pendingKey: nativeOpen != null ? record5.entryClientOrderId : nativePendingLotKey
109232
+ });
109233
+ }
109234
+ if ((nativeOpen != null || nativePendingLotKey != null || record5 !== nativeAddRecord) && !writeNativeProtectionRecord(nativeProfileId, symbol2, record5)) {
108216
109235
  executionReports.push(nativeStorageReport(symbol2, "protective_lifecycle_persistence_failed"));
108217
109236
  }
108218
109237
  if (confirmedMarketFill == null) {
@@ -113043,7 +114062,7 @@ var init_profile_model_cascade = __esm({
113043
114062
  });
113044
114063
 
113045
114064
  // lib/runtime/prompt-variable-validation-contract.ts
113046
- var ESCAPED_OPEN_BRACE, ESCAPED_CLOSE_BRACE, PROMPT_PLACEHOLDER_PATTERN, ESCAPED_BRACE_PAIR_PATTERN, readPromptTemplate, restoreEscapedBraces, countAtMost, countBelow, locatePlaceholders, isPromptVariableName, renderPromptTemplate, promptTemplatePlaceholderSpans, promptTemplatePlaceholders, promptTemplateVariables, NEWS_PROMPT_VARIABLES, REFERENCE_CANDLES_PROMPT_VARIABLE, ALLOWED_PROMPT_VARIABLES, OPTIONAL_BLANK_PROMPT_VARIABLES, coercePromptVariableValue, isMissingPromptVariableValue, validatePromptVariables;
114065
+ var ESCAPED_OPEN_BRACE, ESCAPED_CLOSE_BRACE, PROMPT_PLACEHOLDER_PATTERN, ESCAPED_BRACE_PAIR_PATTERN, readPromptTemplate, restoreEscapedBraces, countAtMost, countBelow, locatePlaceholders, isPromptVariableName, renderPromptTemplate, formatInstructionTemplate, promptTemplatePlaceholderSpans, promptTemplatePlaceholders, promptTemplateVariables, NEWS_PROMPT_VARIABLES, REFERENCE_CANDLES_PROMPT_VARIABLE, ALLOWED_PROMPT_VARIABLES, OPTIONAL_BLANK_PROMPT_VARIABLES, coercePromptVariableValue, isMissingPromptVariableValue, validatePromptVariables;
113047
114066
  var init_prompt_variable_validation_contract = __esm({
113048
114067
  "lib/runtime/prompt-variable-validation-contract.ts"() {
113049
114068
  "use strict";
@@ -113129,6 +114148,40 @@ var init_prompt_variable_validation_contract = __esm({
113129
114148
  rendered.push(prepared.slice(cursor));
113130
114149
  return restoreEscapedBraces(rendered.join(""));
113131
114150
  };
114151
+ formatInstructionTemplate = (template, values, label2 = "instruction template") => {
114152
+ const text = String(template || "");
114153
+ const rendered = [];
114154
+ let index = 0;
114155
+ while (index < text.length) {
114156
+ const char = text[index];
114157
+ const escapedPair = `${char}${char}`;
114158
+ if ((char === "{" || char === "}") && text.startsWith(escapedPair, index)) {
114159
+ rendered.push(char);
114160
+ index += escapedPair.length;
114161
+ continue;
114162
+ }
114163
+ if (char === "}") {
114164
+ throw new Error(`Invalid ${label2}: ${template}`);
114165
+ }
114166
+ if (char !== "{") {
114167
+ rendered.push(char);
114168
+ index += 1;
114169
+ continue;
114170
+ }
114171
+ const end = text.indexOf("}", index + 1);
114172
+ const field = end < 0 ? "" : text.slice(index + 1, end);
114173
+ const name = field.endsWith(":") ? field.slice(0, -1) : field;
114174
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
114175
+ throw new Error(`Invalid ${label2}: ${template}`);
114176
+ }
114177
+ if (!Object.prototype.hasOwnProperty.call(values, name)) {
114178
+ throw new Error(`Unexpected ${label2} placeholder: ${name}`);
114179
+ }
114180
+ rendered.push(String(values[name]));
114181
+ index = end + 1;
114182
+ }
114183
+ return rendered.join("");
114184
+ };
113132
114185
  promptTemplatePlaceholderSpans = (template) => {
113133
114186
  if (typeof template !== "string" || !template) {
113134
114187
  return [];
@@ -117864,7 +118917,7 @@ var init_provider_client = __esm({
117864
118917
  });
117865
118918
 
117866
118919
  // lib/runtime/prompt-contract.ts
117867
- var PROMPT_PLACEHOLDER_MAP, DATA_FORMAT_TAG_ALIASES, buildDecisionInstructionVariables, renderCandleIndicatorDefinitions, NEWS_COLUMN_DESCRIPTIONS, isNewsPromptTag, newsTagBlock, newsRowColumns, renderNewsLegendLine, behaviorStateHasObjectField, candleBlockPayload, candlesHaveLiveField, templateReferencesTag, templateTagOrder, renderDataFormatLegend, replaceEmbeddedDataFormatLegend, SIZE_AMOUNT_USDC_LABEL_PATTERN, labelSizeAmountInUsd, canonicalizePromptPlaceholders, normalizePromptWhitespace, formatInstructionTemplate, constructPromptSystemTemplate;
118920
+ var PROMPT_PLACEHOLDER_MAP, DATA_FORMAT_TAG_ALIASES, buildDecisionInstructionVariables, renderCandleIndicatorDefinitions, NEWS_COLUMN_DESCRIPTIONS, isNewsPromptTag, newsTagBlock, newsRowColumns, renderNewsLegendLine, behaviorStateHasObjectField, candleBlockPayload, candlesHaveLiveField, templateReferencesTag, templateTagOrder, renderDataFormatLegend, replaceEmbeddedDataFormatLegend, SIZE_AMOUNT_USDC_LABEL_PATTERN, labelSizeAmountInUsd, canonicalizePromptPlaceholders, normalizePromptWhitespace, constructPromptSystemTemplate;
117868
118921
  var init_prompt_contract = __esm({
117869
118922
  "lib/runtime/prompt-contract.ts"() {
117870
118923
  "use strict";
@@ -118281,28 +119334,6 @@ var init_prompt_contract = __esm({
118281
119334
  }
118282
119335
  return text.replace(/\r\n/g, "\n").replace(/[\t ]{2,}\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
118283
119336
  };
118284
- formatInstructionTemplate = (template, vars) => {
118285
- const escapedOpen = "__VTX_INSTR_OPEN_BRACE__";
118286
- const escapedClose = "__VTX_INSTR_CLOSE_BRACE__";
118287
- const prepared = String(template ?? "").replaceAll("{{", escapedOpen).replaceAll("}}", escapedClose);
118288
- const replacements = [];
118289
- const formatted = prepared.replace(/\{([a-zA-Z0-9_]+)\}/g, (_match, key) => {
118290
- if (!Object.prototype.hasOwnProperty.call(vars, key)) {
118291
- throw new Error(`Unexpected instruction template placeholder: ${key}`);
118292
- }
118293
- const marker = `__VTX_INSTR_VALUE_${replacements.length}__`;
118294
- replacements.push(String(vars[key]));
118295
- return marker;
118296
- });
118297
- if (/[{}]/.test(formatted)) {
118298
- throw new Error(`Invalid instruction template: ${template}`);
118299
- }
118300
- let rendered = formatted.replaceAll(escapedOpen, "{").replaceAll(escapedClose, "}");
118301
- replacements.forEach((value, index) => {
118302
- rendered = rendered.replaceAll(`__VTX_INSTR_VALUE_${index}__`, value);
118303
- });
118304
- return rendered;
118305
- };
118306
119337
  constructPromptSystemTemplate = (systemTemplate, options) => {
118307
119338
  const instructions = options.instructions ?? {};
118308
119339
  const symbols = (options.symbols ?? []).map((symbol2) => String(symbol2).trim()).filter(Boolean);
@@ -119174,7 +120205,7 @@ __export(local_analysis_exports, {
119174
120205
  runLocalRuntimeCycle: () => runLocalRuntimeCycle,
119175
120206
  summarizeReviewFailureExplanation: () => summarizeReviewFailureExplanation
119176
120207
  });
119177
- var CYCLE_TIMEOUT_FLOOR_MS, DECISION_SETTLEMENT_RESERVE_MAX_BUDGET_DIVISOR, MIN_AGENT_INSTRUCTION_RETRY_AFTER_MS, PROMPT_PARITY_ERROR_DETAIL_MAX_CHARS, EXTERNAL_INFERENCE_RUNTIME_POLL_INTERVAL_MS, REVIEW_PROVIDER_SERVER_ERROR_STATUSES, TRUNCATION_ELLIPSIS2, normalizeNativeValues, assertPromptModelController, resolveRuntimeReasoningControlsForModel, modelScopedKey, resolveNativeValuesForModel, observeRuntimeCycle, observeAccountState, aiOrderSlippageFraction, serverBehaviorStateArtifacts, ClientRuntimeAgentInstructionEmpty, isClientRuntimeAgentInstructionEmpty, ClientRuntimeAiSchedulePaused, ClientRuntimeAiScheduleStillActive, isClientRuntimeAiScheduleStillActive, ServerDispatchAccountStateStale, isServerDispatchAccountStateStale, isClientRuntimeAiSchedulePaused, acceptancePositionCaps, accountSnapshotCapturedAt, buildClaimedAgentRuntimeCycleResult, resolveRuntimeMarginModePreference, resolveRuntimeLeveragePreference, resolveBooleanSetting2, CLIENT_RUNTIME_LIVE_CONTEXT_UNAVAILABLE_ERRORS, BEHAVIOR_STATE_UNAVAILABLE_ERROR, CriticalBehaviorStateError, clampNumber, resolveExternalInferenceRuntimeTimeoutSeconds, toPositiveFinite3, compactSnippet, hashRuntimeDebugText, EFFECTIVE_INPUT_MANIFEST_SCHEMA_VERSION, PROMPT_ASSEMBLY_DEFINITION_VERSION, RUNTIME_SOURCE_DEFINITION_VERSION, DECISION_INPUT_DEFINITION_VERSION, CONTEXT_ENVELOPE_DEFINITION_VERSION, CLIENT_RUNTIME_SOURCE_VERSION, CLIENT_MAIN_PROMPT_RENDERER, SERVER_MAIN_PROMPT_RENDERER, CLIENT_REVIEW_PROMPT_RENDERER, SERVER_REVIEW_PROMPT_RENDERER, resolveEffectivePromptRuntimeProvenance, canonicalManifestValue, canonicalManifestJson, sha256ManifestHex, effectiveInputComponent, buildEffectiveInputManifest, MANIFEST_COMPONENT_NAME, derivePromptVisibleSections, decodeDecisionTracePayload, extractDecisionSymbolTrace, formatDecisionSymbolTrace, formatActionableDecisionSymbols, decisionRecordsBySymbol, normalizePromptSymbols, JSON_MODEL_OUTPUT_FENCE_PATTERN, STRICT_MODEL_OUTPUT_KEYS, currentModelOutputValidationErrors, currentModelOutputMatchesContract, projectCurrentModelDecisionContent, modelOutputValidationError, SERVER_UNREADABLE_REPLY_HOLD_REASONING, buildMissingDecisionHold, buildDecisionPlansFromResponse, buildReviewCandidatePlansFromResponse, forceUnavailableSymbolsToHold, extractTemplatePlaceholders, requireReviewPrimaryUserPromptTemplate, containsCompetingBehaviorStateMarkup, containsCompetingMainBehaviorStateMarkup, requireStrategyReviewTemplates, preflightStrategyReviewPromptContract, extractRuntimeReasoningSelection, isAbortError, isRuntimeTimeoutAbortReason, REVIEW_FAILURE_SENSITIVE_DB_TOKENS, REVIEW_FAILURE_SCHEMA_DISCLOSURE_TOKENS, REVIEW_FAILURE_SQL_STATEMENT_PATTERN, REVIEW_FAILURE_TRACEBACK_PATTERN, isSensitiveReviewFailureDetail, summarizeReviewFailureExplanation, buildReviewFailureHoldReason, createAbortError2, settleRuntimeCyclePromise, unwrapRuntimeCycleSettledResult, normalizeDecisionLabel, normalizeRuntimeSymbol, PromptContractFetchError, isLivePromptContextUnavailableError, buildFailClosedHoldResult, buildPromptConstructionFailureResult, buildLivePromptContextUnavailableFailureResult, pickFirstString, normalizeRuntimeStringList, requirePositiveRuntimeLimit, resolveRuntimeTradingScope, normalizeRuntimeProviderAlias, resolveCatalogModelEntry, createClientRuntimeProviderSetupError, createProviderSetupRejectionError, evaluateModelEligibility, extractReviewRuntimeReasoningSelection, isUsableRuntimeSettingsFallback, resolveRuntimeSettings, formatRuntimeDurationMs, normalizeRuntimeTimingNote, appendRuntimeTimingEvent, reportPromptParityTelemetry, resolveLocalRuntimeSecretRequirements, resolveLocalRuntimeSecretProvider, toEpochSeconds, AI_INDICATOR_KEYS_NEWER_THAN_SOME_SERVERS, sortTradingTimeframes, normalizePromptIdentityTimestamp, resolveCompletedCandleBoundary, normalizeAiIndicatorFlags, getPromptLookback, computeSma, computeEma, computeRsi, computeAtr, computeMacd, computeBollingerBands, getIndicatorValue, buildPromptCandlesComponent, buildPromptCandleTimeframeComponent, resolvePromptRelativeVolumeContext, promptRelativeVolumeBaseline, CANDLE_CLOSE_TICKER_TIMEFRAME, candleCloseTicker, buildPromptCandlesPayload, formatUtcTimestampWithWeekday, formatUtcNowWithWeekday, formatPromptPrice, capacityUnitSize, computePromptUnitsUsedForPosition, buildPromptAccountStatusValue, buildPromptPositionsValue, sanitizePromptSymbol, fillTimeMs, fillSize, normalizeFillSide, normalizeFillOrderId, normalizeFillRiskOrderIdentity, fillStartPosition, fillSortValue, sortFillsAscending, sortFillsDescending, inferEntryFromStartPositionChain, inferEntryFromCurrentPositionSize, calculateCurrentPositionState, calculatePositionEntryTimes, countPositionAdds, latestPositionRiskIncreaseTimeMs, latestPositionRiskIncreaseEvidence, compactPromptRiskIncrease, roundPositiveDecimalHalfUp, compactPromptLastTrade, ENTRY_TRADE_FIELDS, PREVIOUS_DECISION_FIELDS, PREVIOUS_CAMPAIGN_FIELDS, hasExactKeys2, isNonnegativeInteger, isFiniteNumber, isExactEnumString, isNonemptyPromptText, isCampaignReasoningText, projectBackendDecisionMemoryItem, requireRenderedStrategyBehaviorState, canonicalFillSideForRiskEvidence, isValidRiskEvidenceFill, isValidCampaignBoundaryFill, normalizeFillHistoryCoverage, resolveFillHistoryCoverageForSymbol, buildPromptBehaviorStateArtifacts, buildPromptBehaviorStateValue, shouldCompareServerPromptParity, buildLocalRuntimePromptArtifacts, createRuntimeId2, asRecord, buildRuntimeConstraintRejectionMessage, hasDeviceProviderSecret, requireNonEmptyStringField, requirePositiveIntegerField, compareContractVersion, parsePromptContractTimestamp, assertPromptContractCompatibility, assertPromptContractTemporalBounds, sleepWithAbort, requireAgentPollRetryAfterMs, materializeClaimedClientRuntimeAgentInstruction, attachClientRuntimeErrorProvenance, isExternalRuntimeProviderResult, invokeClientExternalInference, assertPromptContractBindingTupleEqual, assertPromptContractScopeMatch, fetchBoundPromptContracts, formatTemplateWithNamedVariables, carryReturnedModelCalls, runLocalRuntimeCycle;
120208
+ var CYCLE_TIMEOUT_FLOOR_MS, DECISION_SETTLEMENT_RESERVE_MAX_BUDGET_DIVISOR, MIN_AGENT_INSTRUCTION_RETRY_AFTER_MS, PROMPT_PARITY_ERROR_DETAIL_MAX_CHARS, EXTERNAL_INFERENCE_RUNTIME_POLL_INTERVAL_MS, REVIEW_PROVIDER_SERVER_ERROR_STATUSES, TRUNCATION_ELLIPSIS2, normalizeNativeValues, assertPromptModelController, resolveRuntimeReasoningControlsForModel, modelScopedKey, resolveNativeValuesForModel, observeRuntimeCycle, observeAccountState, aiOrderSlippageFraction, serverBehaviorStateArtifacts, ClientRuntimeAgentInstructionEmpty, isClientRuntimeAgentInstructionEmpty, ClientRuntimeAiSchedulePaused, ClientRuntimeAiScheduleStillActive, isClientRuntimeAiScheduleStillActive, ServerDispatchAccountStateStale, isServerDispatchAccountStateStale, isClientRuntimeAiSchedulePaused, acceptancePositionCaps, accountSnapshotCapturedAt, buildClaimedAgentRuntimeCycleResult, resolveRuntimeMarginModePreference, resolveRuntimeLeveragePreference, resolveBooleanSetting2, CLIENT_RUNTIME_LIVE_CONTEXT_UNAVAILABLE_ERRORS, BEHAVIOR_STATE_UNAVAILABLE_ERROR, CriticalBehaviorStateError, BEHAVIOR_MEMORY_UNAVAILABLE_ERROR, BehaviorMemoryUnavailableError, clampNumber, resolveExternalInferenceRuntimeTimeoutSeconds, toPositiveFinite3, compactSnippet, hashRuntimeDebugText, EFFECTIVE_INPUT_MANIFEST_SCHEMA_VERSION, PROMPT_ASSEMBLY_DEFINITION_VERSION, RUNTIME_SOURCE_DEFINITION_VERSION, DECISION_INPUT_DEFINITION_VERSION, CONTEXT_ENVELOPE_DEFINITION_VERSION, CLIENT_RUNTIME_SOURCE_VERSION, CLIENT_MAIN_PROMPT_RENDERER, SERVER_MAIN_PROMPT_RENDERER, CLIENT_REVIEW_PROMPT_RENDERER, SERVER_REVIEW_PROMPT_RENDERER, resolveEffectivePromptRuntimeProvenance, canonicalManifestValue, canonicalManifestJson, sha256ManifestHex, effectiveInputComponent, buildEffectiveInputManifest, MANIFEST_COMPONENT_NAME, derivePromptVisibleSections, decodeDecisionTracePayload, extractDecisionSymbolTrace, formatDecisionSymbolTrace, formatActionableDecisionSymbols, decisionRecordsBySymbol, normalizePromptSymbols, JSON_MODEL_OUTPUT_FENCE_PATTERN, STRICT_MODEL_OUTPUT_KEYS, currentModelOutputValidationErrors, currentModelOutputMatchesContract, projectCurrentModelDecisionContent, modelOutputValidationError, SERVER_UNREADABLE_REPLY_HOLD_REASONING, buildMissingDecisionHold, buildDecisionPlansFromResponse, buildReviewCandidatePlansFromResponse, forceUnavailableSymbolsToHold, extractTemplatePlaceholders, requireReviewPrimaryUserPromptTemplate, containsCompetingBehaviorStateMarkup, containsCompetingMainBehaviorStateMarkup, requireStrategyReviewTemplates, preflightStrategyReviewPromptContract, extractRuntimeReasoningSelection, isAbortError, isRuntimeTimeoutAbortReason, REVIEW_FAILURE_SENSITIVE_DB_TOKENS, REVIEW_FAILURE_SCHEMA_DISCLOSURE_TOKENS, REVIEW_FAILURE_SQL_STATEMENT_PATTERN, REVIEW_FAILURE_TRACEBACK_PATTERN, isSensitiveReviewFailureDetail, summarizeReviewFailureExplanation, buildReviewFailureHoldReason, createAbortError2, settleRuntimeCyclePromise, unwrapRuntimeCycleSettledResult, normalizeDecisionLabel, normalizeRuntimeSymbol, PromptContractFetchError, isLivePromptContextUnavailableError, buildFailClosedHoldResult, buildPromptConstructionFailureResult, buildLivePromptContextUnavailableFailureResult, pickFirstString, normalizeRuntimeStringList, requirePositiveRuntimeLimit, resolveRuntimeTradingScope, normalizeRuntimeProviderAlias, resolveCatalogModelEntry, createClientRuntimeProviderSetupError, createProviderSetupRejectionError, evaluateModelEligibility, extractReviewRuntimeReasoningSelection, isUsableRuntimeSettingsFallback, resolveRuntimeSettings, formatRuntimeDurationMs, normalizeRuntimeTimingNote, appendRuntimeTimingEvent, reportPromptParityTelemetry, resolveLocalRuntimeSecretRequirements, resolveLocalRuntimeSecretProvider, toEpochSeconds, AI_INDICATOR_KEYS_NEWER_THAN_SOME_SERVERS, sortTradingTimeframes, normalizePromptIdentityTimestamp, resolveCompletedCandleBoundary, normalizeAiIndicatorFlags, getPromptLookback, computeSma, computeEma, computeRsi, computeAtr, computeMacd, computeBollingerBands, getIndicatorValue, buildPromptCandlesComponent, buildPromptCandleTimeframeComponent, resolvePromptRelativeVolumeContext, promptRelativeVolumeBaseline, CANDLE_CLOSE_TICKER_TIMEFRAME, candleCloseTicker, buildPromptCandlesPayload, formatUtcTimestampWithWeekday, formatUtcNowWithWeekday, formatPromptPrice, capacityUnitSize, computePromptUnitsUsedForPosition, buildPromptAccountStatusValue, buildPromptPositionsValue, sanitizePromptSymbol, fillTimeMs, fillSize, normalizeFillSide, normalizeFillOrderId, normalizeFillRiskOrderIdentity, fillStartPosition, fillSortValue, sortFillsAscending, sortFillsDescending, inferEntryFromStartPositionChain, inferEntryFromCurrentPositionSize, calculateCurrentPositionState, calculatePositionEntryTimes, countPositionAdds, latestPositionRiskIncreaseTimeMs, latestPositionRiskIncreaseEvidence, compactPromptRiskIncrease, roundPositiveDecimalHalfUp, compactPromptLastTrade, ENTRY_TRADE_FIELDS, PREVIOUS_DECISION_FIELDS, PREVIOUS_CAMPAIGN_FIELDS, hasExactKeys2, isNonnegativeInteger, isFiniteNumber, isExactEnumString, isNonemptyPromptText, isCampaignReasoningText, projectBackendDecisionMemoryItem, requireRenderedStrategyBehaviorState, canonicalFillSideForRiskEvidence, isValidRiskEvidenceFill, isValidCampaignBoundaryFill, normalizeFillHistoryCoverage, resolveFillHistoryCoverageForSymbol, buildPromptBehaviorStateArtifacts, buildPromptBehaviorStateValue, shouldCompareServerPromptParity, buildLocalRuntimePromptArtifacts, createRuntimeId2, asRecord, buildRuntimeConstraintRejectionMessage, hasDeviceProviderSecret, requireNonEmptyStringField, requirePositiveIntegerField, compareContractVersion, parsePromptContractTimestamp, assertPromptContractCompatibility, assertPromptContractTemporalBounds, sleepWithAbort, requireAgentPollRetryAfterMs, materializeClaimedClientRuntimeAgentInstruction, attachClientRuntimeErrorProvenance, isExternalRuntimeProviderResult, invokeClientExternalInference, assertPromptContractBindingTupleEqual, assertPromptContractScopeMatch, fetchBoundPromptContracts, carryReturnedModelCalls, runLocalRuntimeCycle;
119178
120209
  var init_local_analysis = __esm({
119179
120210
  "lib/runtime/local-analysis.ts"() {
119180
120211
  "use strict";
@@ -119728,6 +120759,13 @@ var init_local_analysis = __esm({
119728
120759
  this.name = "CriticalBehaviorStateError";
119729
120760
  }
119730
120761
  };
120762
+ BEHAVIOR_MEMORY_UNAVAILABLE_ERROR = "Behavior memory is unavailable for this trading cycle";
120763
+ BehaviorMemoryUnavailableError = class extends Error {
120764
+ constructor(cause) {
120765
+ super(BEHAVIOR_MEMORY_UNAVAILABLE_ERROR, cause === void 0 ? void 0 : { cause });
120766
+ this.name = "BehaviorMemoryUnavailableError";
120767
+ }
120768
+ };
119731
120769
  clampNumber = (value, fallback) => {
119732
120770
  const numeric2 = Number(value);
119733
120771
  return Number.isFinite(numeric2) ? numeric2 : fallback;
@@ -120347,29 +121385,27 @@ var init_local_analysis = __esm({
120347
121385
  return assembledUserTemplate;
120348
121386
  };
120349
121387
  preflightStrategyReviewPromptContract = (metadata, symbols, maxTrades) => {
121388
+ const reviewSystemTemplate = String(metadata.review_system_template ?? "");
121389
+ const reviewUserTemplate = String(metadata.review_user_template ?? "");
121390
+ if (!reviewSystemTemplate.trim() || !reviewUserTemplate.trim() || extractTemplatePlaceholders(reviewSystemTemplate).length > 0) {
121391
+ throw new CriticalBehaviorStateError();
121392
+ }
121393
+ requireStrategyReviewTemplates(reviewSystemTemplate, reviewUserTemplate);
120350
121394
  try {
120351
- requireStrategyReviewTemplates(
120352
- requireNonEmptyStringField(metadata.review_system_template, "review_system_template"),
120353
- requireNonEmptyStringField(metadata.review_user_template, "review_user_template")
120354
- );
120355
121395
  const reviewInstructions = asRecord(metadata.review_instructions);
120356
121396
  const reviewSecurity = requireNonEmptyStringField(
120357
121397
  reviewInstructions.review_security,
120358
121398
  "review_instructions.review_security"
120359
121399
  );
120360
- const reviewOutputContract = formatTemplateWithNamedVariables(
121400
+ const reviewOutputContract = formatInstructionTemplate(
120361
121401
  requireNonEmptyStringField(
120362
121402
  reviewInstructions.review_json_format,
120363
121403
  "review_instructions.review_json_format"
120364
121404
  ),
120365
121405
  buildDecisionInstructionVariables(symbols, maxTrades)
120366
121406
  );
120367
- const reviewSystemTemplate = requireNonEmptyStringField(
120368
- metadata.review_system_template,
120369
- "review_system_template"
120370
- );
120371
- if (extractTemplatePlaceholders(reviewSystemTemplate).length > 0 || extractTemplatePlaceholders(reviewSecurity).length > 0) {
120372
- throw new CriticalBehaviorStateError();
121407
+ if (extractTemplatePlaceholders(reviewSecurity).length > 0) {
121408
+ throw new BehaviorMemoryUnavailableError();
120373
121409
  }
120374
121410
  const securedReviewSystem = reviewSystemTemplate.includes(reviewSecurity) ? reviewSystemTemplate : `${reviewSystemTemplate.trim()}
120375
121411
 
@@ -120378,13 +121414,13 @@ ${reviewSecurity}`;
120378
121414
 
120379
121415
  ${reviewOutputContract}`;
120380
121416
  if (containsCompetingBehaviorStateMarkup(renderedReviewSystem)) {
120381
- throw new CriticalBehaviorStateError();
121417
+ throw new BehaviorMemoryUnavailableError();
120382
121418
  }
120383
121419
  } catch (error48) {
120384
- if (error48 instanceof CriticalBehaviorStateError) {
121420
+ if (error48 instanceof BehaviorMemoryUnavailableError) {
120385
121421
  throw error48;
120386
121422
  }
120387
- throw new CriticalBehaviorStateError();
121423
+ throw new BehaviorMemoryUnavailableError(error48);
120388
121424
  }
120389
121425
  };
120390
121426
  extractRuntimeReasoningSelection = (settings, controlType, toggleBehavior = "disable_reasoning") => {
@@ -121369,33 +122405,11 @@ ${reviewOutputContract}`;
121369
122405
  ].join("\n");
121370
122406
  buildPromptPositionsValue = (input) => {
121371
122407
  const validateInstructionTemplate = (template, allowedKeys) => {
121372
- const escapedOpen = "__VTX_ESCAPED_OPEN__";
121373
- const escapedClose = "__VTX_ESCAPED_CLOSE__";
121374
- const normalizedTemplate = template.replace(/\{\{/g, escapedOpen).replace(/\}\}/g, escapedClose);
121375
- const formatted = normalizedTemplate.replace(/\{([a-z_]+)\}/g, (_match, key) => {
121376
- if (!allowedKeys.includes(key)) {
121377
- throw new Error(`Unexpected positions instruction placeholder: ${key}`);
121378
- }
121379
- return "";
121380
- });
121381
- if (/[{}]/.test(formatted)) {
121382
- throw new Error(`Invalid positions instruction template: ${template}`);
121383
- }
121384
- };
121385
- const formatInstructionTemplate2 = (template, values) => {
121386
- const escapedOpen = "__VTX_ESCAPED_OPEN__";
121387
- const escapedClose = "__VTX_ESCAPED_CLOSE__";
121388
- const normalizedTemplate = template.replace(/\{\{/g, escapedOpen).replace(/\}\}/g, escapedClose);
121389
- const formatted = normalizedTemplate.replace(/\{([a-z_]+)\}/g, (_match, key) => {
121390
- if (!Object.prototype.hasOwnProperty.call(values, key)) {
121391
- throw new Error(`Unexpected positions instruction placeholder: ${key}`);
121392
- }
121393
- return String(values[key]);
121394
- });
121395
- if (/[{}]/.test(formatted)) {
121396
- throw new Error(`Invalid positions instruction template: ${template}`);
121397
- }
121398
- return formatted.replaceAll(escapedOpen, "{").replaceAll(escapedClose, "}");
122408
+ formatInstructionTemplate(
122409
+ template,
122410
+ Object.fromEntries(allowedKeys.map((key) => [key, ""])),
122411
+ "positions instruction template"
122412
+ );
121399
122413
  };
121400
122414
  validateInstructionTemplate(input.positionsInstructions.close_reduce, []);
121401
122415
  validateInstructionTemplate(input.positionsInstructions.capacity_flat, []);
@@ -121490,9 +122504,9 @@ ${reviewOutputContract}`;
121490
122504
  if (remainingGlobal <= 0) {
121491
122505
  parts.push(`${input.positionsInstructions.capacity_full} `);
121492
122506
  } else if (input.maxTradesPerPrompt < input.maxTradesGlobal && remainingGlobal < input.maxTradesPerPrompt) {
121493
- parts.push(`${formatInstructionTemplate2(input.positionsInstructions.capacity_low, {
122507
+ parts.push(`${formatInstructionTemplate(input.positionsInstructions.capacity_low, {
121494
122508
  remaining: remainingGlobal
121495
- })} `);
122509
+ }, "positions instruction template")} `);
121496
122510
  }
121497
122511
  return parts.join("\n");
121498
122512
  };
@@ -121988,6 +123002,9 @@ ${reviewOutputContract}`;
121988
123002
  const matches2 = Array.from(
121989
123003
  userPrompt.matchAll(/<behavior_state>\s*([\s\S]*?)\s*<\/behavior_state>/g)
121990
123004
  );
123005
+ if (openingTags.length === 0 && closingTags.length === 0) {
123006
+ throw new BehaviorMemoryUnavailableError();
123007
+ }
121991
123008
  if (openingTags.length !== 1 || closingTags.length !== 1 || matches2.length !== 1) {
121992
123009
  throw new CriticalBehaviorStateError();
121993
123010
  }
@@ -122006,7 +123023,7 @@ ${reviewOutputContract}`;
122006
123023
  projectBackendDecisionMemoryItem(entry.et, "et");
122007
123024
  }
122008
123025
  } catch (error48) {
122009
- throw new CriticalBehaviorStateError(error48);
123026
+ throw new BehaviorMemoryUnavailableError(error48);
122010
123027
  }
122011
123028
  };
122012
123029
  canonicalFillSideForRiskEvidence = (fill) => {
@@ -122970,27 +123987,6 @@ ${behaviorJson}
122970
123987
  }
122971
123988
  }
122972
123989
  };
122973
- formatTemplateWithNamedVariables = (template, values) => {
122974
- const escapedOpen = "__VTX_FMT_OPEN__";
122975
- const escapedClose = "__VTX_FMT_CLOSE__";
122976
- const prepared = String(template || "").replaceAll("{{", escapedOpen).replaceAll("}}", escapedClose);
122977
- const validatedTemplate = prepared.replace(/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g, (_match, key) => {
122978
- if (!Object.prototype.hasOwnProperty.call(values, key)) {
122979
- throw new Error(`Missing required review template variable: ${key}`);
122980
- }
122981
- return "";
122982
- });
122983
- if (/[{}]/.test(validatedTemplate)) {
122984
- throw new Error(`Invalid review template: ${template}`);
122985
- }
122986
- const formatted = prepared.replace(/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g, (_match, key) => {
122987
- if (!Object.prototype.hasOwnProperty.call(values, key)) {
122988
- throw new Error(`Missing required review template variable: ${key}`);
122989
- }
122990
- return String(values[key]);
122991
- });
122992
- return formatted.replaceAll(escapedOpen, "{").replaceAll(escapedClose, "}");
122993
- };
122994
123990
  carryReturnedModelCalls = (error48, attempts) => {
122995
123991
  if (!attempts.length || !error48 || typeof error48 !== "object" && typeof error48 !== "function") return error48;
122996
123992
  error48.runtimeReturnedModelCalls = attempts;
@@ -123665,7 +124661,7 @@ ${behaviorJson}
123665
124661
  };
123666
124662
  tradeHistory = browserUserFills?.tradeHistory ?? [];
123667
124663
  if (input.mode === "trader" && !serverOwnsBehaviorState && browserUserFills?.evidence?.source !== "live") {
123668
- throw new CriticalBehaviorStateError();
124664
+ throw new BehaviorMemoryUnavailableError();
123669
124665
  }
123670
124666
  const metadataSymbol = requireNonEmptyStringField(promptMetadata.symbol, "symbol");
123671
124667
  const metadataTimeframe = requireNonEmptyStringField(promptMetadata.timeframe, "timeframe");
@@ -123974,7 +124970,7 @@ ${behaviorJson}
123974
124970
  let preMemoryBehaviorState = "";
123975
124971
  try {
123976
124972
  if (input.mode === "trader" && !behaviorMemoryEnabled) {
123977
- throw new CriticalBehaviorStateError();
124973
+ throw new BehaviorMemoryUnavailableError();
123978
124974
  }
123979
124975
  const browserFillEvidence = browserUserFills?.evidence;
123980
124976
  const behaviorFillCoverage = browserFillEvidence?.source === "live" && browserFillEvidence.exactTerminalFillEvidenceComplete === true ? "complete" : "capped";
@@ -123994,7 +124990,7 @@ ${behaviorJson}
123994
124990
  fillHistoryCoverage: behaviorFillCoverage
123995
124991
  });
123996
124992
  } catch (error48) {
123997
- throw new CriticalBehaviorStateError(error48);
124993
+ throw new BehaviorMemoryUnavailableError(error48);
123998
124994
  }
123999
124995
  preMemoryBehaviorState = behaviorStateArtifacts.preMemoryRendered;
124000
124996
  behaviorPolicyState = behaviorStateArtifacts.policyState;
@@ -124049,7 +125045,7 @@ ${stringifyPromptJson(candlesPayload)}
124049
125045
  note: detail,
124050
125046
  outcome: "error"
124051
125047
  });
124052
- if (input.mode !== "trader" || error48 instanceof CriticalBehaviorStateError) {
125048
+ if (input.mode !== "trader" || error48 instanceof CriticalBehaviorStateError || error48 instanceof BehaviorMemoryUnavailableError) {
124053
125049
  throw error48;
124054
125050
  }
124055
125051
  return attachDecisionSettlementDeadline(buildPromptConstructionFailureResult({
@@ -124179,7 +125175,7 @@ ${stringifyPromptJson(candlesPayload)}
124179
125175
  outcome: "error"
124180
125176
  });
124181
125177
  appendRuntimeTimingEvent("prompt_render_failed", promptRenderStartedAtMs, detail, "error");
124182
- if (input.mode !== "trader" || error48 instanceof CriticalBehaviorStateError) {
125178
+ if (input.mode !== "trader" || error48 instanceof CriticalBehaviorStateError || error48 instanceof BehaviorMemoryUnavailableError) {
124183
125179
  throw error48;
124184
125180
  }
124185
125181
  return attachDecisionSettlementDeadline(buildPromptConstructionFailureResult({
@@ -124728,7 +125724,7 @@ ${stringifyPromptJson(candlesPayload)}
124728
125724
  reviewInstructions.review_security,
124729
125725
  "review_instructions.review_security"
124730
125726
  );
124731
- const reviewOutputContract = formatTemplateWithNamedVariables(
125727
+ const reviewOutputContract = formatInstructionTemplate(
124732
125728
  reviewOutputFormat,
124733
125729
  buildDecisionInstructionVariables(reviewSymbols, reviewMaxTrades)
124734
125730
  );
@@ -124751,12 +125747,18 @@ ${reviewOutputContract}`;
124751
125747
  configuredReviewUserTemplate
124752
125748
  ) : configuredReviewUserTemplate;
124753
125749
  const renderedPrimaryUserPrompt = stringifyPromptJson(userPrompt);
124754
- const reviewUserPrompt = formatTemplateWithNamedVariables(reviewUserTemplate, {
124755
- primary_model: selectedPrimaryModel,
124756
- primary_system_prompt: stringifyPromptJson(systemPrompt),
124757
- primary_user_prompt: renderedPrimaryUserPrompt,
124758
- primary_decision_json: primaryDecisionJson
124759
- });
125750
+ let reviewUserPrompt;
125751
+ try {
125752
+ reviewUserPrompt = formatInstructionTemplate(reviewUserTemplate, {
125753
+ primary_model: selectedPrimaryModel,
125754
+ primary_system_prompt: stringifyPromptJson(systemPrompt),
125755
+ primary_user_prompt: renderedPrimaryUserPrompt,
125756
+ primary_decision_json: primaryDecisionJson
125757
+ });
125758
+ } catch (error48) {
125759
+ if (input.mode === "trader") throw new CriticalBehaviorStateError(error48);
125760
+ throw error48;
125761
+ }
124760
125762
  if (input.mode === "trader" && (reviewUserPrompt.split(renderedPrimaryUserPrompt).length - 1 !== 1 || /<\/?behavior_state\b/.test(reviewUserPrompt) || containsCompetingBehaviorStateMarkup(reviewSystemPrompt))) {
124761
125763
  throw new CriticalBehaviorStateError();
124762
125764
  }
@@ -124989,7 +125991,10 @@ ${reviewOutputContract}`;
124989
125991
  });
124990
125992
  } catch (error48) {
124991
125993
  const detail = error48 instanceof Error ? error48.message : String(error48);
124992
- if (error48 instanceof CriticalBehaviorStateError || detail.includes(BEHAVIOR_STATE_UNAVAILABLE_ERROR) || detail.includes("Critical behavior context could not be constructed")) {
125994
+ if (error48 instanceof BehaviorMemoryUnavailableError || detail.includes(BEHAVIOR_MEMORY_UNAVAILABLE_ERROR) || detail.includes("Critical behavior context could not be constructed")) {
125995
+ throw new BehaviorMemoryUnavailableError(error48);
125996
+ }
125997
+ if (error48 instanceof CriticalBehaviorStateError || detail.includes(BEHAVIOR_STATE_UNAVAILABLE_ERROR) || detail.includes("Your prompt on the AI page contains something VTX can't use")) {
124993
125998
  throw new CriticalBehaviorStateError(error48);
124994
125999
  }
124995
126000
  if (input.executionMode === "server" && error48?.code === "settings_superseded") {
@@ -127545,6 +128550,7 @@ var init_engine = __esm({
127545
128550
  const runtime = await this.notifyRuntimeStop(this._profileId, {
127546
128551
  keepalive: options?.keepalive === true,
127547
128552
  reason: stopReason,
128553
+ modeSwitch: options?.modeSwitch === true,
127548
128554
  killswitchTrigger: options?.killswitchTrigger ?? null,
127549
128555
  authoritativeIntent: this._remoteStopPending === "authoritative-stop" && this._pendingAuthoritativeStopDetails?.authoritativeIntent === true
127550
128556
  });
@@ -127624,7 +128630,8 @@ var init_engine = __esm({
127624
128630
  reason: effectiveRemoteStopReason,
127625
128631
  killswitchTrigger: supersedingStop?.killswitchTrigger ?? options?.killswitchTrigger ?? null,
127626
128632
  acceptDeferredStopCompletion: !remoteStopWasAuthoritativeAtDispatch,
127627
- authoritativeIntent: supersedingStop?.authoritativeIntent === true
128633
+ authoritativeIntent: supersedingStop?.authoritativeIntent === true,
128634
+ modeSwitch: !supersedingStop && options?.modeSwitch === true
127628
128635
  });
127629
128636
  this._setRuntimeStatus(runtime, "stop");
127630
128637
  appendRuntimeDebugEvent({
@@ -131169,7 +132176,8 @@ var init_engine = __esm({
131169
132176
  lastRunAt: this._lastRunAt,
131170
132177
  stopReason: options?.reason ?? null,
131171
132178
  killswitchTrigger: options?.killswitchTrigger ?? null,
131172
- authoritativeIntent: options?.authoritativeIntent === true
132179
+ authoritativeIntent: options?.authoritativeIntent === true,
132180
+ modeSwitch: options?.modeSwitch === true
131173
132181
  },
131174
132182
  {
131175
132183
  ...options,