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,22 +1,19 @@
1
1
  import type { MemoryCategory, MemoryEntry } from "../memory/types.js";
2
2
  import {
3
- activeToolsForBundles,
4
- memoryScopesForRoute,
5
- } from "./route-manifest.js";
3
+ buildPlanningEnvelope,
4
+ type PlanningBuildOptions,
5
+ type PlanningEnvelope,
6
+ } from "./planning.js";
7
+ import { activeToolsForBundles, memoryScopesForRoute } from "./route-manifest.js";
6
8
  import type {
9
+ RouterDiagnostic,
7
10
  RouterInputContext,
8
11
  RouterOutput,
9
12
  RouterRoute,
10
13
  RouterRouteKind,
11
14
  RouterSlot,
12
15
  ToolBundleName,
13
- RouterDiagnostic,
14
16
  } from "./router-types.js";
15
- import {
16
- buildPlanningEnvelope,
17
- type PlanningBuildOptions,
18
- type PlanningEnvelope,
19
- } from "./planning.js";
20
17
  import type { ExtractedEntities, WorkflowType } from "./types.js";
21
18
 
22
19
  export interface MemoryQueryPlan {
@@ -63,6 +63,8 @@ export interface CompareAssetsSlots {
63
63
  symbols: string[];
64
64
  timeHorizon?: string;
65
65
  metrics?: string[];
66
+ budget?: number;
67
+ assetScope?: string;
66
68
  }
67
69
 
68
70
  export type SlotSource = "user" | "preference" | "default" | "prior_context" | "memory";
@@ -18,7 +18,9 @@ export type FinalAnswerField =
18
18
  | "freshness_disclosure"
19
19
  | "data_gap_disclosure"
20
20
  | "risk_downside"
21
- | "source_coverage";
21
+ | "source_coverage"
22
+ | "sentiment_rationale"
23
+ | "confidence_or_caveats";
22
24
 
23
25
  export type FrameworkFallbackMode =
24
26
  | "not_allowed"
@@ -160,7 +162,12 @@ export const ANSWER_CONTRACT_REGISTRY: Record<AnswerContractId, AnswerContractDe
160
162
  commitmentMode: "decision",
161
163
  implemented: true,
162
164
  requiredEvidenceTypes: [],
163
- requiredFinalFields: ["clear_commitment", "risk_downside", "freshness_disclosure", "data_gap_disclosure"],
165
+ requiredFinalFields: [
166
+ "clear_commitment",
167
+ "risk_downside",
168
+ "freshness_disclosure",
169
+ "data_gap_disclosure",
170
+ ],
164
171
  requiresFreshness: true,
165
172
  requiresDataGapDisclosure: true,
166
173
  requiresRiskDownside: true,
@@ -175,7 +182,12 @@ export const ANSWER_CONTRACT_REGISTRY: Record<AnswerContractId, AnswerContractDe
175
182
  commitmentMode: "compare_tradeoffs",
176
183
  implemented: true,
177
184
  requiredEvidenceTypes: [],
178
- requiredFinalFields: ["comparison_tradeoffs", "risk_downside", "data_gap_disclosure", "source_coverage"],
185
+ requiredFinalFields: [
186
+ "comparison_tradeoffs",
187
+ "risk_downside",
188
+ "data_gap_disclosure",
189
+ "source_coverage",
190
+ ],
179
191
  requiresFreshness: false,
180
192
  requiresDataGapDisclosure: true,
181
193
  requiresRiskDownside: true,
@@ -184,7 +196,9 @@ export const ANSWER_CONTRACT_REGISTRY: Record<AnswerContractId, AnswerContractDe
184
196
  capabilityGapIds: ["etf_holdings_overlap"],
185
197
  frameworkFallback: "not_allowed",
186
198
  },
