opencandle 0.5.0 → 0.7.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/README.md +170 -186
- package/dist/analysts/contracts.d.ts +1 -3
- package/dist/analysts/contracts.js +1 -11
- package/dist/analysts/contracts.js.map +1 -1
- package/dist/analysts/orchestrator.d.ts +1 -3
- package/dist/analysts/orchestrator.js +1 -26
- package/dist/analysts/orchestrator.js.map +1 -1
- package/dist/cli.js +66 -7
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +13 -3
- package/dist/config.js +25 -5
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infra/cache.d.ts +8 -11
- package/dist/infra/cache.js +17 -15
- package/dist/infra/cache.js.map +1 -1
- package/dist/infra/http-client.d.ts +4 -1
- package/dist/infra/http-client.js +59 -6
- package/dist/infra/http-client.js.map +1 -1
- package/dist/infra/index.d.ts +2 -3
- package/dist/infra/index.js +2 -3
- package/dist/infra/index.js.map +1 -1
- package/dist/infra/native-dependencies.js +2 -2
- package/dist/infra/native-dependencies.js.map +1 -1
- package/dist/infra/node-version.js.map +1 -1
- package/dist/infra/opencandle-paths.d.ts +0 -3
- package/dist/infra/opencandle-paths.js +4 -11
- package/dist/infra/opencandle-paths.js.map +1 -1
- package/dist/infra/rate-limiter.js +12 -9
- package/dist/infra/rate-limiter.js.map +1 -1
- package/dist/market-state/alert-conditions.d.ts +34 -0
- package/dist/market-state/alert-conditions.js +23 -0
- package/dist/market-state/alert-conditions.js.map +1 -0
- package/dist/market-state/alert-runner.d.ts +55 -0
- package/dist/market-state/alert-runner.js +634 -0
- package/dist/market-state/alert-runner.js.map +1 -0
- package/dist/market-state/daily-report.d.ts +26 -0
- package/dist/market-state/daily-report.js +179 -0
- package/dist/market-state/daily-report.js.map +1 -0
- package/dist/market-state/local-automation-service.d.ts +25 -0
- package/dist/market-state/local-automation-service.js +119 -0
- package/dist/market-state/local-automation-service.js.map +1 -0
- package/dist/market-state/notification-delivery.d.ts +14 -0
- package/dist/market-state/notification-delivery.js +139 -0
- package/dist/market-state/notification-delivery.js.map +1 -0
- package/dist/market-state/resolve-for-mutation.d.ts +10 -0
- package/dist/market-state/resolve-for-mutation.js +15 -0
- package/dist/market-state/resolve-for-mutation.js.map +1 -0
- package/dist/market-state/resolve.d.ts +14 -0
- package/dist/market-state/resolve.js +89 -0
- package/dist/market-state/resolve.js.map +1 -0
- package/dist/market-state/service.d.ts +527 -0
- package/dist/market-state/service.js +1099 -0
- package/dist/market-state/service.js.map +1 -0
- package/dist/memory/index.d.ts +7 -7
- package/dist/memory/index.js +6 -6
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/manager.js +11 -11
- package/dist/memory/manager.js.map +1 -1
- package/dist/memory/retrieval.js +7 -4
- package/dist/memory/retrieval.js.map +1 -1
- package/dist/memory/sqlite.js +385 -3
- package/dist/memory/sqlite.js.map +1 -1
- package/dist/memory/storage.js +1 -2
- package/dist/memory/storage.js.map +1 -1
- package/dist/memory/tool-defaults.js +64 -28
- package/dist/memory/tool-defaults.js.map +1 -1
- package/dist/memory/types.js.map +1 -1
- package/dist/monitor.d.ts +2 -0
- package/dist/monitor.js +104 -0
- package/dist/monitor.js.map +1 -0
- package/dist/onboarding/connect.d.ts +2 -2
- package/dist/onboarding/connect.js +13 -8
- package/dist/onboarding/connect.js.map +1 -1
- package/dist/onboarding/credential-interceptor.js +1 -1
- package/dist/onboarding/credential-interceptor.js.map +1 -1
- package/dist/onboarding/degradation-accumulator.js +1 -3
- package/dist/onboarding/degradation-accumulator.js.map +1 -1
- package/dist/onboarding/provider-status.d.ts +48 -0
- package/dist/onboarding/provider-status.js +285 -0
- package/dist/onboarding/provider-status.js.map +1 -0
- package/dist/onboarding/providers.d.ts +85 -8
- package/dist/onboarding/providers.js +83 -18
- package/dist/onboarding/providers.js.map +1 -1
- package/dist/onboarding/state.d.ts +1 -0
- package/dist/onboarding/state.js +5 -0
- package/dist/onboarding/state.js.map +1 -1
- package/dist/onboarding/tool-helpers.js +1 -1
- package/dist/onboarding/tool-helpers.js.map +1 -1
- package/dist/onboarding/tool-tags.d.ts +12 -1
- package/dist/onboarding/tool-tags.js +37 -5
- package/dist/onboarding/tool-tags.js.map +1 -1
- package/dist/onboarding/validation.d.ts +2 -2
- package/dist/onboarding/validation.js +1 -1
- package/dist/onboarding/validation.js.map +1 -1
- package/dist/pi/opencandle-extension.d.ts +8 -0
- package/dist/pi/opencandle-extension.js +502 -42
- package/dist/pi/opencandle-extension.js.map +1 -1
- package/dist/pi/session.d.ts +1 -1
- package/dist/pi/session.js +3 -1
- package/dist/pi/session.js.map +1 -1
- package/dist/pi/setup.js +8 -3
- package/dist/pi/setup.js.map +1 -1
- package/dist/pi/tool-adapter.d.ts +4 -1
- package/dist/pi/tool-adapter.js +10 -6
- package/dist/pi/tool-adapter.js.map +1 -1
- package/dist/prompts/context-builder.d.ts +1 -1
- package/dist/prompts/context-builder.js +20 -7
- package/dist/prompts/context-builder.js.map +1 -1
- package/dist/prompts/policy-cards.d.ts +1 -1
- package/dist/prompts/policy-cards.js +2 -2
- package/dist/prompts/policy-cards.js.map +1 -1
- package/dist/prompts/sections.d.ts +1 -1
- package/dist/prompts/symbol-preflight.d.ts +20 -0
- package/dist/prompts/symbol-preflight.js +49 -0
- package/dist/prompts/symbol-preflight.js.map +1 -0
- package/dist/prompts/workflow-prompts.d.ts +1 -1
- package/dist/prompts/workflow-prompts.js +54 -16
- package/dist/prompts/workflow-prompts.js.map +1 -1
- package/dist/providers/alpha-vantage.d.ts +1 -1
- package/dist/providers/alpha-vantage.js +26 -7
- package/dist/providers/alpha-vantage.js.map +1 -1
- package/dist/providers/coingecko.js +1 -1
- package/dist/providers/coingecko.js.map +1 -1
- package/dist/providers/errors.d.ts +5 -0
- package/dist/providers/errors.js +11 -0
- package/dist/providers/errors.js.map +1 -0
- package/dist/providers/exa-search.d.ts +2 -2
- package/dist/providers/exa-search.js +19 -11
- package/dist/providers/exa-search.js.map +1 -1
- package/dist/providers/external-tool-error.d.ts +10 -0
- package/dist/providers/external-tool-error.js +21 -0
- package/dist/providers/external-tool-error.js.map +1 -0
- package/dist/providers/fear-greed.js +1 -1
- package/dist/providers/fear-greed.js.map +1 -1
- package/dist/providers/finnhub.js +3 -5
- package/dist/providers/finnhub.js.map +1 -1
- package/dist/providers/fred.js +2 -2
- package/dist/providers/fred.js.map +1 -1
- package/dist/providers/index.d.ts +7 -6
- package/dist/providers/index.js +6 -5
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/reddit-cli.d.ts +36 -0
- package/dist/providers/reddit-cli.js +201 -0
- package/dist/providers/reddit-cli.js.map +1 -0
- package/dist/providers/reddit.d.ts +1 -1
- package/dist/providers/reddit.js +9 -37
- package/dist/providers/reddit.js.map +1 -1
- package/dist/providers/sec-edgar.d.ts +1 -0
- package/dist/providers/sec-edgar.js +12 -4
- package/dist/providers/sec-edgar.js.map +1 -1
- package/dist/providers/tradingview.d.ts +47 -0
- package/dist/providers/tradingview.js +275 -0
- package/dist/providers/tradingview.js.map +1 -0
- package/dist/providers/twitter-cli.d.ts +40 -0
- package/dist/providers/twitter-cli.js +153 -0
- package/dist/providers/twitter-cli.js.map +1 -0
- package/dist/providers/twitter.d.ts +0 -8
- package/dist/providers/twitter.js +8 -60
- package/dist/providers/twitter.js.map +1 -1
- package/dist/providers/web-search.js +26 -12
- package/dist/providers/web-search.js.map +1 -1
- package/dist/providers/with-fallback.js +4 -2
- package/dist/providers/with-fallback.js.map +1 -1
- package/dist/providers/wrap-provider.d.ts +2 -3
- package/dist/providers/wrap-provider.js +44 -8
- package/dist/providers/wrap-provider.js.map +1 -1
- package/dist/providers/yahoo-finance.d.ts +1 -1
- package/dist/providers/yahoo-finance.js +153 -48
- package/dist/providers/yahoo-finance.js.map +1 -1
- package/dist/routing/classify-intent.d.ts +6 -0
- package/dist/routing/classify-intent.js +78 -7
- package/dist/routing/classify-intent.js.map +1 -1
- package/dist/routing/defaults.d.ts +1 -1
- package/dist/routing/entity-extractor.d.ts +1 -0
- package/dist/routing/entity-extractor.js +234 -29
- package/dist/routing/entity-extractor.js.map +1 -1
- package/dist/routing/fund-symbols.d.ts +2 -0
- package/dist/routing/fund-symbols.js +55 -0
- package/dist/routing/fund-symbols.js.map +1 -0
- package/dist/routing/horizon.d.ts +1 -0
- package/dist/routing/horizon.js +10 -0
- package/dist/routing/horizon.js.map +1 -0
- package/dist/routing/index.d.ts +10 -10
- package/dist/routing/index.js +6 -6
- package/dist/routing/index.js.map +1 -1
- package/dist/routing/planning.d.ts +2 -2
- package/dist/routing/planning.js +65 -34
- package/dist/routing/planning.js.map +1 -1
- package/dist/routing/route-manifest.d.ts +2 -2
- package/dist/routing/route-manifest.js +25 -4
- package/dist/routing/route-manifest.js.map +1 -1
- package/dist/routing/router-llm-client.js.map +1 -1
- package/dist/routing/router-prompt.js +7 -9
- package/dist/routing/router-prompt.js.map +1 -1
- package/dist/routing/router-types.d.ts +1 -0
- package/dist/routing/router.js +137 -22
- package/dist/routing/router.js.map +1 -1
- package/dist/routing/slot-resolver.d.ts +1 -1
- package/dist/routing/slot-resolver.js +2 -4
- package/dist/routing/slot-resolver.js.map +1 -1
- package/dist/routing/symbol-disambiguator.d.ts +11 -0
- package/dist/routing/symbol-disambiguator.js +52 -0
- package/dist/routing/symbol-disambiguator.js.map +1 -0
- package/dist/routing/turn-context.d.ts +1 -1
- package/dist/routing/turn-context.js +1 -1
- package/dist/routing/turn-context.js.map +1 -1
- package/dist/routing/types.d.ts +2 -0
- package/dist/runtime/answer-contracts.d.ts +1 -1
- package/dist/runtime/answer-contracts.js +48 -9
- package/dist/runtime/answer-contracts.js.map +1 -1
- package/dist/runtime/artifact-contracts.js.map +1 -1
- package/dist/runtime/planning-evidence.js +47 -26
- package/dist/runtime/planning-evidence.js.map +1 -1
- package/dist/runtime/prompt-step.d.ts +1 -9
- package/dist/runtime/prompt-step.js +0 -10
- package/dist/runtime/prompt-step.js.map +1 -1
- package/dist/runtime/run-context.d.ts +5 -2
- package/dist/runtime/run-context.js +8 -1
- package/dist/runtime/run-context.js.map +1 -1
- package/dist/runtime/session-coordinator.d.ts +13 -5
- package/dist/runtime/session-coordinator.js +160 -20
- package/dist/runtime/session-coordinator.js.map +1 -1
- package/dist/runtime/session-title.d.ts +14 -0
- package/dist/runtime/session-title.js +50 -0
- package/dist/runtime/session-title.js.map +1 -0
- package/dist/runtime/tool-defaults-wrapper.js +7 -5
- package/dist/runtime/tool-defaults-wrapper.js.map +1 -1
- package/dist/runtime/validation.js.map +1 -1
- package/dist/runtime/workflow-events.js.map +1 -1
- package/dist/runtime/workflow-runner.d.ts +3 -3
- package/dist/runtime/workflow-runner.js +1 -1
- package/dist/runtime/workflow-runner.js.map +1 -1
- package/dist/sentiment/adapters/finnhub.d.ts +1 -1
- package/dist/sentiment/adapters/finnhub.js +6 -1
- package/dist/sentiment/adapters/finnhub.js.map +1 -1
- package/dist/sentiment/adapters/reddit.d.ts +2 -2
- package/dist/sentiment/adapters/twitter.d.ts +1 -1
- package/dist/sentiment/adapters/web.d.ts +1 -1
- package/dist/sentiment/index.d.ts +10 -11
- package/dist/sentiment/index.js +10 -20
- package/dist/sentiment/index.js.map +1 -1
- package/dist/sentiment/insights.d.ts +17 -0
- package/dist/sentiment/insights.js +206 -0
- package/dist/sentiment/insights.js.map +1 -0
- package/dist/sentiment/keywords.js +26 -4
- package/dist/sentiment/keywords.js.map +1 -1
- package/dist/sentiment/pipeline.d.ts +2 -2
- package/dist/sentiment/pipeline.js +14 -2
- package/dist/sentiment/pipeline.js.map +1 -1
- package/dist/sentiment/scorer.d.ts +2 -0
- package/dist/sentiment/scorer.js +11 -2
- package/dist/sentiment/scorer.js.map +1 -1
- package/dist/sentiment/store.d.ts +1 -1
- package/dist/sentiment/store.js +1 -1
- package/dist/sentiment/store.js.map +1 -1
- package/dist/sentiment/trends.d.ts +1 -1
- package/dist/sentiment/trends.js.map +1 -1
- package/dist/sentiment/types.d.ts +2 -0
- package/dist/sentiment/types.js.map +1 -1
- package/dist/system-prompt.js +6 -9
- package/dist/system-prompt.js.map +1 -1
- package/dist/tool-kit.d.ts +7 -7
- package/dist/tool-kit.js +4 -4
- package/dist/tool-kit.js.map +1 -1
- package/dist/tools/fundamentals/company-overview.js +11 -6
- package/dist/tools/fundamentals/company-overview.js.map +1 -1
- package/dist/tools/fundamentals/comps.js +18 -9
- package/dist/tools/fundamentals/comps.js.map +1 -1
- package/dist/tools/fundamentals/dcf.js +23 -11
- package/dist/tools/fundamentals/dcf.js.map +1 -1
- package/dist/tools/fundamentals/earnings.js +8 -3
- package/dist/tools/fundamentals/earnings.js.map +1 -1
- package/dist/tools/fundamentals/financials.js +8 -3
- package/dist/tools/fundamentals/financials.js.map +1 -1
- package/dist/tools/fundamentals/sec-filings.js +21 -6
- package/dist/tools/fundamentals/sec-filings.js.map +1 -1
- package/dist/tools/index.d.ts +27 -20
- package/dist/tools/index.js +55 -43
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/interaction/ask-user.js +15 -3
- package/dist/tools/interaction/ask-user.js.map +1 -1
- package/dist/tools/macro/fear-greed.js.map +1 -1
- package/dist/tools/macro/fred-data.d.ts +1 -1
- package/dist/tools/macro/fred-data.js +17 -6
- package/dist/tools/macro/fred-data.js.map +1 -1
- package/dist/tools/market/crypto-history.js +3 -1
- package/dist/tools/market/crypto-history.js.map +1 -1
- package/dist/tools/market/crypto-price.js +3 -1
- package/dist/tools/market/crypto-price.js.map +1 -1
- package/dist/tools/market/screen-stocks.d.ts +18 -0
- package/dist/tools/market/screen-stocks.js +252 -0
- package/dist/tools/market/screen-stocks.js.map +1 -0
- package/dist/tools/market/search-ticker.js +160 -8
- package/dist/tools/market/search-ticker.js.map +1 -1
- package/dist/tools/market/stock-history.d.ts +2 -2
- package/dist/tools/market/stock-history.js +26 -7
- package/dist/tools/market/stock-history.js.map +1 -1
- package/dist/tools/market/stock-quote.js +5 -3
- package/dist/tools/market/stock-quote.js.map +1 -1
- package/dist/tools/options/greeks.js +1 -1
- package/dist/tools/options/greeks.js.map +1 -1
- package/dist/tools/options/option-chain.js +19 -6
- package/dist/tools/options/option-chain.js.map +1 -1
- package/dist/tools/portfolio/alerts.d.ts +15 -0
- package/dist/tools/portfolio/alerts.js +357 -0
- package/dist/tools/portfolio/alerts.js.map +1 -0
- package/dist/tools/portfolio/correlation.d.ts +1 -1
- package/dist/tools/portfolio/correlation.js +33 -13
- package/dist/tools/portfolio/correlation.js.map +1 -1
- package/dist/tools/portfolio/daily-report.d.ts +8 -0
- package/dist/tools/portfolio/daily-report.js +83 -0
- package/dist/tools/portfolio/daily-report.js.map +1 -0
- package/dist/tools/portfolio/holdings-overlap.js +10 -3
- package/dist/tools/portfolio/holdings-overlap.js.map +1 -1
- package/dist/tools/portfolio/notifications.d.ts +7 -0
- package/dist/tools/portfolio/notifications.js +43 -0
- package/dist/tools/portfolio/notifications.js.map +1 -0
- package/dist/tools/portfolio/predictions.d.ts +12 -6
- package/dist/tools/portfolio/predictions.js +337 -87
- package/dist/tools/portfolio/predictions.js.map +1 -1
- package/dist/tools/portfolio/risk-analysis.d.ts +1 -1
- package/dist/tools/portfolio/risk-analysis.js +45 -6
- package/dist/tools/portfolio/risk-analysis.js.map +1 -1
- package/dist/tools/portfolio/tracker.d.ts +4 -3
- package/dist/tools/portfolio/tracker.js +246 -101
- package/dist/tools/portfolio/tracker.js.map +1 -1
- package/dist/tools/portfolio/watchlist.d.ts +6 -4
- package/dist/tools/portfolio/watchlist.js +208 -108
- package/dist/tools/portfolio/watchlist.js.map +1 -1
- package/dist/tools/sentiment/insight-format.d.ts +2 -0
- package/dist/tools/sentiment/insight-format.js +36 -0
- package/dist/tools/sentiment/insight-format.js.map +1 -0
- package/dist/tools/sentiment/query-match.d.ts +3 -0
- package/dist/tools/sentiment/query-match.js +113 -0
- package/dist/tools/sentiment/query-match.js.map +1 -0
- package/dist/tools/sentiment/reddit-sentiment.d.ts +12 -1
- package/dist/tools/sentiment/reddit-sentiment.js +266 -107
- package/dist/tools/sentiment/reddit-sentiment.js.map +1 -1
- package/dist/tools/sentiment/sentiment-summary.d.ts +9 -1
- package/dist/tools/sentiment/sentiment-summary.js +223 -205
- package/dist/tools/sentiment/sentiment-summary.js.map +1 -1
- package/dist/tools/sentiment/sentiment-trend.d.ts +1 -1
- package/dist/tools/sentiment/sentiment-trend.js +12 -2
- package/dist/tools/sentiment/sentiment-trend.js.map +1 -1
- package/dist/tools/sentiment/twitter-sentiment.d.ts +11 -1
- package/dist/tools/sentiment/twitter-sentiment.js +188 -58
- package/dist/tools/sentiment/twitter-sentiment.js.map +1 -1
- package/dist/tools/sentiment/untrusted-text.d.ts +2 -0
- package/dist/tools/sentiment/untrusted-text.js +17 -0
- package/dist/tools/sentiment/untrusted-text.js.map +1 -0
- package/dist/tools/sentiment/web-search.js +9 -13
- package/dist/tools/sentiment/web-search.js.map +1 -1
- package/dist/tools/sentiment/web-sentiment.js +19 -3
- package/dist/tools/sentiment/web-sentiment.js.map +1 -1
- package/dist/tools/technical/backtest.d.ts +1 -1
- package/dist/tools/technical/backtest.js +27 -20
- package/dist/tools/technical/backtest.js.map +1 -1
- package/dist/tools/technical/indicators.js +23 -5
- package/dist/tools/technical/indicators.js.map +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/market.d.ts +1 -0
- package/dist/types/portfolio.d.ts +14 -4
- package/dist/types/sentiment.d.ts +52 -0
- package/dist/workflows/compare-assets.d.ts +0 -3
- package/dist/workflows/compare-assets.js +20 -11
- package/dist/workflows/compare-assets.js.map +1 -1
- package/dist/workflows/index.d.ts +3 -4
- package/dist/workflows/index.js +3 -3
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/options-screener.d.ts +0 -3
- package/dist/workflows/options-screener.js +4 -11
- package/dist/workflows/options-screener.js.map +1 -1
- package/dist/workflows/portfolio-builder.d.ts +0 -3
- package/dist/workflows/portfolio-builder.js +0 -8
- package/dist/workflows/portfolio-builder.js.map +1 -1
- package/gui/server/ask-user-bridge.ts +1 -1
- package/gui/server/automation-heartbeat.ts +97 -0
- package/gui/server/background-quotes.ts +97 -1
- package/gui/server/chat-event-adapter.ts +32 -10
- package/gui/server/chat-run-session.ts +16 -0
- package/gui/server/invoke-tool.ts +160 -3
- package/gui/server/live-chat-event-adapter.ts +21 -6
- package/gui/server/market-state-api.ts +315 -0
- package/gui/server/model-setup.ts +156 -2
- package/gui/server/private-api-access.ts +62 -0
- package/gui/server/projector.ts +18 -9
- package/gui/server/prompt-observation.ts +4 -7
- package/gui/server/quote-snapshot-store.ts +50 -0
- package/gui/server/server.ts +218 -451
- package/gui/server/session-actions.ts +186 -1
- package/gui/server/shutdown.ts +47 -0
- package/gui/server/tool-invoke-ack.ts +49 -0
- package/gui/server/tool-metadata.ts +101 -24
- package/gui/server/websocket.ts +13 -3
- package/gui/server/writer-lock.ts +6 -2
- package/gui/server/ws-hub.ts +311 -0
- package/gui/shared/chat-events.ts +16 -1
- package/gui/shared/event-reducer.ts +24 -6
- package/gui/web/dist/assets/CatalogOverlay-CgeY5Pkp.js +1 -0
- package/gui/web/dist/assets/index-C6W_2eAn.js +69 -0
- package/gui/web/dist/assets/index-hwbx24a5.css +1 -0
- package/gui/web/dist/index.html +2 -2
- package/package.json +9 -6
- package/src/analysts/contracts.ts +10 -23
- package/src/analysts/orchestrator.ts +8 -43
- package/src/cli.ts +76 -12
- package/src/config.ts +44 -9
- package/src/index.ts +1 -1
- package/src/infra/cache.ts +41 -30
- package/src/infra/http-client.ts +72 -6
- package/src/infra/index.ts +6 -10
- package/src/infra/native-dependencies.ts +8 -3
- package/src/infra/node-version.ts +3 -1
- package/src/infra/opencandle-paths.ts +3 -14
- package/src/infra/rate-limiter.ts +22 -19
- package/src/market-state/alert-conditions.ts +82 -0
- package/src/market-state/alert-runner.ts +863 -0
- package/src/market-state/daily-report.ts +247 -0
- package/src/market-state/local-automation-service.ts +162 -0
- package/src/market-state/notification-delivery.ts +158 -0
- package/src/market-state/resolve-for-mutation.ts +24 -0
- package/src/market-state/resolve.ts +112 -0
- package/src/market-state/service.ts +2344 -0
- package/src/memory/index.ts +7 -7
- package/src/memory/manager.ts +14 -16
- package/src/memory/retrieval.ts +8 -7
- package/src/memory/sqlite.ts +407 -6
- package/src/memory/storage.ts +5 -15
- package/src/memory/tool-defaults.ts +60 -39
- package/src/memory/types.ts +3 -3
- package/src/monitor.ts +121 -0
- package/src/onboarding/connect.ts +24 -31
- package/src/onboarding/credential-interceptor.ts +3 -15
- package/src/onboarding/degradation-accumulator.ts +1 -3
- package/src/onboarding/provider-status.ts +410 -0
- package/src/onboarding/providers.ts +144 -45
- package/src/onboarding/state.ts +13 -15
- package/src/onboarding/tool-helpers.ts +2 -9
- package/src/onboarding/tool-tags.ts +51 -8
- package/src/onboarding/validation.ts +16 -22
- package/src/pi/opencandle-extension.ts +643 -101
- package/src/pi/session.ts +7 -5
- package/src/pi/setup.ts +61 -43
- package/src/pi/tool-adapter.ts +19 -6
- package/src/prompts/context-builder.ts +24 -13
- package/src/prompts/policy-cards.ts +3 -3
- package/src/prompts/sections.ts +1 -1
- package/src/prompts/symbol-preflight.ts +80 -0
- package/src/prompts/workflow-prompts.ts +77 -28
- package/src/providers/alpha-vantage.ts +58 -39
- package/src/providers/coingecko.ts +2 -5
- package/src/providers/errors.ts +9 -0
- package/src/providers/exa-search.ts +24 -22
- package/src/providers/external-tool-error.ts +20 -0
- package/src/providers/fear-greed.ts +1 -1
- package/src/providers/finnhub.ts +7 -6
- package/src/providers/fred.ts +3 -3
- package/src/providers/index.ts +14 -6
- package/src/providers/reddit-cli.ts +317 -0
- package/src/providers/reddit.ts +14 -59
- package/src/providers/sec-edgar.ts +20 -6
- package/src/providers/tradingview.ts +399 -0
- package/src/providers/twitter-cli.ts +233 -0
- package/src/providers/twitter.ts +8 -79
- package/src/providers/web-search.ts +30 -20
- package/src/providers/with-fallback.ts +8 -7
- package/src/providers/wrap-provider.ts +49 -10
- package/src/providers/yahoo-finance.ts +204 -66
- package/src/routing/classify-intent.ts +101 -10
- package/src/routing/defaults.ts +1 -1
- package/src/routing/entity-extractor.ts +287 -38
- package/src/routing/fund-symbols.ts +58 -0
- package/src/routing/horizon.ts +7 -0
- package/src/routing/index.ts +48 -48
- package/src/routing/planning.ts +145 -53
- package/src/routing/route-manifest.ts +37 -15
- package/src/routing/router-llm-client.ts +4 -4
- package/src/routing/router-prompt.ts +15 -19
- package/src/routing/router-types.ts +2 -5
- package/src/routing/router.ts +251 -53
- package/src/routing/slot-resolver.ts +34 -11
- package/src/routing/symbol-disambiguator.ts +72 -0
- package/src/routing/turn-context.ts +6 -9
- package/src/routing/types.ts +2 -0
- package/src/runtime/answer-contracts.ts +105 -45
- package/src/runtime/artifact-contracts.ts +2 -1
- package/src/runtime/planning-evidence.ts +157 -66
- package/src/runtime/prompt-step.ts +1 -16
- package/src/runtime/run-context.ts +12 -2
- package/src/runtime/session-coordinator.ts +238 -63
- package/src/runtime/session-title.ts +60 -0
- package/src/runtime/tool-defaults-wrapper.ts +13 -5
- package/src/runtime/validation.ts +1 -4
- package/src/runtime/workflow-events.ts +7 -7
- package/src/runtime/workflow-runner.ts +5 -11
- package/src/sentiment/adapters/finnhub.ts +7 -2
- package/src/sentiment/adapters/reddit.ts +2 -2
- package/src/sentiment/adapters/twitter.ts +1 -1
- package/src/sentiment/adapters/web.ts +1 -1
- package/src/sentiment/index.ts +17 -26
- package/src/sentiment/insights.ts +269 -0
- package/src/sentiment/keywords.ts +26 -4
- package/src/sentiment/pipeline.ts +28 -5
- package/src/sentiment/scorer.ts +13 -2
- package/src/sentiment/store.ts +2 -2
- package/src/sentiment/trends.ts +9 -3
- package/src/sentiment/types.ts +8 -4
- package/src/system-prompt.ts +6 -9
- package/src/tool-kit.ts +10 -9
- package/src/tools/fundamentals/company-overview.ts +19 -9
- package/src/tools/fundamentals/comps.ts +68 -55
- package/src/tools/fundamentals/dcf.ts +145 -95
- package/src/tools/fundamentals/earnings.ts +16 -6
- package/src/tools/fundamentals/financials.ts +16 -7
- package/src/tools/fundamentals/sec-filings.ts +37 -16
- package/src/tools/index.ts +56 -43
- package/src/tools/interaction/ask-user.ts +22 -10
- package/src/tools/macro/fear-greed.ts +1 -1
- package/src/tools/macro/fred-data.ts +58 -46
- package/src/tools/market/crypto-history.ts +8 -3
- package/src/tools/market/crypto-price.ts +6 -6
- package/src/tools/market/screen-stocks.ts +279 -0
- package/src/tools/market/search-ticker.ts +218 -17
- package/src/tools/market/stock-history.ts +37 -12
- package/src/tools/market/stock-quote.ts +10 -7
- package/src/tools/options/greeks.ts +5 -5
- package/src/tools/options/option-chain.ts +41 -17
- package/src/tools/portfolio/alerts.ts +457 -0
- package/src/tools/portfolio/correlation.ts +47 -20
- package/src/tools/portfolio/daily-report.ts +101 -0
- package/src/tools/portfolio/holdings-overlap.ts +31 -15
- package/src/tools/portfolio/notifications.ts +45 -0
- package/src/tools/portfolio/predictions.ts +406 -106
- package/src/tools/portfolio/risk-analysis.ts +46 -7
- package/src/tools/portfolio/tracker.ts +270 -109
- package/src/tools/portfolio/watchlist.ts +250 -121
- package/src/tools/sentiment/insight-format.ts +50 -0
- package/src/tools/sentiment/query-match.ts +117 -0
- package/src/tools/sentiment/reddit-sentiment.ts +360 -121
- package/src/tools/sentiment/sentiment-summary.ts +302 -235
- package/src/tools/sentiment/sentiment-trend.ts +24 -7
- package/src/tools/sentiment/twitter-sentiment.ts +264 -73
- package/src/tools/sentiment/untrusted-text.ts +21 -0
- package/src/tools/sentiment/web-search.ts +21 -18
- package/src/tools/sentiment/web-sentiment.ts +30 -10
- package/src/tools/technical/backtest.ts +32 -22
- package/src/tools/technical/indicators.ts +39 -14
- package/src/types/index.ts +8 -3
- package/src/types/market.ts +1 -0
- package/src/types/portfolio.ts +14 -4
- package/src/types/sentiment.ts +61 -2
- package/src/workflows/compare-assets.ts +33 -21
- package/src/workflows/index.ts +3 -4
- package/src/workflows/options-screener.ts +27 -29
- package/src/workflows/portfolio-builder.ts +34 -27
- package/dist/infra/browser.d.ts +0 -35
- package/dist/infra/browser.js +0 -103
- package/dist/infra/browser.js.map +0 -1
- package/dist/tools/interaction/twitter-login.d.ts +0 -8
- package/dist/tools/interaction/twitter-login.js +0 -77
- package/dist/tools/interaction/twitter-login.js.map +0 -1
- package/dist/workflows/types.d.ts +0 -4
- package/dist/workflows/types.js +0 -2
- package/dist/workflows/types.js.map +0 -1
- package/gui/web/dist/assets/CatalogOverlay-Bmp6Knu7.js +0 -1
- package/gui/web/dist/assets/index-Bxt9QpLX.css +0 -1
- package/gui/web/dist/assets/index-CZ9DHZYy.js +0 -67
- package/src/infra/browser.ts +0 -111
- package/src/tools/interaction/twitter-login.ts +0 -93
- package/src/workflows/types.ts +0 -4
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { parseDteTarget } from "../routing/defaults.js";
|
|
2
|
+
import { areLikelyFundOrIndexSymbols, isFundOrIndexAssetScope } from "../routing/fund-symbols.js";
|
|
3
|
+
import { isLongInvestmentHorizon } from "../routing/horizon.js";
|
|
4
|
+
import type { RouterOutput } from "../routing/router-types.js";
|
|
1
5
|
import type {
|
|
2
|
-
PortfolioSlots,
|
|
3
|
-
OptionsScreenerSlots,
|
|
4
6
|
CompareAssetsSlots,
|
|
7
|
+
OptionsScreenerSlots,
|
|
8
|
+
PortfolioSlots,
|
|
5
9
|
SlotResolution,
|
|
6
10
|
SlotSource,
|
|
7
11
|
} from "../routing/types.js";
|
|
8
|
-
import type { RouterOutput } from "../routing/router-types.js";
|
|
9
|
-
import { parseDteTarget } from "../routing/defaults.js";
|
|
10
12
|
|
|
11
13
|
function tag(source: string | undefined): string {
|
|
12
14
|
switch (source) {
|
|
@@ -14,7 +16,6 @@ function tag(source: string | undefined): string {
|
|
|
14
16
|
return " [DEFAULT]";
|
|
15
17
|
case "preference":
|
|
16
18
|
return " [SAVED PREFERENCE]";
|
|
17
|
-
case "user":
|
|
18
19
|
default:
|
|
19
20
|
return "";
|
|
20
21
|
}
|
|
@@ -96,8 +97,10 @@ export function buildDisclosureBlock(
|
|
|
96
97
|
const lines: string[] = [];
|
|
97
98
|
lines.push("Assumptions (reproduce this block exactly — do not relabel sources):");
|
|
98
99
|
if (userSpecified.length > 0) lines.push(` User-specified: ${userSpecified.join(", ")}`);
|
|
99
|
-
if (fromPreferences.length > 0)
|
|
100
|
-
|
|
100
|
+
if (fromPreferences.length > 0)
|
|
101
|
+
lines.push(` From saved preferences: ${fromPreferences.join(", ")}`);
|
|
102
|
+
if (fromPriorContext.length > 0)
|
|
103
|
+
lines.push(` From prior context: ${fromPriorContext.join(", ")}`);
|
|
101
104
|
if (fromMemory.length > 0) lines.push(` From memory: ${fromMemory.join(", ")}`);
|
|
102
105
|
if (defaults.length > 0) lines.push(` Defaults: ${defaults.join(", ")}`);
|
|
103
106
|
if (workflowConstraints && workflowConstraints.length > 0) {
|
|
@@ -139,7 +142,10 @@ function formatSlotValue(value: unknown): string {
|
|
|
139
142
|
export function buildPortfolioPrompt(resolution: SlotResolution<PortfolioSlots>): string {
|
|
140
143
|
const { resolved: s, sources } = resolution;
|
|
141
144
|
const normalizedScope = s.assetScope.toLowerCase();
|
|
142
|
-
const isFundBuildingBlocks =
|
|
145
|
+
const isFundBuildingBlocks =
|
|
146
|
+
normalizedScope.includes("etf") ||
|
|
147
|
+
normalizedScope.includes("fund") ||
|
|
148
|
+
normalizedScope.includes("building_blocks");
|
|
143
149
|
|
|
144
150
|
const disclosureBlock = buildDisclosureBlock(
|
|
145
151
|
{
|
|
@@ -198,7 +204,9 @@ Response format:
|
|
|
198
204
|
- Suggest what to change for more growth or more safety.`;
|
|
199
205
|
}
|
|
200
206
|
|
|
201
|
-
export function buildOptionsScreenerPrompt(
|
|
207
|
+
export function buildOptionsScreenerPrompt(
|
|
208
|
+
resolution: SlotResolution<OptionsScreenerSlots>,
|
|
209
|
+
): string {
|
|
202
210
|
const { resolved: s, sources } = resolution;
|
|
203
211
|
|
|
204
212
|
const dateStr = todayStr();
|
|
@@ -225,14 +233,15 @@ Ranking constraints:
|
|
|
225
233
|
- Do NOT rank ultra-cheap near-zero-delta contracts as "best."
|
|
226
234
|
`
|
|
227
235
|
: "";
|
|
228
|
-
const longDatedInstructions =
|
|
229
|
-
|
|
236
|
+
const longDatedInstructions =
|
|
237
|
+
s.dteTarget === "180_plus_days"
|
|
238
|
+
? `
|
|
230
239
|
For LEAPS / long-dated options:
|
|
231
240
|
- First call get_option_chain without an expiration to inspect available expirations.
|
|
232
241
|
- Choose available expirations inside the target window, then call get_option_chain again with explicit \`expiration\` dates before ranking contracts.
|
|
233
242
|
- Do not rank the nearest-expiration chain as a LEAPS result.
|
|
234
243
|
`
|
|
235
|
-
|
|
244
|
+
: "";
|
|
236
245
|
|
|
237
246
|
const disclosureBlock = buildDisclosureBlock(
|
|
238
247
|
{
|
|
@@ -253,18 +262,26 @@ For LEAPS / long-dated options:
|
|
|
253
262
|
);
|
|
254
263
|
|
|
255
264
|
const coveredCallContext = [
|
|
256
|
-
s.optionStrategy
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
s.
|
|
265
|
+
s.optionStrategy
|
|
266
|
+
? `\n- Option strategy: ${s.optionStrategy}${tag(sources.optionStrategy)}`
|
|
267
|
+
: "",
|
|
268
|
+
s.costBasis !== undefined
|
|
269
|
+
? `\n- Cost basis: ${formatBudget(s.costBasis)} (Position cost basis: ${formatBudget(s.costBasis)})${tag(sources.costBasis)}`
|
|
270
|
+
: "",
|
|
271
|
+
s.shareQuantity !== undefined
|
|
272
|
+
? `\n- Share quantity: ${s.shareQuantity} shares${tag(sources.shareQuantity)}`
|
|
273
|
+
: "",
|
|
274
|
+
s.catalystSymbols?.length
|
|
275
|
+
? `\n- Catalyst/context tickers: ${s.catalystSymbols.join(", ")}${tag(sources.catalystSymbols)}`
|
|
276
|
+
: "",
|
|
260
277
|
].join("");
|
|
261
278
|
|
|
262
279
|
const isProtectivePutContext = s.optionStrategy === "protective_put";
|
|
263
|
-
const isCoveredCallContext =
|
|
264
|
-
|
|
265
|
-
s.
|
|
266
|
-
|
|
267
|
-
|
|
280
|
+
const isCoveredCallContext =
|
|
281
|
+
!isProtectivePutContext &&
|
|
282
|
+
(s.optionStrategy === "covered_call" ||
|
|
283
|
+
s.costBasis !== undefined ||
|
|
284
|
+
(s.catalystSymbols?.length ?? 0) > 0);
|
|
268
285
|
const coveredCallInstructions = isCoveredCallContext
|
|
269
286
|
? `
|
|
270
287
|
Covered-call sale guidance:
|
|
@@ -314,9 +331,17 @@ Steps:
|
|
|
314
331
|
3. Filter contracts matching: ${s.direction === "bullish" && !isProtectivePutContext ? "calls" : "puts"}, DTE near ${s.dteTarget}, ${s.moneynessPreference} strikes.
|
|
315
332
|
4. ${isProtectivePutContext ? "Rank by hedge quality: protection per dollar of premium, expiration fit, moneyness, liquidity, and hedge floor." : `Rank by ${s.objective}: balance premium cost, delta exposure, and probability of profit.`}${s.maxPremium !== undefined ? ` Do not rank contracts above the user's max premium of ${formatBudget(s.maxPremium)} unless no contracts under that cap are liquid; if so, say the cap could not be met.` : ""}
|
|
316
333
|
5. Filter for ${s.liquidityMinimum}: high open interest and tight bid-ask spread.
|
|
317
|
-
${
|
|
318
|
-
|
|
319
|
-
` :
|
|
334
|
+
${
|
|
335
|
+
s.optionStrategy === "covered_call"
|
|
336
|
+
? `6. Covered call framing: treat option premium as premium received, not paid. Use the user's cost basis when provided, and include return-if-assigned and assignment/downside risk instead of long-call max-loss framing.
|
|
337
|
+
`
|
|
338
|
+
: ""
|
|
339
|
+
}${
|
|
340
|
+
isCoveredCallContext && s.costBasis !== undefined
|
|
341
|
+
? `Cost-basis math: if assigned, share gain/loss is strike minus ${formatBudget(s.costBasis)} before premium. Total return if assigned is (strike - cost basis + premium received) / cost basis.
|
|
342
|
+
`
|
|
343
|
+
: ""
|
|
344
|
+
}
|
|
320
345
|
${longDatedInstructions}
|
|
321
346
|
${coveredCallInstructions}
|
|
322
347
|
${protectivePutInstructions}
|
|
@@ -336,10 +361,15 @@ export function buildCompareAssetsPrompt(resolution: SlotResolution<CompareAsset
|
|
|
336
361
|
const symbols = resolution.resolved.symbols;
|
|
337
362
|
const symbolList = symbols.join(", ");
|
|
338
363
|
const timeHorizon = resolution.resolved.timeHorizon;
|
|
364
|
+
const budget = resolution.resolved.budget;
|
|
339
365
|
const includeSentiment = resolution.resolved.metrics?.includes("sentiment") ?? false;
|
|
340
366
|
const isMacroHedge = resolution.resolved.metrics?.includes("macro_hedge") ?? false;
|
|
341
367
|
const isInterestRateSensitive = resolution.resolved.metrics?.includes("interest_rates") ?? false;
|
|
342
368
|
const isOverlapComparison = resolution.resolved.metrics?.includes("overlap") ?? false;
|
|
369
|
+
const hasFundContext =
|
|
370
|
+
isFundOrIndexAssetScope(resolution.resolved.assetScope) || areLikelyFundOrIndexSymbols(symbols);
|
|
371
|
+
const shouldProbeFundOverlap =
|
|
372
|
+
!isOverlapComparison && isLongInvestmentHorizon(timeHorizon) && hasFundContext;
|
|
343
373
|
const sentimentStep = includeSentiment
|
|
344
374
|
? `\n6. Use get_sentiment_summary for each of: ${symbolList} to compare retail/news sentiment and note source availability.`
|
|
345
375
|
: "";
|
|
@@ -365,7 +395,16 @@ ETF overlap guidance:
|
|
|
365
395
|
- Use provider top holdings and overlap weights when available. If provider coverage is partial or unavailable, say so directly and fall back to plain-language fund structure.
|
|
366
396
|
- Discuss top holdings, shared mega-cap names, sector concentration, and whether the position is a deliberate tilt or accidental duplication.
|
|
367
397
|
- avoid treating price, RSI, or generic risk metrics as the main answer.`
|
|
368
|
-
:
|
|
398
|
+
: shouldProbeFundOverlap
|
|
399
|
+
? `
|
|
400
|
+
ETF/fund overlap check:
|
|
401
|
+
- If these assets are ETFs, funds, or index products, use provider-backed holdings-overlap evidence before making diversification claims.
|
|
402
|
+
- Compare fund role, style/factor tilt, concentration, and broad sector exposure when available; do not invent exact holdings or weights.
|
|
403
|
+
- For dividend/income funds versus growth funds over multi-year horizons, explain taxable account dividend drag: dividends can be taxed annually even when reinvested, while more return may be deferred as capital gains in growth-oriented funds. Contrast that with tax-advantaged accounts.
|
|
404
|
+
- Include expense ratios, dividend yields, and AUM only when fetched evidence supports them; otherwise tell the user to verify current fund facts before acting.
|
|
405
|
+
- Treat holdings overlap and sector concentration as different from correlation; correlation is supporting evidence, not a substitute for constituent exposure.
|
|
406
|
+
- If provider holdings coverage is partial or unavailable, say so directly and continue with the available price, risk, and correlation evidence.`
|
|
407
|
+
: "";
|
|
369
408
|
const macroHedgeSteps = isMacroHedge
|
|
370
409
|
? `
|
|
371
410
|
macro hedge decision guidance:
|
|
@@ -380,16 +419,24 @@ macro hedge decision guidance:
|
|
|
380
419
|
? "- Present a comparison table with hedge-relevant columns: hedge role, macro drivers, volatility/drawdown evidence, correlation regime, liquidity/risk-on sensitivity, current data, and missing evidence."
|
|
381
420
|
: isOverlapComparison
|
|
382
421
|
? "- Present an ETF overlap table with columns: fund role, shared top holdings/overlap weight from provider when available, sector concentration, what exposure is duplicated, what exposure is new, and diversification implication."
|
|
383
|
-
|
|
422
|
+
: shouldProbeFundOverlap
|
|
423
|
+
? "- Present a long-horizon fund comparison table with columns: fund role/style, dividend/income versus growth tradeoff, risk evidence, holdings-overlap availability, tax and expense/yield/AUM verification gaps, and horizon fit."
|
|
424
|
+
: `- Present a comparison table with key metrics: price, P/E, revenue growth, profit margin, RSI, Sharpe, max drawdown${sentimentMetric}.
|
|
384
425
|
- Highlight which asset is stronger on each metric.`;
|
|
385
426
|
const technicalRiskSteps = isOverlapComparison
|
|
386
427
|
? `3. Use analyze_holdings_overlap with symbols [${symbolList}] to fetch provider top holdings and compute pairwise overlap by weight.
|
|
387
428
|
4. Use analyze_correlation across [${symbolList}] only as supporting diversification evidence; do not substitute correlation for holdings overlap.
|
|
388
429
|
5. Skip momentum/risk tool calls unless the user asks about timing or trade setup; the core question is top holdings and sector overlap.`
|
|
389
|
-
:
|
|
430
|
+
: shouldProbeFundOverlap
|
|
431
|
+
? `3. Use analyze_holdings_overlap with symbols [${symbolList}] to fetch provider top holdings and compute pairwise overlap by weight.
|
|
432
|
+
4. Use analyze_correlation across [${symbolList}] as supporting diversification evidence.
|
|
433
|
+
5. Use analyze_risk for each to compare long-horizon risk context.
|
|
434
|
+
6. Use get_technical_indicators only as secondary timing context; do not let RSI or short-term momentum dominate the long-horizon fund decision.`
|
|
435
|
+
: `3. Use get_technical_indicators for each to compare momentum and trend.
|
|
390
436
|
4. Use analyze_risk for each to compare risk metrics.
|
|
391
437
|
5. Use analyze_correlation across [${symbolList}] to check diversification.`;
|
|
392
438
|
const horizonLine = timeHorizon ? `\nTime horizon: ${timeHorizon}` : "";
|
|
439
|
+
const budgetLine = budget !== undefined ? `\nBudget: ${formatBudget(budget)}` : "";
|
|
393
440
|
const horizonSteps = timeHorizon
|
|
394
441
|
? `
|
|
395
442
|
6. Adapt the comparison to the ${timeHorizon} horizon: prioritize near-term catalysts, earnings/guidance, estimate revisions, sentiment, and forward-looking valuation evidence over long-term historical averages.
|
|
@@ -406,6 +453,8 @@ macro hedge decision guidance:
|
|
|
406
453
|
{
|
|
407
454
|
symbols: symbolList,
|
|
408
455
|
...(timeHorizon ? { timeHorizon } : {}),
|
|
456
|
+
...(budget !== undefined ? { budget: formatBudget(budget) } : {}),
|
|
457
|
+
...(resolution.resolved.assetScope ? { assetScope: resolution.resolved.assetScope } : {}),
|
|
409
458
|
...(resolution.resolved.metrics ? { metrics: resolution.resolved.metrics.join(", ") } : {}),
|
|
410
459
|
},
|
|
411
460
|
resolution.sources as Record<string, SlotSource | undefined>,
|
|
@@ -413,7 +462,7 @@ macro hedge decision guidance:
|
|
|
413
462
|
|
|
414
463
|
return `Current date: ${todayStr()}
|
|
415
464
|
|
|
416
|
-
Compare these assets side by side: ${symbolList}${horizonLine}
|
|
465
|
+
Compare these assets side by side: ${symbolList}${horizonLine}${budgetLine}
|
|
417
466
|
|
|
418
467
|
Steps:
|
|
419
468
|
1. Use get_stock_quote for each of: ${symbolList}.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { cache, STALE_LIMIT, TTL } from "../infra/cache.js";
|
|
2
|
+
import { HttpError, httpGet } from "../infra/http-client.js";
|
|
3
3
|
import { rateLimiter } from "../infra/rate-limiter.js";
|
|
4
|
-
import { ProviderCredentialError } from "./provider-credential-error.js";
|
|
5
4
|
import type { CompanyOverview, EarningsData, FinancialStatement } from "../types/fundamentals.js";
|
|
6
|
-
import type {
|
|
5
|
+
import type { OHLCV, StockQuote } from "../types/market.js";
|
|
6
|
+
import { ProviderCredentialError } from "./provider-credential-error.js";
|
|
7
7
|
|
|
8
8
|
const BASE_URL = "https://www.alphavantage.co/query";
|
|
9
9
|
const MISSING_OVERVIEW_TTL = 15 * 60_000;
|
|
@@ -44,10 +44,7 @@ function throwIfApiMessage(data: unknown): void {
|
|
|
44
44
|
throw new Error(`Alpha Vantage error: ${message}`);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export async function getOverview(
|
|
48
|
-
symbol: string,
|
|
49
|
-
apiKey: string,
|
|
50
|
-
): Promise<CompanyOverview> {
|
|
47
|
+
export async function getOverview(symbol: string, apiKey: string): Promise<CompanyOverview> {
|
|
51
48
|
const cacheKey = `av:overview:${symbol}`;
|
|
52
49
|
const missingCacheKey = `${cacheKey}:missing`;
|
|
53
50
|
const cached = cache.get<CompanyOverview>(cacheKey);
|
|
@@ -98,10 +95,7 @@ export async function getOverview(
|
|
|
98
95
|
}
|
|
99
96
|
}
|
|
100
97
|
|
|
101
|
-
export async function getEarnings(
|
|
102
|
-
symbol: string,
|
|
103
|
-
apiKey: string,
|
|
104
|
-
): Promise<EarningsData> {
|
|
98
|
+
export async function getEarnings(symbol: string, apiKey: string): Promise<EarningsData> {
|
|
105
99
|
const cacheKey = `av:earnings:${symbol}`;
|
|
106
100
|
const cached = cache.get<EarningsData>(cacheKey);
|
|
107
101
|
if (cached) return cached;
|
|
@@ -132,31 +126,36 @@ export async function getEarnings(
|
|
|
132
126
|
}
|
|
133
127
|
}
|
|
134
128
|
|
|
135
|
-
export async function getFinancials(
|
|
136
|
-
symbol: string,
|
|
137
|
-
apiKey: string,
|
|
138
|
-
): Promise<FinancialStatement[]> {
|
|
129
|
+
export async function getFinancials(symbol: string, apiKey: string): Promise<FinancialStatement[]> {
|
|
139
130
|
const cacheKey = `av:financials:${symbol}`;
|
|
140
131
|
const cached = cache.get<FinancialStatement[]>(cacheKey);
|
|
141
132
|
if (cached) return cached;
|
|
142
133
|
|
|
143
134
|
try {
|
|
144
135
|
// Fetch sequentially to respect Alpha Vantage rate limits (5 req/min free tier)
|
|
145
|
-
const incomeData = await fetchStatement<{ annualReports: any[] }>(
|
|
146
|
-
|
|
147
|
-
|
|
136
|
+
const incomeData = await fetchStatement<{ annualReports: any[] }>(
|
|
137
|
+
"INCOME_STATEMENT",
|
|
138
|
+
symbol,
|
|
139
|
+
apiKey,
|
|
140
|
+
);
|
|
141
|
+
const balanceData = await fetchStatement<{ annualReports: any[] }>(
|
|
142
|
+
"BALANCE_SHEET",
|
|
143
|
+
symbol,
|
|
144
|
+
apiKey,
|
|
145
|
+
);
|
|
146
|
+
const cashFlowData = await fetchStatement<{ annualReports: any[] }>(
|
|
147
|
+
"CASH_FLOW",
|
|
148
|
+
symbol,
|
|
149
|
+
apiKey,
|
|
150
|
+
);
|
|
148
151
|
|
|
149
152
|
const incomeReports = incomeData.annualReports ?? [];
|
|
150
153
|
const balanceReports = balanceData.annualReports ?? [];
|
|
151
154
|
const cashFlowReports = cashFlowData.annualReports ?? [];
|
|
152
155
|
|
|
153
156
|
// Index balance sheet and cash flow by fiscal date for merging
|
|
154
|
-
const balanceByDate = new Map(
|
|
155
|
-
|
|
156
|
-
);
|
|
157
|
-
const cashFlowByDate = new Map(
|
|
158
|
-
cashFlowReports.map((r: any) => [r.fiscalDateEnding, r]),
|
|
159
|
-
);
|
|
157
|
+
const balanceByDate = new Map(balanceReports.map((r: any) => [r.fiscalDateEnding, r]));
|
|
158
|
+
const cashFlowByDate = new Map(cashFlowReports.map((r: any) => [r.fiscalDateEnding, r]));
|
|
160
159
|
|
|
161
160
|
const statements = incomeReports.slice(0, 4).map((r: any) => {
|
|
162
161
|
const balance = balanceByDate.get(r.fiscalDateEnding) ?? {};
|
|
@@ -202,10 +201,7 @@ async function fetchStatement<T>(fn: string, symbol: string, apiKey: string): Pr
|
|
|
202
201
|
return data;
|
|
203
202
|
}
|
|
204
203
|
|
|
205
|
-
export async function getGlobalQuote(
|
|
206
|
-
symbol: string,
|
|
207
|
-
apiKey: string,
|
|
208
|
-
): Promise<StockQuote> {
|
|
204
|
+
export async function getGlobalQuote(symbol: string, apiKey: string): Promise<StockQuote> {
|
|
209
205
|
const cacheKey = `av:globalquote:${symbol}`;
|
|
210
206
|
const cached = cache.get<StockQuote>(cacheKey);
|
|
211
207
|
if (cached) return cached;
|
|
@@ -233,10 +229,10 @@ export async function getGlobalQuote(
|
|
|
233
229
|
low: parseFloat(gq["04. low"]) || 0,
|
|
234
230
|
previousClose: parseFloat(gq["08. previous close"]) || 0,
|
|
235
231
|
volume: parseInt(gq["06. volume"], 10) || 0,
|
|
236
|
-
marketCap: 0,
|
|
237
|
-
pe: null,
|
|
238
|
-
week52High: 0,
|
|
239
|
-
week52Low: 0,
|
|
232
|
+
marketCap: 0, // Not available from GLOBAL_QUOTE
|
|
233
|
+
pe: null, // Not available from GLOBAL_QUOTE
|
|
234
|
+
week52High: 0, // Not available from GLOBAL_QUOTE
|
|
235
|
+
week52Low: 0, // Not available from GLOBAL_QUOTE
|
|
240
236
|
timestamp: Date.now(),
|
|
241
237
|
};
|
|
242
238
|
|
|
@@ -266,7 +262,9 @@ export async function getDailyHistory(
|
|
|
266
262
|
const daysNeeded = rangeToDays(range);
|
|
267
263
|
const outputsize = daysNeeded > 100 ? "full" : "compact";
|
|
268
264
|
const url = buildUrl("TIME_SERIES_DAILY", { symbol, outputsize }, apiKey);
|
|
269
|
-
const data = await httpGet<{ "Time Series (Daily)": Record<string, Record<string, string>> }>(
|
|
265
|
+
const data = await httpGet<{ "Time Series (Daily)": Record<string, Record<string, string>> }>(
|
|
266
|
+
url,
|
|
267
|
+
);
|
|
270
268
|
throwIfApiMessage(data);
|
|
271
269
|
|
|
272
270
|
const timeSeries = data["Time Series (Daily)"];
|
|
@@ -274,7 +272,7 @@ export async function getDailyHistory(
|
|
|
274
272
|
throw new Error(`Alpha Vantage: No daily history for ${symbol}`);
|
|
275
273
|
}
|
|
276
274
|
|
|
277
|
-
const
|
|
275
|
+
const sorted = Object.entries(timeSeries)
|
|
278
276
|
.map(([date, bar]) => ({
|
|
279
277
|
date,
|
|
280
278
|
open: parseFloat(bar["1. open"]) || 0,
|
|
@@ -283,8 +281,14 @@ export async function getDailyHistory(
|
|
|
283
281
|
close: parseFloat(bar["4. close"]) || 0,
|
|
284
282
|
volume: parseInt(bar["5. volume"], 10) || 0,
|
|
285
283
|
}))
|
|
286
|
-
.sort((a, b) => a.date.localeCompare(b.date))
|
|
287
|
-
|
|
284
|
+
.sort((a, b) => a.date.localeCompare(b.date));
|
|
285
|
+
|
|
286
|
+
// Count-based slicing for ytd is only an estimate (ignores holidays and
|
|
287
|
+
// the starting weekday) and can leak prior-year bars; filter by date.
|
|
288
|
+
const ohlcv: OHLCV[] =
|
|
289
|
+
range === "ytd"
|
|
290
|
+
? sorted.filter((bar) => bar.date >= `${new Date().getFullYear()}-01-01`)
|
|
291
|
+
: sorted.slice(-daysNeeded);
|
|
288
292
|
|
|
289
293
|
cache.set(cacheKey, ohlcv, TTL.HISTORY);
|
|
290
294
|
return ohlcv;
|
|
@@ -298,12 +302,27 @@ export async function getDailyHistory(
|
|
|
298
302
|
|
|
299
303
|
function rangeToDays(range: string): number {
|
|
300
304
|
const map: Record<string, number> = {
|
|
301
|
-
"1d": 1,
|
|
302
|
-
"
|
|
305
|
+
"1d": 1,
|
|
306
|
+
"5d": 5,
|
|
307
|
+
"1mo": 22,
|
|
308
|
+
"3mo": 66,
|
|
309
|
+
"6mo": 130,
|
|
310
|
+
"1y": 252,
|
|
311
|
+
"2y": 504,
|
|
312
|
+
"5y": 1260,
|
|
313
|
+
"10y": 2520,
|
|
314
|
+
max: 5000,
|
|
303
315
|
};
|
|
316
|
+
if (range === "ytd") return tradingDaysSinceStartOfYear();
|
|
304
317
|
return map[range] ?? 130;
|
|
305
318
|
}
|
|
306
319
|
|
|
320
|
+
function tradingDaysSinceStartOfYear(date = new Date()): number {
|
|
321
|
+
const start = new Date(date.getFullYear(), 0, 1);
|
|
322
|
+
const calendarDays = Math.max(1, Math.ceil((date.getTime() - start.getTime()) / 86_400_000) + 1);
|
|
323
|
+
return Math.max(1, Math.ceil((calendarDays / 7) * 5));
|
|
324
|
+
}
|
|
325
|
+
|
|
307
326
|
function parseNum(s: string | undefined): number {
|
|
308
327
|
return parseFloat(s ?? "0") || 0;
|
|
309
328
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { cache, STALE_LIMIT, TTL } from "../infra/cache.js";
|
|
1
2
|
import { httpGet } from "../infra/http-client.js";
|
|
2
|
-
import { cache, TTL, STALE_LIMIT } from "../infra/cache.js";
|
|
3
3
|
import { rateLimiter } from "../infra/rate-limiter.js";
|
|
4
4
|
import type { CryptoPrice, OHLCV } from "../types/market.js";
|
|
5
5
|
|
|
@@ -63,10 +63,7 @@ export async function getCryptoPrice(id: string): Promise<CryptoPrice> {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
export async function getCryptoHistory(
|
|
67
|
-
id: string,
|
|
68
|
-
days: number = 180,
|
|
69
|
-
): Promise<OHLCV[]> {
|
|
66
|
+
export async function getCryptoHistory(id: string, days: number = 180): Promise<OHLCV[]> {
|
|
70
67
|
const cacheKey = `coingecko:history:${id}:${days}`;
|
|
71
68
|
const cached = cache.get<OHLCV[]>(cacheKey);
|
|
72
69
|
if (cached) return cached;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { cache, TTL, STALE_LIMIT } from "../infra/cache.js";
|
|
2
|
-
import { rateLimiter } from "../infra/rate-limiter.js";
|
|
3
1
|
import { getConfig } from "../config.js";
|
|
2
|
+
import { cache, STALE_LIMIT, TTL } from "../infra/cache.js";
|
|
3
|
+
import { rateLimiter } from "../infra/rate-limiter.js";
|
|
4
|
+
import type { WebSearchEnvelope, WebSearchResult } from "../types/sentiment.js";
|
|
4
5
|
import { ProviderCredentialError } from "./provider-credential-error.js";
|
|
5
|
-
import type { WebSearchResult, WebSearchEnvelope } from "../types/sentiment.js";
|
|
6
6
|
import type { WebSearchOpts } from "./web-search.js";
|
|
7
7
|
|
|
8
8
|
const EXA_MCP_URL = "https://mcp.exa.ai/mcp";
|
|
@@ -19,19 +19,27 @@ let requestIdCounter = 0;
|
|
|
19
19
|
|
|
20
20
|
function freshnessToMs(freshness: WebSearchOpts["freshness"]): number {
|
|
21
21
|
switch (freshness) {
|
|
22
|
-
case "hours":
|
|
23
|
-
|
|
24
|
-
case "
|
|
25
|
-
|
|
22
|
+
case "hours":
|
|
23
|
+
return 60 * 60 * 1000;
|
|
24
|
+
case "day":
|
|
25
|
+
return 24 * 60 * 60 * 1000;
|
|
26
|
+
case "week":
|
|
27
|
+
return 7 * 24 * 60 * 60 * 1000;
|
|
28
|
+
case "month":
|
|
29
|
+
return 30 * 24 * 60 * 60 * 1000;
|
|
26
30
|
}
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
function enrichQueryForMcp(query: string, freshness: WebSearchOpts["freshness"]): string {
|
|
30
34
|
switch (freshness) {
|
|
31
|
-
case "hours":
|
|
32
|
-
|
|
33
|
-
case "
|
|
34
|
-
|
|
35
|
+
case "hours":
|
|
36
|
+
return `${query} past hour`;
|
|
37
|
+
case "day":
|
|
38
|
+
return `${query} past 24 hours`;
|
|
39
|
+
case "week":
|
|
40
|
+
return `${query} past week`;
|
|
41
|
+
case "month":
|
|
42
|
+
return `${query} past month`;
|
|
35
43
|
}
|
|
36
44
|
}
|
|
37
45
|
|
|
@@ -192,10 +200,7 @@ function exaCacheKey(query: string, opts: WebSearchOpts): string {
|
|
|
192
200
|
// MCP path
|
|
193
201
|
// ---------------------------------------------------------------------------
|
|
194
202
|
|
|
195
|
-
async function exaMcpSearch(
|
|
196
|
-
query: string,
|
|
197
|
-
opts: WebSearchOpts,
|
|
198
|
-
): Promise<WebSearchEnvelope> {
|
|
203
|
+
async function exaMcpSearch(query: string, opts: WebSearchOpts): Promise<WebSearchEnvelope> {
|
|
199
204
|
const enrichedQuery = enrichQueryForMcp(query, opts.freshness);
|
|
200
205
|
|
|
201
206
|
const response = await fetch(EXA_MCP_URL, {
|
|
@@ -330,10 +335,7 @@ async function exaApiSearch(
|
|
|
330
335
|
// Public entry point
|
|
331
336
|
// ---------------------------------------------------------------------------
|
|
332
337
|
|
|
333
|
-
export async function exaSearch(
|
|
334
|
-
query: string,
|
|
335
|
-
opts: WebSearchOpts,
|
|
336
|
-
): Promise<WebSearchEnvelope> {
|
|
338
|
+
export async function exaSearch(query: string, opts: WebSearchOpts): Promise<WebSearchEnvelope> {
|
|
337
339
|
const key = exaCacheKey(query, opts);
|
|
338
340
|
const cached = cache.get<WebSearchEnvelope>(key);
|
|
339
341
|
if (cached) return cached;
|
|
@@ -362,12 +364,12 @@ export async function exaSearch(
|
|
|
362
364
|
}
|
|
363
365
|
}
|
|
364
366
|
|
|
367
|
+
export type { ExaApiResponse, McpRpcResponse, ParsedResult };
|
|
365
368
|
// Exported for testing
|
|
366
369
|
export {
|
|
367
|
-
parseMcpResultBlocks,
|
|
368
|
-
extractJsonRpcPayload,
|
|
369
370
|
enrichQueryForMcp,
|
|
371
|
+
extractJsonRpcPayload,
|
|
370
372
|
filterByFreshness,
|
|
371
373
|
mapApiResults,
|
|
374
|
+
parseMcpResultBlocks,
|
|
372
375
|
};
|
|
373
|
-
export type { ParsedResult, McpRpcResponse, ExaApiResponse };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class ExternalToolError extends Error {
|
|
2
|
+
constructor(
|
|
3
|
+
public readonly toolName: string,
|
|
4
|
+
message: string,
|
|
5
|
+
public readonly code?: string,
|
|
6
|
+
) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "ExternalToolError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class ExternalToolNotInstalled extends Error {
|
|
13
|
+
constructor(
|
|
14
|
+
public readonly toolName: string,
|
|
15
|
+
public readonly installCmd: string,
|
|
16
|
+
) {
|
|
17
|
+
super(`${toolName} is not installed. Install it with: ${installCmd}`);
|
|
18
|
+
this.name = "ExternalToolNotInstalled";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { cache, STALE_LIMIT, TTL } from "../infra/cache.js";
|
|
1
2
|
import { httpGet } from "../infra/http-client.js";
|
|
2
|
-
import { cache, TTL, STALE_LIMIT } from "../infra/cache.js";
|
|
3
3
|
import type { FearGreedData } from "../types/sentiment.js";
|
|
4
4
|
|
|
5
5
|
// alternative.me provides a free crypto Fear & Greed index
|
package/src/providers/finnhub.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { cache, STALE_LIMIT, TTL } from "../infra/cache.js";
|
|
2
|
+
import { HttpError, httpGet } from "../infra/http-client.js";
|
|
3
3
|
import { rateLimiter } from "../infra/rate-limiter.js";
|
|
4
4
|
import { ProviderCredentialError } from "./provider-credential-error.js";
|
|
5
5
|
|
|
@@ -36,7 +36,10 @@ const TICKER_NAMES: Record<string, string> = {
|
|
|
36
36
|
ORCL: "oracle",
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
export function finnhubDateRange(freshness: "hours" | "day" | "week" | "month"): {
|
|
39
|
+
export function finnhubDateRange(freshness: "hours" | "day" | "week" | "month"): {
|
|
40
|
+
from: string;
|
|
41
|
+
to: string;
|
|
42
|
+
} {
|
|
40
43
|
const now = new Date();
|
|
41
44
|
const to = formatDate(now);
|
|
42
45
|
|
|
@@ -86,9 +89,7 @@ export function filterByRelevance(
|
|
|
86
89
|
});
|
|
87
90
|
|
|
88
91
|
// Most recent first, capped
|
|
89
|
-
return filtered
|
|
90
|
-
.sort((a, b) => b.datetime - a.datetime)
|
|
91
|
-
.slice(0, limit);
|
|
92
|
+
return filtered.sort((a, b) => b.datetime - a.datetime).slice(0, limit);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
export async function getCompanyNews(
|
package/src/providers/fred.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { cache, STALE_LIMIT, TTL } from "../infra/cache.js";
|
|
2
|
+
import { HttpError, httpGet } from "../infra/http-client.js";
|
|
3
3
|
import { rateLimiter } from "../infra/rate-limiter.js";
|
|
4
|
+
import type { FredObservation, FredSeries } from "../types/macro.js";
|
|
4
5
|
import { ProviderCredentialError } from "./provider-credential-error.js";
|
|
5
|
-
import type { FredSeries, FredObservation } from "../types/macro.js";
|
|
6
6
|
|
|
7
7
|
const BASE_URL = "https://api.stlouisfed.org/fred";
|
|
8
8
|
|
package/src/providers/index.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
1
|
+
export { getEarnings, getFinancials, getOverview } from "./alpha-vantage.js";
|
|
2
|
+
export { getCryptoHistory, getCryptoPrice } from "./coingecko.js";
|
|
3
|
+
export { getFearGreedIndex } from "./fear-greed.js";
|
|
3
4
|
export { getSeries } from "./fred.js";
|
|
4
|
-
export { getCryptoPrice, getCryptoHistory } from "./coingecko.js";
|
|
5
5
|
export { getSubredditPosts, scoreSentiment } from "./reddit.js";
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export { searchWeb, ddgSearch, braveSearch, normalizeFinancialQuery } from "./web-search.js";
|
|
6
|
+
export { type SECFiling, searchFilings } from "./sec-edgar.js";
|
|
7
|
+
export { getQuotes, screenStocks } from "./tradingview.js";
|
|
9
8
|
export type { WebSearchOpts } from "./web-search.js";
|
|
9
|
+
export { braveSearch, ddgSearch, normalizeFinancialQuery, searchWeb } from "./web-search.js";
|
|
10
|
+
export {
|
|
11
|
+
clearCrumbCache,
|
|
12
|
+
computeTimeToExpiry,
|
|
13
|
+
getHistory,
|
|
14
|
+
getOptionsChain,
|
|
15
|
+
getQuote,
|
|
16
|
+
getYahooCrumb,
|
|
17
|
+
} from "./yahoo-finance.js";
|