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,79 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import { check, foreignKey, index, integer, primaryKey, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
|
|
3
|
+
import { hvAgents } from "./agent-schema.js";
|
|
4
|
+
export const hvSubagents = sqliteTable("hv_subagents", {
|
|
5
|
+
id: text("id").primaryKey(),
|
|
6
|
+
agentId: text("agent_id").notNull().references(() => hvAgents.id, { onDelete: "cascade" }),
|
|
7
|
+
kind: text("kind", { enum: ["orchestrator", "worker"] }).notNull(),
|
|
8
|
+
name: text("name").notNull(),
|
|
9
|
+
description: text("description").notNull().default(""),
|
|
10
|
+
instructions: text("instructions").notNull(),
|
|
11
|
+
provider: text("provider").notNull(),
|
|
12
|
+
modelId: text("model_id").notNull(),
|
|
13
|
+
thinkingLevel: text("thinking_level").notNull().default(""),
|
|
14
|
+
tools: text("tools", { mode: "json" }).$type().notNull(),
|
|
15
|
+
triggers: text("triggers", { mode: "json" }).$type().notNull().default({ inboxEnabled: false, workerDelegates: [], researchSources: [], fills: false, orderChanges: false }),
|
|
16
|
+
templateOrigin: text("template_origin", { mode: "json" }).$type(),
|
|
17
|
+
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
|
|
18
|
+
archived: integer("archived", { mode: "boolean" }).notNull().default(false),
|
|
19
|
+
delegatable: integer("delegatable", { mode: "boolean" }).notNull().default(true),
|
|
20
|
+
persistent: integer("persistent", { mode: "boolean" }).notNull().default(false),
|
|
21
|
+
conversationId: integer("conversation_id"),
|
|
22
|
+
schedule: text("schedule").notNull().default(""),
|
|
23
|
+
delaySeconds: integer("delay_seconds").notNull().default(1),
|
|
24
|
+
nextRunAt: integer("next_run_at"),
|
|
25
|
+
completion: text("completion", { enum: ["save", "notify", "wake"] }).notNull().default("wake"),
|
|
26
|
+
timeoutSeconds: integer("timeout_seconds").notNull().default(900),
|
|
27
|
+
createdAt: integer("created_at").notNull(),
|
|
28
|
+
updatedAt: integer("updated_at").notNull(),
|
|
29
|
+
}, (t) => [
|
|
30
|
+
index("hv_subagents_agent_idx").on(t.agentId),
|
|
31
|
+
uniqueIndex("hv_subagents_identity_idx").on(t.agentId, t.id),
|
|
32
|
+
uniqueIndex("hv_subagents_main_idx").on(t.agentId).where(sql `${t.kind} = 'orchestrator'`),
|
|
33
|
+
check("hv_subagents_main_protected", sql `${t.kind} != 'orchestrator' OR (${t.enabled} = 1 AND ${t.archived} = 0 AND ${t.schedule} = '')`),
|
|
34
|
+
]);
|
|
35
|
+
export const hvSubagentRuns = sqliteTable("hv_subagent_runs", {
|
|
36
|
+
id: text("id").primaryKey(),
|
|
37
|
+
agentId: text("agent_id").notNull().references(() => hvAgents.id, { onDelete: "cascade" }),
|
|
38
|
+
subagentId: text("subagent_id").notNull().references(() => hvSubagents.id, { onDelete: "cascade" }),
|
|
39
|
+
requestId: text("request_id").notNull(),
|
|
40
|
+
source: text("source", { enum: ["manual", "schedule", "delegation", "event"] }).notNull(),
|
|
41
|
+
task: text("task").notNull(),
|
|
42
|
+
config: text("config", { mode: "json" }).$type().notNull(),
|
|
43
|
+
status: text("status", { enum: ["queued", "running", "completed", "failed", "cancelled", "skipped"] }).notNull().default("queued"),
|
|
44
|
+
taskId: integer("task_id"),
|
|
45
|
+
conversationId: integer("conversation_id"),
|
|
46
|
+
result: text("result").notNull().default(""),
|
|
47
|
+
createdAt: integer("created_at").notNull(),
|
|
48
|
+
finishedAt: integer("finished_at"),
|
|
49
|
+
reportedAt: integer("reported_at"),
|
|
50
|
+
}, (t) => [
|
|
51
|
+
uniqueIndex("hv_subagent_runs_request_idx").on(t.agentId, t.requestId),
|
|
52
|
+
uniqueIndex("hv_subagent_runs_producer_idx").on(t.agentId, t.id, t.subagentId),
|
|
53
|
+
uniqueIndex("hv_subagent_runs_identity_idx").on(t.agentId, t.id),
|
|
54
|
+
uniqueIndex("hv_subagent_runs_active_idx").on(t.subagentId).where(sql `${t.status} IN ('queued', 'running')`),
|
|
55
|
+
index("hv_subagent_runs_history_idx").on(t.subagentId, t.createdAt),
|
|
56
|
+
]);
|
|
57
|
+
/** Activation windows are maintained atomically by the inbox migration's SQLite triggers. */
|
|
58
|
+
export const hvWorkerSubscriptions = sqliteTable("hv_worker_subscriptions", {
|
|
59
|
+
subagentId: text("subagent_id").notNull().references(() => hvSubagents.id, { onDelete: "cascade" }),
|
|
60
|
+
eventType: text("event_type").notNull(),
|
|
61
|
+
sourceId: text("source_id").notNull(),
|
|
62
|
+
activatedAt: integer("activated_at").notNull(),
|
|
63
|
+
}, (t) => [primaryKey({ columns: [t.subagentId, t.eventType, t.sourceId] })]);
|
|
64
|
+
/** Application-owned inbox and request provenance; admission atomically links requests to runs. */
|
|
65
|
+
export const hvWorkerRequests = sqliteTable("hv_worker_requests", {
|
|
66
|
+
id: text("id").primaryKey(),
|
|
67
|
+
agentId: text("agent_id").notNull().references(() => hvAgents.id, { onDelete: "cascade" }),
|
|
68
|
+
subagentId: text("subagent_id").notNull(),
|
|
69
|
+
eventKey: text("event_key").notNull(),
|
|
70
|
+
payload: text("payload", { mode: "json" }).$type().notNull(),
|
|
71
|
+
createdAt: integer("created_at").notNull(),
|
|
72
|
+
runId: text("run_id"),
|
|
73
|
+
discardedReason: text("discarded_reason"),
|
|
74
|
+
}, (t) => [
|
|
75
|
+
foreignKey({ columns: [t.agentId, t.subagentId], foreignColumns: [hvSubagents.agentId, hvSubagents.id] }),
|
|
76
|
+
foreignKey({ columns: [t.agentId, t.runId, t.subagentId], foreignColumns: [hvSubagentRuns.agentId, hvSubagentRuns.id, hvSubagentRuns.subagentId] }),
|
|
77
|
+
uniqueIndex("hv_worker_requests_event_idx").on(t.agentId, t.subagentId, t.eventKey),
|
|
78
|
+
index("hv_worker_requests_pending_idx").on(t.subagentId, t.createdAt).where(sql `${t.runId} IS NULL AND ${t.discardedReason} IS NULL`),
|
|
79
|
+
]);
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { sendTelegramNotification } from "./telegram/transport.js";
|
|
2
|
+
import { NotificationDeliveryError } from "../notifications/delivery.js";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { AgentError } from "../agents/agent-input.js";
|
|
5
|
+
import { bindGatewayChat, decryptGatewayToken, gatewayStatus, getGateway, listGateways } from "./gateway-store.js";
|
|
6
|
+
import { PENDING_LINK_TTL_MS } from "./handlers.js";
|
|
7
|
+
function describe(error) {
|
|
8
|
+
return error instanceof Error ? error.message : String(error);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Owns one gateway platform's endpoints. Event-driven lifecycle: configured
|
|
12
|
+
* gateways start once at startup, and later changes flow through `ensure()`
|
|
13
|
+
* and `removed()` from the settings mutations.
|
|
14
|
+
*/
|
|
15
|
+
export class GatewayBridge {
|
|
16
|
+
db;
|
|
17
|
+
agents;
|
|
18
|
+
key;
|
|
19
|
+
connector;
|
|
20
|
+
options;
|
|
21
|
+
endpoints = new Map();
|
|
22
|
+
startup;
|
|
23
|
+
stoppingEndpoints = new Set();
|
|
24
|
+
pending = new Map();
|
|
25
|
+
errors = new Map();
|
|
26
|
+
started = false;
|
|
27
|
+
stopping = false;
|
|
28
|
+
closing;
|
|
29
|
+
constructor(db, agents, key, connector, options = {}) {
|
|
30
|
+
this.db = db;
|
|
31
|
+
this.agents = agents;
|
|
32
|
+
this.key = key;
|
|
33
|
+
this.connector = connector;
|
|
34
|
+
this.options = options;
|
|
35
|
+
}
|
|
36
|
+
get type() { return this.connector.type; }
|
|
37
|
+
/** The active encryption key; gateway credentials require one on the server. */
|
|
38
|
+
requireKey() {
|
|
39
|
+
if (!this.key)
|
|
40
|
+
throw new AgentError(`${this.connector.label} gateways require AGENTS_ENCRYPTION_KEY on the server.`, 503);
|
|
41
|
+
return this.key;
|
|
42
|
+
}
|
|
43
|
+
/** Loads this platform's configured gateways once and starts their endpoints. */
|
|
44
|
+
start() {
|
|
45
|
+
if (this.started || this.stopping)
|
|
46
|
+
return;
|
|
47
|
+
this.started = true;
|
|
48
|
+
this.startup = listGateways(this.db, this.type).then(async (rows) => { await Promise.all(rows.map((row) => this.startEndpoint(row))); })
|
|
49
|
+
.catch((error) => { if (!this.stopping)
|
|
50
|
+
this.options.logger?.error(`Unable to start ${this.connector.label} bridge: ${describe(error)}`); });
|
|
51
|
+
}
|
|
52
|
+
/** Starts the endpoint after a gateway row was created, if it is not running yet. */
|
|
53
|
+
async ensure(agentId) {
|
|
54
|
+
if (this.stopping || this.endpoints.has(agentId))
|
|
55
|
+
return;
|
|
56
|
+
const row = await getGateway(this.db, agentId, this.type);
|
|
57
|
+
if (row)
|
|
58
|
+
await this.startEndpoint(row);
|
|
59
|
+
}
|
|
60
|
+
/** Stops the endpoint and drops pending links: disconnect or agent deletion. */
|
|
61
|
+
async removed(agentId) {
|
|
62
|
+
for (const [token, link] of this.pending)
|
|
63
|
+
if (link.agentId === agentId)
|
|
64
|
+
this.pending.delete(token);
|
|
65
|
+
this.errors.delete(agentId);
|
|
66
|
+
const endpoint = this.endpoints.get(agentId);
|
|
67
|
+
if (!endpoint)
|
|
68
|
+
return;
|
|
69
|
+
this.endpoints.delete(agentId);
|
|
70
|
+
await this.stopEndpoint(endpoint);
|
|
71
|
+
}
|
|
72
|
+
/** Creates or returns the owner's pending link token and its deep-link URL. */
|
|
73
|
+
async startLink(agentId, userId) {
|
|
74
|
+
const row = await getGateway(this.db, agentId, this.type);
|
|
75
|
+
if (!row)
|
|
76
|
+
throw new AgentError(`Add a ${this.connector.label} bot token first.`, 400);
|
|
77
|
+
let existing;
|
|
78
|
+
for (const [token, link] of this.pending) {
|
|
79
|
+
if (link.agentId !== agentId)
|
|
80
|
+
continue;
|
|
81
|
+
if (link.userId !== userId || link.expiresAt <= Date.now())
|
|
82
|
+
this.pending.delete(token);
|
|
83
|
+
else
|
|
84
|
+
existing = { ...link, token };
|
|
85
|
+
}
|
|
86
|
+
const link = existing ?? { token: randomUUID(), agentId, userId, expiresAt: Date.now() + PENDING_LINK_TTL_MS };
|
|
87
|
+
this.pending.set(link.token, link);
|
|
88
|
+
return this.connector.linkUrl(row, link.token);
|
|
89
|
+
}
|
|
90
|
+
/** A queued notification is bound to its original destination, never a newly linked chat. */
|
|
91
|
+
async sendNotification(target, text, signal) {
|
|
92
|
+
if (this.stopping)
|
|
93
|
+
throw new NotificationDeliveryError("Gateway is shutting down");
|
|
94
|
+
const row = await getGateway(this.db, target.agentId, this.type);
|
|
95
|
+
if (!row || row.chatId !== target.chatId || row.botTokenHash !== target.botTokenHash)
|
|
96
|
+
throw new NotificationDeliveryError("Telegram destination changed", true, undefined, true);
|
|
97
|
+
const token = decryptGatewayToken(this.key, row);
|
|
98
|
+
if (!token)
|
|
99
|
+
throw new NotificationDeliveryError("Telegram token cannot be decrypted; reconnect Telegram in settings", true);
|
|
100
|
+
return sendTelegramNotification(token, target.chatId, text, signal);
|
|
101
|
+
}
|
|
102
|
+
/** Render-safe gateway state for the settings page. */
|
|
103
|
+
async status(agentId) {
|
|
104
|
+
const row = await getGateway(this.db, agentId, this.type);
|
|
105
|
+
return gatewayStatus(row, this.errors.get(agentId));
|
|
106
|
+
}
|
|
107
|
+
/** Stops every endpoint and drops all link state. */
|
|
108
|
+
close() {
|
|
109
|
+
return this.closing ??= (async () => {
|
|
110
|
+
this.stopping = true;
|
|
111
|
+
// An initial gateway query must finish before the runtime closes its database.
|
|
112
|
+
await this.startup;
|
|
113
|
+
const endpoints = [...this.endpoints.values()];
|
|
114
|
+
this.endpoints.clear();
|
|
115
|
+
this.pending.clear();
|
|
116
|
+
await Promise.all(endpoints.map((endpoint) => this.stopEndpoint(endpoint)));
|
|
117
|
+
while (this.stoppingEndpoints.size)
|
|
118
|
+
await Promise.all([...this.stoppingEndpoints]);
|
|
119
|
+
})();
|
|
120
|
+
}
|
|
121
|
+
async startEndpoint(row) {
|
|
122
|
+
if (this.stopping || this.endpoints.has(row.agentId))
|
|
123
|
+
return;
|
|
124
|
+
const token = decryptGatewayToken(this.key, row);
|
|
125
|
+
if (!token) {
|
|
126
|
+
this.errors.set(row.agentId, "The bot token cannot be decrypted with the active encryption key. Re-add the bot token in settings.");
|
|
127
|
+
this.options.logger?.warn(`Bot token for agent ${row.agentId} cannot be decrypted; endpoint not started`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const state = {
|
|
131
|
+
endpoint: this.connector.createEndpoint(token, (message) => {
|
|
132
|
+
if (!this.stopping && this.endpoints.get(row.agentId) === state && !state.lifetime.signal.aborted) {
|
|
133
|
+
this.track(state, this.receive(row.agentId, message, state));
|
|
134
|
+
}
|
|
135
|
+
}, this.options.logger),
|
|
136
|
+
lifetime: new AbortController(), tasks: new Set(),
|
|
137
|
+
};
|
|
138
|
+
this.endpoints.set(row.agentId, state);
|
|
139
|
+
this.errors.delete(row.agentId);
|
|
140
|
+
void state.endpoint.start().then(() => {
|
|
141
|
+
void this.stopEndpoint(state);
|
|
142
|
+
if (this.endpoints.get(row.agentId) === state)
|
|
143
|
+
this.endpoints.delete(row.agentId);
|
|
144
|
+
}, (error) => {
|
|
145
|
+
const expected = this.stopping || state.lifetime.signal.aborted;
|
|
146
|
+
void this.stopEndpoint(state);
|
|
147
|
+
if (this.endpoints.get(row.agentId) !== state)
|
|
148
|
+
return;
|
|
149
|
+
this.endpoints.delete(row.agentId);
|
|
150
|
+
if (expected)
|
|
151
|
+
return;
|
|
152
|
+
this.errors.set(row.agentId, describe(error));
|
|
153
|
+
this.options.logger?.warn(`${this.connector.label} endpoint for agent ${row.agentId} stopped: ${describe(error)}`);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
workspace(state) {
|
|
157
|
+
return {
|
|
158
|
+
signal: state.lifetime.signal,
|
|
159
|
+
track: (task) => this.track(state, task),
|
|
160
|
+
loadGateway: (agentId) => getGateway(this.db, agentId, this.type),
|
|
161
|
+
bindChat: (agentId, chatId, chatUsername) => bindGatewayChat(this.db, agentId, this.type, chatId, chatUsername),
|
|
162
|
+
consumeLink: (token) => this.consumeLink(token),
|
|
163
|
+
bridge: async (agentId) => {
|
|
164
|
+
state.lifetime.signal.throwIfAborted();
|
|
165
|
+
const handle = await this.agents.bridge(agentId);
|
|
166
|
+
state.lifetime.signal.throwIfAborted();
|
|
167
|
+
return handle;
|
|
168
|
+
},
|
|
169
|
+
logger: this.options.logger,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/** One-shot link consumption; the token dies with its first use or its expiry. */
|
|
173
|
+
consumeLink(token) {
|
|
174
|
+
const link = this.pending.get(token);
|
|
175
|
+
if (!link)
|
|
176
|
+
return { status: "unknown" };
|
|
177
|
+
this.pending.delete(token);
|
|
178
|
+
if (link.expiresAt <= Date.now())
|
|
179
|
+
return { status: "expired" };
|
|
180
|
+
return { status: "ok", agentId: link.agentId };
|
|
181
|
+
}
|
|
182
|
+
track(state, task) {
|
|
183
|
+
state.tasks.add(task);
|
|
184
|
+
void task.then(() => state.tasks.delete(task), () => state.tasks.delete(task));
|
|
185
|
+
}
|
|
186
|
+
stopEndpoint(state) {
|
|
187
|
+
if (state.closing)
|
|
188
|
+
return state.closing;
|
|
189
|
+
const closing = state.closing = (async () => {
|
|
190
|
+
state.lifetime.abort();
|
|
191
|
+
const stopped = state.endpoint.stop().catch((error) => {
|
|
192
|
+
this.options.logger?.warn(`${this.connector.label} endpoint stop failed: ${describe(error)}`);
|
|
193
|
+
});
|
|
194
|
+
// A message handler can register a reply forwarder while it finishes.
|
|
195
|
+
while (state.tasks.size)
|
|
196
|
+
await Promise.allSettled([...state.tasks]);
|
|
197
|
+
await stopped;
|
|
198
|
+
})();
|
|
199
|
+
this.stoppingEndpoints.add(closing);
|
|
200
|
+
void closing.then(() => this.stoppingEndpoints.delete(closing), () => this.stoppingEndpoints.delete(closing));
|
|
201
|
+
return closing;
|
|
202
|
+
}
|
|
203
|
+
async receive(agentId, message, state) {
|
|
204
|
+
const lifetime = state.lifetime.signal;
|
|
205
|
+
const sender = {
|
|
206
|
+
sendText: async (chatId, text, signal) => {
|
|
207
|
+
lifetime.throwIfAborted();
|
|
208
|
+
return state.endpoint.sendText(chatId, text, signal ? AbortSignal.any([signal, lifetime]) : lifetime);
|
|
209
|
+
},
|
|
210
|
+
sendTyping: async (chatId, signal) => {
|
|
211
|
+
lifetime.throwIfAborted();
|
|
212
|
+
return state.endpoint.sendTyping(chatId, signal ? AbortSignal.any([signal, lifetime]) : lifetime);
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
try {
|
|
216
|
+
await this.connector.handle(agentId, message, this.workspace(state), sender);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
if (!lifetime.aborted)
|
|
220
|
+
this.options.logger?.warn(`${this.connector.label} message handling for agent ${agentId} failed: ${describe(error)}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { and, eq } from "drizzle-orm";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { AgentError } from "../agents/agent-input.js";
|
|
4
|
+
import { hvGateways } from "../db/gateway-schema.js";
|
|
5
|
+
import { decryptSecret, encryptSecret } from "../hyperliquid/crypto.js";
|
|
6
|
+
/** Deterministic token fingerprint backing the cross-Agent uniqueness constraint. */
|
|
7
|
+
export function hashBotToken(token) {
|
|
8
|
+
return createHash("sha256").update(token).digest("hex");
|
|
9
|
+
}
|
|
10
|
+
export async function getGateway(db, agentId, type) {
|
|
11
|
+
return db.select().from(hvGateways).where(and(eq(hvGateways.agentId, agentId), eq(hvGateways.type, type))).get();
|
|
12
|
+
}
|
|
13
|
+
/** Every configured gateway of one type; token presence means the endpoint should run. */
|
|
14
|
+
export async function listGateways(db, type) {
|
|
15
|
+
return db.select().from(hvGateways).where(eq(hvGateways.type, type)).all();
|
|
16
|
+
}
|
|
17
|
+
/** The bot token of one configured gateway; undefined when the encryption key is missing or changed. */
|
|
18
|
+
export function decryptGatewayToken(key, row) {
|
|
19
|
+
if (!key || row.keyId !== key.id)
|
|
20
|
+
return undefined;
|
|
21
|
+
try {
|
|
22
|
+
return decryptSecret(key, row.botTokenCiphertext);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function uniqueTokenViolation(error) {
|
|
29
|
+
let current = error;
|
|
30
|
+
for (let depth = 0; current !== null && typeof current === "object" && depth < 5; depth++) {
|
|
31
|
+
const message = current.message;
|
|
32
|
+
if (typeof message === "string" && message.includes("UNIQUE constraint failed") && message.includes("bot_token_hash"))
|
|
33
|
+
return true;
|
|
34
|
+
current = current.cause;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
/** Stores a newly validated bot token; the token hash stops two Agents sharing one bot. */
|
|
39
|
+
export async function saveGatewayToken(db, key, agentId, type, token, botUsername) {
|
|
40
|
+
const values = {
|
|
41
|
+
botTokenCiphertext: Buffer.from(encryptSecret(key, token)),
|
|
42
|
+
botTokenHash: hashBotToken(token),
|
|
43
|
+
keyId: key.id,
|
|
44
|
+
botUsername,
|
|
45
|
+
updatedAt: Date.now(),
|
|
46
|
+
};
|
|
47
|
+
try {
|
|
48
|
+
await db.insert(hvGateways).values({ agentId, type, ...values }).run();
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (uniqueTokenViolation(error))
|
|
52
|
+
throw new AgentError("This bot is already linked to another Agent.", 409);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Persists the chat that completed the link flow; false when no gateway row exists. */
|
|
57
|
+
export async function bindGatewayChat(db, agentId, type, chatId, chatUsername) {
|
|
58
|
+
const row = await getGateway(db, agentId, type);
|
|
59
|
+
if (!row)
|
|
60
|
+
return false;
|
|
61
|
+
await db.update(hvGateways).set({ chatId, chatUsername, updatedAt: Date.now() }).where(and(eq(hvGateways.agentId, agentId), eq(hvGateways.type, type))).run();
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
/** Removes the bot token and binding; false when no gateway row exists. */
|
|
65
|
+
export async function deleteGateway(db, agentId, type) {
|
|
66
|
+
const row = await getGateway(db, agentId, type);
|
|
67
|
+
if (!row)
|
|
68
|
+
return false;
|
|
69
|
+
await db.delete(hvGateways).where(and(eq(hvGateways.agentId, agentId), eq(hvGateways.type, type))).run();
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
/** Status view of a gateway row, extended with an optional runtime endpoint error. */
|
|
73
|
+
export function gatewayStatus(row, error) {
|
|
74
|
+
if (!row)
|
|
75
|
+
return { hasToken: false, connected: false, botUsername: null, chatId: null, chatUsername: null };
|
|
76
|
+
return { hasToken: true, connected: row.chatId !== null, botUsername: row.botUsername, chatId: row.chatId, chatUsername: row.chatUsername, ...(error ? { error } : {}) };
|
|
77
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { awaitWithContext, BACKGROUND_CONTEXT as context, withAbortSignal } from "@earendil-works/chord/context";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
4
|
+
import { isAgentError } from "../agents/agent-input.js";
|
|
5
|
+
/** A deep-link token is valid for ten minutes, matching the legacy gateway. */
|
|
6
|
+
export const PENDING_LINK_TTL_MS = 10 * 60 * 1000;
|
|
7
|
+
/** How long the bridge forwards one turn's reply before giving up on it. */
|
|
8
|
+
export const REPLY_TIMEOUT_MS = 30 * 60 * 1000;
|
|
9
|
+
/** The typing action expires after ~5 seconds and is refreshed while a turn runs. */
|
|
10
|
+
const TYPING_REFRESH_MS = 4500;
|
|
11
|
+
/** Chunked for the platform's message limit; split by code points so emoji survive. */
|
|
12
|
+
export function chunkText(text, max) {
|
|
13
|
+
const characters = [...text];
|
|
14
|
+
const chunks = [];
|
|
15
|
+
for (let index = 0; index < characters.length; index += max)
|
|
16
|
+
chunks.push(characters.slice(index, index + max).join(""));
|
|
17
|
+
return chunks.length ? chunks : [""];
|
|
18
|
+
}
|
|
19
|
+
/** A public, bounded error message; AgentError and plain reasons carry operator-facing text. */
|
|
20
|
+
export function bridgeErrorText(error) {
|
|
21
|
+
const detail = typeof error === "string" ? error : isAgentError(error) || error instanceof Error ? error.message : "Unknown error";
|
|
22
|
+
return `I couldn't process that message: ${[...detail].slice(0, 1000).join("")}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The operator-facing text of a terminal submission. `reason` is a machine code such as `model_error`;
|
|
26
|
+
* `detail` carries the provider's actual message, which is what an operator can act on.
|
|
27
|
+
*/
|
|
28
|
+
export function submissionErrorText(settled) {
|
|
29
|
+
const detail = typeof settled.detail === "string" ? settled.detail.trim() : "";
|
|
30
|
+
return detail || settled.reason;
|
|
31
|
+
}
|
|
32
|
+
/** Refreshes typing only while forwarding owns it; joins any in-flight typing request. */
|
|
33
|
+
async function withTyping(sender, chatId, operation, lifetime) {
|
|
34
|
+
const stop = new AbortController();
|
|
35
|
+
const signal = lifetime ? AbortSignal.any([stop.signal, lifetime]) : stop.signal;
|
|
36
|
+
const typing = (async () => {
|
|
37
|
+
while (!signal.aborted) {
|
|
38
|
+
await sender.sendTyping(chatId, signal).catch(() => undefined);
|
|
39
|
+
if (!signal.aborted)
|
|
40
|
+
await delay(TYPING_REFRESH_MS, undefined, { signal }).catch(() => undefined);
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
43
|
+
try {
|
|
44
|
+
await operation();
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
stop.abort();
|
|
48
|
+
await typing;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Forwards the assistant reply once the submitted turn settles. */
|
|
52
|
+
export async function forwardReply(workspace, sender, chatId, handle, submission) {
|
|
53
|
+
const timeout = workspace.replyTimeoutMs ?? REPLY_TIMEOUT_MS;
|
|
54
|
+
const expired = new AbortController();
|
|
55
|
+
const timer = setTimeout(() => expired.abort(), timeout);
|
|
56
|
+
const signal = workspace.signal ? AbortSignal.any([workspace.signal, expired.signal]) : expired.signal;
|
|
57
|
+
try {
|
|
58
|
+
await withTyping(sender, chatId, async () => {
|
|
59
|
+
let settled;
|
|
60
|
+
try {
|
|
61
|
+
signal.throwIfAborted();
|
|
62
|
+
const invocation = withAbortSignal(signal, context);
|
|
63
|
+
settled = await awaitWithContext(submission.wait(invocation), invocation);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (workspace.signal?.aborted)
|
|
67
|
+
return;
|
|
68
|
+
if (!expired.signal.aborted)
|
|
69
|
+
throw error;
|
|
70
|
+
await sender.sendText(chatId, "This response is taking longer than expected. The turn is still running; continue in the web dashboard.", workspace.signal);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
workspace.signal?.throwIfAborted();
|
|
74
|
+
if (settled.status === "unanswered" || settled.entry === undefined || settled.answer === undefined) {
|
|
75
|
+
await sender.sendText(chatId, bridgeErrorText(settled.status === "unanswered" ? submissionErrorText(settled) : "The turn produced no reply"), workspace.signal);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const replies = await handle.replyText(settled.entry, settled.answer);
|
|
79
|
+
for (const reply of replies) {
|
|
80
|
+
workspace.signal?.throwIfAborted();
|
|
81
|
+
await sender.sendText(chatId, reply, workspace.signal);
|
|
82
|
+
}
|
|
83
|
+
}, workspace.signal);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (!workspace.signal?.aborted)
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** Submits plain chat text to the Agent's main conversation and forwards the reply in the background. */
|
|
94
|
+
export async function submitChat(agentId, chatId, text, workspace, sender) {
|
|
95
|
+
let handle;
|
|
96
|
+
let submission;
|
|
97
|
+
try {
|
|
98
|
+
workspace.signal?.throwIfAborted();
|
|
99
|
+
handle = await workspace.bridge(agentId);
|
|
100
|
+
workspace.signal?.throwIfAborted();
|
|
101
|
+
submission = await handle.submit(text, randomUUID());
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (!workspace.signal?.aborted)
|
|
105
|
+
await sender.sendText(chatId, bridgeErrorText(error), workspace.signal);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (workspace.signal?.aborted)
|
|
109
|
+
return;
|
|
110
|
+
const status = await submission.status(context).catch(() => undefined);
|
|
111
|
+
if (workspace.signal?.aborted)
|
|
112
|
+
return;
|
|
113
|
+
if (status?.status === "queued")
|
|
114
|
+
await sender.sendText(chatId, "Message queued. It will send when the current turn finishes.", workspace.signal);
|
|
115
|
+
// The turn runs in the background so the next message is picked up immediately,
|
|
116
|
+
// matching the legacy gateway's fire-and-forget reply forwarder.
|
|
117
|
+
const forwarding = forwardReply(workspace, sender, chatId, handle, submission).catch((error) => {
|
|
118
|
+
if (!workspace.signal?.aborted)
|
|
119
|
+
workspace.logger?.warn("Gateway reply forwarding failed", error);
|
|
120
|
+
});
|
|
121
|
+
workspace.track?.(forwarding);
|
|
122
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { bridgeErrorText, submitChat } from "../handlers.js";
|
|
2
|
+
import { grammyEndpoint } from "./transport.js";
|
|
3
|
+
/** Splits a `/name[@bot] args` message; undefined for plain text. */
|
|
4
|
+
function parseCommand(text) {
|
|
5
|
+
const match = /^\/([a-zA-Z]+)(?:@[a-zA-Z0-9_]+)?(?:\s+([\s\S]*))?$/.exec(text);
|
|
6
|
+
const name = match?.[1]?.toLowerCase();
|
|
7
|
+
if (!name)
|
|
8
|
+
return undefined;
|
|
9
|
+
return { name, arg: (match?.[2] ?? "").trim() };
|
|
10
|
+
}
|
|
11
|
+
/** The `/start <token>` payload of a link deep link; undefined for other messages. */
|
|
12
|
+
function extractStartPayload(text) {
|
|
13
|
+
const command = parseCommand(text);
|
|
14
|
+
if (command?.name !== "start")
|
|
15
|
+
return undefined;
|
|
16
|
+
return command.arg || undefined;
|
|
17
|
+
}
|
|
18
|
+
const HELP_TEXT = [
|
|
19
|
+
"Commands:",
|
|
20
|
+
"/reset — start a fresh conversation",
|
|
21
|
+
"/stop — stop the active turn",
|
|
22
|
+
"/compact — compact the conversation",
|
|
23
|
+
"/help — show this help",
|
|
24
|
+
"Everything else goes to this Agent's main conversation.",
|
|
25
|
+
].join("\n");
|
|
26
|
+
async function consumeStart(agentId, message, token, workspace, sender) {
|
|
27
|
+
const result = workspace.consumeLink(token);
|
|
28
|
+
if (result.status === "unknown") {
|
|
29
|
+
await sender.sendText(message.chatId, "This link token is unknown or has expired. Start a new link from the web UI.");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (result.status === "expired") {
|
|
33
|
+
await sender.sendText(message.chatId, "This link token has expired. Start a new link from the web UI.");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (result.agentId !== agentId) {
|
|
37
|
+
await sender.sendText(message.chatId, "This link token belongs to a different agent.");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const bound = await workspace.bindChat(agentId, message.chatId, message.fromUsername);
|
|
41
|
+
if (!bound) {
|
|
42
|
+
await sender.sendText(message.chatId, "This Telegram gateway is no longer configured. Start a new link from the web UI.");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
await sender.sendText(message.chatId, "Telegram chat linked. You can now use this chat with HyperVibes.");
|
|
46
|
+
}
|
|
47
|
+
async function handleCommand(agentId, chatId, command, workspace, sender) {
|
|
48
|
+
if (command.name === "help") {
|
|
49
|
+
await sender.sendText(chatId, HELP_TEXT);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
let handle;
|
|
53
|
+
try {
|
|
54
|
+
handle = await workspace.bridge(agentId);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
await sender.sendText(chatId, bridgeErrorText(error));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
if (command.name === "stop") {
|
|
62
|
+
await handle.stop();
|
|
63
|
+
await sender.sendText(chatId, "Active turn stopped.");
|
|
64
|
+
}
|
|
65
|
+
else if (command.name === "reset") {
|
|
66
|
+
await handle.reset();
|
|
67
|
+
await sender.sendText(chatId, "Started a fresh conversation.");
|
|
68
|
+
}
|
|
69
|
+
else if (command.name === "compact") {
|
|
70
|
+
const result = await handle.compact();
|
|
71
|
+
await sender.sendText(chatId, result.message ?? "Conversation compacted.");
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
await sender.sendText(chatId, HELP_TEXT);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
workspace.logger?.warn("Telegram command failed", error);
|
|
79
|
+
await sender.sendText(chatId, bridgeErrorText(error));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function handleTelegramMessage(agentId, message, workspace, sender) {
|
|
83
|
+
const text = message.text.trim();
|
|
84
|
+
const startToken = extractStartPayload(text);
|
|
85
|
+
if (startToken) {
|
|
86
|
+
await consumeStart(agentId, message, startToken, workspace, sender);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const command = parseCommand(text);
|
|
90
|
+
if (command?.name === "start") {
|
|
91
|
+
// `/start` without a payload: guide the operator toward the link flow.
|
|
92
|
+
await sender.sendText(message.chatId, "To link this chat, open your Agent's settings page and start a Telegram link.");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const gateway = await workspace.loadGateway(agentId);
|
|
96
|
+
// Only the chat that completed the link flow may talk to the Agent.
|
|
97
|
+
if (!gateway || gateway.chatId === null || gateway.chatId !== message.chatId) {
|
|
98
|
+
workspace.logger?.warn(`Telegram message from unauthorized chat ${message.chatId} ignored`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (command) {
|
|
102
|
+
await handleCommand(agentId, message.chatId, command, workspace, sender);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (text)
|
|
106
|
+
await submitChat(agentId, message.chatId, text, workspace, sender);
|
|
107
|
+
}
|
|
108
|
+
/** The Telegram platform: deep links, commands, and the chat authorization model. */
|
|
109
|
+
export const telegramConnector = {
|
|
110
|
+
type: "telegram",
|
|
111
|
+
label: "Telegram",
|
|
112
|
+
createEndpoint: grammyEndpoint,
|
|
113
|
+
handle: handleTelegramMessage,
|
|
114
|
+
linkUrl: (row, token) => `https://t.me/${row.botUsername}?start=${token}`,
|
|
115
|
+
};
|