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
|
@@ -3,60 +3,81 @@ import { initDefaultDatabase } from "./sqlite.js";
|
|
|
3
3
|
export type ToolDefaults = Record<string, unknown>;
|
|
4
4
|
type SqliteDb = ReturnType<typeof initDefaultDatabase>;
|
|
5
5
|
|
|
6
|
-
export function getDefaults(toolName: string, db
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
export function getDefaults(toolName: string, db?: SqliteDb): ToolDefaults {
|
|
7
|
+
const ownedDb = db == null;
|
|
8
|
+
const connection = db ?? initDefaultDatabase();
|
|
9
|
+
try {
|
|
10
|
+
const rows = connection
|
|
11
|
+
.prepare(
|
|
12
|
+
`SELECT param_path, value_json FROM tool_defaults WHERE tool_name = ? ORDER BY param_path`,
|
|
13
|
+
)
|
|
14
|
+
.all(toolName) as Array<{ param_path: string; value_json: string }>;
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const defaults: ToolDefaults = {};
|
|
17
|
+
for (const row of rows) {
|
|
18
|
+
setPath(defaults, row.param_path, parseStoredValue(row.value_json));
|
|
19
|
+
}
|
|
20
|
+
return defaults;
|
|
21
|
+
} finally {
|
|
22
|
+
if (ownedDb) connection.close();
|
|
16
23
|
}
|
|
17
|
-
return defaults;
|
|
18
24
|
}
|
|
19
25
|
|
|
20
|
-
export function getAllDefaults(db
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
export function getAllDefaults(db?: SqliteDb): Map<string, ToolDefaults> {
|
|
27
|
+
const ownedDb = db == null;
|
|
28
|
+
const connection = db ?? initDefaultDatabase();
|
|
29
|
+
try {
|
|
30
|
+
const rows = connection
|
|
31
|
+
.prepare(
|
|
32
|
+
`SELECT tool_name, param_path, value_json FROM tool_defaults ORDER BY tool_name, param_path`,
|
|
33
|
+
)
|
|
34
|
+
.all() as Array<{ tool_name: string; param_path: string; value_json: string }>;
|
|
26
35
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
const groups = new Map<string, ToolDefaults>();
|
|
37
|
+
for (const row of rows) {
|
|
38
|
+
const defaults = groups.get(row.tool_name) ?? {};
|
|
39
|
+
setPath(defaults, row.param_path, parseStoredValue(row.value_json));
|
|
40
|
+
groups.set(row.tool_name, defaults);
|
|
41
|
+
}
|
|
42
|
+
return groups;
|
|
43
|
+
} finally {
|
|
44
|
+
if (ownedDb) connection.close();
|
|
32
45
|
}
|
|
33
|
-
return groups;
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
export function setDefault(
|
|
37
49
|
toolName: string,
|
|
38
50
|
paramPath: string,
|
|
39
51
|
value: unknown,
|
|
40
|
-
db
|
|
52
|
+
db?: SqliteDb,
|
|
41
53
|
): void {
|
|
42
|
-
db
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
const ownedDb = db == null;
|
|
55
|
+
const connection = db ?? initDefaultDatabase();
|
|
56
|
+
try {
|
|
57
|
+
connection
|
|
58
|
+
.prepare(
|
|
59
|
+
`INSERT INTO tool_defaults (tool_name, param_path, value_json, set_at)
|
|
60
|
+
VALUES (?, ?, ?, ?)
|
|
61
|
+
ON CONFLICT(tool_name, param_path) DO UPDATE SET
|
|
62
|
+
value_json = excluded.value_json,
|
|
63
|
+
set_at = excluded.set_at`,
|
|
64
|
+
)
|
|
65
|
+
.run(toolName, paramPath, JSON.stringify(value), new Date().toISOString());
|
|
66
|
+
} finally {
|
|
67
|
+
if (ownedDb) connection.close();
|
|
68
|
+
}
|
|
49
69
|
}
|
|
50
70
|
|
|
51
|
-
export function clearDefault(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
71
|
+
export function clearDefault(toolName: string, paramPath: string, db?: SqliteDb): void {
|
|
72
|
+
const ownedDb = db == null;
|
|
73
|
+
const connection = db ?? initDefaultDatabase();
|
|
74
|
+
try {
|
|
75
|
+
connection
|
|
76
|
+
.prepare(`DELETE FROM tool_defaults WHERE tool_name = ? AND param_path = ?`)
|
|
77
|
+
.run(toolName, paramPath);
|
|
78
|
+
} finally {
|
|
79
|
+
if (ownedDb) connection.close();
|
|
80
|
+
}
|
|
60
81
|
}
|
|
61
82
|
|
|
62
83
|
function parseStoredValue(valueJson: string): unknown {
|
package/src/memory/types.ts
CHANGED
|
@@ -17,10 +17,10 @@ export interface MemoryEntry {
|
|
|
17
17
|
|
|
18
18
|
/** Staleness thresholds in milliseconds per category. */
|
|
19
19
|
export const STALENESS_THRESHOLDS: Record<MemoryCategory, number> = {
|
|
20
|
-
investor_profile: 90 * 24 * 60 * 60 * 1000,
|
|
20
|
+
investor_profile: 90 * 24 * 60 * 60 * 1000, // 90 days
|
|
21
21
|
interaction_feedback: 14 * 24 * 60 * 60 * 1000, // 14 days
|
|
22
|
-
workflow_history: 7 * 24 * 60 * 60 * 1000,
|
|
23
|
-
references: 30 * 24 * 60 * 60 * 1000,
|
|
22
|
+
workflow_history: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
23
|
+
references: 30 * 24 * 60 * 60 * 1000, // 30 days
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
/** Map preference keys to memory categories. */
|
package/src/monitor.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./infra/node-version.js";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { loadEnv } from "./config.js";
|
|
5
|
+
import { runLocalAutomationHeartbeat } from "./market-state/local-automation-service.js";
|
|
6
|
+
import { MarketStateService } from "./market-state/service.js";
|
|
7
|
+
import { initDefaultDatabase } from "./memory/sqlite.js";
|
|
8
|
+
|
|
9
|
+
const DEFAULT_MONITOR_INTERVAL_MS = 60_000;
|
|
10
|
+
const MIN_MONITOR_INTERVAL_MS = 5_000;
|
|
11
|
+
const MONITOR_OWNER_ID = `monitor:${process.pid}`;
|
|
12
|
+
|
|
13
|
+
interface MonitorOptions {
|
|
14
|
+
once: boolean;
|
|
15
|
+
intervalMs: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function parseMonitorOptions(argv = process.argv.slice(2)): MonitorOptions {
|
|
19
|
+
const parsed = parseArgs({
|
|
20
|
+
args: argv,
|
|
21
|
+
options: {
|
|
22
|
+
once: { type: "boolean", default: false },
|
|
23
|
+
"interval-ms": { type: "string" },
|
|
24
|
+
},
|
|
25
|
+
strict: false,
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
once: parsed.values.once === true,
|
|
29
|
+
intervalMs: normalizeMonitorIntervalMs(parsed.values["interval-ms"]),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function normalizeMonitorIntervalMs(raw: string | boolean | undefined): number {
|
|
34
|
+
if (typeof raw !== "string" || raw.trim() === "") return DEFAULT_MONITOR_INTERVAL_MS;
|
|
35
|
+
const parsed = Number(raw);
|
|
36
|
+
if (!Number.isFinite(parsed) || parsed < MIN_MONITOR_INTERVAL_MS)
|
|
37
|
+
return DEFAULT_MONITOR_INTERVAL_MS;
|
|
38
|
+
return Math.floor(parsed);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function runMonitorHeartbeat(
|
|
42
|
+
intervalMs: number,
|
|
43
|
+
releaseLeaseOnComplete = false,
|
|
44
|
+
): Promise<void> {
|
|
45
|
+
const db = initDefaultDatabase();
|
|
46
|
+
const now = new Date().toISOString();
|
|
47
|
+
try {
|
|
48
|
+
const result = await runLocalAutomationHeartbeat(db, {
|
|
49
|
+
ownerId: MONITOR_OWNER_ID,
|
|
50
|
+
ownerKind: "monitor",
|
|
51
|
+
now,
|
|
52
|
+
ttlSeconds: Math.max(90, Math.ceil((intervalMs * 2) / 1000)),
|
|
53
|
+
checkAlerts: true,
|
|
54
|
+
checkReports: true,
|
|
55
|
+
releaseLeaseOnComplete,
|
|
56
|
+
});
|
|
57
|
+
if (!result.lease.acquired) {
|
|
58
|
+
console.log(
|
|
59
|
+
`OpenCandle monitor standby: runner owned by ${result.lease.ownerId} until ${result.lease.expiresAt}`,
|
|
60
|
+
);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const alertSummary = result.alertCheck
|
|
64
|
+
? `${result.alertCheck.checked} alert(s), ${result.alertCheck.triggered} triggered, ${result.alertCheck.unavailable} unavailable`
|
|
65
|
+
: "no due alerts";
|
|
66
|
+
const reportSummary = result.reportRuns.length
|
|
67
|
+
? `${result.reportRuns.length} report run(s)`
|
|
68
|
+
: "no due reports";
|
|
69
|
+
console.log(`OpenCandle monitor heartbeat ${now}: ${alertSummary}; ${reportSummary}.`);
|
|
70
|
+
} finally {
|
|
71
|
+
db.close();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function main(): Promise<void> {
|
|
76
|
+
loadEnv();
|
|
77
|
+
const options = parseMonitorOptions();
|
|
78
|
+
let inFlight = false;
|
|
79
|
+
const runOnce = async (): Promise<void> => {
|
|
80
|
+
if (inFlight) {
|
|
81
|
+
console.log("OpenCandle monitor heartbeat skipped: previous run is still active.");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
inFlight = true;
|
|
85
|
+
try {
|
|
86
|
+
await runMonitorHeartbeat(options.intervalMs, options.once);
|
|
87
|
+
} finally {
|
|
88
|
+
inFlight = false;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
await runOnce();
|
|
93
|
+
if (options.once) return;
|
|
94
|
+
|
|
95
|
+
console.log(
|
|
96
|
+
`OpenCandle monitor running locally every ${options.intervalMs}ms. Keep this process open for local alerts and reports.`,
|
|
97
|
+
);
|
|
98
|
+
const timer = setInterval(() => {
|
|
99
|
+
void runOnce().catch((error) => {
|
|
100
|
+
console.error(
|
|
101
|
+
`OpenCandle monitor heartbeat failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
}, options.intervalMs);
|
|
105
|
+
|
|
106
|
+
const stop = () => {
|
|
107
|
+
clearInterval(timer);
|
|
108
|
+
const db = initDefaultDatabase();
|
|
109
|
+
try {
|
|
110
|
+
new MarketStateService(db).releaseAutomationRunnerLease(MONITOR_OWNER_ID);
|
|
111
|
+
} finally {
|
|
112
|
+
db.close();
|
|
113
|
+
}
|
|
114
|
+
console.log("OpenCandle monitor stopped.");
|
|
115
|
+
process.exit(0);
|
|
116
|
+
};
|
|
117
|
+
process.once("SIGINT", stop);
|
|
118
|
+
process.once("SIGTERM", stop);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
await main();
|
|
@@ -18,23 +18,15 @@
|
|
|
18
18
|
// call will surface any lingering issue via the credential-required tag.
|
|
19
19
|
|
|
20
20
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
21
|
-
import { openInBrowser } from "../infra/open-url.js";
|
|
22
21
|
import {
|
|
23
|
-
loadFileConfig,
|
|
24
|
-
saveFileConfig,
|
|
25
22
|
loadConfig,
|
|
23
|
+
loadFileConfig,
|
|
26
24
|
type OpenCandleFileConfig,
|
|
25
|
+
saveFileConfig,
|
|
27
26
|
} from "../config.js";
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
type ProviderId,
|
|
32
|
-
} from "./providers.js";
|
|
33
|
-
import {
|
|
34
|
-
loadOnboardingState,
|
|
35
|
-
markProviderCompleted,
|
|
36
|
-
saveOnboardingState,
|
|
37
|
-
} from "./state.js";
|
|
27
|
+
import { openInBrowser } from "../infra/open-url.js";
|
|
28
|
+
import { getCredentialSource, getProvider, type ProviderId } from "./providers.js";
|
|
29
|
+
import { loadOnboardingState, markProviderCompleted, saveOnboardingState } from "./state.js";
|
|
38
30
|
import { validateCredential } from "./validation.js";
|
|
39
31
|
|
|
40
32
|
export type ConnectResult =
|
|
@@ -55,9 +47,7 @@ function writeNested(
|
|
|
55
47
|
next[head] = value;
|
|
56
48
|
} else {
|
|
57
49
|
const child =
|
|
58
|
-
next[head] && typeof next[head] === "object"
|
|
59
|
-
? (next[head] as Record<string, unknown>)
|
|
60
|
-
: {};
|
|
50
|
+
next[head] && typeof next[head] === "object" ? (next[head] as Record<string, unknown>) : {};
|
|
61
51
|
next[head] = writeNested(child, rest, value);
|
|
62
52
|
}
|
|
63
53
|
return next;
|
|
@@ -74,17 +64,10 @@ function writeNested(
|
|
|
74
64
|
* provider-setup form. Validation is the caller's responsibility — both
|
|
75
65
|
* call sites run `validateCredential` before invoking this helper.
|
|
76
66
|
*/
|
|
77
|
-
export function persistProviderCredential(
|
|
78
|
-
providerId: ProviderId,
|
|
79
|
-
key: string,
|
|
80
|
-
): void {
|
|
67
|
+
export function persistProviderCredential(providerId: ProviderId, key: string): void {
|
|
81
68
|
const descriptor = getProvider(providerId);
|
|
82
69
|
const existing = loadFileConfig() as unknown as Record<string, unknown>;
|
|
83
|
-
const updated = writeNested(
|
|
84
|
-
existing,
|
|
85
|
-
descriptor.configPath,
|
|
86
|
-
key,
|
|
87
|
-
) as OpenCandleFileConfig;
|
|
70
|
+
const updated = writeNested(existing, descriptor.configPath, key) as OpenCandleFileConfig;
|
|
88
71
|
saveFileConfig(updated);
|
|
89
72
|
loadConfig();
|
|
90
73
|
const state = loadOnboardingState();
|
|
@@ -121,10 +104,7 @@ export async function runProviderConnect(
|
|
|
121
104
|
// the browser can't be opened, the user can still paste a key they
|
|
122
105
|
// already have, so we continue rather than bailing.
|
|
123
106
|
await openInBrowser(descriptor.signupUrl).catch(() => {});
|
|
124
|
-
ctx.ui.notify(
|
|
125
|
-
`Opening ${descriptor.displayName} signup in your browser...`,
|
|
126
|
-
"info",
|
|
127
|
-
);
|
|
107
|
+
ctx.ui.notify(`Opening ${descriptor.displayName} signup in your browser...`, "info");
|
|
128
108
|
|
|
129
109
|
// Prompt for the key. Uses the provider's instructionsHint as the
|
|
130
110
|
// placeholder text to remind the user what they're pasting.
|
|
@@ -175,10 +155,7 @@ export async function runProviderConnect(
|
|
|
175
155
|
|
|
176
156
|
persistProviderCredential(providerId, trimmed);
|
|
177
157
|
|
|
178
|
-
ctx.ui.notify(
|
|
179
|
-
`${descriptor.displayName} connected. Your key has been saved.`,
|
|
180
|
-
"info",
|
|
181
|
-
);
|
|
158
|
+
ctx.ui.notify(`${descriptor.displayName} connected. Your key has been saved.`, "info");
|
|
182
159
|
|
|
183
160
|
return { status: "connected" };
|
|
184
161
|
}
|
|
@@ -54,10 +54,7 @@ function buildRemediation(providerId: ProviderId): string {
|
|
|
54
54
|
return `run /connect ${alias} to unlock`;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function skip(
|
|
58
|
-
providerId: ProviderId,
|
|
59
|
-
silenced: boolean,
|
|
60
|
-
): InterceptAction {
|
|
57
|
+
function skip(providerId: ProviderId, silenced: boolean): InterceptAction {
|
|
61
58
|
return {
|
|
62
59
|
action: "skip",
|
|
63
60
|
provider: providerId,
|
|
@@ -74,17 +71,8 @@ function skip(
|
|
|
74
71
|
*
|
|
75
72
|
* No side effects. No Pi imports. Trivially unit-testable.
|
|
76
73
|
*/
|
|
77
|
-
export function resolveCredentialRequired(
|
|
78
|
-
|
|
79
|
-
): InterceptAction {
|
|
80
|
-
const {
|
|
81
|
-
provider,
|
|
82
|
-
reason,
|
|
83
|
-
state,
|
|
84
|
-
sessionPromptedSet,
|
|
85
|
-
hardPromptFiredInWorkflow,
|
|
86
|
-
now,
|
|
87
|
-
} = input;
|
|
74
|
+
export function resolveCredentialRequired(input: InterceptInput): InterceptAction {
|
|
75
|
+
const { provider, reason, state, sessionPromptedSet, hardPromptFiredInWorkflow, now } = input;
|
|
88
76
|
|
|
89
77
|
const descriptor = getProvider(provider);
|
|
90
78
|
const entry = state.providers[provider];
|
|
@@ -58,9 +58,7 @@ export function createDegradationAccumulator(): DegradationAccumulator {
|
|
|
58
58
|
const silenced = entry?.status === "never_ask";
|
|
59
59
|
const alias = descriptor.aliases[0] ?? descriptor.id;
|
|
60
60
|
const baseRemediation = `run /connect ${alias} to unlock`;
|
|
61
|
-
const remediation = silenced
|
|
62
|
-
? `${baseRemediation} (silenced)`
|
|
63
|
-
: baseRemediation;
|
|
61
|
+
const remediation = silenced ? `${baseRemediation} (silenced)` : baseRemediation;
|
|
64
62
|
lines.push(
|
|
65
63
|
buildSkippedTag({
|
|
66
64
|
provider,
|
|
@@ -10,18 +10,9 @@
|
|
|
10
10
|
|
|
11
11
|
import { getConfig, loadFileConfig } from "../config.js";
|
|
12
12
|
|
|
13
|
-
export type ProviderId =
|
|
14
|
-
| "alpha_vantage"
|
|
15
|
-
| "fred"
|
|
16
|
-
| "finnhub"
|
|
17
|
-
| "brave"
|
|
18
|
-
| "exa";
|
|
13
|
+
export type ProviderId = "alpha_vantage" | "fred" | "finnhub" | "brave" | "exa";
|
|
19
14
|
|
|
20
|
-
export type ProviderCategory =
|
|
21
|
-
| "fundamentals"
|
|
22
|
-
| "macro"
|
|
23
|
-
| "news"
|
|
24
|
-
| "web_search";
|
|
15
|
+
export type ProviderCategory = "fundamentals" | "macro" | "news" | "web_search";
|
|
25
16
|
|
|
26
17
|
export type ProviderTier = "hard" | "soft";
|
|
27
18
|
|
|
@@ -87,12 +78,7 @@ export const PROVIDERS = [
|
|
|
87
78
|
freeTier: true,
|
|
88
79
|
envVar: "FRED_API_KEY",
|
|
89
80
|
configPath: ["providers", "fred", "apiKey"],
|
|
90
|
-
unlocks: [
|
|
91
|
-
"interest rates",
|
|
92
|
-
"inflation data",
|
|
93
|
-
"yield curve",
|
|
94
|
-
"economic indicators",
|
|
95
|
-
],
|
|
81
|
+
unlocks: ["interest rates", "inflation data", "yield curve", "economic indicators"],
|
|
96
82
|
fallbackDescription: null,
|
|
97
83
|
snoozeDurationDays: 7,
|
|
98
84
|
instructionsHint: "Free, about 30 seconds, requires a St. Louis Fed account",
|
|
@@ -107,10 +93,7 @@ export const PROVIDERS = [
|
|
|
107
93
|
freeTier: true,
|
|
108
94
|
envVar: "FINNHUB_API_KEY",
|
|
109
95
|
configPath: ["providers", "finnhub", "apiKey"],
|
|
110
|
-
unlocks: [
|
|
111
|
-
"ticker-tagged company news",
|
|
112
|
-
"sentiment enrichment with a dedicated news source",
|
|
113
|
-
],
|
|
96
|
+
unlocks: ["ticker-tagged company news", "sentiment enrichment with a dedicated news source"],
|
|
114
97
|
// Finnhub is a soft enrichment source — sentiment-summary continues to work
|
|
115
98
|
// with Twitter/Reddit/web search when Finnhub is missing. The fallback is
|
|
116
99
|
// "the other sentiment sources still run".
|
|
@@ -194,15 +177,11 @@ export function getProvider(id: ProviderId): ProviderDescriptor {
|
|
|
194
177
|
return found;
|
|
195
178
|
}
|
|
196
179
|
|
|
197
|
-
export function getProvidersByCategory(
|
|
198
|
-
category: ProviderCategory,
|
|
199
|
-
): readonly ProviderDescriptor[] {
|
|
180
|
+
export function getProvidersByCategory(category: ProviderCategory): readonly ProviderDescriptor[] {
|
|
200
181
|
return PROVIDERS.filter((p) => p.category === category);
|
|
201
182
|
}
|
|
202
183
|
|
|
203
|
-
export function getProvidersByTier(
|
|
204
|
-
tier: ProviderTier,
|
|
205
|
-
): readonly ProviderDescriptor[] {
|
|
184
|
+
export function getProvidersByTier(tier: ProviderTier): readonly ProviderDescriptor[] {
|
|
206
185
|
return PROVIDERS.filter((p) => p.tier === tier);
|
|
207
186
|
}
|
|
208
187
|
|
|
@@ -244,9 +223,7 @@ export function hasCredential(id: ProviderId): boolean {
|
|
|
244
223
|
return typeof value === "string" && value.length > 0;
|
|
245
224
|
}
|
|
246
225
|
|
|
247
|
-
export function getCredentialSource(
|
|
248
|
-
id: ProviderId,
|
|
249
|
-
): "env" | "file" | "absent" {
|
|
226
|
+
export function getCredentialSource(id: ProviderId): "env" | "file" | "absent" {
|
|
250
227
|
return getCredential(id).source;
|
|
251
228
|
}
|
|
252
229
|
|
|
@@ -271,10 +248,7 @@ export function getCredential(
|
|
|
271
248
|
|
|
272
249
|
export function resolveProviderFromArgument(
|
|
273
250
|
arg: string,
|
|
274
|
-
):
|
|
275
|
-
| ProviderDescriptor
|
|
276
|
-
| readonly ProviderDescriptor[]
|
|
277
|
-
| undefined {
|
|
251
|
+
): ProviderDescriptor | readonly ProviderDescriptor[] | undefined {
|
|
278
252
|
const needle = arg.trim().toLowerCase();
|
|
279
253
|
if (!needle) return undefined;
|
|
280
254
|
|
|
@@ -291,12 +265,7 @@ export function resolveProviderFromArgument(
|
|
|
291
265
|
// 3. Category match: if the needle matches a category name, return the
|
|
292
266
|
// providers in that category. One match → single descriptor. Multiple
|
|
293
267
|
// matches → array (triggers the sub-picker in the /connect handler).
|
|
294
|
-
const categories: readonly ProviderCategory[] = [
|
|
295
|
-
"fundamentals",
|
|
296
|
-
"macro",
|
|
297
|
-
"news",
|
|
298
|
-
"web_search",
|
|
299
|
-
];
|
|
268
|
+
const categories: readonly ProviderCategory[] = ["fundamentals", "macro", "news", "web_search"];
|
|
300
269
|
const normalizedCategory = needle.replace("-", "_");
|
|
301
270
|
if ((categories as readonly string[]).includes(normalizedCategory)) {
|
|
302
271
|
const group = getProvidersByCategory(normalizedCategory as ProviderCategory);
|
package/src/onboarding/state.ts
CHANGED
|
@@ -53,9 +53,7 @@ function parseEntry(raw: unknown): ProviderOnboardingEntry | undefined {
|
|
|
53
53
|
return { status: "never_ask", lastPromptAt };
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
function parseProvidersMap(
|
|
57
|
-
raw: unknown,
|
|
58
|
-
): Partial<Record<ProviderId, ProviderOnboardingEntry>> {
|
|
56
|
+
function parseProvidersMap(raw: unknown): Partial<Record<ProviderId, ProviderOnboardingEntry>> {
|
|
59
57
|
if (!raw || typeof raw !== "object") return {};
|
|
60
58
|
const result: Partial<Record<ProviderId, ProviderOnboardingEntry>> = {};
|
|
61
59
|
for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {
|
|
@@ -96,10 +94,7 @@ export function loadOnboardingState(path = getOnboardingPath()): OnboardingState
|
|
|
96
94
|
return { version, welcomeShownAt, providers };
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
export function saveOnboardingState(
|
|
100
|
-
state: OnboardingState,
|
|
101
|
-
path = getOnboardingPath(),
|
|
102
|
-
): void {
|
|
97
|
+
export function saveOnboardingState(state: OnboardingState, path = getOnboardingPath()): void {
|
|
103
98
|
ensureParentDir(path);
|
|
104
99
|
// Strip undefined fields for cleaner on-disk output.
|
|
105
100
|
const serializable: Record<string, unknown> = {
|
|
@@ -120,10 +115,7 @@ function nowIso(): string {
|
|
|
120
115
|
return new Date().toISOString();
|
|
121
116
|
}
|
|
122
117
|
|
|
123
|
-
export function markProviderCompleted(
|
|
124
|
-
state: OnboardingState,
|
|
125
|
-
id: ProviderId,
|
|
126
|
-
): OnboardingState {
|
|
118
|
+
export function markProviderCompleted(state: OnboardingState, id: ProviderId): OnboardingState {
|
|
127
119
|
return {
|
|
128
120
|
...state,
|
|
129
121
|
providers: {
|
|
@@ -153,10 +145,7 @@ export function markProviderSnoozed(
|
|
|
153
145
|
};
|
|
154
146
|
}
|
|
155
147
|
|
|
156
|
-
export function markProviderNeverAsk(
|
|
157
|
-
state: OnboardingState,
|
|
158
|
-
id: ProviderId,
|
|
159
|
-
): OnboardingState {
|
|
148
|
+
export function markProviderNeverAsk(state: OnboardingState, id: ProviderId): OnboardingState {
|
|
160
149
|
return {
|
|
161
150
|
...state,
|
|
162
151
|
providers: {
|
|
@@ -14,10 +14,7 @@
|
|
|
14
14
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
15
15
|
import { ProviderCredentialError } from "../providers/provider-credential-error.js";
|
|
16
16
|
import { getProvider, hasCredential, type ProviderId } from "./providers.js";
|
|
17
|
-
import {
|
|
18
|
-
buildCredentialRequiredTag,
|
|
19
|
-
type CredentialRequiredReason,
|
|
20
|
-
} from "./tool-tags.js";
|
|
17
|
+
import { buildCredentialRequiredTag, type CredentialRequiredReason } from "./tool-tags.js";
|
|
21
18
|
|
|
22
19
|
// Metadata carried on `details` for UI / test assertion. This is NOT the
|
|
23
20
|
// LLM-facing contract — that lives in `content` as the tagged line. Pi
|
|
@@ -100,11 +97,7 @@ export async function withCredentialCheck<T>(
|
|
|
100
97
|
return await fn();
|
|
101
98
|
} catch (error) {
|
|
102
99
|
if (error instanceof ProviderCredentialError) {
|
|
103
|
-
return buildCredentialRequiredResult(
|
|
104
|
-
error.provider,
|
|
105
|
-
error.reason,
|
|
106
|
-
error.httpStatus,
|
|
107
|
-
);
|
|
100
|
+
return buildCredentialRequiredResult(error.provider, error.reason, error.httpStatus);
|
|
108
101
|
}
|
|
109
102
|
throw error;
|
|
110
103
|
}
|
|
@@ -81,12 +81,12 @@ export function buildCredentialRequiredTag(fields: CredentialRequiredTagFields):
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
export function buildSoftDegradedTag(fields: SoftDegradedTagFields): string {
|
|
84
|
-
return [
|
|
84
|
+
return `${[
|
|
85
85
|
"[OPENCANDLE_SOFT_DEGRADED",
|
|
86
86
|
formatField("provider", fields.provider),
|
|
87
87
|
formatField("fallback", fields.fallback),
|
|
88
88
|
`remediation=${quote(fields.remediation)}`,
|
|
89
|
-
].join(" ")
|
|
89
|
+
].join(" ")}]`;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
export function buildSkippedTag(fields: SkippedTagFields): string {
|
|
@@ -117,8 +117,9 @@ function parseFields(raw: string): Record<string, string> {
|
|
|
117
117
|
// Split on `key=value` pairs, respecting quoted values.
|
|
118
118
|
const fields: Record<string, string> = {};
|
|
119
119
|
const pattern = /(\w+)=("((?:[^"\\]|\\.)*)"|([^\s\]]+))/g;
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
while (true) {
|
|
121
|
+
const match = pattern.exec(raw);
|
|
122
|
+
if (!match) break;
|
|
122
123
|
const key = match[1];
|
|
123
124
|
const value = match[3] !== undefined ? match[3].replace(/\\"/g, '"') : match[4];
|
|
124
125
|
fields[key] = value;
|
|
@@ -147,8 +148,7 @@ export function parseToolTag(text: string): ParsedTag | undefined {
|
|
|
147
148
|
.split(",")
|
|
148
149
|
.map((s) => s.trim())
|
|
149
150
|
.filter((s) => s.length > 0);
|
|
150
|
-
const fallback =
|
|
151
|
-
fallbackRaw === undefined || fallbackRaw === "none" ? null : fallbackRaw;
|
|
151
|
+
const fallback = fallbackRaw === undefined || fallbackRaw === "none" ? null : fallbackRaw;
|
|
152
152
|
const parsed: ParsedTag = {
|
|
153
153
|
kind: "credential_required",
|
|
154
154
|
provider: provider as ProviderId,
|
|
@@ -89,7 +89,7 @@ function classifyAlphaVantageBody(body: string): ValidationResult | undefined {
|
|
|
89
89
|
if (typeof errorMessage === "string" && errorMessage.length > 0) {
|
|
90
90
|
return { status: "invalid", message: errorMessage };
|
|
91
91
|
}
|
|
92
|
-
const information = parsed
|
|
92
|
+
const information = parsed.Information;
|
|
93
93
|
if (typeof information === "string" && /invalid api/i.test(information)) {
|
|
94
94
|
return { status: "invalid", message: information };
|
|
95
95
|
}
|
|
@@ -131,28 +131,22 @@ export async function validateCredential(
|
|
|
131
131
|
);
|
|
132
132
|
|
|
133
133
|
case "brave":
|
|
134
|
-
return validateWithFetch(
|
|
135
|
-
"
|
|
136
|
-
{
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
"X-Subscription-Token": key,
|
|
140
|
-
Accept: "application/json",
|
|
141
|
-
},
|
|
134
|
+
return validateWithFetch("https://api.search.brave.com/res/v1/web/search?q=test&count=1", {
|
|
135
|
+
method: "GET",
|
|
136
|
+
headers: {
|
|
137
|
+
"X-Subscription-Token": key,
|
|
138
|
+
Accept: "application/json",
|
|
142
139
|
},
|
|
143
|
-
);
|
|
140
|
+
});
|
|
144
141
|
|
|
145
142
|
case "exa":
|
|
146
|
-
return validateWithFetch(
|
|
147
|
-
"
|
|
148
|
-
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
"Content-Type": "application/json",
|
|
152
|
-
"x-api-key": key,
|
|
153
|
-
},
|
|
154
|
-
body: JSON.stringify({ query: "test", numResults: 1 }),
|
|
143
|
+
return validateWithFetch("https://api.exa.ai/search", {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: {
|
|
146
|
+
"Content-Type": "application/json",
|
|
147
|
+
"x-api-key": key,
|
|
155
148
|
},
|
|
156
|
-
|
|
149
|
+
body: JSON.stringify({ query: "test", numResults: 1 }),
|
|
150
|
+
});
|
|
157
151
|
}
|
|
158
152
|
}
|