opencandle 0.5.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/README.md +164 -187
- 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 +30 -7
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +3 -3
- package/dist/config.js +12 -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/browser.js +3 -1
- 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.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.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 +412 -28
- 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.js +5 -2
- package/dist/pi/tool-adapter.js.map +1 -1
- package/dist/prompts/context-builder.d.ts +1 -1
- package/dist/prompts/context-builder.js +19 -6
- package/dist/prompts/context-builder.js.map +1 -1
- package/dist/prompts/policy-cards.d.ts +1 -1
- package/dist/prompts/policy-cards.js +1 -1
- 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/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 +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.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 +1 -1
- package/dist/providers/yahoo-finance.js +101 -17
- 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 +1 -1
- 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.js +36 -8
- 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 +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 +3 -2
- 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 +23 -19
- package/dist/tools/index.js +51 -39
- 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.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/reddit-sentiment.js +23 -10
- package/dist/tools/sentiment/reddit-sentiment.js.map +1 -1
- package/dist/tools/sentiment/sentiment-summary.js +15 -13
- 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 +12 -5
- 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 +15 -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/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 +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 +12 -7
- package/gui/server/prompt-observation.ts +4 -7
- package/gui/server/quote-snapshot-store.ts +50 -0
- package/gui/server/server.ts +200 -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 +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 +5 -1
- package/src/analysts/contracts.ts +10 -23
- package/src/analysts/orchestrator.ts +8 -43
- package/src/cli.ts +35 -12
- package/src/config.ts +17 -9
- package/src/index.ts +1 -1
- package/src/infra/browser.ts +3 -1
- 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 +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 +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 +529 -85
- package/src/pi/session.ts +7 -5
- package/src/pi/setup.ts +61 -43
- package/src/pi/tool-adapter.ts +5 -2
- package/src/prompts/context-builder.ts +23 -12
- package/src/prompts/policy-cards.ts +2 -2
- 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/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 +20 -6
- 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 +140 -35
- 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 +144 -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 +82 -43
- 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 +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 +3 -2
- 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 +51 -39
- 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 +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/reddit-sentiment.ts +50 -24
- package/src/tools/sentiment/sentiment-summary.ts +62 -41
- package/src/tools/sentiment/sentiment-trend.ts +24 -7
- package/src/tools/sentiment/twitter-sentiment.ts +22 -15
- 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 +26 -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 +2 -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/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/workflows/types.ts +0 -4
package/src/pi/session.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import "../infra/node-version.js";
|
|
2
2
|
import {
|
|
3
3
|
type AuthStorage,
|
|
4
|
+
type CreateAgentSessionResult,
|
|
4
5
|
createAgentSession,
|
|
5
6
|
DefaultResourceLoader,
|
|
7
|
+
getAgentDir,
|
|
6
8
|
type ModelRegistry,
|
|
7
|
-
type CreateAgentSessionResult,
|
|
8
|
-
type SettingsManager,
|
|
9
9
|
type SessionManager,
|
|
10
|
-
|
|
10
|
+
type SettingsManager,
|
|
11
11
|
} from "@earendil-works/pi-coding-agent";
|
|
12
12
|
import { loadEnv } from "../config.js";
|
|
13
|
-
import openCandleExtension from "./opencandle-extension.js";
|
|
14
13
|
import type { AskUserHandler } from "../types/index.js";
|
|
14
|
+
import openCandleExtension from "./opencandle-extension.js";
|
|
15
15
|
|
|
16
16
|
export interface CreateOpenCandleSessionOptions {
|
|
17
17
|
cwd?: string;
|
|
@@ -38,7 +38,9 @@ export async function createOpenCandleSession(
|
|
|
38
38
|
cwd,
|
|
39
39
|
agentDir,
|
|
40
40
|
settingsManager: options.settingsManager,
|
|
41
|
-
extensionFactories: [
|
|
41
|
+
extensionFactories: [
|
|
42
|
+
(pi) => openCandleExtension(pi, { askUserHandler: options.askUserHandler }),
|
|
43
|
+
],
|
|
42
44
|
})
|
|
43
45
|
: undefined;
|
|
44
46
|
|
package/src/pi/setup.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Model } from "@earendil-works/pi-ai";
|
|
2
2
|
import {
|
|
3
|
-
LoginDialogComponent,
|
|
4
3
|
type ExtensionAPI,
|
|
5
4
|
type ExtensionContext,
|
|
5
|
+
LoginDialogComponent,
|
|
6
6
|
} from "@earendil-works/pi-coding-agent";
|
|
7
7
|
|
|
8
8
|
type SetupMode = "startup" | "manual";
|
|
@@ -54,14 +54,18 @@ function getAvailableModels(ctx: ExtensionContext, preferredProvider?: string):
|
|
|
54
54
|
return sortModels(ctx.modelRegistry.getAvailable(), preferredProvider);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
export function getLlmSetupRequirement(
|
|
57
|
+
export function getLlmSetupRequirement(
|
|
58
|
+
ctx: Pick<ExtensionContext, "model" | "modelRegistry">,
|
|
59
|
+
): SetupRequirement {
|
|
58
60
|
if (ctx.model && ctx.modelRegistry.hasConfiguredAuth(ctx.model)) {
|
|
59
61
|
return "ready";
|
|
60
62
|
}
|
|
61
63
|
return ctx.modelRegistry.getAvailable().length > 0 ? "select_model" : "connect_auth";
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
async function selectProviderForApiKey(
|
|
66
|
+
async function selectProviderForApiKey(
|
|
67
|
+
ctx: ExtensionContext,
|
|
68
|
+
): Promise<ApiKeyProviderId | undefined> {
|
|
65
69
|
const choice = await ctx.ui.select("Connect an AI model", [
|
|
66
70
|
"Google Gemini API",
|
|
67
71
|
"OpenAI API",
|
|
@@ -79,7 +83,9 @@ async function selectProviderForApiKey(ctx: ExtensionContext): Promise<ApiKeyPro
|
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
async function selectProviderForLogin(
|
|
86
|
+
async function selectProviderForLogin(
|
|
87
|
+
ctx: ExtensionContext,
|
|
88
|
+
): Promise<OAuthProviderChoice | undefined> {
|
|
83
89
|
const choice = await ctx.ui.select("Connect an AI model", [
|
|
84
90
|
"Google",
|
|
85
91
|
"OpenAI",
|
|
@@ -112,7 +118,9 @@ async function selectAdvancedOAuthProvider(ctx: ExtensionContext): Promise<strin
|
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
async function runLoginDialog(ctx: ExtensionContext, providerId: string): Promise<boolean> {
|
|
115
|
-
const provider = ctx.modelRegistry.authStorage
|
|
121
|
+
const provider = ctx.modelRegistry.authStorage
|
|
122
|
+
.getOAuthProviders()
|
|
123
|
+
.find((item) => item.id === providerId);
|
|
116
124
|
const providerName = provider?.name ?? providerId;
|
|
117
125
|
const usesCallbackServer = provider?.usesCallbackServer ?? false;
|
|
118
126
|
|
|
@@ -136,43 +144,49 @@ async function runLoginDialog(ctx: ExtensionContext, providerId: string): Promis
|
|
|
136
144
|
});
|
|
137
145
|
|
|
138
146
|
// Cast required: advanced providers return dynamic IDs outside the SDK's static union type
|
|
139
|
-
void ctx.modelRegistry.authStorage
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
147
|
+
void ctx.modelRegistry.authStorage
|
|
148
|
+
.login(providerId as any, {
|
|
149
|
+
onAuth: (info) => {
|
|
150
|
+
dialog.showAuth(info.url, info.instructions);
|
|
151
|
+
if (usesCallbackServer) {
|
|
152
|
+
void dialog
|
|
153
|
+
.showManualInput("Paste redirect URL below, or complete login in your browser:")
|
|
154
|
+
.then((value) => {
|
|
155
|
+
if (value && manualCodeResolve) {
|
|
156
|
+
manualCodeResolve(value);
|
|
157
|
+
manualCodeResolve = undefined;
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
.catch(() => {
|
|
161
|
+
if (manualCodeReject) {
|
|
162
|
+
manualCodeReject(new Error("Login cancelled"));
|
|
163
|
+
manualCodeReject = undefined;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
} else if (providerId === "github-copilot") {
|
|
167
|
+
dialog.showWaiting("Waiting for browser authentication...");
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
onDeviceCode: (info) => {
|
|
171
|
+
dialog.showDeviceCode(info);
|
|
172
|
+
dialog.showWaiting("Waiting for authentication...");
|
|
173
|
+
},
|
|
174
|
+
onPrompt: async (prompt) => dialog.showPrompt(prompt.message, prompt.placeholder),
|
|
175
|
+
onProgress: (message) => dialog.showProgress(message),
|
|
176
|
+
onSelect: async (prompt) => {
|
|
177
|
+
const options = prompt.options
|
|
178
|
+
.map((option, index) => `${index + 1}. ${option.label}`)
|
|
179
|
+
.join("\n");
|
|
180
|
+
const answer = await dialog.showPrompt(
|
|
181
|
+
`${prompt.message}\n\n${options}`,
|
|
182
|
+
"Enter a number",
|
|
183
|
+
);
|
|
184
|
+
const selectedIndex = Number.parseInt(answer.trim(), 10) - 1;
|
|
185
|
+
return prompt.options[selectedIndex]?.id;
|
|
186
|
+
},
|
|
187
|
+
onManualCodeInput: () => manualCodePromise,
|
|
188
|
+
signal: dialog.signal,
|
|
189
|
+
})
|
|
176
190
|
.then(() => finish(true))
|
|
177
191
|
.catch((error) => {
|
|
178
192
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -248,7 +262,11 @@ async function activateDefaultModel(
|
|
|
248
262
|
return true;
|
|
249
263
|
}
|
|
250
264
|
|
|
251
|
-
async function selectModel(
|
|
265
|
+
async function selectModel(
|
|
266
|
+
api: ExtensionAPI,
|
|
267
|
+
ctx: ExtensionContext,
|
|
268
|
+
preferredProvider?: string,
|
|
269
|
+
): Promise<boolean> {
|
|
252
270
|
const models = getAvailableModels(ctx, preferredProvider);
|
|
253
271
|
if (models.length === 0) {
|
|
254
272
|
ctx.ui.notify("No available models found yet. Connect a provider first.", "warning");
|
package/src/pi/tool-adapter.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
2
2
|
import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import type { TSchema } from "@sinclair/typebox";
|
|
4
|
-
import { getAllTools } from "../tools/index.js";
|
|
5
4
|
import { getDefaults } from "../memory/tool-defaults.js";
|
|
6
5
|
import { wrapWithDefaults } from "../runtime/tool-defaults-wrapper.js";
|
|
6
|
+
import { getAllTools } from "../tools/index.js";
|
|
7
7
|
|
|
8
8
|
export function agentToolToPiTool<TParams extends TSchema, TDetails>(
|
|
9
9
|
tool: AgentTool<TParams, TDetails>,
|
|
@@ -24,7 +24,10 @@ export function getOpenCandleToolDefinitions(): ToolDefinition[] {
|
|
|
24
24
|
return getAllTools()
|
|
25
25
|
.map((tool) => ({ tool, defaults: safeGetDefaults(tool.name) }))
|
|
26
26
|
.filter(({ defaults }) => defaults.__enabled !== false)
|
|
27
|
-
.map(({ tool, defaults }) =>
|
|
27
|
+
.map(({ tool, defaults }) => {
|
|
28
|
+
const { __enabled: _enabled, ...paramDefaults } = defaults;
|
|
29
|
+
return agentToolToPiTool(wrapWithDefaults(tool, paramDefaults));
|
|
30
|
+
});
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
function safeGetDefaults(toolName: string): Record<string, unknown> {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { PromptSection, SectionName } from "./sections.js";
|
|
2
|
-
import { SECTION_ORDER, DEFAULT_BUDGETS, truncateTobudget } from "./sections.js";
|
|
3
|
-
import { renderPolicyCardForPlanning } from "./policy-cards.js";
|
|
4
1
|
import type { ResolvedTurnContext } from "../routing/turn-context.js";
|
|
2
|
+
import { renderPolicyCardForPlanning } from "./policy-cards.js";
|
|
3
|
+
import type { PromptSection, SectionName } from "./sections.js";
|
|
4
|
+
import { DEFAULT_BUDGETS, SECTION_ORDER, truncateTobudget } from "./sections.js";
|
|
5
5
|
|
|
6
6
|
export interface PromptSectionReport {
|
|
7
7
|
name: SectionName;
|
|
@@ -122,10 +122,7 @@ export class PromptContextBuilder {
|
|
|
122
122
|
policyCard ? `${policyCard}\n\n${routePlaybook}` : routePlaybook,
|
|
123
123
|
);
|
|
124
124
|
} else if (options.fallbackContext) {
|
|
125
|
-
this.setSection(
|
|
126
|
-
"workflow-instructions",
|
|
127
|
-
buildFallbackPlaybook(options.fallbackContext),
|
|
128
|
-
);
|
|
125
|
+
this.setSection("workflow-instructions", buildFallbackPlaybook(options.fallbackContext));
|
|
129
126
|
}
|
|
130
127
|
if (options.memoryContext) {
|
|
131
128
|
this.setSection("memory-context", formatMemorySection(options.memoryContext));
|
|
@@ -150,12 +147,26 @@ export function buildFallbackPlaybook(ctx: FallbackContext): string {
|
|
|
150
147
|
|
|
151
148
|
export function buildRoutePlaybook(ctx: ResolvedTurnContext): string {
|
|
152
149
|
const assumptionsBlock = buildResolvedAssumptionsBlock(ctx);
|
|
150
|
+
const droppedSymbols = ctx.diagnostics
|
|
151
|
+
.filter((diagnostic) => diagnostic.code === "symbol_dropped")
|
|
152
|
+
.map((diagnostic) => diagnostic.details?.token)
|
|
153
|
+
.filter((token): token is string => typeof token === "string" && token.length > 0);
|
|
154
|
+
const dropContext =
|
|
155
|
+
droppedSymbols.length > 0
|
|
156
|
+
? `Dropped ambiguous ticker-like tokens: ${droppedSymbols.join(", ")}.`
|
|
157
|
+
: undefined;
|
|
158
|
+
const extraContext = [
|
|
159
|
+
ctx.entities.symbols.length > 0
|
|
160
|
+
? `Router-extracted symbols: ${ctx.entities.symbols.join(", ")}. Route kind: ${ctx.routeKind}. Tool bundles: ${ctx.toolBundles.join(", ") || "(none)"}.`
|
|
161
|
+
: `Route kind: ${ctx.routeKind}. Tool bundles: ${ctx.toolBundles.join(", ") || "(none)"}.`,
|
|
162
|
+
dropContext,
|
|
163
|
+
]
|
|
164
|
+
.filter((part): part is string => Boolean(part))
|
|
165
|
+
.join(" ");
|
|
153
166
|
const fallbackContext: FallbackContext = {
|
|
154
167
|
assumptionsBlock,
|
|
155
168
|
missingRequired: ctx.missingRequired,
|
|
156
|
-
extraContext
|
|
157
|
-
? `Router-extracted symbols: ${ctx.entities.symbols.join(", ")}. Route kind: ${ctx.routeKind}. Tool bundles: ${ctx.toolBundles.join(", ") || "(none)"}.`
|
|
158
|
-
: `Route kind: ${ctx.routeKind}. Tool bundles: ${ctx.toolBundles.join(", ") || "(none)"}.`,
|
|
169
|
+
extraContext,
|
|
159
170
|
};
|
|
160
171
|
|
|
161
172
|
if (ctx.routeKind === "clarification") {
|
|
@@ -273,14 +284,14 @@ Keep questions concise and offer specific options when possible. Prefer select-t
|
|
|
273
284
|
CRITICAL: After ask_user answers come back, your NEXT action MUST be tool calls — not a text response. You are a data agent, not a chatbot. Never respond with generic investment categories or tell the user to come back with tickers. YOU pick the relevant assets and indicators based on what you learned, then fetch the data.`;
|
|
274
285
|
|
|
275
286
|
const TOOL_CATALOG = `## Available Tools
|
|
276
|
-
- **Market Data**: get_stock_quote, get_stock_history, get_crypto_price, get_crypto_history —
|
|
287
|
+
- **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
|
|
277
288
|
- **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)
|
|
278
289
|
- **Technical Analysis**: get_technical_indicators, backtest_strategy — SMA, EMA, RSI, MACD, Bollinger Bands, OBV, VWAP computed from price data, plus simple strategy backtesting
|
|
279
290
|
- **Macro**: get_economic_data, get_fear_greed — FRED economic indicators and market sentiment
|
|
280
291
|
- **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 and cross-source divergence detection
|
|
281
292
|
- **Web Search**: search_web — breaking news, earnings context, company events, regulatory developments. Supported freshness values are hours, day, week, and month; use category general with freshness month for broad industry context; never pass unsupported values such as all, year, 3mo, quarter, or custom date ranges. When a dedicated tool can answer the question (quotes, fundamentals, earnings, macro, SEC filings, sentiment), use that tool instead — do not add search_web as a supplementary source for data available through dedicated tools
|
|
282
293
|
- **Options**: get_option_chain — full options chain with strikes, bids/asks, volume, OI, IV, and computed Greeks (delta, gamma, theta, vega, rho)
|
|
283
|
-
- **Portfolio**: track_portfolio, analyze_risk, manage_watchlist, analyze_correlation, analyze_holdings_overlap, track_prediction — position tracking, P&L, Sharpe ratio, VaR, watchlist
|
|
294
|
+
- **Portfolio**: track_portfolio, analyze_risk, manage_watchlist, analyze_correlation, analyze_holdings_overlap, 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, ETF/fund holdings overlap, and prediction tracking with accuracy scoring
|
|
284
295
|
- **User Interaction**: ask_user — ask the user a clarification question when their request is ambiguous or missing key details`;
|
|
285
296
|
|
|
286
297
|
function buildToolCatalog(addonDescriptions?: string[]): string {
|
|
@@ -27,7 +27,7 @@ export const POLICY_CARD_IDS = [
|
|
|
27
27
|
"general_fallback",
|
|
28
28
|
] as const;
|
|
29
29
|
|
|
30
|
-
export type PromptPolicyCardId = typeof POLICY_CARD_IDS[number];
|
|
30
|
+
export type PromptPolicyCardId = (typeof POLICY_CARD_IDS)[number];
|
|
31
31
|
|
|
32
32
|
export interface PolicyCard {
|
|
33
33
|
id: PromptPolicyCardId;
|
|
@@ -133,7 +133,7 @@ For strategy backtest prompts, use backtest_strategy evidence before judging whe
|
|
|
133
133
|
status: "implemented",
|
|
134
134
|
capabilityGapIds: [],
|
|
135
135
|
content: `## Stateful Tracking Update Policy
|
|
136
|
-
For watchlist, portfolio tracking, prediction recording, and prediction-check prompts, use the state tool that owns the change or lookup: manage_watchlist, track_prediction, or
|
|
136
|
+
For watchlist, portfolio tracking, alert management, daily-report, prediction recording, and prediction-check prompts, use the state tool that owns the change or lookup: manage_watchlist, track_prediction, track_portfolio, manage_alerts, or daily_watchlist_report. Do not confirm a saved change from prose alone. Confirm the persisted state update with the symbol, action, direction, entry price, target, stop, conviction, timeframe, or check result that the tool accepted. If the user asks to create an alert and check it now in the same request, call manage_alerts with the matching create action and check_after_create=true. If required fields for a state mutation are missing, ask the smallest clarification question instead of inventing values. For check or list operations, summarize the saved state and say clearly when no records exist. Do not turn a state update into a buy/sell recommendation unless the user separately asks for market analysis.`,
|
|
137
137
|
},
|
|
138
138
|
retail_finance_tradeoff: {
|
|
139
139
|
id: "retail_finance_tradeoff",
|
package/src/prompts/sections.ts
CHANGED
|
@@ -32,7 +32,7 @@ export const SECTION_ORDER = [
|
|
|
32
32
|
"output-format",
|
|
33
33
|
] as const;
|
|
34
34
|
|
|
35
|
-
export type SectionName = typeof SECTION_ORDER[number];
|
|
35
|
+
export type SectionName = (typeof SECTION_ORDER)[number];
|
|
36
36
|
|
|
37
37
|
/** Default character budgets per section. */
|
|
38
38
|
export const DEFAULT_BUDGETS: Record<SectionName, number> = {
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type InstrumentCandidate, searchYahooInstruments } from "../market-state/resolve.js";
|
|
2
|
+
|
|
3
|
+
export interface SymbolValidation {
|
|
4
|
+
valid: boolean;
|
|
5
|
+
reason?: string;
|
|
6
|
+
checkedAt: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type SymbolValidationCache = Map<string, SymbolValidation>;
|
|
10
|
+
|
|
11
|
+
export interface SymbolPreflightDrop {
|
|
12
|
+
symbol: string;
|
|
13
|
+
reason: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface SymbolPreflightResult {
|
|
17
|
+
valid: string[];
|
|
18
|
+
dropped: SymbolPreflightDrop[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function preflightSymbols(
|
|
22
|
+
symbols: string[],
|
|
23
|
+
options: {
|
|
24
|
+
cache?: SymbolValidationCache;
|
|
25
|
+
search?: (query: string) => Promise<InstrumentCandidate[]>;
|
|
26
|
+
} = {},
|
|
27
|
+
): Promise<SymbolPreflightResult> {
|
|
28
|
+
const cache = options.cache;
|
|
29
|
+
const search = options.search ?? searchYahooInstruments;
|
|
30
|
+
const valid: string[] = [];
|
|
31
|
+
const dropped: SymbolPreflightDrop[] = [];
|
|
32
|
+
|
|
33
|
+
for (const rawSymbol of symbols) {
|
|
34
|
+
const symbol = rawSymbol.trim().toUpperCase();
|
|
35
|
+
if (!symbol) continue;
|
|
36
|
+
|
|
37
|
+
const cached = cache?.get(symbol);
|
|
38
|
+
const validation = cached ?? (await validateSymbol(symbol, search));
|
|
39
|
+
if (!cached) cache?.set(symbol, validation);
|
|
40
|
+
|
|
41
|
+
if (validation.valid) {
|
|
42
|
+
valid.push(symbol);
|
|
43
|
+
} else {
|
|
44
|
+
dropped.push({
|
|
45
|
+
symbol,
|
|
46
|
+
reason: validation.reason ?? "no matching ticker found via resolver search",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { valid, dropped };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function formatPreflightDropAnnotation(dropped: SymbolPreflightDrop[]): string {
|
|
55
|
+
const count = dropped.length;
|
|
56
|
+
const symbols = dropped.map((drop) => `${drop.symbol} (${drop.reason})`).join(", ");
|
|
57
|
+
return `[Pre-flight: dropped ${count} unknown symbol${count === 1 ? "" : "s"} - ${symbols}]`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function validateSymbol(
|
|
61
|
+
symbol: string,
|
|
62
|
+
search: (query: string) => Promise<InstrumentCandidate[]>,
|
|
63
|
+
): Promise<SymbolValidation> {
|
|
64
|
+
return search(symbol)
|
|
65
|
+
.then((candidates) => ({
|
|
66
|
+
valid: candidates.some((candidate) => candidate.symbol.toUpperCase() === symbol),
|
|
67
|
+
reason: candidates.some((candidate) => candidate.symbol.toUpperCase() === symbol)
|
|
68
|
+
? undefined
|
|
69
|
+
: "no matching ticker found via resolver search",
|
|
70
|
+
checkedAt: Date.now(),
|
|
71
|
+
}))
|
|
72
|
+
.catch((error) => ({
|
|
73
|
+
valid: true,
|
|
74
|
+
reason:
|
|
75
|
+
error instanceof Error
|
|
76
|
+
? `resolver search unavailable: ${error.message}`
|
|
77
|
+
: "resolver search unavailable",
|
|
78
|
+
checkedAt: Date.now(),
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
@@ -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}.
|