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
@@ -1,3 +1,7 @@
1
+ import {
2
+ type ArtifactContractId,
3
+ artifactContractIdsForPlanning,
4
+ } from "../runtime/artifact-contracts.js";
1
5
  import type {
2
6
  RouterDiagnostic,
3
7
  RouterInputContext,
@@ -6,10 +10,6 @@ import type {
6
10
  ToolBundleName,
7
11
  } from "./router-types.js";
8
12
  import type { WorkflowType } from "./types.js";
9
- import {
10
- artifactContractIdsForPlanning,
11
- type ArtifactContractId,
12
- } from "../runtime/artifact-contracts.js";
13
13
 
14
14
  export const PLANNING_VERSION = "planning-v1" as const;
15
15
 
@@ -98,6 +98,7 @@ export type StructuredCheckId =
98
98
  | "freshness_disclosed"
99
99
  | "data_gap_disclosed"
100
100
  | "commitment_mode_respected"
101
+ | "required_final_fields_present"
101
102
  | "source_coverage_disclosed"
102
103
  | "capability_gap_disclosure"
103
104
  | "assumption_disclosed"
@@ -127,7 +128,8 @@ export const CAPABILITY_GAP_REGISTRY: Record<CapabilityGapId, CapabilityGapDefin
127
128
  market_calendar: {
128
129
  id: "market_calendar",
129
130
  label: "Market calendar",
130
- description: "Exchange holiday and session-state data beyond deterministic weekday/known-holiday grounding.",
131
+ description:
132
+ "Exchange holiday and session-state data beyond deterministic weekday/known-holiday grounding.",
131
133
  v1Status: "classified_gap",
132
134
  specialistCompetitive: false,
133
135
  },
@@ -141,7 +143,8 @@ export const CAPABILITY_GAP_REGISTRY: Record<CapabilityGapId, CapabilityGapDefin
141
143
  brokerage_comparison: {
142
144
  id: "brokerage_comparison",
143
145
  label: "Brokerage comparison",
144
- description: "Live brokerage fees, platform features, account support, and execution-quality comparison data.",
146
+ description:
147
+ "Live brokerage fees, platform features, account support, and execution-quality comparison data.",
145
148
  v1Status: "classified_gap",
146
149
  specialistCompetitive: false,
147
150
  },
@@ -155,7 +158,8 @@ export const CAPABILITY_GAP_REGISTRY: Record<CapabilityGapId, CapabilityGapDefin
155
158
  earnings_event_risk: {
156
159
  id: "earnings_event_risk",
157
160
  label: "Earnings-event risk",
158
- description: "Upcoming earnings timing, transcript, implied move, and event-specific risk coverage.",
161
+ description:
162
+ "Upcoming earnings timing, transcript, implied move, and event-specific risk coverage.",
159
163
  v1Status: "classified_gap",
160
164
  specialistCompetitive: false,
161
165
  },
@@ -176,7 +180,8 @@ export const CAPABILITY_GAP_REGISTRY: Record<CapabilityGapId, CapabilityGapDefin
176
180
  sentiment_sample_depth: {
177
181
  id: "sentiment_sample_depth",
178
182
  label: "Sentiment sample depth",
179
- description: "Coverage, sample-size, source-depth, and low-volume confidence metadata for sentiment evidence.",
183
+ description:
184
+ "Coverage, sample-size, source-depth, and low-volume confidence metadata for sentiment evidence.",
180
185
  v1Status: "classified_gap",
181
186
  specialistCompetitive: false,
182
187
  },
@@ -238,7 +243,11 @@ export const PLANNING_MANIFEST: Record<TaskFamily, PlanningManifestEntry> = {
238
243
  policyCardId: "asset_compare",
239
244
  evidencePlanId: "placeholder_asset_compare",
240
245
  answerContractId: "asset_compare_tradeoff",
241
- structuredCheckIds: ["required_evidence_present", "data_gap_disclosed", "capability_gap_disclosure"],
246
+ structuredCheckIds: [
247
+ "required_evidence_present",
248
+ "data_gap_disclosed",
249
+ "capability_gap_disclosure",
250
+ ],
242
251
  capabilityGapIds: ["etf_holdings_overlap"],
243
252
  compatibleToolBundles: ["core_market", "macro", "sentiment", "clarification"],
244
253
  migrated: false,
@@ -265,7 +274,11 @@ export const PLANNING_MANIFEST: Record<TaskFamily, PlanningManifestEntry> = {
265
274
  policyCardId: "portfolio_review",
266
275
  evidencePlanId: "placeholder_portfolio_review",
267
276
  answerContractId: "portfolio_review",
268
- structuredCheckIds: ["required_evidence_present", "data_gap_disclosed", "commitment_mode_respected"],
277
+ structuredCheckIds: [
278
+ "required_evidence_present",
279
+ "data_gap_disclosed",
280
+ "commitment_mode_respected",
281
+ ],
269
282
  capabilityGapIds: [],
270
283
  compatibleToolBundles: ["core_market", "macro", "sentiment", "clarification"],
271
284
  migrated: false,
@@ -334,7 +347,11 @@ export const PLANNING_MANIFEST: Record<TaskFamily, PlanningManifestEntry> = {
334
347
  policyCardId: "sentiment_snapshot",
335
348
  evidencePlanId: "placeholder_sentiment_snapshot",
336
349
  answerContractId: "sentiment_snapshot",
337
- structuredCheckIds: ["required_evidence_present", "source_coverage_disclosed", "data_gap_disclosed"],
350
+ structuredCheckIds: [
351
+ "required_evidence_present",
352
+ "source_coverage_disclosed",
353
+ "data_gap_disclosed",
354
+ ],
338
355
  capabilityGapIds: ["sentiment_sample_depth"],
339
356
  compatibleToolBundles: ["core_market", "sentiment"],
340
357
  migrated: false,
@@ -390,7 +407,11 @@ export const PLANNING_MANIFEST: Record<TaskFamily, PlanningManifestEntry> = {
390
407
  policyCardId: "backtest_review",
391
408
  evidencePlanId: "placeholder_backtest_review",
392
409
  answerContractId: "backtest_review",
393
- structuredCheckIds: ["required_evidence_present", "data_gap_disclosed", "source_coverage_disclosed"],
410
+ structuredCheckIds: [
411
+ "required_evidence_present",
412
+ "data_gap_disclosed",
413
+ "source_coverage_disclosed",
414
+ ],
394
415
  capabilityGapIds: [],
395
416
  compatibleToolBundles: ["core_market", "options", "sentiment", "sec", "clarification"],
396
417
  migrated: false,
@@ -433,11 +454,10 @@ export function buildPlanningEnvelope(
433
454
  const proposed = defaultPlanningSelection(input, output);
434
455
  const { selection, diagnostics } = validatePlanningSelection(output, proposed);
435
456
  const manifestEntry = PLANNING_MANIFEST[selection.taskFamily];
436
- const behaviorMode: PlanningBehaviorMode = options.migrationStatuses?.[selection.taskFamily] ??
457
+ const behaviorMode: PlanningBehaviorMode =
458
+ options.migrationStatuses?.[selection.taskFamily] ??
437
459
  manifestEntry.migrationStatus ??
438
- (manifestEntry.migrated
439
- ? "replacement_active"
440
- : "observe_only");
460
+ (manifestEntry.migrated ? "replacement_active" : "observe_only");
441
461
 
442
462
  return {
443
463
  version: PLANNING_VERSION,
@@ -449,16 +469,21 @@ export function buildPlanningEnvelope(
449
469
  diagnostics: [
450
470
  ...diagnostics,
451
471
  ...(output.diagnostics.length > 0
452
- ? [{
453
- code: "planning_after_router_corrections",
454
- message: "planning selected after router diagnostics were applied",
455
- }]
472
+ ? [
473
+ {
474
+ code: "planning_after_router_corrections",
475
+ message: "planning selected after router diagnostics were applied",
476
+ },
477
+ ]
456
478
  : []),
457
479
  ...(behaviorMode === "observe_only"
458
- ? [{
459
- code: "planning_observe_only",
460
- message: "planning metadata is recorded without changing active prompt, route, workflow, tools, or answer behavior",
461
- }]
480
+ ? [
481
+ {
482
+ code: "planning_observe_only",
483
+ message:
484
+ "planning metadata is recorded without changing active prompt, route, workflow, tools, or answer behavior",
485
+ },
486
+ ]
462
487
  : []),
463
488
  ],
464
489
  };
@@ -476,10 +501,12 @@ export function validatePlanningSelection(
476
501
  const fallback = defaultTaskFamilyForOutput(output, "");
477
502
  return {
478
503
  selection: selectionForTaskFamily(fallback),
479
- diagnostics: [{
480
- code: "planning_task_family_corrected",
481
- message: `${proposed.taskFamily} is not supported for ${output.routeKind}${output.workflow ? `/${output.workflow}` : ""}; using ${fallback}`,
482
- }],
504
+ diagnostics: [
505
+ {
506
+ code: "planning_task_family_corrected",
507
+ message: `${proposed.taskFamily} is not supported for ${output.routeKind}${output.workflow ? `/${output.workflow}` : ""}; using ${fallback}`,
508
+ },
509
+ ],
483
510
  };
484
511
  }
485
512
 
@@ -508,7 +535,10 @@ function defaultTaskFamilyForOutput(output: RouterOutput, text: string): TaskFam
508
535
  const lower = text.toLowerCase();
509
536
  if (output.routeKind === "clarification") return "general_fallback";
510
537
  if (output.routeKind === "pass_through") return "general_fallback";
511
- if (output.workflow === "portfolio_builder" && isExistingRetirementAllocationReviewPrompt(lower)) {
538
+ if (
539
+ output.workflow === "portfolio_builder" &&
540
+ isExistingRetirementAllocationReviewPrompt(lower)
541
+ ) {
512
542
  return "portfolio_review";
513
543
  }
514
544
  if (output.workflow === "portfolio_builder") return "portfolio_build";
@@ -532,7 +562,10 @@ function defaultTaskFamilyForOutput(output: RouterOutput, text: string): TaskFam
532
562
  if (/\b(?:sentiment|mood|reddit|twitter|x\/twitter)\b/.test(lower)) {
533
563
  return "sentiment_snapshot";
534
564
  }
535
- if (isPortfolioRebalancePrompt(lower) || isAddToExistingHoldingsPrompt(lower, output.entities.symbols.length)) {
565
+ if (
566
+ isPortfolioRebalancePrompt(lower) ||
567
+ isAddToExistingHoldingsPrompt(lower, output.entities.symbols.length)
568
+ ) {
536
569
  return "portfolio_review";
537
570
  }
538
571
  if (/\b(?:today|right now|this morning|after close|moved|catalyst)\b/.test(lower)) {
@@ -544,17 +577,29 @@ function defaultTaskFamilyForOutput(output: RouterOutput, text: string): TaskFam
544
577
  if (/\b(?:brokerage|hysa|money-market|t-bills?|cds?|mortgage|taxable account)\b/.test(lower)) {
545
578
  return "retail_finance_tradeoff";
546
579
  }
547
- if (/\b(?:btc|bitcoin|crypto)\b/.test(lower) && /\b(?:allocation|range|position\s+size|sizing|drawdown)\b/.test(lower)) {
580
+ if (
581
+ /\b(?:btc|bitcoin|crypto)\b/.test(lower) &&
582
+ /\b(?:allocation|range|position\s+size|sizing|drawdown)\b/.test(lower)
583
+ ) {
548
584
  return "retail_finance_tradeoff";
549
585
  }
550
- if (/\b(?:60\/40|portfolio|allocation)\b/.test(lower) && /\b(?:evaluate|evaluation|review|risk|prospects)\b/.test(lower)) {
586
+ if (
587
+ /\b(?:60\/40|portfolio|allocation)\b/.test(lower) &&
588
+ /\b(?:evaluate|evaluation|review|risk|prospects)\b/.test(lower)
589
+ ) {
551
590
  return "portfolio_review";
552
591
  }
553
- if (output.entities.symbols.length === 1 && /\b(?:analyze|buy|sell|wait|avoid|recommendation|attractive)\b/.test(lower)) {
592
+ if (
593
+ output.entities.symbols.length === 1 &&
594
+ /\b(?:analyze|buy|sell|wait|avoid|recommendation|attractive)\b/.test(lower)
595
+ ) {
554
596
  return "single_asset_decision";
555
597
  }
556
598
  if (output.workflow === "single_asset_analysis") return "single_asset_decision";
557
- if (/\b(?:explain|what is|what does|how to|define)\b/.test(lower) && output.entities.symbols.length === 0) {
599
+ if (
600
+ /\b(?:explain|what is|what does|how to|define)\b/.test(lower) &&
601
+ output.entities.symbols.length === 0
602
+ ) {
558
603
  return "concept_explainer";
559
604
  }
560
605
  return "general_fallback";
@@ -581,7 +626,9 @@ function refinePlanningSelectionForPrompt(
581
626
  return {
582
627
  ...selection,
583
628
  policyCardId: "concept_inflation_cash_education",
584
- structuredCheckIds: mergeStructuredChecks(selection.structuredCheckIds, ["tax_caveat_present"]),
629
+ structuredCheckIds: mergeStructuredChecks(selection.structuredCheckIds, [
630
+ "tax_caveat_present",
631
+ ]),
585
632
  };
586
633
  }
587
634
  if (isValuationMetricEducationPrompt(lower)) {
@@ -654,54 +701,99 @@ function refinePlanningSelectionForPrompt(
654
701
  }
655
702
 
656
703
  function isNoToolConceptEducationPrompt(lower: string): boolean {
657
- if (!/\b(?:explain|what\s+is|what\s+are|what\s+does|how\s+does|how\s+do|how\s+to|define)\b/.test(lower)) {
704
+ if (
705
+ !/\b(?:explain|what\s+is|what\s+are|what\s+does|how\s+does|how\s+do|how\s+to|define)\b/.test(
706
+ lower,
707
+ )
708
+ ) {
658
709
  return false;
659
710
  }
660
- return isOptionsEducationPrompt(lower) ||
711
+ return (
712
+ isOptionsEducationPrompt(lower) ||
661
713
  isInflationCashEducationPrompt(lower) ||
662
- isValuationMetricEducationPrompt(lower);
714
+ isValuationMetricEducationPrompt(lower)
715
+ );
663
716
  }
664
717
 
665
718
  function isOptionsEducationPrompt(lower: string): boolean {
666
- return /\b(?:covered\s+calls?|protective\s+puts?|options?|option\s+premium|assignment\s+risk|strike|expiration|delta|theta|greeks?)\b/.test(lower);
719
+ return /\b(?:covered\s+calls?|protective\s+puts?|options?|option\s+premium|assignment\s+risk|strike|expiration|delta|theta|greeks?)\b/.test(
720
+ lower,
721
+ );
667
722
  }
668
723
 
669
724
  function isOptionsStrategyPrompt(lower: string): boolean {
670
- return /\b(?:covered\s+calls?|protective\s+puts?|sell(?:ing)?\s+calls?|sell(?:ing)?\s+puts?|options?\s+income|option\s+strategy|hedge|collar)\b/.test(lower) &&
671
- /\b(?:own|have|shares?|position|cost\s+basis|good\s+idea|make\s+sense|income|premium|strike|expiration|assignment|stable|flat|protect|hedge|sell)\b/.test(lower);
725
+ const explicitOptionsStrategy =
726
+ /\b(?:covered\s+calls?|protective\s+puts?|buy(?:ing)?\s+puts?|sell(?:ing)?\s+calls?|sell(?:ing)?\s+puts?|options?\s+income|option\s+strategy|options?\s+hedge|collar)\b/.test(
727
+ lower,
728
+ );
729
+ const optionsHedge =
730
+ /\bhedg(?:e|ing)\b.{0,80}\b(?:puts|put\s+options?|options?)\b/.test(lower) ||
731
+ /\b(?:puts|put\s+options?|options?)\b.{0,80}\bhedg(?:e|ing)\b/.test(lower);
732
+ return (
733
+ (explicitOptionsStrategy || optionsHedge) &&
734
+ /\b(?:own|have|shares?|position|cost\s+basis|good\s+idea|make\s+sense|income|premium|strike|expiration|assignment|stable|flat|protect|hedge|sell)\b/.test(
735
+ lower,
736
+ )
737
+ );
672
738
  }
673
739
 
674
740
  function isTickerDisambiguationPrompt(lower: string): boolean {
675
741
  if (/\b(?:ticker|symbol|formerly|old ticker)\b/.test(lower)) return true;
676
- return /\b(?:earnings are|earnings tonight)\b/.test(lower) &&
742
+ return (
743
+ /\b(?:earnings are|earnings tonight)\b/.test(lower) &&
677
744
  /\b(?:trim|hedge|hold|event[-\s]?risk|position\s+size)\b/.test(lower) &&
678
- !/\b(?:covered\s+calls?|protective\s+puts?|sell(?:ing)?\s+calls?|sell(?:ing)?\s+puts?|option\s+chain|strike|expiration|premium)\b/.test(lower);
745
+ !/\b(?:covered\s+calls?|protective\s+puts?|sell(?:ing)?\s+calls?|sell(?:ing)?\s+puts?|option\s+chain|strike|expiration|premium)\b/.test(
746
+ lower,
747
+ )
748
+ );
679
749
  }
680
750
 
681
751
  function isInflationCashEducationPrompt(lower: string): boolean {
682
- return /\b(?:inflation|purchasing\s+power|real\s+returns?|cash\s+savings?|cash\s+drag|tips|short(?:er)?[-\s]?duration)\b/.test(lower) &&
683
- /\b(?:cash|savings?|purchasing\s+power|real\s+returns?|bonds?|tips|protect|protection|affect)\b/.test(lower);
752
+ return (
753
+ /\b(?:inflation|purchasing\s+power|real\s+returns?|cash\s+savings?|cash\s+drag|tips|short(?:er)?[-\s]?duration)\b/.test(
754
+ lower,
755
+ ) &&
756
+ /\b(?:cash|savings?|purchasing\s+power|real\s+returns?|bonds?|tips|protect|protection|affect)\b/.test(
757
+ lower,
758
+ )
759
+ );
684
760
  }
685
761
 
686
762
  function isValuationMetricEducationPrompt(lower: string): boolean {
687
- return /\b(?:p\/e|pe\s+ratio|price[-\s]?to[-\s]?earnings|ev\/ebitda|p\/s|price[-\s]?to[-\s]?sales|valuation\s+metric|trailing|forward\s+earnings|normalized\s+earnings|cyclically\s+adjusted)\b/.test(lower);
763
+ return /\b(?:p\/e|pe\s+ratio|price[-\s]?to[-\s]?earnings|ev\/ebitda|p\/s|price[-\s]?to[-\s]?sales|valuation\s+metric|trailing|forward\s+earnings|normalized\s+earnings|cyclically\s+adjusted)\b/.test(
764
+ lower,
765
+ );
688
766
  }
689
767
 
690
768
  function isPortfolioRebalancePrompt(lower: string): boolean {
691
- return /\b(?:portfolio|allocation|holdings?|sleeves?|ira|etfs?|funds?|s&p\s*500|index|equity|bonds?|cash)\b/.test(lower) &&
692
- /\b(?:rebalance|diversify|diversifying|concentration|overweight|underweight|target\s+bands?|drift|reduce\s+concentration|adjust|adjustment|more\s+aggressive|higher\s+growth|too\s+risky|riskier|worried|crash|protect|protection|missing\s+out\s+on\s+growth)\b/.test(lower);
769
+ return (
770
+ /\b(?:portfolio|allocation|holdings?|sleeves?|ira|etfs?|funds?|s&p\s*500|index|equity|bonds?|cash)\b/.test(
771
+ lower,
772
+ ) &&
773
+ /\b(?:rebalance|diversify|diversifying|concentration|overweight|underweight|target\s+bands?|drift|reduce\s+concentration|adjust|adjustment|more\s+aggressive|higher\s+growth|too\s+risky|riskier|worried|crash|hedge|protect|protection|missing\s+out\s+on\s+growth)\b/.test(
774
+ lower,
775
+ )
776
+ );
693
777
  }
694
778
 
695
779
  function isAddToExistingHoldingsPrompt(lower: string, symbolCount: number): boolean {
696
- return symbolCount >= 2 &&
697
- /\b(?:already\s+own|already\s+hold|current(?:ly)?\s+own|existing\s+(?:holdings?|portfolio|position)|my\s+portfolio)\b/.test(lower) &&
698
- /\b(?:add(?:ing)?|buy(?:ing)?|make\s+sense|fit|long[-\s]?term|growth)\b/.test(lower);
780
+ return (
781
+ symbolCount >= 2 &&
782
+ /\b(?:already\s+own|already\s+hold|current(?:ly)?\s+own|existing\s+(?:holdings?|portfolio|position)|my\s+portfolio)\b/.test(
783
+ lower,
784
+ ) &&
785
+ /\b(?:add(?:ing)?|buy(?:ing)?|make\s+sense|fit|long[-\s]?term|growth)\b/.test(lower)
786
+ );
699
787
  }
700
788
 
701
789
  function isExistingRetirementAllocationReviewPrompt(lower: string): boolean {
702
- return /\b(?:401k|401\(k\)|target[-\s]?date|tdf)\b/.test(lower) &&
790
+ return (
791
+ /\b(?:401k|401\(k\)|target[-\s]?date|tdf)\b/.test(lower) &&
703
792
  /\b(?:mostly|current(?:ly)?|already|have|holding|invested|allocation)\b/.test(lower) &&
704
- /\b(?:review|solid|worried|inflation|diversify|boost returns?|other options?|without taking crazy risks?|risk)\b/.test(lower);
793
+ /\b(?:review|solid|worried|inflation|diversify|boost returns?|other options?|without taking crazy risks?|risk)\b/.test(
794
+ lower,
795
+ )
796
+ );
705
797
  }
706
798
 
707
799
  function mergeCapabilityGaps(
@@ -1,14 +1,6 @@
1
- import type {
2
- ExtractedEntities,
3
- WorkflowType,
4
- } from "./types.js";
5
- import type {
6
- RouterOutput,
7
- RouterRoute,
8
- RouterRouteKind,
9
- ToolBundleName,
10
- } from "./router-types.js";
11
1
  import type { MemoryCategory } from "../memory/types.js";
2
+ import type { RouterOutput, RouterRoute, RouterRouteKind, ToolBundleName } from "./router-types.js";
3
+ import type { ExtractedEntities, WorkflowType } from "./types.js";
12
4
 
13
5
  export const ROUTE_KINDS: readonly RouterRouteKind[] = [
14
6
  "workflow_dispatch",
@@ -22,6 +14,7 @@ export const TOOL_BUNDLE_TOOLS: Record<ToolBundleName, readonly string[]> = {
22
14
  "search_ticker",
23
15
  "get_stock_quote",
24
16
  "get_stock_history",
17
+ "screen_stocks",
25
18
  "get_crypto_price",
26
19
  "get_crypto_history",
27
20
  "get_company_overview",
@@ -37,6 +30,9 @@ export const TOOL_BUNDLE_TOOLS: Record<ToolBundleName, readonly string[]> = {
37
30
  "track_portfolio",
38
31
  "manage_watchlist",
39
32
  "track_prediction",
33
+ "manage_alerts",
34
+ "daily_watchlist_report",
35
+ "manage_notifications",
40
36
  "search_web",
41
37
  ],
42
38
  options: ["get_option_chain", "get_stock_quote", "search_ticker", "search_web"],
@@ -216,7 +212,11 @@ export function computeMissingRequiredSlots(
216
212
  if (slot === "symbol" && entities.symbols.length === 0 && !slotHasValue(slots.symbol)) {
217
213
  missing.add("symbol");
218
214
  }
219
- if (slot === "symbols" && entities.symbols.length < 2 && !slotHasValue(slots.symbols)) {
215
+ if (
216
+ slot === "symbols" &&
217
+ entities.symbols.length < 2 &&
218
+ !slotHasSymbolListValue(slots.symbols, 2)
219
+ ) {
220
220
  missing.add("symbols");
221
221
  }
222
222
  existing.delete(slot);
@@ -233,22 +233,44 @@ function slotHasValue(slot: RouterOutput["slots"][string] | undefined): boolean
233
233
  return slot.value !== undefined && slot.value !== null && slot.value !== "";
234
234
  }
235
235
 
236
- export function selectToolBundles(output: Pick<RouterOutput, "routeKind" | "workflow" | "entities">): ToolBundleName[] {
236
+ function slotHasSymbolListValue(
237
+ slot: RouterOutput["slots"][string] | undefined,
238
+ minLength: number,
239
+ ): boolean {
240
+ if (!slot) return false;
241
+ if (Array.isArray(slot.value))
242
+ return slot.value.filter((value) => typeof value === "string").length >= minLength;
243
+ return false;
244
+ }
245
+
246
+ export function selectToolBundles(
247
+ output: Pick<RouterOutput, "routeKind" | "workflow" | "entities">,
248
+ ): ToolBundleName[] {
237
249
  if (output.routeKind === "pass_through") return [];
238
250
  if (output.routeKind === "clarification") return ["clarification"];
239
251
 
240
252
  const bundles = new Set<ToolBundleName>();
241
253
  const routeBundles = ROUTE_CAPABILITY_MANIFEST[output.routeKind]?.toolBundles ?? [];
242
- routeBundles.forEach((bundle) => bundles.add(bundle));
254
+ for (const bundle of routeBundles) {
255
+ bundles.add(bundle);
256
+ }
243
257
 
244
258
  if (output.workflow) {
245
259
  const workflow = WORKFLOW_CAPABILITY_MANIFEST[output.workflow];
246
- workflow?.toolBundles.forEach((bundle) => bundles.add(bundle));
260
+ if (workflow) {
261
+ for (const bundle of workflow.toolBundles) {
262
+ bundles.add(bundle);
263
+ }
264
+ }
247
265
  }
248
266
 
249
267
  const metrics = output.entities.compareMetrics ?? [];
250
268
  const horizon = output.entities.timeHorizon ?? "";
251
- if (metrics.includes("macro_hedge") || metrics.includes("interest_rates") || /\b(?:macro|rate|inflation)\b/i.test(horizon)) {
269
+ if (
270
+ metrics.includes("macro_hedge") ||
271
+ metrics.includes("interest_rates") ||
272
+ /\b(?:macro|rate|inflation)\b/i.test(horizon)
273
+ ) {
252
274
  bundles.add("macro");
253
275
  }
254
276
 
@@ -9,7 +9,9 @@ import type { RouterLlmClient } from "./router-types.js";
9
9
  * Zero tools are passed — the router operates on text alone. Temperature
10
10
  * is pinned low for structured-output stability.
11
11
  */
12
- export function createPiAiRouterClient(model: Model<"anthropic-messages"> | Model<any>): RouterLlmClient {
12
+ export function createPiAiRouterClient(
13
+ model: Model<"anthropic-messages"> | Model<any>,
14
+ ): RouterLlmClient {
13
15
  return {
14
16
  async complete(prompt: string): Promise<string> {
15
17
  const response = await completeSimple(
@@ -33,9 +35,7 @@ export function createPiAiRouterClient(model: Model<"anthropic-messages"> | Mode
33
35
  );
34
36
 
35
37
  if (response.stopReason === "error" || response.stopReason === "aborted") {
36
- throw new Error(
37
- `router LLM call failed: ${response.errorMessage ?? response.stopReason}`,
38
- );
38
+ throw new Error(`router LLM call failed: ${response.errorMessage ?? response.stopReason}`);
39
39
  }
40
40
 
41
41
  const text = response.content
@@ -1,7 +1,4 @@
1
- import {
2
- ROUTE_CAPABILITY_MANIFEST,
3
- WORKFLOW_CAPABILITY_MANIFEST,
4
- } from "./route-manifest.js";
1
+ import { ROUTE_CAPABILITY_MANIFEST, WORKFLOW_CAPABILITY_MANIFEST } from "./route-manifest.js";
5
2
  import type { RouterInputContext } from "./router-types.js";
6
3
 
7
4
  /**
@@ -20,18 +17,21 @@ function renderCatalog(): string {
20
17
  portfolio_builder: "user asks to build/allocate a portfolio, invest a budget across positions",
21
18
  options_screener: "user asks for options trades / calls / puts on a specific ticker",
22
19
  compare_assets: "user asks to compare two or more symbols (vs / versus / which is better)",
23
- single_asset_analysis: "user asks for a full analysis / deep dive / 'is X attractive' on ONE symbol",
20
+ single_asset_analysis:
21
+ "user asks for a full analysis / deep dive / 'is X attractive' on ONE symbol",
24
22
  watchlist_or_tracking: "user manages or asks about their saved watchlist / prediction history",
25
- general_finance_qa: "definitional / conceptual questions plus broad market structure, sector, industry, monetary policy, and emerging markets research",
23
+ general_finance_qa:
24
+ "definitional / conceptual questions plus broad market structure, sector, industry, monetary policy, and emerging markets research",
26
25
  };
27
26
 
28
- return Object.values(WORKFLOW_CAPABILITY_MANIFEST).map((w) => {
29
- const required = w.requiredSlots.length > 0
30
- ? ` [required: ${w.requiredSlots.join(", ")}]`
31
- : "";
32
- const mode = w.dispatchable ? "dispatchable workflow" : "agent-task workflow label";
33
- return `- "${w.workflow}" (${mode}): ${descriptions[w.workflow]}${required}`;
34
- }).join("\n");
27
+ return Object.values(WORKFLOW_CAPABILITY_MANIFEST)
28
+ .map((w) => {
29
+ const required =
30
+ w.requiredSlots.length > 0 ? ` [required: ${w.requiredSlots.join(", ")}]` : "";
31
+ const mode = w.dispatchable ? "dispatchable workflow" : "agent-task workflow label";
32
+ return `- "${w.workflow}" (${mode}): ${descriptions[w.workflow]}${required}`;
33
+ })
34
+ .join("\n");
35
35
  }
36
36
 
37
37
  function renderRouteKinds(): string {
@@ -46,13 +46,9 @@ function renderProfile(profile: Record<string, unknown>): string {
46
46
  return entries.map(([k, v]) => `- ${k}: ${JSON.stringify(v)}`).join("\n");
47
47
  }
48
48
 
49
- function renderPriorTurns(
50
- turns: Array<{ role: "user" | "assistant"; text: string }>,
51
- ): string {
49
+ function renderPriorTurns(turns: Array<{ role: "user" | "assistant"; text: string }>): string {
52
50
  if (turns.length === 0) return "(none)";
53
- return turns
54
- .map((t) => `[${t.role}] ${t.text.replace(/\n+/g, " ").slice(0, 400)}`)
55
- .join("\n");
51
+ return turns.map((t) => `[${t.role}] ${t.text.replace(/\n+/g, " ").slice(0, 400)}`).join("\n");
56
52
  }
57
53
 
58
54
  function renderRecentRuns(
@@ -1,11 +1,7 @@
1
1
  import type { ExtractedEntities, SlotSource, WorkflowType } from "./types.js";
2
2
 
3
3
  export type RouterRoute = "workflow" | "fallback";
4
- export type RouterRouteKind =
5
- | "workflow_dispatch"
6
- | "agent_task"
7
- | "clarification"
8
- | "pass_through";
4
+ export type RouterRouteKind = "workflow_dispatch" | "agent_task" | "clarification" | "pass_through";
9
5
 
10
6
  export type ToolBundleName =
11
7
  | "core_market"
@@ -33,6 +29,7 @@ export interface RouterPreferenceUpdate {
33
29
  export interface RouterDiagnostic {
34
30
  code: string;
35
31
  message: string;
32
+ details?: Record<string, unknown>;
36
33
  }
37
34
 
38
35
  /**