187
- portfolio_build: placeholderContract("portfolio_build", "portfolio_build", "construct", ["constructed_output"]),
199
+ portfolio_build: placeholderContract("portfolio_build", "portfolio_build", "construct", [
200
+ "constructed_output",
201
+ ]),
188
202
  portfolio_review: {
189
203
  id: "portfolio_review",
190
204
  taskFamily: "portfolio_review",
@@ -255,7 +269,12 @@ export const ANSWER_CONTRACT_REGISTRY: Record<AnswerContractId, AnswerContractDe
255
269
  commitmentMode: "framework",
256
270
  implemented: true,
257
271
  requiredEvidenceTypes: [],
258
- requiredFinalFields: ["framework_or_checklist", "risk_downside", "data_gap_disclosure", "source_coverage"],
272
+ requiredFinalFields: [
273
+ "framework_or_checklist",
274
+ "risk_downside",
275
+ "data_gap_disclosure",
276
+ "source_coverage",
277
+ ],
259
278
  requiresFreshness: false,
260
279
  requiresDataGapDisclosure: true,
261
280
  requiresRiskDownside: true,
@@ -285,7 +304,12 @@ export const ANSWER_CONTRACT_REGISTRY: Record<AnswerContractId, AnswerContractDe
285
304
  commitmentMode: "framework",
286
305
  implemented: true,
287
306
  requiredEvidenceTypes: ["market_status"],
288
- requiredFinalFields: ["framework_or_checklist", "freshness_disclosure", "source_coverage", "data_gap_disclosure"],
307
+ requiredFinalFields: [
308
+ "framework_or_checklist",
309
+ "freshness_disclosure",
310
+ "source_coverage",
311
+ "data_gap_disclosure",
312
+ ],
289
313
  requiresFreshness: true,
290
314
  requiresDataGapDisclosure: true,
291
315
  requiresRiskDownside: false,
@@ -320,7 +344,12 @@ export const ANSWER_CONTRACT_REGISTRY: Record<AnswerContractId, AnswerContractDe
320
344
  commitmentMode: "framework",
321
345
  implemented: true,
322
346
  requiredEvidenceTypes: [],
323
- requiredFinalFields: ["source_coverage", "data_gap_disclosure"],
347
+ requiredFinalFields: [
348
+ "source_coverage",
349
+ "sentiment_rationale",
350
+ "confidence_or_caveats",
351
+ "data_gap_disclosure",
352
+ ],
324
353
  requiresFreshness: false,
325
354
  requiresDataGapDisclosure: true,
326
355
  requiresRiskDownside: false,
@@ -374,7 +403,9 @@ export const ANSWER_CONTRACT_REGISTRY: Record<AnswerContractId, AnswerContractDe
374
403
  capabilityGapIds: [],
375
404
  frameworkFallback: "not_allowed",
376
405
  },
377
- general_fallback: placeholderContract("general_fallback", "general_fallback", "framework", ["data_gap_disclosure"]),
406
+ general_fallback: placeholderContract("general_fallback", "general_fallback", "framework", [
407
+ "data_gap_disclosure",
408
+ ]),
378
409
  };
379
410
 
380
411
  export function runStructuredChecks(input: StructuredCheckInput): StructuredCheckTrace {
@@ -384,12 +415,15 @@ export function runStructuredChecks(input: StructuredCheckInput): StructuredChec
384
415
  checkFreshness(input.contract, input.finalAnswerMetadata),
385
416
  checkDataGapDisclosure(input.contract, input.evidenceRecords, input.finalAnswerMetadata),
386
417
  checkCommitmentMode(input.contract, input.finalAnswerMetadata),
418
+ checkRequiredFinalFields(input.contract, input.finalAnswerMetadata),
387
419
  checkSourceCoverage(input.contract, input.finalAnswerMetadata),
388
420
  checkCapabilityGapDisclosure(input.contract, input.evidenceRecords, input.finalAnswerMetadata),
389
421
  ...semanticChecks(requestedChecks, input.answerText),
390
422
  ];
391
423
  const failures = results.filter((result) => !result.passed);
392
- const retryReasons = failures.map((failure) => `${failure.checkId}: ${failure.failureReason ?? "failed"}`);
424
+ const retryReasons = failures.map(
425
+ (failure) => `${failure.checkId}: ${failure.failureReason ?? "failed"}`,
426
+ );
393
427
 
