opencandle 0.5.0 → 0.7.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 (574) hide show
  1. package/README.md +170 -186
  2. package/dist/analysts/contracts.d.ts +1 -3
  3. package/dist/analysts/contracts.js +1 -11
  4. package/dist/analysts/contracts.js.map +1 -1
  5. package/dist/analysts/orchestrator.d.ts +1 -3
  6. package/dist/analysts/orchestrator.js +1 -26
  7. package/dist/analysts/orchestrator.js.map +1 -1
  8. package/dist/cli.js +66 -7
  9. package/dist/cli.js.map +1 -1
  10. package/dist/config.d.ts +13 -3
  11. package/dist/config.js +25 -5
  12. package/dist/config.js.map +1 -1
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/infra/cache.d.ts +8 -11
  17. package/dist/infra/cache.js +17 -15
  18. package/dist/infra/cache.js.map +1 -1
  19. package/dist/infra/http-client.d.ts +4 -1
  20. package/dist/infra/http-client.js +59 -6
  21. package/dist/infra/http-client.js.map +1 -1
  22. package/dist/infra/index.d.ts +2 -3
  23. package/dist/infra/index.js +2 -3
  24. package/dist/infra/index.js.map +1 -1
  25. package/dist/infra/native-dependencies.js +2 -2
  26. package/dist/infra/native-dependencies.js.map +1 -1
  27. package/dist/infra/node-version.js.map +1 -1
  28. package/dist/infra/opencandle-paths.d.ts +0 -3
  29. package/dist/infra/opencandle-paths.js +4 -11
  30. package/dist/infra/opencandle-paths.js.map +1 -1
  31. package/dist/infra/rate-limiter.js +12 -9
  32. package/dist/infra/rate-limiter.js.map +1 -1
  33. package/dist/market-state/alert-conditions.d.ts +34 -0
  34. package/dist/market-state/alert-conditions.js +23 -0
  35. package/dist/market-state/alert-conditions.js.map +1 -0
  36. package/dist/market-state/alert-runner.d.ts +55 -0
  37. package/dist/market-state/alert-runner.js +634 -0
  38. package/dist/market-state/alert-runner.js.map +1 -0
  39. package/dist/market-state/daily-report.d.ts +26 -0
  40. package/dist/market-state/daily-report.js +179 -0
  41. package/dist/market-state/daily-report.js.map +1 -0
  42. package/dist/market-state/local-automation-service.d.ts +25 -0
  43. package/dist/market-state/local-automation-service.js +119 -0
  44. package/dist/market-state/local-automation-service.js.map +1 -0
  45. package/dist/market-state/notification-delivery.d.ts +14 -0
  46. package/dist/market-state/notification-delivery.js +139 -0
  47. package/dist/market-state/notification-delivery.js.map +1 -0
  48. package/dist/market-state/resolve-for-mutation.d.ts +10 -0
  49. package/dist/market-state/resolve-for-mutation.js +15 -0
  50. package/dist/market-state/resolve-for-mutation.js.map +1 -0
  51. package/dist/market-state/resolve.d.ts +14 -0
  52. package/dist/market-state/resolve.js +89 -0
  53. package/dist/market-state/resolve.js.map +1 -0
  54. package/dist/market-state/service.d.ts +527 -0
  55. package/dist/market-state/service.js +1099 -0
  56. package/dist/market-state/service.js.map +1 -0
  57. package/dist/memory/index.d.ts +7 -7
  58. package/dist/memory/index.js +6 -6
  59. package/dist/memory/index.js.map +1 -1
  60. package/dist/memory/manager.js +11 -11
  61. package/dist/memory/manager.js.map +1 -1
  62. package/dist/memory/retrieval.js +7 -4
  63. package/dist/memory/retrieval.js.map +1 -1
  64. package/dist/memory/sqlite.js +385 -3
  65. package/dist/memory/sqlite.js.map +1 -1
  66. package/dist/memory/storage.js +1 -2
  67. package/dist/memory/storage.js.map +1 -1
  68. package/dist/memory/tool-defaults.js +64 -28
  69. package/dist/memory/tool-defaults.js.map +1 -1
  70. package/dist/memory/types.js.map +1 -1
  71. package/dist/monitor.d.ts +2 -0
  72. package/dist/monitor.js +104 -0
  73. package/dist/monitor.js.map +1 -0
  74. package/dist/onboarding/connect.d.ts +2 -2
  75. package/dist/onboarding/connect.js +13 -8
  76. package/dist/onboarding/connect.js.map +1 -1
  77. package/dist/onboarding/credential-interceptor.js +1 -1
  78. package/dist/onboarding/credential-interceptor.js.map +1 -1
  79. package/dist/onboarding/degradation-accumulator.js +1 -3
  80. package/dist/onboarding/degradation-accumulator.js.map +1 -1
  81. package/dist/onboarding/provider-status.d.ts +48 -0
  82. package/dist/onboarding/provider-status.js +285 -0
  83. package/dist/onboarding/provider-status.js.map +1 -0
  84. package/dist/onboarding/providers.d.ts +85 -8
  85. package/dist/onboarding/providers.js +83 -18
  86. package/dist/onboarding/providers.js.map +1 -1
  87. package/dist/onboarding/state.d.ts +1 -0
  88. package/dist/onboarding/state.js +5 -0
  89. package/dist/onboarding/state.js.map +1 -1
  90. package/dist/onboarding/tool-helpers.js +1 -1
  91. package/dist/onboarding/tool-helpers.js.map +1 -1
  92. package/dist/onboarding/tool-tags.d.ts +12 -1
  93. package/dist/onboarding/tool-tags.js +37 -5
  94. package/dist/onboarding/tool-tags.js.map +1 -1
  95. package/dist/onboarding/validation.d.ts +2 -2
  96. package/dist/onboarding/validation.js +1 -1
  97. package/dist/onboarding/validation.js.map +1 -1
  98. package/dist/pi/opencandle-extension.d.ts +8 -0
  99. package/dist/pi/opencandle-extension.js +502 -42
  100. package/dist/pi/opencandle-extension.js.map +1 -1
  101. package/dist/pi/session.d.ts +1 -1
  102. package/dist/pi/session.js +3 -1
  103. package/dist/pi/session.js.map +1 -1
  104. package/dist/pi/setup.js +8 -3
  105. package/dist/pi/setup.js.map +1 -1
  106. package/dist/pi/tool-adapter.d.ts +4 -1
  107. package/dist/pi/tool-adapter.js +10 -6
  108. package/dist/pi/tool-adapter.js.map +1 -1
  109. package/dist/prompts/context-builder.d.ts +1 -1
  110. package/dist/prompts/context-builder.js +20 -7
  111. package/dist/prompts/context-builder.js.map +1 -1
  112. package/dist/prompts/policy-cards.d.ts +1 -1
  113. package/dist/prompts/policy-cards.js +2 -2
  114. package/dist/prompts/policy-cards.js.map +1 -1
  115. package/dist/prompts/sections.d.ts +1 -1
  116. package/dist/prompts/symbol-preflight.d.ts +20 -0
  117. package/dist/prompts/symbol-preflight.js +49 -0
  118. package/dist/prompts/symbol-preflight.js.map +1 -0
  119. package/dist/prompts/workflow-prompts.d.ts +1 -1
  120. package/dist/prompts/workflow-prompts.js +54 -16
  121. package/dist/prompts/workflow-prompts.js.map +1 -1
  122. package/dist/providers/alpha-vantage.d.ts +1 -1
  123. package/dist/providers/alpha-vantage.js +26 -7
  124. package/dist/providers/alpha-vantage.js.map +1 -1
  125. package/dist/providers/coingecko.js +1 -1
  126. package/dist/providers/coingecko.js.map +1 -1
  127. package/dist/providers/errors.d.ts +5 -0
  128. package/dist/providers/errors.js +11 -0
  129. package/dist/providers/errors.js.map +1 -0
  130. package/dist/providers/exa-search.d.ts +2 -2
  131. package/dist/providers/exa-search.js +19 -11
  132. package/dist/providers/exa-search.js.map +1 -1
  133. package/dist/providers/external-tool-error.d.ts +10 -0
  134. package/dist/providers/external-tool-error.js +21 -0
  135. package/dist/providers/external-tool-error.js.map +1 -0
  136. package/dist/providers/fear-greed.js +1 -1
  137. package/dist/providers/fear-greed.js.map +1 -1
  138. package/dist/providers/finnhub.js +3 -5
  139. package/dist/providers/finnhub.js.map +1 -1
  140. package/dist/providers/fred.js +2 -2
  141. package/dist/providers/fred.js.map +1 -1
  142. package/dist/providers/index.d.ts +7 -6
  143. package/dist/providers/index.js +6 -5
  144. package/dist/providers/index.js.map +1 -1
  145. package/dist/providers/reddit-cli.d.ts +36 -0
  146. package/dist/providers/reddit-cli.js +201 -0
  147. package/dist/providers/reddit-cli.js.map +1 -0
  148. package/dist/providers/reddit.d.ts +1 -1
  149. package/dist/providers/reddit.js +9 -37
  150. package/dist/providers/reddit.js.map +1 -1
  151. package/dist/providers/sec-edgar.d.ts +1 -0
  152. package/dist/providers/sec-edgar.js +12 -4
  153. package/dist/providers/sec-edgar.js.map +1 -1
  154. package/dist/providers/tradingview.d.ts +47 -0
  155. package/dist/providers/tradingview.js +275 -0
  156. package/dist/providers/tradingview.js.map +1 -0
  157. package/dist/providers/twitter-cli.d.ts +40 -0
  158. package/dist/providers/twitter-cli.js +153 -0
  159. package/dist/providers/twitter-cli.js.map +1 -0
  160. package/dist/providers/twitter.d.ts +0 -8
  161. package/dist/providers/twitter.js +8 -60
  162. package/dist/providers/twitter.js.map +1 -1
  163. package/dist/providers/web-search.js +26 -12
  164. package/dist/providers/web-search.js.map +1 -1
  165. package/dist/providers/with-fallback.js +4 -2
  166. package/dist/providers/with-fallback.js.map +1 -1
  167. package/dist/providers/wrap-provider.d.ts +2 -3
  168. package/dist/providers/wrap-provider.js +44 -8
  169. package/dist/providers/wrap-provider.js.map +1 -1
  170. package/dist/providers/yahoo-finance.d.ts +1 -1
  171. package/dist/providers/yahoo-finance.js +153 -48
  172. package/dist/providers/yahoo-finance.js.map +1 -1
  173. package/dist/routing/classify-intent.d.ts +6 -0
  174. package/dist/routing/classify-intent.js +78 -7
  175. package/dist/routing/classify-intent.js.map +1 -1
  176. package/dist/routing/defaults.d.ts +1 -1
  177. package/dist/routing/entity-extractor.d.ts +1 -0
  178. package/dist/routing/entity-extractor.js +234 -29
  179. package/dist/routing/entity-extractor.js.map +1 -1
  180. package/dist/routing/fund-symbols.d.ts +2 -0
  181. package/dist/routing/fund-symbols.js +55 -0
  182. package/dist/routing/fund-symbols.js.map +1 -0
  183. package/dist/routing/horizon.d.ts +1 -0
  184. package/dist/routing/horizon.js +10 -0
  185. package/dist/routing/horizon.js.map +1 -0
  186. package/dist/routing/index.d.ts +10 -10
  187. package/dist/routing/index.js +6 -6
  188. package/dist/routing/index.js.map +1 -1
  189. package/dist/routing/planning.d.ts +2 -2
  190. package/dist/routing/planning.js +65 -34
  191. package/dist/routing/planning.js.map +1 -1
  192. package/dist/routing/route-manifest.d.ts +2 -2
  193. package/dist/routing/route-manifest.js +25 -4
  194. package/dist/routing/route-manifest.js.map +1 -1
  195. package/dist/routing/router-llm-client.js.map +1 -1
  196. package/dist/routing/router-prompt.js +7 -9
  197. package/dist/routing/router-prompt.js.map +1 -1
  198. package/dist/routing/router-types.d.ts +1 -0
  199. package/dist/routing/router.js +137 -22
  200. package/dist/routing/router.js.map +1 -1
  201. package/dist/routing/slot-resolver.d.ts +1 -1
  202. package/dist/routing/slot-resolver.js +2 -4
  203. package/dist/routing/slot-resolver.js.map +1 -1
  204. package/dist/routing/symbol-disambiguator.d.ts +11 -0
  205. package/dist/routing/symbol-disambiguator.js +52 -0
  206. package/dist/routing/symbol-disambiguator.js.map +1 -0
  207. package/dist/routing/turn-context.d.ts +1 -1
  208. package/dist/routing/turn-context.js +1 -1
  209. package/dist/routing/turn-context.js.map +1 -1
  210. package/dist/routing/types.d.ts +2 -0
  211. package/dist/runtime/answer-contracts.d.ts +1 -1
  212. package/dist/runtime/answer-contracts.js +48 -9
  213. package/dist/runtime/answer-contracts.js.map +1 -1
  214. package/dist/runtime/artifact-contracts.js.map +1 -1
  215. package/dist/runtime/planning-evidence.js +47 -26
  216. package/dist/runtime/planning-evidence.js.map +1 -1
  217. package/dist/runtime/prompt-step.d.ts +1 -9
  218. package/dist/runtime/prompt-step.js +0 -10
  219. package/dist/runtime/prompt-step.js.map +1 -1
  220. package/dist/runtime/run-context.d.ts +5 -2
  221. package/dist/runtime/run-context.js +8 -1
  222. package/dist/runtime/run-context.js.map +1 -1
  223. package/dist/runtime/session-coordinator.d.ts +13 -5
  224. package/dist/runtime/session-coordinator.js +160 -20
  225. package/dist/runtime/session-coordinator.js.map +1 -1
  226. package/dist/runtime/session-title.d.ts +14 -0
  227. package/dist/runtime/session-title.js +50 -0
  228. package/dist/runtime/session-title.js.map +1 -0
  229. package/dist/runtime/tool-defaults-wrapper.js +7 -5
  230. package/dist/runtime/tool-defaults-wrapper.js.map +1 -1
  231. package/dist/runtime/validation.js.map +1 -1
  232. package/dist/runtime/workflow-events.js.map +1 -1
  233. package/dist/runtime/workflow-runner.d.ts +3 -3
  234. package/dist/runtime/workflow-runner.js +1 -1
  235. package/dist/runtime/workflow-runner.js.map +1 -1
  236. package/dist/sentiment/adapters/finnhub.d.ts +1 -1
  237. package/dist/sentiment/adapters/finnhub.js +6 -1
  238. package/dist/sentiment/adapters/finnhub.js.map +1 -1
  239. package/dist/sentiment/adapters/reddit.d.ts +2 -2
  240. package/dist/sentiment/adapters/twitter.d.ts +1 -1
  241. package/dist/sentiment/adapters/web.d.ts +1 -1
  242. package/dist/sentiment/index.d.ts +10 -11
  243. package/dist/sentiment/index.js +10 -20
  244. package/dist/sentiment/index.js.map +1 -1
  245. package/dist/sentiment/insights.d.ts +17 -0
  246. package/dist/sentiment/insights.js +206 -0
  247. package/dist/sentiment/insights.js.map +1 -0
  248. package/dist/sentiment/keywords.js +26 -4
  249. package/dist/sentiment/keywords.js.map +1 -1
  250. package/dist/sentiment/pipeline.d.ts +2 -2
  251. package/dist/sentiment/pipeline.js +14 -2
  252. package/dist/sentiment/pipeline.js.map +1 -1
  253. package/dist/sentiment/scorer.d.ts +2 -0
  254. package/dist/sentiment/scorer.js +11 -2
  255. package/dist/sentiment/scorer.js.map +1 -1
  256. package/dist/sentiment/store.d.ts +1 -1
  257. package/dist/sentiment/store.js +1 -1
  258. package/dist/sentiment/store.js.map +1 -1
  259. package/dist/sentiment/trends.d.ts +1 -1
  260. package/dist/sentiment/trends.js.map +1 -1
  261. package/dist/sentiment/types.d.ts +2 -0
  262. package/dist/sentiment/types.js.map +1 -1
  263. package/dist/system-prompt.js +6 -9
  264. package/dist/system-prompt.js.map +1 -1
  265. package/dist/tool-kit.d.ts +7 -7
  266. package/dist/tool-kit.js +4 -4
  267. package/dist/tool-kit.js.map +1 -1
  268. package/dist/tools/fundamentals/company-overview.js +11 -6
  269. package/dist/tools/fundamentals/company-overview.js.map +1 -1
  270. package/dist/tools/fundamentals/comps.js +18 -9
  271. package/dist/tools/fundamentals/comps.js.map +1 -1
  272. package/dist/tools/fundamentals/dcf.js +23 -11
  273. package/dist/tools/fundamentals/dcf.js.map +1 -1
  274. package/dist/tools/fundamentals/earnings.js +8 -3
  275. package/dist/tools/fundamentals/earnings.js.map +1 -1
  276. package/dist/tools/fundamentals/financials.js +8 -3
  277. package/dist/tools/fundamentals/financials.js.map +1 -1
  278. package/dist/tools/fundamentals/sec-filings.js +21 -6
  279. package/dist/tools/fundamentals/sec-filings.js.map +1 -1
  280. package/dist/tools/index.d.ts +27 -20
  281. package/dist/tools/index.js +55 -43
  282. package/dist/tools/index.js.map +1 -1
  283. package/dist/tools/interaction/ask-user.js +15 -3
  284. package/dist/tools/interaction/ask-user.js.map +1 -1
  285. package/dist/tools/macro/fear-greed.js.map +1 -1
  286. package/dist/tools/macro/fred-data.d.ts +1 -1
  287. package/dist/tools/macro/fred-data.js +17 -6
  288. package/dist/tools/macro/fred-data.js.map +1 -1
  289. package/dist/tools/market/crypto-history.js +3 -1
  290. package/dist/tools/market/crypto-history.js.map +1 -1
  291. package/dist/tools/market/crypto-price.js +3 -1
  292. package/dist/tools/market/crypto-price.js.map +1 -1
  293. package/dist/tools/market/screen-stocks.d.ts +18 -0
  294. package/dist/tools/market/screen-stocks.js +252 -0
  295. package/dist/tools/market/screen-stocks.js.map +1 -0
  296. package/dist/tools/market/search-ticker.js +160 -8
  297. package/dist/tools/market/search-ticker.js.map +1 -1
  298. package/dist/tools/market/stock-history.d.ts +2 -2
  299. package/dist/tools/market/stock-history.js +26 -7
  300. package/dist/tools/market/stock-history.js.map +1 -1
  301. package/dist/tools/market/stock-quote.js +5 -3
  302. package/dist/tools/market/stock-quote.js.map +1 -1
  303. package/dist/tools/options/greeks.js +1 -1
  304. package/dist/tools/options/greeks.js.map +1 -1
  305. package/dist/tools/options/option-chain.js +19 -6
  306. package/dist/tools/options/option-chain.js.map +1 -1
  307. package/dist/tools/portfolio/alerts.d.ts +15 -0
  308. package/dist/tools/portfolio/alerts.js +357 -0
  309. package/dist/tools/portfolio/alerts.js.map +1 -0
  310. package/dist/tools/portfolio/correlation.d.ts +1 -1
  311. package/dist/tools/portfolio/correlation.js +33 -13
  312. package/dist/tools/portfolio/correlation.js.map +1 -1
  313. package/dist/tools/portfolio/daily-report.d.ts +8 -0
  314. package/dist/tools/portfolio/daily-report.js +83 -0
  315. package/dist/tools/portfolio/daily-report.js.map +1 -0
  316. package/dist/tools/portfolio/holdings-overlap.js +10 -3
  317. package/dist/tools/portfolio/holdings-overlap.js.map +1 -1
  318. package/dist/tools/portfolio/notifications.d.ts +7 -0
  319. package/dist/tools/portfolio/notifications.js +43 -0
  320. package/dist/tools/portfolio/notifications.js.map +1 -0
  321. package/dist/tools/portfolio/predictions.d.ts +12 -6
  322. package/dist/tools/portfolio/predictions.js +337 -87
  323. package/dist/tools/portfolio/predictions.js.map +1 -1
  324. package/dist/tools/portfolio/risk-analysis.d.ts +1 -1
  325. package/dist/tools/portfolio/risk-analysis.js +45 -6
  326. package/dist/tools/portfolio/risk-analysis.js.map +1 -1
  327. package/dist/tools/portfolio/tracker.d.ts +4 -3
  328. package/dist/tools/portfolio/tracker.js +246 -101
  329. package/dist/tools/portfolio/tracker.js.map +1 -1
  330. package/dist/tools/portfolio/watchlist.d.ts +6 -4
  331. package/dist/tools/portfolio/watchlist.js +208 -108
  332. package/dist/tools/portfolio/watchlist.js.map +1 -1
  333. package/dist/tools/sentiment/insight-format.d.ts +2 -0
  334. package/dist/tools/sentiment/insight-format.js +36 -0
  335. package/dist/tools/sentiment/insight-format.js.map +1 -0
  336. package/dist/tools/sentiment/query-match.d.ts +3 -0
  337. package/dist/tools/sentiment/query-match.js +113 -0
  338. package/dist/tools/sentiment/query-match.js.map +1 -0
  339. package/dist/tools/sentiment/reddit-sentiment.d.ts +12 -1
  340. package/dist/tools/sentiment/reddit-sentiment.js +266 -107
  341. package/dist/tools/sentiment/reddit-sentiment.js.map +1 -1
  342. package/dist/tools/sentiment/sentiment-summary.d.ts +9 -1
  343. package/dist/tools/sentiment/sentiment-summary.js +223 -205
  344. package/dist/tools/sentiment/sentiment-summary.js.map +1 -1
  345. package/dist/tools/sentiment/sentiment-trend.d.ts +1 -1
  346. package/dist/tools/sentiment/sentiment-trend.js +12 -2
  347. package/dist/tools/sentiment/sentiment-trend.js.map +1 -1
  348. package/dist/tools/sentiment/twitter-sentiment.d.ts +11 -1
  349. package/dist/tools/sentiment/twitter-sentiment.js +188 -58
  350. package/dist/tools/sentiment/twitter-sentiment.js.map +1 -1
  351. package/dist/tools/sentiment/untrusted-text.d.ts +2 -0
  352. package/dist/tools/sentiment/untrusted-text.js +17 -0
  353. package/dist/tools/sentiment/untrusted-text.js.map +1 -0
  354. package/dist/tools/sentiment/web-search.js +9 -13
  355. package/dist/tools/sentiment/web-search.js.map +1 -1
  356. package/dist/tools/sentiment/web-sentiment.js +19 -3
  357. package/dist/tools/sentiment/web-sentiment.js.map +1 -1
  358. package/dist/tools/technical/backtest.d.ts +1 -1
  359. package/dist/tools/technical/backtest.js +27 -20
  360. package/dist/tools/technical/backtest.js.map +1 -1
  361. package/dist/tools/technical/indicators.js +23 -5
  362. package/dist/tools/technical/indicators.js.map +1 -1
  363. package/dist/types/index.d.ts +3 -3
  364. package/dist/types/index.js.map +1 -1
  365. package/dist/types/market.d.ts +1 -0
  366. package/dist/types/portfolio.d.ts +14 -4
  367. package/dist/types/sentiment.d.ts +52 -0
  368. package/dist/workflows/compare-assets.d.ts +0 -3
  369. package/dist/workflows/compare-assets.js +20 -11
  370. package/dist/workflows/compare-assets.js.map +1 -1
  371. package/dist/workflows/index.d.ts +3 -4
  372. package/dist/workflows/index.js +3 -3
  373. package/dist/workflows/index.js.map +1 -1
  374. package/dist/workflows/options-screener.d.ts +0 -3
  375. package/dist/workflows/options-screener.js +4 -11
  376. package/dist/workflows/options-screener.js.map +1 -1
  377. package/dist/workflows/portfolio-builder.d.ts +0 -3
  378. package/dist/workflows/portfolio-builder.js +0 -8
  379. package/dist/workflows/portfolio-builder.js.map +1 -1
  380. package/gui/server/ask-user-bridge.ts +1 -1
  381. package/gui/server/automation-heartbeat.ts +97 -0
  382. package/gui/server/background-quotes.ts +97 -1
  383. package/gui/server/chat-event-adapter.ts +32 -10
  384. package/gui/server/chat-run-session.ts +16 -0
  385. package/gui/server/invoke-tool.ts +160 -3
  386. package/gui/server/live-chat-event-adapter.ts +21 -6
  387. package/gui/server/market-state-api.ts +315 -0
  388. package/gui/server/model-setup.ts +156 -2
  389. package/gui/server/private-api-access.ts +62 -0
  390. package/gui/server/projector.ts +18 -9
  391. package/gui/server/prompt-observation.ts +4 -7
  392. package/gui/server/quote-snapshot-store.ts +50 -0
  393. package/gui/server/server.ts +218 -451
  394. package/gui/server/session-actions.ts +186 -1
  395. package/gui/server/shutdown.ts +47 -0
  396. package/gui/server/tool-invoke-ack.ts +49 -0
  397. package/gui/server/tool-metadata.ts +101 -24
  398. package/gui/server/websocket.ts +13 -3
  399. package/gui/server/writer-lock.ts +6 -2
  400. package/gui/server/ws-hub.ts +311 -0
  401. package/gui/shared/chat-events.ts +16 -1
  402. package/gui/shared/event-reducer.ts +24 -6
  403. package/gui/web/dist/assets/CatalogOverlay-CgeY5Pkp.js +1 -0
  404. package/gui/web/dist/assets/index-C6W_2eAn.js +69 -0
  405. package/gui/web/dist/assets/index-hwbx24a5.css +1 -0
  406. package/gui/web/dist/index.html +2 -2
  407. package/package.json +9 -6
  408. package/src/analysts/contracts.ts +10 -23
  409. package/src/analysts/orchestrator.ts +8 -43
  410. package/src/cli.ts +76 -12
  411. package/src/config.ts +44 -9
  412. package/src/index.ts +1 -1
  413. package/src/infra/cache.ts +41 -30
  414. package/src/infra/http-client.ts +72 -6
  415. package/src/infra/index.ts +6 -10
  416. package/src/infra/native-dependencies.ts +8 -3
  417. package/src/infra/node-version.ts +3 -1
  418. package/src/infra/opencandle-paths.ts +3 -14
  419. package/src/infra/rate-limiter.ts +22 -19
  420. package/src/market-state/alert-conditions.ts +82 -0
  421. package/src/market-state/alert-runner.ts +863 -0
  422. package/src/market-state/daily-report.ts +247 -0
  423. package/src/market-state/local-automation-service.ts +162 -0
  424. package/src/market-state/notification-delivery.ts +158 -0
  425. package/src/market-state/resolve-for-mutation.ts +24 -0
  426. package/src/market-state/resolve.ts +112 -0
  427. package/src/market-state/service.ts +2344 -0
  428. package/src/memory/index.ts +7 -7
  429. package/src/memory/manager.ts +14 -16
  430. package/src/memory/retrieval.ts +8 -7
  431. package/src/memory/sqlite.ts +407 -6
  432. package/src/memory/storage.ts +5 -15
  433. package/src/memory/tool-defaults.ts +60 -39
  434. package/src/memory/types.ts +3 -3
  435. package/src/monitor.ts +121 -0
  436. package/src/onboarding/connect.ts +24 -31
  437. package/src/onboarding/credential-interceptor.ts +3 -15
  438. package/src/onboarding/degradation-accumulator.ts +1 -3
  439. package/src/onboarding/provider-status.ts +410 -0
  440. package/src/onboarding/providers.ts +144 -45
  441. package/src/onboarding/state.ts +13 -15
  442. package/src/onboarding/tool-helpers.ts +2 -9
  443. package/src/onboarding/tool-tags.ts +51 -8
  444. package/src/onboarding/validation.ts +16 -22
  445. package/src/pi/opencandle-extension.ts +643 -101
  446. package/src/pi/session.ts +7 -5
  447. package/src/pi/setup.ts +61 -43
  448. package/src/pi/tool-adapter.ts +19 -6
  449. package/src/prompts/context-builder.ts +24 -13
  450. package/src/prompts/policy-cards.ts +3 -3
  451. package/src/prompts/sections.ts +1 -1
  452. package/src/prompts/symbol-preflight.ts +80 -0
  453. package/src/prompts/workflow-prompts.ts +77 -28
  454. package/src/providers/alpha-vantage.ts +58 -39
  455. package/src/providers/coingecko.ts +2 -5
  456. package/src/providers/errors.ts +9 -0
  457. package/src/providers/exa-search.ts +24 -22
  458. package/src/providers/external-tool-error.ts +20 -0
  459. package/src/providers/fear-greed.ts +1 -1
  460. package/src/providers/finnhub.ts +7 -6
  461. package/src/providers/fred.ts +3 -3
  462. package/src/providers/index.ts +14 -6
  463. package/src/providers/reddit-cli.ts +317 -0
  464. package/src/providers/reddit.ts +14 -59
  465. package/src/providers/sec-edgar.ts +20 -6
  466. package/src/providers/tradingview.ts +399 -0
  467. package/src/providers/twitter-cli.ts +233 -0
  468. package/src/providers/twitter.ts +8 -79
  469. package/src/providers/web-search.ts +30 -20
  470. package/src/providers/with-fallback.ts +8 -7
  471. package/src/providers/wrap-provider.ts +49 -10
  472. package/src/providers/yahoo-finance.ts +204 -66
  473. package/src/routing/classify-intent.ts +101 -10
  474. package/src/routing/defaults.ts +1 -1
  475. package/src/routing/entity-extractor.ts +287 -38
  476. package/src/routing/fund-symbols.ts +58 -0
  477. package/src/routing/horizon.ts +7 -0
  478. package/src/routing/index.ts +48 -48
  479. package/src/routing/planning.ts +145 -53
  480. package/src/routing/route-manifest.ts +37 -15
  481. package/src/routing/router-llm-client.ts +4 -4
  482. package/src/routing/router-prompt.ts +15 -19
  483. package/src/routing/router-types.ts +2 -5
  484. package/src/routing/router.ts +251 -53
  485. package/src/routing/slot-resolver.ts +34 -11
  486. package/src/routing/symbol-disambiguator.ts +72 -0
  487. package/src/routing/turn-context.ts +6 -9
  488. package/src/routing/types.ts +2 -0
  489. package/src/runtime/answer-contracts.ts +105 -45
  490. package/src/runtime/artifact-contracts.ts +2 -1
  491. package/src/runtime/planning-evidence.ts +157 -66
  492. package/src/runtime/prompt-step.ts +1 -16
  493. package/src/runtime/run-context.ts +12 -2
  494. package/src/runtime/session-coordinator.ts +238 -63
  495. package/src/runtime/session-title.ts +60 -0
  496. package/src/runtime/tool-defaults-wrapper.ts +13 -5
  497. package/src/runtime/validation.ts +1 -4
  498. package/src/runtime/workflow-events.ts +7 -7
  499. package/src/runtime/workflow-runner.ts +5 -11
  500. package/src/sentiment/adapters/finnhub.ts +7 -2
  501. package/src/sentiment/adapters/reddit.ts +2 -2
  502. package/src/sentiment/adapters/twitter.ts +1 -1
  503. package/src/sentiment/adapters/web.ts +1 -1
  504. package/src/sentiment/index.ts +17 -26
  505. package/src/sentiment/insights.ts +269 -0
  506. package/src/sentiment/keywords.ts +26 -4
  507. package/src/sentiment/pipeline.ts +28 -5
  508. package/src/sentiment/scorer.ts +13 -2
  509. package/src/sentiment/store.ts +2 -2
  510. package/src/sentiment/trends.ts +9 -3
  511. package/src/sentiment/types.ts +8 -4
  512. package/src/system-prompt.ts +6 -9
  513. package/src/tool-kit.ts +10 -9
  514. package/src/tools/fundamentals/company-overview.ts +19 -9
  515. package/src/tools/fundamentals/comps.ts +68 -55
  516. package/src/tools/fundamentals/dcf.ts +145 -95
  517. package/src/tools/fundamentals/earnings.ts +16 -6
  518. package/src/tools/fundamentals/financials.ts +16 -7
  519. package/src/tools/fundamentals/sec-filings.ts +37 -16
  520. package/src/tools/index.ts +56 -43
  521. package/src/tools/interaction/ask-user.ts +22 -10
  522. package/src/tools/macro/fear-greed.ts +1 -1
  523. package/src/tools/macro/fred-data.ts +58 -46
  524. package/src/tools/market/crypto-history.ts +8 -3
  525. package/src/tools/market/crypto-price.ts +6 -6
  526. package/src/tools/market/screen-stocks.ts +279 -0
  527. package/src/tools/market/search-ticker.ts +218 -17
  528. package/src/tools/market/stock-history.ts +37 -12
  529. package/src/tools/market/stock-quote.ts +10 -7
  530. package/src/tools/options/greeks.ts +5 -5
  531. package/src/tools/options/option-chain.ts +41 -17
  532. package/src/tools/portfolio/alerts.ts +457 -0
  533. package/src/tools/portfolio/correlation.ts +47 -20
  534. package/src/tools/portfolio/daily-report.ts +101 -0
  535. package/src/tools/portfolio/holdings-overlap.ts +31 -15
  536. package/src/tools/portfolio/notifications.ts +45 -0
  537. package/src/tools/portfolio/predictions.ts +406 -106
  538. package/src/tools/portfolio/risk-analysis.ts +46 -7
  539. package/src/tools/portfolio/tracker.ts +270 -109
  540. package/src/tools/portfolio/watchlist.ts +250 -121
  541. package/src/tools/sentiment/insight-format.ts +50 -0
  542. package/src/tools/sentiment/query-match.ts +117 -0
  543. package/src/tools/sentiment/reddit-sentiment.ts +360 -121
  544. package/src/tools/sentiment/sentiment-summary.ts +302 -235
  545. package/src/tools/sentiment/sentiment-trend.ts +24 -7
  546. package/src/tools/sentiment/twitter-sentiment.ts +264 -73
  547. package/src/tools/sentiment/untrusted-text.ts +21 -0
  548. package/src/tools/sentiment/web-search.ts +21 -18
  549. package/src/tools/sentiment/web-sentiment.ts +30 -10
  550. package/src/tools/technical/backtest.ts +32 -22
  551. package/src/tools/technical/indicators.ts +39 -14
  552. package/src/types/index.ts +8 -3
  553. package/src/types/market.ts +1 -0
  554. package/src/types/portfolio.ts +14 -4
  555. package/src/types/sentiment.ts +61 -2
  556. package/src/workflows/compare-assets.ts +33 -21
  557. package/src/workflows/index.ts +3 -4
  558. package/src/workflows/options-screener.ts +27 -29
  559. package/src/workflows/portfolio-builder.ts +34 -27
  560. package/dist/infra/browser.d.ts +0 -35
  561. package/dist/infra/browser.js +0 -103
  562. package/dist/infra/browser.js.map +0 -1
  563. package/dist/tools/interaction/twitter-login.d.ts +0 -8
  564. package/dist/tools/interaction/twitter-login.js +0 -77
  565. package/dist/tools/interaction/twitter-login.js.map +0 -1
  566. package/dist/workflows/types.d.ts +0 -4
  567. package/dist/workflows/types.js +0 -2
  568. package/dist/workflows/types.js.map +0 -1
  569. package/gui/web/dist/assets/CatalogOverlay-Bmp6Knu7.js +0 -1
  570. package/gui/web/dist/assets/index-Bxt9QpLX.css +0 -1
  571. package/gui/web/dist/assets/index-CZ9DHZYy.js +0 -67
  572. package/src/infra/browser.ts +0 -111
  573. package/src/tools/interaction/twitter-login.ts +0 -93
  574. package/src/workflows/types.ts +0 -4
