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
package/gui/web/dist/index.html
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
9
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
10
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-CveNgtDg.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-2KZtKBmu.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencandle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Financial trading & investing agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/Kahtaf/OpenCandle#readme",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
},
|
|
14
14
|
"type": "module",
|
|
15
15
|
"workspaces": [
|
|
16
|
-
"gui
|
|
16
|
+
"gui/server",
|
|
17
|
+
"gui/web"
|
|
17
18
|
],
|
|
18
19
|
"bin": {
|
|
19
20
|
"opencandle": "dist/cli.js"
|
|
@@ -85,8 +86,12 @@
|
|
|
85
86
|
"prestart": "npm run check:node",
|
|
86
87
|
"start": "tsx src/cli.ts",
|
|
87
88
|
"gui:web:build": "npm --workspace @opencandle/gui-web run build",
|
|
89
|
+
"docs:site:build": "node website/build.mjs",
|
|
90
|
+
"docs:site:serve": "node website/serve.mjs",
|
|
88
91
|
"gui": "tsx gui/server/server.ts",
|
|
89
92
|
"gui:dev": "tsx gui/server/server.ts",
|
|
93
|
+
"lint": "biome check .",
|
|
94
|
+
"format": "biome check --write .",
|
|
90
95
|
"pretest": "npm run check:node",
|
|
91
96
|
"test": "vitest run",
|
|
92
97
|
"test:watch": "vitest",
|
|
@@ -101,6 +106,10 @@
|
|
|
101
106
|
"test:evals": "vitest run --config vitest.config.evals.ts",
|
|
102
107
|
"eval:router-live": "tsx tests/scripts/run-live-router-eval.ts",
|
|
103
108
|
"test:evals:usually": "EVAL_TIER=usually vitest run --config vitest.config.evals.ts",
|
|
109
|
+
"test:evals:product": "tsx tests/scripts/run-product-evals.ts",
|
|
110
|
+
"test:evals:competitive": "tsx tests/scripts/run-competitive-finance-eval.ts",
|
|
111
|
+
"eval:competitive:analyze": "tsx tests/scripts/analyze-competitive-finance-report.ts",
|
|
112
|
+
"review:pr": ".agents/skills/autoreview/scripts/autoreview --mode branch --prompt-file .agents/skills/autoreview/references/opencandle-review.md --parallel-tests \"npx tsc --noEmit && npx vitest run\"",
|
|
104
113
|
"version:patch": "npm version patch --no-git-tag-version",
|
|
105
114
|
"version:minor": "npm version minor --no-git-tag-version",
|
|
106
115
|
"version:major": "npm version major --no-git-tag-version",
|
|
@@ -115,29 +124,30 @@
|
|
|
115
124
|
"node": "^20.19.0 || ^22.12.0 || >=24.0.0 <27"
|
|
116
125
|
},
|
|
117
126
|
"dependencies": {
|
|
118
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
119
|
-
"@earendil-works/pi-ai": "^0.
|
|
120
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
127
|
+
"@earendil-works/pi-agent-core": "^0.75.5",
|
|
128
|
+
"@earendil-works/pi-ai": "^0.75.5",
|
|
129
|
+
"@earendil-works/pi-coding-agent": "^0.75.5",
|
|
121
130
|
"@the-convocation/twitter-scraper": "^0.22.3",
|
|
122
131
|
"better-sqlite3": "^12.10.0",
|
|
123
132
|
"camoufox-js": "^0.10.2",
|
|
124
133
|
"duck-duck-scrape": "^2.2.7",
|
|
125
134
|
"playwright-core": "^1.60.0",
|
|
126
|
-
"tsx": "^4.22.
|
|
135
|
+
"tsx": "^4.22.3"
|
|
127
136
|
},
|
|
128
137
|
"peerDependencies": {
|
|
129
138
|
"@sinclair/typebox": "*"
|
|
130
139
|
},
|
|
131
140
|
"devDependencies": {
|
|
132
|
-
"@
|
|
133
|
-
"@
|
|
134
|
-
"@mariozechner/pi-coding-agent": "^0.73.1",
|
|
141
|
+
"@agentclientprotocol/claude-agent-acp": "^0.37.0",
|
|
142
|
+
"@biomejs/biome": "2.5.0",
|
|
135
143
|
"@sinclair/typebox": "^0.34.0",
|
|
136
144
|
"@types/better-sqlite3": "^7.6.13",
|
|
137
145
|
"@types/node": "^22.19.19",
|
|
146
|
+
"@zed-industries/codex-acp": "^0.15.0",
|
|
147
|
+
"acpx": "^0.10.0",
|
|
138
148
|
"typescript": "^6.0.3",
|
|
139
|
-
"vite": "^8.0.
|
|
140
|
-
"vitest": "^4.1.
|
|
141
|
-
"vitest-evals": "^0.
|
|
149
|
+
"vite": "^8.0.14",
|
|
150
|
+
"vitest": "^4.1.7",
|
|
151
|
+
"vitest-evals": "^0.11.0"
|
|
142
152
|
}
|
|
143
153
|
}
|
|
@@ -1,31 +1,19 @@
|
|
|
1
|
-
import type { AnalystOutput, AnalystSignal, DebateSide, DebateOutput } from "../runtime/workflow-types.js";
|
|
2
1
|
import type { EvidenceRecord } from "../runtime/evidence.js";
|
|
2
|
+
import type {
|
|
3
|
+
AnalystOutput,
|
|
4
|
+
AnalystSignal,
|
|
5
|
+
DebateOutput,
|
|
6
|
+
DebateSide,
|
|
7
|
+
} from "../runtime/workflow-types.js";
|
|
3
8
|
|
|
4
9
|
/** All analyst roles. */
|
|
5
|
-
export type AnalystRole =
|
|
6
|
-
| "valuation"
|
|
7
|
-
| "momentum"
|
|
8
|
-
| "options"
|
|
9
|
-
| "contrarian"
|
|
10
|
-
| "risk";
|
|
11
|
-
|
|
12
|
-
/** Evidence fields expected per analyst role. */
|
|
13
|
-
export const ROLE_EXPECTED_EVIDENCE: Record<AnalystRole, string[]> = {
|
|
14
|
-
valuation: ["P/E Ratio", "Forward P/E", "EPS", "Intrinsic Value", "Revenue Growth"],
|
|
15
|
-
momentum: ["RSI", "MACD", "SMA 50", "SMA 200", "Volume Trend"],
|
|
16
|
-
options: ["Put/Call Ratio", "IV Level", "Unusual Volume", "Max Pain"],
|
|
17
|
-
contrarian: ["Fear & Greed Index", "Reddit Sentiment", "Sentiment Score"],
|
|
18
|
-
risk: ["Annualized Volatility", "Sharpe Ratio", "Max Drawdown", "VaR 95%", "Position Size"],
|
|
19
|
-
};
|
|
10
|
+
export type AnalystRole = "valuation" | "momentum" | "options" | "contrarian" | "risk";
|
|
20
11
|
|
|
21
12
|
/**
|
|
22
13
|
* Parse an LLM response into a structured AnalystOutput.
|
|
23
14
|
* Falls back to raw text if parsing fails.
|
|
24
15
|
*/
|
|
25
|
-
export function parseAnalystOutput(
|
|
26
|
-
role: string,
|
|
27
|
-
responseText: string,
|
|
28
|
-
): AnalystOutput {
|
|
16
|
+
export function parseAnalystOutput(role: string, responseText: string): AnalystOutput {
|
|
29
17
|
const signal = extractSignal(responseText);
|
|
30
18
|
const conviction = extractConviction(responseText);
|
|
31
19
|
const thesis = extractThesis(responseText);
|
|
@@ -91,9 +79,8 @@ export function tallyVotes(outputs: AnalystOutput[]): {
|
|
|
91
79
|
weightedSum += signalValue * output.conviction;
|
|
92
80
|
}
|
|
93
81
|
|
|
94
|
-
const weightedConviction =
|
|
95
|
-
? Math.round((totalWeight / outputs.length) * 10) / 10
|
|
96
|
-
: 0;
|
|
82
|
+
const weightedConviction =
|
|
83
|
+
totalWeight > 0 ? Math.round((totalWeight / outputs.length) * 10) / 10 : 0;
|
|
97
84
|
|
|
98
85
|
let verdict: AnalystSignal;
|
|
99
86
|
if (weightedSum > 0) verdict = "BUY";
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
| "contrarian"
|
|
6
|
-
| "risk";
|
|
1
|
+
import type { WorkflowDefinition } from "../runtime/prompt-step.js";
|
|
2
|
+
import { promptStep } from "../runtime/prompt-step.js";
|
|
3
|
+
|
|
4
|
+
export type AnalystRole = "valuation" | "momentum" | "options" | "contrarian" | "risk";
|
|
7
5
|
|
|
8
6
|
const SYMBOL_CAPTURE = "(\\$?[A-Za-z]{1,5}(?:[./-][A-Za-z]{1,2})?)";
|
|
9
7
|
const NORMALIZED_SYMBOL_PATTERN = /^[A-Z]{1,5}(?:[./-][A-Z]{1,2})?$/;
|
|
@@ -173,33 +171,10 @@ export interface ComprehensiveAnalysisOptions {
|
|
|
173
171
|
debate?: boolean;
|
|
174
172
|
}
|
|
175
173
|
|
|
176
|
-
export function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
for (const role of roles) {
|
|
182
|
-
prompts.push(ANALYST_PROMPTS[role](symbol));
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (debate) {
|
|
186
|
-
prompts.push(buildBullPrompt(symbol));
|
|
187
|
-
prompts.push(buildBearPrompt(symbol));
|
|
188
|
-
prompts.push(buildRebuttalPrompt(symbol));
|
|
189
|
-
prompts.push(buildSynthesisPrompt(symbol));
|
|
190
|
-
prompts.push(VALIDATION_PROMPT_DEBATE(symbol));
|
|
191
|
-
} else {
|
|
192
|
-
prompts.push(SYNTHESIS_PROMPT_NO_DEBATE(symbol));
|
|
193
|
-
prompts.push(VALIDATION_PROMPT_NO_DEBATE(symbol));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return prompts;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
import type { WorkflowDefinition } from "../runtime/prompt-step.js";
|
|
200
|
-
import { promptStep } from "../runtime/prompt-step.js";
|
|
201
|
-
|
|
202
|
-
export function buildComprehensiveAnalysisDefinition(symbol: string, options?: ComprehensiveAnalysisOptions): WorkflowDefinition {
|
|
174
|
+
export function buildComprehensiveAnalysisDefinition(
|
|
175
|
+
symbol: string,
|
|
176
|
+
options?: ComprehensiveAnalysisOptions,
|
|
177
|
+
): WorkflowDefinition {
|
|
203
178
|
const debate = options?.debate ?? true;
|
|
204
179
|
const roles: AnalystRole[] = ["valuation", "momentum", "options", "contrarian", "risk"];
|
|
205
180
|
|
|
@@ -265,16 +240,6 @@ export function buildComprehensiveAnalysisDefinition(symbol: string, options?: C
|
|
|
265
240
|
};
|
|
266
241
|
}
|
|
267
242
|
|
|
268
|
-
export function runComprehensiveAnalysis(
|
|
269
|
-
enqueueFollowUp: (prompt: string) => void,
|
|
270
|
-
symbol: string,
|
|
271
|
-
options?: ComprehensiveAnalysisOptions,
|
|
272
|
-
): void {
|
|
273
|
-
for (const prompt of getComprehensiveAnalysisPrompts(symbol, options).slice(1)) {
|
|
274
|
-
enqueueFollowUp(prompt);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
243
|
export function isAnalysisRequest(input: string): { match: boolean; symbol?: string } {
|
|
279
244
|
const patterns = [
|
|
280
245
|
new RegExp(`^analyze\\s+${SYMBOL_CAPTURE}\\s*$`, "i"),
|
package/src/cli.ts
CHANGED
|
@@ -3,22 +3,21 @@ import "./infra/node-version.js";
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { dirname, resolve } from "node:path";
|
|
6
|
-
import { parseArgs } from "node:util";
|
|
7
6
|
import { fileURLToPath } from "node:url";
|
|
8
7
|
import {
|
|
9
8
|
AuthStorage,
|
|
10
|
-
DefaultPackageManager,
|
|
11
|
-
InteractiveMode,
|
|
12
|
-
ModelRegistry,
|
|
13
|
-
SettingsManager,
|
|
14
9
|
createAgentSessionRuntime,
|
|
15
10
|
createAgentSessionServices,
|
|
11
|
+
DefaultPackageManager,
|
|
16
12
|
getAgentDir,
|
|
13
|
+
InteractiveMode,
|
|
17
14
|
initTheme,
|
|
15
|
+
ModelRegistry,
|
|
16
|
+
SettingsManager,
|
|
18
17
|
} from "@earendil-works/pi-coding-agent";
|
|
18
|
+
import { loadEnv } from "./config.js";
|
|
19
19
|
import { createOpenCandleSession } from "./pi/session.js";
|
|
20
20
|
import { continueOpenCandleSession } from "./pi/session-storage.js";
|
|
21
|
-
import { loadEnv } from "./config.js";
|
|
22
21
|
|
|
23
22
|
const require = createRequire(import.meta.url);
|
|
24
23
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
@@ -29,10 +28,7 @@ async function handlePackageCommand(
|
|
|
29
28
|
agentDir: string,
|
|
30
29
|
): Promise<boolean> {
|
|
31
30
|
const [command, ...rest] = args;
|
|
32
|
-
if (
|
|
33
|
-
!command ||
|
|
34
|
-
!["install", "remove", "uninstall", "list", "update"].includes(command)
|
|
35
|
-
) {
|
|
31
|
+
if (!command || !["install", "remove", "uninstall", "list", "update"].includes(command)) {
|
|
36
32
|
return false;
|
|
37
33
|
}
|
|
38
34
|
|
|
@@ -139,16 +135,44 @@ async function handleGuiCommand(args: string[], cwd: string): Promise<boolean> {
|
|
|
139
135
|
return true;
|
|
140
136
|
}
|
|
141
137
|
|
|
138
|
+
async function handleMonitorCommand(args: string[], cwd: string): Promise<boolean> {
|
|
139
|
+
if (args[0] !== "monitor") return false;
|
|
140
|
+
|
|
141
|
+
const tsxCli = require.resolve("tsx/cli");
|
|
142
|
+
const monitorPath = resolve(packageRoot, "src/monitor.ts");
|
|
143
|
+
const child = spawn(process.execPath, [tsxCli, monitorPath, ...args.slice(1)], {
|
|
144
|
+
cwd,
|
|
145
|
+
env: process.env,
|
|
146
|
+
stdio: "inherit",
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const exitCode = await new Promise<number>((resolveExit) => {
|
|
150
|
+
child.on("close", (code, signal) => {
|
|
151
|
+
if (signal) {
|
|
152
|
+
resolveExit(1);
|
|
153
|
+
} else {
|
|
154
|
+
resolveExit(code ?? 0);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
process.exitCode = exitCode;
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
|
|
142
162
|
async function main(): Promise<void> {
|
|
143
|
-
const
|
|
163
|
+
const rawArgs = process.argv.slice(2);
|
|
144
164
|
const cwd = process.cwd();
|
|
145
165
|
const agentDir = getAgentDir();
|
|
146
166
|
|
|
147
|
-
if (await handleGuiCommand(
|
|
167
|
+
if (await handleGuiCommand(rawArgs, cwd)) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (await handleMonitorCommand(rawArgs, cwd)) {
|
|
148
172
|
return;
|
|
149
173
|
}
|
|
150
174
|
|
|
151
|
-
if (await handlePackageCommand(
|
|
175
|
+
if (await handlePackageCommand(rawArgs, cwd, agentDir)) {
|
|
152
176
|
return;
|
|
153
177
|
}
|
|
154
178
|
|
package/src/config.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { chmodSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { ensureParentDir, getConfigPath } from "./infra/opencandle-paths.js";
|
|
3
|
+
import type { PlanningBehaviorMode, TaskFamily } from "./routing/planning.js";
|
|
3
4
|
|
|
4
5
|
export interface SentimentConfig {
|
|
5
6
|
retentionDays: number;
|
|
@@ -9,6 +10,8 @@ export interface SentimentConfig {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export type RouterMode = "rules" | "llm";
|
|
13
|
+
export type ToolScopeMode = "observe" | "enforce";
|
|
14
|
+
export type PlanningMigrationStatuses = Partial<Record<TaskFamily, PlanningBehaviorMode>>;
|
|
12
15
|
|
|
13
16
|
export interface Config {
|
|
14
17
|
alphaVantageApiKey?: string;
|
|
@@ -19,11 +22,24 @@ export interface Config {
|
|
|
19
22
|
/** Enable adversarial bull/bear debate in comprehensive analysis. Default: true. */
|
|
20
23
|
debate?: boolean;
|
|
21
24
|
/**
|
|
22
|
-
* Intent-router
|
|
23
|
-
* `classifyIntent` + `extractPreferences`
|
|
24
|
-
* ahead of prompt assembly. Controlled by
|
|
25
|
+
* Intent-router mode. `"rules"` (default) uses the deterministic rule
|
|
26
|
+
* router (`classifyIntent` + `extractPreferences`). `"llm"` opts into the
|
|
27
|
+
* LLM router ahead of prompt assembly. Controlled by
|
|
28
|
+
* `OPENCANDLE_ROUTER_MODE`.
|
|
25
29
|
*/
|
|
26
30
|
routerMode: RouterMode;
|
|
31
|
+
/**
|
|
32
|
+
* Route-selected tool scope mode. `"observe"` (default) records selected
|
|
33
|
+
* bundles and active-tool candidates. `"enforce"` applies Pi active tools
|
|
34
|
+
* for the turn via `pi.setActiveTools`.
|
|
35
|
+
*/
|
|
36
|
+
toolScopeMode: ToolScopeMode;
|
|
37
|
+
/**
|
|
38
|
+
* Per-task planning behavior rollback/activation overrides. Controlled by
|
|
39
|
+
* `OPENCANDLE_PLANNING_MIGRATION_STATUSES`, e.g.
|
|
40
|
+
* `asset_compare=dual_run,single_asset_decision=observe_only`.
|
|
41
|
+
*/
|
|
42
|
+
planningMigrationStatuses?: PlanningMigrationStatuses;
|
|
27
43
|
sentiment?: SentimentConfig;
|
|
28
44
|
}
|
|
29
45
|
|
|
@@ -84,6 +100,30 @@ const SENTIMENT_DEFAULTS: SentimentConfig = {
|
|
|
84
100
|
divergenceThreshold: 0.4,
|
|
85
101
|
};
|
|
86
102
|
|
|
103
|
+
const PLANNING_TASK_FAMILIES = [
|
|
104
|
+
"single_asset_decision",
|
|
105
|
+
"asset_compare",
|
|
106
|
+
"portfolio_build",
|
|
107
|
+
"portfolio_review",
|
|
108
|
+
"macro_allocation_review",
|
|
109
|
+
"options_strategy",
|
|
110
|
+
"current_event_explanation",
|
|
111
|
+
"ticker_disambiguation",
|
|
112
|
+
"filing_thesis_review",
|
|
113
|
+
"sentiment_snapshot",
|
|
114
|
+
"concept_explainer",
|
|
115
|
+
"retail_finance_tradeoff",
|
|
116
|
+
"stateful_tracking_update",
|
|
117
|
+
"backtest_review",
|
|
118
|
+
"general_fallback",
|
|
119
|
+
] as const satisfies readonly TaskFamily[];
|
|
120
|
+
|
|
121
|
+
const PLANNING_BEHAVIOR_MODES = [
|
|
122
|
+
"observe_only",
|
|
123
|
+
"dual_run",
|
|
124
|
+
"replacement_active",
|
|
125
|
+
] as const satisfies readonly PlanningBehaviorMode[];
|
|
126
|
+
|
|
87
127
|
function resolveRouterMode(): RouterMode {
|
|
88
128
|
const raw = process.env.OPENCANDLE_ROUTER_MODE;
|
|
89
129
|
if (raw === undefined || raw === "") return "rules";
|
|
@@ -93,6 +133,48 @@ function resolveRouterMode(): RouterMode {
|
|
|
93
133
|
);
|
|
94
134
|
}
|
|
95
135
|
|
|
136
|
+
function resolveToolScopeMode(): ToolScopeMode {
|
|
137
|
+
const raw = process.env.OPENCANDLE_TOOL_SCOPE_MODE;
|
|
138
|
+
if (raw === undefined || raw === "") return "observe";
|
|
139
|
+
if (raw === "observe" || raw === "enforce") return raw;
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Invalid OPENCANDLE_TOOL_SCOPE_MODE="${raw}". Allowed values: "observe" (default) or "enforce".`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function resolvePlanningMigrationStatuses(): PlanningMigrationStatuses | undefined {
|
|
146
|
+
const raw = process.env.OPENCANDLE_PLANNING_MIGRATION_STATUSES;
|
|
147
|
+
if (raw === undefined || raw.trim() === "") return undefined;
|
|
148
|
+
|
|
149
|
+
const statuses: PlanningMigrationStatuses = {};
|
|
150
|
+
for (const entry of raw.split(",")) {
|
|
151
|
+
const trimmed = entry.trim();
|
|
152
|
+
if (!trimmed) continue;
|
|
153
|
+
|
|
154
|
+
const parts = trimmed.split("=");
|
|
155
|
+
const taskFamily = parts[0]?.trim();
|
|
156
|
+
const behaviorMode = parts[1]?.trim();
|
|
157
|
+
if (
|
|
158
|
+
parts.length !== 2 ||
|
|
159
|
+
!isPlanningTaskFamily(taskFamily) ||
|
|
160
|
+
!isPlanningBehaviorMode(behaviorMode)
|
|
161
|
+
) {
|
|
162
|
+
throw new Error(`Invalid OPENCANDLE_PLANNING_MIGRATION_STATUSES entry "${trimmed}".`);
|
|
163
|
+
}
|
|
164
|
+
statuses[taskFamily] = behaviorMode;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return Object.keys(statuses).length > 0 ? statuses : undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function isPlanningTaskFamily(value: string | undefined): value is TaskFamily {
|
|
171
|
+
return PLANNING_TASK_FAMILIES.includes(value as TaskFamily);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function isPlanningBehaviorMode(value: string | undefined): value is PlanningBehaviorMode {
|
|
175
|
+
return PLANNING_BEHAVIOR_MODES.includes(value as PlanningBehaviorMode);
|
|
176
|
+
}
|
|
177
|
+
|
|
96
178
|
function resolveConfig(fileConfig: OpenCandleFileConfig): Config {
|
|
97
179
|
const debateEnv = process.env.OPENCANDLE_DEBATE;
|
|
98
180
|
const fileSentiment = fileConfig.sentiment;
|
|
@@ -103,13 +185,19 @@ function resolveConfig(fileConfig: OpenCandleFileConfig): Config {
|
|
|
103
185
|
braveApiKey: process.env.BRAVE_API_KEY ?? fileConfig.providers?.brave?.apiKey,
|
|
104
186
|
exaApiKey: process.env.EXA_API_KEY ?? fileConfig.providers?.exa?.apiKey,
|
|
105
187
|
finnhubApiKey: process.env.FINNHUB_API_KEY ?? fileConfig.providers?.finnhub?.apiKey,
|
|
106
|
-
debate:
|
|
188
|
+
debate:
|
|
189
|
+
debateEnv !== undefined
|
|
190
|
+
? debateEnv !== "false" && debateEnv !== "0"
|
|
191
|
+
: (fileConfig.debate ?? true),
|
|
107
192
|
routerMode: resolveRouterMode(),
|
|
193
|
+
toolScopeMode: resolveToolScopeMode(),
|
|
194
|
+
planningMigrationStatuses: resolvePlanningMigrationStatuses(),
|
|
108
195
|
sentiment: {
|
|
109
196
|
retentionDays: fileSentiment?.retentionDays ?? SENTIMENT_DEFAULTS.retentionDays,
|
|
110
197
|
defaultSubreddits: fileSentiment?.defaultSubreddits ?? SENTIMENT_DEFAULTS.defaultSubreddits,
|
|
111
198
|
commentsPerPost: fileSentiment?.commentsPerPost ?? SENTIMENT_DEFAULTS.commentsPerPost,
|
|
112
|
-
divergenceThreshold:
|
|
199
|
+
divergenceThreshold:
|
|
200
|
+
fileSentiment?.divergenceThreshold ?? SENTIMENT_DEFAULTS.divergenceThreshold,
|
|
113
201
|
},
|
|
114
202
|
};
|
|
115
203
|
}
|
|
@@ -138,7 +226,11 @@ export function loadFileConfig(path = getConfigPath()): OpenCandleFileConfig {
|
|
|
138
226
|
|
|
139
227
|
export function saveFileConfig(config: OpenCandleFileConfig, path = getConfigPath()): void {
|
|
140
228
|
ensureParentDir(path);
|
|
141
|
-
writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`,
|
|
229
|
+
writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`, {
|
|
230
|
+
encoding: "utf-8",
|
|
231
|
+
mode: 0o600,
|
|
232
|
+
});
|
|
233
|
+
if (process.platform !== "win32") chmodSync(path, 0o600);
|
|
142
234
|
}
|
|
143
235
|
|
|
144
236
|
export function loadConfig(): Config {
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { createOpenCandleSession, type CreateOpenCandleSessionOptions } from "./pi/session.js";
|
|
2
1
|
export { default as openCandleExtension } from "./pi/opencandle-extension.js";
|
|
2
|
+
export { type CreateOpenCandleSessionOptions, createOpenCandleSession } from "./pi/session.js";
|
|
3
3
|
export { agentToolToPiTool, getOpenCandleToolDefinitions } from "./pi/tool-adapter.js";
|
|
4
4
|
export { registerTools } from "./tool-kit.js";
|
|
5
5
|
export { getAllTools } from "./tools/index.js";
|
package/src/infra/browser.ts
CHANGED
|
@@ -38,7 +38,9 @@ async function ensureBrowser(): Promise<Page> {
|
|
|
38
38
|
|
|
39
39
|
async function withPage<T>(fn: (p: Page) => Promise<T>): Promise<T> {
|
|
40
40
|
let resolve!: () => void;
|
|
41
|
-
const next = new Promise<void>((r) => {
|
|
41
|
+
const next = new Promise<void>((r) => {
|
|
42
|
+
resolve = r;
|
|
43
|
+
});
|
|
42
44
|
const prev = pageQueue;
|
|
43
45
|
pageQueue = next;
|
|
44
46
|
await prev;
|
|
@@ -65,7 +67,7 @@ export const StealthBrowser = {
|
|
|
65
67
|
* Fetch JSON from a URL using the browser's session (cookies, TLS fingerprint).
|
|
66
68
|
* Useful for APIs that block Node.js fetch but allow real browsers.
|
|
67
69
|
*/
|
|
68
|
-
async fetchJson<T>(url: string
|
|
70
|
+
async fetchJson<T>(url: string): Promise<T> {
|
|
69
71
|
return withPage(async (p) => {
|
|
70
72
|
const result = await p.evaluate(async (fetchUrl: string) => {
|
|
71
73
|
const res = await fetch(fetchUrl, { credentials: "include" });
|
package/src/infra/cache.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
1
3
|
interface CacheEntry<T> {
|
|
2
4
|
value: T;
|
|
3
5
|
expiresAt: number;
|
|
@@ -10,10 +12,26 @@ export interface StaleResult<T> {
|
|
|
10
12
|
cachedAt: number;
|
|
11
13
|
}
|
|
12
14
|
|
|
15
|
+
interface StaleMetadata {
|
|
16
|
+
stale: boolean;
|
|
17
|
+
cachedAt: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const staleMetadataStorage = new AsyncLocalStorage<StaleMetadata>();
|
|
21
|
+
|
|
22
|
+
export async function runWithStaleMetadata<T>(
|
|
23
|
+
fn: () => Promise<T>,
|
|
24
|
+
): Promise<{ value: T; stale?: { cachedAt: number } }> {
|
|
25
|
+
const metadata: StaleMetadata = { stale: false, cachedAt: 0 };
|
|
26
|
+
const value = await staleMetadataStorage.run(metadata, fn);
|
|
27
|
+
return {
|
|
28
|
+
value,
|
|
29
|
+
stale: metadata.stale ? { cachedAt: metadata.cachedAt } : undefined,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
13
33
|
export class Cache {
|
|
14
34
|
private store = new Map<string, CacheEntry<unknown>>();
|
|
15
|
-
private lastStaleHit = false;
|
|
16
|
-
private lastStaleCachedAt = 0;
|
|
17
35
|
|
|
18
36
|
get<T>(key: string): T | undefined {
|
|
19
37
|
const entry = this.store.get(key);
|
|
@@ -36,23 +54,14 @@ export class Cache {
|
|
|
36
54
|
return undefined;
|
|
37
55
|
}
|
|
38
56
|
|
|
39
|
-
|
|
40
|
-
|
|
57
|
+
const metadata = staleMetadataStorage.getStore();
|
|
58
|
+
if (metadata) {
|
|
59
|
+
metadata.stale = true;
|
|
60
|
+
metadata.cachedAt = entry.cachedAt;
|
|
61
|
+
}
|
|
41
62
|
return { value: entry.value as T, stale: true, cachedAt: entry.cachedAt };
|
|
42
63
|
}
|
|
43
64
|
|
|
44
|
-
/**
|
|
45
|
-
* Consume the stale flag set by the last getStale() hit.
|
|
46
|
-
* Returns { stale: true, cachedAt } if the last getStale() found data,
|
|
47
|
-
* then resets the flag. Used by wrapProvider to propagate stale metadata.
|
|
48
|
-
*/
|
|
49
|
-
consumeStaleFlag(): { stale: boolean; cachedAt: number } {
|
|
50
|
-
const result = { stale: this.lastStaleHit, cachedAt: this.lastStaleCachedAt };
|
|
51
|
-
this.lastStaleHit = false;
|
|
52
|
-
this.lastStaleCachedAt = 0;
|
|
53
|
-
return result;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
65
|
set<T>(key: string, value: T, ttlMs: number): void {
|
|
57
66
|
this.store.set(key, { value, expiresAt: Date.now() + ttlMs, cachedAt: Date.now() });
|
|
58
67
|
}
|
|
@@ -79,25 +88,27 @@ export const cache = new Cache();
|
|
|
79
88
|
|
|
80
89
|
// Default TTLs
|
|
81
90
|
export const TTL = {
|
|
82
|
-
QUOTE: 60_000,
|
|
83
|
-
HISTORY: 3_600_000,
|
|
91
|
+
QUOTE: 60_000, // 1 minute
|
|
92
|
+
HISTORY: 3_600_000, // 1 hour
|
|
84
93
|
FUNDAMENTALS: 86_400_000, // 24 hours
|
|
85
|
-
MACRO: 3_600_000,
|
|
86
|
-
SENTIMENT: 300_000,
|
|
94
|
+
MACRO: 3_600_000, // 1 hour
|
|
95
|
+
SENTIMENT: 300_000, // 5 minutes
|
|
87
96
|
OPTIONS_CHAIN: 120_000, // 2 minutes
|
|
88
|
-
|
|
89
|
-
|
|
97
|
+
SCREENER: 60_000, // 1 minute
|
|
98
|
+
CRUMB: 900_000, // 15 minutes
|
|
99
|
+
WEB_SEARCH: 300_000, // 5 minutes
|
|
90
100
|
FINNHUB_NEWS: 300_000, // 5 minutes
|
|
91
101
|
} as const;
|
|
92
102
|
|
|
93
103
|
// Stale limits — how long past TTL expiry a cached value is still useful as fallback
|
|
94
104
|
export const STALE_LIMIT = {
|
|
95
|
-
QUOTE: 15 * 60_000,
|
|
96
|
-
HISTORY: 24 * 3_600_000,
|
|
97
|
-
FUNDAMENTALS: 7 * 86_400_000,
|
|
98
|
-
MACRO: 24 * 3_600_000,
|
|
99
|
-
SENTIMENT: 3_600_000,
|
|
100
|
-
OPTIONS_CHAIN: 30 * 60_000,
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
QUOTE: 15 * 60_000, // 15 minutes
|
|
106
|
+
HISTORY: 24 * 3_600_000, // 24 hours
|
|
107
|
+
FUNDAMENTALS: 7 * 86_400_000, // 7 days
|
|
108
|
+
MACRO: 24 * 3_600_000, // 24 hours
|
|
109
|
+
SENTIMENT: 3_600_000, // 1 hour
|
|
110
|
+
OPTIONS_CHAIN: 30 * 60_000, // 30 minutes
|
|
111
|
+
SCREENER: 15 * 60_000, // 15 minutes
|
|
112
|
+
WEB_SEARCH: 3_600_000, // 1 hour
|
|
113
|
+
FINNHUB_NEWS: 3_600_000, // 1 hour
|
|
103
114
|
} as const;
|