394
428
  return {
395
429
  mode: "observe_only",
@@ -411,36 +445,44 @@ function semanticChecks(
411
445
  ): StructuredCheckResult[] {
412
446
  const checks: StructuredCheckResult[] = [];
413
447
  if (requestedChecks.has("assumption_disclosed")) {
414
- checks.push(checkAnswerText(
415
- "assumption_disclosed",
416
- answerText,
417
- /\b(?:assuming|assumption|assuming that|if your|based on your stated|given your stated)\b/i,
418
- "Explicit assumption disclosure is missing.",
419
- ));
448
+ checks.push(
449
+ checkAnswerText(
450
+ "assumption_disclosed",
451
+ answerText,
452
+ /\b(?:assuming|assumption|assuming that|if your|based on your stated|given your stated)\b/i,
453
+ "Explicit assumption disclosure is missing.",
454
+ ),
455
+ );
420
456
  }
421
457
  if (requestedChecks.has("tax_caveat_present")) {
422
- checks.push(checkAnswerText(
423
- "tax_caveat_present",
424
- answerText,
425
- /\b(?:tax|taxable|after[-\s]?tax|capital gains?|ordinary income|qualified dividend|tax advisor|jurisdiction|account type)\b/i,
426
- "Tax/account caveat is missing.",
427
- ));
458
+ checks.push(
459
+ checkAnswerText(
460
+ "tax_caveat_present",
461
+ answerText,
462
+ /\b(?:tax|taxable|after[-\s]?tax|capital gains?|ordinary income|qualified dividend|tax advisor|jurisdiction|account type)\b/i,
463
+ "Tax/account caveat is missing.",
464
+ ),
465
+ );
428
466
  }
429
467
  if (requestedChecks.has("target_bands_present")) {
430
- checks.push(checkAnswerText(
431
- "target_bands_present",
432
- answerText,
433
- /\b(?:target bands?|bands?|range|threshold|drift|5\s*%|percentage points?)\b/i,
434
- "Target band, range, or rebalance threshold guidance is missing.",
435
- ));
468
+ checks.push(
469
+ checkAnswerText(
470
+ "target_bands_present",
471
+ answerText,
472
+ /\b(?:target bands?|bands?|range|threshold|drift|5\s*%|percentage points?)\b/i,
473
+ "Target band, range, or rebalance threshold guidance is missing.",
474
+ ),
475
+ );
436
476
  }
437
477
  if (requestedChecks.has("when_not_ideal_present")) {
438
- checks.push(checkAnswerText(
439
- "when_not_ideal_present",
440
- answerText,
441
- /\b(?:not ideal|avoid|bad fit|poor fit|when this fails|where it fails|doesn'?t work|not suitable|watch out)\b/i,
442
- "When-not-ideal or unsuitability guidance is missing.",
443
- ));
478
+ checks.push(
479
+ checkAnswerText(
480
+ "when_not_ideal_present",
481
+ answerText,
482
+ /\b(?:not ideal|avoid|bad fit|poor fit|when this fails|where it fails|doesn'?t work|not suitable|watch out)\b/i,
483
+ "When-not-ideal or unsuitability guidance is missing.",
484
+ ),
485
+ );
444
486
  }
445
487
  return checks;
446
488
  }
@@ -452,11 +494,7 @@ function checkAnswerText(
452
494
  failureReason: string,
453
495
  ): StructuredCheckResult {
454
496
  const passed = typeof answerText === "string" && pattern.test(answerText);
455
- return structuredResult(
456
- checkId,
457
- passed,
458
- passed ? undefined : failureReason,
459
- );
497
+ return structuredResult(checkId, passed, passed ? undefined : failureReason);
460
498
  }
461
499
 
462
500
  export function evaluateFrameworkFallbackEligibility(
@@ -471,9 +509,12 @@ export function evaluateFrameworkFallbackEligibility(
471
509
  };
472
510
  }
473
511
 
474
- const hasUnresolvedSymbol = input.evidenceRecords.some((record) =>
475
- record.evidenceType === "ticker_disambiguation" &&
476
- (record.caveats.length > 0 || record.entityScope.symbols === undefined || record.entityScope.symbols.length === 0),
512
+ const hasUnresolvedSymbol = input.evidenceRecords.some(
513
+ (record) =>
514
+ record.evidenceType === "ticker_disambiguation" &&
515
+ (record.caveats.length > 0 ||
516
+ record.entityScope.symbols === undefined ||
517
+ record.entityScope.symbols.length === 0),
477
518
  );
478
519
  if (!hasUnresolvedSymbol) {
479
520
  return {
@@ -513,7 +554,8 @@ function placeholderContract(
513
554
  requiresDataGapDisclosure: requiredFinalFields.includes("data_gap_disclosure"),
514
555
  requiresRiskDownside: requiredFinalFields.includes("risk_downside"),
515
556
  requiresSourceCoverage: requiredFinalFields.includes("source_coverage"),
516
- requiresConcreteCommitment: COMMITMENT_MODE_CONTRACTS[commitmentMode].requiresConcreteCommitment,
557
+ requiresConcreteCommitment:
558
+ COMMITMENT_MODE_CONTRACTS[commitmentMode].requiresConcreteCommitment,
517
559
  capabilityGapIds: [],
518
560
  frameworkFallback: "not_allowed",
519
561
  };
@@ -537,7 +579,8 @@ function checkFreshness(
537
579
  metadata: FinalAnswerMetadata,
538
580
  ): StructuredCheckResult {
539
581
  if (!contract.requiresFreshness) return structuredResult("freshness_disclosed", true);
540
- const present = metadata.finalFields.includes("freshness_disclosure") && metadata.freshness !== undefined;
582
+ const present =
583
+ metadata.finalFields.includes("freshness_disclosure") && metadata.freshness !== undefined;
541
584
  return structuredResult(
542
585
  "freshness_disclosed",
543
586
  present,
@@ -569,7 +612,9 @@ function checkCommitmentMode(
569
612
  ): StructuredCheckResult {
570
613
  const modeContract = COMMITMENT_MODE_CONTRACTS[contract.commitmentMode];
571
614
  const fields = new Set(metadata.finalFields);
572
- const requiredFieldsPresent = modeContract.requiredFinalFields.every((field) => fields.has(field));
615
+ const requiredFieldsPresent = modeContract.requiredFinalFields.every((field) =>
616
+ fields.has(field),
617
+ );
573
618
  const passed =
574
619
  metadata.commitmentMode === contract.commitmentMode &&
575
620
  requiredFieldsPresent &&
@@ -577,7 +622,22 @@ function checkCommitmentMode(
577
622
  return structuredResult(
578
623
  "commitment_mode_respected",
579
624
  passed,
580
- passed ? undefined : `Expected ${contract.commitmentMode} metadata and fields: ${modeContract.requiredFinalFields.join(", ")}`,
625
+ passed
626
+ ? undefined
627
+ : `Expected ${contract.commitmentMode} metadata and fields: ${modeContract.requiredFinalFields.join(", ")}`,
628
+ );
629
+ }
630
+
631
+ function checkRequiredFinalFields(
632
+ contract: AnswerContractDefinition,
633
+ metadata: FinalAnswerMetadata,
634
+ ): StructuredCheckResult {
635
+ const fields = new Set(metadata.finalFields);
636
+ const missing = contract.requiredFinalFields.filter((field) => !fields.has(field));
637
+ return structuredResult(
638
+ "required_final_fields_present",
639
+ missing.length === 0,
640
+ missing.length > 0 ? `Missing required final fields: ${missing.join(", ")}` : undefined,
581
641
  );
582
642
  }
583
643
 
@@ -69,7 +69,8 @@ export function validateArtifactContractRegistry(): string[] {
69
69
  for (const [id, contract] of Object.entries(ARTIFACT_CONTRACT_REGISTRY)) {
70
70
  if (contract.id !== id) errors.push(`${id} key must match contract id`);
71
71
  if (contract.status !== "trace_only") errors.push(`${id} must remain trace-only in V1`);
72
- if (contract.taskFamilies.length === 0) errors.push(`${id} must declare at least one task family`);
72
+ if (contract.taskFamilies.length === 0)
73
+ errors.push(`${id} must declare at least one task family`);
73
74
  if (!contract.description.trim()) errors.push(`${id} must include a description`);
74
75
  }
75
76
  return errors;
@@ -1,5 +1,5 @@
1
- import { parseToolTag } from "../onboarding/tool-tags.js";
2
1
  import type { ParsedTag } from "../onboarding/tool-tags.js";
2
+ import { parseToolTag } from "../onboarding/tool-tags.js";
3
3
  import type { CapabilityGapId, EvidencePlanId, TaskFamily } from "../routing/planning.js";
4
4
  import type { ProviderResult } from "./evidence.js";
5
5
 
@@ -135,23 +135,71 @@ export const EVIDENCE_PLAN_REGISTRY: Record<EvidencePlanId, EvidencePlanDefiniti
135
135
  optionalEvidence: ["tool_result"],
136
136
  capabilityGapIds: ["earnings_event_risk"],
137
137
  },
138
- placeholder_single_asset_decision: placeholderPlan("placeholder_single_asset_decision", ["single_asset_decision"], []),
139
- placeholder_asset_compare: placeholderPlan("placeholder_asset_compare", ["asset_compare"], ["etf_holdings_overlap"]),
140
- placeholder_portfolio_build: placeholderPlan("placeholder_portfolio_build", ["portfolio_build"], []),
141
- placeholder_portfolio_review: placeholderPlan("placeholder_portfolio_review", ["portfolio_review"], []),
142
- placeholder_options_strategy: placeholderPlan("placeholder_options_strategy", ["options_strategy"], []),
143
- placeholder_current_event_explanation: placeholderPlan("placeholder_current_event_explanation", ["current_event_explanation"], ["market_calendar"]),
144
- placeholder_sentiment_snapshot: placeholderPlan("placeholder_sentiment_snapshot", ["sentiment_snapshot"], ["sentiment_sample_depth"]),
145
- placeholder_filing_thesis_review: placeholderPlan("placeholder_filing_thesis_review", ["filing_thesis_review"], []),
146
- placeholder_retail_finance_tradeoff: placeholderPlan("placeholder_retail_finance_tradeoff", ["retail_finance_tradeoff"], [
147
- "brokerage_comparison",
148
- "cash_yield_products",
149
- "fund_tax_efficiency",
150
- ]),
151
- placeholder_concept_explainer: placeholderPlan("placeholder_concept_explainer", ["concept_explainer"], []),
152
- placeholder_backtest_review: placeholderPlan("placeholder_backtest_review", ["backtest_review"], []),
153
- placeholder_stateful_tracking_update: placeholderPlan("placeholder_stateful_tracking_update", ["stateful_tracking_update"], []),
154
- placeholder_general_fallback: placeholderPlan("placeholder_general_fallback", ["general_fallback"], []),
138
+ placeholder_single_asset_decision: placeholderPlan(
139
+ "placeholder_single_asset_decision",
140
+ ["single_asset_decision"],
141
+ [],
142
+ ),
143
+ placeholder_asset_compare: placeholderPlan(
144
+ "placeholder_asset_compare",
145
+ ["asset_compare"],
146
+ ["etf_holdings_overlap"],
147
+ ),
148
+ placeholder_portfolio_build: placeholderPlan(
149
+ "placeholder_portfolio_build",
150
+ ["portfolio_build"],
151
+ [],
152
+ ),
153
+ placeholder_portfolio_review: placeholderPlan(
154
+ "placeholder_portfolio_review",
155
+ ["portfolio_review"],
156
+ [],
157
+ ),
158
+ placeholder_options_strategy: placeholderPlan(
159
+ "placeholder_options_strategy",
160
+ ["options_strategy"],
161
+ [],
162
+ ),
163
+ placeholder_current_event_explanation: placeholderPlan(
164
+ "placeholder_current_event_explanation",
165
+ ["current_event_explanation"],
166
+ ["market_calendar"],
167
+ ),
168
+ placeholder_sentiment_snapshot: placeholderPlan(
169
+ "placeholder_sentiment_snapshot",
170
+ ["sentiment_snapshot"],
171
+ ["sentiment_sample_depth"],
172
+ ),
173
+ placeholder_filing_thesis_review: placeholderPlan(
174
+ "placeholder_filing_thesis_review",
175
+ ["filing_thesis_review"],
176
+ [],
177
+ ),
178
+ placeholder_retail_finance_tradeoff: placeholderPlan(
179
+ "placeholder_retail_finance_tradeoff",
180
+ ["retail_finance_tradeoff"],
181
+ ["brokerage_comparison", "cash_yield_products", "fund_tax_efficiency"],
182
+ ),
183
+ placeholder_concept_explainer: placeholderPlan(
184
+ "placeholder_concept_explainer",
185
+ ["concept_explainer"],
186
+ [],
187
+ ),
188
+ placeholder_backtest_review: placeholderPlan(
189
+ "placeholder_backtest_review",
190
+ ["backtest_review"],
191
+ [],
192
+ ),
193
+ placeholder_stateful_tracking_update: placeholderPlan(
194
+ "placeholder_stateful_tracking_update",
195
+ ["stateful_tracking_update"],
196
+ [],
197
+ ),
198
+ placeholder_general_fallback: placeholderPlan(
199
+ "placeholder_general_fallback",
200
+ ["general_fallback"],
201
+ [],
202
+ ),
155
203
  };
156
204
 
157
205
  const KNOWN_US_MARKET_HOLIDAYS: Record<string, string> = {
@@ -193,11 +241,14 @@ export function buildMarketStatusEvidence(input: MarketStatusInput): PlanningEvi
193
241
  const isMarketHoliday = holidayName !== undefined;
194
242
  const marketStatus = classifyMarketStatus(local, isWeekend, isMarketHoliday, temporalReferences);
195
243
  const lastTradingDate = marketStatus === "open" ? local.date : lastTradingDay(local.date);
196
- const gaps: EvidenceGap[] = [{
197
- kind: "capability_gap",
198
- capabilityGapId: "market_calendar",
199
- reason: "V1 uses deterministic weekday and known-holiday grounding, not a live exchange-calendar provider.",
200
- }];
244
+ const gaps: EvidenceGap[] = [
245
+ {
246
+ kind: "capability_gap",
247
+ capabilityGapId: "market_calendar",
248
+ reason:
249
+ "V1 uses deterministic weekday and known-holiday grounding, not a live exchange-calendar provider.",
250
+ },
251
+ ];
201
252
 
202
253
  return {
203
254
  id: "market_status:deterministic",
@@ -219,20 +270,27 @@ export function buildMarketStatusEvidence(input: MarketStatusInput): PlanningEvi
219
270
  lastTradingDay: lastTradingDate,
220
271
  quoteAsOfCaveat: quoteAsOfCaveat(marketStatus),
221
272
  },
222
- rawTracePointer: input.traceId ? { traceId: input.traceId, toolName: "deterministic_market_status" } : undefined,
273
+ rawTracePointer: input.traceId
274
+ ? { traceId: input.traceId, toolName: "deterministic_market_status" }
275
+ : undefined,
223
276
  gaps,
224
- caveats: ["Market status is deterministic V1 grounding and should be verified against an exchange calendar for edge cases."],
277
+ caveats: [
278
+ "Market status is deterministic V1 grounding and should be verified against an exchange calendar for edge cases.",
279
+ ],
225
280
  };
226
281
  }
227
282
 
228
283
  export function buildTickerDisambiguationEvidence(
229
284
  input: TickerDisambiguationInput,
230
285
  ): PlanningEvidenceRecord {
231
- const gaps: EvidenceGap[] = [{
232
- kind: "capability_gap",
233
- capabilityGapId: "earnings_event_risk",
234
- reason: "Ticker disambiguation can preserve symbol-verification gaps, but V1 does not add richer earnings-event data.",
235
- }];
286
+ const gaps: EvidenceGap[] = [
287
+ {
288
+ kind: "capability_gap",
289
+ capabilityGapId: "earnings_event_risk",
290
+ reason:
291
+ "Ticker disambiguation can preserve symbol-verification gaps, but V1 does not add richer earnings-event data.",
292
+ },
293
+ ];
236
294
 
237
295
  return {
238
296
  id: "ticker_disambiguation:selected_slice",
@@ -247,9 +305,15 @@ export function buildTickerDisambiguationEvidence(
247
305
  requiresSymbolVerification: true,
248
306
  legacyBehaviorRemainsActive: true,
249
307
  },
250
- rawTracePointer: input.traceId ? { traceId: input.traceId, toolName: "planning_ticker_disambiguation" } : undefined,
308
+ rawTracePointer: input.traceId
309
+ ? { traceId: input.traceId, toolName: "planning_ticker_disambiguation" }
310
+ : undefined,
251
311
  gaps,
252
- caveats: input.symbols?.length ? [] : ["No symbol was verified by this evidence plan; active tools remain responsible for lookup."],
312
+ caveats: input.symbols?.length
313
+ ? []
314
+ : [
315
+ "No symbol was verified by this evidence plan; active tools remain responsible for lookup.",
316
+ ],
253
317
  };
254
318
  }
255
319
 
@@ -258,7 +322,8 @@ export function buildPortfolioExposureMapEvidence(
258
322
  ): PlanningEvidenceRecord {
259
323
  const sleeves = extractPortfolioSleeves(input.text);
260
324
  const normalizedSleeves = new Set(sleeves.map((sleeve) => sleeve.normalizedSleeve));
261
- const hasBroadIndex = normalizedSleeves.has("broad_us_index") || normalizedSleeves.has("broad_equity");
325
+ const hasBroadIndex =
326
+ normalizedSleeves.has("broad_us_index") || normalizedSleeves.has("broad_equity");
262
327
  const hasSectorSleeve = sleeves.some((sleeve) => sleeve.normalizedSleeve.endsWith("_sector"));
263
328
  const broadIndexOverlapCaveat = hasBroadIndex && hasSectorSleeve;
264
329
 
@@ -271,24 +336,36 @@ export function buildPortfolioExposureMapEvidence(
271
336
  providerStatus: "available",
272
337
  normalizedFacts: {
273
338
  directSleeves: sleeves,
274
- directExposureTotalPercent: roundPercent(sleeves.reduce((sum, sleeve) => sum + sleeve.percent, 0)),
339
+ directExposureTotalPercent: roundPercent(
340
+ sleeves.reduce((sum, sleeve) => sum + sleeve.percent, 0),
341
+ ),
275
342
  broadIndexOverlapCaveat,
276
343
  exactHoldingsOverlapAvailable: false,
277
- targetBandGuidanceNeeded: /\b(?:rebalance|target\s+bands?|drift|overweight|underweight|concentration|diversif)/i.test(input.text),
344
+ targetBandGuidanceNeeded:
345
+ /\b(?:rebalance|target\s+bands?|drift|overweight|underweight|concentration|diversif)/i.test(
346
+ input.text,
347
+ ),
278
348
  },
279
- rawTracePointer: input.traceId ? {
280
- traceId: input.traceId,
281
- toolName: "deterministic_portfolio_exposure_map",
282
- } : undefined,
283
- gaps: [{
284
- kind: "capability_gap",
285
- capabilityGapId: "etf_holdings_overlap",
286
- reason: "V1 records user-stated sleeves and overlap caveats but does not fetch exact ETF/index holdings or issuer weights.",
287
- }],
349
+ rawTracePointer: input.traceId
350
+ ? {
351
+ traceId: input.traceId,
352
+ toolName: "deterministic_portfolio_exposure_map",
353
+ }
354
+ : undefined,
355
+ gaps: [
356
+ {
357
+ kind: "capability_gap",
358
+ capabilityGapId: "etf_holdings_overlap",
359
+ reason:
360
+ "V1 records user-stated sleeves and overlap caveats but does not fetch exact ETF/index holdings or issuer weights.",
361
+ },
362
+ ],
288
363
  caveats: [
289
364
  "Exact ETF/index holdings overlap requires a provider-backed holdings source.",
290
365
  ...(broadIndexOverlapCaveat
291
- ? ["Broad index exposure may already include sector exposure; V1 does not estimate exact constituent weights."]
366
+ ? [
367
+ "Broad index exposure may already include sector exposure; V1 does not estimate exact constituent weights.",
368
+ ]
292
369
  : []),
293
370
  ],
294
371
  };
@@ -300,7 +377,8 @@ export function captureEvidenceFromToolCall(
300
377
  ): PlanningEvidenceRecord {
301
378
  const text = toolResultText(toolCall.result);
302
379
  const providerGap = text ? normalizeProviderGapFromToolText(text) : undefined;
303
- const providerStatus = providerGap?.providerStatus ?? (toolCall.isError ? "unavailable" : "available");
380
+ const providerStatus =
381
+ providerGap?.providerStatus ?? (toolCall.isError ? "unavailable" : "available");
304
382
  const gaps = providerGap ? [providerGapToEvidenceGap(providerGap)] : [];
305
383
  if (toolCall.isError && !providerGap) {
306
384
  gaps.push({
@@ -378,12 +456,14 @@ export function providerResultToPlanningEvidence<T>(
378
456
  providerStatus: "unavailable",
379
457
  normalizedFacts: { label },
380
458
  rawTracePointer,
381
- gaps: [{
382
- kind: "provider_status",
383
- providerStatus: "unavailable",
384
- provider: result.provider,
385
- reason: result.reason,
386
- }],
459
+ gaps: [
460
+ {
461
+ kind: "provider_status",
462
+ providerStatus: "unavailable",
463
+ provider: result.provider,
464
+ reason: result.reason,
465
+ },
466
+ ],
387
467
  caveats: [],
388
468
  };
389
469
  }
@@ -400,7 +480,9 @@ function providerGapToEvidenceGap(gap: NormalizedProviderGap): EvidenceGap {
400
480
  };
401
481
  }
402
482
 
403
- function providerStatusFromTag(tag: Exclude<ParsedTag, { kind: "connected" }>): Exclude<PlanningProviderStatus, "available"> {
483
+ function providerStatusFromTag(
484
+ tag: Exclude<ParsedTag, { kind: "connected" }>,
485
+ ): Exclude<PlanningProviderStatus, "available"> {
404
486
  if (tag.kind === "credential_required") return "credential_required";
405
487
  if (tag.kind === "soft_degraded") return "soft_degraded";
406
488
  return "skipped";
@@ -428,11 +510,14 @@ function toolResultText(result: unknown): string | undefined {
428
510
  const content = result.content;
429
511
  if (typeof content === "string") return content;
430
512
  if (Array.isArray(content)) {
431
- return content.map((item) => {
432
- if (typeof item === "string") return item;
433
- if (isRecord(item) && typeof item.text === "string") return item.text;
434
- return "";
435
- }).filter(Boolean).join("\n");
513
+ return content
514
+ .map((item) => {
515
+ if (typeof item === "string") return item;
516
+ if (isRecord(item) && typeof item.text === "string") return item.text;
517
+ return "";
518
+ })
519
+ .filter(Boolean)
520
+ .join("\n");
436
521
  }
437
522
  return undefined;
438
523
  }
@@ -449,7 +534,8 @@ function symbolsFromArgs(args: Record<string, unknown>): EntityScope {
449
534
 
450
535
  function extractPortfolioSleeves(text: string): PortfolioExposureSleeve[] {
451
536
  const matches: PortfolioExposureSleeve[] = [];
452
- const pattern = /(\d+(?:\.\d+)?)\s*%\s*(?:in|to|of|toward|towards|allocated\s+to)?\s*([^,;.\n?]+)/gi;
537
+ const pattern =
538
+ /(\d+(?:\.\d+)?)\s*%\s*(?:in|to|of|toward|towards|allocated\s+to)?\s*([^,;.\n?]+)/gi;
453
539
  for (const match of text.matchAll(pattern)) {
454
540
  const percent = Number(match[1]);
455
541
  if (!Number.isFinite(percent)) continue;
@@ -474,15 +560,18 @@ function cleanSleeveLabel(label: string): string {
474
560
  function normalizePortfolioSleeve(label: string): string {
475
561
  const lower = label.toLowerCase();
476
562
  if (/\b(?:s&p\s*500|sp\s*500|index|voo|spy|ivv)\b/.test(lower)) return "broad_us_index";
477
- if (/\b(?:tech|technology|software|semis?|semiconductors?)\b/.test(lower)) return "technology_sector";
563
+ if (/\b(?:tech|technology|software|semis?|semiconductors?)\b/.test(lower))
564
+ return "technology_sector";
478
565
  if (/\b(?:bond|bonds|fixed\s+income|treasur(?:y|ies))\b/.test(lower)) return "bonds";
479
566
  if (/\b(?:cash|savings?|money\s*market|t[-\s]?bills?)\b/.test(lower)) return "cash";
480
567
  if (/\b(?:international|ex[-\s]?us|foreign|global)\b/.test(lower)) return "international_equity";
481
568
  if (/\b(?:stock|stocks|equity|equities)\b/.test(lower)) return "broad_equity";
482
- return lower
483
- .replace(/[^a-z0-9]+/g, "_")
484
- .replace(/^_+|_+$/g, "")
485
- .slice(0, 48) || "unknown_sleeve";
569
+ return (
570
+ lower
571
+ .replace(/[^a-z0-9]+/g, "_")
572
+ .replace(/^_+|_+$/g, "")
573
+ .slice(0, 48) || "unknown_sleeve"
574
+ );
486
575
  }
487
576
 
488
577
  function roundPercent(value: number): number {
@@ -517,8 +606,10 @@ function classifyMarketStatus(
517
606
  }
518
607
 
519
608
  function quoteAsOfCaveat(marketStatus: string): string {
520
- if (marketStatus === "open") return "Quote evidence may be intraday or delayed depending on provider.";
521
- if (marketStatus === "pre_market") return "Quote evidence may reflect the previous regular session until premarket data is fetched.";
609
+ if (marketStatus === "open")
610
+ return "Quote evidence may be intraday or delayed depending on provider.";
611
+ if (marketStatus === "pre_market")
612
+ return "Quote evidence may reflect the previous regular session until premarket data is fetched.";
522
613
  return "Quote evidence should distinguish the current calendar date from the most recent trading session.";
523
614
  }
524
615