hypervibes 0.0.0-stage → 0.4.0-beta
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-Cv9zLaQf.js +1 -0
- package/.build/client/assets/_authenticated.account-BUQIEX6U.js +1 -0
- package/.build/client/assets/_authenticated.agents-dJY4sHg9.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId-M6WEcZ08.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.chart-C7d7IrdC.js +4 -0
- package/.build/client/assets/_authenticated.agents._agentId.chat-ByZuIqSb.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.index-BWIZd3vd.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.indicators-CjCgrxqH.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.indicators_._indicatorId-B45wotiz.js +2 -0
- package/.build/client/assets/_authenticated.agents._agentId.indicators_._indicatorId-Beoq1vKK.js +6 -0
- package/.build/client/assets/_authenticated.agents._agentId.memories-BmofNWcJ.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.memories_._memoryRef-CGnpq7sv.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.notifications-Z1TVoGbh.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.notifications_._notificationId-BU2I1Fui.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.settings-CUai-n8m.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.sub-agents-dJY4sHg9.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.sub-agents._subagentId-CEYRqW8Q.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.sub-agents._subagentId_.runs._runId-Cr7yrAJz.js +3 -0
- package/.build/client/assets/_authenticated.agents._agentId.sub-agents.index-xTEjRPdW.js +1 -0
- package/.build/client/assets/_authenticated.agents._agentId.sub-agents.new-B9ZR8zIn.js +37 -0
- package/.build/client/assets/_authenticated.agents._agentId.transactions-a1xzSbFO.js +1 -0
- package/.build/client/assets/_authenticated.agents.index-CEqeDEgP.js +1 -0
- package/.build/client/assets/_authenticated.agents.new-COOjMCtg.js +1 -0
- package/.build/client/assets/_authenticated.providers-8wsMG9f-.js +1 -0
- package/.build/client/assets/agent-chat-page-vKrkXdzr.js +1 -0
- package/.build/client/assets/agent-enablement-control-BMJ6jULr.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-DcRTuyby.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-fu66g8fn.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-Dni_73Pp.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-BAHfxLOo.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-CpYyLRfb.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 +147 -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 +1002 -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 +97 -0
- package/dist/agents/subagent-dashboard.js +1 -0
- package/dist/agents/subagent-extension.js +155 -0
- package/dist/agents/subagent-history.js +5 -0
- package/dist/agents/subagent-input.js +73 -0
- package/dist/agents/subagent-service.js +1176 -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/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 +76 -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 +33 -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 +91 -4
- 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,117 @@
|
|
|
1
|
+
import { HttpTransport, InfoClient } from "@nktkas/hyperliquid";
|
|
2
|
+
import { compareDecimals, parseDecimal } from "./decimal.js";
|
|
3
|
+
export function accountModeMessage(mode) {
|
|
4
|
+
switch (mode) {
|
|
5
|
+
case "unified": return "";
|
|
6
|
+
case "unregistered":
|
|
7
|
+
return "This wallet is not registered with Hyperliquid yet. Register it before setting up a trading signer, approving a builder fee, transferring funds, or creating agents.";
|
|
8
|
+
case "unsupported":
|
|
9
|
+
return "HyperVibes currently supports Unified Accounts only. Enable Unified Account in Hyperliquid before transferring or creating agents.";
|
|
10
|
+
case "unavailable":
|
|
11
|
+
return "Hyperliquid account mode could not be verified. Transfers are temporarily unavailable.";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function accountModeError(mode) {
|
|
15
|
+
return mode === "unified" ? null : accountModeMessage(mode);
|
|
16
|
+
}
|
|
17
|
+
function usdcBalance(balances) {
|
|
18
|
+
const balance = balances.find((entry) => entry.coin.toLowerCase() === "usdc");
|
|
19
|
+
// A registered account simply not holding USDC is zero, not unavailable.
|
|
20
|
+
if (!balance)
|
|
21
|
+
return "0";
|
|
22
|
+
if (typeof balance.total !== "string")
|
|
23
|
+
return null;
|
|
24
|
+
const value = parseDecimal(balance.total);
|
|
25
|
+
if (!value || value.negative)
|
|
26
|
+
return null;
|
|
27
|
+
return balance.total;
|
|
28
|
+
}
|
|
29
|
+
/** Sub-account capacity follows Hyperliquid's volume-based schedule, capped at 50. */
|
|
30
|
+
function subaccountCapacity(cumulativeVolume, existing) {
|
|
31
|
+
const comparison = compareDecimals(cumulativeVolume, "100000");
|
|
32
|
+
if (comparison === null)
|
|
33
|
+
return null;
|
|
34
|
+
if (comparison < 0)
|
|
35
|
+
return "0 remaining of 0 total";
|
|
36
|
+
// One additional account per $100M of volume above the first $100k.
|
|
37
|
+
const additional = wholeQuotientMinus(cumulativeVolume);
|
|
38
|
+
const limit = Math.min(10 + additional, 50);
|
|
39
|
+
const remaining = Math.max(limit - existing, 0);
|
|
40
|
+
return `${remaining} remaining of ${limit} total`;
|
|
41
|
+
}
|
|
42
|
+
function wholeQuotientMinus(volume) {
|
|
43
|
+
const separator = volume.indexOf(".");
|
|
44
|
+
const whole = separator === -1 ? volume : volume.slice(0, separator);
|
|
45
|
+
const base = BigInt(whole) - 100000n;
|
|
46
|
+
if (base < 0n)
|
|
47
|
+
return 0;
|
|
48
|
+
return Number(base / 100000000n);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Loads the wallet's main account and owned sub-accounts with their spot USDC
|
|
52
|
+
* balances, mirroring the legacy application's unified-account checks.
|
|
53
|
+
*/
|
|
54
|
+
export async function loadOwnedTradingAccounts(transport, walletAddress, options = {}) {
|
|
55
|
+
const mainAddress = walletAddress.toLowerCase();
|
|
56
|
+
const info = new InfoClient({ transport });
|
|
57
|
+
const checkMode = options.checkMode ?? true;
|
|
58
|
+
const [spotState, subaccountsResult, userRole, abstraction] = await Promise.all([
|
|
59
|
+
info.spotClearinghouseState({ user: mainAddress }).then((state) => ({ ok: true, state }), (error) => ({ ok: false, error })),
|
|
60
|
+
info.subAccounts({ user: mainAddress }).then((accounts) => ({ ok: true, accounts }), (error) => ({ ok: false, error })),
|
|
61
|
+
checkMode
|
|
62
|
+
? info.userRole({ user: mainAddress }).then((role) => ({ ok: true, role }), (error) => ({ ok: false, error }))
|
|
63
|
+
: Promise.resolve({ ok: true, role: { role: "user" } }),
|
|
64
|
+
checkMode
|
|
65
|
+
? info.userAbstraction({ user: mainAddress }).then((mode) => ({ ok: true, mode }), (error) => ({ ok: false, error }))
|
|
66
|
+
: Promise.resolve({ ok: true, mode: "unifiedAccount" }),
|
|
67
|
+
]);
|
|
68
|
+
const mainBalance = spotState.ok ? usdcBalance(spotState.state.balances) : null;
|
|
69
|
+
const accountMode = userRole.ok && userRole.role.role === "missing"
|
|
70
|
+
? "unregistered"
|
|
71
|
+
: abstraction.ok && abstraction.mode === "unifiedAccount"
|
|
72
|
+
? "unified"
|
|
73
|
+
: abstraction.ok
|
|
74
|
+
? "unsupported"
|
|
75
|
+
: "unavailable";
|
|
76
|
+
let subaccounts = [];
|
|
77
|
+
let subaccountLookupError = null;
|
|
78
|
+
if (subaccountsResult.ok) {
|
|
79
|
+
subaccounts = (subaccountsResult.accounts ?? [])
|
|
80
|
+
.filter((account) => account.master.toLowerCase() === mainAddress)
|
|
81
|
+
.map((account) => ({
|
|
82
|
+
name: account.name || null,
|
|
83
|
+
address: account.subAccountUser.toLowerCase(),
|
|
84
|
+
// Hyperliquid omits spotState entirely for never-funded sub-accounts.
|
|
85
|
+
balance: usdcBalance(account.spotState?.balances ?? []),
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
subaccountLookupError = "Hyperliquid sub-account data is temporarily unavailable.";
|
|
90
|
+
}
|
|
91
|
+
const lookupError = accountMode === "unregistered"
|
|
92
|
+
? null
|
|
93
|
+
: spotState.ok || mainBalance !== null
|
|
94
|
+
? subaccountLookupError
|
|
95
|
+
: "Hyperliquid account data is temporarily unavailable.";
|
|
96
|
+
let subaccountCapacityText = null;
|
|
97
|
+
if (options.includeCapacity && accountMode === "unified") {
|
|
98
|
+
try {
|
|
99
|
+
const rateLimit = await info.userRateLimit({ user: mainAddress });
|
|
100
|
+
subaccountCapacityText = subaccountCapacity(rateLimit.cumVlm, subaccounts.length);
|
|
101
|
+
}
|
|
102
|
+
catch { /* Capacity is advisory; the page still renders without it. */ }
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
mainAddress,
|
|
106
|
+
mainBalance,
|
|
107
|
+
subaccounts,
|
|
108
|
+
subaccountCapacity: subaccountCapacityText,
|
|
109
|
+
lookupError,
|
|
110
|
+
accountMode,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** Looks up the current builder-fee maximum for a user, in tenths of a bp. */
|
|
114
|
+
export async function maxBuilderFee(transport, user, builder, signal) {
|
|
115
|
+
const info = new InfoClient({ transport });
|
|
116
|
+
return info.maxBuilderFee({ user: user, builder: builder }, signal);
|
|
117
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { InfoClient } from "@nktkas/hyperliquid";
|
|
2
|
+
import { dashboardOrders, dashboardPerps, dashboardSpot } from "./agent-dashboard.js";
|
|
3
|
+
function perpetualOrder(coin) { return !coin.startsWith("@") && !coin.includes("/"); }
|
|
4
|
+
/** A bounded-age read of the shared feed, repaired without modifying its state. */
|
|
5
|
+
export async function loadAccountStatus(transport, address, cached, cancellation) {
|
|
6
|
+
const now = Date.now();
|
|
7
|
+
const result = {
|
|
8
|
+
address, scope: "main-dex-perpetuals-and-spot-usdc", observedAt: now, accountAbstraction: null,
|
|
9
|
+
perpEquity: cached?.perpEquity ?? null, positions: cached?.positions ?? null,
|
|
10
|
+
spotUsdc: cached?.spotUsdc ?? null, spotUsdcHold: cached?.spotUsdcHold ?? null,
|
|
11
|
+
orders: cached?.orders?.filter((order) => perpetualOrder(order.coin)) ?? null,
|
|
12
|
+
sections: {
|
|
13
|
+
perps: { updatedAt: null, fresh: false, source: "unavailable" },
|
|
14
|
+
spot: { updatedAt: null, fresh: false, source: "unavailable" },
|
|
15
|
+
orders: { updatedAt: null, fresh: false, source: "unavailable" },
|
|
16
|
+
mode: { updatedAt: null, fresh: false, source: "unavailable" },
|
|
17
|
+
}, errors: [],
|
|
18
|
+
};
|
|
19
|
+
if (!address) {
|
|
20
|
+
result.errors.push("No trading account is assigned to this Agent.");
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
for (const section of ["perps", "spot", "orders"]) {
|
|
24
|
+
const state = cached?.live?.sections[section];
|
|
25
|
+
if (state?.updatedAt !== null && state?.updatedAt !== undefined) {
|
|
26
|
+
const complete = section === "perps" ? result.perpEquity !== null && result.positions !== null
|
|
27
|
+
: section === "spot" ? result.spotUsdc !== null && result.spotUsdcHold !== null : result.orders !== null;
|
|
28
|
+
result.sections[section] = { updatedAt: state.updatedAt, fresh: complete && state.fresh && cached?.live?.status === "connected" && now - state.updatedAt <= 30_000, source: "live" };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const client = new InfoClient({ transport });
|
|
32
|
+
const user = address;
|
|
33
|
+
const signal = AbortSignal.any([AbortSignal.timeout(8_000), ...(cancellation ? [cancellation] : [])]);
|
|
34
|
+
const errors = {
|
|
35
|
+
perps: "Perpetual balances and positions are unavailable; any retained values are stale.",
|
|
36
|
+
spot: "Spot USDC balance and holds are unavailable; any retained values are stale.",
|
|
37
|
+
orders: "Open perpetual orders are unavailable; any retained values are stale.",
|
|
38
|
+
mode: "Account mode is unavailable. Do not infer collateral availability from balances or the raw perp summary.",
|
|
39
|
+
};
|
|
40
|
+
await Promise.all(["perps", "spot", "orders", "mode"].map(async (section) => {
|
|
41
|
+
if (result.sections[section].fresh)
|
|
42
|
+
return;
|
|
43
|
+
try {
|
|
44
|
+
if (section === "perps")
|
|
45
|
+
Object.assign(result, dashboardPerps(await client.clearinghouseState({ user, dex: "" }, signal)));
|
|
46
|
+
else if (section === "spot")
|
|
47
|
+
Object.assign(result, dashboardSpot(await client.spotClearinghouseState({ user }, signal)));
|
|
48
|
+
else if (section === "mode")
|
|
49
|
+
result.accountAbstraction = await client.userAbstraction({ user }, signal);
|
|
50
|
+
else {
|
|
51
|
+
const orders = await client.frontendOpenOrders({ user, dex: "" }, signal);
|
|
52
|
+
result.orders = dashboardOrders(orders.filter((order) => perpetualOrder(order.coin))).orders;
|
|
53
|
+
}
|
|
54
|
+
result.sections[section] = { updatedAt: Date.now(), fresh: true, source: "http" };
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
if (cancellation?.aborted)
|
|
58
|
+
throw new Error("Account status request aborted");
|
|
59
|
+
result.errors.push(errors[section]);
|
|
60
|
+
}
|
|
61
|
+
}));
|
|
62
|
+
result.observedAt = Date.now();
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { InfoClient } from "@nktkas/hyperliquid";
|
|
2
|
+
import { compareDecimals } from "./decimal.js";
|
|
3
|
+
export function dashboardPerps(state) {
|
|
4
|
+
return {
|
|
5
|
+
perpEquity: state.marginSummary.accountValue,
|
|
6
|
+
positions: state.assetPositions.filter(({ position }) => {
|
|
7
|
+
const size = compareDecimals(position.szi, "0");
|
|
8
|
+
return size !== null && size !== 0;
|
|
9
|
+
}).map(({ position: p }) => ({ coin: p.coin, size: p.szi, entryPrice: p.entryPx, unrealizedPnl: p.unrealizedPnl, liquidationPrice: p.liquidationPx, leverage: p.leverage.value })),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function dashboardSpot(state) {
|
|
13
|
+
const usdc = state.balances.find((balance) => balance.coin === "USDC");
|
|
14
|
+
return { spotUsdc: usdc?.total ?? "0", spotUsdcHold: usdc ? usdc.hold ?? null : "0" };
|
|
15
|
+
}
|
|
16
|
+
export function dashboardOrders(orders) {
|
|
17
|
+
const convert = (order) => ({ id: order.oid, coin: order.coin, side: order.side === "B" ? "Buy" : "Sell", size: order.sz, price: order.limitPx, type: order.orderType,
|
|
18
|
+
...(Number.isFinite(order.timestamp) ? { timestamp: order.timestamp } : {}),
|
|
19
|
+
...(order.isTrigger ? { triggerPrice: order.triggerPx } : {}), ...(order.isPositionTpsl ? { positionTpsl: true } : {}),
|
|
20
|
+
...(order.children?.length ? { children: order.children.map(convert) } : {}), });
|
|
21
|
+
return { orders: orders.map(convert) };
|
|
22
|
+
}
|
|
23
|
+
/** Read-only main-DEX snapshots. No signer, persistence, or trading authority. */
|
|
24
|
+
export async function loadAgentDashboard(transport, address, cancellation) {
|
|
25
|
+
const result = { address, accountAbstraction: null, fetchedAt: Date.now(), perpEquity: null, spotUsdc: null, positions: null, orders: null, errors: [] };
|
|
26
|
+
if (!address)
|
|
27
|
+
return result;
|
|
28
|
+
const client = new InfoClient({ transport });
|
|
29
|
+
const user = address;
|
|
30
|
+
const signal = AbortSignal.any([AbortSignal.timeout(8_000), ...(cancellation ? [cancellation] : [])]);
|
|
31
|
+
const [perps, spot, orders, mode] = await Promise.allSettled([
|
|
32
|
+
client.clearinghouseState({ user }, signal),
|
|
33
|
+
client.spotClearinghouseState({ user }, signal),
|
|
34
|
+
client.frontendOpenOrders({ user }, signal),
|
|
35
|
+
client.userAbstraction({ user }, signal),
|
|
36
|
+
]);
|
|
37
|
+
if (perps.status === "fulfilled") {
|
|
38
|
+
Object.assign(result, dashboardPerps(perps.value));
|
|
39
|
+
}
|
|
40
|
+
else
|
|
41
|
+
result.errors.push("Perpetual balances and positions are temporarily unavailable.");
|
|
42
|
+
if (spot.status === "fulfilled")
|
|
43
|
+
Object.assign(result, dashboardSpot(spot.value));
|
|
44
|
+
else
|
|
45
|
+
result.errors.push("Spot USDC balance is temporarily unavailable.");
|
|
46
|
+
if (orders.status === "fulfilled")
|
|
47
|
+
Object.assign(result, dashboardOrders(orders.value));
|
|
48
|
+
else
|
|
49
|
+
result.errors.push("Open orders are temporarily unavailable.");
|
|
50
|
+
if (mode.status === "fulfilled")
|
|
51
|
+
result.accountAbstraction = mode.value;
|
|
52
|
+
else
|
|
53
|
+
result.errors.push("Account mode is temporarily unavailable; total equity cannot be determined.");
|
|
54
|
+
result.fetchedAt = Date.now();
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const chartIntervals = ["1m", "5m", "15m", "1h", "4h", "1d"];
|
|
2
|
+
export const intervalMillis = { "1m": 60_000, "5m": 300_000, "15m": 900_000, "1h": 3_600_000, "4h": 14_400_000, "1d": 86_400_000 };
|
|
3
|
+
export function isChartInterval(value) { return chartIntervals.some((interval) => interval === value); }
|
|
4
|
+
export function mergeChartCandles(previous, incoming) {
|
|
5
|
+
const values = new Map(previous.map((candle) => [candle.time, candle]));
|
|
6
|
+
for (const candle of incoming)
|
|
7
|
+
values.set(candle.time, candle);
|
|
8
|
+
return [...values.values()].sort((a, b) => a.time - b.time);
|
|
9
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Mainnet-only Hyperliquid constants shared by server code and templates. */
|
|
2
|
+
/** The only builder fee recipient the server accepts and submits. */
|
|
3
|
+
export const BUILDER_RECIPIENT = "0x2ebba955c61116e1c249efb1e39d25cb4a79ea05";
|
|
4
|
+
/** Builder fee limits in whole basis points, stored as tenths of a basis point. */
|
|
5
|
+
export const MIN_BUILDER_FEE_BPS = 1;
|
|
6
|
+
export const MAX_BUILDER_FEE_BPS = 10;
|
|
7
|
+
export const DEFAULT_BUILDER_FEE_BPS = 5;
|
|
8
|
+
export const BUILDER_FEE_BPS_TO_TENTHS = 10;
|
|
9
|
+
/** The maximum builder fee Hyperliquid allows this builder, in tenths of a bp. */
|
|
10
|
+
export const MAX_BUILDER_FEE_TENTHS_OF_BP = MAX_BUILDER_FEE_BPS * BUILDER_FEE_BPS_TO_TENTHS;
|
|
11
|
+
/** The maxFeeRate string that revokes the builder fee approval. */
|
|
12
|
+
export const REVOKED_BUILDER_FEE_RATE = "0.00%";
|
|
13
|
+
/** Name recorded with Hyperliquid for every HyperVibes trading signer. */
|
|
14
|
+
export const USER_API_WALLET_NAME = "HyperVibes";
|
|
15
|
+
/** Arbitrum One: the chain every Hyperliquid action signature must target. */
|
|
16
|
+
export const SIGNATURE_CHAIN_ID = 42_161;
|
|
17
|
+
export const SIGNATURE_CHAIN_HEX = "0xa4b1";
|
|
18
|
+
/** Hyperliquid mainnet API endpoints. */
|
|
19
|
+
export const HYPERLIQUID_API_URL = "https://api.hyperliquid.xyz";
|
|
20
|
+
/** Approvals of trading signers expire on Hyperliquid after 180 days. */
|
|
21
|
+
export const API_WALLET_APPROVAL_MS = 180 * 24 * 60 * 60 * 1000;
|
|
22
|
+
/** `vt-` prefix plus at most 13 characters keeps subaccount names within Hyperliquid's limit. */
|
|
23
|
+
export function agentSubaccountName(displayName) {
|
|
24
|
+
return `vt-${displayName.trim().slice(0, 13).trimEnd()}`;
|
|
25
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
2
|
+
const NONCE_LENGTH = 12;
|
|
3
|
+
const TAG_LENGTH = 16;
|
|
4
|
+
const KEY_LENGTH = 32;
|
|
5
|
+
/** Generates a fresh secp256k1 private key in Hyperliquid's `0x…` hex form. */
|
|
6
|
+
export function generateWalletPrivateKey() {
|
|
7
|
+
return `0x${randomBytes(KEY_LENGTH).toString("hex")}`;
|
|
8
|
+
}
|
|
9
|
+
/** Encrypts a secret with AES-256-GCM: `nonce ‖ ciphertext ‖ tag`. */
|
|
10
|
+
export function encryptSecret(key, plaintext) {
|
|
11
|
+
const nonce = randomBytes(NONCE_LENGTH);
|
|
12
|
+
const cipher = createCipheriv("aes-256-gcm", key.bytes, nonce);
|
|
13
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
14
|
+
return new Uint8Array(Buffer.concat([nonce, ciphertext, cipher.getAuthTag()]));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Decrypts an AES-256-GCM secret. Throws on truncation, tampering or a
|
|
18
|
+
* mismatched key so callers never silently accept corrupted credentials.
|
|
19
|
+
*/
|
|
20
|
+
export function decryptSecret(key, sealed) {
|
|
21
|
+
if (sealed.length < NONCE_LENGTH + TAG_LENGTH)
|
|
22
|
+
throw new Error("Encrypted secret is truncated");
|
|
23
|
+
const decipher = createDecipheriv("aes-256-gcm", key.bytes, sealed.subarray(0, NONCE_LENGTH));
|
|
24
|
+
decipher.setAuthTag(sealed.subarray(sealed.length - TAG_LENGTH));
|
|
25
|
+
return Buffer.concat([
|
|
26
|
+
decipher.update(sealed.subarray(NONCE_LENGTH, sealed.length - TAG_LENGTH)),
|
|
27
|
+
decipher.final(),
|
|
28
|
+
]).toString("utf8");
|
|
29
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Spot identifiers are intentionally not resolved by the perpetual logo feature. */
|
|
2
|
+
export function isPerpetualLogoSymbol(symbol) {
|
|
3
|
+
return symbol.length <= 64 && /^(?:[A-Za-z0-9_-]+:)?[A-Za-z0-9_-]+$/.test(symbol);
|
|
4
|
+
}
|
|
5
|
+
export function currencyLogoUrl(symbol) {
|
|
6
|
+
return isPerpetualLogoSymbol(symbol) ? `/currency/${encodeURIComponent(symbol)}.svg` : null;
|
|
7
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal string-decimal helpers for display-only exchange amounts. Values
|
|
3
|
+
* arriving from Hyperliquid are kept as strings and combined with integer
|
|
4
|
+
* arithmetic; these are never used for signed amounts or order placement.
|
|
5
|
+
*/
|
|
6
|
+
/** Splits a plain decimal string like `-12.3400`; returns null when malformed. */
|
|
7
|
+
export function parseDecimal(value) {
|
|
8
|
+
if (!/^-?\d+(?:\.\d+)?$/.test(value) || value.includes("e") || value.includes("E"))
|
|
9
|
+
return null;
|
|
10
|
+
const negative = value.startsWith("-");
|
|
11
|
+
const unsigned = negative ? value.slice(1) : value;
|
|
12
|
+
const separator = unsigned.indexOf(".");
|
|
13
|
+
const whole = separator === -1 ? unsigned : unsigned.slice(0, separator);
|
|
14
|
+
const fraction = separator === -1 ? "" : unsigned.slice(separator + 1);
|
|
15
|
+
return { negative, whole: BigInt(whole), fraction };
|
|
16
|
+
}
|
|
17
|
+
/** Scales two parsed decimals to a common denominator and returns the parts. */
|
|
18
|
+
function commonScale(left, right) {
|
|
19
|
+
const scale = Math.max(left.fraction.length, right.fraction.length);
|
|
20
|
+
const scaleUp = (part) => BigInt(part.negative ? -1 : 1) * (part.whole * 10n ** BigInt(scale) + BigInt(part.fraction.padEnd(scale, "0") || "0"));
|
|
21
|
+
return { leftScaled: scaleUp(left), rightScaled: scaleUp(right), scale };
|
|
22
|
+
}
|
|
23
|
+
/** Adds two plain decimal strings; returns null when either is malformed. */
|
|
24
|
+
export function addDecimals(left, right) {
|
|
25
|
+
const parsedLeft = parseDecimal(left);
|
|
26
|
+
const parsedRight = parseDecimal(right);
|
|
27
|
+
if (!parsedLeft || !parsedRight)
|
|
28
|
+
return null;
|
|
29
|
+
const { leftScaled, rightScaled, scale } = commonScale(parsedLeft, parsedRight);
|
|
30
|
+
const total = leftScaled + rightScaled;
|
|
31
|
+
return formatScaled(total, scale);
|
|
32
|
+
}
|
|
33
|
+
function formatScaled(scaled, scale) {
|
|
34
|
+
const negative = scaled < 0n;
|
|
35
|
+
const absolute = negative ? -scaled : scaled;
|
|
36
|
+
const denominator = 10n ** BigInt(scale);
|
|
37
|
+
const whole = absolute / denominator;
|
|
38
|
+
const fraction = (absolute % denominator).toString().padStart(scale, "0");
|
|
39
|
+
const canonical = fraction.replace(/0+$/, "");
|
|
40
|
+
const body = canonical ? `${whole}.${canonical}` : `${whole}`;
|
|
41
|
+
return negative && absolute !== 0n ? `-${body}` : body;
|
|
42
|
+
}
|
|
43
|
+
/** Compares two plain decimal strings; null when either is malformed. */
|
|
44
|
+
export function compareDecimals(left, right) {
|
|
45
|
+
const parsedLeft = parseDecimal(left);
|
|
46
|
+
const parsedRight = parseDecimal(right);
|
|
47
|
+
if (!parsedLeft || !parsedRight)
|
|
48
|
+
return null;
|
|
49
|
+
const { leftScaled, rightScaled } = commonScale(parsedLeft, parsedRight);
|
|
50
|
+
return leftScaled === rightScaled ? 0 : leftScaled < rightScaled ? -1 : 1;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Formats a plain decimal string with fixed precision (4 places by default),
|
|
54
|
+
* half-up rounding, thousands separators and negatives in parentheses.
|
|
55
|
+
*/
|
|
56
|
+
export function formatMoneyText(value, decimalPlaces = 4) {
|
|
57
|
+
if (!value)
|
|
58
|
+
return "-";
|
|
59
|
+
const parsed = parseDecimal(value);
|
|
60
|
+
if (!parsed)
|
|
61
|
+
return "-";
|
|
62
|
+
// Keep one guard digit for exact half-up rounding at the requested precision.
|
|
63
|
+
const guard = BigInt(decimalPlaces + 1);
|
|
64
|
+
const scale = 10n ** guard;
|
|
65
|
+
const scaled = parsed.whole * scale
|
|
66
|
+
+ BigInt(parsed.fraction.padEnd(Number(guard), "0").slice(0, Number(guard)) || "0");
|
|
67
|
+
const rounded = (scaled + 5n) / 10n;
|
|
68
|
+
const denominator = 10n ** BigInt(decimalPlaces);
|
|
69
|
+
const whole = rounded / denominator;
|
|
70
|
+
const fraction = (rounded % denominator).toString().padStart(decimalPlaces, "0");
|
|
71
|
+
const grouped = whole.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
72
|
+
const formatted = `${grouped}.${fraction}`;
|
|
73
|
+
return parsed.negative && rounded !== 0n ? `(${formatted})` : formatted;
|
|
74
|
+
}
|
|
75
|
+
/** Formats an exchange amount for display: exact fraction preserved (padded to
|
|
76
|
+
* at least 2 decimals), thousands separators on the whole part, and negatives in
|
|
77
|
+
* parentheses. Never rounds; prices and sizes are exchange-exact. */
|
|
78
|
+
export function formatAmountText(value) {
|
|
79
|
+
if (!value)
|
|
80
|
+
return "-";
|
|
81
|
+
const parsed = parseDecimal(value);
|
|
82
|
+
if (!parsed)
|
|
83
|
+
return "-";
|
|
84
|
+
const fraction = parsed.fraction.length < 2 ? parsed.fraction.padEnd(2, "0") : parsed.fraction;
|
|
85
|
+
const grouped = parsed.whole.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
86
|
+
const body = `${grouped}.${fraction}`;
|
|
87
|
+
return parsed.negative ? `(${body})` : body;
|
|
88
|
+
}
|
|
89
|
+
/** Splits formatted money into the whole part and optional decimals. */
|
|
90
|
+
export function moneyParts(value) {
|
|
91
|
+
if (!value)
|
|
92
|
+
return { whole: "-", decimals: null };
|
|
93
|
+
const separator = value.indexOf(".");
|
|
94
|
+
return {
|
|
95
|
+
whole: separator === -1 ? value : value.slice(0, separator),
|
|
96
|
+
decimals: separator === -1 ? null : value.slice(separator + 1),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
2
|
+
import { createOrderTools, toolResult } from "./orders/order-tools.js";
|
|
3
|
+
import { MarketSnapshotSchema } from "./market-snapshot.js";
|
|
4
|
+
import { defineExtension, defineTool, section } from "@earendil-works/pi-durable";
|
|
5
|
+
const nullable = Type.Union([Type.String(), Type.Null()]);
|
|
6
|
+
const freshness = Type.Object({ updatedAt: Type.Union([Type.Number(), Type.Null()]), fresh: Type.Boolean(), source: Type.Union([Type.Literal("live"), Type.Literal("http"), Type.Literal("unavailable")]) });
|
|
7
|
+
const AccountStatusSchema = Type.Object({
|
|
8
|
+
address: nullable, scope: Type.Literal("main-dex-perpetuals-and-spot-usdc"), observedAt: Type.Number(),
|
|
9
|
+
accountAbstraction: Type.Union([Type.Literal("unifiedAccount"), Type.Literal("portfolioMargin"), Type.Literal("disabled"), Type.Literal("default"), Type.Null()]),
|
|
10
|
+
perpEquity: nullable, spotUsdc: nullable, spotUsdcHold: nullable,
|
|
11
|
+
positions: Type.Union([Type.Array(Type.Object({ coin: Type.String(), size: Type.String(), entryPrice: Type.String(), unrealizedPnl: Type.String(), liquidationPrice: nullable, leverage: Type.Number() })), Type.Null()]),
|
|
12
|
+
orders: Type.Union([Type.Array(Type.Object({ id: Type.Number(), coin: Type.String(), side: Type.String(), size: Type.String(), price: Type.String(), type: Type.String() })), Type.Null()]),
|
|
13
|
+
sections: Type.Object({ perps: freshness, spot: freshness, orders: freshness, mode: freshness }), errors: Type.Array(Type.String()),
|
|
14
|
+
});
|
|
15
|
+
/** Trusted host binding: the model cannot choose an account or supply credentials. */
|
|
16
|
+
export function createHyperliquidExtension(service, userId, agentId, orders) {
|
|
17
|
+
return defineExtension({
|
|
18
|
+
name: "hyperliquid",
|
|
19
|
+
sections: [section("hyperliquid", () => "When get_market_snapshot is selected, fetch fresh data before answering current price/market questions. Report its source and observation time, distinguish mid/mark/oracle from executable quotes, and distinguish this snapshot from older stored research. Missing data is unknown, not zero. Use analyst workers for deeper candle/indicator research, not basic price lookups. Use get_account to read this Agent's assigned Hyperliquid account: main-DEX perpetual positions/orders, spot USDC total and holds, and accountAbstraction (queried for this exact account). Decimal strings preserve exchange precision. Check each section's freshness, timestamps, and errors; null/stale data is not zero or an empty account. In unifiedAccount mode, spot USDC is the single shared balance collateralizing USDC-settled cross-margin perps and used for spot trading; individual perp-DEX balance summaries are not meaningful account equity. In portfolioMargin mode, eligible spot assets and perps share portfolio collateral, but this tool only includes spot USDC, not the whole portfolio. Never conclude the account has zero collateral from perpEquity=0 in either mode. In standard/manual mode, spot and perp balances are separate; do not assume spot USDC automatically collateralizes perps. Do not infer the mode from the application's supported/default mode, or guess if mode lookup failed. Spot total is not available buying power: holds, existing positions, margin requirements, and exposure on other DEXs may constrain it. Do not add spotUsdc and perpEquity into a total in unified/portfolio mode or double-count shared collateral. Report spot USDC explicitly when summarizing the account. Other spot tokens, spot orders, and other DEX positions/orders are outside this view. Order tools place/cancel real orders autonomously on this Agent's assigned account only. Use exact decimal strings and stable unique request_id values. Size is base-asset quantity, not a USDC amount. Main-DEX perps require a minimum order notional of $10 (size × price), in addition to exchange size/tick precision. Check intended notional before submitting; never silently increase the user's intended exposure to satisfy the minimum. Exchange validation is authoritative, including any reduce-only/closing exceptions; do not assume an exception or retry a rejected order unchanged. Reuse the same ID and identical arguments after an interruption; never use a new ID to retry an unknown outcome. Query get_order_request/get_order to reconcile. Unknown/not-found is not rejection or cancellation. Inspect every leg: accepted is not filled; a rejected TP/SL can leave exposure unprotected. Market entries are 0.5%-guarded IOC and can partially fill. Native attached TP/SL activates only on full parent fill (or certain venue margin-cancel paths); manually canceling a partially filled parent also cancels its protection. Triggers use mark prices; market triggers use a 10% guard and may not fully fill. Standalone triggers are fixed-size reduce-only. Cancel-all can remove protective stops and does not close positions. No transfers, leverage changes, or trading on other accounts/DEXs are exposed. Reference: https://hyperliquid.gitbook.io/hyperliquid-docs/trading/account-abstraction-modes")],
|
|
20
|
+
tools: [defineTool({
|
|
21
|
+
name: "get_account",
|
|
22
|
+
description: "Read this Agent's own Hyperliquid account mode, spot USDC total/holds, main-DEX perpetual positions/orders, and raw perp equity summary with per-section freshness. Unified/portfolio accounts use spot collateral; raw perp equity is not account equity. Reuses the live feed with HTTP repair.",
|
|
23
|
+
parameters: Type.Object({}, { additionalProperties: false }),
|
|
24
|
+
replay: "safe",
|
|
25
|
+
structuredOutputSchema: AccountStatusSchema,
|
|
26
|
+
execute: async (_args, _api, context) => {
|
|
27
|
+
const status = await service.agentAccountStatus(userId, agentId, context.abortSignal);
|
|
28
|
+
return toolResult(status);
|
|
29
|
+
},
|
|
30
|
+
}), defineTool({
|
|
31
|
+
name: "get_market_snapshot",
|
|
32
|
+
description: "Read a fresh public Hyperliquid main-DEX perpetual snapshot for one instrument (exact venue symbol, e.g. BTC): mid/mark/oracle prices, mark-based 24h change, volumes, hourly funding and open interest. Read-only; independent of trading permissions. Includes host observation time, not a venue timestamp. Not an executable quote, last trade, or technical-analysis report.",
|
|
33
|
+
parameters: Type.Object({ instrument: Type.String({ minLength: 1, maxLength: 32 }) }, { additionalProperties: false }),
|
|
34
|
+
replay: "safe",
|
|
35
|
+
structuredOutputSchema: MarketSnapshotSchema,
|
|
36
|
+
execute: async (args, _api, context) => toolResult(await service.marketSnapshot(args.instrument, context.abortSignal)),
|
|
37
|
+
}), ...createOrderTools(orders, userId, agentId)],
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { ApiRequestError, ExchangeClient, HttpTransport, InfoClient } from "@nktkas/hyperliquid";
|
|
2
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
3
|
+
import { HYPERLIQUID_API_URL } from "./constants.js";
|
|
4
|
+
/** Splits a 65-byte secp256k1 signature into Hyperliquid's `r`/`s`/`v` fields. */
|
|
5
|
+
export function signatureParts(signature) {
|
|
6
|
+
const raw = signature.slice(2);
|
|
7
|
+
if (!/^[0-9a-fA-F]{130}$/.test(raw))
|
|
8
|
+
throw new Error("Invalid signature");
|
|
9
|
+
return {
|
|
10
|
+
r: `0x${raw.slice(0, 64)}`,
|
|
11
|
+
s: `0x${raw.slice(64, 128)}`,
|
|
12
|
+
v: Number.parseInt(raw.slice(128, 130), 16),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** An exchange response succeeded only when Hyperliquid reports `status: "ok"`. */
|
|
16
|
+
export function exchangeSuccess(response) {
|
|
17
|
+
return typeof response === "object" && response !== null
|
|
18
|
+
&& response.status === "ok";
|
|
19
|
+
}
|
|
20
|
+
/** The message Hyperliquid attached to a rejected exchange response. */
|
|
21
|
+
export function exchangeErrorMessage(response) {
|
|
22
|
+
if (typeof response !== "object" || response === null)
|
|
23
|
+
return "Hyperliquid rejected the request.";
|
|
24
|
+
const inner = response.response;
|
|
25
|
+
const nested = typeof inner === "object" && inner !== null ? inner.data?.status?.error : undefined;
|
|
26
|
+
const message = typeof nested === "string" ? nested
|
|
27
|
+
: typeof inner === "string" ? inner
|
|
28
|
+
: typeof response.message === "string" ? response.message
|
|
29
|
+
: undefined;
|
|
30
|
+
return message ?? "Hyperliquid rejected the request.";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Relays a browser-signed action to the exchange endpoint unchanged. The
|
|
34
|
+
* caller has already validated the action object and recovered its signer.
|
|
35
|
+
*/
|
|
36
|
+
export async function relaySignedAction(transport, action, signature) {
|
|
37
|
+
const nonce = action.nonce;
|
|
38
|
+
if (typeof nonce !== "number" || !Number.isSafeInteger(nonce))
|
|
39
|
+
throw new Error("Invalid action nonce");
|
|
40
|
+
const response = await fetch(`${HYPERLIQUID_API_URL}/exchange`, {
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: { "content-type": "application/json" },
|
|
43
|
+
body: JSON.stringify({ action, nonce, signature: signatureParts(signature) }),
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok)
|
|
46
|
+
throw new Error("Hyperliquid exchange unavailable");
|
|
47
|
+
return response.json();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Serializes creation for each owner and remembers uncertain submissions for
|
|
51
|
+
* the lifetime of the service. A cancelled request also remains uncertain.
|
|
52
|
+
*/
|
|
53
|
+
export class SubaccountCreator {
|
|
54
|
+
transport;
|
|
55
|
+
nonceManager;
|
|
56
|
+
owners = new Map();
|
|
57
|
+
constructor(transport, nonceManager) {
|
|
58
|
+
this.transport = transport;
|
|
59
|
+
this.nonceManager = nonceManager;
|
|
60
|
+
}
|
|
61
|
+
async discover(owner, name) {
|
|
62
|
+
const info = new InfoClient({ transport: this.transport });
|
|
63
|
+
const accounts = await info.subAccounts({ user: owner });
|
|
64
|
+
return accounts?.find((account) => account.master.toLowerCase() === owner && account.name === name)
|
|
65
|
+
?.subAccountUser.toLowerCase() ?? null;
|
|
66
|
+
}
|
|
67
|
+
async create(owner, name, privateKey) {
|
|
68
|
+
const state = this.owners.get(owner) ?? { pending: new Set(), queue: Promise.resolve() };
|
|
69
|
+
this.owners.set(owner, state);
|
|
70
|
+
const attempt = state.queue.then(() => this.attempt(state, owner, name, privateKey));
|
|
71
|
+
state.queue = attempt.then(() => { }, () => { });
|
|
72
|
+
return attempt;
|
|
73
|
+
}
|
|
74
|
+
async attempt(state, owner, name, privateKey) {
|
|
75
|
+
let existing;
|
|
76
|
+
try {
|
|
77
|
+
existing = await this.discover(owner, name);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return state.pending.has(name)
|
|
81
|
+
? { ok: false, failure: { kind: "unconfirmed" } }
|
|
82
|
+
: { ok: false, failure: { kind: "lookup-unavailable" } };
|
|
83
|
+
}
|
|
84
|
+
if (existing) {
|
|
85
|
+
state.pending.delete(name);
|
|
86
|
+
return { ok: true, subaccount: { address: existing, created: false } };
|
|
87
|
+
}
|
|
88
|
+
if (state.pending.has(name))
|
|
89
|
+
return { ok: false, failure: { kind: "unconfirmed" } };
|
|
90
|
+
// Record the name before awaiting submission so a cancelled request cannot
|
|
91
|
+
// enable another request to blindly submit the same creation.
|
|
92
|
+
state.pending.add(name);
|
|
93
|
+
try {
|
|
94
|
+
const wallet = privateKeyToAccount(privateKey);
|
|
95
|
+
const exchange = new ExchangeClient({ transport: this.transport, wallet, nonceManager: this.nonceManager });
|
|
96
|
+
const response = await exchange.createSubAccount({ name });
|
|
97
|
+
state.pending.delete(name);
|
|
98
|
+
const address = typeof response.response?.data === "string" ? response.response.data.toLowerCase() : null;
|
|
99
|
+
if (!address)
|
|
100
|
+
return { ok: false, failure: { kind: "unconfirmed" } };
|
|
101
|
+
return { ok: true, subaccount: { address, created: true } };
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (error instanceof ApiRequestError) {
|
|
105
|
+
// An explicit exchange rejection definitively means nothing was created.
|
|
106
|
+
state.pending.delete(name);
|
|
107
|
+
return { ok: false, failure: { kind: "rejected", message: error.message } };
|
|
108
|
+
}
|
|
109
|
+
// Transport or unexpected failures are uncertain; reconcile by discovery.
|
|
110
|
+
const reconciled = await this.discover(owner, name).catch(() => null);
|
|
111
|
+
if (reconciled) {
|
|
112
|
+
state.pending.delete(name);
|
|
113
|
+
return { ok: true, subaccount: { address: reconciled, created: true } };
|
|
114
|
+
}
|
|
115
|
+
return { ok: false, failure: { kind: "unconfirmed" } };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Exact finite-decimal accounting. Division alone rounds half-even at 28 places.
|
|
2
|
+
* Split fees use subtraction for the remainder, preserving the source total. */
|
|
3
|
+
export class Amount {
|
|
4
|
+
units;
|
|
5
|
+
scale;
|
|
6
|
+
constructor(units, scale) {
|
|
7
|
+
this.units = units;
|
|
8
|
+
this.scale = scale;
|
|
9
|
+
}
|
|
10
|
+
static from(value) {
|
|
11
|
+
if (value.length > 200 || !/^-?\d+(?:\.\d+)?$/.test(value))
|
|
12
|
+
throw new Error("Invalid journal decimal");
|
|
13
|
+
const [whole, fraction = ""] = value.split(".");
|
|
14
|
+
return new Amount(BigInt(`${whole}${fraction}`), fraction.length);
|
|
15
|
+
}
|
|
16
|
+
align(other) {
|
|
17
|
+
const scale = Math.max(this.scale, other.scale);
|
|
18
|
+
return { a: this.units * 10n ** BigInt(scale - this.scale), b: other.units * 10n ** BigInt(scale - other.scale), scale };
|
|
19
|
+
}
|
|
20
|
+
add(other) { const { a, b, scale } = this.align(other); return new Amount(a + b, scale); }
|
|
21
|
+
sub(other) { return this.add(other.neg()); }
|
|
22
|
+
neg() { return new Amount(-this.units, this.scale); }
|
|
23
|
+
abs() { return this.units < 0n ? this.neg() : this; }
|
|
24
|
+
mul(other) { return new Amount(this.units * other.units, this.scale + other.scale); }
|
|
25
|
+
div(other) {
|
|
26
|
+
if (other.units === 0n)
|
|
27
|
+
throw new Error("Division by zero");
|
|
28
|
+
const numerator = this.units * 10n ** BigInt(other.scale + 28);
|
|
29
|
+
const denominator = other.units * 10n ** BigInt(this.scale);
|
|
30
|
+
const negative = (numerator < 0n) !== (denominator < 0n);
|
|
31
|
+
const n = numerator < 0n ? -numerator : numerator;
|
|
32
|
+
const d = denominator < 0n ? -denominator : denominator;
|
|
33
|
+
let result = n / d;
|
|
34
|
+
const remainder = n % d;
|
|
35
|
+
if (remainder * 2n > d || (remainder * 2n === d && result % 2n !== 0n))
|
|
36
|
+
result++;
|
|
37
|
+
return new Amount(negative ? -result : result, 28);
|
|
38
|
+
}
|
|
39
|
+
cmp(other) { const { a, b } = this.align(other); return a < b ? -1 : a > b ? 1 : 0; }
|
|
40
|
+
get zero() { return this.units === 0n; }
|
|
41
|
+
get sign() { return this.units < 0n ? -1 : this.units > 0n ? 1 : 0; }
|
|
42
|
+
toString() {
|
|
43
|
+
const raw = (this.units < 0n ? -this.units : this.units).toString().padStart(this.scale + 1, "0");
|
|
44
|
+
const body = this.scale ? `${raw.slice(0, -this.scale)}.${raw.slice(-this.scale)}`.replace(/\.?0+$/, "") : raw;
|
|
45
|
+
return `${this.units < 0n ? "-" : ""}${body}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export const amount = Amount.from;
|