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,418 @@
|
|
|
1
|
+
import { HyperliquidError } from "../hyperliquid/errors.js";
|
|
2
|
+
import { AgentError, agentId } from "../agents/agent-input.js";
|
|
3
|
+
import { currentUserSession } from "../auth-user.js";
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
const heartbeatMs = 15_000;
|
|
6
|
+
const maxFrameBytes = 2 * 1024 * 1024;
|
|
7
|
+
const frame = (event, data) => encoder.encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
|
|
8
|
+
export const multiplexTopics = ["agent", "chat", "dashboard", "indicators", "chart-layouts", "subagents", "chart", "notifications"];
|
|
9
|
+
const topicLimits = {
|
|
10
|
+
agent: 4096,
|
|
11
|
+
chat: maxFrameBytes,
|
|
12
|
+
dashboard: maxFrameBytes,
|
|
13
|
+
indicators: 4096,
|
|
14
|
+
notifications: 4096,
|
|
15
|
+
"chart-layouts": maxFrameBytes,
|
|
16
|
+
subagents: maxFrameBytes,
|
|
17
|
+
chart: maxFrameBytes,
|
|
18
|
+
};
|
|
19
|
+
/** HTTP subscriptions are app-owned, and closed before Fastify drains requests. */
|
|
20
|
+
export class AgentEventStreams {
|
|
21
|
+
runtime;
|
|
22
|
+
kind;
|
|
23
|
+
stopping = false;
|
|
24
|
+
connections = new Set();
|
|
25
|
+
tasks = new Set();
|
|
26
|
+
users = new Map();
|
|
27
|
+
constructor(runtime, kind = "agent") {
|
|
28
|
+
this.runtime = runtime;
|
|
29
|
+
this.kind = kind;
|
|
30
|
+
}
|
|
31
|
+
async open(request, id, subagentId, runId) {
|
|
32
|
+
try {
|
|
33
|
+
this.runtime.status();
|
|
34
|
+
if (this.stopping)
|
|
35
|
+
throw new AgentError("Server is shutting down", 503);
|
|
36
|
+
if (request.method !== "GET")
|
|
37
|
+
return new Response(null, { status: 405, headers: { Allow: "GET" } });
|
|
38
|
+
if ((request.headers.get("origin") && request.headers.get("origin") !== this.runtime.origin)
|
|
39
|
+
|| request.headers.get("sec-fetch-site") === "cross-site")
|
|
40
|
+
throw new AgentError("Invalid request origin", 403);
|
|
41
|
+
id = agentId(id);
|
|
42
|
+
const session = await currentUserSession(this.runtime, request.headers);
|
|
43
|
+
if (!session)
|
|
44
|
+
throw new AgentError("Sign in to view this agent", 401);
|
|
45
|
+
if (this.kind === "provider-login")
|
|
46
|
+
this.runtime.providers.status(session.user.id, id);
|
|
47
|
+
else
|
|
48
|
+
await this.runtime.agents.owned(session.user.id, id);
|
|
49
|
+
const params = new URL(request.url).searchParams;
|
|
50
|
+
if (this.kind === "agent") {
|
|
51
|
+
const raw = params.get("topics") ?? "";
|
|
52
|
+
const topics = [...new Set(raw.split(",").map((part) => part.trim()).filter(Boolean))];
|
|
53
|
+
if (!topics.length)
|
|
54
|
+
throw new AgentError("Select at least one topic", 400);
|
|
55
|
+
for (const topic of topics) {
|
|
56
|
+
if (!multiplexTopics.includes(topic))
|
|
57
|
+
throw new AgentError(`Unknown topic: ${topic}`, 400);
|
|
58
|
+
}
|
|
59
|
+
const selection = topics.includes("chart")
|
|
60
|
+
? await this.runtime.hyperliquid.charts.selection(params.get("coin") ?? "", params.get("interval") ?? "")
|
|
61
|
+
: undefined;
|
|
62
|
+
if (this.stopping || request.signal.aborted)
|
|
63
|
+
throw new AgentError("Connection closed", 503);
|
|
64
|
+
const count = this.users.get(session.user.id) ?? 0;
|
|
65
|
+
if (count >= 10)
|
|
66
|
+
throw new AgentError("Too many open event connections", 429);
|
|
67
|
+
this.users.set(session.user.id, count + 1);
|
|
68
|
+
return this.connectMultiplex(request, id, session.user.id, session.expiresAt, topics, selection);
|
|
69
|
+
}
|
|
70
|
+
const history = this.kind === "runs" ? { subagentId: subagentId ?? "", page: Number(params.get("page") ?? "1") } : undefined;
|
|
71
|
+
if (history)
|
|
72
|
+
await this.runtime.agents.subagents.history(session.user.id, id, history.subagentId, history.page);
|
|
73
|
+
const run = this.kind === "run" ? { subagentId: subagentId ?? "", runId: runId ?? "" } : undefined;
|
|
74
|
+
if (run)
|
|
75
|
+
await this.runtime.agents.subagents.ownedRun(session.user.id, id, run.subagentId, run.runId);
|
|
76
|
+
if (this.stopping || request.signal.aborted)
|
|
77
|
+
throw new AgentError("Connection closed", 503);
|
|
78
|
+
const count = this.users.get(session.user.id) ?? 0;
|
|
79
|
+
if (count >= 10)
|
|
80
|
+
throw new AgentError("Too many open event connections", 429);
|
|
81
|
+
this.users.set(session.user.id, count + 1);
|
|
82
|
+
return this.connect(request, id, session.user.id, session.expiresAt, history, run);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
const expected = error instanceof AgentError || error instanceof HyperliquidError;
|
|
86
|
+
const status = expected ? error.status : 503;
|
|
87
|
+
const message = expected ? error.message : "Agent event stream is unavailable";
|
|
88
|
+
return Response.json({ error: message }, { status, headers: { "Cache-Control": "no-store" } });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
startTopic(topic, ctx) {
|
|
92
|
+
const publish = (snapshot) => ctx.publish(topic, snapshot);
|
|
93
|
+
switch (topic) {
|
|
94
|
+
case "agent": return this.runtime.agents.watchAgent(ctx.userId, ctx.id, ctx.signal, publish);
|
|
95
|
+
case "chat": return this.runtime.agents.watchChat(ctx.userId, ctx.id, ctx.signal, publish);
|
|
96
|
+
case "dashboard": return this.runtime.hyperliquid.watchDashboard(ctx.userId, ctx.id, ctx.signal, publish);
|
|
97
|
+
case "notifications": return this.runtime.notifications.watch(ctx.id, ctx.signal, publish);
|
|
98
|
+
case "indicators": return this.runtime.agents.indicators.watch(ctx.id, ctx.signal, publish);
|
|
99
|
+
case "chart-layouts": return this.runtime.agents.watchChartLayouts(ctx.userId, ctx.id, ctx.signal, publish);
|
|
100
|
+
case "subagents": return this.runtime.agents.subagents.watchDashboard(ctx.userId, ctx.id, ctx.signal, publish);
|
|
101
|
+
case "chart": return this.runtime.hyperliquid.charts.watch(ctx.selection, ctx.signal, publish);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
connectMultiplex(request, id, userId, expiresAt, topics, selection) {
|
|
105
|
+
const abort = new AbortController();
|
|
106
|
+
let controller;
|
|
107
|
+
const pending = new Map();
|
|
108
|
+
const topicControllers = new Map();
|
|
109
|
+
for (const topic of topics)
|
|
110
|
+
topicControllers.set(topic, new AbortController());
|
|
111
|
+
abort.signal.addEventListener("abort", () => { for (const topicController of topicControllers.values())
|
|
112
|
+
topicController.abort(); });
|
|
113
|
+
let closed = false;
|
|
114
|
+
let expiry = expiresAt.getTime();
|
|
115
|
+
let heartbeat;
|
|
116
|
+
let deadline;
|
|
117
|
+
let checking = false;
|
|
118
|
+
let ticks = 0;
|
|
119
|
+
const flush = () => {
|
|
120
|
+
while (!closed && pending.size > 0 && (controller.desiredSize ?? 0) > 0) {
|
|
121
|
+
const first = pending.entries().next();
|
|
122
|
+
if (first.done)
|
|
123
|
+
return;
|
|
124
|
+
const [, value] = first.value;
|
|
125
|
+
pending.delete(first.value[0]);
|
|
126
|
+
controller.enqueue(value);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const finish = (event, message, cancelled = false) => {
|
|
130
|
+
if (closed)
|
|
131
|
+
return;
|
|
132
|
+
closed = true;
|
|
133
|
+
pending.clear();
|
|
134
|
+
clearInterval(heartbeat);
|
|
135
|
+
clearTimeout(deadline);
|
|
136
|
+
request.signal.removeEventListener("abort", disconnect);
|
|
137
|
+
agentLifetime?.removeEventListener("abort", unavailable);
|
|
138
|
+
this.connections.delete(shutdown);
|
|
139
|
+
const remaining = (this.users.get(userId) ?? 1) - 1;
|
|
140
|
+
if (remaining > 0)
|
|
141
|
+
this.users.set(userId, remaining);
|
|
142
|
+
else
|
|
143
|
+
this.users.delete(userId);
|
|
144
|
+
abort.abort();
|
|
145
|
+
try {
|
|
146
|
+
if (!cancelled && event)
|
|
147
|
+
controller.enqueue(frame(event, { message }));
|
|
148
|
+
// Always close: a disconnected consumer still awaits a definite end.
|
|
149
|
+
controller.close();
|
|
150
|
+
}
|
|
151
|
+
catch { /* The consumer already cancelled or the stream already ended. */ }
|
|
152
|
+
};
|
|
153
|
+
const agentLifetime = this.runtime.agents.signal(id);
|
|
154
|
+
const unavailable = () => finish("unavailable", "Agent is being deleted.");
|
|
155
|
+
const disconnect = () => finish(undefined, undefined, true);
|
|
156
|
+
const shutdown = () => finish("shutdown", "Server is restarting. Reconnecting…");
|
|
157
|
+
const scheduleExpiry = () => {
|
|
158
|
+
clearTimeout(deadline);
|
|
159
|
+
const remaining = expiry - Date.now();
|
|
160
|
+
if (remaining <= 0) {
|
|
161
|
+
finish("unauthorized", "Session expired. Please sign in again.");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
deadline = setTimeout(scheduleExpiry, Math.min(remaining, 2_147_483_647));
|
|
165
|
+
deadline.unref();
|
|
166
|
+
};
|
|
167
|
+
const revalidate = async () => {
|
|
168
|
+
if (closed || checking)
|
|
169
|
+
return;
|
|
170
|
+
checking = true;
|
|
171
|
+
try {
|
|
172
|
+
const session = await currentUserSession(this.runtime, request.headers);
|
|
173
|
+
if (closed)
|
|
174
|
+
return;
|
|
175
|
+
if (!session || session.user.id !== userId) {
|
|
176
|
+
finish("unauthorized", "Session ended. Please sign in again.");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
await this.runtime.agents.owned(userId, id);
|
|
180
|
+
if (closed)
|
|
181
|
+
return;
|
|
182
|
+
expiry = session.expiresAt.getTime();
|
|
183
|
+
scheduleExpiry();
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
finish("unavailable", "Unable to verify this session. Reconnecting…");
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
checking = false;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
const failTopic = (topic, message) => {
|
|
193
|
+
if (closed)
|
|
194
|
+
return;
|
|
195
|
+
topicControllers.get(topic)?.abort();
|
|
196
|
+
try {
|
|
197
|
+
if ((controller.desiredSize ?? 0) > 0)
|
|
198
|
+
controller.enqueue(frame("stream-error", { topic, message }));
|
|
199
|
+
else {
|
|
200
|
+
// Backpressure: queue behind pending frames is unnecessary; stream-errors
|
|
201
|
+
// are terminal for their topic and must not be dropped. Enqueue anyway;
|
|
202
|
+
// the stream buffers until the consumer reads.
|
|
203
|
+
controller.enqueue(frame("stream-error", { topic, message }));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch { /* The consumer already cancelled or the stream already ended. */ }
|
|
207
|
+
};
|
|
208
|
+
const publish = (topic, snapshot) => {
|
|
209
|
+
if (closed || topicControllers.get(topic)?.signal.aborted)
|
|
210
|
+
return;
|
|
211
|
+
if (Date.now() >= expiry) {
|
|
212
|
+
finish("unauthorized", "Session expired. Please sign in again.");
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const value = frame(topic, snapshot);
|
|
216
|
+
if (value.byteLength > topicLimits[topic]) {
|
|
217
|
+
failTopic(topic, topic === "indicators"
|
|
218
|
+
? "Indicator updates are too large to stream. Reload the page."
|
|
219
|
+
: "Snapshot is too large to stream. Reload the page to view it.");
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
// Keep one newest pending snapshot per topic, not an unbounded queue of token events.
|
|
223
|
+
pending.set(topic, value);
|
|
224
|
+
flush();
|
|
225
|
+
};
|
|
226
|
+
const stream = new ReadableStream({
|
|
227
|
+
start(value) { controller = value; controller.enqueue(encoder.encode("retry: 3000\n\n")); },
|
|
228
|
+
pull: flush,
|
|
229
|
+
cancel: disconnect,
|
|
230
|
+
}, { highWaterMark: 1 });
|
|
231
|
+
this.connections.add(shutdown);
|
|
232
|
+
request.signal.addEventListener("abort", disconnect, { once: true });
|
|
233
|
+
agentLifetime?.addEventListener("abort", unavailable, { once: true });
|
|
234
|
+
if (agentLifetime?.aborted)
|
|
235
|
+
unavailable();
|
|
236
|
+
scheduleExpiry();
|
|
237
|
+
if (request.signal.aborted)
|
|
238
|
+
disconnect();
|
|
239
|
+
if (!closed) {
|
|
240
|
+
heartbeat = setInterval(() => {
|
|
241
|
+
if (closed)
|
|
242
|
+
return;
|
|
243
|
+
if ((controller.desiredSize ?? 0) > 0 && pending.size === 0)
|
|
244
|
+
controller.enqueue(encoder.encode(": keepalive\n\n"));
|
|
245
|
+
// Security checks only: no conversation reads or chat polling. Bound the
|
|
246
|
+
// lifetime of a revoked session even when no new chat updates arrive.
|
|
247
|
+
if (++ticks % 4 === 0)
|
|
248
|
+
void revalidate();
|
|
249
|
+
}, heartbeatMs);
|
|
250
|
+
heartbeat.unref();
|
|
251
|
+
const watchers = topics.map((topic) => {
|
|
252
|
+
const signal = topicControllers.get(topic).signal;
|
|
253
|
+
return this.startTopic(topic, { userId, id, signal, selection, publish })
|
|
254
|
+
.catch(() => { failTopic(topic, "Agent event stream interrupted. Reconnecting…"); });
|
|
255
|
+
});
|
|
256
|
+
const task = Promise.all(watchers)
|
|
257
|
+
.then(() => { if (!closed)
|
|
258
|
+
shutdown(); })
|
|
259
|
+
.finally(() => { this.tasks.delete(task); });
|
|
260
|
+
this.tasks.add(task);
|
|
261
|
+
}
|
|
262
|
+
return new Response(stream, { headers: {
|
|
263
|
+
"Content-Type": "text/event-stream; charset=utf-8",
|
|
264
|
+
"Cache-Control": "no-store",
|
|
265
|
+
"X-Accel-Buffering": "no",
|
|
266
|
+
"X-Content-Type-Options": "nosniff",
|
|
267
|
+
} });
|
|
268
|
+
}
|
|
269
|
+
connect(request, id, userId, expiresAt, history, run) {
|
|
270
|
+
const abort = new AbortController();
|
|
271
|
+
let controller;
|
|
272
|
+
let pending;
|
|
273
|
+
let closed = false;
|
|
274
|
+
let expiry = expiresAt.getTime();
|
|
275
|
+
let heartbeat;
|
|
276
|
+
let deadline;
|
|
277
|
+
let checking = false;
|
|
278
|
+
let ticks = 0;
|
|
279
|
+
const flush = () => {
|
|
280
|
+
if (!closed && pending && (controller.desiredSize ?? 0) > 0) {
|
|
281
|
+
const value = pending;
|
|
282
|
+
pending = undefined;
|
|
283
|
+
controller.enqueue(value);
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
const finish = (event, message, cancelled = false) => {
|
|
287
|
+
if (closed)
|
|
288
|
+
return;
|
|
289
|
+
closed = true;
|
|
290
|
+
pending = undefined;
|
|
291
|
+
clearInterval(heartbeat);
|
|
292
|
+
clearTimeout(deadline);
|
|
293
|
+
request.signal.removeEventListener("abort", disconnect);
|
|
294
|
+
agentLifetime?.removeEventListener("abort", unavailable);
|
|
295
|
+
this.connections.delete(shutdown);
|
|
296
|
+
const remaining = (this.users.get(userId) ?? 1) - 1;
|
|
297
|
+
if (remaining > 0)
|
|
298
|
+
this.users.set(userId, remaining);
|
|
299
|
+
else
|
|
300
|
+
this.users.delete(userId);
|
|
301
|
+
abort.abort();
|
|
302
|
+
try {
|
|
303
|
+
if (!cancelled && event)
|
|
304
|
+
controller.enqueue(frame(event, { message }));
|
|
305
|
+
// Always close: a disconnected consumer still awaits a definite end.
|
|
306
|
+
controller.close();
|
|
307
|
+
}
|
|
308
|
+
catch { /* The consumer already cancelled or the stream already ended. */ }
|
|
309
|
+
};
|
|
310
|
+
const agentLifetime = this.kind === "provider-login" ? undefined : this.runtime.agents.signal(id);
|
|
311
|
+
const unavailable = () => finish("unavailable", "Agent is being deleted.");
|
|
312
|
+
const disconnect = () => finish(undefined, undefined, true);
|
|
313
|
+
const shutdown = () => finish("shutdown", "Server is restarting. Reconnecting…");
|
|
314
|
+
const scheduleExpiry = () => {
|
|
315
|
+
clearTimeout(deadline);
|
|
316
|
+
const remaining = expiry - Date.now();
|
|
317
|
+
if (remaining <= 0) {
|
|
318
|
+
finish("unauthorized", "Session expired. Please sign in again.");
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
deadline = setTimeout(scheduleExpiry, Math.min(remaining, 2_147_483_647));
|
|
322
|
+
deadline.unref();
|
|
323
|
+
};
|
|
324
|
+
const revalidate = async () => {
|
|
325
|
+
if (closed || checking)
|
|
326
|
+
return;
|
|
327
|
+
checking = true;
|
|
328
|
+
try {
|
|
329
|
+
const session = await currentUserSession(this.runtime, request.headers);
|
|
330
|
+
if (closed)
|
|
331
|
+
return;
|
|
332
|
+
if (!session || session.user.id !== userId) {
|
|
333
|
+
finish("unauthorized", "Session ended. Please sign in again.");
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (this.kind === "provider-login")
|
|
337
|
+
this.runtime.providers.status(userId, id);
|
|
338
|
+
else
|
|
339
|
+
await this.runtime.agents.owned(userId, id);
|
|
340
|
+
if (closed)
|
|
341
|
+
return;
|
|
342
|
+
expiry = session.expiresAt.getTime();
|
|
343
|
+
scheduleExpiry();
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
finish("unavailable", "Unable to verify this session. Reconnecting…");
|
|
347
|
+
}
|
|
348
|
+
finally {
|
|
349
|
+
checking = false;
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
const publish = (snapshot) => {
|
|
353
|
+
if (closed)
|
|
354
|
+
return;
|
|
355
|
+
if (Date.now() >= expiry) {
|
|
356
|
+
finish("unauthorized", "Session expired. Please sign in again.");
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const value = frame(this.kind, snapshot);
|
|
360
|
+
if (value.byteLength > maxFrameBytes) {
|
|
361
|
+
finish("stream-error", "Snapshot is too large to stream. Reload the page to view it.");
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
// Keep one newest pending snapshot, not an unbounded queue of token events.
|
|
365
|
+
pending = value;
|
|
366
|
+
flush();
|
|
367
|
+
};
|
|
368
|
+
const stream = new ReadableStream({
|
|
369
|
+
start(value) { controller = value; controller.enqueue(encoder.encode("retry: 3000\n\n")); },
|
|
370
|
+
pull: flush,
|
|
371
|
+
cancel: disconnect,
|
|
372
|
+
}, { highWaterMark: 1 });
|
|
373
|
+
this.connections.add(shutdown);
|
|
374
|
+
request.signal.addEventListener("abort", disconnect, { once: true });
|
|
375
|
+
agentLifetime?.addEventListener("abort", unavailable, { once: true });
|
|
376
|
+
if (agentLifetime?.aborted)
|
|
377
|
+
unavailable();
|
|
378
|
+
scheduleExpiry();
|
|
379
|
+
if (request.signal.aborted)
|
|
380
|
+
disconnect();
|
|
381
|
+
if (!closed) {
|
|
382
|
+
heartbeat = setInterval(() => {
|
|
383
|
+
if (closed)
|
|
384
|
+
return;
|
|
385
|
+
if ((controller.desiredSize ?? 0) > 0 && !pending)
|
|
386
|
+
controller.enqueue(encoder.encode(": keepalive\n\n"));
|
|
387
|
+
// Security checks only: no conversation reads or chat polling. Bound the
|
|
388
|
+
// lifetime of a revoked session even when no new chat updates arrive.
|
|
389
|
+
if (++ticks % 4 === 0)
|
|
390
|
+
void revalidate();
|
|
391
|
+
}, heartbeatMs);
|
|
392
|
+
heartbeat.unref();
|
|
393
|
+
const watching = Promise.resolve().then(() => this.kind === "provider-login"
|
|
394
|
+
? this.runtime.providers.watchLogin(userId, id, abort.signal, publish)
|
|
395
|
+
: run ? this.runtime.agents.subagents.watchRun(userId, id, run.subagentId, run.runId, abort.signal, publish)
|
|
396
|
+
: history ? this.runtime.agents.subagents.watchHistory(userId, id, history.subagentId, history.page, abort.signal, publish)
|
|
397
|
+
: this.runtime.hyperliquid.watchDashboard(userId, id, abort.signal, publish));
|
|
398
|
+
const task = watching
|
|
399
|
+
.then(() => { if (!closed)
|
|
400
|
+
shutdown(); })
|
|
401
|
+
.catch(() => finish("unavailable", "Agent event stream interrupted. Reconnecting…"))
|
|
402
|
+
.finally(() => { this.tasks.delete(task); });
|
|
403
|
+
this.tasks.add(task);
|
|
404
|
+
}
|
|
405
|
+
return new Response(stream, { headers: {
|
|
406
|
+
"Content-Type": "text/event-stream; charset=utf-8",
|
|
407
|
+
"Cache-Control": "no-store",
|
|
408
|
+
"X-Accel-Buffering": "no",
|
|
409
|
+
"X-Content-Type-Options": "nosniff",
|
|
410
|
+
} });
|
|
411
|
+
}
|
|
412
|
+
async close() {
|
|
413
|
+
this.stopping = true;
|
|
414
|
+
for (const finish of [...this.connections])
|
|
415
|
+
finish();
|
|
416
|
+
await Promise.all(this.tasks);
|
|
417
|
+
}
|
|
418
|
+
}
|
package/dist/web/app.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import fastifyStatic from "@fastify/static";
|
|
2
|
+
import Fastify from "fastify";
|
|
3
|
+
import { basename, isAbsolute, join, relative, sep } from "node:path";
|
|
4
|
+
import { CurrencyLogoCache } from "../hyperliquid/logo-cache.js";
|
|
5
|
+
import { isPerpetualLogoSymbol } from "../hyperliquid/currency-logo.js";
|
|
6
|
+
import { ProviderLogoCache, isProviderSlug } from "../providers/provider-logo.js";
|
|
7
|
+
import { NodeRequest, sendNodeResponse } from "srvx/node";
|
|
8
|
+
import { defaultCacheDirectory } from "../config.js";
|
|
9
|
+
import { createRuntime } from "../runtime.js";
|
|
10
|
+
import { AgentEventStreams } from "./agent-events.js";
|
|
11
|
+
import { artifactDownloads } from "./artifact-downloads.js";
|
|
12
|
+
import { runMiddleware } from "./middleware.js";
|
|
13
|
+
import { loadStart } from "./start.js";
|
|
14
|
+
/** Constructs a single embedded runtime and web host, without opening a listener. */
|
|
15
|
+
export async function createApp(config, options = {}) {
|
|
16
|
+
for (const publicDir of [config.staticDir, join(config.buildDir, "client")]) {
|
|
17
|
+
const location = relative(publicDir, config.databasePath);
|
|
18
|
+
if (!isAbsolute(location) && location !== ".." && !location.startsWith(`..${sep}`)) {
|
|
19
|
+
throw new Error("APP_SQLITE_PATH must be outside public static and client directories");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const app = Fastify({
|
|
23
|
+
logger: options.logger ? {
|
|
24
|
+
level: options.development ? "debug" : "info",
|
|
25
|
+
redact: ["req.headers.cookie", "req.headers.authorization", "res.headers.set-cookie"],
|
|
26
|
+
// Colorize only on a real console; journald/piped output stays plain.
|
|
27
|
+
transport: { target: "pino-pretty", options: { colorize: process.stdout.isTTY === true, singleLine: true, translateTime: "HH:MM:ss.l", ignore: "pid,hostname" } },
|
|
28
|
+
} : false,
|
|
29
|
+
});
|
|
30
|
+
const cacheDir = config.cacheDir ?? defaultCacheDirectory(process.env);
|
|
31
|
+
const logos = new CurrencyLogoCache(cacheDir, options.logoFetcher);
|
|
32
|
+
const providerLogos = new ProviderLogoCache(cacheDir, options.logoFetcher);
|
|
33
|
+
const origin = new URL(config.authOrigin);
|
|
34
|
+
app.addHook("onRequest", async (request, reply) => {
|
|
35
|
+
let host;
|
|
36
|
+
try {
|
|
37
|
+
host = new URL(`${origin.protocol}//${request.headers.host ?? ""}`).host;
|
|
38
|
+
}
|
|
39
|
+
catch { /* Reject malformed hosts below. */ }
|
|
40
|
+
if (host !== origin.host)
|
|
41
|
+
return reply.code(400).send({ error: "Invalid request host" });
|
|
42
|
+
});
|
|
43
|
+
const runtime = await createRuntime(config, { logger: app.log });
|
|
44
|
+
const multiplex = new AgentEventStreams(runtime, "agent");
|
|
45
|
+
const providerLogins = new AgentEventStreams(runtime, "provider-login");
|
|
46
|
+
const runs = new AgentEventStreams(runtime, "runs");
|
|
47
|
+
const runDetails = new AgentEventStreams(runtime, "run");
|
|
48
|
+
let web;
|
|
49
|
+
// SSE responses must finish before Fastify waits for active HTTP connections.
|
|
50
|
+
app.addHook("preClose", async () => { await Promise.all([multiplex.close(), providerLogins.close(), runs.close(), runDetails.close(), logos.close(), providerLogos.close()]); });
|
|
51
|
+
app.addHook("onClose", async () => {
|
|
52
|
+
try {
|
|
53
|
+
await web?.close();
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
await runtime.close(options.forceShutdown);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
let shuttingDown;
|
|
60
|
+
app.decorate("shutdown", () => shuttingDown ??= (async () => {
|
|
61
|
+
try {
|
|
62
|
+
await runtime.agents.drain(options.forceShutdown);
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
await app.close();
|
|
66
|
+
}
|
|
67
|
+
})());
|
|
68
|
+
try {
|
|
69
|
+
const development = options.development ?? false;
|
|
70
|
+
web = await (options.loadWeb ?? loadStart)(config, development);
|
|
71
|
+
const start = web;
|
|
72
|
+
app.register(fastifyStatic, {
|
|
73
|
+
root: config.staticDir,
|
|
74
|
+
prefix: "/static/",
|
|
75
|
+
dotfiles: "deny",
|
|
76
|
+
index: false,
|
|
77
|
+
cacheControl: false,
|
|
78
|
+
setHeaders(response, path) {
|
|
79
|
+
if (relative(config.staticDir, path).startsWith(`dist${sep}`)) {
|
|
80
|
+
response.header("Cache-Control", "no-store");
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
if (!development) {
|
|
85
|
+
app.register(fastifyStatic, {
|
|
86
|
+
root: join(config.buildDir, "client", "assets"),
|
|
87
|
+
prefix: "/assets/",
|
|
88
|
+
decorateReply: false,
|
|
89
|
+
dotfiles: "deny",
|
|
90
|
+
index: false,
|
|
91
|
+
setHeaders(response, path) {
|
|
92
|
+
// Vite's client output uses [name]-[hash].[ext], with an 8-character
|
|
93
|
+
// base64url hash. Keep HTML and non-hashed files on the default policy.
|
|
94
|
+
const filename = basename(path);
|
|
95
|
+
if (/^.+-[A-Za-z0-9_-]{8}\.[A-Za-z0-9]+$/.test(filename) && !/\.html?$/i.test(filename)) {
|
|
96
|
+
response.header("Cache-Control", "public, max-age=31536000, immutable");
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
app.get("/currency/:file", async (request, reply) => {
|
|
102
|
+
const file = request.params.file;
|
|
103
|
+
const symbol = file.endsWith(".svg") ? file.slice(0, -4) : "";
|
|
104
|
+
if (!isPerpetualLogoSymbol(symbol))
|
|
105
|
+
return reply.code(400).type("text/plain").send("Invalid currency logo filename");
|
|
106
|
+
return reply.type("image/svg+xml; charset=utf-8")
|
|
107
|
+
.header("Cache-Control", "public, max-age=86400")
|
|
108
|
+
.header("X-Content-Type-Options", "nosniff")
|
|
109
|
+
.header("Content-Security-Policy", "sandbox; default-src 'none'; style-src 'unsafe-inline'; img-src 'none'; base-uri 'none'; form-action 'none'")
|
|
110
|
+
.send(await logos.get(symbol));
|
|
111
|
+
});
|
|
112
|
+
app.get("/model-catalog/logos/:file", async (request, reply) => {
|
|
113
|
+
const file = request.params.file;
|
|
114
|
+
const provider = file.endsWith(".svg") ? file.slice(0, -4) : "";
|
|
115
|
+
if (!isProviderSlug(provider))
|
|
116
|
+
return reply.code(400).type("text/plain").send("Invalid provider logo filename");
|
|
117
|
+
return reply.type("image/svg+xml; charset=utf-8")
|
|
118
|
+
.header("Cache-Control", "public, max-age=2592000")
|
|
119
|
+
.header("X-Content-Type-Options", "nosniff")
|
|
120
|
+
.header("Content-Security-Policy", "sandbox; default-src 'none'; style-src 'unsafe-inline'; img-src 'none'; base-uri 'none'; form-action 'none'")
|
|
121
|
+
.send(await providerLogos.get(provider));
|
|
122
|
+
});
|
|
123
|
+
artifactDownloads(app, runtime);
|
|
124
|
+
app.get("/healthz", async () => {
|
|
125
|
+
runtime.status();
|
|
126
|
+
await runtime.database.get("SELECT 1");
|
|
127
|
+
return { status: "ok" };
|
|
128
|
+
});
|
|
129
|
+
// Provider sign-in prompts, progress and completion are pushed, with no polling.
|
|
130
|
+
app.get("/api/providers/logins/:id/events", async (request, reply) => {
|
|
131
|
+
reply.hijack();
|
|
132
|
+
const webRequest = new NodeRequest({ req: request.raw, res: reply.raw, maxRequestBodySize: 1024 * 1024 });
|
|
133
|
+
webRequest.headers.set("x-hv-client-ip", request.ip);
|
|
134
|
+
const response = await providerLogins.open(webRequest, request.params.id);
|
|
135
|
+
await sendNodeResponse(reply.raw, response);
|
|
136
|
+
});
|
|
137
|
+
// One multiplexed Server-Sent Events subscription per agent page: chat,
|
|
138
|
+
// dashboard, chart, layouts, indicators and sub-agents share a single
|
|
139
|
+
// browser connection, with no polling.
|
|
140
|
+
app.get("/api/agents/:id/stream", async (request, reply) => {
|
|
141
|
+
reply.hijack();
|
|
142
|
+
const webRequest = new NodeRequest({ req: request.raw, res: reply.raw, maxRequestBodySize: 1024 * 1024 });
|
|
143
|
+
webRequest.headers.set("x-hv-client-ip", request.ip);
|
|
144
|
+
const response = await multiplex.open(webRequest, request.params.id);
|
|
145
|
+
response.headers.set("Cache-Control", "no-store");
|
|
146
|
+
await sendNodeResponse(reply.raw, response);
|
|
147
|
+
});
|
|
148
|
+
app.get("/api/agents/:id/sub-agents/:subagentId/runs/events", async (request, reply) => {
|
|
149
|
+
reply.hijack();
|
|
150
|
+
const webRequest = new NodeRequest({ req: request.raw, res: reply.raw, maxRequestBodySize: 1024 * 1024 });
|
|
151
|
+
webRequest.headers.set("x-hv-client-ip", request.ip);
|
|
152
|
+
const response = await runs.open(webRequest, request.params.id, request.params.subagentId);
|
|
153
|
+
await sendNodeResponse(reply.raw, response);
|
|
154
|
+
});
|
|
155
|
+
app.get("/api/agents/:id/sub-agents/:subagentId/runs/:runId/events", async (request, reply) => {
|
|
156
|
+
reply.hijack();
|
|
157
|
+
const webRequest = new NodeRequest({ req: request.raw, res: reply.raw, maxRequestBodySize: 1024 * 1024 });
|
|
158
|
+
webRequest.headers.set("x-hv-client-ip", request.ip);
|
|
159
|
+
const response = await runDetails.open(webRequest, request.params.id, request.params.subagentId, request.params.runId);
|
|
160
|
+
await sendNodeResponse(reply.raw, response);
|
|
161
|
+
});
|
|
162
|
+
// Leave request streams unread for Start (JSON, FormData, etc.). The Node
|
|
163
|
+
// adapter enforces a body limit when Start reads buffered or streamed input.
|
|
164
|
+
app.removeAllContentTypeParsers();
|
|
165
|
+
app.addContentTypeParser("*", (_request, payload, done) => done(null, payload));
|
|
166
|
+
app.all("/*", async (request, reply) => {
|
|
167
|
+
reply.hijack();
|
|
168
|
+
try {
|
|
169
|
+
if (start.middleware && await runMiddleware(start.middleware, request.raw, reply.raw))
|
|
170
|
+
return;
|
|
171
|
+
const webRequest = new NodeRequest({ req: request.raw, res: reply.raw, maxRequestBodySize: 1024 * 1024 });
|
|
172
|
+
// Set this on the Web Request, whose headers may be reconstructed from
|
|
173
|
+
// Node rawHeaders rather than Fastify's normalized header object.
|
|
174
|
+
webRequest.headers.set("x-hv-client-ip", request.ip);
|
|
175
|
+
const response = new URL(webRequest.url).pathname.startsWith("/api/auth/")
|
|
176
|
+
? await runtime.auth.handler(webRequest)
|
|
177
|
+
: await start.fetch(webRequest, { context: { runtime } });
|
|
178
|
+
if (reply.raw.destroyed) {
|
|
179
|
+
await response.body?.cancel();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
// Never cache cookie-sensitive HTML, server functions or auth responses.
|
|
183
|
+
response.headers.set("Cache-Control", "no-store");
|
|
184
|
+
await sendNodeResponse(reply.raw, response);
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
if (error instanceof Error && error.name === "AbortError" && (request.raw.aborted || reply.raw.destroyed))
|
|
188
|
+
return;
|
|
189
|
+
request.log.error(error, "Web request failed");
|
|
190
|
+
if (reply.raw.headersSent)
|
|
191
|
+
reply.raw.destroy();
|
|
192
|
+
else {
|
|
193
|
+
reply.raw.writeHead(500, { "Content-Type": "text/plain" });
|
|
194
|
+
reply.raw.end("Internal Server Error");
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
await app.ready();
|
|
199
|
+
runtime.start();
|
|
200
|
+
return app;
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
await app.close();
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { currentUser } from "../auth-user.js";
|
|
2
|
+
import { AgentError } from "../agents/agent-input.js";
|
|
3
|
+
export function artifactDownloads(app, runtime) {
|
|
4
|
+
app.get("/api/agents/:agentId/artifacts/:id/content", async (request, reply) => {
|
|
5
|
+
reply.header("Cache-Control", "no-store").header("X-Content-Type-Options", "nosniff").header("Content-Security-Policy", "sandbox; default-src 'none'; base-uri 'none'");
|
|
6
|
+
const user = await currentUser(runtime, new Headers({ cookie: request.headers.cookie ?? "" }));
|
|
7
|
+
if (!user)
|
|
8
|
+
return reply.code(401).send({ error: "Authentication required" });
|
|
9
|
+
try {
|
|
10
|
+
await runtime.agents.owned(user.id, request.params.agentId);
|
|
11
|
+
const item = await runtime.agents.research.artifacts.get(request.params.agentId, request.params.id);
|
|
12
|
+
const extension = { "text/markdown": "md", "text/plain": "txt", "text/csv": "csv", "application/json": "json", "image/png": "png", "image/jpeg": "jpg", "image/webp": "webp" }[item.mediaType] ?? "bin";
|
|
13
|
+
const filename = `${item.title.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 80)}.${extension}`;
|
|
14
|
+
const disposition = request.query.inline === "1" && item.mediaType.startsWith("image/") ? "inline" : "attachment";
|
|
15
|
+
return reply.type(item.mediaType).header("Content-Disposition", `${disposition}; filename="${filename}"`).send(item.payload);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error instanceof AgentError)
|
|
19
|
+
return reply.code(error.status).send({ error: error.message });
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Resolves whether middleware sent a response, including streaming/disconnects. */
|
|
2
|
+
export function runMiddleware(middleware, request, response) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
const cleanup = () => {
|
|
5
|
+
response.off("finish", handled);
|
|
6
|
+
response.off("close", handled);
|
|
7
|
+
};
|
|
8
|
+
const handled = () => { cleanup(); resolve(true); };
|
|
9
|
+
response.once("finish", handled);
|
|
10
|
+
response.once("close", handled);
|
|
11
|
+
try {
|
|
12
|
+
middleware(request, response, (error) => {
|
|
13
|
+
cleanup();
|
|
14
|
+
if (error)
|
|
15
|
+
reject(error);
|
|
16
|
+
else
|
|
17
|
+
resolve(false);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
cleanup();
|
|
22
|
+
reject(error);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|