opencandle 0.11.1 → 0.13.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.
Files changed (678) hide show
  1. package/README.md +50 -186
  2. package/dist/analysts/contracts.js +0 -1
  3. package/dist/analysts/orchestrator.js +0 -1
  4. package/dist/cli-main.js +22 -15
  5. package/dist/cli-options.d.ts +4 -0
  6. package/dist/cli-options.js +33 -0
  7. package/dist/cli.js +8 -3
  8. package/dist/config.d.ts +4 -0
  9. package/dist/config.js +1 -1
  10. package/dist/doctor/cli-command.js +9 -5
  11. package/dist/doctor/render.js +0 -1
  12. package/dist/doctor/report.js +53 -11
  13. package/dist/gui/server/ask-user-bridge.d.ts +19 -0
  14. package/dist/gui/server/ask-user-bridge.js +55 -0
  15. package/dist/gui/server/automation-heartbeat.d.ts +25 -0
  16. package/dist/gui/server/automation-heartbeat.js +61 -0
  17. package/dist/gui/server/background-quotes.d.ts +39 -0
  18. package/dist/gui/server/background-quotes.js +71 -0
  19. package/dist/gui/server/chat-event-adapter.d.ts +16 -0
  20. package/dist/gui/server/chat-event-adapter.js +388 -0
  21. package/dist/gui/server/gui-session-manager.d.ts +2 -0
  22. package/dist/gui/server/gui-session-manager.js +4 -0
  23. package/dist/gui/server/history-snapshot-store.d.ts +8 -0
  24. package/dist/gui/server/history-snapshot-store.js +43 -0
  25. package/dist/gui/server/http-routes.d.ts +71 -0
  26. package/dist/gui/server/http-routes.js +1033 -0
  27. package/dist/gui/server/invoke-tool.d.ts +47 -0
  28. package/dist/gui/server/invoke-tool.js +373 -0
  29. package/dist/gui/server/live-chat-event-adapter.d.ts +21 -0
  30. package/dist/gui/server/live-chat-event-adapter.js +224 -0
  31. package/dist/gui/server/local-session-coordinator.d.ts +26 -0
  32. package/dist/gui/server/local-session-coordinator.js +53 -0
  33. package/dist/gui/server/market-indices-api.d.ts +21 -0
  34. package/dist/gui/server/market-indices-api.js +26 -0
  35. package/dist/gui/server/market-indices-snapshot-store.d.ts +12 -0
  36. package/dist/gui/server/market-indices-snapshot-store.js +56 -0
  37. package/dist/gui/server/market-state-api.d.ts +250 -0
  38. package/dist/gui/server/market-state-api.js +597 -0
  39. package/dist/gui/server/model-setup.d.ts +55 -0
  40. package/dist/gui/server/model-setup.js +154 -0
  41. package/dist/gui/server/private-api-access.d.ts +6 -0
  42. package/dist/gui/server/private-api-access.js +53 -0
  43. package/dist/gui/server/projector.d.ts +49 -0
  44. package/dist/gui/server/projector.js +296 -0
  45. package/dist/gui/server/prompt-observation.d.ts +8 -0
  46. package/dist/gui/server/prompt-observation.js +43 -0
  47. package/dist/gui/server/quote-snapshot-store.d.ts +14 -0
  48. package/dist/gui/server/quote-snapshot-store.js +49 -0
  49. package/dist/gui/server/server.d.ts +1 -0
  50. package/dist/gui/server/server.js +262 -0
  51. package/dist/gui/server/session-actions.d.ts +60 -0
  52. package/dist/gui/server/session-actions.js +218 -0
  53. package/dist/gui/server/session-entry-wait.d.ts +27 -0
  54. package/dist/gui/server/session-entry-wait.js +129 -0
  55. package/dist/gui/server/session-list.d.ts +2 -0
  56. package/dist/gui/server/session-list.js +11 -0
  57. package/dist/gui/server/shutdown.d.ts +10 -0
  58. package/dist/gui/server/shutdown.js +29 -0
  59. package/dist/gui/server/tool-invoke-ack.d.ts +17 -0
  60. package/dist/gui/server/tool-invoke-ack.js +26 -0
  61. package/dist/gui/server/tool-metadata.d.ts +93 -0
  62. package/dist/gui/server/tool-metadata.js +148 -0
  63. package/dist/gui/server/websocket.d.ts +9 -0
  64. package/dist/gui/server/websocket.js +124 -0
  65. package/dist/gui/server/writer-lock.d.ts +1 -0
  66. package/dist/gui/server/writer-lock.js +1 -0
  67. package/dist/gui/server/ws-hub.d.ts +50 -0
  68. package/dist/gui/server/ws-hub.js +284 -0
  69. package/dist/gui/shared/chat-events.d.ts +174 -0
  70. package/dist/gui/shared/chat-events.js +13 -0
  71. package/dist/gui/shared/event-reducer.d.ts +3 -0
  72. package/dist/gui/shared/event-reducer.js +187 -0
  73. package/dist/index.js +0 -1
  74. package/dist/infra/cache.d.ts +4 -0
  75. package/dist/infra/cache.js +4 -1
  76. package/dist/infra/freshness.js +0 -1
  77. package/dist/infra/http-client.js +1 -2
  78. package/dist/infra/index.js +0 -1
  79. package/dist/infra/lse-byte-budget.d.ts +10 -0
  80. package/dist/infra/lse-byte-budget.js +47 -0
  81. package/dist/infra/market-calendar.js +0 -1
  82. package/dist/infra/native-dependencies.js +0 -1
  83. package/dist/infra/node-version.js +0 -1
  84. package/dist/infra/open-url.js +0 -1
  85. package/dist/infra/opencandle-paths.js +0 -1
  86. package/dist/infra/rate-limiter.js +1 -1
  87. package/dist/market-state/alert-conditions.js +0 -1
  88. package/dist/market-state/alert-runner.d.ts +1 -0
  89. package/dist/market-state/alert-runner.js +5 -4
  90. package/dist/market-state/daily-report.js +0 -1
  91. package/dist/market-state/local-automation-service.js +0 -1
  92. package/dist/market-state/notification-delivery.js +0 -1
  93. package/dist/market-state/resolve-for-mutation.js +0 -1
  94. package/dist/market-state/resolve.js +0 -1
  95. package/dist/market-state/service.d.ts +26 -21
  96. package/dist/market-state/service.js +175 -36
  97. package/dist/market-state/summaries.js +1 -13
  98. package/dist/memory/index.js +0 -1
  99. package/dist/memory/manager.js +0 -1
  100. package/dist/memory/preference-extractor.js +0 -1
  101. package/dist/memory/retrieval.js +0 -1
  102. package/dist/memory/sqlite.js +60 -11
  103. package/dist/memory/storage.js +0 -1
  104. package/dist/memory/tool-defaults.js +0 -1
  105. package/dist/memory/types.js +0 -1
  106. package/dist/monitor.js +0 -1
  107. package/dist/onboarding/connect.js +0 -1
  108. package/dist/onboarding/credential-interceptor.js +0 -1
  109. package/dist/onboarding/degradation-accumulator.js +0 -1
  110. package/dist/onboarding/prompt-user.d.ts +1 -1
  111. package/dist/onboarding/prompt-user.js +0 -1
  112. package/dist/onboarding/provider-status.js +0 -1
  113. package/dist/onboarding/providers.d.ts +16 -1
  114. package/dist/onboarding/providers.js +20 -1
  115. package/dist/onboarding/state.js +0 -1
  116. package/dist/onboarding/tool-helpers.js +0 -1
  117. package/dist/onboarding/tool-tags.js +0 -1
  118. package/dist/onboarding/validate-model-key.d.ts +17 -0
  119. package/dist/onboarding/validate-model-key.js +86 -0
  120. package/dist/onboarding/validation.js +8 -1
  121. package/dist/pi/opencandle-extension.d.ts +2 -1
  122. package/dist/pi/opencandle-extension.js +4 -4
  123. package/dist/pi/session-action-dedupe.js +0 -1
  124. package/dist/pi/session-storage.js +0 -1
  125. package/dist/pi/session-writer-lock.js +0 -1
  126. package/dist/pi/session.d.ts +2 -3
  127. package/dist/pi/session.js +7 -6
  128. package/dist/pi/setup.d.ts +4 -2
  129. package/dist/pi/setup.js +60 -61
  130. package/dist/pi/tool-adapter.js +0 -1
  131. package/dist/pi/tui-session-coordinator.js +0 -1
  132. package/dist/prompts/context-builder.js +1 -2
  133. package/dist/prompts/disclaimer.js +0 -1
  134. package/dist/prompts/policy-cards.js +0 -1
  135. package/dist/prompts/sections.js +0 -1
  136. package/dist/prompts/symbol-preflight.js +0 -1
  137. package/dist/prompts/workflow-prompts.js +16 -15
  138. package/dist/providers/alpha-vantage.js +2 -3
  139. package/dist/providers/coingecko.js +0 -1
  140. package/dist/providers/errors.js +0 -1
  141. package/dist/providers/exa-search.js +11 -10
  142. package/dist/providers/external-tool-command.js +0 -1
  143. package/dist/providers/external-tool-error.js +0 -1
  144. package/dist/providers/fear-greed.js +0 -1
  145. package/dist/providers/finnhub.js +0 -1
  146. package/dist/providers/fred.js +0 -1
  147. package/dist/providers/index.d.ts +1 -0
  148. package/dist/providers/index.js +1 -1
  149. package/dist/providers/lse.d.ts +35 -0
  150. package/dist/providers/lse.js +284 -0
  151. package/dist/providers/polymarket.js +22 -6
  152. package/dist/providers/provider-credential-error.js +0 -1
  153. package/dist/providers/reddit-cli.js +0 -1
  154. package/dist/providers/reddit.js +0 -1
  155. package/dist/providers/sec-edgar.js +0 -1
  156. package/dist/providers/tradingview.js +1 -2
  157. package/dist/providers/twitter-cli.js +0 -1
  158. package/dist/providers/twitter.js +0 -1
  159. package/dist/providers/web-search.js +15 -12
  160. package/dist/providers/with-fallback.js +0 -1
  161. package/dist/providers/wrap-provider.js +1 -1
  162. package/dist/providers/yahoo-finance.js +68 -4
  163. package/dist/routing/classify-intent.js +0 -1
  164. package/dist/routing/defaults.js +0 -1
  165. package/dist/routing/entity-extractor.js +2 -3
  166. package/dist/routing/fund-symbols.js +0 -1
  167. package/dist/routing/horizon.js +0 -1
  168. package/dist/routing/index.js +0 -1
  169. package/dist/routing/legacy-rule-router.js +0 -1
  170. package/dist/routing/planning.js +0 -1
  171. package/dist/routing/route-manifest.js +1 -1
  172. package/dist/routing/router-llm-client.d.ts +2 -2
  173. package/dist/routing/router-llm-client.js +0 -1
  174. package/dist/routing/router-prompt.js +0 -1
  175. package/dist/routing/router-types.js +0 -1
  176. package/dist/routing/router.js +9 -3
  177. package/dist/routing/slot-resolver.js +0 -1
  178. package/dist/routing/symbol-disambiguator.js +0 -1
  179. package/dist/routing/turn-context.js +0 -1
  180. package/dist/routing/types.js +0 -1
  181. package/dist/runtime/answer-contracts.js +0 -1
  182. package/dist/runtime/artifact-contracts.js +0 -1
  183. package/dist/runtime/evidence.d.ts +1 -0
  184. package/dist/runtime/evidence.js +1 -2
  185. package/dist/runtime/numeric-claims.js +0 -1
  186. package/dist/runtime/planning-evidence.js +0 -1
  187. package/dist/runtime/prompt-step.js +0 -1
  188. package/dist/runtime/provider-tracker.js +0 -1
  189. package/dist/runtime/run-context.js +0 -1
  190. package/dist/runtime/session-coordinator.d.ts +2 -2
  191. package/dist/runtime/session-coordinator.js +2 -3
  192. package/dist/runtime/session-title.js +0 -1
  193. package/dist/runtime/tool-defaults-wrapper.js +0 -1
  194. package/dist/runtime/validation.js +0 -1
  195. package/dist/runtime/workflow-events.js +0 -1
  196. package/dist/runtime/workflow-runner.d.ts +1 -0
  197. package/dist/runtime/workflow-runner.js +8 -3
  198. package/dist/runtime/workflow-types.js +0 -1
  199. package/dist/sentiment/adapters/finnhub.js +0 -1
  200. package/dist/sentiment/adapters/reddit.js +0 -1
  201. package/dist/sentiment/adapters/twitter.js +0 -1
  202. package/dist/sentiment/adapters/web.js +0 -1
  203. package/dist/sentiment/index.js +4 -2
  204. package/dist/sentiment/insights.js +0 -1
  205. package/dist/sentiment/keywords.js +0 -1
  206. package/dist/sentiment/pipeline.js +0 -1
  207. package/dist/sentiment/scorer.js +0 -1
  208. package/dist/sentiment/store.js +0 -1
  209. package/dist/sentiment/trends.js +0 -1
  210. package/dist/sentiment/types.js +0 -1
  211. package/dist/system-prompt.js +0 -1
  212. package/dist/tool-kit.js +0 -1
  213. package/dist/tools/fundamentals/company-overview.d.ts +1 -1
  214. package/dist/tools/fundamentals/company-overview.js +2 -1
  215. package/dist/tools/fundamentals/comps.js +6 -4
  216. package/dist/tools/fundamentals/dcf.js +37 -9
  217. package/dist/tools/fundamentals/earnings.d.ts +1 -1
  218. package/dist/tools/fundamentals/earnings.js +2 -1
  219. package/dist/tools/fundamentals/financials.js +88 -9
  220. package/dist/tools/fundamentals/sec-filings.js +0 -1
  221. package/dist/tools/index.d.ts +121 -2
  222. package/dist/tools/index.js +3 -1
  223. package/dist/tools/interaction/ask-user.js +11 -1
  224. package/dist/tools/macro/event-probabilities.js +0 -1
  225. package/dist/tools/macro/fear-greed.d.ts +1 -1
  226. package/dist/tools/macro/fear-greed.js +0 -1
  227. package/dist/tools/macro/fred-data.d.ts +1 -1
  228. package/dist/tools/macro/fred-data.js +2 -1
  229. package/dist/tools/market/crypto-history.js +0 -1
  230. package/dist/tools/market/crypto-price.d.ts +2 -2
  231. package/dist/tools/market/crypto-price.js +0 -1
  232. package/dist/tools/market/price-comparison.d.ts +30 -0
  233. package/dist/tools/market/price-comparison.js +202 -0
  234. package/dist/tools/market/screen-stocks.js +0 -1
  235. package/dist/tools/market/search-ticker.js +1 -2
  236. package/dist/tools/market/stock-history.d.ts +18 -3
  237. package/dist/tools/market/stock-history.js +132 -18
  238. package/dist/tools/market/stock-quote.d.ts +2 -2
  239. package/dist/tools/market/stock-quote.js +0 -1
  240. package/dist/tools/options/greeks.js +0 -1
  241. package/dist/tools/options/option-chain.d.ts +2 -2
  242. package/dist/tools/options/option-chain.js +0 -1
  243. package/dist/tools/portfolio/alerts.d.ts +2 -1
  244. package/dist/tools/portfolio/alerts.js +228 -2
  245. package/dist/tools/portfolio/correlation.d.ts +1 -1
  246. package/dist/tools/portfolio/correlation.js +23 -5
  247. package/dist/tools/portfolio/daily-report.js +0 -1
  248. package/dist/tools/portfolio/holdings-overlap.js +0 -1
  249. package/dist/tools/portfolio/notifications.js +0 -1
  250. package/dist/tools/portfolio/risk-analysis.d.ts +2 -2
  251. package/dist/tools/portfolio/risk-analysis.js +0 -1
  252. package/dist/tools/portfolio/tracker.d.ts +3 -1
  253. package/dist/tools/portfolio/tracker.js +57 -10
  254. package/dist/tools/portfolio/watchlist.d.ts +3 -6
  255. package/dist/tools/portfolio/watchlist.js +101 -110
  256. package/dist/tools/sentiment/insight-format.js +0 -1
  257. package/dist/tools/sentiment/query-match.js +0 -1
  258. package/dist/tools/sentiment/reddit-sentiment.js +0 -1
  259. package/dist/tools/sentiment/sentiment-summary.js +8 -4
  260. package/dist/tools/sentiment/sentiment-trend.d.ts +5 -1
  261. package/dist/tools/sentiment/sentiment-trend.js +6 -2
  262. package/dist/tools/sentiment/twitter-sentiment.js +0 -1
  263. package/dist/tools/sentiment/untrusted-text.js +0 -1
  264. package/dist/tools/sentiment/web-search.d.ts +1 -1
  265. package/dist/tools/sentiment/web-search.js +0 -1
  266. package/dist/tools/sentiment/web-sentiment.js +0 -1
  267. package/dist/tools/technical/backtest.js +0 -1
  268. package/dist/tools/technical/indicators.js +0 -1
  269. package/dist/types/fundamentals.js +0 -1
  270. package/dist/types/index.js +0 -1
  271. package/dist/types/macro.js +0 -1
  272. package/dist/types/market.d.ts +8 -0
  273. package/dist/types/market.js +0 -1
  274. package/dist/types/options.js +0 -1
  275. package/dist/types/portfolio.js +0 -1
  276. package/dist/types/prediction-markets.js +0 -1
  277. package/dist/types/sentiment.js +0 -1
  278. package/dist/workflows/compare-assets.js +0 -1
  279. package/dist/workflows/index.js +0 -1
  280. package/dist/workflows/options-screener.js +0 -1
  281. package/dist/workflows/portfolio-builder.js +0 -1
  282. package/gui/web/dist/assets/CatalogOverlay-Cy8Fq0fn.js +1 -0
  283. package/gui/web/dist/assets/allocation-donut-DgBRIKCk.js +52 -0
  284. package/gui/web/dist/assets/index-DIlFyIOO.js +66 -0
  285. package/gui/web/dist/assets/index-DS4jESOB.css +2 -0
  286. package/gui/web/dist/assets/market-chart-DammaCjH.js +1 -0
  287. package/gui/web/dist/assets/utils-CnADgYgh.js +1 -0
  288. package/gui/web/dist/index.html +3 -2
  289. package/package.json +23 -26
  290. package/dist/analysts/contracts.js.map +0 -1
  291. package/dist/analysts/orchestrator.js.map +0 -1
  292. package/dist/cli-main.js.map +0 -1
  293. package/dist/cli.js.map +0 -1
  294. package/dist/config.js.map +0 -1
  295. package/dist/doctor/cli-command.js.map +0 -1
  296. package/dist/doctor/render.js.map +0 -1
  297. package/dist/doctor/report.js.map +0 -1
  298. package/dist/index.js.map +0 -1
  299. package/dist/infra/cache.js.map +0 -1
  300. package/dist/infra/freshness.js.map +0 -1
  301. package/dist/infra/http-client.js.map +0 -1
  302. package/dist/infra/index.js.map +0 -1
  303. package/dist/infra/market-calendar.js.map +0 -1
  304. package/dist/infra/native-dependencies.js.map +0 -1
  305. package/dist/infra/node-version.js.map +0 -1
  306. package/dist/infra/open-url.js.map +0 -1
  307. package/dist/infra/opencandle-paths.js.map +0 -1
  308. package/dist/infra/rate-limiter.js.map +0 -1
  309. package/dist/market-state/alert-conditions.js.map +0 -1
  310. package/dist/market-state/alert-runner.js.map +0 -1
  311. package/dist/market-state/daily-report.js.map +0 -1
  312. package/dist/market-state/local-automation-service.js.map +0 -1
  313. package/dist/market-state/notification-delivery.js.map +0 -1
  314. package/dist/market-state/resolve-for-mutation.js.map +0 -1
  315. package/dist/market-state/resolve.js.map +0 -1
  316. package/dist/market-state/service.js.map +0 -1
  317. package/dist/market-state/summaries.js.map +0 -1
  318. package/dist/memory/index.js.map +0 -1
  319. package/dist/memory/manager.js.map +0 -1
  320. package/dist/memory/preference-extractor.js.map +0 -1
  321. package/dist/memory/retrieval.js.map +0 -1
  322. package/dist/memory/sqlite.js.map +0 -1
  323. package/dist/memory/storage.js.map +0 -1
  324. package/dist/memory/tool-defaults.js.map +0 -1
  325. package/dist/memory/types.js.map +0 -1
  326. package/dist/monitor.js.map +0 -1
  327. package/dist/onboarding/connect.js.map +0 -1
  328. package/dist/onboarding/credential-interceptor.js.map +0 -1
  329. package/dist/onboarding/degradation-accumulator.js.map +0 -1
  330. package/dist/onboarding/prompt-user.js.map +0 -1
  331. package/dist/onboarding/provider-status.js.map +0 -1
  332. package/dist/onboarding/providers.js.map +0 -1
  333. package/dist/onboarding/state.js.map +0 -1
  334. package/dist/onboarding/tool-helpers.js.map +0 -1
  335. package/dist/onboarding/tool-tags.js.map +0 -1
  336. package/dist/onboarding/validation.js.map +0 -1
  337. package/dist/pi/opencandle-extension.js.map +0 -1
  338. package/dist/pi/session-action-dedupe.js.map +0 -1
  339. package/dist/pi/session-storage.js.map +0 -1
  340. package/dist/pi/session-writer-lock.js.map +0 -1
  341. package/dist/pi/session.js.map +0 -1
  342. package/dist/pi/setup.js.map +0 -1
  343. package/dist/pi/tool-adapter.js.map +0 -1
  344. package/dist/pi/tui-session-coordinator.js.map +0 -1
  345. package/dist/prompts/context-builder.js.map +0 -1
  346. package/dist/prompts/disclaimer.js.map +0 -1
  347. package/dist/prompts/policy-cards.js.map +0 -1
  348. package/dist/prompts/sections.js.map +0 -1
  349. package/dist/prompts/symbol-preflight.js.map +0 -1
  350. package/dist/prompts/workflow-prompts.js.map +0 -1
  351. package/dist/providers/alpha-vantage.js.map +0 -1
  352. package/dist/providers/coingecko.js.map +0 -1
  353. package/dist/providers/errors.js.map +0 -1
  354. package/dist/providers/exa-search.js.map +0 -1
  355. package/dist/providers/external-tool-command.js.map +0 -1
  356. package/dist/providers/external-tool-error.js.map +0 -1
  357. package/dist/providers/fear-greed.js.map +0 -1
  358. package/dist/providers/finnhub.js.map +0 -1
  359. package/dist/providers/fred.js.map +0 -1
  360. package/dist/providers/index.js.map +0 -1
  361. package/dist/providers/polymarket.js.map +0 -1
  362. package/dist/providers/provider-credential-error.js.map +0 -1
  363. package/dist/providers/reddit-cli.js.map +0 -1
  364. package/dist/providers/reddit.js.map +0 -1
  365. package/dist/providers/sec-edgar.js.map +0 -1
  366. package/dist/providers/tradingview.js.map +0 -1
  367. package/dist/providers/twitter-cli.js.map +0 -1
  368. package/dist/providers/twitter.js.map +0 -1
  369. package/dist/providers/web-search.js.map +0 -1
  370. package/dist/providers/with-fallback.js.map +0 -1
  371. package/dist/providers/wrap-provider.js.map +0 -1
  372. package/dist/providers/yahoo-finance.js.map +0 -1
  373. package/dist/routing/classify-intent.js.map +0 -1
  374. package/dist/routing/defaults.js.map +0 -1
  375. package/dist/routing/entity-extractor.js.map +0 -1
  376. package/dist/routing/fund-symbols.js.map +0 -1
  377. package/dist/routing/horizon.js.map +0 -1
  378. package/dist/routing/index.js.map +0 -1
  379. package/dist/routing/legacy-rule-router.js.map +0 -1
  380. package/dist/routing/planning.js.map +0 -1
  381. package/dist/routing/route-manifest.js.map +0 -1
  382. package/dist/routing/router-llm-client.js.map +0 -1
  383. package/dist/routing/router-prompt.js.map +0 -1
  384. package/dist/routing/router-types.js.map +0 -1
  385. package/dist/routing/router.js.map +0 -1
  386. package/dist/routing/slot-resolver.js.map +0 -1
  387. package/dist/routing/symbol-disambiguator.js.map +0 -1
  388. package/dist/routing/turn-context.js.map +0 -1
  389. package/dist/routing/types.js.map +0 -1
  390. package/dist/runtime/answer-contracts.js.map +0 -1
  391. package/dist/runtime/artifact-contracts.js.map +0 -1
  392. package/dist/runtime/evidence.js.map +0 -1
  393. package/dist/runtime/numeric-claims.js.map +0 -1
  394. package/dist/runtime/planning-evidence.js.map +0 -1
  395. package/dist/runtime/prompt-step.js.map +0 -1
  396. package/dist/runtime/provider-tracker.js.map +0 -1
  397. package/dist/runtime/run-context.js.map +0 -1
  398. package/dist/runtime/session-coordinator.js.map +0 -1
  399. package/dist/runtime/session-title.js.map +0 -1
  400. package/dist/runtime/tool-defaults-wrapper.js.map +0 -1
  401. package/dist/runtime/validation.js.map +0 -1
  402. package/dist/runtime/workflow-events.js.map +0 -1
  403. package/dist/runtime/workflow-runner.js.map +0 -1
  404. package/dist/runtime/workflow-types.js.map +0 -1
  405. package/dist/sentiment/adapters/finnhub.js.map +0 -1
  406. package/dist/sentiment/adapters/reddit.js.map +0 -1
  407. package/dist/sentiment/adapters/twitter.js.map +0 -1
  408. package/dist/sentiment/adapters/web.js.map +0 -1
  409. package/dist/sentiment/index.js.map +0 -1
  410. package/dist/sentiment/insights.js.map +0 -1
  411. package/dist/sentiment/keywords.js.map +0 -1
  412. package/dist/sentiment/pipeline.js.map +0 -1
  413. package/dist/sentiment/scorer.js.map +0 -1
  414. package/dist/sentiment/store.js.map +0 -1
  415. package/dist/sentiment/trends.js.map +0 -1
  416. package/dist/sentiment/types.js.map +0 -1
  417. package/dist/system-prompt.js.map +0 -1
  418. package/dist/tool-kit.js.map +0 -1
  419. package/dist/tools/fundamentals/company-overview.js.map +0 -1
  420. package/dist/tools/fundamentals/comps.js.map +0 -1
  421. package/dist/tools/fundamentals/dcf.js.map +0 -1
  422. package/dist/tools/fundamentals/earnings.js.map +0 -1
  423. package/dist/tools/fundamentals/financials.js.map +0 -1
  424. package/dist/tools/fundamentals/sec-filings.js.map +0 -1
  425. package/dist/tools/index.js.map +0 -1
  426. package/dist/tools/interaction/ask-user.js.map +0 -1
  427. package/dist/tools/macro/event-probabilities.js.map +0 -1
  428. package/dist/tools/macro/fear-greed.js.map +0 -1
  429. package/dist/tools/macro/fred-data.js.map +0 -1
  430. package/dist/tools/market/crypto-history.js.map +0 -1
  431. package/dist/tools/market/crypto-price.js.map +0 -1
  432. package/dist/tools/market/screen-stocks.js.map +0 -1
  433. package/dist/tools/market/search-ticker.js.map +0 -1
  434. package/dist/tools/market/stock-history.js.map +0 -1
  435. package/dist/tools/market/stock-quote.js.map +0 -1
  436. package/dist/tools/options/greeks.js.map +0 -1
  437. package/dist/tools/options/option-chain.js.map +0 -1
  438. package/dist/tools/portfolio/alerts.js.map +0 -1
  439. package/dist/tools/portfolio/correlation.js.map +0 -1
  440. package/dist/tools/portfolio/daily-report.js.map +0 -1
  441. package/dist/tools/portfolio/holdings-overlap.js.map +0 -1
  442. package/dist/tools/portfolio/notifications.js.map +0 -1
  443. package/dist/tools/portfolio/risk-analysis.js.map +0 -1
  444. package/dist/tools/portfolio/tracker.js.map +0 -1
  445. package/dist/tools/portfolio/watchlist.js.map +0 -1
  446. package/dist/tools/sentiment/insight-format.js.map +0 -1
  447. package/dist/tools/sentiment/query-match.js.map +0 -1
  448. package/dist/tools/sentiment/reddit-sentiment.js.map +0 -1
  449. package/dist/tools/sentiment/sentiment-summary.js.map +0 -1
  450. package/dist/tools/sentiment/sentiment-trend.js.map +0 -1
  451. package/dist/tools/sentiment/twitter-sentiment.js.map +0 -1
  452. package/dist/tools/sentiment/untrusted-text.js.map +0 -1
  453. package/dist/tools/sentiment/web-search.js.map +0 -1
  454. package/dist/tools/sentiment/web-sentiment.js.map +0 -1
  455. package/dist/tools/technical/backtest.js.map +0 -1
  456. package/dist/tools/technical/indicators.js.map +0 -1
  457. package/dist/types/fundamentals.js.map +0 -1
  458. package/dist/types/index.js.map +0 -1
  459. package/dist/types/macro.js.map +0 -1
  460. package/dist/types/market.js.map +0 -1
  461. package/dist/types/options.js.map +0 -1
  462. package/dist/types/portfolio.js.map +0 -1
  463. package/dist/types/prediction-markets.js.map +0 -1
  464. package/dist/types/sentiment.js.map +0 -1
  465. package/dist/workflows/compare-assets.js.map +0 -1
  466. package/dist/workflows/index.js.map +0 -1
  467. package/dist/workflows/options-screener.js.map +0 -1
  468. package/dist/workflows/portfolio-builder.js.map +0 -1
  469. package/gui/server/ask-user-bridge.ts +0 -89
  470. package/gui/server/automation-heartbeat.ts +0 -97
  471. package/gui/server/background-quotes.ts +0 -127
  472. package/gui/server/chat-event-adapter.ts +0 -294
  473. package/gui/server/gui-session-manager.ts +0 -5
  474. package/gui/server/http-routes.ts +0 -1201
  475. package/gui/server/invoke-tool.ts +0 -490
  476. package/gui/server/live-chat-event-adapter.ts +0 -243
  477. package/gui/server/local-session-coordinator.ts +0 -97
  478. package/gui/server/market-state-api.ts +0 -331
  479. package/gui/server/model-setup.ts +0 -254
  480. package/gui/server/package.json +0 -5
  481. package/gui/server/private-api-access.ts +0 -62
  482. package/gui/server/projector.ts +0 -392
  483. package/gui/server/prompt-observation.ts +0 -58
  484. package/gui/server/quote-snapshot-store.ts +0 -50
  485. package/gui/server/server.ts +0 -289
  486. package/gui/server/session-actions.ts +0 -323
  487. package/gui/server/session-entry-wait.ts +0 -179
  488. package/gui/server/shutdown.ts +0 -47
  489. package/gui/server/tool-invoke-ack.ts +0 -49
  490. package/gui/server/tool-metadata.ts +0 -167
  491. package/gui/server/websocket.ts +0 -138
  492. package/gui/server/writer-lock.ts +0 -1
  493. package/gui/server/ws-hub.ts +0 -403
  494. package/gui/shared/chat-events.ts +0 -165
  495. package/gui/shared/event-reducer.ts +0 -220
  496. package/gui/web/dist/assets/CatalogOverlay-DZ1niyQm.js +0 -1
  497. package/gui/web/dist/assets/index-D4F9AJnn.css +0 -2
  498. package/gui/web/dist/assets/index-DtqMMBTr.js +0 -65
  499. package/src/analysts/contracts.ts +0 -176
  500. package/src/analysts/orchestrator.ts +0 -244
  501. package/src/cli-main.ts +0 -510
  502. package/src/cli.ts +0 -17
  503. package/src/config.ts +0 -272
  504. package/src/doctor/cli-command.ts +0 -83
  505. package/src/doctor/render.ts +0 -37
  506. package/src/doctor/report.ts +0 -638
  507. package/src/index.ts +0 -5
  508. package/src/infra/cache.ts +0 -127
  509. package/src/infra/freshness.ts +0 -165
  510. package/src/infra/http-client.ts +0 -134
  511. package/src/infra/index.ts +0 -14
  512. package/src/infra/market-calendar.ts +0 -193
  513. package/src/infra/native-dependencies.ts +0 -84
  514. package/src/infra/node-version.ts +0 -23
  515. package/src/infra/open-url.ts +0 -28
  516. package/src/infra/opencandle-paths.ts +0 -53
  517. package/src/infra/rate-limiter.ts +0 -77
  518. package/src/market-state/alert-conditions.ts +0 -82
  519. package/src/market-state/alert-runner.ts +0 -863
  520. package/src/market-state/daily-report.ts +0 -237
  521. package/src/market-state/local-automation-service.ts +0 -162
  522. package/src/market-state/notification-delivery.ts +0 -158
  523. package/src/market-state/resolve-for-mutation.ts +0 -24
  524. package/src/market-state/resolve.ts +0 -112
  525. package/src/market-state/service.ts +0 -2208
  526. package/src/market-state/summaries.ts +0 -75
  527. package/src/memory/index.ts +0 -10
  528. package/src/memory/manager.ts +0 -190
  529. package/src/memory/preference-extractor.ts +0 -106
  530. package/src/memory/retrieval.ts +0 -71
  531. package/src/memory/sqlite.ts +0 -577
  532. package/src/memory/storage.ts +0 -195
  533. package/src/memory/tool-defaults.ts +0 -108
  534. package/src/memory/types.ts +0 -71
  535. package/src/monitor.ts +0 -123
  536. package/src/onboarding/connect.ts +0 -177
  537. package/src/onboarding/credential-interceptor.ts +0 -122
  538. package/src/onboarding/degradation-accumulator.ts +0 -77
  539. package/src/onboarding/prompt-user.ts +0 -85
  540. package/src/onboarding/provider-status.ts +0 -382
  541. package/src/onboarding/providers.ts +0 -442
  542. package/src/onboarding/state.ts +0 -216
  543. package/src/onboarding/tool-helpers.ts +0 -104
  544. package/src/onboarding/tool-tags.ts +0 -244
  545. package/src/onboarding/validation.ts +0 -152
  546. package/src/pi/opencandle-extension.ts +0 -1294
  547. package/src/pi/session-action-dedupe.ts +0 -155
  548. package/src/pi/session-storage.ts +0 -5
  549. package/src/pi/session-writer-lock.ts +0 -426
  550. package/src/pi/session.ts +0 -84
  551. package/src/pi/setup.ts +0 -399
  552. package/src/pi/tool-adapter.ts +0 -49
  553. package/src/pi/tui-session-coordinator.ts +0 -351
  554. package/src/prompts/context-builder.ts +0 -326
  555. package/src/prompts/disclaimer.ts +0 -9
  556. package/src/prompts/policy-cards.ts +0 -228
  557. package/src/prompts/sections.ts +0 -46
  558. package/src/prompts/symbol-preflight.ts +0 -80
  559. package/src/prompts/workflow-prompts.ts +0 -504
  560. package/src/providers/alpha-vantage.ts +0 -340
  561. package/src/providers/coingecko.ts +0 -95
  562. package/src/providers/errors.ts +0 -9
  563. package/src/providers/exa-search.ts +0 -375
  564. package/src/providers/external-tool-command.ts +0 -164
  565. package/src/providers/external-tool-error.ts +0 -20
  566. package/src/providers/fear-greed.ts +0 -45
  567. package/src/providers/finnhub.ts +0 -125
  568. package/src/providers/fred.ts +0 -83
  569. package/src/providers/index.ts +0 -17
  570. package/src/providers/polymarket.ts +0 -214
  571. package/src/providers/provider-credential-error.ts +0 -23
  572. package/src/providers/reddit-cli.ts +0 -286
  573. package/src/providers/reddit.ts +0 -106
  574. package/src/providers/sec-edgar.ts +0 -326
  575. package/src/providers/tradingview.ts +0 -399
  576. package/src/providers/twitter-cli.ts +0 -202
  577. package/src/providers/twitter.ts +0 -102
  578. package/src/providers/web-search.ts +0 -303
  579. package/src/providers/with-fallback.ts +0 -42
  580. package/src/providers/wrap-provider.ts +0 -105
  581. package/src/providers/yahoo-finance.ts +0 -984
  582. package/src/routing/classify-intent.ts +0 -380
  583. package/src/routing/defaults.ts +0 -29
  584. package/src/routing/entity-extractor.ts +0 -557
  585. package/src/routing/fund-symbols.ts +0 -58
  586. package/src/routing/horizon.ts +0 -7
  587. package/src/routing/index.ts +0 -70
  588. package/src/routing/legacy-rule-router.ts +0 -13
  589. package/src/routing/planning.ts +0 -829
  590. package/src/routing/route-manifest.ts +0 -308
  591. package/src/routing/router-llm-client.ts +0 -64
  592. package/src/routing/router-prompt.ts +0 -159
  593. package/src/routing/router-types.ts +0 -84
  594. package/src/routing/router.ts +0 -1332
  595. package/src/routing/slot-resolver.ts +0 -213
  596. package/src/routing/symbol-disambiguator.ts +0 -72
  597. package/src/routing/turn-context.ts +0 -108
  598. package/src/routing/types.ts +0 -77
  599. package/src/runtime/answer-contracts.ts +0 -693
  600. package/src/runtime/artifact-contracts.ts +0 -77
  601. package/src/runtime/evidence.ts +0 -78
  602. package/src/runtime/numeric-claims.ts +0 -108
  603. package/src/runtime/planning-evidence.ts +0 -597
  604. package/src/runtime/prompt-step.ts +0 -185
  605. package/src/runtime/provider-tracker.ts +0 -40
  606. package/src/runtime/run-context.ts +0 -32
  607. package/src/runtime/session-coordinator.ts +0 -1037
  608. package/src/runtime/session-title.ts +0 -60
  609. package/src/runtime/tool-defaults-wrapper.ts +0 -43
  610. package/src/runtime/validation.ts +0 -211
  611. package/src/runtime/workflow-events.ts +0 -77
  612. package/src/runtime/workflow-runner.ts +0 -182
  613. package/src/runtime/workflow-types.ts +0 -105
  614. package/src/sentiment/adapters/finnhub.ts +0 -49
  615. package/src/sentiment/adapters/reddit.ts +0 -65
  616. package/src/sentiment/adapters/twitter.ts +0 -36
  617. package/src/sentiment/adapters/web.ts +0 -44
  618. package/src/sentiment/index.ts +0 -49
  619. package/src/sentiment/insights.ts +0 -269
  620. package/src/sentiment/keywords.ts +0 -31
  621. package/src/sentiment/pipeline.ts +0 -91
  622. package/src/sentiment/scorer.ts +0 -89
  623. package/src/sentiment/store.ts +0 -260
  624. package/src/sentiment/trends.ts +0 -96
  625. package/src/sentiment/types.ts +0 -112
  626. package/src/system-prompt.ts +0 -115
  627. package/src/tool-kit.ts +0 -69
  628. package/src/tools/AGENTS.md +0 -36
  629. package/src/tools/fundamentals/company-overview.ts +0 -64
  630. package/src/tools/fundamentals/comps.ts +0 -180
  631. package/src/tools/fundamentals/dcf.ts +0 -447
  632. package/src/tools/fundamentals/earnings.ts +0 -57
  633. package/src/tools/fundamentals/financials.ts +0 -63
  634. package/src/tools/fundamentals/sec-filings.ts +0 -105
  635. package/src/tools/index.ts +0 -104
  636. package/src/tools/interaction/ask-user.ts +0 -93
  637. package/src/tools/macro/event-probabilities.ts +0 -141
  638. package/src/tools/macro/fear-greed.ts +0 -41
  639. package/src/tools/macro/fred-data.ts +0 -92
  640. package/src/tools/market/crypto-history.ts +0 -72
  641. package/src/tools/market/crypto-price.ts +0 -65
  642. package/src/tools/market/screen-stocks.ts +0 -290
  643. package/src/tools/market/search-ticker.ts +0 -254
  644. package/src/tools/market/stock-history.ts +0 -104
  645. package/src/tools/market/stock-quote.ts +0 -73
  646. package/src/tools/options/greeks.ts +0 -81
  647. package/src/tools/options/option-chain.ts +0 -134
  648. package/src/tools/portfolio/alerts.ts +0 -457
  649. package/src/tools/portfolio/correlation.ts +0 -189
  650. package/src/tools/portfolio/daily-report.ts +0 -107
  651. package/src/tools/portfolio/holdings-overlap.ts +0 -139
  652. package/src/tools/portfolio/notifications.ts +0 -45
  653. package/src/tools/portfolio/risk-analysis.ts +0 -173
  654. package/src/tools/portfolio/tracker.ts +0 -308
  655. package/src/tools/portfolio/watchlist.ts +0 -288
  656. package/src/tools/sentiment/insight-format.ts +0 -50
  657. package/src/tools/sentiment/query-match.ts +0 -117
  658. package/src/tools/sentiment/reddit-sentiment.ts +0 -403
  659. package/src/tools/sentiment/sentiment-summary.ts +0 -383
  660. package/src/tools/sentiment/sentiment-trend.ts +0 -75
  661. package/src/tools/sentiment/twitter-sentiment.ts +0 -287
  662. package/src/tools/sentiment/untrusted-text.ts +0 -21
  663. package/src/tools/sentiment/web-search.ts +0 -186
  664. package/src/tools/sentiment/web-sentiment.ts +0 -96
  665. package/src/tools/technical/backtest.ts +0 -336
  666. package/src/tools/technical/indicators.ts +0 -281
  667. package/src/types/fundamentals.ts +0 -47
  668. package/src/types/index.ts +0 -26
  669. package/src/types/macro.ts +0 -27
  670. package/src/types/market.ts +0 -46
  671. package/src/types/options.ts +0 -53
  672. package/src/types/portfolio.ts +0 -83
  673. package/src/types/prediction-markets.ts +0 -13
  674. package/src/types/sentiment.ts +0 -129
  675. package/src/workflows/compare-assets.ts +0 -89
  676. package/src/workflows/index.ts +0 -3
  677. package/src/workflows/options-screener.ts +0 -125
  678. package/src/workflows/portfolio-builder.ts +0 -63
