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
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import type { MemoryCategory } from "../memory/types.js";
|
|
2
|
+
import type { RouterOutput, RouterRoute, RouterRouteKind, ToolBundleName } from "./router-types.js";
|
|
3
|
+
import type { ExtractedEntities, WorkflowType } from "./types.js";
|
|
4
|
+
|
|
5
|
+
export const ROUTE_KINDS: readonly RouterRouteKind[] = [
|
|
6
|
+
"workflow_dispatch",
|
|
7
|
+
"agent_task",
|
|
8
|
+
"clarification",
|
|
9
|
+
"pass_through",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export const TOOL_BUNDLE_TOOLS: Record<ToolBundleName, readonly string[]> = {
|
|
13
|
+
core_market: [
|
|
14
|
+
"search_ticker",
|
|
15
|
+
"get_stock_quote",
|
|
16
|
+
"get_stock_history",
|
|
17
|
+
"screen_stocks",
|
|
18
|
+
"get_crypto_price",
|
|
19
|
+
"get_crypto_history",
|
|
20
|
+
"get_company_overview",
|
|
21
|
+
"get_financials",
|
|
22
|
+
"get_earnings",
|
|
23
|
+
"compare_companies",
|
|
24
|
+
"compute_dcf",
|
|
25
|
+
"get_technical_indicators",
|
|
26
|
+
"backtest_strategy",
|
|
27
|
+
"analyze_risk",
|
|
28
|
+
"analyze_correlation",
|
|
29
|
+
"analyze_holdings_overlap",
|
|
30
|
+
"track_portfolio",
|
|
31
|
+
"manage_watchlist",
|
|
32
|
+
"track_prediction",
|
|
33
|
+
"manage_alerts",
|
|
34
|
+
"daily_watchlist_report",
|
|
35
|
+
"manage_notifications",
|
|
36
|
+
"search_web",
|
|
37
|
+
],
|
|
38
|
+
options: ["get_option_chain", "get_stock_quote", "search_ticker", "search_web"],
|
|
39
|
+
macro: ["get_economic_data", "get_fear_greed", "search_web"],
|
|
40
|
+
sentiment: [
|
|
41
|
+
"get_reddit_sentiment",
|
|
42
|
+
"get_twitter_sentiment",
|
|
43
|
+
"get_web_sentiment",
|
|
44
|
+
"get_sentiment_trend",
|
|
45
|
+
"get_sentiment_summary",
|
|
46
|
+
"get_fear_greed",
|
|
47
|
+
"search_web",
|
|
48
|
+
],
|
|
49
|
+
sec: ["get_sec_filings", "get_company_overview", "search_web"],
|
|
50
|
+
clarification: ["ask_user"],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type PromptPlaybookId =
|
|
54
|
+
| "workflow_dispatch"
|
|
55
|
+
| "agent_task"
|
|
56
|
+
| "clarification"
|
|
57
|
+
| "pass_through";
|
|
58
|
+
|
|
59
|
+
interface RouteCapability {
|
|
60
|
+
routeKind: RouterRouteKind;
|
|
61
|
+
legacyRoute: RouterRoute;
|
|
62
|
+
promptPlaybook: PromptPlaybookId;
|
|
63
|
+
toolBundles: ToolBundleName[];
|
|
64
|
+
memoryScopes: MemoryCategory[];
|
|
65
|
+
allowWorkflow: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface WorkflowCapability {
|
|
69
|
+
workflow: Exclude<WorkflowType, "unclassified">;
|
|
70
|
+
dispatchable: boolean;
|
|
71
|
+
requiredSlots: string[];
|
|
72
|
+
toolBundles: ToolBundleName[];
|
|
73
|
+
memoryScopes: MemoryCategory[];
|
|
74
|
+
promptPlaybook: PromptPlaybookId;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const ROUTE_CAPABILITY_MANIFEST: Record<RouterRouteKind, RouteCapability> = {
|
|
78
|
+
workflow_dispatch: {
|
|
79
|
+
routeKind: "workflow_dispatch",
|
|
80
|
+
legacyRoute: "workflow",
|
|
81
|
+
promptPlaybook: "workflow_dispatch",
|
|
82
|
+
toolBundles: ["core_market"],
|
|
83
|
+
memoryScopes: ["investor_profile", "workflow_history"],
|
|
84
|
+
allowWorkflow: true,
|
|
85
|
+
},
|
|
86
|
+
agent_task: {
|
|
87
|
+
routeKind: "agent_task",
|
|
88
|
+
legacyRoute: "fallback",
|
|
89
|
+
promptPlaybook: "agent_task",
|
|
90
|
+
toolBundles: ["core_market"],
|
|
91
|
+
memoryScopes: ["investor_profile", "workflow_history"],
|
|
92
|
+
allowWorkflow: false,
|
|
93
|
+
},
|
|
94
|
+
clarification: {
|
|
95
|
+
routeKind: "clarification",
|
|
96
|
+
legacyRoute: "fallback",
|
|
97
|
+
promptPlaybook: "clarification",
|
|
98
|
+
toolBundles: ["clarification"],
|
|
99
|
+
memoryScopes: ["investor_profile", "workflow_history"],
|
|
100
|
+
allowWorkflow: true,
|
|
101
|
+
},
|
|
102
|
+
pass_through: {
|
|
103
|
+
routeKind: "pass_through",
|
|
104
|
+
legacyRoute: "fallback",
|
|
105
|
+
promptPlaybook: "pass_through",
|
|
106
|
+
toolBundles: [],
|
|
107
|
+
memoryScopes: [],
|
|
108
|
+
allowWorkflow: false,
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const WORKFLOW_CAPABILITY_MANIFEST: Record<
|
|
113
|
+
Exclude<WorkflowType, "unclassified">,
|
|
114
|
+
WorkflowCapability
|
|
115
|
+
> = {
|
|
116
|
+
portfolio_builder: {
|
|
117
|
+
workflow: "portfolio_builder",
|
|
118
|
+
dispatchable: true,
|
|
119
|
+
requiredSlots: ["budget"],
|
|
120
|
+
toolBundles: ["core_market", "macro", "sentiment", "clarification"],
|
|
121
|
+
memoryScopes: ["investor_profile", "interaction_feedback", "workflow_history"],
|
|
122
|
+
promptPlaybook: "workflow_dispatch",
|
|
123
|
+
},
|
|
124
|
+
options_screener: {
|
|
125
|
+
workflow: "options_screener",
|
|
126
|
+
dispatchable: true,
|
|
127
|
+
requiredSlots: ["symbol"],
|
|
128
|
+
toolBundles: ["core_market", "options", "sentiment", "clarification"],
|
|
129
|
+
memoryScopes: ["investor_profile", "interaction_feedback", "workflow_history"],
|
|
130
|
+
promptPlaybook: "workflow_dispatch",
|
|
131
|
+
},
|
|
132
|
+
compare_assets: {
|
|
133
|
+
workflow: "compare_assets",
|
|
134
|
+
dispatchable: true,
|
|
135
|
+
requiredSlots: ["symbols"],
|
|
136
|
+
toolBundles: ["core_market", "macro", "sentiment", "clarification"],
|
|
137
|
+
memoryScopes: ["investor_profile", "workflow_history"],
|
|
138
|
+
promptPlaybook: "workflow_dispatch",
|
|
139
|
+
},
|
|
140
|
+
single_asset_analysis: {
|
|
141
|
+
workflow: "single_asset_analysis",
|
|
142
|
+
dispatchable: false,
|
|
143
|
+
requiredSlots: ["symbol"],
|
|
144
|
+
toolBundles: ["core_market", "options", "sentiment", "sec", "clarification"],
|
|
145
|
+
memoryScopes: ["investor_profile", "workflow_history"],
|
|
146
|
+
promptPlaybook: "agent_task",
|
|
147
|
+
},
|
|
148
|
+
watchlist_or_tracking: {
|
|
149
|
+
workflow: "watchlist_or_tracking",
|
|
150
|
+
dispatchable: false,
|
|
151
|
+
requiredSlots: [],
|
|
152
|
+
toolBundles: ["core_market", "clarification"],
|
|
153
|
+
memoryScopes: ["investor_profile", "workflow_history"],
|
|
154
|
+
promptPlaybook: "agent_task",
|
|
155
|
+
},
|
|
156
|
+
general_finance_qa: {
|
|
157
|
+
workflow: "general_finance_qa",
|
|
158
|
+
dispatchable: false,
|
|
159
|
+
requiredSlots: [],
|
|
160
|
+
toolBundles: ["core_market", "macro", "sentiment", "sec", "clarification"],
|
|
161
|
+
memoryScopes: ["investor_profile", "workflow_history"],
|
|
162
|
+
promptPlaybook: "agent_task",
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export function isRouteKind(value: string): value is RouterRouteKind {
|
|
167
|
+
return ROUTE_KINDS.includes(value as RouterRouteKind);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function isToolBundleName(value: string): value is ToolBundleName {
|
|
171
|
+
return Object.hasOwn(TOOL_BUNDLE_TOOLS, value);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function legacyRouteForRouteKind(routeKind: RouterRouteKind): RouterRoute {
|
|
175
|
+
return ROUTE_CAPABILITY_MANIFEST[routeKind].legacyRoute;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function isDispatchableWorkflow(
|
|
179
|
+
workflow: Exclude<WorkflowType, "unclassified"> | undefined,
|
|
180
|
+
): boolean {
|
|
181
|
+
if (!workflow) return false;
|
|
182
|
+
return WORKFLOW_CAPABILITY_MANIFEST[workflow]?.dispatchable === true;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function routeKindFromLegacyRoute(
|
|
186
|
+
route: RouterRoute,
|
|
187
|
+
missingRequired: readonly string[] = [],
|
|
188
|
+
): RouterRouteKind {
|
|
189
|
+
if (missingRequired.length > 0) return "clarification";
|
|
190
|
+
return route === "workflow" ? "workflow_dispatch" : "agent_task";
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function workflowRequiredSlots(
|
|
194
|
+
workflow: Exclude<WorkflowType, "unclassified"> | undefined,
|
|
195
|
+
): string[] {
|
|
196
|
+
if (!workflow) return [];
|
|
197
|
+
return WORKFLOW_CAPABILITY_MANIFEST[workflow]?.requiredSlots ?? [];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function computeMissingRequiredSlots(
|
|
201
|
+
workflow: Exclude<WorkflowType, "unclassified"> | undefined,
|
|
202
|
+
entities: ExtractedEntities,
|
|
203
|
+
slots: RouterOutput["slots"] = {},
|
|
204
|
+
existingMissing: readonly string[] = [],
|
|
205
|
+
): string[] {
|
|
206
|
+
const missing = new Set<string>();
|
|
207
|
+
const existing = new Set(existingMissing);
|
|
208
|
+
for (const slot of workflowRequiredSlots(workflow)) {
|
|
209
|
+
if (slot === "budget" && entities.budget === undefined && !slotHasValue(slots.budget)) {
|
|
210
|
+
missing.add("budget");
|
|
211
|
+
}
|
|
212
|
+
if (slot === "symbol" && entities.symbols.length === 0 && !slotHasValue(slots.symbol)) {
|
|
213
|
+
missing.add("symbol");
|
|
214
|
+
}
|
|
215
|
+
if (
|
|
216
|
+
slot === "symbols" &&
|
|
217
|
+
entities.symbols.length < 2 &&
|
|
218
|
+
!slotHasSymbolListValue(slots.symbols, 2)
|
|
219
|
+
) {
|
|
220
|
+
missing.add("symbols");
|
|
221
|
+
}
|
|
222
|
+
existing.delete(slot);
|
|
223
|
+
}
|
|
224
|
+
for (const slot of existing) {
|
|
225
|
+
if (!slotHasValue(slots[slot])) missing.add(slot);
|
|
226
|
+
}
|
|
227
|
+
return Array.from(missing);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function slotHasValue(slot: RouterOutput["slots"][string] | undefined): boolean {
|
|
231
|
+
if (!slot) return false;
|
|
232
|
+
if (Array.isArray(slot.value)) return slot.value.length > 0;
|
|
233
|
+
return slot.value !== undefined && slot.value !== null && slot.value !== "";
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function slotHasSymbolListValue(
|
|
237
|
+
slot: RouterOutput["slots"][string] | undefined,
|
|
238
|
+
minLength: number,
|
|
239
|
+
): boolean {
|
|
240
|
+
if (!slot) return false;
|
|
241
|
+
if (Array.isArray(slot.value))
|
|
242
|
+
return slot.value.filter((value) => typeof value === "string").length >= minLength;
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function selectToolBundles(
|
|
247
|
+
output: Pick<RouterOutput, "routeKind" | "workflow" | "entities">,
|
|
248
|
+
): ToolBundleName[] {
|
|
249
|
+
if (output.routeKind === "pass_through") return [];
|
|
250
|
+
if (output.routeKind === "clarification") return ["clarification"];
|
|
251
|
+
|
|
252
|
+
const bundles = new Set<ToolBundleName>();
|
|
253
|
+
const routeBundles = ROUTE_CAPABILITY_MANIFEST[output.routeKind]?.toolBundles ?? [];
|
|
254
|
+
for (const bundle of routeBundles) {
|
|
255
|
+
bundles.add(bundle);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (output.workflow) {
|
|
259
|
+
const workflow = WORKFLOW_CAPABILITY_MANIFEST[output.workflow];
|
|
260
|
+
if (workflow) {
|
|
261
|
+
for (const bundle of workflow.toolBundles) {
|
|
262
|
+
bundles.add(bundle);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const metrics = output.entities.compareMetrics ?? [];
|
|
268
|
+
const horizon = output.entities.timeHorizon ?? "";
|
|
269
|
+
if (
|
|
270
|
+
metrics.includes("macro_hedge") ||
|
|
271
|
+
metrics.includes("interest_rates") ||
|
|
272
|
+
/\b(?:macro|rate|inflation)\b/i.test(horizon)
|
|
273
|
+
) {
|
|
274
|
+
bundles.add("macro");
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (output.entities.symbols.length > 0) {
|
|
278
|
+
bundles.add("core_market");
|
|
279
|
+
}
|
|
280
|
+
if (output.entities.optionStrategy) {
|
|
281
|
+
bundles.add("options");
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return Array.from(bundles);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function activeToolsForBundles(
|
|
288
|
+
bundles: readonly ToolBundleName[],
|
|
289
|
+
availableToolNames?: readonly string[],
|
|
290
|
+
): string[] {
|
|
291
|
+
const selected = new Set<string>();
|
|
292
|
+
for (const bundle of bundles) {
|
|
293
|
+
for (const tool of TOOL_BUNDLE_TOOLS[bundle] ?? []) {
|
|
294
|
+
selected.add(tool);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (!availableToolNames) return Array.from(selected);
|
|
299
|
+
const available = new Set(availableToolNames);
|
|
300
|
+
return Array.from(selected).filter((tool) => available.has(tool));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function memoryScopesForRoute(
|
|
304
|
+
routeKind: RouterRouteKind,
|
|
305
|
+
workflow?: Exclude<WorkflowType, "unclassified">,
|
|
306
|
+
): MemoryCategory[] {
|
|
307
|
+
if (workflow) return WORKFLOW_CAPABILITY_MANIFEST[workflow]?.memoryScopes ?? [];
|
|
308
|
+
return ROUTE_CAPABILITY_MANIFEST[routeKind]?.memoryScopes ?? [];
|
|
309
|
+
}
|
|
@@ -9,7 +9,9 @@ import type { RouterLlmClient } from "./router-types.js";
|
|
|
9
9
|
* Zero tools are passed — the router operates on text alone. Temperature
|
|
10
10
|
* is pinned low for structured-output stability.
|
|
11
11
|
*/
|
|
12
|
-
export function createPiAiRouterClient(
|
|
12
|
+
export function createPiAiRouterClient(
|
|
13
|
+
model: Model<"anthropic-messages"> | Model<any>,
|
|
14
|
+
): RouterLlmClient {
|
|
13
15
|
return {
|
|
14
16
|
async complete(prompt: string): Promise<string> {
|
|
15
17
|
const response = await completeSimple(
|
|
@@ -33,9 +35,7 @@ export function createPiAiRouterClient(model: Model<"anthropic-messages"> | Mode
|
|
|
33
35
|
);
|
|
34
36
|
|
|
35
37
|
if (response.stopReason === "error" || response.stopReason === "aborted") {
|
|
36
|
-
throw new Error(
|
|
37
|
-
`router LLM call failed: ${response.errorMessage ?? response.stopReason}`,
|
|
38
|
-
);
|
|
38
|
+
throw new Error(`router LLM call failed: ${response.errorMessage ?? response.stopReason}`);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
const text = response.content
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ROUTE_CAPABILITY_MANIFEST, WORKFLOW_CAPABILITY_MANIFEST } from "./route-manifest.js";
|
|
1
2
|
import type { RouterInputContext } from "./router-types.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -11,48 +12,32 @@ import type { RouterInputContext } from "./router-types.js";
|
|
|
11
12
|
* `openspec/changes/router-context-and-observability/` for the follow-up.
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
|
-
/**
|
|
15
|
-
* List of workflows the router may emit. Keep this in sync with
|
|
16
|
-
* `WorkflowType` in `src/routing/types.ts` minus the `unclassified` sentinel.
|
|
17
|
-
*/
|
|
18
|
-
const WORKFLOW_CATALOG = [
|
|
19
|
-
{
|
|
20
|
-
name: "portfolio_builder",
|
|
21
|
-
when: "user asks to build/allocate a portfolio, invest a budget across positions",
|
|
22
|
-
required: ["budget"],
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
name: "options_screener",
|
|
26
|
-
when: "user asks for options trades / calls / puts on a specific ticker",
|
|
27
|
-
required: ["symbol"],
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: "compare_assets",
|
|
31
|
-
when: "user asks to compare two or more symbols (vs / versus / which is better)",
|
|
32
|
-
required: ["symbols (>=2)"],
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: "single_asset_analysis",
|
|
36
|
-
when: "user asks for a full analysis / deep dive / 'is X attractive' on ONE symbol",
|
|
37
|
-
required: ["symbol"],
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
name: "watchlist_or_tracking",
|
|
41
|
-
when: "user manages or asks about their saved watchlist / prediction history",
|
|
42
|
-
required: [],
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: "general_finance_qa",
|
|
46
|
-
when: "definitional / conceptual 'what is X', 'explain Y' questions",
|
|
47
|
-
required: [],
|
|
48
|
-
},
|
|
49
|
-
];
|
|
50
|
-
|
|
51
15
|
function renderCatalog(): string {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
16
|
+
const descriptions: Record<string, string> = {
|
|
17
|
+
portfolio_builder: "user asks to build/allocate a portfolio, invest a budget across positions",
|
|
18
|
+
options_screener: "user asks for options trades / calls / puts on a specific ticker",
|
|
19
|
+
compare_assets: "user asks to compare two or more symbols (vs / versus / which is better)",
|
|
20
|
+
single_asset_analysis:
|
|
21
|
+
"user asks for a full analysis / deep dive / 'is X attractive' on ONE symbol",
|
|
22
|
+
watchlist_or_tracking: "user manages or asks about their saved watchlist / prediction history",
|
|
23
|
+
general_finance_qa:
|
|
24
|
+
"definitional / conceptual questions plus broad market structure, sector, industry, monetary policy, and emerging markets research",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return Object.values(WORKFLOW_CAPABILITY_MANIFEST)
|
|
28
|
+
.map((w) => {
|
|
29
|
+
const required =
|
|
30
|
+
w.requiredSlots.length > 0 ? ` [required: ${w.requiredSlots.join(", ")}]` : "";
|
|
31
|
+
const mode = w.dispatchable ? "dispatchable workflow" : "agent-task workflow label";
|
|
32
|
+
return `- "${w.workflow}" (${mode}): ${descriptions[w.workflow]}${required}`;
|
|
33
|
+
})
|
|
34
|
+
.join("\n");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function renderRouteKinds(): string {
|
|
38
|
+
return Object.values(ROUTE_CAPABILITY_MANIFEST)
|
|
39
|
+
.map((route) => `- "${route.routeKind}" -> legacy route "${route.legacyRoute}"`)
|
|
40
|
+
.join("\n");
|
|
56
41
|
}
|
|
57
42
|
|
|
58
43
|
function renderProfile(profile: Record<string, unknown>): string {
|
|
@@ -61,13 +46,9 @@ function renderProfile(profile: Record<string, unknown>): string {
|
|
|
61
46
|
return entries.map(([k, v]) => `- ${k}: ${JSON.stringify(v)}`).join("\n");
|
|
62
47
|
}
|
|
63
48
|
|
|
64
|
-
function renderPriorTurns(
|
|
65
|
-
turns: Array<{ role: "user" | "assistant"; text: string }>,
|
|
66
|
-
): string {
|
|
49
|
+
function renderPriorTurns(turns: Array<{ role: "user" | "assistant"; text: string }>): string {
|
|
67
50
|
if (turns.length === 0) return "(none)";
|
|
68
|
-
return turns
|
|
69
|
-
.map((t) => `[${t.role}] ${t.text.replace(/\n+/g, " ").slice(0, 400)}`)
|
|
70
|
-
.join("\n");
|
|
51
|
+
return turns.map((t) => `[${t.role}] ${t.text.replace(/\n+/g, " ").slice(0, 400)}`).join("\n");
|
|
71
52
|
}
|
|
72
53
|
|
|
73
54
|
function renderRecentRuns(
|
|
@@ -90,6 +71,7 @@ function renderRecentRuns(
|
|
|
90
71
|
const SCHEMA_SPEC = `You MUST respond with a SINGLE JSON object and nothing else (no markdown fences, no prose outside the JSON). The object MUST conform to this TypeScript interface exactly:
|
|
91
72
|
|
|
92
73
|
interface RouterOutput {
|
|
74
|
+
routeKind: "workflow_dispatch" | "agent_task" | "clarification" | "pass_through";
|
|
93
75
|
route: "workflow" | "fallback";
|
|
94
76
|
workflow?: "portfolio_builder" | "options_screener" | "compare_assets" | "single_asset_analysis" | "watchlist_or_tracking" | "general_finance_qa";
|
|
95
77
|
entities: {
|
|
@@ -100,10 +82,16 @@ interface RouterOutput {
|
|
|
100
82
|
riskProfile?: string; // "conservative" | "balanced" | "aggressive"
|
|
101
83
|
direction?: "bullish" | "bearish";
|
|
102
84
|
dteHint?: string;
|
|
85
|
+
optionStrategy?: "covered_call" | "protective_put"; // set when user explicitly asks for a known option strategy
|
|
86
|
+
heldSymbol?: string; // for covered calls/protective puts: ticker the user owns/holds
|
|
87
|
+
catalystSymbols?: string[]; // tickers mentioned as event/catalyst context, not the option-chain underlying
|
|
88
|
+
costBasis?: number; // per-share basis when user says "cost basis is $X"
|
|
89
|
+
shareQuantity?: number; // number of shares owned when stated, e.g. "200 shares"
|
|
90
|
+
compareMetrics?: string[]; // optional compare focus tags, e.g. "sentiment", "macro_hedge"
|
|
103
91
|
};
|
|
104
92
|
slots: Record<string, {
|
|
105
93
|
value: unknown;
|
|
106
|
-
source: "user" | "preference" | "default"
|
|
94
|
+
source: "user" | "preference" | "default" | "prior_context" | "memory";
|
|
107
95
|
confidence: "high" | "medium" | "low";
|
|
108
96
|
}>;
|
|
109
97
|
preference_updates: Array<{
|
|
@@ -113,18 +101,27 @@ interface RouterOutput {
|
|
|
113
101
|
source: "inferred";
|
|
114
102
|
}>;
|
|
115
103
|
missing_required: string[]; // required slot names the turn/profile/defaults did not fill
|
|
104
|
+
tool_bundles: Array<"core_market" | "options" | "macro" | "sentiment" | "sec" | "clarification">;
|
|
105
|
+
diagnostics: Array<{ code: string; message: string }>;
|
|
116
106
|
reasoning: string; // one or two short sentences; used for debugging only
|
|
117
107
|
}`;
|
|
118
108
|
|
|
119
109
|
const ROUTING_RULES = `Routing rules:
|
|
120
|
-
- Choose
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
110
|
+
- Choose routeKind = "workflow_dispatch" ONLY when the turn clearly matches a dispatchable workflow (portfolio_builder, options_screener, or compare_assets) AND required slots are filled from the turn, trusted prior context, or profile snapshot.
|
|
111
|
+
- For single_asset_analysis, watchlist_or_tracking, and general_finance_qa, set routeKind = "agent_task" even when you set the workflow label. These are workflow labels for prompt/tool policy, not structured workflow dispatch.
|
|
112
|
+
- Choose routeKind = "agent_task" for in-scope finance work that should be answered by the main agent, including simple data fetches like "AAPL quote" and open-ended questions like "entry levels on ASTS for 6 months".
|
|
113
|
+
- Choose routeKind = "clarification" when required slots are missing (e.g. options workflow needs a symbol, portfolio needs a budget). List specific slot names in missing_required. The main agent will use ask_user to collect them.
|
|
114
|
+
- Choose routeKind = "pass_through" when the request is outside OpenCandle's finance task surface.
|
|
115
|
+
- Set legacy route = "workflow" only for routeKind = "workflow_dispatch"; otherwise set legacy route = "fallback".
|
|
116
|
+
- DO NOT invent a "direct_tool" route. Tool execution belongs to the main agent.
|
|
117
|
+
- For covered call prompts, distinguish the owned underlying from catalyst tickers. Put the owned symbol first in symbols, set heldSymbol to the owned symbol, put event/context tickers in catalystSymbols, set workflow="options_screener", and preserve costBasis if stated.
|
|
118
|
+
- For protective put prompts, treat the owned/held ticker as the option-chain underlying, set optionStrategy="protective_put", direction="bearish", and preserve shareQuantity if stated. This is a hedge on an existing long share position, not a bullish call screen.
|
|
124
119
|
- Source attribution rules (per-slot source field):
|
|
125
120
|
- source = "user": the value came from THIS turn's text.
|
|
126
121
|
- source = "preference": the value came from profileSnapshot (not this turn).
|
|
127
122
|
- source = "default": a sensible default was applied (workflow fallback).
|
|
123
|
+
- source = "prior_context": the value came from prior conversation turns.
|
|
124
|
+
- source = "memory": the value came from retrieved non-profile memory.
|
|
128
125
|
- Preference updates:
|
|
129
126
|
- Emit preference_updates ONLY for stable user-dispositions stated (or very strongly implied) in the current turn. E.g. "I'm aggressive" → risk_profile=aggressive, high.
|
|
130
127
|
- Do NOT emit preference_updates that merely echo profileSnapshot.
|
|
@@ -134,6 +131,9 @@ const ROUTING_RULES = `Routing rules:
|
|
|
134
131
|
export function buildRouterPrompt(input: RouterInputContext): string {
|
|
135
132
|
return `You are OpenCandle's routing agent. Your job is to classify the user's turn into one of the known workflows (or fallback), extract entities + per-slot provenance, and surface any stable preferences the user expressed. Your output feeds the main analyst agent — it does NOT go to the user.
|
|
136
133
|
|
|
134
|
+
ROUTE KINDS:
|
|
135
|
+
${renderRouteKinds()}
|
|
136
|
+
|
|
137
137
|
WORKFLOW CATALOG:
|
|
138
138
|
${renderCatalog()}
|
|
139
139
|
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { ExtractedEntities, SlotSource, WorkflowType } from "./types.js";
|
|
2
2
|
|
|
3
3
|
export type RouterRoute = "workflow" | "fallback";
|
|
4
|
+
export type RouterRouteKind = "workflow_dispatch" | "agent_task" | "clarification" | "pass_through";
|
|
5
|
+
|
|
6
|
+
export type ToolBundleName =
|
|
7
|
+
| "core_market"
|
|
8
|
+
| "options"
|
|
9
|
+
| "macro"
|
|
10
|
+
| "sentiment"
|
|
11
|
+
| "sec"
|
|
12
|
+
| "clarification";
|
|
4
13
|
|
|
5
14
|
export type RouterConfidence = "high" | "medium" | "low";
|
|
6
15
|
|
|
@@ -17,6 +26,12 @@ export interface RouterPreferenceUpdate {
|
|
|
17
26
|
source: "inferred";
|
|
18
27
|
}
|
|
19
28
|
|
|
29
|
+
export interface RouterDiagnostic {
|
|
30
|
+
code: string;
|
|
31
|
+
message: string;
|
|
32
|
+
details?: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
|
|
20
35
|
/**
|
|
21
36
|
* Structured output from the LLM router. Mirrors existing types
|
|
22
37
|
* (`ClassificationResult`, `ExtractedEntities`, `SlotSource`) so downstream
|
|
@@ -26,12 +41,15 @@ export interface RouterPreferenceUpdate {
|
|
|
26
41
|
* routes, `workflow_type` at the storage layer is the sentinel `"fallback"`.
|
|
27
42
|
*/
|
|
28
43
|
export interface RouterOutput {
|
|
44
|
+
routeKind: RouterRouteKind;
|
|
29
45
|
route: RouterRoute;
|
|
30
46
|
workflow?: Exclude<WorkflowType, "unclassified">;
|
|
31
47
|
entities: ExtractedEntities;
|
|
32
48
|
slots: Record<string, RouterSlot>;
|
|
33
49
|
preference_updates: RouterPreferenceUpdate[];
|
|
34
50
|
missing_required: string[];
|
|
51
|
+
tool_bundles: ToolBundleName[];
|
|
52
|
+
diagnostics: RouterDiagnostic[];
|
|
35
53
|
reasoning: string;
|
|
36
54
|
}
|
|
37
55
|
|