package/src/pi/session.ts CHANGED
@@ -1,17 +1,17 @@
1
1
  import "../infra/node-version.js";
2
2
  import {
3
3
  type AuthStorage,
4
+ type CreateAgentSessionResult,
4
5
  createAgentSession,
5
6
  DefaultResourceLoader,
7
+ getAgentDir,
6
8
  type ModelRegistry,
7
- type CreateAgentSessionResult,
8
- type SettingsManager,
9
9
  type SessionManager,
10
- getAgentDir,
10
+ type SettingsManager,
11
11
  } from "@earendil-works/pi-coding-agent";
12
12
  import { loadEnv } from "../config.js";
13
- import openCandleExtension from "./opencandle-extension.js";
14
13
  import type { AskUserHandler } from "../types/index.js";
14
+ import openCandleExtension from "./opencandle-extension.js";
15
15
 
16
16
  export interface CreateOpenCandleSessionOptions {
17
17
  cwd?: string;
@@ -38,7 +38,9 @@ export async function createOpenCandleSession(
38
38
  cwd,
39
39
  agentDir,
40
40
  settingsManager: options.settingsManager,
41
- extensionFactories: [(pi) => openCandleExtension(pi, { askUserHandler: options.askUserHandler })],
41
+ extensionFactories: [
42
+ (pi) => openCandleExtension(pi, { askUserHandler: options.askUserHandler }),
43
+ ],
42
44
  })
