hypervibes 0.0.0-stage → 0.4.0
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/.build/client/assets/_authenticated-C87LKvH0.js +1 -0
- package/.build/client/assets/_authenticated.account-D-nTh_fC.js +1 -0
- package/.build/client/assets/_authenticated.agents-HwcveLyB.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId-DuE8Lv62.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.chart-Bb_XkvQx.js +4 -0
- package/.build/client/assets/_authenticated.agents._agentId.chat-ClMMKw_N.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.index-DNJwBwn9.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.indicators-BmVjLtRI.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.indicators_._indicatorId-CMqaaFQf.js +2 -0
- package/.build/client/assets/_authenticated.agents._agentId.indicators_._indicatorId-DtgkoNV5.js +6 -0
- package/.build/client/assets/_authenticated.agents._agentId.memories-O-4f6a4G.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.memories_._memoryRef-BUPtUcj3.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.notifications-2lyhXCSk.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.notifications_._notificationId-Da3ZVT4v.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.settings-C5cWHoYw.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.sub-agents-HwcveLyB.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.sub-agents._subagentId-CZ4MeRy4.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.sub-agents._subagentId_.runs._runId-dVbo5kMU.js +3 -0
- package/.build/client/assets/_authenticated.agents._agentId.sub-agents.index-DeWTOYJD.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.sub-agents.new-D02TflCE.js +37 -0
- package/.build/client/assets/_authenticated.agents._agentId.transactions-D3a8Glgj.js +1 -0
- package/.build/client/assets/_authenticated.agents.index-CEqeDEgP.js +1 -0
- package/.build/client/assets/_authenticated.agents.new-DLRWK5Uk.js +1 -0
- package/.build/client/assets/_authenticated.providers-D0iPLXra.js +1 -0
- package/.build/client/assets/agent-chat-page-C5eYFgxw.js +1 -0
- package/.build/client/assets/agent-enablement-control-CUzOp9ce.js +1 -0
- package/.build/client/assets/agent-events-DC8eDZf3.js +1 -0
- package/.build/client/assets/agent-input-aolvZ47U.js +1 -0
- package/.build/client/assets/agent-notifications-page-B0mr-Zz8.js +1 -0
- package/.build/client/assets/agent-queries-CNMBImun.js +1 -0
- package/.build/client/assets/app-DjmsvbUC.css +2 -0
- package/.build/client/assets/artifact-content-COO4VTSZ.js +1 -0
- package/.build/client/assets/auth-client-K13li9H1.js +3 -0
- package/.build/client/assets/call-DxlGie4_.js +31 -0
- package/.build/client/assets/ccip-BgPlVPYP.js +1 -0
- package/.build/client/assets/chart-contracts-Cr5SFCbE.js +1 -0
- package/.build/client/assets/chart-queries-Bpvrgd0-.js +1 -0
- package/.build/client/assets/chat-bubble-CAJkT-vL.js +1 -0
- package/.build/client/assets/config-dialog-C9x9gKW9.js +1 -0
- package/.build/client/assets/contracts-HhAL7Tt7.js +1 -0
- package/.build/client/assets/createServerFn-DfZIp2Fu.js +3 -0
- package/.build/client/assets/custom-BeqXuIIS.js +5 -0
- package/.build/client/assets/decimal-B0DEG-1V.js +1 -0
- package/.build/client/assets/esm-BTb2nBdW.js +1 -0
- package/.build/client/assets/identicon-Lb9pS4O1.js +1 -0
- package/.build/client/assets/index-B4hvjMmI.js +10 -0
- package/.build/client/assets/indicator-input-fields-CtmrfVfS.js +1 -0
- package/.build/client/assets/indicator-queries-CzZ6u1Mh.js +1 -0
- package/.build/client/assets/indicator-renderer-CfccsIt2.js +1 -0
- package/.build/client/assets/instrument-label-BZYlWXR5.js +1 -0
- package/.build/client/assets/instrument-picker-DLPpryOm.js +1 -0
- package/.build/client/assets/journal-decimal-DBvd_Ibi.js +1 -0
- package/.build/client/assets/jsx-runtime-CIazjfqY.js +1 -0
- package/.build/client/assets/lazyRouteComponent-CJgUa7_r.js +1 -0
- package/.build/client/assets/lightweight-charts.production-BiBiFZSH.js +1 -0
- package/.build/client/assets/login-MNgYxCOY.js +3 -0
- package/.build/client/assets/memory-badge-BbN-DJQi.js +1 -0
- package/.build/client/assets/memory-contracts-Doi_Q1XJ.js +1 -0
- package/.build/client/assets/memory-queries-BttL580R.js +1 -0
- package/.build/client/assets/model-picker-YCQNNmyw.js +1 -0
- package/.build/client/assets/notification-queries-B12DG3aS.js +1 -0
- package/.build/client/assets/preload-helper-Czpn1I53.js +1 -0
- package/.build/client/assets/provider-logo-Ddb77aBD.js +1 -0
- package/.build/client/assets/provider-queries-DxPwhDOU.js +1 -0
- package/.build/client/assets/query-nvK_95Jo.js +1 -0
- package/.build/client/assets/random-uuid-DJR3ygJS.js +1 -0
- package/.build/client/assets/react-dom-C6bOPxes.js +1 -0
- package/.build/client/assets/risk-queries-D_6PHwus.js +1 -0
- package/.build/client/assets/run-subagent-dialog-B4yQe9T9.js +1 -0
- package/.build/client/assets/secp256k1-BbZnIgDP.js +1 -0
- package/.build/client/assets/setup-checklist-CUW-K484.js +1 -0
- package/.build/client/assets/sha2-hT-Q4pur.js +1 -0
- package/.build/client/assets/subagent-enabled-toggle-Bk5wfScg.js +1 -0
- package/.build/client/assets/subagent-input-TQke90I1.js +1 -0
- package/.build/client/assets/subagent-mutations-DfsDbmFu.js +1 -0
- package/.build/client/assets/subagent-queries-DVv5JCfs.js +1 -0
- package/.build/client/assets/subagent-run-history-D55Uh5VK.js +1 -0
- package/.build/client/assets/toggle-timestamp-B50FTPmA.js +1 -0
- package/.build/client/assets/useBaseQuery-Bxruo_mV.js +1 -0
- package/.build/client/assets/useMutation-DrF53EQG.js +1 -0
- package/.build/client/assets/useQuery-BMSU16jY.js +1 -0
- package/.build/client/assets/useRouter-c0I1aURm.js +1 -0
- package/.build/client/assets/useSelector-ERD9RroG.js +2 -0
- package/.build/client/assets/useSuspenseQuery-vODFwDb8.js +1 -0
- package/.build/client/assets/utils-Bpv4vmSW.js +1 -0
- package/.build/client/assets/worker-triggers-DtXyn40O.js +1 -0
- package/.build/server/assets/_authenticated-Bch0_2QH.js +264 -0
- package/.build/server/assets/_authenticated-DGV5cZYE.js +22 -0
- package/.build/server/assets/_authenticated.account-6qu6oQ1y.js +685 -0
- package/.build/server/assets/_authenticated.agents-DYDnQxli.js +5 -0
- package/.build/server/assets/_authenticated.agents._agentId-4HvB3mhd.js +17 -0
- package/.build/server/assets/_authenticated.agents._agentId-Cl608F1T.js +260 -0
- package/.build/server/assets/_authenticated.agents._agentId-G2jAHjma.js +15 -0
- package/.build/server/assets/_authenticated.agents._agentId.chart-BIA8wy73.js +2644 -0
- package/.build/server/assets/_authenticated.agents._agentId.chart-D4aj8Qy9.js +22 -0
- package/.build/server/assets/_authenticated.agents._agentId.chat-ClsVle4g.js +13 -0
- package/.build/server/assets/_authenticated.agents._agentId.chat-JV3FDsTp.js +18 -0
- package/.build/server/assets/_authenticated.agents._agentId.index-Ct4kbu2f.js +1044 -0
- package/.build/server/assets/_authenticated.agents._agentId.index-DJgrupvW.js +18 -0
- package/.build/server/assets/_authenticated.agents._agentId.indicators-DrKd0aP5.js +184 -0
- package/.build/server/assets/_authenticated.agents._agentId.indicators-wiVaY8fW.js +18 -0
- package/.build/server/assets/_authenticated.agents._agentId.indicators_._indicatorId-C4Ox2R-a.js +25 -0
- package/.build/server/assets/_authenticated.agents._agentId.indicators_._indicatorId-D8Q0hCW0.js +489 -0
- package/.build/server/assets/_authenticated.agents._agentId.memories-BUTyVLYy.js +42 -0
- package/.build/server/assets/_authenticated.agents._agentId.memories-E8-nSEMT.js +362 -0
- package/.build/server/assets/_authenticated.agents._agentId.memories_._memoryRef-C-SC6wzq.js +14 -0
- package/.build/server/assets/_authenticated.agents._agentId.memories_._memoryRef-ZCrdrc8C.js +490 -0
- package/.build/server/assets/_authenticated.agents._agentId.notifications-DQeQqTzh.js +14 -0
- package/.build/server/assets/_authenticated.agents._agentId.notifications-DlFyYyHh.js +16 -0
- package/.build/server/assets/_authenticated.agents._agentId.notifications_._notificationId-B0RosY_R.js +15 -0
- package/.build/server/assets/_authenticated.agents._agentId.notifications_._notificationId-C1NikQ9e.js +13 -0
- package/.build/server/assets/_authenticated.agents._agentId.settings-DDwjT3Ui.js +42 -0
- package/.build/server/assets/_authenticated.agents._agentId.settings-PEzEvOfo.js +751 -0
- package/.build/server/assets/_authenticated.agents._agentId.sub-agents-z34-J3Tu.js +5 -0
- package/.build/server/assets/_authenticated.agents._agentId.sub-agents._subagentId-D-6TOi1U.js +1371 -0
- package/.build/server/assets/_authenticated.agents._agentId.sub-agents._subagentId-DipzVdnr.js +13 -0
- package/.build/server/assets/_authenticated.agents._agentId.sub-agents._subagentId_.runs._runId-BZR3VLV7.js +610 -0
- package/.build/server/assets/_authenticated.agents._agentId.sub-agents._subagentId_.runs._runId-DsYJKfGm.js +12 -0
- package/.build/server/assets/_authenticated.agents._agentId.sub-agents.index-BF8Cuzcr.js +231 -0
- package/.build/server/assets/_authenticated.agents._agentId.sub-agents.index-D2x0qCnt.js +12 -0
- package/.build/server/assets/_authenticated.agents._agentId.sub-agents.new-CYm_vuDD.js +13 -0
- package/.build/server/assets/_authenticated.agents._agentId.sub-agents.new-CiVShIka.js +497 -0
- package/.build/server/assets/_authenticated.agents._agentId.transactions-BC_XfGqw.js +95 -0
- package/.build/server/assets/_authenticated.agents._agentId.transactions-WtBW3xmh.js +495 -0
- package/.build/server/assets/_authenticated.agents.index-C8zmu8T8.js +78 -0
- package/.build/server/assets/_authenticated.agents.new-Bt-tBR47.js +302 -0
- package/.build/server/assets/_authenticated.providers-C0pb-ujV.js +672 -0
- package/.build/server/assets/_tanstack-start-manifest_v-Baw5u9sk.js +354 -0
- package/.build/server/assets/account-XvMwzRXh.js +66 -0
- package/.build/server/assets/account-queries-AJJVkLAV.js +32 -0
- package/.build/server/assets/agent-chat-page-DChiz8KQ.js +686 -0
- package/.build/server/assets/agent-enablement-control-C90f0uIb.js +143 -0
- package/.build/server/assets/agent-events-DK9Yz5__.js +217 -0
- package/.build/server/assets/agent-notifications-page-BdyKAyds.js +276 -0
- package/.build/server/assets/agent-queries-Cmx8RiUx.js +51 -0
- package/.build/server/assets/agents-CZq-0mna.js +106 -0
- package/.build/server/assets/agents-CfjmtW7A.js +278 -0
- package/.build/server/assets/artifact-content-B6uHmPz7.js +35 -0
- package/.build/server/assets/artifacts-HtLwHs8q.js +42 -0
- package/.build/server/assets/auth-DTikZAVz.js +12 -0
- package/.build/server/assets/auth-client-Vb3O0v7P.js +1897 -0
- package/.build/server/assets/auth-user-DkLo8ojH.js +108 -0
- package/.build/server/assets/chart-queries-Bc3AfsEb.js +109 -0
- package/.build/server/assets/charts-C4dKuwTJ.js +130 -0
- package/.build/server/assets/chat-bubble-ik3itVbx.js +109 -0
- package/.build/server/assets/config-dialog-9gSAjwwT.js +55 -0
- package/.build/server/assets/contracts-CG-nZuYJ.js +155 -0
- package/.build/server/assets/createServerRpc-DNqhdU4z.js +12 -0
- package/.build/server/assets/decimal-BthtZ77w.js +97 -0
- package/.build/server/assets/empty-plugin-adapters-MOWBbCMw.js +5 -0
- package/.build/server/assets/errors-DaZqUftX.js +151 -0
- package/.build/server/assets/gateway-CHkruO_a.js +193 -0
- package/.build/server/assets/identicon-CyawcVnx.js +41 -0
- package/.build/server/assets/indicator-input-fields-bzuhIh6t.js +75 -0
- package/.build/server/assets/indicator-queries-4dY1-LXx.js +171 -0
- package/.build/server/assets/indicator-renderer-B2muPS-8.js +395 -0
- package/.build/server/assets/indicators-ENxAHN42.js +192 -0
- package/.build/server/assets/insight-contracts-B5rmUDfO.js +14 -0
- package/.build/server/assets/instrument-label-C-tTGGsD.js +40 -0
- package/.build/server/assets/instrument-picker-CRroLwVq.js +381 -0
- package/.build/server/assets/journal-9aE-um9f.js +107 -0
- package/.build/server/assets/journal-decimal-Bh9EL029.js +66 -0
- package/.build/server/assets/login-BsEFUvTX.js +125 -0
- package/.build/server/assets/memories-2WF2fW1G.js +100 -0
- package/.build/server/assets/memory-badge-DVYLTtRR.js +53 -0
- package/.build/server/assets/memory-contracts-DQGN2IKV.js +22 -0
- package/.build/server/assets/memory-queries--4RbPRrk.js +92 -0
- package/.build/server/assets/model-picker-CA1uYb--.js +225 -0
- package/.build/server/assets/notification-queries-0CJUkBt9.js +52 -0
- package/.build/server/assets/notifications-Cn7BiCyw.js +72 -0
- package/.build/server/assets/provider-logo-BRdbOr9I.js +32 -0
- package/.build/server/assets/provider-queries-BaZWLw8J.js +78 -0
- package/.build/server/assets/providers-CyoN_jgW.js +89 -0
- package/.build/server/assets/risk-Bqrb6hKQ.js +34 -0
- package/.build/server/assets/risk-queries-JQpByHT2.js +18 -0
- package/.build/server/assets/router-Hkr5TH_I.js +419 -0
- package/.build/server/assets/run-subagent-dialog-C7iUOZa-.js +59 -0
- package/.build/server/assets/setup-DqMlwgNr.js +30 -0
- package/.build/server/assets/setup-checklist-BICTmBo2.js +60 -0
- package/.build/server/assets/start-C-GPoWRt.js +4 -0
- package/.build/server/assets/subagent-enabled-toggle-Djte00oo.js +22 -0
- package/.build/server/assets/subagent-input-BHQKs2cW.js +57 -0
- package/.build/server/assets/subagent-mutations-dUo3B_SG.js +32 -0
- package/.build/server/assets/subagent-queries-sAwBjFxC.js +146 -0
- package/.build/server/assets/subagent-run-history-C_xmucO-.js +186 -0
- package/.build/server/assets/subagents-CIoilC66.js +180 -0
- package/.build/server/assets/toggle-timestamp-CToUVn67.js +28 -0
- package/.build/server/assets/trading-contracts-zWq1Hxnb.js +26 -0
- package/.build/server/assets/validation-BX-krL0i.js +33 -0
- package/.build/server/assets/worker-triggers-CJF5HWzR.js +51 -0
- package/.build/server/server.js +7501 -0
- package/LICENSE +661 -0
- package/README.md +145 -2
- package/bin/hypervibes.js +24 -0
- package/dist/agents/agent-enablement.js +10 -0
- package/dist/agents/agent-input.js +38 -0
- package/dist/agents/agent-service.js +1004 -0
- package/dist/agents/cancel-task-scope.js +52 -0
- package/dist/agents/candle-intervals.js +1 -0
- package/dist/agents/default-subagents.js +36 -0
- package/dist/agents/execution-context-contracts.js +1 -0
- package/dist/agents/execution-context.js +206 -0
- package/dist/agents/execution-warnings.js +33 -0
- package/dist/agents/orchestrator-insights.js +14 -0
- package/dist/agents/run-inspection.js +99 -0
- package/dist/agents/subagent-dashboard.js +1 -0
- package/dist/agents/subagent-extension.js +156 -0
- package/dist/agents/subagent-history.js +5 -0
- package/dist/agents/subagent-input.js +73 -0
- package/dist/agents/subagent-service.js +1177 -0
- package/dist/agents/subagent-templates.js +20 -0
- package/dist/agents/template-manifest.js +34 -0
- package/dist/agents/templates/basic-analysis.json +40 -0
- package/dist/agents/templates/basic-review.json +48 -0
- package/dist/agents/templates/basic-trading.json +45 -0
- package/dist/agents/templates/indicator-developer.json +16 -0
- package/dist/agents/time-guidance.js +29 -0
- package/dist/agents/worker-events.js +18 -0
- package/dist/agents/worker-inbox.js +28 -0
- package/dist/agents/worker-triggers.js +23 -0
- package/dist/auth-options.js +98 -0
- package/dist/auth-user.js +15 -0
- package/dist/auth.js +28 -0
- package/dist/cache/svg-logo-cache.js +155 -0
- package/dist/canonical.js +13 -0
- package/dist/charts/chart-service.js +236 -0
- package/dist/charts/contracts.js +118 -0
- package/dist/charts/durable-extension.js +27 -0
- package/dist/charts/trading-contracts.js +14 -0
- package/dist/config.js +85 -0
- package/dist/db/agent-schema.js +26 -0
- package/dist/db/auth-schema.js +122 -0
- package/dist/db/database.js +31 -0
- package/dist/db/exchange-schema.js +23 -0
- package/dist/db/gateway-schema.js +24 -0
- package/dist/db/indicator-schema.js +19 -0
- package/dist/db/migrations/20261015221717_auth/migration.sql +62 -0
- package/dist/db/migrations/20261015231224_agents/migration.sql +35 -0
- package/dist/db/migrations/20261016040641_provider_connections/migration.sql +19 -0
- package/dist/db/migrations/20261016061831_trade_journal/migration.sql +48 -0
- package/dist/db/migrations/20261016080320_order_execution/migration.sql +62 -0
- package/dist/db/migrations/20261016181110_subagents/migration.sql +51 -0
- package/dist/db/migrations/20261017222959_research_artifacts/migration.sql +37 -0
- package/dist/db/migrations/20261018061531_memories_and_insights/migration.sql +162 -0
- package/dist/db/migrations/20261020091156_worker_event_inbox/migration.sql +54 -0
- package/dist/db/migrations/20261021051229_chart_workspace/migration.sql +33 -0
- package/dist/db/migrations/20261021222116_gateways/migration.sql +15 -0
- package/dist/db/migrations/20261022015813_pine_indicators/migration.sql +43 -0
- package/dist/db/migrations/20261022101559_notifications/migration.sql +51 -0
- package/dist/db/migrations.js +12 -0
- package/dist/db/order-provenance-schema.js +17 -0
- package/dist/db/order-schema.js +32 -0
- package/dist/db/profile-lock.js +12 -0
- package/dist/db/provider-schema.js +16 -0
- package/dist/db/shared-database.js +128 -0
- package/dist/db/subagent-schema.js +79 -0
- package/dist/gateway/bridge-service.js +223 -0
- package/dist/gateway/gateway-store.js +77 -0
- package/dist/gateway/handlers.js +122 -0
- package/dist/gateway/telegram/connector.js +115 -0
- package/dist/gateway/telegram/transport.js +96 -0
- package/dist/hyperliquid/account-info.js +117 -0
- package/dist/hyperliquid/account-status.js +64 -0
- package/dist/hyperliquid/agent-dashboard.js +56 -0
- package/dist/hyperliquid/chart-contracts.js +9 -0
- package/dist/hyperliquid/constants.js +25 -0
- package/dist/hyperliquid/crypto.js +29 -0
- package/dist/hyperliquid/currency-logo.js +7 -0
- package/dist/hyperliquid/decimal.js +98 -0
- package/dist/hyperliquid/durable-extension.js +39 -0
- package/dist/hyperliquid/errors.js +8 -0
- package/dist/hyperliquid/exchange.js +118 -0
- package/dist/hyperliquid/journal-decimal.js +48 -0
- package/dist/hyperliquid/journal-model.js +167 -0
- package/dist/hyperliquid/journal-service.js +648 -0
- package/dist/hyperliquid/live-dashboard.js +245 -0
- package/dist/hyperliquid/logo-cache.js +27 -0
- package/dist/hyperliquid/market-charts.js +242 -0
- package/dist/hyperliquid/market-snapshot.js +45 -0
- package/dist/hyperliquid/orders/order-contracts.js +42 -0
- package/dist/hyperliquid/orders/order-math.js +89 -0
- package/dist/hyperliquid/orders/order-outcomes.js +74 -0
- package/dist/hyperliquid/orders/order-prepare.js +109 -0
- package/dist/hyperliquid/orders/order-service.js +432 -0
- package/dist/hyperliquid/orders/order-store.js +134 -0
- package/dist/hyperliquid/orders/order-tools.js +40 -0
- package/dist/hyperliquid/orders/protection.js +35 -0
- package/dist/hyperliquid/orders/risk-settings.js +44 -0
- package/dist/hyperliquid/orders/trade-admission.js +117 -0
- package/dist/hyperliquid/orders/trade-planning.js +60 -0
- package/dist/hyperliquid/service.js +529 -0
- package/dist/hyperliquid/shared-feeds.js +40 -0
- package/dist/hyperliquid/signing.js +89 -0
- package/dist/indicators/builtin-catalog.js +59 -0
- package/dist/indicators/builtins/adx.pine +22 -0
- package/dist/indicators/builtins/atr.pine +11 -0
- package/dist/indicators/builtins/bollinger.pine +10 -0
- package/dist/indicators/builtins/ema.pine +5 -0
- package/dist/indicators/builtins/macd.pine +18 -0
- package/dist/indicators/builtins/rsi.pine +18 -0
- package/dist/indicators/builtins/sma.pine +5 -0
- package/dist/indicators/candle-window.js +36 -0
- package/dist/indicators/chart-contracts.js +64 -0
- package/dist/indicators/contracts.js +14 -0
- package/dist/indicators/durable-extension.js +32 -0
- package/dist/indicators/indicator-service.js +300 -0
- package/dist/indicators/indicator-store.js +137 -0
- package/dist/indicators/normalize.js +149 -0
- package/dist/indicators/result-schema.js +79 -0
- package/dist/indicators/runtime-wrapper.js +52 -0
- package/dist/indicators/runtime.js +201 -0
- package/dist/indicators/validation.js +124 -0
- package/dist/indicators/worker-queue.js +48 -0
- package/dist/initialize-config.js +160 -0
- package/dist/main.js +59 -0
- package/dist/memory/decision-audit.js +47 -0
- package/dist/memory/durable-extension.js +40 -0
- package/dist/memory/execution-audit.js +83 -0
- package/dist/memory/insight-contracts.js +33 -0
- package/dist/memory/insight-service.js +117 -0
- package/dist/memory/memory-contracts.js +113 -0
- package/dist/memory/memory-service.js +179 -0
- package/dist/memory/operations.js +46 -0
- package/dist/memory/tool-schemas.js +44 -0
- package/dist/memory/validation.js +42 -0
- package/dist/notifications/contracts.js +1 -0
- package/dist/notifications/delivery.js +11 -0
- package/dist/notifications/durable-extension.js +20 -0
- package/dist/notifications/notification-service.js +324 -0
- package/dist/providers/credential-store.js +86 -0
- package/dist/providers/ollama-cloud.js +148 -0
- package/dist/providers/provider-logo-url.js +18 -0
- package/dist/providers/provider-logo.js +31 -0
- package/dist/providers/provider-service.js +295 -0
- package/dist/research/artifacts.js +151 -0
- package/dist/research/call-queue.js +43 -0
- package/dist/research/contracts.js +37 -0
- package/dist/research/evidence.js +43 -0
- package/dist/research/journal.js +30 -0
- package/dist/research/research-service.js +191 -0
- package/dist/research/tool-activity.js +49 -0
- package/dist/research/tool-response.js +25 -0
- package/dist/runtime.js +145 -0
- package/dist/web/agent-events.js +418 -0
- package/dist/web/app.js +206 -0
- package/dist/web/artifact-downloads.js +23 -0
- package/dist/web/middleware.js +25 -0
- package/dist/web/random-uuid.js +14 -0
- package/dist/web/start.js +56 -0
- package/package.json +93 -3
- package/scripts/check-node.mjs +24 -0
- package/static/android-chrome-192x192.png +0 -0
- package/static/android-chrome-512x512.png +0 -0
- package/static/apple-touch-icon.png +0 -0
- package/static/favicon-16x16.png +0 -0
- package/static/favicon-32x32.png +0 -0
- package/static/favicon.ico +0 -0
- package/static/github.svg +3 -0
- package/static/hypervibes.png +0 -0
- package/static/logo.png +0 -0
- package/static/site.webmanifest +1 -0
- package/static/telegram.svg +1 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { ApiRequestError, ExchangeClient, InfoClient } from "@nktkas/hyperliquid";
|
|
2
|
+
import { TradeAdmissionService } from "./trade-admission.js";
|
|
3
|
+
import { preparePositionProtection, prepareProtectedEntry } from "./trade-planning.js";
|
|
4
|
+
import { verifyProtection } from "./protection.js";
|
|
5
|
+
import { compare, positionSize } from "./order-math.js";
|
|
6
|
+
import { assertAgentExecutable } from "../../agents/agent-enablement.js";
|
|
7
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
8
|
+
import { HyperliquidError } from "../errors.js";
|
|
9
|
+
import { assertStringAmounts, exchangeOid, instruments, instrument, isPerpetual, liveView, newView, prepareSubmit } from "./order-prepare.js";
|
|
10
|
+
import { OrderStore, active } from "./order-store.js";
|
|
11
|
+
import { reconciledView, responseViews, unknownViews } from "./order-outcomes.js";
|
|
12
|
+
/** Application-owned intent/outcome gateway. Reconciliation NEVER submits orders. */
|
|
13
|
+
export class OrderService {
|
|
14
|
+
database;
|
|
15
|
+
transport;
|
|
16
|
+
bindings;
|
|
17
|
+
log;
|
|
18
|
+
store;
|
|
19
|
+
info;
|
|
20
|
+
locks = new Map();
|
|
21
|
+
tasks = new Set();
|
|
22
|
+
agentTasks = new Map();
|
|
23
|
+
stoppedAgents = new Set();
|
|
24
|
+
shutdown = new AbortController();
|
|
25
|
+
timer;
|
|
26
|
+
started = false;
|
|
27
|
+
stopping = false;
|
|
28
|
+
admission;
|
|
29
|
+
constructor(database, transport, bindings, log) {
|
|
30
|
+
this.database = database;
|
|
31
|
+
this.transport = transport;
|
|
32
|
+
this.bindings = bindings;
|
|
33
|
+
this.log = log;
|
|
34
|
+
this.store = new OrderStore(database);
|
|
35
|
+
this.info = new InfoClient({ transport });
|
|
36
|
+
}
|
|
37
|
+
installAdmission(execution) { this.admission = new TradeAdmissionService(this.database, execution); }
|
|
38
|
+
executionHandle(agentId, api, context) {
|
|
39
|
+
if (!this.admission)
|
|
40
|
+
throw new HyperliquidError("Execution identity is not initialized; model orders are unavailable", 503);
|
|
41
|
+
return this.admission.handle(agentId, api, context);
|
|
42
|
+
}
|
|
43
|
+
async plan(userId, agentId, input, handle, cancellation) {
|
|
44
|
+
await this.account(userId, agentId);
|
|
45
|
+
if (!this.admission)
|
|
46
|
+
throw new HyperliquidError("Trade planning is not initialized", 503);
|
|
47
|
+
this.admission.planning(agentId, handle);
|
|
48
|
+
return prepareProtectedEntry(this.info, input, this.signal(cancellation));
|
|
49
|
+
}
|
|
50
|
+
async planProtection(userId, agentId, input, handle, cancellation) {
|
|
51
|
+
const account = await this.account(userId, agentId);
|
|
52
|
+
if (!this.admission)
|
|
53
|
+
throw new HyperliquidError("Trade planning is not initialized", 503);
|
|
54
|
+
this.admission.planning(agentId, handle);
|
|
55
|
+
return preparePositionProtection(this.info, input, account, this.signal(cancellation));
|
|
56
|
+
}
|
|
57
|
+
async protection(userId, agentId, cancellation) {
|
|
58
|
+
const account = await this.account(userId, agentId), signal = this.signal(cancellation);
|
|
59
|
+
const [state, orders, mids] = await Promise.all([this.info.clearinghouseState({ user: account, dex: "" }, signal), this.info.frontendOpenOrders({ user: account, dex: "" }, signal), this.info.allMids({ dex: "" }, signal)]);
|
|
60
|
+
if (orders.length > 100 || state.assetPositions.length > 100)
|
|
61
|
+
throw new HyperliquidError("More than 100 open orders/positions; protection coverage is over budget and must be reviewed manually", 409);
|
|
62
|
+
const positions = await verifyProtection(this.info, account, state.assetPositions.map(({ position }) => ({ coin: position.coin, size: position.szi })), orders, mids, signal);
|
|
63
|
+
return { observedAt: Date.now(), positions, warning: "Snapshot verification only. Native children waitingForFill do not protect partial positions. Scheduled model repair cannot guarantee zero unprotected time. Preserve known orders; do not flatten or cancel-all without authorization." };
|
|
64
|
+
}
|
|
65
|
+
recover() { return this.store.recover(); }
|
|
66
|
+
start() {
|
|
67
|
+
if (this.started || this.stopping)
|
|
68
|
+
return;
|
|
69
|
+
this.started = true;
|
|
70
|
+
this.log?.info("Starting order reconciliation loop");
|
|
71
|
+
const tick = async () => {
|
|
72
|
+
try {
|
|
73
|
+
for (const request of await this.store.pendingRequests()) {
|
|
74
|
+
if (this.stopping)
|
|
75
|
+
break;
|
|
76
|
+
if (this.stoppedAgents.has(request.agentId))
|
|
77
|
+
continue;
|
|
78
|
+
const agent = await this.database.get("SELECT state FROM hv_agents WHERE id=?", request.agentId);
|
|
79
|
+
if (!agent || agent.state === "stopping" || agent.state === "stopped" || this.stoppedAgents.has(request.agentId))
|
|
80
|
+
continue;
|
|
81
|
+
await this.trackAgent(request.agentId, () => this.lock(request.id, () => this.reconcile(request, this.signal())));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
this.log?.warn(error, "Order reconciliation pass failed; retrying on the next pass");
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
if (!this.stopping) {
|
|
89
|
+
this.timer = setTimeout(() => { void this.track(tick()); }, 15_000);
|
|
90
|
+
this.timer.unref();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
void this.track(tick());
|
|
95
|
+
}
|
|
96
|
+
async close() {
|
|
97
|
+
this.stopping = true;
|
|
98
|
+
clearTimeout(this.timer);
|
|
99
|
+
this.shutdown.abort();
|
|
100
|
+
await Promise.allSettled([...this.tasks]);
|
|
101
|
+
}
|
|
102
|
+
/** Join the per-agent mutation queue without sealing operator exits or reconciliation. */
|
|
103
|
+
quiesce(agentId) { return this.lock(agentId, async () => { }); }
|
|
104
|
+
/** Seal this agent only; join submissions and reconciliation before cascading its records. */
|
|
105
|
+
async stopAgent(agentId) {
|
|
106
|
+
this.stoppedAgents.add(agentId);
|
|
107
|
+
await Promise.allSettled([...(this.agentTasks.get(agentId) ?? [])]);
|
|
108
|
+
}
|
|
109
|
+
trackAgent(agentId, run) {
|
|
110
|
+
if (this.stoppedAgents.has(agentId))
|
|
111
|
+
return Promise.reject(new HyperliquidError("Agent is being deleted", 409));
|
|
112
|
+
const tasks = this.agentTasks.get(agentId) ?? new Set();
|
|
113
|
+
this.agentTasks.set(agentId, tasks);
|
|
114
|
+
const task = this.track(run());
|
|
115
|
+
tasks.add(task);
|
|
116
|
+
void task.finally(() => {
|
|
117
|
+
tasks.delete(task);
|
|
118
|
+
if (!tasks.size)
|
|
119
|
+
this.agentTasks.delete(agentId);
|
|
120
|
+
}).catch(() => { });
|
|
121
|
+
return task;
|
|
122
|
+
}
|
|
123
|
+
signal(signal) { return AbortSignal.any([this.shutdown.signal, AbortSignal.timeout(15_000), ...(signal ? [signal] : [])]); }
|
|
124
|
+
track(task) {
|
|
125
|
+
this.tasks.add(task);
|
|
126
|
+
void task.finally(() => this.tasks.delete(task)).catch(() => { });
|
|
127
|
+
return task;
|
|
128
|
+
}
|
|
129
|
+
admit() { if (this.stopping)
|
|
130
|
+
throw new HyperliquidError("Order service is closed", 503); }
|
|
131
|
+
lock(key, run) {
|
|
132
|
+
const task = (this.locks.get(key) ?? Promise.resolve()).catch(() => { }).then(run);
|
|
133
|
+
this.locks.set(key, task);
|
|
134
|
+
void task.finally(() => { if (this.locks.get(key) === task)
|
|
135
|
+
this.locks.delete(key); }).catch(() => { });
|
|
136
|
+
return task;
|
|
137
|
+
}
|
|
138
|
+
async account(userId, agentId) {
|
|
139
|
+
this.admit();
|
|
140
|
+
if (this.stoppedAgents.has(agentId))
|
|
141
|
+
throw new HyperliquidError("Agent is being deleted", 409);
|
|
142
|
+
const address = await this.bindings.account(userId, agentId);
|
|
143
|
+
if (!address || !/^0x[0-9a-fA-F]{40}$/.test(address))
|
|
144
|
+
throw new HyperliquidError("This Agent has no valid assigned trading account.", 409);
|
|
145
|
+
return address.toLowerCase();
|
|
146
|
+
}
|
|
147
|
+
requestKey(key) { if (typeof key !== "string" || !/^[a-zA-Z0-9_-]{1,120}$/.test(key))
|
|
148
|
+
throw new HyperliquidError("Use a stable request_id of 1–120 letters, digits, underscores or hyphens."); }
|
|
149
|
+
submit(userId, agentId, input, signal, execution) {
|
|
150
|
+
assertStringAmounts(input);
|
|
151
|
+
if (!Array.isArray(input.orders) || input.orders.length < 1 || input.orders.length > 20)
|
|
152
|
+
throw new HyperliquidError("Submit 1–20 entry orders per request.");
|
|
153
|
+
return this.mutate(userId, agentId, input.request_id, "submit", input, signal, (authority, abort) => prepareSubmit(this.info, input.request_id, input.orders, authority.builder, abort), execution);
|
|
154
|
+
}
|
|
155
|
+
cancel(userId, agentId, input, signal, execution) {
|
|
156
|
+
assertStringAmounts(input);
|
|
157
|
+
if (!Array.isArray(input.orders) || input.orders.length < 1 || input.orders.length > 100)
|
|
158
|
+
throw new HyperliquidError("Cancel 1–100 orders per request.");
|
|
159
|
+
return this.mutate(userId, agentId, input.request_id, "cancel", input, signal, (authority, abort) => this.prepareCancel(authority.account, input.request_id, input.orders, abort), execution);
|
|
160
|
+
}
|
|
161
|
+
cancelAll(userId, agentId, input, signal, execution) {
|
|
162
|
+
return this.mutate(userId, agentId, input.request_id, "cancel_all", input, signal, async (authority, abort) => {
|
|
163
|
+
const orders = (await this.info.frontendOpenOrders({ user: authority.account, dex: "" }, abort))
|
|
164
|
+
.filter((order) => isPerpetual(order.coin) && (!input.symbol || order.coin === input.symbol));
|
|
165
|
+
if (orders.length > 100)
|
|
166
|
+
throw new HyperliquidError("More than 100 open orders; cancel explicit bounded batches instead.");
|
|
167
|
+
if (!orders.length)
|
|
168
|
+
return [];
|
|
169
|
+
return this.prepareCancel(authority.account, input.request_id, orders.map((order) => ({ symbol: order.coin, oid: String(order.oid) })), abort);
|
|
170
|
+
}, execution);
|
|
171
|
+
}
|
|
172
|
+
/** Operator-only single-order cancellation; mutate owns the per-agent lock and replay. */
|
|
173
|
+
cancelOrder(userId, agentId, symbol, oid, key) {
|
|
174
|
+
const input = { request_id: key, orders: [{ symbol, oid }] };
|
|
175
|
+
return this.mutate(userId, agentId, key, "cancel", input, undefined, (authority, signal) => this.prepareCancel(authority.account, key, input.orders, signal), undefined, { operator: true });
|
|
176
|
+
}
|
|
177
|
+
/** Operator-only exit. Browser/model input never supplies side, size, or signing authority. */
|
|
178
|
+
closePosition(userId, agentId, symbol, key) {
|
|
179
|
+
this.admit();
|
|
180
|
+
this.requestKey(key);
|
|
181
|
+
if (key.length > 100)
|
|
182
|
+
throw new HyperliquidError("Close request ID must be at most 100 characters");
|
|
183
|
+
return this.trackAgent(agentId, () => this.lock(agentId, async () => {
|
|
184
|
+
const account = await this.account(userId, agentId);
|
|
185
|
+
instrument(await instruments(this.info, this.signal()), symbol);
|
|
186
|
+
const unresolved = await this.database.get(`SELECT r.request_key FROM hv_order_requests r JOIN hv_order_actions a ON a.request_id=r.id WHERE r.account=? AND r.kind='close_position' AND json_extract(r.input,'$.symbol')=? AND a.state IN ('submitting','unknown') AND r.request_key!=? LIMIT 1`, account, symbol, `${key}-close`);
|
|
187
|
+
if (unresolved)
|
|
188
|
+
throw new HyperliquidError(`An earlier position close has an unknown outcome. Reconcile request ${unresolved.request_key} before issuing another close.`, 409);
|
|
189
|
+
const cancel = await this.mutate(userId, agentId, `${key}-cancel`, "cancel_all", { symbol }, undefined, async (authority, signal) => {
|
|
190
|
+
const orders = (await this.info.frontendOpenOrders({ user: authority.account, dex: "" }, signal)).filter((order) => order.coin === symbol);
|
|
191
|
+
if (orders.length > 100)
|
|
192
|
+
throw new HyperliquidError("More than 100 orders in this market; review manually", 409);
|
|
193
|
+
return orders.length ? this.prepareCancel(account, `${key}-cancel`, orders.map((order) => ({ symbol, oid: String(order.oid) })), signal) : [];
|
|
194
|
+
}, undefined, { operator: true, locked: true });
|
|
195
|
+
const close = await this.mutate(userId, agentId, `${key}-close`, "close_position", { symbol }, undefined, async (authority, signal) => {
|
|
196
|
+
const state = await this.info.clearinghouseState({ user: account, dex: "" }, signal);
|
|
197
|
+
const current = state.assetPositions.find(({ position }) => position.coin === symbol)?.position;
|
|
198
|
+
if (!current)
|
|
199
|
+
return [];
|
|
200
|
+
const position = positionSize(current.szi);
|
|
201
|
+
if (position.side === "flat")
|
|
202
|
+
return [];
|
|
203
|
+
return prepareSubmit(this.info, `${key}-close`, [{ symbol, side: position.side === "long" ? "sell" : "buy", size: position.size, order_type: "market", reduce_only: true }], authority.builder, signal);
|
|
204
|
+
}, undefined, { operator: true, locked: true });
|
|
205
|
+
const warnings = [...close.warnings];
|
|
206
|
+
if (cancel.uncertain)
|
|
207
|
+
warnings.push("Cancellation outcome is unknown. Check the original operation instead of retrying with a new ID.");
|
|
208
|
+
if (cancel.results.some((order) => order.commandStatus === "rejected" || order.commandStatus === "unknown" || order.commandStatus === "not_sent"))
|
|
209
|
+
warnings.push("Some market orders were not confirmed canceled; inspect remaining orders.");
|
|
210
|
+
let remainingSize = null, remainingOrders = null;
|
|
211
|
+
try {
|
|
212
|
+
const [state, orders] = await Promise.all([
|
|
213
|
+
this.info.clearinghouseState({ user: account, dex: "" }, this.signal()),
|
|
214
|
+
this.info.frontendOpenOrders({ user: account, dex: "" }, this.signal()),
|
|
215
|
+
]);
|
|
216
|
+
remainingSize = state.assetPositions.find(({ position }) => position.coin === symbol)?.position.szi ?? "0";
|
|
217
|
+
remainingOrders = orders.filter((order) => order.coin === symbol).length;
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
warnings.push("Could not verify remaining position/orders. Inspect the account before retrying.");
|
|
221
|
+
}
|
|
222
|
+
return { requestId: key, cancel, close, remainingSize, remainingOrders, warnings,
|
|
223
|
+
complete: remainingSize !== null && positionSize(remainingSize).side === "flat" && remainingOrders === 0 && !cancel.uncertain && !close.uncertain };
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
async prepareCancel(account, key, inputs, signal) {
|
|
227
|
+
const meta = await instruments(this.info, signal);
|
|
228
|
+
const seen = new Set();
|
|
229
|
+
const items = [], cancels = [];
|
|
230
|
+
for (const input of inputs) {
|
|
231
|
+
const asset = instrument(meta, input.symbol).asset;
|
|
232
|
+
const oid = exchangeOid(input.oid);
|
|
233
|
+
if (seen.has(input.oid))
|
|
234
|
+
throw new HyperliquidError("Duplicate cancellation target.");
|
|
235
|
+
seen.add(input.oid);
|
|
236
|
+
// OIDs alone confer no authority. Check the assigned account and symbol,
|
|
237
|
+
// including orders this account placed outside HyperVibes.
|
|
238
|
+
const status = await this.info.orderStatus({ user: account, oid }, signal);
|
|
239
|
+
if (status.status !== "order" || status.order.order.coin !== input.symbol || status.order.order.oid !== oid)
|
|
240
|
+
throw new HyperliquidError("Cancellation target was not found on this Agent's account/symbol.", 409);
|
|
241
|
+
const view = liveView(status.order.order, status.order.status, status.order.statusTimestamp);
|
|
242
|
+
items.push({ ...view, id: newView(key, input.symbol, "cancel").id, requestId: key, kind: "cancel", cloid: null, commandStatus: "not_sent", source: "intent" });
|
|
243
|
+
cancels.push({ a: asset, o: oid });
|
|
244
|
+
}
|
|
245
|
+
return [{ payload: { kind: "cancel", cancels }, items }];
|
|
246
|
+
}
|
|
247
|
+
mutate(userId, agentId, key, kind, input, cancellation, prepare, execution, options = {}) {
|
|
248
|
+
this.admit();
|
|
249
|
+
this.requestKey(key);
|
|
250
|
+
const operator = options.operator === true;
|
|
251
|
+
if (!this.started)
|
|
252
|
+
return Promise.reject(new HyperliquidError("Order execution is not started", 503));
|
|
253
|
+
const run = async () => {
|
|
254
|
+
const account = await this.account(userId, agentId);
|
|
255
|
+
if (!operator)
|
|
256
|
+
await assertAgentExecutable(this.database, agentId);
|
|
257
|
+
const submission = kind === "submit" || kind === "close_position";
|
|
258
|
+
const signal = this.signal(cancellation);
|
|
259
|
+
signal.throwIfAborted();
|
|
260
|
+
let request = await this.store.request(agentId, key);
|
|
261
|
+
let authority;
|
|
262
|
+
if (request) {
|
|
263
|
+
this.store.matches(request, account, kind, input);
|
|
264
|
+
const existing = request;
|
|
265
|
+
if (operator)
|
|
266
|
+
await this.lock(existing.id, () => this.reconcile(existing, signal));
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
if (kind === "submit" && input.orders.some((order) => !order.reduce_only && ["limit", "market"].includes(order.order_type)) && await this.store.hasUncertain(account)) {
|
|
270
|
+
throw new HyperliquidError("An earlier command has an unknown outcome on this account. Reconcile it before adding exposure; do not retry with a new request_id.", 409);
|
|
271
|
+
}
|
|
272
|
+
authority = await this.bindings.authority(userId, agentId, signal, submission);
|
|
273
|
+
if (authority.account !== account)
|
|
274
|
+
throw new HyperliquidError("Account assignment changed", 409);
|
|
275
|
+
const prepared = await prepare(authority, signal);
|
|
276
|
+
if (kind === "submit" && this.admission)
|
|
277
|
+
await this.admission.validate(agentId, this.info, account, signal, prepared, execution);
|
|
278
|
+
const capability = kind === "submit" ? "submit_orders" : kind === "cancel" ? "cancel_orders" : "cancel_all_orders";
|
|
279
|
+
const origin = operator ? undefined : this.admission?.origin(agentId, execution, capability);
|
|
280
|
+
request = await this.store.prepare(agentId, account, key, kind, input, prepared, origin);
|
|
281
|
+
}
|
|
282
|
+
// The same request lock is also used by background reconciliation.
|
|
283
|
+
const captured = request;
|
|
284
|
+
return this.lock(captured.id, async () => {
|
|
285
|
+
const actions = await this.store.actions(captured.id);
|
|
286
|
+
let stop = actions.some((action) => action.state === "unknown" || action.state === "submitting")
|
|
287
|
+
|| (await this.store.allItems(captured.id)).some(({ view }) => JSON.parse(view).commandStatus === "rejected");
|
|
288
|
+
for (const action of actions) {
|
|
289
|
+
if (action.state !== "prepared")
|
|
290
|
+
continue;
|
|
291
|
+
const views = (await this.store.items(action.id)).map(({ view }) => JSON.parse(view));
|
|
292
|
+
if (stop || signal.aborted || Date.now() >= action.expiresAt) {
|
|
293
|
+
await this.store.outcome(action.id, "not_sent", views.map((view) => ({ ...view, commandStatus: "not_sent", orderStatus: "not_sent", updatedAt: Date.now(), error: "Not sent: previous action uncertain/rejected, request expired, or execution aborted." })), "not_sent");
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (!operator)
|
|
297
|
+
await assertAgentExecutable(this.database, agentId);
|
|
298
|
+
authority ??= await this.bindings.authority(userId, agentId, signal, submission);
|
|
299
|
+
if (authority.account !== captured.account)
|
|
300
|
+
throw new HyperliquidError("Account assignment changed", 409);
|
|
301
|
+
if (kind === "submit" && this.admission) {
|
|
302
|
+
if (views.some((view) => !view.reduceOnly) && await this.store.hasUncertain(account))
|
|
303
|
+
throw new HyperliquidError("An earlier command has an unknown outcome on this account. Reconcile it before adding exposure.", 409);
|
|
304
|
+
await this.admission.validate(agentId, this.info, account, signal, [{ payload: JSON.parse(action.payload), items: views }], execution);
|
|
305
|
+
}
|
|
306
|
+
if (operator && submission && views.some((view) => !view.reduceOnly))
|
|
307
|
+
throw new HyperliquidError("Operator exits must be reduce-only", 403);
|
|
308
|
+
if (!operator)
|
|
309
|
+
await assertAgentExecutable(this.database, agentId);
|
|
310
|
+
if (!(await this.store.begin(action, operator ? undefined : agentId)))
|
|
311
|
+
continue;
|
|
312
|
+
const payload = JSON.parse(action.payload);
|
|
313
|
+
let response;
|
|
314
|
+
let uncertain = false;
|
|
315
|
+
try {
|
|
316
|
+
const client = new ExchangeClient({ transport: this.transport, wallet: privateKeyToAccount(authority.privateKey),
|
|
317
|
+
nonceManager: (signer) => this.store.nonce(signer, action.id) });
|
|
318
|
+
const options = { signal, vaultAddress: authority.vaultAddress, expiresAfter: action.expiresAt };
|
|
319
|
+
response = payload.kind === "submit" ? await client.order({ orders: payload.orders, grouping: payload.grouping, builder: payload.builder }, options)
|
|
320
|
+
: await client.cancel({ cancels: payload.cancels }, options);
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
if (error instanceof ApiRequestError)
|
|
324
|
+
response = error.response;
|
|
325
|
+
else
|
|
326
|
+
uncertain = true;
|
|
327
|
+
}
|
|
328
|
+
const outcomes = uncertain ? unknownViews(views, "Submission outcome is unknown after transport/signing interruption. Do not resubmit; reconcile this request_id.") : responseViews(payload.kind, response, views);
|
|
329
|
+
const unknown = outcomes.some((view) => view.commandStatus === "unknown");
|
|
330
|
+
await this.store.outcome(action.id, unknown ? "unknown" : "done", outcomes, "exchange_response");
|
|
331
|
+
stop = unknown || outcomes.some((view) => view.commandStatus === "rejected");
|
|
332
|
+
}
|
|
333
|
+
return this.result(captured);
|
|
334
|
+
});
|
|
335
|
+
};
|
|
336
|
+
return this.trackAgent(agentId, () => options.locked ? run() : this.lock(agentId, run));
|
|
337
|
+
}
|
|
338
|
+
async result(request) {
|
|
339
|
+
const results = (await this.store.allItems(request.id)).map(({ view }) => JSON.parse(view));
|
|
340
|
+
const warnings = [];
|
|
341
|
+
if (request.kind === "cancel_all")
|
|
342
|
+
warnings.push("Cancel-all targets only the original captured main-DEX perpetual orders, including any protective TP/SL. It does not sweep new orders or close positions.");
|
|
343
|
+
if (results.some((view) => view.kind === "take_profit" || view.kind === "stop_loss"))
|
|
344
|
+
warnings.push("TP/SL uses fixed-size reduce-only triggers. Native attached TP/SL activates on full parent fill; manually canceling a partially filled parent also cancels its attached protection. Inspect every leg; a rejected leg can leave exposure unprotected.");
|
|
345
|
+
if (results.some((view) => view.filledSize && view.size && compare(view.filledSize, view.size) < 0))
|
|
346
|
+
warnings.push("Only part of the requested size was filled. filledSize is the executed quantity; a filled receipt does not imply the whole requested size traded. IOC remainders do not rest.");
|
|
347
|
+
if (results.some((view) => view.commandStatus === "unknown"))
|
|
348
|
+
warnings.push("Unknown is not failure. Reconcile using get_order_request/get_order; never retry with a new request_id.");
|
|
349
|
+
return { operationId: request.id, requestId: request.requestKey, kind: request.kind, results, uncertain: results.some((view) => view.commandStatus === "unknown"), warnings };
|
|
350
|
+
}
|
|
351
|
+
async reconcile(request, signal) {
|
|
352
|
+
for (const action of await this.store.actions(request.id)) {
|
|
353
|
+
if (action.state === "prepared" || action.state === "not_sent")
|
|
354
|
+
continue;
|
|
355
|
+
const items = await this.store.items(action.id);
|
|
356
|
+
const views = [];
|
|
357
|
+
for (const item of items) {
|
|
358
|
+
const view = JSON.parse(item.view);
|
|
359
|
+
if (!active(view)) {
|
|
360
|
+
views.push(view);
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
const oid = view.exchangeOid ? exchangeOid(view.exchangeOid) : view.cloid;
|
|
365
|
+
if (!oid) {
|
|
366
|
+
views.push(view);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
views.push(reconciledView(view, await this.info.orderStatus({ user: request.account, oid }, signal)));
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
views.push({ ...view, updatedAt: Date.now(), error: "Order reconciliation unavailable; previous state retained." });
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
await this.store.outcome(action.id, views.some((view) => view.commandStatus === "unknown") ? "unknown" : "done", views, "reconciliation");
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
request(userId, agentId, key, cancellation) {
|
|
379
|
+
this.admit();
|
|
380
|
+
this.requestKey(key);
|
|
381
|
+
return this.trackAgent(agentId, async () => {
|
|
382
|
+
const account = await this.account(userId, agentId);
|
|
383
|
+
const request = await this.store.request(agentId, key);
|
|
384
|
+
if (!request || request.account !== account)
|
|
385
|
+
throw new HyperliquidError("Order request not found", 404);
|
|
386
|
+
return this.lock(request.id, async () => { await this.reconcile(request, this.signal(cancellation)); return this.result(request); });
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
list(userId, agentId, input, cancellation) {
|
|
390
|
+
this.admit();
|
|
391
|
+
return this.track((async () => {
|
|
392
|
+
const account = await this.account(userId, agentId);
|
|
393
|
+
const source = input.source ?? "open", limit = input.limit ?? 50, offset = input.offset ?? 0;
|
|
394
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100 || !Number.isInteger(offset) || offset < 0 || offset > 100000)
|
|
395
|
+
throw new HyperliquidError("Invalid pagination.");
|
|
396
|
+
let items;
|
|
397
|
+
if (source === "local") {
|
|
398
|
+
items = (await this.store.local(agentId, account)).map(({ view }) => JSON.parse(view));
|
|
399
|
+
}
|
|
400
|
+
else if (source === "open")
|
|
401
|
+
items = (await this.info.frontendOpenOrders({ user: account, dex: "" }, this.signal(cancellation))).filter((order) => isPerpetual(order.coin)).map((order) => liveView(order));
|
|
402
|
+
else
|
|
403
|
+
throw new HyperliquidError("Invalid order source.");
|
|
404
|
+
items = items.filter((item) => (!input.symbol || item.symbol === input.symbol) && (!input.status || item.orderStatus === input.status));
|
|
405
|
+
return { items: items.slice(offset, offset + limit), nextOffset: offset + limit < items.length ? offset + limit : null, source, observedAt: Date.now(),
|
|
406
|
+
coverage: source === "open" ? "Current main-DEX perpetual open orders, including externally placed orders. Pagination is over a changing live snapshot." : "Locally recorded submissions from the latest 500 requests only; not full exchange history. States may lag; get_order refreshes a selected order." };
|
|
407
|
+
})());
|
|
408
|
+
}
|
|
409
|
+
get(userId, agentId, id, includeEvents = false, cancellation) {
|
|
410
|
+
this.admit();
|
|
411
|
+
return this.trackAgent(agentId, async () => {
|
|
412
|
+
const account = await this.account(userId, agentId);
|
|
413
|
+
const found = await this.store.find(agentId, account, id);
|
|
414
|
+
if (found && found.request.account !== account)
|
|
415
|
+
throw new HyperliquidError("Order not found", 404);
|
|
416
|
+
if (found) {
|
|
417
|
+
return this.lock(found.request.id, async () => {
|
|
418
|
+
await this.reconcile(found.request, this.signal(cancellation));
|
|
419
|
+
const updated = await this.store.find(agentId, account, found.item.id);
|
|
420
|
+
return { order: updated ? JSON.parse(updated.item.view) : null, events: includeEvents ? await this.store.events(found.item.id) : [], error: null, observedAt: Date.now() };
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
const oid = /^0x[0-9a-fA-F]{32}$/.test(id) ? id : exchangeOid(id);
|
|
424
|
+
const response = await this.info.orderStatus({ user: account, oid }, this.signal(cancellation));
|
|
425
|
+
if (response.status !== "order")
|
|
426
|
+
return { order: null, events: [], error: "Order not found; absence is not proof of rejection, fill, or cancellation.", observedAt: Date.now() };
|
|
427
|
+
if (!isPerpetual(response.order.order.coin))
|
|
428
|
+
throw new HyperliquidError("Only main-DEX perpetual orders are supported.");
|
|
429
|
+
return { order: liveView(response.order.order, response.order.status, response.order.statusTimestamp), events: [], error: null, observedAt: Date.now() };
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { and, asc, desc, eq, inArray, or } from "drizzle-orm";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { assertAgentExecutable } from "../../agents/agent-enablement.js";
|
|
4
|
+
import { hvExchangeNonces, hvOrderActions, hvOrderEvents, hvOrderItems, hvOrderRequests } from "../../db/order-schema.js";
|
|
5
|
+
import { applicationDatabase } from "../../db/shared-database.js";
|
|
6
|
+
import { HyperliquidError } from "../errors.js";
|
|
7
|
+
import { canonical } from "../../canonical.js";
|
|
8
|
+
import { hvOrderRequestProvenance } from "../../db/order-provenance-schema.js";
|
|
9
|
+
import { assertActiveActor } from "../../memory/operations.js";
|
|
10
|
+
export { canonical } from "../../canonical.js";
|
|
11
|
+
export function active(view) {
|
|
12
|
+
return view.commandStatus === "unknown" || ["open", "waitingForFill", "waitingForTrigger", "triggered"].includes(view.orderStatus);
|
|
13
|
+
}
|
|
14
|
+
export class OrderStore {
|
|
15
|
+
database;
|
|
16
|
+
notifications;
|
|
17
|
+
db;
|
|
18
|
+
constructor(database) {
|
|
19
|
+
this.database = database;
|
|
20
|
+
this.db = applicationDatabase(database);
|
|
21
|
+
}
|
|
22
|
+
request(agentId, key) { return this.db.select().from(hvOrderRequests).where(and(eq(hvOrderRequests.agentId, agentId), eq(hvOrderRequests.requestKey, key))).get(); }
|
|
23
|
+
actions(id) { return this.db.select().from(hvOrderActions).where(eq(hvOrderActions.requestId, id)).orderBy(asc(hvOrderActions.ordinal)).all(); }
|
|
24
|
+
items(actionId) { return this.db.select().from(hvOrderItems).where(eq(hvOrderItems.actionId, actionId)).orderBy(asc(hvOrderItems.ordinal)).all(); }
|
|
25
|
+
async allItems(requestId) { return (await Promise.all((await this.actions(requestId)).map((action) => this.items(action.id)))).flat(); }
|
|
26
|
+
async prepare(agentId, account, key, kind, input, actions, origin) {
|
|
27
|
+
return this.database.appTransaction(async (db, tx) => {
|
|
28
|
+
const existing = await db.select().from(hvOrderRequests).where(and(eq(hvOrderRequests.agentId, agentId), eq(hvOrderRequests.requestKey, key))).get();
|
|
29
|
+
if (existing) {
|
|
30
|
+
this.matches(existing, account, kind, input);
|
|
31
|
+
return existing;
|
|
32
|
+
}
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
const row = { id: randomUUID(), agentId, account, requestKey: key, kind, input: canonical(input), createdAt: now };
|
|
35
|
+
await db.insert(hvOrderRequests).values(row).run();
|
|
36
|
+
if (origin) {
|
|
37
|
+
if (origin.agentId !== agentId || !origin.subagentId || origin.conversationId === null || origin.toolTaskId === null)
|
|
38
|
+
throw new HyperliquidError("Invalid execution provenance", 403);
|
|
39
|
+
await assertActiveActor(tx, origin);
|
|
40
|
+
await db.insert(hvOrderRequestProvenance).values({ requestId: row.id, agentId, producerSubagentId: origin.subagentId, sourceRunId: origin.runId, conversationId: origin.conversationId, toolTaskId: origin.toolTaskId }).run();
|
|
41
|
+
}
|
|
42
|
+
for (const [ordinal, action] of actions.entries()) {
|
|
43
|
+
const actionId = randomUUID();
|
|
44
|
+
await db.insert(hvOrderActions).values({ id: actionId, requestId: row.id, ordinal, payload: JSON.stringify(action.payload), state: "prepared", expiresAt: now + 60_000, updatedAt: now }).run();
|
|
45
|
+
for (const [index, view] of action.items.entries()) {
|
|
46
|
+
await db.insert(hvOrderItems).values({ id: view.id, actionId, ordinal: index, symbol: view.symbol, cloid: view.cloid, oid: view.exchangeOid, active: 0, view: JSON.stringify(view), updatedAt: now }).run();
|
|
47
|
+
await db.insert(hvOrderEvents).values({ itemId: view.id, source: "intent", time: now, data: JSON.stringify(view) }).run();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return row;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
matches(row, account, kind, input) {
|
|
54
|
+
if (row.account !== account || row.kind !== kind || row.input !== canonical(input))
|
|
55
|
+
throw new HyperliquidError("This request_id was already used with different arguments or an account assignment.", 409);
|
|
56
|
+
}
|
|
57
|
+
async begin(action, modelAgentId) {
|
|
58
|
+
return this.database.appTransaction(async (db, tx) => {
|
|
59
|
+
if (modelAgentId)
|
|
60
|
+
await assertAgentExecutable(tx, modelAgentId);
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
const rows = await db.update(hvOrderActions).set({ state: "submitting", updatedAt: now })
|
|
63
|
+
.where(and(eq(hvOrderActions.id, action.id), eq(hvOrderActions.state, "prepared"))).returning().all();
|
|
64
|
+
if (!rows.length)
|
|
65
|
+
return false;
|
|
66
|
+
for (const item of await db.select().from(hvOrderItems).where(eq(hvOrderItems.actionId, action.id)).all()) {
|
|
67
|
+
const view = { ...JSON.parse(item.view), commandStatus: "unknown", orderStatus: "unknown", updatedAt: now, error: "Submission started; venue outcome not yet committed." };
|
|
68
|
+
await db.update(hvOrderItems).set({ active: 1, view: JSON.stringify(view), updatedAt: now }).where(eq(hvOrderItems.id, item.id)).run();
|
|
69
|
+
await db.insert(hvOrderEvents).values({ itemId: item.id, source: "submission_intent", time: now, data: JSON.stringify(view) }).run();
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async hasUncertain(account) {
|
|
75
|
+
const row = await this.db.select({ id: hvOrderActions.id }).from(hvOrderActions).innerJoin(hvOrderRequests, eq(hvOrderRequests.id, hvOrderActions.requestId))
|
|
76
|
+
.where(and(eq(hvOrderRequests.account, account), or(eq(hvOrderActions.state, "unknown"), eq(hvOrderActions.state, "submitting")))).get();
|
|
77
|
+
return Boolean(row);
|
|
78
|
+
}
|
|
79
|
+
async outcome(actionId, state, views, source) {
|
|
80
|
+
const agentId = await this.database.appTransaction(async (db, tx) => {
|
|
81
|
+
await db.update(hvOrderActions).set({ state, updatedAt: Date.now() }).where(eq(hvOrderActions.id, actionId)).run();
|
|
82
|
+
for (const view of views) {
|
|
83
|
+
const previous = await db.select().from(hvOrderItems).where(eq(hvOrderItems.id, view.id)).get();
|
|
84
|
+
if (!previous || previous.actionId !== actionId)
|
|
85
|
+
throw new Error("Order item identity changed");
|
|
86
|
+
const old = JSON.parse(previous.view);
|
|
87
|
+
await db.update(hvOrderItems).set({ oid: view.exchangeOid, view: JSON.stringify(view), active: active(view) ? 1 : 0, updatedAt: view.updatedAt }).where(eq(hvOrderItems.id, view.id)).run();
|
|
88
|
+
// Polling timestamps do not produce an unbounded event log of identical states.
|
|
89
|
+
const comparable = (v) => ({ ...v, updatedAt: 0, source: "", venueTimestamp: null });
|
|
90
|
+
if (canonical(comparable(old)) !== canonical(comparable(view)))
|
|
91
|
+
await db.insert(hvOrderEvents).values({ itemId: view.id, source, time: Date.now(), data: JSON.stringify(view) }).run();
|
|
92
|
+
}
|
|
93
|
+
return this.notifications?.orderOutcomeTx(tx, actionId);
|
|
94
|
+
});
|
|
95
|
+
if (agentId)
|
|
96
|
+
this.notifications?.changed(agentId);
|
|
97
|
+
}
|
|
98
|
+
async nonce(signer, actionId) {
|
|
99
|
+
return this.database.appTransaction(async (db) => {
|
|
100
|
+
signer = signer.toLowerCase();
|
|
101
|
+
const previous = await db.select().from(hvExchangeNonces).where(eq(hvExchangeNonces.signer, signer)).get();
|
|
102
|
+
const nonce = Math.max(Date.now(), (previous?.nonce ?? 0) + 1);
|
|
103
|
+
await db.insert(hvExchangeNonces).values({ signer, nonce }).onConflictDoUpdate({ target: hvExchangeNonces.signer, set: { nonce } }).run();
|
|
104
|
+
if (actionId)
|
|
105
|
+
await db.update(hvOrderActions).set({ nonce }).where(eq(hvOrderActions.id, actionId)).run();
|
|
106
|
+
return nonce;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async recover() {
|
|
110
|
+
for (const action of await this.db.select().from(hvOrderActions).where(eq(hvOrderActions.state, "submitting")).all()) {
|
|
111
|
+
const views = (await this.items(action.id)).map(({ view }) => ({ ...JSON.parse(view), commandStatus: "unknown", orderStatus: "unknown", source: "restart", updatedAt: Date.now(), error: "Process stopped during submission. Reconciliation required; do not resubmit." }));
|
|
112
|
+
await this.outcome(action.id, "unknown", views, "restart");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async pendingRequests(limit = 20) {
|
|
116
|
+
const rows = await this.db.select({ request: hvOrderRequests }).from(hvOrderRequests)
|
|
117
|
+
.innerJoin(hvOrderActions, eq(hvOrderActions.requestId, hvOrderRequests.id))
|
|
118
|
+
.innerJoin(hvOrderItems, eq(hvOrderItems.actionId, hvOrderActions.id))
|
|
119
|
+
.where(eq(hvOrderItems.active, 1)).orderBy(asc(hvOrderItems.updatedAt)).limit(limit).all();
|
|
120
|
+
return [...new Map(rows.map(({ request }) => [request.id, request])).values()];
|
|
121
|
+
}
|
|
122
|
+
async local(agentId, account) {
|
|
123
|
+
// Bounded local history scan. Live open orders are queried separately.
|
|
124
|
+
const requests = await this.db.select().from(hvOrderRequests).where(and(eq(hvOrderRequests.agentId, agentId), eq(hvOrderRequests.account, account), inArray(hvOrderRequests.kind, ["submit", "close_position"]))).orderBy(desc(hvOrderRequests.createdAt)).limit(500).all();
|
|
125
|
+
return (await Promise.all(requests.map((request) => this.allItems(request.id)))).flat();
|
|
126
|
+
}
|
|
127
|
+
async find(agentId, account, id) {
|
|
128
|
+
const rows = await this.db.select({ item: hvOrderItems, request: hvOrderRequests }).from(hvOrderItems)
|
|
129
|
+
.innerJoin(hvOrderActions, eq(hvOrderActions.id, hvOrderItems.actionId)).innerJoin(hvOrderRequests, eq(hvOrderRequests.id, hvOrderActions.requestId))
|
|
130
|
+
.where(and(eq(hvOrderRequests.agentId, agentId), eq(hvOrderRequests.account, account), or(eq(hvOrderItems.id, id), eq(hvOrderItems.cloid, id), eq(hvOrderItems.oid, id)))).orderBy(desc(hvOrderRequests.createdAt)).get();
|
|
131
|
+
return rows;
|
|
132
|
+
}
|
|
133
|
+
events(id) { return this.db.select({ id: hvOrderEvents.id, source: hvOrderEvents.source, time: hvOrderEvents.time, data: hvOrderEvents.data }).from(hvOrderEvents).where(eq(hvOrderEvents.itemId, id)).orderBy(desc(hvOrderEvents.id)).limit(100).all(); }
|
|
134
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
2
|
+
import { defineTool } from "@earendil-works/pi-durable";
|
|
3
|
+
import { OrderInputSchema, OrderSize, OrderPrice, Decimal, CancelAllSchema, CancelSchema, GetResultSchema, GetSchema, ListResultSchema, ListSchema, OperationSchema, RequestId, SubmitSchema } from "./order-contracts.js";
|
|
4
|
+
import { assertStringAmounts } from "./order-prepare.js";
|
|
5
|
+
import { assertEntryStyle } from "./trade-planning.js";
|
|
6
|
+
/** Both model and nested/code-mode callers get the same typed, bounded value. */
|
|
7
|
+
export function toolResult(value) {
|
|
8
|
+
return { output: [{ type: "text", text: JSON.stringify(value) }], structuredOutput: value };
|
|
9
|
+
}
|
|
10
|
+
export function createOrderTools(service, userId, agentId) {
|
|
11
|
+
return [
|
|
12
|
+
defineTool({ name: "prepare_protected_entry", description: "Read-only exact protected-entry planner for your own size and TP/SL levels, using a current string-valued quote and exchange precision. Read list_instruments size/price rules before calculating amounts. entry_style must be \"guarded_ioc\" (market-like entry with a 0.5% guarded IOC limit; omit limit_price) or \"limit\" (GTC with an explicit limit_price), never \"market\". Returns a short-lived draft of submit_orders.orders, NOT authority, an order, or confirmation that trading is enabled. TP/SL must be explicit prices on the correct side of the entry. Sizing and protection levels are your strategy decisions within this Agent's risk settings; never silently increase size to meet the venue minimum.", parameters: Type.Object({ instrument: Type.String({ maxLength: 32 }), side: Type.Union([Type.Literal("buy"), Type.Literal("sell")]), entry_style: Type.Union([Type.Literal("guarded_ioc"), Type.Literal("limit")], { description: 'Exactly "guarded_ioc" (market-like, 0.5% guarded IOC; omit limit_price) or "limit" (GTC; require limit_price). "market" is NOT a valid planner entry_style.' }), size: OrderSize, limit_price: Type.Optional(OrderPrice), take_profit_price: OrderPrice, stop_loss_price: OrderPrice }, { additionalProperties: false }), structuredOutputSchema: Type.Object({ orders: Type.Array(OrderInputSchema, { maxItems: 1 }), quote: Decimal, quoteSource: Type.String(), observedAt: Type.Integer(), validUntil: Type.Integer(), calculationBasis: Type.String(), warning: Type.String() }), replay: "safe", prepareArguments(args) { assertStringAmounts(args); assertEntryStyle(args && typeof args === "object" ? Reflect.get(args, "entry_style") : undefined); return args; }, execute: async (args, api, context) => toolResult(await service.plan(userId, agentId, args, await service.executionHandle(agentId, api, context), context.abortSignal)) }),
|
|
13
|
+
defineTool({ name: "prepare_position_protection", description: "Read-only repair planner for an ACTUAL current position, including partial/external exposure. Derives signed size and closing side from this account; you supply explicit exact TP and SL trigger prices on the correct side of the market. No entry, authority or mutation. Inspect get_protection_status first and submit ONLY missing appropriate legs; never duplicate/cancel known live protection blindly. Crossed/unknown levels require review, not automatic flattening.", parameters: Type.Object({ instrument: Type.String({ maxLength: 32 }), take_profit_price: OrderPrice, stop_loss_price: OrderPrice }, { additionalProperties: false }), structuredOutputSchema: Type.Object({ orders: Type.Array(OrderInputSchema, { maxItems: 2 }), quote: Decimal, quoteSource: Type.String(), observedAt: Type.Integer(), validUntil: Type.Integer(), calculationBasis: Type.String(), warning: Type.String() }), replay: "safe", prepareArguments(args) { assertStringAmounts(args); return args; }, execute: async (args, api, context) => toolResult(await service.planProtection(userId, agentId, args, await service.executionHandle(agentId, api, context), context.abortSignal)) }),
|
|
14
|
+
defineTool({ name: "get_protection_status", description: "Inspect current main-DEX positions and top-level reduce-only TP/SL triggers with individual venue statuses. waitingForFill/native children do not count as active partial-position protection. Snapshot only, no continuous guarantee; missing coverage calls for deliberate repair, not blind duplicate orders, cancel-all or unapproved flattening.", parameters: Type.Object({}, { additionalProperties: false }), structuredOutputSchema: Type.Object({ observedAt: Type.Integer(), positions: Type.Array(Type.Object({ instrument: Type.String(), side: Type.String(), size: Decimal, takeProfitOids: Type.Array(Type.String()), stopLossOids: Type.Array(Type.String()), covered: Type.Boolean(), warning: Type.String() }), { maxItems: 100 }), warning: Type.String() }), replay: "safe", execute: async (_args, _api, context) => toolResult(await service.protection(userId, agentId, context.abortSignal)) }),
|
|
15
|
+
defineTool({ name: "submit_orders", description: "Place real main-DEX perpetual orders on this Agent's assigned account. The only host-enforced rules are this Agent's risk settings (trading enabled, allowed instruments, order/total notional caps); strategy, protection and sizing are yours within them. Always pair new entries with TP and SL protection (attached native TP/SL, or standalone reduce-only triggers). A direct/manual operator request does not require consulting memories or creating a decision publication; omit decision_ref when no decision memory actually motivates the order. For memory-based decisions, record_trade_decision and decision_ref are optional rationale/audit aids, never execution prerequisites or authority. Do not attach unrelated or previously blocked/skipped decisions merely to populate decision_ref. Host-recorded Agent/worker provenance does not depend on a memory ref. Exact decimal-string size/prices; size is base-asset quantity. Read list_instruments sizeDecimals/sizeStep and price precision rules before calculating amounts. Hyperliquid main-DEX perps have a $10 minimum order notional (size × price), plus symbol-specific size/tick precision. Do not silently increase size to meet the minimum or bypass reduce-only constraints; report exchange rejections/exceptions. Limit GTC/IOC/ALO, market entries (0.5% guarded IOC), attached native TP/SL (one each), and standalone reduce-only TP/SL. Attached SL is market-on-trigger; triggers without a limit use a 10% guard. Persisted request_id deduplicates retries; never use a new ID to retry unknown outcomes. Inspect every result/leg; accepted does not mean filled or protected.",
|
|
16
|
+
parameters: SubmitSchema, structuredOutputSchema: OperationSchema, replay: "safe", executionMode: "sequential",
|
|
17
|
+
prepareArguments(args) { assertStringAmounts(args); return args; },
|
|
18
|
+
execute: async (args, api, context) => toolResult(await service.submit(userId, agentId, args, context.abortSignal, await service.executionHandle(agentId, api, context))), }),
|
|
19
|
+
defineTool({ name: "cancel_orders", description: "Cancel explicit exchange OIDs on this Agent's own main-DEX perpetual account. Each item requires symbol and oid (decimal string). May remove protective TP/SL; does not close positions. Use the same request_id for retries; inspect per-item results and unknown outcomes.",
|
|
20
|
+
parameters: CancelSchema, structuredOutputSchema: OperationSchema, replay: "safe", executionMode: "sequential",
|
|
21
|
+
prepareArguments(args) { assertStringAmounts(args); return args; },
|
|
22
|
+
execute: async (args, api, context) => toolResult(await service.cancel(userId, agentId, args, context.abortSignal, await service.executionHandle(agentId, api, context))), }),
|
|
23
|
+
defineTool({ name: "cancel_all_orders", description: "Cancel one captured set of current main-DEX perpetual orders, optionally for one symbol. Includes protective stops/TP; does not close positions. Replaying the same request_id never captures newly created orders. Maximum 100 targets; use explicit batches beyond that.",
|
|
24
|
+
parameters: CancelAllSchema, structuredOutputSchema: OperationSchema, replay: "safe", executionMode: "sequential",
|
|
25
|
+
execute: async (args, api, context) => toolResult(await service.cancelAll(userId, agentId, args, context.abortSignal, await service.executionHandle(agentId, api, context))),
|
|
26
|
+
}),
|
|
27
|
+
defineTool({ name: "list_orders", description: "List this Agent's main-DEX perpetual orders. source=open (default) reads live exchange orders, including external orders. source=local reads the latest 500 recorded submission requests, not full exchange history; states can lag. Optional symbol/status and bounded limit/offset. Use get_order for fresh status of a selected local order.",
|
|
28
|
+
parameters: ListSchema, structuredOutputSchema: ListResultSchema, replay: "safe",
|
|
29
|
+
execute: async (args, _api, context) => toolResult(await service.list(userId, agentId, args, context.abortSignal)),
|
|
30
|
+
}),
|
|
31
|
+
defineTool({ name: "get_order", description: "Query this Agent's main-DEX perpetual order by local ID, decimal-string exchange OID, or 128-bit hex CLOID. Reconciles local requests before returning. Optional include_events returns up to 100 latest local events, newest first. Not-found does not prove rejection, fill, or cancellation.",
|
|
32
|
+
parameters: GetSchema, structuredOutputSchema: GetResultSchema, replay: "safe",
|
|
33
|
+
execute: async (args, _api, context) => toolResult(await service.get(userId, agentId, args.order_id, args.include_events, context.abortSignal)),
|
|
34
|
+
}),
|
|
35
|
+
defineTool({ name: "get_order_request", description: "Read and reconcile one existing exchange submit/cancel request, including per-leg outcomes and uncertainty. Supply the original request_id used with submit_orders, cancel_orders or cancel_all_orders (returned as requestId in their results or local list_orders items). Worker inbox request IDs, assignment/run IDs and exchange order OIDs are NOT order request IDs. To discover local submissions, use list_orders with source=local; do not guess an ID or query this tool just because an assignment contains a request ID. Never sends/retries exchange actions. Use after timeouts/restarts instead of issuing a new request_id. Not-found does not prove rejection, cancellation or absence of exchange orders.",
|
|
36
|
+
parameters: Type.Object({ request_id: { ...RequestId, description: "Original request_id of a submit_orders, cancel_orders or cancel_all_orders call; returned as requestId. Never a worker inbox request ID, assignment/run ID or exchange order OID." } }, { additionalProperties: false }), structuredOutputSchema: OperationSchema, replay: "safe",
|
|
37
|
+
execute: async (args, _api, context) => toolResult(await service.request(userId, agentId, args.request_id, context.abortSignal)),
|
|
38
|
+
}),
|
|
39
|
+
];
|
|
40
|
+
}
|