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,16 +1,19 @@
1
- import { Type } from "@sinclair/typebox";
2
1
  import type { AgentTool } from "@earendil-works/pi-agent-core";
3
- import { getOverview } from "../../providers/alpha-vantage.js";
4
- import { wrapProvider } from "../../providers/wrap-provider.js";
2
+ import { Type } from "@sinclair/typebox";
5
3
  import { getConfig } from "../../config.js";
6
4
  import { withCredentialCheck } from "../../onboarding/tool-helpers.js";
5
+ import { getOverview } from "../../providers/alpha-vantage.js";
6
+ import { wrapProvider } from "../../providers/wrap-provider.js";
7
7
  import type { CompanyOverview } from "../../types/fundamentals.js";
8
8
 
9
9
  const params = Type.Object({
10
10
  symbol: Type.String({ description: "Stock ticker symbol (e.g. AAPL, MSFT)" }),
11
11
  });
12
12
 
13
- export const companyOverviewTool: AgentTool<typeof params, CompanyOverview | { credentialRequired: unknown }> = {
13
+ export const companyOverviewTool: AgentTool<
14
+ typeof params,
15
+ CompanyOverview | { credentialRequired: unknown }
16
+ > = {
14
17
  name: "get_company_overview",
15
18
  label: "Company Overview",
16
19
  description:
@@ -19,10 +22,17 @@ export const companyOverviewTool: AgentTool<typeof params, CompanyOverview | { c
19
22
  async execute(_toolCallId, args) {
20
23
  return withCredentialCheck("alpha_vantage", async () => {
21
24
  const apiKey = getConfig().alphaVantageApiKey!;
22
- const result = await wrapProvider("alphavantage", () => getOverview(args.symbol.toUpperCase(), apiKey));
25
+ const result = await wrapProvider("alphavantage", () =>
26
+ getOverview(args.symbol.toUpperCase(), apiKey),
27
+ );
23
28
  if (result.status === "unavailable") {
24
29
  return {
25
- content: [{ type: "text", text: `⚠ Company overview unavailable for ${args.symbol.toUpperCase()} (${result.reason}). Analysis will proceed without fundamentals.` }],
30
+ content: [
31
+ {
32
+ type: "text",
33
+ text: `⚠ Company overview unavailable for ${args.symbol.toUpperCase()} (${result.reason}). Analysis will proceed without fundamentals.`,
34
+ },
35
+ ],
26
36
  details: null as any,
27
37
  };
28
38
  }
@@ -31,11 +41,11 @@ export const companyOverviewTool: AgentTool<typeof params, CompanyOverview | { c
31
41
  `**${ov.name}** (${ov.symbol}) — ${ov.exchange}`,
32
42
  `Sector: ${ov.sector} | Industry: ${ov.industry}`,
33
43
  `Market Cap: $${formatLargeNumber(ov.marketCap)} | P/E: ${ov.pe ?? "N/A"} | Fwd P/E: ${ov.forwardPe ?? "N/A"}`,
34
- `EPS: $${ov.eps ?? "N/A"} | Div Yield: ${ov.dividendYield ? (ov.dividendYield * 100).toFixed(2) + "%" : "N/A"}`,
35
- `Beta: ${ov.beta ?? "N/A"} | Profit Margin: ${ov.profitMargin ? (ov.profitMargin * 100).toFixed(1) + "%" : "N/A"}`,
44
+ `EPS: $${ov.eps ?? "N/A"} | Div Yield: ${ov.dividendYield ? `${(ov.dividendYield * 100).toFixed(2)}%` : "N/A"}`,
45
+ `Beta: ${ov.beta ?? "N/A"} | Profit Margin: ${ov.profitMargin ? `${(ov.profitMargin * 100).toFixed(1)}%` : "N/A"}`,
36
46
  `52W: $${ov.week52Low.toFixed(2)} - $${ov.week52High.toFixed(2)}`,
37
47
  ``,
38
- ov.description.slice(0, 300) + (ov.description.length > 300 ? "..." : ""),
48
+ `${ov.description.slice(0, 300)}${ov.description.length > 300 ? "..." : ""}`,
39
49
  ].join("\n");
40
50
 
41
51
  const prefix = result.stale
@@ -1,9 +1,9 @@
1
- import { Type } from "@sinclair/typebox";
2
1
  import type { AgentTool } from "@earendil-works/pi-agent-core";
3
- import { getOverview } from "../../providers/alpha-vantage.js";
4
- import { wrapProvider } from "../../providers/wrap-provider.js";
2
+ import { Type } from "@sinclair/typebox";
5
3
  import { getConfig } from "../../config.js";
6
4
  import { withCredentialCheck } from "../../onboarding/tool-helpers.js";
5
+ import { getOverview } from "../../providers/alpha-vantage.js";
6
+ import { wrapProvider } from "../../providers/wrap-provider.js";
7
7
  import type { CompanyOverview } from "../../types/fundamentals.js";
8
8
 
9
9
  export interface CompsMetric {
@@ -55,8 +55,12 @@ export function computeComps(companies: CompanyOverview[]): CompsResult {
55
55
  const p25 = computePercentile(sortedVals, 0.25);
56
56
  const p75 = computePercentile(sortedVals, 0.75);
57
57
 
58
- const best = def.lowerIsBetter ? sorted[0]?.sym ?? "" : sorted[sorted.length - 1]?.sym ?? "";
59
- const worst = def.lowerIsBetter ? sorted[sorted.length - 1]?.sym ?? "" : sorted[0]?.sym ?? "";
58
+ const best = def.lowerIsBetter
59
+ ? (sorted[0]?.sym ?? "")
60
+ : (sorted[sorted.length - 1]?.sym ?? "");
61
+ const worst = def.lowerIsBetter
62
+ ? (sorted[sorted.length - 1]?.sym ?? "")
63
+ : (sorted[0]?.sym ?? "");
60
64
 
61
65
  return { metric: def.name, values, median, p25, p75, best, worst };
62
66
  });
@@ -67,9 +71,7 @@ export function computeComps(companies: CompanyOverview[]): CompsResult {
67
71
  function computeMedian(sorted: number[]): number | null {
68
72
  if (sorted.length === 0) return null;
69
73
  const mid = Math.floor(sorted.length / 2);
70
- return sorted.length % 2 === 0
71
- ? (sorted[mid - 1] + sorted[mid]) / 2
72
- : sorted[mid];
74
+ return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
73
75
  }
74
76
 
75
77
  function computePercentile(sorted: number[], p: number): number | null {
@@ -98,59 +100,70 @@ export const compsTool: AgentTool<typeof params> = {
98
100
  parameters: params,
99
101
  async execute(_toolCallId, args) {
100
102
  return withCredentialCheck("alpha_vantage", async () => {
101
- const config = getConfig();
102
- const symbols = args.symbols.map((s) => s.toUpperCase());
103
-
104
- const results = await Promise.all(
105
- symbols.map(async (s) => ({
106
- symbol: s,
107
- result: await wrapProvider("alphavantage", () => getOverview(s, config.alphaVantageApiKey!)),
108
- })),
109
- );
110
-
111
- const companies: CompanyOverview[] = [];
112
- const unavailableSymbols: string[] = [];
113
-
114
- for (const { symbol: sym, result: r } of results) {
115
- if (r.status === "ok") {
116
- companies.push(r.data);
117
- } else {
118
- unavailableSymbols.push(sym);
103
+ const config = getConfig();
104
+ const symbols = args.symbols.map((s) => s.toUpperCase());
105
+
106
+ const results = await Promise.all(
107
+ symbols.map(async (s) => ({
108
+ symbol: s,
109
+ result: await wrapProvider("alphavantage", () =>
110
+ getOverview(s, config.alphaVantageApiKey!),
111
+ ),
112
+ })),
113
+ );
114
+
115
+ const companies: CompanyOverview[] = [];
116
+ const unavailableSymbols: string[] = [];
117
+
118
+ for (const { symbol: sym, result: r } of results) {
119
+ if (r.status === "ok") {
120
+ companies.push(r.data);
121
+ } else {
122
+ unavailableSymbols.push(sym);
123
+ }
119
124
  }
120
- }
121
125
 
122
- if (companies.length === 0) {
123
- return {
124
- content: [{ type: "text", text: `⚠ Company fundamentals unavailable for all symbols: ${symbols.join(", ")}. Alpha Vantage may be rate limited.` }],
125
- details: null as any,
126
- };
127
- }
126
+ if (companies.length === 0) {
127
+ return {
128
+ content: [
129
+ {
130
+ type: "text",
131
+ text: `⚠ Company fundamentals unavailable for all symbols: ${symbols.join(", ")}. Alpha Vantage may be rate limited.`,
132
+ },
133
+ ],
134
+ details: null as any,
135
+ };
136
+ }
128
137
 
129
- const result = computeComps(companies);
130
- result.unavailableSymbols = unavailableSymbols;
131
-
132
- const availableSymbols = companies.map((company) => company.symbol);
133
- const header = `**Comparable Company Analysis**: ${availableSymbols.join(" vs ")}`;
134
- const rows = result.metrics.map((m) => {
135
- const vals = availableSymbols.map((s) => {
136
- const v = m.values[s];
137
- if (v == null) return "N/A".padStart(10);
138
- if (Math.abs(v) < 1) return `${(v * 100).toFixed(1)}%`.padStart(10);
139
- return v.toFixed(2).padStart(10);
138
+ const result = computeComps(companies);
139
+ result.unavailableSymbols = unavailableSymbols;
140
+
141
+ const availableSymbols = companies.map((company) => company.symbol);
142
+ const header = `**Comparable Company Analysis**: ${availableSymbols.join(" vs ")}`;
143
+ const rows = result.metrics.map((m) => {
144
+ const vals = availableSymbols.map((s) => {
145
+ const v = m.values[s];
146
+ if (v == null) return "N/A".padStart(10);
147
+ if (Math.abs(v) < 1) return `${(v * 100).toFixed(1)}%`.padStart(10);
148
+ return v.toFixed(2).padStart(10);
149
+ });
150
+ const medStr =
151
+ m.median != null
152
+ ? Math.abs(m.median) < 1
153
+ ? `${(m.median * 100).toFixed(1)}%`
154
+ : m.median.toFixed(2)
155
+ : "N/A";
156
+ return ` ${m.metric.padEnd(16)} ${vals.join("")} Med: ${medStr} Best: ${m.best}`;
140
157
  });
141
- const medStr = m.median != null
142
- ? (Math.abs(m.median) < 1 ? `${(m.median * 100).toFixed(1)}%` : m.median.toFixed(2))
143
- : "N/A";
144
- return ` ${m.metric.padEnd(16)} ${vals.join("")} Med: ${medStr} Best: ${m.best}`;
145
- });
146
158
 
147
- const symHeader = ` ${"Metric".padEnd(16)} ${availableSymbols.map((s) => s.padStart(10)).join("")}`;
148
- const noteLines = unavailableSymbols.length > 0
149
- ? ["", `Unavailable fundamentals: ${unavailableSymbols.join(", ")}`]
150
- : [];
151
- const text = [header, "", symHeader, ...rows, ...noteLines].join("\n");
159
+ const symHeader = ` ${"Metric".padEnd(16)} ${availableSymbols.map((s) => s.padStart(10)).join("")}`;
160
+ const noteLines =
161
+ unavailableSymbols.length > 0
162
+ ? ["", `Unavailable fundamentals: ${unavailableSymbols.join(", ")}`]
163
+ : [];
164
+ const text = [header, "", symHeader, ...rows, ...noteLines].join("\n");
152
165
 
153
- return { content: [{ type: "text", text }], details: result };
166
+ return { content: [{ type: "text", text }], details: result };
154
167
  });
155
168
  },
156
169
  };
@@ -1,10 +1,10 @@
1
- import { Type } from "@sinclair/typebox";
2
1
  import type { AgentTool } from "@earendil-works/pi-agent-core";
3
- import { getOverview, getFinancials } from "../../providers/alpha-vantage.js";
4
- import { getQuote } from "../../providers/yahoo-finance.js";
5
- import { wrapProvider } from "../../providers/wrap-provider.js";
2
+ import { Type } from "@sinclair/typebox";
6
3
  import { getConfig } from "../../config.js";
7
4
  import { withCredentialCheck } from "../../onboarding/tool-helpers.js";
5
+ import { getFinancials, getOverview } from "../../providers/alpha-vantage.js";
6
+ import { wrapProvider } from "../../providers/wrap-provider.js";
7
+ import { getQuote } from "../../providers/yahoo-finance.js";
8
8
  import type { FinancialStatement } from "../../types/fundamentals.js";
9
9
 
10
10
  export interface DCFResult {
@@ -35,7 +35,15 @@ export interface DCFParams {
35
35
  }
36
36
 
37
37
  export function computeDCF(params: DCFParams): DCFResult {
38
- const { freeCashFlow, growthRate, discountRate, terminalGrowth, years, netDebt, sharesOutstanding } = params;
38
+ const {
39
+ freeCashFlow,
40
+ growthRate,
41
+ discountRate,
42
+ terminalGrowth,
43
+ years,
44
+ netDebt,
45
+ sharesOutstanding,
46
+ } = params;
39
47
 
40
48
  // Project future cash flows (mid-year convention: discount at year-0.5)
41
49
  const projectedCashFlows: Array<{ year: number; fcf: number; presentValue: number }> = [];
@@ -59,13 +67,25 @@ export function computeDCF(params: DCFParams): DCFResult {
59
67
  const intrinsicValue = equityValue / sharesOutstanding;
60
68
 
61
69
  // Sensitivity table: vary growth ±2% and discount ±2%
62
- const sensitivityTable: Array<{ growthRate: number; discountRate: number; intrinsicValue: number }> = [];
70
+ const sensitivityTable: Array<{
71
+ growthRate: number;
72
+ discountRate: number;
73
+ intrinsicValue: number;
74
+ }> = [];
63
75
  for (let gDelta = -0.02; gDelta <= 0.02; gDelta += 0.01) {
64
76
  for (let dDelta = -0.02; dDelta <= 0.02; dDelta += 0.01) {
65
77
  const g = growthRate + gDelta;
66
78
  const d = discountRate + dDelta;
67
79
  if (d <= terminalGrowth || d <= 0 || g < 0) continue;
68
- const sensResult = computeDCFSimple(freeCashFlow, g, d, terminalGrowth, years, netDebt, sharesOutstanding);
80
+ const sensResult = computeDCFSimple(
81
+ freeCashFlow,
82
+ g,
83
+ d,
84
+ terminalGrowth,
85
+ years,
86
+ netDebt,
87
+ sharesOutstanding,
88
+ );
69
89
  sensitivityTable.push({ growthRate: g, discountRate: d, intrinsicValue: sensResult });
70
90
  }
71
91
  }
@@ -74,17 +94,25 @@ export function computeDCF(params: DCFParams): DCFResult {
74
94
  const warnings: string[] = [];
75
95
  const tvPctOfEV = pvTerminal / enterpriseValue;
76
96
  if (tvPctOfEV > 0.85) {
77
- warnings.push(`Terminal value is ${(tvPctOfEV * 100).toFixed(0)}% of enterprise value (typical: 40-80%). The valuation is heavily dependent on terminal assumptions.`);
97
+ warnings.push(
98
+ `Terminal value is ${(tvPctOfEV * 100).toFixed(0)}% of enterprise value (typical: 40-80%). The valuation is heavily dependent on terminal assumptions.`,
99
+ );
78
100
  }
79
101
  const spreadPct = discountRate - terminalGrowth;
80
102
  if (spreadPct < 0.02) {
81
- warnings.push(`Terminal growth (${(terminalGrowth * 100).toFixed(1)}%) is very close to discount rate (${(discountRate * 100).toFixed(1)}%). Small changes in assumptions will produce large swings in value.`);
103
+ warnings.push(
104
+ `Terminal growth (${(terminalGrowth * 100).toFixed(1)}%) is very close to discount rate (${(discountRate * 100).toFixed(1)}%). Small changes in assumptions will produce large swings in value.`,
105
+ );
82
106
  }
83
- if (discountRate < 0.05 || discountRate > 0.20) {
84
- warnings.push(`Discount rate of ${(discountRate * 100).toFixed(1)}% is outside typical WACC range (5-20%).`);
107
+ if (discountRate < 0.05 || discountRate > 0.2) {
108
+ warnings.push(
109
+ `Discount rate of ${(discountRate * 100).toFixed(1)}% is outside typical WACC range (5-20%).`,
110
+ );
85
111
  }
86
- if (growthRate > 0.20) {
87
- warnings.push(`Growth rate of ${(growthRate * 100).toFixed(1)}% exceeds 20%. High growth is difficult to sustain — consider a multi-stage model.`);
112
+ if (growthRate > 0.2) {
113
+ warnings.push(
114
+ `Growth rate of ${(growthRate * 100).toFixed(1)}% exceeds 20%. High growth is difficult to sustain — consider a multi-stage model.`,
115
+ );
88
116
  }
89
117
 
90
118
  return {
@@ -106,7 +134,13 @@ export function computeDCF(params: DCFParams): DCFResult {
106
134
  }
107
135
 
108
136
  function computeDCFSimple(
109
- fcf: number, g: number, d: number, tg: number, years: number, debt: number, shares: number,
137
+ fcf: number,
138
+ g: number,
139
+ d: number,
140
+ tg: number,
141
+ years: number,
142
+ debt: number,
143
+ shares: number,
110
144
  ): number {
111
145
  let sumPV = 0;
112
146
  for (let y = 1; y <= years; y++) {
@@ -129,7 +163,10 @@ export function computeNetDebt(f: FinancialStatement): number {
129
163
  const params = Type.Object({
130
164
  symbol: Type.String({ description: "Stock ticker symbol (e.g. AAPL, MSFT)" }),
131
165
  growth_rate: Type.Optional(
132
- Type.Number({ description: "Annual FCF growth rate as decimal (e.g. 0.10 for 10%). If omitted, estimated from historical data." }),
166
+ Type.Number({
167
+ description:
168
+ "Annual FCF growth rate as decimal (e.g. 0.10 for 10%). If omitted, estimated from historical data.",
169
+ }),
133
170
  ),
134
171
  discount_rate: Type.Optional(
135
172
  Type.Number({ description: "Discount rate / WACC as decimal (default: 0.10 for 10%)" }),
@@ -150,98 +187,111 @@ export const dcfTool: AgentTool<typeof params> = {
150
187
  parameters: params,
151
188
  async execute(_toolCallId, args) {
152
189
  return withCredentialCheck("alpha_vantage", async () => {
153
- const symbol = args.symbol.toUpperCase();
154
- const config = getConfig();
190
+ const symbol = args.symbol.toUpperCase();
191
+ const config = getConfig();
155
192
 
156
- const [overviewResult, financialsResult, quoteResult] = await Promise.all([
157
- wrapProvider("alphavantage", () => getOverview(symbol, config.alphaVantageApiKey!)),
158
- wrapProvider("alphavantage", () => getFinancials(symbol, config.alphaVantageApiKey!)),
159
- wrapProvider("yahoo", () => getQuote(symbol)),
160
- ]);
193
+ const [overviewResult, financialsResult, quoteResult] = await Promise.all([
194
+ wrapProvider("alphavantage", () => getOverview(symbol, config.alphaVantageApiKey!)),
195
+ wrapProvider("alphavantage", () => getFinancials(symbol, config.alphaVantageApiKey!)),
196
+ wrapProvider("yahoo", () => getQuote(symbol)),
197
+ ]);
161
198
 
162
- const missing: string[] = [];
163
- if (overviewResult.status === "unavailable") missing.push(`company overview (${overviewResult.reason})`);
164
- if (financialsResult.status === "unavailable") missing.push(`financial statements (${financialsResult.reason})`);
165
- if (quoteResult.status === "unavailable") missing.push(`stock quote (${quoteResult.reason})`);
199
+ const missing: string[] = [];
200
+ if (overviewResult.status === "unavailable")
201
+ missing.push(`company overview (${overviewResult.reason})`);
202
+ if (financialsResult.status === "unavailable")
203
+ missing.push(`financial statements (${financialsResult.reason})`);
204
+ if (quoteResult.status === "unavailable") missing.push(`stock quote (${quoteResult.reason})`);
166
205
 
167
- if (financialsResult.status === "unavailable" || quoteResult.status === "unavailable") {
168
- return {
169
- content: [{ type: "text", text: `⚠ DCF valuation unavailable for ${symbol}. Missing: ${missing.join(", ")}. Both financials and current price are required.` }],
170
- details: null,
171
- };
172
- }
206
+ if (financialsResult.status === "unavailable" || quoteResult.status === "unavailable") {
207
+ return {
208
+ content: [
209
+ {
210
+ type: "text",
211
+ text: `⚠ DCF valuation unavailable for ${symbol}. Missing: ${missing.join(", ")}. Both financials and current price are required.`,
212
+ },
213
+ ],
214
+ details: null,
215
+ };
216
+ }
173
217
 
174
- const overview = overviewResult.status === "ok" ? overviewResult.data : null;
175
- const financials = financialsResult.data;
176
- const quote = quoteResult.data;
218
+ const overview = overviewResult.status === "ok" ? overviewResult.data : null;
219
+ const financials = financialsResult.data;
220
+ const quote = quoteResult.data;
177
221
 
178
- const latestFCF = financials[0]?.freeCashFlow ?? 0;
179
- if (latestFCF <= 0) {
180
- return {
181
- content: [{ type: "text", text: `${symbol} has negative or zero free cash flow ($${latestFCF.toLocaleString()}). DCF is not meaningful for companies without positive FCF.` }],
182
- details: null,
183
- };
184
- }
222
+ const latestFCF = financials[0]?.freeCashFlow ?? 0;
223
+ if (latestFCF <= 0) {
224
+ return {
225
+ content: [
226
+ {
227
+ type: "text",
228
+ text: `${symbol} has negative or zero free cash flow ($${latestFCF.toLocaleString()}). DCF is not meaningful for companies without positive FCF.`,
229
+ },
230
+ ],
231
+ details: null,
232
+ };
233
+ }
185
234
 
186
- // Estimate growth from historical FCF if not provided
187
- let growthRate = args.growth_rate ?? 0.10;
188
- if (!args.growth_rate && financials.length >= 2) {
189
- const olderFCF = financials[1]?.freeCashFlow;
190
- if (olderFCF && olderFCF > 0) {
191
- growthRate = Math.max(0.02, Math.min(0.25, (latestFCF - olderFCF) / olderFCF));
235
+ // Estimate growth from historical FCF if not provided
236
+ let growthRate = args.growth_rate ?? 0.1;
237
+ if (!args.growth_rate && financials.length >= 2) {
238
+ const olderFCF = financials[1]?.freeCashFlow;
239
+ if (olderFCF && olderFCF > 0) {
240
+ growthRate = Math.max(0.02, Math.min(0.25, (latestFCF - olderFCF) / olderFCF));
241
+ }
192
242
  }
193
- }
194
243
 
195
- const discountRate = args.discount_rate ?? 0.10;
196
- const terminalGrowth = args.terminal_growth ?? 0.03;
197
- const years = args.projection_years ?? 5;
198
- const marketCap = overview?.marketCap ?? 0;
199
- const sharesOutstanding = quote.price > 0 && marketCap > 0 ? marketCap / quote.price : 1;
200
- const netDebt = financials[0] ? computeNetDebt(financials[0]) : 0;
244
+ const discountRate = args.discount_rate ?? 0.1;
245
+ const terminalGrowth = args.terminal_growth ?? 0.03;
246
+ const years = args.projection_years ?? 5;
247
+ const marketCap = overview?.marketCap ?? 0;
248
+ const sharesOutstanding = quote.price > 0 && marketCap > 0 ? marketCap / quote.price : 1;
249
+ const netDebt = financials[0] ? computeNetDebt(financials[0]) : 0;
201
250
 
202
- const result = computeDCF({
203
- freeCashFlow: latestFCF,
204
- growthRate,
205
- discountRate,
206
- terminalGrowth,
207
- years,
208
- netDebt: Math.max(0, netDebt),
209
- sharesOutstanding,
210
- });
251
+ const result = computeDCF({
252
+ freeCashFlow: latestFCF,
253
+ growthRate,
254
+ discountRate,
255
+ terminalGrowth,
256
+ years,
257
+ netDebt: Math.max(0, netDebt),
258
+ sharesOutstanding,
259
+ });
211
260
 
212
- const marginOfSafety = (result.intrinsicValue - quote.price) / result.intrinsicValue;
213
- const upside = (result.intrinsicValue - quote.price) / quote.price;
261
+ const marginOfSafety = (result.intrinsicValue - quote.price) / result.intrinsicValue;
262
+ const upside = (result.intrinsicValue - quote.price) / quote.price;
214
263
 
215
- const lines = [
216
- `**${symbol} DCF Valuation**`,
217
- ``,
218
- `Current Price: $${quote.price.toFixed(2)}`,
219
- `Intrinsic Value: $${result.intrinsicValue.toFixed(2)}`,
220
- `Margin of Safety: ${(marginOfSafety * 100).toFixed(1)}%`,
221
- `Upside/Downside: ${upside >= 0 ? "+" : ""}${(upside * 100).toFixed(1)}%`,
222
- ``,
223
- `**Assumptions**`,
224
- `Free Cash Flow: $${(latestFCF / 1e9).toFixed(2)}B`,
225
- `Growth Rate: ${(growthRate * 100).toFixed(1)}%`,
226
- `Discount Rate (WACC): ${(discountRate * 100).toFixed(1)}%`,
227
- `Terminal Growth: ${(terminalGrowth * 100).toFixed(1)}%`,
228
- `Projection: ${years} years`,
229
- ``,
230
- `**Projected Cash Flows**`,
231
- ...result.projectedCashFlows.map((cf) =>
232
- ` Year ${cf.year}: FCF $${(cf.fcf / 1e9).toFixed(2)}B → PV $${(cf.presentValue / 1e9).toFixed(2)}B`
233
- ),
234
- ` Terminal Value: $${(result.terminalValue / 1e9).toFixed(2)}B`,
235
- ` Enterprise Value: $${(result.enterpriseValue / 1e9).toFixed(2)}B`,
236
- ``,
237
- `**Sensitivity Table** (Intrinsic Value at different Growth/Discount rates)`,
238
- ...formatSensitivityTable(result.sensitivityTable),
239
- ];
264
+ const lines = [
265
+ `**${symbol} DCF Valuation**`,
266
+ ``,
267
+ `Current Price: $${quote.price.toFixed(2)}`,
268
+ `Intrinsic Value: $${result.intrinsicValue.toFixed(2)}`,
269
+ `Margin of Safety: ${(marginOfSafety * 100).toFixed(1)}%`,
270
+ `Upside/Downside: ${upside >= 0 ? "+" : ""}${(upside * 100).toFixed(1)}%`,
271
+ ``,
272
+ `**Assumptions**`,
273
+ `Free Cash Flow: $${(latestFCF / 1e9).toFixed(2)}B`,
274
+ `Growth Rate: ${(growthRate * 100).toFixed(1)}%`,
275
+ `Discount Rate (WACC): ${(discountRate * 100).toFixed(1)}%`,
276
+ `Terminal Growth: ${(terminalGrowth * 100).toFixed(1)}%`,
277
+ `Projection: ${years} years`,
278
+ ``,
279
+ `**Projected Cash Flows**`,
280
+ ...result.projectedCashFlows.map(
281
+ (cf) =>
282
+ ` Year ${cf.year}: FCF $${(cf.fcf / 1e9).toFixed(2)}B → PV $${(cf.presentValue / 1e9).toFixed(2)}B`,
283
+ ),
284
+ ` Terminal Value: $${(result.terminalValue / 1e9).toFixed(2)}B`,
285
+ ` Enterprise Value: $${(result.enterpriseValue / 1e9).toFixed(2)}B`,
286
+ ``,
287
+ `**Sensitivity Table** (Intrinsic Value at different Growth/Discount rates)`,
288
+ ...formatSensitivityTable(result.sensitivityTable),
289
+ ];
240
290
 
241
- return {
242
- content: [{ type: "text", text: lines.join("\n") }],
243
- details: { ...result, currentPrice: quote.price, marginOfSafety, upside },
244
- };
291
+ return {
292
+ content: [{ type: "text", text: lines.join("\n") }],
293
+ details: { ...result, currentPrice: quote.price, marginOfSafety, upside },
294
+ };
245
295
  });
246
296
  },
247
297
  };
@@ -1,16 +1,19 @@
1
- import { Type } from "@sinclair/typebox";
2
1
  import type { AgentTool } from "@earendil-works/pi-agent-core";
3
- import { getEarnings } from "../../providers/alpha-vantage.js";
4
- import { wrapProvider } from "../../providers/wrap-provider.js";
2
+ import { Type } from "@sinclair/typebox";
5
3
  import { getConfig } from "../../config.js";
6
4
  import { withCredentialCheck } from "../../onboarding/tool-helpers.js";
5
+ import { getEarnings } from "../../providers/alpha-vantage.js";
6
+ import { wrapProvider } from "../../providers/wrap-provider.js";
7
7
  import type { EarningsData } from "../../types/fundamentals.js";
8
8
 
9
9
  const params = Type.Object({
10
10
  symbol: Type.String({ description: "Stock ticker symbol (e.g. AAPL, MSFT)" }),
11
11
  });
12
12
 
13
- export const earningsTool: AgentTool<typeof params, EarningsData | { credentialRequired: unknown }> = {
13
+ export const earningsTool: AgentTool<
14
+ typeof params,
15
+ EarningsData | { credentialRequired: unknown }
16
+ > = {
14
17
  name: "get_earnings",
15
18
  label: "Earnings History",
16
19
  description:
@@ -19,10 +22,17 @@ export const earningsTool: AgentTool<typeof params, EarningsData | { credentialR
19
22
  async execute(_toolCallId, args) {
20
23
  return withCredentialCheck("alpha_vantage", async () => {
21
24
  const apiKey = getConfig().alphaVantageApiKey!;
22
- const result = await wrapProvider("alphavantage", () => getEarnings(args.symbol.toUpperCase(), apiKey));
25
+ const result = await wrapProvider("alphavantage", () =>
26
+ getEarnings(args.symbol.toUpperCase(), apiKey),
27
+ );
23
28
  if (result.status === "unavailable") {
24
29
  return {
25
- content: [{ type: "text", text: `⚠ Earnings data unavailable for ${args.symbol.toUpperCase()} (${result.reason}). Analysis will proceed without earnings history.` }],
30
+ content: [
31
+ {
32
+ type: "text",
33
+ text: `⚠ Earnings data unavailable for ${args.symbol.toUpperCase()} (${result.reason}). Analysis will proceed without earnings history.`,
34
+ },
35
+ ],
26
36
  details: null as any,
27
37
  };
28
38
  }
@@ -1,16 +1,19 @@
1
- import { Type } from "@sinclair/typebox";
2
1
  import type { AgentTool } from "@earendil-works/pi-agent-core";
3
- import { getFinancials } from "../../providers/alpha-vantage.js";
4
- import { wrapProvider } from "../../providers/wrap-provider.js";
2
+ import { Type } from "@sinclair/typebox";
5
3
  import { getConfig } from "../../config.js";
6
4
  import { withCredentialCheck } from "../../onboarding/tool-helpers.js";
5
+ import { getFinancials } from "../../providers/alpha-vantage.js";
6
+ import { wrapProvider } from "../../providers/wrap-provider.js";
7
7
  import type { FinancialStatement } from "../../types/fundamentals.js";
8
8
 
9
9
  const params = Type.Object({
10
10
  symbol: Type.String({ description: "Stock ticker symbol (e.g. AAPL, MSFT)" }),
11
11
  });
12
12
 
13
- export const financialsTool: AgentTool<typeof params, FinancialStatement[] | { credentialRequired: unknown }> = {
13
+ export const financialsTool: AgentTool<
14
+ typeof params,
15
+ FinancialStatement[] | { credentialRequired: unknown }
16
+ > = {
14
17
  name: "get_financials",
15
18
  label: "Financial Statements",
16
19
  description:
@@ -24,7 +27,12 @@ export const financialsTool: AgentTool<typeof params, FinancialStatement[] | { c
24
27
  );
25
28
  if (result.status === "unavailable") {
26
29
  return {
27
- content: [{ type: "text", text: `⚠ Financial statements unavailable for ${args.symbol.toUpperCase()} (${result.reason}). Analysis will proceed without financials.` }],
30
+ content: [
31
+ {
32
+ type: "text",
33
+ text: `⚠ Financial statements unavailable for ${args.symbol.toUpperCase()} (${result.reason}). Analysis will proceed without financials.`,
34
+ },
35
+ ],
28
36
  details: [],
29
37
  };
30
38
  }
@@ -37,8 +45,9 @@ export const financialsTool: AgentTool<typeof params, FinancialStatement[] | { c
37
45
  }
38
46
 
39
47
  const header = `${args.symbol.toUpperCase()} — Annual Income Statement (${statements.length} years)`;
40
- const rows = statements.map((s) =>
41
- `${s.fiscalDate} | Rev: $${fmt(s.revenue)} | GP: $${fmt(s.grossProfit)} | OpInc: $${fmt(s.operatingIncome)} | Net: $${fmt(s.netIncome)}`,
48
+ const rows = statements.map(
49
+ (s) =>
50
+ `${s.fiscalDate} | Rev: $${fmt(s.revenue)} | GP: $${fmt(s.grossProfit)} | OpInc: $${fmt(s.operatingIncome)} | Net: $${fmt(s.netIncome)}`,
42
51
  );
43
52
 
44
53
  const text = [header, ...rows].join("\n");