43
45
  : undefined;
44
46
 
package/src/pi/setup.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import type { Model } from "@earendil-works/pi-ai";
2
2
  import {
3
- LoginDialogComponent,
4
3
  type ExtensionAPI,
5
4
  type ExtensionContext,
5
+ LoginDialogComponent,
6
6
  } from "@earendil-works/pi-coding-agent";
7
7
 
8
8
  type SetupMode = "startup" | "manual";
@@ -54,14 +54,18 @@ function getAvailableModels(ctx: ExtensionContext, preferredProvider?: string):
54
54
  return sortModels(ctx.modelRegistry.getAvailable(), preferredProvider);
55
55
  }
56
56
 
57
- export function getLlmSetupRequirement(ctx: Pick<ExtensionContext, "model" | "modelRegistry">): SetupRequirement {
57
+ export function getLlmSetupRequirement(
58
+ ctx: Pick<ExtensionContext, "model" | "modelRegistry">,
59
+ ): SetupRequirement {
58
60
  if (ctx.model && ctx.modelRegistry.hasConfiguredAuth(ctx.model)) {
59
61
  return "ready";
60
62
  }
61
63
  return ctx.modelRegistry.getAvailable().length > 0 ? "select_model" : "connect_auth";
62
64
  }
63
65
 
64
- async function selectProviderForApiKey(ctx: ExtensionContext): Promise<ApiKeyProviderId | undefined> {
66
+ async function selectProviderForApiKey(
67
+ ctx: ExtensionContext,
68
+ ): Promise<ApiKeyProviderId | undefined> {
65
69
  const choice = await ctx.ui.select("Connect an AI model", [
66
70
  "Google Gemini API",
67
71
  "OpenAI API",
@@ -79,7 +83,9 @@ async function selectProviderForApiKey(ctx: ExtensionContext): Promise<ApiKeyPro
79
83
  }
80
84
  }
81
85
 
82
- async function selectProviderForLogin(ctx: ExtensionContext): Promise<OAuthProviderChoice | undefined> {
86
+ async function selectProviderForLogin(
87
+ ctx: ExtensionContext,
88
+ ): Promise<OAuthProviderChoice | undefined> {
83
89
  const choice = await ctx.ui.select("Connect an AI model", [
84
90
  "Google",
85
91
  "OpenAI",
@@ -112,7 +118,9 @@ async function selectAdvancedOAuthProvider(ctx: ExtensionContext): Promise<strin
112
118
  }
113
119
 
114
120
  async function runLoginDialog(ctx: ExtensionContext, providerId: string): Promise<boolean> {
115
- const provider = ctx.modelRegistry.authStorage.getOAuthProviders().find((item) => item.id === providerId);
121
+ const provider = ctx.modelRegistry.authStorage
122
+ .getOAuthProviders()
123
+ .find((item) => item.id === providerId);
116
124
  const providerName = provider?.name ?? providerId;
117
125
  const usesCallbackServer = provider?.usesCallbackServer ?? false;
118
126
 
@@ -136,43 +144,49 @@ async function runLoginDialog(ctx: ExtensionContext, providerId: string): Promis
136
144
  });
137
145
 
138
146
  // Cast required: advanced providers return dynamic IDs outside the SDK's static union type
139
- void ctx.modelRegistry.authStorage.login(providerId as any, {
140
- onAuth: (info) => {
141
- dialog.showAuth(info.url, info.instructions);
142
- if (usesCallbackServer) {
143
- void dialog
144
- .showManualInput("Paste redirect URL below, or complete login in your browser:")
145
- .then((value) => {
146
- if (value && manualCodeResolve) {
147
- manualCodeResolve(value);
148
- manualCodeResolve = undefined;
149
- }
150
- })
151
- .catch(() => {
152
- if (manualCodeReject) {
153
- manualCodeReject(new Error("Login cancelled"));
154
- manualCodeReject = undefined;
155
- }
156
- });
157
- } else if (providerId === "github-copilot") {
158
- dialog.showWaiting("Waiting for browser authentication...");
159
- }
160
- },
161
- onDeviceCode: (info) => {
162
- dialog.showDeviceCode(info);
163
- dialog.showWaiting("Waiting for authentication...");
164
- },
165
- onPrompt: async (prompt) => dialog.showPrompt(prompt.message, prompt.placeholder),
166
- onProgress: (message) => dialog.showProgress(message),
167
- onSelect: async (prompt) => {
168
- const options = prompt.options.map((option, index) => `${index + 1}. ${option.label}`).join("\n");
169
- const answer = await dialog.showPrompt(`${prompt.message}\n\n${options}`, "Enter a number");
170
- const selectedIndex = Number.parseInt(answer.trim(), 10) - 1;
171
- return prompt.options[selectedIndex]?.id;
172
- },
173
- onManualCodeInput: () => manualCodePromise,
174
- signal: dialog.signal,
175
- })
147
+ void ctx.modelRegistry.authStorage
148
+ .login(providerId as any, {
149
+ onAuth: (info) => {
150
+ dialog.showAuth(info.url, info.instructions);
151
+ if (usesCallbackServer) {
152
+ void dialog
153
+ .showManualInput("Paste redirect URL below, or complete login in your browser:")
154
+ .then((value) => {
155
+ if (value && manualCodeResolve) {
156
+ manualCodeResolve(value);
157
+ manualCodeResolve = undefined;
158
+ }
159
+ })
160
+ .catch(() => {
161
+ if (manualCodeReject) {
162
+ manualCodeReject(new Error("Login cancelled"));
163
+ manualCodeReject = undefined;
164
+ }
165
+ });
166
+ } else if (providerId === "github-copilot") {
167
+ dialog.showWaiting("Waiting for browser authentication...");
168
+ }
169
+ },
170
+ onDeviceCode: (info) => {
171
+ dialog.showDeviceCode(info);
172
+ dialog.showWaiting("Waiting for authentication...");
173
+ },
174
+ onPrompt: async (prompt) => dialog.showPrompt(prompt.message, prompt.placeholder),
175
+ onProgress: (message) => dialog.showProgress(message),
176
+ onSelect: async (prompt) => {
177
+ const options = prompt.options
178
+ .map((option, index) => `${index + 1}. ${option.label}`)
179
+ .join("\n");
180
+ const answer = await dialog.showPrompt(
181
+ `${prompt.message}\n\n${options}`,
182
+ "Enter a number",
183
+ );
184
+ const selectedIndex = Number.parseInt(answer.trim(), 10) - 1;
185
+ return prompt.options[selectedIndex]?.id;
186
+ },
187
+ onManualCodeInput: () => manualCodePromise,
188
+ signal: dialog.signal,
189
+ })
176
190
  .then(() => finish(true))
177
191
  .catch((error) => {
178
192
  const message = error instanceof Error ? error.message : String(error);
@@ -248,7 +262,11 @@ async function activateDefaultModel(
248
262
  return true;
249
263
  }
250
264
 
251
- async function selectModel(api: ExtensionAPI, ctx: ExtensionContext, preferredProvider?: string): Promise<boolean> {
265
+ async function selectModel(
266
+ api: ExtensionAPI,
267
+ ctx: ExtensionContext,
268
+ preferredProvider?: string,
269
+ ): Promise<boolean> {
252
270
  const models = getAvailableModels(ctx, preferredProvider);
253
271
  if (models.length === 0) {
254
272
  ctx.ui.notify("No available models found yet. Connect a provider first.", "warning");
@@ -1,9 +1,10 @@
1
1
  import type { AgentTool } from "@earendil-works/pi-agent-core";
2
2
  import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
3
3
  import type { TSchema } from "@sinclair/typebox";
4
- import { getAllTools } from "../tools/index.js";
5
4
  import { getDefaults } from "../memory/tool-defaults.js";
6
5
  import { wrapWithDefaults } from "../runtime/tool-defaults-wrapper.js";
6
+ import { getAllTools } from "../tools/index.js";
7
+ import type { AskUserHandler } from "../types/index.js";
7
8
 
8
9
  export function agentToolToPiTool<TParams extends TSchema, TDetails>(
9
10
  tool: AgentTool<TParams, TDetails>,
@@ -14,17 +15,29 @@ export function agentToolToPiTool<TParams extends TSchema, TDetails>(
14
15
  description: tool.description,
15
16
  promptSnippet: `${tool.name}: ${tool.description}`,
16
17
  parameters: tool.parameters,
17
- execute: async (toolCallId, params, signal, onUpdate) => {
18
- return tool.execute(toolCallId, params, signal, onUpdate);
18
+ execute: async (toolCallId, params, signal, onUpdate, ctx) => {
19
+ const executeWithContext = tool.execute as unknown as (
20
+ id: string,
21
+ params: unknown,
22
+ signal: AbortSignal | undefined,
23
+ onUpdate: unknown,
24
+ ctx: unknown,
25
+ ) => ReturnType<typeof tool.execute>;
26
+ return executeWithContext(toolCallId, params, signal, onUpdate, ctx);
19
27
  },
20
28
  };
21
29
  }
22
30
 
23
- export function getOpenCandleToolDefinitions(): ToolDefinition[] {
24
- return getAllTools()
31
+ export function getOpenCandleToolDefinitions(
32
+ options: { askUserHandler?: AskUserHandler } = {},
33
+ ): ToolDefinition[] {
34
+ return getAllTools(options)
25
35
  .map((tool) => ({ tool, defaults: safeGetDefaults(tool.name) }))
26
36
  .filter(({ defaults }) => defaults.__enabled !== false)
27
- .map(({ tool, defaults }) => agentToolToPiTool(wrapWithDefaults(tool, defaults)));
37
+ .map(({ tool, defaults }) => {
38
+ const { __enabled: _enabled, ...paramDefaults } = defaults;
39
+ return agentToolToPiTool(wrapWithDefaults(tool, paramDefaults));
40
+ });
28
41
  }
29
42
 
30
43
  function safeGetDefaults(toolName: string): Record<string, unknown> {
@@ -1,7 +1,7 @@
1
- import type { PromptSection, SectionName } from "./sections.js";
2
- import { SECTION_ORDER, DEFAULT_BUDGETS, truncateTobudget } from "./sections.js";
3
- import { renderPolicyCardForPlanning } from "./policy-cards.js";
4
1
  import type { ResolvedTurnContext } from "../routing/turn-context.js";
2
+ import { renderPolicyCardForPlanning } from "./policy-cards.js";
3
+ import type { PromptSection, SectionName } from "./sections.js";
4
+ import { DEFAULT_BUDGETS, SECTION_ORDER, truncateTobudget } from "./sections.js";
5
5
 
6
6
  export interface PromptSectionReport {
7
7
  name: SectionName;
@@ -122,10 +122,7 @@ export class PromptContextBuilder {
122
122
  policyCard ? `${policyCard}\n\n${routePlaybook}` : routePlaybook,
123
123
  );
124
124
  } else if (options.fallbackContext) {
125
- this.setSection(
126
- "workflow-instructions",
127
- buildFallbackPlaybook(options.fallbackContext),
128
- );
125
+ this.setSection("workflow-instructions", buildFallbackPlaybook(options.fallbackContext));
129
126
  }
130
127
  if (options.memoryContext) {
131
128
  this.setSection("memory-context", formatMemorySection(options.memoryContext));
@@ -150,12 +147,26 @@ export function buildFallbackPlaybook(ctx: FallbackContext): string {
150
147
 
151
148
  export function buildRoutePlaybook(ctx: ResolvedTurnContext): string {
152
149
  const assumptionsBlock = buildResolvedAssumptionsBlock(ctx);
150
+ const droppedSymbols = ctx.diagnostics
151
+ .filter((diagnostic) => diagnostic.code === "symbol_dropped")
152
+ .map((diagnostic) => diagnostic.details?.token)
153
+ .filter((token): token is string => typeof token === "string" && token.length > 0);
154
+ const dropContext =
155
+ droppedSymbols.length > 0
156
+ ? `Dropped ambiguous ticker-like tokens: ${droppedSymbols.join(", ")}.`
157
+ : undefined;
158
+ const extraContext = [
159
+ ctx.entities.symbols.length > 0
160
+ ? `Router-extracted symbols: ${ctx.entities.symbols.join(", ")}. Route kind: ${ctx.routeKind}. Tool bundles: ${ctx.toolBundles.join(", ") || "(none)"}.`
161
+ : `Route kind: ${ctx.routeKind}. Tool bundles: ${ctx.toolBundles.join(", ") || "(none)"}.`,
162
+ dropContext,
163
+ ]
164
+ .filter((part): part is string => Boolean(part))
165
+ .join(" ");
153
166
  const fallbackContext: FallbackContext = {
154
167
  assumptionsBlock,
155
168
  missingRequired: ctx.missingRequired,
156
- extraContext: ctx.entities.symbols.length > 0
157
- ? `Router-extracted symbols: ${ctx.entities.symbols.join(", ")}. Route kind: ${ctx.routeKind}. Tool bundles: ${ctx.toolBundles.join(", ") || "(none)"}.`
158
- : `Route kind: ${ctx.routeKind}. Tool bundles: ${ctx.toolBundles.join(", ") || "(none)"}.`,
169
+ extraContext,
159
170
  };
160
171
 
161
172
  if (ctx.routeKind === "clarification") {
@@ -240,7 +251,7 @@ const SAFETY_RULES = `## Guidelines
240
251
  - For crypto position-sizing prompts, start with a concrete allocation range and dollar amount, then show drawdown impact on the user's portfolio, a sleep test, dollar-cost averaging, rebalancing rules, position caps, tax tracking, reputable custody/exchange considerations, and emergency-fund/high-interest-debt prerequisites. Cite the crypto tool-output date or history period and label sparse or unavailable history instead of implying unsupported precision.
241
252
  - For rate-cut market-pricing questions, use get_economic_data for the current Fed funds backdrop and search_web for CME FedWatch / Federal Funds futures probabilities before naming what the market is pricing. Distinguish historical Fed rates from futures-implied expectations.
242
253
  - For backtest_strategy results, report strategy return, buy-and-hold return, outperformance, trade count, win rate, and max drawdown. Include risk-adjusted metrics such as Sharpe or Sortino when available; otherwise say they were unavailable. Explain why the strategy worked or failed in the tested regime and discuss trading costs/slippage when the user asks whether the edge is practical. Do not reduce a backtest answer to return-only.
243
- - For sentiment-only prompts, final answer must include the direction and strength of the sentiment signal, the score scale when available, missing sources, why those missing sources matter for the user's question, the source-coverage risk, low sample counts, and how those gaps downgrade confidence. For ticker-specific sentiment prompts, call get_stock_quote before the final answer and state whether sentiment diverges from price action.
254
+ - For sentiment-only prompts, final answer must include the direction and strength of the sentiment signal, the score scale when available, the key positive and negative drivers behind the signal, representative source evidence, missing sources, why those missing sources matter for the user's question, the source-coverage risk, low sample counts, and how those gaps downgrade confidence. For ticker-specific sentiment prompts, call get_stock_quote before the final answer and state whether sentiment diverges from price action; if quote data is unavailable, say price-action divergence could not be evaluated.
244
255
  - Commit to specifics when asked for entries, targets, stops, allocations, or position sizes. Refusal is not an acceptable output shape.
245
256
  - Each committal response carries FOUR things: the specific number or range, a reasoning chain naming the data points you used, a confidence band, and an invalidation level (what would break the thesis).
246
257
  - Conceptual education prompts are not committal responses. Do not append "Analyst View", "Commitment", "Reasoning Chain", "Confidence Band", or "Invalidation Level" sections when the user asked for an explanation, definition, or learning framework rather than a trade, allocation, or recommendation.
@@ -273,14 +284,14 @@ Keep questions concise and offer specific options when possible. Prefer select-t
273
284
  CRITICAL: After ask_user answers come back, your NEXT action MUST be tool calls — not a text response. You are a data agent, not a chatbot. Never respond with generic investment categories or tell the user to come back with tickers. YOU pick the relevant assets and indicators based on what you learned, then fetch the data.`;
274
285
 
275
286
  const TOOL_CATALOG = `## Available Tools
276
- - **Market Data**: get_stock_quote, get_stock_history, get_crypto_price, get_crypto_history — real-time and historical price data
287
+ - **Market Data**: screen_stocks, get_stock_quote, get_stock_history, get_crypto_price, get_crypto_history — use screen_stocks for breadth and screening prompts such as large-cap lists, oversold stocks, market movers, and filtered market scans; use get_stock_quote/get_stock_history for a single-security quote or historical OHLCV
277
288
  - **Fundamentals**: get_company_overview, get_financials, get_earnings, compute_dcf, compare_companies, get_sec_filings — company financials, valuation metrics, DCF intrinsic value, peer comparison, and SEC EDGAR filings (10-K, 10-Q, 8-K)
278
289
  - **Technical Analysis**: get_technical_indicators, backtest_strategy — SMA, EMA, RSI, MACD, Bollinger Bands, OBV, VWAP computed from price data, plus simple strategy backtesting
279
290
  - **Macro**: get_economic_data, get_fear_greed — FRED economic indicators and market sentiment
280
291
  - **Sentiment**: get_reddit_sentiment, get_twitter_sentiment, get_web_sentiment, get_sentiment_trend, get_sentiment_summary — retail and news sentiment from Reddit, Twitter/X, and web sources with historical trends and cross-source divergence detection
281
292
  - **Web Search**: search_web — breaking news, earnings context, company events, regulatory developments. Supported freshness values are hours, day, week, and month; use category general with freshness month for broad industry context; never pass unsupported values such as all, year, 3mo, quarter, or custom date ranges. When a dedicated tool can answer the question (quotes, fundamentals, earnings, macro, SEC filings, sentiment), use that tool instead — do not add search_web as a supplementary source for data available through dedicated tools
282
293
  - **Options**: get_option_chain — full options chain with strikes, bids/asks, volume, OI, IV, and computed Greeks (delta, gamma, theta, vega, rho)
283
- - **Portfolio**: track_portfolio, analyze_risk, manage_watchlist, analyze_correlation, analyze_holdings_overlap, track_prediction — position tracking, P&L, Sharpe ratio, VaR, watchlist with price alerts, correlation matrix, ETF/fund holdings overlap, and prediction tracking with accuracy scoring
294
+ - **Portfolio**: track_portfolio, analyze_risk, manage_watchlist, analyze_correlation, analyze_holdings_overlap, track_prediction, manage_alerts, daily_watchlist_report, manage_notifications — position tracking, P&L, Sharpe ratio, VaR, watchlist tracking, durable local alerts, daily watchlist reports, notification history, correlation matrix, ETF/fund holdings overlap, and prediction tracking with accuracy scoring
284
295
  - **User Interaction**: ask_user — ask the user a clarification question when their request is ambiguous or missing key details`;
285
296
 
286
297
  function buildToolCatalog(addonDescriptions?: string[]): string {
@@ -27,7 +27,7 @@ export const POLICY_CARD_IDS = [
27
27
  "general_fallback",
28
28
  ] as const;
29
29
 
30
- export type PromptPolicyCardId = typeof POLICY_CARD_IDS[number];
30
+ export type PromptPolicyCardId = (typeof POLICY_CARD_IDS)[number];
31
31
 
32
32
  export interface PolicyCard {
33
33
  id: PromptPolicyCardId;
@@ -68,7 +68,7 @@ For "today", "right now", "this morning", "after close", or "why did it move" pr
68
68
  status: "implemented",
69
69
  capabilityGapIds: ["sentiment_sample_depth"],
70
70
  content: `## Sentiment Snapshot Policy
71
- For sentiment-only prompts, include the direction and strength of the sentiment signal, the score scale when available, missing sources, why missing sources matter for the user's question, source-coverage risk, low sample counts, and how those gaps downgrade confidence. For ticker-specific sentiment prompts, compare sentiment with fetched price action and state whether sentiment diverges from price action. Treat sentiment as supporting evidence, not a standalone buy/sell verdict. Disclose sparse source coverage, unavailable Twitter/X sessions, provider gaps, or low sample depth instead of implying full-market sentiment coverage.`,
71
+ For sentiment-only prompts, include the direction and strength of the sentiment signal, the score scale when available, the key positive and negative drivers behind the signal, representative source evidence, missing sources, why missing sources matter for the user's question, source-coverage risk, low sample counts, and how those gaps downgrade confidence. For ticker-specific sentiment prompts, compare sentiment with fetched price action and state whether sentiment diverges from price action; if quote data is unavailable, say price-action divergence could not be evaluated. Treat sentiment as supporting evidence, not a standalone buy/sell verdict. Disclose sparse source coverage, unavailable Twitter/X sessions, provider gaps, or low sample depth instead of implying full-market sentiment coverage.`,
72
72
  },
73
73
  filing_thesis_review: {
74
74
  id: "filing_thesis_review",
@@ -133,7 +133,7 @@ For strategy backtest prompts, use backtest_strategy evidence before judging whe
133
133
  status: "implemented",
134
134
  capabilityGapIds: [],
135
135
  content: `## Stateful Tracking Update Policy
136
- For watchlist, portfolio tracking, prediction recording, and prediction-check prompts, use the state tool that owns the change or lookup: manage_watchlist, track_prediction, or track_portfolio. Do not confirm a saved change from prose alone. Confirm the persisted state update with the symbol, action, direction, entry price, target, stop, conviction, timeframe, or check result that the tool accepted. If required fields for a state mutation are missing, ask the smallest clarification question instead of inventing values. For check or list operations, summarize the saved state and say clearly when no records exist. Do not turn a state update into a buy/sell recommendation unless the user separately asks for market analysis.`,
136
+ For watchlist, portfolio tracking, alert management, daily-report, prediction recording, and prediction-check prompts, use the state tool that owns the change or lookup: manage_watchlist, track_prediction, track_portfolio, manage_alerts, or daily_watchlist_report. Do not confirm a saved change from prose alone. Confirm the persisted state update with the symbol, action, direction, entry price, target, stop, conviction, timeframe, or check result that the tool accepted. If the user asks to create an alert and check it now in the same request, call manage_alerts with the matching create action and check_after_create=true. If required fields for a state mutation are missing, ask the smallest clarification question instead of inventing values. For check or list operations, summarize the saved state and say clearly when no records exist. Do not turn a state update into a buy/sell recommendation unless the user separately asks for market analysis.`,
137
137
  },
138
138
  retail_finance_tradeoff: {
139
139
  id: "retail_finance_tradeoff",
@@ -32,7 +32,7 @@ export const SECTION_ORDER = [
32
32
  "output-format",
33
33
  ] as const;
34
34
 
35
- export type SectionName = typeof SECTION_ORDER[number];
35
+ export type SectionName = (typeof SECTION_ORDER)[number];
36
36
 
37
37
  /** Default character budgets per section. */
38
38
  export const DEFAULT_BUDGETS: Record<SectionName, number> = {
@@ -0,0 +1,80 @@
1
+ import { type InstrumentCandidate, searchYahooInstruments } from "../market-state/resolve.js";
2
+
3
+ export interface SymbolValidation {
4
+ valid: boolean;
5
+ reason?: string;
6
+ checkedAt: number;
7
+ }
8
+
9
+ export type SymbolValidationCache = Map<string, SymbolValidation>;
10
+
11
+ export interface SymbolPreflightDrop {
12
+ symbol: string;
13
+ reason: string;
14
+ }
15
+
16
+ export interface SymbolPreflightResult {
17
+ valid: string[];
18
+ dropped: SymbolPreflightDrop[];
19
+ }
20
+
21
+ export async function preflightSymbols(
22
+ symbols: string[],
23
+ options: {
24
+ cache?: SymbolValidationCache;
25
+ search?: (query: string) => Promise<InstrumentCandidate[]>;
26
+ } = {},
27
+ ): Promise<SymbolPreflightResult> {
28
+ const cache = options.cache;
29
+ const search = options.search ?? searchYahooInstruments;
30
+ const valid: string[] = [];
31
+ const dropped: SymbolPreflightDrop[] = [];
32
+
33
+ for (const rawSymbol of symbols) {
34
+ const symbol = rawSymbol.trim().toUpperCase();
35
+ if (!symbol) continue;
36
+
37
+ const cached = cache?.get(symbol);
38
+ const validation = cached ?? (await validateSymbol(symbol, search));
39
+ if (!cached) cache?.set(symbol, validation);
40
+
41
+ if (validation.valid) {
42
+ valid.push(symbol);
43
+ } else {
44
+ dropped.push({
45
+ symbol,
46
+ reason: validation.reason ?? "no matching ticker found via resolver search",
47
+ });
48
+ }
49
+ }
50
+
51
+ return { valid, dropped };
52
+ }
53
+
54
+ export function formatPreflightDropAnnotation(dropped: SymbolPreflightDrop[]): string {
55
+ const count = dropped.length;
56
+ const symbols = dropped.map((drop) => `${drop.symbol} (${drop.reason})`).join(", ");
57
+ return `[Pre-flight: dropped ${count} unknown symbol${count === 1 ? "" : "s"} - ${symbols}]`;
58
+ }
59
+
60
+ function validateSymbol(
61
+ symbol: string,
62
+ search: (query: string) => Promise<InstrumentCandidate[]>,
63
+ ): Promise<SymbolValidation> {
64
+ return search(symbol)
65
+ .then((candidates) => ({
66
+ valid: candidates.some((candidate) => candidate.symbol.toUpperCase() === symbol),
67
+ reason: candidates.some((candidate) => candidate.symbol.toUpperCase() === symbol)
68
+ ? undefined
69
+ : "no matching ticker found via resolver search",
70
+ checkedAt: Date.now(),
71
+ }))
72
+ .catch((error) => ({
73
+ valid: true,
74
+ reason:
75
+ error instanceof Error
76
+ ? `resolver search unavailable: ${error.message}`
77
+ : "resolver search unavailable",
78
+ checkedAt: Date.now(),
79
+ }));
80
+ }