@@ -1,117 +0,0 @@
1
- import { extractEntities } from "../../routing/entity-extractor.js";
2
- import type { SentinelRecord } from "../../sentiment/types.js";
3
-
4
- const STOP_TERMS = new Set([
5
- "about",
6
- "around",
7
- "are",
8
- "from",
9
- "how",
10
- "is",
11
- "latest",
12
- "mood",
13
- "now",
14
- "on",
15
- "or",
16
- "people",
17
- "reddit",
18
- "retail",
19
- "right",
20
- "say",
21
- "saying",
22
- "says",
23
- "sentiment",
24
- "social",
25
- "stock",
26
- "stocks",
27
- "talking",
28
- "the",
29
- "think",
30
- "thinking",
31
- "to",
32
- "tweet",
33
- "tweets",
34
- "twitter",
35
- "what",
36
- "with",
37
- ]);
38
-
39
- export function sentimentQueryTerms(query: string): string[] {
40
- const hasSp500 = /\bs\s*&\s*p\s*500\b/i.test(query) || /\bspx\b/i.test(query);
41
-
42
- const symbols = hasSp500
43
- ? ["sp500"]
44
- : extractEntities(query).symbols.map((symbol) => symbol.toLowerCase());
45
- const punctuationTerms = [...query.toLowerCase().matchAll(/\b([a-z])\s*[&/]\s*([a-z])\b/g)].map(
46
- (match) => `${match[1]}${match[2]}`,
47
- );
48
- const terms = query.toLowerCase().match(/[a-z0-9]{2,}/g);
49
- if (!terms) {
50
- if (punctuationTerms.length > 0) return [...new Set(punctuationTerms)];
51
- const compact = query.toLowerCase().replace(/[^a-z0-9]/g, "");
52
- if (compact.length >= 2) return [compact];
53
- return query.trim().length > 0 ? [query.trim().toLowerCase()] : [];
54
- }
55
-
56
- const stopTerms = hasSp500 ? new Set([...STOP_TERMS, "sp", "spx", "500"]) : STOP_TERMS;
57
- const filtered = [
58
- ...new Set([...punctuationTerms, ...terms.filter((term) => !stopTerms.has(term))]),
59
- ].slice(0, 6);
60
- if (symbols.length > 0) {
61
- return [
62
- ...new Set([
63
- ...symbols,
64
- ...filtered.filter((term) => !symbols.some((symbol) => symbol.startsWith(term))),
65
- ]),
66
- ].slice(0, 6);
67
- }
68
- if (filtered.length > 0) return filtered;
69
- return query.trim().length > 0 ? [query.trim().toLowerCase()] : [];
70
- }
71
-
72
- export function recordMatchesSentimentQuery(
73
- record: SentinelRecord,
74
- terms: readonly string[],
75
- ): boolean {
76
- if (terms.length === 0) return true;
77
- const text = `${record.title ?? ""}\n${record.text}`.toLowerCase();
78
- const textTokens = new Set(text.match(/[a-z0-9]+/g) ?? []);
79
- const metadataTokens = new Set<string>();
80
- const subreddit = record.metadata.subreddit;
81
- if (typeof subreddit === "string") {
82
- metadataTokens.add(subreddit.toLowerCase());
83
- metadataTokens.add(subreddit.toLowerCase().replace(/^r\//, ""));
84
- }
85
- if (/\bs\s*&\s*p\s*500\b/i.test(text) || /\bspx\b/i.test(text)) textTokens.add("sp500");
86
- for (const match of text.matchAll(/\b([a-z])\s*[&/]\s*([a-z])\b/g)) {
87
- textTokens.add(`${match[1]}${match[2]}`);
88
- }
89
- for (const match of text.matchAll(/\b([a-z]{1,5})[.-]([a-z])\b/g)) {
90
- textTokens.add(`${match[1]}${match[2]}`);
91
- }
92
- const tickerTokens = new Set<string>();
93
- for (const ticker of record.sentiment.tickers) {
94
- const normalized = ticker.toLowerCase();
95
- tickerTokens.add(normalized);
96
- tickerTokens.add(normalized.replace(/[^a-z0-9]/g, ""));
97
- }
98
- const matchedTerms = terms.filter(
99
- (term) => tickerTokens.has(term) || textTokens.has(term) || metadataTokens.has(term),
100
- );
101
- for (const term of terms) {
102
- if (matchedTerms.includes(term) || !term.includes(" ")) continue;
103
- if (text.includes(term)) matchedTerms.push(term);
104
- }
105
- for (const term of terms) {
106
- if (matchedTerms.includes(term) || term.length < 4) continue;
107
- if (textTokens.has(`${term}s`)) {
108
- matchedTerms.push(term);
109
- continue;
110
- }
111
- if (term.endsWith("s") && textTokens.has(term.slice(0, -1))) {
112
- matchedTerms.push(term);
113
- }
114
- }
115
- const requiredMatches = terms.length > 1 ? 2 : 1;
116
- return matchedTerms.length >= requiredMatches;
117
- }
@@ -1,403 +0,0 @@
1
- import type { AgentTool } from "@earendil-works/pi-agent-core";
2
- import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
3
- import { Type } from "@sinclair/typebox";
4
- import { getConfig } from "../../config.js";
5
- import { promptUser } from "../../onboarding/prompt-user.js";
6
- import { getProvider } from "../../onboarding/providers.js";
7
- import {
8
- loadOnboardingState,
9
- markProviderNeverAsk,
10
- saveOnboardingState,
11
- } from "../../onboarding/state.js";
12
- import { buildExternalToolRequiredTag, buildSkippedTag } from "../../onboarding/tool-tags.js";
13
- import { getPostComments, getSubredditPosts } from "../../providers/reddit.js";
14
- import { wrapProvider } from "../../providers/wrap-provider.js";
15
- import { RedditAdapter } from "../../sentiment/adapters/reddit.js";
16
- import { getSentimentPipeline } from "../../sentiment/index.js";
17
- import type { AskUserHandler } from "../../types/index.js";
18
- import type { RedditSentimentResult } from "../../types/sentiment.js";
19
- import { formatInsightSection } from "./insight-format.js";
20
- import { recordMatchesSentimentQuery, sentimentQueryTerms } from "./query-match.js";
21
- import { renderUntrustedText, untrustedContentHeader } from "./untrusted-text.js";
22
-
23
- const params = Type.Object({
24
- subreddit: Type.Optional(
25
- Type.String({
26
- description:
27
- "Subreddit name (e.g. wallstreetbets, stocks). If omitted, searches across default subreddits.",
28
- }),
29
- ),
30
- query: Type.Optional(
31
- Type.String({
32
- description:
33
- "Topic or ticker to filter posts by (e.g. AAPL, bitcoin). Searches titles and post bodies.",
34
- }),
35
- ),
36
- subreddits: Type.Optional(
37
- Type.Array(Type.String(), {
38
- description: "Multiple subreddits to search. Overrides single subreddit param.",
39
- }),
40
- ),
41
- limit: Type.Optional(
42
- Type.Number({ description: "Number of posts per subreddit. Default: 25, max: 100" }),
43
- ),
44
- });
45
-
46
- const INSTALL_CONTINUE_LABEL = "Continue after installing Reddit";
47
- const SESSION_CONTINUE_LABEL = "Continue after logging in to Reddit";
48
- const SKIP_ONCE_LABEL = "Skip Reddit once";
49
- const ALWAYS_SKIP_LABEL = "Always skip Reddit";
50
-
51
- interface ExtensionContextWithAskUserHandler extends Partial<ExtensionContext> {
52
- askUserHandler?: AskUserHandler;
53
- }
54
-
55
- interface RedditSentimentToolOptions {
56
- askUserHandler?: AskUserHandler;
57
- }
58
-
59
- type RedditToolDetails = RedditSentimentResult | null;
60
-
61
- export function createRedditSentimentTool(
62
- options: RedditSentimentToolOptions = {},
63
- ): AgentTool<typeof params, RedditToolDetails> {
64
- return {
65
- name: "get_reddit_sentiment",
66
- label: "Reddit Sentiment",
67
- description:
68
- "Analyze sentiment from financial Reddit communities. Supports single subreddit, multi-subreddit, and topic filtering. Returns scored posts with comment analysis and trend context.",
69
- parameters: params,
70
- async execute(_toolCallId, args, _signal, _onUpdate, ctx?: ExtensionContext) {
71
- const limit = Math.min(args.limit ?? 25, 100);
72
- const config = getConfig();
73
- const state = loadOnboardingState();
74
- const descriptor = getProvider("reddit");
75
- if (state.providers.reddit?.status === "never_ask") {
76
- return skippedRedditResult(
77
- "You previously asked not to be reminded about Reddit.",
78
- "run opencandle doctor --enable reddit to re-enable Reddit sentiment (silenced)",
79
- true,
80
- );
81
- }
82
-
83
- // Determine subreddits to search
84
- let subreddits: string[];
85
- if (args.subreddits && args.subreddits.length > 0) {
86
- subreddits = args.subreddits;
87
- } else if (args.subreddit) {
88
- subreddits = [args.subreddit];
89
- } else {
90
- subreddits = config.sentiment?.defaultSubreddits ?? [
91
- "wallstreetbets",
92
- "stocks",
93
- "investing",
94
- "options",
95
- ];
96
- }
97
-
98
- let { allResults, warnings } = await fetchRedditSubreddits(subreddits, limit, args.query);
99
- let retriedAfterContinue = false;
100
- let promptedSetupIssue: ReturnType<typeof classifyRedditSetupIssue> = null;
101
-
102
- if (allResults.length === 0) {
103
- const setupIssue = classifyRedditSetupIssue(warnings);
104
- if (setupIssue) {
105
- promptedSetupIssue = setupIssue;
106
- const askUserHandler =
107
- options.askUserHandler ??
108
- (ctx as ExtensionContextWithAskUserHandler | undefined)?.askUserHandler;
109
- const canAsk = askUserHandler != null || ctx?.hasUI === true;
110
- if (canAsk) {
111
- const promptResult = await promptUser(
112
- (ctx ?? { hasUI: false }) as ExtensionContext,
113
- {
114
- question:
115
- setupIssue === "not_installed"
116
- ? "Reddit sentiment needs the local rdt-cli command before it can fetch discussions. Install command: uv tool install rdt-cli. How would you like to proceed?"
117
- : "Reddit sentiment needs an active Reddit browser session for rdt-cli. Login command: rdt login. How would you like to proceed?",
118
- questionType: "select",
119
- options: [
120
- setupIssue === "not_installed" ? INSTALL_CONTINUE_LABEL : SESSION_CONTINUE_LABEL,
121
- SKIP_ONCE_LABEL,
122
- ALWAYS_SKIP_LABEL,
123
- ],
124
- reason: "Reddit sentiment needs rdt-cli and a Reddit browser session.",
125
- },
126
- askUserHandler,
127
- );
128
-
129
- if (!promptResult.cancelled && promptResult.answer?.startsWith("Continue")) {
130
- retriedAfterContinue = true;
131
- ({ allResults, warnings } = await fetchRedditSubreddits(
132
- subreddits,
133
- limit,
134
- args.query,
135
- ));
136
- } else if (!promptResult.cancelled && promptResult.answer === ALWAYS_SKIP_LABEL) {
137
- saveOnboardingState(markProviderNeverAsk(state, "reddit"));
138
- return skippedRedditResult(
139
- `User chose to always skip ${descriptor.displayName} data. Do not ask about Reddit setup again unless the user explicitly re-enables it.`,
140
- "run opencandle doctor --enable reddit to re-enable Reddit sentiment (silenced)",
141
- true,
142
- );
143
- } else {
144
- return skippedRedditResult(
145
- `User chose to skip ${descriptor.displayName} data for this request. Do not ask about Reddit setup again in this turn.`,
146
- "user chose to skip Reddit for this request",
147
- false,
148
- );
149
- }
150
- }
151
- }
152
- }
153
-
154
- if (allResults.length === 0) {
155
- const setupIssue = classifyRedditSetupIssue(warnings);
156
- if (retriedAfterContinue && (!setupIssue || setupIssue === promptedSetupIssue)) {
157
- return unavailableRedditResult(warnings);
158
- }
159
- if (setupIssue) {
160
- const tag = buildExternalToolRequiredTag({
161
- provider: "reddit",
162
- reason: setupIssue,
163
- installCmd: "uv tool install rdt-cli",
164
- loginCmd: "rdt login",
165
- fallback: "twitter-web-news",
166
- });
167
- const guidance =
168
- setupIssue === "not_installed"
169
- ? "Reddit sentiment requires the local rdt-cli tool. Install it with `uv tool install rdt-cli`, then run `rdt login` if needed."
170
- : "Reddit sentiment requires an active Reddit browser session for rdt-cli. Run `rdt login` or refresh your Reddit browser login.";
171
- return {
172
- content: [{ type: "text", text: `${tag}\n\n${guidance}` }],
173
- details: null,
174
- };
175
- }
176
- return unavailableRedditResult(warnings);
177
- }
178
-
179
- // Merge records returned by the provider. rdt-cli handles query-bearing
180
- // requests server-side; the local filter remains a defensive post-filter.
181
- const adapter = new RedditAdapter();
182
- let allRecords = allResults.flatMap((r) =>
183
- adapter.mapPostsToRecords(r, args.query ?? subreddits.join("+")),
184
- );
185
- const queryTerms = args.query ? sentimentQueryTerms(args.query) : null;
186
-
187
- // Topic filtering
188
- if (queryTerms) {
189
- allRecords = allRecords.filter((record) => recordMatchesSentimentQuery(record, queryTerms));
190
- }
191
-
192
- // Deduplicate by sourceId (crossposts)
193
- const seen = new Set<string>();
194
- allRecords = allRecords.filter((r) => {
195
- if (seen.has(r.sourceId)) return false;
196
- seen.add(r.sourceId);
197
- return true;
198
- });
199
-
200
- // Fetch comments for top 10 posts by engagement
201
- const commentsPerPost = config.sentiment?.commentsPerPost ?? 5;
202
- const topPosts = [...allRecords]
203
- .sort((a, b) => b.engagement.score - a.engagement.score)
204
- .slice(0, 10);
205
-
206
- for (const post of topPosts) {
207
- const sub = (post.metadata.subreddit as string) ?? subreddits[0];
208
- if ((post.engagement.replies ?? 0) === 0) continue;
209
- try {
210
- const comments = await getPostComments(sub, post.sourceId, commentsPerPost);
211
- const commentRecords = adapter.mapCommentsToRecords(
212
- comments,
213
- post.sourceId,
214
- sub,
215
- args.query ?? subreddits.join("+"),
216
- );
217
- allRecords.push(
218
- ...(queryTerms
219
- ? commentRecords.filter((record) => recordMatchesSentimentQuery(record, queryTerms))
220
- : commentRecords),
221
- );
222
- } catch {
223
- // Comment fetch failures are non-fatal
224
- }
225
- }
226
-
227
- // Process through pipeline
228
- const pipeline = getSentimentPipeline();
229
- const pipelineResult = await pipeline.processRecords(
230
- allRecords,
231
- args.query ?? subreddits.join("+"),
232
- );
233
-
234
- // Build output using first result as base for backward compatibility
235
- const firstResult = allResults[0];
236
- const postRecords = pipelineResult.fresh.filter((r) => !r.metadata.isComment);
237
- const commentRecords = pipelineResult.fresh.filter((r) => r.metadata.isComment);
238
- const sentimentRecords = pipelineResult.fresh;
239
- const rawPostsById = new Map(
240
- allResults.flatMap((result) => result.posts.map((post) => [post.id, post] as const)),
241
- );
242
- const aggregatePosts: RedditSentimentResult["posts"] = postRecords.map((record) => {
243
- const rawPost = rawPostsById.get(record.sourceId);
244
- return {
245
- id: record.sourceId,
246
- title: rawPost?.title ?? record.title ?? "",
247
- selftext: rawPost?.selftext ?? "",
248
- author: rawPost?.author ?? record.author ?? "unknown",
249
- score: rawPost?.score ?? record.engagement.score,
250
- comments: rawPost?.comments ?? record.engagement.replies ?? 0,
251
- url: rawPost?.url ?? record.url,
252
- created: rawPost?.created ?? record.publishedAt ?? record.fetchedAt,
253
- };
254
- });
255
- const aggregateTopMentions = [
256
- ...new Set(postRecords.flatMap((record) => record.sentiment.tickers)),
257
- ];
258
- const avgScore =
259
- sentimentRecords.length > 0
260
- ? sentimentRecords.reduce((s, r) => s + r.sentiment.score, 0) / sentimentRecords.length
261
- : 0;
262
-
263
- const sentimentLabel =
264
- avgScore > 0.3
265
- ? "Bullish"
266
- : avgScore < -0.3
267
- ? "Bearish"
268
- : avgScore > 0
269
- ? "Leaning Bullish"
270
- : avgScore < 0
271
- ? "Leaning Bearish"
272
- : "Neutral";
273
-
274
- const subLabel =
275
- subreddits.length === 1 ? `r/${subreddits[0]}` : `${subreddits.length} subreddits`;
276
- const lines = [
277
- `**Reddit: ${args.query ?? subLabel}** — ${postRecords.length} posts, ${commentRecords.length} comments`,
278
- `Sentiment: ${avgScore.toFixed(2)} (${sentimentLabel})`,
279
- ];
280
-
281
- const details: RedditSentimentResult = {
282
- ...firstResult,
283
- subreddit: subreddits.length === 1 ? firstResult.subreddit : subreddits.join(","),
284
- postCount: postRecords.length,
285
- posts: aggregatePosts,
286
- topMentions: aggregateTopMentions,
287
- sentimentScore: avgScore,
288
- bullishCount: sentimentRecords.filter((record) => record.sentiment.score > 0).length,
289
- bearishCount: sentimentRecords.filter((record) => record.sentiment.score < 0).length,
290
- insight: pipelineResult.insight,
291
- records: pipelineResult.fresh,
292
- };
293
-
294
- if (pipelineResult.insight) {
295
- lines.push(...formatInsightSection(pipelineResult.insight));
296
- }
297
-
298
- if (aggregateTopMentions.length > 0) {
299
- lines.push(`Tickers: ${aggregateTopMentions.map((t) => `$${t}`).join(", ")}`);
300
- }
301
-
302
- lines.push("");
303
- lines.push(untrustedContentHeader("Reddit posts"));
304
- for (const post of postRecords.slice(0, 10)) {
305
- const scoreIndicator =
306
- post.sentiment.score > 0 ? "🟢" : post.sentiment.score < 0 ? "🔴" : "⚪";
307
- lines.push(
308
- ` ${scoreIndicator} ⬆${post.engagement.score} 💬${post.engagement.replies ?? 0} — ${renderUntrustedText(post.title ?? post.text, 100)}`,
309
- );
310
- }
311
-
312
- if (pipelineResult.trend && pipelineResult.trend.length > 0) {
313
- const t = pipelineResult.trend[0];
314
- lines.push("");
315
- lines.push(
316
- `Trend: ${t.sparkline} ${t.direction} (${t.delta >= 0 ? "+" : ""}${t.delta.toFixed(2)}, ${t.count} records)`,
317
- );
318
- }
319
-
320
- if (warnings.length > 0) {
321
- lines.push("");
322
- lines.push(`⚠ ${warnings.join("; ")}`);
323
- }
324
-
325
- return { content: [{ type: "text", text: lines.join("\n") }], details };
326
- },
327
- };
328
- }
329
-
330
- export const redditSentimentTool = createRedditSentimentTool();
331
-
332
- function unavailableRedditResult(warnings: readonly string[]): {
333
- content: [{ type: "text"; text: string }];
334
- details: null;
335
- } {
336
- return {
337
- content: [{ type: "text", text: `⚠ Reddit sentiment unavailable (${warnings.join("; ")}).` }],
338
- details: null,
339
- };
340
- }
341
-
342
- async function fetchRedditSubreddits(
343
- subreddits: readonly string[],
344
- limit: number,
345
- query: string | undefined,
346
- ): Promise<{ allResults: RedditSentimentResult[]; warnings: string[] }> {
347
- const allResults: RedditSentimentResult[] = [];
348
- const warnings: string[] = [];
349
- for (const sub of subreddits) {
350
- const providerResult = await wrapProvider("reddit", () => getSubredditPosts(sub, limit, query));
351
- if (providerResult.status === "unavailable") {
352
- warnings.push(`r/${sub}: ${providerResult.reason}`);
353
- continue;
354
- }
355
- allResults.push(providerResult.data);
356
- }
357
- return { allResults, warnings };
358
- }
359
-
360
- function skippedRedditResult(
361
- message: string,
362
- remediation: string,
363
- silenced: boolean,
364
- ): { content: [{ type: "text"; text: string }]; details: null } {
365
- return {
366
- content: [
367
- {
368
- type: "text",
369
- text: `${buildSkippedTag({
370
- provider: "reddit",
371
- reason: "credential_not_provided",
372
- remediation,
373
- silenced,
374
- })}\n\n${message}`,
375
- },
376
- ],
377
- details: null,
378
- };
379
- }
380
-
381
- function classifyRedditSetupIssue(
382
- warnings: readonly string[],
383
- ): "not_installed" | "session_missing" | "session_stale" | null {
384
- const combined = warnings.join("\n").toLowerCase();
385
- if (combined.includes("not installed") || combined.includes("enoent")) {
386
- return "not_installed";
387
- }
388
- if (
389
- combined.includes("no reddit cookies") ||
390
- combined.includes("not authenticated") ||
391
- combined.includes("rdt login")
392
- ) {
393
- return "session_missing";
394
- }
395
- if (
396
- combined.includes("401") ||
397
- combined.includes("unauthorized") ||
398
- combined.includes("expired")
399
- ) {
400
- return "session_stale";
401
- }
402
- return null;
403
- }