opencandle 0.4.0 → 0.6.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/LICENSE +1 -1
- package/README.md +186 -117
- 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 +32 -8
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +19 -3
- package/dist/config.js +69 -3
- 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/browser.d.ts +1 -3
- package/dist/infra/browser.js +4 -2
- package/dist/infra/browser.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 +3 -3
- package/dist/infra/index.js +3 -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.d.ts +4 -0
- package/dist/infra/rate-limiter.js +17 -10
- 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.d.ts +9 -0
- package/dist/memory/manager.js +39 -22
- 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.d.ts +3 -2
- 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 +4 -0
- 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.js +4 -6
- 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/providers.js +3 -16
- package/dist/onboarding/providers.js.map +1 -1
- 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.js +6 -4
- package/dist/onboarding/tool-tags.js.map +1 -1
- 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 +637 -59
- 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 +17 -2
- package/dist/pi/setup.js.map +1 -1
- package/dist/pi/tool-adapter.js +5 -2
- package/dist/pi/tool-adapter.js.map +1 -1
- package/dist/prompts/context-builder.d.ts +18 -3
- package/dist/prompts/context-builder.js +117 -18
- package/dist/prompts/context-builder.js.map +1 -1
- package/dist/prompts/disclaimer.js +1 -1
- package/dist/prompts/disclaimer.js.map +1 -1
- package/dist/prompts/policy-cards.d.ts +13 -0
- package/dist/prompts/policy-cards.js +197 -0
- package/dist/prompts/policy-cards.js.map +1 -0
- package/dist/prompts/sections.d.ts +1 -1
- package/dist/prompts/sections.js +3 -3
- package/dist/prompts/sections.js.map +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 +209 -19
- package/dist/prompts/workflow-prompts.js.map +1 -1
- package/dist/providers/alpha-vantage.d.ts +1 -1
- package/dist/providers/alpha-vantage.js +49 -8
- 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/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.js +2 -2
- package/dist/providers/reddit.js.map +1 -1
- package/dist/providers/sec-edgar.d.ts +9 -1
- package/dist/providers/sec-edgar.js +181 -6
- 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.js +6 -8
- 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 +14 -8
- package/dist/providers/wrap-provider.js.map +1 -1
- package/dist/providers/yahoo-finance.d.ts +3 -1
- package/dist/providers/yahoo-finance.js +226 -11
- package/dist/providers/yahoo-finance.js.map +1 -1
- package/dist/routing/classify-intent.d.ts +9 -0
- package/dist/routing/classify-intent.js +153 -3
- package/dist/routing/classify-intent.js.map +1 -1
- package/dist/routing/defaults.d.ts +1 -1
- package/dist/routing/defaults.js +3 -3
- package/dist/routing/defaults.js.map +1 -1
- package/dist/routing/entity-extractor.d.ts +2 -0
- package/dist/routing/entity-extractor.js +377 -26
- 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 +12 -6
- package/dist/routing/index.js +8 -4
- package/dist/routing/index.js.map +1 -1
- package/dist/routing/legacy-rule-router.d.ts +9 -0
- package/dist/routing/legacy-rule-router.js +12 -0
- package/dist/routing/legacy-rule-router.js.map +1 -0
- package/dist/routing/planning.d.ts +54 -0
- package/dist/routing/planning.js +562 -0
- package/dist/routing/planning.js.map +1 -0
- package/dist/routing/route-manifest.d.ts +35 -0
- package/dist/routing/route-manifest.js +242 -0
- package/dist/routing/route-manifest.js.map +1 -0
- package/dist/routing/router-llm-client.js.map +1 -1
- package/dist/routing/router-prompt.js +46 -45
- package/dist/routing/router-prompt.js.map +1 -1
- package/dist/routing/router-types.d.ts +10 -0
- package/dist/routing/router.d.ts +1 -0
- package/dist/routing/router.js +572 -13
- package/dist/routing/router.js.map +1 -1
- package/dist/routing/slot-resolver.d.ts +1 -1
- package/dist/routing/slot-resolver.js +45 -7
- 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 +44 -0
- package/dist/routing/turn-context.js +45 -0
- package/dist/routing/turn-context.js.map +1 -0
- package/dist/routing/types.d.ts +15 -1
- package/dist/runtime/answer-contracts.d.ts +82 -0
- package/dist/runtime/answer-contracts.js +442 -0
- package/dist/runtime/answer-contracts.js.map +1 -0
- package/dist/runtime/artifact-contracts.d.ts +14 -0
- package/dist/runtime/artifact-contracts.js +57 -0
- package/dist/runtime/artifact-contracts.js.map +1 -0
- package/dist/runtime/planning-evidence.d.ts +99 -0
- package/dist/runtime/planning-evidence.js +466 -0
- package/dist/runtime/planning-evidence.js.map +1 -0
- 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 +29 -3
- package/dist/runtime/session-coordinator.js +204 -31
- 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 +1 -3
- 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 +9 -11
- package/dist/sentiment/index.js +9 -20
- package/dist/sentiment/index.js.map +1 -1
- 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 +1 -1
- package/dist/sentiment/pipeline.js.map +1 -1
- package/dist/sentiment/scorer.js +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.js.map +1 -1
- package/dist/system-prompt.js +7 -3
- 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 +12 -7
- package/dist/tools/fundamentals/company-overview.js.map +1 -1
- package/dist/tools/fundamentals/comps.js +19 -10
- package/dist/tools/fundamentals/comps.js.map +1 -1
- package/dist/tools/fundamentals/dcf.js +24 -12
- package/dist/tools/fundamentals/dcf.js.map +1 -1
- package/dist/tools/fundamentals/earnings.js +9 -4
- package/dist/tools/fundamentals/earnings.js.map +1 -1
- package/dist/tools/fundamentals/financials.js +9 -4
- package/dist/tools/fundamentals/financials.js.map +1 -1
- package/dist/tools/fundamentals/sec-filings.d.ts +1 -0
- package/dist/tools/fundamentals/sec-filings.js +36 -4
- package/dist/tools/fundamentals/sec-filings.js.map +1 -1
- package/dist/tools/index.d.ts +23 -18
- package/dist/tools/index.js +53 -38
- 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/interaction/twitter-login.js +13 -3
- package/dist/tools/interaction/twitter-login.js.map +1 -1
- package/dist/tools/macro/fear-greed.js +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 +44 -9
- package/dist/tools/macro/fred-data.js.map +1 -1
- package/dist/tools/market/crypto-history.js +21 -3
- package/dist/tools/market/crypto-history.js.map +1 -1
- package/dist/tools/market/crypto-price.js +4 -2
- 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 +161 -9
- 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 +27 -8
- package/dist/tools/market/stock-history.js.map +1 -1
- package/dist/tools/market/stock-quote.js +6 -4
- package/dist/tools/market/stock-quote.js.map +1 -1
- package/dist/tools/options/greeks.js +1 -2
- package/dist/tools/options/greeks.js.map +1 -1
- package/dist/tools/options/option-chain.js +27 -9
- 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 +34 -14
- 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.d.ts +8 -0
- package/dist/tools/portfolio/holdings-overlap.js +112 -0
- package/dist/tools/portfolio/holdings-overlap.js.map +1 -0
- 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 +338 -88
- 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 +46 -7
- 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 +247 -102
- package/dist/tools/portfolio/tracker.js.map +1 -1
- package/dist/tools/portfolio/watchlist.d.ts +6 -4
- package/dist/tools/portfolio/watchlist.js +209 -101
- package/dist/tools/portfolio/watchlist.js.map +1 -1
- package/dist/tools/sentiment/reddit-sentiment.js +24 -11
- package/dist/tools/sentiment/reddit-sentiment.js.map +1 -1
- package/dist/tools/sentiment/sentiment-summary.js +71 -14
- 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.js +13 -6
- 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 +37 -12
- package/dist/tools/sentiment/web-search.js.map +1 -1
- package/dist/tools/sentiment/web-sentiment.js +16 -4
- package/dist/tools/sentiment/web-sentiment.js.map +1 -1
- package/dist/tools/technical/backtest.d.ts +3 -3
- package/dist/tools/technical/backtest.js +65 -44
- package/dist/tools/technical/backtest.js.map +1 -1
- package/dist/tools/technical/indicators.js +24 -8
- 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/options.d.ts +10 -0
- package/dist/types/portfolio.d.ts +41 -4
- package/dist/workflows/compare-assets.d.ts +0 -3
- package/dist/workflows/compare-assets.js +55 -10
- 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 +88 -14
- package/dist/workflows/options-screener.js.map +1 -1
- package/dist/workflows/portfolio-builder.d.ts +0 -3
- package/dist/workflows/portfolio-builder.js +7 -11
- package/dist/workflows/portfolio-builder.js.map +1 -1
- package/gui/server/ask-user-bridge.ts +82 -0
- 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/gui-session-manager.ts +5 -0
- package/gui/server/invoke-tool.ts +144 -1
- 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 +149 -2
- package/gui/server/private-api-access.ts +62 -0
- package/gui/server/projector.ts +58 -11
- package/gui/server/prompt-observation.ts +58 -0
- package/gui/server/quote-snapshot-store.ts +50 -0
- package/gui/server/server.ts +236 -376
- package/gui/server/session-actions.ts +186 -1
- package/gui/server/session-entry-wait.ts +81 -0
- package/gui/server/shutdown.ts +47 -0
- package/gui/server/tool-invoke-ack.ts +49 -0
- package/gui/server/tool-metadata.ts +23 -10
- package/gui/server/websocket.ts +13 -3
- package/gui/server/writer-lock.ts +6 -2
- package/gui/server/ws-hub.ts +292 -0
- package/gui/shared/chat-events.ts +16 -1
- package/gui/shared/event-reducer.ts +24 -6
- package/gui/web/dist/assets/CatalogOverlay-eJ2cBk33.js +1 -0
- package/gui/web/dist/assets/index-2KZtKBmu.css +1 -0
- package/gui/web/dist/assets/index-CveNgtDg.js +69 -0
- package/gui/web/dist/index.html +2 -2
- package/package.json +22 -12
- package/src/analysts/contracts.ts +10 -23
- package/src/analysts/orchestrator.ts +8 -43
- package/src/cli.ts +37 -13
- package/src/config.ts +99 -7
- package/src/index.ts +1 -1
- package/src/infra/browser.ts +4 -2
- package/src/infra/cache.ts +41 -30
- package/src/infra/http-client.ts +72 -6
- package/src/infra/index.ts +7 -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 +32 -20
- 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 +57 -26
- package/src/memory/retrieval.ts +8 -7
- package/src/memory/sqlite.ts +407 -6
- package/src/memory/storage.ts +8 -17
- package/src/memory/tool-defaults.ts +60 -39
- package/src/memory/types.ts +7 -3
- package/src/monitor.ts +121 -0
- package/src/onboarding/connect.ts +10 -33
- package/src/onboarding/credential-interceptor.ts +3 -15
- package/src/onboarding/degradation-accumulator.ts +1 -3
- package/src/onboarding/providers.ts +9 -40
- package/src/onboarding/state.ts +4 -15
- package/src/onboarding/tool-helpers.ts +2 -9
- package/src/onboarding/tool-tags.ts +6 -6
- package/src/onboarding/validation.ts +14 -20
- package/src/pi/opencandle-extension.ts +795 -120
- package/src/pi/session.ts +7 -5
- package/src/pi/setup.ts +61 -33
- package/src/pi/tool-adapter.ts +5 -2
- package/src/prompts/context-builder.ts +143 -21
- package/src/prompts/disclaimer.ts +1 -1
- package/src/prompts/policy-cards.ts +220 -0
- package/src/prompts/sections.ts +4 -4
- package/src/prompts/symbol-preflight.ts +80 -0
- package/src/prompts/workflow-prompts.ts +231 -28
- package/src/providers/alpha-vantage.ts +82 -40
- 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/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.ts +17 -6
- package/src/providers/sec-edgar.ts +235 -5
- package/src/providers/tradingview.ts +399 -0
- package/src/providers/twitter.ts +6 -8
- package/src/providers/web-search.ts +30 -20
- package/src/providers/with-fallback.ts +8 -7
- package/src/providers/wrap-provider.ts +15 -10
- package/src/providers/yahoo-finance.ts +292 -20
- package/src/routing/classify-intent.ts +186 -4
- package/src/routing/defaults.ts +4 -4
- package/src/routing/entity-extractor.ts +428 -28
- package/src/routing/fund-symbols.ts +58 -0
- package/src/routing/horizon.ts +7 -0
- package/src/routing/index.ts +60 -16
- package/src/routing/legacy-rule-router.ts +13 -0
- package/src/routing/planning.ts +823 -0
- package/src/routing/route-manifest.ts +309 -0
- package/src/routing/router-llm-client.ts +4 -4
- package/src/routing/router-prompt.ts +52 -52
- package/src/routing/router-types.ts +18 -0
- package/src/routing/router.ts +717 -20
- package/src/routing/slot-resolver.ts +75 -14
- package/src/routing/symbol-disambiguator.ts +72 -0
- package/src/routing/turn-context.ts +108 -0
- package/src/routing/types.ts +15 -1
- package/src/runtime/answer-contracts.ts +672 -0
- package/src/runtime/artifact-contracts.ts +77 -0
- package/src/runtime/planning-evidence.ts +682 -0
- package/src/runtime/prompt-step.ts +1 -16
- package/src/runtime/run-context.ts +12 -2
- package/src/runtime/session-coordinator.ts +297 -56
- package/src/runtime/session-title.ts +60 -0
- package/src/runtime/tool-defaults-wrapper.ts +1 -3
- 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 +16 -26
- package/src/sentiment/keywords.ts +26 -4
- package/src/sentiment/pipeline.ts +15 -4
- package/src/sentiment/scorer.ts +1 -1
- package/src/sentiment/store.ts +2 -2
- package/src/sentiment/trends.ts +9 -3
- package/src/sentiment/types.ts +5 -4
- package/src/system-prompt.ts +7 -3
- package/src/tool-kit.ts +10 -9
- package/src/tools/fundamentals/company-overview.ts +20 -10
- package/src/tools/fundamentals/comps.ts +69 -56
- package/src/tools/fundamentals/dcf.ts +146 -96
- package/src/tools/fundamentals/earnings.ts +17 -7
- package/src/tools/fundamentals/financials.ts +17 -8
- package/src/tools/fundamentals/sec-filings.ts +52 -8
- package/src/tools/index.ts +53 -38
- package/src/tools/interaction/ask-user.ts +22 -10
- package/src/tools/interaction/twitter-login.ts +17 -5
- package/src/tools/macro/fear-greed.ts +2 -2
- package/src/tools/macro/fred-data.ts +80 -42
- package/src/tools/market/crypto-history.ts +25 -4
- package/src/tools/market/crypto-price.ts +7 -7
- package/src/tools/market/screen-stocks.ts +279 -0
- package/src/tools/market/search-ticker.ts +219 -18
- package/src/tools/market/stock-history.ts +38 -13
- package/src/tools/market/stock-quote.ts +11 -8
- package/src/tools/options/greeks.ts +5 -6
- package/src/tools/options/option-chain.ts +47 -18
- package/src/tools/portfolio/alerts.ts +457 -0
- package/src/tools/portfolio/correlation.ts +48 -21
- package/src/tools/portfolio/daily-report.ts +101 -0
- package/src/tools/portfolio/holdings-overlap.ts +139 -0
- package/src/tools/portfolio/notifications.ts +45 -0
- package/src/tools/portfolio/predictions.ts +407 -107
- package/src/tools/portfolio/risk-analysis.ts +47 -8
- package/src/tools/portfolio/tracker.ts +271 -110
- package/src/tools/portfolio/watchlist.ts +251 -116
- package/src/tools/sentiment/reddit-sentiment.ts +51 -25
- package/src/tools/sentiment/sentiment-summary.ts +116 -35
- package/src/tools/sentiment/sentiment-trend.ts +24 -7
- package/src/tools/sentiment/twitter-sentiment.ts +23 -16
- package/src/tools/sentiment/untrusted-text.ts +21 -0
- package/src/tools/sentiment/web-search.ts +52 -16
- package/src/tools/sentiment/web-sentiment.ts +27 -11
- package/src/tools/technical/backtest.ts +78 -47
- package/src/tools/technical/indicators.ts +40 -17
- package/src/types/index.ts +8 -3
- package/src/types/market.ts +1 -0
- package/src/types/options.ts +17 -0
- package/src/types/portfolio.ts +46 -4
- package/src/types/sentiment.ts +2 -2
- package/src/workflows/compare-assets.ts +67 -19
- package/src/workflows/index.ts +3 -4
- package/src/workflows/options-screener.ts +98 -22
- package/src/workflows/portfolio-builder.ts +40 -29
- package/dist/runtime/index.d.ts +0 -16
- package/dist/runtime/index.js +0 -10
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/provider-ids.d.ts +0 -14
- package/dist/runtime/provider-ids.js +0 -14
- package/dist/runtime/provider-ids.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-D1ImSJTe.js +0 -1
- package/gui/web/dist/assets/index-DBrWq43L.css +0 -1
- package/gui/web/dist/assets/index-RflHaj0y.js +0 -67
- package/src/runtime/index.ts +0 -55
- package/src/runtime/provider-ids.ts +0 -15
- package/src/workflows/types.ts +0 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import type { SentinelRecord, SentimentAdapter } from "../types.js";
|
|
3
|
-
import type { RedditSentimentResult } from "../../types/sentiment.js";
|
|
4
2
|
import type { RedditComment } from "../../providers/reddit.js";
|
|
3
|
+
import type { RedditSentimentResult } from "../../types/sentiment.js";
|
|
4
|
+
import type { SentimentAdapter, SentinelRecord } from "../types.js";
|
|
5
5
|
|
|
6
6
|
export class RedditAdapter implements SentimentAdapter {
|
|
7
7
|
readonly source = "reddit" as const;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import type { SentinelRecord, SentimentAdapter } from "../types.js";
|
|
3
2
|
import type { TwitterSentimentResult } from "../../types/sentiment.js";
|
|
3
|
+
import type { SentimentAdapter, SentinelRecord } from "../types.js";
|
|
4
4
|
|
|
5
5
|
export class TwitterAdapter implements SentimentAdapter {
|
|
6
6
|
readonly source = "twitter" as const;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import type { SentinelRecord, SentimentAdapter } from "../types.js";
|
|
3
2
|
import type { WebSearchEnvelope } from "../../types/sentiment.js";
|
|
3
|
+
import type { SentimentAdapter, SentinelRecord } from "../types.js";
|
|
4
4
|
|
|
5
5
|
export class WebAdapter implements SentimentAdapter {
|
|
6
6
|
readonly source = "web" as const;
|
package/src/sentiment/index.ts
CHANGED
|
@@ -1,30 +1,29 @@
|
|
|
1
|
+
export { RedditAdapter } from "./adapters/reddit.js";
|
|
2
|
+
export { TwitterAdapter } from "./adapters/twitter.js";
|
|
3
|
+
export { WebAdapter } from "./adapters/web.js";
|
|
4
|
+
export { BEARISH_TERMS, BULLISH_TERMS } from "./keywords.js";
|
|
5
|
+
export { SentimentPipeline } from "./pipeline.js";
|
|
6
|
+
export { keywordScore, scoreRecords } from "./scorer.js";
|
|
7
|
+
export { SentimentStore } from "./store.js";
|
|
8
|
+
export { computeDivergence, computeTrend, renderSparkline } from "./trends.js";
|
|
1
9
|
export type {
|
|
2
|
-
|
|
10
|
+
DivergenceResult,
|
|
11
|
+
ScorerOptions,
|
|
12
|
+
SentimentAdapter,
|
|
13
|
+
SentimentSource,
|
|
14
|
+
SentimentSummary,
|
|
3
15
|
SentinelEngagement,
|
|
16
|
+
SentinelRecord,
|
|
4
17
|
SentinelSentiment,
|
|
5
|
-
SentimentAdapter,
|
|
6
|
-
ScorerOptions,
|
|
7
18
|
TrendBucket,
|
|
8
19
|
TrendResult,
|
|
9
|
-
DivergenceResult,
|
|
10
|
-
SentimentSummary,
|
|
11
|
-
SentimentSource,
|
|
12
20
|
} from "./types.js";
|
|
13
|
-
|
|
14
21
|
export { isSentinelRecord, SENTIMENT_SOURCES } from "./types.js";
|
|
15
|
-
export { SentimentStore } from "./store.js";
|
|
16
|
-
export { scoreRecords, keywordScore } from "./scorer.js";
|
|
17
|
-
export { SentimentPipeline } from "./pipeline.js";
|
|
18
|
-
export { renderSparkline, computeTrend, computeDivergence } from "./trends.js";
|
|
19
|
-
export { BULLISH_TERMS, BEARISH_TERMS } from "./keywords.js";
|
|
20
|
-
export { TwitterAdapter } from "./adapters/twitter.js";
|
|
21
|
-
export { RedditAdapter } from "./adapters/reddit.js";
|
|
22
|
-
export { WebAdapter } from "./adapters/web.js";
|
|
23
22
|
|
|
24
|
-
import { SentimentStore } from "./store.js";
|
|
25
|
-
import { SentimentPipeline } from "./pipeline.js";
|
|
26
23
|
import { getConfig } from "../config.js";
|
|
27
24
|
import { resolveOpenCandlePath } from "../infra/opencandle-paths.js";
|
|
25
|
+
import { SentimentPipeline } from "./pipeline.js";
|
|
26
|
+
import { SentimentStore } from "./store.js";
|
|
28
27
|
|
|
29
28
|
let _pipeline: SentimentPipeline | null = null;
|
|
30
29
|
let _store: SentimentStore | null = null;
|
|
@@ -47,12 +46,3 @@ export function getSentimentPipeline(): SentimentPipeline {
|
|
|
47
46
|
}
|
|
48
47
|
return _pipeline;
|
|
49
48
|
}
|
|
50
|
-
|
|
51
|
-
/** For testing: reset singletons */
|
|
52
|
-
export function _resetSentimentSingletons(): void {
|
|
53
|
-
if (_store) {
|
|
54
|
-
try { _store.close(); } catch { /* ignore */ }
|
|
55
|
-
}
|
|
56
|
-
_pipeline = null;
|
|
57
|
-
_store = null;
|
|
58
|
-
}
|
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
export const BULLISH_TERMS = [
|
|
2
|
-
"moon",
|
|
3
|
-
"
|
|
2
|
+
"moon",
|
|
3
|
+
"buy",
|
|
4
|
+
"undervalued",
|
|
5
|
+
"breakout",
|
|
6
|
+
"calls",
|
|
7
|
+
"bullish",
|
|
8
|
+
"rocket",
|
|
9
|
+
"diamond hands",
|
|
10
|
+
"accumulate",
|
|
11
|
+
"dip buy",
|
|
12
|
+
"long",
|
|
13
|
+
"rip",
|
|
14
|
+
"squeeze",
|
|
4
15
|
] as const;
|
|
5
16
|
|
|
6
17
|
export const BEARISH_TERMS = [
|
|
7
|
-
"crash",
|
|
8
|
-
"
|
|
18
|
+
"crash",
|
|
19
|
+
"overvalued",
|
|
20
|
+
"sell",
|
|
21
|
+
"puts",
|
|
22
|
+
"bearish",
|
|
23
|
+
"bubble",
|
|
24
|
+
"dump",
|
|
25
|
+
"short",
|
|
26
|
+
"bagholding",
|
|
27
|
+
"exit",
|
|
28
|
+
"drill",
|
|
29
|
+
"tank",
|
|
30
|
+
"rug",
|
|
9
31
|
] as const;
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import type { SentinelRecord, SentimentSummary, TrendResult, DivergenceResult, SentimentSource } from "./types.js";
|
|
2
1
|
import type { SentimentConfig } from "../config.js";
|
|
3
2
|
import { scoreRecords } from "./scorer.js";
|
|
4
|
-
import { SentimentStore } from "./store.js";
|
|
5
|
-
import {
|
|
3
|
+
import type { SentimentStore } from "./store.js";
|
|
4
|
+
import { computeDivergence, computeTrend, type SourceStats } from "./trends.js";
|
|
5
|
+
import type {
|
|
6
|
+
DivergenceResult,
|
|
7
|
+
SentimentSource,
|
|
8
|
+
SentimentSummary,
|
|
9
|
+
SentinelRecord,
|
|
10
|
+
TrendResult,
|
|
11
|
+
} from "./types.js";
|
|
6
12
|
|
|
7
13
|
export class SentimentPipeline {
|
|
8
14
|
constructor(
|
|
@@ -39,7 +45,12 @@ export class SentimentPipeline {
|
|
|
39
45
|
// Compute divergence from fresh records
|
|
40
46
|
let divergence: DivergenceResult | null = null;
|
|
41
47
|
const sourceGroups = groupBySource(scored);
|
|
42
|
-
const sourceStats: {
|
|
48
|
+
const sourceStats: {
|
|
49
|
+
twitter?: SourceStats;
|
|
50
|
+
reddit?: SourceStats;
|
|
51
|
+
web?: SourceStats;
|
|
52
|
+
finnhub?: SourceStats;
|
|
53
|
+
} = {};
|
|
43
54
|
|
|
44
55
|
for (const [source, recs] of Object.entries(sourceGroups)) {
|
|
45
56
|
// Exclude comments from divergence calculation
|
package/src/sentiment/scorer.ts
CHANGED
package/src/sentiment/store.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import Database from "better-sqlite3";
|
|
2
1
|
import { mkdirSync } from "node:fs";
|
|
3
2
|
import { dirname } from "node:path";
|
|
4
|
-
import
|
|
3
|
+
import Database from "better-sqlite3";
|
|
4
|
+
import type { SentimentSource, SentinelRecord, TrendBucket } from "./types.js";
|
|
5
5
|
|
|
6
6
|
const SCHEMA_VERSION = 1;
|
|
7
7
|
|
package/src/sentiment/trends.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DivergenceResult, SentimentSource, TrendBucket, TrendResult } from "./types.js";
|
|
2
2
|
|
|
3
3
|
const SPARKLINE_CHARS = "▁▂▃▄▅▆▇█";
|
|
4
4
|
|
|
@@ -24,7 +24,8 @@ export function computeTrend(
|
|
|
24
24
|
): TrendResult {
|
|
25
25
|
const scores = buckets.map((b) => b.avgScore);
|
|
26
26
|
const totalCount = buckets.reduce((sum, b) => sum + b.count, 0);
|
|
27
|
-
const avgScore =
|
|
27
|
+
const avgScore =
|
|
28
|
+
totalCount === 0 ? 0 : buckets.reduce((sum, b) => sum + b.avgScore * b.count, 0) / totalCount;
|
|
28
29
|
|
|
29
30
|
const sparkline = renderSparkline(scores);
|
|
30
31
|
|
|
@@ -45,7 +46,12 @@ export interface SourceStats {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
export function computeDivergence(
|
|
48
|
-
sources: {
|
|
49
|
+
sources: {
|
|
50
|
+
twitter?: SourceStats;
|
|
51
|
+
reddit?: SourceStats;
|
|
52
|
+
web?: SourceStats;
|
|
53
|
+
finnhub?: SourceStats;
|
|
54
|
+
},
|
|
49
55
|
threshold: number,
|
|
50
56
|
): DivergenceResult {
|
|
51
57
|
const retailSources: SourceStats[] = [];
|
package/src/sentiment/types.ts
CHANGED
|
@@ -9,9 +9,9 @@ export interface SentinelEngagement {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export interface SentinelSentiment {
|
|
12
|
-
score: number;
|
|
13
|
-
confidence: number;
|
|
14
|
-
method: "keyword";
|
|
12
|
+
score: number; // -1.0 to +1.0
|
|
13
|
+
confidence: number; // 0.0 to 1.0
|
|
14
|
+
method: "keyword"; // v1 is keyword-only; future: "llm"
|
|
15
15
|
tickers: string[];
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -36,7 +36,8 @@ export function isSentinelRecord(val: unknown): val is SentinelRecord {
|
|
|
36
36
|
const r = val as Record<string, unknown>;
|
|
37
37
|
|
|
38
38
|
if (typeof r.id !== "string") return false;
|
|
39
|
-
if (typeof r.source !== "string" || !SENTIMENT_SOURCES.includes(r.source as SentimentSource))
|
|
39
|
+
if (typeof r.source !== "string" || !SENTIMENT_SOURCES.includes(r.source as SentimentSource))
|
|
40
|
+
return false;
|
|
40
41
|
if (typeof r.sourceId !== "string") return false;
|
|
41
42
|
if (typeof r.query !== "string") return false;
|
|
42
43
|
if (r.title !== null && typeof r.title !== "string") return false;
|
package/src/system-prompt.ts
CHANGED
|
@@ -10,16 +10,16 @@ ${memoryContext}`
|
|
|
10
10
|
return `You are OpenCandle, a research analyst for investors and traders.
|
|
11
11
|
|
|
12
12
|
## Your Role
|
|
13
|
-
You are an analyst, not a fiduciary advisor. When asked for entry levels, price targets, stops, position sizes, or allocations, you COMMIT to specific numbers backed by the data you fetched. Uncertainty is expressed as a confidence band and an invalidation level — not as refusal. Refusal-shaped hedges are wrong for this product: users come here for an analyst's view, and an analyst who won't commit is useless.
|
|
13
|
+
You are an analyst, not a fiduciary advisor. When asked for entry levels, price targets, stops, position sizes, or allocations, you COMMIT to specific numbers backed by the data you fetched. Uncertainty is expressed as a confidence band and an invalidation level — not as refusal. Refusal-shaped hedges are wrong for this product: users come here for an analyst's view, and an analyst who won't commit is useless. For conceptual education questions, teach the concept directly, do not name tool functions, and do not append analyst-view, confidence-band, or invalidation boilerplate. For valuation-metric education, start with "Bottom line", use a heading exactly named "Practical workflow" with numbered question-driven application steps, explain where the metric misleads, include a compact cross-check table with why/when each metric helps, include relevant trailing, forward, normalized, or cyclically adjusted variants when useful, and end with a heading exactly named "Quick checklist".
|
|
14
14
|
|
|
15
15
|
## Available Tools
|
|
16
|
-
- **Market Data**: get_stock_quote, get_stock_history, get_crypto_price, get_crypto_history —
|
|
16
|
+
- **Market Data**: screen_stocks, get_stock_quote, get_stock_history, get_crypto_price, get_crypto_history — use screen_stocks for breadth and screening prompts such as large-cap lists, oversold stocks, market movers, and filtered market scans; use get_stock_quote/get_stock_history for a single-security quote or historical OHLCV
|
|
17
17
|
- **Fundamentals**: get_company_overview, get_financials, get_earnings, compute_dcf, compare_companies, get_sec_filings — company financials, valuation metrics, DCF intrinsic value, peer comparison, and SEC EDGAR filings (10-K, 10-Q, 8-K)
|
|
18
18
|
- **Technical Analysis**: get_technical_indicators, backtest_strategy — SMA, EMA, RSI, MACD, Bollinger Bands, OBV, VWAP computed from price data, plus simple strategy backtesting
|
|
19
19
|
- **Macro**: get_economic_data, get_fear_greed — FRED economic indicators and market sentiment
|
|
20
20
|
- **Sentiment**: get_reddit_sentiment, get_twitter_sentiment, get_web_sentiment, get_sentiment_trend, get_sentiment_summary — retail and news sentiment from Reddit, Twitter/X, and web sources with historical trends
|
|
21
21
|
- **Options**: get_option_chain — full options chain with strikes, bids/asks, volume, OI, IV, and computed Greeks (delta, gamma, theta, vega, rho)
|
|
22
|
-
- **Portfolio**: track_portfolio, analyze_risk, manage_watchlist, analyze_correlation, track_prediction — position tracking, P&L, Sharpe ratio, VaR, watchlist
|
|
22
|
+
- **Portfolio**: track_portfolio, analyze_risk, manage_watchlist, analyze_correlation, track_prediction, manage_alerts, daily_watchlist_report, manage_notifications — position tracking, P&L, Sharpe ratio, VaR, watchlist tracking, durable local alerts, daily watchlist reports, notification history, correlation matrix, and prediction tracking with accuracy scoring
|
|
23
23
|
- **User Interaction**: ask_user — ask clarification questions; trigger_twitter_login — open a browser for Twitter/X login
|
|
24
24
|
|
|
25
25
|
## Analytical Framework
|
|
@@ -45,11 +45,15 @@ Calibrate explanation depth from conversational signals: the user's vocabulary i
|
|
|
45
45
|
|
|
46
46
|
## Guidelines
|
|
47
47
|
- Always fetch data with tools before stating prices, ratios, or metrics. Never guess financial numbers. Every substantive response should be backed by at least one tool call — if you find yourself writing a response with zero tool calls, stop and think about what data would make it better.
|
|
48
|
+
- Use screen_stocks for breadth and screening prompts ("which large caps...", "find oversold stocks...", "market movers by filter"). Use get_stock_quote, get_stock_history, get_option_chain, fundamentals, and analysis workflows for single-security quote, history, options, DCF, or company-analysis prompts.
|
|
49
|
+
- For current single-stock recommendations, state the quote or tool-output date in the final answer. If tool output says the market is closed, the quote is delayed, or this is the last available quote, carry that freshness note into the final answer. If DCF or another valuation model is unavailable or not meaningful, do not let that tool failure become the whole valuation view; use supported fallback valuation lenses such as relative multiples, growth-adjusted multiples, cash-flow quality, balance-sheet risk, and historical range context. Do not make missing fundamentals the main thesis when quote, earnings, technicals, sentiment, or news are available; use those data points plus structural business risks to give a clear call, position sizing, and entry strategy.
|
|
50
|
+
- For ticker-specific sentiment prompts, call get_stock_quote before the final answer and state whether sentiment diverges from price action. For sentiment-only prompts, include source-coverage risk, low sample counts, missing sources, and how those gaps downgrade confidence.
|
|
48
51
|
- For options analysis, use get_option_chain to see the full chain with Greeks. Pay attention to put/call ratio, unusual volume, and IV levels.
|
|
49
52
|
- Present numerical data in tables when comparing multiple securities.
|
|
50
53
|
- Include data timestamps so users know how fresh the information is.
|
|
51
54
|
- Be concise and actionable. Lead with the commitment, then the reasoning chain.
|
|
52
55
|
- Flag downside and risks loudly. Commitment is not optimism — a bearish analyst view with conviction is valid output. Risk is expressed through the invalidation level and confidence band, never through refusal.
|
|
56
|
+
- Conceptual education prompts are not committal responses. Do not append "Analyst View", "Commitment", "Reasoning Chain", "Confidence Band", or "Invalidation Level" sections when the user asked for an explanation, definition, or learning framework rather than a trade, allocation, or recommendation.
|
|
53
57
|
- Reuse prior tool outputs when they already answer the question. Do not re-fetch the same symbol and parameters unless you need a missing field or fresher timestamp.
|
|
54
58
|
- If one provider is missing data, continue with the remaining tools and clearly label unavailable metrics instead of aborting the entire response.
|
|
55
59
|
|
package/src/tool-kit.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import type { TSchema } from "@sinclair/typebox";
|
|
2
1
|
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
3
2
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
4
4
|
import { agentToolToPiTool } from "./pi/tool-adapter.js";
|
|
5
5
|
|
|
6
|
+
export type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
7
|
+
export type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
8
|
+
export { Type } from "@sinclair/typebox";
|
|
6
9
|
// Re-exports for tool authors — import from "opencandle/tool-kit"
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
9
|
-
export {
|
|
10
|
+
export { Cache, cache, TTL } from "./infra/cache.js";
|
|
11
|
+
export { type HttpClientOptions, HttpError, httpGet } from "./infra/http-client.js";
|
|
12
|
+
export { RateLimiter, rateLimiter } from "./infra/rate-limiter.js";
|
|
10
13
|
export { agentToolToPiTool } from "./pi/tool-adapter.js";
|
|
11
|
-
export { Type } from "@sinclair/typebox";
|
|
12
|
-
export type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
13
|
-
export type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
14
14
|
|
|
15
15
|
// Module-level registry — all extensions run in the same Node.js process,
|
|
16
16
|
// so keep a deduped index keyed by tool name.
|
|
@@ -20,7 +20,8 @@ export function getAddonToolDescriptions(): ReadonlyArray<{ name: string; descri
|
|
|
20
20
|
return Array.from(addonToolRegistry.values());
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const SNAKE_CASE_VERB_RE =
|
|
23
|
+
const SNAKE_CASE_VERB_RE =
|
|
24
|
+
/^(get|analyze|search|calculate|compare|compute|track|manage|backtest|list|fetch|check)_[a-z][a-z0-9_]*$/;
|
|
24
25
|
|
|
25
26
|
export interface ToolConfig<TParams extends TSchema, TDetails = unknown> {
|
|
26
27
|
name: string;
|
|
@@ -36,7 +37,7 @@ export function createTool<TParams extends TSchema, TDetails = unknown>(
|
|
|
36
37
|
if (!config.name || !SNAKE_CASE_VERB_RE.test(config.name)) {
|
|
37
38
|
throw new Error(
|
|
38
39
|
`Invalid tool name "${config.name}": must be snake_case and start with a verb prefix ` +
|
|
39
|
-
|
|
40
|
+
`(get_, analyze_, search_, calculate_, compare_, compute_, track_, manage_, backtest_, list_, fetch_, check_)`,
|
|
40
41
|
);
|
|
41
42
|
}
|
|
42
43
|
if (!config.description || config.description.trim().length === 0) {
|
|
@@ -1,28 +1,38 @@
|
|
|
1
|
-
import { Type } from "@sinclair/typebox";
|
|
2
1
|
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
3
|
-
import {
|
|
4
|
-
import { wrapProvider } from "../../providers/wrap-provider.js";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
5
3
|
import { getConfig } from "../../config.js";
|
|
6
4
|
import { withCredentialCheck } from "../../onboarding/tool-helpers.js";
|
|
5
|
+
import { getOverview } from "../../providers/alpha-vantage.js";
|
|
6
|
+
import { wrapProvider } from "../../providers/wrap-provider.js";
|
|
7
7
|
import type { CompanyOverview } from "../../types/fundamentals.js";
|
|
8
8
|
|
|
9
9
|
const params = Type.Object({
|
|
10
10
|
symbol: Type.String({ description: "Stock ticker symbol (e.g. AAPL, MSFT)" }),
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
export const companyOverviewTool: AgentTool<
|
|
13
|
+
export const companyOverviewTool: AgentTool<
|
|
14
|
+
typeof params,
|
|
15
|
+
CompanyOverview | { credentialRequired: unknown }
|
|
16
|
+
> = {
|
|
14
17
|
name: "get_company_overview",
|
|
15
18
|
label: "Company Overview",
|
|
16
19
|
description:
|
|
17
20
|
"Get company fundamentals: P/E ratio, EPS, market cap, sector, dividend yield, profit margin, beta, and description. Requires Alpha Vantage.",
|
|
18
21
|
parameters: params,
|
|
19
|
-
async execute(
|
|
22
|
+
async execute(_toolCallId, args) {
|
|
20
23
|
return withCredentialCheck("alpha_vantage", async () => {
|
|
21
24
|
const apiKey = getConfig().alphaVantageApiKey!;
|
|
22
|
-
const result = await wrapProvider("alphavantage", () =>
|
|
25
|
+
const result = await wrapProvider("alphavantage", () =>
|
|
26
|
+
getOverview(args.symbol.toUpperCase(), apiKey),
|
|
27
|
+
);
|
|
23
28
|
if (result.status === "unavailable") {
|
|
24
29
|
return {
|
|
25
|
-
content: [
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: `⚠ Company overview unavailable for ${args.symbol.toUpperCase()} (${result.reason}). Analysis will proceed without fundamentals.`,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
26
36
|
details: null as any,
|
|
27
37
|
};
|
|
28
38
|
}
|
|
@@ -31,11 +41,11 @@ export const companyOverviewTool: AgentTool<typeof params, CompanyOverview | { c
|
|
|
31
41
|
`**${ov.name}** (${ov.symbol}) — ${ov.exchange}`,
|
|
32
42
|
`Sector: ${ov.sector} | Industry: ${ov.industry}`,
|
|
33
43
|
`Market Cap: $${formatLargeNumber(ov.marketCap)} | P/E: ${ov.pe ?? "N/A"} | Fwd P/E: ${ov.forwardPe ?? "N/A"}`,
|
|
34
|
-
`EPS: $${ov.eps ?? "N/A"} | Div Yield: ${ov.dividendYield ? (ov.dividendYield * 100).toFixed(2)
|
|
35
|
-
`Beta: ${ov.beta ?? "N/A"} | Profit Margin: ${ov.profitMargin ? (ov.profitMargin * 100).toFixed(1)
|
|
44
|
+
`EPS: $${ov.eps ?? "N/A"} | Div Yield: ${ov.dividendYield ? `${(ov.dividendYield * 100).toFixed(2)}%` : "N/A"}`,
|
|
45
|
+
`Beta: ${ov.beta ?? "N/A"} | Profit Margin: ${ov.profitMargin ? `${(ov.profitMargin * 100).toFixed(1)}%` : "N/A"}`,
|
|
36
46
|
`52W: $${ov.week52Low.toFixed(2)} - $${ov.week52High.toFixed(2)}`,
|
|
37
47
|
``,
|
|
38
|
-
ov.description.slice(0, 300)
|
|
48
|
+
`${ov.description.slice(0, 300)}${ov.description.length > 300 ? "..." : ""}`,
|
|
39
49
|
].join("\n");
|
|
40
50
|
|
|
41
51
|
const prefix = result.stale
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Type } from "@sinclair/typebox";
|
|
2
1
|
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
3
|
-
import {
|
|
4
|
-
import { wrapProvider } from "../../providers/wrap-provider.js";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
5
3
|
import { getConfig } from "../../config.js";
|
|
6
4
|
import { withCredentialCheck } from "../../onboarding/tool-helpers.js";
|
|
5
|
+
import { getOverview } from "../../providers/alpha-vantage.js";
|
|
6
|
+
import { wrapProvider } from "../../providers/wrap-provider.js";
|
|
7
7
|
import type { CompanyOverview } from "../../types/fundamentals.js";
|
|
8
8
|
|
|
9
9
|
export interface CompsMetric {
|
|
@@ -55,8 +55,12 @@ export function computeComps(companies: CompanyOverview[]): CompsResult {
|
|
|
55
55
|
const p25 = computePercentile(sortedVals, 0.25);
|
|
56
56
|
const p75 = computePercentile(sortedVals, 0.75);
|
|
57
57
|
|
|
58
|
-
const best = def.lowerIsBetter
|
|
59
|
-
|
|
58
|
+
const best = def.lowerIsBetter
|
|
59
|
+
? (sorted[0]?.sym ?? "")
|
|
60
|
+
: (sorted[sorted.length - 1]?.sym ?? "");
|
|
61
|
+
const worst = def.lowerIsBetter
|
|
62
|
+
? (sorted[sorted.length - 1]?.sym ?? "")
|
|
63
|
+
: (sorted[0]?.sym ?? "");
|
|
60
64
|
|
|
61
65
|
return { metric: def.name, values, median, p25, p75, best, worst };
|
|
62
66
|
});
|
|
@@ -67,9 +71,7 @@ export function computeComps(companies: CompanyOverview[]): CompsResult {
|
|
|
67
71
|
function computeMedian(sorted: number[]): number | null {
|
|
68
72
|
if (sorted.length === 0) return null;
|
|
69
73
|
const mid = Math.floor(sorted.length / 2);
|
|
70
|
-
return sorted.length % 2 === 0
|
|
71
|
-
? (sorted[mid - 1] + sorted[mid]) / 2
|
|
72
|
-
: sorted[mid];
|
|
74
|
+
return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
function computePercentile(sorted: number[], p: number): number | null {
|
|
@@ -96,61 +98,72 @@ export const compsTool: AgentTool<typeof params> = {
|
|
|
96
98
|
description:
|
|
97
99
|
"Compare 2-6 companies side-by-side on key valuation and financial metrics: P/E, Forward P/E, EPS, Profit Margin, Revenue Growth, Dividend Yield, Beta. Identifies the cheapest and most expensive on each metric.",
|
|
98
100
|
parameters: params,
|
|
99
|
-
async execute(
|
|
101
|
+
async execute(_toolCallId, args) {
|
|
100
102
|
return withCredentialCheck("alpha_vantage", async () => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
103
|
+
const config = getConfig();
|
|
104
|
+
const symbols = args.symbols.map((s) => s.toUpperCase());
|
|
105
|
+
|
|
106
|
+
const results = await Promise.all(
|
|
107
|
+
symbols.map(async (s) => ({
|
|
108
|
+
symbol: s,
|
|
109
|
+
result: await wrapProvider("alphavantage", () =>
|
|
110
|
+
getOverview(s, config.alphaVantageApiKey!),
|
|
111
|
+
),
|
|
112
|
+
})),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const companies: CompanyOverview[] = [];
|
|
116
|
+
const unavailableSymbols: string[] = [];
|
|
117
|
+
|
|
118
|
+
for (const { symbol: sym, result: r } of results) {
|
|
119
|
+
if (r.status === "ok") {
|
|
120
|
+
companies.push(r.data);
|
|
121
|
+
} else {
|
|
122
|
+
unavailableSymbols.push(sym);
|
|
123
|
+
}
|
|
119
124
|
}
|
|
120
|
-
}
|
|
121
125
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
if (companies.length === 0) {
|
|
127
|
+
return {
|
|
128
|
+
content: [
|
|
129
|
+
{
|
|
130
|
+
type: "text",
|
|
131
|
+
text: `⚠ Company fundamentals unavailable for all symbols: ${symbols.join(", ")}. Alpha Vantage may be rate limited.`,
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
details: null as any,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
128
137
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
const result = computeComps(companies);
|
|
139
|
+
result.unavailableSymbols = unavailableSymbols;
|
|
140
|
+
|
|
141
|
+
const availableSymbols = companies.map((company) => company.symbol);
|
|
142
|
+
const header = `**Comparable Company Analysis**: ${availableSymbols.join(" vs ")}`;
|
|
143
|
+
const rows = result.metrics.map((m) => {
|
|
144
|
+
const vals = availableSymbols.map((s) => {
|
|
145
|
+
const v = m.values[s];
|
|
146
|
+
if (v == null) return "N/A".padStart(10);
|
|
147
|
+
if (Math.abs(v) < 1) return `${(v * 100).toFixed(1)}%`.padStart(10);
|
|
148
|
+
return v.toFixed(2).padStart(10);
|
|
149
|
+
});
|
|
150
|
+
const medStr =
|
|
151
|
+
m.median != null
|
|
152
|
+
? Math.abs(m.median) < 1
|
|
153
|
+
? `${(m.median * 100).toFixed(1)}%`
|
|
154
|
+
: m.median.toFixed(2)
|
|
155
|
+
: "N/A";
|
|
156
|
+
return ` ${m.metric.padEnd(16)} ${vals.join("")} Med: ${medStr} Best: ${m.best}`;
|
|
140
157
|
});
|
|
141
|
-
const medStr = m.median != null
|
|
142
|
-
? (Math.abs(m.median) < 1 ? `${(m.median * 100).toFixed(1)}%` : m.median.toFixed(2))
|
|
143
|
-
: "N/A";
|
|
144
|
-
return ` ${m.metric.padEnd(16)} ${vals.join("")} Med: ${medStr} Best: ${m.best}`;
|
|
145
|
-
});
|
|
146
158
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
159
|
+
const symHeader = ` ${"Metric".padEnd(16)} ${availableSymbols.map((s) => s.padStart(10)).join("")}`;
|
|
160
|
+
const noteLines =
|
|
161
|
+
unavailableSymbols.length > 0
|
|
162
|
+
? ["", `Unavailable fundamentals: ${unavailableSymbols.join(", ")}`]
|
|
163
|
+
: [];
|
|
164
|
+
const text = [header, "", symHeader, ...rows, ...noteLines].join("\n");
|
|
152
165
|
|
|
153
|
-
|
|
166
|
+
return { content: [{ type: "text", text }], details: result };
|
|
154
167
|
});
|
|
155
168
|
},
|
|
156
169
|
};
|